Skip to content

Commit 663d39f

Browse files
JIT: Reduce heuristics-derived edge likelihoods into throw blocks found by morph (#116637)
1 parent c154588 commit 663d39f

File tree

9 files changed

+142
-1
lines changed

9 files changed

+142
-1
lines changed

src/coreclr/jit/block.h

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -594,6 +594,9 @@ struct FlowEdge
594594
// Convenience flag for phases that need to track edge visitation
595595
bool m_visited;
596596

597+
// Indicates if m_likelihood was determined using profile synthesis's heuristics
598+
bool m_heuristicBasedLikelihood;
599+
597600
// True if likelihood has been set
598601
INDEBUG(bool m_likelihoodSet);
599602

@@ -605,6 +608,7 @@ struct FlowEdge
605608
, m_likelihood(0)
606609
, m_dupCount(0)
607610
, m_visited(false)
611+
, m_heuristicBasedLikelihood(false)
608612
#ifdef DEBUG
609613
, m_likelihoodSet(false)
610614
#endif // DEBUG
@@ -661,7 +665,8 @@ struct FlowEdge
661665

662666
void clearLikelihood()
663667
{
664-
m_likelihood = 0.0;
668+
m_likelihood = 0.0;
669+
m_heuristicBasedLikelihood = false;
665670
INDEBUG(m_likelihoodSet = false);
666671
}
667672

@@ -706,6 +711,16 @@ struct FlowEdge
706711
assert(visited());
707712
m_visited = false;
708713
}
714+
715+
bool isHeuristicBased() const
716+
{
717+
return m_heuristicBasedLikelihood;
718+
}
719+
720+
void setHeuristicBased(bool isHeuristicBased)
721+
{
722+
m_heuristicBasedLikelihood = isHeuristicBased;
723+
}
709724
};
710725

711726
//------------------------------------------------------------------------

src/coreclr/jit/compiler.cpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
2121
#include "lower.h"
2222
#include "stacklevelsetter.h"
2323
#include "patchpointinfo.h"
24+
#include "fgprofilesynthesis.h"
2425
#include "jitstd/algorithm.h"
2526
#include "minipal/time.h"
2627

