Skip to content

Commit edaa6d7

Browse files
author
Sergey Andreenko
authored
Check that 'lvDoNotEnregister' is set as necessary. (#52802)
* add a repro test. * LclVar which addresses are taken should be marked as doNotEnreg. Check that we don't have independently promoted LCL_VAR that are references after lowering. Check that all LclVars that have ADDR() on top of them are marked as doNotEnreg. In the past when we did not enregister structs we were allocating them on the stack even without doNotEnreg set.
1 parent 62712ec commit edaa6d7

File tree

8 files changed

+105
-10
lines changed

8 files changed

+105
-10
lines changed

src/coreclr/jit/compiler.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3433,6 +3433,7 @@ class Compiler
34333433
DNER_NoRegVars, // opts.compFlags & CLFLG_REGVAR is not set
34343434
DNER_MinOptsGC, // It is a GC Ref and we are compiling MinOpts
34353435
#if !defined(TARGET_64BIT)
3436+
DNER_LongParamVar, // It is a long parameter.
34363437
DNER_LongParamField, // It is a decomposed field of a long parameter.
34373438
#endif
34383439
#ifdef JIT32_GCENCODER

src/coreclr/jit/decomposelongs.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -356,6 +356,7 @@ GenTree* DecomposeLongs::DecomposeLclVar(LIR::Use& use)
356356
}
357357
else
358358
{
359+
m_compiler->lvaSetVarDoNotEnregister(varNum DEBUGARG(Compiler::DNER_LocalField));
359360
loResult->SetOper(GT_LCL_FLD);
360361
loResult->AsLclFld()->SetLclOffs(0);
361362
loResult->AsLclFld()->SetFieldSeq(FieldSeqStore::NotAField());

src/coreclr/jit/lclvars.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2635,6 +2635,9 @@ void Compiler::lvaSetVarDoNotEnregister(unsigned varNum DEBUGARG(DoNotEnregister
26352635
case DNER_LongParamField:
26362636
JITDUMP("it is a decomposed field of a long parameter\n");
26372637
break;
2638+
case DNER_LongParamVar:
2639+
JITDUMP("it is a long parameter\n");
2640+
break;
26382641
#endif
26392642
default:
26402643
unreached();

src/coreclr/jit/lower.cpp

Lines changed: 39 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -354,6 +354,16 @@ GenTree* Lowering::LowerNode(GenTree* node)
354354
node->gtGetOp1()->SetRegOptional();
355355
break;
356356

357+
case GT_LCL_FLD_ADDR:
358+
case GT_LCL_VAR_ADDR:
359+
{
360+
// TODO-Cleanup: this is definitely not the best place for this detection,
361+
// but for now it is the easiest. Move it to morph.
362+
const GenTreeLclVarCommon* lclAddr = node->AsLclVarCommon();
363+
comp->lvaSetVarDoNotEnregister(lclAddr->GetLclNum() DEBUGARG(Compiler::DNER_BlockOp));
364+
}
365+
break;
366+
357367
default:
358368
break;
359369
}
@@ -3208,7 +3218,9 @@ void Lowering::LowerStoreLocCommon(GenTreeLclVarCommon* lclStore)
32083218

32093219
if (convertToStoreObj)
32103220
{
3211-
GenTreeLclVar* addr = comp->gtNewLclVarAddrNode(lclStore->GetLclNum(), TYP_BYREF);
3221+
const unsigned lclNum = lclStore->GetLclNum();
3222+
GenTreeLclVar* addr = comp->gtNewLclVarAddrNode(lclNum, TYP_BYREF);
3223+
comp->lvaSetVarDoNotEnregister(lclNum DEBUGARG(Compiler::DNER_BlockOp));
32123224

32133225
addr->gtFlags |= GTF_VAR_DEF;
32143226
assert(!addr->IsPartialLclFld(comp));
@@ -3584,7 +3596,8 @@ void Lowering::LowerStoreSingleRegCallStruct(GenTreeBlk* store)
35843596
GenTreeLclVar* Lowering::SpillStructCallResult(GenTreeCall* call) const
35853597
{
35863598
// TODO-1stClassStructs: we can support this in codegen for `GT_STORE_BLK` without new temps.
3587-
const unsigned spillNum = comp->lvaGrabTemp(true DEBUGARG("Return value temp for an odd struct return size"));
3599+
const unsigned spillNum = comp->lvaGrabTemp(true DEBUGARG("Return value temp for an odd struct return size"));
3600+
comp->lvaSetVarDoNotEnregister(spillNum DEBUGARG(Compiler::DNER_LocalField));
35883601
CORINFO_CLASS_HANDLE retClsHnd = call->gtRetClsHnd;
35893602
comp->lvaSetStruct(spillNum, retClsHnd, false);
35903603
GenTreeLclFld* spill = new (comp, GT_STORE_LCL_FLD) GenTreeLclFld(GT_STORE_LCL_FLD, call->gtType, spillNum, 0);
@@ -6011,20 +6024,26 @@ void Lowering::CheckNode(Compiler* compiler, GenTree* node)
60116024
case GT_HWINTRINSIC:
60126025
assert(node->TypeGet() != TYP_SIMD12);
60136026
break;
6014-
#ifdef TARGET_64BIT
6027+
#endif // FEATURE_SIMD
6028+
60156029
case GT_LCL_VAR:
60166030
case GT_STORE_LCL_VAR:
60176031
{
6018-
unsigned lclNum = node->AsLclVarCommon()->GetLclNum();
6019-
LclVarDsc* lclVar = &compiler->lvaTable[lclNum];
6032+
GenTreeLclVar* lclVar = node->AsLclVar();
6033+
const unsigned lclNum = lclVar->GetLclNum();
6034+
const LclVarDsc* varDsc = compiler->lvaGetDesc(lclNum);
6035+
#if defined(FEATURE_SIMD) && defined(TARGET_64BIT)
60206036
if (node->TypeIs(TYP_SIMD12))
60216037
{
6022-
assert(compiler->lvaIsFieldOfDependentlyPromotedStruct(lclVar) || (lclVar->lvSize() == 12));
6038+
assert(compiler->lvaIsFieldOfDependentlyPromotedStruct(varDsc) || (varDsc->lvSize() == 12));
6039+
}
6040+
#endif // FEATURE_SIMD && TARGET_64BIT
6041+
if (varDsc->lvPromoted)
6042+
{
6043+
assert(varDsc->lvDoNotEnregister || varDsc->lvIsMultiRegRet);
60236044
}
60246045
}
60256046
break;
6026-
#endif // TARGET_64BIT
6027-
#endif // SIMD
60286047

60296048
case GT_LCL_VAR_ADDR:
60306049
case GT_LCL_FLD_ADDR:
@@ -6043,6 +6062,8 @@ void Lowering::CheckNode(Compiler* compiler, GenTree* node)
60436062
assert(lclVarAddr->isContained() || !varDsc->lvTracked || varTypeIsStruct(varDsc));
60446063
// TODO: support this assert for uses, see https://github.com/dotnet/runtime/issues/51900.
60456064
}
6065+
6066+
assert(varDsc->lvDoNotEnregister);
60466067
break;
60476068
}
60486069

@@ -6051,6 +6072,16 @@ void Lowering::CheckNode(Compiler* compiler, GenTree* node)
60516072
assert(!"Should not see phi nodes after rationalize");
60526073
break;
60536074

6075+
case GT_LCL_FLD:
6076+
case GT_STORE_LCL_FLD:
6077+
{
6078+
GenTreeLclFld* lclFld = node->AsLclFld();
6079+
const unsigned lclNum = lclFld->GetLclNum();
6080+
const LclVarDsc* varDsc = compiler->lvaGetDesc(lclNum);
6081+
assert(varDsc->lvDoNotEnregister);
6082+
}
6083+
break;
6084+
60546085
default:
60556086
break;
60566087
}

src/coreclr/jit/morph.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3959,6 +3959,7 @@ GenTreeCall* Compiler::fgMorphArgs(GenTreeCall* call)
39593959
{
39603960
// Can't use the existing field's type, so use GT_LCL_FLD to swizzle
39613961
// to a new type
3962+
lvaSetVarDoNotEnregister(lclNum DEBUGARG(DNER_LocalField));
39623963
argObj->ChangeOper(GT_LCL_FLD);
39633964
argObj->gtType = structBaseType;
39643965
}
@@ -3983,6 +3984,7 @@ GenTreeCall* Compiler::fgMorphArgs(GenTreeCall* call)
39833984
else if (genTypeSize(varDsc->TypeGet()) != genTypeSize(structBaseType))
39843985
{
39853986
// Not a promoted struct, so just swizzle the type by using GT_LCL_FLD
3987+
lvaSetVarDoNotEnregister(lclNum DEBUGARG(DNER_LocalField));
39863988
argObj->ChangeOper(GT_LCL_FLD);
39873989
argObj->gtType = structBaseType;
39883990
}

src/coreclr/jit/rationalize.cpp

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -139,7 +139,11 @@ void Rationalizer::RewriteSIMDIndir(LIR::Use& use)
139139
// replace the expression by GT_LCL_VAR or GT_LCL_FLD.
140140
BlockRange().Remove(indir);
141141

142-
var_types lclType = comp->lvaGetDesc(addr->AsLclVar())->TypeGet();
142+
const GenTreeLclVar* lclAddr = addr->AsLclVar();
143+
const unsigned lclNum = lclAddr->GetLclNum();
144+
LclVarDsc* varDsc = comp->lvaGetDesc(lclNum);
145+
146+
var_types lclType = varDsc->TypeGet();
143147

144148
if (lclType == simdType)
145149
{
@@ -156,7 +160,11 @@ void Rationalizer::RewriteSIMDIndir(LIR::Use& use)
156160
addr->gtFlags |= GTF_VAR_USEASG;
157161
}
158162

159-
comp->lvaSetVarDoNotEnregister(addr->AsLclFld()->GetLclNum() DEBUGARG(Compiler::DNER_LocalField));
163+
comp->lvaSetVarDoNotEnregister(lclNum DEBUGARG(Compiler::DNER_LocalField));
164+
}
165+
if (varDsc->lvPromotedStruct())
166+
{
167+
comp->lvaSetVarDoNotEnregister(lclNum DEBUGARG(Compiler::DNER_IsStructArg));
160168
}
161169

162170
addr->gtType = simdType;
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
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+
using System;
4+
using System.Runtime.CompilerServices;
5+
using System.Numerics;
6+
using System.Diagnostics;
7+
8+
namespace Runtime_49489
9+
{
10+
public class Program
11+
{
12+
[MethodImpl(MethodImplOptions.NoInlining)]
13+
static int Callee(float fltRef0, float fltRef1, float fltReg2, float fltReg3, float fltReg4, float fltReg5, float fltReg6, float fltReg7, Vector2 simd8)
14+
{
15+
const double eps = 1E-10;
16+
Debug.Assert(Math.Abs(simd8.X) <= eps);
17+
Debug.Assert(Math.Abs(simd8.Y - 1) <= eps);
18+
return 100;
19+
}
20+
21+
[MethodImpl(MethodImplOptions.NoInlining)]
22+
static int Caller()
23+
{
24+
Vector2 simd8;
25+
simd8.X = 0;
26+
simd8.Y = 1;
27+
return Callee(0, 0, 0, 0, 0, 0, 0, 0, simd8);
28+
29+
}
30+
31+
static int Main(string[] args)
32+
{
33+
return Caller();
34+
}
35+
}
36+
}
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+
<CLRTestPriority>1</CLRTestPriority>
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)