Skip to content
Draft

Find sccs #120534

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
8 changes: 8 additions & 0 deletions src/coreclr/jit/compiler.h
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,7 @@ struct JumpThreadInfo; // defined in redundantbranchopts.cpp
class ProfileSynthesis; // defined in profilesynthesis.h
class PerLoopInfo; // defined in inductionvariableopts.cpp
class RangeCheck; // defined in rangecheck.h
class SCC;
#ifdef DEBUG
struct IndentStack;
#endif
Expand Down Expand Up @@ -2751,6 +2752,7 @@ class Compiler
bool bbInHandlerRegions(unsigned regionIndex, BasicBlock* blk);
bool bbInCatchHandlerRegions(BasicBlock* tryBlk, BasicBlock* hndBlk);
unsigned short bbFindInnermostCommonTryRegion(BasicBlock* bbOne, BasicBlock* bbTwo);
unsigned short bbFindInnermostCommonTryRegion(unsigned tryIndex, BasicBlock* bbTwo);

unsigned short bbFindInnermostTryRegionContainingHandlerRegion(unsigned handlerIndex);
unsigned short bbFindInnermostHandlerRegionContainingTryRegion(unsigned tryIndex);
Expand Down Expand Up @@ -6239,6 +6241,9 @@ class Compiler
template <typename VisitPreorder, typename VisitPostorder, typename VisitEdge, const bool useProfile = false>
unsigned fgRunDfs(VisitPreorder assignPreorder, VisitPostorder assignPostorder, VisitEdge visitEdge);

template <typename VisitPreorder, typename VisitPostorder, typename VisitEdge, const bool useProfile = false>
unsigned fgRunSubgraphDfs(VisitPreorder assignPreorder, VisitPostorder assignPostorder, VisitEdge visitEdge, BitVec& subgraph, BitVecTraits& subgraphTraits);

template <const bool useProfile = false>
FlowGraphDfsTree* fgComputeDfs();
void fgInvalidateDfsTree();
Expand Down Expand Up @@ -7024,6 +7029,9 @@ class Compiler
void optFindLoops();
bool optCanonicalizeLoops();

bool optFindSCCs(bool& failedToModify);
void optFindSCCs(BitVec& subset, BitVecTraits& traits, ArrayStack<SCC*>& sccs, BasicBlock** postorder, unsigned postorderCount);

void optCompactLoops();
void optCompactLoop(FlowGraphNaturalLoop* loop);
bool optCreatePreheader(FlowGraphNaturalLoop* loop);
Expand Down
137 changes: 137 additions & 0 deletions src/coreclr/jit/compiler.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -5197,6 +5197,143 @@ unsigned Compiler::fgRunDfs(VisitPreorder visitPreorder, VisitPostorder visitPos
return preOrderIndex;
}

