Skip to content

Commit 5e1caf1

Browse files
JIT: Use successor edges instead of block targets for BBJ_EHFINALLYRET (#98563)
Part of #93020. This is a first step in a broader effort to replace BasicBlock's jump targets (bbTarget, bbFalseTarget, etc.) with successor flow edges. This PR also adds overloaded implementations for commonly used edge maintenance methods (fgReplacePred, fgRemoveRefPred, etc.) that can take advantage of the cheap access to successor edges (i.e. without calling fgGetPredForBlock -- hopefully we'll be able to get rid of that at some point).
1 parent b313138 commit 5e1caf1

9 files changed

+250
-92
lines changed

src/coreclr/jit/block.cpp

+6-6
Original file line numberDiff line numberDiff line change
@@ -658,12 +658,12 @@ void BasicBlock::dspKind() const
658658
}
659659
else
660660
{
661-
const unsigned jumpCnt = bbEhfTargets->bbeCount;
662-
BasicBlock** const jumpTab = bbEhfTargets->bbeSuccs;
661+
const unsigned jumpCnt = bbEhfTargets->bbeCount;
662+
FlowEdge** const jumpTab = bbEhfTargets->bbeSuccs;
663663

664664
for (unsigned i = 0; i < jumpCnt; i++)
665665
{
666-
printf("%c%s", (i == 0) ? ' ' : ',', dspBlockNum(jumpTab[i]));
666+
printf("%c%s", (i == 0) ? ' ' : ',', dspBlockNum(jumpTab[i]->getDestinationBlock()));
667667
}
668668
}
669669

@@ -1214,7 +1214,7 @@ BasicBlock* BasicBlock::GetSucc(unsigned i) const
12141214
}
12151215

12161216
case BBJ_EHFINALLYRET:
1217-
return bbEhfTargets->bbeSuccs[i];
1217+
return bbEhfTargets->bbeSuccs[i]->getDestinationBlock();
12181218

12191219
case BBJ_SWITCH:
12201220
return bbSwtTargets->bbsDstTab[i];
@@ -1315,7 +1315,7 @@ BasicBlock* BasicBlock::GetSucc(unsigned i, Compiler* comp)
13151315
case BBJ_EHFINALLYRET:
13161316
assert(bbEhfTargets != nullptr);
13171317
assert(i < bbEhfTargets->bbeCount);
1318-
return bbEhfTargets->bbeSuccs[i];
1318+
return bbEhfTargets->bbeSuccs[i]->getDestinationBlock();
13191319

