Exemplo n.º 1
0
        public bool SimplifyShortCircuit(List <ILNode> body, ILBasicBlock head, int pos)
        {
            Debug.Assert(body.Contains(head));

            ILExpression condExpr;
            ILLabel      trueLabel;
            ILLabel      falseLabel;

            if (head.MatchLastAndBr(ILCode.Brtrue, out trueLabel, out condExpr, out falseLabel))
            {
                for (int pass = 0; pass < 2; pass++)
                {
                    // On the second pass, swap labels and negate expression of the first branch
                    // It is slightly ugly, but much better then copy-pasting this whole block
                    ILLabel nextLabel   = (pass == 0) ? trueLabel  : falseLabel;
                    ILLabel otherLablel = (pass == 0) ? falseLabel : trueLabel;
                    bool    negate      = (pass == 1);

                    ILBasicBlock nextBasicBlock = labelToBasicBlock[nextLabel];
                    ILExpression nextCondExpr;
                    ILLabel      nextTrueLablel;
                    ILLabel      nextFalseLabel;
                    if (body.Contains(nextBasicBlock) &&
                        nextBasicBlock != head &&
                        labelGlobalRefCount[(ILLabel)nextBasicBlock.Body.First()] == 1 &&
                        nextBasicBlock.MatchSingleAndBr(ILCode.Brtrue, out nextTrueLablel, out nextCondExpr, out nextFalseLabel) &&
                        (otherLablel == nextFalseLabel || otherLablel == nextTrueLablel))
                    {
                        // Create short cicuit branch
                        ILExpression logicExpr;
                        if (otherLablel == nextFalseLabel)
                        {
                            logicExpr = MakeLeftAssociativeShortCircuit(ILCode.LogicAnd, negate ? new ILExpression(ILCode.LogicNot, null, condExpr) : condExpr, nextCondExpr);
                        }
                        else
                        {
                            logicExpr = MakeLeftAssociativeShortCircuit(ILCode.LogicOr, negate ? condExpr : new ILExpression(ILCode.LogicNot, null, condExpr), nextCondExpr);
                        }
                        head.Body.RemoveTail(ILCode.Brtrue, ILCode.Br);
                        head.Body.Add(new ILExpression(ILCode.Brtrue, nextTrueLablel, logicExpr));
                        head.Body.Add(new ILExpression(ILCode.Br, nextFalseLabel));

                        // Remove the inlined branch from scope
                        body.RemoveOrThrow(nextBasicBlock);

                        return(true);
                    }
                }
            }
            return(false);
        }
Exemplo n.º 2
0
        public bool SimplifyNullCoalescing(List <ILNode> body, ILBasicBlock head, int pos)
        {
            // ...
            // v = ldloc(leftVar)
            // brtrue(endBBLabel, ldloc(leftVar))
            // br(rightBBLabel)
            //
            // rightBBLabel:
            // v = rightExpr
            // br(endBBLabel)
            // ...
            // =>
            // ...
            // v = NullCoalescing(ldloc(leftVar), rightExpr)
            // br(endBBLabel)

            ILVariable   v, v2;
            ILExpression leftExpr, leftExpr2;
            ILVariable   leftVar;
            ILLabel      endBBLabel, endBBLabel2;
            ILLabel      rightBBLabel;
            ILBasicBlock rightBB;
            ILExpression rightExpr;

            if (head.Body.Count >= 3 &&
                head.Body[head.Body.Count - 3].Match(ILCode.Stloc, out v, out leftExpr) &&
                leftExpr.Match(ILCode.Ldloc, out leftVar) &&
                head.MatchLastAndBr(ILCode.Brtrue, out endBBLabel, out leftExpr2, out rightBBLabel) &&
                leftExpr2.MatchLdloc(leftVar) &&
                labelToBasicBlock.TryGetValue(rightBBLabel, out rightBB) &&
                rightBB.MatchSingleAndBr(ILCode.Stloc, out v2, out rightExpr, out endBBLabel2) &&
                v == v2 &&
                endBBLabel == endBBLabel2 &&
                labelGlobalRefCount.GetOrDefault(rightBBLabel) == 1 &&
                body.Contains(rightBB)
                )
            {
                head.Body.RemoveTail(ILCode.Stloc, ILCode.Brtrue, ILCode.Br);
                head.Body.Add(new ILExpression(ILCode.Stloc, v, new ILExpression(ILCode.NullCoalescing, null, leftExpr, rightExpr)));
                head.Body.Add(new ILExpression(ILCode.Br, endBBLabel));

                body.RemoveOrThrow(labelToBasicBlock[rightBBLabel]);
                return(true);
            }
            return(false);
        }
