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 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 #3
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 #4
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 #5
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 #6
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 #7
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);
        }