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