Exemple #1
0
 public WhileLoop(ControlType type, NodeBlock source, ControlBlock body, ControlBlock join)
     : base(source)
 {
     body_ = body;
     join_ = join;
     type_ = type;
 }
Exemple #2
0
 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);
     }
 }
Exemple #3
0
        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);
        }
Exemple #4
0
        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);
        }
Exemple #5
0
 public SwitchBlock(NodeBlock source, ControlBlock defaultCase, List <Case> cases, ControlBlock join)
     : base(source)
 {
     defaultCase_ = defaultCase;
     cases_       = cases;
     join_        = join;
 }
Exemple #6
0
        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();
                }
            }
        }
Exemple #7
0
 private void writeStatements(NodeBlock block)
 {
     for (NodeList.iterator iter = block.nodes.begin(); iter.more(); iter.next())
     {
         writeStatement(iter.node);
     }
 }
Exemple #8
0
 public IfBlock(NodeBlock source, bool invert, ControlBlock trueArm, ControlBlock falseArm, ControlBlock join)
     : base(source)
 {
     trueArm_  = trueArm;
     falseArm_ = falseArm;
     join_     = join;
     invert_   = invert;
 }
Exemple #9
0
 private ControlBlock traverseJoin(NodeBlock block)
 {
     if (isJoin(block))
     {
         return(null);
     }
     return(traverseBlock(block));
 }
Exemple #10
0
 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]);
 }
Exemple #11
0
 public DJumpCondition(SPOpcode spop, DNode node, NodeBlock lht, NodeBlock rht)
     : base(node)
 {
     // //Debug.Assert(getOperand(0) != null);
     spop_        = spop;
     trueTarget_  = lht;
     falseTarget_ = rht;
 }
Exemple #12
0
 public static NodeBlock GetEmptyTarget(NodeBlock block)
 {
     if (block.nodes.last != block.nodes.first)
     {
         return(null);
     }
     return(GetSingleTarget(block));
 }
Exemple #13
0
 public IfBlock(NodeBlock source, LogicChain chain, ControlBlock trueArm, ControlBlock falseArm, ControlBlock join)
     : base(source)
 {
     trueArm_  = trueArm;
     falseArm_ = falseArm;
     join_     = join;
     invert_   = invert;
     logic_    = logic;
 }
Exemple #14
0
 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);
     }
 }
Exemple #15
0
        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));
        }
Exemple #16
0
        public static NodeBlock GetSingleTarget(NodeBlock block)
        {
            if (block.nodes.last.type != NodeType.Jump)
            {
                return(null);
            }
            DJump jump = (DJump)block.nodes.last;

            return(jump.target);
        }
Exemple #17
0
 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]);
     }
 }
Exemple #18
0
 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);
         }
     }
 }
Exemple #19
0
 private bool isJoin(NodeBlock block)
 {
     for (int i = joinStack_.Count - 1; i >= 0; i--)
     {
         if (joinStack_.ElementAt(i) == block)
         {
             return(true);
         }
     }
     return(false);
 }
Exemple #20
0
 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();
     }
 }
Exemple #21
0
 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);
         }
     }
 }
Exemple #22
0
 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);
         }
     }
 }
Exemple #23
0
 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);
             }
         }
     }
 }
Exemple #24
0
 private ControlBlock traverseBlock(NodeBlock block)
 {
     if (block != null)
     {
         if (block.lir != null)
         {
             if (block.lir.backedge != null)
             {
                 return(traverseLoop(block));
             }
         }
     }
     return(traverseBlockNoLoop(block));
 }
Exemple #25
0
        public static NodeBlock EffectiveTarget(NodeBlock block)
        {
            NodeBlock target = block;

            for (;;)
            {
                block = GetEmptyTarget(block);
                if (block == null)
                {
                    return(target);
                }
                target = block;
            }
        }
Exemple #26
0
 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]));
 }
Exemple #27
0
 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;
     }
 }
