Skip to content

Commit d165b64

Browse files
amanasifkhalidmikelle-rogers
authored andcommitted
JIT: Replace BlockSet with BitVec, and remove BB epoch (dotnet#110034)
Part of dotnet#107749. Prerequisite for dotnet#110026. Use postorder number-based BitVecs in RBO and block layout. Use bbID-based BitVecs in fgIncorporateProfileData. This runs early enough in the JIT frontend such that I would expect bbIDs and bbNums to be 1:1, so I don't expect any TP impact from this change. Switch descriptor creation still uses bbNums as a key into a BitVec as a workaround for BB epoch invariants -- I'll try switching this over to bbID in a follow-up to evaluate the TP cost of a sparser bitset.
1 parent d84aeb1 commit d165b64

14 files changed

+73
-280
lines changed

src/coreclr/jit/CMakeLists.txt

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -299,7 +299,6 @@ set( JIT_HEADERS
299299
bitsetops.h
300300
bitvec.h
301301
block.h
302-
blockset.h
303302
codegen.h
304303
codegeninterface.h
305304
compiler.h

src/coreclr/jit/block.cpp

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -617,8 +617,7 @@ void BasicBlock::dspSuccs(Compiler* compiler)
617617
// compute it ourselves here.
618618
if (bbKind == BBJ_SWITCH)
619619
{
620-
// Create a set with all the successors. Don't use BlockSet, so we don't need to worry
621-
// about the BlockSet epoch.
620+
// Create a set with all the successors.
622621
unsigned bbNumMax = compiler->fgBBNumMax;
623622
BitVecTraits bitVecTraits(bbNumMax + 1, compiler);
624623
BitVec uniqueSuccBlocks(BitVecOps::MakeEmpty(&bitVecTraits));
@@ -1036,10 +1035,10 @@ unsigned JitPtrKeyFuncs<BasicBlock>::GetHashCode(const BasicBlock* ptr)
10361035
unsigned hash = SsaStressHashHelper();
10371036
if (hash != 0)
10381037
{
1039-
return (hash ^ (ptr->bbNum << 16) ^ ptr->bbNum);
1038+
return (hash ^ (ptr->bbID << 16) ^ ptr->bbID);
10401039
}
10411040
#endif
1042-
return ptr->bbNum;
1041+
return ptr->bbID;
10431042
}
10441043

10451044
//------------------------------------------------------------------------

src/coreclr/jit/block.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,6 @@ XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
2323
// Defines VARSET_TP
2424
#include "varset.h"
2525

26-
#include "blockset.h"
2726
#include "jitstd.h"
2827
#include "bitvec.h"
2928
#include "jithashtable.h"

src/coreclr/jit/blockset.h

Lines changed: 0 additions & 61 deletions
This file was deleted.

src/coreclr/jit/compiler.h

Lines changed: 1 addition & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,6 @@ XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
3636
#include "regalloc.h"
3737
#include "sm.h"
3838
#include "cycletimer.h"
39-
#include "blockset.h"
4039
#include "arraystack.h"
4140
#include "priorityqueue.h"
4241
#include "hashbv.h"
@@ -5225,65 +5224,6 @@ class Compiler
52255224
return getAllocator(cmk).allocate<T>(fgBBNumMax + 1);
52265225
}
52275226

5228-
// BlockSets are relative to a specific set of BasicBlock numbers. If that changes
5229-
// (if the blocks are renumbered), this changes. BlockSets from different epochs
5230-
// cannot be meaningfully combined. Note that new blocks can be created with higher
5231-
// block numbers without changing the basic block epoch. These blocks *cannot*
5232-
// participate in a block set until the blocks are all renumbered, causing the epoch
5233-
// to change. This is useful if continuing to use previous block sets is valuable.
5234-
// If the epoch is zero, then it is uninitialized, and block sets can't be used.
5235-
unsigned fgCurBBEpoch = 0;
5236-
5237-
unsigned GetCurBasicBlockEpoch()
5238-
{
5239-
return fgCurBBEpoch;
5240-
}
5241-
5242-
// The number of basic blocks in the current epoch. When the blocks are renumbered,
5243-
// this is fgBBcount. As blocks are added, fgBBcount increases, fgCurBBEpochSize remains
5244-
// the same, until a new BasicBlock epoch is created, such as when the blocks are all renumbered.
5245-
unsigned fgCurBBEpochSize = 0;
5246-
5247-
// The number of "size_t" elements required to hold a bitset large enough for fgCurBBEpochSize
5248-
// bits. This is precomputed to avoid doing math every time BasicBlockBitSetTraits::GetArrSize() is called.
5249-
unsigned fgBBSetCountInSizeTUnits = 0;
5250-
5251-
void NewBasicBlockEpoch()
5252-
{
5253-
INDEBUG(unsigned oldEpochArrSize = fgBBSetCountInSizeTUnits);
5254-
5255-
// We have a new epoch. Compute and cache the size needed for new BlockSets.
5256-
fgCurBBEpoch++;
5257-
fgCurBBEpochSize = fgBBNumMax + 1;
5258-
fgBBSetCountInSizeTUnits =
5259-
roundUp(fgCurBBEpochSize, (unsigned)(sizeof(size_t) * 8)) / unsigned(sizeof(size_t) * 8);
5260-
5261-
#ifdef DEBUG
5262-
if (verbose)
5263-
{
5264-
unsigned epochArrSize = BasicBlockBitSetTraits::GetArrSize(this);
5265-
printf("\nNew BlockSet epoch %d, # of blocks (including unused BB00): %u, bitset array size: %u (%s)",
5266-
fgCurBBEpoch, fgCurBBEpochSize, epochArrSize, (epochArrSize <= 1) ? "short" : "long");
5267-
if ((fgCurBBEpoch != 1) && ((oldEpochArrSize <= 1) != (epochArrSize <= 1)))
5268-
{
5269-
// If we're not just establishing the first epoch, and the epoch array size has changed such that we're
5270-
// going to change our bitset representation from short (just a size_t bitset) to long (a pointer to an
5271-
// array of size_t bitsets), then print that out.
5272-
printf("; NOTE: BlockSet size was previously %s!", (oldEpochArrSize <= 1) ? "short" : "long");
5273-
}
5274-
printf("\n");
5275-
}
5276-
#endif // DEBUG
5277-
}
5278-
5279-
void EnsureBasicBlockEpoch()
5280-
{
5281-
if (fgCurBBEpochSize != fgBBNumMax + 1)
5282-
{
5283-
NewBasicBlockEpoch();
5284-
}
5285-
}
5286-
52875227
bool fgEnsureFirstBBisScratch();
52885228
bool fgFirstBBisScratch();
52895229
bool fgBBisScratch(BasicBlock* block);
@@ -6305,7 +6245,7 @@ class Compiler
63056245
};
63066246

