Skip to content

Commit fdb7415

Browse files
authored
JIT: Extend USEASG liveness to cover partial writes to retbufs (#105996)
Liveness will add uses for explicit USEASG local stores that are not dead, but not for similar stores to locals via calls. Extend the coverage to calls. Fixes #105667.
1 parent 4783909 commit fdb7415

File tree

2 files changed

+45
-30
lines changed

2 files changed

+45
-30
lines changed

src/coreclr/jit/compiler.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5591,7 +5591,7 @@ class Compiler
55915591

55925592
void fgLiveVarAnalysis();
55935593

5594-
void fgComputeLifeCall(VARSET_TP& life, VARSET_VALARG_TP keepAliveVars, GenTreeCall* call);
5594+
GenTreeLclVarCommon* fgComputeLifeCall(VARSET_TP& life, VARSET_VALARG_TP keepAliveVars, GenTreeCall* call);
55955595

55965596
void fgComputeLifeTrackedLocalUse(VARSET_TP& life, LclVarDsc& varDsc, GenTreeLclVarCommon* node);
55975597
bool fgComputeLifeTrackedLocalDef(VARSET_TP& life,

src/coreclr/jit/liveness.cpp

Lines changed: 44 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -772,9 +772,13 @@ void Compiler::fgLiveVarAnalysis()
772772
// keepAliveVars - Tracked locals that must be kept alive everywhere in the block
773773
// call - The call node in question.
774774
//
775-
void Compiler::fgComputeLifeCall(VARSET_TP& life, VARSET_VALARG_TP keepAliveVars, GenTreeCall* call)
775+
// Returns:
776+
// local defined by the call, if any (eg retbuf)
777+
//
778+
GenTreeLclVarCommon* Compiler::fgComputeLifeCall(VARSET_TP& life, VARSET_VALARG_TP keepAliveVars, GenTreeCall* call)
776779
{
777780
assert(call != nullptr);
781+
GenTreeLclVarCommon* definedLcl = nullptr;
778782

779783
// If this is a tail-call via helper, and we have any unmanaged p/invoke calls in
780784
// the method, then we're going to run the p/invoke epilog
@@ -834,11 +838,13 @@ void Compiler::fgComputeLifeCall(VARSET_TP& life, VARSET_VALARG_TP keepAliveVars
834838
}
835839
}
836840

837-
GenTreeLclVarCommon* definedLcl = gtCallGetDefinedRetBufLclAddr(call);
841+
definedLcl = gtCallGetDefinedRetBufLclAddr(call);
838842
if (definedLcl != nullptr)
839843
{
840844
fgComputeLifeLocal(life, keepAliveVars, definedLcl);
841845
}
846+
847+
return definedLcl;
842848
}
843849

844850
//------------------------------------------------------------------------
@@ -1171,54 +1177,63 @@ void Compiler::fgComputeLife(VARSET_TP& life,
11711177
AGAIN:
11721178
assert(tree->OperGet() != GT_QMARK);
11731179

1180+
bool isUse = false;
1181+
bool doAgain = false;
1182+
bool storeRemoved = false;
1183+
LclVarDsc* varDsc = nullptr;
1184+
11741185
if (tree->IsCall())
11751186
{
1176-
fgComputeLifeCall(life, keepAliveVars, tree->AsCall());
1187+
GenTreeLclVarCommon* const definedLcl = fgComputeLifeCall(life, keepAliveVars, tree->AsCall());
1188+
if (definedLcl != nullptr)
1189+
{
1190+
isUse = (definedLcl->gtFlags & GTF_VAR_USEASG) != 0;
1191+
varDsc = lvaGetDesc(definedLcl);
1192+
}
11771193
}
11781194
else if (tree->OperIsNonPhiLocal())
11791195
{
1196+
isUse = (tree->gtFlags & GTF_VAR_USEASG) != 0;
11801197
bool isDeadStore = fgComputeLifeLocal(life, keepAliveVars, tree);
11811198
if (isDeadStore)
11821199
{
1183-
LclVarDsc* varDsc = lvaGetDesc(tree->AsLclVarCommon());
1184-
bool isUse = (tree->gtFlags & GTF_VAR_USEASG) != 0;
1185-
bool doAgain = false;
1186-
bool storeRemoved = false;
1200+
varDsc = lvaGetDesc(tree->AsLclVarCommon());
11871201

11881202
if (fgRemoveDeadStore(&tree, varDsc, life, &doAgain, pStmtInfoDirty, &storeRemoved DEBUGARG(treeModf)))
11891203
{
11901204
assert(!doAgain);
11911205
break;
11921206
}
1207+
}
1208+
}
11931209

1194-
if (isUse && !storeRemoved)
1210+
// SSA and VN treat "partial definitions" as true uses, so for this
1211+
// front-end liveness pass we must add them to the live set in case
1212+
// we failed to remove the dead store.
1213+
//
1214+
if ((varDsc != nullptr) && isUse && !storeRemoved)
1215+
{
1216+
if (varDsc->lvTracked)
1217+
{
1218+
VarSetOps::AddElemD(this, life, varDsc->lvVarIndex);
1219+
}
1220+
if (varDsc->lvPromoted)
1221+
{
1222+
for (unsigned fieldIndex = 0; fieldIndex < varDsc->lvFieldCnt; fieldIndex++)
11951223
{
1196-
// SSA and VN treat "partial definitions" as true uses, so for this
1197-
// front-end liveness pass we must add them to the live set in case
1198-
// we failed to remove the dead store.
1199-
if (varDsc->lvTracked)
1200-
{
1201-
VarSetOps::AddElemD(this, life, varDsc->lvVarIndex);
1202-
}
1203-
if (varDsc->lvPromoted)
1224+
LclVarDsc* fieldVarDsc = lvaGetDesc(varDsc->lvFieldLclStart + fieldIndex);
1225+
if (fieldVarDsc->lvTracked)
12041226
{
1205-
for (unsigned fieldIndex = 0; fieldIndex < varDsc->lvFieldCnt; fieldIndex++)
1206-
{
1207-
LclVarDsc* fieldVarDsc = lvaGetDesc(varDsc->lvFieldLclStart + fieldIndex);
1208-
if (fieldVarDsc->lvTracked)
1209-
{
1210-
VarSetOps::AddElemD(this, life, fieldVarDsc->lvVarIndex);
1211-
}
1212-
}
1227+
VarSetOps::AddElemD(this, life, fieldVarDsc->lvVarIndex);
12131228
}
12141229
}
1215-
1216-
if (doAgain)
1217-
{
1218-
goto AGAIN;
1219-
}
12201230
}
12211231
}
1232+
1233+
if (doAgain)
1234+
{
1235+
goto AGAIN;
1236+
}
12221237
}
12231238
}
12241239

0 commit comments

Comments
 (0)