Skip to content

Commit

Permalink
JIT: morph blocks in RPO (#94247)
Browse files Browse the repository at this point in the history
When optimizing, process blocks in RPO. Disallow creation of new blocks
and new flow edges (the latter with certain preapproved exceptions).

Morph does not yet take advantage of the RPO to enable more optimization.

Contributes to #93246.
  • Loading branch information
AndyAyersMS committed Nov 2, 2023
1 parent 0052480 commit 655b177
Show file tree
Hide file tree
Showing 6 changed files with 75 additions and 11 deletions.
1 change: 1 addition & 0 deletions src/coreclr/jit/block.h
Expand Up @@ -440,6 +440,7 @@ enum BasicBlockFlags : unsigned __int64
BBF_TAILCALL_SUCCESSOR = MAKE_BBFLAG(40), // BB has pred that has potential tail call
BBF_RECURSIVE_TAILCALL = MAKE_BBFLAG(41), // Block has recursive tailcall that may turn into a loop
BBF_NO_CSE_IN = MAKE_BBFLAG(42), // Block should kill off any incoming CSE
BBF_CAN_ADD_PRED = MAKE_BBFLAG(43), // Ok to add pred edge to this block, even when "safe" edge creation disabled

// The following are sets of flags.

Expand Down
7 changes: 4 additions & 3 deletions src/coreclr/jit/compiler.h
Expand Up @@ -3215,10 +3215,11 @@ class Compiler
//=========================================================================
// BasicBlock functions
#ifdef DEBUG
// This is a debug flag we will use to assert when creating block during codegen
// as this interferes with procedure splitting. If you know what you're doing, set
// it to true before creating the block. (DEBUG only)
// When false, assert when creating a new basic block.
bool fgSafeBasicBlockCreation;

// When false, assert when creating a new flow edge
bool fgSafeFlowEdgeCreation;
#endif

/*
Expand Down
1 change: 1 addition & 0 deletions src/coreclr/jit/fgbasic.cpp
Expand Up @@ -84,6 +84,7 @@ void Compiler::fgInit()

#ifdef DEBUG
fgSafeBasicBlockCreation = true;
fgSafeFlowEdgeCreation = true;
#endif // DEBUG

fgLocalVarLivenessDone = false;
Expand Down
5 changes: 5 additions & 0 deletions src/coreclr/jit/fgflow.cpp
Expand Up @@ -162,6 +162,11 @@ FlowEdge* Compiler::fgAddRefPred(BasicBlock* block, BasicBlock* blockPred, FlowE
}
else
{
// Create a new edge
//
// We may be disallowing edge creation, except for edges targeting special blocks.
//
assert(fgSafeFlowEdgeCreation || ((block->bbFlags & BBF_CAN_ADD_PRED) != 0));

#if MEASURE_BLOCK_SIZE
genFlowNodeCnt += 1;
Expand Down
2 changes: 1 addition & 1 deletion src/coreclr/jit/flowgraph.cpp
Expand Up @@ -2228,7 +2228,7 @@ class MergedReturns
// Add 'return' expression to the return block
comp->fgNewStmtAtEnd(newReturnBB, returnExpr);
// Flag that this 'return' was generated by return merging so that subsequent
// return block morhping will know to leave it alone.
// return block merging will know to leave it alone.
returnExpr->gtFlags |= GTF_RET_MERGED;

#ifdef DEBUG
Expand Down
70 changes: 63 additions & 7 deletions src/coreclr/jit/morph.cpp
Expand Up @@ -7472,7 +7472,6 @@ void Compiler::fgMorphRecursiveFastTailCallIntoLoop(BasicBlock* block, GenTreeCa
//------------------------------------------------------------------------------
// fgAssignRecursiveCallArgToCallerParam : Assign argument to a recursive call to the corresponding caller parameter.
//
//
// Arguments:
// arg - argument to assign
// late - whether to use early or late arg
Expand Down Expand Up @@ -13892,13 +13891,70 @@ PhaseStatus Compiler::fgMorphBlocks()

// Morph all blocks.
//
// Note morph can add blocks downstream from the current block,
// and alter (but not null out) the current block's bbNext;
// this iterator ensures they all get visited.
//
for (BasicBlock* block : Blocks())
if (!optLocalAssertionProp)
{
fgMorphBlock(block);
// If we aren't optimizing, we just morph in normal bbNext order.
//
// Note morph can add blocks downstream from the current block,
// and alter (but not null out) the current block's bbNext;
// this iterator ensures they all get visited.
//
for (BasicBlock* block : Blocks())
{
fgMorphBlock(block);
}
}
else
{
// We are optimizing. Process in RPO.
//
fgRenumberBlocks();
EnsureBasicBlockEpoch();
fgComputeEnterBlocksSet();
fgDfsReversePostorder();

// Disallow general creation of new blocks or edges as it
// would invalidate RPO.
//
// Removal of edges, or altering dup counts, is OK.
//
INDEBUG(fgSafeBasicBlockCreation = false;);
INDEBUG(fgSafeFlowEdgeCreation = false;);

// Allow edge creation to genReturnBB (target of return merging)
// and the scratch block successor (target for tail call to loop).
// This will also disallow dataflow into these blocks.
//
if (genReturnBB != nullptr)
{
genReturnBB->bbFlags |= BBF_CAN_ADD_PRED;
}
if (fgFirstBBisScratch())
{
fgFirstBB->Next()->bbFlags |= BBF_CAN_ADD_PRED;
}

unsigned const bbNumMax = fgBBNumMax;
for (unsigned i = 1; i <= bbNumMax; i++)
{
BasicBlock* const block = fgBBReversePostorder[i];
fgMorphBlock(block);
}

// Re-enable block and edge creation, and revoke
// special treatment of genReturnBB and the "first" bb
//
INDEBUG(fgSafeBasicBlockCreation = true;);
INDEBUG(fgSafeFlowEdgeCreation = true;);

if (genReturnBB != nullptr)
{
genReturnBB->bbFlags &= ~BBF_CAN_ADD_PRED;
}
if (fgFirstBBisScratch())
{
fgFirstBB->Next()->bbFlags &= ~BBF_CAN_ADD_PRED;
}
}

// Under OSR, we no longer need to specially protect the original method entry
Expand Down

0 comments on commit 655b177

Please sign in to comment.