Exemplo n.º 3
0
        public bool SimplifyTernaryOperator(List <ILNode> body, ILBasicBlock head, int pos)
        {
            Debug.Assert(body.Contains(head));

            ILExpression condExpr;
            ILLabel      trueLabel;
            ILLabel      falseLabel;
            ILVariable   trueLocVar = null;
            ILExpression trueExpr;
            ILLabel      trueFall;
            ILVariable   falseLocVar = null;
            ILExpression falseExpr;
            ILLabel      falseFall;
            object       unused;

            if (head.MatchLastAndBr(ILCode.Brtrue, out trueLabel, out condExpr, out falseLabel) &&
                labelGlobalRefCount[trueLabel] == 1 &&
                labelGlobalRefCount[falseLabel] == 1 &&
                ((labelToBasicBlock[trueLabel].MatchSingleAndBr(ILCode.Stloc, out trueLocVar, out trueExpr, out trueFall) &&
                  labelToBasicBlock[falseLabel].MatchSingleAndBr(ILCode.Stloc, out falseLocVar, out falseExpr, out falseFall) &&
                  trueLocVar == falseLocVar && trueFall == falseFall) ||
                 (labelToBasicBlock[trueLabel].MatchSingle(ILCode.Ret, out unused, out trueExpr) &&
                  labelToBasicBlock[falseLabel].MatchSingle(ILCode.Ret, out unused, out falseExpr))) &&
                body.Contains(labelToBasicBlock[trueLabel]) &&
                body.Contains(labelToBasicBlock[falseLabel])
                )
            {
                bool          isStloc          = trueLocVar != null;
                ILCode        opCode           = isStloc ? ILCode.Stloc : ILCode.Ret;
                TypeReference retType          = isStloc ? trueLocVar.Type : this.context.CurrentMethod.ReturnType;
                bool          retTypeIsBoolean = TypeAnalysis.IsBoolean(retType);
                int           leftBoolVal;
                int           rightBoolVal;
                ILExpression  newExpr;
                // a ? true:false  is equivalent to  a
                // a ? false:true  is equivalent to  !a
                // a ? true : b    is equivalent to  a || b
                // a ? b : true    is equivalent to  !a || b
                // a ? b : false   is equivalent to  a && b
                // a ? false : b   is equivalent to  !a && b
                if (retTypeIsBoolean &&
                    trueExpr.Match(ILCode.Ldc_I4, out leftBoolVal) &&
                    falseExpr.Match(ILCode.Ldc_I4, out rightBoolVal) &&
                    ((leftBoolVal != 0 && rightBoolVal == 0) || (leftBoolVal == 0 && rightBoolVal != 0))
                    )
                {
                    // It can be expressed as trivilal expression
                    if (leftBoolVal != 0)
                    {
                        newExpr = condExpr;
                    }
                    else
                    {
                        newExpr = new ILExpression(ILCode.LogicNot, null, condExpr)
                        {
                            InferredType = typeSystem.Boolean
                        };
                    }
                }
                else if ((retTypeIsBoolean || TypeAnalysis.IsBoolean(falseExpr.InferredType)) && trueExpr.Match(ILCode.Ldc_I4, out leftBoolVal) && (leftBoolVal == 0 || leftBoolVal == 1))
                {
                    // It can be expressed as logical expression
                    if (leftBoolVal != 0)
                    {
                        newExpr = MakeLeftAssociativeShortCircuit(ILCode.LogicOr, condExpr, falseExpr);
                    }
                    else
                    {
                        newExpr = MakeLeftAssociativeShortCircuit(ILCode.LogicAnd, new ILExpression(ILCode.LogicNot, null, condExpr), falseExpr);
                    }
                }
                else if ((retTypeIsBoolean || TypeAnalysis.IsBoolean(trueExpr.InferredType)) && falseExpr.Match(ILCode.Ldc_I4, out rightBoolVal) && (rightBoolVal == 0 || rightBoolVal == 1))
                {
                    // It can be expressed as logical expression
                    if (rightBoolVal != 0)
                    {
                        newExpr = MakeLeftAssociativeShortCircuit(ILCode.LogicOr, new ILExpression(ILCode.LogicNot, null, condExpr), trueExpr);
                    }
                    else
                    {
                        newExpr = MakeLeftAssociativeShortCircuit(ILCode.LogicAnd, condExpr, trueExpr);
                    }
                }
                else
                {
                    // Ternary operator tends to create long complicated return statements
                    if (opCode == ILCode.Ret)
                    {
                        return(false);
                    }

                    // Only simplify generated variables
                    if (opCode == ILCode.Stloc && !trueLocVar.IsGenerated)
                    {
                        return(false);
                    }

                    // Create ternary expression
                    newExpr = new ILExpression(ILCode.TernaryOp, null, condExpr, trueExpr, falseExpr);
                }

                head.Body.RemoveTail(ILCode.Brtrue, ILCode.Br);
                head.Body.Add(new ILExpression(opCode, trueLocVar, newExpr));
                if (isStloc)
                {
                    head.Body.Add(new ILExpression(ILCode.Br, trueFall));
                }

                // Remove the old basic blocks
                body.RemoveOrThrow(labelToBasicBlock[trueLabel]);
                body.RemoveOrThrow(labelToBasicBlock[falseLabel]);

                return(true);
            }
            return(false);
        }
