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}