Skip to content

Commit 0d90354

Browse files
authored
JIT: remember indir store addresses in escape analysis (#115689)
Instead of analyzing the indir store address when we are processing the stored value, save off the address bvIndex when processing the address.
1 parent af6a2c1 commit 0d90354

File tree

3 files changed

+64
-40
lines changed

3 files changed

+64
-40
lines changed

src/coreclr/jit/jitconfigvalues.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -686,6 +686,7 @@ RELEASE_CONFIG_INTEGER(JitObjectStackAllocationArray, "JitObjectStackAllocationA
686686
RELEASE_CONFIG_INTEGER(JitObjectStackAllocationSize, "JitObjectStackAllocationSize", 528)
687687
RELEASE_CONFIG_INTEGER(JitObjectStackAllocationTrackFields, "JitObjectStackAllocationTrackFields", 1)
688688
CONFIG_STRING(JitObjectStackAllocationTrackFieldsRange, "JitObjectStackAllocationTrackFieldsRange")
689+
CONFIG_INTEGER(JitObjectStackAllocationDumpConnGraph, "JitObjectStackAllocationDumpConnGraph", 0)
689690

690691
RELEASE_CONFIG_INTEGER(JitEECallTimingInfo, "JitEECallTimingInfo", 0)
691692

src/coreclr/jit/objectalloc.cpp

Lines changed: 60 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ ObjectAllocator::ObjectAllocator(Compiler* comp)
5151
, m_maxPseudos(0)
5252
, m_regionsToClone(0)
5353
, m_trackFields(false)
54+
, m_StoreAddressToIndexMap(comp->getAllocator(CMK_ObjectAllocator))
5455
{
5556
m_EscapingPointers = BitVecOps::UninitVal();
5657
m_PossiblyStackPointingPointers = BitVecOps::UninitVal();
@@ -564,6 +565,34 @@ void ObjectAllocator::DoAnalysis()
564565
ComputeEscapingNodes(&m_bitVecTraits, m_EscapingPointers);
565566
}
566567

568+
#ifdef DEBUG
569+
// Print the connection graph
570+
//
571+
if (JitConfig.JitObjectStackAllocationDumpConnGraph() > 0)
572+
{
573+
JITDUMP("digraph ConnectionGraph {\n");
574+
for (unsigned int i = 0; i < m_bvCount; i++)
575+
{
576+
BitVecOps::Iter iterator(&m_bitVecTraits, m_ConnGraphAdjacencyMatrix[i]);
577+
unsigned int lclIndex;
578+
while (iterator.NextElem(&lclIndex))
579+
{
580+
JITDUMPEXEC(DumpIndex(lclIndex));
581+
JITDUMP(" -> ");
582+
JITDUMPEXEC(DumpIndex(i));
583+
JITDUMP(";\n");
584+
}
585+
586+
if (CanIndexEscape(i))
587+
{
588+
JITDUMPEXEC(DumpIndex(i));
589+
JITDUMP(" -> E;\n");
590+
}
591+
}
592+
JITDUMP("}\n");
593+
}
594+
#endif
595+
567596
m_AnalysisDone = true;
568597
}
569598

@@ -1731,6 +1760,7 @@ void ObjectAllocator::AnalyzeParentStack(ArrayStack<GenTree*>* parentStack, unsi
17311760
}
17321761

17331762
// Check whether the local escapes higher up
1763+
isAddress = false;
17341764
++parentIndex;
17351765
keepChecking = true;
17361766
break;
@@ -1755,58 +1785,49 @@ void ObjectAllocator::AnalyzeParentStack(ArrayStack<GenTree*>* parentStack, unsi
17551785

17561786
case GT_STOREIND:
17571787
case GT_STORE_BLK:
1758-
case GT_BLK:
17591788
{
17601789
GenTree* const addr = parent->AsIndir()->Addr();
17611790
if (tree == addr)
17621791
{
1763-
JITDUMP("... store address\n");
1792+
if (isAddress)
1793+
{
1794+
// Remember the resource being stored to.
1795+
//
1796+
JITDUMP("... store address\n");
1797+
m_StoreAddressToIndexMap.Set(tree, lclIndex);
1798+
}
1799+
1800+
// The address does not escape
1801+
//
17641802
canLclVarEscapeViaParentStack = false;
17651803
break;
17661804
}
17671805

1768-
// If the value being stored is a local address, anything assigned to that local escapes
1806+
// Is this a store to a tracked resource?
17691807
//
1770-
if (isAddress)
1808+
unsigned dstIndex;
1809+
if (m_trackFields && m_StoreAddressToIndexMap.Lookup(addr, &dstIndex) && (dstIndex != BAD_VAR_NUM))
17711810
{
1772-
break;
1773-
}
1811+
JITDUMP("... local.field store\n");
17741812

1775-
// Is this a store to a field of a local struct...?
1776-
//
1777-
if (parent->OperIs(GT_STOREIND))
1778-
{
1779-
// Are we storing to a local field?
1780-
//
1781-
if (addr->OperIs(GT_FIELD_ADDR))
1813+
if (!isAddress)
17821814
{
1783-
// Simple check for which local.
1784-
//
1785-
GenTree* const base = addr->AsOp()->gtGetOp1();
1786-
1787-
if (base->OperIs(GT_LCL_ADDR))
1788-
{
1789-
unsigned const dstLclNum = base->AsLclVarCommon()->GetLclNum();
1790-
1791-
if (IsTrackedLocal(dstLclNum))
1792-
{
1793-
JITDUMP("... local.field store\n");
1794-
const unsigned dstIndex = LocalToIndex(dstLclNum);
1795-
// Add an edge to the connection graph.
1796-
//
1797-
AddConnGraphEdgeIndex(dstIndex, lclIndex);
1798-
canLclVarEscapeViaParentStack = false;
1799-
}
1800-
}
1815+
AddConnGraphEdgeIndex(dstIndex, lclIndex);
1816+
canLclVarEscapeViaParentStack = false;
1817+
break;
1818+
}
1819+
else
1820+
{
1821+
AddConnGraphEdgeIndex(dstIndex, m_unknownSourceIndex);
18011822
}
1802-
1803-
// Else we're storing the value somewhere unknown.
1804-
// Assume the worst.
18051823
}
1824+
1825+
// We're storing the value somewhere unknown. Assume the worst.
18061826
break;
18071827
}
18081828

18091829
case GT_IND:
1830+
case GT_BLK:
18101831
{
18111832
// Does this load a type we're tracking?
18121833
//
@@ -1820,12 +1841,12 @@ void ObjectAllocator::AnalyzeParentStack(ArrayStack<GenTree*>* parentStack, unsi
18201841

18211842
// For loads from local structs we may be tracking the underlying fields.
18221843
//
1823-
// We can assume that the local being read is lclNum, since we have walked up to this node from a leaf
1824-
// local.
1844+
// We can assume that the local being read is lclNum,
1845+
// since we have walked up to this node from a leaf local.
18251846
//
18261847
// We only track through the first indir.
18271848
//
1828-
if (m_trackFields && isAddress && addr->OperIs(GT_FIELD_ADDR))
1849+
if (m_trackFields && isAddress)
18291850
{
18301851
JITDUMP("... load local.field\n");
18311852
++parentIndex;
@@ -2076,7 +2097,6 @@ void ObjectAllocator::UpdateAncestorTypes(GenTree* tree,
20762097

20772098
case GT_STOREIND:
20782099
case GT_STORE_BLK:
2079-
case GT_BLK:
20802100
{
20812101
if (tree == parent->AsIndir()->Addr())
20822102
{
@@ -2107,10 +2127,11 @@ void ObjectAllocator::UpdateAncestorTypes(GenTree* tree,
21072127
}
21082128

21092129
case GT_IND:
2130+
case GT_BLK:
21102131
{
21112132
// If we are loading from a GC struct field, we may need to retype the load
21122133
//
2113-
if (retypeFields && (tree->OperIs(GT_FIELD_ADDR)) && (varTypeIsGC(parent->TypeGet())))
2134+
if (retypeFields && (varTypeIsGC(parent->TypeGet())))
21142135
{
21152136
parent->ChangeType(newType);
21162137
++parentIndex;

src/coreclr/jit/objectalloc.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,7 @@ struct CloneInfo : public GuardInfo
110110
};
111111

112112
typedef JitHashTable<unsigned, JitSmallPrimitiveKeyFuncs<unsigned>, CloneInfo*> CloneMap;
113+
typedef JitHashTable<GenTree*, JitPtrKeyFuncs<GenTree>, unsigned> NodeToIndexMap;
113114

114115
class ObjectAllocator final : public Phase
115116
{
@@ -148,7 +149,8 @@ class ObjectAllocator final : public Phase
148149
unsigned m_regionsToClone;
149150

150151
// Struct fields
151-
bool m_trackFields;
152+
bool m_trackFields;
153+
NodeToIndexMap m_StoreAddressToIndexMap;
152154

153155
//===============================================================================
154156
// Methods

0 commit comments

Comments
 (0)