125828Ssam #ifndef lint 2*32879Sdonn static char sccsid[] = "@(#)local2.c 1.17 (Berkeley) 12/10/87"; 325828Ssam #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 1925828Ssam where(c){ 2025828Ssam fprintf( stderr, "%s, line %d: ", filename, lineno ); 2125828Ssam } 2225828Ssam # endif 2325828Ssam 2425828Ssam lineid( l, fn ) char *fn; { 2525828Ssam /* identify line l and file fn */ 2625828Ssam printf( "# line %d, file %s\n", l, fn ); 2725828Ssam } 2825828Ssam 2925828Ssam int ent_mask; 3025828Ssam 3125828Ssam eobl2(){ 3225828Ssam register OFFSZ spoff; /* offset from stack pointer */ 3325828Ssam #ifndef FORT 3425828Ssam extern int ftlab1, ftlab2; 3525828Ssam #endif 3625828Ssam 3725828Ssam spoff = maxoff; 3825828Ssam spoff /= SZCHAR; 3925828Ssam SETOFF(spoff,4); 4025828Ssam #ifdef FORT 4125828Ssam #ifndef FLEXNAMES 4225828Ssam printf( " .set .F%d,%d\n", ftnno, spoff ); 4325828Ssam #else 4425828Ssam /* SHOULD BE L%d ... ftnno but must change pc/f77 */ 4525828Ssam printf( " .set LF%d,%d\n", ftnno, spoff ); 4625828Ssam #endif 4725828Ssam printf( " .set LWM%d,0x%x\n", ftnno, ent_mask&0x1ffc|0x1000); 4825828Ssam #else 4925828Ssam printf( " .set L%d,0x%x\n", ftnno, ent_mask&0x1ffc); 5025828Ssam printf( "L%d:\n", ftlab1); 5125828Ssam if( maxoff > AUTOINIT ) 5225828Ssam printf( " subl3 $%d,fp,sp\n", spoff); 5325828Ssam printf( " jbr L%d\n", ftlab2); 5425828Ssam #endif 5525828Ssam ent_mask = 0; 5625828Ssam maxargs = -1; 5725828Ssam } 5825828Ssam 5925828Ssam struct hoptab { int opmask; char * opstring; } ioptab[] = { 6025828Ssam 6125828Ssam PLUS, "add", 6225828Ssam MINUS, "sub", 6325828Ssam MUL, "mul", 6425828Ssam DIV, "div", 6525828Ssam MOD, "div", 6625828Ssam OR, "or", 6725828Ssam ER, "xor", 6825828Ssam AND, "and", 6925828Ssam -1, "" }; 7025828Ssam 7125828Ssam hopcode( f, o ){ 7225828Ssam /* output the appropriate string from the above table */ 7325828Ssam 7425828Ssam register struct hoptab *q; 7525828Ssam 7625828Ssam if(asgop(o)) 7725828Ssam o = NOASG o; 7825828Ssam for( q = ioptab; q->opmask>=0; ++q ){ 7925828Ssam if( q->opmask == o ){ 8025828Ssam if(f == 'E') 8125828Ssam printf( "e%s", q->opstring); 8225828Ssam else 8325828Ssam printf( "%s%c", q->opstring, tolower(f)); 8425828Ssam return; 8525828Ssam } 8625828Ssam } 8725828Ssam cerror( "no hoptab for %s", opst[o] ); 8825828Ssam } 8925828Ssam 9025828Ssam char * 9125828Ssam rnames[] = { /* keyed to register number tokens */ 9225828Ssam 9325828Ssam "r0", "r1", 9425828Ssam "r2", "r3", "r4", "r5", 9525828Ssam "r6", "r7", "r8", "r9", "r10", "r11", 9625828Ssam "r12", "fp", "sp", "pc", 9725828Ssam }; 9825828Ssam 9925828Ssam /* output register name and update entry mask */ 10025828Ssam char * 10125828Ssam rname(r) 10225828Ssam register int r; 10325828Ssam { 10425828Ssam 10525828Ssam ent_mask |= 1<<r; 10625828Ssam return(rnames[r]); 10725828Ssam } 10825828Ssam 10925828Ssam int rstatus[] = { 11025828Ssam SAREG|STAREG, SAREG|STAREG, 11125828Ssam SAREG|STAREG, SAREG|STAREG, SAREG|STAREG, SAREG|STAREG, 11225828Ssam SAREG, SAREG, SAREG, SAREG, SAREG, SAREG, 11325828Ssam SAREG, SAREG, SAREG, SAREG, 11425828Ssam }; 11525828Ssam 11625828Ssam tlen(p) NODE *p; 11725828Ssam { 11825828Ssam switch(p->in.type) { 11925828Ssam case CHAR: 12025828Ssam case UCHAR: 12125828Ssam return(1); 12225828Ssam 12325828Ssam case SHORT: 12425828Ssam case USHORT: 12525828Ssam return(2); 12625828Ssam 12725828Ssam case DOUBLE: 12825828Ssam return(8); 12925828Ssam 13025828Ssam default: 13125828Ssam return(4); 13225828Ssam } 13325828Ssam } 13425828Ssam 13530360Ssam anyfloat(p, q) 13630360Ssam NODE *p, *q; 13730360Ssam { 13830360Ssam register TWORD tp, tq; 13930360Ssam 14030360Ssam tp = p->in.type; 14130360Ssam tq = q->in.type; 14230360Ssam return (tp == FLOAT || tp == DOUBLE || tq == FLOAT || tq == DOUBLE); 14330360Ssam } 14430360Ssam 14525828Ssam prtype(n) NODE *n; 14625828Ssam { 14725828Ssam switch (n->in.type) 14825828Ssam { 14925828Ssam 15025828Ssam case DOUBLE: 15126162Ssam putchar('d'); 15225828Ssam return; 15325828Ssam 15425828Ssam case FLOAT: 15526162Ssam putchar('f'); 15625828Ssam return; 15725828Ssam 15825828Ssam case INT: 15925828Ssam case UNSIGNED: 16026162Ssam putchar('l'); 16125828Ssam return; 16225828Ssam 16325828Ssam case SHORT: 16425828Ssam case USHORT: 16526162Ssam putchar('w'); 16625828Ssam return; 16725828Ssam 16825828Ssam case CHAR: 16925828Ssam case UCHAR: 17026162Ssam putchar('b'); 17125828Ssam return; 17225828Ssam 17325828Ssam default: 17425828Ssam if ( !ISPTR( n->in.type ) ) cerror("zzzcode- bad type"); 17525828Ssam else { 17626162Ssam putchar('l'); 17725828Ssam return; 17825828Ssam } 17925828Ssam } 18025828Ssam } 18125828Ssam 18225828Ssam zzzcode( p, c ) register NODE *p; { 18325828Ssam register int m; 18425828Ssam int val; 18525828Ssam switch( c ){ 18625828Ssam 18725828Ssam case 'N': /* logical ops, turned into 0-1 */ 18825828Ssam /* use register given by register 1 */ 18925828Ssam cbgen( 0, m=getlab(), 'I' ); 19025828Ssam deflab( p->bn.label ); 19125828Ssam printf( " clrl %s\n", rname(getlr( p, '1' )->tn.rval) ); 19225828Ssam deflab( m ); 19325828Ssam return; 19425828Ssam 19525828Ssam case 'P': 19625828Ssam cbgen( p->in.op, p->bn.label, c ); 19725828Ssam return; 19825828Ssam 19932876Sdonn case 'G': /* i *= f; asgops with int lhs and float rhs */ 20025828Ssam { 20132876Sdonn register NODE *l, *r, *s; 20232876Sdonn int lt, rt; 20325828Ssam 20432876Sdonn l = p->in.left; 20532876Sdonn r = p->in.right; 20632876Sdonn s = talloc(); 20732876Sdonn rt = r->in.type; 20832876Sdonn lt = l->in.type; 20925828Ssam 21032876Sdonn if (lt != INT && lt != UNSIGNED) { 21132876Sdonn s->in.op = SCONV; 21232876Sdonn s->in.left = l; 21332876Sdonn s->in.type = ISUNSIGNED(lt) ? UNSIGNED : INT; 21432876Sdonn zzzcode(s, 'U'); 21532876Sdonn putstr("\n\t"); 21625828Ssam } 21732876Sdonn 21832876Sdonn if (ISUNSIGNED(lt)) { 21932876Sdonn s->in.op = SCONV; 22032876Sdonn s->in.left = lt == UNSIGNED ? l : resc; 22132876Sdonn s->in.type = rt; 22232876Sdonn unsigned_to_float(s); 22332876Sdonn } else { 22432876Sdonn putstr("cvl"); 22532876Sdonn prtype(r); 22632876Sdonn putchar('\t'); 22732876Sdonn adrput(lt == INT ? l : resc); 22832876Sdonn } 22932876Sdonn putstr("\n\t"); 23032876Sdonn 23132876Sdonn hopcode(rt == FLOAT ? 'F' : 'D', p->in.op); 23226162Ssam putchar('\t'); 23325828Ssam adrput(r); 23432876Sdonn 23532876Sdonn if (ISUNSIGNED(lt)) { 23632876Sdonn putstr("\n\t"); 23732876Sdonn s->in.op = SCONV; 23832876Sdonn s->in.left = r; /* we need only the type */ 23932876Sdonn s->in.type = UNSIGNED; 24032876Sdonn float_to_unsigned(s); 24132876Sdonn } else { 24232876Sdonn putstr("\n\tcv"); 24332876Sdonn prtype(r); 24432876Sdonn putstr("l\t"); 24532876Sdonn if (lt == INT) 24632876Sdonn adrput(l); 24732876Sdonn else 24832876Sdonn adrput(resc); 24932876Sdonn } 25032876Sdonn if (lt != INT) { 25132876Sdonn putstr("\n\t"); 25232876Sdonn s->in.op = ASSIGN; 25332876Sdonn s->in.left = l; 25432876Sdonn s->in.right = resc; 25532876Sdonn s->in.type = lt; 25632876Sdonn zzzcode(s, 'U'); 25732876Sdonn } 25832876Sdonn 25932876Sdonn s->in.op = FREE; 26025828Ssam return; 26125828Ssam } 26225828Ssam 26325828Ssam case 'B': /* get oreg value in temp register for shift */ 26425828Ssam { 26525828Ssam register NODE *r; 26625828Ssam if (xdebug) eprint(p, 0, &val, &val); 26725828Ssam r = p->in.right; 26825828Ssam if( tlen(r) == sizeof(int) && r->in.type != FLOAT ) 26926162Ssam putstr("movl"); 27025828Ssam else { 27126162Ssam putstr(ISUNSIGNED(r->in.type) ? "movz" : "cvt"); 27225828Ssam prtype(r); 27326162Ssam putchar('l'); 27425828Ssam } 27525828Ssam return; 27625828Ssam } 27725828Ssam 27825828Ssam case 'C': /* num bytes pushed on arg stack */ 27925828Ssam { 28025828Ssam extern int gc_numbytes; 28125828Ssam extern int xdebug; 28225828Ssam 28325828Ssam if (xdebug) printf("->%d<-",gc_numbytes); 28425828Ssam 28525828Ssam printf("call%c $%d", 28625828Ssam (p->in.left->in.op==ICON && gc_numbytes<60)?'f':'s', 28725828Ssam gc_numbytes+4); 28825828Ssam /* dont change to double (here's the only place to catch it) */ 28925828Ssam if(p->in.type == FLOAT) 29025828Ssam rtyflg = 1; 29125828Ssam return; 29225828Ssam } 29325828Ssam 29425828Ssam case 'D': /* INCR and DECR */ 29532876Sdonn zzzcode(p->in.left, 'U'); 29626162Ssam putstr("\n "); 29725828Ssam 29825828Ssam case 'E': /* INCR and DECR, FOREFF */ 29925828Ssam if (p->in.right->tn.lval == 1) 30025828Ssam { 30126162Ssam putstr(p->in.op == INCR ? "inc" : "dec"); 30225828Ssam prtype(p->in.left); 30326162Ssam putchar('\t'); 30425828Ssam adrput(p->in.left); 30525828Ssam return; 30625828Ssam } 30726162Ssam putstr(p->in.op == INCR ? "add" : "sub"); 30825828Ssam prtype(p->in.left); 30926162Ssam putstr("2 "); 31025828Ssam adrput(p->in.right); 31126162Ssam putchar(','); 31225828Ssam adrput(p->in.left); 31325828Ssam return; 31425828Ssam 31525828Ssam case 'F': /* masked constant for fields */ 31625947Ssam printf(ACONFMT, (p->in.right->tn.lval&((1<<fldsz)-1))<<fldshf); 31725828Ssam return; 31825828Ssam 31925828Ssam case 'H': /* opcode for shift */ 32025828Ssam if(p->in.op == LS || p->in.op == ASG LS) 32126162Ssam putstr("shll"); 32225828Ssam else if(ISUNSIGNED(p->in.left->in.type)) 32326162Ssam putstr("shrl"); 32425828Ssam else 32526162Ssam putstr("shar"); 32625828Ssam return; 32725828Ssam 32825828Ssam case 'L': /* type of left operand */ 32925828Ssam case 'R': /* type of right operand */ 33025828Ssam { 33125828Ssam register NODE *n; 33225828Ssam extern int xdebug; 33325828Ssam 33425828Ssam n = getlr ( p, c); 33525828Ssam if (xdebug) printf("->%d<-", n->in.type); 33625828Ssam 33725828Ssam prtype(n); 33825828Ssam return; 33925828Ssam } 34025828Ssam 34130360Ssam case 'M': { /* initiate ediv for mod and unsigned div */ 34225828Ssam register char *r; 34325828Ssam m = getlr(p, '1')->tn.rval; 34425828Ssam r = rname(m); 34525828Ssam printf("\tclrl\t%s\n\tmovl\t", r); 34625828Ssam adrput(p->in.left); 34725828Ssam printf(",%s\n", rname(m+1)); 34825828Ssam if(!ISUNSIGNED(p->in.type)) { /* should be MOD */ 34925828Ssam m = getlab(); 35025828Ssam printf("\tjgeq\tL%d\n\tmnegl\t$1,%s\n", m, r); 35125828Ssam deflab(m); 35225828Ssam } 35325828Ssam return; 35430360Ssam } 35525828Ssam 35630360Ssam case 'T': { /* rounded structure length for arguments */ 35730360Ssam int size = p->stn.stsize; 35825828Ssam SETOFF( size, 4); 35925828Ssam printf("movab -%d(sp),sp", size); 36025828Ssam return; 36130360Ssam } 36225828Ssam 36325828Ssam case 'S': /* structure assignment */ 36425977Ssam stasg(p); 36525977Ssam break; 36625828Ssam 36729672Ssam case 'X': /* multiplication for short and char */ 36829672Ssam if (ISUNSIGNED(p->in.left->in.type)) 36929672Ssam printf("\tmovz"); 37029672Ssam else 37129672Ssam printf("\tcvt"); 37229672Ssam zzzcode(p, 'L'); 37329672Ssam printf("l\t"); 37429672Ssam adrput(p->in.left); 37529672Ssam printf(","); 37629672Ssam adrput(&resc[0]); 37729672Ssam printf("\n"); 37829672Ssam if (ISUNSIGNED(p->in.right->in.type)) 37929672Ssam printf("\tmovz"); 38029672Ssam else 38129672Ssam printf("\tcvt"); 38229672Ssam zzzcode(p, 'R'); 38329672Ssam printf("l\t"); 38429672Ssam adrput(p->in.right); 38529672Ssam printf(","); 38629672Ssam adrput(&resc[1]); 38729672Ssam printf("\n"); 38829672Ssam return; 38929672Ssam 39030360Ssam case 'U': /* SCONV */ 39130360Ssam case 'V': /* SCONV with FORCC */ 39230360Ssam sconv(p, c == 'V'); 39330360Ssam break; 39430360Ssam 395*32879Sdonn case 'W': { /* SCONV or ASSIGN float/double => unsigned */ 396*32879Sdonn NODE *src = p->in.op == SCONV ? p->in.left : p->in.right; 397*32879Sdonn 39832876Sdonn putstr("ld"); 399*32879Sdonn prtype(src); 40032876Sdonn putchar('\t'); 401*32879Sdonn adrput(src); 40232876Sdonn putstr("\n\t"); 40332876Sdonn float_to_unsigned(p); 40432876Sdonn break; 405*32879Sdonn } 40632876Sdonn 407*32879Sdonn case 'Y': /* SCONV or ASSIGN unsigned => float/double */ 40832876Sdonn unsigned_to_float(p); /* stores into accumulator */ 40932876Sdonn putstr("\n\tst"); 41032876Sdonn prtype(p); 41132876Sdonn putchar('\t'); 412*32879Sdonn if (p->in.op == SCONV) 413*32879Sdonn adrput(resc); 414*32879Sdonn else 415*32879Sdonn adrput(p->in.left); 416*32879Sdonn rtyflg = 1; 41732876Sdonn break; 41832876Sdonn 41930360Ssam case 'Z': 42030360Ssam p = p->in.right; 42130360Ssam switch (p->in.type) { 42230360Ssam case SHORT: { 42330360Ssam short w = p->tn.lval; 42430360Ssam p->tn.lval = w; 42530360Ssam break; 42630360Ssam } 42730360Ssam case CHAR: { 42830360Ssam char c = p->tn.lval; 42930360Ssam p->tn.lval = c; 43030360Ssam break; 43130360Ssam } 43230360Ssam } 43330360Ssam printf("$%d", p->tn.lval); 43430360Ssam break; 43530360Ssam 43625977Ssam default: 43725977Ssam cerror( "illegal zzzcode" ); 43825977Ssam } 43930360Ssam } 44025828Ssam 44125977Ssam #define MOVB(dst, src, off) { \ 44226162Ssam putstr("\tmovb\t"); upput(src, off); putchar(','); \ 44325977Ssam upput(dst, off); putchar('\n'); \ 44425977Ssam } 44525977Ssam #define MOVW(dst, src, off) { \ 44626162Ssam putstr("\tmovw\t"); upput(src, off); putchar(','); \ 44725977Ssam upput(dst, off); putchar('\n'); \ 44825977Ssam } 44925977Ssam #define MOVL(dst, src, off) { \ 45026162Ssam putstr("\tmovl\t"); upput(src, off); putchar(','); \ 45125977Ssam upput(dst, off); putchar('\n'); \ 45225977Ssam } 45325977Ssam /* 45425977Ssam * Generate code for a structure assignment. 45525977Ssam */ 45625977Ssam stasg(p) 45725977Ssam register NODE *p; 45825977Ssam { 45925977Ssam register NODE *l, *r; 46025977Ssam register int size; 46125828Ssam 46225977Ssam switch (p->in.op) { 46325977Ssam case STASG: /* regular assignment */ 46425977Ssam l = p->in.left; 46525977Ssam r = p->in.right; 46625977Ssam break; 46725977Ssam case STARG: /* place arg on the stack */ 46825977Ssam l = getlr(p, '3'); 46925977Ssam r = p->in.left; 47025977Ssam break; 47125977Ssam default: 47225977Ssam cerror("STASG bad"); 47325977Ssam /*NOTREACHED*/ 47425977Ssam } 47525977Ssam /* 47625977Ssam * Pun source for use in code generation. 47725977Ssam */ 47825977Ssam switch (r->in.op) { 47925977Ssam case ICON: 48025977Ssam r->in.op = NAME; 48125977Ssam break; 48225977Ssam case REG: 48325977Ssam r->in.op = OREG; 48425977Ssam break; 48525977Ssam default: 48625977Ssam cerror( "STASG-r" ); 48725977Ssam /*NOTREACHED*/ 48825977Ssam } 48925977Ssam size = p->stn.stsize; 49025977Ssam if (size <= 0 || size > 65535) 49125977Ssam cerror("structure size out of range"); 49225977Ssam /* 49325977Ssam * Generate optimized code based on structure size 49425977Ssam * and alignment properties.... 49525977Ssam */ 49625977Ssam switch (size) { 49725828Ssam 49825977Ssam case 1: 49926162Ssam putstr("\tmovb\t"); 50025977Ssam optimized: 50125977Ssam adrput(r); 50226162Ssam putchar(','); 50325977Ssam adrput(l); 50426162Ssam putchar('\n'); 50525977Ssam break; 50625828Ssam 50725977Ssam case 2: 50825977Ssam if (p->stn.stalign != 2) { 50925977Ssam MOVB(l, r, SZCHAR); 51026162Ssam putstr("\tmovb\t"); 51125977Ssam } else 51226162Ssam putstr("\tmovw\t"); 51325977Ssam goto optimized; 51425977Ssam 51525977Ssam case 4: 51625977Ssam if (p->stn.stalign != 4) { 51725977Ssam if (p->stn.stalign != 2) { 51825977Ssam MOVB(l, r, 3*SZCHAR); 51925977Ssam MOVB(l, r, 2*SZCHAR); 52025977Ssam MOVB(l, r, 1*SZCHAR); 52126162Ssam putstr("\tmovb\t"); 52225947Ssam } else { 52325977Ssam MOVW(l, r, SZSHORT); 52426162Ssam putstr("\tmovw\t"); 52525828Ssam } 52625977Ssam } else 52726162Ssam putstr("\tmovl\t"); 52825977Ssam goto optimized; 52925828Ssam 53025977Ssam case 6: 53125977Ssam if (p->stn.stalign != 2) 53225977Ssam goto movblk; 53325977Ssam MOVW(l, r, 2*SZSHORT); 53425977Ssam MOVW(l, r, 1*SZSHORT); 53526162Ssam putstr("\tmovw\t"); 53625977Ssam goto optimized; 53725977Ssam 53825977Ssam case 8: 53925977Ssam if (p->stn.stalign == 4) { 54025977Ssam MOVL(l, r, SZLONG); 54126162Ssam putstr("\tmovl\t"); 54225977Ssam goto optimized; 54325977Ssam } 54425977Ssam /* fall thru...*/ 54525977Ssam 54625977Ssam default: 54725977Ssam movblk: 54825977Ssam /* 54925977Ssam * Can we ever get a register conflict with R1 here? 55025977Ssam */ 55126162Ssam putstr("\tmovab\t"); 55225977Ssam adrput(l); 55326162Ssam putstr(",r1\n\tmovab\t"); 55425977Ssam adrput(r); 55525977Ssam printf(",r0\n\tmovl\t$%d,r2\n\tmovblk\n", size); 55625977Ssam rname(R2); 55725828Ssam break; 55825977Ssam } 55925977Ssam /* 56025977Ssam * Reverse above pun for reclaim. 56125977Ssam */ 56225977Ssam if (r->in.op == NAME) 56325977Ssam r->in.op = ICON; 56425977Ssam else if (r->in.op == OREG) 56525977Ssam r->in.op = REG; 56625977Ssam } 56725828Ssam 56825977Ssam /* 56925977Ssam * Output the address of the second item in the 57025977Ssam * pair pointed to by p. 57125977Ssam */ 57225977Ssam upput(p, size) 57325977Ssam register NODE *p; 57425977Ssam { 57525977Ssam CONSZ save; 57625977Ssam 57725977Ssam if (p->in.op == FLD) 57825977Ssam p = p->in.left; 57925977Ssam switch (p->in.op) { 58025977Ssam 58125977Ssam case NAME: 58225977Ssam case OREG: 58325977Ssam save = p->tn.lval; 58425977Ssam p->tn.lval += size/SZCHAR; 58525977Ssam adrput(p); 58625977Ssam p->tn.lval = save; 58725977Ssam break; 58825977Ssam 58925977Ssam case REG: 59025977Ssam if (size == SZLONG) { 59126162Ssam putstr(rname(p->tn.rval+1)); 59225977Ssam break; 59325977Ssam } 59425977Ssam /* fall thru... */ 59525977Ssam 59625828Ssam default: 59725977Ssam cerror("illegal upper address op %s size %d", 59825977Ssam opst[p->tn.op], size); 59925977Ssam /*NOTREACHED*/ 60025828Ssam } 60125977Ssam } 60225828Ssam 60330360Ssam /* 60432876Sdonn * Convert a float or double in the accumulator into an unsigned int. 60532876Sdonn * Unlike the vax, the tahoe stores 0 into the destination 60632876Sdonn * on a conversion of > 2 ** 31, so we compensate. 60732876Sdonn */ 60832876Sdonn float_to_unsigned(p) 60932876Sdonn NODE *p; 61032876Sdonn { 61132876Sdonn register NODE *l = p->in.left; 61232876Sdonn int label1 = getlab(); 61332876Sdonn int label2 = getlab(); 61432876Sdonn int label3 = getlab(); 615*32879Sdonn NODE *src, *dst; 61632876Sdonn 617*32879Sdonn if (p->in.op == SCONV) { 618*32879Sdonn src = p->in.left; 619*32879Sdonn dst = resc; 620*32879Sdonn } else { 621*32879Sdonn src = p->in.right; 622*32879Sdonn dst = p->in.left; 623*32879Sdonn } 624*32879Sdonn 62532876Sdonn printf(".data\n\t.align\t2\nL%d:\n\t.long\t0x50000000", label1); 626*32879Sdonn if (src->in.type == DOUBLE) 627*32879Sdonn putstr(", 0x00000000 # .double"); 628*32879Sdonn else 629*32879Sdonn putstr(" # .float"); 630*32879Sdonn putstr(" 2147483648\n\t.text\n\tcmp"); 631*32879Sdonn prtype(src); 63232876Sdonn printf("\tL%d\n\tjlss\tL%d\n\tsub", label1, label2); 633*32879Sdonn prtype(src); 63432876Sdonn printf("\tL%d\n\tcv", label1); 635*32879Sdonn prtype(src); 63632876Sdonn putstr("l\t"); 637*32879Sdonn adrput(dst); 63832876Sdonn putstr("\n\taddl2\t$-2147483648,"); 639*32879Sdonn adrput(dst); 64032876Sdonn printf("\n\tjbr\tL%d\nL%d:\n\tcv", label3, label2); 641*32879Sdonn prtype(src); 64232876Sdonn putstr("l\t"); 643*32879Sdonn adrput(dst); 64432876Sdonn printf("\nL%d:", label3); 64532876Sdonn } 64632876Sdonn 64732876Sdonn /* 64832876Sdonn * Convert an unsigned int into a float or double, leaving the result 64932876Sdonn * in the accumulator. 65032876Sdonn */ 65132876Sdonn unsigned_to_float(p) 65232876Sdonn register NODE *p; 65332876Sdonn { 65432876Sdonn int label1 = getlab(); 65532876Sdonn int label2 = getlab(); 656*32879Sdonn NODE *src, *dst; 65732876Sdonn 658*32879Sdonn if (p->in.op == SCONV) { 659*32879Sdonn src = p->in.left; 660*32879Sdonn dst = resc; 661*32879Sdonn } else { 662*32879Sdonn src = p->in.right; 663*32879Sdonn dst = p->in.left; 664*32879Sdonn } 665*32879Sdonn 66632876Sdonn printf(".data\n\t.align\t2\nL%d:\n\t.long\t0x50800000", label2); 66732876Sdonn if (p->in.type == DOUBLE) 668*32879Sdonn putstr(", 0x00000000 # .double"); 669*32879Sdonn else 670*32879Sdonn putstr(" # .float"); 671*32879Sdonn putstr(" 4294967296\n\t.text\n\tmovl\t"); 672*32879Sdonn adrput(src); 67332876Sdonn putchar(','); 674*32879Sdonn adrput(dst); 67532876Sdonn putstr("\n\tcvl"); 67632876Sdonn prtype(p); 67732876Sdonn putchar('\t'); 678*32879Sdonn adrput(dst); 679*32879Sdonn printf("\n\tjgeq\tL%d\n\tadd", label1); 680*32879Sdonn prtype(p); 681*32879Sdonn printf("\tL%d\nL%d:", label2, label1); 68232876Sdonn } 68332876Sdonn 68432876Sdonn /* 68532875Sdonn * Prlen() is a cheap prtype()... 68632875Sdonn */ 68732875Sdonn static char convtab[SZINT/SZCHAR + 1] = { 68832875Sdonn '?', 'b', 'w', '?', 'l' 68932875Sdonn }; 69032875Sdonn #define prlen(len) putchar(convtab[len]) 69132875Sdonn 69232875Sdonn 69332875Sdonn /* 69432873Sdonn * Generate code for integral scalar conversions. 69532875Sdonn * Some of this code is designed to work around a tahoe misfeature 69632875Sdonn * that causes sign- and zero- extension to be defeated in 69732875Sdonn * certain circumstances. 69832875Sdonn * Basically if the source operand of a CVT or MOVZ instruction is 69932875Sdonn * shorter than the destination, and the source is a register 70032875Sdonn * or an immediate constant, sign- and zero- extension are 70132875Sdonn * ignored and the high bits of the source are copied. (Note 70232875Sdonn * that zero-extension is not a problem for immediate 70332875Sdonn * constants.) 70432873Sdonn */ 70532873Sdonn sconv(p, forcc) 70632873Sdonn NODE *p; 70732873Sdonn int forcc; 70832873Sdonn { 70932873Sdonn register NODE *src, *dst; 71032873Sdonn register NODE *tmp; 71132873Sdonn register int srclen, dstlen; 71232873Sdonn int srctype, dsttype; 71332873Sdonn int val; 71430360Ssam 71532873Sdonn if (p->in.op == ASSIGN) { 716*32879Sdonn src = p->in.right; 717*32879Sdonn dst = p->in.left; 71832873Sdonn dstlen = tlen(dst); 71932873Sdonn dsttype = dst->in.type; 720*32879Sdonn } else if (p->in.op == SCONV) { 721*32879Sdonn src = p->in.left; 722*32879Sdonn dst = resc; 72332873Sdonn dstlen = tlen(p); 72432873Sdonn dsttype = p->in.type; 725*32879Sdonn } else /* if (p->in.op == OPLEAF) */ { 726*32879Sdonn src = p; 727*32879Sdonn dst = resc; 728*32879Sdonn dstlen = SZINT/SZCHAR; 729*32879Sdonn dsttype = ISUNSIGNED(src->in.type) ? UNSIGNED : INT; 73032873Sdonn } 73132873Sdonn 73232875Sdonn if (src->in.op == REG) { 73332875Sdonn srclen = SZINT/SZCHAR; 73432875Sdonn srctype = ISUNSIGNED(src->in.type) ? UNSIGNED : INT; 73532875Sdonn } else { 73632875Sdonn srclen = tlen(src); 73732875Sdonn srctype = src->in.type; 73832875Sdonn } 73932873Sdonn 74032875Sdonn if (src->in.op == ICON) { 74132875Sdonn if (src->tn.lval == 0) { 74232875Sdonn putstr("clr"); 74332875Sdonn prtype(dst); 74432875Sdonn putchar('\t'); 74532875Sdonn adrput(dst); 74632875Sdonn return; 74732875Sdonn } 74832875Sdonn if (dstlen < srclen) { 74932875Sdonn switch (dsttype) { 75032875Sdonn case CHAR: 75132875Sdonn src->tn.lval = (char) src->tn.lval; 75232875Sdonn break; 75332875Sdonn case UCHAR: 75432875Sdonn src->tn.lval = (unsigned char) src->tn.lval; 75532875Sdonn break; 75632875Sdonn case SHORT: 75732875Sdonn src->tn.lval = (short) src->tn.lval; 75832875Sdonn break; 75932875Sdonn case USHORT: 76032875Sdonn src->tn.lval = (unsigned short) src->tn.lval; 76132875Sdonn break; 76232875Sdonn } 76332875Sdonn } 76432875Sdonn if (dst->in.op == REG) { 76532875Sdonn dsttype = INT; 76632875Sdonn dstlen = SZINT/SZCHAR; 76732875Sdonn } 76832875Sdonn srctype = dsttype; 76932875Sdonn srclen = dstlen; 77032875Sdonn } 77132875Sdonn 77232873Sdonn if (srclen < dstlen) { 77332873Sdonn if (srctype == CHAR && dsttype == USHORT && dst->in.op == REG) { 77432873Sdonn /* (unsigned short) c; => sign extend to 16 bits */ 77532874Sdonn putstr("cvtbl\t"); 77632873Sdonn adrput(src); 77732873Sdonn putstr(",-(sp)\n\tmovzwl\t2(sp),"); 77832873Sdonn adrput(dst); 77932873Sdonn putstr("\n\tmovab\t4(sp),sp"); 78032873Sdonn if (forcc) { 78132873Sdonn /* inverted test */ 78232873Sdonn putstr("\n\tcmpl\t$0,"); 78332873Sdonn adrput(dst); 78432873Sdonn } 78532873Sdonn return; 78632873Sdonn } 78732873Sdonn genconv(ISUNSIGNED(srctype), 78832873Sdonn srclen, dst->in.op == REG ? SZINT/SZCHAR : dstlen, 78932873Sdonn src, dst); 79032873Sdonn return; 79132873Sdonn } 79232873Sdonn 79332873Sdonn if (srclen > dstlen && dst->in.op == REG) { 79432875Sdonn /* if dst is a register, the result must look like an int */ 79532873Sdonn if (src->in.op == REG) { 79632873Sdonn if (ISUNSIGNED(dsttype)) { 79732873Sdonn val = (1 << dstlen * SZCHAR) - 1; 79832873Sdonn if (src->tn.rval == dst->tn.rval) 79932873Sdonn /* conversion in place */ 80032874Sdonn printf("andl2\t$%#x,", val); 80132873Sdonn else { 80232874Sdonn printf("andl3\t$%#x,", val); 80332873Sdonn adrput(src); 80432873Sdonn putchar(','); 80532873Sdonn } 80632873Sdonn adrput(dst); 80732873Sdonn return; 80832873Sdonn } 80932875Sdonn /* 81032875Sdonn * Sign extension in register can also be 81132875Sdonn * accomplished by shifts, but unfortunately 81232875Sdonn * shifts are extremely slow, due to the lack 81332875Sdonn * of a barrel shifter. 81432875Sdonn */ 81532875Sdonn putstr("pushl\t"); 81632873Sdonn adrput(src); 81732875Sdonn putstr("\n\tcvt"); 81832875Sdonn prlen(dstlen); 81932875Sdonn printf("l\t%d(sp),", SZINT/SZCHAR - dstlen); 82032873Sdonn adrput(dst); 82132875Sdonn putstr("\n\tmovab\t4(sp),sp"); 82232875Sdonn if (forcc) { 82332875Sdonn /* inverted test */ 82432875Sdonn putstr("\n\tcmpl\t$0,"); 82532875Sdonn adrput(dst); 82632875Sdonn } 82732873Sdonn return; 82832873Sdonn } 82932873Sdonn tmp = talloc(); 83032873Sdonn if ((src->in.op == UNARY MUL && 83132873Sdonn ((src->in.left->in.op == NAME || 83232873Sdonn (src->in.left->in.op == ICON)))) || 83332873Sdonn (src->in.op == OREG && !R2TEST(src->tn.rval))) { 83432873Sdonn /* we can increment src's address & pun it */ 83532873Sdonn *tmp = *src; 83632873Sdonn tmp->tn.lval += srclen - dstlen; 83732873Sdonn } else { 83832873Sdonn /* we must store src's address */ 83932873Sdonn *tmp = *dst; 84032875Sdonn putstr("mova"); 84132875Sdonn prlen(srclen); 84232875Sdonn putchar('\t'); 84332873Sdonn adrput(src); 84432873Sdonn putchar(','); 84532873Sdonn adrput(tmp); 84632874Sdonn putstr("\n\t"); 84732873Sdonn tmp->tn.op = OREG; 84832873Sdonn tmp->tn.lval = srclen - dstlen; 84932873Sdonn } 85032873Sdonn genconv(ISUNSIGNED(dsttype), dstlen, SZINT/SZCHAR, tmp, dst); 85132873Sdonn tmp->in.op = FREE; 85232873Sdonn return; 85332873Sdonn } 85432873Sdonn 85532873Sdonn genconv(ISUNSIGNED(dsttype), 85632873Sdonn srclen, dst->in.op == REG ? SZINT/SZCHAR : dstlen, 85732873Sdonn src, dst); 85832873Sdonn } 85932873Sdonn 86032873Sdonn genconv(usrc, srclen, dstlen, src, dst) 86132875Sdonn int usrc; 86232875Sdonn register int srclen, dstlen; 86332873Sdonn NODE *src, *dst; 86432873Sdonn { 86532873Sdonn if (srclen != dstlen) { 86632873Sdonn if (usrc && srclen < dstlen) 86732874Sdonn putstr("movz"); 86832873Sdonn else 86932874Sdonn putstr("cvt"); 87032875Sdonn prlen(srclen); 87132873Sdonn } else 87232874Sdonn putstr("mov"); 87332875Sdonn prlen(dstlen); 87432873Sdonn putchar('\t'); 87532873Sdonn adrput(src); 87632873Sdonn putchar(','); 87732873Sdonn adrput(dst); 87832873Sdonn } 87932873Sdonn 88025828Ssam rmove( rt, rs, t ) TWORD t;{ 88125828Ssam printf( " movl %s,%s\n", rname(rs), rname(rt) ); 88225828Ssam if(t==DOUBLE) 88325828Ssam printf( " movl %s,%s\n", rname(rs+1), rname(rt+1) ); 88425828Ssam } 88525828Ssam 88625828Ssam struct respref 88725828Ssam respref[] = { 88825828Ssam INTAREG|INTBREG, INTAREG|INTBREG, 88925828Ssam INAREG|INBREG, INAREG|INBREG|SOREG|STARREG|STARNM|SNAME|SCON, 89025828Ssam INTEMP, INTEMP, 89125828Ssam FORARG, FORARG, 89225828Ssam INTEMP, INTAREG|INAREG|INTBREG|INBREG|SOREG|STARREG|STARNM, 89325828Ssam 0, 0 }; 89425828Ssam 89525828Ssam setregs(){ /* set up temporary registers */ 89625828Ssam fregs = 6; /* tbl- 6 free regs on Tahoe (0-5) */ 89725828Ssam } 89825828Ssam 89926076Ssam #ifndef szty 90025828Ssam szty(t) TWORD t;{ /* size, in registers, needed to hold thing of type t */ 90125828Ssam return(t==DOUBLE ? 2 : 1 ); 90225828Ssam } 90326076Ssam #endif 90425828Ssam 90525828Ssam rewfld( p ) NODE *p; { 90625828Ssam return(1); 90725828Ssam } 90825828Ssam 90925828Ssam callreg(p) NODE *p; { 91025828Ssam return( R0 ); 91125828Ssam } 91225828Ssam 91325828Ssam base( p ) register NODE *p; { 91425828Ssam register int o = p->in.op; 91525828Ssam 91625828Ssam if( (o==ICON && p->in.name[0] != '\0')) return( 100 ); /* ie no base reg */ 91725828Ssam if( o==REG ) return( p->tn.rval ); 91825828Ssam if( (o==PLUS || o==MINUS) && p->in.left->in.op == REG && p->in.right->in.op==ICON) 91925828Ssam return( p->in.left->tn.rval ); 92025828Ssam if( o==OREG && !R2TEST(p->tn.rval) && (p->in.type==INT || p->in.type==UNSIGNED || ISPTR(p->in.type)) ) 92125828Ssam return( p->tn.rval + 0200*1 ); 92225828Ssam return( -1 ); 92325828Ssam } 92425828Ssam 92525828Ssam offset( p, tyl ) register NODE *p; int tyl; { 92625828Ssam 92725828Ssam if(tyl > 8) return( -1 ); 92825828Ssam if( tyl==1 && p->in.op==REG && (p->in.type==INT || p->in.type==UNSIGNED) ) return( p->tn.rval ); 92925828Ssam if( (p->in.op==LS && p->in.left->in.op==REG && (p->in.left->in.type==INT || p->in.left->in.type==UNSIGNED) && 93025828Ssam (p->in.right->in.op==ICON && p->in.right->in.name[0]=='\0') 93125828Ssam && (1<<p->in.right->tn.lval)==tyl)) 93225828Ssam return( p->in.left->tn.rval ); 93325828Ssam return( -1 ); 93425828Ssam } 93525828Ssam 93625828Ssam makeor2( p, q, b, o) register NODE *p, *q; register int b, o; { 93725828Ssam register NODE *t; 93825828Ssam register int i; 93925828Ssam NODE *f; 94025828Ssam 94125828Ssam p->in.op = OREG; 94225828Ssam f = p->in.left; /* have to free this subtree later */ 94325828Ssam 94425828Ssam /* init base */ 94525828Ssam switch (q->in.op) { 94625828Ssam case ICON: 94725828Ssam case REG: 94825828Ssam case OREG: 94925828Ssam t = q; 95025828Ssam break; 95125828Ssam 95225828Ssam case MINUS: 95325828Ssam q->in.right->tn.lval = -q->in.right->tn.lval; 95425828Ssam case PLUS: 95525828Ssam t = q->in.right; 95625828Ssam break; 95725828Ssam 95825828Ssam case UNARY MUL: 95925828Ssam t = q->in.left->in.left; 96025828Ssam break; 96125828Ssam 96225828Ssam default: 96325828Ssam cerror("illegal makeor2"); 96425828Ssam } 96525828Ssam 96625828Ssam p->tn.lval = t->tn.lval; 96725828Ssam #ifndef FLEXNAMES 96825828Ssam for(i=0; i<NCHNAM; ++i) 96925828Ssam p->in.name[i] = t->in.name[i]; 97025828Ssam #else 97125828Ssam p->in.name = t->in.name; 97225828Ssam #endif 97325828Ssam 97425828Ssam /* init offset */ 97525828Ssam p->tn.rval = R2PACK( (b & 0177), o, (b>>7) ); 97625828Ssam 97725828Ssam tfree(f); 97825828Ssam return; 97925828Ssam } 98025828Ssam 98125828Ssam canaddr( p ) NODE *p; { 98225828Ssam register int o = p->in.op; 98325828Ssam 98425828Ssam if( o==NAME || o==REG || o==ICON || o==OREG || (o==UNARY MUL && shumul(p->in.left)) ) return(1); 98525828Ssam return(0); 98625828Ssam } 98725828Ssam 98826076Ssam #ifndef shltype 98925828Ssam shltype( o, p ) register NODE *p; { 99025828Ssam return( o== REG || o == NAME || o == ICON || o == OREG || ( o==UNARY MUL && shumul(p->in.left)) ); 99125828Ssam } 99226076Ssam #endif 99325828Ssam 99425828Ssam flshape( p ) NODE *p; { 99525828Ssam register int o = p->in.op; 99625828Ssam 99725828Ssam if( o==NAME || o==REG || o==ICON || o==OREG || (o==UNARY MUL && shumul(p->in.left)) ) return(1); 99825828Ssam return(0); 99925828Ssam } 100025828Ssam 100125828Ssam shtemp( p ) register NODE *p; { 100225828Ssam if( p->in.op == STARG ) p = p->in.left; 100325828Ssam return( p->in.op==NAME || p->in.op ==ICON || p->in.op == OREG || (p->in.op==UNARY MUL && shumul(p->in.left)) ); 100425828Ssam } 100525828Ssam 100625828Ssam shumul( p ) register NODE *p; { 100725828Ssam register int o; 100825828Ssam extern int xdebug; 100925828Ssam 101025828Ssam if (xdebug) { 101125828Ssam printf("\nshumul:op=%d,lop=%d,rop=%d", p->in.op, p->in.left->in.op, p->in.right->in.op); 101225828Ssam printf(" prname=%s,plty=%d, prlval=%D\n", p->in.right->in.name, p->in.left->in.type, p->in.right->tn.lval); 101325828Ssam } 101425828Ssam 101525828Ssam o = p->in.op; 101625828Ssam if(( o == NAME || (o == OREG && !R2TEST(p->tn.rval)) || o == ICON ) 101725828Ssam && p->in.type != PTR+DOUBLE) 101825828Ssam return( STARNM ); 101925828Ssam 102025828Ssam return( 0 ); 102125828Ssam } 102225828Ssam 102325828Ssam special( p, shape ) register NODE *p; { 102425828Ssam if( shape==SIREG && p->in.op == OREG && R2TEST(p->tn.rval) ) return(1); 102525828Ssam else return(0); 102625828Ssam } 102725828Ssam 102825828Ssam adrcon( val ) CONSZ val; { 102925947Ssam printf(ACONFMT, val); 103025828Ssam } 103125828Ssam 103225828Ssam conput( p ) register NODE *p; { 103325828Ssam switch( p->in.op ){ 103425828Ssam 103525828Ssam case ICON: 103625828Ssam acon( p ); 103725828Ssam return; 103825828Ssam 103925828Ssam case REG: 104026162Ssam putstr(rname(p->tn.rval)); 104125828Ssam return; 104225828Ssam 104325828Ssam default: 104425828Ssam cerror( "illegal conput" ); 104525828Ssam } 104625828Ssam } 104725828Ssam 104825828Ssam insput( p ) NODE *p; { 104925828Ssam cerror( "insput" ); 105025828Ssam } 105125828Ssam 105225828Ssam adrput( p ) register NODE *p; { 105325828Ssam register int r; 105425828Ssam /* output an address, with offsets, from p */ 105525828Ssam 105625828Ssam if( p->in.op == FLD ){ 105725828Ssam p = p->in.left; 105825828Ssam } 105925828Ssam switch( p->in.op ){ 106025828Ssam 106125828Ssam case NAME: 106225828Ssam acon( p ); 106325828Ssam return; 106425828Ssam 106525828Ssam case ICON: 106625828Ssam /* addressable value of the constant */ 106726162Ssam putchar('$'); 106825828Ssam acon( p ); 106925828Ssam return; 107025828Ssam 107125828Ssam case REG: 107226162Ssam putstr(rname(p->tn.rval)); 107325828Ssam if(p->in.type == DOUBLE) /* for entry mask */ 107425828Ssam (void) rname(p->tn.rval+1); 107525828Ssam return; 107625828Ssam 107725828Ssam case OREG: 107825828Ssam r = p->tn.rval; 107925828Ssam if( R2TEST(r) ){ /* double indexing */ 108025828Ssam register int flags; 108125828Ssam 108225828Ssam flags = R2UPK3(r); 108326162Ssam if( flags & 1 ) putchar('*'); 108425828Ssam if( p->tn.lval != 0 || p->in.name[0] != '\0' ) acon(p); 108525828Ssam if( R2UPK1(r) != 100) printf( "(%s)", rname(R2UPK1(r)) ); 108625828Ssam printf( "[%s]", rname(R2UPK2(r)) ); 108725828Ssam return; 108825828Ssam } 108925828Ssam if( r == FP && p->tn.lval > 0 ){ /* in the argument region */ 109025828Ssam if( p->in.name[0] != '\0' ) werror( "bad arg temp" ); 109125828Ssam printf( CONFMT, p->tn.lval ); 109226162Ssam putstr( "(fp)" ); 109325828Ssam return; 109425828Ssam } 109525828Ssam if( p->tn.lval != 0 || p->in.name[0] != '\0') acon( p ); 109625828Ssam printf( "(%s)", rname(p->tn.rval) ); 109725828Ssam return; 109825828Ssam 109925828Ssam case UNARY MUL: 110025828Ssam /* STARNM or STARREG found */ 110125828Ssam if( tshape(p, STARNM) ) { 110226162Ssam putchar( '*' ); 110325828Ssam adrput( p->in.left); 110425828Ssam } 110525828Ssam return; 110625828Ssam 110725828Ssam default: 110825828Ssam cerror( "illegal address" ); 110925828Ssam return; 111025828Ssam 111125828Ssam } 111225828Ssam 111325828Ssam } 111425828Ssam 111525828Ssam acon( p ) register NODE *p; { /* print out a constant */ 111625828Ssam 111725828Ssam if( p->in.name[0] == '\0' ){ 111825828Ssam printf( CONFMT, p->tn.lval); 111926162Ssam return; 112026162Ssam } else { 112125828Ssam #ifndef FLEXNAMES 112225828Ssam printf( "%.8s", p->in.name ); 112325828Ssam #else 112426162Ssam putstr(p->in.name); 112525828Ssam #endif 112626162Ssam if (p->tn.lval != 0) { 112726162Ssam putchar('+'); 112826162Ssam printf(CONFMT, p->tn.lval); 112925828Ssam } 113025828Ssam } 113126162Ssam } 113225828Ssam 113325828Ssam genscall( p, cookie ) register NODE *p; { 113425828Ssam /* structure valued call */ 113525828Ssam return( gencall( p, cookie ) ); 113625828Ssam } 113725828Ssam 113825828Ssam genfcall( p, cookie ) register NODE *p; { 113925828Ssam register NODE *p1; 114025828Ssam register int m; 114125828Ssam static char *funcops[6] = { 114225828Ssam "sin", "cos", "sqrt", "exp", "log", "atan" 114325828Ssam }; 114425828Ssam 114525828Ssam /* generate function opcodes */ 114625828Ssam if(p->in.op==UNARY FORTCALL && p->in.type==FLOAT && 114725828Ssam (p1 = p->in.left)->in.op==ICON && 114825828Ssam p1->tn.lval==0 && p1->in.type==INCREF(FTN|FLOAT)) { 114925828Ssam #ifdef FLEXNAMES 115025828Ssam p1->in.name++; 115125828Ssam #else 115225828Ssam strcpy(p1->in.name, p1->in.name[1]); 115325828Ssam #endif 115425828Ssam for(m=0; m<6; m++) 115525828Ssam if(!strcmp(p1->in.name, funcops[m])) 115625828Ssam break; 115725828Ssam if(m >= 6) 115825828Ssam uerror("no opcode for fortarn function %s", p1->in.name); 115925828Ssam } else 116025828Ssam uerror("illegal type of fortarn function"); 116125828Ssam p1 = p->in.right; 116225828Ssam p->in.op = FORTCALL; 116325828Ssam if(!canaddr(p1)) 116425828Ssam order( p1, INAREG|INBREG|SOREG|STARREG|STARNM ); 116525828Ssam m = match( p, INTAREG|INTBREG ); 116625828Ssam return(m != MDONE); 116725828Ssam } 116825828Ssam 116925828Ssam /* tbl */ 117025828Ssam int gc_numbytes; 117125828Ssam /* tbl */ 117225828Ssam 117325828Ssam gencall( p, cookie ) register NODE *p; { 117425828Ssam /* generate the call given by p */ 117525828Ssam register NODE *p1, *ptemp; 117625828Ssam register int temp, temp1; 117725828Ssam register int m; 117825828Ssam 117925828Ssam if( p->in.right ) temp = argsize( p->in.right ); 118025828Ssam else temp = 0; 118125828Ssam 118225828Ssam if( p->in.op == STCALL || p->in.op == UNARY STCALL ){ 118325828Ssam /* set aside room for structure return */ 118425828Ssam 118525828Ssam if( p->stn.stsize > temp ) temp1 = p->stn.stsize; 118625828Ssam else temp1 = temp; 118725828Ssam } 118825828Ssam 118925828Ssam if( temp > maxargs ) maxargs = temp; 119025828Ssam SETOFF(temp1,4); 119125828Ssam 119225828Ssam if( p->in.right ){ /* make temp node, put offset in, and generate args */ 119325828Ssam ptemp = talloc(); 119425828Ssam ptemp->in.op = OREG; 119525828Ssam ptemp->tn.lval = -1; 119625828Ssam ptemp->tn.rval = SP; 119725828Ssam #ifndef FLEXNAMES 119825828Ssam ptemp->in.name[0] = '\0'; 119925828Ssam #else 120025828Ssam ptemp->in.name = ""; 120125828Ssam #endif 120225828Ssam ptemp->in.rall = NOPREF; 120325828Ssam ptemp->in.su = 0; 120425828Ssam genargs( p->in.right, ptemp ); 120525828Ssam ptemp->in.op = FREE; 120625828Ssam } 120725828Ssam 120825828Ssam p1 = p->in.left; 120925828Ssam if( p1->in.op != ICON ){ 121025828Ssam if( p1->in.op != REG ){ 121125828Ssam if( p1->in.op != OREG || R2TEST(p1->tn.rval) ){ 121225828Ssam if( p1->in.op != NAME ){ 121325828Ssam order( p1, INAREG ); 121425828Ssam } 121525828Ssam } 121625828Ssam } 121725828Ssam } 121825828Ssam 121925828Ssam /* tbl 122025828Ssam setup gc_numbytes so reference to ZC works */ 122125828Ssam 122225828Ssam gc_numbytes = temp&(0x3ff); 122325828Ssam 122425828Ssam p->in.op = UNARY CALL; 122525828Ssam m = match( p, INTAREG|INTBREG ); 122625828Ssam 122725828Ssam return(m != MDONE); 122825828Ssam } 122925828Ssam 123025828Ssam /* tbl */ 123125828Ssam char * 123225828Ssam ccbranches[] = { 123325828Ssam "eql", 123425828Ssam "neq", 123525828Ssam "leq", 123625828Ssam "lss", 123725828Ssam "geq", 123825828Ssam "gtr", 123925828Ssam "lequ", 124025828Ssam "lssu", 124125828Ssam "gequ", 124225828Ssam "gtru", 124325828Ssam }; 124425828Ssam /* tbl */ 124525828Ssam 124625828Ssam cbgen( o, lab, mode ) { /* printf conditional and unconditional branches */ 124725828Ssam 124825828Ssam if(o != 0 && (o < EQ || o > UGT )) 124925828Ssam cerror( "bad conditional branch: %s", opst[o] ); 125025828Ssam printf( " j%s L%d\n", 125125828Ssam o == 0 ? "br" : ccbranches[o-EQ], lab ); 125225828Ssam } 125325828Ssam 125425828Ssam nextcook( p, cookie ) NODE *p; { 125525828Ssam /* we have failed to match p with cookie; try another */ 125625828Ssam if( cookie == FORREW ) return( 0 ); /* hopeless! */ 125725828Ssam if( !(cookie&(INTAREG|INTBREG)) ) return( INTAREG|INTBREG ); 125825828Ssam if( !(cookie&INTEMP) && asgop(p->in.op) ) return( INTEMP|INAREG|INTAREG|INTBREG|INBREG ); 125925828Ssam return( FORREW ); 126025828Ssam } 126125828Ssam 126225828Ssam lastchance( p, cook ) NODE *p; { 126325828Ssam /* forget it! */ 126425828Ssam return(0); 126525828Ssam } 126625828Ssam 126725828Ssam optim2( p ) register NODE *p; { 126825828Ssam # ifdef ONEPASS 126925828Ssam /* do local tree transformations and optimizations */ 127025828Ssam # define RV(p) p->in.right->tn.lval 127126076Ssam # define nncon(p) ((p)->in.op == ICON && (p)->in.name[0] == 0) 127230360Ssam register int o, i; 127330360Ssam register NODE *l, *r; 127425828Ssam 127530360Ssam switch (o = p->in.op) { 127630360Ssam 127730360Ssam case DIV: case ASG DIV: 127830360Ssam case MOD: case ASG MOD: 127930360Ssam /* 128030360Ssam * Change unsigned mods and divs to 128130360Ssam * logicals (mul is done in mip & c2) 128230360Ssam */ 128330360Ssam if (ISUNSIGNED(p->in.left->in.type) && nncon(p->in.right) && 128430360Ssam (i = ispow2(RV(p))) >= 0) { 128530360Ssam if (o == DIV || o == ASG DIV) { 128630360Ssam p->in.op = RS; 128730360Ssam RV(p) = i; 128830360Ssam } else { 128930360Ssam p->in.op = AND; 129030360Ssam RV(p)--; 129130360Ssam } 129230360Ssam if (asgop(o)) 129330360Ssam p->in.op = ASG p->in.op; 129425828Ssam } 129530360Ssam return; 129630360Ssam 129730360Ssam case SCONV: 129830360Ssam l = p->in.left; 1299*32879Sdonn if (anyfloat(p, l)) { 1300*32879Sdonn /* save some labor later */ 1301*32879Sdonn NODE *t = talloc(); 1302*32879Sdonn 1303*32879Sdonn if (p->in.type == UCHAR || p->in.type == USHORT) { 1304*32879Sdonn *t = *p; 1305*32879Sdonn t->in.type = UNSIGNED; 1306*32879Sdonn p->in.left = t; 1307*32879Sdonn } else if (l->in.type == UCHAR || l->in.type == USHORT) { 1308*32879Sdonn *t = *p; 1309*32879Sdonn t->in.type = INT; 1310*32879Sdonn p->in.left = t; 1311*32879Sdonn } 1312*32879Sdonn } else if (l->in.op != PCONV && 131332878Sdonn l->in.op != CALL && l->in.op != UNARY CALL && 131430360Ssam tlen(p) == tlen(l)) { 1315*32879Sdonn /* clobber conversions w/o side effects */ 131630360Ssam if (l->in.op != FLD) 131730360Ssam l->in.type = p->in.type; 131830360Ssam ncopy(p, l); 131930360Ssam l->in.op = FREE; 132030360Ssam } 132130360Ssam return; 132230360Ssam 132330360Ssam case ASSIGN: 132430360Ssam /* 132530360Ssam * Try to zap storage conversions of non-float items. 132630360Ssam */ 132730360Ssam r = p->in.right; 132830360Ssam if (r->in.op == SCONV && !anyfloat(r->in.left, r)) { 132930360Ssam int wdest, wconv, wsrc; 133030360Ssam wdest = tlen(p->in.left); 133130360Ssam wconv = tlen(r); 133230360Ssam /* 133330360Ssam * If size doesn't change across assignment or 133430360Ssam * conversion expands src before shrinking again 133530360Ssam * due to the assignment, delete conversion so 133630360Ssam * code generator can create optimal code. 133730360Ssam */ 133830360Ssam if (wdest == wconv || 133930360Ssam (wdest == (wsrc = tlen(r->in.left)) && wconv > wsrc)) { 134030360Ssam p->in.right = r->in.left; 134130360Ssam r->in.op = FREE; 134230360Ssam } 1343*32879Sdonn } else if (p->in.left->in.type == UNSIGNED && 1344*32879Sdonn r->in.type == UNSIGNED) { 1345*32879Sdonn /* let the code table handle it */ 1346*32879Sdonn p->in.right = r->in.left; 1347*32879Sdonn r->in.op = FREE; 1348*32879Sdonn } else if ((p->in.left->in.type == FLOAT || 1349*32879Sdonn p->in.left->in.type == DOUBLE) && 1350*32879Sdonn p->in.left->in.type == r->in.type && 1351*32879Sdonn r->in.left->in.type == UNSIGNED) { 1352*32879Sdonn /* let the code table handle it */ 1353*32879Sdonn p->in.right = r->in.left; 1354*32879Sdonn r->in.op = FREE; 135530360Ssam } 135630360Ssam return; 135725828Ssam } 135825828Ssam # endif 135925828Ssam } 136025828Ssam 136125828Ssam struct functbl { 136225828Ssam int fop; 136332877Sdonn TWORD ftype; 136425828Ssam char *func; 136532877Sdonn } opfunc[] = { 136632877Sdonn DIV, TANY, "udiv", 136732877Sdonn MOD, TANY, "urem", 136832877Sdonn ASG DIV, TANY, "audiv", 136932877Sdonn ASG MOD, TANY, "aurem", 137032877Sdonn 0, 0, 0 }; 137125828Ssam 137225828Ssam hardops(p) register NODE *p; { 137325828Ssam /* change hard to do operators into function calls. */ 137425828Ssam register NODE *q; 137525828Ssam register struct functbl *f; 137632877Sdonn register o; 137732877Sdonn NODE *old,*temp; 137825828Ssam 137925828Ssam o = p->in.op; 138032877Sdonn if( ! (optype(o)==BITYPE && 138132877Sdonn (ISUNSIGNED(p->in.left->in.type) || 138232877Sdonn ISUNSIGNED(p->in.right->in.type))) ) 138332877Sdonn return; 138425828Ssam 138525828Ssam for( f=opfunc; f->fop; f++ ) { 138625828Ssam if( o==f->fop ) goto convert; 138732877Sdonn } 138825828Ssam return; 138925828Ssam 139025828Ssam convert: 139125828Ssam if( asgop( o ) ) { 139232877Sdonn old = NIL; 139332877Sdonn switch( p->in.left->in.op ){ 139432877Sdonn case FLD: 139532877Sdonn q = p->in.left->in.left; 139632877Sdonn /* 139732877Sdonn * rewrite (lval.fld /= rval); as 139832877Sdonn * ((*temp).fld = udiv((*(temp = &lval)).fld,rval)); 139932877Sdonn * else the compiler will evaluate lval twice. 140032877Sdonn */ 140132877Sdonn if( q->in.op == UNARY MUL ){ 140232877Sdonn /* first allocate a temp storage */ 140332877Sdonn temp = talloc(); 140432877Sdonn temp->in.op = OREG; 140532877Sdonn temp->tn.rval = TMPREG; 140632877Sdonn temp->tn.lval = BITOOR(freetemp(1)); 140732877Sdonn temp->in.type = INCREF(p->in.type); 140832877Sdonn #ifdef FLEXNAMES 140932877Sdonn temp->in.name = ""; 141032877Sdonn #else 141132877Sdonn temp->in.name[0] = '\0'; 141232877Sdonn #endif 141332877Sdonn old = q->in.left; 141432877Sdonn q->in.left = temp; 141532877Sdonn } 141632877Sdonn /* fall thru ... */ 141725828Ssam 141832877Sdonn case REG: 141932877Sdonn case NAME: 142032877Sdonn case OREG: 142132877Sdonn /* change ASG OP to a simple OP */ 142232877Sdonn q = talloc(); 142332877Sdonn q->in.op = NOASG p->in.op; 142432877Sdonn q->in.rall = NOPREF; 142532877Sdonn q->in.type = p->in.type; 142632877Sdonn q->in.left = tcopy(p->in.left); 142732877Sdonn q->in.right = p->in.right; 142832877Sdonn p->in.op = ASSIGN; 142932877Sdonn p->in.right = q; 143032877Sdonn p = q; 143132877Sdonn f -= 2; /* Note: this depends on the table order */ 143232877Sdonn /* on the right side only - replace *temp with 143332877Sdonn *(temp = &lval), build the assignment node */ 143432877Sdonn if( old ){ 143532877Sdonn temp = q->in.left->in.left; /* the "*" node */ 143632877Sdonn q = talloc(); 143732877Sdonn q->in.op = ASSIGN; 143832877Sdonn q->in.left = temp->in.left; 143932877Sdonn q->in.right = old; 144032877Sdonn q->in.type = old->in.type; 144132877Sdonn #ifdef FLEXNAMES 144232877Sdonn q->in.name = ""; 144325828Ssam #else 144432877Sdonn q->in.name[0] = '\0'; 144525828Ssam #endif 144632877Sdonn temp->in.left = q; 144732877Sdonn } 144832877Sdonn break; 144925828Ssam 145032877Sdonn case UNARY MUL: 145132877Sdonn /* avoid doing side effects twice */ 145232877Sdonn q = p->in.left; 145332877Sdonn p->in.left = q->in.left; 145432877Sdonn q->in.op = FREE; 145532877Sdonn break; 145632877Sdonn 145732877Sdonn default: 145832877Sdonn cerror( "hardops: can't compute & LHS" ); 145932877Sdonn } 146032877Sdonn } 146132877Sdonn 146225828Ssam /* build comma op for args to function */ 146332877Sdonn q = talloc(); 146432877Sdonn q->in.op = CM; 146532877Sdonn q->in.rall = NOPREF; 146632877Sdonn q->in.type = INT; 146732877Sdonn q->in.left = p->in.left; 146832877Sdonn q->in.right = p->in.right; 146925828Ssam p->in.op = CALL; 147025828Ssam p->in.right = q; 147125828Ssam 147225828Ssam /* put function name in left node of call */ 147325828Ssam p->in.left = q = talloc(); 147425828Ssam q->in.op = ICON; 147525828Ssam q->in.rall = NOPREF; 147625828Ssam q->in.type = INCREF( FTN + p->in.type ); 147725828Ssam #ifndef FLEXNAMES 147832877Sdonn strcpy( q->in.name, f->func ); 147925828Ssam #else 148032877Sdonn q->in.name = f->func; 148125828Ssam #endif 148225828Ssam q->tn.lval = 0; 148325828Ssam q->tn.rval = 0; 148425828Ssam 148525828Ssam } 148625828Ssam 148725828Ssam zappost(p) NODE *p; { 148825828Ssam /* look for ++ and -- operators and remove them */ 148925828Ssam 149025828Ssam register int o, ty; 149125828Ssam register NODE *q; 149225828Ssam o = p->in.op; 149325828Ssam ty = optype( o ); 149425828Ssam 149525828Ssam switch( o ){ 149625828Ssam 149725828Ssam case INCR: 149825828Ssam case DECR: 149925828Ssam q = p->in.left; 150025828Ssam p->in.right->in.op = FREE; /* zap constant */ 150125828Ssam ncopy( p, q ); 150225828Ssam q->in.op = FREE; 150325828Ssam return; 150425828Ssam 150525828Ssam } 150625828Ssam 150725828Ssam if( ty == BITYPE ) zappost( p->in.right ); 150825828Ssam if( ty != LTYPE ) zappost( p->in.left ); 150925828Ssam } 151025828Ssam 151125828Ssam fixpre(p) NODE *p; { 151225828Ssam 151325828Ssam register int o, ty; 151425828Ssam o = p->in.op; 151525828Ssam ty = optype( o ); 151625828Ssam 151725828Ssam switch( o ){ 151825828Ssam 151925828Ssam case ASG PLUS: 152025828Ssam p->in.op = PLUS; 152125828Ssam break; 152225828Ssam case ASG MINUS: 152325828Ssam p->in.op = MINUS; 152425828Ssam break; 152525828Ssam } 152625828Ssam 152725828Ssam if( ty == BITYPE ) fixpre( p->in.right ); 152825828Ssam if( ty != LTYPE ) fixpre( p->in.left ); 152925828Ssam } 153025828Ssam 153125828Ssam NODE * addroreg(l) NODE *l; 153225828Ssam /* OREG was built in clocal() 153325828Ssam * for an auto or formal parameter 153425828Ssam * now its address is being taken 153525828Ssam * local code must unwind it 153625828Ssam * back to PLUS/MINUS REG ICON 153725828Ssam * according to local conventions 153825828Ssam */ 153925828Ssam { 154025828Ssam cerror("address of OREG taken"); 154125828Ssam } 154225828Ssam 154325828Ssam # ifndef ONEPASS 154425828Ssam main( argc, argv ) char *argv[]; { 154525828Ssam return( mainp2( argc, argv ) ); 154625828Ssam } 154725828Ssam # endif 154825828Ssam 154930360Ssam strip(p) register NODE *p; { 155030360Ssam NODE *q; 155130360Ssam 155230360Ssam /* strip nodes off the top when no side effects occur */ 155330360Ssam for( ; ; ) { 155430360Ssam switch( p->in.op ) { 155530360Ssam case SCONV: /* remove lint tidbits */ 155630360Ssam q = p->in.left; 155730360Ssam ncopy( p, q ); 155830360Ssam q->in.op = FREE; 155930360Ssam break; 156030360Ssam /* could probably add a few more here */ 156130360Ssam default: 156230360Ssam return; 156330360Ssam } 156430360Ssam } 156530360Ssam } 156630360Ssam 156725828Ssam myreader(p) register NODE *p; { 156830360Ssam strip( p ); /* strip off operations with no side effects */ 156925828Ssam walkf( p, hardops ); /* convert ops to function calls */ 157025828Ssam canon( p ); /* expands r-vals for fileds */ 157125828Ssam walkf( p, optim2 ); 157225828Ssam } 1573