bool* doAgain,
bool* pStmtInfoDirty DEBUGARG(bool* treeModf));
- // For updating liveset during traversal AFTER fgComputeLife has completed
- VARSET_VALRET_TP fgGetVarBits(GenTree* tree);
- VARSET_VALRET_TP fgUpdateLiveSet(VARSET_VALARG_TP liveSet, GenTree* tree);
-
- // Returns the set of live variables after endTree,
- // assuming that liveSet is the set of live variables BEFORE tree.
- // Requires that fgComputeLife has completed, and that tree is in the same
- // statement as endTree, and that it comes before endTree in execution order
-
- VARSET_VALRET_TP fgUpdateLiveSet(VARSET_VALARG_TP liveSet, GenTree* tree, GenTree* endTree)
- {
- VARSET_TP newLiveSet(VarSetOps::MakeCopy(this, liveSet));
- while (tree != nullptr && tree != endTree->gtNext)
- {
- VarSetOps::AssignNoCopy(this, newLiveSet, fgUpdateLiveSet(newLiveSet, tree));
- tree = tree->gtNext;
- }
- assert(tree == endTree->gtNext);
- return newLiveSet;
- }
-
void fgInterBlockLocalVarLiveness();
// The presence of a partial definition presents some difficulties for SSA: this is both a use of some SSA name
#endif
}
-VARSET_VALRET_TP Compiler::fgGetVarBits(GenTree* tree)
-{
- VARSET_TP varBits(VarSetOps::MakeEmpty(this));
-
- assert(tree->gtOper == GT_LCL_VAR || tree->gtOper == GT_LCL_FLD);
-
- unsigned int lclNum = tree->AsLclVarCommon()->GetLclNum();
- LclVarDsc* varDsc = lvaTable + lclNum;
- if (varDsc->lvTracked)
- {
- VarSetOps::AddElemD(this, varBits, varDsc->lvVarIndex);
- }
- // We have to check type of root tree, not Local Var descriptor because
- // for legacy backend we promote TYP_STRUCT to TYP_INT if it is an unused or
- // independently promoted non-argument struct local.
- // For more details see Compiler::raAssignVars() method.
- else if (tree->gtType == TYP_STRUCT && varDsc->lvPromoted)
- {
- assert(varDsc->lvType == TYP_STRUCT);
- for (unsigned i = varDsc->lvFieldLclStart; i < varDsc->lvFieldLclStart + varDsc->lvFieldCnt; ++i)
- {
- noway_assert(lvaTable[i].lvIsStructField);
- if (lvaTable[i].lvTracked)
- {
- unsigned varIndex = lvaTable[i].lvVarIndex;
- noway_assert(varIndex < lvaTrackedCount);
- VarSetOps::AddElemD(this, varBits, varIndex);
- }
- }
- }
- return varBits;
-}
-
/*****************************************************************************
*
* Find and remove any basic blocks that are useless (e.g. they have not been
#endif // DEBUG
}
-/*****************************************************************************
- * For updating liveset during traversal AFTER fgComputeLife has completed
- */
-
-VARSET_VALRET_TP Compiler::fgUpdateLiveSet(VARSET_VALARG_TP liveSet, GenTree* tree)
-{
- VARSET_TP newLiveSet(VarSetOps::MakeCopy(this, liveSet));
- assert(fgLocalVarLivenessDone == true);
- GenTree* lclVarTree = tree; // After the tests below, "lclVarTree" will be the local variable.
- if (tree->gtOper == GT_LCL_VAR || tree->gtOper == GT_LCL_FLD ||
- (lclVarTree = fgIsIndirOfAddrOfLocal(tree)) != nullptr)
- {
- const VARSET_TP& varBits(fgGetVarBits(lclVarTree));
-
- if (!VarSetOps::IsEmpty(this, varBits))
- {
- if (tree->gtFlags & GTF_VAR_DEATH)
- {
- // We'd like to be able to assert the following, however if we are walking
- // through a qmark/colon tree, we may encounter multiple last-use nodes.
- // assert (VarSetOps::IsSubset(this, varBits, newLiveSet));
-
- // We maintain the invariant that if the lclVarTree is a promoted struct, but the
- // the lookup fails, then all the field vars (i.e., "varBits") are dying.
- VARSET_TP* deadVarBits = nullptr;
- if (varTypeIsStruct(lclVarTree) && LookupPromotedStructDeathVars(lclVarTree, &deadVarBits))
- {
- VarSetOps::DiffD(this, newLiveSet, *deadVarBits);
- }
- else
- {
- VarSetOps::DiffD(this, newLiveSet, varBits);
- }
- }
- else if ((tree->gtFlags & GTF_VAR_DEF) != 0 && (tree->gtFlags & GTF_VAR_USEASG) == 0)
- {
- assert(tree == lclVarTree); // LDOBJ case should only be a use.
-
- // This shouldn't be in newLiveSet, unless this is debug code, in which
- // case we keep vars live everywhere, OR it is address-exposed, OR this block
- // is part of a try block, in which case it may be live at the handler
- // Could add a check that, if it's in the newLiveSet, that it's also in
- // fgGetHandlerLiveVars(compCurBB), but seems excessive
- //
- assert(VarSetOps::IsEmptyIntersection(this, newLiveSet, varBits) || opts.compDbgCode ||
- lvaTable[tree->AsLclVarCommon()->GetLclNum()].lvAddrExposed ||
- (compCurBB != nullptr && ehBlockHasExnFlowDsc(compCurBB)));
- VarSetOps::UnionD(this, newLiveSet, varBits);
- }
- }
- }
- return newLiveSet;
-}
-
//------------------------------------------------------------------------
// Compiler::fgComputeLifeCall: compute the changes to local var liveness
// due to a GT_CALL node.