diff --git a/src/coreclr/jit/compiler.h b/src/coreclr/jit/compiler.h index 97853ad6fc8d30..7900ae57e329ae 100644 --- a/src/coreclr/jit/compiler.h +++ b/src/coreclr/jit/compiler.h @@ -6286,6 +6286,9 @@ class Compiler FlowGraphDfsTree* fgComputeDfs(); void fgInvalidateDfsTree(); + template + void fgVisitBlocksInLoopAwareRPO(FlowGraphDfsTree* dfsTree, FlowGraphNaturalLoops* loops, TFunc func); + void fgRemoveReturnBlock(BasicBlock* block); void fgConvertBBToThrowBB(BasicBlock* block); diff --git a/src/coreclr/jit/compiler.hpp b/src/coreclr/jit/compiler.hpp index 4f70a01a8a79e8..b341b017d344e5 100644 --- a/src/coreclr/jit/compiler.hpp +++ b/src/coreclr/jit/compiler.hpp @@ -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 +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); + 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. diff --git a/src/coreclr/jit/lsra.cpp b/src/coreclr/jit/lsra.cpp index c57ae36038e8d8..1467d1a6b51f43 100644 --- a/src/coreclr/jit/lsra.cpp +++ b/src/coreclr/jit/lsra.cpp @@ -953,9 +953,29 @@ void LinearScan::setBlockSequence() assert((blockSequence == nullptr) && (bbSeqCount == 0)); FlowGraphDfsTree* const dfsTree = compiler->fgComputeDfs(); - 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)