public WhileLoop(ControlType type, NodeBlock source, ControlBlock body, ControlBlock join) : base(source) { body_ = body; join_ = join; type_ = type; }
public void inherit(LGraph graph, NodeBlock other) { if (other == null) { stack_ = new AbstractStack(graph.nargs); for (int i = 0; i < graph.nargs; i++) { DDeclareLocal local = new DDeclareLocal(lir_.pc, null); local.setOffset((i * 4) + 12); add(local); stack_.init((i * 4) + 12, local); } } else if (stack_ == null) { //Debug.Assert(other.stack_ != null); stack_ = new AbstractStack(other.stack_); } else { // Right now we only create phis for pri/alt. joinRegs(Register.Pri, other.stack_.pri); joinRegs(Register.Alt, other.stack_.alt); } }
private void writeSignature(NodeBlock entry) { Function f = file_.lookupFunction(entry.lir.pc); Debug.Assert(f != null); if (file_.lookupPublic(entry.lir.pc) != null) { out_.Append("public "); } if (f != null) { out_.Append(buildTag(f.returnType) + f.name); } else { out_.Append("function" + f.address); } out_.Append("("); for (int i = 0; i < f.args.Length; i++) { out_.Append(buildArgDeclaration(f.args[i])); if (i != f.args.Length - 1) { out_.Append(", "); } } out_.Append(")" + Environment.NewLine); }
private static bool HasSharedTarget(NodeBlock pred, DJumpCondition jcc) { NodeBlock trueTarget = BlockAnalysis.EffectiveTarget(jcc.trueTarget); if (trueTarget.lir.numPredecessors == 1) { return(false); } if (pred.lir.idominated.Length > 3) { return(true); } // Hack... sniff out the case we care about, the true target // probably having a conditional. if (trueTarget.lir.instructions.Length == 2 && trueTarget.lir.instructions[0].op == Opcode.Constant && trueTarget.lir.instructions[1].op == Opcode.Jump) { return(true); } // Because of edge splitting, there will always be at least 4 // dominators for the immediate dominator of a shared block. return(false); }
public SwitchBlock(NodeBlock source, ControlBlock defaultCase, List <Case> cases, ControlBlock join) : base(source) { defaultCase_ = defaultCase; cases_ = cases; join_ = join; }
public static void CoalesceLoadsAndDeclarations(NodeGraph graph) { for (int i = 0; i < graph.numBlocks; i++) { NodeBlock block = graph[i]; for (NodeList.iterator iter = block.nodes.begin(); iter.more();) { DNode node = iter.node; if (node.type == NodeType.DeclareLocal) { // Peephole next = store(this, expr) DDeclareLocal local = (DDeclareLocal)node; if (node.next.type == NodeType.Store) { DStore store = (DStore)node.next; if (store.getOperand(0) == local) { local.replaceOperand(0, store.getOperand(1)); store.removeFromUseChains(); iter.next(); block.nodes.remove(iter); continue; } } } iter.next(); } } }
private void writeStatements(NodeBlock block) { for (NodeList.iterator iter = block.nodes.begin(); iter.more(); iter.next()) { writeStatement(iter.node); } }
public IfBlock(NodeBlock source, bool invert, ControlBlock trueArm, ControlBlock falseArm, ControlBlock join) : base(source) { trueArm_ = trueArm; falseArm_ = falseArm; join_ = join; invert_ = invert; }
private ControlBlock traverseJoin(NodeBlock block) { if (isJoin(block)) { return(null); } return(traverseBlock(block)); }
public NodeBuilder(SourcePawnFile file, LGraph graph) { file_ = file; graph_ = graph; blocks_ = new NodeBlock[graph_.blocks.Length]; for (int i = 0; i < graph_.blocks.Length; i++) blocks_[i] = new NodeBlock(graph_.blocks[i]); }
public DJumpCondition(SPOpcode spop, DNode node, NodeBlock lht, NodeBlock rht) : base(node) { // //Debug.Assert(getOperand(0) != null); spop_ = spop; trueTarget_ = lht; falseTarget_ = rht; }
public static NodeBlock GetEmptyTarget(NodeBlock block) { if (block.nodes.last != block.nodes.first) { return(null); } return(GetSingleTarget(block)); }
public IfBlock(NodeBlock source, LogicChain chain, ControlBlock trueArm, ControlBlock falseArm, ControlBlock join) : base(source) { trueArm_ = trueArm; falseArm_ = falseArm; join_ = join; invert_ = invert; logic_ = logic; }
public void propagate() { for (int i = 0; i < graph_.numBlocks; i++) { block_ = graph_[i]; for (NodeList.iterator iter = block_.nodes.begin(); iter.more(); iter.next()) iter.node.accept(this); } }
private IfBlock traverseIf(NodeBlock block, DJumpCondition jcc) { if (HasSharedTarget(block, jcc)) { return(traverseComplexIf(block, jcc)); } NodeBlock trueTarget = (jcc.spop == SPOpcode.jzer) ? jcc.falseTarget : jcc.trueTarget; NodeBlock falseTarget = (jcc.spop == SPOpcode.jzer) ? jcc.trueTarget : jcc.falseTarget; NodeBlock joinTarget = findJoinOfSimpleIf(block, jcc); // If there is no join block (both arms terminate control flow), // eliminate one arm and use the other as a join point. if (joinTarget == null) { joinTarget = falseTarget; } // If the false target is equivalent to the join point, eliminate // it. if (BlockAnalysis.EffectiveTarget(falseTarget) == joinTarget) { falseTarget = null; } // If the true target is equivalent to the join point, promote // the false target to the true target and undo the inversion. bool invert = false; if (BlockAnalysis.EffectiveTarget(trueTarget) == joinTarget) { trueTarget = falseTarget; falseTarget = null; invert ^= true; } // If there is always a true target and a join target. pushScope(joinTarget); ControlBlock trueArm = traverseBlock(trueTarget); popScope(); ControlBlock joinArm = traverseJoin(joinTarget); if (falseTarget == null) { return(new IfBlock(block, invert, trueArm, joinArm)); } pushScope(joinTarget); ControlBlock falseArm = traverseBlock(falseTarget); popScope(); return(new IfBlock(block, invert, trueArm, falseArm, joinArm)); }
public static NodeBlock GetSingleTarget(NodeBlock block) { if (block.nodes.last.type != NodeType.Jump) { return(null); } DJump jump = (DJump)block.nodes.last; return(jump.target); }
public NodeBuilder(SourcePawnFile file, LGraph graph) { file_ = file; graph_ = graph; blocks_ = new NodeBlock[graph_.blocks.Length]; for (int i = 0; i < graph_.blocks.Length; i++) { blocks_[i] = new NodeBlock(graph_.blocks[i]); } }
public void propagate() { for (var i = graph_.numBlocks - 1; i >= 0; i--) { block_ = graph_[i]; for (var iter = block_.nodes.rbegin(); iter.more(); iter.next()) { iter.node.accept(this); } } }
private bool isJoin(NodeBlock block) { for (int i = joinStack_.Count - 1; i >= 0; i--) { if (joinStack_.ElementAt(i) == block) { return(true); } } return(false); }
private void rewriteBlock(NodeBlock block) { current_ = block; iterator_ = block.nodes.begin(); while (iterator_.more()) { // Iterate before accepting so we can replace the node. iterator_.node.accept(this); iterator_.next(); } }
public void propagate() { for (int i = graph_.numBlocks - 1; i >= 0; i--) { block_ = graph_[i]; for (NodeList.reverse_iterator iter = block_.nodes.rbegin(); iter.more(); iter.next()) { iter.node.accept(this); } } }
public void propagate() { for (int i = 0; i < graph_.numBlocks; i++) { block_ = graph_[i]; for (NodeList.iterator iter = block_.nodes.begin(); iter.more(); iter.next()) { iter.node.accept(this); } } }
private static void AnalyzeHeapUsage(NodeBlock block) { for (NodeList.reverse_iterator riter = block.nodes.rbegin(); riter.more(); riter.next()) { if (riter.node.type == NodeType.Heap) { if (AnalyzeHeapNode(block, (DHeap)riter.node)) { block.nodes.remove(riter); } } } }
private ControlBlock traverseBlock(NodeBlock block) { if (block != null) { if (block.lir != null) { if (block.lir.backedge != null) { return(traverseLoop(block)); } } } return(traverseBlockNoLoop(block)); }
public static NodeBlock EffectiveTarget(NodeBlock block) { NodeBlock target = block; for (;;) { block = GetEmptyTarget(block); if (block == null) { return(target); } target = block; } }
private static NodeBlock FindJoinBlock(NodeGraph graph, NodeBlock block) { if (block.nodes.last.type == NodeType.JumpCondition && block.lir.idominated.Length == 3) { return(graph[block.lir.idominated[2].id]); } if (block.lir.idom == null) { return(null); } if (block.lir.idom == block.lir) { return(null); } return(FindJoinBlock(graph, graph[block.lir.idom.id])); }
private static NodeBlock InLoop(NodeGraph graph, NodeBlock block) { while (true) { if (block.lir.backedge != null) { return(block); } NodeBlock next = graph[block.lir.idom.id]; if (block == next) { return(null); } block = next; } }
private ControlBlock traverseLoop(NodeBlock block) { DNode last = block.nodes.last; NodeBlock effectiveHeader = block; LogicChain chain = null; if (last.type == NodeType.JumpCondition) { DJumpCondition jcc = (DJumpCondition)last; if (HasSharedTarget(block, jcc)) { chain = buildLogicChain(block, null, out effectiveHeader); } } last = effectiveHeader.nodes.last; //Debug.Assert(last.type == NodeType.JumpCondition); if (last.type == NodeType.JumpCondition) { // Assert that the backedge is a straight jump. //Debug.Assert(BlockAnalysis.GetSingleTarget(graph_[block.lir.backedge.id]) == block); NodeBlock join, body, cond; ControlType type = findLoopJoinAndBody(block, effectiveHeader, out join, out body, out cond); ControlBlock joinArm = traverseBlock(join); ControlBlock bodyArm = null; if (body != null) { pushScope(block); pushScope(cond); bodyArm = traverseBlockNoLoop(body); popScope(); popScope(); } if (chain != null) { return(new WhileLoop(type, chain, bodyArm, joinArm)); } return(new WhileLoop(type, cond, bodyArm, joinArm)); } return(null); }
public static void RemoveGuards(NodeGraph graph) { for (int i = graph.numBlocks - 1; i >= 0; i--) { NodeBlock block = graph[i]; for (NodeList.reverse_iterator iter = block.nodes.rbegin(); iter.more();) { if (iter.node.guard) { //Debug.Assert(iter.node.idempotent); iter.node.removeFromUseChains(); block.nodes.remove(iter); continue; } iter.next(); } } }
private NodeBlock findJoinOfSimpleIf(NodeBlock block, DJumpCondition jcc) { //Debug.Assert(block.nodes.last == jcc); //Debug.Assert(block.lir.idominated[0] == jcc.falseTarget.lir || block.lir.idominated[0] == jcc.trueTarget.lir); //Debug.Assert(block.lir.idominated[1] == jcc.falseTarget.lir || block.lir.idominated[1] == jcc.trueTarget.lir); if (block.lir.idominated.Length == 2) { if (jcc.trueTarget != BlockAnalysis.EffectiveTarget(jcc.trueTarget)) { return(jcc.trueTarget); } if (jcc.falseTarget != BlockAnalysis.EffectiveTarget(jcc.falseTarget)) { return(jcc.falseTarget); } return(null); } return(graph_[block.lir.idominated[2].id]); }
private ControlBlock traverseSwitch(NodeBlock block, DSwitch switch_) { var dominators = new List <LBlock>(); for (int i = 0; i < block.lir.idominated.Length; i++) { dominators.Add(block.lir.idominated[i]); } dominators.Remove(switch_.defaultCase); for (int i = 0; i < switch_.numCases; i++) { dominators.Remove(switch_.getCase(i).target); } NodeBlock join = null; if (dominators.Count > 0) { //Debug.Assert(dominators.Count == 1); join = graph_[dominators[dominators.Count - 1].id]; } ControlBlock joinArm = null; if (join != null) { joinArm = traverseBlock(join); } pushScope(join); var cases = new List <SwitchBlock.Case>(); ControlBlock defaultArm = traverseBlock(graph_[switch_.defaultCase.id]); for (int i = 0; i < switch_.numCases; i++) { ControlBlock arm = traverseBlock(graph_[switch_.getCase(i).target.id]); cases.Add(new SwitchBlock.Case(switch_.getCase(i).value, arm)); } popScope(); return(new SwitchBlock(block, defaultArm, cases, joinArm)); }
public override void visit(DPhi phi) { // Convert a phi into a move on each incoming edge. Declare the // temporary name in the dominator. NodeBlock idom = graph_[phi.block.lir.idom.id]; DTempName name = new DTempName(graph_.tempName()); idom.prepend(name); for (int i = 0; i < phi.numOperands; i++) { DNode input = phi.getOperand(i); DStore store = new DStore(name, input); NodeBlock pred = graph_[phi.block.lir.getPredecessor(i).id]; pred.prepend(store); } phi.replaceAllUsesWith(name); }
private static void RemoveDeadCodeInBlock(NodeBlock block) { for (NodeList.reverse_iterator iter = block.nodes.rbegin(); iter.more(); ) { if (iter.node.type == NodeType.DeclareLocal) { DDeclareLocal decl = (DDeclareLocal)iter.node; if (decl.var == null && (decl.uses.Count == 0 || (decl.uses.Count == 1 && decl.value != null))) { // This was probably just a stack temporary. if (decl.uses.Count == 1) { DUse use = decl.uses.First.Value; use.node.replaceOperand(use.index, decl.value); } iter.node.removeFromUseChains(); block.nodes.remove(iter); continue; } } if ((iter.node.type == NodeType.Store && iter.node.getOperand(0).type == NodeType.Heap && iter.node.getOperand(0).uses.Count == 1)) { iter.node.removeFromUseChains(); block.nodes.remove(iter); } if (!iter.node.idempotent || iter.node.guard || iter.node.uses.Count > 0) { iter.next(); continue; } iter.node.removeFromUseChains(); block.nodes.remove(iter); } }
private NodeBlock findJoinOfSimpleIf(NodeBlock block, DJumpCondition jcc) { //Debug.Assert(block.nodes.last == jcc); //Debug.Assert(block.lir.idominated[0] == jcc.falseTarget.lir || block.lir.idominated[0] == jcc.trueTarget.lir); //Debug.Assert(block.lir.idominated[1] == jcc.falseTarget.lir || block.lir.idominated[1] == jcc.trueTarget.lir); if (block.lir.idominated.Length == 2) { if (jcc.trueTarget != BlockAnalysis.EffectiveTarget(jcc.trueTarget)) return jcc.trueTarget; if (jcc.falseTarget != BlockAnalysis.EffectiveTarget(jcc.falseTarget)) return jcc.falseTarget; return null; } return graph_[block.lir.idominated[2].id]; }
public static NodeBlock EffectiveTarget(NodeBlock block) { NodeBlock target = block; for (;;) { block = GetEmptyTarget(block); if (block == null) return target; target = block; } }
private ControlBlock traverseBlockNoLoop(NodeBlock block) { if (block == null) { return null; } DNode last = block.nodes.last; if (last.type == NodeType.JumpCondition) return traverseIf(block, (DJumpCondition)last); if (last.type == NodeType.Jump) { DJump jump = (DJump)last; NodeBlock target = BlockAnalysis.EffectiveTarget(jump.target); ControlBlock next = null; if (!isJoin(target)) next = traverseBlock(target); return new StatementBlock(block, next); } if (last.type == NodeType.Switch) return traverseSwitch(block, (DSwitch)last); //Debug.Assert(last.type == NodeType.Return); return new ReturnBlock(block); }
public void propagate() { for (int i = graph_.numBlocks - 1; i >= 0; i--) { block_ = graph_[i]; for (NodeList.reverse_iterator iter = block_.nodes.rbegin(); iter.more(); iter.next()) iter.node.accept(this); } }
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 ControlBlock traverseSwitch(NodeBlock block, DSwitch switch_) { var dominators = new List<LBlock>(); for (int i = 0; i < block.lir.idominated.Length; i++) dominators.Add(block.lir.idominated[i]); dominators.Remove(switch_.defaultCase); for (int i = 0; i < switch_.numCases; i++) dominators.Remove(switch_.getCase(i).target); NodeBlock join = null; if (dominators.Count > 0) { //Debug.Assert(dominators.Count == 1); join = graph_[dominators[dominators.Count - 1].id]; } ControlBlock joinArm = null; if (join != null) joinArm = traverseBlock(join); pushScope(join); var cases = new List<SwitchBlock.Case>(); ControlBlock defaultArm = traverseBlock(graph_[switch_.defaultCase.id]); for (int i = 0; i < switch_.numCases; i++) { ControlBlock arm = traverseBlock(graph_[switch_.getCase(i).target.id]); cases.Add(new SwitchBlock.Case(switch_.getCase(i).value, arm)); } popScope(); return new SwitchBlock(block, defaultArm, cases, joinArm); }
public ReturnBlock(NodeBlock source) : base(source) { }
public StatementBlock(NodeBlock source, ControlBlock next) : base(source) { next_ = next; }
public ControlBlock(NodeBlock source) { source_ = source; }
public SwitchBlock(NodeBlock source, ControlBlock defaultCase, List<Case> cases, ControlBlock join) : base(source) { defaultCase_ = defaultCase; cases_ = cases; join_ = join; }
private IfBlock traverseComplexIf(NodeBlock block, DJumpCondition jcc) { // Degenerate case: using || or &&, or any combination thereof, // will generate a chain of n+1 conditional blocks, where each // |n| has a target to a shared "success" block, setting a // phony variable. We decompose this giant mess into the intended // sequence of expressions. NodeBlock join; LogicChain chain = buildLogicChain(block, null, out join); DJumpCondition finalJcc = (DJumpCondition)join.nodes.last; //Debug.Assert(finalJcc.spop == SPOpcode.jzer); // The final conditional should have the normal dominator // properties: 2 or 3 idoms, depending on the number of arms. // Because of critical edge splitting, we may have 3 idoms // even if there are only actually two arms. NodeBlock joinBlock = findJoinOfSimpleIf(join, finalJcc); // If an AND chain reaches its end, the result is 1. jzer tests // for zero, so this is effectively testing (!success). // If an OR expression reaches its end, the result is 0. jzer // tests for zero, so this is effectively testing if (failure). // // In both cases, the true target represents a failure, so flip // the targets around. NodeBlock trueBlock = finalJcc.falseTarget; NodeBlock falseBlock = finalJcc.trueTarget; // If there is no join block, both arms terminate control flow, // eliminate one arm and use the other as a join point. if (joinBlock == null) joinBlock = falseBlock; if (join.lir.idominated.Length == 2 || BlockAnalysis.EffectiveTarget(falseBlock) == joinBlock) { if (join.lir.idominated.Length == 3) joinBlock = BlockAnalysis.EffectiveTarget(falseBlock); // One-armed structure. pushScope(joinBlock); ControlBlock trueArm1 = traverseBlock(trueBlock); popScope(); ControlBlock joinArm1 = traverseBlock(joinBlock); return new IfBlock(block, chain, trueArm1, joinArm1); } //Debug.Assert(join.lir.idominated.Length == 3); pushScope(joinBlock); ControlBlock trueArm2 = traverseBlock(trueBlock); ControlBlock falseArm = traverseBlock(falseBlock); popScope(); ControlBlock joinArm2 = traverseBlock(joinBlock); return new IfBlock(block, chain, trueArm2, falseArm, joinArm2); }
private void pushScope(NodeBlock block) { joinStack_.Push(block); }
private IfBlock traverseIf(NodeBlock block, DJumpCondition jcc) { if (HasSharedTarget(block, jcc)) return traverseComplexIf(block, jcc); NodeBlock trueTarget = (jcc.spop == SPOpcode.jzer) ? jcc.falseTarget : jcc.trueTarget; NodeBlock falseTarget = (jcc.spop == SPOpcode.jzer) ? jcc.trueTarget : jcc.falseTarget; NodeBlock joinTarget = findJoinOfSimpleIf(block, jcc); // If there is no join block (both arms terminate control flow), // eliminate one arm and use the other as a join point. if (joinTarget == null) joinTarget = falseTarget; // If the false target is equivalent to the join point, eliminate // it. if (BlockAnalysis.EffectiveTarget(falseTarget) == joinTarget) falseTarget = null; // If the true target is equivalent to the join point, promote // the false target to the true target and undo the inversion. bool invert = false; if (BlockAnalysis.EffectiveTarget(trueTarget) == joinTarget) { trueTarget = falseTarget; falseTarget = null; invert ^= true; } // If there is always a true target and a join target. pushScope(joinTarget); ControlBlock trueArm = traverseBlock(trueTarget); popScope(); ControlBlock joinArm = traverseJoin(joinTarget); if (falseTarget == null) return new IfBlock(block, invert, trueArm, joinArm); pushScope(joinTarget); ControlBlock falseArm = traverseBlock(falseTarget); popScope(); return new IfBlock(block, invert, trueArm, falseArm, joinArm); }
private bool isJoin(NodeBlock block) { for (int i = joinStack_.Count - 1; i >= 0; i--) { if (joinStack_.ElementAt(i) == block) return true; } return false; }
private ControlBlock traverseLoop(NodeBlock block) { DNode last = block.nodes.last; NodeBlock effectiveHeader = block; LogicChain chain = null; if (last.type == NodeType.JumpCondition) { DJumpCondition jcc = (DJumpCondition)last; if (HasSharedTarget(block, jcc)) chain = buildLogicChain(block, null, out effectiveHeader); } last = effectiveHeader.nodes.last; //Debug.Assert(last.type == NodeType.JumpCondition); if (last.type == NodeType.JumpCondition) { // Assert that the backedge is a straight jump. //Debug.Assert(BlockAnalysis.GetSingleTarget(graph_[block.lir.backedge.id]) == block); NodeBlock join, body, cond; ControlType type = findLoopJoinAndBody(block, effectiveHeader, out join, out body, out cond); ControlBlock joinArm = traverseBlock(join); ControlBlock bodyArm = null; if (body != null) { pushScope(block); pushScope(cond); bodyArm = traverseBlockNoLoop(body); popScope(); popScope(); } if (chain != null) return new WhileLoop(type, chain, bodyArm, joinArm); return new WhileLoop(type, cond, bodyArm, joinArm); } return null; }
private static bool HasSharedTarget(NodeBlock pred, DJumpCondition jcc) { NodeBlock trueTarget = BlockAnalysis.EffectiveTarget(jcc.trueTarget); if (trueTarget.lir.numPredecessors == 1) return false; if (pred.lir.idominated.Length > 3) return true; // Hack... sniff out the case we care about, the true target // probably having a conditional. if (trueTarget.lir.instructions.Length == 2 && trueTarget.lir.instructions[0].op == Opcode.Constant && trueTarget.lir.instructions[1].op == Opcode.Jump) { return true; } // Because of edge splitting, there will always be at least 4 // dominators for the immediate dominator of a shared block. return false; }
private ControlBlock traverseJoin(NodeBlock block) { if (isJoin(block)) return null; return traverseBlock(block); }
private void renameBlock(NodeBlock block) { for (NodeList.iterator iter = block.nodes.begin(); iter.more();) { DNode node = iter.node; switch (node.type) { case NodeType.TempName: case NodeType.Jump: case NodeType.JumpCondition: case NodeType.Store: case NodeType.Return: case NodeType.IncDec: case NodeType.DeclareStatic: case NodeType.Switch: { iter.next(); continue; } case NodeType.DeclareLocal: { DDeclareLocal decl = (DDeclareLocal)node; if (decl.var == null) { if (decl.uses.Count <= 1) { // This was probably just a stack temporary. if (decl.uses.Count == 1) { DUse use = decl.uses.First.Value; use.node.replaceOperand(use.index, decl.value); } block.nodes.remove(iter); continue; } DTempName name = new DTempName(graph_.tempName()); node.replaceAllUsesWith(name); name.init(decl.value); block.nodes.replace(iter, name); } iter.next(); continue; } case NodeType.SysReq: case NodeType.Call: { // Calls are statements or expressions, so we can't // remove them if they have no uses. if (node.uses.Count <= 1) { if (node.uses.Count == 1) block.nodes.remove(iter); else iter.next(); continue; } break; } case NodeType.Constant: { // Constants can be deeply copied. block.nodes.remove(iter); continue; } default: { if (node.uses.Count <= 1) { // This node has one or zero uses, so instead of // renaming it, we remove it from the instruction // stream. This way the source printer will deep- // print it instead of using its 'SSA' name. block.nodes.remove(iter); continue; } break; } } // If we've reached here, the expression has more than one use // and we have to wrap it in some kind of name, lest we // duplicate it in the expression tree which may be illegal. DTempName replacement = new DTempName(graph_.tempName()); node.replaceAllUsesWith(replacement); replacement.init(node); block.nodes.replace(iter, replacement); iter.next(); } }
private ControlBlock traverseBlock(NodeBlock block) { if (block != null) { if (block.lir != null) { if (block.lir.backedge != null) { return traverseLoop(block); } } } return traverseBlockNoLoop(block); }
private static void AssertInnerJoinValidity(NodeBlock join, NodeBlock earlyExit) { DJumpCondition jcc = (DJumpCondition)join.nodes.last; //Debug.Assert(BlockAnalysis.EffectiveTarget(jcc.trueTarget) == earlyExit || join == SingleTarget(earlyExit)); }
private static NodeBlock InLoop(NodeGraph graph, NodeBlock block) { while (true) { if (block.lir.backedge != null) return block; NodeBlock next = graph[block.lir.idom.id]; if (block == next) return null; block = next; } }
private LogicChain buildLogicChain(NodeBlock block, NodeBlock earlyExitStop, out NodeBlock join) { DJumpCondition jcc = (DJumpCondition)block.nodes.last; LogicChain chain = new LogicChain(ToLogicOp(jcc)); // Grab the true target, which will be either the "1" or "0" // branch of the AND/OR expression. NodeBlock earlyExit = BlockAnalysis.EffectiveTarget(jcc.trueTarget); NodeBlock exprBlock = block; do { do { DJumpCondition childJcc = (DJumpCondition)exprBlock.nodes.last; if (BlockAnalysis.EffectiveTarget(childJcc.trueTarget) != earlyExit) { // Parse a sub-expression. NodeBlock innerJoin; LogicChain rhs = buildLogicChain(exprBlock, earlyExit, out innerJoin); AssertInnerJoinValidity(innerJoin, earlyExit); chain.append(rhs); exprBlock = innerJoin; childJcc = (DJumpCondition)exprBlock.nodes.last; } else { chain.append(childJcc.getOperand(0)); } exprBlock = childJcc.falseTarget; } while (exprBlock.nodes.last.type == NodeType.JumpCondition); do { // We have reached the end of a sequence - a block containing // a Constant and a Jump to the join point of the sequence. //Debug.Assert(exprBlock.lir.instructions[0].op == Opcode.Constant); // The next block is the join point. NodeBlock condBlock = SingleTarget(exprBlock); var last = condBlock.nodes.last; DJumpCondition condJcc; try { condJcc = (DJumpCondition)last; } catch (Exception e) { throw new LogicChainConversionException(e.Message); } join = condBlock; // If the cond block is the tagret of the early stop, we've // gone a tad too far. This is the case for a simple // expression like (a && b) || c. if (earlyExitStop != null && SingleTarget(earlyExitStop) == condBlock) return chain; // If the true connects back to the early exit stop, we're // done. if (BlockAnalysis.EffectiveTarget(condJcc.trueTarget) == earlyExitStop) return chain; // If the true target does not have a shared target, we're // done parsing the whole logic chain. if (!HasSharedTarget(condBlock, condJcc)) return chain; // Otherwise, there is another link in the chain. This link // joins the existing chain to a new subexpression, which // actually starts hanging off the false branch of this // conditional. earlyExit = BlockAnalysis.EffectiveTarget(condJcc.trueTarget); // Build the right-hand side of the expression. NodeBlock innerJoin; LogicChain rhs = buildLogicChain(condJcc.falseTarget, earlyExit, out innerJoin); AssertInnerJoinValidity(innerJoin, earlyExit); // Build the full expression. LogicChain root = new LogicChain(ToLogicOp(condJcc)); root.append(chain); root.append(rhs); chain = root; // If the inner join's false target is a conditional, the // outer expression may continue. DJumpCondition innerJcc = (DJumpCondition)innerJoin.nodes.last; if (innerJcc.falseTarget.nodes.last.type == NodeType.JumpCondition) { exprBlock = innerJcc.falseTarget; break; } // Finally, the new expression block is always the early exit // block. It's on the "trueTarget" edge of the expression, // whereas incoming into this loop it's on the "falseTarget" // edge, but this does not matter. exprBlock = earlyExit; } while (true); } while (true); }
private static NodeBlock SingleTarget(NodeBlock block) { DJump jump = (DJump)block.nodes.last; return jump.target; }
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]); } }