Browse Source

Improve control flow decompilation in ConditionDetection

pull/1176/head
Chicken-Bones 7 years ago
parent
commit
3fb7c71f8a
  1. 86
      ICSharpCode.Decompiler.Tests/TestCases/Pretty/ExceptionHandling.cs
  2. 372
      ICSharpCode.Decompiler.Tests/TestCases/Pretty/ExceptionHandling.il
  3. 227
      ICSharpCode.Decompiler.Tests/TestCases/Pretty/ExceptionHandling.opt.il
  4. 259
      ICSharpCode.Decompiler.Tests/TestCases/Pretty/ExceptionHandling.opt.roslyn.il
  5. 360
      ICSharpCode.Decompiler.Tests/TestCases/Pretty/ExceptionHandling.roslyn.il
  6. 195
      ICSharpCode.Decompiler.Tests/TestCases/Pretty/Loops.cs
  7. 487
      ICSharpCode.Decompiler.Tests/TestCases/Pretty/Loops.il
  8. 295
      ICSharpCode.Decompiler.Tests/TestCases/Pretty/Loops.mcs.il
  9. 308
      ICSharpCode.Decompiler.Tests/TestCases/Pretty/Loops.opt.il
  10. 295
      ICSharpCode.Decompiler.Tests/TestCases/Pretty/Loops.opt.mcs.il
  11. 305
      ICSharpCode.Decompiler.Tests/TestCases/Pretty/Loops.opt.roslyn.il
  12. 483
      ICSharpCode.Decompiler.Tests/TestCases/Pretty/Loops.roslyn.il
  13. 114
      ICSharpCode.Decompiler.Tests/TestCases/Pretty/ShortCircuit.cs
  14. 647
      ICSharpCode.Decompiler.Tests/TestCases/Pretty/ShortCircuit.il
  15. 441
      ICSharpCode.Decompiler.Tests/TestCases/Pretty/ShortCircuit.opt.il
  16. 441
      ICSharpCode.Decompiler.Tests/TestCases/Pretty/ShortCircuit.opt.roslyn.il
  17. 609
      ICSharpCode.Decompiler.Tests/TestCases/Pretty/ShortCircuit.roslyn.il
  18. 720
      ICSharpCode.Decompiler/IL/ControlFlow/ConditionDetection.cs
  19. 68
      ICSharpCode.Decompiler/IL/Transforms/HighLevelLoopTransform.cs

86
ICSharpCode.Decompiler.Tests/TestCases/Pretty/ExceptionHandling.cs

@ -195,5 +195,91 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty @@ -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);
}
}
}
}
}

372
ICSharpCode.Decompiler.Tests/TestCases/Pretty/ExceptionHandling.il

@ -434,6 +434,378 @@ @@ -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
{

227
ICSharpCode.Decompiler.Tests/TestCases/Pretty/ExceptionHandling.opt.il

@ -337,6 +337,233 @@ @@ -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
{

259
ICSharpCode.Decompiler.Tests/TestCases/Pretty/ExceptionHandling.opt.roslyn.il

@ -689,6 +689,265 @@ @@ -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
{

360
ICSharpCode.Decompiler.Tests/TestCases/Pretty/ExceptionHandling.roslyn.il

@ -854,6 +854,366 @@ @@ -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
{

195
ICSharpCode.Decompiler.Tests/TestCases/Pretty/Loops.cs

@ -573,29 +573,37 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty @@ -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 @@ -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 @@ -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 @@ -731,5 +772,47 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
}
}
}
public void NestedForeach(List<object> items1, List<object> 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");
}
}
}

487
ICSharpCode.Decompiler.Tests/TestCases/Pretty/Loops.il

