@@ -13207,13 +13207,49 @@ void Compiler::fgMorphStmts(BasicBlock* block)
1320713207 fgRemoveRestOfBlock = false;
1320813208}
1320913209
13210+ //------------------------------------------------------------------------
13211+ // MorphUnreachbleInfo: construct info for unreachability tracking during morph
13212+ //
13213+ // Arguments:
13214+ // comp - compiler object
13215+ //
13216+ Compiler::MorphUnreachableInfo::MorphUnreachableInfo(Compiler* comp)
13217+ : m_traits(comp->m_dfsTree->GetPostOrderCount(), comp)
13218+ , m_vec(BitVecOps::MakeEmpty(&m_traits)){};
13219+
13220+ //------------------------------------------------------------------------
13221+ // SetUnreachable: during morph, mark a block as unreachable
13222+ //
13223+ // Arguments:
13224+ // block - block in question
13225+ //
13226+ void Compiler::MorphUnreachableInfo::SetUnreachable(BasicBlock* block)
13227+ {
13228+ BitVecOps::AddElemD(&m_traits, m_vec, block->bbPostorderNum);
13229+ }
13230+
13231+ //------------------------------------------------------------------------
13232+ // IsUnreachable: during morph, see if a block is now known to be unreachable
13233+ //
13234+ // Arguments:
13235+ // block - block in question
13236+ //
13237+ // Returns:
13238+ // true if so
13239+ //
13240+ bool Compiler::MorphUnreachableInfo::IsUnreachable(BasicBlock* block)
13241+ {
13242+ return BitVecOps::IsMember(&m_traits, m_vec, block->bbPostorderNum);
13243+ }
13244+
1321013245//------------------------------------------------------------------------
1321113246// fgMorphBlock: Morph a basic block
1321213247//
1321313248// Arguments:
1321413249// block - block in question
13250+ // unreachableInfo - [optional] info on blocks proven unreachable
1321513251//
13216- void Compiler::fgMorphBlock(BasicBlock* block)
13252+ void Compiler::fgMorphBlock(BasicBlock* block, MorphUnreachableInfo* unreachableInfo )
1321713253{
1321813254 JITDUMP("\nMorphing " FMT_BB "\n", block->bbNum);
1321913255
@@ -13243,6 +13279,8 @@ void Compiler::fgMorphBlock(BasicBlock* block)
1324313279 else
1324413280 {
1324513281 bool hasPredAssertions = false;
13282+ bool isReachable =
13283+ (block == fgFirstBB) || (block == genReturnBB) || (opts.IsOSR() && (block == fgEntryBB));
1324613284
1324713285 for (BasicBlock* const pred : block->PredBlocks())
1324813286 {
@@ -13257,10 +13295,27 @@ void Compiler::fgMorphBlock(BasicBlock* block)
1325713295 JITDUMP(FMT_BB " pred " FMT_BB " not processed; clearing assertions in\n", block->bbNum,
1325813296 pred->bbNum);
1325913297 hasPredAssertions = false;
13298+
13299+ // Generally we must assume this pred will be reachable.
13300+ //
13301+ isReachable = true;
1326013302 break;
1326113303 }
1326213304
13263- // Yes, pred assertions are available.
13305+ // This pred was reachable in the pre-morph DFS, but might have
13306+ // become unreachable during morph. If so, we can ignore its assertion state.
13307+ //
13308+ if (unreachableInfo->IsUnreachable(pred))
13309+ {
13310+ JITDUMP("Pred " FMT_BB " is no longer reachable\n", pred->bbNum);
13311+ continue;
13312+ }
13313+
13314+ // Since we have a reachable pred, this blocks is also reachable.
13315+ //
13316+ isReachable = true;
13317+
13318+ // This pred is reachable and has available assertions.
1326413319 // If the pred is (a non-degenerate) BBJ_COND, fetch the appropriate out set.
1326513320 //
1326613321 ASSERT_TP assertionsOut;
@@ -13312,6 +13367,31 @@ void Compiler::fgMorphBlock(BasicBlock* block)
1331213367 //
1331313368 canUsePredAssertions = false;
1331413369 }
13370+
13371+ // If there wasn't any reachable pred, this block is also not
13372+ // reachable. Note we exclude handler entries above, since we don't
13373+ // do the correct assertion tracking for handlers. Thus there is
13374+ // no need to consider reachable EH preds.
13375+ //
13376+ if (!isReachable)
13377+ {
13378+ JITDUMP(FMT_BB " has no reachable preds, marking as unreachable\n", block->bbNum);
13379+ unreachableInfo->SetUnreachable(block);
13380+
13381+ // Remove the block's IR and flow edges but don't mark the block as removed.
13382+ // Convert to BBJ_THROW. But leave CALLFINALLY alone.
13383+ //
13384+ // If we clear out the block, there is nothing to morph, so just return.
13385+ //
13386+ bool const isCallFinally = block->KindIs(BBJ_CALLFINALLY);
13387+ if (!isCallFinally)
13388+ {
13389+ fgUnreachableBlock(block);
13390+ block->RemoveFlags(BBF_REMOVED);
13391+ block->SetKindAndTargetEdge(BBJ_THROW);
13392+ return;
13393+ }
13394+ }
1331513395 }
1331613396
1331713397 if (!canUsePredAssertions)
@@ -13430,6 +13510,10 @@ PhaseStatus Compiler::fgMorphBlocks()
1343013510 INDEBUG(fgSafeBasicBlockCreation = false;);
1343113511 INDEBUG(fgSafeFlowEdgeCreation = false;);
1343213512
13513+ // We will track which blocks become unreachable during morph
13514+ //
13515+ MorphUnreachableInfo unreachableInfo(this);
13516+
1343313517 // Allow edge creation to genReturnBB (target of return merging)
1343413518 // and the scratch block successor (target for tail call to loop).
1343513519 // This will also disallow dataflow into these blocks.
@@ -13452,7 +13536,7 @@ PhaseStatus Compiler::fgMorphBlocks()
1345213536 for (unsigned i = m_dfsTree->GetPostOrderCount(); i != 0; i--)
1345313537 {
1345413538 BasicBlock* const block = m_dfsTree->GetPostOrder(i - 1);
13455- fgMorphBlock(block);
13539+ fgMorphBlock(block, &unreachableInfo );
1345613540 }
1345713541 assert(bbNumMax == fgBBNumMax);
1345813542
0 commit comments