コード例 #1
0
		void MarkReachable(ControlFlowNode node)
		{
			if (node.PreviousStatement != null)
				reachableEndPoints.Add(node.PreviousStatement);
			if (node.NextStatement != null)
				reachableStatements.Add(node.NextStatement);
			foreach (var edge in node.Outgoing) {
				if (visitedNodes.Add(edge.To))
					stack.Push(edge.To);
			}
		}
コード例 #2
0
        protected override bool CanReachModification(ControlFlowNode node, Statement start,
												   IDictionary<Statement, IList<Node>> modifications)
        {
            if (base.CanReachModification (node, start, modifications))
                return true;

            if (node.NextStatement != start) {
                var usingStatement = node.PreviousStatement as UsingStatement;
                if (usingStatement != null) {
                    if (modifications.ContainsKey(usingStatement))
                        return true;
                    if (usingStatement.ResourceAcquisition is Statement &&
                        modifications.ContainsKey ((Statement)usingStatement.ResourceAcquisition))
                        return true;
                }
            }
            return false;
        }
コード例 #3
0
ファイル: ControlFlowEdge.cs プロジェクト: GreenDamTan/dnSpy
		public ControlFlowEdge(ControlFlowNode source, ControlFlowNode target, JumpType type)
		{
			this.Source = source;
			this.Target = target;
			this.Type = type;
		}
コード例 #4
0
        private void DetectSwitchBody(Block block, SwitchInstruction switchInst)
        {
            Debug.Assert(block.Instructions.Last() == switchInst);
            ControlFlowNode h = context.ControlFlowNode;             // CFG node for our switch head

            Debug.Assert(h.UserData == block);
            Debug.Assert(!TreeTraversal.PreOrder(h, n => n.DominatorTreeChildren).Any(n => n.Visited));

            var nodesInSwitch = new List <ControlFlowNode>();

            nodesInSwitch.Add(h);
            h.Visited = true;
            ExtendLoop(h, nodesInSwitch, out var exitPoint, isSwitch: true);
            if (exitPoint != null && exitPoint.Predecessors.Count == 1 && !context.ControlFlowGraph.HasReachableExit(exitPoint))
            {
                // If the exit point is reachable from just one single "break;",
                // it's better to move the code into the switch.
                // (unlike loops which should not be nested unless necessary,
                //  nesting switches makes it clearer in which cases a piece of code is reachable)
                nodesInSwitch.AddRange(TreeTraversal.PreOrder(exitPoint, p => p.DominatorTreeChildren));
                exitPoint = null;
            }

            context.Step("Create BlockContainer for switch", switchInst);
            // Sort blocks in the loop in reverse post-order to make the output look a bit nicer.
            // (if the loop doesn't contain nested loops, this is a topological sort)
            nodesInSwitch.Sort((a, b) => b.PostOrderNumber.CompareTo(a.PostOrderNumber));
            Debug.Assert(nodesInSwitch[0] == h);
            foreach (var node in nodesInSwitch)
            {
                node.Visited = false;                 // reset visited flag so that we can find outer loops
                Debug.Assert(h.Dominates(node) || !node.IsReachable, "The switch body must be dominated by the switch head");
            }

            BlockContainer switchContainer = new BlockContainer();
            Block          newEntryPoint   = new Block();

            newEntryPoint.ILRange = switchInst.ILRange;
            switchContainer.Blocks.Add(newEntryPoint);
            newEntryPoint.Instructions.Add(switchInst);
            block.Instructions[block.Instructions.Count - 1] = switchContainer;

            Block exitTargetBlock = (Block)exitPoint?.UserData;

            if (exitTargetBlock != null)
            {
                block.Instructions.Add(new Branch(exitTargetBlock));
            }

            MoveBlocksIntoContainer(nodesInSwitch, switchContainer);

            // Rewrite branches within the loop from oldEntryPoint to newEntryPoint:
            foreach (var branch in switchContainer.Descendants.OfType <Branch>())
            {
                if (branch.TargetBlock == exitTargetBlock)
                {
                    branch.ReplaceWith(new Leave(switchContainer)
                    {
                        ILRange = branch.ILRange
                    });
                }
            }
        }
コード例 #5
0
        /// <summary>
        /// Check whether 'block' is a loop head; and construct a loop instruction
        /// (nested BlockContainer) if it is.
        /// </summary>
        public void Run(Block block, BlockTransformContext context)
        {
            this.context = context;
            // LoopDetection runs early enough so that block should still
            // be in the original container at this point.
            Debug.Assert(block.Parent == context.ControlFlowGraph.Container);
            this.currentBlockContainer = context.ControlFlowGraph.Container;

            // Because this is a post-order block transform, we can assume that
            // any nested loops within this loop have already been constructed.

            if (block.Instructions.Last() is SwitchInstruction switchInst)
            {
                // Switch instructions support "break;" just like loops
                DetectSwitchBody(block, switchInst);
            }

            ControlFlowNode h = context.ControlFlowNode;             // CFG node for our potential loop head

            Debug.Assert(h.UserData == block);
            Debug.Assert(!TreeTraversal.PreOrder(h, n => n.DominatorTreeChildren).Any(n => n.Visited));

            List <ControlFlowNode> loop = null;

            foreach (var t in h.Predecessors)
            {
                if (h.Dominates(t))
                {
                    // h->t is a back edge, and h is a loop header
                    // Add the natural loop of t->h to the loop.

                    // Definitions:
                    // * A back edge is an edge t->h so that h dominates t.
                    // * The natural loop of the back edge is the smallest set of nodes
                    //   that includes the back edge and has no predecessors outside the set
                    //   except for the predecessor of the header.

                    if (loop == null)
                    {
                        loop = new List <ControlFlowNode>();
                        loop.Add(h);
                        // Mark loop header as visited so that the pre-order traversal
                        // stops at the loop header.
                        h.Visited = true;
                    }
                    t.TraversePreOrder(n => n.Predecessors, loop.Add);
                }
            }
            if (loop != null)
            {
                var headBlock = (Block)h.UserData;
                context.Step($"Construct loop with head {headBlock.Label}", headBlock);
                // loop now is the union of all natural loops with loop head h.
                // Try to extend the loop to reduce the number of exit points:
                ExtendLoop(h, loop, out var exitPoint);

                // Sort blocks in the loop in reverse post-order to make the output look a bit nicer.
                // (if the loop doesn't contain nested loops, this is a topological sort)
                loop.Sort((a, b) => b.PostOrderNumber.CompareTo(a.PostOrderNumber));
                Debug.Assert(loop[0] == h);
                foreach (var node in loop)
                {
                    node.Visited = false;                     // reset visited flag so that we can find outer loops
                    Debug.Assert(h.Dominates(node) || !node.IsReachable, "The loop body must be dominated by the loop head");
                }
                ConstructLoop(loop, exitPoint);
            }
        }
