1 /* Id: local.c,v 1.26 2009/09/07 08:06:35 gmcgarry Exp */ 2 /* $NetBSD: local.c,v 1.1.1.3 2010/06/03 18:57:26 plunky Exp $ */ 3 /* 4 * Copyright (c) 2003 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 #include <assert.h> 31 #include "pass1.h" 32 33 #define IALLOC(sz) (isinlining ? permalloc(sz) : tmpalloc(sz)) 34 35 extern int kflag; 36 37 static void simmod(NODE *p); 38 39 /* this file contains code which is dependent on the target machine */ 40 41 #if defined(MACHOABI) 42 43 /* 44 * Keep track of PIC stubs. 45 */ 46 47 void 48 addstub(struct stub *list, char *name) 49 { 50 struct stub *s; 51 52 DLIST_FOREACH(s, list, link) { 53 if (strcmp(s->name, name) == 0) 54 return; 55 } 56 57 s = permalloc(sizeof(struct stub)); 58 s->name = permalloc(strlen(name) + 1); 59 strcpy(s->name, name); 60 DLIST_INSERT_BEFORE(list, s, link); 61 } 62 63 #endif 64 65 66 /* 67 * Make a symtab entry for PIC use. 68 */ 69 static struct symtab * 70 picsymtab(char *p, char *s, char *s2) 71 { 72 struct symtab *sp = IALLOC(sizeof(struct symtab)); 73 size_t len = strlen(p) + strlen(s) + strlen(s2) + 1; 74 75 sp->sname = sp->soname = IALLOC(len); 76 strlcpy(sp->soname, p, len); 77 strlcat(sp->soname, s, len); 78 strlcat(sp->soname, s2, len); 79 sp->sclass = EXTERN; 80 sp->sflags = sp->slevel = 0; 81 82 return sp; 83 } 84 85 int gotnr; /* tempnum for GOT register */ 86 87 /* 88 * Create a reference for an extern variable. 89 */ 90 static NODE * 91 picext(NODE *p) 92 { 93 NODE *q; 94 struct symtab *sp; 95 char *name; 96 97 name = p->n_sp->soname ? p->n_sp->soname : exname(p->n_sp->sname); 98 99 if (strncmp(name, "__builtin", 9) == 0) 100 return p; 101 102 #if defined(ELFABI) 103 104 sp = picsymtab("", name, "@got(31)"); 105 q = xbcon(0, sp, PTR+VOID); 106 q = block(UMUL, q, 0, PTR+VOID, 0, MKSUE(VOID)); 107 108 #elif defined(MACHOABI) 109 110 char buf2[64]; 111 NODE *r; 112 char *fname; 113 114 fname = cftnsp->soname ? cftnsp->soname : cftnsp->sname; 115 116 if (p->n_sp->sclass == EXTDEF) { 117 snprintf(buf2, 64, "-L%s$pb", fname); 118 sp = picsymtab("", name, buf2); 119 } else { 120 snprintf(buf2, 64, "$non_lazy_ptr-L%s$pb", fname); 121 sp = picsymtab("L", name, buf2); 122 addstub(&nlplist, name); 123 } 124 #if USE_GOTNR 125 q = tempnode(gotnr, PTR+VOID, 0, MKSUE(VOID)); 126 #else 127 q = block(REG, NIL, NIL, PTR+VOID, 0, MKSUE(VOID)); 128 regno(q) = GOTREG; 129 #endif 130 r = xbcon(0, sp, INT); 131 q = buildtree(PLUS, q, r); 132 133 if (p->n_sp->sclass != EXTDEF) 134 q = block(UMUL, q, 0, PTR+VOID, 0, MKSUE(VOID)); 135 136 #endif 137 138 q = block(UMUL, q, 0, p->n_type, p->n_df, p->n_sue); 139 q->n_sp = p->n_sp; /* for init */ 140 nfree(p); 141 142 return q; 143 } 144 145 /* 146 * Create a reference for a static variable 147 */ 148 149 static NODE * 150 picstatic(NODE *p) 151 { 152 NODE *q; 153 struct symtab *sp; 154 155 #if defined(ELFABI) 156 char *n; 157 158 if (p->n_sp->slevel > 0) { 159 char buf[64]; 160 snprintf(buf, 64, LABFMT, (int)p->n_sp->soffset); 161 sp = picsymtab("", buf, "@got(31)"); 162 } else { 163 n = p->n_sp->soname ? p->n_sp->soname : p->n_sp->sname; 164 sp = picsymtab("", exname(n), "@got(31)"); 165 } 166 sp->sclass = STATIC; 167 sp->stype = p->n_sp->stype; 168 q = xbcon(0, sp, PTR+VOID); 169 q = block(UMUL, q, 0, p->n_type, p->n_df, p->n_sue); 170 q->n_sp = p->n_sp; 171 nfree(p); 172 173 #elif defined(MACHOABI) 174 175 char buf2[64]; 176 NODE *r; 177 178 snprintf(buf2, 64, "-L%s$pb", 179 cftnsp->soname ? cftnsp->soname : cftnsp->sname); 180 181 if (p->n_sp->slevel > 0) { 182 char buf1[64]; 183 snprintf(buf1, 64, LABFMT, (int)p->n_sp->soffset); 184 sp = picsymtab("", buf1, buf2); 185 } else { 186 char *name = p->n_sp->soname ? p->n_sp->soname : exname(p->n_sp->sname); 187 sp = picsymtab("", name, buf2); 188 } 189 sp->sclass = STATIC; 190 sp->stype = p->n_sp->stype; 191 #if USE_GOTNR 192 q = tempnode(gotnr, PTR+VOID, 0, MKSUE(VOID)); 193 #else 194 q = block(REG, NIL, NIL, PTR+VOID, 0, MKSUE(VOID)); 195 regno(q) = GOTREG; 196 #endif 197 r = xbcon(0, sp, INT); 198 q = buildtree(PLUS, q, r); 199 q = block(UMUL, q, 0, p->n_type, p->n_df, p->n_sue); 200 q->n_sp = p->n_sp; 201 nfree(p); 202 203 #endif 204 205 return q; 206 } 207 208 static NODE * 209 convert_ulltof(NODE *p) 210 { 211 NODE *q, *r, *l, *t; 212 int ty; 213 int tmpnr; 214 215 ty = p->n_type; 216 l = p->n_left; 217 nfree(p); 218 219 q = tempnode(0, ULONGLONG, 0, MKSUE(ULONGLONG)); 220 tmpnr = regno(q); 221 t = buildtree(ASSIGN, q, l); 222 ecomp(t); 223 224 #if 0 225 q = tempnode(tmpnr, ULONGLONG, 0, MKSUE(ULONGLONG)); 226 q = block(SCONV, q, NIL, LONGLONG, 0, MKSUE(LONGLONG)); 227 #endif 228 q = tempnode(tmpnr, LONGLONG, 0, MKSUE(LONGLONG)); 229 r = block(SCONV, q, NIL, ty, 0, MKSUE(ty)); 230 231 q = tempnode(tmpnr, ULONGLONG, 0, MKSUE(ULONGLONG)); 232 q = block(RS, q, bcon(1), ULONGLONG, 0, MKSUE(ULONGLONG)); 233 q = block(SCONV, q, NIL, LONGLONG, 0, MKSUE(LONGLONG)); 234 q = block(SCONV, q, NIL, ty, 0, MKSUE(ty)); 235 t = block(FCON, NIL, NIL, ty, 0, MKSUE(ty)); 236 t->n_dcon = 2; 237 l = block(MUL, q, t, ty, 0, MKSUE(ty)); 238 239 r = buildtree(COLON, l, r); 240 241 q = tempnode(tmpnr, ULONGLONG, 0, MKSUE(ULONGLONG)); 242 q = block(SCONV, q, NIL, LONGLONG, 0, MKSUE(LONGLONG)); 243 l = block(LE, q, xbcon(0, NULL, LONGLONG), INT, 0, MKSUE(INT)); 244 245 return clocal(buildtree(QUEST, l, r)); 246 247 } 248 249 250 /* clocal() is called to do local transformations on 251 * an expression tree preparitory to its being 252 * written out in intermediate code. 253 * 254 * the major essential job is rewriting the 255 * automatic variables and arguments in terms of 256 * REG and OREG nodes 257 * conversion ops which are not necessary are also clobbered here 258 * in addition, any special features (such as rewriting 259 * exclusive or) are easily handled here as well 260 */ 261 NODE * 262 clocal(NODE *p) 263 { 264 265 struct symtab *q; 266 NODE *r, *l; 267 int o; 268 int m; 269 TWORD t; 270 int isptrvoid = 0; 271 int tmpnr; 272 273 #ifdef PCC_DEBUG 274 if (xdebug) { 275 printf("clocal: %p\n", p); 276 fwalk(p, eprint, 0); 277 } 278 #endif 279 switch (o = p->n_op) { 280 281 case ADDROF: 282 #ifdef PCC_DEBUG 283 if (xdebug) { 284 printf("clocal(): ADDROF\n"); 285 printf("type: 0x%x\n", p->n_type); 286 } 287 #endif 288 /* XXX cannot takes addresses of PARAMs */ 289 290 if (kflag == 0 || blevel == 0) 291 break; 292 /* char arrays may end up here */ 293 l = p->n_left; 294 if (l->n_op != NAME || 295 (l->n_type != ARY+CHAR && l->n_type != ARY+WCHAR_TYPE)) 296 break; 297 l = p; 298 p = picstatic(p->n_left); 299 nfree(l); 300 if (p->n_op != UMUL) 301 cerror("ADDROF error"); 302 l = p; 303 p = p->n_left; 304 nfree(l); 305 break; 306 307 case NAME: 308 if ((q = p->n_sp) == NULL) 309 return p; /* Nothing to care about */ 310 311 switch (q->sclass) { 312 313 case PARAM: 314 case AUTO: 315 /* fake up a structure reference */ 316 r = block(REG, NIL, NIL, PTR+STRTY, 0, 0); 317 r->n_lval = 0; 318 r->n_rval = FPREG; 319 p = stref(block(STREF, r, p, 0, 0, 0)); 320 break; 321 322 case USTATIC: 323 if (kflag == 0) 324 break; 325 /* FALLTHROUGH */ 326 327 case STATIC: 328 if (kflag == 0) { 329 if (q->slevel == 0) 330 break; 331 p->n_lval = 0; 332 } else if (blevel > 0) { 333 p = picstatic(p); 334 } 335 break; 336 337 case REGISTER: 338 p->n_op = REG; 339 p->n_lval = 0; 340 p->n_rval = q->soffset; 341 break; 342 343 case EXTERN: 344 case EXTDEF: 345 if (kflag == 0) 346 break; 347 if (blevel > 0) 348 p = picext(p); 349 break; 350 } 351 break; 352 353 case UCALL: 354 case CALL: 355 case USTCALL: 356 case STCALL: 357 if (p->n_type == VOID) 358 break; 359 /* 360 * if the function returns void*, ecode() invokes 361 * delvoid() to convert it to uchar*. 362 * We just let this happen on the ASSIGN to the temp, 363 * and cast the pointer back to void* on access 364 * from the temp. 365 */ 366 if (p->n_type == PTR+VOID) 367 isptrvoid = 1; 368 r = tempnode(0, p->n_type, p->n_df, p->n_sue); 369 tmpnr = regno(r); 370 r = buildtree(ASSIGN, r, p); 371 372 p = tempnode(tmpnr, r->n_type, r->n_df, r->n_sue); 373 if (isptrvoid) { 374 p = block(PCONV, p, NIL, PTR+VOID, 375 p->n_df, MKSUE(PTR+VOID)); 376 } 377 #if 1 378 p = buildtree(COMOP, r, p); 379 #else 380 /* XXX this doesn't work if the call is already in a COMOP */ 381 r = clocal(r); 382 ecomp(r); 383 #endif 384 break; 385 386 case CBRANCH: 387 l = p->n_left; 388 389 /* 390 * Remove unnecessary conversion ops. 391 */ 392 if (clogop(l->n_op) && l->n_left->n_op == SCONV) { 393 if (coptype(l->n_op) != BITYPE) 394 break; 395 if (l->n_right->n_op == ICON) { 396 r = l->n_left->n_left; 397 if (r->n_type >= FLOAT && r->n_type <= LDOUBLE) 398 break; 399 /* Type must be correct */ 400 t = r->n_type; 401 nfree(l->n_left); 402 l->n_left = r; 403 l->n_type = t; 404 l->n_right->n_type = t; 405 } 406 } 407 break; 408 409 case PCONV: 410 /* Remove redundant PCONV's. Be careful */ 411 l = p->n_left; 412 if (l->n_op == ICON) { 413 l->n_lval = (unsigned)l->n_lval; 414 goto delp; 415 } 416 if (l->n_type < INT || DEUNSIGN(l->n_type) == LONGLONG) { 417 /* float etc? */ 418 p->n_left = block(SCONV, l, NIL, 419 UNSIGNED, 0, MKSUE(UNSIGNED)); 420 break; 421 } 422 /* if left is SCONV, cannot remove */ 423 if (l->n_op == SCONV) 424 break; 425 426 /* avoid ADDROF TEMP */ 427 if (l->n_op == ADDROF && l->n_left->n_op == TEMP) 428 break; 429 430 /* if conversion to another pointer type, just remove */ 431 if (p->n_type > BTMASK && l->n_type > BTMASK) 432 goto delp; 433 break; 434 435 delp: l->n_type = p->n_type; 436 l->n_qual = p->n_qual; 437 l->n_df = p->n_df; 438 l->n_sue = p->n_sue; 439 nfree(p); 440 p = l; 441 break; 442 443 case SCONV: 444 l = p->n_left; 445 446 if (p->n_type == l->n_type) { 447 nfree(p); 448 return l; 449 } 450 451 if ((p->n_type & TMASK) == 0 && (l->n_type & TMASK) == 0 && 452 btdims[p->n_type].suesize == btdims[l->n_type].suesize) { 453 if (p->n_type != FLOAT && p->n_type != DOUBLE && 454 l->n_type != FLOAT && l->n_type != DOUBLE && 455 l->n_type != LDOUBLE && p->n_type != LDOUBLE) { 456 if (l->n_op == NAME || l->n_op == UMUL || 457 l->n_op == TEMP) { 458 l->n_type = p->n_type; 459 nfree(p); 460 return l; 461 } 462 } 463 } 464 465 if (DEUNSIGN(p->n_type) == INT && DEUNSIGN(l->n_type) == INT && 466 coptype(l->n_op) == BITYPE) { 467 l->n_type = p->n_type; 468 nfree(p); 469 return l; 470 } 471 472 /* 473 * if converting ULONGLONG to FLOAT/(L)DOUBLE, 474 * replace ___floatunsdidf() with ___floatdidf() 475 */ 476 if (l->n_type == ULONGLONG && p->n_type >= FLOAT && 477 p->n_type <= LDOUBLE) { 478 return convert_ulltof(p); 479 } 480 481 o = l->n_op; 482 m = p->n_type; 483 484 if (o == ICON) { 485 CONSZ val = l->n_lval; 486 487 if (!ISPTR(m)) /* Pointers don't need to be conv'd */ 488 switch (m) { 489 case BOOL: 490 l->n_lval = l->n_lval != 0; 491 break; 492 case CHAR: 493 l->n_lval = (char)val; 494 break; 495 case UCHAR: 496 l->n_lval = val & 0377; 497 break; 498 case SHORT: 499 l->n_lval = (short)val; 500 break; 501 case USHORT: 502 l->n_lval = val & 0177777; 503 break; 504 case ULONG: 505 case UNSIGNED: 506 l->n_lval = val & 0xffffffff; 507 break; 508 case LONG: 509 case INT: 510 l->n_lval = (int)val; 511 break; 512 case LONGLONG: 513 l->n_lval = (long long)val; 514 break; 515 case ULONGLONG: 516 l->n_lval = val; 517 break; 518 case VOID: 519 break; 520 case LDOUBLE: 521 case DOUBLE: 522 case FLOAT: 523 l->n_op = FCON; 524 l->n_dcon = val; 525 break; 526 default: 527 cerror("unknown type %d", m); 528 } 529 l->n_type = m; 530 l->n_sue = MKSUE(m); 531 nfree(p); 532 return l; 533 } else if (o == FCON) { 534 l->n_lval = l->n_dcon; 535 l->n_sp = NULL; 536 l->n_op = ICON; 537 l->n_type = m; 538 l->n_sue = MKSUE(m); 539 nfree(p); 540 return clocal(l); 541 } 542 if (DEUNSIGN(p->n_type) == SHORT && 543 DEUNSIGN(l->n_type) == SHORT) { 544 nfree(p); 545 p = l; 546 } 547 if ((DEUNSIGN(p->n_type) == CHAR || 548 DEUNSIGN(p->n_type) == SHORT) && 549 (l->n_type == FLOAT || l->n_type == DOUBLE || 550 l->n_type == LDOUBLE)) { 551 p = block(SCONV, p, NIL, p->n_type, p->n_df, p->n_sue); 552 p->n_left->n_type = INT; 553 return p; 554 } 555 if ((DEUNSIGN(l->n_type) == CHAR || 556 DEUNSIGN(l->n_type) == SHORT) && 557 (p->n_type == FLOAT || p->n_type == DOUBLE || 558 p->n_type == LDOUBLE)) { 559 p = block(SCONV, p, NIL, p->n_type, p->n_df, p->n_sue); 560 p->n_left->n_type = INT; 561 return p; 562 } 563 break; 564 565 case MOD: 566 simmod(p); 567 break; 568 569 case DIV: 570 if (o == DIV && p->n_type != CHAR && p->n_type != SHORT) 571 break; 572 /* make it an int division by inserting conversions */ 573 p->n_left = block(SCONV, p->n_left, NIL, INT, 0, MKSUE(INT)); 574 p->n_right = block(SCONV, p->n_right, NIL, INT, 0, MKSUE(INT)); 575 p = block(SCONV, p, NIL, p->n_type, 0, MKSUE(p->n_type)); 576 p->n_left->n_type = INT; 577 break; 578 579 case PMCONV: 580 case PVCONV: 581 582 nfree(p); 583 return(buildtree(o==PMCONV?MUL:DIV, p->n_left, p->n_right)); 584 585 case STNAME: 586 if ((q = p->n_sp) == NULL) 587 return p; 588 if (q->sclass != STNAME) 589 return p; 590 t = p->n_type; 591 p = block(ADDROF, p, NIL, INCREF(t), p->n_df, p->n_sue); 592 p = block(UMUL, p, NIL, t, p->n_df, p->n_sue); 593 break; 594 595 case FORCE: 596 /* put return value in return reg */ 597 p->n_op = ASSIGN; 598 p->n_right = p->n_left; 599 p->n_left = block(REG, NIL, NIL, p->n_type, 0, MKSUE(INT)); 600 p->n_left->n_rval = p->n_left->n_type == BOOL ? 601 RETREG(BOOL_TYPE) : RETREG(p->n_type); 602 break; 603 604 case LS: 605 case RS: 606 if (p->n_right->n_op == ICON) 607 break; /* do not do anything */ 608 if (DEUNSIGN(p->n_right->n_type) == INT) 609 break; 610 p->n_right = block(SCONV, p->n_right, NIL, INT, 0, MKSUE(INT)); 611 break; 612 } 613 614 #ifdef PCC_DEBUG 615 if (xdebug) { 616 printf("clocal end: %p\n", p); 617 fwalk(p, eprint, 0); 618 } 619 #endif 620 return(p); 621 } 622 623 /* 624 * Change CALL references to either direct (static) or PLT. 625 */ 626 static void 627 fixnames(NODE *p, void *arg) 628 { 629 struct symtab *sp; 630 struct suedef *sue; 631 NODE *q; 632 char *c; 633 int isu; 634 635 if ((cdope(p->n_op) & CALLFLG) == 0) 636 return; 637 638 isu = 0; 639 q = p->n_left; 640 sue = q->n_sue; 641 if (q->n_op == UMUL) 642 q = q->n_left, isu = 1; 643 644 #if defined(ELFABI) 645 646 if (q->n_op == ICON) { 647 sp = q->n_sp; 648 649 #elif defined(MACHOABI) 650 651 #ifdef USE_GOTNR 652 if (q->n_op == PLUS && q->n_left->n_op == TEMP && 653 #else 654 if (q->n_op == PLUS && q->n_left->n_op == REG && 655 #endif 656 q->n_right->n_op == ICON) { 657 sp = q->n_right->n_sp; 658 #endif 659 660 if (sp == NULL) 661 return; /* nothing to do */ 662 if (sp->sclass == STATIC && !ISFTN(sp->stype)) 663 return; /* function pointer */ 664 665 if (sp->sclass != STATIC && sp->sclass != EXTERN && 666 sp->sclass != EXTDEF) 667 cerror("fixnames"); 668 c = NULL; 669 #if defined(ELFABI) 670 671 if (sp->soname == NULL || 672 (c = strstr(sp->soname, "@got(31)")) == NULL) 673 cerror("fixnames2"); 674 if (isu) { 675 strcpy(c, "@plt"); 676 } else 677 *c = 0; 678 679 #elif defined(MACHOABI) 680 681 if (sp->soname == NULL || 682 ((c = strstr(sp->soname, "$non_lazy_ptr")) == NULL && 683 (c = strstr(sp->soname, "-L")) == NULL)) 684 cerror("fixnames2"); 685 if (isu) { 686 *c = 0; 687 addstub(&stublist, sp->soname+1); 688 strcpy(c, "$stub"); 689 } else 690 *c = 0; 691 692 nfree(q->n_left); 693 q = q->n_right; 694 if (isu) 695 nfree(p->n_left->n_left); 696 nfree(p->n_left); 697 p->n_left = q; 698 q->n_sue = sue; 699 700 #endif 701 } 702 } 703 704 void 705 myp2tree(NODE *p) 706 { 707 int o = p->n_op; 708 struct symtab *sp; 709 710 if (kflag) 711 walkf(p, fixnames, 0); 712 if (o != FCON) 713 return; 714 715 /* Write float constants to memory */ 716 /* Should be voluntary per architecture */ 717 718 sp = IALLOC(sizeof(struct symtab)); 719 sp->sclass = STATIC; 720 sp->ssue = MKSUE(p->n_type); 721 sp->slevel = 1; /* fake numeric label */ 722 sp->soffset = getlab(); 723 sp->sflags = 0; 724 sp->stype = p->n_type; 725 sp->squal = (CON >> TSHIFT); 726 727 defloc(sp); 728 ninval(0, sp->ssue->suesize, p); 729 730 p->n_op = NAME; 731 p->n_lval = 0; 732 p->n_sp = sp; 733 } 734 735 /*ARGSUSED*/ 736 int 737 andable(NODE *p) 738 { 739 return(1); /* all names can have & taken on them */ 740 } 741 742 /* 743 * at the end of the arguments of a ftn, set the automatic offset 744 */ 745 void 746 cendarg() 747 { 748 #ifdef PCC_DEBUG 749 if (xdebug) 750 printf("cendarg: autooff=%d (was %d)\n", AUTOINIT, autooff); 751 #endif 752 autooff = AUTOINIT; 753 } 754 755 /* 756 * Return 1 if a variable of type type is OK to put in register. 757 */ 758 int 759 cisreg(TWORD t) 760 { 761 return 1; 762 } 763 764 /* 765 * return a node, for structure references, which is suitable for 766 * being added to a pointer of type t, in order to be off bits offset 767 * into a structure 768 * t, d, and s are the type, dimension offset, and sizeoffset 769 * Be careful about only handling first-level pointers, the following 770 * indirections must be fullword. 771 */ 772 NODE * 773 offcon(OFFSZ off, TWORD t, union dimfun *d, struct suedef *sue) 774 { 775 register NODE *p; 776 777 #ifdef PCC_DEBUG 778 if (xdebug) 779 printf("offcon: OFFSZ %lld type %x dim %p siz %d\n", 780 off, t, d, sue->suesize); 781 #endif 782 783 p = bcon(0); 784 p->n_lval = off/SZCHAR; /* Default */ 785 return(p); 786 } 787 788 /* 789 * Allocate bits on the stack. 790 * 'off' is the number of bits to allocate 791 * 'p' is a tree that when evaluated is the multiply count for 'off' 792 * 't' is a storeable node where to write the allocated address 793 */ 794 void 795 spalloc(NODE *t, NODE *p, OFFSZ off) 796 { 797 NODE *q, *r; 798 int nbytes = off / SZCHAR; 799 int stacksize = 24+40; /* this should be p2stacksize */ 800 801 /* 802 * After we subtract the requisite bytes 803 * off the stack, we need to step back over 804 * the 40 bytes for the arguments registers 805 * *and* any other parameters which will get 806 * saved to the stack. Unfortunately, we 807 * don't have that information in pass1 and 808 * the parameters will stomp on the allocated 809 * space for alloca(). 810 * 811 * No fix yet. 812 */ 813 werror("parameters may stomp on alloca()"); 814 815 /* compute size */ 816 p = buildtree(MUL, p, bcon(nbytes)); 817 p = buildtree(PLUS, p, bcon(ALSTACK/SZCHAR)); 818 819 /* load the top-of-stack */ 820 q = block(REG, NIL, NIL, PTR+INT, 0, MKSUE(INT)); 821 regno(q) = SPREG; 822 q = block(UMUL, q, NIL, INT, 0, MKSUE(INT)); 823 824 /* save old top-of-stack value to new top-of-stack position */ 825 r = block(REG, NIL, NIL, PTR+INT, 0, MKSUE(INT)); 826 regno(r) = SPREG; 827 r = block(MINUSEQ, r, p, INT, 0, MKSUE(INT)); 828 r = block(UMUL, r, NIL, INT, 0, MKSUE(INT)); 829 ecomp(buildtree(ASSIGN, r, q)); 830 831 r = block(REG, NIL, NIL, PTR+INT, 0, MKSUE(INT)); 832 regno(r) = SPREG; 833 834 /* skip over the arguments space and align to 16 bytes */ 835 r = block(PLUS, r, bcon(stacksize + 15), INT, 0, MKSUE(INT)); 836 r = block(RS, r, bcon(4), INT, 0, MKSUE(INT)); 837 r = block(LS, r, bcon(4), INT, 0, MKSUE(INT)); 838 839 t->n_type = p->n_type; 840 ecomp(buildtree(ASSIGN, t, r)); 841 } 842 843 /* 844 * Print out a string of characters. 845 * Unfortunately, this code assumes that the assembler understands 846 * C-style escape sequences. (which it doesn't!) 847 * Location is already set. 848 */ 849 void 850 instring(struct symtab *sp) 851 { 852 char *s, *str = sp->sname; 853 854 #if defined(ELFABI) 855 856 defloc(sp); 857 858 #elif defined(MACHOABI) 859 860 extern int lastloc; 861 if (lastloc != STRNG) 862 printf(" .cstring\n"); 863 lastloc = STRNG; 864 printf("\t.p2align 2\n"); 865 printf(LABFMT ":\n", sp->soffset); 866 867 #endif 868 869 /* be kind to assemblers and avoid long strings */ 870 printf("\t.ascii \""); 871 for (s = str; *s != 0; ) { 872 if (*s++ == '\\') { 873 (void)esccon(&s); 874 } 875 if (s - str > 64) { 876 fwrite(str, 1, s - str, stdout); 877 printf("\"\n\t.ascii \""); 878 str = s; 879 } 880 } 881 fwrite(str, 1, s - str, stdout); 882 printf("\\0\"\n"); 883 } 884 885 static int inbits, inval; 886 887 /* 888 * set fsz bits in sequence to zero. 889 */ 890 void 891 zbits(OFFSZ off, int fsz) 892 { 893 int m; 894 895 if (idebug) 896 printf("zbits off %lld, fsz %d inbits %d\n", off, fsz, inbits); 897 898 #if 0 899 /* little-endian */ 900 if ((m = (inbits % SZCHAR))) { 901 m = SZCHAR - m; 902 if (fsz < m) { 903 inbits += fsz; 904 return; 905 } else { 906 fsz -= m; 907 printf("\t.byte %d\n", inval); 908 inval = inbits = 0; 909 } 910 } 911 #endif 912 /* big-endian */ 913 if (inbits) { 914 m = SZCHAR - inbits; 915 if (fsz < m) { 916 inbits += fsz; 917 inval <<= fsz; 918 } else { 919 printf("\t.byte %d\n", inval << m); 920 fsz -= m; 921 inval = inbits = 0; 922 } 923 } 924 925 if (fsz >= SZCHAR) { 926 printf("\t.space %d\n", fsz/SZCHAR); 927 fsz -= (fsz/SZCHAR) * SZCHAR; 928 } 929 if (fsz) { 930 inval = 0; 931 inbits = fsz; 932 } 933 } 934 935 /* 936 * Initialize a bitfield. 937 */ 938 void 939 infld(CONSZ off, int fsz, CONSZ val) 940 { 941 if (idebug) 942 printf("infld off %lld, fsz %d, val %lld inbits %d\n", 943 off, fsz, val, inbits); 944 945 val &= (1 << fsz)-1; 946 947 #if 0 948 /* little-endian */ 949 while (fsz + inbits >= SZCHAR) { 950 inval |= (val << inbits); 951 printf("\t.byte %d\n", inval & 255); 952 fsz -= (SZCHAR - inbits); 953 val >>= (SZCHAR - inbits); 954 inval = inbits = 0; 955 } 956 if (fsz) { 957 inval |= (val << inbits); 958 inbits += fsz; 959 } 960 #endif 961 962 /* big-endian */ 963 inval <<= fsz; 964 inval |= val; 965 inbits += fsz; 966 while (inbits >= SZCHAR) { 967 int pval = inval >> (inbits - SZCHAR); 968 printf("\t.byte %d\n", pval & 255); 969 inbits -= SZCHAR; 970 } 971 } 972 973 /* 974 * print out a constant node, may be associated with a label. 975 * Do not free the node after use. 976 * off is bit offset from the beginning of the aggregate 977 * fsz is the number of bits this is referring to 978 */ 979 void 980 ninval(CONSZ off, int fsz, NODE *p) 981 { 982 union { float f; double d; long double l; int i[3]; } u; 983 struct symtab *q; 984 char *c; 985 TWORD t; 986 int i; 987 988 t = p->n_type; 989 if (t > BTMASK) 990 t = INT; /* pointer */ 991 992 while (p->n_op == SCONV || p->n_op == PCONV) { 993 NODE *l = p->n_left; 994 l->n_type = p->n_type; 995 p = l; 996 } 997 998 if (kflag && (p->n_op == PLUS || p->n_op == UMUL)) { 999 if (p->n_op == UMUL) 1000 p = p->n_left; 1001 p = p->n_right; 1002 q = p->n_sp; 1003 1004 #if defined(ELFABI) 1005 1006 if (q->soname && (c = strstr(q->soname, "@got(31)")) != NULL) 1007 *c = 0; /* ignore GOT ref here */ 1008 1009 #elif defined(MACHOABI) 1010 1011 if ((c = strstr(q->soname, "$non_lazy_ptr")) != NULL) { 1012 q->soname++; /* skip "L" */ 1013 *c = 0; /* ignore GOT ref here */ 1014 } 1015 else if ((c = strstr(q->soname, "-L")) != NULL) 1016 *c = 0; /* ignore GOT ref here */ 1017 1018 #endif 1019 1020 } 1021 1022 if (p->n_op != ICON && p->n_op != FCON) 1023 cerror("ninval: init node not constant: node %p [%s]", 1024 p, cftnsp->soname); 1025 1026 if (p->n_op == ICON && p->n_sp != NULL && DEUNSIGN(t) != INT) 1027 uerror("element not constant"); 1028 1029 switch (t) { 1030 case LONGLONG: 1031 case ULONGLONG: 1032 #if 0 1033 /* little-endian */ 1034 i = (p->n_lval >> 32); 1035 p->n_lval &= 0xffffffff; 1036 p->n_type = INT; 1037 ninval(off, 32, p); 1038 p->n_lval = i; 1039 ninval(off+32, 32, p); 1040 #endif 1041 /* big-endian */ 1042 i = (p->n_lval & 0xffffffff); 1043 p->n_lval >>= 32; 1044 p->n_type = INT; 1045 ninval(off, 32, p); 1046 p->n_lval = i; 1047 ninval(off+32, 32, p); 1048 1049 break; 1050 case INT: 1051 case UNSIGNED: 1052 printf("\t.long %d", (int)p->n_lval); 1053 if ((q = p->n_sp) != NULL) { 1054 if ((q->sclass == STATIC && q->slevel > 0)) { 1055 printf("+" LABFMT, q->soffset); 1056 } else { 1057 char *name = q->soname ? q->soname : exname(q->sname); 1058 printf("+%s", name); 1059 } 1060 } 1061 printf("\n"); 1062 break; 1063 case SHORT: 1064 case USHORT: 1065 printf("\t.short %d\n", (int)p->n_lval & 0xffff); 1066 break; 1067 case BOOL: 1068 if (p->n_lval > 1) 1069 p->n_lval = p->n_lval != 0; 1070 /* FALLTHROUGH */ 1071 case CHAR: 1072 case UCHAR: 1073 printf("\t.byte %d\n", (int)p->n_lval & 0xff); 1074 break; 1075 case LDOUBLE: 1076 u.i[2] = 0; 1077 u.l = (long double)p->n_dcon; 1078 #if 0 1079 /* little-endian */ 1080 printf("\t.long 0x%x,0x%x,0x%x\n", u.i[0], u.i[1], u.i[2]); 1081 #endif 1082 /* big-endian */ 1083 printf("\t.long 0x%x,0x%x,0x%x\n", u.i[0], u.i[1], u.i[2]); 1084 break; 1085 case DOUBLE: 1086 u.d = (double)p->n_dcon; 1087 printf("\t.long 0x%x\n\t.long 0x%x\n", u.i[0], u.i[1]); 1088 break; 1089 case FLOAT: 1090 u.f = (float)p->n_dcon; 1091 printf("\t.long 0x%x\n", u.i[0]); 1092 break; 1093 default: 1094 cerror("ninval"); 1095 } 1096 } 1097 1098 /* make a name look like an external name in the local machine */ 1099 char * 1100 exname(char *p) 1101 { 1102 #if defined(ELFABI) 1103 1104 return (p == NULL ? "" : p); 1105 1106 #elif defined(MACHOABI) 1107 1108 #define NCHNAM 256 1109 static char text[NCHNAM+1]; 1110 int i; 1111 1112 if (p == NULL) 1113 return ""; 1114 1115 text[0] = '_'; 1116 for (i=1; *p && i<NCHNAM; ++i) 1117 text[i] = *p++; 1118 1119 text[i] = '\0'; 1120 text[NCHNAM] = '\0'; /* truncate */ 1121 1122 return (text); 1123 1124 #endif 1125 } 1126 1127 /* 1128 * map types which are not defined on the local machine 1129 */ 1130 TWORD 1131 ctype(TWORD type) 1132 { 1133 switch (BTYPE(type)) { 1134 case LONG: 1135 MODTYPE(type,INT); 1136 break; 1137 1138 case ULONG: 1139 MODTYPE(type,UNSIGNED); 1140 1141 } 1142 return (type); 1143 } 1144 1145 void 1146 calldec(NODE *p, NODE *q) 1147 { 1148 #ifdef PCC_DEBUG 1149 if (xdebug) 1150 printf("calldec:\n"); 1151 #endif 1152 } 1153 1154 void 1155 extdec(struct symtab *q) 1156 { 1157 #ifdef PCC_DEBUG 1158 if (xdebug) 1159 printf("extdec:\n"); 1160 #endif 1161 } 1162 1163 /* make a common declaration for id, if reasonable */ 1164 void 1165 defzero(struct symtab *sp) 1166 { 1167 char *n; 1168 int off; 1169 1170 off = tsize(sp->stype, sp->sdf, sp->ssue); 1171 off = (off+(SZCHAR-1))/SZCHAR; 1172 printf("\t.%scomm ", sp->sclass == STATIC ? "l" : ""); 1173 n = sp->soname ? sp->soname : exname(sp->sname); 1174 if (sp->slevel == 0) 1175 printf("%s,%d\n", n, off); 1176 else 1177 printf(LABFMT ",%d\n", sp->soffset, off); 1178 } 1179 1180 1181 #ifdef notdef 1182 /* make a common declaration for id, if reasonable */ 1183 void 1184 commdec(struct symtab *q) 1185 { 1186 int off; 1187 1188 off = tsize(q->stype, q->sdf, q->ssue); 1189 off = (off+(SZCHAR-1))/SZCHAR; 1190 printf("\t.comm %s,0%o\n", q->soname ? q->soname : exname(q->sname), off); 1191 } 1192 1193 /* make a local common declaration for id, if reasonable */ 1194 void 1195 lcommdec(struct symtab *q) 1196 { 1197 int off; 1198 1199 off = tsize(q->stype, q->sdf, q->ssue); 1200 off = (off+(SZCHAR-1))/SZCHAR; 1201 if (q->slevel == 0) 1202 printf("\t.lcomm %s,%d\n", q->soname ? q->soname : exname(q->sname), off); 1203 else 1204 printf("\t.lcomm " LABFMT ",%d\n", q->soffset, off); 1205 } 1206 1207 /* 1208 * print a (non-prog) label. 1209 */ 1210 void 1211 deflab1(int label) 1212 { 1213 printf(LABFMT ":\n", label); 1214 } 1215 1216 #if defined(ELFABI) 1217 1218 static char *loctbl[] = { "text", "data", "section .rodata,", 1219 "section .rodata" }; 1220 1221 #elif defined(MACHOABI) 1222 1223 static char *loctbl[] = { "text", "data", "section .rodata,", "cstring" }; 1224 1225 #endif 1226 1227 void 1228 setloc1(int locc) 1229 { 1230 #ifdef PCC_DEBUG 1231 if (xdebug) 1232 printf("setloc1: locc=%d, lastloc=%d\n", locc, lastloc); 1233 #endif 1234 1235 if (locc == lastloc) 1236 return; 1237 lastloc = locc; 1238 printf(" .%s\n", loctbl[locc]); 1239 } 1240 #endif 1241 1242 /* simulate and optimise the MOD opcode */ 1243 static void 1244 simmod(NODE *p) 1245 { 1246 NODE *r = p->n_right; 1247 1248 assert(p->n_op == MOD); 1249 1250 if (!ISUNSIGNED(p->n_type)) 1251 return; 1252 1253 #define ISPOW2(n) ((n) && (((n)&((n)-1)) == 0)) 1254 1255 /* if the right is a constant power of two, then replace with AND */ 1256 if (r->n_op == ICON && ISPOW2(r->n_lval)) { 1257 p->n_op = AND; 1258 r->n_lval--; 1259 return; 1260 } 1261 1262 #undef ISPOW2 1263 1264 /* other optimizations can go here */ 1265 } 1266 1267 static int constructor; 1268 static int destructor; 1269 1270 /* 1271 * Give target the opportunity of handling pragmas. 1272 */ 1273 int 1274 mypragma(char **ary) 1275 { 1276 if (strcmp(ary[1], "tls") == 0) { 1277 uerror("thread-local storage not supported for this target"); 1278 return 1; 1279 } 1280 if (strcmp(ary[1], "constructor") == 0 || strcmp(ary[1], "init") == 0) { 1281 constructor = 1; 1282 return 1; 1283 } 1284 if (strcmp(ary[1], "destructor") == 0 || strcmp(ary[1], "fini") == 0) { 1285 destructor = 1; 1286 return 1; 1287 } 1288 1289 return 0; 1290 } 1291 1292 /* 1293 * Called when a identifier has been declared, to give target last word. 1294 */ 1295 void 1296 fixdef(struct symtab *sp) 1297 { 1298 /* may have sanity checks here */ 1299 if ((constructor || destructor) && (sp->sclass != PARAM)) { 1300 #ifdef MACHOABI 1301 if (kflag) { 1302 if (constructor) 1303 printf("\t.mod_init_func\n"); 1304 else 1305 printf("\t.mod_term_func\n"); 1306 } else { 1307 if (constructor) 1308 printf("\t.constructor\n"); 1309 else 1310 printf("\t.destructor\n"); 1311 } 1312 printf("\t.p2align 2\n"); 1313 printf("\t.long %s\n", exname(sp->sname)); 1314 printf("\t.text\n"); 1315 constructor = destructor = 0; 1316 #endif 1317 } 1318 } 1319 1320 /* 1321 * There is very little different here to the standard builtins. 1322 * It basically handles promotion of types smaller than INT. 1323 */ 1324 1325 NODE * 1326 powerpc_builtin_stdarg_start(NODE *f, NODE *a) 1327 { 1328 NODE *p, *q; 1329 int sz = 1; 1330 1331 /* check num args and type */ 1332 if (a == NULL || a->n_op != CM || a->n_left->n_op == CM || 1333 !ISPTR(a->n_left->n_type)) 1334 goto bad; 1335 1336 /* must first deal with argument size; use int size */ 1337 p = a->n_right; 1338 if (p->n_type < INT) { 1339 /* round up to word */ 1340 sz = SZINT / tsize(p->n_type, p->n_df, p->n_sue); 1341 } 1342 1343 p = buildtree(ADDROF, p, NIL); /* address of last arg */ 1344 p = optim(buildtree(PLUS, p, bcon(sz))); 1345 q = block(NAME, NIL, NIL, PTR+VOID, 0, 0); 1346 q = buildtree(CAST, q, p); 1347 p = q->n_right; 1348 nfree(q->n_left); 1349 nfree(q); 1350 p = buildtree(ASSIGN, a->n_left, p); 1351 tfree(f); 1352 nfree(a); 1353 1354 return p; 1355 1356 bad: 1357 uerror("bad argument to __builtin_stdarg_start"); 1358 return bcon(0); 1359 } 1360 1361 NODE * 1362 powerpc_builtin_va_arg(NODE *f, NODE *a) 1363 { 1364 NODE *p, *q, *r; 1365 int sz, tmpnr; 1366 1367 /* check num args and type */ 1368 if (a == NULL || a->n_op != CM || a->n_left->n_op == CM || 1369 !ISPTR(a->n_left->n_type) || a->n_right->n_op != TYPE) 1370 goto bad; 1371 1372 r = a->n_right; 1373 1374 /* get type size */ 1375 sz = tsize(r->n_type, r->n_df, r->n_sue) / SZCHAR; 1376 if (sz < SZINT/SZCHAR) { 1377 werror("%s%s promoted to int when passed through ...", 1378 ISUNSIGNED(r->n_type) ? "unsigned " : "", 1379 DEUNSIGN(r->n_type) == SHORT ? "short" : "char"); 1380 sz = SZINT/SZCHAR; 1381 r->n_type = INT; 1382 r->n_sue = MKSUE(INT); 1383 } 1384 1385 p = tcopy(a->n_left); 1386 1387 #if defined(ELFABI) 1388 1389 /* alignment */ 1390 if (SZINT/SZCHAR && r->n_type != UNIONTY && r->n_type != STRTY) { 1391 p = buildtree(PLUS, p, bcon(ALSTACK/8 - 1)); 1392 p = block(AND, p, bcon(-ALSTACK/8), p->n_type, p->n_df, p->n_sue); 1393 } 1394 1395 #endif 1396 1397 /* create a copy to a temp node */ 1398 q = tempnode(0, p->n_type, p->n_df, p->n_sue); 1399 tmpnr = regno(q); 1400 p = buildtree(ASSIGN, q, p); 1401 1402 q = tempnode(tmpnr, p->n_type, p->n_df, p->n_sue); 1403 q = buildtree(PLUS, q, bcon(sz)); 1404 q = buildtree(ASSIGN, a->n_left, q); 1405 1406 q = buildtree(COMOP, p, q); 1407 1408 nfree(a->n_right); 1409 nfree(a); 1410 nfree(f); 1411 1412 p = tempnode(tmpnr, INCREF(r->n_type), r->n_df, r->n_sue); 1413 p = buildtree(UMUL, p, NIL); 1414 p = buildtree(COMOP, q, p); 1415 1416 return p; 1417 1418 bad: 1419 uerror("bad argument to __builtin_va_arg"); 1420 return bcon(0); 1421 } 1422 1423 NODE * 1424 powerpc_builtin_va_end(NODE *f, NODE *a) 1425 { 1426 tfree(f); 1427 tfree(a); 1428 1429 return bcon(0); 1430 } 1431 1432 NODE * 1433 powerpc_builtin_va_copy(NODE *f, NODE *a) 1434 { 1435 if (a == NULL || a->n_op != CM || a->n_left->n_op == CM) 1436 goto bad; 1437 tfree(f); 1438 f = buildtree(ASSIGN, a->n_left, a->n_right); 1439 nfree(a); 1440 return f; 1441 1442 bad: 1443 uerror("bad argument to __buildtin_va_copy"); 1444 return bcon(0); 1445 } 1446 1447 NODE * 1448 powerpc_builtin_return_address(NODE *f, NODE *a) 1449 { 1450 int nframes; 1451 int i = 0; 1452 1453 if (a == NULL || a->n_op != ICON) 1454 goto bad; 1455 1456 nframes = a->n_lval; 1457 1458 tfree(f); 1459 tfree(a); 1460 1461 f = block(REG, NIL, NIL, PTR+VOID, 0, MKSUE(VOID)); 1462 regno(f) = SPREG; 1463 1464 do { 1465 f = block(UMUL, f, NIL, PTR+VOID, 0, MKSUE(VOID)); 1466 } while (i++ < nframes); 1467 1468 f = block(PLUS, f, bcon(8), INCREF(PTR+VOID), 0, MKSUE(VOID)); 1469 f = buildtree(UMUL, f, NIL); 1470 1471 return f; 1472 bad: 1473 uerror("bad argument to __builtin_return_address"); 1474 return bcon(0); 1475 } 1476 1477 NODE * 1478 powerpc_builtin_frame_address(NODE *f, NODE *a) 1479 { 1480 int nframes; 1481 int i = 0; 1482 1483 if (a == NULL || a->n_op != ICON) 1484 goto bad; 1485 1486 nframes = a->n_lval; 1487 1488 tfree(f); 1489 tfree(a); 1490 1491 if (nframes == 0) { 1492 f = block(REG, NIL, NIL, PTR+VOID, 0, MKSUE(VOID)); 1493 regno(f) = FPREG; 1494 } else { 1495 f = block(REG, NIL, NIL, PTR+VOID, 0, MKSUE(VOID)); 1496 regno(f) = SPREG; 1497 do { 1498 f = block(UMUL, f, NIL, PTR+VOID, 0, MKSUE(VOID)); 1499 } while (i++ < nframes); 1500 f = block(PLUS, f, bcon(24), INCREF(PTR+VOID), 0, MKSUE(VOID)); 1501 f = buildtree(UMUL, f, NIL); 1502 } 1503 1504 return f; 1505 bad: 1506 uerror("bad argument to __builtin_frame_address"); 1507 return bcon(0); 1508 } 1509 1510 void 1511 pass1_lastchance(struct interpass *ip) 1512 { 1513 } 1514