コード例 #1
0
ファイル: TransformAssignment.cs プロジェクト: ozzyince/ILSpy
        /// <code>
        /// stloc s(ldobj(ldsflda))
        /// stobj (ldsflda, binary.op(ldloc s, ldc.i4 1))
        /// -->
        /// stloc s(compound.op.old(ldobj(ldsflda), ldc.i4 1))
        /// </code>
        bool TransformPostIncDecOnStaticField(Block block, int i)
        {
            var inst  = block.Instructions[i] as StLoc;
            var stobj = block.Instructions.ElementAtOrDefault(i + 1) as StObj;

            if (inst == null || stobj == null)
            {
                return(false);
            }
            ILInstruction target;
            IType         type;
            IField        field, field2;

            if (inst.Variable.Kind != VariableKind.StackSlot || !inst.Value.MatchLdObj(out target, out type) || !target.MatchLdsFlda(out field))
            {
                return(false);
            }
            if (!stobj.Target.MatchLdsFlda(out field2) || !IsSameMember(field, field2))
            {
                return(false);
            }
            var binary = stobj.Value as BinaryNumericInstruction;

            if (binary == null || !binary.Left.MatchLdLoc(inst.Variable) || !binary.Right.MatchLdcI4(1))
            {
                return(false);
            }
            context.Step($"TransformPostIncDecOnStaticField", inst);
            var assignment = new CompoundAssignmentInstruction(binary, inst.Value, binary.Right, type, CompoundAssignmentType.EvaluatesToOldValue);

            stobj.ReplaceWith(new StLoc(inst.Variable, assignment));
            return(true);
        }
コード例 #2
0
        /// <summary>
        /// Transform compound assignments where the return value is not being used,
        /// or where there's an inlined assignment within the setter call.
        /// </summary>
        /// <remarks>
        /// Called by ExpressionTransforms.
        /// </remarks>
        internal static bool HandleCallCompoundAssign(CallInstruction setterCall, StatementTransformContext context)
        {
            // callvirt set_Property(ldloc S_1, binary.op(callvirt get_Property(ldloc S_1), value))
            // ==> compound.op.new(callvirt get_Property(ldloc S_1), value)
            var setterValue   = setterCall.Arguments.LastOrDefault();
            var storeInSetter = setterValue as StLoc;

            if (storeInSetter != null)
            {
                // callvirt set_Property(ldloc S_1, stloc v(binary.op(callvirt get_Property(ldloc S_1), value)))
                // ==> stloc v(compound.op.new(callvirt get_Property(ldloc S_1), value))
                setterValue = storeInSetter.Value;
            }
            setterValue = UnwrapSmallIntegerConv(setterValue, out var conv);
            if (!(setterValue is BinaryNumericInstruction binary))
            {
                return(false);
            }
            var getterCall = binary.Left as CallInstruction;

            if (!MatchingGetterAndSetterCalls(getterCall, setterCall))
            {
                return(false);
            }
            IType targetType = getterCall.Method.ReturnType;

            if (!ValidateCompoundAssign(binary, conv, targetType))
            {
                return(false);
            }
            if (storeInSetter != null && storeInSetter.Variable.Type.IsSmallIntegerType())
            {
                // 'stloc v' implicitly truncates.
                // Ensure that type of 'v' must match type of the property:
                if (storeInSetter.Variable.Type.GetSize() != targetType.GetSize())
                {
                    return(false);
                }
                if (storeInSetter.Variable.Type.GetSign() != targetType.GetSign())
                {
                    return(false);
                }
            }
            context.Step($"Compound assignment to '{getterCall.Method.AccessorOwner.Name}'", setterCall);
            ILInstruction newInst = new CompoundAssignmentInstruction(
                binary, getterCall, binary.Right,
                getterCall.Method.ReturnType, CompoundAssignmentType.EvaluatesToNewValue);

            if (storeInSetter != null)
            {
                storeInSetter.Value = newInst;
                newInst             = storeInSetter;
                context.RequestRerun();                 // moving stloc to top-level might trigger inlining
            }
            setterCall.ReplaceWith(newInst);
            return(true);
        }
コード例 #3
0
 static bool ValidateCompoundAssign(BinaryNumericInstruction binary, Conv conv, IType targetType)
 {
     if (!CompoundAssignmentInstruction.IsBinaryCompatibleWithType(binary, targetType))
     {
         return(false);
     }
     if (conv != null && !(conv.TargetType == targetType.ToPrimitiveType() && conv.CheckForOverflow == binary.CheckForOverflow))
     {
         return(false);                // conv does not match binary operation
     }
     return(true);
 }
