Skip to content

Commit ba43e08

Browse files
authored
Fix underestimation of temps size (#58969)
It was possible for us to underestimate the size of temps required. This happened because we used the state of the frame layout to check if the size of temps was computed and that check was wrong. This could lead us to make different decisions about which registers needed to be saved in the prolog and epilog on ARM32. In particular, if the frame size was around the size where a stack probe is necessary, this could be possible. There are also other comments that suggest that this could result in failure while encoding instructions that reference the stack locals. Fix #58293
1 parent a8c2d1e commit ba43e08

File tree

7 files changed

+132
-2
lines changed

7 files changed

+132
-2
lines changed

src/coreclr/jit/codegenarm.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1884,6 +1884,7 @@ void CodeGen::genAllocLclFrame(unsigned frameSize, regNumber initReg, bool* pIni
18841884
INS_FLAGS_DONT_CARE, REG_STACK_PROBE_HELPER_ARG);
18851885
regSet.verifyRegUsed(REG_STACK_PROBE_HELPER_ARG);
18861886
genEmitHelperCall(CORINFO_HELP_STACK_PROBE, 0, EA_UNKNOWN, REG_STACK_PROBE_HELPER_CALL_TARGET);
1887+
regSet.verifyRegUsed(REG_STACK_PROBE_HELPER_CALL_TARGET);
18871888
compiler->unwindPadding();
18881889
GetEmitter()->emitIns_Mov(INS_mov, EA_PTRSIZE, REG_SPBASE, REG_STACK_PROBE_HELPER_ARG, /* canSkip */ false);
18891890

src/coreclr/jit/lclvars.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4689,7 +4689,7 @@ unsigned Compiler::lvaGetMaxSpillTempSize()
46894689
{
46904690
unsigned result = 0;
46914691

4692-
if (lvaDoneFrameLayout >= REGALLOC_FRAME_LAYOUT)
4692+
if (codeGen->regSet.hasComputedTmpSize())
46934693
{
46944694
result = codeGen->regSet.tmpGetTotalSize();
46954695
}

src/coreclr/jit/lsra.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6478,6 +6478,8 @@ void LinearScan::recordMaxSpill()
64786478
maxSpill[TYP_FLOAT] += 1;
64796479
}
64806480
#endif // TARGET_X86
6481+
6482+
compiler->codeGen->regSet.tmpBeginPreAllocateTemps();
64816483
for (int i = 0; i < TYP_COUNT; i++)
64826484
{
64836485
if (var_types(i) != RegSet::tmpNormalizeType(var_types(i)))

src/coreclr/jit/regset.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -625,7 +625,7 @@ XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
625625
void RegSet::tmpInit()
626626
{
627627
tmpCount = 0;
628-
tmpSize = 0;
628+
tmpSize = UINT_MAX;
629629
#ifdef DEBUG
630630
tmpGetCount = 0;
631631
#endif

src/coreclr/jit/regset.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -192,13 +192,23 @@ class RegSet
192192
bool tmpAllFree() const;
193193
#endif // DEBUG
194194

195+
void tmpBeginPreAllocateTemps()
196+
{
197+
tmpSize = 0;
198+
}
195199
void tmpPreAllocateTemps(var_types type, unsigned count);
196200

197201
unsigned tmpGetTotalSize()
198202
{
203+
assert(hasComputedTmpSize());
199204
return tmpSize;
200205
}
201206

207+
bool hasComputedTmpSize()
208+
{
209+
return tmpSize != UINT_MAX;
210+
}
211+
202212
private:
203213
unsigned tmpCount; // Number of temps
204214
unsigned tmpSize; // Size of all the temps
Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
// Licensed to the .NET Foundation under one or more agreements.
2+
// The .NET Foundation licenses this file to you under the MIT license.
3+
4+
// Generated by Fuzzlyn v1.4 on 2021-08-24 18:42:34
5+
// Run on .NET 7.0.0-dev on Arm Linux
6+
// Seed: 4314857431407232792
7+
// Reduced from 582.3 KiB to 3.3 KiB in 02:00:04
8+
// Crashes the runtime
9+
public interface I0
10+
{
11+
}
12+
13+
public interface I3
14+
{
15+
}
16+
17+
public struct S0 : I0
18+
{
19+
public sbyte F0;
20+
public short F1;
21+
public sbyte F2;
22+
public int F4;
23+
public bool F5;
24+
public S0(bool f5): this()
25+
{
26+
}
27+
28+
public S1 M34(S1[] arg0)
29+
{
30+
return default(S1);
31+
}
32+
}
33+
34+
public struct S1 : I0, I3
35+
{
36+
public short F0;
37+
public S0 F1;
38+
public S0 F2;
39+
public S0 F3;
40+
public S1(S0 f1, S0 f2, S0 f3): this()
41+
{
42+
}
43+
}
44+
45+
public class Runtime_58293
46+
{
47+
private static I s_rt;
48+
public static I3 s_21;
49+
public static S1 s_29;
50+
public static S1[][] s_32 = new S1[][]{new S1[]{new S1(new S0(false), new S0(false), new S0(true))}};
51+
public static I3[][] s_42;
52+
public static int Main()
53+
{
54+
s_rt = new C();
55+
var vr3 = s_32[0][0].F3.F2;
56+
M33(vr3);
57+
return 100;
58+
}
59+
60+
public static I0[] M33(sbyte arg0)
61+
{
62+
S1 var3;
63+
I3 var8;
64+
S1 var9;
65+
uint var11;
66+
S0 var12;
67+
var vr24 = s_32[0];
68+
new S0(false).M34(vr24);
69+
I0 var0 = new S0(true);
70+
var vr0 = new S1[]{new S1(new S0(true), new S0(false), new S0(false)), new S1(new S0(true), new S0(false), new S0(false)), new S1(new S0(true), new S0(false), new S0(true))};
71+
new S0(true).M34(vr0);
72+
try
73+
{
74+
bool var1 = s_29.F2.F5;
75+
s_rt.WriteLine(var1);
76+
}
77+
finally
78+
{
79+
s_42 = new I3[][]{new I3[]{new S1(new S0(true), new S0(true), new S0(true)), new S1(new S0(true), new S0(true), new S0(true))}, new I3[]{new S1(new S0(false), new S0(true), new S0(true)), new S1(new S0(false), new S0(true), new S0(true)), new S1(new S0(true), new S0(false), new S0(true)), new S1(new S0(true), new S0(false), new S0(false))}, new I3[]{new S1(new S0(true), new S0(true), new S0(false)), new S1(new S0(true), new S0(false), new S0(true)), new S1(new S0(false), new S0(false), new S0(false)), new S1(new S0(false), new S0(false), new S0(true)), new S1(new S0(true), new S0(true), new S0(false))}, new I3[]{new S1(new S0(false), new S0(true), new S0(false)), new S1(new S0(true), new S0(false), new S0(false)), new S1(new S0(true), new S0(false), new S0(false)), new S1(new S0(true), new S0(false), new S0(true)), new S1(new S0(true), new S0(false), new S0(true))}, new I3[]{new S1(new S0(false), new S0(false), new S0(false)), new S1(new S0(true), new S0(false), new S0(true)), new S1(new S0(true), new S0(false), new S0(true)), new S1(new S0(false), new S0(true), new S0(true)), new S1(new S0(false), new S0(true), new S0(true))}, new I3[]{new S1(new S0(false), new S0(true), new S0(true)), new S1(new S0(false), new S0(false), new S0(false))}};
80+
}
81+
82+
var vr30 = new S1[]{new S1(new S0(true), new S0(false), new S0(false)), new S1(new S0(true), new S0(false), new S0(false)), new S1(new S0(true), new S0(false), new S0(true)), new S1(new S0(true), new S0(false), new S0(true)), new S1(new S0(true), new S0(false), new S0(false))};
83+
s_21 = s_29.F2.M34(vr30);
84+
var0 = new S1(new S0(true), new S0(false), new S0(true));
85+
var vr2 = new S0(true);
86+
I3 vr23;
87+
I3 var2 = new S1(new S0(true), new S0(true), new S0(false));
88+
bool vr25;
89+
bool vr26;
90+
bool vr28;
91+
bool vr29;
92+
bool vr31;
93+
return new I0[]{new S0(false), new S0(true), new S1(new S0(true), new S0(true), new S0(false))};
94+
}
95+
}
96+
97+
public interface I { void WriteLine<T>(T val); }
98+
public class C : I
99+
{
100+
public void WriteLine<T>(T val)
101+
{
102+
System.Console.WriteLine(val);
103+
}
104+
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
<Project Sdk="Microsoft.NET.Sdk">
2+
<PropertyGroup>
3+
<OutputType>Exe</OutputType>
4+
<AllowUnsafeBlocks>True</AllowUnsafeBlocks>
5+
</PropertyGroup>
6+
<PropertyGroup>
7+
<DebugType>None</DebugType>
8+
<Optimize>True</Optimize>
9+
</PropertyGroup>
10+
<ItemGroup>
11+
<Compile Include="$(MSBuildProjectName).cs" />
12+
</ItemGroup>
13+
</Project>

0 commit comments

Comments
 (0)