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