Skip to content

Commit 48ace18

Browse files
JIT: Re-introduce late fgOptimizeBranch pass (#113491)
Part of #107749. fgReorderBlocks runs fgOptimizeBranch when it decides not to reorder a particular block. Turning off the old layout in favor of RPO layout in .NET 9 had the unintended consequence of also disabling the later fgOptimizeBranch pass the JIT used to do. After finding cases in #113108 that benefit from cloning and hoisting loop tests, I decided to reintroduce this late pass. These regressions also highlight that fgOptimizeBranch can create compaction opportunities inside loop bodies that we don't currently take advantage of; I've added a check to handle this.
1 parent 322735d commit 48ace18

File tree

2 files changed

+35
-18
lines changed

2 files changed

+35
-18
lines changed

src/coreclr/jit/fgopt.cpp

+23-18
Original file line numberDiff line numberDiff line change
@@ -2526,7 +2526,6 @@ bool Compiler::fgOptimizeBranch(BasicBlock* bJump)
25262526
return false;
25272527
}
25282528

2529-
// We might be able to compact blocks that always jump to the next block.
25302529
if (bJump->JumpsToNext())
25312530
{
25322531
return false;
@@ -2537,7 +2536,7 @@ bool Compiler::fgOptimizeBranch(BasicBlock* bJump)
25372536
return false;
25382537
}
25392538

2540-
BasicBlock* bDest = bJump->GetTarget();
2539+
BasicBlock* const bDest = bJump->GetTarget();
25412540

25422541
if (!bDest->KindIs(BBJ_COND))
25432542
{
@@ -2556,12 +2555,11 @@ bool Compiler::fgOptimizeBranch(BasicBlock* bJump)
25562555
return false;
25572556
}
25582557

2559-
// do not jump into another try region
2560-
BasicBlock* bDestNormalTarget = bDest->GetFalseTarget();
2561-
if (bDestNormalTarget->hasTryIndex() && !BasicBlock::sameTryRegion(bJump, bDestNormalTarget))
2562-
{
2563-
return false;
2564-
}
2558+
// We should have already compacted 'bDest' into 'bJump', if it is possible.
2559+
assert(!fgCanCompactBlock(bJump));
2560+
2561+
BasicBlock* const trueTarget = bDest->GetTrueTarget();
2562+
BasicBlock* const falseTarget = bDest->GetFalseTarget();
25652563

25662564
// This function is only called in the frontend.
25672565
assert(!bJump->IsLIR());
@@ -2587,10 +2585,10 @@ bool Compiler::fgOptimizeBranch(BasicBlock* bJump)
25872585
bool haveProfileWeights = false;
25882586
weight_t weightJump = bJump->bbWeight;
25892587
weight_t weightDest = bDest->bbWeight;
2590-
weight_t weightNext = bJump->Next()->bbWeight;
2588+
weight_t weightNext = trueTarget->bbWeight;
25912589
bool rareJump = bJump->isRunRarely();
25922590
bool rareDest = bDest->isRunRarely();
2593-
bool rareNext = bJump->Next()->isRunRarely();
2591+
bool rareNext = trueTarget->isRunRarely();
25942592

