|
|
1.1 root 1: /* @(#) cgen.c: 1.3 4/26/84 */
2:
3: # include "mfile2.h"
4: # define istnode(p) (p->in.op==REG && istreg(p->tn.rval))
5:
6: /*
7: ** For God's workes are, like him, all infinite
8: ** And curious search but craftie sin's delight.
9: */
10:
11: rewcom( p, goal )
12: NODE *p;
13:
14: {
15: /* find all , ops, move as high as is legal */
16: /* rewrite p in place; this takes some doing! */
17: /* while we are at it, take care of setting the goal field */
18: int o, ty, g1, g2;
19: NODE *l, *r, *ql, *qr;
20:
21: o = p->tn.op;
22: g1 = g2 = NRGS;
23: p->tn.goal = goal;
24:
25: /* special cases for subtrees:
26: ** GENBR has left as Condition codes
27: ** COMOP has left as Effects
28: ** COLON, GENUBR, CM, GENLAB have descendents = node
29: ** CALL, STCALL, FORTCALL has right as Effects
30: ** All others use registers
31: */
32:
33: switch( o )
34: {
35:
36: case FREE:
37: cerror( "rewcom(%d) is FREE", p-node );
38:
39: case GENBR:
40: g1 = CCC;
41: break;
42:
43: case COMOP:
44: g1 = CEFF;
45: g2 = goal;
46: break;
47:
48: case COLON:
49: case GENUBR:
50: case CM:
51: case GENLAB:
52: g1 = g2 = goal;
53: break;
54:
55: case CALL:
56: case STCALL:
57: case FORTCALL:
58: g2 = CEFF;
59: break;
60: }
61:
62:
63: switch( ty = optype(o) )
64: {
65:
66: case BITYPE:
67: rewcom( r = p->in.right, g2 );
68: case UTYPE:
69: rewcom( l = p->in.left, g1 );
70: break;
71: case LTYPE:
72: return;
73: }
74:
75: if( o==COMOP || o==COLON || o==GENLAB ) return;
76:
77: /* look for (A,B) op C and A op (B,C), and rewrite */
78: /* A,B if A headed by GENBR can't be rewritten */
79: /* the assumption is that B is executed immediately after A, */
80: /* and this won't necessarily be true if op is commutative */
81:
82: if( l->tn.op == COMOP && l->in.left->tn.op != GENBR )
83: {
84: /* rewrite it... */
85: /* (A,B) op C => A,(B op C) */
86: /* also, for unary ops, op (A,B) => A , (op B) */
87: ql = l->in.left;
88: qr = l->in.right;
89: *l = *p; /* copies op, and other stuff if op is unary */
90: l->in.left = qr;
91: p->in.right = l;
92: p->in.left = ql;
93: p->tn.op = COMOP;
94: rewcom( p, p->tn.goal );
95: }
96: if( ty == UTYPE ) return;
97: if( r->tn.op == COMOP && r->in.right->tn.op != GENBR )
98: {
99: /* rewrite, again */
100: /* A op (B,C) => B,(A op C) */
101: /* op is not unary now */
102: ql = r->in.left;
103: qr = r->in.right;
104: *r = *p;
105: p->tn.op = COMOP;
106: p->in.left = ql;
107: r->in.right = qr;
108: rewcom( p, p->tn.goal );
109: }
110: }
111:
112: rewlhs(p)
113: NODE *p;
114:
115: {
116: /* rewrite x op= y as (x op= y),x */
117: /* it would be really nice to optimize after doing this . . . */
118: NODE *q, *t;
119: q = talloc();
120: *q = *p;
121: t = tcopy( p->in.left );
122: p->in.left = q;
123: p->in.right = t;
124: p->tn.op = COMOP;
125: return;
126: }
127:
128: rewsto(p)
129: NODE *p;
130: {
131: /* a temp, t, is generated, and p is rewritten as ((t=p),t) */
132: /* if p has the form x op= A, and x is of the right form, rewrite
133: /* as ((x op= A), x) */
134:
135: int o, ao;
136: NODE *t, *q;
137: /* probably not perfect for structs: CHECK UP.. */
138:
139: while( (o=p->tn.op) == COMOP ) p = p->in.right;
140: if( o == TEMP ) return(0); /* nothing to do */
141: if( o == STARG )
142: {
143: /* store a structure argument */ /* like storing a usual argument, but we have addresses */
144:
145: t = talloc();
146: *t = *p->in.left; /* copy contents, mainly for type, etc. */
147: q = talloc();
148: *q = *t;
149: t->tn.op = TEMP;
150: t->tn.lval = freetemp(argsize(p)/SZINT );
151: t->tn.lval = BITOOR(t->tn.lval);
152: t->tn.name = (char *) 0;
153: t->tn.type = TSTRUCT;
154: q->tn.op = UNARY AND;
155: q->in.left = t;
156: /* now, q has & TEMP */
157: t = talloc();
158: *t = *p;
159: t->in.left = q;
160: t->in.right = p->in.left;
161: t->tn.op = STASG;
162: /* now, t has (&TEMP) = struct */
163: p->in.left = talloc();
164: p->in.left->tn.op = COMOP;
165: p->in.left->in.left = t;
166: p->in.left->in.right = t = talloc(); /* copy q here */
167: *t = *q;
168: t->in.left = talloc();
169: *t->in.left = *q->in.left;
170: /* finally, have (&TEMP = struct),(&TEMP) */
171: /* this should do it: whew! */
172: #ifndef NODBG
173: if( odebug>1 ) e2print( p );
174: #endif
175: return( 1 );
176: }
177:
178: #ifndef NODBG
179: if( odebug>1 )
180: {
181: e2print( p );
182: printf( "\nrewritten by rewsto as:\n" );
183: }
184: #endif
185: if( asgop(o) && o!=INCR && o!=DECR && lhsok( p->in.left ) ) {
186: /* x op= y turns into (x op= y), x */
187: rewlhs( p );
188: return( 1 );
189: }
190: ao = ASG o;
191: if( asgbinop(ao) )
192: {
193: if( p->in.left->tn.op == TEMP )
194: {
195: p->tn.op = ao;
196: rewlhs( p );
197: #ifndef NODBG
198: if( odebug>1 ) e2print( p );
199: #endif
200: return( 1 );
201: }
202: }
203:
204: /* to rewrite in place, p becomes a COMOP; rhs is the temp, lsh
205: ** /* is t = p, where p has been converted to the intermediate type
206: */
207: /* after some debate, the type of the temp will be the type of p */
208:
209: t = talloc();
210: *t = *p; /* copy contents, mainly for type, etc. */
211: q = talloc();
212: *q = *p;
213: t->tn.op = TEMP;
214: t->tn.lval = freetemp(argsize(p)/SZINT );
215: t->tn.lval = BITOOR(t->tn.lval);
216: t->tn.name = (char *) 0;
217: q->tn.op = ASSIGN;
218: q->in.left = t;
219: q->in.right = talloc();
220: *(q->in.right) = *p;
221: /* now, q has (t=p) */
222: p->in.right = talloc();
223: *(p->in.right) = *t;
224: p->tn.op = COMOP;
225: p->in.left = q;
226: /* this should do it: whew! */
227: #ifndef NODBG
228: if( odebug>1 ) e2print( p );
229: #endif
230: return( 1 );
231: }
232:
233: iseff( p )
234: NODE *p;
235:
236: {
237: /* return 1 if p has some side effects, 0 otherwise */
238: int o;
239: o = p->tn.op;
240: if( callop(o) || asgop(o) ) return( 1 );
241: switch( optype( o ) )
242: {
243: case BITYPE:
244: if( iseff( p->in.right ) ) return( 1 );
245: case UTYPE:
246: return( iseff( p->in.left ) );
247: }
248: return( 0 );
249: }
250:
251: NODE *
252: lhsto( p )
253: NODE *p;
254:
255: {
256: /* find a piece of the LHS to be stored */
257: /* if found, rewrite tree */
258: NODE *q;
259: int o;
260:
261: for( q = p->in.left; (o=q->tn.op)!=STAR; q=q->in.left )
262: {
263: if( optype(o) == LTYPE ) return( (NODE *)0);
264: }
265: /* q is now the * node, if there one */
266: q = q->in.left;
267: o = q->tn.op;
268: if( optype(o) == LTYPE ) return( (NODE *)0 );
269: else return( q );
270: }
271:
272: static int
273: c2bigger( p ) NODE *p; {
274: /* p is a conversion op; does it make things bigger */
275: register TWORD t, tl;
276:
277: t = p->tn.type;
278: tl = p->in.left->tn.type;
279:
280: if( (t|tl)&TPOINT ) return( 0 ); /* pointers are funny */
281: if( t&TDOUBLE ) return( 1 );
282: if( tl&TDOUBLE ) return( 0 );
283: if( t&TFLOAT ) return( 1 );
284: if( tl&TFLOAT ) return( 0 );
285: if( t&(TLONG|TULONG) ) return( 1 );
286: if( tl&(TLONG|TULONG) ) return( 0 );
287: if( t&(TINT|TUNSIGNED) ) return( 1 );
288: if( tl&(TINT|TUNSIGNED) ) return( 0 );
289: if( t &(TSHORT|TUSHORT) ) return( 1 );
290: return( 0 );
291: }
292:
293: NODE *
294: ind2type( p )
295: register NODE *p;
296:
297: {
298: /* make the type of p be the appropriate type for an argument */
299: register TWORD t;
300: NODE *q;
301:
302: if ( !p )
303: return( p );
304: t = p->tn.type;
305: if( t == TCHAR || t == TSHORT ) t = TINT;
306: else if( t == TUCHAR || t == TUSHORT ) t = TUNSIGNED;
307: else if( t == TFLOAT ) t = TDOUBLE;
308: else return( p );
309:
310: if( p->tn.op == CONV && c2bigger(p) )
311: {
312: p->tn.type = t;
313: return( p );
314: }
315: q = talloc();
316: q->tn.op = CONV;
317: q->in.left = p;
318: q->in.right = 0;
319: q->tn.name = (char *) 0;
320: q->tn.type = t;
321: q->tn.goal = NRGS;
322: return( q );
323: }
324:
325: NODE *
326: reweop( p )
327: register NODE *p;
328:
329: {
330: /* rewrite A op= B as A = A op B */
331: /* also, rewrite (CONV A) op= B as A = (CONV ( (CONV A) op B ) ) */
332: /* rewritten in place */
333: /* on input, the type of the op= equals the type of A */
334: /* the type of the op node on output is the type of B */
335: /* the type of the = node on output is the type of A */
336:
337: register NODE *q, *t;
338: register TWORD ty;
339:
340: #ifndef NODBG
341: if( odebug>1 )
342: {
343: e2print( p );
344: printf( "\nrewritten by reweop as:\n" );
345: }
346: #endif
347: /* rewrite tree with duplicate left subtree in new right subtree */
348: /* there is an implicit q->in.right = p->in.right in *q = *p */
349: q = talloc();
350: *q = *p;
351: q->in.left = tcopy( p->in.left );
352: if( p->in.left->tn.op == CONV )
353: {
354: /* ( CONV (A) ) op= B becomes A = CONV ( CONV(A) op B ) */
355: /* the op is done to the type of B */
356: /* the assignment is done to the type of A */
357: t = p->in.left;
358: ty = t->in.left->tn.type;
359: p->in.left = t->in.left;
360: p->in.right = t;
361: t->in.left = q;
362: /* now, have the tree built; fix the types */
363: t->tn.type = ty;
364: }
365: else
366: {
367: p->in.right = q;
368: }
369: /* NOTE: no =ops for structures... */
370: p->tn.op = ASSIGN;
371: q->tn.op = NOASG q->tn.op;
372: p->tn.type = p->in.left->tn.type;
373: q->tn.type = q->in.right->tn.type;
374: #ifndef NODBG
375: if( odebug>1 ) e2print( p );
376: #endif
377: }
378:
379: rewass( p )
380: NODE *p;
381:
382: {
383: NODE *q;
384: int o;
385: /* look for =ops to be rewritten */
386:
387: #ifndef NODBG
388: if( odebug )
389: {
390: printf( "rewass called with:\n" );
391: e2print( p );
392: }
393: #endif
394: o = p->tn.op;
395: if( o == UNARY AND )
396: {
397: if( p->in.left->tn.op == RNODE )
398: {
399: /* this should happen only with structure returns */
400: q = p->in.left;
401: q->tn.op = ICON;
402: *p = *q;
403: q->tn.op = FREE;
404: return(0); /* keep going in costs */
405: }
406: /* this case should happen only with short structures */
407: rewsto( p->in.left );
408: /* & f() has turned into & ( t=f(),t) */
409: #ifndef NODBG
410: if( odebug )
411: {
412: printf( "\nrewritten by rewass as:\n" );
413: e2print( p );
414: }
415: #endif
416: return(1);
417: }
418: if( !asgop(o) || o==ASSIGN )
419: {
420: if( o==ASSIGN )
421: {
422: /* look for funny nodes on lhs */
423: o = p->in.left->tn.op;
424: if( o==RNODE || o==QNODE || o==SNODE )
425: {
426: /* force into r0 */
427: p->in.left->tn.op = REG;
428: p->in.left->tn.rval = callreg( p->in.right );
429: #ifndef NODBG
430: if( odebug )
431: {
432: printf( "funny node redone\n" );
433: e2print(p);
434: }
435: #endif
436: return(0);
437: }
438: }
439: else
440: {
441: TWORD t = p->in.left->tn.type;
442: /* this case is, for example,
443: unsigned char a, b;
444: ... a*b
445: /* we convert both to a reasonable type */
446: /* the result is assumed to be automatically
447: /* converted downwards if it should be... */
448:
449: p->in.left = ind2type( p->in.left );
450: p->in.right = ind2type( p->in.right );
451: #ifndef NODBG
452: if( odebug ) {
453: printf( "conversions inserted" );
454: e2print(p);
455: }
456: #endif
457: /* if this didn't work, we are in trouble */
458: if( t != p->in.left->tn.type ) {
459: /* we have changed something */
460: return( 0 );
461: }
462: }
463: e2print(p);
464: cerror( "can't deal with op %s", opst[o] );
465: }
466: if( o == INCR || o == DECR )
467: {
468: /* very crude: a++ becomes (a+=1)-1 */
469: #ifndef NODBG
470: if( odebug>1 )
471: {
472: e2print( p );
473: printf( "\nrewritten by rewass as:\n" );
474: }
475: #endif
476: if( p->in.goal == CEFF )
477: {
478: p->in.op = ((o==INCR)?ASG PLUS:ASG MINUS);
479: }
480: else
481: {
482: /* rewrite tree with duplicate left subree in new
483: /* right subtree...
484: /* there is an implict q->in.left = p->in.left in *q = * p
485: */
486: q = talloc();
487: *q = *p;
488: q->in.right = tcopy( p->in.right );
489: p->in.left = q;
490: q->tn.op = ((o==INCR)?ASG PLUS:ASG MINUS);
491: p->tn.op = ((o==INCR)?MINUS:PLUS);
492: }
493: #ifndef NODBG
494: if( odebug )
495: {
496: printf( "\nrewritten by rewass as:\n" );
497: e2print( p );
498: }
499: #endif
500: return(1);
501: }
502: /* find out if some subtree has to be stored into a temp... */
503: if( q = lhsto(p) )
504: {
505: if( !rewsto( q ) ) cerror( "rewass0" ); /* q => t=q,t */
506: rewcom( p, p->tn.goal ); /* move COMOP to the top */
507: if( p->tn.op != COMOP ) cerror( "rewass1" );
508: if( !asgop( p->in.right->tn.op ) ) cerror( "rewass2" );
509: reweop( p->in.right );
510: }
511: else reweop( p ); /* rewrite p as an =OP */
512: return(1);
513: }
514:
515: # ifdef NONEST
516: subcall( p )
517: register NODE *p;
518:
519: {
520: /* return 1 if p contains a callop */
521: register o, t;
522:
523: o = p->tn.op;
524: if( callop(o)
525: # ifndef UCALLBAD
526: && o!=UNARY CALL
527: # endif
528: # ifndef STCALLBAD
529: && o!=UNARY STCALL
530: # endif
531: # ifndef UFCALLBAD
532: && o!=UNARY FORTCALL
533: # endif
534: ) return( 1 );
535: t = optype( o );
536: if( t==BITYPE && subcall(p->in.right) ) return( 1 );
537: if( t!=LTYPE ) return( subcall( p->in.left ) );
538: return( 0 );
539: }
540:
541: nonest( p )
542: register NODE *p;
543:
544: {
545: register o, t;
546: /* right now, this is very crude */
547: /* find arguments below a call; store them */
548: /* nonest is called up to a call; stocm is called within args */
549:
550: o = p->tn.op;
551: t = optype( o );
552: if( o==CALL || o==STCALL || o==FORTCALL)
553: {
554: stocm( p->in.right );
555: nonest( p->in.left );
556: return;
557: }
558: if( t == BITYPE ) nonest( p->in.right );
559: if( t != LTYPE ) nonest( p->in.left );
560: }
561:
562: stocm( p )
563: register NODE *p;
564:
565: {
566: /* all call arguments below p must be stored */
567: register NODE *q;
568: register o;
569:
570: while( (o=p->tn.op) == CM )
571: {
572: stocm( p->in.right );
573: p = p->in.left;
574: }
575: if( o != STARG && o != FUNARG ) cerror( "stocm" );
576:
577: q = p->in.left;
578: if( subcall( q ) )
579: {
580: if( o == FUNARG ) rewsto( q );
581: else
582: {
583: /* structure argument with call beneath */
584: rewsto( p );
585: }
586: /* now q will be done outside of a call, so use nonest */
587: nonest( q );
588: }
589: }
590: # endif
591:
592: outshp( pp )
593: SHAPE **pp;
594:
595: {
596: SHAPE *p;
597:
598: if (pp == 0)
599: return;
600:
601: for( ; p = *pp; ++pp )
602: {
603: printf("\t\t");
604: shpr(p);
605: printf( " (%d)\n", p->sc );
606: }
607: }
608:
609: tabpr()
610: {
611: register OPTAB *p;
612: for (p =table; ;p++)
613: {
614: printf("Dump of table[%d] (stinline %d)\n", p-table, p->stinline );
615: printf("\top = %s\n", opst[p->op]);
616: printf("\tnextop = %d\n", p->nextop?p->nextop-table:-1 );
617: printf("\tlshape = %d\n", p->lshape-pshape);
618: printf("\tltype = 0%o\n", p->ltype);
619: printf("\trshape = %d\n", p->rshape-pshape);
620: printf("\trtype = 0%o\n", p->rtype);
621: printf("\tneeds = %d\n", p->needs);
622: printf("\trewrite = %d\n", p->rewrite);
623: printf("\tcstring = %s", p->cstring);
624: printf("\tcost = %d\n", p->cost);
625: printf("\tLeft:\n");
626: outshp(p->lshape);
627: printf("\tRight:\n");
628: outshp(p->rshape);
629: printf("\n");
630: }
631: }
632:
633: codgen( p )
634: NODE *p;
635:
636: {
637:
638: /* generate the code for p; */
639: int i, flag;
640:
641: #ifndef NODBG
642: if (odebug > 5)
643: {
644: tabpr();
645: /* NOTREACHED */
646: }
647: #endif
648:
649: # ifdef NONEST
650: nonest(p);
651: # endif
652:
653: /* if we make drastic changes to the tree (e.g., introduce temps)
654: ** /* we will go back and do the whole thing again
655: */
656: /* statistics indicate that this happens about 10% of the time */
657: /* if the percentage rises, there are many things that can be done to
658: ** /* improve matters
659: */
660: /* for example, RNODE, etc., could be removed by reader, and some of
661: ** /* the op rewriting could be discovered by reader as well
662: */
663:
664: again:
665:
666: /* move the comma ops as high as practical */
667:
668: rewcom( p, CEFF );
669:
670: #ifndef NODBG
671: if( odebug )
672: {
673: printf( "After goals are computed:" );
674: e2print( p );
675: }
676: #endif
677:
678: /* compute the costs */
679:
680: if( costs( p ) ) goto again; /* if rewritten, do again */
681:
682: #ifndef NODBG
683: if( odebug )
684: {
685: printf( "After costs are computed:" );
686: e2print( p );
687: }
688: #endif
689:
690: /* do a trial code generation */
691: nins = 0;
692: insout( p, CEFF );
693:
694: /* rewrite stored subtrees as assignments to temps, with COMOP's */
695: flag = 0;
696: for( i=0; i<nins; ++i )
697: {
698: if( inst[i].goal == CTEMP )
699: {
700: #ifndef NODBG
701: if( odebug )
702: {
703: printf( "subtree is stored in temp:\n" );
704: e2print( inst[i].p );
705: }
706: #endif
707: if( rewsto( inst[i].p ) ) {
708: if( !fast ) goto again;
709: /* otherwise, rewrite all temps now */
710: flag = 1;
711: }
712: }
713: }
714: if( flag ) goto again;
715:
716: #ifndef NODBG
717: if( odebug ) e2print(p);
718: #endif
719: /* output the actual instructions */
720: insprt();
721: }
722:
723: INST inst[NINS];
724: int nins;
725:
726: insprt()
727: {
728: int i;
729: register INST *pi;
730: register NODE *p;
731: register OPTAB *q;
732: register c, goal;
733:
734: for( pi=inst,i=0; i<nins; ++i,++pi )
735: {
736: p = pi->p;
737: q = pi->q;
738: c = pi->goal;
739: if( c == CCC && (q->rewrite&RESCC) ) goal = FORCC;
740: else if( c == CEFF ) goal = FOREFF;
741: else goal = INREG;
742: #ifndef NODEBUG
743: if(odebug > 4)
744: {
745: printf("INSOUT: %d c=",i);
746: preff(c);
747: printf(" goal=");
748: prgoal(goal);
749: printf("\n");
750: e2print(p);
751: }
752: #endif
753:
754: allo( p, q );
755: # ifdef TMPSRET
756: /* not the best place in the world, but... */
757: if (p->in.op == STCALL || p->in.op == UNARY STCALL)
758: expand(p, goal, TMPSRET, q);
759: #endif
760: expand( p, goal, q->cstring, q );
761: reclaim( p, q->rewrite, goal );
762:
763: /* now, if condition codes needed, test */
764: if( c == CCC && p->tn.op != CCODES )
765: {
766: cfix( p, CCC );
767: if( p->tn.op != CCODES ) cerror( "ctest fails" );
768: }
769: if( c>=0 && c<=NRGS && !istnode( p ) )
770: {
771: cfix( p, NRGS );
772: }
773: }
774: }
775:
776: SHTABLE sha;
777: int odebug = 0;
778:
779: cfix( p, goal )
780: NODE *p;
781: {
782: /* p is to be fixed according to goal (CCC or NRGS) */
783: OPTAB *q;
784: NODE *pp;
785: int r;
786:
787: #ifndef NODBG
788: if(odebug > 4)
789: {
790: printf("CFIX: goal=");
791: prgoal(goal);
792: printf("\n");
793: e2print(p);
794: }
795: #endif
796: if( goal == CCC )
797: {
798: r = RESCC;
799: p->tn.goal = CCC;
800: }
801: else
802: {
803: r = (RESC1|RESC2|RESC3);
804: pp = getl( p );
805: if( istnode( pp ) ) r |= RLEFT;
806: pp = getr( p );
807: if( istnode( pp ) ) r |= RRIGHT;
808: }
809:
810: if( goal == CCC ) goal = FORCC;
811: else goal = INREG;
812:
813: for( q=0; q = match( p, q ); )
814: {
815: /* takes the first match (may not be cheapest) */
816: /* template writers, take note! */
817: if( q->rewrite & r )
818: {
819: /* generate the code on the spot */
820: allo( p, q );
821: # ifdef TMPSRET
822: /* likewise */
823: if (p->in.op == STCALL || p->in.op == UNARY STCALL)
824: expand(p, goal, TMPSRET, q);
825: #endif
826: expand( p, goal, q->cstring, q );
827: reclaim( p, q->rewrite, goal );
828: return;
829: }
830: }
831: e2print(p);
832: cerror( "cfix trouble" );
833: }
834:
835:
836: preff(c)
837: {
838: char buf[20];
839: register char *p;
840:
841: p = c==CCC ? "CCC" : c==CTEMP ? "CTEMP" : c==CEFF ? "CEFF" : 0;
842: if(!p)
843: {
844: sprintf(buf,"0%o",c);
845: p = buf;
846: }
847: printf("%s",p);
848: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.