13201320
case BBJ_CALLFINALLY:
13211321
case BBJ_CALLFINALLYRET:
@@ -1792,7 +1792,7 @@ BBehfDesc::BBehfDesc(Compiler* comp, const BBehfDesc* other) : bbeCount(other->b
17921792
{
17931793
// Allocate and fill in a new dst tab
17941794
//
1795-
bbeSuccs = new (comp, CMK_BasicBlock) BasicBlock*[bbeCount];
1795+
bbeSuccs = new (comp, CMK_FlowEdge) FlowEdge*[bbeCount];
17961796
for (unsigned i = 0; i < bbeCount; i++)
17971797
{
17981798
bbeSuccs[i] = other->bbeSuccs[i];

src/coreclr/jit/block.h

+60-18
Original file line numberDiff line numberDiff line change
@@ -314,21 +314,27 @@ class PredBlockList
314314
//
315315
class BBArrayIterator
316316
{
317-
BasicBlock* const* m_bbEntry;
317+
// Quirk: Some BasicBlock kinds refer to their successors with BasicBlock pointers,
318+
// while others use FlowEdge pointers. Eventually, every type will use FlowEdge pointers.
319+
// For now, support iterating with both types.
320+
union {
321+
BasicBlock* const* m_bbEntry;
322+
FlowEdge* const* m_edgeEntry;
323+
};
324+
325+
bool iterateEdges;
318326

319327
public:
320-
BBArrayIterator(BasicBlock* const* bbEntry) : m_bbEntry(bbEntry)
328+
BBArrayIterator(BasicBlock* const* bbEntry) : m_bbEntry(bbEntry), iterateEdges(false)
321329
{
322330
}
323331

324-
BasicBlock* operator*() const
332+
BBArrayIterator(FlowEdge* const* edgeEntry) : m_edgeEntry(edgeEntry), iterateEdges(true)
325333
{
326-
assert(m_bbEntry != nullptr);
327-
BasicBlock* bTarget = *m_bbEntry;
328-
assert(bTarget != nullptr);
329-
return bTarget;
330334
}
331335

336+
BasicBlock* operator*() const;
337+
332338
BBArrayIterator& operator++()
333339
{
334340
assert(m_bbEntry != nullptr);
@@ -1570,9 +1576,22 @@ struct BasicBlock : private LIR::Range
15701576
// need to call a function or execute another `switch` to get them. Also, pre-compute the begin and end
15711577
// points of the iteration, for use by BBArrayIterator. `m_begin` and `m_end` will either point at
15721578
// `m_succs` or at the switch table successor array.
1573-
BasicBlock* m_succs[2];
1574-
BasicBlock* const* m_begin;
1575-
BasicBlock* const* m_end;
1579+
BasicBlock* m_succs[2];
1580+
1581+
// Quirk: Some BasicBlock kinds refer to their successors with BasicBlock pointers,
1582+
// while others use FlowEdge pointers. Eventually, every type will use FlowEdge pointers.
1583+
// For now, support iterating with both types.
1584+
union {
1585+
BasicBlock* const* m_begin;
1586+
FlowEdge* const* m_beginEdge;
1587+
};
1588+
1589+
union {
1590+
BasicBlock* const* m_end;
1591+
FlowEdge* const* m_endEdge;
1592+
};
1593+
1594+
bool iterateEdges;
15761595

15771596
public:
15781597
BBSuccList(const BasicBlock* block);
@@ -1879,8 +1898,8 @@ inline BBArrayIterator BBSwitchTargetList::end() const
18791898
//
18801899
struct BBehfDesc
18811900
{
1882-
BasicBlock** bbeSuccs; // array of `BasicBlock*` pointing to BBJ_EHFINALLYRET block successors
1883-
unsigned bbeCount; // size of `bbeSuccs` array
1901+
FlowEdge** bbeSuccs; // array of `FlowEdge*` pointing to BBJ_EHFINALLYRET block successors
1902+
unsigned bbeCount; // size of `bbeSuccs` array
18841903

18851904
BBehfDesc() : bbeSuccs(nullptr), bbeCount(0)
18861905
{
@@ -1913,6 +1932,8 @@ inline BBArrayIterator BBEhfSuccList::end() const
19131932
inline BasicBlock::BBSuccList::BBSuccList(const BasicBlock* block)
19141933
{
19151934
assert(block != nullptr);
1935+
iterateEdges = false;
1936+
19161937
switch (block->bbKind)
19171938
{
19181939
case BBJ_THROW:
@@ -1957,14 +1978,16 @@ inline BasicBlock::BBSuccList::BBSuccList(const BasicBlock* block)
19571978
// been computed.
19581979
if (block->GetEhfTargets() == nullptr)
19591980
{
1960-
m_begin = nullptr;
1961-
m_end = nullptr;
1981+
m_beginEdge = nullptr;
1982+
m_endEdge = nullptr;
19621983
}
19631984
else
19641985
{
1965-
m_begin = block->GetEhfTargets()->bbeSuccs;
1966-
m_end = block->GetEhfTargets()->bbeSuccs + block->GetEhfTargets()->bbeCount;
1986+
m_beginEdge = block->GetEhfTargets()->bbeSuccs;
1987+
m_endEdge = block->GetEhfTargets()->bbeSuccs + block->GetEhfTargets()->bbeCount;
19671988
}
1989+
1990+
iterateEdges = true;
19681991
break;
19691992

19701993
case BBJ_SWITCH:
@@ -1984,12 +2007,12 @@ inline BasicBlock::BBSuccList::BBSuccList(const BasicBlock* block)
19842007

19852008
inline BBArrayIterator BasicBlock::BBSuccList::begin() const
19862009
{
1987-
return BBArrayIterator(m_begin);
2010+
return (iterateEdges ? BBArrayIterator(m_beginEdge) : BBArrayIterator(m_begin));
19882011
}
19892012

19902013
inline BBArrayIterator BasicBlock::BBSuccList::end() const
19912014
{
1992-
return BBArrayIterator(m_end);
2015+
return (iterateEdges ? BBArrayIterator(m_endEdge) : BBArrayIterator(m_end));
19932016
}
19942017

19952018
// We have a simpler struct, BasicBlockList, which is simply a singly-linked
@@ -2192,6 +2215,25 @@ struct FlowEdge
21922215
}
21932216
};
21942217

2218+
// BasicBlock iterator implementations (that are required to be defined after the declaration of FlowEdge)
2219+
2220+
inline BasicBlock* BBArrayIterator::operator*() const
2221+
{
2222+
if (iterateEdges)
2223+
{
2224+
assert(m_edgeEntry != nullptr);
2225+
FlowEdge* edgeTarget = *m_edgeEntry;
2226+
assert(edgeTarget != nullptr);
2227+
assert(edgeTarget->getDestinationBlock() != nullptr);
2228+
return edgeTarget->getDestinationBlock();
2229+
}
2230+
2231+
assert(m_bbEntry != nullptr);
2232+
BasicBlock* bTarget = *m_bbEntry;
2233+
assert(bTarget != nullptr);
2234+
return bTarget;
2235+
}
2236+
21952237
// Pred list iterator implementations (that are required to be defined after the declaration of BasicBlock and FlowEdge)
21962238

21972239
inline PredEdgeList::iterator::iterator(FlowEdge* pred) : m_pred(pred)

src/coreclr/jit/compiler.h

+7-1
Original file line numberDiff line numberDiff line change
@@ -5883,6 +5883,8 @@ class Compiler
58835883

58845884
FlowEdge* fgRemoveRefPred(BasicBlock* block, BasicBlock* blockPred);
58855885

5886+
void fgRemoveRefPred(FlowEdge* edge);
5887+
58865888
FlowEdge* fgRemoveAllRefPreds(BasicBlock* block, BasicBlock* blockPred);
58875889

58885890
void fgRemoveBlockAsPred(BasicBlock* block);
@@ -5893,12 +5895,16 @@ class Compiler
58935895

58945896
void fgReplaceEhfSuccessor(BasicBlock* block, BasicBlock* oldSucc, BasicBlock* newSucc);
58955897

5896-
void fgRemoveEhfSuccessor(BasicBlock* block, BasicBlock* succ);
5898+
void fgRemoveEhfSuccessor(BasicBlock* block, const unsigned succIndex);
5899+
5900+
void fgRemoveEhfSuccessor(FlowEdge* succEdge);
58975901

58985902
void fgReplaceJumpTarget(BasicBlock* block, BasicBlock* oldTarget, BasicBlock* newTarget);
58995903

59005904
void fgReplacePred(BasicBlock* block, BasicBlock* oldPred, BasicBlock* newPred);
59015905

5906+
void fgReplacePred(FlowEdge* edge, BasicBlock* const newPred);
5907+
59025908
// initializingPreds is only 'true' when we are computing preds in fgLinkBasicBlocks()
59035909
template <bool initializingPreds = false>
59045910
FlowEdge* fgAddRefPred(BasicBlock* block, BasicBlock* blockPred, FlowEdge* oldEdge = nullptr);

src/coreclr/jit/compiler.hpp

+2-2
Original file line numberDiff line numberDiff line change
@@ -657,7 +657,7 @@ BasicBlockVisit BasicBlock::VisitAllSuccs(Compiler* comp, TFunc func)
657657
{
658658
for (unsigned i = 0; i < bbEhfTargets->bbeCount; i++)
659659
{
660-
RETURN_ON_ABORT(func(bbEhfTargets->bbeSuccs[i]));
660+
RETURN_ON_ABORT(func(bbEhfTargets->bbeSuccs[i]->getDestinationBlock()));
661661
}
662662
}
663663

@@ -732,7 +732,7 @@ BasicBlockVisit BasicBlock::VisitRegularSuccs(Compiler* comp, TFunc func)
732732
{
733733
for (unsigned i = 0; i < bbEhfTargets->bbeCount; i++)
734734
{
735-
RETURN_ON_ABORT(func(bbEhfTargets->bbeSuccs[i]));
735+
RETURN_ON_ABORT(func(bbEhfTargets->bbeSuccs[i]->getDestinationBlock()));
736736
}
737737
}
738738

0 commit comments

Comments
 (0)