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