Пример #1
0
        bool MatchWhileLoop(BlockContainer loop, out IfInstruction condition, out Block loopBody)
        {
            // ConditionDetection favours leave inside if and branch at end of block
            // while-loop:
            // if (!loop-condition) leave loop-container
            // ...
            condition = null;
            loopBody  = null;
            if (!(loop.EntryPoint.Instructions[0] is IfInstruction ifInstruction))
            {
                return(false);
            }
            if (!ifInstruction.FalseInst.MatchNop())
            {
                return(false);
            }
            if (UsesVariableCapturedInLoop(loop, ifInstruction.Condition))
            {
                return(false);
            }

            condition = ifInstruction;
            if (!ifInstruction.TrueInst.MatchLeave(loop))
            {
                return(false);
            }

            context.Step("Transform to while (condition) loop", loop);
            loop.Kind = ContainerKind.While;
            //invert comparison
            ifInstruction.Condition = Comp.LogicNot(ifInstruction.Condition);
            ifInstruction.FalseInst = ifInstruction.TrueInst;
            //move the rest of the body into a new block
            loopBody = ConditionDetection.ExtractBlock(loop.EntryPoint, 1, loop.EntryPoint.Instructions.Count);
            loop.Blocks.Insert(1, loopBody);
            if (!loopBody.HasFlag(InstructionFlags.EndPointUnreachable))
            {
                loopBody.Instructions.Add(new Leave(loop));
            }

            ifInstruction.TrueInst = new Branch(loopBody);
            ExpressionTransforms.RunOnSingleStatement(ifInstruction, context);

            // Analyze conditions and decide whether to move some of them out of the condition block:

            /*var conditions = new List<ILInstruction>();
             * SplitConditions(condition.Condition, conditions);
             * // Break apart conditions that could be a MoveNext call followed by a Current accessor call:
             * if (MightBeHeaderOfForEach(loop, conditions)) {
             *      ifInstruction.Condition = conditions[0];
             *      foreach (var cond in conditions.Skip(1).Reverse()) {
             *              IfInstruction inst;
             *              loopBody.Instructions.Insert(0, inst = new IfInstruction(Comp.LogicNot(cond), new Leave(loop)));
             *              ExpressionTransforms.RunOnSingleStatment(inst, context);
             *      }
             * }*/

            // Invert condition and unwrap nested block, if loop ends in a break or return statement preceeded by an IfInstruction.

            /*while (loopBody.Instructions.Last() is Leave leave && loopBody.Instructions.SecondToLastOrDefault() is IfInstruction nestedIf && nestedIf.FalseInst.MatchNop()) {
             *      switch (nestedIf.TrueInst) {
             *              case Block nestedBlock:
             *                      loopBody.Instructions.RemoveAt(leave.ChildIndex);
             *                      loopBody.Instructions.AddRange(nestedBlock.Instructions);
             *                      break;
             *              case Branch br:
             *                      leave.ReplaceWith(nestedIf.TrueInst);
             *                      break;
             *              default:
             *                      return true;
             *      }
             *      nestedIf.Condition = Comp.LogicNot(nestedIf.Condition);
             *      nestedIf.TrueInst = leave;
             *      ExpressionTransforms.RunOnSingleStatment(nestedIf, context);
             *      if (!loopBody.HasFlag(InstructionFlags.EndPointUnreachable))
             *              loopBody.Instructions.Add(new Leave(loop));
             * }*/
            return(true);
        }
Пример #2
0
        bool MatchWhileLoop(BlockContainer loop, out IfInstruction condition, out Block loopBody)
        {
            // ConditionDetection favours leave inside if and branch at end of block
            // while-loop:
            // if (!loop-condition) leave loop-container
            // ...
            condition = null;
            loopBody  = loop.EntryPoint;
            if (!(loopBody.Instructions[0] is IfInstruction ifInstruction))
            {
                return(false);
            }

            if (!ifInstruction.FalseInst.MatchNop())
            {
                return(false);
            }

            if (UsesVariableCapturedInLoop(loop, ifInstruction.Condition))
            {
                return(false);
            }

            condition = ifInstruction;
            if (!ifInstruction.TrueInst.MatchLeave(loop))
            {
                // sometimes the loop-body is nested within the if
                // if (loop-condition) { loop-body }
                // leave loop-container

                if (loopBody.Instructions.Count != 2 || !loop.EntryPoint.Instructions.Last().MatchLeave(loop))
                {
                    return(false);
                }

                if (!ifInstruction.TrueInst.HasFlag(InstructionFlags.EndPointUnreachable))
                {
                    ((Block)ifInstruction.TrueInst).Instructions.Add(new Leave(loop));
                }

                ConditionDetection.InvertIf(loopBody, ifInstruction, context);
            }

            context.Step("Transform to while (condition) loop", loop);
            loop.Kind = ContainerKind.While;
            //invert comparison
            ifInstruction.Condition = Comp.LogicNot(ifInstruction.Condition);
            ifInstruction.FalseInst = ifInstruction.TrueInst;
            //move the rest of the body into a new block
            loopBody = ConditionDetection.ExtractBlock(loop.EntryPoint, 1, loop.EntryPoint.Instructions.Count);
            loop.Blocks.Insert(1, loopBody);
            if (!loopBody.HasFlag(InstructionFlags.EndPointUnreachable))
            {
                loopBody.Instructions.Add(new Leave(loop));
            }

            ifInstruction.TrueInst = new Branch(loopBody);
            ExpressionTransforms.RunOnSingleStatement(ifInstruction, context);

            // Analyze conditions and decide whether to move some of them out of the condition block:

            /*var conditions = new List<ILInstruction>();
             * SplitConditions(condition.Condition, conditions);
             * // Break apart conditions that could be a MoveNext call followed by a Current accessor call:
             * if (MightBeHeaderOfForEach(loop, conditions)) {
             *      ifInstruction.Condition = conditions[0];
             *      foreach (var cond in conditions.Skip(1).Reverse()) {
             *              IfInstruction inst;
             *              loopBody.Instructions.Insert(0, inst = new IfInstruction(Comp.LogicNot(cond), new Leave(loop)));
             *              ExpressionTransforms.RunOnSingleStatment(inst, context);
             *      }
             * }*/

            return(true);
        }