summaryrefslogtreecommitdiff
path: root/src/jit/ssabuilder.cpp
diff options
context:
space:
mode:
authormikedn <onemihaid@hotmail.com>2018-08-26 01:29:28 +0300
committerSergey Andreenko <seandree@microsoft.com>2018-08-25 15:29:28 -0700
commit9951a1b06f1279fdf8ad465dff355fc38238211f (patch)
treecc50b25b0f2d3e3317f3765fb7496a9cb7402870 /src/jit/ssabuilder.cpp
parenta1404cafbe1cd15a5c0cfbd4995ad97694b708bd (diff)
downloadcoreclr-9951a1b06f1279fdf8ad465dff355fc38238211f.tar.gz
coreclr-9951a1b06f1279fdf8ad465dff355fc38238211f.tar.bz2
coreclr-9951a1b06f1279fdf8ad465dff355fc38238211f.zip
Streamline fgExcludeFromSsa (#15351)
This function is relatively expensive due to the many checks it does. Adding an LclVarDsc "in SSA" bit that is set during SSA construction by calling fgExcludeFromSsa only once per variable results in 0.35% drop in instructions retired. Most of the checks done in fgExcludeFromSsa are implied by lvTracked and they could probably be converted to asserts. But lvOverlappingFields is not implied by lvTracked so even if all redundant checks are converted to asserts fgExcludeFromSsa still needs 2 checks rather than just one. Incidentally, this difference between tracked variables and SSA variables results in SSA and value numbers being assigned to some variables that are actually excluded from SSA - SsaBuilder::RenameVariables and fgValueNumber assign numbers to all live in fgFirstBB variables that require initialization without checking fgExcludeFromSsa first. Structs with overlapping fields are not common but properly excluding them is still enough to save 0.15% memory when compiling corelib. - Replace calls to fgExcludeFromSsa with calls to lvaInSsa (the old name is kind of weird, it has nothing to do with the flow graph and "exclude" results in double negation) - Move fgExcludeFromSsa logic to SsaBuild::IncludeInSsa and use it to initialize LclVarDsc::lvInSsa for all variables - Change RenameVariables and fgValueNumber to call lvaInSsa before assigning numbers to live in fgFirstBB variables
Diffstat (limited to 'src/jit/ssabuilder.cpp')
-rw-r--r--src/jit/ssabuilder.cpp79
1 files changed, 68 insertions, 11 deletions
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()