コード例 #4
0
ファイル: TransformAssignment.cs プロジェクト: ozzyince/ILSpy
        /// <code>
        /// stloc s(binary(callvirt(getter), value))
        /// callvirt (setter, ldloc s)
        /// (followed by single usage of s in next instruction)
        /// -->
        /// stloc s(compound.op.new(callvirt(getter), value))
        /// </code>
        bool TransformInlineCompoundAssignmentCall(Block block, int i)
        {
            var mainStLoc = block.Instructions[i] as StLoc;

            // in some cases it can be a compiler-generated local
            if (mainStLoc == null || (mainStLoc.Variable.Kind != VariableKind.StackSlot && mainStLoc.Variable.Kind != VariableKind.Local))
            {
                return(false);
            }
            BinaryNumericInstruction binary = mainStLoc.Value as BinaryNumericInstruction;
            ILVariable localVariable        = mainStLoc.Variable;

            if (!localVariable.IsSingleDefinition)
            {
                return(false);
            }
            if (localVariable.LoadCount != 2)
            {
                return(false);
            }
            var getterCall = binary?.Left as CallInstruction;
            var setterCall = block.Instructions.ElementAtOrDefault(i + 1) as CallInstruction;

            if (!MatchingGetterAndSetterCalls(getterCall, setterCall))
            {
                return(false);
            }
            if (!setterCall.Arguments.Last().MatchLdLoc(localVariable))
            {
                return(false);
            }

            var next = block.Instructions.ElementAtOrDefault(i + 2);

            if (next == null)
            {
                return(false);
            }
            if (next.Descendants.Where(d => d.MatchLdLoc(localVariable)).Count() != 1)
            {
                return(false);
            }
            if (!CompoundAssignmentInstruction.IsBinaryCompatibleWithType(binary, getterCall.Method.ReturnType))
            {
                return(false);
            }
            context.Step($"Inline compound assignment to '{getterCall.Method.AccessorOwner.Name}'", setterCall);
            block.Instructions.RemoveAt(i + 1);             // remove setter call
            binary.ReplaceWith(new CompoundAssignmentInstruction(
                                   binary, getterCall, binary.Right,
                                   getterCall.Method.ReturnType, CompoundAssignmentType.EvaluatesToNewValue));
            return(true);
        }
コード例 #5
0
        /// ldaddress ::= ldelema | ldflda | ldsflda;
        /// <code>
        /// stloc s(ldaddress)
        /// stloc l(ldobj(ldloc s))
        /// stobj(ldloc s, binary.op(ldloc l, ldc.i4 1))
        /// -->
        /// stloc l(compound.op.old(ldobj(ldaddress), ldc.i4 1))
        /// </code>
        bool TransformPostIncDecOperatorOnAddress(Block block, int i)
        {
            var inst     = block.Instructions[i] as StLoc;
            var nextInst = block.Instructions.ElementAtOrDefault(i + 1) as StLoc;
            var stobj    = block.Instructions.ElementAtOrDefault(i + 2) as StObj;

            if (inst == null || nextInst == null || stobj == null)
            {
                return(false);
            }
            if (!(inst.Value is LdElema || inst.Value is LdFlda || inst.Value is LdsFlda))
            {
                return(false);
            }
            ILInstruction target;
            IType         targetType;

            if (nextInst.Variable.Kind == VariableKind.StackSlot || !nextInst.Value.MatchLdObj(out target, out targetType) || !target.MatchLdLoc(inst.Variable))
            {
                return(false);
            }
            if (!stobj.Target.MatchLdLoc(inst.Variable))
            {
                return(false);
            }
            var binary = stobj.Value as BinaryNumericInstruction;

            if (binary == null || !binary.Left.MatchLdLoc(nextInst.Variable) || !binary.Right.MatchLdcI4(1) ||
                (binary.Operator != BinaryNumericOperator.Add && binary.Operator != BinaryNumericOperator.Sub))
            {
                return(false);
            }
            if (binary.IsLifted)
            {
                return(false);
            }
            context.Step($"TransformPostIncDecOperator", inst);
            var assignment = new CompoundAssignmentInstruction(binary.Operator, new LdObj(inst.Value, targetType), binary.Right, targetType, binary.CheckForOverflow, binary.Sign, CompoundAssignmentType.EvaluatesToOldValue);

            stobj.ReplaceWith(new StLoc(nextInst.Variable, assignment));
            block.Instructions.RemoveAt(i + 1);
            return(true);
        }
