1 #ifndef lint 2 static char sccsid[] = "@(#)local2.c 1.31 (Berkeley) 01/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 /* inverted test */ 850 putstr("\n\tcmpl\t$0,"); 851 adrput(dst); 852 } 853 return; 854 } 855 genconv(ISUNSIGNED(srctype), 856 srclen, dst->in.op == REG ? SZINT/SZCHAR : dstlen, 857 src, dst, forcc); 858 return; 859 } 860 861 if (srclen > dstlen && dst->in.op == REG) { 862 /* if dst is a register, the result must look like an int */ 863 if (src->in.op == REG) { 864 if (ISUNSIGNED(dsttype)) { 865 val = (1 << dstlen * SZCHAR) - 1; 866 if (src->tn.rval == dst->tn.rval) 867 /* conversion in place */ 868 printf("andl2\t$%ld,", val); 869 else { 870 printf("andl3\t$%ld,", val); 871 adrput(src); 872 putchar(','); 873 } 874 adrput(dst); 875 return; 876 } 877 /* 878 * Sign extension in register can also be 879 * accomplished by shifts, but unfortunately 880 * shifts are extremely slow, due to the lack 881 * of a barrel shifter. 882 */ 883 putstr("pushl\t"); 884 adrput(src); 885 putstr("\n\tcvt"); 886 prlen(dstlen); 887 printf("l\t%d(sp),", SZINT/SZCHAR - dstlen); 888 adrput(dst); 889 putstr("\n\tmovab\t4(sp),sp"); 890 if (forcc) { 891 /* inverted test */ 892 putstr("\n\tcmpl\t$0,"); 893 adrput(dst); 894 } 895 return; 896 } 897 tmp = talloc(); 898 if ((src->in.op == NAME) || 899 (src->in.op == UNARY MUL && src->in.left->in.op == ICON) || 900 (src->in.op == OREG && !R2TEST(src->tn.rval))) { 901 /* we can increment src's address & pun it */ 902 *tmp = *src; 903 tmp->tn.lval += srclen - dstlen; 904 } else { 905 /* we must store src's address */ 906 *tmp = *dst; 907 putstr("mova"); 908 prlen(srclen); 909 putchar('\t'); 910 adrput(src); 911 putchar(','); 912 adrput(tmp); 913 putstr("\n\t"); 914 tmp->tn.op = OREG; 915 tmp->tn.lval = srclen - dstlen; 916 } 917 genconv(ISUNSIGNED(dsttype), dstlen, SZINT/SZCHAR, tmp, dst, forcc); 918 tmp->in.op = FREE; 919 return; 920 } 921 922 genconv(neg ? -1 : ISUNSIGNED(dsttype), 923 srclen, dst->in.op == REG ? SZINT/SZCHAR : dstlen, 924 src, dst, forcc); 925 } 926 927 genconv(srcflag, srclen, dstlen, src, dst, forcc) 928 int srcflag; 929 register int srclen, dstlen; 930 NODE *src, *dst; 931 int forcc; 932 { 933 if (srclen != dstlen) { 934 if (srcflag > 0 && srclen < dstlen) 935 putstr("movz"); 936 else 937 putstr("cvt"); 938 prlen(srclen); 939 } else if (srcflag < 0) 940 putstr("mneg"); 941 else 942 putstr("mov"); 943 prlen(dstlen); 944 putchar('\t'); 945 adrput(src); 946 putchar(','); 947 adrput(dst); 948 949 /* 950 * This hack is made necessary by architecture problems 951 * described above 952 */ 953 if (forcc && src->in.op == REG && srclen > dstlen) { 954 putstr("\n\ttst"); 955 prlen(dstlen); 956 putchar('\t'); 957 adrput(dst); 958 } 959 } 960 961 rmove( rt, rs, t ) TWORD t; { 962 printf( " movl %s,%s\n", rname(rs), rname(rt) ); 963 if(t==DOUBLE) 964 printf( " movl %s,%s\n", rname(rs+1), rname(rt+1) ); 965 } 966 967 struct respref 968 respref[] = { 969 INTAREG|INTBREG, INTAREG|INTBREG, 970 INAREG|INBREG, INAREG|INBREG|SOREG|STARREG|STARNM|SNAME|SCON, 971 INTEMP, INTEMP, 972 FORARG, FORARG, 973 INTEMP, INTAREG|INAREG|INTBREG|INBREG|SOREG|STARREG|STARNM, 974 0, 0 }; 975 976 setregs(){ /* set up temporary registers */ 977 fregs = 6; /* tbl- 6 free regs on Tahoe (0-5) */ 978 } 979 980 #ifndef szty 981 szty(t) TWORD t;{ /* size, in registers, needed to hold thing of type t */ 982 return(t==DOUBLE ? 2 : 1 ); 983 } 984 #endif 985 986 /*ARGSUSED*/ 987 rewfld( p ) NODE *p; { 988 return(1); 989 } 990 991 /*ARGSUSED*/ 992 callreg(p) NODE *p; { 993 return( R0 ); 994 } 995 996 base( p ) register NODE *p; { 997 register int o = p->in.op; 998 999 if( o==ICON && p->in.name[0] != '\0' ) return( 100 ); /* ie no base reg */ 1000 if( o==REG ) return( p->tn.rval ); 1001 if( (o==PLUS || o==MINUS) && p->in.left->in.op == REG && p->in.right->in.op==ICON) 1002 return( p->in.left->tn.rval ); 1003 if( o==OREG && !R2TEST(p->tn.rval) && (p->in.type==INT || p->in.type==UNSIGNED || ISPTR(p->in.type)) ) 1004 return( p->tn.rval + 0200*1 ); 1005 if( o==NAME ) return( 100 + 0200*1 ); 1006 return( -1 ); 1007 } 1008 1009 offset( p, tyl ) register NODE *p; int tyl; { 1010 1011 if( tyl==1 && 1012 p->in.op==REG && 1013 (p->in.type==INT || p->in.type==UNSIGNED) ) 1014 return( p->tn.rval ); 1015 if( p->in.op==LS && 1016 p->in.left->in.op==REG && 1017 (p->in.left->in.type==INT || p->in.left->in.type==UNSIGNED) && 1018 p->in.right->in.op==ICON && 1019 p->in.right->in.name[0]=='\0' && 1020 (1<<p->in.right->tn.lval)==tyl) 1021 return( p->in.left->tn.rval ); 1022 if( tyl==2 && 1023 p->in.op==PLUS && 1024 (p->in.left->in.type==INT || p->in.left->in.type==UNSIGNED) && 1025 p->in.left->in.op==REG && 1026 p->in.right->in.op==REG && 1027 p->in.left->tn.rval==p->in.right->tn.rval ) 1028 return( p->in.left->tn.rval ); 1029 return( -1 ); 1030 } 1031 1032 makeor2( p, q, b, o) register NODE *p, *q; register int b, o; { 1033 register NODE *t; 1034 NODE *f; 1035 1036 p->in.op = OREG; 1037 f = p->in.left; /* have to free this subtree later */ 1038 1039 /* init base */ 1040 switch (q->in.op) { 1041 case ICON: 1042 case REG: 1043 case OREG: 1044 case NAME: 1045 t = q; 1046 break; 1047 1048 case MINUS: 1049 q->in.right->tn.lval = -q->in.right->tn.lval; 1050 case PLUS: 1051 t = q->in.right; 1052 break; 1053 1054 case UNARY MUL: 1055 t = q->in.left->in.left; 1056 break; 1057 1058 default: 1059 cerror("illegal makeor2"); 1060 } 1061 1062 p->tn.lval = t->tn.lval; 1063 #ifndef FLEXNAMES 1064 { 1065 register int i; 1066 for(i=0; i<NCHNAM; ++i) 1067 p->in.name[i] = t->in.name[i]; 1068 } 1069 #else 1070 p->in.name = t->in.name; 1071 #endif 1072 1073 /* init offset */ 1074 p->tn.rval = R2PACK( (b & 0177), o, (b>>7) ); 1075 1076 tfree(f); 1077 return; 1078 } 1079 1080 canaddr( p ) NODE *p; { 1081 register int o = p->in.op; 1082 1083 if( o==NAME || o==REG || o==ICON || o==OREG || (o==UNARY MUL && shumul(p->in.left)) ) return(1); 1084 return(0); 1085 } 1086 1087 #ifndef shltype 1088 shltype( o, p ) register NODE *p; { 1089 return( o== REG || o == NAME || o == ICON || o == OREG || ( o==UNARY MUL && shumul(p->in.left)) ); 1090 } 1091 #endif 1092 1093 flshape( p ) NODE *p; { 1094 register int o = p->in.op; 1095 1096 if( o==NAME || o==REG || o==ICON || o==OREG || (o==UNARY MUL && shumul(p->in.left)) ) return(1); 1097 return(0); 1098 } 1099 1100 /* INTEMP shapes must not contain any temporary registers */ 1101 shtemp( p ) register NODE *p; { 1102 int r; 1103 1104 if( p->in.op == STARG ) p = p->in.left; 1105 1106 switch (p->in.op) { 1107 case REG: 1108 return( !istreg(p->tn.rval) ); 1109 case OREG: 1110 r = p->tn.rval; 1111 if( R2TEST(r) ) { 1112 if( istreg(R2UPK1(r)) ) 1113 return(0); 1114 r = R2UPK2(r); 1115 } 1116 return( !istreg(r) ); 1117 case UNARY MUL: 1118 p = p->in.left; 1119 return( p->in.op != UNARY MUL && shtemp(p) ); 1120 } 1121 1122 if( optype( p->in.op ) != LTYPE ) return(0); 1123 return(1); 1124 } 1125 1126 shumul( p ) register NODE *p; { 1127 register int o; 1128 extern int xdebug; 1129 1130 if (xdebug) { 1131 printf("\nshumul:op=%d,lop=%d,rop=%d", p->in.op, p->in.left->in.op, p->in.right->in.op); 1132 printf(" prname=%s,plty=%d, prlval=%D\n", p->in.right->in.name, p->in.left->in.type, p->in.right->tn.lval); 1133 } 1134 1135 o = p->in.op; 1136 if(( o == NAME || (o == OREG && !R2TEST(p->tn.rval)) || o == ICON ) 1137 && p->in.type != PTR+DOUBLE) 1138 return( STARNM ); 1139 1140 return( 0 ); 1141 } 1142 1143 special( p, shape ) register NODE *p; { 1144 if( shape==SIREG && p->in.op == OREG && R2TEST(p->tn.rval) ) return(1); 1145 else return(0); 1146 } 1147 1148 adrcon( val ) CONSZ val; { 1149 printf(ACONFMT, val); 1150 } 1151 1152 conput( p ) register NODE *p; { 1153 switch( p->in.op ){ 1154 1155 case ICON: 1156 acon( p ); 1157 return; 1158 1159 case REG: 1160 putstr(rname(p->tn.rval)); 1161 return; 1162 1163 default: 1164 cerror( "illegal conput" ); 1165 } 1166 } 1167 1168 /*ARGSUSED*/ 1169 insput( p ) NODE *p; { 1170 cerror( "insput" ); 1171 } 1172 1173 /* 1174 * Output the address of the second item in the 1175 * pair pointed to by p. 1176 */ 1177 upput(p, size) 1178 register NODE *p; 1179 { 1180 CONSZ save; 1181 1182 if (p->in.op == FLD) 1183 p = p->in.left; 1184 switch (p->in.op) { 1185 1186 case NAME: 1187 case OREG: 1188 save = p->tn.lval; 1189 p->tn.lval += size/SZCHAR; 1190 adrput(p); 1191 p->tn.lval = save; 1192 break; 1193 1194 case REG: 1195 if (size == SZLONG) { 1196 putstr(rname(p->tn.rval+1)); 1197 break; 1198 } 1199 /* fall thru... */ 1200 1201 default: 1202 cerror("illegal upper address op %s size %d", 1203 opst[p->tn.op], size); 1204 /*NOTREACHED*/ 1205 } 1206 } 1207 1208 adrput( p ) register NODE *p; { 1209 register int r; 1210 /* output an address, with offsets, from p */ 1211 1212 if( p->in.op == FLD ){ 1213 p = p->in.left; 1214 } 1215 switch( p->in.op ){ 1216 1217 case NAME: 1218 acon( p ); 1219 return; 1220 1221 case ICON: 1222 /* addressable value of the constant */ 1223 putchar('$'); 1224 acon( p ); 1225 return; 1226 1227 case REG: 1228 putstr(rname(p->tn.rval)); 1229 if(p->in.type == DOUBLE) /* for entry mask */ 1230 (void) rname(p->tn.rval+1); 1231 return; 1232 1233 case OREG: 1234 r = p->tn.rval; 1235 if( R2TEST(r) ){ /* double indexing */ 1236 register int flags; 1237 1238 flags = R2UPK3(r); 1239 if( flags & 1 ) putchar('*'); 1240 if( p->tn.lval != 0 || p->in.name[0] != '\0' ) acon(p); 1241 if( R2UPK1(r) != 100) printf( "(%s)", rname(R2UPK1(r)) ); 1242 printf( "[%s]", rname(R2UPK2(r)) ); 1243 return; 1244 } 1245 if( r == FP && p->tn.lval > 0 ){ /* in the argument region */ 1246 if( p->in.name[0] != '\0' ) werror( "bad arg temp" ); 1247 printf( CONFMT, p->tn.lval ); 1248 putstr( "(fp)" ); 1249 return; 1250 } 1251 if( p->tn.lval != 0 || p->in.name[0] != '\0') acon( p ); 1252 printf( "(%s)", rname(p->tn.rval) ); 1253 return; 1254 1255 case UNARY MUL: 1256 /* STARNM or STARREG found */ 1257 if( tshape(p, STARNM) ) { 1258 putchar( '*' ); 1259 adrput( p->in.left); 1260 } 1261 return; 1262 1263 default: 1264 cerror( "illegal address" ); 1265 return; 1266 1267 } 1268 1269 } 1270 1271 acon( p ) register NODE *p; { /* print out a constant */ 1272 1273 if( p->in.name[0] == '\0' ) 1274 printf( CONFMT, p->tn.lval); 1275 else { 1276 #ifndef FLEXNAMES 1277 printf( "%.8s", p->in.name ); 1278 #else 1279 putstr( p->in.name ); 1280 #endif 1281 if( p->tn.lval != 0 ) { 1282 putchar( '+' ); 1283 printf( CONFMT, p->tn.lval ); 1284 } 1285 } 1286 } 1287 1288 genscall( p, cookie ) register NODE *p; { 1289 /* structure valued call */ 1290 return( gencall( p, cookie ) ); 1291 } 1292 1293 genfcall( p, cookie ) register NODE *p; { 1294 register NODE *p1; 1295 register int m; 1296 static char *funcops[6] = { 1297 "sin", "cos", "sqrt", "exp", "log", "atan" 1298 }; 1299 1300 /* generate function opcodes */ 1301 if(p->in.op==UNARY FORTCALL && p->in.type==FLOAT && 1302 (p1 = p->in.left)->in.op==ICON && 1303 p1->tn.lval==0 && p1->in.type==INCREF(FTN|FLOAT)) { 1304 #ifdef FLEXNAMES 1305 p1->in.name++; 1306 #else 1307 strcpy(p1->in.name, p1->in.name[1]); 1308 #endif 1309 for(m=0; m<6; m++) 1310 if(!strcmp(p1->in.name, funcops[m])) 1311 break; 1312 if(m >= 6) 1313 uerror("no opcode for fortarn function %s", p1->in.name); 1314 } else 1315 uerror("illegal type of fortarn function"); 1316 p1 = p->in.right; 1317 p->in.op = FORTCALL; 1318 if(!canaddr(p1)) 1319 order( p1, INAREG|INBREG|SOREG|STARREG|STARNM ); 1320 m = match( p, INTAREG|INTBREG ); 1321 return(m != MDONE); 1322 } 1323 1324 /* tbl */ 1325 int gc_numbytes; 1326 /* tbl */ 1327 1328 /*ARGSUSED*/ 1329 gencall( p, cookie ) register NODE *p; { 1330 /* generate the call given by p */ 1331 register NODE *p1, *ptemp; 1332 register int temp, temp1; 1333 register int m; 1334 1335 if( p->in.right ) temp = argsize( p->in.right ); 1336 else temp = 0; 1337 1338 if( p->in.op == STCALL || p->in.op == UNARY STCALL ){ 1339 /* set aside room for structure return */ 1340 1341 if( p->stn.stsize > temp ) temp1 = p->stn.stsize; 1342 else temp1 = temp; 1343 } 1344 1345 if( temp > maxargs ) maxargs = temp; 1346 SETOFF(temp1,4); 1347 1348 if( p->in.right ){ /* make temp node, put offset in, and generate args */ 1349 ptemp = talloc(); 1350 ptemp->in.op = OREG; 1351 ptemp->tn.lval = -1; 1352 ptemp->tn.rval = SP; 1353 #ifndef FLEXNAMES 1354 ptemp->in.name[0] = '\0'; 1355 #else 1356 ptemp->in.name = ""; 1357 #endif 1358 ptemp->in.rall = NOPREF; 1359 ptemp->in.su = 0; 1360 genargs( p->in.right, ptemp ); 1361 ptemp->in.op = FREE; 1362 } 1363 1364 p1 = p->in.left; 1365 if( p1->in.op != ICON ){ 1366 if( p1->in.op != REG ){ 1367 if( p1->in.op != OREG || R2TEST(p1->tn.rval) ){ 1368 if( p1->in.op != NAME ){ 1369 order( p1, INAREG ); 1370 } 1371 } 1372 } 1373 } 1374 1375 /* tbl 1376 setup gc_numbytes so reference to ZC works */ 1377 1378 gc_numbytes = temp&(0x3ff); 1379 1380 p->in.op = UNARY CALL; 1381 m = match( p, INTAREG|INTBREG ); 1382 1383 return(m != MDONE); 1384 } 1385 1386 /* tbl */ 1387 char * 1388 ccbranches[] = { 1389 "eql", 1390 "neq", 1391 "leq", 1392 "lss", 1393 "geq", 1394 "gtr", 1395 "lequ", 1396 "lssu", 1397 "gequ", 1398 "gtru", 1399 }; 1400 /* tbl */ 1401 1402 /*ARGSUSED*/ 1403 cbgen( o, lab, mode ) { /* printf conditional and unconditional branches */ 1404 1405 if( o != 0 && ( o < EQ || o > UGT ) ) 1406 cerror( "bad conditional branch: %s", opst[o] ); 1407 printf( " j%s L%d\n", o == 0 ? "br" : ccbranches[o-EQ], lab ); 1408 } 1409 1410 nextcook( p, cookie ) NODE *p; { 1411 /* we have failed to match p with cookie; try another */ 1412 if( cookie == FORREW ) return( 0 ); /* hopeless! */ 1413 if( !(cookie&(INTAREG|INTBREG)) ) return( INTAREG|INTBREG ); 1414 if( !(cookie&INTEMP) && asgop(p->in.op) ) return( INTEMP|INAREG|INTAREG|INTBREG|INBREG ); 1415 return( FORREW ); 1416 } 1417 1418 /*ARGSUSED*/ 1419 lastchance( p, cook ) NODE *p; { 1420 /* forget it! */ 1421 return(0); 1422 } 1423 1424 optim2( p ) register NODE *p; { 1425 /* do local tree transformations and optimizations */ 1426 1427 int o; 1428 int i, mask; 1429 register NODE *l, *r; 1430 1431 switch( o = p->in.op ) { 1432 1433 case ASG PLUS: 1434 case ASG MINUS: 1435 case ASG MUL: 1436 case ASG OR: 1437 /* simple ASG OPSIMP -- reduce range of constant rhs */ 1438 l = p->in.left; 1439 r = p->in.right; 1440 if( tlen(l) < SZINT/SZCHAR && 1441 r->in.op==ICON && r->in.name[0]==0 ){ 1442 mask = (1 << tlen(l) * SZCHAR) - 1; 1443 if( r->tn.lval & (mask & ~(mask >> 1)) ) 1444 r->tn.lval |= ~mask; 1445 else 1446 r->tn.lval &= mask; 1447 } 1448 break; 1449 1450 case AND: 1451 case ASG AND: 1452 r = p->in.right; 1453 if( r->in.op==ICON && r->in.name[0]==0 ) { 1454 /* check for degenerate operations */ 1455 l = p->in.left; 1456 mask = (1 << tlen(l) * SZCHAR) - 1; 1457 if( o == ASG AND || ISUNSIGNED(r->in.type) ) { 1458 i = r->tn.lval & mask; 1459 if( i == mask ) { 1460 /* redundant mask */ 1461 r->in.op = FREE; 1462 ncopy(p, l); 1463 l->in.op = FREE; 1464 break; 1465 } 1466 else if( i == 0 ) 1467 /* all bits masked off */ 1468 goto zero; 1469 r->tn.lval = i; 1470 if( tlen(l) < SZINT/SZCHAR ){ 1471 /* sign extend */ 1472 if( r->tn.lval & (mask & ~(mask >> 1)) ) 1473 r->tn.lval |= ~mask; 1474 else 1475 r->tn.lval &= mask; 1476 } 1477 } 1478 else if( r->tn.lval == mask && 1479 tlen(l) < SZINT/SZCHAR ) { 1480 /* use movz instead of and */ 1481 r->in.op = SCONV; 1482 r->in.left = l; 1483 r->in.right = 0; 1484 r->in.type = ENUNSIGN(l->in.type); 1485 r->in.su = l->in.su > 1 ? l->in.su : 1; 1486 ncopy(p, r); 1487 p->in.left = r; 1488 p->in.type = INT; 1489 } 1490 } 1491 break; 1492 1493 case SCONV: 1494 l = p->in.left; 1495 if( p->in.type == FLOAT || p->in.type == DOUBLE || 1496 l->in.type == FLOAT || l->in.type == DOUBLE ) 1497 return; 1498 if( l->in.op == PCONV ) 1499 return; 1500 if( (l->in.op == CALL || l->in.op == UNARY CALL) && 1501 l->in.type != INT && l->in.type != UNSIGNED ) 1502 return; 1503 1504 /* Only trust it to get it right if the size is the same */ 1505 if( tlen(p) != tlen(l) ) 1506 return; 1507 1508 /* clobber conversion */ 1509 if( l->in.op != FLD ) 1510 l->in.type = p->in.type; 1511 ncopy( p, l ); 1512 l->in.op = FREE; 1513 1514 break; 1515 1516 case ASSIGN: 1517 /* 1518 * Conversions are equivalent to assignments; 1519 * when the two operations are combined, 1520 * we can sometimes zap the conversion. 1521 */ 1522 r = p->in.right; 1523 l = p->in.left; 1524 if ( r->in.op == SCONV && 1525 !mixtypes(l, r) && 1526 l->in.op != FLD && 1527 tlen(l) == tlen(r) ) { 1528 p->in.right = r->in.left; 1529 r->in.op = FREE; 1530 } 1531 break; 1532 1533 case ULE: 1534 case ULT: 1535 case UGE: 1536 case UGT: 1537 p->in.op -= (UGE-GE); 1538 if( degenerate(p) ) 1539 break; 1540 p->in.op += (UGE-GE); 1541 break; 1542 1543 case EQ: 1544 case NE: 1545 case LE: 1546 case LT: 1547 case GE: 1548 case GT: 1549 if( p->in.left->in.op == SCONV && 1550 p->in.right->in.op == SCONV ) { 1551 l = p->in.left; 1552 r = p->in.right; 1553 if( l->in.type == DOUBLE && 1554 l->in.left->in.type == FLOAT && 1555 r->in.left->in.type == FLOAT ) { 1556 /* nuke the conversions */ 1557 p->in.left = l->in.left; 1558 p->in.right = r->in.left; 1559 l->in.op = FREE; 1560 r->in.op = FREE; 1561 } 1562 /* more? */ 1563 } 1564 (void) degenerate(p); 1565 break; 1566 1567 case DIV: 1568 if( p->in.right->in.op == ICON && 1569 p->in.right->tn.name[0] == '\0' && 1570 ISUNSIGNED(p->in.right->in.type) && 1571 (unsigned) p->in.right->tn.lval >= 0x80000000 ) { 1572 /* easy to do here, harder to do in zzzcode() */ 1573 p->in.op = UGE; 1574 break; 1575 } 1576 case MOD: 1577 case ASG DIV: 1578 case ASG MOD: 1579 /* 1580 * optimize DIV and MOD 1581 * 1582 * basically we spot UCHAR and USHORT and try to do them 1583 * as signed ints... this may need tuning for the tahoe. 1584 */ 1585 if( degenerate(p) ) 1586 break; 1587 l = p->in.left; 1588 r = p->in.right; 1589 if( !ISUNSIGNED(r->in.type) || 1590 tlen(l) >= SZINT/SZCHAR || 1591 !(tlen(r) < SZINT/SZCHAR || 1592 (r->in.op == ICON && r->tn.name[0] == '\0')) ) 1593 break; 1594 if( r->in.op == ICON ) 1595 r->tn.type = INT; 1596 else { 1597 NODE *t = talloc(); 1598 t->in.left = r; 1599 r = t; 1600 r->in.op = SCONV; 1601 r->in.type = INT; 1602 r->in.right = 0; 1603 p->in.right = r; 1604 } 1605 if( o == DIV || o == MOD ) { 1606 NODE *t = talloc(); 1607 t->in.left = l; 1608 l = t; 1609 l->in.op = SCONV; 1610 l->in.type = INT; 1611 l->in.right = 0; 1612 p->in.left = l; 1613 } 1614 /* handle asgops in table */ 1615 break; 1616 1617 case RS: 1618 case ASG RS: 1619 case LS: 1620 case ASG LS: 1621 /* pick up degenerate shifts */ 1622 l = p->in.left; 1623 r = p->in.right; 1624 if( !(r->in.op == ICON && r->tn.name[0] == '\0') ) 1625 break; 1626 i = r->tn.lval; 1627 if( i < 0 ) 1628 /* front end 'fixes' this? */ 1629 if( o == LS || o == ASG LS ) 1630 o += (RS-LS); 1631 else 1632 o += (LS-RS); 1633 if( (o == RS || o == ASG RS) && 1634 !ISUNSIGNED(l->in.type) ) 1635 /* can't optimize signed right shifts */ 1636 break; 1637 if( o == LS ) { 1638 if( i < SZINT ) 1639 break; 1640 } 1641 else { 1642 if( i < tlen(l) * SZCHAR ) 1643 break; 1644 } 1645 zero: 1646 if( !asgop( o ) ) 1647 if( tshape(l, SAREG|SNAME|SCON|SOREG|STARNM) ) { 1648 /* no side effects */ 1649 tfree(l); 1650 ncopy(p, r); 1651 r->in.op = FREE; 1652 p->tn.lval = 0; 1653 } 1654 else { 1655 p->in.op = COMOP; 1656 r->tn.lval = 0; 1657 } 1658 else { 1659 p->in.op = ASSIGN; 1660 r->tn.lval = 0; 1661 } 1662 break; 1663 } 1664 } 1665 1666 degenerate(p) register NODE *p; { 1667 int o; 1668 int result, i; 1669 int lower, upper; 1670 register NODE *l, *r; 1671 1672 /* 1673 * try to keep degenerate comparisons with constants 1674 * out of the table. 1675 */ 1676 r = p->in.right; 1677 l = p->in.left; 1678 if( r->in.op != ICON || 1679 r->tn.name[0] != '\0' || 1680 tlen(l) >= tlen(r) ) 1681 return (0); 1682 switch( l->in.type ) { 1683 case CHAR: 1684 lower = -(1 << SZCHAR - 1); 1685 upper = (1 << SZCHAR - 1) - 1; 1686 break; 1687 case UCHAR: 1688 lower = 0; 1689 upper = (1 << SZCHAR) - 1; 1690 break; 1691 case SHORT: 1692 lower = -(1 << SZSHORT - 1); 1693 upper = (1 << SZSHORT - 1) - 1; 1694 break; 1695 case USHORT: 1696 lower = 0; 1697 upper = (1 << SZSHORT) - 1; 1698 break; 1699 default: 1700 cerror("unsupported type in degenerate()"); 1701 } 1702 i = r->tn.lval; 1703 switch( o = p->in.op ) { 1704 case DIV: 1705 case ASG DIV: 1706 case MOD: 1707 case ASG MOD: 1708 /* DIV and MOD work like EQ */ 1709 case EQ: 1710 case NE: 1711 if( lower == 0 && (unsigned) i > upper ) 1712 result = o == NE; 1713 else if( i < lower || i > upper ) 1714 result = o == NE; 1715 else 1716 return (0); 1717 break; 1718 case LT: 1719 case GE: 1720 if( lower == 0 && (unsigned) i > upper ) 1721 result = o == LT; 1722 else if( i <= lower ) 1723 result = o != LT; 1724 else if( i > upper ) 1725 result = o == LT; 1726 else 1727 return (0); 1728 break; 1729 case LE: 1730 case GT: 1731 if( lower == 0 && (unsigned) i >= upper ) 1732 result = o == LE; 1733 else if( i < lower ) 1734 result = o != LE; 1735 else if( i >= upper ) 1736 result = o == LE; 1737 else 1738 return (0); 1739 break; 1740 default: 1741 cerror("unknown op in degenerate()"); 1742 } 1743 1744 if( o == MOD || o == ASG MOD ) { 1745 r->in.op = FREE; 1746 ncopy(p, l); 1747 l->in.op = FREE; 1748 } 1749 else if( o != ASG DIV && tshape(l, SAREG|SNAME|SCON|SOREG|STARNM) ) { 1750 /* no side effects */ 1751 tfree(l); 1752 ncopy(p, r); 1753 r->in.op = FREE; 1754 p->tn.lval = result; 1755 } 1756 else { 1757 if( o == ASG DIV ) 1758 p->in.op = ASSIGN; 1759 else { 1760 p->in.op = COMOP; 1761 r->tn.type = INT; 1762 } 1763 r->tn.lval = result; 1764 } 1765 if( logop(o) ) 1766 p->in.type = INT; 1767 1768 return (1); 1769 } 1770 1771 struct functbl { 1772 int fop; 1773 TWORD ftype; 1774 char *func; 1775 } opfunc[] = { 1776 DIV, TANY, "udiv", 1777 MOD, TANY, "urem", 1778 ASG DIV, TANY, "audiv", 1779 ASG MOD, TANY, "aurem", 1780 0, 0, 0 }; 1781 1782 hardops(p) register NODE *p; { 1783 /* change hard to do operators into function calls. */ 1784 register NODE *q; 1785 register struct functbl *f; 1786 register o; 1787 NODE *old,*temp; 1788 1789 o = p->in.op; 1790 if( ! (optype(o)==BITYPE && 1791 (ISUNSIGNED(p->in.left->in.type) || 1792 ISUNSIGNED(p->in.right->in.type))) ) 1793 return; 1794 1795 for( f=opfunc; f->fop; f++ ) { 1796 if( o==f->fop ) goto convert; 1797 } 1798 return; 1799 1800 convert: 1801 if( p->in.right->in.op == ICON && p->in.right->tn.name[0] == '\0' ) 1802 /* 'J' in zzzcode() -- assumes DIV or MOD operations */ 1803 /* save a subroutine call -- use at most 5 instructions */ 1804 return; 1805 if( tlen(p->in.left) < SZINT/SZCHAR && tlen(p->in.right) < SZINT/SZCHAR ) 1806 /* optim2() will modify the op into an ordinary int op */ 1807 return; 1808 if( asgop( o ) ) { 1809 old = NIL; 1810 switch( p->in.left->in.op ){ 1811 case FLD: 1812 q = p->in.left->in.left; 1813 /* 1814 * rewrite (lval.fld /= rval); as 1815 * ((*temp).fld = udiv((*(temp = &lval)).fld,rval)); 1816 * else the compiler will evaluate lval twice. 1817 */ 1818 if( q->in.op == UNARY MUL ){ 1819 /* first allocate a temp storage */ 1820 temp = talloc(); 1821 temp->in.op = OREG; 1822 temp->tn.rval = TMPREG; 1823 temp->tn.lval = BITOOR(freetemp(1)); 1824 temp->in.type = INCREF(p->in.type); 1825 #ifdef FLEXNAMES 1826 temp->in.name = ""; 1827 #else 1828 temp->in.name[0] = '\0'; 1829 #endif 1830 old = q->in.left; 1831 q->in.left = temp; 1832 } 1833 /* fall thru ... */ 1834 1835 case REG: 1836 case NAME: 1837 case OREG: 1838 /* change ASG OP to a simple OP */ 1839 q = talloc(); 1840 q->in.op = NOASG p->in.op; 1841 q->in.rall = NOPREF; 1842 q->in.type = p->in.type; 1843 q->in.left = tcopy(p->in.left); 1844 q->in.right = p->in.right; 1845 p->in.op = ASSIGN; 1846 p->in.right = q; 1847 p = q; 1848 f -= 2; /* Note: this depends on the table order */ 1849 /* on the right side only - replace *temp with 1850 *(temp = &lval), build the assignment node */ 1851 if( old ){ 1852 temp = q->in.left->in.left; /* the "*" node */ 1853 q = talloc(); 1854 q->in.op = ASSIGN; 1855 q->in.left = temp->in.left; 1856 q->in.right = old; 1857 q->in.type = old->in.type; 1858 #ifdef FLEXNAMES 1859 q->in.name = ""; 1860 #else 1861 q->in.name[0] = '\0'; 1862 #endif 1863 temp->in.left = q; 1864 } 1865 break; 1866 1867 case UNARY MUL: 1868 /* avoid doing side effects twice */ 1869 q = p->in.left; 1870 p->in.left = q->in.left; 1871 q->in.op = FREE; 1872 break; 1873 1874 default: 1875 cerror( "hardops: can't compute & LHS" ); 1876 } 1877 } 1878 1879 /* build comma op for args to function */ 1880 q = talloc(); 1881 q->in.op = CM; 1882 q->in.rall = NOPREF; 1883 q->in.type = INT; 1884 q->in.left = p->in.left; 1885 q->in.right = p->in.right; 1886 p->in.op = CALL; 1887 p->in.right = q; 1888 1889 /* put function name in left node of call */ 1890 p->in.left = q = talloc(); 1891 q->in.op = ICON; 1892 q->in.rall = NOPREF; 1893 q->in.type = INCREF( FTN + p->in.type ); 1894 #ifndef FLEXNAMES 1895 strcpy( q->in.name, f->func ); 1896 #else 1897 q->in.name = f->func; 1898 #endif 1899 q->tn.lval = 0; 1900 q->tn.rval = 0; 1901 1902 } 1903 1904 zappost(p) NODE *p; { 1905 /* look for ++ and -- operators and remove them */ 1906 1907 register int o, ty; 1908 register NODE *q; 1909 o = p->in.op; 1910 ty = optype( o ); 1911 1912 switch( o ){ 1913 1914 case INCR: 1915 case DECR: 1916 q = p->in.left; 1917 p->in.right->in.op = FREE; /* zap constant */ 1918 ncopy( p, q ); 1919 q->in.op = FREE; 1920 return; 1921 1922 } 1923 1924 if( ty == BITYPE ) zappost( p->in.right ); 1925 if( ty != LTYPE ) zappost( p->in.left ); 1926 } 1927 1928 fixpre(p) NODE *p; { 1929 1930 register int o, ty; 1931 o = p->in.op; 1932 ty = optype( o ); 1933 1934 switch( o ){ 1935 1936 case ASG PLUS: 1937 p->in.op = PLUS; 1938 break; 1939 case ASG MINUS: 1940 p->in.op = MINUS; 1941 break; 1942 } 1943 1944 if( ty == BITYPE ) fixpre( p->in.right ); 1945 if( ty != LTYPE ) fixpre( p->in.left ); 1946 } 1947 1948 /*ARGSUSED*/ 1949 NODE * addroreg(l) NODE *l; 1950 /* OREG was built in clocal() 1951 * for an auto or formal parameter 1952 * now its address is being taken 1953 * local code must unwind it 1954 * back to PLUS/MINUS REG ICON 1955 * according to local conventions 1956 */ 1957 { 1958 cerror("address of OREG taken"); 1959 /*NOTREACHED*/ 1960 } 1961 1962 # ifndef ONEPASS 1963 main( argc, argv ) char *argv[]; { 1964 return( mainp2( argc, argv ) ); 1965 } 1966 # endif 1967 1968 strip(p) register NODE *p; { 1969 NODE *q; 1970 1971 /* strip nodes off the top when no side effects occur */ 1972 for( ; ; ) { 1973 switch( p->in.op ) { 1974 case SCONV: /* remove lint tidbits */ 1975 q = p->in.left; 1976 ncopy( p, q ); 1977 q->in.op = FREE; 1978 break; 1979 /* could probably add a few more here */ 1980 default: 1981 return; 1982 } 1983 } 1984 } 1985 1986 myreader(p) register NODE *p; { 1987 strip( p ); /* strip off operations with no side effects */ 1988 canon( p ); /* expands r-vals for fields */ 1989 walkf( p, hardops ); /* convert ops to function calls */ 1990 walkf( p, optim2 ); 1991 } 1992