コード例 #6
0
ファイル: LoopDetection.cs プロジェクト: YuLiangLin/ILSpy
 /// <summary>
 /// Returns the children in a loop dominator tree, with an optional exit point
 /// Avoids returning continue statements when analysing switches (because increment blocks can be dominated)
 /// </summary>
 IEnumerable <ControlFlowNode> DominatorTreeChildren(ControlFlowNode n, ControlFlowNode exitPoint) =>
 n.DominatorTreeChildren.Where(c => c != exitPoint && (!isSwitch || !loopContext.MatchContinue(c)));
コード例 #7
0
ファイル: LoopDetection.cs プロジェクト: YuLiangLin/ILSpy
        /// <summary>
        /// Finds a suitable single exit point for the specified loop.
        /// </summary>
        /// <returns>
        /// 1) If a suitable exit point was found: the control flow block that should be reached when breaking from the loop
        /// 2) If the loop should not have any exit point (extend by all dominated blocks): NoExitPoint
        /// 3) otherwise (exit point unknown, heuristically extend loop): null
        /// </returns>
        /// <remarks>This method must not write to the Visited flags on the CFG.</remarks>
        internal ControlFlowNode FindExitPoint(ControlFlowNode loopHead, IReadOnlyList <ControlFlowNode> naturalLoop)
        {
            bool hasReachableExit = HasReachableExit(loopHead);

            if (!hasReachableExit)
            {
                // Case 1:
                // There are no nodes n so that loopHead dominates a predecessor of n but not n itself
                // -> we could build a loop with zero exit points.
                if (IsPossibleForeachLoop((Block)loopHead.UserData, out var exitBranch))
                {
                    if (exitBranch != null)
                    {
                        // let's see if the target of the exit branch is a suitable exit point
                        var cfgNode = loopHead.Successors.FirstOrDefault(n => n.UserData == exitBranch.TargetBlock);
                        if (cfgNode != null && loopHead.Dominates(cfgNode) && !context.ControlFlowGraph.HasReachableExit(cfgNode))
                        {
                            return(cfgNode);
                        }
                    }
                    return(NoExitPoint);
                }
                ControlFlowNode exitPoint         = null;
                int             exitPointILOffset = -1;
                ConsiderReturnAsExitPoint((Block)loopHead.UserData, ref exitPoint, ref exitPointILOffset);
                foreach (var node in loopHead.DominatorTreeChildren)
                {
                    PickExitPoint(node, ref exitPoint, ref exitPointILOffset);
                }
                return(exitPoint);
            }
            else
            {
                // Case 2:
                // We need to pick our exit point so that all paths from the loop head
                // to the reachable exits run through that exit point.
                var cfg    = context.ControlFlowGraph.cfg;
                var revCfg = PrepareReverseCFG(loopHead, out int exitNodeArity);
                //ControlFlowNode.ExportGraph(cfg).Show("cfg");
                //ControlFlowNode.ExportGraph(revCfg).Show("rev");
                ControlFlowNode commonAncestor = revCfg[loopHead.UserIndex];
                Debug.Assert(commonAncestor.IsReachable);
                foreach (ControlFlowNode cfgNode in naturalLoop)
                {
                    ControlFlowNode revNode = revCfg[cfgNode.UserIndex];
                    if (revNode.IsReachable)
                    {
                        commonAncestor = Dominance.FindCommonDominator(commonAncestor, revNode);
                    }
                }
                // All paths from within the loop to a reachable exit run through 'commonAncestor'.
                // However, this doesn't mean that 'commonAncestor' is valid as an exit point.
                // We walk up the post-dominator tree until we've got a valid exit point:
                ControlFlowNode exitPoint;
                while (commonAncestor.UserIndex >= 0)
                {
                    exitPoint = cfg[commonAncestor.UserIndex];
                    Debug.Assert(exitPoint.Visited == naturalLoop.Contains(exitPoint));
                    // It's possible that 'commonAncestor' is itself part of the natural loop.
                    // If so, it's not a valid exit point.
                    if (!exitPoint.Visited && ValidateExitPoint(loopHead, exitPoint))
                    {
                        // we found an exit point
                        return(exitPoint);
                    }
                    commonAncestor = commonAncestor.ImmediateDominator;
                }
                // least common post-dominator is the artificial exit node
                // This means we're in one of two cases:
                // * The loop might have multiple exit points.
                //     -> we should return null
                // * The loop has a single exit point that wasn't considered during post-dominance analysis.
                //        (which means the single exit isn't dominated by the loop head)
                //     -> we should return NoExitPoint so that all code dominated by the loop head is included into the loop
                if (exitNodeArity > 1)
                {
                    return(null);
                }

                // Exit node is on the very edge of the tree, and isn't important for determining inclusion
                // Still necessary for switch detection to insert correct leave statements
                if (exitNodeArity == 1 && isSwitch)
                {
                    return(loopContext.GetBreakTargets(loopHead).Distinct().Single());
                }

                // If exitNodeArity == 0, we should maybe look test if our exits out of the block container are all compatible?
                // but I don't think it hurts to have a bit too much code inside the loop in this rare case.
                return(NoExitPoint);
            }
        }
