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%
643216Sbostic */
743216Sbostic
843216Sbostic #ifndef lint
9*47951Sbostic static char sccsid[] = "@(#)optcse.c 5.3 (Berkeley) 04/12/91";
10*47951Sbostic #endif /* not lint */
1143216Sbostic
1243216Sbostic /*
1343216Sbostic * optcse.c
1443216Sbostic *
1543216Sbostic * Common subexpression elimination routines, F77 compiler pass 1.
1643216Sbostic *
1743216Sbostic * University of Utah CS Dept modification history:
1843216Sbostic *
1943216Sbostic * $Log: optcse.c,v $
2043216Sbostic * Revision 2.4 84/10/29 04:40:48 donn
2143216Sbostic * Problem with conversions -- two expressions headed by a conversion may be
2243216Sbostic * identical in structure but different in type, thus type must be checked in
2343216Sbostic * findnode(). This was causing a subscript to become REAL*8 type...
2443216Sbostic *
2543216Sbostic * Revision 2.3 84/08/04 20:38:53 donn
2643216Sbostic * Added fix from Jerry Berkman for an earlier fix from Alastair Fyfe --
2743216Sbostic * samebase() should treat EQUIVALENCEd variables just as daintily as
2843216Sbostic * COMMON variables.
2943216Sbostic *
3043216Sbostic * Revision 2.2 84/08/01 16:04:33 donn
3143216Sbostic * Changed rmcommaop so that it does subscripts too.
3243216Sbostic *
3343216Sbostic * Revision 2.1 84/07/19 12:03:44 donn
3443216Sbostic * Changed comment headers for UofU.
3543216Sbostic *
3643216Sbostic * Revision 1.5 84/07/09 14:43:05 donn
3743216Sbostic * Added changes to make OPPLUSEQ and OPSTAREQ expressions ineligible for
3843216Sbostic * CSE, since I can't think of a simple way to handle them and they are broken
3943216Sbostic * in the previous version, where they were treated like OPASSIGN -- this
4043216Sbostic * fails because CSE would think that the value of the lhs and rhs were equal.
4143216Sbostic *
4243216Sbostic * Revision 1.4 84/06/08 11:43:35 donn
4343216Sbostic * Yet another way of handling the bug with COMMON -- this one is from Alastair
4443216Sbostic * Fyfe at Sun. I backed out the old fix.
4543216Sbostic *
4643216Sbostic * Revision 1.3 84/03/07 19:25:14 donn
4743216Sbostic * Changed method of handling COMMON bug -- COMMON variables are now treated
4843216Sbostic * like array elements and hence are ineligible for CSE.
4943216Sbostic *
5043216Sbostic * Revision 1.2 84/02/26 03:30:47 donn
5143216Sbostic * Fixed bug in evaluation graph construction that caused two variables in
5243216Sbostic * common to be considered identical if they were merely in the same common,
5343216Sbostic * rather than in the same common at the same offset.
5443216Sbostic *
5543216Sbostic */
5643216Sbostic
5743216Sbostic #include "defs.h"
5843216Sbostic #include "optim.h"
5943216Sbostic
6043216Sbostic #define FALSE 0
6143216Sbostic #define TRUE 1
6243216Sbostic
6343216Sbostic LOCAL Bblockp current_BB;
6443216Sbostic LOCAL int cse1count; /* count of number of cse uses eliminated */
6543216Sbostic LOCAL int cse2count; /* count of number of cse def's eliminated */
6643216Sbostic
6743216Sbostic
6843216Sbostic
6943216Sbostic
dumpstacks()7043216Sbostic LOCAL dumpstacks()
7143216Sbostic {
7243216Sbostic duplptr dl;
7343216Sbostic valuen p;
7443216Sbostic idlptr idl;
7543216Sbostic idptr idp;
7643216Sbostic nodelptr nl;
7743216Sbostic int i;
7843216Sbostic
7943216Sbostic fprintf(diagfile,"\n *** IDblocks ***\n");
8043216Sbostic for(idp=current_BB->headid;idp;idp=idp->next)
8143216Sbostic {
8243216Sbostic fprintf(diagfile,
8343216Sbostic "idp= %d idaddr= %d initval= %d assgnval= %d \n",
8443216Sbostic idp, idp->idaddr, idp->initval, idp->assgnval);
8543216Sbostic fprintf(diagfile,"nodes: ");
8643216Sbostic i=0;
8743216Sbostic for (nl=idp->headnodelist;nl;nl=nl->next) {
8843216Sbostic if(++i>20){
8943216Sbostic fprintf(diagfile,"\n");
9043216Sbostic i=0;
9143216Sbostic }
9243216Sbostic fprintf(diagfile," %d ",nl->nodep);
9343216Sbostic }
9443216Sbostic fprintf(diagfile,"\n");
9543216Sbostic }
9643216Sbostic
9743216Sbostic fprintf(diagfile,"\n *** VALUE NODES *** \n");
9843216Sbostic for(p=current_BB->headnode;p;p=p->next) {
9943216Sbostic fprintf(diagfile,
10043216Sbostic "\np= %d opp= %d lc= %d rc= %d rs= %d is_dead= %d n_dups %d",
10143216Sbostic p, p->opp,p->lc,p->rc, p->rs, p->is_dead, p->n_dups);
10243216Sbostic if (p->rs){
10343216Sbostic fprintf(diagfile,"tag= %d ",p->opp->tag);
10443216Sbostic if(p->opp->tag==TEXPR)
10543216Sbostic fprintf(diagfile,"opco= %d ",
10643216Sbostic p->opp->exprblock.opcode);
10743216Sbostic }
10843216Sbostic fprintf(diagfile,"\n");
10943216Sbostic fprintf(diagfile,"parent= %d dups: ",p->parent);
11043216Sbostic i=0;
11143216Sbostic for(dl=p->headduplist;dl;dl=dl->next) {
11243216Sbostic if(++i>20){
11343216Sbostic fprintf(diagfile,"\n");
11443216Sbostic i=0;
11543216Sbostic }
11643216Sbostic fprintf(diagfile," %d ",dl->parent);
11743216Sbostic }
11843216Sbostic
11943216Sbostic fprintf(diagfile,"\ndeps IDs");
12043216Sbostic i=0;
12143216Sbostic for(idl=p->headdeplist;idl;idl=idl->next) {
12243216Sbostic if(++i>20){
12343216Sbostic fprintf(diagfile,"\n");
12443216Sbostic i=0;
12543216Sbostic }
12643216Sbostic fprintf(diagfile," %d ",idl->idp);
12743216Sbostic }
12843216Sbostic }
12943216Sbostic }
13043216Sbostic
13143216Sbostic
13243216Sbostic
mergedeps(lnode,rnode)13343216Sbostic LOCAL idlptr mergedeps(lnode,rnode)
13443216Sbostic valuen lnode,rnode;
13543216Sbostic /* Given two value nodes, merge the lists of identifiers on which they
13643216Sbostic ** depend to produce a new list incorporating both dependencies. Lists
13743216Sbostic ** are assumed to be ordered by increasing idp address. No duplicate identifiers
13843216Sbostic ** are generated in the output list.
13943216Sbostic */
14043216Sbostic {
14143216Sbostic register idlptr lp,lp1,lp2;
14243216Sbostic idlptr head;
14343216Sbostic
14443216Sbostic lp = lp1 = lp2 = head = NULL;
14543216Sbostic if(lnode) lp1 = lnode->headdeplist;
14643216Sbostic if(rnode) lp2 = rnode->headdeplist;
14743216Sbostic
14843216Sbostic while (lp1 || lp2) {
14943216Sbostic if (lp) {
15043216Sbostic lp->next = ALLOC(IDlist);
15143216Sbostic lp = lp->next;
15243216Sbostic }
15343216Sbostic else lp = head = ALLOC(IDlist);
15443216Sbostic lp->next = 0;
15543216Sbostic if (lp1 == 0) {
15643216Sbostic lp->idp = lp2->idp;
15743216Sbostic lp2 = lp2->next;
15843216Sbostic }
15943216Sbostic else if (lp2 == 0) {
16043216Sbostic lp->idp = lp1->idp;
16143216Sbostic lp1 = lp1->next;
16243216Sbostic }
16343216Sbostic else if (lp1->idp < lp2->idp) {
16443216Sbostic lp->idp = lp1->idp;
16543216Sbostic lp1 = lp1->next;
16643216Sbostic }
16743216Sbostic else if (lp1->idp > lp2->idp) {
16843216Sbostic lp->idp = lp2->idp;
16943216Sbostic lp2 = lp2->next;
17043216Sbostic }
17143216Sbostic else {
17243216Sbostic lp->idp = lp1->idp;
17343216Sbostic lp1 = lp1->next;
17443216Sbostic lp2 = lp2->next;
17543216Sbostic }
17643216Sbostic }
17743216Sbostic return(head);
17843216Sbostic }
17943216Sbostic
18043216Sbostic
18143216Sbostic
removenode(nodep)18243216Sbostic LOCAL removenode(nodep)
18343216Sbostic valuen nodep;
18443216Sbostic /* Removes a value node from every IDblock on the node's list of identifiers.
18543216Sbostic */
18643216Sbostic {
18743216Sbostic register idlptr idl;
18843216Sbostic register nodelptr nl;
18943216Sbostic register nodelptr *addrnl;
19043216Sbostic
19143216Sbostic if(nodep == NULL) return ;
19243216Sbostic
19343216Sbostic /* loop through all identifiers */
19443216Sbostic for(idl=nodep->headdeplist;idl;idl=idl->next)
19543216Sbostic {
19643216Sbostic addrnl = &(idl->idp->headnodelist);
19743216Sbostic /* for each identifier loop through all nodes until match is found */
19843216Sbostic for(nl = *addrnl; nl; nl = *addrnl)
19943216Sbostic {
20043216Sbostic if(nl->nodep == nodep) {
20143216Sbostic *addrnl = nl->next;
20243216Sbostic free ( (charptr) nl );
20343216Sbostic break;
20443216Sbostic }
20543216Sbostic addrnl = &nl->next;
20643216Sbostic }
20743216Sbostic }
20843216Sbostic nodep->is_dead = TRUE;
20943216Sbostic }
21043216Sbostic
21143216Sbostic
21243216Sbostic
killid(idp)21343216Sbostic LOCAL killid(idp)
21443216Sbostic idptr idp;
21543216Sbostic /* Kill all nodes on one identifier's list of dependent nodes, i.e. remove
21643216Sbostic ** all calculations that depend on this identifier from the available
21743216Sbostic ** values stack. Free the list of records pointing at the dependent nodes.
21843216Sbostic */
21943216Sbostic {
22043216Sbostic nodelptr nl1,nl2;
22143216Sbostic
22243216Sbostic for (nl1 = idp->headnodelist; nl1; nl1=nl2)
22343216Sbostic {
22443216Sbostic nl2 = nl1->next;
22543216Sbostic removenode(nl1->nodep);
22643216Sbostic }
22743216Sbostic /* the above call frees the node list record pointed at by nl1 since it frees
22843216Sbostic ** all the node list records that reference the value node being killed
22943216Sbostic */
23043216Sbostic idp->headnodelist = NULL;
23143216Sbostic
23243216Sbostic }
23343216Sbostic
23443216Sbostic
23543216Sbostic
killdepnodes(idp)23643216Sbostic LOCAL killdepnodes(idp)
23743216Sbostic idptr idp;
23843216Sbostic /* Kill all value nodes that represent calculations which depend on
23943216Sbostic ** this identifier. If the identifier is in COMMON or EQUIVALENCE storage,
24043216Sbostic ** kill all values that depend on identifiers in COMMON or EQUIVALENCE
24143216Sbostic */
24243216Sbostic {
24343216Sbostic int thismemno;
24443216Sbostic
24543216Sbostic if(idp->idaddr->addrblock.vstg == STGCOMMON)
24643216Sbostic {
24743216Sbostic for(idp=current_BB->headid;idp;idp=idp->next)
24843216Sbostic if(idp->idaddr->addrblock.vstg == STGCOMMON)
24943216Sbostic killid(idp);
25043216Sbostic }
25143216Sbostic else if(idp->idaddr->addrblock.vstg == STGEQUIV)
25243216Sbostic {
25343216Sbostic thismemno=idp->idaddr->addrblock.memno;
25443216Sbostic for(idp=current_BB->headid;idp;idp=idp->next)
25543216Sbostic if(idp->idaddr->addrblock.vstg == STGEQUIV
25643216Sbostic && idp->idaddr->addrblock.memno == thismemno)
25743216Sbostic killid(idp);
25843216Sbostic }
25943216Sbostic else killid(idp);
26043216Sbostic
26143216Sbostic }
26243216Sbostic
26343216Sbostic
26443216Sbostic
appendnode(nodep)26543216Sbostic LOCAL appendnode(nodep)
26643216Sbostic valuen nodep;
26743216Sbostic /* Append a value node to all the IDblocks on that node's list of
26843216Sbostic ** dependent identifiers i.e., since this computation depends on
26943216Sbostic ** all the identifiers on its list then each of those identifiers should
27043216Sbostic ** include this node in their list of dependent nodes.
27143216Sbostic */
27243216Sbostic {
27343216Sbostic register idlptr idl;
27443216Sbostic register nodelptr nl;
27543216Sbostic
27643216Sbostic for(idl=nodep->headdeplist;idl;idl=idl->next)
27743216Sbostic if(idl->idp->idaddr->tag == TADDR ||
27843216Sbostic idl->idp->idaddr->tag == TTEMP)
27943216Sbostic {
28043216Sbostic nl=ALLOC(NODElist);
28143216Sbostic nl->nodep = nodep;
28243216Sbostic nl->next = idl->idp->headnodelist;
28343216Sbostic idl->idp->headnodelist = nl;
28443216Sbostic }
28543216Sbostic }
28643216Sbostic
28743216Sbostic
28843216Sbostic
addadep(idp,nodep)28943216Sbostic LOCAL idlptr addadep(idp,nodep)
29043216Sbostic idptr idp;
29143216Sbostic valuen nodep;
29243216Sbostic /* Add an identifier to the dependents list of a value node. Dependents
29343216Sbostic ** lists are ordered by increasing idp value
29443216Sbostic */
29543216Sbostic {
29643216Sbostic register idlptr lp1,lp2;
29743216Sbostic
29843216Sbostic lp2 = ALLOC(IDlist);
29943216Sbostic lp2->idp = idp;
30043216Sbostic if(nodep->headdeplist == 0) {
30143216Sbostic lp2->next = 0;
30243216Sbostic nodep->headdeplist = lp2;
30343216Sbostic }
30443216Sbostic else if(idp <= nodep->headdeplist->idp) {
30543216Sbostic lp2->next = nodep->headdeplist;
30643216Sbostic nodep->headdeplist = lp2;
30743216Sbostic }
30843216Sbostic else for(lp1 = nodep->headdeplist; lp1; lp1 = lp1->next)
30943216Sbostic if( (lp1->next == 0) || (idp <= lp1->next->idp) )
31043216Sbostic {
31143216Sbostic lp2->next = lp1->next;
31243216Sbostic lp1->next = lp2;
31343216Sbostic break;
31443216Sbostic }
31543216Sbostic return(lp2);
31643216Sbostic }
31743216Sbostic
31843216Sbostic
31943216Sbostic
newnode(expr,left,right,rslt)32043216Sbostic LOCAL valuen newnode(expr,left,right,rslt)
32143216Sbostic expptr expr;
32243216Sbostic valuen left,right,rslt;
32343216Sbostic /* Build a new value node
32443216Sbostic */
32543216Sbostic {
32643216Sbostic register valuen p;
32743216Sbostic
32843216Sbostic p= ALLOC(VALUEnode);
32943216Sbostic p->opp = expr ;
33043216Sbostic p->parent = NULL ;
33143216Sbostic p->lc = left;
33243216Sbostic p->rc = right;
33343216Sbostic p->rs = rslt;
33443216Sbostic p->n_dups = 0;
33543216Sbostic p->is_dead = FALSE;
33643216Sbostic p->next=NULL;
33743216Sbostic p->headdeplist = mergedeps(left,right);
33843216Sbostic p->headduplist=NULL;
33943216Sbostic if(current_BB->headnode == 0) current_BB->headnode=p;
34043216Sbostic else if(current_BB->tailnode) current_BB->tailnode->next=p;
34143216Sbostic current_BB->tailnode=p;
34243216Sbostic
34343216Sbostic return(p);
34443216Sbostic }
34543216Sbostic
34643216Sbostic
34743216Sbostic
newid(idaddr,addrof_idptr)34843216Sbostic LOCAL newid(idaddr,addrof_idptr)
34943216Sbostic expptr idaddr;
35043216Sbostic idptr *addrof_idptr;
35143216Sbostic /* Build a new IDblock and hook it on the current BB's ID list
35243216Sbostic */
35343216Sbostic {
35443216Sbostic register idptr p;
35543216Sbostic
35643216Sbostic p= ALLOC(IDblock);
35743216Sbostic
35843216Sbostic /* build a leaf value node for the identifier and put the ID on the leaf node's
35943216Sbostic ** list of dependent identifiers
36043216Sbostic */
36143216Sbostic p->initval = newnode(idaddr,NULL,NULL,NULL);
36243216Sbostic p->initval->rs = p->initval;
36343216Sbostic addadep(p,p->initval);
36443216Sbostic
36543216Sbostic p->idaddr = idaddr;
36643216Sbostic *addrof_idptr = p;
36743216Sbostic p->headnodelist=NULL;
36843216Sbostic p->next=NULL;
36943216Sbostic
37043216Sbostic }
37143216Sbostic
37243216Sbostic
37343216Sbostic
addadup(parent,nodep)37443216Sbostic LOCAL addadup(parent,nodep)
37543216Sbostic expptr *parent;
37643216Sbostic valuen nodep;
37743216Sbostic
37843216Sbostic /* A subtree has been found that duplicates the calculation represented
37943216Sbostic ** by the value node referenced by nodep : add the root of the reduntant
38043216Sbostic ** tree to the value node's list of duplicates.
38143216Sbostic */
38243216Sbostic
38343216Sbostic {
38443216Sbostic register duplptr dp;
38543216Sbostic valuen child;
38643216Sbostic
38743216Sbostic dp = ALLOC(DUPlist);
38843216Sbostic dp->parent = parent;
38943216Sbostic dp->next = nodep->headduplist;
39043216Sbostic nodep->headduplist = dp;
39143216Sbostic ++nodep->n_dups;
39243216Sbostic
39343216Sbostic /* Check whether either of nodep's children is also a duplicate calculation
39443216Sbostic ** and if so peel off it's most recent dup record
39543216Sbostic */
39643216Sbostic
39743216Sbostic if ( (child = nodep->lc) && (child->n_dups) )
39843216Sbostic {
39943216Sbostic dp = child->headduplist;
40043216Sbostic child->headduplist = dp->next;
40143216Sbostic free ( (charptr) dp );
40243216Sbostic --child->n_dups;
40343216Sbostic }
40443216Sbostic if ( (child = nodep->rc) && (child->n_dups) )
40543216Sbostic {
40643216Sbostic dp = child->headduplist;
40743216Sbostic child->headduplist = dp->next;
40843216Sbostic free ( (charptr) dp );
40943216Sbostic --child->n_dups;
41043216Sbostic }
41143216Sbostic
41243216Sbostic }
41343216Sbostic
41443216Sbostic
41543216Sbostic
samebase(ep1,ep2)41643216Sbostic LOCAL samebase(ep1,ep2)
41743216Sbostic expptr ep1,ep2;
41843216Sbostic {
41943216Sbostic if ( ep1->tag == ep2->tag )
42043216Sbostic switch (ep2->tag) {
42143216Sbostic case TTEMP :
42243216Sbostic if (ep1->tempblock.memalloc == ep2->tempblock.memalloc)
42343216Sbostic return (TRUE);
42443216Sbostic break;
42543216Sbostic case TADDR :
42643216Sbostic if (ep1->addrblock.vstg == ep2->addrblock.vstg) {
42743216Sbostic switch(ep1->addrblock.vstg) {
42843216Sbostic case STGEQUIV:
42943216Sbostic case STGCOMMON:
43043216Sbostic if (ep1->addrblock.memno == ep2->addrblock.memno &&
43143216Sbostic ISCONST(ep1->addrblock.memoffset) &&
43243216Sbostic ISCONST(ep2->addrblock.memoffset) &&
43346305Sbostic ep1->addrblock.memoffset->constblock.constant.ci ==
43446305Sbostic ep2->addrblock.memoffset->constblock.constant.ci ) {
43543216Sbostic return(TRUE);
43643216Sbostic }
43743216Sbostic break;
43843216Sbostic
43943216Sbostic default:
44043216Sbostic if (ep1->addrblock.memno == ep2->addrblock.memno ) {
44143216Sbostic return(TRUE);
44243216Sbostic }
44343216Sbostic }
44443216Sbostic }
44543216Sbostic break;
44643216Sbostic case TCONST :
44743216Sbostic if( (ep1->constblock.vtype) ==
44843216Sbostic (ep2->constblock.vtype) )
44943216Sbostic {
45043216Sbostic union Constant *ap,*bp;
45146305Sbostic ap= &ep1->constblock.constant;
45246305Sbostic bp= &ep2->constblock.constant;
45343216Sbostic switch(ep1->constblock.vtype)
45443216Sbostic
45543216Sbostic {
45643216Sbostic case TYSHORT:
45743216Sbostic case TYLONG:
45843216Sbostic if(ap->ci == bp->ci) return(TRUE);
45943216Sbostic break;
46043216Sbostic case TYREAL:
46143216Sbostic case TYDREAL:
46243216Sbostic if(ap->cd[0] == bp->cd[0]) return(TRUE);
46343216Sbostic break;
46443216Sbostic case TYCOMPLEX:
46543216Sbostic case TYDCOMPLEX:
46643216Sbostic if(ap->cd[0] == bp->cd[0] &&
46743216Sbostic ap->cd[1] == bp->cd[1] )
46843216Sbostic return(TRUE);
46943216Sbostic break;
47043216Sbostic }
47143216Sbostic }
47243216Sbostic break;
47343216Sbostic
47443216Sbostic default :
47543216Sbostic badtag ("samebase",ep2->tag);
47643216Sbostic }
47743216Sbostic return(FALSE);
47843216Sbostic }
47943216Sbostic
48043216Sbostic
48143216Sbostic
findid(idaddr)48243216Sbostic LOCAL idptr findid(idaddr)
48343216Sbostic expptr idaddr;
48443216Sbostic
48543216Sbostic /* Find an identifier's IDblock given its idaddr. If the identifier has no
48643216Sbostic ** IBblock build one
48743216Sbostic */
48843216Sbostic
48943216Sbostic {
49043216Sbostic register idptr idp;
49143216Sbostic if(current_BB->headid == 0) newid(idaddr,¤t_BB->headid);
49243216Sbostic idp=current_BB->headid;
49343216Sbostic
49443216Sbostic do {
49543216Sbostic if (samebase(idp->idaddr,idaddr) ) break;
49643216Sbostic if (idp->next == 0) {
49743216Sbostic newid(idaddr,&idp->next);
49843216Sbostic idp = idp->next;
49943216Sbostic break;
50043216Sbostic }
50143216Sbostic idp = idp->next;
50243216Sbostic }
50343216Sbostic while(TRUE);
50443216Sbostic
50543216Sbostic return(idp);
50643216Sbostic }
50743216Sbostic
50843216Sbostic
50943216Sbostic
findnode(ep,leftc,rightc)51043216Sbostic LOCAL valuen findnode(ep,leftc,rightc)
51143216Sbostic expptr ep;
51243216Sbostic valuen leftc,rightc;
51343216Sbostic {
51443216Sbostic /* Look for a matching value node in the available computations stack
51543216Sbostic */
51643216Sbostic register valuen p;
51743216Sbostic
51843216Sbostic for ( p=current_BB->headnode; p ; p=p->next) {
51943216Sbostic if( ( ! p->is_dead) &&
52043216Sbostic (p->lc == leftc) &&
52143216Sbostic (p->rc == rightc) &&
52243216Sbostic ( (ep->tag == TEXPR && p->opp->tag == TEXPR
52343216Sbostic && p->opp->exprblock.opcode == ep->exprblock.opcode
52443216Sbostic && p->opp->exprblock.vtype == ep->exprblock.vtype
52543216Sbostic )
52643216Sbostic || (ep->tag == TADDR) || (ep->tag == TTEMP)
52743216Sbostic )
52843216Sbostic )
52943216Sbostic return(p);
53043216Sbostic }
53143216Sbostic return(NULL);
53243216Sbostic }
53343216Sbostic
53443216Sbostic
53543216Sbostic
scanchain(listp,p_parent)53643216Sbostic LOCAL valuen scanchain(listp,p_parent)
53743216Sbostic expptr listp;
53843216Sbostic chainp *p_parent;
53943216Sbostic
54043216Sbostic /* Make value nodes from the chain hanging off a LISTBLOCK
54143216Sbostic */
54243216Sbostic
54343216Sbostic {
54443216Sbostic valuen lnode,rnode,new,scantree();
54543216Sbostic chainp p;
54643216Sbostic
54743216Sbostic p= *p_parent;
54843216Sbostic if (p == NULL) return(NULL);
54943216Sbostic lnode = scantree( &p->datap);
55043216Sbostic rnode = scanchain(listp, &p->nextp);
55143216Sbostic new = newnode(listp,lnode,rnode,0);
55243216Sbostic new->rs = new;
55343216Sbostic return(new->rs);
55443216Sbostic }
55543216Sbostic
55643216Sbostic
55743216Sbostic
scantree(p_parent)55843216Sbostic LOCAL valuen scantree(p_parent)
55943216Sbostic expptr *p_parent;
56043216Sbostic
56143216Sbostic /* build a value node and return its address. p must point to an
56243216Sbostic ** exprblock an addrblock a listblock or a constblock.
56343216Sbostic */
56443216Sbostic
56543216Sbostic {
56643216Sbostic valuen lnode, rnode,rsltnode,new;
56743216Sbostic expptr opp,p;
56843216Sbostic Exprp ep1,ep2;
56943216Sbostic idptr idp;
57043216Sbostic
57143216Sbostic p = *p_parent;
57243216Sbostic if(p == NULL) return(NULL);
57343216Sbostic
57443216Sbostic switch (p->tag) {
57543216Sbostic case TCONST :
57643216Sbostic return( findid(p)->initval );
57743216Sbostic
57843216Sbostic case TTEMP :
57943216Sbostic idp = findid(p);
58043216Sbostic if(idp->assgnval) return(idp->assgnval);
58143216Sbostic
58243216Sbostic lnode = idp->initval;
58343216Sbostic rnode = scantree( &p->tempblock.memalloc);
58443216Sbostic
58543216Sbostic rsltnode = findnode(p,lnode,rnode);
58643216Sbostic if(rsltnode)
58743216Sbostic return(rsltnode);
58843216Sbostic else {
58943216Sbostic new = newnode(p,lnode,rnode,0);
59043216Sbostic new->rs = new;
59143216Sbostic new->parent = p_parent;
59243216Sbostic return(new->rs);
59343216Sbostic }
59443216Sbostic
59543216Sbostic case TADDR :
59643216Sbostic idp = findid(p);
59743216Sbostic if(idp->assgnval) return(idp->assgnval);
59843216Sbostic
59943216Sbostic lnode = idp->initval;
60043216Sbostic rnode = scantree( &p->addrblock.memoffset);
60143216Sbostic
60243216Sbostic rsltnode = findnode(p,lnode,rnode);
60343216Sbostic if(rsltnode) {
60443216Sbostic #ifdef notdef
60543216Sbostic /*
60643216Sbostic * This code is broken until OPINDIRECT is implemented.
60743216Sbostic */
60843216Sbostic if(p->addrblock.memoffset != NULL &&
60943216Sbostic p->addrblock.memoffset->tag == TEXPR)
61043216Sbostic addadup(p_parent,rsltnode);
61143216Sbostic #endif notdef
61243216Sbostic return(rsltnode);
61343216Sbostic }
61443216Sbostic else {
61543216Sbostic new = newnode(p,lnode,rnode,0);
61643216Sbostic new->rs = new;
61743216Sbostic new->parent = p_parent;
61843216Sbostic return(new->rs);
61943216Sbostic }
62043216Sbostic
62143216Sbostic case TLIST :
62243216Sbostic return(scanchain(p->listblock.listp,&p->listblock.listp));
62343216Sbostic
62443216Sbostic default :
62543216Sbostic badtag ("scantree",p->tag);
62643216Sbostic
62743216Sbostic case TEXPR :
62843216Sbostic lnode = scantree(&p->exprblock.leftp);
62943216Sbostic rnode = scantree(&p->exprblock.rightp);
63043216Sbostic
63143216Sbostic switch (p->exprblock.opcode) {
63243216Sbostic case OPASSIGN :
63343216Sbostic {
63443216Sbostic Addrp ap;
63543216Sbostic
63643216Sbostic ap = (Addrp) p->exprblock.leftp;
63743216Sbostic idp = findid(ap);
63843216Sbostic killdepnodes(idp);
63943216Sbostic if( ! ap->isarray ) {
64043216Sbostic if(rnode->is_dead)idp->assgnval=idp->initval;
64143216Sbostic else idp->assgnval = rnode;
64243216Sbostic }
64343216Sbostic new = newnode(p,idp->initval,NULL,NULL);
64443216Sbostic appendnode(new);
64543216Sbostic new->rs = new;
64643216Sbostic return(new->rs);
64743216Sbostic }
64843216Sbostic
64943216Sbostic /*
65043216Sbostic * Don't optimize these... they're a real hassle.
65143216Sbostic */
65243216Sbostic case OPPLUSEQ :
65343216Sbostic case OPSTAREQ :
65443216Sbostic {
65543216Sbostic Addrp ap;
65643216Sbostic
65743216Sbostic ap = (Addrp) p->exprblock.leftp;
65843216Sbostic idp = findid(ap);
65943216Sbostic killdepnodes(idp);
66043216Sbostic idp->assgnval = NULL;
66143216Sbostic new = newnode(p,lnode,rnode,NULL);
66243216Sbostic new->rs = new;
66343216Sbostic return(new->rs);
66443216Sbostic }
66543216Sbostic
66643216Sbostic case OPCALL :
66743216Sbostic {
66843216Sbostic chainp cp;
66943216Sbostic
67043216Sbostic if(p->exprblock.rightp)
67143216Sbostic
67243216Sbostic /* pretend that all variables on the arglist have just
67343216Sbostic ** been assigned to i.e. kill of calculations that
67443216Sbostic ** depend on them. Not necessary for CCALL(by value)
67543216Sbostic */
67643216Sbostic
67743216Sbostic for(cp=p->exprblock.rightp->listblock.listp;
67843216Sbostic cp;cp=cp->nextp)
67943216Sbostic if (cp->datap->tag == TADDR ||
68043216Sbostic cp->datap->tag == TTEMP){
68143216Sbostic idp = findid(cp->datap);
68243216Sbostic killdepnodes(idp);
68343216Sbostic idp->assgnval = NULL;
68443216Sbostic }
68543216Sbostic
68643216Sbostic new = newnode(p,lnode,rnode,NULL);
68743216Sbostic new->rs = new;
68843216Sbostic return(new->rs);
68943216Sbostic }
69043216Sbostic
69143216Sbostic case OPCONCAT:
69243216Sbostic case OPADDR:
69343216Sbostic case OPCOLON:
69443216Sbostic case OPINDIRECT:
69543216Sbostic /*
69643216Sbostic * For now, do not optimize LSHIFT until OPINDIRECT
69743216Sbostic * implemented.
69843216Sbostic */
69943216Sbostic case OPLSHIFT:
70043216Sbostic new = newnode(p,lnode,rnode,NULL);
70143216Sbostic new->rs = new;
70243216Sbostic return(new->rs);
70343216Sbostic
70443216Sbostic case OPCOMMA:
70543216Sbostic badop ("scantree",OPCOMMA);
70643216Sbostic break;
70743216Sbostic
70843216Sbostic default :
70943216Sbostic rsltnode = findnode(p,lnode,rnode);
71043216Sbostic if (rsltnode) {
71143216Sbostic addadup(p_parent,rsltnode);
71243216Sbostic return(rsltnode);
71343216Sbostic }
71443216Sbostic else {
71543216Sbostic new = newnode(p,lnode,rnode,NULL);
71643216Sbostic new->rs = new;
71743216Sbostic new->parent = p_parent;
71843216Sbostic appendnode(new);
71943216Sbostic return(new->rs);
72043216Sbostic }
72143216Sbostic }
72243216Sbostic }
72343216Sbostic }
72443216Sbostic
72543216Sbostic
72643216Sbostic
prunetrees()72743216Sbostic LOCAL prunetrees()
72843216Sbostic
72943216Sbostic /* The only optcse.c routine that does any real work: go through the available
73043216Sbostic ** computations stack and eliminate redundant subtrees.
73143216Sbostic */
73243216Sbostic
73343216Sbostic {
73443216Sbostic Addrp tempv;
73543216Sbostic register duplptr dl;
73643216Sbostic register valuen p;
73743216Sbostic expptr t;
73843216Sbostic int is_addrnode;
73943216Sbostic expptr *addr_tree1 = NULL ;
74043216Sbostic expptr tree2 = NULL ;
74143216Sbostic
74243216Sbostic for(p=current_BB->headnode;p;p=p->next)
74343216Sbostic {
74443216Sbostic if(p->rs == NULL) {
74543216Sbostic if( addr_tree1 && tree2 )
74643216Sbostic *addr_tree1 = fixtype(mkexpr(OPCOMMA,tree2,*addr_tree1));
74743216Sbostic addr_tree1 = (expptr*) p->opp;
74843216Sbostic tree2 = NULL;
74943216Sbostic }
75043216Sbostic if (p->n_dups ) {
75143216Sbostic
75243216Sbostic if (p->opp->tag == TTEMP)
75343216Sbostic fprintf(diagfile,"TTEMP in prunetrees - cbb\n");
75443216Sbostic if(p->opp->tag == TADDR) is_addrnode = TRUE;
75543216Sbostic else is_addrnode = FALSE;
75643216Sbostic
75743216Sbostic if (is_addrnode)
75843216Sbostic tempv = mktemp(TYADDR,NULL);
75943216Sbostic else
76043216Sbostic tempv = mktemp(p->opp->exprblock.vtype,
76143216Sbostic p->opp->exprblock.vleng);
76243216Sbostic cse2count++;
76343216Sbostic
76443216Sbostic if(tree2)
76543216Sbostic tree2 = fixtype(mkexpr(OPCOMMA,tree2,
76643216Sbostic fixtype(mkexpr(OPASSIGN,cpexpr(tempv),
76743216Sbostic (is_addrnode ? addrof(p->opp) : p->opp)
76843216Sbostic ))));
76943216Sbostic else
77043216Sbostic tree2 = fixtype(mkexpr(OPASSIGN,cpexpr(tempv),
77143216Sbostic (is_addrnode ? addrof(p->opp) : p->opp)
77243216Sbostic ));
77343216Sbostic
77443216Sbostic if(is_addrnode)
77543216Sbostic *(p->parent) = fixtype(mkexpr(OPINDIRECT,cpexpr(tempv), NULL));
77643216Sbostic else
77743216Sbostic *(p->parent) = (expptr) cpexpr(tempv);
77843216Sbostic
77943216Sbostic /* then replaces all future instances of the calculation by references to
78043216Sbostic the temporary */
78143216Sbostic
78243216Sbostic for(dl=p->headduplist;dl->next;dl=dl->next) {
78343216Sbostic cse1count++;
78443216Sbostic frexpr(*dl->parent);
78543216Sbostic if(is_addrnode)
78643216Sbostic *(dl->parent) = fixtype(
78743216Sbostic mkexpr(OPINDIRECT,cpexpr(tempv), NULL));
78843216Sbostic else
78943216Sbostic *(dl->parent) = (expptr) cpexpr(tempv);
79043216Sbostic }
79143216Sbostic
79243216Sbostic /* the last reference does not use a copy since the temporary can
79343216Sbostic now be freed */
79443216Sbostic
79543216Sbostic cse1count++;
79643216Sbostic frexpr(*dl->parent);
79743216Sbostic if(is_addrnode)
79843216Sbostic *(dl->parent) = fixtype(mkexpr(OPINDIRECT,tempv, NULL));
79943216Sbostic else
80043216Sbostic *(dl->parent) = (expptr) tempv;
80143216Sbostic
80243216Sbostic frtemp (tempv);
80343216Sbostic }
80443216Sbostic }
80543216Sbostic if(addr_tree1 && tree2)
80643216Sbostic *addr_tree1 = fixtype(mkexpr(OPCOMMA,tree2,*addr_tree1));
80743216Sbostic }
80843216Sbostic
80943216Sbostic
81043216Sbostic
rewritebb(bb)81143216Sbostic LOCAL rewritebb (bb)
81243216Sbostic Bblockp bb;
81343216Sbostic {
81443216Sbostic Slotp sp;
81543216Sbostic expptr p;
81643216Sbostic
81743216Sbostic if (bb == NULL)
81843216Sbostic return;
81943216Sbostic else
82043216Sbostic current_BB = bb;
82143216Sbostic sp = current_BB->first;
82243216Sbostic
82343216Sbostic /* loop trough all BB slots and scan candidate expr trees when found */
82443216Sbostic
82543216Sbostic for (sp = current_BB->first; ; sp = sp->next)
82643216Sbostic {
82743216Sbostic switch (sp->type)
82843216Sbostic {
82943216Sbostic case SKEQ :
83043216Sbostic case SKIFN :
83143216Sbostic case SKCMGOTO :
83243216Sbostic case SKCALL :
83343216Sbostic newnode((expptr) &sp->expr,NULL,NULL,NULL);
83443216Sbostic scantree(&sp->expr);
83543216Sbostic break;
83643216Sbostic
83743216Sbostic default :
83843216Sbostic break;
83943216Sbostic }
84043216Sbostic if (sp == current_BB->last) break;
84143216Sbostic }
84243216Sbostic
84343216Sbostic /* use the information built up by scantree to prune reduntant subtrees */
84443216Sbostic prunetrees();
84543216Sbostic
84643216Sbostic current_BB = NULL;
84743216Sbostic }
84843216Sbostic
84943216Sbostic
85043216Sbostic
85143216Sbostic /*
85243216Sbostic * removes all instances of OPCOMMA from the given subexpression of
85343216Sbostic * the given buffer slot
85443216Sbostic */
85543216Sbostic
rmcommaop(p,sl)85643216Sbostic expptr rmcommaop (p,sl)
85743216Sbostic expptr p;
85843216Sbostic Slotp sl;
85943216Sbostic
86043216Sbostic {
86143216Sbostic expptr leftp,rightp;
86243216Sbostic chainp cp;
86343216Sbostic
86443216Sbostic if (!p)
86543216Sbostic return (ENULL);
86643216Sbostic switch (p->tag)
86743216Sbostic {
86843216Sbostic case TEXPR:
86943216Sbostic leftp = p->exprblock.leftp;
87043216Sbostic rightp = p->exprblock.rightp;
87143216Sbostic leftp = rmcommaop (leftp,sl);
87243216Sbostic if (p->exprblock.opcode == OPCOMMA)
87343216Sbostic {
87443216Sbostic optinsert (SKEQ,leftp,0,0,sl);
87543216Sbostic if (p->exprblock.vleng)
87643216Sbostic free ((charptr) p->exprblock.vleng);
87743216Sbostic free ((charptr) p);
87843216Sbostic p = rmcommaop (rightp,sl);
87943216Sbostic return (p);
88043216Sbostic }
88143216Sbostic p->exprblock.leftp = leftp;
88243216Sbostic p->exprblock.rightp = rmcommaop (rightp,sl);
88343216Sbostic return (p);
88443216Sbostic
88543216Sbostic case TLIST:
88643216Sbostic for (cp = p->listblock.listp; cp; cp = cp->nextp)
88743216Sbostic cp->datap = (tagptr) rmcommaop (cp->datap,sl);
88843216Sbostic return (p);
88943216Sbostic
89043216Sbostic case TADDR:
89143216Sbostic p->addrblock.memoffset = rmcommaop (p->addrblock.memoffset,sl);
89243216Sbostic return (p);
89343216Sbostic
89443216Sbostic default:
89543216Sbostic return (p);
89643216Sbostic }
89743216Sbostic }
89843216Sbostic
89943216Sbostic
90043216Sbostic
90143216Sbostic /*
90243216Sbostic * scans the code buffer, performing common subexpression elimination
90343216Sbostic */
90443216Sbostic
optcse()90543216Sbostic optcse ()
90643216Sbostic
90743216Sbostic {
90843216Sbostic Slotp sl;
90943216Sbostic Bblockp bb;
91043216Sbostic
91143216Sbostic if (debugflag[13])
91243216Sbostic return;
91343216Sbostic
91443216Sbostic cse1count = 0;
91543216Sbostic cse2count = 0;
91643216Sbostic for (sl = firstslot; sl; sl = sl->next)
91743216Sbostic sl->expr = rmcommaop (sl->expr,sl);
91843216Sbostic for (bb = firstblock; bb; bb = bb->next)
91943216Sbostic rewritebb (bb);
92043216Sbostic
92143216Sbostic if (debugflag[0])
92243216Sbostic fprintf (diagfile,
92343216Sbostic "%d common subexpression use%s eliminated (%d definition%s)\n",
92443216Sbostic cse1count, (cse1count==1 ? "" : "s"),
92543216Sbostic cse2count, (cse2count==1 ? "" : "s"));
92643216Sbostic }
927