Skip to content

Commit aecae2c

Browse files
JIT: Enable profile consistency checking up to morph (#111047)
Part of #107749.
1 parent 2d7f45b commit aecae2c

File tree

5 files changed

+68
-89
lines changed

5 files changed

+68
-89
lines changed

src/coreclr/jit/compiler.cpp

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4711,11 +4711,6 @@ void Compiler::compCompile(void** methodCodePtr, uint32_t* methodCodeSize, JitFl
47114711
//
47124712
DoPhase(this, PHASE_CLONE_FINALLY, &Compiler::fgCloneFinally);
47134713

4714-
// Drop back to just checking profile likelihoods.
4715-
//
4716-
activePhaseChecks &= ~PhaseChecks::CHECK_PROFILE;
4717-
activePhaseChecks |= PhaseChecks::CHECK_LIKELIHOODS;
4718-
47194714
// Do some flow-related optimizations
47204715
//
47214716
if (opts.OptimizationEnabled())
@@ -4784,6 +4779,11 @@ void Compiler::compCompile(void** methodCodePtr, uint32_t* methodCodeSize, JitFl
47844779
//
47854780
DoPhase(this, PHASE_MORPH_IMPBYREF, &Compiler::fgRetypeImplicitByRefArgs);
47864781

4782+
// Drop back to just checking profile likelihoods.
4783+
//
4784+
activePhaseChecks &= ~PhaseChecks::CHECK_PROFILE;
4785+
activePhaseChecks |= PhaseChecks::CHECK_LIKELIHOODS;
4786+
47874787
#ifdef DEBUG
47884788
// Now that locals have address-taken and implicit byref marked, we can safely apply stress.
47894789
lvaStressLclFld();

src/coreclr/jit/fgehopt.cpp

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2410,6 +2410,7 @@ PhaseStatus Compiler::fgTailMergeThrows()
24102410
}
24112411

24122412
JITDUMP("\n*** found %d merge candidates, rewriting flow\n\n", numCandidates);
2413+
bool modifiedProfile = false;
24132414

24142415
// Second pass.
24152416
//
@@ -2418,14 +2419,37 @@ PhaseStatus Compiler::fgTailMergeThrows()
24182419
{
24192420
BasicBlock* const nonCanonicalBlock = iter->GetKey();
24202421
BasicBlock* const canonicalBlock = iter->GetValue();
2422+
weight_t removedWeight = BB_ZERO_WEIGHT;
24212423

24222424
// Walk pred list of the non canonical block, updating flow to target
24232425
// the canonical block instead.
2424-
for (BasicBlock* const predBlock : nonCanonicalBlock->PredBlocksEditing())
2426+
for (FlowEdge* const predEdge : nonCanonicalBlock->PredEdgesEditing())
24252427
{
2428+
removedWeight += predEdge->getLikelyWeight();
2429+
BasicBlock* const predBlock = predEdge->getSourceBlock();
24262430
JITDUMP("*** " FMT_BB " now branching to " FMT_BB "\n", predBlock->bbNum, canonicalBlock->bbNum);
24272431
fgReplaceJumpTarget(predBlock, nonCanonicalBlock, canonicalBlock);
24282432
}
2433+
2434+
if (canonicalBlock->hasProfileWeight())
2435+
{
2436+
canonicalBlock->setBBProfileWeight(canonicalBlock->bbWeight + removedWeight);
2437+
modifiedProfile = true;
2438+
2439+
// Don't bother updating flow into nonCanonicalBlock, since it is now unreachable
2440+
}
2441+
}
2442+
2443+
// In practice, when we have true profile data, we can repair it locally above, since the no-return
2444+
// calls mean that there is no contribution from the throw blocks to any of their successors.
2445+
// However, these blocks won't be morphed into BBJ_THROW blocks until later,
2446+
// so mark profile data as inconsistent for now.
2447+
if (modifiedProfile)
2448+
{
2449+
JITDUMP(
2450+
"fgTailMergeThrows: Modified flow into no-return blocks that still have successors. Data %s inconsistent.\n",
2451+
fgPgoConsistent ? "is now" : "was already");
2452+
fgPgoConsistent = false;
24292453
}
24302454

24312455
// Update the count of noreturn call sites

src/coreclr/jit/fgopt.cpp

Lines changed: 27 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1317,37 +1317,15 @@ bool Compiler::fgOptimizeBranchToEmptyUnconditional(BasicBlock* block, BasicBloc
13171317
}
13181318
#endif // DEBUG
13191319

1320-
//
1321-
// When we optimize a branch to branch we need to update the profile weight
1322-
// of bDest by subtracting out the weight of the path that is being optimized.
1323-
//
1324-
if (bDest->hasProfileWeight())
1325-
{
1326-
FlowEdge* const edge = fgGetPredForBlock(bDest, block);
1327-
noway_assert(edge != nullptr);
1328-
1329-
const weight_t edgeWeight = edge->getLikelyWeight();
1330-
1331-
//
1332-
// Update the bDest->bbWeight
1333-
//
1334-
if (bDest->bbWeight > edgeWeight)
1335-
{
1336-
bDest->bbWeight -= edgeWeight;
1337-
}
1338-
else
1339-
{
1340-
bDest->bbWeight = BB_ZERO_WEIGHT;
1341-
bDest->SetFlags(BBF_RUN_RARELY); // Set the RarelyRun flag
1342-
}
1343-
}
1320+
weight_t removedWeight;
13441321

13451322
// Optimize the JUMP to empty unconditional JUMP to go to the new target
13461323
switch (block->GetKind())
13471324
{
13481325
case BBJ_ALWAYS:
13491326
case BBJ_CALLFINALLYRET:
13501327
{
1328+
removedWeight = block->bbWeight;
13511329
fgRedirectTargetEdge(block, bDest->GetTarget());
13521330
break;
13531331
}
@@ -1356,11 +1334,13 @@ bool Compiler::fgOptimizeBranchToEmptyUnconditional(BasicBlock* block, BasicBloc
13561334
if (block->TrueTargetIs(bDest))
13571335
{
13581336
assert(!block->FalseTargetIs(bDest));
1337+
removedWeight = block->GetTrueEdge()->getLikelyWeight();
13591338
fgRedirectTrueEdge(block, bDest->GetTarget());
13601339
}
13611340
else
13621341
{
13631342
assert(block->FalseTargetIs(bDest));
1343+
removedWeight = block->GetFalseEdge()->getLikelyWeight();
13641344
fgRedirectFalseEdge(block, bDest->GetTarget());
13651345
}
13661346
break;
@@ -1369,6 +1349,15 @@ bool Compiler::fgOptimizeBranchToEmptyUnconditional(BasicBlock* block, BasicBloc
13691349
unreached();
13701350
}
13711351

1352+
//
1353+
// When we optimize a branch to branch we need to update the profile weight
1354+
// of bDest by subtracting out the weight of the path that is being optimized.
1355+
//
1356+
if (bDest->hasProfileWeight())
1357+
{
1358+
bDest->setBBProfileWeight(max(0.0, bDest->bbWeight - removedWeight));
1359+
}
1360+
13721361
return true;
13731362
}
13741363
return false;
@@ -1628,17 +1617,10 @@ bool Compiler::fgOptimizeSwitchBranches(BasicBlock* block)
16281617
//
16291618
FlowEdge* const oldEdge = *jmpTab;
16301619

1631-
if (fgIsUsingProfileWeights() && bDest->hasProfileWeight())
1620+
if (bDest->hasProfileWeight())
16321621
{
16331622
weight_t const branchThroughWeight = oldEdge->getLikelyWeight();
1634-
if (bDest->bbWeight > branchThroughWeight)
1635-
{
1636-
bDest->bbWeight -= branchThroughWeight;
1637-
}
1638-
else
1639-
{
1640-
bDest->bbSetRunRarely();
1641-
}
1623+
bDest->setBBProfileWeight(max(0.0, bDest->bbWeight - branchThroughWeight));
16421624
}
16431625

16441626
// Update the switch jump table
@@ -1676,6 +1658,11 @@ bool Compiler::fgOptimizeSwitchBranches(BasicBlock* block)
16761658
{
16771659
// Invalidate the set of unique targets for block, since we modified the targets
16781660
fgInvalidateSwitchDescMapEntry(block);
1661+
1662+
JITDUMP(
1663+
"fgOptimizeSwitchBranches: Optimized switch flow. Profile needs to be re-propagated. Data %s consistent.\n",
1664+
fgPgoConsistent ? "is now" : "was already");
1665+
fgPgoConsistent = false;
16791666
}
16801667

16811668
Statement* switchStmt = nullptr;
@@ -6632,6 +6619,13 @@ PhaseStatus Compiler::fgHeadTailMerge(bool early)
66326619
FlowEdge* const newEdge = fgAddRefPred(crossJumpTarget, predBlock);
66336620
predBlock->SetKindAndTargetEdge(BBJ_ALWAYS, newEdge);
66346621
}
6622+
6623+
// For tail merge we have a common successor of predBlock and
6624+
// crossJumpTarget, so the profile update can be done locally.
6625+
if (crossJumpTarget->hasProfileWeight())
6626+
{
6627+
crossJumpTarget->setBBProfileWeight(crossJumpTarget->bbWeight + predBlock->bbWeight);
6628+
}
66356629
}
66366630

66376631
// We changed things

src/coreclr/jit/fgprofile.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5119,7 +5119,8 @@ void Compiler::fgRepairProfileCondToUncond(BasicBlock* block,
51195119

51205120
// If profile weights are consistent, expect at worst a slight underflow.
51215121
//
5122-
if (fgPgoConsistent && (alternateNewWeight < 0.0))
5122+
const bool checkProfileConsistency = hasFlag(activePhaseChecks, PhaseChecks::CHECK_PROFILE);
5123+
if (checkProfileConsistency && fgPgoConsistent && (alternateNewWeight < 0.0))
51235124
{
51245125
assert(fgProfileWeightsEqual(alternateNewWeight, 0.0));
51255126
}

src/coreclr/jit/morph.cpp

Lines changed: 9 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -12658,63 +12658,23 @@ Compiler::FoldResult Compiler::fgFoldConditional(BasicBlock* block)
1265812658
fgRemoveStmt(block, lastStmt);
1265912659
result = FoldResult::FOLD_REMOVED_LAST_STMT;
1266012660
}
12661-
// block is a BBJ_COND that we are folding the conditional for.
12662-
// bTaken is the path that will always be taken from block.
12663-
// bNotTaken is the path that will never be taken from block.
12664-
//
12665-
BasicBlock* bTaken;
12666-
BasicBlock* bNotTaken;
12667-
FlowEdge* edgeTaken;
12661+
12662+
FlowEdge *retainedEdge, *removedEdge;
1266812663

1266912664
if (cond->AsIntCon()->gtIconVal != 0)
1267012665
{
12671-
// JTRUE 1 - transform the basic block into a BBJ_ALWAYS
12672-
bTaken = block->GetTrueTarget();
12673-
bNotTaken = block->GetFalseTarget();
12674-
12675-
// Remove 'block' from the predecessor list of 'bNotTaken' */
12676-
fgRemoveRefPred(block->GetFalseEdge());
12677-
12678-
edgeTaken = block->GetTrueEdge();
12679-
block->SetKindAndTargetEdge(BBJ_ALWAYS, edgeTaken);
12666+
retainedEdge = block->GetTrueEdge();
12667+
removedEdge = block->GetFalseEdge();
1268012668
}
1268112669
else
1268212670
{
12683-
// JTRUE 0 - transform the basic block into a BBJ_ALWAYS
12684-
bTaken = block->GetFalseTarget();
12685-
bNotTaken = block->GetTrueTarget();
12686-
12687-
// Remove 'block' from the predecessor list of 'bNotTaken' */
12688-
fgRemoveRefPred(block->GetTrueEdge());
12689-
12690-
edgeTaken = block->GetFalseEdge();
12691-
block->SetKindAndTargetEdge(BBJ_ALWAYS, block->GetFalseEdge());
12671+
retainedEdge = block->GetFalseEdge();
12672+
removedEdge = block->GetTrueEdge();
1269212673
}
1269312674

12694-
// We examine the taken edge (block -> bTaken)
12695-
// if block has valid profile weight and bTaken does not we try to adjust bTaken's weight
12696-
// else if bTaken has valid profile weight and block does not we try to adjust block's weight
12697-
// We can only adjust the block weights when (the edge block -> bTaken) is the only edge into bTaken
12698-
//
12699-
if (block->hasProfileWeight())
12700-
{
12701-
if (!bTaken->hasProfileWeight())
12702-
{
12703-
if ((bTaken->countOfInEdges() == 1) || (bTaken->bbWeight < block->bbWeight))
12704-
{
12705-
// Update the weight of bTaken
12706-
bTaken->inheritWeight(block);
12707-
}
12708-
}
12709-
}
12710-
else if (bTaken->hasProfileWeight())
12711-
{
12712-
if (bTaken->countOfInEdges() == 1)
12713-
{
12714-
// Update the weight of block
12715-
block->inheritWeight(bTaken);
12716-
}
12717-
}
12675+
fgRemoveRefPred(removedEdge);
12676+
block->SetKindAndTargetEdge(BBJ_ALWAYS, retainedEdge);
12677+
fgRepairProfileCondToUncond(block, retainedEdge, removedEdge);
1271812678

1271912679
#ifdef DEBUG
1272012680
if (verbose)

0 commit comments

Comments
 (0)