/*
* This file is part of the Jikes RVM project (http://jikesrvm.org).
*
* This file is licensed to You under the Eclipse Public License (EPL);
* 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/eclipse-1.0.php
*
* See the COPYRIGHT.txt file distributed with this work for information
* regarding copyright ownership.
*/
package org.jikesrvm.compilers.opt.controlflow;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;
import org.jikesrvm.VM;
import org.jikesrvm.compilers.opt.OptimizingCompilerException;
import org.jikesrvm.compilers.opt.ir.BasicBlock;
import org.jikesrvm.compilers.opt.ir.ControlFlowGraph;
import org.jikesrvm.compilers.opt.ir.IR;
import org.jikesrvm.compilers.opt.util.SpaceEffGraph;
import org.jikesrvm.compilers.opt.util.SpaceEffGraphEdge;
import org.jikesrvm.compilers.opt.util.SpaceEffGraphNode;
import org.jikesrvm.compilers.opt.util.Stack;
import org.jikesrvm.util.BitVector;
/**
* Identify natural loops and builds the LST (Loop Structure Tree)
* <p>
* Note: throws an exception if an irreducible loop is found
* (which I believe could only happen in Java from modified bytecode,
* because Java source code is structured enough to prevent
* irreducible loops.)
*
* @see DominatorsPhase
*/
public class LSTGraph extends SpaceEffGraph {
private static final boolean DEBUG = false;
protected LSTNode rootNode;
/** Map of bb to LSTNode of innermost loop containing bb */
private final HashMap<BasicBlock, LSTNode> loopMap;
private IR ir;
/**
* The main entry point
* @param ir the IR to process
*/
public static void perform(IR ir) {
if (DEBUG) System.out.println("LSTGraph:" + ir.method);
ir.HIRInfo.loopStructureTree = new LSTGraph(ir);
if (DEBUG) {
System.out.println(ir.HIRInfo.loopStructureTree.toString());
}
}
/**
* @param bb the basic block
* @return the loop nesting depth or 0, if not in loop
*/
public int getLoopNestDepth(BasicBlock bb) {
LSTNode loop = loopMap.get(bb);
if (loop == null) return 0;
return loop.depth;
}
/**
* Is a given basic block in an innermost loop?
* @param bb the basic block
* @return whether the block is in an innermost loop
*/
public boolean inInnermostLoop(BasicBlock bb) {
LSTNode node = loopMap.get(bb);
return node != null && node.firstOutEdge() == null && node.loop != null;
}
public boolean isLoopExit(BasicBlock source, BasicBlock target) {
LSTNode snode = loopMap.get(source);
LSTNode tnode = loopMap.get(target);
if (snode == null || snode == rootNode) return false; // source isn't in a loop
if (tnode == null || tnode == rootNode) return true; // source is in a loop and target isn't
if (snode == tnode) return false; // in same loop
for (LSTNode ptr = tnode; ptr != rootNode; ptr = ptr.getParent()) {
if (ptr == snode) return false; // tnode is nested inside of snode
}
return true;
}
public LSTNode getLoop(BasicBlock b) {
return loopMap.get(b);
}
/**
* Return the root node of the tree
* @return the root node of the loop structure tree
*/
public LSTNode getRoot() {
return rootNode;
}
@Override
public String toString() {
return "LST:\n" + dumpIt(rootNode);
}
private String dumpIt(LSTNode n) {
StringBuilder ans = new StringBuilder(n.toString());
ans.append('\n');
for (Enumeration<LSTNode> e = n.getChildren(); e.hasMoreElements();) {
ans.append(dumpIt(e.nextElement()));
}
return ans.toString();
}
/*
* Code to construct the LST for an IR.
*/
/**
* Copying constructor
*
* @param graph to copy
*/
protected LSTGraph(LSTGraph graph) {
rootNode = graph.rootNode;
loopMap = graph.loopMap;
}
/**
* Constructor, it creates the LST graph
* @param ir the IR
*/
private LSTGraph(IR ir) {
this.ir = ir;
loopMap = new HashMap<BasicBlock, LSTNode>();
ControlFlowGraph cfg = ir.cfg;
BasicBlock entry = ir.cfg.entry();
// do DFN pass
cfg.clearDFS();
entry.sortDFS();
int dfn = 0;
Map<SpaceEffGraphNode, Integer> dfnMap = new HashMap<SpaceEffGraphNode, Integer>();
for (SpaceEffGraphNode node = entry; node != null; node = node.nextSorted) {
node.clearLoopHeader();
dfnMap.put(node, Integer.valueOf(dfn++));
clearBackEdges(node);
}
cfg.clearDFS();
int bbCount = ir.cfg.numberOfNodes();
findBackEdges(entry, bbCount, dfnMap);
// entry node is considered the LST head
LSTNode lstheader = new LSTNode(entry);
rootNode = lstheader;
addGraphNode(lstheader);
// compute the natural loops for each back edge.
// merge backedges with the same header
for (BasicBlock node = (BasicBlock) entry.nextSorted; node != null; node = (BasicBlock) node.nextSorted) {
LSTNode header = null;
for (SpaceEffGraphEdge edge = node.firstInEdge(); edge != null; edge = edge.getNextIn()) {
if (edge.backEdge()) {
BitVector loop;
if (header == null) {
header = new LSTNode(node);
addGraphNode(header);
loop = new BitVector(cfg.numberOfNodes());
loop.set(node.getNumber());
header.loop = loop;
if (DEBUG) {
System.out.println("header" + header);
}
} else {
loop = header.loop;
}
cfg.clearDFS();
node.setDfsVisited();
findNaturalLoop(edge, loop);
}
}
}
if (DEBUG) {
for (SpaceEffGraphNode node = _firstNode; node != null; node = node.getNext()) {
System.out.println(node);
}
}
// now build the LST
lstloop:
for (LSTNode node = (LSTNode) _firstNode.getNext(); node != null; node = (LSTNode) node.getNext()) {
int number = node.header.getNumber();
for (LSTNode prev = (LSTNode) node.getPrev(); prev != _firstNode; prev = (LSTNode) prev.getPrev()) {
if (prev.loop.get(number)) { // nested
prev.insertOut(node);
continue lstloop;
}
}
// else the node is considered to be connected to the LST head
_firstNode.insertOut(node);
}
// Set loop nest depth for each node in the LST and initialize LoopMap
ir.resetBasicBlockMap();
setDepth(ir, rootNode, 0);
}
private void setDepth(IR ir, LSTNode node, int depth) {
if (VM.VerifyAssertions) VM._assert(node.depth == 0);
node.depth = depth;
for (Enumeration<LSTNode> e = node.getChildren(); e.hasMoreElements();) {
setDepth(ir, e.nextElement(), depth + 1);
}
BitVector loop = node.loop;
if (loop != null) {
for (int i = 0; i < loop.length(); i++) {
if (loop.get(i)) {
BasicBlock bb = ir.getBasicBlock(i);
if (loopMap.get(bb) == null) {
loopMap.put(bb, node);
}
}
}
}
}
/**
* This routine performs a non-recursive depth-first search starting at
* the block passed looking for back edges. It uses dominator information
* to determine back edges.
* @param bb The basic block to process
* @param numBlocks The number of basic blocks
* @param dfnMap numbering from the depth first traversal
*/
private void findBackEdges(BasicBlock bb, int numBlocks, Map<SpaceEffGraphNode, Integer> dfnMap) {
Stack<BasicBlock> stack = new Stack<BasicBlock>();
SpaceEffGraphNode.OutEdgeEnumeration[] BBenum = new SpaceEffGraphNode.OutEdgeEnumeration[numBlocks];
// push node on to the emulated activation stack
stack.push(bb);
recurse:
while (!stack.empty()) {
bb = stack.peek();
// check if we were already processing this node, if so we would have
// saved the state of the enumeration in the loop below
SpaceEffGraphNode.OutEdgeEnumeration e = BBenum[bb.getNumber()];
if (e == null) {
if (DEBUG) {
System.out.println(" Initial processing of " + bb);
}
bb.setDfsVisited();
e = bb.outEdges();
} else {
if (DEBUG) {
System.out.println(" Resuming processing of " + bb);
}
}
while (e.hasMoreElements()) {
SpaceEffGraphEdge outEdge = (SpaceEffGraphEdge) e.next();
BasicBlock outbb = (BasicBlock) outEdge.toNode();
if (LTDominatorInfo.isDominatedBy(bb, outbb, ir)) { // backedge
outbb.setLoopHeader();
outEdge.setBackEdge();
if (DEBUG) {
System.out.println("backedge from " +
dfnMap.get(bb) +
" ( " + bb + " ) " +
dfnMap.get(outbb) +
" ( " + outbb + " ) ");
}
} else if (!outbb.dfsVisited()) {
// irreducible loop test
if (dfnMap.get(outbb) < dfnMap.get(bb)) {
throw new OptimizingCompilerException("irreducible loop found!");
}
// simulate a recursive call
// but first save the enumeration state for resumption later
BBenum[bb.getNumber()] = e;
stack.push(outbb);
continue recurse;
}
} // enum
// "Pop" from the emulated activiation stack
if (DEBUG) {
System.out.println(" Popping");
}
stack.pop();
} // while !empty
}
/**
* Clears the back edges for the basic block passed
* @param bb the basic block
*/
private void clearBackEdges(SpaceEffGraphNode bb) {
SpaceEffGraphNode.OutEdgeEnumeration f = bb.outEdges();
while (f.hasMoreElements()) {
SpaceEffGraphEdge outEdge = (SpaceEffGraphEdge) f.next();
outEdge.clearBackEdge();
}
}
/**
* This routine implements part of the algorithm to compute natural loops
* as defined in Muchnick p 192. See caller for more details.
* @param edge the edge to process
* @param loop bit vector to hold the results of the algorithm
*/
private void findNaturalLoop(SpaceEffGraphEdge edge, BitVector loop) {
/* Algorithm to compute Natural Loops, Muchnick, pp. 192:
procedure Nat_Loop(m,n,Pred) return set of Node
m, n: in Node
Pred: in Node -> set of Node
begin
Loop: set of Node
Stack: sequence of Node
p, q: Node
Stack := []
Loop := {m,n}
if m != n then
Stack += [m]
while Stack != [] do
// add predecessors of m that are not predecessors of n
// to the set of nodes in the loop; since n dominates m,
// this only adds nodes in the loop
p := Stack drop -1
Stack -= -1
for each q in Pred(p) do
if q belongs Loop then
Loop U= {q}
Stack += [q]
return Loop
end
*/
SpaceEffGraphNode fromNode = edge.fromNode();
if (!fromNode.dfsVisited()) {
fromNode.setDfsVisited();
loop.set(fromNode.getNumber());
for (SpaceEffGraphEdge in = fromNode.firstInEdge(); in != null; in = in.getNextIn()) {
findNaturalLoop(in, loop);
}
}
}
}