63076247
template <bool hasEH>
6308-
void fgMoveHotJumps();
6248+
void fgMoveHotJumps(FlowGraphDfsTree* dfsTree);
63096249

63106250
bool fgFuncletsAreCold();
63116251

src/coreclr/jit/compilerbitsettraits.h

Lines changed: 0 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -69,30 +69,6 @@ class AllVarBitSetTraits : public CompAllocBitSetTraits
6969
static inline BitSetSupport::BitSetOpCounter* GetOpCounter(Compiler* comp);
7070
};
7171

72-
///////////////////////////////////////////////////////////////////////////////
73-
//
74-
// BasicBlockBitSetTraits
75-
//
76-
// This class is customizes the bit set to represent sets of BasicBlocks.
77-
// The size of the bitset is determined by maximum assigned BasicBlock number
78-
// (Compiler::fgBBNumMax) (Note that fgBBcount is not equal to this during inlining,
79-
// when fgBBcount is the number of blocks in the inlined function, but the assigned
80-
// block numbers are higher than the inliner function. fgBBNumMax counts both.
81-
// Thus, if you only care about the inlinee, during inlining, this bit set will waste
82-
// the lower numbered block bits.) The Compiler* tracks the BasicBlock epochs.
83-
//
84-
class BasicBlockBitSetTraits : public CompAllocBitSetTraits
85-
{
86-
public:
87-
static inline unsigned GetSize(Compiler* comp);
88-
89-
static inline unsigned GetArrSize(Compiler* comp);
90-
91-
static inline unsigned GetEpoch(class Compiler* comp);
92-
93-
static inline BitSetSupport::BitSetOpCounter* GetOpCounter(Compiler* comp);
94-
};
95-
9672
///////////////////////////////////////////////////////////////////////////////
9773
//
9874
// BitVecTraits

