From 895bfa452da4aeeda52447e76d9e9e987d68f331 Mon Sep 17 00:00:00 2001 From: Andy Ayers Date: Mon, 20 Aug 2018 15:03:29 -0700 Subject: JIT: remove incremental ref count updates (#19345) Remove almost all of the code in the jit that tries to maintain local ref counts incrementally. Also remove `lvaSortAgain` and related machinery. Explicitly sort locals before post-lower-liveness when optimizing to get the best set of tracked locals. Explicitly recount after post-lower liveness to get accurate counts after dead stores. This can lead to tracked unreferenced arguments; tolerate this during codegen. --- src/jit/assertionprop.cpp | 43 +-------- src/jit/codegencommon.cpp | 7 +- src/jit/compiler.cpp | 3 +- src/jit/compiler.h | 21 +--- src/jit/compiler.hpp | 184 +++-------------------------------- src/jit/copyprop.cpp | 2 - src/jit/decomposelongs.cpp | 43 +-------- src/jit/earlyprop.cpp | 2 - src/jit/flowgraph.cpp | 56 +---------- src/jit/gentree.cpp | 28 +----- src/jit/lclvars.cpp | 234 +++++---------------------------------------- src/jit/lir.cpp | 35 +------ src/jit/liveness.cpp | 32 ++----- src/jit/lower.cpp | 62 ++---------- src/jit/morph.cpp | 83 ++-------------- src/jit/optcse.cpp | 37 +------ src/jit/optimizer.cpp | 40 +------- src/jit/rationalize.cpp | 1 - src/jit/regalloc.cpp | 11 ++- 19 files changed, 89 insertions(+), 835 deletions(-) diff --git a/src/jit/assertionprop.cpp b/src/jit/assertionprop.cpp index d4153a287e..0cc35a9ceb 100644 --- a/src/jit/assertionprop.cpp +++ b/src/jit/assertionprop.cpp @@ -430,12 +430,6 @@ void Compiler::optAddCopies() { stmt = fgInsertStmtNearEnd(bestBlock, copyAsgn); } - - /* Increment its lvRefCnt and lvRefCntWtd */ - lvaTable[lclNum].incRefCnts(fgFirstBB->getBBWeight(this), this); - - /* Increment its lvRefCnt and lvRefCntWtd */ - lvaTable[copyLclNum].incRefCnts(fgFirstBB->getBBWeight(this), this); } else { @@ -461,10 +455,6 @@ void Compiler::optAddCopies() /* TODO-Review: BB_UNITY_WEIGHT is not the correct block weight */ unsigned blockWeight = BB_UNITY_WEIGHT; - /* Increment its lvRefCnt and lvRefCntWtd twice */ - lvaTable[copyLclNum].incRefCnts(blockWeight, this); - lvaTable[copyLclNum].incRefCnts(blockWeight, this); - /* Assign the old expression into the new temp */ GenTree* newAsgn = gtNewTempAssign(copyLclNum, tree->gtOp.gtOp2); @@ -2698,10 +2688,6 @@ GenTree* Compiler::optConstantAssertionProp(AssertionDsc* curAssertion, gtDispTree(newTree, nullptr, nullptr, true); } #endif - if (lvaLocalVarRefCounted()) - { - lvaTable[lclNum].decRefCnts(compCurBB->getBBWeight(this), this); - } return optAssertionProp_Update(newTree, tree, stmt); } @@ -2811,13 +2797,7 @@ GenTree* Compiler::optCopyAssertionProp(AssertionDsc* curAssertion, return nullptr; } - // If global assertion prop, by now we should have ref counts, fix them. - if (lvaLocalVarRefCounted()) - { - lvaTable[lclNum].decRefCnts(compCurBB->getBBWeight(this), this); - lvaTable[copyLclNum].incRefCnts(compCurBB->getBBWeight(this), this); - tree->gtLclVarCommon.SetSsaNum(copySsaNum); - } + tree->gtLclVarCommon.SetSsaNum(copySsaNum); tree->gtLclVarCommon.SetLclNum(copyLclNum); #ifdef DEBUG @@ -3097,9 +3077,6 @@ GenTree* Compiler::optAssertionPropGlobal_RelOp(ASSERT_VALARG_TP assertions, Gen gtDispTree(tree, nullptr, nullptr, true); } #endif - // Decrement the ref counts, before we change the oper. - lvaTable[op1->gtLclVar.gtLclNum].decRefCnts(compCurBB->getBBWeight(this), this); - // Change the oper to const. if (genActualType(op1->TypeGet()) == TYP_INT) { @@ -3158,8 +3135,6 @@ GenTree* Compiler::optAssertionPropGlobal_RelOp(ASSERT_VALARG_TP assertions, Gen gtDispTree(tree, nullptr, nullptr, true); } #endif - lvaTable[op1->gtLclVar.gtLclNum].decRefCnts(compCurBB->getBBWeight(this), this); - // If floating point, don't just substitute op1 with op2, this won't work if // op2 is NaN. Just turn it into a "true" or "false" yielding expression. if (op1->TypeGet() == TYP_DOUBLE || op1->TypeGet() == TYP_FLOAT) @@ -3169,7 +3144,6 @@ GenTree* Compiler::optAssertionPropGlobal_RelOp(ASSERT_VALARG_TP assertions, Gen // point only on JTrue nodes, so if the condition held earlier, it will hold // now. We don't create OAK_EQUAL assertion on floating point from GT_ASG // because we depend on value num which would constant prop the NaN. - lvaTable[op2->gtLclVar.gtLclNum].decRefCnts(compCurBB->getBBWeight(this), this); op1->ChangeOperConst(GT_CNS_DBL); op1->gtDblCon.gtDconVal = 0; op2->ChangeOperConst(GT_CNS_DBL); @@ -3179,7 +3153,6 @@ GenTree* Compiler::optAssertionPropGlobal_RelOp(ASSERT_VALARG_TP assertions, Gen else { noway_assert(varTypeIsIntegralOrI(op1->TypeGet())); - lvaTable[op2->gtLclVar.gtLclNum].incRefCnts(compCurBB->getBBWeight(this), this); op1->AsLclVarCommon()->SetLclNum(op2->AsLclVarCommon()->GetLclNum()); op1->AsLclVarCommon()->SetSsaNum(op2->AsLclVarCommon()->GetSsaNum()); } @@ -4631,13 +4604,11 @@ GenTree* Compiler::optPrepareTreeForReplacement(GenTree* oldTree, GenTree* newTr gtExtractSideEffList(oldTree, &sideEffList, GTF_SIDE_EFFECT, ignoreRoot); } + if (sideEffList != nullptr) { noway_assert((sideEffList->gtFlags & GTF_SIDE_EFFECT) != 0); - // Increment the ref counts as we want to keep the side effects. - lvaRecursiveIncRefCounts(sideEffList); - if (newTree != nullptr) { newTree = gtNewOperNode(GT_COMMA, newTree->TypeGet(), sideEffList, newTree); @@ -4648,8 +4619,6 @@ GenTree* Compiler::optPrepareTreeForReplacement(GenTree* oldTree, GenTree* newTr } } - // Decrement the ref counts as the oldTree is going to be dropped. - lvaRecursiveDecRefCounts(oldTree); return newTree; } @@ -5169,12 +5138,4 @@ void Compiler::optAssertionPropMain() fgDebugCheckBBlist(); fgDebugCheckLinks(); #endif - - // Assertion propagation may have changed the reference counts - // We need to resort the variable table - - if (optAssertionPropagated) - { - lvaSortAgain = true; - } } diff --git a/src/jit/codegencommon.cpp b/src/jit/codegencommon.cpp index 0f6beec574..67faf40095 100644 --- a/src/jit/codegencommon.cpp +++ b/src/jit/codegencommon.cpp @@ -3668,7 +3668,12 @@ void CodeGen::genFnPrologCalleeRegArgs(regNumber xtraReg, bool* pXtraRegClobbere { if (varDsc->lvTrackedNonStruct()) { - noway_assert(!VarSetOps::IsMember(compiler, compiler->fgFirstBB->bbLiveIn, varDsc->lvVarIndex)); + // We may now see some tracked locals with zero refs. + // See Lowering::DoPhase. Tolerate these. + if (varDsc->lvRefCnt() > 0) + { + noway_assert(!VarSetOps::IsMember(compiler, compiler->fgFirstBB->bbLiveIn, varDsc->lvVarIndex)); + } } else { diff --git a/src/jit/compiler.cpp b/src/jit/compiler.cpp index b66236b032..ded0920c3d 100644 --- a/src/jit/compiler.cpp +++ b/src/jit/compiler.cpp @@ -4912,8 +4912,7 @@ void Compiler::compCompile(void** methodCodePtr, ULONG* methodCodeSize, JitFlags StackLevelSetter stackLevelSetter(this); // PHASE_STACK_LEVEL_SETTER stackLevelSetter.Run(); - assert(lvaSortAgain == false); // We should have re-run fgLocalVarLiveness() in lower.Run() - lvaTrackedFixed = true; // We can not add any new tracked variables after this point. + lvaTrackedFixed = true; // We can not add any new tracked variables after this point. /* Now that lowering is completed we can proceed to perform register allocation */ m_pLinearScan->doLinearScan(); diff --git a/src/jit/compiler.h b/src/jit/compiler.h index 09ff104d7a..6015cf327e 100644 --- a/src/jit/compiler.h +++ b/src/jit/compiler.h @@ -613,12 +613,10 @@ private: 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); 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 @@ -711,11 +709,6 @@ public: !(lvIsParam || lvAddrExposed || lvIsStructField); } - 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, @@ -2541,7 +2534,6 @@ public: 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 @@ -2798,13 +2790,6 @@ public: VARSET_VALRET_TP lvaStmtLclMask(GenTree* stmt); - void lvaIncRefCnts(GenTree* tree); - void lvaDecRefCnts(GenTree* tree); - - void lvaDecRefCnts(BasicBlock* basicBlock, GenTree* tree); - void lvaRecursiveDecRefCounts(GenTree* tree); - void lvaRecursiveIncRefCounts(GenTree* tree); - #ifdef DEBUG struct lvaStressLclFldArgs { @@ -3970,10 +3955,6 @@ public: void fgLiveVarAnalysis(bool updateInternalOnly = false); - void fgUpdateRefCntForClone(BasicBlock* addedToBlock, GenTree* clonedTree); - - void fgUpdateRefCntForExtract(GenTree* wholeTree, GenTree* keptTree); - void fgComputeLifeCall(VARSET_TP& life, GenTreeCall* call); void fgComputeLifeTrackedLocalUse(VARSET_TP& life, LclVarDsc& varDsc, GenTreeLclVarCommon* node); @@ -4488,7 +4469,7 @@ public: void fgRemoveEmptyBlocks(); - void fgRemoveStmt(BasicBlock* block, GenTree* stmt, bool updateRefCnt = true); + void fgRemoveStmt(BasicBlock* block, GenTree* stmt); bool fgCheckRemoveStmt(BasicBlock* block, GenTree* stmt); diff --git a/src/jit/compiler.hpp b/src/jit/compiler.hpp index c1b050cc4f..2063d55bd8 100644 --- a/src/jit/compiler.hpp +++ b/src/jit/compiler.hpp @@ -1685,18 +1685,25 @@ inline unsigned Compiler::lvaGrabTemp(bool shortLifetime DEBUGARG(const char* re const unsigned tempNum = lvaCount; lvaCount++; - lvaTable[tempNum].lvType = TYP_UNDEF; // Initialize lvType, lvIsTemp and lvOnFrame + // Initialize lvType, lvIsTemp and lvOnFrame + lvaTable[tempNum].lvType = TYP_UNDEF; lvaTable[tempNum].lvIsTemp = shortLifetime; lvaTable[tempNum].lvOnFrame = true; - // If we've started normal ref counting and are in minopts or debug - // mark this variable as implictly referenced. + // If we've started normal ref counting, bump the ref count of this + // local, as we no longer do any incremental counting, and we presume + // this new local will be referenced. if (lvaLocalVarRefCounted()) { if (opts.MinOpts() || opts.compDbgCode) { lvaTable[tempNum].lvImplicitlyReferenced = 1; } + else + { + lvaTable[tempNum].setLvRefCnt(1); + lvaTable[tempNum].setLvRefCntWtd(BB_UNITY_WEIGHT); + } } #ifdef DEBUG @@ -1732,6 +1739,9 @@ inline unsigned Compiler::lvaGrabTemps(unsigned cnt DEBUGARG(const char* reason) } #endif + // Could handle this... + assert(!lvaLocalVarRefCounted()); + // You cannot allocate more space after frame layout! noway_assert(lvaDoneFrameLayout < Compiler::TENTATIVE_FRAME_LAYOUT); @@ -1812,124 +1822,6 @@ inline unsigned Compiler::lvaGrabTempWithImplicitUse(bool shortLifetime DEBUGARG return lclNum; } -/***************************************************************************** - * - * If lvaTrackedFixed is false then set the lvaSortAgain flag - * (this allows us to grow the number of tracked variables) - * and zero lvRefCntWtd when lvRefCnt is zero - */ - -inline void LclVarDsc::lvaResetSortAgainFlag(Compiler* comp, RefCountState state) -{ - if (!comp->lvaTrackedFixed && !comp->opts.MinOpts() && !comp->opts.compDbgCode) - { - /* Flag this change, set lvaSortAgain to true */ - comp->lvaSortAgain = true; - } - /* Set weighted ref count to zero if ref count is zero */ - if (lvRefCnt(state) == 0) - { - setLvRefCntWtd(0, state); - } -} - -/***************************************************************************** - * - * Decrement the ref counts for a local variable - */ - -inline void LclVarDsc::decRefCnts(BasicBlock::weight_t weight, Compiler* comp, RefCountState state, bool propagate) -{ - // In minopts and debug codegen, we don't maintain normal ref counts. - if ((state == RCS_NORMAL) && (comp->opts.MinOpts() || comp->opts.compDbgCode)) - { - return; - } - - /* Decrement lvRefCnt and lvRefCntWtd */ - Compiler::lvaPromotionType promotionType = DUMMY_INIT(Compiler::PROMOTION_TYPE_NONE); - if (varTypeIsStruct(lvType)) - { - promotionType = comp->lvaGetPromotionType(this); - } - - // - // Decrement counts on the local itself. - // - if (lvType != TYP_STRUCT || promotionType != Compiler::PROMOTION_TYPE_INDEPENDENT) - { - 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(state) > 0) - { - // - // Decrement lvRefCnt - // - decLvRefCnt(1, state); - - // - // Decrement lvRefCntWtd - // - if (weight != 0) - { - if (lvIsTemp && (weight * 2 > weight)) - { - weight *= 2; - } - - if (lvRefCntWtd(state) <= weight) - { // Can't go below zero - setLvRefCntWtd(0, state); - } - else - { - decLvRefCntWtd(weight, state); - } - } - } - } - - if (varTypeIsStruct(lvType) && propagate) - { - // For promoted struct locals, decrement lvRefCnt on its field locals as well. - if (promotionType == Compiler::PROMOTION_TYPE_INDEPENDENT || - promotionType == Compiler::PROMOTION_TYPE_DEPENDENT) - { - for (unsigned i = lvFieldLclStart; i < lvFieldLclStart + lvFieldCnt; ++i) - { - comp->lvaTable[i].decRefCnts(weight, comp, state, false); // Don't propagate - } - } - } - - if (lvIsStructField && propagate) - { - // Depending on the promotion type, decrement the ref count for the parent struct as well. - promotionType = comp->lvaGetParentPromotionType(this); - LclVarDsc* parentvarDsc = &comp->lvaTable[lvParentLcl]; - assert(!parentvarDsc->lvRegStruct); - if (promotionType == Compiler::PROMOTION_TYPE_DEPENDENT) - { - parentvarDsc->decRefCnts(weight, comp, state, false); // Don't propagate - } - } - - 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(state), - refCntWtd2str(lvRefCntWtd(state))); - } -#endif -} - /***************************************************************************** * * Increment the ref counts for a local variable @@ -2014,8 +1906,6 @@ inline void LclVarDsc::incRefCnts(BasicBlock::weight_t weight, Compiler* comp, R } } - lvaResetSortAgainFlag(comp, state); - #ifdef DEBUG if (comp->verbose) { @@ -4916,30 +4806,6 @@ inline void LclVarDsc::incLvRefCnt(unsigned short delta, RefCountState state) 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 // @@ -5014,30 +4880,6 @@ inline void LclVarDsc::incLvRefCntWtd(BasicBlock::weight_t delta, RefCountState 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 // diff --git a/src/jit/copyprop.cpp b/src/jit/copyprop.cpp index c09fa91509..98671c1b32 100644 --- a/src/jit/copyprop.cpp +++ b/src/jit/copyprop.cpp @@ -266,8 +266,6 @@ void Compiler::optCopyProp(BasicBlock* block, GenTree* stmt, GenTree* tree, LclN } #endif - lvaTable[lclNum].decRefCnts(block->getBBWeight(this), this); - lvaTable[newLclNum].incRefCnts(block->getBBWeight(this), this); tree->gtLclVarCommon.SetLclNum(newLclNum); tree->AsLclVarCommon()->SetSsaNum(newSsaNum); gtUpdateSideEffects(stmt, tree); diff --git a/src/jit/decomposelongs.cpp b/src/jit/decomposelongs.cpp index 9e6da62c86..74863ade63 100644 --- a/src/jit/decomposelongs.cpp +++ b/src/jit/decomposelongs.cpp @@ -141,10 +141,8 @@ GenTree* DecomposeLongs::DecomposeNode(GenTree* tree) m_compiler->gtDispTreeRange(Range(), tree); } #endif // DEBUG - m_compiler->lvaDecRefCnts(tree); unsigned loVarNum = varDsc->lvFieldLclStart; tree->AsLclVarCommon()->SetLclNum(loVarNum); - m_compiler->lvaIncRefCnts(tree); return tree->gtNext; } } @@ -343,13 +341,11 @@ GenTree* DecomposeLongs::DecomposeLclVar(LIR::Use& use) assert(use.IsInitialized()); assert(use.Def()->OperGet() == GT_LCL_VAR); - GenTree* tree = use.Def(); - unsigned varNum = tree->AsLclVarCommon()->gtLclNum; - LclVarDsc* varDsc = m_compiler->lvaTable + varNum; - m_compiler->lvaDecRefCnts(tree); - - GenTree* loResult = tree; - loResult->gtType = TYP_INT; + GenTree* tree = use.Def(); + unsigned varNum = tree->AsLclVarCommon()->gtLclNum; + LclVarDsc* varDsc = m_compiler->lvaTable + varNum; + GenTree* loResult = tree; + loResult->gtType = TYP_INT; GenTree* hiResult = m_compiler->gtNewLclLNode(varNum, TYP_INT); Range().InsertAfter(loResult, hiResult); @@ -373,9 +369,6 @@ GenTree* DecomposeLongs::DecomposeLclVar(LIR::Use& use) hiResult->AsLclFld()->gtFieldSeq = FieldSeqStore::NotAField(); } - m_compiler->lvaIncRefCnts(loResult); - m_compiler->lvaIncRefCnts(hiResult); - return FinalizeDecomposition(use, loResult, hiResult, hiResult); } @@ -400,8 +393,6 @@ GenTree* DecomposeLongs::DecomposeLclFld(LIR::Use& use) GenTree* hiResult = m_compiler->gtNewLclFldNode(loResult->gtLclNum, TYP_INT, loResult->gtLclOffs + 4); Range().InsertAfter(loResult, hiResult); - m_compiler->lvaIncRefCnts(hiResult); - return FinalizeDecomposition(use, loResult, hiResult, hiResult); } @@ -472,8 +463,6 @@ GenTree* DecomposeLongs::DecomposeStoreLclVar(LIR::Use& use) } assert(varDsc->lvFieldCnt == 2); - m_compiler->lvaDecRefCnts(tree); - GenTreeOp* value = rhs->AsOp(); Range().Remove(value); @@ -489,9 +478,6 @@ GenTree* DecomposeLongs::DecomposeStoreLclVar(LIR::Use& use) hiStore->gtOp.gtOp1 = value->gtOp2; hiStore->gtFlags |= GTF_VAR_DEF; - m_compiler->lvaIncRefCnts(loStore); - m_compiler->lvaIncRefCnts(hiStore); - Range().InsertAfter(tree, hiStore); return hiStore->gtNext; @@ -529,9 +515,6 @@ GenTree* DecomposeLongs::DecomposeStoreLclFld(LIR::Use& use) hiStore->gtOp1 = value->gtOp2; hiStore->gtFlags |= (GTF_VAR_DEF | GTF_VAR_USEASG); - // Bump the ref count for the destination. - m_compiler->lvaIncRefCnts(hiStore); - Range().InsertAfter(loStore, hiStore); return hiStore->gtNext; @@ -653,8 +636,6 @@ GenTree* DecomposeLongs::DecomposeCast(LIR::Use& use) hiResult = m_compiler->gtNewOperNode(GT_RSH, TYP_INT, loCopy, shiftBy); Range().InsertAfter(cast, loCopy, shiftBy, hiResult); - m_compiler->lvaIncRefCnts(loCopy); - Range().Remove(cast); } } @@ -830,8 +811,6 @@ GenTree* DecomposeLongs::DecomposeStoreInd(LIR::Use& use) GenTree* storeIndHigh = new (m_compiler, GT_STOREIND) GenTreeStoreInd(TYP_INT, addrHigh, dataHigh); storeIndHigh->gtFlags = (storeIndLow->gtFlags & (GTF_ALL_EFFECT | GTF_LIVENESS_MASK)); - m_compiler->lvaIncRefCnts(addrBaseHigh); - Range().InsertAfter(storeIndLow, dataHigh, addrBaseHigh, addrHigh, storeIndHigh); return storeIndHigh; @@ -884,8 +863,6 @@ GenTree* DecomposeLongs::DecomposeInd(LIR::Use& use) GenTree* indHigh = new (m_compiler, GT_IND) GenTreeIndir(GT_IND, TYP_INT, addrHigh, nullptr); indHigh->gtFlags |= (indLow->gtFlags & (GTF_GLOB_REF | GTF_EXCEPT | GTF_IND_FLAGS)); - m_compiler->lvaIncRefCnts(addrBaseHigh); - Range().InsertAfter(indLow, addrBaseHigh, addrHigh, indHigh); return FinalizeDecomposition(use, indLow, indHigh, indHigh); @@ -1149,8 +1126,6 @@ GenTree* DecomposeLongs::DecomposeShift(LIR::Use& use) GenTree* hiOp = new (m_compiler, GT_LONG) GenTreeOp(GT_LONG, TYP_LONG, loCopy, hiOp1); hiResult = m_compiler->gtNewOperNode(GT_LSH_HI, TYP_INT, hiOp, shiftByHi); - m_compiler->lvaIncRefCnts(loCopy); - Range().InsertBefore(shift, loOp1, shiftByLo, loResult); Range().InsertBefore(shift, loCopy, hiOp, shiftByHi, hiResult); @@ -1226,8 +1201,6 @@ GenTree* DecomposeLongs::DecomposeShift(LIR::Use& use) GenTree* shiftByHi = m_compiler->gtNewIconNode(count, TYP_INT); GenTree* shiftByLo = m_compiler->gtNewIconNode(count, TYP_INT); - m_compiler->lvaIncRefCnts(hiCopy); - hiResult = m_compiler->gtNewOperNode(GT_RSZ, TYP_INT, hiOp1, shiftByHi); // Create a GT_LONG that contains loOp1 and hiCopy. This will be used in codegen to @@ -1298,7 +1271,6 @@ GenTree* DecomposeLongs::DecomposeShift(LIR::Use& use) GenTree* shiftByHi = m_compiler->gtNewIconNode(count, TYP_INT); GenTree* shiftByLo = m_compiler->gtNewIconNode(count, TYP_INT); - m_compiler->lvaIncRefCnts(hiCopy); hiResult = m_compiler->gtNewOperNode(GT_RSH, TYP_INT, hiOp1, shiftByHi); @@ -1349,8 +1321,6 @@ GenTree* DecomposeLongs::DecomposeShift(LIR::Use& use) GenTree* shiftBy = m_compiler->gtNewIconNode(31, TYP_INT); hiResult = m_compiler->gtNewOperNode(GT_RSH, TYP_INT, hiCopy, shiftBy); Range().InsertBefore(shift, shiftBy, hiCopy, hiResult); - - m_compiler->lvaIncRefCnts(hiCopy); } insertAfter = hiResult; @@ -1543,9 +1513,6 @@ GenTree* DecomposeLongs::DecomposeRotate(LIR::Use& use) GenTree* hiOp = new (m_compiler, GT_LONG) GenTreeOp(GT_LONG, TYP_LONG, loCopy, hiOp1); hiResult = m_compiler->gtNewOperNode(oper, TYP_INT, hiOp, rotateByHi); - m_compiler->lvaIncRefCnts(loCopy); - m_compiler->lvaIncRefCnts(hiCopy); - Range().InsertBefore(tree, hiCopy, loOp1, loOp); Range().InsertBefore(tree, rotateByLo, loResult); Range().InsertBefore(tree, loCopy, hiOp1, hiOp); diff --git a/src/jit/earlyprop.cpp b/src/jit/earlyprop.cpp index f97c0ac448..325f85df55 100644 --- a/src/jit/earlyprop.cpp +++ b/src/jit/earlyprop.cpp @@ -361,10 +361,8 @@ GenTree* Compiler::optEarlyPropRewriteTree(GenTree* tree) actualValClone->LabelIndex(this); } - DecLclVarRefCountsVisitor::WalkTree(this, tree); // actualValClone has small tree node size, it is safe to use CopyFrom here. tree->ReplaceWith(actualValClone, this); - IncLclVarRefCountsVisitor::WalkTree(this, tree); #ifdef DEBUG if (verbose) diff --git a/src/jit/flowgraph.cpp b/src/jit/flowgraph.cpp index d98cf2f389..b06b16c527 100644 --- a/src/jit/flowgraph.cpp +++ b/src/jit/flowgraph.cpp @@ -9670,41 +9670,6 @@ void Compiler::fgSimpleLowering() #endif } -/***************************************************************************** - */ - -void Compiler::fgUpdateRefCntForClone(BasicBlock* addedToBlock, GenTree* clonedTree) -{ - assert(clonedTree->gtOper != GT_STMT); - - if (lvaLocalVarRefCounted()) - { - compCurBB = addedToBlock; - IncLclVarRefCountsVisitor::WalkTree(this, clonedTree); - } -} - -/***************************************************************************** - */ - -void Compiler::fgUpdateRefCntForExtract(GenTree* wholeTree, GenTree* keptTree) -{ - 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 - * increment all refCnts for side effects then decrement everything - * in the statement - */ - if (keptTree) - { - IncLclVarRefCountsVisitor::WalkTree(this, keptTree); - } - - DecLclVarRefCountsVisitor::WalkTree(this, wholeTree); - } -} - VARSET_VALRET_TP Compiler::fgGetVarBits(GenTree* tree) { VARSET_TP varBits(VarSetOps::MakeEmpty(this)); @@ -9875,14 +9840,10 @@ void Compiler::fgRemoveEmptyBlocks() /***************************************************************************** * * Remove a useless statement from a basic block. - * The default is to decrement ref counts of included vars * */ -void Compiler::fgRemoveStmt(BasicBlock* block, - GenTree* node, - // whether to decrement ref counts for tracked vars in statement - bool updateRefCount) +void Compiler::fgRemoveStmt(BasicBlock* block, GenTree* node) { noway_assert(node); assert(fgOrder == FGOrderTree); @@ -9940,14 +9901,6 @@ void Compiler::fgRemoveStmt(BasicBlock* block, noway_assert(!optValnumCSE_phase); - if (updateRefCount) - { - if (fgStmtListThreaded) - { - DecLclVarRefCountsVisitor::WalkTree(this, stmt->gtStmtExpr); - } - } - fgStmtRemoved = true; #ifdef DEBUG @@ -14142,9 +14095,7 @@ bool Compiler::fgOptimizeSwitchBranches(BasicBlock* block) if (fgStmtListThreaded) { - /* Update the lclvar ref counts */ compCurBB = block; - fgUpdateRefCntForExtract(switchTree, sideEffList); /* Update ordering, costs, FP levels, etc. */ gtSetStmtInfo(switchStmt); @@ -14553,9 +14504,7 @@ bool Compiler::fgOptimizeBranchToNext(BasicBlock* block, BasicBlock* bNext, Basi if (fgStmtListThreaded) { - /* Update the lclvar ref counts */ compCurBB = block; - fgUpdateRefCntForExtract(cond->gtStmtExpr, sideEffList); /* Update ordering, costs, FP levels, etc. */ gtSetStmtInfo(cond); @@ -14836,9 +14785,6 @@ bool Compiler::fgOptimizeBranch(BasicBlock* bJump) return false; } - // Bump up the ref-counts of any variables in 'stmt' - fgUpdateRefCntForClone(bJump, stmt->gtStmtExpr); - // // Find the last statement in the bJump block // diff --git a/src/jit/gentree.cpp b/src/jit/gentree.cpp index c3ce836da4..5a5d2e1a3c 100644 --- a/src/jit/gentree.cpp +++ b/src/jit/gentree.cpp @@ -12017,9 +12017,6 @@ GenTree* Compiler::gtFoldExpr(GenTree* tree) GenTree* sideEffList = nullptr; gtExtractSideEffList(op1, &sideEffList); - fgUpdateRefCntForExtract(op1, sideEffList); // Decrement refcounts for op1, Keeping any side-effects - fgUpdateRefCntForExtract(colon_op1, nullptr); // Decrement refcounts for colon_op1 - // Clear colon flags only if the qmark itself is not conditionaly executed if ((tree->gtFlags & GTF_COLON_COND) == 0) { @@ -12230,10 +12227,7 @@ GenTree* Compiler::gtFoldExprCompare(GenTree* tree) cons->gtNext = tree->gtNext; cons->gtPrev = tree->gtPrev; } - if (lvaLocalVarRefCounted()) - { - lvaRecursiveDecRefCounts(tree); - } + return cons; } @@ -12671,10 +12665,6 @@ GenTree* Compiler::gtFoldExprSpecial(GenTree* tree) /* Multiply by zero - return the 'zero' node, but not if side effects */ if (!(op->gtFlags & GTF_SIDE_EFFECT)) { - if (lvaLocalVarRefCounted()) - { - lvaRecursiveDecRefCounts(op); - } op = cons; goto DONE_FOLD; } @@ -12703,10 +12693,6 @@ GenTree* Compiler::gtFoldExprSpecial(GenTree* tree) if (!(op->gtFlags & GTF_SIDE_EFFECT)) { - if (lvaLocalVarRefCounted()) - { - lvaRecursiveDecRefCounts(op); - } op = cons; goto DONE_FOLD; } @@ -12743,10 +12729,6 @@ GenTree* Compiler::gtFoldExprSpecial(GenTree* tree) if (!(op->gtFlags & GTF_SIDE_EFFECT)) { - if (lvaLocalVarRefCounted()) - { - lvaRecursiveDecRefCounts(op); - } op = cons; goto DONE_FOLD; } @@ -12766,10 +12748,6 @@ GenTree* Compiler::gtFoldExprSpecial(GenTree* tree) } else if (!(op->gtFlags & GTF_SIDE_EFFECT)) { - if (lvaLocalVarRefCounted()) - { - lvaRecursiveDecRefCounts(op); - } op = cons; goto DONE_FOLD; } @@ -12794,10 +12772,6 @@ GenTree* Compiler::gtFoldExprSpecial(GenTree* tree) op = op2->AsColon()->ElseNode(); opToDelete = op2->AsColon()->ThenNode(); } - if (lvaLocalVarRefCounted()) - { - lvaRecursiveDecRefCounts(opToDelete); - } // Clear colon flags only if the qmark itself is not conditionaly executed if ((tree->gtFlags & GTF_COLON_COND) == 0) diff --git a/src/jit/lclvars.cpp b/src/jit/lclvars.cpp index 324896b1ad..5f51739cf1 100644 --- a/src/jit/lclvars.cpp +++ b/src/jit/lclvars.cpp @@ -41,7 +41,6 @@ void Compiler::lvaInit() lvaTrackedToVarNum = nullptr; - lvaSortAgain = false; // false: We don't need to call lvaSortOnly() lvaTrackedFixed = false; // false: We can still add new tracked variables lvaDoneFrameLayout = NO_FRAME_LAYOUT; @@ -2798,188 +2797,6 @@ BasicBlock::weight_t BasicBlock::getBBWeight(Compiler* comp) } } -// Decrement the ref counts for all locals contained in the tree and its children. -void Compiler::lvaRecursiveDecRefCounts(GenTree* tree) -{ - 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. - if (tree->OperIsLeaf()) - { - if (tree->OperIsLocal()) - { - lvaDecRefCnts(tree); - } - } - else - { - DecLclVarRefCountsVisitor::WalkTree(this, tree); - } -} - -DecLclVarRefCountsVisitor::DecLclVarRefCountsVisitor(Compiler* compiler) - : GenTreeVisitor(compiler) -{ -} - -Compiler::fgWalkResult DecLclVarRefCountsVisitor::PreOrderVisit(GenTree** use, GenTree* user) -{ - m_compiler->lvaDecRefCnts(*use); - return fgWalkResult::WALK_CONTINUE; -} - -Compiler::fgWalkResult DecLclVarRefCountsVisitor::WalkTree(Compiler* compiler, GenTree* tree) -{ - DecLclVarRefCountsVisitor visitor(compiler); - return static_cast*>(&visitor)->WalkTree(&tree, nullptr); -} - -/***************************************************************************** - * - * Helper passed to the tree walker to decrement the refCnts for - * all local variables in an expression - */ -void Compiler::lvaDecRefCnts(GenTree* tree) -{ - assert(compCurBB != nullptr); - lvaDecRefCnts(compCurBB, tree); -} - -void Compiler::lvaDecRefCnts(BasicBlock* block, GenTree* tree) -{ - assert(block != nullptr); - assert(tree != nullptr); - - unsigned lclNum; - LclVarDsc* varDsc; - - noway_assert(lvaLocalVarRefCounted()); - - if ((tree->gtOper == GT_CALL) && (tree->gtFlags & GTF_CALL_UNMANAGED)) - { - assert((!opts.ShouldUsePInvokeHelpers()) || (info.compLvFrameListRoot == BAD_VAR_NUM)); - if (!opts.ShouldUsePInvokeHelpers()) - { - /* Get the special variable descriptor */ - - lclNum = info.compLvFrameListRoot; - - assert(lclNum <= lvaCount); - varDsc = lvaTable + lclNum; - - /* Decrement the reference counts twice */ - - varDsc->decRefCnts(block->getBBWeight(this), this); - varDsc->decRefCnts(block->getBBWeight(this), this); - } - } - else - { - /* This must be a local variable */ - - noway_assert(tree->OperIsLocal()); - - /* Get the variable descriptor */ - - lclNum = tree->gtLclVarCommon.gtLclNum; - - assert(lclNum < lvaCount); - varDsc = lvaTable + lclNum; - - /* Decrement its lvRefCnt and lvRefCntWtd */ - - varDsc->decRefCnts(block->getBBWeight(this), this); - } -} - -// Increment the ref counts for all locals contained in the tree and its children. -void Compiler::lvaRecursiveIncRefCounts(GenTree* tree) -{ - 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. - if (tree->OperIsLeaf()) - { - if (tree->OperIsLocal()) - { - lvaIncRefCnts(tree); - } - } - else - { - IncLclVarRefCountsVisitor::WalkTree(this, tree); - } -} - -IncLclVarRefCountsVisitor::IncLclVarRefCountsVisitor(Compiler* compiler) - : GenTreeVisitor(compiler) -{ -} - -Compiler::fgWalkResult IncLclVarRefCountsVisitor::PreOrderVisit(GenTree** use, GenTree* user) -{ - m_compiler->lvaIncRefCnts(*use); - return fgWalkResult::WALK_CONTINUE; -} - -Compiler::fgWalkResult IncLclVarRefCountsVisitor::WalkTree(Compiler* compiler, GenTree* tree) -{ - IncLclVarRefCountsVisitor visitor(compiler); - return static_cast*>(&visitor)->WalkTree(&tree, nullptr); -} - -/***************************************************************************** - * - * Helper passed to the tree walker to increment the refCnts for - * all local variables in an expression - */ -void Compiler::lvaIncRefCnts(GenTree* tree) -{ - unsigned lclNum; - LclVarDsc* varDsc; - - noway_assert(lvaLocalVarRefCounted()); - - if ((tree->gtOper == GT_CALL) && (tree->gtFlags & GTF_CALL_UNMANAGED)) - { - assert((!opts.ShouldUsePInvokeHelpers()) || (info.compLvFrameListRoot == BAD_VAR_NUM)); - if (!opts.ShouldUsePInvokeHelpers()) - { - /* Get the special variable descriptor */ - - lclNum = info.compLvFrameListRoot; - - assert(lclNum <= lvaCount); - varDsc = lvaTable + lclNum; - - /* Increment the reference counts twice */ - - varDsc->incRefCnts(compCurBB->getBBWeight(this), this); - varDsc->incRefCnts(compCurBB->getBBWeight(this), this); - } - } - else - { - /* This must be a local variable */ - - noway_assert(tree->gtOper == GT_LCL_VAR || tree->gtOper == GT_LCL_FLD || tree->gtOper == GT_STORE_LCL_VAR || - tree->gtOper == GT_STORE_LCL_FLD); - - /* Get the variable descriptor */ - - lclNum = tree->gtLclVarCommon.gtLclNum; - - assert(lclNum < lvaCount); - varDsc = lvaTable + lclNum; - - /* Increment its lvRefCnt and lvRefCntWtd */ - - varDsc->incRefCnts(compCurBB->getBBWeight(this), this); - } -} - /***************************************************************************** * * Compare function passed to qsort() by Compiler::lclVars.lvaSortByRefCount(). @@ -3239,9 +3056,6 @@ void Compiler::lvaSortOnly() /* Now sort the variable table by ref-count */ qsort(lvaRefSorted, lvaCount, sizeof(*lvaRefSorted), (compCodeOpt() == SMALL_CODE) ? RefCntCmp : WtdRefCntCmp); - - lvaSortAgain = false; - lvaDumpRefCounts(); } @@ -3311,24 +3125,6 @@ void Compiler::lvaSortByRefCount() *refTab++ = varDsc; - /* If we have JMP, all arguments must have a location - * even if we don't use them inside the method */ - - if (compJmpOpUsed && varDsc->lvIsParam) - { - /* ...except when we have varargs and the argument is - passed on the stack. In that case, it's important - for the ref count to be zero, so that we don't attempt - to track them for GC info (which is not possible since we - don't know their offset in the stack). See the assert at the - end of raMarkStkVars and bug #28949 for more info. */ - - if (!raIsVarargsStackArg(lclNum)) - { - varDsc->incRefCnts(1, this); - } - } - /* For now assume we'll be able to track all locals */ varDsc->lvTracked = 1; @@ -4080,6 +3876,7 @@ void Compiler::lvaMarkLocalVars() void Compiler::lvaComputeRefCounts(bool isRecompute, bool setSlotNumbers) { + JITDUMP("\n*** lvaComputeRefCounts ***\n"); unsigned lclNum = 0; LclVarDsc* varDsc = nullptr; @@ -4093,11 +3890,8 @@ void Compiler::lvaComputeRefCounts(bool isRecompute, bool setSlotNumbers) { #if defined(DEBUG) - // All local vars should be marked as implicitly referenced. - // - // This happens today for temps introduced after lvMarkRefs via - // incremental ref count updates. If/when we remove that we'll need - // to do something else to ensure late temps are considered. + // All local vars should be marked as implicitly referenced + // and not tracked. for (lclNum = 0, varDsc = lvaTable; lclNum < lvaCount; lclNum++, varDsc++) { const bool isSpecialVarargsParam = varDsc->lvIsParam && raIsVarargsStackArg(lclNum); @@ -4110,6 +3904,8 @@ void Compiler::lvaComputeRefCounts(bool isRecompute, bool setSlotNumbers) { assert(varDsc->lvImplicitlyReferenced); } + + assert(!varDsc->lvTracked); } #endif // defined (DEBUG) @@ -4168,6 +3964,8 @@ void Compiler::lvaComputeRefCounts(bool isRecompute, bool setSlotNumbers) } } + JITDUMP("\n*** lvaComputeRefCounts -- explicit counts ***\n"); + // Second, account for all explicit local variable references for (BasicBlock* block = fgFirstBB; block; block = block->bbNext) { @@ -4203,6 +4001,8 @@ void Compiler::lvaComputeRefCounts(bool isRecompute, bool setSlotNumbers) } } + JITDUMP("\n*** lvaComputeRefCounts -- implicit counts ***\n"); + // Third, bump ref counts for some implicit prolog references for (lclNum = 0, varDsc = lvaTable; lclNum < lvaCount; lclNum++, varDsc++) { @@ -4225,6 +4025,22 @@ void Compiler::lvaComputeRefCounts(bool isRecompute, bool setSlotNumbers) varDsc->incRefCnts(BB_UNITY_WEIGHT, this); } } + + // If we have JMP, all arguments must have a location + // even if we don't use them inside the method + if (compJmpOpUsed && varDsc->lvIsParam && (varDsc->lvRefCnt() == 0)) + { + // except when we have varargs and the argument is + // passed on the stack. In that case, it's important + // for the ref count to be zero, so that we don't attempt + // to track them for GC info (which is not possible since we + // don't know their offset in the stack). See the assert at the + // end of raMarkStkVars and bug #28949 for more info. + if (!raIsVarargsStackArg(lclNum)) + { + varDsc->lvImplicitlyReferenced = 1; + } + } } } diff --git a/src/jit/lir.cpp b/src/jit/lir.cpp index 0ba18a2d6d..480a5d3e95 100644 --- a/src/jit/lir.cpp +++ b/src/jit/lir.cpp @@ -265,10 +265,6 @@ unsigned LIR::Use::ReplaceWithLclVar(Compiler* compiler, unsigned blockWeight, u lclNum = compiler->lvaGrabTemp(true DEBUGARG("ReplaceWithLclVar is creating a new local variable")); } - // Increment its lvRefCnt and lvRefCntWtd twice, one for the def and one for the use - compiler->lvaTable[lclNum].incRefCnts(blockWeight, compiler); - compiler->lvaTable[lclNum].incRefCnts(blockWeight, compiler); - GenTreeLclVar* const store = compiler->gtNewTempAssign(lclNum, node)->AsLclVar(); assert(store != nullptr); assert(store->gtOp1 == node); @@ -1083,8 +1079,7 @@ LIR::Range LIR::Range::Remove(ReadOnlyRange&& range) // LIR::Range::Delete: Deletes a node from this range. // // Note that the deleted node must not be used after this function has -// been called. If the deleted node is part of a block, this function also -// calls `Compiler::lvaDecRefCnts` as necessary. +// been called. // // Arguments: // node - The node to delete. Must be part of this range. @@ -1097,16 +1092,6 @@ void LIR::Range::Delete(Compiler* compiler, BasicBlock* block, GenTree* node) assert((block == nullptr) == (compiler == nullptr)); Remove(node); - - if (block != nullptr) - { - if (((node->OperGet() == GT_CALL) && ((node->gtFlags & GTF_CALL_UNMANAGED) != 0)) || - (node->OperIsLocal() && !node->IsPhiNode())) - { - compiler->lvaDecRefCnts(block, node); - } - } - DEBUG_DESTROY_NODE(node); } @@ -1115,8 +1100,7 @@ void LIR::Range::Delete(Compiler* compiler, BasicBlock* block, GenTree* node) // // Both the start and the end of the subrange must be part of this range. // Note that the deleted nodes must not be used after this function has -// been called. If the deleted nodes are part of a block, this function -// also calls `Compiler::lvaDecRefCnts` as necessary. +// been called. // // Arguments: // firstNode - The first node in the subrange. @@ -1134,18 +1118,6 @@ void LIR::Range::Delete(Compiler* compiler, BasicBlock* block, GenTree* firstNod assert(lastNode->gtNext == nullptr); - if (block != nullptr) - { - for (GenTree* node = firstNode; node != nullptr; node = node->gtNext) - { - if (((node->OperGet() == GT_CALL) && ((node->gtFlags & GTF_CALL_UNMANAGED) != 0)) || - (node->OperIsLocal() && !node->IsPhiNode())) - { - compiler->lvaDecRefCnts(block, node); - } - } - } - #ifdef DEBUG // We can't do this in the loop above because it causes `IsPhiNode` to return a false negative // for `GT_STORE_LCL_VAR` nodes that participate in phi definitions. @@ -1161,8 +1133,7 @@ void LIR::Range::Delete(Compiler* compiler, BasicBlock* block, GenTree* firstNod // // Both the start and the end of the subrange must be part of this range. // Note that the deleted nodes must not be used after this function has -// been called. If the deleted nodes are part of a block, this function -// also calls `Compiler::lvaDecRefCnts` as necessary. +// been called. // // Arguments: // range - The subrange to delete. diff --git a/src/jit/liveness.cpp b/src/jit/liveness.cpp index 9f8910f1e3..c749152da3 100644 --- a/src/jit/liveness.cpp +++ b/src/jit/liveness.cpp @@ -134,7 +134,6 @@ void Compiler::fgLocalVarLiveness() // Init liveness data structures. fgLocalVarLivenessInit(); - assert(lvaSortAgain == false); // Set to false by lvaSortOnly() EndPhase(PHASE_LCLVARLIVENESS_INIT); @@ -157,25 +156,18 @@ void Compiler::fgLocalVarLiveness() fgInterBlockLocalVarLiveness(); } while (fgStmtRemoved && fgLocalVarLivenessChanged); - // If we removed any dead code we will have set 'lvaSortAgain' via decRefCnts - if (lvaSortAgain) - { - JITDUMP("In fgLocalVarLiveness, setting lvaSortAgain back to false (set during dead-code removal)\n"); - lvaSortAgain = false; // We don't re-Sort because we just performed LclVar liveness. - } - EndPhase(PHASE_LCLVARLIVENESS_INTERBLOCK); } /*****************************************************************************/ void Compiler::fgLocalVarLivenessInit() { - // If necessary, re-sort the variable table by ref-count...before creating any varsets using this sorting. - if (lvaSortAgain) + JITDUMP("In fgLocalVarLivenessInit\n"); + + // Sort locals first, if we're optimizing + if (!opts.MinOpts() && !opts.compDbgCode) { - JITDUMP("In fgLocalVarLivenessInit, sorting locals\n"); lvaSortByRefCount(); - assert(lvaSortAgain == false); // Set to false by lvaSortOnly() } // We mark a lcl as must-init in a first pass of local variable @@ -1025,10 +1017,7 @@ void Compiler::fgExtendDbgLifetimes() { printf("Created zero-init of V%02u in BB%02u\n", varNum, block->bbNum); } -#endif // DEBUG - - varDsc->incRefCnts(block->getBBWeight(this), this); - +#endif // DEBUG block->bbFlags |= BBF_CHANGED; // indicates that the contents of the block have changed. } @@ -1888,8 +1877,6 @@ void Compiler::fgComputeLifeLIR(VARSET_TP& life, BasicBlock* block, VARSET_VALAR // Remove the store. DCE will iteratively clean up any ununsed operands. lclVarNode->gtOp1->SetUnusedValue(); - lvaDecRefCnts(block, node); - // If the store is marked as a late argument, it is referenced by a call. Instead of removing // it, bash it to a NOP. if ((node->gtFlags & GTF_LATE_ARG) != 0) @@ -2192,7 +2179,6 @@ bool Compiler::fgRemoveDeadStore(GenTree** pTree, printf("\n"); } #endif // DEBUG - fgUpdateRefCntForExtract(asgNode, sideEffList); /* Replace the assignment statement with the list of side effects */ noway_assert(sideEffList->gtOper != GT_STMT); @@ -2285,7 +2271,6 @@ bool Compiler::fgRemoveDeadStore(GenTree** pTree, #endif // DEBUG if (sideEffList->gtOper == asgNode->gtOper) { - fgUpdateRefCntForExtract(asgNode, sideEffList); #ifdef DEBUG *treeModf = true; #endif // DEBUG @@ -2295,7 +2280,6 @@ bool Compiler::fgRemoveDeadStore(GenTree** pTree, } else { - fgUpdateRefCntForExtract(asgNode, sideEffList); #ifdef DEBUG *treeModf = true; #endif // DEBUG @@ -2330,11 +2314,7 @@ bool Compiler::fgRemoveDeadStore(GenTree** pTree, printf("\n"); } #endif // DEBUG - /* No side effects - Remove the interior statement */ - fgUpdateRefCntForExtract(asgNode, nullptr); - - /* Change the assignment to a GT_NOP node */ - + /* No side effects - Change the assignment to a GT_NOP node */ asgNode->gtBashToNOP(); #ifdef DEBUG diff --git a/src/jit/lower.cpp b/src/jit/lower.cpp index 13780ca188..4098c6e826 100644 --- a/src/jit/lower.cpp +++ b/src/jit/lower.cpp @@ -480,9 +480,7 @@ GenTree* Lowering::LowerSwitch(GenTree* node) GenTree* rhs = node->gtOp.gtOp1; unsigned lclNum = comp->lvaGrabTemp(true DEBUGARG("Lowering is creating a new local variable")); - comp->lvaSortAgain = true; comp->lvaTable[lclNum].lvType = rhs->TypeGet(); - comp->lvaTable[lclNum].setLvRefCnt(1); GenTreeLclVar* store = new (comp, GT_STORE_LCL_VAR) GenTreeLclVar(GT_STORE_LCL_VAR, rhs->TypeGet(), lclNum, BAD_IL_OFFSET); @@ -549,9 +547,6 @@ GenTree* Lowering::LowerSwitch(GenTree* node) // is now less than zero 0 (that would also hit the default case). gtDefaultCaseCond->gtFlags |= GTF_UNSIGNED; - /* Increment the lvRefCnt and lvRefCntWtd for temp */ - tempVarDsc->incRefCnts(blockWeight, comp); - GenTree* gtDefaultCaseJump = comp->gtNewOperNode(GT_JTRUE, TYP_VOID, gtDefaultCaseCond); gtDefaultCaseJump->gtFlags = node->gtFlags; @@ -724,9 +719,6 @@ GenTree* Lowering::LowerSwitch(GenTree* node) // |____ (ICon) (The actual case constant) GenTree* gtCaseCond = comp->gtNewOperNode(GT_EQ, TYP_INT, comp->gtNewLclvNode(tempLclNum, tempLclType), comp->gtNewIconNode(i, tempLclType)); - /* Increment the lvRefCnt and lvRefCntWtd for temp */ - tempVarDsc->incRefCnts(blockWeight, comp); - GenTree* gtCaseBranch = comp->gtNewOperNode(GT_JTRUE, TYP_VOID, gtCaseCond); LIR::Range caseRange = LIR::SeqTree(comp, gtCaseBranch); currentBBRange->InsertAtEnd(std::move(caseRange)); @@ -761,7 +753,6 @@ GenTree* Lowering::LowerSwitch(GenTree* node) // switch variants need the switch value so create the necessary LclVar node here. GenTree* switchValue = comp->gtNewLclvNode(tempLclNum, tempLclType); LIR::Range& switchBlockRange = LIR::AsRange(afterDefaultCondBlock); - tempVarDsc->incRefCnts(blockWeight, comp); switchBlockRange.InsertAtEnd(switchValue); // Try generating a bit test based switch first, @@ -2055,9 +2046,7 @@ void Lowering::LowerFastTailCall(GenTreeCall* call) tmpLclNum = comp->lvaGrabTemp( true DEBUGARG("Fast tail call lowering is creating a new local variable")); - comp->lvaSortAgain = true; - comp->lvaTable[tmpLclNum].lvType = tmpType; - comp->lvaTable[tmpLclNum].setLvRefCnt(1); + comp->lvaTable[tmpLclNum].lvType = tmpType; comp->lvaTable[tmpLclNum].lvDoNotEnregister = comp->lvaTable[lcl->gtLclNum].lvDoNotEnregister; } @@ -2472,11 +2461,6 @@ GenTree* Lowering::DecomposeLongCompare(GenTree* cmp) if (loSrc1->OperIs(GT_CNS_INT, GT_LCL_VAR, GT_LCL_FLD)) { BlockRange().Remove(loSrc1); - - if (loSrc1->OperIs(GT_LCL_VAR, GT_LCL_FLD)) - { - comp->lvaDecRefCnts(m_block, loSrc1); - } } else { @@ -3953,9 +3937,6 @@ GenTree* Lowering::LowerVirtualVtableCall(GenTreeCall* call) lclNum = vtableCallTemp; } - // We'll introduce another use of this local so increase its ref count. - comp->lvaTable[lclNum].incRefCnts(comp->compCurBB->getBBWeight(comp), comp); - // Get hold of the vtable offset (note: this might be expensive) unsigned vtabOffsOfIndirection; unsigned vtabOffsAfterIndirection; @@ -4001,11 +3982,8 @@ GenTree* Lowering::LowerVirtualVtableCall(GenTreeCall* call) // tmp2 = tmp1 + vtabOffsOfIndirection + vtabOffsAfterIndirection + [tmp1 + vtabOffsOfIndirection] // result = tmp2 + [tmp2] // - unsigned lclNumTmp = comp->lvaGrabTemp(true DEBUGARG("lclNumTmp")); - comp->lvaTable[lclNumTmp].incRefCnts(comp->compCurBB->getBBWeight(comp), comp); - + unsigned lclNumTmp = comp->lvaGrabTemp(true DEBUGARG("lclNumTmp")); unsigned lclNumTmp2 = comp->lvaGrabTemp(true DEBUGARG("lclNumTmp2")); - comp->lvaTable[lclNumTmp2].incRefCnts(comp->compCurBB->getBBWeight(comp), comp); GenTree* lclvNodeStore = comp->gtNewTempAssign(lclNumTmp, result); @@ -4598,7 +4576,6 @@ bool Lowering::LowerUnsignedDivOrMod(GenTreeOp* divMod) GenTree* dividend = comp->gtNewLclvNode(dividendLclNum, type); GenTree* sub = comp->gtNewOperNode(GT_SUB, type, dividend, mulhi); BlockRange().InsertBefore(divMod, dividend, sub); - comp->lvaTable[dividendLclNum].incRefCnts(curBBWeight, comp); GenTree* one = comp->gtNewIconNode(1, TYP_INT); GenTree* rsz = comp->gtNewOperNode(GT_RSZ, type, sub, one); @@ -4610,7 +4587,6 @@ bool Lowering::LowerUnsignedDivOrMod(GenTreeOp* divMod) GenTree* mulhiCopy = comp->gtNewLclvNode(mulhiLclNum, type); GenTree* add = comp->gtNewOperNode(GT_ADD, type, rsz, mulhiCopy); BlockRange().InsertBefore(divMod, mulhiCopy, add); - comp->lvaTable[mulhiLclNum].incRefCnts(curBBWeight, comp); mulhi = add; shift -= 1; @@ -4639,7 +4615,6 @@ bool Lowering::LowerUnsignedDivOrMod(GenTreeOp* divMod) divMod->gtOp2 = mul; BlockRange().InsertBefore(divMod, div, divisor, mul, dividend); - comp->lvaTable[dividendLclNum].incRefCnts(curBBWeight, comp); } ContainCheckRange(firstNode, divMod); @@ -4783,8 +4758,6 @@ GenTree* Lowering::LowerConstIntDivOrMod(GenTree* node) if (requiresAddSubAdjust) { dividend = comp->gtNewLclvNode(dividendLclNum, type); - comp->lvaTable[dividendLclNum].incRefCnts(curBBWeight, comp); - adjusted = comp->gtNewOperNode(divisorValue > 0 ? GT_ADD : GT_SUB, type, mulhi, dividend); BlockRange().InsertBefore(divMod, dividend, adjusted); } @@ -4800,7 +4773,6 @@ GenTree* Lowering::LowerConstIntDivOrMod(GenTree* node) LIR::Use adjustedUse(BlockRange(), &signBit->gtOp.gtOp1, signBit); unsigned adjustedLclNum = ReplaceWithLclVar(adjustedUse); adjusted = comp->gtNewLclvNode(adjustedLclNum, type); - comp->lvaTable[adjustedLclNum].incRefCnts(curBBWeight, comp); BlockRange().InsertBefore(divMod, adjusted); if (requiresShiftAdjust) @@ -4821,7 +4793,6 @@ GenTree* Lowering::LowerConstIntDivOrMod(GenTree* node) GenTree* div = comp->gtNewOperNode(GT_ADD, type, adjusted, signBit); dividend = comp->gtNewLclvNode(dividendLclNum, type); - comp->lvaTable[dividendLclNum].incRefCnts(curBBWeight, comp); // divisor % dividend = dividend - divisor x div GenTree* divisor = comp->gtNewIconNode(divisorValue, type); @@ -4878,8 +4849,6 @@ GenTree* Lowering::LowerConstIntDivOrMod(GenTree* node) GenTree* adjustedDividend = comp->gtNewOperNode(GT_ADD, type, adjustment, comp->gtNewLclvNode(dividendLclNum, type)); - comp->lvaTable[dividendLclNum].incRefCnts(curBBWeight, comp); - GenTree* newDivMod; if (isDiv) @@ -4907,8 +4876,6 @@ GenTree* Lowering::LowerConstIntDivOrMod(GenTree* node) newDivMod = comp->gtNewOperNode(GT_SUB, type, comp->gtNewLclvNode(dividendLclNum, type), comp->gtNewOperNode(GT_AND, type, adjustedDividend, divisor)); ContainCheckBinary(newDivMod->AsOp()); - - comp->lvaTable[dividendLclNum].incRefCnts(curBBWeight, comp); } // Remove the divisor and dividend nodes from the linear order, @@ -5141,7 +5108,6 @@ GenTree* Lowering::LowerArrElem(GenTree* node) else { idxArrObjNode = comp->gtClone(arrObjNode); - varDsc->incRefCnts(blockWeight, comp); BlockRange().InsertBefore(insertionPoint, idxArrObjNode); } @@ -5152,7 +5118,6 @@ GenTree* Lowering::LowerArrElem(GenTree* node) BlockRange().InsertBefore(insertionPoint, arrMDIdx); GenTree* offsArrObjNode = comp->gtClone(arrObjNode); - varDsc->incRefCnts(blockWeight, comp); BlockRange().InsertBefore(insertionPoint, offsArrObjNode); GenTreeArrOffs* arrOffs = @@ -5182,7 +5147,6 @@ GenTree* Lowering::LowerArrElem(GenTree* node) } GenTree* leaBase = comp->gtClone(arrObjNode); - varDsc->incRefCnts(blockWeight, comp); BlockRange().InsertBefore(insertionPoint, leaBase); GenTree* leaNode = new (comp, GT_LEA) GenTreeAddrMode(arrElem->TypeGet(), leaBase, leaIndexNode, scale, offset); @@ -5249,40 +5213,32 @@ void Lowering::DoPhase() } #endif - // Recompute local var ref counts before potentially sorting. + // Recompute local var ref counts before potentially sorting for liveness. // Note this does minimal work in cases where we are not going to sort. const bool isRecompute = true; const bool setSlotNumbers = false; comp->lvaComputeRefCounts(isRecompute, setSlotNumbers); - // TODO-Throughput: We re-sort local variables to get the goodness of enregistering recently - // introduced local variables both by Rationalize and Lower; downside is we need to - // recompute standard local variable liveness in order to get Linear CodeGen working. - // For now we'll take the throughput hit of recomputing local liveness but in the long term - // we're striving to use the unified liveness computation (fgLocalVarLiveness) and stop - // computing it separately in LSRA. - if ((comp->lvaCount != 0) && comp->backendRequiresLocalVarLifetimes()) - { - comp->lvaSortAgain = true; - } - comp->EndPhase(PHASE_LOWERING_DECOMP); - comp->fgLocalVarLiveness(); // local var liveness can delete code, which may create empty blocks if (!comp->opts.MinOpts() && !comp->opts.compDbgCode) { comp->optLoopsMarked = false; bool modified = comp->fgUpdateFlowGraph(); - if (modified || comp->lvaSortAgain) + if (modified) { JITDUMP("had to run another liveness pass:\n"); comp->fgLocalVarLiveness(); } } + // Recompute local var ref counts again after liveness to reflect + // impact of any dead code removal. Note this may leave us with + // tracked vars that have zero refs. + comp->lvaComputeRefCounts(isRecompute, setSlotNumbers); + #ifdef DEBUG JITDUMP("Liveness pass finished after lowering, IR:\n"); - JITDUMP("lvasortagain = %d\n", comp->lvaSortAgain); if (VERBOSE) { comp->fgDispBasicBlocks(true); diff --git a/src/jit/morph.cpp b/src/jit/morph.cpp index 7c093c4b46..83707b0a2f 100644 --- a/src/jit/morph.cpp +++ b/src/jit/morph.cpp @@ -2333,18 +2333,9 @@ void fgArgInfo::EvalArgsToTemps() { setupArg = compiler->gtNewTempAssign(tmpVarNum, argx); - LclVarDsc* varDsc = compiler->lvaTable + tmpVarNum; - - if (compiler->fgOrder == Compiler::FGOrderLinear) - { - // We'll reference this temporary variable just once - // when we perform the function call after - // setting up this argument. - varDsc->setLvRefCnt(1); - } - - var_types lclVarType = genActualType(argx->gtType); - var_types scalarType = TYP_UNKNOWN; + LclVarDsc* varDsc = compiler->lvaTable + tmpVarNum; + var_types lclVarType = genActualType(argx->gtType); + var_types scalarType = TYP_UNKNOWN; if (setupArg->OperIsCopyBlkOp()) { @@ -2628,28 +2619,11 @@ GenTree* Compiler::fgMakeMultiUse(GenTree** pOp) GenTree* tree = *pOp; if (tree->IsLocal()) { - auto result = gtClone(tree); - if (lvaLocalVarRefCounted()) - { - lvaTable[tree->gtLclVarCommon.gtLclNum].incRefCnts(compCurBB->getBBWeight(this), this); - } - return result; + return gtClone(tree); } else { - GenTree* result = fgInsertCommaFormTemp(pOp); - - // 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()) - { - lvaTable[result->gtLclVarCommon.gtLclNum].incRefCnts(compCurBB->getBBWeight(this), this); - lvaTable[result->gtLclVarCommon.gtLclNum].incRefCnts(compCurBB->getBBWeight(this), this); - lvaTable[result->gtLclVarCommon.gtLclNum].incRefCnts(compCurBB->getBBWeight(this), this); - } - - return result; + return fgInsertCommaFormTemp(pOp); } } @@ -5913,13 +5887,6 @@ GenTree* Compiler::fgMorphArrayIndex(GenTree* tree) bndsChk = arrBndsChk; - // Make sure to increment ref-counts if already ref-counted. - if (lvaLocalVarRefCounted()) - { - lvaRecursiveIncRefCounts(index); - lvaRecursiveIncRefCounts(arrRef); - } - // Now we'll switch to using the second copies for arrRef and index // to compute the address expression @@ -12576,21 +12543,6 @@ DONE_MORPHING_CHILDREN: DEBUG_DESTROY_NODE(asg->gtOp.gtOp1); DEBUG_DESTROY_NODE(lcl); - - /* This local variable should never be used again */ - // - // VSW 184221: Make RefCnt to zero to indicate that this local var - // is not used any more. (Keey the lvType as is.) - // Otherwise lvOnFrame will be set to true in Compiler::raMarkStkVars - // And then emitter::emitEndCodeGen will assert in the following line: - // noway_assert( dsc->lvTracked); - // - noway_assert(varDsc->lvRefCnt() == 0 || // lvRefCnt may not have been set yet. - varDsc->lvRefCnt() == 2 // Or, we assume this tmp should only be used here, - // and it only shows up twice. - ); - lvaTable[lclNum].setLvRefCnt(0); - lvaTable[lclNum].lvaResetSortAgainFlag(this); } if (op1->OperIsCompare()) @@ -12599,9 +12551,9 @@ DONE_MORPHING_CHILDREN: // // EQ/NE -> RELOP/!RELOP // / \ / \ - // RELOP CNS 0/1 + // RELOP CNS 0/1 // / \ - // + // // Note that we will remove/destroy the EQ/NE node and move // the RELOP up into it's location. @@ -13755,11 +13707,6 @@ DONE_MORPHING_CHILDREN: } else { - /* The left operand is worthless, throw it away */ - if (lvaLocalVarRefCounted()) - { - lvaRecursiveDecRefCounts(op1); - } op2->gtFlags |= (tree->gtFlags & (GTF_DONT_CSE | GTF_LATE_ARG)); DEBUG_DESTROY_NODE(tree); DEBUG_DESTROY_NODE(op1); @@ -14328,21 +14275,11 @@ GenTree* Compiler::fgMorphModToSubMulDiv(GenTreeOp* tree) { numerator = fgMakeMultiUse(&tree->gtOp1); } - else if (lvaLocalVarRefCounted() && numerator->OperIsLocal()) - { - // Morphing introduces new lclVar references. Increase ref counts - lvaIncRefCnts(numerator); - } if (!denominator->OperIsLeaf()) { denominator = fgMakeMultiUse(&tree->gtOp2); } - else if (lvaLocalVarRefCounted() && denominator->OperIsLocal()) - { - // Morphing introduces new lclVar references. Increase ref counts - lvaIncRefCnts(denominator); - } // The numerator and denominator may have been assigned to temps, in which case // their defining assignments are in the current tree. Therefore, we need to @@ -15698,12 +15635,6 @@ bool Compiler::fgMorphBlockStmt(BasicBlock* block, GenTreeStmt* stmt DEBUGARG(co stmt->gtStmtExpr = morph; - if (lvaLocalVarRefCounted()) - { - // fgMorphTree may have introduced new lclVar references. Bump the ref counts if requested. - lvaRecursiveIncRefCounts(stmt->gtStmtExpr); - } - // Can the entire tree be removed? bool removedStmt = false; diff --git a/src/jit/optcse.cpp b/src/jit/optcse.cpp index f389aa5bee..3abab600b1 100644 --- a/src/jit/optcse.cpp +++ b/src/jit/optcse.cpp @@ -283,28 +283,6 @@ Compiler::fgWalkResult Compiler::optUnmarkCSEs(GenTree** pTree, fgWalkData* data // The call to optUnmarkCSE(tree) should have cleared any CSE info // assert(!IS_CSE_INDEX(tree->gtCSEnum)); - - // This node is to be removed from the graph of GenTree* - // next decrement any LclVar references. - // - if (tree->gtOper == GT_LCL_VAR) - { - unsigned lclNum; - LclVarDsc* varDsc; - - // This variable ref is going away, decrease its ref counts - - lclNum = tree->gtLclVarCommon.gtLclNum; - assert(lclNum < comp->lvaCount); - varDsc = comp->lvaTable + lclNum; - - // make sure it's been initialized - assert(comp->optCSEweight <= BB_MAX_WEIGHT); - - // Decrement its lvRefCnt and lvRefCntWtd - - varDsc->decRefCnts(comp->optCSEweight, comp); - } } else // optUnmarkCSE(tree) returned false { @@ -2337,15 +2315,6 @@ public: // cannot add any new exceptions } - // Increment ref count for the CSE ref - m_pCompiler->lvaTable[cseLclVarNum].incRefCnts(blk->getBBWeight(m_pCompiler), m_pCompiler); - - if (isDef) - { - // Also increment ref count for the CSE assignment - m_pCompiler->lvaTable[cseLclVarNum].incRefCnts(blk->getBBWeight(m_pCompiler), m_pCompiler); - } - // Walk the statement 'stm' and find the pointer // in the tree is pointing to 'exp' // @@ -2462,11 +2431,7 @@ public: // void Cleanup() { - if (m_addCSEcount > 0) - { - /* We've added new local variables to the lvaTable so note that we need to recreate the sorted table */ - m_pCompiler->lvaSortAgain = true; - } + // Nothing to do, currently. } }; diff --git a/src/jit/optimizer.cpp b/src/jit/optimizer.cpp index 9a1e015969..dbf13a3101 100644 --- a/src/jit/optimizer.cpp +++ b/src/jit/optimizer.cpp @@ -6225,16 +6225,10 @@ void Compiler::optPerformHoistExpr(GenTree* origExpr, unsigned lnum) BasicBlock* preHead = optLoopTable[lnum].lpHead; assert(preHead->bbJumpKind == BBJ_NONE); - // fgMorphTree and lvaRecursiveIncRefCounts requires that compCurBB be the block that contains + // fgMorphTree requires that compCurBB be the block that contains // (or in this case, will contain) the expression. compCurBB = preHead; - - // Increment the ref counts of any local vars appearing in "hoist". - // Note that we need to do this before fgMorphTree() as fgMorph() could constant - // fold away some of the lcl vars referenced by "hoist". - lvaRecursiveIncRefCounts(hoist); - - hoist = fgMorphTree(hoist); + hoist = fgMorphTree(hoist); GenTree* hoistStmt = gtNewStmt(hoist); hoistStmt->gtFlags |= GTF_STMT_CMPADD; @@ -7937,32 +7931,6 @@ Compiler::fgWalkResult Compiler::optRemoveTreeVisitor(GenTree** pTree, fgWalkDat } } - // This node is being removed from the graph of GenTree* - - // Look for any local variable references - - if (tree->gtOper == GT_LCL_VAR && comp->lvaLocalVarRefCounted()) - { - unsigned lclNum; - LclVarDsc* varDsc; - - /* This variable ref is going away, decrease its ref counts */ - - lclNum = tree->gtLclVarCommon.gtLclNum; - assert(lclNum < comp->lvaCount); - varDsc = comp->lvaTable + lclNum; - - // make sure it's been initialized - assert(comp->compCurBB != nullptr); - assert(comp->compCurBB->bbWeight <= BB_MAX_WEIGHT); - - /* Decrement its lvRefCnt and lvRefCntWtd */ - - // Use getBBWeight to determine the proper block weight. - // This impacts the block weights when we have IBC data. - varDsc->decRefCnts(comp->compCurBB->getBBWeight(comp), comp); - } - return WALK_CONTINUE; } @@ -8784,10 +8752,6 @@ void Compiler::optOptimizeBoolsGcStress(BasicBlock* condBlock) GenTree* comparandClone = gtCloneExpr(comparand); - // Bump up the ref-counts of any variables in 'comparandClone' - compCurBB = condBlock; - IncLclVarRefCountsVisitor::WalkTree(this, comparandClone); - noway_assert(relop->gtOp.gtOp1 == comparand); genTreeOps oper = compStressCompile(STRESS_OPT_BOOLS_GC, 50) ? GT_OR : GT_AND; relop->gtOp.gtOp1 = gtNewOperNode(oper, TYP_I_IMPL, comparand, comparandClone); diff --git a/src/jit/rationalize.cpp b/src/jit/rationalize.cpp index 89e41679bb..cbbeaeaded 100644 --- a/src/jit/rationalize.cpp +++ b/src/jit/rationalize.cpp @@ -931,7 +931,6 @@ Compiler::fgWalkResult Rationalizer::RewriteNode(GenTree** useEdge, ArrayStacklvaDecRefCnts(node); BlockRange().Remove(node); } else diff --git a/src/jit/regalloc.cpp b/src/jit/regalloc.cpp index f80c81bbe1..eb6ddf8921 100644 --- a/src/jit/regalloc.cpp +++ b/src/jit/regalloc.cpp @@ -335,18 +335,19 @@ void Compiler::raMarkStkVars() /* For Debug Code, we have to reserve space even if the variable is never in scope. We will also need to initialize it if it is a GC var. - So we set lvMustInit and artifically bump up the ref-cnt. + So we set lvMustInit and verify it has a nonzero ref-cnt. */ if (opts.compDbgCode && !stkFixedArgInVarArgs && lclNum < info.compLocalsCount) { - needSlot |= true; - - if (lvaTypeIsGC(lclNum)) + if (varDsc->lvRefCnt() == 0) { - varDsc->setLvRefCnt(1); + assert(!"unreferenced local in debug codegen"); + varDsc->lvImplicitlyReferenced = 1; } + needSlot |= true; + if (!varDsc->lvIsParam) { varDsc->lvMustInit = true; -- cgit v1.2.3