コード例 #8
0
 /// <summary>
 /// Constructor.
 /// </summary>
 /// <param name="cfg">ControlFlowGraph</param>
 /// <param name="summary">MethodSummary</param>
 /// <param name="loopExitNode">ControlFlowNode</param>
 internal LoopHeadControlFlowNode(IGraph <IControlFlowNode> cfg,
                                  MethodSummary summary, ControlFlowNode loopExitNode)
     : base(cfg, summary)
 {
     this.LoopExitNode = loopExitNode;
 }
コード例 #9
0
		protected virtual bool CanReachModification (ControlFlowNode node, Statement start,
												     IDictionary<Statement, IList<Node>> modifications)
		{
			return node.NextStatement != null && node.NextStatement != start &&
				   modifications.ContainsKey (node.NextStatement);
		}
コード例 #10
0
        static HashSet <ControlFlowNode> FindLoopContent(HashSet <ControlFlowNode> scope, ControlFlowNode head)
        {
            HashSet <ControlFlowNode> agenda = new HashSet <ControlFlowNode>();

            for (int i = 0; i < head.Incoming.Count; i++)
            {
                var p = head.Incoming[i].Source;
                if (head.Dominates(p))
                {
                    agenda.Add(p);
                }
            }
            HashSet <ControlFlowNode> result = new HashSet <ControlFlowNode>();

            while (agenda.Count > 0)
            {
                ControlFlowNode addNode = agenda.First();
                agenda.Remove(addNode);

                if (scope.Contains(addNode) && head.Dominates(addNode) && result.Add(addNode))
                {
                    for (int i = 0; i < addNode.Incoming.Count; i++)
                    {
                        agenda.Add(addNode.Incoming[i].Source);
                    }
                }
            }
            if (scope.Contains(head))
            {
                result.Add(head);
            }

            return(result);
        }
コード例 #11
0
        static HashSet <ControlFlowNode> FindDominatedNodes(HashSet <ControlFlowNode> scope, ControlFlowNode head)
        {
            HashSet <ControlFlowNode> agenda = new HashSet <ControlFlowNode>();
            HashSet <ControlFlowNode> result = new HashSet <ControlFlowNode>();

            agenda.Add(head);

            while (agenda.Count > 0)
            {
                ControlFlowNode addNode = agenda.First();
                agenda.Remove(addNode);

                if (scope.Contains(addNode) && head.Dominates(addNode) && result.Add(addNode))
                {
                    for (int i = 0; i < addNode.Outgoing.Count; i++)
                    {
                        agenda.Add(addNode.Outgoing[i].Target);
                    }
                }
            }

            return(result);
        }
コード例 #12
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
                        IList <ILExpression> cases;
                        ILLabel[]            caseLabels;
                        ILExpression         switchCondition;
                        ILLabel fallLabel;
                        //   IList<ILExpression> cases; out IList<ILExpression> arg, out ILLabel fallLabel)
                        // matches a switch statment, not sure how the hell I am going to do this
                        if (block.MatchLastAndBr(GMCode.Switch, out caseLabels, out cases, out fallLabel))
                        {
                            //    Debug.Assert(fallLabel == endBlock); // this should be true
                            switchCondition = cases[0]; // thats the switch arg
                            cases.RemoveAt(0);          // remove the switch condition

                            // Replace the switch code with ILSwitch
                            ILSwitch ilSwitch = new ILSwitch()
                            {
                                Condition = switchCondition
                            };
                            block.Body.RemoveTail(GMCode.Switch, GMCode.B);
                            block.Body.Add(ilSwitch);
                            block.Body.Add(new ILExpression(GMCode.B, fallLabel));
                            result.Add(block);

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

                            // 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 <ILExpression>(),
                                        EntryGoto = new ILExpression(GMCode.B, 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);
                                        foreach (var con in FindConditions(content, condTarget))
                                        {
                                            caseBlock.Body.Add(con);
                                        }
                                        //   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(GMCode.LoopOrSwitchBreak, null)
                                            }
                                        });
                                    }
                                }
                                if (cases[i].Code != GMCode.DefaultCase)
                                {
                                    caseBlock.Values.Add(cases[i].Arguments[0]);
                                }
                                else
                                {
                                    caseBlock.Values.Add(new ILExpression(GMCode.DefaultCase, null));
                                }
                            }

                            // 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(GMCode.B, fallLabel)
                                    };
                                    ilSwitch.CaseBlocks.Add(caseBlock);
                                    block.Body.RemoveTail(GMCode.B);

                                    scope.ExceptWith(content);
                                    foreach (var con in FindConditions(content, fallTarget))
                                    {
                                        caseBlock.Body.Add(con);
                                    }

                                    // 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(GMCode.LoopOrSwitchBreak, null)
                                        }
                                    });
                                }
                            }
                        }
                        //   Debug.Assert((block.Body.First() as ILLabel).Name != "L1938");
                        // Two-way branch
                        ILLabel trueLabel;
                        ILLabel falseLabel;
                        IList <ILExpression> condExprs;
                        if (block.MatchLastAndBr(GMCode.Bf, out falseLabel, out condExprs, out trueLabel) &&
                            condExprs[0].Code != GMCode.Pop)     // its resolved
                        {
                            ILExpression   condExpr = condExprs[0];
                            IList <ILNode> body     = block.Body;
                            // this is a simple condition, skip anything short curiket for now
                            // Match a condition patern
                            // Convert the brtrue to ILCondition
                            ILCondition ilCond = new ILCondition()
                            {
                                Condition = condExpr,
                                TrueBlock = new ILBlock()
                                {
                                    EntryGoto = new ILExpression(GMCode.B, trueLabel)
                                },
                                FalseBlock = new ILBlock()
                                {
                                    EntryGoto = new ILExpression(GMCode.B, falseLabel)
                                }
                            };
                            block.Body.RemoveTail(GMCode.Bf, GMCode.B);
                            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);
                                foreach (var con in FindConditions(content, trueTarget))
                                {
                                    ilCond.TrueBlock.Body.Add(con);
                                }
                            }
                            if (falseTarget != null && HasSingleEdgeEnteringBlock(falseTarget))
                            {
                                HashSet <ControlFlowNode> content = FindDominatedNodes(scope, falseTarget);
                                scope.ExceptWith(content);
                                foreach (var con in FindConditions(content, falseTarget))
                                {
                                    ilCond.FalseBlock.Body.Add(con);
                                }
                            }
                        }
                    }

                    // 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);
        }
