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