src/coreclr/jit/compilerbitsettraits.hpp

Lines changed: 0 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -96,40 +96,6 @@ BitSetSupport::BitSetOpCounter* AllVarBitSetTraits::GetOpCounter(Compiler* comp)
9696
#endif
9797
}
9898

99-
///////////////////////////////////////////////////////////////////////////////
100-
//
101-
// BasicBlockBitSetTraits
102-
//
103-
///////////////////////////////////////////////////////////////////////////////
104-
105-
// static
106-
unsigned BasicBlockBitSetTraits::GetSize(Compiler* comp)
107-
{
108-
return comp->fgCurBBEpochSize;
109-
}
110-
111-
// static
112-
unsigned BasicBlockBitSetTraits::GetArrSize(Compiler* comp)
113-
{
114-
// Assert that the epoch has been initialized. This is a convenient place to assert this because
115-
// GetArrSize() is called for every function, via IsShort().
116-
assert(GetEpoch(comp) != 0);
117-
118-
return comp->fgBBSetCountInSizeTUnits; // This is precomputed to avoid doing math every time this function is called
119-
}
120-
121-
// static
122-
unsigned BasicBlockBitSetTraits::GetEpoch(Compiler* comp)
123-
{
124-
return comp->GetCurBasicBlockEpoch();
125-
}
126-
127-
// static
128-
BitSetSupport::BitSetOpCounter* BasicBlockBitSetTraits::GetOpCounter(Compiler* comp)
129-
{
130-
return nullptr;
131-
}
132-
13399
///////////////////////////////////////////////////////////////////////////////
134100
//
135101
// BitVecTraits

src/coreclr/jit/fgbasic.cpp

Lines changed: 0 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -5400,30 +5400,6 @@ bool Compiler::fgRenumberBlocks()
54005400
JITDUMP("=============== No blocks renumbered!\n");
54015401
}
54025402

5403-
// Now update the BlockSet epoch, which depends on the block numbers.
5404-
// If any blocks have been renumbered then create a new BlockSet epoch.
5405-
// Even if we have not renumbered any blocks, we might still need to force
5406-
// a new BlockSet epoch, for one of several reasons. If there are any new
5407-
// blocks with higher numbers than the former maximum numbered block, then we
5408-
// need a new epoch with a new size matching the new largest numbered block.
5409-
// Also, if the number of blocks is different from the last time we set the
5410-
// BlockSet epoch, then we need a new epoch. This wouldn't happen if we
5411-
// renumbered blocks after every block addition/deletion, but it might be
5412-
// the case that we can change the number of blocks, then set the BlockSet
5413-
// epoch without renumbering, then change the number of blocks again, then
5414-
// renumber.
5415-
if (renumbered || newMaxBBNum)
5416-
{
5417-
NewBasicBlockEpoch();
5418-
5419-
// The key in the unique switch successor map is dependent on the block number, so invalidate that cache.
5420-
InvalidateUniqueSwitchSuccMap();
5421-
}
5422-
else
5423-
{
5424-
EnsureBasicBlockEpoch();
5425-
}
5426-
54275403
// Tell our caller if any blocks actually were renumbered.
54285404
return renumbered || newMaxBBNum;
54295405
}

