001/*
002 *  This file is part of the Jikes RVM project (http://jikesrvm.org).
003 *
004 *  This file is licensed to You under the Eclipse Public License (EPL);
005 *  You may not use this file except in compliance with the License. You
006 *  may obtain a copy of the License at
007 *
008 *      http://www.opensource.org/licenses/eclipse-1.0.php
009 *
010 *  See the COPYRIGHT.txt file distributed with this work for information
011 *  regarding copyright ownership.
012 */
013package org.jikesrvm.compilers.opt.controlflow;
014
015import java.util.Enumeration;
016import java.util.HashMap;
017import java.util.Map;
018
019import org.jikesrvm.VM;
020import org.jikesrvm.compilers.opt.OptimizingCompilerException;
021import org.jikesrvm.compilers.opt.ir.BasicBlock;
022import org.jikesrvm.compilers.opt.ir.ControlFlowGraph;
023import org.jikesrvm.compilers.opt.ir.IR;
024import org.jikesrvm.compilers.opt.util.SpaceEffGraph;
025import org.jikesrvm.compilers.opt.util.SpaceEffGraphEdge;
026import org.jikesrvm.compilers.opt.util.SpaceEffGraphNode;
027import org.jikesrvm.compilers.opt.util.Stack;
028import org.jikesrvm.util.BitVector;
029
030/**
031 * Identify natural loops and builds the LST (Loop Structure Tree)
032 * <p>
033 * Note: throws an exception if an irreducible loop is found
034 * (which I believe could only happen in Java from modified bytecode,
035 *  because Java source code is structured enough to prevent
036 *  irreducible loops.)
037 *
038 * @see DominatorsPhase
039 */
040public class LSTGraph extends SpaceEffGraph {
041  private static final boolean DEBUG = false;
042
043  protected LSTNode rootNode;
044  /** Map of bb to LSTNode of innermost loop containing bb */
045  private final HashMap<BasicBlock, LSTNode> loopMap;
046
047  private IR ir;
048
049  /**
050   * The main entry point
051   * @param ir the IR to process
052   */
053  public static void perform(IR ir) {
054    if (DEBUG) System.out.println("LSTGraph:" + ir.method);
055    ir.HIRInfo.loopStructureTree = new LSTGraph(ir);
056    if (DEBUG) {
057      System.out.println(ir.HIRInfo.loopStructureTree.toString());
058    }
059  }
060
061  /**
062   * @param bb the basic block
063   * @return the loop nesting depth or 0, if not in loop
064   */
065  public int getLoopNestDepth(BasicBlock bb) {
066    LSTNode loop = loopMap.get(bb);
067    if (loop == null) return 0;
068    return loop.depth;
069  }
070
071  /**
072   * Is a given basic block in an innermost loop?
073   * @param bb the basic block
074   * @return whether the block is in an innermost loop
075   */
076  public boolean inInnermostLoop(BasicBlock bb) {
077    LSTNode node = loopMap.get(bb);
078    return node != null && node.firstOutEdge() == null && node.loop != null;
079  }
080
081  public boolean isLoopExit(BasicBlock source, BasicBlock target) {
082    LSTNode snode = loopMap.get(source);
083    LSTNode tnode = loopMap.get(target);
084
085    if (snode == null || snode == rootNode) return false; // source isn't in a loop
086    if (tnode == null || tnode == rootNode) return true;  // source is in a loop and target isn't
087    if (snode == tnode) return false; // in same loop
088
089    for (LSTNode ptr = tnode; ptr != rootNode; ptr = ptr.getParent()) {
090      if (ptr == snode) return false; // tnode is nested inside of snode
091    }
092
093    return true;
094  }
095
096  public LSTNode getLoop(BasicBlock b) {
097    return loopMap.get(b);
098  }
099
100  /**
101   * Return the root node of the tree
102   * @return the root node of the loop structure tree
103   */
104  public LSTNode getRoot() {
105    return rootNode;
106  }
107
108  @Override
109  public String toString() {
110    return "LST:\n" + dumpIt(rootNode);
111  }
112
113  private String dumpIt(LSTNode n) {
114    StringBuilder ans = new StringBuilder(n.toString());
115    ans.append('\n');
116    for (Enumeration<LSTNode> e = n.getChildren(); e.hasMoreElements();) {
117      ans.append(dumpIt(e.nextElement()));
118    }
119    return ans.toString();
120  }
121
122  /*
123  * Code to construct the LST for an IR.
124  */
125
126  /**
127   * Copying constructor
128   *
129   * @param graph to copy
130   */
131  protected LSTGraph(LSTGraph graph) {
132    rootNode = graph.rootNode;
133    loopMap = graph.loopMap;
134  }
135
136  /**
137   * Constructor, it creates the LST graph
138   * @param  ir the IR
139   */
140  private LSTGraph(IR ir) {
141    this.ir = ir;
142    loopMap = new HashMap<BasicBlock, LSTNode>();
143
144    ControlFlowGraph cfg = ir.cfg;
145    BasicBlock entry = ir.cfg.entry();
146
147    // do DFN pass
148    cfg.clearDFS();
149    entry.sortDFS();
150    int dfn = 0;
151    Map<SpaceEffGraphNode, Integer> dfnMap = new HashMap<SpaceEffGraphNode, Integer>();
152    for (SpaceEffGraphNode node = entry; node != null; node = node.nextSorted) {
153      node.clearLoopHeader();
154      dfnMap.put(node, Integer.valueOf(dfn++));
155      clearBackEdges(node);
156    }
157    cfg.clearDFS();
158    int bbCount = ir.cfg.numberOfNodes();
159    findBackEdges(entry, bbCount, dfnMap);
160
161    // entry node is considered the LST head
162    LSTNode lstheader = new LSTNode(entry);
163    rootNode = lstheader;
164    addGraphNode(lstheader);
165
166    // compute the natural loops for each back edge.
167    // merge backedges with the same header
168    for (BasicBlock node = (BasicBlock) entry.nextSorted; node != null; node = (BasicBlock) node.nextSorted) {
169      LSTNode header = null;
170      for (SpaceEffGraphEdge edge = node.firstInEdge(); edge != null; edge = edge.getNextIn()) {
171        if (edge.backEdge()) {
172          BitVector loop;
173          if (header == null) {
174            header = new LSTNode(node);
175            addGraphNode(header);
176            loop = new BitVector(cfg.numberOfNodes());
177            loop.set(node.getNumber());
178            header.loop = loop;
179            if (DEBUG) {
180              System.out.println("header" + header);
181            }
182          } else {
183            loop = header.loop;
184          }
185          cfg.clearDFS();
186          node.setDfsVisited();
187          findNaturalLoop(edge, loop);
188        }
189      }
190    }
191    if (DEBUG) {
192      for (SpaceEffGraphNode node = _firstNode; node != null; node = node.getNext()) {
193        System.out.println(node);
194      }
195    }
196
197    // now build the LST
198    lstloop:
199    for (LSTNode node = (LSTNode) _firstNode.getNext(); node != null; node = (LSTNode) node.getNext()) {
200      int number = node.header.getNumber();
201      for (LSTNode prev = (LSTNode) node.getPrev(); prev != _firstNode; prev = (LSTNode) prev.getPrev()) {
202        if (prev.loop.get(number)) {            // nested
203          prev.insertOut(node);
204          continue lstloop;
205        }
206      }
207      // else the node is considered to be connected to the LST head
208      _firstNode.insertOut(node);
209    }
210
211    // Set loop nest depth for each node in the LST and initialize LoopMap
212    ir.resetBasicBlockMap();
213    setDepth(ir, rootNode, 0);
214  }
215
216  private void setDepth(IR ir, LSTNode node, int depth) {
217    if (VM.VerifyAssertions) VM._assert(node.depth == 0);
218    node.depth = depth;
219    for (Enumeration<LSTNode> e = node.getChildren(); e.hasMoreElements();) {
220      setDepth(ir, e.nextElement(), depth + 1);
221    }
222    BitVector loop = node.loop;
223    if (loop != null) {
224      for (int i = 0; i < loop.length(); i++) {
225        if (loop.get(i)) {
226          BasicBlock bb = ir.getBasicBlock(i);
227          if (loopMap.get(bb) == null) {
228            loopMap.put(bb, node);
229          }
230        }
231      }
232    }
233  }
234
235  /**
236   * This routine performs a non-recursive depth-first search starting at
237   *  the block passed looking for back edges.  It uses dominator information
238   *  to determine back edges.
239   * @param bb        The basic block to process
240   * @param numBlocks The number of basic blocks
241   * @param dfnMap numbering from the depth first traversal
242   */
243  private void findBackEdges(BasicBlock bb, int numBlocks, Map<SpaceEffGraphNode, Integer> dfnMap) {
244    Stack<BasicBlock> stack = new Stack<BasicBlock>();
245    SpaceEffGraphNode.OutEdgeEnumeration[] BBenum = new SpaceEffGraphNode.OutEdgeEnumeration[numBlocks];
246
247    // push node on to the emulated activation stack
248    stack.push(bb);
249
250    recurse:
251    while (!stack.empty()) {
252      bb = stack.peek();
253
254      // check if we were already processing this node, if so we would have
255      // saved the state of the enumeration in the loop below
256      SpaceEffGraphNode.OutEdgeEnumeration e = BBenum[bb.getNumber()];
257      if (e == null) {
258        if (DEBUG) {
259          System.out.println(" Initial processing of " + bb);
260        }
261        bb.setDfsVisited();
262        e = bb.outEdges();
263      } else {
264        if (DEBUG) {
265          System.out.println(" Resuming processing of " + bb);
266        }
267      }
268
269      while (e.hasMoreElements()) {
270        SpaceEffGraphEdge outEdge = (SpaceEffGraphEdge) e.next();
271
272        BasicBlock outbb = (BasicBlock) outEdge.toNode();
273        if (LTDominatorInfo.isDominatedBy(bb, outbb, ir)) {   // backedge
274          outbb.setLoopHeader();
275          outEdge.setBackEdge();
276          if (DEBUG) {
277            System.out.println("backedge from " +
278                               dfnMap.get(bb) +
279                               " ( " + bb + " ) " +
280                               dfnMap.get(outbb) +
281                               " ( " + outbb + " ) ");
282          }
283        } else if (!outbb.dfsVisited()) {
284          // irreducible loop test
285          if (dfnMap.get(outbb) < dfnMap.get(bb)) {
286            throw new OptimizingCompilerException("irreducible loop found!");
287          }
288          // simulate a recursive call
289          // but first save the enumeration state for resumption later
290          BBenum[bb.getNumber()] = e;
291          stack.push(outbb);
292          continue recurse;
293        }
294      } // enum
295      // "Pop" from the emulated activiation stack
296      if (DEBUG) {
297        System.out.println(" Popping");
298      }
299      stack.pop();
300    } // while !empty
301  }
302
303  /**
304   * Clears the back edges for the basic block passed
305   * @param bb the basic block
306   */
307  private void clearBackEdges(SpaceEffGraphNode bb) {
308    SpaceEffGraphNode.OutEdgeEnumeration f = bb.outEdges();
309    while (f.hasMoreElements()) {
310      SpaceEffGraphEdge outEdge = (SpaceEffGraphEdge) f.next();
311      outEdge.clearBackEdge();
312    }
313  }
314
315  /**
316   * This routine implements part of the algorithm to compute natural loops
317   *  as defined in Muchnick p 192.  See caller for more details.
318   * @param edge the edge to process
319   * @param loop bit vector to hold the results of the algorithm
320   */
321  private void findNaturalLoop(SpaceEffGraphEdge edge, BitVector loop) {
322
323    /* Algorithm to compute Natural Loops, Muchnick, pp. 192:
324       procedure Nat_Loop(m,n,Pred) return set of Node
325       m, n: in Node
326       Pred: in Node -> set of Node
327       begin
328       Loop:  set of Node
329       Stack: sequence of Node
330       p, q: Node
331       Stack := []
332       Loop  := {m,n}
333       if m != n then
334       Stack += [m]
335       while Stack != [] do
336       // add predecessors of m that are not predecessors of n
337       // to the set of nodes in the loop; since n dominates m,
338       // this only adds nodes in the loop
339       p := Stack drop -1
340       Stack -= -1
341       for each q in Pred(p) do
342       if q belongs Loop then
343       Loop U= {q}
344       Stack += [q]
345
346       return Loop
347       end
348    */
349
350    SpaceEffGraphNode fromNode = edge.fromNode();
351    if (!fromNode.dfsVisited()) {
352      fromNode.setDfsVisited();
353      loop.set(fromNode.getNumber());
354      for (SpaceEffGraphEdge in = fromNode.firstInEdge(); in != null; in = in.getNextIn()) {
355        findNaturalLoop(in, loop);
356      }
357    }
358  }
359}