コード例 #13
0
 internal AdjacencyCollection(ControlFlowNode <TContents> owner, ControlFlowEdgeType edgeType)
 {
     EdgeType = edgeType;
     Owner    = owner ?? throw new ArgumentNullException(nameof(owner));
 }
コード例 #14
0
 /// <summary>
 /// Obtains all edges to the provided neighbour, if any.
 /// </summary>
 /// <param name="target">The neighbouring node.</param>
 /// <returns>The edges.</returns>
 public IEnumerable <ControlFlowEdge <TContents> > GetEdgesToNeighbour(ControlFlowNode <TContents> target) =>
 GetEdges(target);
コード例 #15
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);
        }
コード例 #16
0
        static HashSet <ControlFlowNode> FindDominatedNodes(HashSet <ControlFlowNode> scope, ControlFlowNode head)
        {
            HashSet <ControlFlowNode> agenda = new HashSet <ControlFlowNode>();
            HashSet <ControlFlowNode> result = new HashSet <ControlFlowNode>();

            agenda.Add(head);

            while (agenda.Count > 0)
            {
                ControlFlowNode addNode = agenda.First();
                agenda.Remove(addNode);

                if (scope.Contains(addNode) && head.Dominates(addNode) && result.Add(addNode))
                {
                    foreach (var successor in addNode.Successors)
                    {
                        agenda.Add(successor);
                    }
                }
            }

            return(result);
        }
コード例 #17
0
ファイル: BlockBuilder.cs プロジェクト: HoLLy-HaCKeR/Echo
        private void UpdateScopeStack(ControlFlowNode <TInstruction> node, IndexableStack <ScopeInfo> scopeStack)
        {
            var activeRegions = node.GetSituatedRegions()
                                .Reverse()
                                .ToArray();

            int largestPossibleCommonDepth = Math.Min(scopeStack.Count, activeRegions.Length);

            // Figure out common region depth.
            int commonDepth = 1;

            while (commonDepth < largestPossibleCommonDepth)
            {
                if (scopeStack[commonDepth].Region != activeRegions[commonDepth])
                {
                    break;
                }
                commonDepth++;
            }

            // Leave for every left region a scope block.
            while (scopeStack.Count > commonDepth)
            {
                scopeStack.Pop();
            }

            // Enter for every entered region a new block.
            while (scopeStack.Count < activeRegions.Length)
            {
                // Create new scope block.
                var enteredRegion = activeRegions[scopeStack.Count];

                // Add new cope block to the current scope.
                var currentScope = scopeStack.Peek();

                if (enteredRegion is ExceptionHandlerRegion <TInstruction> ehRegion)
                {
                    // We entered an exception handler region.
                    var ehBlock = new ExceptionHandlerBlock <TInstruction>();
                    currentScope.AddBlock(ehBlock);
                    scopeStack.Push(new ScopeInfo(ehRegion, ehBlock));
                }
                else if (enteredRegion.ParentRegion is ExceptionHandlerRegion <TInstruction> parentEhRegion)
                {
                    // We entered one of the exception handler sub regions. Figure out which one it is.
                    var enteredBlock = default(ScopeBlock <TInstruction>);

                    if (!(currentScope.Block is ExceptionHandlerBlock <TInstruction> ehBlock))
                    {
                        throw new InvalidOperationException("The parent scope is not an exception handler scope.");
                    }

                    if (parentEhRegion.ProtectedRegion == enteredRegion)
                    {
                        // We entered the protected region.
                        enteredBlock = ehBlock.ProtectedBlock;
                    }
                    else
                    {
                        // We entered a handler region.
                        enteredBlock = new ScopeBlock <TInstruction>();
                        ehBlock.HandlerBlocks.Add(enteredBlock);
                    }

                    // Push the entered scope.
                    scopeStack.Push(new ScopeInfo(parentEhRegion.ProtectedRegion, enteredBlock));
                }
                else
                {
                    // Fall back method: just enter a new scope block.
                    var scopeBlock = new ScopeBlock <TInstruction>();
                    currentScope.AddBlock(scopeBlock);
                    scopeStack.Push(new ScopeInfo(enteredRegion, scopeBlock));
                }
            }
        }
