Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 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
2 changes: 1 addition & 1 deletion src/coreclr/jit/block.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -637,7 +637,7 @@ void BasicBlock::dspJumpKind()
break;

case BBJ_EHFILTERRET:
printf(" (fltret)");
printf(" -> " FMT_BB " (fltret)", bbJumpDest->bbNum);
break;

case BBJ_EHCATCHRET:
Expand Down
2 changes: 1 addition & 1 deletion src/coreclr/jit/clrjit.natvis
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ Documentation for VS debugger format specifiers: https://docs.microsoft.com/en-u
</Type>

<Type Name="BasicBlock">
<DisplayString Condition="bbJumpKind==BBJ_COND || bbJumpKind==BBJ_ALWAYS || bbJumpKind==BBJ_LEAVE || bbJumpKind==BBJ_EHCATCHRET || bbJumpKind==BBJ_CALLFINALLY">BB{bbNum,d}->BB{bbJumpDest->bbNum,d}; {bbJumpKind,en}</DisplayString>
<DisplayString Condition="bbJumpKind==BBJ_COND || bbJumpKind==BBJ_ALWAYS || bbJumpKind==BBJ_LEAVE || bbJumpKind==BBJ_EHCATCHRET || bbJumpKind==BBJ_CALLFINALLY || bbJumpKind==BBJ_EHFILTERRET">BB{bbNum,d}->BB{bbJumpDest->bbNum,d}; {bbJumpKind,en}</DisplayString>
<DisplayString Condition="bbJumpKind==BBJ_SWITCH">BB{bbNum,d}; {bbJumpKind,en}; {bbJumpSwt->bbsCount} cases</DisplayString>
<DisplayString Condition="bbJumpKind==BBJ_EHFINALLYRET">BB{bbNum,d}; {bbJumpKind,en}; {bbJumpEhf->bbeCount} succs</DisplayString>
<DisplayString>BB{bbNum,d}; {bbJumpKind,en}</DisplayString>
Expand Down
2 changes: 1 addition & 1 deletion src/coreclr/jit/fgbasic.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -268,7 +268,7 @@ bool Compiler::fgEnsureFirstBBisScratch()
}

