Encapsulate live var analysis in its own class.
authorPat Gavlin <pagavlin@microsoft.com>
Mon, 9 Jan 2017 18:41:16 +0000 (10:41 -0800)
committerPat Gavlin <pagavlin@microsoft.com>
Mon, 9 Jan 2017 18:41:16 +0000 (10:41 -0800)
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.

src/jit/liveness.cpp

index 1b19785..965c6fa 100644 (file)
@@ -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
 }