blob: 49938249870b1bb71581f9288d29e11cb9bc636f [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* @author Intel, Pavel A. Ozhdikhin
*
*/
#include "Dominator.h"
#include <string.h>
namespace Jitrino {
// BOTTOM : no idom. idom[entry] = BOTTOM
#define NONE MAX_UINT32
// TOP : no information computed yet
#define UNDEFINED 0
// Cooper / Harvey / Kennedy variation on simple iterative dominator algorithm.
// They claim that this is faster than Lengauer / Tarjan in practice.
DominatorTree*
DominatorBuilder::computeDominators(MemoryManager& mm, ControlFlowGraph* flowgraph, bool isPost, bool ignoreUnreach) {
// Temp memory manager
MemoryManager tmm("DominatorBuilder::computeDominators");
Nodes nodes(tmm);
// Get the nodes of the flowgraph in postorder.
flowgraph->getNodesPostOrder(nodes, !isPost);
U_32 numNodes = (U_32) nodes.size();
#ifdef _DEBUG
// Start (entry/exit) node should be last.
Node* start = nodes.back();
assert((start == (isPost ? flowgraph->getExitNode() : flowgraph->getEntryNode())
&& start->getPostNum() == numNodes-1));
#endif
// Initialize the idom array to UNDEFINED. Idiom maps the postorder
// number of a node to the postorder number of its idom.
StlVector<U_32> idom(tmm);
idom.insert(idom.end(), (unsigned int) numNodes-1, UNDEFINED);
// Initialize idom[entry] = NONE.
idom.insert(idom.end(), NONE);
// Find maximal fixed point
bool changed = true;
while(changed) {
changed = false;
// Process all nodes except entry in reverse postorder.
Nodes::reverse_iterator i;
for(i = nodes.rbegin()+1; i != nodes.rend(); ++i) {
Node* node = *i;
U_32 nodeNum = node->getPostNum();
// Compute updated idom from predecessors
U_32 newIdom = UNDEFINED;
Edges::const_iterator j;
for(j = node->getEdges(isPost).begin(); j != node->getEdges(isPost).end(); ++j) {
Node* pred = (*j)->getNode(isPost);
// Assert that pred is reachable.
if (!ignoreUnreach)
assert(pred->getTraversalNum() == flowgraph->getTraversalNum());
if (!ignoreUnreach || (ignoreUnreach && (pred->getTraversalNum() == flowgraph->getTraversalNum()))) {
U_32 predNum = pred->getPostNum();
// Skip unprocessed preds (only happens on first iteration).
if(idom[predNum] != UNDEFINED)
// Intersect dominator sets.
newIdom = (newIdom == UNDEFINED) ? predNum : intersect(idom, newIdom, predNum);
}
}
assert(newIdom != UNDEFINED);
// Update if changed
if(newIdom != idom[nodeNum]) {
// Assert that we are converging.
assert(newIdom > idom[nodeNum]);
idom[nodeNum] = newIdom;
changed = true;
}
}
}
// Build dominator tree and return.
return new (mm) DominatorTree(mm, flowgraph, nodes, idom, isPost);
}
U_32
DominatorBuilder::intersect(StlVector<U_32>& idom, U_32 finger1, U_32 finger2) {
// Intersect the dominator sets represented by finger1 and finger2.
while(finger1 != finger2) {
while(finger1 < finger2)
finger1 = idom[finger1];
while(finger2 < finger1)
finger2 = idom[finger2];
}
// Set should at least contain root/entry.
assert(finger1 != NONE);
return finger1;
}
DominatorTree::DominatorTree(MemoryManager& mm,
ControlFlowGraph* fg,
Nodes& nodes,
StlVector<U_32>& idom,
bool isPostDominator)
: flowgraph(fg), traversalNum(fg->getTraversalNum()),
numNodes(fg->getMaxNodeId()),
_isPostDominator(isPostDominator), tree(mm, numNodes, NULL) {
// Create the dominator tree nodes..
U_32 postNum, id=MAX_UINT32;
for(postNum = 0; postNum < nodes.size(); ++postNum) {
Node* node = nodes[postNum];
id = node->getId();
tree[id] = new (mm) DominatorNode(node);
}
// Create tree itself. Note that the children of each
// dominator parent node will be in sorted in
// reverse postorder. It's assumed that nodes is
// in postorder.
for(postNum = 0; postNum < nodes.size(); ++postNum) {
Node* node = nodes[postNum];
id = node->getId();
// Assert post-ordering of nodes.
assert((U_32) postNum == node->getPostNum());
if(idom[postNum] != NONE) {
// Assert that idoms are acyclic.
assert(idom[postNum] > postNum);
Node* parent = nodes[idom[postNum]];
U_32 parentId = parent->getId();
assert(tree[parentId] != NULL);
// Assert that new child (added to beginning) has highest postorder number.
assert(tree[parentId]->getChild() == NULL || tree[parentId]->getChild()->getNode()->getPostNum() < postNum);
tree[parentId]->addChild(tree[id]);
}
}
// Last node is root.
root = tree[id];
computeOrder();
}
bool DominatorTree::dominates(Node* a, Node* b) {
assert(a != NULL && b != NULL);
assert(a->getId() < numNodes && b->getId() < numNodes);
DominatorNode* na = tree[a->getId()];
DominatorNode* nb = tree[b->getId()];
if (na == NULL || nb == NULL) {
return false;
}
return a==b || isAncestor(na, nb);
}
DomFrontier::DomFrontier(MemoryManager& mm,
DominatorTree& d,
ControlFlowGraph* fg)
: memManager(mm), dom(d), isPostDominator(d.isPostDominator()) {
// To Do: may want to keep number of nodes in flow graph instead of recomputing every time
numNodes = (U_32) fg->getNodeCount();
// if flow graph has been modified since dominator was computed, then
// dominator information needs to be recomputed
if (!dom.isValid()) {
DominatorBuilder db;
dom = *db.computeDominators(memManager,fg);
}
beenComputed = new (memManager) BitSet(memManager, numNodes);
DF = (List<Node>**) memManager.alloc(sizeof(List<Node>*)*numNodes);
memset(DF, 0, numNodes*sizeof(List<Node>*)); // initialized with NULL
}
void DomFrontier::addDF(U_32 entry, Node* n) {
assert(entry < numNodes);
// make sure no duplicate entry
for (List<Node>* l = DF[entry]; l != NULL; l = l->getNext())
if (l->getElem() == n)
return;
DF[entry] = new (memManager) List<Node>(n,DF[entry]);
}
void DomFrontier::computeDomFrontier(Node* node) {
U_32 dfnum = node->getDfNum();
// if dom frontiers are not computed yet
if (beenComputed->getBit(dfnum))
return;
beenComputed->setBit(dfnum,true);
// If this is a post-dominance frontier, use the reverse graph.
bool forward = !isPostDominator;
// compute DF local: the successors of node that are not strictly
// dominated by node
const Edges& edges = node->getEdges(forward);
Edges::const_iterator eiter;
for(eiter = edges.begin(); eiter != edges.end(); ++eiter) {
Edge* e = *eiter;
Node *succ = e->getNode(forward);
if (dom.getIdom(succ) != node) {
addDF(dfnum,succ);
}
}
// compute DF up: Nodes in the dom frontier of node that are dominated
// by node's immediate dominator
for (DominatorNode* c = dom.getDominatorNode(node)->getChild(); c != NULL; c = c->getSiblings()) {
Node* child = c->getNode();
computeDomFrontier(child);
// go over each frontier of child
for (List<Node>* f = DF[child->getDfNum()];f != NULL; f = f->getNext()) {
Node *elem = f->getElem();
// if node does not strictly dominates elem
if (elem == node || !dom.dominates(node,elem)) {
addDF(dfnum,elem);
}
}
}
}
} //namespace Jitrino