Browse Source

Fix TDCU's version of copy propagation being too aggressive.

pull/2005/head
Daniel Grunwald 5 years ago
parent
commit
80063e3c15
  1. 44
      ICSharpCode.Decompiler.Tests/TestCases/Ugly/AggressiveScalarReplacementOfAggregates.Expected.cs
  2. 54
      ICSharpCode.Decompiler.Tests/TestCases/Ugly/AggressiveScalarReplacementOfAggregates.cs
  3. 162
      ICSharpCode.Decompiler.Tests/TestCases/Ugly/AggressiveScalarReplacementOfAggregates.opt.roslyn.il
  4. 178
      ICSharpCode.Decompiler.Tests/TestCases/Ugly/AggressiveScalarReplacementOfAggregates.roslyn.il
  5. 18
      ICSharpCode.Decompiler/IL/Transforms/TransformDisplayClassUsage.cs

44
ICSharpCode.Decompiler.Tests/TestCases/Ugly/AggressiveScalarReplacementOfAggregates.Expected.cs

@ -120,5 +120,49 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Ugly @@ -120,5 +120,49 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Ugly
}
Console.WriteLine("{0} {1}", field1, field2);
}
public void Test6b(int i)
{
int num = i;
int field1 = num;
string field2 = "Hello World!";
if (num < 0) {
num = -num;
}
Console.WriteLine("{0} {1}", field1, field2);
}
public void Test7(int i)
{
int field1 = i;
string field2 = "Hello World!";
Console.WriteLine("{0} {1} {2}", field1++, field2, i);
}
public void Test8(int i)
{
int field1 = i;
string field2 = "Hello World!";
i = 42;
Console.WriteLine("{0} {1}", field1, field2);
}
public void Test8b(int i)
{
int num = i;
int field1 = num;
string field2 = "Hello World!";
num = 42;
Console.WriteLine("{0} {1}", field1, field2);
}
public void Test9()
{
Program thisField = this;
int field1 = 1;
string field2 = "Hello World!";
thisField = new Program();
Console.WriteLine("{0} {1}", this, thisField);
}
}
}

54
ICSharpCode.Decompiler.Tests/TestCases/Ugly/AggressiveScalarReplacementOfAggregates.cs

@ -126,5 +126,59 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Ugly @@ -126,5 +126,59 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Ugly
}
Console.WriteLine("{0} {1}", displayClass.field1, displayClass.field2);
}
public void Test6b(int i)
{
int num = i;
DisplayClass displayClass = new DisplayClass {
field1 = num,
field2 = "Hello World!"
};
if (num < 0) {
num = -num;
}
Console.WriteLine("{0} {1}", displayClass.field1, displayClass.field2);
}
public void Test7(int i)
{
DisplayClass displayClass = new DisplayClass {
field1 = i,
field2 = "Hello World!"
};
Console.WriteLine("{0} {1} {2}", displayClass.field1++, displayClass.field2, i);
}
public void Test8(int i)
{
DisplayClass displayClass = new DisplayClass {
field1 = i,
field2 = "Hello World!"
};
i = 42;
Console.WriteLine("{0} {1}", displayClass.field1, displayClass.field2);
}
public void Test8b(int i)
{
int num = i;
DisplayClass displayClass = new DisplayClass {
field1 = num,
field2 = "Hello World!"
};
num = 42;
Console.WriteLine("{0} {1}", displayClass.field1, displayClass.field2);
}
public void Test9()
{
DisplayClass displayClass = new DisplayClass {
thisField = this,
field1 = 1,
field2 = "Hello World!"
};
displayClass.thisField = new Program();
Console.WriteLine("{0} {1}", this, displayClass.thisField);
}
}
}

162
ICSharpCode.Decompiler.Tests/TestCases/Ugly/AggressiveScalarReplacementOfAggregates.opt.roslyn.il