@ -2318,6 +2318,190 @@ @@ -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 @@ @@ -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 @@ @@ -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<object> items1,
class [mscorlib]System.Collections.Generic.List`1<object> 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<object> V_3,
valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator<object> 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<!0> class [mscorlib]System.Collections.Generic.List`1<object>::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<object>::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<!0> class [mscorlib]System.Collections.Generic.List`1<object>::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<object>::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<object>::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<object>
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<object>::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<object>
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
{

295
ICSharpCode.Decompiler.Tests/TestCases/Pretty/Loops.mcs.il

@ -1696,6 +1696,104 @@ @@ -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 @@ @@ -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 @@ @@ -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<object> items1,
class [mscorlib]System.Collections.Generic.List`1<object> items2) cil managed
{
// Code size 139 (0x8b)
.maxstack 19
.locals init (object V_0,
valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator<object> V_1,
bool V_2,
object V_3,
valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator<object> V_4)
IL_0000: ldarg.1
IL_0001: callvirt instance valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator<!0> class [mscorlib]System.Collections.Generic.List`1<object>::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<object>::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<!0> class [mscorlib]System.Collections.Generic.List`1<object>::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<object>::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<object>::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<object>
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<object>::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<object>
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

308
ICSharpCode.Decompiler.Tests/TestCases/Pretty/Loops.opt.il

@ -1842,6 +1842,98 @@ @@ -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 @@ @@ -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 @@ @@ -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<object> items1,
class [mscorlib]System.Collections.Generic.List`1<object> 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<object> V_3,
valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator<object> V_4)
IL_0000: ldarg.1
IL_0001: callvirt instance valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator<!0> class [mscorlib]System.Collections.Generic.List`1<object>::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<object>::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<!0> class [mscorlib]System.Collections.Generic.List`1<object>::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<object>::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<object>::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<object>
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<object>::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<object>
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
{

295
ICSharpCode.Decompiler.Tests/TestCases/Pretty/Loops.opt.mcs.il

@ -1696,6 +1696,104 @@ @@ -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 @@ @@ -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 @@ @@ -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<object> items1,
class [mscorlib]System.Collections.Generic.List`1<object> items2) cil managed
{
// Code size 139 (0x8b)
.maxstack 19
.locals init (object V_0,
valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator<object> V_1,
bool V_2,
object V_3,
valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator<object> V_4)
IL_0000: ldarg.1
IL_0001: callvirt instance valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator<!0> class [mscorlib]System.Collections.Generic.List`1<object>::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<object>::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<!0> class [mscorlib]System.Collections.Generic.List`1<object>::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<object>::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<object>::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<object>
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<object>::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<object>
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

305
ICSharpCode.Decompiler.Tests/TestCases/Pretty/Loops.opt.roslyn.il

@ -1786,6 +1786,98 @@ @@ -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 @@ @@ -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 @@ @@ -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<object> items1,
class [mscorlib]System.Collections.Generic.List`1<object> items2) cil managed
{
// Code size 112 (0x70)
.maxstack 2
.locals init (valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator<object> V_0,
object V_1,
bool V_2,
valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator<object> V_3)
IL_0000: ldarg.1
IL_0001: callvirt instance valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator<!0> class [mscorlib]System.Collections.Generic.List`1<object>::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<object>::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<!0> class [mscorlib]System.Collections.Generic.List`1<object>::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<object>::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<object>::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<object>
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<object>::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<object>
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
{

483
ICSharpCode.Decompiler.Tests/TestCases/Pretty/Loops.roslyn.il

@ -2149,6 +2149,186 @@ @@ -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 @@ @@ -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 @@ @@ -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<object> items1,
class [mscorlib]System.Collections.Generic.List`1<object> items2) cil managed
{
// Code size 141 (0x8d)
.maxstack 2
.locals init (valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator<object> V_0,
object V_1,
bool V_2,
valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator<object> 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<!0> class [mscorlib]System.Collections.Generic.List`1<object>::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<object>::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<!0> class [mscorlib]System.Collections.Generic.List`1<object>::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<object>::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<object>::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<object>
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<object>::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<object>
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
{

114
ICSharpCode.Decompiler.Tests/TestCases/Pretty/ShortCircuit.cs

@ -51,6 +51,21 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty @@ -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 @@ -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 @@ -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 @@ -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 @@ -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;
}
}
}

647
ICSharpCode.Decompiler.Tests/TestCases/Pretty/ShortCircuit.il

