1 /* Id: local.c,v 1.6 2009/05/07 02:34:11 gmcgarry Exp */ 2 /* $NetBSD: local.c,v 1.1.1.2 2010/06/03 18:57:24 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 31 #include "pass1.h" 32 33 /* this file contains code which is dependent on the target machine */ 34 35 /* clocal() is called to do local transformations on 36 * an expression tree preparitory to its being 37 * written out in intermediate code. 38 * 39 * the major essential job is rewriting the 40 * automatic variables and arguments in terms of 41 * REG and OREG nodes 42 * conversion ops which are not necessary are also clobbered here 43 * in addition, any special features (such as rewriting 44 * exclusive or) are easily handled here as well 45 */ 46 NODE * 47 clocal(NODE *p) 48 { 49 50 register struct symtab *q; 51 register NODE *r, *l; 52 register int o; 53 int m; 54 55 #ifdef PCC_DEBUG 56 if (xdebug) { 57 printf("clocal: %p\n", p); 58 fwalk(p, eprint, 0); 59 } 60 #endif 61 switch( o = p->n_op ){ 62 63 case NAME: 64 if ((q = p->n_sp) == NULL) 65 return p; /* Nothing to care about */ 66 67 switch (q->sclass) { 68 69 case PARAM: 70 case AUTO: 71 /* fake up a structure reference */ 72 r = block(REG, NIL, NIL, PTR+STRTY, 0, 0); 73 r->n_lval = 0; 74 r->n_rval = FPREG; 75 p = stref(block(STREF, r, p, 0, 0, 0)); 76 break; 77 78 case STATIC: 79 if (q->slevel == 0) 80 break; 81 p->n_lval = 0; 82 break; 83 84 case REGISTER: 85 p->n_op = REG; 86 p->n_lval = 0; 87 p->n_rval = q->soffset; 88 break; 89 90 case EXTERN: 91 case EXTDEF: 92 break; 93 } 94 break; 95 96 case PCONV: 97 /* Remove redundant PCONV's. Be careful */ 98 l = p->n_left; 99 if (l->n_op == ICON) { 100 l->n_lval = (unsigned)l->n_lval; 101 goto delp; 102 } 103 if (l->n_type < INT || l->n_type == LONGLONG || 104 l->n_type == ULONGLONG) { 105 /* float etc? */ 106 p->n_left = block(SCONV, l, NIL, 107 UNSIGNED, 0, MKSUE(UNSIGNED)); 108 break; 109 } 110 /* if left is SCONV, cannot remove */ 111 if (l->n_op == SCONV) 112 break; 113 114 /* avoid ADDROF TEMP */ 115 if (l->n_op == ADDROF && l->n_left->n_op == TEMP) 116 break; 117 118 /* if conversion to another pointer type, just remove */ 119 if (p->n_type > BTMASK && l->n_type > BTMASK) 120 goto delp; 121 break; 122 123 delp: l->n_type = p->n_type; 124 l->n_qual = p->n_qual; 125 l->n_df = p->n_df; 126 l->n_sue = p->n_sue; 127 nfree(p); 128 p = l; 129 break; 130 131 case SCONV: 132 l = p->n_left; 133 134 #if 0 135 if (p->n_type == l->n_type) { 136 nfree(p); 137 return l; 138 } 139 140 if ((p->n_type & TMASK) == 0 && (l->n_type & TMASK) == 0 && 141 btdims[p->n_type].suesize == btdims[l->n_type].suesize) { 142 if (p->n_type != FLOAT && p->n_type != DOUBLE && 143 l->n_type != FLOAT && l->n_type != DOUBLE && 144 l->n_type != LDOUBLE && p->n_type != LDOUBLE) { 145 if (l->n_op == NAME || l->n_op == UMUL || 146 l->n_op == TEMP) { 147 l->n_type = p->n_type; 148 nfree(p); 149 return l; 150 } 151 } 152 } 153 154 if (DEUNSIGN(p->n_type) == INT && DEUNSIGN(l->n_type) == INT && 155 coptype(l->n_op) == BITYPE) { 156 l->n_type = p->n_type; 157 nfree(p); 158 return l; 159 } 160 #endif 161 o = l->n_op; 162 m = p->n_type; 163 164 if (o == ICON) { 165 CONSZ val = l->n_lval; 166 167 if (!ISPTR(m)) /* Pointers don't need to be conv'd */ 168 switch (m) { 169 case BOOL: 170 l->n_lval = l->n_lval != 0; 171 break; 172 case CHAR: 173 l->n_lval = (char)val; 174 break; 175 case UCHAR: 176 l->n_lval = val & 0377; 177 break; 178 case INT: 179 l->n_lval = (short)val; 180 break; 181 case UNSIGNED: 182 l->n_lval = val & 0177777; 183 break; 184 case ULONG: 185 l->n_lval = val & 0xffffffff; 186 break; 187 case LONG: 188 l->n_lval = (long)val; 189 break; 190 case LONGLONG: 191 l->n_lval = (long long)val; 192 break; 193 case ULONGLONG: 194 l->n_lval = val; 195 break; 196 case VOID: 197 break; 198 case LDOUBLE: 199 case DOUBLE: 200 case FLOAT: 201 l->n_op = FCON; 202 l->n_dcon = FLOAT_CAST(val, l->n_type); 203 break; 204 default: 205 cerror("unknown type %d", m); 206 } 207 l->n_type = m; 208 l->n_sue = MKSUE(m); 209 nfree(p); 210 return l; 211 } else if (l->n_op == FCON) { 212 l->n_lval = FLOAT_VAL(l->n_dcon); 213 l->n_sp = NULL; 214 l->n_op = ICON; 215 l->n_type = m; 216 l->n_sue = MKSUE(m); 217 nfree(p); 218 return clocal(l); 219 } 220 if (DEUNSIGN(p->n_type) == INT && 221 DEUNSIGN(l->n_type) == INT) { 222 nfree(p); 223 p = l; 224 } 225 break; 226 227 case CBRANCH: 228 l = p->n_left; 229 if (coptype(l->n_op) != BITYPE) 230 break; 231 if (l->n_left->n_op != SCONV || l->n_right->n_op != ICON) 232 break; 233 if ((r = l->n_left->n_left)->n_type > INT) 234 break; 235 /* compare with constant without casting */ 236 nfree(l->n_left); 237 l->n_left = r; 238 l->n_right->n_type = l->n_left->n_type; 239 break; 240 241 case STASG: /* struct assignment, modify left */ 242 l = p->n_left; 243 if (l->n_type == STRTY) 244 p->n_left = buildtree(ADDROF, l, NIL); 245 break; 246 247 case PMCONV: 248 case PVCONV: 249 r = p; 250 p = buildtree(o == PMCONV ? MUL : DIV, p->n_left, p->n_right); 251 nfree(r); 252 break; 253 254 case FORCE: 255 /* put return value in return reg */ 256 p->n_op = ASSIGN; 257 p->n_right = p->n_left; 258 p->n_left = block(REG, NIL, NIL, p->n_type, 0, MKSUE(INT)); 259 p->n_left->n_rval = p->n_left->n_type == BOOL ? 260 RETREG(CHAR) : RETREG(p->n_type); 261 break; 262 263 } 264 #ifdef PCC_DEBUG 265 if (xdebug) { 266 printf("clocal end: %p\n", p); 267 fwalk(p, eprint, 0); 268 } 269 #endif 270 return(p); 271 } 272 273 void 274 myp2tree(NODE *p) 275 { 276 struct symtab *sp; 277 278 if (p->n_op != FCON) 279 return; 280 281 sp = inlalloc(sizeof(struct symtab)); 282 sp->sclass = STATIC; 283 sp->ssue = MKSUE(p->n_type); 284 sp->slevel = 1; /* fake numeric label */ 285 sp->soffset = getlab(); 286 sp->sflags = 0; 287 sp->stype = p->n_type; 288 sp->squal = (CON >> TSHIFT); 289 290 defloc(sp); 291 ninval(0, sp->ssue->suesize, p); 292 293 p->n_op = NAME; 294 p->n_lval = 0; 295 p->n_sp = sp; 296 } 297 298 /*ARGSUSED*/ 299 int 300 andable(NODE *p) 301 { 302 return(1); /* all names can have & taken on them */ 303 } 304 305 /* 306 * at the end of the arguments of a ftn, set the automatic offset 307 */ 308 void 309 cendarg() 310 { 311 autooff = AUTOINIT; 312 } 313 314 /* 315 * Return 1 if a variable of type type is OK to put in register. 316 */ 317 int 318 cisreg(TWORD t) 319 { 320 if (t == FLOAT || t == DOUBLE || t == LDOUBLE || 321 t == LONGLONG || t == ULONGLONG) 322 return 0; /* not yet */ 323 return 1; 324 } 325 326 /* 327 * return a node, for structure references, which is suitable for 328 * being added to a pointer of type t, in order to be off bits offset 329 * into a structure 330 * t, d, and s are the type, dimension offset, and sizeoffset 331 * For pdp10, return the type-specific index number which calculation 332 * is based on its size. For example, short a[3] would return 3. 333 * Be careful about only handling first-level pointers, the following 334 * indirections must be fullword. 335 */ 336 NODE * 337 offcon(OFFSZ off, TWORD t, union dimfun *d, struct suedef *sue) 338 { 339 register NODE *p; 340 341 if (xdebug) 342 printf("offcon: OFFSZ %lld type %x dim %p siz %d\n", 343 off, t, d, sue->suesize); 344 345 p = bcon(0); 346 p->n_lval = off/SZCHAR; /* Default */ 347 return(p); 348 } 349 350 /* 351 * Allocate off bits on the stack. p is a tree that when evaluated 352 * is the multiply count for off, t is a storeable node where to write 353 * the allocated address. 354 */ 355 void 356 spalloc(NODE *t, NODE *p, OFFSZ off) 357 { 358 NODE *sp; 359 360 p = buildtree(MUL, p, bcon(off/SZCHAR)); /* XXX word alignment? */ 361 362 /* sub the size from sp */ 363 sp = block(REG, NIL, NIL, p->n_type, 0, MKSUE(INT)); 364 sp->n_lval = 0; 365 sp->n_rval = STKREG; 366 ecomp(buildtree(MINUSEQ, sp, p)); 367 368 /* save the address of sp */ 369 sp = block(REG, NIL, NIL, PTR+INT, t->n_df, t->n_sue); 370 sp->n_lval = 0; 371 sp->n_rval = STKREG; 372 t->n_type = sp->n_type; 373 ecomp(buildtree(ASSIGN, t, sp)); /* Emit! */ 374 375 } 376 377 /* 378 * Print out a string of characters. 379 * Assume that the assembler understands C-style escape 380 * sequences. 381 */ 382 void 383 instring(struct symtab *sp) 384 { 385 char *s; 386 int val, cnt; 387 388 defloc(sp); 389 390 for (cnt = 0, s = sp->sname; *s != 0; ) { 391 if (cnt++ == 0) 392 printf(".byte "); 393 if (*s++ == '\\') 394 val = esccon(&s); 395 else 396 val = s[-1]; 397 printf("%o", val & 0377); 398 if (cnt > 15) { 399 cnt = 0; 400 printf("\n"); 401 } else 402 printf(","); 403 } 404 printf("%s0\n", cnt ? "" : ".byte "); 405 } 406 407 static int inbits, inval; 408 409 /* 410 * set fsz bits in sequence to zero. 411 */ 412 void 413 zbits(OFFSZ off, int fsz) 414 { 415 int m; 416 417 if (idebug) 418 printf("zbits off %lld, fsz %d inbits %d\n", off, fsz, inbits); 419 if ((m = (inbits % SZCHAR))) { 420 m = SZCHAR - m; 421 if (fsz < m) { 422 inbits += fsz; 423 return; 424 } else { 425 fsz -= m; 426 printf("\t.byte %d\n", inval); 427 inval = inbits = 0; 428 } 429 } 430 if (fsz >= SZCHAR) { 431 printf(".=.+%o\n", fsz/SZCHAR); 432 fsz -= (fsz/SZCHAR) * SZCHAR; 433 } 434 if (fsz) { 435 inval = 0; 436 inbits = fsz; 437 } 438 } 439 440 /* 441 * Initialize a bitfield. 442 */ 443 void 444 infld(CONSZ off, int fsz, CONSZ val) 445 { 446 if (idebug) 447 printf("infld off %lld, fsz %d, val %lld inbits %d\n", 448 off, fsz, val, inbits); 449 val &= ((CONSZ)1 << fsz)-1; 450 while (fsz + inbits >= SZCHAR) { 451 inval |= (val << inbits); 452 printf("\t.byte %d\n", inval & 255); 453 fsz -= (SZCHAR - inbits); 454 val >>= (SZCHAR - inbits); 455 inval = inbits = 0; 456 } 457 if (fsz) { 458 inval |= (val << inbits); 459 inbits += fsz; 460 } 461 } 462 463 /* 464 * print out a constant node, may be associated with a label. 465 * Do not free the node after use. 466 * off is bit offset from the beginning of the aggregate 467 * fsz is the number of bits this is referring to 468 */ 469 void 470 ninval(CONSZ off, int fsz, NODE *p) 471 { 472 #ifdef __pdp11__ 473 union { float f; double d; short s[4]; int i[2]; } u; 474 #endif 475 struct symtab *q; 476 TWORD t; 477 int i; 478 479 t = p->n_type; 480 if (t > BTMASK) 481 t = INT; /* pointer */ 482 483 while (p->n_op == SCONV || p->n_op == PCONV) { 484 NODE *l = p->n_left; 485 l->n_type = p->n_type; 486 p = l; 487 } 488 489 if (p->n_op != ICON && p->n_op != FCON) 490 cerror("ninval: init node not constant"); 491 492 if (p->n_op == ICON && p->n_sp != NULL && DEUNSIGN(t) != INT) 493 uerror("element not constant"); 494 495 switch (t) { 496 case LONGLONG: 497 case ULONGLONG: 498 i = (p->n_lval >> 32); 499 p->n_lval &= 0xffffffff; 500 p->n_type = INT; 501 ninval(off, 32, p); 502 p->n_lval = i; 503 ninval(off+32, 32, p); 504 break; 505 case LONG: 506 case ULONG: 507 printf("%o ; %o\n", (int)((p->n_lval >> 16) & 0177777), 508 (int)(p->n_lval & 0177777)); 509 break; 510 case INT: 511 case UNSIGNED: 512 printf("%o", (int)(p->n_lval & 0177777)); 513 if ((q = p->n_sp) != NULL) { 514 if ((q->sclass == STATIC && q->slevel > 0)) { 515 printf("+" LABFMT, q->soffset); 516 } else { 517 printf("+%s", q->soname ? q->soname : exname(q->sname)); 518 } 519 } 520 printf("\n"); 521 break; 522 case BOOL: 523 if (p->n_lval > 1) 524 p->n_lval = p->n_lval != 0; 525 /* FALLTHROUGH */ 526 case CHAR: 527 case UCHAR: 528 printf("\t.byte %o\n", (int)p->n_lval & 0xff); 529 break; 530 #ifdef __pdp11__ 531 case FLOAT: 532 u.f = (float)p->n_dcon; 533 printf("%o ; %o\n", u.i[0], u.i[1]); 534 break; 535 case LDOUBLE: 536 case DOUBLE: 537 u.d = (double)p->n_dcon; 538 printf("%o ; %o ; %o ; %o\n", u.i[0], u.i[1], u.i[2], u.i[3]); 539 break; 540 #else 541 /* cross-compiling */ 542 case FLOAT: 543 printf("%o ; %o\n", p->n_dcon.fd1, p->n_dcon.fd2); 544 break; 545 case LDOUBLE: 546 case DOUBLE: 547 printf("%o ; %o ; %o ; %o\n", p->n_dcon.fd1, p->n_dcon.fd2, 548 p->n_dcon.fd3, p->n_dcon.fd4); 549 break; 550 #endif 551 default: 552 cerror("ninval"); 553 } 554 } 555 556 /* make a name look like an external name in the local machine */ 557 char * 558 exname(char *p) 559 { 560 #define NCHNAM 256 561 static char text[NCHNAM+1]; 562 int i; 563 564 if (p == NULL) 565 return ""; 566 567 text[0] = '_'; 568 for (i=1; *p && i<NCHNAM; ++i) 569 text[i] = *p++; 570 571 text[i] = '\0'; 572 text[NCHNAM] = '\0'; /* truncate */ 573 574 return (text); 575 576 } 577 578 /* 579 * map types which are not defined on the local machine 580 */ 581 TWORD 582 ctype(TWORD type) 583 { 584 switch (BTYPE(type)) { 585 case SHORT: 586 MODTYPE(type,INT); 587 break; 588 589 case USHORT: 590 MODTYPE(type,UNSIGNED); 591 break; 592 593 case LDOUBLE: 594 MODTYPE(type,DOUBLE); 595 break; 596 597 } 598 return (type); 599 } 600 601 void 602 calldec(NODE *p, NODE *q) 603 { 604 } 605 606 void 607 extdec(struct symtab *q) 608 { 609 } 610 611 /* make a common declaration for id, if reasonable */ 612 void 613 defzero(struct symtab *sp) 614 { 615 extern int lastloc; 616 char *n; 617 int off; 618 619 off = tsize(sp->stype, sp->sdf, sp->ssue); 620 off = (off+(SZCHAR-1))/SZCHAR; 621 n = sp->soname ? sp->soname : exname(sp->sname); 622 if (sp->sclass == STATIC) { 623 printf(".bss\n"); 624 if (sp->slevel == 0) 625 printf("%s:", n); 626 else 627 printf(LABFMT ":", sp->soffset); 628 printf(" .=.+%o\n", off); 629 lastloc = -1; 630 return; 631 } 632 printf(".comm "); 633 if (sp->slevel == 0) 634 printf("%s,0%o\n", n, off); 635 else 636 printf(LABFMT ",0%o\n", sp->soffset, off); 637 } 638 639 /* 640 * Give target the opportunity of handling pragmas. 641 */ 642 int 643 mypragma(char **ary) 644 { 645 return 0; 646 } 647 648 /* 649 * Called when a identifier has been declared. 650 */ 651 void 652 fixdef(struct symtab *sp) 653 { 654 } 655 656 void 657 pass1_lastchance(struct interpass *ip) 658 { 659 } 660