Skip to content

Commit edd6d63

Browse files
authored
JIT: Fix liveness for partial defs of parent locals (#85654)
Partial defs in liveness are modelled as full uses of all fields and then a full def of the entire local. The logic that handled fields directly got that right, but the logic that handled parent locals did not. For example, for IR like ``` ------------ BB18 [045..046), preds={BB16} succs={BB19} ***** BB18 STMT00096 ( INL10 @ 0x01F[E-] ... ??? ) <- INL04 @ ??? <- INLRT @ 0x045[E-] N003 ( 5, 4) [000403] -A------R-- ▌ ASG byref N002 ( 3, 2) [000402] D------N--- ├──▌ LCL_VAR byref V73 tmp45 N001 ( 1, 1) [000401] ----------- └──▌ LCL_VAR long V43 tmp15 ***** BB18 STMT00097 ( INL10 @ 0x026[E-] ... ??? ) <- INL04 @ ??? <- INLRT @ 0x045[E-] N003 ( 5, 4) [000407] -A------R-- ▌ ASG int N002 ( 3, 2) [000406] D------N--- ├──▌ LCL_VAR int V74 tmp46 N001 ( 1, 1) [000405] ----------- └──▌ LCL_VAR int V42 tmp14 ***** BB18 STMT00072 ( INL04 @ 0x073[--] ... ??? ) <- INLRT @ 0x045[E-] N007 ( 14, 14) [000627] -A--------- ▌ COMMA void N003 ( 7, 7) [000623] -A------R-- ├──▌ ASG byref N002 ( 3, 4) [000621] U------N--- │ ├──▌ LCL_FLD byref (P) V12 loc3 [+16] │ ├──▌ ref field V12._managedArray (fldOffset=0x0) -> V57 tmp29 │ ├──▌ long field V12._allocatedMemory (fldOffset=0x8) -> V58 tmp30 │ ├──▌ byref field V12._reference (fldOffset=0x10) -> V59 tmp31 │ ├──▌ int field V12._length (fldOffset=0x18) -> V60 tmp32 N001 ( 3, 2) [000622] ----------- │ └──▌ LCL_VAR byref V73 tmp45 N006 ( 7, 7) [000626] -A------R-- └──▌ ASG int N005 ( 3, 4) [000624] U------N--- ├──▌ LCL_FLD int (P) V12 loc3 [+24] ├──▌ ref field V12._managedArray (fldOffset=0x0) -> V57 tmp29 ├──▌ long field V12._allocatedMemory (fldOffset=0x8) -> V58 tmp30 ├──▌ byref field V12._reference (fldOffset=0x10) -> V59 tmp31 ├──▌ int field V12._length (fldOffset=0x18) -> V60 tmp32 N004 ( 3, 2) [000625] ----------- └──▌ LCL_VAR int V74 tmp46 ``` we would see ``` BB18 USE(6)={V58 V57 V59 V60 V42 V43 } DEF(2)={ V73 V74} ``` which is obviously incorrect as V57-V60 are all defined under this model. This would lead to an assert in SSA since SSA did treat this as a def.
1 parent fc22ee9 commit edd6d63

File tree

1 file changed

+12
-17
lines changed

1 file changed

+12
-17
lines changed

src/coreclr/jit/liveness.cpp

Lines changed: 12 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -93,28 +93,23 @@ void Compiler::fgMarkUseDef(GenTreeLclVarCommon* tree)
9393

9494
if (promotionType != PROMOTION_TYPE_NONE)
9595
{
96-
VARSET_TP bitMask(VarSetOps::MakeEmpty(this));
97-
9896
for (unsigned i = varDsc->lvFieldLclStart; i < varDsc->lvFieldLclStart + varDsc->lvFieldCnt; ++i)
9997
{
100-
noway_assert(lvaTable[i].lvIsStructField);
101-
if (lvaTable[i].lvTracked)
98+
if (!lvaTable[i].lvTracked)
10299
{
103-
noway_assert(lvaTable[i].lvVarIndex < lvaTrackedCount);
104-
VarSetOps::AddElemD(this, bitMask, lvaTable[i].lvVarIndex);
100+
continue;
105101
}
106-
}
107102

108-
// For pure defs (i.e. not an "update" def which is also a use), add to the (all) def set.
109-
if (!isUse)
110-
{
111-
assert(isDef);
112-
VarSetOps::UnionD(this, fgCurDefSet, bitMask);
113-
}
114-
else if (!VarSetOps::IsSubset(this, bitMask, fgCurDefSet))
115-
{
116-
// Mark as used any struct fields that are not yet defined.
117-
VarSetOps::UnionD(this, fgCurUseSet, bitMask);
103+
unsigned varIndex = lvaTable[i].lvVarIndex;
104+
if (isUse && !VarSetOps::IsMember(this, fgCurDefSet, varIndex))
105+
{
106+
VarSetOps::AddElemD(this, fgCurUseSet, varIndex);
107+
}
108+
109+
if (isDef)
110+
{
111+
VarSetOps::AddElemD(this, fgCurDefSet, varIndex);
112+
}
118113
}
119114
}
120115
}

0 commit comments

Comments
 (0)