/* src/vm/jit/optimizing/dominators.cpp - dominators and dominance frontier Copyright (C) 2005, 2006, 2008 CACAOVM - Verein zur Foerderung der freien virtuellen Maschine CACAO This file is part of CACAO. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "config.h" #include "config.h" #include "mm/memory.hpp" #include "toolbox/bitvector.h" #include "vm/jit/jit.hpp" #include "vm/jit/optimizing/graph.h" #include "vm/jit/optimizing/dominators.hpp" /* function prototypes */ void dom_Dominators_init(dominatordata *dd, int basicblockcount); #ifdef DOM_DEBUG_CHECK int dom_AncestorWithLowestSemi(dominatordata *dd, int v, int basicblockcount); void dom_Link(dominatordata *dd, int p, int n, int basicblockcount); void dom_DFS(graphdata *gd, dominatordata *dd, int p, int n, int *N, int basicblockcount); #else int dom_AncestorWithLowestSemi(dominatordata *dd, int v); void dom_Link(dominatordata *dd, int p, int n); void dom_DFS(graphdata *gd, dominatordata *dd, int p, int n, int *N); #endif /************************************* Calculate Dominators *************************************/ dominatordata *compute_Dominators(graphdata *gd, int basicblockcount) { int i,j,n,N,p,s,s_,v,y; graphiterator iter; dominatordata *dd; dd = (dominatordata*) DumpMemory::allocate(sizeof(dominatordata)); dom_Dominators_init(dd, basicblockcount); N=0; /* 1 ist the root node of the method */ /* 0 is the artificial parent, where locals are set to their parameters */ dom_DFS(gd, dd, -1, 0, &N #ifdef DOM_DEBUG_CHECK ,basicblockcount #endif ); for(i = N-1; i > 0; i--) { _DOM_CHECK_BOUNDS(i, 0, basicblockcount); n = dd->vertex[i]; _DOM_CHECK_BOUNDS(n, 0, basicblockcount); p = dd->parent[n]; s = p; j = graph_get_first_predecessor(gd, n, &iter); for (; j != -1; j = graph_get_next(&iter)) { _DOM_CHECK_BOUNDS(j, 0, basicblockcount); if (dd->dfnum[j] <= dd->dfnum[n]) s_ = j; else s_ = dd->semi[dom_AncestorWithLowestSemi(dd, j #ifdef DOM_DEBUG_CHECK ,basicblockcount #endif )]; _DOM_CHECK_BOUNDS(s_, 0, basicblockcount); _DOM_CHECK_BOUNDS(s, 0, basicblockcount); if (dd->dfnum[s_] < dd->dfnum[s]) s = s_; } dd->semi[n] = s; _DOM_CHECK_BOUNDS(dd->num_bucket[s], 0, basicblockcount); dd->bucket[s][dd->num_bucket[s]] = n; dd->num_bucket[s]++; dom_Link(dd, p, n #ifdef DOM_DEBUG_CHECK , basicblockcount #endif ); _DOM_CHECK_BOUNDS(p, 0, basicblockcount); for(j = 0; j < dd->num_bucket[p]; j++) { _DOM_CHECK_BOUNDS(j, 0, basicblockcount); v = dd->bucket[p][j]; y = dom_AncestorWithLowestSemi(dd, v #ifdef DOM_DEBUG_CHECK , basicblockcount #endif ); _DOM_CHECK_BOUNDS(y, 0, basicblockcount); _DOM_CHECK_BOUNDS(v, 0, basicblockcount); if (dd->semi[y] == dd->semi[v]) dd->idom[v] = p; else dd->samedom[v] = y; } dd->num_bucket[p] = 0; } for(i = 1; i < N; i++) { n = dd->vertex[i]; _DOM_CHECK_BOUNDS(n, 0, basicblockcount); if (dd->samedom[n] != -1) { _DOM_CHECK_BOUNDS(dd->samedom[n], 0, basicblockcount); dd->idom[n] = dd->idom[dd->samedom[n]]; } } return dd; } /******************************************** compute Dominace Frontier ********************************************/ void computeDF(graphdata *gd, dominatordata *dd, int basicblockcount, int n) { int c,i,j; bool *_S; graphiterator iter; _S = (bool*) DumpMemory::allocate(sizeof(bool) * basicblockcount); for(i = 0; i < basicblockcount; i++) _S[i] = false; i = graph_get_first_successor(gd, n, &iter); for (; i != -1; i = graph_get_next(&iter)) { _DOM_CHECK_BOUNDS(i, 0, basicblockcount); if (dd->idom[i] != n) _S[i] = true; } for(c=0; c < basicblockcount; c++) { if (dd->idom[c] == n) { computeDF(gd, dd, basicblockcount, c); for(j=0; j < dd->num_DF[c]; j++) { _DOM_CHECK_BOUNDS(dd->DF[c][j], 0, basicblockcount); if (n != dd->idom[dd->DF[c][j]]) /* n does not dominate DF[c][j] -> traverse idom list? */ _S[dd->DF[c][j]] = true; } } } for(i = 0; i < basicblockcount; i++) if (_S[i]) { _DOM_CHECK_BOUNDS(dd->num_DF[n], 0, basicblockcount); dd->DF[n][dd->num_DF[n]] = i; dd->num_DF[n]++; } } void dom_Dominators_init(dominatordata *dd, int basicblockcount) { int i; dd->dfnum = (int*) DumpMemory::allocate(sizeof(int) * basicblockcount); dd->vertex = (int*) DumpMemory::allocate(sizeof(int) * basicblockcount); dd->parent = (int*) DumpMemory::allocate(sizeof(int) * basicblockcount); dd->semi = (int*) DumpMemory::allocate(sizeof(int) * basicblockcount); dd->ancestor = (int*) DumpMemory::allocate(sizeof(int) * basicblockcount); dd->idom = (int*) DumpMemory::allocate(sizeof(int) * basicblockcount); dd->samedom = (int*) DumpMemory::allocate(sizeof(int) * basicblockcount); dd->bucket = (int**) DumpMemory::allocate(sizeof(int*) * basicblockcount); dd->num_bucket = (int*) DumpMemory::allocate(sizeof(int) * basicblockcount); dd->DF = (int**) DumpMemory::allocate(sizeof(int*) * basicblockcount); dd->num_DF = (int*) DumpMemory::allocate(sizeof(int) * basicblockcount); dd->best = (int*) DumpMemory::allocate(sizeof(int) * basicblockcount); for (i=0; i < basicblockcount; i++) { dd->dfnum[i] = -1; dd->semi[i] = dd->ancestor[i] = dd->idom[i] = dd->samedom[i] = -1; dd->num_bucket[i] = 0; dd->bucket[i] = (int*) DumpMemory::allocate(sizeof(int) * basicblockcount); dd->num_DF[i] = 0; dd->DF[i] = (int*) DumpMemory::allocate(sizeof(int) * basicblockcount); } } /************************************** Create Depth First Spanning Tree **************************************/ #ifdef DOM_DEBUG_CHECK void dom_DFS(graphdata *gd, dominatordata *dd, int p, int n, int *N, int basicblockcount) { #else void dom_DFS(graphdata *gd, dominatordata *dd, int p, int n, int *N) { #endif int i; graphiterator iter; _DOM_CHECK_BOUNDS(n,0,basicblockcount); if (dd->dfnum[n] == -1) { /* not visited till now? */ dd->dfnum[n] = *N; _DOM_CHECK_BOUNDS(*N,0,basicblockcount); dd->vertex[*N] = n; dd->parent[n] = p; (*N)++; i = graph_get_first_successor(gd, n, &iter); for (; i != -1; i = graph_get_next(&iter)) { dom_DFS(gd, dd, n, i, N #ifdef DOM_DEBUG_CHECK , basicblockcount #endif ); } } } #ifdef DOM_DEBUG_CHECK int dom_AncestorWithLowestSemi(dominatordata *dd, int v, int basicblockcount) { #else int dom_AncestorWithLowestSemi(dominatordata *dd, int v) { #endif int a,b; _DOM_CHECK_BOUNDS(v, 0, basicblockcount); a = dd->ancestor[v]; _DOM_CHECK_BOUNDS(a,0,basicblockcount); if (dd->ancestor[a] != -1) { b = dom_AncestorWithLowestSemi(dd, a #ifdef DOM_DEBUG_CHECK , basicblockcount #endif ); dd->ancestor[v] = dd->ancestor[a]; _DOM_CHECK_BOUNDS(b,0,basicblockcount); _DOM_CHECK_BOUNDS(dd->best[v],0,basicblockcount); _DOM_CHECK_BOUNDS(dd->semi[dd->best[v]],0,basicblockcount); if (dd->dfnum[dd->semi[b]] < dd->dfnum[dd->semi[dd->best[v]]]) dd->best[v] = b; } return dd->best[v]; } #ifdef DOM_DEBUG_CHECK void dom_Link(dominatordata *dd, int p, int n, int basicblockcount) { #else void dom_Link(dominatordata *dd, int p, int n) { #endif _DOM_CHECK_BOUNDS(n,0,basicblockcount); dd->ancestor[n] = p; dd->best[n] = n; } /*********************************************************/ typedef struct basicblock_info basicblock_info; struct basicblock_info { basicblock *bb; int dfnum; basicblock_info *parent; basicblock_info *semi; basicblock_info *ancestor; basicblock_info *best; basicblock_info *idom; basicblock_info *samedom; basicblock_info **bucket; unsigned bucketcount; }; typedef struct dominator_tree_info dominator_tree_info; struct dominator_tree_info { jitdata *jd; basicblock_info *basicblocks; basicblock_info **df_map; unsigned df_counter; }; static dominator_tree_info *dominator_tree_init(jitdata *jd) { dominator_tree_info *di; basicblock *itb; basicblock_info *iti; di = (dominator_tree_info*) DumpMemory::allocate(sizeof(dominator_tree_info)); di->jd = jd; di->basicblocks = (basicblock_info*) DumpMemory::allocate(sizeof(basicblock_info) * jd->basicblockcount); MZERO(di->basicblocks, basicblock_info, jd->basicblockcount); for (iti = di->basicblocks; iti != di->basicblocks + jd->basicblockcount; ++iti) { iti->dfnum = -1; iti->bucket = (basicblock_info**) DumpMemory::allocate(sizeof(basicblock_info*) * jd->basicblockcount); iti->bucketcount = 0; } for (itb = jd->basicblocks; itb; itb = itb->next) { di->basicblocks[itb->nr].bb = itb; } di->df_map = (basicblock_info**) DumpMemory::allocate(sizeof(basicblock_info*) * jd->basicblockcount); MZERO(di->df_map, basicblock_info *, jd->basicblockcount); di->df_counter = 0; return di; } static inline basicblock_info *dominator_tree_get_basicblock(dominator_tree_info *di, basicblock *bb) { return di->basicblocks + bb->nr; } static void dominator_tree_depth_first_search( dominator_tree_info *di, basicblock_info *parent, basicblock_info *node ) { basicblock **it; if (node->dfnum == -1) { node->dfnum = di->df_counter; node->parent = parent; di->df_map[di->df_counter] = node; di->df_counter += 1; for (it = node->bb->successors; it != node->bb->successors + node->bb->successorcount; ++it) { dominator_tree_depth_first_search( di, node, dominator_tree_get_basicblock(di, *it) ); } } } void dominator_tree_link(dominator_tree_info *di, basicblock_info *parent, basicblock_info *node) { node->ancestor = parent; node->best = node; } basicblock_info *dominator_tree_ancestor_with_lowest_semi( dominator_tree_info *di, basicblock_info *node ) { basicblock_info *a, *b; a = node->ancestor; if (a->ancestor != NULL) { b = dominator_tree_ancestor_with_lowest_semi(di, a); node->ancestor = a->ancestor; if (b->semi->dfnum < node->best->semi->dfnum) { node->best = b; } } return node->best; } void dominator_tree_build_intern(jitdata *jd) { dominator_tree_info *di; basicblock_info *node; basicblock_info *semicand; basicblock_info *pred; basicblock **itb; basicblock_info **itii; basicblock_info *v, *y; int i; di = dominator_tree_init(jd); dominator_tree_depth_first_search(di, NULL, dominator_tree_get_basicblock(di, jd->basicblocks)); for (i = di->df_counter - 1; i >= 1; --i) { node = di->df_map[i]; node->semi = node->parent; for ( itb = node->bb->predecessors; itb != node->bb->predecessors + node->bb->predecessorcount; ++itb ) { pred = dominator_tree_get_basicblock(di, *itb); if (pred->dfnum <= node->dfnum) { semicand = pred; } else { semicand = dominator_tree_ancestor_with_lowest_semi(di, pred)->semi; } if (semicand->dfnum < node->semi->dfnum) { node->semi = semicand; } } node->semi->bucket[node->semi->bucketcount] = node; node->semi->bucketcount += 1; dominator_tree_link(di, node->parent, node); for (itii = node->parent->bucket; itii != node->parent->bucket + node->parent->bucketcount; ++itii) { v = *itii; y = dominator_tree_ancestor_with_lowest_semi(di, v); if (y->semi == v->semi) { v->idom = node->parent; } else { v->samedom = y; } } node->parent->bucketcount = 0; } for (i = 1; i < di->df_counter; ++i) { node = di->df_map[i]; if (node->samedom) { node->idom = node->samedom->idom; } node->bb->idom = node->idom->bb; node->idom->bb->domsuccessorcount += 1; } } void dominator_tree_link_children(jitdata *jd) { basicblock *bb; /* basicblock number => current number of successors */ unsigned *numsuccessors; // Create new dump memory area. DumpMemoryArea dma; /* Allocate memory for successors */ for (bb = jd->basicblocks; bb; bb = bb->next) { if (bb->domsuccessorcount > 0) { bb->domsuccessors = (basicblock**) DumpMemory::allocate(sizeof(basicblock*) * bb->domsuccessorcount); } } /* Allocate memory for per basic block counter of successors */ numsuccessors = (unsigned*) DumpMemory::allocate(sizeof(unsigned) * jd->basicblockcount); MZERO(numsuccessors, unsigned, jd->basicblockcount); /* Link immediate dominators with successors */ for (bb = jd->basicblocks; bb; bb = bb->next) { if (bb->idom) { bb->idom->domsuccessors[numsuccessors[bb->idom->nr]] = bb; numsuccessors[bb->idom->nr] += 1; } } } bool dominator_tree_build(jitdata *jd) { // Create new dump memory area. DumpMemoryArea dma; dominator_tree_build_intern(jd); dominator_tree_link_children(jd); return true; } typedef struct dominance_frontier_item dominance_frontier_item; struct dominance_frontier_item { basicblock *bb; dominance_frontier_item *next; }; typedef struct dominance_frontier_list dominance_frontier_list; struct dominance_frontier_list { dominance_frontier_item *first; unsigned count; }; void dominance_frontier_list_add(dominance_frontier_list *list, basicblock *bb) { dominance_frontier_item *item; for (item = list->first; item; item = item->next) { if (item->bb == bb) return; } item = (dominance_frontier_item*) DumpMemory::allocate(sizeof(dominance_frontier_item)); item->bb = bb; item->next = list->first; list->first = item; list->count += 1; } typedef struct dominance_frontier_info dominance_frontier_info; struct dominance_frontier_info { jitdata *jd; dominance_frontier_list *map; }; dominance_frontier_info *dominance_frontier_init(jitdata *jd) { dominance_frontier_info *dfi = (dominance_frontier_info*) DumpMemory::allocate(sizeof(dominance_frontier_info)); dfi->jd = jd; dfi->map = (dominance_frontier_list*) DumpMemory::allocate(sizeof(dominance_frontier_list) * jd->basicblockcount); MZERO(dfi->map, dominance_frontier_list, jd->basicblockcount); return dfi; } bool dominance_frontier_dominates(basicblock *d, basicblock *x) { x = x->idom; while (x != NULL) { if (x == d) { return true; } x = x->idom; } return false; } void dominance_frontier_for_block(dominance_frontier_info *dfi, basicblock *b) { basicblock **it; dominance_frontier_item *itdf; dominance_frontier_list s = { NULL, 0 }; for (it = b->successors; it != b->successors + b->successorcount; ++it) { if ((*it)->idom != b) { dominance_frontier_list_add(&s, *it); } } for (it = b->domsuccessors; it != b->domsuccessors + b->domsuccessorcount; ++it) { dominance_frontier_for_block(dfi, *it); for (itdf = dfi->map[(*it)->nr].first; itdf; itdf = itdf->next) { if (! dominance_frontier_dominates(b, itdf->bb)) { dominance_frontier_list_add(&s, itdf->bb); } } } dfi->map[b->nr] = s; } void dominance_frontier_store(dominance_frontier_info *dfi) { basicblock *bb; dominance_frontier_item *itdf; basicblock **itout; for (bb = dfi->jd->basicblocks; bb; bb = bb->next) { if (bb->nr < dfi->jd->basicblockcount) { if (dfi->map[bb->nr].count > 0) { bb->domfrontiercount = dfi->map[bb->nr].count; itout = bb->domfrontier = (basicblock**) DumpMemory::allocate(sizeof(basicblock*) * bb->domfrontiercount); for (itdf = dfi->map[bb->nr].first; itdf; itdf = itdf->next) { *itout = itdf->bb; itout += 1; } } } } } bool dominance_frontier_build(jitdata *jd) { // Create new dump memory area. DumpMemoryArea dma; dominance_frontier_info *dfi = dominance_frontier_init(jd); dominance_frontier_for_block(dfi, jd->basicblocks); dominance_frontier_store(dfi); } #include "vm/jit/show.hpp" #include "vm/jit/python.h" extern "C" void graph_add_edge( graphdata *gd, int from, int to ); void dominator_tree_validate(jitdata *jd, dominatordata *_dd) { graphdata *gd; int i, j; basicblock *bptr, **it; dominatordata *dd; int *itnr; bool found; // Create new dump memory area. DumpMemoryArea dma; fprintf(stderr, "%s/%s: \n", jd->m->clazz->name->text, jd->m->name->text); gd = graph_init(jd->basicblockcount); for (bptr = jd->basicblocks; bptr; bptr = bptr->next) { for (it = bptr->successors; it != bptr->successors + bptr->successorcount; ++it) { graph_add_edge(gd, bptr->nr, (*it)->nr); } } dd = compute_Dominators(gd, jd->basicblockcount); for (bptr = jd->basicblocks; bptr; bptr = bptr->next) { if (bptr->flags >= BBREACHED) { if (bptr->idom == NULL) { if (!(dd->idom[bptr->nr] == -1)) { printf("-- %d %d\n", dd->idom[bptr->nr], bptr->nr); assert(0); } } else { assert(dd->idom[bptr->nr] == bptr->idom->nr); } } } computeDF(gd, dd, jd->basicblockcount, 0); for (bptr = jd->basicblocks; bptr; bptr = bptr->next) { if (bptr->flags >= BBREACHED) { assert(bptr->domfrontiercount == dd->num_DF[bptr->nr]); for (itnr = dd->DF[bptr->nr]; itnr != dd->DF[bptr->nr] + dd->num_DF[bptr->nr]; ++itnr) { found = false; for (it = bptr->domfrontier; it != bptr->domfrontier + bptr->domfrontiercount; ++it) { if ((*it)->nr == *itnr) { found =true; break; } } assert(found); } } } } /* * These are local overrides for various environment variables in Emacs. * Please do not remove this and leave it at the end of the file, where * Emacs will automagically detect them. * --------------------------------------------------------------------- * Local variables: * mode: c++ * indent-tabs-mode: t * c-basic-offset: 4 * tab-width: 4 * End: */