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,&current_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