25952593
// If we have profile data then we calculate the number of time
25962594
// the loop will iterate into loopIterations
@@ -2601,7 +2599,7 @@ bool Compiler::fgOptimizeBranch(BasicBlock* bJump)
26012599
//
26022600
if (bJump->HasAnyFlag(BBF_PROF_WEIGHT | BBF_RUN_RARELY) &&
26032601
bDest->HasAnyFlag(BBF_PROF_WEIGHT | BBF_RUN_RARELY) &&
2604-
bJump->Next()->HasAnyFlag(BBF_PROF_WEIGHT | BBF_RUN_RARELY))
2602+
trueTarget->HasAnyFlag(BBF_PROF_WEIGHT | BBF_RUN_RARELY))
26052603
{
26062604
haveProfileWeights = true;
26072605

@@ -2715,7 +2713,7 @@ bool Compiler::fgOptimizeBranch(BasicBlock* bJump)
27152713
noway_assert(condTree->gtOper == GT_JTRUE);
27162714

27172715
// Set condTree to the operand to the GT_JTRUE.
2718-
condTree = condTree->AsOp()->gtOp1;
2716+
condTree = condTree->gtGetOp1();
27192717

27202718
// This condTree has to be a RelOp comparison.
27212719
if (condTree->OperIsCompare() == false)
@@ -2767,12 +2765,11 @@ bool Compiler::fgOptimizeBranch(BasicBlock* bJump)
27672765
// because the comparison in 'bJump' is flipped.
27682766
// Similarly, we will derive the true edge's likelihood from 'destFalseEdge'.
27692767
//
2770-
BasicBlock* const bDestFalseTarget = bJump->Next();
2771-
FlowEdge* const falseEdge = fgAddRefPred(bDestFalseTarget, bJump, destTrueEdge);
2768+
FlowEdge* const falseEdge = fgAddRefPred(trueTarget, bJump, destTrueEdge);
27722769

27732770
// bJump now jumps to bDest's normal jump target
27742771
//
2775-
fgRedirectTargetEdge(bJump, bDestNormalTarget);
2772+
fgRedirectTargetEdge(bJump, falseTarget);
27762773
bJump->GetTargetEdge()->setLikelihood(destFalseEdge->getLikelihood());
27772774

27782775
bJump->SetCond(bJump->GetTargetEdge(), falseEdge);
@@ -2787,10 +2784,10 @@ bool Compiler::fgOptimizeBranch(BasicBlock* bJump)
27872784

27882785
// Propagate bJump's weight into its new successors
27892786
//
2790-
bDestNormalTarget->setBBProfileWeight(bDestNormalTarget->computeIncomingWeight());
2791-
bDestFalseTarget->setBBProfileWeight(bDestFalseTarget->computeIncomingWeight());
2787+
trueTarget->setBBProfileWeight(trueTarget->computeIncomingWeight());
2788+
falseTarget->setBBProfileWeight(falseTarget->computeIncomingWeight());
27922789

2793-
if ((bDestNormalTarget->NumSucc() > 0) || (bDestFalseTarget->NumSucc() > 0))
2790+
if ((trueTarget->NumSucc() > 0) || (falseTarget->NumSucc() > 0))
27942791
{
27952792
JITDUMP("fgOptimizeBranch: New flow out of " FMT_BB " needs to be propagated. Data %s inconsistent.\n",
27962793
bJump->bbNum, fgPgoConsistent ? "is now" : "was already");
@@ -2815,6 +2812,14 @@ bool Compiler::fgOptimizeBranch(BasicBlock* bJump)
28152812
}
28162813
#endif // DEBUG
28172814

2815+
// Removing flow from 'bJump' into 'bDest' may have made it possible to compact the latter.
2816+
BasicBlock* const uniquePred = bDest->GetUniquePred(this);
2817+
if ((uniquePred != nullptr) && fgCanCompactBlock(uniquePred))
2818+
{
2819+
JITDUMP(FMT_BB " can now be compacted into its remaining predecessor.\n", bDest->bbNum);
2820+
fgCompactBlock(uniquePred);
2821+
}
2822+
28182823
return true;
28192824
}
28202825

src/coreclr/jit/optimizer.cpp

+12
Original file line numberDiff line numberDiff line change
@@ -2420,6 +2420,18 @@ PhaseStatus Compiler::optOptimizePreLayout()
24202420
modified |= fgExpandRarelyRunBlocks();
24212421
}
24222422

2423+
// Run a late pass of unconditional-to-conditional branch optimization, skipping handler blocks.
2424+
for (BasicBlock* block = fgFirstBB; block != fgFirstFuncletBB; block = block->Next())
2425+
{
2426+
if (!UsesFunclets() && block->hasHndIndex())
2427+
{
2428+
block = ehGetDsc(block->getHndIndex())->ebdHndLast;
2429+
continue;
2430+
}
2431+
2432+
modified |= fgOptimizeBranch(block);
2433+
}
2434+
24232435
return modified ? PhaseStatus::MODIFIED_EVERYTHING : PhaseStatus::MODIFIED_NOTHING;
24242436
}
24252437

0 commit comments

Comments
 (0)