コード例 #18
0
        ControlFlowGraph BuildGraph(List <ILNode> nodes, ILLabel entryLabel)
        {
            int index = 0;
            List <ControlFlowNode> cfNodes    = new List <ControlFlowNode>();
            ControlFlowNode        entryPoint = new ControlFlowNode(index++, 0, ControlFlowNodeType.EntryPoint);

            cfNodes.Add(entryPoint);
            ControlFlowNode regularExit = new ControlFlowNode(index++, 0xffffffff, ControlFlowNodeType.RegularExit);

            cfNodes.Add(regularExit);
            ControlFlowNode exceptionalExit = new ControlFlowNode(index++, 0xffffffff, ControlFlowNodeType.ExceptionalExit);

            cfNodes.Add(exceptionalExit);

            // Create graph nodes
            labelToCfNode = new Dictionary <ILLabel, ControlFlowNode>();
            Dictionary <ILNode, ControlFlowNode> astNodeToCfNode = new Dictionary <ILNode, ControlFlowNode>();

            foreach (ILBasicBlock node in nodes)
            {
                ControlFlowNode cfNode = new ControlFlowNode(index++, 0xffffffff, ControlFlowNodeType.Normal);
                cfNodes.Add(cfNode);
                astNodeToCfNode[node] = cfNode;
                cfNode.UserData       = node;

                // Find all contained labels
                foreach (ILLabel label in node.GetSelfAndChildrenRecursive <ILLabel>())
                {
                    labelToCfNode[label] = cfNode;
                }
            }

            // Entry endge
            ControlFlowNode entryNode = labelToCfNode[entryLabel];
            ControlFlowEdge entryEdge = new ControlFlowEdge(entryPoint, entryNode, JumpType.Normal);

            entryPoint.Outgoing.Add(entryEdge);
            entryNode.Incoming.Add(entryEdge);

            // Create edges
            foreach (ILBasicBlock node in nodes)
            {
                ControlFlowNode source = astNodeToCfNode[node];

                // Find all branches
                foreach (ILLabel target in node.GetSelfAndChildrenRecursive <ILExpression>(e => e.IsBranch()).SelectMany(e => e.GetBranchTargets()))
                {
                    ControlFlowNode destination;
                    // Labels which are out of out scope will not be in the collection
                    // Insert self edge only if we are sure we are a loop
                    if (labelToCfNode.TryGetValue(target, out destination) && (destination != source || target == node.Body.FirstOrDefault()))
                    {
                        ControlFlowEdge edge = new ControlFlowEdge(source, destination, JumpType.Normal);
                        source.Outgoing.Add(edge);
                        destination.Incoming.Add(edge);
                    }
                }
            }

            return(new ControlFlowGraph(cfNodes.ToArray()));
        }
コード例 #19
0
ファイル: SwitchDetection.cs プロジェクト: zz110/ILSpy
 public bool MatchContinue(ControlFlowNode node) => MatchContinue(node, out var _);
コード例 #20
0
ファイル: LoopDetection.cs プロジェクト: zy850580380/ILSpy
        /// <summary>
        /// Constructs a new control flow graph.
        /// Each node cfg[i] has a corresponding node rev[i].
        /// Edges are only created for nodes dominated by loopHead, and are in reverse from their direction
        /// in the primary CFG.
        /// An artificial exit node is used for edges that leave the set of nodes dominated by loopHead,
        /// or that leave the block Container.
        /// </summary>
        /// <param name="loopHead">Entry point of the loop.</param>
        /// <param name="exitNodeArity">out: The number of different CFG nodes.
        /// Possible values:
        ///  0 = no CFG nodes used as exit nodes (although edges leaving the block container might still be exits);
        ///  1 = a single CFG node (not dominated by loopHead) was used as an exit node;
        ///  2 = more than one CFG node (not dominated by loopHead) was used as an exit node.
        /// </param>
        /// <returns></returns>
        ControlFlowNode[] PrepareReverseCFG(ControlFlowNode loopHead, out int exitNodeArity)
        {
            ControlFlowNode[] cfg = context.ControlFlowGraph.cfg;
            ControlFlowNode[] rev = new ControlFlowNode[cfg.Length + 1];
            for (int i = 0; i < cfg.Length; i++)
            {
                rev[i] = new ControlFlowNode {
                    UserIndex = i, UserData = cfg[i].UserData
                };
            }
            ControlFlowNode nodeTreatedAsExitNode           = null;
            bool            multipleNodesTreatedAsExitNodes = false;
            ControlFlowNode exitNode = new ControlFlowNode {
                UserIndex = -1
            };

            rev[cfg.Length] = exitNode;
            for (int i = 0; i < cfg.Length; i++)
            {
                if (!loopHead.Dominates(cfg[i]) || isSwitch && cfg[i] != loopHead && loopContext.MatchContinue(cfg[i]))
                {
                    continue;
                }

                // Add reverse edges for all edges in cfg
                foreach (var succ in cfg[i].Successors)
                {
                    // edges to outer loops still count as exits (labelled continue not implemented)
                    if (isSwitch && loopContext.MatchContinue(succ, 1))
                    {
                        continue;
                    }

                    if (loopHead.Dominates(succ))
                    {
                        rev[succ.UserIndex].AddEdgeTo(rev[i]);
                    }
                    else
                    {
                        if (nodeTreatedAsExitNode == null)
                        {
                            nodeTreatedAsExitNode = succ;
                        }
                        if (nodeTreatedAsExitNode != succ)
                        {
                            multipleNodesTreatedAsExitNodes = true;
                        }
                        exitNode.AddEdgeTo(rev[i]);
                    }
                }
                if (context.ControlFlowGraph.HasDirectExitOutOfContainer(cfg[i]))
                {
                    exitNode.AddEdgeTo(rev[i]);
                }
            }
            if (multipleNodesTreatedAsExitNodes)
            {
                exitNodeArity = 2;                 // more than 1
            }
            else if (nodeTreatedAsExitNode != null)
            {
                exitNodeArity = 1;
            }
            else
            {
                exitNodeArity = 0;
            }
            Dominance.ComputeDominance(exitNode, context.CancellationToken);
            return(rev);
        }
コード例 #21
0
ファイル: SwitchDetection.cs プロジェクト: zz110/ILSpy
 public bool MatchContinue(ControlFlowNode node, int depth) =>
 MatchContinue(node, out int _depth) && depth == _depth;
コード例 #22
0
ファイル: LoopDetection.cs プロジェクト: YuLiangLin/ILSpy
 /// <summary>
 /// Extension of ControlFlowGraph.HasReachableExit
 /// Uses loopContext.GetBreakTargets().Any() when analyzing switches to avoid
 /// classifying continue blocks as reachable exits.
 /// </summary>
 bool HasReachableExit(ControlFlowNode node) => isSwitch
                 ? loopContext.GetBreakTargets(node).Any()
                 : context.ControlFlowGraph.HasReachableExit(node);
