/*
* 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 java.util.HashMap;
import org.jikesrvm.VM;
import org.jikesrvm.compilers.opt.ir.OPT_BasicBlock;
import org.jikesrvm.compilers.opt.ir.OPT_ControlFlowGraph;
import org.jikesrvm.compilers.opt.ir.OPT_IR;
/**
* Identify natural loops and builds the LST (Loop Structure Tree)
*
* 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 OPT_DominatorsPhase
*/
public class OPT_LSTGraph extends OPT_SpaceEffGraph {
private static final boolean DEBUG = false;
protected OPT_LSTNode rootNode;
/** Map of bb to OPT_LSTNode of innermost loop containing bb */
private final HashMap<OPT_BasicBlock, OPT_LSTNode> loopMap;
/**
* The main entry point
* @param ir the IR to process
*/
public static void perform(OPT_IR ir) {
if (DEBUG) System.out.println("LSTGraph:" + ir.method);
ir.HIRInfo.LoopStructureTree = new OPT_LSTGraph(ir);
if (DEBUG) {
OPT_VCG.printVCG("cfg", ir.cfg);
OPT_VCG.printVCG("lst", ir.HIRInfo.LoopStructureTree);
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(OPT_BasicBlock bb) {
OPT_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(OPT_BasicBlock bb) {
OPT_LSTNode node = loopMap.get(bb);
return node != null && node.firstOutEdge() == null && node.loop != null;
}
/**
* Is the edge from source to target an exit from the loop containing source?
* @param source the basic block that is the source of the edge
* @param target the basic block that is the target of the edge
*/
public boolean isLoopExit(OPT_BasicBlock source, OPT_BasicBlock target) {
OPT_LSTNode snode = loopMap.get(source);
OPT_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 (OPT_LSTNode ptr = tnode; ptr != rootNode; ptr = ptr.getParent()) {
if (ptr == snode) return false; // tnode is nested inside of snode
}
return true;
}
public OPT_LSTNode getLoop(OPT_BasicBlock b) {
return loopMap.get(b);
}
/**
* Return the root node of the tree
* @return the root node of the loop structure tree
*/
public OPT_LSTNode getRoot() {
return rootNode;
}
public String toString() {
return "LST:\n" + dumpIt(rootNode);
}
private String dumpIt(OPT_LSTNode n) {
String ans = n.toString() + "\n";
for (Enumeration<OPT_LSTNode> e = n.getChildren(); e.hasMoreElements();) {
ans += dumpIt(e.nextElement());
}
return ans;
}
/*
* Code to construct the LST for an IR.
*/
/**
* Copying constructor
*
* @param graph to copy
*/
protected OPT_LSTGraph(OPT_LSTGraph graph) {
rootNode = graph.rootNode;
loopMap = graph.loopMap;
}
/**
* Constructor, it creates the LST graph
* @param ir the IR
*/
private OPT_LSTGraph(OPT_IR ir) {
loopMap = new HashMap<OPT_BasicBlock, OPT_LSTNode>();
OPT_ControlFlowGraph cfg = ir.cfg;
OPT_BasicBlock entry = ir.cfg.entry();
// do DFN pass
cfg.clearDFS();
entry.sortDFS();
int dfn = 0;
for (OPT_SpaceEffGraphNode node = entry; node != null; node = node.nextSorted) {
node.clearLoopHeader();
node.scratch = dfn++;
clearBackEdges(node);
}
cfg.clearDFS();
findBackEdges(entry, ir.cfg.numberOfNodes());
// entry node is considered the LST head
OPT_LSTNode lstheader = new OPT_LSTNode(entry);
rootNode = lstheader;
addGraphNode(lstheader);
// compute the natural loops for each back edge.
// merge backedges with the same header
for (OPT_BasicBlock node = (OPT_BasicBlock) entry.nextSorted; node != null; node = (OPT_BasicBlock) node.nextSorted)
{
OPT_LSTNode header = null;
for (OPT_SpaceEffGraphEdge edge = node.firstInEdge(); edge != null; edge = edge.getNextIn()) {
if (edge.backEdge()) {
OPT_BitVector loop;
if (header == null) {
header = new OPT_LSTNode(node);
addGraphNode(header);
loop = new OPT_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 (OPT_SpaceEffGraphNode node = _firstNode; node != null; node = node.getNext()) {
System.out.println(node);
}
}
// now build the LST
lstloop:
for (OPT_LSTNode node = (OPT_LSTNode) _firstNode.getNext(); node != null; node = (OPT_LSTNode) node.getNext()) {
int number = node.header.getNumber();
for (OPT_LSTNode prev = (OPT_LSTNode) node.getPrev(); prev != _firstNode; prev = (OPT_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(OPT_IR ir, OPT_LSTNode node, int depth) {
if (VM.VerifyAssertions) VM._assert(node.depth == 0);
node.depth = depth;
for (Enumeration<OPT_LSTNode> e = node.getChildren(); e.hasMoreElements();) {
setDepth(ir, e.nextElement(), depth + 1);
}
OPT_BitVector loop = node.loop;
if (loop != null) {
for (int i = 0; i < loop.length(); i++) {
if (loop.get(i)) {
OPT_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
*/
private void findBackEdges(OPT_BasicBlock bb, int numBlocks) {
OPT_Stack<OPT_BasicBlock> stack = new OPT_Stack<OPT_BasicBlock>();
OPT_SpaceEffGraphNode.OutEdgeEnumeration[] BBenum = new OPT_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
OPT_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()) {
OPT_SpaceEffGraphEdge outEdge = (OPT_SpaceEffGraphEdge) e.next();
OPT_BasicBlock outbb = (OPT_BasicBlock) outEdge.toNode();
if (OPT_LTDominatorInfo.isDominatedBy(bb, outbb)) { // backedge
outbb.setLoopHeader();
outEdge.setBackEdge();
if (DEBUG) {
System.out.println("backedge from " +
bb
.scratch +
" ( " +
bb +
" ) " +
outbb
.scratch +
" ( " +
outbb +
" ) ");
}
} else if (!outbb.dfsVisited()) {
// irreducible loop test
if (outbb.scratch < bb.scratch) {
throw new OPT_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(OPT_SpaceEffGraphNode bb) {
OPT_SpaceEffGraphNode.OutEdgeEnumeration f = bb.outEdges();
while (f.hasMoreElements()) {
OPT_SpaceEffGraphEdge outEdge = (OPT_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(OPT_SpaceEffGraphEdge edge, OPT_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
*/
OPT_SpaceEffGraphNode fromNode = edge.fromNode();
if (!fromNode.dfsVisited()) {
fromNode.setDfsVisited();
loop.set(fromNode.getNumber());
for (OPT_SpaceEffGraphEdge in = fromNode.firstInEdge(); in != null; in = in.getNextIn()) {
findNaturalLoop(in, loop);
}
}
}
}