xref: /csrg-svn/usr.bin/f77/pass1.vax/optim.c (revision 47955)
1*47955Sbostic /*-
2*47955Sbostic  * Copyright (c) 1980 The Regents of the University of California.
3*47955Sbostic  * All rights reserved.
4*47955Sbostic  *
5*47955Sbostic  * %sccs.include.proprietary.c%
622851Smckusick  */
722851Smckusick 
822851Smckusick #ifndef lint
9*47955Sbostic static char sccsid[] = "@(#)optim.c	5.5 (Berkeley) 04/12/91";
10*47955Sbostic #endif /* not lint */
1122851Smckusick 
1222851Smckusick /*
1322851Smckusick  * optim.c
1422851Smckusick  *
1522851Smckusick  * Miscellaneous optimizer routines, f77 compiler pass 1.
1622851Smckusick  *
1722851Smckusick  * UCSD Chemistry modification history:
1822851Smckusick  *
1922851Smckusick  * $Log:	optim.c,v $
2026512Sdonn  * Revision 5.2  86/03/04  17:47:08  donn
2126512Sdonn  * Change buffcat() and buffct1() analogously to putcat and putct1() --
2226512Sdonn  * ensure that memoffset is evaluated before vleng.  Take care not to
2326512Sdonn  * screw up and return something other than an expression.
2426512Sdonn  *
2526512Sdonn  * Revision 5.1  85/08/10  03:48:42  donn
2626512Sdonn  * 4.3 alpha
2726512Sdonn  *
2823478Smckusick  * Revision 2.12  85/06/08  22:57:01  donn
2923478Smckusick  * Prevent core dumps -- bug in optinsert was causing lastslot to be wrong
3023478Smckusick  * when a slot was inserted at the end of the buffer.
3123478Smckusick  *
3222851Smckusick  * Revision 2.11  85/03/18  08:05:05  donn
3322851Smckusick  * Prevent warnings about implicit conversions.
3422851Smckusick  *
3522851Smckusick  * Revision 2.10  85/02/12  20:13:00  donn
3622851Smckusick  * Resurrected the hack in 2.6.1.1 to avoid creating a temporary when
3722851Smckusick  * there is a concatenation on the rhs of an assignment, and threw out
3822851Smckusick  * all the code dealing with starcat().  It seems that we can't use a
3922851Smckusick  * temporary because the lhs as well as the rhs may have nonconstant length.
4022851Smckusick  *
4122851Smckusick  * Revision 2.9  85/01/18  00:53:52  donn
4222851Smckusick  * Missed a call to free() in the last change...
4322851Smckusick  *
4422851Smckusick  * Revision 2.8  85/01/18  00:50:03  donn
4522851Smckusick  * Fixed goof made when modifying buffmnmx() to explicitly call expand().
4622851Smckusick  *
4722851Smckusick  * Revision 2.7  85/01/15  18:47:35  donn
4822851Smckusick  * Changes to allow character*(*) variables to appear in concatenations in
4922851Smckusick  * the rhs of an assignment statement.
5022851Smckusick  *
5122851Smckusick  * Revision 2.6  84/12/16  21:46:27  donn
5222851Smckusick  * Fixed bug that prevented concatenations from being run together.  Changed
5322851Smckusick  * buffpower() to not touch exponents greater than 64 -- let putpower do them.
5422851Smckusick  *
5522851Smckusick  * Revision 2.5  84/10/29  08:41:45  donn
5622851Smckusick  * Added hack to flushopt() to prevent the compiler from trying to generate
5722851Smckusick  * intermediate code after an error.
5822851Smckusick  *
5922851Smckusick  * Revision 2.4  84/08/07  21:28:00  donn
6022851Smckusick  * Removed call to p2flush() in putopt() -- this allows us to make better use
6122851Smckusick  * of the buffering on the intermediate code file.
6222851Smckusick  *
6322851Smckusick  * Revision 2.3  84/08/01  16:06:24  donn
6422851Smckusick  * Forced expand() to expand subscripts.
6522851Smckusick  *
6622851Smckusick  * Revision 2.2  84/07/19  20:21:55  donn
6722851Smckusick  * Decided I liked the expression tree algorithm after all.  The algorithm
6822851Smckusick  * which repeatedly squares temporaries is now checked in as rev. 2.1.
6922851Smckusick  *
7022851Smckusick  * Revision 1.3.1.1  84/07/10  14:18:18  donn
7122851Smckusick  * I'm taking this branch off the trunk -- it works but it's not as good as
7222851Smckusick  * the old version would be if it worked right.
7322851Smckusick  *
7422851Smckusick  * Revision 1.5  84/07/09  22:28:50  donn
7522851Smckusick  * Added fix to buffpower() to prevent it chasing after huge exponents.
7622851Smckusick  *
7722851Smckusick  * Revision 1.4  84/07/09  20:13:59  donn
7822851Smckusick  * Replaced buffpower() routine with a new one that generates trees which can
7922851Smckusick  * be handled by CSE later on.
8022851Smckusick  *
8122851Smckusick  * Revision 1.3  84/05/04  21:02:07  donn
8222851Smckusick  * Added fix for a bug in buffpower() that caused func(x)**2 to turn into
8322851Smckusick  * func(x) * func(x).  This bug had already been fixed in putpower()...
8422851Smckusick  *
8522851Smckusick  * Revision 1.2  84/03/23  22:47:21  donn
8622851Smckusick  * The subroutine argument temporary fixes from Bob Corbett didn't take into
8722851Smckusick  * account the fact that the code generator collects all the assignments to
8822851Smckusick  * temporaries at the start of a statement -- hence the temporaries need to
8922851Smckusick  * be initialized once per statement instead of once per call.
9022851Smckusick  *
9122851Smckusick  */
9222851Smckusick 
9322851Smckusick #include "defs.h"
9422851Smckusick #include "optim.h"
9522851Smckusick 
9622851Smckusick 
9722851Smckusick 
9822851Smckusick /*
9922851Smckusick  *		Information buffered for each slot type
10022851Smckusick  *
10122851Smckusick  *  slot type	       expptr	       integer		pointer
10222851Smckusick  *
10322851Smckusick  *  IFN			expr		label		-
10422851Smckusick  *  GOTO		-		label		-
10522851Smckusick  *  LABEL		-		label		-
10622851Smckusick  *  EQ			expr		-		-
10722851Smckusick  *  CALL		expr		-		-
10822851Smckusick  *  CMGOTO		expr		num		labellist*
10922851Smckusick  *  STOP		expr		-		-
11022851Smckusick  *  DOHEAD		[1]		-		ctlframe*
11122851Smckusick  *  ENDDO		[1]		-		ctlframe*
11222851Smckusick  *  ARIF		expr		-		labellist*
11322851Smckusick  *  RETURN		expr		label		-
11422851Smckusick  *  ASGOTO		expr		-		labellist*
11522851Smckusick  *  PAUSE		expr		-		-
11622851Smckusick  *  ASSIGN		expr		label		-
11722851Smckusick  *  SKIOIFN		expr		label		-
11822851Smckusick  *  SKFRTEMP		expr		-		-
11922851Smckusick  *
12022851Smckusick  *     Note [1]:  the nullslot field is a pointer to a fake slot which is
12122851Smckusick  *     at the end of the slots which may be replaced by this slot.  In
12222851Smckusick  *     other words, it looks like this:
12322851Smckusick  *		DOHEAD slot
12422851Smckusick  *		slot   \
12522851Smckusick  *		slot    > ordinary IF, GOTO, LABEL slots which implement the DO
12622851Smckusick  *		slot   /
12722851Smckusick  *		NULL slot
12822851Smckusick  */
12922851Smckusick 
13022851Smckusick 
13122851Smckusick expptr expand();
13222851Smckusick 
13322851Smckusick Slotp	firstslot = NULL;
13422851Smckusick Slotp	lastslot = NULL;
13522851Smckusick int	numslots = 0;
13622851Smckusick 
13722851Smckusick 
13822851Smckusick /*
13922851Smckusick  *  turns off optimization option
14022851Smckusick  */
14122851Smckusick 
optoff()14222851Smckusick optoff()
14322851Smckusick 
14422851Smckusick {
14522851Smckusick flushopt();
14622851Smckusick optimflag = 0;
14722851Smckusick }
14822851Smckusick 
14922851Smckusick 
15022851Smckusick 
15122851Smckusick /*
15222851Smckusick  *  initializes the code buffer for optimization
15322851Smckusick  */
15422851Smckusick 
setopt()15522851Smckusick setopt()
15622851Smckusick 
15722851Smckusick {
15822851Smckusick register Slotp sp;
15922851Smckusick 
16022851Smckusick for (sp = firstslot; sp; sp = sp->next)
16122851Smckusick 	free ( (charptr) sp);
16222851Smckusick firstslot = lastslot = NULL;
16322851Smckusick numslots = 0;
16422851Smckusick }
16522851Smckusick 
16622851Smckusick 
16722851Smckusick 
16822851Smckusick /*
16922851Smckusick  *  flushes the code buffer
17022851Smckusick  */
17122851Smckusick 
17222851Smckusick LOCAL int alreadycalled = 0;
17322851Smckusick 
flushopt()17422851Smckusick flushopt()
17522851Smckusick {
17622851Smckusick register Slotp sp;
17722851Smckusick int savelineno;
17822851Smckusick 
17922851Smckusick if (alreadycalled) return;	/* to prevent recursive call during errors */
18022851Smckusick alreadycalled = 1;
18122851Smckusick 
18222851Smckusick if (debugflag[1])
18322851Smckusick 	showbuffer ();
18422851Smckusick 
18522851Smckusick frtempbuff ();
18622851Smckusick 
18722851Smckusick savelineno = lineno;
18822851Smckusick for (sp = firstslot; sp; sp = sp->next)
18922851Smckusick 	{
19022851Smckusick 	if (nerr == 0)
19122851Smckusick 		putopt (sp);
19222851Smckusick 	else
19322851Smckusick 		frexpr (sp->expr);
19422851Smckusick         if(sp->ctlinfo) free ( (charptr) sp->ctlinfo);
19522851Smckusick         free ( (charptr) sp);
19622851Smckusick         numslots--;
19722851Smckusick 	}
19822851Smckusick firstslot = lastslot = NULL;
19922851Smckusick numslots = 0;
20022851Smckusick clearbb();
20122851Smckusick lineno = savelineno;
20222851Smckusick 
20322851Smckusick alreadycalled = 0;
20422851Smckusick }
20522851Smckusick 
20622851Smckusick 
20722851Smckusick 
20822851Smckusick /*
20922851Smckusick  *  puts out code for the given slot (from the code buffer)
21022851Smckusick  */
21122851Smckusick 
putopt(sp)21222851Smckusick LOCAL putopt (sp)
21322851Smckusick register Slotp sp;
21422851Smckusick {
21522851Smckusick 	lineno = sp->lineno;
21622851Smckusick 	switch (sp->type) {
21722851Smckusick 	    case SKNULL:
21822851Smckusick 		break;
21922851Smckusick 	    case SKIFN:
22022851Smckusick 	    case SKIOIFN:
22122851Smckusick 		putif(sp->expr, sp->label);
22222851Smckusick 		break;
22322851Smckusick 	    case SKGOTO:
22422851Smckusick 		putgoto(sp->label);
22522851Smckusick 		break;
22622851Smckusick 	    case SKCMGOTO:
22722851Smckusick 		putcmgo(sp->expr, sp->label, sp->ctlinfo);
22822851Smckusick 		break;
22922851Smckusick 	    case SKCALL:
23022851Smckusick 		putexpr(sp->expr);
23122851Smckusick 		break;
23222851Smckusick 	    case SKSTOP:
23322851Smckusick 		putexpr (call1 (TYSUBR, "s_stop", sp->expr));
23422851Smckusick 		break;
23522851Smckusick 	    case SKPAUSE:
23622851Smckusick 		putexpr (call1 (TYSUBR, "s_paus", sp->expr));
23722851Smckusick 		break;
23822851Smckusick 	    case SKASSIGN:
23922851Smckusick 		puteq (sp->expr,
24022851Smckusick 		    intrconv(sp->expr->headblock.vtype, mkaddcon(sp->label)));
24122851Smckusick 		break;
24222851Smckusick 	    case SKDOHEAD:
24322851Smckusick 	    case SKENDDO:
24422851Smckusick 		break;
24522851Smckusick 	    case SKEQ:
24622851Smckusick 		putexpr(sp->expr);
24722851Smckusick 		break;
24822851Smckusick 	    case SKARIF:
24922851Smckusick #define LM   ((struct Labelblock * *)sp->ctlinfo)[0]->labelno
25022851Smckusick #define LZ   ((struct Labelblock * *)sp->ctlinfo)[1]->labelno
25122851Smckusick #define LP   ((struct Labelblock * *)sp->ctlinfo)[2]->labelno
25222851Smckusick        		prarif(sp->expr, LM, LZ, LP);
25322851Smckusick 		break;
25422851Smckusick 	    case SKASGOTO:
25522851Smckusick 		putbranch((Addrp) sp->expr);
25622851Smckusick 		break;
25722851Smckusick 	    case SKLABEL:
25822851Smckusick 		putlabel(sp->label);
25922851Smckusick 		break;
26022851Smckusick 	    case SKRETURN:
26122851Smckusick 		if (sp->expr)
26222851Smckusick 			{
26322851Smckusick 			putforce(TYINT, sp->expr);
26422851Smckusick 			putgoto(sp->label);
26522851Smckusick 			}
26622851Smckusick 		else
26722851Smckusick 			putgoto(sp->label);
26822851Smckusick 		break;
26922851Smckusick 	    case SKFRTEMP:
27022851Smckusick 		templist = mkchain (sp->expr,templist);
27122851Smckusick 		break;
27222851Smckusick 	    default:
27322851Smckusick 		badthing("SKtype", "putopt", sp->type);
27422851Smckusick 		break;
27522851Smckusick 	}
27622851Smckusick 
27722851Smckusick 	/*
27822851Smckusick 	 * Recycle argument temporaries here.  This must get done on a
27922851Smckusick 	 *	statement-by-statement basis because the code generator
28022851Smckusick 	 *	makes side effects happen at the start of a statement.
28122851Smckusick 	 */
28222851Smckusick 	argtemplist = hookup(argtemplist, activearglist);
28322851Smckusick 	activearglist = CHNULL;
28422851Smckusick }
28522851Smckusick 
28622851Smckusick 
28722851Smckusick 
28822851Smckusick /*
28922851Smckusick  *  copies one element of the control stack
29022851Smckusick  */
29122851Smckusick 
cpframe(p)29222851Smckusick LOCAL struct Ctlframe *cpframe(p)
29322851Smckusick register char *p;
29422851Smckusick {
29522851Smckusick static int size =  sizeof (struct Ctlframe);
29622851Smckusick register int n;
29722851Smckusick register char *q;
29822851Smckusick struct Ctlframe *q0;
29922851Smckusick 
30022851Smckusick q0 = ALLOC(Ctlframe);
30122851Smckusick q = (char *) q0;
30222851Smckusick n = size;
30322851Smckusick while(n-- > 0)
30422851Smckusick 	*q++ = *p++;
30522851Smckusick return( q0);
30622851Smckusick }
30722851Smckusick 
30822851Smckusick 
30922851Smckusick 
31022851Smckusick /*
31122851Smckusick  *  copies an array of labelblock pointers
31222851Smckusick  */
31322851Smckusick 
cplabarr(n,arr)31422851Smckusick LOCAL struct Labelblock **cplabarr(n,arr)
31522851Smckusick struct Labelblock *arr[];
31622851Smckusick int n;
31722851Smckusick {
31822851Smckusick struct Labelblock **newarr;
31922851Smckusick register char *in, *out;
32022851Smckusick register int i,j;
32122851Smckusick 
32222851Smckusick newarr = (struct Labelblock **) ckalloc (n * sizeof (char *));
32322851Smckusick for (i = 0; i < n; i++)
32422851Smckusick 	{
32522851Smckusick 	newarr[i] = ALLOC (Labelblock);
32622851Smckusick 	out = (char *) newarr[i];
32722851Smckusick 	in = (char *) arr[i];
32822851Smckusick 	j = sizeof (struct Labelblock);
32922851Smckusick 	while (j-- > 0)
33022851Smckusick 		*out++ = *in++;
33122851Smckusick 	}
33222851Smckusick return (newarr);
33322851Smckusick }
33422851Smckusick 
33522851Smckusick 
33622851Smckusick 
33722851Smckusick /*
33822851Smckusick  *  creates a new slot in the code buffer
33922851Smckusick  */
34022851Smckusick 
newslot()34122851Smckusick LOCAL Slotp newslot()
34222851Smckusick {
34322851Smckusick register Slotp sp;
34422851Smckusick 
34522851Smckusick ++numslots;
34622851Smckusick sp = ALLOC( slt );
34722851Smckusick sp->next = NULL ;
34822851Smckusick if (lastslot)
34922851Smckusick 	{
35022851Smckusick 	sp->prev = lastslot;
35122851Smckusick 	lastslot = lastslot->next = sp;
35222851Smckusick 	}
35322851Smckusick else
35422851Smckusick 	{
35522851Smckusick 	firstslot = lastslot = sp;
35622851Smckusick 	sp->prev = NULL;
35722851Smckusick 	}
35822851Smckusick sp->lineno = lineno;
35922851Smckusick return (sp);
36022851Smckusick }
36122851Smckusick 
36222851Smckusick 
36322851Smckusick 
36422851Smckusick /*
36522851Smckusick  *  removes (but not deletes) the specified slot from the code buffer
36622851Smckusick  */
36722851Smckusick 
removeslot(sl)36822851Smckusick removeslot (sl)
36922851Smckusick Slotp	sl;
37022851Smckusick 
37122851Smckusick {
37222851Smckusick if (sl->next)
37322851Smckusick 	sl->next->prev = sl->prev;
37422851Smckusick else
37522851Smckusick 	lastslot = sl->prev;
37622851Smckusick if (sl->prev)
37722851Smckusick 	sl->prev->next = sl->next;
37822851Smckusick else
37922851Smckusick 	firstslot = sl->next;
38022851Smckusick sl->next = sl->prev = NULL;
38122851Smckusick 
38222851Smckusick --numslots;
38322851Smckusick }
38422851Smckusick 
38522851Smckusick 
38622851Smckusick 
38722851Smckusick /*
38822851Smckusick  *  inserts slot s1 before existing slot s2 in the code buffer;
38922851Smckusick  *  appends to end of list if s2 is NULL.
39022851Smckusick  */
39122851Smckusick 
insertslot(s1,s2)39222851Smckusick insertslot (s1,s2)
39322851Smckusick Slotp	s1,s2;
39422851Smckusick 
39522851Smckusick {
39622851Smckusick if (s2)
39722851Smckusick 	{
39822851Smckusick 	if (s2->prev)
39922851Smckusick 		s2->prev->next = s1;
40022851Smckusick 	else
40122851Smckusick 		firstslot = s1;
40222851Smckusick 	s1->prev = s2->prev;
40322851Smckusick 	s2->prev = s1;
40422851Smckusick 	}
40522851Smckusick else
40622851Smckusick 	{
40722851Smckusick 	s1->prev = lastslot;
40822851Smckusick 	lastslot->next = s1;
40922851Smckusick 	lastslot = s1;
41022851Smckusick 	}
41122851Smckusick s1->next = s2;
41222851Smckusick 
41322851Smckusick ++numslots;
41422851Smckusick }
41522851Smckusick 
41622851Smckusick 
41722851Smckusick 
41822851Smckusick /*
41922851Smckusick  *  deletes the specified slot from the code buffer
42022851Smckusick  */
42122851Smckusick 
delslot(sl)42222851Smckusick delslot (sl)
42322851Smckusick Slotp	sl;
42422851Smckusick 
42522851Smckusick {
42622851Smckusick removeslot (sl);
42722851Smckusick 
42822851Smckusick if (sl->ctlinfo)
42922851Smckusick 	free ((charptr) sl->ctlinfo);
43022851Smckusick frexpr (sl->expr);
43122851Smckusick free ((charptr) sl);
43222851Smckusick numslots--;
43322851Smckusick }
43422851Smckusick 
43522851Smckusick 
43622851Smckusick 
43722851Smckusick /*
43822851Smckusick  *  inserts a slot before the specified slot; if given NULL, it is
43922851Smckusick  *  inserted at the end of the buffer
44022851Smckusick  */
44122851Smckusick 
optinsert(type,p,l,c,currslot)44222851Smckusick Slotp optinsert (type,p,l,c,currslot)
44322851Smckusick int	type;
44422851Smckusick expptr	p;
44522851Smckusick int	l;
44622851Smckusick int	*c;
44722851Smckusick Slotp	currslot;
44822851Smckusick 
44922851Smckusick {
45022851Smckusick Slotp	savelast,new;
45122851Smckusick 
45222851Smckusick savelast = lastslot;
45322851Smckusick if (currslot)
45422851Smckusick 	lastslot = currslot->prev;
45522851Smckusick new = optbuff (type,p,l,c);
45622851Smckusick new->next = currslot;
45722851Smckusick if (currslot)
45822851Smckusick 	currslot->prev = new;
45922851Smckusick new->lineno = -1;	/* who knows what the line number should be ??!! */
46023478Smckusick if (currslot)
46123478Smckusick 	lastslot = savelast;
46222851Smckusick return (new);
46322851Smckusick }
46422851Smckusick 
46522851Smckusick 
46622851Smckusick 
46722851Smckusick /*
46822851Smckusick  *  buffers the FRTEMP slots which have been waiting
46922851Smckusick  */
47022851Smckusick 
frtempbuff()47122851Smckusick frtempbuff ()
47222851Smckusick 
47322851Smckusick {
47422851Smckusick chainp ht;
47522851Smckusick register Slotp sp;
47622851Smckusick 
47722851Smckusick for (ht = holdtemps; ht; ht = ht->nextp)
47822851Smckusick 	{
47922851Smckusick 	sp = newslot();
48022851Smckusick 		/* this slot actually belongs to some previous source line */
48122851Smckusick 	sp->lineno = sp->lineno - 1;
48222851Smckusick 	sp->type = SKFRTEMP;
48322851Smckusick 	sp->expr = (expptr) ht->datap;
48422851Smckusick 	sp->label = 0;
48522851Smckusick 	sp->ctlinfo = NULL;
48622851Smckusick 	}
48722851Smckusick holdtemps = NULL;
48822851Smckusick }
48922851Smckusick 
49022851Smckusick 
49122851Smckusick 
49222851Smckusick /*
49322851Smckusick  *  puts the given information into a slot at the end of the code buffer
49422851Smckusick  */
49522851Smckusick 
optbuff(type,p,l,c)49622851Smckusick Slotp optbuff (type,p,l,c)
49722851Smckusick int	type;
49822851Smckusick expptr	p;
49922851Smckusick int	l;
50022851Smckusick int	*c;
50122851Smckusick 
50222851Smckusick {
50322851Smckusick register Slotp sp;
50422851Smckusick 
50522851Smckusick if (debugflag[1])
50622851Smckusick 	{
50722851Smckusick 	fprintf (diagfile,"-----optbuff-----"); showslottype (type);
50822851Smckusick 	showexpr (p,0); fprintf (diagfile,"\n");
50922851Smckusick 	}
51022851Smckusick 
51122851Smckusick p = expand (p);
51222851Smckusick sp = newslot();
51322851Smckusick sp->type = type;
51422851Smckusick sp->expr = p;
51522851Smckusick sp->label = l;
51622851Smckusick sp->ctlinfo = NULL;
51722851Smckusick switch (type)
51822851Smckusick 	{
51922851Smckusick 	case SKCMGOTO:
52022851Smckusick 		sp->ctlinfo = (int*) cplabarr (l, (struct Labelblock**) c);
52122851Smckusick 		break;
52222851Smckusick 	case SKARIF:
52322851Smckusick 		sp->ctlinfo = (int*) cplabarr (3, (struct Labelblock**) c);
52422851Smckusick 		break;
52522851Smckusick 	case SKDOHEAD:
52622851Smckusick 	case SKENDDO:
52722851Smckusick 		sp->ctlinfo = (int*) cpframe ((struct Ctlframe*) c);
52822851Smckusick 		break;
52922851Smckusick 	default:
53022851Smckusick 		break;
53122851Smckusick 	}
53222851Smckusick 
53322851Smckusick frtempbuff ();
53422851Smckusick 
53522851Smckusick return (sp);
53622851Smckusick }
53722851Smckusick 
53822851Smckusick 
53922851Smckusick 
54022851Smckusick /*
54122851Smckusick  *  expands the given expression, if possible (e.g., concat, min, max, etc.);
54222851Smckusick  *  also frees temporaries when they are indicated as being the last use
54322851Smckusick  */
54422851Smckusick 
54522851Smckusick #define APPEND(z)	\
54622851Smckusick 	res = res->exprblock.rightp = mkexpr (OPCOMMA, z, newtemp)
54722851Smckusick 
expand(p)54822851Smckusick LOCAL expptr expand (p)
54922851Smckusick tagptr p;
55022851Smckusick 
55122851Smckusick {
55222851Smckusick Addrp t;
55322851Smckusick expptr q;
55426512Sdonn expptr buffmnmx(), buffpower(), buffcat();
55522851Smckusick 
55622851Smckusick if (!p)
55722851Smckusick 	return (ENULL);
55822851Smckusick switch (p->tag)
55922851Smckusick 	{
56022851Smckusick 	case TEXPR:
56122851Smckusick 		switch (p->exprblock.opcode)
56222851Smckusick 			{
56322851Smckusick 			case OPASSIGN: /* handle a = b // c */
56422851Smckusick 				if (p->exprblock.vtype != TYCHAR)
56522851Smckusick 					goto standard;
56622851Smckusick 				q = p->exprblock.rightp;
56722851Smckusick 				if (!(q->tag == TEXPR &&
56822851Smckusick 				      q->exprblock.opcode == OPCONCAT))
56922851Smckusick 					goto standard;
57022851Smckusick 				t = (Addrp) expand(p->exprblock.leftp);
57122851Smckusick 				frexpr(p->exprblock.vleng);
57222851Smckusick 				free( (charptr) p );
57322851Smckusick 				p = (tagptr) q;
57422851Smckusick 				goto cat;
57522851Smckusick 			case OPCONCAT:
57622851Smckusick 				t = mktemp (TYCHAR, ICON(lencat(p)));
57722851Smckusick 			cat:
57822851Smckusick 				q = (expptr) cpexpr (p->exprblock.vleng);
57926512Sdonn 				p = (tagptr) buffcat (t, p);
58026512Sdonn 				frexpr (p->headblock.vleng);
58126512Sdonn 				p->headblock.vleng = q;
58222851Smckusick 				break;
58322851Smckusick 			case OPMIN:
58422851Smckusick 			case OPMAX:
58522851Smckusick 				p = (tagptr) buffmnmx (p);
58622851Smckusick 				break;
58722851Smckusick 			case OPPOWER:
58822851Smckusick 				p = (tagptr) buffpower (p);
58922851Smckusick 				break;
59022851Smckusick 			default:
59122851Smckusick 			standard:
59222851Smckusick 				p->exprblock.leftp =
59322851Smckusick 					expand (p->exprblock.leftp);
59422851Smckusick 				if (p->exprblock.rightp)
59522851Smckusick 					p->exprblock.rightp =
59622851Smckusick 						expand (p->exprblock.rightp);
59722851Smckusick 				break;
59822851Smckusick 			}
59922851Smckusick 		break;
60022851Smckusick 
60122851Smckusick 	case TLIST:
60222851Smckusick 		{
60322851Smckusick 		chainp t;
60422851Smckusick 		for (t = p->listblock.listp; t; t = t->nextp)
60522851Smckusick 			t->datap = (tagptr) expand (t->datap);
60622851Smckusick 		}
60722851Smckusick 		break;
60822851Smckusick 
60922851Smckusick 	case TTEMP:
61022851Smckusick 		if (p->tempblock.istemp)
61122851Smckusick 			frtemp(p);
61222851Smckusick 		break;
61322851Smckusick 
61422851Smckusick 	case TADDR:
61522851Smckusick 		p->addrblock.memoffset = expand( p->addrblock.memoffset );
61622851Smckusick 		break;
61722851Smckusick 
61822851Smckusick 	default:
61922851Smckusick 		break;
62022851Smckusick 	}
62122851Smckusick return ((expptr) p);
62222851Smckusick }
62322851Smckusick 
62422851Smckusick 
62522851Smckusick 
62622851Smckusick /*
62722851Smckusick  *  local version of routine putcat in putpcc.c, called by expand
62822851Smckusick  */
62922851Smckusick 
buffcat(lhs,rhs)63026512Sdonn LOCAL expptr buffcat(lhs, rhs)
63122851Smckusick register Addrp lhs;
63222851Smckusick register expptr rhs;
63322851Smckusick {
63422851Smckusick int n;
63522851Smckusick Addrp lp, cp;
63626512Sdonn expptr ep, buffct1();
63722851Smckusick 
63822851Smckusick n = ncat(rhs);
63922851Smckusick lp = (Addrp) mkaltmpn(n, TYLENG, PNULL);
64022851Smckusick cp = (Addrp) mkaltmpn(n, TYADDR, PNULL);
64122851Smckusick 
64222851Smckusick n = 0;
64326512Sdonn ep = buffct1(rhs, lp, cp, &n);
64422851Smckusick 
64526512Sdonn ep = mkexpr(OPCOMMA, ep,
64626512Sdonn 	call4(TYSUBR, "s_cat", lhs, cp, lp, mkconv(TYLONG, ICON(n))));
64726512Sdonn 
64826512Sdonn return (ep);
64922851Smckusick }
65022851Smckusick 
65122851Smckusick 
65222851Smckusick 
65322851Smckusick /*
65422851Smckusick  *  local version of routine putct1 in putpcc.c, called by expand
65522851Smckusick  */
65622851Smckusick 
buffct1(q,lp,cp,ip)65726512Sdonn LOCAL expptr buffct1(q, lp, cp, ip)
65822851Smckusick register expptr q;
65922851Smckusick register Addrp lp, cp;
66022851Smckusick int *ip;
66122851Smckusick {
66222851Smckusick int i;
66322851Smckusick Addrp lp1, cp1;
66426512Sdonn expptr eleft, eright;
66522851Smckusick 
66622851Smckusick if(q->tag==TEXPR && q->exprblock.opcode==OPCONCAT)
66722851Smckusick 	{
66826512Sdonn 	eleft = buffct1(q->exprblock.leftp, lp, cp, ip);
66926512Sdonn 	eright = buffct1(q->exprblock.rightp, lp, cp, ip);
67022851Smckusick 	frexpr(q->exprblock.vleng);
67122851Smckusick 	free( (charptr) q );
67222851Smckusick 	}
67322851Smckusick else
67422851Smckusick 	{
67522851Smckusick 	i = (*ip)++;
67622851Smckusick 	cp1 = (Addrp) cpexpr(cp);
67722851Smckusick 	cp1->memoffset = mkexpr(OPPLUS, cp1->memoffset, ICON(i*SZADDR));
67826512Sdonn 	lp1 = (Addrp) cpexpr(lp);
67926512Sdonn 	lp1->memoffset = mkexpr(OPPLUS, lp1->memoffset, ICON(i*SZLENG));
68026512Sdonn 	eleft = mkexpr(OPASSIGN, cp1, addrof(expand(cpexpr(q))));
68126512Sdonn 	eright = mkexpr(OPASSIGN, lp1, cpexpr(q->headblock.vleng));
68226512Sdonn 	frexpr(q);
68322851Smckusick 	}
68426512Sdonn return (mkexpr(OPCOMMA, eleft, eright));
68522851Smckusick }
68622851Smckusick 
68722851Smckusick 
68822851Smckusick 
68922851Smckusick /*
69022851Smckusick  *  local version of routine putmnmx in putpcc.c, called by expand
69122851Smckusick  */
69222851Smckusick 
buffmnmx(p)69322851Smckusick LOCAL expptr buffmnmx(p)
69422851Smckusick register expptr p;
69522851Smckusick {
69622851Smckusick int op, type;
69722851Smckusick expptr qp;
69822851Smckusick chainp p0, p1;
69922851Smckusick Addrp sp, tp;
70022851Smckusick Addrp newtemp;
70122851Smckusick expptr result, res;
70222851Smckusick 
70322851Smckusick if(p->tag != TEXPR)
70422851Smckusick 	badtag("buffmnmx", p->tag);
70522851Smckusick 
70622851Smckusick type = p->exprblock.vtype;
70722851Smckusick op = (p->exprblock.opcode==OPMIN ? OPLT : OPGT );
70822851Smckusick qp = expand(p->exprblock.leftp);
70922851Smckusick if(qp->tag != TLIST)
71022851Smckusick 	badtag("buffmnmx list", qp->tag);
71122851Smckusick p0 = qp->listblock.listp;
71222851Smckusick free( (charptr) qp );
71322851Smckusick free( (charptr) p );
71422851Smckusick 
71522851Smckusick sp = mktemp(type, PNULL);
71622851Smckusick tp = mktemp(type, PNULL);
71722851Smckusick qp = mkexpr(OPCOLON, cpexpr(tp), cpexpr(sp));
71822851Smckusick qp = mkexpr(OPQUEST, mkexpr(op, cpexpr(tp),cpexpr(sp)), qp);
71922851Smckusick qp = fixexpr(qp);
72022851Smckusick 
72122851Smckusick newtemp = mktemp (type,PNULL);
72222851Smckusick 
72322851Smckusick result = res = mkexpr (OPCOMMA,
72422851Smckusick 	mkexpr( OPASSIGN, cpexpr(sp), p0->datap ), cpexpr(newtemp));
72522851Smckusick 
72622851Smckusick for(p1 = p0->nextp ; p1 ; p1 = p1->nextp)
72722851Smckusick 	{
72822851Smckusick 	APPEND (mkexpr( OPASSIGN, cpexpr(tp), p1->datap ));
72922851Smckusick 	if(p1->nextp)
73022851Smckusick 		APPEND (mkexpr (OPASSIGN, cpexpr(sp), cpexpr(qp)) );
73122851Smckusick 	else
73222851Smckusick 		APPEND (mkexpr (OPASSIGN, cpexpr(newtemp), qp));
73322851Smckusick 	}
73422851Smckusick 
73522851Smckusick frtemp(sp);
73622851Smckusick frtemp(tp);
73722851Smckusick frtemp(newtemp);
73822851Smckusick frchain( &p0 );
73922851Smckusick 
74022851Smckusick return (result);
74122851Smckusick }
74222851Smckusick 
74322851Smckusick 
74422851Smckusick 
74522851Smckusick /*
74622851Smckusick  * Called by expand() to eliminate exponentiations to integer constants.
74722851Smckusick  */
buffpower(p)74822851Smckusick LOCAL expptr buffpower( p )
74922851Smckusick 	expptr p;
75022851Smckusick {
75122851Smckusick 	expptr base;
75222851Smckusick 	Addrp newtemp;
75322851Smckusick 	expptr storetemp = ENULL;
75422851Smckusick 	expptr powtree();
75522851Smckusick 	expptr result;
75622851Smckusick 	ftnint exp;
75722851Smckusick 
75822851Smckusick 	if ( ! ISICON( p->exprblock.rightp ) )
75922851Smckusick 		fatal( "buffpower: bad non-integer exponent" );
76022851Smckusick 
76122851Smckusick 	base = expand(p->exprblock.leftp);
76233257Sbostic 	exp = p->exprblock.rightp->constblock.constant.ci;
76322851Smckusick 	if ( exp < 2 )
76422851Smckusick 		fatal( "buffpower: bad exponent less than 2" );
76522851Smckusick 
76622851Smckusick 	if ( exp > 64 ) {
76722851Smckusick 		/*
76822851Smckusick 		 * Let's be reasonable, here...  Let putpower() do the job.
76922851Smckusick 		 */
77022851Smckusick 		p->exprblock.leftp = base;
77122851Smckusick 		return ( p );
77222851Smckusick 	}
77322851Smckusick 
77422851Smckusick 	/*
77522851Smckusick 	 * If the base is not a simple variable, evaluate it and copy the
77622851Smckusick 	 *	result into a temporary.
77722851Smckusick 	 */
77822851Smckusick 	if ( ! (base->tag == TADDR && ISCONST( base->addrblock.memoffset )) ) {
77922851Smckusick 		newtemp = mktemp( base->headblock.vtype, PNULL );
78022851Smckusick 		storetemp = mkexpr( OPASSIGN,
78122851Smckusick 			      cpexpr( (expptr) newtemp ),
78222851Smckusick 			      cpexpr( base ) );
78322851Smckusick 		base = (expptr) newtemp;
78422851Smckusick 	}
78522851Smckusick 
78622851Smckusick 	result = powtree( base, exp );
78722851Smckusick 
78822851Smckusick 	if ( storetemp != ENULL )
78922851Smckusick 		result = mkexpr( OPCOMMA, storetemp, result );
79022851Smckusick 	frexpr( p );
79122851Smckusick 
79222851Smckusick 	return ( result );
79322851Smckusick }
79422851Smckusick 
79522851Smckusick 
79622851Smckusick 
79722851Smckusick /*
79822851Smckusick  * powtree( base, exp ) -- Create a tree of multiplications which computes
79922851Smckusick  *	base ** exp.  The tree is built so that CSE will compact it if
80022851Smckusick  *	possible.  The routine works by creating subtrees that compute
80122851Smckusick  *	exponents which are powers of two, then multiplying these
80222851Smckusick  *	together to get the result; this gives a log2( exp ) tree depth
80322851Smckusick  *	and lots of subexpressions which can be eliminated.
80422851Smckusick  */
powtree(base,exp)80522851Smckusick LOCAL expptr powtree( base, exp )
80622851Smckusick 	expptr base;
80722851Smckusick 	register ftnint exp;
80822851Smckusick {
80922851Smckusick 	register expptr r = ENULL, r1;
81022851Smckusick 	register int i;
81122851Smckusick 
81222851Smckusick 	for ( i = 0; exp; ++i, exp >>= 1 )
81322851Smckusick 		if ( exp & 1 )
81422851Smckusick 			if ( i == 0 )
81522851Smckusick 				r = (expptr) cpexpr( base );
81622851Smckusick 			else {
81722851Smckusick 				r1 = powtree( base, 1 << (i - 1) );
81822851Smckusick 				r1 = mkexpr( OPSTAR, r1, cpexpr( r1 ) );
81922851Smckusick 				r = (r ? mkexpr( OPSTAR, r1, r ) : r1);
82022851Smckusick 			}
82122851Smckusick 
82222851Smckusick 	return ( r );
82322851Smckusick }
824