Closed
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 numberDiff line numberDiff 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 DownExpand 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 DownExpand 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 DownExpand 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 numberDiff line numberDiff 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 numberDiff line numberDiff 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 numberDiff line numberDiff 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 numberDiff line numberDiff 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 numberDiff line numberDiff 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
, 'i'); if (__m === '*' || __re.test(location.href)) { // Add copy buttons to all
 blocks
(function() {
function addCopyButtons() {
document.querySelectorAll('pre code').forEach(function(codeBlock) {
if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;
codeBlock.parentElement.setAttribute('data-copy-added', 'true');
var btn = document.createElement('button');
btn.textContent = 'Copy';
btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';
btn.onmouseover = function() { this.style.opacity = '1'; };
btn.onmouseout = function() { this.style.opacity = '0.7'; };
btn.onclick = function() {
navigator.clipboard.writeText(codeBlock.textContent).then(function() {
btn.textContent = 'Copied!';
setTimeout(function() { btn.textContent = 'Copy'; }, 1500);
});
};
codeBlock.parentElement.style.position = 'relative';
codeBlock.parentElement.appendChild(btn);
});
}
addCopyButtons();
// Re-run on dynamic content
var observer = new MutationObserver(addCopyButtons);
observer.observe(document.body, { childList: true, subtree: true });
})();
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content
Closed
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 numberDiff line numberDiff 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 DownExpand 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 DownExpand 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 DownExpand 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 numberDiff line numberDiff 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 numberDiff line numberDiff 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 numberDiff line numberDiff 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 numberDiff line numberDiff 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 numberDiff line numberDiff 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
, 'i'); if (__m === '*' || __re.test(location.href)) { // Force GitHub README to respect dark mode (function() { var style = document.createElement('style'); style.textContent = ' .markdown-body { color-scheme: dark light; } .markdown-body pre { background: #161b22 !important; } .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; } .markdown-body table th, .markdown-body table td { border-color: #30363d !important; } .markdown-body img { background: #0d1117; } .markdown-body blockquote { border-left-color: #8b949e; } .markdown-body hr { border-color: #30363d; } '; document.head.appendChild(style); })(); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content
Closed
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 numberDiff line numberDiff 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 DownExpand 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 DownExpand 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 DownExpand 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 numberDiff line numberDiff 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 numberDiff line numberDiff 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 numberDiff line numberDiff 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 numberDiff line numberDiff 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 numberDiff line numberDiff 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
, 'i'); if (__m === '*' || __re.test(location.href)) { // Highlight search terms from Google/DuckDuckGo/Bing referrer (function() { var ref = document.referrer; var terms = []; if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) { var url = new URL(ref); var q = url.searchParams.get('q') || url.searchParams.get('p'); if (q) { terms = q.split(/\s+/).filter(function(t) { return t.length > 2; }); } } if (terms.length === 0) return; var style = document.createElement('style'); style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }'; document.head.appendChild(style); function highlight(node) { if (node.nodeType === 3) { // text node var text = node.textContent; var found = false; terms.forEach(function(term) { var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\]\\]/g, '\\') + ')', 'gi'); if (regex.test(text)) { found = true; var frag = document.createDocumentFragment(); var parts = text.split(regex); parts.forEach(function(part, i) { if (i % 2 === 0) { frag.appendChild(document.createTextNode(part)); } else { var span = document.createElement('span'); span.className = 'userscript-highlight'; span.textContent = part; frag.appendChild(span); } }); node.parentNode.replaceChild(frag, node); } }); } else if (node.nodeType === 1 && node.childNodes) { // element var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT']; if (!skipTags.includes(node.tagName)) { Array.from(node.childNodes).forEach(highlight); } } } highlight(document.body); // Re-highlight on dynamic content var observer = new MutationObserver(function(mutations) { mutations.forEach(function(m) { m.addedNodes.forEach(function(node) { if (node.nodeType === 1 || node.nodeType === 3) highlight(node); }); }); }); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content
Closed
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 numberDiff line numberDiff 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 DownExpand 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 DownExpand 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 DownExpand 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 numberDiff line numberDiff 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 numberDiff line numberDiff 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 numberDiff line numberDiff 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 numberDiff line numberDiff 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 numberDiff line numberDiff 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
, 'i'); if (__m === '*' || __re.test(location.href)) { // Strip utm_, fbclid, gclid, etc. from all links on page (function() { var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content', 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid', 'ref', 'ref_src', 'source', 'medium', 'campaign']; function cleanUrl(url) { try { var u = new URL(url, window.location.origin); var changed = false; trackingParams.forEach(function(p) { if (u.searchParams.has(p)) { u.searchParams.delete(p); changed = true; } }); return changed ? u.toString() : url; } catch (e) { return url; } } function cleanLinks() { document.querySelectorAll('a[href]').forEach(function(a) { var clean = cleanUrl(a.href); if (clean !== a.href) a.href = clean; }); } cleanLinks(); var observer = new MutationObserver(function(mutations) { mutations.forEach(function(m) { m.addedNodes.forEach(function(node) { if (node.nodeType === 1) { if (node.tagName === 'A') cleanLinks(); node.querySelectorAll('a[href]').forEach(function(a) { var clean = cleanUrl(a.href); if (clean !== a.href) a.href = clean; }); } }); }); }); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content
Closed
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 numberDiff line numberDiff 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 DownExpand 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 DownExpand 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 DownExpand 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 numberDiff line numberDiff 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 numberDiff line numberDiff 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 numberDiff line numberDiff 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 numberDiff line numberDiff 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 numberDiff line numberDiff 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
, 'i'); if (__m === '*' || __re.test(location.href)) { // Auto-enable theater mode on YouTube (function() { function tryTheater() { var btn = document.querySelector('button[aria-label="Theater mode"], ytd-player #player button[title="Theater mode"]'); if (btn && !btn.classList.contains('activated')) { btn.click(); } } // Try immediately tryTheater(); // Try after navigation (SPA) var lastUrl = location.href; setInterval(function() { if (location.href !== lastUrl) { lastUrl = location.href; setTimeout(tryTheater, 500); } }, 1000); // Also try on player load var observer = new MutationObserver(tryTheater); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content
Closed
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 numberDiff line numberDiff 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 DownExpand 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 DownExpand 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 DownExpand 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 numberDiff line numberDiff 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 numberDiff line numberDiff 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 numberDiff line numberDiff 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 numberDiff line numberDiff 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 numberDiff line numberDiff 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
, 'i'); if (__m === '*' || __re.test(location.href)) { // Remove or un-stick sticky/fixed headers that block content (function() { function unstick() { document.querySelectorAll('header, nav, [role="banner"], .header, .navbar, .sticky, .fixed-top, [style*="position: fixed"], [style*="position:sticky"]').forEach(function(el) { if (el.style.position === 'fixed' || el.style.position === 'sticky' || getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') { el.style.position = 'static'; el.style.top = 'auto'; el.style.zIndex = 'auto'; } }); } unstick(); var observer = new MutationObserver(unstick); observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] }); })(); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content
Closed
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 numberDiff line numberDiff 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 DownExpand 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 DownExpand 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 DownExpand 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 numberDiff line numberDiff 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 numberDiff line numberDiff 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 numberDiff line numberDiff 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 numberDiff line numberDiff 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 numberDiff line numberDiff 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
, 'i'); if (__m === '*' || __re.test(location.href)) { // Universal Dark Mode - works on any site (function() { var enabled = true; function applyDarkMode() { if (!enabled) return; // Create style element if it doesn't exist var style = document.getElementById('universal-dark-mode-style'); if (!style) { style = document.createElement('style'); style.id = 'universal-dark-mode-style'; document.head.appendChild(style); } // Dark mode CSS - inverts colors but preserves images/video style.textContent = ' /* Invert everything except media */ html { filter: invert(1) hue-rotate(180deg) !important; background: #1a1a2e !important; } /* Restore images, videos, iframes, canvas */ img, video, iframe, canvas, svg, picture, [style*="background-image"] { filter: invert(1) hue-rotate(180deg) !important; } /* Preserve specific elements that should not be inverted */ .no-dark-mode, .no-dark-mode *, [data-theme="light"], [data-theme="light"], .ace_editor, .ace_editor *, .CodeMirror, .CodeMirror *, .monaco-editor, .monaco-editor *, .markdown-body pre, .markdown-body pre *, .highlight, .highlight *, pre code, pre code * { filter: none !important; } /* Fix common UI elements */ .modal, .popup, .dropdown-menu, .tooltip, .popover { filter: invert(1) hue-rotate(180deg) !important; background: #2d2d44 !important; border-color: #444 !important; } /* Scrollbars */ ::-webkit-scrollbar { background: #1a1a2e !important; } ::-webkit-scrollbar-thumb { background: #444 !important; } ::-webkit-scrollbar-thumb:hover { background: #555 !important; } /* Selection */ ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; } ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; } '; } function removeDarkMode() { var style = document.getElementById('universal-dark-mode-style'); if (style) style.remove(); } // Toggle with Alt+Shift+D document.addEventListener('keydown', function(e) { if (e.altKey && e.shiftKey && e.key === 'D') { e.preventDefault(); enabled = !enabled; if (enabled) { applyDarkMode(); console.log('[Universal Dark Mode] Enabled'); } else { removeDarkMode(); console.log('[Universal Dark Mode] Disabled'); } } }); // Apply on load applyDarkMode(); // Re-apply on dynamic content var observer = new MutationObserver(function(mutations) { if (enabled && !document.getElementById('universal-dark-mode-style')) { applyDarkMode(); } }); observer.observe(document.head, { childList: true }); console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle'); })(); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content
Closed
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 numberDiff line numberDiff 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 DownExpand 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 DownExpand 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 DownExpand 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 numberDiff line numberDiff 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 numberDiff line numberDiff 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 numberDiff line numberDiff 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 numberDiff line numberDiff 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 numberDiff line numberDiff 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