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