1*47951Sbostic /*-
2*47951Sbostic  * Copyright (c) 1980 The Regents of the University of California.
3*47951Sbostic  * All rights reserved.
4*47951Sbostic  *
5*47951Sbostic  * %sccs.include.proprietary.c%
643217Sbostic  */
743217Sbostic 
843217Sbostic #ifndef lint
9*47951Sbostic static char sccsid[] = "@(#)optim.c	5.3 (Berkeley) 04/12/91";
10*47951Sbostic #endif /* not lint */
1143217Sbostic 
1243217Sbostic /*
1343217Sbostic  * optim.c
1443217Sbostic  *
1543217Sbostic  * Miscellaneous optimizer routines, f77 compiler pass 1.
1643217Sbostic  *
1743217Sbostic  * UCSD Chemistry modification history:
1843217Sbostic  *
1943217Sbostic  * $Log:	optim.c,v $
2043217Sbostic  * Revision 2.12  85/06/08  22:57:01  donn
2143217Sbostic  * Prevent core dumps -- bug in optinsert was causing lastslot to be wrong
2243217Sbostic  * when a slot was inserted at the end of the buffer.
2343217Sbostic  *
2443217Sbostic  * Revision 2.11  85/03/18  08:05:05  donn
2543217Sbostic  * Prevent warnings about implicit conversions.
2643217Sbostic  *
2743217Sbostic  * Revision 2.10  85/02/12  20:13:00  donn
2843217Sbostic  * Resurrected the hack in 2.6.1.1 to avoid creating a temporary when
2943217Sbostic  * there is a concatenation on the rhs of an assignment, and threw out
3043217Sbostic  * all the code dealing with starcat().  It seems that we can't use a
3143217Sbostic  * temporary because the lhs as well as the rhs may have nonconstant length.
3243217Sbostic  *
3343217Sbostic  * Revision 2.9  85/01/18  00:53:52  donn
3443217Sbostic  * Missed a call to free() in the last change...
3543217Sbostic  *
3643217Sbostic  * Revision 2.8  85/01/18  00:50:03  donn
3743217Sbostic  * Fixed goof made when modifying buffmnmx() to explicitly call expand().
3843217Sbostic  *
3943217Sbostic  * Revision 2.7  85/01/15  18:47:35  donn
4043217Sbostic  * Changes to allow character*(*) variables to appear in concatenations in
4143217Sbostic  * the rhs of an assignment statement.
4243217Sbostic  *
4343217Sbostic  * Revision 2.6  84/12/16  21:46:27  donn
4443217Sbostic  * Fixed bug that prevented concatenations from being run together.  Changed
4543217Sbostic  * buffpower() to not touch exponents greater than 64 -- let putpower do them.
4643217Sbostic  *
4743217Sbostic  * Revision 2.5  84/10/29  08:41:45  donn
4843217Sbostic  * Added hack to flushopt() to prevent the compiler from trying to generate
4943217Sbostic  * intermediate code after an error.
5043217Sbostic  *
5143217Sbostic  * Revision 2.4  84/08/07  21:28:00  donn
5243217Sbostic  * Removed call to p2flush() in putopt() -- this allows us to make better use
5343217Sbostic  * of the buffering on the intermediate code file.
5443217Sbostic  *
5543217Sbostic  * Revision 2.3  84/08/01  16:06:24  donn
5643217Sbostic  * Forced expand() to expand subscripts.
5743217Sbostic  *
5843217Sbostic  * Revision 2.2  84/07/19  20:21:55  donn
5943217Sbostic  * Decided I liked the expression tree algorithm after all.  The algorithm
6043217Sbostic  * which repeatedly squares temporaries is now checked in as rev. 2.1.
6143217Sbostic  *
6243217Sbostic  * Revision 1.3.1.1  84/07/10  14:18:18  donn
6343217Sbostic  * I'm taking this branch off the trunk -- it works but it's not as good as
6443217Sbostic  * the old version would be if it worked right.
6543217Sbostic  *
6643217Sbostic  * Revision 1.5  84/07/09  22:28:50  donn
6743217Sbostic  * Added fix to buffpower() to prevent it chasing after huge exponents.
6843217Sbostic  *
6943217Sbostic  * Revision 1.4  84/07/09  20:13:59  donn
7043217Sbostic  * Replaced buffpower() routine with a new one that generates trees which can
7143217Sbostic  * be handled by CSE later on.
7243217Sbostic  *
7343217Sbostic  * Revision 1.3  84/05/04  21:02:07  donn
7443217Sbostic  * Added fix for a bug in buffpower() that caused func(x)**2 to turn into
7543217Sbostic  * func(x) * func(x).  This bug had already been fixed in putpower()...
7643217Sbostic  *
7743217Sbostic  * Revision 1.2  84/03/23  22:47:21  donn
7843217Sbostic  * The subroutine argument temporary fixes from Bob Corbett didn't take into
7943217Sbostic  * account the fact that the code generator collects all the assignments to
8043217Sbostic  * temporaries at the start of a statement -- hence the temporaries need to
8143217Sbostic  * be initialized once per statement instead of once per call.
8243217Sbostic  *
8343217Sbostic  */
8443217Sbostic 
8543217Sbostic #include "defs.h"
8643217Sbostic #include "optim.h"
8743217Sbostic 
8843217Sbostic 
8943217Sbostic 
9043217Sbostic /*
9143217Sbostic  *		Information buffered for each slot type
9243217Sbostic  *
9343217Sbostic  *  slot type	       expptr	       integer		pointer
9443217Sbostic  *
9543217Sbostic  *  IFN			expr		label		-
9643217Sbostic  *  GOTO		-		label		-
9743217Sbostic  *  LABEL		-		label		-
9843217Sbostic  *  EQ			expr		-		-
9943217Sbostic  *  CALL		expr		-		-
10043217Sbostic  *  CMGOTO		expr		num		labellist*
10143217Sbostic  *  STOP		expr		-		-
10243217Sbostic  *  DOHEAD		[1]		-		ctlframe*
10343217Sbostic  *  ENDDO		[1]		-		ctlframe*
10443217Sbostic  *  ARIF		expr		-		labellist*
10543217Sbostic  *  RETURN		expr		label		-
10643217Sbostic  *  ASGOTO		expr		-		labellist*
10743217Sbostic  *  PAUSE		expr		-		-
10843217Sbostic  *  ASSIGN		expr		label		-
10943217Sbostic  *  SKIOIFN		expr		label		-
11043217Sbostic  *  SKFRTEMP		expr		-		-
11143217Sbostic  *
11243217Sbostic  *     Note [1]:  the nullslot field is a pointer to a fake slot which is
11343217Sbostic  *     at the end of the slots which may be replaced by this slot.  In
11443217Sbostic  *     other words, it looks like this:
11543217Sbostic  *		DOHEAD slot
11643217Sbostic  *		slot   \
11743217Sbostic  *		slot    > ordinary IF, GOTO, LABEL slots which implement the DO
11843217Sbostic  *		slot   /
11943217Sbostic  *		NULL slot
12043217Sbostic  */
12143217Sbostic 
12243217Sbostic 
12343217Sbostic expptr expand();
12443217Sbostic 
12543217Sbostic Slotp	firstslot = NULL;
12643217Sbostic Slotp	lastslot = NULL;
12743217Sbostic int	numslots = 0;
12843217Sbostic 
12943217Sbostic 
13043217Sbostic /*
13143217Sbostic  *  turns off optimization option
13243217Sbostic  */
13343217Sbostic 
optoff()13443217Sbostic optoff()
13543217Sbostic 
13643217Sbostic {
13743217Sbostic flushopt();
13843217Sbostic optimflag = 0;
13943217Sbostic }
14043217Sbostic 
14143217Sbostic 
14243217Sbostic 
14343217Sbostic /*
14443217Sbostic  *  initializes the code buffer for optimization
14543217Sbostic  */
14643217Sbostic 
setopt()14743217Sbostic setopt()
14843217Sbostic 
14943217Sbostic {
15043217Sbostic register Slotp sp;
15143217Sbostic 
15243217Sbostic for (sp = firstslot; sp; sp = sp->next)
15343217Sbostic 	free ( (charptr) sp);
15443217Sbostic firstslot = lastslot = NULL;
15543217Sbostic numslots = 0;
15643217Sbostic }
15743217Sbostic 
15843217Sbostic 
15943217Sbostic 
16043217Sbostic /*
16143217Sbostic  *  flushes the code buffer
16243217Sbostic  */
16343217Sbostic 
16443217Sbostic LOCAL int alreadycalled = 0;
16543217Sbostic 
flushopt()16643217Sbostic flushopt()
16743217Sbostic {
16843217Sbostic register Slotp sp;
16943217Sbostic int savelineno;
17043217Sbostic 
17143217Sbostic if (alreadycalled) return;	/* to prevent recursive call during errors */
17243217Sbostic alreadycalled = 1;
17343217Sbostic 
17443217Sbostic if (debugflag[1])
17543217Sbostic 	showbuffer ();
17643217Sbostic 
17743217Sbostic frtempbuff ();
17843217Sbostic 
17943217Sbostic savelineno = lineno;
18043217Sbostic for (sp = firstslot; sp; sp = sp->next)
18143217Sbostic 	{
18243217Sbostic 	if (nerr == 0)
18343217Sbostic 		putopt (sp);
18443217Sbostic 	else
18543217Sbostic 		frexpr (sp->expr);
18643217Sbostic         if(sp->ctlinfo) free ( (charptr) sp->ctlinfo);
18743217Sbostic         free ( (charptr) sp);
18843217Sbostic         numslots--;
18943217Sbostic 	}
19043217Sbostic firstslot = lastslot = NULL;
19143217Sbostic numslots = 0;
19243217Sbostic clearbb();
19343217Sbostic lineno = savelineno;
19443217Sbostic 
19543217Sbostic alreadycalled = 0;
19643217Sbostic }
19743217Sbostic 
19843217Sbostic 
19943217Sbostic 
20043217Sbostic /*
20143217Sbostic  *  puts out code for the given slot (from the code buffer)
20243217Sbostic  */
20343217Sbostic 
putopt(sp)20443217Sbostic LOCAL putopt (sp)
20543217Sbostic register Slotp sp;
20643217Sbostic {
20743217Sbostic 	lineno = sp->lineno;
20843217Sbostic 	switch (sp->type) {
20943217Sbostic 	    case SKNULL:
21043217Sbostic 		break;
21143217Sbostic 	    case SKIFN:
21243217Sbostic 	    case SKIOIFN:
21343217Sbostic 		putif(sp->expr, sp->label);
21443217Sbostic 		break;
21543217Sbostic 	    case SKGOTO:
21643217Sbostic 		putgoto(sp->label);
21743217Sbostic 		break;
21843217Sbostic 	    case SKCMGOTO:
21943217Sbostic 		putcmgo(sp->expr, sp->label, sp->ctlinfo);
22043217Sbostic 		break;
22143217Sbostic 	    case SKCALL:
22243217Sbostic 		putexpr(sp->expr);
22343217Sbostic 		break;
22443217Sbostic 	    case SKSTOP:
22543217Sbostic 		putexpr (call1 (TYSUBR, "s_stop", sp->expr));
22643217Sbostic 		break;
22743217Sbostic 	    case SKPAUSE:
22843217Sbostic 		putexpr (call1 (TYSUBR, "s_paus", sp->expr));
22943217Sbostic 		break;
23043217Sbostic 	    case SKASSIGN:
23143217Sbostic 		puteq (sp->expr,
23243217Sbostic 		    intrconv(sp->expr->headblock.vtype, mkaddcon(sp->label)));
23343217Sbostic 		break;
23443217Sbostic 	    case SKDOHEAD:
23543217Sbostic 	    case SKENDDO:
23643217Sbostic 		break;
23743217Sbostic 	    case SKEQ:
23843217Sbostic 		putexpr(sp->expr);
23943217Sbostic 		break;
24043217Sbostic 	    case SKARIF:
24143217Sbostic #define LM   ((struct Labelblock * *)sp->ctlinfo)[0]->labelno
24243217Sbostic #define LZ   ((struct Labelblock * *)sp->ctlinfo)[1]->labelno
24343217Sbostic #define LP   ((struct Labelblock * *)sp->ctlinfo)[2]->labelno
24443217Sbostic        		prarif(sp->expr, LM, LZ, LP);
24543217Sbostic 		break;
24643217Sbostic 	    case SKASGOTO:
24743217Sbostic 		putbranch((Addrp) sp->expr);
24843217Sbostic 		break;
24943217Sbostic 	    case SKLABEL:
25043217Sbostic 		putlabel(sp->label);
25143217Sbostic 		break;
25243217Sbostic 	    case SKRETURN:
25343217Sbostic 		if (sp->expr)
25443217Sbostic 			{
25543217Sbostic 			putforce(TYINT, sp->expr);
25643217Sbostic 			putgoto(sp->label);
25743217Sbostic 			}
25843217Sbostic 		else
25943217Sbostic 			putgoto(sp->label);
26043217Sbostic 		break;
26143217Sbostic 	    case SKFRTEMP:
26243217Sbostic 		templist = mkchain (sp->expr,templist);
26343217Sbostic 		break;
26443217Sbostic 	    default:
26543217Sbostic 		badthing("SKtype", "putopt", sp->type);
26643217Sbostic 		break;
26743217Sbostic 	}
26843217Sbostic 
26943217Sbostic 	/*
27043217Sbostic 	 * Recycle argument temporaries here.  This must get done on a
27143217Sbostic 	 *	statement-by-statement basis because the code generator
27243217Sbostic 	 *	makes side effects happen at the start of a statement.
27343217Sbostic 	 */
27443217Sbostic 	argtemplist = hookup(argtemplist, activearglist);
27543217Sbostic 	activearglist = CHNULL;
27643217Sbostic }
27743217Sbostic 
27843217Sbostic 
27943217Sbostic 
28043217Sbostic /*
28143217Sbostic  *  copies one element of the control stack
28243217Sbostic  */
28343217Sbostic 
cpframe(p)28443217Sbostic LOCAL struct Ctlframe *cpframe(p)
28543217Sbostic register char *p;
28643217Sbostic {
28743217Sbostic static int size =  sizeof (struct Ctlframe);
28843217Sbostic register int n;
28943217Sbostic register char *q;
29043217Sbostic struct Ctlframe *q0;
29143217Sbostic 
29243217Sbostic q0 = ALLOC(Ctlframe);
29343217Sbostic q = (char *) q0;
29443217Sbostic n = size;
29543217Sbostic while(n-- > 0)
29643217Sbostic 	*q++ = *p++;
29743217Sbostic return( q0);
29843217Sbostic }
29943217Sbostic 
30043217Sbostic 
30143217Sbostic 
30243217Sbostic /*
30343217Sbostic  *  copies an array of labelblock pointers
30443217Sbostic  */
30543217Sbostic 
cplabarr(n,arr)30643217Sbostic LOCAL struct Labelblock **cplabarr(n,arr)
30743217Sbostic struct Labelblock *arr[];
30843217Sbostic int n;
30943217Sbostic {
31043217Sbostic struct Labelblock **newarr;
31143217Sbostic register char *in, *out;
31243217Sbostic register int i,j;
31343217Sbostic 
31443217Sbostic newarr = (struct Labelblock **) ckalloc (n * sizeof (char *));
31543217Sbostic for (i = 0; i < n; i++)
31643217Sbostic 	{
31743217Sbostic 	newarr[i] = ALLOC (Labelblock);
31843217Sbostic 	out = (char *) newarr[i];
31943217Sbostic 	in = (char *) arr[i];
32043217Sbostic 	j = sizeof (struct Labelblock);
32143217Sbostic 	while (j-- > 0)
32243217Sbostic 		*out++ = *in++;
32343217Sbostic 	}
32443217Sbostic return (newarr);
32543217Sbostic }
32643217Sbostic 
32743217Sbostic 
32843217Sbostic 
32943217Sbostic /*
33043217Sbostic  *  creates a new slot in the code buffer
33143217Sbostic  */
33243217Sbostic 
newslot()33343217Sbostic LOCAL Slotp newslot()
33443217Sbostic {
33543217Sbostic register Slotp sp;
33643217Sbostic 
33743217Sbostic ++numslots;
33843217Sbostic sp = ALLOC( slt );
33943217Sbostic sp->next = NULL ;
34043217Sbostic if (lastslot)
34143217Sbostic 	{
34243217Sbostic 	sp->prev = lastslot;
34343217Sbostic 	lastslot = lastslot->next = sp;
34443217Sbostic 	}
34543217Sbostic else
34643217Sbostic 	{
34743217Sbostic 	firstslot = lastslot = sp;
34843217Sbostic 	sp->prev = NULL;
34943217Sbostic 	}
35043217Sbostic sp->lineno = lineno;
35143217Sbostic return (sp);
35243217Sbostic }
35343217Sbostic 
35443217Sbostic 
35543217Sbostic 
35643217Sbostic /*
35743217Sbostic  *  removes (but not deletes) the specified slot from the code buffer
35843217Sbostic  */
35943217Sbostic 
removeslot(sl)36043217Sbostic removeslot (sl)
36143217Sbostic Slotp	sl;
36243217Sbostic 
36343217Sbostic {
36443217Sbostic if (sl->next)
36543217Sbostic 	sl->next->prev = sl->prev;
36643217Sbostic else
36743217Sbostic 	lastslot = sl->prev;
36843217Sbostic if (sl->prev)
36943217Sbostic 	sl->prev->next = sl->next;
37043217Sbostic else
37143217Sbostic 	firstslot = sl->next;
37243217Sbostic sl->next = sl->prev = NULL;
37343217Sbostic 
37443217Sbostic --numslots;
37543217Sbostic }
37643217Sbostic 
37743217Sbostic 
37843217Sbostic 
37943217Sbostic /*
38043217Sbostic  *  inserts slot s1 before existing slot s2 in the code buffer;
38143217Sbostic  *  appends to end of list if s2 is NULL.
38243217Sbostic  */
38343217Sbostic 
insertslot(s1,s2)38443217Sbostic insertslot (s1,s2)
38543217Sbostic Slotp	s1,s2;
38643217Sbostic 
38743217Sbostic {
38843217Sbostic if (s2)
38943217Sbostic 	{
39043217Sbostic 	if (s2->prev)
39143217Sbostic 		s2->prev->next = s1;
39243217Sbostic 	else
39343217Sbostic 		firstslot = s1;
39443217Sbostic 	s1->prev = s2->prev;
39543217Sbostic 	s2->prev = s1;
39643217Sbostic 	}
39743217Sbostic else
39843217Sbostic 	{
39943217Sbostic 	s1->prev = lastslot;
40043217Sbostic 	lastslot->next = s1;
40143217Sbostic 	lastslot = s1;
40243217Sbostic 	}
40343217Sbostic s1->next = s2;
40443217Sbostic 
40543217Sbostic ++numslots;
40643217Sbostic }
40743217Sbostic 
40843217Sbostic 
40943217Sbostic 
41043217Sbostic /*
41143217Sbostic  *  deletes the specified slot from the code buffer
41243217Sbostic  */
41343217Sbostic 
delslot(sl)41443217Sbostic delslot (sl)
41543217Sbostic Slotp	sl;
41643217Sbostic 
41743217Sbostic {
41843217Sbostic removeslot (sl);
41943217Sbostic 
42043217Sbostic if (sl->ctlinfo)
42143217Sbostic 	free ((charptr) sl->ctlinfo);
42243217Sbostic frexpr (sl->expr);
42343217Sbostic free ((charptr) sl);
42443217Sbostic numslots--;
42543217Sbostic }
42643217Sbostic 
42743217Sbostic 
42843217Sbostic 
42943217Sbostic /*
43043217Sbostic  *  inserts a slot before the specified slot; if given NULL, it is
43143217Sbostic  *  inserted at the end of the buffer
43243217Sbostic  */
43343217Sbostic 
optinsert(type,p,l,c,currslot)43443217Sbostic Slotp optinsert (type,p,l,c,currslot)
43543217Sbostic int	type;
43643217Sbostic expptr	p;
43743217Sbostic int	l;
43843217Sbostic int	*c;
43943217Sbostic Slotp	currslot;
44043217Sbostic 
44143217Sbostic {
44243217Sbostic Slotp	savelast,new;
44343217Sbostic 
44443217Sbostic savelast = lastslot;
44543217Sbostic if (currslot)
44643217Sbostic 	lastslot = currslot->prev;
44743217Sbostic new = optbuff (type,p,l,c);
44843217Sbostic new->next = currslot;
44943217Sbostic if (currslot)
45043217Sbostic 	currslot->prev = new;
45143217Sbostic new->lineno = -1;	/* who knows what the line number should be ??!! */
45243217Sbostic if (currslot)
45343217Sbostic 	lastslot = savelast;
45443217Sbostic return (new);
45543217Sbostic }
45643217Sbostic 
45743217Sbostic 
45843217Sbostic 
45943217Sbostic /*
46043217Sbostic  *  buffers the FRTEMP slots which have been waiting
46143217Sbostic  */
46243217Sbostic 
frtempbuff()46343217Sbostic frtempbuff ()
46443217Sbostic 
46543217Sbostic {
46643217Sbostic chainp ht;
46743217Sbostic register Slotp sp;
46843217Sbostic 
46943217Sbostic for (ht = holdtemps; ht; ht = ht->nextp)
47043217Sbostic 	{
47143217Sbostic 	sp = newslot();
47243217Sbostic 		/* this slot actually belongs to some previous source line */
47343217Sbostic 	sp->lineno = sp->lineno - 1;
47443217Sbostic 	sp->type = SKFRTEMP;
47543217Sbostic 	sp->expr = (expptr) ht->datap;
47643217Sbostic 	sp->label = 0;
47743217Sbostic 	sp->ctlinfo = NULL;
47843217Sbostic 	}
47943217Sbostic holdtemps = NULL;
48043217Sbostic }
48143217Sbostic 
48243217Sbostic 
48343217Sbostic 
48443217Sbostic /*
48543217Sbostic  *  puts the given information into a slot at the end of the code buffer
48643217Sbostic  */
48743217Sbostic 
optbuff(type,p,l,c)48843217Sbostic Slotp optbuff (type,p,l,c)
48943217Sbostic int	type;
49043217Sbostic expptr	p;
49143217Sbostic int	l;
49243217Sbostic int	*c;
49343217Sbostic 
49443217Sbostic {
49543217Sbostic register Slotp sp;
49643217Sbostic 
49743217Sbostic if (debugflag[1])
49843217Sbostic 	{
49943217Sbostic 	fprintf (diagfile,"-----optbuff-----"); showslottype (type);
50043217Sbostic 	showexpr (p,0); fprintf (diagfile,"\n");
50143217Sbostic 	}
50243217Sbostic 
50343217Sbostic p = expand (p);
50443217Sbostic sp = newslot();
50543217Sbostic sp->type = type;
50643217Sbostic sp->expr = p;
50743217Sbostic sp->label = l;
50843217Sbostic sp->ctlinfo = NULL;
50943217Sbostic switch (type)
51043217Sbostic 	{
51143217Sbostic 	case SKCMGOTO:
51243217Sbostic 		sp->ctlinfo = (int*) cplabarr (l, (struct Labelblock**) c);
51343217Sbostic 		break;
51443217Sbostic 	case SKARIF:
51543217Sbostic 		sp->ctlinfo = (int*) cplabarr (3, (struct Labelblock**) c);
51643217Sbostic 		break;
51743217Sbostic 	case SKDOHEAD:
51843217Sbostic 	case SKENDDO:
51943217Sbostic 		sp->ctlinfo = (int*) cpframe ((struct Ctlframe*) c);
52043217Sbostic 		break;
52143217Sbostic 	default:
52243217Sbostic 		break;
52343217Sbostic 	}
52443217Sbostic 
52543217Sbostic frtempbuff ();
52643217Sbostic 
52743217Sbostic return (sp);
52843217Sbostic }
52943217Sbostic 
53043217Sbostic 
53143217Sbostic 
53243217Sbostic /*
53343217Sbostic  *  expands the given expression, if possible (e.g., concat, min, max, etc.);
53443217Sbostic  *  also frees temporaries when they are indicated as being the last use
53543217Sbostic  */
53643217Sbostic 
53743217Sbostic #define APPEND(z)	\
53843217Sbostic 	res = res->exprblock.rightp = mkexpr (OPCOMMA, z, newtemp)
53943217Sbostic 
expand(p)54043217Sbostic LOCAL expptr expand (p)
54143217Sbostic tagptr p;
54243217Sbostic 
54343217Sbostic {
54443217Sbostic Addrp t;
54543217Sbostic expptr q;
54643217Sbostic expptr buffmnmx(), buffpower();
54743217Sbostic 
54843217Sbostic if (!p)
54943217Sbostic 	return (ENULL);
55043217Sbostic switch (p->tag)
55143217Sbostic 	{
55243217Sbostic 	case TEXPR:
55343217Sbostic 		switch (p->exprblock.opcode)
55443217Sbostic 			{
55543217Sbostic 			case OPASSIGN: /* handle a = b // c */
55643217Sbostic 				if (p->exprblock.vtype != TYCHAR)
55743217Sbostic 					goto standard;
55843217Sbostic 				q = p->exprblock.rightp;
55943217Sbostic 				if (!(q->tag == TEXPR &&
56043217Sbostic 				      q->exprblock.opcode == OPCONCAT))
56143217Sbostic 					goto standard;
56243217Sbostic 				t = (Addrp) expand(p->exprblock.leftp);
56343217Sbostic 				frexpr(p->exprblock.vleng);
56443217Sbostic 				free( (charptr) p );
56543217Sbostic 				p = (tagptr) q;
56643217Sbostic 				goto cat;
56743217Sbostic 			case OPCONCAT:
56843217Sbostic 				t = mktemp (TYCHAR, ICON(lencat(p)));
56943217Sbostic 			cat:
57043217Sbostic 				q = (expptr) cpexpr (p->exprblock.vleng);
57143217Sbostic 				buffcat (cpexpr(t),p);
57243217Sbostic 				frexpr (t->vleng);
57343217Sbostic 				t->vleng = q;
57443217Sbostic 				p = (tagptr) t;
57543217Sbostic 				break;
57643217Sbostic 			case OPMIN:
57743217Sbostic 			case OPMAX:
57843217Sbostic 				p = (tagptr) buffmnmx (p);
57943217Sbostic 				break;
58043217Sbostic 			case OPPOWER:
58143217Sbostic 				p = (tagptr) buffpower (p);
58243217Sbostic 				break;
58343217Sbostic 			default:
58443217Sbostic 			standard:
58543217Sbostic 				p->exprblock.leftp =
58643217Sbostic 					expand (p->exprblock.leftp);
58743217Sbostic 				if (p->exprblock.rightp)
58843217Sbostic 					p->exprblock.rightp =
58943217Sbostic 						expand (p->exprblock.rightp);
59043217Sbostic 				break;
59143217Sbostic 			}
59243217Sbostic 		break;
59343217Sbostic 
59443217Sbostic 	case TLIST:
59543217Sbostic 		{
59643217Sbostic 		chainp t;
59743217Sbostic 		for (t = p->listblock.listp; t; t = t->nextp)
59843217Sbostic 			t->datap = (tagptr) expand (t->datap);
59943217Sbostic 		}
60043217Sbostic 		break;
60143217Sbostic 
60243217Sbostic 	case TTEMP:
60343217Sbostic 		if (p->tempblock.istemp)
60443217Sbostic 			frtemp(p);
60543217Sbostic 		break;
60643217Sbostic 
60743217Sbostic 	case TADDR:
60843217Sbostic 		p->addrblock.memoffset = expand( p->addrblock.memoffset );
60943217Sbostic 		break;
61043217Sbostic 
61143217Sbostic 	default:
61243217Sbostic 		break;
61343217Sbostic 	}
61443217Sbostic return ((expptr) p);
61543217Sbostic }
61643217Sbostic 
61743217Sbostic 
61843217Sbostic 
61943217Sbostic /*
62043217Sbostic  *  local version of routine putcat in putpcc.c, called by expand
62143217Sbostic  */
62243217Sbostic 
buffcat(lhs,rhs)62343217Sbostic LOCAL buffcat(lhs, rhs)
62443217Sbostic register Addrp lhs;
62543217Sbostic register expptr rhs;
62643217Sbostic {
62743217Sbostic int n;
62843217Sbostic Addrp lp, cp;
62943217Sbostic 
63043217Sbostic n = ncat(rhs);
63143217Sbostic lp = (Addrp) mkaltmpn(n, TYLENG, PNULL);
63243217Sbostic cp = (Addrp) mkaltmpn(n, TYADDR, PNULL);
63343217Sbostic 
63443217Sbostic n = 0;
63543217Sbostic buffct1(rhs, lp, cp, &n);
63643217Sbostic 
63743217Sbostic optbuff (SKCALL, call4(TYSUBR, "s_cat", lhs, cp, lp, mkconv(TYLONG, ICON(n))),
63843217Sbostic 	0, 0);
63943217Sbostic }
64043217Sbostic 
64143217Sbostic 
64243217Sbostic 
64343217Sbostic /*
64443217Sbostic  *  local version of routine putct1 in putpcc.c, called by expand
64543217Sbostic  */
64643217Sbostic 
buffct1(q,lp,cp,ip)64743217Sbostic LOCAL buffct1(q, lp, cp, ip)
64843217Sbostic register expptr q;
64943217Sbostic register Addrp lp, cp;
65043217Sbostic int *ip;
65143217Sbostic {
65243217Sbostic int i;
65343217Sbostic Addrp lp1, cp1;
65443217Sbostic 
65543217Sbostic if(q->tag==TEXPR && q->exprblock.opcode==OPCONCAT)
65643217Sbostic 	{
65743217Sbostic 	buffct1(q->exprblock.leftp, lp, cp, ip);
65843217Sbostic 	buffct1(q->exprblock.rightp, lp, cp, ip);
65943217Sbostic 	frexpr(q->exprblock.vleng);
66043217Sbostic 	free( (charptr) q );
66143217Sbostic 	}
66243217Sbostic else
66343217Sbostic 	{
66443217Sbostic 	i = (*ip)++;
66543217Sbostic 	lp1 = (Addrp) cpexpr(lp);
66643217Sbostic 	lp1->memoffset = mkexpr(OPPLUS,lp1->memoffset, ICON(i*SZLENG));
66743217Sbostic 	cp1 = (Addrp) cpexpr(cp);
66843217Sbostic 	cp1->memoffset = mkexpr(OPPLUS, cp1->memoffset, ICON(i*SZADDR));
66943217Sbostic 	optbuff (SKEQ, (mkexpr(OPASSIGN, lp1, cpexpr(q->headblock.vleng))),
67043217Sbostic 		0,0);
67143217Sbostic 	optbuff (SKEQ, (mkexpr(OPASSIGN, cp1, addrof(expand (q)))), 0, 0);
67243217Sbostic 	}
67343217Sbostic }
67443217Sbostic 
67543217Sbostic 
67643217Sbostic 
67743217Sbostic /*
67843217Sbostic  *  local version of routine putmnmx in putpcc.c, called by expand
67943217Sbostic  */
68043217Sbostic 
buffmnmx(p)68143217Sbostic LOCAL expptr buffmnmx(p)
68243217Sbostic register expptr p;
68343217Sbostic {
68443217Sbostic int op, type;
68543217Sbostic expptr qp;
68643217Sbostic chainp p0, p1;
68743217Sbostic Addrp sp, tp;
68843217Sbostic Addrp newtemp;
68943217Sbostic expptr result, res;
69043217Sbostic 
69143217Sbostic if(p->tag != TEXPR)
69243217Sbostic 	badtag("buffmnmx", p->tag);
69343217Sbostic 
69443217Sbostic type = p->exprblock.vtype;
69543217Sbostic op = (p->exprblock.opcode==OPMIN ? OPLT : OPGT );
69643217Sbostic qp = expand(p->exprblock.leftp);
69743217Sbostic if(qp->tag != TLIST)
69843217Sbostic 	badtag("buffmnmx list", qp->tag);
69943217Sbostic p0 = qp->listblock.listp;
70043217Sbostic free( (charptr) qp );
70143217Sbostic free( (charptr) p );
70243217Sbostic 
70343217Sbostic sp = mktemp(type, PNULL);
70443217Sbostic tp = mktemp(type, PNULL);
70543217Sbostic qp = mkexpr(OPCOLON, cpexpr(tp), cpexpr(sp));
70643217Sbostic qp = mkexpr(OPQUEST, mkexpr(op, cpexpr(tp),cpexpr(sp)), qp);
70743217Sbostic qp = fixexpr(qp);
70843217Sbostic 
70943217Sbostic newtemp = mktemp (type,PNULL);
71043217Sbostic 
71143217Sbostic result = res = mkexpr (OPCOMMA,
71243217Sbostic 	mkexpr( OPASSIGN, cpexpr(sp), p0->datap ), cpexpr(newtemp));
71343217Sbostic 
71443217Sbostic for(p1 = p0->nextp ; p1 ; p1 = p1->nextp)
71543217Sbostic 	{
71643217Sbostic 	APPEND (mkexpr( OPASSIGN, cpexpr(tp), p1->datap ));
71743217Sbostic 	if(p1->nextp)
71843217Sbostic 		APPEND (mkexpr (OPASSIGN, cpexpr(sp), cpexpr(qp)) );
71943217Sbostic 	else
72043217Sbostic 		APPEND (mkexpr (OPASSIGN, cpexpr(newtemp), qp));
72143217Sbostic 	}
72243217Sbostic 
72343217Sbostic frtemp(sp);
72443217Sbostic frtemp(tp);
72543217Sbostic frtemp(newtemp);
72643217Sbostic frchain( &p0 );
72743217Sbostic 
72843217Sbostic return (result);
72943217Sbostic }
73043217Sbostic 
73143217Sbostic 
73243217Sbostic 
73343217Sbostic /*
73443217Sbostic  * Called by expand() to eliminate exponentiations to integer constants.
73543217Sbostic  */
buffpower(p)73643217Sbostic LOCAL expptr buffpower( p )
73743217Sbostic 	expptr p;
73843217Sbostic {
73943217Sbostic 	expptr base;
74043217Sbostic 	Addrp newtemp;
74143217Sbostic 	expptr storetemp = ENULL;
74243217Sbostic 	expptr powtree();
74343217Sbostic 	expptr result;
74443217Sbostic 	ftnint exp;
74543217Sbostic 
74643217Sbostic 	if ( ! ISICON( p->exprblock.rightp ) )
74743217Sbostic 		fatal( "buffpower: bad non-integer exponent" );
74843217Sbostic 
74943217Sbostic 	base = expand(p->exprblock.leftp);
75046305Sbostic 	exp = p->exprblock.rightp->constblock.constant.ci;
75143217Sbostic 	if ( exp < 2 )
75243217Sbostic 		fatal( "buffpower: bad exponent less than 2" );
75343217Sbostic 
75443217Sbostic 	if ( exp > 64 ) {
75543217Sbostic 		/*
75643217Sbostic 		 * Let's be reasonable, here...  Let putpower() do the job.
75743217Sbostic 		 */
75843217Sbostic 		p->exprblock.leftp = base;
75943217Sbostic 		return ( p );
76043217Sbostic 	}
76143217Sbostic 
76243217Sbostic 	/*
76343217Sbostic 	 * If the base is not a simple variable, evaluate it and copy the
76443217Sbostic 	 *	result into a temporary.
76543217Sbostic 	 */
76643217Sbostic 	if ( ! (base->tag == TADDR && ISCONST( base->addrblock.memoffset )) ) {
76743217Sbostic 		newtemp = mktemp( base->headblock.vtype, PNULL );
76843217Sbostic 		storetemp = mkexpr( OPASSIGN,
76943217Sbostic 			      cpexpr( (expptr) newtemp ),
77043217Sbostic 			      cpexpr( base ) );
77143217Sbostic 		base = (expptr) newtemp;
77243217Sbostic 	}
77343217Sbostic 
77443217Sbostic 	result = powtree( base, exp );
77543217Sbostic 
77643217Sbostic 	if ( storetemp != ENULL )
77743217Sbostic 		result = mkexpr( OPCOMMA, storetemp, result );
77843217Sbostic 	frexpr( p );
77943217Sbostic 
78043217Sbostic 	return ( result );
78143217Sbostic }
78243217Sbostic 
78343217Sbostic 
78443217Sbostic 
78543217Sbostic /*
78643217Sbostic  * powtree( base, exp ) -- Create a tree of multiplications which computes
78743217Sbostic  *	base ** exp.  The tree is built so that CSE will compact it if
78843217Sbostic  *	possible.  The routine works by creating subtrees that compute
78943217Sbostic  *	exponents which are powers of two, then multiplying these
79043217Sbostic  *	together to get the result; this gives a log2( exp ) tree depth
79143217Sbostic  *	and lots of subexpressions which can be eliminated.
79243217Sbostic  */
powtree(base,exp)79343217Sbostic LOCAL expptr powtree( base, exp )
79443217Sbostic 	expptr base;
79543217Sbostic 	register ftnint exp;
79643217Sbostic {
79743217Sbostic 	register expptr r = ENULL, r1;
79843217Sbostic 	register int i;
79943217Sbostic 
80043217Sbostic 	for ( i = 0; exp; ++i, exp >>= 1 )
80143217Sbostic 		if ( exp & 1 )
80243217Sbostic 			if ( i == 0 )
80343217Sbostic 				r = (expptr) cpexpr( base );
80443217Sbostic 			else {
80543217Sbostic 				r1 = powtree( base, 1 << (i - 1) );
80643217Sbostic 				r1 = mkexpr( OPSTAR, r1, cpexpr( r1 ) );
80743217Sbostic 				r = (r ? mkexpr( OPSTAR, r1, r ) : r1);
80843217Sbostic 			}
80943217Sbostic 
81043217Sbostic 	return ( r );
81143217Sbostic }
812