Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions src/coreclr/jit/compiler.h
Original file line number Diff line number Diff line change
Expand Up @@ -6286,6 +6286,9 @@ class Compiler
FlowGraphDfsTree* fgComputeDfs();
void fgInvalidateDfsTree();

template <typename TFunc>
void fgVisitBlocksInLoopAwareRPO(FlowGraphDfsTree* dfsTree, FlowGraphNaturalLoops* loops, TFunc func);

void fgRemoveReturnBlock(BasicBlock* block);

void fgConvertBBToThrowBB(BasicBlock* block);
Expand Down
69 changes: 69 additions & 0 deletions src/coreclr/jit/compiler.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -4970,6 +4970,75 @@ unsigned Compiler::fgRunDfs(VisitPreorder visitPreorder, VisitPostorder visitPos
return preOrderIndex;
}

//------------------------------------------------------------------------
// fgVisitBlocksInLoopAwareRPO: Visit the blocks in 'dfsTree' in reverse post-order,
// but ensure loop bodies are visited before loop successors.
//
// Type parameters:
// TFunc - Callback functor type
//
// Parameters:
// dfsTree - The DFS tree of the flow graph
// loops - A collection of the loops in the flow graph
// func - Callback functor that operates on a BasicBlock*
//
// Returns:
// A postorder traversal with compact loop bodies.
//
template <typename TFunc>
void Compiler::fgVisitBlocksInLoopAwareRPO(FlowGraphDfsTree* dfsTree, FlowGraphNaturalLoops* loops, TFunc func)
{
assert(dfsTree != nullptr);
assert(loops != nullptr);

// We will start by visiting blocks in reverse post-order.
// If we encounter the header of a loop, we will visit the loop's remaining blocks next
// to keep the loop body compact in the visitation order.
// We have to do this recursively to handle nested loops.
// Since the presence of loops implies we will try to visit some blocks more than once,
// we need to track visited blocks.
struct LoopAwareVisitor
{
BitVecTraits traits;
BitVec visitedBlocks;
FlowGraphNaturalLoops* loops;
TFunc func;

LoopAwareVisitor(FlowGraphDfsTree* dfsTree, FlowGraphNaturalLoops* loops, TFunc func)
: traits(dfsTree->PostOrderTraits())
, visitedBlocks(BitVecOps::MakeEmpty(&traits))
, loops(loops)
, func(func)
{
}

void VisitBlock(BasicBlock* block)
{
if (BitVecOps::TryAddElemD(&traits, visitedBlocks, block->bbPostorderNum))
{
func(block);

FlowGraphNaturalLoop* const loop = loops->GetLoopByHeader(block);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we may need to optimize the GetLoopByHeader implementation since right now this is quadratic complexity for pathological cases.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed -- is it alright if I do this in a followup?

if (loop != nullptr)
{
loop->VisitLoopBlocksReversePostOrder([&](BasicBlock* block) {
VisitBlock(block);
return BasicBlockVisit::Continue;
});
}
}
}
};

LoopAwareVisitor visitor(dfsTree, loops, func);

for (unsigned i = dfsTree->GetPostOrderCount(); i != 0; i--)
{
BasicBlock* const block = dfsTree->GetPostOrder(i - 1);
visitor.VisitBlock(block);
}
}

//------------------------------------------------------------------------------
// FlowGraphNaturalLoop::VisitLoopBlocksReversePostOrder: Visit all of the
// loop's blocks in reverse post order.
Expand Down
26 changes: 23 additions & 3 deletions src/coreclr/jit/lsra.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -953,9 +953,29 @@ void LinearScan::setBlockSequence()

assert((blockSequence == nullptr) && (bbSeqCount == 0));
FlowGraphDfsTree* const dfsTree = compiler->fgComputeDfs</* useProfile */ true>();
blockSequence = dfsTree->GetPostOrder();
bbNumMaxBeforeResolution = compiler->fgBBNumMax;
blockInfo = new (compiler, CMK_LSRA) LsraBlockInfo[bbNumMaxBeforeResolution + 1];

if (compiler->opts.OptimizationEnabled() && dfsTree->HasCycle())
{
// Ensure loop bodies are compact in the visitation order
FlowGraphNaturalLoops* const loops = FlowGraphNaturalLoops::Find(dfsTree);
blockSequence = new (compiler, CMK_LSRA) BasicBlock*[compiler->fgBBcount];
unsigned index = dfsTree->GetPostOrderCount();

auto addToSequence = [this, &index](BasicBlock* block) {
assert(index != 0);
blockSequence[--index] = block;
};

compiler->fgVisitBlocksInLoopAwareRPO(dfsTree, loops, addToSequence);
}
else
{
// TODO: Just use lexical block order in MinOpts
blockSequence = dfsTree->GetPostOrder();
}

bbNumMaxBeforeResolution = compiler->fgBBNumMax;
blockInfo = new (compiler, CMK_LSRA) LsraBlockInfo[bbNumMaxBeforeResolution + 1];

// Flip the DFS traversal to get the reverse post-order traversal
// (this is the order in which blocks will be allocated)
Expand Down
Loading