|
|
1.1 root 1: /*
2: * Copyright (c) 1980 Regents of the University of California.
3: * All rights reserved. The Berkeley software License Agreement
4: * specifies the terms and conditions for redistribution.
5: */
6:
7: #ifndef lint
8: static char sccsid[] = "@(#)optim.c 5.2 (Berkeley) 6/9/85";
9: #endif not lint
10:
11: /*
12: * optim.c
13: *
14: * Miscellaneous optimizer routines, f77 compiler pass 1.
15: *
16: * UCSD Chemistry modification history:
17: *
18: * $Log: optim.c,v $
19: * Revision 2.12 85/06/08 22:57:01 donn
20: * Prevent core dumps -- bug in optinsert was causing lastslot to be wrong
21: * when a slot was inserted at the end of the buffer.
22: *
23: * Revision 2.11 85/03/18 08:05:05 donn
24: * Prevent warnings about implicit conversions.
25: *
26: * Revision 2.10 85/02/12 20:13:00 donn
27: * Resurrected the hack in 2.6.1.1 to avoid creating a temporary when
28: * there is a concatenation on the rhs of an assignment, and threw out
29: * all the code dealing with starcat(). It seems that we can't use a
30: * temporary because the lhs as well as the rhs may have nonconstant length.
31: *
32: * Revision 2.9 85/01/18 00:53:52 donn
33: * Missed a call to free() in the last change...
34: *
35: * Revision 2.8 85/01/18 00:50:03 donn
36: * Fixed goof made when modifying buffmnmx() to explicitly call expand().
37: *
38: * Revision 2.7 85/01/15 18:47:35 donn
39: * Changes to allow character*(*) variables to appear in concatenations in
40: * the rhs of an assignment statement.
41: *
42: * Revision 2.6 84/12/16 21:46:27 donn
43: * Fixed bug that prevented concatenations from being run together. Changed
44: * buffpower() to not touch exponents greater than 64 -- let putpower do them.
45: *
46: * Revision 2.5 84/10/29 08:41:45 donn
47: * Added hack to flushopt() to prevent the compiler from trying to generate
48: * intermediate code after an error.
49: *
50: * Revision 2.4 84/08/07 21:28:00 donn
51: * Removed call to p2flush() in putopt() -- this allows us to make better use
52: * of the buffering on the intermediate code file.
53: *
54: * Revision 2.3 84/08/01 16:06:24 donn
55: * Forced expand() to expand subscripts.
56: *
57: * Revision 2.2 84/07/19 20:21:55 donn
58: * Decided I liked the expression tree algorithm after all. The algorithm
59: * which repeatedly squares temporaries is now checked in as rev. 2.1.
60: *
61: * Revision 1.3.1.1 84/07/10 14:18:18 donn
62: * I'm taking this branch off the trunk -- it works but it's not as good as
63: * the old version would be if it worked right.
64: *
65: * Revision 1.5 84/07/09 22:28:50 donn
66: * Added fix to buffpower() to prevent it chasing after huge exponents.
67: *
68: * Revision 1.4 84/07/09 20:13:59 donn
69: * Replaced buffpower() routine with a new one that generates trees which can
70: * be handled by CSE later on.
71: *
72: * Revision 1.3 84/05/04 21:02:07 donn
73: * Added fix for a bug in buffpower() that caused func(x)**2 to turn into
74: * func(x) * func(x). This bug had already been fixed in putpower()...
75: *
76: * Revision 1.2 84/03/23 22:47:21 donn
77: * The subroutine argument temporary fixes from Bob Corbett didn't take into
78: * account the fact that the code generator collects all the assignments to
79: * temporaries at the start of a statement -- hence the temporaries need to
80: * be initialized once per statement instead of once per call.
81: *
82: */
83:
84: #include "defs.h"
85: #include "optim.h"
86:
87:
88:
89: /*
90: * Information buffered for each slot type
91: *
92: * slot type expptr integer pointer
93: *
94: * IFN expr label -
95: * GOTO - label -
96: * LABEL - label -
97: * EQ expr - -
98: * CALL expr - -
99: * CMGOTO expr num labellist*
100: * STOP expr - -
101: * DOHEAD [1] - ctlframe*
102: * ENDDO [1] - ctlframe*
103: * ARIF expr - labellist*
104: * RETURN expr label -
105: * ASGOTO expr - labellist*
106: * PAUSE expr - -
107: * ASSIGN expr label -
108: * SKIOIFN expr label -
109: * SKFRTEMP expr - -
110: *
111: * Note [1]: the nullslot field is a pointer to a fake slot which is
112: * at the end of the slots which may be replaced by this slot. In
113: * other words, it looks like this:
114: * DOHEAD slot
115: * slot \
116: * slot > ordinary IF, GOTO, LABEL slots which implement the DO
117: * slot /
118: * NULL slot
119: */
120:
121:
122: expptr expand();
123:
124: Slotp firstslot = NULL;
125: Slotp lastslot = NULL;
126: int numslots = 0;
127:
128:
129: /*
130: * turns off optimization option
131: */
132:
133: optoff()
134:
135: {
136: flushopt();
137: optimflag = 0;
138: }
139:
140:
141:
142: /*
143: * initializes the code buffer for optimization
144: */
145:
146: setopt()
147:
148: {
149: register Slotp sp;
150:
151: for (sp = firstslot; sp; sp = sp->next)
152: free ( (charptr) sp);
153: firstslot = lastslot = NULL;
154: numslots = 0;
155: }
156:
157:
158:
159: /*
160: * flushes the code buffer
161: */
162:
163: LOCAL int alreadycalled = 0;
164:
165: flushopt()
166: {
167: register Slotp sp;
168: int savelineno;
169:
170: if (alreadycalled) return; /* to prevent recursive call during errors */
171: alreadycalled = 1;
172:
173: if (debugflag[1])
174: showbuffer ();
175:
176: frtempbuff ();
177:
178: savelineno = lineno;
179: for (sp = firstslot; sp; sp = sp->next)
180: {
181: if (nerr == 0)
182: putopt (sp);
183: else
184: frexpr (sp->expr);
185: if(sp->ctlinfo) free ( (charptr) sp->ctlinfo);
186: free ( (charptr) sp);
187: numslots--;
188: }
189: firstslot = lastslot = NULL;
190: numslots = 0;
191: clearbb();
192: lineno = savelineno;
193:
194: alreadycalled = 0;
195: }
196:
197:
198:
199: /*
200: * puts out code for the given slot (from the code buffer)
201: */
202:
203: LOCAL putopt (sp)
204: register Slotp sp;
205: {
206: lineno = sp->lineno;
207: switch (sp->type) {
208: case SKNULL:
209: break;
210: case SKIFN:
211: case SKIOIFN:
212: putif(sp->expr, sp->label);
213: break;
214: case SKGOTO:
215: putgoto(sp->label);
216: break;
217: case SKCMGOTO:
218: putcmgo(sp->expr, sp->label, sp->ctlinfo);
219: break;
220: case SKCALL:
221: putexpr(sp->expr);
222: break;
223: case SKSTOP:
224: putexpr (call1 (TYSUBR, "s_stop", sp->expr));
225: break;
226: case SKPAUSE:
227: putexpr (call1 (TYSUBR, "s_paus", sp->expr));
228: break;
229: case SKASSIGN:
230: puteq (sp->expr,
231: intrconv(sp->expr->headblock.vtype, mkaddcon(sp->label)));
232: break;
233: case SKDOHEAD:
234: case SKENDDO:
235: break;
236: case SKEQ:
237: putexpr(sp->expr);
238: break;
239: case SKARIF:
240: #define LM ((struct Labelblock * *)sp->ctlinfo)[0]->labelno
241: #define LZ ((struct Labelblock * *)sp->ctlinfo)[1]->labelno
242: #define LP ((struct Labelblock * *)sp->ctlinfo)[2]->labelno
243: prarif(sp->expr, LM, LZ, LP);
244: break;
245: case SKASGOTO:
246: putbranch((Addrp) sp->expr);
247: break;
248: case SKLABEL:
249: putlabel(sp->label);
250: break;
251: case SKRETURN:
252: if (sp->expr)
253: {
254: putforce(TYINT, sp->expr);
255: putgoto(sp->label);
256: }
257: else
258: putgoto(sp->label);
259: break;
260: case SKFRTEMP:
261: templist = mkchain (sp->expr,templist);
262: break;
263: default:
264: badthing("SKtype", "putopt", sp->type);
265: break;
266: }
267:
268: /*
269: * Recycle argument temporaries here. This must get done on a
270: * statement-by-statement basis because the code generator
271: * makes side effects happen at the start of a statement.
272: */
273: argtemplist = hookup(argtemplist, activearglist);
274: activearglist = CHNULL;
275: }
276:
277:
278:
279: /*
280: * copies one element of the control stack
281: */
282:
283: LOCAL struct Ctlframe *cpframe(p)
284: register char *p;
285: {
286: static int size = sizeof (struct Ctlframe);
287: register int n;
288: register char *q;
289: struct Ctlframe *q0;
290:
291: q0 = ALLOC(Ctlframe);
292: q = (char *) q0;
293: n = size;
294: while(n-- > 0)
295: *q++ = *p++;
296: return( q0);
297: }
298:
299:
300:
301: /*
302: * copies an array of labelblock pointers
303: */
304:
305: LOCAL struct Labelblock **cplabarr(n,arr)
306: struct Labelblock *arr[];
307: int n;
308: {
309: struct Labelblock **newarr;
310: register char *in, *out;
311: register int i,j;
312:
313: newarr = (struct Labelblock **) ckalloc (n * sizeof (char *));
314: for (i = 0; i < n; i++)
315: {
316: newarr[i] = ALLOC (Labelblock);
317: out = (char *) newarr[i];
318: in = (char *) arr[i];
319: j = sizeof (struct Labelblock);
320: while (j-- > 0)
321: *out++ = *in++;
322: }
323: return (newarr);
324: }
325:
326:
327:
328: /*
329: * creates a new slot in the code buffer
330: */
331:
332: LOCAL Slotp newslot()
333: {
334: register Slotp sp;
335:
336: ++numslots;
337: sp = ALLOC( slt );
338: sp->next = NULL ;
339: if (lastslot)
340: {
341: sp->prev = lastslot;
342: lastslot = lastslot->next = sp;
343: }
344: else
345: {
346: firstslot = lastslot = sp;
347: sp->prev = NULL;
348: }
349: sp->lineno = lineno;
350: return (sp);
351: }
352:
353:
354:
355: /*
356: * removes (but not deletes) the specified slot from the code buffer
357: */
358:
359: removeslot (sl)
360: Slotp sl;
361:
362: {
363: if (sl->next)
364: sl->next->prev = sl->prev;
365: else
366: lastslot = sl->prev;
367: if (sl->prev)
368: sl->prev->next = sl->next;
369: else
370: firstslot = sl->next;
371: sl->next = sl->prev = NULL;
372:
373: --numslots;
374: }
375:
376:
377:
378: /*
379: * inserts slot s1 before existing slot s2 in the code buffer;
380: * appends to end of list if s2 is NULL.
381: */
382:
383: insertslot (s1,s2)
384: Slotp s1,s2;
385:
386: {
387: if (s2)
388: {
389: if (s2->prev)
390: s2->prev->next = s1;
391: else
392: firstslot = s1;
393: s1->prev = s2->prev;
394: s2->prev = s1;
395: }
396: else
397: {
398: s1->prev = lastslot;
399: lastslot->next = s1;
400: lastslot = s1;
401: }
402: s1->next = s2;
403:
404: ++numslots;
405: }
406:
407:
408:
409: /*
410: * deletes the specified slot from the code buffer
411: */
412:
413: delslot (sl)
414: Slotp sl;
415:
416: {
417: removeslot (sl);
418:
419: if (sl->ctlinfo)
420: free ((charptr) sl->ctlinfo);
421: frexpr (sl->expr);
422: free ((charptr) sl);
423: numslots--;
424: }
425:
426:
427:
428: /*
429: * inserts a slot before the specified slot; if given NULL, it is
430: * inserted at the end of the buffer
431: */
432:
433: Slotp optinsert (type,p,l,c,currslot)
434: int type;
435: expptr p;
436: int l;
437: int *c;
438: Slotp currslot;
439:
440: {
441: Slotp savelast,new;
442:
443: savelast = lastslot;
444: if (currslot)
445: lastslot = currslot->prev;
446: new = optbuff (type,p,l,c);
447: new->next = currslot;
448: if (currslot)
449: currslot->prev = new;
450: new->lineno = -1; /* who knows what the line number should be ??!! */
451: if (currslot)
452: lastslot = savelast;
453: return (new);
454: }
455:
456:
457:
458: /*
459: * buffers the FRTEMP slots which have been waiting
460: */
461:
462: frtempbuff ()
463:
464: {
465: chainp ht;
466: register Slotp sp;
467:
468: for (ht = holdtemps; ht; ht = ht->nextp)
469: {
470: sp = newslot();
471: /* this slot actually belongs to some previous source line */
472: sp->lineno = sp->lineno - 1;
473: sp->type = SKFRTEMP;
474: sp->expr = (expptr) ht->datap;
475: sp->label = 0;
476: sp->ctlinfo = NULL;
477: }
478: holdtemps = NULL;
479: }
480:
481:
482:
483: /*
484: * puts the given information into a slot at the end of the code buffer
485: */
486:
487: Slotp optbuff (type,p,l,c)
488: int type;
489: expptr p;
490: int l;
491: int *c;
492:
493: {
494: register Slotp sp;
495:
496: if (debugflag[1])
497: {
498: fprintf (diagfile,"-----optbuff-----"); showslottype (type);
499: showexpr (p,0); fprintf (diagfile,"\n");
500: }
501:
502: p = expand (p);
503: sp = newslot();
504: sp->type = type;
505: sp->expr = p;
506: sp->label = l;
507: sp->ctlinfo = NULL;
508: switch (type)
509: {
510: case SKCMGOTO:
511: sp->ctlinfo = (int*) cplabarr (l, (struct Labelblock**) c);
512: break;
513: case SKARIF:
514: sp->ctlinfo = (int*) cplabarr (3, (struct Labelblock**) c);
515: break;
516: case SKDOHEAD:
517: case SKENDDO:
518: sp->ctlinfo = (int*) cpframe ((struct Ctlframe*) c);
519: break;
520: default:
521: break;
522: }
523:
524: frtempbuff ();
525:
526: return (sp);
527: }
528:
529:
530:
531: /*
532: * expands the given expression, if possible (e.g., concat, min, max, etc.);
533: * also frees temporaries when they are indicated as being the last use
534: */
535:
536: #define APPEND(z) \
537: res = res->exprblock.rightp = mkexpr (OPCOMMA, z, newtemp)
538:
539: LOCAL expptr expand (p)
540: tagptr p;
541:
542: {
543: Addrp t;
544: expptr q;
545: expptr buffmnmx(), buffpower();
546:
547: if (!p)
548: return (ENULL);
549: switch (p->tag)
550: {
551: case TEXPR:
552: switch (p->exprblock.opcode)
553: {
554: case OPASSIGN: /* handle a = b // c */
555: if (p->exprblock.vtype != TYCHAR)
556: goto standard;
557: q = p->exprblock.rightp;
558: if (!(q->tag == TEXPR &&
559: q->exprblock.opcode == OPCONCAT))
560: goto standard;
561: t = (Addrp) expand(p->exprblock.leftp);
562: frexpr(p->exprblock.vleng);
563: free( (charptr) p );
564: p = (tagptr) q;
565: goto cat;
566: case OPCONCAT:
567: t = mktemp (TYCHAR, ICON(lencat(p)));
568: cat:
569: q = (expptr) cpexpr (p->exprblock.vleng);
570: buffcat (cpexpr(t),p);
571: frexpr (t->vleng);
572: t->vleng = q;
573: p = (tagptr) t;
574: break;
575: case OPMIN:
576: case OPMAX:
577: p = (tagptr) buffmnmx (p);
578: break;
579: case OPPOWER:
580: p = (tagptr) buffpower (p);
581: break;
582: default:
583: standard:
584: p->exprblock.leftp =
585: expand (p->exprblock.leftp);
586: if (p->exprblock.rightp)
587: p->exprblock.rightp =
588: expand (p->exprblock.rightp);
589: break;
590: }
591: break;
592:
593: case TLIST:
594: {
595: chainp t;
596: for (t = p->listblock.listp; t; t = t->nextp)
597: t->datap = (tagptr) expand (t->datap);
598: }
599: break;
600:
601: case TTEMP:
602: if (p->tempblock.istemp)
603: frtemp(p);
604: break;
605:
606: case TADDR:
607: p->addrblock.memoffset = expand( p->addrblock.memoffset );
608: break;
609:
610: default:
611: break;
612: }
613: return ((expptr) p);
614: }
615:
616:
617:
618: /*
619: * local version of routine putcat in putpcc.c, called by expand
620: */
621:
622: LOCAL buffcat(lhs, rhs)
623: register Addrp lhs;
624: register expptr rhs;
625: {
626: int n;
627: Addrp lp, cp;
628:
629: n = ncat(rhs);
630: lp = (Addrp) mkaltmpn(n, TYLENG, PNULL);
631: cp = (Addrp) mkaltmpn(n, TYADDR, PNULL);
632:
633: n = 0;
634: buffct1(rhs, lp, cp, &n);
635:
636: optbuff (SKCALL, call4(TYSUBR, "s_cat", lhs, cp, lp, mkconv(TYLONG, ICON(n))),
637: 0, 0);
638: }
639:
640:
641:
642: /*
643: * local version of routine putct1 in putpcc.c, called by expand
644: */
645:
646: LOCAL buffct1(q, lp, cp, ip)
647: register expptr q;
648: register Addrp lp, cp;
649: int *ip;
650: {
651: int i;
652: Addrp lp1, cp1;
653:
654: if(q->tag==TEXPR && q->exprblock.opcode==OPCONCAT)
655: {
656: buffct1(q->exprblock.leftp, lp, cp, ip);
657: buffct1(q->exprblock.rightp, lp, cp, ip);
658: frexpr(q->exprblock.vleng);
659: free( (charptr) q );
660: }
661: else
662: {
663: i = (*ip)++;
664: lp1 = (Addrp) cpexpr(lp);
665: lp1->memoffset = mkexpr(OPPLUS,lp1->memoffset, ICON(i*SZLENG));
666: cp1 = (Addrp) cpexpr(cp);
667: cp1->memoffset = mkexpr(OPPLUS, cp1->memoffset, ICON(i*SZADDR));
668: optbuff (SKEQ, (mkexpr(OPASSIGN, lp1, cpexpr(q->headblock.vleng))),
669: 0,0);
670: optbuff (SKEQ, (mkexpr(OPASSIGN, cp1, addrof(expand (q)))), 0, 0);
671: }
672: }
673:
674:
675:
676: /*
677: * local version of routine putmnmx in putpcc.c, called by expand
678: */
679:
680: LOCAL expptr buffmnmx(p)
681: register expptr p;
682: {
683: int op, type;
684: expptr qp;
685: chainp p0, p1;
686: Addrp sp, tp;
687: Addrp newtemp;
688: expptr result, res;
689:
690: if(p->tag != TEXPR)
691: badtag("buffmnmx", p->tag);
692:
693: type = p->exprblock.vtype;
694: op = (p->exprblock.opcode==OPMIN ? OPLT : OPGT );
695: qp = expand(p->exprblock.leftp);
696: if(qp->tag != TLIST)
697: badtag("buffmnmx list", qp->tag);
698: p0 = qp->listblock.listp;
699: free( (charptr) qp );
700: free( (charptr) p );
701:
702: sp = mktemp(type, PNULL);
703: tp = mktemp(type, PNULL);
704: qp = mkexpr(OPCOLON, cpexpr(tp), cpexpr(sp));
705: qp = mkexpr(OPQUEST, mkexpr(op, cpexpr(tp),cpexpr(sp)), qp);
706: qp = fixexpr(qp);
707:
708: newtemp = mktemp (type,PNULL);
709:
710: result = res = mkexpr (OPCOMMA,
711: mkexpr( OPASSIGN, cpexpr(sp), p0->datap ), cpexpr(newtemp));
712:
713: for(p1 = p0->nextp ; p1 ; p1 = p1->nextp)
714: {
715: APPEND (mkexpr( OPASSIGN, cpexpr(tp), p1->datap ));
716: if(p1->nextp)
717: APPEND (mkexpr (OPASSIGN, cpexpr(sp), cpexpr(qp)) );
718: else
719: APPEND (mkexpr (OPASSIGN, cpexpr(newtemp), qp));
720: }
721:
722: frtemp(sp);
723: frtemp(tp);
724: frtemp(newtemp);
725: frchain( &p0 );
726:
727: return (result);
728: }
729:
730:
731:
732: /*
733: * Called by expand() to eliminate exponentiations to integer constants.
734: */
735: LOCAL expptr buffpower( p )
736: expptr p;
737: {
738: expptr base;
739: Addrp newtemp;
740: expptr storetemp = ENULL;
741: expptr powtree();
742: expptr result;
743: ftnint exp;
744:
745: if ( ! ISICON( p->exprblock.rightp ) )
746: fatal( "buffpower: bad non-integer exponent" );
747:
748: base = expand(p->exprblock.leftp);
749: exp = p->exprblock.rightp->constblock.const.ci;
750: if ( exp < 2 )
751: fatal( "buffpower: bad exponent less than 2" );
752:
753: if ( exp > 64 ) {
754: /*
755: * Let's be reasonable, here... Let putpower() do the job.
756: */
757: p->exprblock.leftp = base;
758: return ( p );
759: }
760:
761: /*
762: * If the base is not a simple variable, evaluate it and copy the
763: * result into a temporary.
764: */
765: if ( ! (base->tag == TADDR && ISCONST( base->addrblock.memoffset )) ) {
766: newtemp = mktemp( base->headblock.vtype, PNULL );
767: storetemp = mkexpr( OPASSIGN,
768: cpexpr( (expptr) newtemp ),
769: cpexpr( base ) );
770: base = (expptr) newtemp;
771: }
772:
773: result = powtree( base, exp );
774:
775: if ( storetemp != ENULL )
776: result = mkexpr( OPCOMMA, storetemp, result );
777: frexpr( p );
778:
779: return ( result );
780: }
781:
782:
783:
784: /*
785: * powtree( base, exp ) -- Create a tree of multiplications which computes
786: * base ** exp. The tree is built so that CSE will compact it if
787: * possible. The routine works by creating subtrees that compute
788: * exponents which are powers of two, then multiplying these
789: * together to get the result; this gives a log2( exp ) tree depth
790: * and lots of subexpressions which can be eliminated.
791: */
792: LOCAL expptr powtree( base, exp )
793: expptr base;
794: register ftnint exp;
795: {
796: register expptr r = ENULL, r1;
797: register int i;
798:
799: for ( i = 0; exp; ++i, exp >>= 1 )
800: if ( exp & 1 )
801: if ( i == 0 )
802: r = (expptr) cpexpr( base );
803: else {
804: r1 = powtree( base, 1 << (i - 1) );
805: r1 = mkexpr( OPSTAR, r1, cpexpr( r1 ) );
806: r = (r ? mkexpr( OPSTAR, r1, r ) : r1);
807: }
808:
809: return ( r );
810: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.