From 3fb7c71f8a369c24bce01c671c4bb57288d908a1 Mon Sep 17 00:00:00 2001 From: Chicken-Bones Date: Tue, 12 Jun 2018 18:39:22 +1000 Subject: [PATCH] Improve control flow decompilation in ConditionDetection --- .../TestCases/Pretty/ExceptionHandling.cs | 86 +++ .../TestCases/Pretty/ExceptionHandling.il | 372 +++++++++ .../TestCases/Pretty/ExceptionHandling.opt.il | 227 ++++++ .../Pretty/ExceptionHandling.opt.roslyn.il | 259 +++++++ .../Pretty/ExceptionHandling.roslyn.il | 360 +++++++++ .../TestCases/Pretty/Loops.cs | 195 +++-- .../TestCases/Pretty/Loops.il | 487 ++++++++++++ .../TestCases/Pretty/Loops.mcs.il | 295 +++++++ .../TestCases/Pretty/Loops.opt.il | 308 ++++++++ .../TestCases/Pretty/Loops.opt.mcs.il | 295 +++++++ .../TestCases/Pretty/Loops.opt.roslyn.il | 305 ++++++++ .../TestCases/Pretty/Loops.roslyn.il | 483 ++++++++++++ .../TestCases/Pretty/ShortCircuit.cs | 114 ++- .../TestCases/Pretty/ShortCircuit.il | 647 +++++++++++++++- .../TestCases/Pretty/ShortCircuit.opt.il | 441 ++++++++++- .../Pretty/ShortCircuit.opt.roslyn.il | 441 ++++++++++- .../TestCases/Pretty/ShortCircuit.roslyn.il | 609 ++++++++++++++- .../IL/ControlFlow/ConditionDetection.cs | 720 ++++++++++++------ .../IL/Transforms/HighLevelLoopTransform.cs | 68 +- 19 files changed, 6393 insertions(+), 319 deletions(-) diff --git a/ICSharpCode.Decompiler.Tests/TestCases/Pretty/ExceptionHandling.cs b/ICSharpCode.Decompiler.Tests/TestCases/Pretty/ExceptionHandling.cs index 65c9b0e12..06b071f85 100644 --- a/ICSharpCode.Decompiler.Tests/TestCases/Pretty/ExceptionHandling.cs +++ b/ICSharpCode.Decompiler.Tests/TestCases/Pretty/ExceptionHandling.cs @@ -195,5 +195,91 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty throw new Exception(); } } + +#if ROSLYN || !OPT + // TODO Non-Roslyn compilers create a second while loop inside the try, by inverting the if + // This is fixed in the non-optimised version by the enabling the RemoveDeadCode flag + //public bool EarlyExitInLoopTry() + //{ + // while (true) { + // try { + // while (B(0)) { + // Console.WriteLine(); + // } + // + // return false; + // } catch { + // } + // } + //} + public bool EarlyExitInLoopTry() + { + while (true) { + try { + if (!B(0)) { + return false; + } + + Console.WriteLine(); + } catch { + } + } + } +#endif + + public bool ComplexConditionalReturnInThrow() + { + try { + if (B(0)) { + if (B(1)) { + Console.WriteLine("0 && 1"); + return B(2); + } + + if (B(3)) { + Console.WriteLine("0 && 3"); + return !B(2); + } + + Console.WriteLine("0"); + } + + Console.WriteLine("End Try"); + + } catch { + try { + try { + if (((B(0) || B(1)) && B(2)) || B(3)) { + return B(4) && !B(5); + } + if (B(6) || B(7)) { + return B(8) || B(9); + } + } catch { + Console.WriteLine("Catch2"); + } + return B(10) && B(11); + } catch { + Console.WriteLine("Catch"); + } finally { + Console.WriteLine("Finally"); + } + } + return false; + } + + public void AppropriateLockExit() + { + int num = 0; + lock (this) { + if (num <= 256) { + Console.WriteLine(0); + } else if (num <= 1024) { + Console.WriteLine(1); + } else if (num <= 16384) { + Console.WriteLine(2); + } + } + } } } \ No newline at end of file diff --git a/ICSharpCode.Decompiler.Tests/TestCases/Pretty/ExceptionHandling.il b/ICSharpCode.Decompiler.Tests/TestCases/Pretty/ExceptionHandling.il index da21e9e03..23796659f 100644 --- a/ICSharpCode.Decompiler.Tests/TestCases/Pretty/ExceptionHandling.il +++ b/ICSharpCode.Decompiler.Tests/TestCases/Pretty/ExceptionHandling.il @@ -434,6 +434,378 @@ IL_000c: br.s IL_000c } // end of method ExceptionHandling::ThrowInFinally + .method public hidebysig instance bool + EarlyExitInLoopTry() cil managed + { + // Code size 44 (0x2c) + .maxstack 2 + .locals init (bool V_0, + bool V_1) + IL_0000: nop + IL_0001: br.s IL_0025 + + IL_0003: nop + .try + { + IL_0004: nop + IL_0005: ldarg.0 + IL_0006: ldc.i4.0 + IL_0007: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ExceptionHandling::B(int32) + IL_000c: stloc.1 + IL_000d: ldloc.1 + IL_000e: brtrue.s IL_0015 + + IL_0010: nop + IL_0011: ldc.i4.0 + IL_0012: stloc.0 + IL_0013: leave.s IL_0029 + + IL_0015: call void [mscorlib]System.Console::WriteLine() + IL_001a: nop + IL_001b: nop + IL_001c: leave.s IL_0023 + + } // end .try + catch [mscorlib]System.Object + { + IL_001e: pop + IL_001f: nop + IL_0020: nop + IL_0021: leave.s IL_0023 + + } // end handler + IL_0023: nop + IL_0024: nop + IL_0025: ldc.i4.1 + IL_0026: stloc.1 + IL_0027: br.s IL_0003 + + IL_0029: nop + IL_002a: ldloc.0 + IL_002b: ret + } // end of method ExceptionHandling::EarlyExitInLoopTry + + .method public hidebysig instance bool + ComplexConditionalReturnInThrow() cil managed + { + // Code size 348 (0x15c) + .maxstack 2 + .locals init (bool V_0, + bool V_1) + IL_0000: nop + .try + { + IL_0001: nop + IL_0002: ldarg.0 + IL_0003: ldc.i4.0 + IL_0004: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ExceptionHandling::B(int32) + IL_0009: ldc.i4.0 + IL_000a: ceq + IL_000c: stloc.1 + IL_000d: ldloc.1 + IL_000e: brtrue.s IL_006e + + IL_0010: nop + IL_0011: ldarg.0 + IL_0012: ldc.i4.1 + IL_0013: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ExceptionHandling::B(int32) + IL_0018: ldc.i4.0 + IL_0019: ceq + IL_001b: stloc.1 + IL_001c: ldloc.1 + IL_001d: brtrue.s IL_0038 + + IL_001f: nop + IL_0020: ldstr "0 && 1" + IL_0025: call void [mscorlib]System.Console::WriteLine(string) + IL_002a: nop + IL_002b: ldarg.0 + IL_002c: ldc.i4.2 + IL_002d: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ExceptionHandling::B(int32) + IL_0032: stloc.0 + IL_0033: leave IL_0159 + + IL_0038: ldarg.0 + IL_0039: ldc.i4.3 + IL_003a: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ExceptionHandling::B(int32) + IL_003f: ldc.i4.0 + IL_0040: ceq + IL_0042: stloc.1 + IL_0043: ldloc.1 + IL_0044: brtrue.s IL_0062 + + IL_0046: nop + IL_0047: ldstr "0 && 3" + IL_004c: call void [mscorlib]System.Console::WriteLine(string) + IL_0051: nop + IL_0052: ldarg.0 + IL_0053: ldc.i4.2 + IL_0054: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ExceptionHandling::B(int32) + IL_0059: ldc.i4.0 + IL_005a: ceq + IL_005c: stloc.0 + IL_005d: leave IL_0159 + + IL_0062: ldstr "0" + IL_0067: call void [mscorlib]System.Console::WriteLine(string) + IL_006c: nop + IL_006d: nop + IL_006e: ldstr "End Try" + IL_0073: call void [mscorlib]System.Console::WriteLine(string) + IL_0078: nop + IL_0079: nop + IL_007a: leave IL_0154 + + } // end .try + catch [mscorlib]System.Object + { + IL_007f: pop + IL_0080: nop + .try + { + .try + { + IL_0081: nop + .try + { + IL_0082: nop + IL_0083: ldarg.0 + IL_0084: ldc.i4.0 + IL_0085: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ExceptionHandling::B(int32) + IL_008a: brtrue.s IL_0095 + + IL_008c: ldarg.0 + IL_008d: ldc.i4.1 + IL_008e: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ExceptionHandling::B(int32) + IL_0093: brfalse.s IL_009e + + IL_0095: ldarg.0 + IL_0096: ldc.i4.2 + IL_0097: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ExceptionHandling::B(int32) + IL_009c: brtrue.s IL_00aa + + IL_009e: ldarg.0 + IL_009f: ldc.i4.3 + IL_00a0: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ExceptionHandling::B(int32) + IL_00a5: ldc.i4.0 + IL_00a6: ceq + IL_00a8: br.s IL_00ab + + IL_00aa: ldc.i4.0 + IL_00ab: nop + IL_00ac: stloc.1 + IL_00ad: ldloc.1 + IL_00ae: brtrue.s IL_00ce + + IL_00b0: nop + IL_00b1: ldarg.0 + IL_00b2: ldc.i4.4 + IL_00b3: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ExceptionHandling::B(int32) + IL_00b8: brfalse.s IL_00c6 + + IL_00ba: ldarg.0 + IL_00bb: ldc.i4.5 + IL_00bc: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ExceptionHandling::B(int32) + IL_00c1: ldc.i4.0 + IL_00c2: ceq + IL_00c4: br.s IL_00c7 + + IL_00c6: ldc.i4.0 + IL_00c7: nop + IL_00c8: stloc.0 + IL_00c9: leave IL_0159 + + IL_00ce: ldarg.0 + IL_00cf: ldc.i4.6 + IL_00d0: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ExceptionHandling::B(int32) + IL_00d5: brtrue.s IL_00e3 + + IL_00d7: ldarg.0 + IL_00d8: ldc.i4.7 + IL_00d9: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ExceptionHandling::B(int32) + IL_00de: ldc.i4.0 + IL_00df: ceq + IL_00e1: br.s IL_00e4 + + IL_00e3: ldc.i4.0 + IL_00e4: nop + IL_00e5: stloc.1 + IL_00e6: ldloc.1 + IL_00e7: brtrue.s IL_0102 + + IL_00e9: nop + IL_00ea: ldarg.0 + IL_00eb: ldc.i4.8 + IL_00ec: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ExceptionHandling::B(int32) + IL_00f1: brtrue.s IL_00fd + + IL_00f3: ldarg.0 + IL_00f4: ldc.i4.s 9 + IL_00f6: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ExceptionHandling::B(int32) + IL_00fb: br.s IL_00fe + + IL_00fd: ldc.i4.1 + IL_00fe: nop + IL_00ff: stloc.0 + IL_0100: leave.s IL_0159 + + IL_0102: nop + IL_0103: leave.s IL_0115 + + } // end .try + catch [mscorlib]System.Object + { + IL_0105: pop + IL_0106: nop + IL_0107: ldstr "Catch2" + IL_010c: call void [mscorlib]System.Console::WriteLine(string) + IL_0111: nop + IL_0112: nop + IL_0113: leave.s IL_0115 + + } // end handler + IL_0115: nop + IL_0116: ldarg.0 + IL_0117: ldc.i4.s 10 + IL_0119: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ExceptionHandling::B(int32) + IL_011e: brfalse.s IL_012a + + IL_0120: ldarg.0 + IL_0121: ldc.i4.s 11 + IL_0123: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ExceptionHandling::B(int32) + IL_0128: br.s IL_012b + + IL_012a: ldc.i4.0 + IL_012b: nop + IL_012c: stloc.0 + IL_012d: leave.s IL_0159 + + } // end .try + catch [mscorlib]System.Object + { + IL_012f: pop + IL_0130: nop + IL_0131: ldstr "Catch" + IL_0136: call void [mscorlib]System.Console::WriteLine(string) + IL_013b: nop + IL_013c: nop + IL_013d: leave.s IL_013f + + } // end handler + IL_013f: nop + IL_0140: leave.s IL_0150 + + } // end .try + finally + { + IL_0142: nop + IL_0143: ldstr "Finally" + IL_0148: call void [mscorlib]System.Console::WriteLine(string) + IL_014d: nop + IL_014e: nop + IL_014f: endfinally + } // end handler + IL_0150: nop + IL_0151: nop + IL_0152: leave.s IL_0154 + + } // end handler + IL_0154: nop + IL_0155: ldc.i4.0 + IL_0156: stloc.0 + IL_0157: br.s IL_0159 + + IL_0159: nop + IL_015a: ldloc.0 + IL_015b: ret + } // end of method ExceptionHandling::ComplexConditionalReturnInThrow + + .method public hidebysig instance void + AppropriateLockExit() cil managed + { + // Code size 105 (0x69) + .maxstack 2 + .locals init (int32 V_0, + bool V_1, + class ICSharpCode.Decompiler.Tests.TestCases.Pretty.ExceptionHandling V_2, + bool V_3) + IL_0000: nop + IL_0001: ldc.i4.0 + IL_0002: stloc.0 + IL_0003: ldc.i4.0 + IL_0004: stloc.1 + .try + { + IL_0005: ldarg.0 + IL_0006: dup + IL_0007: stloc.2 + IL_0008: ldloca.s V_1 + IL_000a: call void [mscorlib]System.Threading.Monitor::Enter(object, + bool&) + IL_000f: nop + IL_0010: nop + IL_0011: ldloc.0 + IL_0012: ldc.i4 0x100 + IL_0017: cgt + IL_0019: stloc.3 + IL_001a: ldloc.3 + IL_001b: brtrue.s IL_0028 + + IL_001d: nop + IL_001e: ldc.i4.0 + IL_001f: call void [mscorlib]System.Console::WriteLine(int32) + IL_0024: nop + IL_0025: nop + IL_0026: br.s IL_0054 + + IL_0028: ldloc.0 + IL_0029: ldc.i4 0x400 + IL_002e: cgt + IL_0030: stloc.3 + IL_0031: ldloc.3 + IL_0032: brtrue.s IL_003f + + IL_0034: nop + IL_0035: ldc.i4.1 + IL_0036: call void [mscorlib]System.Console::WriteLine(int32) + IL_003b: nop + IL_003c: nop + IL_003d: br.s IL_0054 + + IL_003f: ldloc.0 + IL_0040: ldc.i4 0x4000 + IL_0045: cgt + IL_0047: stloc.3 + IL_0048: ldloc.3 + IL_0049: brtrue.s IL_0054 + + IL_004b: nop + IL_004c: ldc.i4.2 + IL_004d: call void [mscorlib]System.Console::WriteLine(int32) + IL_0052: nop + IL_0053: nop + IL_0054: nop + IL_0055: leave.s IL_0067 + + } // end .try + finally + { + IL_0057: ldloc.1 + IL_0058: ldc.i4.0 + IL_0059: ceq + IL_005b: stloc.3 + IL_005c: ldloc.3 + IL_005d: brtrue.s IL_0066 + + IL_005f: ldloc.2 + IL_0060: call void [mscorlib]System.Threading.Monitor::Exit(object) + IL_0065: nop + IL_0066: endfinally + } // end handler + IL_0067: nop + IL_0068: ret + } // end of method ExceptionHandling::AppropriateLockExit + .method family hidebysig specialname rtspecialname instance void .ctor() cil managed { diff --git a/ICSharpCode.Decompiler.Tests/TestCases/Pretty/ExceptionHandling.opt.il b/ICSharpCode.Decompiler.Tests/TestCases/Pretty/ExceptionHandling.opt.il index 1c840804b..5aec1a2c1 100644 --- a/ICSharpCode.Decompiler.Tests/TestCases/Pretty/ExceptionHandling.opt.il +++ b/ICSharpCode.Decompiler.Tests/TestCases/Pretty/ExceptionHandling.opt.il @@ -337,6 +337,233 @@ IL_0008: br.s IL_0008 } // end of method ExceptionHandling::ThrowInFinally + .method public hidebysig instance bool + ComplexConditionalReturnInThrow() cil managed + { + // Code size 275 (0x113) + .maxstack 2 + .locals init (bool V_0) + .try + { + IL_0000: ldarg.0 + IL_0001: ldc.i4.0 + IL_0002: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ExceptionHandling::B(int32) + IL_0007: brfalse.s IL_0056 + + IL_0009: ldarg.0 + IL_000a: ldc.i4.1 + IL_000b: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ExceptionHandling::B(int32) + IL_0010: brfalse.s IL_0029 + + IL_0012: ldstr "0 && 1" + IL_0017: call void [mscorlib]System.Console::WriteLine(string) + IL_001c: ldarg.0 + IL_001d: ldc.i4.2 + IL_001e: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ExceptionHandling::B(int32) + IL_0023: stloc.0 + IL_0024: leave IL_0111 + + IL_0029: ldarg.0 + IL_002a: ldc.i4.3 + IL_002b: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ExceptionHandling::B(int32) + IL_0030: brfalse.s IL_004c + + IL_0032: ldstr "0 && 3" + IL_0037: call void [mscorlib]System.Console::WriteLine(string) + IL_003c: ldarg.0 + IL_003d: ldc.i4.2 + IL_003e: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ExceptionHandling::B(int32) + IL_0043: ldc.i4.0 + IL_0044: ceq + IL_0046: stloc.0 + IL_0047: leave IL_0111 + + IL_004c: ldstr "0" + IL_0051: call void [mscorlib]System.Console::WriteLine(string) + IL_0056: ldstr "End Try" + IL_005b: call void [mscorlib]System.Console::WriteLine(string) + IL_0060: leave IL_010f + + } // end .try + catch [mscorlib]System.Object + { + IL_0065: pop + .try + { + .try + { + .try + { + IL_0066: ldarg.0 + IL_0067: ldc.i4.0 + IL_0068: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ExceptionHandling::B(int32) + IL_006d: brtrue.s IL_0078 + + IL_006f: ldarg.0 + IL_0070: ldc.i4.1 + IL_0071: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ExceptionHandling::B(int32) + IL_0076: brfalse.s IL_0081 + + IL_0078: ldarg.0 + IL_0079: ldc.i4.2 + IL_007a: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ExceptionHandling::B(int32) + IL_007f: brtrue.s IL_008a + + IL_0081: ldarg.0 + IL_0082: ldc.i4.3 + IL_0083: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ExceptionHandling::B(int32) + IL_0088: brfalse.s IL_00a3 + + IL_008a: ldarg.0 + IL_008b: ldc.i4.4 + IL_008c: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ExceptionHandling::B(int32) + IL_0091: brfalse.s IL_009f + + IL_0093: ldarg.0 + IL_0094: ldc.i4.5 + IL_0095: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ExceptionHandling::B(int32) + IL_009a: ldc.i4.0 + IL_009b: ceq + IL_009d: br.s IL_00a0 + + IL_009f: ldc.i4.0 + IL_00a0: stloc.0 + IL_00a1: leave.s IL_0111 + + IL_00a3: ldarg.0 + IL_00a4: ldc.i4.6 + IL_00a5: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ExceptionHandling::B(int32) + IL_00aa: brtrue.s IL_00b5 + + IL_00ac: ldarg.0 + IL_00ad: ldc.i4.7 + IL_00ae: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ExceptionHandling::B(int32) + IL_00b3: brfalse.s IL_00cc + + IL_00b5: ldarg.0 + IL_00b6: ldc.i4.8 + IL_00b7: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ExceptionHandling::B(int32) + IL_00bc: brtrue.s IL_00c8 + + IL_00be: ldarg.0 + IL_00bf: ldc.i4.s 9 + IL_00c1: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ExceptionHandling::B(int32) + IL_00c6: br.s IL_00c9 + + IL_00c8: ldc.i4.1 + IL_00c9: stloc.0 + IL_00ca: leave.s IL_0111 + + IL_00cc: leave.s IL_00db + + } // end .try + catch [mscorlib]System.Object + { + IL_00ce: pop + IL_00cf: ldstr "Catch2" + IL_00d4: call void [mscorlib]System.Console::WriteLine(string) + IL_00d9: leave.s IL_00db + + } // end handler + IL_00db: ldarg.0 + IL_00dc: ldc.i4.s 10 + IL_00de: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ExceptionHandling::B(int32) + IL_00e3: brfalse.s IL_00ef + + IL_00e5: ldarg.0 + IL_00e6: ldc.i4.s 11 + IL_00e8: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ExceptionHandling::B(int32) + IL_00ed: br.s IL_00f0 + + IL_00ef: ldc.i4.0 + IL_00f0: stloc.0 + IL_00f1: leave.s IL_0111 + + } // end .try + catch [mscorlib]System.Object + { + IL_00f3: pop + IL_00f4: ldstr "Catch" + IL_00f9: call void [mscorlib]System.Console::WriteLine(string) + IL_00fe: leave.s IL_0100 + + } // end handler + IL_0100: leave.s IL_010d + + } // end .try + finally + { + IL_0102: ldstr "Finally" + IL_0107: call void [mscorlib]System.Console::WriteLine(string) + IL_010c: endfinally + } // end handler + IL_010d: leave.s IL_010f + + } // end handler + IL_010f: ldc.i4.0 + IL_0110: ret + + IL_0111: ldloc.0 + IL_0112: ret + } // end of method ExceptionHandling::ComplexConditionalReturnInThrow + + .method public hidebysig instance void + AppropriateLockExit() cil managed + { + // Code size 73 (0x49) + .maxstack 2 + .locals init (int32 V_0, + bool V_1, + class ICSharpCode.Decompiler.Tests.TestCases.Pretty.ExceptionHandling V_2) + IL_0000: ldc.i4.0 + IL_0001: stloc.0 + IL_0002: ldc.i4.0 + IL_0003: stloc.1 + .try + { + IL_0004: ldarg.0 + IL_0005: dup + IL_0006: stloc.2 + IL_0007: ldloca.s V_1 + IL_0009: call void [mscorlib]System.Threading.Monitor::Enter(object, + bool&) + IL_000e: ldloc.0 + IL_000f: ldc.i4 0x100 + IL_0014: bgt.s IL_001e + + IL_0016: ldc.i4.0 + IL_0017: call void [mscorlib]System.Console::WriteLine(int32) + IL_001c: br.s IL_003c + + IL_001e: ldloc.0 + IL_001f: ldc.i4 0x400 + IL_0024: bgt.s IL_002e + + IL_0026: ldc.i4.1 + IL_0027: call void [mscorlib]System.Console::WriteLine(int32) + IL_002c: br.s IL_003c + + IL_002e: ldloc.0 + IL_002f: ldc.i4 0x4000 + IL_0034: bgt.s IL_003c + + IL_0036: ldc.i4.2 + IL_0037: call void [mscorlib]System.Console::WriteLine(int32) + IL_003c: leave.s IL_0048 + + } // end .try + finally + { + IL_003e: ldloc.1 + IL_003f: brfalse.s IL_0047 + + IL_0041: ldloc.2 + IL_0042: call void [mscorlib]System.Threading.Monitor::Exit(object) + IL_0047: endfinally + } // end handler + IL_0048: ret + } // end of method ExceptionHandling::AppropriateLockExit + .method family hidebysig specialname rtspecialname instance void .ctor() cil managed { diff --git a/ICSharpCode.Decompiler.Tests/TestCases/Pretty/ExceptionHandling.opt.roslyn.il b/ICSharpCode.Decompiler.Tests/TestCases/Pretty/ExceptionHandling.opt.roslyn.il index 6ea9bd327..b9af94a41 100644 --- a/ICSharpCode.Decompiler.Tests/TestCases/Pretty/ExceptionHandling.opt.roslyn.il +++ b/ICSharpCode.Decompiler.Tests/TestCases/Pretty/ExceptionHandling.opt.roslyn.il @@ -689,6 +689,265 @@ IL_0008: br.s IL_0008 } // end of method ExceptionHandling::ThrowInFinally + .method public hidebysig instance bool + EarlyExitInLoopTry() cil managed + { + // Code size 26 (0x1a) + .maxstack 2 + .locals init (bool V_0) + IL_0000: nop + .try + { + IL_0001: ldarg.0 + IL_0002: ldc.i4.0 + IL_0003: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ExceptionHandling::B(int32) + IL_0008: brtrue.s IL_000e + + IL_000a: ldc.i4.0 + IL_000b: stloc.0 + IL_000c: leave.s IL_0018 + + IL_000e: call void [mscorlib]System.Console::WriteLine() + IL_0013: leave.s IL_0000 + + } // end .try + catch [mscorlib]System.Object + { + IL_0015: pop + IL_0016: leave.s IL_0000 + + } // end handler + IL_0018: ldloc.0 + IL_0019: ret + } // end of method ExceptionHandling::EarlyExitInLoopTry + + .method public hidebysig instance bool + ComplexConditionalReturnInThrow() cil managed + { + // Code size 275 (0x113) + .maxstack 2 + .locals init (bool V_0) + .try + { + IL_0000: ldarg.0 + IL_0001: ldc.i4.0 + IL_0002: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ExceptionHandling::B(int32) + IL_0007: brfalse.s IL_0056 + + IL_0009: ldarg.0 + IL_000a: ldc.i4.1 + IL_000b: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ExceptionHandling::B(int32) + IL_0010: brfalse.s IL_0029 + + IL_0012: ldstr "0 && 1" + IL_0017: call void [mscorlib]System.Console::WriteLine(string) + IL_001c: ldarg.0 + IL_001d: ldc.i4.2 + IL_001e: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ExceptionHandling::B(int32) + IL_0023: stloc.0 + IL_0024: leave IL_0111 + + IL_0029: ldarg.0 + IL_002a: ldc.i4.3 + IL_002b: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ExceptionHandling::B(int32) + IL_0030: brfalse.s IL_004c + + IL_0032: ldstr "0 && 3" + IL_0037: call void [mscorlib]System.Console::WriteLine(string) + IL_003c: ldarg.0 + IL_003d: ldc.i4.2 + IL_003e: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ExceptionHandling::B(int32) + IL_0043: ldc.i4.0 + IL_0044: ceq + IL_0046: stloc.0 + IL_0047: leave IL_0111 + + IL_004c: ldstr "0" + IL_0051: call void [mscorlib]System.Console::WriteLine(string) + IL_0056: ldstr "End Try" + IL_005b: call void [mscorlib]System.Console::WriteLine(string) + IL_0060: leave IL_010f + + } // end .try + catch [mscorlib]System.Object + { + IL_0065: pop + .try + { + .try + { + .try + { + IL_0066: ldarg.0 + IL_0067: ldc.i4.0 + IL_0068: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ExceptionHandling::B(int32) + IL_006d: brtrue.s IL_0078 + + IL_006f: ldarg.0 + IL_0070: ldc.i4.1 + IL_0071: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ExceptionHandling::B(int32) + IL_0076: brfalse.s IL_0081 + + IL_0078: ldarg.0 + IL_0079: ldc.i4.2 + IL_007a: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ExceptionHandling::B(int32) + IL_007f: brtrue.s IL_008a + + IL_0081: ldarg.0 + IL_0082: ldc.i4.3 + IL_0083: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ExceptionHandling::B(int32) + IL_0088: brfalse.s IL_00a3 + + IL_008a: ldarg.0 + IL_008b: ldc.i4.4 + IL_008c: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ExceptionHandling::B(int32) + IL_0091: brfalse.s IL_009f + + IL_0093: ldarg.0 + IL_0094: ldc.i4.5 + IL_0095: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ExceptionHandling::B(int32) + IL_009a: ldc.i4.0 + IL_009b: ceq + IL_009d: br.s IL_00a0 + + IL_009f: ldc.i4.0 + IL_00a0: stloc.0 + IL_00a1: leave.s IL_0111 + + IL_00a3: ldarg.0 + IL_00a4: ldc.i4.6 + IL_00a5: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ExceptionHandling::B(int32) + IL_00aa: brtrue.s IL_00b5 + + IL_00ac: ldarg.0 + IL_00ad: ldc.i4.7 + IL_00ae: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ExceptionHandling::B(int32) + IL_00b3: brfalse.s IL_00cc + + IL_00b5: ldarg.0 + IL_00b6: ldc.i4.8 + IL_00b7: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ExceptionHandling::B(int32) + IL_00bc: brtrue.s IL_00c8 + + IL_00be: ldarg.0 + IL_00bf: ldc.i4.s 9 + IL_00c1: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ExceptionHandling::B(int32) + IL_00c6: br.s IL_00c9 + + IL_00c8: ldc.i4.1 + IL_00c9: stloc.0 + IL_00ca: leave.s IL_0111 + + IL_00cc: leave.s IL_00db + + } // end .try + catch [mscorlib]System.Object + { + IL_00ce: pop + IL_00cf: ldstr "Catch2" + IL_00d4: call void [mscorlib]System.Console::WriteLine(string) + IL_00d9: leave.s IL_00db + + } // end handler + IL_00db: ldarg.0 + IL_00dc: ldc.i4.s 10 + IL_00de: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ExceptionHandling::B(int32) + IL_00e3: brfalse.s IL_00ef + + IL_00e5: ldarg.0 + IL_00e6: ldc.i4.s 11 + IL_00e8: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ExceptionHandling::B(int32) + IL_00ed: br.s IL_00f0 + + IL_00ef: ldc.i4.0 + IL_00f0: stloc.0 + IL_00f1: leave.s IL_0111 + + } // end .try + catch [mscorlib]System.Object + { + IL_00f3: pop + IL_00f4: ldstr "Catch" + IL_00f9: call void [mscorlib]System.Console::WriteLine(string) + IL_00fe: leave.s IL_0100 + + } // end handler + IL_0100: leave.s IL_010d + + } // end .try + finally + { + IL_0102: ldstr "Finally" + IL_0107: call void [mscorlib]System.Console::WriteLine(string) + IL_010c: endfinally + } // end handler + IL_010d: leave.s IL_010f + + } // end handler + IL_010f: ldc.i4.0 + IL_0110: ret + + IL_0111: ldloc.0 + IL_0112: ret + } // end of method ExceptionHandling::ComplexConditionalReturnInThrow + + .method public hidebysig instance void + AppropriateLockExit() cil managed + { + // Code size 73 (0x49) + .maxstack 2 + .locals init (int32 V_0, + class ICSharpCode.Decompiler.Tests.TestCases.Pretty.ExceptionHandling V_1, + bool V_2) + IL_0000: ldc.i4.0 + IL_0001: stloc.0 + IL_0002: ldarg.0 + IL_0003: stloc.1 + IL_0004: ldc.i4.0 + IL_0005: stloc.2 + .try + { + IL_0006: ldloc.1 + IL_0007: ldloca.s V_2 + IL_0009: call void [mscorlib]System.Threading.Monitor::Enter(object, + bool&) + IL_000e: ldloc.0 + IL_000f: ldc.i4 0x100 + IL_0014: bgt.s IL_001e + + IL_0016: ldc.i4.0 + IL_0017: call void [mscorlib]System.Console::WriteLine(int32) + IL_001c: leave.s IL_0048 + + IL_001e: ldloc.0 + IL_001f: ldc.i4 0x400 + IL_0024: bgt.s IL_002e + + IL_0026: ldc.i4.1 + IL_0027: call void [mscorlib]System.Console::WriteLine(int32) + IL_002c: leave.s IL_0048 + + IL_002e: ldloc.0 + IL_002f: ldc.i4 0x4000 + IL_0034: bgt.s IL_003c + + IL_0036: ldc.i4.2 + IL_0037: call void [mscorlib]System.Console::WriteLine(int32) + IL_003c: leave.s IL_0048 + + } // end .try + finally + { + IL_003e: ldloc.2 + IL_003f: brfalse.s IL_0047 + + IL_0041: ldloc.1 + IL_0042: call void [mscorlib]System.Threading.Monitor::Exit(object) + IL_0047: endfinally + } // end handler + IL_0048: ret + } // end of method ExceptionHandling::AppropriateLockExit + .method family hidebysig specialname rtspecialname instance void .ctor() cil managed { diff --git a/ICSharpCode.Decompiler.Tests/TestCases/Pretty/ExceptionHandling.roslyn.il b/ICSharpCode.Decompiler.Tests/TestCases/Pretty/ExceptionHandling.roslyn.il index dce07ee7d..44c1456fb 100644 --- a/ICSharpCode.Decompiler.Tests/TestCases/Pretty/ExceptionHandling.roslyn.il +++ b/ICSharpCode.Decompiler.Tests/TestCases/Pretty/ExceptionHandling.roslyn.il @@ -854,6 +854,366 @@ IL_000c: br.s IL_000c } // end of method ExceptionHandling::ThrowInFinally + .method public hidebysig instance bool + EarlyExitInLoopTry() cil managed + { + // Code size 45 (0x2d) + .maxstack 2 + .locals init (bool V_0, + bool V_1, + bool V_2) + IL_0000: nop + IL_0001: br.s IL_0027 + + IL_0003: nop + .try + { + IL_0004: nop + IL_0005: ldarg.0 + IL_0006: ldc.i4.0 + IL_0007: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ExceptionHandling::B(int32) + IL_000c: ldc.i4.0 + IL_000d: ceq + IL_000f: stloc.0 + IL_0010: ldloc.0 + IL_0011: brfalse.s IL_0018 + + IL_0013: nop + IL_0014: ldc.i4.0 + IL_0015: stloc.1 + IL_0016: leave.s IL_002b + + IL_0018: call void [mscorlib]System.Console::WriteLine() + IL_001d: nop + IL_001e: nop + IL_001f: leave.s IL_0026 + + } // end .try + catch [mscorlib]System.Object + { + IL_0021: pop + IL_0022: nop + IL_0023: nop + IL_0024: leave.s IL_0026 + + } // end handler + IL_0026: nop + IL_0027: ldc.i4.1 + IL_0028: stloc.2 + IL_0029: br.s IL_0003 + + IL_002b: ldloc.1 + IL_002c: ret + } // end of method ExceptionHandling::EarlyExitInLoopTry + + .method public hidebysig instance bool + ComplexConditionalReturnInThrow() cil managed + { + // Code size 327 (0x147) + .maxstack 2 + .locals init (bool V_0, + bool V_1, + bool V_2, + bool V_3, + bool V_4, + bool V_5) + IL_0000: nop + .try + { + IL_0001: nop + IL_0002: ldarg.0 + IL_0003: ldc.i4.0 + IL_0004: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ExceptionHandling::B(int32) + IL_0009: stloc.0 + IL_000a: ldloc.0 + IL_000b: brfalse.s IL_0065 + + IL_000d: nop + IL_000e: ldarg.0 + IL_000f: ldc.i4.1 + IL_0010: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ExceptionHandling::B(int32) + IL_0015: stloc.1 + IL_0016: ldloc.1 + IL_0017: brfalse.s IL_0032 + + IL_0019: nop + IL_001a: ldstr "0 && 1" + IL_001f: call void [mscorlib]System.Console::WriteLine(string) + IL_0024: nop + IL_0025: ldarg.0 + IL_0026: ldc.i4.2 + IL_0027: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ExceptionHandling::B(int32) + IL_002c: stloc.2 + IL_002d: leave IL_0145 + + IL_0032: ldarg.0 + IL_0033: ldc.i4.3 + IL_0034: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ExceptionHandling::B(int32) + IL_0039: stloc.3 + IL_003a: ldloc.3 + IL_003b: brfalse.s IL_0059 + + IL_003d: nop + IL_003e: ldstr "0 && 3" + IL_0043: call void [mscorlib]System.Console::WriteLine(string) + IL_0048: nop + IL_0049: ldarg.0 + IL_004a: ldc.i4.2 + IL_004b: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ExceptionHandling::B(int32) + IL_0050: ldc.i4.0 + IL_0051: ceq + IL_0053: stloc.2 + IL_0054: leave IL_0145 + + IL_0059: ldstr "0" + IL_005e: call void [mscorlib]System.Console::WriteLine(string) + IL_0063: nop + IL_0064: nop + IL_0065: ldstr "End Try" + IL_006a: call void [mscorlib]System.Console::WriteLine(string) + IL_006f: nop + IL_0070: nop + IL_0071: leave IL_0141 + + } // end .try + catch [mscorlib]System.Object + { + IL_0076: pop + IL_0077: nop + .try + { + .try + { + IL_0078: nop + .try + { + IL_0079: nop + IL_007a: ldarg.0 + IL_007b: ldc.i4.0 + IL_007c: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ExceptionHandling::B(int32) + IL_0081: brtrue.s IL_008c + + IL_0083: ldarg.0 + IL_0084: ldc.i4.1 + IL_0085: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ExceptionHandling::B(int32) + IL_008a: brfalse.s IL_0095 + + IL_008c: ldarg.0 + IL_008d: ldc.i4.2 + IL_008e: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ExceptionHandling::B(int32) + IL_0093: brtrue.s IL_009e + + IL_0095: ldarg.0 + IL_0096: ldc.i4.3 + IL_0097: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ExceptionHandling::B(int32) + IL_009c: br.s IL_009f + + IL_009e: ldc.i4.1 + IL_009f: stloc.s V_4 + IL_00a1: ldloc.s V_4 + IL_00a3: brfalse.s IL_00c2 + + IL_00a5: nop + IL_00a6: ldarg.0 + IL_00a7: ldc.i4.4 + IL_00a8: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ExceptionHandling::B(int32) + IL_00ad: brfalse.s IL_00bb + + IL_00af: ldarg.0 + IL_00b0: ldc.i4.5 + IL_00b1: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ExceptionHandling::B(int32) + IL_00b6: ldc.i4.0 + IL_00b7: ceq + IL_00b9: br.s IL_00bc + + IL_00bb: ldc.i4.0 + IL_00bc: stloc.2 + IL_00bd: leave IL_0145 + + IL_00c2: ldarg.0 + IL_00c3: ldc.i4.6 + IL_00c4: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ExceptionHandling::B(int32) + IL_00c9: brtrue.s IL_00d4 + + IL_00cb: ldarg.0 + IL_00cc: ldc.i4.7 + IL_00cd: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ExceptionHandling::B(int32) + IL_00d2: br.s IL_00d5 + + IL_00d4: ldc.i4.1 + IL_00d5: stloc.s V_5 + IL_00d7: ldloc.s V_5 + IL_00d9: brfalse.s IL_00f3 + + IL_00db: nop + IL_00dc: ldarg.0 + IL_00dd: ldc.i4.8 + IL_00de: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ExceptionHandling::B(int32) + IL_00e3: brtrue.s IL_00ef + + IL_00e5: ldarg.0 + IL_00e6: ldc.i4.s 9 + IL_00e8: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ExceptionHandling::B(int32) + IL_00ed: br.s IL_00f0 + + IL_00ef: ldc.i4.1 + IL_00f0: stloc.2 + IL_00f1: leave.s IL_0145 + + IL_00f3: nop + IL_00f4: leave.s IL_0106 + + } // end .try + catch [mscorlib]System.Object + { + IL_00f6: pop + IL_00f7: nop + IL_00f8: ldstr "Catch2" + IL_00fd: call void [mscorlib]System.Console::WriteLine(string) + IL_0102: nop + IL_0103: nop + IL_0104: leave.s IL_0106 + + } // end handler + IL_0106: ldarg.0 + IL_0107: ldc.i4.s 10 + IL_0109: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ExceptionHandling::B(int32) + IL_010e: brfalse.s IL_011a + + IL_0110: ldarg.0 + IL_0111: ldc.i4.s 11 + IL_0113: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ExceptionHandling::B(int32) + IL_0118: br.s IL_011b + + IL_011a: ldc.i4.0 + IL_011b: stloc.2 + IL_011c: leave.s IL_0145 + + } // end .try + catch [mscorlib]System.Object + { + IL_011e: pop + IL_011f: nop + IL_0120: ldstr "Catch" + IL_0125: call void [mscorlib]System.Console::WriteLine(string) + IL_012a: nop + IL_012b: nop + IL_012c: leave.s IL_012e + + } // end handler + IL_012e: leave.s IL_013e + + } // end .try + finally + { + IL_0130: nop + IL_0131: ldstr "Finally" + IL_0136: call void [mscorlib]System.Console::WriteLine(string) + IL_013b: nop + IL_013c: nop + IL_013d: endfinally + } // end handler + IL_013e: nop + IL_013f: leave.s IL_0141 + + } // end handler + IL_0141: ldc.i4.0 + IL_0142: stloc.2 + IL_0143: br.s IL_0145 + + IL_0145: ldloc.2 + IL_0146: ret + } // end of method ExceptionHandling::ComplexConditionalReturnInThrow + + .method public hidebysig instance void + AppropriateLockExit() cil managed + { + // Code size 112 (0x70) + .maxstack 2 + .locals init (int32 V_0, + class ICSharpCode.Decompiler.Tests.TestCases.Pretty.ExceptionHandling V_1, + bool V_2, + bool V_3, + bool V_4, + bool V_5) + IL_0000: nop + IL_0001: ldc.i4.0 + IL_0002: stloc.0 + IL_0003: ldarg.0 + IL_0004: stloc.1 + IL_0005: ldc.i4.0 + IL_0006: stloc.2 + .try + { + IL_0007: ldloc.1 + IL_0008: ldloca.s V_2 + IL_000a: call void [mscorlib]System.Threading.Monitor::Enter(object, + bool&) + IL_000f: nop + IL_0010: nop + IL_0011: ldloc.0 + IL_0012: ldc.i4 0x100 + IL_0017: cgt + IL_0019: ldc.i4.0 + IL_001a: ceq + IL_001c: stloc.3 + IL_001d: ldloc.3 + IL_001e: brfalse.s IL_002b + + IL_0020: nop + IL_0021: ldc.i4.0 + IL_0022: call void [mscorlib]System.Console::WriteLine(int32) + IL_0027: nop + IL_0028: nop + IL_0029: br.s IL_0061 + + IL_002b: ldloc.0 + IL_002c: ldc.i4 0x400 + IL_0031: cgt + IL_0033: ldc.i4.0 + IL_0034: ceq + IL_0036: stloc.s V_4 + IL_0038: ldloc.s V_4 + IL_003a: brfalse.s IL_0047 + + IL_003c: nop + IL_003d: ldc.i4.1 + IL_003e: call void [mscorlib]System.Console::WriteLine(int32) + IL_0043: nop + IL_0044: nop + IL_0045: br.s IL_0061 + + IL_0047: ldloc.0 + IL_0048: ldc.i4 0x4000 + IL_004d: cgt + IL_004f: ldc.i4.0 + IL_0050: ceq + IL_0052: stloc.s V_5 + IL_0054: ldloc.s V_5 + IL_0056: brfalse.s IL_0061 + + IL_0058: nop + IL_0059: ldc.i4.2 + IL_005a: call void [mscorlib]System.Console::WriteLine(int32) + IL_005f: nop + IL_0060: nop + IL_0061: nop + IL_0062: leave.s IL_006f + + } // end .try + finally + { + IL_0064: ldloc.2 + IL_0065: brfalse.s IL_006e + + IL_0067: ldloc.1 + IL_0068: call void [mscorlib]System.Threading.Monitor::Exit(object) + IL_006d: nop + IL_006e: endfinally + } // end handler + IL_006f: ret + } // end of method ExceptionHandling::AppropriateLockExit + .method family hidebysig specialname rtspecialname instance void .ctor() cil managed { diff --git a/ICSharpCode.Decompiler.Tests/TestCases/Pretty/Loops.cs b/ICSharpCode.Decompiler.Tests/TestCases/Pretty/Loops.cs index 7e988af22..435bdc06a 100644 --- a/ICSharpCode.Decompiler.Tests/TestCases/Pretty/Loops.cs +++ b/ICSharpCode.Decompiler.Tests/TestCases/Pretty/Loops.cs @@ -573,29 +573,37 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty } } - //public int MultipleExits() - //{ - // int i = 0; - // while (true) { - // if (i % 4 == 0) { return 4; } - // if (i % 7 == 0) { break; } - // if (i % 9 == 0) { return 5; } - // if (i % 11 == 0) { break; } - // i++; - // } - // i = int.MinValue; - // return i; - //} + public int MultipleExits() + { + int num = 0; + while (true) { + if (num % 4 == 0) { + return 4; + } + if (num % 7 == 0) { + break; + } + if (num % 9 == 0) { + return 5; + } + if (num % 11 == 0) { + break; + } + num++; + } + return -2147483648; + } //public int InterestingLoop() //{ - // int i = 0; - // if (i % 11 == 0) { + // int num = 0; + // if (num % 11 == 0) { // while (true) { - // if (i % 4 == 0) { - // if (i % 7 == 0) { - // if (i % 11 == 0) { - // continue; // use a continue here to prevent moving the if (i%7) outside the loop + // if (num % 4 == 0) { + // if (num % 7 == 0) { + // if (num % 11 == 0) { + // // use a continue here to prevent moving the if (i%7) outside the loop + // continue; // } // Console.WriteLine("7"); // } else { @@ -604,14 +612,37 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty // } // break; // } - // i++; + // num++; // } // // This instruction is still dominated by the loop header - // i = int.MinValue; + // num = -2147483648;//int.MinValue; // } - // return i; + // return num; //} + public int InterestingLoop() + { + int num = 0; + if (num % 11 == 0) { + while (true) { + if (num % 4 == 0) { + if (num % 7 != 0) { + Console.WriteLine("!7"); + break; + } + if (num % 11 != 0) { + Console.WriteLine("7"); + break; + } + } else { + num++; + } + } + num = -2147483648; + } + return num; + } + private bool Condition(string arg) { Console.WriteLine("Condition: " + arg); @@ -638,41 +669,51 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty } Console.WriteLine("End of method"); } + + //other configurations work fine, just with different labels +#if OPT && !MCS + public void WhileWithGoto() + { + while (Condition("Main Loop")) { + if (Condition("Condition")) { + goto IL_000f; + } + // TODO reorder branches with successive block? + goto IL_0026; + IL_000f: + Console.WriteLine("Block1"); + if (Condition("Condition2")) { + continue; + } + // TODO remove redundant goto? + goto IL_0026; + IL_0026: + Console.WriteLine("Block2"); + goto IL_000f; + } + } +#endif - //public void WhileWithGoto() - //{ - // while (Condition("Main Loop")) { - // if (!Condition("Condition")) - // goto block2; - // block1: - // Console.WriteLine("Block1"); - // if (Condition("Condition2")) - // continue; - // block2: - // Console.WriteLine("Block2"); - // goto block1; - // } - //} - - //public void DoWhileLoop() - //{ - // Console.WriteLine("Initial"); - // if (Condition("if")) { - // do { - // Console.WriteLine("Loop Body"); - // if (Condition("test")) { - // if (Condition("continue")) { - // continue; - // } - // if (!Condition("break")) - // break; - // } - // Console.WriteLine("End of loop body"); - // } while (Condition("while")); - // Console.WriteLine("After loop"); - // } - // Console.WriteLine("End of method"); - //} + public void DoWhileLoop() + { + Console.WriteLine("Initial"); + if (Condition("if")) { + do { + Console.WriteLine("Loop Body"); + if (Condition("test")) { + if (Condition("continue")) { + continue; + } + if (!Condition("break")) { + break; + } + } + Console.WriteLine("End of loop body"); + } while (Condition("while")); + Console.WriteLine("After loop"); + } + Console.WriteLine("End of method"); + } public void ForLoop() { @@ -731,5 +772,47 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty } } } + + public void NestedForeach(List items1, List items2) + { + foreach (object item in items1) { + bool flag = false; + foreach (object item2 in items2) { + if (item2 == item) { + flag = true; + break; + } + } + + if (!flag) { + Console.WriteLine(item); + } + } + Console.WriteLine("end"); + } + + public void MergeAroundContinue() + { + for (int i = 0; i < 20; i++) { + if (i % 3 == 0) { + if (i != 6) { + continue; + } + } else if (i % 5 == 0) { + if (i != 5) { + continue; + } + } else if (i % 7 == 0) { + if (i != 7) { + continue; + } + } else if (i % 11 == 0) { + continue; + } + + Console.WriteLine(i); + } + Console.WriteLine("end"); + } } } diff --git a/ICSharpCode.Decompiler.Tests/TestCases/Pretty/Loops.il b/ICSharpCode.Decompiler.Tests/TestCases/Pretty/Loops.il index 126d1df28..b17ddd9ff 100644 --- a/ICSharpCode.Decompiler.Tests/TestCases/Pretty/Loops.il +++ b/ICSharpCode.Decompiler.Tests/TestCases/Pretty/Loops.il @@ -2318,6 +2318,190 @@ IL_004f: ret } // end of method Loops::NestedLoops + .method public hidebysig instance int32 + MultipleExits() cil managed + { + // Code size 95 (0x5f) + .maxstack 2 + .locals init (int32 V_0, + int32 V_1, + bool V_2) + IL_0000: nop + IL_0001: ldc.i4.0 + IL_0002: stloc.0 + IL_0003: br.s IL_0051 + + IL_0005: nop + IL_0006: ldloc.0 + IL_0007: ldc.i4.4 + IL_0008: rem + IL_0009: ldc.i4.0 + IL_000a: ceq + IL_000c: ldc.i4.0 + IL_000d: ceq + IL_000f: stloc.2 + IL_0010: ldloc.2 + IL_0011: brtrue.s IL_0018 + + IL_0013: nop + IL_0014: ldc.i4.4 + IL_0015: stloc.1 + IL_0016: br.s IL_005d + + IL_0018: ldloc.0 + IL_0019: ldc.i4.7 + IL_001a: rem + IL_001b: ldc.i4.0 + IL_001c: ceq + IL_001e: ldc.i4.0 + IL_001f: ceq + IL_0021: stloc.2 + IL_0022: ldloc.2 + IL_0023: brtrue.s IL_0028 + + IL_0025: nop + IL_0026: br.s IL_0055 + + IL_0028: ldloc.0 + IL_0029: ldc.i4.s 9 + IL_002b: rem + IL_002c: ldc.i4.0 + IL_002d: ceq + IL_002f: ldc.i4.0 + IL_0030: ceq + IL_0032: stloc.2 + IL_0033: ldloc.2 + IL_0034: brtrue.s IL_003b + + IL_0036: nop + IL_0037: ldc.i4.5 + IL_0038: stloc.1 + IL_0039: br.s IL_005d + + IL_003b: ldloc.0 + IL_003c: ldc.i4.s 11 + IL_003e: rem + IL_003f: ldc.i4.0 + IL_0040: ceq + IL_0042: ldc.i4.0 + IL_0043: ceq + IL_0045: stloc.2 + IL_0046: ldloc.2 + IL_0047: brtrue.s IL_004c + + IL_0049: nop + IL_004a: br.s IL_0055 + + IL_004c: ldloc.0 + IL_004d: ldc.i4.1 + IL_004e: add + IL_004f: stloc.0 + IL_0050: nop + IL_0051: ldc.i4.1 + IL_0052: stloc.2 + IL_0053: br.s IL_0005 + + IL_0055: ldc.i4 0x80000000 + IL_005a: stloc.1 + IL_005b: br.s IL_005d + + IL_005d: ldloc.1 + IL_005e: ret + } // end of method Loops::MultipleExits + + .method public hidebysig instance int32 + InterestingLoop() cil managed + { + // Code size 111 (0x6f) + .maxstack 2 + .locals init (int32 V_0, + int32 V_1, + bool V_2) + IL_0000: nop + IL_0001: ldc.i4.0 + IL_0002: stloc.0 + IL_0003: ldloc.0 + IL_0004: ldc.i4.s 11 + IL_0006: rem + IL_0007: ldc.i4.0 + IL_0008: ceq + IL_000a: ldc.i4.0 + IL_000b: ceq + IL_000d: stloc.2 + IL_000e: ldloc.2 + IL_000f: brtrue.s IL_0069 + + IL_0011: nop + IL_0012: br.s IL_005e + + IL_0014: nop + IL_0015: ldloc.0 + IL_0016: ldc.i4.4 + IL_0017: rem + IL_0018: ldc.i4.0 + IL_0019: ceq + IL_001b: ldc.i4.0 + IL_001c: ceq + IL_001e: stloc.2 + IL_001f: ldloc.2 + IL_0020: brtrue.s IL_0057 + + IL_0022: nop + IL_0023: ldloc.0 + IL_0024: ldc.i4.7 + IL_0025: rem + IL_0026: ldc.i4.0 + IL_0027: ceq + IL_0029: stloc.2 + IL_002a: ldloc.2 + IL_002b: brtrue.s IL_003b + + IL_002d: nop + IL_002e: ldstr "!7" + IL_0033: call void [mscorlib]System.Console::WriteLine(string) + IL_0038: nop + IL_0039: br.s IL_0062 + + IL_003b: ldloc.0 + IL_003c: ldc.i4.s 11 + IL_003e: rem + IL_003f: ldc.i4.0 + IL_0040: ceq + IL_0042: stloc.2 + IL_0043: ldloc.2 + IL_0044: brtrue.s IL_0054 + + IL_0046: nop + IL_0047: ldstr "7" + IL_004c: call void [mscorlib]System.Console::WriteLine(string) + IL_0051: nop + IL_0052: br.s IL_0062 + + IL_0054: nop + IL_0055: br.s IL_005d + + IL_0057: nop + IL_0058: ldloc.0 + IL_0059: ldc.i4.1 + IL_005a: add + IL_005b: stloc.0 + IL_005c: nop + IL_005d: nop + IL_005e: ldc.i4.1 + IL_005f: stloc.2 + IL_0060: br.s IL_0014 + + IL_0062: ldc.i4 0x80000000 + IL_0067: stloc.0 + IL_0068: nop + IL_0069: ldloc.0 + IL_006a: stloc.1 + IL_006b: br.s IL_006d + + IL_006d: ldloc.1 + IL_006e: ret + } // end of method Loops::InterestingLoop + .method private hidebysig instance bool Condition(string arg) cil managed { @@ -2419,6 +2603,84 @@ IL_009a: ret } // end of method Loops::WhileLoop + .method public hidebysig instance void + DoWhileLoop() cil managed + { + // Code size 153 (0x99) + .maxstack 2 + .locals init (bool V_0) + IL_0000: nop + IL_0001: ldstr "Initial" + IL_0006: call void [mscorlib]System.Console::WriteLine(string) + IL_000b: nop + IL_000c: ldarg.0 + IL_000d: ldstr "if" + IL_0012: call instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.Loops::Condition(string) + IL_0017: ldc.i4.0 + IL_0018: ceq + IL_001a: stloc.0 + IL_001b: ldloc.0 + IL_001c: brtrue.s IL_008d + + IL_001e: nop + IL_001f: nop + IL_0020: ldstr "Loop Body" + IL_0025: call void [mscorlib]System.Console::WriteLine(string) + IL_002a: nop + IL_002b: ldarg.0 + IL_002c: ldstr "test" + IL_0031: call instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.Loops::Condition(string) + IL_0036: ldc.i4.0 + IL_0037: ceq + IL_0039: stloc.0 + IL_003a: ldloc.0 + IL_003b: brtrue.s IL_0066 + + IL_003d: nop + IL_003e: ldarg.0 + IL_003f: ldstr "continue" + IL_0044: call instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.Loops::Condition(string) + IL_0049: ldc.i4.0 + IL_004a: ceq + IL_004c: stloc.0 + IL_004d: ldloc.0 + IL_004e: brtrue.s IL_0053 + + IL_0050: nop + IL_0051: br.s IL_0072 + + IL_0053: ldarg.0 + IL_0054: ldstr "break" + IL_0059: call instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.Loops::Condition(string) + IL_005e: stloc.0 + IL_005f: ldloc.0 + IL_0060: brtrue.s IL_0065 + + IL_0062: nop + IL_0063: br.s IL_0081 + + IL_0065: nop + IL_0066: ldstr "End of loop body" + IL_006b: call void [mscorlib]System.Console::WriteLine(string) + IL_0070: nop + IL_0071: nop + IL_0072: ldarg.0 + IL_0073: ldstr "while" + IL_0078: call instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.Loops::Condition(string) + IL_007d: stloc.0 + IL_007e: ldloc.0 + IL_007f: brtrue.s IL_001f + + IL_0081: ldstr "After loop" + IL_0086: call void [mscorlib]System.Console::WriteLine(string) + IL_008b: nop + IL_008c: nop + IL_008d: ldstr "End of method" + IL_0092: call void [mscorlib]System.Console::WriteLine(string) + IL_0097: nop + IL_0098: ret + } // end of method Loops::DoWhileLoop + .method public hidebysig instance void ForLoop() cil managed { @@ -2672,6 +2934,231 @@ IL_0049: ret } // end of method Loops::ForeachLoopWithEarlyReturn + .method public hidebysig instance void + NestedForeach(class [mscorlib]System.Collections.Generic.List`1 items1, + class [mscorlib]System.Collections.Generic.List`1 items2) cil managed + { + // Code size 150 (0x96) + .maxstack 2 + .locals init (object V_0, + bool V_1, + object V_2, + valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator V_3, + valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator V_4, + bool V_5) + IL_0000: nop + IL_0001: nop + IL_0002: ldarg.1 + IL_0003: callvirt instance valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator class [mscorlib]System.Collections.Generic.List`1::GetEnumerator() + IL_0008: stloc.3 + .try + { + IL_0009: br.s IL_006b + + IL_000b: ldloca.s V_3 + IL_000d: call instance !0 valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator::get_Current() + IL_0012: stloc.0 + IL_0013: nop + IL_0014: ldc.i4.0 + IL_0015: stloc.1 + IL_0016: nop + IL_0017: ldarg.2 + IL_0018: callvirt instance valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator class [mscorlib]System.Collections.Generic.List`1::GetEnumerator() + IL_001d: stloc.s V_4 + .try + { + IL_001f: br.s IL_003d + + IL_0021: ldloca.s V_4 + IL_0023: call instance !0 valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator::get_Current() + IL_0028: stloc.2 + IL_0029: nop + IL_002a: ldloc.2 + IL_002b: ldloc.0 + IL_002c: ceq + IL_002e: ldc.i4.0 + IL_002f: ceq + IL_0031: stloc.s V_5 + IL_0033: ldloc.s V_5 + IL_0035: brtrue.s IL_003c + + IL_0037: nop + IL_0038: ldc.i4.1 + IL_0039: stloc.1 + IL_003a: br.s IL_004a + + IL_003c: nop + IL_003d: ldloca.s V_4 + IL_003f: call instance bool valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator::MoveNext() + IL_0044: stloc.s V_5 + IL_0046: ldloc.s V_5 + IL_0048: brtrue.s IL_0021 + + IL_004a: leave.s IL_005b + + } // end .try + finally + { + IL_004c: ldloca.s V_4 + IL_004e: constrained. valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator + IL_0054: callvirt instance void [mscorlib]System.IDisposable::Dispose() + IL_0059: nop + IL_005a: endfinally + } // end handler + IL_005b: nop + IL_005c: ldloc.1 + IL_005d: stloc.s V_5 + IL_005f: ldloc.s V_5 + IL_0061: brtrue.s IL_006a + + IL_0063: ldloc.0 + IL_0064: call void [mscorlib]System.Console::WriteLine(object) + IL_0069: nop + IL_006a: nop + IL_006b: ldloca.s V_3 + IL_006d: call instance bool valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator::MoveNext() + IL_0072: stloc.s V_5 + IL_0074: ldloc.s V_5 + IL_0076: brtrue.s IL_000b + + IL_0078: leave.s IL_0089 + + } // end .try + finally + { + IL_007a: ldloca.s V_3 + IL_007c: constrained. valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator + IL_0082: callvirt instance void [mscorlib]System.IDisposable::Dispose() + IL_0087: nop + IL_0088: endfinally + } // end handler + IL_0089: nop + IL_008a: ldstr "end" + IL_008f: call void [mscorlib]System.Console::WriteLine(string) + IL_0094: nop + IL_0095: ret + } // end of method Loops::NestedForeach + + .method public hidebysig instance void + MergeAroundContinue() cil managed + { + // Code size 137 (0x89) + .maxstack 2 + .locals init (int32 V_0, + bool V_1) + IL_0000: nop + IL_0001: ldc.i4.0 + IL_0002: stloc.0 + IL_0003: br.s IL_0074 + + IL_0005: nop + IL_0006: ldloc.0 + IL_0007: ldc.i4.3 + IL_0008: rem + IL_0009: ldc.i4.0 + IL_000a: ceq + IL_000c: ldc.i4.0 + IL_000d: ceq + IL_000f: stloc.1 + IL_0010: ldloc.1 + IL_0011: brtrue.s IL_0021 + + IL_0013: nop + IL_0014: ldloc.0 + IL_0015: ldc.i4.6 + IL_0016: ceq + IL_0018: stloc.1 + IL_0019: ldloc.1 + IL_001a: brtrue.s IL_001e + + IL_001c: br.s IL_0070 + + IL_001e: nop + IL_001f: br.s IL_0068 + + IL_0021: ldloc.0 + IL_0022: ldc.i4.5 + IL_0023: rem + IL_0024: ldc.i4.0 + IL_0025: ceq + IL_0027: ldc.i4.0 + IL_0028: ceq + IL_002a: stloc.1 + IL_002b: ldloc.1 + IL_002c: brtrue.s IL_003c + + IL_002e: nop + IL_002f: ldloc.0 + IL_0030: ldc.i4.5 + IL_0031: ceq + IL_0033: stloc.1 + IL_0034: ldloc.1 + IL_0035: brtrue.s IL_0039 + + IL_0037: br.s IL_0070 + + IL_0039: nop + IL_003a: br.s IL_0068 + + IL_003c: ldloc.0 + IL_003d: ldc.i4.7 + IL_003e: rem + IL_003f: ldc.i4.0 + IL_0040: ceq + IL_0042: ldc.i4.0 + IL_0043: ceq + IL_0045: stloc.1 + IL_0046: ldloc.1 + IL_0047: brtrue.s IL_0057 + + IL_0049: nop + IL_004a: ldloc.0 + IL_004b: ldc.i4.7 + IL_004c: ceq + IL_004e: stloc.1 + IL_004f: ldloc.1 + IL_0050: brtrue.s IL_0054 + + IL_0052: br.s IL_0070 + + IL_0054: nop + IL_0055: br.s IL_0068 + + IL_0057: ldloc.0 + IL_0058: ldc.i4.s 11 + IL_005a: rem + IL_005b: ldc.i4.0 + IL_005c: ceq + IL_005e: ldc.i4.0 + IL_005f: ceq + IL_0061: stloc.1 + IL_0062: ldloc.1 + IL_0063: brtrue.s IL_0068 + + IL_0065: nop + IL_0066: br.s IL_0070 + + IL_0068: ldloc.0 + IL_0069: call void [mscorlib]System.Console::WriteLine(int32) + IL_006e: nop + IL_006f: nop + IL_0070: ldloc.0 + IL_0071: ldc.i4.1 + IL_0072: add + IL_0073: stloc.0 + IL_0074: ldloc.0 + IL_0075: ldc.i4.s 20 + IL_0077: clt + IL_0079: stloc.1 + IL_007a: ldloc.1 + IL_007b: brtrue.s IL_0005 + + IL_007d: ldstr "end" + IL_0082: call void [mscorlib]System.Console::WriteLine(string) + IL_0087: nop + IL_0088: ret + } // end of method Loops::MergeAroundContinue + .method public hidebysig specialname rtspecialname instance void .ctor() cil managed { diff --git a/ICSharpCode.Decompiler.Tests/TestCases/Pretty/Loops.mcs.il b/ICSharpCode.Decompiler.Tests/TestCases/Pretty/Loops.mcs.il index 2cab9de50..65457fe39 100644 --- a/ICSharpCode.Decompiler.Tests/TestCases/Pretty/Loops.mcs.il +++ b/ICSharpCode.Decompiler.Tests/TestCases/Pretty/Loops.mcs.il @@ -1696,6 +1696,104 @@ IL_0046: ret } // end of method Loops::NestedLoops + .method public hidebysig instance int32 + MultipleExits() cil managed + { + // Code size 65 (0x41) + .maxstack 5 + .locals init (int32 V_0) + IL_0000: ldc.i4.0 + IL_0001: stloc.0 + IL_0002: ldloc.0 + IL_0003: ldc.i4.4 + IL_0004: rem + IL_0005: brtrue IL_000c + + IL_000a: ldc.i4.4 + IL_000b: ret + + IL_000c: ldloc.0 + IL_000d: ldc.i4.7 + IL_000e: rem + IL_000f: brtrue IL_0019 + + IL_0014: br IL_003b + + IL_0019: ldloc.0 + IL_001a: ldc.i4.s 9 + IL_001c: rem + IL_001d: brtrue IL_0024 + + IL_0022: ldc.i4.5 + IL_0023: ret + + IL_0024: ldloc.0 + IL_0025: ldc.i4.s 11 + IL_0027: rem + IL_0028: brtrue IL_0032 + + IL_002d: br IL_003b + + IL_0032: ldloc.0 + IL_0033: ldc.i4.1 + IL_0034: add + IL_0035: stloc.0 + IL_0036: br IL_0002 + + IL_003b: ldc.i4 0x80000000 + IL_0040: ret + } // end of method Loops::MultipleExits + + .method public hidebysig instance int32 + InterestingLoop() cil managed + { + // Code size 88 (0x58) + .maxstack 5 + .locals init (int32 V_0) + IL_0000: ldc.i4.0 + IL_0001: stloc.0 + IL_0002: ldloc.0 + IL_0003: ldc.i4.s 11 + IL_0005: rem + IL_0006: brtrue IL_0056 + + IL_000b: ldloc.0 + IL_000c: ldc.i4.4 + IL_000d: rem + IL_000e: brtrue IL_0047 + + IL_0013: ldloc.0 + IL_0014: ldc.i4.7 + IL_0015: rem + IL_0016: brfalse IL_002a + + IL_001b: ldstr "!7" + IL_0020: call void [mscorlib]System.Console::WriteLine(string) + IL_0025: br IL_0050 + + IL_002a: ldloc.0 + IL_002b: ldc.i4.s 11 + IL_002d: rem + IL_002e: brfalse IL_0042 + + IL_0033: ldstr "7" + IL_0038: call void [mscorlib]System.Console::WriteLine(string) + IL_003d: br IL_0050 + + IL_0042: br IL_004b + + IL_0047: ldloc.0 + IL_0048: ldc.i4.1 + IL_0049: add + IL_004a: stloc.0 + IL_004b: br IL_000b + + IL_0050: ldc.i4 0x80000000 + IL_0055: stloc.0 + IL_0056: ldloc.0 + IL_0057: ret + } // end of method Loops::InterestingLoop + .method private hidebysig instance bool Condition(string arg) cil managed { @@ -1759,6 +1857,53 @@ IL_0091: ret } // end of method Loops::WhileLoop + .method public hidebysig instance void + DoWhileLoop() cil managed + { + // Code size 141 (0x8d) + .maxstack 16 + IL_0000: ldstr "Initial" + IL_0005: call void [mscorlib]System.Console::WriteLine(string) + IL_000a: ldarg.0 + IL_000b: ldstr "if" + IL_0010: call instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.Loops::Condition(string) + IL_0015: brfalse IL_0082 + + IL_001a: ldstr "Loop Body" + IL_001f: call void [mscorlib]System.Console::WriteLine(string) + IL_0024: ldarg.0 + IL_0025: ldstr "test" + IL_002a: call instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.Loops::Condition(string) + IL_002f: brfalse IL_005e + + IL_0034: ldarg.0 + IL_0035: ldstr "continue" + IL_003a: call instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.Loops::Condition(string) + IL_003f: brfalse IL_0049 + + IL_0044: br IL_0068 + + IL_0049: ldarg.0 + IL_004a: ldstr "break" + IL_004f: call instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.Loops::Condition(string) + IL_0054: brtrue IL_005e + + IL_0059: br IL_0078 + + IL_005e: ldstr "End of loop body" + IL_0063: call void [mscorlib]System.Console::WriteLine(string) + IL_0068: ldarg.0 + IL_0069: ldstr "while" + IL_006e: call instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.Loops::Condition(string) + IL_0073: brtrue IL_001a + + IL_0078: ldstr "After loop" + IL_007d: call void [mscorlib]System.Console::WriteLine(string) + IL_0082: ldstr "End of method" + IL_0087: call void [mscorlib]System.Console::WriteLine(string) + IL_008c: ret + } // end of method Loops::DoWhileLoop + .method public hidebysig instance void ForLoop() cil managed { @@ -1933,6 +2078,156 @@ IL_0045: ret } // end of method Loops::ForeachLoopWithEarlyReturn + .method public hidebysig instance void + NestedForeach(class [mscorlib]System.Collections.Generic.List`1 items1, + class [mscorlib]System.Collections.Generic.List`1 items2) cil managed + { + // Code size 139 (0x8b) + .maxstack 19 + .locals init (object V_0, + valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator V_1, + bool V_2, + object V_3, + valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator V_4) + IL_0000: ldarg.1 + IL_0001: callvirt instance valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator class [mscorlib]System.Collections.Generic.List`1::GetEnumerator() + IL_0006: stloc.1 + .try + { + IL_0007: br IL_0063 + + IL_000c: ldloca.s V_1 + IL_000e: call instance !0 valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator::get_Current() + IL_0013: stloc.0 + IL_0014: ldc.i4.0 + IL_0015: stloc.2 + IL_0016: ldarg.2 + IL_0017: callvirt instance valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator class [mscorlib]System.Collections.Generic.List`1::GetEnumerator() + IL_001c: stloc.s V_4 + .try + { + IL_001e: br IL_0039 + + IL_0023: ldloca.s V_4 + IL_0025: call instance !0 valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator::get_Current() + IL_002a: stloc.3 + IL_002b: ldloc.3 + IL_002c: ldloc.0 + IL_002d: bne.un IL_0039 + + IL_0032: ldc.i4.1 + IL_0033: stloc.2 + IL_0034: br IL_0045 + + IL_0039: ldloca.s V_4 + IL_003b: call instance bool valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator::MoveNext() + IL_0040: brtrue IL_0023 + + IL_0045: leave IL_0057 + + } // end .try + finally + { + IL_004a: ldloc.s V_4 + IL_004c: box valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator + IL_0051: callvirt instance void [mscorlib]System.IDisposable::Dispose() + IL_0056: endfinally + } // end handler + IL_0057: ldloc.2 + IL_0058: brtrue IL_0063 + + IL_005d: ldloc.0 + IL_005e: call void [mscorlib]System.Console::WriteLine(object) + IL_0063: ldloca.s V_1 + IL_0065: call instance bool valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator::MoveNext() + IL_006a: brtrue IL_000c + + IL_006f: leave IL_0080 + + } // end .try + finally + { + IL_0074: ldloc.1 + IL_0075: box valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator + IL_007a: callvirt instance void [mscorlib]System.IDisposable::Dispose() + IL_007f: endfinally + } // end handler + IL_0080: ldstr "end" + IL_0085: call void [mscorlib]System.Console::WriteLine(string) + IL_008a: ret + } // end of method Loops::NestedForeach + + .method public hidebysig instance void + MergeAroundContinue() cil managed + { + // Code size 125 (0x7d) + .maxstack 4 + .locals init (int32 V_0) + IL_0000: ldc.i4.0 + IL_0001: stloc.0 + IL_0002: br IL_006a + + IL_0007: ldloc.0 + IL_0008: ldc.i4.3 + IL_0009: rem + IL_000a: brtrue IL_0020 + + IL_000f: ldloc.0 + IL_0010: ldc.i4.6 + IL_0011: beq IL_001b + + IL_0016: br IL_0066 + + IL_001b: br IL_0060 + + IL_0020: ldloc.0 + IL_0021: ldc.i4.5 + IL_0022: rem + IL_0023: brtrue IL_0039 + + IL_0028: ldloc.0 + IL_0029: ldc.i4.5 + IL_002a: beq IL_0034 + + IL_002f: br IL_0066 + + IL_0034: br IL_0060 + + IL_0039: ldloc.0 + IL_003a: ldc.i4.7 + IL_003b: rem + IL_003c: brtrue IL_0052 + + IL_0041: ldloc.0 + IL_0042: ldc.i4.7 + IL_0043: beq IL_004d + + IL_0048: br IL_0066 + + IL_004d: br IL_0060 + + IL_0052: ldloc.0 + IL_0053: ldc.i4.s 11 + IL_0055: rem + IL_0056: brtrue IL_0060 + + IL_005b: br IL_0066 + + IL_0060: ldloc.0 + IL_0061: call void [mscorlib]System.Console::WriteLine(int32) + IL_0066: ldloc.0 + IL_0067: ldc.i4.1 + IL_0068: add + IL_0069: stloc.0 + IL_006a: ldloc.0 + IL_006b: ldc.i4.s 20 + IL_006d: blt IL_0007 + + IL_0072: ldstr "end" + IL_0077: call void [mscorlib]System.Console::WriteLine(string) + IL_007c: ret + } // end of method Loops::MergeAroundContinue + } // end of class ICSharpCode.Decompiler.Tests.TestCases.Pretty.Loops diff --git a/ICSharpCode.Decompiler.Tests/TestCases/Pretty/Loops.opt.il b/ICSharpCode.Decompiler.Tests/TestCases/Pretty/Loops.opt.il index 103ba4c66..204ad1436 100644 --- a/ICSharpCode.Decompiler.Tests/TestCases/Pretty/Loops.opt.il +++ b/ICSharpCode.Decompiler.Tests/TestCases/Pretty/Loops.opt.il @@ -1842,6 +1842,98 @@ IL_0034: ret } // end of method Loops::NestedLoops + .method public hidebysig instance int32 + MultipleExits() cil managed + { + // Code size 40 (0x28) + .maxstack 2 + .locals init (int32 V_0) + IL_0000: ldc.i4.0 + IL_0001: stloc.0 + IL_0002: ldloc.0 + IL_0003: ldc.i4.4 + IL_0004: rem + IL_0005: brtrue.s IL_0009 + + IL_0007: ldc.i4.4 + IL_0008: ret + + IL_0009: ldloc.0 + IL_000a: ldc.i4.7 + IL_000b: rem + IL_000c: brfalse.s IL_0022 + + IL_000e: ldloc.0 + IL_000f: ldc.i4.s 9 + IL_0011: rem + IL_0012: brtrue.s IL_0016 + + IL_0014: ldc.i4.5 + IL_0015: ret + + IL_0016: ldloc.0 + IL_0017: ldc.i4.s 11 + IL_0019: rem + IL_001a: brfalse.s IL_0022 + + IL_001c: ldloc.0 + IL_001d: ldc.i4.1 + IL_001e: add + IL_001f: stloc.0 + IL_0020: br.s IL_0002 + + IL_0022: ldc.i4 0x80000000 + IL_0027: ret + } // end of method Loops::MultipleExits + + .method public hidebysig instance int32 + InterestingLoop() cil managed + { + // Code size 62 (0x3e) + .maxstack 2 + .locals init (int32 V_0) + IL_0000: ldc.i4.0 + IL_0001: stloc.0 + IL_0002: ldloc.0 + IL_0003: ldc.i4.s 11 + IL_0005: rem + IL_0006: brtrue.s IL_003c + + IL_0008: ldloc.0 + IL_0009: ldc.i4.4 + IL_000a: rem + IL_000b: brtrue.s IL_0030 + + IL_000d: ldloc.0 + IL_000e: ldc.i4.7 + IL_000f: rem + IL_0010: brfalse.s IL_001e + + IL_0012: ldstr "!7" + IL_0017: call void [mscorlib]System.Console::WriteLine(string) + IL_001c: br.s IL_0036 + + IL_001e: ldloc.0 + IL_001f: ldc.i4.s 11 + IL_0021: rem + IL_0022: brfalse.s IL_0008 + + IL_0024: ldstr "7" + IL_0029: call void [mscorlib]System.Console::WriteLine(string) + IL_002e: br.s IL_0036 + + IL_0030: ldloc.0 + IL_0031: ldc.i4.1 + IL_0032: add + IL_0033: stloc.0 + IL_0034: br.s IL_0008 + + IL_0036: ldc.i4 0x80000000 + IL_003b: stloc.0 + IL_003c: ldloc.0 + IL_003d: ret + } // end of method Loops::InterestingLoop + .method private hidebysig instance bool Condition(string arg) cil managed { @@ -1901,6 +1993,80 @@ IL_0075: ret } // end of method Loops::WhileLoop + .method public hidebysig instance void + WhileWithGoto() cil managed + { + // Code size 64 (0x40) + .maxstack 2 + IL_0000: br.s IL_0032 + + IL_0002: ldarg.0 + IL_0003: ldstr "Condition" + IL_0008: call instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.Loops::Condition(string) + IL_000d: brfalse.s IL_0026 + + IL_000f: ldstr "Block1" + IL_0014: call void [mscorlib]System.Console::WriteLine(string) + IL_0019: ldarg.0 + IL_001a: ldstr "Condition2" + IL_001f: call instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.Loops::Condition(string) + IL_0024: brtrue.s IL_0032 + + IL_0026: ldstr "Block2" + IL_002b: call void [mscorlib]System.Console::WriteLine(string) + IL_0030: br.s IL_000f + + IL_0032: ldarg.0 + IL_0033: ldstr "Main Loop" + IL_0038: call instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.Loops::Condition(string) + IL_003d: brtrue.s IL_0002 + + IL_003f: ret + } // end of method Loops::WhileWithGoto + + .method public hidebysig instance void + DoWhileLoop() cil managed + { + // Code size 116 (0x74) + .maxstack 2 + IL_0000: ldstr "Initial" + IL_0005: call void [mscorlib]System.Console::WriteLine(string) + IL_000a: ldarg.0 + IL_000b: ldstr "if" + IL_0010: call instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.Loops::Condition(string) + IL_0015: brfalse.s IL_0069 + + IL_0017: ldstr "Loop Body" + IL_001c: call void [mscorlib]System.Console::WriteLine(string) + IL_0021: ldarg.0 + IL_0022: ldstr "test" + IL_0027: call instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.Loops::Condition(string) + IL_002c: brfalse.s IL_0048 + + IL_002e: ldarg.0 + IL_002f: ldstr "continue" + IL_0034: call instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.Loops::Condition(string) + IL_0039: brtrue.s IL_0052 + + IL_003b: ldarg.0 + IL_003c: ldstr "break" + IL_0041: call instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.Loops::Condition(string) + IL_0046: brfalse.s IL_005f + + IL_0048: ldstr "End of loop body" + IL_004d: call void [mscorlib]System.Console::WriteLine(string) + IL_0052: ldarg.0 + IL_0053: ldstr "while" + IL_0058: call instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.Loops::Condition(string) + IL_005d: brtrue.s IL_0017 + + IL_005f: ldstr "After loop" + IL_0064: call void [mscorlib]System.Console::WriteLine(string) + IL_0069: ldstr "End of method" + IL_006e: call void [mscorlib]System.Console::WriteLine(string) + IL_0073: ret + } // end of method Loops::DoWhileLoop + .method public hidebysig instance void ForLoop() cil managed { @@ -2069,6 +2235,148 @@ IL_0036: ret } // end of method Loops::ForeachLoopWithEarlyReturn + .method public hidebysig instance void + NestedForeach(class [mscorlib]System.Collections.Generic.List`1 items1, + class [mscorlib]System.Collections.Generic.List`1 items2) cil managed + { + // Code size 115 (0x73) + .maxstack 2 + .locals init (object V_0, + bool V_1, + object V_2, + valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator V_3, + valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator V_4) + IL_0000: ldarg.1 + IL_0001: callvirt instance valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator class [mscorlib]System.Collections.Generic.List`1::GetEnumerator() + IL_0006: stloc.3 + .try + { + IL_0007: br.s IL_004f + + IL_0009: ldloca.s V_3 + IL_000b: call instance !0 valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator::get_Current() + IL_0010: stloc.0 + IL_0011: ldc.i4.0 + IL_0012: stloc.1 + IL_0013: ldarg.2 + IL_0014: callvirt instance valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator class [mscorlib]System.Collections.Generic.List`1::GetEnumerator() + IL_0019: stloc.s V_4 + .try + { + IL_001b: br.s IL_002d + + IL_001d: ldloca.s V_4 + IL_001f: call instance !0 valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator::get_Current() + IL_0024: stloc.2 + IL_0025: ldloc.2 + IL_0026: ldloc.0 + IL_0027: bne.un.s IL_002d + + IL_0029: ldc.i4.1 + IL_002a: stloc.1 + IL_002b: br.s IL_0036 + + IL_002d: ldloca.s V_4 + IL_002f: call instance bool valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator::MoveNext() + IL_0034: brtrue.s IL_001d + + IL_0036: leave.s IL_0046 + + } // end .try + finally + { + IL_0038: ldloca.s V_4 + IL_003a: constrained. valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator + IL_0040: callvirt instance void [mscorlib]System.IDisposable::Dispose() + IL_0045: endfinally + } // end handler + IL_0046: ldloc.1 + IL_0047: brtrue.s IL_004f + + IL_0049: ldloc.0 + IL_004a: call void [mscorlib]System.Console::WriteLine(object) + IL_004f: ldloca.s V_3 + IL_0051: call instance bool valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator::MoveNext() + IL_0056: brtrue.s IL_0009 + + IL_0058: leave.s IL_0068 + + } // end .try + finally + { + IL_005a: ldloca.s V_3 + IL_005c: constrained. valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator + IL_0062: callvirt instance void [mscorlib]System.IDisposable::Dispose() + IL_0067: endfinally + } // end handler + IL_0068: ldstr "end" + IL_006d: call void [mscorlib]System.Console::WriteLine(string) + IL_0072: ret + } // end of method Loops::NestedForeach + + .method public hidebysig instance void + MergeAroundContinue() cil managed + { + // Code size 69 (0x45) + .maxstack 2 + .locals init (int32 V_0) + IL_0000: ldc.i4.0 + IL_0001: stloc.0 + IL_0002: br.s IL_0035 + + IL_0004: ldloc.0 + IL_0005: ldc.i4.3 + IL_0006: rem + IL_0007: brtrue.s IL_000f + + IL_0009: ldloc.0 + IL_000a: ldc.i4.6 + IL_000b: beq.s IL_002b + + IL_000d: br.s IL_0031 + + IL_000f: ldloc.0 + IL_0010: ldc.i4.5 + IL_0011: rem + IL_0012: brtrue.s IL_001a + + IL_0014: ldloc.0 + IL_0015: ldc.i4.5 + IL_0016: beq.s IL_002b + + IL_0018: br.s IL_0031 + + IL_001a: ldloc.0 + IL_001b: ldc.i4.7 + IL_001c: rem + IL_001d: brtrue.s IL_0025 + + IL_001f: ldloc.0 + IL_0020: ldc.i4.7 + IL_0021: beq.s IL_002b + + IL_0023: br.s IL_0031 + + IL_0025: ldloc.0 + IL_0026: ldc.i4.s 11 + IL_0028: rem + IL_0029: brfalse.s IL_0031 + + IL_002b: ldloc.0 + IL_002c: call void [mscorlib]System.Console::WriteLine(int32) + IL_0031: ldloc.0 + IL_0032: ldc.i4.1 + IL_0033: add + IL_0034: stloc.0 + IL_0035: ldloc.0 + IL_0036: ldc.i4.s 20 + IL_0038: blt.s IL_0004 + + IL_003a: ldstr "end" + IL_003f: call void [mscorlib]System.Console::WriteLine(string) + IL_0044: ret + } // end of method Loops::MergeAroundContinue + .method public hidebysig specialname rtspecialname instance void .ctor() cil managed { diff --git a/ICSharpCode.Decompiler.Tests/TestCases/Pretty/Loops.opt.mcs.il b/ICSharpCode.Decompiler.Tests/TestCases/Pretty/Loops.opt.mcs.il index 4bf899496..32a7b66a2 100644 --- a/ICSharpCode.Decompiler.Tests/TestCases/Pretty/Loops.opt.mcs.il +++ b/ICSharpCode.Decompiler.Tests/TestCases/Pretty/Loops.opt.mcs.il @@ -1696,6 +1696,104 @@ IL_0046: ret } // end of method Loops::NestedLoops + .method public hidebysig instance int32 + MultipleExits() cil managed + { + // Code size 65 (0x41) + .maxstack 5 + .locals init (int32 V_0) + IL_0000: ldc.i4.0 + IL_0001: stloc.0 + IL_0002: ldloc.0 + IL_0003: ldc.i4.4 + IL_0004: rem + IL_0005: brtrue IL_000c + + IL_000a: ldc.i4.4 + IL_000b: ret + + IL_000c: ldloc.0 + IL_000d: ldc.i4.7 + IL_000e: rem + IL_000f: brtrue IL_0019 + + IL_0014: br IL_003b + + IL_0019: ldloc.0 + IL_001a: ldc.i4.s 9 + IL_001c: rem + IL_001d: brtrue IL_0024 + + IL_0022: ldc.i4.5 + IL_0023: ret + + IL_0024: ldloc.0 + IL_0025: ldc.i4.s 11 + IL_0027: rem + IL_0028: brtrue IL_0032 + + IL_002d: br IL_003b + + IL_0032: ldloc.0 + IL_0033: ldc.i4.1 + IL_0034: add + IL_0035: stloc.0 + IL_0036: br IL_0002 + + IL_003b: ldc.i4 0x80000000 + IL_0040: ret + } // end of method Loops::MultipleExits + + .method public hidebysig instance int32 + InterestingLoop() cil managed + { + // Code size 88 (0x58) + .maxstack 5 + .locals init (int32 V_0) + IL_0000: ldc.i4.0 + IL_0001: stloc.0 + IL_0002: ldloc.0 + IL_0003: ldc.i4.s 11 + IL_0005: rem + IL_0006: brtrue IL_0056 + + IL_000b: ldloc.0 + IL_000c: ldc.i4.4 + IL_000d: rem + IL_000e: brtrue IL_0047 + + IL_0013: ldloc.0 + IL_0014: ldc.i4.7 + IL_0015: rem + IL_0016: brfalse IL_002a + + IL_001b: ldstr "!7" + IL_0020: call void [mscorlib]System.Console::WriteLine(string) + IL_0025: br IL_0050 + + IL_002a: ldloc.0 + IL_002b: ldc.i4.s 11 + IL_002d: rem + IL_002e: brfalse IL_0042 + + IL_0033: ldstr "7" + IL_0038: call void [mscorlib]System.Console::WriteLine(string) + IL_003d: br IL_0050 + + IL_0042: br IL_004b + + IL_0047: ldloc.0 + IL_0048: ldc.i4.1 + IL_0049: add + IL_004a: stloc.0 + IL_004b: br IL_000b + + IL_0050: ldc.i4 0x80000000 + IL_0055: stloc.0 + IL_0056: ldloc.0 + IL_0057: ret + } // end of method Loops::InterestingLoop + .method private hidebysig instance bool Condition(string arg) cil managed { @@ -1759,6 +1857,53 @@ IL_0091: ret } // end of method Loops::WhileLoop + .method public hidebysig instance void + DoWhileLoop() cil managed + { + // Code size 141 (0x8d) + .maxstack 16 + IL_0000: ldstr "Initial" + IL_0005: call void [mscorlib]System.Console::WriteLine(string) + IL_000a: ldarg.0 + IL_000b: ldstr "if" + IL_0010: call instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.Loops::Condition(string) + IL_0015: brfalse IL_0082 + + IL_001a: ldstr "Loop Body" + IL_001f: call void [mscorlib]System.Console::WriteLine(string) + IL_0024: ldarg.0 + IL_0025: ldstr "test" + IL_002a: call instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.Loops::Condition(string) + IL_002f: brfalse IL_005e + + IL_0034: ldarg.0 + IL_0035: ldstr "continue" + IL_003a: call instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.Loops::Condition(string) + IL_003f: brfalse IL_0049 + + IL_0044: br IL_0068 + + IL_0049: ldarg.0 + IL_004a: ldstr "break" + IL_004f: call instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.Loops::Condition(string) + IL_0054: brtrue IL_005e + + IL_0059: br IL_0078 + + IL_005e: ldstr "End of loop body" + IL_0063: call void [mscorlib]System.Console::WriteLine(string) + IL_0068: ldarg.0 + IL_0069: ldstr "while" + IL_006e: call instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.Loops::Condition(string) + IL_0073: brtrue IL_001a + + IL_0078: ldstr "After loop" + IL_007d: call void [mscorlib]System.Console::WriteLine(string) + IL_0082: ldstr "End of method" + IL_0087: call void [mscorlib]System.Console::WriteLine(string) + IL_008c: ret + } // end of method Loops::DoWhileLoop + .method public hidebysig instance void ForLoop() cil managed { @@ -1933,6 +2078,156 @@ IL_0045: ret } // end of method Loops::ForeachLoopWithEarlyReturn + .method public hidebysig instance void + NestedForeach(class [mscorlib]System.Collections.Generic.List`1 items1, + class [mscorlib]System.Collections.Generic.List`1 items2) cil managed + { + // Code size 139 (0x8b) + .maxstack 19 + .locals init (object V_0, + valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator V_1, + bool V_2, + object V_3, + valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator V_4) + IL_0000: ldarg.1 + IL_0001: callvirt instance valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator class [mscorlib]System.Collections.Generic.List`1::GetEnumerator() + IL_0006: stloc.1 + .try + { + IL_0007: br IL_0063 + + IL_000c: ldloca.s V_1 + IL_000e: call instance !0 valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator::get_Current() + IL_0013: stloc.0 + IL_0014: ldc.i4.0 + IL_0015: stloc.2 + IL_0016: ldarg.2 + IL_0017: callvirt instance valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator class [mscorlib]System.Collections.Generic.List`1::GetEnumerator() + IL_001c: stloc.s V_4 + .try + { + IL_001e: br IL_0039 + + IL_0023: ldloca.s V_4 + IL_0025: call instance !0 valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator::get_Current() + IL_002a: stloc.3 + IL_002b: ldloc.3 + IL_002c: ldloc.0 + IL_002d: bne.un IL_0039 + + IL_0032: ldc.i4.1 + IL_0033: stloc.2 + IL_0034: br IL_0045 + + IL_0039: ldloca.s V_4 + IL_003b: call instance bool valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator::MoveNext() + IL_0040: brtrue IL_0023 + + IL_0045: leave IL_0057 + + } // end .try + finally + { + IL_004a: ldloc.s V_4 + IL_004c: box valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator + IL_0051: callvirt instance void [mscorlib]System.IDisposable::Dispose() + IL_0056: endfinally + } // end handler + IL_0057: ldloc.2 + IL_0058: brtrue IL_0063 + + IL_005d: ldloc.0 + IL_005e: call void [mscorlib]System.Console::WriteLine(object) + IL_0063: ldloca.s V_1 + IL_0065: call instance bool valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator::MoveNext() + IL_006a: brtrue IL_000c + + IL_006f: leave IL_0080 + + } // end .try + finally + { + IL_0074: ldloc.1 + IL_0075: box valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator + IL_007a: callvirt instance void [mscorlib]System.IDisposable::Dispose() + IL_007f: endfinally + } // end handler + IL_0080: ldstr "end" + IL_0085: call void [mscorlib]System.Console::WriteLine(string) + IL_008a: ret + } // end of method Loops::NestedForeach + + .method public hidebysig instance void + MergeAroundContinue() cil managed + { + // Code size 125 (0x7d) + .maxstack 4 + .locals init (int32 V_0) + IL_0000: ldc.i4.0 + IL_0001: stloc.0 + IL_0002: br IL_006a + + IL_0007: ldloc.0 + IL_0008: ldc.i4.3 + IL_0009: rem + IL_000a: brtrue IL_0020 + + IL_000f: ldloc.0 + IL_0010: ldc.i4.6 + IL_0011: beq IL_001b + + IL_0016: br IL_0066 + + IL_001b: br IL_0060 + + IL_0020: ldloc.0 + IL_0021: ldc.i4.5 + IL_0022: rem + IL_0023: brtrue IL_0039 + + IL_0028: ldloc.0 + IL_0029: ldc.i4.5 + IL_002a: beq IL_0034 + + IL_002f: br IL_0066 + + IL_0034: br IL_0060 + + IL_0039: ldloc.0 + IL_003a: ldc.i4.7 + IL_003b: rem + IL_003c: brtrue IL_0052 + + IL_0041: ldloc.0 + IL_0042: ldc.i4.7 + IL_0043: beq IL_004d + + IL_0048: br IL_0066 + + IL_004d: br IL_0060 + + IL_0052: ldloc.0 + IL_0053: ldc.i4.s 11 + IL_0055: rem + IL_0056: brtrue IL_0060 + + IL_005b: br IL_0066 + + IL_0060: ldloc.0 + IL_0061: call void [mscorlib]System.Console::WriteLine(int32) + IL_0066: ldloc.0 + IL_0067: ldc.i4.1 + IL_0068: add + IL_0069: stloc.0 + IL_006a: ldloc.0 + IL_006b: ldc.i4.s 20 + IL_006d: blt IL_0007 + + IL_0072: ldstr "end" + IL_0077: call void [mscorlib]System.Console::WriteLine(string) + IL_007c: ret + } // end of method Loops::MergeAroundContinue + } // end of class ICSharpCode.Decompiler.Tests.TestCases.Pretty.Loops diff --git a/ICSharpCode.Decompiler.Tests/TestCases/Pretty/Loops.opt.roslyn.il b/ICSharpCode.Decompiler.Tests/TestCases/Pretty/Loops.opt.roslyn.il index f3a5c8dcd..02ccb1df7 100644 --- a/ICSharpCode.Decompiler.Tests/TestCases/Pretty/Loops.opt.roslyn.il +++ b/ICSharpCode.Decompiler.Tests/TestCases/Pretty/Loops.opt.roslyn.il @@ -1786,6 +1786,98 @@ IL_0034: ret } // end of method Loops::NestedLoops + .method public hidebysig instance int32 + MultipleExits() cil managed + { + // Code size 40 (0x28) + .maxstack 2 + .locals init (int32 V_0) + IL_0000: ldc.i4.0 + IL_0001: stloc.0 + IL_0002: ldloc.0 + IL_0003: ldc.i4.4 + IL_0004: rem + IL_0005: brtrue.s IL_0009 + + IL_0007: ldc.i4.4 + IL_0008: ret + + IL_0009: ldloc.0 + IL_000a: ldc.i4.7 + IL_000b: rem + IL_000c: brfalse.s IL_0022 + + IL_000e: ldloc.0 + IL_000f: ldc.i4.s 9 + IL_0011: rem + IL_0012: brtrue.s IL_0016 + + IL_0014: ldc.i4.5 + IL_0015: ret + + IL_0016: ldloc.0 + IL_0017: ldc.i4.s 11 + IL_0019: rem + IL_001a: brfalse.s IL_0022 + + IL_001c: ldloc.0 + IL_001d: ldc.i4.1 + IL_001e: add + IL_001f: stloc.0 + IL_0020: br.s IL_0002 + + IL_0022: ldc.i4 0x80000000 + IL_0027: ret + } // end of method Loops::MultipleExits + + .method public hidebysig instance int32 + InterestingLoop() cil managed + { + // Code size 62 (0x3e) + .maxstack 2 + .locals init (int32 V_0) + IL_0000: ldc.i4.0 + IL_0001: stloc.0 + IL_0002: ldloc.0 + IL_0003: ldc.i4.s 11 + IL_0005: rem + IL_0006: brtrue.s IL_003c + + IL_0008: ldloc.0 + IL_0009: ldc.i4.4 + IL_000a: rem + IL_000b: brtrue.s IL_0030 + + IL_000d: ldloc.0 + IL_000e: ldc.i4.7 + IL_000f: rem + IL_0010: brfalse.s IL_001e + + IL_0012: ldstr "!7" + IL_0017: call void [mscorlib]System.Console::WriteLine(string) + IL_001c: br.s IL_0036 + + IL_001e: ldloc.0 + IL_001f: ldc.i4.s 11 + IL_0021: rem + IL_0022: brfalse.s IL_0008 + + IL_0024: ldstr "7" + IL_0029: call void [mscorlib]System.Console::WriteLine(string) + IL_002e: br.s IL_0036 + + IL_0030: ldloc.0 + IL_0031: ldc.i4.1 + IL_0032: add + IL_0033: stloc.0 + IL_0034: br.s IL_0008 + + IL_0036: ldc.i4 0x80000000 + IL_003b: stloc.0 + IL_003c: ldloc.0 + IL_003d: ret + } // end of method Loops::InterestingLoop + .method private hidebysig instance bool Condition(string arg) cil managed { @@ -1845,6 +1937,80 @@ IL_0075: ret } // end of method Loops::WhileLoop + .method public hidebysig instance void + WhileWithGoto() cil managed + { + // Code size 64 (0x40) + .maxstack 2 + IL_0000: br.s IL_0032 + + IL_0002: ldarg.0 + IL_0003: ldstr "Condition" + IL_0008: call instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.Loops::Condition(string) + IL_000d: brfalse.s IL_0026 + + IL_000f: ldstr "Block1" + IL_0014: call void [mscorlib]System.Console::WriteLine(string) + IL_0019: ldarg.0 + IL_001a: ldstr "Condition2" + IL_001f: call instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.Loops::Condition(string) + IL_0024: brtrue.s IL_0032 + + IL_0026: ldstr "Block2" + IL_002b: call void [mscorlib]System.Console::WriteLine(string) + IL_0030: br.s IL_000f + + IL_0032: ldarg.0 + IL_0033: ldstr "Main Loop" + IL_0038: call instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.Loops::Condition(string) + IL_003d: brtrue.s IL_0002 + + IL_003f: ret + } // end of method Loops::WhileWithGoto + + .method public hidebysig instance void + DoWhileLoop() cil managed + { + // Code size 116 (0x74) + .maxstack 2 + IL_0000: ldstr "Initial" + IL_0005: call void [mscorlib]System.Console::WriteLine(string) + IL_000a: ldarg.0 + IL_000b: ldstr "if" + IL_0010: call instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.Loops::Condition(string) + IL_0015: brfalse.s IL_0069 + + IL_0017: ldstr "Loop Body" + IL_001c: call void [mscorlib]System.Console::WriteLine(string) + IL_0021: ldarg.0 + IL_0022: ldstr "test" + IL_0027: call instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.Loops::Condition(string) + IL_002c: brfalse.s IL_0048 + + IL_002e: ldarg.0 + IL_002f: ldstr "continue" + IL_0034: call instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.Loops::Condition(string) + IL_0039: brtrue.s IL_0052 + + IL_003b: ldarg.0 + IL_003c: ldstr "break" + IL_0041: call instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.Loops::Condition(string) + IL_0046: brfalse.s IL_005f + + IL_0048: ldstr "End of loop body" + IL_004d: call void [mscorlib]System.Console::WriteLine(string) + IL_0052: ldarg.0 + IL_0053: ldstr "while" + IL_0058: call instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.Loops::Condition(string) + IL_005d: brtrue.s IL_0017 + + IL_005f: ldstr "After loop" + IL_0064: call void [mscorlib]System.Console::WriteLine(string) + IL_0069: ldstr "End of method" + IL_006e: call void [mscorlib]System.Console::WriteLine(string) + IL_0073: ret + } // end of method Loops::DoWhileLoop + .method public hidebysig instance void ForLoop() cil managed { @@ -2013,6 +2179,145 @@ IL_0038: ret } // end of method Loops::ForeachLoopWithEarlyReturn + .method public hidebysig instance void + NestedForeach(class [mscorlib]System.Collections.Generic.List`1 items1, + class [mscorlib]System.Collections.Generic.List`1 items2) cil managed + { + // Code size 112 (0x70) + .maxstack 2 + .locals init (valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator V_0, + object V_1, + bool V_2, + valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator V_3) + IL_0000: ldarg.1 + IL_0001: callvirt instance valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator class [mscorlib]System.Collections.Generic.List`1::GetEnumerator() + IL_0006: stloc.0 + .try + { + IL_0007: br.s IL_004c + + IL_0009: ldloca.s V_0 + IL_000b: call instance !0 valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator::get_Current() + IL_0010: stloc.1 + IL_0011: ldc.i4.0 + IL_0012: stloc.2 + IL_0013: ldarg.2 + IL_0014: callvirt instance valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator class [mscorlib]System.Collections.Generic.List`1::GetEnumerator() + IL_0019: stloc.3 + .try + { + IL_001a: br.s IL_002a + + IL_001c: ldloca.s V_3 + IL_001e: call instance !0 valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator::get_Current() + IL_0023: ldloc.1 + IL_0024: bne.un.s IL_002a + + IL_0026: ldc.i4.1 + IL_0027: stloc.2 + IL_0028: leave.s IL_0043 + + IL_002a: ldloca.s V_3 + IL_002c: call instance bool valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator::MoveNext() + IL_0031: brtrue.s IL_001c + + IL_0033: leave.s IL_0043 + + } // end .try + finally + { + IL_0035: ldloca.s V_3 + IL_0037: constrained. valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator + IL_003d: callvirt instance void [mscorlib]System.IDisposable::Dispose() + IL_0042: endfinally + } // end handler + IL_0043: ldloc.2 + IL_0044: brtrue.s IL_004c + + IL_0046: ldloc.1 + IL_0047: call void [mscorlib]System.Console::WriteLine(object) + IL_004c: ldloca.s V_0 + IL_004e: call instance bool valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator::MoveNext() + IL_0053: brtrue.s IL_0009 + + IL_0055: leave.s IL_0065 + + } // end .try + finally + { + IL_0057: ldloca.s V_0 + IL_0059: constrained. valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator + IL_005f: callvirt instance void [mscorlib]System.IDisposable::Dispose() + IL_0064: endfinally + } // end handler + IL_0065: ldstr "end" + IL_006a: call void [mscorlib]System.Console::WriteLine(string) + IL_006f: ret + } // end of method Loops::NestedForeach + + .method public hidebysig instance void + MergeAroundContinue() cil managed + { + // Code size 69 (0x45) + .maxstack 2 + .locals init (int32 V_0) + IL_0000: ldc.i4.0 + IL_0001: stloc.0 + IL_0002: br.s IL_0035 + + IL_0004: ldloc.0 + IL_0005: ldc.i4.3 + IL_0006: rem + IL_0007: brtrue.s IL_000f + + IL_0009: ldloc.0 + IL_000a: ldc.i4.6 + IL_000b: beq.s IL_002b + + IL_000d: br.s IL_0031 + + IL_000f: ldloc.0 + IL_0010: ldc.i4.5 + IL_0011: rem + IL_0012: brtrue.s IL_001a + + IL_0014: ldloc.0 + IL_0015: ldc.i4.5 + IL_0016: beq.s IL_002b + + IL_0018: br.s IL_0031 + + IL_001a: ldloc.0 + IL_001b: ldc.i4.7 + IL_001c: rem + IL_001d: brtrue.s IL_0025 + + IL_001f: ldloc.0 + IL_0020: ldc.i4.7 + IL_0021: beq.s IL_002b + + IL_0023: br.s IL_0031 + + IL_0025: ldloc.0 + IL_0026: ldc.i4.s 11 + IL_0028: rem + IL_0029: brfalse.s IL_0031 + + IL_002b: ldloc.0 + IL_002c: call void [mscorlib]System.Console::WriteLine(int32) + IL_0031: ldloc.0 + IL_0032: ldc.i4.1 + IL_0033: add + IL_0034: stloc.0 + IL_0035: ldloc.0 + IL_0036: ldc.i4.s 20 + IL_0038: blt.s IL_0004 + + IL_003a: ldstr "end" + IL_003f: call void [mscorlib]System.Console::WriteLine(string) + IL_0044: ret + } // end of method Loops::MergeAroundContinue + .method public hidebysig specialname rtspecialname instance void .ctor() cil managed { diff --git a/ICSharpCode.Decompiler.Tests/TestCases/Pretty/Loops.roslyn.il b/ICSharpCode.Decompiler.Tests/TestCases/Pretty/Loops.roslyn.il index d20845c22..40e3f3412 100644 --- a/ICSharpCode.Decompiler.Tests/TestCases/Pretty/Loops.roslyn.il +++ b/ICSharpCode.Decompiler.Tests/TestCases/Pretty/Loops.roslyn.il @@ -2149,6 +2149,186 @@ IL_004e: ret } // end of method Loops::NestedLoops + .method public hidebysig instance int32 + MultipleExits() cil managed + { + // Code size 88 (0x58) + .maxstack 2 + .locals init (int32 V_0, + bool V_1, + int32 V_2, + bool V_3, + bool V_4, + bool V_5, + bool V_6) + IL_0000: nop + IL_0001: ldc.i4.0 + IL_0002: stloc.0 + IL_0003: br.s IL_0049 + + IL_0005: nop + IL_0006: ldloc.0 + IL_0007: ldc.i4.4 + IL_0008: rem + IL_0009: ldc.i4.0 + IL_000a: ceq + IL_000c: stloc.1 + IL_000d: ldloc.1 + IL_000e: brfalse.s IL_0015 + + IL_0010: nop + IL_0011: ldc.i4.4 + IL_0012: stloc.2 + IL_0013: br.s IL_0056 + + IL_0015: ldloc.0 + IL_0016: ldc.i4.7 + IL_0017: rem + IL_0018: ldc.i4.0 + IL_0019: ceq + IL_001b: stloc.3 + IL_001c: ldloc.3 + IL_001d: brfalse.s IL_0022 + + IL_001f: nop + IL_0020: br.s IL_004e + + IL_0022: ldloc.0 + IL_0023: ldc.i4.s 9 + IL_0025: rem + IL_0026: ldc.i4.0 + IL_0027: ceq + IL_0029: stloc.s V_4 + IL_002b: ldloc.s V_4 + IL_002d: brfalse.s IL_0034 + + IL_002f: nop + IL_0030: ldc.i4.5 + IL_0031: stloc.2 + IL_0032: br.s IL_0056 + + IL_0034: ldloc.0 + IL_0035: ldc.i4.s 11 + IL_0037: rem + IL_0038: ldc.i4.0 + IL_0039: ceq + IL_003b: stloc.s V_5 + IL_003d: ldloc.s V_5 + IL_003f: brfalse.s IL_0044 + + IL_0041: nop + IL_0042: br.s IL_004e + + IL_0044: ldloc.0 + IL_0045: ldc.i4.1 + IL_0046: add + IL_0047: stloc.0 + IL_0048: nop + IL_0049: ldc.i4.1 + IL_004a: stloc.s V_6 + IL_004c: br.s IL_0005 + + IL_004e: ldc.i4 0x80000000 + IL_0053: stloc.2 + IL_0054: br.s IL_0056 + + IL_0056: ldloc.2 + IL_0057: ret + } // end of method Loops::MultipleExits + + .method public hidebysig instance int32 + InterestingLoop() cil managed + { + // Code size 110 (0x6e) + .maxstack 2 + .locals init (int32 V_0, + bool V_1, + bool V_2, + bool V_3, + bool V_4, + bool V_5, + int32 V_6) + IL_0000: nop + IL_0001: ldc.i4.0 + IL_0002: stloc.0 + IL_0003: ldloc.0 + IL_0004: ldc.i4.s 11 + IL_0006: rem + IL_0007: ldc.i4.0 + IL_0008: ceq + IL_000a: stloc.1 + IL_000b: ldloc.1 + IL_000c: brfalse.s IL_0066 + + IL_000e: nop + IL_000f: br.s IL_005a + + IL_0011: nop + IL_0012: ldloc.0 + IL_0013: ldc.i4.4 + IL_0014: rem + IL_0015: ldc.i4.0 + IL_0016: ceq + IL_0018: stloc.2 + IL_0019: ldloc.2 + IL_001a: brfalse.s IL_0053 + + IL_001c: nop + IL_001d: ldloc.0 + IL_001e: ldc.i4.7 + IL_001f: rem + IL_0020: ldc.i4.0 + IL_0021: cgt.un + IL_0023: stloc.3 + IL_0024: ldloc.3 + IL_0025: brfalse.s IL_0035 + + IL_0027: nop + IL_0028: ldstr "!7" + IL_002d: call void [mscorlib]System.Console::WriteLine(string) + IL_0032: nop + IL_0033: br.s IL_005f + + IL_0035: ldloc.0 + IL_0036: ldc.i4.s 11 + IL_0038: rem + IL_0039: ldc.i4.0 + IL_003a: cgt.un + IL_003c: stloc.s V_4 + IL_003e: ldloc.s V_4 + IL_0040: brfalse.s IL_0050 + + IL_0042: nop + IL_0043: ldstr "7" + IL_0048: call void [mscorlib]System.Console::WriteLine(string) + IL_004d: nop + IL_004e: br.s IL_005f + + IL_0050: nop + IL_0051: br.s IL_0059 + + IL_0053: nop + IL_0054: ldloc.0 + IL_0055: ldc.i4.1 + IL_0056: add + IL_0057: stloc.0 + IL_0058: nop + IL_0059: nop + IL_005a: ldc.i4.1 + IL_005b: stloc.s V_5 + IL_005d: br.s IL_0011 + + IL_005f: ldc.i4 0x80000000 + IL_0064: stloc.0 + IL_0065: nop + IL_0066: ldloc.0 + IL_0067: stloc.s V_6 + IL_0069: br.s IL_006b + + IL_006b: ldloc.s V_6 + IL_006d: ret + } // end of method Loops::InterestingLoop + .method private hidebysig instance bool Condition(string arg) cil managed { @@ -2250,6 +2430,84 @@ IL_0096: ret } // end of method Loops::WhileLoop + .method public hidebysig instance void + DoWhileLoop() cil managed + { + // Code size 149 (0x95) + .maxstack 2 + .locals init (bool V_0, + bool V_1, + bool V_2, + bool V_3, + bool V_4) + IL_0000: nop + IL_0001: ldstr "Initial" + IL_0006: call void [mscorlib]System.Console::WriteLine(string) + IL_000b: nop + IL_000c: ldarg.0 + IL_000d: ldstr "if" + IL_0012: call instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.Loops::Condition(string) + IL_0017: stloc.0 + IL_0018: ldloc.0 + IL_0019: brfalse.s IL_0089 + + IL_001b: nop + IL_001c: nop + IL_001d: ldstr "Loop Body" + IL_0022: call void [mscorlib]System.Console::WriteLine(string) + IL_0027: nop + IL_0028: ldarg.0 + IL_0029: ldstr "test" + IL_002e: call instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.Loops::Condition(string) + IL_0033: stloc.1 + IL_0034: ldloc.1 + IL_0035: brfalse.s IL_0060 + + IL_0037: nop + IL_0038: ldarg.0 + IL_0039: ldstr "continue" + IL_003e: call instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.Loops::Condition(string) + IL_0043: stloc.2 + IL_0044: ldloc.2 + IL_0045: brfalse.s IL_004a + + IL_0047: nop + IL_0048: br.s IL_006c + + IL_004a: ldarg.0 + IL_004b: ldstr "break" + IL_0050: call instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.Loops::Condition(string) + IL_0055: ldc.i4.0 + IL_0056: ceq + IL_0058: stloc.3 + IL_0059: ldloc.3 + IL_005a: brfalse.s IL_005f + + IL_005c: nop + IL_005d: br.s IL_007d + + IL_005f: nop + IL_0060: ldstr "End of loop body" + IL_0065: call void [mscorlib]System.Console::WriteLine(string) + IL_006a: nop + IL_006b: nop + IL_006c: ldarg.0 + IL_006d: ldstr "while" + IL_0072: call instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.Loops::Condition(string) + IL_0077: stloc.s V_4 + IL_0079: ldloc.s V_4 + IL_007b: brtrue.s IL_001c + + IL_007d: ldstr "After loop" + IL_0082: call void [mscorlib]System.Console::WriteLine(string) + IL_0087: nop + IL_0088: nop + IL_0089: ldstr "End of method" + IL_008e: call void [mscorlib]System.Console::WriteLine(string) + IL_0093: nop + IL_0094: ret + } // end of method Loops::DoWhileLoop + .method public hidebysig instance void ForLoop() cil managed { @@ -2494,6 +2752,231 @@ IL_0043: ret } // end of method Loops::ForeachLoopWithEarlyReturn + .method public hidebysig instance void + NestedForeach(class [mscorlib]System.Collections.Generic.List`1 items1, + class [mscorlib]System.Collections.Generic.List`1 items2) cil managed + { + // Code size 141 (0x8d) + .maxstack 2 + .locals init (valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator V_0, + object V_1, + bool V_2, + valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator V_3, + object V_4, + bool V_5, + bool V_6) + IL_0000: nop + IL_0001: nop + IL_0002: ldarg.1 + IL_0003: callvirt instance valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator class [mscorlib]System.Collections.Generic.List`1::GetEnumerator() + IL_0008: stloc.0 + .try + { + IL_0009: br.s IL_0067 + + IL_000b: ldloca.s V_0 + IL_000d: call instance !0 valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator::get_Current() + IL_0012: stloc.1 + IL_0013: nop + IL_0014: ldc.i4.0 + IL_0015: stloc.2 + IL_0016: nop + IL_0017: ldarg.2 + IL_0018: callvirt instance valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator class [mscorlib]System.Collections.Generic.List`1::GetEnumerator() + IL_001d: stloc.3 + .try + { + IL_001e: br.s IL_003b + + IL_0020: ldloca.s V_3 + IL_0022: call instance !0 valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator::get_Current() + IL_0027: stloc.s V_4 + IL_0029: nop + IL_002a: ldloc.s V_4 + IL_002c: ldloc.1 + IL_002d: ceq + IL_002f: stloc.s V_5 + IL_0031: ldloc.s V_5 + IL_0033: brfalse.s IL_003a + + IL_0035: nop + IL_0036: ldc.i4.1 + IL_0037: stloc.2 + IL_0038: br.s IL_0044 + + IL_003a: nop + IL_003b: ldloca.s V_3 + IL_003d: call instance bool valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator::MoveNext() + IL_0042: brtrue.s IL_0020 + + IL_0044: leave.s IL_0055 + + } // end .try + finally + { + IL_0046: ldloca.s V_3 + IL_0048: constrained. valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator + IL_004e: callvirt instance void [mscorlib]System.IDisposable::Dispose() + IL_0053: nop + IL_0054: endfinally + } // end handler + IL_0055: ldloc.2 + IL_0056: ldc.i4.0 + IL_0057: ceq + IL_0059: stloc.s V_6 + IL_005b: ldloc.s V_6 + IL_005d: brfalse.s IL_0066 + + IL_005f: ldloc.1 + IL_0060: call void [mscorlib]System.Console::WriteLine(object) + IL_0065: nop + IL_0066: nop + IL_0067: ldloca.s V_0 + IL_0069: call instance bool valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator::MoveNext() + IL_006e: brtrue.s IL_000b + + IL_0070: leave.s IL_0081 + + } // end .try + finally + { + IL_0072: ldloca.s V_0 + IL_0074: constrained. valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator + IL_007a: callvirt instance void [mscorlib]System.IDisposable::Dispose() + IL_007f: nop + IL_0080: endfinally + } // end handler + IL_0081: ldstr "end" + IL_0086: call void [mscorlib]System.Console::WriteLine(string) + IL_008b: nop + IL_008c: ret + } // end of method Loops::NestedForeach + + .method public hidebysig instance void + MergeAroundContinue() cil managed + { + // Code size 144 (0x90) + .maxstack 2 + .locals init (int32 V_0, + bool V_1, + bool V_2, + bool V_3, + bool V_4, + bool V_5, + bool V_6, + bool V_7, + bool V_8) + IL_0000: nop + IL_0001: ldc.i4.0 + IL_0002: stloc.0 + IL_0003: br.s IL_0079 + + IL_0005: nop + IL_0006: ldloc.0 + IL_0007: ldc.i4.3 + IL_0008: rem + IL_0009: ldc.i4.0 + IL_000a: ceq + IL_000c: stloc.1 + IL_000d: ldloc.1 + IL_000e: brfalse.s IL_0021 + + IL_0010: nop + IL_0011: ldloc.0 + IL_0012: ldc.i4.6 + IL_0013: ceq + IL_0015: ldc.i4.0 + IL_0016: ceq + IL_0018: stloc.2 + IL_0019: ldloc.2 + IL_001a: brfalse.s IL_001e + + IL_001c: br.s IL_0075 + + IL_001e: nop + IL_001f: br.s IL_006d + + IL_0021: ldloc.0 + IL_0022: ldc.i4.5 + IL_0023: rem + IL_0024: ldc.i4.0 + IL_0025: ceq + IL_0027: stloc.3 + IL_0028: ldloc.3 + IL_0029: brfalse.s IL_003e + + IL_002b: nop + IL_002c: ldloc.0 + IL_002d: ldc.i4.5 + IL_002e: ceq + IL_0030: ldc.i4.0 + IL_0031: ceq + IL_0033: stloc.s V_4 + IL_0035: ldloc.s V_4 + IL_0037: brfalse.s IL_003b + + IL_0039: br.s IL_0075 + + IL_003b: nop + IL_003c: br.s IL_006d + + IL_003e: ldloc.0 + IL_003f: ldc.i4.7 + IL_0040: rem + IL_0041: ldc.i4.0 + IL_0042: ceq + IL_0044: stloc.s V_5 + IL_0046: ldloc.s V_5 + IL_0048: brfalse.s IL_005d + + IL_004a: nop + IL_004b: ldloc.0 + IL_004c: ldc.i4.7 + IL_004d: ceq + IL_004f: ldc.i4.0 + IL_0050: ceq + IL_0052: stloc.s V_6 + IL_0054: ldloc.s V_6 + IL_0056: brfalse.s IL_005a + + IL_0058: br.s IL_0075 + + IL_005a: nop + IL_005b: br.s IL_006d + + IL_005d: ldloc.0 + IL_005e: ldc.i4.s 11 + IL_0060: rem + IL_0061: ldc.i4.0 + IL_0062: ceq + IL_0064: stloc.s V_7 + IL_0066: ldloc.s V_7 + IL_0068: brfalse.s IL_006d + + IL_006a: nop + IL_006b: br.s IL_0075 + + IL_006d: ldloc.0 + IL_006e: call void [mscorlib]System.Console::WriteLine(int32) + IL_0073: nop + IL_0074: nop + IL_0075: ldloc.0 + IL_0076: ldc.i4.1 + IL_0077: add + IL_0078: stloc.0 + IL_0079: ldloc.0 + IL_007a: ldc.i4.s 20 + IL_007c: clt + IL_007e: stloc.s V_8 + IL_0080: ldloc.s V_8 + IL_0082: brtrue.s IL_0005 + + IL_0084: ldstr "end" + IL_0089: call void [mscorlib]System.Console::WriteLine(string) + IL_008e: nop + IL_008f: ret + } // end of method Loops::MergeAroundContinue + .method public hidebysig specialname rtspecialname instance void .ctor() cil managed { diff --git a/ICSharpCode.Decompiler.Tests/TestCases/Pretty/ShortCircuit.cs b/ICSharpCode.Decompiler.Tests/TestCases/Pretty/ShortCircuit.cs index 8395774c5..f89058b5f 100644 --- a/ICSharpCode.Decompiler.Tests/TestCases/Pretty/ShortCircuit.cs +++ b/ICSharpCode.Decompiler.Tests/TestCases/Pretty/ShortCircuit.cs @@ -51,6 +51,21 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty { B((F(0) && F(1)) ? F(2) : F(3)); } + + public void ExprMix4A() + { + B(((F(0) || F(1)) && F(2)) || F(3)); + } + + public void ExprMix4B() + { + B((F(0) || F(1)) && (F(2) || F(3))); + } + + public void ExprMix4C() + { + B((F(0) && F(1)) || (F(2) && F(3))); + } public void StmtAnd2() { @@ -61,8 +76,15 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty } E(); } + + public void StmtOr2A() + { + if (F(0) || F(1)) { + M1(); + } + } - public void StmtOr2() + public void StmtOr2B() { if (F(0) || F(1)) { M1(); @@ -84,7 +106,7 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty public void StmtOr3() { - if (F(0) || F(1) || F(3)) { + if (F(0) || F(1) || F(2)) { M1(); } else { M2(); @@ -102,6 +124,70 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty E(); } + public void StmtMix3A() + { + if ((F(0) || F(1)) && F(2)) { + M1(); + } + } + + public void StmtMix3B() + { + if ((F(0) || F(1)) && F(2)) { + M1(); + } else { + M2(); + } + } + + public void StmtMix4V1A() + { + if (((F(0) || F(1)) && F(2)) || F(3)) { + M1(); + } + } + + public void StmtMix4V1B() + { + if (((F(0) || F(1)) && F(2)) || F(3)) { + M1(); + } else { + M2(); + } + } + + public void StmtMix4V2A() + { + if ((F(0) || F(1)) && (F(2) || F(3))) { + M1(); + } + } + + public void StmtMix4V2B() + { + if ((F(0) || F(1)) && (F(2) || F(3))) { + M1(); + } else { + M2(); + } + } + + public void StmtMix4V3A() + { + if ((F(0) && F(1)) || (F(2) && F(3))) { + M1(); + } + } + + public void StmtMix4V3B() + { + if ((F(0) && F(1)) || (F(2) && F(3))) { + M1(); + } else { + M2(); + } + } + public void StmtComplex() { if (F(0) && F(1) && !F(2) && (F(3) || F(4))) { @@ -141,5 +227,29 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty } E(); } + + public void StmtComplex5() + { + if (F(0)) { + if (!F(1) && !F(2)) { + return; + } + } else if (!F(3) || !F(4)) { + M2(); + return; + } + E(); + } + + public int StmtComplex6() + { + if (F(0)) { + M1(); + if (F(1) || F(2)) { + return 1; + } + } + return 2; + } } } diff --git a/ICSharpCode.Decompiler.Tests/TestCases/Pretty/ShortCircuit.il b/ICSharpCode.Decompiler.Tests/TestCases/Pretty/ShortCircuit.il index 970c9135e..aef2f09e0 100644 --- a/ICSharpCode.Decompiler.Tests/TestCases/Pretty/ShortCircuit.il +++ b/ICSharpCode.Decompiler.Tests/TestCases/Pretty/ShortCircuit.il @@ -167,6 +167,116 @@ IL_002b: ret } // end of method ShortCircuit::ExprCondAnd + .method public hidebysig instance void + ExprMix4A() cil managed + { + // Code size 47 (0x2f) + .maxstack 8 + IL_0000: nop + IL_0001: ldarg.0 + IL_0002: ldarg.0 + IL_0003: ldc.i4.0 + IL_0004: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ShortCircuit::F(int32) + IL_0009: brtrue.s IL_0014 + + IL_000b: ldarg.0 + IL_000c: ldc.i4.1 + IL_000d: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ShortCircuit::F(int32) + IL_0012: brfalse.s IL_001d + + IL_0014: ldarg.0 + IL_0015: ldc.i4.2 + IL_0016: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ShortCircuit::F(int32) + IL_001b: brtrue.s IL_0026 + + IL_001d: ldarg.0 + IL_001e: ldc.i4.3 + IL_001f: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ShortCircuit::F(int32) + IL_0024: br.s IL_0027 + + IL_0026: ldc.i4.1 + IL_0027: nop + IL_0028: callvirt instance void ICSharpCode.Decompiler.Tests.TestCases.Pretty.ShortCircuit::B(bool) + IL_002d: nop + IL_002e: ret + } // end of method ShortCircuit::ExprMix4A + + .method public hidebysig instance void + ExprMix4B() cil managed + { + // Code size 51 (0x33) + .maxstack 8 + IL_0000: nop + IL_0001: ldarg.0 + IL_0002: ldarg.0 + IL_0003: ldc.i4.0 + IL_0004: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ShortCircuit::F(int32) + IL_0009: brtrue.s IL_0014 + + IL_000b: ldarg.0 + IL_000c: ldc.i4.1 + IL_000d: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ShortCircuit::F(int32) + IL_0012: brfalse.s IL_002a + + IL_0014: ldarg.0 + IL_0015: ldc.i4.2 + IL_0016: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ShortCircuit::F(int32) + IL_001b: brtrue.s IL_0026 + + IL_001d: ldarg.0 + IL_001e: ldc.i4.3 + IL_001f: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ShortCircuit::F(int32) + IL_0024: br.s IL_0027 + + IL_0026: ldc.i4.1 + IL_0027: nop + IL_0028: br.s IL_002b + + IL_002a: ldc.i4.0 + IL_002b: nop + IL_002c: callvirt instance void ICSharpCode.Decompiler.Tests.TestCases.Pretty.ShortCircuit::B(bool) + IL_0031: nop + IL_0032: ret + } // end of method ShortCircuit::ExprMix4B + + .method public hidebysig instance void + ExprMix4C() cil managed + { + // Code size 51 (0x33) + .maxstack 8 + IL_0000: nop + IL_0001: ldarg.0 + IL_0002: ldarg.0 + IL_0003: ldc.i4.0 + IL_0004: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ShortCircuit::F(int32) + IL_0009: brfalse.s IL_0014 + + IL_000b: ldarg.0 + IL_000c: ldc.i4.1 + IL_000d: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ShortCircuit::F(int32) + IL_0012: brtrue.s IL_002a + + IL_0014: ldarg.0 + IL_0015: ldc.i4.2 + IL_0016: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ShortCircuit::F(int32) + IL_001b: brfalse.s IL_0026 + + IL_001d: ldarg.0 + IL_001e: ldc.i4.3 + IL_001f: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ShortCircuit::F(int32) + IL_0024: br.s IL_0027 + + IL_0026: ldc.i4.0 + IL_0027: nop + IL_0028: br.s IL_002b + + IL_002a: ldc.i4.1 + IL_002b: nop + IL_002c: callvirt instance void ICSharpCode.Decompiler.Tests.TestCases.Pretty.ShortCircuit::B(bool) + IL_0031: nop + IL_0032: ret + } // end of method ShortCircuit::ExprMix4C + .method public hidebysig instance void StmtAnd2() cil managed { @@ -211,7 +321,40 @@ } // end of method ShortCircuit::StmtAnd2 .method public hidebysig instance void - StmtOr2() cil managed + StmtOr2A() cil managed + { + // Code size 38 (0x26) + .maxstack 2 + .locals init (bool V_0) + IL_0000: nop + IL_0001: ldarg.0 + IL_0002: ldc.i4.0 + IL_0003: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ShortCircuit::F(int32) + IL_0008: brtrue.s IL_0016 + + IL_000a: ldarg.0 + IL_000b: ldc.i4.1 + IL_000c: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ShortCircuit::F(int32) + IL_0011: ldc.i4.0 + IL_0012: ceq + IL_0014: br.s IL_0017 + + IL_0016: ldc.i4.0 + IL_0017: nop + IL_0018: stloc.0 + IL_0019: ldloc.0 + IL_001a: brtrue.s IL_0025 + + IL_001c: nop + IL_001d: ldarg.0 + IL_001e: callvirt instance void ICSharpCode.Decompiler.Tests.TestCases.Pretty.ShortCircuit::M1() + IL_0023: nop + IL_0024: nop + IL_0025: ret + } // end of method ShortCircuit::StmtOr2A + + .method public hidebysig instance void + StmtOr2B() cil managed { // Code size 56 (0x38) .maxstack 2 @@ -251,7 +394,7 @@ IL_0031: callvirt instance void ICSharpCode.Decompiler.Tests.TestCases.Pretty.ShortCircuit::E() IL_0036: nop IL_0037: ret - } // end of method ShortCircuit::StmtOr2 + } // end of method ShortCircuit::StmtOr2B .method public hidebysig instance void StmtAnd3() cil managed @@ -319,7 +462,7 @@ IL_0011: brtrue.s IL_001f IL_0013: ldarg.0 - IL_0014: ldc.i4.3 + IL_0014: ldc.i4.2 IL_0015: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ShortCircuit::F(int32) IL_001a: ldc.i4.0 IL_001b: ceq @@ -392,6 +535,384 @@ IL_0037: ret } // end of method ShortCircuit::StmtOr4 + .method public hidebysig instance void + StmtMix3A() cil managed + { + // Code size 47 (0x2f) + .maxstack 2 + .locals init (bool V_0) + IL_0000: nop + IL_0001: ldarg.0 + IL_0002: ldc.i4.0 + IL_0003: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ShortCircuit::F(int32) + IL_0008: brtrue.s IL_0013 + + IL_000a: ldarg.0 + IL_000b: ldc.i4.1 + IL_000c: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ShortCircuit::F(int32) + IL_0011: brfalse.s IL_001f + + IL_0013: ldarg.0 + IL_0014: ldc.i4.2 + IL_0015: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ShortCircuit::F(int32) + IL_001a: ldc.i4.0 + IL_001b: ceq + IL_001d: br.s IL_0020 + + IL_001f: ldc.i4.1 + IL_0020: nop + IL_0021: stloc.0 + IL_0022: ldloc.0 + IL_0023: brtrue.s IL_002e + + IL_0025: nop + IL_0026: ldarg.0 + IL_0027: callvirt instance void ICSharpCode.Decompiler.Tests.TestCases.Pretty.ShortCircuit::M1() + IL_002c: nop + IL_002d: nop + IL_002e: ret + } // end of method ShortCircuit::StmtMix3A + + .method public hidebysig instance void + StmtMix3B() cil managed + { + // Code size 58 (0x3a) + .maxstack 2 + .locals init (bool V_0) + IL_0000: nop + IL_0001: ldarg.0 + IL_0002: ldc.i4.0 + IL_0003: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ShortCircuit::F(int32) + IL_0008: brtrue.s IL_0013 + + IL_000a: ldarg.0 + IL_000b: ldc.i4.1 + IL_000c: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ShortCircuit::F(int32) + IL_0011: brfalse.s IL_001f + + IL_0013: ldarg.0 + IL_0014: ldc.i4.2 + IL_0015: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ShortCircuit::F(int32) + IL_001a: ldc.i4.0 + IL_001b: ceq + IL_001d: br.s IL_0020 + + IL_001f: ldc.i4.1 + IL_0020: nop + IL_0021: stloc.0 + IL_0022: ldloc.0 + IL_0023: brtrue.s IL_0030 + + IL_0025: nop + IL_0026: ldarg.0 + IL_0027: callvirt instance void ICSharpCode.Decompiler.Tests.TestCases.Pretty.ShortCircuit::M1() + IL_002c: nop + IL_002d: nop + IL_002e: br.s IL_0039 + + IL_0030: nop + IL_0031: ldarg.0 + IL_0032: callvirt instance void ICSharpCode.Decompiler.Tests.TestCases.Pretty.ShortCircuit::M2() + IL_0037: nop + IL_0038: nop + IL_0039: ret + } // end of method ShortCircuit::StmtMix3B + + .method public hidebysig instance void + StmtMix4V1A() cil managed + { + // Code size 56 (0x38) + .maxstack 2 + .locals init (bool V_0) + IL_0000: nop + IL_0001: ldarg.0 + IL_0002: ldc.i4.0 + IL_0003: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ShortCircuit::F(int32) + IL_0008: brtrue.s IL_0013 + + IL_000a: ldarg.0 + IL_000b: ldc.i4.1 + IL_000c: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ShortCircuit::F(int32) + IL_0011: brfalse.s IL_001c + + IL_0013: ldarg.0 + IL_0014: ldc.i4.2 + IL_0015: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ShortCircuit::F(int32) + IL_001a: brtrue.s IL_0028 + + IL_001c: ldarg.0 + IL_001d: ldc.i4.3 + IL_001e: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ShortCircuit::F(int32) + IL_0023: ldc.i4.0 + IL_0024: ceq + IL_0026: br.s IL_0029 + + IL_0028: ldc.i4.0 + IL_0029: nop + IL_002a: stloc.0 + IL_002b: ldloc.0 + IL_002c: brtrue.s IL_0037 + + IL_002e: nop + IL_002f: ldarg.0 + IL_0030: callvirt instance void ICSharpCode.Decompiler.Tests.TestCases.Pretty.ShortCircuit::M1() + IL_0035: nop + IL_0036: nop + IL_0037: ret + } // end of method ShortCircuit::StmtMix4V1A + + .method public hidebysig instance void + StmtMix4V1B() cil managed + { + // Code size 67 (0x43) + .maxstack 2 + .locals init (bool V_0) + IL_0000: nop + IL_0001: ldarg.0 + IL_0002: ldc.i4.0 + IL_0003: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ShortCircuit::F(int32) + IL_0008: brtrue.s IL_0013 + + IL_000a: ldarg.0 + IL_000b: ldc.i4.1 + IL_000c: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ShortCircuit::F(int32) + IL_0011: brfalse.s IL_001c + + IL_0013: ldarg.0 + IL_0014: ldc.i4.2 + IL_0015: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ShortCircuit::F(int32) + IL_001a: brtrue.s IL_0028 + + IL_001c: ldarg.0 + IL_001d: ldc.i4.3 + IL_001e: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ShortCircuit::F(int32) + IL_0023: ldc.i4.0 + IL_0024: ceq + IL_0026: br.s IL_0029 + + IL_0028: ldc.i4.0 + IL_0029: nop + IL_002a: stloc.0 + IL_002b: ldloc.0 + IL_002c: brtrue.s IL_0039 + + IL_002e: nop + IL_002f: ldarg.0 + IL_0030: callvirt instance void ICSharpCode.Decompiler.Tests.TestCases.Pretty.ShortCircuit::M1() + IL_0035: nop + IL_0036: nop + IL_0037: br.s IL_0042 + + IL_0039: nop + IL_003a: ldarg.0 + IL_003b: callvirt instance void ICSharpCode.Decompiler.Tests.TestCases.Pretty.ShortCircuit::M2() + IL_0040: nop + IL_0041: nop + IL_0042: ret + } // end of method ShortCircuit::StmtMix4V1B + + .method public hidebysig instance void + StmtMix4V2A() cil managed + { + // Code size 60 (0x3c) + .maxstack 2 + .locals init (bool V_0) + IL_0000: nop + IL_0001: ldarg.0 + IL_0002: ldc.i4.0 + IL_0003: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ShortCircuit::F(int32) + IL_0008: brtrue.s IL_0013 + + IL_000a: ldarg.0 + IL_000b: ldc.i4.1 + IL_000c: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ShortCircuit::F(int32) + IL_0011: brfalse.s IL_002c + + IL_0013: ldarg.0 + IL_0014: ldc.i4.2 + IL_0015: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ShortCircuit::F(int32) + IL_001a: brtrue.s IL_0028 + + IL_001c: ldarg.0 + IL_001d: ldc.i4.3 + IL_001e: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ShortCircuit::F(int32) + IL_0023: ldc.i4.0 + IL_0024: ceq + IL_0026: br.s IL_0029 + + IL_0028: ldc.i4.0 + IL_0029: nop + IL_002a: br.s IL_002d + + IL_002c: ldc.i4.1 + IL_002d: nop + IL_002e: stloc.0 + IL_002f: ldloc.0 + IL_0030: brtrue.s IL_003b + + IL_0032: nop + IL_0033: ldarg.0 + IL_0034: callvirt instance void ICSharpCode.Decompiler.Tests.TestCases.Pretty.ShortCircuit::M1() + IL_0039: nop + IL_003a: nop + IL_003b: ret + } // end of method ShortCircuit::StmtMix4V2A + + .method public hidebysig instance void + StmtMix4V2B() cil managed + { + // Code size 71 (0x47) + .maxstack 2 + .locals init (bool V_0) + IL_0000: nop + IL_0001: ldarg.0 + IL_0002: ldc.i4.0 + IL_0003: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ShortCircuit::F(int32) + IL_0008: brtrue.s IL_0013 + + IL_000a: ldarg.0 + IL_000b: ldc.i4.1 + IL_000c: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ShortCircuit::F(int32) + IL_0011: brfalse.s IL_002c + + IL_0013: ldarg.0 + IL_0014: ldc.i4.2 + IL_0015: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ShortCircuit::F(int32) + IL_001a: brtrue.s IL_0028 + + IL_001c: ldarg.0 + IL_001d: ldc.i4.3 + IL_001e: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ShortCircuit::F(int32) + IL_0023: ldc.i4.0 + IL_0024: ceq + IL_0026: br.s IL_0029 + + IL_0028: ldc.i4.0 + IL_0029: nop + IL_002a: br.s IL_002d + + IL_002c: ldc.i4.1 + IL_002d: nop + IL_002e: stloc.0 + IL_002f: ldloc.0 + IL_0030: brtrue.s IL_003d + + IL_0032: nop + IL_0033: ldarg.0 + IL_0034: callvirt instance void ICSharpCode.Decompiler.Tests.TestCases.Pretty.ShortCircuit::M1() + IL_0039: nop + IL_003a: nop + IL_003b: br.s IL_0046 + + IL_003d: nop + IL_003e: ldarg.0 + IL_003f: callvirt instance void ICSharpCode.Decompiler.Tests.TestCases.Pretty.ShortCircuit::M2() + IL_0044: nop + IL_0045: nop + IL_0046: ret + } // end of method ShortCircuit::StmtMix4V2B + + .method public hidebysig instance void + StmtMix4V3A() cil managed + { + // Code size 60 (0x3c) + .maxstack 2 + .locals init (bool V_0) + IL_0000: nop + IL_0001: ldarg.0 + IL_0002: ldc.i4.0 + IL_0003: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ShortCircuit::F(int32) + IL_0008: brfalse.s IL_0013 + + IL_000a: ldarg.0 + IL_000b: ldc.i4.1 + IL_000c: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ShortCircuit::F(int32) + IL_0011: brtrue.s IL_002c + + IL_0013: ldarg.0 + IL_0014: ldc.i4.2 + IL_0015: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ShortCircuit::F(int32) + IL_001a: brfalse.s IL_0028 + + IL_001c: ldarg.0 + IL_001d: ldc.i4.3 + IL_001e: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ShortCircuit::F(int32) + IL_0023: ldc.i4.0 + IL_0024: ceq + IL_0026: br.s IL_0029 + + IL_0028: ldc.i4.1 + IL_0029: nop + IL_002a: br.s IL_002d + + IL_002c: ldc.i4.0 + IL_002d: nop + IL_002e: stloc.0 + IL_002f: ldloc.0 + IL_0030: brtrue.s IL_003b + + IL_0032: nop + IL_0033: ldarg.0 + IL_0034: callvirt instance void ICSharpCode.Decompiler.Tests.TestCases.Pretty.ShortCircuit::M1() + IL_0039: nop + IL_003a: nop + IL_003b: ret + } // end of method ShortCircuit::StmtMix4V3A + + .method public hidebysig instance void + StmtMix4V3B() cil managed + { + // Code size 71 (0x47) + .maxstack 2 + .locals init (bool V_0) + IL_0000: nop + IL_0001: ldarg.0 + IL_0002: ldc.i4.0 + IL_0003: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ShortCircuit::F(int32) + IL_0008: brfalse.s IL_0013 + + IL_000a: ldarg.0 + IL_000b: ldc.i4.1 + IL_000c: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ShortCircuit::F(int32) + IL_0011: brtrue.s IL_002c + + IL_0013: ldarg.0 + IL_0014: ldc.i4.2 + IL_0015: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ShortCircuit::F(int32) + IL_001a: brfalse.s IL_0028 + + IL_001c: ldarg.0 + IL_001d: ldc.i4.3 + IL_001e: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ShortCircuit::F(int32) + IL_0023: ldc.i4.0 + IL_0024: ceq + IL_0026: br.s IL_0029 + + IL_0028: ldc.i4.1 + IL_0029: nop + IL_002a: br.s IL_002d + + IL_002c: ldc.i4.0 + IL_002d: nop + IL_002e: stloc.0 + IL_002f: ldloc.0 + IL_0030: brtrue.s IL_003d + + IL_0032: nop + IL_0033: ldarg.0 + IL_0034: callvirt instance void ICSharpCode.Decompiler.Tests.TestCases.Pretty.ShortCircuit::M1() + IL_0039: nop + IL_003a: nop + IL_003b: br.s IL_0046 + + IL_003d: nop + IL_003e: ldarg.0 + IL_003f: callvirt instance void ICSharpCode.Decompiler.Tests.TestCases.Pretty.ShortCircuit::M2() + IL_0044: nop + IL_0045: nop + IL_0046: ret + } // end of method ShortCircuit::StmtMix4V3B + .method public hidebysig instance void StmtComplex() cil managed { @@ -616,6 +1137,126 @@ IL_0041: ret } // end of method ShortCircuit::StmtComplex4 + .method public hidebysig instance void + StmtComplex5() cil managed + { + // Code size 88 (0x58) + .maxstack 2 + .locals init (bool V_0) + IL_0000: nop + IL_0001: ldarg.0 + IL_0002: ldc.i4.0 + IL_0003: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ShortCircuit::F(int32) + IL_0008: ldc.i4.0 + IL_0009: ceq + IL_000b: stloc.0 + IL_000c: ldloc.0 + IL_000d: brtrue.s IL_002e + + IL_000f: nop + IL_0010: ldarg.0 + IL_0011: ldc.i4.1 + IL_0012: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ShortCircuit::F(int32) + IL_0017: brtrue.s IL_0022 + + IL_0019: ldarg.0 + IL_001a: ldc.i4.2 + IL_001b: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ShortCircuit::F(int32) + IL_0020: br.s IL_0023 + + IL_0022: ldc.i4.1 + IL_0023: nop + IL_0024: stloc.0 + IL_0025: ldloc.0 + IL_0026: brtrue.s IL_002b + + IL_0028: nop + IL_0029: br.s IL_0057 + + IL_002b: nop + IL_002c: br.s IL_0050 + + IL_002e: ldarg.0 + IL_002f: ldc.i4.3 + IL_0030: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ShortCircuit::F(int32) + IL_0035: brfalse.s IL_0040 + + IL_0037: ldarg.0 + IL_0038: ldc.i4.4 + IL_0039: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ShortCircuit::F(int32) + IL_003e: br.s IL_0041 + + IL_0040: ldc.i4.0 + IL_0041: nop + IL_0042: stloc.0 + IL_0043: ldloc.0 + IL_0044: brtrue.s IL_0050 + + IL_0046: nop + IL_0047: ldarg.0 + IL_0048: callvirt instance void ICSharpCode.Decompiler.Tests.TestCases.Pretty.ShortCircuit::M2() + IL_004d: nop + IL_004e: br.s IL_0057 + + IL_0050: ldarg.0 + IL_0051: callvirt instance void ICSharpCode.Decompiler.Tests.TestCases.Pretty.ShortCircuit::E() + IL_0056: nop + IL_0057: ret + } // end of method ShortCircuit::StmtComplex5 + + .method public hidebysig instance int32 + StmtComplex6() cil managed + { + // Code size 62 (0x3e) + .maxstack 2 + .locals init (int32 V_0, + bool V_1) + IL_0000: nop + IL_0001: ldarg.0 + IL_0002: ldc.i4.0 + IL_0003: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ShortCircuit::F(int32) + IL_0008: ldc.i4.0 + IL_0009: ceq + IL_000b: stloc.1 + IL_000c: ldloc.1 + IL_000d: brtrue.s IL_0038 + + IL_000f: nop + IL_0010: ldarg.0 + IL_0011: callvirt instance void ICSharpCode.Decompiler.Tests.TestCases.Pretty.ShortCircuit::M1() + IL_0016: nop + IL_0017: ldarg.0 + IL_0018: ldc.i4.1 + IL_0019: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ShortCircuit::F(int32) + IL_001e: brtrue.s IL_002c + + IL_0020: ldarg.0 + IL_0021: ldc.i4.2 + IL_0022: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ShortCircuit::F(int32) + IL_0027: ldc.i4.0 + IL_0028: ceq + IL_002a: br.s IL_002d + + IL_002c: ldc.i4.0 + IL_002d: nop + IL_002e: stloc.1 + IL_002f: ldloc.1 + IL_0030: brtrue.s IL_0037 + + IL_0032: nop + IL_0033: ldc.i4.1 + IL_0034: stloc.0 + IL_0035: br.s IL_003c + + IL_0037: nop + IL_0038: ldc.i4.2 + IL_0039: stloc.0 + IL_003a: br.s IL_003c + + IL_003c: ldloc.0 + IL_003d: ret + } // end of method ShortCircuit::StmtComplex6 + .method family hidebysig specialname rtspecialname instance void .ctor() cil managed { diff --git a/ICSharpCode.Decompiler.Tests/TestCases/Pretty/ShortCircuit.opt.il b/ICSharpCode.Decompiler.Tests/TestCases/Pretty/ShortCircuit.opt.il index c4b693be9..bc052b300 100644 --- a/ICSharpCode.Decompiler.Tests/TestCases/Pretty/ShortCircuit.opt.il +++ b/ICSharpCode.Decompiler.Tests/TestCases/Pretty/ShortCircuit.opt.il @@ -155,6 +155,105 @@ IL_0028: ret } // end of method ShortCircuit::ExprCondAnd + .method public hidebysig instance void + ExprMix4A() cil managed + { + // Code size 44 (0x2c) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: ldarg.0 + IL_0002: ldc.i4.0 + IL_0003: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ShortCircuit::F(int32) + IL_0008: brtrue.s IL_0013 + + IL_000a: ldarg.0 + IL_000b: ldc.i4.1 + IL_000c: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ShortCircuit::F(int32) + IL_0011: brfalse.s IL_001c + + IL_0013: ldarg.0 + IL_0014: ldc.i4.2 + IL_0015: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ShortCircuit::F(int32) + IL_001a: brtrue.s IL_0025 + + IL_001c: ldarg.0 + IL_001d: ldc.i4.3 + IL_001e: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ShortCircuit::F(int32) + IL_0023: br.s IL_0026 + + IL_0025: ldc.i4.1 + IL_0026: callvirt instance void ICSharpCode.Decompiler.Tests.TestCases.Pretty.ShortCircuit::B(bool) + IL_002b: ret + } // end of method ShortCircuit::ExprMix4A + + .method public hidebysig instance void + ExprMix4B() cil managed + { + // Code size 47 (0x2f) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: ldarg.0 + IL_0002: ldc.i4.0 + IL_0003: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ShortCircuit::F(int32) + IL_0008: brtrue.s IL_0013 + + IL_000a: ldarg.0 + IL_000b: ldc.i4.1 + IL_000c: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ShortCircuit::F(int32) + IL_0011: brfalse.s IL_0028 + + IL_0013: ldarg.0 + IL_0014: ldc.i4.2 + IL_0015: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ShortCircuit::F(int32) + IL_001a: brtrue.s IL_0025 + + IL_001c: ldarg.0 + IL_001d: ldc.i4.3 + IL_001e: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ShortCircuit::F(int32) + IL_0023: br.s IL_0029 + + IL_0025: ldc.i4.1 + IL_0026: br.s IL_0029 + + IL_0028: ldc.i4.0 + IL_0029: callvirt instance void ICSharpCode.Decompiler.Tests.TestCases.Pretty.ShortCircuit::B(bool) + IL_002e: ret + } // end of method ShortCircuit::ExprMix4B + + .method public hidebysig instance void + ExprMix4C() cil managed + { + // Code size 47 (0x2f) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: ldarg.0 + IL_0002: ldc.i4.0 + IL_0003: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ShortCircuit::F(int32) + IL_0008: brfalse.s IL_0013 + + IL_000a: ldarg.0 + IL_000b: ldc.i4.1 + IL_000c: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ShortCircuit::F(int32) + IL_0011: brtrue.s IL_0028 + + IL_0013: ldarg.0 + IL_0014: ldc.i4.2 + IL_0015: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ShortCircuit::F(int32) + IL_001a: brfalse.s IL_0025 + + IL_001c: ldarg.0 + IL_001d: ldc.i4.3 + IL_001e: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ShortCircuit::F(int32) + IL_0023: br.s IL_0029 + + IL_0025: ldc.i4.0 + IL_0026: br.s IL_0029 + + IL_0028: ldc.i4.1 + IL_0029: callvirt instance void ICSharpCode.Decompiler.Tests.TestCases.Pretty.ShortCircuit::B(bool) + IL_002e: ret + } // end of method ShortCircuit::ExprMix4C + .method public hidebysig instance void StmtAnd2() cil managed { @@ -182,7 +281,27 @@ } // end of method ShortCircuit::StmtAnd2 .method public hidebysig instance void - StmtOr2() cil managed + StmtOr2A() cil managed + { + // Code size 25 (0x19) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: ldc.i4.0 + IL_0002: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ShortCircuit::F(int32) + IL_0007: brtrue.s IL_0012 + + IL_0009: ldarg.0 + IL_000a: ldc.i4.1 + IL_000b: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ShortCircuit::F(int32) + IL_0010: brfalse.s IL_0018 + + IL_0012: ldarg.0 + IL_0013: callvirt instance void ICSharpCode.Decompiler.Tests.TestCases.Pretty.ShortCircuit::M1() + IL_0018: ret + } // end of method ShortCircuit::StmtOr2A + + .method public hidebysig instance void + StmtOr2B() cil managed { // Code size 39 (0x27) .maxstack 8 @@ -205,7 +324,7 @@ IL_0020: ldarg.0 IL_0021: callvirt instance void ICSharpCode.Decompiler.Tests.TestCases.Pretty.ShortCircuit::E() IL_0026: ret - } // end of method ShortCircuit::StmtOr2 + } // end of method ShortCircuit::StmtOr2B .method public hidebysig instance void StmtAnd3() cil managed @@ -254,7 +373,7 @@ IL_0010: brtrue.s IL_001b IL_0012: ldarg.0 - IL_0013: ldc.i4.3 + IL_0013: ldc.i4.2 IL_0014: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ShortCircuit::F(int32) IL_0019: brfalse.s IL_0023 @@ -295,6 +414,252 @@ IL_0026: ret } // end of method ShortCircuit::StmtOr4 + .method public hidebysig instance void + StmtMix3A() cil managed + { + // Code size 34 (0x22) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: ldc.i4.0 + IL_0002: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ShortCircuit::F(int32) + IL_0007: brtrue.s IL_0012 + + IL_0009: ldarg.0 + IL_000a: ldc.i4.1 + IL_000b: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ShortCircuit::F(int32) + IL_0010: brfalse.s IL_0021 + + IL_0012: ldarg.0 + IL_0013: ldc.i4.2 + IL_0014: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ShortCircuit::F(int32) + IL_0019: brfalse.s IL_0021 + + IL_001b: ldarg.0 + IL_001c: callvirt instance void ICSharpCode.Decompiler.Tests.TestCases.Pretty.ShortCircuit::M1() + IL_0021: ret + } // end of method ShortCircuit::StmtMix3A + + .method public hidebysig instance void + StmtMix3B() cil managed + { + // Code size 41 (0x29) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: ldc.i4.0 + IL_0002: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ShortCircuit::F(int32) + IL_0007: brtrue.s IL_0012 + + IL_0009: ldarg.0 + IL_000a: ldc.i4.1 + IL_000b: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ShortCircuit::F(int32) + IL_0010: brfalse.s IL_0022 + + IL_0012: ldarg.0 + IL_0013: ldc.i4.2 + IL_0014: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ShortCircuit::F(int32) + IL_0019: brfalse.s IL_0022 + + IL_001b: ldarg.0 + IL_001c: callvirt instance void ICSharpCode.Decompiler.Tests.TestCases.Pretty.ShortCircuit::M1() + IL_0021: ret + + IL_0022: ldarg.0 + IL_0023: callvirt instance void ICSharpCode.Decompiler.Tests.TestCases.Pretty.ShortCircuit::M2() + IL_0028: ret + } // end of method ShortCircuit::StmtMix3B + + .method public hidebysig instance void + StmtMix4V1A() cil managed + { + // Code size 43 (0x2b) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: ldc.i4.0 + IL_0002: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ShortCircuit::F(int32) + IL_0007: brtrue.s IL_0012 + + IL_0009: ldarg.0 + IL_000a: ldc.i4.1 + IL_000b: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ShortCircuit::F(int32) + IL_0010: brfalse.s IL_001b + + IL_0012: ldarg.0 + IL_0013: ldc.i4.2 + IL_0014: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ShortCircuit::F(int32) + IL_0019: brtrue.s IL_0024 + + IL_001b: ldarg.0 + IL_001c: ldc.i4.3 + IL_001d: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ShortCircuit::F(int32) + IL_0022: brfalse.s IL_002a + + IL_0024: ldarg.0 + IL_0025: callvirt instance void ICSharpCode.Decompiler.Tests.TestCases.Pretty.ShortCircuit::M1() + IL_002a: ret + } // end of method ShortCircuit::StmtMix4V1A + + .method public hidebysig instance void + StmtMix4V1B() cil managed + { + // Code size 50 (0x32) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: ldc.i4.0 + IL_0002: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ShortCircuit::F(int32) + IL_0007: brtrue.s IL_0012 + + IL_0009: ldarg.0 + IL_000a: ldc.i4.1 + IL_000b: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ShortCircuit::F(int32) + IL_0010: brfalse.s IL_001b + + IL_0012: ldarg.0 + IL_0013: ldc.i4.2 + IL_0014: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ShortCircuit::F(int32) + IL_0019: brtrue.s IL_0024 + + IL_001b: ldarg.0 + IL_001c: ldc.i4.3 + IL_001d: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ShortCircuit::F(int32) + IL_0022: brfalse.s IL_002b + + IL_0024: ldarg.0 + IL_0025: callvirt instance void ICSharpCode.Decompiler.Tests.TestCases.Pretty.ShortCircuit::M1() + IL_002a: ret + + IL_002b: ldarg.0 + IL_002c: callvirt instance void ICSharpCode.Decompiler.Tests.TestCases.Pretty.ShortCircuit::M2() + IL_0031: ret + } // end of method ShortCircuit::StmtMix4V1B + + .method public hidebysig instance void + StmtMix4V2A() cil managed + { + // Code size 43 (0x2b) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: ldc.i4.0 + IL_0002: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ShortCircuit::F(int32) + IL_0007: brtrue.s IL_0012 + + IL_0009: ldarg.0 + IL_000a: ldc.i4.1 + IL_000b: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ShortCircuit::F(int32) + IL_0010: brfalse.s IL_002a + + IL_0012: ldarg.0 + IL_0013: ldc.i4.2 + IL_0014: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ShortCircuit::F(int32) + IL_0019: brtrue.s IL_0024 + + IL_001b: ldarg.0 + IL_001c: ldc.i4.3 + IL_001d: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ShortCircuit::F(int32) + IL_0022: brfalse.s IL_002a + + IL_0024: ldarg.0 + IL_0025: callvirt instance void ICSharpCode.Decompiler.Tests.TestCases.Pretty.ShortCircuit::M1() + IL_002a: ret + } // end of method ShortCircuit::StmtMix4V2A + + .method public hidebysig instance void + StmtMix4V2B() cil managed + { + // Code size 50 (0x32) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: ldc.i4.0 + IL_0002: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ShortCircuit::F(int32) + IL_0007: brtrue.s IL_0012 + + IL_0009: ldarg.0 + IL_000a: ldc.i4.1 + IL_000b: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ShortCircuit::F(int32) + IL_0010: brfalse.s IL_002b + + IL_0012: ldarg.0 + IL_0013: ldc.i4.2 + IL_0014: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ShortCircuit::F(int32) + IL_0019: brtrue.s IL_0024 + + IL_001b: ldarg.0 + IL_001c: ldc.i4.3 + IL_001d: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ShortCircuit::F(int32) + IL_0022: brfalse.s IL_002b + + IL_0024: ldarg.0 + IL_0025: callvirt instance void ICSharpCode.Decompiler.Tests.TestCases.Pretty.ShortCircuit::M1() + IL_002a: ret + + IL_002b: ldarg.0 + IL_002c: callvirt instance void ICSharpCode.Decompiler.Tests.TestCases.Pretty.ShortCircuit::M2() + IL_0031: ret + } // end of method ShortCircuit::StmtMix4V2B + + .method public hidebysig instance void + StmtMix4V3A() cil managed + { + // Code size 43 (0x2b) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: ldc.i4.0 + IL_0002: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ShortCircuit::F(int32) + IL_0007: brfalse.s IL_0012 + + IL_0009: ldarg.0 + IL_000a: ldc.i4.1 + IL_000b: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ShortCircuit::F(int32) + IL_0010: brtrue.s IL_0024 + + IL_0012: ldarg.0 + IL_0013: ldc.i4.2 + IL_0014: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ShortCircuit::F(int32) + IL_0019: brfalse.s IL_002a + + IL_001b: ldarg.0 + IL_001c: ldc.i4.3 + IL_001d: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ShortCircuit::F(int32) + IL_0022: brfalse.s IL_002a + + IL_0024: ldarg.0 + IL_0025: callvirt instance void ICSharpCode.Decompiler.Tests.TestCases.Pretty.ShortCircuit::M1() + IL_002a: ret + } // end of method ShortCircuit::StmtMix4V3A + + .method public hidebysig instance void + StmtMix4V3B() cil managed + { + // Code size 50 (0x32) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: ldc.i4.0 + IL_0002: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ShortCircuit::F(int32) + IL_0007: brfalse.s IL_0012 + + IL_0009: ldarg.0 + IL_000a: ldc.i4.1 + IL_000b: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ShortCircuit::F(int32) + IL_0010: brtrue.s IL_0024 + + IL_0012: ldarg.0 + IL_0013: ldc.i4.2 + IL_0014: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ShortCircuit::F(int32) + IL_0019: brfalse.s IL_002b + + IL_001b: ldarg.0 + IL_001c: ldc.i4.3 + IL_001d: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ShortCircuit::F(int32) + IL_0022: brfalse.s IL_002b + + IL_0024: ldarg.0 + IL_0025: callvirt instance void ICSharpCode.Decompiler.Tests.TestCases.Pretty.ShortCircuit::M1() + IL_002a: ret + + IL_002b: ldarg.0 + IL_002c: callvirt instance void ICSharpCode.Decompiler.Tests.TestCases.Pretty.ShortCircuit::M2() + IL_0031: ret + } // end of method ShortCircuit::StmtMix4V3B + .method public hidebysig instance void StmtComplex() cil managed { @@ -444,6 +809,76 @@ IL_002e: ret } // end of method ShortCircuit::StmtComplex4 + .method public hidebysig instance void + StmtComplex5() cil managed + { + // Code size 60 (0x3c) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: ldc.i4.0 + IL_0002: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ShortCircuit::F(int32) + IL_0007: brfalse.s IL_001c + + IL_0009: ldarg.0 + IL_000a: ldc.i4.1 + IL_000b: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ShortCircuit::F(int32) + IL_0010: brtrue.s IL_0035 + + IL_0012: ldarg.0 + IL_0013: ldc.i4.2 + IL_0014: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ShortCircuit::F(int32) + IL_0019: brtrue.s IL_0035 + + IL_001b: ret + + IL_001c: ldarg.0 + IL_001d: ldc.i4.3 + IL_001e: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ShortCircuit::F(int32) + IL_0023: brfalse.s IL_002e + + IL_0025: ldarg.0 + IL_0026: ldc.i4.4 + IL_0027: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ShortCircuit::F(int32) + IL_002c: brtrue.s IL_0035 + + IL_002e: ldarg.0 + IL_002f: callvirt instance void ICSharpCode.Decompiler.Tests.TestCases.Pretty.ShortCircuit::M2() + IL_0034: ret + + IL_0035: ldarg.0 + IL_0036: callvirt instance void ICSharpCode.Decompiler.Tests.TestCases.Pretty.ShortCircuit::E() + IL_003b: ret + } // end of method ShortCircuit::StmtComplex5 + + .method public hidebysig instance int32 + StmtComplex6() cil managed + { + // Code size 37 (0x25) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: ldc.i4.0 + IL_0002: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ShortCircuit::F(int32) + IL_0007: brfalse.s IL_0023 + + IL_0009: ldarg.0 + IL_000a: callvirt instance void ICSharpCode.Decompiler.Tests.TestCases.Pretty.ShortCircuit::M1() + IL_000f: ldarg.0 + IL_0010: ldc.i4.1 + IL_0011: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ShortCircuit::F(int32) + IL_0016: brtrue.s IL_0021 + + IL_0018: ldarg.0 + IL_0019: ldc.i4.2 + IL_001a: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ShortCircuit::F(int32) + IL_001f: brfalse.s IL_0023 + + IL_0021: ldc.i4.1 + IL_0022: ret + + IL_0023: ldc.i4.2 + IL_0024: ret + } // end of method ShortCircuit::StmtComplex6 + .method family hidebysig specialname rtspecialname instance void .ctor() cil managed { diff --git a/ICSharpCode.Decompiler.Tests/TestCases/Pretty/ShortCircuit.opt.roslyn.il b/ICSharpCode.Decompiler.Tests/TestCases/Pretty/ShortCircuit.opt.roslyn.il index c6a651817..e9b3fdd90 100644 --- a/ICSharpCode.Decompiler.Tests/TestCases/Pretty/ShortCircuit.opt.roslyn.il +++ b/ICSharpCode.Decompiler.Tests/TestCases/Pretty/ShortCircuit.opt.roslyn.il @@ -159,6 +159,105 @@ IL_0028: ret } // end of method ShortCircuit::ExprCondAnd + .method public hidebysig instance void + ExprMix4A() cil managed + { + // Code size 44 (0x2c) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: ldarg.0 + IL_0002: ldc.i4.0 + IL_0003: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ShortCircuit::F(int32) + IL_0008: brtrue.s IL_0013 + + IL_000a: ldarg.0 + IL_000b: ldc.i4.1 + IL_000c: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ShortCircuit::F(int32) + IL_0011: brfalse.s IL_001c + + IL_0013: ldarg.0 + IL_0014: ldc.i4.2 + IL_0015: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ShortCircuit::F(int32) + IL_001a: brtrue.s IL_0025 + + IL_001c: ldarg.0 + IL_001d: ldc.i4.3 + IL_001e: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ShortCircuit::F(int32) + IL_0023: br.s IL_0026 + + IL_0025: ldc.i4.1 + IL_0026: callvirt instance void ICSharpCode.Decompiler.Tests.TestCases.Pretty.ShortCircuit::B(bool) + IL_002b: ret + } // end of method ShortCircuit::ExprMix4A + + .method public hidebysig instance void + ExprMix4B() cil managed + { + // Code size 47 (0x2f) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: ldarg.0 + IL_0002: ldc.i4.0 + IL_0003: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ShortCircuit::F(int32) + IL_0008: brtrue.s IL_0013 + + IL_000a: ldarg.0 + IL_000b: ldc.i4.1 + IL_000c: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ShortCircuit::F(int32) + IL_0011: brfalse.s IL_0028 + + IL_0013: ldarg.0 + IL_0014: ldc.i4.2 + IL_0015: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ShortCircuit::F(int32) + IL_001a: brtrue.s IL_0025 + + IL_001c: ldarg.0 + IL_001d: ldc.i4.3 + IL_001e: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ShortCircuit::F(int32) + IL_0023: br.s IL_0029 + + IL_0025: ldc.i4.1 + IL_0026: br.s IL_0029 + + IL_0028: ldc.i4.0 + IL_0029: callvirt instance void ICSharpCode.Decompiler.Tests.TestCases.Pretty.ShortCircuit::B(bool) + IL_002e: ret + } // end of method ShortCircuit::ExprMix4B + + .method public hidebysig instance void + ExprMix4C() cil managed + { + // Code size 47 (0x2f) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: ldarg.0 + IL_0002: ldc.i4.0 + IL_0003: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ShortCircuit::F(int32) + IL_0008: brfalse.s IL_0013 + + IL_000a: ldarg.0 + IL_000b: ldc.i4.1 + IL_000c: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ShortCircuit::F(int32) + IL_0011: brtrue.s IL_0028 + + IL_0013: ldarg.0 + IL_0014: ldc.i4.2 + IL_0015: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ShortCircuit::F(int32) + IL_001a: brfalse.s IL_0025 + + IL_001c: ldarg.0 + IL_001d: ldc.i4.3 + IL_001e: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ShortCircuit::F(int32) + IL_0023: br.s IL_0029 + + IL_0025: ldc.i4.0 + IL_0026: br.s IL_0029 + + IL_0028: ldc.i4.1 + IL_0029: callvirt instance void ICSharpCode.Decompiler.Tests.TestCases.Pretty.ShortCircuit::B(bool) + IL_002e: ret + } // end of method ShortCircuit::ExprMix4C + .method public hidebysig instance void StmtAnd2() cil managed { @@ -186,7 +285,27 @@ } // end of method ShortCircuit::StmtAnd2 .method public hidebysig instance void - StmtOr2() cil managed + StmtOr2A() cil managed + { + // Code size 25 (0x19) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: ldc.i4.0 + IL_0002: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ShortCircuit::F(int32) + IL_0007: brtrue.s IL_0012 + + IL_0009: ldarg.0 + IL_000a: ldc.i4.1 + IL_000b: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ShortCircuit::F(int32) + IL_0010: brfalse.s IL_0018 + + IL_0012: ldarg.0 + IL_0013: callvirt instance void ICSharpCode.Decompiler.Tests.TestCases.Pretty.ShortCircuit::M1() + IL_0018: ret + } // end of method ShortCircuit::StmtOr2A + + .method public hidebysig instance void + StmtOr2B() cil managed { // Code size 39 (0x27) .maxstack 8 @@ -209,7 +328,7 @@ IL_0020: ldarg.0 IL_0021: callvirt instance void ICSharpCode.Decompiler.Tests.TestCases.Pretty.ShortCircuit::E() IL_0026: ret - } // end of method ShortCircuit::StmtOr2 + } // end of method ShortCircuit::StmtOr2B .method public hidebysig instance void StmtAnd3() cil managed @@ -258,7 +377,7 @@ IL_0010: brtrue.s IL_001b IL_0012: ldarg.0 - IL_0013: ldc.i4.3 + IL_0013: ldc.i4.2 IL_0014: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ShortCircuit::F(int32) IL_0019: brfalse.s IL_0023 @@ -299,6 +418,252 @@ IL_0026: ret } // end of method ShortCircuit::StmtOr4 + .method public hidebysig instance void + StmtMix3A() cil managed + { + // Code size 34 (0x22) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: ldc.i4.0 + IL_0002: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ShortCircuit::F(int32) + IL_0007: brtrue.s IL_0012 + + IL_0009: ldarg.0 + IL_000a: ldc.i4.1 + IL_000b: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ShortCircuit::F(int32) + IL_0010: brfalse.s IL_0021 + + IL_0012: ldarg.0 + IL_0013: ldc.i4.2 + IL_0014: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ShortCircuit::F(int32) + IL_0019: brfalse.s IL_0021 + + IL_001b: ldarg.0 + IL_001c: callvirt instance void ICSharpCode.Decompiler.Tests.TestCases.Pretty.ShortCircuit::M1() + IL_0021: ret + } // end of method ShortCircuit::StmtMix3A + + .method public hidebysig instance void + StmtMix3B() cil managed + { + // Code size 41 (0x29) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: ldc.i4.0 + IL_0002: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ShortCircuit::F(int32) + IL_0007: brtrue.s IL_0012 + + IL_0009: ldarg.0 + IL_000a: ldc.i4.1 + IL_000b: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ShortCircuit::F(int32) + IL_0010: brfalse.s IL_0022 + + IL_0012: ldarg.0 + IL_0013: ldc.i4.2 + IL_0014: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ShortCircuit::F(int32) + IL_0019: brfalse.s IL_0022 + + IL_001b: ldarg.0 + IL_001c: callvirt instance void ICSharpCode.Decompiler.Tests.TestCases.Pretty.ShortCircuit::M1() + IL_0021: ret + + IL_0022: ldarg.0 + IL_0023: callvirt instance void ICSharpCode.Decompiler.Tests.TestCases.Pretty.ShortCircuit::M2() + IL_0028: ret + } // end of method ShortCircuit::StmtMix3B + + .method public hidebysig instance void + StmtMix4V1A() cil managed + { + // Code size 43 (0x2b) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: ldc.i4.0 + IL_0002: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ShortCircuit::F(int32) + IL_0007: brtrue.s IL_0012 + + IL_0009: ldarg.0 + IL_000a: ldc.i4.1 + IL_000b: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ShortCircuit::F(int32) + IL_0010: brfalse.s IL_001b + + IL_0012: ldarg.0 + IL_0013: ldc.i4.2 + IL_0014: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ShortCircuit::F(int32) + IL_0019: brtrue.s IL_0024 + + IL_001b: ldarg.0 + IL_001c: ldc.i4.3 + IL_001d: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ShortCircuit::F(int32) + IL_0022: brfalse.s IL_002a + + IL_0024: ldarg.0 + IL_0025: callvirt instance void ICSharpCode.Decompiler.Tests.TestCases.Pretty.ShortCircuit::M1() + IL_002a: ret + } // end of method ShortCircuit::StmtMix4V1A + + .method public hidebysig instance void + StmtMix4V1B() cil managed + { + // Code size 50 (0x32) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: ldc.i4.0 + IL_0002: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ShortCircuit::F(int32) + IL_0007: brtrue.s IL_0012 + + IL_0009: ldarg.0 + IL_000a: ldc.i4.1 + IL_000b: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ShortCircuit::F(int32) + IL_0010: brfalse.s IL_001b + + IL_0012: ldarg.0 + IL_0013: ldc.i4.2 + IL_0014: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ShortCircuit::F(int32) + IL_0019: brtrue.s IL_0024 + + IL_001b: ldarg.0 + IL_001c: ldc.i4.3 + IL_001d: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ShortCircuit::F(int32) + IL_0022: brfalse.s IL_002b + + IL_0024: ldarg.0 + IL_0025: callvirt instance void ICSharpCode.Decompiler.Tests.TestCases.Pretty.ShortCircuit::M1() + IL_002a: ret + + IL_002b: ldarg.0 + IL_002c: callvirt instance void ICSharpCode.Decompiler.Tests.TestCases.Pretty.ShortCircuit::M2() + IL_0031: ret + } // end of method ShortCircuit::StmtMix4V1B + + .method public hidebysig instance void + StmtMix4V2A() cil managed + { + // Code size 43 (0x2b) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: ldc.i4.0 + IL_0002: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ShortCircuit::F(int32) + IL_0007: brtrue.s IL_0012 + + IL_0009: ldarg.0 + IL_000a: ldc.i4.1 + IL_000b: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ShortCircuit::F(int32) + IL_0010: brfalse.s IL_002a + + IL_0012: ldarg.0 + IL_0013: ldc.i4.2 + IL_0014: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ShortCircuit::F(int32) + IL_0019: brtrue.s IL_0024 + + IL_001b: ldarg.0 + IL_001c: ldc.i4.3 + IL_001d: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ShortCircuit::F(int32) + IL_0022: brfalse.s IL_002a + + IL_0024: ldarg.0 + IL_0025: callvirt instance void ICSharpCode.Decompiler.Tests.TestCases.Pretty.ShortCircuit::M1() + IL_002a: ret + } // end of method ShortCircuit::StmtMix4V2A + + .method public hidebysig instance void + StmtMix4V2B() cil managed + { + // Code size 50 (0x32) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: ldc.i4.0 + IL_0002: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ShortCircuit::F(int32) + IL_0007: brtrue.s IL_0012 + + IL_0009: ldarg.0 + IL_000a: ldc.i4.1 + IL_000b: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ShortCircuit::F(int32) + IL_0010: brfalse.s IL_002b + + IL_0012: ldarg.0 + IL_0013: ldc.i4.2 + IL_0014: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ShortCircuit::F(int32) + IL_0019: brtrue.s IL_0024 + + IL_001b: ldarg.0 + IL_001c: ldc.i4.3 + IL_001d: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ShortCircuit::F(int32) + IL_0022: brfalse.s IL_002b + + IL_0024: ldarg.0 + IL_0025: callvirt instance void ICSharpCode.Decompiler.Tests.TestCases.Pretty.ShortCircuit::M1() + IL_002a: ret + + IL_002b: ldarg.0 + IL_002c: callvirt instance void ICSharpCode.Decompiler.Tests.TestCases.Pretty.ShortCircuit::M2() + IL_0031: ret + } // end of method ShortCircuit::StmtMix4V2B + + .method public hidebysig instance void + StmtMix4V3A() cil managed + { + // Code size 43 (0x2b) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: ldc.i4.0 + IL_0002: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ShortCircuit::F(int32) + IL_0007: brfalse.s IL_0012 + + IL_0009: ldarg.0 + IL_000a: ldc.i4.1 + IL_000b: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ShortCircuit::F(int32) + IL_0010: brtrue.s IL_0024 + + IL_0012: ldarg.0 + IL_0013: ldc.i4.2 + IL_0014: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ShortCircuit::F(int32) + IL_0019: brfalse.s IL_002a + + IL_001b: ldarg.0 + IL_001c: ldc.i4.3 + IL_001d: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ShortCircuit::F(int32) + IL_0022: brfalse.s IL_002a + + IL_0024: ldarg.0 + IL_0025: callvirt instance void ICSharpCode.Decompiler.Tests.TestCases.Pretty.ShortCircuit::M1() + IL_002a: ret + } // end of method ShortCircuit::StmtMix4V3A + + .method public hidebysig instance void + StmtMix4V3B() cil managed + { + // Code size 50 (0x32) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: ldc.i4.0 + IL_0002: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ShortCircuit::F(int32) + IL_0007: brfalse.s IL_0012 + + IL_0009: ldarg.0 + IL_000a: ldc.i4.1 + IL_000b: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ShortCircuit::F(int32) + IL_0010: brtrue.s IL_0024 + + IL_0012: ldarg.0 + IL_0013: ldc.i4.2 + IL_0014: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ShortCircuit::F(int32) + IL_0019: brfalse.s IL_002b + + IL_001b: ldarg.0 + IL_001c: ldc.i4.3 + IL_001d: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ShortCircuit::F(int32) + IL_0022: brfalse.s IL_002b + + IL_0024: ldarg.0 + IL_0025: callvirt instance void ICSharpCode.Decompiler.Tests.TestCases.Pretty.ShortCircuit::M1() + IL_002a: ret + + IL_002b: ldarg.0 + IL_002c: callvirt instance void ICSharpCode.Decompiler.Tests.TestCases.Pretty.ShortCircuit::M2() + IL_0031: ret + } // end of method ShortCircuit::StmtMix4V3B + .method public hidebysig instance void StmtComplex() cil managed { @@ -448,6 +813,76 @@ IL_002e: ret } // end of method ShortCircuit::StmtComplex4 + .method public hidebysig instance void + StmtComplex5() cil managed + { + // Code size 60 (0x3c) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: ldc.i4.0 + IL_0002: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ShortCircuit::F(int32) + IL_0007: brfalse.s IL_001c + + IL_0009: ldarg.0 + IL_000a: ldc.i4.1 + IL_000b: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ShortCircuit::F(int32) + IL_0010: brtrue.s IL_0035 + + IL_0012: ldarg.0 + IL_0013: ldc.i4.2 + IL_0014: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ShortCircuit::F(int32) + IL_0019: brtrue.s IL_0035 + + IL_001b: ret + + IL_001c: ldarg.0 + IL_001d: ldc.i4.3 + IL_001e: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ShortCircuit::F(int32) + IL_0023: brfalse.s IL_002e + + IL_0025: ldarg.0 + IL_0026: ldc.i4.4 + IL_0027: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ShortCircuit::F(int32) + IL_002c: brtrue.s IL_0035 + + IL_002e: ldarg.0 + IL_002f: callvirt instance void ICSharpCode.Decompiler.Tests.TestCases.Pretty.ShortCircuit::M2() + IL_0034: ret + + IL_0035: ldarg.0 + IL_0036: callvirt instance void ICSharpCode.Decompiler.Tests.TestCases.Pretty.ShortCircuit::E() + IL_003b: ret + } // end of method ShortCircuit::StmtComplex5 + + .method public hidebysig instance int32 + StmtComplex6() cil managed + { + // Code size 37 (0x25) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: ldc.i4.0 + IL_0002: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ShortCircuit::F(int32) + IL_0007: brfalse.s IL_0023 + + IL_0009: ldarg.0 + IL_000a: callvirt instance void ICSharpCode.Decompiler.Tests.TestCases.Pretty.ShortCircuit::M1() + IL_000f: ldarg.0 + IL_0010: ldc.i4.1 + IL_0011: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ShortCircuit::F(int32) + IL_0016: brtrue.s IL_0021 + + IL_0018: ldarg.0 + IL_0019: ldc.i4.2 + IL_001a: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ShortCircuit::F(int32) + IL_001f: brfalse.s IL_0023 + + IL_0021: ldc.i4.1 + IL_0022: ret + + IL_0023: ldc.i4.2 + IL_0024: ret + } // end of method ShortCircuit::StmtComplex6 + .method family hidebysig specialname rtspecialname instance void .ctor() cil managed { diff --git a/ICSharpCode.Decompiler.Tests/TestCases/Pretty/ShortCircuit.roslyn.il b/ICSharpCode.Decompiler.Tests/TestCases/Pretty/ShortCircuit.roslyn.il index 7bd50e5e7..0a4da1490 100644 --- a/ICSharpCode.Decompiler.Tests/TestCases/Pretty/ShortCircuit.roslyn.il +++ b/ICSharpCode.Decompiler.Tests/TestCases/Pretty/ShortCircuit.roslyn.il @@ -167,6 +167,111 @@ IL_002a: ret } // end of method ShortCircuit::ExprCondAnd + .method public hidebysig instance void + ExprMix4A() cil managed + { + // Code size 46 (0x2e) + .maxstack 8 + IL_0000: nop + IL_0001: ldarg.0 + IL_0002: ldarg.0 + IL_0003: ldc.i4.0 + IL_0004: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ShortCircuit::F(int32) + IL_0009: brtrue.s IL_0014 + + IL_000b: ldarg.0 + IL_000c: ldc.i4.1 + IL_000d: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ShortCircuit::F(int32) + IL_0012: brfalse.s IL_001d + + IL_0014: ldarg.0 + IL_0015: ldc.i4.2 + IL_0016: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ShortCircuit::F(int32) + IL_001b: brtrue.s IL_0026 + + IL_001d: ldarg.0 + IL_001e: ldc.i4.3 + IL_001f: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ShortCircuit::F(int32) + IL_0024: br.s IL_0027 + + IL_0026: ldc.i4.1 + IL_0027: callvirt instance void ICSharpCode.Decompiler.Tests.TestCases.Pretty.ShortCircuit::B(bool) + IL_002c: nop + IL_002d: ret + } // end of method ShortCircuit::ExprMix4A + + .method public hidebysig instance void + ExprMix4B() cil managed + { + // Code size 49 (0x31) + .maxstack 8 + IL_0000: nop + IL_0001: ldarg.0 + IL_0002: ldarg.0 + IL_0003: ldc.i4.0 + IL_0004: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ShortCircuit::F(int32) + IL_0009: brtrue.s IL_0014 + + IL_000b: ldarg.0 + IL_000c: ldc.i4.1 + IL_000d: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ShortCircuit::F(int32) + IL_0012: brfalse.s IL_0029 + + IL_0014: ldarg.0 + IL_0015: ldc.i4.2 + IL_0016: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ShortCircuit::F(int32) + IL_001b: brtrue.s IL_0026 + + IL_001d: ldarg.0 + IL_001e: ldc.i4.3 + IL_001f: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ShortCircuit::F(int32) + IL_0024: br.s IL_0027 + + IL_0026: ldc.i4.1 + IL_0027: br.s IL_002a + + IL_0029: ldc.i4.0 + IL_002a: callvirt instance void ICSharpCode.Decompiler.Tests.TestCases.Pretty.ShortCircuit::B(bool) + IL_002f: nop + IL_0030: ret + } // end of method ShortCircuit::ExprMix4B + + .method public hidebysig instance void + ExprMix4C() cil managed + { + // Code size 49 (0x31) + .maxstack 8 + IL_0000: nop + IL_0001: ldarg.0 + IL_0002: ldarg.0 + IL_0003: ldc.i4.0 + IL_0004: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ShortCircuit::F(int32) + IL_0009: brfalse.s IL_0014 + + IL_000b: ldarg.0 + IL_000c: ldc.i4.1 + IL_000d: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ShortCircuit::F(int32) + IL_0012: brtrue.s IL_0029 + + IL_0014: ldarg.0 + IL_0015: ldc.i4.2 + IL_0016: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ShortCircuit::F(int32) + IL_001b: brfalse.s IL_0026 + + IL_001d: ldarg.0 + IL_001e: ldc.i4.3 + IL_001f: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ShortCircuit::F(int32) + IL_0024: br.s IL_0027 + + IL_0026: ldc.i4.0 + IL_0027: br.s IL_002a + + IL_0029: ldc.i4.1 + IL_002a: callvirt instance void ICSharpCode.Decompiler.Tests.TestCases.Pretty.ShortCircuit::B(bool) + IL_002f: nop + IL_0030: ret + } // end of method ShortCircuit::ExprMix4C + .method public hidebysig instance void StmtAnd2() cil managed { @@ -208,7 +313,37 @@ } // end of method ShortCircuit::StmtAnd2 .method public hidebysig instance void - StmtOr2() cil managed + StmtOr2A() cil managed + { + // Code size 34 (0x22) + .maxstack 2 + .locals init (bool V_0) + IL_0000: nop + IL_0001: ldarg.0 + IL_0002: ldc.i4.0 + IL_0003: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ShortCircuit::F(int32) + IL_0008: brtrue.s IL_0013 + + IL_000a: ldarg.0 + IL_000b: ldc.i4.1 + IL_000c: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ShortCircuit::F(int32) + IL_0011: br.s IL_0014 + + IL_0013: ldc.i4.1 + IL_0014: stloc.0 + IL_0015: ldloc.0 + IL_0016: brfalse.s IL_0021 + + IL_0018: nop + IL_0019: ldarg.0 + IL_001a: callvirt instance void ICSharpCode.Decompiler.Tests.TestCases.Pretty.ShortCircuit::M1() + IL_001f: nop + IL_0020: nop + IL_0021: ret + } // end of method ShortCircuit::StmtOr2A + + .method public hidebysig instance void + StmtOr2B() cil managed { // Code size 52 (0x34) .maxstack 2 @@ -245,7 +380,7 @@ IL_002d: callvirt instance void ICSharpCode.Decompiler.Tests.TestCases.Pretty.ShortCircuit::E() IL_0032: nop IL_0033: ret - } // end of method ShortCircuit::StmtOr2 + } // end of method ShortCircuit::StmtOr2B .method public hidebysig instance void StmtAnd3() cil managed @@ -310,7 +445,7 @@ IL_0011: brtrue.s IL_001c IL_0013: ldarg.0 - IL_0014: ldc.i4.3 + IL_0014: ldc.i4.2 IL_0015: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ShortCircuit::F(int32) IL_001a: br.s IL_001d @@ -379,6 +514,356 @@ IL_0036: ret } // end of method ShortCircuit::StmtOr4 + .method public hidebysig instance void + StmtMix3A() cil managed + { + // Code size 43 (0x2b) + .maxstack 2 + .locals init (bool V_0) + IL_0000: nop + IL_0001: ldarg.0 + IL_0002: ldc.i4.0 + IL_0003: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ShortCircuit::F(int32) + IL_0008: brtrue.s IL_0013 + + IL_000a: ldarg.0 + IL_000b: ldc.i4.1 + IL_000c: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ShortCircuit::F(int32) + IL_0011: brfalse.s IL_001c + + IL_0013: ldarg.0 + IL_0014: ldc.i4.2 + IL_0015: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ShortCircuit::F(int32) + IL_001a: br.s IL_001d + + IL_001c: ldc.i4.0 + IL_001d: stloc.0 + IL_001e: ldloc.0 + IL_001f: brfalse.s IL_002a + + IL_0021: nop + IL_0022: ldarg.0 + IL_0023: callvirt instance void ICSharpCode.Decompiler.Tests.TestCases.Pretty.ShortCircuit::M1() + IL_0028: nop + IL_0029: nop + IL_002a: ret + } // end of method ShortCircuit::StmtMix3A + + .method public hidebysig instance void + StmtMix3B() cil managed + { + // Code size 54 (0x36) + .maxstack 2 + .locals init (bool V_0) + IL_0000: nop + IL_0001: ldarg.0 + IL_0002: ldc.i4.0 + IL_0003: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ShortCircuit::F(int32) + IL_0008: brtrue.s IL_0013 + + IL_000a: ldarg.0 + IL_000b: ldc.i4.1 + IL_000c: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ShortCircuit::F(int32) + IL_0011: brfalse.s IL_001c + + IL_0013: ldarg.0 + IL_0014: ldc.i4.2 + IL_0015: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ShortCircuit::F(int32) + IL_001a: br.s IL_001d + + IL_001c: ldc.i4.0 + IL_001d: stloc.0 + IL_001e: ldloc.0 + IL_001f: brfalse.s IL_002c + + IL_0021: nop + IL_0022: ldarg.0 + IL_0023: callvirt instance void ICSharpCode.Decompiler.Tests.TestCases.Pretty.ShortCircuit::M1() + IL_0028: nop + IL_0029: nop + IL_002a: br.s IL_0035 + + IL_002c: nop + IL_002d: ldarg.0 + IL_002e: callvirt instance void ICSharpCode.Decompiler.Tests.TestCases.Pretty.ShortCircuit::M2() + IL_0033: nop + IL_0034: nop + IL_0035: ret + } // end of method ShortCircuit::StmtMix3B + + .method public hidebysig instance void + StmtMix4V1A() cil managed + { + // Code size 52 (0x34) + .maxstack 2 + .locals init (bool V_0) + IL_0000: nop + IL_0001: ldarg.0 + IL_0002: ldc.i4.0 + IL_0003: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ShortCircuit::F(int32) + IL_0008: brtrue.s IL_0013 + + IL_000a: ldarg.0 + IL_000b: ldc.i4.1 + IL_000c: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ShortCircuit::F(int32) + IL_0011: brfalse.s IL_001c + + IL_0013: ldarg.0 + IL_0014: ldc.i4.2 + IL_0015: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ShortCircuit::F(int32) + IL_001a: brtrue.s IL_0025 + + IL_001c: ldarg.0 + IL_001d: ldc.i4.3 + IL_001e: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ShortCircuit::F(int32) + IL_0023: br.s IL_0026 + + IL_0025: ldc.i4.1 + IL_0026: stloc.0 + IL_0027: ldloc.0 + IL_0028: brfalse.s IL_0033 + + IL_002a: nop + IL_002b: ldarg.0 + IL_002c: callvirt instance void ICSharpCode.Decompiler.Tests.TestCases.Pretty.ShortCircuit::M1() + IL_0031: nop + IL_0032: nop + IL_0033: ret + } // end of method ShortCircuit::StmtMix4V1A + + .method public hidebysig instance void + StmtMix4V1B() cil managed + { + // Code size 63 (0x3f) + .maxstack 2 + .locals init (bool V_0) + IL_0000: nop + IL_0001: ldarg.0 + IL_0002: ldc.i4.0 + IL_0003: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ShortCircuit::F(int32) + IL_0008: brtrue.s IL_0013 + + IL_000a: ldarg.0 + IL_000b: ldc.i4.1 + IL_000c: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ShortCircuit::F(int32) + IL_0011: brfalse.s IL_001c + + IL_0013: ldarg.0 + IL_0014: ldc.i4.2 + IL_0015: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ShortCircuit::F(int32) + IL_001a: brtrue.s IL_0025 + + IL_001c: ldarg.0 + IL_001d: ldc.i4.3 + IL_001e: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ShortCircuit::F(int32) + IL_0023: br.s IL_0026 + + IL_0025: ldc.i4.1 + IL_0026: stloc.0 + IL_0027: ldloc.0 + IL_0028: brfalse.s IL_0035 + + IL_002a: nop + IL_002b: ldarg.0 + IL_002c: callvirt instance void ICSharpCode.Decompiler.Tests.TestCases.Pretty.ShortCircuit::M1() + IL_0031: nop + IL_0032: nop + IL_0033: br.s IL_003e + + IL_0035: nop + IL_0036: ldarg.0 + IL_0037: callvirt instance void ICSharpCode.Decompiler.Tests.TestCases.Pretty.ShortCircuit::M2() + IL_003c: nop + IL_003d: nop + IL_003e: ret + } // end of method ShortCircuit::StmtMix4V1B + + .method public hidebysig instance void + StmtMix4V2A() cil managed + { + // Code size 55 (0x37) + .maxstack 2 + .locals init (bool V_0) + IL_0000: nop + IL_0001: ldarg.0 + IL_0002: ldc.i4.0 + IL_0003: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ShortCircuit::F(int32) + IL_0008: brtrue.s IL_0013 + + IL_000a: ldarg.0 + IL_000b: ldc.i4.1 + IL_000c: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ShortCircuit::F(int32) + IL_0011: brfalse.s IL_0028 + + IL_0013: ldarg.0 + IL_0014: ldc.i4.2 + IL_0015: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ShortCircuit::F(int32) + IL_001a: brtrue.s IL_0025 + + IL_001c: ldarg.0 + IL_001d: ldc.i4.3 + IL_001e: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ShortCircuit::F(int32) + IL_0023: br.s IL_0026 + + IL_0025: ldc.i4.1 + IL_0026: br.s IL_0029 + + IL_0028: ldc.i4.0 + IL_0029: stloc.0 + IL_002a: ldloc.0 + IL_002b: brfalse.s IL_0036 + + IL_002d: nop + IL_002e: ldarg.0 + IL_002f: callvirt instance void ICSharpCode.Decompiler.Tests.TestCases.Pretty.ShortCircuit::M1() + IL_0034: nop + IL_0035: nop + IL_0036: ret + } // end of method ShortCircuit::StmtMix4V2A + + .method public hidebysig instance void + StmtMix4V2B() cil managed + { + // Code size 66 (0x42) + .maxstack 2 + .locals init (bool V_0) + IL_0000: nop + IL_0001: ldarg.0 + IL_0002: ldc.i4.0 + IL_0003: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ShortCircuit::F(int32) + IL_0008: brtrue.s IL_0013 + + IL_000a: ldarg.0 + IL_000b: ldc.i4.1 + IL_000c: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ShortCircuit::F(int32) + IL_0011: brfalse.s IL_0028 + + IL_0013: ldarg.0 + IL_0014: ldc.i4.2 + IL_0015: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ShortCircuit::F(int32) + IL_001a: brtrue.s IL_0025 + + IL_001c: ldarg.0 + IL_001d: ldc.i4.3 + IL_001e: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ShortCircuit::F(int32) + IL_0023: br.s IL_0026 + + IL_0025: ldc.i4.1 + IL_0026: br.s IL_0029 + + IL_0028: ldc.i4.0 + IL_0029: stloc.0 + IL_002a: ldloc.0 + IL_002b: brfalse.s IL_0038 + + IL_002d: nop + IL_002e: ldarg.0 + IL_002f: callvirt instance void ICSharpCode.Decompiler.Tests.TestCases.Pretty.ShortCircuit::M1() + IL_0034: nop + IL_0035: nop + IL_0036: br.s IL_0041 + + IL_0038: nop + IL_0039: ldarg.0 + IL_003a: callvirt instance void ICSharpCode.Decompiler.Tests.TestCases.Pretty.ShortCircuit::M2() + IL_003f: nop + IL_0040: nop + IL_0041: ret + } // end of method ShortCircuit::StmtMix4V2B + + .method public hidebysig instance void + StmtMix4V3A() cil managed + { + // Code size 55 (0x37) + .maxstack 2 + .locals init (bool V_0) + IL_0000: nop + IL_0001: ldarg.0 + IL_0002: ldc.i4.0 + IL_0003: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ShortCircuit::F(int32) + IL_0008: brfalse.s IL_0013 + + IL_000a: ldarg.0 + IL_000b: ldc.i4.1 + IL_000c: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ShortCircuit::F(int32) + IL_0011: brtrue.s IL_0028 + + IL_0013: ldarg.0 + IL_0014: ldc.i4.2 + IL_0015: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ShortCircuit::F(int32) + IL_001a: brfalse.s IL_0025 + + IL_001c: ldarg.0 + IL_001d: ldc.i4.3 + IL_001e: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ShortCircuit::F(int32) + IL_0023: br.s IL_0026 + + IL_0025: ldc.i4.0 + IL_0026: br.s IL_0029 + + IL_0028: ldc.i4.1 + IL_0029: stloc.0 + IL_002a: ldloc.0 + IL_002b: brfalse.s IL_0036 + + IL_002d: nop + IL_002e: ldarg.0 + IL_002f: callvirt instance void ICSharpCode.Decompiler.Tests.TestCases.Pretty.ShortCircuit::M1() + IL_0034: nop + IL_0035: nop + IL_0036: ret + } // end of method ShortCircuit::StmtMix4V3A + + .method public hidebysig instance void + StmtMix4V3B() cil managed + { + // Code size 66 (0x42) + .maxstack 2 + .locals init (bool V_0) + IL_0000: nop + IL_0001: ldarg.0 + IL_0002: ldc.i4.0 + IL_0003: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ShortCircuit::F(int32) + IL_0008: brfalse.s IL_0013 + + IL_000a: ldarg.0 + IL_000b: ldc.i4.1 + IL_000c: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ShortCircuit::F(int32) + IL_0011: brtrue.s IL_0028 + + IL_0013: ldarg.0 + IL_0014: ldc.i4.2 + IL_0015: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ShortCircuit::F(int32) + IL_001a: brfalse.s IL_0025 + + IL_001c: ldarg.0 + IL_001d: ldc.i4.3 + IL_001e: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ShortCircuit::F(int32) + IL_0023: br.s IL_0026 + + IL_0025: ldc.i4.0 + IL_0026: br.s IL_0029 + + IL_0028: ldc.i4.1 + IL_0029: stloc.0 + IL_002a: ldloc.0 + IL_002b: brfalse.s IL_0038 + + IL_002d: nop + IL_002e: ldarg.0 + IL_002f: callvirt instance void ICSharpCode.Decompiler.Tests.TestCases.Pretty.ShortCircuit::M1() + IL_0034: nop + IL_0035: nop + IL_0036: br.s IL_0041 + + IL_0038: nop + IL_0039: ldarg.0 + IL_003a: callvirt instance void ICSharpCode.Decompiler.Tests.TestCases.Pretty.ShortCircuit::M2() + IL_003f: nop + IL_0040: nop + IL_0041: ret + } // end of method ShortCircuit::StmtMix4V3B + .method public hidebysig instance void StmtComplex() cil managed { @@ -590,6 +1075,124 @@ IL_003d: ret } // end of method ShortCircuit::StmtComplex4 + .method public hidebysig instance void + StmtComplex5() cil managed + { + // Code size 89 (0x59) + .maxstack 2 + .locals init (bool V_0, + bool V_1, + bool V_2) + IL_0000: nop + IL_0001: ldarg.0 + IL_0002: ldc.i4.0 + IL_0003: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ShortCircuit::F(int32) + IL_0008: stloc.0 + IL_0009: ldloc.0 + IL_000a: brfalse.s IL_002d + + IL_000c: nop + IL_000d: ldarg.0 + IL_000e: ldc.i4.1 + IL_000f: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ShortCircuit::F(int32) + IL_0014: brtrue.s IL_0022 + + IL_0016: ldarg.0 + IL_0017: ldc.i4.2 + IL_0018: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ShortCircuit::F(int32) + IL_001d: ldc.i4.0 + IL_001e: ceq + IL_0020: br.s IL_0023 + + IL_0022: ldc.i4.0 + IL_0023: stloc.1 + IL_0024: ldloc.1 + IL_0025: brfalse.s IL_002a + + IL_0027: nop + IL_0028: br.s IL_0058 + + IL_002a: nop + IL_002b: br.s IL_0051 + + IL_002d: ldarg.0 + IL_002e: ldc.i4.3 + IL_002f: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ShortCircuit::F(int32) + IL_0034: brfalse.s IL_0042 + + IL_0036: ldarg.0 + IL_0037: ldc.i4.4 + IL_0038: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ShortCircuit::F(int32) + IL_003d: ldc.i4.0 + IL_003e: ceq + IL_0040: br.s IL_0043 + + IL_0042: ldc.i4.1 + IL_0043: stloc.2 + IL_0044: ldloc.2 + IL_0045: brfalse.s IL_0051 + + IL_0047: nop + IL_0048: ldarg.0 + IL_0049: callvirt instance void ICSharpCode.Decompiler.Tests.TestCases.Pretty.ShortCircuit::M2() + IL_004e: nop + IL_004f: br.s IL_0058 + + IL_0051: ldarg.0 + IL_0052: callvirt instance void ICSharpCode.Decompiler.Tests.TestCases.Pretty.ShortCircuit::E() + IL_0057: nop + IL_0058: ret + } // end of method ShortCircuit::StmtComplex5 + + .method public hidebysig instance int32 + StmtComplex6() cil managed + { + // Code size 55 (0x37) + .maxstack 2 + .locals init (bool V_0, + bool V_1, + int32 V_2) + IL_0000: nop + IL_0001: ldarg.0 + IL_0002: ldc.i4.0 + IL_0003: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ShortCircuit::F(int32) + IL_0008: stloc.0 + IL_0009: ldloc.0 + IL_000a: brfalse.s IL_0031 + + IL_000c: nop + IL_000d: ldarg.0 + IL_000e: callvirt instance void ICSharpCode.Decompiler.Tests.TestCases.Pretty.ShortCircuit::M1() + IL_0013: nop + IL_0014: ldarg.0 + IL_0015: ldc.i4.1 + IL_0016: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ShortCircuit::F(int32) + IL_001b: brtrue.s IL_0026 + + IL_001d: ldarg.0 + IL_001e: ldc.i4.2 + IL_001f: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ShortCircuit::F(int32) + IL_0024: br.s IL_0027 + + IL_0026: ldc.i4.1 + IL_0027: stloc.1 + IL_0028: ldloc.1 + IL_0029: brfalse.s IL_0030 + + IL_002b: nop + IL_002c: ldc.i4.1 + IL_002d: stloc.2 + IL_002e: br.s IL_0035 + + IL_0030: nop + IL_0031: ldc.i4.2 + IL_0032: stloc.2 + IL_0033: br.s IL_0035 + + IL_0035: ldloc.2 + IL_0036: ret + } // end of method ShortCircuit::StmtComplex6 + .method family hidebysig specialname rtspecialname instance void .ctor() cil managed { diff --git a/ICSharpCode.Decompiler/IL/ControlFlow/ConditionDetection.cs b/ICSharpCode.Decompiler/IL/ControlFlow/ConditionDetection.cs index 657a5f7a0..38be61648 100644 --- a/ICSharpCode.Decompiler/IL/ControlFlow/ConditionDetection.cs +++ b/ICSharpCode.Decompiler/IL/ControlFlow/ConditionDetection.cs @@ -16,6 +16,8 @@ // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER // DEALINGS IN THE SOFTWARE. +using System; +using System.Collections.Generic; using System.Diagnostics; using System.Linq; using ICSharpCode.Decompiler.FlowAnalysis; @@ -34,8 +36,18 @@ namespace ICSharpCode.Decompiler.IL.ControlFlow /// public class ConditionDetection : IBlockTransform { - BlockTransformContext context; - BlockContainer currentContainer; + private enum Keyword + { + Break, + Return, + Continue, + Other + } + + private BlockTransformContext context; + private ControlFlowNode cfgNode; + private BlockContainer currentContainer; + private Block continueBlock; /// /// Builds structured control flow for the block associated with the control flow node. @@ -47,264 +59,546 @@ namespace ICSharpCode.Decompiler.IL.ControlFlow public void Run(Block block, BlockTransformContext context) { this.context = context; - this.currentContainer = (BlockContainer)block.Parent; + currentContainer = (BlockContainer)block.Parent; + + // for detection of continue statements + continueBlock = GuessContinueBlock(); // We only embed blocks into this block if they aren't referenced anywhere else, // so those blocks are dominated by this block. // BlockILTransform thus guarantees that the blocks being embedded are already // fully processed. - var cfgNode = context.ControlFlowNode; + cfgNode = context.ControlFlowNode; Debug.Assert(cfgNode.UserData == block); // Because this transform runs at the beginning of the block transforms, // we know that `block` is still a (non-extended) basic block. - - // Last instruction is one with unreachable endpoint - // (guaranteed by combination of BlockContainer and Block invariants) - Debug.Assert(block.Instructions.Last().HasFlag(InstructionFlags.EndPointUnreachable)); - - ILInstruction exitInst = block.Instructions.Last(); // Previous-to-last instruction might have conditional control flow, // usually an IfInstruction with a branch: - IfInstruction ifInst = block.Instructions.SecondToLastOrDefault() as IfInstruction; - if (ifInst != null && ifInst.FalseInst.OpCode == OpCode.Nop) { - HandleIfInstruction(cfgNode, block, ifInst, ref exitInst); + if (block.Instructions.SecondToLastOrDefault() is IfInstruction ifInst) + HandleIfInstruction(block, ifInst); + else + InlineExitBranch(block); + } + + /// + /// Repeatedly inlines and simplifies, maintaining a good block exit and then attempting to match IL order + /// + private void HandleIfInstruction(Block block, IfInstruction ifInst) + { + while (InlineTrueBranch(ifInst) || InlineExitBranch(block)) { + PickBetterBlockExit(block, ifInst); + MergeCommonBranches(block, ifInst); + SwapEmptyThen(ifInst); + IntroduceShortCircuit(ifInst); } - if (IsUsableBranchToChild(cfgNode, exitInst)) { - // "...; goto usableblock;" - // -> embed target block in this block - context.Step("Inline target block of unconditional branch", exitInst); - var targetBlock = ((Branch)exitInst).TargetBlock; - Debug.Assert(exitInst == block.Instructions.Last()); - block.Instructions.RemoveAt(block.Instructions.Count - 1); - block.Instructions.AddRange(targetBlock.Instructions); - targetBlock.Remove(); + PickBetterBlockExit(block, ifInst); + OrderIfBlocks(ifInst); + } + + /// + /// if (...) br trueBlock; + /// -> + /// if (...) { trueBlock... } + /// + /// Only inlines branches that are strictly dominated by this block (incoming edge count == 1) + /// + private bool InlineTrueBranch(IfInstruction ifInst) + { + if (!CanInline(ifInst.TrueInst)) + return false; + + context.Step("Inline block as then-branch", ifInst.TrueInst); + // The targetBlock was already processed, and is ready to embed + var targetBlock = ((Branch)ifInst.TrueInst).TargetBlock; + targetBlock.Remove(); + ifInst.TrueInst = targetBlock; + + return true; + } + + /// + /// ...; br nextBlock; + /// -> + /// ...; { nextBlock... } + /// + /// Only inlines branches that are strictly dominated by this block (incoming edge count == 1) + /// + private bool InlineExitBranch(Block block) + { + var exitInst = GetExit(block); + if (!CanInline(exitInst)) + return false; + + context.Step("Inline target block of unconditional branch", exitInst); + // The targetBlock was already processed, and is ready to embed + var targetBlock = ((Branch)exitInst).TargetBlock; + block.Instructions.RemoveAt(block.Instructions.Count - 1); + block.Instructions.AddRange(targetBlock.Instructions); + targetBlock.Remove(); + + return true; + } + + /// + /// Gets whether potentialBranchInstruction is a branch to a block that is dominated by cfgNode. + /// If this function returns true, we replace the branch instruction with the block itself. + /// + private bool CanInline(ILInstruction exitInst) + { + if (exitInst is Branch branch + && branch.TargetBlock.Parent == currentContainer + && branch.TargetBlock.IncomingEdgeCount == 1 + && branch.TargetBlock.FinalInstruction is Nop) { + // if the incoming edge count is 1, then this must be the sole branch, and dominance is already ensured + Debug.Assert(cfgNode.Dominates(context.ControlFlowGraph.GetNode(branch.TargetBlock))); + return true; } + + return false; } - private void HandleIfInstruction(ControlFlowNode cfgNode, Block block, IfInstruction ifInst, ref ILInstruction exitInst) + /// + /// Looks for common exits in the inlined then and else branches of an if instruction + /// and performs inversions and simplifications to merge them provided they don't + /// isolate a higher priority block exit + /// + private void MergeCommonBranches(Block block, IfInstruction ifInst) { - if (ShouldSwapIfTargets(ifInst.TrueInst, exitInst)) { - // "if (c) goto lateBlock; goto earlierBlock;" - // -> "if (!c)" goto earlierBlock; goto lateBlock; - // This reordering should make the if structure correspond more closely to the original C# source code - context.Step("Negate if", ifInst); - block.Instructions[block.Instructions.Count - 1] = ifInst.TrueInst; - ifInst.TrueInst = exitInst; - exitInst = block.Instructions.Last(); - ifInst.Condition = Comp.LogicNot(ifInst.Condition); + var thenExits = new List(); + AddExits(ifInst.TrueInst, 0, thenExits); + if (thenExits.Count == 0) + return; + + // if there are any exits from the then branch, then the else is redundant and shouldn't exist + Debug.Assert(IsEmpty(ifInst.FalseInst)); + var elseExits = new List(); + int falseInstIndex = block.Instructions.IndexOf(ifInst) + 1; + AddExits(block, falseInstIndex, elseExits); + + var commonExits = elseExits.Where(e1 => thenExits.Any(e2 => DetectExitPoints.CompatibleExitInstruction(e1, e2))); + + // find the common exit with the highest block exit priority + ILInstruction commonExit = null; + foreach (var exit in commonExits) + if (commonExit == null || CompareBlockExitPriority(exit, commonExit) > 0) + commonExit = exit; + + if (commonExit == null) + return; + + // if the current block exit has higher priority than the exits to merge, + // determine if this merge will isolate the current block exit + // that is, no sequence of inversions can restore it to the block exit position + var blockExit = block.Instructions.Last(); + if (CompareBlockExitPriority(blockExit, commonExit, true) > 0 && !WillShortCircuit(block, ifInst, commonExit)) + return; + + // could improve performance by directly implementing the || short-circuit when WillShortCircuit + // currently the same general sequence of transformations introduces both operators + + context.StepStartGroup("Merge common branches "+commonExit, ifInst); + ProduceExit(ifInst.TrueInst, 0, commonExit); + ProduceExit(block, falseInstIndex, commonExit); + + // if (...) { ...; blockExit; } ...; blockExit; + // -> if (...) { ...; blockExit; } else { ... } blockExit; + if (ifInst != block.Instructions.SecondToLastOrDefault()) { + context.Step("Embed else-block for goto removal", ifInst); + Debug.Assert(IsEmpty(ifInst.FalseInst)); + ifInst.FalseInst = ExtractBlock(block, block.Instructions.IndexOf(ifInst) + 1, block.Instructions.Count - 2); } + + // if (...) { ...; goto blockExit; } blockExit; + // -> if (...) { ... } blockExit; + // OR + // if (...) { ...; goto blockExit; } else { ... } blockExit; + // -> if (...) { ... } else { ... } blockExit; + context.Step("Remove redundant 'goto blockExit;' in then-branch", ifInst); + if (!(ifInst.TrueInst is Block trueBlock) || trueBlock.Instructions.Count == 1) + ifInst.TrueInst = new Nop { ILRange = ifInst.TrueInst.ILRange }; + else + trueBlock.Instructions.RemoveAt(trueBlock.Instructions.Count - 1); - ILInstruction trueExitInst; - if (IsUsableBranchToChild(cfgNode, ifInst.TrueInst)) { - // "if (...) goto targetBlock; exitInst;" - // -> "if (...) { targetBlock } exitInst;" - context.Step("Inline block as then-branch", ifInst); - var targetBlock = ((Branch)ifInst.TrueInst).TargetBlock; - // The targetBlock was already processed, we can embed it into the if statement: - targetBlock.Remove(); - ifInst.TrueInst = targetBlock; - ILInstruction nestedCondition, nestedTrueInst; - while (targetBlock.Instructions.Count > 0 - && targetBlock.Instructions[0].MatchIfInstruction(out nestedCondition, out nestedTrueInst)) - { - nestedTrueInst = UnpackBlockContainingOnlyBranch(nestedTrueInst); - if (DetectExitPoints.CompatibleExitInstruction(exitInst, nestedTrueInst)) { - // "if (...) { if (nestedCondition) goto exitPoint; ... } goto exitPoint;" - // -> "if (... && !nestedCondition) { ... } goto exitPoint;" - context.Step("Combine 'if (cond1 && !cond2)' in then-branch", ifInst); - ifInst.Condition = IfInstruction.LogicAnd(ifInst.Condition, Comp.LogicNot(nestedCondition)); - targetBlock.Instructions.RemoveAt(0); - // Update targetBlock label now that we've removed the first instruction - if (targetBlock.Instructions.FirstOrDefault()?.ILRange.IsEmpty == false) { - int offset = targetBlock.Instructions[0].ILRange.Start; - targetBlock.ILRange = new Interval(offset, offset); - } - continue; // try to find more nested conditions - } - if (nestedTrueInst is Block nestedTrueBlock - && DetectExitPoints.CompatibleExitInstruction(exitInst, nestedTrueBlock.Instructions.Last()) - && targetBlock.HasFlag(InstructionFlags.EndPointUnreachable)) - { - // "if (...) { if (nestedCondition) { trueInst...; goto exitPoint; } falseInst...; } goto exitPoint;" - // -> "if (...) { if (!nestedCondition) { falseInst...; } trueInst... } goto exitPoint;" - // (only if end-point of 'falseInst...' is unreachable) - context.Step("Invert nested condition to reduce number of gotos", ifInst); - var nestedIfInst = (IfInstruction)targetBlock.Instructions[0]; - nestedIfInst.Condition = Comp.LogicNot(nestedCondition); - nestedTrueBlock.Instructions.RemoveAt(nestedTrueBlock.Instructions.Count - 1); // remove nested goto exitPoint; - // remove falseInsts from outer block - var falseInsts = targetBlock.Instructions.Skip(1).ToArray(); - targetBlock.Instructions.RemoveRange(1, targetBlock.Instructions.Count - 1); - // add trueInsts to outer block - targetBlock.Instructions.AddRange(nestedTrueBlock.Instructions); - // add falseInsts to inner block - nestedTrueBlock.Instructions.ReplaceList(falseInsts); - nestedIfInst.Condition.AcceptVisitor(new ExpressionTransforms { context = new StatementTransformContext(context) }); - } - break; - } + context.StepEndGroup(); + } + + /// + /// Finds all exits which could be brought to the block root via inversion + /// + private void AddExits(ILInstruction searchInst, int startIndex, IList exits) + { + if (!TryGetExit(searchInst, out var exitInst)) + return; + + exits.Add(exitInst); + if (searchInst is Block block) + for (int i = startIndex; i < block.Instructions.Count; i++) + if (block.Instructions[i] is IfInstruction ifInst) + AddExits(ifInst.TrueInst, 0, exits); + } + + /// + /// Recursively performs inversions to bring a desired exit to the root of the block + /// for example: + /// if (a) { + /// ...; + /// if (b) { + /// ...; + /// targetExit; + /// } + /// ...; + /// exit1; + /// } + /// ...; + /// exit2; + /// -> + /// if (!a) { + /// ...; + /// exit2; + /// } + /// ...; + /// if (!b) { + /// ...; + /// exit1; + /// } + /// ...; + /// targetExit; + /// + private bool ProduceExit(ILInstruction searchInst, int startIndex, ILInstruction targetExit) + { + if (!TryGetExit(searchInst, out var exitInst)) + return false; + + if (DetectExitPoints.CompatibleExitInstruction(exitInst, targetExit)) + return true; - trueExitInst = targetBlock.Instructions.LastOrDefault(); - if (DetectExitPoints.CompatibleExitInstruction(exitInst, trueExitInst)) { - // "if (...) { ...; goto exitPoint } goto exitPoint;" - // -> "if (...) { ... } goto exitPoint;" - context.Step("Remove redundant 'goto exitPoint;' in then-branch", ifInst); - targetBlock.Instructions.RemoveAt(targetBlock.Instructions.Count - 1); - trueExitInst = null; - if (targetBlock.Instructions.Count == 1 && targetBlock.Instructions[0].MatchIfInstruction(out nestedCondition, out nestedTrueInst)) { - // "if (...) { if (nestedCondition) nestedTrueInst; } exitInst;" - // --> "if (... && nestedCondition) nestedTrueInst; } exitInst" - context.Step("Combine if conditions into logic.and (in then-branch)", ifInst); - ifInst.Condition = IfInstruction.LogicAnd(ifInst.Condition, nestedCondition); - ifInst.TrueInst = nestedTrueInst; - trueExitInst = (nestedTrueInst as Block)?.Instructions.LastOrDefault(); + if (searchInst is Block block) + for (int i = startIndex; i < block.Instructions.Count; i++) + if (block.Instructions[i] is IfInstruction ifInst && ProduceExit(ifInst.TrueInst, 0, targetExit)) { + InvertIf(block, ifInst); + Debug.Assert(DetectExitPoints.CompatibleExitInstruction(GetExit(block), targetExit)); + return true; } - } + + return false; + } + + /// + /// Anticipates the introduction of an || operator when merging ifInst and elseExit + /// + /// if (cond) commonExit; + /// if (cond2) commonExit; + /// ...; + /// blockExit; + /// will become: + /// if (cond || cond2) commonExit; + /// ...; + /// blockExit; + /// + private bool WillShortCircuit(Block block, IfInstruction ifInst, ILInstruction elseExit) + { + bool ThenInstIsSingleExit(ILInstruction inst) => + inst.MatchIfInstruction(out var _, out var trueInst) + && (!(trueInst is Block trueBlock) || trueBlock.Instructions.Count == 1) + && TryGetExit(trueInst, out var _); + + if (!ThenInstIsSingleExit(ifInst)) + return false; + + // find the host if statement + var elseIfInst = elseExit; + while (elseIfInst.Parent != block) + elseIfInst = elseIfInst.Parent; + + return block.Instructions.IndexOf(elseIfInst) == block.Instructions.IndexOf(ifInst) + 1 + && ThenInstIsSingleExit(elseIfInst); + } + + /// + /// if (cond) { then... } + /// else...; + /// -> + /// if (!cond) { else... } + /// then...; + /// + /// Assumes ifInst does not have an else block + /// + private void InvertIf(Block block, IfInstruction ifInst) + { + Debug.Assert(ifInst.Parent == block); + + //assert then block terminates + var trueExitInst = GetExit(ifInst.TrueInst); + var exitInst = GetExit(block); + context.Step("Negate if for desired branch "+trueExitInst, ifInst); + + //if the then block terminates, else blocks are redundant, and should not exist + Debug.Assert(IsEmpty(ifInst.FalseInst)); + + //save a copy + var trueInst = ifInst.TrueInst; + + if (ifInst != block.Instructions.SecondToLastOrDefault()) { + ifInst.TrueInst = ExtractBlock(block, block.Instructions.IndexOf(ifInst) + 1, block.Instructions.Count - 1); } else { - trueExitInst = ifInst.TrueInst; - } - if (IsUsableBranchToChild(cfgNode, exitInst)) { - var targetBlock = ((Branch)exitInst).TargetBlock; - var falseExitInst = targetBlock.Instructions.LastOrDefault(); - if (DetectExitPoints.CompatibleExitInstruction(trueExitInst, falseExitInst)) { - // if (...) { ...; goto exitPoint; } goto nextBlock; nextBlock: ...; goto exitPoint; - // -> if (...) { ... } else { ... } goto exitPoint; - - // the else block is not empty or nop-only: - if (targetBlock.Children.Any(inst => !(inst is Nop) && inst != falseExitInst)) { - context.Step("Inline block as else-branch", ifInst); - targetBlock.Instructions.RemoveAt(targetBlock.Instructions.Count - 1); - targetBlock.Remove(); - ifInst.FalseInst = targetBlock; - } else { - // the else block is empty or nop-only and can be safely removed: - context.Step("Remove empty else-branch", ifInst); - targetBlock.Instructions.RemoveAt(targetBlock.Instructions.Count - 1); - targetBlock.Remove(); - } - exitInst = block.Instructions[block.Instructions.Count - 1] = falseExitInst; - Block trueBlock = ifInst.TrueInst as Block; - if (trueBlock != null) { - Debug.Assert(trueExitInst == trueBlock.Instructions.Last()); - trueBlock.Instructions.RemoveAt(trueBlock.Instructions.Count - 1); - } else { - Debug.Assert(trueExitInst == ifInst.TrueInst); - ifInst.TrueInst = new Nop { ILRange = ifInst.TrueInst.ILRange }; - } - } + block.Instructions.RemoveAt(block.Instructions.Count - 1); + ifInst.TrueInst = exitInst; } - if (IsEmpty(ifInst.TrueInst)) { - // prefer empty true-branch to empty-else branch - context.Step("Swap empty then-branch with else-branch", ifInst); - var oldTrue = ifInst.TrueInst; - ifInst.TrueInst = ifInst.FalseInst; - ifInst.FalseInst = new Nop { ILRange = oldTrue.ILRange }; - ifInst.Condition = Comp.LogicNot(ifInst.Condition); - - // After swapping, it's possible that we can introduce a short-circuit operator: - Block trueBlock = ifInst.TrueInst as Block; - ILInstruction nestedCondition, nestedTrueInst; - if (trueBlock != null && trueBlock.Instructions.Count == 1 + + if (trueInst is Block trueBlock) { + block.Instructions.AddRange(trueBlock.Instructions); + } else + block.Instructions.Add(trueInst); + + ifInst.Condition = Comp.LogicNot(ifInst.Condition); + ExpressionTransforms.RunOnSingleStatment(ifInst, context); + } + + /// + /// if (cond) { } else { ... } + /// -> + /// if (!cond) { ... } + /// + private void SwapEmptyThen(IfInstruction ifInst) + { + if (!IsEmpty(ifInst.TrueInst)) + return; + + context.Step("Swap empty then-branch with else-branch", ifInst); + var oldTrue = ifInst.TrueInst; + ifInst.TrueInst = ifInst.FalseInst; + ifInst.FalseInst = new Nop { ILRange = oldTrue.ILRange }; + ifInst.Condition = Comp.LogicNot(ifInst.Condition); + } + + /// + /// if (cond) { if (nestedCond) { nestedThen... } } + /// -> + /// if (cond && nestedCond) { nestedThen... } + /// + private void IntroduceShortCircuit(IfInstruction ifInst) + { + if (IsEmpty(ifInst.FalseInst) + && ifInst.TrueInst is Block trueBlock + && trueBlock.Instructions.Count == 1 && trueBlock.FinalInstruction is Nop - && trueBlock.Instructions[0].MatchIfInstruction(out nestedCondition, out nestedTrueInst)) { - // if (cond) if (nestedCond) nestedTrueInst - // ==> if (cond && nestedCond) nestedTrueInst - context.Step("Combine if conditions into logic.and (after branch swapping)", ifInst); - ifInst.Condition = IfInstruction.LogicAnd(ifInst.Condition, nestedCondition); - ifInst.TrueInst = nestedTrueInst; - } - } else if (ifInst.FalseInst.OpCode != OpCode.Nop && ifInst.FalseInst.ILRange.Start < ifInst.TrueInst.ILRange.Start) { - // swap true and false branches of if/else construct, - // to bring them in the same order as the IL code - context.Step("Swap then-branch with else-branch", ifInst); - var oldTrue = ifInst.TrueInst; - ifInst.TrueInst = ifInst.FalseInst; - ifInst.FalseInst = oldTrue; - ifInst.Condition = Comp.LogicNot(ifInst.Condition); + && trueBlock.Instructions[0].MatchIfInstruction(out var nestedCondition, out var nestedTrueInst)) { + context.Step("Combine 'if (cond1 && cond2)' in then-branch", ifInst); + ifInst.Condition = IfInstruction.LogicAnd(ifInst.Condition, nestedCondition); + ifInst.TrueInst = nestedTrueInst; } } - static bool IsEmpty(ILInstruction inst) + /// + /// if (cond) { lateBlock... } else { earlyBlock... } + /// -> + /// if (!cond) { earlyBlock... } else { lateBlock... } + /// + private void OrderIfBlocks(IfInstruction ifInst) { - var block = inst as Block; - return block != null && block.Instructions.Count == 0 && block.FinalInstruction is Nop - || inst is Nop; + if (IsEmpty(ifInst.FalseInst) || ifInst.TrueInst.ILRange.Start <= ifInst.FalseInst.ILRange.Start) + return; + + context.Step("Swap then-branch with else-branch to match IL order", ifInst); + var oldTrue = ifInst.TrueInst; + ifInst.TrueInst = ifInst.FalseInst; + ifInst.FalseInst = oldTrue; + ifInst.Condition = Comp.LogicNot(ifInst.Condition); } - private ILInstruction UnpackBlockContainingOnlyBranch(ILInstruction inst) + /// + /// Compares the current block exit, and the exit of ifInst.ThenInst + /// and inverts if necessary to pick the better exit + /// + /// Does nothing when ifInst has an else block (because inverting wouldn't affect the block exit) + /// + private void PickBetterBlockExit(Block block, IfInstruction ifInst) { - Block block = inst as Block; - if (block != null && block.Instructions.Count == 1 && block.FinalInstruction is Nop && IsBranchOrLeave(block.Instructions[0])) - return block.Instructions.Single(); - else - return inst; + var exitInst = GetExit(block); + if (IsEmpty(ifInst.FalseInst) + && TryGetExit(ifInst.TrueInst, out var trueExitInst) + && CompareBlockExitPriority(trueExitInst, exitInst) > 0) + InvertIf(block, ifInst); } - - bool ShouldSwapIfTargets(ILInstruction inst1, ILInstruction inst2) + + /// + /// Compares two exit instructions for block exit priority + /// A higher priority exit should be kept as the last instruction in a block + /// even if it prevents the merging of a two compatible lower priority exits + /// + /// leave from try containers must always be the final instruction, or a goto will be inserted + /// loops will endeavour to leave at least one continue branch as the last instruction in the block + /// + /// The priority is: + /// leave > branch > other-keyword > continue > return > break + /// + /// non-keyword leave instructions are ordered with the outer container having higher priority + /// + /// if the exits have equal priority, and the strongly flag is not provided + /// then the exits are sorted by IL order (target block for branches) + /// + /// break has higher priority than other keywords in a switch block (for aesthetic reasons) + /// + /// {-1, 0, 1} if exit1 has {lower, equal, higher} priority an exit2 + private int CompareBlockExitPriority(ILInstruction exit1, ILInstruction exit2, bool strongly = false) { - Block block1 = null, block2 = null; - if (inst1.MatchBranch(out block1) && inst2.MatchBranch(out block2)) { + // keywords have lower priority than non-keywords + bool isKeyword1 = IsKeywordExit(exit1, out var keyword1), isKeyword2 = IsKeywordExit(exit2, out var keyword2); + if (isKeyword1 != isKeyword2) + return isKeyword1 ? -1 : 1; + + + if (isKeyword1) { + //for keywords + if (currentContainer.Kind == ContainerKind.Switch) { + // breaks have highest priority in a switch + if ((keyword1 == Keyword.Break) != (keyword2 == Keyword.Break)) + return keyword1 == Keyword.Break ? 1 : -1; + + } else { + // breaks have lowest priority + if ((keyword1 == Keyword.Break) != (keyword2 == Keyword.Break)) + return keyword1 == Keyword.Break ? -1 : 1; + + // continue has highest priority (to prevent having to jump to the end of a loop block) + if ((keyword1 == Keyword.Continue) != (keyword2 == Keyword.Continue)) + return keyword1 == Keyword.Continue ? 1 : -1; + } + } else {// for non-keywords (only Branch or Leave) + // branches have lower priority than non-keyword leaves + bool isBranch1 = exit1 is Branch, isBranch2 = exit2 is Branch; + if (isBranch1 != isBranch2) + return isBranch1 ? -1 : 1; + + // two leaves that both want end of block priority + if (exit1.MatchLeave(out var container1) && exit2.MatchLeave(out var container2) && container1 != container2) { + // choose the outer one + return container2.IsDescendantOf(container1) ? 1 : -1; + } + } + + if (strongly) + return 0; + + if (exit1.MatchBranch(out var block1) && exit2.MatchBranch(out var block2)) { // prefer arranging stuff in IL order - return block1.ILRange.Start > block2.ILRange.Start; + return block1.ILRange.Start.CompareTo(block2.ILRange.Start); } - BlockContainer container1, container2; - if (inst1.MatchLeave(out container1) && container1.Parent is TryInstruction) { - // 'leave tryBlock' is considered to have a later target than - // any branch within the container, and also a later target - // than a return instruction. - // This is necessary to avoid "goto" statements in the - // ExceptionHandling.ConditionalReturnInThrow test. - if (!inst2.MatchLeave(out container2)) - container2 = block2?.Parent as BlockContainer; - return container2 == null || container2.IsDescendantOf(container1); + // prefer arranging stuff in IL order + return exit1.ILRange.Start.CompareTo(exit2.ILRange.Start); + } + + /// + /// Determines if an exit instruction has a corresponding keyword and thus doesn't strictly need merging + /// Branches can be 'continue' or goto (non-keyword) + /// Leave can be 'return', 'break' or a pinned container exit (try/using/lock etc) + /// All other instructions (throw, using, etc) are returned as Keyword.Other + /// + private bool IsKeywordExit(ILInstruction exitInst, out Keyword keyword) + { + keyword = Keyword.Other; + switch (exitInst) { + case Branch branch: + if (branch.TargetBlock == continueBlock) { + keyword = Keyword.Continue; + return true; + } + return false; + case Leave leave: + if (leave.IsLeavingFunction) { + keyword = Keyword.Return; + return true; + } + if (leave.TargetContainer.Kind != ContainerKind.Normal) { + keyword = Keyword.Break; + return true; + } + return false; + default: + return true; } - if (inst1.MatchBranch(out block1) && inst2.MatchLeave(out container2) - && block1.IncomingEdgeCount > 1) - { - // if (..) goto x; leave c; - // Unless x can be inlined, it's better to swap the order if the 'leave' - // has a chance to turn into a 'break;' or 'return;' - if (container2.Parent is ILFunction) { - return true; // return - } - if (container2.EntryPoint.IncomingEdgeCount > 1) { - // break - return BlockContainer.FindClosestContainer(inst2) == container2; - } + } + + /// + /// Determine if the specified instruction necessarily exits (EndPointUnreachable) + /// and if so return last (or single) exit instruction + /// + private static bool TryGetExit(ILInstruction inst, out ILInstruction exitInst) + { + if (inst is Block block && block.Instructions.Count > 0) + inst = block.Instructions.Last(); + + if (inst.HasFlag(InstructionFlags.EndPointUnreachable)) { + exitInst = inst; + return true; } + + exitInst = null; return false; } /// - /// Gets whether potentialBranchInstruction is a branch to a block - /// that is dominated by cfgNode. - /// If this function returns true, we replace the branch instruction with the block itself. + /// Gets the final instruction from a block (or a single instruction) assuming that all blocks + /// or instructions in this position have unreachable endpoints /// - bool IsUsableBranchToChild(ControlFlowNode cfgNode, ILInstruction potentialBranchInstruction) + private static ILInstruction GetExit(ILInstruction inst) { - Branch br = potentialBranchInstruction as Branch; - if (br == null) - return false; - var targetBlock = br.TargetBlock; - return targetBlock.Parent == currentContainer - && targetBlock.IncomingEdgeCount == 1 && targetBlock.FinalInstruction.OpCode == OpCode.Nop - && cfgNode.Dominates(context.ControlFlowGraph.GetNode(targetBlock)); + ILInstruction exitInst = inst is Block block ? block.Instructions.Last() : inst; + // Last instruction is one with unreachable endpoint + // (guaranteed by combination of BlockContainer and Block invariants) + Debug.Assert(exitInst.HasFlag(InstructionFlags.EndPointUnreachable)); + return exitInst; } - - private bool IsBranchOrLeave(ILInstruction inst) + + /// + /// Returns true if inst is Nop or a Block with no instructions. + /// + private static bool IsEmpty(ILInstruction inst) => + inst is Nop || inst is Block block && block.Instructions.Count == 0 && block.FinalInstruction is Nop; + + /// + /// Import some pattern matching from HighLevelLoopTransform to guess the continue block of loop containers. + /// Used to identify branches targetting this block as continue statements, for ordering priority. + /// + /// + private Block GuessContinueBlock() { - switch (inst) { - case Branch branch: - return true; - case Leave leave: - // only void returns are supported as 'exit points' - return leave.Value.MatchNop(); - default: - return false; + if (currentContainer.Kind != ContainerKind.Loop) + return null; + + // continue blocks have exactly 2 incoming edges + if (currentContainer.EntryPoint.IncomingEdgeCount == 2) { + try { + var forIncrement = HighLevelLoopTransform.GetIncrementBlock(currentContainer, currentContainer.EntryPoint); + if (forIncrement != null) + return forIncrement; + } catch (InvalidOperationException) { + // multiple potential increment blocks. Can get this because we don't check that the while loop + // has a condition first, as we don't need to do too much of HighLevelLoopTransform's job. + } } + + return currentContainer.EntryPoint; + } + + /// + /// Removes a subrange of instructions from a block and returns them in a new Block + /// + internal static Block ExtractBlock(Block block, int firstInstIndex, int lastInstIndex) + { + var extractedBlock = new Block(); + for (int i = firstInstIndex; i <= lastInstIndex; i++) { + var inst = block.Instructions[firstInstIndex]; + block.Instructions.RemoveAt(firstInstIndex); + + extractedBlock.Instructions.Add(inst); + extractedBlock.AddILRange(inst.ILRange); + } + + return extractedBlock; } } } diff --git a/ICSharpCode.Decompiler/IL/Transforms/HighLevelLoopTransform.cs b/ICSharpCode.Decompiler/IL/Transforms/HighLevelLoopTransform.cs index aa2ce86cf..30c53efd7 100644 --- a/ICSharpCode.Decompiler/IL/Transforms/HighLevelLoopTransform.cs +++ b/ICSharpCode.Decompiler/IL/Transforms/HighLevelLoopTransform.cs @@ -21,6 +21,7 @@ using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Text; +using ICSharpCode.Decompiler.IL.ControlFlow; using ICSharpCode.Decompiler.Util; namespace ICSharpCode.Decompiler.IL.Transforms @@ -51,43 +52,39 @@ namespace ICSharpCode.Decompiler.IL.Transforms bool MatchWhileLoop(BlockContainer loop, out IfInstruction condition, out Block loopBody) { + // ConditionDetection favours leave inside if and branch at end of block // while-loop: - // if (loop-condition) br loop-content-block - // leave loop-container - // -or- - // if (loop-condition) block content-block - // leave loop-container + // if (!loop-condition) leave loop-container + // ... condition = null; loopBody = null; - if (loop.EntryPoint.Instructions.Count != 2) - return false; if (!(loop.EntryPoint.Instructions[0] is IfInstruction ifInstruction)) return false; if (!ifInstruction.FalseInst.MatchNop()) return false; if (UsesVariableCapturedInLoop(loop, ifInstruction.Condition)) return false; + condition = ifInstruction; - var trueInst = ifInstruction.TrueInst; - if (!loop.EntryPoint.Instructions[1].MatchLeave(loop)) - return false; - if (trueInst is Block b) { - context.Step("Transform to while (condition) loop", loop); - // move the loop body to its own block: - loopBody = b; - trueInst.ReplaceWith(new Branch(loopBody)); - loop.Blocks.Insert(1, loopBody); - // sometimes the loop-content-block does not end with a leave/branch - if (!loopBody.HasFlag(InstructionFlags.EndPointUnreachable)) - loopBody.Instructions.Add(new Leave(loop)); - } else if (trueInst is Branch br) { - context.Step("Transform to while (condition) loop", loop); - loopBody = br.TargetBlock; - } else { + if (!ifInstruction.TrueInst.MatchLeave(loop)) return false; - } + + context.Step("Transform to while (condition) loop", loop); + loop.Kind = ContainerKind.While; + //invert comparison + ifInstruction.Condition = Comp.LogicNot(ifInstruction.Condition); + ifInstruction.FalseInst = ifInstruction.TrueInst; + //move the rest of the body into a new block + loopBody = ConditionDetection.ExtractBlock(loop.EntryPoint, 1, loop.EntryPoint.Instructions.Count - 1); + loop.Blocks.Insert(1, loopBody); + if (!loopBody.HasFlag(InstructionFlags.EndPointUnreachable)) + loopBody.Instructions.Add(new Leave(loop)); + + ifInstruction.TrueInst = new Branch(loopBody); + ExpressionTransforms.RunOnSingleStatment(ifInstruction, context); + // Analyze conditions and decide whether to move some of them out of the condition block: - var conditions = new List(); + /*var conditions = new List(); SplitConditions(condition.Condition, conditions); // Break apart conditions that could be a MoveNext call followed by a Current accessor call: if (MightBeHeaderOfForEach(loop, conditions)) { @@ -97,13 +94,10 @@ namespace ICSharpCode.Decompiler.IL.Transforms loopBody.Instructions.Insert(0, inst = new IfInstruction(Comp.LogicNot(cond), new Leave(loop))); ExpressionTransforms.RunOnSingleStatment(inst, context); } - } - // move the branch/leave instruction into the condition block - ifInstruction.FalseInst = loop.EntryPoint.Instructions[1]; - loop.EntryPoint.Instructions.RemoveAt(1); - loop.Kind = ContainerKind.While; + }*/ + // Invert condition and unwrap nested block, if loop ends in a break or return statement preceeded by an IfInstruction. - while (loopBody.Instructions.Last() is Leave leave && loopBody.Instructions.SecondToLastOrDefault() is IfInstruction nestedIf && nestedIf.FalseInst.MatchNop()) { + /*while (loopBody.Instructions.Last() is Leave leave && loopBody.Instructions.SecondToLastOrDefault() is IfInstruction nestedIf && nestedIf.FalseInst.MatchNop()) { switch (nestedIf.TrueInst) { case Block nestedBlock: loopBody.Instructions.RemoveAt(leave.ChildIndex); @@ -120,7 +114,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms ExpressionTransforms.RunOnSingleStatment(nestedIf, context); if (!loopBody.HasFlag(InstructionFlags.EndPointUnreachable)) loopBody.Instructions.Add(new Leave(loop)); - } + }*/ return true; } @@ -331,6 +325,11 @@ namespace ICSharpCode.Decompiler.IL.Transforms return true; } + internal static Block GetIncrementBlock(BlockContainer loop, Block whileLoopBody) => + loop.Blocks.SingleOrDefault(b => b != whileLoopBody + && b.Instructions.Last().MatchBranch(loop.EntryPoint) + && b.Instructions.SkipLast(1).All(IsSimpleStatement)); + bool MatchForLoop(BlockContainer loop, IfInstruction whileCondition, Block whileLoopBody) { // for loops have exactly two incoming edges at the entry point. @@ -338,10 +337,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms return false; // try to find an increment block: // consists of simple statements only. - var incrementBlock = loop.Blocks.SingleOrDefault( - b => b != whileLoopBody - && b.Instructions.Last().MatchBranch(loop.EntryPoint) - && b.Instructions.SkipLast(1).All(IsSimpleStatement)); + var incrementBlock = GetIncrementBlock(loop, whileLoopBody); if (incrementBlock != null) { // we found a possible increment block, just make sure, that there are at least three blocks: // - condition block