1 #ifndef lint 2 static char sccsid[] = "@(#)local2.c 1.29 (Berkeley) 01/14/88"; 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 /*ARGSUSED*/ 20 where(c){ 21 fprintf( stderr, "%s, line %d: ", filename, lineno ); 22 } 23 # endif 24 25 lineid( l, fn ) char *fn; { 26 /* identify line l and file fn */ 27 printf( "# line %d, file %s\n", l, fn ); 28 } 29 30 int ent_mask; 31 32 eobl2(){ 33 register OFFSZ spoff; /* offset from stack pointer */ 34 #ifndef FORT 35 extern int ftlab1, ftlab2; 36 #endif 37 38 spoff = maxoff; 39 spoff /= SZCHAR; 40 SETOFF(spoff,4); 41 #ifdef FORT 42 #ifndef FLEXNAMES 43 printf( " .set .F%d,%ld\n", ftnno, spoff ); 44 #else 45 /* SHOULD BE L%d ... ftnno but must change pc/f77 */ 46 printf( " .set LF%d,%ld\n", ftnno, spoff ); 47 #endif 48 printf( " .set LWM%d,0x%x\n", ftnno, ent_mask&0x1ffc|0x1000); 49 #else 50 printf( " .set L%d,0x%x\n", ftnno, ent_mask&0x1ffc); 51 printf( "L%d:\n", ftlab1); 52 if( maxoff > AUTOINIT ) 53 printf( " subl3 $%ld,fp,sp\n", spoff); 54 printf( " jbr L%d\n", ftlab2); 55 #endif 56 ent_mask = 0; 57 maxargs = -1; 58 } 59 60 struct hoptab { int opmask; char * opstring; } ioptab[] = { 61 62 PLUS, "add", 63 MINUS, "sub", 64 MUL, "mul", 65 DIV, "div", 66 MOD, "div", 67 OR, "or", 68 ER, "xor", 69 AND, "and", 70 -1, "" }; 71 72 hopcode( f, o ){ 73 /* output the appropriate string from the above table */ 74 75 register struct hoptab *q; 76 77 if(asgop(o)) 78 o = NOASG o; 79 for( q = ioptab; q->opmask>=0; ++q ){ 80 if( q->opmask == o ){ 81 if(f == 'E') 82 printf( "e%s", q->opstring); 83 else 84 printf( "%s%c", q->opstring, tolower(f)); 85 return; 86 } 87 } 88 cerror( "no hoptab for %s", opst[o] ); 89 } 90 91 char * 92 rnames[] = { /* keyed to register number tokens */ 93 94 "r0", "r1", 95 "r2", "r3", "r4", "r5", 96 "r6", "r7", "r8", "r9", "r10", "r11", 97 "r12", "fp", "sp", "pc", 98 }; 99 100 /* output register name and update entry mask */ 101 char * 102 rname(r) 103 register int r; 104 { 105 106 if (!istreg(r)) 107 ent_mask |= 1<<r; 108 return(rnames[r]); 109 } 110 111 int rstatus[] = { 112 SAREG|STAREG, SAREG|STAREG, 113 SAREG|STAREG, SAREG|STAREG, SAREG|STAREG, SAREG|STAREG, 114 SAREG, SAREG, SAREG, SAREG, SAREG, SAREG, 115 SAREG, SAREG, SAREG, SAREG, 116 }; 117 118 tlen(p) NODE *p; 119 { 120 switch(p->in.type) { 121 case CHAR: 122 case UCHAR: 123 return(1); 124 125 case SHORT: 126 case USHORT: 127 return(SZSHORT/SZCHAR); 128 129 case DOUBLE: 130 return(SZDOUBLE/SZCHAR); 131 132 default: 133 return(SZINT/SZCHAR); 134 } 135 } 136 137 mixtypes(p, q) NODE *p, *q; 138 { 139 register TWORD tp, tq; 140 141 tp = p->in.type; 142 tq = q->in.type; 143 144 return( (tp==FLOAT || tp==DOUBLE) != 145 (tq==FLOAT || tq==DOUBLE) ); 146 } 147 148 prtype(n) NODE *n; 149 { 150 switch (n->in.type) 151 { 152 153 case DOUBLE: 154 putchar('d'); 155 return; 156 157 case FLOAT: 158 putchar('f'); 159 return; 160 161 case LONG: 162 case ULONG: 163 case INT: 164 case UNSIGNED: 165 putchar('l'); 166 return; 167 168 case SHORT: 169 case USHORT: 170 putchar('w'); 171 return; 172 173 case CHAR: 174 case UCHAR: 175 putchar('b'); 176 return; 177 178 default: 179 if ( !ISPTR( n->in.type ) ) cerror("zzzcode- bad type"); 180 else { 181 putchar('l'); 182 return; 183 } 184 } 185 } 186 187 zzzcode( p, c ) register NODE *p; { 188 register int m; 189 int val; 190 switch( c ){ 191 192 case 'N': /* logical ops, turned into 0-1 */ 193 /* use register given by register 1 */ 194 cbgen( 0, m=getlab(), 'I' ); 195 deflab( p->bn.label ); 196 printf( " clrl %s\n", rname(getlr( p, '1' )->tn.rval) ); 197 deflab( m ); 198 return; 199 200 case 'P': 201 cbgen( p->in.op, p->bn.label, c ); 202 return; 203 204 case 'G': /* i *= f; asgops with int lhs and float rhs */ 205 { 206 register NODE *l, *r, *s; 207 int lt, rt; 208 209 l = p->in.left; 210 r = p->in.right; 211 s = talloc(); 212 rt = r->in.type; 213 lt = l->in.type; 214 215 if (lt != INT && lt != UNSIGNED) { 216 s->in.op = SCONV; 217 s->in.left = l; 218 s->in.type = ISUNSIGNED(lt) ? UNSIGNED : INT; 219 zzzcode(s, 'U'); 220 putstr("\n\t"); 221 } 222 223 if (ISUNSIGNED(lt)) { 224 s->in.op = SCONV; 225 s->in.left = lt == UNSIGNED ? l : resc; 226 s->in.type = rt; 227 unsigned_to_float(s); 228 } else { 229 putstr("cvl"); 230 prtype(r); 231 putchar('\t'); 232 adrput(lt == INT ? l : resc); 233 } 234 putstr("\n\t"); 235 236 hopcode(rt == FLOAT ? 'F' : 'D', p->in.op); 237 putchar('\t'); 238 adrput(r); 239 240 if (ISUNSIGNED(lt)) { 241 putstr("\n\t"); 242 s->in.op = SCONV; 243 s->in.left = r; /* we need only the type */ 244 s->in.type = UNSIGNED; 245 float_to_unsigned(s); 246 } else { 247 putstr("\n\tcv"); 248 prtype(r); 249 putstr("l\t"); 250 if (lt == INT) 251 adrput(l); 252 else 253 adrput(resc); 254 } 255 if (lt != INT) { 256 putstr("\n\t"); 257 s->in.op = ASSIGN; 258 s->in.left = l; 259 s->in.right = resc; 260 s->in.type = lt; 261 zzzcode(s, 'U'); 262 } 263 264 s->in.op = FREE; 265 return; 266 } 267 268 case 'J': /* unsigned DIV/MOD with constant divisors */ 269 { 270 register int ck = INAREG; 271 int label1, label2; 272 273 /* case constant <= 1 is handled by optim() in pass 1 */ 274 /* case constant < 0x80000000 is handled in table */ 275 switch( p->in.op ) { 276 /* case DIV: handled in optim2() */ 277 case MOD: 278 if( p->in.left->in.op == REG && 279 p->in.left->tn.rval == resc->tn.rval ) 280 goto asgmod; 281 label1 = getlab(); 282 expand(p, ck, "movl\tAL,A1\n\tcmpl\tA1,AR\n"); 283 printf("\tjlssu\tL%d\n", label1); 284 expand(p, ck, "\tsubl2\tAR,A1\n"); 285 printf("L%d:", label1); 286 break; 287 case ASG DIV: 288 label1 = getlab(); 289 label2 = getlab(); 290 expand(p, ck, "cmpl\tAL,AR\n"); 291 printf("\tjgequ\tL%d\n", label1); 292 expand(p, ck, "\tmovl\t$1,AL\n"); 293 printf("\tjbr\tL%d\nL%d:\n", label2, label1); 294 expand(p, ck, "\tclrl\tAL\n"); 295 printf("L%d:", label2); 296 break; 297 case ASG MOD: 298 asgmod: 299 label1 = getlab(); 300 expand(p, ck, "cmpl\tAL,AR\n"); 301 printf("\tjlssu\tL%d\n", label1); 302 expand(p, ck, "\tsubl2\tAR,AL\n"); 303 printf("L%d:", label1); 304 break; 305 } 306 return; 307 } 308 309 case 'B': /* get oreg value in temp register for shift */ 310 { 311 register NODE *r; 312 if (xdebug) eprint(p, 0, &val, &val); 313 r = p->in.right; 314 if( tlen(r) == SZINT/SZCHAR && r->in.type != FLOAT ) 315 putstr("movl"); 316 else { 317 putstr(ISUNSIGNED(r->in.type) ? "movz" : "cvt"); 318 prtype(r); 319 putchar('l'); 320 } 321 return; 322 } 323 324 case 'C': /* generate 'call[fs] $bytes' */ 325 { 326 extern int gc_numbytes; 327 extern int xdebug; 328 329 if (xdebug) printf("->%d<-",gc_numbytes); 330 331 printf("call%c $%d", 332 (p->in.left->in.op==ICON && gc_numbytes<60)?'f':'s', 333 gc_numbytes+4); 334 /* don't change to double (here's the only place to catch it) */ 335 if(p->in.type == FLOAT) 336 rtyflg = 1; 337 return; 338 } 339 340 case 'D': /* INCR and DECR */ 341 zzzcode(p->in.left, 'U'); 342 putstr("\n "); 343 344 case 'E': /* INCR and DECR, FOREFF */ 345 if (p->in.right->tn.lval == 1) 346 { 347 putstr(p->in.op == INCR ? "inc" : "dec"); 348 prtype(p->in.left); 349 putchar('\t'); 350 adrput(p->in.left); 351 return; 352 } 353 putstr(p->in.op == INCR ? "add" : "sub"); 354 prtype(p->in.left); 355 putstr("2 "); 356 adrput(p->in.right); 357 putchar(','); 358 adrput(p->in.left); 359 return; 360 361 case 'F': /* masked constant for fields */ 362 printf(ACONFMT, (p->in.right->tn.lval&((1<<fldsz)-1))<<fldshf); 363 return; 364 365 case 'I': /* produce value of bitfield assignment */ 366 /* avoid shifts -- shifts are SLOW on this machine */ 367 /* XXX this wouldn't be necessary if we were smarter 368 and masked BEFORE shifting XXX */ 369 { 370 register NODE *r = p->in.right; 371 if(r->in.op == ICON && r->tn.name[0] == '\0') { 372 putstr("movl\t"); 373 printf(ACONFMT, r->tn.lval & ((1<<fldsz)-1)); 374 } 375 else { 376 putstr("andl3\t"); 377 printf(ACONFMT, (1 << fldsz) - 1); 378 putchar(','); 379 adrput(r); 380 } 381 putchar(','); 382 adrput(resc); 383 break; 384 } 385 386 case 'H': /* opcode for shift */ 387 if(p->in.op == LS || p->in.op == ASG LS) 388 putstr("shll"); 389 else if(ISUNSIGNED(p->in.left->in.type)) 390 putstr("shrl"); 391 else 392 putstr("shar"); 393 return; 394 395 case 'L': /* type of left operand */ 396 case 'R': /* type of right operand */ 397 { 398 register NODE *n; 399 extern int xdebug; 400 401 n = getlr ( p, c); 402 if (xdebug) printf("->%d<-", n->in.type); 403 404 prtype(n); 405 return; 406 } 407 408 case 'M': { /* initiate ediv for mod and unsigned div */ 409 putstr("clrl\t"); 410 adrput(resc); 411 putstr("\n\tmovl\t"); 412 adrput(p->in.left); 413 putchar(','); 414 upput(resc, SZLONG); 415 printf("\n\tjgeq\tL%d\n\tmnegl\t$1,", m = getlab()); 416 adrput(resc); 417 putchar('\n'); 418 deflab(m); 419 return; 420 } 421 422 case 'T': { /* rounded structure length for arguments */ 423 int size = p->stn.stsize; 424 SETOFF( size, 4); 425 printf("movab -%d(sp),sp", size); 426 return; 427 } 428 429 case 'S': /* structure assignment */ 430 stasg(p); 431 break; 432 433 #ifdef I_don_t_understand_this 434 case 'X': /* multiplication for short and char */ 435 if (ISUNSIGNED(p->in.left->in.type)) 436 printf("\tmovz"); 437 else 438 printf("\tcvt"); 439 zzzcode(p, 'L'); 440 printf("l\t"); 441 adrput(p->in.left); 442 printf(","); 443 adrput(&resc[0]); 444 printf("\n"); 445 if (ISUNSIGNED(p->in.right->in.type)) 446 printf("\tmovz"); 447 else 448 printf("\tcvt"); 449 zzzcode(p, 'R'); 450 printf("l\t"); 451 adrput(p->in.right); 452 printf(","); 453 adrput(&resc[1]); 454 printf("\n"); 455 return; 456 #endif 457 458 case 'U': /* SCONV */ 459 case 'V': /* SCONV with FORCC */ 460 sconv(p, c == 'V'); 461 break; 462 463 case 'W': { /* SCONV or ASSIGN float/double => unsigned */ 464 NODE *src = p->in.op == SCONV ? p->in.left : p->in.right; 465 466 putstr("ld"); 467 prtype(src); 468 putchar('\t'); 469 adrput(src); 470 putstr("\n\t"); 471 float_to_unsigned(p); 472 break; 473 } 474 475 case 'Y': /* SCONV or ASSIGN unsigned => float/double */ 476 unsigned_to_float(p); /* stores into accumulator */ 477 putstr("\n\tst"); 478 prtype(p); 479 putchar('\t'); 480 if (p->in.op == SCONV) 481 adrput(resc); 482 else 483 adrput(p->in.left); 484 rtyflg = 1; 485 break; 486 487 #ifdef I_don_t_understand_this 488 case 'Z': 489 p = p->in.right; 490 switch (p->in.type) { 491 case SHORT: { 492 short w = p->tn.lval; 493 p->tn.lval = w; 494 break; 495 } 496 case CHAR: { 497 char c = p->tn.lval; 498 p->tn.lval = c; 499 break; 500 } 501 } 502 printf("$%d", p->tn.lval); 503 break; 504 #endif 505 506 default: 507 cerror( "illegal zzzcode" ); 508 } 509 } 510 511 #define MOVB(dst, src, off) { \ 512 putstr("\tmovb\t"); upput(src, off); putchar(','); \ 513 upput(dst, off); putchar('\n'); \ 514 } 515 #define MOVW(dst, src, off) { \ 516 putstr("\tmovw\t"); upput(src, off); putchar(','); \ 517 upput(dst, off); putchar('\n'); \ 518 } 519 #define MOVL(dst, src, off) { \ 520 putstr("\tmovl\t"); upput(src, off); putchar(','); \ 521 upput(dst, off); putchar('\n'); \ 522 } 523 /* 524 * Generate code for a structure assignment. 525 */ 526 stasg(p) 527 register NODE *p; 528 { 529 register NODE *l, *r; 530 register int size; 531 532 switch (p->in.op) { 533 case STASG: /* regular assignment */ 534 l = p->in.left; 535 r = p->in.right; 536 break; 537 case STARG: /* place arg on the stack */ 538 l = getlr(p, '3'); 539 r = p->in.left; 540 break; 541 default: 542 cerror("STASG bad"); 543 /*NOTREACHED*/ 544 } 545 /* 546 * Pun source for use in code generation. 547 */ 548 switch (r->in.op) { 549 case ICON: 550 r->in.op = NAME; 551 break; 552 case REG: 553 r->in.op = OREG; 554 break; 555 default: 556 cerror( "STASG-r" ); 557 /*NOTREACHED*/ 558 } 559 size = p->stn.stsize; 560 if (size <= 0 || size > 65535) 561 cerror("structure size out of range"); 562 /* 563 * Generate optimized code based on structure size 564 * and alignment properties.... 565 */ 566 switch (size) { 567 568 case 1: 569 putstr("\tmovb\t"); 570 optimized: 571 adrput(r); 572 putchar(','); 573 adrput(l); 574 putchar('\n'); 575 break; 576 577 case 2: 578 if (p->stn.stalign != 2) { 579 MOVB(l, r, SZCHAR); 580 putstr("\tmovb\t"); 581 } else 582 putstr("\tmovw\t"); 583 goto optimized; 584 585 case 4: 586 if (p->stn.stalign != 4) { 587 if (p->stn.stalign != 2) { 588 MOVB(l, r, 3*SZCHAR); 589 MOVB(l, r, 2*SZCHAR); 590 MOVB(l, r, 1*SZCHAR); 591 putstr("\tmovb\t"); 592 } else { 593 MOVW(l, r, SZSHORT); 594 putstr("\tmovw\t"); 595 } 596 } else 597 putstr("\tmovl\t"); 598 goto optimized; 599 600 case 6: 601 if (p->stn.stalign != 2) 602 goto movblk; 603 MOVW(l, r, 2*SZSHORT); 604 MOVW(l, r, 1*SZSHORT); 605 putstr("\tmovw\t"); 606 goto optimized; 607 608 case 8: 609 if (p->stn.stalign == 4) { 610 MOVL(l, r, SZLONG); 611 putstr("\tmovl\t"); 612 goto optimized; 613 } 614 /* fall thru...*/ 615 616 default: 617 movblk: 618 /* 619 * Can we ever get a register conflict with R1 here? 620 */ 621 putstr("\tmovab\t"); 622 if(r->in.op == OREG && r->tn.rval == R1) 623 { 624 adrput(r); 625 printf(",r0\n\tmovab\t"); 626 adrput(l); 627 putstr(",r1\n"); 628 } 629 else 630 { 631 adrput(l); 632 putstr(",r1\n\tmovab\t"); 633 adrput(r); 634 printf(",r0\n"); 635 } 636 printf("\tmovl\t$%d,r2\n\tmovblk\n", size); 637 rname(R2); 638 break; 639 } 640 /* 641 * Reverse above pun for reclaim. 642 */ 643 if (r->in.op == NAME) 644 r->in.op = ICON; 645 else if (r->in.op == OREG) 646 r->in.op = REG; 647 } 648 649 /* 650 * Convert a float or double in the accumulator into an unsigned int. 651 * Unlike the vax, the tahoe stores 0 into the destination 652 * on a conversion of > 2 ** 31, so we compensate. 653 */ 654 float_to_unsigned(p) 655 NODE *p; 656 { 657 register NODE *l = p->in.left; 658 int label1 = getlab(); 659 int label2 = getlab(); 660 int label3 = getlab(); 661 NODE *src, *dst; 662 663 if (p->in.op == SCONV) { 664 src = p->in.left; 665 dst = resc; 666 } else { 667 src = p->in.right; 668 dst = p->in.left; 669 } 670 671 printf(".data\n\t.align\t2\nL%d:\n\t.long\t0x50000000", label1); 672 if (src->in.type == DOUBLE) 673 putstr(", 0x00000000 # .double"); 674 else 675 putstr(" # .float"); 676 putstr(" 2147483648\n\t.text\n\tcmp"); 677 prtype(src); 678 printf("\tL%d\n\tjlss\tL%d\n\tsub", label1, label2); 679 prtype(src); 680 printf("\tL%d\n\tcv", label1); 681 prtype(src); 682 putstr("l\t"); 683 adrput(dst); 684 putstr("\n\taddl2\t$-2147483648,"); 685 adrput(dst); 686 printf("\n\tjbr\tL%d\nL%d:\n\tcv", label3, label2); 687 prtype(src); 688 putstr("l\t"); 689 adrput(dst); 690 printf("\nL%d:", label3); 691 } 692 693 /* 694 * Convert an unsigned int into a float or double, leaving the result 695 * in the accumulator. 696 */ 697 unsigned_to_float(p) 698 register NODE *p; 699 { 700 int label1 = getlab(); 701 int label2 = getlab(); 702 NODE *src, *dst; 703 704 if (p->in.op == SCONV) { 705 src = p->in.left; 706 dst = resc; 707 } else { 708 src = p->in.right; 709 dst = p->in.left; 710 } 711 712 printf(".data\n\t.align\t2\nL%d:\n\t.long\t0x50800000", label2); 713 if (p->in.type == DOUBLE) 714 putstr(", 0x00000000 # .double"); 715 else 716 putstr(" # .float"); 717 putstr(" 4294967296\n\t.text\n\tmovl\t"); 718 adrput(src); 719 putchar(','); 720 adrput(dst); 721 putstr("\n\tcvl"); 722 prtype(p); 723 putchar('\t'); 724 adrput(dst); 725 printf("\n\tjgeq\tL%d\n\tadd", label1); 726 prtype(p); 727 printf("\tL%d\nL%d:", label2, label1); 728 } 729 730 /* 731 * Prlen() is a cheap prtype()... 732 */ 733 static char convtab[SZINT/SZCHAR + 1] = { 734 '?', 'b', 'w', '?', 'l' 735 }; 736 #define prlen(len) putchar(convtab[len]) 737 738 739 /* 740 * Generate code for integral scalar conversions. 741 * Some of this code is designed to work around a tahoe misfeature 742 * that causes sign- and zero- extension to be defeated in 743 * certain circumstances. 744 * Basically if the source operand of a CVT or MOVZ instruction is 745 * shorter than the destination, and the source is a register 746 * or an immediate constant, sign- and zero- extension are 747 * ignored and the high bits of the source are copied. (Note 748 * that zero-extension is not a problem for immediate 749 * constants.) 750 * Another problem -- condition codes for a conversion with a 751 * register source reflect the source rather than the destination. 752 */ 753 sconv(p, forcc) 754 NODE *p; 755 int forcc; 756 { 757 register NODE *src, *dst; 758 register NODE *tmp; 759 register int srclen, dstlen; 760 int srctype, dsttype; 761 int val; 762 int neg = 0; 763 764 if (p->in.op == ASSIGN) { 765 src = p->in.right; 766 dst = p->in.left; 767 dstlen = tlen(dst); 768 dsttype = dst->in.type; 769 } else if (p->in.op == SCONV) { 770 src = p->in.left; 771 dst = resc; 772 dstlen = tlen(p); 773 dsttype = p->in.type; 774 } else /* if (p->in.op == OPLEAF) */ { 775 src = p; 776 dst = resc; 777 dstlen = SZINT/SZCHAR; 778 dsttype = ISUNSIGNED(src->in.type) ? UNSIGNED : INT; 779 } 780 781 if (src->in.op == REG) { 782 srclen = SZINT/SZCHAR; 783 srctype = ISUNSIGNED(src->in.type) ? UNSIGNED : INT; 784 } else { 785 srclen = tlen(src); 786 srctype = src->in.type; 787 } 788 789 if (src->in.op == ICON && src->tn.name[0] == '\0') { 790 if (src->tn.lval == 0) { 791 putstr("clr"); 792 prtype(dst); 793 putchar('\t'); 794 adrput(dst); 795 return; 796 } 797 if (dstlen < srclen) { 798 switch (dsttype) { 799 case CHAR: 800 src->tn.lval = (char) src->tn.lval; 801 break; 802 case UCHAR: 803 src->tn.lval = (unsigned char) src->tn.lval; 804 break; 805 case SHORT: 806 src->tn.lval = (short) src->tn.lval; 807 break; 808 case USHORT: 809 src->tn.lval = (unsigned short) src->tn.lval; 810 break; 811 } 812 } 813 if (dst->in.op == REG) { 814 dsttype = INT; 815 dstlen = SZINT/SZCHAR; 816 } 817 srctype = dsttype; 818 srclen = dstlen; 819 val = -src->tn.lval & ((1 << dstlen * SZCHAR) - 1); 820 if ((unsigned) val < 64) { 821 src->tn.lval = val; 822 ++neg; /* MNEGx may be shorter */ 823 } 824 } 825 826 if (srclen < dstlen) { 827 if (srctype == CHAR && dsttype == USHORT && dst->in.op == REG) { 828 /* (unsigned short) c; => sign extend to 16 bits */ 829 putstr("cvtbl\t"); 830 adrput(src); 831 putstr(",-(sp)\n\tmovzwl\t2(sp),"); 832 adrput(dst); 833 putstr("\n\tmovab\t4(sp),sp"); 834 if (forcc) { 835 /* inverted test */ 836 putstr("\n\tcmpl\t$0,"); 837 adrput(dst); 838 } 839 return; 840 } 841 genconv(ISUNSIGNED(srctype), 842 srclen, dst->in.op == REG ? SZINT/SZCHAR : dstlen, 843 src, dst, forcc); 844 return; 845 } 846 847 if (srclen > dstlen && dst->in.op == REG) { 848 /* if dst is a register, the result must look like an int */ 849 if (src->in.op == REG) { 850 if (ISUNSIGNED(dsttype)) { 851 val = (1 << dstlen * SZCHAR) - 1; 852 if (src->tn.rval == dst->tn.rval) 853 /* conversion in place */ 854 printf("andl2\t$%ld,", val); 855 else { 856 printf("andl3\t$%ld,", val); 857 adrput(src); 858 putchar(','); 859 } 860 adrput(dst); 861 return; 862 } 863 /* 864 * Sign extension in register can also be 865 * accomplished by shifts, but unfortunately 866 * shifts are extremely slow, due to the lack 867 * of a barrel shifter. 868 */ 869 putstr("pushl\t"); 870 adrput(src); 871 putstr("\n\tcvt"); 872 prlen(dstlen); 873 printf("l\t%d(sp),", SZINT/SZCHAR - dstlen); 874 adrput(dst); 875 putstr("\n\tmovab\t4(sp),sp"); 876 if (forcc) { 877 /* inverted test */ 878 putstr("\n\tcmpl\t$0,"); 879 adrput(dst); 880 } 881 return; 882 } 883 tmp = talloc(); 884 if ((src->in.op == NAME) || 885 (src->in.op == UNARY MUL && src->in.left->in.op == ICON) || 886 (src->in.op == OREG && !R2TEST(src->tn.rval))) { 887 /* we can increment src's address & pun it */ 888 *tmp = *src; 889 tmp->tn.lval += srclen - dstlen; 890 } else { 891 /* we must store src's address */ 892 *tmp = *dst; 893 putstr("mova"); 894 prlen(srclen); 895 putchar('\t'); 896 adrput(src); 897 putchar(','); 898 adrput(tmp); 899 putstr("\n\t"); 900 tmp->tn.op = OREG; 901 tmp->tn.lval = srclen - dstlen; 902 } 903 genconv(ISUNSIGNED(dsttype), dstlen, SZINT/SZCHAR, tmp, dst, forcc); 904 tmp->in.op = FREE; 905 return; 906 } 907 908 genconv(neg ? -1 : ISUNSIGNED(dsttype), 909 srclen, dst->in.op == REG ? SZINT/SZCHAR : dstlen, 910 src, dst, forcc); 911 } 912 913 genconv(srcflag, srclen, dstlen, src, dst, forcc) 914 int srcflag; 915 register int srclen, dstlen; 916 NODE *src, *dst; 917 int forcc; 918 { 919 if (srclen != dstlen) { 920 if (srcflag > 0 && srclen < dstlen) 921 putstr("movz"); 922 else 923 putstr("cvt"); 924 prlen(srclen); 925 } else if (srcflag < 0) 926 putstr("mneg"); 927 else 928 putstr("mov"); 929 prlen(dstlen); 930 putchar('\t'); 931 adrput(src); 932 putchar(','); 933 adrput(dst); 934 935 /* 936 * This hack is made necessary by architecture problems 937 * described above 938 */ 939 if (forcc && src->in.op == REG && srclen > dstlen) { 940 putstr("\n\ttst"); 941 prlen(dstlen); 942 putchar('\t'); 943 adrput(dst); 944 } 945 } 946 947 rmove( rt, rs, t ) TWORD t; { 948 printf( " movl %s,%s\n", rname(rs), rname(rt) ); 949 if(t==DOUBLE) 950 printf( " movl %s,%s\n", rname(rs+1), rname(rt+1) ); 951 } 952 953 struct respref 954 respref[] = { 955 INTAREG|INTBREG, INTAREG|INTBREG, 956 INAREG|INBREG, INAREG|INBREG|SOREG|STARREG|STARNM|SNAME|SCON, 957 INTEMP, INTEMP, 958 FORARG, FORARG, 959 INTEMP, INTAREG|INAREG|INTBREG|INBREG|SOREG|STARREG|STARNM, 960 0, 0 }; 961 962 setregs(){ /* set up temporary registers */ 963 fregs = 6; /* tbl- 6 free regs on Tahoe (0-5) */ 964 } 965 966 #ifndef szty 967 szty(t) TWORD t;{ /* size, in registers, needed to hold thing of type t */ 968 return(t==DOUBLE ? 2 : 1 ); 969 } 970 #endif 971 972 /*ARGSUSED*/ 973 rewfld( p ) NODE *p; { 974 return(1); 975 } 976 977 /*ARGSUSED*/ 978 callreg(p) NODE *p; { 979 return( R0 ); 980 } 981 982 base( p ) register NODE *p; { 983 register int o = p->in.op; 984 985 if( o==ICON && p->in.name[0] != '\0' ) return( 100 ); /* ie no base reg */ 986 if( o==REG ) return( p->tn.rval ); 987 if( (o==PLUS || o==MINUS) && p->in.left->in.op == REG && p->in.right->in.op==ICON) 988 return( p->in.left->tn.rval ); 989 if( o==OREG && !R2TEST(p->tn.rval) && (p->in.type==INT || p->in.type==UNSIGNED || ISPTR(p->in.type)) ) 990 return( p->tn.rval + 0200*1 ); 991 if( o==NAME ) return( 100 + 0200*1 ); 992 return( -1 ); 993 } 994 995 offset( p, tyl ) register NODE *p; int tyl; { 996 997 if( tyl==1 && 998 p->in.op==REG && 999 (p->in.type==INT || p->in.type==UNSIGNED) ) 1000 return( p->tn.rval ); 1001 if( p->in.op==LS && 1002 p->in.left->in.op==REG && 1003 (p->in.left->in.type==INT || p->in.left->in.type==UNSIGNED) && 1004 p->in.right->in.op==ICON && 1005 p->in.right->in.name[0]=='\0' && 1006 (1<<p->in.right->tn.lval)==tyl) 1007 return( p->in.left->tn.rval ); 1008 if( tyl==2 && 1009 p->in.op==PLUS && 1010 (p->in.left->in.type==INT || p->in.left->in.type==UNSIGNED) && 1011 p->in.left->in.op==REG && 1012 p->in.right->in.op==REG && 1013 p->in.left->tn.rval==p->in.right->tn.rval ) 1014 return( p->in.left->tn.rval ); 1015 return( -1 ); 1016 } 1017 1018 makeor2( p, q, b, o) register NODE *p, *q; register int b, o; { 1019 register NODE *t; 1020 NODE *f; 1021 1022 p->in.op = OREG; 1023 f = p->in.left; /* have to free this subtree later */ 1024 1025 /* init base */ 1026 switch (q->in.op) { 1027 case ICON: 1028 case REG: 1029 case OREG: 1030 case NAME: 1031 t = q; 1032 break; 1033 1034 case MINUS: 1035 q->in.right->tn.lval = -q->in.right->tn.lval; 1036 case PLUS: 1037 t = q->in.right; 1038 break; 1039 1040 case UNARY MUL: 1041 t = q->in.left->in.left; 1042 break; 1043 1044 default: 1045 cerror("illegal makeor2"); 1046 } 1047 1048 p->tn.lval = t->tn.lval; 1049 #ifndef FLEXNAMES 1050 { 1051 register int i; 1052 for(i=0; i<NCHNAM; ++i) 1053 p->in.name[i] = t->in.name[i]; 1054 } 1055 #else 1056 p->in.name = t->in.name; 1057 #endif 1058 1059 /* init offset */ 1060 p->tn.rval = R2PACK( (b & 0177), o, (b>>7) ); 1061 1062 tfree(f); 1063 return; 1064 } 1065 1066 canaddr( p ) NODE *p; { 1067 register int o = p->in.op; 1068 1069 if( o==NAME || o==REG || o==ICON || o==OREG || (o==UNARY MUL && shumul(p->in.left)) ) return(1); 1070 return(0); 1071 } 1072 1073 #ifndef shltype 1074 shltype( o, p ) register NODE *p; { 1075 return( o== REG || o == NAME || o == ICON || o == OREG || ( o==UNARY MUL && shumul(p->in.left)) ); 1076 } 1077 #endif 1078 1079 flshape( p ) NODE *p; { 1080 register int o = p->in.op; 1081 1082 if( o==NAME || o==REG || o==ICON || o==OREG || (o==UNARY MUL && shumul(p->in.left)) ) return(1); 1083 return(0); 1084 } 1085 1086 /* INTEMP shapes must not contain any temporary registers */ 1087 shtemp( p ) register NODE *p; { 1088 int r; 1089 1090 if( p->in.op == STARG ) p = p->in.left; 1091 1092 switch (p->in.op) { 1093 case REG: 1094 return( !istreg(p->tn.rval) ); 1095 case OREG: 1096 r = p->tn.rval; 1097 if( R2TEST(r) ) { 1098 if( istreg(R2UPK1(r)) ) 1099 return(0); 1100 r = R2UPK2(r); 1101 } 1102 return( !istreg(r) ); 1103 case UNARY MUL: 1104 p = p->in.left; 1105 return( p->in.op != UNARY MUL && shtemp(p) ); 1106 } 1107 1108 if( optype( p->in.op ) != LTYPE ) return(0); 1109 return(1); 1110 } 1111 1112 shumul( p ) register NODE *p; { 1113 register int o; 1114 extern int xdebug; 1115 1116 if (xdebug) { 1117 printf("\nshumul:op=%d,lop=%d,rop=%d", p->in.op, p->in.left->in.op, p->in.right->in.op); 1118 printf(" prname=%s,plty=%d, prlval=%D\n", p->in.right->in.name, p->in.left->in.type, p->in.right->tn.lval); 1119 } 1120 1121 o = p->in.op; 1122 if(( o == NAME || (o == OREG && !R2TEST(p->tn.rval)) || o == ICON ) 1123 && p->in.type != PTR+DOUBLE) 1124 return( STARNM ); 1125 1126 return( 0 ); 1127 } 1128 1129 special( p, shape ) register NODE *p; { 1130 if( shape==SIREG && p->in.op == OREG && R2TEST(p->tn.rval) ) return(1); 1131 else return(0); 1132 } 1133 1134 adrcon( val ) CONSZ val; { 1135 printf(ACONFMT, val); 1136 } 1137 1138 conput( p ) register NODE *p; { 1139 switch( p->in.op ){ 1140 1141 case ICON: 1142 acon( p ); 1143 return; 1144 1145 case REG: 1146 putstr(rname(p->tn.rval)); 1147 return; 1148 1149 default: 1150 cerror( "illegal conput" ); 1151 } 1152 } 1153 1154 /*ARGSUSED*/ 1155 insput( p ) NODE *p; { 1156 cerror( "insput" ); 1157 } 1158 1159 /* 1160 * Output the address of the second item in the 1161 * pair pointed to by p. 1162 */ 1163 upput(p, size) 1164 register NODE *p; 1165 { 1166 CONSZ save; 1167 1168 if (p->in.op == FLD) 1169 p = p->in.left; 1170 switch (p->in.op) { 1171 1172 case NAME: 1173 case OREG: 1174 save = p->tn.lval; 1175 p->tn.lval += size/SZCHAR; 1176 adrput(p); 1177 p->tn.lval = save; 1178 break; 1179 1180 case REG: 1181 if (size == SZLONG) { 1182 putstr(rname(p->tn.rval+1)); 1183 break; 1184 } 1185 /* fall thru... */ 1186 1187 default: 1188 cerror("illegal upper address op %s size %d", 1189 opst[p->tn.op], size); 1190 /*NOTREACHED*/ 1191 } 1192 } 1193 1194 adrput( p ) register NODE *p; { 1195 register int r; 1196 /* output an address, with offsets, from p */ 1197 1198 if( p->in.op == FLD ){ 1199 p = p->in.left; 1200 } 1201 switch( p->in.op ){ 1202 1203 case NAME: 1204 acon( p ); 1205 return; 1206 1207 case ICON: 1208 /* addressable value of the constant */ 1209 putchar('$'); 1210 acon( p ); 1211 return; 1212 1213 case REG: 1214 putstr(rname(p->tn.rval)); 1215 if(p->in.type == DOUBLE) /* for entry mask */ 1216 (void) rname(p->tn.rval+1); 1217 return; 1218 1219 case OREG: 1220 r = p->tn.rval; 1221 if( R2TEST(r) ){ /* double indexing */ 1222 register int flags; 1223 1224 flags = R2UPK3(r); 1225 if( flags & 1 ) putchar('*'); 1226 if( p->tn.lval != 0 || p->in.name[0] != '\0' ) acon(p); 1227 if( R2UPK1(r) != 100) printf( "(%s)", rname(R2UPK1(r)) ); 1228 printf( "[%s]", rname(R2UPK2(r)) ); 1229 return; 1230 } 1231 if( r == FP && p->tn.lval > 0 ){ /* in the argument region */ 1232 if( p->in.name[0] != '\0' ) werror( "bad arg temp" ); 1233 printf( CONFMT, p->tn.lval ); 1234 putstr( "(fp)" ); 1235 return; 1236 } 1237 if( p->tn.lval != 0 || p->in.name[0] != '\0') acon( p ); 1238 printf( "(%s)", rname(p->tn.rval) ); 1239 return; 1240 1241 case UNARY MUL: 1242 /* STARNM or STARREG found */ 1243 if( tshape(p, STARNM) ) { 1244 putchar( '*' ); 1245 adrput( p->in.left); 1246 } 1247 return; 1248 1249 default: 1250 cerror( "illegal address" ); 1251 return; 1252 1253 } 1254 1255 } 1256 1257 acon( p ) register NODE *p; { /* print out a constant */ 1258 1259 if( p->in.name[0] == '\0' ) 1260 printf( CONFMT, p->tn.lval); 1261 else { 1262 #ifndef FLEXNAMES 1263 printf( "%.8s", p->in.name ); 1264 #else 1265 putstr( p->in.name ); 1266 #endif 1267 if( p->tn.lval != 0 ) { 1268 putchar( '+' ); 1269 printf( CONFMT, p->tn.lval ); 1270 } 1271 } 1272 } 1273 1274 genscall( p, cookie ) register NODE *p; { 1275 /* structure valued call */ 1276 return( gencall( p, cookie ) ); 1277 } 1278 1279 genfcall( p, cookie ) register NODE *p; { 1280 register NODE *p1; 1281 register int m; 1282 static char *funcops[6] = { 1283 "sin", "cos", "sqrt", "exp", "log", "atan" 1284 }; 1285 1286 /* generate function opcodes */ 1287 if(p->in.op==UNARY FORTCALL && p->in.type==FLOAT && 1288 (p1 = p->in.left)->in.op==ICON && 1289 p1->tn.lval==0 && p1->in.type==INCREF(FTN|FLOAT)) { 1290 #ifdef FLEXNAMES 1291 p1->in.name++; 1292 #else 1293 strcpy(p1->in.name, p1->in.name[1]); 1294 #endif 1295 for(m=0; m<6; m++) 1296 if(!strcmp(p1->in.name, funcops[m])) 1297 break; 1298 if(m >= 6) 1299 uerror("no opcode for fortarn function %s", p1->in.name); 1300 } else 1301 uerror("illegal type of fortarn function"); 1302 p1 = p->in.right; 1303 p->in.op = FORTCALL; 1304 if(!canaddr(p1)) 1305 order( p1, INAREG|INBREG|SOREG|STARREG|STARNM ); 1306 m = match( p, INTAREG|INTBREG ); 1307 return(m != MDONE); 1308 } 1309 1310 /* tbl */ 1311 int gc_numbytes; 1312 /* tbl */ 1313 1314 /*ARGSUSED*/ 1315 gencall( p, cookie ) register NODE *p; { 1316 /* generate the call given by p */ 1317 register NODE *p1, *ptemp; 1318 register int temp, temp1; 1319 register int m; 1320 1321 if( p->in.right ) temp = argsize( p->in.right ); 1322 else temp = 0; 1323 1324 if( p->in.op == STCALL || p->in.op == UNARY STCALL ){ 1325 /* set aside room for structure return */ 1326 1327 if( p->stn.stsize > temp ) temp1 = p->stn.stsize; 1328 else temp1 = temp; 1329 } 1330 1331 if( temp > maxargs ) maxargs = temp; 1332 SETOFF(temp1,4); 1333 1334 if( p->in.right ){ /* make temp node, put offset in, and generate args */ 1335 ptemp = talloc(); 1336 ptemp->in.op = OREG; 1337 ptemp->tn.lval = -1; 1338 ptemp->tn.rval = SP; 1339 #ifndef FLEXNAMES 1340 ptemp->in.name[0] = '\0'; 1341 #else 1342 ptemp->in.name = ""; 1343 #endif 1344 ptemp->in.rall = NOPREF; 1345 ptemp->in.su = 0; 1346 genargs( p->in.right, ptemp ); 1347 ptemp->in.op = FREE; 1348 } 1349 1350 p1 = p->in.left; 1351 if( p1->in.op != ICON ){ 1352 if( p1->in.op != REG ){ 1353 if( p1->in.op != OREG || R2TEST(p1->tn.rval) ){ 1354 if( p1->in.op != NAME ){ 1355 order( p1, INAREG ); 1356 } 1357 } 1358 } 1359 } 1360 1361 /* tbl 1362 setup gc_numbytes so reference to ZC works */ 1363 1364 gc_numbytes = temp&(0x3ff); 1365 1366 p->in.op = UNARY CALL; 1367 m = match( p, INTAREG|INTBREG ); 1368 1369 return(m != MDONE); 1370 } 1371 1372 /* tbl */ 1373 char * 1374 ccbranches[] = { 1375 "eql", 1376 "neq", 1377 "leq", 1378 "lss", 1379 "geq", 1380 "gtr", 1381 "lequ", 1382 "lssu", 1383 "gequ", 1384 "gtru", 1385 }; 1386 /* tbl */ 1387 1388 /*ARGSUSED*/ 1389 cbgen( o, lab, mode ) { /* printf conditional and unconditional branches */ 1390 1391 if( o != 0 && ( o < EQ || o > UGT ) ) 1392 cerror( "bad conditional branch: %s", opst[o] ); 1393 printf( " j%s L%d\n", o == 0 ? "br" : ccbranches[o-EQ], lab ); 1394 } 1395 1396 nextcook( p, cookie ) NODE *p; { 1397 /* we have failed to match p with cookie; try another */ 1398 if( cookie == FORREW ) return( 0 ); /* hopeless! */ 1399 if( !(cookie&(INTAREG|INTBREG)) ) return( INTAREG|INTBREG ); 1400 if( !(cookie&INTEMP) && asgop(p->in.op) ) return( INTEMP|INAREG|INTAREG|INTBREG|INBREG ); 1401 return( FORREW ); 1402 } 1403 1404 /*ARGSUSED*/ 1405 lastchance( p, cook ) NODE *p; { 1406 /* forget it! */ 1407 return(0); 1408 } 1409 1410 optim2( p ) register NODE *p; { 1411 /* do local tree transformations and optimizations */ 1412 1413 int o; 1414 int i, mask; 1415 register NODE *l, *r; 1416 1417 switch( o = p->in.op ) { 1418 1419 case ASG PLUS: 1420 case ASG MINUS: 1421 case ASG MUL: 1422 case ASG OR: 1423 /* simple ASG OPSIMP -- reduce range of constant rhs */ 1424 l = p->in.left; 1425 r = p->in.right; 1426 if( tlen(l) < SZINT/SZCHAR && 1427 r->in.op==ICON && r->in.name[0]==0 ){ 1428 mask = (1 << tlen(l) * SZCHAR) - 1; 1429 if( r->tn.lval & (mask & ~(mask >> 1)) ) 1430 r->tn.lval |= ~mask; 1431 else 1432 r->tn.lval &= mask; 1433 } 1434 break; 1435 1436 case AND: 1437 case ASG AND: 1438 r = p->in.right; 1439 if( r->in.op==ICON && r->in.name[0]==0 ) { 1440 /* check for degenerate operations */ 1441 l = p->in.left; 1442 mask = (1 << tlen(l) * SZCHAR) - 1; 1443 if( o == ASG AND || ISUNSIGNED(r->in.type) ) { 1444 i = r->tn.lval & mask; 1445 if( i == mask ) { 1446 /* redundant mask */ 1447 r->in.op = FREE; 1448 ncopy(p, l); 1449 l->in.op = FREE; 1450 break; 1451 } 1452 else if( i == 0 ) 1453 /* all bits masked off */ 1454 goto zero; 1455 r->tn.lval = i; 1456 if( tlen(l) < SZINT/SZCHAR ){ 1457 /* sign extend */ 1458 if( r->tn.lval & (mask & ~(mask >> 1)) ) 1459 r->tn.lval |= ~mask; 1460 else 1461 r->tn.lval &= mask; 1462 } 1463 } 1464 else if( r->tn.lval == mask && 1465 tlen(l) < SZINT/SZCHAR ) { 1466 /* use movz instead of and */ 1467 r->in.op = SCONV; 1468 r->in.left = l; 1469 r->in.right = 0; 1470 r->in.type = ENUNSIGN(l->in.type); 1471 r->in.su = l->in.su > 1 ? l->in.su : 1; 1472 ncopy(p, r); 1473 p->in.left = r; 1474 p->in.type = INT; 1475 } 1476 } 1477 break; 1478 1479 case SCONV: 1480 l = p->in.left; 1481 if( p->in.type == FLOAT || p->in.type == DOUBLE || 1482 l->in.type == FLOAT || l->in.type == DOUBLE ) 1483 return; 1484 if( l->in.op == PCONV ) 1485 return; 1486 if( (l->in.op == CALL || l->in.op == UNARY CALL) && 1487 l->in.type != INT && l->in.type != UNSIGNED ) 1488 return; 1489 1490 /* Only trust it to get it right if the size is the same */ 1491 if( tlen(p) != tlen(l) ) 1492 return; 1493 1494 /* clobber conversion */ 1495 if( l->in.op != FLD ) 1496 l->in.type = p->in.type; 1497 ncopy( p, l ); 1498 l->in.op = FREE; 1499 1500 break; 1501 1502 case ASSIGN: 1503 /* 1504 * Conversions are equivalent to assignments; 1505 * when the two operations are combined, 1506 * we can sometimes zap the conversion. 1507 */ 1508 r = p->in.right; 1509 l = p->in.left; 1510 if ( r->in.op == SCONV && 1511 !mixtypes(l, r) && 1512 l->in.op != FLD && 1513 tlen(l) == tlen(r) ) { 1514 p->in.right = r->in.left; 1515 r->in.op = FREE; 1516 } 1517 break; 1518 1519 case ULE: 1520 case ULT: 1521 case UGE: 1522 case UGT: 1523 p->in.op -= (UGE-GE); 1524 if( degenerate(p) ) 1525 break; 1526 p->in.op += (UGE-GE); 1527 break; 1528 1529 case EQ: 1530 case NE: 1531 case LE: 1532 case LT: 1533 case GE: 1534 case GT: 1535 if( p->in.left->in.op == SCONV && 1536 p->in.right->in.op == SCONV ) { 1537 l = p->in.left; 1538 r = p->in.right; 1539 if( l->in.type == DOUBLE && 1540 l->in.left->in.type == FLOAT && 1541 r->in.left->in.type == FLOAT ) { 1542 /* nuke the conversions */ 1543 p->in.left = l->in.left; 1544 p->in.right = r->in.left; 1545 l->in.op = FREE; 1546 r->in.op = FREE; 1547 } 1548 /* more? */ 1549 } 1550 (void) degenerate(p); 1551 break; 1552 1553 case DIV: 1554 if( p->in.right->in.op == ICON && 1555 p->in.right->tn.name[0] == '\0' && 1556 ISUNSIGNED(p->in.right->in.type) && 1557 (unsigned) p->in.right->tn.lval >= 0x80000000 ) { 1558 /* easy to do here, harder to do in zzzcode() */ 1559 p->in.op = UGE; 1560 break; 1561 } 1562 case MOD: 1563 case ASG DIV: 1564 case ASG MOD: 1565 /* 1566 * optimize DIV and MOD 1567 * 1568 * basically we spot UCHAR and USHORT and try to do them 1569 * as signed ints... this may need tuning for the tahoe. 1570 */ 1571 if( degenerate(p) ) 1572 break; 1573 l = p->in.left; 1574 r = p->in.right; 1575 if( !ISUNSIGNED(r->in.type) || 1576 tlen(l) >= SZINT/SZCHAR || 1577 !(tlen(r) < SZINT/SZCHAR || 1578 (r->in.op == ICON && r->tn.name[0] == '\0')) ) 1579 break; 1580 if( r->in.op == ICON ) 1581 r->tn.type = INT; 1582 else { 1583 NODE *t = talloc(); 1584 t->in.left = r; 1585 r = t; 1586 r->in.op = SCONV; 1587 r->in.type = INT; 1588 r->in.right = 0; 1589 p->in.right = r; 1590 } 1591 if( o == DIV || o == MOD ) { 1592 NODE *t = talloc(); 1593 t->in.left = l; 1594 l = t; 1595 l->in.op = SCONV; 1596 l->in.type = INT; 1597 l->in.right = 0; 1598 p->in.left = l; 1599 } 1600 /* handle asgops in table */ 1601 break; 1602 1603 case RS: 1604 case ASG RS: 1605 case LS: 1606 case ASG LS: 1607 /* pick up degenerate shifts */ 1608 l = p->in.left; 1609 r = p->in.right; 1610 if( !(r->in.op == ICON && r->tn.name[0] == '\0') ) 1611 break; 1612 i = r->tn.lval; 1613 if( i < 0 ) 1614 /* front end 'fixes' this? */ 1615 if( o == LS || o == ASG LS ) 1616 o += (RS-LS); 1617 else 1618 o += (LS-RS); 1619 if( (o == RS || o == ASG RS) && 1620 !ISUNSIGNED(l->in.type) ) 1621 /* can't optimize signed right shifts */ 1622 break; 1623 if( o == LS ) { 1624 if( i < SZINT ) 1625 break; 1626 } 1627 else { 1628 if( i < tlen(l) * SZCHAR ) 1629 break; 1630 } 1631 zero: 1632 if( !asgop( o ) ) 1633 if( tshape(l, SAREG|SNAME|SCON|SOREG|STARNM) ) { 1634 /* no side effects */ 1635 tfree(l); 1636 ncopy(p, r); 1637 r->in.op = FREE; 1638 p->tn.lval = 0; 1639 } 1640 else { 1641 p->in.op = COMOP; 1642 r->tn.lval = 0; 1643 } 1644 else { 1645 p->in.op = ASSIGN; 1646 r->tn.lval = 0; 1647 } 1648 break; 1649 } 1650 } 1651 1652 degenerate(p) register NODE *p; { 1653 int o; 1654 int result, i; 1655 int lower, upper; 1656 register NODE *l, *r; 1657 1658 /* 1659 * try to keep degenerate comparisons with constants 1660 * out of the table. 1661 */ 1662 r = p->in.right; 1663 l = p->in.left; 1664 if( r->in.op != ICON || 1665 r->tn.name[0] != '\0' || 1666 tlen(l) >= tlen(r) ) 1667 return (0); 1668 switch( l->in.type ) { 1669 case CHAR: 1670 lower = -(1 << SZCHAR - 1); 1671 upper = (1 << SZCHAR - 1) - 1; 1672 break; 1673 case UCHAR: 1674 lower = 0; 1675 upper = (1 << SZCHAR) - 1; 1676 break; 1677 case SHORT: 1678 lower = -(1 << SZSHORT - 1); 1679 upper = (1 << SZSHORT - 1) - 1; 1680 break; 1681 case USHORT: 1682 lower = 0; 1683 upper = (1 << SZSHORT) - 1; 1684 break; 1685 default: 1686 cerror("unsupported type in degenerate()"); 1687 } 1688 i = r->tn.lval; 1689 switch( o = p->in.op ) { 1690 case DIV: 1691 case ASG DIV: 1692 case MOD: 1693 case ASG MOD: 1694 /* DIV and MOD work like EQ */ 1695 case EQ: 1696 case NE: 1697 if( lower == 0 && (unsigned) i > upper ) 1698 result = o == NE; 1699 else if( i < lower || i > upper ) 1700 result = o == NE; 1701 else 1702 return (0); 1703 break; 1704 case LT: 1705 case GE: 1706 if( lower == 0 && (unsigned) i > upper ) 1707 result = o == LT; 1708 else if( i <= lower ) 1709 result = o != LT; 1710 else if( i > upper ) 1711 result = o == LT; 1712 else 1713 return (0); 1714 break; 1715 case LE: 1716 case GT: 1717 if( lower == 0 && (unsigned) i >= upper ) 1718 result = o == LE; 1719 else if( i < lower ) 1720 result = o != LE; 1721 else if( i >= upper ) 1722 result = o == LE; 1723 else 1724 return (0); 1725 break; 1726 default: 1727 cerror("unknown op in degenerate()"); 1728 } 1729 1730 if( o == MOD || o == ASG MOD ) { 1731 r->in.op = FREE; 1732 ncopy(p, l); 1733 l->in.op = FREE; 1734 } 1735 else if( o != ASG DIV && tshape(l, SAREG|SNAME|SCON|SOREG|STARNM) ) { 1736 /* no side effects */ 1737 tfree(l); 1738 ncopy(p, r); 1739 r->in.op = FREE; 1740 p->tn.lval = result; 1741 } 1742 else { 1743 if( o == ASG DIV ) 1744 p->in.op = ASSIGN; 1745 else { 1746 p->in.op = COMOP; 1747 r->tn.type = INT; 1748 } 1749 r->tn.lval = result; 1750 } 1751 if( logop(o) ) 1752 p->in.type = INT; 1753 1754 return (1); 1755 } 1756 1757 struct functbl { 1758 int fop; 1759 TWORD ftype; 1760 char *func; 1761 } opfunc[] = { 1762 DIV, TANY, "udiv", 1763 MOD, TANY, "urem", 1764 ASG DIV, TANY, "audiv", 1765 ASG MOD, TANY, "aurem", 1766 0, 0, 0 }; 1767 1768 hardops(p) register NODE *p; { 1769 /* change hard to do operators into function calls. */ 1770 register NODE *q; 1771 register struct functbl *f; 1772 register o; 1773 NODE *old,*temp; 1774 1775 o = p->in.op; 1776 if( ! (optype(o)==BITYPE && 1777 (ISUNSIGNED(p->in.left->in.type) || 1778 ISUNSIGNED(p->in.right->in.type))) ) 1779 return; 1780 1781 for( f=opfunc; f->fop; f++ ) { 1782 if( o==f->fop ) goto convert; 1783 } 1784 return; 1785 1786 convert: 1787 if( p->in.right->in.op == ICON && p->in.right->tn.name[0] == '\0' ) 1788 /* 'J' in zzzcode() -- assumes DIV or MOD operations */ 1789 /* save a subroutine call -- use at most 5 instructions */ 1790 return; 1791 if( tlen(p->in.left) < SZINT/SZCHAR && tlen(p->in.right) < SZINT/SZCHAR ) 1792 /* optim2() will modify the op into an ordinary int op */ 1793 return; 1794 if( asgop( o ) ) { 1795 old = NIL; 1796 switch( p->in.left->in.op ){ 1797 case FLD: 1798 q = p->in.left->in.left; 1799 /* 1800 * rewrite (lval.fld /= rval); as 1801 * ((*temp).fld = udiv((*(temp = &lval)).fld,rval)); 1802 * else the compiler will evaluate lval twice. 1803 */ 1804 if( q->in.op == UNARY MUL ){ 1805 /* first allocate a temp storage */ 1806 temp = talloc(); 1807 temp->in.op = OREG; 1808 temp->tn.rval = TMPREG; 1809 temp->tn.lval = BITOOR(freetemp(1)); 1810 temp->in.type = INCREF(p->in.type); 1811 #ifdef FLEXNAMES 1812 temp->in.name = ""; 1813 #else 1814 temp->in.name[0] = '\0'; 1815 #endif 1816 old = q->in.left; 1817 q->in.left = temp; 1818 } 1819 /* fall thru ... */ 1820 1821 case REG: 1822 case NAME: 1823 case OREG: 1824 /* change ASG OP to a simple OP */ 1825 q = talloc(); 1826 q->in.op = NOASG p->in.op; 1827 q->in.rall = NOPREF; 1828 q->in.type = p->in.type; 1829 q->in.left = tcopy(p->in.left); 1830 q->in.right = p->in.right; 1831 p->in.op = ASSIGN; 1832 p->in.right = q; 1833 p = q; 1834 f -= 2; /* Note: this depends on the table order */ 1835 /* on the right side only - replace *temp with 1836 *(temp = &lval), build the assignment node */ 1837 if( old ){ 1838 temp = q->in.left->in.left; /* the "*" node */ 1839 q = talloc(); 1840 q->in.op = ASSIGN; 1841 q->in.left = temp->in.left; 1842 q->in.right = old; 1843 q->in.type = old->in.type; 1844 #ifdef FLEXNAMES 1845 q->in.name = ""; 1846 #else 1847 q->in.name[0] = '\0'; 1848 #endif 1849 temp->in.left = q; 1850 } 1851 break; 1852 1853 case UNARY MUL: 1854 /* avoid doing side effects twice */ 1855 q = p->in.left; 1856 p->in.left = q->in.left; 1857 q->in.op = FREE; 1858 break; 1859 1860 default: 1861 cerror( "hardops: can't compute & LHS" ); 1862 } 1863 } 1864 1865 /* build comma op for args to function */ 1866 q = talloc(); 1867 q->in.op = CM; 1868 q->in.rall = NOPREF; 1869 q->in.type = INT; 1870 q->in.left = p->in.left; 1871 q->in.right = p->in.right; 1872 p->in.op = CALL; 1873 p->in.right = q; 1874 1875 /* put function name in left node of call */ 1876 p->in.left = q = talloc(); 1877 q->in.op = ICON; 1878 q->in.rall = NOPREF; 1879 q->in.type = INCREF( FTN + p->in.type ); 1880 #ifndef FLEXNAMES 1881 strcpy( q->in.name, f->func ); 1882 #else 1883 q->in.name = f->func; 1884 #endif 1885 q->tn.lval = 0; 1886 q->tn.rval = 0; 1887 1888 } 1889 1890 zappost(p) NODE *p; { 1891 /* look for ++ and -- operators and remove them */ 1892 1893 register int o, ty; 1894 register NODE *q; 1895 o = p->in.op; 1896 ty = optype( o ); 1897 1898 switch( o ){ 1899 1900 case INCR: 1901 case DECR: 1902 q = p->in.left; 1903 p->in.right->in.op = FREE; /* zap constant */ 1904 ncopy( p, q ); 1905 q->in.op = FREE; 1906 return; 1907 1908 } 1909 1910 if( ty == BITYPE ) zappost( p->in.right ); 1911 if( ty != LTYPE ) zappost( p->in.left ); 1912 } 1913 1914 fixpre(p) NODE *p; { 1915 1916 register int o, ty; 1917 o = p->in.op; 1918 ty = optype( o ); 1919 1920 switch( o ){ 1921 1922 case ASG PLUS: 1923 p->in.op = PLUS; 1924 break; 1925 case ASG MINUS: 1926 p->in.op = MINUS; 1927 break; 1928 } 1929 1930 if( ty == BITYPE ) fixpre( p->in.right ); 1931 if( ty != LTYPE ) fixpre( p->in.left ); 1932 } 1933 1934 /*ARGSUSED*/ 1935 NODE * addroreg(l) NODE *l; 1936 /* OREG was built in clocal() 1937 * for an auto or formal parameter 1938 * now its address is being taken 1939 * local code must unwind it 1940 * back to PLUS/MINUS REG ICON 1941 * according to local conventions 1942 */ 1943 { 1944 cerror("address of OREG taken"); 1945 /*NOTREACHED*/ 1946 } 1947 1948 # ifndef ONEPASS 1949 main( argc, argv ) char *argv[]; { 1950 return( mainp2( argc, argv ) ); 1951 } 1952 # endif 1953 1954 strip(p) register NODE *p; { 1955 NODE *q; 1956 1957 /* strip nodes off the top when no side effects occur */ 1958 for( ; ; ) { 1959 switch( p->in.op ) { 1960 case SCONV: /* remove lint tidbits */ 1961 q = p->in.left; 1962 ncopy( p, q ); 1963 q->in.op = FREE; 1964 break; 1965 /* could probably add a few more here */ 1966 default: 1967 return; 1968 } 1969 } 1970 } 1971 1972 myreader(p) register NODE *p; { 1973 strip( p ); /* strip off operations with no side effects */ 1974 canon( p ); /* expands r-vals for fields */ 1975 walkf( p, hardops ); /* convert ops to function calls */ 1976 walkf( p, optim2 ); 1977 } 1978