Beispiel #1
0
        /// <summary>
        /// Builds structured control flow for the block associated with the control flow node.
        /// </summary>
        /// <remarks>
        /// After a block was processed, it should use structured control flow
        /// and have just a single 'regular' exit point (last branch instruction in the block)
        /// </remarks>
        public void Run(Block block, BlockTransformContext context)
        {
            this.context     = context;
            currentContainer = (BlockContainer)block.Parent;

            // We only embed blocks into this block if they aren't referenced anywhere else,
            // so those blocks are dominated by this block.
            // BlockILTransform thus guarantees that the blocks being embedded are already
            // fully processed.

            cfgNode = context.ControlFlowNode;
            Debug.Assert(cfgNode.UserData == block);

            // Because this transform runs at the beginning of the block transforms,
            // we know that `block` is still a (non-extended) basic block.

            // Previous-to-last instruction might have conditional control flow,
            // usually an IfInstruction with a branch:
            if (block.Instructions.SecondToLastOrDefault() is IfInstruction ifInst)
            {
                HandleIfInstruction(block, ifInst);
            }
            else
            {
                InlineExitBranch(block);
            }
        }
Beispiel #2
0
 public void RunTransforms(IEnumerable <IBlockTransform> transforms, BlockTransformContext context)
 {
     this.CheckInvariant(ILPhase.Normal);
     foreach (var transform in transforms)
     {
         context.CancellationToken.ThrowIfCancellationRequested();
         context.StepStartGroup(transform.GetType().Name);
         transform.Run(this, context);
         this.CheckInvariant(ILPhase.Normal);
         context.StepEndGroup();
     }
 }
Beispiel #3
0
        /// <summary>
        /// Builds structured control flow for the block associated with the control flow node.
        /// </summary>
        /// <remarks>
        /// After a block was processed, it should use structured control flow
        /// and have just a single 'regular' exit point (last branch instruction in the block)
        /// </remarks>
        public void Run(Block block, BlockTransformContext context)
        {
            this.context          = context;
            this.currentContainer = (BlockContainer)block.Parent;

            // We only embed blocks into this block if they aren't referenced anywhere else,
            // so those blocks are dominated by this block.
            // BlockILTransform thus guarantees that the blocks being embedded are already
            // fully processed.

            var cfgNode = context.ControlFlowNode;

            Debug.Assert(cfgNode.UserData == block);

            // Because this transform runs at the beginning of the block transforms,
            // we know that `block` is still a (non-extended) basic block.

            // Last instruction is one with unreachable endpoint
            // (guaranteed by combination of BlockContainer and Block invariants)
            Debug.Assert(block.Instructions.Last().HasFlag(InstructionFlags.EndPointUnreachable));
            ILInstruction exitInst = block.Instructions.Last();

            // Previous-to-last instruction might have conditional control flow,
            // usually an IfInstruction with a branch:
            IfInstruction ifInst = block.Instructions.SecondToLastOrDefault() as IfInstruction;

            if (ifInst != null && ifInst.FalseInst.OpCode == OpCode.Nop)
            {
                HandleIfInstruction(cfgNode, block, ifInst, ref exitInst);
            }
            else
            {
                SwitchInstruction switchInst = block.Instructions.SecondToLastOrDefault() as SwitchInstruction;
                if (switchInst != null)
                {
                    HandleSwitchInstruction(cfgNode, block, switchInst, ref exitInst);
                }
            }
            if (IsUsableBranchToChild(cfgNode, exitInst))
            {
                // "...; goto usableblock;"
                // -> embed target block in this block
                context.Step("Inline target block of unconditional branch", exitInst);
                var targetBlock = ((Branch)exitInst).TargetBlock;
                Debug.Assert(exitInst == block.Instructions.Last());
                block.Instructions.RemoveAt(block.Instructions.Count - 1);
                block.Instructions.AddRange(targetBlock.Instructions);
                targetBlock.Remove();
            }
        }
Beispiel #4
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);
            }
        }