Exemplo n.º 4
0
        public bool SimplifyCustomShortCircuit(List <ILNode> body, ILBasicBlock head, int pos)
        {
            Debug.Assert(body.Contains(head));

            // --- looking for the following pattern ---
            // stloc(targetVar, leftVar)
            // brtrue(exitLabel, call(op_False, leftVar)
            // br(followingBlock)
            //
            // FollowingBlock:
            // stloc(targetVar, call(op_BitwiseAnd, leftVar, rightExpression))
            // br(exitLabel)
            // ---

            if (head.Body.Count < 3)
            {
                return(false);
            }

            // looking for:
            // stloc(targetVar, leftVar)
            ILVariable   targetVar;
            ILExpression targetVarInitExpr;

            if (!head.Body[head.Body.Count - 3].Match(ILCode.Stloc, out targetVar, out targetVarInitExpr))
            {
                return(false);
            }

            ILVariable leftVar;

            if (!targetVarInitExpr.Match(ILCode.Ldloc, out leftVar))
            {
                return(false);
            }

            // looking for:
            // brtrue(exitLabel, call(op_False, leftVar)
            // br(followingBlock)
            ILExpression callExpr;
            ILLabel      exitLabel;
            ILLabel      followingBlock;

            if (!head.MatchLastAndBr(ILCode.Brtrue, out exitLabel, out callExpr, out followingBlock))
            {
                return(false);
            }

            if (labelGlobalRefCount[followingBlock] > 1)
            {
                return(false);
            }

            MethodReference opFalse;
            ILExpression    opFalseArg;

            if (!callExpr.Match(ILCode.Call, out opFalse, out opFalseArg))
            {
                return(false);
            }

            // ignore operators other than op_False and op_True
            if (opFalse.Name != "op_False" && opFalse.Name != "op_True")
            {
                return(false);
            }

            if (!opFalseArg.MatchLdloc(leftVar))
            {
                return(false);
            }

            ILBasicBlock followingBasicBlock = labelToBasicBlock[followingBlock];

            // FollowingBlock:
            // stloc(targetVar, call(op_BitwiseAnd, leftVar, rightExpression))
            // br(exitLabel)
            ILVariable   _targetVar;
            ILExpression opBitwiseCallExpr;
            ILLabel      _exitLabel;

            if (!followingBasicBlock.MatchSingleAndBr(ILCode.Stloc, out _targetVar, out opBitwiseCallExpr, out _exitLabel))
            {
                return(false);
            }

            if (_targetVar != targetVar || exitLabel != _exitLabel)
            {
                return(false);
            }

            MethodReference opBitwise;
            ILExpression    leftVarExpression;
            ILExpression    rightExpression;

            if (!opBitwiseCallExpr.Match(ILCode.Call, out opBitwise, out leftVarExpression, out rightExpression))
            {
                return(false);
            }

            if (!leftVarExpression.MatchLdloc(leftVar))
            {
                return(false);
            }

            // ignore operators other than op_BitwiseAnd and op_BitwiseOr
            if (opBitwise.Name != "op_BitwiseAnd" && opBitwise.Name != "op_BitwiseOr")
            {
                return(false);
            }

            // insert:
            // stloc(targetVar, LogicAnd(C::op_BitwiseAnd, leftVar, rightExpression)
            // br(exitLabel)
            ILCode op = opBitwise.Name == "op_BitwiseAnd" ? ILCode.LogicAnd : ILCode.LogicOr;

            if (op == ILCode.LogicAnd && opFalse.Name != "op_False")
            {
                return(false);
            }

            if (op == ILCode.LogicOr && opFalse.Name != "op_True")
            {
                return(false);
            }

            ILExpression shortCircuitExpr = MakeLeftAssociativeShortCircuit(op, opFalseArg, rightExpression);

            shortCircuitExpr.Operand = opBitwise;

            head.Body.RemoveTail(ILCode.Stloc, ILCode.Brtrue, ILCode.Br);
            head.Body.Add(new ILExpression(ILCode.Stloc, targetVar, shortCircuitExpr));
            head.Body.Add(new ILExpression(ILCode.Br, exitLabel));
            body.Remove(followingBasicBlock);

            return(true);
        }
