Skip to content

Commit 867250c

Browse files
JIT: Allow hot/cold splitting between a BBJ_COND block and its false target (#96431)
Next step for #93020. When doing hot/cold splitting, if the first cold block succeeds a BBJ_COND block (meaning the false target is the first cold block), we previously needed to insert a BBJ_ALWAYS block at the end of the hot section to unconditionally jump to the cold section. Since we will need to conditionally generate a jump to the false target depending on its location once bbFalseTarget can diverge from bbNext, this seemed like a nice opportunity to add that logic in, and instead generate a jump to the cold section by checking if a jump is needed to the false target, rather than by appending a BBJ_ALWAYS block to the hot section.
1 parent 1337d7a commit 867250c

File tree

6 files changed

+40
-55
lines changed

6 files changed

+40
-55
lines changed

Diff for: src/coreclr/jit/block.cpp

+16-1
Original file line numberDiff line numberDiff line change
@@ -294,12 +294,27 @@ bool BasicBlock::IsFirstColdBlock(Compiler* compiler) const
294294
// Returns:
295295
// true if block is a BBJ_ALWAYS to the next block that we can fall into
296296
//
297-
bool BasicBlock::CanRemoveJumpToNext(Compiler* compiler)
297+
bool BasicBlock::CanRemoveJumpToNext(Compiler* compiler) const
298298
{
299299
assert(KindIs(BBJ_ALWAYS));
300300
return JumpsToNext() && !hasAlign() && !compiler->fgInDifferentRegions(this, bbTarget);
301301
}
302302

303+
//------------------------------------------------------------------------
304+
// CanRemoveJumpToFalseTarget: determine if jump to false target can be omitted
305+
//
306+
// Arguments:
307+
// compiler - current compiler instance
308+
//
309+
// Returns:
310+
// true if block is a BBJ_COND that can fall into its false target
311+
//
312+
bool BasicBlock::CanRemoveJumpToFalseTarget(Compiler* compiler) const
313+
{
314+
assert(KindIs(BBJ_COND));
315+
return NextIs(bbFalseTarget) && !hasAlign() && !compiler->fgInDifferentRegions(this, bbFalseTarget);
316+
}
317+
303318
//------------------------------------------------------------------------
304319
// checkPredListOrder: see if pred list is properly ordered
305320
//

Diff for: src/coreclr/jit/block.h

+3-1
Original file line numberDiff line numberDiff line change
@@ -616,7 +616,9 @@ struct BasicBlock : private LIR::Range
616616

617617
bool IsFirstColdBlock(Compiler* compiler) const;
618618

619-
bool CanRemoveJumpToNext(Compiler* compiler);
619+
bool CanRemoveJumpToNext(Compiler* compiler) const;
620+
621+
bool CanRemoveJumpToFalseTarget(Compiler* compiler) const;
620622

621623
unsigned GetTargetOffs() const
622624
{

Diff for: src/coreclr/jit/codegencommon.cpp

+7
Original file line numberDiff line numberDiff line change
@@ -395,6 +395,13 @@ void CodeGen::genMarkLabelsForCodegen()
395395
case BBJ_COND:
396396
JITDUMP(" " FMT_BB " : branch target\n", block->GetTrueTarget()->bbNum);
397397
block->GetTrueTarget()->SetFlags(BBF_HAS_LABEL);
398+
399+
// If we need a jump to the false target, give it a label
400+
if (!block->CanRemoveJumpToFalseTarget(compiler))
401+
{
402+
JITDUMP(" " FMT_BB " : branch target\n", block->GetFalseTarget()->bbNum);
403+
block->GetFalseTarget()->SetFlags(BBF_HAS_LABEL);
404+
}
398405
break;
399406

400407
case BBJ_SWITCH:

Diff for: src/coreclr/jit/codegenlinear.cpp

+8-2
Original file line numberDiff line numberDiff line change
@@ -314,8 +314,8 @@ void CodeGen::genCodeForBBlist()
314314
printf("\nThis is the start of the cold region of the method\n");
315315
}
316316
#endif
317-
// We should never have a block that falls through into the Cold section
318-
noway_assert(!block->Prev()->bbFallsThrough());
317+
// We should never split call/finally pairs between hot/cold sections
318+
noway_assert(!block->isBBCallFinallyPairTail());
319319

320320
needLabel = true;
321321
}
@@ -2619,6 +2619,12 @@ void CodeGen::genCodeForJcc(GenTreeCC* jcc)
26192619
assert(jcc->OperIs(GT_JCC));
26202620

