Skip to content

Commit 75408bb

Browse files
authored
JIT: build pred lists first (#81448)
Move pred list building before importation. It now runs as the first phase in the phase list. * Split up some unions in block.h as some things can't share storage anymore (may revisit this later). * Modify importer not to rely on cheap preds. Most of the work here is in `impImportLeave`. * Adjust OSR protection strategy for the method entry. In particular, watch for the degenerate case where the OSR entry is the method entry. * Ensure we don't double-decrement some ref counts when blocks with degenerate or folded flow are re-imported. * Update spill clique discovery to use the actual pred lists. * Add new method `impFixPredLists` for the importer to use at the end of importation. This adds pred list entries finally returns, which can't be done until all `BBJ_LEAVE` blocks are processed. * trigger badcode inside `fgComputePreds` * fix issue with `STRESS_CATCH_ARG` Contributes to #80193.
1 parent ac18cc9 commit 75408bb

File tree

11 files changed

+313
-188
lines changed

11 files changed

+313
-188
lines changed

src/coreclr/jit/block.h

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -902,10 +902,7 @@ struct BasicBlock : private LIR::Range
902902
m_firstNode = tree;
903903
}
904904

905-
union {
906-
EntryState* bbEntryState; // verifier tracked state of all entries in stack.
907-
flowList* bbLastPred; // last pred list entry
908-
};
905+
EntryState* bbEntryState; // verifier tracked state of all entries in stack.
909906

910907
#define NO_BASE_TMP UINT_MAX // base# to use when we have none
911908

@@ -1091,10 +1088,14 @@ struct BasicBlock : private LIR::Range
10911088
BlockSet bbReach; // Set of all blocks that can reach this one
10921089

10931090
union {
1094-
BasicBlock* bbIDom; // Represent the closest dominator to this block (called the Immediate
1095-
// Dominator) used to compute the dominance tree.
1096-
void* bbSparseProbeList; // Used early on by fgInstrument
1091+
BasicBlock* bbIDom; // Represent the closest dominator to this block (called the Immediate
1092+
// Dominator) used to compute the dominance tree.
1093+
flowList* bbLastPred; // Used early on by fgComputePreds
1094+
};
1095+
1096+
union {
10971097
void* bbSparseCountInfo; // Used early on by fgIncorporateEdgeCounts
1098+
void* bbSparseProbeList; // Used early on by fgInstrument
10981099
};
10991100

11001101
unsigned bbPostOrderNum; // the block's post order number in the graph.

src/coreclr/jit/compiler.cpp