コード例 #23
0
ファイル: SwitchDetection.cs プロジェクト: zz110/ILSpy
 public bool MatchContinue(ControlFlowNode node, out int depth) => continueDepth.TryGetValue(node, out depth);
コード例 #24
0
        /// <summary>
        /// Finds a suitable single exit point for the specified loop.
        /// </summary>
        /// <returns>
        /// 1) If a suitable exit point was found: the control flow block that should be reached when breaking from the loop
        /// 2) If the loop should not have any exit point (extend by all dominated blocks): NoExitPoint
        /// 3) otherwise (exit point unknown, heuristically extend loop): null
        /// </returns>
        /// <remarks>This method must not write to the Visited flags on the CFG.</remarks>
        ControlFlowNode FindExitPoint(ControlFlowNode loopHead, IReadOnlyList <ControlFlowNode> naturalLoop, bool treatBackEdgesAsExits)
        {
            bool hasReachableExit = context.ControlFlowGraph.HasReachableExit(loopHead);

            if (!hasReachableExit && treatBackEdgesAsExits)
            {
                // If we're analyzing the switch, there's no reachable exit, but the loopHead (=switchHead) block
                // is also a loop head, we consider the back-edge a reachable exit for the switch.
                hasReachableExit = loopHead.Predecessors.Any(p => loopHead.Dominates(p));
            }
            if (!hasReachableExit)
            {
                // Case 1:
                // There are no nodes n so that loopHead dominates a predecessor of n but not n itself
                // -> we could build a loop with zero exit points.
                if (IsPossibleForeachLoop((Block)loopHead.UserData, out var exitBranch))
                {
                    if (exitBranch != null)
                    {
                        // let's see if the target of the exit branch is a suitable exit point
                        var cfgNode = loopHead.Successors.FirstOrDefault(n => n.UserData == exitBranch.TargetBlock);
                        if (cfgNode != null && loopHead.Dominates(cfgNode) && !context.ControlFlowGraph.HasReachableExit(cfgNode))
                        {
                            return(cfgNode);
                        }
                    }
                    return(NoExitPoint);
                }
                ControlFlowNode exitPoint         = null;
                int             exitPointILOffset = -1;
                foreach (var node in loopHead.DominatorTreeChildren)
                {
                    PickExitPoint(node, ref exitPoint, ref exitPointILOffset);
                }
                return(exitPoint);
            }
            else
            {
                // Case 2:
                // We need to pick our exit point so that all paths from the loop head
                // to the reachable exits run through that exit point.
                var cfg    = context.ControlFlowGraph.cfg;
                var revCfg = PrepareReverseCFG(loopHead, treatBackEdgesAsExits);
                //ControlFlowNode.ExportGraph(cfg).Show("cfg");
                //ControlFlowNode.ExportGraph(revCfg).Show("rev");
                ControlFlowNode commonAncestor = revCfg[loopHead.UserIndex];
                Debug.Assert(commonAncestor.IsReachable);
                foreach (ControlFlowNode cfgNode in naturalLoop)
                {
                    ControlFlowNode revNode = revCfg[cfgNode.UserIndex];
                    if (revNode.IsReachable)
                    {
                        commonAncestor = Dominance.FindCommonDominator(commonAncestor, revNode);
                    }
                }
                // All paths from within the loop to a reachable exit run through 'commonAncestor'.
                // However, this doesn't mean that 'commonAncestor' is valid as an exit point.
                // We walk up the post-dominator tree until we've got a valid exit point:
                ControlFlowNode exitPoint;
                while (commonAncestor.UserIndex >= 0)
                {
                    exitPoint = cfg[commonAncestor.UserIndex];
                    Debug.Assert(exitPoint.Visited == naturalLoop.Contains(exitPoint));
                    // It's possible that 'commonAncestor' is itself part of the natural loop.
                    // If so, it's not a valid exit point.
                    if (!exitPoint.Visited && ValidateExitPoint(loopHead, exitPoint))
                    {
                        // we found an exit point
                        return(exitPoint);
                    }
                    commonAncestor = commonAncestor.ImmediateDominator;
                }
                // least common post-dominator is the artificial exit node
                return(null);
            }
        }
コード例 #25
0
ファイル: SwitchDetection.cs プロジェクト: zz110/ILSpy
 public int GetContinueDepth(ControlFlowNode node) => MatchContinue(node, out var depth) ? depth : 0;
コード例 #26
0
 /// <summary>
 /// This function implements a heuristic algorithm that tries to reduce the number of exit
 /// points. It is only used as fall-back when it is impossible to use a single exit point.
 /// </summary>
 /// <remarks>
 /// This heuristic loop extension algorithm traverses the loop head's dominator tree in pre-order.
 /// For each candidate node, we detect whether adding it to the loop reduces the number of exit points.
 /// If it does, the candidate is added to the loop.
 ///
 /// Adding a node to the loop has two effects on the the number of exit points:
 /// * exit points that were added to the loop are no longer exit points, thus reducing the total number of exit points
 /// * successors of the newly added nodes might be new, additional exit points
 ///
 /// Requires and maintains the invariant that a node is marked as visited iff it is contained in the loop.
 /// </remarks>
 void ExtendLoopHeuristic(ControlFlowNode loopHead, List <ControlFlowNode> loop, ControlFlowNode candidate)
 {
     Debug.Assert(candidate.Visited == loop.Contains(candidate));
     if (!candidate.Visited)
     {
         // This node not yet part of the loop, but might be added
         List <ControlFlowNode> additionalNodes = new List <ControlFlowNode>();
         // Find additionalNodes nodes and mark them as visited.
         candidate.TraversePreOrder(n => n.Predecessors, additionalNodes.Add);
         // This means Visited now represents the candiate extended loop.
         // Determine new exit points that are reachable from the additional nodes
         // (note: some of these might have previously been exit points, too)
         var newExitPoints = additionalNodes.SelectMany(n => n.Successors).Where(n => !n.Visited).ToHashSet();
         // Make visited represent the unextended loop, so that we can measure the exit points
         // in the old state.
         foreach (var node in additionalNodes)
         {
             node.Visited = false;
         }
         // Measure number of added and removed exit points
         int removedExitPoints = additionalNodes.Count(IsExitPoint);
         int addedExitPoints   = newExitPoints.Count(n => !IsExitPoint(n));
         if (removedExitPoints > addedExitPoints)
         {
             // We can reduce the number of exit points by adding the candidate node to the loop.
             candidate.TraversePreOrder(n => n.Predecessors, loop.Add);
         }
     }
     // Pre-order traversal of dominator tree
     foreach (var node in candidate.DominatorTreeChildren)
     {
         ExtendLoopHeuristic(loopHead, loop, node);
     }
 }