コード例 #6
0
ファイル: TransformAssignment.cs プロジェクト: ozzyince/ILSpy
        /// <summary>
        /// Transform compound assignments where the return value is not being used,
        /// or where there's an inlined assignment within the setter call.
        /// </summary>
        /// <remarks>
        /// Called by ExpressionTransforms.
        /// </remarks>
        internal static bool HandleCallCompoundAssign(CallInstruction setterCall, StatementTransformContext context)
        {
            // callvirt set_Property(ldloc S_1, binary.op(callvirt get_Property(ldloc S_1), value))
            // ==> compound.op.new(callvirt(callvirt get_Property(ldloc S_1)), value)
            var setterValue   = setterCall.Arguments.LastOrDefault();
            var storeInSetter = setterValue as StLoc;

            if (storeInSetter != null)
            {
                // callvirt set_Property(ldloc S_1, stloc v(binary.op(callvirt get_Property(ldloc S_1), value)))
                // ==> stloc v(compound.op.new(callvirt(callvirt get_Property(ldloc S_1)), value))
                setterValue = storeInSetter.Value;
            }
            if (!(setterValue is BinaryNumericInstruction binary))
            {
                return(false);
            }
            var getterCall = binary.Left as CallInstruction;

            if (!MatchingGetterAndSetterCalls(getterCall, setterCall))
            {
                return(false);
            }
            if (!CompoundAssignmentInstruction.IsBinaryCompatibleWithType(binary, getterCall.Method.ReturnType))
            {
                return(false);
            }
            context.Step($"Compound assignment to '{getterCall.Method.AccessorOwner.Name}'", setterCall);
            ILInstruction newInst = new CompoundAssignmentInstruction(
                binary, getterCall, binary.Right,
                getterCall.Method.ReturnType, CompoundAssignmentType.EvaluatesToNewValue);

            if (storeInSetter != null)
            {
                storeInSetter.Value = newInst;
                newInst             = storeInSetter;
                context.RequestRerun();                 // moving stloc to top-level might trigger inlining
            }
            setterCall.ReplaceWith(newInst);
            return(true);
        }
コード例 #7
0
        protected internal override void VisitStObj(StObj inst)
        {
            base.VisitStObj(inst);
            if (EarlyExpressionTransforms.StObjToStLoc(inst, context))
            {
                context.RequestRerun();
                return;
            }

            if (inst.Value is BinaryNumericInstruction binary &&
                binary.Left.MatchLdObj(out ILInstruction target, out IType t) &&
                inst.Target.Match(target).Success &&
                SemanticHelper.IsPure(target.Flags) &&
                CompoundAssignmentInstruction.IsBinaryCompatibleWithType(binary, t))
            {
                context.Step("compound assignment", inst);
                // stobj(target, binary.op(ldobj(target), ...))
                // => compound.op(target, ...)
                inst.ReplaceWith(new CompoundAssignmentInstruction(
                                     binary, binary.Left, binary.Right,
                                     t, CompoundAssignmentType.EvaluatesToNewValue));
            }
        }
コード例 #8
0
ファイル: TransformAssignment.cs プロジェクト: ozzyince/ILSpy
        /// <summary>
        /// Roslyn compound assignment that's not inline within another instruction.
        /// </summary>
        bool TransformRoslynCompoundAssignmentCall(Block block, int i)
        {
            // stloc variable(callvirt get_Property(ldloc obj))
            // callvirt set_Property(ldloc obj, binary.op(ldloc variable, ldc.i4 1))
            // => compound.op.new(callvirt get_Property(ldloc obj), ldc.i4 1)
            if (!(block.Instructions[i] is StLoc stloc))
            {
                return(false);
            }
            if (!(stloc.Variable.IsSingleDefinition && stloc.Variable.LoadCount == 1))
            {
                return(false);
            }
            var getterCall = stloc.Value as CallInstruction;
            var setterCall = block.Instructions[i + 1] as CallInstruction;

            if (!(MatchingGetterAndSetterCalls(getterCall, setterCall)))
            {
                return(false);
            }
            var binary = setterCall.Arguments.Last() as BinaryNumericInstruction;

            if (binary == null || !binary.Left.MatchLdLoc(stloc.Variable))
            {
                return(false);
            }
            if (!CompoundAssignmentInstruction.IsBinaryCompatibleWithType(binary, getterCall.Method.ReturnType))
            {
                return(false);
            }
            context.Step($"Compound assignment to '{getterCall.Method.AccessorOwner.Name}'", setterCall);
            block.Instructions.RemoveAt(i + 1);             // remove setter call
            stloc.ReplaceWith(new CompoundAssignmentInstruction(
                                  binary, getterCall, binary.Right,
                                  getterCall.Method.ReturnType, CompoundAssignmentType.EvaluatesToNewValue));
            return(true);
        }
