From 74eb0d8d63bab45f7b435b0f205fafcc79d8bfe5 Mon Sep 17 00:00:00 2001 From: Daniel Grunwald Date: Mon, 16 Oct 2017 21:05:03 +0200 Subject: [PATCH] Avoid unnecessary casts in pointer comparisons. --- .../TestCases/Correctness/TrickyTypes.cs | 46 ++++++++ .../TestCases/Pretty/UnsafeCode.cs | 25 +++++ .../TestCases/Pretty/UnsafeCode.il | 100 +++++++++++++++++- .../TestCases/Pretty/UnsafeCode.opt.il | 83 ++++++++++++++- .../TestCases/Pretty/UnsafeCode.opt.roslyn.il | 79 +++++++++++++- .../TestCases/Pretty/UnsafeCode.roslyn.il | 96 ++++++++++++++++- .../CSharp/ExpressionBuilder.cs | 49 +++++++-- .../Transforms/IntroduceUnsafeModifier.cs | 9 +- 8 files changed, 467 insertions(+), 20 deletions(-) diff --git a/ICSharpCode.Decompiler.Tests/TestCases/Correctness/TrickyTypes.cs b/ICSharpCode.Decompiler.Tests/TestCases/Correctness/TrickyTypes.cs index 3f2b2b717..83b609b2f 100644 --- a/ICSharpCode.Decompiler.Tests/TestCases/Correctness/TrickyTypes.cs +++ b/ICSharpCode.Decompiler.Tests/TestCases/Correctness/TrickyTypes.cs @@ -25,6 +25,7 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Correctness static void Main() { InterestingConstants(); + TruncatedComp(); } static void Print(T val) @@ -46,5 +47,50 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Correctness Print(val2); Print(2147483648u); } + + static void TruncatedComp() + { + Console.WriteLine("TruncatedComp1(1):"); + TruncatedComp1(1); + + Console.WriteLine("TruncatedComp1(-1):"); + TruncatedComp1(-1); + + Console.WriteLine("TruncatedComp1(0x100000001):"); + TruncatedComp1(0x100000001); + + Console.WriteLine("TruncatedComp1(long.MinValue):"); + TruncatedComp1(long.MinValue); + + Console.WriteLine("TruncatedComp2(1):"); + TruncatedComp2(1, 1); + + Console.WriteLine("TruncatedComp2(-1):"); + TruncatedComp2(-1, -1); + + Console.WriteLine("TruncatedComp2(0x100000001):"); + TruncatedComp2(0x100000001, 1); + + Console.WriteLine("TruncatedComp2(long.MinValue):"); + TruncatedComp2(long.MinValue, int.MinValue); + } + + static void TruncatedComp1(long val) + { + Print((int)val == val); + Print(val == (int)val); + Print(val < (int)val); + Print((int)val >= val); + } + + static void TruncatedComp2(long val1, int val2) + { + Print(val1 == val2); + Print((int)val1 == val2); + Print(val1 < val2); + Print((int)val1 < val2); + Print(val1 <= val2); + Print((int)val1 <= val2); + } } } diff --git a/ICSharpCode.Decompiler.Tests/TestCases/Pretty/UnsafeCode.cs b/ICSharpCode.Decompiler.Tests/TestCases/Pretty/UnsafeCode.cs index 6ca516963..0c1b46ef5 100644 --- a/ICSharpCode.Decompiler.Tests/TestCases/Pretty/UnsafeCode.cs +++ b/ICSharpCode.Decompiler.Tests/TestCases/Pretty/UnsafeCode.cs @@ -32,6 +32,31 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty } } + public unsafe int SizeOf() + { + return sizeof(SimpleStruct); + } + + private static void UseBool(bool b) + { + } + + public unsafe void PointerComparison(int* a, double* b) + { + UnsafeCode.UseBool(a == b); + UnsafeCode.UseBool(a != b); + UnsafeCode.UseBool(a < b); + UnsafeCode.UseBool(a > b); + UnsafeCode.UseBool(a <= b); + UnsafeCode.UseBool(a >= b); + } + + public unsafe void PointerComparisonWithNull(int* a) + { + UnsafeCode.UseBool(a == null); + UnsafeCode.UseBool(a != null); + } + public unsafe int* PointerCast(long* p) { return (int*)p; diff --git a/ICSharpCode.Decompiler.Tests/TestCases/Pretty/UnsafeCode.il b/ICSharpCode.Decompiler.Tests/TestCases/Pretty/UnsafeCode.il index 7bf84bf45..9b69878c6 100644 --- a/ICSharpCode.Decompiler.Tests/TestCases/Pretty/UnsafeCode.il +++ b/ICSharpCode.Decompiler.Tests/TestCases/Pretty/UnsafeCode.il @@ -10,7 +10,7 @@ .publickeytoken = (B7 7A 5C 56 19 34 E0 89 ) // .z\V.4.. .ver 4:0:0:0 } -.assembly aaldze1a +.assembly '40okgik0' { .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 @@ .hash algorithm 0x00008004 .ver 0:0:0:0 } -.module aaldze1a.dll -// MVID: {70B2C372-F51A-4F0B-B8F4-F20FC0522B70} +.module '40okgik0.dll' +// MVID: {668B0983-7797-493E-81D1-A040A24E86AA} .custom instance void [mscorlib]System.Security.UnverifiableCodeAttribute::.ctor() = ( 01 00 00 00 ) .imagebase 0x10000000 .file alignment 0x00000200 .stackreserve 0x00100000 .subsystem 0x0003 // WINDOWS_CUI .corflags 0x00000001 // ILONLY -// Image base: 0x015B0000 +// Image base: 0x00C20000 // =============== CLASS MEMBERS DECLARATION =================== @@ -59,6 +59,98 @@ IL_0007: ret } // end of method UnsafeCode::get_NullPointer + .method public hidebysig instance int32 + SizeOf() cil managed + { + // Code size 12 (0xc) + .maxstack 1 + .locals init (int32 V_0) + IL_0000: nop + IL_0001: sizeof ICSharpCode.Decompiler.Tests.TestCases.Pretty.UnsafeCode/SimpleStruct + IL_0007: stloc.0 + IL_0008: br.s IL_000a + + IL_000a: ldloc.0 + IL_000b: ret + } // end of method UnsafeCode::SizeOf + + .method private hidebysig static void UseBool(bool b) cil managed + { + // Code size 2 (0x2) + .maxstack 8 + IL_0000: nop + IL_0001: ret + } // end of method UnsafeCode::UseBool + + .method public hidebysig instance void + PointerComparison(int32* a, + float64* b) cil managed + { + // Code size 71 (0x47) + .maxstack 2 + IL_0000: nop + IL_0001: ldarg.1 + IL_0002: ldarg.2 + IL_0003: ceq + IL_0005: call void ICSharpCode.Decompiler.Tests.TestCases.Pretty.UnsafeCode::UseBool(bool) + IL_000a: nop + IL_000b: ldarg.1 + IL_000c: ldarg.2 + IL_000d: ceq + IL_000f: ldc.i4.0 + IL_0010: ceq + IL_0012: call void ICSharpCode.Decompiler.Tests.TestCases.Pretty.UnsafeCode::UseBool(bool) + IL_0017: nop + IL_0018: ldarg.1 + IL_0019: ldarg.2 + IL_001a: clt.un + IL_001c: call void ICSharpCode.Decompiler.Tests.TestCases.Pretty.UnsafeCode::UseBool(bool) + IL_0021: nop + IL_0022: ldarg.1 + IL_0023: ldarg.2 + IL_0024: cgt.un + IL_0026: call void ICSharpCode.Decompiler.Tests.TestCases.Pretty.UnsafeCode::UseBool(bool) + IL_002b: nop + IL_002c: ldarg.1 + IL_002d: ldarg.2 + IL_002e: cgt.un + IL_0030: ldc.i4.0 + IL_0031: ceq + IL_0033: call void ICSharpCode.Decompiler.Tests.TestCases.Pretty.UnsafeCode::UseBool(bool) + IL_0038: nop + IL_0039: ldarg.1 + IL_003a: ldarg.2 + IL_003b: clt.un + IL_003d: ldc.i4.0 + IL_003e: ceq + IL_0040: call void ICSharpCode.Decompiler.Tests.TestCases.Pretty.UnsafeCode::UseBool(bool) + IL_0045: nop + IL_0046: ret + } // end of method UnsafeCode::PointerComparison + + .method public hidebysig instance void + PointerComparisonWithNull(int32* a) cil managed + { + // Code size 27 (0x1b) + .maxstack 8 + IL_0000: nop + IL_0001: ldarg.1 + IL_0002: ldc.i4.0 + IL_0003: conv.u + IL_0004: ceq + IL_0006: call void ICSharpCode.Decompiler.Tests.TestCases.Pretty.UnsafeCode::UseBool(bool) + IL_000b: nop + IL_000c: ldarg.1 + IL_000d: ldc.i4.0 + IL_000e: conv.u + IL_000f: ceq + IL_0011: ldc.i4.0 + IL_0012: ceq + IL_0014: call void ICSharpCode.Decompiler.Tests.TestCases.Pretty.UnsafeCode::UseBool(bool) + IL_0019: nop + IL_001a: ret + } // end of method UnsafeCode::PointerComparisonWithNull + .method public hidebysig instance int32* PointerCast(int64* p) cil managed { diff --git a/ICSharpCode.Decompiler.Tests/TestCases/Pretty/UnsafeCode.opt.il b/ICSharpCode.Decompiler.Tests/TestCases/Pretty/UnsafeCode.opt.il index c628de3c4..5908d6786 100644 --- a/ICSharpCode.Decompiler.Tests/TestCases/Pretty/UnsafeCode.opt.il +++ b/ICSharpCode.Decompiler.Tests/TestCases/Pretty/UnsafeCode.opt.il @@ -10,7 +10,7 @@ .publickeytoken = (B7 7A 5C 56 19 34 E0 89 ) // .z\V.4.. .ver 4:0:0:0 } -.assembly puaa14mr +.assembly '0iyybovr' { .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 @@ .hash algorithm 0x00008004 .ver 0:0:0:0 } -.module puaa14mr.dll -// MVID: {CFE0F8E8-DA3C-494E-93C4-14BC506B54FF} +.module '0iyybovr.dll' +// MVID: {4E5B1C69-64A7-4276-A009-A657A9B697D4} .custom instance void [mscorlib]System.Security.UnverifiableCodeAttribute::.ctor() = ( 01 00 00 00 ) .imagebase 0x10000000 .file alignment 0x00000200 .stackreserve 0x00100000 .subsystem 0x0003 // WINDOWS_CUI .corflags 0x00000001 // ILONLY -// Image base: 0x014E0000 +// Image base: 0x02F80000 // =============== CLASS MEMBERS DECLARATION =================== @@ -53,6 +53,81 @@ IL_0002: ret } // end of method UnsafeCode::get_NullPointer + .method public hidebysig instance int32 + SizeOf() cil managed + { + // Code size 7 (0x7) + .maxstack 8 + IL_0000: sizeof ICSharpCode.Decompiler.Tests.TestCases.Pretty.UnsafeCode/SimpleStruct + IL_0006: ret + } // end of method UnsafeCode::SizeOf + + .method private hidebysig static void UseBool(bool b) cil managed + { + // Code size 1 (0x1) + .maxstack 8 + IL_0000: ret + } // end of method UnsafeCode::UseBool + + .method public hidebysig instance void + PointerComparison(int32* a, + float64* b) cil managed + { + // Code size 64 (0x40) + .maxstack 2 + IL_0000: ldarg.1 + IL_0001: ldarg.2 + IL_0002: ceq + IL_0004: call void ICSharpCode.Decompiler.Tests.TestCases.Pretty.UnsafeCode::UseBool(bool) + IL_0009: ldarg.1 + IL_000a: ldarg.2 + IL_000b: ceq + IL_000d: ldc.i4.0 + IL_000e: ceq + IL_0010: call void ICSharpCode.Decompiler.Tests.TestCases.Pretty.UnsafeCode::UseBool(bool) + IL_0015: ldarg.1 + IL_0016: ldarg.2 + IL_0017: clt.un + IL_0019: call void ICSharpCode.Decompiler.Tests.TestCases.Pretty.UnsafeCode::UseBool(bool) + IL_001e: ldarg.1 + IL_001f: ldarg.2 + IL_0020: cgt.un + IL_0022: call void ICSharpCode.Decompiler.Tests.TestCases.Pretty.UnsafeCode::UseBool(bool) + IL_0027: ldarg.1 + IL_0028: ldarg.2 + IL_0029: cgt.un + IL_002b: ldc.i4.0 + IL_002c: ceq + IL_002e: call void ICSharpCode.Decompiler.Tests.TestCases.Pretty.UnsafeCode::UseBool(bool) + IL_0033: ldarg.1 + IL_0034: ldarg.2 + IL_0035: clt.un + IL_0037: ldc.i4.0 + IL_0038: ceq + IL_003a: call void ICSharpCode.Decompiler.Tests.TestCases.Pretty.UnsafeCode::UseBool(bool) + IL_003f: ret + } // end of method UnsafeCode::PointerComparison + + .method public hidebysig instance void + PointerComparisonWithNull(int32* a) cil managed + { + // Code size 24 (0x18) + .maxstack 8 + IL_0000: ldarg.1 + IL_0001: ldc.i4.0 + IL_0002: conv.u + IL_0003: ceq + IL_0005: call void ICSharpCode.Decompiler.Tests.TestCases.Pretty.UnsafeCode::UseBool(bool) + IL_000a: ldarg.1 + IL_000b: ldc.i4.0 + IL_000c: conv.u + IL_000d: ceq + IL_000f: ldc.i4.0 + IL_0010: ceq + IL_0012: call void ICSharpCode.Decompiler.Tests.TestCases.Pretty.UnsafeCode::UseBool(bool) + IL_0017: ret + } // end of method UnsafeCode::PointerComparisonWithNull + .method public hidebysig instance int32* PointerCast(int64* p) cil managed { diff --git a/ICSharpCode.Decompiler.Tests/TestCases/Pretty/UnsafeCode.opt.roslyn.il b/ICSharpCode.Decompiler.Tests/TestCases/Pretty/UnsafeCode.opt.roslyn.il index bd5b99a4c..90719a725 100644 --- a/ICSharpCode.Decompiler.Tests/TestCases/Pretty/UnsafeCode.opt.roslyn.il +++ b/ICSharpCode.Decompiler.Tests/TestCases/Pretty/UnsafeCode.opt.roslyn.il @@ -25,14 +25,14 @@ .ver 0:0:0:0 } .module UnsafeCode.dll -// MVID: {858D67FE-2C39-4F0B-B696-FA10954BDC00} +// MVID: {98803778-6CDE-4C69-BDF2-64568153FD06} .custom instance void [mscorlib]System.Security.UnverifiableCodeAttribute::.ctor() = ( 01 00 00 00 ) .imagebase 0x10000000 .file alignment 0x00000200 .stackreserve 0x00100000 .subsystem 0x0003 // WINDOWS_CUI .corflags 0x00000001 // ILONLY -// Image base: 0x01270000 +// Image base: 0x02790000 // =============== CLASS MEMBERS DECLARATION =================== @@ -57,6 +57,81 @@ IL_0002: ret } // end of method UnsafeCode::get_NullPointer + .method public hidebysig instance int32 + SizeOf() cil managed + { + // Code size 7 (0x7) + .maxstack 8 + IL_0000: sizeof ICSharpCode.Decompiler.Tests.TestCases.Pretty.UnsafeCode/SimpleStruct + IL_0006: ret + } // end of method UnsafeCode::SizeOf + + .method private hidebysig static void UseBool(bool b) cil managed + { + // Code size 1 (0x1) + .maxstack 8 + IL_0000: ret + } // end of method UnsafeCode::UseBool + + .method public hidebysig instance void + PointerComparison(int32* a, + float64* b) cil managed + { + // Code size 64 (0x40) + .maxstack 2 + IL_0000: ldarg.1 + IL_0001: ldarg.2 + IL_0002: ceq + IL_0004: call void ICSharpCode.Decompiler.Tests.TestCases.Pretty.UnsafeCode::UseBool(bool) + IL_0009: ldarg.1 + IL_000a: ldarg.2 + IL_000b: ceq + IL_000d: ldc.i4.0 + IL_000e: ceq + IL_0010: call void ICSharpCode.Decompiler.Tests.TestCases.Pretty.UnsafeCode::UseBool(bool) + IL_0015: ldarg.1 + IL_0016: ldarg.2 + IL_0017: clt.un + IL_0019: call void ICSharpCode.Decompiler.Tests.TestCases.Pretty.UnsafeCode::UseBool(bool) + IL_001e: ldarg.1 + IL_001f: ldarg.2 + IL_0020: cgt.un + IL_0022: call void ICSharpCode.Decompiler.Tests.TestCases.Pretty.UnsafeCode::UseBool(bool) + IL_0027: ldarg.1 + IL_0028: ldarg.2 + IL_0029: cgt.un + IL_002b: ldc.i4.0 + IL_002c: ceq + IL_002e: call void ICSharpCode.Decompiler.Tests.TestCases.Pretty.UnsafeCode::UseBool(bool) + IL_0033: ldarg.1 + IL_0034: ldarg.2 + IL_0035: clt.un + IL_0037: ldc.i4.0 + IL_0038: ceq + IL_003a: call void ICSharpCode.Decompiler.Tests.TestCases.Pretty.UnsafeCode::UseBool(bool) + IL_003f: ret + } // end of method UnsafeCode::PointerComparison + + .method public hidebysig instance void + PointerComparisonWithNull(int32* a) cil managed + { + // Code size 24 (0x18) + .maxstack 8 + IL_0000: ldarg.1 + IL_0001: ldc.i4.0 + IL_0002: conv.u + IL_0003: ceq + IL_0005: call void ICSharpCode.Decompiler.Tests.TestCases.Pretty.UnsafeCode::UseBool(bool) + IL_000a: ldarg.1 + IL_000b: ldc.i4.0 + IL_000c: conv.u + IL_000d: ceq + IL_000f: ldc.i4.0 + IL_0010: ceq + IL_0012: call void ICSharpCode.Decompiler.Tests.TestCases.Pretty.UnsafeCode::UseBool(bool) + IL_0017: ret + } // end of method UnsafeCode::PointerComparisonWithNull + .method public hidebysig instance int32* PointerCast(int64* p) cil managed { diff --git a/ICSharpCode.Decompiler.Tests/TestCases/Pretty/UnsafeCode.roslyn.il b/ICSharpCode.Decompiler.Tests/TestCases/Pretty/UnsafeCode.roslyn.il index 8577e57aa..6e9de6b42 100644 --- a/ICSharpCode.Decompiler.Tests/TestCases/Pretty/UnsafeCode.roslyn.il +++ b/ICSharpCode.Decompiler.Tests/TestCases/Pretty/UnsafeCode.roslyn.il @@ -25,14 +25,14 @@ .ver 0:0:0:0 } .module UnsafeCode.dll -// MVID: {BCDFA7E7-0E94-44F0-8A8C-85049FECA738} +// MVID: {8E29CB23-0809-4825-9EB4-4274E16E25C8} .custom instance void [mscorlib]System.Security.UnverifiableCodeAttribute::.ctor() = ( 01 00 00 00 ) .imagebase 0x10000000 .file alignment 0x00000200 .stackreserve 0x00100000 .subsystem 0x0003 // WINDOWS_CUI .corflags 0x00000001 // ILONLY -// Image base: 0x01330000 +// Image base: 0x00690000 // =============== CLASS MEMBERS DECLARATION =================== @@ -63,6 +63,98 @@ IL_0007: ret } // end of method UnsafeCode::get_NullPointer + .method public hidebysig instance int32 + SizeOf() cil managed + { + // Code size 12 (0xc) + .maxstack 1 + .locals init (int32 V_0) + IL_0000: nop + IL_0001: sizeof ICSharpCode.Decompiler.Tests.TestCases.Pretty.UnsafeCode/SimpleStruct + IL_0007: stloc.0 + IL_0008: br.s IL_000a + + IL_000a: ldloc.0 + IL_000b: ret + } // end of method UnsafeCode::SizeOf + + .method private hidebysig static void UseBool(bool b) cil managed + { + // Code size 2 (0x2) + .maxstack 8 + IL_0000: nop + IL_0001: ret + } // end of method UnsafeCode::UseBool + + .method public hidebysig instance void + PointerComparison(int32* a, + float64* b) cil managed + { + // Code size 71 (0x47) + .maxstack 2 + IL_0000: nop + IL_0001: ldarg.1 + IL_0002: ldarg.2 + IL_0003: ceq + IL_0005: call void ICSharpCode.Decompiler.Tests.TestCases.Pretty.UnsafeCode::UseBool(bool) + IL_000a: nop + IL_000b: ldarg.1 + IL_000c: ldarg.2 + IL_000d: ceq + IL_000f: ldc.i4.0 + IL_0010: ceq + IL_0012: call void ICSharpCode.Decompiler.Tests.TestCases.Pretty.UnsafeCode::UseBool(bool) + IL_0017: nop + IL_0018: ldarg.1 + IL_0019: ldarg.2 + IL_001a: clt.un + IL_001c: call void ICSharpCode.Decompiler.Tests.TestCases.Pretty.UnsafeCode::UseBool(bool) + IL_0021: nop + IL_0022: ldarg.1 + IL_0023: ldarg.2 + IL_0024: cgt.un + IL_0026: call void ICSharpCode.Decompiler.Tests.TestCases.Pretty.UnsafeCode::UseBool(bool) + IL_002b: nop + IL_002c: ldarg.1 + IL_002d: ldarg.2 + IL_002e: cgt.un + IL_0030: ldc.i4.0 + IL_0031: ceq + IL_0033: call void ICSharpCode.Decompiler.Tests.TestCases.Pretty.UnsafeCode::UseBool(bool) + IL_0038: nop + IL_0039: ldarg.1 + IL_003a: ldarg.2 + IL_003b: clt.un + IL_003d: ldc.i4.0 + IL_003e: ceq + IL_0040: call void ICSharpCode.Decompiler.Tests.TestCases.Pretty.UnsafeCode::UseBool(bool) + IL_0045: nop + IL_0046: ret + } // end of method UnsafeCode::PointerComparison + + .method public hidebysig instance void + PointerComparisonWithNull(int32* a) cil managed + { + // Code size 27 (0x1b) + .maxstack 8 + IL_0000: nop + IL_0001: ldarg.1 + IL_0002: ldc.i4.0 + IL_0003: conv.u + IL_0004: ceq + IL_0006: call void ICSharpCode.Decompiler.Tests.TestCases.Pretty.UnsafeCode::UseBool(bool) + IL_000b: nop + IL_000c: ldarg.1 + IL_000d: ldc.i4.0 + IL_000e: conv.u + IL_000f: ceq + IL_0011: ldc.i4.0 + IL_0012: ceq + IL_0014: call void ICSharpCode.Decompiler.Tests.TestCases.Pretty.UnsafeCode::UseBool(bool) + IL_0019: nop + IL_001a: ret + } // end of method UnsafeCode::PointerComparisonWithNull + .method public hidebysig instance int32* PointerCast(int64* p) cil managed { diff --git a/ICSharpCode.Decompiler/CSharp/ExpressionBuilder.cs b/ICSharpCode.Decompiler/CSharp/ExpressionBuilder.cs index f5fbadee1..f504de3a4 100644 --- a/ICSharpCode.Decompiler/CSharp/ExpressionBuilder.cs +++ b/ICSharpCode.Decompiler/CSharp/ExpressionBuilder.cs @@ -487,6 +487,20 @@ namespace ICSharpCode.Decompiler.CSharp return right; } } + // Handle comparisons between unsafe pointers and null: + if (left.Type.Kind == TypeKind.Pointer && inst.Right.MatchLdcI(0)) { + negateOutput = false; + right = new NullReferenceExpression().WithRR(new ConstantResolveResult(SpecialType.NullType, null)) + .WithILInstruction(inst.Right); + return CreateBuiltinBinaryOperator(left, inst.Kind.ToBinaryOperatorType(), right) + .WithILInstruction(inst); + } else if (right.Type.Kind == TypeKind.Pointer && inst.Left.MatchLdcI(0)) { + negateOutput = false; + left = new NullReferenceExpression().WithRR(new ConstantResolveResult(SpecialType.NullType, null)) + .WithILInstruction(inst.Left); + return CreateBuiltinBinaryOperator(left, inst.Kind.ToBinaryOperatorType(), right) + .WithILInstruction(inst); + } // Special case comparisons with enum and char literals left = AdjustConstantExpressionToType(left, right.Type); @@ -497,12 +511,8 @@ namespace ICSharpCode.Decompiler.CSharp { // When comparing a delegate with null, the C# compiler generates a reference comparison. negateOutput = false; - return new BinaryOperatorExpression(left.Expression, inst.Kind.ToBinaryOperatorType(), right.Expression) - .WithILInstruction(inst) - .WithRR(new OperatorResolveResult( - compilation.FindType(KnownTypeCode.Boolean), - inst.Kind == ComparisonKind.Equality ? ExpressionType.Equal : ExpressionType.NotEqual, - left.ResolveResult, right.ResolveResult)); + return CreateBuiltinBinaryOperator(left, inst.Kind.ToBinaryOperatorType(), right) + .WithILInstruction(inst); } var rr = resolver.ResolveBinaryOperator(inst.Kind.ToBinaryOperatorType(), left.ResolveResult, right.ResolveResult) @@ -514,7 +524,15 @@ namespace ICSharpCode.Decompiler.CSharp if (inst.InputType == StackType.O) { targetType = compilation.FindType(KnownTypeCode.Object); } else { - targetType = TypeUtils.GetLargerType(NullableType.GetUnderlyingType(left.Type), NullableType.GetUnderlyingType(right.Type)); + var leftUType = NullableType.GetUnderlyingType(left.Type); + var rightUType = NullableType.GetUnderlyingType(right.Type); + if (leftUType.GetStackType() == inst.InputType) { + targetType = leftUType; + } else if (rightUType.GetStackType() == inst.InputType) { + targetType = rightUType; + } else { + targetType = compilation.FindType(inst.InputType.ToKnownTypeCode(leftUType.GetSign())); + } } if (inst.IsLifted) { targetType = NullableType.Create(compilation, targetType); @@ -542,6 +560,17 @@ namespace ICSharpCode.Decompiler.CSharp .WithILInstruction(inst) .WithRR(rr); } + + ExpressionWithResolveResult CreateBuiltinBinaryOperator( + TranslatedExpression left, BinaryOperatorType type, TranslatedExpression right, + bool checkForOverflow = false) + { + return new BinaryOperatorExpression(left.Expression, type, right.Expression) + .WithRR(new OperatorResolveResult( + compilation.FindType(KnownTypeCode.Boolean), + BinaryOperatorExpression.GetLinqNodeType(type, checkForOverflow), + left.ResolveResult, right.ResolveResult)); + } /// /// Handle Comp instruction, operators other than equality/inequality. @@ -551,6 +580,12 @@ namespace ICSharpCode.Decompiler.CSharp var op = inst.Kind.ToBinaryOperatorType(); var left = Translate(inst.Left); var right = Translate(inst.Right); + + if (left.Type.Kind == TypeKind.Pointer && right.Type.Kind == TypeKind.Pointer) { + return CreateBuiltinBinaryOperator(left, op, right) + .WithILInstruction(inst); + } + left = PrepareArithmeticArgument(left, inst.InputType, inst.Sign, inst.IsLifted); right = PrepareArithmeticArgument(right, inst.InputType, inst.Sign, inst.IsLifted); diff --git a/ICSharpCode.Decompiler/CSharp/Transforms/IntroduceUnsafeModifier.cs b/ICSharpCode.Decompiler/CSharp/Transforms/IntroduceUnsafeModifier.cs index fb3d52b6f..cf759f9e2 100644 --- a/ICSharpCode.Decompiler/CSharp/Transforms/IntroduceUnsafeModifier.cs +++ b/ICSharpCode.Decompiler/CSharp/Transforms/IntroduceUnsafeModifier.cs @@ -52,7 +52,14 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms base.VisitPointerReferenceExpression(pointerReferenceExpression); return true; } - + + public override bool VisitSizeOfExpression(SizeOfExpression sizeOfExpression) + { + // C# sizeof(MyStruct) requires unsafe{} + // (not for sizeof(int), but that gets constant-folded and thus decompiled to 4) + return true; + } + public override bool VisitComposedType(ComposedType composedType) { if (composedType.PointerRank > 0)