summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/jit/assertionprop.cpp4
-rw-r--r--src/jit/compiler.h12
-rw-r--r--src/jit/compiler.hpp44
-rw-r--r--src/jit/copyprop.cpp8
-rw-r--r--src/jit/earlyprop.cpp4
-rw-r--r--src/jit/morph.cpp2
-rw-r--r--src/jit/optimizer.cpp6
-rw-r--r--src/jit/ssabuilder.cpp79
-rw-r--r--src/jit/ssabuilder.h2
-rw-r--r--src/jit/valuenum.cpp40
10 files changed, 115 insertions, 86 deletions
diff --git a/src/jit/assertionprop.cpp b/src/jit/assertionprop.cpp
index ebf118038b..87cf677b5e 100644
--- a/src/jit/assertionprop.cpp
+++ b/src/jit/assertionprop.cpp
@@ -1296,8 +1296,8 @@ AssertionIndex Compiler::optCreateAssertion(GenTree* op1,
noway_assert(lclNum < lvaCount);
LclVarDsc* lclVar = &lvaTable[lclNum];
- // If the local variable has its address exposed then bail
- if (fgExcludeFromSsa(lclNum))
+ // If the local variable is not in SSA then bail
+ if (!lvaInSsa(lclNum))
{
goto DONE_ASSERTION;
}
diff --git a/src/jit/compiler.h b/src/jit/compiler.h
index d3179509d5..a7629fcbe7 100644
--- a/src/jit/compiler.h
+++ b/src/jit/compiler.h
@@ -330,6 +330,8 @@ public:
unsigned char lvFieldAccessed : 1; // The var is a struct local, and a field of the variable is accessed. Affects
// struct promotion.
+ unsigned char lvInSsa : 1; // The variable is in SSA form (set by SsaBuilder)
+
#ifdef DEBUG
// These further document the reasons for setting "lvDoNotEnregister". (Note that "lvAddrExposed" is one of the
// reasons;
@@ -3025,6 +3027,13 @@ public:
unsigned lvaGSSecurityCookie; // LclVar number
bool lvaTempsHaveLargerOffsetThanVars();
+ // Returns "true" iff local variable "lclNum" is in SSA form.
+ bool lvaInSsa(unsigned lclNum)
+ {
+ assert(lclNum < lvaCount);
+ return lvaTable[lclNum].lvInSsa;
+ }
+
unsigned lvaSecurityObject; // variable representing the security object on the stack
unsigned lvaStubArgumentVar; // variable representing the secret stub argument coming in EAX
@@ -4133,9 +4142,6 @@ public:
unsigned fgSsaPassesCompleted; // Number of times fgSsaBuild has been run.
- // Returns "true" iff lcl "lclNum" should be excluded from SSA.
- inline bool fgExcludeFromSsa(unsigned lclNum);
-
// Returns "true" if a struct temp of the given type requires needs zero init in this block
inline bool fgStructTempNeedsExplicitZeroInit(LclVarDsc* varDsc, BasicBlock* block);
diff --git a/src/jit/compiler.hpp b/src/jit/compiler.hpp
index 45d0828582..cdaa04a53d 100644
--- a/src/jit/compiler.hpp
+++ b/src/jit/compiler.hpp
@@ -4276,48 +4276,6 @@ bool Compiler::fgStructTempNeedsExplicitZeroInit(LclVarDsc* varDsc, BasicBlock*
}
/*****************************************************************************/
-bool Compiler::fgExcludeFromSsa(unsigned lclNum)
-{
- if (opts.MinOpts())
- {
- return true; // If we're doing MinOpts, no SSA vars.
- }
-
- LclVarDsc* varDsc = &lvaTable[lclNum];
-
- if (varDsc->lvAddrExposed)
- {
- return true; // We exclude address-exposed variables.
- }
- if (!varDsc->lvTracked)
- {
- return true; // SSA is only done for tracked variables
- }
- // lvPromoted structs are never tracked...
- assert(!varDsc->lvPromoted);
-
- if (varDsc->lvOverlappingFields)
- {
- return true; // Don't use SSA on structs that have overlapping fields
- }
-
- if (varDsc->lvIsStructField && (lvaGetParentPromotionType(lclNum) != PROMOTION_TYPE_INDEPENDENT))
- {
- // SSA must exclude struct fields that are not independent
- // - because we don't model the struct assignment properly when multiple fields can be assigned by one struct
- // assignment.
- // - SSA doesn't allow a single node to contain multiple SSA definitions.
- // - and PROMOTION_TYPE_DEPENDEDNT fields are never candidates for a register.
- //
- // Example mscorlib method: CompatibilitySwitches:IsCompatibilitySwitchSet
- //
- return true;
- }
- // otherwise this variable is *not* excluded for SSA
- return false;
-}
-
-/*****************************************************************************/
ValueNum Compiler::GetUseAsgDefVNOrTreeVN(GenTree* op)
{
if (op->gtFlags & GTF_VAR_USEASG)
@@ -4336,7 +4294,7 @@ ValueNum Compiler::GetUseAsgDefVNOrTreeVN(GenTree* op)
unsigned Compiler::GetSsaNumForLocalVarDef(GenTree* lcl)
{
// Address-taken variables don't have SSA numbers.
- if (fgExcludeFromSsa(lcl->AsLclVarCommon()->gtLclNum))
+ if (!lvaInSsa(lcl->AsLclVarCommon()->gtLclNum))
{
return SsaConfig::RESERVED_SSA_NUM;
}
diff --git a/src/jit/copyprop.cpp b/src/jit/copyprop.cpp
index a83682df97..a1beccacb5 100644
--- a/src/jit/copyprop.cpp
+++ b/src/jit/copyprop.cpp
@@ -38,7 +38,7 @@ void Compiler::optBlockCopyPropPopStacks(BasicBlock* block, LclNumToGenTreePtrSt
continue;
}
unsigned lclNum = tree->gtLclVarCommon.gtLclNum;
- if (fgExcludeFromSsa(lclNum))
+ if (!lvaInSsa(lclNum))
{
continue;
}
@@ -153,8 +153,8 @@ void Compiler::optCopyProp(BasicBlock* block, GenTree* stmt, GenTree* tree, LclN
}
unsigned lclNum = tree->AsLclVarCommon()->GetLclNum();
- // Skip address exposed variables.
- if (fgExcludeFromSsa(lclNum))
+ // Skip non-SSA variables.
+ if (!lvaInSsa(lclNum))
{
return;
}
@@ -287,7 +287,7 @@ void Compiler::optCopyProp(BasicBlock* block, GenTree* stmt, GenTree* tree, LclN
*/
bool Compiler::optIsSsaLocal(GenTree* tree)
{
- return tree->IsLocal() && !fgExcludeFromSsa(tree->AsLclVarCommon()->GetLclNum());
+ return tree->IsLocal() && lvaInSsa(tree->AsLclVarCommon()->GetLclNum());
}
//------------------------------------------------------------------------------
diff --git a/src/jit/earlyprop.cpp b/src/jit/earlyprop.cpp
index 787dc84de5..edbcefdf69 100644
--- a/src/jit/earlyprop.cpp
+++ b/src/jit/earlyprop.cpp
@@ -273,7 +273,7 @@ GenTree* Compiler::optEarlyPropRewriteTree(GenTree* tree)
return nullptr;
}
- if (!objectRefPtr->OperIsScalarLocal() || fgExcludeFromSsa(objectRefPtr->AsLclVarCommon()->GetLclNum()))
+ if (!objectRefPtr->OperIsScalarLocal() || !lvaInSsa(objectRefPtr->AsLclVarCommon()->GetLclNum()))
{
return nullptr;
@@ -442,7 +442,7 @@ GenTree* Compiler::optPropGetValueRec(unsigned lclNum, unsigned ssaNum, optPropK
assert(treelhs == treeDefParent->gtGetOp1());
GenTree* treeRhs = treeDefParent->gtGetOp2();
- if (treeRhs->OperIsScalarLocal() && !fgExcludeFromSsa(treeRhs->AsLclVarCommon()->GetLclNum()))
+ if (treeRhs->OperIsScalarLocal() && lvaInSsa(treeRhs->AsLclVarCommon()->GetLclNum()))
{
// Recursively track the Rhs
unsigned rhsLclNum = treeRhs->AsLclVarCommon()->GetLclNum();
diff --git a/src/jit/morph.cpp b/src/jit/morph.cpp
index 806a3cfba7..dd570d3256 100644
--- a/src/jit/morph.cpp
+++ b/src/jit/morph.cpp
@@ -17712,7 +17712,7 @@ void Compiler::fgRetypeImplicitByRefArgs()
// Since this previously was a TYP_STRUCT and we have changed it to a TYP_BYREF
// make sure that the following flag is not set as these will force SSA to
- // exclude tracking/enregistering these LclVars. (see fgExcludeFromSsa)
+ // exclude tracking/enregistering these LclVars. (see SsaBuilder::IncludeInSsa)
//
varDsc->lvOverlappingFields = 0; // This flag could have been set, clear it.
diff --git a/src/jit/optimizer.cpp b/src/jit/optimizer.cpp
index 83f3a021e2..73c79c9c2a 100644
--- a/src/jit/optimizer.cpp
+++ b/src/jit/optimizer.cpp
@@ -7178,7 +7178,7 @@ bool Compiler::optTreeIsValidAtLoopHead(GenTree* tree, unsigned lnum)
unsigned lclNum = lclVar->gtLclNum;
// The lvlVar must be have an Ssa tracked lifetime
- if (fgExcludeFromSsa(lclNum))
+ if (!lvaInSsa(lclNum))
{
return false;
}
@@ -7627,7 +7627,7 @@ void Compiler::optComputeLoopSideEffectsOfBlock(BasicBlock* blk)
{
// If it's a local byref for which we recorded a value number, use that...
GenTreeLclVar* argLcl = arg->AsLclVar();
- if (!fgExcludeFromSsa(argLcl->GetLclNum()))
+ if (lvaInSsa(argLcl->GetLclNum()))
{
ValueNum argVN =
lvaTable[argLcl->GetLclNum()].GetPerSsaData(argLcl->GetSsaNum())->m_vnPair.GetLiberal();
@@ -7717,7 +7717,7 @@ void Compiler::optComputeLoopSideEffectsOfBlock(BasicBlock* blk)
if (rhsVN != ValueNumStore::NoVN)
{
rhsVN = vnStore->VNNormVal(rhsVN);
- if (!fgExcludeFromSsa(lhsLcl->GetLclNum()))
+ if (lvaInSsa(lhsLcl->GetLclNum()))
{
lvaTable[lhsLcl->GetLclNum()]
.GetPerSsaData(lhsLcl->GetSsaNum())
diff --git a/src/jit/ssabuilder.cpp b/src/jit/ssabuilder.cpp
index b4bb8afa67..d7347c2d87 100644
--- a/src/jit/ssabuilder.cpp
+++ b/src/jit/ssabuilder.cpp
@@ -687,10 +687,6 @@ void SsaBuilder::InsertPhiFunctions(BasicBlock** postOrder, int count)
{
JITDUMP("*************** In SsaBuilder::InsertPhiFunctions()\n");
- // Compute liveness on the graph.
- m_pCompiler->fgLocalVarLiveness();
- EndPhase(PHASE_BUILD_SSA_LIVENESS);
-
// Compute dominance frontier.
BlkToBlkVectorMap mapDF(m_allocator);
ComputeDominanceFrontiers(postOrder, count, &mapDF);
@@ -722,7 +718,7 @@ void SsaBuilder::InsertPhiFunctions(BasicBlock** postOrder, int count)
unsigned lclNum = m_pCompiler->lvaTrackedToVarNum[varIndex];
DBG_SSA_JITDUMP(" Considering local var V%02u:\n", lclNum);
- if (m_pCompiler->fgExcludeFromSsa(lclNum))
+ if (!m_pCompiler->lvaInSsa(lclNum))
{
DBG_SSA_JITDUMP(" Skipping because it is excluded.\n");
continue;
@@ -914,7 +910,7 @@ void SsaBuilder::TreeRenameVariables(GenTree* tree, BasicBlock* block, SsaRename
unsigned lclNum = tree->gtLclVarCommon.gtLclNum;
// Is this a variable we exclude from SSA?
- if (m_pCompiler->fgExcludeFromSsa(lclNum))
+ if (!m_pCompiler->lvaInSsa(lclNum))
{
tree->gtLclVarCommon.SetSsaNum(SsaConfig::RESERVED_SSA_NUM);
return;
@@ -1526,20 +1522,25 @@ void SsaBuilder::RenameVariables(BlkToBlkVectorMap* domTree, SsaRenameState* pRe
// The first thing we do is treat parameters and must-init variables as if they have a
// virtual definition before entry -- they start out at SSA name 1.
- for (unsigned i = 0; i < m_pCompiler->lvaCount; i++)
+ for (unsigned lclNum = 0; lclNum < m_pCompiler->lvaCount; lclNum++)
{
- LclVarDsc* varDsc = &m_pCompiler->lvaTable[i];
+ if (!m_pCompiler->lvaInSsa(lclNum))
+ {
+ continue;
+ }
+
+ LclVarDsc* varDsc = &m_pCompiler->lvaTable[lclNum];
+ assert(varDsc->lvTracked);
if (varDsc->lvIsParam || m_pCompiler->info.compInitMem || varDsc->lvMustInit ||
- (varDsc->lvTracked &&
- VarSetOps::IsMember(m_pCompiler, m_pCompiler->fgFirstBB->bbLiveIn, varDsc->lvVarIndex)))
+ VarSetOps::IsMember(m_pCompiler, m_pCompiler->fgFirstBB->bbLiveIn, varDsc->lvVarIndex))
{
unsigned ssaNum = varDsc->lvPerSsaData.AllocSsaNum(m_allocator);
// In ValueNum we'd assume un-inited variables get FIRST_SSA_NUM.
assert(ssaNum == SsaConfig::FIRST_SSA_NUM);
- pRenameState->Push(nullptr, i, ssaNum);
+ pRenameState->Push(nullptr, lclNum, ssaNum);
}
}
@@ -1729,6 +1730,16 @@ void SsaBuilder::Build()
ComputeDominators(postOrder, count, domTree);
EndPhase(PHASE_BUILD_SSA_DOMS);
+ // Compute liveness on the graph.
+ m_pCompiler->fgLocalVarLiveness();
+ EndPhase(PHASE_BUILD_SSA_LIVENESS);
+
+ // Mark all variables that will be tracked by SSA
+ for (unsigned lclNum = 0; lclNum < m_pCompiler->lvaCount; lclNum++)
+ {
+ m_pCompiler->lvaTable[lclNum].lvInSsa = IncludeInSsa(lclNum);
+ }
+
// Insert phi functions.
InsertPhiFunctions(postOrder, count);
@@ -1791,6 +1802,52 @@ void SsaBuilder::SetupBBRoot()
}
}
+//------------------------------------------------------------------------
+// IncludeInSsa: Check if the specified variable can be included in SSA.
+//
+// Arguments:
+// lclNum - the variable number
+//
+// Return Value:
+// true if the variable is included in SSA
+//
+bool SsaBuilder::IncludeInSsa(unsigned lclNum)
+{
+ LclVarDsc* varDsc = &m_pCompiler->lvaTable[lclNum];
+
+ if (varDsc->lvAddrExposed)
+ {
+ return false; // We exclude address-exposed variables.
+ }
+ if (!varDsc->lvTracked)
+ {
+ return false; // SSA is only done for tracked variables
+ }
+ // lvPromoted structs are never tracked...
+ assert(!varDsc->lvPromoted);
+
+ if (varDsc->lvOverlappingFields)
+ {
+ return false; // Don't use SSA on structs that have overlapping fields
+ }
+
+ if (varDsc->lvIsStructField &&
+ (m_pCompiler->lvaGetParentPromotionType(lclNum) != Compiler::PROMOTION_TYPE_INDEPENDENT))
+ {
+ // SSA must exclude struct fields that are not independent
+ // - because we don't model the struct assignment properly when multiple fields can be assigned by one struct
+ // assignment.
+ // - SSA doesn't allow a single node to contain multiple SSA definitions.
+ // - and PROMOTION_TYPE_DEPENDEDNT fields are never candidates for a register.
+ //
+ // Example mscorlib method: CompatibilitySwitches:IsCompatibilitySwitchSet
+ //
+ return false;
+ }
+ // otherwise this variable is included in SSA
+ return true;
+}
+
#ifdef DEBUG
// This method asserts that SSA name constraints specified are satisfied.
void Compiler::JitTestCheckSSA()
diff --git a/src/jit/ssabuilder.h b/src/jit/ssabuilder.h
index 27934c8aac..eab25549df 100644
--- a/src/jit/ssabuilder.h
+++ b/src/jit/ssabuilder.h
@@ -24,6 +24,8 @@ private:
m_pCompiler->EndPhase(phase);
}
+ bool IncludeInSsa(unsigned lclNum);
+
public:
// Constructor
SsaBuilder(Compiler* pCompiler);
diff --git a/src/jit/valuenum.cpp b/src/jit/valuenum.cpp
index 8d07436402..9ab6098b33 100644
--- a/src/jit/valuenum.cpp
+++ b/src/jit/valuenum.cpp
@@ -4756,9 +4756,16 @@ void Compiler::fgValueNumber()
// Start by giving incoming arguments value numbers.
// Also give must-init vars a zero of their type.
- for (unsigned i = 0; i < lvaCount; i++)
+ for (unsigned lclNum = 0; lclNum < lvaCount; lclNum++)
{
- LclVarDsc* varDsc = &lvaTable[i];
+ if (!lvaInSsa(lclNum))
+ {
+ continue;
+ }
+
+ LclVarDsc* varDsc = &lvaTable[lclNum];
+ assert(varDsc->lvTracked);
+
if (varDsc->lvIsParam)
{
// We assume that code equivalent to this variable initialization loop
@@ -4767,13 +4774,13 @@ void Compiler::fgValueNumber()
// SSA numbers always start from FIRST_SSA_NUM, and we give the value number to SSA name FIRST_SSA_NUM.
// We use the VNF_InitVal(i) from here so we know that this value is loop-invariant
// in all loops.
- ValueNum initVal = vnStore->VNForFunc(varDsc->TypeGet(), VNF_InitVal, vnStore->VNForIntCon(i));
+ ValueNum initVal = vnStore->VNForFunc(varDsc->TypeGet(), VNF_InitVal, vnStore->VNForIntCon(lclNum));
LclSsaVarDsc* ssaDef = varDsc->GetPerSsaData(SsaConfig::FIRST_SSA_NUM);
ssaDef->m_vnPair.SetBoth(initVal);
ssaDef->m_defLoc.m_blk = fgFirstBB;
}
else if (info.compInitMem || varDsc->lvMustInit ||
- (varDsc->lvTracked && VarSetOps::IsMember(this, fgFirstBB->bbLiveIn, varDsc->lvVarIndex)))
+ VarSetOps::IsMember(this, fgFirstBB->bbLiveIn, varDsc->lvVarIndex))
{
// The last clause covers the use-before-def variables (the ones that are live-in to the the first block),
// these are variables that are read before being initialized (at least on some control flow paths)
@@ -4804,7 +4811,7 @@ void Compiler::fgValueNumber()
else
{
// Here we have uninitialized TYP_BYREF
- initVal = vnStore->VNForFunc(typ, VNF_InitVal, vnStore->VNForIntCon(i));
+ initVal = vnStore->VNForFunc(typ, VNF_InitVal, vnStore->VNForIntCon(lclNum));
}
break;
@@ -4816,12 +4823,12 @@ void Compiler::fgValueNumber()
}
else
{
- initVal = vnStore->VNForFunc(typ, VNF_InitVal, vnStore->VNForIntCon(i));
+ initVal = vnStore->VNForFunc(typ, VNF_InitVal, vnStore->VNForIntCon(lclNum));
}
break;
}
#ifdef _TARGET_X86_
- bool isVarargParam = (i == lvaVarargsBaseOfStkArgs || i == lvaVarargsHandleArg);
+ bool isVarargParam = (lclNum == lvaVarargsBaseOfStkArgs || lclNum == lvaVarargsHandleArg);
if (isVarargParam)
initVal = vnStore->VNForExpr(fgFirstBB); // a new, unique VN.
#endif
@@ -5530,7 +5537,7 @@ void Compiler::fgValueNumberBlockAssignment(GenTree* tree, bool evalAsgLhsInd)
// Ignore vars that we excluded from SSA (for example, because they're address-exposed). They don't have
// SSA names in which to store VN's on defs. We'll yield unique VN's when we read from them.
- if (!fgExcludeFromSsa(lclNum))
+ if (lvaInSsa(lclNum))
{
// Should not have been recorded as updating ByrefExposed.
assert(!GetMemorySsaMap(ByrefExposed)->Lookup(tree, &memorySsaNum));
@@ -5598,7 +5605,7 @@ void Compiler::fgValueNumberBlockAssignment(GenTree* tree, bool evalAsgLhsInd)
unsigned lhsLclNum = lclVarTree->GetLclNum();
FieldSeqNode* lhsFldSeq = nullptr;
// If it's excluded from SSA, don't need to do anything.
- if (!fgExcludeFromSsa(lhsLclNum))
+ if (lvaInSsa(lhsLclNum))
{
// Should not have been recorded as updating ByrefExposed.
assert(!GetMemorySsaMap(ByrefExposed)->Lookup(tree, &memorySsaNum));
@@ -5652,7 +5659,7 @@ void Compiler::fgValueNumberBlockAssignment(GenTree* tree, bool evalAsgLhsInd)
{
unsigned rhsLclNum = rhsLclVarTree->GetLclNum();
rhsVarDsc = &lvaTable[rhsLclNum];
- if (fgExcludeFromSsa(rhsLclNum) || rhsFldSeq == FieldSeqStore::NotAField())
+ if (!lvaInSsa(rhsLclNum) || rhsFldSeq == FieldSeqStore::NotAField())
{
rhsVNPair.SetBoth(vnStore->VNForExpr(compCurBB, rhsLclVarTree->TypeGet()));
isNewUniq = true;
@@ -5681,7 +5688,7 @@ void Compiler::fgValueNumberBlockAssignment(GenTree* tree, bool evalAsgLhsInd)
{
unsigned rhsLclNum = rhsLclVarTree->GetLclNum();
rhsVarDsc = &lvaTable[rhsLclNum];
- if (fgExcludeFromSsa(rhsLclNum) || rhsFldSeq == FieldSeqStore::NotAField())
+ if (!lvaInSsa(rhsLclNum) || rhsFldSeq == FieldSeqStore::NotAField())
{
isNewUniq = true;
}
@@ -5983,7 +5990,7 @@ void Compiler::fgValueNumberTree(GenTree* tree, bool evalAsgLhsInd)
case GT_LCL_FLD:
{
GenTreeLclFld* lclFld = tree->AsLclFld();
- assert(fgExcludeFromSsa(lclFld->GetLclNum()) || lclFld->gtFieldSeq != nullptr);
+ assert(!lvaInSsa(lclFld->GetLclNum()) || lclFld->gtFieldSeq != nullptr);
// If this is a (full) def, then the variable will be labeled with the new SSA number,
// which will not have a value. We skip; it will be handled by one of the assignment-like
// forms (assignment, or initBlk or copyBlk).
@@ -5994,7 +6001,7 @@ void Compiler::fgValueNumberTree(GenTree* tree, bool evalAsgLhsInd)
LclVarDsc* varDsc = &lvaTable[lclNum];
var_types indType = tree->TypeGet();
- if (lclFld->gtFieldSeq == FieldSeqStore::NotAField() || fgExcludeFromSsa(lclFld->GetLclNum()))
+ if (lclFld->gtFieldSeq == FieldSeqStore::NotAField() || !lvaInSsa(lclFld->GetLclNum()))
{
// This doesn't represent a proper field access or it's a struct
// with overlapping fields that is hard to reason about; return a new unique VN.
@@ -6363,7 +6370,7 @@ void Compiler::fgValueNumberTree(GenTree* tree, bool evalAsgLhsInd)
wasLocal = true;
- if (!fgExcludeFromSsa(lclNum))
+ if (lvaInSsa(lclNum))
{
FieldSeqNode* fieldSeq = vnStore->FieldSeqVNToFieldSeq(funcApp.m_args[1]);
@@ -6716,7 +6723,7 @@ void Compiler::fgValueNumberTree(GenTree* tree, bool evalAsgLhsInd)
{
FieldSeqNode* fieldSeq = nullptr;
ValueNum newVN = ValueNumStore::NoVN;
- if (fgExcludeFromSsa(arg->gtLclVarCommon.GetLclNum()))
+ if (!lvaInSsa(arg->gtLclVarCommon.GetLclNum()))
{
newVN = vnStore->VNForExpr(compCurBB, TYP_BYREF);
}
@@ -6928,8 +6935,7 @@ void Compiler::fgValueNumberTree(GenTree* tree, bool evalAsgLhsInd)
VNFuncApp funcApp;
// Is it a local or a heap address?
- if (addr->IsLocalAddrExpr(this, &lclVarTree, &localFldSeq) &&
- !fgExcludeFromSsa(lclVarTree->GetLclNum()))
+ if (addr->IsLocalAddrExpr(this, &lclVarTree, &localFldSeq) && lvaInSsa(lclVarTree->GetLclNum()))
{
unsigned lclNum = lclVarTree->GetLclNum();
unsigned ssaNum = lclVarTree->GetSsaNum();