Lines changed: 13 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -4347,6 +4347,17 @@ void Compiler::EndPhase(Phases phase)
43474347
//
43484348
void Compiler::compCompile(void** methodCodePtr, uint32_t* methodCodeSize, JitFlags* compileFlags)
43494349
{
4350+
compFunctionTraceStart();
4351+
4352+
// Compute bbRefs and bbPreds
4353+
//
4354+
auto computePredsPhase = [this]() {
4355+
fgComputePreds();
4356+
// Enable flow graph checks
4357+
activePhaseChecks |= PhaseChecks::CHECK_FG;
4358+
};
4359+
DoPhase(this, PHASE_COMPUTE_PREDS, computePredsPhase);
4360+
43504361
// Prepare for importation
43514362
//
43524363
auto preImportPhase = [this]() {
@@ -4375,8 +4386,6 @@ void Compiler::compCompile(void** methodCodePtr, uint32_t* methodCodeSize, JitFl
43754386
};
43764387
DoPhase(this, PHASE_PRE_IMPORT, preImportPhase);
43774388

4378-
compFunctionTraceStart();
4379-
43804389
// Incorporate profile data.
43814390
//
43824391
// Note: the importer is sensitive to block weights, so this has
@@ -4401,8 +4410,8 @@ void Compiler::compCompile(void** methodCodePtr, uint32_t* methodCodeSize, JitFl
44014410

44024411
// Enable the post-phase checks that use internal logic to decide when checking makes sense.
44034412
//
4404-
activePhaseChecks = PhaseChecks::CHECK_EH | PhaseChecks::CHECK_LOOPS | PhaseChecks::CHECK_UNIQUE |
4405-
PhaseChecks::CHECK_PROFILE | PhaseChecks::CHECK_LINKED_LOCALS;
4413+
activePhaseChecks |= PhaseChecks::CHECK_EH | PhaseChecks::CHECK_LOOPS | PhaseChecks::CHECK_UNIQUE |
4414+
PhaseChecks::CHECK_PROFILE | PhaseChecks::CHECK_LINKED_LOCALS;
44064415

44074416
// Import: convert the instrs in each basic block to a tree based intermediate representation
44084417
//
@@ -4425,23 +4434,6 @@ void Compiler::compCompile(void** methodCodePtr, uint32_t* methodCodeSize, JitFl
44254434
return;
44264435
}
44274436

4428-
// Compute bbNum, bbRefs and bbPreds
4429-
//
4430-
// This is the first time full (not cheap) preds will be computed.
4431-
// And, if we have profile data, we can now check integrity.
4432-
//
4433-
// From this point on the flowgraph information such as bbNum,
4434-
// bbRefs or bbPreds has to be kept updated.
4435-
//
4436-
auto computePredsPhase = [this]() {
4437-
JITDUMP("\nRenumbering the basic blocks for fgComputePred\n");
4438-
fgRenumberBlocks();
4439-
fgComputePreds();
4440-
// Enable flow graph checks
4441-
activePhaseChecks |= PhaseChecks::CHECK_FG;
4442-
};
4443-
DoPhase(this, PHASE_COMPUTE_PREDS, computePredsPhase);
4444-
44454437
// If instrumenting, add block and class probes.
44464438
//
44474439
if (compileFlags->IsSet(JitFlags::JIT_FLAG_BBINSTR))

src/coreclr/jit/compiler.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3687,6 +3687,7 @@ class Compiler
36873687
public:
36883688
void impInit();
36893689
void impImport();
3690+
void impFixPredLists();
36903691

36913692
CORINFO_CLASS_HANDLE impGetRefAnyClass();
36923693
CORINFO_CLASS_HANDLE impGetRuntimeArgumentHandle();
@@ -4397,6 +4398,7 @@ class Compiler
43974398
DomTreeNode* fgSsaDomTree;
43984399

43994400
bool fgBBVarSetsInited;
4401+
bool fgOSROriginalEntryBBProtected;
44004402

44014403
// Allocate array like T* a = new T[fgBBNumMax + 1];
44024404
// Using helper so we don't keep forgetting +1.

src/coreclr/jit/fgbasic.cpp

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -46,11 +46,12 @@ void Compiler::fgInit()
4646

4747
/* Initialize the basic block list */
4848

49-
fgFirstBB = nullptr;
50-
fgLastBB = nullptr;
51-
fgFirstColdBlock = nullptr;
52-
fgEntryBB = nullptr;
53-
fgOSREntryBB = nullptr;
49+
fgFirstBB = nullptr;
50+
fgLastBB = nullptr;
51+
fgFirstColdBlock = nullptr;
52+
fgEntryBB = nullptr;
53+
fgOSREntryBB = nullptr;
54+
fgOSROriginalEntryBBProtected = false;
5455

5556
#if defined(FEATURE_EH_FUNCLETS)
5657
fgFirstFuncletBB = nullptr;
@@ -3922,6 +3923,10 @@ void Compiler::fgCheckForLoopsInHandlers()
39223923
// the middle of the try. But we defer that until after importation.
39233924
// See fgPostImportationCleanup.
39243925
//
3926+
// Also protect the original method entry, if it was imported, since
3927+
// we may decide to branch there during morph as part of the tail recursion
3928+
// to loop optimization.
3929+
//
39253930
void Compiler::fgFixEntryFlowForOSR()
39263931
{
39273932
// Ensure lookup IL->BB lookup table is valid
@@ -3944,6 +3949,8 @@ void Compiler::fgFixEntryFlowForOSR()
39443949
// Now branch from method start to the right spot.
39453950
//
39463951
fgEnsureFirstBBisScratch();
3952+
assert(fgFirstBB->bbJumpKind == BBJ_NONE);
3953+
fgRemoveRefPred(fgFirstBB->bbNext, fgFirstBB);
39473954
fgFirstBB->bbJumpKind = BBJ_ALWAYS;
39483955
fgFirstBB->bbJumpDest = osrEntry;
39493956
fgAddRefPred(osrEntry, fgFirstBB);

src/coreclr/jit/fgdiagnostic.cpp

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -785,7 +785,7 @@ bool Compiler::fgDumpFlowGraph(Phases phase, PhasePosition pos)
785785
return false;
786786
}
787787

788-
JITDUMP("Dumping flow graph %s phase %s\n", (pos == PhasePosition::PrePhase) ? "before" : "after",
788+
JITDUMP("Writing out flow graph %s phase %s\n", (pos == PhasePosition::PrePhase) ? "before" : "after",
789789
PhaseNames[phase]);
790790

791791
bool validWeights = fgHaveValidEdgeWeights;
@@ -2664,8 +2664,8 @@ bool BBPredsChecker::CheckJump(BasicBlock* blockPred, BasicBlock* block)
26642664
break;
26652665

26662666
case BBJ_LEAVE:
2667-
// We may see BBJ_LEAVE preds in unimported blocks if we haven't done cleanup yet.
2668-
if (!comp->compPostImportationCleanupDone && ((blockPred->bbFlags & BBF_IMPORTED) == 0))
2667+
// We may see BBJ_LEAVE preds if we haven't done cleanup yet.
2668+
if (!comp->compPostImportationCleanupDone)
26692669
{
26702670
return true;
26712671
}
@@ -2907,7 +2907,7 @@ void Compiler::fgDebugCheckBBlist(bool checkBBNum /* = false */, bool checkBBRef
29072907

29082908
// Under OSR, if we also are keeping the original method entry around,
29092909
// mark that as implicitly referenced as well.
2910-
if (opts.IsOSR() && (block == fgEntryBB) && ((block->bbFlags & BBF_IMPORTED) != 0))
2910+
if (opts.IsOSR() && (block == fgEntryBB) && fgOSROriginalEntryBBProtected)
29112911
{
29122912
blockRefs += 1;
29132913
}

src/coreclr/jit/fgflow.cpp

Lines changed: 2 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -693,14 +693,6 @@ void Compiler::fgComputePreds()
693693
// the first block is always reachable
694694
fgFirstBB->bbRefs = 1;
695695

696-
// Under OSR, we may need to specially protect the original method entry.
697-
//
698-
if (opts.IsOSR() && (fgEntryBB != nullptr) && (fgEntryBB->bbFlags & BBF_IMPORTED))
699-
{
700-
JITDUMP("OSR: protecting original method entry " FMT_BB "\n", fgEntryBB->bbNum);
701-
fgEntryBB->bbRefs = 1;
702-
}
703-
704696
for (BasicBlock* const block : Blocks())
705697
{
706698
switch (block->bbJumpKind)
@@ -760,15 +752,15 @@ void Compiler::fgComputePreds()
760752

761753
if (!block->hasHndIndex())
762754
{
763-
NO_WAY("endfinally outside a finally/fault block.");
755+
BADCODE("endfinally outside a finally/fault block.");
764756
}
765757

766758
unsigned hndIndex = block->getHndIndex();
767759
EHblkDsc* ehDsc = ehGetDsc(hndIndex);
768760

769761
if (!ehDsc->HasFinallyOrFaultHandler())
770762
{
771-
NO_WAY("endfinally outside a finally/fault block.");
763+
BADCODE("endfinally outside a finally/fault block.");
772764
}
773765

774766
if (ehDsc->HasFinallyHandler())

src/coreclr/jit/flowgraph.cpp

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -616,14 +616,6 @@ PhaseStatus Compiler::fgImport()
616616
compInlineResult->SetImportedILSize(info.compILImportSize);
617617
}
618618

619-
// Full preds are only used later on
620-
assert(!fgComputePredsDone);
621-
if (fgCheapPredsValid)
622-
{
623-
// Cheap predecessors are only used during importation
624-
fgRemovePreds();
625-
}
626-
627619
return PhaseStatus::MODIFIED_EVERYTHING;
628620
}
629621

0 commit comments

Comments
 (0)