Skip to content

Commit d1dc7b2

Browse files
authored
Copy-propagate the stack slot for collection initializers (#3554)
* Copy-propagate the stack slot for collection initializers * Use pattern matching
1 parent bd06b70 commit d1dc7b2

File tree

5 files changed

+277
-0
lines changed

5 files changed

+277
-0
lines changed

ICSharpCode.Decompiler.Tests/ICSharpCode.Decompiler.Tests.csproj

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,7 @@
105105
<None Include="TestCases\ILPretty\Issue3466.il" />
106106
<None Include="testcases\ilpretty\Issue3504.il" />
107107
<None Include="testcases\ilpretty\Issue3524.il" />
108+
<None Include="testcases\ilpretty\Issue3552.il" />
108109
<None Include="TestCases\ILPretty\MonoFixed.il" />
109110
<None Include="TestCases\Correctness\NonGenericConstrainedCallVirt.il" />
110111
<None Include="TestCases\ILPretty\UnknownTypes.cs" />
@@ -150,6 +151,7 @@
150151
<Compile Include="TestCases\ILPretty\Issue3442.cs" />
151152
<Compile Include="TestCases\ILPretty\Issue3466.cs" />
152153
<Compile Include="TestCases\ILPretty\Issue3524.cs" />
154+
<Compile Include="TestCases\ILPretty\Issue3552.cs" />
153155
<Compile Include="TestCases\Pretty\ExpandParamsArgumentsDisabled.cs" />
154156
<Compile Include="TestCases\Pretty\ExtensionProperties.cs" />
155157
<None Include="TestCases\ILPretty\Issue3504.cs" />

ICSharpCode.Decompiler.Tests/ILPrettyTestRunner.cs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -249,6 +249,12 @@ public async Task Issue3524()
249249
await Run();
250250
}
251251

