Skip to content

Commit ed71783

Browse files
[release/6.0] Undo struct promotion on "RetInd" code path (#58602)
* TOREVERT: small repro case * Fix the undone struct promotion for return * Display lclVar number * Revert "TOREVERT: small repro case" This reverts commit 9ef80ba. * Add test case * jit format * Combine the condition * Add an assert to catch the missing places * Remove unneeded variable setting from csproj Co-authored-by: Kunal Pathak <Kunal.Pathak@microsoft.com>
1 parent dd0ecba commit ed71783

File tree

6 files changed

+82
-3
lines changed

6 files changed

+82
-3
lines changed

src/coreclr/jit/clrjit.natvis

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -65,8 +65,8 @@ Documentation for VS debugger format specifiers: https://docs.microsoft.com/en-u
6565
</Type>
6666

6767
<Type Name="LclVarDsc">
68-
<DisplayString Condition="lvReason==0">[{lvType,en}]</DisplayString>
69-
<DisplayString>[{lvType,en}-{lvReason,s}]</DisplayString>
68+
<DisplayString Condition="lvReason==0">[V{lvSlotNum,d}: {lvType,en}]</DisplayString>
69+
<DisplayString>[V{lvSlotNum,d}: {lvType,en}-{lvReason,s}]</DisplayString>
7070
</Type>
7171

7272
<Type Name="GenTreeLclVar" Inheritable="false">

src/coreclr/jit/compiler.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -502,6 +502,9 @@ class LclVarDsc
502502
unsigned char lvUnusedStruct : 1; // All references to this promoted struct are through its field locals.
503503
// I.e. there is no longer any reference to the struct directly.
504504
// In this case we can simply remove this struct local.
505+
506+
unsigned char lvUndoneStructPromotion : 1; // The struct promotion was undone and hence there should be no
507+
// reference to the fields of this struct.
505508
#endif
506509

507510
unsigned char lvLRACandidate : 1; // Tracked for linear scan register allocation purposes

src/coreclr/jit/lclvars.cpp

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4075,6 +4075,16 @@ void Compiler::lvaMarkLclRefs(GenTree* tree, BasicBlock* block, Statement* stmt,
40754075

40764076
varDsc->incRefCnts(weight, this);
40774077

4078+
#ifdef DEBUG
4079+
if (varDsc->lvIsStructField)
4080+
{
4081+
// If ref count was increased for struct field, ensure that the
4082+
// parent struct is still promoted.
4083+
LclVarDsc* parentStruct = &lvaTable[varDsc->lvParentLcl];
4084+
assert(!parentStruct->lvUndoneStructPromotion);
4085+
}
4086+
#endif
4087+
40784088
if (!isRecompute)
40794089
{
40804090
if (lvaVarAddrExposed(lclNum))

src/coreclr/jit/morph.cpp

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13997,6 +13997,12 @@ GenTree* Compiler::fgMorphRetInd(GenTreeUnOp* ret)
1399713997

1399813998
if (addr->OperIs(GT_ADDR) && addr->gtGetOp1()->OperIs(GT_LCL_VAR))
1399913999
{
14000+
// If struct promotion was undone, adjust the annotations
14001+
if (fgGlobalMorph && fgMorphImplicitByRefArgs(addr))
14002+
{
14003+
return ind;
14004+
}
14005+
1400014006
// If `return` retypes LCL_VAR as a smaller struct it should not set `doNotEnregister` on that
1400114007
// LclVar.
1400214008
// Example: in `Vector128:AsVector2` we have RETURN SIMD8(OBJ SIMD8(ADDR byref(LCL_VAR SIMD16))).
@@ -17662,6 +17668,8 @@ void Compiler::fgRetypeImplicitByRefArgs()
1766217668

1766317669
void Compiler::fgMarkDemotedImplicitByRefArgs()
1766417670
{
17671+
JITDUMP("\n*************** In fgMarkDemotedImplicitByRefArgs()\n");
17672+
1766517673
#if (defined(TARGET_AMD64) && !defined(UNIX_AMD64_ABI)) || defined(TARGET_ARM64)
1766617674

1766717675
for (unsigned lclNum = 0; lclNum < info.compArgsCount; lclNum++)
@@ -17670,6 +17678,8 @@ void Compiler::fgMarkDemotedImplicitByRefArgs()
1767017678

1767117679
if (lvaIsImplicitByRefLocal(lclNum))
1767217680
{
17681+
JITDUMP("Clearing annotation for V%02d\n", lclNum);
17682+
1767317683
if (varDsc->lvPromoted)
1767417684
{
1767517685
// The parameter is simply a pointer now, so clear lvPromoted. It was left set
@@ -17696,7 +17706,8 @@ void Compiler::fgMarkDemotedImplicitByRefArgs()
1769617706
LclVarDsc* structVarDsc = &lvaTable[structLclNum];
1769717707
structVarDsc->lvAddrExposed = false;
1769817708
#ifdef DEBUG
17699-
structVarDsc->lvUnusedStruct = true;
17709+
structVarDsc->lvUnusedStruct = true;
17710+
structVarDsc->lvUndoneStructPromotion = true;
1770017711
#endif // DEBUG
1770117712

1770217713
unsigned fieldLclStart = structVarDsc->lvFieldLclStart;
@@ -17705,6 +17716,8 @@ void Compiler::fgMarkDemotedImplicitByRefArgs()
1770517716

1770617717
for (unsigned fieldLclNum = fieldLclStart; fieldLclNum < fieldLclStop; ++fieldLclNum)
1770717718
{
17719+
JITDUMP("Fixing pointer for field V%02d from V%02d to V%02d\n", fieldLclNum, lclNum, structLclNum);
17720+
1770817721
// Fix the pointer to the parent local.
1770917722
LclVarDsc* fieldVarDsc = &lvaTable[fieldLclNum];
1771017723
assert(fieldVarDsc->lvParentLcl == lclNum);
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
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+
using System;
5+
using System.Runtime.CompilerServices;
6+
using System.Runtime.InteropServices;
7+
8+
[StructLayout(LayoutKind.Sequential)]
9+
internal struct AA
10+
{
11+
public short tmp1;
12+
public short q;
13+
14+
public ushort tmp2;
15+
public int tmp3;
16+
17+
public AA(short qq)
18+
{
19+
tmp1 = 106;
20+
tmp2 = 107;
21+
tmp3 = 108;
22+
q = qq;
23+
}
24+
25+
// The test verifies that we accurately update the byref variable that is a field of struct.
26+
public static short call_target_ref(ref short arg) { arg = 100; return arg; }
27+
}
28+
29+
30+
public class Runtime_57912
31+
{
32+
33+
public static int Main()
34+
{
35+
return (int)test_0_17(100, new AA(100), new AA(0));
36+
}
37+
38+
[MethodImpl(MethodImplOptions.NoInlining)]
39+
static short test_0_17(int num, AA init, AA zero)
40+
{
41+
return AA.call_target_ref(ref init.q);
42+
}
43+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
<Project Sdk="Microsoft.NET.Sdk">
2+
<PropertyGroup>
3+
<OutputType>Exe</OutputType>
4+
<Optimize>True</Optimize>
5+
<DebugType>None</DebugType>
6+
</PropertyGroup>
7+
<ItemGroup>
8+
<Compile Include="$(MSBuildProjectName).cs" />
9+
</ItemGroup>
10+
</Project>

0 commit comments

Comments
 (0)