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