Browse Source

Basic implementation of CompoundAssignmentInstruction

pull/734/head
Siegfried Pammer 9 years ago
parent
commit
ae75c57e22
  1. 99
      ICSharpCode.Decompiler/CSharp/ExpressionBuilder.cs
  2. 1
      ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj
  3. 89
      ICSharpCode.Decompiler/IL/Instructions.cs
  4. 3
      ICSharpCode.Decompiler/IL/Instructions.tt
  5. 31
      ICSharpCode.Decompiler/IL/Instructions/BinaryNumericInstruction.cs
  6. 150
      ICSharpCode.Decompiler/IL/Instructions/CompoundAssignmentInstruction.cs
  7. 15
      ICSharpCode.Decompiler/IL/Instructions/PatternMatching.cs
  8. 18
      ICSharpCode.Decompiler/IL/Transforms/ExpressionTransforms.cs
  9. 16
      ICSharpCode.Decompiler/Tests/TestCases/Pretty/CompoundAssignmentTest.cs
  10. 100
      ICSharpCode.Decompiler/Tests/TestCases/Pretty/CompoundAssignmentTest.il

99
ICSharpCode.Decompiler/CSharp/ExpressionBuilder.cs

@ -597,6 +597,101 @@ namespace ICSharpCode.Decompiler.CSharp @@ -597,6 +597,101 @@ namespace ICSharpCode.Decompiler.CSharp
return result;
}
protected internal override TranslatedExpression VisitCompoundAssignmentInstruction(CompoundAssignmentInstruction inst)
{
switch (inst.Operator) {
case BinaryNumericOperator.Add:
return HandleCompoundAssigment(inst, AssignmentOperatorType.Add);
case BinaryNumericOperator.Sub:
return HandleCompoundAssigment(inst, AssignmentOperatorType.Subtract);
case BinaryNumericOperator.Mul:
return HandleCompoundAssigment(inst, AssignmentOperatorType.Multiply);
case BinaryNumericOperator.Div:
return HandleCompoundAssigment(inst, AssignmentOperatorType.Divide);
case BinaryNumericOperator.Rem:
return HandleCompoundAssigment(inst, AssignmentOperatorType.Modulus);
case BinaryNumericOperator.BitAnd:
return HandleCompoundAssigment(inst, AssignmentOperatorType.BitwiseAnd);
case BinaryNumericOperator.BitOr:
return HandleCompoundAssigment(inst, AssignmentOperatorType.BitwiseOr);
case BinaryNumericOperator.BitXor:
return HandleCompoundAssigment(inst, AssignmentOperatorType.ExclusiveOr);
case BinaryNumericOperator.ShiftLeft:
return HandleCompoundShift(inst, AssignmentOperatorType.ShiftLeft);
case BinaryNumericOperator.ShiftRight:
return HandleCompoundShift(inst, AssignmentOperatorType.ShiftRight);
default:
throw new ArgumentOutOfRangeException();
}
}
TranslatedExpression HandleCompoundAssigment(CompoundAssignmentInstruction inst, AssignmentOperatorType op)
{
var resolverWithOverflowCheck = resolver.WithCheckForOverflow(inst.CheckForOverflow);
var target = Translate(inst.Target);
var value = Translate(inst.Value);
value = PrepareArithmeticArgument(value, inst.Value.ResultType, inst.Sign);
var rr = resolverWithOverflowCheck.ResolveAssignment(op, target.ResolveResult, value.ResolveResult);
if (rr.IsError || rr.Type.GetStackType() != inst.ResultType
|| !IsCompatibleWithSign(target.Type, inst.Sign) || !IsCompatibleWithSign(value.Type, inst.Sign))
{
// Target and value are incompatible, so convert value to the target type
// inst.ResultType should match inst.Target.ResultType
Debug.Assert(inst.ResultType == inst.Target.ResultType);
StackType targetStackType = inst.ResultType == StackType.I ? StackType.I8 : inst.ResultType;
IType targetType = compilation.FindType(targetStackType.ToKnownTypeCode(inst.Sign));
value = value.ConvertTo(targetType, this);
rr = resolverWithOverflowCheck.ResolveAssignment(op, target.ResolveResult, value.ResolveResult);
}
var resultExpr = new AssignmentExpression(target.Expression, op, value.Expression)
.WithILInstruction(inst)
.WithRR(rr);
if (AssignmentOperatorMightCheckForOverflow(op))
resultExpr.Expression.AddAnnotation(inst.CheckForOverflow ? AddCheckedBlocks.CheckedAnnotation : AddCheckedBlocks.UncheckedAnnotation);
return resultExpr;
}
TranslatedExpression HandleCompoundShift(CompoundAssignmentInstruction inst, AssignmentOperatorType op)
{
var target = Translate(inst.Target);
var value = Translate(inst.Value);
IType targetType;
if (inst.ResultType == StackType.I4)
targetType = compilation.FindType(inst.Sign == Sign.Unsigned ? KnownTypeCode.UInt32 : KnownTypeCode.Int32);
else
targetType = compilation.FindType(inst.Sign == Sign.Unsigned ? KnownTypeCode.UInt64 : KnownTypeCode.Int64);
target = target.ConvertTo(targetType, this);
// Shift operators in C# always expect type 'int' on the right-hand-side
value = value.ConvertTo(compilation.FindType(KnownTypeCode.Int32), this);
TranslatedExpression result = new AssignmentExpression(target.Expression, op, value.Expression)
.WithILInstruction(inst)
.WithRR(resolver.ResolveAssignment(op, target.ResolveResult, value.ResolveResult));
if (inst.ResultType == StackType.I) {
// C# doesn't have shift operators for IntPtr, so we first shifted a long/ulong,
// and now have to case back down to IntPtr/UIntPtr:
result = result.ConvertTo(compilation.FindType(inst.Sign == Sign.Unsigned ? KnownTypeCode.UIntPtr : KnownTypeCode.IntPtr), this);
}
return result;
}
static bool AssignmentOperatorMightCheckForOverflow(AssignmentOperatorType op)
{
switch (op) {
case AssignmentOperatorType.BitwiseAnd:
case AssignmentOperatorType.BitwiseOr:
case AssignmentOperatorType.ExclusiveOr:
case AssignmentOperatorType.ShiftLeft:
case AssignmentOperatorType.ShiftRight:
return false;
default:
return true;
}
}
protected internal override TranslatedExpression VisitConv(Conv inst)
{
var arg = Translate(inst.Argument);
@ -1050,12 +1145,12 @@ namespace ICSharpCode.Decompiler.CSharp @@ -1050,12 +1145,12 @@ namespace ICSharpCode.Decompiler.CSharp
// {
// return Assignment(ConvertField(inst.Field, inst.Target).WithoutILInstruction(), Translate(inst.Value)).WithILInstruction(inst);
// }
//
//
// protected internal override TranslatedExpression VisitLdsFld(LdsFld inst)
// {
// return ConvertField(inst.Field).WithILInstruction(inst);
// }
//
//
// protected internal override TranslatedExpression VisitStsFld(StsFld inst)
// {
// return Assignment(ConvertField(inst.Field).WithoutILInstruction(), Translate(inst.Value)).WithILInstruction(inst);

1
ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj

@ -106,6 +106,7 @@ @@ -106,6 +106,7 @@
<Compile Include="IL\Instructions\BlockContainer.cs" />
<Compile Include="IL\Instructions\Branch.cs" />
<Compile Include="IL\Instructions\CallInstruction.cs" />
<Compile Include="IL\Instructions\CompoundAssignmentInstruction.cs" />
<Compile Include="IL\Instructions\Conv.cs" />
<Compile Include="IL\Instructions\IfInstruction.cs" />
<Compile Include="IL\Instructions\ILFunction.cs" />

89
ICSharpCode.Decompiler/IL/Instructions.cs

@ -45,6 +45,8 @@ namespace ICSharpCode.Decompiler.IL @@ -45,6 +45,8 @@ namespace ICSharpCode.Decompiler.IL
LogicNot,
/// <summary>Common instruction for add, sub, mul, div, rem, bit.and, bit.or, bit.xor, shl and shr.</summary>
BinaryNumericInstruction,
/// <summary>Common instruction for compound assignments.</summary>
CompoundAssignmentInstruction,
/// <summary>Bitwise NOT</summary>
BitNot,
/// <summary>Retrieves the RuntimeArgumentHandle.</summary>
@ -718,6 +720,84 @@ namespace ICSharpCode.Decompiler.IL @@ -718,6 +720,84 @@ namespace ICSharpCode.Decompiler.IL
}
}
/// <summary>Common instruction for compound assignments.</summary>
public sealed partial class CompoundAssignmentInstruction : ILInstruction
{
public static readonly SlotInfo TargetSlot = new SlotInfo("Target", canInlineInto: true);
ILInstruction target;
public ILInstruction Target {
get { return this.target; }
set {
ValidateChild(value);
SetChildInstruction(ref this.target, value, 0);
}
}
public static readonly SlotInfo ValueSlot = new SlotInfo("Value", canInlineInto: true);
ILInstruction value;
public ILInstruction Value {
get { return this.value; }
set {
ValidateChild(value);
SetChildInstruction(ref this.value, value, 1);
}
}
protected sealed override int GetChildCount()
{
return 2;
}
protected sealed override ILInstruction GetChild(int index)
{
switch (index) {
case 0:
return this.target;
case 1:
return this.value;
default:
throw new IndexOutOfRangeException();
}
}
protected sealed override void SetChild(int index, ILInstruction value)
{
switch (index) {
case 0:
this.Target = value;
break;
case 1:
this.Value = value;
break;
default:
throw new IndexOutOfRangeException();
}
}
protected sealed override SlotInfo GetChildSlot(int index)
{
switch (index) {
case 0:
return TargetSlot;
case 1:
return ValueSlot;
default:
throw new IndexOutOfRangeException();
}
}
public sealed override ILInstruction Clone()
{
var clone = (CompoundAssignmentInstruction)ShallowClone();
clone.Target = this.target.Clone();
clone.Value = this.value.Clone();
return clone;
}
public override StackType ResultType { get { return target.ResultType; } }
public override void AcceptVisitor(ILVisitor visitor)
{
visitor.VisitCompoundAssignmentInstruction(this);
}
public override T AcceptVisitor<T>(ILVisitor<T> visitor)
{
return visitor.VisitCompoundAssignmentInstruction(this);
}
}
/// <summary>Bitwise NOT</summary>
public sealed partial class BitNot : UnaryInstruction
{
@ -2922,6 +3002,10 @@ namespace ICSharpCode.Decompiler.IL @@ -2922,6 +3002,10 @@ namespace ICSharpCode.Decompiler.IL
{
Default(inst);
}
protected internal virtual void VisitCompoundAssignmentInstruction(CompoundAssignmentInstruction inst)
{
Default(inst);
}
protected internal virtual void VisitBitNot(BitNot inst)
{
Default(inst);
@ -3180,6 +3264,10 @@ namespace ICSharpCode.Decompiler.IL @@ -3180,6 +3264,10 @@ namespace ICSharpCode.Decompiler.IL
{
return Default(inst);
}
protected internal virtual T VisitCompoundAssignmentInstruction(CompoundAssignmentInstruction inst)
{
return Default(inst);
}
protected internal virtual T VisitBitNot(BitNot inst)
{
return Default(inst);
@ -3420,6 +3508,7 @@ namespace ICSharpCode.Decompiler.IL @@ -3420,6 +3508,7 @@ namespace ICSharpCode.Decompiler.IL
"PinnedRegion",
"logic.not",
"binary",
"compound",
"bit.not",
"arglist",
"br",

3
ICSharpCode.Decompiler/IL/Instructions.tt

@ -60,6 +60,9 @@ @@ -60,6 +60,9 @@
ResultType("I4"), Unary),
new OpCode("binary", "Common instruction for add, sub, mul, div, rem, bit.and, bit.or, bit.xor, shl and shr.",
CustomClassName("BinaryNumericInstruction"), Binary, CustomWriteTo, CustomConstructor, CustomComputeFlags),
new OpCode("compound", "Common instruction for compound assignments.",
CustomClassName("CompoundAssignmentInstruction"), CustomConstructor, CustomComputeFlags,
MayThrow, CustomArguments("target", "value"), ResultType("target.ResultType"), CustomWriteTo),
new OpCode("bit.not", "Bitwise NOT", Unary),
new OpCode("arglist", "Retrieves the RuntimeArgumentHandle.", NoArguments, ResultType("O")),
new OpCode("br", "Unconditional branch. <c>goto target;</c>",

31
ICSharpCode.Decompiler/IL/Instructions/BinaryNumericInstruction.cs

@ -17,22 +17,16 @@ @@ -17,22 +17,16 @@
// DEALINGS IN THE SOFTWARE.
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using ICSharpCode.NRefactory.TypeSystem;
namespace ICSharpCode.Decompiler.IL
{
public enum CompoundAssignmentType : byte
{
None,
EvaluatesToOldValue,
EvaluatesToNewValue
}
{
public enum BinaryNumericOperator : byte
{
None,
Add,
Sub,
Mul,
@ -74,21 +68,6 @@ namespace ICSharpCode.Decompiler.IL @@ -74,21 +68,6 @@ namespace ICSharpCode.Decompiler.IL
this.Operator = op;
this.resultType = ComputeResultType(op, left.ResultType, right.ResultType);
Debug.Assert(resultType != StackType.Unknown);
//Debug.Assert(CompoundAssignmentType == CompoundAssignmentType.None || IsValidCompoundAssignmentTarget(Left));
}
internal static bool IsValidCompoundAssignmentTarget(ILInstruction inst)
{
switch (inst.OpCode) {
case OpCode.LdLoc:
case OpCode.LdObj:
return true;
case OpCode.Call:
case OpCode.CallVirt:
return true; // TODO: check if corresponding setter exists
default:
return false;
}
}
internal static StackType ComputeResultType(BinaryNumericOperator op, StackType left, StackType right)

150
ICSharpCode.Decompiler/IL/Instructions/CompoundAssignmentInstruction.cs

@ -0,0 +1,150 @@ @@ -0,0 +1,150 @@
// Copyright (c) 2016 Siegfried Pammer
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
// software and associated documentation files (the "Software"), to deal in the Software
// without restriction, including without limitation the rights to use, copy, modify, merge,
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
// to whom the Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or
// substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
using System;
using System.Diagnostics;
using System.Linq;
using ICSharpCode.NRefactory.TypeSystem;
namespace ICSharpCode.Decompiler.IL
{
public enum CompoundAssignmentType : byte
{
EvaluatesToOldValue,
EvaluatesToNewValue
}
public partial class CompoundAssignmentInstruction : ILInstruction
{
/// <summary>
/// Gets whether the instruction checks for overflow.
/// </summary>
public readonly bool CheckForOverflow;
/// <summary>
/// For integer operations that depend on the sign, specifies whether the operation
/// is signed or unsigned.
/// For instructions that produce the same result for either sign, returns Sign.None.
/// </summary>
public readonly Sign Sign;
/// <summary>
/// The operator used by this assignment operator instruction.
/// </summary>
public readonly BinaryNumericOperator Operator;
public readonly CompoundAssignmentType CompoundAssignmentType;
public CompoundAssignmentInstruction(BinaryNumericOperator op, ILInstruction target, ILInstruction value, bool checkForOverflow, Sign sign, CompoundAssignmentType compoundAssigmentType)
: base(OpCode.CompoundAssignmentInstruction)
{
this.CheckForOverflow = checkForOverflow;
this.Sign = sign;
this.Operator = op;
this.Target = target;
this.Value = value;
this.CompoundAssignmentType = compoundAssigmentType;
Debug.Assert(compoundAssigmentType == CompoundAssignmentType.EvaluatesToNewValue || (op == BinaryNumericOperator.Add || op == BinaryNumericOperator.Sub));
Debug.Assert(IsValidCompoundAssignmentTarget(Target));
}
internal static bool IsValidCompoundAssignmentTarget(ILInstruction inst)
{
switch (inst.OpCode) {
case OpCode.LdLoc:
case OpCode.LdObj:
return true;
case OpCode.Call:
case OpCode.CallVirt:
var owner = ((CallInstruction)inst).Method.AccessorOwner as IProperty;
return owner != null && owner.CanSet;
default:
return false;
}
}
protected override InstructionFlags ComputeFlags()
{
var flags = target.Flags | value.Flags | InstructionFlags.SideEffect;
if (CheckForOverflow || (Operator == BinaryNumericOperator.Div || Operator == BinaryNumericOperator.Rem))
flags |= InstructionFlags.MayThrow;
return flags;
}
public override InstructionFlags DirectFlags {
get {
var flags = InstructionFlags.SideEffect;
if (Operator == BinaryNumericOperator.Div || Operator == BinaryNumericOperator.Rem)
flags |= InstructionFlags.MayThrow;
return flags;
}
}
string GetOperatorName(BinaryNumericOperator @operator)
{
switch (@operator) {
case BinaryNumericOperator.Add:
return "add";
case BinaryNumericOperator.Sub:
return "sub";
case BinaryNumericOperator.Mul:
return "mul";
case BinaryNumericOperator.Div:
return "div";
case BinaryNumericOperator.Rem:
return "rem";
case BinaryNumericOperator.BitAnd:
return "bit.and";
case BinaryNumericOperator.BitOr:
return "bit.or";
case BinaryNumericOperator.BitXor:
return "bit.xor";
case BinaryNumericOperator.ShiftLeft:
return "bit.shl";
case BinaryNumericOperator.ShiftRight:
return "bit.shr";
default:
throw new ArgumentOutOfRangeException();
}
}
public override void WriteTo(ITextOutput output)
{
output.Write(OpCode);
output.Write("." + GetOperatorName(Operator));
if (CompoundAssignmentType == CompoundAssignmentType.EvaluatesToNewValue)
output.Write(".new");
else
output.Write(".old");
if (CheckForOverflow)
output.Write(".ovf");
if (Sign == Sign.Unsigned)
output.Write(".unsigned");
else if (Sign == Sign.Signed)
output.Write(".signed");
output.Write('(');
Target.WriteTo(output);
output.Write(", ");
Value.WriteTo(output);
output.Write(')');
}
}
}

15
ICSharpCode.Decompiler/IL/Instructions/PatternMatching.cs

@ -221,6 +221,21 @@ namespace ICSharpCode.Decompiler.IL @@ -221,6 +221,21 @@ namespace ICSharpCode.Decompiler.IL
return false;
}
public bool MatchBinaryNumericInstruction(out BinaryNumericOperator @operator, out ILInstruction left, out ILInstruction right)
{
var op = this as BinaryNumericInstruction;
if (op != null) {
@operator = op.Operator;
left = op.Left;
right = op.Right;
return true;
}
@operator = BinaryNumericOperator.None;
left = null;
right = null;
return false;
}
/// <summary>
/// If this instruction is a conversion of the specified kind, return its argument.
/// Otherwise, return the instruction itself.

18
ICSharpCode.Decompiler/IL/Transforms/ExpressionTransforms.cs

@ -188,6 +188,24 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -188,6 +188,24 @@ namespace ICSharpCode.Decompiler.IL.Transforms
// => stloc(v, ...)
inst.ReplaceWith(new StLoc(v, inst.Value));
}
ILInstruction target;
IType t;
BinaryNumericInstruction binary = inst.Value as BinaryNumericInstruction;
if (binary != null && binary.Left.MatchLdObj(out target, out t) && IsSameTarget(inst.Target, target)) {
// stobj(target, binary.op(ldobj(target), ...))
// => compound.op(target, ...)
inst.ReplaceWith(new CompoundAssignmentInstruction(binary.Operator, binary.Left, binary.Right, binary.CheckForOverflow, binary.Sign, CompoundAssignmentType.EvaluatesToNewValue));
}
}
bool IsSameTarget(ILInstruction target, ILInstruction left)
{
IField f, f2;
ILInstruction t, t2;
if (target.MatchLdFlda(out t, out f) && left.MatchLdFlda(out t2, out f2) && f.Equals(f2))
return true;
return false;
}
protected internal override void VisitIfInstruction(IfInstruction inst)

16
ICSharpCode.Decompiler/Tests/TestCases/Pretty/CompoundAssignmentTest.cs

@ -22,6 +22,8 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty @@ -22,6 +22,8 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
{
public class CompoundAssignmentTest
{
private int test1;
public static void Main()
{
@ -37,5 +39,19 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty @@ -37,5 +39,19 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
V_0 -= i;
}
}
public void IntegerWithInline(int i)
{
Console.WriteLine(i += 5);
Console.WriteLine(i);
}
public void IntegerField(int i)
{
Console.WriteLine(this.test1 += i);
Console.WriteLine(this.test1);
Console.WriteLine(this.test1 -= i);
Console.WriteLine(this.test1);
}
}
}

100
ICSharpCode.Decompiler/Tests/TestCases/Pretty/CompoundAssignmentTest.il

@ -10,7 +10,7 @@ @@ -10,7 +10,7 @@
.publickeytoken = (B7 7A 5C 56 19 34 E0 89 ) // .z\V.4..
.ver 4:0:0:0
}
.assembly '2lky0ish'
.assembly baqif21x
{
.custom instance void [mscorlib]System.Runtime.CompilerServices.CompilationRelaxationsAttribute::.ctor(int32) = ( 01 00 08 00 00 00 00 00 )
.custom instance void [mscorlib]System.Runtime.CompilerServices.RuntimeCompatibilityAttribute::.ctor() = ( 01 00 01 00 54 02 16 57 72 61 70 4E 6F 6E 45 78 // ....T..WrapNonEx
@ -20,15 +20,15 @@ @@ -20,15 +20,15 @@
.hash algorithm 0x00008004
.ver 0:0:0:0
}
.module '2lky0ish.exe'
// MVID: {EF50960E-81BF-4C58-B168-629EA572CC14}
.module baqif21x.exe
// MVID: {1149F1EE-8A3E-4309-9B0E-D81380AC971E}
.custom instance void [mscorlib]System.Security.UnverifiableCodeAttribute::.ctor() = ( 01 00 00 00 )
.imagebase 0x00400000
.file alignment 0x00000200
.stackreserve 0x00100000
.subsystem 0x0003 // WINDOWS_CUI
.corflags 0x00000001 // ILONLY
// Image base: 0x00D20000
// Image base: 0x011D0000
// =============== CLASS MEMBERS DECLARATION ===================
@ -36,6 +36,7 @@ @@ -36,6 +36,7 @@
.class public auto ansi beforefieldinit ICSharpCode.Decompiler.Tests.TestCases.Pretty.CompoundAssignmentTest
extends [mscorlib]System.Object
{
.field private int32 test1
.method public hidebysig static void Main() cil managed
{
.entrypoint
@ -48,7 +49,7 @@ @@ -48,7 +49,7 @@
.method public hidebysig instance void
Integer(int32 i) cil managed
{
// Code size 25 (0x19)
// Code size 29 (0x1d)
.maxstack 2
.locals init (int32 V_0,
bool V_1)
@ -62,21 +63,84 @@ @@ -62,21 +63,84 @@
IL_0008: ceq
IL_000a: stloc.1
IL_000b: ldloc.1
IL_000c: brtrue.s IL_0014
IL_000e: ldloc.0
IL_000f: ldarg.1
IL_0010: add
IL_0011: stloc.0
IL_0012: br.s IL_0018
IL_0014: ldloc.0
IL_0015: ldarg.1
IL_0016: sub
IL_0017: stloc.0
IL_0018: ret
IL_000c: brtrue.s IL_0016
IL_000e: nop
IL_000f: ldloc.0
IL_0010: ldarg.1
IL_0011: add
IL_0012: stloc.0
IL_0013: nop
IL_0014: br.s IL_001c
IL_0016: nop
IL_0017: ldloc.0
IL_0018: ldarg.1
IL_0019: sub
IL_001a: stloc.0
IL_001b: nop
IL_001c: ret
} // end of method CompoundAssignmentTest::Integer
.method public hidebysig instance void
IntegerWithInline(int32 i) cil managed
{
// Code size 21 (0x15)
.maxstack 8
IL_0000: nop
IL_0001: ldarg.1
IL_0002: ldc.i4.5
IL_0003: add
IL_0004: dup
IL_0005: starg.s i
IL_0007: call void [mscorlib]System.Console::WriteLine(int32)
IL_000c: nop
IL_000d: ldarg.1
IL_000e: call void [mscorlib]System.Console::WriteLine(int32)
IL_0013: nop
IL_0014: ret
} // end of method CompoundAssignmentTest::IntegerWithInline
.method public hidebysig instance void
IntegerField(int32 i) cil managed
{
// Code size 72 (0x48)
.maxstack 3
.locals init (int32 V_0)
IL_0000: nop
IL_0001: ldarg.0
IL_0002: dup
IL_0003: ldfld int32 ICSharpCode.Decompiler.Tests.TestCases.Pretty.CompoundAssignmentTest::test1
IL_0008: ldarg.1
IL_0009: add
IL_000a: dup
IL_000b: stloc.0
IL_000c: stfld int32 ICSharpCode.Decompiler.Tests.TestCases.Pretty.CompoundAssignmentTest::test1
IL_0011: ldloc.0
IL_0012: call void [mscorlib]System.Console::WriteLine(int32)
IL_0017: nop
IL_0018: ldarg.0
IL_0019: ldfld int32 ICSharpCode.Decompiler.Tests.TestCases.Pretty.CompoundAssignmentTest::test1
IL_001e: call void [mscorlib]System.Console::WriteLine(int32)
IL_0023: nop
IL_0024: ldarg.0
IL_0025: dup
IL_0026: ldfld int32 ICSharpCode.Decompiler.Tests.TestCases.Pretty.CompoundAssignmentTest::test1
IL_002b: ldarg.1
IL_002c: sub
IL_002d: dup
IL_002e: stloc.0
IL_002f: stfld int32 ICSharpCode.Decompiler.Tests.TestCases.Pretty.CompoundAssignmentTest::test1
IL_0034: ldloc.0
IL_0035: call void [mscorlib]System.Console::WriteLine(int32)
IL_003a: nop
IL_003b: ldarg.0
IL_003c: ldfld int32 ICSharpCode.Decompiler.Tests.TestCases.Pretty.CompoundAssignmentTest::test1
IL_0041: call void [mscorlib]System.Console::WriteLine(int32)
IL_0046: nop
IL_0047: ret
} // end of method CompoundAssignmentTest::IntegerField
.method public hidebysig specialname rtspecialname
instance void .ctor() cil managed
{

Loading…
Cancel
Save