Beispiel #1
0
        /// <summary>
        /// Adds a new section to the Sections list.
        ///
        /// If the instruction is a branch instruction, unify the new section with an existing section
        /// that also branches to the same target.
        /// </summary>
        void AddSection(LongSet values, ILInstruction inst)
        {
            if (values.IsEmpty)
            {
                return;
            }
            Block targetBlock;

            if (inst.MatchBranch(out targetBlock))
            {
                int index;
                if (targetBlockToSectionIndex.TryGetValue(targetBlock, out index))
                {
                    Sections[index] = new KeyValuePair <LongSet, ILInstruction>(
                        Sections[index].Key.UnionWith(values),
                        inst
                        );
                }
                else
                {
                    targetBlockToSectionIndex.Add(targetBlock, Sections.Count);
                    Sections.Add(new KeyValuePair <LongSet, ILInstruction>(values, inst));
                }
            }
            else
            {
                Sections.Add(new KeyValuePair <LongSet, ILInstruction>(values, inst));
            }
        }
Beispiel #2
0
        bool ShouldSwapIfTargets(ILInstruction inst1, ILInstruction inst2)
        {
            Block block1 = null, block2 = null;

            if (inst1.MatchBranch(out block1) && inst2.MatchBranch(out block2))
            {
                // prefer arranging stuff in IL order
                return(block1.ILRange.Start > block2.ILRange.Start);
            }
            BlockContainer container1, container2;

            if (inst1.MatchLeave(out container1) && container1.Parent is TryInstruction)
            {
                // 'leave tryBlock' is considered to have a later target than
                // any branch within the container, and also a later target
                // than a return instruction.
                // This is necessary to avoid "goto" statements in the
                // ExceptionHandling.ConditionalReturnInThrow test.
                if (!inst2.MatchLeave(out container2))
                {
                    container2 = block2?.Parent as BlockContainer;
                }
                return(container2 == null || container2.IsDescendantOf(container1));
            }
            if (inst1.MatchBranch(out block1) && inst2.MatchLeave(out container2) &&
                block1.IncomingEdgeCount > 1)
            {
                // if (..) goto x; leave c;
                // Unless x can be inlined, it's better to swap the order if the 'leave'
                // has a chance to turn into a 'break;' or 'return;'
                if (container2.Parent is ILFunction)
                {
                    return(true);                    // return
                }
                if (container2.EntryPoint.IncomingEdgeCount > 1)
                {
                    // break
                    return(BlockContainer.FindClosestContainer(inst2) == container2);
                }
            }
            return(false);
        }
Beispiel #3
0
        /// <summary>
        /// Analyzes the tail end (last two instructions) of a block.
        /// </summary>
        /// <remarks>
        /// Sets <c>switchVar</c> and <c>defaultInstruction</c> if they are null,
        /// and adds found sections to <c>sectionLabels</c> and <c>sectionInstructions</c>.
        ///
        /// If the function returns false, <c>sectionLabels</c> and <c>sectionInstructions</c> are unmodified.
        /// </remarks>
        /// <param name="block">The block to analyze.</param>
        /// <param name="inputValues">The possible values of the "interesting" variable
        /// when control flow reaches this block.</param>
        /// <param name="tailOnly">If true, analyze only the tail (last two instructions).
        /// If false, analyze the whole block.</param>
        bool AnalyzeBlock(Block block, LongSet inputValues, bool tailOnly = false)
        {
            if (tailOnly)
            {
                Debug.Assert(block == rootBlock);
                if (block.Instructions.Count < 2)
                {
                    return(false);
                }
            }
            else
            {
                Debug.Assert(switchVar != null);                 // switchVar should always be determined by the top-level call
                if (block.IncomingEdgeCount != 1 || block == rootBlock)
                {
                    return(false);                    // for now, let's only consider if-structures that form a tree
                }
                if (block.Instructions.Count != 2)
                {
                    return(false);
                }
                if (block.Parent != rootBlock.Parent)
                {
                    return(false);                    // all blocks should belong to the same container
                }
            }
            var           inst = block.Instructions[block.Instructions.Count - 2];
            ILInstruction condition, trueInst;
            LongSet       trueValues;

            if (inst.MatchIfInstruction(out condition, out trueInst) &&
                AnalyzeCondition(condition, out trueValues)
                )
            {
                trueValues = trueValues.IntersectWith(inputValues);
                Block trueBlock;
                if (trueInst.MatchBranch(out trueBlock) && AnalyzeBlock(trueBlock, trueValues))
                {
                    // OK, true block was further analyzed.
                    InnerBlocks.Add(trueBlock);
                }
                else
                {
                    // Create switch section for trueInst.
                    AddSection(trueValues, trueInst);
                }
            }
            else if (inst.OpCode == OpCode.SwitchInstruction)
            {
                if (AnalyzeSwitch((SwitchInstruction)inst, inputValues, out trueValues))
                {
                    ContainsILSwitch = true; // OK
                }
                else                         // switch analysis failed (e.g. switchVar mismatch)
                {
                    return(false);
                }
            }
            else                 // unknown inst
            {
                return(false);
            }

            var           remainingValues = inputValues.ExceptWith(trueValues);
            ILInstruction falseInst       = block.Instructions.Last();
            Block         falseBlock;

            if (falseInst.MatchBranch(out falseBlock) && AnalyzeBlock(falseBlock, remainingValues))
            {
                // OK, false block was further analyzed.
                InnerBlocks.Add(falseBlock);
            }
            else
            {
                // Create switch section for falseInst.
                AddSection(remainingValues, falseInst);
            }
            return(true);
        }