{
for (GenTree* node = newSubListFirst->gtPrev; node != nullptr; node = node->gtPrev)
{
- if ((node->gtFlags & GTF_VAR_DEATH) == 0)
+ if ((node->gtFlags & GTF_VAR_DEATH_MASK) == 0)
{
continue;
}
unsigned lclNum = node->AsLclVarCommon()->GetLclNum();
LclVarDsc* dsc = lvaGetDesc(lclNum);
- // Last-use copy omission does not work for promoted structs today, so
- // we can always unmark these which saves us from having to update the
- // promoted struct death vars map.
- if (dsc->lvPromoted)
- {
- node->gtFlags &= ~GTF_VAR_DEATH;
- continue;
- }
unsigned parentLclNum = dsc->lvIsStructField ? dsc->lvParentLcl : BAD_VAR_NUM;
GenTree* candidate = newSubListFirst;
- // See if a new instance of this local or its parent appeared.
while (true)
{
unsigned newUseLclNum = candidate->AsLclVarCommon()->GetLclNum();
- if ((newUseLclNum == lclNum) || (newUseLclNum == parentLclNum))
+ if (dsc->lvPromoted)
{
- node->gtFlags &= ~GTF_VAR_DEATH;
- break;
+ // Is the parent struct being used?
+ if (newUseLclNum == lclNum)
+ {
+ // Then all fields are not dying.
+ node->gtFlags &= ~GTF_VAR_DEATH_MASK;
+ break;
+ }
+
+ // Otherwise, is one single field being used?
+ if ((newUseLclNum >= dsc->lvFieldLclStart) && (newUseLclNum < dsc->lvFieldLclStart + dsc->lvFieldCnt))
+ {
+ node->ClearLastUse(newUseLclNum - dsc->lvFieldLclStart);
+
+ if ((node->gtFlags & GTF_VAR_DEATH_MASK) == 0)
+ {
+ break;
+ }
+ }
+ }
+ else
+ {
+ // See if a new instance of this local or its parent appeared.
+ if ((newUseLclNum == lclNum) || (newUseLclNum == parentLclNum))
+ {
+ node->gtFlags &= ~GTF_VAR_DEATH;
+ break;
+ }
}
if (candidate == newSubListLast)
// GetLastUseBit: Get the last use bit for regIndex
//
// Arguments:
-// regIndex - the register index
+// fieldIndex - the field index
//
// Return Value:
-// The bit to set, clear or query for the last-use of the regIndex'th value.
+// The bit to set, clear or query for the last-use of the fieldIndex'th value.
//
// Notes:
// This must be a GenTreeLclVar or GenTreeCopyOrReload node.
//
-inline GenTreeFlags GenTree::GetLastUseBit(int regIndex) const
+inline GenTreeFlags GenTree::GetLastUseBit(int fieldIndex) const
{
- assert(regIndex < 4);
+ assert(fieldIndex < 4);
assert(OperIs(GT_LCL_VAR, GT_STORE_LCL_VAR, GT_LCL_VAR_ADDR, GT_LCL_FLD, GT_STORE_LCL_FLD, GT_LCL_FLD_ADDR, GT_COPY,
GT_RELOAD));
static_assert_no_msg((1 << FIELD_LAST_USE_SHIFT) == GTF_VAR_FIELD_DEATH0);
- return (GenTreeFlags)(1 << (FIELD_LAST_USE_SHIFT + regIndex));
+ return (GenTreeFlags)(1 << (FIELD_LAST_USE_SHIFT + fieldIndex));
}
//-----------------------------------------------------------------------------------
//
inline bool GenTree::HasLastUse() const
{
+ assert(OperIs(GT_LCL_VAR, GT_STORE_LCL_VAR, GT_LCL_VAR_ADDR, GT_LCL_FLD, GT_STORE_LCL_FLD, GT_LCL_FLD_ADDR, GT_COPY,
+ GT_RELOAD));
return (gtFlags & (GTF_VAR_DEATH_MASK)) != 0;
}
// SetLastUse: Set the last use bit for the given index
//
// Arguments:
-// regIndex - the index
+// fieldIndex - the index
//
// Notes:
// This must be a GenTreeLclVar or GenTreeCopyOrReload node.
//
-inline void GenTree::SetLastUse(int index)
+inline void GenTree::SetLastUse(int fieldIndex)
{
- gtFlags |= GetLastUseBit(index);
+ gtFlags |= GetLastUseBit(fieldIndex);
}
//-----------------------------------------------------------------------------------
// ClearLastUse: Clear the last use bit for the given index
//
// Arguments:
-// regIndex - the register index
+// fieldIndex - the index
//
// Notes:
// This must be a GenTreeLclVar or GenTreeCopyOrReload node.
//
-inline void GenTree::ClearLastUse(int regIndex)
+inline void GenTree::ClearLastUse(int fieldIndex)
{
- gtFlags &= ~GetLastUseBit(regIndex);
+ gtFlags &= ~GetLastUseBit(fieldIndex);
}
//-------------------------------------------------------------------------