summaryrefslogtreecommitdiff
path: root/src/jit
diff options
context:
space:
mode:
authorPat Gavlin <pagavlin@microsoft.com>2017-01-09 10:41:16 -0800
committerPat Gavlin <pagavlin@microsoft.com>2017-01-09 10:41:16 -0800
commit474e27a5ac4ee651e2456a7503d4a8cf2ce7b00c (patch)
treed8f712ac085211e51c2ed2373547a2c8019bb665 /src/jit
parent583733b399edb423719e4754a3184913495e7575 (diff)
downloadcoreclr-474e27a5ac4ee651e2456a7503d4a8cf2ce7b00c.tar.gz
coreclr-474e27a5ac4ee651e2456a7503d4a8cf2ce7b00c.tar.bz2
coreclr-474e27a5ac4ee651e2456a7503d4a8cf2ce7b00c.zip
Encapsulate live var analysis in its own class.
This change moves the implementation of live variable analysis from a single function into a class in which the per-block portion of the algorithm is contained in its own function. There is no functional change.
Diffstat (limited to 'src/jit')
-rw-r--r--src/jit/liveness.cpp271
1 files changed, 146 insertions, 125 deletions
diff --git a/src/jit/liveness.cpp b/src/jit/liveness.cpp
index 1b19785375..965c6fa773 100644
--- a/src/jit/liveness.cpp
+++ b/src/jit/liveness.cpp
@@ -1070,181 +1070,202 @@ VARSET_VALRET_TP Compiler::fgGetHandlerLiveVars(BasicBlock* block)
return liveVars;
}
-/*****************************************************************************
- *
- * This is the classic algorithm for Live Variable Analysis.
- * If updateInternalOnly==true, only update BBF_INTERNAL blocks.
- */
-
-void Compiler::fgLiveVarAnalysis(bool updateInternalOnly)
+class LiveVarAnalysis
{
- BasicBlock* block;
- bool change;
-#ifdef DEBUG
- VARSET_TP VARSET_INIT_NOCOPY(extraLiveOutFromFinally, VarSetOps::MakeEmpty(this));
-#endif // DEBUG
- bool keepAliveThis = lvaKeepAliveAndReportThis() && lvaTable[info.compThisArg].lvTracked;
+ Compiler* m_compiler;
- /* Live Variable Analysis - Backward dataflow */
+ bool m_changed;
+ bool m_hasPossibleBackEdge;
- bool hasPossibleBackEdge = false;
+ bool m_heapLiveIn;
+ bool m_heapLiveOut;
+ VARSET_TP m_liveIn;
+ VARSET_TP m_liveOut;
- do
+ LiveVarAnalysis(Compiler* compiler)
+ : m_compiler(compiler), m_changed(false), m_hasPossibleBackEdge(false), m_heapLiveIn(false), m_heapLiveOut(false), m_liveIn(VarSetOps::MakeEmpty(compiler)), m_liveOut(VarSetOps::MakeEmpty(compiler))
{
- change = false;
-
- /* Visit all blocks and compute new data flow values */
-
- VARSET_TP VARSET_INIT_NOCOPY(liveIn, VarSetOps::MakeEmpty(this));
- VARSET_TP VARSET_INIT_NOCOPY(liveOut, VarSetOps::MakeEmpty(this));
-
- bool heapLiveIn = false;
- bool heapLiveOut = false;
+ }
- for (block = fgLastBB; block; block = block->bbPrev)
+ void PerBlock(BasicBlock* block, bool updateInternalOnly, bool keepAliveThis)
+ {
+ /* Compute the 'liveOut' set */
+ VarSetOps::ClearD(m_compiler, m_liveOut);
+ m_heapLiveOut = false;
+ if (block->endsWithJmpMethod(m_compiler))
{
- // sometimes block numbers are not monotonically increasing which
- // would cause us not to identify backedges
- if (block->bbNext && block->bbNext->bbNum <= block->bbNum)
+ // A JMP uses all the arguments, so mark them all
+ // as live at the JMP instruction
+ //
+ const LclVarDsc* varDscEndParams = m_compiler->lvaTable + m_compiler->info.compArgsCount;
+ for (LclVarDsc* varDsc = m_compiler->lvaTable; varDsc < varDscEndParams; varDsc++)
{
- hasPossibleBackEdge = true;
+ noway_assert(!varDsc->lvPromoted);
+ if (varDsc->lvTracked)
+ {
+ VarSetOps::AddElemD(m_compiler, m_liveOut, varDsc->lvVarIndex);
+ }
}
+ }
- if (updateInternalOnly)
+ // Additionally, union in all the live-in tracked vars of successors.
+ AllSuccessorIter succsEnd = block->GetAllSuccs(m_compiler).end();
+ for (AllSuccessorIter succs = block->GetAllSuccs(m_compiler).begin(); succs != succsEnd; ++succs)
+ {
+ BasicBlock* succ = (*succs);
+ VarSetOps::UnionD(m_compiler, m_liveOut, succ->bbLiveIn);
+ m_heapLiveOut = m_heapLiveOut || (*succs)->bbHeapLiveIn;
+ if (succ->bbNum <= block->bbNum)
{
- /* Only update BBF_INTERNAL blocks as they may be
- syntactically out of sequence. */
+ m_hasPossibleBackEdge = true;
+ }
+ }
- noway_assert(opts.compDbgCode && (info.compVarScopesCount > 0));
+ /* For lvaKeepAliveAndReportThis methods, "m_compiler" has to be kept alive everywhere
+ Note that a function may end in a throw on an infinite loop (as opposed to a return).
+ "m_compiler" has to be alive everywhere even in such methods. */
- if (!(block->bbFlags & BBF_INTERNAL))
- {
- continue;
- }
- }
+ if (keepAliveThis)
+ {
+ VarSetOps::AddElemD(m_compiler, m_liveOut, m_compiler->lvaTable[m_compiler->info.compThisArg].lvVarIndex);
+ }
- /* Compute the 'liveOut' set */
+ /* Compute the 'm_liveIn' set */
+ VarSetOps::Assign(m_compiler, m_liveIn, m_liveOut);
+ VarSetOps::DiffD(m_compiler, m_liveIn, block->bbVarDef);
+ VarSetOps::UnionD(m_compiler, m_liveIn, block->bbVarUse);
+
+ m_heapLiveIn = (m_heapLiveOut && !block->bbHeapDef) || block->bbHeapUse;
+
+ /* Can exceptions from m_compiler block be handled (in m_compiler function)? */
+
+ if (m_compiler->ehBlockHasExnFlowDsc(block))
+ {
+ VARSET_TP VARSET_INIT_NOCOPY(liveVars, m_compiler->fgGetHandlerLiveVars(block));
+
+ VarSetOps::UnionD(m_compiler, m_liveIn, liveVars);
+ VarSetOps::UnionD(m_compiler, m_liveOut, liveVars);
+ }
- VarSetOps::ClearD(this, liveOut);
- heapLiveOut = false;
- if (block->endsWithJmpMethod(this))
+ /* Has there been any change in either live set? */
+
+ if (!VarSetOps::Equal(m_compiler, block->bbLiveIn, m_liveIn) || !VarSetOps::Equal(m_compiler, block->bbLiveOut, m_liveOut))
+ {
+ if (updateInternalOnly)
{
- // A JMP uses all the arguments, so mark them all
- // as live at the JMP instruction
- //
- const LclVarDsc* varDscEndParams = lvaTable + info.compArgsCount;
- for (LclVarDsc* varDsc = lvaTable; varDsc < varDscEndParams; varDsc++)
+ // Only "extend" liveness over BBF_INTERNAL blocks
+
+ noway_assert(block->bbFlags & BBF_INTERNAL);
+
+ if (!VarSetOps::Equal(m_compiler, VarSetOps::Intersection(m_compiler, block->bbLiveIn, m_liveIn), m_liveIn) ||
+ !VarSetOps::Equal(m_compiler, VarSetOps::Intersection(m_compiler, block->bbLiveOut, m_liveOut), m_liveOut))
{
- noway_assert(!varDsc->lvPromoted);
- if (varDsc->lvTracked)
+#ifdef DEBUG
+ if (m_compiler->verbose)
{
- VarSetOps::AddElemD(this, liveOut, varDsc->lvVarIndex);
+ printf("Scope info: block BB%02u LiveIn+ ", block->bbNum);
+ dumpConvertedVarSet(m_compiler, VarSetOps::Diff(m_compiler, m_liveIn, block->bbLiveIn));
+ printf(", LiveOut+ ");
+ dumpConvertedVarSet(m_compiler, VarSetOps::Diff(m_compiler, m_liveOut, block->bbLiveOut));
+ printf("\n");
}
- }
- }
+#endif // DEBUG
- // Additionally, union in all the live-in tracked vars of successors.
- AllSuccessorIter succsEnd = block->GetAllSuccs(this).end();
- for (AllSuccessorIter succs = block->GetAllSuccs(this).begin(); succs != succsEnd; ++succs)
- {
- BasicBlock* succ = (*succs);
- VarSetOps::UnionD(this, liveOut, succ->bbLiveIn);
- heapLiveOut = heapLiveOut || (*succs)->bbHeapLiveIn;
- if (succ->bbNum <= block->bbNum)
- {
- hasPossibleBackEdge = true;
+ VarSetOps::UnionD(m_compiler, block->bbLiveIn, m_liveIn);
+ VarSetOps::UnionD(m_compiler, block->bbLiveOut, m_liveOut);
+ m_changed = true;
}
}
-
- /* For lvaKeepAliveAndReportThis methods, "this" has to be kept alive everywhere
- Note that a function may end in a throw on an infinite loop (as opposed to a return).
- "this" has to be alive everywhere even in such methods. */
-
- if (keepAliveThis)
+ else
{
- VarSetOps::AddElemD(this, liveOut, lvaTable[info.compThisArg].lvVarIndex);
+ VarSetOps::Assign(m_compiler, block->bbLiveIn, m_liveIn);
+ VarSetOps::Assign(m_compiler, block->bbLiveOut, m_liveOut);
+ m_changed = true;
}
+ }
- /* Compute the 'liveIn' set */
-
- VarSetOps::Assign(this, liveIn, liveOut);
- VarSetOps::DiffD(this, liveIn, block->bbVarDef);
- VarSetOps::UnionD(this, liveIn, block->bbVarUse);
+ if ((block->bbHeapLiveIn == 1) != m_heapLiveIn || (block->bbHeapLiveOut == 1) != m_heapLiveOut)
+ {
+ block->bbHeapLiveIn = m_heapLiveIn;
+ block->bbHeapLiveOut = m_heapLiveOut;
+ m_changed = true;
+ }
+ }
- heapLiveIn = (heapLiveOut && !block->bbHeapDef) || block->bbHeapUse;
+ void Run(bool updateInternalOnly)
+ {
+ const bool keepAliveThis = m_compiler->lvaKeepAliveAndReportThis() && m_compiler->lvaTable[m_compiler->info.compThisArg].lvTracked;
- /* Can exceptions from this block be handled (in this function)? */
+ /* Live Variable Analysis - Backward dataflow */
+ do
+ {
+ m_changed = false;
- if (ehBlockHasExnFlowDsc(block))
- {
- VARSET_TP VARSET_INIT_NOCOPY(liveVars, fgGetHandlerLiveVars(block));
+ /* Visit all blocks and compute new data flow values */
- VarSetOps::UnionD(this, liveIn, liveVars);
- VarSetOps::UnionD(this, liveOut, liveVars);
- }
+ VarSetOps::ClearD(m_compiler, m_liveIn);
+ VarSetOps::ClearD(m_compiler, m_liveOut);
- /* Has there been any change in either live set? */
+ m_heapLiveIn = false;
+ m_heapLiveOut = false;
- if (!VarSetOps::Equal(this, block->bbLiveIn, liveIn) || !VarSetOps::Equal(this, block->bbLiveOut, liveOut))
+ for (BasicBlock* block = m_compiler->fgLastBB; block; block = block->bbPrev)
{
+ // sometimes block numbers are not monotonically increasing which
+ // would cause us not to identify backedges
+ if (block->bbNext && block->bbNext->bbNum <= block->bbNum)
+ {
+ m_hasPossibleBackEdge = true;
+ }
+
if (updateInternalOnly)
{
- // Only "extend" liveness over BBF_INTERNAL blocks
+ /* Only update BBF_INTERNAL blocks as they may be
+ syntactically out of sequence. */
- noway_assert(block->bbFlags & BBF_INTERNAL);
+ noway_assert(m_compiler->opts.compDbgCode && (m_compiler->info.compVarScopesCount > 0));
- if (!VarSetOps::Equal(this, VarSetOps::Intersection(this, block->bbLiveIn, liveIn), liveIn) ||
- !VarSetOps::Equal(this, VarSetOps::Intersection(this, block->bbLiveOut, liveOut), liveOut))
+ if (!(block->bbFlags & BBF_INTERNAL))
{
-#ifdef DEBUG
- if (verbose)
- {
- printf("Scope info: block BB%02u LiveIn+ ", block->bbNum);
- dumpConvertedVarSet(this, VarSetOps::Diff(this, liveIn, block->bbLiveIn));
- printf(", LiveOut+ ");
- dumpConvertedVarSet(this, VarSetOps::Diff(this, liveOut, block->bbLiveOut));
- printf("\n");
- }
-#endif // DEBUG
-
- VarSetOps::UnionD(this, block->bbLiveIn, liveIn);
- VarSetOps::UnionD(this, block->bbLiveOut, liveOut);
- change = true;
+ continue;
}
}
- else
- {
- VarSetOps::Assign(this, block->bbLiveIn, liveIn);
- VarSetOps::Assign(this, block->bbLiveOut, liveOut);
- change = true;
- }
- }
- if ((block->bbHeapLiveIn == 1) != heapLiveIn || (block->bbHeapLiveOut == 1) != heapLiveOut)
+ PerBlock(block, updateInternalOnly, keepAliveThis);
+ }
+ // if there is no way we could have processed a block without seeing all of its predecessors
+ // then there is no need to iterate
+ if (!m_hasPossibleBackEdge)
{
- block->bbHeapLiveIn = heapLiveIn;
- block->bbHeapLiveOut = heapLiveOut;
- change = true;
+ break;
}
- }
- // if there is no way we could have processed a block without seeing all of its predecessors
- // then there is no need to iterate
- if (!hasPossibleBackEdge)
- {
- break;
- }
- } while (change);
+ } while (m_changed);
+ }
-//-------------------------------------------------------------------------
+public:
+ static void Run(Compiler* compiler, bool updateInternalOnly)
+ {
+ LiveVarAnalysis analysis(compiler);
+ analysis.Run(updateInternalOnly);
+ }
+};
-#ifdef DEBUG
+/*****************************************************************************
+ *
+ * This is the classic algorithm for Live Variable Analysis.
+ * If updateInternalOnly==true, only update BBF_INTERNAL blocks.
+ */
+void Compiler::fgLiveVarAnalysis(bool updateInternalOnly)
+{
+ LiveVarAnalysis::Run(this, updateInternalOnly);
+
+#ifdef DEBUG
if (verbose && !updateInternalOnly)
{
printf("\nBB liveness after fgLiveVarAnalysis():\n\n");
fgDispBBLiveness();
}
-
#endif // DEBUG
}