コード例 #27
0
ファイル: SwitchDetection.cs プロジェクト: zz110/ILSpy
 /// <summary>
 /// Lists all potential targets for break; statements from a domination tree,
 /// assuming the domination tree must be exited via either break; or continue;
 ///
 /// First list all nodes in the dominator tree (excluding continue nodes)
 /// Then return the all successors not contained within said tree.
 ///
 /// Note that node will be returned once for each outgoing edge.
 /// Labelled continue statements (depth > 1) are counted as break targets
 /// </summary>
 internal IEnumerable <ControlFlowNode> GetBreakTargets(ControlFlowNode dominator) =>
 TreeTraversal.PreOrder(dominator, n => n.DominatorTreeChildren.Where(c => !MatchContinue(c)))
 .SelectMany(n => n.Successors)
 .Where(n => !dominator.Dominates(n) && !MatchContinue(n, 1));
コード例 #28
0
ファイル: ControlFlowLink.cs プロジェクト: anurse/ILspect
 public ControlFlowLink(Condition condition, ControlFlowNode target)
 {
     Condition = condition;
     Target    = target;
 }
コード例 #29
0
ファイル: SwitchDetection.cs プロジェクト: zz110/ILSpy
 /// <summary>
 /// A flow node contains only two instructions, the first of which is an IfInstruction
 /// A short circuit expression is comprised of a root block ending in an IfInstruction and one or more flow nodes
 /// </summary>
 static bool IsFlowNode(ControlFlowNode n) => ((Block)n.UserData).Instructions.FirstOrDefault() is IfInstruction;
コード例 #30
0
        List <ILNode> FindLoops(HashSet <ControlFlowNode> scope, ControlFlowNode entryPoint, bool excludeEntryPoint)
        {
            List <ILNode> result = new List <ILNode>();

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

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

            agenda.Enqueue(entryPoint);
            while (agenda.Count > 0)
            {
                ControlFlowNode node = agenda.Dequeue();

                // If the node is a loop header
                if (scope.Contains(node) &&
                    node.DominanceFrontier.Contains(node) &&
                    (node != entryPoint || !excludeEntryPoint))
                {
                    HashSet <ControlFlowNode> loopContents = FindLoopContent(scope, node);

                    // If the first expression is a loop condition
                    ILBasicBlock basicBlock = (ILBasicBlock)node.UserData;
                    ILExpression condExpr;
                    ILLabel      trueLabel;
                    ILLabel      falseLabel;
                    // It has to be just brtrue - any preceding code would introduce goto
                    if (basicBlock.MatchSingleAndBr(ILCode.Brtrue, out trueLabel, out condExpr, out falseLabel))
                    {
                        ControlFlowNode trueTarget;
                        labelToCfNode.TryGetValue(trueLabel, out trueTarget);
                        ControlFlowNode falseTarget;
                        labelToCfNode.TryGetValue(falseLabel, out falseTarget);

                        // If one point inside the loop and the other outside
                        if ((!loopContents.Contains(trueTarget) && loopContents.Contains(falseTarget)) ||
                            (loopContents.Contains(trueTarget) && !loopContents.Contains(falseTarget)))
                        {
                            loopContents.RemoveOrThrow(node);
                            scope.RemoveOrThrow(node);

                            // If false means enter the loop
                            if (loopContents.Contains(falseTarget) || falseTarget == node)
                            {
                                // Negate the condition
                                condExpr = new ILExpression(ILCode.LogicNot, null, condExpr);
                                ILLabel tmp = trueLabel;
                                trueLabel  = falseLabel;
                                falseLabel = tmp;
                            }

                            ControlFlowNode postLoopTarget;
                            labelToCfNode.TryGetValue(falseLabel, out postLoopTarget);
                            if (postLoopTarget != null)
                            {
                                // Pull more nodes into the loop
                                HashSet <ControlFlowNode> postLoopContents = FindDominatedNodes(scope, postLoopTarget);
                                var pullIn = scope.Except(postLoopContents).Where(n => node.Dominates(n));
                                loopContents.UnionWith(pullIn);
                            }

                            // Use loop to implement the brtrue
                            basicBlock.Body.RemoveTail(ILCode.Brtrue, ILCode.Br);
                            basicBlock.Body.Add(new ILWhileLoop()
                            {
                                Condition = condExpr,
                                BodyBlock = new ILBlock()
                                {
                                    EntryGoto = new ILExpression(ILCode.Br, trueLabel),
                                    Body      = FindLoops(loopContents, node, false)
                                }
                            });
                            basicBlock.Body.Add(new ILExpression(ILCode.Br, falseLabel));
                            result.Add(basicBlock);

                            scope.ExceptWith(loopContents);
                        }
                    }

                    // Fallback method: while(true)
                    if (scope.Contains(node))
                    {
                        result.Add(new ILBasicBlock()
                        {
                            Body = new List <ILNode>()
                            {
                                new ILLabel()
                                {
                                    Name = "Loop_" + (nextLabelIndex++)
                                },
                                new ILWhileLoop()
                                {
                                    BodyBlock = new ILBlock()
                                    {
                                        EntryGoto = new ILExpression(ILCode.Br, (ILLabel)basicBlock.Body.First()),
                                        Body      = FindLoops(loopContents, node, true)
                                    }
                                },
                            },
                        });

                        scope.ExceptWith(loopContents);
                    }
                }

                // Using the dominator tree should ensure we find the the widest loop first
                foreach (var child in node.DominatorTreeChildren)
                {
                    agenda.Enqueue(child);
                }
            }

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

            return(result);
        }
