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