Beispiel #1
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);
        }
Beispiel #2
0
        private void writeIf(IfBlock block)
        {
            string cond;

            if (block.logic == null)
            {
                writeStatements(block.source);

                DJumpCondition jcc = (DJumpCondition)block.source.nodes.last;

                if (block.invert)
                {
                    if (jcc.getOperand(0).type == NodeType.Unary &&
                        ((DUnary)jcc.getOperand(0)).spop == SPOpcode.not)
                    {
                        cond = buildExpression(jcc.getOperand(0).getOperand(0));
                    }
                    else if (jcc.getOperand(0).type == NodeType.Load)
                    {
                        cond = "!" + buildExpression(jcc.getOperand(0));
                    }
                    else
                    {
                        cond = "!(" + buildExpression(jcc.getOperand(0)) + ")";
                    }
                }
                else
                {
                    cond = buildExpression(jcc.getOperand(0));
                }
            }
            else
            {
                cond = buildLogicChain(block.logic);
                Debug.Assert(!block.invert);
            }

            outputLine("if (" + cond + ")");
            outputLine("{");
            increaseIndent();
            writeBlock(block.trueArm);
            decreaseIndent();
            if (block.falseArm != null &&
                BlockAnalysis.GetEmptyTarget(block.falseArm.source) == null)
            {
                outputLine("}");
                outputLine("else");
                outputLine("{");
                increaseIndent();
                writeBlock(block.falseArm);
                decreaseIndent();
            }
            outputLine("}");
            if (block.join != null)
            {
                writeBlock(block.join);
            }
        }
Beispiel #3
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));
        }
Beispiel #4
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]);
 }
Beispiel #5
0
        private LGraph buildBlocks()
        {
            lir_.entry = new LBlock(lir_.entry_pc);
            var builder = new BlockBuilder(lir_);
            var entry   = builder.parse();

            // Get an RPO ordering of the blocks, since we don't have predecessors yet.
            var blocks = BlockAnalysis.Order(entry);

            if (!BlockAnalysis.IsReducible(blocks))
            {
                throw new Exception("control flow graph is not reducible");
            }

            // Split critical edges in the graph (is this even needed?)
            BlockAnalysis.SplitCriticalEdges(blocks);

            // Reorder the blocks since we could have introduced new nodes.
            blocks = BlockAnalysis.Order(entry);
            //Debug.Assert(BlockAnalysis.IsReducible(blocks));

            BlockAnalysis.ComputeDominators(blocks);
            BlockAnalysis.ComputeImmediateDominators(blocks);
            BlockAnalysis.ComputeDominatorTree(blocks);
            BlockAnalysis.FindLoops(blocks);

            var graph = new LGraph
            {
                blocks = blocks,
                entry  = blocks[0]
            };

            if (lir_.argDepth > 0)
            {
                graph.nargs = ((lir_.argDepth - 12) / 4) + 1;
            }
            else
            {
                graph.nargs = 0;
            }

            return(graph);
        }
Beispiel #6
0
        private static LogicOperator ToLogicOp(DJumpCondition jcc)
        {
            NodeBlock trueTarget     = BlockAnalysis.EffectiveTarget(jcc.trueTarget);
            bool      targetIsTruthy = false;

            if (trueTarget.lir.instructions[0] is LConstant)
            {
                LConstant constant = (LConstant)trueTarget.lir.instructions[0];
                targetIsTruthy = (constant.val == 1);
            }

            // jump on true -> 1 == ||
            // jump on false -> 0 == &&
            // other combinations are nonsense, so assert.
            ////Debug.Assert((jcc.spop == SPOpcode.jnz && targetIsTruthy) ||
            //             (jcc.spop == SPOpcode.jzer && !targetIsTruthy));
            LogicOperator logicop = (jcc.spop == SPOpcode.jnz && targetIsTruthy)
                                    ? LogicOperator.Or
                                    : LogicOperator.And;

            return(logicop);
        }
Beispiel #7
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));
        }
Beispiel #8
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);
            }
        }
Beispiel #9
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));
        }
Beispiel #10
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);
        }