//------------------------------------------------------------------------
// fgRunSubgraphDfs: Run DFS over a subgraph of the flow graph.
//
// Type parameters:
// VisitPreorder - Functor type that takes a BasicBlock* and its preorder number
// VisitPostorder - Functor type that takes a BasicBlock* and its postorder number
// VisitEdge - Functor type that takes two BasicBlock*.
// useProfile - If true, determines order of successors visited using profile data
//
// Parameters:
// visitPreorder - Functor to visit block in its preorder
// visitPostorder - Functor to visit block in its postorder
// visitEdge - Functor to visit an edge. Called after visitPreorder (if
// this is the first time the successor is seen).
// subgraphBlocks - bitvector (in postorder num space) identifying the subgraph
// subgraphTraits - traits for the subgraphBlocks
//
// Returns:
// Number of blocks visited.
//
// Notes:
// Assumes m_dfs is valid (in particular, uses block post order numbers)
//
template <typename VisitPreorder, typename VisitPostorder, typename VisitEdge, const bool useProfile /* = false */>
unsigned Compiler::fgRunSubgraphDfs(VisitPreorder visitPreorder,
VisitPostorder visitPostorder,
VisitEdge visitEdge,
BitVec& subgraph,
BitVecTraits& subgraphTraits)
{
// just reuse the existing traits here, and index by bbPostorderNum?
JITDUMP("Running subgraph DFS on %u blocks\n", BitVecOps::Count(&subgraphTraits, subgraph));
BitVecTraits traits(fgBBNumMax + 1, this);
BitVec visited(BitVecOps::MakeEmpty(&traits));

unsigned preOrderIndex = 0;
unsigned postOrderIndex = 0;

ArrayStack<AllSuccessorEnumerator> blocks(getAllocator(CMK_DepthFirstSearch));

auto dfsFrom = [&](BasicBlock* firstBB) {
BitVecOps::AddElemD(&traits, visited, firstBB->bbNum);
blocks.Emplace(this, firstBB, useProfile);
JITDUMP(" visiting " FMT_BB "\n", firstBB->bbNum);
visitPreorder(firstBB, preOrderIndex++);

while (!blocks.Empty())
{
BasicBlock* const block = blocks.TopRef().Block();
BasicBlock* const succ = blocks.TopRef().NextSuccessor();

if (succ != nullptr)
{
if (BitVecOps::IsMember(&subgraphTraits, subgraph, succ->bbPostorderNum))
{
if (BitVecOps::TryAddElemD(&traits, visited, succ->bbNum))
{
blocks.Emplace(this, succ, useProfile);
visitPreorder(succ, preOrderIndex++);
}

visitEdge(block, succ);
}

// If this is a callfinally but the finally itself is not
// in the subset, summarize the flow to the pair tail.
//
// Note a callfinally will only have one successor, so
// we don't need extra conditions here.
//
else if (block->isBBCallFinallyPair())
{
BasicBlock* const callFinallyRet = block->Next();

if (BitVecOps::IsMember(&subgraphTraits, subgraph, callFinallyRet->bbPostorderNum))
{
if (BitVecOps::TryAddElemD(&traits, visited, callFinallyRet->bbNum))
{
blocks.Emplace(this, callFinallyRet, useProfile);
visitPreorder(callFinallyRet, preOrderIndex++);
}

visitEdge(block, callFinallyRet);
}
}

continue;
}

blocks.Pop();
visitPostorder(block, postOrderIndex++);
}
};

// Find the subgraph entry blocks (blocks that have no pred, or a pred not in the subgraph).
//
ArrayStack<BasicBlock*> entries(getAllocator(CMK_DepthFirstSearch));

unsigned poNum = 0;
BitVecOps::Iter iterator(&subgraphTraits, subgraph);
while (iterator.NextElem(&poNum))
{
BasicBlock* const block = m_dfsTree->GetPostOrder(poNum);
bool hasPred = false;
for (BasicBlock* const pred : block->PredBlocks())
{
hasPred = true;
if (!BitVecOps::IsMember(&subgraphTraits, subgraph, pred->bbPostorderNum))
{
JITDUMP(FMT_BB " is subgraph entry\n", block->bbNum);
entries.Emplace(block);
}
}

if (!hasPred)
{
JITDUMP(FMT_BB " is an isolated subgraph entry\n", block->bbNum);
entries.Emplace(block);
}
}

// Kick off a DFS from each unvisited entry
//
while (entries.Height() > 0)
{
BasicBlock* const block = entries.Pop();

if (!BitVecOps::IsMember(&traits, visited, block->bbNum))
{
dfsFrom(block);
}
}

assert(preOrderIndex == postOrderIndex);
return preOrderIndex;
}

//------------------------------------------------------------------------
// fgVisitBlocksInLoopAwareRPO: Visit the blocks in 'dfsTree' in reverse post-order,
// but ensure loop bodies are visited before loop successors.
Expand Down
11 changes: 7 additions & 4 deletions src/coreclr/jit/fgbasic.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4909,31 +4909,34 @@ BasicBlock* Compiler::fgSplitBlockAtBeginning(BasicBlock* curr)
// Returns a new block, that is a successor of 'curr' and which branches unconditionally to 'succ'
//
// Assumptions:
// 'curr' must have a bbKind of BBJ_COND, BBJ_ALWAYS, or BBJ_SWITCH
// 'curr' must have a bbKind of BBJ_COND, BBJ_ALWAYS, BBJ_SWITCH, BBJ_CALLFINALLYRET, or BBJ_EHCATCHRET
//
// Notes:
// The returned block is empty.
// Can be invoked before pred lists are built.

