Skip to content

Commit

Permalink
JIT: Add an "init BB" invariant (dotnet#110404)
Browse files Browse the repository at this point in the history
This adds an invariant that there always exists an "init BB" throughout
the JIT's phases. The init BB has the following properties:
- It is only executed once, so it does not have any predecessors
- It is not inside a try region, hence it dominates all other blocks in
  the function

There are no further requirements on the BB. The init BB does not have
to be `BBJ_ALWAYS` (unlike the old "scratch BB" concept). This is mainly
because it philosophically does not make sense to insert IR at the end
of the init BB, since earlier phases can have inserted arbitrary IR in
them.
  • Loading branch information
jakobbotsch authored and hez2010 committed Dec 14, 2024
1 parent a4ca48f commit 34cf5bc
Show file tree
Hide file tree
Showing 16 changed files with 283 additions and 363 deletions.
18 changes: 7 additions & 11 deletions src/coreclr/jit/codegenlinear.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -156,10 +156,6 @@ void CodeGen::genCodeForBBlist()

genMarkLabelsForCodegen();

assert(!compiler->fgFirstBBScratch ||
compiler->fgFirstBB == compiler->fgFirstBBScratch); // compiler->fgFirstBBScratch
// has to be first.

/* Initialize structures used in the block list iteration */
genInitialize();

Expand Down Expand Up @@ -367,9 +363,9 @@ void CodeGen::genCodeForBBlist()
siBeginBlock(block);

// BBF_INTERNAL blocks don't correspond to any single IL instruction.
if (compiler->opts.compDbgInfo && block->HasFlag(BBF_INTERNAL) &&
!compiler->fgBBisScratch(block)) // If the block is the distinguished first scratch block, then no need to
// emit a NO_MAPPING entry, immediately after the prolog.
// Add a NoMapping entry unless this is right after the prolog where it
// is unnecessary.
if (compiler->opts.compDbgInfo && block->HasFlag(BBF_INTERNAL) && !block->IsFirst())
{
genIPmappingAdd(IPmappingDscKind::NoMapping, DebugInfo(), true);
}
Expand All @@ -388,17 +384,17 @@ void CodeGen::genCodeForBBlist()

#ifdef SWIFT_SUPPORT
// Reassemble Swift struct parameters on the local stack frame in the
// scratch BB right after the prolog. There can be arbitrary amounts of
// init BB right after the prolog. There can be arbitrary amounts of
// codegen related to doing this, so it cannot be done in the prolog.
if (compiler->fgBBisScratch(block) && compiler->lvaHasAnySwiftStackParamToReassemble())
if (block->IsFirst() && compiler->lvaHasAnySwiftStackParamToReassemble())
{
genHomeSwiftStructParameters(/* handleStack */ true);
}
#endif

// Emit poisoning into scratch BB that comes right after prolog.
// Emit poisoning into the init BB that comes right after prolog.
// We cannot emit this code in the prolog as it might make the prolog too large.
if (compiler->compShouldPoisonFrame() && compiler->fgBBisScratch(block))
if (compiler->compShouldPoisonFrame() && block->IsFirst())
{
genPoisonFrame(newLiveRegSet);
}
Expand Down
31 changes: 3 additions & 28 deletions src/coreclr/jit/compiler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3743,20 +3743,6 @@ void Compiler::compInitDebuggingInfo()
compInitScopeLists();
}