@@ -4592,6 +4593,14 @@ void Compiler::compCompile(void** methodCodePtr, uint32_t* methodCodeSize, JitFl
45924593
//
45934594
DoPhase(this, PHASE_DFS_BLOCKS3, &Compiler::fgDfsBlocksAndRemove);
45944595

4596+
auto adjustThrowEdgeLikelihoods = [this]() -> PhaseStatus {
4597+
return ProfileSynthesis::AdjustThrowEdgeLikelihoods(this);
4598+
};
4599+
4600+
// Adjust heuristic-derived edge likelihoods into paths that are known to throw.
4601+
//
4602+
DoPhase(this, PHASE_ADJUST_THROW_LIKELIHOODS, adjustThrowEdgeLikelihoods);
4603+
45954604
// Discover and classify natural loops (e.g. mark iterative loops as such).
45964605
//
45974606
DoPhase(this, PHASE_FIND_LOOPS, &Compiler::optFindLoopsPhase);

src/coreclr/jit/compphases.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,7 @@ CompPhaseNameMacro(PHASE_COMPUTE_DOMINATORS, "Compute dominators",
7272
CompPhaseNameMacro(PHASE_CANONICALIZE_ENTRY, "Canonicalize entry", false, -1, false)
7373
CompPhaseNameMacro(PHASE_SET_BLOCK_WEIGHTS, "Set block weights", false, -1, false)
7474
CompPhaseNameMacro(PHASE_ZERO_INITS, "Redundant zero Inits", false, -1, false)
75+
CompPhaseNameMacro(PHASE_ADJUST_THROW_LIKELIHOODS, "Adjust throw edge likelihoods", false, -1, false)
7576
CompPhaseNameMacro(PHASE_FIND_LOOPS, "Find loops", false, -1, false)
7677
CompPhaseNameMacro(PHASE_CLONE_LOOPS, "Clone loops", false, -1, false)
7778
CompPhaseNameMacro(PHASE_UNROLL_LOOPS, "Unroll loops", false, -1, false)

src/coreclr/jit/fgdiagnostic.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3106,6 +3106,11 @@ void Compiler::fgDebugCheckBBlist(bool checkBBNum /* = false */, bool checkBBRef
31063106
assert(block->HasInitializedTarget());
31073107
}
31083108

3109+
if (block->KindIs(BBJ_COND))
3110+
{
3111+
assert(block->GetTrueEdge()->isHeuristicBased() == block->GetFalseEdge()->isHeuristicBased());
3112+
}
3113+
31093114
// A branch or fall-through to a BBJ_CALLFINALLY block must come from the `try` region associated
31103115
// with the finally block the BBJ_CALLFINALLY is targeting. There is one special case: if the
31113116
// BBJ_CALLFINALLY is the first block of a `try`, then its predecessor can be outside the `try`:

src/coreclr/jit/fgflow.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -182,6 +182,7 @@ FlowEdge* Compiler::fgAddRefPred(BasicBlock* block, BasicBlock* blockPred, FlowE
182182
// Copy likelihood from old edge.
183183
//
184184
flow->setLikelihood(oldEdge->getLikelihood());
185+
flow->setHeuristicBased(oldEdge->isHeuristicBased());
185186
}
186187
}
187188

src/coreclr/jit/fgopt.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2247,6 +2247,7 @@ bool Compiler::fgOptimizeUncondBranchToSimpleCond(BasicBlock* block, BasicBlock*
22472247
//
22482248
fgRedirectTargetEdge(block, target->GetTrueTarget());
22492249
block->GetTargetEdge()->setLikelihood(target->GetTrueEdge()->getLikelihood());
2250+
block->GetTargetEdge()->setHeuristicBased(target->GetTrueEdge()->isHeuristicBased());
22502251

22512252
FlowEdge* const falseEdge = fgAddRefPred(target->GetFalseTarget(), block, target->GetFalseEdge());
22522253
block->SetCond(block->GetTargetEdge(), falseEdge);
@@ -2741,6 +2742,7 @@ bool Compiler::fgOptimizeBranch(BasicBlock* bJump)
27412742

27422743
fgRedirectTargetEdge(bJump, falseTarget);
27432744
bJump->GetTargetEdge()->setLikelihood(falseEdge->getLikelihood());
2745+
bJump->GetTargetEdge()->setHeuristicBased(falseEdge->isHeuristicBased());
27442746

27452747
FlowEdge* const newTrueEdge = fgAddRefPred(trueTarget, bJump, trueEdge);
27462748

src/coreclr/jit/fgprofilesynthesis.cpp

Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,107 @@
99

1010
#include "fgprofilesynthesis.h"
1111

12+
//------------------------------------------------------------------------
13+
// AdjustThrowEdgeLikelihoods: Find throw blocks in the flowgraph, and propagate
14+
// their throwable state through their predecessors in postorder.
15+
// Then, adjust heuristic-based likelihoods of edges into paths known to throw.
16+
//
17+
// Arguments:
18+
// compiler - the Compiler object
19+
//
20+
// Returns:
21+
// Suitable phase status
22+
//
23+
/* static */ PhaseStatus ProfileSynthesis::AdjustThrowEdgeLikelihoods(Compiler* compiler)
24+
{
25+
const FlowGraphDfsTree* dfsTree = compiler->m_dfsTree;
26+
assert(dfsTree != nullptr);
27+
BitVecTraits traits = dfsTree->PostOrderTraits();
28+
BitVec willThrow(BitVecOps::MakeEmpty(&traits));
29+
30+
// Adjusts the likelihoods out of a block that conditionally flows into a path that throws
31+
auto tweakLikelihoods = [&](BasicBlock* block) {
32+
assert(block->KindIs(BBJ_COND));
33+
FlowEdge *throwEdge, *normalEdge;
34+
35+
if (BitVecOps::IsMember(&traits, willThrow, block->GetTrueTarget()->bbPostorderNum))
36+
{
37+
throwEdge = block->GetTrueEdge();
38+
normalEdge = block->GetFalseEdge();
39+
}
40+
else
41+
{
42+
throwEdge = block->GetFalseEdge();
43+
normalEdge = block->GetTrueEdge();
44+
}
45+
46+
throwEdge->setLikelihood(throwLikelihood);
47+
normalEdge->setLikelihood(1.0 - throwLikelihood);
48+
};
49+
50+
bool modified = false;
51+
52+
// Walk the flowgraph in postorder, propagating throw state backwards
53+
for (unsigned i = 0; i < dfsTree->GetPostOrderCount(); i++)
54+
{
55+
BasicBlock* const block = dfsTree->GetPostOrder(i);
56+
if (block->KindIs(BBJ_THROW))
57+
{
58+
JITDUMP(FMT_BB " will throw.\n", block->bbNum);
59+
BitVecOps::AddElemD(&traits, willThrow, i);
60+
}
61+
// Avoid slightly more expensive successor iteration for blocks with one outgoing edge
62+
else if ((block->GetUniqueSucc() != nullptr) &&
63+
BitVecOps::IsMember(&traits, willThrow, block->GetUniqueSucc()->bbPostorderNum))
64+
{
65+
JITDUMP(FMT_BB " flows into a throw block.\n", block->bbNum);
66+
BitVecOps::AddElemD(&traits, willThrow, i);
67+
}
68+
else
69+
{
70+
bool anyPathThrows = false;
71+
bool allPathsThrow = true;
72+
73+
for (BasicBlock* const succBlock : block->Succs(compiler))
74+
{
75+
if (BitVecOps::IsMember(&traits, willThrow, succBlock->bbPostorderNum))
76+
{
77+
anyPathThrows = true;
78+
}
79+
else
80+
{
81+
allPathsThrow = false;
82+
}
83+
}
84+
85+
if (anyPathThrows)
86+
{
87+
if (allPathsThrow)
88+
{
89+
JITDUMP(FMT_BB " flows into a throw block.\n", block->bbNum);
90+
BitVecOps::AddElemD(&traits, willThrow, i);
91+
}
92+
else if (block->KindIs(BBJ_COND) && block->GetTrueEdge()->isHeuristicBased())
93+
{
94+
JITDUMP(FMT_BB " can flow into a throw block.\n", block->bbNum);
95+
assert(block->GetFalseEdge()->isHeuristicBased());
96+
tweakLikelihoods(block);
97+
modified = true;
98+
}
99+
}
100+
}
101+
}
102+
103+
if (modified && compiler->fgIsUsingProfileWeights())
104+
{
105+
JITDUMP("Modified edge likelihoods. Data %s inconsistent.\n",
106+
compiler->fgPgoConsistent ? "is now" : "was already");
107+
compiler->fgPgoConsistent = false;
108+
}
109+
110+
return modified ? PhaseStatus::MODIFIED_EVERYTHING : PhaseStatus::MODIFIED_NOTHING;
111+
}
112+
12113
// TODO
13114
//
14115
// * vet against some real data
@@ -252,6 +353,8 @@ void ProfileSynthesis::AssignLikelihoods()
252353

253354
case BBJ_COND:
254355
// Two successor cases
356+
block->GetTrueEdge()->setHeuristicBased(true);
357+
block->GetFalseEdge()->setHeuristicBased(true);
255358
AssignLikelihoodCond(block);
256359
break;
257360

src/coreclr/jit/fgprofilesynthesis.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,8 @@ class ProfileSynthesis
3737
p.Run(option);
3838
}
3939

40+
static PhaseStatus AdjustThrowEdgeLikelihoods(Compiler* compiler);
41+
4042
static constexpr weight_t epsilon = 0.001;
4143

4244
private:

src/coreclr/jit/optimizebools.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -824,6 +824,7 @@ bool OptBoolsDsc::optOptimizeRangeTests()
824824
FlowEdge* const newEdge = m_comp->fgAddRefPred(inRangeBb, m_b1);
825825
FlowEdge* const oldFalseEdge = m_b1->GetFalseEdge();
826826
FlowEdge* const oldTrueEdge = m_b1->GetTrueEdge();
827+
newEdge->setHeuristicBased(oldTrueEdge->isHeuristicBased());
827828

828829
if (!cmp2IsReversed)
829830
{
@@ -1243,6 +1244,7 @@ void OptBoolsDsc::optOptimizeBoolsUpdateTrees()
12431244
// Modify flow for true side of B1
12441245
//
12451246
m_comp->fgRedirectTrueEdge(m_b1, m_b2->GetTrueTarget());
1247+
origB1TrueEdge->setHeuristicBased(origB2TrueEdge->isHeuristicBased());
12461248

12471249
newB1TrueLikelihood =
12481250
(1.0 - origB1TrueLikelihood) + origB1TrueLikelihood * origB2FalseEdge->getLikelihood();
@@ -1267,6 +1269,7 @@ void OptBoolsDsc::optOptimizeBoolsUpdateTrees()
12671269
// Fix B1 false edge likelihood
12681270
//
12691271
newB1FalseEdge->setLikelihood(1.0 - newB1TrueLikelihood);
1272+
newB1FalseEdge->setHeuristicBased(origB1TrueEdge->isHeuristicBased());
12701273

12711274
// Update profile
12721275
if (m_b1->hasProfileWeight())

0 commit comments

Comments
 (0)