117742Sralph # ifndef lint 2*32937Sdonn static char *sccsid ="@(#)local2.c 1.31 (Berkeley) 12/11/87"; 317742Sralph # endif 417742Sralph 518556Sralph # include "pass2.h" 632935Sdonn # include <ctype.h> 732935Sdonn 832935Sdonn # define putstr(s) fputs((s), stdout) 932935Sdonn 109702Slinton # ifdef FORT 119702Slinton int ftlab1, ftlab2; 129702Slinton # endif 139702Slinton /* a lot of the machine dependent parts of the second pass */ 149702Slinton 159702Slinton # define BITMASK(n) ((1L<<n)-1) 169702Slinton 1732924Sdonn /*ARGSUSED*/ 189702Slinton where(c){ 199702Slinton fprintf( stderr, "%s, line %d: ", filename, lineno ); 209702Slinton } 219702Slinton 229702Slinton lineid( l, fn ) char *fn; { 239702Slinton /* identify line l and file fn */ 249702Slinton printf( "# line %d, file %s\n", l, fn ); 259702Slinton } 269702Slinton 279702Slinton 289702Slinton eobl2(){ 2932935Sdonn register OFFSZ spoff; /* offset from stack pointer */ 3032935Sdonn #ifndef FORT 3132935Sdonn extern int ftlab1, ftlab2; 3232935Sdonn #endif 3332935Sdonn 349702Slinton spoff = maxoff; 359702Slinton if( spoff >= AUTOINIT ) spoff -= AUTOINIT; 369702Slinton spoff /= SZCHAR; 379702Slinton SETOFF(spoff,4); 3832935Sdonn #ifdef FORT 399702Slinton #ifndef FLEXNAMES 409702Slinton printf( " .set .F%d,%ld\n", ftnno, spoff ); 419702Slinton #else 429702Slinton /* SHOULD BE L%d ... ftnno but must change pc/f77 */ 439702Slinton printf( " .set LF%d,%ld\n", ftnno, spoff ); 449702Slinton #endif 459702Slinton #else 469702Slinton printf( "L%d:\n", ftlab1); 479702Slinton if( spoff!=0 ) 489702Slinton if( spoff < 64 ) 499702Slinton printf( " subl2 $%ld,sp\n", spoff); 509702Slinton else 519702Slinton printf( " movab -%ld(sp),sp\n", spoff); 529702Slinton printf( " jbr L%d\n", ftlab2); 539702Slinton #endif 549702Slinton maxargs = -1; 559702Slinton } 569702Slinton 579702Slinton struct hoptab { int opmask; char * opstring; } ioptab[] = { 589702Slinton 599702Slinton PLUS, "add", 609702Slinton MINUS, "sub", 619702Slinton MUL, "mul", 629702Slinton DIV, "div", 639702Slinton OR, "bis", 649702Slinton ER, "xor", 659702Slinton AND, "bic", 669702Slinton -1, "" }; 679702Slinton 689702Slinton hopcode( f, o ){ 699702Slinton /* output the appropriate string from the above table */ 709702Slinton 719702Slinton register struct hoptab *q; 729702Slinton 7332935Sdonn if(asgop(o)) 7432935Sdonn o = NOASG o; 759702Slinton for( q = ioptab; q->opmask>=0; ++q ){ 769702Slinton if( q->opmask == o ){ 7732935Sdonn printf( "%s%c", q->opstring, tolower(f)); 789702Slinton return; 799702Slinton } 809702Slinton } 819702Slinton cerror( "no hoptab for %s", opst[o] ); 829702Slinton } 839702Slinton 849702Slinton char * 859702Slinton rnames[] = { /* keyed to register number tokens */ 869702Slinton 879702Slinton "r0", "r1", 889702Slinton "r2", "r3", "r4", "r5", 899702Slinton "r6", "r7", "r8", "r9", "r10", "r11", 909702Slinton "ap", "fp", "sp", "pc", 919702Slinton }; 929702Slinton 939702Slinton int rstatus[] = { 949702Slinton SAREG|STAREG, SAREG|STAREG, 959702Slinton SAREG|STAREG, SAREG|STAREG, SAREG|STAREG, SAREG|STAREG, 969702Slinton SAREG, SAREG, SAREG, SAREG, SAREG, SAREG, 979702Slinton SAREG, SAREG, SAREG, SAREG, 989702Slinton }; 999702Slinton 1009702Slinton tlen(p) NODE *p; 1019702Slinton { 1029702Slinton switch(p->in.type) { 1039702Slinton case CHAR: 1049702Slinton case UCHAR: 1059702Slinton return(1); 1069702Slinton 1079702Slinton case SHORT: 1089702Slinton case USHORT: 109*32937Sdonn return(SZSHORT/SZCHAR); 1109702Slinton 1119702Slinton case DOUBLE: 112*32937Sdonn return(SZDOUBLE/SZCHAR); 1139702Slinton 1149702Slinton default: 115*32937Sdonn return(SZINT/SZCHAR); 1169702Slinton } 1179702Slinton } 1189702Slinton 1199702Slinton mixtypes(p, q) NODE *p, *q; 1209702Slinton { 12116181Sralph register TWORD tp, tq; 1229702Slinton 1239702Slinton tp = p->in.type; 1249702Slinton tq = q->in.type; 1259702Slinton 1269702Slinton return( (tp==FLOAT || tp==DOUBLE) != 1279702Slinton (tq==FLOAT || tq==DOUBLE) ); 1289702Slinton } 1299702Slinton 1309702Slinton prtype(n) NODE *n; 1319702Slinton { 1329702Slinton switch (n->in.type) 1339702Slinton { 13432935Sdonn 1359702Slinton case DOUBLE: 13624418Smckusick putchar('d'); 1379702Slinton return; 1389702Slinton 1399702Slinton case FLOAT: 14024418Smckusick putchar('f'); 1419702Slinton return; 1429702Slinton 1439702Slinton case LONG: 1449702Slinton case ULONG: 1459702Slinton case INT: 1469702Slinton case UNSIGNED: 14724418Smckusick putchar('l'); 1489702Slinton return; 1499702Slinton 1509702Slinton case SHORT: 1519702Slinton case USHORT: 15224418Smckusick putchar('w'); 1539702Slinton return; 1549702Slinton 1559702Slinton case CHAR: 1569702Slinton case UCHAR: 15724418Smckusick putchar('b'); 1589702Slinton return; 1599702Slinton 1609702Slinton default: 1619702Slinton if ( !ISPTR( n->in.type ) ) cerror("zzzcode- bad type"); 1629702Slinton else { 16324418Smckusick putchar('l'); 1649702Slinton return; 1659702Slinton } 1669702Slinton } 1679702Slinton } 1689702Slinton 1699702Slinton zzzcode( p, c ) register NODE *p; { 17032935Sdonn register int m; 17132924Sdonn int val; 1729702Slinton switch( c ){ 1739702Slinton 1749702Slinton case 'N': /* logical ops, turned into 0-1 */ 1759702Slinton /* use register given by register 1 */ 1769702Slinton cbgen( 0, m=getlab(), 'I' ); 1779702Slinton deflab( p->bn.label ); 1789702Slinton printf( " clrl %s\n", rnames[getlr( p, '1' )->tn.rval] ); 1799702Slinton deflab( m ); 1809702Slinton return; 1819702Slinton 1829702Slinton case 'P': 1839702Slinton cbgen( p->in.op, p->bn.label, c ); 1849702Slinton return; 1859702Slinton 1869702Slinton case 'A': 18732935Sdonn case 'V': 18832935Sdonn sconv( p, c == 'V' ); 1899702Slinton return; 1909702Slinton 19125751Sdonn case 'G': /* i *= f; asgops with int lhs and float rhs */ 19225751Sdonn { 19325751Sdonn register NODE *l, *r, *s; 19425751Sdonn int rt; 19525751Sdonn 19625751Sdonn l = p->in.left; 19725751Sdonn r = p->in.right; 19825751Sdonn s = talloc(); 19925751Sdonn rt = r->in.type; 20025751Sdonn 20125751Sdonn s->in.op = SCONV; 20225751Sdonn s->in.left = l; 20325751Sdonn s->in.type = rt; 20425751Sdonn zzzcode(s, 'A'); 20525751Sdonn putstr("\n\t"); 20625751Sdonn 20725751Sdonn hopcode(rt == FLOAT ? 'F' : 'D', p->in.op); 20825751Sdonn putstr("2\t"); 20925751Sdonn adrput(r); 21025751Sdonn putchar(','); 21125751Sdonn adrput(resc); 21225751Sdonn putstr("\n\t"); 21325751Sdonn 21425751Sdonn s->in.op = ASSIGN; 21525751Sdonn s->in.left = l; 21625751Sdonn s->in.right = resc; 21725751Sdonn s->in.type = l->in.type; 21825751Sdonn zzzcode(s, 'A'); 21925751Sdonn 22025751Sdonn s->in.op = FREE; 22125751Sdonn return; 22225751Sdonn } 22325751Sdonn 22432928Sdonn case 'J': /* unsigned DIV/MOD with constant divisors */ 22532928Sdonn { 22632928Sdonn register int ck = INAREG; 22732928Sdonn int label1, label2; 22832928Sdonn 22932928Sdonn /* case constant <= 1 is handled by optim() in pass 1 */ 23032928Sdonn /* case constant < 0x80000000 is handled in table */ 23132928Sdonn switch( p->in.op ) { 23232928Sdonn /* case DIV: handled in hardops() */ 23332928Sdonn case MOD: 23432928Sdonn if( p->in.left->in.op == REG && 23532928Sdonn p->in.left->tn.rval == resc->tn.rval ) 23632928Sdonn goto asgmod; 23732928Sdonn label1 = getlab(); 23832928Sdonn expand(p, ck, "movl\tAL,A1\n\tcmpl\tA1,AR\n"); 23932928Sdonn printf("\tjlssu\tL%d\n", label1); 24032928Sdonn expand(p, ck, "\tsubl2\tAR,A1\n"); 24132928Sdonn printf("L%d:", label1); 24232928Sdonn break; 24332928Sdonn case ASG DIV: 24432928Sdonn label1 = getlab(); 24532928Sdonn label2 = getlab(); 24632928Sdonn expand(p, ck, "cmpl\tAL,AR\n"); 24732928Sdonn printf("\tjgequ\tL%d\n", label1); 24832928Sdonn expand(p, ck, "\tmovl\t$1,AL\n"); 24932928Sdonn printf("\tjbr\tL%d\nL%d:\n", label2, label1); 25032928Sdonn expand(p, ck, "\tclrl\tAL\n"); 25132928Sdonn printf("L%d:", label2); 25232928Sdonn break; 25332928Sdonn case ASG MOD: 25432928Sdonn asgmod: 25532928Sdonn label1 = getlab(); 25632928Sdonn expand(p, ck, "cmpl\tAL,AR\n"); 25732928Sdonn printf("\tjlssu\tL%d\n", label1); 25832928Sdonn expand(p, ck, "\tsubl2\tAR,AL\n"); 25932928Sdonn printf("L%d:", label1); 26032928Sdonn break; 26132928Sdonn } 26232928Sdonn return; 26332928Sdonn } 26432928Sdonn 2659702Slinton case 'B': /* get oreg value in temp register for left shift */ 2669702Slinton { 2679702Slinton register NODE *r; 2689702Slinton if (xdebug) eprint(p, 0, &val, &val); 2699702Slinton r = p->in.right; 270*32937Sdonn if( tlen(r) == SZINT/SZCHAR && r->in.type != FLOAT ) 27124418Smckusick putstr("movl"); 2729702Slinton else { 27332935Sdonn putstr(ISUNSIGNED(r->in.type) ? "movz" : "cvt"); 2749702Slinton prtype(r); 27524418Smckusick putchar('l'); 2769702Slinton } 2779702Slinton return; 2789702Slinton } 2799702Slinton 2809702Slinton case 'C': /* num words pushed on arg stack */ 2819702Slinton { 2829702Slinton extern int gc_numbytes; 2839702Slinton extern int xdebug; 2849702Slinton 2859702Slinton if (xdebug) printf("->%d<-",gc_numbytes); 2869702Slinton 2879702Slinton printf("$%d", gc_numbytes/(SZLONG/SZCHAR) ); 2889702Slinton return; 2899702Slinton } 2909702Slinton 2919702Slinton case 'D': /* INCR and DECR */ 2929702Slinton zzzcode(p->in.left, 'A'); 29324418Smckusick putchar('\n'); 29424418Smckusick putchar('\t'); 2959702Slinton 2969702Slinton case 'E': /* INCR and DECR, FOREFF */ 29732934Sdonn if (p->in.right->in.op == ICON && p->in.right->tn.lval == 1) 2989702Slinton { 29932935Sdonn putstr(p->in.op == INCR ? "inc" : "dec"); 3009702Slinton prtype(p->in.left); 30124418Smckusick putchar('\t'); 3029702Slinton adrput(p->in.left); 3039702Slinton return; 3049702Slinton } 30532935Sdonn putstr(p->in.op == INCR ? "add" : "sub"); 3069702Slinton prtype(p->in.left); 30724418Smckusick putchar('2'); 30824418Smckusick putchar('\t'); 3099702Slinton adrput(p->in.right); 31024418Smckusick putchar(','); 3119702Slinton adrput(p->in.left); 3129702Slinton return; 3139702Slinton 3149702Slinton case 'F': /* register type of right operand */ 3159702Slinton { 3169702Slinton register NODE *n; 3179702Slinton extern int xdebug; 3189702Slinton register int ty; 3199702Slinton 3209702Slinton n = getlr( p, 'R' ); 3219702Slinton ty = n->in.type; 3229702Slinton 3239702Slinton if (xdebug) printf("->%d<-", ty); 3249702Slinton 32524418Smckusick if ( ty==DOUBLE) putchar('d'); 32624418Smckusick else if ( ty==FLOAT ) putchar('f'); 32724418Smckusick else putchar('l'); 3289702Slinton return; 3299702Slinton } 3309702Slinton 3319702Slinton case 'L': /* type of left operand */ 3329702Slinton case 'R': /* type of right operand */ 3339702Slinton { 3349702Slinton register NODE *n; 3359702Slinton extern int xdebug; 3369702Slinton 33716181Sralph n = getlr( p, c ); 3389702Slinton if (xdebug) printf("->%d<-", n->in.type); 3399702Slinton 3409702Slinton prtype(n); 3419702Slinton return; 3429702Slinton } 3439702Slinton 3449702Slinton case 'Z': /* complement mask for bit instr */ 3459702Slinton printf("$%ld", ~p->in.right->tn.lval); 3469702Slinton return; 3479702Slinton 3489702Slinton case 'U': /* 32 - n, for unsigned right shifts */ 3499702Slinton printf("$%d", 32 - p->in.right->tn.lval ); 3509702Slinton return; 3519702Slinton 3529702Slinton case 'T': /* rounded structure length for arguments */ 3539702Slinton { 3549702Slinton int size; 3559702Slinton 3569702Slinton size = p->stn.stsize; 3579702Slinton SETOFF( size, 4); 3589702Slinton printf("$%d", size); 3599702Slinton return; 3609702Slinton } 3619702Slinton 3629702Slinton case 'S': /* structure assignment */ 36332935Sdonn stasg(p); 36432935Sdonn break; 3659702Slinton 36632935Sdonn default: 36732935Sdonn cerror( "illegal zzzcode" ); 36832935Sdonn } 36932935Sdonn } 3709702Slinton 37132935Sdonn stasg(p) 37232935Sdonn register NODE *p; 37332935Sdonn { 37432935Sdonn register NODE *l, *r; 37532935Sdonn register size; 3769702Slinton 37732935Sdonn if( p->in.op == STASG ){ 37832935Sdonn l = p->in.left; 37932935Sdonn r = p->in.right; 3809702Slinton 38132935Sdonn } 38232935Sdonn else if( p->in.op == STARG ){ /* store an arg into a temporary */ 38332935Sdonn r = p->in.left; 38432935Sdonn } 38532935Sdonn else cerror( "STASG bad" ); 3869702Slinton 38732935Sdonn if( r->in.op == ICON ) r->in.op = NAME; 38832935Sdonn else if( r->in.op == REG ) r->in.op = OREG; 38932935Sdonn else if( r->in.op != OREG ) cerror( "STASG-r" ); 3909702Slinton 39132935Sdonn size = p->stn.stsize; 39232935Sdonn 39332935Sdonn if( size <= 0 || size > 65535 ) 39432935Sdonn cerror("structure size <0=0 or >65535"); 39532935Sdonn 39632935Sdonn switch(size) { 39732935Sdonn case 1: 39832935Sdonn putstr(" movb "); 39932935Sdonn break; 40032935Sdonn case 2: 40132935Sdonn putstr(" movw "); 40232935Sdonn break; 40332935Sdonn case 4: 40432935Sdonn putstr(" movl "); 40532935Sdonn break; 40632935Sdonn case 8: 40732935Sdonn putstr(" movq "); 40832935Sdonn break; 40932935Sdonn default: 41032935Sdonn printf(" movc3 $%d,", size); 41132935Sdonn break; 41232935Sdonn } 41332935Sdonn adrput(r); 41432935Sdonn if( p->in.op == STASG ){ 41532935Sdonn putchar(','); 41632935Sdonn adrput(l); 41732935Sdonn putchar('\n'); 41832935Sdonn } 41932935Sdonn else 42032935Sdonn putstr(",(sp)\n"); 42132935Sdonn 42232935Sdonn if( r->in.op == NAME ) r->in.op = ICON; 42332935Sdonn else if( r->in.op == OREG ) r->in.op = REG; 42432935Sdonn } 42532935Sdonn 42632935Sdonn NODE *makearg( ty ) int ty; { 42732935Sdonn register NODE *p, *q; 42832935Sdonn 42932935Sdonn /* build a -(sp) operand */ 43032935Sdonn p = talloc(); 43132935Sdonn p->in.op = REG; 43232935Sdonn /* the type needn't be right, just consistent */ 43332935Sdonn p->in.type = INCREF(ty); 43432935Sdonn p->tn.rval = SP; 43532935Sdonn p->tn.lval = 0; 43632935Sdonn q = talloc(); 43732935Sdonn q->in.op = ASG MINUS; 43832935Sdonn q->in.type = INCREF(ty); 43932935Sdonn q->in.left = p; 44032935Sdonn p = talloc(); 44132935Sdonn p->in.op = ICON; 44232935Sdonn p->in.type = INT; 44332935Sdonn p->tn.name = ""; 44432935Sdonn p->tn.lval = tlen(ty); 44532935Sdonn q->in.right = p; 44632935Sdonn p = talloc(); 44732935Sdonn p->in.op = UNARY MUL; 44832935Sdonn p->in.left = q; 44932935Sdonn return( p ); 45032935Sdonn } 45132935Sdonn 45232935Sdonn sconv( p, forarg ) register NODE *p; { 45332935Sdonn register NODE *l, *r; 45432935Sdonn int m, val; 45532935Sdonn 45632935Sdonn if (xdebug) eprint(p, 0, &val, &val); 45732935Sdonn r = getlr(p, 'R'); 45832935Sdonn if (p->in.op == ASSIGN) 45932935Sdonn l = getlr(p, 'L'); 46032935Sdonn else if (p->in.op == SCONV) { 46132935Sdonn #if defined(FORT) || defined(SPRECC) 46232935Sdonn m = r->in.type; 46332935Sdonn #else 46432935Sdonn m = r->in.type==FLOAT ? DOUBLE : r->in.type; 46532935Sdonn #endif 46632935Sdonn if (forarg) 46732935Sdonn l = makearg( m ); 46832935Sdonn else 46932935Sdonn l = resc; 47032935Sdonn l->in.type = m; 47132935Sdonn r = getlr(p, 'L'); 47232935Sdonn } 47332935Sdonn else { /* OPLTYPE */ 47432935Sdonn #if defined(FORT) || defined(SPRECC) 47532935Sdonn m = (r->in.type==FLOAT || r->in.type==DOUBLE ? r->in.type : INT); 47632935Sdonn #else 47732935Sdonn m = (r->in.type==FLOAT || r->in.type==DOUBLE ? DOUBLE : INT); 47832935Sdonn #endif 47932935Sdonn if (forarg) 48032935Sdonn l = makearg( m ); 48132935Sdonn else 48232935Sdonn l = resc; 48332935Sdonn l->in.type = m; 48432935Sdonn } 48532935Sdonn if (r->in.op == ICON) 48632935Sdonn if (r->in.name[0] == '\0') { 48732935Sdonn if (r->tn.lval == 0) { 48832935Sdonn putstr("clr"); 48932935Sdonn prtype(l); 49032935Sdonn putchar('\t'); 49116418Sralph adrput(l); 49232935Sdonn goto cleanup; 49316418Sralph } 49432935Sdonn if (r->tn.lval < 0 && r->tn.lval >= -63) { 49532935Sdonn putstr("mneg"); 49632935Sdonn prtype(l); 49732935Sdonn r->tn.lval = -r->tn.lval; 49832935Sdonn goto ops; 49932935Sdonn } 50032935Sdonn if (r->tn.lval < 0) 50132935Sdonn r->in.type = r->tn.lval >= -128 ? CHAR 50232935Sdonn : (r->tn.lval >= -32768 ? SHORT 50332935Sdonn : INT); 50432935Sdonn else if (l->in.type == FLOAT || 50532935Sdonn l->in.type == DOUBLE) 50632935Sdonn r->in.type = r->tn.lval <= 63 ? INT 50732935Sdonn : (r->tn.lval <= 127 ? CHAR 50832935Sdonn : (r->tn.lval <= 32767 ? SHORT 50932935Sdonn : INT)); 51016418Sralph else 51132935Sdonn r->in.type = r->tn.lval <= 63 ? INT 51232935Sdonn : (r->tn.lval <= 127 ? CHAR 51332935Sdonn : (r->tn.lval <= 255 ? UCHAR 51432935Sdonn : (r->tn.lval <= 32767 ? SHORT 51532935Sdonn : (r->tn.lval <= 65535 ? USHORT 51632935Sdonn : INT)))); 51732935Sdonn } 51832935Sdonn else { 51932935Sdonn putstr("moval"); 52032935Sdonn putchar('\t'); 52132935Sdonn acon(r); 52232935Sdonn putchar(','); 52332935Sdonn adrput(l); 52432935Sdonn goto cleanup; 52532935Sdonn } 5269702Slinton 52732935Sdonn if (p->in.op == SCONV && 52832935Sdonn !(l->in.type == FLOAT || l->in.type == DOUBLE) && 52932935Sdonn !mixtypes(l, r)) { 53032935Sdonn /* 53132935Sdonn * Because registers must always contain objects 53232935Sdonn * of the same width as INTs, we may have to 53332935Sdonn * perform two conversions to get an INT. Can 53432935Sdonn * the conversions be collapsed into one? 53532935Sdonn */ 53632935Sdonn if (m = collapsible(l, r)) 53732935Sdonn r->in.type = m; 53832935Sdonn else { 53932935Sdonn /* 54032935Sdonn * Two steps are required. 54132935Sdonn */ 54232935Sdonn NODE *x = &resc[1]; 5439702Slinton 54432935Sdonn *x = *l; 54532935Sdonn if (tlen(x) > tlen(r) && ISUNSIGNED(r->in.type)) 54632935Sdonn putstr("movz"); 54732935Sdonn else 54832935Sdonn putstr("cvt"); 54932935Sdonn prtype(r); 55032935Sdonn prtype(x); 55132935Sdonn putchar('\t'); 55232935Sdonn adrput(r); 55332935Sdonn putchar(','); 55432935Sdonn adrput(x); 55532935Sdonn putchar('\n'); 55632935Sdonn putchar('\t'); 55732935Sdonn r = x; 5589702Slinton } 55932935Sdonn l->in.type = (ISUNSIGNED(l->in.type) ? UNSIGNED : INT); 56032935Sdonn } 5619702Slinton 56232935Sdonn if ((r->in.type == UNSIGNED || r->in.type == ULONG) && 56332935Sdonn mixtypes(l, r)) { 56432935Sdonn int label1, label2; 56532935Sdonn 56632935Sdonn label1 = getlab(); 56732935Sdonn label2 = getlab(); 56832935Sdonn 56932935Sdonn putstr("movl\t"); 57032935Sdonn adrput(r); 57132935Sdonn putchar(','); 57232935Sdonn adrput(l); 57332935Sdonn putstr("\n\tjbsc\t$31,"); 57432935Sdonn adrput(l); 57532935Sdonn printf(",L%d\n\tcvtl", label1); 57632935Sdonn prtype(l); 57732935Sdonn putchar('\t'); 57832935Sdonn adrput(l); 57932935Sdonn putchar(','); 58032935Sdonn adrput(l); 58132935Sdonn printf("\n\tjbr\tL%d\nL%d:\n\tcvtl", label2, label1); 58232935Sdonn prtype(l); 58332935Sdonn putchar('\t'); 58432935Sdonn adrput(l); 58532935Sdonn putchar(','); 58632935Sdonn adrput(l); 58732935Sdonn putstr("\n\tadd"); 58832935Sdonn prtype(l); 58932935Sdonn putstr("2\t$0"); 59032935Sdonn prtype(l); 59132935Sdonn putstr("2.147483648e9,"); 59232935Sdonn adrput(l); 59332935Sdonn printf("\nL%d:", label2); 59432935Sdonn 59532935Sdonn goto cleanup; 5969702Slinton } 59732935Sdonn 59832935Sdonn if (!mixtypes(l,r)) { 59932935Sdonn if (tlen(l) == tlen(r)) { 60032935Sdonn putstr("mov"); 60132935Sdonn #ifdef FORT 60232935Sdonn if (Oflag) 60332935Sdonn prtype(l); 60432935Sdonn else { 60532935Sdonn if (l->in.type == DOUBLE) 60632935Sdonn putchar('q'); 60732935Sdonn else if(l->in.type == FLOAT) 60832935Sdonn putchar('l'); 60932935Sdonn else 61032935Sdonn prtype(l); 61132935Sdonn } 61232935Sdonn #else 61332935Sdonn prtype(l); 61432935Sdonn #endif FORT 61532935Sdonn goto ops; 61632935Sdonn } 61732935Sdonn else if (tlen(l) > tlen(r) && ISUNSIGNED(r->in.type)) 61832935Sdonn putstr("movz"); 61932935Sdonn else 62032935Sdonn putstr("cvt"); 62132935Sdonn } 62232935Sdonn else 62332935Sdonn putstr("cvt"); 62432935Sdonn prtype(r); 62532935Sdonn prtype(l); 62632935Sdonn ops: 62732935Sdonn putchar('\t'); 62832935Sdonn adrput(r); 62932935Sdonn putchar(','); 63032935Sdonn adrput(l); 63132935Sdonn 63232935Sdonn cleanup: 63332935Sdonn if (forarg) 63432935Sdonn tfree(l); 6359702Slinton } 6369702Slinton 63723536Sbloom /* 63823536Sbloom * collapsible(dest, src) -- if a conversion with a register destination 63923536Sbloom * can be accomplished in one instruction, return the type of src 64023536Sbloom * that will do the job correctly; otherwise return 0. Note that 64123536Sbloom * a register must always end up having type INT or UNSIGNED. 64223536Sbloom */ 64323536Sbloom int 64423536Sbloom collapsible(dest, src) 64523536Sbloom NODE *dest, *src; 64623536Sbloom { 64723536Sbloom int st = src->in.type; 64823536Sbloom int dt = dest->in.type; 64923536Sbloom int newt = 0; 65023536Sbloom 65123536Sbloom /* 65223536Sbloom * Are there side effects of evaluating src? 65323536Sbloom * If the derived type will not be the same size as src, 65424418Smckusick * we may have to use two steps. 65523536Sbloom */ 65624418Smckusick if (tlen(src) > tlen(dest)) { 65724418Smckusick if (tshape(src, STARREG)) 65824418Smckusick return (0); 65924418Smckusick if (src->in.op == OREG && R2TEST(src->tn.rval)) 66024418Smckusick return (0); 66124418Smckusick } 66223536Sbloom 66323536Sbloom /* 66423536Sbloom * Can we get an object of dest's type by punning src? 66523536Sbloom * Praises be to great Cthulhu for little-endian machines... 66623536Sbloom */ 66723536Sbloom if (st == CHAR && dt == USHORT) 66823536Sbloom /* 66923536Sbloom * Special case -- we must sign-extend to 16 bits. 67023536Sbloom */ 67123536Sbloom return (0); 67223536Sbloom 67323536Sbloom if (tlen(src) < tlen(dest)) 67423536Sbloom newt = st; 67523536Sbloom else 67623536Sbloom newt = dt; 67723536Sbloom 67823536Sbloom return (newt); 67923536Sbloom } 68023536Sbloom 68117742Sralph rmove( rt, rs, t ) TWORD t; { 6829702Slinton printf( " %s %s,%s\n", 68317742Sralph #ifdef FORT 68417742Sralph !Oflag ? (t==DOUBLE ? "movq" : "movl") : 68517742Sralph #endif 6869702Slinton (t==FLOAT ? "movf" : (t==DOUBLE ? "movd" : "movl")), 6879702Slinton rnames[rs], rnames[rt] ); 6889702Slinton } 6899702Slinton 6909702Slinton struct respref 6919702Slinton respref[] = { 6929702Slinton INTAREG|INTBREG, INTAREG|INTBREG, 6939702Slinton INAREG|INBREG, INAREG|INBREG|SOREG|STARREG|STARNM|SNAME|SCON, 6949702Slinton INTEMP, INTEMP, 6959702Slinton FORARG, FORARG, 6969702Slinton INTEMP, INTAREG|INAREG|INTBREG|INBREG|SOREG|STARREG|STARNM, 6979702Slinton 0, 0 }; 6989702Slinton 6999702Slinton setregs(){ /* set up temporary registers */ 7009702Slinton fregs = 6; /* tbl- 6 free regs on VAX (0-5) */ 7019702Slinton } 7029702Slinton 70332924Sdonn /*ARGSUSED*/ 7049702Slinton rewfld( p ) NODE *p; { 7059702Slinton return(1); 7069702Slinton } 7079702Slinton 70832924Sdonn /*ARGSUSED*/ 7099702Slinton callreg(p) NODE *p; { 7109702Slinton return( R0 ); 7119702Slinton } 7129702Slinton 7139702Slinton base( p ) register NODE *p; { 7149702Slinton register int o = p->in.op; 7159702Slinton 7169702Slinton if( (o==ICON && p->in.name[0] != '\0')) return( 100 ); /* ie no base reg */ 7179702Slinton if( o==REG ) return( p->tn.rval ); 7189702Slinton if( (o==PLUS || o==MINUS) && p->in.left->in.op == REG && p->in.right->in.op==ICON) 7199702Slinton return( p->in.left->tn.rval ); 7209702Slinton if( o==OREG && !R2TEST(p->tn.rval) && (p->in.type==INT || p->in.type==UNSIGNED || ISPTR(p->in.type)) ) 7219702Slinton return( p->tn.rval + 0200*1 ); 7229702Slinton if( o==INCR && p->in.left->in.op==REG ) return( p->in.left->tn.rval + 0200*2 ); 7239702Slinton if( o==ASG MINUS && p->in.left->in.op==REG) return( p->in.left->tn.rval + 0200*4 ); 7249702Slinton if( o==UNARY MUL && p->in.left->in.op==INCR && p->in.left->in.left->in.op==REG 7259702Slinton && (p->in.type==INT || p->in.type==UNSIGNED || ISPTR(p->in.type)) ) 7269702Slinton return( p->in.left->in.left->tn.rval + 0200*(1+2) ); 7279702Slinton return( -1 ); 7289702Slinton } 7299702Slinton 7309702Slinton offset( p, tyl ) register NODE *p; int tyl; { 7319702Slinton 73224418Smckusick if( tyl==1 && 73324418Smckusick p->in.op==REG && 73424418Smckusick (p->in.type==INT || p->in.type==UNSIGNED) ) 73524418Smckusick return( p->tn.rval ); 73624418Smckusick if( p->in.op==LS && 73724418Smckusick p->in.left->in.op==REG && 73824418Smckusick (p->in.left->in.type==INT || p->in.left->in.type==UNSIGNED) && 73924418Smckusick p->in.right->in.op==ICON && 74024418Smckusick p->in.right->in.name[0]=='\0' && 74124418Smckusick (1<<p->in.right->tn.lval)==tyl) 7429702Slinton return( p->in.left->tn.rval ); 74324418Smckusick if( tyl==2 && 74424418Smckusick p->in.op==PLUS && 74524418Smckusick (p->in.left->in.type==INT || p->in.left->in.type==UNSIGNED) && 74624418Smckusick p->in.left->in.op==REG && 74724418Smckusick p->in.right->in.op==REG && 74824418Smckusick p->in.left->tn.rval==p->in.right->tn.rval ) 74924418Smckusick return( p->in.left->tn.rval ); 7509702Slinton return( -1 ); 7519702Slinton } 7529702Slinton 7539702Slinton makeor2( p, q, b, o) register NODE *p, *q; register int b, o; { 7549702Slinton register NODE *t; 7559702Slinton NODE *f; 7569702Slinton 7579702Slinton p->in.op = OREG; 7589702Slinton f = p->in.left; /* have to free this subtree later */ 7599702Slinton 7609702Slinton /* init base */ 7619702Slinton switch (q->in.op) { 7629702Slinton case ICON: 7639702Slinton case REG: 7649702Slinton case OREG: 7659702Slinton t = q; 7669702Slinton break; 7679702Slinton 7689702Slinton case MINUS: 7699702Slinton q->in.right->tn.lval = -q->in.right->tn.lval; 7709702Slinton case PLUS: 7719702Slinton t = q->in.right; 7729702Slinton break; 7739702Slinton 7749702Slinton case INCR: 7759702Slinton case ASG MINUS: 7769702Slinton t = q->in.left; 7779702Slinton break; 7789702Slinton 7799702Slinton case UNARY MUL: 7809702Slinton t = q->in.left->in.left; 7819702Slinton break; 7829702Slinton 7839702Slinton default: 7849702Slinton cerror("illegal makeor2"); 7859702Slinton } 7869702Slinton 7879702Slinton p->tn.lval = t->tn.lval; 7889702Slinton #ifndef FLEXNAMES 78932924Sdonn { 79032924Sdonn register int i; 79132924Sdonn for(i=0; i<NCHNAM; ++i) 79232924Sdonn p->in.name[i] = t->in.name[i]; 79332924Sdonn } 7949702Slinton #else 7959702Slinton p->in.name = t->in.name; 7969702Slinton #endif 7979702Slinton 7989702Slinton /* init offset */ 7999702Slinton p->tn.rval = R2PACK( (b & 0177), o, (b>>7) ); 8009702Slinton 8019702Slinton tfree(f); 8029702Slinton return; 8039702Slinton } 8049702Slinton 8059702Slinton canaddr( p ) NODE *p; { 8069702Slinton register int o = p->in.op; 8079702Slinton 8089702Slinton if( o==NAME || o==REG || o==ICON || o==OREG || (o==UNARY MUL && shumul(p->in.left)) ) return(1); 8099702Slinton return(0); 8109702Slinton } 8119702Slinton 81232935Sdonn flshape( p ) NODE *p; { 81332935Sdonn register int o = p->in.op; 81432935Sdonn 81532935Sdonn return( o == REG || o == NAME || o == ICON || 81632935Sdonn (o == OREG && (!R2TEST(p->tn.rval) || tlen(p) == 1)) ); 8179702Slinton } 8189702Slinton 81932926Sdonn /* INTEMP shapes must not contain any temporary registers */ 8209702Slinton shtemp( p ) register NODE *p; { 82132926Sdonn int r; 82232926Sdonn 8239702Slinton if( p->in.op == STARG ) p = p->in.left; 82432926Sdonn 82532926Sdonn switch (p->in.op) { 82632926Sdonn case REG: 82732926Sdonn return( !istreg(p->tn.rval) ); 82832926Sdonn case OREG: 82932926Sdonn r = p->tn.rval; 83032926Sdonn if( R2TEST(r) ) { 83132926Sdonn if( istreg(R2UPK1(r)) ) 83232926Sdonn return(0); 83332926Sdonn r = R2UPK2(r); 83432926Sdonn } 83532926Sdonn return( !istreg(r) ); 83632926Sdonn case UNARY MUL: 83732926Sdonn p = p->in.left; 83832926Sdonn return( p->in.op != UNARY MUL && shtemp(p) ); 83932926Sdonn } 84032926Sdonn 84132926Sdonn if( optype( p->in.op ) != LTYPE ) return(0); 84232926Sdonn return(1); 8439702Slinton } 8449702Slinton 8459702Slinton shumul( p ) register NODE *p; { 84632935Sdonn register int o; 8479702Slinton extern int xdebug; 8489702Slinton 8499702Slinton if (xdebug) { 85032933Sdonn int val; 85132933Sdonn printf("shumul:\n"); 85232933Sdonn eprint(p, 0, &val, &val); 8539702Slinton } 8549702Slinton 8559702Slinton o = p->in.op; 8569702Slinton if( o == NAME || (o == OREG && !R2TEST(p->tn.rval)) || o == ICON ) return( STARNM ); 8579702Slinton 8589702Slinton if( ( o == INCR || o == ASG MINUS ) && 8599702Slinton ( p->in.left->in.op == REG && p->in.right->in.op == ICON ) && 8609702Slinton p->in.right->in.name[0] == '\0' ) 8619702Slinton { 86217659Sralph switch (p->in.type) 8639702Slinton { 8649702Slinton case CHAR|PTR: 8659702Slinton case UCHAR|PTR: 8669702Slinton o = 1; 8679702Slinton break; 8689702Slinton 8699702Slinton case SHORT|PTR: 8709702Slinton case USHORT|PTR: 8719702Slinton o = 2; 8729702Slinton break; 8739702Slinton 8749702Slinton case INT|PTR: 8759702Slinton case UNSIGNED|PTR: 8769702Slinton case LONG|PTR: 8779702Slinton case ULONG|PTR: 8789702Slinton case FLOAT|PTR: 8799702Slinton o = 4; 8809702Slinton break; 8819702Slinton 8829702Slinton case DOUBLE|PTR: 8839702Slinton o = 8; 8849702Slinton break; 8859702Slinton 8869702Slinton default: 88717742Sralph if ( ISPTR(p->in.type) && 88817742Sralph ISPTR(DECREF(p->in.type)) ) { 8899702Slinton o = 4; 8909702Slinton break; 8919702Slinton } 8929702Slinton else return(0); 8939702Slinton } 8949702Slinton return( p->in.right->tn.lval == o ? STARREG : 0); 8959702Slinton } 8969702Slinton 8979702Slinton return( 0 ); 8989702Slinton } 8999702Slinton 9009702Slinton adrcon( val ) CONSZ val; { 90124418Smckusick putchar( '$' ); 9029702Slinton printf( CONFMT, val ); 9039702Slinton } 9049702Slinton 9059702Slinton conput( p ) register NODE *p; { 9069702Slinton switch( p->in.op ){ 9079702Slinton 9089702Slinton case ICON: 9099702Slinton acon( p ); 9109702Slinton return; 9119702Slinton 9129702Slinton case REG: 91324418Smckusick putstr( rnames[p->tn.rval] ); 9149702Slinton return; 9159702Slinton 9169702Slinton default: 9179702Slinton cerror( "illegal conput" ); 9189702Slinton } 9199702Slinton } 9209702Slinton 92132923Sdonn /*ARGSUSED*/ 92232924Sdonn insput( p ) NODE *p; { 9239702Slinton cerror( "insput" ); 9249702Slinton } 9259702Slinton 92632928Sdonn upput( p, size ) NODE *p; int size; { 92732928Sdonn if( size == SZLONG && p->in.op == REG ) { 92832928Sdonn putstr( rnames[p->tn.rval + 1] ); 92932928Sdonn return; 93032928Sdonn } 9319702Slinton cerror( "upput" ); 9329702Slinton } 9339702Slinton 9349702Slinton adrput( p ) register NODE *p; { 9359702Slinton register int r; 9369702Slinton /* output an address, with offsets, from p */ 9379702Slinton 9389702Slinton if( p->in.op == FLD ){ 9399702Slinton p = p->in.left; 9409702Slinton } 9419702Slinton switch( p->in.op ){ 9429702Slinton 9439702Slinton case NAME: 9449702Slinton acon( p ); 9459702Slinton return; 9469702Slinton 9479702Slinton case ICON: 9489702Slinton /* addressable value of the constant */ 94924418Smckusick putchar( '$' ); 9509702Slinton acon( p ); 9519702Slinton return; 9529702Slinton 9539702Slinton case REG: 95424418Smckusick putstr( rnames[p->tn.rval] ); 9559702Slinton return; 9569702Slinton 9579702Slinton case OREG: 9589702Slinton r = p->tn.rval; 9599702Slinton if( R2TEST(r) ){ /* double indexing */ 9609702Slinton register int flags; 9619702Slinton 9629702Slinton flags = R2UPK3(r); 96324418Smckusick if( flags & 1 ) putchar('*'); 96424418Smckusick if( flags & 4 ) putchar('-'); 9659702Slinton if( p->tn.lval != 0 || p->in.name[0] != '\0' ) acon(p); 9669702Slinton if( R2UPK1(r) != 100) printf( "(%s)", rnames[R2UPK1(r)] ); 96724418Smckusick if( flags & 2 ) putchar('+'); 9689702Slinton printf( "[%s]", rnames[R2UPK2(r)] ); 9699702Slinton return; 9709702Slinton } 9719702Slinton if( r == AP ){ /* in the argument region */ 97232925Sdonn if( p->in.name[0] != '\0' ) werror( "bad arg temp" ); 9739702Slinton printf( CONFMT, p->tn.lval ); 97424418Smckusick putstr( "(ap)" ); 9759702Slinton return; 9769702Slinton } 9779702Slinton if( p->tn.lval != 0 || p->in.name[0] != '\0') acon( p ); 9789702Slinton printf( "(%s)", rnames[p->tn.rval] ); 9799702Slinton return; 9809702Slinton 9819702Slinton case UNARY MUL: 9829702Slinton /* STARNM or STARREG found */ 9839702Slinton if( tshape(p, STARNM) ) { 98424418Smckusick putchar( '*' ); 9859702Slinton adrput( p->in.left); 9869702Slinton } 9879702Slinton else { /* STARREG - really auto inc or dec */ 9889702Slinton register NODE *q; 9899702Slinton 99017659Sralph q = p->in.left; 99117742Sralph if( q->in.right->tn.lval != tlen(p) ) 99217742Sralph cerror("adrput: bad auto-increment/decrement"); 99317659Sralph printf("%s(%s)%s", (q->in.op==INCR ? "" : "-"), 99417659Sralph rnames[q->in.left->tn.rval], 99517659Sralph (q->in.op==INCR ? "+" : "") ); 9969702Slinton p->in.op = OREG; 99717659Sralph p->tn.rval = q->in.left->tn.rval; 99817659Sralph p->tn.lval = (q->in.op == INCR ? -q->in.right->tn.lval : 0); 9999702Slinton #ifndef FLEXNAMES 10009702Slinton p->in.name[0] = '\0'; 10019702Slinton #else 10029702Slinton p->in.name = ""; 10039702Slinton #endif 10049702Slinton tfree(q); 10059702Slinton } 10069702Slinton return; 10079702Slinton 10089702Slinton default: 10099702Slinton cerror( "illegal address" ); 10109702Slinton return; 10119702Slinton 10129702Slinton } 10139702Slinton 10149702Slinton } 10159702Slinton 10169702Slinton acon( p ) register NODE *p; { /* print out a constant */ 10179702Slinton 101832935Sdonn if( p->in.name[0] == '\0' ) 10199702Slinton printf( CONFMT, p->tn.lval); 102032935Sdonn else { 10219702Slinton #ifndef FLEXNAMES 10229702Slinton printf( "%.8s", p->in.name ); 10239702Slinton #else 102424418Smckusick putstr( p->in.name ); 10259702Slinton #endif 102632935Sdonn if( p->tn.lval != 0 ) { 102732935Sdonn putchar( '+' ); 102832935Sdonn printf( CONFMT, p->tn.lval ); 102932935Sdonn } 10309702Slinton } 10319702Slinton } 10329702Slinton 10339702Slinton genscall( p, cookie ) register NODE *p; { 10349702Slinton /* structure valued call */ 10359702Slinton return( gencall( p, cookie ) ); 10369702Slinton } 10379702Slinton 10389702Slinton /* tbl */ 10399702Slinton int gc_numbytes; 10409702Slinton /* tbl */ 10419702Slinton 104232924Sdonn /*ARGSUSED*/ 10439702Slinton gencall( p, cookie ) register NODE *p; { 10449702Slinton /* generate the call given by p */ 104516418Sralph register NODE *p1; 104632935Sdonn register int temp, temp1; 104732935Sdonn register int m; 10489702Slinton 10499702Slinton if( p->in.right ) temp = argsize( p->in.right ); 10509702Slinton else temp = 0; 10519702Slinton 10529702Slinton if( p->in.op == STCALL || p->in.op == UNARY STCALL ){ 10539702Slinton /* set aside room for structure return */ 10549702Slinton 10559702Slinton if( p->stn.stsize > temp ) temp1 = p->stn.stsize; 10569702Slinton else temp1 = temp; 10579702Slinton } 10589702Slinton 10599702Slinton if( temp > maxargs ) maxargs = temp; 10609702Slinton SETOFF(temp1,4); 10619702Slinton 10629702Slinton if( p->in.right ){ /* make temp node, put offset in, and generate args */ 106316418Sralph genargs( p->in.right ); 10649702Slinton } 10659702Slinton 10669702Slinton p1 = p->in.left; 10679702Slinton if( p1->in.op != ICON ){ 10689702Slinton if( p1->in.op != REG ){ 10699702Slinton if( p1->in.op != OREG || R2TEST(p1->tn.rval) ){ 10709702Slinton if( p1->in.op != NAME ){ 10719702Slinton order( p1, INAREG ); 10729702Slinton } 10739702Slinton } 10749702Slinton } 10759702Slinton } 10769702Slinton 10779702Slinton /* tbl 10789702Slinton setup gc_numbytes so reference to ZC works */ 10799702Slinton 10809702Slinton gc_numbytes = temp&(0x3ff); 10819702Slinton /* tbl */ 10829702Slinton 10839702Slinton p->in.op = UNARY CALL; 10849702Slinton m = match( p, INTAREG|INTBREG ); 10859702Slinton 10869702Slinton /* compensate for deficiency in 'ret' instruction ... wah,kre */ 10879702Slinton /* (plus in assignment to gc_numbytes above, for neatness only) */ 10889702Slinton if (temp >= 1024) 10899702Slinton printf(" addl2 $%d,sp\n", (temp&(~0x3ff))); 10909702Slinton 10919702Slinton return(m != MDONE); 10929702Slinton } 10939702Slinton 10949702Slinton /* tbl */ 10959702Slinton char * 10969702Slinton ccbranches[] = { 109732935Sdonn "eql", 109832935Sdonn "neq", 109932935Sdonn "leq", 110032935Sdonn "lss", 110132935Sdonn "geq", 110232935Sdonn "gtr", 110332935Sdonn "lequ", 110432935Sdonn "lssu", 110532935Sdonn "gequ", 110632935Sdonn "gtru", 11079702Slinton }; 11089702Slinton /* tbl */ 11099702Slinton 111032924Sdonn /*ARGSUSED*/ 11119702Slinton cbgen( o, lab, mode ) { /* printf conditional and unconditional branches */ 11129702Slinton 111332935Sdonn if( o != 0 && ( o < EQ || o > UGT ) ) 111432935Sdonn cerror( "bad conditional branch: %s", opst[o] ); 111532935Sdonn printf( " j%s L%d\n", o == 0 ? "br" : ccbranches[o-EQ], lab ); 11169702Slinton } 11179702Slinton 11189702Slinton nextcook( p, cookie ) NODE *p; { 11199702Slinton /* we have failed to match p with cookie; try another */ 11209702Slinton if( cookie == FORREW ) return( 0 ); /* hopeless! */ 11219702Slinton if( !(cookie&(INTAREG|INTBREG)) ) return( INTAREG|INTBREG ); 11229702Slinton if( !(cookie&INTEMP) && asgop(p->in.op) ) return( INTEMP|INAREG|INTAREG|INTBREG|INBREG ); 11239702Slinton return( FORREW ); 11249702Slinton } 11259702Slinton 112632924Sdonn /*ARGSUSED*/ 11279702Slinton lastchance( p, cook ) NODE *p; { 11289702Slinton /* forget it! */ 11299702Slinton return(0); 11309702Slinton } 11319702Slinton 11329702Slinton optim2( p ) register NODE *p; { 11339702Slinton /* do local tree transformations and optimizations */ 11349702Slinton 113532929Sdonn int o; 113632932Sdonn int i, mask; 113716181Sralph register NODE *l, *r; 11389702Slinton 113932929Sdonn switch( o = p->in.op ) { 11409702Slinton 11419702Slinton case AND: 114219933Smckusick /* commute L and R to eliminate complements and constants */ 114316181Sralph if( (l = p->in.left)->in.op == ICON && l->in.name[0] == 0 || 114416181Sralph l->in.op == COMPL ) { 11459702Slinton p->in.left = p->in.right; 114616181Sralph p->in.right = l; 11479702Slinton } 11489702Slinton case ASG AND: 11499702Slinton /* change meaning of AND to ~R&L - bic on pdp11 */ 11509702Slinton r = p->in.right; 115132931Sdonn if( r->in.op==ICON && r->in.name[0]==0 ) { 115232931Sdonn /* check for degenerate operations */ 115332931Sdonn l = p->in.left; 115432932Sdonn mask = (1 << tlen(l) * SZCHAR) - 1; 115532932Sdonn if( ISUNSIGNED(r->in.type) ) { 115632932Sdonn i = (r->tn.lval & mask); 115732932Sdonn if( i == mask ) { 115832932Sdonn r->in.op = FREE; 115932932Sdonn ncopy(p, l); 116032932Sdonn l->in.op = FREE; 116132932Sdonn break; 116232932Sdonn } 116332932Sdonn else if( i == 0 ) 116432932Sdonn goto zero; 116532932Sdonn else 116632932Sdonn r->tn.lval = i; 116732932Sdonn } 116832932Sdonn else if( r->tn.lval == mask && 116932932Sdonn tlen(l) < SZINT/SZCHAR ) { 117032932Sdonn r->in.op = SCONV; 117132932Sdonn r->in.left = l; 117232932Sdonn r->in.right = 0; 117332932Sdonn r->in.type = ENUNSIGN(l->in.type); 117432932Sdonn r->in.su = l->in.su > 1 ? l->in.su : 1; 117532932Sdonn ncopy(p, r); 117632932Sdonn p->in.left = r; 117732932Sdonn p->in.type = INT; 117832931Sdonn break; 117932931Sdonn } 118032931Sdonn /* complement constant */ 11819702Slinton r->tn.lval = ~r->tn.lval; 11829702Slinton } 11839702Slinton else if( r->in.op==COMPL ) { /* ~~A => A */ 11849702Slinton r->in.op = FREE; 11859702Slinton p->in.right = r->in.left; 11869702Slinton } 11879702Slinton else { /* insert complement node */ 118816181Sralph p->in.right = l = talloc(); 118916181Sralph l->in.op = COMPL; 119016181Sralph l->in.rall = NOPREF; 119116181Sralph l->in.type = r->in.type; 119216181Sralph l->in.left = r; 119316181Sralph l->in.right = NULL; 11949702Slinton } 11959702Slinton break; 11969702Slinton 119716181Sralph case SCONV: 119819933Smckusick l = p->in.left; 119917742Sralph #if defined(FORT) || defined(SPRECC) 120016573Sralph if( p->in.type == FLOAT || p->in.type == DOUBLE || 120119933Smckusick l->in.type == FLOAT || l->in.type == DOUBLE ) 120219933Smckusick return; 120316573Sralph #else 120419933Smckusick if( mixtypes(p, l) ) return; 120516573Sralph #endif 120632924Sdonn if( l->in.op == PCONV || l->in.op == CALL || l->in.op == UNARY CALL ) 120725751Sdonn return; 120825751Sdonn 120919933Smckusick /* Only trust it to get it right if the size is the same */ 121019933Smckusick if( tlen(p) != tlen(l) ) 121119933Smckusick return; 121216181Sralph 121316181Sralph /* clobber conversion */ 121419933Smckusick if( l->in.op != FLD ) 121516181Sralph l->in.type = p->in.type; 121616181Sralph ncopy( p, l ); 121716181Sralph l->in.op = FREE; 121819933Smckusick 121916181Sralph break; 122016181Sralph 122124418Smckusick case ASSIGN: 122224418Smckusick /* 122324418Smckusick * Conversions are equivalent to assignments; 122424418Smckusick * when the two operations are combined, 122524418Smckusick * we can sometimes zap the conversion. 122624418Smckusick */ 122724418Smckusick r = p->in.right; 122824418Smckusick l = p->in.left; 122924418Smckusick if ( r->in.op == SCONV && 123024418Smckusick !mixtypes(l, r) && 123132922Sdonn l->in.op != FLD && 123224418Smckusick tlen(l) == tlen(r) ) { 123324418Smckusick p->in.right = r->in.left; 123424418Smckusick r->in.op = FREE; 123524418Smckusick } 123624418Smckusick break; 123724418Smckusick 123832929Sdonn case ULE: 123932929Sdonn case ULT: 124032929Sdonn case UGE: 124132929Sdonn case UGT: 124232931Sdonn p->in.op -= (UGE-GE); 124332931Sdonn if( degenerate(p) ) 124432931Sdonn break; 124532931Sdonn p->in.op += (UGE-GE); 124632931Sdonn break; 124732931Sdonn 124832929Sdonn case EQ: 124932929Sdonn case NE: 125032929Sdonn case LE: 125132929Sdonn case LT: 125232929Sdonn case GE: 125332929Sdonn case GT: 125432931Sdonn (void) degenerate(p); 125532931Sdonn break; 125632931Sdonn 125732931Sdonn case DIV: 125832931Sdonn if( p->in.right->in.op == ICON && 125932931Sdonn p->in.right->tn.name[0] == '\0' && 126032931Sdonn ISUNSIGNED(p->in.right->in.type) && 126132931Sdonn (unsigned) p->in.right->tn.lval >= 0x80000000 ) { 126232931Sdonn /* easy to do here, harder to do in zzzcode() */ 126332931Sdonn p->in.op = UGE; 126432929Sdonn break; 126532931Sdonn } 126632931Sdonn case MOD: 126732931Sdonn case ASG DIV: 126832931Sdonn case ASG MOD: 126932931Sdonn /* 127032931Sdonn * optimize DIV and MOD 127132931Sdonn * 127232931Sdonn * basically we spot UCHAR and USHORT and try to do them 127332931Sdonn * as signed ints... apparently div+mul+sub is always 127432931Sdonn * faster than ediv for finding MOD on the VAX, when 127532931Sdonn * full unsigned MOD isn't needed. 127632931Sdonn * 127732931Sdonn * a curious fact: for MOD, cmp+sub and cmp+sub+cmp+sub 127832931Sdonn * are faster for unsigned dividend and a constant divisor 127932931Sdonn * in the right range (.5 to 1 of dividend's range for the 128032931Sdonn * first, .333+ to .5 for the second). full unsigned is 128132931Sdonn * already done cmp+sub in the appropriate case; the 128232931Sdonn * other cases are less common and require more ambition. 128332931Sdonn */ 128432931Sdonn if( degenerate(p) ) 128532929Sdonn break; 128632931Sdonn l = p->in.left; 128732931Sdonn r = p->in.right; 128832931Sdonn if( !ISUNSIGNED(r->in.type) || 128932931Sdonn tlen(l) >= SZINT/SZCHAR || 129032931Sdonn !(tlen(r) < SZINT/SZCHAR || 129132931Sdonn (r->in.op == ICON && r->tn.name[0] == '\0')) ) 129232929Sdonn break; 129332931Sdonn if( r->in.op == ICON ) 129432931Sdonn r->tn.type = INT; 129532931Sdonn else { 129632931Sdonn NODE *t = talloc(); 129732931Sdonn t->in.left = r; 129832931Sdonn r = t; 129932931Sdonn r->in.op = SCONV; 130032931Sdonn r->in.type = INT; 130132931Sdonn r->in.right = 0; 130232931Sdonn p->in.right = r; 130332931Sdonn } 130432931Sdonn if( o == DIV || o == MOD ) { 130532931Sdonn NODE *t = talloc(); 130632931Sdonn t->in.left = l; 130732931Sdonn l = t; 130832931Sdonn l->in.op = SCONV; 130932931Sdonn l->in.type = INT; 131032931Sdonn l->in.right = 0; 131132931Sdonn p->in.left = l; 131232931Sdonn } 131332931Sdonn /* handle asgops in table */ 131432931Sdonn break; 131532931Sdonn 131632931Sdonn case RS: 131732931Sdonn case ASG RS: 131832931Sdonn case LS: 131932931Sdonn case ASG LS: 132032931Sdonn /* pick up degenerate shifts */ 132132931Sdonn l = p->in.left; 132232931Sdonn r = p->in.right; 132332931Sdonn if( !(r->in.op == ICON && r->tn.name[0] == '\0') ) 132432929Sdonn break; 132532929Sdonn i = r->tn.lval; 132632931Sdonn if( i < 0 ) 132732931Sdonn /* front end 'fixes' this? */ 132832931Sdonn if( o == LS || o == ASG LS ) 132932931Sdonn o += (RS-LS); 133032931Sdonn else 133132931Sdonn o += (LS-RS); 133232931Sdonn if( (o == RS || o == ASG RS) && 133332931Sdonn !ISUNSIGNED(l->in.type) ) 133432931Sdonn /* can't optimize signed right shifts */ 133532929Sdonn break; 133632935Sdonn if( o == LS ) { 133732935Sdonn if( i < SZINT ) 133832935Sdonn break; 133932935Sdonn } 134032935Sdonn else { 134132935Sdonn if( i < tlen(l) * SZCHAR ) 134232935Sdonn break; 134332935Sdonn } 134432931Sdonn zero: 134532931Sdonn if( !asgop( o ) ) 134632931Sdonn if( tshape(l, SAREG|SNAME|SCON|SOREG|STARNM) ) { 134732931Sdonn /* no side effects */ 134832932Sdonn tfree(l); 134932931Sdonn ncopy(p, r); 135032931Sdonn r->in.op = FREE; 135132931Sdonn p->tn.lval = 0; 135232931Sdonn } 135332931Sdonn else { 135432931Sdonn p->in.op = COMOP; 135532932Sdonn r->tn.lval = 0; 135632931Sdonn } 135732931Sdonn else { 135832931Sdonn p->in.op = ASSIGN; 135932931Sdonn r->tn.lval = 0; 136032929Sdonn } 136132931Sdonn break; 136232931Sdonn } 136332931Sdonn } 136432931Sdonn 136532931Sdonn degenerate(p) register NODE *p; { 136632931Sdonn int o; 136732931Sdonn int result, i; 136832931Sdonn int lower, upper; 136932931Sdonn register NODE *l, *r; 137032931Sdonn 137132931Sdonn /* 137232931Sdonn * try to keep degenerate comparisons with constants 137332931Sdonn * out of the table. 137432931Sdonn */ 137532931Sdonn r = p->in.right; 137632931Sdonn l = p->in.left; 137732931Sdonn if( r->in.op != ICON || 137832931Sdonn r->tn.name[0] != '\0' || 137932931Sdonn tlen(l) >= tlen(r) ) 138032931Sdonn return (0); 138132931Sdonn switch( l->in.type ) { 138232931Sdonn case CHAR: 138332931Sdonn lower = -(1 << SZCHAR - 1); 138432931Sdonn upper = (1 << SZCHAR - 1) - 1; 138532931Sdonn break; 138632931Sdonn case UCHAR: 138732931Sdonn lower = 0; 138832931Sdonn upper = (1 << SZCHAR) - 1; 138932931Sdonn break; 139032931Sdonn case SHORT: 139132931Sdonn lower = -(1 << SZSHORT - 1); 139232931Sdonn upper = (1 << SZSHORT - 1) - 1; 139332931Sdonn break; 139432931Sdonn case USHORT: 139532931Sdonn lower = 0; 139632931Sdonn upper = (1 << SZSHORT) - 1; 139732931Sdonn break; 139832931Sdonn default: 139932932Sdonn cerror("unsupported type in degenerate()"); 140032931Sdonn } 140132931Sdonn i = r->tn.lval; 140232931Sdonn switch( o = p->in.op ) { 140332931Sdonn case DIV: 140432931Sdonn case ASG DIV: 140532931Sdonn case MOD: 140632931Sdonn case ASG MOD: 140732931Sdonn /* DIV and MOD work like EQ */ 140832931Sdonn case EQ: 140932931Sdonn case NE: 141032931Sdonn if( lower == 0 && (unsigned) i > upper ) 141132931Sdonn result = o == NE; 141232931Sdonn else if( i < lower || i > upper ) 141332931Sdonn result = o == NE; 141432931Sdonn else 141532931Sdonn return (0); 141632931Sdonn break; 141732931Sdonn case LT: 141832931Sdonn case GE: 141932931Sdonn if( lower == 0 && (unsigned) i > upper ) 142032931Sdonn result = o == LT; 142132931Sdonn else if( i <= lower ) 142232931Sdonn result = o != LT; 142332931Sdonn else if( i > upper ) 142432931Sdonn result = o == LT; 142532931Sdonn else 142632931Sdonn return (0); 142732931Sdonn break; 142832931Sdonn case LE: 142932931Sdonn case GT: 143032931Sdonn if( lower == 0 && (unsigned) i >= upper ) 143132931Sdonn result = o == LE; 143232931Sdonn else if( i < lower ) 143332931Sdonn result = o != LE; 143432931Sdonn else if( i >= upper ) 143532931Sdonn result = o == LE; 143632931Sdonn else 143732931Sdonn return (0); 143832931Sdonn break; 143932931Sdonn default: 144032931Sdonn cerror("unknown op in degenerate()"); 144132931Sdonn } 144232931Sdonn 144332931Sdonn if( o == MOD || o == ASG MOD ) { 144432931Sdonn r->in.op = FREE; 144532931Sdonn ncopy(p, l); 144632931Sdonn l->in.op = FREE; 144732931Sdonn } 144832931Sdonn else if( o != ASG DIV && tshape(l, SAREG|SNAME|SCON|SOREG|STARNM) ) { 144932931Sdonn /* no side effects */ 145032932Sdonn tfree(l); 145132931Sdonn ncopy(p, r); 145232931Sdonn r->in.op = FREE; 145332931Sdonn p->tn.lval = result; 145432931Sdonn } 145532931Sdonn else { 145632931Sdonn if( o == ASG DIV ) 145732931Sdonn p->in.op = ASSIGN; 145832929Sdonn else { 145932929Sdonn p->in.op = COMOP; 146032929Sdonn r->tn.type = INT; 146132929Sdonn } 146232931Sdonn r->tn.lval = result; 14639702Slinton } 146432931Sdonn if( logop(o) ) 146532931Sdonn p->in.type = INT; 146632931Sdonn 146732931Sdonn return (1); 14689702Slinton } 14699702Slinton 14709702Slinton /* added by jwf */ 14719702Slinton struct functbl { 14729702Slinton int fop; 14739702Slinton TWORD ftype; 14749702Slinton char *func; 14759702Slinton } opfunc[] = { 14769702Slinton DIV, TANY, "udiv", 14779702Slinton MOD, TANY, "urem", 147817715Sralph ASG DIV, TANY, "audiv", 147917715Sralph ASG MOD, TANY, "aurem", 14809702Slinton 0, 0, 0 }; 14819702Slinton 14829702Slinton hardops(p) register NODE *p; { 14839702Slinton /* change hard to do operators into function calls. */ 14849702Slinton register NODE *q; 14859702Slinton register struct functbl *f; 14869702Slinton register o; 148717742Sralph NODE *old,*temp; 14889702Slinton 14899702Slinton o = p->in.op; 149017742Sralph if( ! (optype(o)==BITYPE && 149117742Sralph (ISUNSIGNED(p->in.left->in.type) || 149217742Sralph ISUNSIGNED(p->in.right->in.type))) ) 149317742Sralph return; 14949702Slinton 14959702Slinton for( f=opfunc; f->fop; f++ ) { 14969702Slinton if( o==f->fop ) goto convert; 14979702Slinton } 14989702Slinton return; 14999702Slinton 15009702Slinton convert: 150132931Sdonn if( p->in.right->in.op == ICON && p->in.right->tn.name[0] == '\0' ) 150232928Sdonn /* 'J', 'K' in zzzcode() -- assumes DIV or MOD operations */ 150332928Sdonn /* save a subroutine call -- use at most 5 instructions */ 150432928Sdonn return; 150532931Sdonn if( tlen(p->in.left) < SZINT/SZCHAR && tlen(p->in.right) < SZINT/SZCHAR ) 150632931Sdonn /* optim2() will modify the op into an ordinary int op */ 150732931Sdonn return; 15089702Slinton if( asgop( o ) ) { 150917742Sralph old = NIL; 151017715Sralph switch( p->in.left->in.op ){ 151117742Sralph case FLD: 151217742Sralph q = p->in.left->in.left; 151317742Sralph /* 151417742Sralph * rewrite (lval.fld /= rval); as 151517742Sralph * ((*temp).fld = udiv((*(temp = &lval)).fld,rval)); 151617742Sralph * else the compiler will evaluate lval twice. 151717742Sralph */ 151817742Sralph if( q->in.op == UNARY MUL ){ 151917742Sralph /* first allocate a temp storage */ 152017742Sralph temp = talloc(); 152117742Sralph temp->in.op = OREG; 152217742Sralph temp->tn.rval = TMPREG; 152317742Sralph temp->tn.lval = BITOOR(freetemp(1)); 152417742Sralph temp->in.type = INCREF(p->in.type); 152517742Sralph #ifdef FLEXNAMES 152617742Sralph temp->in.name = ""; 152717742Sralph #else 152817742Sralph temp->in.name[0] = '\0'; 152917742Sralph #endif 153017742Sralph old = q->in.left; 153117742Sralph q->in.left = temp; 153217742Sralph } 153317742Sralph /* fall thru ... */ 153417742Sralph 153517715Sralph case REG: 153617715Sralph case NAME: 153717715Sralph case OREG: 153817715Sralph /* change ASG OP to a simple OP */ 153917715Sralph q = talloc(); 154017715Sralph q->in.op = NOASG p->in.op; 154117715Sralph q->in.rall = NOPREF; 154217715Sralph q->in.type = p->in.type; 154317715Sralph q->in.left = tcopy(p->in.left); 154417715Sralph q->in.right = p->in.right; 154517715Sralph p->in.op = ASSIGN; 154617715Sralph p->in.right = q; 154717715Sralph p = q; 154817715Sralph f -= 2; /* Note: this depends on the table order */ 154917742Sralph /* on the right side only - replace *temp with 155017742Sralph *(temp = &lval), build the assignment node */ 155117742Sralph if( old ){ 155217742Sralph temp = q->in.left->in.left; /* the "*" node */ 155317742Sralph q = talloc(); 155417742Sralph q->in.op = ASSIGN; 155517742Sralph q->in.left = temp->in.left; 155617742Sralph q->in.right = old; 155717742Sralph q->in.type = old->in.type; 155817742Sralph #ifdef FLEXNAMES 155917742Sralph q->in.name = ""; 156017742Sralph #else 156117742Sralph q->in.name[0] = '\0'; 156217742Sralph #endif 156317742Sralph temp->in.left = q; 156417742Sralph } 156517715Sralph break; 15669702Slinton 156717715Sralph case UNARY MUL: 156817715Sralph /* avoid doing side effects twice */ 156917715Sralph q = p->in.left; 157017715Sralph p->in.left = q->in.left; 157117715Sralph q->in.op = FREE; 157217715Sralph break; 157317715Sralph 157417715Sralph default: 157517715Sralph cerror( "hardops: can't compute & LHS" ); 157617715Sralph } 157717742Sralph } 157817715Sralph 15799702Slinton /* build comma op for args to function */ 15809702Slinton q = talloc(); 15819702Slinton q->in.op = CM; 15829702Slinton q->in.rall = NOPREF; 15839702Slinton q->in.type = INT; 15849702Slinton q->in.left = p->in.left; 15859702Slinton q->in.right = p->in.right; 15869702Slinton p->in.op = CALL; 15879702Slinton p->in.right = q; 15889702Slinton 15899702Slinton /* put function name in left node of call */ 15909702Slinton p->in.left = q = talloc(); 15919702Slinton q->in.op = ICON; 15929702Slinton q->in.rall = NOPREF; 15939702Slinton q->in.type = INCREF( FTN + p->in.type ); 15949702Slinton #ifndef FLEXNAMES 15959702Slinton strcpy( q->in.name, f->func ); 15969702Slinton #else 15979702Slinton q->in.name = f->func; 15989702Slinton #endif 15999702Slinton q->tn.lval = 0; 16009702Slinton q->tn.rval = 0; 16019702Slinton 16029702Slinton } 16039702Slinton 160417742Sralph zappost(p) NODE *p; { 160517742Sralph /* look for ++ and -- operators and remove them */ 160617742Sralph 160732935Sdonn register int o, ty; 160817742Sralph register NODE *q; 160917742Sralph o = p->in.op; 161017742Sralph ty = optype( o ); 161117742Sralph 161217742Sralph switch( o ){ 161317742Sralph 161417742Sralph case INCR: 161517742Sralph case DECR: 161617742Sralph q = p->in.left; 161717742Sralph p->in.right->in.op = FREE; /* zap constant */ 161817742Sralph ncopy( p, q ); 161917742Sralph q->in.op = FREE; 162017742Sralph return; 162117742Sralph 162217742Sralph } 162317742Sralph 162417742Sralph if( ty == BITYPE ) zappost( p->in.right ); 162517742Sralph if( ty != LTYPE ) zappost( p->in.left ); 162617742Sralph } 162717742Sralph 162817742Sralph fixpre(p) NODE *p; { 162917742Sralph 163032935Sdonn register int o, ty; 163117742Sralph o = p->in.op; 163217742Sralph ty = optype( o ); 163317742Sralph 163417742Sralph switch( o ){ 163517742Sralph 163617742Sralph case ASG PLUS: 163717742Sralph p->in.op = PLUS; 163817742Sralph break; 163917742Sralph case ASG MINUS: 164017742Sralph p->in.op = MINUS; 164117742Sralph break; 164217742Sralph } 164317742Sralph 164417742Sralph if( ty == BITYPE ) fixpre( p->in.right ); 164517742Sralph if( ty != LTYPE ) fixpre( p->in.left ); 164617742Sralph } 164717742Sralph 164832935Sdonn /*ARGSUSED*/ 164932935Sdonn NODE * addroreg(l) NODE *l; 165032935Sdonn /* OREG was built in clocal() 165132935Sdonn * for an auto or formal parameter 165232935Sdonn * now its address is being taken 165332935Sdonn * local code must unwind it 165432935Sdonn * back to PLUS/MINUS REG ICON 165532935Sdonn * according to local conventions 165632935Sdonn */ 165732935Sdonn { 165832935Sdonn cerror("address of OREG taken"); 165932935Sdonn /*NOTREACHED*/ 166032935Sdonn } 166132935Sdonn 166232935Sdonn 166332935Sdonn 166432935Sdonn # ifndef ONEPASS 166532935Sdonn main( argc, argv ) char *argv[]; { 166632935Sdonn return( mainp2( argc, argv ) ); 166732935Sdonn } 166832935Sdonn # endif 166932935Sdonn 167024418Smckusick strip(p) register NODE *p; { 167124418Smckusick NODE *q; 167224418Smckusick 167324418Smckusick /* strip nodes off the top when no side effects occur */ 167424418Smckusick for( ; ; ) { 167524418Smckusick switch( p->in.op ) { 167624418Smckusick case SCONV: /* remove lint tidbits */ 167724418Smckusick q = p->in.left; 167824418Smckusick ncopy( p, q ); 167924418Smckusick q->in.op = FREE; 168024418Smckusick break; 168124418Smckusick /* could probably add a few more here */ 168224418Smckusick default: 168324418Smckusick return; 168424418Smckusick } 168524418Smckusick } 168624418Smckusick } 168724418Smckusick 16889702Slinton myreader(p) register NODE *p; { 168924418Smckusick strip( p ); /* strip off operations with no side effects */ 169017742Sralph canon( p ); /* expands r-vals for fields */ 16919702Slinton walkf( p, hardops ); /* convert ops to function calls */ 16929702Slinton walkf( p, optim2 ); 16939702Slinton } 1694