Browse Source

Allow inline assignments to short integers when we can tell that there's no truncation.

pull/960/head
Daniel Grunwald 8 years ago
parent
commit
b0bf6326ad
  1. 6
      ICSharpCode.Decompiler.Tests/TestCases/Pretty/InlineAssignmentTest.cs
  2. 67
      ICSharpCode.Decompiler.Tests/TestCases/Pretty/InlineAssignmentTest.il
  3. 64
      ICSharpCode.Decompiler.Tests/TestCases/Pretty/InlineAssignmentTest.opt.il
  4. 48
      ICSharpCode.Decompiler/IL/Transforms/TransformAssignment.cs

6
ICSharpCode.Decompiler.Tests/TestCases/Pretty/InlineAssignmentTest.cs

@ -51,12 +51,16 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
Console.WriteLine(InlineAssignmentTest.field2 = new InlineAssignmentTest()); Console.WriteLine(InlineAssignmentTest.field2 = new InlineAssignmentTest());
Console.WriteLine(InlineAssignmentTest.field2); Console.WriteLine(InlineAssignmentTest.field2);
this.UseShort(this.field4 = 6); this.UseShort(this.field4 = 6);
this.UseShort(this.field4 = -10000);
this.UseShort(this.field4 = (short)this.field1);
this.UseShort(this.field4 = this.UseShort(0));
Console.WriteLine(this.field4); Console.WriteLine(this.field4);
} }
public void UseShort(short s) public short UseShort(short s)
{ {
Console.WriteLine(s); Console.WriteLine(s);
return s;
} }
public void ReadLoop1(TextReader r) public void ReadLoop1(TextReader r)

67
ICSharpCode.Decompiler.Tests/TestCases/Pretty/InlineAssignmentTest.il