Exemplo n.º 5
0
        List <ILNode> FindConditions(HashSet <ControlFlowNode> scope, ControlFlowNode entryNode)
        {
            List <ILNode> result = new List <ILNode>();

            // Do not modify entry data
            scope = new HashSet <ControlFlowNode>(scope);

            Stack <ControlFlowNode> agenda = new Stack <ControlFlowNode>();

            agenda.Push(entryNode);
            while (agenda.Count > 0)
            {
                ControlFlowNode node = agenda.Pop();

                // Find a block that represents a simple condition
                if (scope.Contains(node))
                {
                    ILBasicBlock block = (ILBasicBlock)node.UserData;

                    {
                        // Switch
                        ILLabel[]    caseLabels;
                        ILExpression switchArg;
                        ILLabel      fallLabel;
                        if (block.MatchLastAndBr(ILCode.Switch, out caseLabels, out switchArg, out fallLabel))
                        {
                            // Replace the switch code with ILSwitch
                            ILSwitch ilSwitch = new ILSwitch()
                            {
                                Condition = switchArg
                            };
                            block.Body.RemoveTail(ILCode.Switch, ILCode.Br);
                            block.Body.Add(ilSwitch);
                            block.Body.Add(new ILExpression(ILCode.Br, fallLabel));
                            result.Add(block);

                            // Remove the item so that it is not picked up as content
                            scope.RemoveOrThrow(node);

                            // Find the switch offset
                            int addValue = 0;
                            List <ILExpression> subArgs;
                            if (ilSwitch.Condition.Match(ILCode.Sub, out subArgs) && subArgs[1].Match(ILCode.Ldc_I4, out addValue))
                            {
                                ilSwitch.Condition = subArgs[0];
                            }

                            // Pull in code of cases
                            ControlFlowNode fallTarget = null;
                            labelToCfNode.TryGetValue(fallLabel, out fallTarget);

                            HashSet <ControlFlowNode> frontiers = new HashSet <ControlFlowNode>();
                            if (fallTarget != null)
                            {
                                frontiers.UnionWith(fallTarget.DominanceFrontier.Except(new [] { fallTarget }));
                            }

                            foreach (ILLabel condLabel in caseLabels)
                            {
                                ControlFlowNode condTarget = null;
                                labelToCfNode.TryGetValue(condLabel, out condTarget);
                                if (condTarget != null)
                                {
                                    frontiers.UnionWith(condTarget.DominanceFrontier.Except(new [] { condTarget }));
                                }
                            }

                            for (int i = 0; i < caseLabels.Length; i++)
                            {
                                ILLabel condLabel = caseLabels[i];

                                // Find or create new case block
                                ILSwitch.CaseBlock caseBlock = ilSwitch.CaseBlocks.FirstOrDefault(b => b.EntryGoto.Operand == condLabel);
                                if (caseBlock == null)
                                {
                                    caseBlock = new ILSwitch.CaseBlock()
                                    {
                                        Values    = new List <int>(),
                                        EntryGoto = new ILExpression(ILCode.Br, condLabel)
                                    };
                                    ilSwitch.CaseBlocks.Add(caseBlock);

                                    ControlFlowNode condTarget = null;
                                    labelToCfNode.TryGetValue(condLabel, out condTarget);
                                    if (condTarget != null && !frontiers.Contains(condTarget))
                                    {
                                        HashSet <ControlFlowNode> content = FindDominatedNodes(scope, condTarget);
                                        scope.ExceptWith(content);
                                        caseBlock.Body.AddRange(FindConditions(content, condTarget));
                                        // Add explicit break which should not be used by default, but the goto removal might decide to use it
                                        caseBlock.Body.Add(new ILBasicBlock()
                                        {
                                            Body =
                                            {
                                                new ILLabel()
                                                {
                                                    Name = "SwitchBreak_" + (nextLabelIndex++)
                                                },
                                                new ILExpression(ILCode.LoopOrSwitchBreak, null)
                                            }
                                        });
                                    }
                                }
                                caseBlock.Values.Add(i + addValue);
                            }

                            // Heuristis to determine if we want to use fallthough as default case
                            if (fallTarget != null && !frontiers.Contains(fallTarget))
                            {
                                HashSet <ControlFlowNode> content = FindDominatedNodes(scope, fallTarget);
                                if (content.Any())
                                {
                                    var caseBlock = new ILSwitch.CaseBlock()
                                    {
                                        EntryGoto = new ILExpression(ILCode.Br, fallLabel)
                                    };
                                    ilSwitch.CaseBlocks.Add(caseBlock);
                                    block.Body.RemoveTail(ILCode.Br);

                                    scope.ExceptWith(content);
                                    caseBlock.Body.AddRange(FindConditions(content, fallTarget));
                                    // Add explicit break which should not be used by default, but the goto removal might decide to use it
                                    caseBlock.Body.Add(new ILBasicBlock()
                                    {
                                        Body =
                                        {
                                            new ILLabel()
                                            {
                                                Name = "SwitchBreak_" + (nextLabelIndex++)
                                            },
                                            new ILExpression(ILCode.LoopOrSwitchBreak, null)
                                        }
                                    });
                                }
                            }
                        }

                        // Two-way branch
                        ILExpression condExpr;
                        ILLabel      trueLabel;
                        ILLabel      falseLabel;
                        if (block.MatchLastAndBr(ILCode.Brtrue, out trueLabel, out condExpr, out falseLabel))
                        {
                            // Swap bodies since that seems to be the usual C# order
                            ILLabel temp = trueLabel;
                            trueLabel  = falseLabel;
                            falseLabel = temp;
                            condExpr   = new ILExpression(ILCode.LogicNot, null, condExpr);

                            // Convert the brtrue to ILCondition
                            ILCondition ilCond = new ILCondition()
                            {
                                Condition = condExpr,
                                TrueBlock = new ILBlock()
                                {
                                    EntryGoto = new ILExpression(ILCode.Br, trueLabel)
                                },
                                FalseBlock = new ILBlock()
                                {
                                    EntryGoto = new ILExpression(ILCode.Br, falseLabel)
                                }
                            };
                            block.Body.RemoveTail(ILCode.Brtrue, ILCode.Br);
                            block.Body.Add(ilCond);
                            result.Add(block);

                            // Remove the item immediately so that it is not picked up as content
                            scope.RemoveOrThrow(node);

                            ControlFlowNode trueTarget = null;
                            labelToCfNode.TryGetValue(trueLabel, out trueTarget);
                            ControlFlowNode falseTarget = null;
                            labelToCfNode.TryGetValue(falseLabel, out falseTarget);

                            // Pull in the conditional code
                            if (trueTarget != null && HasSingleEdgeEnteringBlock(trueTarget))
                            {
                                HashSet <ControlFlowNode> content = FindDominatedNodes(scope, trueTarget);
                                scope.ExceptWith(content);
                                ilCond.TrueBlock.Body.AddRange(FindConditions(content, trueTarget));
                            }
                            if (falseTarget != null && HasSingleEdgeEnteringBlock(falseTarget))
                            {
                                HashSet <ControlFlowNode> content = FindDominatedNodes(scope, falseTarget);
                                scope.ExceptWith(content);
                                ilCond.FalseBlock.Body.AddRange(FindConditions(content, falseTarget));
                            }
                        }
                    }

                    // Add the node now so that we have good ordering
                    if (scope.Contains(node))
                    {
                        result.Add((ILNode)node.UserData);
                        scope.Remove(node);
                    }
                }

                // depth-first traversal of dominator tree
                for (int i = node.DominatorTreeChildren.Count - 1; i >= 0; i--)
                {
                    agenda.Push(node.DominatorTreeChildren[i]);
                }
            }

            // Add whatever is left
            foreach (var node in scope)
            {
                result.Add((ILNode)node.UserData);
            }

            return(result);
        }