BasicBlock* Compiler::fgSplitEdge(BasicBlock* curr, BasicBlock* succ)
{
assert(curr->KindIs(BBJ_COND, BBJ_SWITCH, BBJ_ALWAYS));
assert(curr->KindIs(BBJ_COND, BBJ_SWITCH, BBJ_ALWAYS, BBJ_CALLFINALLYRET, BBJ_EHCATCHRET));
assert(fgPredsComputed);
assert(fgGetPredForBlock(succ, curr) != nullptr);

// For EHCATCHRET put the split block in succ's EH region
BasicBlock* const cursor = curr->KindIs(BBJ_EHCATCHRET) ? succ : curr;

BasicBlock* newBlock;
if (curr->NextIs(succ))
{
// The successor is the fall-through path of a BBJ_COND, or
// an immediately following block of a BBJ_SWITCH (which has
// no fall-through path). For this case, simply insert a new
// fall-through block after 'curr'.
newBlock = fgNewBBafter(BBJ_ALWAYS, curr, true /* extendRegion */);
newBlock = fgNewBBafter(BBJ_ALWAYS, cursor, true /* extendRegion */);
}
else
{
// The new block always jumps to 'succ'
newBlock = fgNewBBinRegion(BBJ_ALWAYS, curr, /* isRunRarely */ curr->isRunRarely());
newBlock = fgNewBBinRegion(BBJ_ALWAYS, cursor, /* isRunRarely */ curr->isRunRarely());
}
newBlock->CopyFlags(curr, succ->GetFlagsRaw() & BBF_BACKWARD_JUMP);

Expand Down
3 changes: 3 additions & 0 deletions src/coreclr/jit/jitconfigvalues.h
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,9 @@ CONFIG_INTEGER(JitUnrollLoopMaxIterationCount,

CONFIG_INTEGER(JitUnrollLoopsWithEH, "JitUnrollLoopsWithEH", 0) // If 0, don't unroll loops containing EH regions

RELEASE_CONFIG_INTEGER(JitTransformIrreducibleLoops, "JitTransformIrreducibleLoops", 1) // 0: leave as is; 1: switch
// dispatch

CONFIG_INTEGER(JitDirectAlloc, "JitDirectAlloc", 0)
CONFIG_INTEGER(JitDoubleAlign, "JitDoubleAlign", 1)
CONFIG_INTEGER(JitEmitPrintRefRegs, "JitEmitPrintRefRegs", 0)
Expand Down
26 changes: 26 additions & 0 deletions src/coreclr/jit/jiteh.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -615,6 +615,32 @@ unsigned short Compiler::bbFindInnermostCommonTryRegion(BasicBlock* bbOne, Basic
return 0;
}

/******************************************************************************************
* Given a one-biased region index (which may be 0, indicating method region) and a block,
* return one-biased index for the inner-most enclosing try region that contains the block and the region.
* Return 0 if it does not find any try region (which means the inner-most region
* is the method itself).
*/

unsigned short Compiler::bbFindInnermostCommonTryRegion(unsigned index, BasicBlock* bbTwo)
{
assert(index <= compHndBBtabCount);

if (index == 0)
return 0;

for (unsigned XTnum = index - 1; XTnum < compHndBBtabCount; XTnum++)
{
if (bbInTryRegions(XTnum, bbTwo))
{
noway_assert(XTnum < MAX_XCPTN_INDEX);
return (unsigned short)(XTnum + 1); // Return the tryIndex
}
}

return 0;
}

// bbIsTryBeg() returns true if this block is the start of any try region.
// This is computed by examining the current values in the
// EH table rather than just looking at the block's bbFlags.
Expand Down
2 changes: 2 additions & 0 deletions src/coreclr/jit/jitmetadatalist.h
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,8 @@ JITMETADATAMETRIC(MorphTrackedLocals, int, 0)
JITMETADATAMETRIC(MorphLocals, int, 0)
JITMETADATAMETRIC(EnumeratorGDVProvisionalNoEscape, int, 0)
JITMETADATAMETRIC(EnumeratorGDVCanCloneToEnsureNoEscape, int, 0)
JITMETADATAMETRIC(IrreducibleLoopsFoundDuringOpts, int, 0)
JITMETADATAMETRIC(IrreducibleNestedLoopsFoundDuringOpts, int, 0)

#undef JITMETADATA
#undef JITMETADATAINFO
Expand Down
Loading
Loading