コード例 #31
0
        public void Complex()
        {
            // Example graph from:
            // http://www.sable.mcgill.ca/~hendren/621/ControlFlowAnalysis_Handouts.pdf
            // (slide 57)

            var cfg = new ControlFlowGraph <int>(IntArchitecture.Instance);

            var nodes = new ControlFlowNode <int> [11];

            for (int i = 0; i < nodes.Length; i++)
            {
                nodes[i] = new ControlFlowNode <int>(i, i);
                cfg.Nodes.Add(nodes[i]);
            }

            nodes[0].ConnectWith(nodes[1]);
            nodes[1].ConnectWith(nodes[2], ControlFlowEdgeType.Conditional);
            nodes[1].ConnectWith(nodes[3]);
            nodes[2].ConnectWith(nodes[3]);
            nodes[3].ConnectWith(nodes[4]);
            nodes[4].ConnectWith(nodes[3], ControlFlowEdgeType.Conditional);
            nodes[4].ConnectWith(nodes[5]);
            nodes[4].ConnectWith(nodes[6], ControlFlowEdgeType.Conditional);
            nodes[5].ConnectWith(nodes[7]);
            nodes[6].ConnectWith(nodes[7]);
            nodes[7].ConnectWith(nodes[8]);
            nodes[7].ConnectWith(nodes[4], ControlFlowEdgeType.Conditional);
            nodes[8].ConnectWith(nodes[9]);
            nodes[8].ConnectWith(nodes[10], ControlFlowEdgeType.Conditional);
            nodes[8].ConnectWith(nodes[3], ControlFlowEdgeType.Conditional);
            nodes[9].ConnectWith(nodes[1]);
            nodes[10].ConnectWith(nodes[7]);

            cfg.Entrypoint = nodes[0];

            var tree = DominatorTree.FromGraph(cfg);

            Assert.Empty(tree.GetDominanceFrontier(nodes[0]));
            Assert.Equal(new HashSet <INode> {
                nodes[1]
            }, tree.GetDominanceFrontier(nodes[1]));
            Assert.Equal(new HashSet <INode> {
                nodes[3]
            }, tree.GetDominanceFrontier(nodes[2]));
            Assert.Equal(new HashSet <INode> {
                nodes[1], nodes[3]
            }, tree.GetDominanceFrontier(nodes[3]));
            Assert.Equal(new HashSet <INode> {
                nodes[1], nodes[3], nodes[4]
            }, tree.GetDominanceFrontier(nodes[4]));
            Assert.Equal(new HashSet <INode> {
                nodes[7]
            }, tree.GetDominanceFrontier(nodes[5]));
            Assert.Equal(new HashSet <INode> {
                nodes[7]
            }, tree.GetDominanceFrontier(nodes[6]));
            Assert.Equal(new HashSet <INode> {
                nodes[1], nodes[3], nodes[4], nodes[7]
            }, tree.GetDominanceFrontier(nodes[7]));
            Assert.Equal(new HashSet <INode> {
                nodes[1], nodes[3], nodes[7]
            }, tree.GetDominanceFrontier(nodes[8]));
            Assert.Equal(new HashSet <INode> {
                nodes[1]
            }, tree.GetDominanceFrontier(nodes[9]));
            Assert.Equal(new HashSet <INode> {
                nodes[7]
            }, tree.GetDominanceFrontier(nodes[10]));
        }
コード例 #32
0
 static bool HasSingleEdgeEnteringBlock(ControlFlowNode node)
 {
     return(node.Incoming.Count(edge => !node.Dominates(edge.Source)) == 1);
 }
コード例 #33
0
 protected virtual bool CanReachModification(ControlFlowNode node, Statement start,
                                             IDictionary <Statement, IList <Node> > modifications)
 {
     return(node.NextStatement != null && node.NextStatement != start &&
            modifications.ContainsKey(node.NextStatement));
 }
コード例 #34
0
        static HashSet <ControlFlowNode> FindLoopContent(HashSet <ControlFlowNode> scope, ControlFlowNode head)
        {
            var viaBackEdges = head.Predecessors.Where(p => head.Dominates(p));
            HashSet <ControlFlowNode> agenda = new HashSet <ControlFlowNode>(viaBackEdges);
            HashSet <ControlFlowNode> result = new HashSet <ControlFlowNode>();

            while (agenda.Count > 0)
            {
                ControlFlowNode addNode = agenda.First();
                agenda.Remove(addNode);

                if (scope.Contains(addNode) && head.Dominates(addNode) && result.Add(addNode))
                {
                    foreach (var predecessor in addNode.Predecessors)
                    {
                        agenda.Add(predecessor);
                    }
                }
            }
            if (scope.Contains(head))
            {
                result.Add(head);
            }

            return(result);
        }
コード例 #35
0
 /// <summary>
 /// Constructor.
 /// </summary>
 /// <param name="cfg">ControlFlowGraph</param>
 /// <param name="summary">MethodSummary</param>
 /// <param name="loopExitNode">ControlFlowNode</param>
 internal LoopHeadControlFlowNode(IGraph<IControlFlowNode> cfg,
     MethodSummary summary, ControlFlowNode loopExitNode)
     : base(cfg, summary)
 {
     this.LoopExitNode = loopExitNode;
 }