1/* Id: local.c,v 1.32 2011/11/13 22:30:18 gmcgarry Exp */ 2/* $NetBSD$ */ 3/* 4 * Copyright (c) 2007 Gregory McGarry (g.mcgarry@ieee.org). 5 * Copyright (c) 2003 Anders Magnusson (ragge@ludd.luth.se). 6 * All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 */ 28 29/* 30 * We define location operations which operate on the expression tree 31 * during the first pass (before sending to the backend for code generation.) 32 */ 33 34#include <assert.h> 35 36#include "pass1.h" 37 38extern void defalign(int); 39 40/* 41 * clocal() is called to do local transformations on 42 * an expression tree before being sent to the backend. 43 */ 44NODE * 45clocal(NODE *p) 46{ 47 struct symtab *q; 48 NODE *l, *r, *t; 49 int o; 50 int ty; 51 int tmpnr, isptrvoid = 0; 52 char *n; 53 54 o = p->n_op; 55 switch (o) { 56 57 case STASG: 58 59 l = p->n_left; 60 r = p->n_right; 61 if (r->n_op != STCALL && r->n_op != USTCALL) 62 return p; 63 64 /* assign left node as first argument to function */ 65 nfree(p); 66 t = block(REG, NIL, NIL, r->n_type, r->n_df, r->n_ap); 67 l->n_rval = R0; 68 l = buildtree(ADDROF, l, NIL); 69 l = buildtree(ASSIGN, t, l); 70 71 if (r->n_right->n_op != CM) { 72 r->n_right = block(CM, l, r->n_right, INT, 0, 0); 73 } else { 74 for (t = r->n_right; t->n_left->n_op == CM; 75 t = t->n_left) 76 ; 77 t->n_left = block(CM, l, t->n_left, INT, 0, 0); 78 } 79 return r; 80 81 case CALL: 82 case STCALL: 83 case USTCALL: 84 if (p->n_type == VOID) 85 break; 86 /* 87 * if the function returns void*, ecode() invokes 88 * delvoid() to convert it to uchar*. 89 * We just let this happen on the ASSIGN to the temp, 90 * and cast the pointer back to void* on access 91 * from the temp. 92 */ 93 if (p->n_type == PTR+VOID) 94 isptrvoid = 1; 95 r = tempnode(0, p->n_type, p->n_df, p->n_ap); 96 tmpnr = regno(r); 97 r = block(ASSIGN, r, p, p->n_type, p->n_df, p->n_ap); 98 99 p = tempnode(tmpnr, r->n_type, r->n_df, r->n_ap); 100 if (isptrvoid) { 101 p = block(PCONV, p, NIL, PTR+VOID, p->n_df, 0); 102 } 103 p = buildtree(COMOP, r, p); 104 break; 105 106 case NAME: 107 if ((q = p->n_sp) == NULL) 108 return p; 109 if (blevel == 0) 110 return p; 111 112 switch (q->sclass) { 113 case PARAM: 114 case AUTO: 115 /* fake up a structure reference */ 116 r = block(REG, NIL, NIL, PTR+STRTY, 0, 0); 117 r->n_lval = 0; 118 r->n_rval = FPREG; 119 p = stref(block(STREF, r, p, 0, 0, 0)); 120 break; 121 case REGISTER: 122 p->n_op = REG; 123 p->n_lval = 0; 124 p->n_rval = q->soffset; 125 break; 126 case STATIC: 127 if (q->slevel > 0) { 128 p->n_lval = 0; 129 p->n_sp = q; 130 } 131 /* FALL-THROUGH */ 132 default: 133 ty = p->n_type; 134 n = p->n_sp->soname ? p->n_sp->soname : p->n_sp->sname; 135 if (strncmp(n, "__builtin", 9) == 0) 136 break; 137 p = block(ADDROF, p, NIL, INCREF(ty), p->n_df, p->n_ap); 138 p = block(UMUL, p, NIL, ty, p->n_df, p->n_ap); 139 break; 140 } 141 break; 142 143 case STNAME: 144 if ((q = p->n_sp) == NULL) 145 return p; 146 if (q->sclass != STNAME) 147 return p; 148 ty = p->n_type; 149 p = block(ADDROF, p, NIL, INCREF(ty), 150 p->n_df, p->n_ap); 151 p = block(UMUL, p, NIL, ty, p->n_df, p->n_ap); 152 break; 153 154 case FORCE: 155 /* put return value in return reg */ 156 p->n_op = ASSIGN; 157 p->n_right = p->n_left; 158 p->n_left = block(REG, NIL, NIL, p->n_type, 0, 0); 159 p->n_left->n_rval = p->n_left->n_type == BOOL ? 160 RETREG(BOOL_TYPE) : RETREG(p->n_type); 161 break; 162 163 case SCONV: 164 l = p->n_left; 165 if (p->n_type == l->n_type) { 166 nfree(p); 167 return l; 168 } 169 if ((p->n_type & TMASK) == 0 && (l->n_type & TMASK) == 0 && 170 tsize(p->n_type, p->n_df, p->n_ap) == tsize(l->n_type, l->n_df, l->n_ap)) { 171 if (p->n_type != FLOAT && p->n_type != DOUBLE && 172 l->n_type != FLOAT && l->n_type != DOUBLE && 173 l->n_type != LDOUBLE && p->n_type != LDOUBLE) { 174 if (l->n_op == NAME || l->n_op == UMUL || 175 l->n_op == TEMP) { 176 l->n_type = p->n_type; 177 nfree(p); 178 return l; 179 } 180 } 181 } 182 183 if (l->n_op == ICON) { 184 CONSZ val = l->n_lval; 185 186 if (!ISPTR(p->n_type)) /* Pointers don't need to be conv'd */ 187 switch (p->n_type) { 188 case BOOL: 189 l->n_lval = l->n_lval != 0; 190 break; 191 case CHAR: 192 l->n_lval = (char)val; 193 break; 194 case UCHAR: 195 l->n_lval = val & 0377; 196 break; 197 case SHORT: 198 l->n_lval = (short)val; 199 break; 200 case USHORT: 201 l->n_lval = val & 0177777; 202 break; 203 case ULONG: 204 case UNSIGNED: 205 l->n_lval = val & 0xffffffff; 206 break; 207 case LONG: 208 case INT: 209 l->n_lval = (int)val; 210 break; 211 case LONGLONG: 212 l->n_lval = (long long)val; 213 break; 214 case ULONGLONG: 215 l->n_lval = val; 216 break; 217 case VOID: 218 break; 219 case LDOUBLE: 220 case DOUBLE: 221 case FLOAT: 222 l->n_op = FCON; 223 l->n_dcon = val; 224 break; 225 default: 226 cerror("unknown type %d", l->n_type); 227 } 228 l->n_type = p->n_type; 229 l->n_ap = 0; 230 nfree(p); 231 return l; 232 } else if (p->n_op == FCON) { 233 l->n_lval = l->n_dcon; 234 l->n_sp = NULL; 235 l->n_op = ICON; 236 l->n_type = p->n_type; 237 l->n_ap = 0; 238 nfree(p); 239 return clocal(l); 240 } 241 if ((DEUNSIGN(p->n_type) == CHAR || 242 DEUNSIGN(p->n_type) == SHORT) && 243 (l->n_type == FLOAT || l->n_type == DOUBLE || 244 l->n_type == LDOUBLE)) { 245 p = block(SCONV, p, NIL, p->n_type, p->n_df, p->n_ap); 246 p->n_left->n_type = INT; 247 return p; 248 } 249 break; 250 251 case PCONV: 252 l = p->n_left; 253 if (l->n_op == ICON) { 254 l->n_lval = (unsigned)l->n_lval; 255 goto delp; 256 } 257 if (l->n_type < INT || DEUNSIGN(l->n_type) == LONGLONG) { 258 p->n_left = block(SCONV, l, NIL, UNSIGNED, 0, 0); 259 break; 260 } 261 if (l->n_op == SCONV) 262 break; 263 if (l->n_op == ADDROF && l->n_left->n_op == TEMP) 264 goto delp; 265 if (p->n_type > BTMASK && l->n_type > BTMASK) 266 goto delp; 267 break; 268 269 delp: 270 l->n_type = p->n_type; 271 l->n_qual = p->n_qual; 272 l->n_df = p->n_df; 273 l->n_ap = p->n_ap; 274 nfree(p); 275 p = l; 276 break; 277 } 278 279 return p; 280} 281 282/* 283 * Called before sending the tree to the backend. 284 */ 285void 286myp2tree(NODE *p) 287{ 288 struct symtab *sp; 289 290 if (p->n_op != FCON) 291 return; 292 293#define IALLOC(sz) (isinlining ? permalloc(sz) : tmpalloc(sz)) 294 295 sp = IALLOC(sizeof(struct symtab)); 296 sp->sclass = STATIC; 297 sp->sap = 0; 298 sp->slevel = 1; /* fake numeric label */ 299 sp->soffset = getlab(); 300 sp->sflags = 0; 301 sp->stype = p->n_type; 302 sp->squal = (CON >> TSHIFT); 303 304 defloc(sp); 305 ninval(0, tsize(sp->stype, sp->sdf, sp->sap), p); 306 307 p->n_op = NAME; 308 p->n_lval = 0; 309 p->n_sp = sp; 310} 311 312/* 313 * Called during the first pass to determine if a NAME can be addressed. 314 * 315 * Return nonzero if supported, otherwise return 0. 316 */ 317int 318andable(NODE *p) 319{ 320 if (blevel == 0) 321 return 1; 322 if (ISFTN(p->n_type)) 323 return 1; 324 return 0; 325} 326 327/* 328 * Return 1 if a variable of type 't' is OK to put in register. 329 */ 330int 331cisreg(TWORD t) 332{ 333 if (t == FLOAT || t == DOUBLE || t == LDOUBLE) 334 return 0; /* not yet */ 335 return 1; 336} 337 338/* 339 * Allocate bits from the stack for dynamic-sized arrays. 340 * 341 * 'p' is the tree which represents the type being allocated. 342 * 'off' is the number of 'p's to be allocated. 343 * 't' is the storeable node where the address is written. 344 */ 345void 346spalloc(NODE *t, NODE *p, OFFSZ off) 347{ 348 NODE *sp; 349 350 p = buildtree(MUL, p, bcon(off/SZCHAR)); /* XXX word alignment? */ 351 352 /* sub the size from sp */ 353 sp = block(REG, NIL, NIL, p->n_type, 0, 0); 354 sp->n_lval = 0; 355 sp->n_rval = SP; 356 ecomp(buildtree(MINUSEQ, sp, p)); 357 358 /* save the address of sp */ 359 sp = block(REG, NIL, NIL, PTR+INT, t->n_df, t->n_ap); 360 sp->n_lval = 0; 361 sp->n_rval = SP; 362 t->n_type = sp->n_type; 363 ecomp(buildtree(ASSIGN, t, sp)); 364} 365 366/* 367 * Print an integer constant node, may be associated with a label. 368 * Do not free the node after use. 369 * 'off' is bit offset from the beginning of the aggregate 370 * 'fsz' is the number of bits this is referring to 371 */ 372int 373ninval(CONSZ off, int fsz, NODE *p) 374{ 375 union { float f; double d; int i[2]; } u; 376 struct symtab *q; 377 TWORD t; 378 int i, j; 379 380 t = p->n_type; 381 if (t > BTMASK) 382 t = p->n_type = INT; /* pointer */ 383 384 if (p->n_op == ICON && p->n_sp != NULL && DEUNSIGN(t) != INT) 385 uerror("element not constant"); 386 387 switch (t) { 388 case LONGLONG: 389 case ULONGLONG: 390 i = (p->n_lval >> 32); 391 j = (p->n_lval & 0xffffffff); 392 p->n_type = INT; 393 if (features(FEATURE_BIGENDIAN)) { 394 p->n_lval = i; 395 ninval(off+32, 32, p); 396 p->n_lval = j; 397 ninval(off, 32, p); 398 } else { 399 p->n_lval = j; 400 ninval(off, 32, p); 401 p->n_lval = i; 402 ninval(off+32, 32, p); 403 } 404 break; 405 case INT: 406 case UNSIGNED: 407 printf("\t.word 0x%x", (int)p->n_lval); 408 if ((q = p->n_sp) != NULL) { 409 if ((q->sclass == STATIC && q->slevel > 0)) { 410 printf("+" LABFMT, q->soffset); 411 } else 412 printf("+%s", 413 q->soname ? q->soname : exname(q->sname)); 414 } 415 printf("\n"); 416 break; 417 case LDOUBLE: 418 case DOUBLE: 419 u.d = (double)p->n_dcon; 420#if defined(HOST_BIG_ENDIAN) 421 if (features(FEATURE_BIGENDIAN)) 422#else 423 if (!features(FEATURE_BIGENDIAN)) 424#endif 425 printf("\t.word\t0x%x\n\t.word\t0x%x\n", 426 u.i[0], u.i[1]); 427 else 428 printf("\t.word\t0x%x\n\t.word\t0x%x\n", 429 u.i[1], u.i[0]); 430 break; 431 case FLOAT: 432 u.f = (float)p->n_dcon; 433 printf("\t.word\t0x%x\n", u.i[0]); 434 break; 435 default: 436 return 0; 437 } 438 return 1; 439} 440 441/* 442 * Prefix a leading underscore to a global variable (if necessary). 443 */ 444char * 445exname(char *p) 446{ 447 return (p == NULL ? "" : p); 448} 449 450/* 451 * Map types which are not defined on the local machine. 452 */ 453TWORD 454ctype(TWORD type) 455{ 456 switch (BTYPE(type)) { 457 case LONG: 458 MODTYPE(type,INT); 459 break; 460 case ULONG: 461 MODTYPE(type,UNSIGNED); 462 break; 463 } 464 return (type); 465} 466 467/* 468 * Before calling a function do any tree re-writing for the local machine. 469 * 470 * 'p' is the function tree (NAME) 471 * 'q' is the CM-separated list of arguments. 472 */ 473void 474calldec(NODE *p, NODE *q) 475{ 476} 477 478/* 479 * While handling uninitialised variables, handle variables marked extern. 480 */ 481void 482extdec(struct symtab *q) 483{ 484} 485 486/* make a common declaration for id, if reasonable */ 487void 488defzero(struct symtab *sp) 489{ 490 int off; 491 492 off = tsize(sp->stype, sp->sdf, sp->sap); 493 off = (off+(SZCHAR-1))/SZCHAR; 494 printf(" .%scomm ", sp->sclass == STATIC ? "l" : ""); 495 if (sp->slevel == 0) 496 printf("%s,0%o\n", 497 sp->soname ? sp->soname : exname(sp->sname), off); 498 else 499 printf(LABFMT ",0%o\n", sp->soffset, off); 500} 501 502/* 503 * va_start(ap, last) implementation. 504 * 505 * f is the NAME node for this builtin function. 506 * a is the argument list containing: 507 * CM 508 * ap last 509 */ 510NODE * 511arm_builtin_stdarg_start(NODE *f, NODE *a) 512{ 513 NODE *p, *q; 514 int sz = 1; 515 516 /* check num args and type */ 517 if (a == NULL || a->n_op != CM || a->n_left->n_op == CM || 518 !ISPTR(a->n_left->n_type)) 519 goto bad; 520 521 /* must first deal with argument size; use int size */ 522 p = a->n_right; 523 if (p->n_type < INT) { 524 /* round up to word */ 525 sz = SZINT / tsize(p->n_type, p->n_df, p->n_ap); 526 } 527 528 p = buildtree(ADDROF, p, NIL); /* address of last arg */ 529 p = optim(buildtree(PLUS, p, bcon(sz))); 530 q = block(NAME, NIL, NIL, PTR+VOID, 0, 0); 531 q = buildtree(CAST, q, p); 532 p = q->n_right; 533 nfree(q->n_left); 534 nfree(q); 535 p = buildtree(ASSIGN, a->n_left, p); 536 tfree(f); 537 nfree(a); 538 539 return p; 540 541bad: 542 uerror("bad argument to __builtin_stdarg_start"); 543 return bcon(0); 544} 545 546NODE * 547arm_builtin_va_arg(NODE *f, NODE *a) 548{ 549 NODE *p, *q, *r; 550 int sz, tmpnr; 551 552 /* check num args and type */ 553 if (a == NULL || a->n_op != CM || a->n_left->n_op == CM || 554 !ISPTR(a->n_left->n_type) || a->n_right->n_op != TYPE) 555 goto bad; 556 557 r = a->n_right; 558 559 /* get type size */ 560 sz = tsize(r->n_type, r->n_df, r->n_ap) / SZCHAR; 561 if (sz < SZINT/SZCHAR) { 562 werror("%s%s promoted to int when passed through ...", 563 ISUNSIGNED(r->n_type) ? "unsigned " : "", 564 DEUNSIGN(r->n_type) == SHORT ? "short" : "char"); 565 sz = SZINT/SZCHAR; 566 } 567 568 /* alignment */ 569 p = tcopy(a->n_left); 570 if (sz > SZINT/SZCHAR && r->n_type != UNIONTY && r->n_type != STRTY) { 571 p = buildtree(PLUS, p, bcon(ALSTACK/8 - 1)); 572 p = block(AND, p, bcon(-ALSTACK/8), p->n_type, p->n_df, p->n_ap); 573 } 574 575 /* create a copy to a temp node */ 576 q = tempnode(0, p->n_type, p->n_df, p->n_ap); 577 tmpnr = regno(q); 578 p = buildtree(ASSIGN, q, p); 579 580 q = tempnode(tmpnr, p->n_type, p->n_df,p->n_ap); 581 q = buildtree(PLUS, q, bcon(sz)); 582 q = buildtree(ASSIGN, a->n_left, q); 583 584 q = buildtree(COMOP, p, q); 585 586 nfree(a->n_right); 587 nfree(a); 588 nfree(f); 589 590 p = tempnode(tmpnr, INCREF(r->n_type), r->n_df, r->n_ap); 591 p = buildtree(UMUL, p, NIL); 592 p = buildtree(COMOP, q, p); 593 594 return p; 595 596bad: 597 uerror("bad argument to __builtin_va_arg"); 598 return bcon(0); 599} 600 601NODE * 602arm_builtin_va_end(NODE *f, NODE *a) 603{ 604 tfree(f); 605 tfree(a); 606 607 return bcon(0); 608} 609 610NODE * 611arm_builtin_va_copy(NODE *f, NODE *a) 612{ 613 if (a == NULL || a->n_op != CM || a->n_left->n_op == CM) 614 goto bad; 615 tfree(f); 616 f = buildtree(ASSIGN, a->n_left, a->n_right); 617 nfree(a); 618 return f; 619 620bad: 621 uerror("bad argument to __buildtin_va_copy"); 622 return bcon(0); 623} 624 625char *nextsect; 626static int constructor; 627static int destructor; 628 629/* 630 * Give target the opportunity of handling pragmas. 631 */ 632int 633mypragma(char *str) 634{ 635 char *a2 = pragtok(NULL); 636 637 if (strcmp(str, "tls") == 0) { 638 uerror("thread-local storage not supported for this target"); 639 return 1; 640 } 641 if (strcmp(str, "constructor") == 0 || strcmp(str, "init") == 0) { 642 constructor = 1; 643 return 1; 644 } 645 if (strcmp(str, "destructor") == 0 || strcmp(str, "fini") == 0) { 646 destructor = 1; 647 return 1; 648 } 649 if (strcmp(str, "section") == 0 && a2 != NULL) { 650 nextsect = newstring(a2, strlen(a2)); 651 return 1; 652 } 653 654 return 0; 655} 656 657/* 658 * Called when a identifier has been declared, to give target last word. 659 */ 660void 661fixdef(struct symtab *sp) 662{ 663 if ((constructor || destructor) && (sp->sclass != PARAM)) { 664 printf("\t.section .%ctors,\"aw\",@progbits\n", 665 constructor ? 'c' : 'd'); 666 printf("\t.p2align 2\n"); 667 printf("\t.long %s\n", exname(sp->sname)); 668 printf("\t.previous\n"); 669 constructor = destructor = 0; 670 } 671} 672 673void 674pass1_lastchance(struct interpass *ip) 675{ 676} 677