252+
[Test]
253+
public async Task Issue3552()
254+
{
255+
await Run();
256+
}
257+
252258
[Test]
253259
public async Task Issue2260SwitchString()
254260
{
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
using System;
2+
using System.Collections;
3+
using System.Collections.Generic;
4+
5+
namespace ICSharpCode.Decompiler.Tests.TestCases.ILPretty
6+
{
7+
public static class Issue3552
8+
{
9+
public static Issue3552_IntegerPair MakePair1(int x, int y)
10+
{
11+
Issue3552_IntegerPairBuilder issue3552_IntegerPairBuilder = new Issue3552_IntegerPairBuilder { x, y };
12+
return issue3552_IntegerPairBuilder.ToPair();
13+
}
14+
public static Issue3552_IntegerPair MakePair2(int x, int y)
15+
{
16+
Issue3552_IntegerPairBuilder issue3552_IntegerPairBuilder = new Issue3552_IntegerPairBuilder { x, y };
17+
return issue3552_IntegerPairBuilder.ToPair();
18+
}
19+
public static Issue3552_IntegerPair MakePair3(int x, int y)
20+
{
21+
Issue3552_IntegerPairBuilder issue3552_IntegerPairBuilder = new Issue3552_IntegerPairBuilder { x, y };
22+
return issue3552_IntegerPairBuilder.ToPair();
23+
}
24+
}
25+
public struct Issue3552_IntegerPair
26+
{
27+
public int X;
28+
public int Y;
29+
}
30+
public struct Issue3552_IntegerPairBuilder : IEnumerable<int>, IEnumerable
31+
{
32+
private int index;
33+
private Issue3552_IntegerPair pair;
34+
35+
public readonly Issue3552_IntegerPair ToPair()
36+
{
37+
return pair;
38+
}
39+
40+
public void Add(int value)
41+
{
42+
switch (index)
43+
{
44+
case 0:
45+
pair.X = value;
46+
break;
47+
case 1:
48+
pair.Y = value;
49+
break;
50+
default:
51+
throw new IndexOutOfRangeException();
52+
}
53+
index++;
54+
}
55+
56+
public IEnumerator<int> GetEnumerator()
57+
{
58+
return null;
59+
}
60+
61+
IEnumerator IEnumerable.GetEnumerator()
62+
{
63+
return GetEnumerator();
64+
}
65+
}
66+
}
Lines changed: 198 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,198 @@
1+
.class public auto ansi abstract sealed beforefieldinit ICSharpCode.Decompiler.Tests.TestCases.ILPretty.Issue3552
2+
extends [System.Runtime]System.Object
3+
{
4+
// Methods
5+
.method public hidebysig static
6+
valuetype ICSharpCode.Decompiler.Tests.TestCases.ILPretty.Issue3552_IntegerPair MakePair1 (
7+
int32 x,
8+
int32 y
9+
) cil managed
10+
{
11+
// Method begins at RVA 0x2050
12+
// Header size: 12
13+
// Code size: 34 (0x22)
14+
.maxstack 2
15+
.locals init (
16+
[0] valuetype ICSharpCode.Decompiler.Tests.TestCases.ILPretty.Issue3552_IntegerPairBuilder
17+
)
18+
19+
IL_0000: ldloca.s 0
20+
IL_0002: initobj ICSharpCode.Decompiler.Tests.TestCases.ILPretty.Issue3552_IntegerPairBuilder
21+
IL_0008: ldloca.s 0
22+
IL_000a: ldarg.0
23+
IL_000b: call instance void ICSharpCode.Decompiler.Tests.TestCases.ILPretty.Issue3552_IntegerPairBuilder::Add(int32)
24+
IL_0010: ldloca.s 0
25+
IL_0012: ldarg.1
26+
IL_0013: call instance void ICSharpCode.Decompiler.Tests.TestCases.ILPretty.Issue3552_IntegerPairBuilder::Add(int32)
27+
IL_0015: ldloca.s 0
28+
IL_001c: call instance valuetype ICSharpCode.Decompiler.Tests.TestCases.ILPretty.Issue3552_IntegerPair ICSharpCode.Decompiler.Tests.TestCases.ILPretty.Issue3552_IntegerPairBuilder::ToPair()
29+
IL_0021: ret
30+
} // end of method Issue3552::MakePair1
31+
32+
.method public hidebysig static
33+
valuetype ICSharpCode.Decompiler.Tests.TestCases.ILPretty.Issue3552_IntegerPair MakePair2 (
34+
int32 x,
35+
int32 y
36+
) cil managed
37+
{
38+
// Method begins at RVA 0x2050
39+
// Header size: 12
40+
// Code size: 34 (0x22)
41+
.maxstack 2
42+
.locals init (
43+
[0] valuetype ICSharpCode.Decompiler.Tests.TestCases.ILPretty.Issue3552_IntegerPairBuilder
44+
)
45+
46+
IL_0000: ldloca.s 0
47+
IL_0001: dup
48+
IL_0002: initobj ICSharpCode.Decompiler.Tests.TestCases.ILPretty.Issue3552_IntegerPairBuilder
49+
IL_0008: dup
50+
IL_000a: ldarg.0
51+
IL_000b: call instance void ICSharpCode.Decompiler.Tests.TestCases.ILPretty.Issue3552_IntegerPairBuilder::Add(int32)
52+
IL_0012: ldarg.1
53+
IL_0013: call instance void ICSharpCode.Decompiler.Tests.TestCases.ILPretty.Issue3552_IntegerPairBuilder::Add(int32)
54+
IL_0015: ldloca.s 0
55+
IL_001c: call instance valuetype ICSharpCode.Decompiler.Tests.TestCases.ILPretty.Issue3552_IntegerPair ICSharpCode.Decompiler.Tests.TestCases.ILPretty.Issue3552_IntegerPairBuilder::ToPair()
56+
IL_0021: ret
57+
} // end of method Issue3552::MakePair2
58+
59+
.method public hidebysig static
60+
valuetype ICSharpCode.Decompiler.Tests.TestCases.ILPretty.Issue3552_IntegerPair MakePair3 (
61+
int32 x,
62+
int32 y
63+
) cil managed
64+
{
65+
// Method begins at RVA 0x2050
66+
// Header size: 12
67+
// Code size: 34 (0x22)
68+
.maxstack 2
69+
.locals init (
70+
[0] valuetype ICSharpCode.Decompiler.Tests.TestCases.ILPretty.Issue3552_IntegerPairBuilder
71+
)
72+
73+
IL_0000: ldloca.s 0
74+
IL_0001: dup
75+
IL_0002: initobj ICSharpCode.Decompiler.Tests.TestCases.ILPretty.Issue3552_IntegerPairBuilder
76+
IL_0008: dup
77+
IL_000a: ldarg.0
78+
IL_000b: call instance void ICSharpCode.Decompiler.Tests.TestCases.ILPretty.Issue3552_IntegerPairBuilder::Add(int32)
79+
IL_0010: dup
80+
IL_0012: ldarg.1
81+
IL_0013: call instance void ICSharpCode.Decompiler.Tests.TestCases.ILPretty.Issue3552_IntegerPairBuilder::Add(int32)
82+
IL_001c: call instance valuetype ICSharpCode.Decompiler.Tests.TestCases.ILPretty.Issue3552_IntegerPair ICSharpCode.Decompiler.Tests.TestCases.ILPretty.Issue3552_IntegerPairBuilder::ToPair()
83+
IL_0021: ret
84+
} // end of method Issue3552::MakePair3
85+
86+
} // end of class ICSharpCode.Decompiler.Tests.TestCases.ILPretty.Issue3552
87+
88+
.class public sequential ansi sealed beforefieldinit ICSharpCode.Decompiler.Tests.TestCases.ILPretty.Issue3552_IntegerPair
89+
extends [System.Runtime]System.ValueType
90+
{
91+
// Fields
92+
.field public int32 X
93+
.field public int32 Y
94+
95+
} // end of class ICSharpCode.Decompiler.Tests.TestCases.ILPretty.Issue3552_IntegerPair
96+
97+
.class public sequential ansi sealed beforefieldinit ICSharpCode.Decompiler.Tests.TestCases.ILPretty.Issue3552_IntegerPairBuilder
98+
extends [System.Runtime]System.ValueType
99+
implements class [System.Runtime]System.Collections.Generic.IEnumerable`1<int32>,
100+
[System.Runtime]System.Collections.IEnumerable
101+
{
102+
// Fields
103+
.field private int32 index
104+
.field private valuetype ICSharpCode.Decompiler.Tests.TestCases.ILPretty.Issue3552_IntegerPair pair
105+
106+
// Methods
107+
.method public hidebysig
108+
instance valuetype ICSharpCode.Decompiler.Tests.TestCases.ILPretty.Issue3552_IntegerPair ToPair () cil managed
109+
{
110+
.custom instance void [System.Runtime]System.Runtime.CompilerServices.IsReadOnlyAttribute::.ctor() = (
111+
01 00 00 00
112+
)
113+
// Method begins at RVA 0x207e
114+
// Header size: 1
115+
// Code size: 7 (0x7)
116+
.maxstack 8
117+
118+
IL_0000: ldarg.0
119+
IL_0001: ldfld valuetype ICSharpCode.Decompiler.Tests.TestCases.ILPretty.Issue3552_IntegerPair ICSharpCode.Decompiler.Tests.TestCases.ILPretty.Issue3552_IntegerPairBuilder::pair
120+
IL_0006: ret
121+
} // end of method Issue3552_IntegerPairBuilder::ToPair
122+
123+
.method public hidebysig
124+
instance void Add (
125+
int32 'value'
126+
) cil managed
127+
{
128+
// Method begins at RVA 0x2088
129+
// Header size: 12
130+
// Code size: 65 (0x41)
131+
.maxstack 3
132+
.locals init (
133+
[0] int32
134+
)
135+
136+
IL_0000: ldarg.0
137+
IL_0001: ldfld int32 ICSharpCode.Decompiler.Tests.TestCases.ILPretty.Issue3552_IntegerPairBuilder::index
138+
IL_0006: stloc.0
139+
IL_0007: ldloc.0
140+
IL_0008: brfalse.s IL_0010
141+
142+
IL_000a: ldloc.0
143+
IL_000b: ldc.i4.1
144+
IL_000c: beq.s IL_001e
145+
146+
IL_000e: br.s IL_002c
147+
148+
IL_0010: ldarg.0
149+
IL_0011: ldflda valuetype ICSharpCode.Decompiler.Tests.TestCases.ILPretty.Issue3552_IntegerPair ICSharpCode.Decompiler.Tests.TestCases.ILPretty.Issue3552_IntegerPairBuilder::pair
150+
IL_0016: ldarg.1
151+
IL_0017: stfld int32 ICSharpCode.Decompiler.Tests.TestCases.ILPretty.Issue3552_IntegerPair::X
152+
IL_001c: br.s IL_0032
153+
154+
IL_001e: ldarg.0
155+
IL_001f: ldflda valuetype ICSharpCode.Decompiler.Tests.TestCases.ILPretty.Issue3552_IntegerPair ICSharpCode.Decompiler.Tests.TestCases.ILPretty.Issue3552_IntegerPairBuilder::pair
156+
IL_0024: ldarg.1
157+
IL_0025: stfld int32 ICSharpCode.Decompiler.Tests.TestCases.ILPretty.Issue3552_IntegerPair::Y
158+
IL_002a: br.s IL_0032
159+
160+
IL_002c: newobj instance void [System.Runtime]System.IndexOutOfRangeException::.ctor()
161+
IL_0031: throw
162+
163+
IL_0032: ldarg.0
164+
IL_0033: ldarg.0
165+
IL_0034: ldfld int32 ICSharpCode.Decompiler.Tests.TestCases.ILPretty.Issue3552_IntegerPairBuilder::index
166+
IL_0039: ldc.i4.1
167+
IL_003a: add
168+
IL_003b: stfld int32 ICSharpCode.Decompiler.Tests.TestCases.ILPretty.Issue3552_IntegerPairBuilder::index
169+
IL_0040: ret
170+
} // end of method Issue3552_IntegerPairBuilder::Add
171+
172+
.method public final hidebysig newslot virtual
173+
instance class [System.Runtime]System.Collections.Generic.IEnumerator`1<int32> GetEnumerator () cil managed
174+
{
175+
// Method begins at RVA 0x20d5
176+
// Header size: 1
177+
// Code size: 2 (0x2)
178+
.maxstack 8
179+
180+
IL_0000: ldnull
181+
IL_0001: ret
182+
} // end of method Issue3552_IntegerPairBuilder::GetEnumerator
183+
184+
.method private final hidebysig newslot virtual
185+
instance class [System.Runtime]System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator () cil managed
186+
{
187+
.override method instance class [System.Runtime]System.Collections.IEnumerator [System.Runtime]System.Collections.IEnumerable::GetEnumerator()
188+
// Method begins at RVA 0x20d8
189+
// Header size: 1
190+
// Code size: 7 (0x7)
191+
.maxstack 8
192+
193+
IL_0000: ldarg.0
194+
IL_0001: call instance class [System.Runtime]System.Collections.Generic.IEnumerator`1<int32> ICSharpCode.Decompiler.Tests.TestCases.ILPretty.Issue3552_IntegerPairBuilder::GetEnumerator()
195+
IL_0006: ret
196+
} // end of method Issue3552_IntegerPairBuilder::System.Collections.IEnumerable.GetEnumerator
197+
198+
} // end of class ICSharpCode.Decompiler.Tests.TestCases.ILPretty.Issue3552_IntegerPairBuilder

ICSharpCode.Decompiler/IL/Transforms/TransformCollectionAndObjectInitializers.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,11 @@ void IStatementTransform.Run(Block block, int pos, StatementTransformContext con
9797
}
9898
return;
9999
}
100+
// Copy-propagate stack slot holding an 'ldloca' of the variable
101+
if (pos < block.Instructions.Count && block.Instructions[pos + 1] is StLoc { Variable: { Kind: VariableKind.StackSlot, IsSingleDefinition: true }, Value: LdLoca ldLoca } stLocStack && ldLoca.Variable == v)
102+
{
103+
CopyPropagation.Propagate(stLocStack, context);
104+
}
100105
int initializerItemsCount = 0;
101106
bool initializerContainsInitOnlyItems = false;
102107
possibleIndexVariables.Clear();

0 commit comments

Comments
 (0)