Skip to content

Commit ac7b120

Browse files
Account for type mismatch of FIELD_LIST members in LSRA (#57450)
* Add the test * Fix the bug Assertion propagation can replace a TYP_UBYTE field in a field list with a TYP_INT constant, so LSRA must use the actual field type when deciding whether an internal register to allocate must be byteable.
1 parent a1eefbb commit ac7b120

File tree

4 files changed

+96
-8
lines changed

4 files changed

+96
-8
lines changed

src/coreclr/jit/lowerxarch.cpp

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -452,10 +452,10 @@ void Lowering::LowerPutArgStk(GenTreePutArgStk* putArgStk)
452452
unsigned prevOffset = putArgStk->GetStackByteSize();
453453
for (GenTreeFieldList::Use& use : fieldList->Uses())
454454
{
455-
GenTree* const fieldNode = use.GetNode();
456-
const var_types fieldType = fieldNode->TypeGet();
457-
const unsigned fieldOffset = use.GetOffset();
458-
assert(fieldType != TYP_LONG);
455+
GenTree* const fieldNode = use.GetNode();
456+
const unsigned fieldOffset = use.GetOffset();
457+
458+
assert(!fieldNode->TypeIs(TYP_LONG));
459459

460460
// We can treat as a slot any field that is stored at a slot boundary, where the previous
461461
// field is not in the same slot. (Note that we store the fields in reverse order.)

src/coreclr/jit/lsraxarch.cpp

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1501,18 +1501,18 @@ int LinearScan::BuildPutArgStk(GenTreePutArgStk* putArgStk)
15011501
for (GenTreeFieldList::Use& use : putArgStk->gtOp1->AsFieldList()->Uses())
15021502
{
15031503
GenTree* const fieldNode = use.GetNode();
1504-
const var_types fieldType = fieldNode->TypeGet();
15051504
const unsigned fieldOffset = use.GetOffset();
1505+
const var_types fieldType = use.GetType();
15061506

15071507
#ifdef TARGET_X86
15081508
assert(fieldType != TYP_LONG);
15091509
#endif // TARGET_X86
15101510

15111511
#if defined(FEATURE_SIMD)
1512-
// Note that we need to check the GT_FIELD_LIST type, not 'fieldType'. This is because the
1513-
// GT_FIELD_LIST will be TYP_SIMD12 whereas the fieldType might be TYP_SIMD16 for lclVar, where
1512+
// Note that we need to check the field type, not the type of the node. This is because the
1513+
// field type will be TYP_SIMD12 whereas the node type might be TYP_SIMD16 for lclVar, where
15141514
// we "round up" to 16.
1515-
if ((use.GetType() == TYP_SIMD12) && (simdTemp == nullptr))
1515+
if ((fieldType == TYP_SIMD12) && (simdTemp == nullptr))
15161516
{
15171517
simdTemp = buildInternalFloatRegisterDefForNode(putArgStk);
15181518
}
Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
using System.Runtime.CompilerServices;
2+
using System.Runtime.InteropServices;
3+
4+
public unsafe class FieldListByteNodeTypeMismatchX86
5+
{
6+
private static readonly byte* _addr = (byte*)Marshal.AllocHGlobal(20);
7+
private static int _result = 100;
8+
9+
public static int Main()
10+
{
11+
int sum = 0;
12+
Problem(&sum);
13+
14+
return _result;
15+
}
16+
17+
[MethodImpl(MethodImplOptions.NoInlining)]
18+
private static void Problem(int* sum)
19+
{
20+
// Just a loop with some computations so that we can use
21+
// callee-saved registers (which happen to be non-byteable ones).
22+
for (int i = 0; i < 10; i++)
23+
{
24+
var i1 = i ^ i;
25+
var i2 = i | i;
26+
var i3 = i & i;
27+
var i4 = i1 + i + i2 - i3;
28+
i4 = i2 ^ i4;
29+
30+
*sum += i4;
31+
}
32+
33+
Sx2x1 s;
34+
byte* j = Addr();
35+
36+
int o1 = j[-2];
37+
int o2 = j[-1];
38+
s.Short = j[0];
39+
s.Byte = j[1];
40+
41+
o1 = o1 + o1;
42+
o2 = o2 + o2;
43+
44+
if (s.Byte != 1)
45+
{
46+
return;
47+
}
48+
49+
// Here assertion propagation will make s.Byte into CNS_INT(TYP_INT), yet the RA must
50+
// still allocate a byteable register so that it can be saved to the stack correctly.
51+
Call(s, 0, 0, o2, o1, j);
52+
}
53+
54+
[MethodImpl(MethodImplOptions.NoInlining)]
55+
private static byte* Addr()
56+
{
57+
_addr[11] = 1;
58+
return _addr + 10;
59+
}
60+
61+
[MethodImpl(MethodImplOptions.NoInlining)]
62+
private static void Call(Sx2x1 s, int i3, int i4, int i5, int i6, byte* i1)
63+
{
64+
if (s.Byte != 1)
65+
{
66+
_result = -1;
67+
}
68+
}
69+
70+
private struct Sx2x1
71+
{
72+
public short Short;
73+
public byte Byte;
74+
}
75+
}
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)