125828Ssam #ifndef lint 2*32884Sdonn static char sccsid[] = "@(#)local2.c 1.22 (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 319*32884Sdonn case 'I': /* produce value of bitfield assignment */ 320*32884Sdonn /* avoid shifts -- shifts are SLOW on this machine */ 321*32884Sdonn { 322*32884Sdonn register NODE *r = p->in.right; 323*32884Sdonn if(r->in.op == ICON && r->tn.name[0] == '\0') { 324*32884Sdonn putstr("movl\t"); 325*32884Sdonn printf(ACONFMT, r->tn.lval & ((1<<fldsz)-1)); 326*32884Sdonn } 327*32884Sdonn else { 328*32884Sdonn putstr("andl3\t"); 329*32884Sdonn printf(ACONFMT, (1 << fldsz) - 1); 330*32884Sdonn putchar(','); 331*32884Sdonn adrput(r); 332*32884Sdonn } 333*32884Sdonn putchar(','); 334*32884Sdonn adrput(resc); 335*32884Sdonn break; 336*32884Sdonn } 337*32884Sdonn 33825828Ssam case 'H': /* opcode for shift */ 33925828Ssam if(p->in.op == LS || p->in.op == ASG LS) 34026162Ssam putstr("shll"); 34125828Ssam else if(ISUNSIGNED(p->in.left->in.type)) 34226162Ssam putstr("shrl"); 34325828Ssam else 34426162Ssam putstr("shar"); 34525828Ssam return; 34625828Ssam 34725828Ssam case 'L': /* type of left operand */ 34825828Ssam case 'R': /* type of right operand */ 34925828Ssam { 35025828Ssam register NODE *n; 35125828Ssam extern int xdebug; 35225828Ssam 35325828Ssam n = getlr ( p, c); 35425828Ssam if (xdebug) printf("->%d<-", n->in.type); 35525828Ssam 35625828Ssam prtype(n); 35725828Ssam return; 35825828Ssam } 35925828Ssam 36030360Ssam case 'M': { /* initiate ediv for mod and unsigned div */ 36125828Ssam register char *r; 36225828Ssam m = getlr(p, '1')->tn.rval; 36325828Ssam r = rname(m); 36425828Ssam printf("\tclrl\t%s\n\tmovl\t", r); 36525828Ssam adrput(p->in.left); 36625828Ssam printf(",%s\n", rname(m+1)); 36725828Ssam if(!ISUNSIGNED(p->in.type)) { /* should be MOD */ 36825828Ssam m = getlab(); 36925828Ssam printf("\tjgeq\tL%d\n\tmnegl\t$1,%s\n", m, r); 37025828Ssam deflab(m); 37125828Ssam } 37225828Ssam return; 37330360Ssam } 37425828Ssam 37530360Ssam case 'T': { /* rounded structure length for arguments */ 37630360Ssam int size = p->stn.stsize; 37725828Ssam SETOFF( size, 4); 37825828Ssam printf("movab -%d(sp),sp", size); 37925828Ssam return; 38030360Ssam } 38125828Ssam 38225828Ssam case 'S': /* structure assignment */ 38325977Ssam stasg(p); 38425977Ssam break; 38525828Ssam 38629672Ssam case 'X': /* multiplication for short and char */ 38729672Ssam if (ISUNSIGNED(p->in.left->in.type)) 38829672Ssam printf("\tmovz"); 38929672Ssam else 39029672Ssam printf("\tcvt"); 39129672Ssam zzzcode(p, 'L'); 39229672Ssam printf("l\t"); 39329672Ssam adrput(p->in.left); 39429672Ssam printf(","); 39529672Ssam adrput(&resc[0]); 39629672Ssam printf("\n"); 39729672Ssam if (ISUNSIGNED(p->in.right->in.type)) 39829672Ssam printf("\tmovz"); 39929672Ssam else 40029672Ssam printf("\tcvt"); 40129672Ssam zzzcode(p, 'R'); 40229672Ssam printf("l\t"); 40329672Ssam adrput(p->in.right); 40429672Ssam printf(","); 40529672Ssam adrput(&resc[1]); 40629672Ssam printf("\n"); 40729672Ssam return; 40829672Ssam 40930360Ssam case 'U': /* SCONV */ 41030360Ssam case 'V': /* SCONV with FORCC */ 41130360Ssam sconv(p, c == 'V'); 41230360Ssam break; 41330360Ssam 41432879Sdonn case 'W': { /* SCONV or ASSIGN float/double => unsigned */ 41532879Sdonn NODE *src = p->in.op == SCONV ? p->in.left : p->in.right; 41632879Sdonn 41732876Sdonn putstr("ld"); 41832879Sdonn prtype(src); 41932876Sdonn putchar('\t'); 42032879Sdonn adrput(src); 42132876Sdonn putstr("\n\t"); 42232876Sdonn float_to_unsigned(p); 42332876Sdonn break; 42432879Sdonn } 42532876Sdonn 42632879Sdonn case 'Y': /* SCONV or ASSIGN unsigned => float/double */ 42732876Sdonn unsigned_to_float(p); /* stores into accumulator */ 42832876Sdonn putstr("\n\tst"); 42932876Sdonn prtype(p); 43032876Sdonn putchar('\t'); 43132879Sdonn if (p->in.op == SCONV) 43232879Sdonn adrput(resc); 43332879Sdonn else 43432879Sdonn adrput(p->in.left); 43532879Sdonn rtyflg = 1; 43632876Sdonn break; 43732876Sdonn 43830360Ssam case 'Z': 43930360Ssam p = p->in.right; 44030360Ssam switch (p->in.type) { 44130360Ssam case SHORT: { 44230360Ssam short w = p->tn.lval; 44330360Ssam p->tn.lval = w; 44430360Ssam break; 44530360Ssam } 44630360Ssam case CHAR: { 44730360Ssam char c = p->tn.lval; 44830360Ssam p->tn.lval = c; 44930360Ssam break; 45030360Ssam } 45130360Ssam } 45230360Ssam printf("$%d", p->tn.lval); 45330360Ssam break; 45430360Ssam 45525977Ssam default: 45625977Ssam cerror( "illegal zzzcode" ); 45725977Ssam } 45830360Ssam } 45925828Ssam 46025977Ssam #define MOVB(dst, src, off) { \ 46126162Ssam putstr("\tmovb\t"); upput(src, off); putchar(','); \ 46225977Ssam upput(dst, off); putchar('\n'); \ 46325977Ssam } 46425977Ssam #define MOVW(dst, src, off) { \ 46526162Ssam putstr("\tmovw\t"); upput(src, off); putchar(','); \ 46625977Ssam upput(dst, off); putchar('\n'); \ 46725977Ssam } 46825977Ssam #define MOVL(dst, src, off) { \ 46926162Ssam putstr("\tmovl\t"); upput(src, off); putchar(','); \ 47025977Ssam upput(dst, off); putchar('\n'); \ 47125977Ssam } 47225977Ssam /* 47325977Ssam * Generate code for a structure assignment. 47425977Ssam */ 47525977Ssam stasg(p) 47625977Ssam register NODE *p; 47725977Ssam { 47825977Ssam register NODE *l, *r; 47925977Ssam register int size; 48025828Ssam 48125977Ssam switch (p->in.op) { 48225977Ssam case STASG: /* regular assignment */ 48325977Ssam l = p->in.left; 48425977Ssam r = p->in.right; 48525977Ssam break; 48625977Ssam case STARG: /* place arg on the stack */ 48725977Ssam l = getlr(p, '3'); 48825977Ssam r = p->in.left; 48925977Ssam break; 49025977Ssam default: 49125977Ssam cerror("STASG bad"); 49225977Ssam /*NOTREACHED*/ 49325977Ssam } 49425977Ssam /* 49525977Ssam * Pun source for use in code generation. 49625977Ssam */ 49725977Ssam switch (r->in.op) { 49825977Ssam case ICON: 49925977Ssam r->in.op = NAME; 50025977Ssam break; 50125977Ssam case REG: 50225977Ssam r->in.op = OREG; 50325977Ssam break; 50425977Ssam default: 50525977Ssam cerror( "STASG-r" ); 50625977Ssam /*NOTREACHED*/ 50725977Ssam } 50825977Ssam size = p->stn.stsize; 50925977Ssam if (size <= 0 || size > 65535) 51025977Ssam cerror("structure size out of range"); 51125977Ssam /* 51225977Ssam * Generate optimized code based on structure size 51325977Ssam * and alignment properties.... 51425977Ssam */ 51525977Ssam switch (size) { 51625828Ssam 51725977Ssam case 1: 51826162Ssam putstr("\tmovb\t"); 51925977Ssam optimized: 52025977Ssam adrput(r); 52126162Ssam putchar(','); 52225977Ssam adrput(l); 52326162Ssam putchar('\n'); 52425977Ssam break; 52525828Ssam 52625977Ssam case 2: 52725977Ssam if (p->stn.stalign != 2) { 52825977Ssam MOVB(l, r, SZCHAR); 52926162Ssam putstr("\tmovb\t"); 53025977Ssam } else 53126162Ssam putstr("\tmovw\t"); 53225977Ssam goto optimized; 53325977Ssam 53425977Ssam case 4: 53525977Ssam if (p->stn.stalign != 4) { 53625977Ssam if (p->stn.stalign != 2) { 53725977Ssam MOVB(l, r, 3*SZCHAR); 53825977Ssam MOVB(l, r, 2*SZCHAR); 53925977Ssam MOVB(l, r, 1*SZCHAR); 54026162Ssam putstr("\tmovb\t"); 54125947Ssam } else { 54225977Ssam MOVW(l, r, SZSHORT); 54326162Ssam putstr("\tmovw\t"); 54425828Ssam } 54525977Ssam } else 54626162Ssam putstr("\tmovl\t"); 54725977Ssam goto optimized; 54825828Ssam 54925977Ssam case 6: 55025977Ssam if (p->stn.stalign != 2) 55125977Ssam goto movblk; 55225977Ssam MOVW(l, r, 2*SZSHORT); 55325977Ssam MOVW(l, r, 1*SZSHORT); 55426162Ssam putstr("\tmovw\t"); 55525977Ssam goto optimized; 55625977Ssam 55725977Ssam case 8: 55825977Ssam if (p->stn.stalign == 4) { 55925977Ssam MOVL(l, r, SZLONG); 56026162Ssam putstr("\tmovl\t"); 56125977Ssam goto optimized; 56225977Ssam } 56325977Ssam /* fall thru...*/ 56425977Ssam 56525977Ssam default: 56625977Ssam movblk: 56725977Ssam /* 56825977Ssam * Can we ever get a register conflict with R1 here? 56925977Ssam */ 57026162Ssam putstr("\tmovab\t"); 57125977Ssam adrput(l); 57226162Ssam putstr(",r1\n\tmovab\t"); 57325977Ssam adrput(r); 57425977Ssam printf(",r0\n\tmovl\t$%d,r2\n\tmovblk\n", size); 57525977Ssam rname(R2); 57625828Ssam break; 57725977Ssam } 57825977Ssam /* 57925977Ssam * Reverse above pun for reclaim. 58025977Ssam */ 58125977Ssam if (r->in.op == NAME) 58225977Ssam r->in.op = ICON; 58325977Ssam else if (r->in.op == OREG) 58425977Ssam r->in.op = REG; 58525977Ssam } 58625828Ssam 58725977Ssam /* 58825977Ssam * Output the address of the second item in the 58925977Ssam * pair pointed to by p. 59025977Ssam */ 59125977Ssam upput(p, size) 59225977Ssam register NODE *p; 59325977Ssam { 59425977Ssam CONSZ save; 59525977Ssam 59625977Ssam if (p->in.op == FLD) 59725977Ssam p = p->in.left; 59825977Ssam switch (p->in.op) { 59925977Ssam 60025977Ssam case NAME: 60125977Ssam case OREG: 60225977Ssam save = p->tn.lval; 60325977Ssam p->tn.lval += size/SZCHAR; 60425977Ssam adrput(p); 60525977Ssam p->tn.lval = save; 60625977Ssam break; 60725977Ssam 60825977Ssam case REG: 60925977Ssam if (size == SZLONG) { 61026162Ssam putstr(rname(p->tn.rval+1)); 61125977Ssam break; 61225977Ssam } 61325977Ssam /* fall thru... */ 61425977Ssam 61525828Ssam default: 61625977Ssam cerror("illegal upper address op %s size %d", 61725977Ssam opst[p->tn.op], size); 61825977Ssam /*NOTREACHED*/ 61925828Ssam } 62025977Ssam } 62125828Ssam 62230360Ssam /* 62332876Sdonn * Convert a float or double in the accumulator into an unsigned int. 62432876Sdonn * Unlike the vax, the tahoe stores 0 into the destination 62532876Sdonn * on a conversion of > 2 ** 31, so we compensate. 62632876Sdonn */ 62732876Sdonn float_to_unsigned(p) 62832876Sdonn NODE *p; 62932876Sdonn { 63032876Sdonn register NODE *l = p->in.left; 63132876Sdonn int label1 = getlab(); 63232876Sdonn int label2 = getlab(); 63332876Sdonn int label3 = getlab(); 63432879Sdonn NODE *src, *dst; 63532876Sdonn 63632879Sdonn if (p->in.op == SCONV) { 63732879Sdonn src = p->in.left; 63832879Sdonn dst = resc; 63932879Sdonn } else { 64032879Sdonn src = p->in.right; 64132879Sdonn dst = p->in.left; 64232879Sdonn } 64332879Sdonn 64432876Sdonn printf(".data\n\t.align\t2\nL%d:\n\t.long\t0x50000000", label1); 64532879Sdonn if (src->in.type == DOUBLE) 64632879Sdonn putstr(", 0x00000000 # .double"); 64732879Sdonn else 64832879Sdonn putstr(" # .float"); 64932879Sdonn putstr(" 2147483648\n\t.text\n\tcmp"); 65032879Sdonn prtype(src); 65132876Sdonn printf("\tL%d\n\tjlss\tL%d\n\tsub", label1, label2); 65232879Sdonn prtype(src); 65332876Sdonn printf("\tL%d\n\tcv", label1); 65432879Sdonn prtype(src); 65532876Sdonn putstr("l\t"); 65632879Sdonn adrput(dst); 65732876Sdonn putstr("\n\taddl2\t$-2147483648,"); 65832879Sdonn adrput(dst); 65932876Sdonn printf("\n\tjbr\tL%d\nL%d:\n\tcv", label3, label2); 66032879Sdonn prtype(src); 66132876Sdonn putstr("l\t"); 66232879Sdonn adrput(dst); 66332876Sdonn printf("\nL%d:", label3); 66432876Sdonn } 66532876Sdonn 66632876Sdonn /* 66732876Sdonn * Convert an unsigned int into a float or double, leaving the result 66832876Sdonn * in the accumulator. 66932876Sdonn */ 67032876Sdonn unsigned_to_float(p) 67132876Sdonn register NODE *p; 67232876Sdonn { 67332876Sdonn int label1 = getlab(); 67432876Sdonn int label2 = getlab(); 67532879Sdonn NODE *src, *dst; 67632876Sdonn 67732879Sdonn if (p->in.op == SCONV) { 67832879Sdonn src = p->in.left; 67932879Sdonn dst = resc; 68032879Sdonn } else { 68132879Sdonn src = p->in.right; 68232879Sdonn dst = p->in.left; 68332879Sdonn } 68432879Sdonn 68532876Sdonn printf(".data\n\t.align\t2\nL%d:\n\t.long\t0x50800000", label2); 68632876Sdonn if (p->in.type == DOUBLE) 68732879Sdonn putstr(", 0x00000000 # .double"); 68832879Sdonn else 68932879Sdonn putstr(" # .float"); 69032879Sdonn putstr(" 4294967296\n\t.text\n\tmovl\t"); 69132879Sdonn adrput(src); 69232876Sdonn putchar(','); 69332879Sdonn adrput(dst); 69432876Sdonn putstr("\n\tcvl"); 69532876Sdonn prtype(p); 69632876Sdonn putchar('\t'); 69732879Sdonn adrput(dst); 69832879Sdonn printf("\n\tjgeq\tL%d\n\tadd", label1); 69932879Sdonn prtype(p); 70032879Sdonn printf("\tL%d\nL%d:", label2, label1); 70132876Sdonn } 70232876Sdonn 70332876Sdonn /* 70432875Sdonn * Prlen() is a cheap prtype()... 70532875Sdonn */ 70632875Sdonn static char convtab[SZINT/SZCHAR + 1] = { 70732875Sdonn '?', 'b', 'w', '?', 'l' 70832875Sdonn }; 70932875Sdonn #define prlen(len) putchar(convtab[len]) 71032875Sdonn 71132875Sdonn 71232875Sdonn /* 71332873Sdonn * Generate code for integral scalar conversions. 71432875Sdonn * Some of this code is designed to work around a tahoe misfeature 71532875Sdonn * that causes sign- and zero- extension to be defeated in 71632875Sdonn * certain circumstances. 71732875Sdonn * Basically if the source operand of a CVT or MOVZ instruction is 71832875Sdonn * shorter than the destination, and the source is a register 71932875Sdonn * or an immediate constant, sign- and zero- extension are 72032875Sdonn * ignored and the high bits of the source are copied. (Note 72132875Sdonn * that zero-extension is not a problem for immediate 72232875Sdonn * constants.) 72332873Sdonn */ 72432873Sdonn sconv(p, forcc) 72532873Sdonn NODE *p; 72632873Sdonn int forcc; 72732873Sdonn { 72832873Sdonn register NODE *src, *dst; 72932873Sdonn register NODE *tmp; 73032873Sdonn register int srclen, dstlen; 73132873Sdonn int srctype, dsttype; 73232873Sdonn int val; 73332882Sdonn int neg = 0; 73430360Ssam 73532873Sdonn if (p->in.op == ASSIGN) { 73632879Sdonn src = p->in.right; 73732879Sdonn dst = p->in.left; 73832873Sdonn dstlen = tlen(dst); 73932873Sdonn dsttype = dst->in.type; 74032879Sdonn } else if (p->in.op == SCONV) { 74132879Sdonn src = p->in.left; 74232879Sdonn dst = resc; 74332873Sdonn dstlen = tlen(p); 74432873Sdonn dsttype = p->in.type; 74532879Sdonn } else /* if (p->in.op == OPLEAF) */ { 74632879Sdonn src = p; 74732879Sdonn dst = resc; 74832879Sdonn dstlen = SZINT/SZCHAR; 74932879Sdonn dsttype = ISUNSIGNED(src->in.type) ? UNSIGNED : INT; 75032873Sdonn } 75132873Sdonn 75232875Sdonn if (src->in.op == REG) { 75332875Sdonn srclen = SZINT/SZCHAR; 75432875Sdonn srctype = ISUNSIGNED(src->in.type) ? UNSIGNED : INT; 75532875Sdonn } else { 75632875Sdonn srclen = tlen(src); 75732875Sdonn srctype = src->in.type; 75832875Sdonn } 75932873Sdonn 76032882Sdonn if (src->in.op == ICON && src->tn.name[0] == '\0') { 76132875Sdonn if (src->tn.lval == 0) { 76232875Sdonn putstr("clr"); 76332875Sdonn prtype(dst); 76432875Sdonn putchar('\t'); 76532875Sdonn adrput(dst); 76632875Sdonn return; 76732875Sdonn } 76832875Sdonn if (dstlen < srclen) { 76932875Sdonn switch (dsttype) { 77032875Sdonn case CHAR: 77132875Sdonn src->tn.lval = (char) src->tn.lval; 77232875Sdonn break; 77332875Sdonn case UCHAR: 77432875Sdonn src->tn.lval = (unsigned char) src->tn.lval; 77532875Sdonn break; 77632875Sdonn case SHORT: 77732875Sdonn src->tn.lval = (short) src->tn.lval; 77832875Sdonn break; 77932875Sdonn case USHORT: 78032875Sdonn src->tn.lval = (unsigned short) src->tn.lval; 78132875Sdonn break; 78232875Sdonn } 78332875Sdonn } 78432875Sdonn if (dst->in.op == REG) { 78532875Sdonn dsttype = INT; 78632875Sdonn dstlen = SZINT/SZCHAR; 78732875Sdonn } 78832875Sdonn srctype = dsttype; 78932875Sdonn srclen = dstlen; 79032882Sdonn if ((val = src->tn.lval) & 1 << dstlen * SZCHAR - 1) { 79132882Sdonn src->tn.lval = -(val | ~((1 << dstlen * SZCHAR) - 1)); 79232882Sdonn ++neg; /* MNEGx may be shorter */ 79332882Sdonn } 79432875Sdonn } 79532875Sdonn 79632873Sdonn if (srclen < dstlen) { 79732873Sdonn if (srctype == CHAR && dsttype == USHORT && dst->in.op == REG) { 79832873Sdonn /* (unsigned short) c; => sign extend to 16 bits */ 79932874Sdonn putstr("cvtbl\t"); 80032873Sdonn adrput(src); 80132873Sdonn putstr(",-(sp)\n\tmovzwl\t2(sp),"); 80232873Sdonn adrput(dst); 80332873Sdonn putstr("\n\tmovab\t4(sp),sp"); 80432873Sdonn if (forcc) { 80532873Sdonn /* inverted test */ 80632873Sdonn putstr("\n\tcmpl\t$0,"); 80732873Sdonn adrput(dst); 80832873Sdonn } 80932873Sdonn return; 81032873Sdonn } 81132873Sdonn genconv(ISUNSIGNED(srctype), 81232873Sdonn srclen, dst->in.op == REG ? SZINT/SZCHAR : dstlen, 81332873Sdonn src, dst); 81432873Sdonn return; 81532873Sdonn } 81632873Sdonn 81732873Sdonn if (srclen > dstlen && dst->in.op == REG) { 81832875Sdonn /* if dst is a register, the result must look like an int */ 81932873Sdonn if (src->in.op == REG) { 82032873Sdonn if (ISUNSIGNED(dsttype)) { 82132873Sdonn val = (1 << dstlen * SZCHAR) - 1; 82232873Sdonn if (src->tn.rval == dst->tn.rval) 82332873Sdonn /* conversion in place */ 82432874Sdonn printf("andl2\t$%#x,", val); 82532873Sdonn else { 82632874Sdonn printf("andl3\t$%#x,", val); 82732873Sdonn adrput(src); 82832873Sdonn putchar(','); 82932873Sdonn } 83032873Sdonn adrput(dst); 83132873Sdonn return; 83232873Sdonn } 83332875Sdonn /* 83432875Sdonn * Sign extension in register can also be 83532875Sdonn * accomplished by shifts, but unfortunately 83632875Sdonn * shifts are extremely slow, due to the lack 83732875Sdonn * of a barrel shifter. 83832875Sdonn */ 83932875Sdonn putstr("pushl\t"); 84032873Sdonn adrput(src); 84132875Sdonn putstr("\n\tcvt"); 84232875Sdonn prlen(dstlen); 84332875Sdonn printf("l\t%d(sp),", SZINT/SZCHAR - dstlen); 84432873Sdonn adrput(dst); 84532875Sdonn putstr("\n\tmovab\t4(sp),sp"); 84632875Sdonn if (forcc) { 84732875Sdonn /* inverted test */ 84832875Sdonn putstr("\n\tcmpl\t$0,"); 84932875Sdonn adrput(dst); 85032875Sdonn } 85132873Sdonn return; 85232873Sdonn } 85332873Sdonn tmp = talloc(); 85432873Sdonn if ((src->in.op == UNARY MUL && 85532873Sdonn ((src->in.left->in.op == NAME || 85632873Sdonn (src->in.left->in.op == ICON)))) || 85732873Sdonn (src->in.op == OREG && !R2TEST(src->tn.rval))) { 85832873Sdonn /* we can increment src's address & pun it */ 85932873Sdonn *tmp = *src; 86032873Sdonn tmp->tn.lval += srclen - dstlen; 86132873Sdonn } else { 86232873Sdonn /* we must store src's address */ 86332873Sdonn *tmp = *dst; 86432875Sdonn putstr("mova"); 86532875Sdonn prlen(srclen); 86632875Sdonn putchar('\t'); 86732873Sdonn adrput(src); 86832873Sdonn putchar(','); 86932873Sdonn adrput(tmp); 87032874Sdonn putstr("\n\t"); 87132873Sdonn tmp->tn.op = OREG; 87232873Sdonn tmp->tn.lval = srclen - dstlen; 87332873Sdonn } 87432873Sdonn genconv(ISUNSIGNED(dsttype), dstlen, SZINT/SZCHAR, tmp, dst); 87532873Sdonn tmp->in.op = FREE; 87632873Sdonn return; 87732873Sdonn } 87832873Sdonn 87932882Sdonn genconv(neg ? -1 : ISUNSIGNED(dsttype), 88032873Sdonn srclen, dst->in.op == REG ? SZINT/SZCHAR : dstlen, 88132873Sdonn src, dst); 88232873Sdonn } 88332873Sdonn 88432882Sdonn genconv(srcflag, srclen, dstlen, src, dst) 88532882Sdonn int srcflag; 88632875Sdonn register int srclen, dstlen; 88732873Sdonn NODE *src, *dst; 88832873Sdonn { 88932873Sdonn if (srclen != dstlen) { 89032882Sdonn if (srcflag > 0 && srclen < dstlen) 89132874Sdonn putstr("movz"); 89232873Sdonn else 89332874Sdonn putstr("cvt"); 89432875Sdonn prlen(srclen); 89532882Sdonn } else if (srcflag < 0) 89632882Sdonn putstr("mneg"); 89732882Sdonn else 89832874Sdonn putstr("mov"); 89932875Sdonn prlen(dstlen); 90032873Sdonn putchar('\t'); 90132873Sdonn adrput(src); 90232873Sdonn putchar(','); 90332873Sdonn adrput(dst); 90432873Sdonn } 90532873Sdonn 90625828Ssam rmove( rt, rs, t ) TWORD t;{ 90725828Ssam printf( " movl %s,%s\n", rname(rs), rname(rt) ); 90825828Ssam if(t==DOUBLE) 90925828Ssam printf( " movl %s,%s\n", rname(rs+1), rname(rt+1) ); 91025828Ssam } 91125828Ssam 91225828Ssam struct respref 91325828Ssam respref[] = { 91425828Ssam INTAREG|INTBREG, INTAREG|INTBREG, 91525828Ssam INAREG|INBREG, INAREG|INBREG|SOREG|STARREG|STARNM|SNAME|SCON, 91625828Ssam INTEMP, INTEMP, 91725828Ssam FORARG, FORARG, 91825828Ssam INTEMP, INTAREG|INAREG|INTBREG|INBREG|SOREG|STARREG|STARNM, 91925828Ssam 0, 0 }; 92025828Ssam 92125828Ssam setregs(){ /* set up temporary registers */ 92225828Ssam fregs = 6; /* tbl- 6 free regs on Tahoe (0-5) */ 92325828Ssam } 92425828Ssam 92526076Ssam #ifndef szty 92625828Ssam szty(t) TWORD t;{ /* size, in registers, needed to hold thing of type t */ 92725828Ssam return(t==DOUBLE ? 2 : 1 ); 92825828Ssam } 92926076Ssam #endif 93025828Ssam 93125828Ssam rewfld( p ) NODE *p; { 93225828Ssam return(1); 93325828Ssam } 93425828Ssam 93525828Ssam callreg(p) NODE *p; { 93625828Ssam return( R0 ); 93725828Ssam } 93825828Ssam 93925828Ssam base( p ) register NODE *p; { 94025828Ssam register int o = p->in.op; 94125828Ssam 94225828Ssam if( (o==ICON && p->in.name[0] != '\0')) return( 100 ); /* ie no base reg */ 94325828Ssam if( o==REG ) return( p->tn.rval ); 94425828Ssam if( (o==PLUS || o==MINUS) && p->in.left->in.op == REG && p->in.right->in.op==ICON) 94525828Ssam return( p->in.left->tn.rval ); 94625828Ssam if( o==OREG && !R2TEST(p->tn.rval) && (p->in.type==INT || p->in.type==UNSIGNED || ISPTR(p->in.type)) ) 94725828Ssam return( p->tn.rval + 0200*1 ); 94825828Ssam return( -1 ); 94925828Ssam } 95025828Ssam 95125828Ssam offset( p, tyl ) register NODE *p; int tyl; { 95225828Ssam 95325828Ssam if(tyl > 8) return( -1 ); 95425828Ssam if( tyl==1 && p->in.op==REG && (p->in.type==INT || p->in.type==UNSIGNED) ) return( p->tn.rval ); 95525828Ssam if( (p->in.op==LS && p->in.left->in.op==REG && (p->in.left->in.type==INT || p->in.left->in.type==UNSIGNED) && 95625828Ssam (p->in.right->in.op==ICON && p->in.right->in.name[0]=='\0') 95725828Ssam && (1<<p->in.right->tn.lval)==tyl)) 95825828Ssam return( p->in.left->tn.rval ); 95925828Ssam return( -1 ); 96025828Ssam } 96125828Ssam 96225828Ssam makeor2( p, q, b, o) register NODE *p, *q; register int b, o; { 96325828Ssam register NODE *t; 96425828Ssam register int i; 96525828Ssam NODE *f; 96625828Ssam 96725828Ssam p->in.op = OREG; 96825828Ssam f = p->in.left; /* have to free this subtree later */ 96925828Ssam 97025828Ssam /* init base */ 97125828Ssam switch (q->in.op) { 97225828Ssam case ICON: 97325828Ssam case REG: 97425828Ssam case OREG: 97525828Ssam t = q; 97625828Ssam break; 97725828Ssam 97825828Ssam case MINUS: 97925828Ssam q->in.right->tn.lval = -q->in.right->tn.lval; 98025828Ssam case PLUS: 98125828Ssam t = q->in.right; 98225828Ssam break; 98325828Ssam 98425828Ssam case UNARY MUL: 98525828Ssam t = q->in.left->in.left; 98625828Ssam break; 98725828Ssam 98825828Ssam default: 98925828Ssam cerror("illegal makeor2"); 99025828Ssam } 99125828Ssam 99225828Ssam p->tn.lval = t->tn.lval; 99325828Ssam #ifndef FLEXNAMES 99425828Ssam for(i=0; i<NCHNAM; ++i) 99525828Ssam p->in.name[i] = t->in.name[i]; 99625828Ssam #else 99725828Ssam p->in.name = t->in.name; 99825828Ssam #endif 99925828Ssam 100025828Ssam /* init offset */ 100125828Ssam p->tn.rval = R2PACK( (b & 0177), o, (b>>7) ); 100225828Ssam 100325828Ssam tfree(f); 100425828Ssam return; 100525828Ssam } 100625828Ssam 100725828Ssam canaddr( p ) NODE *p; { 100825828Ssam register int o = p->in.op; 100925828Ssam 101025828Ssam if( o==NAME || o==REG || o==ICON || o==OREG || (o==UNARY MUL && shumul(p->in.left)) ) return(1); 101125828Ssam return(0); 101225828Ssam } 101325828Ssam 101426076Ssam #ifndef shltype 101525828Ssam shltype( o, p ) register NODE *p; { 101625828Ssam return( o== REG || o == NAME || o == ICON || o == OREG || ( o==UNARY MUL && shumul(p->in.left)) ); 101725828Ssam } 101826076Ssam #endif 101925828Ssam 102025828Ssam flshape( p ) NODE *p; { 102125828Ssam register int o = p->in.op; 102225828Ssam 102325828Ssam if( o==NAME || o==REG || o==ICON || o==OREG || (o==UNARY MUL && shumul(p->in.left)) ) return(1); 102425828Ssam return(0); 102525828Ssam } 102625828Ssam 102725828Ssam shtemp( p ) register NODE *p; { 102825828Ssam if( p->in.op == STARG ) p = p->in.left; 102925828Ssam return( p->in.op==NAME || p->in.op ==ICON || p->in.op == OREG || (p->in.op==UNARY MUL && shumul(p->in.left)) ); 103025828Ssam } 103125828Ssam 103225828Ssam shumul( p ) register NODE *p; { 103325828Ssam register int o; 103425828Ssam extern int xdebug; 103525828Ssam 103625828Ssam if (xdebug) { 103725828Ssam printf("\nshumul:op=%d,lop=%d,rop=%d", p->in.op, p->in.left->in.op, p->in.right->in.op); 103825828Ssam printf(" prname=%s,plty=%d, prlval=%D\n", p->in.right->in.name, p->in.left->in.type, p->in.right->tn.lval); 103925828Ssam } 104025828Ssam 104125828Ssam o = p->in.op; 104225828Ssam if(( o == NAME || (o == OREG && !R2TEST(p->tn.rval)) || o == ICON ) 104325828Ssam && p->in.type != PTR+DOUBLE) 104425828Ssam return( STARNM ); 104525828Ssam 104625828Ssam return( 0 ); 104725828Ssam } 104825828Ssam 104925828Ssam special( p, shape ) register NODE *p; { 105025828Ssam if( shape==SIREG && p->in.op == OREG && R2TEST(p->tn.rval) ) return(1); 105125828Ssam else return(0); 105225828Ssam } 105325828Ssam 105425828Ssam adrcon( val ) CONSZ val; { 105525947Ssam printf(ACONFMT, val); 105625828Ssam } 105725828Ssam 105825828Ssam conput( p ) register NODE *p; { 105925828Ssam switch( p->in.op ){ 106025828Ssam 106125828Ssam case ICON: 106225828Ssam acon( p ); 106325828Ssam return; 106425828Ssam 106525828Ssam case REG: 106626162Ssam putstr(rname(p->tn.rval)); 106725828Ssam return; 106825828Ssam 106925828Ssam default: 107025828Ssam cerror( "illegal conput" ); 107125828Ssam } 107225828Ssam } 107325828Ssam 107425828Ssam insput( p ) NODE *p; { 107525828Ssam cerror( "insput" ); 107625828Ssam } 107725828Ssam 107825828Ssam adrput( p ) register NODE *p; { 107925828Ssam register int r; 108025828Ssam /* output an address, with offsets, from p */ 108125828Ssam 108225828Ssam if( p->in.op == FLD ){ 108325828Ssam p = p->in.left; 108425828Ssam } 108525828Ssam switch( p->in.op ){ 108625828Ssam 108725828Ssam case NAME: 108825828Ssam acon( p ); 108925828Ssam return; 109025828Ssam 109125828Ssam case ICON: 109225828Ssam /* addressable value of the constant */ 109326162Ssam putchar('$'); 109425828Ssam acon( p ); 109525828Ssam return; 109625828Ssam 109725828Ssam case REG: 109826162Ssam putstr(rname(p->tn.rval)); 109925828Ssam if(p->in.type == DOUBLE) /* for entry mask */ 110025828Ssam (void) rname(p->tn.rval+1); 110125828Ssam return; 110225828Ssam 110325828Ssam case OREG: 110425828Ssam r = p->tn.rval; 110525828Ssam if( R2TEST(r) ){ /* double indexing */ 110625828Ssam register int flags; 110725828Ssam 110825828Ssam flags = R2UPK3(r); 110926162Ssam if( flags & 1 ) putchar('*'); 111025828Ssam if( p->tn.lval != 0 || p->in.name[0] != '\0' ) acon(p); 111125828Ssam if( R2UPK1(r) != 100) printf( "(%s)", rname(R2UPK1(r)) ); 111225828Ssam printf( "[%s]", rname(R2UPK2(r)) ); 111325828Ssam return; 111425828Ssam } 111525828Ssam if( r == FP && p->tn.lval > 0 ){ /* in the argument region */ 111625828Ssam if( p->in.name[0] != '\0' ) werror( "bad arg temp" ); 111725828Ssam printf( CONFMT, p->tn.lval ); 111826162Ssam putstr( "(fp)" ); 111925828Ssam return; 112025828Ssam } 112125828Ssam if( p->tn.lval != 0 || p->in.name[0] != '\0') acon( p ); 112225828Ssam printf( "(%s)", rname(p->tn.rval) ); 112325828Ssam return; 112425828Ssam 112525828Ssam case UNARY MUL: 112625828Ssam /* STARNM or STARREG found */ 112725828Ssam if( tshape(p, STARNM) ) { 112826162Ssam putchar( '*' ); 112925828Ssam adrput( p->in.left); 113025828Ssam } 113125828Ssam return; 113225828Ssam 113325828Ssam default: 113425828Ssam cerror( "illegal address" ); 113525828Ssam return; 113625828Ssam 113725828Ssam } 113825828Ssam 113925828Ssam } 114025828Ssam 114125828Ssam acon( p ) register NODE *p; { /* print out a constant */ 114225828Ssam 114325828Ssam if( p->in.name[0] == '\0' ){ 114425828Ssam printf( CONFMT, p->tn.lval); 114526162Ssam return; 114626162Ssam } else { 114725828Ssam #ifndef FLEXNAMES 114825828Ssam printf( "%.8s", p->in.name ); 114925828Ssam #else 115026162Ssam putstr(p->in.name); 115125828Ssam #endif 115226162Ssam if (p->tn.lval != 0) { 115326162Ssam putchar('+'); 115426162Ssam printf(CONFMT, p->tn.lval); 115525828Ssam } 115625828Ssam } 115726162Ssam } 115825828Ssam 115925828Ssam genscall( p, cookie ) register NODE *p; { 116025828Ssam /* structure valued call */ 116125828Ssam return( gencall( p, cookie ) ); 116225828Ssam } 116325828Ssam 116425828Ssam genfcall( p, cookie ) register NODE *p; { 116525828Ssam register NODE *p1; 116625828Ssam register int m; 116725828Ssam static char *funcops[6] = { 116825828Ssam "sin", "cos", "sqrt", "exp", "log", "atan" 116925828Ssam }; 117025828Ssam 117125828Ssam /* generate function opcodes */ 117225828Ssam if(p->in.op==UNARY FORTCALL && p->in.type==FLOAT && 117325828Ssam (p1 = p->in.left)->in.op==ICON && 117425828Ssam p1->tn.lval==0 && p1->in.type==INCREF(FTN|FLOAT)) { 117525828Ssam #ifdef FLEXNAMES 117625828Ssam p1->in.name++; 117725828Ssam #else 117825828Ssam strcpy(p1->in.name, p1->in.name[1]); 117925828Ssam #endif 118025828Ssam for(m=0; m<6; m++) 118125828Ssam if(!strcmp(p1->in.name, funcops[m])) 118225828Ssam break; 118325828Ssam if(m >= 6) 118425828Ssam uerror("no opcode for fortarn function %s", p1->in.name); 118525828Ssam } else 118625828Ssam uerror("illegal type of fortarn function"); 118725828Ssam p1 = p->in.right; 118825828Ssam p->in.op = FORTCALL; 118925828Ssam if(!canaddr(p1)) 119025828Ssam order( p1, INAREG|INBREG|SOREG|STARREG|STARNM ); 119125828Ssam m = match( p, INTAREG|INTBREG ); 119225828Ssam return(m != MDONE); 119325828Ssam } 119425828Ssam 119525828Ssam /* tbl */ 119625828Ssam int gc_numbytes; 119725828Ssam /* tbl */ 119825828Ssam 119925828Ssam gencall( p, cookie ) register NODE *p; { 120025828Ssam /* generate the call given by p */ 120125828Ssam register NODE *p1, *ptemp; 120225828Ssam register int temp, temp1; 120325828Ssam register int m; 120425828Ssam 120525828Ssam if( p->in.right ) temp = argsize( p->in.right ); 120625828Ssam else temp = 0; 120725828Ssam 120825828Ssam if( p->in.op == STCALL || p->in.op == UNARY STCALL ){ 120925828Ssam /* set aside room for structure return */ 121025828Ssam 121125828Ssam if( p->stn.stsize > temp ) temp1 = p->stn.stsize; 121225828Ssam else temp1 = temp; 121325828Ssam } 121425828Ssam 121525828Ssam if( temp > maxargs ) maxargs = temp; 121625828Ssam SETOFF(temp1,4); 121725828Ssam 121825828Ssam if( p->in.right ){ /* make temp node, put offset in, and generate args */ 121925828Ssam ptemp = talloc(); 122025828Ssam ptemp->in.op = OREG; 122125828Ssam ptemp->tn.lval = -1; 122225828Ssam ptemp->tn.rval = SP; 122325828Ssam #ifndef FLEXNAMES 122425828Ssam ptemp->in.name[0] = '\0'; 122525828Ssam #else 122625828Ssam ptemp->in.name = ""; 122725828Ssam #endif 122825828Ssam ptemp->in.rall = NOPREF; 122925828Ssam ptemp->in.su = 0; 123025828Ssam genargs( p->in.right, ptemp ); 123125828Ssam ptemp->in.op = FREE; 123225828Ssam } 123325828Ssam 123425828Ssam p1 = p->in.left; 123525828Ssam if( p1->in.op != ICON ){ 123625828Ssam if( p1->in.op != REG ){ 123725828Ssam if( p1->in.op != OREG || R2TEST(p1->tn.rval) ){ 123825828Ssam if( p1->in.op != NAME ){ 123925828Ssam order( p1, INAREG ); 124025828Ssam } 124125828Ssam } 124225828Ssam } 124325828Ssam } 124425828Ssam 124525828Ssam /* tbl 124625828Ssam setup gc_numbytes so reference to ZC works */ 124725828Ssam 124825828Ssam gc_numbytes = temp&(0x3ff); 124925828Ssam 125025828Ssam p->in.op = UNARY CALL; 125125828Ssam m = match( p, INTAREG|INTBREG ); 125225828Ssam 125325828Ssam return(m != MDONE); 125425828Ssam } 125525828Ssam 125625828Ssam /* tbl */ 125725828Ssam char * 125825828Ssam ccbranches[] = { 125925828Ssam "eql", 126025828Ssam "neq", 126125828Ssam "leq", 126225828Ssam "lss", 126325828Ssam "geq", 126425828Ssam "gtr", 126525828Ssam "lequ", 126625828Ssam "lssu", 126725828Ssam "gequ", 126825828Ssam "gtru", 126925828Ssam }; 127025828Ssam /* tbl */ 127125828Ssam 127225828Ssam cbgen( o, lab, mode ) { /* printf conditional and unconditional branches */ 127325828Ssam 127425828Ssam if(o != 0 && (o < EQ || o > UGT )) 127525828Ssam cerror( "bad conditional branch: %s", opst[o] ); 127625828Ssam printf( " j%s L%d\n", 127725828Ssam o == 0 ? "br" : ccbranches[o-EQ], lab ); 127825828Ssam } 127925828Ssam 128025828Ssam nextcook( p, cookie ) NODE *p; { 128125828Ssam /* we have failed to match p with cookie; try another */ 128225828Ssam if( cookie == FORREW ) return( 0 ); /* hopeless! */ 128325828Ssam if( !(cookie&(INTAREG|INTBREG)) ) return( INTAREG|INTBREG ); 128425828Ssam if( !(cookie&INTEMP) && asgop(p->in.op) ) return( INTEMP|INAREG|INTAREG|INTBREG|INBREG ); 128525828Ssam return( FORREW ); 128625828Ssam } 128725828Ssam 128825828Ssam lastchance( p, cook ) NODE *p; { 128925828Ssam /* forget it! */ 129025828Ssam return(0); 129125828Ssam } 129225828Ssam 129325828Ssam optim2( p ) register NODE *p; { 129425828Ssam # ifdef ONEPASS 129525828Ssam /* do local tree transformations and optimizations */ 129625828Ssam # define RV(p) p->in.right->tn.lval 129726076Ssam # define nncon(p) ((p)->in.op == ICON && (p)->in.name[0] == 0) 129830360Ssam register int o, i; 129930360Ssam register NODE *l, *r; 130025828Ssam 130130360Ssam switch (o = p->in.op) { 130230360Ssam 130330360Ssam case DIV: case ASG DIV: 130430360Ssam case MOD: case ASG MOD: 130530360Ssam /* 130630360Ssam * Change unsigned mods and divs to 130730360Ssam * logicals (mul is done in mip & c2) 130830360Ssam */ 130930360Ssam if (ISUNSIGNED(p->in.left->in.type) && nncon(p->in.right) && 131030360Ssam (i = ispow2(RV(p))) >= 0) { 131130360Ssam if (o == DIV || o == ASG DIV) { 131230360Ssam p->in.op = RS; 131330360Ssam RV(p) = i; 131430360Ssam } else { 131530360Ssam p->in.op = AND; 131630360Ssam RV(p)--; 131730360Ssam } 131830360Ssam if (asgop(o)) 131930360Ssam p->in.op = ASG p->in.op; 132025828Ssam } 132130360Ssam return; 132230360Ssam 132330360Ssam case SCONV: 132430360Ssam l = p->in.left; 132532879Sdonn if (anyfloat(p, l)) { 132632879Sdonn /* save some labor later */ 132732879Sdonn NODE *t = talloc(); 132832879Sdonn 132932879Sdonn if (p->in.type == UCHAR || p->in.type == USHORT) { 133032879Sdonn *t = *p; 133132879Sdonn t->in.type = UNSIGNED; 133232879Sdonn p->in.left = t; 133332879Sdonn } else if (l->in.type == UCHAR || l->in.type == USHORT) { 133432879Sdonn *t = *p; 133532879Sdonn t->in.type = INT; 133632879Sdonn p->in.left = t; 133732879Sdonn } 133832879Sdonn } else if (l->in.op != PCONV && 133932878Sdonn l->in.op != CALL && l->in.op != UNARY CALL && 134030360Ssam tlen(p) == tlen(l)) { 134132879Sdonn /* clobber conversions w/o side effects */ 134230360Ssam if (l->in.op != FLD) 134330360Ssam l->in.type = p->in.type; 134430360Ssam ncopy(p, l); 134530360Ssam l->in.op = FREE; 134630360Ssam } 134730360Ssam return; 134830360Ssam 134930360Ssam case ASSIGN: 135030360Ssam /* 135130360Ssam * Try to zap storage conversions of non-float items. 135230360Ssam */ 135330360Ssam r = p->in.right; 135432880Sdonn if (r->in.op == SCONV) { 135530360Ssam int wdest, wconv, wsrc; 135632880Sdonn 135732883Sdonn if (p->in.left->in.op == FLD) 135832883Sdonn return; 135932880Sdonn if (anyfloat(r, r->in.left)) { 136032880Sdonn /* let the code table handle two cases */ 136132880Sdonn if (p->in.left->in.type == UNSIGNED && 136232880Sdonn r->in.type == UNSIGNED) { 136332880Sdonn p->in.right = r->in.left; 136432880Sdonn r->in.op = FREE; 136532880Sdonn } else if ((p->in.left->in.type == FLOAT || 136632880Sdonn p->in.left->in.type == DOUBLE) && 136732880Sdonn p->in.left->in.type == r->in.type && 136832880Sdonn r->in.left->in.type == UNSIGNED) { 136932880Sdonn p->in.right = r->in.left; 137032880Sdonn r->in.op = FREE; 137132880Sdonn } 137232880Sdonn return; 137332880Sdonn } 137430360Ssam wdest = tlen(p->in.left); 137530360Ssam wconv = tlen(r); 137630360Ssam /* 137730360Ssam * If size doesn't change across assignment or 137830360Ssam * conversion expands src before shrinking again 137930360Ssam * due to the assignment, delete conversion so 138030360Ssam * code generator can create optimal code. 138130360Ssam */ 138230360Ssam if (wdest == wconv || 138330360Ssam (wdest == (wsrc = tlen(r->in.left)) && wconv > wsrc)) { 138430360Ssam p->in.right = r->in.left; 138530360Ssam r->in.op = FREE; 138630360Ssam } 138730360Ssam } 138830360Ssam return; 138925828Ssam } 139025828Ssam # endif 139125828Ssam } 139225828Ssam 139325828Ssam struct functbl { 139425828Ssam int fop; 139532877Sdonn TWORD ftype; 139625828Ssam char *func; 139732877Sdonn } opfunc[] = { 139832877Sdonn DIV, TANY, "udiv", 139932877Sdonn MOD, TANY, "urem", 140032877Sdonn ASG DIV, TANY, "audiv", 140132877Sdonn ASG MOD, TANY, "aurem", 140232877Sdonn 0, 0, 0 }; 140325828Ssam 140425828Ssam hardops(p) register NODE *p; { 140525828Ssam /* change hard to do operators into function calls. */ 140625828Ssam register NODE *q; 140725828Ssam register struct functbl *f; 140832877Sdonn register o; 140932877Sdonn NODE *old,*temp; 141025828Ssam 141125828Ssam o = p->in.op; 141232877Sdonn if( ! (optype(o)==BITYPE && 141332877Sdonn (ISUNSIGNED(p->in.left->in.type) || 141432877Sdonn ISUNSIGNED(p->in.right->in.type))) ) 141532877Sdonn return; 141625828Ssam 141725828Ssam for( f=opfunc; f->fop; f++ ) { 141825828Ssam if( o==f->fop ) goto convert; 141932877Sdonn } 142025828Ssam return; 142125828Ssam 142225828Ssam convert: 142325828Ssam if( asgop( o ) ) { 142432877Sdonn old = NIL; 142532877Sdonn switch( p->in.left->in.op ){ 142632877Sdonn case FLD: 142732877Sdonn q = p->in.left->in.left; 142832877Sdonn /* 142932877Sdonn * rewrite (lval.fld /= rval); as 143032877Sdonn * ((*temp).fld = udiv((*(temp = &lval)).fld,rval)); 143132877Sdonn * else the compiler will evaluate lval twice. 143232877Sdonn */ 143332877Sdonn if( q->in.op == UNARY MUL ){ 143432877Sdonn /* first allocate a temp storage */ 143532877Sdonn temp = talloc(); 143632877Sdonn temp->in.op = OREG; 143732877Sdonn temp->tn.rval = TMPREG; 143832877Sdonn temp->tn.lval = BITOOR(freetemp(1)); 143932877Sdonn temp->in.type = INCREF(p->in.type); 144032877Sdonn #ifdef FLEXNAMES 144132877Sdonn temp->in.name = ""; 144232877Sdonn #else 144332877Sdonn temp->in.name[0] = '\0'; 144432877Sdonn #endif 144532877Sdonn old = q->in.left; 144632877Sdonn q->in.left = temp; 144732877Sdonn } 144832877Sdonn /* fall thru ... */ 144925828Ssam 145032877Sdonn case REG: 145132877Sdonn case NAME: 145232877Sdonn case OREG: 145332877Sdonn /* change ASG OP to a simple OP */ 145432877Sdonn q = talloc(); 145532877Sdonn q->in.op = NOASG p->in.op; 145632877Sdonn q->in.rall = NOPREF; 145732877Sdonn q->in.type = p->in.type; 145832877Sdonn q->in.left = tcopy(p->in.left); 145932877Sdonn q->in.right = p->in.right; 146032877Sdonn p->in.op = ASSIGN; 146132877Sdonn p->in.right = q; 146232877Sdonn p = q; 146332877Sdonn f -= 2; /* Note: this depends on the table order */ 146432877Sdonn /* on the right side only - replace *temp with 146532877Sdonn *(temp = &lval), build the assignment node */ 146632877Sdonn if( old ){ 146732877Sdonn temp = q->in.left->in.left; /* the "*" node */ 146832877Sdonn q = talloc(); 146932877Sdonn q->in.op = ASSIGN; 147032877Sdonn q->in.left = temp->in.left; 147132877Sdonn q->in.right = old; 147232877Sdonn q->in.type = old->in.type; 147332877Sdonn #ifdef FLEXNAMES 147432877Sdonn q->in.name = ""; 147525828Ssam #else 147632877Sdonn q->in.name[0] = '\0'; 147725828Ssam #endif 147832877Sdonn temp->in.left = q; 147932877Sdonn } 148032877Sdonn break; 148125828Ssam 148232877Sdonn case UNARY MUL: 148332877Sdonn /* avoid doing side effects twice */ 148432877Sdonn q = p->in.left; 148532877Sdonn p->in.left = q->in.left; 148632877Sdonn q->in.op = FREE; 148732877Sdonn break; 148832877Sdonn 148932877Sdonn default: 149032877Sdonn cerror( "hardops: can't compute & LHS" ); 149132877Sdonn } 149232877Sdonn } 149332877Sdonn 149425828Ssam /* build comma op for args to function */ 149532877Sdonn q = talloc(); 149632877Sdonn q->in.op = CM; 149732877Sdonn q->in.rall = NOPREF; 149832877Sdonn q->in.type = INT; 149932877Sdonn q->in.left = p->in.left; 150032877Sdonn q->in.right = p->in.right; 150125828Ssam p->in.op = CALL; 150225828Ssam p->in.right = q; 150325828Ssam 150425828Ssam /* put function name in left node of call */ 150525828Ssam p->in.left = q = talloc(); 150625828Ssam q->in.op = ICON; 150725828Ssam q->in.rall = NOPREF; 150825828Ssam q->in.type = INCREF( FTN + p->in.type ); 150925828Ssam #ifndef FLEXNAMES 151032877Sdonn strcpy( q->in.name, f->func ); 151125828Ssam #else 151232877Sdonn q->in.name = f->func; 151325828Ssam #endif 151425828Ssam q->tn.lval = 0; 151525828Ssam q->tn.rval = 0; 151625828Ssam 151725828Ssam } 151825828Ssam 151925828Ssam zappost(p) NODE *p; { 152025828Ssam /* look for ++ and -- operators and remove them */ 152125828Ssam 152225828Ssam register int o, ty; 152325828Ssam register NODE *q; 152425828Ssam o = p->in.op; 152525828Ssam ty = optype( o ); 152625828Ssam 152725828Ssam switch( o ){ 152825828Ssam 152925828Ssam case INCR: 153025828Ssam case DECR: 153125828Ssam q = p->in.left; 153225828Ssam p->in.right->in.op = FREE; /* zap constant */ 153325828Ssam ncopy( p, q ); 153425828Ssam q->in.op = FREE; 153525828Ssam return; 153625828Ssam 153725828Ssam } 153825828Ssam 153925828Ssam if( ty == BITYPE ) zappost( p->in.right ); 154025828Ssam if( ty != LTYPE ) zappost( p->in.left ); 154125828Ssam } 154225828Ssam 154325828Ssam fixpre(p) NODE *p; { 154425828Ssam 154525828Ssam register int o, ty; 154625828Ssam o = p->in.op; 154725828Ssam ty = optype( o ); 154825828Ssam 154925828Ssam switch( o ){ 155025828Ssam 155125828Ssam case ASG PLUS: 155225828Ssam p->in.op = PLUS; 155325828Ssam break; 155425828Ssam case ASG MINUS: 155525828Ssam p->in.op = MINUS; 155625828Ssam break; 155725828Ssam } 155825828Ssam 155925828Ssam if( ty == BITYPE ) fixpre( p->in.right ); 156025828Ssam if( ty != LTYPE ) fixpre( p->in.left ); 156125828Ssam } 156225828Ssam 156325828Ssam NODE * addroreg(l) NODE *l; 156425828Ssam /* OREG was built in clocal() 156525828Ssam * for an auto or formal parameter 156625828Ssam * now its address is being taken 156725828Ssam * local code must unwind it 156825828Ssam * back to PLUS/MINUS REG ICON 156925828Ssam * according to local conventions 157025828Ssam */ 157125828Ssam { 157225828Ssam cerror("address of OREG taken"); 157325828Ssam } 157425828Ssam 157525828Ssam # ifndef ONEPASS 157625828Ssam main( argc, argv ) char *argv[]; { 157725828Ssam return( mainp2( argc, argv ) ); 157825828Ssam } 157925828Ssam # endif 158025828Ssam 158130360Ssam strip(p) register NODE *p; { 158230360Ssam NODE *q; 158330360Ssam 158430360Ssam /* strip nodes off the top when no side effects occur */ 158530360Ssam for( ; ; ) { 158630360Ssam switch( p->in.op ) { 158730360Ssam case SCONV: /* remove lint tidbits */ 158830360Ssam q = p->in.left; 158930360Ssam ncopy( p, q ); 159030360Ssam q->in.op = FREE; 159130360Ssam break; 159230360Ssam /* could probably add a few more here */ 159330360Ssam default: 159430360Ssam return; 159530360Ssam } 159630360Ssam } 159730360Ssam } 159830360Ssam 159925828Ssam myreader(p) register NODE *p; { 160030360Ssam strip( p ); /* strip off operations with no side effects */ 160125828Ssam walkf( p, hardops ); /* convert ops to function calls */ 160225828Ssam canon( p ); /* expands r-vals for fileds */ 160325828Ssam walkf( p, optim2 ); 160425828Ssam } 1605