Beispiel #1
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 #2
0
        /// <summary>
        /// Looks for common exits in the inlined then and else branches of an if instruction
        /// and performs inversions and simplifications to merge them provided they don't
        /// isolate a higher priority block exit
        /// </summary>
        private void MergeCommonBranches(Block block, IfInstruction ifInst)
        {
            var thenExits = new List <ILInstruction>();

            AddExits(ifInst.TrueInst, 0, thenExits);
            if (thenExits.Count == 0)
            {
                return;
            }

            // if there are any exits from the then branch, then the else is redundant and shouldn't exist
            Debug.Assert(IsEmpty(ifInst.FalseInst));
            Debug.Assert(ifInst.Parent == block);
            var elseExits      = new List <ILInstruction>();
            int falseInstIndex = block.Instructions.IndexOf(ifInst) + 1;

            AddExits(block, falseInstIndex, elseExits);

            var commonExits = elseExits.Where(e1 => thenExits.Any(e2 => DetectExitPoints.CompatibleExitInstruction(e1, e2)));

            // find the common exit with the highest block exit priority
            ILInstruction commonExit = null;

            foreach (var exit in commonExits)
            {
                if (commonExit == null || CompareBlockExitPriority(exit, commonExit) > 0)
                {
                    commonExit = exit;
                }
            }

            if (commonExit == null)
            {
                return;
            }

            // if the current block exit has higher priority than the exits to merge,
            // determine if this merge will isolate the current block exit
            // that is, no sequence of inversions can restore it to the block exit position
            var blockExit = block.Instructions.Last();

            if (CompareBlockExitPriority(blockExit, commonExit, true) > 0 && !WillShortCircuit(block, ifInst, commonExit))
            {
                return;
            }

            // could improve performance by directly implementing the || short-circuit when WillShortCircuit
            // currently the same general sequence of transformations introduces both operators

            context.StepStartGroup("Merge common branches " + commonExit, ifInst);
            ProduceExit(ifInst.TrueInst, 0, commonExit);
            ProduceExit(block, falseInstIndex, commonExit);

            // if (...) { ...; blockExit; } ...; blockExit;
            // -> if (...) { ...; blockExit; } else { ... } blockExit;
            if (ifInst != block.Instructions.SecondToLastOrDefault())
            {
                context.Step("Embed else-block for goto removal", ifInst);
                Debug.Assert(IsEmpty(ifInst.FalseInst));
                ifInst.FalseInst = ExtractBlock(block, block.Instructions.IndexOf(ifInst) + 1, block.Instructions.Count - 1);
            }

            // if (...) { ...; goto blockExit; } blockExit;
            // -> if (...) { ... } blockExit;
            // OR
            // if (...) { ...; goto blockExit; } else { ... } blockExit;
            // -> if (...) { ... } else { ... } blockExit;
            context.Step("Remove redundant 'goto blockExit;' in then-branch", ifInst);
            if (!(ifInst.TrueInst is Block trueBlock) || trueBlock.Instructions.Count == 1)
            {
                ifInst.TrueInst = new Nop().WithILRange(ifInst.TrueInst);
            }