117742Sralph # ifndef lint 2*32932Sdonn static char *sccsid ="@(#)local2.c 1.26 (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*32932Sdonn int i, mask; 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; 119932931Sdonn if( r->in.op==ICON && r->in.name[0]==0 ) { 120032931Sdonn /* check for degenerate operations */ 120132931Sdonn l = p->in.left; 1202*32932Sdonn mask = (1 << tlen(l) * SZCHAR) - 1; 1203*32932Sdonn if( ISUNSIGNED(r->in.type) ) { 1204*32932Sdonn i = (r->tn.lval & mask); 1205*32932Sdonn if( i == mask ) { 1206*32932Sdonn r->in.op = FREE; 1207*32932Sdonn ncopy(p, l); 1208*32932Sdonn l->in.op = FREE; 1209*32932Sdonn break; 1210*32932Sdonn } 1211*32932Sdonn else if( i == 0 ) 1212*32932Sdonn goto zero; 1213*32932Sdonn else 1214*32932Sdonn r->tn.lval = i; 1215*32932Sdonn } 1216*32932Sdonn else if( r->tn.lval == mask && 1217*32932Sdonn tlen(l) < SZINT/SZCHAR ) { 1218*32932Sdonn r->in.op = SCONV; 1219*32932Sdonn r->in.left = l; 1220*32932Sdonn r->in.right = 0; 1221*32932Sdonn r->in.type = ENUNSIGN(l->in.type); 1222*32932Sdonn r->in.su = l->in.su > 1 ? l->in.su : 1; 1223*32932Sdonn ncopy(p, r); 1224*32932Sdonn p->in.left = r; 1225*32932Sdonn p->in.type = INT; 122632931Sdonn break; 122732931Sdonn } 122832931Sdonn /* complement constant */ 12299702Slinton r->tn.lval = ~r->tn.lval; 12309702Slinton } 12319702Slinton else if( r->in.op==COMPL ) { /* ~~A => A */ 12329702Slinton r->in.op = FREE; 12339702Slinton p->in.right = r->in.left; 12349702Slinton } 12359702Slinton else { /* insert complement node */ 123616181Sralph p->in.right = l = talloc(); 123716181Sralph l->in.op = COMPL; 123816181Sralph l->in.rall = NOPREF; 123916181Sralph l->in.type = r->in.type; 124016181Sralph l->in.left = r; 124116181Sralph l->in.right = NULL; 12429702Slinton } 12439702Slinton break; 12449702Slinton 124516181Sralph case SCONV: 124619933Smckusick l = p->in.left; 124717742Sralph #if defined(FORT) || defined(SPRECC) 124816573Sralph if( p->in.type == FLOAT || p->in.type == DOUBLE || 124919933Smckusick l->in.type == FLOAT || l->in.type == DOUBLE ) 125019933Smckusick return; 125116573Sralph #else 125219933Smckusick if( mixtypes(p, l) ) return; 125316573Sralph #endif 125432924Sdonn if( l->in.op == PCONV || l->in.op == CALL || l->in.op == UNARY CALL ) 125525751Sdonn return; 125625751Sdonn 125719933Smckusick /* Only trust it to get it right if the size is the same */ 125819933Smckusick if( tlen(p) != tlen(l) ) 125919933Smckusick return; 126016181Sralph 126116181Sralph /* clobber conversion */ 126219933Smckusick if( l->in.op != FLD ) 126316181Sralph l->in.type = p->in.type; 126416181Sralph ncopy( p, l ); 126516181Sralph l->in.op = FREE; 126619933Smckusick 126716181Sralph break; 126816181Sralph 126924418Smckusick case ASSIGN: 127024418Smckusick /* 127124418Smckusick * Conversions are equivalent to assignments; 127224418Smckusick * when the two operations are combined, 127324418Smckusick * we can sometimes zap the conversion. 127424418Smckusick */ 127524418Smckusick r = p->in.right; 127624418Smckusick l = p->in.left; 127724418Smckusick if ( r->in.op == SCONV && 127824418Smckusick !mixtypes(l, r) && 127932922Sdonn l->in.op != FLD && 128024418Smckusick tlen(l) == tlen(r) ) { 128124418Smckusick p->in.right = r->in.left; 128224418Smckusick r->in.op = FREE; 128324418Smckusick } 128424418Smckusick break; 128524418Smckusick 128632929Sdonn case ULE: 128732929Sdonn case ULT: 128832929Sdonn case UGE: 128932929Sdonn case UGT: 129032931Sdonn p->in.op -= (UGE-GE); 129132931Sdonn if( degenerate(p) ) 129232931Sdonn break; 129332931Sdonn p->in.op += (UGE-GE); 129432931Sdonn break; 129532931Sdonn 129632929Sdonn case EQ: 129732929Sdonn case NE: 129832929Sdonn case LE: 129932929Sdonn case LT: 130032929Sdonn case GE: 130132929Sdonn case GT: 130232931Sdonn (void) degenerate(p); 130332931Sdonn break; 130432931Sdonn 130532931Sdonn case DIV: 130632931Sdonn if( p->in.right->in.op == ICON && 130732931Sdonn p->in.right->tn.name[0] == '\0' && 130832931Sdonn ISUNSIGNED(p->in.right->in.type) && 130932931Sdonn (unsigned) p->in.right->tn.lval >= 0x80000000 ) { 131032931Sdonn /* easy to do here, harder to do in zzzcode() */ 131132931Sdonn p->in.op = UGE; 131232929Sdonn break; 131332931Sdonn } 131432931Sdonn case MOD: 131532931Sdonn case ASG DIV: 131632931Sdonn case ASG MOD: 131732931Sdonn /* 131832931Sdonn * optimize DIV and MOD 131932931Sdonn * 132032931Sdonn * basically we spot UCHAR and USHORT and try to do them 132132931Sdonn * as signed ints... apparently div+mul+sub is always 132232931Sdonn * faster than ediv for finding MOD on the VAX, when 132332931Sdonn * full unsigned MOD isn't needed. 132432931Sdonn * 132532931Sdonn * a curious fact: for MOD, cmp+sub and cmp+sub+cmp+sub 132632931Sdonn * are faster for unsigned dividend and a constant divisor 132732931Sdonn * in the right range (.5 to 1 of dividend's range for the 132832931Sdonn * first, .333+ to .5 for the second). full unsigned is 132932931Sdonn * already done cmp+sub in the appropriate case; the 133032931Sdonn * other cases are less common and require more ambition. 133132931Sdonn */ 133232931Sdonn if( degenerate(p) ) 133332929Sdonn break; 133432931Sdonn l = p->in.left; 133532931Sdonn r = p->in.right; 133632931Sdonn if( !ISUNSIGNED(r->in.type) || 133732931Sdonn tlen(l) >= SZINT/SZCHAR || 133832931Sdonn !(tlen(r) < SZINT/SZCHAR || 133932931Sdonn (r->in.op == ICON && r->tn.name[0] == '\0')) ) 134032929Sdonn break; 134132931Sdonn if( r->in.op == ICON ) 134232931Sdonn r->tn.type = INT; 134332931Sdonn else { 134432931Sdonn NODE *t = talloc(); 134532931Sdonn t->in.left = r; 134632931Sdonn r = t; 134732931Sdonn r->in.op = SCONV; 134832931Sdonn r->in.type = INT; 134932931Sdonn r->in.right = 0; 135032931Sdonn p->in.right = r; 135132931Sdonn } 135232931Sdonn if( o == DIV || o == MOD ) { 135332931Sdonn NODE *t = talloc(); 135432931Sdonn t->in.left = l; 135532931Sdonn l = t; 135632931Sdonn l->in.op = SCONV; 135732931Sdonn l->in.type = INT; 135832931Sdonn l->in.right = 0; 135932931Sdonn p->in.left = l; 136032931Sdonn } 136132931Sdonn /* handle asgops in table */ 136232931Sdonn break; 136332931Sdonn 136432931Sdonn case RS: 136532931Sdonn case ASG RS: 136632931Sdonn case LS: 136732931Sdonn case ASG LS: 136832931Sdonn /* pick up degenerate shifts */ 136932931Sdonn l = p->in.left; 137032931Sdonn r = p->in.right; 137132931Sdonn if( !(r->in.op == ICON && r->tn.name[0] == '\0') ) 137232929Sdonn break; 137332929Sdonn i = r->tn.lval; 137432931Sdonn if( i < 0 ) 137532931Sdonn /* front end 'fixes' this? */ 137632931Sdonn if( o == LS || o == ASG LS ) 137732931Sdonn o += (RS-LS); 137832931Sdonn else 137932931Sdonn o += (LS-RS); 138032931Sdonn if( (o == RS || o == ASG RS) && 138132931Sdonn !ISUNSIGNED(l->in.type) ) 138232931Sdonn /* can't optimize signed right shifts */ 138332929Sdonn break; 138432931Sdonn if( i < tlen(l) * SZCHAR ) 138532929Sdonn break; 138632931Sdonn zero: 138732931Sdonn if( !asgop( o ) ) 138832931Sdonn if( tshape(l, SAREG|SNAME|SCON|SOREG|STARNM) ) { 138932931Sdonn /* no side effects */ 1390*32932Sdonn tfree(l); 139132931Sdonn ncopy(p, r); 139232931Sdonn r->in.op = FREE; 139332931Sdonn p->tn.lval = 0; 139432931Sdonn } 139532931Sdonn else { 139632931Sdonn p->in.op = COMOP; 1397*32932Sdonn r->tn.lval = 0; 139832931Sdonn } 139932931Sdonn else { 140032931Sdonn p->in.op = ASSIGN; 140132931Sdonn r->tn.lval = 0; 140232929Sdonn } 140332931Sdonn break; 140432931Sdonn } 140532931Sdonn } 140632931Sdonn 140732931Sdonn degenerate(p) register NODE *p; { 140832931Sdonn int o; 140932931Sdonn int result, i; 141032931Sdonn int lower, upper; 141132931Sdonn register NODE *l, *r; 141232931Sdonn 141332931Sdonn /* 141432931Sdonn * try to keep degenerate comparisons with constants 141532931Sdonn * out of the table. 141632931Sdonn */ 141732931Sdonn r = p->in.right; 141832931Sdonn l = p->in.left; 141932931Sdonn if( r->in.op != ICON || 142032931Sdonn r->tn.name[0] != '\0' || 142132931Sdonn tlen(l) >= tlen(r) ) 142232931Sdonn return (0); 142332931Sdonn switch( l->in.type ) { 142432931Sdonn case CHAR: 142532931Sdonn lower = -(1 << SZCHAR - 1); 142632931Sdonn upper = (1 << SZCHAR - 1) - 1; 142732931Sdonn break; 142832931Sdonn case UCHAR: 142932931Sdonn lower = 0; 143032931Sdonn upper = (1 << SZCHAR) - 1; 143132931Sdonn break; 143232931Sdonn case SHORT: 143332931Sdonn lower = -(1 << SZSHORT - 1); 143432931Sdonn upper = (1 << SZSHORT - 1) - 1; 143532931Sdonn break; 143632931Sdonn case USHORT: 143732931Sdonn lower = 0; 143832931Sdonn upper = (1 << SZSHORT) - 1; 143932931Sdonn break; 144032931Sdonn default: 1441*32932Sdonn cerror("unsupported type in degenerate()"); 144232931Sdonn } 144332931Sdonn i = r->tn.lval; 144432931Sdonn switch( o = p->in.op ) { 144532931Sdonn case DIV: 144632931Sdonn case ASG DIV: 144732931Sdonn case MOD: 144832931Sdonn case ASG MOD: 144932931Sdonn /* DIV and MOD work like EQ */ 145032931Sdonn case EQ: 145132931Sdonn case NE: 145232931Sdonn if( lower == 0 && (unsigned) i > upper ) 145332931Sdonn result = o == NE; 145432931Sdonn else if( i < lower || i > upper ) 145532931Sdonn result = o == NE; 145632931Sdonn else 145732931Sdonn return (0); 145832931Sdonn break; 145932931Sdonn case LT: 146032931Sdonn case GE: 146132931Sdonn if( lower == 0 && (unsigned) i > upper ) 146232931Sdonn result = o == LT; 146332931Sdonn else if( i <= lower ) 146432931Sdonn result = o != LT; 146532931Sdonn else if( i > upper ) 146632931Sdonn result = o == LT; 146732931Sdonn else 146832931Sdonn return (0); 146932931Sdonn break; 147032931Sdonn case LE: 147132931Sdonn case GT: 147232931Sdonn if( lower == 0 && (unsigned) i >= upper ) 147332931Sdonn result = o == LE; 147432931Sdonn else if( i < lower ) 147532931Sdonn result = o != LE; 147632931Sdonn else if( i >= upper ) 147732931Sdonn result = o == LE; 147832931Sdonn else 147932931Sdonn return (0); 148032931Sdonn break; 148132931Sdonn default: 148232931Sdonn cerror("unknown op in degenerate()"); 148332931Sdonn } 148432931Sdonn 148532931Sdonn if( o == MOD || o == ASG MOD ) { 148632931Sdonn r->in.op = FREE; 148732931Sdonn ncopy(p, l); 148832931Sdonn l->in.op = FREE; 148932931Sdonn } 149032931Sdonn else if( o != ASG DIV && tshape(l, SAREG|SNAME|SCON|SOREG|STARNM) ) { 149132931Sdonn /* no side effects */ 1492*32932Sdonn tfree(l); 149332931Sdonn ncopy(p, r); 149432931Sdonn r->in.op = FREE; 149532931Sdonn p->tn.lval = result; 149632931Sdonn } 149732931Sdonn else { 149832931Sdonn if( o == ASG DIV ) 149932931Sdonn p->in.op = ASSIGN; 150032929Sdonn else { 150132929Sdonn p->in.op = COMOP; 150232929Sdonn r->tn.type = INT; 150332929Sdonn } 150432931Sdonn r->tn.lval = result; 15059702Slinton } 150632931Sdonn if( logop(o) ) 150732931Sdonn p->in.type = INT; 150832931Sdonn 150932931Sdonn return (1); 15109702Slinton } 15119702Slinton 151232924Sdonn /*ARGSUSED*/ 151317742Sralph NODE * addroreg(l) NODE *l; 15149702Slinton /* OREG was built in clocal() 15159702Slinton * for an auto or formal parameter 15169702Slinton * now its address is being taken 15179702Slinton * local code must unwind it 15189702Slinton * back to PLUS/MINUS REG ICON 15199702Slinton * according to local conventions 15209702Slinton */ 15219702Slinton { 15229702Slinton cerror("address of OREG taken"); 152317742Sralph /*NOTREACHED*/ 15249702Slinton } 15259702Slinton 15269702Slinton 15279702Slinton 15289702Slinton # ifndef ONEPASS 15299702Slinton main( argc, argv ) char *argv[]; { 15309702Slinton return( mainp2( argc, argv ) ); 15319702Slinton } 15329702Slinton # endif 15339702Slinton 15349702Slinton 15359702Slinton /* added by jwf */ 15369702Slinton struct functbl { 15379702Slinton int fop; 15389702Slinton TWORD ftype; 15399702Slinton char *func; 15409702Slinton } opfunc[] = { 15419702Slinton DIV, TANY, "udiv", 15429702Slinton MOD, TANY, "urem", 154317715Sralph ASG DIV, TANY, "audiv", 154417715Sralph ASG MOD, TANY, "aurem", 15459702Slinton 0, 0, 0 }; 15469702Slinton 15479702Slinton hardops(p) register NODE *p; { 15489702Slinton /* change hard to do operators into function calls. */ 15499702Slinton register NODE *q; 15509702Slinton register struct functbl *f; 15519702Slinton register o; 155217742Sralph NODE *old,*temp; 15539702Slinton 15549702Slinton o = p->in.op; 155517742Sralph if( ! (optype(o)==BITYPE && 155617742Sralph (ISUNSIGNED(p->in.left->in.type) || 155717742Sralph ISUNSIGNED(p->in.right->in.type))) ) 155817742Sralph return; 15599702Slinton 15609702Slinton for( f=opfunc; f->fop; f++ ) { 15619702Slinton if( o==f->fop ) goto convert; 15629702Slinton } 15639702Slinton return; 15649702Slinton 15659702Slinton convert: 156632931Sdonn if( p->in.right->in.op == ICON && p->in.right->tn.name[0] == '\0' ) 156732928Sdonn /* 'J', 'K' in zzzcode() -- assumes DIV or MOD operations */ 156832928Sdonn /* save a subroutine call -- use at most 5 instructions */ 156932928Sdonn return; 157032931Sdonn if( tlen(p->in.left) < SZINT/SZCHAR && tlen(p->in.right) < SZINT/SZCHAR ) 157132931Sdonn /* optim2() will modify the op into an ordinary int op */ 157232931Sdonn return; 15739702Slinton if( asgop( o ) ) { 157417742Sralph old = NIL; 157517715Sralph switch( p->in.left->in.op ){ 157617742Sralph case FLD: 157717742Sralph q = p->in.left->in.left; 157817742Sralph /* 157917742Sralph * rewrite (lval.fld /= rval); as 158017742Sralph * ((*temp).fld = udiv((*(temp = &lval)).fld,rval)); 158117742Sralph * else the compiler will evaluate lval twice. 158217742Sralph */ 158317742Sralph if( q->in.op == UNARY MUL ){ 158417742Sralph /* first allocate a temp storage */ 158517742Sralph temp = talloc(); 158617742Sralph temp->in.op = OREG; 158717742Sralph temp->tn.rval = TMPREG; 158817742Sralph temp->tn.lval = BITOOR(freetemp(1)); 158917742Sralph temp->in.type = INCREF(p->in.type); 159017742Sralph #ifdef FLEXNAMES 159117742Sralph temp->in.name = ""; 159217742Sralph #else 159317742Sralph temp->in.name[0] = '\0'; 159417742Sralph #endif 159517742Sralph old = q->in.left; 159617742Sralph q->in.left = temp; 159717742Sralph } 159817742Sralph /* fall thru ... */ 159917742Sralph 160017715Sralph case REG: 160117715Sralph case NAME: 160217715Sralph case OREG: 160317715Sralph /* change ASG OP to a simple OP */ 160417715Sralph q = talloc(); 160517715Sralph q->in.op = NOASG p->in.op; 160617715Sralph q->in.rall = NOPREF; 160717715Sralph q->in.type = p->in.type; 160817715Sralph q->in.left = tcopy(p->in.left); 160917715Sralph q->in.right = p->in.right; 161017715Sralph p->in.op = ASSIGN; 161117715Sralph p->in.right = q; 161217715Sralph p = q; 161317715Sralph f -= 2; /* Note: this depends on the table order */ 161417742Sralph /* on the right side only - replace *temp with 161517742Sralph *(temp = &lval), build the assignment node */ 161617742Sralph if( old ){ 161717742Sralph temp = q->in.left->in.left; /* the "*" node */ 161817742Sralph q = talloc(); 161917742Sralph q->in.op = ASSIGN; 162017742Sralph q->in.left = temp->in.left; 162117742Sralph q->in.right = old; 162217742Sralph q->in.type = old->in.type; 162317742Sralph #ifdef FLEXNAMES 162417742Sralph q->in.name = ""; 162517742Sralph #else 162617742Sralph q->in.name[0] = '\0'; 162717742Sralph #endif 162817742Sralph temp->in.left = q; 162917742Sralph } 163017715Sralph break; 16319702Slinton 163217715Sralph case UNARY MUL: 163317715Sralph /* avoid doing side effects twice */ 163417715Sralph q = p->in.left; 163517715Sralph p->in.left = q->in.left; 163617715Sralph q->in.op = FREE; 163717715Sralph break; 163817715Sralph 163917715Sralph default: 164017715Sralph cerror( "hardops: can't compute & LHS" ); 164117715Sralph } 164217742Sralph } 164317715Sralph 16449702Slinton /* build comma op for args to function */ 16459702Slinton q = talloc(); 16469702Slinton q->in.op = CM; 16479702Slinton q->in.rall = NOPREF; 16489702Slinton q->in.type = INT; 16499702Slinton q->in.left = p->in.left; 16509702Slinton q->in.right = p->in.right; 16519702Slinton p->in.op = CALL; 16529702Slinton p->in.right = q; 16539702Slinton 16549702Slinton /* put function name in left node of call */ 16559702Slinton p->in.left = q = talloc(); 16569702Slinton q->in.op = ICON; 16579702Slinton q->in.rall = NOPREF; 16589702Slinton q->in.type = INCREF( FTN + p->in.type ); 16599702Slinton #ifndef FLEXNAMES 16609702Slinton strcpy( q->in.name, f->func ); 16619702Slinton #else 16629702Slinton q->in.name = f->func; 16639702Slinton #endif 16649702Slinton q->tn.lval = 0; 16659702Slinton q->tn.rval = 0; 16669702Slinton 16679702Slinton } 16689702Slinton 166917742Sralph zappost(p) NODE *p; { 167017742Sralph /* look for ++ and -- operators and remove them */ 167117742Sralph 167217742Sralph register o, ty; 167317742Sralph register NODE *q; 167417742Sralph o = p->in.op; 167517742Sralph ty = optype( o ); 167617742Sralph 167717742Sralph switch( o ){ 167817742Sralph 167917742Sralph case INCR: 168017742Sralph case DECR: 168117742Sralph q = p->in.left; 168217742Sralph p->in.right->in.op = FREE; /* zap constant */ 168317742Sralph ncopy( p, q ); 168417742Sralph q->in.op = FREE; 168517742Sralph return; 168617742Sralph 168717742Sralph } 168817742Sralph 168917742Sralph if( ty == BITYPE ) zappost( p->in.right ); 169017742Sralph if( ty != LTYPE ) zappost( p->in.left ); 169117742Sralph } 169217742Sralph 169317742Sralph fixpre(p) NODE *p; { 169417742Sralph 169517742Sralph register o, ty; 169617742Sralph o = p->in.op; 169717742Sralph ty = optype( o ); 169817742Sralph 169917742Sralph switch( o ){ 170017742Sralph 170117742Sralph case ASG PLUS: 170217742Sralph p->in.op = PLUS; 170317742Sralph break; 170417742Sralph case ASG MINUS: 170517742Sralph p->in.op = MINUS; 170617742Sralph break; 170717742Sralph } 170817742Sralph 170917742Sralph if( ty == BITYPE ) fixpre( p->in.right ); 171017742Sralph if( ty != LTYPE ) fixpre( p->in.left ); 171117742Sralph } 171217742Sralph 171324418Smckusick strip(p) register NODE *p; { 171424418Smckusick NODE *q; 171524418Smckusick 171624418Smckusick /* strip nodes off the top when no side effects occur */ 171724418Smckusick for( ; ; ) { 171824418Smckusick switch( p->in.op ) { 171924418Smckusick case SCONV: /* remove lint tidbits */ 172024418Smckusick q = p->in.left; 172124418Smckusick ncopy( p, q ); 172224418Smckusick q->in.op = FREE; 172324418Smckusick break; 172424418Smckusick /* could probably add a few more here */ 172524418Smckusick default: 172624418Smckusick return; 172724418Smckusick } 172824418Smckusick } 172924418Smckusick } 173024418Smckusick 17319702Slinton myreader(p) register NODE *p; { 173224418Smckusick strip( p ); /* strip off operations with no side effects */ 173317742Sralph canon( p ); /* expands r-vals for fields */ 17349702Slinton walkf( p, hardops ); /* convert ops to function calls */ 17359702Slinton walkf( p, optim2 ); 17369702Slinton /* jwf toff = 0; /* stack offset swindle */ 17379702Slinton } 1738