Пример #1
0
        protected internal override void VisitIfInstruction(IfInstruction inst)
        {
            inst.TrueInst.AcceptVisitor(this);
            inst.FalseInst.AcceptVisitor(this);
            inst = HandleConditionalOperator(inst);

            // Bring LogicAnd/LogicOr into their canonical forms:
            // if (cond) ldc.i4 0 else RHS --> if (!cond) RHS else ldc.i4 0
            // if (cond) RHS else ldc.i4 1 --> if (!cond) ldc.i4 1 else RHS
            // Be careful: when both LHS and RHS are the constant 1, we must not
            // swap the arguments as it would lead to an infinite transform loop.
            if (inst.TrueInst.MatchLdcI4(0) && !inst.FalseInst.MatchLdcI4(0) ||
                inst.FalseInst.MatchLdcI4(1) && !inst.TrueInst.MatchLdcI4(1))
            {
                context.Step("canonicalize logic and/or", inst);
                var t = inst.TrueInst;
                inst.TrueInst  = inst.FalseInst;
                inst.FalseInst = t;
                inst.Condition = Comp.LogicNot(inst.Condition);
            }
            // Process condition after our potential modifications.
            inst.Condition.AcceptVisitor(this);

            if (new NullableLiftingTransform(context).Run(inst))
            {
                return;
            }

            if (TransformDynamicAddAssignOrRemoveAssign(inst))
            {
                return;
            }
            if (inst.MatchIfInstructionPositiveCondition(out var condition, out var trueInst, out var falseInst))
            {
                ILInstruction transformed = UserDefinedLogicTransform.Transform(condition, trueInst, falseInst);
                if (transformed == null)
                {
                    transformed = UserDefinedLogicTransform.TransformDynamic(condition, trueInst, falseInst);
                }
                if (transformed != null)
                {
                    context.Step("User-defined short-circuiting logic operator (roslyn pattern)", condition);
                    transformed.AddILRange(inst);
                    inst.ReplaceWith(transformed);
                    return;
                }
            }
        }
        /// <summary>
        /// if (comp(ldloc v == ldnull)) {
        ///     stloc v(DelegateConstruction)
        /// }
        /// =>
        /// stloc v(DelegateConstruction)
        /// </summary>
        bool CachedDelegateInitializationWithLocal(IfInstruction inst)
        {
            Block trueInst = inst.TrueInst as Block;

            if (trueInst == null || (trueInst.Instructions.Count != 1) || !inst.FalseInst.MatchNop())
            {
                return(false);
            }
            if (!inst.Condition.MatchCompEquals(out ILInstruction left, out ILInstruction right) || !left.MatchLdLoc(out ILVariable v) || !right.MatchLdNull())
            {
                return(false);
            }
            var storeInst = trueInst.Instructions.Last();

            if (!storeInst.MatchStLoc(v, out ILInstruction value))
            {
                return(false);
            }
            if (!DelegateConstruction.IsDelegateConstruction(value as NewObj, true))
            {
                return(false);
            }
            // do not transform if there are other stores/loads of this variable
            if (v.StoreCount != 2 || v.LoadCount != 2 || v.AddressCount != 0)
            {
                return(false);
            }
            // do not transform if there is no usage directly aftewards
            var nextInstruction = inst.Parent.Children.ElementAtOrDefault(inst.ChildIndex + 1);

            if (nextInstruction == null)
            {
                return(false);
            }
            var usages = nextInstruction.Descendants.Where(i => i.MatchLdLoc(v)).ToArray();

            if (usages.Length != 1)
            {
                return(false);
            }
            context.Step("CachedDelegateInitializationWithLocal", inst);
            inst.ReplaceWith(new StLoc(v, value));
            return(true);
        }