// The first block has an implicit ref count which we must
// remove. Note the ref count could be greater that one, if
// remove. Note the ref count could be greater than one, if
// the first block is not scratch and is targeted by a
// branch.
assert(fgFirstBB->bbRefs >= 1);
Expand Down
3 changes: 2 additions & 1 deletion src/coreclr/jit/fgdiagnostic.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2077,7 +2077,8 @@ void Compiler::fgTableDispBasicBlock(BasicBlock* block, int ibcColWidth /* = 0 *
break;

case BBJ_EHFILTERRET:
printf("%*s (fltret)", maxBlockNumWidth - 2, "");
printf("-> " FMT_BB "%*s (fltret)", block->GetJumpDest()->bbNum,
maxBlockNumWidth - max(CountDigits(block->GetJumpDest()->bbNum), 2), "");
break;

case BBJ_EHCATCHRET:
Expand Down
6 changes: 1 addition & 5 deletions src/coreclr/jit/fgflow.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -346,6 +346,7 @@ void Compiler::fgRemoveBlockAsPred(BasicBlock* block)
case BBJ_CALLFINALLY:
case BBJ_ALWAYS:
case BBJ_EHCATCHRET:
case BBJ_EHFILTERRET:
fgRemoveRefPred(block->GetJumpDest(), block);
break;

Expand All @@ -358,11 +359,6 @@ void Compiler::fgRemoveBlockAsPred(BasicBlock* block)
fgRemoveRefPred(block->Next(), block);
break;

case BBJ_EHFILTERRET:
block->GetJumpDest()->bbRefs++; // To compensate the bbRefs-- inside fgRemoveRefPred
fgRemoveRefPred(block->GetJumpDest(), block);
break;

case BBJ_EHFINALLYRET:
for (BasicBlock* const succ : block->EHFinallyRetSuccs())
{
Expand Down
84 changes: 49 additions & 35 deletions src/coreclr/jit/fgopt.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -437,6 +437,11 @@ bool Compiler::fgRemoveUnreachableBlocks(CanRemoveBlockBody canRemoveBlock)
// to properly set the info.compProfilerCallback flag.
continue;
}
else if ((block->bbFlags & BBF_DONT_REMOVE) && block->isEmpty() && block->KindIs(BBJ_THROW))
{
// We already converted a non-removable block to a throw; don't bother processing it again.
continue;
}
else if (!canRemoveBlock(block))
{
continue;
Expand All @@ -458,6 +463,8 @@ bool Compiler::fgRemoveUnreachableBlocks(CanRemoveBlockBody canRemoveBlock)

// Unmark the block as removed, clear BBF_INTERNAL, and set BBJ_IMPORTED

JITDUMP("Converting BBF_DONT_REMOVE block " FMT_BB " to BBJ_THROW\n", block->bbNum);

// The successors may be unreachable after this change.
changed |= block->NumSucc() > 0;

Expand Down Expand Up @@ -631,34 +638,6 @@ bool Compiler::fgRemoveDeadBlocks()
{
JITDUMP("\n*************** In fgRemoveDeadBlocks()");

jitstd::list<BasicBlock*> worklist(jitstd::allocator<void>(getAllocator(CMK_Reachability)));

worklist.push_back(fgFirstBB);

// Do not remove handler blocks
for (EHblkDsc* const HBtab : EHClauses(this))
{
if (HBtab->HasFilter())
{
worklist.push_back(HBtab->ebdFilter);
}
worklist.push_back(HBtab->ebdHndBeg);
}

#if defined(FEATURE_EH_FUNCLETS) && defined(TARGET_ARM)
// For ARM code, prevent creating retless calls by adding the BBJ_ALWAYS to the "fgAlwaysBlks" list.
for (BasicBlock* const block : Blocks())
{
if (block->KindIs(BBJ_CALLFINALLY))
{
assert(block->isBBCallAlwaysPair());

// Don't remove the BBJ_ALWAYS block that is only here for the unwinder.
worklist.push_back(block->Next());
}
}
#endif // defined(FEATURE_EH_FUNCLETS) && defined(TARGET_ARM)

unsigned prevFgCurBBEpoch = fgCurBBEpoch;
EnsureBasicBlockEpoch();

Expand All @@ -673,6 +652,9 @@ bool Compiler::fgRemoveDeadBlocks()

BlockSet visitedBlocks(BlockSetOps::MakeEmpty(this));

jitstd::list<BasicBlock*> worklist(jitstd::allocator<void>(getAllocator(CMK_Reachability)));
worklist.push_back(fgFirstBB);

// Visit all the reachable blocks, everything else can be removed
while (!worklist.empty())
{
Expand All @@ -690,6 +672,43 @@ bool Compiler::fgRemoveDeadBlocks()
{
worklist.push_back(succ);
}

// Add all the "EH" successors. For every `try`, add its handler (including filter) to the worklist.
if (bbIsTryBeg(block))
{
// Due to EH normalization, a block can only be the start of a single `try` region, with the exception
// of mutually-protect regions.
assert(block->hasTryIndex());
unsigned tryIndex = block->getTryIndex();
EHblkDsc* ehDsc = ehGetDsc(tryIndex);
for (;;)
{
worklist.push_back(ehDsc->ebdHndBeg);
if (ehDsc->HasFilter())
{
worklist.push_back(ehDsc->ebdFilter);
}
tryIndex = ehDsc->ebdEnclosingTryIndex;
if (tryIndex == EHblkDsc::NO_ENCLOSING_INDEX)
{
break;
}
ehDsc = ehGetDsc(tryIndex);
if (ehDsc->ebdTryBeg != block)
{
break;
}
}
}

#if defined(FEATURE_EH_FUNCLETS) && defined(TARGET_ARM)
// For ARM code, always keep BBJ_CALLFINALLY/BBJ_ALWAYS as a pair
if (block->KindIs(BBJ_CALLFINALLY))
{
assert(block->isBBCallAlwaysPair());
worklist.push_back(block->Next());
}
#endif // defined(FEATURE_EH_FUNCLETS) && defined(TARGET_ARM)
}

// Track if there is any unreachable block. Even if it is marked with
Expand All @@ -702,14 +721,8 @@ bool Compiler::fgRemoveDeadBlocks()
// any of the fgFirstBB, handler, filter or BBJ_ALWAYS (Arm) blocks.
auto isBlockRemovable = [&](BasicBlock* block) -> bool {
bool isVisited = BlockSetOps::IsMember(this, visitedBlocks, block->bbNum);
bool isRemovable = (!isVisited || block->bbRefs == 0);

#if defined(FEATURE_EH_FUNCLETS) && defined(TARGET_ARM)
isRemovable &=
!block->isBBCallAlwaysPairTail(); // can't remove the BBJ_ALWAYS of a BBJ_CALLFINALLY / BBJ_ALWAYS pair
#endif
bool isRemovable = !isVisited || (block->bbRefs == 0);
hasUnreachableBlock |= isRemovable;

return isRemovable;
};

Expand Down Expand Up @@ -738,6 +751,7 @@ bool Compiler::fgRemoveDeadBlocks()
fgVerifyHandlerTab();
fgDebugCheckBBlist(false);
#endif // DEBUG

return hasUnreachableBlock;
}

Expand Down