@ -359,6 +359,168 @@ @@ -359,6 +359,168 @@
IL_003b: ret
} // end of method Program::Test6
.method public hidebysig instance void
Test6b(int32 i) cil managed
{
// Code size 61 (0x3d)
.maxstack 3
.locals init (int32 V_0,
class ICSharpCode.Decompiler.Tests.TestCases.Ugly.DisplayClass V_1)
IL_0000: ldarg.1
IL_0001: stloc.0
IL_0002: newobj instance void ICSharpCode.Decompiler.Tests.TestCases.Ugly.DisplayClass::.ctor()
IL_0007: dup
IL_0008: ldloc.0
IL_0009: stfld int32 ICSharpCode.Decompiler.Tests.TestCases.Ugly.DisplayClass::field1
IL_000e: dup
IL_000f: ldstr "Hello World!"
IL_0014: stfld string ICSharpCode.Decompiler.Tests.TestCases.Ugly.DisplayClass::field2
IL_0019: stloc.1
IL_001a: ldloc.0
IL_001b: ldc.i4.0
IL_001c: bge.s IL_0021
IL_001e: ldloc.0
IL_001f: neg
IL_0020: stloc.0
IL_0021: ldstr "{0} {1}"
IL_0026: ldloc.1
IL_0027: ldfld int32 ICSharpCode.Decompiler.Tests.TestCases.Ugly.DisplayClass::field1
IL_002c: box [mscorlib]System.Int32
IL_0031: ldloc.1
IL_0032: ldfld string ICSharpCode.Decompiler.Tests.TestCases.Ugly.DisplayClass::field2
IL_0037: call void [mscorlib]System.Console::WriteLine(string,
object,
object)
IL_003c: ret
} // end of method Program::Test6b
.method public hidebysig instance void
Test7(int32 i) cil managed
{
// Code size 69 (0x45)
.maxstack 4
.locals init (class ICSharpCode.Decompiler.Tests.TestCases.Ugly.DisplayClass V_0,
int32 V_1)
IL_0000: newobj instance void ICSharpCode.Decompiler.Tests.TestCases.Ugly.DisplayClass::.ctor()
IL_0005: dup
IL_0006: ldarg.1
IL_0007: stfld int32 ICSharpCode.Decompiler.Tests.TestCases.Ugly.DisplayClass::field1
IL_000c: dup
IL_000d: ldstr "Hello World!"
IL_0012: stfld string ICSharpCode.Decompiler.Tests.TestCases.Ugly.DisplayClass::field2
IL_0017: stloc.0
IL_0018: ldstr "{0} {1} {2}"
IL_001d: ldloc.0
IL_001e: dup
IL_001f: ldfld int32 ICSharpCode.Decompiler.Tests.TestCases.Ugly.DisplayClass::field1
IL_0024: stloc.1
IL_0025: ldloc.1
IL_0026: ldc.i4.1
IL_0027: add
IL_0028: stfld int32 ICSharpCode.Decompiler.Tests.TestCases.Ugly.DisplayClass::field1
IL_002d: ldloc.1
IL_002e: box [mscorlib]System.Int32
IL_0033: ldloc.0
IL_0034: ldfld string ICSharpCode.Decompiler.Tests.TestCases.Ugly.DisplayClass::field2
IL_0039: ldarg.1
IL_003a: box [mscorlib]System.Int32
IL_003f: call void [mscorlib]System.Console::WriteLine(string,
object,
object,
object)
IL_0044: ret
} // end of method Program::Test7
.method public hidebysig instance void
Test8(int32 i) cil managed
{
// Code size 56 (0x38)
.maxstack 3
.locals init (class ICSharpCode.Decompiler.Tests.TestCases.Ugly.DisplayClass V_0)
IL_0000: newobj instance void ICSharpCode.Decompiler.Tests.TestCases.Ugly.DisplayClass::.ctor()
IL_0005: dup
IL_0006: ldarg.1
IL_0007: stfld int32 ICSharpCode.Decompiler.Tests.TestCases.Ugly.DisplayClass::field1
IL_000c: dup
IL_000d: ldstr "Hello World!"
IL_0012: stfld string ICSharpCode.Decompiler.Tests.TestCases.Ugly.DisplayClass::field2
IL_0017: stloc.0
IL_0018: ldc.i4.s 42
IL_001a: starg.s i
IL_001c: ldstr "{0} {1}"
IL_0021: ldloc.0
IL_0022: ldfld int32 ICSharpCode.Decompiler.Tests.TestCases.Ugly.DisplayClass::field1
IL_0027: box [mscorlib]System.Int32
IL_002c: ldloc.0
IL_002d: ldfld string ICSharpCode.Decompiler.Tests.TestCases.Ugly.DisplayClass::field2
IL_0032: call void [mscorlib]System.Console::WriteLine(string,
object,
object)
IL_0037: ret
} // end of method Program::Test8
.method public hidebysig instance void
Test8b(int32 i) cil managed
{
// Code size 57 (0x39)
.maxstack 3
.locals init (int32 V_0,
class ICSharpCode.Decompiler.Tests.TestCases.Ugly.DisplayClass V_1)
IL_0000: ldarg.1
IL_0001: stloc.0
IL_0002: newobj instance void ICSharpCode.Decompiler.Tests.TestCases.Ugly.DisplayClass::.ctor()
IL_0007: dup
IL_0008: ldloc.0
IL_0009: stfld int32 ICSharpCode.Decompiler.Tests.TestCases.Ugly.DisplayClass::field1
IL_000e: dup
IL_000f: ldstr "Hello World!"
IL_0014: stfld string ICSharpCode.Decompiler.Tests.TestCases.Ugly.DisplayClass::field2
IL_0019: stloc.1
IL_001a: ldc.i4.s 42
IL_001c: stloc.0
IL_001d: ldstr "{0} {1}"
IL_0022: ldloc.1
IL_0023: ldfld int32 ICSharpCode.Decompiler.Tests.TestCases.Ugly.DisplayClass::field1
IL_0028: box [mscorlib]System.Int32
IL_002d: ldloc.1
IL_002e: ldfld string ICSharpCode.Decompiler.Tests.TestCases.Ugly.DisplayClass::field2
IL_0033: call void [mscorlib]System.Console::WriteLine(string,
object,
object)
IL_0038: ret
} // end of method Program::Test8b
.method public hidebysig instance void
Test9() cil managed
{
// Code size 60 (0x3c)
.maxstack 3
.locals init (class ICSharpCode.Decompiler.Tests.TestCases.Ugly.DisplayClass V_0)
IL_0000: newobj instance void ICSharpCode.Decompiler.Tests.TestCases.Ugly.DisplayClass::.ctor()
IL_0005: dup
IL_0006: ldarg.0
IL_0007: stfld class ICSharpCode.Decompiler.Tests.TestCases.Ugly.Program ICSharpCode.Decompiler.Tests.TestCases.Ugly.DisplayClass::thisField
IL_000c: dup
IL_000d: ldc.i4.1
IL_000e: stfld int32 ICSharpCode.Decompiler.Tests.TestCases.Ugly.DisplayClass::field1
IL_0013: dup
IL_0014: ldstr "Hello World!"
IL_0019: stfld string ICSharpCode.Decompiler.Tests.TestCases.Ugly.DisplayClass::field2
IL_001e: stloc.0
IL_001f: ldloc.0
IL_0020: newobj instance void ICSharpCode.Decompiler.Tests.TestCases.Ugly.Program::.ctor()
IL_0025: stfld class ICSharpCode.Decompiler.Tests.TestCases.Ugly.Program ICSharpCode.Decompiler.Tests.TestCases.Ugly.DisplayClass::thisField
IL_002a: ldstr "{0} {1}"
IL_002f: ldarg.0
IL_0030: ldloc.0
IL_0031: ldfld class ICSharpCode.Decompiler.Tests.TestCases.Ugly.Program ICSharpCode.Decompiler.Tests.TestCases.Ugly.DisplayClass::thisField
IL_0036: call void [mscorlib]System.Console::WriteLine(string,
object,
object)
IL_003b: ret
} // end of method Program::Test9
.method public hidebysig specialname rtspecialname
instance void .ctor() cil managed
{

178
ICSharpCode.Decompiler.Tests/TestCases/Ugly/AggressiveScalarReplacementOfAggregates.roslyn.il

@ -412,6 +412,184 @@ @@ -412,6 +412,184 @@
IL_0043: ret
} // end of method Program::Test6
.method public hidebysig instance void
Test6b(int32 i) cil managed
{
// Code size 69 (0x45)
.maxstack 3
.locals init (int32 V_0,
class ICSharpCode.Decompiler.Tests.TestCases.Ugly.DisplayClass V_1,
bool V_2)
IL_0000: nop
IL_0001: ldarg.1
IL_0002: stloc.0
IL_0003: newobj instance void ICSharpCode.Decompiler.Tests.TestCases.Ugly.DisplayClass::.ctor()
IL_0008: dup
IL_0009: ldloc.0
IL_000a: stfld int32 ICSharpCode.Decompiler.Tests.TestCases.Ugly.DisplayClass::field1
IL_000f: dup
IL_0010: ldstr "Hello World!"
IL_0015: stfld string ICSharpCode.Decompiler.Tests.TestCases.Ugly.DisplayClass::field2
IL_001a: stloc.1
IL_001b: ldloc.0
IL_001c: ldc.i4.0
IL_001d: clt
IL_001f: stloc.2
IL_0020: ldloc.2
IL_0021: brfalse.s IL_0028
IL_0023: nop
IL_0024: ldloc.0
IL_0025: neg
IL_0026: stloc.0
IL_0027: nop
IL_0028: ldstr "{0} {1}"
IL_002d: ldloc.1
IL_002e: ldfld int32 ICSharpCode.Decompiler.Tests.TestCases.Ugly.DisplayClass::field1
IL_0033: box [mscorlib]System.Int32
IL_0038: ldloc.1
IL_0039: ldfld string ICSharpCode.Decompiler.Tests.TestCases.Ugly.DisplayClass::field2
IL_003e: call void [mscorlib]System.Console::WriteLine(string,
object,
object)
IL_0043: nop
IL_0044: ret
} // end of method Program::Test6b
.method public hidebysig instance void
Test7(int32 i) cil managed
{
// Code size 71 (0x47)
.maxstack 4
.locals init (class ICSharpCode.Decompiler.Tests.TestCases.Ugly.DisplayClass V_0,
int32 V_1)
IL_0000: nop
IL_0001: newobj instance void ICSharpCode.Decompiler.Tests.TestCases.Ugly.DisplayClass::.ctor()
IL_0006: dup
IL_0007: ldarg.1
IL_0008: stfld int32 ICSharpCode.Decompiler.Tests.TestCases.Ugly.DisplayClass::field1
IL_000d: dup
IL_000e: ldstr "Hello World!"
IL_0013: stfld string ICSharpCode.Decompiler.Tests.TestCases.Ugly.DisplayClass::field2
IL_0018: stloc.0
IL_0019: ldstr "{0} {1} {2}"
IL_001e: ldloc.0
IL_001f: dup
IL_0020: ldfld int32 ICSharpCode.Decompiler.Tests.TestCases.Ugly.DisplayClass::field1
IL_0025: stloc.1
IL_0026: ldloc.1
IL_0027: ldc.i4.1
IL_0028: add
IL_0029: stfld int32 ICSharpCode.Decompiler.Tests.TestCases.Ugly.DisplayClass::field1
IL_002e: ldloc.1
IL_002f: box [mscorlib]System.Int32
IL_0034: ldloc.0
IL_0035: ldfld string ICSharpCode.Decompiler.Tests.TestCases.Ugly.DisplayClass::field2
IL_003a: ldarg.1
IL_003b: box [mscorlib]System.Int32
IL_0040: call void [mscorlib]System.Console::WriteLine(string,
object,
object,
object)
IL_0045: nop
IL_0046: ret
} // end of method Program::Test7
.method public hidebysig instance void
Test8(int32 i) cil managed
{
// Code size 58 (0x3a)
.maxstack 3
.locals init (class ICSharpCode.Decompiler.Tests.TestCases.Ugly.DisplayClass V_0)
IL_0000: nop
IL_0001: newobj instance void ICSharpCode.Decompiler.Tests.TestCases.Ugly.DisplayClass::.ctor()
IL_0006: dup
IL_0007: ldarg.1
IL_0008: stfld int32 ICSharpCode.Decompiler.Tests.TestCases.Ugly.DisplayClass::field1
IL_000d: dup
IL_000e: ldstr "Hello World!"
IL_0013: stfld string ICSharpCode.Decompiler.Tests.TestCases.Ugly.DisplayClass::field2
IL_0018: stloc.0
IL_0019: ldc.i4.s 42
IL_001b: starg.s i
IL_001d: ldstr "{0} {1}"
IL_0022: ldloc.0
IL_0023: ldfld int32 ICSharpCode.Decompiler.Tests.TestCases.Ugly.DisplayClass::field1
IL_0028: box [mscorlib]System.Int32
IL_002d: ldloc.0
IL_002e: ldfld string ICSharpCode.Decompiler.Tests.TestCases.Ugly.DisplayClass::field2
IL_0033: call void [mscorlib]System.Console::WriteLine(string,
object,
object)
IL_0038: nop
IL_0039: ret
} // end of method Program::Test8
.method public hidebysig instance void
Test8b(int32 i) cil managed
{
// Code size 59 (0x3b)
.maxstack 3
.locals init (int32 V_0,
class ICSharpCode.Decompiler.Tests.TestCases.Ugly.DisplayClass V_1)
IL_0000: nop
IL_0001: ldarg.1
IL_0002: stloc.0
IL_0003: newobj instance void ICSharpCode.Decompiler.Tests.TestCases.Ugly.DisplayClass::.ctor()
IL_0008: dup
IL_0009: ldloc.0
IL_000a: stfld int32 ICSharpCode.Decompiler.Tests.TestCases.Ugly.DisplayClass::field1
IL_000f: dup
IL_0010: ldstr "Hello World!"
IL_0015: stfld string ICSharpCode.Decompiler.Tests.TestCases.Ugly.DisplayClass::field2
IL_001a: stloc.1
IL_001b: ldc.i4.s 42
IL_001d: stloc.0
IL_001e: ldstr "{0} {1}"
IL_0023: ldloc.1
IL_0024: ldfld int32 ICSharpCode.Decompiler.Tests.TestCases.Ugly.DisplayClass::field1
IL_0029: box [mscorlib]System.Int32
IL_002e: ldloc.1
IL_002f: ldfld string ICSharpCode.Decompiler.Tests.TestCases.Ugly.DisplayClass::field2
IL_0034: call void [mscorlib]System.Console::WriteLine(string,
object,
object)
IL_0039: nop
IL_003a: ret
} // end of method Program::Test8b
.method public hidebysig instance void
Test9() cil managed
{
// Code size 62 (0x3e)
.maxstack 3
.locals init (class ICSharpCode.Decompiler.Tests.TestCases.Ugly.DisplayClass V_0)
IL_0000: nop
IL_0001: newobj instance void ICSharpCode.Decompiler.Tests.TestCases.Ugly.DisplayClass::.ctor()
IL_0006: dup
IL_0007: ldarg.0
IL_0008: stfld class ICSharpCode.Decompiler.Tests.TestCases.Ugly.Program ICSharpCode.Decompiler.Tests.TestCases.Ugly.DisplayClass::thisField
IL_000d: dup
IL_000e: ldc.i4.1
IL_000f: stfld int32 ICSharpCode.Decompiler.Tests.TestCases.Ugly.DisplayClass::field1
IL_0014: dup
IL_0015: ldstr "Hello World!"
IL_001a: stfld string ICSharpCode.Decompiler.Tests.TestCases.Ugly.DisplayClass::field2
IL_001f: stloc.0
IL_0020: ldloc.0
IL_0021: newobj instance void ICSharpCode.Decompiler.Tests.TestCases.Ugly.Program::.ctor()
IL_0026: stfld class ICSharpCode.Decompiler.Tests.TestCases.Ugly.Program ICSharpCode.Decompiler.Tests.TestCases.Ugly.DisplayClass::thisField
IL_002b: ldstr "{0} {1}"
IL_0030: ldarg.0
IL_0031: ldloc.0
IL_0032: ldfld class ICSharpCode.Decompiler.Tests.TestCases.Ugly.Program ICSharpCode.Decompiler.Tests.TestCases.Ugly.DisplayClass::thisField
IL_0037: call void [mscorlib]System.Console::WriteLine(string,
object,
object)
IL_003c: nop
IL_003d: ret
} // end of method Program::Test9
.method public hidebysig specialname rtspecialname
instance void .ctor() cil managed
{

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

@ -447,9 +447,23 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -447,9 +447,23 @@ namespace ICSharpCode.Decompiler.IL.Transforms
switch (value) {
case LdLoc load when load.Variable.StateMachineField == null:
v = load.Variable;
// If the variable is a parameter and it is used elsewhere, we cannot propagate it.
if (v.Kind == VariableKind.Parameter && v.Index >= 0 && v.LoadCount != 1)
if (v.Kind == VariableKind.Parameter) {
if (v.LoadCount != 1 && !v.IsThis()) {
// If the variable is a parameter and it is used elsewhere, we cannot propagate it.
// "dc.field = v; dc.field.mutate(); use(v);" cannot turn to "v.mutate(); use(v)"
return null;
}
} else {
// Non-parameter propagation will later be checked, and will only be allowed for display classes
if (v.Type.IsReferenceType != true) {
// don't allow propagation for display structs (as used with local functions)
return null;
}
}
if (!v.IsSingleDefinition) {
// "dc.field = v; v = 42; use(dc.field)" cannot turn to "v = 42; use(v);"
return null;
}
if (!(expectedType == null || v.Kind == VariableKind.StackSlot || v.Type.Equals(expectedType)))
return null;
return v;

Loading…
Cancel
Save