@ -10,7 +10,7 @@
.publickeytoken = (B7 7A 5C 56 19 34 E0 89 ) // .z\V.4.. .publickeytoken = (B7 7A 5C 56 19 34 E0 89 ) // .z\V.4..
.ver 4:0:0:0 .ver 4:0:0:0
} }
.assembly uq03kalt .assembly w1xqybg1
{ {
.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.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 .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 @@
.hash algorithm 0x00008004 .hash algorithm 0x00008004
.ver 0:0:0:0 .ver 0:0:0:0
} }
.module uq03kalt.dll .module w1xqybg1.dll
// MVID: {D636DE2E-D2CD-4EDF-B87B-0B0985C6C0B8} // MVID: {1BE5829A-0D5E-43DC-8C02-E3012B1780A2}
.custom instance void [mscorlib]System.Security.UnverifiableCodeAttribute::.ctor() = ( 01 00 00 00 ) .custom instance void [mscorlib]System.Security.UnverifiableCodeAttribute::.ctor() = ( 01 00 00 00 )
.imagebase 0x10000000 .imagebase 0x10000000
.file alignment 0x00000200 .file alignment 0x00000200
.stackreserve 0x00100000 .stackreserve 0x00100000
.subsystem 0x0003 // WINDOWS_CUI .subsystem 0x0003 // WINDOWS_CUI
.corflags 0x00000001 // ILONLY .corflags 0x00000001 // ILONLY
// Image base: 0x018D0000 // Image base: 0x033B0000
// =============== CLASS MEMBERS DECLARATION =================== // =============== CLASS MEMBERS DECLARATION ===================
@ -93,7 +93,7 @@
.method public hidebysig instance void .method public hidebysig instance void
SimpleInlineWithFields2() cil managed SimpleInlineWithFields2() cil managed
{ {
// Code size 87 (0x57) // Code size 154 (0x9a)
.maxstack 4 .maxstack 4
.locals init (int32 V_0, .locals init (int32 V_0,
int16 V_1) int16 V_1)
@ -125,25 +125,62 @@
IL_003d: stloc.1 IL_003d: stloc.1
IL_003e: stfld int16 ICSharpCode.Decompiler.Tests.TestCases.Pretty.InlineAssignmentTest::field4 IL_003e: stfld int16 ICSharpCode.Decompiler.Tests.TestCases.Pretty.InlineAssignmentTest::field4
IL_0043: ldloc.1 IL_0043: ldloc.1
IL_0044: call instance void ICSharpCode.Decompiler.Tests.TestCases.Pretty.InlineAssignmentTest::UseShort(int16) IL_0044: call instance int16 ICSharpCode.Decompiler.Tests.TestCases.Pretty.InlineAssignmentTest::UseShort(int16)
IL_0049: nop IL_0049: pop
IL_004a: ldarg.0 IL_004a: ldarg.0
IL_004b: ldfld int16 ICSharpCode.Decompiler.Tests.TestCases.Pretty.InlineAssignmentTest::field4 IL_004b: ldarg.0
IL_0050: call void [mscorlib]System.Console::WriteLine(int32) IL_004c: ldc.i4 0xffffd8f0
IL_0055: nop IL_0051: dup
IL_0056: ret IL_0052: stloc.1
IL_0053: stfld int16 ICSharpCode.Decompiler.Tests.TestCases.Pretty.InlineAssignmentTest::field4
IL_0058: ldloc.1
IL_0059: call instance int16 ICSharpCode.Decompiler.Tests.TestCases.Pretty.InlineAssignmentTest::UseShort(int16)
IL_005e: pop
IL_005f: ldarg.0
IL_0060: ldarg.0
IL_0061: ldarg.0
IL_0062: ldfld int32 ICSharpCode.Decompiler.Tests.TestCases.Pretty.InlineAssignmentTest::field1
IL_0067: conv.i2
IL_0068: dup
IL_0069: stloc.1
IL_006a: stfld int16 ICSharpCode.Decompiler.Tests.TestCases.Pretty.InlineAssignmentTest::field4
IL_006f: ldloc.1
IL_0070: call instance int16 ICSharpCode.Decompiler.Tests.TestCases.Pretty.InlineAssignmentTest::UseShort(int16)
IL_0075: pop
IL_0076: ldarg.0
IL_0077: ldarg.0
IL_0078: ldarg.0
IL_0079: ldc.i4.0
IL_007a: call instance int16 ICSharpCode.Decompiler.Tests.TestCases.Pretty.InlineAssignmentTest::UseShort(int16)
IL_007f: dup
IL_0080: stloc.1
IL_0081: stfld int16 ICSharpCode.Decompiler.Tests.TestCases.Pretty.InlineAssignmentTest::field4
IL_0086: ldloc.1
IL_0087: call instance int16 ICSharpCode.Decompiler.Tests.TestCases.Pretty.InlineAssignmentTest::UseShort(int16)
IL_008c: pop
IL_008d: ldarg.0
IL_008e: ldfld int16 ICSharpCode.Decompiler.Tests.TestCases.Pretty.InlineAssignmentTest::field4
IL_0093: call void [mscorlib]System.Console::WriteLine(int32)
IL_0098: nop
IL_0099: ret
} // end of method InlineAssignmentTest::SimpleInlineWithFields2 } // end of method InlineAssignmentTest::SimpleInlineWithFields2
.method public hidebysig instance void .method public hidebysig instance int16
UseShort(int16 s) cil managed UseShort(int16 s) cil managed
{ {
// Code size 9 (0x9) // Code size 14 (0xe)
.maxstack 8 .maxstack 1
.locals init (int16 V_0)
IL_0000: nop IL_0000: nop
IL_0001: ldarg.1 IL_0001: ldarg.1
IL_0002: call void [mscorlib]System.Console::WriteLine(int32) IL_0002: call void [mscorlib]System.Console::WriteLine(int32)
IL_0007: nop IL_0007: nop
IL_0008: ret IL_0008: ldarg.1
IL_0009: stloc.0
IL_000a: br.s IL_000c
IL_000c: ldloc.0
IL_000d: ret
} // end of method InlineAssignmentTest::UseShort } // end of method InlineAssignmentTest::UseShort
.method public hidebysig instance void .method public hidebysig instance void

64
ICSharpCode.Decompiler.Tests/TestCases/Pretty/InlineAssignmentTest.opt.il

@ -10,7 +10,7 @@
.publickeytoken = (B7 7A 5C 56 19 34 E0 89 ) // .z\V.4.. .publickeytoken = (B7 7A 5C 56 19 34 E0 89 ) // .z\V.4..
.ver 4:0:0:0 .ver 4:0:0:0
} }
.assembly zztqnmi4 .assembly f1ibwsev
{ {
.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.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 .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 @@
.hash algorithm 0x00008004 .hash algorithm 0x00008004
.ver 0:0:0:0 .ver 0:0:0:0
} }
.module zztqnmi4.dll .module f1ibwsev.dll
// MVID: {038F2DF5-AE7B-4B0A-B846-AC254CE46038} // MVID: {8DB4E6AA-A0C2-49F3-8E9C-A28CE30F145A}
.custom instance void [mscorlib]System.Security.UnverifiableCodeAttribute::.ctor() = ( 01 00 00 00 ) .custom instance void [mscorlib]System.Security.UnverifiableCodeAttribute::.ctor() = ( 01 00 00 00 )
.imagebase 0x10000000 .imagebase 0x10000000
.file alignment 0x00000200 .file alignment 0x00000200
.stackreserve 0x00100000 .stackreserve 0x00100000
.subsystem 0x0003 // WINDOWS_CUI .subsystem 0x0003 // WINDOWS_CUI
.corflags 0x00000001 // ILONLY .corflags 0x00000001 // ILONLY
// Image base: 0x006A0000 // Image base: 0x01400000
// =============== CLASS MEMBERS DECLARATION =================== // =============== CLASS MEMBERS DECLARATION ===================
@ -85,10 +85,13 @@
.method public hidebysig instance void .method public hidebysig instance void
SimpleInlineWithFields2() cil managed SimpleInlineWithFields2() cil managed
{ {
// Code size 80 (0x50) // Code size 150 (0x96)
.maxstack 4 .maxstack 4
.locals init (int32 V_0, .locals init (int32 V_0,
int16 V_1) int16 V_1,
int16 V_2,
int16 V_3,
int16 V_4)
IL_0000: ldarg.0 IL_0000: ldarg.0
IL_0001: ldc.i4.5 IL_0001: ldc.i4.5
IL_0002: dup IL_0002: dup
@ -112,21 +115,54 @@
IL_0038: stloc.1 IL_0038: stloc.1
IL_0039: stfld int16 ICSharpCode.Decompiler.Tests.TestCases.Pretty.InlineAssignmentTest::field4 IL_0039: stfld int16 ICSharpCode.Decompiler.Tests.TestCases.Pretty.InlineAssignmentTest::field4
IL_003e: ldloc.1 IL_003e: ldloc.1
IL_003f: call instance void ICSharpCode.Decompiler.Tests.TestCases.Pretty.InlineAssignmentTest::UseShort(int16) IL_003f: call instance int16 ICSharpCode.Decompiler.Tests.TestCases.Pretty.InlineAssignmentTest::UseShort(int16)
IL_0044: ldarg.0 IL_0044: pop
IL_0045: ldfld int16 ICSharpCode.Decompiler.Tests.TestCases.Pretty.InlineAssignmentTest::field4 IL_0045: ldarg.0
IL_004a: call void [mscorlib]System.Console::WriteLine(int32) IL_0046: ldarg.0
IL_004f: ret IL_0047: ldc.i4 0xffffd8f0
IL_004c: dup
IL_004d: stloc.2
IL_004e: stfld int16 ICSharpCode.Decompiler.Tests.TestCases.Pretty.InlineAssignmentTest::field4
IL_0053: ldloc.2
IL_0054: call instance int16 ICSharpCode.Decompiler.Tests.TestCases.Pretty.InlineAssignmentTest::UseShort(int16)
IL_0059: pop
IL_005a: ldarg.0
IL_005b: ldarg.0
IL_005c: ldarg.0
IL_005d: ldfld int32 ICSharpCode.Decompiler.Tests.TestCases.Pretty.InlineAssignmentTest::field1
IL_0062: conv.i2
IL_0063: dup
IL_0064: stloc.3
IL_0065: stfld int16 ICSharpCode.Decompiler.Tests.TestCases.Pretty.InlineAssignmentTest::field4
IL_006a: ldloc.3
IL_006b: call instance int16 ICSharpCode.Decompiler.Tests.TestCases.Pretty.InlineAssignmentTest::UseShort(int16)
IL_0070: pop
IL_0071: ldarg.0
IL_0072: ldarg.0
IL_0073: ldarg.0
IL_0074: ldc.i4.0
IL_0075: call instance int16 ICSharpCode.Decompiler.Tests.TestCases.Pretty.InlineAssignmentTest::UseShort(int16)
IL_007a: dup
IL_007b: stloc.s V_4
IL_007d: stfld int16 ICSharpCode.Decompiler.Tests.TestCases.Pretty.InlineAssignmentTest::field4
IL_0082: ldloc.s V_4
IL_0084: call instance int16 ICSharpCode.Decompiler.Tests.TestCases.Pretty.InlineAssignmentTest::UseShort(int16)
IL_0089: pop
IL_008a: ldarg.0
IL_008b: ldfld int16 ICSharpCode.Decompiler.Tests.TestCases.Pretty.InlineAssignmentTest::field4
IL_0090: call void [mscorlib]System.Console::WriteLine(int32)
IL_0095: ret
} // end of method InlineAssignmentTest::SimpleInlineWithFields2 } // end of method InlineAssignmentTest::SimpleInlineWithFields2
.method public hidebysig instance void .method public hidebysig instance int16
UseShort(int16 s) cil managed UseShort(int16 s) cil managed
{ {
// Code size 7 (0x7) // Code size 8 (0x8)
.maxstack 8 .maxstack 8
IL_0000: ldarg.1 IL_0000: ldarg.1
IL_0001: call void [mscorlib]System.Console::WriteLine(int32) IL_0001: call void [mscorlib]System.Console::WriteLine(int32)
IL_0006: ret IL_0006: ldarg.1
IL_0007: ret
} // end of method InlineAssignmentTest::UseShort } // end of method InlineAssignmentTest::UseShort
.method public hidebysig instance void .method public hidebysig instance void

48
ICSharpCode.Decompiler/IL/Transforms/TransformAssignment.cs

@ -268,9 +268,55 @@ namespace ICSharpCode.Decompiler.IL.Transforms
return true; return true;
} }
/// <summary>
/// Gets whether 'stobj type(..., value)' would evaluate to a different value than 'value'
/// due to implicit truncation.
/// </summary>
bool IsImplicitTruncation(ILInstruction value, IType type) bool IsImplicitTruncation(ILInstruction value, IType type)
{ {
return type.IsSmallIntegerType(); if (!type.IsSmallIntegerType()) {
// Implicit truncation in ILAst only happens for small integer types;
// other types of implicit truncation in IL cause the ILReader to insert
// conv instructions.
return false;
}
// With small integer types, test whether the value being stored
// is being truncated:
if (value.MatchLdcI4(out int val)) {
switch (type.GetEnumUnderlyingType().GetDefinition()?.KnownTypeCode) {
case KnownTypeCode.Boolean:
return !(val == 0 || val == 1);
case KnownTypeCode.Byte:
return !(val >= byte.MinValue && val <= byte.MaxValue);
case KnownTypeCode.SByte:
return !(val >= sbyte.MinValue && val <= sbyte.MaxValue);
case KnownTypeCode.Int16:
return !(val >= short.MinValue && val <= short.MaxValue);
case KnownTypeCode.UInt16:
case KnownTypeCode.Char:
return !(val >= ushort.MinValue && val <= ushort.MaxValue);
}
} else if (value is LdObj ldobj) {
return IsImplicitTruncation(ldobj.Type, type);
} else if (value is StObj stobj) {
return IsImplicitTruncation(stobj.Type, type);
} else if (value is LdLoc ldloc) {
return IsImplicitTruncation(ldloc.Variable.Type, type);
} else if (value is StLoc stloc) {
return IsImplicitTruncation(stloc.Variable.Type, type);
} else if (value is CallInstruction call) {
return IsImplicitTruncation(call.Method.ReturnType, type);
} else if (value is Conv conv) {
return conv.TargetType != type.ToPrimitiveType();
} else if (value is Comp) {
return false; // comp returns 0 or 1, which always fits
}
return true;
}
bool IsImplicitTruncation(IType fromType, IType toType)
{
return !(fromType.GetSize() <= toType.GetSize() && fromType.GetSign() == toType.GetSign());
} }
/// <code> /// <code>

Loading…
Cancel
Save