Пример #3
0
        protected internal override void VisitIfInstruction(IfInstruction inst)
        {
            // Bring LogicAnd/LogicOr into their canonical forms:
            // if (cond) ldc.i4 0 else RHS --> if (!cond) RHS else ldc.i4 0
            // if (cond) RHS else ldc.i4 1 --> if (!cond) ldc.i4 1 else RHS
            // Be careful: when both LHS and RHS are the constant 1, we must not
            // swap the arguments as it would lead to an infinite transform loop.
            if (inst.TrueInst.MatchLdcI4(0) && !inst.FalseInst.MatchLdcI4(0) ||
                inst.FalseInst.MatchLdcI4(1) && !inst.TrueInst.MatchLdcI4(1))
            {
                context.Step("canonicalize logic and/or", inst);
                var t = inst.TrueInst;
                inst.TrueInst  = inst.FalseInst;
                inst.FalseInst = t;
                inst.Condition = new LogicNot(inst.Condition);
            }

            base.VisitIfInstruction(inst);

            // if (cond) stloc (A, V1) else stloc (A, V2) --> stloc (A, if (cond) V1 else V2)
            Block trueInst = inst.TrueInst as Block;

            if (trueInst == null || trueInst.Instructions.Count != 1)
            {
                return;
            }
            Block falseInst = inst.FalseInst as Block;

            if (falseInst == null || falseInst.Instructions.Count != 1)
            {
                return;
            }
            ILVariable    v;
            ILInstruction value1, value2;

            if (trueInst.Instructions[0].MatchStLoc(out v, out value1) && falseInst.Instructions[0].MatchStLoc(v, out value2))
            {
                context.Step("conditional operator", inst);
                inst.ReplaceWith(new StLoc(v, new IfInstruction(new LogicNot(inst.Condition), value2, value1)));
            }
        }
Пример #4
0
        /// <summary>
        /// op is either add or remove/subtract:
        /// if (dynamic.isevent (target)) {
        ///     dynamic.invokemember.invokespecial.discard op_Name(target, value)
        /// } else {
        ///     dynamic.compound.op (dynamic.getmember Name(target), value)
        /// }
        /// =>
        /// dynamic.compound.op (dynamic.getmember Name(target), value)
        /// </summary>
        bool TransformDynamicAddAssignOrRemoveAssign(IfInstruction inst)
        {
            if (!inst.MatchIfInstructionPositiveCondition(out var condition, out var trueInst, out var falseInst))
            {
                return(false);
            }
            if (!(condition is DynamicIsEventInstruction isEvent))
            {
                return(false);
            }
            trueInst  = Block.Unwrap(trueInst);
            falseInst = Block.Unwrap(falseInst);
            if (!(falseInst is DynamicCompoundAssign dynamicCompoundAssign))
            {
                return(false);
            }
            if (!(dynamicCompoundAssign.Target is DynamicGetMemberInstruction getMember))
            {
                return(false);
            }
            if (!SemanticHelper.IsPure(isEvent.Argument.Flags))
            {
                return(false);
            }
            if (!isEvent.Argument.Match(getMember.Target).Success)
            {
                return(false);
            }
            if (!(trueInst is DynamicInvokeMemberInstruction invokeMember))
            {
                return(false);
            }
            if (!(invokeMember.BinderFlags.HasFlag(CSharpBinderFlags.InvokeSpecialName) && invokeMember.BinderFlags.HasFlag(CSharpBinderFlags.ResultDiscarded)))
            {
                return(false);
            }
            switch (dynamicCompoundAssign.Operation)
            {
            case ExpressionType.AddAssign:
                if (invokeMember.Name != "add_" + getMember.Name)
                {
                    return(false);
                }
                break;

            case ExpressionType.SubtractAssign:
                if (invokeMember.Name != "remove_" + getMember.Name)
                {
                    return(false);
                }
                break;

            default:
                return(false);
            }
            if (!dynamicCompoundAssign.Value.Match(invokeMember.Arguments[1]).Success)
            {
                return(false);
            }
            if (!invokeMember.Arguments[0].Match(getMember.Target).Success)
            {
                return(false);
            }
            context.Step("+= / -= dynamic.isevent pattern -> dynamic.compound.op", inst);
            inst.ReplaceWith(dynamicCompoundAssign);
            return(true);
        }
