Skip to content

Commit 7c05ef1

Browse files
authored
JIT: stop tracking TYP_I_IMPL locals in escape analysis (#114130)
Abstractly a non-GC local can't cause escape. On 32 bit platforms tracking connections to `TYP_I_IMPL` leads to confusion once we start struct field tracking, as we logically "overlay" GC and non-GC fields. Contributes to #104936
1 parent 5d51698 commit 7c05ef1

File tree

1 file changed

+51
-6
lines changed

1 file changed

+51
-6
lines changed

src/coreclr/jit/objectalloc.cpp

Lines changed: 51 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ ObjectAllocator::ObjectAllocator(Compiler* comp)
7171
//
7272
bool ObjectAllocator::IsTrackedType(var_types type)
7373
{
74-
const bool isTrackableScalar = (type == TYP_REF) || (genActualType(type) == TYP_I_IMPL) || (type == TYP_BYREF);
74+
const bool isTrackableScalar = (type == TYP_REF) || (type == TYP_BYREF);
7575
return isTrackableScalar;
7676
}
7777

@@ -1579,12 +1579,19 @@ bool ObjectAllocator::CanLclVarEscapeViaParentStack(ArrayStack<GenTree*>* parent
15791579

15801580
switch (parent->OperGet())
15811581
{
1582-
// Update the connection graph if we are storing to a local.
1583-
// For all other stores we mark the local as escaping.
15841582
case GT_STORE_LCL_VAR:
15851583
{
1586-
// Add an edge to the connection graph.
15871584
const unsigned int dstLclNum = parent->AsLclVar()->GetLclNum();
1585+
1586+
// If we're not tracking stores to this local, the value
1587+
// does not escape.
1588+
if (!IsTrackedLocal(dstLclNum))
1589+
{
1590+
canLclVarEscapeViaParentStack = false;
1591+
break;
1592+
}
1593+
1594+
// Add an edge to the connection graph.
15881595
const unsigned int srcLclNum = lclNum;
15891596

15901597
AddConnGraphEdge(dstLclNum, srcLclNum);
@@ -1626,13 +1633,25 @@ bool ObjectAllocator::CanLclVarEscapeViaParentStack(ArrayStack<GenTree*>* parent
16261633
case GT_COLON:
16271634
case GT_QMARK:
16281635
case GT_ADD:
1629-
case GT_SUB:
16301636
case GT_FIELD_ADDR:
16311637
// Check whether the local escapes via its grandparent.
16321638
++parentIndex;
16331639
keepChecking = true;
16341640
break;
16351641

1642+
case GT_SUB:
1643+
// Sub of two GC refs is no longer a GC ref.
1644+
if (!parent->TypeIs(TYP_BYREF, TYP_REF))
1645+
{
1646+
canLclVarEscapeViaParentStack = false;
1647+
break;
1648+
}
1649+
1650+
// Check whether the local escapes higher up
1651+
++parentIndex;
1652+
keepChecking = true;
1653+
break;
1654+
16361655
case GT_BOX:
16371656
isCopy = wasCopy;
16381657
++parentIndex;
@@ -1787,7 +1806,6 @@ void ObjectAllocator::UpdateAncestorTypes(GenTree* tree, ArrayStack<GenTree*>* p
17871806
FALLTHROUGH;
17881807
case GT_QMARK:
17891808
case GT_ADD:
1790-
case GT_SUB:
17911809
case GT_FIELD_ADDR:
17921810
case GT_INDEX_ADDR:
17931811
case GT_BOX:
@@ -1799,6 +1817,33 @@ void ObjectAllocator::UpdateAncestorTypes(GenTree* tree, ArrayStack<GenTree*>* p
17991817
keepChecking = true;
18001818
break;
18011819

1820+
case GT_SUB:
1821+
{
1822+
// Parent type can be TYP_I_IMPL, TYP_BYREF.
1823+
// But not TYP_REF.
1824+
//
1825+
var_types parentType = parent->TypeGet();
1826+
assert(parentType != TYP_REF);
1827+
1828+
// New type can be TYP_I_IMPL, TYP_BYREF.
1829+
// But TYP_BYREF only if parent is also
1830+
//
1831+
if (parentType != newType)
1832+
{
1833+
// We must be retyping TYP_BYREF to TYP_I_IMPL.
1834+
//
1835+
assert(newType == TYP_I_IMPL);
1836+
assert(parentType == TYP_BYREF);
1837+
parent->ChangeType(newType);
1838+
1839+
// Propgate that upwards.
1840+
//
1841+
++parentIndex;
1842+
keepChecking = true;
1843+
}
1844+
break;
1845+
}
1846+
18021847
case GT_COLON:
18031848
{
18041849
GenTree* const lhs = parent->AsOp()->gtGetOp1();

0 commit comments

Comments
 (0)