|
|
1.1 root 1: #ifndef lint
2: static char sccsid[] = "@(#)local2.c 1.32 (Berkeley) 2/29/88";
3: #endif
4:
5: # include "pass2.h"
6: # include <ctype.h>
7:
8: # define putstr(s) fputs((s), stdout)
9: # define ISCHAR(p) (p->in.type == UCHAR || p->in.type == CHAR)
10:
11: # ifdef FORT
12: int ftlab1, ftlab2;
13: # endif
14: /* a lot of the machine dependent parts of the second pass */
15:
16: # define BITMASK(n) ((1L<<n)-1)
17:
18: # ifndef ONEPASS
19: /*ARGSUSED*/
20: where(c){
21: fprintf( stderr, "%s, line %d: ", filename, lineno );
22: }
23: # endif
24:
25: lineid( l, fn ) char *fn; {
26: /* identify line l and file fn */
27: printf( "# line %d, file %s\n", l, fn );
28: }
29:
30: int ent_mask;
31:
32: eobl2(){
33: register OFFSZ spoff; /* offset from stack pointer */
34: #ifndef FORT
35: extern int ftlab1, ftlab2;
36: #endif
37:
38: spoff = maxoff;
39: spoff /= SZCHAR;
40: SETOFF(spoff,4);
41: #ifdef FORT
42: #ifndef FLEXNAMES
43: printf( " .set .F%d,%ld\n", ftnno, spoff );
44: #else
45: /* SHOULD BE L%d ... ftnno but must change pc/f77 */
46: printf( " .set LF%d,%ld\n", ftnno, spoff );
47: #endif
48: printf( " .set LWM%d,0x%x\n", ftnno, ent_mask&0x1ffc|0x1000);
49: #else
50: printf( " .set L%d,0x%x\n", ftnno, ent_mask&0x1ffc);
51: printf( "L%d:\n", ftlab1);
52: if( maxoff > AUTOINIT )
53: printf( " subl3 $%ld,fp,sp\n", spoff);
54: printf( " jbr L%d\n", ftlab2);
55: #endif
56: ent_mask = 0;
57: maxargs = -1;
58: }
59:
60: struct hoptab { int opmask; char * opstring; } ioptab[] = {
61:
62: PLUS, "add",
63: MINUS, "sub",
64: MUL, "mul",
65: DIV, "div",
66: MOD, "div",
67: OR, "or",
68: ER, "xor",
69: AND, "and",
70: -1, "" };
71:
72: hopcode( f, o ){
73: /* output the appropriate string from the above table */
74:
75: register struct hoptab *q;
76:
77: if(asgop(o))
78: o = NOASG o;
79: for( q = ioptab; q->opmask>=0; ++q ){
80: if( q->opmask == o ){
81: if(f == 'E')
82: printf( "e%s", q->opstring);
83: else
84: printf( "%s%c", q->opstring, tolower(f));
85: return;
86: }
87: }
88: cerror( "no hoptab for %s", opst[o] );
89: }
90:
91: char *
92: rnames[] = { /* keyed to register number tokens */
93:
94: "r0", "r1",
95: "r2", "r3", "r4", "r5",
96: "r6", "r7", "r8", "r9", "r10", "r11",
97: "r12", "fp", "sp", "pc",
98: };
99:
100: /* output register name and update entry mask */
101: char *
102: rname(r)
103: register int r;
104: {
105:
106: if (!istreg(r))
107: ent_mask |= 1<<r;
108: return(rnames[r]);
109: }
110:
111: int rstatus[] = {
112: SAREG|STAREG, SAREG|STAREG,
113: SAREG|STAREG, SAREG|STAREG, SAREG|STAREG, SAREG|STAREG,
114: SAREG, SAREG, SAREG, SAREG, SAREG, SAREG,
115: SAREG, SAREG, SAREG, SAREG,
116: };
117:
118: tlen(p) NODE *p;
119: {
120: switch(p->in.type) {
121: case CHAR:
122: case UCHAR:
123: return(1);
124:
125: case SHORT:
126: case USHORT:
127: return(SZSHORT/SZCHAR);
128:
129: case DOUBLE:
130: return(SZDOUBLE/SZCHAR);
131:
132: default:
133: return(SZINT/SZCHAR);
134: }
135: }
136:
137: mixtypes(p, q) NODE *p, *q;
138: {
139: register TWORD tp, tq;
140:
141: tp = p->in.type;
142: tq = q->in.type;
143:
144: return( (tp==FLOAT || tp==DOUBLE) !=
145: (tq==FLOAT || tq==DOUBLE) );
146: }
147:
148: prtype(n) NODE *n;
149: {
150: switch (n->in.type)
151: {
152:
153: case DOUBLE:
154: putchar('d');
155: return;
156:
157: case FLOAT:
158: putchar('f');
159: return;
160:
161: case LONG:
162: case ULONG:
163: case INT:
164: case UNSIGNED:
165: putchar('l');
166: return;
167:
168: case SHORT:
169: case USHORT:
170: putchar('w');
171: return;
172:
173: case CHAR:
174: case UCHAR:
175: putchar('b');
176: return;
177:
178: default:
179: if ( !ISPTR( n->in.type ) ) cerror("zzzcode- bad type");
180: else {
181: putchar('l');
182: return;
183: }
184: }
185: }
186:
187: zzzcode( p, c ) register NODE *p; {
188: register int m;
189: int val;
190: switch( c ){
191:
192: case 'N': /* logical ops, turned into 0-1 */
193: /* use register given by register 1 */
194: cbgen( 0, m=getlab(), 'I' );
195: deflab( p->bn.label );
196: printf( " clrl %s\n", rname(getlr( p, '1' )->tn.rval) );
197: deflab( m );
198: return;
199:
200: case 'P':
201: cbgen( p->in.op, p->bn.label, c );
202: return;
203:
204: case 'G': /* i *= f; asgops with int lhs and float rhs */
205: {
206: register NODE *l, *r, *s;
207: int lt, rt;
208:
209: l = p->in.left;
210: r = p->in.right;
211: s = talloc();
212: rt = r->in.type;
213: lt = l->in.type;
214:
215: if (lt != INT && lt != UNSIGNED) {
216: s->in.op = SCONV;
217: s->in.left = l;
218: s->in.type = ISUNSIGNED(lt) ? UNSIGNED : INT;
219: zzzcode(s, 'U');
220: putstr("\n\t");
221: }
222:
223: if (ISUNSIGNED(lt)) {
224: s->in.op = SCONV;
225: s->in.left = lt == UNSIGNED ? l : resc;
226: s->in.type = rt;
227: unsigned_to_float(s);
228: } else {
229: putstr("cvl");
230: prtype(r);
231: putchar('\t');
232: adrput(lt == INT ? l : resc);
233: }
234: putstr("\n\t");
235:
236: hopcode(rt == FLOAT ? 'F' : 'D', p->in.op);
237: putchar('\t');
238: adrput(r);
239:
240: if (ISUNSIGNED(lt)) {
241: putstr("\n\t");
242: s->in.op = SCONV;
243: s->in.left = r; /* we need only the type */
244: s->in.type = UNSIGNED;
245: float_to_unsigned(s);
246: } else {
247: putstr("\n\tcv");
248: prtype(r);
249: putstr("l\t");
250: if (lt == INT)
251: adrput(l);
252: else
253: adrput(resc);
254: }
255: if (lt != INT) {
256: putstr("\n\t");
257: s->in.op = ASSIGN;
258: s->in.left = l;
259: s->in.right = resc;
260: s->in.type = lt;
261: zzzcode(s, 'U');
262: }
263:
264: s->in.op = FREE;
265: return;
266: }
267:
268: case 'J': /* unsigned DIV/MOD with constant divisors */
269: {
270: register int ck = INAREG;
271: int label1, label2;
272:
273: /* case constant <= 1 is handled by optim() in pass 1 */
274: /* case constant < 0x80000000 is handled in table */
275: switch( p->in.op ) {
276: /* case DIV: handled in optim2() */
277: case MOD:
278: if( p->in.left->in.op == REG &&
279: p->in.left->tn.rval == resc->tn.rval )
280: goto asgmod;
281: label1 = getlab();
282: expand(p, ck, "movl\tAL,A1\n\tcmpl\tA1,AR\n");
283: printf("\tjlssu\tL%d\n", label1);
284: expand(p, ck, "\tsubl2\tAR,A1\n");
285: printf("L%d:", label1);
286: break;
287: case ASG DIV:
288: label1 = getlab();
289: label2 = getlab();
290: expand(p, ck, "cmpl\tAL,AR\n");
291: printf("\tjgequ\tL%d\n", label1);
292: expand(p, ck, "\tmovl\t$1,AL\n");
293: printf("\tjbr\tL%d\nL%d:\n", label2, label1);
294: expand(p, ck, "\tclrl\tAL\n");
295: printf("L%d:", label2);
296: break;
297: case ASG MOD:
298: asgmod:
299: label1 = getlab();
300: expand(p, ck, "cmpl\tAL,AR\n");
301: printf("\tjlssu\tL%d\n", label1);
302: expand(p, ck, "\tsubl2\tAR,AL\n");
303: printf("L%d:", label1);
304: break;
305: }
306: return;
307: }
308:
309: case 'B': /* get oreg value in temp register for shift */
310: {
311: register NODE *r;
312: if (xdebug) eprint(p, 0, &val, &val);
313: r = p->in.right;
314: if( tlen(r) == SZINT/SZCHAR && r->in.type != FLOAT )
315: putstr("movl");
316: else {
317: putstr(ISUNSIGNED(r->in.type) ? "movz" : "cvt");
318: prtype(r);
319: putchar('l');
320: }
321: return;
322: }
323:
324: case 'C': /* generate 'call[fs] $bytes' */
325: {
326: extern int gc_numbytes;
327: extern int xdebug;
328:
329: if (xdebug) printf("->%d<-",gc_numbytes);
330:
331: printf("call%c $%d",
332: (p->in.left->in.op==ICON && gc_numbytes<60)?'f':'s',
333: gc_numbytes+4);
334: /* don't change to double (here's the only place to catch it) */
335: if(p->in.type == FLOAT)
336: rtyflg = 1;
337: return;
338: }
339:
340: case 'D': /* INCR and DECR */
341: if (p->in.left->in.type == FLOAT)
342: expand(p, INAREG, "movl\tAL,A1");
343: else if (p->in.left->in.type == DOUBLE)
344: expand(p, INAREG, "ldd\tAL\n\tstd\tA1");
345: else
346: zzzcode(p->in.left, 'U');
347: putstr("\n ");
348:
349: case 'E': /* INCR and DECR, FOREFF */
350: if (p->in.right->in.op == ICON && p->in.right->tn.lval == 1)
351: {
352: putstr(p->in.op == INCR ? "inc" : "dec");
353: prtype(p->in.left);
354: putchar('\t');
355: adrput(p->in.left);
356: return;
357: }
358: else if (p->in.left->in.type == FLOAT || p->in.left->in.type == DOUBLE) {
359: if (c == 'E' || p->in.left->in.type == FLOAT)
360: expand(p, INAREG, "ldZL\tAL\n\t");
361: if (p->in.op == INCR)
362: expand(p, INAREG, "addZL\tAR\n\tstZL\tAL");
363: else /* DECR */
364: expand(p, INAREG, "subZL\tAR\n\tstZL\tAL");
365: return;
366: }
367: putstr(p->in.op == INCR ? "add" : "sub");
368: prtype(p->in.left);
369: putstr("2 ");
370: adrput(p->in.right);
371: putchar(',');
372: adrput(p->in.left);
373: return;
374:
375: case 'F': /* masked constant for fields */
376: printf(ACONFMT, (p->in.right->tn.lval&((1<<fldsz)-1))<<fldshf);
377: return;
378:
379: case 'I': /* produce value of bitfield assignment */
380: /* avoid shifts -- shifts are SLOW on this machine */
381: /* XXX this wouldn't be necessary if we were smarter
382: and masked BEFORE shifting XXX */
383: {
384: register NODE *r = p->in.right;
385: if(r->in.op == ICON && r->tn.name[0] == '\0') {
386: putstr("movl\t");
387: printf(ACONFMT, r->tn.lval & ((1<<fldsz)-1));
388: }
389: else {
390: putstr("andl3\t");
391: printf(ACONFMT, (1 << fldsz) - 1);
392: putchar(',');
393: adrput(r);
394: }
395: putchar(',');
396: adrput(resc);
397: break;
398: }
399:
400: case 'H': /* opcode for shift */
401: if(p->in.op == LS || p->in.op == ASG LS)
402: putstr("shll");
403: else if(ISUNSIGNED(p->in.left->in.type))
404: putstr("shrl");
405: else
406: putstr("shar");
407: return;
408:
409: case 'L': /* type of left operand */
410: case 'R': /* type of right operand */
411: {
412: register NODE *n;
413: extern int xdebug;
414:
415: n = getlr ( p, c);
416: if (xdebug) printf("->%d<-", n->in.type);
417:
418: prtype(n);
419: return;
420: }
421:
422: case 'M': { /* initiate ediv for mod and unsigned div */
423: putstr("clrl\t");
424: adrput(resc);
425: putstr("\n\tmovl\t");
426: adrput(p->in.left);
427: putchar(',');
428: upput(resc, SZLONG);
429: printf("\n\tjgeq\tL%d\n\tmnegl\t$1,", m = getlab());
430: adrput(resc);
431: putchar('\n');
432: deflab(m);
433: return;
434: }
435:
436: case 'T': { /* rounded structure length for arguments */
437: int size = p->stn.stsize;
438: SETOFF( size, 4);
439: printf("movab -%d(sp),sp", size);
440: return;
441: }
442:
443: case 'S': /* structure assignment */
444: stasg(p);
445: break;
446:
447: #ifdef I_don_t_understand_this
448: case 'X': /* multiplication for short and char */
449: if (ISUNSIGNED(p->in.left->in.type))
450: printf("\tmovz");
451: else
452: printf("\tcvt");
453: zzzcode(p, 'L');
454: printf("l\t");
455: adrput(p->in.left);
456: printf(",");
457: adrput(&resc[0]);
458: printf("\n");
459: if (ISUNSIGNED(p->in.right->in.type))
460: printf("\tmovz");
461: else
462: printf("\tcvt");
463: zzzcode(p, 'R');
464: printf("l\t");
465: adrput(p->in.right);
466: printf(",");
467: adrput(&resc[1]);
468: printf("\n");
469: return;
470: #endif
471:
472: case 'U': /* SCONV */
473: case 'V': /* SCONV with FORCC */
474: sconv(p, c == 'V');
475: break;
476:
477: case 'W': { /* SCONV or ASSIGN float/double => unsigned */
478: NODE *src = p->in.op == SCONV ? p->in.left : p->in.right;
479:
480: putstr("ld");
481: prtype(src);
482: putchar('\t');
483: adrput(src);
484: putstr("\n\t");
485: float_to_unsigned(p);
486: break;
487: }
488:
489: case 'Y': /* SCONV or ASSIGN unsigned => float/double */
490: unsigned_to_float(p); /* stores into accumulator */
491: putstr("\n\tst");
492: prtype(p);
493: putchar('\t');
494: if (p->in.op == SCONV)
495: adrput(resc);
496: else
497: adrput(p->in.left);
498: rtyflg = 1;
499: break;
500:
501: #ifdef I_don_t_understand_this
502: case 'Z':
503: p = p->in.right;
504: switch (p->in.type) {
505: case SHORT: {
506: short w = p->tn.lval;
507: p->tn.lval = w;
508: break;
509: }
510: case CHAR: {
511: char c = p->tn.lval;
512: p->tn.lval = c;
513: break;
514: }
515: }
516: printf("$%d", p->tn.lval);
517: break;
518: #endif
519:
520: default:
521: cerror( "illegal zzzcode" );
522: }
523: }
524:
525: #define MOVB(dst, src, off) { \
526: putstr("\tmovb\t"); upput(src, off); putchar(','); \
527: upput(dst, off); putchar('\n'); \
528: }
529: #define MOVW(dst, src, off) { \
530: putstr("\tmovw\t"); upput(src, off); putchar(','); \
531: upput(dst, off); putchar('\n'); \
532: }
533: #define MOVL(dst, src, off) { \
534: putstr("\tmovl\t"); upput(src, off); putchar(','); \
535: upput(dst, off); putchar('\n'); \
536: }
537: /*
538: * Generate code for a structure assignment.
539: */
540: stasg(p)
541: register NODE *p;
542: {
543: register NODE *l, *r;
544: register int size;
545:
546: switch (p->in.op) {
547: case STASG: /* regular assignment */
548: l = p->in.left;
549: r = p->in.right;
550: break;
551: case STARG: /* place arg on the stack */
552: l = getlr(p, '3');
553: r = p->in.left;
554: break;
555: default:
556: cerror("STASG bad");
557: /*NOTREACHED*/
558: }
559: /*
560: * Pun source for use in code generation.
561: */
562: switch (r->in.op) {
563: case ICON:
564: r->in.op = NAME;
565: break;
566: case REG:
567: r->in.op = OREG;
568: break;
569: default:
570: cerror( "STASG-r" );
571: /*NOTREACHED*/
572: }
573: size = p->stn.stsize;
574: if (size <= 0 || size > 65535)
575: cerror("structure size out of range");
576: /*
577: * Generate optimized code based on structure size
578: * and alignment properties....
579: */
580: switch (size) {
581:
582: case 1:
583: putstr("\tmovb\t");
584: optimized:
585: adrput(r);
586: putchar(',');
587: adrput(l);
588: putchar('\n');
589: break;
590:
591: case 2:
592: if (p->stn.stalign != 2) {
593: MOVB(l, r, SZCHAR);
594: putstr("\tmovb\t");
595: } else
596: putstr("\tmovw\t");
597: goto optimized;
598:
599: case 4:
600: if (p->stn.stalign != 4) {
601: if (p->stn.stalign != 2) {
602: MOVB(l, r, 3*SZCHAR);
603: MOVB(l, r, 2*SZCHAR);
604: MOVB(l, r, 1*SZCHAR);
605: putstr("\tmovb\t");
606: } else {
607: MOVW(l, r, SZSHORT);
608: putstr("\tmovw\t");
609: }
610: } else
611: putstr("\tmovl\t");
612: goto optimized;
613:
614: case 6:
615: if (p->stn.stalign != 2)
616: goto movblk;
617: MOVW(l, r, 2*SZSHORT);
618: MOVW(l, r, 1*SZSHORT);
619: putstr("\tmovw\t");
620: goto optimized;
621:
622: case 8:
623: if (p->stn.stalign == 4) {
624: MOVL(l, r, SZLONG);
625: putstr("\tmovl\t");
626: goto optimized;
627: }
628: /* fall thru...*/
629:
630: default:
631: movblk:
632: /*
633: * Can we ever get a register conflict with R1 here?
634: */
635: putstr("\tmovab\t");
636: if(r->in.op == OREG && r->tn.rval == R1)
637: {
638: adrput(r);
639: printf(",r0\n\tmovab\t");
640: adrput(l);
641: putstr(",r1\n");
642: }
643: else
644: {
645: adrput(l);
646: putstr(",r1\n\tmovab\t");
647: adrput(r);
648: printf(",r0\n");
649: }
650: printf("\tmovl\t$%d,r2\n\tmovblk\n", size);
651: rname(R2);
652: break;
653: }
654: /*
655: * Reverse above pun for reclaim.
656: */
657: if (r->in.op == NAME)
658: r->in.op = ICON;
659: else if (r->in.op == OREG)
660: r->in.op = REG;
661: }
662:
663: /*
664: * Convert a float or double in the accumulator into an unsigned int.
665: * Unlike the vax, the tahoe stores 0 into the destination
666: * on a conversion of > 2 ** 31, so we compensate.
667: */
668: float_to_unsigned(p)
669: NODE *p;
670: {
671: register NODE *l = p->in.left;
672: int label1 = getlab();
673: int label2 = getlab();
674: int label3 = getlab();
675: NODE *src, *dst;
676:
677: if (p->in.op == SCONV) {
678: src = p->in.left;
679: dst = resc;
680: } else {
681: src = p->in.right;
682: dst = p->in.left;
683: }
684:
685: printf(".data\n\t.align\t2\nL%d:\n\t.long\t0x50000000", label1);
686: if (src->in.type == DOUBLE)
687: putstr(", 0x00000000 # .double");
688: else
689: putstr(" # .float");
690: putstr(" 2147483648\n\t.text\n\tcmp");
691: prtype(src);
692: printf("\tL%d\n\tjlss\tL%d\n\tsub", label1, label2);
693: prtype(src);
694: printf("\tL%d\n\tcv", label1);
695: prtype(src);
696: putstr("l\t");
697: adrput(dst);
698: putstr("\n\taddl2\t$-2147483648,");
699: adrput(dst);
700: printf("\n\tjbr\tL%d\nL%d:\n\tcv", label3, label2);
701: prtype(src);
702: putstr("l\t");
703: adrput(dst);
704: printf("\nL%d:", label3);
705: }
706:
707: /*
708: * Convert an unsigned int into a float or double, leaving the result
709: * in the accumulator.
710: */
711: unsigned_to_float(p)
712: register NODE *p;
713: {
714: int label1 = getlab();
715: int label2 = getlab();
716: NODE *src, *dst;
717:
718: if (p->in.op == SCONV) {
719: src = p->in.left;
720: dst = resc;
721: } else {
722: src = p->in.right;
723: dst = p->in.left;
724: }
725:
726: printf(".data\n\t.align\t2\nL%d:\n\t.long\t0x50800000", label2);
727: if (p->in.type == DOUBLE)
728: putstr(", 0x00000000 # .double");
729: else
730: putstr(" # .float");
731: putstr(" 4294967296\n\t.text\n\tmovl\t");
732: adrput(src);
733: putchar(',');
734: adrput(dst);
735: putstr("\n\tcvl");
736: prtype(p);
737: putchar('\t');
738: adrput(dst);
739: printf("\n\tjgeq\tL%d\n\tadd", label1);
740: prtype(p);
741: printf("\tL%d\nL%d:", label2, label1);
742: }
743:
744: /*
745: * Prlen() is a cheap prtype()...
746: */
747: static char convtab[SZINT/SZCHAR + 1] = {
748: '?', 'b', 'w', '?', 'l'
749: };
750: #define prlen(len) putchar(convtab[len])
751:
752:
753: /*
754: * Generate code for integral scalar conversions.
755: * Some of this code is designed to work around a tahoe misfeature
756: * that causes sign- and zero- extension to be defeated in
757: * certain circumstances.
758: * Basically if the source operand of a CVT or MOVZ instruction is
759: * shorter than the destination, and the source is a register
760: * or an immediate constant, sign- and zero- extension are
761: * ignored and the high bits of the source are copied. (Note
762: * that zero-extension is not a problem for immediate
763: * constants.)
764: * Another problem -- condition codes for a conversion with a
765: * register source reflect the source rather than the destination.
766: */
767: sconv(p, forcc)
768: NODE *p;
769: int forcc;
770: {
771: register NODE *src, *dst;
772: register NODE *tmp;
773: register int srclen, dstlen;
774: int srctype, dsttype;
775: int val;
776: int neg = 0;
777:
778: if (p->in.op == ASSIGN) {
779: src = p->in.right;
780: dst = p->in.left;
781: dstlen = tlen(dst);
782: dsttype = dst->in.type;
783: } else if (p->in.op == SCONV) {
784: src = p->in.left;
785: dst = resc;
786: dstlen = tlen(p);
787: dsttype = p->in.type;
788: } else /* if (p->in.op == OPLEAF) */ {
789: src = p;
790: dst = resc;
791: dstlen = SZINT/SZCHAR;
792: dsttype = ISUNSIGNED(src->in.type) ? UNSIGNED : INT;
793: }
794:
795: if (src->in.op == REG) {
796: srclen = SZINT/SZCHAR;
797: srctype = ISUNSIGNED(src->in.type) ? UNSIGNED : INT;
798: } else {
799: srclen = tlen(src);
800: srctype = src->in.type;
801: }
802:
803: if (src->in.op == ICON && src->tn.name[0] == '\0') {
804: if (src->tn.lval == 0) {
805: putstr("clr");
806: prtype(dst);
807: putchar('\t');
808: adrput(dst);
809: return;
810: }
811: if (dstlen < srclen) {
812: switch (dsttype) {
813: case CHAR:
814: src->tn.lval = (char) src->tn.lval;
815: break;
816: case UCHAR:
817: src->tn.lval = (unsigned char) src->tn.lval;
818: break;
819: case SHORT:
820: src->tn.lval = (short) src->tn.lval;
821: break;
822: case USHORT:
823: src->tn.lval = (unsigned short) src->tn.lval;
824: break;
825: }
826: }
827: if (dst->in.op == REG) {
828: dsttype = INT;
829: dstlen = SZINT/SZCHAR;
830: }
831: srctype = dsttype;
832: srclen = dstlen;
833: val = -src->tn.lval & ((1 << dstlen * SZCHAR) - 1);
834: if ((unsigned) val < 64) {
835: src->tn.lval = val;
836: ++neg; /* MNEGx may be shorter */
837: }
838: }
839:
840: if (srclen < dstlen) {
841: if (srctype == CHAR && dsttype == USHORT && dst->in.op == REG) {
842: /* (unsigned short) c; => sign extend to 16 bits */
843: putstr("cvtbl\t");
844: adrput(src);
845: putstr(",-(sp)\n\tmovzwl\t2(sp),");
846: adrput(dst);
847: putstr("\n\tmovab\t4(sp),sp");
848: if (forcc) {
849: putstr("\n\ttstl\t");
850: adrput(dst);
851: }
852: return;
853: }
854: genconv(ISUNSIGNED(srctype),
855: srclen, dst->in.op == REG ? SZINT/SZCHAR : dstlen,
856: src, dst, forcc);
857: return;
858: }
859:
860: if (srclen > dstlen && dst->in.op == REG) {
861: /* if dst is a register, the result must look like an int */
862: if (src->in.op == REG) {
863: if (ISUNSIGNED(dsttype)) {
864: val = (1 << dstlen * SZCHAR) - 1;
865: if (src->tn.rval == dst->tn.rval)
866: /* conversion in place */
867: printf("andl2\t$%ld,", val);
868: else {
869: printf("andl3\t$%ld,", val);
870: adrput(src);
871: putchar(',');
872: }
873: adrput(dst);
874: return;
875: }
876: /*
877: * Sign extension in register can also be
878: * accomplished by shifts, but unfortunately
879: * shifts are extremely slow, due to the lack
880: * of a barrel shifter.
881: */
882: putstr("pushl\t");
883: adrput(src);
884: putstr("\n\tcvt");
885: prlen(dstlen);
886: printf("l\t%d(sp),", SZINT/SZCHAR - dstlen);
887: adrput(dst);
888: putstr("\n\tmovab\t4(sp),sp");
889: if (forcc) {
890: putstr("\n\ttstl\t");
891: adrput(dst);
892: }
893: return;
894: }
895: tmp = talloc();
896: if ((src->in.op == NAME) ||
897: (src->in.op == UNARY MUL && src->in.left->in.op == ICON) ||
898: (src->in.op == OREG && !R2TEST(src->tn.rval))) {
899: /* we can increment src's address & pun it */
900: *tmp = *src;
901: tmp->tn.lval += srclen - dstlen;
902: } else {
903: /* we must store src's address */
904: *tmp = *dst;
905: putstr("mova");
906: prlen(srclen);
907: putchar('\t');
908: adrput(src);
909: putchar(',');
910: adrput(tmp);
911: putstr("\n\t");
912: tmp->tn.op = OREG;
913: tmp->tn.lval = srclen - dstlen;
914: }
915: genconv(ISUNSIGNED(dsttype), dstlen, SZINT/SZCHAR, tmp, dst, forcc);
916: tmp->in.op = FREE;
917: return;
918: }
919:
920: genconv(neg ? -1 : ISUNSIGNED(dsttype),
921: srclen, dst->in.op == REG ? SZINT/SZCHAR : dstlen,
922: src, dst, forcc);
923: }
924:
925: genconv(srcflag, srclen, dstlen, src, dst, forcc)
926: int srcflag;
927: register int srclen, dstlen;
928: NODE *src, *dst;
929: int forcc;
930: {
931: if (srclen != dstlen) {
932: if (srcflag > 0 && srclen < dstlen)
933: putstr("movz");
934: else
935: putstr("cvt");
936: prlen(srclen);
937: } else if (srcflag < 0)
938: putstr("mneg");
939: else
940: putstr("mov");
941: prlen(dstlen);
942: putchar('\t');
943: adrput(src);
944: putchar(',');
945: adrput(dst);
946:
947: /*
948: * This hack is made necessary by architecture problems
949: * described above
950: */
951: if (forcc && src->in.op == REG && srclen > dstlen) {
952: putstr("\n\ttst");
953: prlen(dstlen);
954: putchar('\t');
955: adrput(dst);
956: }
957: }
958:
959: rmove( rt, rs, t ) TWORD t; {
960: printf( " movl %s,%s\n", rname(rs), rname(rt) );
961: if(t==DOUBLE)
962: printf( " movl %s,%s\n", rname(rs+1), rname(rt+1) );
963: }
964:
965: struct respref
966: respref[] = {
967: INTAREG|INTBREG, INTAREG|INTBREG,
968: INAREG|INBREG, INAREG|INBREG|SOREG|STARREG|STARNM|SNAME|SCON,
969: INTEMP, INTEMP,
970: FORARG, FORARG,
971: INTEMP, INTAREG|INAREG|INTBREG|INBREG|SOREG|STARREG|STARNM,
972: 0, 0 };
973:
974: setregs(){ /* set up temporary registers */
975: fregs = 6; /* tbl- 6 free regs on Tahoe (0-5) */
976: }
977:
978: #ifndef szty
979: szty(t) TWORD t;{ /* size, in registers, needed to hold thing of type t */
980: return(t==DOUBLE ? 2 : 1 );
981: }
982: #endif
983:
984: /*ARGSUSED*/
985: rewfld( p ) NODE *p; {
986: return(1);
987: }
988:
989: /*ARGSUSED*/
990: callreg(p) NODE *p; {
991: return( R0 );
992: }
993:
994: base( p ) register NODE *p; {
995: register int o = p->in.op;
996:
997: if( o==ICON && p->in.name[0] != '\0' ) return( 100 ); /* ie no base reg */
998: if( o==REG ) return( p->tn.rval );
999: if( (o==PLUS || o==MINUS) && p->in.left->in.op == REG && p->in.right->in.op==ICON)
1000: return( p->in.left->tn.rval );
1001: if( o==OREG && !R2TEST(p->tn.rval) && (p->in.type==INT || p->in.type==UNSIGNED || ISPTR(p->in.type)) )
1002: return( p->tn.rval + 0200*1 );
1003: if( o==NAME ) return( 100 + 0200*1 );
1004: return( -1 );
1005: }
1006:
1007: offset( p, tyl ) register NODE *p; int tyl; {
1008:
1009: if( tyl==1 &&
1010: p->in.op==REG &&
1011: (p->in.type==INT || p->in.type==UNSIGNED) )
1012: return( p->tn.rval );
1013: if( p->in.op==LS &&
1014: p->in.left->in.op==REG &&
1015: (p->in.left->in.type==INT || p->in.left->in.type==UNSIGNED) &&
1016: p->in.right->in.op==ICON &&
1017: p->in.right->in.name[0]=='\0' &&
1018: (1<<p->in.right->tn.lval)==tyl)
1019: return( p->in.left->tn.rval );
1020: if( tyl==2 &&
1021: p->in.op==PLUS &&
1022: (p->in.left->in.type==INT || p->in.left->in.type==UNSIGNED) &&
1023: p->in.left->in.op==REG &&
1024: p->in.right->in.op==REG &&
1025: p->in.left->tn.rval==p->in.right->tn.rval )
1026: return( p->in.left->tn.rval );
1027: return( -1 );
1028: }
1029:
1030: makeor2( p, q, b, o) register NODE *p, *q; register int b, o; {
1031: register NODE *t;
1032: NODE *f;
1033:
1034: p->in.op = OREG;
1035: f = p->in.left; /* have to free this subtree later */
1036:
1037: /* init base */
1038: switch (q->in.op) {
1039: case ICON:
1040: case REG:
1041: case OREG:
1042: case NAME:
1043: t = q;
1044: break;
1045:
1046: case MINUS:
1047: q->in.right->tn.lval = -q->in.right->tn.lval;
1048: case PLUS:
1049: t = q->in.right;
1050: break;
1051:
1052: case UNARY MUL:
1053: t = q->in.left->in.left;
1054: break;
1055:
1056: default:
1057: cerror("illegal makeor2");
1058: }
1059:
1060: p->tn.lval = t->tn.lval;
1061: #ifndef FLEXNAMES
1062: {
1063: register int i;
1064: for(i=0; i<NCHNAM; ++i)
1065: p->in.name[i] = t->in.name[i];
1066: }
1067: #else
1068: p->in.name = t->in.name;
1069: #endif
1070:
1071: /* init offset */
1072: p->tn.rval = R2PACK( (b & 0177), o, (b>>7) );
1073:
1074: tfree(f);
1075: return;
1076: }
1077:
1078: canaddr( p ) NODE *p; {
1079: register int o = p->in.op;
1080:
1081: if( o==NAME || o==REG || o==ICON || o==OREG || (o==UNARY MUL && shumul(p->in.left)) ) return(1);
1082: return(0);
1083: }
1084:
1085: #ifndef shltype
1086: shltype( o, p ) register NODE *p; {
1087: return( o== REG || o == NAME || o == ICON || o == OREG || ( o==UNARY MUL && shumul(p->in.left)) );
1088: }
1089: #endif
1090:
1091: flshape( p ) NODE *p; {
1092: register int o = p->in.op;
1093:
1094: if( o==NAME || o==REG || o==ICON || o==OREG || (o==UNARY MUL && shumul(p->in.left)) ) return(1);
1095: return(0);
1096: }
1097:
1098: /* INTEMP shapes must not contain any temporary registers */
1099: shtemp( p ) register NODE *p; {
1100: int r;
1101:
1102: if( p->in.op == STARG ) p = p->in.left;
1103:
1104: switch (p->in.op) {
1105: case REG:
1106: return( !istreg(p->tn.rval) );
1107: case OREG:
1108: r = p->tn.rval;
1109: if( R2TEST(r) ) {
1110: if( istreg(R2UPK1(r)) )
1111: return(0);
1112: r = R2UPK2(r);
1113: }
1114: return( !istreg(r) );
1115: case UNARY MUL:
1116: p = p->in.left;
1117: return( p->in.op != UNARY MUL && shtemp(p) );
1118: }
1119:
1120: if( optype( p->in.op ) != LTYPE ) return(0);
1121: return(1);
1122: }
1123:
1124: shumul( p ) register NODE *p; {
1125: register int o;
1126: extern int xdebug;
1127:
1128: if (xdebug) {
1129: printf("\nshumul:op=%d,lop=%d,rop=%d", p->in.op, p->in.left->in.op, p->in.right->in.op);
1130: printf(" prname=%s,plty=%d, prlval=%D\n", p->in.right->in.name, p->in.left->in.type, p->in.right->tn.lval);
1131: }
1132:
1133: o = p->in.op;
1134: if(( o == NAME || (o == OREG && !R2TEST(p->tn.rval)) || o == ICON )
1135: && p->in.type != PTR+DOUBLE)
1136: return( STARNM );
1137:
1138: return( 0 );
1139: }
1140:
1141: special( p, shape ) register NODE *p; {
1142: if( shape==SIREG && p->in.op == OREG && R2TEST(p->tn.rval) ) return(1);
1143: else return(0);
1144: }
1145:
1146: adrcon( val ) CONSZ val; {
1147: printf(ACONFMT, val);
1148: }
1149:
1150: conput( p ) register NODE *p; {
1151: switch( p->in.op ){
1152:
1153: case ICON:
1154: acon( p );
1155: return;
1156:
1157: case REG:
1158: putstr(rname(p->tn.rval));
1159: return;
1160:
1161: default:
1162: cerror( "illegal conput" );
1163: }
1164: }
1165:
1166: /*ARGSUSED*/
1167: insput( p ) NODE *p; {
1168: cerror( "insput" );
1169: }
1170:
1171: /*
1172: * Output the address of the second item in the
1173: * pair pointed to by p.
1174: */
1175: upput(p, size)
1176: register NODE *p;
1177: {
1178: CONSZ save;
1179:
1180: if (p->in.op == FLD)
1181: p = p->in.left;
1182: switch (p->in.op) {
1183:
1184: case NAME:
1185: case OREG:
1186: save = p->tn.lval;
1187: p->tn.lval += size/SZCHAR;
1188: adrput(p);
1189: p->tn.lval = save;
1190: break;
1191:
1192: case REG:
1193: if (size == SZLONG) {
1194: putstr(rname(p->tn.rval+1));
1195: break;
1196: }
1197: /* fall thru... */
1198:
1199: default:
1200: cerror("illegal upper address op %s size %d",
1201: opst[p->tn.op], size);
1202: /*NOTREACHED*/
1203: }
1204: }
1205:
1206: adrput( p ) register NODE *p; {
1207: register int r;
1208: /* output an address, with offsets, from p */
1209:
1210: if( p->in.op == FLD ){
1211: p = p->in.left;
1212: }
1213: switch( p->in.op ){
1214:
1215: case NAME:
1216: acon( p );
1217: return;
1218:
1219: case ICON:
1220: /* addressable value of the constant */
1221: putchar('$');
1222: acon( p );
1223: return;
1224:
1225: case REG:
1226: putstr(rname(p->tn.rval));
1227: if(p->in.type == DOUBLE) /* for entry mask */
1228: (void) rname(p->tn.rval+1);
1229: return;
1230:
1231: case OREG:
1232: r = p->tn.rval;
1233: if( R2TEST(r) ){ /* double indexing */
1234: register int flags;
1235:
1236: flags = R2UPK3(r);
1237: if( flags & 1 ) putchar('*');
1238: if( p->tn.lval != 0 || p->in.name[0] != '\0' ) acon(p);
1239: if( R2UPK1(r) != 100) printf( "(%s)", rname(R2UPK1(r)) );
1240: printf( "[%s]", rname(R2UPK2(r)) );
1241: return;
1242: }
1243: if( r == FP && p->tn.lval > 0 ){ /* in the argument region */
1244: if( p->in.name[0] != '\0' ) werror( "bad arg temp" );
1245: printf( CONFMT, p->tn.lval );
1246: putstr( "(fp)" );
1247: return;
1248: }
1249: if( p->tn.lval != 0 || p->in.name[0] != '\0') acon( p );
1250: printf( "(%s)", rname(p->tn.rval) );
1251: return;
1252:
1253: case UNARY MUL:
1254: /* STARNM or STARREG found */
1255: if( tshape(p, STARNM) ) {
1256: putchar( '*' );
1257: adrput( p->in.left);
1258: }
1259: return;
1260:
1261: default:
1262: cerror( "illegal address" );
1263: return;
1264:
1265: }
1266:
1267: }
1268:
1269: acon( p ) register NODE *p; { /* print out a constant */
1270:
1271: if( p->in.name[0] == '\0' )
1272: printf( CONFMT, p->tn.lval);
1273: else {
1274: #ifndef FLEXNAMES
1275: printf( "%.8s", p->in.name );
1276: #else
1277: putstr( p->in.name );
1278: #endif
1279: if( p->tn.lval != 0 ) {
1280: putchar( '+' );
1281: printf( CONFMT, p->tn.lval );
1282: }
1283: }
1284: }
1285:
1286: genscall( p, cookie ) register NODE *p; {
1287: /* structure valued call */
1288: return( gencall( p, cookie ) );
1289: }
1290:
1291: genfcall( p, cookie ) register NODE *p; {
1292: register NODE *p1;
1293: register int m;
1294: static char *funcops[6] = {
1295: "sin", "cos", "sqrt", "exp", "log", "atan"
1296: };
1297:
1298: /* generate function opcodes */
1299: if(p->in.op==UNARY FORTCALL && p->in.type==FLOAT &&
1300: (p1 = p->in.left)->in.op==ICON &&
1301: p1->tn.lval==0 && p1->in.type==INCREF(FTN|FLOAT)) {
1302: #ifdef FLEXNAMES
1303: p1->in.name++;
1304: #else
1305: strcpy(p1->in.name, p1->in.name[1]);
1306: #endif
1307: for(m=0; m<6; m++)
1308: if(!strcmp(p1->in.name, funcops[m]))
1309: break;
1310: if(m >= 6)
1311: uerror("no opcode for fortarn function %s", p1->in.name);
1312: } else
1313: uerror("illegal type of fortarn function");
1314: p1 = p->in.right;
1315: p->in.op = FORTCALL;
1316: if(!canaddr(p1))
1317: order( p1, INAREG|INBREG|SOREG|STARREG|STARNM );
1318: m = match( p, INTAREG|INTBREG );
1319: return(m != MDONE);
1320: }
1321:
1322: /* tbl */
1323: int gc_numbytes;
1324: /* tbl */
1325:
1326: /*ARGSUSED*/
1327: gencall( p, cookie ) register NODE *p; {
1328: /* generate the call given by p */
1329: register NODE *p1, *ptemp;
1330: register int temp, temp1;
1331: register int m;
1332:
1333: if( p->in.right ) temp = argsize( p->in.right );
1334: else temp = 0;
1335:
1336: if( p->in.op == STCALL || p->in.op == UNARY STCALL ){
1337: /* set aside room for structure return */
1338:
1339: if( p->stn.stsize > temp ) temp1 = p->stn.stsize;
1340: else temp1 = temp;
1341: }
1342:
1343: if( temp > maxargs ) maxargs = temp;
1344: SETOFF(temp1,4);
1345:
1346: if( p->in.right ){ /* make temp node, put offset in, and generate args */
1347: ptemp = talloc();
1348: ptemp->in.op = OREG;
1349: ptemp->tn.lval = -1;
1350: ptemp->tn.rval = SP;
1351: #ifndef FLEXNAMES
1352: ptemp->in.name[0] = '\0';
1353: #else
1354: ptemp->in.name = "";
1355: #endif
1356: ptemp->in.rall = NOPREF;
1357: ptemp->in.su = 0;
1358: genargs( p->in.right, ptemp );
1359: ptemp->in.op = FREE;
1360: }
1361:
1362: p1 = p->in.left;
1363: if( p1->in.op != ICON ){
1364: if( p1->in.op != REG ){
1365: if( p1->in.op != OREG || R2TEST(p1->tn.rval) ){
1366: if( p1->in.op != NAME ){
1367: order( p1, INAREG );
1368: }
1369: }
1370: }
1371: }
1372:
1373: /* tbl
1374: setup gc_numbytes so reference to ZC works */
1375:
1376: gc_numbytes = temp&(0x3ff);
1377:
1378: p->in.op = UNARY CALL;
1379: m = match( p, INTAREG|INTBREG );
1380:
1381: return(m != MDONE);
1382: }
1383:
1384: /* tbl */
1385: char *
1386: ccbranches[] = {
1387: "eql",
1388: "neq",
1389: "leq",
1390: "lss",
1391: "geq",
1392: "gtr",
1393: "lequ",
1394: "lssu",
1395: "gequ",
1396: "gtru",
1397: };
1398: /* tbl */
1399:
1400: /*ARGSUSED*/
1401: cbgen( o, lab, mode ) { /* printf conditional and unconditional branches */
1402:
1403: if( o != 0 && ( o < EQ || o > UGT ) )
1404: cerror( "bad conditional branch: %s", opst[o] );
1405: printf( " j%s L%d\n", o == 0 ? "br" : ccbranches[o-EQ], lab );
1406: }
1407:
1408: nextcook( p, cookie ) NODE *p; {
1409: /* we have failed to match p with cookie; try another */
1410: if( cookie == FORREW ) return( 0 ); /* hopeless! */
1411: if( !(cookie&(INTAREG|INTBREG)) ) return( INTAREG|INTBREG );
1412: if( !(cookie&INTEMP) && asgop(p->in.op) ) return( INTEMP|INAREG|INTAREG|INTBREG|INBREG );
1413: return( FORREW );
1414: }
1415:
1416: /*ARGSUSED*/
1417: lastchance( p, cook ) NODE *p; {
1418: /* forget it! */
1419: return(0);
1420: }
1421:
1422: optim2( p ) register NODE *p; {
1423: /* do local tree transformations and optimizations */
1424:
1425: int o;
1426: int i, mask;
1427: register NODE *l, *r;
1428:
1429: switch( o = p->in.op ) {
1430:
1431: case ASG PLUS:
1432: case ASG MINUS:
1433: case ASG MUL:
1434: case ASG OR:
1435: /* simple ASG OPSIMP -- reduce range of constant rhs */
1436: l = p->in.left;
1437: r = p->in.right;
1438: if( tlen(l) < SZINT/SZCHAR &&
1439: r->in.op==ICON && r->in.name[0]==0 ){
1440: mask = (1 << tlen(l) * SZCHAR) - 1;
1441: if( r->tn.lval & (mask & ~(mask >> 1)) )
1442: r->tn.lval |= ~mask;
1443: else
1444: r->tn.lval &= mask;
1445: }
1446: break;
1447:
1448: case AND:
1449: case ASG AND:
1450: r = p->in.right;
1451: if( r->in.op==ICON && r->in.name[0]==0 ) {
1452: /* check for degenerate operations */
1453: l = p->in.left;
1454: mask = (1 << tlen(l) * SZCHAR) - 1;
1455: if( o == ASG AND || ISUNSIGNED(r->in.type) ) {
1456: i = r->tn.lval & mask;
1457: if( i == mask ) {
1458: /* redundant mask */
1459: r->in.op = FREE;
1460: ncopy(p, l);
1461: l->in.op = FREE;
1462: break;
1463: }
1464: else if( i == 0 )
1465: /* all bits masked off */
1466: goto zero;
1467: r->tn.lval = i;
1468: if( tlen(l) < SZINT/SZCHAR ){
1469: /* sign extend */
1470: if( r->tn.lval & (mask & ~(mask >> 1)) )
1471: r->tn.lval |= ~mask;
1472: else
1473: r->tn.lval &= mask;
1474: }
1475: }
1476: else if( r->tn.lval == mask &&
1477: tlen(l) < SZINT/SZCHAR ) {
1478: /* use movz instead of and */
1479: r->in.op = SCONV;
1480: r->in.left = l;
1481: r->in.right = 0;
1482: r->in.type = ENUNSIGN(l->in.type);
1483: r->in.su = l->in.su > 1 ? l->in.su : 1;
1484: ncopy(p, r);
1485: p->in.left = r;
1486: p->in.type = INT;
1487: }
1488: }
1489: break;
1490:
1491: case SCONV:
1492: l = p->in.left;
1493: if( p->in.type == FLOAT || p->in.type == DOUBLE ||
1494: l->in.type == FLOAT || l->in.type == DOUBLE )
1495: return;
1496: if( l->in.op == PCONV )
1497: return;
1498: if( (l->in.op == CALL || l->in.op == UNARY CALL) &&
1499: l->in.type != INT && l->in.type != UNSIGNED )
1500: return;
1501:
1502: /* Only trust it to get it right if the size is the same */
1503: if( tlen(p) != tlen(l) )
1504: return;
1505:
1506: /* clobber conversion */
1507: if( l->in.op != FLD )
1508: l->in.type = p->in.type;
1509: ncopy( p, l );
1510: l->in.op = FREE;
1511:
1512: break;
1513:
1514: case ASSIGN:
1515: /*
1516: * Conversions are equivalent to assignments;
1517: * when the two operations are combined,
1518: * we can sometimes zap the conversion.
1519: */
1520: r = p->in.right;
1521: l = p->in.left;
1522: if ( r->in.op == SCONV &&
1523: !mixtypes(l, r) &&
1524: l->in.op != FLD &&
1525: tlen(l) == tlen(r) ) {
1526: p->in.right = r->in.left;
1527: r->in.op = FREE;
1528: }
1529: break;
1530:
1531: case ULE:
1532: case ULT:
1533: case UGE:
1534: case UGT:
1535: p->in.op -= (UGE-GE);
1536: if( degenerate(p) )
1537: break;
1538: p->in.op += (UGE-GE);
1539: break;
1540:
1541: case EQ:
1542: case NE:
1543: case LE:
1544: case LT:
1545: case GE:
1546: case GT:
1547: if( p->in.left->in.op == SCONV &&
1548: p->in.right->in.op == SCONV ) {
1549: l = p->in.left;
1550: r = p->in.right;
1551: if( l->in.type == DOUBLE &&
1552: l->in.left->in.type == FLOAT &&
1553: r->in.left->in.type == FLOAT ) {
1554: /* nuke the conversions */
1555: p->in.left = l->in.left;
1556: p->in.right = r->in.left;
1557: l->in.op = FREE;
1558: r->in.op = FREE;
1559: }
1560: /* more? */
1561: }
1562: (void) degenerate(p);
1563: break;
1564:
1565: case DIV:
1566: if( p->in.right->in.op == ICON &&
1567: p->in.right->tn.name[0] == '\0' &&
1568: ISUNSIGNED(p->in.right->in.type) &&
1569: (unsigned) p->in.right->tn.lval >= 0x80000000 ) {
1570: /* easy to do here, harder to do in zzzcode() */
1571: p->in.op = UGE;
1572: break;
1573: }
1574: case MOD:
1575: case ASG DIV:
1576: case ASG MOD:
1577: /*
1578: * optimize DIV and MOD
1579: *
1580: * basically we spot UCHAR and USHORT and try to do them
1581: * as signed ints... this may need tuning for the tahoe.
1582: */
1583: if( degenerate(p) )
1584: break;
1585: l = p->in.left;
1586: r = p->in.right;
1587: if( !ISUNSIGNED(r->in.type) ||
1588: tlen(l) >= SZINT/SZCHAR ||
1589: !(tlen(r) < SZINT/SZCHAR ||
1590: (r->in.op == ICON && r->tn.name[0] == '\0')) )
1591: break;
1592: if( r->in.op == ICON )
1593: r->tn.type = INT;
1594: else {
1595: NODE *t = talloc();
1596: t->in.left = r;
1597: r = t;
1598: r->in.op = SCONV;
1599: r->in.type = INT;
1600: r->in.right = 0;
1601: p->in.right = r;
1602: }
1603: if( o == DIV || o == MOD ) {
1604: NODE *t = talloc();
1605: t->in.left = l;
1606: l = t;
1607: l->in.op = SCONV;
1608: l->in.type = INT;
1609: l->in.right = 0;
1610: p->in.left = l;
1611: }
1612: /* handle asgops in table */
1613: break;
1614:
1615: case RS:
1616: case ASG RS:
1617: case LS:
1618: case ASG LS:
1619: /* pick up degenerate shifts */
1620: l = p->in.left;
1621: r = p->in.right;
1622: if( !(r->in.op == ICON && r->tn.name[0] == '\0') )
1623: break;
1624: i = r->tn.lval;
1625: if( i < 0 )
1626: /* front end 'fixes' this? */
1627: if( o == LS || o == ASG LS )
1628: o += (RS-LS);
1629: else
1630: o += (LS-RS);
1631: if( (o == RS || o == ASG RS) &&
1632: !ISUNSIGNED(l->in.type) )
1633: /* can't optimize signed right shifts */
1634: break;
1635: if( o == LS ) {
1636: if( i < SZINT )
1637: break;
1638: }
1639: else {
1640: if( i < tlen(l) * SZCHAR )
1641: break;
1642: }
1643: zero:
1644: if( !asgop( o ) )
1645: if( tshape(l, SAREG|SNAME|SCON|SOREG|STARNM) ) {
1646: /* no side effects */
1647: tfree(l);
1648: ncopy(p, r);
1649: r->in.op = FREE;
1650: p->tn.lval = 0;
1651: }
1652: else {
1653: p->in.op = COMOP;
1654: r->tn.lval = 0;
1655: }
1656: else {
1657: p->in.op = ASSIGN;
1658: r->tn.lval = 0;
1659: }
1660: break;
1661: }
1662: }
1663:
1664: degenerate(p) register NODE *p; {
1665: int o;
1666: int result, i;
1667: int lower, upper;
1668: register NODE *l, *r;
1669:
1670: /*
1671: * try to keep degenerate comparisons with constants
1672: * out of the table.
1673: */
1674: r = p->in.right;
1675: l = p->in.left;
1676: if( r->in.op != ICON ||
1677: r->tn.name[0] != '\0' ||
1678: tlen(l) >= tlen(r) )
1679: return (0);
1680: switch( l->in.type ) {
1681: case CHAR:
1682: lower = -(1 << SZCHAR - 1);
1683: upper = (1 << SZCHAR - 1) - 1;
1684: break;
1685: case UCHAR:
1686: lower = 0;
1687: upper = (1 << SZCHAR) - 1;
1688: break;
1689: case SHORT:
1690: lower = -(1 << SZSHORT - 1);
1691: upper = (1 << SZSHORT - 1) - 1;
1692: break;
1693: case USHORT:
1694: lower = 0;
1695: upper = (1 << SZSHORT) - 1;
1696: break;
1697: default:
1698: cerror("unsupported type in degenerate()");
1699: }
1700: i = r->tn.lval;
1701: switch( o = p->in.op ) {
1702: case DIV:
1703: case ASG DIV:
1704: case MOD:
1705: case ASG MOD:
1706: /* DIV and MOD work like EQ */
1707: case EQ:
1708: case NE:
1709: if( lower == 0 && (unsigned) i > upper )
1710: result = o == NE;
1711: else if( i < lower || i > upper )
1712: result = o == NE;
1713: else
1714: return (0);
1715: break;
1716: case LT:
1717: case GE:
1718: if( lower == 0 && (unsigned) i > upper )
1719: result = o == LT;
1720: else if( i <= lower )
1721: result = o != LT;
1722: else if( i > upper )
1723: result = o == LT;
1724: else
1725: return (0);
1726: break;
1727: case LE:
1728: case GT:
1729: if( lower == 0 && (unsigned) i >= upper )
1730: result = o == LE;
1731: else if( i < lower )
1732: result = o != LE;
1733: else if( i >= upper )
1734: result = o == LE;
1735: else
1736: return (0);
1737: break;
1738: default:
1739: cerror("unknown op in degenerate()");
1740: }
1741:
1742: if( o == MOD || o == ASG MOD ) {
1743: r->in.op = FREE;
1744: ncopy(p, l);
1745: l->in.op = FREE;
1746: }
1747: else if( o != ASG DIV && tshape(l, SAREG|SNAME|SCON|SOREG|STARNM) ) {
1748: /* no side effects */
1749: tfree(l);
1750: ncopy(p, r);
1751: r->in.op = FREE;
1752: p->tn.lval = result;
1753: }
1754: else {
1755: if( o == ASG DIV )
1756: p->in.op = ASSIGN;
1757: else {
1758: p->in.op = COMOP;
1759: r->tn.type = INT;
1760: }
1761: r->tn.lval = result;
1762: }
1763: if( logop(o) )
1764: p->in.type = INT;
1765:
1766: return (1);
1767: }
1768:
1769: struct functbl {
1770: int fop;
1771: TWORD ftype;
1772: char *func;
1773: } opfunc[] = {
1774: DIV, TANY, "udiv",
1775: MOD, TANY, "urem",
1776: ASG DIV, TANY, "audiv",
1777: ASG MOD, TANY, "aurem",
1778: 0, 0, 0 };
1779:
1780: hardops(p) register NODE *p; {
1781: /* change hard to do operators into function calls. */
1782: register NODE *q;
1783: register struct functbl *f;
1784: register o;
1785: NODE *old,*temp;
1786:
1787: o = p->in.op;
1788: if( ! (optype(o)==BITYPE &&
1789: (ISUNSIGNED(p->in.left->in.type) ||
1790: ISUNSIGNED(p->in.right->in.type))) )
1791: return;
1792:
1793: for( f=opfunc; f->fop; f++ ) {
1794: if( o==f->fop ) goto convert;
1795: }
1796: return;
1797:
1798: convert:
1799: if( p->in.right->in.op == ICON && p->in.right->tn.name[0] == '\0' )
1800: /* 'J' in zzzcode() -- assumes DIV or MOD operations */
1801: /* save a subroutine call -- use at most 5 instructions */
1802: return;
1803: if( tlen(p->in.left) < SZINT/SZCHAR && tlen(p->in.right) < SZINT/SZCHAR )
1804: /* optim2() will modify the op into an ordinary int op */
1805: return;
1806: if( asgop( o ) ) {
1807: old = NIL;
1808: switch( p->in.left->in.op ){
1809: case FLD:
1810: q = p->in.left->in.left;
1811: /*
1812: * rewrite (lval.fld /= rval); as
1813: * ((*temp).fld = udiv((*(temp = &lval)).fld,rval));
1814: * else the compiler will evaluate lval twice.
1815: */
1816: if( q->in.op == UNARY MUL ){
1817: /* first allocate a temp storage */
1818: temp = talloc();
1819: temp->in.op = OREG;
1820: temp->tn.rval = TMPREG;
1821: temp->tn.lval = BITOOR(freetemp(1));
1822: temp->in.type = INCREF(p->in.type);
1823: #ifdef FLEXNAMES
1824: temp->in.name = "";
1825: #else
1826: temp->in.name[0] = '\0';
1827: #endif
1828: old = q->in.left;
1829: q->in.left = temp;
1830: }
1831: /* fall thru ... */
1832:
1833: case REG:
1834: case NAME:
1835: case OREG:
1836: /* change ASG OP to a simple OP */
1837: q = talloc();
1838: q->in.op = NOASG p->in.op;
1839: q->in.rall = NOPREF;
1840: q->in.type = p->in.type;
1841: q->in.left = tcopy(p->in.left);
1842: q->in.right = p->in.right;
1843: p->in.op = ASSIGN;
1844: p->in.right = q;
1845: p = q;
1846: f -= 2; /* Note: this depends on the table order */
1847: /* on the right side only - replace *temp with
1848: *(temp = &lval), build the assignment node */
1849: if( old ){
1850: temp = q->in.left->in.left; /* the "*" node */
1851: q = talloc();
1852: q->in.op = ASSIGN;
1853: q->in.left = temp->in.left;
1854: q->in.right = old;
1855: q->in.type = old->in.type;
1856: #ifdef FLEXNAMES
1857: q->in.name = "";
1858: #else
1859: q->in.name[0] = '\0';
1860: #endif
1861: temp->in.left = q;
1862: }
1863: break;
1864:
1865: case UNARY MUL:
1866: /* avoid doing side effects twice */
1867: q = p->in.left;
1868: p->in.left = q->in.left;
1869: q->in.op = FREE;
1870: break;
1871:
1872: default:
1873: cerror( "hardops: can't compute & LHS" );
1874: }
1875: }
1876:
1877: /* build comma op for args to function */
1878: q = talloc();
1879: q->in.op = CM;
1880: q->in.rall = NOPREF;
1881: q->in.type = INT;
1882: q->in.left = p->in.left;
1883: q->in.right = p->in.right;
1884: p->in.op = CALL;
1885: p->in.right = q;
1886:
1887: /* put function name in left node of call */
1888: p->in.left = q = talloc();
1889: q->in.op = ICON;
1890: q->in.rall = NOPREF;
1891: q->in.type = INCREF( FTN + p->in.type );
1892: #ifndef FLEXNAMES
1893: strcpy( q->in.name, f->func );
1894: #else
1895: q->in.name = f->func;
1896: #endif
1897: q->tn.lval = 0;
1898: q->tn.rval = 0;
1899:
1900: }
1901:
1902: zappost(p) NODE *p; {
1903: /* look for ++ and -- operators and remove them */
1904:
1905: register int o, ty;
1906: register NODE *q;
1907: o = p->in.op;
1908: ty = optype( o );
1909:
1910: switch( o ){
1911:
1912: case INCR:
1913: case DECR:
1914: q = p->in.left;
1915: p->in.right->in.op = FREE; /* zap constant */
1916: ncopy( p, q );
1917: q->in.op = FREE;
1918: return;
1919:
1920: }
1921:
1922: if( ty == BITYPE ) zappost( p->in.right );
1923: if( ty != LTYPE ) zappost( p->in.left );
1924: }
1925:
1926: fixpre(p) NODE *p; {
1927:
1928: register int o, ty;
1929: o = p->in.op;
1930: ty = optype( o );
1931:
1932: switch( o ){
1933:
1934: case ASG PLUS:
1935: p->in.op = PLUS;
1936: break;
1937: case ASG MINUS:
1938: p->in.op = MINUS;
1939: break;
1940: }
1941:
1942: if( ty == BITYPE ) fixpre( p->in.right );
1943: if( ty != LTYPE ) fixpre( p->in.left );
1944: }
1945:
1946: /*ARGSUSED*/
1947: NODE * addroreg(l) NODE *l;
1948: /* OREG was built in clocal()
1949: * for an auto or formal parameter
1950: * now its address is being taken
1951: * local code must unwind it
1952: * back to PLUS/MINUS REG ICON
1953: * according to local conventions
1954: */
1955: {
1956: cerror("address of OREG taken");
1957: /*NOTREACHED*/
1958: }
1959:
1960: # ifndef ONEPASS
1961: main( argc, argv ) char *argv[]; {
1962: return( mainp2( argc, argv ) );
1963: }
1964: # endif
1965:
1966: strip(p) register NODE *p; {
1967: NODE *q;
1968:
1969: /* strip nodes off the top when no side effects occur */
1970: for( ; ; ) {
1971: switch( p->in.op ) {
1972: case SCONV: /* remove lint tidbits */
1973: q = p->in.left;
1974: ncopy( p, q );
1975: q->in.op = FREE;
1976: break;
1977: /* could probably add a few more here */
1978: default:
1979: return;
1980: }
1981: }
1982: }
1983:
1984: myreader(p) register NODE *p; {
1985: strip( p ); /* strip off operations with no side effects */
1986: canon( p ); /* expands r-vals for fields */
1987: walkf( p, hardops ); /* convert ops to function calls */
1988: walkf( p, optim2 );
1989: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.