Skip to content

Commit b0d68f7

Browse files
JIT: Use flowgraph annotations to scale loop blocks in optSetBlockWeights (#116120)
Part of #107749. This replaces optMarkLoopHeads and optFindAndScaleLoopBlocks with the graph-based loop visitor pattern we now use elsewhere in the JIT. I tried to preserve the heuristics in optScaleLoopBlocks, but a side effect of this change is we no longer scale unnatural loops. However, we no longer rely on lexical loop finding, so we gain some precision as well. Once this and graph-based loop inversion have been merged, we will no longer have any fgRenumberBlocks calls.
1 parent 60e9340 commit b0d68f7

File tree

7 files changed

+76
-316
lines changed

7 files changed

+76
-316
lines changed

src/coreclr/jit/block.cpp

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -497,7 +497,6 @@ void BasicBlock::dspFlags() const
497497
{BBF_DONT_REMOVE, "keep"},
498498
{BBF_INTERNAL, "internal"},
499499
{BBF_HAS_SUPPRESSGC_CALL, "sup-gc"},
500-
{BBF_LOOP_HEAD, "loophead"},
501500
{BBF_HAS_LABEL, "label"},
502501
{BBF_HAS_JMP, "jmp"},
503502
{BBF_HAS_CALL, "hascall"},

src/coreclr/jit/block.h

Lines changed: 32 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -431,50 +431,49 @@ enum BasicBlockFlags : uint64_t
431431
BBF_HAS_NULLCHECK = MAKE_BBFLAG( 9), // BB contains a null check
432432
BBF_HAS_SUPPRESSGC_CALL = MAKE_BBFLAG(10), // BB contains a call to a method with SuppressGCTransitionAttribute
433433
BBF_RUN_RARELY = MAKE_BBFLAG(11), // BB is rarely run (catch clauses, blocks with throws etc)
434-
BBF_LOOP_HEAD = MAKE_BBFLAG(12), // BB is the head of a loop (can reach a predecessor)
435-
BBF_HAS_LABEL = MAKE_BBFLAG(13), // BB needs a label
436-
BBF_LOOP_ALIGN = MAKE_BBFLAG(14), // Block is lexically the first block in a loop we intend to align.
437-
BBF_HAS_ALIGN = MAKE_BBFLAG(15), // BB ends with 'align' instruction
438-
BBF_HAS_JMP = MAKE_BBFLAG(16), // BB executes a JMP instruction (instead of return)
439-
BBF_GC_SAFE_POINT = MAKE_BBFLAG(17), // BB has a GC safe point (e.g. a call)
440-
BBF_HAS_IDX_LEN = MAKE_BBFLAG(18), // BB contains simple index or length expressions on an SD array local var.
441-
BBF_HAS_MD_IDX_LEN = MAKE_BBFLAG(19), // BB contains simple index, length, or lower bound expressions on an MD array local var.
442-
BBF_HAS_MDARRAYREF = MAKE_BBFLAG(20), // Block has a multi-dimensional array reference
443-
BBF_HAS_NEWOBJ = MAKE_BBFLAG(21), // BB contains 'new' of an object type.
444-
445-
BBF_RETLESS_CALL = MAKE_BBFLAG(22), // BBJ_CALLFINALLY that will never return (and therefore, won't need a paired
434+
BBF_HAS_LABEL = MAKE_BBFLAG(12), // BB needs a label
435+
BBF_LOOP_ALIGN = MAKE_BBFLAG(13), // Block is lexically the first block in a loop we intend to align.
436+
BBF_HAS_ALIGN = MAKE_BBFLAG(14), // BB ends with 'align' instruction
437+
BBF_HAS_JMP = MAKE_BBFLAG(15), // BB executes a JMP instruction (instead of return)
438+
BBF_GC_SAFE_POINT = MAKE_BBFLAG(16), // BB has a GC safe point (e.g. a call)
439+
BBF_HAS_IDX_LEN = MAKE_BBFLAG(17), // BB contains simple index or length expressions on an SD array local var.
440+
BBF_HAS_MD_IDX_LEN = MAKE_BBFLAG(18), // BB contains simple index, length, or lower bound expressions on an MD array local var.
441+
BBF_HAS_MDARRAYREF = MAKE_BBFLAG(19), // Block has a multi-dimensional array reference
442+
BBF_HAS_NEWOBJ = MAKE_BBFLAG(20), // BB contains 'new' of an object type.
443+
444+
BBF_RETLESS_CALL = MAKE_BBFLAG(21), // BBJ_CALLFINALLY that will never return (and therefore, won't need a paired
446445
// BBJ_CALLFINALLYRET); see isBBCallFinallyPair().
447-
BBF_COLD = MAKE_BBFLAG(23), // BB is cold
448-
BBF_PROF_WEIGHT = MAKE_BBFLAG(24), // BB weight is computed from profile data
449-
BBF_KEEP_BBJ_ALWAYS = MAKE_BBFLAG(25), // A special BBJ_ALWAYS block, used by EH code generation. Keep the jump kind
446+
BBF_COLD = MAKE_BBFLAG(22), // BB is cold
447+
BBF_PROF_WEIGHT = MAKE_BBFLAG(23), // BB weight is computed from profile data
448+
BBF_KEEP_BBJ_ALWAYS = MAKE_BBFLAG(24), // A special BBJ_ALWAYS block, used by EH code generation. Keep the jump kind
450449
// as BBJ_ALWAYS. Used on x86 for the final step block out of a finally.
451-
BBF_HAS_CALL = MAKE_BBFLAG(26), // BB contains a call
452-
BBF_DOMINATED_BY_EXCEPTIONAL_ENTRY = MAKE_BBFLAG(27), // Block is dominated by exceptional entry.
453-
BBF_BACKWARD_JUMP = MAKE_BBFLAG(28), // BB is surrounded by a backward jump/switch arc
454-
BBF_BACKWARD_JUMP_SOURCE = MAKE_BBFLAG(29), // Block is a source of a backward jump
455-
BBF_BACKWARD_JUMP_TARGET = MAKE_BBFLAG(30), // Block is a target of a backward jump
456-
BBF_PATCHPOINT = MAKE_BBFLAG(31), // Block is a patchpoint
457-
BBF_PARTIAL_COMPILATION_PATCHPOINT = MAKE_BBFLAG(32), // Block is a partial compilation patchpoint
458-
BBF_HAS_HISTOGRAM_PROFILE = MAKE_BBFLAG(33), // BB contains a call needing a histogram profile
459-
BBF_TAILCALL_SUCCESSOR = MAKE_BBFLAG(34), // BB has pred that has potential tail call
460-
BBF_RECURSIVE_TAILCALL = MAKE_BBFLAG(35), // Block has recursive tailcall that may turn into a loop
461-
BBF_NO_CSE_IN = MAKE_BBFLAG(36), // Block should kill off any incoming CSE
462-
BBF_CAN_ADD_PRED = MAKE_BBFLAG(37), // Ok to add pred edge to this block, even when "safe" edge creation disabled
463-
BBF_HAS_VALUE_PROFILE = MAKE_BBFLAG(38), // Block has a node that needs a value probing
464-
BBF_HAS_NEWARR = MAKE_BBFLAG(39), // BB contains 'new' of an array type.
465-
BBF_MAY_HAVE_BOUNDS_CHECKS = MAKE_BBFLAG(40), // BB *likely* has a bounds check (after rangecheck phase).
466-
BBF_ASYNC_RESUMPTION = MAKE_BBFLAG(41), // Block is a resumption block in an async method
450+
BBF_HAS_CALL = MAKE_BBFLAG(25), // BB contains a call
451+
BBF_DOMINATED_BY_EXCEPTIONAL_ENTRY = MAKE_BBFLAG(26), // Block is dominated by exceptional entry.
452+
BBF_BACKWARD_JUMP = MAKE_BBFLAG(27), // BB is surrounded by a backward jump/switch arc
453+
BBF_BACKWARD_JUMP_SOURCE = MAKE_BBFLAG(28), // Block is a source of a backward jump
454+
BBF_BACKWARD_JUMP_TARGET = MAKE_BBFLAG(29), // Block is a target of a backward jump
455+
BBF_PATCHPOINT = MAKE_BBFLAG(30), // Block is a patchpoint
456+
BBF_PARTIAL_COMPILATION_PATCHPOINT = MAKE_BBFLAG(31), // Block is a partial compilation patchpoint
457+
BBF_HAS_HISTOGRAM_PROFILE = MAKE_BBFLAG(32), // BB contains a call needing a histogram profile
458+
BBF_TAILCALL_SUCCESSOR = MAKE_BBFLAG(33), // BB has pred that has potential tail call
459+
BBF_RECURSIVE_TAILCALL = MAKE_BBFLAG(34), // Block has recursive tailcall that may turn into a loop
460+
BBF_NO_CSE_IN = MAKE_BBFLAG(35), // Block should kill off any incoming CSE
461+
BBF_CAN_ADD_PRED = MAKE_BBFLAG(36), // Ok to add pred edge to this block, even when "safe" edge creation disabled
462+
BBF_HAS_VALUE_PROFILE = MAKE_BBFLAG(37), // Block has a node that needs a value probing
463+
BBF_HAS_NEWARR = MAKE_BBFLAG(38), // BB contains 'new' of an array type.
464+
BBF_MAY_HAVE_BOUNDS_CHECKS = MAKE_BBFLAG(39), // BB *likely* has a bounds check (after rangecheck phase).
465+
BBF_ASYNC_RESUMPTION = MAKE_BBFLAG(40), // Block is a resumption block in an async method
467466

468467
// The following are sets of flags.
469468

470469
// Flags to update when two blocks are compacted
471470

472471
BBF_COMPACT_UPD = BBF_GC_SAFE_POINT | BBF_NEEDS_GCPOLL | BBF_HAS_JMP | BBF_HAS_IDX_LEN | BBF_HAS_MD_IDX_LEN | BBF_BACKWARD_JUMP | \
473-
BBF_HAS_NEWOBJ | BBF_HAS_NEWARR | BBF_HAS_NULLCHECK | BBF_HAS_MDARRAYREF | BBF_LOOP_HEAD | BBF_MAY_HAVE_BOUNDS_CHECKS,
472+
BBF_HAS_NEWOBJ | BBF_HAS_NEWARR | BBF_HAS_NULLCHECK | BBF_HAS_MDARRAYREF | BBF_MAY_HAVE_BOUNDS_CHECKS,
474473

475474
// Flags a block should not have had before it is split.
476475

477-
BBF_SPLIT_NONEXIST = BBF_LOOP_HEAD | BBF_RETLESS_CALL | BBF_COLD,
476+
BBF_SPLIT_NONEXIST = BBF_RETLESS_CALL | BBF_COLD,
478477

479478
// Flags lost by the top block when a block is split.
480479
// Note, this is a conservative guess.
@@ -1150,10 +1149,6 @@ struct BasicBlock : private LIR::Range
11501149
{
11511150
return HasFlag(BBF_RUN_RARELY);
11521151
}
1153-
bool isLoopHead() const
1154-
{
1155-
return HasFlag(BBF_LOOP_HEAD);
1156-
}
11571152

11581153
bool isLoopAlign() const
11591154
{

src/coreclr/jit/compiler.h

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7085,12 +7085,8 @@ class Compiler
70857085
#endif
70867086

70877087
void optResetLoopInfo();
7088-
void optFindAndScaleGeneralLoopBlocks();
70897088

7090-
// Determine if there are any potential loops, and set BBF_LOOP_HEAD on potential loop heads.
7091-
void optMarkLoopHeads();
7092-
7093-
void optScaleLoopBlocks(BasicBlock* begBlk, BasicBlock* endBlk);
7089+
void optScaleLoopBlocks(FlowGraphNaturalLoop* loop);
70947090

70957091
bool optIsLoopTestEvalIntoTemp(Statement* testStmt, Statement** newTestStmt);
70967092
unsigned optIsLoopIncrTree(GenTree* incr);

src/coreclr/jit/fgbasic.cpp

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4704,8 +4704,7 @@ BasicBlock* Compiler::fgSplitBlockAtEnd(BasicBlock* curr)
47044704
newBlock->CopyFlags(curr);
47054705

47064706
// Remove flags that the new block can't have.
4707-
newBlock->RemoveFlags(BBF_LOOP_HEAD | BBF_KEEP_BBJ_ALWAYS | BBF_PATCHPOINT | BBF_BACKWARD_JUMP_TARGET |
4708-
BBF_LOOP_ALIGN);
4707+
newBlock->RemoveFlags(BBF_KEEP_BBJ_ALWAYS | BBF_PATCHPOINT | BBF_BACKWARD_JUMP_TARGET | BBF_LOOP_ALIGN);
47094708

47104709
// Remove the GC safe bit on the new block. It seems clear that if we split 'curr' at the end,
47114710
// such that all the code is left in 'curr', and 'newBlock' just gets the control flow, then

src/coreclr/jit/fgdiagnostic.cpp

Lines changed: 1 addition & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -820,8 +820,7 @@ bool Compiler::fgDumpFlowGraph(Phases phase, PhasePosition pos)
820820
const bool isTryEntryBlock = bbIsTryBeg(block);
821821
const bool isFuncletEntryBlock = fgFuncletsCreated && bbIsFuncletBeg(block);
822822

823-
if (isTryEntryBlock || isFuncletEntryBlock ||
824-
block->HasAnyFlag(BBF_RUN_RARELY | BBF_LOOP_HEAD | BBF_LOOP_ALIGN))
823+
if (isTryEntryBlock || isFuncletEntryBlock || block->HasAnyFlag(BBF_RUN_RARELY | BBF_LOOP_ALIGN))
825824
{
826825
// Display a very few, useful, block flags
827826
fprintf(fgxFile, " [");
@@ -837,10 +836,6 @@ bool Compiler::fgDumpFlowGraph(Phases phase, PhasePosition pos)
837836
{
838837
fprintf(fgxFile, "R");
839838
}
840-
if (block->HasFlag(BBF_LOOP_HEAD))
841-
{
842-
fprintf(fgxFile, "L");
843-
}
844839
if (block->HasFlag(BBF_LOOP_ALIGN))
845840
{
846841
fprintf(fgxFile, "A");
@@ -968,10 +963,6 @@ bool Compiler::fgDumpFlowGraph(Phases phase, PhasePosition pos)
968963
{
969964
fprintf(fgxFile, "\n callsNewArr=\"true\"");
970965
}
971-
if (block->HasFlag(BBF_LOOP_HEAD))
972-
{
973-
fprintf(fgxFile, "\n loopHead=\"true\"");
974-
}
975966

976967
const char* rootTreeOpName = "n/a";
977968
if (block->IsLIR() || (block->lastStmt() != nullptr))

src/coreclr/jit/flowgraph.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -277,7 +277,7 @@ BasicBlock* Compiler::fgCreateGCPoll(GCPollType pollType, BasicBlock* block)
277277

278278
// We need to keep a few flags...
279279
//
280-
noway_assert((originalFlags & (BBF_SPLIT_NONEXIST & ~(BBF_LOOP_HEAD | BBF_RETLESS_CALL))) == 0);
280+
noway_assert((originalFlags & (BBF_SPLIT_NONEXIST & ~BBF_RETLESS_CALL)) == 0);
281281
top->SetFlagsRaw(originalFlags & (~(BBF_SPLIT_LOST | BBF_RETLESS_CALL) | BBF_GC_SAFE_POINT));
282282
bottom->SetFlags(originalFlags & (BBF_SPLIT_GAINED | BBF_IMPORTED | BBF_GC_SAFE_POINT | BBF_RETLESS_CALL));
283283
bottom->inheritWeight(top);

0 commit comments

Comments
 (0)