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