src/coreclr/jit/fgflow.cpp

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -530,11 +530,7 @@ Compiler::SwitchUniqueSuccSet Compiler::GetDescriptorForSwitch(BasicBlock* switc
530530
{
531531
// We must compute the descriptor. Find which are dups, by creating a bit set with the unique successors.
532532
// We create a temporary bitset of blocks to compute the unique set of successor blocks,
533-
// since adding a block's number twice leaves just one "copy" in the bitset. Note that
534-
// we specifically don't use the BlockSet type, because doing so would require making a
535-
// call to EnsureBasicBlockEpoch() to make sure the epoch is up-to-date. However, that
536-
// can create a new epoch, thus invalidating all existing BlockSet objects, such as
537-
// reachability information stored in the blocks. To avoid that, we just use a local BitVec.
533+
// since adding a block's number twice leaves just one "copy" in the bitset.
538534

539535
BitVecTraits blockVecTraits(fgBBNumMax + 1, this);
540536
BitVec uniqueSuccBlocks(BitVecOps::MakeEmpty(&blockVecTraits));

src/coreclr/jit/fgopt.cpp

Lines changed: 19 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -4463,8 +4463,11 @@ bool Compiler::fgReorderBlocks(bool useProfile)
44634463
// Template parameters:
44644464
// hasEH - If true, method has EH regions, so check that we don't try to move blocks in different regions
44654465
//
4466+
// Parameters:
4467+
// dfsTree - The depth-first traversal of the flowgraph
4468+
//
44664469
template <bool hasEH>
4467-
void Compiler::fgMoveHotJumps()
4470+
void Compiler::fgMoveHotJumps(FlowGraphDfsTree* dfsTree)
44684471
{
44694472
#ifdef DEBUG
44704473
if (verbose)
@@ -4477,17 +4480,22 @@ void Compiler::fgMoveHotJumps()
44774480
}
44784481
#endif // DEBUG
44794482

4480-
EnsureBasicBlockEpoch();
4481-
BlockSet visitedBlocks(BlockSetOps::MakeEmpty(this));
4482-
BlockSetOps::AddElemD(this, visitedBlocks, fgFirstBB->bbNum);
4483+
assert(dfsTree != nullptr);
4484+
BitVecTraits traits(dfsTree->PostOrderTraits());
4485+
BitVec visitedBlocks = BitVecOps::MakeEmpty(&traits);
44834486

44844487
// If we have a funclet region, don't bother reordering anything in it.
44854488
//
44864489
BasicBlock* next;
44874490
for (BasicBlock* block = fgFirstBB; block != fgFirstFuncletBB; block = next)
44884491
{
44894492
next = block->Next();
4490-
BlockSetOps::AddElemD(this, visitedBlocks, block->bbNum);
4493+
if (!dfsTree->Contains(block))
4494+
{
4495+
continue;
4496+
}
4497+
4498+
BitVecOps::AddElemD(&traits, visitedBlocks, block->bbPostorderNum);
44914499

44924500
// Don't bother trying to move cold blocks
44934501
//
@@ -4534,7 +4542,8 @@ void Compiler::fgMoveHotJumps()
45344542
}
45354543

45364544
BasicBlock* target = targetEdge->getDestinationBlock();
4537-
bool isBackwardJump = BlockSetOps::IsMember(this, visitedBlocks, target->bbNum);
4545+
bool isBackwardJump = BitVecOps::IsMember(&traits, visitedBlocks, target->bbPostorderNum);
4546+
assert(dfsTree->Contains(target));
45384547

45394548
if (isBackwardJump)
45404549
{
@@ -4553,7 +4562,8 @@ void Compiler::fgMoveHotJumps()
45534562
//
45544563
targetEdge = unlikelyEdge;
45554564
target = targetEdge->getDestinationBlock();
4556-
isBackwardJump = BlockSetOps::IsMember(this, visitedBlocks, target->bbNum);
4565+
isBackwardJump = BitVecOps::IsMember(&traits, visitedBlocks, target->bbPostorderNum);
4566+
assert(dfsTree->Contains(target));
45574567

45584568
if (isBackwardJump)
45594569
{
@@ -4696,7 +4706,7 @@ void Compiler::fgDoReversePostOrderLayout()
46964706
}
46974707
}
46984708

4699-
fgMoveHotJumps</* hasEH */ false>();
4709+
fgMoveHotJumps</* hasEH */ false>(dfsTree);
47004710

47014711
return;
47024712
}
@@ -4769,7 +4779,7 @@ void Compiler::fgDoReversePostOrderLayout()
47694779
fgInsertBBafter(pair.callFinally, pair.callFinallyRet);
47704780
}
47714781

4772-
fgMoveHotJumps</* hasEH */ true>();
4782+
fgMoveHotJumps</* hasEH */ true>(dfsTree);
47734783
}
47744784

47754785
//-----------------------------------------------------------------------------

0 commit comments

Comments
 (0)