132890Sdonn #ifndef lint 2*33351Sdonn static char sccsid[] = "@(#)local2.c 1.29 (Berkeley) 01/14/88"; 332890Sdonn #endif 425828Ssam 526076Ssam # include "pass2.h" 626076Ssam # include <ctype.h> 726162Ssam 826162Ssam # define putstr(s) fputs((s), stdout) 929672Ssam # define ISCHAR(p) (p->in.type == UCHAR || p->in.type == CHAR) 1026162Ssam 1125828Ssam # ifdef FORT 1225828Ssam int ftlab1, ftlab2; 1325828Ssam # endif 1425828Ssam /* a lot of the machine dependent parts of the second pass */ 1525828Ssam 1625828Ssam # define BITMASK(n) ((1L<<n)-1) 1725828Ssam 1825828Ssam # ifndef ONEPASS 1932886Sdonn /*ARGSUSED*/ 2025828Ssam where(c){ 2125828Ssam fprintf( stderr, "%s, line %d: ", filename, lineno ); 2225828Ssam } 2325828Ssam # endif 2425828Ssam 2525828Ssam lineid( l, fn ) char *fn; { 2625828Ssam /* identify line l and file fn */ 2725828Ssam printf( "# line %d, file %s\n", l, fn ); 2825828Ssam } 2925828Ssam 3025828Ssam int ent_mask; 3125828Ssam 3225828Ssam eobl2(){ 3325828Ssam register OFFSZ spoff; /* offset from stack pointer */ 3425828Ssam #ifndef FORT 3525828Ssam extern int ftlab1, ftlab2; 3625828Ssam #endif 3725828Ssam 3825828Ssam spoff = maxoff; 3925828Ssam spoff /= SZCHAR; 4025828Ssam SETOFF(spoff,4); 4125828Ssam #ifdef FORT 4225828Ssam #ifndef FLEXNAMES 4332886Sdonn printf( " .set .F%d,%ld\n", ftnno, spoff ); 4425828Ssam #else 4525828Ssam /* SHOULD BE L%d ... ftnno but must change pc/f77 */ 4632886Sdonn printf( " .set LF%d,%ld\n", ftnno, spoff ); 4725828Ssam #endif 4825828Ssam printf( " .set LWM%d,0x%x\n", ftnno, ent_mask&0x1ffc|0x1000); 4925828Ssam #else 5025828Ssam printf( " .set L%d,0x%x\n", ftnno, ent_mask&0x1ffc); 5125828Ssam printf( "L%d:\n", ftlab1); 5225828Ssam if( maxoff > AUTOINIT ) 5332886Sdonn printf( " subl3 $%ld,fp,sp\n", spoff); 5425828Ssam printf( " jbr L%d\n", ftlab2); 5525828Ssam #endif 5625828Ssam ent_mask = 0; 5725828Ssam maxargs = -1; 5825828Ssam } 5925828Ssam 6025828Ssam struct hoptab { int opmask; char * opstring; } ioptab[] = { 6125828Ssam 6225828Ssam PLUS, "add", 6325828Ssam MINUS, "sub", 6425828Ssam MUL, "mul", 6525828Ssam DIV, "div", 6625828Ssam MOD, "div", 6725828Ssam OR, "or", 6825828Ssam ER, "xor", 6925828Ssam AND, "and", 7025828Ssam -1, "" }; 7125828Ssam 7225828Ssam hopcode( f, o ){ 7325828Ssam /* output the appropriate string from the above table */ 7425828Ssam 7525828Ssam register struct hoptab *q; 7625828Ssam 7725828Ssam if(asgop(o)) 7825828Ssam o = NOASG o; 7925828Ssam for( q = ioptab; q->opmask>=0; ++q ){ 8025828Ssam if( q->opmask == o ){ 8125828Ssam if(f == 'E') 8225828Ssam printf( "e%s", q->opstring); 8325828Ssam else 8425828Ssam printf( "%s%c", q->opstring, tolower(f)); 8525828Ssam return; 8625828Ssam } 8725828Ssam } 8825828Ssam cerror( "no hoptab for %s", opst[o] ); 8925828Ssam } 9025828Ssam 9125828Ssam char * 9225828Ssam rnames[] = { /* keyed to register number tokens */ 9325828Ssam 9425828Ssam "r0", "r1", 9525828Ssam "r2", "r3", "r4", "r5", 9625828Ssam "r6", "r7", "r8", "r9", "r10", "r11", 9725828Ssam "r12", "fp", "sp", "pc", 9825828Ssam }; 9925828Ssam 10025828Ssam /* output register name and update entry mask */ 10125828Ssam char * 10225828Ssam rname(r) 10325828Ssam register int r; 10425828Ssam { 10525828Ssam 10632887Sdonn if (!istreg(r)) 10732887Sdonn ent_mask |= 1<<r; 10825828Ssam return(rnames[r]); 10925828Ssam } 11025828Ssam 11125828Ssam int rstatus[] = { 11225828Ssam SAREG|STAREG, SAREG|STAREG, 11325828Ssam SAREG|STAREG, SAREG|STAREG, SAREG|STAREG, SAREG|STAREG, 11425828Ssam SAREG, SAREG, SAREG, SAREG, SAREG, SAREG, 11525828Ssam SAREG, SAREG, SAREG, SAREG, 11625828Ssam }; 11725828Ssam 11825828Ssam tlen(p) NODE *p; 11925828Ssam { 12025828Ssam switch(p->in.type) { 12125828Ssam case CHAR: 12225828Ssam case UCHAR: 12325828Ssam return(1); 12425828Ssam 12525828Ssam case SHORT: 12625828Ssam case USHORT: 12732886Sdonn return(SZSHORT/SZCHAR); 12825828Ssam 12925828Ssam case DOUBLE: 13032886Sdonn return(SZDOUBLE/SZCHAR); 13125828Ssam 13225828Ssam default: 13332886Sdonn return(SZINT/SZCHAR); 13425828Ssam } 13525828Ssam } 13625828Ssam 13732886Sdonn mixtypes(p, q) NODE *p, *q; 13830360Ssam { 13930360Ssam register TWORD tp, tq; 14030360Ssam 14130360Ssam tp = p->in.type; 14230360Ssam tq = q->in.type; 14332886Sdonn 14432886Sdonn return( (tp==FLOAT || tp==DOUBLE) != 14532886Sdonn (tq==FLOAT || tq==DOUBLE) ); 14630360Ssam } 14730360Ssam 14825828Ssam prtype(n) NODE *n; 14925828Ssam { 15025828Ssam switch (n->in.type) 15125828Ssam { 15225828Ssam 15325828Ssam case DOUBLE: 15426162Ssam putchar('d'); 15525828Ssam return; 15625828Ssam 15725828Ssam case FLOAT: 15826162Ssam putchar('f'); 15925828Ssam return; 16025828Ssam 16132886Sdonn case LONG: 16232886Sdonn case ULONG: 16325828Ssam case INT: 16425828Ssam case UNSIGNED: 16526162Ssam putchar('l'); 16625828Ssam return; 16725828Ssam 16825828Ssam case SHORT: 16925828Ssam case USHORT: 17026162Ssam putchar('w'); 17125828Ssam return; 17225828Ssam 17325828Ssam case CHAR: 17425828Ssam case UCHAR: 17526162Ssam putchar('b'); 17625828Ssam return; 17725828Ssam 17825828Ssam default: 17925828Ssam if ( !ISPTR( n->in.type ) ) cerror("zzzcode- bad type"); 18025828Ssam else { 18126162Ssam putchar('l'); 18225828Ssam return; 18325828Ssam } 18425828Ssam } 18525828Ssam } 18625828Ssam 18725828Ssam zzzcode( p, c ) register NODE *p; { 18825828Ssam register int m; 18925828Ssam int val; 19025828Ssam switch( c ){ 19125828Ssam 19225828Ssam case 'N': /* logical ops, turned into 0-1 */ 19325828Ssam /* use register given by register 1 */ 19425828Ssam cbgen( 0, m=getlab(), 'I' ); 19525828Ssam deflab( p->bn.label ); 19625828Ssam printf( " clrl %s\n", rname(getlr( p, '1' )->tn.rval) ); 19725828Ssam deflab( m ); 19825828Ssam return; 19925828Ssam 20025828Ssam case 'P': 20125828Ssam cbgen( p->in.op, p->bn.label, c ); 20225828Ssam return; 20325828Ssam 20432876Sdonn case 'G': /* i *= f; asgops with int lhs and float rhs */ 20525828Ssam { 20632876Sdonn register NODE *l, *r, *s; 20732876Sdonn int lt, rt; 20825828Ssam 20932876Sdonn l = p->in.left; 21032876Sdonn r = p->in.right; 21132876Sdonn s = talloc(); 21232876Sdonn rt = r->in.type; 21332876Sdonn lt = l->in.type; 21425828Ssam 21532876Sdonn if (lt != INT && lt != UNSIGNED) { 21632876Sdonn s->in.op = SCONV; 21732876Sdonn s->in.left = l; 21832876Sdonn s->in.type = ISUNSIGNED(lt) ? UNSIGNED : INT; 21932876Sdonn zzzcode(s, 'U'); 22032876Sdonn putstr("\n\t"); 22125828Ssam } 22232876Sdonn 22332876Sdonn if (ISUNSIGNED(lt)) { 22432876Sdonn s->in.op = SCONV; 22532876Sdonn s->in.left = lt == UNSIGNED ? l : resc; 22632876Sdonn s->in.type = rt; 22732876Sdonn unsigned_to_float(s); 22832876Sdonn } else { 22932876Sdonn putstr("cvl"); 23032876Sdonn prtype(r); 23132876Sdonn putchar('\t'); 23232876Sdonn adrput(lt == INT ? l : resc); 23332876Sdonn } 23432876Sdonn putstr("\n\t"); 23532876Sdonn 23632876Sdonn hopcode(rt == FLOAT ? 'F' : 'D', p->in.op); 23726162Ssam putchar('\t'); 23825828Ssam adrput(r); 23932876Sdonn 24032876Sdonn if (ISUNSIGNED(lt)) { 24132876Sdonn putstr("\n\t"); 24232876Sdonn s->in.op = SCONV; 24332876Sdonn s->in.left = r; /* we need only the type */ 24432876Sdonn s->in.type = UNSIGNED; 24532876Sdonn float_to_unsigned(s); 24632876Sdonn } else { 24732876Sdonn putstr("\n\tcv"); 24832876Sdonn prtype(r); 24932876Sdonn putstr("l\t"); 25032876Sdonn if (lt == INT) 25132876Sdonn adrput(l); 25232876Sdonn else 25332876Sdonn adrput(resc); 25432876Sdonn } 25532876Sdonn if (lt != INT) { 25632876Sdonn putstr("\n\t"); 25732876Sdonn s->in.op = ASSIGN; 25832876Sdonn s->in.left = l; 25932876Sdonn s->in.right = resc; 26032876Sdonn s->in.type = lt; 26132876Sdonn zzzcode(s, 'U'); 26232876Sdonn } 26332876Sdonn 26432876Sdonn s->in.op = FREE; 26525828Ssam return; 26625828Ssam } 26725828Ssam 26832886Sdonn case 'J': /* unsigned DIV/MOD with constant divisors */ 26932886Sdonn { 27032886Sdonn register int ck = INAREG; 27132886Sdonn int label1, label2; 27232886Sdonn 27332886Sdonn /* case constant <= 1 is handled by optim() in pass 1 */ 27432886Sdonn /* case constant < 0x80000000 is handled in table */ 27532886Sdonn switch( p->in.op ) { 27632887Sdonn /* case DIV: handled in optim2() */ 27732886Sdonn case MOD: 27832886Sdonn if( p->in.left->in.op == REG && 27932886Sdonn p->in.left->tn.rval == resc->tn.rval ) 28032886Sdonn goto asgmod; 28132886Sdonn label1 = getlab(); 28232886Sdonn expand(p, ck, "movl\tAL,A1\n\tcmpl\tA1,AR\n"); 28332886Sdonn printf("\tjlssu\tL%d\n", label1); 28432886Sdonn expand(p, ck, "\tsubl2\tAR,A1\n"); 28532886Sdonn printf("L%d:", label1); 28632886Sdonn break; 28732886Sdonn case ASG DIV: 28832886Sdonn label1 = getlab(); 28932886Sdonn label2 = getlab(); 29032886Sdonn expand(p, ck, "cmpl\tAL,AR\n"); 29132886Sdonn printf("\tjgequ\tL%d\n", label1); 29232886Sdonn expand(p, ck, "\tmovl\t$1,AL\n"); 29332886Sdonn printf("\tjbr\tL%d\nL%d:\n", label2, label1); 29432886Sdonn expand(p, ck, "\tclrl\tAL\n"); 29532886Sdonn printf("L%d:", label2); 29632886Sdonn break; 29732886Sdonn case ASG MOD: 29832886Sdonn asgmod: 29932886Sdonn label1 = getlab(); 30032886Sdonn expand(p, ck, "cmpl\tAL,AR\n"); 30132886Sdonn printf("\tjlssu\tL%d\n", label1); 30232886Sdonn expand(p, ck, "\tsubl2\tAR,AL\n"); 30332886Sdonn printf("L%d:", label1); 30432886Sdonn break; 30532886Sdonn } 30632886Sdonn return; 30732886Sdonn } 30832886Sdonn 30925828Ssam case 'B': /* get oreg value in temp register for shift */ 31025828Ssam { 31125828Ssam register NODE *r; 31225828Ssam if (xdebug) eprint(p, 0, &val, &val); 31325828Ssam r = p->in.right; 31432886Sdonn if( tlen(r) == SZINT/SZCHAR && r->in.type != FLOAT ) 31526162Ssam putstr("movl"); 31625828Ssam else { 31726162Ssam putstr(ISUNSIGNED(r->in.type) ? "movz" : "cvt"); 31825828Ssam prtype(r); 31926162Ssam putchar('l'); 32025828Ssam } 32125828Ssam return; 32225828Ssam } 32325828Ssam 32432886Sdonn case 'C': /* generate 'call[fs] $bytes' */ 32525828Ssam { 32625828Ssam extern int gc_numbytes; 32725828Ssam extern int xdebug; 32825828Ssam 32925828Ssam if (xdebug) printf("->%d<-",gc_numbytes); 33025828Ssam 33125828Ssam printf("call%c $%d", 33225828Ssam (p->in.left->in.op==ICON && gc_numbytes<60)?'f':'s', 33325828Ssam gc_numbytes+4); 33432886Sdonn /* don't change to double (here's the only place to catch it) */ 33525828Ssam if(p->in.type == FLOAT) 33625828Ssam rtyflg = 1; 33725828Ssam return; 33825828Ssam } 33925828Ssam 34025828Ssam case 'D': /* INCR and DECR */ 34132876Sdonn zzzcode(p->in.left, 'U'); 34226162Ssam putstr("\n "); 34325828Ssam 34425828Ssam case 'E': /* INCR and DECR, FOREFF */ 34525828Ssam if (p->in.right->tn.lval == 1) 34625828Ssam { 34726162Ssam putstr(p->in.op == INCR ? "inc" : "dec"); 34825828Ssam prtype(p->in.left); 34926162Ssam putchar('\t'); 35025828Ssam adrput(p->in.left); 35125828Ssam return; 35225828Ssam } 35326162Ssam putstr(p->in.op == INCR ? "add" : "sub"); 35425828Ssam prtype(p->in.left); 35526162Ssam putstr("2 "); 35625828Ssam adrput(p->in.right); 35726162Ssam putchar(','); 35825828Ssam adrput(p->in.left); 35925828Ssam return; 36025828Ssam 36125828Ssam case 'F': /* masked constant for fields */ 36225947Ssam printf(ACONFMT, (p->in.right->tn.lval&((1<<fldsz)-1))<<fldshf); 36325828Ssam return; 36425828Ssam 36532884Sdonn case 'I': /* produce value of bitfield assignment */ 36632884Sdonn /* avoid shifts -- shifts are SLOW on this machine */ 36732887Sdonn /* XXX this wouldn't be necessary if we were smarter 36832887Sdonn and masked BEFORE shifting XXX */ 36932884Sdonn { 37032886Sdonn register NODE *r = p->in.right; 37132886Sdonn if(r->in.op == ICON && r->tn.name[0] == '\0') { 37232886Sdonn putstr("movl\t"); 37332886Sdonn printf(ACONFMT, r->tn.lval & ((1<<fldsz)-1)); 37432886Sdonn } 37532886Sdonn else { 37632886Sdonn putstr("andl3\t"); 37732886Sdonn printf(ACONFMT, (1 << fldsz) - 1); 37832884Sdonn putchar(','); 37932886Sdonn adrput(r); 38032884Sdonn } 38132886Sdonn putchar(','); 38232886Sdonn adrput(resc); 38332886Sdonn break; 38432886Sdonn } 38532884Sdonn 38625828Ssam case 'H': /* opcode for shift */ 38725828Ssam if(p->in.op == LS || p->in.op == ASG LS) 38826162Ssam putstr("shll"); 38925828Ssam else if(ISUNSIGNED(p->in.left->in.type)) 39026162Ssam putstr("shrl"); 39125828Ssam else 39226162Ssam putstr("shar"); 39325828Ssam return; 39425828Ssam 39525828Ssam case 'L': /* type of left operand */ 39625828Ssam case 'R': /* type of right operand */ 39725828Ssam { 39825828Ssam register NODE *n; 39925828Ssam extern int xdebug; 40025828Ssam 40125828Ssam n = getlr ( p, c); 40225828Ssam if (xdebug) printf("->%d<-", n->in.type); 40325828Ssam 40425828Ssam prtype(n); 40525828Ssam return; 40625828Ssam } 40725828Ssam 40830360Ssam case 'M': { /* initiate ediv for mod and unsigned div */ 40932887Sdonn putstr("clrl\t"); 41032887Sdonn adrput(resc); 41132887Sdonn putstr("\n\tmovl\t"); 41225828Ssam adrput(p->in.left); 41332887Sdonn putchar(','); 41432887Sdonn upput(resc, SZLONG); 41532887Sdonn printf("\n\tjgeq\tL%d\n\tmnegl\t$1,", m = getlab()); 41632887Sdonn adrput(resc); 41732887Sdonn putchar('\n'); 41832887Sdonn deflab(m); 41925828Ssam return; 42030360Ssam } 42125828Ssam 42230360Ssam case 'T': { /* rounded structure length for arguments */ 42330360Ssam int size = p->stn.stsize; 42425828Ssam SETOFF( size, 4); 42525828Ssam printf("movab -%d(sp),sp", size); 42625828Ssam return; 42730360Ssam } 42825828Ssam 42925828Ssam case 'S': /* structure assignment */ 43025977Ssam stasg(p); 43125977Ssam break; 43225828Ssam 43332886Sdonn #ifdef I_don_t_understand_this 43429672Ssam case 'X': /* multiplication for short and char */ 43529672Ssam if (ISUNSIGNED(p->in.left->in.type)) 43629672Ssam printf("\tmovz"); 43729672Ssam else 43829672Ssam printf("\tcvt"); 43929672Ssam zzzcode(p, 'L'); 44029672Ssam printf("l\t"); 44129672Ssam adrput(p->in.left); 44229672Ssam printf(","); 44329672Ssam adrput(&resc[0]); 44429672Ssam printf("\n"); 44529672Ssam if (ISUNSIGNED(p->in.right->in.type)) 44629672Ssam printf("\tmovz"); 44729672Ssam else 44829672Ssam printf("\tcvt"); 44929672Ssam zzzcode(p, 'R'); 45029672Ssam printf("l\t"); 45129672Ssam adrput(p->in.right); 45229672Ssam printf(","); 45329672Ssam adrput(&resc[1]); 45429672Ssam printf("\n"); 45529672Ssam return; 45632886Sdonn #endif 45729672Ssam 45830360Ssam case 'U': /* SCONV */ 45930360Ssam case 'V': /* SCONV with FORCC */ 46030360Ssam sconv(p, c == 'V'); 46130360Ssam break; 46230360Ssam 46332879Sdonn case 'W': { /* SCONV or ASSIGN float/double => unsigned */ 46432879Sdonn NODE *src = p->in.op == SCONV ? p->in.left : p->in.right; 46532879Sdonn 46632876Sdonn putstr("ld"); 46732879Sdonn prtype(src); 46832876Sdonn putchar('\t'); 46932879Sdonn adrput(src); 47032876Sdonn putstr("\n\t"); 47132876Sdonn float_to_unsigned(p); 47232876Sdonn break; 47332879Sdonn } 47432876Sdonn 47532879Sdonn case 'Y': /* SCONV or ASSIGN unsigned => float/double */ 47632876Sdonn unsigned_to_float(p); /* stores into accumulator */ 47732876Sdonn putstr("\n\tst"); 47832876Sdonn prtype(p); 47932876Sdonn putchar('\t'); 48032879Sdonn if (p->in.op == SCONV) 48132879Sdonn adrput(resc); 48232879Sdonn else 48332879Sdonn adrput(p->in.left); 48432879Sdonn rtyflg = 1; 48532876Sdonn break; 48632876Sdonn 48732886Sdonn #ifdef I_don_t_understand_this 48830360Ssam case 'Z': 48930360Ssam p = p->in.right; 49030360Ssam switch (p->in.type) { 49130360Ssam case SHORT: { 49230360Ssam short w = p->tn.lval; 49330360Ssam p->tn.lval = w; 49430360Ssam break; 49530360Ssam } 49630360Ssam case CHAR: { 49730360Ssam char c = p->tn.lval; 49830360Ssam p->tn.lval = c; 49930360Ssam break; 50030360Ssam } 50130360Ssam } 50230360Ssam printf("$%d", p->tn.lval); 50330360Ssam break; 50432886Sdonn #endif 50530360Ssam 50625977Ssam default: 50725977Ssam cerror( "illegal zzzcode" ); 50825977Ssam } 50930360Ssam } 51025828Ssam 51125977Ssam #define MOVB(dst, src, off) { \ 51226162Ssam putstr("\tmovb\t"); upput(src, off); putchar(','); \ 51325977Ssam upput(dst, off); putchar('\n'); \ 51425977Ssam } 51525977Ssam #define MOVW(dst, src, off) { \ 51626162Ssam putstr("\tmovw\t"); upput(src, off); putchar(','); \ 51725977Ssam upput(dst, off); putchar('\n'); \ 51825977Ssam } 51925977Ssam #define MOVL(dst, src, off) { \ 52026162Ssam putstr("\tmovl\t"); upput(src, off); putchar(','); \ 52125977Ssam upput(dst, off); putchar('\n'); \ 52225977Ssam } 52325977Ssam /* 52425977Ssam * Generate code for a structure assignment. 52525977Ssam */ 52625977Ssam stasg(p) 52725977Ssam register NODE *p; 52825977Ssam { 52925977Ssam register NODE *l, *r; 53025977Ssam register int size; 53125828Ssam 53225977Ssam switch (p->in.op) { 53325977Ssam case STASG: /* regular assignment */ 53425977Ssam l = p->in.left; 53525977Ssam r = p->in.right; 53625977Ssam break; 53725977Ssam case STARG: /* place arg on the stack */ 53825977Ssam l = getlr(p, '3'); 53925977Ssam r = p->in.left; 54025977Ssam break; 54125977Ssam default: 54225977Ssam cerror("STASG bad"); 54325977Ssam /*NOTREACHED*/ 54425977Ssam } 54525977Ssam /* 54625977Ssam * Pun source for use in code generation. 54725977Ssam */ 54825977Ssam switch (r->in.op) { 54925977Ssam case ICON: 55025977Ssam r->in.op = NAME; 55125977Ssam break; 55225977Ssam case REG: 55325977Ssam r->in.op = OREG; 55425977Ssam break; 55525977Ssam default: 55625977Ssam cerror( "STASG-r" ); 55725977Ssam /*NOTREACHED*/ 55825977Ssam } 55925977Ssam size = p->stn.stsize; 56025977Ssam if (size <= 0 || size > 65535) 56125977Ssam cerror("structure size out of range"); 56225977Ssam /* 56325977Ssam * Generate optimized code based on structure size 56425977Ssam * and alignment properties.... 56525977Ssam */ 56625977Ssam switch (size) { 56725828Ssam 56825977Ssam case 1: 56926162Ssam putstr("\tmovb\t"); 57025977Ssam optimized: 57125977Ssam adrput(r); 57226162Ssam putchar(','); 57325977Ssam adrput(l); 57426162Ssam putchar('\n'); 57525977Ssam break; 57625828Ssam 57725977Ssam case 2: 57825977Ssam if (p->stn.stalign != 2) { 57925977Ssam MOVB(l, r, SZCHAR); 58026162Ssam putstr("\tmovb\t"); 58125977Ssam } else 58226162Ssam putstr("\tmovw\t"); 58325977Ssam goto optimized; 58425977Ssam 58525977Ssam case 4: 58625977Ssam if (p->stn.stalign != 4) { 58725977Ssam if (p->stn.stalign != 2) { 58825977Ssam MOVB(l, r, 3*SZCHAR); 58925977Ssam MOVB(l, r, 2*SZCHAR); 59025977Ssam MOVB(l, r, 1*SZCHAR); 59126162Ssam putstr("\tmovb\t"); 59225947Ssam } else { 59325977Ssam MOVW(l, r, SZSHORT); 59426162Ssam putstr("\tmovw\t"); 59525828Ssam } 59625977Ssam } else 59726162Ssam putstr("\tmovl\t"); 59825977Ssam goto optimized; 59925828Ssam 60025977Ssam case 6: 60125977Ssam if (p->stn.stalign != 2) 60225977Ssam goto movblk; 60325977Ssam MOVW(l, r, 2*SZSHORT); 60425977Ssam MOVW(l, r, 1*SZSHORT); 60526162Ssam putstr("\tmovw\t"); 60625977Ssam goto optimized; 60725977Ssam 60825977Ssam case 8: 60925977Ssam if (p->stn.stalign == 4) { 61025977Ssam MOVL(l, r, SZLONG); 61126162Ssam putstr("\tmovl\t"); 61225977Ssam goto optimized; 61325977Ssam } 61425977Ssam /* fall thru...*/ 61525977Ssam 61625977Ssam default: 61725977Ssam movblk: 61825977Ssam /* 61925977Ssam * Can we ever get a register conflict with R1 here? 62025977Ssam */ 62126162Ssam putstr("\tmovab\t"); 62232890Sdonn if(r->in.op == OREG && r->tn.rval == R1) 62332890Sdonn { 62432890Sdonn adrput(r); 62532890Sdonn printf(",r0\n\tmovab\t"); 62632890Sdonn adrput(l); 62732890Sdonn putstr(",r1\n"); 62832890Sdonn } 62932890Sdonn else 63032890Sdonn { 63132890Sdonn adrput(l); 63232890Sdonn putstr(",r1\n\tmovab\t"); 63332890Sdonn adrput(r); 63432890Sdonn printf(",r0\n"); 63532890Sdonn } 63632890Sdonn printf("\tmovl\t$%d,r2\n\tmovblk\n", size); 63725977Ssam rname(R2); 63825828Ssam break; 63925977Ssam } 64025977Ssam /* 64125977Ssam * Reverse above pun for reclaim. 64225977Ssam */ 64325977Ssam if (r->in.op == NAME) 64425977Ssam r->in.op = ICON; 64525977Ssam else if (r->in.op == OREG) 64625977Ssam r->in.op = REG; 64725977Ssam } 64825828Ssam 64925977Ssam /* 65032876Sdonn * Convert a float or double in the accumulator into an unsigned int. 65132876Sdonn * Unlike the vax, the tahoe stores 0 into the destination 65232876Sdonn * on a conversion of > 2 ** 31, so we compensate. 65332876Sdonn */ 65432876Sdonn float_to_unsigned(p) 65532876Sdonn NODE *p; 65632876Sdonn { 65732876Sdonn register NODE *l = p->in.left; 65832876Sdonn int label1 = getlab(); 65932876Sdonn int label2 = getlab(); 66032876Sdonn int label3 = getlab(); 66132879Sdonn NODE *src, *dst; 66232876Sdonn 66332879Sdonn if (p->in.op == SCONV) { 66432879Sdonn src = p->in.left; 66532879Sdonn dst = resc; 66632879Sdonn } else { 66732879Sdonn src = p->in.right; 66832879Sdonn dst = p->in.left; 66932879Sdonn } 67032879Sdonn 67132876Sdonn printf(".data\n\t.align\t2\nL%d:\n\t.long\t0x50000000", label1); 67232879Sdonn if (src->in.type == DOUBLE) 67332879Sdonn putstr(", 0x00000000 # .double"); 67432879Sdonn else 67532879Sdonn putstr(" # .float"); 67632879Sdonn putstr(" 2147483648\n\t.text\n\tcmp"); 67732879Sdonn prtype(src); 67832876Sdonn printf("\tL%d\n\tjlss\tL%d\n\tsub", label1, label2); 67932879Sdonn prtype(src); 68032876Sdonn printf("\tL%d\n\tcv", label1); 68132879Sdonn prtype(src); 68232876Sdonn putstr("l\t"); 68332879Sdonn adrput(dst); 68432876Sdonn putstr("\n\taddl2\t$-2147483648,"); 68532879Sdonn adrput(dst); 68632876Sdonn printf("\n\tjbr\tL%d\nL%d:\n\tcv", label3, label2); 68732879Sdonn prtype(src); 68832876Sdonn putstr("l\t"); 68932879Sdonn adrput(dst); 69032876Sdonn printf("\nL%d:", label3); 69132876Sdonn } 69232876Sdonn 69332876Sdonn /* 69432876Sdonn * Convert an unsigned int into a float or double, leaving the result 69532876Sdonn * in the accumulator. 69632876Sdonn */ 69732876Sdonn unsigned_to_float(p) 69832876Sdonn register NODE *p; 69932876Sdonn { 70032876Sdonn int label1 = getlab(); 70132876Sdonn int label2 = getlab(); 70232879Sdonn NODE *src, *dst; 70332876Sdonn 70432879Sdonn if (p->in.op == SCONV) { 70532879Sdonn src = p->in.left; 70632879Sdonn dst = resc; 70732879Sdonn } else { 70832879Sdonn src = p->in.right; 70932879Sdonn dst = p->in.left; 71032879Sdonn } 71132879Sdonn 71232876Sdonn printf(".data\n\t.align\t2\nL%d:\n\t.long\t0x50800000", label2); 71332876Sdonn if (p->in.type == DOUBLE) 71432879Sdonn putstr(", 0x00000000 # .double"); 71532879Sdonn else 71632879Sdonn putstr(" # .float"); 71732879Sdonn putstr(" 4294967296\n\t.text\n\tmovl\t"); 71832879Sdonn adrput(src); 71932876Sdonn putchar(','); 72032879Sdonn adrput(dst); 72132876Sdonn putstr("\n\tcvl"); 72232876Sdonn prtype(p); 72332876Sdonn putchar('\t'); 72432879Sdonn adrput(dst); 72532879Sdonn printf("\n\tjgeq\tL%d\n\tadd", label1); 72632879Sdonn prtype(p); 72732879Sdonn printf("\tL%d\nL%d:", label2, label1); 72832876Sdonn } 72932876Sdonn 73032876Sdonn /* 73132875Sdonn * Prlen() is a cheap prtype()... 73232875Sdonn */ 73332875Sdonn static char convtab[SZINT/SZCHAR + 1] = { 73432875Sdonn '?', 'b', 'w', '?', 'l' 73532875Sdonn }; 73632875Sdonn #define prlen(len) putchar(convtab[len]) 73732875Sdonn 73832875Sdonn 73932875Sdonn /* 74032873Sdonn * Generate code for integral scalar conversions. 74132875Sdonn * Some of this code is designed to work around a tahoe misfeature 74232875Sdonn * that causes sign- and zero- extension to be defeated in 74332875Sdonn * certain circumstances. 74432875Sdonn * Basically if the source operand of a CVT or MOVZ instruction is 74532875Sdonn * shorter than the destination, and the source is a register 74632875Sdonn * or an immediate constant, sign- and zero- extension are 74732875Sdonn * ignored and the high bits of the source are copied. (Note 74832875Sdonn * that zero-extension is not a problem for immediate 74932875Sdonn * constants.) 750*33351Sdonn * Another problem -- condition codes for a conversion with a 751*33351Sdonn * register source reflect the source rather than the destination. 75232873Sdonn */ 75332873Sdonn sconv(p, forcc) 75432873Sdonn NODE *p; 75532873Sdonn int forcc; 75632873Sdonn { 75732873Sdonn register NODE *src, *dst; 75832873Sdonn register NODE *tmp; 75932873Sdonn register int srclen, dstlen; 76032873Sdonn int srctype, dsttype; 76132873Sdonn int val; 76232882Sdonn int neg = 0; 76330360Ssam 76432873Sdonn if (p->in.op == ASSIGN) { 76532879Sdonn src = p->in.right; 76632879Sdonn dst = p->in.left; 76732873Sdonn dstlen = tlen(dst); 76832873Sdonn dsttype = dst->in.type; 76932879Sdonn } else if (p->in.op == SCONV) { 77032879Sdonn src = p->in.left; 77132879Sdonn dst = resc; 77232873Sdonn dstlen = tlen(p); 77332873Sdonn dsttype = p->in.type; 77432879Sdonn } else /* if (p->in.op == OPLEAF) */ { 77532879Sdonn src = p; 77632879Sdonn dst = resc; 77732879Sdonn dstlen = SZINT/SZCHAR; 77832879Sdonn dsttype = ISUNSIGNED(src->in.type) ? UNSIGNED : INT; 77932873Sdonn } 78032873Sdonn 78132875Sdonn if (src->in.op == REG) { 78232875Sdonn srclen = SZINT/SZCHAR; 78332875Sdonn srctype = ISUNSIGNED(src->in.type) ? UNSIGNED : INT; 78432875Sdonn } else { 78532875Sdonn srclen = tlen(src); 78632875Sdonn srctype = src->in.type; 78732875Sdonn } 78832873Sdonn 78932882Sdonn if (src->in.op == ICON && src->tn.name[0] == '\0') { 79032875Sdonn if (src->tn.lval == 0) { 79132875Sdonn putstr("clr"); 79232875Sdonn prtype(dst); 79332875Sdonn putchar('\t'); 79432875Sdonn adrput(dst); 79532875Sdonn return; 79632875Sdonn } 79732875Sdonn if (dstlen < srclen) { 79832875Sdonn switch (dsttype) { 79932875Sdonn case CHAR: 80032875Sdonn src->tn.lval = (char) src->tn.lval; 80132875Sdonn break; 80232875Sdonn case UCHAR: 80332875Sdonn src->tn.lval = (unsigned char) src->tn.lval; 80432875Sdonn break; 80532875Sdonn case SHORT: 80632875Sdonn src->tn.lval = (short) src->tn.lval; 80732875Sdonn break; 80832875Sdonn case USHORT: 80932875Sdonn src->tn.lval = (unsigned short) src->tn.lval; 81032875Sdonn break; 81132875Sdonn } 81232875Sdonn } 81332875Sdonn if (dst->in.op == REG) { 81432875Sdonn dsttype = INT; 81532875Sdonn dstlen = SZINT/SZCHAR; 81632875Sdonn } 81732875Sdonn srctype = dsttype; 81832875Sdonn srclen = dstlen; 81932887Sdonn val = -src->tn.lval & ((1 << dstlen * SZCHAR) - 1); 82032887Sdonn if ((unsigned) val < 64) { 82132887Sdonn src->tn.lval = val; 82232882Sdonn ++neg; /* MNEGx may be shorter */ 82332882Sdonn } 82432875Sdonn } 82532875Sdonn 82632873Sdonn if (srclen < dstlen) { 82732873Sdonn if (srctype == CHAR && dsttype == USHORT && dst->in.op == REG) { 82832873Sdonn /* (unsigned short) c; => sign extend to 16 bits */ 82932874Sdonn putstr("cvtbl\t"); 83032873Sdonn adrput(src); 83132873Sdonn putstr(",-(sp)\n\tmovzwl\t2(sp),"); 83232873Sdonn adrput(dst); 83332873Sdonn putstr("\n\tmovab\t4(sp),sp"); 83432873Sdonn if (forcc) { 83532873Sdonn /* inverted test */ 83632873Sdonn putstr("\n\tcmpl\t$0,"); 83732873Sdonn adrput(dst); 83832873Sdonn } 83932873Sdonn return; 84032873Sdonn } 84132873Sdonn genconv(ISUNSIGNED(srctype), 84232873Sdonn srclen, dst->in.op == REG ? SZINT/SZCHAR : dstlen, 843*33351Sdonn src, dst, forcc); 84432873Sdonn return; 84532873Sdonn } 84632873Sdonn 84732873Sdonn if (srclen > dstlen && dst->in.op == REG) { 84832875Sdonn /* if dst is a register, the result must look like an int */ 84932873Sdonn if (src->in.op == REG) { 85032873Sdonn if (ISUNSIGNED(dsttype)) { 85132873Sdonn val = (1 << dstlen * SZCHAR) - 1; 85232873Sdonn if (src->tn.rval == dst->tn.rval) 85332873Sdonn /* conversion in place */ 85432887Sdonn printf("andl2\t$%ld,", val); 85532873Sdonn else { 85632887Sdonn printf("andl3\t$%ld,", val); 85732873Sdonn adrput(src); 85832873Sdonn putchar(','); 85932873Sdonn } 86032873Sdonn adrput(dst); 86132873Sdonn return; 86232873Sdonn } 86332875Sdonn /* 86432875Sdonn * Sign extension in register can also be 86532875Sdonn * accomplished by shifts, but unfortunately 86632875Sdonn * shifts are extremely slow, due to the lack 86732875Sdonn * of a barrel shifter. 86832875Sdonn */ 86932875Sdonn putstr("pushl\t"); 87032873Sdonn adrput(src); 87132875Sdonn putstr("\n\tcvt"); 87232875Sdonn prlen(dstlen); 87332875Sdonn printf("l\t%d(sp),", SZINT/SZCHAR - dstlen); 87432873Sdonn adrput(dst); 87532875Sdonn putstr("\n\tmovab\t4(sp),sp"); 87632875Sdonn if (forcc) { 87732875Sdonn /* inverted test */ 87832875Sdonn putstr("\n\tcmpl\t$0,"); 87932875Sdonn adrput(dst); 88032875Sdonn } 88132873Sdonn return; 88232873Sdonn } 88332873Sdonn tmp = talloc(); 88432887Sdonn if ((src->in.op == NAME) || 88532887Sdonn (src->in.op == UNARY MUL && src->in.left->in.op == ICON) || 88632873Sdonn (src->in.op == OREG && !R2TEST(src->tn.rval))) { 88732873Sdonn /* we can increment src's address & pun it */ 88832873Sdonn *tmp = *src; 88932873Sdonn tmp->tn.lval += srclen - dstlen; 89032873Sdonn } else { 89132873Sdonn /* we must store src's address */ 89232873Sdonn *tmp = *dst; 89332875Sdonn putstr("mova"); 89432875Sdonn prlen(srclen); 89532875Sdonn putchar('\t'); 89632873Sdonn adrput(src); 89732873Sdonn putchar(','); 89832873Sdonn adrput(tmp); 89932874Sdonn putstr("\n\t"); 90032873Sdonn tmp->tn.op = OREG; 90132873Sdonn tmp->tn.lval = srclen - dstlen; 90232873Sdonn } 903*33351Sdonn genconv(ISUNSIGNED(dsttype), dstlen, SZINT/SZCHAR, tmp, dst, forcc); 90432873Sdonn tmp->in.op = FREE; 90532873Sdonn return; 90632873Sdonn } 90732873Sdonn 90832882Sdonn genconv(neg ? -1 : ISUNSIGNED(dsttype), 90932873Sdonn srclen, dst->in.op == REG ? SZINT/SZCHAR : dstlen, 910*33351Sdonn src, dst, forcc); 91132873Sdonn } 91232873Sdonn 913*33351Sdonn genconv(srcflag, srclen, dstlen, src, dst, forcc) 91432882Sdonn int srcflag; 91532875Sdonn register int srclen, dstlen; 91632873Sdonn NODE *src, *dst; 917*33351Sdonn int forcc; 91832873Sdonn { 91932873Sdonn if (srclen != dstlen) { 92032882Sdonn if (srcflag > 0 && srclen < dstlen) 92132874Sdonn putstr("movz"); 92232873Sdonn else 92332874Sdonn putstr("cvt"); 92432875Sdonn prlen(srclen); 92532882Sdonn } else if (srcflag < 0) 92632882Sdonn putstr("mneg"); 92732882Sdonn else 92832874Sdonn putstr("mov"); 92932875Sdonn prlen(dstlen); 93032873Sdonn putchar('\t'); 93132873Sdonn adrput(src); 93232873Sdonn putchar(','); 93332873Sdonn adrput(dst); 934*33351Sdonn 935*33351Sdonn /* 936*33351Sdonn * This hack is made necessary by architecture problems 937*33351Sdonn * described above 938*33351Sdonn */ 939*33351Sdonn if (forcc && src->in.op == REG && srclen > dstlen) { 940*33351Sdonn putstr("\n\ttst"); 941*33351Sdonn prlen(dstlen); 942*33351Sdonn putchar('\t'); 943*33351Sdonn adrput(dst); 944*33351Sdonn } 94532873Sdonn } 94632873Sdonn 94732886Sdonn rmove( rt, rs, t ) TWORD t; { 94825828Ssam printf( " movl %s,%s\n", rname(rs), rname(rt) ); 94925828Ssam if(t==DOUBLE) 95025828Ssam printf( " movl %s,%s\n", rname(rs+1), rname(rt+1) ); 95125828Ssam } 95225828Ssam 95325828Ssam struct respref 95425828Ssam respref[] = { 95525828Ssam INTAREG|INTBREG, INTAREG|INTBREG, 95625828Ssam INAREG|INBREG, INAREG|INBREG|SOREG|STARREG|STARNM|SNAME|SCON, 95725828Ssam INTEMP, INTEMP, 95825828Ssam FORARG, FORARG, 95925828Ssam INTEMP, INTAREG|INAREG|INTBREG|INBREG|SOREG|STARREG|STARNM, 96025828Ssam 0, 0 }; 96125828Ssam 96225828Ssam setregs(){ /* set up temporary registers */ 96325828Ssam fregs = 6; /* tbl- 6 free regs on Tahoe (0-5) */ 96425828Ssam } 96525828Ssam 96626076Ssam #ifndef szty 96725828Ssam szty(t) TWORD t;{ /* size, in registers, needed to hold thing of type t */ 96825828Ssam return(t==DOUBLE ? 2 : 1 ); 96925828Ssam } 97026076Ssam #endif 97125828Ssam 97232886Sdonn /*ARGSUSED*/ 97325828Ssam rewfld( p ) NODE *p; { 97425828Ssam return(1); 97525828Ssam } 97625828Ssam 97732886Sdonn /*ARGSUSED*/ 97825828Ssam callreg(p) NODE *p; { 97925828Ssam return( R0 ); 98025828Ssam } 98125828Ssam 98225828Ssam base( p ) register NODE *p; { 98325828Ssam register int o = p->in.op; 98425828Ssam 98532887Sdonn if( o==ICON && p->in.name[0] != '\0' ) return( 100 ); /* ie no base reg */ 98625828Ssam if( o==REG ) return( p->tn.rval ); 98725828Ssam if( (o==PLUS || o==MINUS) && p->in.left->in.op == REG && p->in.right->in.op==ICON) 98825828Ssam return( p->in.left->tn.rval ); 98925828Ssam if( o==OREG && !R2TEST(p->tn.rval) && (p->in.type==INT || p->in.type==UNSIGNED || ISPTR(p->in.type)) ) 99025828Ssam return( p->tn.rval + 0200*1 ); 99132887Sdonn if( o==NAME ) return( 100 + 0200*1 ); 99225828Ssam return( -1 ); 99325828Ssam } 99425828Ssam 99525828Ssam offset( p, tyl ) register NODE *p; int tyl; { 99625828Ssam 99732886Sdonn if( tyl==1 && 99832886Sdonn p->in.op==REG && 99932886Sdonn (p->in.type==INT || p->in.type==UNSIGNED) ) 100032886Sdonn return( p->tn.rval ); 100132886Sdonn if( p->in.op==LS && 100232886Sdonn p->in.left->in.op==REG && 100332886Sdonn (p->in.left->in.type==INT || p->in.left->in.type==UNSIGNED) && 100432886Sdonn p->in.right->in.op==ICON && 100532886Sdonn p->in.right->in.name[0]=='\0' && 100632886Sdonn (1<<p->in.right->tn.lval)==tyl) 100725828Ssam return( p->in.left->tn.rval ); 100832886Sdonn if( tyl==2 && 100932886Sdonn p->in.op==PLUS && 101032886Sdonn (p->in.left->in.type==INT || p->in.left->in.type==UNSIGNED) && 101132886Sdonn p->in.left->in.op==REG && 101232886Sdonn p->in.right->in.op==REG && 101332886Sdonn p->in.left->tn.rval==p->in.right->tn.rval ) 101432886Sdonn return( p->in.left->tn.rval ); 101525828Ssam return( -1 ); 101625828Ssam } 101725828Ssam 101825828Ssam makeor2( p, q, b, o) register NODE *p, *q; register int b, o; { 101925828Ssam register NODE *t; 102025828Ssam NODE *f; 102125828Ssam 102225828Ssam p->in.op = OREG; 102325828Ssam f = p->in.left; /* have to free this subtree later */ 102425828Ssam 102525828Ssam /* init base */ 102625828Ssam switch (q->in.op) { 102725828Ssam case ICON: 102825828Ssam case REG: 102925828Ssam case OREG: 103032887Sdonn case NAME: 103125828Ssam t = q; 103225828Ssam break; 103325828Ssam 103425828Ssam case MINUS: 103525828Ssam q->in.right->tn.lval = -q->in.right->tn.lval; 103625828Ssam case PLUS: 103725828Ssam t = q->in.right; 103825828Ssam break; 103925828Ssam 104025828Ssam case UNARY MUL: 104125828Ssam t = q->in.left->in.left; 104225828Ssam break; 104325828Ssam 104425828Ssam default: 104525828Ssam cerror("illegal makeor2"); 104625828Ssam } 104725828Ssam 104825828Ssam p->tn.lval = t->tn.lval; 104925828Ssam #ifndef FLEXNAMES 105032886Sdonn { 105132886Sdonn register int i; 105232886Sdonn for(i=0; i<NCHNAM; ++i) 105332886Sdonn p->in.name[i] = t->in.name[i]; 105432886Sdonn } 105525828Ssam #else 105625828Ssam p->in.name = t->in.name; 105725828Ssam #endif 105825828Ssam 105925828Ssam /* init offset */ 106025828Ssam p->tn.rval = R2PACK( (b & 0177), o, (b>>7) ); 106125828Ssam 106225828Ssam tfree(f); 106325828Ssam return; 106425828Ssam } 106525828Ssam 106625828Ssam canaddr( p ) NODE *p; { 106725828Ssam register int o = p->in.op; 106825828Ssam 106925828Ssam if( o==NAME || o==REG || o==ICON || o==OREG || (o==UNARY MUL && shumul(p->in.left)) ) return(1); 107025828Ssam return(0); 107125828Ssam } 107225828Ssam 107326076Ssam #ifndef shltype 107425828Ssam shltype( o, p ) register NODE *p; { 107525828Ssam return( o== REG || o == NAME || o == ICON || o == OREG || ( o==UNARY MUL && shumul(p->in.left)) ); 107625828Ssam } 107726076Ssam #endif 107825828Ssam 107925828Ssam flshape( p ) NODE *p; { 108025828Ssam register int o = p->in.op; 108125828Ssam 108225828Ssam if( o==NAME || o==REG || o==ICON || o==OREG || (o==UNARY MUL && shumul(p->in.left)) ) return(1); 108325828Ssam return(0); 108425828Ssam } 108525828Ssam 108632886Sdonn /* INTEMP shapes must not contain any temporary registers */ 108725828Ssam shtemp( p ) register NODE *p; { 108832886Sdonn int r; 108932886Sdonn 109025828Ssam if( p->in.op == STARG ) p = p->in.left; 109132886Sdonn 109232886Sdonn switch (p->in.op) { 109332886Sdonn case REG: 109432886Sdonn return( !istreg(p->tn.rval) ); 109532886Sdonn case OREG: 109632886Sdonn r = p->tn.rval; 109732886Sdonn if( R2TEST(r) ) { 109832886Sdonn if( istreg(R2UPK1(r)) ) 109932886Sdonn return(0); 110032886Sdonn r = R2UPK2(r); 110132886Sdonn } 110232886Sdonn return( !istreg(r) ); 110332886Sdonn case UNARY MUL: 110432886Sdonn p = p->in.left; 110532886Sdonn return( p->in.op != UNARY MUL && shtemp(p) ); 110632886Sdonn } 110732886Sdonn 110832886Sdonn if( optype( p->in.op ) != LTYPE ) return(0); 110932886Sdonn return(1); 111025828Ssam } 111125828Ssam 111225828Ssam shumul( p ) register NODE *p; { 111325828Ssam register int o; 111425828Ssam extern int xdebug; 111525828Ssam 111625828Ssam if (xdebug) { 111725828Ssam printf("\nshumul:op=%d,lop=%d,rop=%d", p->in.op, p->in.left->in.op, p->in.right->in.op); 111825828Ssam printf(" prname=%s,plty=%d, prlval=%D\n", p->in.right->in.name, p->in.left->in.type, p->in.right->tn.lval); 111925828Ssam } 112025828Ssam 112125828Ssam o = p->in.op; 112225828Ssam if(( o == NAME || (o == OREG && !R2TEST(p->tn.rval)) || o == ICON ) 112325828Ssam && p->in.type != PTR+DOUBLE) 112425828Ssam return( STARNM ); 112525828Ssam 112625828Ssam return( 0 ); 112725828Ssam } 112825828Ssam 112932887Sdonn special( p, shape ) register NODE *p; { 113032887Sdonn if( shape==SIREG && p->in.op == OREG && R2TEST(p->tn.rval) ) return(1); 113132887Sdonn else return(0); 113232887Sdonn } 113332887Sdonn 113425828Ssam adrcon( val ) CONSZ val; { 113525947Ssam printf(ACONFMT, val); 113625828Ssam } 113725828Ssam 113825828Ssam conput( p ) register NODE *p; { 113925828Ssam switch( p->in.op ){ 114025828Ssam 114125828Ssam case ICON: 114225828Ssam acon( p ); 114325828Ssam return; 114425828Ssam 114525828Ssam case REG: 114626162Ssam putstr(rname(p->tn.rval)); 114725828Ssam return; 114825828Ssam 114925828Ssam default: 115025828Ssam cerror( "illegal conput" ); 115125828Ssam } 115225828Ssam } 115325828Ssam 115432886Sdonn /*ARGSUSED*/ 115525828Ssam insput( p ) NODE *p; { 115625828Ssam cerror( "insput" ); 115725828Ssam } 115825828Ssam 115932886Sdonn /* 116032886Sdonn * Output the address of the second item in the 116132886Sdonn * pair pointed to by p. 116232886Sdonn */ 116332886Sdonn upput(p, size) 116432886Sdonn register NODE *p; 116532886Sdonn { 116632886Sdonn CONSZ save; 116732886Sdonn 116832886Sdonn if (p->in.op == FLD) 116932886Sdonn p = p->in.left; 117032886Sdonn switch (p->in.op) { 117132886Sdonn 117232886Sdonn case NAME: 117332886Sdonn case OREG: 117432886Sdonn save = p->tn.lval; 117532886Sdonn p->tn.lval += size/SZCHAR; 117632886Sdonn adrput(p); 117732886Sdonn p->tn.lval = save; 117832886Sdonn break; 117932886Sdonn 118032886Sdonn case REG: 118132886Sdonn if (size == SZLONG) { 118232886Sdonn putstr(rname(p->tn.rval+1)); 118332886Sdonn break; 118432886Sdonn } 118532886Sdonn /* fall thru... */ 118632886Sdonn 118732886Sdonn default: 118832886Sdonn cerror("illegal upper address op %s size %d", 118932886Sdonn opst[p->tn.op], size); 119032886Sdonn /*NOTREACHED*/ 119132886Sdonn } 119232886Sdonn } 119332886Sdonn 119425828Ssam adrput( p ) register NODE *p; { 119525828Ssam register int r; 119625828Ssam /* output an address, with offsets, from p */ 119725828Ssam 119825828Ssam if( p->in.op == FLD ){ 119925828Ssam p = p->in.left; 120025828Ssam } 120125828Ssam switch( p->in.op ){ 120225828Ssam 120325828Ssam case NAME: 120425828Ssam acon( p ); 120525828Ssam return; 120625828Ssam 120725828Ssam case ICON: 120825828Ssam /* addressable value of the constant */ 120926162Ssam putchar('$'); 121025828Ssam acon( p ); 121125828Ssam return; 121225828Ssam 121325828Ssam case REG: 121426162Ssam putstr(rname(p->tn.rval)); 121525828Ssam if(p->in.type == DOUBLE) /* for entry mask */ 121625828Ssam (void) rname(p->tn.rval+1); 121725828Ssam return; 121825828Ssam 121925828Ssam case OREG: 122025828Ssam r = p->tn.rval; 122125828Ssam if( R2TEST(r) ){ /* double indexing */ 122225828Ssam register int flags; 122325828Ssam 122425828Ssam flags = R2UPK3(r); 122526162Ssam if( flags & 1 ) putchar('*'); 122625828Ssam if( p->tn.lval != 0 || p->in.name[0] != '\0' ) acon(p); 122725828Ssam if( R2UPK1(r) != 100) printf( "(%s)", rname(R2UPK1(r)) ); 122825828Ssam printf( "[%s]", rname(R2UPK2(r)) ); 122925828Ssam return; 123025828Ssam } 123125828Ssam if( r == FP && p->tn.lval > 0 ){ /* in the argument region */ 123225828Ssam if( p->in.name[0] != '\0' ) werror( "bad arg temp" ); 123325828Ssam printf( CONFMT, p->tn.lval ); 123426162Ssam putstr( "(fp)" ); 123525828Ssam return; 123625828Ssam } 123725828Ssam if( p->tn.lval != 0 || p->in.name[0] != '\0') acon( p ); 123825828Ssam printf( "(%s)", rname(p->tn.rval) ); 123925828Ssam return; 124025828Ssam 124125828Ssam case UNARY MUL: 124225828Ssam /* STARNM or STARREG found */ 124325828Ssam if( tshape(p, STARNM) ) { 124426162Ssam putchar( '*' ); 124525828Ssam adrput( p->in.left); 124625828Ssam } 124725828Ssam return; 124825828Ssam 124925828Ssam default: 125025828Ssam cerror( "illegal address" ); 125125828Ssam return; 125225828Ssam 125325828Ssam } 125425828Ssam 125525828Ssam } 125625828Ssam 125725828Ssam acon( p ) register NODE *p; { /* print out a constant */ 125825828Ssam 125932886Sdonn if( p->in.name[0] == '\0' ) 126025828Ssam printf( CONFMT, p->tn.lval); 126132886Sdonn else { 126225828Ssam #ifndef FLEXNAMES 126325828Ssam printf( "%.8s", p->in.name ); 126425828Ssam #else 126532886Sdonn putstr( p->in.name ); 126625828Ssam #endif 126732886Sdonn if( p->tn.lval != 0 ) { 126832886Sdonn putchar( '+' ); 126932886Sdonn printf( CONFMT, p->tn.lval ); 127032886Sdonn } 127125828Ssam } 127225828Ssam } 127325828Ssam 127425828Ssam genscall( p, cookie ) register NODE *p; { 127525828Ssam /* structure valued call */ 127625828Ssam return( gencall( p, cookie ) ); 127725828Ssam } 127825828Ssam 127925828Ssam genfcall( p, cookie ) register NODE *p; { 128025828Ssam register NODE *p1; 128125828Ssam register int m; 128225828Ssam static char *funcops[6] = { 128325828Ssam "sin", "cos", "sqrt", "exp", "log", "atan" 128425828Ssam }; 128525828Ssam 128625828Ssam /* generate function opcodes */ 128725828Ssam if(p->in.op==UNARY FORTCALL && p->in.type==FLOAT && 128825828Ssam (p1 = p->in.left)->in.op==ICON && 128925828Ssam p1->tn.lval==0 && p1->in.type==INCREF(FTN|FLOAT)) { 129025828Ssam #ifdef FLEXNAMES 129125828Ssam p1->in.name++; 129225828Ssam #else 129325828Ssam strcpy(p1->in.name, p1->in.name[1]); 129425828Ssam #endif 129525828Ssam for(m=0; m<6; m++) 129625828Ssam if(!strcmp(p1->in.name, funcops[m])) 129725828Ssam break; 129825828Ssam if(m >= 6) 129925828Ssam uerror("no opcode for fortarn function %s", p1->in.name); 130025828Ssam } else 130125828Ssam uerror("illegal type of fortarn function"); 130225828Ssam p1 = p->in.right; 130325828Ssam p->in.op = FORTCALL; 130425828Ssam if(!canaddr(p1)) 130525828Ssam order( p1, INAREG|INBREG|SOREG|STARREG|STARNM ); 130625828Ssam m = match( p, INTAREG|INTBREG ); 130725828Ssam return(m != MDONE); 130825828Ssam } 130925828Ssam 131025828Ssam /* tbl */ 131125828Ssam int gc_numbytes; 131225828Ssam /* tbl */ 131325828Ssam 131432886Sdonn /*ARGSUSED*/ 131525828Ssam gencall( p, cookie ) register NODE *p; { 131625828Ssam /* generate the call given by p */ 131725828Ssam register NODE *p1, *ptemp; 131825828Ssam register int temp, temp1; 131925828Ssam register int m; 132025828Ssam 132125828Ssam if( p->in.right ) temp = argsize( p->in.right ); 132225828Ssam else temp = 0; 132325828Ssam 132425828Ssam if( p->in.op == STCALL || p->in.op == UNARY STCALL ){ 132525828Ssam /* set aside room for structure return */ 132625828Ssam 132725828Ssam if( p->stn.stsize > temp ) temp1 = p->stn.stsize; 132825828Ssam else temp1 = temp; 132925828Ssam } 133025828Ssam 133125828Ssam if( temp > maxargs ) maxargs = temp; 133225828Ssam SETOFF(temp1,4); 133325828Ssam 133425828Ssam if( p->in.right ){ /* make temp node, put offset in, and generate args */ 133525828Ssam ptemp = talloc(); 133625828Ssam ptemp->in.op = OREG; 133725828Ssam ptemp->tn.lval = -1; 133825828Ssam ptemp->tn.rval = SP; 133925828Ssam #ifndef FLEXNAMES 134025828Ssam ptemp->in.name[0] = '\0'; 134125828Ssam #else 134225828Ssam ptemp->in.name = ""; 134325828Ssam #endif 134425828Ssam ptemp->in.rall = NOPREF; 134525828Ssam ptemp->in.su = 0; 134625828Ssam genargs( p->in.right, ptemp ); 134725828Ssam ptemp->in.op = FREE; 134825828Ssam } 134925828Ssam 135025828Ssam p1 = p->in.left; 135125828Ssam if( p1->in.op != ICON ){ 135225828Ssam if( p1->in.op != REG ){ 135325828Ssam if( p1->in.op != OREG || R2TEST(p1->tn.rval) ){ 135425828Ssam if( p1->in.op != NAME ){ 135525828Ssam order( p1, INAREG ); 135625828Ssam } 135725828Ssam } 135825828Ssam } 135925828Ssam } 136025828Ssam 136125828Ssam /* tbl 136225828Ssam setup gc_numbytes so reference to ZC works */ 136325828Ssam 136425828Ssam gc_numbytes = temp&(0x3ff); 136525828Ssam 136625828Ssam p->in.op = UNARY CALL; 136725828Ssam m = match( p, INTAREG|INTBREG ); 136825828Ssam 136925828Ssam return(m != MDONE); 137025828Ssam } 137125828Ssam 137225828Ssam /* tbl */ 137325828Ssam char * 137425828Ssam ccbranches[] = { 137525828Ssam "eql", 137625828Ssam "neq", 137725828Ssam "leq", 137825828Ssam "lss", 137925828Ssam "geq", 138025828Ssam "gtr", 138125828Ssam "lequ", 138225828Ssam "lssu", 138325828Ssam "gequ", 138425828Ssam "gtru", 138525828Ssam }; 138625828Ssam /* tbl */ 138725828Ssam 138832886Sdonn /*ARGSUSED*/ 138925828Ssam cbgen( o, lab, mode ) { /* printf conditional and unconditional branches */ 139025828Ssam 139132886Sdonn if( o != 0 && ( o < EQ || o > UGT ) ) 139232886Sdonn cerror( "bad conditional branch: %s", opst[o] ); 139332886Sdonn printf( " j%s L%d\n", o == 0 ? "br" : ccbranches[o-EQ], lab ); 139425828Ssam } 139525828Ssam 139625828Ssam nextcook( p, cookie ) NODE *p; { 139725828Ssam /* we have failed to match p with cookie; try another */ 139825828Ssam if( cookie == FORREW ) return( 0 ); /* hopeless! */ 139925828Ssam if( !(cookie&(INTAREG|INTBREG)) ) return( INTAREG|INTBREG ); 140025828Ssam if( !(cookie&INTEMP) && asgop(p->in.op) ) return( INTEMP|INAREG|INTAREG|INTBREG|INBREG ); 140125828Ssam return( FORREW ); 140225828Ssam } 140325828Ssam 140432886Sdonn /*ARGSUSED*/ 140525828Ssam lastchance( p, cook ) NODE *p; { 140625828Ssam /* forget it! */ 140725828Ssam return(0); 140825828Ssam } 140925828Ssam 141025828Ssam optim2( p ) register NODE *p; { 141125828Ssam /* do local tree transformations and optimizations */ 141232886Sdonn 141332886Sdonn int o; 141432886Sdonn int i, mask; 141530360Ssam register NODE *l, *r; 141625828Ssam 141732886Sdonn switch( o = p->in.op ) { 141830360Ssam 141932887Sdonn case ASG PLUS: 142032887Sdonn case ASG MINUS: 142132887Sdonn case ASG MUL: 142232887Sdonn case ASG OR: 142332887Sdonn /* simple ASG OPSIMP -- reduce range of constant rhs */ 142432887Sdonn l = p->in.left; 142532887Sdonn r = p->in.right; 142632887Sdonn if( tlen(l) < SZINT/SZCHAR && 142732887Sdonn r->in.op==ICON && r->in.name[0]==0 ){ 142832887Sdonn mask = (1 << tlen(l) * SZCHAR) - 1; 142932887Sdonn if( r->tn.lval & (mask & ~(mask >> 1)) ) 143032887Sdonn r->tn.lval |= ~mask; 143132887Sdonn else 143232887Sdonn r->tn.lval &= mask; 143332887Sdonn } 143432887Sdonn break; 143532887Sdonn 143632886Sdonn case AND: 143732886Sdonn case ASG AND: 143832886Sdonn r = p->in.right; 143932886Sdonn if( r->in.op==ICON && r->in.name[0]==0 ) { 144032886Sdonn /* check for degenerate operations */ 144132886Sdonn l = p->in.left; 144232886Sdonn mask = (1 << tlen(l) * SZCHAR) - 1; 144332887Sdonn if( o == ASG AND || ISUNSIGNED(r->in.type) ) { 144432887Sdonn i = r->tn.lval & mask; 144532886Sdonn if( i == mask ) { 144632887Sdonn /* redundant mask */ 144732886Sdonn r->in.op = FREE; 144832886Sdonn ncopy(p, l); 144932886Sdonn l->in.op = FREE; 145032886Sdonn break; 145132886Sdonn } 145232886Sdonn else if( i == 0 ) 145332887Sdonn /* all bits masked off */ 145432886Sdonn goto zero; 145532887Sdonn r->tn.lval = i; 145632887Sdonn if( tlen(l) < SZINT/SZCHAR ){ 145732887Sdonn /* sign extend */ 145832887Sdonn if( r->tn.lval & (mask & ~(mask >> 1)) ) 145932887Sdonn r->tn.lval |= ~mask; 146032887Sdonn else 146132887Sdonn r->tn.lval &= mask; 146232887Sdonn } 146332886Sdonn } 146432886Sdonn else if( r->tn.lval == mask && 146532886Sdonn tlen(l) < SZINT/SZCHAR ) { 146632887Sdonn /* use movz instead of and */ 146732886Sdonn r->in.op = SCONV; 146832886Sdonn r->in.left = l; 146932886Sdonn r->in.right = 0; 147032886Sdonn r->in.type = ENUNSIGN(l->in.type); 147132886Sdonn r->in.su = l->in.su > 1 ? l->in.su : 1; 147232886Sdonn ncopy(p, r); 147332886Sdonn p->in.left = r; 147432886Sdonn p->in.type = INT; 147532886Sdonn } 147630360Ssam } 147732886Sdonn break; 147830360Ssam 147930360Ssam case SCONV: 148030360Ssam l = p->in.left; 148132886Sdonn if( p->in.type == FLOAT || p->in.type == DOUBLE || 148232886Sdonn l->in.type == FLOAT || l->in.type == DOUBLE ) 148332886Sdonn return; 148432887Sdonn if( l->in.op == PCONV ) 148532886Sdonn return; 148632887Sdonn if( (l->in.op == CALL || l->in.op == UNARY CALL) && 148732887Sdonn l->in.type != INT && l->in.type != UNSIGNED ) 148832887Sdonn return; 148932879Sdonn 149032886Sdonn /* Only trust it to get it right if the size is the same */ 149132886Sdonn if( tlen(p) != tlen(l) ) 149232886Sdonn return; 149330360Ssam 149432886Sdonn /* clobber conversion */ 149532886Sdonn if( l->in.op != FLD ) 149632886Sdonn l->in.type = p->in.type; 149732886Sdonn ncopy( p, l ); 149832886Sdonn l->in.op = FREE; 149932886Sdonn 150032886Sdonn break; 150132886Sdonn 150230360Ssam case ASSIGN: 150330360Ssam /* 150432886Sdonn * Conversions are equivalent to assignments; 150532886Sdonn * when the two operations are combined, 150632886Sdonn * we can sometimes zap the conversion. 150730360Ssam */ 150830360Ssam r = p->in.right; 150932886Sdonn l = p->in.left; 151032886Sdonn if ( r->in.op == SCONV && 151132886Sdonn !mixtypes(l, r) && 151232886Sdonn l->in.op != FLD && 151332886Sdonn tlen(l) == tlen(r) ) { 151430360Ssam p->in.right = r->in.left; 151530360Ssam r->in.op = FREE; 151630360Ssam } 151732886Sdonn break; 151832885Sdonn 151932885Sdonn case ULE: 152032885Sdonn case ULT: 152132885Sdonn case UGE: 152232885Sdonn case UGT: 152332886Sdonn p->in.op -= (UGE-GE); 152432886Sdonn if( degenerate(p) ) 152532886Sdonn break; 152632886Sdonn p->in.op += (UGE-GE); 152732886Sdonn break; 152832886Sdonn 152932885Sdonn case EQ: 153032885Sdonn case NE: 153132885Sdonn case LE: 153232885Sdonn case LT: 153332885Sdonn case GE: 153432885Sdonn case GT: 153532887Sdonn if( p->in.left->in.op == SCONV && 153632887Sdonn p->in.right->in.op == SCONV ) { 153732887Sdonn l = p->in.left; 153832887Sdonn r = p->in.right; 153932887Sdonn if( l->in.type == DOUBLE && 154032887Sdonn l->in.left->in.type == FLOAT && 154132887Sdonn r->in.left->in.type == FLOAT ) { 154232887Sdonn /* nuke the conversions */ 154332887Sdonn p->in.left = l->in.left; 154432887Sdonn p->in.right = r->in.left; 154532887Sdonn l->in.op = FREE; 154632887Sdonn r->in.op = FREE; 154732887Sdonn } 154832887Sdonn /* more? */ 154932887Sdonn } 155032886Sdonn (void) degenerate(p); 155132886Sdonn break; 155232886Sdonn 155332886Sdonn case DIV: 155432886Sdonn if( p->in.right->in.op == ICON && 155532886Sdonn p->in.right->tn.name[0] == '\0' && 155632886Sdonn ISUNSIGNED(p->in.right->in.type) && 155732886Sdonn (unsigned) p->in.right->tn.lval >= 0x80000000 ) { 155832886Sdonn /* easy to do here, harder to do in zzzcode() */ 155932886Sdonn p->in.op = UGE; 156032886Sdonn break; 156132886Sdonn } 156232886Sdonn case MOD: 156332886Sdonn case ASG DIV: 156432886Sdonn case ASG MOD: 156532885Sdonn /* 156632886Sdonn * optimize DIV and MOD 156732886Sdonn * 156832886Sdonn * basically we spot UCHAR and USHORT and try to do them 156932886Sdonn * as signed ints... this may need tuning for the tahoe. 157032885Sdonn */ 157132886Sdonn if( degenerate(p) ) 157232886Sdonn break; 157332886Sdonn l = p->in.left; 157432885Sdonn r = p->in.right; 157532886Sdonn if( !ISUNSIGNED(r->in.type) || 157632886Sdonn tlen(l) >= SZINT/SZCHAR || 157732886Sdonn !(tlen(r) < SZINT/SZCHAR || 157832886Sdonn (r->in.op == ICON && r->tn.name[0] == '\0')) ) 157932886Sdonn break; 158032886Sdonn if( r->in.op == ICON ) 158132886Sdonn r->tn.type = INT; 158232886Sdonn else { 158332886Sdonn NODE *t = talloc(); 158432886Sdonn t->in.left = r; 158532886Sdonn r = t; 158632886Sdonn r->in.op = SCONV; 158732886Sdonn r->in.type = INT; 158832886Sdonn r->in.right = 0; 158932886Sdonn p->in.right = r; 159032886Sdonn } 159132886Sdonn if( o == DIV || o == MOD ) { 159232886Sdonn NODE *t = talloc(); 159332886Sdonn t->in.left = l; 159432886Sdonn l = t; 159532886Sdonn l->in.op = SCONV; 159632886Sdonn l->in.type = INT; 159732886Sdonn l->in.right = 0; 159832886Sdonn p->in.left = l; 159932886Sdonn } 160032886Sdonn /* handle asgops in table */ 160132886Sdonn break; 160232886Sdonn 160332886Sdonn case RS: 160432886Sdonn case ASG RS: 160532886Sdonn case LS: 160632886Sdonn case ASG LS: 160732886Sdonn /* pick up degenerate shifts */ 160832885Sdonn l = p->in.left; 160932886Sdonn r = p->in.right; 161032886Sdonn if( !(r->in.op == ICON && r->tn.name[0] == '\0') ) 161132885Sdonn break; 161232885Sdonn i = r->tn.lval; 161332886Sdonn if( i < 0 ) 161432886Sdonn /* front end 'fixes' this? */ 161532886Sdonn if( o == LS || o == ASG LS ) 161632886Sdonn o += (RS-LS); 161732886Sdonn else 161832886Sdonn o += (LS-RS); 161932886Sdonn if( (o == RS || o == ASG RS) && 162032886Sdonn !ISUNSIGNED(l->in.type) ) 162132886Sdonn /* can't optimize signed right shifts */ 162232885Sdonn break; 162332886Sdonn if( o == LS ) { 162432886Sdonn if( i < SZINT ) 162532886Sdonn break; 162632886Sdonn } 162732886Sdonn else { 162832886Sdonn if( i < tlen(l) * SZCHAR ) 162932886Sdonn break; 163032886Sdonn } 163132886Sdonn zero: 163232886Sdonn if( !asgop( o ) ) 163332886Sdonn if( tshape(l, SAREG|SNAME|SCON|SOREG|STARNM) ) { 163432886Sdonn /* no side effects */ 163532886Sdonn tfree(l); 163632886Sdonn ncopy(p, r); 163732886Sdonn r->in.op = FREE; 163832886Sdonn p->tn.lval = 0; 163932886Sdonn } 164032886Sdonn else { 164132886Sdonn p->in.op = COMOP; 164232886Sdonn r->tn.lval = 0; 164332886Sdonn } 164432886Sdonn else { 164532886Sdonn p->in.op = ASSIGN; 164632886Sdonn r->tn.lval = 0; 164732886Sdonn } 164832886Sdonn break; 164932885Sdonn } 165032886Sdonn } 165132885Sdonn 165232886Sdonn degenerate(p) register NODE *p; { 165332886Sdonn int o; 165432886Sdonn int result, i; 165532886Sdonn int lower, upper; 165632886Sdonn register NODE *l, *r; 165732886Sdonn 165832886Sdonn /* 165932886Sdonn * try to keep degenerate comparisons with constants 166032886Sdonn * out of the table. 166132886Sdonn */ 166232886Sdonn r = p->in.right; 166332886Sdonn l = p->in.left; 166432886Sdonn if( r->in.op != ICON || 166532886Sdonn r->tn.name[0] != '\0' || 166632886Sdonn tlen(l) >= tlen(r) ) 166732886Sdonn return (0); 166832886Sdonn switch( l->in.type ) { 166932886Sdonn case CHAR: 167032886Sdonn lower = -(1 << SZCHAR - 1); 167132886Sdonn upper = (1 << SZCHAR - 1) - 1; 167232886Sdonn break; 167332886Sdonn case UCHAR: 167432886Sdonn lower = 0; 167532886Sdonn upper = (1 << SZCHAR) - 1; 167632886Sdonn break; 167732886Sdonn case SHORT: 167832886Sdonn lower = -(1 << SZSHORT - 1); 167932886Sdonn upper = (1 << SZSHORT - 1) - 1; 168032886Sdonn break; 168132886Sdonn case USHORT: 168232886Sdonn lower = 0; 168332886Sdonn upper = (1 << SZSHORT) - 1; 168432886Sdonn break; 168532886Sdonn default: 168632886Sdonn cerror("unsupported type in degenerate()"); 168732886Sdonn } 168832886Sdonn i = r->tn.lval; 168932886Sdonn switch( o = p->in.op ) { 169032886Sdonn case DIV: 169132886Sdonn case ASG DIV: 169232886Sdonn case MOD: 169332886Sdonn case ASG MOD: 169432886Sdonn /* DIV and MOD work like EQ */ 169532886Sdonn case EQ: 169632886Sdonn case NE: 169732886Sdonn if( lower == 0 && (unsigned) i > upper ) 169832886Sdonn result = o == NE; 169932886Sdonn else if( i < lower || i > upper ) 170032886Sdonn result = o == NE; 170132886Sdonn else 170232886Sdonn return (0); 170332886Sdonn break; 170432886Sdonn case LT: 170532886Sdonn case GE: 170632886Sdonn if( lower == 0 && (unsigned) i > upper ) 170732886Sdonn result = o == LT; 170832886Sdonn else if( i <= lower ) 170932886Sdonn result = o != LT; 171032886Sdonn else if( i > upper ) 171132886Sdonn result = o == LT; 171232886Sdonn else 171332886Sdonn return (0); 171432886Sdonn break; 171532886Sdonn case LE: 171632886Sdonn case GT: 171732886Sdonn if( lower == 0 && (unsigned) i >= upper ) 171832886Sdonn result = o == LE; 171932886Sdonn else if( i < lower ) 172032886Sdonn result = o != LE; 172132886Sdonn else if( i >= upper ) 172232886Sdonn result = o == LE; 172332886Sdonn else 172432886Sdonn return (0); 172532886Sdonn break; 172632886Sdonn default: 172732886Sdonn cerror("unknown op in degenerate()"); 172832886Sdonn } 172932886Sdonn 173032886Sdonn if( o == MOD || o == ASG MOD ) { 173132886Sdonn r->in.op = FREE; 173232886Sdonn ncopy(p, l); 173332886Sdonn l->in.op = FREE; 173432886Sdonn } 173532886Sdonn else if( o != ASG DIV && tshape(l, SAREG|SNAME|SCON|SOREG|STARNM) ) { 173632886Sdonn /* no side effects */ 173732886Sdonn tfree(l); 173832886Sdonn ncopy(p, r); 173932886Sdonn r->in.op = FREE; 174032886Sdonn p->tn.lval = result; 174132886Sdonn } 174232886Sdonn else { 174332886Sdonn if( o == ASG DIV ) 174432886Sdonn p->in.op = ASSIGN; 174532886Sdonn else { 174632885Sdonn p->in.op = COMOP; 174732885Sdonn r->tn.type = INT; 174832886Sdonn } 174932886Sdonn r->tn.lval = result; 175032885Sdonn } 175132886Sdonn if( logop(o) ) 175232886Sdonn p->in.type = INT; 175332886Sdonn 175432886Sdonn return (1); 175525828Ssam } 175625828Ssam 175725828Ssam struct functbl { 175825828Ssam int fop; 175932877Sdonn TWORD ftype; 176025828Ssam char *func; 176132877Sdonn } opfunc[] = { 176232877Sdonn DIV, TANY, "udiv", 176332877Sdonn MOD, TANY, "urem", 176432877Sdonn ASG DIV, TANY, "audiv", 176532877Sdonn ASG MOD, TANY, "aurem", 176632877Sdonn 0, 0, 0 }; 176725828Ssam 176825828Ssam hardops(p) register NODE *p; { 176925828Ssam /* change hard to do operators into function calls. */ 177025828Ssam register NODE *q; 177125828Ssam register struct functbl *f; 177232877Sdonn register o; 177332877Sdonn NODE *old,*temp; 177425828Ssam 177525828Ssam o = p->in.op; 177632877Sdonn if( ! (optype(o)==BITYPE && 177732877Sdonn (ISUNSIGNED(p->in.left->in.type) || 177832877Sdonn ISUNSIGNED(p->in.right->in.type))) ) 177932877Sdonn return; 178025828Ssam 178125828Ssam for( f=opfunc; f->fop; f++ ) { 178225828Ssam if( o==f->fop ) goto convert; 178332877Sdonn } 178425828Ssam return; 178525828Ssam 178625828Ssam convert: 178732886Sdonn if( p->in.right->in.op == ICON && p->in.right->tn.name[0] == '\0' ) 178832886Sdonn /* 'J' in zzzcode() -- assumes DIV or MOD operations */ 178932886Sdonn /* save a subroutine call -- use at most 5 instructions */ 179032886Sdonn return; 179132886Sdonn if( tlen(p->in.left) < SZINT/SZCHAR && tlen(p->in.right) < SZINT/SZCHAR ) 179232886Sdonn /* optim2() will modify the op into an ordinary int op */ 179332886Sdonn return; 179425828Ssam if( asgop( o ) ) { 179532877Sdonn old = NIL; 179632877Sdonn switch( p->in.left->in.op ){ 179732877Sdonn case FLD: 179832877Sdonn q = p->in.left->in.left; 179932877Sdonn /* 180032877Sdonn * rewrite (lval.fld /= rval); as 180132877Sdonn * ((*temp).fld = udiv((*(temp = &lval)).fld,rval)); 180232877Sdonn * else the compiler will evaluate lval twice. 180332877Sdonn */ 180432877Sdonn if( q->in.op == UNARY MUL ){ 180532877Sdonn /* first allocate a temp storage */ 180632877Sdonn temp = talloc(); 180732877Sdonn temp->in.op = OREG; 180832877Sdonn temp->tn.rval = TMPREG; 180932877Sdonn temp->tn.lval = BITOOR(freetemp(1)); 181032877Sdonn temp->in.type = INCREF(p->in.type); 181132877Sdonn #ifdef FLEXNAMES 181232877Sdonn temp->in.name = ""; 181332877Sdonn #else 181432877Sdonn temp->in.name[0] = '\0'; 181532877Sdonn #endif 181632877Sdonn old = q->in.left; 181732877Sdonn q->in.left = temp; 181832877Sdonn } 181932877Sdonn /* fall thru ... */ 182025828Ssam 182132877Sdonn case REG: 182232877Sdonn case NAME: 182332877Sdonn case OREG: 182432877Sdonn /* change ASG OP to a simple OP */ 182532877Sdonn q = talloc(); 182632877Sdonn q->in.op = NOASG p->in.op; 182732877Sdonn q->in.rall = NOPREF; 182832877Sdonn q->in.type = p->in.type; 182932877Sdonn q->in.left = tcopy(p->in.left); 183032877Sdonn q->in.right = p->in.right; 183132877Sdonn p->in.op = ASSIGN; 183232877Sdonn p->in.right = q; 183332877Sdonn p = q; 183432877Sdonn f -= 2; /* Note: this depends on the table order */ 183532877Sdonn /* on the right side only - replace *temp with 183632877Sdonn *(temp = &lval), build the assignment node */ 183732877Sdonn if( old ){ 183832877Sdonn temp = q->in.left->in.left; /* the "*" node */ 183932877Sdonn q = talloc(); 184032877Sdonn q->in.op = ASSIGN; 184132877Sdonn q->in.left = temp->in.left; 184232877Sdonn q->in.right = old; 184332877Sdonn q->in.type = old->in.type; 184432877Sdonn #ifdef FLEXNAMES 184532877Sdonn q->in.name = ""; 184625828Ssam #else 184732877Sdonn q->in.name[0] = '\0'; 184825828Ssam #endif 184932877Sdonn temp->in.left = q; 185032877Sdonn } 185132877Sdonn break; 185225828Ssam 185332877Sdonn case UNARY MUL: 185432877Sdonn /* avoid doing side effects twice */ 185532877Sdonn q = p->in.left; 185632877Sdonn p->in.left = q->in.left; 185732877Sdonn q->in.op = FREE; 185832877Sdonn break; 185932877Sdonn 186032877Sdonn default: 186132877Sdonn cerror( "hardops: can't compute & LHS" ); 186232877Sdonn } 186332877Sdonn } 186432877Sdonn 186525828Ssam /* build comma op for args to function */ 186632877Sdonn q = talloc(); 186732877Sdonn q->in.op = CM; 186832877Sdonn q->in.rall = NOPREF; 186932877Sdonn q->in.type = INT; 187032877Sdonn q->in.left = p->in.left; 187132877Sdonn q->in.right = p->in.right; 187225828Ssam p->in.op = CALL; 187325828Ssam p->in.right = q; 187425828Ssam 187525828Ssam /* put function name in left node of call */ 187625828Ssam p->in.left = q = talloc(); 187725828Ssam q->in.op = ICON; 187825828Ssam q->in.rall = NOPREF; 187925828Ssam q->in.type = INCREF( FTN + p->in.type ); 188025828Ssam #ifndef FLEXNAMES 188132877Sdonn strcpy( q->in.name, f->func ); 188225828Ssam #else 188332877Sdonn q->in.name = f->func; 188425828Ssam #endif 188525828Ssam q->tn.lval = 0; 188625828Ssam q->tn.rval = 0; 188725828Ssam 188825828Ssam } 188925828Ssam 189025828Ssam zappost(p) NODE *p; { 189125828Ssam /* look for ++ and -- operators and remove them */ 189225828Ssam 189325828Ssam register int o, ty; 189425828Ssam register NODE *q; 189525828Ssam o = p->in.op; 189625828Ssam ty = optype( o ); 189725828Ssam 189825828Ssam switch( o ){ 189925828Ssam 190025828Ssam case INCR: 190125828Ssam case DECR: 190225828Ssam q = p->in.left; 190325828Ssam p->in.right->in.op = FREE; /* zap constant */ 190425828Ssam ncopy( p, q ); 190525828Ssam q->in.op = FREE; 190625828Ssam return; 190725828Ssam 190825828Ssam } 190925828Ssam 191025828Ssam if( ty == BITYPE ) zappost( p->in.right ); 191125828Ssam if( ty != LTYPE ) zappost( p->in.left ); 191225828Ssam } 191325828Ssam 191425828Ssam fixpre(p) NODE *p; { 191525828Ssam 191625828Ssam register int o, ty; 191725828Ssam o = p->in.op; 191825828Ssam ty = optype( o ); 191925828Ssam 192025828Ssam switch( o ){ 192125828Ssam 192225828Ssam case ASG PLUS: 192325828Ssam p->in.op = PLUS; 192425828Ssam break; 192525828Ssam case ASG MINUS: 192625828Ssam p->in.op = MINUS; 192725828Ssam break; 192825828Ssam } 192925828Ssam 193025828Ssam if( ty == BITYPE ) fixpre( p->in.right ); 193125828Ssam if( ty != LTYPE ) fixpre( p->in.left ); 193225828Ssam } 193325828Ssam 193432886Sdonn /*ARGSUSED*/ 193525828Ssam NODE * addroreg(l) NODE *l; 193625828Ssam /* OREG was built in clocal() 193725828Ssam * for an auto or formal parameter 193825828Ssam * now its address is being taken 193925828Ssam * local code must unwind it 194025828Ssam * back to PLUS/MINUS REG ICON 194125828Ssam * according to local conventions 194225828Ssam */ 194325828Ssam { 194425828Ssam cerror("address of OREG taken"); 194532886Sdonn /*NOTREACHED*/ 194625828Ssam } 194725828Ssam 194825828Ssam # ifndef ONEPASS 194925828Ssam main( argc, argv ) char *argv[]; { 195025828Ssam return( mainp2( argc, argv ) ); 195125828Ssam } 195225828Ssam # endif 195325828Ssam 195430360Ssam strip(p) register NODE *p; { 195530360Ssam NODE *q; 195630360Ssam 195730360Ssam /* strip nodes off the top when no side effects occur */ 195830360Ssam for( ; ; ) { 195930360Ssam switch( p->in.op ) { 196030360Ssam case SCONV: /* remove lint tidbits */ 196130360Ssam q = p->in.left; 196230360Ssam ncopy( p, q ); 196330360Ssam q->in.op = FREE; 196430360Ssam break; 196530360Ssam /* could probably add a few more here */ 196630360Ssam default: 196730360Ssam return; 196830360Ssam } 196930360Ssam } 197030360Ssam } 197130360Ssam 197225828Ssam myreader(p) register NODE *p; { 197330360Ssam strip( p ); /* strip off operations with no side effects */ 197432886Sdonn canon( p ); /* expands r-vals for fields */ 197525828Ssam walkf( p, hardops ); /* convert ops to function calls */ 197625828Ssam walkf( p, optim2 ); 197725828Ssam } 1978