132890Sdonn #ifndef lint
2*33622Sdonn static char sccsid[] = "@(#)local2.c 1.32 (Berkeley) 02/29/88";
332890Sdonn #endif
425828Ssam
526076Ssam # include "pass2.h"
626076Ssam # include <ctype.h>
726162Ssam
826162Ssam # define putstr(s) fputs((s), stdout)
929672Ssam # define ISCHAR(p) (p->in.type == UCHAR || p->in.type == CHAR)
1026162Ssam
1125828Ssam # ifdef FORT
1225828Ssam int ftlab1, ftlab2;
1325828Ssam # endif
1425828Ssam /* a lot of the machine dependent parts of the second pass */
1525828Ssam
1625828Ssam # define BITMASK(n) ((1L<<n)-1)
1725828Ssam
1825828Ssam # ifndef ONEPASS
1932886Sdonn /*ARGSUSED*/
where(c)2025828Ssam where(c){
2125828Ssam fprintf( stderr, "%s, line %d: ", filename, lineno );
2225828Ssam }
2325828Ssam # endif
2425828Ssam
lineid(l,fn)2525828Ssam lineid( l, fn ) char *fn; {
2625828Ssam /* identify line l and file fn */
2725828Ssam printf( "# line %d, file %s\n", l, fn );
2825828Ssam }
2925828Ssam
3025828Ssam int ent_mask;
3125828Ssam
eobl2()3225828Ssam eobl2(){
3325828Ssam register OFFSZ spoff; /* offset from stack pointer */
3425828Ssam #ifndef FORT
3525828Ssam extern int ftlab1, ftlab2;
3625828Ssam #endif
3725828Ssam
3825828Ssam spoff = maxoff;
3925828Ssam spoff /= SZCHAR;
4025828Ssam SETOFF(spoff,4);
4125828Ssam #ifdef FORT
4225828Ssam #ifndef FLEXNAMES
4332886Sdonn printf( " .set .F%d,%ld\n", ftnno, spoff );
4425828Ssam #else
4525828Ssam /* SHOULD BE L%d ... ftnno but must change pc/f77 */
4632886Sdonn printf( " .set LF%d,%ld\n", ftnno, spoff );
4725828Ssam #endif
4825828Ssam printf( " .set LWM%d,0x%x\n", ftnno, ent_mask&0x1ffc|0x1000);
4925828Ssam #else
5025828Ssam printf( " .set L%d,0x%x\n", ftnno, ent_mask&0x1ffc);
5125828Ssam printf( "L%d:\n", ftlab1);
5225828Ssam if( maxoff > AUTOINIT )
5332886Sdonn printf( " subl3 $%ld,fp,sp\n", spoff);
5425828Ssam printf( " jbr L%d\n", ftlab2);
5525828Ssam #endif
5625828Ssam ent_mask = 0;
5725828Ssam maxargs = -1;
5825828Ssam }
5925828Ssam
6025828Ssam struct hoptab { int opmask; char * opstring; } ioptab[] = {
6125828Ssam
6225828Ssam PLUS, "add",
6325828Ssam MINUS, "sub",
6425828Ssam MUL, "mul",
6525828Ssam DIV, "div",
6625828Ssam MOD, "div",
6725828Ssam OR, "or",
6825828Ssam ER, "xor",
6925828Ssam AND, "and",
7025828Ssam -1, "" };
7125828Ssam
hopcode(f,o)7225828Ssam hopcode( f, o ){
7325828Ssam /* output the appropriate string from the above table */
7425828Ssam
7525828Ssam register struct hoptab *q;
7625828Ssam
7725828Ssam if(asgop(o))
7825828Ssam o = NOASG o;
7925828Ssam for( q = ioptab; q->opmask>=0; ++q ){
8025828Ssam if( q->opmask == o ){
8125828Ssam if(f == 'E')
8225828Ssam printf( "e%s", q->opstring);
8325828Ssam else
8425828Ssam printf( "%s%c", q->opstring, tolower(f));
8525828Ssam return;
8625828Ssam }
8725828Ssam }
8825828Ssam cerror( "no hoptab for %s", opst[o] );
8925828Ssam }
9025828Ssam
9125828Ssam char *
9225828Ssam rnames[] = { /* keyed to register number tokens */
9325828Ssam
9425828Ssam "r0", "r1",
9525828Ssam "r2", "r3", "r4", "r5",
9625828Ssam "r6", "r7", "r8", "r9", "r10", "r11",
9725828Ssam "r12", "fp", "sp", "pc",
9825828Ssam };
9925828Ssam
10025828Ssam /* output register name and update entry mask */
10125828Ssam char *
rname(r)10225828Ssam rname(r)
10325828Ssam register int r;
10425828Ssam {
10525828Ssam
10632887Sdonn if (!istreg(r))
10732887Sdonn ent_mask |= 1<<r;
10825828Ssam return(rnames[r]);
10925828Ssam }
11025828Ssam
11125828Ssam int rstatus[] = {
11225828Ssam SAREG|STAREG, SAREG|STAREG,
11325828Ssam SAREG|STAREG, SAREG|STAREG, SAREG|STAREG, SAREG|STAREG,
11425828Ssam SAREG, SAREG, SAREG, SAREG, SAREG, SAREG,
11525828Ssam SAREG, SAREG, SAREG, SAREG,
11625828Ssam };
11725828Ssam
tlen(p)11825828Ssam tlen(p) NODE *p;
11925828Ssam {
12025828Ssam switch(p->in.type) {
12125828Ssam case CHAR:
12225828Ssam case UCHAR:
12325828Ssam return(1);
12425828Ssam
12525828Ssam case SHORT:
12625828Ssam case USHORT:
12732886Sdonn return(SZSHORT/SZCHAR);
12825828Ssam
12925828Ssam case DOUBLE:
13032886Sdonn return(SZDOUBLE/SZCHAR);
13125828Ssam
13225828Ssam default:
13332886Sdonn return(SZINT/SZCHAR);
13425828Ssam }
13525828Ssam }
13625828Ssam
mixtypes(p,q)13732886Sdonn mixtypes(p, q) NODE *p, *q;
13830360Ssam {
13930360Ssam register TWORD tp, tq;
14030360Ssam
14130360Ssam tp = p->in.type;
14230360Ssam tq = q->in.type;
14332886Sdonn
14432886Sdonn return( (tp==FLOAT || tp==DOUBLE) !=
14532886Sdonn (tq==FLOAT || tq==DOUBLE) );
14630360Ssam }
14730360Ssam
prtype(n)14825828Ssam prtype(n) NODE *n;
14925828Ssam {
15025828Ssam switch (n->in.type)
15125828Ssam {
15225828Ssam
15325828Ssam case DOUBLE:
15426162Ssam putchar('d');
15525828Ssam return;
15625828Ssam
15725828Ssam case FLOAT:
15826162Ssam putchar('f');
15925828Ssam return;
16025828Ssam
16132886Sdonn case LONG:
16232886Sdonn case ULONG:
16325828Ssam case INT:
16425828Ssam case UNSIGNED:
16526162Ssam putchar('l');
16625828Ssam return;
16725828Ssam
16825828Ssam case SHORT:
16925828Ssam case USHORT:
17026162Ssam putchar('w');
17125828Ssam return;
17225828Ssam
17325828Ssam case CHAR:
17425828Ssam case UCHAR:
17526162Ssam putchar('b');
17625828Ssam return;
17725828Ssam
17825828Ssam default:
17925828Ssam if ( !ISPTR( n->in.type ) ) cerror("zzzcode- bad type");
18025828Ssam else {
18126162Ssam putchar('l');
18225828Ssam return;
18325828Ssam }
18425828Ssam }
18525828Ssam }
18625828Ssam
zzzcode(p,c)18725828Ssam zzzcode( p, c ) register NODE *p; {
18825828Ssam register int m;
18925828Ssam int val;
19025828Ssam switch( c ){
19125828Ssam
19225828Ssam case 'N': /* logical ops, turned into 0-1 */
19325828Ssam /* use register given by register 1 */
19425828Ssam cbgen( 0, m=getlab(), 'I' );
19525828Ssam deflab( p->bn.label );
19625828Ssam printf( " clrl %s\n", rname(getlr( p, '1' )->tn.rval) );
19725828Ssam deflab( m );
19825828Ssam return;
19925828Ssam
20025828Ssam case 'P':
20125828Ssam cbgen( p->in.op, p->bn.label, c );
20225828Ssam return;
20325828Ssam
20432876Sdonn case 'G': /* i *= f; asgops with int lhs and float rhs */
20525828Ssam {
20632876Sdonn register NODE *l, *r, *s;
20732876Sdonn int lt, rt;
20825828Ssam
20932876Sdonn l = p->in.left;
21032876Sdonn r = p->in.right;
21132876Sdonn s = talloc();
21232876Sdonn rt = r->in.type;
21332876Sdonn lt = l->in.type;
21425828Ssam
21532876Sdonn if (lt != INT && lt != UNSIGNED) {
21632876Sdonn s->in.op = SCONV;
21732876Sdonn s->in.left = l;
21832876Sdonn s->in.type = ISUNSIGNED(lt) ? UNSIGNED : INT;
21932876Sdonn zzzcode(s, 'U');
22032876Sdonn putstr("\n\t");
22125828Ssam }
22232876Sdonn
22332876Sdonn if (ISUNSIGNED(lt)) {
22432876Sdonn s->in.op = SCONV;
22532876Sdonn s->in.left = lt == UNSIGNED ? l : resc;
22632876Sdonn s->in.type = rt;
22732876Sdonn unsigned_to_float(s);
22832876Sdonn } else {
22932876Sdonn putstr("cvl");
23032876Sdonn prtype(r);
23132876Sdonn putchar('\t');
23232876Sdonn adrput(lt == INT ? l : resc);
23332876Sdonn }
23432876Sdonn putstr("\n\t");
23532876Sdonn
23632876Sdonn hopcode(rt == FLOAT ? 'F' : 'D', p->in.op);
23726162Ssam putchar('\t');
23825828Ssam adrput(r);
23932876Sdonn
24032876Sdonn if (ISUNSIGNED(lt)) {
24132876Sdonn putstr("\n\t");
24232876Sdonn s->in.op = SCONV;
24332876Sdonn s->in.left = r; /* we need only the type */
24432876Sdonn s->in.type = UNSIGNED;
24532876Sdonn float_to_unsigned(s);
24632876Sdonn } else {
24732876Sdonn putstr("\n\tcv");
24832876Sdonn prtype(r);
24932876Sdonn putstr("l\t");
25032876Sdonn if (lt == INT)
25132876Sdonn adrput(l);
25232876Sdonn else
25332876Sdonn adrput(resc);
25432876Sdonn }
25532876Sdonn if (lt != INT) {
25632876Sdonn putstr("\n\t");
25732876Sdonn s->in.op = ASSIGN;
25832876Sdonn s->in.left = l;
25932876Sdonn s->in.right = resc;
26032876Sdonn s->in.type = lt;
26132876Sdonn zzzcode(s, 'U');
26232876Sdonn }
26332876Sdonn
26432876Sdonn s->in.op = FREE;
26525828Ssam return;
26625828Ssam }
26725828Ssam
26832886Sdonn case 'J': /* unsigned DIV/MOD with constant divisors */
26932886Sdonn {
27032886Sdonn register int ck = INAREG;
27132886Sdonn int label1, label2;
27232886Sdonn
27332886Sdonn /* case constant <= 1 is handled by optim() in pass 1 */
27432886Sdonn /* case constant < 0x80000000 is handled in table */
27532886Sdonn switch( p->in.op ) {
27632887Sdonn /* case DIV: handled in optim2() */
27732886Sdonn case MOD:
27832886Sdonn if( p->in.left->in.op == REG &&
27932886Sdonn p->in.left->tn.rval == resc->tn.rval )
28032886Sdonn goto asgmod;
28132886Sdonn label1 = getlab();
28232886Sdonn expand(p, ck, "movl\tAL,A1\n\tcmpl\tA1,AR\n");
28332886Sdonn printf("\tjlssu\tL%d\n", label1);
28432886Sdonn expand(p, ck, "\tsubl2\tAR,A1\n");
28532886Sdonn printf("L%d:", label1);
28632886Sdonn break;
28732886Sdonn case ASG DIV:
28832886Sdonn label1 = getlab();
28932886Sdonn label2 = getlab();
29032886Sdonn expand(p, ck, "cmpl\tAL,AR\n");
29132886Sdonn printf("\tjgequ\tL%d\n", label1);
29232886Sdonn expand(p, ck, "\tmovl\t$1,AL\n");
29332886Sdonn printf("\tjbr\tL%d\nL%d:\n", label2, label1);
29432886Sdonn expand(p, ck, "\tclrl\tAL\n");
29532886Sdonn printf("L%d:", label2);
29632886Sdonn break;
29732886Sdonn case ASG MOD:
29832886Sdonn asgmod:
29932886Sdonn label1 = getlab();
30032886Sdonn expand(p, ck, "cmpl\tAL,AR\n");
30132886Sdonn printf("\tjlssu\tL%d\n", label1);
30232886Sdonn expand(p, ck, "\tsubl2\tAR,AL\n");
30332886Sdonn printf("L%d:", label1);
30432886Sdonn break;
30532886Sdonn }
30632886Sdonn return;
30732886Sdonn }
30832886Sdonn
30925828Ssam case 'B': /* get oreg value in temp register for shift */
31025828Ssam {
31125828Ssam register NODE *r;
31225828Ssam if (xdebug) eprint(p, 0, &val, &val);
31325828Ssam r = p->in.right;
31432886Sdonn if( tlen(r) == SZINT/SZCHAR && r->in.type != FLOAT )
31526162Ssam putstr("movl");
31625828Ssam else {
31726162Ssam putstr(ISUNSIGNED(r->in.type) ? "movz" : "cvt");
31825828Ssam prtype(r);
31926162Ssam putchar('l');
32025828Ssam }
32125828Ssam return;
32225828Ssam }
32325828Ssam
32432886Sdonn case 'C': /* generate 'call[fs] $bytes' */
32525828Ssam {
32625828Ssam extern int gc_numbytes;
32725828Ssam extern int xdebug;
32825828Ssam
32925828Ssam if (xdebug) printf("->%d<-",gc_numbytes);
33025828Ssam
33125828Ssam printf("call%c $%d",
33225828Ssam (p->in.left->in.op==ICON && gc_numbytes<60)?'f':'s',
33325828Ssam gc_numbytes+4);
33432886Sdonn /* don't change to double (here's the only place to catch it) */
33525828Ssam if(p->in.type == FLOAT)
33625828Ssam rtyflg = 1;
33725828Ssam return;
33825828Ssam }
33925828Ssam
34025828Ssam case 'D': /* INCR and DECR */
34133413Sdonn if (p->in.left->in.type == FLOAT)
34233413Sdonn expand(p, INAREG, "movl\tAL,A1");
34333413Sdonn else if (p->in.left->in.type == DOUBLE)
34433413Sdonn expand(p, INAREG, "ldd\tAL\n\tstd\tA1");
34533413Sdonn else
34633413Sdonn zzzcode(p->in.left, 'U');
34726162Ssam putstr("\n ");
34825828Ssam
34925828Ssam case 'E': /* INCR and DECR, FOREFF */
35033368Sdonn if (p->in.right->in.op == ICON && p->in.right->tn.lval == 1)
35125828Ssam {
35226162Ssam putstr(p->in.op == INCR ? "inc" : "dec");
35325828Ssam prtype(p->in.left);
35426162Ssam putchar('\t');
35525828Ssam adrput(p->in.left);
35625828Ssam return;
35725828Ssam }
35833368Sdonn else if (p->in.left->in.type == FLOAT || p->in.left->in.type == DOUBLE) {
35933413Sdonn if (c == 'E' || p->in.left->in.type == FLOAT)
36033413Sdonn expand(p, INAREG, "ldZL\tAL\n\t");
36133368Sdonn if (p->in.op == INCR)
36233413Sdonn expand(p, INAREG, "addZL\tAR\n\tstZL\tAL");
36333368Sdonn else /* DECR */
36433413Sdonn expand(p, INAREG, "subZL\tAR\n\tstZL\tAL");
36533368Sdonn return;
36633368Sdonn }
36726162Ssam putstr(p->in.op == INCR ? "add" : "sub");
36825828Ssam prtype(p->in.left);
36926162Ssam putstr("2 ");
37025828Ssam adrput(p->in.right);
37126162Ssam putchar(',');
37225828Ssam adrput(p->in.left);
37325828Ssam return;
37425828Ssam
37525828Ssam case 'F': /* masked constant for fields */
37625947Ssam printf(ACONFMT, (p->in.right->tn.lval&((1<<fldsz)-1))<<fldshf);
37725828Ssam return;
37825828Ssam
37932884Sdonn case 'I': /* produce value of bitfield assignment */
38032884Sdonn /* avoid shifts -- shifts are SLOW on this machine */
38132887Sdonn /* XXX this wouldn't be necessary if we were smarter
38232887Sdonn and masked BEFORE shifting XXX */
38332884Sdonn {
38432886Sdonn register NODE *r = p->in.right;
38532886Sdonn if(r->in.op == ICON && r->tn.name[0] == '\0') {
38632886Sdonn putstr("movl\t");
38732886Sdonn printf(ACONFMT, r->tn.lval & ((1<<fldsz)-1));
38832886Sdonn }
38932886Sdonn else {
39032886Sdonn putstr("andl3\t");
39132886Sdonn printf(ACONFMT, (1 << fldsz) - 1);
39232884Sdonn putchar(',');
39332886Sdonn adrput(r);
39432884Sdonn }
39532886Sdonn putchar(',');
39632886Sdonn adrput(resc);
39732886Sdonn break;
39832886Sdonn }
39932884Sdonn
40025828Ssam case 'H': /* opcode for shift */
40125828Ssam if(p->in.op == LS || p->in.op == ASG LS)
40226162Ssam putstr("shll");
40325828Ssam else if(ISUNSIGNED(p->in.left->in.type))
40426162Ssam putstr("shrl");
40525828Ssam else
40626162Ssam putstr("shar");
40725828Ssam return;
40825828Ssam
40925828Ssam case 'L': /* type of left operand */
41025828Ssam case 'R': /* type of right operand */
41125828Ssam {
41225828Ssam register NODE *n;
41325828Ssam extern int xdebug;
41425828Ssam
41525828Ssam n = getlr ( p, c);
41625828Ssam if (xdebug) printf("->%d<-", n->in.type);
41725828Ssam
41825828Ssam prtype(n);
41925828Ssam return;
42025828Ssam }
42125828Ssam
42230360Ssam case 'M': { /* initiate ediv for mod and unsigned div */
42332887Sdonn putstr("clrl\t");
42432887Sdonn adrput(resc);
42532887Sdonn putstr("\n\tmovl\t");
42625828Ssam adrput(p->in.left);
42732887Sdonn putchar(',');
42832887Sdonn upput(resc, SZLONG);
42932887Sdonn printf("\n\tjgeq\tL%d\n\tmnegl\t$1,", m = getlab());
43032887Sdonn adrput(resc);
43132887Sdonn putchar('\n');
43232887Sdonn deflab(m);
43325828Ssam return;
43430360Ssam }
43525828Ssam
43630360Ssam case 'T': { /* rounded structure length for arguments */
43730360Ssam int size = p->stn.stsize;
43825828Ssam SETOFF( size, 4);
43925828Ssam printf("movab -%d(sp),sp", size);
44025828Ssam return;
44130360Ssam }
44225828Ssam
44325828Ssam case 'S': /* structure assignment */
44425977Ssam stasg(p);
44525977Ssam break;
44625828Ssam
44732886Sdonn #ifdef I_don_t_understand_this
44829672Ssam case 'X': /* multiplication for short and char */
44929672Ssam if (ISUNSIGNED(p->in.left->in.type))
45029672Ssam printf("\tmovz");
45129672Ssam else
45229672Ssam printf("\tcvt");
45329672Ssam zzzcode(p, 'L');
45429672Ssam printf("l\t");
45529672Ssam adrput(p->in.left);
45629672Ssam printf(",");
45729672Ssam adrput(&resc[0]);
45829672Ssam printf("\n");
45929672Ssam if (ISUNSIGNED(p->in.right->in.type))
46029672Ssam printf("\tmovz");
46129672Ssam else
46229672Ssam printf("\tcvt");
46329672Ssam zzzcode(p, 'R');
46429672Ssam printf("l\t");
46529672Ssam adrput(p->in.right);
46629672Ssam printf(",");
46729672Ssam adrput(&resc[1]);
46829672Ssam printf("\n");
46929672Ssam return;
47032886Sdonn #endif
47129672Ssam
47230360Ssam case 'U': /* SCONV */
47330360Ssam case 'V': /* SCONV with FORCC */
47430360Ssam sconv(p, c == 'V');
47530360Ssam break;
47630360Ssam
47732879Sdonn case 'W': { /* SCONV or ASSIGN float/double => unsigned */
47832879Sdonn NODE *src = p->in.op == SCONV ? p->in.left : p->in.right;
47932879Sdonn
48032876Sdonn putstr("ld");
48132879Sdonn prtype(src);
48232876Sdonn putchar('\t');
48332879Sdonn adrput(src);
48432876Sdonn putstr("\n\t");
48532876Sdonn float_to_unsigned(p);
48632876Sdonn break;
48732879Sdonn }
48832876Sdonn
48932879Sdonn case 'Y': /* SCONV or ASSIGN unsigned => float/double */
49032876Sdonn unsigned_to_float(p); /* stores into accumulator */
49132876Sdonn putstr("\n\tst");
49232876Sdonn prtype(p);
49332876Sdonn putchar('\t');
49432879Sdonn if (p->in.op == SCONV)
49532879Sdonn adrput(resc);
49632879Sdonn else
49732879Sdonn adrput(p->in.left);
49832879Sdonn rtyflg = 1;
49932876Sdonn break;
50032876Sdonn
50132886Sdonn #ifdef I_don_t_understand_this
50230360Ssam case 'Z':
50330360Ssam p = p->in.right;
50430360Ssam switch (p->in.type) {
50530360Ssam case SHORT: {
50630360Ssam short w = p->tn.lval;
50730360Ssam p->tn.lval = w;
50830360Ssam break;
50930360Ssam }
51030360Ssam case CHAR: {
51130360Ssam char c = p->tn.lval;
51230360Ssam p->tn.lval = c;
51330360Ssam break;
51430360Ssam }
51530360Ssam }
51630360Ssam printf("$%d", p->tn.lval);
51730360Ssam break;
51832886Sdonn #endif
51930360Ssam
52025977Ssam default:
52125977Ssam cerror( "illegal zzzcode" );
52225977Ssam }
52330360Ssam }
52425828Ssam
52525977Ssam #define MOVB(dst, src, off) { \
52626162Ssam putstr("\tmovb\t"); upput(src, off); putchar(','); \
52725977Ssam upput(dst, off); putchar('\n'); \
52825977Ssam }
52925977Ssam #define MOVW(dst, src, off) { \
53026162Ssam putstr("\tmovw\t"); upput(src, off); putchar(','); \
53125977Ssam upput(dst, off); putchar('\n'); \
53225977Ssam }
53325977Ssam #define MOVL(dst, src, off) { \
53426162Ssam putstr("\tmovl\t"); upput(src, off); putchar(','); \
53525977Ssam upput(dst, off); putchar('\n'); \
53625977Ssam }
53725977Ssam /*
53825977Ssam * Generate code for a structure assignment.
53925977Ssam */
stasg(p)54025977Ssam stasg(p)
54125977Ssam register NODE *p;
54225977Ssam {
54325977Ssam register NODE *l, *r;
54425977Ssam register int size;
54525828Ssam
54625977Ssam switch (p->in.op) {
54725977Ssam case STASG: /* regular assignment */
54825977Ssam l = p->in.left;
54925977Ssam r = p->in.right;
55025977Ssam break;
55125977Ssam case STARG: /* place arg on the stack */
55225977Ssam l = getlr(p, '3');
55325977Ssam r = p->in.left;
55425977Ssam break;
55525977Ssam default:
55625977Ssam cerror("STASG bad");
55725977Ssam /*NOTREACHED*/
55825977Ssam }
55925977Ssam /*
56025977Ssam * Pun source for use in code generation.
56125977Ssam */
56225977Ssam switch (r->in.op) {
56325977Ssam case ICON:
56425977Ssam r->in.op = NAME;
56525977Ssam break;
56625977Ssam case REG:
56725977Ssam r->in.op = OREG;
56825977Ssam break;
56925977Ssam default:
57025977Ssam cerror( "STASG-r" );
57125977Ssam /*NOTREACHED*/
57225977Ssam }
57325977Ssam size = p->stn.stsize;
57425977Ssam if (size <= 0 || size > 65535)
57525977Ssam cerror("structure size out of range");
57625977Ssam /*
57725977Ssam * Generate optimized code based on structure size
57825977Ssam * and alignment properties....
57925977Ssam */
58025977Ssam switch (size) {
58125828Ssam
58225977Ssam case 1:
58326162Ssam putstr("\tmovb\t");
58425977Ssam optimized:
58525977Ssam adrput(r);
58626162Ssam putchar(',');
58725977Ssam adrput(l);
58826162Ssam putchar('\n');
58925977Ssam break;
59025828Ssam
59125977Ssam case 2:
59225977Ssam if (p->stn.stalign != 2) {
59325977Ssam MOVB(l, r, SZCHAR);
59426162Ssam putstr("\tmovb\t");
59525977Ssam } else
59626162Ssam putstr("\tmovw\t");
59725977Ssam goto optimized;
59825977Ssam
59925977Ssam case 4:
60025977Ssam if (p->stn.stalign != 4) {
60125977Ssam if (p->stn.stalign != 2) {
60225977Ssam MOVB(l, r, 3*SZCHAR);
60325977Ssam MOVB(l, r, 2*SZCHAR);
60425977Ssam MOVB(l, r, 1*SZCHAR);
60526162Ssam putstr("\tmovb\t");
60625947Ssam } else {
60725977Ssam MOVW(l, r, SZSHORT);
60826162Ssam putstr("\tmovw\t");
60925828Ssam }
61025977Ssam } else
61126162Ssam putstr("\tmovl\t");
61225977Ssam goto optimized;
61325828Ssam
61425977Ssam case 6:
61525977Ssam if (p->stn.stalign != 2)
61625977Ssam goto movblk;
61725977Ssam MOVW(l, r, 2*SZSHORT);
61825977Ssam MOVW(l, r, 1*SZSHORT);
61926162Ssam putstr("\tmovw\t");
62025977Ssam goto optimized;
62125977Ssam
62225977Ssam case 8:
62325977Ssam if (p->stn.stalign == 4) {
62425977Ssam MOVL(l, r, SZLONG);
62526162Ssam putstr("\tmovl\t");
62625977Ssam goto optimized;
62725977Ssam }
62825977Ssam /* fall thru...*/
62925977Ssam
63025977Ssam default:
63125977Ssam movblk:
63225977Ssam /*
63325977Ssam * Can we ever get a register conflict with R1 here?
63425977Ssam */
63526162Ssam putstr("\tmovab\t");
63632890Sdonn if(r->in.op == OREG && r->tn.rval == R1)
63732890Sdonn {
63832890Sdonn adrput(r);
63932890Sdonn printf(",r0\n\tmovab\t");
64032890Sdonn adrput(l);
64132890Sdonn putstr(",r1\n");
64232890Sdonn }
64332890Sdonn else
64432890Sdonn {
64532890Sdonn adrput(l);
64632890Sdonn putstr(",r1\n\tmovab\t");
64732890Sdonn adrput(r);
64832890Sdonn printf(",r0\n");
64932890Sdonn }
65032890Sdonn printf("\tmovl\t$%d,r2\n\tmovblk\n", size);
65125977Ssam rname(R2);
65225828Ssam break;
65325977Ssam }
65425977Ssam /*
65525977Ssam * Reverse above pun for reclaim.
65625977Ssam */
65725977Ssam if (r->in.op == NAME)
65825977Ssam r->in.op = ICON;
65925977Ssam else if (r->in.op == OREG)
66025977Ssam r->in.op = REG;
66125977Ssam }
66225828Ssam
66325977Ssam /*
66432876Sdonn * Convert a float or double in the accumulator into an unsigned int.
66532876Sdonn * Unlike the vax, the tahoe stores 0 into the destination
66632876Sdonn * on a conversion of > 2 ** 31, so we compensate.
66732876Sdonn */
float_to_unsigned(p)66832876Sdonn float_to_unsigned(p)
66932876Sdonn NODE *p;
67032876Sdonn {
67132876Sdonn register NODE *l = p->in.left;
67232876Sdonn int label1 = getlab();
67332876Sdonn int label2 = getlab();
67432876Sdonn int label3 = 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\t0x50000000", label1);
68632879Sdonn if (src->in.type == DOUBLE)
68732879Sdonn putstr(", 0x00000000 # .double");
68832879Sdonn else
68932879Sdonn putstr(" # .float");
69032879Sdonn putstr(" 2147483648\n\t.text\n\tcmp");
69132879Sdonn prtype(src);
69232876Sdonn printf("\tL%d\n\tjlss\tL%d\n\tsub", label1, label2);
69332879Sdonn prtype(src);
69432876Sdonn printf("\tL%d\n\tcv", label1);
69532879Sdonn prtype(src);
69632876Sdonn putstr("l\t");
69732879Sdonn adrput(dst);
69832876Sdonn putstr("\n\taddl2\t$-2147483648,");
69932879Sdonn adrput(dst);
70032876Sdonn printf("\n\tjbr\tL%d\nL%d:\n\tcv", label3, label2);
70132879Sdonn prtype(src);
70232876Sdonn putstr("l\t");
70332879Sdonn adrput(dst);
70432876Sdonn printf("\nL%d:", label3);
70532876Sdonn }
70632876Sdonn
70732876Sdonn /*
70832876Sdonn * Convert an unsigned int into a float or double, leaving the result
70932876Sdonn * in the accumulator.
71032876Sdonn */
unsigned_to_float(p)71132876Sdonn unsigned_to_float(p)
71232876Sdonn register NODE *p;
71332876Sdonn {
71432876Sdonn int label1 = getlab();
71532876Sdonn int label2 = getlab();
71632879Sdonn NODE *src, *dst;
71732876Sdonn
71832879Sdonn if (p->in.op == SCONV) {
71932879Sdonn src = p->in.left;
72032879Sdonn dst = resc;
72132879Sdonn } else {
72232879Sdonn src = p->in.right;
72332879Sdonn dst = p->in.left;
72432879Sdonn }
72532879Sdonn
72632876Sdonn printf(".data\n\t.align\t2\nL%d:\n\t.long\t0x50800000", label2);
72732876Sdonn if (p->in.type == DOUBLE)
72832879Sdonn putstr(", 0x00000000 # .double");
72932879Sdonn else
73032879Sdonn putstr(" # .float");
73132879Sdonn putstr(" 4294967296\n\t.text\n\tmovl\t");
73232879Sdonn adrput(src);
73332876Sdonn putchar(',');
73432879Sdonn adrput(dst);
73532876Sdonn putstr("\n\tcvl");
73632876Sdonn prtype(p);
73732876Sdonn putchar('\t');
73832879Sdonn adrput(dst);
73932879Sdonn printf("\n\tjgeq\tL%d\n\tadd", label1);
74032879Sdonn prtype(p);
74132879Sdonn printf("\tL%d\nL%d:", label2, label1);
74232876Sdonn }
74332876Sdonn
74432876Sdonn /*
74532875Sdonn * Prlen() is a cheap prtype()...
74632875Sdonn */
74732875Sdonn static char convtab[SZINT/SZCHAR + 1] = {
74832875Sdonn '?', 'b', 'w', '?', 'l'
74932875Sdonn };
75032875Sdonn #define prlen(len) putchar(convtab[len])
75132875Sdonn
75232875Sdonn
75332875Sdonn /*
75432873Sdonn * Generate code for integral scalar conversions.
75532875Sdonn * Some of this code is designed to work around a tahoe misfeature
75632875Sdonn * that causes sign- and zero- extension to be defeated in
75732875Sdonn * certain circumstances.
75832875Sdonn * Basically if the source operand of a CVT or MOVZ instruction is
75932875Sdonn * shorter than the destination, and the source is a register
76032875Sdonn * or an immediate constant, sign- and zero- extension are
76132875Sdonn * ignored and the high bits of the source are copied. (Note
76232875Sdonn * that zero-extension is not a problem for immediate
76332875Sdonn * constants.)
76433351Sdonn * Another problem -- condition codes for a conversion with a
76533351Sdonn * register source reflect the source rather than the destination.
76632873Sdonn */
sconv(p,forcc)76732873Sdonn sconv(p, forcc)
76832873Sdonn NODE *p;
76932873Sdonn int forcc;
77032873Sdonn {
77132873Sdonn register NODE *src, *dst;
77232873Sdonn register NODE *tmp;
77332873Sdonn register int srclen, dstlen;
77432873Sdonn int srctype, dsttype;
77532873Sdonn int val;
77632882Sdonn int neg = 0;
77730360Ssam
77832873Sdonn if (p->in.op == ASSIGN) {
77932879Sdonn src = p->in.right;
78032879Sdonn dst = p->in.left;
78132873Sdonn dstlen = tlen(dst);
78232873Sdonn dsttype = dst->in.type;
78332879Sdonn } else if (p->in.op == SCONV) {
78432879Sdonn src = p->in.left;
78532879Sdonn dst = resc;
78632873Sdonn dstlen = tlen(p);
78732873Sdonn dsttype = p->in.type;
78832879Sdonn } else /* if (p->in.op == OPLEAF) */ {
78932879Sdonn src = p;
79032879Sdonn dst = resc;
79132879Sdonn dstlen = SZINT/SZCHAR;
79232879Sdonn dsttype = ISUNSIGNED(src->in.type) ? UNSIGNED : INT;
79332873Sdonn }
79432873Sdonn
79532875Sdonn if (src->in.op == REG) {
79632875Sdonn srclen = SZINT/SZCHAR;
79732875Sdonn srctype = ISUNSIGNED(src->in.type) ? UNSIGNED : INT;
79832875Sdonn } else {
79932875Sdonn srclen = tlen(src);
80032875Sdonn srctype = src->in.type;
80132875Sdonn }
80232873Sdonn
80332882Sdonn if (src->in.op == ICON && src->tn.name[0] == '\0') {
80432875Sdonn if (src->tn.lval == 0) {
80532875Sdonn putstr("clr");
80632875Sdonn prtype(dst);
80732875Sdonn putchar('\t');
80832875Sdonn adrput(dst);
80932875Sdonn return;
81032875Sdonn }
81132875Sdonn if (dstlen < srclen) {
81232875Sdonn switch (dsttype) {
81332875Sdonn case CHAR:
81432875Sdonn src->tn.lval = (char) src->tn.lval;
81532875Sdonn break;
81632875Sdonn case UCHAR:
81732875Sdonn src->tn.lval = (unsigned char) src->tn.lval;
81832875Sdonn break;
81932875Sdonn case SHORT:
82032875Sdonn src->tn.lval = (short) src->tn.lval;
82132875Sdonn break;
82232875Sdonn case USHORT:
82332875Sdonn src->tn.lval = (unsigned short) src->tn.lval;
82432875Sdonn break;
82532875Sdonn }
82632875Sdonn }
82732875Sdonn if (dst->in.op == REG) {
82832875Sdonn dsttype = INT;
82932875Sdonn dstlen = SZINT/SZCHAR;
83032875Sdonn }
83132875Sdonn srctype = dsttype;
83232875Sdonn srclen = dstlen;
83332887Sdonn val = -src->tn.lval & ((1 << dstlen * SZCHAR) - 1);
83432887Sdonn if ((unsigned) val < 64) {
83532887Sdonn src->tn.lval = val;
83632882Sdonn ++neg; /* MNEGx may be shorter */
83732882Sdonn }
83832875Sdonn }
83932875Sdonn
84032873Sdonn if (srclen < dstlen) {
84132873Sdonn if (srctype == CHAR && dsttype == USHORT && dst->in.op == REG) {
84232873Sdonn /* (unsigned short) c; => sign extend to 16 bits */
84332874Sdonn putstr("cvtbl\t");
84432873Sdonn adrput(src);
84532873Sdonn putstr(",-(sp)\n\tmovzwl\t2(sp),");
84632873Sdonn adrput(dst);
84732873Sdonn putstr("\n\tmovab\t4(sp),sp");
84832873Sdonn if (forcc) {
849*33622Sdonn putstr("\n\ttstl\t");
85032873Sdonn adrput(dst);
85132873Sdonn }
85232873Sdonn return;
85332873Sdonn }
85432873Sdonn genconv(ISUNSIGNED(srctype),
85532873Sdonn srclen, dst->in.op == REG ? SZINT/SZCHAR : dstlen,
85633351Sdonn src, dst, forcc);
85732873Sdonn return;
85832873Sdonn }
85932873Sdonn
86032873Sdonn if (srclen > dstlen && dst->in.op == REG) {
86132875Sdonn /* if dst is a register, the result must look like an int */
86232873Sdonn if (src->in.op == REG) {
86332873Sdonn if (ISUNSIGNED(dsttype)) {
86432873Sdonn val = (1 << dstlen * SZCHAR) - 1;
86532873Sdonn if (src->tn.rval == dst->tn.rval)
86632873Sdonn /* conversion in place */
86732887Sdonn printf("andl2\t$%ld,", val);
86832873Sdonn else {
86932887Sdonn printf("andl3\t$%ld,", val);
87032873Sdonn adrput(src);
87132873Sdonn putchar(',');
87232873Sdonn }
87332873Sdonn adrput(dst);
87432873Sdonn return;
87532873Sdonn }
87632875Sdonn /*
87732875Sdonn * Sign extension in register can also be
87832875Sdonn * accomplished by shifts, but unfortunately
87932875Sdonn * shifts are extremely slow, due to the lack
88032875Sdonn * of a barrel shifter.
88132875Sdonn */
88232875Sdonn putstr("pushl\t");
88332873Sdonn adrput(src);
88432875Sdonn putstr("\n\tcvt");
88532875Sdonn prlen(dstlen);
88632875Sdonn printf("l\t%d(sp),", SZINT/SZCHAR - dstlen);
88732873Sdonn adrput(dst);
88832875Sdonn putstr("\n\tmovab\t4(sp),sp");
88932875Sdonn if (forcc) {
890*33622Sdonn putstr("\n\ttstl\t");
89132875Sdonn adrput(dst);
89232875Sdonn }
89332873Sdonn return;
89432873Sdonn }
89532873Sdonn tmp = talloc();
89632887Sdonn if ((src->in.op == NAME) ||
89732887Sdonn (src->in.op == UNARY MUL && src->in.left->in.op == ICON) ||
89832873Sdonn (src->in.op == OREG && !R2TEST(src->tn.rval))) {
89932873Sdonn /* we can increment src's address & pun it */
90032873Sdonn *tmp = *src;
90132873Sdonn tmp->tn.lval += srclen - dstlen;
90232873Sdonn } else {
90332873Sdonn /* we must store src's address */
90432873Sdonn *tmp = *dst;
90532875Sdonn putstr("mova");
90632875Sdonn prlen(srclen);
90732875Sdonn putchar('\t');
90832873Sdonn adrput(src);
90932873Sdonn putchar(',');
91032873Sdonn adrput(tmp);
91132874Sdonn putstr("\n\t");
91232873Sdonn tmp->tn.op = OREG;
91332873Sdonn tmp->tn.lval = srclen - dstlen;
91432873Sdonn }
91533351Sdonn genconv(ISUNSIGNED(dsttype), dstlen, SZINT/SZCHAR, tmp, dst, forcc);
91632873Sdonn tmp->in.op = FREE;
91732873Sdonn return;
91832873Sdonn }
91932873Sdonn
92032882Sdonn genconv(neg ? -1 : ISUNSIGNED(dsttype),
92132873Sdonn srclen, dst->in.op == REG ? SZINT/SZCHAR : dstlen,
92233351Sdonn src, dst, forcc);
92332873Sdonn }
92432873Sdonn
genconv(srcflag,srclen,dstlen,src,dst,forcc)92533351Sdonn genconv(srcflag, srclen, dstlen, src, dst, forcc)
92632882Sdonn int srcflag;
92732875Sdonn register int srclen, dstlen;
92832873Sdonn NODE *src, *dst;
92933351Sdonn int forcc;
93032873Sdonn {
93132873Sdonn if (srclen != dstlen) {
93232882Sdonn if (srcflag > 0 && srclen < dstlen)
93332874Sdonn putstr("movz");
93432873Sdonn else
93532874Sdonn putstr("cvt");
93632875Sdonn prlen(srclen);
93732882Sdonn } else if (srcflag < 0)
93832882Sdonn putstr("mneg");
93932882Sdonn else
94032874Sdonn putstr("mov");
94132875Sdonn prlen(dstlen);
94232873Sdonn putchar('\t');
94332873Sdonn adrput(src);
94432873Sdonn putchar(',');
94532873Sdonn adrput(dst);
94633351Sdonn
94733351Sdonn /*
94833351Sdonn * This hack is made necessary by architecture problems
94933351Sdonn * described above
95033351Sdonn */
95133351Sdonn if (forcc && src->in.op == REG && srclen > dstlen) {
95233351Sdonn putstr("\n\ttst");
95333351Sdonn prlen(dstlen);
95433351Sdonn putchar('\t');
95533351Sdonn adrput(dst);
95633351Sdonn }
95732873Sdonn }
95832873Sdonn
rmove(rt,rs,t)95932886Sdonn rmove( rt, rs, t ) TWORD t; {
96025828Ssam printf( " movl %s,%s\n", rname(rs), rname(rt) );
96125828Ssam if(t==DOUBLE)
96225828Ssam printf( " movl %s,%s\n", rname(rs+1), rname(rt+1) );
96325828Ssam }
96425828Ssam
96525828Ssam struct respref
96625828Ssam respref[] = {
96725828Ssam INTAREG|INTBREG, INTAREG|INTBREG,
96825828Ssam INAREG|INBREG, INAREG|INBREG|SOREG|STARREG|STARNM|SNAME|SCON,
96925828Ssam INTEMP, INTEMP,
97025828Ssam FORARG, FORARG,
97125828Ssam INTEMP, INTAREG|INAREG|INTBREG|INBREG|SOREG|STARREG|STARNM,
97225828Ssam 0, 0 };
97325828Ssam
setregs()97425828Ssam setregs(){ /* set up temporary registers */
97525828Ssam fregs = 6; /* tbl- 6 free regs on Tahoe (0-5) */
97625828Ssam }
97725828Ssam
97826076Ssam #ifndef szty
szty(t)97925828Ssam szty(t) TWORD t;{ /* size, in registers, needed to hold thing of type t */
98025828Ssam return(t==DOUBLE ? 2 : 1 );
98125828Ssam }
98226076Ssam #endif
98325828Ssam
98432886Sdonn /*ARGSUSED*/
rewfld(p)98525828Ssam rewfld( p ) NODE *p; {
98625828Ssam return(1);
98725828Ssam }
98825828Ssam
98932886Sdonn /*ARGSUSED*/
callreg(p)99025828Ssam callreg(p) NODE *p; {
99125828Ssam return( R0 );
99225828Ssam }
99325828Ssam
base(p)99425828Ssam base( p ) register NODE *p; {
99525828Ssam register int o = p->in.op;
99625828Ssam
99732887Sdonn if( o==ICON && p->in.name[0] != '\0' ) return( 100 ); /* ie no base reg */
99825828Ssam if( o==REG ) return( p->tn.rval );
99925828Ssam if( (o==PLUS || o==MINUS) && p->in.left->in.op == REG && p->in.right->in.op==ICON)
100025828Ssam return( p->in.left->tn.rval );
100125828Ssam if( o==OREG && !R2TEST(p->tn.rval) && (p->in.type==INT || p->in.type==UNSIGNED || ISPTR(p->in.type)) )
100225828Ssam return( p->tn.rval + 0200*1 );
100332887Sdonn if( o==NAME ) return( 100 + 0200*1 );
100425828Ssam return( -1 );
100525828Ssam }
100625828Ssam
offset(p,tyl)100725828Ssam offset( p, tyl ) register NODE *p; int tyl; {
100825828Ssam
100932886Sdonn if( tyl==1 &&
101032886Sdonn p->in.op==REG &&
101132886Sdonn (p->in.type==INT || p->in.type==UNSIGNED) )
101232886Sdonn return( p->tn.rval );
101332886Sdonn if( p->in.op==LS &&
101432886Sdonn p->in.left->in.op==REG &&
101532886Sdonn (p->in.left->in.type==INT || p->in.left->in.type==UNSIGNED) &&
101632886Sdonn p->in.right->in.op==ICON &&
101732886Sdonn p->in.right->in.name[0]=='\0' &&
101832886Sdonn (1<<p->in.right->tn.lval)==tyl)
101925828Ssam return( p->in.left->tn.rval );
102032886Sdonn if( tyl==2 &&
102132886Sdonn p->in.op==PLUS &&
102232886Sdonn (p->in.left->in.type==INT || p->in.left->in.type==UNSIGNED) &&
102332886Sdonn p->in.left->in.op==REG &&
102432886Sdonn p->in.right->in.op==REG &&
102532886Sdonn p->in.left->tn.rval==p->in.right->tn.rval )
102632886Sdonn return( p->in.left->tn.rval );
102725828Ssam return( -1 );
102825828Ssam }
102925828Ssam
makeor2(p,q,b,o)103025828Ssam makeor2( p, q, b, o) register NODE *p, *q; register int b, o; {
103125828Ssam register NODE *t;
103225828Ssam NODE *f;
103325828Ssam
103425828Ssam p->in.op = OREG;
103525828Ssam f = p->in.left; /* have to free this subtree later */
103625828Ssam
103725828Ssam /* init base */
103825828Ssam switch (q->in.op) {
103925828Ssam case ICON:
104025828Ssam case REG:
104125828Ssam case OREG:
104232887Sdonn case NAME:
104325828Ssam t = q;
104425828Ssam break;
104525828Ssam
104625828Ssam case MINUS:
104725828Ssam q->in.right->tn.lval = -q->in.right->tn.lval;
104825828Ssam case PLUS:
104925828Ssam t = q->in.right;
105025828Ssam break;
105125828Ssam
105225828Ssam case UNARY MUL:
105325828Ssam t = q->in.left->in.left;
105425828Ssam break;
105525828Ssam
105625828Ssam default:
105725828Ssam cerror("illegal makeor2");
105825828Ssam }
105925828Ssam
106025828Ssam p->tn.lval = t->tn.lval;
106125828Ssam #ifndef FLEXNAMES
106232886Sdonn {
106332886Sdonn register int i;
106432886Sdonn for(i=0; i<NCHNAM; ++i)
106532886Sdonn p->in.name[i] = t->in.name[i];
106632886Sdonn }
106725828Ssam #else
106825828Ssam p->in.name = t->in.name;
106925828Ssam #endif
107025828Ssam
107125828Ssam /* init offset */
107225828Ssam p->tn.rval = R2PACK( (b & 0177), o, (b>>7) );
107325828Ssam
107425828Ssam tfree(f);
107525828Ssam return;
107625828Ssam }
107725828Ssam
canaddr(p)107825828Ssam canaddr( p ) NODE *p; {
107925828Ssam register int o = p->in.op;
108025828Ssam
108125828Ssam if( o==NAME || o==REG || o==ICON || o==OREG || (o==UNARY MUL && shumul(p->in.left)) ) return(1);
108225828Ssam return(0);
108325828Ssam }
108425828Ssam
108526076Ssam #ifndef shltype
shltype(o,p)108625828Ssam shltype( o, p ) register NODE *p; {
108725828Ssam return( o== REG || o == NAME || o == ICON || o == OREG || ( o==UNARY MUL && shumul(p->in.left)) );
108825828Ssam }
108926076Ssam #endif
109025828Ssam
flshape(p)109125828Ssam flshape( p ) NODE *p; {
109225828Ssam register int o = p->in.op;
109325828Ssam
109425828Ssam if( o==NAME || o==REG || o==ICON || o==OREG || (o==UNARY MUL && shumul(p->in.left)) ) return(1);
109525828Ssam return(0);
109625828Ssam }
109725828Ssam
109832886Sdonn /* INTEMP shapes must not contain any temporary registers */
shtemp(p)109925828Ssam shtemp( p ) register NODE *p; {
110032886Sdonn int r;
110132886Sdonn
110225828Ssam if( p->in.op == STARG ) p = p->in.left;
110332886Sdonn
110432886Sdonn switch (p->in.op) {
110532886Sdonn case REG:
110632886Sdonn return( !istreg(p->tn.rval) );
110732886Sdonn case OREG:
110832886Sdonn r = p->tn.rval;
110932886Sdonn if( R2TEST(r) ) {
111032886Sdonn if( istreg(R2UPK1(r)) )
111132886Sdonn return(0);
111232886Sdonn r = R2UPK2(r);
111332886Sdonn }
111432886Sdonn return( !istreg(r) );
111532886Sdonn case UNARY MUL:
111632886Sdonn p = p->in.left;
111732886Sdonn return( p->in.op != UNARY MUL && shtemp(p) );
111832886Sdonn }
111932886Sdonn
112032886Sdonn if( optype( p->in.op ) != LTYPE ) return(0);
112132886Sdonn return(1);
112225828Ssam }
112325828Ssam
shumul(p)112425828Ssam shumul( p ) register NODE *p; {
112525828Ssam register int o;
112625828Ssam extern int xdebug;
112725828Ssam
112825828Ssam if (xdebug) {
112925828Ssam printf("\nshumul:op=%d,lop=%d,rop=%d", p->in.op, p->in.left->in.op, p->in.right->in.op);
113025828Ssam printf(" prname=%s,plty=%d, prlval=%D\n", p->in.right->in.name, p->in.left->in.type, p->in.right->tn.lval);
113125828Ssam }
113225828Ssam
113325828Ssam o = p->in.op;
113425828Ssam if(( o == NAME || (o == OREG && !R2TEST(p->tn.rval)) || o == ICON )
113525828Ssam && p->in.type != PTR+DOUBLE)
113625828Ssam return( STARNM );
113725828Ssam
113825828Ssam return( 0 );
113925828Ssam }
114025828Ssam
special(p,shape)114132887Sdonn special( p, shape ) register NODE *p; {
114232887Sdonn if( shape==SIREG && p->in.op == OREG && R2TEST(p->tn.rval) ) return(1);
114332887Sdonn else return(0);
114432887Sdonn }
114532887Sdonn
adrcon(val)114625828Ssam adrcon( val ) CONSZ val; {
114725947Ssam printf(ACONFMT, val);
114825828Ssam }
114925828Ssam
conput(p)115025828Ssam conput( p ) register NODE *p; {
115125828Ssam switch( p->in.op ){
115225828Ssam
115325828Ssam case ICON:
115425828Ssam acon( p );
115525828Ssam return;
115625828Ssam
115725828Ssam case REG:
115826162Ssam putstr(rname(p->tn.rval));
115925828Ssam return;
116025828Ssam
116125828Ssam default:
116225828Ssam cerror( "illegal conput" );
116325828Ssam }
116425828Ssam }
116525828Ssam
116632886Sdonn /*ARGSUSED*/
insput(p)116725828Ssam insput( p ) NODE *p; {
116825828Ssam cerror( "insput" );
116925828Ssam }
117025828Ssam
117132886Sdonn /*
117232886Sdonn * Output the address of the second item in the
117332886Sdonn * pair pointed to by p.
117432886Sdonn */
upput(p,size)117532886Sdonn upput(p, size)
117632886Sdonn register NODE *p;
117732886Sdonn {
117832886Sdonn CONSZ save;
117932886Sdonn
118032886Sdonn if (p->in.op == FLD)
118132886Sdonn p = p->in.left;
118232886Sdonn switch (p->in.op) {
118332886Sdonn
118432886Sdonn case NAME:
118532886Sdonn case OREG:
118632886Sdonn save = p->tn.lval;
118732886Sdonn p->tn.lval += size/SZCHAR;
118832886Sdonn adrput(p);
118932886Sdonn p->tn.lval = save;
119032886Sdonn break;
119132886Sdonn
119232886Sdonn case REG:
119332886Sdonn if (size == SZLONG) {
119432886Sdonn putstr(rname(p->tn.rval+1));
119532886Sdonn break;
119632886Sdonn }
119732886Sdonn /* fall thru... */
119832886Sdonn
119932886Sdonn default:
120032886Sdonn cerror("illegal upper address op %s size %d",
120132886Sdonn opst[p->tn.op], size);
120232886Sdonn /*NOTREACHED*/
120332886Sdonn }
120432886Sdonn }
120532886Sdonn
adrput(p)120625828Ssam adrput( p ) register NODE *p; {
120725828Ssam register int r;
120825828Ssam /* output an address, with offsets, from p */
120925828Ssam
121025828Ssam if( p->in.op == FLD ){
121125828Ssam p = p->in.left;
121225828Ssam }
121325828Ssam switch( p->in.op ){
121425828Ssam
121525828Ssam case NAME:
121625828Ssam acon( p );
121725828Ssam return;
121825828Ssam
121925828Ssam case ICON:
122025828Ssam /* addressable value of the constant */
122126162Ssam putchar('$');
122225828Ssam acon( p );
122325828Ssam return;
122425828Ssam
122525828Ssam case REG:
122626162Ssam putstr(rname(p->tn.rval));
122725828Ssam if(p->in.type == DOUBLE) /* for entry mask */
122825828Ssam (void) rname(p->tn.rval+1);
122925828Ssam return;
123025828Ssam
123125828Ssam case OREG:
123225828Ssam r = p->tn.rval;
123325828Ssam if( R2TEST(r) ){ /* double indexing */
123425828Ssam register int flags;
123525828Ssam
123625828Ssam flags = R2UPK3(r);
123726162Ssam if( flags & 1 ) putchar('*');
123825828Ssam if( p->tn.lval != 0 || p->in.name[0] != '\0' ) acon(p);
123925828Ssam if( R2UPK1(r) != 100) printf( "(%s)", rname(R2UPK1(r)) );
124025828Ssam printf( "[%s]", rname(R2UPK2(r)) );
124125828Ssam return;
124225828Ssam }
124325828Ssam if( r == FP && p->tn.lval > 0 ){ /* in the argument region */
124425828Ssam if( p->in.name[0] != '\0' ) werror( "bad arg temp" );
124525828Ssam printf( CONFMT, p->tn.lval );
124626162Ssam putstr( "(fp)" );
124725828Ssam return;
124825828Ssam }
124925828Ssam if( p->tn.lval != 0 || p->in.name[0] != '\0') acon( p );
125025828Ssam printf( "(%s)", rname(p->tn.rval) );
125125828Ssam return;
125225828Ssam
125325828Ssam case UNARY MUL:
125425828Ssam /* STARNM or STARREG found */
125525828Ssam if( tshape(p, STARNM) ) {
125626162Ssam putchar( '*' );
125725828Ssam adrput( p->in.left);
125825828Ssam }
125925828Ssam return;
126025828Ssam
126125828Ssam default:
126225828Ssam cerror( "illegal address" );
126325828Ssam return;
126425828Ssam
126525828Ssam }
126625828Ssam
126725828Ssam }
126825828Ssam
acon(p)126925828Ssam acon( p ) register NODE *p; { /* print out a constant */
127025828Ssam
127132886Sdonn if( p->in.name[0] == '\0' )
127225828Ssam printf( CONFMT, p->tn.lval);
127332886Sdonn else {
127425828Ssam #ifndef FLEXNAMES
127525828Ssam printf( "%.8s", p->in.name );
127625828Ssam #else
127732886Sdonn putstr( p->in.name );
127825828Ssam #endif
127932886Sdonn if( p->tn.lval != 0 ) {
128032886Sdonn putchar( '+' );
128132886Sdonn printf( CONFMT, p->tn.lval );
128232886Sdonn }
128325828Ssam }
128425828Ssam }
128525828Ssam
genscall(p,cookie)128625828Ssam genscall( p, cookie ) register NODE *p; {
128725828Ssam /* structure valued call */
128825828Ssam return( gencall( p, cookie ) );
128925828Ssam }
129025828Ssam
genfcall(p,cookie)129125828Ssam genfcall( p, cookie ) register NODE *p; {
129225828Ssam register NODE *p1;
129325828Ssam register int m;
129425828Ssam static char *funcops[6] = {
129525828Ssam "sin", "cos", "sqrt", "exp", "log", "atan"
129625828Ssam };
129725828Ssam
129825828Ssam /* generate function opcodes */
129925828Ssam if(p->in.op==UNARY FORTCALL && p->in.type==FLOAT &&
130025828Ssam (p1 = p->in.left)->in.op==ICON &&
130125828Ssam p1->tn.lval==0 && p1->in.type==INCREF(FTN|FLOAT)) {
130225828Ssam #ifdef FLEXNAMES
130325828Ssam p1->in.name++;
130425828Ssam #else
130525828Ssam strcpy(p1->in.name, p1->in.name[1]);
130625828Ssam #endif
130725828Ssam for(m=0; m<6; m++)
130825828Ssam if(!strcmp(p1->in.name, funcops[m]))
130925828Ssam break;
131025828Ssam if(m >= 6)
131125828Ssam uerror("no opcode for fortarn function %s", p1->in.name);
131225828Ssam } else
131325828Ssam uerror("illegal type of fortarn function");
131425828Ssam p1 = p->in.right;
131525828Ssam p->in.op = FORTCALL;
131625828Ssam if(!canaddr(p1))
131725828Ssam order( p1, INAREG|INBREG|SOREG|STARREG|STARNM );
131825828Ssam m = match( p, INTAREG|INTBREG );
131925828Ssam return(m != MDONE);
132025828Ssam }
132125828Ssam
132225828Ssam /* tbl */
132325828Ssam int gc_numbytes;
132425828Ssam /* tbl */
132525828Ssam
132632886Sdonn /*ARGSUSED*/
gencall(p,cookie)132725828Ssam gencall( p, cookie ) register NODE *p; {
132825828Ssam /* generate the call given by p */
132925828Ssam register NODE *p1, *ptemp;
133025828Ssam register int temp, temp1;
133125828Ssam register int m;
133225828Ssam
133325828Ssam if( p->in.right ) temp = argsize( p->in.right );
133425828Ssam else temp = 0;
133525828Ssam
133625828Ssam if( p->in.op == STCALL || p->in.op == UNARY STCALL ){
133725828Ssam /* set aside room for structure return */
133825828Ssam
133925828Ssam if( p->stn.stsize > temp ) temp1 = p->stn.stsize;
134025828Ssam else temp1 = temp;
134125828Ssam }
134225828Ssam
134325828Ssam if( temp > maxargs ) maxargs = temp;
134425828Ssam SETOFF(temp1,4);
134525828Ssam
134625828Ssam if( p->in.right ){ /* make temp node, put offset in, and generate args */
134725828Ssam ptemp = talloc();
134825828Ssam ptemp->in.op = OREG;
134925828Ssam ptemp->tn.lval = -1;
135025828Ssam ptemp->tn.rval = SP;
135125828Ssam #ifndef FLEXNAMES
135225828Ssam ptemp->in.name[0] = '\0';
135325828Ssam #else
135425828Ssam ptemp->in.name = "";
135525828Ssam #endif
135625828Ssam ptemp->in.rall = NOPREF;
135725828Ssam ptemp->in.su = 0;
135825828Ssam genargs( p->in.right, ptemp );
135925828Ssam ptemp->in.op = FREE;
136025828Ssam }
136125828Ssam
136225828Ssam p1 = p->in.left;
136325828Ssam if( p1->in.op != ICON ){
136425828Ssam if( p1->in.op != REG ){
136525828Ssam if( p1->in.op != OREG || R2TEST(p1->tn.rval) ){
136625828Ssam if( p1->in.op != NAME ){
136725828Ssam order( p1, INAREG );
136825828Ssam }
136925828Ssam }
137025828Ssam }
137125828Ssam }
137225828Ssam
137325828Ssam /* tbl
137425828Ssam setup gc_numbytes so reference to ZC works */
137525828Ssam
137625828Ssam gc_numbytes = temp&(0x3ff);
137725828Ssam
137825828Ssam p->in.op = UNARY CALL;
137925828Ssam m = match( p, INTAREG|INTBREG );
138025828Ssam
138125828Ssam return(m != MDONE);
138225828Ssam }
138325828Ssam
138425828Ssam /* tbl */
138525828Ssam char *
138625828Ssam ccbranches[] = {
138725828Ssam "eql",
138825828Ssam "neq",
138925828Ssam "leq",
139025828Ssam "lss",
139125828Ssam "geq",
139225828Ssam "gtr",
139325828Ssam "lequ",
139425828Ssam "lssu",
139525828Ssam "gequ",
139625828Ssam "gtru",
139725828Ssam };
139825828Ssam /* tbl */
139925828Ssam
140032886Sdonn /*ARGSUSED*/
cbgen(o,lab,mode)140125828Ssam cbgen( o, lab, mode ) { /* printf conditional and unconditional branches */
140225828Ssam
140332886Sdonn if( o != 0 && ( o < EQ || o > UGT ) )
140432886Sdonn cerror( "bad conditional branch: %s", opst[o] );
140532886Sdonn printf( " j%s L%d\n", o == 0 ? "br" : ccbranches[o-EQ], lab );
140625828Ssam }
140725828Ssam
nextcook(p,cookie)140825828Ssam nextcook( p, cookie ) NODE *p; {
140925828Ssam /* we have failed to match p with cookie; try another */
141025828Ssam if( cookie == FORREW ) return( 0 ); /* hopeless! */
141125828Ssam if( !(cookie&(INTAREG|INTBREG)) ) return( INTAREG|INTBREG );
141225828Ssam if( !(cookie&INTEMP) && asgop(p->in.op) ) return( INTEMP|INAREG|INTAREG|INTBREG|INBREG );
141325828Ssam return( FORREW );
141425828Ssam }
141525828Ssam
141632886Sdonn /*ARGSUSED*/
lastchance(p,cook)141725828Ssam lastchance( p, cook ) NODE *p; {
141825828Ssam /* forget it! */
141925828Ssam return(0);
142025828Ssam }
142125828Ssam
optim2(p)142225828Ssam optim2( p ) register NODE *p; {
142325828Ssam /* do local tree transformations and optimizations */
142432886Sdonn
142532886Sdonn int o;
142632886Sdonn int i, mask;
142730360Ssam register NODE *l, *r;
142825828Ssam
142932886Sdonn switch( o = p->in.op ) {
143030360Ssam
143132887Sdonn case ASG PLUS:
143232887Sdonn case ASG MINUS:
143332887Sdonn case ASG MUL:
143432887Sdonn case ASG OR:
143532887Sdonn /* simple ASG OPSIMP -- reduce range of constant rhs */
143632887Sdonn l = p->in.left;
143732887Sdonn r = p->in.right;
143832887Sdonn if( tlen(l) < SZINT/SZCHAR &&
143932887Sdonn r->in.op==ICON && r->in.name[0]==0 ){
144032887Sdonn mask = (1 << tlen(l) * SZCHAR) - 1;
144132887Sdonn if( r->tn.lval & (mask & ~(mask >> 1)) )
144232887Sdonn r->tn.lval |= ~mask;
144332887Sdonn else
144432887Sdonn r->tn.lval &= mask;
144532887Sdonn }
144632887Sdonn break;
144732887Sdonn
144832886Sdonn case AND:
144932886Sdonn case ASG AND:
145032886Sdonn r = p->in.right;
145132886Sdonn if( r->in.op==ICON && r->in.name[0]==0 ) {
145232886Sdonn /* check for degenerate operations */
145332886Sdonn l = p->in.left;
145432886Sdonn mask = (1 << tlen(l) * SZCHAR) - 1;
145532887Sdonn if( o == ASG AND || ISUNSIGNED(r->in.type) ) {
145632887Sdonn i = r->tn.lval & mask;
145732886Sdonn if( i == mask ) {
145832887Sdonn /* redundant mask */
145932886Sdonn r->in.op = FREE;
146032886Sdonn ncopy(p, l);
146132886Sdonn l->in.op = FREE;
146232886Sdonn break;
146332886Sdonn }
146432886Sdonn else if( i == 0 )
146532887Sdonn /* all bits masked off */
146632886Sdonn goto zero;
146732887Sdonn r->tn.lval = i;
146832887Sdonn if( tlen(l) < SZINT/SZCHAR ){
146932887Sdonn /* sign extend */
147032887Sdonn if( r->tn.lval & (mask & ~(mask >> 1)) )
147132887Sdonn r->tn.lval |= ~mask;
147232887Sdonn else
147332887Sdonn r->tn.lval &= mask;
147432887Sdonn }
147532886Sdonn }
147632886Sdonn else if( r->tn.lval == mask &&
147732886Sdonn tlen(l) < SZINT/SZCHAR ) {
147832887Sdonn /* use movz instead of and */
147932886Sdonn r->in.op = SCONV;
148032886Sdonn r->in.left = l;
148132886Sdonn r->in.right = 0;
148232886Sdonn r->in.type = ENUNSIGN(l->in.type);
148332886Sdonn r->in.su = l->in.su > 1 ? l->in.su : 1;
148432886Sdonn ncopy(p, r);
148532886Sdonn p->in.left = r;
148632886Sdonn p->in.type = INT;
148732886Sdonn }
148830360Ssam }
148932886Sdonn break;
149030360Ssam
149130360Ssam case SCONV:
149230360Ssam l = p->in.left;
149332886Sdonn if( p->in.type == FLOAT || p->in.type == DOUBLE ||
149432886Sdonn l->in.type == FLOAT || l->in.type == DOUBLE )
149532886Sdonn return;
149632887Sdonn if( l->in.op == PCONV )
149732886Sdonn return;
149832887Sdonn if( (l->in.op == CALL || l->in.op == UNARY CALL) &&
149932887Sdonn l->in.type != INT && l->in.type != UNSIGNED )
150032887Sdonn return;
150132879Sdonn
150232886Sdonn /* Only trust it to get it right if the size is the same */
150332886Sdonn if( tlen(p) != tlen(l) )
150432886Sdonn return;
150530360Ssam
150632886Sdonn /* clobber conversion */
150732886Sdonn if( l->in.op != FLD )
150832886Sdonn l->in.type = p->in.type;
150932886Sdonn ncopy( p, l );
151032886Sdonn l->in.op = FREE;
151132886Sdonn
151232886Sdonn break;
151332886Sdonn
151430360Ssam case ASSIGN:
151530360Ssam /*
151632886Sdonn * Conversions are equivalent to assignments;
151732886Sdonn * when the two operations are combined,
151832886Sdonn * we can sometimes zap the conversion.
151930360Ssam */
152030360Ssam r = p->in.right;
152132886Sdonn l = p->in.left;
152232886Sdonn if ( r->in.op == SCONV &&
152332886Sdonn !mixtypes(l, r) &&
152432886Sdonn l->in.op != FLD &&
152532886Sdonn tlen(l) == tlen(r) ) {
152630360Ssam p->in.right = r->in.left;
152730360Ssam r->in.op = FREE;
152830360Ssam }
152932886Sdonn break;
153032885Sdonn
153132885Sdonn case ULE:
153232885Sdonn case ULT:
153332885Sdonn case UGE:
153432885Sdonn case UGT:
153532886Sdonn p->in.op -= (UGE-GE);
153632886Sdonn if( degenerate(p) )
153732886Sdonn break;
153832886Sdonn p->in.op += (UGE-GE);
153932886Sdonn break;
154032886Sdonn
154132885Sdonn case EQ:
154232885Sdonn case NE:
154332885Sdonn case LE:
154432885Sdonn case LT:
154532885Sdonn case GE:
154632885Sdonn case GT:
154732887Sdonn if( p->in.left->in.op == SCONV &&
154832887Sdonn p->in.right->in.op == SCONV ) {
154932887Sdonn l = p->in.left;
155032887Sdonn r = p->in.right;
155132887Sdonn if( l->in.type == DOUBLE &&
155232887Sdonn l->in.left->in.type == FLOAT &&
155332887Sdonn r->in.left->in.type == FLOAT ) {
155432887Sdonn /* nuke the conversions */
155532887Sdonn p->in.left = l->in.left;
155632887Sdonn p->in.right = r->in.left;
155732887Sdonn l->in.op = FREE;
155832887Sdonn r->in.op = FREE;
155932887Sdonn }
156032887Sdonn /* more? */
156132887Sdonn }
156232886Sdonn (void) degenerate(p);
156332886Sdonn break;
156432886Sdonn
156532886Sdonn case DIV:
156632886Sdonn if( p->in.right->in.op == ICON &&
156732886Sdonn p->in.right->tn.name[0] == '\0' &&
156832886Sdonn ISUNSIGNED(p->in.right->in.type) &&
156932886Sdonn (unsigned) p->in.right->tn.lval >= 0x80000000 ) {
157032886Sdonn /* easy to do here, harder to do in zzzcode() */
157132886Sdonn p->in.op = UGE;
157232886Sdonn break;
157332886Sdonn }
157432886Sdonn case MOD:
157532886Sdonn case ASG DIV:
157632886Sdonn case ASG MOD:
157732885Sdonn /*
157832886Sdonn * optimize DIV and MOD
157932886Sdonn *
158032886Sdonn * basically we spot UCHAR and USHORT and try to do them
158132886Sdonn * as signed ints... this may need tuning for the tahoe.
158232885Sdonn */
158332886Sdonn if( degenerate(p) )
158432886Sdonn break;
158532886Sdonn l = p->in.left;
158632885Sdonn r = p->in.right;
158732886Sdonn if( !ISUNSIGNED(r->in.type) ||
158832886Sdonn tlen(l) >= SZINT/SZCHAR ||
158932886Sdonn !(tlen(r) < SZINT/SZCHAR ||
159032886Sdonn (r->in.op == ICON && r->tn.name[0] == '\0')) )
159132886Sdonn break;
159232886Sdonn if( r->in.op == ICON )
159332886Sdonn r->tn.type = INT;
159432886Sdonn else {
159532886Sdonn NODE *t = talloc();
159632886Sdonn t->in.left = r;
159732886Sdonn r = t;
159832886Sdonn r->in.op = SCONV;
159932886Sdonn r->in.type = INT;
160032886Sdonn r->in.right = 0;
160132886Sdonn p->in.right = r;
160232886Sdonn }
160332886Sdonn if( o == DIV || o == MOD ) {
160432886Sdonn NODE *t = talloc();
160532886Sdonn t->in.left = l;
160632886Sdonn l = t;
160732886Sdonn l->in.op = SCONV;
160832886Sdonn l->in.type = INT;
160932886Sdonn l->in.right = 0;
161032886Sdonn p->in.left = l;
161132886Sdonn }
161232886Sdonn /* handle asgops in table */
161332886Sdonn break;
161432886Sdonn
161532886Sdonn case RS:
161632886Sdonn case ASG RS:
161732886Sdonn case LS:
161832886Sdonn case ASG LS:
161932886Sdonn /* pick up degenerate shifts */
162032885Sdonn l = p->in.left;
162132886Sdonn r = p->in.right;
162232886Sdonn if( !(r->in.op == ICON && r->tn.name[0] == '\0') )
162332885Sdonn break;
162432885Sdonn i = r->tn.lval;
162532886Sdonn if( i < 0 )
162632886Sdonn /* front end 'fixes' this? */
162732886Sdonn if( o == LS || o == ASG LS )
162832886Sdonn o += (RS-LS);
162932886Sdonn else
163032886Sdonn o += (LS-RS);
163132886Sdonn if( (o == RS || o == ASG RS) &&
163232886Sdonn !ISUNSIGNED(l->in.type) )
163332886Sdonn /* can't optimize signed right shifts */
163432885Sdonn break;
163532886Sdonn if( o == LS ) {
163632886Sdonn if( i < SZINT )
163732886Sdonn break;
163832886Sdonn }
163932886Sdonn else {
164032886Sdonn if( i < tlen(l) * SZCHAR )
164132886Sdonn break;
164232886Sdonn }
164332886Sdonn zero:
164432886Sdonn if( !asgop( o ) )
164532886Sdonn if( tshape(l, SAREG|SNAME|SCON|SOREG|STARNM) ) {
164632886Sdonn /* no side effects */
164732886Sdonn tfree(l);
164832886Sdonn ncopy(p, r);
164932886Sdonn r->in.op = FREE;
165032886Sdonn p->tn.lval = 0;
165132886Sdonn }
165232886Sdonn else {
165332886Sdonn p->in.op = COMOP;
165432886Sdonn r->tn.lval = 0;
165532886Sdonn }
165632886Sdonn else {
165732886Sdonn p->in.op = ASSIGN;
165832886Sdonn r->tn.lval = 0;
165932886Sdonn }
166032886Sdonn break;
166132885Sdonn }
166232886Sdonn }
166332885Sdonn
degenerate(p)166432886Sdonn degenerate(p) register NODE *p; {
166532886Sdonn int o;
166632886Sdonn int result, i;
166732886Sdonn int lower, upper;
166832886Sdonn register NODE *l, *r;
166932886Sdonn
167032886Sdonn /*
167132886Sdonn * try to keep degenerate comparisons with constants
167232886Sdonn * out of the table.
167332886Sdonn */
167432886Sdonn r = p->in.right;
167532886Sdonn l = p->in.left;
167632886Sdonn if( r->in.op != ICON ||
167732886Sdonn r->tn.name[0] != '\0' ||
167832886Sdonn tlen(l) >= tlen(r) )
167932886Sdonn return (0);
168032886Sdonn switch( l->in.type ) {
168132886Sdonn case CHAR:
168232886Sdonn lower = -(1 << SZCHAR - 1);
168332886Sdonn upper = (1 << SZCHAR - 1) - 1;
168432886Sdonn break;
168532886Sdonn case UCHAR:
168632886Sdonn lower = 0;
168732886Sdonn upper = (1 << SZCHAR) - 1;
168832886Sdonn break;
168932886Sdonn case SHORT:
169032886Sdonn lower = -(1 << SZSHORT - 1);
169132886Sdonn upper = (1 << SZSHORT - 1) - 1;
169232886Sdonn break;
169332886Sdonn case USHORT:
169432886Sdonn lower = 0;
169532886Sdonn upper = (1 << SZSHORT) - 1;
169632886Sdonn break;
169732886Sdonn default:
169832886Sdonn cerror("unsupported type in degenerate()");
169932886Sdonn }
170032886Sdonn i = r->tn.lval;
170132886Sdonn switch( o = p->in.op ) {
170232886Sdonn case DIV:
170332886Sdonn case ASG DIV:
170432886Sdonn case MOD:
170532886Sdonn case ASG MOD:
170632886Sdonn /* DIV and MOD work like EQ */
170732886Sdonn case EQ:
170832886Sdonn case NE:
170932886Sdonn if( lower == 0 && (unsigned) i > upper )
171032886Sdonn result = o == NE;
171132886Sdonn else if( i < lower || i > upper )
171232886Sdonn result = o == NE;
171332886Sdonn else
171432886Sdonn return (0);
171532886Sdonn break;
171632886Sdonn case LT:
171732886Sdonn case GE:
171832886Sdonn if( lower == 0 && (unsigned) i > upper )
171932886Sdonn result = o == LT;
172032886Sdonn else if( i <= lower )
172132886Sdonn result = o != LT;
172232886Sdonn else if( i > upper )
172332886Sdonn result = o == LT;
172432886Sdonn else
172532886Sdonn return (0);
172632886Sdonn break;
172732886Sdonn case LE:
172832886Sdonn case GT:
172932886Sdonn if( lower == 0 && (unsigned) i >= upper )
173032886Sdonn result = o == LE;
173132886Sdonn else if( i < lower )
173232886Sdonn result = o != LE;
173332886Sdonn else if( i >= upper )
173432886Sdonn result = o == LE;
173532886Sdonn else
173632886Sdonn return (0);
173732886Sdonn break;
173832886Sdonn default:
173932886Sdonn cerror("unknown op in degenerate()");
174032886Sdonn }
174132886Sdonn
174232886Sdonn if( o == MOD || o == ASG MOD ) {
174332886Sdonn r->in.op = FREE;
174432886Sdonn ncopy(p, l);
174532886Sdonn l->in.op = FREE;
174632886Sdonn }
174732886Sdonn else if( o != ASG DIV && tshape(l, SAREG|SNAME|SCON|SOREG|STARNM) ) {
174832886Sdonn /* no side effects */
174932886Sdonn tfree(l);
175032886Sdonn ncopy(p, r);
175132886Sdonn r->in.op = FREE;
175232886Sdonn p->tn.lval = result;
175332886Sdonn }
175432886Sdonn else {
175532886Sdonn if( o == ASG DIV )
175632886Sdonn p->in.op = ASSIGN;
175732886Sdonn else {
175832885Sdonn p->in.op = COMOP;
175932885Sdonn r->tn.type = INT;
176032886Sdonn }
176132886Sdonn r->tn.lval = result;
176232885Sdonn }
176332886Sdonn if( logop(o) )
176432886Sdonn p->in.type = INT;
176532886Sdonn
176632886Sdonn return (1);
176725828Ssam }
176825828Ssam
176925828Ssam struct functbl {
177025828Ssam int fop;
177132877Sdonn TWORD ftype;
177225828Ssam char *func;
177332877Sdonn } opfunc[] = {
177432877Sdonn DIV, TANY, "udiv",
177532877Sdonn MOD, TANY, "urem",
177632877Sdonn ASG DIV, TANY, "audiv",
177732877Sdonn ASG MOD, TANY, "aurem",
177832877Sdonn 0, 0, 0 };
177925828Ssam
hardops(p)178025828Ssam hardops(p) register NODE *p; {
178125828Ssam /* change hard to do operators into function calls. */
178225828Ssam register NODE *q;
178325828Ssam register struct functbl *f;
178432877Sdonn register o;
178532877Sdonn NODE *old,*temp;
178625828Ssam
178725828Ssam o = p->in.op;
178832877Sdonn if( ! (optype(o)==BITYPE &&
178932877Sdonn (ISUNSIGNED(p->in.left->in.type) ||
179032877Sdonn ISUNSIGNED(p->in.right->in.type))) )
179132877Sdonn return;
179225828Ssam
179325828Ssam for( f=opfunc; f->fop; f++ ) {
179425828Ssam if( o==f->fop ) goto convert;
179532877Sdonn }
179625828Ssam return;
179725828Ssam
179825828Ssam convert:
179932886Sdonn if( p->in.right->in.op == ICON && p->in.right->tn.name[0] == '\0' )
180032886Sdonn /* 'J' in zzzcode() -- assumes DIV or MOD operations */
180132886Sdonn /* save a subroutine call -- use at most 5 instructions */
180232886Sdonn return;
180332886Sdonn if( tlen(p->in.left) < SZINT/SZCHAR && tlen(p->in.right) < SZINT/SZCHAR )
180432886Sdonn /* optim2() will modify the op into an ordinary int op */
180532886Sdonn return;
180625828Ssam if( asgop( o ) ) {
180732877Sdonn old = NIL;
180832877Sdonn switch( p->in.left->in.op ){
180932877Sdonn case FLD:
181032877Sdonn q = p->in.left->in.left;
181132877Sdonn /*
181232877Sdonn * rewrite (lval.fld /= rval); as
181332877Sdonn * ((*temp).fld = udiv((*(temp = &lval)).fld,rval));
181432877Sdonn * else the compiler will evaluate lval twice.
181532877Sdonn */
181632877Sdonn if( q->in.op == UNARY MUL ){
181732877Sdonn /* first allocate a temp storage */
181832877Sdonn temp = talloc();
181932877Sdonn temp->in.op = OREG;
182032877Sdonn temp->tn.rval = TMPREG;
182132877Sdonn temp->tn.lval = BITOOR(freetemp(1));
182232877Sdonn temp->in.type = INCREF(p->in.type);
182332877Sdonn #ifdef FLEXNAMES
182432877Sdonn temp->in.name = "";
182532877Sdonn #else
182632877Sdonn temp->in.name[0] = '\0';
182732877Sdonn #endif
182832877Sdonn old = q->in.left;
182932877Sdonn q->in.left = temp;
183032877Sdonn }
183132877Sdonn /* fall thru ... */
183225828Ssam
183332877Sdonn case REG:
183432877Sdonn case NAME:
183532877Sdonn case OREG:
183632877Sdonn /* change ASG OP to a simple OP */
183732877Sdonn q = talloc();
183832877Sdonn q->in.op = NOASG p->in.op;
183932877Sdonn q->in.rall = NOPREF;
184032877Sdonn q->in.type = p->in.type;
184132877Sdonn q->in.left = tcopy(p->in.left);
184232877Sdonn q->in.right = p->in.right;
184332877Sdonn p->in.op = ASSIGN;
184432877Sdonn p->in.right = q;
184532877Sdonn p = q;
184632877Sdonn f -= 2; /* Note: this depends on the table order */
184732877Sdonn /* on the right side only - replace *temp with
184832877Sdonn *(temp = &lval), build the assignment node */
184932877Sdonn if( old ){
185032877Sdonn temp = q->in.left->in.left; /* the "*" node */
185132877Sdonn q = talloc();
185232877Sdonn q->in.op = ASSIGN;
185332877Sdonn q->in.left = temp->in.left;
185432877Sdonn q->in.right = old;
185532877Sdonn q->in.type = old->in.type;
185632877Sdonn #ifdef FLEXNAMES
185732877Sdonn q->in.name = "";
185825828Ssam #else
185932877Sdonn q->in.name[0] = '\0';
186025828Ssam #endif
186132877Sdonn temp->in.left = q;
186232877Sdonn }
186332877Sdonn break;
186425828Ssam
186532877Sdonn case UNARY MUL:
186632877Sdonn /* avoid doing side effects twice */
186732877Sdonn q = p->in.left;
186832877Sdonn p->in.left = q->in.left;
186932877Sdonn q->in.op = FREE;
187032877Sdonn break;
187132877Sdonn
187232877Sdonn default:
187332877Sdonn cerror( "hardops: can't compute & LHS" );
187432877Sdonn }
187532877Sdonn }
187632877Sdonn
187725828Ssam /* build comma op for args to function */
187832877Sdonn q = talloc();
187932877Sdonn q->in.op = CM;
188032877Sdonn q->in.rall = NOPREF;
188132877Sdonn q->in.type = INT;
188232877Sdonn q->in.left = p->in.left;
188332877Sdonn q->in.right = p->in.right;
188425828Ssam p->in.op = CALL;
188525828Ssam p->in.right = q;
188625828Ssam
188725828Ssam /* put function name in left node of call */
188825828Ssam p->in.left = q = talloc();
188925828Ssam q->in.op = ICON;
189025828Ssam q->in.rall = NOPREF;
189125828Ssam q->in.type = INCREF( FTN + p->in.type );
189225828Ssam #ifndef FLEXNAMES
189332877Sdonn strcpy( q->in.name, f->func );
189425828Ssam #else
189532877Sdonn q->in.name = f->func;
189625828Ssam #endif
189725828Ssam q->tn.lval = 0;
189825828Ssam q->tn.rval = 0;
189925828Ssam
190025828Ssam }
190125828Ssam
zappost(p)190225828Ssam zappost(p) NODE *p; {
190325828Ssam /* look for ++ and -- operators and remove them */
190425828Ssam
190525828Ssam register int o, ty;
190625828Ssam register NODE *q;
190725828Ssam o = p->in.op;
190825828Ssam ty = optype( o );
190925828Ssam
191025828Ssam switch( o ){
191125828Ssam
191225828Ssam case INCR:
191325828Ssam case DECR:
191425828Ssam q = p->in.left;
191525828Ssam p->in.right->in.op = FREE; /* zap constant */
191625828Ssam ncopy( p, q );
191725828Ssam q->in.op = FREE;
191825828Ssam return;
191925828Ssam
192025828Ssam }
192125828Ssam
192225828Ssam if( ty == BITYPE ) zappost( p->in.right );
192325828Ssam if( ty != LTYPE ) zappost( p->in.left );
192425828Ssam }
192525828Ssam
fixpre(p)192625828Ssam fixpre(p) NODE *p; {
192725828Ssam
192825828Ssam register int o, ty;
192925828Ssam o = p->in.op;
193025828Ssam ty = optype( o );
193125828Ssam
193225828Ssam switch( o ){
193325828Ssam
193425828Ssam case ASG PLUS:
193525828Ssam p->in.op = PLUS;
193625828Ssam break;
193725828Ssam case ASG MINUS:
193825828Ssam p->in.op = MINUS;
193925828Ssam break;
194025828Ssam }
194125828Ssam
194225828Ssam if( ty == BITYPE ) fixpre( p->in.right );
194325828Ssam if( ty != LTYPE ) fixpre( p->in.left );
194425828Ssam }
194525828Ssam
194632886Sdonn /*ARGSUSED*/
addroreg(l)194725828Ssam NODE * addroreg(l) NODE *l;
194825828Ssam /* OREG was built in clocal()
194925828Ssam * for an auto or formal parameter
195025828Ssam * now its address is being taken
195125828Ssam * local code must unwind it
195225828Ssam * back to PLUS/MINUS REG ICON
195325828Ssam * according to local conventions
195425828Ssam */
195525828Ssam {
195625828Ssam cerror("address of OREG taken");
195732886Sdonn /*NOTREACHED*/
195825828Ssam }
195925828Ssam
196025828Ssam # ifndef ONEPASS
main(argc,argv)196125828Ssam main( argc, argv ) char *argv[]; {
196225828Ssam return( mainp2( argc, argv ) );
196325828Ssam }
196425828Ssam # endif
196525828Ssam
strip(p)196630360Ssam strip(p) register NODE *p; {
196730360Ssam NODE *q;
196830360Ssam
196930360Ssam /* strip nodes off the top when no side effects occur */
197030360Ssam for( ; ; ) {
197130360Ssam switch( p->in.op ) {
197230360Ssam case SCONV: /* remove lint tidbits */
197330360Ssam q = p->in.left;
197430360Ssam ncopy( p, q );
197530360Ssam q->in.op = FREE;
197630360Ssam break;
197730360Ssam /* could probably add a few more here */
197830360Ssam default:
197930360Ssam return;
198030360Ssam }
198130360Ssam }
198230360Ssam }
198330360Ssam
myreader(p)198425828Ssam myreader(p) register NODE *p; {
198530360Ssam strip( p ); /* strip off operations with no side effects */
198632886Sdonn canon( p ); /* expands r-vals for fields */
198725828Ssam walkf( p, hardops ); /* convert ops to function calls */
198825828Ssam walkf( p, optim2 );
198925828Ssam }
1990