コード例 #9
0
ファイル: TransformAssignment.cs プロジェクト: ozzyince/ILSpy
        /// <code>
        /// stloc s(ldflda)
        /// stloc s2(ldobj(ldflda(ldloc s)))
        /// stloc l(ldloc s2)
        /// stobj (ldflda(ldloc s), binary.add(ldloc s2, ldc.i4 1))
        /// -->
        /// stloc l(compound.op.old(ldobj(ldflda(ldflda)), ldc.i4 1))
        /// </code>
        bool TransformCSharp4PostIncDecOperatorOnAddress(Block block, int i)
        {
            var baseFieldAddress      = block.Instructions[i] as StLoc;
            var fieldValue            = block.Instructions.ElementAtOrDefault(i + 1) as StLoc;
            var fieldValueCopyToLocal = block.Instructions.ElementAtOrDefault(i + 2) as StLoc;
            var stobj = block.Instructions.ElementAtOrDefault(i + 3) as StObj;

            if (baseFieldAddress == null || fieldValue == null || fieldValueCopyToLocal == null || stobj == null)
            {
                return(false);
            }
            if (baseFieldAddress.Variable.Kind != VariableKind.StackSlot || fieldValue.Variable.Kind != VariableKind.StackSlot || fieldValueCopyToLocal.Variable.Kind != VariableKind.Local)
            {
                return(false);
            }
            IType         t;
            IField        targetField;
            ILInstruction targetFieldLoad, baseFieldAddressLoad2;

            if (!fieldValue.Value.MatchLdObj(out targetFieldLoad, out t))
            {
                return(false);
            }
            ILInstruction baseAddress;

            if (baseFieldAddress.Value is LdFlda)
            {
                IField        targetField2;
                ILInstruction baseFieldAddressLoad3;
                if (!targetFieldLoad.MatchLdFlda(out baseFieldAddressLoad2, out targetField) || !baseFieldAddressLoad2.MatchLdLoc(baseFieldAddress.Variable))
                {
                    return(false);
                }
                if (!stobj.Target.MatchLdFlda(out baseFieldAddressLoad3, out targetField2) || !baseFieldAddressLoad3.MatchLdLoc(baseFieldAddress.Variable) || !IsSameMember(targetField, targetField2))
                {
                    return(false);
                }
                baseAddress = new LdFlda(baseFieldAddress.Value, targetField);
            }
            else if (baseFieldAddress.Value is LdElema)
            {
                if (!targetFieldLoad.MatchLdLoc(baseFieldAddress.Variable) || !stobj.Target.MatchLdLoc(baseFieldAddress.Variable))
                {
                    return(false);
                }
                baseAddress = baseFieldAddress.Value;
            }
            else
            {
                return(false);
            }
            BinaryNumericInstruction binary = stobj.Value as BinaryNumericInstruction;

            if (binary == null || !binary.Left.MatchLdLoc(fieldValue.Variable) || !binary.Right.MatchLdcI4(1) ||
                (binary.Operator != BinaryNumericOperator.Add && binary.Operator != BinaryNumericOperator.Sub))
            {
                return(false);
            }
            context.Step($"TransformCSharp4PostIncDecOperatorOnAddress", baseFieldAddress);
            var assignment = new CompoundAssignmentInstruction(binary, new LdObj(baseAddress, t), binary.Right, t, CompoundAssignmentType.EvaluatesToOldValue);

            stobj.ReplaceWith(new StLoc(fieldValueCopyToLocal.Variable, assignment));
            block.Instructions.RemoveAt(i + 2);
            block.Instructions.RemoveAt(i + 1);
            return(true);
        }