Exemple #28
0
        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);
        }
Exemple #29
0
 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();
         }
     }
 }
Exemple #30
0
 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]);
 }
Exemple #31
0
        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));
        }
Exemple #32
0
        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);
        }
Exemple #33
0
        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);
            }
        }
Exemple #34
0
 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];
 }
Exemple #35
0
 public static NodeBlock EffectiveTarget(NodeBlock block)
 {
     NodeBlock target = block;
     for (;;)
     {
         block = GetEmptyTarget(block);
         if (block == null)
             return target;
         target = block;
     }
 }
Exemple #36
0
        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);
        }
Exemple #37
0
 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);
     }
 }
Exemple #38
0
        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;
            }
        }
Exemple #39
0
        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);
        }
Exemple #40
0
 public ReturnBlock(NodeBlock source)
   : base(source)
 {
 }
Exemple #41
0
 public StatementBlock(NodeBlock source, ControlBlock next)
     : base(source)
 {
                 next_ = next;
 }
Exemple #42
0
 public ControlBlock(NodeBlock source)
 {
     source_ = source;
 }
Exemple #43
0
 public SwitchBlock(NodeBlock source, ControlBlock defaultCase, List<Case> cases, ControlBlock join)
   : base(source)
 {
     defaultCase_ = defaultCase;
     cases_ = cases;
     join_ = join;
 }
Exemple #44
0
 public WhileLoop(ControlType type, NodeBlock source, ControlBlock body, ControlBlock join)
   : base(source)
 {
     body_ = body;
     join_ = join;
     type_ = type;
 }
Exemple #45
0
 public IfBlock(NodeBlock source, LogicChain chain, ControlBlock trueArm, ControlBlock falseArm, ControlBlock join)
     : base(source)
 {
     trueArm_ = trueArm;
     falseArm_ = falseArm;
     join_ = join;
     invert_ = invert;
     logic_ = logic;
 }
Exemple #46
0
 public IfBlock(NodeBlock source, bool invert, ControlBlock trueArm, ControlBlock falseArm, ControlBlock join)
   : base(source)
 {
     trueArm_ = trueArm;
     falseArm_ = falseArm;
     join_ = join;
     invert_ = invert;
 }
Exemple #47
0
        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);
        }
Exemple #48
0
 private void pushScope(NodeBlock block)
 {
     joinStack_.Push(block);
 }
Exemple #49
0
        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);
        }
Exemple #50
0
 private bool isJoin(NodeBlock block)
 {
     for (int i = joinStack_.Count - 1; i >= 0; i--)
     {
         if (joinStack_.ElementAt(i) == block)
             return true;
     }
     return false;
 }
Exemple #51
0
        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;
        }
Exemple #52
0
        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;
        }
Exemple #53
0
 private ControlBlock traverseJoin(NodeBlock block)
 {
     if (isJoin(block))
         return null;
     return traverseBlock(block);
 }
Exemple #54
0
        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();
            }
        }
Exemple #55
0
 private ControlBlock traverseBlock(NodeBlock block)
 {
     if (block != null)
     {
         if (block.lir != null)
         {
             if (block.lir.backedge != null)
             {
                 return traverseLoop(block);
             }
         }
     }
     return traverseBlockNoLoop(block);
 }
Exemple #56
0
 private static void AssertInnerJoinValidity(NodeBlock join, NodeBlock earlyExit)
 {
     DJumpCondition jcc = (DJumpCondition)join.nodes.last;
     //Debug.Assert(BlockAnalysis.EffectiveTarget(jcc.trueTarget) == earlyExit || join == SingleTarget(earlyExit));
 }
Exemple #57
0
 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;
     }
 }
Exemple #58
0
        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);
        }
Exemple #59
0
 private static NodeBlock SingleTarget(NodeBlock block)
 {
     DJump jump = (DJump)block.nodes.last;
     return jump.target;
 }
Exemple #60
0
        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]);
            }
        }