diff --git a/src/coreclr/jit/compiler.h b/src/coreclr/jit/compiler.h index 351e49636dfde..22d904e7ab380 100644 --- a/src/coreclr/jit/compiler.h +++ b/src/coreclr/jit/compiler.h @@ -4985,6 +4985,10 @@ class Compiler BlockSet fgEnterBlks; // Set of blocks which have a special transfer of control; the "entry" blocks plus EH handler // begin blocks. +#if defined(FEATURE_EH_FUNCLETS) && defined(TARGET_ARM) + BlockSet fgAlwaysBlks; // Set of blocks which are BBJ_ALWAYS part of BBJ_CALLFINALLY/BBJ_ALWAYS pair that should never + // be removed due to a requirement to use the BBJ_ALWAYS for generating code and not have "retless" blocks. +#endif // defined(FEATURE_EH_FUNCLETS) && defined(TARGET_ARM) #ifdef DEBUG bool fgReachabilitySetsValid; // Are the bbReach sets valid? diff --git a/src/coreclr/jit/fgbasic.cpp b/src/coreclr/jit/fgbasic.cpp index f3d48c8d33869..5dbf989ff86fa 100644 --- a/src/coreclr/jit/fgbasic.cpp +++ b/src/coreclr/jit/fgbasic.cpp @@ -119,6 +119,10 @@ void Compiler::fgInit() /* This is set by fgComputeReachability */ fgEnterBlks = BlockSetOps::UninitVal(); +#if defined(FEATURE_EH_FUNCLETS) && defined(TARGET_ARM) + fgAlwaysBlks = BlockSetOps::UninitVal(); +#endif // defined(FEATURE_EH_FUNCLETS) && defined(TARGET_ARM) + #ifdef DEBUG fgEnterBlksSetValid = false; #endif // DEBUG diff --git a/src/coreclr/jit/fgopt.cpp b/src/coreclr/jit/fgopt.cpp index 1a8fa855a6572..98ed38531a635 100644 --- a/src/coreclr/jit/fgopt.cpp +++ b/src/coreclr/jit/fgopt.cpp @@ -297,6 +297,10 @@ void Compiler::fgComputeEnterBlocksSet() fgEnterBlks = BlockSetOps::MakeEmpty(this); +#if defined(FEATURE_EH_FUNCLETS) && defined(TARGET_ARM) + fgAlwaysBlks = BlockSetOps::MakeEmpty(this); +#endif // defined(FEATURE_EH_FUNCLETS) && defined(TARGET_ARM) + /* Now set the entry basic block */ BlockSetOps::AddElemD(this, fgEnterBlks, fgFirstBB->bbNum); assert(fgFirstBB->bbNum == 1); @@ -315,19 +319,15 @@ void Compiler::fgComputeEnterBlocksSet() } #if defined(FEATURE_EH_FUNCLETS) && defined(TARGET_ARM) - // TODO-ARM-Cleanup: The ARM code here to prevent creating retless calls by adding the BBJ_ALWAYS - // to the enter blocks is a bit of a compromise, because sometimes the blocks are already reachable, - // and it messes up DFS ordering to have them marked as enter block. We should prevent the - // creation of retless calls some other way. + // For ARM code, prevent creating retless calls by adding the BBJ_ALWAYS to the "fgAlwaysBlks" list. for (BasicBlock* const block : Blocks()) { if (block->bbJumpKind == BBJ_CALLFINALLY) { assert(block->isBBCallAlwaysPair()); - - // Don't remove the BBJ_ALWAYS block that is only here for the unwinder. It might be dead - // if the finally is no-return, so mark it as an entry point. - BlockSetOps::AddElemD(this, fgEnterBlks, block->bbNext->bbNum); + + // Don't remove the BBJ_ALWAYS block that is only here for the unwinder. + BlockSetOps::AddElemD(this, fgAlwaysBlks, block->bbNext->bbNum); } } #endif // defined(FEATURE_EH_FUNCLETS) && defined(TARGET_ARM) @@ -401,6 +401,13 @@ bool Compiler::fgRemoveUnreachableBlocks() { goto SKIP_BLOCK; } + +#if defined(FEATURE_EH_FUNCLETS) && defined(TARGET_ARM) + if (!BlockSetOps::IsEmptyIntersection(this, fgAlwaysBlks, block->bbReach)) + { + goto SKIP_BLOCK; + } +#endif // defined(FEATURE_EH_FUNCLETS) && defined(TARGET_ARM) } // Remove all the code for the block @@ -637,7 +644,6 @@ void Compiler::fgDfsInvPostOrder() assert(fgEnterBlksSetValid); BlockSetOps::UnionD(this, startNodes, fgEnterBlks); - assert(BlockSetOps::IsMember(this, startNodes, fgFirstBB->bbNum)); // Call the flowgraph DFS traversal helper.