Пример #5
0
        bool MatchForLoop(BlockContainer loop, IfInstruction whileCondition, Block whileLoopBody)
        {
            // for loops have exactly two incoming edges at the entry point.
            if (loop.EntryPoint.IncomingEdgeCount != 2)
            {
                return(false);
            }
            // try to find an increment block:
            // consists of simple statements only.
            var incrementBlock = GetIncrementBlock(loop, whileLoopBody);

            if (incrementBlock != null)
            {
                // we found a possible increment block, just make sure, that there are at least three blocks:
                // - condition block
                // - loop body
                // - increment block
                if (incrementBlock.Instructions.Count <= 1 || loop.Blocks.Count < 3)
                {
                    return(false);
                }
                context.Step("Transform to for loop", loop);
                // move the block to the end of the loop:
                loop.Blocks.MoveElementToEnd(incrementBlock);
                loop.Kind = ContainerKind.For;
            }
            else
            {
                // we need to move the increment statements into its own block:
                // last must be a branch entry-point
                var last         = whileLoopBody.Instructions.LastOrDefault();
                var secondToLast = whileLoopBody.Instructions.SecondToLastOrDefault();
                if (last == null || secondToLast == null)
                {
                    return(false);
                }
                if (!last.MatchBranch(loop.EntryPoint))
                {
                    return(false);
                }
                // we only deal with 'numeric' increments
                if (!MatchIncrement(secondToLast, out var incrementVariable))
                {
                    return(false);
                }
                // the increment variable must be local/stack variable
                if (incrementVariable.Kind == VariableKind.Parameter)
                {
                    return(false);
                }
                // split conditions:
                var conditions = new List <ILInstruction>();
                SplitConditions(whileCondition.Condition, conditions);
                IfInstruction forCondition       = null;
                int           numberOfConditions = 0;
                foreach (var condition in conditions)
                {
                    // the increment variable must be used in the condition
                    if (!condition.Descendants.Any(inst => inst.MatchLdLoc(incrementVariable)))
                    {
                        break;
                    }
                    // condition should not contain an assignment
                    if (condition.Descendants.Any(IsAssignment))
                    {
                        break;
                    }
                    if (forCondition == null)
                    {
                        forCondition = new IfInstruction(condition, whileCondition.TrueInst, whileCondition.FalseInst);
                    }
                    else
                    {
                        forCondition.Condition = IfInstruction.LogicAnd(forCondition.Condition, condition);
                    }
                    numberOfConditions++;
                }
                if (numberOfConditions == 0)
                {
                    return(false);
                }
                context.Step("Transform to for loop", loop);
                // split condition block:
                whileCondition.ReplaceWith(forCondition);
                ExpressionTransforms.RunOnSingleStatement(forCondition, context);
                for (int i = conditions.Count - 1; i >= numberOfConditions; i--)
                {
                    IfInstruction inst;
                    whileLoopBody.Instructions.Insert(0, inst = new IfInstruction(Comp.LogicNot(conditions[i]), new Leave(loop)));
                    ExpressionTransforms.RunOnSingleStatement(inst, context);
                }
                // create a new increment block and add it at the end:
                int secondToLastIndex = secondToLast.ChildIndex;
                var newIncremenBlock  = new Block();
                loop.Blocks.Add(newIncremenBlock);
                // move the increment instruction:
                newIncremenBlock.Instructions.Add(secondToLast);
                newIncremenBlock.Instructions.Add(last);
                newIncremenBlock.AddILRange(secondToLast.ILRange);
                whileLoopBody.Instructions.RemoveRange(secondToLastIndex, 2);
                whileLoopBody.Instructions.Add(new Branch(newIncremenBlock));
                // complete transform.
                loop.Kind = ContainerKind.For;
            }
            return(true);
        }