// Split critical edges in the graph. A critical edge is an edge which // is neither its successor's only predecessor, nor its predecessor's // only successor. Critical edges must be split to prevent copy-insertion // and code motion from affecting other edges. It is probably not strictly // needed here. public static void SplitCriticalEdges(LBlock[] blocks) { for (int i = 0; i < blocks.Length; i++) { LBlock block = blocks[i]; if (block.numSuccessors < 2) { continue; } for (int j = 0; j < block.numSuccessors; j++) { LBlock target = block.getSuccessor(j); if (target.numPredecessors < 2) { continue; } // Create a new block inheriting from the predecessor. LBlock split = new LBlock(block.pc); LGoto ins = new LGoto(target); LInstruction[] instructions = { ins }; split.setInstructions(instructions); block.replaceSuccessor(j, split); target.replacePredecessor(block, split); split.addPredecessor(block); } } }
public static void FindLoops(LBlock[] blocks) { // Mark backedges and headers. for (int i = 1; i < blocks.Length; i++) { LBlock block = blocks[i]; for (int j = 0; j < block.numSuccessors; j++) { LBlock successor = block.getSuccessor(j); if (successor.id < block.id) { successor.setLoopHeader(block); block.setInLoop(successor); break; } } } for (int i = 0; i < blocks.Length; i++) { LBlock block = blocks[i]; if (block.backedge != null) { MarkLoop(block.backedge); } } }
// Return a reverse post-order listing of reachable blocks. public static LBlock[] Order(LBlock entry) { // Postorder traversal without recursion. Stack <LBlock> pending = new Stack <LBlock>(); Stack <int> successors = new Stack <int>(); Stack <LBlock> done = new Stack <LBlock>(); LBlock current = entry; int nextSuccessor = 0; for (; ;) { if (!current.marked) { current.mark(); if (nextSuccessor < current.numSuccessors) { pending.Push(current); successors.Push(nextSuccessor); current = current.getSuccessor(nextSuccessor); nextSuccessor = 0; continue; } done.Push(current); } if (pending.Count == 0) { break; } current = pending.Pop(); current.unmark(); nextSuccessor = successors.Pop() + 1; } List <LBlock> blocks = new List <LBlock>(); while (done.Count > 0) { current = done.Pop(); current.unmark(); current.setId(blocks.Count); blocks.Add(current); } return(blocks.ToArray()); }
private ControlType findLoopJoinAndBody(NodeBlock header, NodeBlock effectiveHeader, out NodeBlock join, out NodeBlock body, out NodeBlock cond) { //Debug.Assert(effectiveHeader.lir.numSuccessors == 2); LBlock succ1 = effectiveHeader.lir.getSuccessor(0); LBlock succ2 = effectiveHeader.lir.getSuccessor(1); if (succ1.loop != header.lir || succ2.loop != header.lir) { //Debug.Assert(succ1.loop == header.lir || succ2.loop == header.lir); if (succ1.loop != header.lir) { join = graph_[succ1.id]; body = graph_[succ2.id]; } else { join = graph_[succ2.id]; body = graph_[succ1.id]; } cond = header; // If this is a self-loop, it is more correct to decompose it // to a do-while loop. This may not be source accurate in the // case of something like |while (x);| but it catches many more // source-accurate cases. if (header == effectiveHeader && BlockAnalysis.GetEmptyTarget(body) == header) { body = null; return(ControlType.DoWhileLoop); } return(ControlType.WhileLoop); } else { // Neither successor of the header exits the loop, so this is // probably a do-while loop. For now, assume it's simple. //Debug.Assert(header == effectiveHeader); LBlock backedge = header.lir.backedge; if (BlockAnalysis.GetEmptyTarget(graph_[backedge.id]) == header) { // Skip an empty block sitting in between the backedge and // the condition. //Debug.Assert(backedge.numPredecessors == 1); backedge = backedge.getPredecessor(0); } //Debug.Assert(backedge.numSuccessors == 2); succ1 = backedge.getSuccessor(0); succ2 = backedge.getSuccessor(1); body = header; cond = graph_[backedge.id]; if (succ1.loop != header.lir) { join = graph_[succ1.id]; } else { //Debug.Assert(succ2.loop != header.lir); join = graph_[succ2.id]; } return(ControlType.DoWhileLoop); } }
// From Engineering a Compiler (Cooper, Torczon) public static bool IsReducible(LBlock[] blocks) { // Copy the graph into a temporary mutable structure. RBlock[] rblocks = new RBlock[blocks.Length]; for (int i = 0; i < blocks.Length; i++) { rblocks[i] = new RBlock(i); } for (int i = 0; i < blocks.Length; i++) { LBlock block = blocks[i]; RBlock rblock = rblocks[i]; for (int j = 0; j < block.numPredecessors; j++) { rblock.predecessors.Add(rblocks[block.getPredecessor(j).id]); } for (int j = 0; j < block.numSuccessors; j++) { rblock.successors.Add(rblocks[block.getSuccessor(j).id]); } } // Okay, start reducing. LinkedList <RBlock> queue = new LinkedList <RBlock>(rblocks); for (;;) { List <RBlock> deleteQueue = new List <RBlock>(); foreach (RBlock rblock in queue) { // Transformation T1, remove self-edges. if (rblock.predecessors.Contains(rblock)) { rblock.predecessors.Remove(rblock); } if (rblock.successors.Contains(rblock)) { rblock.successors.Remove(rblock); } // Transformation T2, remove blocks with one predecessor, // reroute successors' predecessors. if (rblock.predecessors.Count == 1) { // Mark this node for removal since C# sucks and can't delete during iteration. deleteQueue.Add(rblock); RBlock predecessor = rblock.predecessors[0]; // Delete the edge from pred -> me predecessor.successors.Remove(rblock); for (int i = 0; i < rblock.successors.Count; i++) { RBlock successor = rblock.successors[i]; //Debug.Assert(successor.predecessors.Contains(rblock)); successor.predecessors.Remove(rblock); if (!successor.predecessors.Contains(predecessor)) { successor.predecessors.Add(predecessor); } if (!predecessor.successors.Contains(successor)) { predecessor.successors.Add(successor); } } } } if (deleteQueue.Count == 0) { break; } foreach (RBlock rblock in deleteQueue) { queue.Remove(rblock); } } // If the graph reduced to one node, it was reducible. return(queue.Count == 1); }