Skip to content

Commit 6bae351

Browse files
Include dependently promoted fields in SSA (#77238)
* Remove quirks * Early prop fix for call asgs * Include all tracked locals in SSA * Remove a (now incorrect) comment * Fix a typo * Encoding fixes 1) The definition of SIMPLE_NUM_COUNT was wrong. 2) SsaNumInfo::Composite, in the compact case, did not clear the old value. 3) SsaNumInfo::Composite, in the outlined case, did not copy the already (compactly) encoded simple names. * Fix store numbering The load path needs to use the offset relative to the store's target location. * Clarify 'fieldValueOffset' calculations
1 parent 94cbc49 commit 6bae351

File tree

9 files changed

+50
-82
lines changed

9 files changed

+50
-82
lines changed

src/coreclr/jit/compiler.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2815,7 +2815,7 @@ class Compiler
28152815
bool gtIsStaticFieldPtrToBoxedStruct(var_types fieldNodeType, CORINFO_FIELD_HANDLE fldHnd);
28162816

28172817
bool gtStoreDefinesField(
2818-
LclVarDsc* fieldVarDsc, ssize_t offset, unsigned size, ssize_t* pFieldStoreOffset, unsigned* pFileStoreSize);
2818+
LclVarDsc* fieldVarDsc, ssize_t offset, unsigned size, ssize_t* pFieldStoreOffset, unsigned* pFieldStoreSize);
28192819

28202820
// Return true if call is a recursive call; return false otherwise.
28212821
// Note when inlining, this looks for calls back to the root method.

src/coreclr/jit/copyprop.cpp

Lines changed: 4 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -326,20 +326,12 @@ void Compiler::optCopyPropPushDef(GenTree* defNode, GenTreeLclVarCommon* lclNode
326326
LclVarDsc* varDsc = lvaGetDesc(lclNum);
327327
assert(varDsc->lvPromoted);
328328

329-
if (varDsc->CanBeReplacedWithItsField(this))
329+
for (unsigned index = 0; index < varDsc->lvFieldCnt; index++)
330330
{
331-
// TODO-CQ: remove this zero-diff quirk.
332-
pushDef(varDsc->lvFieldLclStart, SsaConfig::RESERVED_SSA_NUM);
333-
}
334-
else
335-
{
336-
for (unsigned index = 0; index < varDsc->lvFieldCnt; index++)
331+
unsigned ssaNum = lclNode->GetSsaNum(this, index);
332+
if (ssaNum != SsaConfig::RESERVED_SSA_NUM)
337333
{
338-
unsigned ssaNum = lclNode->GetSsaNum(this, index);
339-
if (ssaNum != SsaConfig::RESERVED_SSA_NUM)
340-
{
341-
pushDef(varDsc->lvFieldLclStart + index, ssaNum);
342-
}
334+
pushDef(varDsc->lvFieldLclStart + index, ssaNum);
343335
}
344336
}
345337
}

