Skip to content

Commit 8f6af6e

Browse files
authored
JIT: Reorder physical promotion and forward sub (#87265)
Physical promotion breaks more forward sub opportunities than it introduces, so reorder these phases. Then teach physical promotion to recognize when it creates new opportunities and selectively reinvoke forward sub for just those cases.
1 parent 37c0371 commit 8f6af6e

File tree

4 files changed

+63
-9
lines changed

4 files changed

+63
-9
lines changed

src/coreclr/jit/compiler.cpp

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4716,14 +4716,14 @@ void Compiler::compCompile(void** methodCodePtr, uint32_t* methodCodeSize, JitFl
47164716
//
47174717
DoPhase(this, PHASE_EARLY_LIVENESS, &Compiler::fgEarlyLiveness);
47184718

4719-
// Promote struct locals based on primitive access patterns
4720-
//
4721-
DoPhase(this, PHASE_PHYSICAL_PROMOTION, &Compiler::PhysicalPromotion);
4722-
47234719
// Run a simple forward substitution pass.
47244720
//
47254721
DoPhase(this, PHASE_FWD_SUB, &Compiler::fgForwardSub);
47264722

4723+
// Promote struct locals based on primitive access patterns
4724+
//
4725+
DoPhase(this, PHASE_PHYSICAL_PROMOTION, &Compiler::PhysicalPromotion);
4726+
47274727
// Locals tree list is no longer kept valid.
47284728
fgNodeThreading = NodeThreading::None;
47294729

src/coreclr/jit/promotion.cpp

Lines changed: 40 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1358,6 +1358,7 @@ void ReplaceVisitor::LoadStoreAroundCall(GenTreeCall* call, GenTree* user)
13581358
if ((m_aggregates[argNodeLcl->GetLclNum()] != nullptr) && IsPromotedStructLocalDying(argNodeLcl))
13591359
{
13601360
argNodeLcl->gtFlags |= GTF_VAR_DEATH;
1361+
CheckForwardSubForLastUse(argNodeLcl->GetLclNum());
13611362
}
13621363
}
13631364
}
@@ -1498,7 +1499,11 @@ void ReplaceVisitor::ReplaceLocal(GenTree** use, GenTree* user)
14981499
*use = m_compiler->gtNewLclvNode(rep.LclNum, accessType);
14991500
}
15001501

1501-
(*use)->gtFlags |= lcl->gtFlags & GTF_VAR_DEATH;
1502+
if ((lcl->gtFlags & GTF_VAR_DEATH) != 0)
1503+
{
1504+
(*use)->gtFlags |= GTF_VAR_DEATH;
1505+
CheckForwardSubForLastUse(rep.LclNum);
1506+
}
15021507

15031508
if (isDef)
15041509
{
@@ -1540,6 +1545,30 @@ void ReplaceVisitor::ReplaceLocal(GenTree** use, GenTree* user)
15401545
m_madeChanges = true;
15411546
}
15421547

1548+
//------------------------------------------------------------------------
1549+
// CheckForwardSubForLastUse:
1550+
// Indicate that a local has a last use in the current statement and that
1551+
// there thus may be a forward substitution opportunity.
1552+
//
1553+
// Parameters:
1554+
// lclNum - The local number with a last use in this statement.
1555+
//
1556+
void ReplaceVisitor::CheckForwardSubForLastUse(unsigned lclNum)
1557+
{
1558+
if (m_currentBlock->firstStmt() == m_currentStmt)
1559+
{
1560+
return;
1561+
}
1562+
1563+
Statement* prevStmt = m_currentStmt->GetPrevStmt();
1564+
GenTree* prevNode = prevStmt->GetRootNode();
1565+
1566+
if (prevNode->OperIsLocalStore() && (prevNode->AsLclVarCommon()->GetLclNum() == lclNum))
1567+
{
1568+
m_mayHaveForwardSub = true;
1569+
}
1570+
}
1571+
15431572
//------------------------------------------------------------------------
15441573
// StoreBeforeReturn:
15451574
// Handle a return of a potential struct local.
@@ -1780,7 +1809,7 @@ PhaseStatus Promotion::Run()
17801809
for (Statement* stmt : bb->Statements())
17811810
{
17821811
DISPSTMT(stmt);
1783-
replacer.StartStatement();
1812+
replacer.StartStatement(stmt);
17841813
replacer.WalkTree(stmt->GetRootNodePointer(), nullptr);
17851814

17861815
if (replacer.MadeChanges())
@@ -1790,6 +1819,15 @@ PhaseStatus Promotion::Run()
17901819
JITDUMP("New statement:\n");
17911820
DISPSTMT(stmt);
17921821
}
1822+
1823+
if (replacer.MayHaveForwardSubOpportunity())
1824+
{
1825+
JITDUMP("Invoking forward sub due to a potential opportunity\n");
1826+
while ((stmt != bb->firstStmt()) && m_compiler->fgForwardSubStatement(stmt->GetPrevStmt()))
1827+
{
1828+
m_compiler->fgRemoveStmt(bb, stmt->GetPrevStmt());
1829+
}
1830+
}
17931831
}
17941832

