117742Sralph # ifndef lint 2*32931Sdonn static char *sccsid ="@(#)local2.c 1.25 (Berkeley) 12/11/87"; 317742Sralph # endif 417742Sralph 518556Sralph # include "pass2.h" 69702Slinton # include "ctype.h" 79702Slinton # ifdef FORT 89702Slinton int ftlab1, ftlab2; 99702Slinton # endif 109702Slinton /* a lot of the machine dependent parts of the second pass */ 119702Slinton 1224418Smckusick # define putstr(s) fputs((s), stdout) 1324418Smckusick 149702Slinton # define BITMASK(n) ((1L<<n)-1) 159702Slinton 1632924Sdonn /*ARGSUSED*/ 179702Slinton where(c){ 189702Slinton fprintf( stderr, "%s, line %d: ", filename, lineno ); 199702Slinton } 209702Slinton 219702Slinton lineid( l, fn ) char *fn; { 229702Slinton /* identify line l and file fn */ 239702Slinton printf( "# line %d, file %s\n", l, fn ); 249702Slinton } 259702Slinton 269702Slinton 279702Slinton eobl2(){ 289702Slinton OFFSZ spoff; /* offset from stack pointer */ 299702Slinton #ifdef FORT 309702Slinton spoff = maxoff; 319702Slinton if( spoff >= AUTOINIT ) spoff -= AUTOINIT; 329702Slinton spoff /= SZCHAR; 339702Slinton SETOFF(spoff,4); 349702Slinton #ifndef FLEXNAMES 359702Slinton printf( " .set .F%d,%ld\n", ftnno, spoff ); 369702Slinton #else 379702Slinton /* SHOULD BE L%d ... ftnno but must change pc/f77 */ 389702Slinton printf( " .set LF%d,%ld\n", ftnno, spoff ); 399702Slinton #endif 409702Slinton #else 419702Slinton extern int ftlab1, ftlab2; 429702Slinton 439702Slinton spoff = maxoff; 449702Slinton if( spoff >= AUTOINIT ) spoff -= AUTOINIT; 459702Slinton spoff /= SZCHAR; 469702Slinton SETOFF(spoff,4); 479702Slinton printf( "L%d:\n", ftlab1); 489702Slinton if( spoff!=0 ) 499702Slinton if( spoff < 64 ) 509702Slinton printf( " subl2 $%ld,sp\n", spoff); 519702Slinton else 529702Slinton printf( " movab -%ld(sp),sp\n", spoff); 539702Slinton printf( " jbr L%d\n", ftlab2); 549702Slinton #endif 559702Slinton maxargs = -1; 569702Slinton } 579702Slinton 589702Slinton struct hoptab { int opmask; char * opstring; } ioptab[] = { 599702Slinton 609702Slinton ASG PLUS, "add", 619702Slinton ASG MINUS, "sub", 629702Slinton ASG MUL, "mul", 639702Slinton ASG DIV, "div", 649702Slinton ASG OR, "bis", 659702Slinton ASG ER, "xor", 669702Slinton ASG AND, "bic", 679702Slinton PLUS, "add", 689702Slinton MINUS, "sub", 699702Slinton MUL, "mul", 709702Slinton DIV, "div", 719702Slinton OR, "bis", 729702Slinton ER, "xor", 739702Slinton AND, "bic", 749702Slinton -1, "" }; 759702Slinton 769702Slinton hopcode( f, o ){ 779702Slinton /* output the appropriate string from the above table */ 789702Slinton 799702Slinton register struct hoptab *q; 809702Slinton 819702Slinton for( q = ioptab; q->opmask>=0; ++q ){ 829702Slinton if( q->opmask == o ){ 8324418Smckusick putstr( q->opstring ); 849702Slinton /* tbl 8524418Smckusick if( f == 'F' ) putchar( 'e' ); 8624418Smckusick else if( f == 'D' ) putchar( 'd' ); 879702Slinton tbl */ 889702Slinton /* tbl */ 899702Slinton switch( f ) { 909702Slinton case 'L': 919702Slinton case 'W': 929702Slinton case 'B': 939702Slinton case 'D': 949702Slinton case 'F': 9524418Smckusick putchar(tolower(f)); 969702Slinton break; 979702Slinton 989702Slinton } 999702Slinton /* tbl */ 1009702Slinton return; 1019702Slinton } 1029702Slinton } 1039702Slinton cerror( "no hoptab for %s", opst[o] ); 1049702Slinton } 1059702Slinton 1069702Slinton char * 1079702Slinton rnames[] = { /* keyed to register number tokens */ 1089702Slinton 1099702Slinton "r0", "r1", 1109702Slinton "r2", "r3", "r4", "r5", 1119702Slinton "r6", "r7", "r8", "r9", "r10", "r11", 1129702Slinton "ap", "fp", "sp", "pc", 1139702Slinton 1149702Slinton }; 1159702Slinton 1169702Slinton int rstatus[] = { 1179702Slinton SAREG|STAREG, SAREG|STAREG, 1189702Slinton SAREG|STAREG, SAREG|STAREG, SAREG|STAREG, SAREG|STAREG, 1199702Slinton SAREG, SAREG, SAREG, SAREG, SAREG, SAREG, 1209702Slinton SAREG, SAREG, SAREG, SAREG, 1219702Slinton 1229702Slinton }; 1239702Slinton 1249702Slinton tlen(p) NODE *p; 1259702Slinton { 1269702Slinton switch(p->in.type) { 1279702Slinton case CHAR: 1289702Slinton case UCHAR: 1299702Slinton return(1); 1309702Slinton 1319702Slinton case SHORT: 1329702Slinton case USHORT: 1339702Slinton return(2); 1349702Slinton 1359702Slinton case DOUBLE: 1369702Slinton return(8); 1379702Slinton 1389702Slinton default: 1399702Slinton return(4); 1409702Slinton } 1419702Slinton } 1429702Slinton 1439702Slinton mixtypes(p, q) NODE *p, *q; 1449702Slinton { 14516181Sralph register TWORD tp, tq; 1469702Slinton 1479702Slinton tp = p->in.type; 1489702Slinton tq = q->in.type; 1499702Slinton 1509702Slinton return( (tp==FLOAT || tp==DOUBLE) != 1519702Slinton (tq==FLOAT || tq==DOUBLE) ); 1529702Slinton } 1539702Slinton 1549702Slinton prtype(n) NODE *n; 1559702Slinton { 1569702Slinton switch (n->in.type) 1579702Slinton { 1589702Slinton case DOUBLE: 15924418Smckusick putchar('d'); 1609702Slinton return; 1619702Slinton 1629702Slinton case FLOAT: 16324418Smckusick putchar('f'); 1649702Slinton return; 1659702Slinton 1669702Slinton case LONG: 1679702Slinton case ULONG: 1689702Slinton case INT: 1699702Slinton case UNSIGNED: 17024418Smckusick putchar('l'); 1719702Slinton return; 1729702Slinton 1739702Slinton case SHORT: 1749702Slinton case USHORT: 17524418Smckusick putchar('w'); 1769702Slinton return; 1779702Slinton 1789702Slinton case CHAR: 1799702Slinton case UCHAR: 18024418Smckusick putchar('b'); 1819702Slinton return; 1829702Slinton 1839702Slinton default: 1849702Slinton if ( !ISPTR( n->in.type ) ) cerror("zzzcode- bad type"); 1859702Slinton else { 18624418Smckusick putchar('l'); 1879702Slinton return; 1889702Slinton } 1899702Slinton } 1909702Slinton } 1919702Slinton 1929702Slinton zzzcode( p, c ) register NODE *p; { 1939702Slinton register m; 19432924Sdonn int val; 1959702Slinton switch( c ){ 1969702Slinton 1979702Slinton case 'N': /* logical ops, turned into 0-1 */ 1989702Slinton /* use register given by register 1 */ 1999702Slinton cbgen( 0, m=getlab(), 'I' ); 2009702Slinton deflab( p->bn.label ); 2019702Slinton printf( " clrl %s\n", rnames[getlr( p, '1' )->tn.rval] ); 2029702Slinton deflab( m ); 2039702Slinton return; 2049702Slinton 2059702Slinton case 'I': 2069702Slinton case 'P': 2079702Slinton cbgen( p->in.op, p->bn.label, c ); 2089702Slinton return; 2099702Slinton 2109702Slinton case 'A': 2119702Slinton { 2129702Slinton register NODE *l, *r; 2139702Slinton 2149702Slinton if (xdebug) eprint(p, 0, &val, &val); 2159702Slinton r = getlr(p, 'R'); 21616181Sralph if (p->in.op == ASSIGN) 21716181Sralph l = getlr(p, 'L'); 21817208Sralph else if (p->in.op == SCONV) { 2199702Slinton l = resc; 22017742Sralph #if defined(FORT) || defined(SPRECC) 22116181Sralph l->in.type = r->in.type; 22216181Sralph #else 22316181Sralph l->in.type = r->in.type==FLOAT ? DOUBLE : r->in.type; 22416181Sralph #endif 22516181Sralph r = getlr(p, 'L'); 22616181Sralph } 22717208Sralph else { /* OPLTYPE */ 22816181Sralph l = resc; 22917742Sralph #if defined(FORT) || defined(SPRECC) 23016181Sralph l->in.type = (r->in.type==FLOAT || r->in.type==DOUBLE ? r->in.type : INT); 23116181Sralph #else 2329702Slinton l->in.type = (r->in.type==FLOAT || r->in.type==DOUBLE ? DOUBLE : INT); 23316181Sralph #endif 2349702Slinton } 2359702Slinton if (r->in.op == ICON) 23617208Sralph if (r->in.name[0] == '\0') { 23717208Sralph if (r->tn.lval == 0) { 23824418Smckusick putstr("clr"); 2399702Slinton prtype(l); 24024418Smckusick putchar('\t'); 2419702Slinton adrput(l); 2429702Slinton return; 2439702Slinton } 24417208Sralph if (r->tn.lval < 0 && r->tn.lval >= -63) { 24524418Smckusick putstr("mneg"); 2469702Slinton prtype(l); 2479702Slinton r->tn.lval = -r->tn.lval; 2489702Slinton goto ops; 2499702Slinton } 25017208Sralph if (r->tn.lval < 0) 25117208Sralph r->in.type = r->tn.lval >= -128 ? CHAR 2529702Slinton : (r->tn.lval >= -32768 ? SHORT 25317208Sralph : INT); 25417208Sralph else if (l->in.type == FLOAT || 25517208Sralph l->in.type == DOUBLE) 25617208Sralph r->in.type = r->tn.lval <= 63 ? INT 25717208Sralph : (r->tn.lval <= 127 ? CHAR 25817208Sralph : (r->tn.lval <= 32767 ? SHORT 25917208Sralph : INT)); 26017208Sralph else 26117208Sralph r->in.type = r->tn.lval <= 63 ? INT 26217208Sralph : (r->tn.lval <= 127 ? CHAR 2639702Slinton : (r->tn.lval <= 255 ? UCHAR 2649702Slinton : (r->tn.lval <= 32767 ? SHORT 2659702Slinton : (r->tn.lval <= 65535 ? USHORT 26617208Sralph : INT)))); 2679702Slinton } 26817208Sralph else { 26924418Smckusick putstr("moval"); 27024418Smckusick putchar('\t'); 27116181Sralph acon(r); 27224418Smckusick putchar(','); 27316181Sralph adrput(l); 27416181Sralph return; 27516181Sralph } 2769702Slinton 27723536Sbloom if (p->in.op == SCONV && 27823536Sbloom !(l->in.type == FLOAT || l->in.type == DOUBLE) && 27923536Sbloom !mixtypes(l, r)) { 28023536Sbloom /* 28123536Sbloom * Because registers must always contain objects 28223536Sbloom * of the same width as INTs, we may have to 28323536Sbloom * perform two conversions to get an INT. Can 28423536Sbloom * the conversions be collapsed into one? 28523536Sbloom */ 28623536Sbloom if (m = collapsible(l, r)) 28723536Sbloom r->in.type = m; 28823536Sbloom else { 28923536Sbloom /* 29023536Sbloom * Two steps are required. 29123536Sbloom */ 29223536Sbloom NODE *x = &resc[1]; 29323536Sbloom 29423536Sbloom *x = *l; 29523536Sbloom if (tlen(x) > tlen(r) && ISUNSIGNED(r->in.type)) 29624418Smckusick putstr("movz"); 2979702Slinton else 29824418Smckusick putstr("cvt"); 29923536Sbloom prtype(r); 30023536Sbloom prtype(x); 30124418Smckusick putchar('\t'); 30223536Sbloom adrput(r); 30324418Smckusick putchar(','); 30423536Sbloom adrput(x); 30524418Smckusick putchar('\n'); 30624418Smckusick putchar('\t'); 30723536Sbloom r = x; 3089702Slinton } 30923536Sbloom l->in.type = (ISUNSIGNED(l->in.type) ? UNSIGNED : INT); 3109702Slinton } 31123536Sbloom 31225751Sdonn if ((r->in.type == UNSIGNED || r->in.type == ULONG) && 31325751Sdonn mixtypes(l, r)) { 31425751Sdonn int label1, label2; 31525751Sdonn 31625751Sdonn label1 = getlab(); 31725751Sdonn label2 = getlab(); 31825751Sdonn 31925751Sdonn putstr("movl\t"); 32025751Sdonn adrput(r); 32125751Sdonn putchar(','); 32225751Sdonn adrput(l); 32327269Sdonn putstr("\n\tjbsc\t$31,"); 32425751Sdonn adrput(l); 32525751Sdonn printf(",L%d\n\tcvtl", label1); 32625751Sdonn prtype(l); 32725751Sdonn putchar('\t'); 32825751Sdonn adrput(l); 32925751Sdonn putchar(','); 33025751Sdonn adrput(l); 33125751Sdonn printf("\n\tjbr\tL%d\nL%d:\n\tcvtl", label2, label1); 33225751Sdonn prtype(l); 33325751Sdonn putchar('\t'); 33425751Sdonn adrput(l); 33525751Sdonn putchar(','); 33625751Sdonn adrput(l); 33725751Sdonn putstr("\n\tadd"); 33825751Sdonn prtype(l); 33925751Sdonn putstr("2\t$0"); 34025751Sdonn prtype(l); 34125751Sdonn putstr("2.147483648e9,"); 34225751Sdonn adrput(l); 34325751Sdonn printf("\nL%d:", label2); 34425751Sdonn 34525751Sdonn return; 34625751Sdonn } 34725751Sdonn 34817208Sralph if (!mixtypes(l,r)) { 34917208Sralph if (tlen(l) == tlen(r)) { 35024418Smckusick putstr("mov"); 35117742Sralph #ifdef FORT 35217742Sralph if (Oflag) 35317742Sralph prtype(l); 35417742Sralph else { 35517742Sralph if (l->in.type == DOUBLE) 35624418Smckusick putchar('q'); 35717742Sralph else if(l->in.type == FLOAT) 35824418Smckusick putchar('l'); 35917742Sralph else 36017742Sralph prtype(l); 36117742Sralph } 36217742Sralph #else 3639702Slinton prtype(l); 36417742Sralph #endif FORT 3659702Slinton goto ops; 3669702Slinton } 3679702Slinton else if (tlen(l) > tlen(r) && ISUNSIGNED(r->in.type)) 36824418Smckusick putstr("movz"); 3699702Slinton else 37024418Smckusick putstr("cvt"); 3719702Slinton } 3729702Slinton else 37324418Smckusick putstr("cvt"); 3749702Slinton prtype(r); 3759702Slinton prtype(l); 3769702Slinton ops: 37724418Smckusick putchar('\t'); 3789702Slinton adrput(r); 37924418Smckusick putchar(','); 3809702Slinton adrput(l); 3819702Slinton return; 3829702Slinton } 3839702Slinton 38425751Sdonn case 'G': /* i *= f; asgops with int lhs and float rhs */ 38525751Sdonn { 38625751Sdonn register NODE *l, *r, *s; 38725751Sdonn int rt; 38825751Sdonn 38925751Sdonn l = p->in.left; 39025751Sdonn r = p->in.right; 39125751Sdonn s = talloc(); 39225751Sdonn rt = r->in.type; 39325751Sdonn 39425751Sdonn s->in.op = SCONV; 39525751Sdonn s->in.left = l; 39625751Sdonn s->in.type = rt; 39725751Sdonn zzzcode(s, 'A'); 39825751Sdonn putstr("\n\t"); 39925751Sdonn 40025751Sdonn hopcode(rt == FLOAT ? 'F' : 'D', p->in.op); 40125751Sdonn putstr("2\t"); 40225751Sdonn adrput(r); 40325751Sdonn putchar(','); 40425751Sdonn adrput(resc); 40525751Sdonn putstr("\n\t"); 40625751Sdonn 40725751Sdonn s->in.op = ASSIGN; 40825751Sdonn s->in.left = l; 40925751Sdonn s->in.right = resc; 41025751Sdonn s->in.type = l->in.type; 41125751Sdonn zzzcode(s, 'A'); 41225751Sdonn 41325751Sdonn s->in.op = FREE; 41425751Sdonn return; 41525751Sdonn } 41625751Sdonn 41732928Sdonn case 'J': /* unsigned DIV/MOD with constant divisors */ 41832928Sdonn { 41932928Sdonn register int ck = INAREG; 42032928Sdonn int label1, label2; 42132928Sdonn 42232928Sdonn /* case constant <= 1 is handled by optim() in pass 1 */ 42332928Sdonn /* case constant < 0x80000000 is handled in table */ 42432928Sdonn switch( p->in.op ) { 42532928Sdonn /* case DIV: handled in hardops() */ 42632928Sdonn case MOD: 42732928Sdonn if( p->in.left->in.op == REG && 42832928Sdonn p->in.left->tn.rval == resc->tn.rval ) 42932928Sdonn goto asgmod; 43032928Sdonn label1 = getlab(); 43132928Sdonn expand(p, ck, "movl\tAL,A1\n\tcmpl\tA1,AR\n"); 43232928Sdonn printf("\tjlssu\tL%d\n", label1); 43332928Sdonn expand(p, ck, "\tsubl2\tAR,A1\n"); 43432928Sdonn printf("L%d:", label1); 43532928Sdonn break; 43632928Sdonn case ASG DIV: 43732928Sdonn label1 = getlab(); 43832928Sdonn label2 = getlab(); 43932928Sdonn expand(p, ck, "cmpl\tAL,AR\n"); 44032928Sdonn printf("\tjgequ\tL%d\n", label1); 44132928Sdonn expand(p, ck, "\tmovl\t$1,AL\n"); 44232928Sdonn printf("\tjbr\tL%d\nL%d:\n", label2, label1); 44332928Sdonn expand(p, ck, "\tclrl\tAL\n"); 44432928Sdonn printf("L%d:", label2); 44532928Sdonn break; 44632928Sdonn case ASG MOD: 44732928Sdonn asgmod: 44832928Sdonn label1 = getlab(); 44932928Sdonn expand(p, ck, "cmpl\tAL,AR\n"); 45032928Sdonn printf("\tjlssu\tL%d\n", label1); 45132928Sdonn expand(p, ck, "\tsubl2\tAR,AL\n"); 45232928Sdonn printf("L%d:", label1); 45332928Sdonn break; 45432928Sdonn } 45532928Sdonn return; 45632928Sdonn } 45732928Sdonn 4589702Slinton case 'B': /* get oreg value in temp register for left shift */ 4599702Slinton { 4609702Slinton register NODE *r; 4619702Slinton if (xdebug) eprint(p, 0, &val, &val); 4629702Slinton r = p->in.right; 4639702Slinton if( tlen(r) == sizeof(int) && r->in.type != FLOAT ) 46424418Smckusick putstr("movl"); 4659702Slinton else { 46624418Smckusick putstr("cvt"); 4679702Slinton prtype(r); 46824418Smckusick putchar('l'); 4699702Slinton } 4709702Slinton return; 4719702Slinton } 4729702Slinton 4739702Slinton case 'C': /* num words pushed on arg stack */ 4749702Slinton { 4759702Slinton extern int gc_numbytes; 4769702Slinton extern int xdebug; 4779702Slinton 4789702Slinton if (xdebug) printf("->%d<-",gc_numbytes); 4799702Slinton 4809702Slinton printf("$%d", gc_numbytes/(SZLONG/SZCHAR) ); 4819702Slinton return; 4829702Slinton } 4839702Slinton 4849702Slinton case 'D': /* INCR and DECR */ 4859702Slinton zzzcode(p->in.left, 'A'); 48624418Smckusick putchar('\n'); 48724418Smckusick putchar('\t'); 4889702Slinton 4899702Slinton case 'E': /* INCR and DECR, FOREFF */ 4909702Slinton if (p->in.right->tn.lval == 1) 4919702Slinton { 49224418Smckusick putstr( p->in.op == INCR ? "inc" : "dec" ); 4939702Slinton prtype(p->in.left); 49424418Smckusick putchar('\t'); 4959702Slinton adrput(p->in.left); 4969702Slinton return; 4979702Slinton } 49824418Smckusick putstr( p->in.op == INCR ? "add" : "sub" ); 4999702Slinton prtype(p->in.left); 50024418Smckusick putchar('2'); 50124418Smckusick putchar('\t'); 5029702Slinton adrput(p->in.right); 50324418Smckusick putchar(','); 5049702Slinton adrput(p->in.left); 5059702Slinton return; 5069702Slinton 5079702Slinton case 'F': /* register type of right operand */ 5089702Slinton { 5099702Slinton register NODE *n; 5109702Slinton extern int xdebug; 5119702Slinton register int ty; 5129702Slinton 5139702Slinton n = getlr( p, 'R' ); 5149702Slinton ty = n->in.type; 5159702Slinton 5169702Slinton if (xdebug) printf("->%d<-", ty); 5179702Slinton 51824418Smckusick if ( ty==DOUBLE) putchar('d'); 51924418Smckusick else if ( ty==FLOAT ) putchar('f'); 52024418Smckusick else putchar('l'); 5219702Slinton return; 5229702Slinton } 5239702Slinton 5249702Slinton case 'L': /* type of left operand */ 5259702Slinton case 'R': /* type of right operand */ 5269702Slinton { 5279702Slinton register NODE *n; 5289702Slinton extern int xdebug; 5299702Slinton 53016181Sralph n = getlr( p, c ); 5319702Slinton if (xdebug) printf("->%d<-", n->in.type); 5329702Slinton 5339702Slinton prtype(n); 5349702Slinton return; 5359702Slinton } 5369702Slinton 5379702Slinton case 'Z': /* complement mask for bit instr */ 5389702Slinton printf("$%ld", ~p->in.right->tn.lval); 5399702Slinton return; 5409702Slinton 5419702Slinton case 'U': /* 32 - n, for unsigned right shifts */ 5429702Slinton printf("$%d", 32 - p->in.right->tn.lval ); 5439702Slinton return; 5449702Slinton 5459702Slinton case 'T': /* rounded structure length for arguments */ 5469702Slinton { 5479702Slinton int size; 5489702Slinton 5499702Slinton size = p->stn.stsize; 5509702Slinton SETOFF( size, 4); 5519702Slinton printf("$%d", size); 5529702Slinton return; 5539702Slinton } 5549702Slinton 5559702Slinton case 'S': /* structure assignment */ 5569702Slinton { 5579702Slinton register NODE *l, *r; 5589702Slinton register size; 5599702Slinton 5609702Slinton if( p->in.op == STASG ){ 5619702Slinton l = p->in.left; 5629702Slinton r = p->in.right; 5639702Slinton 5649702Slinton } 5659702Slinton else if( p->in.op == STARG ){ /* store an arg into a temporary */ 5669702Slinton r = p->in.left; 5679702Slinton } 5689702Slinton else cerror( "STASG bad" ); 5699702Slinton 5709702Slinton if( r->in.op == ICON ) r->in.op = NAME; 5719702Slinton else if( r->in.op == REG ) r->in.op = OREG; 5729702Slinton else if( r->in.op != OREG ) cerror( "STASG-r" ); 5739702Slinton 5749702Slinton size = p->stn.stsize; 5759702Slinton 5769702Slinton if( size <= 0 || size > 65535 ) 5779702Slinton cerror("structure size <0=0 or >65535"); 5789702Slinton 5799702Slinton switch(size) { 5809702Slinton case 1: 58124418Smckusick putstr(" movb "); 5829702Slinton break; 5839702Slinton case 2: 58424418Smckusick putstr(" movw "); 5859702Slinton break; 5869702Slinton case 4: 58724418Smckusick putstr(" movl "); 5889702Slinton break; 5899702Slinton case 8: 59024418Smckusick putstr(" movq "); 5919702Slinton break; 5929702Slinton default: 5939702Slinton printf(" movc3 $%d,", size); 5949702Slinton break; 5959702Slinton } 5969702Slinton adrput(r); 59716418Sralph if( p->in.op == STASG ){ 59824418Smckusick putchar(','); 59916418Sralph adrput(l); 60024418Smckusick putchar('\n'); 60116418Sralph } 60216418Sralph else 60324418Smckusick putstr(",(sp)\n"); 6049702Slinton 6059702Slinton if( r->in.op == NAME ) r->in.op = ICON; 6069702Slinton else if( r->in.op == OREG ) r->in.op = REG; 6079702Slinton 6089702Slinton } 6099702Slinton break; 6109702Slinton 6119702Slinton default: 6129702Slinton cerror( "illegal zzzcode" ); 6139702Slinton } 6149702Slinton } 6159702Slinton 61623536Sbloom /* 61723536Sbloom * collapsible(dest, src) -- if a conversion with a register destination 61823536Sbloom * can be accomplished in one instruction, return the type of src 61923536Sbloom * that will do the job correctly; otherwise return 0. Note that 62023536Sbloom * a register must always end up having type INT or UNSIGNED. 62123536Sbloom */ 62223536Sbloom int 62323536Sbloom collapsible(dest, src) 62423536Sbloom NODE *dest, *src; 62523536Sbloom { 62623536Sbloom int st = src->in.type; 62723536Sbloom int dt = dest->in.type; 62823536Sbloom int newt = 0; 62923536Sbloom 63023536Sbloom /* 63123536Sbloom * Are there side effects of evaluating src? 63223536Sbloom * If the derived type will not be the same size as src, 63324418Smckusick * we may have to use two steps. 63423536Sbloom */ 63524418Smckusick if (tlen(src) > tlen(dest)) { 63624418Smckusick if (tshape(src, STARREG)) 63724418Smckusick return (0); 63824418Smckusick if (src->in.op == OREG && R2TEST(src->tn.rval)) 63924418Smckusick return (0); 64024418Smckusick } 64123536Sbloom 64223536Sbloom /* 64323536Sbloom * Can we get an object of dest's type by punning src? 64423536Sbloom * Praises be to great Cthulhu for little-endian machines... 64523536Sbloom */ 64623536Sbloom if (st == CHAR && dt == USHORT) 64723536Sbloom /* 64823536Sbloom * Special case -- we must sign-extend to 16 bits. 64923536Sbloom */ 65023536Sbloom return (0); 65123536Sbloom 65223536Sbloom if (tlen(src) < tlen(dest)) 65323536Sbloom newt = st; 65423536Sbloom else 65523536Sbloom newt = dt; 65623536Sbloom 65723536Sbloom return (newt); 65823536Sbloom } 65923536Sbloom 66017742Sralph rmove( rt, rs, t ) TWORD t; { 6619702Slinton printf( " %s %s,%s\n", 66217742Sralph #ifdef FORT 66317742Sralph !Oflag ? (t==DOUBLE ? "movq" : "movl") : 66417742Sralph #endif 6659702Slinton (t==FLOAT ? "movf" : (t==DOUBLE ? "movd" : "movl")), 6669702Slinton rnames[rs], rnames[rt] ); 6679702Slinton } 6689702Slinton 6699702Slinton struct respref 6709702Slinton respref[] = { 6719702Slinton INTAREG|INTBREG, INTAREG|INTBREG, 6729702Slinton INAREG|INBREG, INAREG|INBREG|SOREG|STARREG|STARNM|SNAME|SCON, 6739702Slinton INTEMP, INTEMP, 6749702Slinton FORARG, FORARG, 6759702Slinton INTEMP, INTAREG|INAREG|INTBREG|INBREG|SOREG|STARREG|STARNM, 6769702Slinton 0, 0 }; 6779702Slinton 6789702Slinton setregs(){ /* set up temporary registers */ 6799702Slinton fregs = 6; /* tbl- 6 free regs on VAX (0-5) */ 6809702Slinton ; 6819702Slinton } 6829702Slinton 68332924Sdonn /*ARGSUSED*/ 6849702Slinton rewfld( p ) NODE *p; { 6859702Slinton return(1); 6869702Slinton } 6879702Slinton 68832924Sdonn /*ARGSUSED*/ 6899702Slinton callreg(p) NODE *p; { 6909702Slinton return( R0 ); 6919702Slinton } 6929702Slinton 6939702Slinton base( p ) register NODE *p; { 6949702Slinton register int o = p->in.op; 6959702Slinton 6969702Slinton if( (o==ICON && p->in.name[0] != '\0')) return( 100 ); /* ie no base reg */ 6979702Slinton if( o==REG ) return( p->tn.rval ); 6989702Slinton if( (o==PLUS || o==MINUS) && p->in.left->in.op == REG && p->in.right->in.op==ICON) 6999702Slinton return( p->in.left->tn.rval ); 7009702Slinton if( o==OREG && !R2TEST(p->tn.rval) && (p->in.type==INT || p->in.type==UNSIGNED || ISPTR(p->in.type)) ) 7019702Slinton return( p->tn.rval + 0200*1 ); 7029702Slinton if( o==INCR && p->in.left->in.op==REG ) return( p->in.left->tn.rval + 0200*2 ); 7039702Slinton if( o==ASG MINUS && p->in.left->in.op==REG) return( p->in.left->tn.rval + 0200*4 ); 7049702Slinton if( o==UNARY MUL && p->in.left->in.op==INCR && p->in.left->in.left->in.op==REG 7059702Slinton && (p->in.type==INT || p->in.type==UNSIGNED || ISPTR(p->in.type)) ) 7069702Slinton return( p->in.left->in.left->tn.rval + 0200*(1+2) ); 7079702Slinton return( -1 ); 7089702Slinton } 7099702Slinton 7109702Slinton offset( p, tyl ) register NODE *p; int tyl; { 7119702Slinton 71224418Smckusick if( tyl==1 && 71324418Smckusick p->in.op==REG && 71424418Smckusick (p->in.type==INT || p->in.type==UNSIGNED) ) 71524418Smckusick return( p->tn.rval ); 71624418Smckusick if( p->in.op==LS && 71724418Smckusick p->in.left->in.op==REG && 71824418Smckusick (p->in.left->in.type==INT || p->in.left->in.type==UNSIGNED) && 71924418Smckusick p->in.right->in.op==ICON && 72024418Smckusick p->in.right->in.name[0]=='\0' && 72124418Smckusick (1<<p->in.right->tn.lval)==tyl) 7229702Slinton return( p->in.left->tn.rval ); 72324418Smckusick if( tyl==2 && 72424418Smckusick p->in.op==PLUS && 72524418Smckusick (p->in.left->in.type==INT || p->in.left->in.type==UNSIGNED) && 72624418Smckusick p->in.left->in.op==REG && 72724418Smckusick p->in.right->in.op==REG && 72824418Smckusick p->in.left->tn.rval==p->in.right->tn.rval ) 72924418Smckusick return( p->in.left->tn.rval ); 7309702Slinton return( -1 ); 7319702Slinton } 7329702Slinton 7339702Slinton makeor2( p, q, b, o) register NODE *p, *q; register int b, o; { 7349702Slinton register NODE *t; 7359702Slinton NODE *f; 7369702Slinton 7379702Slinton p->in.op = OREG; 7389702Slinton f = p->in.left; /* have to free this subtree later */ 7399702Slinton 7409702Slinton /* init base */ 7419702Slinton switch (q->in.op) { 7429702Slinton case ICON: 7439702Slinton case REG: 7449702Slinton case OREG: 7459702Slinton t = q; 7469702Slinton break; 7479702Slinton 7489702Slinton case MINUS: 7499702Slinton q->in.right->tn.lval = -q->in.right->tn.lval; 7509702Slinton case PLUS: 7519702Slinton t = q->in.right; 7529702Slinton break; 7539702Slinton 7549702Slinton case INCR: 7559702Slinton case ASG MINUS: 7569702Slinton t = q->in.left; 7579702Slinton break; 7589702Slinton 7599702Slinton case UNARY MUL: 7609702Slinton t = q->in.left->in.left; 7619702Slinton break; 7629702Slinton 7639702Slinton default: 7649702Slinton cerror("illegal makeor2"); 7659702Slinton } 7669702Slinton 7679702Slinton p->tn.lval = t->tn.lval; 7689702Slinton #ifndef FLEXNAMES 76932924Sdonn { 77032924Sdonn register int i; 77132924Sdonn for(i=0; i<NCHNAM; ++i) 77232924Sdonn p->in.name[i] = t->in.name[i]; 77332924Sdonn } 7749702Slinton #else 7759702Slinton p->in.name = t->in.name; 7769702Slinton #endif 7779702Slinton 7789702Slinton /* init offset */ 7799702Slinton p->tn.rval = R2PACK( (b & 0177), o, (b>>7) ); 7809702Slinton 7819702Slinton tfree(f); 7829702Slinton return; 7839702Slinton } 7849702Slinton 7859702Slinton canaddr( p ) NODE *p; { 7869702Slinton register int o = p->in.op; 7879702Slinton 7889702Slinton if( o==NAME || o==REG || o==ICON || o==OREG || (o==UNARY MUL && shumul(p->in.left)) ) return(1); 7899702Slinton return(0); 7909702Slinton } 7919702Slinton 7929702Slinton flshape( p ) register NODE *p; { 7939702Slinton return( p->in.op == REG || p->in.op == NAME || p->in.op == ICON || 7949702Slinton (p->in.op == OREG && (!R2TEST(p->tn.rval) || tlen(p) == 1)) ); 7959702Slinton } 7969702Slinton 79732926Sdonn /* INTEMP shapes must not contain any temporary registers */ 7989702Slinton shtemp( p ) register NODE *p; { 79932926Sdonn int r; 80032926Sdonn 8019702Slinton if( p->in.op == STARG ) p = p->in.left; 80232926Sdonn 80332926Sdonn switch (p->in.op) { 80432926Sdonn case REG: 80532926Sdonn return( !istreg(p->tn.rval) ); 80632926Sdonn case OREG: 80732926Sdonn r = p->tn.rval; 80832926Sdonn if( R2TEST(r) ) { 80932926Sdonn if( istreg(R2UPK1(r)) ) 81032926Sdonn return(0); 81132926Sdonn r = R2UPK2(r); 81232926Sdonn } 81332926Sdonn return( !istreg(r) ); 81432926Sdonn case UNARY MUL: 81532926Sdonn p = p->in.left; 81632926Sdonn return( p->in.op != UNARY MUL && shtemp(p) ); 81732926Sdonn } 81832926Sdonn 81932926Sdonn if( optype( p->in.op ) != LTYPE ) return(0); 82032926Sdonn return(1); 8219702Slinton } 8229702Slinton 8239702Slinton shumul( p ) register NODE *p; { 8249702Slinton register o; 8259702Slinton extern int xdebug; 8269702Slinton 8279702Slinton if (xdebug) { 8289702Slinton printf("\nshumul:op=%d,lop=%d,rop=%d", p->in.op, p->in.left->in.op, p->in.right->in.op); 8299702Slinton printf(" prname=%s,plty=%d, prlval=%D\n", p->in.right->in.name, p->in.left->in.type, p->in.right->tn.lval); 8309702Slinton } 8319702Slinton 8329702Slinton 8339702Slinton o = p->in.op; 8349702Slinton if( o == NAME || (o == OREG && !R2TEST(p->tn.rval)) || o == ICON ) return( STARNM ); 8359702Slinton 8369702Slinton if( ( o == INCR || o == ASG MINUS ) && 8379702Slinton ( p->in.left->in.op == REG && p->in.right->in.op == ICON ) && 8389702Slinton p->in.right->in.name[0] == '\0' ) 8399702Slinton { 84017659Sralph switch (p->in.type) 8419702Slinton { 8429702Slinton case CHAR|PTR: 8439702Slinton case UCHAR|PTR: 8449702Slinton o = 1; 8459702Slinton break; 8469702Slinton 8479702Slinton case SHORT|PTR: 8489702Slinton case USHORT|PTR: 8499702Slinton o = 2; 8509702Slinton break; 8519702Slinton 8529702Slinton case INT|PTR: 8539702Slinton case UNSIGNED|PTR: 8549702Slinton case LONG|PTR: 8559702Slinton case ULONG|PTR: 8569702Slinton case FLOAT|PTR: 8579702Slinton o = 4; 8589702Slinton break; 8599702Slinton 8609702Slinton case DOUBLE|PTR: 8619702Slinton o = 8; 8629702Slinton break; 8639702Slinton 8649702Slinton default: 86517742Sralph if ( ISPTR(p->in.type) && 86617742Sralph ISPTR(DECREF(p->in.type)) ) { 8679702Slinton o = 4; 8689702Slinton break; 8699702Slinton } 8709702Slinton else return(0); 8719702Slinton } 8729702Slinton return( p->in.right->tn.lval == o ? STARREG : 0); 8739702Slinton } 8749702Slinton 8759702Slinton return( 0 ); 8769702Slinton } 8779702Slinton 8789702Slinton adrcon( val ) CONSZ val; { 87924418Smckusick putchar( '$' ); 8809702Slinton printf( CONFMT, val ); 8819702Slinton } 8829702Slinton 8839702Slinton conput( p ) register NODE *p; { 8849702Slinton switch( p->in.op ){ 8859702Slinton 8869702Slinton case ICON: 8879702Slinton acon( p ); 8889702Slinton return; 8899702Slinton 8909702Slinton case REG: 89124418Smckusick putstr( rnames[p->tn.rval] ); 8929702Slinton return; 8939702Slinton 8949702Slinton default: 8959702Slinton cerror( "illegal conput" ); 8969702Slinton } 8979702Slinton } 8989702Slinton 89932923Sdonn /*ARGSUSED*/ 90032924Sdonn insput( p ) NODE *p; { 9019702Slinton cerror( "insput" ); 9029702Slinton } 9039702Slinton 90432928Sdonn upput( p, size ) NODE *p; int size; { 90532928Sdonn if( size == SZLONG && p->in.op == REG ) { 90632928Sdonn putstr( rnames[p->tn.rval + 1] ); 90732928Sdonn return; 90832928Sdonn } 9099702Slinton cerror( "upput" ); 9109702Slinton } 9119702Slinton 9129702Slinton adrput( p ) register NODE *p; { 9139702Slinton register int r; 9149702Slinton /* output an address, with offsets, from p */ 9159702Slinton 9169702Slinton if( p->in.op == FLD ){ 9179702Slinton p = p->in.left; 9189702Slinton } 9199702Slinton switch( p->in.op ){ 9209702Slinton 9219702Slinton case NAME: 9229702Slinton acon( p ); 9239702Slinton return; 9249702Slinton 9259702Slinton case ICON: 9269702Slinton /* addressable value of the constant */ 92724418Smckusick putchar( '$' ); 9289702Slinton acon( p ); 9299702Slinton return; 9309702Slinton 9319702Slinton case REG: 93224418Smckusick putstr( rnames[p->tn.rval] ); 9339702Slinton return; 9349702Slinton 9359702Slinton case OREG: 9369702Slinton r = p->tn.rval; 9379702Slinton if( R2TEST(r) ){ /* double indexing */ 9389702Slinton register int flags; 9399702Slinton 9409702Slinton flags = R2UPK3(r); 94124418Smckusick if( flags & 1 ) putchar('*'); 94224418Smckusick if( flags & 4 ) putchar('-'); 9439702Slinton if( p->tn.lval != 0 || p->in.name[0] != '\0' ) acon(p); 9449702Slinton if( R2UPK1(r) != 100) printf( "(%s)", rnames[R2UPK1(r)] ); 94524418Smckusick if( flags & 2 ) putchar('+'); 9469702Slinton printf( "[%s]", rnames[R2UPK2(r)] ); 9479702Slinton return; 9489702Slinton } 9499702Slinton if( r == AP ){ /* in the argument region */ 95032925Sdonn if( p->in.name[0] != '\0' ) werror( "bad arg temp" ); 9519702Slinton printf( CONFMT, p->tn.lval ); 95224418Smckusick putstr( "(ap)" ); 9539702Slinton return; 9549702Slinton } 9559702Slinton if( p->tn.lval != 0 || p->in.name[0] != '\0') acon( p ); 9569702Slinton printf( "(%s)", rnames[p->tn.rval] ); 9579702Slinton return; 9589702Slinton 9599702Slinton case UNARY MUL: 9609702Slinton /* STARNM or STARREG found */ 9619702Slinton if( tshape(p, STARNM) ) { 96224418Smckusick putchar( '*' ); 9639702Slinton adrput( p->in.left); 9649702Slinton } 9659702Slinton else { /* STARREG - really auto inc or dec */ 9669702Slinton register NODE *q; 9679702Slinton 9689702Slinton /* tbl 9699702Slinton p = p->in.left; 9709702Slinton p->in.left->in.op = OREG; 9719702Slinton if( p->in.op == INCR ) { 9729702Slinton adrput( p->in.left ); 97324418Smckusick putchar( '+' ); 9749702Slinton } 9759702Slinton else { 97624418Smckusick putchar( '-' ); 9779702Slinton adrput( p->in.left ); 9789702Slinton } 9799702Slinton tbl */ 98017659Sralph q = p->in.left; 98117742Sralph if( q->in.right->tn.lval != tlen(p) ) 98217742Sralph cerror("adrput: bad auto-increment/decrement"); 98317659Sralph printf("%s(%s)%s", (q->in.op==INCR ? "" : "-"), 98417659Sralph rnames[q->in.left->tn.rval], 98517659Sralph (q->in.op==INCR ? "+" : "") ); 9869702Slinton p->in.op = OREG; 98717659Sralph p->tn.rval = q->in.left->tn.rval; 98817659Sralph p->tn.lval = (q->in.op == INCR ? -q->in.right->tn.lval : 0); 9899702Slinton #ifndef FLEXNAMES 9909702Slinton p->in.name[0] = '\0'; 9919702Slinton #else 9929702Slinton p->in.name = ""; 9939702Slinton #endif 9949702Slinton tfree(q); 9959702Slinton } 9969702Slinton return; 9979702Slinton 9989702Slinton default: 9999702Slinton cerror( "illegal address" ); 10009702Slinton return; 10019702Slinton 10029702Slinton } 10039702Slinton 10049702Slinton } 10059702Slinton 10069702Slinton acon( p ) register NODE *p; { /* print out a constant */ 10079702Slinton 10089702Slinton if( p->in.name[0] == '\0' ){ 10099702Slinton printf( CONFMT, p->tn.lval); 10109702Slinton } 10119702Slinton else if( p->tn.lval == 0 ) { 10129702Slinton #ifndef FLEXNAMES 10139702Slinton printf( "%.8s", p->in.name ); 10149702Slinton #else 101524418Smckusick putstr( p->in.name ); 10169702Slinton #endif 10179702Slinton } 10189702Slinton else { 10199702Slinton #ifndef FLEXNAMES 10209702Slinton printf( "%.8s+", p->in.name ); 10219702Slinton #else 10229702Slinton printf( "%s+", p->in.name ); 10239702Slinton #endif 10249702Slinton printf( CONFMT, p->tn.lval ); 10259702Slinton } 10269702Slinton } 10279702Slinton 10289702Slinton /* 10299702Slinton aacon( p ) register NODE *p; { /* print out a constant */ 10309702Slinton /* 10319702Slinton 10329702Slinton if( p->in.name[0] == '\0' ){ 10339702Slinton printf( CONFMT, p->tn.lval); 10349702Slinton return( 0 ); 10359702Slinton } 10369702Slinton else if( p->tn.lval == 0 ) { 10379702Slinton #ifndef FLEXNAMES 10389702Slinton printf( "$%.8s", p->in.name ); 10399702Slinton #else 10409702Slinton printf( "$%s", p->in.name ); 10419702Slinton #endif 10429702Slinton return( 1 ); 10439702Slinton } 10449702Slinton else { 10459702Slinton printf( "$(" ); 10469702Slinton printf( CONFMT, p->tn.lval ); 10479702Slinton printf( "+" ); 10489702Slinton #ifndef FLEXNAMES 10499702Slinton printf( "%.8s)", p->in.name ); 10509702Slinton #else 10519702Slinton printf( "%s)", p->in.name ); 10529702Slinton #endif 10539702Slinton return(1); 10549702Slinton } 10559702Slinton } 10569702Slinton */ 10579702Slinton 10589702Slinton genscall( p, cookie ) register NODE *p; { 10599702Slinton /* structure valued call */ 10609702Slinton return( gencall( p, cookie ) ); 10619702Slinton } 10629702Slinton 10639702Slinton /* tbl */ 10649702Slinton int gc_numbytes; 10659702Slinton /* tbl */ 10669702Slinton 106732924Sdonn /*ARGSUSED*/ 10689702Slinton gencall( p, cookie ) register NODE *p; { 10699702Slinton /* generate the call given by p */ 107016418Sralph register NODE *p1; 10719702Slinton register temp, temp1; 10729702Slinton register m; 10739702Slinton 10749702Slinton if( p->in.right ) temp = argsize( p->in.right ); 10759702Slinton else temp = 0; 10769702Slinton 10779702Slinton if( p->in.op == STCALL || p->in.op == UNARY STCALL ){ 10789702Slinton /* set aside room for structure return */ 10799702Slinton 10809702Slinton if( p->stn.stsize > temp ) temp1 = p->stn.stsize; 10819702Slinton else temp1 = temp; 10829702Slinton } 10839702Slinton 10849702Slinton if( temp > maxargs ) maxargs = temp; 10859702Slinton SETOFF(temp1,4); 10869702Slinton 10879702Slinton if( p->in.right ){ /* make temp node, put offset in, and generate args */ 108816418Sralph genargs( p->in.right ); 10899702Slinton } 10909702Slinton 10919702Slinton p1 = p->in.left; 10929702Slinton if( p1->in.op != ICON ){ 10939702Slinton if( p1->in.op != REG ){ 10949702Slinton if( p1->in.op != OREG || R2TEST(p1->tn.rval) ){ 10959702Slinton if( p1->in.op != NAME ){ 10969702Slinton order( p1, INAREG ); 10979702Slinton } 10989702Slinton } 10999702Slinton } 11009702Slinton } 11019702Slinton 11029702Slinton /* 11039702Slinton if( p1->in.op == REG && p->tn.rval == R5 ){ 11049702Slinton cerror( "call register overwrite" ); 11059702Slinton } 11069702Slinton */ 11079702Slinton /* tbl 11089702Slinton setup gc_numbytes so reference to ZC works */ 11099702Slinton 11109702Slinton gc_numbytes = temp&(0x3ff); 11119702Slinton /* tbl */ 11129702Slinton 11139702Slinton p->in.op = UNARY CALL; 11149702Slinton m = match( p, INTAREG|INTBREG ); 11159702Slinton 11169702Slinton /* compensate for deficiency in 'ret' instruction ... wah,kre */ 11179702Slinton /* (plus in assignment to gc_numbytes above, for neatness only) */ 11189702Slinton if (temp >= 1024) 11199702Slinton printf(" addl2 $%d,sp\n", (temp&(~0x3ff))); 11209702Slinton 11219702Slinton /* tbl 11229702Slinton switch( temp ) { 11239702Slinton case 0: 11249702Slinton break; 11259702Slinton case 2: 11269702Slinton printf( " tst (sp)+\n" ); 11279702Slinton break; 11289702Slinton case 4: 11299702Slinton printf( " cmp (sp)+,(sp)+\n" ); 11309702Slinton break; 11319702Slinton default: 11329702Slinton printf( " add $%d,sp\n", temp); 11339702Slinton } 11349702Slinton tbl */ 11359702Slinton return(m != MDONE); 11369702Slinton } 11379702Slinton 11389702Slinton /* tbl */ 11399702Slinton char * 11409702Slinton ccbranches[] = { 11419702Slinton " jeql L%d\n", 11429702Slinton " jneq L%d\n", 11439702Slinton " jleq L%d\n", 11449702Slinton " jlss L%d\n", 11459702Slinton " jgeq L%d\n", 11469702Slinton " jgtr L%d\n", 11479702Slinton " jlequ L%d\n", 11489702Slinton " jlssu L%d\n", 11499702Slinton " jgequ L%d\n", 11509702Slinton " jgtru L%d\n", 11519702Slinton }; 11529702Slinton /* tbl */ 11539702Slinton 115432924Sdonn /*ARGSUSED*/ 11559702Slinton cbgen( o, lab, mode ) { /* printf conditional and unconditional branches */ 11569702Slinton 11579702Slinton /* tbl */ 11589702Slinton if( o == 0 ) printf( " jbr L%d\n", lab ); 11599702Slinton /* tbl */ 11609702Slinton else { 11619702Slinton if( o > UGT ) cerror( "bad conditional branch: %s", opst[o] ); 11629702Slinton printf( ccbranches[o-EQ], lab ); 11639702Slinton } 11649702Slinton } 11659702Slinton 11669702Slinton nextcook( p, cookie ) NODE *p; { 11679702Slinton /* we have failed to match p with cookie; try another */ 11689702Slinton if( cookie == FORREW ) return( 0 ); /* hopeless! */ 11699702Slinton if( !(cookie&(INTAREG|INTBREG)) ) return( INTAREG|INTBREG ); 11709702Slinton if( !(cookie&INTEMP) && asgop(p->in.op) ) return( INTEMP|INAREG|INTAREG|INTBREG|INBREG ); 11719702Slinton return( FORREW ); 11729702Slinton } 11739702Slinton 117432924Sdonn /*ARGSUSED*/ 11759702Slinton lastchance( p, cook ) NODE *p; { 11769702Slinton /* forget it! */ 11779702Slinton return(0); 11789702Slinton } 11799702Slinton 11809702Slinton optim2( p ) register NODE *p; { 11819702Slinton /* do local tree transformations and optimizations */ 11829702Slinton 118332929Sdonn int o; 1184*32931Sdonn int i; 118516181Sralph register NODE *l, *r; 11869702Slinton 118732929Sdonn switch( o = p->in.op ) { 11889702Slinton 11899702Slinton case AND: 119019933Smckusick /* commute L and R to eliminate complements and constants */ 119116181Sralph if( (l = p->in.left)->in.op == ICON && l->in.name[0] == 0 || 119216181Sralph l->in.op == COMPL ) { 11939702Slinton p->in.left = p->in.right; 119416181Sralph p->in.right = l; 11959702Slinton } 11969702Slinton case ASG AND: 11979702Slinton /* change meaning of AND to ~R&L - bic on pdp11 */ 11989702Slinton r = p->in.right; 1199*32931Sdonn if( r->in.op==ICON && r->in.name[0]==0 ) { 1200*32931Sdonn /* check for degenerate operations */ 1201*32931Sdonn l = p->in.left; 1202*32931Sdonn if( (i = (r->tn.lval & (1 << tlen(l) * SZCHAR) - 1)) == 0 ) 1203*32931Sdonn goto zero; 1204*32931Sdonn else if( i == (1 << tlen(l) * SZCHAR) - 1 ) { 1205*32931Sdonn r->in.op = FREE; 1206*32931Sdonn ncopy(p, l); 1207*32931Sdonn l->in.op = FREE; 1208*32931Sdonn break; 1209*32931Sdonn } 1210*32931Sdonn /* complement constant */ 12119702Slinton r->tn.lval = ~r->tn.lval; 12129702Slinton } 12139702Slinton else if( r->in.op==COMPL ) { /* ~~A => A */ 12149702Slinton r->in.op = FREE; 12159702Slinton p->in.right = r->in.left; 12169702Slinton } 12179702Slinton else { /* insert complement node */ 121816181Sralph p->in.right = l = talloc(); 121916181Sralph l->in.op = COMPL; 122016181Sralph l->in.rall = NOPREF; 122116181Sralph l->in.type = r->in.type; 122216181Sralph l->in.left = r; 122316181Sralph l->in.right = NULL; 12249702Slinton } 12259702Slinton break; 12269702Slinton 122716181Sralph case SCONV: 122819933Smckusick l = p->in.left; 122917742Sralph #if defined(FORT) || defined(SPRECC) 123016573Sralph if( p->in.type == FLOAT || p->in.type == DOUBLE || 123119933Smckusick l->in.type == FLOAT || l->in.type == DOUBLE ) 123219933Smckusick return; 123316573Sralph #else 123419933Smckusick if( mixtypes(p, l) ) return; 123516573Sralph #endif 123632924Sdonn if( l->in.op == PCONV || l->in.op == CALL || l->in.op == UNARY CALL ) 123725751Sdonn return; 123825751Sdonn 123919933Smckusick /* Only trust it to get it right if the size is the same */ 124019933Smckusick if( tlen(p) != tlen(l) ) 124119933Smckusick return; 124216181Sralph 124316181Sralph /* clobber conversion */ 124419933Smckusick if( l->in.op != FLD ) 124516181Sralph l->in.type = p->in.type; 124616181Sralph ncopy( p, l ); 124716181Sralph l->in.op = FREE; 124819933Smckusick 124916181Sralph break; 125016181Sralph 125124418Smckusick case ASSIGN: 125224418Smckusick /* 125324418Smckusick * Conversions are equivalent to assignments; 125424418Smckusick * when the two operations are combined, 125524418Smckusick * we can sometimes zap the conversion. 125624418Smckusick */ 125724418Smckusick r = p->in.right; 125824418Smckusick l = p->in.left; 125924418Smckusick if ( r->in.op == SCONV && 126024418Smckusick !mixtypes(l, r) && 126132922Sdonn l->in.op != FLD && 126224418Smckusick tlen(l) == tlen(r) ) { 126324418Smckusick p->in.right = r->in.left; 126424418Smckusick r->in.op = FREE; 126524418Smckusick } 126624418Smckusick break; 126724418Smckusick 126832929Sdonn case ULE: 126932929Sdonn case ULT: 127032929Sdonn case UGE: 127132929Sdonn case UGT: 1272*32931Sdonn p->in.op -= (UGE-GE); 1273*32931Sdonn if( degenerate(p) ) 1274*32931Sdonn break; 1275*32931Sdonn p->in.op += (UGE-GE); 1276*32931Sdonn break; 1277*32931Sdonn 127832929Sdonn case EQ: 127932929Sdonn case NE: 128032929Sdonn case LE: 128132929Sdonn case LT: 128232929Sdonn case GE: 128332929Sdonn case GT: 1284*32931Sdonn (void) degenerate(p); 1285*32931Sdonn break; 1286*32931Sdonn 1287*32931Sdonn case DIV: 1288*32931Sdonn if( p->in.right->in.op == ICON && 1289*32931Sdonn p->in.right->tn.name[0] == '\0' && 1290*32931Sdonn ISUNSIGNED(p->in.right->in.type) && 1291*32931Sdonn (unsigned) p->in.right->tn.lval >= 0x80000000 ) { 1292*32931Sdonn /* easy to do here, harder to do in zzzcode() */ 1293*32931Sdonn p->in.op = UGE; 129432929Sdonn break; 1295*32931Sdonn } 1296*32931Sdonn case MOD: 1297*32931Sdonn case ASG DIV: 1298*32931Sdonn case ASG MOD: 1299*32931Sdonn /* 1300*32931Sdonn * optimize DIV and MOD 1301*32931Sdonn * 1302*32931Sdonn * basically we spot UCHAR and USHORT and try to do them 1303*32931Sdonn * as signed ints... apparently div+mul+sub is always 1304*32931Sdonn * faster than ediv for finding MOD on the VAX, when 1305*32931Sdonn * full unsigned MOD isn't needed. 1306*32931Sdonn * 1307*32931Sdonn * a curious fact: for MOD, cmp+sub and cmp+sub+cmp+sub 1308*32931Sdonn * are faster for unsigned dividend and a constant divisor 1309*32931Sdonn * in the right range (.5 to 1 of dividend's range for the 1310*32931Sdonn * first, .333+ to .5 for the second). full unsigned is 1311*32931Sdonn * already done cmp+sub in the appropriate case; the 1312*32931Sdonn * other cases are less common and require more ambition. 1313*32931Sdonn */ 1314*32931Sdonn if( degenerate(p) ) 131532929Sdonn break; 1316*32931Sdonn l = p->in.left; 1317*32931Sdonn r = p->in.right; 1318*32931Sdonn if( !ISUNSIGNED(r->in.type) || 1319*32931Sdonn tlen(l) >= SZINT/SZCHAR || 1320*32931Sdonn !(tlen(r) < SZINT/SZCHAR || 1321*32931Sdonn (r->in.op == ICON && r->tn.name[0] == '\0')) ) 132232929Sdonn break; 1323*32931Sdonn if( r->in.op == ICON ) 1324*32931Sdonn r->tn.type = INT; 1325*32931Sdonn else { 1326*32931Sdonn NODE *t = talloc(); 1327*32931Sdonn t->in.left = r; 1328*32931Sdonn r = t; 1329*32931Sdonn r->in.op = SCONV; 1330*32931Sdonn r->in.type = INT; 1331*32931Sdonn r->in.right = 0; 1332*32931Sdonn p->in.right = r; 1333*32931Sdonn } 1334*32931Sdonn if( o == DIV || o == MOD ) { 1335*32931Sdonn NODE *t = talloc(); 1336*32931Sdonn t->in.left = l; 1337*32931Sdonn l = t; 1338*32931Sdonn l->in.op = SCONV; 1339*32931Sdonn l->in.type = INT; 1340*32931Sdonn l->in.right = 0; 1341*32931Sdonn p->in.left = l; 1342*32931Sdonn } 1343*32931Sdonn /* handle asgops in table */ 1344*32931Sdonn break; 1345*32931Sdonn 1346*32931Sdonn case RS: 1347*32931Sdonn case ASG RS: 1348*32931Sdonn case LS: 1349*32931Sdonn case ASG LS: 1350*32931Sdonn /* pick up degenerate shifts */ 1351*32931Sdonn l = p->in.left; 1352*32931Sdonn r = p->in.right; 1353*32931Sdonn if( !(r->in.op == ICON && r->tn.name[0] == '\0') ) 135432929Sdonn break; 135532929Sdonn i = r->tn.lval; 1356*32931Sdonn if( i < 0 ) 1357*32931Sdonn /* front end 'fixes' this? */ 1358*32931Sdonn if( o == LS || o == ASG LS ) 1359*32931Sdonn o += (RS-LS); 1360*32931Sdonn else 1361*32931Sdonn o += (LS-RS); 1362*32931Sdonn if( (o == RS || o == ASG RS) && 1363*32931Sdonn !ISUNSIGNED(l->in.type) ) 1364*32931Sdonn /* can't optimize signed right shifts */ 136532929Sdonn break; 1366*32931Sdonn if( i < tlen(l) * SZCHAR ) 136732929Sdonn break; 1368*32931Sdonn zero: 1369*32931Sdonn if( !asgop( o ) ) 1370*32931Sdonn if( tshape(l, SAREG|SNAME|SCON|SOREG|STARNM) ) { 1371*32931Sdonn /* no side effects */ 1372*32931Sdonn l->in.op = FREE; 1373*32931Sdonn ncopy(p, r); 1374*32931Sdonn r->in.op = FREE; 1375*32931Sdonn p->tn.lval = 0; 1376*32931Sdonn } 1377*32931Sdonn else { 1378*32931Sdonn p->in.op = COMOP; 1379*32931Sdonn r->in.lval = 0; 1380*32931Sdonn } 1381*32931Sdonn else { 1382*32931Sdonn p->in.op = ASSIGN; 1383*32931Sdonn r->tn.lval = 0; 138432929Sdonn } 1385*32931Sdonn break; 1386*32931Sdonn } 1387*32931Sdonn } 1388*32931Sdonn 1389*32931Sdonn degenerate(p) register NODE *p; { 1390*32931Sdonn int o; 1391*32931Sdonn int result, i; 1392*32931Sdonn int lower, upper; 1393*32931Sdonn register NODE *l, *r; 1394*32931Sdonn 1395*32931Sdonn /* 1396*32931Sdonn * try to keep degenerate comparisons with constants 1397*32931Sdonn * out of the table. 1398*32931Sdonn */ 1399*32931Sdonn r = p->in.right; 1400*32931Sdonn l = p->in.left; 1401*32931Sdonn if( r->in.op != ICON || 1402*32931Sdonn r->tn.name[0] != '\0' || 1403*32931Sdonn tlen(l) >= tlen(r) ) 1404*32931Sdonn return (0); 1405*32931Sdonn switch( l->in.type ) { 1406*32931Sdonn case CHAR: 1407*32931Sdonn lower = -(1 << SZCHAR - 1); 1408*32931Sdonn upper = (1 << SZCHAR - 1) - 1; 1409*32931Sdonn break; 1410*32931Sdonn case UCHAR: 1411*32931Sdonn lower = 0; 1412*32931Sdonn upper = (1 << SZCHAR) - 1; 1413*32931Sdonn break; 1414*32931Sdonn case SHORT: 1415*32931Sdonn lower = -(1 << SZSHORT - 1); 1416*32931Sdonn upper = (1 << SZSHORT - 1) - 1; 1417*32931Sdonn break; 1418*32931Sdonn case USHORT: 1419*32931Sdonn lower = 0; 1420*32931Sdonn upper = (1 << SZSHORT) - 1; 1421*32931Sdonn break; 1422*32931Sdonn default: 1423*32931Sdonn cerror("unsupported OPLOG in optim2"); 1424*32931Sdonn } 1425*32931Sdonn i = r->tn.lval; 1426*32931Sdonn switch( o = p->in.op ) { 1427*32931Sdonn case DIV: 1428*32931Sdonn case ASG DIV: 1429*32931Sdonn case MOD: 1430*32931Sdonn case ASG MOD: 1431*32931Sdonn /* DIV and MOD work like EQ */ 1432*32931Sdonn case EQ: 1433*32931Sdonn case NE: 1434*32931Sdonn if( lower == 0 && (unsigned) i > upper ) 1435*32931Sdonn result = o == NE; 1436*32931Sdonn else if( i < lower || i > upper ) 1437*32931Sdonn result = o == NE; 1438*32931Sdonn else 1439*32931Sdonn return (0); 1440*32931Sdonn break; 1441*32931Sdonn case LT: 1442*32931Sdonn case GE: 1443*32931Sdonn if( lower == 0 && (unsigned) i > upper ) 1444*32931Sdonn result = o == LT; 1445*32931Sdonn else if( i <= lower ) 1446*32931Sdonn result = o != LT; 1447*32931Sdonn else if( i > upper ) 1448*32931Sdonn result = o == LT; 1449*32931Sdonn else 1450*32931Sdonn return (0); 1451*32931Sdonn break; 1452*32931Sdonn case LE: 1453*32931Sdonn case GT: 1454*32931Sdonn if( lower == 0 && (unsigned) i >= upper ) 1455*32931Sdonn result = o == LE; 1456*32931Sdonn else if( i < lower ) 1457*32931Sdonn result = o != LE; 1458*32931Sdonn else if( i >= upper ) 1459*32931Sdonn result = o == LE; 1460*32931Sdonn else 1461*32931Sdonn return (0); 1462*32931Sdonn break; 1463*32931Sdonn default: 1464*32931Sdonn cerror("unknown op in degenerate()"); 1465*32931Sdonn } 1466*32931Sdonn 1467*32931Sdonn if( o == MOD || o == ASG MOD ) { 1468*32931Sdonn r->in.op = FREE; 1469*32931Sdonn ncopy(p, l); 1470*32931Sdonn l->in.op = FREE; 1471*32931Sdonn } 1472*32931Sdonn else if( o != ASG DIV && tshape(l, SAREG|SNAME|SCON|SOREG|STARNM) ) { 1473*32931Sdonn /* no side effects */ 1474*32931Sdonn l->in.op = FREE; 1475*32931Sdonn ncopy(p, r); 1476*32931Sdonn r->in.op = FREE; 1477*32931Sdonn p->tn.lval = result; 1478*32931Sdonn } 1479*32931Sdonn else { 1480*32931Sdonn if( o == ASG DIV ) 1481*32931Sdonn p->in.op = ASSIGN; 148232929Sdonn else { 148332929Sdonn p->in.op = COMOP; 148432929Sdonn r->tn.type = INT; 148532929Sdonn } 1486*32931Sdonn r->tn.lval = result; 14879702Slinton } 1488*32931Sdonn if( logop(o) ) 1489*32931Sdonn p->in.type = INT; 1490*32931Sdonn 1491*32931Sdonn return (1); 14929702Slinton } 14939702Slinton 149432924Sdonn /*ARGSUSED*/ 149517742Sralph NODE * addroreg(l) NODE *l; 14969702Slinton /* OREG was built in clocal() 14979702Slinton * for an auto or formal parameter 14989702Slinton * now its address is being taken 14999702Slinton * local code must unwind it 15009702Slinton * back to PLUS/MINUS REG ICON 15019702Slinton * according to local conventions 15029702Slinton */ 15039702Slinton { 15049702Slinton cerror("address of OREG taken"); 150517742Sralph /*NOTREACHED*/ 15069702Slinton } 15079702Slinton 15089702Slinton 15099702Slinton 15109702Slinton # ifndef ONEPASS 15119702Slinton main( argc, argv ) char *argv[]; { 15129702Slinton return( mainp2( argc, argv ) ); 15139702Slinton } 15149702Slinton # endif 15159702Slinton 15169702Slinton 15179702Slinton /* added by jwf */ 15189702Slinton struct functbl { 15199702Slinton int fop; 15209702Slinton TWORD ftype; 15219702Slinton char *func; 15229702Slinton } opfunc[] = { 15239702Slinton DIV, TANY, "udiv", 15249702Slinton MOD, TANY, "urem", 152517715Sralph ASG DIV, TANY, "audiv", 152617715Sralph ASG MOD, TANY, "aurem", 15279702Slinton 0, 0, 0 }; 15289702Slinton 15299702Slinton hardops(p) register NODE *p; { 15309702Slinton /* change hard to do operators into function calls. */ 15319702Slinton register NODE *q; 15329702Slinton register struct functbl *f; 15339702Slinton register o; 153417742Sralph NODE *old,*temp; 15359702Slinton 15369702Slinton o = p->in.op; 153717742Sralph if( ! (optype(o)==BITYPE && 153817742Sralph (ISUNSIGNED(p->in.left->in.type) || 153917742Sralph ISUNSIGNED(p->in.right->in.type))) ) 154017742Sralph return; 15419702Slinton 15429702Slinton for( f=opfunc; f->fop; f++ ) { 15439702Slinton if( o==f->fop ) goto convert; 15449702Slinton } 15459702Slinton return; 15469702Slinton 15479702Slinton convert: 1548*32931Sdonn if( p->in.right->in.op == ICON && p->in.right->tn.name[0] == '\0' ) 154932928Sdonn /* 'J', 'K' in zzzcode() -- assumes DIV or MOD operations */ 155032928Sdonn /* save a subroutine call -- use at most 5 instructions */ 155132928Sdonn return; 1552*32931Sdonn if( tlen(p->in.left) < SZINT/SZCHAR && tlen(p->in.right) < SZINT/SZCHAR ) 1553*32931Sdonn /* optim2() will modify the op into an ordinary int op */ 1554*32931Sdonn return; 15559702Slinton if( asgop( o ) ) { 155617742Sralph old = NIL; 155717715Sralph switch( p->in.left->in.op ){ 155817742Sralph case FLD: 155917742Sralph q = p->in.left->in.left; 156017742Sralph /* 156117742Sralph * rewrite (lval.fld /= rval); as 156217742Sralph * ((*temp).fld = udiv((*(temp = &lval)).fld,rval)); 156317742Sralph * else the compiler will evaluate lval twice. 156417742Sralph */ 156517742Sralph if( q->in.op == UNARY MUL ){ 156617742Sralph /* first allocate a temp storage */ 156717742Sralph temp = talloc(); 156817742Sralph temp->in.op = OREG; 156917742Sralph temp->tn.rval = TMPREG; 157017742Sralph temp->tn.lval = BITOOR(freetemp(1)); 157117742Sralph temp->in.type = INCREF(p->in.type); 157217742Sralph #ifdef FLEXNAMES 157317742Sralph temp->in.name = ""; 157417742Sralph #else 157517742Sralph temp->in.name[0] = '\0'; 157617742Sralph #endif 157717742Sralph old = q->in.left; 157817742Sralph q->in.left = temp; 157917742Sralph } 158017742Sralph /* fall thru ... */ 158117742Sralph 158217715Sralph case REG: 158317715Sralph case NAME: 158417715Sralph case OREG: 158517715Sralph /* change ASG OP to a simple OP */ 158617715Sralph q = talloc(); 158717715Sralph q->in.op = NOASG p->in.op; 158817715Sralph q->in.rall = NOPREF; 158917715Sralph q->in.type = p->in.type; 159017715Sralph q->in.left = tcopy(p->in.left); 159117715Sralph q->in.right = p->in.right; 159217715Sralph p->in.op = ASSIGN; 159317715Sralph p->in.right = q; 159417715Sralph p = q; 159517715Sralph f -= 2; /* Note: this depends on the table order */ 159617742Sralph /* on the right side only - replace *temp with 159717742Sralph *(temp = &lval), build the assignment node */ 159817742Sralph if( old ){ 159917742Sralph temp = q->in.left->in.left; /* the "*" node */ 160017742Sralph q = talloc(); 160117742Sralph q->in.op = ASSIGN; 160217742Sralph q->in.left = temp->in.left; 160317742Sralph q->in.right = old; 160417742Sralph q->in.type = old->in.type; 160517742Sralph #ifdef FLEXNAMES 160617742Sralph q->in.name = ""; 160717742Sralph #else 160817742Sralph q->in.name[0] = '\0'; 160917742Sralph #endif 161017742Sralph temp->in.left = q; 161117742Sralph } 161217715Sralph break; 16139702Slinton 161417715Sralph case UNARY MUL: 161517715Sralph /* avoid doing side effects twice */ 161617715Sralph q = p->in.left; 161717715Sralph p->in.left = q->in.left; 161817715Sralph q->in.op = FREE; 161917715Sralph break; 162017715Sralph 162117715Sralph default: 162217715Sralph cerror( "hardops: can't compute & LHS" ); 162317715Sralph } 162417742Sralph } 162517715Sralph 16269702Slinton /* build comma op for args to function */ 16279702Slinton q = talloc(); 16289702Slinton q->in.op = CM; 16299702Slinton q->in.rall = NOPREF; 16309702Slinton q->in.type = INT; 16319702Slinton q->in.left = p->in.left; 16329702Slinton q->in.right = p->in.right; 16339702Slinton p->in.op = CALL; 16349702Slinton p->in.right = q; 16359702Slinton 16369702Slinton /* put function name in left node of call */ 16379702Slinton p->in.left = q = talloc(); 16389702Slinton q->in.op = ICON; 16399702Slinton q->in.rall = NOPREF; 16409702Slinton q->in.type = INCREF( FTN + p->in.type ); 16419702Slinton #ifndef FLEXNAMES 16429702Slinton strcpy( q->in.name, f->func ); 16439702Slinton #else 16449702Slinton q->in.name = f->func; 16459702Slinton #endif 16469702Slinton q->tn.lval = 0; 16479702Slinton q->tn.rval = 0; 16489702Slinton 16499702Slinton } 16509702Slinton 165117742Sralph zappost(p) NODE *p; { 165217742Sralph /* look for ++ and -- operators and remove them */ 165317742Sralph 165417742Sralph register o, ty; 165517742Sralph register NODE *q; 165617742Sralph o = p->in.op; 165717742Sralph ty = optype( o ); 165817742Sralph 165917742Sralph switch( o ){ 166017742Sralph 166117742Sralph case INCR: 166217742Sralph case DECR: 166317742Sralph q = p->in.left; 166417742Sralph p->in.right->in.op = FREE; /* zap constant */ 166517742Sralph ncopy( p, q ); 166617742Sralph q->in.op = FREE; 166717742Sralph return; 166817742Sralph 166917742Sralph } 167017742Sralph 167117742Sralph if( ty == BITYPE ) zappost( p->in.right ); 167217742Sralph if( ty != LTYPE ) zappost( p->in.left ); 167317742Sralph } 167417742Sralph 167517742Sralph fixpre(p) NODE *p; { 167617742Sralph 167717742Sralph register o, ty; 167817742Sralph o = p->in.op; 167917742Sralph ty = optype( o ); 168017742Sralph 168117742Sralph switch( o ){ 168217742Sralph 168317742Sralph case ASG PLUS: 168417742Sralph p->in.op = PLUS; 168517742Sralph break; 168617742Sralph case ASG MINUS: 168717742Sralph p->in.op = MINUS; 168817742Sralph break; 168917742Sralph } 169017742Sralph 169117742Sralph if( ty == BITYPE ) fixpre( p->in.right ); 169217742Sralph if( ty != LTYPE ) fixpre( p->in.left ); 169317742Sralph } 169417742Sralph 169524418Smckusick strip(p) register NODE *p; { 169624418Smckusick NODE *q; 169724418Smckusick 169824418Smckusick /* strip nodes off the top when no side effects occur */ 169924418Smckusick for( ; ; ) { 170024418Smckusick switch( p->in.op ) { 170124418Smckusick case SCONV: /* remove lint tidbits */ 170224418Smckusick q = p->in.left; 170324418Smckusick ncopy( p, q ); 170424418Smckusick q->in.op = FREE; 170524418Smckusick break; 170624418Smckusick /* could probably add a few more here */ 170724418Smckusick default: 170824418Smckusick return; 170924418Smckusick } 171024418Smckusick } 171124418Smckusick } 171224418Smckusick 17139702Slinton myreader(p) register NODE *p; { 171424418Smckusick strip( p ); /* strip off operations with no side effects */ 171517742Sralph canon( p ); /* expands r-vals for fields */ 17169702Slinton walkf( p, hardops ); /* convert ops to function calls */ 17179702Slinton walkf( p, optim2 ); 17189702Slinton /* jwf toff = 0; /* stack offset swindle */ 17199702Slinton } 1720