if (opts.compDbgCode && (info.compVarScopesCount > 0))
{
/* Create a new empty basic block. fgExtendDbgLifetimes() may add
initialization of variables which are in scope right from the
start of the (real) first BB (and therefore artificially marked
as alive) into this block.
*/

fgEnsureFirstBBisScratch();

fgNewStmtAtEnd(fgFirstBB, gtNewNothingNode());

JITDUMP("Debuggable code - Add new %s to perform initialization of variables\n", fgFirstBB->dspToString());
}
/*-------------------------------------------------------------------------
*
* Read the stmt-offsets table and the line-number table
Expand Down Expand Up @@ -4526,6 +4512,9 @@ void Compiler::compCompile(void** methodCodePtr, uint32_t* methodCodeSize, JitFl
activePhaseChecks |= PhaseChecks::CHECK_PROFILE;
DoPhase(this, PHASE_INCPROFILE, &Compiler::fgIncorporateProfileData);

activePhaseChecks |= PhaseChecks::CHECK_FG_INIT_BLOCK;
DoPhase(this, PHASE_CANONICALIZE_ENTRY, &Compiler::fgCanonicalizeFirstBB);

// If we are doing OSR, update flow to initially reach the appropriate IL offset.
//
if (opts.IsOSR())
Expand Down Expand Up @@ -4694,10 +4683,6 @@ void Compiler::compCompile(void** methodCodePtr, uint32_t* methodCodeSize, JitFl

if (opts.OptimizationEnabled())
{
// Canonicalize entry to have unique entry BB to put IR in for the upcoming phases
//
DoPhase(this, PHASE_CANONICALIZE_ENTRY, &Compiler::fgCanonicalizeFirstBB);

// Build post-order and remove dead blocks
//
DoPhase(this, PHASE_DFS_BLOCKS2, &Compiler::fgDfsBlocksAndRemove);
Expand Down Expand Up @@ -4792,10 +4777,6 @@ void Compiler::compCompile(void** methodCodePtr, uint32_t* methodCodeSize, JitFl
return fgHeadTailMerge(false);
});

// Canonicalize entry to give a unique dominator tree root
//
DoPhase(this, PHASE_CANONICALIZE_ENTRY, &Compiler::fgCanonicalizeFirstBB);

// Compute DFS tree and remove all unreachable blocks.
//
DoPhase(this, PHASE_DFS_BLOCKS3, &Compiler::fgDfsBlocksAndRemove);
Expand Down Expand Up @@ -5027,12 +5008,6 @@ void Compiler::compCompile(void** methodCodePtr, uint32_t* methodCodeSize, JitFl

assert(opts.optRepeat);

// We may have optimized away the canonical entry BB that SSA
// depends on above, so if we are going for another iteration then
// make sure we still have a canonical entry.
//
DoPhase(this, PHASE_CANONICALIZE_ENTRY, &Compiler::fgCanonicalizeFirstBB);

ResetOptAnnotations();
RecomputeFlowGraphAnnotations();

Expand Down
12 changes: 6 additions & 6 deletions src/coreclr/jit/compiler.h
Original file line number Diff line number Diff line change
Expand Up @@ -1542,6 +1542,7 @@ enum class PhaseChecks : unsigned int
CHECK_LIKELIHOODS = 1 << 5, // profile data likelihood integrity
CHECK_PROFILE = 1 << 6, // profile data full integrity
CHECK_LINKED_LOCALS = 1 << 7, // check linked list of locals
CHECK_FG_INIT_BLOCK = 1 << 8, // flow graph has an init block
};

inline constexpr PhaseChecks operator ~(PhaseChecks a)
Expand Down Expand Up @@ -5197,8 +5198,6 @@ class Compiler
BasicBlock* fgEntryBB = nullptr; // For OSR, the original method's entry point
BasicBlock* fgOSREntryBB = nullptr; // For OSR, the logical entry point (~ patchpoint)
BasicBlock* fgFirstFuncletBB = nullptr; // First block of outlined funclets (to allow block insertion before the funclets)
BasicBlock* fgFirstBBScratch = nullptr; // Block inserted for initialization stuff. Is nullptr if no such block has been
// created.
BasicBlockList* fgReturnBlocks = nullptr; // list of BBJ_RETURN blocks
unsigned fgEdgeCount = 0; // # of control flow edges between the BBs
unsigned fgBBcount = 0; // # of BBs in the method (in the linked list that starts with fgFirstBB)
Expand Down Expand Up @@ -5246,10 +5245,6 @@ class Compiler
return getAllocator(cmk).allocate<T>(fgBBNumMax + 1);
}

bool fgEnsureFirstBBisScratch();
bool fgFirstBBisScratch();
bool fgBBisScratch(BasicBlock* block);

void fgExtendEHRegionBefore(BasicBlock* block);
void fgExtendEHRegionAfter(BasicBlock* block);

Expand Down Expand Up @@ -5439,6 +5434,7 @@ class Compiler
};

PhaseStatus fgMorphBlocks();
BasicBlock* fgGetFirstILBlock();
void fgMorphBlock(BasicBlock* block, MorphUnreachableInfo* unreachableInfo = nullptr);
void fgMorphStmts(BasicBlock* block);

Expand Down Expand Up @@ -6158,6 +6154,7 @@ class Compiler
bool fgCheckRemoveStmt(BasicBlock* block, Statement* stmt);

PhaseStatus fgCanonicalizeFirstBB();
void fgCreateNewInitBB();

void fgSetEHRegionForNewPreheaderOrExit(BasicBlock* preheader);

Expand All @@ -6179,6 +6176,8 @@ class Compiler

bool fgCanCompactBlock(BasicBlock* block);

bool fgCanCompactInitBlock();

void fgCompactBlock(BasicBlock* block);

BasicBlock* fgConnectFallThrough(BasicBlock* bSrc, BasicBlock* bDst);
Expand Down Expand Up @@ -6355,6 +6354,7 @@ class Compiler
void fgDebugCheckBBNumIncreasing();
void fgDebugCheckBBlist(bool checkBBNum = false, bool checkBBRefs = true);
void fgDebugCheckBlockLinks();
void fgDebugCheckInitBB();
void fgDebugCheckLinks(bool morphTrees = false);
void fgDebugCheckStmtsList(BasicBlock* block, bool morphTrees);
void fgDebugCheckNodeLinks(BasicBlock* block, Statement* stmt);
Expand Down
Loading

0 comments on commit 34cf5bc

Please sign in to comment.