/* * This file is part of the Jikes RVM project (http://jikesrvm.org). * * This file is licensed to You under the Common Public License (CPL); * You may not use this file except in compliance with the License. You * may obtain a copy of the License at * * http://www.opensource.org/licenses/cpl1.0.php * * See the COPYRIGHT.txt file distributed with this work for information * regarding copyright ownership. */ package org.jikesrvm.compilers.opt; import java.util.Enumeration; import org.jikesrvm.compilers.opt.ir.OPT_BasicBlock; import org.jikesrvm.compilers.opt.ir.OPT_IR; /** * This class provides the abstraction of a dominator tree * * TODO: we do not support IRs with exception handlers. */ public class OPT_DominatorTree extends OPT_Tree { /** * control for debugging messages. */ static final boolean DEBUG = false; /** * True if we are computing regular dominators, false for post-dominators */ private boolean forward; /** * The governing IR */ private OPT_IR ir; /** * A structure used to quickly index into the DominatorVertex tree */ private OPT_DominatorTreeNode[] dominatorInfoMap; /** * Build a dominator tree from an IR. NOTE: the dominator * information MUST be computed BEFORE calling this method! * We assume the scratch object of each basic block contains * the OPT_LTDominatorInfo object holding this information. * * @param ir the governing IR * @param forward are we building regular dominators or post-dominators? */ public static void perform(OPT_IR ir, boolean forward) { if (forward) { ir.HIRInfo.dominatorTree = new OPT_DominatorTree(ir, forward); if (ir.options.PRINT_DOMINATORS) { if (DEBUG) { System.out.println("Here is the CFG for method " + ir.method.getName() + "\n" + ir.cfg); } System.out.println("Here is the Dominator Tree for method " + ir.method.getName() + "\n" + ir.HIRInfo .dominatorTree); } } else { ir.HIRInfo.postDominatorTree = new OPT_DominatorTree(ir, forward); if (ir.options.PRINT_POST_DOMINATORS) { if (DEBUG) { System.out.println("Here is the CFG for method " + ir.method.getName() + "\n" + ir.cfg); } System.out.println("Here is the Post-Dominator Tree for method " + ir.method.getName() + "\n" + ir.HIRInfo .postDominatorTree); } } } /** * Build a dominator tree from an IR. NOTE: the dominator * information MUST be computed BEFORE calling this * constructor! * * @param ir the governing IR * @param forward are we building regular dominators or post-dominators? */ OPT_DominatorTree(OPT_IR ir, boolean forward) { this.ir = ir; this.forward = forward; // The query methods of dominator information, such as // getDominanceFrontier, dominates, and domFrontierEnumerator // all use ir.getBasicBlock(int). This method relies on // the basic block map being up to date. Here we ensure this // property, even though it is needed for computing the dominator // tree. ir.resetBasicBlockMap(); // allocate the dominator vertex map dominatorInfoMap = new OPT_DominatorTreeNode[ir.getMaxBasicBlockNumber() + 1]; // allocate the tree and root node // Step 1: add all basic blocks to the tree as nodes for (Enumeration<OPT_BasicBlock> bbEnum = ir.cfg.basicBlocks(); bbEnum.hasMoreElements();) { OPT_BasicBlock block = bbEnum.nextElement(); // We treat the exit node as not being part of the CFG if (!forward || !block.isExit()) { addNode(block); } } // Step 2: set the root value setRoot(dominatorInfoMap[getFirstNode().getNumber()]); // Step 3: Walk the nodes, for each node create link with parent // Leaf nodes have no links to add for (Enumeration<OPT_BasicBlock> bbEnum = ir.cfg.basicBlocks(); bbEnum.hasMoreElements();) { OPT_BasicBlock block = bbEnum.nextElement(); // skip the exit node if (forward && block.isExit()) { continue; } // get the tree node corresponding to "block" OPT_DominatorTreeNode blockNode = dominatorInfoMap[block.getNumber()]; // if parent = null, this is the root of the tree, nothing to do if (OPT_LTDominatorInfo.getInfo(block) == null) { System.out.println("info field is null for block: " + block); } OPT_BasicBlock parent = OPT_LTDominatorInfo.getInfo(block).getDominator(); if (parent != null) { OPT_DominatorTreeNode parentNode = dominatorInfoMap[parent.getNumber()]; // tell the parent they have a child parentNode.addChild(blockNode); } } // for loop } // method /** * Get the first node, either entry or exit * depending on which way we are viewing the graph * @return the entry node or exit node */ private OPT_BasicBlock getFirstNode() { if (forward) { return ir.cfg.entry(); } else { return ir.cfg.exit(); } } /** * Enumerate the children of the vertex corresponding to a basic * block * * @param bb the basic block * @return an Enumeration of bb's children */ public Enumeration<OPT_TreeNode> getChildren(OPT_BasicBlock bb) { OPT_DominatorTreeNode node = dominatorInfoMap[bb.getNumber()]; return node.getChildren(); } /** * Return the parent of the vertex corresponding to a basic * block * * @param bb the basic block * @return bb's parent */ public OPT_BasicBlock getParent(OPT_BasicBlock bb) { OPT_DominatorTreeNode node = dominatorInfoMap[bb.getNumber()]; return ((OPT_DominatorTreeNode) node.getParent()).getBlock(); } /** * Return the (already calculated) dominance frontier for * a basic block * * @param bb the basic block * @return a BitVector representing the dominance frontier */ public OPT_BitVector getDominanceFrontier(OPT_BasicBlock bb) { OPT_DominatorTreeNode info = dominatorInfoMap[bb.getNumber()]; return info.getDominanceFrontier(); } /** * Return the (already calculated) dominance frontier for * a basic block * * @param number the number of the basic block * @return a BitVector representing the dominance frontier */ public OPT_BitVector getDominanceFrontier(int number) { return getDominanceFrontier(ir.getBasicBlock(number)); } /** * Does basic block number b dominate all basic blocks in a set? * * @param b the number of the basic block to test * @param bits BitVector representation of the set of basic blocks to test * @return true or false */ public boolean dominates(int b, OPT_BitVector bits) { for (int i = 0; i < bits.length(); i++) { if (!bits.get(i)) { continue; } if (!dominates(b, i)) { return false; } } return true; } /** * Does basic block number "master" dominate basic block number "slave"? * * @param master the number of the proposed "master" basic block * @param slave the number of the proposed "slave block * @return "master dominates slave" */ public boolean dominates(int master, int slave) { OPT_BasicBlock masterBlock = ir.getBasicBlock(master); OPT_BasicBlock slaveBlock = ir.getBasicBlock(slave); OPT_DominatorTreeNode masterNode = dominatorInfoMap[masterBlock.getNumber()]; OPT_DominatorTreeNode slaveNode = dominatorInfoMap[slaveBlock.getNumber()]; return slaveNode.isDominatedBy(masterNode); } /** * Does basic block number "master" dominate basic block number "slave"? * * @param master the number of the proposed "master" basic block * @param slave the number of the proposed "slave block * @return "master dominates slave" */ public boolean dominates(OPT_BasicBlock master, OPT_BasicBlock slave) { OPT_DominatorTreeNode masterNode = dominatorInfoMap[master.getNumber()]; OPT_DominatorTreeNode slaveNode = dominatorInfoMap[slave.getNumber()]; return slaveNode.isDominatedBy(masterNode); } /** * Creates domniator tree nodes for the passed block and adds them to the * map. * @param b the basic block */ private void addNode(OPT_BasicBlock b) { OPT_DominatorTreeNode node = new OPT_DominatorTreeNode(b); dominatorInfoMap[b.getNumber()] = node; } /** * Return the distance from the root of the dominator tree to a given * basic block * * @param b the basic block in question * @return <code>b</code>'s depth */ public int depth(OPT_BasicBlock b) { return dominatorInfoMap[b.getNumber()].getDepth(); } /** * Return the deepest common dominance ancestor of blocks <code>a</code> and <code>b</code> * * @param a The first basic block * @param b The second basic block * @return the deepest common dominance ancestor of blocks <code>a</code> * and <code>b</code> */ public OPT_BasicBlock deepestCommonAncestor(OPT_BasicBlock a, OPT_BasicBlock b) { OPT_DominatorTreeNode n_a = dominatorInfoMap[a.getNumber()]; OPT_DominatorTreeNode n_b = dominatorInfoMap[b.getNumber()]; while (n_a != n_b) { if (n_a.getDepth() > n_b.getDepth()) { n_a = (OPT_DominatorTreeNode) n_a.getParent(); } else { n_b = (OPT_DominatorTreeNode) n_b.getParent(); } } return n_a.getBlock(); } }