Example #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;
                }
            }
            if (MatchInstruction.IsPatternMatch(inst.Condition, out _) &&
                inst.TrueInst.MatchLdcI4(1) && inst.FalseInst.MatchLdcI4(0))
            {
                context.Step("match(x) ? true : false -> match(x)", inst);
                inst.Condition.AddILRange(inst);
                inst.ReplaceWith(inst.Condition);
                return;
            }
        }
Example #2
0
        /// <summary>
        /// Inlines 'expr' into 'next', if possible.
        ///
        /// Note that this method does not check whether 'v' has only one use;
        /// the caller is expected to validate whether inlining 'v' has any effects on other uses of 'v'.
        /// </summary>
        static bool DoInline(ILVariable v, ILInstruction inlinedExpression, ILInstruction next, InliningOptions options, ILTransformContext context)
        {
            var r = FindLoadInNext(next, v, inlinedExpression, options);

            if (r.Type == FindResultType.Found || r.Type == FindResultType.NamedArgument)
            {
                var loadInst = r.LoadInst;
                if (loadInst.OpCode == OpCode.LdLoca)
                {
                    if (!IsGeneratedValueTypeTemporary((LdLoca)loadInst, v, inlinedExpression))
                    {
                        return(false);
                    }
                }
                else
                {
                    Debug.Assert(loadInst.OpCode == OpCode.LdLoc);
                    bool aggressive = (options & InliningOptions.Aggressive) != 0;
                    if (!aggressive && v.Kind != VariableKind.StackSlot &&
                        !NonAggressiveInlineInto(next, r, inlinedExpression, v))
                    {
                        return(false);
                    }
                }

                if (r.Type == FindResultType.NamedArgument)
                {
                    NamedArgumentTransform.IntroduceNamedArgument(r.CallArgument, context);
                    // Now that the argument is evaluated early, we can inline as usual
                }

                context.Step($"Inline variable '{v.Name}'", inlinedExpression);
                // Assign the ranges of the ldloc instruction:
                inlinedExpression.AddILRange(loadInst);

                if (loadInst.OpCode == OpCode.LdLoca)
                {
                    // it was an ldloca instruction, so we need to use the pseudo-opcode 'addressof'
                    // to preserve the semantics of the compiler-generated temporary
                    Debug.Assert(((LdLoca)loadInst).Variable == v);
                    loadInst.ReplaceWith(new AddressOf(inlinedExpression, v.Type));
                }
                else
                {
                    loadInst.ReplaceWith(inlinedExpression);
                }
                return(true);
            }
            return(false);
        }
Example #3
0
        /// <summary>
        /// Inlines 'expr' into 'next', if possible.
        ///
        /// Note that this method does not check whether 'v' has only one use;
        /// the caller is expected to validate whether inlining 'v' has any effects on other uses of 'v'.
        /// </summary>
        static bool DoInline(ILVariable v, ILInstruction inlinedExpression, ILInstruction next, InliningOptions options, ILTransformContext context)
        {
            var r = FindLoadInNext(next, v, inlinedExpression, out var loadInst);

            if (r == FindResult.Found)
            {
                if (loadInst.OpCode == OpCode.LdLoca)
                {
                    if (!IsGeneratedValueTypeTemporary(next, (LdLoca)loadInst, v, inlinedExpression))
                    {
                        return(false);
                    }
                }
                else
                {
                    Debug.Assert(loadInst.OpCode == OpCode.LdLoc);
                    bool aggressive = (options & InliningOptions.Aggressive) != 0;
                    if (!aggressive && v.Kind != VariableKind.StackSlot &&
                        !NonAggressiveInlineInto(next, loadInst, inlinedExpression, v))
                    {
                        return(false);
                    }
                }

                context.Step($"Inline variable '{v.Name}'", inlinedExpression);
                // Assign the ranges of the ldloc instruction:
                inlinedExpression.AddILRange(loadInst.ILRange);

                if (loadInst.OpCode == OpCode.LdLoca)
                {
                    // it was an ldloca instruction, so we need to use the pseudo-opcode 'addressof'
                    // to preserve the semantics of the compiler-generated temporary
                    loadInst.ReplaceWith(new AddressOf(inlinedExpression));
                }
                else
                {
                    loadInst.ReplaceWith(inlinedExpression);
                }
                return(true);
            }
            else if (r == FindResult.NamedArgument && (options & InliningOptions.IntroduceNamedArguments) != 0)
            {
                return(NamedArgumentTransform.DoInline(v, (StLoc)inlinedExpression.Parent, (LdLoc)loadInst,
                                                       options, context));
            }
            return(false);
        }
Example #4
0
        /// <summary>
        /// Inlines 'expr' into 'next', if possible.
        ///
        /// Note that this method does not check whether 'v' has only one use;
        /// the caller is expected to validate whether inlining 'v' has any effects on other uses of 'v'.
        /// </summary>
        static bool DoInline(ILVariable v, ILInstruction inlinedExpression, ILInstruction next, bool aggressive, ILTransformContext context)
        {
            ILInstruction loadInst;

            if (FindLoadInNext(next, v, inlinedExpression, out loadInst) == true)
            {
                if (loadInst.OpCode == OpCode.LdLoca)
                {
                    if (!IsGeneratedValueTypeTemporary(next, loadInst.Parent, loadInst.ChildIndex, v, inlinedExpression))
                    {
                        return(false);
                    }
                }
                else
                {
                    Debug.Assert(loadInst.OpCode == OpCode.LdLoc);
                    if (!aggressive && v.Kind != VariableKind.StackSlot && !NonAggressiveInlineInto(next, loadInst, inlinedExpression, v))
                    {
                        return(false);
                    }
                }

                context.Step($"Inline variable '{v.Name}'", inlinedExpression);
                // Assign the ranges of the ldloc instruction:
                inlinedExpression.AddILRange(loadInst.ILRange);

                if (loadInst.OpCode == OpCode.LdLoca)
                {
                    // it was an ldloca instruction, so we need to use the pseudo-opcode 'addressof'
                    // to preserve the semantics of the compiler-generated temporary
                    loadInst.ReplaceWith(new AddressOf(inlinedExpression));
                }
                else
                {
                    loadInst.ReplaceWith(inlinedExpression);
                }
                return(true);
            }
            return(false);
        }