1 /* Id: gcc_compat.c,v 1.52 2010/05/15 15:58:33 ragge Exp */ 2 /* $NetBSD: gcc_compat.c,v 1.1.1.3 2010/06/03 18:57:39 plunky Exp $ */ 3 /* 4 * Copyright (c) 2004 Anders Magnusson (ragge@ludd.luth.se). 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. The name of the author may not be used to endorse or promote products 16 * derived from this software without specific prior written permission 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 19 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 20 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 21 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 22 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 23 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 24 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 25 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 */ 29 30 /* 31 * Routines to support some of the gcc extensions to C. 32 */ 33 #ifdef GCC_COMPAT 34 35 #include "pass1.h" 36 #include "cgram.h" 37 38 #include <string.h> 39 40 static struct kw { 41 char *name, *ptr; 42 int rv; 43 } kw[] = { 44 /* 45 * Do NOT change the order of these entries unless you know 46 * what you're doing! 47 */ 48 /* 0 */ { "__asm", NULL, C_ASM }, 49 /* 1 */ { "__signed", NULL, 0 }, 50 /* 2 */ { "__inline", NULL, C_FUNSPEC }, 51 /* 3 */ { "__const", NULL, 0 }, 52 /* 4 */ { "__asm__", NULL, C_ASM }, 53 /* 5 */ { "__inline__", NULL, C_FUNSPEC }, 54 /* 6 */ { "__thread", NULL, 0 }, 55 /* 7 */ { "__FUNCTION__", NULL, 0 }, 56 /* 8 */ { "__volatile", NULL, 0 }, 57 /* 9 */ { "__volatile__", NULL, 0 }, 58 /* 10 */{ "__restrict", NULL, -1 }, 59 /* 11 */{ "__typeof__", NULL, C_TYPEOF }, 60 /* 12 */{ "typeof", NULL, C_TYPEOF }, 61 /* 13 */{ "__extension__", NULL, -1 }, 62 /* 14 */{ "__signed__", NULL, 0 }, 63 /* 15 */{ "__attribute__", NULL, 0 }, 64 /* 16 */{ "__attribute", NULL, 0 }, 65 /* 17 */{ "__real__", NULL, 0 }, 66 /* 18 */{ "__imag__", NULL, 0 }, 67 /* 19 */{ "__builtin_offsetof", NULL, PCC_OFFSETOF }, 68 { NULL, NULL, 0 }, 69 }; 70 71 /* g77 stuff */ 72 #if SZFLOAT == SZLONG 73 #define G77_INTEGER LONG 74 #define G77_UINTEGER ULONG 75 #elif SZFLOAT == SZINT 76 #define G77_INTEGER INT 77 #define G77_UINTEGER UNSIGNED 78 #else 79 #error fix g77 stuff 80 #endif 81 #if SZFLOAT*2 == SZLONG 82 #define G77_LONGINT LONG 83 #define G77_ULONGINT ULONG 84 #elif SZFLOAT*2 == SZLONGLONG 85 #define G77_LONGINT LONGLONG 86 #define G77_ULONGINT ULONGLONG 87 #else 88 #error fix g77 long stuff 89 #endif 90 91 static TWORD g77t[] = { G77_INTEGER, G77_UINTEGER, G77_LONGINT, G77_ULONGINT }; 92 static char *g77n[] = { "__g77_integer", "__g77_uinteger", 93 "__g77_longint", "__g77_ulongint" }; 94 95 void 96 gcc_init() 97 { 98 struct kw *kwp; 99 NODE *p; 100 TWORD t; 101 int i; 102 103 for (kwp = kw; kwp->name; kwp++) 104 kwp->ptr = addname(kwp->name); 105 106 for (i = 0; i < 4; i++) { 107 struct symtab *sp; 108 t = ctype(g77t[i]); 109 p = block(NAME, NIL, NIL, t, NULL, MKSUE(t)); 110 sp = lookup(addname(g77n[i]), 0); 111 p->n_sp = sp; 112 defid(p, TYPEDEF); 113 nfree(p); 114 } 115 116 } 117 118 #define TS "\n#pragma tls\n# %d\n" 119 #define TLLEN sizeof(TS)+10 120 /* 121 * See if a string matches a gcc keyword. 122 */ 123 int 124 gcc_keyword(char *str, NODE **n) 125 { 126 extern int inattr, parlvl, parbal; 127 YYSTYPE *yyl = (YYSTYPE *)n; /* XXX should pass yylval */ 128 char tlbuf[TLLEN], *tw; 129 struct kw *kwp; 130 int i; 131 132 for (i = 0, kwp = kw; kwp->name; kwp++, i++) 133 if (str == kwp->ptr) 134 break; 135 if (kwp->name == NULL) 136 return 0; 137 if (kwp->rv) 138 return kwp->rv; 139 switch (i) { 140 case 1: /* __signed */ 141 case 14: /* __signed__ */ 142 *n = mkty((TWORD)SIGNED, 0, MKSUE(SIGNED)); 143 return C_TYPE; 144 case 3: /* __const */ 145 *n = block(QUALIFIER, NIL, NIL, CON, 0, 0); 146 return C_QUALIFIER; 147 case 6: /* __thread */ 148 snprintf(tlbuf, TLLEN, TS, lineno); 149 tw = &tlbuf[strlen(tlbuf)]; 150 while (tw > tlbuf) 151 cunput(*--tw); 152 return -1; 153 case 7: /* __FUNCTION__ */ 154 if (cftnsp == NULL) { 155 uerror("__FUNCTION__ outside function"); 156 yylval.strp = ""; 157 } else 158 yylval.strp = cftnsp->sname; /* XXX - not C99 */ 159 return C_STRING; 160 case 8: /* __volatile */ 161 case 9: /* __volatile__ */ 162 *n = block(QUALIFIER, NIL, NIL, VOL, 0, 0); 163 return C_QUALIFIER; 164 case 15: /* __attribute__ */ 165 case 16: /* __attribute */ 166 inattr = 1; 167 parlvl = parbal; 168 return C_ATTRIBUTE; 169 case 17: /* __real__ */ 170 yyl->intval = XREAL; 171 return C_UNOP; 172 case 18: /* __imag__ */ 173 yyl->intval = XIMAG; 174 return C_UNOP; 175 } 176 cerror("gcc_keyword"); 177 return 0; 178 } 179 180 #ifndef TARGET_ATTR 181 #define TARGET_ATTR(p, sue) 0 182 #endif 183 #ifndef ALMAX 184 #define ALMAX (ALLDOUBLE > ALLONGLONG ? ALLDOUBLE : ALLONGLONG) 185 #endif 186 187 /* allowed number of args */ 188 #define A_0ARG 0x01 189 #define A_1ARG 0x02 190 #define A_2ARG 0x04 191 #define A_3ARG 0x08 192 /* arg # is a name */ 193 #define A1_NAME 0x10 194 #define A2_NAME 0x20 195 #define A3_NAME 0x40 196 #define A_MANY 0x80 197 /* arg # is "string" */ 198 #define A1_STR 0x100 199 #define A2_STR 0x200 200 #define A3_STR 0x400 201 202 struct atax { 203 int typ; 204 char *name; 205 } atax[GCC_ATYP_MAX] = { 206 #ifndef __MSC__ 207 [GCC_ATYP_ALIGNED] = { A_0ARG|A_1ARG, "aligned" }, 208 [GCC_ATYP_PACKED] = { A_0ARG|A_1ARG, "packed" }, 209 [GCC_ATYP_SECTION] = { A_1ARG|A1_STR, "section" }, 210 [GCC_ATYP_UNUSED] = { A_0ARG, "unused" }, 211 [GCC_ATYP_DEPRECATED] = { A_0ARG, "deprecated" }, 212 [GCC_ATYP_NORETURN] = { A_0ARG, "noreturn" }, 213 [GCC_ATYP_FORMAT] = { A_3ARG|A1_NAME, "format" }, 214 [GCC_ATYP_BOUNDED] = { A_3ARG|A_MANY|A1_NAME, "bounded" }, 215 [GCC_ATYP_NONNULL] = { A_MANY, "nonnull" }, 216 [GCC_ATYP_SENTINEL] = { A_0ARG|A_1ARG, "sentinel" }, 217 [GCC_ATYP_WEAK] = { A_0ARG, "weak" }, 218 [GCC_ATYP_FORMATARG] = { A_1ARG, "format_arg" }, 219 [GCC_ATYP_GNU_INLINE] = { A_0ARG, "gnu_inline" }, 220 [GCC_ATYP_MALLOC] = { A_0ARG, "malloc" }, 221 [GCC_ATYP_NOTHROW] = { A_0ARG, "nothrow" }, 222 [GCC_ATYP_MODE] = { A_1ARG|A1_NAME, "mode" }, 223 [GCC_ATYP_CONST] = { A_0ARG, "const" }, 224 [GCC_ATYP_PURE] = { A_0ARG, "pure" }, 225 [GCC_ATYP_CONSTRUCTOR] ={ A_0ARG, "constructor" }, 226 [GCC_ATYP_DESTRUCTOR] = { A_0ARG, "destructor" }, 227 [GCC_ATYP_VISIBILITY] = { A_1ARG|A1_STR, "visibility" }, 228 [GCC_ATYP_STDCALL] = { A_0ARG, "stdcall" }, 229 [GCC_ATYP_CDECL] = { A_0ARG, "cdecl" }, 230 [GCC_ATYP_WARN_UNUSED_RESULT] = { A_0ARG, "warn_unused_result" }, 231 [GCC_ATYP_USED] = { A_0ARG, "used" }, 232 #else 233 { 0, NULL }, 234 { A_0ARG|A_1ARG, "aligned" }, 235 { A_0ARG, "packed" }, 236 { A_1ARG|A1_STR, "section" }, 237 { 0, NULL }, /* GCC_ATYP_TRANSP_UNION */ 238 { A_0ARG, "unused" }, 239 { A_0ARG, "deprecated" }, 240 { 0, NULL }, /* GCC_ATYP_MAYALIAS */ 241 { A_1ARG|A1_NAME, "mode" }, 242 { A_0ARG, "noreturn" }, 243 { A_3ARG|A1_STR, "format" }, 244 { A_MANY, "nonnull" }, 245 { A_0ARG|A_1ARG, "sentinel" }, 246 { A_0ARG, "weak" }, 247 { A_1ARG, "format_arg" }, 248 { A_0ARG, "gnu_inline" }, 249 { A_0ARG, "malloc" }, 250 { A_0ARG, "nothrow" }, 251 { A_0ARG, "const" }, 252 { A_0ARG, "pure" }, 253 { A_0ARG, "constructor" }, 254 { A_0ARG, "destructor" }, 255 { A_1ARG|A1_STR, "visibility" }, 256 { A_0ARG, "stdcall" }, 257 { A_0ARG, "cdecl" }, 258 { A_0ARG, "warn_unused_result" }, 259 { A_0ARG, "used" }, 260 { A_3ARG|A_MANY|A1_STR, "bounded" }, 261 { 0, NULL }, /* ATTR_COMPLEX */ 262 #endif 263 }; 264 #if SZPOINT(CHAR) == SZLONGLONG 265 #define GPT LONGLONG 266 #else 267 #define GPT INT 268 #endif 269 270 struct atax mods[] = { 271 { 0, NULL }, 272 { INT, "SI" }, 273 { INT, "word" }, 274 { GPT, "pointer" }, 275 { CHAR, "byte" }, 276 { CHAR, "QI" }, 277 { SHORT, "HI" }, 278 { LONGLONG, "DI" }, 279 { FLOAT, "SF" }, 280 { DOUBLE, "DF" }, 281 }; 282 #define ATSZ (sizeof(mods)/sizeof(mods[0])) 283 284 static int 285 amatch(char *s, struct atax *at, int mx) 286 { 287 int i, len; 288 289 if (s[0] == '_' && s[1] == '_') 290 s += 2; 291 len = strlen(s); 292 if (len > 2 && s[len-1] == '_' && s[len-2] == '_') 293 len -= 2; 294 for (i = 0; i < mx; i++) { 295 char *t = at[i].name; 296 if (t != NULL && strncmp(s, t, len) == 0 && t[len] == 0) 297 return i; 298 } 299 return 0; 300 } 301 302 static void 303 setaarg(int str, union gcc_aarg *aa, NODE *p) 304 { 305 if (str) { 306 if (((str & (A1_STR|A2_STR|A3_STR)) && p->n_op != STRING) || 307 ((str & (A1_NAME|A2_NAME|A3_NAME)) && p->n_op != NAME)) 308 uerror("bad arg to attribute"); 309 aa->sarg = p->n_op == STRING ? p->n_name : (char *)p->n_sp; 310 nfree(p); 311 } else 312 aa->iarg = (int)icons(eve(p)); 313 } 314 315 /* 316 * Parse attributes from an argument list. 317 */ 318 static void 319 gcc_attribs(NODE *p, void *arg) 320 { 321 NODE *q, *r; 322 gcc_ap_t *gap = arg; 323 char *name = NULL, *c; 324 int num, cw, attr, narg, i; 325 326 if (p->n_op == NAME) { 327 name = (char *)p->n_sp; 328 } else if (p->n_op == CALL || p->n_op == UCALL) { 329 name = (char *)p->n_left->n_sp; 330 } else 331 cerror("bad variable attribute"); 332 333 if ((attr = amatch(name, atax, GCC_ATYP_MAX)) == 0) { 334 werror("unsupported attribute '%s'", name); 335 goto out; 336 } 337 narg = 0; 338 if (p->n_op == CALL) 339 for (narg = 1, q = p->n_right; q->n_op == CM; q = q->n_left) 340 narg++; 341 342 cw = atax[attr].typ; 343 if (!(cw & A_MANY) && ((narg > 3) || ((cw & (1 << narg)) == 0))) { 344 uerror("wrong attribute arg count"); 345 return; 346 } 347 num = gap->num; 348 gap->ga[num].atype = attr; 349 q = p->n_right; 350 351 switch (narg) { 352 default: 353 /* XXX */ 354 while (narg-- > 3) { 355 r = q; 356 q = q->n_left; 357 tfree(r->n_right); 358 nfree(r); 359 } 360 /* FALLTHROUGH */ 361 case 3: 362 setaarg(cw & (A3_NAME|A3_STR), &gap->ga[num].a3, q->n_right); 363 r = q; 364 q = q->n_left; 365 nfree(r); 366 /* FALLTHROUGH */ 367 case 2: 368 setaarg(cw & (A2_NAME|A2_STR), &gap->ga[num].a2, q->n_right); 369 r = q; 370 q = q->n_left; 371 nfree(r); 372 /* FALLTHROUGH */ 373 case 1: 374 setaarg(cw & (A1_NAME|A1_STR), &gap->ga[num].a1, q); 375 p->n_op = UCALL; 376 /* FALLTHROUGH */ 377 case 0: 378 break; 379 } 380 381 /* some attributes must be massaged special */ 382 switch (attr) { 383 case GCC_ATYP_ALIGNED: 384 if (narg == 0) 385 gap->ga[num].a1.iarg = ALMAX; 386 else 387 gap->ga[num].a1.iarg *= SZCHAR; 388 break; 389 case GCC_ATYP_PACKED: 390 if (narg == 0) 391 gap->ga[num].a1.iarg = 1; /* bitwise align */ 392 else 393 gap->ga[num].a1.iarg *= SZCHAR; 394 break; 395 396 case GCC_ATYP_MODE: 397 if ((i = amatch(gap->ga[num].a1.sarg, mods, ATSZ)) == 0) 398 werror("unknown mode arg %s", gap->ga[num].a1.sarg); 399 gap->ga[num].a1.iarg = mods[i].typ; 400 break; 401 402 case GCC_ATYP_VISIBILITY: 403 c = gap->ga[num].a1.sarg; 404 if (strcmp(c, "default") && strcmp(c, "hidden") && 405 strcmp(c, "internal") && strcmp(c, "protected")) 406 werror("unknown visibility %s", c); 407 break; 408 409 default: 410 break; 411 } 412 out: 413 gap->num++; 414 } 415 416 /* 417 * Extract type attributes from a node tree and create a gcc_attr_pack 418 * struct based on its contents. 419 */ 420 gcc_ap_t * 421 gcc_attr_parse(NODE *p) 422 { 423 gcc_ap_t *gap; 424 NODE *q, *r; 425 int i, sz; 426 427 /* count number of elems and build tower to the left */ 428 for (q = p, i = 1; q->n_op == CM; q = q->n_left, i++) 429 if (q->n_right->n_op == CM) 430 r = q->n_right, q->n_right = q->n_left, q->n_left = r; 431 432 /* get memory for struct */ 433 sz = sizeof(struct gcc_attr_pack) + sizeof(struct gcc_attrib) * i; 434 if (blevel == 0) 435 gap = memset(permalloc(sz), 0, sz); 436 else 437 gap = tmpcalloc(sz); 438 439 flist(p, gcc_attribs, gap); 440 if (gap->num != i) 441 cerror("attribute sync error"); 442 443 tfree(p); 444 return gap; 445 } 446 447 /* 448 * Fixup struct/unions depending on attributes. 449 */ 450 void 451 gcc_tcattrfix(NODE *p, NODE *q) 452 { 453 struct symtab *sp; 454 struct suedef *sue; 455 gcc_ap_t *gap; 456 int align = 0; 457 int i, sz, coff, csz; 458 459 gap = gcc_attr_parse(q); 460 sue = p->n_sue; 461 if (sue->suega) { 462 if (p->n_sp == NULL) 463 cerror("gcc_tcattrfix"); 464 } 465 466 /* must know about align first */ 467 for (i = 0; i < gap->num; i++) 468 if (gap->ga[i].atype == GCC_ATYP_ALIGNED) 469 align = gap->ga[i].a1.iarg; 470 471 /* Check following attributes */ 472 for (i = 0; i < gap->num; i++) { 473 switch (gap->ga[i].atype) { 474 case GCC_ATYP_PACKED: 475 /* Must repack struct */ 476 /* XXX - aligned types inside? */ 477 coff = csz = 0; 478 for (sp = sue->suem; sp; sp = sp->snext) { 479 if (sp->sclass & FIELD) 480 sz = sp->sclass&FLDSIZ; 481 else 482 sz = (int)tsize(sp->stype, sp->sdf, sp->ssue); 483 SETOFF(sz, gap->ga[i].a1.iarg); 484 sp->soffset = coff; 485 coff += sz; 486 if (coff > csz) 487 csz = coff; 488 if (p->n_type == UNIONTY) 489 coff = 0; 490 } 491 SETOFF(csz, SZCHAR); 492 sue->suesize = csz; 493 sue->suealign = gap->ga[i].a1.iarg; 494 break; 495 496 case GCC_ATYP_ALIGNED: 497 break; 498 499 default: 500 werror("unsupported attribute %d", gap->ga[i].atype); 501 } 502 } 503 if (align) { 504 sue->suealign = align; 505 SETOFF(sue->suesize, sue->suealign); 506 } 507 sue->suega = gap; 508 } 509 510 /* 511 * Search for a specific attribute type. 512 */ 513 struct gcc_attrib * 514 gcc_get_attr(struct suedef *sue, int typ) 515 { 516 gcc_ap_t *gap; 517 int i; 518 519 if (sue == NULL) 520 return NULL; 521 522 if ((gap = sue->suega) == NULL) 523 return NULL; 524 525 for (i = 0; i < gap->num; i++) 526 if (gap->ga[i].atype == typ) 527 return &gap->ga[i]; 528 if (sue->suep) 529 return gcc_get_attr(sue->suep, typ); 530 return NULL; 531 } 532 533 #ifdef PCC_DEBUG 534 void 535 dump_attr(gcc_ap_t *gap) 536 { 537 int i; 538 539 printf("GCC attributes\n"); 540 if (gap == NULL) 541 return; 542 for (i = 0; i < gap->num; i++) { 543 printf("%d: ", gap->ga[i].atype); 544 printf("%d %d %d", gap->ga[i].a1.iarg, 545 gap->ga[i].a2.iarg, gap->ga[i].a3.iarg); 546 printf("\n"); 547 } 548 } 549 #endif 550 #endif 551