src/coreclr/jit/earlyprop.cpp

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -364,13 +364,10 @@ GenTree* Compiler::optPropGetValueRec(unsigned lclNum, unsigned ssaNum, optPropK
364364
LclSsaVarDsc* ssaVarDsc = lvaTable[lclNum].GetPerSsaData(ssaNum);
365365
GenTreeOp* ssaDefAsg = ssaVarDsc->GetAssignment();
366366

367-
if (ssaDefAsg == nullptr)
368-
{
369-
// Incoming parameters or live-in variables don't have actual definition tree node
370-
// for their FIRST_SSA_NUM. See SsaBuilder::RenameVariables.
371-
assert(ssaNum == SsaConfig::FIRST_SSA_NUM);
372-
}
373-
else
367+
// Incoming parameters or live-in variables don't have actual definition tree node for
368+
// their FIRST_SSA_NUM. Definitions induced by calls do not record the store node. See
369+
// SsaBuilder::RenameDef.
370+
if (ssaDefAsg != nullptr)
374371
{
375372
assert(ssaDefAsg->OperIs(GT_ASG));
376373

@@ -569,8 +566,19 @@ GenTree* Compiler::optFindNullCheckToFold(GenTree* tree, LocalNumberToNullCheckT
569566
return nullptr;
570567
}
571568

572-
GenTree* defRHS = defLoc->GetAssignment()->gtGetOp2();
569+
GenTree* defNode = defLoc->GetAssignment();
570+
if (defNode == nullptr)
571+
{
572+
return nullptr;
573+
}
574+
575+
GenTree* defLHS = defNode->gtGetOp1();
576+
if (!defLHS->OperIs(GT_LCL_VAR) || (defLHS->AsLclVar()->GetLclNum() != lclNum))
577+
{
578+
return nullptr;
579+
}
573580

581+
GenTree* defRHS = defNode->gtGetOp2();
574582
if (defRHS->OperGet() != GT_COMMA)
575583
{
576584
return nullptr;

src/coreclr/jit/gentree.cpp

Lines changed: 22 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -17626,15 +17626,15 @@ bool Compiler::gtIsStaticFieldPtrToBoxedStruct(var_types fieldNodeType, CORINFO_
1762617626
// size - Size of the store in bytes
1762717627
// pFieldStoreOffset - [out] parameter for the store's offset relative
1762817628
// to the field local itself
17629-
// pFileStoreSize - [out] parameter for the amount of the field's
17629+
// pFieldStoreSize - [out] parameter for the amount of the field's
1763017630
// local's bytes affected by the store
1763117631
//
1763217632
// Return Value:
1763317633
// If the given store affects the given field local, "true, "false"
1763417634
// otherwise.
1763517635
//
1763617636
bool Compiler::gtStoreDefinesField(
17637-
LclVarDsc* fieldVarDsc, ssize_t offset, unsigned size, ssize_t* pFieldStoreOffset, unsigned* pFileStoreSize)
17637+
LclVarDsc* fieldVarDsc, ssize_t offset, unsigned size, ssize_t* pFieldStoreOffset, unsigned* pFieldStoreSize)
1763817638
{
1763917639
ssize_t fieldOffset = fieldVarDsc->lvFldOffset;
1764017640
unsigned fieldSize = genTypeSize(fieldVarDsc); // No TYP_STRUCT field locals.
@@ -17644,7 +17644,7 @@ bool Compiler::gtStoreDefinesField(
1764417644
if ((fieldOffset < storeEndOffset) && (offset < fieldEndOffset))
1764517645
{
1764617646
*pFieldStoreOffset = (offset < fieldOffset) ? 0 : (offset - fieldOffset);
17647-
*pFileStoreSize = static_cast<unsigned>(min(storeEndOffset, fieldEndOffset) - max(offset, fieldOffset));
17647+
*pFieldStoreSize = static_cast<unsigned>(min(storeEndOffset, fieldEndOffset) - max(offset, fieldOffset));
1764817648

1764917649
return true;
1765017650
}
@@ -23790,10 +23790,10 @@ unsigned* SsaNumInfo::GetOutlinedNumSlot(Compiler* compiler, unsigned index) con
2379023790
return SsaNumInfo(COMPOSITE_ENCODING_BIT | ssaNumEncoded);
2379123791
}
2379223792

23793-
return SsaNumInfo(ssaNumEncoded | baseNum.m_value);
23793+
return SsaNumInfo(ssaNumEncoded | (baseNum.m_value & ~(SIMPLE_NUM_MASK << (index * BITS_PER_SIMPLE_NUM))));
2379423794
}
2379523795

23796-
if (!baseNum.IsInvalid())
23796+
if (!baseNum.IsInvalid() && !baseNum.HasCompactFormat())
2379723797
{
2379823798
*baseNum.GetOutlinedNumSlot(compiler, index) = ssaNum;
2379923799
return baseNum;
@@ -23807,11 +23807,23 @@ unsigned* SsaNumInfo::GetOutlinedNumSlot(Compiler* compiler, unsigned index) con
2380723807
}
2380823808

2380923809
// Allocate a new chunk for the field numbers. Once allocated, it cannot be expanded.
23810-
int count = compiler->lvaGetDesc(parentLclNum)->lvFieldCnt;
23811-
JitExpandArrayStack<unsigned>* table = compiler->m_outlinedCompositeSsaNums;
23812-
int outIdx = table->Size();
23813-
unsigned* pLastSlot = &table->GetRef(outIdx + count - 1); // This will grow the table.
23814-
pLastSlot[-(count - 1) + static_cast<int>(index)] = ssaNum;
23810+
int count = compiler->lvaGetDesc(parentLclNum)->lvFieldCnt;
23811+
JitExpandArrayStack<unsigned>* table = compiler->m_outlinedCompositeSsaNums;
23812+
int outIdx = table->Size();
23813+
unsigned* pLastSlot = &table->GetRef(outIdx + count - 1); // This will grow the table.
23814+
unsigned* pFirstSlot = pLastSlot - count + 1;
23815+
23816+
// Copy over all of the already encoded numbers.
23817+
if (!baseNum.IsInvalid())
23818+
{
23819+
for (int i = 0; i < SIMPLE_NUM_COUNT; i++)
23820+
{
23821+
pFirstSlot[i] = baseNum.GetNum(compiler, i);
23822+
}
23823+
}
23824+
23825+
// Copy the one being set last to overwrite any previous values.
23826+
pFirstSlot[index] = ssaNum;
2381523827

2381623828
// Split the index if it does not fit into a small encoding.
2381723829
if ((outIdx & ~OUTLINED_INDEX_LOW_MASK) != 0)

src/coreclr/jit/gentree.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3538,7 +3538,7 @@ class SsaNumInfo final
35383538
static const int BITS_PER_SIMPLE_NUM = 8;
35393539
static const int MAX_SIMPLE_NUM = (1 << (BITS_PER_SIMPLE_NUM - 1)) - 1;
35403540
static const int SIMPLE_NUM_MASK = MAX_SIMPLE_NUM;
3541-
static const int SIMPLE_NUM_COUNT = sizeof(int) / BITS_PER_SIMPLE_NUM;
3541+
static const int SIMPLE_NUM_COUNT = (sizeof(int) * BITS_PER_BYTE) / BITS_PER_SIMPLE_NUM;
35423542
static const int COMPOSITE_ENCODING_BIT = 1 << 31;
35433543
static const int OUTLINED_ENCODING_BIT = 1 << 15;
35443544
static const int OUTLINED_INDEX_LOW_MASK = OUTLINED_ENCODING_BIT - 1;

src/coreclr/jit/morphblock.cpp

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -814,8 +814,6 @@ void MorphCopyBlockHelper::TrySpecialCases()
814814
{
815815
assert(m_dst->OperIs(GT_LCL_VAR));
816816

817-
// This will exclude field locals (if any) from SSA: we do not have a way to
818-
// associate multiple SSA definitions (SSA numbers) with one store.
819817
m_dstVarDsc->lvIsMultiRegRet = true;
820818

821819
JITDUMP("Not morphing a multireg node return\n");

src/coreclr/jit/ssabuilder.cpp

Lines changed: 1 addition & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -1584,7 +1584,7 @@ void SsaBuilder::Build()
15841584
// Mark all variables that will be tracked by SSA
15851585
for (unsigned lclNum = 0; lclNum < m_pCompiler->lvaCount; lclNum++)
15861586
{
1587-
m_pCompiler->lvaTable[lclNum].lvInSsa = IncludeInSsa(lclNum);
1587+
m_pCompiler->lvaTable[lclNum].lvInSsa = m_pCompiler->lvaGetDesc(lclNum)->lvTracked;
15881588
}
15891589

15901590
// Insert phi functions.
@@ -1641,45 +1641,6 @@ void SsaBuilder::SetupBBRoot()
16411641
}
16421642
}
16431643

1644-
//------------------------------------------------------------------------
1645-
// IncludeInSsa: Check if the specified variable can be included in SSA.
1646-
//
1647-
// Arguments:
1648-
// lclNum - the variable number
1649-
//
1650-
// Return Value:
1651-
// true if the variable is included in SSA
1652-
//
1653-
bool SsaBuilder::IncludeInSsa(unsigned lclNum)
1654-
{
1655-
LclVarDsc* varDsc = m_pCompiler->lvaGetDesc(lclNum);
1656-
1657-
if (!varDsc->lvTracked)
1658-
{
1659-
return false; // SSA is only done for tracked variables
1660-
}
1661-
// lvPromoted structs are never tracked...
1662-
assert(!varDsc->lvPromoted);
1663-
1664-
if (varDsc->lvIsStructField &&
1665-
(m_pCompiler->lvaGetParentPromotionType(lclNum) != Compiler::PROMOTION_TYPE_INDEPENDENT))
1666-
{
1667-
// SSA must exclude struct fields that are not independent
1668-
// - because we don't model the struct assignment properly when multiple fields can be assigned by one struct
1669-
// assignment.
1670-
// - SSA doesn't allow a single node to contain multiple SSA definitions.
1671-
// - and PROMOTION_TYPE_DEPENDEDNT fields are never candidates for a register.
1672-
//
1673-
return false;
1674-
}
1675-
else if (varDsc->lvIsStructField && m_pCompiler->lvaGetDesc(varDsc->lvParentLcl)->lvIsMultiRegRet)
1676-
{
1677-
return false;
1678-
}
1679-
// otherwise this variable is included in SSA
1680-
return true;
1681-
}
1682-
16831644
#ifdef DEBUG
16841645

16851646
//------------------------------------------------------------------------

src/coreclr/jit/ssabuilder.h

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,6 @@ class SsaBuilder
2020
m_pCompiler->EndPhase(phase);
2121
}
2222

23-
bool IncludeInSsa(unsigned lclNum);
24-
2523
public:
2624
// Constructor
2725
SsaBuilder(Compiler* pCompiler);

src/coreclr/jit/valuenum.cpp

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4966,8 +4966,12 @@ void Compiler::fgValueNumberLocalStore(GenTree* storeNode,
49664966
// Avoid redundant bitcasts for the common case of a full definition.
49674967
fieldStoreType = fieldVarDsc->TypeGet();
49684968
}
4969+
4970+
// Calculate offset of this field's value, relative to the entire one.
4971+
ssize_t fieldOffset = fieldVarDsc->lvFldOffset;
4972+
ssize_t fieldValueOffset = (fieldOffset < offset) ? 0 : (fieldOffset - offset);
49694973
ValueNumPair fieldStoreValue =
4970-
vnStore->VNPairForLoad(value, storeSize, fieldStoreType, offset, fieldStoreSize);
4974+
vnStore->VNPairForLoad(value, storeSize, fieldStoreType, fieldValueOffset, fieldStoreSize);
49714975

49724976
processDef(fieldLclNum, lclDefNode->GetSsaNum(this, index), fieldStoreOffset, fieldStoreSize,
49734977
fieldStoreValue);
@@ -8503,11 +8507,6 @@ void Compiler::fgValueNumberBlockAssignment(GenTree* tree)
85038507

85048508
rhsVNPair.SetBoth(initObjVN);
85058509
}
8506-
else if (lhs->OperIs(GT_LCL_VAR) && lhsVarDsc->CanBeReplacedWithItsField(this))
8507-
{
8508-
// TODO-CQ: remove this zero-diff quirk.
8509-
rhsVNPair.SetBoth(vnStore->VNForExpr(compCurBB, lvaGetDesc(lhsVarDsc->lvFieldLclStart)->TypeGet()));
8510-
}
85118510
else
85128511
{
85138512
assert(tree->OperIsCopyBlkOp());

0 commit comments

Comments
 (0)