public void writeInline(EmitContext emitContext, InstructionAdapter mv) { // Last check for assumption violations types.verifyFunctionAssumptions(runtimeState); Label exitLabel = new Label(); for (BasicBlock basicBlock : cfg.getBasicBlocks()) { if (basicBlock != cfg.getEntry() && basicBlock != cfg.getExit()) { for (IRLabel label : basicBlock.getLabels()) { mv.visitLabel(emitContext.getAsmLabel(label)); } for (Statement stmt : basicBlock.getStatements()) { try { if (stmt instanceof ReturnStatement) { // Instead of returning, just push the return value on the stack // and jump to the exit point for the function. stmt.getRHS().load(emitContext, mv); mv.goTo(exitLabel); } else { stmt.emit(emitContext, mv); } } catch (NotCompilableException e) { throw e; } catch (Exception e) { throw new InternalCompilerException("Exception compiling statement " + stmt, e); } } } } mv.mark(exitLabel); }
public RPST build() { // find canonical regions detectRegions(); // build tree of canonical regions RPSTRegion root = new RPSTRegion(cfg.getEntryBlock(), null); buildRegionTree(cfg.getEntryBlock(), root); // build children for (RPSTRegion r : bb2region.values()) { for (RPSTRegion r2 = r; r2 != null; r2 = r2.parent) { if (r2.parent != null) { r2.parent.children.add(r2); } } } RPST rpst = new RPST(cfg, new RegionImpl(cfg.getEntryBlock(), null, ParentType.ROOT)); Map<RPSTRegion, Region> mapR = new HashMap<>(); a(root, rpst.getRootRegion(), rpst, mapR); for (Map.Entry<BasicBlock, RPSTRegion> entry : bb2region.entrySet()) { BasicBlock bb = entry.getKey(); RPSTRegion r = entry.getValue(); Region r2 = mapR.get(r); rpst.addRegion(bb, r2); } // add non canonical region to the tree findNonCanonicalRegions(rpst, rpst.getRootRegion()); return rpst; }
private void enforceSingleEntry() { Debug.debugMessage(getClass(), "Enforcing single entry in CFG", 3); ArrayList<Vertex> noPreds = new ArrayList<Vertex>(); for (Vertex v : cfg) { if (v.numOfPredecessors() == 0) { Debug.debugMessage(getClass(), v.getVertexID() + " is currently an entry vertex", 4); noPreds.add(v); } } while (noPreds.size() > 1) { int newVertexID = cfg.getNextVertexID(); cfg.addBasicBlock(newVertexID); Debug.debugMessage(getClass(), "Adding basic block " + newVertexID, 4); for (int i = 1; i <= MainProgramGenerator.Globals.getFanOut(); ++i) { if (!noPreds.isEmpty()) { Vertex v = noPreds.remove(noPreds.size() - 1); Debug.debugMessage(getClass(), "...and connecting it to " + v.getVertexID(), 4); if (i == 1) { cfg.addEdge(newVertexID, v.getVertexID(), BranchType.TAKEN); } else { cfg.addEdge(newVertexID, v.getVertexID(), BranchType.NOTTAKEN); } } } noPreds.add(cfg.getVertex(newVertexID)); } }
private ArrayList<Integer> setLoopEntryExit(int n, int position) { ArrayList<Integer> result = new ArrayList<Integer>(); int entryID, exitID; if (n == 1) { int id = cfg.getNextVertexID(); cfg.addBasicBlock(id); entryID = id; exitID = id; } else if (n < 3) { addNonBranchComponents(n); exitID = disconnectedVertices.get(0); entryID = disconnectedVertices.get(disconnectedVertices.size() - 1); } else { addBranchComponents(n); exitID = disconnectedBranches.get(0); entryID = disconnectedBranches.get(disconnectedBranches.size() - 1); } if (position == 1) { result.add(exitID); result.add(entryID); } else { result.add(entryID); result.add(exitID); } return result; }
/** * Gets all the edges of the graph. */ private static List<DiGraphEdge<Node, Branch>> getAllEdges( ControlFlowGraph<Node> cfg) { List<DiGraphEdge<Node, Branch>> edges = new ArrayList<>(); for (DiGraphNode<Node, Branch> n : cfg.getDirectedGraphNodes()) { edges.addAll(cfg.getOutEdges(n.getValue())); } return edges; }
@Test public void singleBlock() { IRBody block = buildBody("y<-x+1;z<-3; 4"); ControlFlowGraph cfg = new ControlFlowGraph(block); System.out.println(cfg); List<BasicBlock> basicBlocks = cfg.getBasicBlocks(); assertThat(basicBlocks.size(), equalTo(3)); // entry + 1 + exit = 3 assertThat(basicBlocks.get(1).getStatements().size(), equalTo(block.getStatements().size())); }
@Test public void forLoop() { IRBody block = buildBody("y <- 0; for(i in 1:10) y <- y + i; sqrt(y + 3 * x)"); System.out.println(block); ControlFlowGraph cfg = new ControlFlowGraph(block); System.out.println(cfg); List<BasicBlock> basicBlocks = cfg.getBasicBlocks(); assertThat(basicBlocks.size(), equalTo(7)); }
private void printAllRegions() { for (BasicBlock bb1 : cfg.getBasicBlocks()) { for (BasicBlock bb2 : cfg.getBasicBlocks()) { if (!bb1.equals(bb2) && getDomInfo().dominates(bb1, bb2)) { if (isRegion(bb1, bb2)) { LOGGER.debug("REGION {},{}", bb1, bb2); } } } } }
private void addSelfLoops() { int counter = MainProgramGenerator.Globals.getNumberOfSelfLoops(); while (counter > 0) { int vertexID; do { vertexID = random.nextInt(cfg.numOfVertices() + 1); } while (vertexID == cfg.getEntryID()); Debug.debugMessage(getClass(), "Adding self-loop " + vertexID + " => " + vertexID, 4); cfg.addEdge(vertexID, vertexID, BranchType.TAKEN); counter--; } }
private void addLoops() { int loops = MainProgramGenerator.Globals.getNumberOfLoops(); int vertices = MainProgramGenerator.Globals.getNumberOfVerticesInCFG(); if (vertices == 1) { cfg.addBasicBlock(vertices); } else { if (loops == 0) { addNoLoops(vertices); } else { int entryID, exitID, endOfExitStructure = 0; remainingVertices = vertices - 2 * loops; if (remainingVertices == 2) { entryID = setLoopEntryExit(1, 0).get(0); exitID = setLoopEntryExit(1, 1).get(0); remainingVertices = 0; } else { int loopEntry = random.nextInt(remainingVertices / 2) + 1; remainingVertices -= loopEntry; entryID = setLoopEntryExit(loopEntry, 0).get(0); int loopExit = random.nextInt(remainingVertices / 2) + 1; remainingVertices -= loopExit; ArrayList<Integer> exit = setLoopEntryExit(loopExit, 1); exitID = exit.get(0); endOfExitStructure = exit.get(1); } buildIndividualLoops(loops); initLevelMap(); setLoopTree(loops); connectLoops(); if (remainingVertices > 0) { int newExitID = setLoopEntryExit(remainingVertices, 1).get(0); remainingVertices = 0; Debug.debugMessage(getClass(), "Adding edge " + endOfExitStructure + "=>" + newExitID, 4); cfg.addEdge(endOfExitStructure, newExitID, BranchType.TAKEN); } Debug.debugMessage( getClass(), "Adding entry edge " + entryID + "=>" + disconnectedLoopsArray.get(0), 4); cfg.addEdge(entryID, disconnectedLoopsArray.get(0), BranchType.TAKEN); Debug.debugMessage( getClass(), "Adding exit edge " + disconnectedLoopsArray.get(0) + "=>" + exitID, 4); cfg.addEdge(disconnectedLoopsArray.get(0), exitID, BranchType.TAKEN); } } }
/** @return true if all paths from block must exit with an explicit return. */ private boolean allPathsReturn(Node function) { // Computes the control flow graph. ControlFlowAnalysis cfa = new ControlFlowAnalysis(compiler, false, false); cfa.process(null, function); ControlFlowGraph<Node> cfg = cfa.getCfg(); Node returnPathsParent = cfg.getImplicitReturn().getValue(); for (DiGraphNode<Node, Branch> pred : cfg.getDirectedPredNodes(returnPathsParent)) { Node n = pred.getValue(); if (!n.isReturn()) { return false; } } return true; }
private void addNonBranchComponents(int n) { disconnectedVertices = new ArrayList<Integer>(); for (int i = 0; i < n; ++i) { int vertexID = cfg.getNextVertexID(); Debug.debugMessage(getClass(), "Adding basic block " + vertexID, 4); cfg.addBasicBlock(vertexID); disconnectedVertices.add(vertexID); } for (int i = 0; i < disconnectedVertices.size() - 1; ++i) { Debug.debugMessage( getClass(), "Adding edge " + disconnectedVertices.get(i) + "=>" + disconnectedVertices.get(i + 1), 4); cfg.addEdge(disconnectedVertices.get(i), disconnectedVertices.get(i + 1), BranchType.TAKEN); } }
@Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + ((cfg == null) ? 0 : cfg.hashCode()); result = prime * result + ((context == null) ? 0 : context.hashCode()); return result; }
private boolean isCommonDomFrontier(BasicBlock bb, BasicBlock entry, BasicBlock exit) { for (BasicBlock p : cfg.getPredecessorsOf(bb)) { if (getDomInfo().dominates(entry, p) && !getDomInfo().dominates(exit, p)) { return false; } } return true; }
private void addIndirectEntrypoints(ControlFlowGraph.Edge edge, ControlFlowGraph cfg) { List<Integer> edges = program.getIndirectEdges(edge.getSource().getLastAddress()); if (edges == null) return; for (Integer targetAddr : edges) { ControlFlowGraph.Block target = cfg.getBlockStartingAt(targetAddr); if (target != null) { ENTRYPOINTS.add(target); } } }
/** Test if two canonical regions could be merge in one non canonical region. */ private boolean isNonCanonicalRegion(RPST rpst, Region region1, Region region2) { if (!region1.getExit().equals(region2.getEntry())) { return false; } if (rpst.getChildCount(region2) == 0) { return false; } // basic blocks of merged region Set<BasicBlock> basicBlocks = new HashSet<>(); basicBlocks.addAll(rpst.getBasicBlocks(region1)); basicBlocks.addAll(rpst.getBasicBlocks(region2)); basicBlocks.add(region2.getExit()); if (!basicBlocks.containsAll(cfg.getSuccessorsOf(region1.getExit()))) { return false; } if (!basicBlocks.containsAll(cfg.getPredecessorsOf(region1.getExit()))) { return false; } return true; }
@Override public void process(Node externs, Node root) { this.root = root; astPositionCounter = 0; astPosition = Maps.newHashMap(); nodePriorities = Maps.newHashMap(); cfg = new AstControlFlowGraph(computeFallThrough(root), nodePriorities); NodeTraversal.traverse(compiler, root, this); astPosition.put(null, ++astPositionCounter); // the implicit return is last. // Now, generate the priority of nodes by doing a depth-first // search on the CFG. priorityCounter = 0; DiGraphNode<Node, Branch> entry = cfg.getEntry(); prioritizeFromEntryNode(entry); if (shouldTraverseFunctions) { // If we're traversing inner functions, we need to rank the // priority of them too. for (DiGraphNode<Node, Branch> candidate : cfg.getDirectedGraphNodes()) { Node value = candidate.getValue(); if (value != null && value.getType() == Token.FUNCTION) { Preconditions.checkState(!nodePriorities.containsKey(candidate) || candidate == entry); prioritizeFromEntryNode(candidate); } } } // At this point, all reachable nodes have been given a priority, but // unreachable nodes have not been given a priority. Put them last. // Presumably, it doesn't really matter what priority they get, since // this shouldn't happen in real code. for (DiGraphNode<Node, Branch> candidate : cfg.getDirectedGraphNodes()) { if (!nodePriorities.containsKey(candidate)) { nodePriorities.put(candidate, ++priorityCounter); } } // Again, the implicit return node is always last. nodePriorities.put(cfg.getImplicitReturn(), ++priorityCounter); }
/** * Assert that there exists no control flow edge of the given type * from some node with the first token to the return node. */ private static void assertNoReturnEdge(ControlFlowGraph<Node> cfg, int startToken) { List<DiGraphEdge<Node, Branch>> edges = getAllEdges(cfg); for (DiGraphEdge<Node, Branch> edge : edges) { Node source = edge.getSource().getValue(); DiGraphNode<Node, Branch> dest = edge.getDestination(); if (source.getType() == startToken) { assertFalse("Token " + startToken + " should not have an out going" + " edge to the implicit return", cfg.isImplicitReturn(dest)); return; } } }
private void discoverEntrypoints() { ENTRYPOINTS = new HashSet<ControlFlowGraph.Block>(); // discover edges that have incoming call edges Iterator<ControlFlowGraph.Edge> edges = cfg.getEdgeIterator(); while (edges.hasNext()) { ControlFlowGraph.Edge edge = edges.next(); if ("CALL".equals(edge.getType())) { if (edge.getTarget() == null) { addIndirectEntrypoints(edge, cfg); } else ENTRYPOINTS.add(edge.getTarget()); } } }
private void checkExits() { Debug.debugMessage(getClass(), "Enforcing single exit out of CFG", 3); ArrayList<Vertex> noSuccs = new ArrayList<Vertex>(); for (Vertex v : cfg) { if (v.numOfSuccessors() == 0) { Debug.debugMessage(getClass(), v.getVertexID() + " is currently an exit vertex", 4); noSuccs.add(v); } } if (noSuccs.size() > MainProgramGenerator.Globals.getNumberOfReturns()) { int newVertexID = cfg.getNextVertexID(); cfg.addBasicBlock(newVertexID); Debug.debugMessage(getClass(), "Adding basic block " + newVertexID, 4); while (!noSuccs.isEmpty()) { Vertex v = noSuccs.remove(noSuccs.size() - 1); Debug.debugMessage(getClass(), "...and connecting it from " + v.getVertexID(), 4); cfg.addEdge(v.getVertexID(), newVertexID, BranchType.TAKEN); } } }
/** * Assert that there exists a control flow edge of the given type * from some node with the first token to the return node. */ private static void assertReturnEdge(ControlFlowGraph<Node> cfg, int startToken) { List<DiGraphEdge<Node, Branch>> edges = getAllEdges(cfg); for (DiGraphEdge<Node, Branch> edge : edges) { Node source = edge.getSource().getValue(); DiGraphNode<Node, Branch> dest = edge.getDestination(); if (source.getType() == startToken && cfg.isImplicitReturn(dest)) { return; } } fail("No return edge found"); }
private FlowState<LiveVariablesAnalysis.LiveVariableLattice> getFlowStateAtX( Node node, ControlFlowGraph<Node> cfg) { if (node.getType() == Token.LABEL) { if (node.getFirstChild().getString().equals("X")) { return cfg.getNode(node.getLastChild()).getAnnotation(); } } for (Node c = node.getFirstChild(); c != null; c = c.getNext()) { FlowState<LiveVariablesAnalysis.LiveVariableLattice> state = getFlowStateAtX(c, cfg); if (state != null) { return state; } } return null; }
@Override @SuppressWarnings({"AccessingNonPublicFieldOfAnotherObject"}) public boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return false; if (getClass() != obj.getClass()) return false; SuperGraphNode other = (SuperGraphNode) obj; if (cfg == null) { if (other.cfg != null) return false; } else if (!cfg.equals(other.cfg)) return false; if (context == null) { if (other.context != null) return false; } else if (!context.equals(other.context)) return false; return true; }
private void connectBranches(int noOfComponents, int unusedNodes) { if (noOfComponents > 1) { int destinationToRemove = random.nextInt(2); for (int i = 0; i < disconnectedBranches.size() - 3; i = i + 2) { if (random.nextBoolean()) { int sourceID = disconnectedBranches.get(i); int destinationRemovedID; if (destinationToRemove == 0) { destinationRemovedID = cfg.getVertex(sourceID).getNthSuccessor(destinationToRemove).getVertexID(); } else { destinationRemovedID = disconnectedBranches.get(i + 1); } Debug.debugMessage( getClass(), "Removing edge " + sourceID + "=>" + destinationRemovedID, 4); cfg.removeEdge(sourceID, destinationRemovedID); int newDestinationID = disconnectedBranches.get(i + 2); Debug.debugMessage(getClass(), "Adding edge " + sourceID + "=>" + newDestinationID, 4); cfg.addEdge(sourceID, newDestinationID, BranchType.TAKEN); sourceID = disconnectedBranches.get(i + 3); Debug.debugMessage( getClass(), "Adding edge " + sourceID + "=>" + destinationRemovedID, 4); cfg.addEdge(sourceID, destinationRemovedID, BranchType.TAKEN); } else { Debug.debugMessage( getClass(), "Adding edge " + disconnectedBranches.get(i + 1) + "=>" + disconnectedBranches.get(i + 2), 4); cfg.addEdge( disconnectedBranches.get(i + 1), disconnectedBranches.get(i + 2), BranchType.TAKEN); } } } if (unusedNodes > 0) { addNonBranchComponents(unusedNodes); Debug.debugMessage( getClass(), "Adding edge " + disconnectedBranches.get(disconnectedBranches.size() - 1) + "=>" + disconnectedVertices.get(0), 4); cfg.addEdge( disconnectedBranches.get(disconnectedBranches.size() - 1), disconnectedVertices.get(0), BranchType.TAKEN); } }
public LoopsData(final StructuredGraph graph) { cfg = Debug.scope( "ControlFlowGraph", new Callable<ControlFlowGraph>() { @Override public ControlFlowGraph call() throws Exception { return ControlFlowGraph.compute(graph, true, true, true, true); } }); for (Loop lirLoop : cfg.getLoops()) { LoopEx ex = new LoopEx(lirLoop, this); lirLoopToEx.put(lirLoop, ex); loopBeginToEx.put(ex.loopBegin(), ex); } }
private void buildIndividualBlocks(int noOfComponents) { for (int i = 0; i < noOfComponents; ++i) { int branchID = cfg.getNextVertexID(); Debug.debugMessage(getClass(), "Adding basic block " + branchID, 4); cfg.addBasicBlock(branchID); int ifBranchID = cfg.getNextVertexID(); Debug.debugMessage(getClass(), "Adding basic block " + ifBranchID, 4); cfg.addBasicBlock(ifBranchID); int mergeID = cfg.getNextVertexID(); Debug.debugMessage(getClass(), "Adding basic block " + mergeID, 4); cfg.addBasicBlock(mergeID); Debug.debugMessage(getClass(), "Adding edge " + branchID + "=>" + ifBranchID, 4); cfg.addEdge(branchID, ifBranchID, BranchType.TAKEN); Debug.debugMessage(getClass(), "Adding edge " + ifBranchID + "=>" + mergeID, 4); cfg.addEdge(ifBranchID, mergeID, BranchType.TAKEN); Debug.debugMessage(getClass(), "Adding edge " + branchID + "=>" + mergeID, 4); cfg.addEdge(branchID, mergeID, BranchType.TAKEN); disconnectedBranches.add(branchID); disconnectedBranches.add(mergeID); } }
void buildIndividualLoops(int loops) { for (int i = 0; i < loops; ++i) { int headerID = cfg.getNextVertexID(); Debug.debugMessage(getClass(), "Adding basic block " + headerID, 4); cfg.addBasicBlock(headerID); verticesInLoopBody.put(headerID, new ArrayList<Integer>()); int tailID = cfg.getNextVertexID(); Debug.debugMessage(getClass(), "Adding basic block " + tailID, 4); cfg.addBasicBlock(tailID); verticesInLoopBody.get(headerID).add(tailID); if (remainingVertices > 1) { int loopBody = random.nextInt(remainingVertices / 2 + 1) + 1; remainingVertices -= loopBody; decideLoopBody(loopBody, headerID); Debug.debugMessage( getClass(), "Adding edge " + headerID + "=>" + disconnectedBranches.get(0), 4); cfg.addEdge(headerID, disconnectedBranches.get(0), BranchType.TAKEN); Debug.debugMessage( getClass(), "Adding edge " + disconnectedBranches.get(disconnectedBranches.size() - 1) + "=>" + tailID, 4); cfg.addEdge( disconnectedBranches.get(disconnectedBranches.size() - 1), tailID, BranchType.TAKEN); } else { Debug.debugMessage(getClass(), "Adding edge " + headerID + "=>" + tailID, 4); cfg.addEdge(headerID, tailID, BranchType.TAKEN); } Debug.debugMessage(getClass(), "Adding edge " + tailID + "=>" + headerID, 4); cfg.addEdge(tailID, headerID, BranchType.TAKEN); disconnectedLoopsArray.add(headerID); disconnectedLoops.addVertex(headerID); } }
/** Given an entry node, find all the nodes reachable from that node and prioritize them. */ private void prioritizeFromEntryNode(DiGraphNode<Node, Branch> entry) { PriorityQueue<DiGraphNode<Node, Branch>> worklist = new PriorityQueue<DiGraphNode<Node, Branch>>(10, priorityComparator); worklist.add(entry); while (!worklist.isEmpty()) { DiGraphNode<Node, Branch> current = worklist.remove(); if (nodePriorities.containsKey(current)) { continue; } nodePriorities.put(current, ++priorityCounter); List<DiGraphNode<Node, Branch>> successors = cfg.getDirectedSuccNodes(current); for (DiGraphNode<Node, Branch> candidate : successors) { worklist.add(candidate); } } }
/** Determines if the subtree might throw an exception. */ private static boolean mayThrowException(Node n) { switch (n.getType()) { case Token.CALL: case Token.GETPROP: case Token.GETELEM: case Token.THROW: case Token.NEW: case Token.ASSIGN: case Token.INC: case Token.DEC: case Token.INSTANCEOF: return true; case Token.FUNCTION: return false; } for (Node c = n.getFirstChild(); c != null; c = c.getNext()) { if (!ControlFlowGraph.isEnteringNewCfgNode(c) && mayThrowException(c)) { return true; } } return false; }
private HashMap<ControlFlowGraph.Block, Collection<ControlFlowGraph.Block>> buildProcedureBlockLists() { // maps procedure entry to list blocks in the procedure HashMap<ControlFlowGraph.Block, Collection<ControlFlowGraph.Block>> procMap = new HashMap<ControlFlowGraph.Block, Collection<ControlFlowGraph.Block>>(); // create the initial map of entry points to empty lists for (ControlFlowGraph.Block entry : ENTRYPOINTS) { procMap.put(entry, new LinkedList<ControlFlowGraph.Block>()); } // add each block to the list of its respective procedure Iterator<ControlFlowGraph.Block> block_iter = cfg.getBlockIterator(); while (block_iter.hasNext()) { ControlFlowGraph.Block block = block_iter.next(); Object mark = ENTRYMAP.get(block); if (mark == null || !(mark instanceof ControlFlowGraph.Block)) continue; ControlFlowGraph.Block entry = (ControlFlowGraph.Block) mark; procMap.get(entry).add(block); } return procMap; }