Mirror of the BLOAT repository https://www.cs.purdue.edu/homes/hosking/bloat/
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
bloat/src/EDU/purdue/cs/bloat/cfg/DominatorTree.java

387 lines
11 KiB

/**
* All files in the distribution of BLOAT (Bytecode Level Optimization and
* Analysis tool for Java(tm)) are Copyright 1997-2001 by the Purdue
* Research Foundation of Purdue University. All rights reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
package EDU.purdue.cs.bloat.cfg;
import java.util.*;
import EDU.purdue.cs.bloat.util.*;
/**
* DominatorTree finds the dominator tree of a FlowGraph.
* <p>
* The algorithm used is Purdum-Moore. It isn't as fast as Lengauer-Tarjan, but
* it's a lot simpler.
*
* @see FlowGraph
* @see Block
*/
public class DominatorTree {
public static boolean DEBUG = false;
/**
* Calculates what vertices dominate other verices and notify the basic
* Blocks as to who their dominator is.
*
* @param graph
* The cfg that is used to find the dominator tree.
* @param reverse
* Do we go in revsers? That is, are we computing the dominatance
* (false) or postdominance (true) tree.
* @see Block
*/
public static void buildTree(final FlowGraph graph, boolean reverse) {
final int size = graph.size(); // The number of vertices in the cfg
final Map snkPreds = new HashMap(); // The predacessor vertices from the
// sink
// Determine the predacessors of the cfg's sink node
DominatorTree.insertEdgesToSink(graph, snkPreds, reverse);
// Get the index of the root
final int root = reverse ? graph.preOrderIndex(graph.sink()) : graph
.preOrderIndex(graph.source());
Assert.isTrue((0 <= root) && (root < size));
// Bit matrix indicating the dominators of each vertex.
// If bit j of dom[i] is set, then node j dominates node i.
final BitSet[] dom = new BitSet[size];
// A bit vector of all 1's
final BitSet ALL = new BitSet(size);
for (int i = 0; i < size; i++) {
ALL.set(i);
}
// Initially, all the bits in the dominance matrix are set, except
// for the root node. The root node is initialized to have itself
// as an immediate dominator.
//
for (int i = 0; i < size; i++) {
final BitSet blockDoms = new BitSet(size);
dom[i] = blockDoms;
if (i != root) {
blockDoms.or(ALL);
} else {
blockDoms.set(root);
}
}
// Did the dominator bit vector array change?
boolean changed = true;
while (changed) {
changed = false;
// Get the basic blocks contained in the cfg
final Iterator blocks = reverse ? graph.postOrder().iterator()
: graph.preOrder().iterator();
// Compute the dominators of each node in the cfg. We iterate
// over every node in the cfg. The dominators of a node, x, are
// found by taking the intersection of the dominator bit vectors
// of each predacessor of x and unioning that with x. This
// process is repeated until no changes are made to any dominator
// bit vector.
while (blocks.hasNext()) {
final Block block = (Block) blocks.next();
final int i = graph.preOrderIndex(block);
Assert.isTrue((0 <= i) && (i < size), "Unreachable block "
+ block);
// We already know the dominators of the root, keep looking
if (i == root) {
continue;
}
final BitSet oldSet = dom[i];
final BitSet blockDoms = new BitSet(size);
blockDoms.or(oldSet);
// print(graph, reverse, "old set", i, blockDoms);
// blockDoms := intersection of dom(pred) for all pred(block).
Collection preds = reverse ? graph.succs(block) : graph
.preds(block);
Iterator e = preds.iterator();
// Find the intersection of the dominators of block's
// predacessors.
while (e.hasNext()) {
final Block pred = (Block) e.next();
final int j = graph.preOrderIndex(pred);
Assert.isTrue(j >= 0, "Unreachable block " + pred);
blockDoms.and(dom[j]);
}
// Don't forget to account for the sink node if block is a
// leaf node. Appearantly, there are not edges between
// leaf nodes and the sink node!
preds = (Collection) snkPreds.get(block);
if (preds != null) {
e = preds.iterator();
while (e.hasNext()) {
final Block pred = (Block) e.next();
final int j = graph.preOrderIndex(pred);
Assert.isTrue(j >= 0, "Unreachable block " + pred);
blockDoms.and(dom[j]);
}
}
// Include yourself in your dominators?!
blockDoms.set(i);
// print(graph, reverse, "intersecting " + preds, i, blockDoms);
// If the set changed, set the changed bit.
if (!blockDoms.equals(oldSet)) {
changed = true;
dom[i] = blockDoms;
}
}
}
// Once we have the predacessor bit vectors all squared away, we can
// determine which vertices dominate which vertices.
Iterator blocks = graph.nodes().iterator();
// Initialize each block's (post)dominator parent and children
while (blocks.hasNext()) {
final Block block = (Block) blocks.next();
if (!reverse) {
block.setDomParent(null);
block.domChildren().clear();
} else {
block.setPdomParent(null);
block.pdomChildren().clear();
}
}
blocks = graph.nodes().iterator();
// A block's immediate dominator is its closest dominator. So, we
// start with the dominators, dom(b), of a block, b. To find the
// imediate dominator of b, we remove all blocks from dom(b) that
// dominate any block in dom(b).
while (blocks.hasNext()) {
final Block block = (Block) blocks.next();
final int i = graph.preOrderIndex(block);
Assert.isTrue((0 <= i) && (i < size), "Unreachable block " + block);
if (i == root) {
if (!reverse) {
block.setDomParent(null);
} else {
block.setPdomParent(null);
}
} else {
// Find the immediate dominator
// idom := dom(block) - dom(dom(block)) - block
final BitSet blockDoms = dom[i];
// print(graph, reverse, "dom set", i, blockDoms);
final BitSet idom = new BitSet(size);
idom.or(blockDoms);
idom.clear(i);
for (int j = 0; j < size; j++) {
if ((i != j) && blockDoms.get(j)) {
final BitSet domDomBlocks = dom[j];
// idom = idom - (domDomBlocks - {j})
final BitSet b = new BitSet(size);
b.or(domDomBlocks);
b.xor(ALL);
b.set(j);
idom.and(b);
// print(graph, reverse,
// "removing dom(" + graph.preOrder().get(j) +")",
// i, idom);
}
}
Block parent = null;
// A block should only have one immediate dominator.
for (int j = 0; j < size; j++) {
if (idom.get(j)) {
final Block p = (Block) graph.preOrder().get(j);
Assert.isTrue(parent == null, block
+ " has more than one immediate dominator: "
+ parent + " and " + p);
parent = p;
}
}
Assert.isTrue(parent != null, block + " has 0 immediate "
+ (reverse ? "postdominators" : "dominators"));
if (!reverse) {
if (DominatorTree.DEBUG) {
System.out.println(parent + " dominates " + block);
}
block.setDomParent(parent);
} else {
if (DominatorTree.DEBUG) {
System.out.println(parent + " postdominates " + block);
}
block.setPdomParent(parent);
}
}
}
}
/**
* Determines which nodes are predacessors of a cfg's sink node. Creates a
* Map that maps the sink node to its predacessors (or the leaf nodes to the
* sink node, their predacessor, if we're going backwards).
*
* @param graph
* The cfg to operate on.
* @param preds
* A mapping from leaf nodes to their predacessors. The exact
* semantics depend on whether or not we are going forwards.
* @param reverse
* Are we computing the dominators or postdominators?
*/
private static void insertEdgesToSink(final FlowGraph graph,
final Map preds, final boolean reverse) {
final BitSet visited = new BitSet(); // see insertEdgesToSinkDFS
final BitSet returned = new BitSet();
visited.set(graph.preOrderIndex(graph.source()));
DominatorTree.insertEdgesToSinkDFS(graph, graph.source(), visited,
returned, preds, reverse);
}
/**
* This method determines which nodes are the predacessor of the sink node
* of a cfg. A depth-first traversal of the cfg is performed. When a leaf
* node (that is not the sink node) is encountered, add an entry to the
* preds Map.
*
* @param graph
* The cfg being operated on.
* @param block
* The basic Block to start at.
* @param visited
* Vertices that were visited
* @param returned
* Vertices that returned
* @param preds
* Maps a node to a HashSet representing its predacessors. In the
* case that we're determining the dominace tree, preds maps the
* sink node to its predacessors. In the case that we're
* determining the postdominance tree, preds maps the sink node's
* predacessors to the sink node.
* @param reverse
* Do we go in reverse?
*/
private static void insertEdgesToSinkDFS(final FlowGraph graph,
final Block block, final BitSet visited, final BitSet returned,
final Map preds, boolean reverse) {
boolean leaf = true; // Is a vertex a leaf node?
// Get the successors of block
final Iterator e = graph.succs(block).iterator();
while (e.hasNext()) {
final Block succ = (Block) e.next();
// Determine index of succ vertex in a pre-order traversal
final int index = graph.preOrderIndex(succ);
Assert.isTrue(index >= 0, "Unreachable block " + succ);
if (!visited.get(index)) {
// If the successor block hasn't been visited, visit it
visited.set(index);
DominatorTree.insertEdgesToSinkDFS(graph, succ, visited,
returned, preds, reverse);
returned.set(index);
leaf = false;
} else if (returned.get(index)) {
// Already visited and returned, so a descendent of succ
// has an edge to the sink.
leaf = false;
}
}
if (leaf && (block != graph.sink())) {
// If we're dealing with a leaf node that is not the sink, set
// up its predacessor set.
if (!reverse) {
// If we're going forwards (computing dominators), get the
// predacessor vertices from the sink
Set p = (Set) preds.get(graph.sink());
// If there are no (known) predacessors, make a new HashSet to
// store them and register it in the pred Map.
if (p == null) {
p = new HashSet();
preds.put(graph.sink(), p);
}
// The block is in the predacessors of the sink
p.add(block);
} else {
// If we're going backwards, get the block's predacessors
Set p = (Set) preds.get(block);
if (p == null) {
p = new HashSet();
preds.put(block, p);
}
// Add the sink vertex to the predacessors of the block
p.add(graph.sink());
}
}
}
}