private void transitionBlocks(LBlock next) { assert (pending_.size() == 0 || block_ != null); if (block_ != null) { assert (pending_.get(pending_.size() - 1).isControl()); assert (block_.pc() >= lir_.entry_pc && block_.pc() < lir_.exit_pc); block_.setInstructions(pending_.toArray(new LInstruction[0])); pending_.clear(); } block_ = next; }
private LGraph buildBlocks() throws Exception { lir_.entry = new LBlock(lir_.entry_pc); BlockBuilder builder = new BlockBuilder(lir_); LBlock entry = builder.parse(); // Get an RPO ordering of the blocks, since we don't have predecessors yet. LBlock[] blocks = BlockAnalysis.Order(entry); // Remove dead references. // Ignore blocks that are unreachable and are always jumped over // e.g. // if(1 != 1) // loop().. for (LBlock block : blocks) { int numPredecessors = block.numPredecessors(); for (int i = 0; i < numPredecessors; i++) { if (!ContainsBlock(blocks, block.getPredecessor(i))) { block.removePredecessor(block.getPredecessor(i)); numPredecessors--; } } } if (!BlockAnalysis.IsReducible(blocks)) throw new Exception("control flow graph is not reducible"); // Split critical edges in the graph (is this even needed?) BlockAnalysis.SplitCriticalEdges(blocks); // Reorder the blocks since we could have introduced new nodes. blocks = BlockAnalysis.Order(entry); assert (BlockAnalysis.IsReducible(blocks)); BlockAnalysis.ComputeDominators(blocks); BlockAnalysis.ComputeImmediateDominators(blocks); BlockAnalysis.ComputeDominatorTree(blocks); BlockAnalysis.FindLoops(blocks); LGraph graph = new LGraph(); graph.blocks = blocks; graph.entry = blocks[0]; if (lir_.argDepth > 0) graph.nargs = ((lir_.argDepth - 12) / 4) + 1; else graph.nargs = 0; return graph; }
public LBlock parse() { for (int i = 0; i < lir_.instructions.size(); i++) { LInstruction ins = lir_.instructions.get(i); if (lir_.isTarget(ins.pc())) { // This instruction is the target of a basic block, so // finish the old one. LBlock next = lir_.blockOfTarget(ins.pc()); // Multiple instructions could be at the same pc, // because of decomposition, so make sure we're not // transitioning to the same block. if (block_ != next) { // Add implicit control flow to make further algorithms easier. if (block_ != null) { assert (!pending_.get(pending_.size() - 1).isControl()); pending_.add(new LGoto(next)); next.addPredecessor(block_); } // Fallthrough to the next block. transitionBlocks(next); } } // If there is no block present, we assume this is dead code. if (block_ == null) continue; pending_.add(ins); switch (ins.op()) { case Return: { // A return terminates the current block. transitionBlocks(null); break; } case Jump: { LJump jump = (LJump) ins; jump.target().addPredecessor(block_); transitionBlocks(null); break; } case JumpCondition: { LJumpCondition jcc = (LJumpCondition) ins; jcc.trueTarget().addPredecessor(block_); jcc.falseTarget().addPredecessor(block_); // The next iteration will pick the false target up. assert (lir_.instructions.get(i + 1).pc() == jcc.falseTarget().pc()); transitionBlocks(null); break; } case Switch: { LSwitch switch_ = (LSwitch) ins; for (int j = 0; j < switch_.numSuccessors(); j++) { switch_.getSuccessor(j).addPredecessor(block_); } transitionBlocks(null); break; } default: break; } } return lir_.entry; }