17951833
replacer.EndBlock();

src/coreclr/jit/promotion.h

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -248,10 +248,14 @@ class DecompositionPlan;
248248

249249
class ReplaceVisitor : public GenTreeVisitor<ReplaceVisitor>
250250
{
251+
friend class DecompositionPlan;
252+
251253
jitstd::vector<AggregateInfo*>& m_aggregates;
252254
PromotionLiveness* m_liveness;
253255
bool m_madeChanges = false;
254256
bool m_hasPendingReadBacks = false;
257+
bool m_mayHaveForwardSub = false;
258+
Statement* m_currentStmt = nullptr;
255259
BasicBlock* m_currentBlock = nullptr;
256260

257261
public:
@@ -271,16 +275,23 @@ class ReplaceVisitor : public GenTreeVisitor<ReplaceVisitor>
271275
return m_madeChanges;
272276
}
273277

278+
bool MayHaveForwardSubOpportunity()
279+
{
280+
return m_mayHaveForwardSub;
281+
}
282+
274283
void StartBlock(BasicBlock* block)
275284
{
276285
m_currentBlock = block;
277286
}
278287

279288
void EndBlock();
280289

281-
void StartStatement()
290+
void StartStatement(Statement* stmt)
282291
{
283-
m_madeChanges = false;
292+
m_currentStmt = stmt;
293+
m_madeChanges = false;
294+
m_mayHaveForwardSub = false;
284295
}
285296

286297
fgWalkResult PostOrderVisit(GenTree** use, GenTree* user);
@@ -290,6 +301,7 @@ class ReplaceVisitor : public GenTreeVisitor<ReplaceVisitor>
290301
void LoadStoreAroundCall(GenTreeCall* call, GenTree* user);
291302
bool IsPromotedStructLocalDying(GenTreeLclVarCommon* structLcl);
292303
void ReplaceLocal(GenTree** use, GenTree* user);
304+
void CheckForwardSubForLastUse(unsigned lclNum);
293305
void StoreBeforeReturn(GenTreeUnOp* ret);
294306
void WriteBackBefore(GenTree** use, unsigned lcl, unsigned offs, unsigned size);
295307
bool MarkForReadBack(unsigned lcl, unsigned offs, unsigned size);

src/coreclr/jit/promotiondecomposition.cpp

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ class DecompositionPlan
5050
};
5151

5252
Compiler* m_compiler;
53+
ReplaceVisitor* m_replacer;
5354
jitstd::vector<AggregateInfo*>& m_aggregates;
5455
PromotionLiveness* m_liveness;
5556
GenTree* m_store;
@@ -61,13 +62,15 @@ class DecompositionPlan
6162

6263
public:
6364
DecompositionPlan(Compiler* comp,
65+
ReplaceVisitor* replacer,
6466
jitstd::vector<AggregateInfo*>& aggregates,
6567
PromotionLiveness* liveness,
6668
GenTree* store,
6769
GenTree* src,
6870
bool dstInvolvesReplacements,
6971
bool srcInvolvesReplacements)
7072
: m_compiler(comp)
73+
, m_replacer(replacer)
7174
, m_aggregates(aggregates)
7275
, m_liveness(liveness)
7376
, m_store(store)
@@ -718,6 +721,7 @@ class DecompositionPlan
718721
if (srcDeaths.IsReplacementDying((unsigned)replacementIndex))
719722
{
720723
src->gtFlags |= GTF_VAR_DEATH;
724+
m_replacer->CheckForwardSubForLastUse(entry.FromLclNum);
721725
}
722726
}
723727
}
@@ -1083,7 +1087,7 @@ void ReplaceVisitor::HandleStore(GenTree** use, GenTree* user)
10831087
DecompositionStatementList result;
10841088
EliminateCommasInBlockOp(store, &result);
10851089

1086-
DecompositionPlan plan(m_compiler, m_aggregates, m_liveness, store, src, dstInvolvesReplacements,
1090+
DecompositionPlan plan(m_compiler, this, m_aggregates, m_liveness, store, src, dstInvolvesReplacements,
10871091
srcInvolvesReplacements);
10881092

10891093
if (dstInvolvesReplacements)

0 commit comments

Comments
 (0)