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