summaryrefslogtreecommitdiff
path: root/usr.bin/pcc/mip/optim2.c
diff options
context:
space:
mode:
Diffstat (limited to 'usr.bin/pcc/mip/optim2.c')
-rw-r--r--usr.bin/pcc/mip/optim2.c882
1 files changed, 882 insertions, 0 deletions
diff --git a/usr.bin/pcc/mip/optim2.c b/usr.bin/pcc/mip/optim2.c
new file mode 100644
index 00000000000..fcf367eb412
--- /dev/null
+++ b/usr.bin/pcc/mip/optim2.c
@@ -0,0 +1,882 @@
+/* $Id: optim2.c,v 1.1 2007/09/15 18:12:36 otto Exp $ */
+/*
+ * Copyright (c) 2004 Anders Magnusson (ragge@ludd.luth.se).
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "pass2.h"
+
+#include <string.h>
+#include <stdlib.h>
+
+#ifndef MIN
+#define MIN(a,b) (((a)<(b))?(a):(b))
+#endif
+
+#ifndef MAX
+#define MAX(a,b) (((a) > (b)) ? (a) : (b))
+#endif
+
+#define BDEBUG(x) if (b2debug) printf x
+
+static int dfsnum;
+
+void saveip(struct interpass *ip);
+void deljumps(struct interpass *);
+void optdump(struct interpass *ip);
+void printip(struct interpass *pole);
+
+static struct varinfo defsites;
+struct interpass *storesave;
+static struct interpass_prolog *ipp, *epp; /* prolog/epilog */
+
+void bblocks_build(struct interpass *, struct labelinfo *, struct bblockinfo *);
+void cfg_build(struct labelinfo *labinfo);
+void cfg_dfs(struct basicblock *bb, unsigned int parent,
+ struct bblockinfo *bbinfo);
+void dominators(struct bblockinfo *bbinfo);
+struct basicblock *
+ancestorwithlowestsemi(struct basicblock *bblock, struct bblockinfo *bbinfo);
+void link(struct basicblock *parent, struct basicblock *child);
+void computeDF(struct basicblock *bblock, struct bblockinfo *bbinfo);
+void findTemps(struct interpass *ip);
+void placePhiFunctions(struct bblockinfo *bbinfo);
+void remunreach(void);
+
+struct basicblock bblocks;
+int nbblocks;
+static struct interpass *cvpole;
+
+struct addrof {
+ struct addrof *next;
+ int tempnum;
+ int oregoff;
+} *otlink;
+
+static int
+getoff(int num)
+{
+ struct addrof *w;
+
+ for (w = otlink; w; w = w->next)
+ if (w->tempnum == num)
+ return w->oregoff;
+ return 0;
+}
+
+/*
+ * Use stack argument addresses instead of copying if & is used on a var.
+ */
+static int
+setargs(int tval, struct addrof *w)
+{
+ struct interpass *ip;
+ NODE *p;
+
+ ip = DLIST_NEXT(cvpole, qelem); /* PROLOG */
+ ip = DLIST_NEXT(ip, qelem); /* first DEFLAB */
+ ip = DLIST_NEXT(ip, qelem); /* first NODE */
+ for (; ip->type != IP_DEFLAB; ip = DLIST_NEXT(ip, qelem)) {
+ p = ip->ip_node;
+#ifdef PCC_DEBUG
+ if (p->n_op != ASSIGN || p->n_left->n_op != TEMP)
+ comperr("temparg");
+#endif
+ if (p->n_right->n_op != OREG)
+ continue; /* arg in register */
+ if (tval != p->n_left->n_lval)
+ continue; /* wrong assign */
+ w->oregoff = p->n_right->n_lval;
+ tfree(p);
+ DLIST_REMOVE(ip, qelem);
+ return 1;
+ }
+ return 0;
+}
+
+/*
+ * Search for ADDROF elements and, if found, record them.
+ */
+static void
+findaddrof(NODE *p)
+{
+ struct addrof *w;
+
+ if (p->n_op != ADDROF)
+ return;
+ if (getoff(p->n_left->n_lval))
+ return;
+ w = tmpalloc(sizeof(struct addrof));
+ w->tempnum = p->n_left->n_lval;
+ if (setargs(p->n_left->n_lval, w) == 0)
+ w->oregoff = BITOOR(freetemp(szty(p->n_left->n_type)));
+ w->next = otlink;
+ otlink = w;
+}
+
+
+/*
+ * Convert address-taken temps to OREGs.
+ */
+static void
+cvtaddrof(NODE *p)
+{
+ NODE *l;
+ int n;
+
+ if (p->n_op != ADDROF && p->n_op != TEMP)
+ return;
+ if (p->n_op == TEMP) {
+ n = getoff(p->n_lval);
+ if (n == 0)
+ return;
+ p->n_op = OREG;
+ p->n_lval = n;
+ p->n_rval = FPREG;
+ } else {
+ l = p->n_left;
+ l->n_type = p->n_type;
+ p->n_right = mklnode(ICON, l->n_lval, 0, l->n_type);
+ p->n_op = PLUS;
+ l->n_op = REG;
+ l->n_lval = 0;
+ l->n_rval = FPREG;
+
+ }
+}
+
+void
+optimize(struct interpass *ipole)
+{
+ struct interpass *ip;
+ struct labelinfo labinfo;
+ struct bblockinfo bbinfo;
+
+ ipp = (struct interpass_prolog *)DLIST_NEXT(ipole, qelem);
+ epp = (struct interpass_prolog *)DLIST_PREV(ipole, qelem);
+
+ if (b2debug) {
+ printf("initial links\n");
+ printip(ipole);
+ }
+
+ /*
+ * Convert ADDROF TEMP to OREGs.
+ */
+ if (xtemps) {
+ otlink = NULL;
+ cvpole = ipole;
+ DLIST_FOREACH(ip, ipole, qelem) {
+ if (ip->type != IP_NODE)
+ continue;
+ walkf(ip->ip_node, findaddrof);
+ }
+ if (otlink) {
+ DLIST_FOREACH(ip, ipole, qelem) {
+ if (ip->type != IP_NODE)
+ continue;
+ walkf(ip->ip_node, cvtaddrof);
+ }
+ }
+ }
+
+ if (xdeljumps)
+ deljumps(ipole); /* Delete redundant jumps and dead code */
+
+#ifdef PCC_DEBUG
+ if (b2debug) {
+ printf("links after deljumps\n");
+ printip(ipole);
+ }
+#endif
+ if (xssaflag || xtemps) {
+ DLIST_INIT(&bblocks, bbelem);
+ bblocks_build(ipole, &labinfo, &bbinfo);
+ BDEBUG(("Calling cfg_build\n"));
+ cfg_build(&labinfo);
+ }
+ if (xssaflag) {
+ BDEBUG(("Calling dominators\n"));
+ dominators(&bbinfo);
+ BDEBUG(("Calling computeDF\n"));
+ computeDF(DLIST_NEXT(&bblocks, bbelem), &bbinfo);
+ BDEBUG(("Calling remunreach\n"));
+ remunreach();
+#if 0
+ dfg = dfg_build(cfg);
+ ssa = ssa_build(cfg, dfg);
+#endif
+ }
+
+#ifdef PCC_DEBUG
+ if (epp->ipp_regs != 0)
+ comperr("register error");
+#endif
+
+#ifdef MYOPTIM
+ myoptim((struct interpass *)ipp);
+#endif
+}
+
+/*
+ * Delete unused labels, excess of labels, gotos to gotos.
+ * This routine can be made much more efficient.
+ */
+void
+deljumps(struct interpass *ipole)
+{
+ struct interpass *ip, *n, *ip2;
+ int gotone,low, high;
+ int *lblary, sz, o, i;
+
+ low = ipp->ip_lblnum;
+ high = epp->ip_lblnum;
+
+#ifdef notyet
+ mark = tmpmark(); /* temporary used memory */
+#endif
+
+ sz = (high-low) * sizeof(int);
+ lblary = tmpalloc(sz);
+
+again: gotone = 0;
+ memset(lblary, 0, sz);
+
+ /* refcount and coalesce all labels */
+ DLIST_FOREACH(ip, ipole, qelem) {
+ if (ip->type == IP_DEFLAB) {
+ n = DLIST_NEXT(ip, qelem);
+ while (n->type == IP_DEFLAB) {
+ if (n->type == IP_DEFLAB &&
+ lblary[n->ip_lbl-low] >= 0)
+ lblary[n->ip_lbl-low] = -ip->ip_lbl;
+ n = DLIST_NEXT(n, qelem);
+ }
+ }
+ if (ip->type != IP_NODE)
+ continue;
+ o = ip->ip_node->n_op;
+ if (o == GOTO)
+ i = ip->ip_node->n_left->n_lval;
+ else if (o == CBRANCH)
+ i = ip->ip_node->n_right->n_lval;
+ else
+ continue;
+ lblary[i-low] |= 1;
+ }
+
+ /* delete coalesced/unused labels and rename gotos */
+ DLIST_FOREACH(ip, ipole, qelem) {
+ n = DLIST_NEXT(ip, qelem);
+ if (n->type == IP_DEFLAB) {
+ if (lblary[n->ip_lbl-low] <= 0) {
+ DLIST_REMOVE(n, qelem);
+ gotone = 1;
+ }
+ continue;
+ }
+ if (n->type != IP_NODE)
+ continue;
+ o = n->ip_node->n_op;
+ if (o == GOTO)
+ i = n->ip_node->n_left->n_lval;
+ else if (o == CBRANCH)
+ i = n->ip_node->n_right->n_lval;
+ else
+ continue;
+ if (lblary[i-low] < 0) {
+ if (o == GOTO)
+ n->ip_node->n_left->n_lval = -lblary[i-low];
+ else
+ n->ip_node->n_right->n_lval = -lblary[i-low];
+ }
+ }
+
+ /* Delete gotos to the next statement */
+ DLIST_FOREACH(ip, ipole, qelem) {
+ n = DLIST_NEXT(ip, qelem);
+ if (n->type != IP_NODE)
+ continue;
+ o = n->ip_node->n_op;
+ if (o == GOTO)
+ i = n->ip_node->n_left->n_lval;
+ else if (o == CBRANCH)
+ i = n->ip_node->n_right->n_lval;
+ else
+ continue;
+
+ ip2 = n;
+ ip2 = DLIST_NEXT(ip2, qelem);
+
+ if (ip2->type != IP_DEFLAB)
+ continue;
+ if (ip2->ip_lbl == i) {
+ tfree(n->ip_node);
+ DLIST_REMOVE(n, qelem);
+ gotone = 1;
+ }
+ }
+
+ if (gotone)
+ goto again;
+
+#ifdef notyet
+ tmpfree(mark);
+#endif
+}
+
+void
+optdump(struct interpass *ip)
+{
+ static char *nm[] = { "node", "prolog", "newblk", "epilog", "locctr",
+ "deflab", "defnam", "asm" };
+ printf("type %s\n", nm[ip->type-1]);
+ switch (ip->type) {
+ case IP_NODE:
+ fwalk(ip->ip_node, e2print, 0);
+ break;
+ case IP_DEFLAB:
+ printf("label " LABFMT "\n", ip->ip_lbl);
+ break;
+ case IP_ASM:
+ printf(": %s\n", ip->ip_asm);
+ break;
+ }
+}
+
+/*
+ * Build the basic blocks, algorithm 9.1, pp 529 in Compilers.
+ *
+ * Also fills the labelinfo struct with information about which bblocks
+ * that contain which label.
+ */
+
+void
+bblocks_build(struct interpass *ipole, struct labelinfo *labinfo,
+ struct bblockinfo *bbinfo)
+{
+ struct interpass *ip;
+ struct basicblock *bb = NULL;
+ int low, high;
+ int count = 0;
+ int i;
+
+ BDEBUG(("bblocks_build (%p, %p)\n", labinfo, bbinfo));
+ low = ipp->ip_lblnum;
+ high = epp->ip_lblnum;
+
+ /*
+ * First statement is a leader.
+ * Any statement that is target of a jump is a leader.
+ * Any statement that immediately follows a jump is a leader.
+ */
+ DLIST_FOREACH(ip, ipole, qelem) {
+ if (bb == NULL || (ip->type == IP_EPILOG) ||
+ (ip->type == IP_DEFLAB) || (ip->type == IP_DEFNAM)) {
+ bb = tmpalloc(sizeof(struct basicblock));
+ bb->first = ip;
+ SLIST_INIT(&bb->children);
+ SLIST_INIT(&bb->parents);
+ bb->dfnum = 0;
+ bb->dfparent = 0;
+ bb->semi = 0;
+ bb->ancestor = 0;
+ bb->idom = 0;
+ bb->samedom = 0;
+ bb->bucket = NULL;
+ bb->df = NULL;
+ bb->dfchildren = NULL;
+ bb->Aorig = NULL;
+ bb->Aphi = NULL;
+ bb->bbnum = count;
+ DLIST_INSERT_BEFORE(&bblocks, bb, bbelem);
+ count++;
+ }
+ bb->last = ip;
+ if ((ip->type == IP_NODE) && (ip->ip_node->n_op == GOTO ||
+ ip->ip_node->n_op == CBRANCH))
+ bb = NULL;
+ if (ip->type == IP_PROLOG)
+ bb = NULL;
+ }
+ nbblocks = count;
+
+ if (b2debug) {
+ printf("Basic blocks in func: %d, low %d, high %d\n",
+ count, low, high);
+ DLIST_FOREACH(bb, &bblocks, bbelem) {
+ printf("bb %p: first %p last %p\n", bb,
+ bb->first, bb->last);
+ }
+ }
+
+ labinfo->low = low;
+ labinfo->size = high - low + 1;
+ labinfo->arr = tmpalloc(labinfo->size * sizeof(struct basicblock *));
+ for (i = 0; i < labinfo->size; i++) {
+ labinfo->arr[i] = NULL;
+ }
+
+ bbinfo->size = count + 1;
+ bbinfo->arr = tmpalloc(bbinfo->size * sizeof(struct basicblock *));
+ for (i = 0; i < bbinfo->size; i++) {
+ bbinfo->arr[i] = NULL;
+ }
+
+ /* Build the label table */
+ DLIST_FOREACH(bb, &bblocks, bbelem) {
+ if (bb->first->type == IP_DEFLAB)
+ labinfo->arr[bb->first->ip_lbl - low] = bb;
+ }
+
+ if (b2debug) {
+ printf("Label table:\n");
+ for (i = 0; i < labinfo->size; i++)
+ if (labinfo->arr[i])
+ printf("Label %d bblock %p\n", i+low,
+ labinfo->arr[i]);
+ }
+}
+
+/*
+ * Build the control flow graph.
+ */
+
+void
+cfg_build(struct labelinfo *labinfo)
+{
+ /* Child and parent nodes */
+ struct cfgnode *cnode;
+ struct cfgnode *pnode;
+ struct basicblock *bb;
+
+ DLIST_FOREACH(bb, &bblocks, bbelem) {
+
+ if (bb->first->type == IP_EPILOG) {
+ break;
+ }
+
+ cnode = tmpalloc(sizeof(struct cfgnode));
+ pnode = tmpalloc(sizeof(struct cfgnode));
+ pnode->bblock = bb;
+
+ if ((bb->last->type == IP_NODE) &&
+ (bb->last->ip_node->n_op == GOTO)) {
+ if (bb->last->ip_node->n_left->n_lval - labinfo->low >
+ labinfo->size) {
+ comperr("Label out of range: %d, base %d",
+ bb->last->ip_node->n_left->n_lval,
+ labinfo->low);
+ }
+ cnode->bblock = labinfo->arr[bb->last->ip_node->n_left->n_lval - labinfo->low];
+ SLIST_INSERT_LAST(&cnode->bblock->parents, pnode, cfgelem);
+ SLIST_INSERT_LAST(&bb->children, cnode, cfgelem);
+ continue;
+ }
+ if ((bb->last->type == IP_NODE) &&
+ (bb->last->ip_node->n_op == CBRANCH)) {
+ if (bb->last->ip_node->n_right->n_lval - labinfo->low >
+ labinfo->size)
+ comperr("Label out of range: %d",
+ bb->last->ip_node->n_left->n_lval);
+
+ cnode->bblock = labinfo->arr[bb->last->ip_node->n_right->n_lval - labinfo->low];
+ SLIST_INSERT_LAST(&cnode->bblock->parents, pnode, cfgelem);
+ SLIST_INSERT_LAST(&bb->children, cnode, cfgelem);
+ cnode = tmpalloc(sizeof(struct cfgnode));
+ pnode = tmpalloc(sizeof(struct cfgnode));
+ pnode->bblock = bb;
+ }
+
+ cnode->bblock = DLIST_NEXT(bb, bbelem);
+ SLIST_INSERT_LAST(&cnode->bblock->parents, pnode, cfgelem);
+ SLIST_INSERT_LAST(&bb->children, cnode, cfgelem);
+ }
+}
+
+void
+cfg_dfs(struct basicblock *bb, unsigned int parent, struct bblockinfo *bbinfo)
+{
+ struct cfgnode *cnode;
+
+ if (bb->dfnum != 0)
+ return;
+
+ bb->dfnum = ++dfsnum;
+ bb->dfparent = parent;
+ bbinfo->arr[bb->dfnum] = bb;
+ SLIST_FOREACH(cnode, &bb->children, cfgelem) {
+ cfg_dfs(cnode->bblock, bb->dfnum, bbinfo);
+ }
+ /* Don't bring in unreachable nodes in the future */
+ bbinfo->size = dfsnum + 1;
+}
+
+static bittype *
+setalloc(int nelem)
+{
+ bittype *b;
+ int sz = (nelem+NUMBITS-1)/NUMBITS;
+
+ b = tmpalloc(sz * sizeof(bittype));
+ memset(b, 0, sz * sizeof(bittype));
+ return b;
+}
+
+/*
+ * Algorithm 19.9, pp 414 from Appel.
+ */
+
+void
+dominators(struct bblockinfo *bbinfo)
+{
+ struct cfgnode *cnode;
+ struct basicblock *bb, *y, *v;
+ struct basicblock *s, *sprime, *p;
+ int h, i;
+
+ DLIST_FOREACH(bb, &bblocks, bbelem) {
+ bb->bucket = setalloc(bbinfo->size);
+ bb->df = setalloc(bbinfo->size);
+ bb->dfchildren = setalloc(bbinfo->size);
+ }
+
+ dfsnum = 0;
+ cfg_dfs(DLIST_NEXT(&bblocks, bbelem), 0, bbinfo);
+
+ if (b2debug) {
+ struct basicblock *bbb;
+ struct cfgnode *ccnode;
+
+ DLIST_FOREACH(bbb, &bblocks, bbelem) {
+ printf("Basic block %d, parents: ", bbb->dfnum);
+ SLIST_FOREACH(ccnode, &bbb->parents, cfgelem) {
+ printf("%d, ", ccnode->bblock->dfnum);
+ }
+ printf("\nChildren: ");
+ SLIST_FOREACH(ccnode, &bbb->children, cfgelem) {
+ printf("%d, ", ccnode->bblock->dfnum);
+ }
+ printf("\n");
+ }
+ }
+
+ for(h = bbinfo->size - 1; h > 1; h--) {
+ bb = bbinfo->arr[h];
+ p = s = bbinfo->arr[bb->dfparent];
+ SLIST_FOREACH(cnode, &bb->parents, cfgelem) {
+ if (cnode->bblock->dfnum <= bb->dfnum)
+ sprime = cnode->bblock;
+ else
+ sprime = bbinfo->arr[ancestorwithlowestsemi
+ (cnode->bblock, bbinfo)->semi];
+ if (sprime->dfnum < s->dfnum)
+ s = sprime;
+ }
+ bb->semi = s->dfnum;
+ BITSET(s->bucket, bb->dfnum);
+ link(p, bb);
+ for (i = 1; i < bbinfo->size; i++) {
+ if(TESTBIT(p->bucket, i)) {
+ v = bbinfo->arr[i];
+ y = ancestorwithlowestsemi(v, bbinfo);
+ if (y->semi == v->semi)
+ v->idom = p->dfnum;
+ else
+ v->samedom = y->dfnum;
+ }
+ }
+ memset(p->bucket, 0, (bbinfo->size + 7)/8);
+ }
+
+ if (b2debug) {
+ printf("Num\tSemi\tAncest\tidom\n");
+ DLIST_FOREACH(bb, &bblocks, bbelem) {
+ printf("%d\t%d\t%d\t%d\n", bb->dfnum, bb->semi,
+ bb->ancestor, bb->idom);
+ }
+ }
+
+ for(h = 2; h < bbinfo->size; h++) {
+ bb = bbinfo->arr[h];
+ if (bb->samedom != 0) {
+ bb->idom = bbinfo->arr[bb->samedom]->idom;
+ }
+ }
+ DLIST_FOREACH(bb, &bblocks, bbelem) {
+ if (bb->idom != 0 && bb->idom != bb->dfnum) {
+ BDEBUG(("Setting child %d of %d\n",
+ bb->dfnum, bbinfo->arr[bb->idom]->dfnum));
+ BITSET(bbinfo->arr[bb->idom]->dfchildren, bb->dfnum);
+ }
+ }
+}
+
+
+struct basicblock *
+ancestorwithlowestsemi(struct basicblock *bblock, struct bblockinfo *bbinfo)
+{
+ struct basicblock *u = bblock;
+ struct basicblock *v = bblock;
+
+ while (v->ancestor != 0) {
+ if (bbinfo->arr[v->semi]->dfnum <
+ bbinfo->arr[u->semi]->dfnum)
+ u = v;
+ v = bbinfo->arr[v->ancestor];
+ }
+ return u;
+}
+
+void
+link(struct basicblock *parent, struct basicblock *child)
+{
+ child->ancestor = parent->dfnum;
+}
+
+void
+computeDF(struct basicblock *bblock, struct bblockinfo *bbinfo)
+{
+ struct cfgnode *cnode;
+ int h, i;
+
+ SLIST_FOREACH(cnode, &bblock->children, cfgelem) {
+ if (cnode->bblock->idom != bblock->dfnum)
+ BITSET(bblock->df, cnode->bblock->dfnum);
+ }
+ for (h = 1; h < bbinfo->size; h++) {
+ if (!TESTBIT(bblock->dfchildren, h))
+ continue;
+ computeDF(bbinfo->arr[h], bbinfo);
+ for (i = 1; i < bbinfo->size; i++) {
+ if (TESTBIT(bbinfo->arr[h]->df, i) &&
+ (bbinfo->arr[h] == bblock ||
+ (bblock->idom != bbinfo->arr[h]->dfnum)))
+ BITSET(bblock->df, i);
+ }
+ }
+}
+
+static struct basicblock *currbb;
+static struct interpass *currip;
+
+/* Helper function for findTemps, Find assignment nodes. */
+static void
+searchasg(NODE *p)
+{
+ struct pvarinfo *pv;
+
+ if (p->n_op != ASSIGN)
+ return;
+
+ if (p->n_left->n_op != TEMP)
+ return;
+
+ pv = tmpcalloc(sizeof(struct pvarinfo));
+ pv->next = defsites.arr[p->n_left->n_lval];
+ pv->bb = currbb;
+ pv->top = currip->ip_node;
+ pv->n = p->n_left;
+ BITSET(currbb->Aorig, p->n_left->n_lval);
+
+ defsites.arr[p->n_left->n_lval] = pv;
+}
+
+/* Walk the interpass looking for assignment nodes. */
+void findTemps(struct interpass *ip)
+{
+ if (ip->type != IP_NODE)
+ return;
+
+ currip = ip;
+
+ walkf(ip->ip_node, searchasg);
+}
+
+/*
+ * Algorithm 19.6 from Appel.
+ */
+
+void
+placePhiFunctions(struct bblockinfo *bbinfo)
+{
+ struct basicblock *bb;
+ struct interpass *ip;
+ int maxtmp, i, j, k, l;
+ struct pvarinfo *n;
+ struct cfgnode *cnode;
+ TWORD ntype;
+ NODE *p;
+ struct pvarinfo *pv;
+
+ bb = DLIST_NEXT(&bblocks, bbelem);
+ defsites.low = ((struct interpass_prolog *)bb->first)->ip_tmpnum;
+ bb = DLIST_PREV(&bblocks, bbelem);
+ maxtmp = ((struct interpass_prolog *)bb->first)->ip_tmpnum;
+ defsites.size = maxtmp - defsites.low + 1;
+ defsites.arr = tmpcalloc(defsites.size*sizeof(struct pvarinfo *));
+
+ /* Find all defsites */
+ DLIST_FOREACH(bb, &bblocks, bbelem) {
+ currbb = bb;
+ ip = bb->first;
+ bb->Aorig = setalloc(defsites.size);
+ bb->Aphi = setalloc(defsites.size);
+
+
+ while (ip != bb->last) {
+ findTemps(ip);
+ ip = DLIST_NEXT(ip, qelem);
+ }
+ /* Make sure we get the last statement in the bblock */
+ findTemps(ip);
+ }
+ /* For each variable */
+ for (i = defsites.low; i < defsites.size; i++) {
+ /* While W not empty */
+ while (defsites.arr[i] != NULL) {
+ /* Remove some node n from W */
+ n = defsites.arr[i];
+ defsites.arr[i] = n->next;
+ /* For each y in n->bb->df */
+ for (j = 0; j < bbinfo->size; j++) {
+ if (!TESTBIT(n->bb->df, j))
+ continue;
+
+ if (TESTBIT(bbinfo->arr[j]->Aphi, i))
+ continue;
+
+ ntype = n->n->n_type;
+ k = 0;
+ /* Amount of predecessors for y */
+ SLIST_FOREACH(cnode, &n->bb->parents, cfgelem)
+ k++;
+ /* Construct phi(...) */
+ p = mklnode(TEMP, i, 0, ntype);
+ for (l = 0; l < k-1; l++)
+ p = mkbinode(PHI, p,
+ mklnode(TEMP, i, 0, ntype), ntype);
+ ip = ipnode(mkbinode(ASSIGN,
+ mklnode(TEMP, i, 0, ntype), p, ntype));
+ /* Insert phi at top of basic block */
+ DLIST_INSERT_BEFORE(((struct interpass*)&n->bb->first), ip, qelem);
+ n->bb->first = ip;
+ BITSET(bbinfo->arr[j]->Aphi, i);
+ if (!TESTBIT(bbinfo->arr[j]->Aorig, i)) {
+ pv = tmpalloc(sizeof(struct pvarinfo));
+ // XXXpj Ej fullständig information.
+ pv->bb = bbinfo->arr[j];
+ pv->next = defsites.arr[i]->next;
+ defsites.arr[i] = pv;
+ }
+
+
+ }
+ }
+ }
+}
+
+/*
+ * Remove unreachable nodes in the CFG.
+ */
+
+void
+remunreach(void)
+{
+ struct basicblock *bb, *nbb;
+ struct interpass *next, *ctree;
+
+ bb = DLIST_NEXT(&bblocks, bbelem);
+ while (bb != &bblocks) {
+ nbb = DLIST_NEXT(bb, bbelem);
+
+ /* Code with dfnum 0 is unreachable */
+ if (bb->dfnum != 0) {
+ bb = nbb;
+ continue;
+ }
+
+ /* Need the epilogue node for other parts of the
+ compiler, set its label to 0 and backend will
+ handle it. */
+ if (bb->first->type == IP_EPILOG) {
+ bb->first->ip_lbl = 0;
+ bb = nbb;
+ continue;
+ }
+
+ next = bb->first;
+ do {
+ ctree = next;
+ next = DLIST_NEXT(ctree, qelem);
+
+ if (ctree->type == IP_NODE)
+ tfree(ctree->ip_node);
+ DLIST_REMOVE(ctree, qelem);
+ } while (ctree != bb->last);
+
+ DLIST_REMOVE(bb, bbelem);
+ bb = nbb;
+ }
+}
+
+void
+printip(struct interpass *pole)
+{
+ static char *foo[] = {
+ 0, "NODE", "PROLOG", "STKOFF", "EPILOG", "DEFLAB", "DEFNAM", "ASM" };
+ struct interpass *ip;
+ struct interpass_prolog *ipp, *epp;
+
+ DLIST_FOREACH(ip, pole, qelem) {
+ if (ip->type > MAXIP)
+ printf("IP(%d) (%p): ", ip->type, ip);
+ else
+ printf("%s (%p): ", foo[ip->type], ip);
+ switch (ip->type) {
+ case IP_NODE: printf("\n");
+ fwalk(ip->ip_node, e2print, 0); break;
+ case IP_PROLOG:
+ ipp = (struct interpass_prolog *)ip;
+ printf("%s %s regs %x autos %d mintemp %d minlbl %d\n",
+ ipp->ipp_name, ipp->ipp_vis ? "(local)" : "",
+ ipp->ipp_regs, ipp->ipp_autos, ipp->ip_tmpnum,
+ ipp->ip_lblnum);
+ break;
+ case IP_EPILOG:
+ epp = (struct interpass_prolog *)ip;
+ printf("%s %s regs %x autos %d mintemp %d minlbl %d\n",
+ epp->ipp_name, epp->ipp_vis ? "(local)" : "",
+ epp->ipp_regs, epp->ipp_autos, epp->ip_tmpnum,
+ epp->ip_lblnum);
+ break;
+ case IP_DEFLAB: printf(LABFMT "\n", ip->ip_lbl); break;
+ case IP_DEFNAM: printf("\n"); break;
+ case IP_ASM: printf("%s\n", ip->ip_asm); break;
+ default:
+ break;
+ }
+ }
+}