Introduce a notion of state for local var ref counts and weighted ref counts.
Accesses and current state must agree.
State is invalid initially, enabled for an early period around bits of morph,
invalid again for a time, and then enabled normally once lvaMarkRefs is called.
Accesses normally specify RCS_NORMAL as the desired state, but in the accesses
of selected ref counts in morph, specify RCS_EARLY.
Revise how we decide if normal ref counting is active by changing
`lvaLocalVarRefCounted` into a method.
Update `gtIsLikelyRegVar` to not access ref counts when they're not in a valid
state.
Change weight APIs over to use `weight_t`.
gtDispTree(newTree, nullptr, nullptr, true);
}
#endif
- if (lvaLocalVarRefCounted)
+ if (lvaLocalVarRefCounted())
{
lvaTable[lclNum].decRefCnts(compCurBB->getBBWeight(this), this);
}
}
// If global assertion prop, by now we should have ref counts, fix them.
- if (lvaLocalVarRefCounted)
+ if (lvaLocalVarRefCounted())
{
lvaTable[lclNum].decRefCnts(compCurBB->getBBWeight(this), this);
lvaTable[copyLclNum].incRefCnts(compCurBB->getBBWeight(this), this);
// You can test the value of the following variable to see if
// the local variable ref counts must be updated
//
- assert(lvaLocalVarRefCounted == true);
+ assert(lvaLocalVarRefCounted());
if (!opts.MinOpts() && !opts.compDbgCode)
{
typedef JitExpandArray<LclSsaVarDsc> PerSsaArray;
+enum RefCountState
+{
+ RCS_INVALID, // not valid to get/set ref counts
+ RCS_EARLY, // early counts for struct promotion and struct passing
+ RCS_NORMAL, // normal ref counts (from lvaMarkRefs onward)
+};
+
class LclVarDsc
{
public:
// appearance count (computed during address-exposed analysis)
// that fgMakeOutgoingStructArgCopy consults during global morph
// to determine if eliding its copy is legal.
- unsigned m_lvRefCntWtd; // weighted reference count
-
-public:
- unsigned short lvRefCnt() const
- {
- if (lvImplicitlyReferenced && (m_lvRefCnt == 0))
- {
- return 1;
- }
-
- return m_lvRefCnt;
- }
-
- void incLvRefCnt(unsigned short delta)
- {
- unsigned short oldRefCnt = m_lvRefCnt;
- m_lvRefCnt += delta;
- assert(m_lvRefCnt >= oldRefCnt);
- }
-
- void decLvRefCnt(unsigned short delta)
- {
- assert(m_lvRefCnt >= delta);
- m_lvRefCnt -= delta;
- }
-
- void setLvRefCnt(unsigned short newValue)
- {
- m_lvRefCnt = newValue;
- }
-
- unsigned lvRefCntWtd() const
- {
- if (lvImplicitlyReferenced && (m_lvRefCntWtd == 0))
- {
- return BB_UNITY_WEIGHT;
- }
- return m_lvRefCntWtd;
- }
-
- void incLvRefCntWtd(unsigned delta)
- {
- unsigned oldRefCntWtd = m_lvRefCntWtd;
- m_lvRefCntWtd += delta;
- assert(m_lvRefCntWtd >= oldRefCntWtd);
- }
+ BasicBlock::weight_t m_lvRefCntWtd; // weighted reference count
- void decLvRefCntWtd(unsigned delta)
- {
- assert(m_lvRefCntWtd >= delta);
- m_lvRefCntWtd -= delta;
- }
+public:
+ unsigned short lvRefCnt(RefCountState state = RCS_NORMAL) const;
+ void incLvRefCnt(unsigned short delta, RefCountState state = RCS_NORMAL);
+ void decLvRefCnt(unsigned short delta, RefCountState state = RCS_NORMAL);
+ void setLvRefCnt(unsigned short newValue, RefCountState state = RCS_NORMAL);
- void setLvRefCntWtd(unsigned newValue)
- {
- m_lvRefCntWtd = newValue;
- }
+ BasicBlock::weight_t lvRefCntWtd(RefCountState state = RCS_NORMAL) const;
+ void incLvRefCntWtd(BasicBlock::weight_t delta, RefCountState state = RCS_NORMAL);
+ void decLvRefCntWtd(BasicBlock::weight_t delta, RefCountState state = RCS_NORMAL);
+ void setLvRefCntWtd(BasicBlock::weight_t newValue, RefCountState state = RCS_NORMAL);
int lvStkOffs; // stack offset of home
unsigned lvExactSize; // (exact) size of the type in bytes
!(lvIsParam || lvAddrExposed || lvIsStructField);
}
- void lvaResetSortAgainFlag(Compiler* pComp);
- void decRefCnts(BasicBlock::weight_t weight, Compiler* pComp, bool propagate = true);
- void incRefCnts(BasicBlock::weight_t weight, Compiler* pComp, bool propagate = true);
+ void lvaResetSortAgainFlag(Compiler* pComp, RefCountState = RCS_NORMAL);
+ void decRefCnts(BasicBlock::weight_t weight,
+ Compiler* pComp,
+ RefCountState state = RCS_NORMAL,
+ bool propagate = true);
+ void incRefCnts(BasicBlock::weight_t weight,
+ Compiler* pComp,
+ RefCountState state = RCS_NORMAL,
+ bool propagate = true);
void setPrefReg(regNumber regNum, Compiler* pComp);
void addPrefReg(regMaskTP regMask, Compiler* pComp);
bool IsFloatRegType() const
};
public:
- bool lvaRefCountingStarted; // Set to true when we have started counting the local vars
- bool lvaLocalVarRefCounted; // Set to true after we have called lvaMarkLocalVars()
- bool lvaSortAgain; // true: We need to sort the lvaTable
- bool lvaTrackedFixed; // true: We cannot add new 'tracked' variable
- unsigned lvaCount; // total number of locals
+ RefCountState lvaRefCountState; // Current local ref count state
+
+ bool lvaLocalVarRefCounted() const
+ {
+ return lvaRefCountState == RCS_NORMAL;
+ }
+
+ bool lvaSortAgain; // true: We need to sort the lvaTable
+ bool lvaTrackedFixed; // true: We cannot add new 'tracked' variable
+ unsigned lvaCount; // total number of locals
unsigned lvaRefCount; // total number of references to locals
LclVarDsc* lvaTable; // variable descriptor table
* and zero lvRefCntWtd when lvRefCnt is zero
*/
-inline void LclVarDsc::lvaResetSortAgainFlag(Compiler* comp)
+inline void LclVarDsc::lvaResetSortAgainFlag(Compiler* comp, RefCountState state)
{
if (!comp->lvaTrackedFixed)
{
comp->lvaSortAgain = true;
}
/* Set weighted ref count to zero if ref count is zero */
- if (lvRefCnt() == 0)
+ if (lvRefCnt(state) == 0)
{
- setLvRefCntWtd(0);
+ setLvRefCntWtd(0, state);
}
}
* Decrement the ref counts for a local variable
*/
-inline void LclVarDsc::decRefCnts(BasicBlock::weight_t weight, Compiler* comp, bool propagate)
+inline void LclVarDsc::decRefCnts(BasicBlock::weight_t weight, Compiler* comp, RefCountState state, bool propagate)
{
/* Decrement lvRefCnt and lvRefCntWtd */
Compiler::lvaPromotionType promotionType = DUMMY_INIT(Compiler::PROMOTION_TYPE_NONE);
//
if (lvType != TYP_STRUCT || promotionType != Compiler::PROMOTION_TYPE_INDEPENDENT)
{
- assert(lvRefCnt()); // Can't decrement below zero
+ assert(lvRefCnt(state)); // Can't decrement below zero
// TODO: Well, the assert above could be bogus.
// If lvRefCnt has overflowed before, then might drop to 0.
// Therefore we do need the following check to keep lvRefCnt from underflow:
- if (lvRefCnt() > 0)
+ if (lvRefCnt(state) > 0)
{
//
// Decrement lvRefCnt
//
- decLvRefCnt(1);
+ decLvRefCnt(1, state);
//
// Decrement lvRefCntWtd
weight *= 2;
}
- if (lvRefCntWtd() <= weight)
+ if (lvRefCntWtd(state) <= weight)
{ // Can't go below zero
- setLvRefCntWtd(0);
+ setLvRefCntWtd(0, state);
}
else
{
- decLvRefCntWtd(weight);
+ decLvRefCntWtd(weight, state);
}
}
}
{
for (unsigned i = lvFieldLclStart; i < lvFieldLclStart + lvFieldCnt; ++i)
{
- comp->lvaTable[i].decRefCnts(comp->lvaMarkRefsWeight, comp, false); // Don't propagate
+ comp->lvaTable[i].decRefCnts(comp->lvaMarkRefsWeight, comp, state, false); // Don't propagate
}
}
}
assert(!parentvarDsc->lvRegStruct);
if (promotionType == Compiler::PROMOTION_TYPE_DEPENDENT)
{
- parentvarDsc->decRefCnts(comp->lvaMarkRefsWeight, comp, false); // Don't propagate
+ parentvarDsc->decRefCnts(comp->lvaMarkRefsWeight, comp, state, false); // Don't propagate
}
}
- lvaResetSortAgainFlag(comp);
+ lvaResetSortAgainFlag(comp, state);
#ifdef DEBUG
if (comp->verbose)
{
unsigned varNum = (unsigned)(this - comp->lvaTable);
assert(&comp->lvaTable[varNum] == this);
- printf("New refCnts for V%02u: refCnt = %2u, refCntWtd = %s\n", varNum, lvRefCnt(),
- refCntWtd2str(lvRefCntWtd()));
+ printf("New refCnts for V%02u: refCnt = %2u, refCntWtd = %s\n", varNum, lvRefCnt(state),
+ refCntWtd2str(lvRefCntWtd(state)));
}
#endif
}
* Increment the ref counts for a local variable
*/
-inline void LclVarDsc::incRefCnts(BasicBlock::weight_t weight, Compiler* comp, bool propagate)
+inline void LclVarDsc::incRefCnts(BasicBlock::weight_t weight, Compiler* comp, RefCountState state, bool propagate)
{
Compiler::lvaPromotionType promotionType = DUMMY_INIT(Compiler::PROMOTION_TYPE_NONE);
if (varTypeIsStruct(lvType))
//
// Increment lvRefCnt
//
- int newRefCnt = lvRefCnt() + 1;
+ int newRefCnt = lvRefCnt(state) + 1;
if (newRefCnt == (unsigned short)newRefCnt) // lvRefCnt is an "unsigned short". Don't overflow it.
{
- setLvRefCnt((unsigned short)newRefCnt);
+ setLvRefCnt((unsigned short)newRefCnt, state);
}
// This fires when an uninitialize value for 'weight' is used (see lvaMarkRefsWeight)
weight *= 2;
}
- unsigned newWeight = lvRefCntWtd() + weight;
- if (newWeight >= lvRefCntWtd())
+ unsigned newWeight = lvRefCntWtd(state) + weight;
+ if (newWeight >= lvRefCntWtd(state))
{ // lvRefCntWtd is an "unsigned". Don't overflow it
- setLvRefCntWtd(newWeight);
+ setLvRefCntWtd(newWeight, state);
}
else
{ // On overflow we assign ULONG_MAX
- setLvRefCntWtd(ULONG_MAX);
+ setLvRefCntWtd(ULONG_MAX, state);
}
}
}
{
for (unsigned i = lvFieldLclStart; i < lvFieldLclStart + lvFieldCnt; ++i)
{
- comp->lvaTable[i].incRefCnts(comp->lvaMarkRefsWeight, comp, false); // Don't propagate
+ comp->lvaTable[i].incRefCnts(comp->lvaMarkRefsWeight, comp, state, false); // Don't propagate
}
}
}
assert(!parentvarDsc->lvRegStruct);
if (promotionType == Compiler::PROMOTION_TYPE_DEPENDENT)
{
- parentvarDsc->incRefCnts(comp->lvaMarkRefsWeight, comp, false); // Don't propagate
+ parentvarDsc->incRefCnts(comp->lvaMarkRefsWeight, comp, state, false); // Don't propagate
}
}
- lvaResetSortAgainFlag(comp);
+ lvaResetSortAgainFlag(comp, state);
#ifdef DEBUG
if (comp->verbose)
{
unsigned varNum = (unsigned)(this - comp->lvaTable);
assert(&comp->lvaTable[varNum] == this);
- printf("New refCnts for V%02u: refCnt = %2u, refCntWtd = %s\n", varNum, lvRefCnt(),
- refCntWtd2str(lvRefCntWtd()));
+ printf("New refCnts for V%02u: refCnt = %2u, refCntWtd = %s\n", varNum, lvRefCnt(state),
+ refCntWtd2str(lvRefCntWtd(state)));
}
#endif
}
#endif
}
+//------------------------------------------------------------------------------
+// lvRefCnt: access reference count for this local var
+//
+// Arguments:
+// state: the requestor's expected ref count state; defaults to RCS_NORMAL
+//
+// Return Value:
+// Ref count for the local.
+
+inline unsigned short LclVarDsc::lvRefCnt(RefCountState state) const
+{
+
+#if defined(DEBUG)
+ assert(state != RCS_INVALID);
+ Compiler* compiler = JitTls::GetCompiler();
+ assert(compiler->lvaRefCountState == state);
+#endif
+
+ if (lvImplicitlyReferenced && (m_lvRefCnt == 0))
+ {
+ return 1;
+ }
+
+ return m_lvRefCnt;
+}
+
+//------------------------------------------------------------------------------
+// incLvRefCnt: increment reference count for this local var
+//
+// Arguments:
+// delta: the amount of the increment
+// state: the requestor's expected ref count state; defaults to RCS_NORMAL
+//
+// Notes:
+// It is currently the caller's responsibilty to ensure this increment
+// will not cause overflow.
+
+inline void LclVarDsc::incLvRefCnt(unsigned short delta, RefCountState state)
+{
+
+#if defined(DEBUG)
+ assert(state != RCS_INVALID);
+ Compiler* compiler = JitTls::GetCompiler();
+ assert(compiler->lvaRefCountState == state);
+#endif
+
+ unsigned short oldRefCnt = m_lvRefCnt;
+ m_lvRefCnt += delta;
+ assert(m_lvRefCnt >= oldRefCnt);
+}
+
+//------------------------------------------------------------------------------
+// decLvRefCnt: decrement reference count for this local var
+//
+// Arguments:
+// delta: the amount of the decrement
+// state: the requestor's expected ref count state; defaults to RCS_NORMAL
+//
+// Notes:
+// It is currently the caller's responsibilty to ensure this decrement
+// will not cause underflow.
+
+inline void LclVarDsc::decLvRefCnt(unsigned short delta, RefCountState state)
+{
+
+#if defined(DEBUG)
+ assert(state != RCS_INVALID);
+ Compiler* compiler = JitTls::GetCompiler();
+ assert(compiler->lvaRefCountState == state);
+#endif
+
+ assert(m_lvRefCnt >= delta);
+ m_lvRefCnt -= delta;
+}
+
+//------------------------------------------------------------------------------
+// setLvRefCnt: set the reference count for this local var
+//
+// Arguments:
+// newValue: the desired new reference count
+// state: the requestor's expected ref count state; defaults to RCS_NORMAL
+//
+// Notes:
+// Generally after calling v->setLvRefCnt(Y), v->lvRefCnt() == Y.
+// However this may not be true when v->lvImplicitlyReferenced == 1.
+
+inline void LclVarDsc::setLvRefCnt(unsigned short newValue, RefCountState state)
+{
+
+#if defined(DEBUG)
+ assert(state != RCS_INVALID);
+ Compiler* compiler = JitTls::GetCompiler();
+ assert(compiler->lvaRefCountState == state);
+#endif
+
+ m_lvRefCnt = newValue;
+}
+
+//------------------------------------------------------------------------------
+// lvRefCntWtd: access wighted reference count for this local var
+//
+// Arguments:
+// state: the requestor's expected ref count state; defaults to RCS_NORMAL
+//
+// Return Value:
+// Weighted ref count for the local.
+
+inline BasicBlock::weight_t LclVarDsc::lvRefCntWtd(RefCountState state) const
+{
+
+#if defined(DEBUG)
+ assert(state != RCS_INVALID);
+ Compiler* compiler = JitTls::GetCompiler();
+ assert(compiler->lvaRefCountState == state);
+#endif
+
+ if (lvImplicitlyReferenced && (m_lvRefCntWtd == 0))
+ {
+ return BB_UNITY_WEIGHT;
+ }
+
+ return m_lvRefCntWtd;
+}
+
+//------------------------------------------------------------------------------
+// incLvRefCntWtd: increment weighted reference count for this local var
+//
+// Arguments:
+// delta: the amount of the increment
+// state: the requestor's expected ref count state; defaults to RCS_NORMAL
+//
+// Notes:
+// It is currently the caller's responsibilty to ensure this increment
+// will not cause overflow.
+
+inline void LclVarDsc::incLvRefCntWtd(BasicBlock::weight_t delta, RefCountState state)
+{
+
+#if defined(DEBUG)
+ assert(state != RCS_INVALID);
+ Compiler* compiler = JitTls::GetCompiler();
+ assert(compiler->lvaRefCountState == state);
+#endif
+
+ BasicBlock::weight_t oldRefCntWtd = m_lvRefCntWtd;
+ m_lvRefCntWtd += delta;
+ assert(m_lvRefCntWtd >= oldRefCntWtd);
+}
+
+//------------------------------------------------------------------------------
+// decLvRefCntWtd: decrement weighted reference count for this local var
+//
+// Arguments:
+// delta: the amount of the decrement
+// state: the requestor's expected ref count state; defaults to RCS_NORMAL
+//
+// Notes:
+// It is currently the caller's responsibilty to ensure this decrement
+// will not cause underflow.
+
+inline void LclVarDsc::decLvRefCntWtd(BasicBlock::weight_t delta, RefCountState state)
+{
+
+#if defined(DEBUG)
+ assert(state != RCS_INVALID);
+ Compiler* compiler = JitTls::GetCompiler();
+ assert(compiler->lvaRefCountState == state);
+#endif
+
+ assert(m_lvRefCntWtd >= delta);
+ m_lvRefCntWtd -= delta;
+}
+
+//------------------------------------------------------------------------------
+// setLvRefCntWtd: set the weighted reference count for this local var
+//
+// Arguments:
+// newValue: the desired new weighted reference count
+// state: the requestor's expected ref count state; defaults to RCS_NORMAL
+//
+// Notes:
+// Generally after calling v->setLvRefCntWtd(Y), v->lvRefCntWtd() == Y.
+// However this may not be true when v->lvImplicitlyReferenced == 1.
+
+inline void LclVarDsc::setLvRefCntWtd(BasicBlock::weight_t newValue, RefCountState state)
+{
+
+#if defined(DEBUG)
+ assert(state != RCS_INVALID);
+ Compiler* compiler = JitTls::GetCompiler();
+ assert(compiler->lvaRefCountState == state);
+#endif
+
+ m_lvRefCntWtd = newValue;
+}
+
/*****************************************************************************/
#endif //_COMPILER_HPP_
/*****************************************************************************/
{
assert(clonedTree->gtOper != GT_STMT);
- if (lvaLocalVarRefCounted)
+ if (lvaLocalVarRefCounted())
{
compCurBB = addedToBlock;
IncLclVarRefCountsVisitor::WalkTree(this, clonedTree);
void Compiler::fgUpdateRefCntForExtract(GenTree* wholeTree, GenTree* keptTree)
{
- if (lvaLocalVarRefCounted)
+ if (lvaLocalVarRefCounted())
{
/* Update the refCnts of removed lcl vars - The problem is that
* we have to consider back the side effects trees so we first
return false;
}
+ // Be pessimistic if ref counts are not yet set up.
+ //
+ // Perhaps we should be optimistic though.
+ // See notes in GitHub issue 18969.
+ if (!lvaLocalVarRefCounted())
+ {
+ return false;
+ }
+
if (varDsc->lvRefCntWtd() < (BB_UNITY_WEIGHT * 3))
{
return false;
cons->gtNext = tree->gtNext;
cons->gtPrev = tree->gtPrev;
}
- if (lvaLocalVarRefCounted)
+ if (lvaLocalVarRefCounted())
{
lvaRecursiveDecRefCounts(tree);
}
/* Multiply by zero - return the 'zero' node, but not if side effects */
if (!(op->gtFlags & GTF_SIDE_EFFECT))
{
- if (lvaLocalVarRefCounted)
+ if (lvaLocalVarRefCounted())
{
lvaRecursiveDecRefCounts(op);
}
if (!(op->gtFlags & GTF_SIDE_EFFECT))
{
- if (lvaLocalVarRefCounted)
+ if (lvaLocalVarRefCounted())
{
lvaRecursiveDecRefCounts(op);
}
if (!(op->gtFlags & GTF_SIDE_EFFECT))
{
- if (lvaLocalVarRefCounted)
+ if (lvaLocalVarRefCounted())
{
lvaRecursiveDecRefCounts(op);
}
}
else if (!(op->gtFlags & GTF_SIDE_EFFECT))
{
- if (lvaLocalVarRefCounted)
+ if (lvaLocalVarRefCounted())
{
lvaRecursiveDecRefCounts(op);
}
op = op2->AsColon()->ElseNode();
opToDelete = op2->AsColon()->ThenNode();
}
- if (lvaLocalVarRefCounted)
+ if (lvaLocalVarRefCounted())
{
lvaRecursiveDecRefCounts(opToDelete);
}
void Compiler::lvaInit()
{
/* We haven't allocated stack variables yet */
- lvaRefCountingStarted = false;
- lvaLocalVarRefCounted = false;
+ lvaRefCountState = RCS_INVALID;
lvaGenericsContextUseCount = 0;
}
#endif // FEATURE_MULTIREG_ARGS && defined(FEATURE_SIMD)
- lvaMarkRefsWeight = BB_UNITY_WEIGHT; // incRefCnts can use this compiler global variable
- fieldVarDsc->incRefCnts(BB_UNITY_WEIGHT, this); // increment the ref count for prolog initialization
+ lvaMarkRefsWeight = BB_UNITY_WEIGHT; // incRefCnts can use this compiler global variable
+ fieldVarDsc->incRefCnts(BB_UNITY_WEIGHT, this,
+ RCS_EARLY); // increment the ref count for prolog initialization
}
#endif
// Decrement the ref counts for all locals contained in the tree and its children.
void Compiler::lvaRecursiveDecRefCounts(GenTree* tree)
{
- assert(lvaLocalVarRefCounted);
+ assert(lvaLocalVarRefCounted());
// We could just use the recursive walker for all cases but that is a
// fairly heavyweight thing to spin up when we're usually just handling a leaf.
unsigned lclNum;
LclVarDsc* varDsc;
- noway_assert(lvaRefCountingStarted || lvaLocalVarRefCounted);
+ noway_assert(lvaLocalVarRefCounted());
if ((tree->gtOper == GT_CALL) && (tree->gtFlags & GTF_CALL_UNMANAGED))
{
// Increment the ref counts for all locals contained in the tree and its children.
void Compiler::lvaRecursiveIncRefCounts(GenTree* tree)
{
- assert(lvaLocalVarRefCounted);
+ assert(lvaLocalVarRefCounted());
// We could just use the recursive walker for all cases but that is a
// fairly heavyweight thing to spin up when we're usually just handling a leaf.
unsigned lclNum;
LclVarDsc* varDsc;
- noway_assert(lvaRefCountingStarted || lvaLocalVarRefCounted);
+ noway_assert(lvaLocalVarRefCounted());
if ((tree->gtOper == GT_CALL) && (tree->gtFlags & GTF_CALL_UNMANAGED))
{
}
}
- /* Mark all local variable references */
+ // Ref counting is now enabled normally.
+ lvaRefCountState = RCS_NORMAL;
- lvaRefCountingStarted = true;
+ /* Mark all local variable references */
for (block = fgFirstBB; block; block = block->bbNext)
{
lvaMarkLocalVars(block);
lvaTable[info.compTypeCtxtArg].lvImplicitlyReferenced = 1;
}
- lvaLocalVarRefCounted = true;
- lvaRefCountingStarted = false;
-
lvaSortByRefCount();
}
if (tree->IsLocal())
{
auto result = gtClone(tree);
- if (lvaLocalVarRefCounted)
+ if (lvaLocalVarRefCounted())
{
lvaTable[tree->gtLclVarCommon.gtLclNum].incRefCnts(compCurBB->getBBWeight(this), this);
}
// At this point, *pOp is GT_COMMA(GT_ASG(V01, *pOp), V01) and result = V01
// Therefore, the ref count has to be incremented 3 times for *pOp and result, if result will
// be added by the caller.
- if (lvaLocalVarRefCounted)
+ if (lvaLocalVarRefCounted())
{
lvaTable[result->gtLclVarCommon.gtLclNum].incRefCnts(compCurBB->getBBWeight(this), this);
lvaTable[result->gtLclVarCommon.gtLclNum].incRefCnts(compCurBB->getBBWeight(this), this);
// on the caller's frame. If an argument lives on the caller caller's frame, it may get
// overwritten if that frame is reused for the tail call. Therefore, we should always copy
// struct parameters if they are passed as arguments to a tail call.
- if (!call->IsTailCallViaHelper() && (varDsc->lvRefCnt() == 1) && !fgMightHaveLoop())
+ if (!call->IsTailCallViaHelper() && (varDsc->lvRefCnt(RCS_EARLY) == 1) && !fgMightHaveLoop())
{
- varDsc->setLvRefCnt(0);
+ varDsc->setLvRefCnt(0, RCS_EARLY);
args->gtOp.gtOp1 = lcl;
fp->node = lcl;
bndsChk = arrBndsChk;
// Make sure to increment ref-counts if already ref-counted.
- if (lvaLocalVarRefCounted)
+ if (lvaLocalVarRefCounted())
{
lvaRecursiveIncRefCounts(index);
lvaRecursiveIncRefCounts(arrRef);
else
{
/* The left operand is worthless, throw it away */
- if (lvaLocalVarRefCounted)
+ if (lvaLocalVarRefCounted())
{
lvaRecursiveDecRefCounts(op1);
}
{
numerator = fgMakeMultiUse(&tree->gtOp1);
}
- else if (lvaLocalVarRefCounted && numerator->OperIsLocal())
+ else if (lvaLocalVarRefCounted() && numerator->OperIsLocal())
{
// Morphing introduces new lclVar references. Increase ref counts
lvaIncRefCnts(numerator);
{
denominator = fgMakeMultiUse(&tree->gtOp2);
}
- else if (lvaLocalVarRefCounted && denominator->OperIsLocal())
+ else if (lvaLocalVarRefCounted() && denominator->OperIsLocal())
{
// Morphing introduces new lclVar references. Increase ref counts
lvaIncRefCnts(denominator);
stmt->gtStmtExpr = morph;
- if (lvaLocalVarRefCounted)
+ if (lvaLocalVarRefCounted())
{
// fgMorphTree may have introduced new lclVar references. Bump the ref counts if requested.
lvaRecursiveIncRefCounts(stmt->gtStmtExpr);
fgUpdateFinallyTargetFlags();
/* For x64 and ARM64 we need to mark irregular parameters */
+
+ lvaRefCountState = RCS_EARLY;
fgMarkImplicitByRefArgs();
/* Promote struct locals if necessary */
/* Fix any LclVar annotations on discarded struct promotion temps for implicit by-ref args */
fgMarkDemotedImplicitByRefArgs();
+ lvaRefCountState = RCS_INVALID;
EndPhase(PHASE_MORPH_GLOBAL);
// chance, so have to check now.
JITDUMP(
"Incrementing ref count from %d to %d for V%02d in fgMorphStructField for promoted struct\n",
- varDsc->lvRefCnt(), varDsc->lvRefCnt() + 1, lclNum);
- varDsc->incLvRefCnt(1);
+ varDsc->lvRefCnt(RCS_EARLY), varDsc->lvRefCnt(RCS_EARLY) + 1, lclNum);
+ varDsc->incLvRefCnt(1, RCS_EARLY);
}
tree->SetOper(GT_LCL_VAR);
// lclVars, but here we're about to return SKIP_SUBTREES and rob it of the
// chance, so have to check now.
JITDUMP("Incrementing ref count from %d to %d for V%02d in fgMorphStructField for normed struct\n",
- varDsc->lvRefCnt(), varDsc->lvRefCnt() + 1, lclNum);
- varDsc->incLvRefCnt(1);
+ varDsc->lvRefCnt(RCS_EARLY), varDsc->lvRefCnt(RCS_EARLY) + 1, lclNum);
+ varDsc->incLvRefCnt(1, RCS_EARLY);
}
tree->ChangeOper(GT_LCL_VAR);
// appearance of implicit-by-ref param so that call arg morphing can do an
// optimization for single-use implicit-by-ref params whose single use is as
// an outgoing call argument.
- varDsc->setLvRefCnt(0);
+ varDsc->setLvRefCnt(0, RCS_EARLY);
}
}
}
// parameter if it weren't promoted at all (otherwise the initialization
// of the new temp would just be a needless memcpy at method entry).
bool undoPromotion = (lvaGetPromotionType(newVarDsc) == PROMOTION_TYPE_DEPENDENT) ||
- (varDsc->lvRefCnt() <= varDsc->lvFieldCnt);
+ (varDsc->lvRefCnt(RCS_EARLY) <= varDsc->lvFieldCnt);
if (!undoPromotion)
{
// to the implicit byref parameter when morphing calls that pass the implicit byref
// out as an outgoing argument value, but that doesn't pertain to this field local
// which is now a field of a non-arg local.
- fieldVarDsc->setLvRefCnt(0);
+ fieldVarDsc->setLvRefCnt(0, RCS_EARLY);
}
fieldVarDsc->lvIsParam = false;
// call morphing could identify single-use implicit byrefs; we're done with
// that, and want it to be in its default state of zero when we go to set
// real ref counts for all variables.
- varDsc->setLvRefCnt(0);
+ varDsc->setLvRefCnt(0, RCS_EARLY);
// The temp struct is now unused; set flags appropriately so that we
// won't allocate space for it on the stack.
LclVarDsc* structVarDsc = &lvaTable[structLclNum];
- structVarDsc->setLvRefCnt(0);
+ structVarDsc->setLvRefCnt(0, RCS_EARLY);
structVarDsc->lvAddrExposed = false;
#ifdef DEBUG
structVarDsc->lvUnusedStruct = true;
// The field local is now unused; set flags appropriately so that
// we won't allocate stack space for it.
- fieldVarDsc->setLvRefCnt(0);
+ fieldVarDsc->setLvRefCnt(0, RCS_EARLY);
fieldVarDsc->lvAddrExposed = false;
}
}
// checks the ref counts for implicit byref params when deciding if it's legal
// to elide certain copies of them.
LclVarDsc* varDsc = &comp->lvaTable[lclNum];
- JITDUMP("Incrementing ref count from %d to %d for V%02d in fgMorphStructField\n", varDsc->lvRefCnt(),
- varDsc->lvRefCnt() + 1, lclNum);
+ JITDUMP("Incrementing ref count from %d to %d for V%02d in fgMorphStructField\n",
+ varDsc->lvRefCnt(RCS_EARLY), varDsc->lvRefCnt(RCS_EARLY) + 1, lclNum);
- varDsc->incLvRefCnt(1);
+ varDsc->incLvRefCnt(1, RCS_EARLY);
}
// This recognizes certain forms, and does all the work. In that case, returns WALK_SKIP_SUBTREES,
// else WALK_CONTINUE. We do the same here.
// byref (here during address-exposed analysis); fgMakeOutgoingStructArgCopy
// checks the ref counts for implicit byref params when deciding if it's legal
// to elide certain copies of them.
- JITDUMP("Incrementing ref count from %d to %d for V%02d in fgMorphStructField\n", varDsc->lvRefCnt(),
- varDsc->lvRefCnt() + 1, lclNum);
+ JITDUMP("Incrementing ref count from %d to %d for V%02d in fgMorphStructField\n",
+ varDsc->lvRefCnt(RCS_EARLY), varDsc->lvRefCnt(RCS_EARLY) + 1, lclNum);
- varDsc->incLvRefCnt(1);
+ varDsc->incLvRefCnt(1, RCS_EARLY);
}
if (axc == AXC_Addr || axc == AXC_AddrWide)
// Look for any local variable references
- if (tree->gtOper == GT_LCL_VAR && comp->lvaLocalVarRefCounted)
+ if (tree->gtOper == GT_LCL_VAR && comp->lvaLocalVarRefCounted())
{
unsigned lclNum;
LclVarDsc* varDsc;