1 #ifndef lint 2 static char sccsid[] = "@(#)local2.c 1.15 (Berkeley) 12/10/87"; 3 #endif 4 5 # include "pass2.h" 6 # include <ctype.h> 7 8 # define putstr(s) fputs((s), stdout) 9 # define ISCHAR(p) (p->in.type == UCHAR || p->in.type == CHAR) 10 11 # ifdef FORT 12 int ftlab1, ftlab2; 13 # endif 14 /* a lot of the machine dependent parts of the second pass */ 15 16 # define BITMASK(n) ((1L<<n)-1) 17 18 # ifndef ONEPASS 19 where(c){ 20 fprintf( stderr, "%s, line %d: ", filename, lineno ); 21 } 22 # endif 23 24 lineid( l, fn ) char *fn; { 25 /* identify line l and file fn */ 26 printf( "# line %d, file %s\n", l, fn ); 27 } 28 29 int ent_mask; 30 31 eobl2(){ 32 register OFFSZ spoff; /* offset from stack pointer */ 33 #ifndef FORT 34 extern int ftlab1, ftlab2; 35 #endif 36 37 spoff = maxoff; 38 spoff /= SZCHAR; 39 SETOFF(spoff,4); 40 #ifdef FORT 41 #ifndef FLEXNAMES 42 printf( " .set .F%d,%d\n", ftnno, spoff ); 43 #else 44 /* SHOULD BE L%d ... ftnno but must change pc/f77 */ 45 printf( " .set LF%d,%d\n", ftnno, spoff ); 46 #endif 47 printf( " .set LWM%d,0x%x\n", ftnno, ent_mask&0x1ffc|0x1000); 48 #else 49 printf( " .set L%d,0x%x\n", ftnno, ent_mask&0x1ffc); 50 printf( "L%d:\n", ftlab1); 51 if( maxoff > AUTOINIT ) 52 printf( " subl3 $%d,fp,sp\n", spoff); 53 printf( " jbr L%d\n", ftlab2); 54 #endif 55 ent_mask = 0; 56 maxargs = -1; 57 } 58 59 struct hoptab { int opmask; char * opstring; } ioptab[] = { 60 61 PLUS, "add", 62 MINUS, "sub", 63 MUL, "mul", 64 DIV, "div", 65 MOD, "div", 66 OR, "or", 67 ER, "xor", 68 AND, "and", 69 -1, "" }; 70 71 hopcode( f, o ){ 72 /* output the appropriate string from the above table */ 73 74 register struct hoptab *q; 75 76 if(asgop(o)) 77 o = NOASG o; 78 for( q = ioptab; q->opmask>=0; ++q ){ 79 if( q->opmask == o ){ 80 if(f == 'E') 81 printf( "e%s", q->opstring); 82 else 83 printf( "%s%c", q->opstring, tolower(f)); 84 return; 85 } 86 } 87 cerror( "no hoptab for %s", opst[o] ); 88 } 89 90 char * 91 rnames[] = { /* keyed to register number tokens */ 92 93 "r0", "r1", 94 "r2", "r3", "r4", "r5", 95 "r6", "r7", "r8", "r9", "r10", "r11", 96 "r12", "fp", "sp", "pc", 97 }; 98 99 /* output register name and update entry mask */ 100 char * 101 rname(r) 102 register int r; 103 { 104 105 ent_mask |= 1<<r; 106 return(rnames[r]); 107 } 108 109 int rstatus[] = { 110 SAREG|STAREG, SAREG|STAREG, 111 SAREG|STAREG, SAREG|STAREG, SAREG|STAREG, SAREG|STAREG, 112 SAREG, SAREG, SAREG, SAREG, SAREG, SAREG, 113 SAREG, SAREG, SAREG, SAREG, 114 }; 115 116 tlen(p) NODE *p; 117 { 118 switch(p->in.type) { 119 case CHAR: 120 case UCHAR: 121 return(1); 122 123 case SHORT: 124 case USHORT: 125 return(2); 126 127 case DOUBLE: 128 return(8); 129 130 default: 131 return(4); 132 } 133 } 134 135 anyfloat(p, q) 136 NODE *p, *q; 137 { 138 register TWORD tp, tq; 139 140 tp = p->in.type; 141 tq = q->in.type; 142 return (tp == FLOAT || tp == DOUBLE || tq == FLOAT || tq == DOUBLE); 143 } 144 145 prtype(n) NODE *n; 146 { 147 switch (n->in.type) 148 { 149 150 case DOUBLE: 151 putchar('d'); 152 return; 153 154 case FLOAT: 155 putchar('f'); 156 return; 157 158 case INT: 159 case UNSIGNED: 160 putchar('l'); 161 return; 162 163 case SHORT: 164 case USHORT: 165 putchar('w'); 166 return; 167 168 case CHAR: 169 case UCHAR: 170 putchar('b'); 171 return; 172 173 default: 174 if ( !ISPTR( n->in.type ) ) cerror("zzzcode- bad type"); 175 else { 176 putchar('l'); 177 return; 178 } 179 } 180 } 181 182 zzzcode( p, c ) register NODE *p; { 183 register int m; 184 int val; 185 switch( c ){ 186 187 case 'N': /* logical ops, turned into 0-1 */ 188 /* use register given by register 1 */ 189 cbgen( 0, m=getlab(), 'I' ); 190 deflab( p->bn.label ); 191 printf( " clrl %s\n", rname(getlr( p, '1' )->tn.rval) ); 192 deflab( m ); 193 return; 194 195 case 'P': 196 cbgen( p->in.op, p->bn.label, c ); 197 return; 198 199 case 'G': /* i *= f; asgops with int lhs and float rhs */ 200 { 201 register NODE *l, *r, *s; 202 int lt, rt; 203 204 l = p->in.left; 205 r = p->in.right; 206 s = talloc(); 207 rt = r->in.type; 208 lt = l->in.type; 209 210 if (lt != INT && lt != UNSIGNED) { 211 s->in.op = SCONV; 212 s->in.left = l; 213 s->in.type = ISUNSIGNED(lt) ? UNSIGNED : INT; 214 zzzcode(s, 'U'); 215 putstr("\n\t"); 216 } 217 218 if (ISUNSIGNED(lt)) { 219 s->in.op = SCONV; 220 s->in.left = lt == UNSIGNED ? l : resc; 221 s->in.type = rt; 222 unsigned_to_float(s); 223 } else { 224 putstr("cvl"); 225 prtype(r); 226 putchar('\t'); 227 adrput(lt == INT ? l : resc); 228 } 229 putstr("\n\t"); 230 231 hopcode(rt == FLOAT ? 'F' : 'D', p->in.op); 232 putchar('\t'); 233 adrput(r); 234 235 if (ISUNSIGNED(lt)) { 236 putstr("\n\t"); 237 s->in.op = SCONV; 238 s->in.left = r; /* we need only the type */ 239 s->in.type = UNSIGNED; 240 float_to_unsigned(s); 241 } else { 242 putstr("\n\tcv"); 243 prtype(r); 244 putstr("l\t"); 245 if (lt == INT) 246 adrput(l); 247 else 248 adrput(resc); 249 } 250 if (lt != INT) { 251 putstr("\n\t"); 252 s->in.op = ASSIGN; 253 s->in.left = l; 254 s->in.right = resc; 255 s->in.type = lt; 256 zzzcode(s, 'U'); 257 } 258 259 s->in.op = FREE; 260 return; 261 } 262 263 case 'B': /* get oreg value in temp register for shift */ 264 { 265 register NODE *r; 266 if (xdebug) eprint(p, 0, &val, &val); 267 r = p->in.right; 268 if( tlen(r) == sizeof(int) && r->in.type != FLOAT ) 269 putstr("movl"); 270 else { 271 putstr(ISUNSIGNED(r->in.type) ? "movz" : "cvt"); 272 prtype(r); 273 putchar('l'); 274 } 275 return; 276 } 277 278 case 'C': /* num bytes pushed on arg stack */ 279 { 280 extern int gc_numbytes; 281 extern int xdebug; 282 283 if (xdebug) printf("->%d<-",gc_numbytes); 284 285 printf("call%c $%d", 286 (p->in.left->in.op==ICON && gc_numbytes<60)?'f':'s', 287 gc_numbytes+4); 288 /* dont change to double (here's the only place to catch it) */ 289 if(p->in.type == FLOAT) 290 rtyflg = 1; 291 return; 292 } 293 294 case 'D': /* INCR and DECR */ 295 zzzcode(p->in.left, 'U'); 296 putstr("\n "); 297 298 case 'E': /* INCR and DECR, FOREFF */ 299 if (p->in.right->tn.lval == 1) 300 { 301 putstr(p->in.op == INCR ? "inc" : "dec"); 302 prtype(p->in.left); 303 putchar('\t'); 304 adrput(p->in.left); 305 return; 306 } 307 putstr(p->in.op == INCR ? "add" : "sub"); 308 prtype(p->in.left); 309 putstr("2 "); 310 adrput(p->in.right); 311 putchar(','); 312 adrput(p->in.left); 313 return; 314 315 case 'F': /* masked constant for fields */ 316 printf(ACONFMT, (p->in.right->tn.lval&((1<<fldsz)-1))<<fldshf); 317 return; 318 319 case 'H': /* opcode for shift */ 320 if(p->in.op == LS || p->in.op == ASG LS) 321 putstr("shll"); 322 else if(ISUNSIGNED(p->in.left->in.type)) 323 putstr("shrl"); 324 else 325 putstr("shar"); 326 return; 327 328 case 'L': /* type of left operand */ 329 case 'R': /* type of right operand */ 330 { 331 register NODE *n; 332 extern int xdebug; 333 334 n = getlr ( p, c); 335 if (xdebug) printf("->%d<-", n->in.type); 336 337 prtype(n); 338 return; 339 } 340 341 case 'M': { /* initiate ediv for mod and unsigned div */ 342 register char *r; 343 m = getlr(p, '1')->tn.rval; 344 r = rname(m); 345 printf("\tclrl\t%s\n\tmovl\t", r); 346 adrput(p->in.left); 347 printf(",%s\n", rname(m+1)); 348 if(!ISUNSIGNED(p->in.type)) { /* should be MOD */ 349 m = getlab(); 350 printf("\tjgeq\tL%d\n\tmnegl\t$1,%s\n", m, r); 351 deflab(m); 352 } 353 return; 354 } 355 356 case 'T': { /* rounded structure length for arguments */ 357 int size = p->stn.stsize; 358 SETOFF( size, 4); 359 printf("movab -%d(sp),sp", size); 360 return; 361 } 362 363 case 'S': /* structure assignment */ 364 stasg(p); 365 break; 366 367 case 'X': /* multiplication for short and char */ 368 if (ISUNSIGNED(p->in.left->in.type)) 369 printf("\tmovz"); 370 else 371 printf("\tcvt"); 372 zzzcode(p, 'L'); 373 printf("l\t"); 374 adrput(p->in.left); 375 printf(","); 376 adrput(&resc[0]); 377 printf("\n"); 378 if (ISUNSIGNED(p->in.right->in.type)) 379 printf("\tmovz"); 380 else 381 printf("\tcvt"); 382 zzzcode(p, 'R'); 383 printf("l\t"); 384 adrput(p->in.right); 385 printf(","); 386 adrput(&resc[1]); 387 printf("\n"); 388 return; 389 390 case 'U': /* SCONV */ 391 case 'V': /* SCONV with FORCC */ 392 sconv(p, c == 'V'); 393 break; 394 395 case 'W': /* SCONV float/double => unsigned */ 396 putstr("ld"); 397 prtype(p->in.left); 398 putchar('\t'); 399 adrput(p->in.left); 400 putstr("\n\t"); 401 float_to_unsigned(p); 402 break; 403 404 case 'Y': /* SCONV unsigned => float/double */ 405 unsigned_to_float(p); /* stores into accumulator */ 406 putstr("\n\tst"); 407 prtype(p); 408 putchar('\t'); 409 adrput(resc); 410 break; 411 412 case 'Z': 413 p = p->in.right; 414 switch (p->in.type) { 415 case SHORT: { 416 short w = p->tn.lval; 417 p->tn.lval = w; 418 break; 419 } 420 case CHAR: { 421 char c = p->tn.lval; 422 p->tn.lval = c; 423 break; 424 } 425 } 426 printf("$%d", p->tn.lval); 427 break; 428 429 default: 430 cerror( "illegal zzzcode" ); 431 } 432 } 433 434 #define MOVB(dst, src, off) { \ 435 putstr("\tmovb\t"); upput(src, off); putchar(','); \ 436 upput(dst, off); putchar('\n'); \ 437 } 438 #define MOVW(dst, src, off) { \ 439 putstr("\tmovw\t"); upput(src, off); putchar(','); \ 440 upput(dst, off); putchar('\n'); \ 441 } 442 #define MOVL(dst, src, off) { \ 443 putstr("\tmovl\t"); upput(src, off); putchar(','); \ 444 upput(dst, off); putchar('\n'); \ 445 } 446 /* 447 * Generate code for a structure assignment. 448 */ 449 stasg(p) 450 register NODE *p; 451 { 452 register NODE *l, *r; 453 register int size; 454 455 switch (p->in.op) { 456 case STASG: /* regular assignment */ 457 l = p->in.left; 458 r = p->in.right; 459 break; 460 case STARG: /* place arg on the stack */ 461 l = getlr(p, '3'); 462 r = p->in.left; 463 break; 464 default: 465 cerror("STASG bad"); 466 /*NOTREACHED*/ 467 } 468 /* 469 * Pun source for use in code generation. 470 */ 471 switch (r->in.op) { 472 case ICON: 473 r->in.op = NAME; 474 break; 475 case REG: 476 r->in.op = OREG; 477 break; 478 default: 479 cerror( "STASG-r" ); 480 /*NOTREACHED*/ 481 } 482 size = p->stn.stsize; 483 if (size <= 0 || size > 65535) 484 cerror("structure size out of range"); 485 /* 486 * Generate optimized code based on structure size 487 * and alignment properties.... 488 */ 489 switch (size) { 490 491 case 1: 492 putstr("\tmovb\t"); 493 optimized: 494 adrput(r); 495 putchar(','); 496 adrput(l); 497 putchar('\n'); 498 break; 499 500 case 2: 501 if (p->stn.stalign != 2) { 502 MOVB(l, r, SZCHAR); 503 putstr("\tmovb\t"); 504 } else 505 putstr("\tmovw\t"); 506 goto optimized; 507 508 case 4: 509 if (p->stn.stalign != 4) { 510 if (p->stn.stalign != 2) { 511 MOVB(l, r, 3*SZCHAR); 512 MOVB(l, r, 2*SZCHAR); 513 MOVB(l, r, 1*SZCHAR); 514 putstr("\tmovb\t"); 515 } else { 516 MOVW(l, r, SZSHORT); 517 putstr("\tmovw\t"); 518 } 519 } else 520 putstr("\tmovl\t"); 521 goto optimized; 522 523 case 6: 524 if (p->stn.stalign != 2) 525 goto movblk; 526 MOVW(l, r, 2*SZSHORT); 527 MOVW(l, r, 1*SZSHORT); 528 putstr("\tmovw\t"); 529 goto optimized; 530 531 case 8: 532 if (p->stn.stalign == 4) { 533 MOVL(l, r, SZLONG); 534 putstr("\tmovl\t"); 535 goto optimized; 536 } 537 /* fall thru...*/ 538 539 default: 540 movblk: 541 /* 542 * Can we ever get a register conflict with R1 here? 543 */ 544 putstr("\tmovab\t"); 545 adrput(l); 546 putstr(",r1\n\tmovab\t"); 547 adrput(r); 548 printf(",r0\n\tmovl\t$%d,r2\n\tmovblk\n", size); 549 rname(R2); 550 break; 551 } 552 /* 553 * Reverse above pun for reclaim. 554 */ 555 if (r->in.op == NAME) 556 r->in.op = ICON; 557 else if (r->in.op == OREG) 558 r->in.op = REG; 559 } 560 561 /* 562 * Output the address of the second item in the 563 * pair pointed to by p. 564 */ 565 upput(p, size) 566 register NODE *p; 567 { 568 CONSZ save; 569 570 if (p->in.op == FLD) 571 p = p->in.left; 572 switch (p->in.op) { 573 574 case NAME: 575 case OREG: 576 save = p->tn.lval; 577 p->tn.lval += size/SZCHAR; 578 adrput(p); 579 p->tn.lval = save; 580 break; 581 582 case REG: 583 if (size == SZLONG) { 584 putstr(rname(p->tn.rval+1)); 585 break; 586 } 587 /* fall thru... */ 588 589 default: 590 cerror("illegal upper address op %s size %d", 591 opst[p->tn.op], size); 592 /*NOTREACHED*/ 593 } 594 } 595 596 /* 597 * Convert a float or double in the accumulator into an unsigned int. 598 * Unlike the vax, the tahoe stores 0 into the destination 599 * on a conversion of > 2 ** 31, so we compensate. 600 */ 601 float_to_unsigned(p) 602 NODE *p; 603 { 604 register NODE *l = p->in.left; 605 int label1 = getlab(); 606 int label2 = getlab(); 607 int label3 = getlab(); 608 609 printf(".data\n\t.align\t2\nL%d:\n\t.long\t0x50000000", label1); 610 if (l->in.type == DOUBLE) 611 putstr(", 0x00000000"); 612 putstr(" # .double 2147483648\n\t.text\n\tcmp"); 613 prtype(l); 614 printf("\tL%d\n\tjlss\tL%d\n\tsub", label1, label2); 615 prtype(l); 616 printf("\tL%d\n\tcv", label1); 617 prtype(l); 618 putstr("l\t"); 619 adrput(resc); 620 putstr("\n\taddl2\t$-2147483648,"); 621 adrput(resc); 622 printf("\n\tjbr\tL%d\nL%d:\n\tcv", label3, label2); 623 prtype(l); 624 putstr("l\t"); 625 adrput(resc); 626 printf("\nL%d:", label3); 627 } 628 629 /* 630 * Convert an unsigned int into a float or double, leaving the result 631 * in the accumulator. 632 */ 633 unsigned_to_float(p) 634 register NODE *p; 635 { 636 int label1 = getlab(); 637 int label2 = getlab(); 638 639 printf(".data\n\t.align\t2\nL%d:\n\t.long\t0x50800000", label2); 640 if (p->in.type == DOUBLE) 641 putstr(", 0x00000000"); 642 putstr(" # .double 4294967296\n\t.text\n\tmovl\t"); 643 adrput(p->in.left); 644 putchar(','); 645 adrput(resc); 646 putstr("\n\tcvl"); 647 prtype(p); 648 putchar('\t'); 649 adrput(resc); 650 printf("\n\tjgeq\tL%d\n\taddd\tL%d\nL%d:", label1, label2, label1); 651 } 652 653 /* 654 * Prlen() is a cheap prtype()... 655 */ 656 static char convtab[SZINT/SZCHAR + 1] = { 657 '?', 'b', 'w', '?', 'l' 658 }; 659 #define prlen(len) putchar(convtab[len]) 660 661 662 /* 663 * Generate code for integral scalar conversions. 664 * Some of this code is designed to work around a tahoe misfeature 665 * that causes sign- and zero- extension to be defeated in 666 * certain circumstances. 667 * Basically if the source operand of a CVT or MOVZ instruction is 668 * shorter than the destination, and the source is a register 669 * or an immediate constant, sign- and zero- extension are 670 * ignored and the high bits of the source are copied. (Note 671 * that zero-extension is not a problem for immediate 672 * constants.) 673 */ 674 sconv(p, forcc) 675 NODE *p; 676 int forcc; 677 { 678 register NODE *src, *dst; 679 register NODE *tmp; 680 register int srclen, dstlen; 681 int srctype, dsttype; 682 int val; 683 684 if (p->in.op == ASSIGN) { 685 src = getlr(p, 'R'); 686 dst = getlr(p, 'L'); 687 dstlen = tlen(dst); 688 dsttype = dst->in.type; 689 } else /* if (p->in.op == SCONV || optype(p->in.op) == LTYPE) */ { 690 src = getlr(p, 'L'); 691 dst = getlr(p, '1'); 692 dstlen = tlen(p); 693 dsttype = p->in.type; 694 } 695 696 if (src->in.op == REG) { 697 srclen = SZINT/SZCHAR; 698 srctype = ISUNSIGNED(src->in.type) ? UNSIGNED : INT; 699 } else { 700 srclen = tlen(src); 701 srctype = src->in.type; 702 } 703 704 if (src->in.op == ICON) { 705 if (src->tn.lval == 0) { 706 putstr("clr"); 707 prtype(dst); 708 putchar('\t'); 709 adrput(dst); 710 return; 711 } 712 if (dstlen < srclen) { 713 switch (dsttype) { 714 case CHAR: 715 src->tn.lval = (char) src->tn.lval; 716 break; 717 case UCHAR: 718 src->tn.lval = (unsigned char) src->tn.lval; 719 break; 720 case SHORT: 721 src->tn.lval = (short) src->tn.lval; 722 break; 723 case USHORT: 724 src->tn.lval = (unsigned short) src->tn.lval; 725 break; 726 } 727 } 728 if (dst->in.op == REG) { 729 dsttype = INT; 730 dstlen = SZINT/SZCHAR; 731 } 732 srctype = dsttype; 733 srclen = dstlen; 734 } 735 736 if (srclen < dstlen) { 737 if (srctype == CHAR && dsttype == USHORT && dst->in.op == REG) { 738 /* (unsigned short) c; => sign extend to 16 bits */ 739 putstr("cvtbl\t"); 740 adrput(src); 741 putstr(",-(sp)\n\tmovzwl\t2(sp),"); 742 adrput(dst); 743 putstr("\n\tmovab\t4(sp),sp"); 744 if (forcc) { 745 /* inverted test */ 746 putstr("\n\tcmpl\t$0,"); 747 adrput(dst); 748 } 749 return; 750 } 751 genconv(ISUNSIGNED(srctype), 752 srclen, dst->in.op == REG ? SZINT/SZCHAR : dstlen, 753 src, dst); 754 return; 755 } 756 757 if (srclen > dstlen && dst->in.op == REG) { 758 /* if dst is a register, the result must look like an int */ 759 if (src->in.op == REG) { 760 if (ISUNSIGNED(dsttype)) { 761 val = (1 << dstlen * SZCHAR) - 1; 762 if (src->tn.rval == dst->tn.rval) 763 /* conversion in place */ 764 printf("andl2\t$%#x,", val); 765 else { 766 printf("andl3\t$%#x,", val); 767 adrput(src); 768 putchar(','); 769 } 770 adrput(dst); 771 return; 772 } 773 /* 774 * Sign extension in register can also be 775 * accomplished by shifts, but unfortunately 776 * shifts are extremely slow, due to the lack 777 * of a barrel shifter. 778 */ 779 putstr("pushl\t"); 780 adrput(src); 781 putstr("\n\tcvt"); 782 prlen(dstlen); 783 printf("l\t%d(sp),", SZINT/SZCHAR - dstlen); 784 adrput(dst); 785 putstr("\n\tmovab\t4(sp),sp"); 786 if (forcc) { 787 /* inverted test */ 788 putstr("\n\tcmpl\t$0,"); 789 adrput(dst); 790 } 791 return; 792 } 793 tmp = talloc(); 794 if ((src->in.op == UNARY MUL && 795 ((src->in.left->in.op == NAME || 796 (src->in.left->in.op == ICON)))) || 797 (src->in.op == OREG && !R2TEST(src->tn.rval))) { 798 /* we can increment src's address & pun it */ 799 *tmp = *src; 800 tmp->tn.lval += srclen - dstlen; 801 } else { 802 /* we must store src's address */ 803 *tmp = *dst; 804 putstr("mova"); 805 prlen(srclen); 806 putchar('\t'); 807 adrput(src); 808 putchar(','); 809 adrput(tmp); 810 putstr("\n\t"); 811 tmp->tn.op = OREG; 812 tmp->tn.lval = srclen - dstlen; 813 } 814 genconv(ISUNSIGNED(dsttype), dstlen, SZINT/SZCHAR, tmp, dst); 815 tmp->in.op = FREE; 816 return; 817 } 818 819 genconv(ISUNSIGNED(dsttype), 820 srclen, dst->in.op == REG ? SZINT/SZCHAR : dstlen, 821 src, dst); 822 } 823 824 genconv(usrc, srclen, dstlen, src, dst) 825 int usrc; 826 register int srclen, dstlen; 827 NODE *src, *dst; 828 { 829 if (srclen != dstlen) { 830 if (usrc && srclen < dstlen) 831 putstr("movz"); 832 else 833 putstr("cvt"); 834 prlen(srclen); 835 } else 836 putstr("mov"); 837 prlen(dstlen); 838 putchar('\t'); 839 adrput(src); 840 putchar(','); 841 adrput(dst); 842 } 843 844 rmove( rt, rs, t ) TWORD t;{ 845 printf( " movl %s,%s\n", rname(rs), rname(rt) ); 846 if(t==DOUBLE) 847 printf( " movl %s,%s\n", rname(rs+1), rname(rt+1) ); 848 } 849 850 struct respref 851 respref[] = { 852 INTAREG|INTBREG, INTAREG|INTBREG, 853 INAREG|INBREG, INAREG|INBREG|SOREG|STARREG|STARNM|SNAME|SCON, 854 INTEMP, INTEMP, 855 FORARG, FORARG, 856 INTEMP, INTAREG|INAREG|INTBREG|INBREG|SOREG|STARREG|STARNM, 857 0, 0 }; 858 859 setregs(){ /* set up temporary registers */ 860 fregs = 6; /* tbl- 6 free regs on Tahoe (0-5) */ 861 } 862 863 #ifndef szty 864 szty(t) TWORD t;{ /* size, in registers, needed to hold thing of type t */ 865 return(t==DOUBLE ? 2 : 1 ); 866 } 867 #endif 868 869 rewfld( p ) NODE *p; { 870 return(1); 871 } 872 873 callreg(p) NODE *p; { 874 return( R0 ); 875 } 876 877 base( p ) register NODE *p; { 878 register int o = p->in.op; 879 880 if( (o==ICON && p->in.name[0] != '\0')) return( 100 ); /* ie no base reg */ 881 if( o==REG ) return( p->tn.rval ); 882 if( (o==PLUS || o==MINUS) && p->in.left->in.op == REG && p->in.right->in.op==ICON) 883 return( p->in.left->tn.rval ); 884 if( o==OREG && !R2TEST(p->tn.rval) && (p->in.type==INT || p->in.type==UNSIGNED || ISPTR(p->in.type)) ) 885 return( p->tn.rval + 0200*1 ); 886 return( -1 ); 887 } 888 889 offset( p, tyl ) register NODE *p; int tyl; { 890 891 if(tyl > 8) return( -1 ); 892 if( tyl==1 && p->in.op==REG && (p->in.type==INT || p->in.type==UNSIGNED) ) return( p->tn.rval ); 893 if( (p->in.op==LS && p->in.left->in.op==REG && (p->in.left->in.type==INT || p->in.left->in.type==UNSIGNED) && 894 (p->in.right->in.op==ICON && p->in.right->in.name[0]=='\0') 895 && (1<<p->in.right->tn.lval)==tyl)) 896 return( p->in.left->tn.rval ); 897 return( -1 ); 898 } 899 900 makeor2( p, q, b, o) register NODE *p, *q; register int b, o; { 901 register NODE *t; 902 register int i; 903 NODE *f; 904 905 p->in.op = OREG; 906 f = p->in.left; /* have to free this subtree later */ 907 908 /* init base */ 909 switch (q->in.op) { 910 case ICON: 911 case REG: 912 case OREG: 913 t = q; 914 break; 915 916 case MINUS: 917 q->in.right->tn.lval = -q->in.right->tn.lval; 918 case PLUS: 919 t = q->in.right; 920 break; 921 922 case UNARY MUL: 923 t = q->in.left->in.left; 924 break; 925 926 default: 927 cerror("illegal makeor2"); 928 } 929 930 p->tn.lval = t->tn.lval; 931 #ifndef FLEXNAMES 932 for(i=0; i<NCHNAM; ++i) 933 p->in.name[i] = t->in.name[i]; 934 #else 935 p->in.name = t->in.name; 936 #endif 937 938 /* init offset */ 939 p->tn.rval = R2PACK( (b & 0177), o, (b>>7) ); 940 941 tfree(f); 942 return; 943 } 944 945 canaddr( p ) NODE *p; { 946 register int o = p->in.op; 947 948 if( o==NAME || o==REG || o==ICON || o==OREG || (o==UNARY MUL && shumul(p->in.left)) ) return(1); 949 return(0); 950 } 951 952 #ifndef shltype 953 shltype( o, p ) register NODE *p; { 954 return( o== REG || o == NAME || o == ICON || o == OREG || ( o==UNARY MUL && shumul(p->in.left)) ); 955 } 956 #endif 957 958 flshape( p ) NODE *p; { 959 register int o = p->in.op; 960 961 if( o==NAME || o==REG || o==ICON || o==OREG || (o==UNARY MUL && shumul(p->in.left)) ) return(1); 962 return(0); 963 } 964 965 shtemp( p ) register NODE *p; { 966 if( p->in.op == STARG ) p = p->in.left; 967 return( p->in.op==NAME || p->in.op ==ICON || p->in.op == OREG || (p->in.op==UNARY MUL && shumul(p->in.left)) ); 968 } 969 970 shumul( p ) register NODE *p; { 971 register int o; 972 extern int xdebug; 973 974 if (xdebug) { 975 printf("\nshumul:op=%d,lop=%d,rop=%d", p->in.op, p->in.left->in.op, p->in.right->in.op); 976 printf(" prname=%s,plty=%d, prlval=%D\n", p->in.right->in.name, p->in.left->in.type, p->in.right->tn.lval); 977 } 978 979 o = p->in.op; 980 if(( o == NAME || (o == OREG && !R2TEST(p->tn.rval)) || o == ICON ) 981 && p->in.type != PTR+DOUBLE) 982 return( STARNM ); 983 984 return( 0 ); 985 } 986 987 special( p, shape ) register NODE *p; { 988 if( shape==SIREG && p->in.op == OREG && R2TEST(p->tn.rval) ) return(1); 989 else return(0); 990 } 991 992 adrcon( val ) CONSZ val; { 993 printf(ACONFMT, val); 994 } 995 996 conput( p ) register NODE *p; { 997 switch( p->in.op ){ 998 999 case ICON: 1000 acon( p ); 1001 return; 1002 1003 case REG: 1004 putstr(rname(p->tn.rval)); 1005 return; 1006 1007 default: 1008 cerror( "illegal conput" ); 1009 } 1010 } 1011 1012 insput( p ) NODE *p; { 1013 cerror( "insput" ); 1014 } 1015 1016 adrput( p ) register NODE *p; { 1017 register int r; 1018 /* output an address, with offsets, from p */ 1019 1020 if( p->in.op == FLD ){ 1021 p = p->in.left; 1022 } 1023 switch( p->in.op ){ 1024 1025 case NAME: 1026 acon( p ); 1027 return; 1028 1029 case ICON: 1030 /* addressable value of the constant */ 1031 putchar('$'); 1032 acon( p ); 1033 return; 1034 1035 case REG: 1036 putstr(rname(p->tn.rval)); 1037 if(p->in.type == DOUBLE) /* for entry mask */ 1038 (void) rname(p->tn.rval+1); 1039 return; 1040 1041 case OREG: 1042 r = p->tn.rval; 1043 if( R2TEST(r) ){ /* double indexing */ 1044 register int flags; 1045 1046 flags = R2UPK3(r); 1047 if( flags & 1 ) putchar('*'); 1048 if( p->tn.lval != 0 || p->in.name[0] != '\0' ) acon(p); 1049 if( R2UPK1(r) != 100) printf( "(%s)", rname(R2UPK1(r)) ); 1050 printf( "[%s]", rname(R2UPK2(r)) ); 1051 return; 1052 } 1053 if( r == FP && p->tn.lval > 0 ){ /* in the argument region */ 1054 if( p->in.name[0] != '\0' ) werror( "bad arg temp" ); 1055 printf( CONFMT, p->tn.lval ); 1056 putstr( "(fp)" ); 1057 return; 1058 } 1059 if( p->tn.lval != 0 || p->in.name[0] != '\0') acon( p ); 1060 printf( "(%s)", rname(p->tn.rval) ); 1061 return; 1062 1063 case UNARY MUL: 1064 /* STARNM or STARREG found */ 1065 if( tshape(p, STARNM) ) { 1066 putchar( '*' ); 1067 adrput( p->in.left); 1068 } 1069 return; 1070 1071 default: 1072 cerror( "illegal address" ); 1073 return; 1074 1075 } 1076 1077 } 1078 1079 acon( p ) register NODE *p; { /* print out a constant */ 1080 1081 if( p->in.name[0] == '\0' ){ 1082 printf( CONFMT, p->tn.lval); 1083 return; 1084 } else { 1085 #ifndef FLEXNAMES 1086 printf( "%.8s", p->in.name ); 1087 #else 1088 putstr(p->in.name); 1089 #endif 1090 if (p->tn.lval != 0) { 1091 putchar('+'); 1092 printf(CONFMT, p->tn.lval); 1093 } 1094 } 1095 } 1096 1097 genscall( p, cookie ) register NODE *p; { 1098 /* structure valued call */ 1099 return( gencall( p, cookie ) ); 1100 } 1101 1102 genfcall( p, cookie ) register NODE *p; { 1103 register NODE *p1; 1104 register int m; 1105 static char *funcops[6] = { 1106 "sin", "cos", "sqrt", "exp", "log", "atan" 1107 }; 1108 1109 /* generate function opcodes */ 1110 if(p->in.op==UNARY FORTCALL && p->in.type==FLOAT && 1111 (p1 = p->in.left)->in.op==ICON && 1112 p1->tn.lval==0 && p1->in.type==INCREF(FTN|FLOAT)) { 1113 #ifdef FLEXNAMES 1114 p1->in.name++; 1115 #else 1116 strcpy(p1->in.name, p1->in.name[1]); 1117 #endif 1118 for(m=0; m<6; m++) 1119 if(!strcmp(p1->in.name, funcops[m])) 1120 break; 1121 if(m >= 6) 1122 uerror("no opcode for fortarn function %s", p1->in.name); 1123 } else 1124 uerror("illegal type of fortarn function"); 1125 p1 = p->in.right; 1126 p->in.op = FORTCALL; 1127 if(!canaddr(p1)) 1128 order( p1, INAREG|INBREG|SOREG|STARREG|STARNM ); 1129 m = match( p, INTAREG|INTBREG ); 1130 return(m != MDONE); 1131 } 1132 1133 /* tbl */ 1134 int gc_numbytes; 1135 /* tbl */ 1136 1137 gencall( p, cookie ) register NODE *p; { 1138 /* generate the call given by p */ 1139 register NODE *p1, *ptemp; 1140 register int temp, temp1; 1141 register int m; 1142 1143 if( p->in.right ) temp = argsize( p->in.right ); 1144 else temp = 0; 1145 1146 if( p->in.op == STCALL || p->in.op == UNARY STCALL ){ 1147 /* set aside room for structure return */ 1148 1149 if( p->stn.stsize > temp ) temp1 = p->stn.stsize; 1150 else temp1 = temp; 1151 } 1152 1153 if( temp > maxargs ) maxargs = temp; 1154 SETOFF(temp1,4); 1155 1156 if( p->in.right ){ /* make temp node, put offset in, and generate args */ 1157 ptemp = talloc(); 1158 ptemp->in.op = OREG; 1159 ptemp->tn.lval = -1; 1160 ptemp->tn.rval = SP; 1161 #ifndef FLEXNAMES 1162 ptemp->in.name[0] = '\0'; 1163 #else 1164 ptemp->in.name = ""; 1165 #endif 1166 ptemp->in.rall = NOPREF; 1167 ptemp->in.su = 0; 1168 genargs( p->in.right, ptemp ); 1169 ptemp->in.op = FREE; 1170 } 1171 1172 p1 = p->in.left; 1173 if( p1->in.op != ICON ){ 1174 if( p1->in.op != REG ){ 1175 if( p1->in.op != OREG || R2TEST(p1->tn.rval) ){ 1176 if( p1->in.op != NAME ){ 1177 order( p1, INAREG ); 1178 } 1179 } 1180 } 1181 } 1182 1183 /* tbl 1184 setup gc_numbytes so reference to ZC works */ 1185 1186 gc_numbytes = temp&(0x3ff); 1187 1188 p->in.op = UNARY CALL; 1189 m = match( p, INTAREG|INTBREG ); 1190 1191 return(m != MDONE); 1192 } 1193 1194 /* tbl */ 1195 char * 1196 ccbranches[] = { 1197 "eql", 1198 "neq", 1199 "leq", 1200 "lss", 1201 "geq", 1202 "gtr", 1203 "lequ", 1204 "lssu", 1205 "gequ", 1206 "gtru", 1207 }; 1208 /* tbl */ 1209 1210 cbgen( o, lab, mode ) { /* printf conditional and unconditional branches */ 1211 1212 if(o != 0 && (o < EQ || o > UGT )) 1213 cerror( "bad conditional branch: %s", opst[o] ); 1214 printf( " j%s L%d\n", 1215 o == 0 ? "br" : ccbranches[o-EQ], lab ); 1216 } 1217 1218 nextcook( p, cookie ) NODE *p; { 1219 /* we have failed to match p with cookie; try another */ 1220 if( cookie == FORREW ) return( 0 ); /* hopeless! */ 1221 if( !(cookie&(INTAREG|INTBREG)) ) return( INTAREG|INTBREG ); 1222 if( !(cookie&INTEMP) && asgop(p->in.op) ) return( INTEMP|INAREG|INTAREG|INTBREG|INBREG ); 1223 return( FORREW ); 1224 } 1225 1226 lastchance( p, cook ) NODE *p; { 1227 /* forget it! */ 1228 return(0); 1229 } 1230 1231 optim2( p ) register NODE *p; { 1232 # ifdef ONEPASS 1233 /* do local tree transformations and optimizations */ 1234 # define RV(p) p->in.right->tn.lval 1235 # define nncon(p) ((p)->in.op == ICON && (p)->in.name[0] == 0) 1236 register int o, i; 1237 register NODE *l, *r; 1238 1239 switch (o = p->in.op) { 1240 1241 case DIV: case ASG DIV: 1242 case MOD: case ASG MOD: 1243 /* 1244 * Change unsigned mods and divs to 1245 * logicals (mul is done in mip & c2) 1246 */ 1247 if (ISUNSIGNED(p->in.left->in.type) && nncon(p->in.right) && 1248 (i = ispow2(RV(p))) >= 0) { 1249 if (o == DIV || o == ASG DIV) { 1250 p->in.op = RS; 1251 RV(p) = i; 1252 } else { 1253 p->in.op = AND; 1254 RV(p)--; 1255 } 1256 if (asgop(o)) 1257 p->in.op = ASG p->in.op; 1258 } 1259 return; 1260 1261 case SCONV: 1262 l = p->in.left; 1263 /* clobber conversions w/o side effects */ 1264 if (!anyfloat(p, l) && l->in.op != PCONV && 1265 tlen(p) == tlen(l)) { 1266 if (l->in.op != FLD) 1267 l->in.type = p->in.type; 1268 ncopy(p, l); 1269 l->in.op = FREE; 1270 } 1271 return; 1272 1273 case ASSIGN: 1274 /* 1275 * Try to zap storage conversions of non-float items. 1276 */ 1277 r = p->in.right; 1278 if (r->in.op == SCONV && !anyfloat(r->in.left, r)) { 1279 int wdest, wconv, wsrc; 1280 wdest = tlen(p->in.left); 1281 wconv = tlen(r); 1282 /* 1283 * If size doesn't change across assignment or 1284 * conversion expands src before shrinking again 1285 * due to the assignment, delete conversion so 1286 * code generator can create optimal code. 1287 */ 1288 if (wdest == wconv || 1289 (wdest == (wsrc = tlen(r->in.left)) && wconv > wsrc)) { 1290 p->in.right = r->in.left; 1291 r->in.op = FREE; 1292 } 1293 } 1294 return; 1295 } 1296 # endif 1297 } 1298 1299 struct functbl { 1300 int fop; 1301 TWORD ftype; 1302 char *func; 1303 } opfunc[] = { 1304 DIV, TANY, "udiv", 1305 MOD, TANY, "urem", 1306 ASG DIV, TANY, "audiv", 1307 ASG MOD, TANY, "aurem", 1308 0, 0, 0 }; 1309 1310 hardops(p) register NODE *p; { 1311 /* change hard to do operators into function calls. */ 1312 register NODE *q; 1313 register struct functbl *f; 1314 register o; 1315 NODE *old,*temp; 1316 1317 o = p->in.op; 1318 if( ! (optype(o)==BITYPE && 1319 (ISUNSIGNED(p->in.left->in.type) || 1320 ISUNSIGNED(p->in.right->in.type))) ) 1321 return; 1322 1323 for( f=opfunc; f->fop; f++ ) { 1324 if( o==f->fop ) goto convert; 1325 } 1326 return; 1327 1328 convert: 1329 if( asgop( o ) ) { 1330 old = NIL; 1331 switch( p->in.left->in.op ){ 1332 case FLD: 1333 q = p->in.left->in.left; 1334 /* 1335 * rewrite (lval.fld /= rval); as 1336 * ((*temp).fld = udiv((*(temp = &lval)).fld,rval)); 1337 * else the compiler will evaluate lval twice. 1338 */ 1339 if( q->in.op == UNARY MUL ){ 1340 /* first allocate a temp storage */ 1341 temp = talloc(); 1342 temp->in.op = OREG; 1343 temp->tn.rval = TMPREG; 1344 temp->tn.lval = BITOOR(freetemp(1)); 1345 temp->in.type = INCREF(p->in.type); 1346 #ifdef FLEXNAMES 1347 temp->in.name = ""; 1348 #else 1349 temp->in.name[0] = '\0'; 1350 #endif 1351 old = q->in.left; 1352 q->in.left = temp; 1353 } 1354 /* fall thru ... */ 1355 1356 case REG: 1357 case NAME: 1358 case OREG: 1359 /* change ASG OP to a simple OP */ 1360 q = talloc(); 1361 q->in.op = NOASG p->in.op; 1362 q->in.rall = NOPREF; 1363 q->in.type = p->in.type; 1364 q->in.left = tcopy(p->in.left); 1365 q->in.right = p->in.right; 1366 p->in.op = ASSIGN; 1367 p->in.right = q; 1368 p = q; 1369 f -= 2; /* Note: this depends on the table order */ 1370 /* on the right side only - replace *temp with 1371 *(temp = &lval), build the assignment node */ 1372 if( old ){ 1373 temp = q->in.left->in.left; /* the "*" node */ 1374 q = talloc(); 1375 q->in.op = ASSIGN; 1376 q->in.left = temp->in.left; 1377 q->in.right = old; 1378 q->in.type = old->in.type; 1379 #ifdef FLEXNAMES 1380 q->in.name = ""; 1381 #else 1382 q->in.name[0] = '\0'; 1383 #endif 1384 temp->in.left = q; 1385 } 1386 break; 1387 1388 case UNARY MUL: 1389 /* avoid doing side effects twice */ 1390 q = p->in.left; 1391 p->in.left = q->in.left; 1392 q->in.op = FREE; 1393 break; 1394 1395 default: 1396 cerror( "hardops: can't compute & LHS" ); 1397 } 1398 } 1399 1400 /* build comma op for args to function */ 1401 q = talloc(); 1402 q->in.op = CM; 1403 q->in.rall = NOPREF; 1404 q->in.type = INT; 1405 q->in.left = p->in.left; 1406 q->in.right = p->in.right; 1407 p->in.op = CALL; 1408 p->in.right = q; 1409 1410 /* put function name in left node of call */ 1411 p->in.left = q = talloc(); 1412 q->in.op = ICON; 1413 q->in.rall = NOPREF; 1414 q->in.type = INCREF( FTN + p->in.type ); 1415 #ifndef FLEXNAMES 1416 strcpy( q->in.name, f->func ); 1417 #else 1418 q->in.name = f->func; 1419 #endif 1420 q->tn.lval = 0; 1421 q->tn.rval = 0; 1422 1423 } 1424 1425 zappost(p) NODE *p; { 1426 /* look for ++ and -- operators and remove them */ 1427 1428 register int o, ty; 1429 register NODE *q; 1430 o = p->in.op; 1431 ty = optype( o ); 1432 1433 switch( o ){ 1434 1435 case INCR: 1436 case DECR: 1437 q = p->in.left; 1438 p->in.right->in.op = FREE; /* zap constant */ 1439 ncopy( p, q ); 1440 q->in.op = FREE; 1441 return; 1442 1443 } 1444 1445 if( ty == BITYPE ) zappost( p->in.right ); 1446 if( ty != LTYPE ) zappost( p->in.left ); 1447 } 1448 1449 fixpre(p) NODE *p; { 1450 1451 register int o, ty; 1452 o = p->in.op; 1453 ty = optype( o ); 1454 1455 switch( o ){ 1456 1457 case ASG PLUS: 1458 p->in.op = PLUS; 1459 break; 1460 case ASG MINUS: 1461 p->in.op = MINUS; 1462 break; 1463 } 1464 1465 if( ty == BITYPE ) fixpre( p->in.right ); 1466 if( ty != LTYPE ) fixpre( p->in.left ); 1467 } 1468 1469 NODE * addroreg(l) NODE *l; 1470 /* OREG was built in clocal() 1471 * for an auto or formal parameter 1472 * now its address is being taken 1473 * local code must unwind it 1474 * back to PLUS/MINUS REG ICON 1475 * according to local conventions 1476 */ 1477 { 1478 cerror("address of OREG taken"); 1479 } 1480 1481 # ifndef ONEPASS 1482 main( argc, argv ) char *argv[]; { 1483 return( mainp2( argc, argv ) ); 1484 } 1485 # endif 1486 1487 strip(p) register NODE *p; { 1488 NODE *q; 1489 1490 /* strip nodes off the top when no side effects occur */ 1491 for( ; ; ) { 1492 switch( p->in.op ) { 1493 case SCONV: /* remove lint tidbits */ 1494 q = p->in.left; 1495 ncopy( p, q ); 1496 q->in.op = FREE; 1497 break; 1498 /* could probably add a few more here */ 1499 default: 1500 return; 1501 } 1502 } 1503 } 1504 1505 myreader(p) register NODE *p; { 1506 strip( p ); /* strip off operations with no side effects */ 1507 walkf( p, hardops ); /* convert ops to function calls */ 1508 canon( p ); /* expands r-vals for fileds */ 1509 walkf( p, optim2 ); 1510 } 1511