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); } } }
// 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 (var i = 0; i < blocks.Length; i++) { var block = blocks[i]; if (block.numSuccessors < 2) { continue; } for (var j = 0; j < block.numSuccessors; j++) { var target = block.getSuccessor(j); if (target.numPredecessors < 2) { continue; } // Create a new block inheriting from the predecessor. var split = new LBlock(block.pc); var ins = new LGoto(target); LInstruction[] instructions = { ins }; split.setInstructions(instructions); block.replaceSuccessor(j, split); target.replacePredecessor(block, split); split.addPredecessor(block); } } }
public static void ComputeDominators(LBlock[] blocks) { BitArray[] doms = new BitArray[blocks.Length]; for (int i = 0; i < doms.Length; i++) { doms[i] = new BitArray(doms.Length); } doms[0].Set(0, true); for (int i = 1; i < blocks.Length; i++) { for (int j = 0; j < blocks.Length; j++) { doms[i].SetAll(true); } } // Compute dominators. bool changed; do { changed = false; for (int i = 1; i < blocks.Length; i++) { LBlock block = blocks[i]; for (int j = 0; j < block.numPredecessors; j++) { LBlock pred = block.getPredecessor(j); BitArray u = new BitArray(doms[i]); doms[block.id].And(doms[pred.id]); doms[block.id].Set(block.id, true); if (!CompareBitArrays(doms[block.id], u)) { changed = true; } } } }while (changed); // Turn the bit vectors into lists. for (int i = 0; i < blocks.Length; i++) { LBlock block = blocks[i]; List <LBlock> list = new List <LBlock>(); for (int j = 0; j < blocks.Length; j++) { if (doms[block.id][j]) { list.Add(blocks[j]); } } block.setDominators(list.ToArray()); } }
public override void replaceSuccessor(int i, LBlock block) { if (i == 0) { defaultCase_ = block; } if (cases_.Count >= i && i > 0) { cases_[i - 1].target = block; } }
private void transitionBlocks(LBlock next) { //Debug.Assert(pending_.Count == 0 || block_ != null); if (block_ != null) { //Debug.Assert(pending_[pending_.Count - 1].isControl()); //Debug.Assert(block_.pc >= lir_.entry_pc && block_.pc < lir_.exit_pc); block_.setInstructions(pending_.ToArray()); pending_.Clear(); } block_ = next; }
private static void MarkLoop(LBlock backedge) { var worklist = new LoopBodyWorklist(backedge); worklist.scan(backedge); while (!worklist.empty) { var block = worklist.pop(); worklist.scan(block); block.setInLoop(backedge.loop); } }
public void replacePredecessor(LBlock from, LBlock split) { //Debug.Assert(predecessors_.Contains(from)); for (int i = 0; i < numPredecessors; i++) { if (getPredecessor(i) == from) { predecessors_[i] = split; break; } } //Debug.Assert(!predecessors_.Contains(from)); }
public static void DumpGraph(LBlock[] blocks, TextWriter tw) { for (int i = 0; i < blocks.Length; i++) { tw.WriteLine("Block " + i + ": (" + blocks[i].pc + ")"); for (int j = 0; j < blocks[i].instructions.Length; j++) { tw.Write(" "); blocks[i].instructions[j].print(tw); tw.Write("\n"); } tw.WriteLine("\n"); } }
// Return a reverse post-order listing of reachable blocks. public static LBlock[] Order(LBlock entry) { // Postorder traversal without recursion. var pending = new Stack <LBlock>(); var successors = new Stack <int>(); var done = new Stack <LBlock>(); var current = entry; var 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; } var blocks = new List <LBlock>(); while (done.Count > 0) { current = done.Pop(); current.unmark(); current.setId(blocks.Count); blocks.Add(current); } return(blocks.ToArray()); }
private static LBlock SkipContainedLoop(LBlock block, LBlock header) { while (block.loop != null && block.loop == block) { if (block.loop != null) { block = block.loop; } if (block == header) { break; } block = block.getLoopPredecessor(); } return(block); }
// 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 static bool StrictlyDominatesADominator(LBlock from, LBlock dom) { for (var i = 0; i < from.dominators.Length; i++) { var other = from.dominators[i]; if (other == from || other == dom) { continue; } if (other.dominators.Contains(dom)) { return(true); } } return(false); }
// The immediate dominator or idom of a node n is the unique node that // strictly dominates n but does not strictly dominate any other node // that strictly dominates n. private static void ComputeImmediateDominator(LBlock block) { for (var i = 0; i < block.dominators.Length; i++) { var dom = block.dominators[i]; if (dom == block) { continue; } if (!StrictlyDominatesADominator(block, dom)) { block.setImmediateDominator(dom); return; } } //Debug.Assert(false, "not reached"); }
public static void ComputeDominatorTree(LBlock[] blocks) { List <LBlock>[] idominated = new List <LBlock> [blocks.Length]; for (int i = 0; i < blocks.Length; i++) { idominated[i] = new List <LBlock>(); } for (int i = 1; i < blocks.Length; i++) { LBlock block = blocks[i]; idominated[block.idom.id].Add(block); } for (int i = 0; i < blocks.Length; i++) { blocks[i].setImmediateDominated(idominated[i].ToArray()); } }
private LGraph buildBlocks() { 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); 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); //Debug.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); }
// 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 void scan(LBlock block) { for (var i = 0; i < block.numPredecessors; i++) { var pred = block.getPredecessor(i); // Has this block already been scanned? if (pred.loop == backedge_.loop) { continue; } pred = SkipContainedLoop(pred, backedge_.loop); // If this assert hits, there is probably a |break| keyword. //Debug.Assert(pred.loop == null || pred.loop == backedge_.loop); if (pred.loop != null) { continue; } stack_.Push(pred); } }
public void setDominators(LBlock[] dominators) { dominators_ = dominators; }
public virtual void replaceSuccessor(int i, LBlock block) { successors_[i] = block; }
public SwitchCase(int value, LBlock target) { value_ = value; this.target = target; }
public void setInLoop(LBlock loop) { loop_ = loop; }
public void traverse(NodeBlock block) { for (int i = 0; i < block.lir.numPredecessors; i++) { NodeBlock pred = blocks_[block.lir.getPredecessor(i).id]; // Don't bother with backedges yet. if (pred.lir.id >= block.lir.id) { continue; } block.inherit(graph_, pred); } foreach (LInstruction uins in block.lir.instructions) { // Attempt to find static declarations. This is really // expensive - we could cheapen it by creating per-method // lists of statics. { int i = -1; do { Variable var = file_.lookupDeclarations(uins.pc, ref i, Scope.Static); if (var == null) { break; } block.add(new DDeclareStatic(var)); } while (true); } switch (uins.op) { case Opcode.DebugBreak: break; case Opcode.Stack: { LStack ins = (LStack)uins; if (ins.amount < 0) { for (int i = 0; i < -ins.amount / 4; i++) { DDeclareLocal local = new DDeclareLocal(ins.pc, null); block.stack.push(local); block.add(local); } } else { for (int i = 0; i < ins.amount / 4; i++) { block.stack.pop(); } } break; } case Opcode.Fill: { LFill ins = (LFill)uins; DNode node = block.stack.alt; DDeclareLocal local = (DDeclareLocal)node; //Debug.Assert(block.stack.pri.type == NodeType.Constant); for (int i = 0; i < ins.amount; i += 4) { block.stack.set(local.offset + i, block.stack.pri); } break; } case Opcode.Constant: { LConstant ins = (LConstant)uins; DConstant v = new DConstant(ins.val, ins.pc); block.stack.set(ins.reg, v); block.add(v); break; } case Opcode.PushConstant: { LPushConstant ins = (LPushConstant)uins; DConstant v = new DConstant(ins.val); DDeclareLocal local = new DDeclareLocal(ins.pc, v); block.stack.push(local); block.add(v); block.add(local); break; } case Opcode.PushReg: { LPushReg ins = (LPushReg)uins; DDeclareLocal local = new DDeclareLocal(ins.pc, block.stack.reg(ins.reg)); block.stack.push(local); block.add(local); break; } case Opcode.Pop: { LPop ins = (LPop)uins; DNode node = block.stack.popAsTemp(); block.stack.set(ins.reg, node); break; } case Opcode.StackAddress: { LStackAddress ins = (LStackAddress)uins; DDeclareLocal local = block.stack.getName(ins.offset); block.stack.set(ins.reg, local); break; } case Opcode.PushStackAddress: { LPushStackAddress ins = (LPushStackAddress)uins; DLocalRef lref = new DLocalRef(block.stack.getName(ins.offset)); DDeclareLocal local = new DDeclareLocal(ins.pc, lref); block.stack.push(local); block.add(lref); block.add(local); break; } case Opcode.Goto: { LGoto ins = (LGoto)uins; DJump node = new DJump(blocks_[ins.target.id]); block.add(node); break; } case Opcode.Jump: { LJump ins = (LJump)uins; DJump node = new DJump(blocks_[ins.target.id]); block.add(node); break; } case Opcode.JumpCondition: { LJumpCondition ins = (LJumpCondition)uins; NodeBlock lhtarget = blocks_[ins.trueTarget.id]; NodeBlock rhtarget = blocks_[ins.falseTarget.id]; DNode cmp = block.stack.pri; SPOpcode jmp = ins.spop; if (jmp != SPOpcode.jzer && jmp != SPOpcode.jnz) { SPOpcode newop; switch (ins.spop) { case SPOpcode.jeq: newop = SPOpcode.neq; jmp = SPOpcode.jzer; break; case SPOpcode.jneq: newop = SPOpcode.eq; jmp = SPOpcode.jzer; break; case SPOpcode.jsgeq: newop = SPOpcode.sless; jmp = SPOpcode.jzer; break; case SPOpcode.jsgrtr: newop = SPOpcode.sleq; jmp = SPOpcode.jzer; break; case SPOpcode.jsleq: newop = SPOpcode.sgrtr; jmp = SPOpcode.jzer; break; case SPOpcode.jsless: newop = SPOpcode.sgeq; jmp = SPOpcode.jzer; break; default: //Debug.Assert(false); return; } cmp = new DBinary(newop, block.stack.pri, block.stack.alt); block.add(cmp); } DJumpCondition jcc = new DJumpCondition(jmp, cmp, lhtarget, rhtarget); block.add(jcc); break; } case Opcode.LoadLocal: { LLoadLocal ins = (LLoadLocal)uins; DLoad load = new DLoad(block.stack.getName(ins.offset)); block.stack.set(ins.reg, load); block.add(load); break; } case Opcode.LoadLocalRef: { LLoadLocalRef ins = (LLoadLocalRef)uins; DLoad load = new DLoad(block.stack.getName(ins.offset)); load = new DLoad(load); block.stack.set(ins.reg, load); block.add(load); break; } case Opcode.StoreLocal: { LStoreLocal ins = (LStoreLocal)uins; DStore store = new DStore(block.stack.getName(ins.offset), block.stack.reg(ins.reg)); block.add(store); break; } case Opcode.StoreLocalRef: { LStoreLocalRef ins = (LStoreLocalRef)uins; DLoad load = new DLoad(block.stack.getName(ins.offset)); DStore store = new DStore(load, block.stack.reg(ins.reg)); block.add(store); break; } case Opcode.SysReq: { LSysReq sysreq = (LSysReq)uins; DConstant ins = (DConstant)block.stack.popValue(); List <DNode> arguments = new List <DNode>(); for (int i = 0; i < ins.value; i++) { arguments.Add(block.stack.popName()); } DSysReq call = new DSysReq(sysreq.native, arguments.ToArray()); block.stack.set(Register.Pri, call); block.add(call); break; } case Opcode.AddConstant: { LAddConstant ins = (LAddConstant)uins; DConstant val = new DConstant(ins.amount); DBinary node = new DBinary(SPOpcode.add, block.stack.pri, val); block.stack.set(Register.Pri, node); block.add(val); block.add(node); break; } case Opcode.MulConstant: { LMulConstant ins = (LMulConstant)uins; DConstant val = new DConstant(ins.amount); DBinary node = new DBinary(SPOpcode.smul, block.stack.pri, val); block.stack.set(Register.Pri, node); block.add(val); block.add(node); break; } case Opcode.Bounds: { LBounds ins = (LBounds)uins; DBoundsCheck node = new DBoundsCheck(block.stack.pri); block.add(node); break; } case Opcode.IndexAddress: { LIndexAddress ins = (LIndexAddress)uins; DArrayRef node = new DArrayRef(block.stack.alt, block.stack.pri, ins.shift); block.stack.set(Register.Pri, node); block.add(node); break; } case Opcode.Move: { LMove ins = (LMove)uins; if (ins.reg == Register.Pri) { block.stack.set(Register.Pri, block.stack.alt); } else { block.stack.set(Register.Alt, block.stack.pri); } break; } case Opcode.Store: { LStore ins = (LStore)uins; DStore store = new DStore(block.stack.alt, block.stack.pri); block.add(store); break; } case Opcode.Load: { LLoad ins = (LLoad)uins; DLoad load = new DLoad(block.stack.pri); block.stack.set(Register.Pri, load); block.add(load); break; } case Opcode.Swap: { LSwap ins = (LSwap)uins; DNode lhs = block.stack.popAsTemp(); DNode rhs = block.stack.reg(ins.reg); DDeclareLocal local = new DDeclareLocal(ins.pc, rhs); block.stack.set(ins.reg, lhs); block.stack.push(local); block.add(local); break; } case Opcode.IncI: { DIncDec inc = new DIncDec(block.stack.pri, 1); block.add(inc); break; } case Opcode.DecI: { DIncDec dec = new DIncDec(block.stack.pri, -1); block.add(dec); break; } case Opcode.IncLocal: { LIncLocal ins = (LIncLocal)uins; DDeclareLocal local = block.stack.getName(ins.offset); DIncDec inc = new DIncDec(local, 1); block.add(inc); break; } case Opcode.IncReg: { LIncReg ins = (LIncReg)uins; DIncDec dec = new DIncDec(block.stack.reg(ins.reg), 1); block.add(dec); break; } case Opcode.DecLocal: { LDecLocal ins = (LDecLocal)uins; DDeclareLocal local = block.stack.getName(ins.offset); DIncDec dec = new DIncDec(local, -1); block.add(dec); break; } case Opcode.DecReg: { LDecReg ins = (LDecReg)uins; DIncDec dec = new DIncDec(block.stack.reg(ins.reg), -1); block.add(dec); break; } case Opcode.Return: { DReturn node = new DReturn(block.stack.pri); block.add(node); break; } case Opcode.PushLocal: { LPushLocal ins = (LPushLocal)uins; DLoad load = new DLoad(block.stack.getName(ins.offset)); DDeclareLocal local = new DDeclareLocal(ins.pc, load); block.stack.push(local); block.add(load); block.add(local); break; } case Opcode.Exchange: { DNode node = block.stack.alt; block.stack.set(Register.Alt, block.stack.pri); block.stack.set(Register.Pri, node); break; } case Opcode.Unary: { LUnary ins = (LUnary)uins; DUnary unary = new DUnary(ins.spop, block.stack.reg(ins.reg)); block.stack.set(Register.Pri, unary); block.add(unary); break; } case Opcode.Binary: { LBinary ins = (LBinary)uins; DBinary binary = new DBinary(ins.spop, block.stack.reg(ins.lhs), block.stack.reg(ins.rhs)); block.stack.set(Register.Pri, binary); block.add(binary); break; } case Opcode.PushGlobal: { LPushGlobal ins = (LPushGlobal)uins; Variable global = file_.lookupGlobal(ins.address); if (global == null) { global = file_.lookupVariable(ins.pc, ins.address, Scope.Static); } DGlobal dglobal = new DGlobal(global); DNode node = new DLoad(dglobal); DDeclareLocal local = new DDeclareLocal(ins.pc, node); block.stack.push(local); block.add(dglobal); block.add(node); block.add(local); break; } case Opcode.LoadGlobal: { LLoadGlobal ins = (LLoadGlobal)uins; Variable global = file_.lookupGlobal(ins.address); if (global == null) { global = file_.lookupVariable(ins.pc, ins.address, Scope.Static); } DNode dglobal = new DGlobal(global); DNode node = new DLoad(dglobal); block.stack.set(ins.reg, node); block.add(dglobal); block.add(node); break; } case Opcode.StoreGlobal: { LStoreGlobal ins = (LStoreGlobal)uins; Variable global = file_.lookupGlobal(ins.address); if (global == null) { global = file_.lookupVariable(ins.pc, ins.address, Scope.Static); } DGlobal node = new DGlobal(global); DStore store = new DStore(node, block.stack.reg(ins.reg)); block.add(node); block.add(store); break; } case Opcode.Call: { LCall ins = (LCall)uins; Function f = file_.lookupFunction((uint)ins.address); DConstant args = (DConstant)block.stack.popValue(); List <DNode> arguments = new List <DNode>(); for (int i = 0; i < args.value; i++) { arguments.Add(block.stack.popName()); } DCall call = new DCall(f, arguments.ToArray()); block.stack.set(Register.Pri, call); block.add(call); break; } case Opcode.EqualConstant: { LEqualConstant ins = (LEqualConstant)uins; DConstant c = new DConstant(ins.value); DBinary node = new DBinary(SPOpcode.eq, block.stack.reg(ins.reg), c); block.stack.set(Register.Pri, node); block.add(c); block.add(node); break; } case Opcode.LoadIndex: { LLoadIndex ins = (LLoadIndex)uins; DArrayRef aref = new DArrayRef(block.stack.alt, block.stack.pri, ins.shift); DLoad load = new DLoad(aref); block.stack.set(Register.Pri, load); block.add(aref); block.add(load); break; } case Opcode.ZeroGlobal: { LZeroGlobal ins = (LZeroGlobal)uins; Variable global = file_.lookupGlobal(ins.address); DNode dglobal = new DGlobal(global); DConstant rhs = new DConstant(0); DStore lhs = new DStore(dglobal, rhs); block.add(dglobal); block.add(rhs); block.add(lhs); break; } case Opcode.IncGlobal: { LIncGlobal ins = (LIncGlobal)uins; Variable global = file_.lookupGlobal(ins.address); DNode dglobal = new DGlobal(global); DLoad load = new DLoad(dglobal); DConstant val = new DConstant(1); DBinary add = new DBinary(SPOpcode.add, load, val); DStore store = new DStore(dglobal, add); block.add(load); block.add(val); block.add(add); block.add(store); break; } case Opcode.StoreGlobalConstant: { LStoreGlobalConstant lstore = (LStoreGlobalConstant)uins; Variable var = file_.lookupGlobal(lstore.address); DConstant val = new DConstant(lstore.value); DGlobal global = new DGlobal(var); DStore store = new DStore(global, val); block.add(val); block.add(global); block.add(store); break; } case Opcode.StoreLocalConstant: { LStoreLocalConstant lstore = (LStoreLocalConstant)uins; DDeclareLocal var = block.stack.getName(lstore.address); DConstant val = new DConstant(lstore.value); DStore store = new DStore(var, val); block.add(val); block.add(store); break; } case Opcode.ZeroLocal: { LZeroLocal lstore = (LZeroLocal)uins; DDeclareLocal var = block.stack.getName(lstore.address); DConstant val = new DConstant(0); DStore store = new DStore(var, val); block.add(val); block.add(store); break; } case Opcode.Heap: { LHeap ins = (LHeap)uins; DHeap heap = new DHeap(ins.amount); block.add(heap); block.stack.set(Register.Alt, heap); break; } case Opcode.MemCopy: { LMemCopy ins = (LMemCopy)uins; DMemCopy copy = new DMemCopy(block.stack.alt, block.stack.pri, ins.bytes); block.add(copy); break; } case Opcode.Switch: { LSwitch ins = (LSwitch)uins; DSwitch switch_ = new DSwitch(block.stack.pri, ins); block.add(switch_); break; } default: throw new Exception("unhandled opcode"); } } for (int i = 0; i < block.lir.idominated.Length; i++) { LBlock lir = block.lir.idominated[i]; traverse(blocks_[lir.id]); } }
public void scan(LBlock block) { for (int i = 0; i < block.numPredecessors; i++) { LBlock pred = block.getPredecessor(i); // Has this block already been scanned? if (pred.loop == backedge_.loop) continue; pred = SkipContainedLoop(pred, backedge_.loop); // If this assert hits, there is probably a |break| keyword. //Debug.Assert(pred.loop == null || pred.loop == backedge_.loop); if (pred.loop != null) continue; stack_.Push(pred); } }
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); } }
public LJump(LBlock target, uint target_offs) : base(target_offs, target) { }
public LJumpCondition(SPOpcode op, LBlock true_target, LBlock false_target, uint target_offs) : base(target_offs, true_target, false_target) { op_ = op; }
public LGoto(LBlock target) : base(target) { }
public override void replaceSuccessor(int i, LBlock block) { if (i == 0) defaultCase_ = block; if (cases_.Count >= i && i > 0) { cases_[i - 1].target = block; } }
public LSwitch(LBlock defaultCase, List<SwitchCase> cases) { defaultCase_ = defaultCase; cases_ = cases; }
public LSwitch(LBlock defaultCase, List <SwitchCase> cases) { defaultCase_ = defaultCase; cases_ = cases; }
public LoopBodyWorklist(LBlock backedge) { backedge_ = backedge; }
private static LBlock SkipContainedLoop(LBlock block, LBlock header) { while (block.loop != null && block.loop == block) { if (block.loop != null) block = block.loop; if (block == header) break; block = block.getLoopPredecessor(); } return block; }
public void setImmediateDominator(LBlock idom) { idom_ = idom; }
public void replaceSuccessor(int pos, LBlock split) { last.replaceSuccessor(pos, split); }
public BlockBuilder(LIR lir) { lir_ = lir; block_ = lir_.entry; }
public void addPredecessor(LBlock pred) { //Debug.Assert(!predecessors_.Contains(pred)); predecessors_.Add(pred); }
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); } }
private static bool StrictlyDominatesADominator(LBlock from, LBlock dom) { for (int i = 0; i < from.dominators.Length; i++) { LBlock other = from.dominators[i]; if (other == from || other == dom) continue; if (other.dominators.Contains(dom)) return true; } return false; }
public void setLoopHeader(LBlock backedge) { backedge_ = backedge; loop_ = this; }
public static void ComputeDominators(LBlock[] blocks) { BitArray[] doms = new BitArray[blocks.Length]; for (int i = 0; i < doms.Length; i++) doms[i] = new BitArray(doms.Length); doms[0].Set(0, true); for (int i = 1; i < blocks.Length; i++) { for (int j = 0; j < blocks.Length; j++) doms[i].SetAll(true); } // Compute dominators. bool changed; do { changed = false; for (int i = 1; i < blocks.Length; i++) { LBlock block = blocks[i]; for (int j = 0; j < block.numPredecessors; j++) { LBlock pred = block.getPredecessor(j); BitArray u = new BitArray(doms[i]); doms[block.id].And(doms[pred.id]); doms[block.id].Set(block.id, true); if (!CompareBitArrays(doms[block.id], u)) changed = true; } } } while (changed); // Turn the bit vectors into lists. for (int i = 0; i < blocks.Length; i++) { LBlock block = blocks[i]; List<LBlock> list = new List<LBlock>(); for (int j = 0; j < blocks.Length; j++) { if (doms[block.id][j]) list.Add(blocks[j]); } block.setDominators(list.ToArray()); } }
public void setImmediateDominated(LBlock[] idominated) { idominated_ = idominated; }
public static void ComputeImmediateDominators(LBlock[] blocks) { blocks[0].setImmediateDominator(blocks[0]); for (int i = 1; i < blocks.Length; i++) ComputeImmediateDominator(blocks[i]); }
public static void ComputeDominatorTree(LBlock[] blocks) { List<LBlock>[] idominated = new List<LBlock>[blocks.Length]; for (int i = 0; i < blocks.Length; i++) idominated[i] = new List<LBlock>(); for (int i = 1; i < blocks.Length; i++) { LBlock block = blocks[i]; idominated[block.idom.id].Add(block); } for (int i = 0; i < blocks.Length; i++) blocks[i].setImmediateDominated(idominated[i].ToArray()); }
private static void MarkLoop(LBlock backedge) { var worklist = new LoopBodyWorklist(backedge); worklist.scan(backedge); while (!worklist.empty) { LBlock block = worklist.pop(); worklist.scan(block); block.setInLoop(backedge.loop); } }
public LBlock parse() { for (int i = 0; i < lir_.instructions.Count; i++) { LInstruction ins = lir_.instructions[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) { //Debug.Assert(!pending_[pending_.Count - 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 Opcode.Return: { // A return terminates the current block. transitionBlocks(null); break; } case Opcode.Jump: { LJump jump = (LJump)ins; jump.target.addPredecessor(block_); transitionBlocks(null); break; } case Opcode.JumpCondition: { LJumpCondition jcc = (LJumpCondition)ins; jcc.trueTarget.addPredecessor(block_); jcc.falseTarget.addPredecessor(block_); // The next iteration will pick the false target up. //Debug.Assert(lir_.instructions[i + 1].pc == jcc.falseTarget.pc); transitionBlocks(null); break; } case Opcode.Switch: { LSwitch switch_ = (LSwitch)ins; for (int j = 0; j < switch_.numSuccessors; j++) { switch_.getSuccessor(j).addPredecessor(block_); } transitionBlocks(null); break; } } } return(lir_.entry); }
// The immediate dominator or idom of a node n is the unique node that // strictly dominates n but does not strictly dominate any other node // that strictly dominates n. private static void ComputeImmediateDominator(LBlock block) { for (int i = 0; i < block.dominators.Length; i++) { LBlock dom = block.dominators[i]; if (dom == block) continue; if (!StrictlyDominatesADominator(block, dom)) { block.setImmediateDominator(dom); return; } } //Debug.Assert(false, "not reached"); }
private LInstruction readInstruction(SPOpcode op) { switch (op) { case SPOpcode.load_pri: case SPOpcode.load_alt: { Register reg = (op == SPOpcode.load_pri) ? Register.Pri : Register.Alt; return(new LLoadGlobal(readInt32(), reg)); } case SPOpcode.load_s_pri: case SPOpcode.load_s_alt: { Register reg = (op == SPOpcode.load_s_pri) ? Register.Pri : Register.Alt; return(new LLoadLocal(trackStack(readInt32()), reg)); } case SPOpcode.lref_s_pri: case SPOpcode.lref_s_alt: { Register reg = (op == SPOpcode.lref_s_pri) ? Register.Pri : Register.Alt; return(new LLoadLocalRef(trackStack(readInt32()), reg)); } case SPOpcode.stor_s_pri: case SPOpcode.stor_s_alt: { Register reg = (op == SPOpcode.stor_s_pri) ? Register.Pri : Register.Alt; return(new LStoreLocal(reg, trackStack(readInt32()))); } case SPOpcode.sref_s_pri: case SPOpcode.sref_s_alt: { Register reg = (op == SPOpcode.sref_s_pri) ? Register.Pri : Register.Alt; return(new LStoreLocalRef(reg, trackStack(readInt32()))); } case SPOpcode.load_i: return(new LLoad(4)); case SPOpcode.lodb_i: return(new LLoad(readInt32())); case SPOpcode.const_pri: case SPOpcode.const_alt: { Register reg = (op == SPOpcode.const_pri) ? Register.Pri : Register.Alt; return(new LConstant(readInt32(), reg)); } case SPOpcode.addr_pri: case SPOpcode.addr_alt: { Register reg = (op == SPOpcode.addr_pri) ? Register.Pri : Register.Alt; return(new LStackAddress(trackStack(readInt32()), reg)); } case SPOpcode.stor_pri: case SPOpcode.stor_alt: { Register reg = (op == SPOpcode.stor_pri) ? Register.Pri : Register.Alt; return(new LStoreGlobal(readInt32(), reg)); } case SPOpcode.stor_i: return(new LStore(4)); case SPOpcode.strb_i: return(new LStore(readInt32())); case SPOpcode.lidx: return(new LLoadIndex(4)); case SPOpcode.lidx_b: return(new LLoadIndex(readInt32())); case SPOpcode.idxaddr: return(new LIndexAddress(2)); case SPOpcode.idxaddr_b: return(new LIndexAddress(readInt32())); case SPOpcode.move_pri: case SPOpcode.move_alt: { Register reg = (op == SPOpcode.move_pri) ? Register.Pri : Register.Alt; return(new LMove(reg)); } case SPOpcode.xchg: return(new LExchange()); case SPOpcode.push_pri: case SPOpcode.push_alt: { Register reg = (op == SPOpcode.push_pri) ? Register.Pri : Register.Alt; return(new LPushReg(reg)); } case SPOpcode.push_c: return(new LPushConstant(readInt32())); case SPOpcode.push: return(new LPushGlobal(readInt32())); case SPOpcode.push_s: return(new LPushLocal(trackStack(readInt32()))); case SPOpcode.pop_pri: case SPOpcode.pop_alt: { Register reg = (op == SPOpcode.pop_pri) ? Register.Pri : Register.Alt; return(new LPop(reg)); } case SPOpcode.stack: return(new LStack(readInt32())); case SPOpcode.retn: return(new LReturn()); case SPOpcode.call: return(new LCall(readInt32())); case SPOpcode.jump: { uint offset = readUInt32(); return(new LJump(prepareJumpTarget(offset), offset)); } case SPOpcode.jeq: case SPOpcode.jneq: case SPOpcode.jnz: case SPOpcode.jzer: case SPOpcode.jsgeq: case SPOpcode.jsless: case SPOpcode.jsgrtr: case SPOpcode.jsleq: { uint offset = readUInt32(); if (offset == pc_) { return(new LJump(prepareJumpTarget(offset), offset)); } return(new LJumpCondition(op, prepareJumpTarget(offset), prepareJumpTarget(pc_), offset)); } case SPOpcode.sdiv_alt: case SPOpcode.sub_alt: return(new LBinary(op, Register.Alt, Register.Pri)); case SPOpcode.add: case SPOpcode.and: case SPOpcode.or: case SPOpcode.smul: case SPOpcode.shr: case SPOpcode.shl: case SPOpcode.sub: case SPOpcode.sshr: case SPOpcode.xor: return(new LBinary(op, Register.Pri, Register.Alt)); case SPOpcode.not: case SPOpcode.invert: return(new LUnary(op, Register.Pri)); case SPOpcode.add_c: return(new LAddConstant(readInt32())); case SPOpcode.smul_c: return(new LMulConstant(readInt32())); case SPOpcode.zero_pri: case SPOpcode.zero_alt: { Register reg = (op == SPOpcode.zero_pri) ? Register.Pri : Register.Alt; return(new LConstant(0, reg)); } case SPOpcode.zero_s: return(new LZeroLocal(trackStack(readInt32()))); case SPOpcode.zero: return(new LZeroGlobal(readInt32())); case SPOpcode.eq: case SPOpcode.neq: case SPOpcode.sleq: case SPOpcode.sgeq: case SPOpcode.sgrtr: case SPOpcode.sless: return(new LBinary(op, Register.Pri, Register.Alt)); case SPOpcode.eq_c_pri: case SPOpcode.eq_c_alt: { Register reg = (op == SPOpcode.eq_c_pri) ? Register.Pri : Register.Alt; return(new LEqualConstant(reg, readInt32())); } case SPOpcode.inc: return(new LIncGlobal(readInt32())); case SPOpcode.inc_s: return(new LIncLocal(trackStack(readInt32()))); case SPOpcode.dec_s: return(new LDecLocal(trackStack(readInt32()))); case SPOpcode.inc_i: return(new LIncI()); case SPOpcode.inc_pri: case SPOpcode.inc_alt: { Register reg = (op == SPOpcode.inc_pri) ? Register.Pri : Register.Alt; return(new LIncReg(reg)); } case SPOpcode.dec_pri: case SPOpcode.dec_alt: { Register reg = (op == SPOpcode.dec_pri) ? Register.Pri : Register.Alt; return(new LDecReg(reg)); } case SPOpcode.dec_i: return(new LDecI()); case SPOpcode.fill: return(new LFill(readInt32())); case SPOpcode.bounds: return(new LBounds(readInt32())); case SPOpcode.swap_pri: case SPOpcode.swap_alt: { Register reg = (op == SPOpcode.swap_pri) ? Register.Pri : Register.Alt; return(new LSwap(reg)); } case SPOpcode.push_adr: return(new LPushStackAddress(trackStack(readInt32()))); case SPOpcode.sysreq_n: { int index = readInt32(); add(new LPushConstant(readInt32())); return(new LSysReq(file_.natives[index])); } case SPOpcode.dbreak: return(new LDebugBreak()); case SPOpcode.endproc: return(null); case SPOpcode.push2_s: { add(new LPushLocal(trackStack(readInt32()))); return(new LPushLocal(trackStack(readInt32()))); } case SPOpcode.push2_adr: { add(new LPushStackAddress(trackStack(readInt32()))); return(new LPushStackAddress(trackStack(readInt32()))); } case SPOpcode.push2_c: { add(new LPushConstant(readInt32())); return(new LPushConstant(readInt32())); } case SPOpcode.push2: { add(new LPushGlobal(readInt32())); return(new LPushGlobal(readInt32())); } case SPOpcode.push3_s: { add(new LPushLocal(trackStack(readInt32()))); add(new LPushLocal(trackStack(readInt32()))); return(new LPushLocal(trackStack(readInt32()))); } case SPOpcode.push3_adr: { add(new LPushStackAddress(trackStack(readInt32()))); add(new LPushStackAddress(trackStack(readInt32()))); return(new LPushStackAddress(trackStack(readInt32()))); } case SPOpcode.push3_c: { add(new LPushConstant(readInt32())); add(new LPushConstant(readInt32())); return(new LPushConstant(readInt32())); } case SPOpcode.push3: { add(new LPushGlobal(readInt32())); add(new LPushGlobal(readInt32())); return(new LPushGlobal(readInt32())); } case SPOpcode.push4_s: { add(new LPushLocal(trackStack(readInt32()))); add(new LPushLocal(trackStack(readInt32()))); add(new LPushLocal(trackStack(readInt32()))); return(new LPushLocal(trackStack(readInt32()))); } case SPOpcode.push4_adr: { add(new LPushStackAddress(trackStack(readInt32()))); add(new LPushStackAddress(trackStack(readInt32()))); add(new LPushStackAddress(trackStack(readInt32()))); return(new LPushStackAddress(trackStack(readInt32()))); } case SPOpcode.push4_c: { add(new LPushConstant(readInt32())); add(new LPushConstant(readInt32())); add(new LPushConstant(readInt32())); return(new LPushConstant(readInt32())); } case SPOpcode.push4: { add(new LPushGlobal(readInt32())); add(new LPushGlobal(readInt32())); add(new LPushGlobal(readInt32())); return(new LPushGlobal(readInt32())); } case SPOpcode.push5_s: { add(new LPushLocal(trackStack(readInt32()))); add(new LPushLocal(trackStack(readInt32()))); add(new LPushLocal(trackStack(readInt32()))); add(new LPushLocal(trackStack(readInt32()))); return(new LPushLocal(trackStack(readInt32()))); } case SPOpcode.push5_c: { add(new LPushConstant(readInt32())); add(new LPushConstant(readInt32())); add(new LPushConstant(readInt32())); add(new LPushConstant(readInt32())); return(new LPushConstant(readInt32())); } case SPOpcode.push5_adr: { add(new LPushStackAddress(trackStack(readInt32()))); add(new LPushStackAddress(trackStack(readInt32()))); add(new LPushStackAddress(trackStack(readInt32()))); add(new LPushStackAddress(trackStack(readInt32()))); return(new LPushStackAddress(trackStack(readInt32()))); } case SPOpcode.push5: { add(new LPushGlobal(readInt32())); add(new LPushGlobal(readInt32())); add(new LPushGlobal(readInt32())); add(new LPushGlobal(readInt32())); return(new LPushGlobal(readInt32())); } case SPOpcode.load_both: { add(new LLoadLocal(readInt32(), Register.Pri)); return(new LLoadLocal(readInt32(), Register.Alt)); } case SPOpcode.load_s_both: { add(new LLoadLocal(trackStack(readInt32()), Register.Pri)); return(new LLoadLocal(trackStack(readInt32()), Register.Alt)); } case SPOpcode.const_: { return(new LStoreGlobalConstant(readInt32(), readInt32())); } case SPOpcode.const_s: { return(new LStoreLocalConstant(trackStack(readInt32()), readInt32())); } case SPOpcode.heap: { return(new LHeap(readInt32())); } case SPOpcode.movs: { return(new LMemCopy(readInt32())); } case SPOpcode.switch_: { uint table = readUInt32(); uint savePc = pc_; pc_ = table; SPOpcode casetbl = (SPOpcode)readUInt32(); //Debug.Assert(casetbl == SPOpcode.casetbl); int ncases = readInt32(); uint defaultCase = readUInt32(); var cases = new List <SwitchCase>(); for (int i = 0; i < ncases; i++) { int value = readInt32(); uint pc = readUInt32(); LBlock target = prepareJumpTarget(pc); cases.Add(new SwitchCase(value, target)); } pc_ = savePc; return(new LSwitch(prepareJumpTarget(defaultCase), cases)); } case SPOpcode.casetbl: { int ncases = readInt32(); pc_ += (uint)ncases * 8 + 4; return(new LDebugBreak()); } default: { throw new OpCodeNotKnownException("Unrecognized opcode " + op); } } }