26212621
inst_JCC(jcc->gtCondition, compiler->compCurBB->GetTrueTarget());
2622+
2623+
// If we cannot fall into the false target, emit a jump to it
2624+
if (!compiler->compCurBB->CanRemoveJumpToFalseTarget(compiler))
2625+
{
2626+
inst_JMP(EJ_jmp, compiler->compCurBB->GetFalseTarget());
2627+
}
26222628
}
26232629

26242630
//------------------------------------------------------------------------

Diff for: src/coreclr/jit/compiler.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -6406,7 +6406,7 @@ class Compiler
64066406
bool fgIsThrow(GenTree* tree);
64076407

64086408
public:
6409-
bool fgInDifferentRegions(BasicBlock* blk1, BasicBlock* blk2);
6409+
bool fgInDifferentRegions(const BasicBlock* blk1, const BasicBlock* blk2) const;
64106410

64116411
private:
64126412
bool fgIsBlockCold(BasicBlock* block);

Diff for: src/coreclr/jit/flowgraph.cpp

+5-50
Original file line numberDiff line numberDiff line change
@@ -635,7 +635,7 @@ bool Compiler::fgIsThrow(GenTree* tree)
635635
* It returns false when the blocks are both in the same regions
636636
*/
637637

638-
bool Compiler::fgInDifferentRegions(BasicBlock* blk1, BasicBlock* blk2)
638+
bool Compiler::fgInDifferentRegions(const BasicBlock* blk1, const BasicBlock* blk2) const
639639
{
640640
noway_assert(blk1 != nullptr);
641641
noway_assert(blk2 != nullptr);
@@ -3185,56 +3185,11 @@ PhaseStatus Compiler::fgDetermineFirstColdBlock()
31853185
}
31863186
}
31873187

3188-
// When the last Hot block fall through into the Cold section
3189-
// we may need to add a jump
3190-
//
3191-
if (prevToFirstColdBlock->bbFallsThrough())
3188+
// Don't split up call/finally pairs
3189+
if (prevToFirstColdBlock->isBBCallFinallyPair())
31923190
{
3193-
switch (prevToFirstColdBlock->GetKind())
3194-
{
3195-
default:
3196-
noway_assert(!"Unhandled jumpkind in fgDetermineFirstColdBlock()");
3197-
break;
3198-
3199-
case BBJ_CALLFINALLY:
3200-
// A BBJ_CALLFINALLY that falls through is always followed
3201-
// by an empty BBJ_CALLFINALLYRET.
3202-
//
3203-
assert(prevToFirstColdBlock->isBBCallFinallyPair());
3204-
firstColdBlock =
3205-
firstColdBlock->Next(); // Note that this assignment could make firstColdBlock == nullptr
3206-
break;
3207-
3208-
case BBJ_COND:
3209-
//
3210-
// This is a slightly more complicated case, because we will
3211-
// probably need to insert a block to jump to the cold section.
3212-
//
3213-
3214-
// TODO-NoFallThrough: Below logic will need additional check once bbFalseTarget can diverge from
3215-
// bbNext
3216-
assert(prevToFirstColdBlock->FalseTargetIs(firstColdBlock));
3217-
if (firstColdBlock->isEmpty() && firstColdBlock->KindIs(BBJ_ALWAYS))
3218-
{
3219-
// We can just use this block as the transitionBlock
3220-
firstColdBlock = firstColdBlock->Next();
3221-
// Note that this assignment could make firstColdBlock == NULL
3222-
}
3223-
else
3224-
{
3225-
BasicBlock* transitionBlock =
3226-
fgNewBBafter(BBJ_ALWAYS, prevToFirstColdBlock, true, firstColdBlock);
3227-
transitionBlock->inheritWeight(firstColdBlock);
3228-
prevToFirstColdBlock->SetFalseTarget(transitionBlock);
3229-
3230-
// Update the predecessor list for firstColdBlock
3231-
fgReplacePred(firstColdBlock, prevToFirstColdBlock, transitionBlock);
3232-
3233-
// Add prevToFirstColdBlock as a predecessor for transitionBlock
3234-
fgAddRefPred(transitionBlock, prevToFirstColdBlock);
3235-
}
3236-
break;
3237-
}
3191+
// Note that this assignment could make firstColdBlock == nullptr
3192+
firstColdBlock = firstColdBlock->Next();
32383193
}
32393194
}
32403195

0 commit comments

Comments
 (0)