@ -167,6 +167,116 @@ @@ -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 @@ @@ -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 @@ @@ -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 @@ @@ -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 @@ @@ -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 @@ @@ -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
{

441
ICSharpCode.Decompiler.Tests/TestCases/Pretty/ShortCircuit.opt.il

@ -155,6 +155,105 @@ @@ -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 @@ @@ -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 @@ @@ -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 @@ @@ -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 @@ @@ -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 @@ @@ -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
{

441
ICSharpCode.Decompiler.Tests/TestCases/Pretty/ShortCircuit.opt.roslyn.il

@ -159,6 +159,105 @@ @@ -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 @@ @@ -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 @@ @@ -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 @@ @@ -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 @@ @@ -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 @@ @@ -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
{

609
ICSharpCode.Decompiler.Tests/TestCases/Pretty/ShortCircuit.roslyn.il

@ -167,6 +167,111 @@ @@ -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 @@ @@ -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 @@ @@ -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 @@ @@ -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 @@ @@ -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 @@ @@ -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
{

720
ICSharpCode.Decompiler/IL/ControlFlow/ConditionDetection.cs

@ -16,6 +16,8 @@ @@ -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 @@ -34,8 +36,18 @@ namespace ICSharpCode.Decompiler.IL.ControlFlow
/// </remarks>
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;
/// <summary>
/// Builds structured control flow for the block associated with the control flow node.
@ -47,264 +59,546 @@ namespace ICSharpCode.Decompiler.IL.ControlFlow @@ -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);
}
/// <summary>
/// Repeatedly inlines and simplifies, maintaining a good block exit and then attempting to match IL order
/// </summary>
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);
}
/// <summary>
/// if (...) br trueBlock;
/// ->
/// if (...) { trueBlock... }
///
/// Only inlines branches that are strictly dominated by this block (incoming edge count == 1)
/// </summary>
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;
}
/// <summary>
/// ...; br nextBlock;
/// ->
/// ...; { nextBlock... }
///
/// Only inlines branches that are strictly dominated by this block (incoming edge count == 1)
/// </summary>
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;
}
/// <summary>
/// Gets whether <c>potentialBranchInstruction</c> is a branch to a block that is dominated by <c>cfgNode</c>.
/// If this function returns true, we replace the branch instruction with the block itself.
/// </summary>
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)
/// <summary>
/// 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
/// </summary>
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<ILInstruction>();
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<ILInstruction>();
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();
}
/// <summary>
/// Finds all exits which could be brought to the block root via inversion
/// </summary>
private void AddExits(ILInstruction searchInst, int startIndex, IList<ILInstruction> 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);
}
/// <summary>
/// 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;
/// </summary>
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;
}
/// <summary>
/// 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;
/// </summary>
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);
}
/// <summary>
/// if (cond) { then... }
/// else...;
/// ->
/// if (!cond) { else... }
/// then...;
///
/// Assumes ifInst does not have an else block
/// </summary>
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);
}
/// <summary>
/// if (cond) { } else { ... }
/// ->
/// if (!cond) { ... }
/// </summary>
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);
}
/// <summary>
/// if (cond) { if (nestedCond) { nestedThen... } }
/// ->
/// if (cond && nestedCond) { nestedThen... }
/// </summary>
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)
/// <summary>
/// if (cond) { lateBlock... } else { earlyBlock... }
/// ->
/// if (!cond) { earlyBlock... } else { lateBlock... }
/// </summary>
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)
/// <summary>
/// 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)
/// </summary>
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)
/// <summary>
/// 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 <c>strongly</c> 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)
/// </summary>
/// <returns>{-1, 0, 1} if exit1 has {lower, equal, higher} priority an exit2</returns>
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);
}
/// <summary>
/// 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
/// </summary>
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;
}
}
/// <summary>
/// Determine if the specified instruction necessarily exits (EndPointUnreachable)
/// and if so return last (or single) exit instruction
/// </summary>
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;
}
/// <summary>
/// Gets whether <c>potentialBranchInstruction</c> is a branch to a block
/// that is dominated by <c>cfgNode</c>.
/// 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
/// </summary>
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)
/// <summary>
/// Returns true if inst is Nop or a Block with no instructions.
/// </summary>
private static bool IsEmpty(ILInstruction inst) =>
inst is Nop || inst is Block block && block.Instructions.Count == 0 && block.FinalInstruction is Nop;
/// <summary>
/// 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.
/// </summary>
/// <returns></returns>
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;
}
/// <summary>
/// Removes a subrange of instructions from a block and returns them in a new Block
/// </summary>
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;
}
}
}

68
ICSharpCode.Decompiler/IL/Transforms/HighLevelLoopTransform.cs

@ -21,6 +21,7 @@ using System.Collections.Generic; @@ -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 @@ -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<ILInstruction>();
/*var conditions = new List<ILInstruction>();
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 @@ -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 @@ -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 @@ -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 @@ -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

Loading…
Cancel
Save