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