@@ -373,7 +373,7 @@ void ObjectAllocator::PrepareAnalysis()
373373    // 
374374    //  If conditional escape analysis is enabled, we reserve the range [N...N+M-1]
375375    //  for locals allocated during the conditional escape analysis expansions,
376-     //  where N  is the maximum number of pseudos.
376+     //  where M  is the maximum number of pseudos.
377377    // 
378378    //  We reserve the range [N+M ... N+2M-1] for pseudos.
379379    // 
@@ -614,47 +614,51 @@ void ObjectAllocator::MarkEscapingVarsAndBuildConnGraph()
614614            unsigned  const    lclNum = tree->AsLclVarCommon ()->GetLclNum ();
615615            LclVarDsc* const  lclDsc = m_compiler->lvaGetDesc (lclNum);
616616
617-             //  If this local already escapes, no need to look further. 
617+             //  Are we tracking this local? 
618618            // 
619-             if  (m_allocator->CanLclVarEscape (lclNum))
619+             if  (! m_allocator->IsTrackedLocal (lclNum))
620620            {
621621                return  Compiler::fgWalkResult::WALK_CONTINUE;
622622            }
623623
624-             bool  lclEscapes = true ;
624+             const  unsigned  lclIndex = m_allocator->LocalToIndex (lclNum);
625+ 
626+             //  If this local already escapes, no need to look further.
627+             // 
628+             if  (m_allocator->CanIndexEscape (lclIndex))
629+             {
630+                 return  Compiler::fgWalkResult::WALK_CONTINUE;
631+             }
625632
626633            if  (tree->OperIsLocalStore ())
627634            {
628-                 lclEscapes = false ;
629635                m_allocator->CheckForGuardedAllocationOrCopy (m_block, m_stmt, use, lclNum);
630636            }
631-             else  if  (tree->OperIs (GT_LCL_VAR) && m_allocator-> IsTrackedLocal (lclNum) )
637+             else  if  (tree->OperIs (GT_LCL_VAR))
632638            {
633639                assert (tree == m_ancestors.Top ());
634-                 if  (!m_allocator->CanLclVarEscapeViaParentStack (&m_ancestors, lclNum, m_block))
635-                 {
636-                     lclEscapes = false ;
637-                 }
640+                 m_allocator->AnalyzeParentStack (&m_ancestors, lclIndex, m_block);
638641            }
639-             else  if  (tree->OperIs (GT_LCL_ADDR) && (lclDsc->TypeGet () == TYP_STRUCT) &&
640-                      m_allocator->IsTrackedLocal (lclNum))
642+             else  if  (tree->OperIs (GT_LCL_ADDR) && (lclDsc->TypeGet () == TYP_STRUCT))
641643            {
642644                assert (tree == m_ancestors.Top ());
643-                 if  (!m_allocator->CanLclVarEscapeViaParentStack (&m_ancestors, lclNum, m_block))
644-                 {
645-                     lclEscapes = false ;
646-                 }
645+                 m_allocator->AnalyzeParentStack (&m_ancestors, lclIndex, m_block);
647646            }
648- 
649-             if  (lclEscapes)
647+             else  if  (tree->OperIs (GT_LCL_FLD))
650648            {
651-                 if  (!m_allocator->CanLclVarEscape (lclNum))
652-                 {
653-                     JITDUMP (" V%02u first escapes via [%06u]\n " dspTreeID (tree));
654-                 }
649+                 //  We generally don't see these in early IR. Bail for now.
650+                 // 
651+                 JITDUMP (" V%02u local field at [%06u]\n " dspTreeID (tree));
652+                 m_allocator->MarkLclVarAsEscaping (lclNum);
653+             }
654+             else 
655+             {
656+                 assert ((tree->OperIs (GT_LCL_ADDR) && (lclDsc->TypeGet () != TYP_STRUCT)));
657+                 JITDUMP (" V%02u address taken at [%06u]\n " dspTreeID (tree));
655658                m_allocator->MarkLclVarAsEscaping (lclNum);
656659            }
657-             else  if  (!tree->OperIsLocalStore ())
660+ 
661+             if  (!m_allocator->CanIndexEscape (lclIndex) && !tree->OperIsLocalStore ())
658662            {
659663                //  Note uses of variables of interest to conditional escape analysis.
660664                // 
@@ -1606,29 +1610,22 @@ unsigned int ObjectAllocator::MorphAllocObjNodeIntoStackAlloc(GenTreeAllocObj* a
16061610}
16071611
16081612// ------------------------------------------------------------------------
1609- //  CanLclVarEscapeViaParentStack : Check if the local variable escapes via the given parent stack.
1613+ //  AnalyzeParentStack : Check if the local variable escapes via the given parent stack.
16101614//                                 Update the connection graph as necessary.
16111615// 
16121616//  Arguments:
16131617//     parentStack     - Parent stack of the current visit
1614- //     lclNum           - Local variable number 
1618+ //     lclIndex         - Index for a tracked, unescaped local referenced at the top of the stack 
16151619//     block           - basic block holding the trees
16161620// 
1617- //  Return Value:
1618- //     true if the local can escape via the parent stack; false otherwise
1619- // 
1620- //  Notes:
1621- //     The method currently treats all locals assigned to a field as escaping.
1622- //     The can potentially be tracked by special field edges in the connection graph.
1623- // 
1624- bool  ObjectAllocator::CanLclVarEscapeViaParentStack (ArrayStack<GenTree*>* parentStack,
1625-                                                     unsigned  int           lclNum,
1626-                                                     BasicBlock*           block)
1621+ void  ObjectAllocator::AnalyzeParentStack (ArrayStack<GenTree*>* parentStack, unsigned  int  lclIndex, BasicBlock* block)
16271622{
16281623    assert (parentStack != nullptr );
1629-     int  parentIndex =  1 ;
1624+     assert (! CanIndexEscape (lclIndex)) ;
16301625
1631-     LclVarDsc* const  lclDsc = comp->lvaGetDesc (lclNum);
1626+     int               parentIndex = 1 ;
1627+     const  unsigned    lclNum      = IndexToLocal (lclIndex);
1628+     LclVarDsc* const  lclDsc      = comp->lvaGetDesc (lclNum);
16321629
16331630    bool        keepChecking                  = true ;
16341631    bool        canLclVarEscapeViaParentStack = true ;
@@ -1675,18 +1672,19 @@ bool ObjectAllocator::CanLclVarEscapeViaParentStack(ArrayStack<GenTree*>* parent
16751672                    break ;
16761673                }
16771674
1678-                 //  Add an edge to the connection graph.
1679-                 const  unsigned  int  srcLclNum = lclNum;
1675+                 const  unsigned  dstIndex = LocalToIndex (dstLclNum);
16801676
1681-                 AddConnGraphEdge (dstLclNum, srcLclNum);
1677+                 //  Add an edge to the connection graph.
1678+                 // 
1679+                 AddConnGraphEdgeIndex (dstIndex, lclIndex);
16821680                canLclVarEscapeViaParentStack = false ;
16831681
16841682                //  If the source of this store is an enumerator local,
16851683                //  then the dest also becomes an enumerator local.
16861684                // 
16871685                if  (isCopy)
16881686                {
1689-                     CheckForEnumeratorUse (srcLclNum , dstLclNum);
1687+                     CheckForEnumeratorUse (lclNum , dstLclNum);
16901688                }
16911689
16921690                //  Note that we modelled this store in the connection graph
@@ -1788,14 +1786,15 @@ bool ObjectAllocator::CanLclVarEscapeViaParentStack(ArrayStack<GenTree*>* parent
17881786
17891787                        if  (base->OperIs (GT_LCL_ADDR))
17901788                        {
1791-                             unsigned  const    dstLclNum = base->AsLclVarCommon ()->GetLclNum ();
1792-                             LclVarDsc* const  dstDsc    = comp->lvaGetDesc (dstLclNum);
1789+                             unsigned  const  dstLclNum = base->AsLclVarCommon ()->GetLclNum ();
17931790
17941791                            if  (IsTrackedLocal (dstLclNum))
17951792                            {
17961793                                JITDUMP (" ... local.field store\n " 
1794+                                 const  unsigned  dstIndex = LocalToIndex (dstLclNum);
17971795                                //  Add an edge to the connection graph.
1798-                                 AddConnGraphEdge (dstLclNum, lclNum);
1796+                                 // 
1797+                                 AddConnGraphEdgeIndex (dstIndex, lclIndex);
17991798                                canLclVarEscapeViaParentStack = false ;
18001799                            }
18011800                        }
@@ -1902,7 +1901,12 @@ bool ObjectAllocator::CanLclVarEscapeViaParentStack(ArrayStack<GenTree*>* parent
19021901        }
19031902    }
19041903
1905-     return  canLclVarEscapeViaParentStack;
1904+     if  (canLclVarEscapeViaParentStack)
1905+     {
1906+         JITDUMP (" V%02u first escapes via [%06u]...[%06u]\n " dspTreeID (parentStack->Top ()),
1907+                 comp->dspTreeID (parentStack->Top (parentIndex)));
1908+         MarkLclVarAsEscaping (lclNum);
1909+     }
19061910}
19071911
19081912// ------------------------------------------------------------------------
@@ -2510,11 +2514,11 @@ bool ObjectAllocator::AnalyzeIfCloningCanPreventEscape(BitVecTraits* bitVecTrait
25102514
25112515        //  See what locals were "assigned" to the pseudo.
25122516        // 
2513-         BitVec PseudoAdjacencies  = m_ConnGraphAdjacencyMatrix[pseudoIndex];
2517+         BitVec pseudoAdjacencies  = m_ConnGraphAdjacencyMatrix[pseudoIndex];
25142518
25152519        //  If we found an allocation but didn't find any conditionally escaping uses, then cloning is of no use
25162520        // 
2517-         if  (BitVecOps::IsEmpty (bitVecTraits, PseudoAdjacencies ))
2521+         if  (BitVecOps::IsEmpty (bitVecTraits, pseudoAdjacencies ))
25182522        {
25192523            JITDUMP ("    No conditionally escaping uses under" 
25202524            JITDUMPEXEC (DumpIndex (pseudoIndex));
@@ -2525,7 +2529,7 @@ bool ObjectAllocator::AnalyzeIfCloningCanPreventEscape(BitVecTraits* bitVecTrait
25252529
25262530        //  Check if each conditionally escaping local escapes on its own; if so cloning is of no use
25272531        // 
2528-         BitVecOps::Iter iterator (bitVecTraits, PseudoAdjacencies );
2532+         BitVecOps::Iter iterator (bitVecTraits, pseudoAdjacencies );
25292533        unsigned         lclNumIndex = BAD_VAR_NUM;
25302534        while  (canClone && iterator.NextElem (&lclNumIndex))
25312535        {
0 commit comments