From 0aaa51f80e0cd53b75f0dc38d559069d205c1f1b Mon Sep 17 00:00:00 2001 From: "Aman Khalid (from Dev Box)" Date: Fri, 13 Jun 2025 12:22:11 -0400 Subject: [PATCH 1/6] Tweak edge likelihoods into throw blocks --- src/coreclr/jit/block.h | 17 ++++++++++++++- src/coreclr/jit/fgbasic.cpp | 30 ++++++++++++++++++++++++++ src/coreclr/jit/fgprofilesynthesis.cpp | 2 ++ 3 files changed, 48 insertions(+), 1 deletion(-) diff --git a/src/coreclr/jit/block.h b/src/coreclr/jit/block.h index 25df699d387dd8..a854569415a316 100644 --- a/src/coreclr/jit/block.h +++ b/src/coreclr/jit/block.h @@ -594,6 +594,9 @@ struct FlowEdge // Convenience flag for phases that need to track edge visitation bool m_visited; + // Indicates if m_likelihood was determined using profile synthesis's heuristics + bool m_heuristicBasedLikelihood; + // True if likelihood has been set INDEBUG(bool m_likelihoodSet); @@ -605,6 +608,7 @@ struct FlowEdge , m_likelihood(0) , m_dupCount(0) , m_visited(false) + , m_heuristicBasedLikelihood(false) #ifdef DEBUG , m_likelihoodSet(false) #endif // DEBUG @@ -661,7 +665,8 @@ struct FlowEdge void clearLikelihood() { - m_likelihood = 0.0; + m_likelihood = 0.0; + m_heuristicBasedLikelihood = false; INDEBUG(m_likelihoodSet = false); } @@ -706,6 +711,16 @@ struct FlowEdge assert(visited()); m_visited = false; } + + bool isHeuristicBased() const + { + return m_heuristicBasedLikelihood; + } + + void setHeuristicBased() + { + m_heuristicBasedLikelihood = true; + } }; //------------------------------------------------------------------------ diff --git a/src/coreclr/jit/fgbasic.cpp b/src/coreclr/jit/fgbasic.cpp index a88be6113c34e7..9c1d426af827c9 100644 --- a/src/coreclr/jit/fgbasic.cpp +++ b/src/coreclr/jit/fgbasic.cpp @@ -173,6 +173,36 @@ void Compiler::fgConvertBBToThrowBB(BasicBlock* block) } } + // Reduce the heuristics-derived edge likelihoods into 'block' to indicate exceptional behavior + for (FlowEdge* const predEdge : block->PredEdges()) + { + if (predEdge->isHeuristicBased() && predEdge->getSourceBlock()->KindIs(BBJ_COND)) + { + BasicBlock* const condBlock = predEdge->getSourceBlock(); + FlowEdge* const otherEdge = + condBlock->TrueEdgeIs(predEdge) ? condBlock->GetFalseEdge() : condBlock->GetTrueEdge(); + + // We should not have degenerate branches + assert(predEdge != otherEdge); + assert(otherEdge->isHeuristicBased()); + + // If the predecessor can jump to a non-throw block, bias the likelihoods to that path + if (!otherEdge->getDestinationBlock()->KindIs(BBJ_THROW)) + { + predEdge->setLikelihood(0.0); + otherEdge->setLikelihood(1.0); + } + // If both branches are to throw blocks, consider them equally likely + else + { + predEdge->setLikelihood(0.5); + otherEdge->setLikelihood(0.5); + } + + profileInconsistent = true; + } + } + if (profileInconsistent) { JITDUMP("Flow removal of " FMT_BB " needs to be propagated. Data %s inconsistent.\n", block->bbNum, diff --git a/src/coreclr/jit/fgprofilesynthesis.cpp b/src/coreclr/jit/fgprofilesynthesis.cpp index 63fd3fd489d26d..a36422665dbda5 100644 --- a/src/coreclr/jit/fgprofilesynthesis.cpp +++ b/src/coreclr/jit/fgprofilesynthesis.cpp @@ -252,6 +252,8 @@ void ProfileSynthesis::AssignLikelihoods() case BBJ_COND: // Two successor cases + block->GetTrueEdge()->setHeuristicBased(); + block->GetFalseEdge()->setHeuristicBased(); AssignLikelihoodCond(block); break; From 92d2e5b64bde1020cf2ed67142e243942e382c12 Mon Sep 17 00:00:00 2001 From: "Aman Khalid (from Dev Box)" Date: Sat, 14 Jun 2025 13:35:13 -0400 Subject: [PATCH 2/6] Revert "Tweak edge likelihoods into throw blocks" This reverts commit 0aaa51f80e0cd53b75f0dc38d559069d205c1f1b. --- src/coreclr/jit/block.h | 17 +-------------- src/coreclr/jit/fgbasic.cpp | 30 -------------------------- src/coreclr/jit/fgprofilesynthesis.cpp | 2 -- 3 files changed, 1 insertion(+), 48 deletions(-) diff --git a/src/coreclr/jit/block.h b/src/coreclr/jit/block.h index a854569415a316..25df699d387dd8 100644 --- a/src/coreclr/jit/block.h +++ b/src/coreclr/jit/block.h @@ -594,9 +594,6 @@ struct FlowEdge // Convenience flag for phases that need to track edge visitation bool m_visited; - // Indicates if m_likelihood was determined using profile synthesis's heuristics - bool m_heuristicBasedLikelihood; - // True if likelihood has been set INDEBUG(bool m_likelihoodSet); @@ -608,7 +605,6 @@ struct FlowEdge , m_likelihood(0) , m_dupCount(0) , m_visited(false) - , m_heuristicBasedLikelihood(false) #ifdef DEBUG , m_likelihoodSet(false) #endif // DEBUG @@ -665,8 +661,7 @@ struct FlowEdge void clearLikelihood() { - m_likelihood = 0.0; - m_heuristicBasedLikelihood = false; + m_likelihood = 0.0; INDEBUG(m_likelihoodSet = false); } @@ -711,16 +706,6 @@ struct FlowEdge assert(visited()); m_visited = false; } - - bool isHeuristicBased() const - { - return m_heuristicBasedLikelihood; - } - - void setHeuristicBased() - { - m_heuristicBasedLikelihood = true; - } }; //------------------------------------------------------------------------ diff --git a/src/coreclr/jit/fgbasic.cpp b/src/coreclr/jit/fgbasic.cpp index 9c1d426af827c9..a88be6113c34e7 100644 --- a/src/coreclr/jit/fgbasic.cpp +++ b/src/coreclr/jit/fgbasic.cpp @@ -173,36 +173,6 @@ void Compiler::fgConvertBBToThrowBB(BasicBlock* block) } } - // Reduce the heuristics-derived edge likelihoods into 'block' to indicate exceptional behavior - for (FlowEdge* const predEdge : block->PredEdges()) - { - if (predEdge->isHeuristicBased() && predEdge->getSourceBlock()->KindIs(BBJ_COND)) - { - BasicBlock* const condBlock = predEdge->getSourceBlock(); - FlowEdge* const otherEdge = - condBlock->TrueEdgeIs(predEdge) ? condBlock->GetFalseEdge() : condBlock->GetTrueEdge(); - - // We should not have degenerate branches - assert(predEdge != otherEdge); - assert(otherEdge->isHeuristicBased()); - - // If the predecessor can jump to a non-throw block, bias the likelihoods to that path - if (!otherEdge->getDestinationBlock()->KindIs(BBJ_THROW)) - { - predEdge->setLikelihood(0.0); - otherEdge->setLikelihood(1.0); - } - // If both branches are to throw blocks, consider them equally likely - else - { - predEdge->setLikelihood(0.5); - otherEdge->setLikelihood(0.5); - } - - profileInconsistent = true; - } - } - if (profileInconsistent) { JITDUMP("Flow removal of " FMT_BB " needs to be propagated. Data %s inconsistent.\n", block->bbNum, diff --git a/src/coreclr/jit/fgprofilesynthesis.cpp b/src/coreclr/jit/fgprofilesynthesis.cpp index a36422665dbda5..63fd3fd489d26d 100644 --- a/src/coreclr/jit/fgprofilesynthesis.cpp +++ b/src/coreclr/jit/fgprofilesynthesis.cpp @@ -252,8 +252,6 @@ void ProfileSynthesis::AssignLikelihoods() case BBJ_COND: // Two successor cases - block->GetTrueEdge()->setHeuristicBased(); - block->GetFalseEdge()->setHeuristicBased(); AssignLikelihoodCond(block); break; From 70d635346e8f0c1d5f4264311e8207ac11b340a1 Mon Sep 17 00:00:00 2001 From: "Aman Khalid (from Dev Box)" Date: Sat, 14 Jun 2025 14:12:49 -0400 Subject: [PATCH 3/6] Add heuristic-based flag to FlowEdge --- src/coreclr/jit/block.h | 17 ++++++++++++++++- src/coreclr/jit/fgprofilesynthesis.cpp | 2 ++ 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/src/coreclr/jit/block.h b/src/coreclr/jit/block.h index c55918689ffe22..25c5f12db1fbdf 100644 --- a/src/coreclr/jit/block.h +++ b/src/coreclr/jit/block.h @@ -594,6 +594,9 @@ struct FlowEdge // Convenience flag for phases that need to track edge visitation bool m_visited; + // Indicates if m_likelihood was determined using profile synthesis's heuristics + bool m_heuristicBasedLikelihood; + // True if likelihood has been set INDEBUG(bool m_likelihoodSet); @@ -605,6 +608,7 @@ struct FlowEdge , m_likelihood(0) , m_dupCount(0) , m_visited(false) + , m_heuristicBasedLikelihood(false) #ifdef DEBUG , m_likelihoodSet(false) #endif // DEBUG @@ -661,7 +665,8 @@ struct FlowEdge void clearLikelihood() { - m_likelihood = 0.0; + m_likelihood = 0.0; + m_heuristicBasedLikelihood = false; INDEBUG(m_likelihoodSet = false); } @@ -706,6 +711,16 @@ struct FlowEdge assert(visited()); m_visited = false; } + + bool isHeuristicBased() const + { + return m_heuristicBasedLikelihood; + } + + void setHeuristicBased() + { + m_heuristicBasedLikelihood = true; + } }; //------------------------------------------------------------------------ diff --git a/src/coreclr/jit/fgprofilesynthesis.cpp b/src/coreclr/jit/fgprofilesynthesis.cpp index b9ed07053108bc..e6632a479d8b60 100644 --- a/src/coreclr/jit/fgprofilesynthesis.cpp +++ b/src/coreclr/jit/fgprofilesynthesis.cpp @@ -252,6 +252,8 @@ void ProfileSynthesis::AssignLikelihoods() case BBJ_COND: // Two successor cases + block->GetTrueEdge()->setHeuristicBased(); + block->GetFalseEdge()->setHeuristicBased(); AssignLikelihoodCond(block); break; From 2bde909d8a14ba90d529395378163ecf3dcef213 Mon Sep 17 00:00:00 2001 From: "Aman Khalid (from Dev Box)" Date: Sun, 15 Jun 2025 17:12:19 -0400 Subject: [PATCH 4/6] Ensure heuristic-based flag is updated --- src/coreclr/jit/block.h | 4 ++-- src/coreclr/jit/fgdiagnostic.cpp | 5 +++++ src/coreclr/jit/fgflow.cpp | 1 + src/coreclr/jit/fgopt.cpp | 2 ++ src/coreclr/jit/fgprofilesynthesis.cpp | 4 ++-- src/coreclr/jit/optimizebools.cpp | 3 +++ 6 files changed, 15 insertions(+), 4 deletions(-) diff --git a/src/coreclr/jit/block.h b/src/coreclr/jit/block.h index 25c5f12db1fbdf..2a55d1b8396f1b 100644 --- a/src/coreclr/jit/block.h +++ b/src/coreclr/jit/block.h @@ -717,9 +717,9 @@ struct FlowEdge return m_heuristicBasedLikelihood; } - void setHeuristicBased() + void setHeuristicBased(bool isHeuristicBased) { - m_heuristicBasedLikelihood = true; + m_heuristicBasedLikelihood = isHeuristicBased; } }; diff --git a/src/coreclr/jit/fgdiagnostic.cpp b/src/coreclr/jit/fgdiagnostic.cpp index 4bcb2bdd359c7b..08ed93adbf9775 100644 --- a/src/coreclr/jit/fgdiagnostic.cpp +++ b/src/coreclr/jit/fgdiagnostic.cpp @@ -3106,6 +3106,11 @@ void Compiler::fgDebugCheckBBlist(bool checkBBNum /* = false */, bool checkBBRef assert(block->HasInitializedTarget()); } + if (block->KindIs(BBJ_COND)) + { + assert(block->GetTrueEdge()->isHeuristicBased() == block->GetFalseEdge()->isHeuristicBased()); + } + // A branch or fall-through to a BBJ_CALLFINALLY block must come from the `try` region associated // with the finally block the BBJ_CALLFINALLY is targeting. There is one special case: if the // BBJ_CALLFINALLY is the first block of a `try`, then its predecessor can be outside the `try`: diff --git a/src/coreclr/jit/fgflow.cpp b/src/coreclr/jit/fgflow.cpp index 730c77cd74bec9..0e2bba0f12299d 100644 --- a/src/coreclr/jit/fgflow.cpp +++ b/src/coreclr/jit/fgflow.cpp @@ -182,6 +182,7 @@ FlowEdge* Compiler::fgAddRefPred(BasicBlock* block, BasicBlock* blockPred, FlowE // Copy likelihood from old edge. // flow->setLikelihood(oldEdge->getLikelihood()); + flow->setHeuristicBased(oldEdge->isHeuristicBased()); } } diff --git a/src/coreclr/jit/fgopt.cpp b/src/coreclr/jit/fgopt.cpp index ab2b2d22859dff..86cc704a436447 100644 --- a/src/coreclr/jit/fgopt.cpp +++ b/src/coreclr/jit/fgopt.cpp @@ -2247,6 +2247,7 @@ bool Compiler::fgOptimizeUncondBranchToSimpleCond(BasicBlock* block, BasicBlock* // fgRedirectTargetEdge(block, target->GetTrueTarget()); block->GetTargetEdge()->setLikelihood(target->GetTrueEdge()->getLikelihood()); + block->GetTargetEdge()->setHeuristicBased(target->GetTrueEdge()->isHeuristicBased()); FlowEdge* const falseEdge = fgAddRefPred(target->GetFalseTarget(), block, target->GetFalseEdge()); block->SetCond(block->GetTargetEdge(), falseEdge); @@ -2741,6 +2742,7 @@ bool Compiler::fgOptimizeBranch(BasicBlock* bJump) fgRedirectTargetEdge(bJump, falseTarget); bJump->GetTargetEdge()->setLikelihood(falseEdge->getLikelihood()); + bJump->GetTargetEdge()->setHeuristicBased(falseEdge->isHeuristicBased()); FlowEdge* const newTrueEdge = fgAddRefPred(trueTarget, bJump, trueEdge); diff --git a/src/coreclr/jit/fgprofilesynthesis.cpp b/src/coreclr/jit/fgprofilesynthesis.cpp index e6632a479d8b60..e14d0bf126a92a 100644 --- a/src/coreclr/jit/fgprofilesynthesis.cpp +++ b/src/coreclr/jit/fgprofilesynthesis.cpp @@ -252,8 +252,8 @@ void ProfileSynthesis::AssignLikelihoods() case BBJ_COND: // Two successor cases - block->GetTrueEdge()->setHeuristicBased(); - block->GetFalseEdge()->setHeuristicBased(); + block->GetTrueEdge()->setHeuristicBased(true); + block->GetFalseEdge()->setHeuristicBased(true); AssignLikelihoodCond(block); break; diff --git a/src/coreclr/jit/optimizebools.cpp b/src/coreclr/jit/optimizebools.cpp index c748aa5b739448..23372828ff4df8 100644 --- a/src/coreclr/jit/optimizebools.cpp +++ b/src/coreclr/jit/optimizebools.cpp @@ -824,6 +824,7 @@ bool OptBoolsDsc::optOptimizeRangeTests() FlowEdge* const newEdge = m_comp->fgAddRefPred(inRangeBb, m_b1); FlowEdge* const oldFalseEdge = m_b1->GetFalseEdge(); FlowEdge* const oldTrueEdge = m_b1->GetTrueEdge(); + newEdge->setHeuristicBased(oldTrueEdge->isHeuristicBased()); if (!cmp2IsReversed) { @@ -1243,6 +1244,7 @@ void OptBoolsDsc::optOptimizeBoolsUpdateTrees() // Modify flow for true side of B1 // m_comp->fgRedirectTrueEdge(m_b1, m_b2->GetTrueTarget()); + origB1TrueEdge->setHeuristicBased(origB2TrueEdge->isHeuristicBased()); newB1TrueLikelihood = (1.0 - origB1TrueLikelihood) + origB1TrueLikelihood * origB2FalseEdge->getLikelihood(); @@ -1267,6 +1269,7 @@ void OptBoolsDsc::optOptimizeBoolsUpdateTrees() // Fix B1 false edge likelihood // newB1FalseEdge->setLikelihood(1.0 - newB1TrueLikelihood); + newB1FalseEdge->setHeuristicBased(origB1TrueEdge->isHeuristicBased()); // Update profile if (m_b1->hasProfileWeight()) From c8ebd5b180983b2ef9238f467f9f43030f6aca44 Mon Sep 17 00:00:00 2001 From: "Aman Khalid (from Dev Box)" Date: Sun, 15 Jun 2025 22:51:42 -0400 Subject: [PATCH 5/6] Add edge likelihood adjustment phase --- src/coreclr/jit/compiler.cpp | 9 +++ src/coreclr/jit/compphases.h | 1 + src/coreclr/jit/fgprofilesynthesis.cpp | 86 ++++++++++++++++++++++++++ src/coreclr/jit/fgprofilesynthesis.h | 2 + 4 files changed, 98 insertions(+) diff --git a/src/coreclr/jit/compiler.cpp b/src/coreclr/jit/compiler.cpp index 5b12af96ea5b45..29bdd306e7cd2c 100644 --- a/src/coreclr/jit/compiler.cpp +++ b/src/coreclr/jit/compiler.cpp @@ -21,6 +21,7 @@ XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX #include "lower.h" #include "stacklevelsetter.h" #include "patchpointinfo.h" +#include "fgprofilesynthesis.h" #include "jitstd/algorithm.h" #include "minipal/time.h" @@ -4592,6 +4593,14 @@ void Compiler::compCompile(void** methodCodePtr, uint32_t* methodCodeSize, JitFl // DoPhase(this, PHASE_DFS_BLOCKS3, &Compiler::fgDfsBlocksAndRemove); + auto adjustThrowEdgeLikelihoods = [this]() -> PhaseStatus { + return ProfileSynthesis::AdjustThrowEdgeLikelihoods(this); + }; + + // Adjust heuristic-derived edge likelihoods into paths that are known to throw. + // + DoPhase(this, PHASE_ADJUST_THROW_LIKELIHOODS, adjustThrowEdgeLikelihoods); + // Discover and classify natural loops (e.g. mark iterative loops as such). // DoPhase(this, PHASE_FIND_LOOPS, &Compiler::optFindLoopsPhase); diff --git a/src/coreclr/jit/compphases.h b/src/coreclr/jit/compphases.h index 2c816dc0ef9a43..6ede9a61508682 100644 --- a/src/coreclr/jit/compphases.h +++ b/src/coreclr/jit/compphases.h @@ -72,6 +72,7 @@ CompPhaseNameMacro(PHASE_COMPUTE_DOMINATORS, "Compute dominators", CompPhaseNameMacro(PHASE_CANONICALIZE_ENTRY, "Canonicalize entry", false, -1, false) CompPhaseNameMacro(PHASE_SET_BLOCK_WEIGHTS, "Set block weights", false, -1, false) CompPhaseNameMacro(PHASE_ZERO_INITS, "Redundant zero Inits", false, -1, false) +CompPhaseNameMacro(PHASE_ADJUST_THROW_LIKELIHOODS, "Adjust throw edge likelihoods", false, -1, false) CompPhaseNameMacro(PHASE_FIND_LOOPS, "Find loops", false, -1, false) CompPhaseNameMacro(PHASE_CLONE_LOOPS, "Clone loops", false, -1, false) CompPhaseNameMacro(PHASE_UNROLL_LOOPS, "Unroll loops", false, -1, false) diff --git a/src/coreclr/jit/fgprofilesynthesis.cpp b/src/coreclr/jit/fgprofilesynthesis.cpp index e14d0bf126a92a..4212ae34986f44 100644 --- a/src/coreclr/jit/fgprofilesynthesis.cpp +++ b/src/coreclr/jit/fgprofilesynthesis.cpp @@ -9,6 +9,92 @@ #include "fgprofilesynthesis.h" +/* static */ PhaseStatus ProfileSynthesis::AdjustThrowEdgeLikelihoods(Compiler* compiler) +{ + const FlowGraphDfsTree* dfsTree = compiler->m_dfsTree; + assert(dfsTree != nullptr); + BitVecTraits traits = dfsTree->PostOrderTraits(); + BitVec willThrow(BitVecOps::MakeEmpty(&traits)); + + auto tweakLikelihoods = [&](BasicBlock* block) { + assert(block->KindIs(BBJ_COND)); + FlowEdge *throwEdge, *normalEdge; + + if (BitVecOps::IsMember(&traits, willThrow, block->GetTrueTarget()->bbPostorderNum)) + { + throwEdge = block->GetTrueEdge(); + normalEdge = block->GetFalseEdge(); + } + else + { + throwEdge = block->GetFalseEdge(); + normalEdge = block->GetTrueEdge(); + } + + throwEdge->setLikelihood(throwLikelihood); + normalEdge->setLikelihood(1.0 - throwLikelihood); + }; + + bool modified = false; + + for (unsigned i = 0; i < dfsTree->GetPostOrderCount(); i++) + { + BasicBlock* const block = dfsTree->GetPostOrder(i); + if (block->KindIs(BBJ_THROW)) + { + JITDUMP(FMT_BB " will throw.\n", block->bbNum); + BitVecOps::AddElemD(&traits, willThrow, i); + } + else if ((block->GetUniqueSucc() != nullptr) && + BitVecOps::IsMember(&traits, willThrow, block->GetUniqueSucc()->bbPostorderNum)) + { + JITDUMP(FMT_BB " flows into a throw block.\n", block->bbNum); + BitVecOps::AddElemD(&traits, willThrow, i); + } + else + { + bool anyPathThrows = false; + bool allPathsThrow = true; + + for (BasicBlock* const succBlock : block->Succs(compiler)) + { + if (BitVecOps::IsMember(&traits, willThrow, succBlock->bbPostorderNum)) + { + anyPathThrows = true; + } + else + { + allPathsThrow = false; + } + } + + if (anyPathThrows) + { + JITDUMP(FMT_BB " flows into a throw block.\n", block->bbNum); + if (allPathsThrow) + { + BitVecOps::AddElemD(&traits, willThrow, i); + } + else if (block->KindIs(BBJ_COND) && block->GetTrueEdge()->isHeuristicBased()) + { + assert(block->GetFalseEdge()->isHeuristicBased()); + tweakLikelihoods(block); + modified = true; + } + } + } + } + + if (modified && compiler->fgIsUsingProfileWeights()) + { + JITDUMP("Modified edge likelihoods. Data %s inconsistent.\n", + compiler->fgPgoConsistent ? "is now" : "was already"); + compiler->fgPgoConsistent = false; + } + + return modified ? PhaseStatus::MODIFIED_EVERYTHING : PhaseStatus::MODIFIED_NOTHING; +} + // TODO // // * vet against some real data diff --git a/src/coreclr/jit/fgprofilesynthesis.h b/src/coreclr/jit/fgprofilesynthesis.h index b1425167c752c1..d34783a19525f1 100644 --- a/src/coreclr/jit/fgprofilesynthesis.h +++ b/src/coreclr/jit/fgprofilesynthesis.h @@ -37,6 +37,8 @@ class ProfileSynthesis p.Run(option); } + static PhaseStatus AdjustThrowEdgeLikelihoods(Compiler* compiler); + static constexpr weight_t epsilon = 0.001; private: From 761dded11befcc66262468c85df63e21b530859e Mon Sep 17 00:00:00 2001 From: "Aman Khalid (from Dev Box)" Date: Sun, 15 Jun 2025 23:09:34 -0400 Subject: [PATCH 6/6] Add comments --- src/coreclr/jit/fgprofilesynthesis.cpp | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/src/coreclr/jit/fgprofilesynthesis.cpp b/src/coreclr/jit/fgprofilesynthesis.cpp index 4212ae34986f44..1e90c43c81b824 100644 --- a/src/coreclr/jit/fgprofilesynthesis.cpp +++ b/src/coreclr/jit/fgprofilesynthesis.cpp @@ -9,6 +9,17 @@ #include "fgprofilesynthesis.h" +//------------------------------------------------------------------------ +// AdjustThrowEdgeLikelihoods: Find throw blocks in the flowgraph, and propagate +// their throwable state through their predecessors in postorder. +// Then, adjust heuristic-based likelihoods of edges into paths known to throw. +// +// Arguments: +// compiler - the Compiler object +// +// Returns: +// Suitable phase status +// /* static */ PhaseStatus ProfileSynthesis::AdjustThrowEdgeLikelihoods(Compiler* compiler) { const FlowGraphDfsTree* dfsTree = compiler->m_dfsTree; @@ -16,6 +27,7 @@ BitVecTraits traits = dfsTree->PostOrderTraits(); BitVec willThrow(BitVecOps::MakeEmpty(&traits)); + // Adjusts the likelihoods out of a block that conditionally flows into a path that throws auto tweakLikelihoods = [&](BasicBlock* block) { assert(block->KindIs(BBJ_COND)); FlowEdge *throwEdge, *normalEdge; @@ -37,6 +49,7 @@ bool modified = false; + // Walk the flowgraph in postorder, propagating throw state backwards for (unsigned i = 0; i < dfsTree->GetPostOrderCount(); i++) { BasicBlock* const block = dfsTree->GetPostOrder(i); @@ -45,6 +58,7 @@ JITDUMP(FMT_BB " will throw.\n", block->bbNum); BitVecOps::AddElemD(&traits, willThrow, i); } + // Avoid slightly more expensive successor iteration for blocks with one outgoing edge else if ((block->GetUniqueSucc() != nullptr) && BitVecOps::IsMember(&traits, willThrow, block->GetUniqueSucc()->bbPostorderNum)) { @@ -70,13 +84,14 @@ if (anyPathThrows) { - JITDUMP(FMT_BB " flows into a throw block.\n", block->bbNum); if (allPathsThrow) { + JITDUMP(FMT_BB " flows into a throw block.\n", block->bbNum); BitVecOps::AddElemD(&traits, willThrow, i); } else if (block->KindIs(BBJ_COND) && block->GetTrueEdge()->isHeuristicBased()) { + JITDUMP(FMT_BB " can flow into a throw block.\n", block->bbNum); assert(block->GetFalseEdge()->isHeuristicBased()); tweakLikelihoods(block); modified = true;