Skip to content

Commit 3a3e1c7

Browse files
JIT: Set bbJumpKind and bbJumpDest during block initialization (#93415)
Followup to #93152. This refactor enforces new invariants on BasicBlock's bbJumpKind and bbJumpDest. In particular, whenever bbJumpKind is a kind that must have a jump target, bbJumpDest must be set, else bbJumpDest must be null. This means bbJumpKind and bbJumpDest must be simultaneously initialized/updated when creating/converting a jump block.
1 parent 90c417a commit 3a3e1c7

25 files changed

+480
-396
lines changed

src/coreclr/jit/block.cpp

Lines changed: 32 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,10 @@ size_t BasicBlock::s_Count;
2828
// The max # of tree nodes in any BB
2929
/* static */
3030
unsigned BasicBlock::s_nMaxTrees;
31+
32+
// Temporary target to initialize blocks with jumps
33+
/* static */
34+
BasicBlock BasicBlock::bbTempJumpDest;
3135
#endif // DEBUG
3236

3337
#ifdef DEBUG
@@ -1441,7 +1445,7 @@ bool BasicBlock::endsWithTailCallConvertibleToLoop(Compiler* comp, GenTree** tai
14411445
* Allocate a basic block but don't append it to the current BB list.
14421446
*/
14431447

1444-
BasicBlock* Compiler::bbNewBasicBlock(BBjumpKinds jumpKind)
1448+
BasicBlock* Compiler::bbNewBasicBlock()
14451449
{
14461450
BasicBlock* block;
14471451

@@ -1492,15 +1496,6 @@ BasicBlock* Compiler::bbNewBasicBlock(BBjumpKinds jumpKind)
14921496

14931497
block->bbEntryState = nullptr;
14941498

1495-
/* Record the jump kind in the block */
1496-
1497-
block->SetJumpKind(jumpKind DEBUG_ARG(this));
1498-
1499-
if (jumpKind == BBJ_THROW)
1500-
{
1501-
block->bbSetRunRarely();
1502-
}
1503-
15041499
#ifdef DEBUG
15051500
if (verbose)
15061501
{
@@ -1551,6 +1546,33 @@ BasicBlock* Compiler::bbNewBasicBlock(BBjumpKinds jumpKind)
15511546
return block;
15521547
}
15531548

1549+
BasicBlock* Compiler::bbNewBasicBlock(BBjumpKinds jumpKind, BasicBlock* jumpDest /* = nullptr */)
1550+
{
1551+
BasicBlock* block = bbNewBasicBlock();
1552+
block->SetJumpKindAndTarget(jumpKind, jumpDest DEBUG_ARG(this));
1553+
1554+
if (jumpKind == BBJ_THROW)
1555+
{
1556+
block->bbSetRunRarely();
1557+
}
1558+
1559+
return block;
1560+
}
1561+
1562+
BasicBlock* Compiler::bbNewBasicBlock(BBswtDesc* jumpSwt)
1563+
{
1564+
BasicBlock* block = bbNewBasicBlock();
1565+
block->SetSwitchKindAndTarget(jumpSwt);
1566+
return block;
1567+
}
1568+
1569+
BasicBlock* Compiler::bbNewBasicBlock(BBjumpKinds jumpKind, unsigned jumpOffs)
1570+
{
1571+
BasicBlock* block = bbNewBasicBlock();
1572+
block->SetJumpKindAndTarget(jumpKind, jumpOffs);
1573+
return block;
1574+
}
1575+
15541576
//------------------------------------------------------------------------
15551577
// isBBCallAlwaysPair: Determine if this is the first block of a BBJ_CALLFINALLY/BBJ_ALWAYS pair
15561578
//

src/coreclr/jit/block.h

Lines changed: 64 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -538,20 +538,26 @@ struct BasicBlock : private LIR::Range
538538
};
539539

540540
public:
541+
#ifdef DEBUG
542+
// When creating a block with a jump, we require its jump kind and target be initialized simultaneously.
543+
// In a few edge cases (for example, in Compiler::impImportLeave), we don't know the jump target at block creation.
544+
// In these cases, temporarily set the jump target to bbTempJumpDest, and update the jump target later.
545+
// We won't check jump targets against bbTempJumpDest in Release builds.
546+
static BasicBlock bbTempJumpDest;
547+
#endif // DEBUG
548+
541549
BBjumpKinds GetJumpKind() const
542550
{
543551
return bbJumpKind;
544552
}
545553

546-
void SetJumpKind(BBjumpKinds jumpKind DEBUG_ARG(Compiler* compiler))
554+
void SetJumpKind(BBjumpKinds jumpKind)
547555
{
548-
#ifdef DEBUG
549-
// BBJ_NONE should only be assigned when optimizing jumps in Compiler::optOptimizeLayout
550-
// TODO: Change assert to check if compiler is in appropriate optimization phase to use BBJ_NONE
551-
// (right now, this assertion does the null check to avoid unused variable warnings)
552-
assert((jumpKind != BBJ_NONE) || (compiler != nullptr));
553-
#endif // DEBUG
556+
// If this block's jump kind requires a target, ensure it is already set
557+
assert(HasJump() || !KindIs(BBJ_ALWAYS, BBJ_CALLFINALLY, BBJ_COND, BBJ_EHCATCHRET, BBJ_LEAVE));
554558
bbJumpKind = jumpKind;
559+
// If new jump kind requires a target, ensure a target is already set
560+
assert(HasJump() || !KindIs(BBJ_ALWAYS, BBJ_CALLFINALLY, BBJ_COND, BBJ_EHCATCHRET, BBJ_LEAVE));
555561
}
556562

557563
BasicBlock* Prev() const
@@ -611,54 +617,84 @@ struct BasicBlock : private LIR::Range
611617
return bbJumpOffs;
612618
}
613619

614-
void SetJumpOffs(unsigned jumpOffs)
620+
void SetJumpKindAndTarget(BBjumpKinds jumpKind, unsigned jumpOffs)
615621
{
622+
bbJumpKind = jumpKind;
616623
bbJumpOffs = jumpOffs;
624+
assert(KindIs(BBJ_ALWAYS, BBJ_COND, BBJ_LEAVE));
617625
}
618626

619627
BasicBlock* GetJumpDest() const
620628
{
629+
// If bbJumpKind indicates this block has a jump, bbJumpDest cannot be null
630+
assert(HasJump() || !KindIs(BBJ_ALWAYS, BBJ_CALLFINALLY, BBJ_COND, BBJ_EHCATCHRET, BBJ_LEAVE));
621631
return bbJumpDest;
622632
}
623633

624634
void SetJumpDest(BasicBlock* jumpDest)
625635
{
636+
// If bbJumpKind indicates this block has a jump,
637+
// bbJumpDest should have previously been set in SetJumpKindAndTarget().
638+
assert(HasJump() || !KindIs(BBJ_ALWAYS, BBJ_CALLFINALLY, BBJ_COND, BBJ_EHCATCHRET, BBJ_LEAVE));
639+
640+
// SetJumpKindAndTarget() nulls jumpDest for non-jump kinds,
641+
// so don't use SetJumpDest() to null bbJumpDest without updating bbJumpKind.
626642
bbJumpDest = jumpDest;
643+
assert(HasJump());
627644
}
628645

629-
void SetJumpKindAndTarget(BBjumpKinds jumpKind, BasicBlock* jumpDest)
646+
void SetJumpKindAndTarget(BBjumpKinds jumpKind, BasicBlock* jumpDest DEBUG_ARG(Compiler* compiler))
630647
{
631-
assert(jumpDest != nullptr);
648+
#ifdef DEBUG
649+
// BBJ_NONE should only be assigned when optimizing jumps in Compiler::optOptimizeLayout
650+
// TODO: Change assert to check if compiler is in appropriate optimization phase to use BBJ_NONE
651+
//
652+
// (right now, this assertion does the null check to avoid unused variable warnings)
653+
assert((jumpKind != BBJ_NONE) || (compiler != nullptr));
654+
#endif // DEBUG
655+
632656
bbJumpKind = jumpKind;
633657
bbJumpDest = jumpDest;
634-
assert(KindIs(BBJ_ALWAYS, BBJ_CALLFINALLY, BBJ_COND, BBJ_EHCATCHRET, BBJ_LEAVE));
658+
659+
// If bbJumpKind indicates this block has a jump, bbJumpDest cannot be null
660+
assert(HasJump() || !KindIs(BBJ_ALWAYS, BBJ_CALLFINALLY, BBJ_COND, BBJ_EHCATCHRET, BBJ_LEAVE));
661+
}
662+
663+
void SetJumpKindAndTarget(BBjumpKinds jumpKind DEBUG_ARG(Compiler* compiler))
664+
{
665+
BasicBlock* jumpDest = nullptr;
666+
SetJumpKindAndTarget(jumpKind, jumpDest DEBUG_ARG(compiler));
667+
}
668+
669+
bool HasJump() const
670+
{
671+
return (bbJumpDest != nullptr);
635672
}
636673

637674
bool HasJumpTo(const BasicBlock* jumpDest) const
638675
{
676+
assert(HasJump());
677+
assert(!KindIs(BBJ_SWITCH, BBJ_EHFINALLYRET));
639678
return (bbJumpDest == jumpDest);
640679
}
641680

642681
bool JumpsToNext() const
643682
{
683+
assert(HasJump());
644684
return (bbJumpDest == bbNext);
645685
}
646686

647687
BBswtDesc* GetJumpSwt() const
648688
{
689+
assert(KindIs(BBJ_SWITCH));
690+
assert(bbJumpSwt != nullptr);
649691
return bbJumpSwt;
650692
}
651693

652-
void SetJumpSwt(BBswtDesc* jumpSwt)
694+
void SetSwitchKindAndTarget(BBswtDesc* jumpSwt)
653695
{
654-
bbJumpSwt = jumpSwt;
655-
}
656-
657-
void SetJumpKindAndTarget(BBjumpKinds jumpKind, BBswtDesc* jumpSwt)
658-
{
659-
assert(jumpKind == BBJ_SWITCH);
660696
assert(jumpSwt != nullptr);
661-
bbJumpKind = jumpKind;
697+
bbJumpKind = BBJ_SWITCH;
662698
bbJumpSwt = jumpSwt;
663699
}
664700

@@ -1739,7 +1775,7 @@ inline BBArrayIterator BBEhfSuccList::end() const
17391775
inline BasicBlock::BBSuccList::BBSuccList(const BasicBlock* block)
17401776
{
17411777
assert(block != nullptr);
1742-
switch (block->GetJumpKind())
1778+
switch (block->bbJumpKind)
17431779
{
17441780
case BBJ_THROW:
17451781
case BBJ_RETURN:
@@ -1754,19 +1790,19 @@ inline BasicBlock::BBSuccList::BBSuccList(const BasicBlock* block)
17541790
case BBJ_EHCATCHRET:
17551791
case BBJ_EHFILTERRET:
17561792
case BBJ_LEAVE:
1757-
m_succs[0] = block->GetJumpDest();
1793+
m_succs[0] = block->bbJumpDest;
17581794
m_begin = &m_succs[0];
17591795
m_end = &m_succs[1];
17601796
break;
17611797

17621798
case BBJ_NONE:
1763-
m_succs[0] = block->Next();
1799+
m_succs[0] = block->bbNext;
17641800
m_begin = &m_succs[0];
17651801
m_end = &m_succs[1];
17661802
break;
17671803

17681804
case BBJ_COND:
1769-
m_succs[0] = block->Next();
1805+
m_succs[0] = block->bbNext;
17701806
m_begin = &m_succs[0];
17711807

17721808
// If both fall-through and branch successors are identical, then only include
@@ -1777,7 +1813,7 @@ inline BasicBlock::BBSuccList::BBSuccList(const BasicBlock* block)
17771813
}
17781814
else
17791815
{
1780-
m_succs[1] = block->GetJumpDest();
1816+
m_succs[1] = block->bbJumpDest;
17811817
m_end = &m_succs[2];
17821818
}
17831819
break;
@@ -1800,10 +1836,10 @@ inline BasicBlock::BBSuccList::BBSuccList(const BasicBlock* block)
18001836

18011837
case BBJ_SWITCH:
18021838
// We don't use the m_succs in-line data for switches; use the existing jump table in the block.
1803-
assert(block->GetJumpSwt() != nullptr);
1804-
assert(block->GetJumpSwt()->bbsDstTab != nullptr);
1805-
m_begin = block->GetJumpSwt()->bbsDstTab;
1806-
m_end = block->GetJumpSwt()->bbsDstTab + block->GetJumpSwt()->bbsCount;
1839+
assert(block->bbJumpSwt != nullptr);
1840+
assert(block->bbJumpSwt->bbsDstTab != nullptr);
1841+
m_begin = block->bbJumpSwt->bbsDstTab;
1842+
m_end = block->bbJumpSwt->bbsDstTab + block->bbJumpSwt->bbsCount;
18071843
break;
18081844

18091845
default:

src/coreclr/jit/codegenarm.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -125,7 +125,7 @@ BasicBlock* CodeGen::genCallFinally(BasicBlock* block)
125125

126126
assert(!block->IsLast());
127127
assert(block->Next()->KindIs(BBJ_ALWAYS));
128-
assert(!block->Next()->HasJumpTo(nullptr));
128+
assert(block->Next()->HasJump());
129129
assert(block->Next()->GetJumpDest()->bbFlags & BBF_FINALLY_TARGET);
130130

131131
bbFinallyRet = block->Next()->GetJumpDest();

src/coreclr/jit/codegencommon.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -856,7 +856,8 @@ BasicBlock* CodeGen::genCreateTempLabel()
856856
compiler->fgSafeBasicBlockCreation = true;
857857
#endif
858858

859-
BasicBlock* block = compiler->bbNewBasicBlock(BBJ_NONE);
859+
// Label doesn't need a jump kind
860+
BasicBlock* block = compiler->bbNewBasicBlock();
860861

861862
#ifdef DEBUG
862863
compiler->fgSafeBasicBlockCreation = false;

src/coreclr/jit/compiler.h

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3221,7 +3221,10 @@ class Compiler
32213221
bool fgSafeBasicBlockCreation;
32223222
#endif
32233223

3224-
BasicBlock* bbNewBasicBlock(BBjumpKinds jumpKind);
3224+
BasicBlock* bbNewBasicBlock();
3225+
BasicBlock* bbNewBasicBlock(BBjumpKinds jumpKind, BasicBlock* jumpDest = nullptr);
3226+
BasicBlock* bbNewBasicBlock(BBswtDesc* jumpSwt);
3227+
BasicBlock* bbNewBasicBlock(BBjumpKinds jumpKind, unsigned jumpOffs);
32253228

32263229
/*
32273230
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
@@ -4582,39 +4585,41 @@ class Compiler
45824585
}
45834586
}
45844587

4585-
BasicBlock* fgNewBasicBlock(BBjumpKinds jumpKind);
45864588
bool fgEnsureFirstBBisScratch();
45874589
bool fgFirstBBisScratch();
45884590
bool fgBBisScratch(BasicBlock* block);
45894591

45904592
void fgExtendEHRegionBefore(BasicBlock* block);
45914593
void fgExtendEHRegionAfter(BasicBlock* block);
45924594

4593-
BasicBlock* fgNewBBbefore(BBjumpKinds jumpKind, BasicBlock* block, bool extendRegion);
4595+
BasicBlock* fgNewBBbefore(BBjumpKinds jumpKind, BasicBlock* block, bool extendRegion, BasicBlock* jumpDest = nullptr);
45944596

4595-
BasicBlock* fgNewBBafter(BBjumpKinds jumpKind, BasicBlock* block, bool extendRegion);
4597+
BasicBlock* fgNewBBafter(BBjumpKinds jumpKind, BasicBlock* block, bool extendRegion, BasicBlock* jumpDest = nullptr);
45964598

4597-
BasicBlock* fgNewBBFromTreeAfter(BBjumpKinds jumpKind, BasicBlock* block, GenTree* tree, DebugInfo& debugInfo, bool updateSideEffects = false);
4599+
BasicBlock* fgNewBBFromTreeAfter(BBjumpKinds jumpKind, BasicBlock* block, GenTree* tree, DebugInfo& debugInfo, BasicBlock* jumpDest = nullptr, bool updateSideEffects = false);
45984600

45994601
BasicBlock* fgNewBBinRegion(BBjumpKinds jumpKind,
46004602
unsigned tryIndex,
46014603
unsigned hndIndex,
46024604
BasicBlock* nearBlk,
4605+
BasicBlock* jumpDest = nullptr,
46034606
bool putInFilter = false,
46044607
bool runRarely = false,
46054608
bool insertAtEnd = false);
46064609

46074610
BasicBlock* fgNewBBinRegion(BBjumpKinds jumpKind,
46084611
BasicBlock* srcBlk,
4612+
BasicBlock* jumpDest = nullptr,
46094613
bool runRarely = false,
46104614
bool insertAtEnd = false);
46114615

4612-
BasicBlock* fgNewBBinRegion(BBjumpKinds jumpKind);
4616+
BasicBlock* fgNewBBinRegion(BBjumpKinds jumpKind, BasicBlock* jumpDest = nullptr);
46134617

46144618
BasicBlock* fgNewBBinRegionWorker(BBjumpKinds jumpKind,
46154619
BasicBlock* afterBlk,
46164620
unsigned xcptnIndex,
4617-
bool putInTryRegion);
4621+
bool putInTryRegion,
4622+
BasicBlock* jumpDest = nullptr);
46184623

46194624
void fgInsertBBbefore(BasicBlock* insertBeforeBlk, BasicBlock* newBlk);
46204625
void fgInsertBBafter(BasicBlock* insertAfterBlk, BasicBlock* newBlk);

0 commit comments

Comments
 (0)