|
|
1.1 root 1: /* @(#) cgen.c: 1.2 1/12/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, 0 );
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: t = p->tn.type;
303: if( t == TCHAR || t == TSHORT ) t = TINT;
304: else if( t == TUCHAR || t == TUSHORT ) t = TUNSIGNED;
305: else if( t == TFLOAT ) t = TDOUBLE;
306: else return( p );
307:
308: if( p->tn.op == CONV && c2bigger(p) )
309: {
310: p->tn.type = t;
311: return( p );
312: }
313: q = talloc();
314: q->tn.op = CONV;
315: q->in.left = p;
316: q->in.right = 0;
317: q->tn.name = (char *) 0;
318: q->tn.type = t;
319: q->tn.goal = NRGS;
320: return( q );
321: }
322:
323: NODE *
324: reweop( p )
325: register NODE *p;
326:
327: {
328: /* rewrite A op= B as A = A op B */
329: /* also, rewrite (CONV A) op= B as A = (CONV ( (CONV A) op B ) ) */
330: /* rewritten in place */
331: /* on input, the type of the op= equals the type of A */
332: /* the type of the op node on output is the type of B */
333: /* the type of the = node on output is the type of A */
334:
335: register NODE *q, *t;
336: register TWORD ty;
337:
338: #ifndef NODBG
339: if( odebug>1 )
340: {
341: e2print( p );
342: printf( "\nrewritten by reweop as:\n" );
343: }
344: #endif
345: q = tcopy( p, 0 );
346: if( p->in.left->tn.op == CONV )
347: {
348: /* ( CONV (A) ) op= B becomes A = CONV ( CONV(A) op B ) */
349: /* the op is done to the type of B */
350: /* the assignment is done to the type of A */
351: t = p->in.left;
352: ty = t->in.left->tn.type;
353: p->in.left = t->in.left;
354: tfree( p->in.right );
355: p->in.right = t;
356: t->in.left = q;
357: /* now, have the tree built; fix the types */
358: t->tn.type = ty;
359: }
360: else
361: {
362: tfree( p->in.right );
363: p->in.right = q;
364: }
365: /* NOTE: no =ops for structures... */
366: p->tn.op = ASSIGN;
367: q->tn.op = NOASG q->tn.op;
368: p->tn.type = p->in.left->tn.type;
369: q->tn.type = q->in.right->tn.type;
370: #ifndef NODBG
371: if( odebug>1 ) e2print( p );
372: #endif
373: }
374:
375: rewass( p )
376: NODE *p;
377:
378: {
379: NODE *q;
380: int o;
381: /* look for =ops to be rewritten */
382:
383: #ifndef NODBG
384: if( odebug )
385: {
386: printf( "rewass called with:\n" );
387: e2print( p );
388: }
389: #endif
390: o = p->tn.op;
391: if( o == UNARY AND )
392: {
393: if( p->in.left->tn.op == RNODE )
394: {
395: /* this should happen only with structure returns */
396: q = p->in.left;
397: q->tn.op = ICON;
398: *p = *q;
399: q->tn.op = FREE;
400: return(0); /* keep going in costs */
401: }
402: /* this case should happen only with short structures */
403: rewsto( p->in.left );
404: /* & f() has turned into & ( t=f(),t) */
405: #ifndef NODBG
406: if( odebug )
407: {
408: printf( "\nrewritten by rewass as:\n" );
409: e2print( p );
410: }
411: #endif
412: return(1);
413: }
414: if( !asgop(o) || o==ASSIGN )
415: {
416: if( o==ASSIGN )
417: {
418: /* look for funny nodes on lhs */
419: o = p->in.left->tn.op;
420: if( o==RNODE || o==QNODE || o==SNODE )
421: {
422: /* force into r0 */
423: p->in.left->tn.op = REG;
424: p->in.left->tn.rval = callreg( p->in.right );
425: #ifndef NODBG
426: if( odebug )
427: {
428: printf( "funny node redone\n" );
429: e2print(p);
430: }
431: #endif
432: return(0);
433: }
434: }
435: else
436: {
437: TWORD t = p->in.left->tn.type;
438: /* this case is, for example,
439: unsigned char a, b;
440: ... a*b
441: /* we convert both to a reasonable type */
442: /* the result is assumed to be automatically
443: /* converted downwards if it should be... */
444:
445: p->in.left = ind2type( p->in.left );
446: p->in.right = ind2type( p->in.right );
447: #ifndef NODBG
448: if( odebug ) {
449: printf( "conversions inserted" );
450: e2print(p);
451: }
452: #endif
453: /* if this didn't work, we are in trouble */
454: if( t != p->in.left->tn.type ) {
455: /* we have changed something */
456: return( 0 );
457: }
458: }
459: e2print(p);
460: cerror( "can't deal with op %s", opst[o] );
461: }
462: if( o == INCR || o == DECR )
463: {
464: /* very crude: a++ becomes (a+=1)-1 */
465: #ifndef NODBG
466: if( odebug>1 )
467: {
468: e2print( p );
469: printf( "\nrewritten by rewass as:\n" );
470: }
471: #endif
472: if( p->in.goal == CEFF )
473: {
474: p->in.op = ((o==INCR)?ASG PLUS:ASG MINUS);
475: }
476: else
477: {
478: q = tcopy(p, 0);
479: regrcl( p->in.left );
480: tfree( p->in.left );
481: p->in.left = q;
482: q->tn.op = ((o==INCR)?ASG PLUS:ASG MINUS);
483: p->tn.op = ((o==INCR)?MINUS:PLUS);
484: }
485: #ifndef NODBG
486: if( odebug )
487: {
488: printf( "\nrewritten by rewass as:\n" );
489: e2print( p );
490: }
491: #endif
492: return(1);
493: }
494: /* find out if some subtree has to be stored into a temp... */
495: if( q = lhsto(p) )
496: {
497: if( !rewsto( q ) ) cerror( "rewass0" ); /* q => t=q,t */
498: rewcom( p, p->tn.goal ); /* move COMOP to the top */
499: if( p->tn.op != COMOP ) cerror( "rewass1" );
500: if( !asgop( p->in.right->tn.op ) ) cerror( "rewass2" );
501: reweop( p->in.right );
502: }
503: else reweop( p ); /* rewrite p as an =OP */
504: return(1);
505: }
506:
507: # ifdef NONEST
508: subcall( p )
509: register NODE *p;
510:
511: {
512: /* return 1 if p contains a callop */
513: register o, t;
514:
515: o = p->tn.op;
516: if( callop(o)
517: # ifndef UCALLBAD
518: && o!=UNARY CALL
519: # endif
520: # ifndef STCALLBAD
521: && o!=UNARY STCALL
522: # endif
523: # ifndef UFCALLBAD
524: && o!=UNARY FORTCALL
525: # endif
526: ) return( 1 );
527: t = optype( o );
528: if( t==BITYPE && subcall(p->in.right) ) return( 1 );
529: if( t!=LTYPE ) return( subcall( p->in.left ) );
530: return( 0 );
531: }
532:
533: nonest( p )
534: register NODE *p;
535:
536: {
537: register o, t;
538: /* right now, this is very crude */
539: /* find arguments below a call; store them */
540: /* nonest is called up to a call; stocm is called within args */
541:
542: o = p->tn.op;
543: t = optype( o );
544: if( o==CALL || o==STCALL || o==FORTCALL)
545: {
546: stocm( p->in.right );
547: nonest( p->in.left );
548: return;
549: }
550: if( t == BITYPE ) nonest( p->in.right );
551: if( t != LTYPE ) nonest( p->in.left );
552: }
553:
554: stocm( p )
555: register NODE *p;
556:
557: {
558: /* all call arguments below p must be stored */
559: register NODE *q;
560: register o;
561:
562: while( (o=p->tn.op) == CM )
563: {
564: stocm( p->in.right );
565: p = p->in.left;
566: }
567: if( o != STARG && o != FUNARG ) cerror( "stocm" );
568:
569: q = p->in.left;
570: if( subcall( q ) )
571: {
572: if( o == FUNARG ) rewsto( q );
573: else
574: {
575: /* structure argument with call beneath */
576: rewsto( p );
577: }
578: /* now q will be done outside of a call, so use nonest */
579: nonest( q );
580: }
581: }
582: # endif
583:
584: outshp( pp )
585: SHAPE **pp;
586:
587: {
588: SHAPE *p;
589:
590: if (pp == 0)
591: return;
592:
593: for( ; p = *pp; ++pp )
594: {
595: printf("\t\t");
596: shpr(p);
597: printf( " (%d)\n", p->sc );
598: }
599: }
600:
601: tabpr()
602: {
603: register OPTAB *p;
604: for (p =table; ;p++)
605: {
606: printf("Dump of table[%d] (stinline %d)\n", p-table, p->stinline );
607: printf("\top = %s\n", opst[p->op]);
608: printf("\tnextop = %d\n", p->nextop?p->nextop-table:-1 );
609: printf("\tlshape = %d\n", p->lshape-pshape);
610: printf("\tltype = 0%o\n", p->ltype);
611: printf("\trshape = %d\n", p->rshape-pshape);
612: printf("\trtype = 0%o\n", p->rtype);
613: printf("\tneeds = %d\n", p->needs);
614: printf("\trewrite = %d\n", p->rewrite);
615: printf("\tcstring = %s", p->cstring);
616: printf("\tcost = %d\n", p->cost);
617: printf("\tLeft:\n");
618: outshp(p->lshape);
619: printf("\tRight:\n");
620: outshp(p->rshape);
621: printf("\n");
622: }
623: }
624:
625: codgen( p )
626: NODE *p;
627:
628: {
629:
630: /* generate the code for p; */
631: int i, flag;
632:
633: #ifndef NODBG
634: if (odebug > 5)
635: {
636: tabpr();
637: /* NOTREACHED */
638: }
639: #endif
640:
641: # ifdef NONEST
642: nonest(p);
643: # endif
644:
645: /* if we make drastic changes to the tree (e.g., introduce temps)
646: ** /* we will go back and do the whole thing again
647: */
648: /* statistics indicate that this happens about 10% of the time */
649: /* if the percentage rises, there are many things that can be done to
650: ** /* improve matters
651: */
652: /* for example, RNODE, etc., could be removed by reader, and some of
653: ** /* the op rewriting could be discovered by reader as well
654: */
655:
656: again:
657:
658: /* move the comma ops as high as practical */
659:
660: rewcom( p, CEFF );
661:
662: #ifndef NODBG
663: if( odebug )
664: {
665: printf( "After goals are computed:" );
666: e2print( p );
667: }
668: #endif
669:
670: /* compute the costs */
671:
672: if( costs( p ) ) goto again; /* if rewritten, do again */
673:
674: #ifndef NODBG
675: if( odebug )
676: {
677: printf( "After costs are computed:" );
678: e2print( p );
679: }
680: #endif
681:
682: /* do a trial code generation */
683: nins = 0;
684: insout( p, CEFF );
685:
686: /* rewrite stored subtrees as assignments to temps, with COMOP's */
687: flag = 0;
688: for( i=0; i<nins; ++i )
689: {
690: if( inst[i].goal == CTEMP )
691: {
692: #ifndef NODBG
693: if( odebug )
694: {
695: printf( "subtree is stored in temp:\n" );
696: e2print( inst[i].p );
697: }
698: #endif
699: if( rewsto( inst[i].p ) ) {
700: if( !fast ) goto again;
701: /* otherwise, rewrite all temps now */
702: flag = 1;
703: }
704: }
705: }
706: if( flag ) goto again;
707:
708: #ifndef NODBG
709: if( odebug ) e2print(p);
710: #endif
711: /* output the actual instructions */
712: insprt();
713: }
714:
715: INST inst[NINS];
716: int nins;
717:
718: insprt()
719: {
720: int i;
721: register INST *pi;
722: register NODE *p;
723: register OPTAB *q;
724: register c, goal;
725:
726: for( pi=inst,i=0; i<nins; ++i,++pi )
727: {
728: p = pi->p;
729: q = pi->q;
730: c = pi->goal;
731: if( c == CCC && (q->rewrite&RESCC) ) goal = FORCC;
732: else if( c == CEFF ) goal = FOREFF;
733: else goal = INREG;
734: #ifndef NODEBUG
735: if(odebug > 4)
736: {
737: printf("INSOUT: %d c=",i);
738: preff(c);
739: printf(" goal=");
740: prgoal(goal);
741: printf("\n");
742: e2print(p);
743: }
744: #endif
745:
746: allo( p, q );
747: # ifdef TMPSRET
748: /* not the best place in the world, but... */
749: if (p->in.op == STCALL || p->in.op == UNARY STCALL)
750: expand(p, goal, TMPSRET, q);
751: #endif
752: expand( p, goal, q->cstring, q );
753: reclaim( p, q->rewrite, goal );
754:
755: /* now, if condition codes needed, test */
756: if( c == CCC && p->tn.op != CCODES )
757: {
758: cfix( p, CCC );
759: if( p->tn.op != CCODES ) cerror( "ctest fails" );
760: }
761: if( c>=0 && c<=NRGS && !istnode( p ) )
762: {
763: cfix( p, NRGS );
764: }
765: }
766: }
767:
768: SHTABLE sha;
769:
770: cfix( p, goal )
771: NODE *p;
772: {
773: /* p is to be fixed according to goal (CCC or NRGS) */
774: OPTAB *q;
775: NODE *pp;
776: int r;
777:
778: #ifndef NODBG
779: if(odebug > 4)
780: {
781: printf("CFIX: goal=");
782: prgoal(goal);
783: printf("\n");
784: e2print(p);
785: }
786: #endif
787: if( goal == CCC )
788: {
789: r = RESCC;
790: p->tn.goal = CCC;
791: }
792: else
793: {
794: r = (RESC1|RESC2|RESC3);
795: pp = getl( p );
796: if( istnode( pp ) ) r |= RLEFT;
797: pp = getr( p );
798: if( istnode( pp ) ) r |= RRIGHT;
799: }
800:
801: if( goal == CCC ) goal = FORCC;
802: else goal = INREG;
803:
804: for( q=0; q = match( p, q ); )
805: {
806: /* takes the first match (may not be cheapest) */
807: /* template writers, take note! */
808: if( q->rewrite & r )
809: {
810: /* generate the code on the spot */
811: allo( p, q );
812: # ifdef TMPSRET
813: /* likewise */
814: if (p->in.op == STCALL || p->in.op == UNARY STCALL)
815: expand(p, goal, TMPSRET, q);
816: #endif
817: expand( p, goal, q->cstring, q );
818: reclaim( p, q->rewrite, goal );
819: return;
820: }
821: }
822: e2print(p);
823: cerror( "cfix trouble" );
824: }
825:
826:
827: preff(c)
828: {
829: char buf[20];
830: register char *p;
831:
832: p = c==CCC ? "CCC" : c==CTEMP ? "CTEMP" : c==CEFF ? "CEFF" : 0;
833: if(!p)
834: {
835: sprintf(buf,"0%o",c);
836: p = buf;
837: }
838: printf("%s",p);
839: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.