diff --git a/src/coreclr/jit/compiler.h b/src/coreclr/jit/compiler.h index 56f79d07641ec3..bc23aef0c3f298 100644 --- a/src/coreclr/jit/compiler.h +++ b/src/coreclr/jit/compiler.h @@ -9897,6 +9897,7 @@ class Compiler void funSetCurrentFunc(unsigned funcIdx); FuncInfoDsc* funGetFunc(unsigned funcIdx); unsigned int funGetFuncIdx(BasicBlock* block); + unsigned int bbFuncletRegionOf(BasicBlock* block); bool bbIsInSameFunclet(BasicBlock* block1, BasicBlock* block2); // LIVENESS diff --git a/src/coreclr/jit/compiler.hpp b/src/coreclr/jit/compiler.hpp index ecd0a3eeb94024..e0fe73e3f7deba 100644 --- a/src/coreclr/jit/compiler.hpp +++ b/src/coreclr/jit/compiler.hpp @@ -860,36 +860,45 @@ inline unsigned Compiler::funGetFuncIdx(BasicBlock* block) } /***************************************************************************** - * Are two blocks physically contained in the same function region (funclet)? - * The main method is region 0. Unlike funGetFuncIdx, this works for an - * arbitrary block (not just a funclet entry), distinguishing a filter + * Return the index of the function region (funclet) that physically contains + * `block`. The main method is region 0. Unlike funGetFuncIdx, this works for + * an arbitrary block (not just a funclet entry), distinguishing a filter * funclet (FUNC_FILTER) from its filter-handler. Only valid after funclets * are created. * */ -inline bool Compiler::bbIsInSameFunclet(BasicBlock* block1, BasicBlock* block2) +inline unsigned Compiler::bbFuncletRegionOf(BasicBlock* block) { assert(fgFuncletsCreated); - auto funcRegionOf = [this](BasicBlock* blk) -> unsigned { - if (!blk->hasHndIndex()) - { - return 0; - } + if (!block->hasHndIndex()) + { + return 0; + } - EHblkDsc* const eh = ehGetDsc(blk->getHndIndex()); - unsigned funcIdx = eh->ebdFuncIndex; + EHblkDsc* const eh = ehGetDsc(block->getHndIndex()); + unsigned funcIdx = eh->ebdFuncIndex; - if (eh->HasFilter() && eh->InFilterRegionBBRange(blk)) - { - // The filter is the funclet immediately preceding its filter-handler. - funcIdx--; - } + if (eh->HasFilter() && eh->InFilterRegionBBRange(block)) + { + // The filter is the funclet immediately preceding its filter-handler. + funcIdx--; + } - return funcIdx; - }; + return funcIdx; +} - return funcRegionOf(block1) == funcRegionOf(block2); +/***************************************************************************** + * Are two blocks physically contained in the same function region (funclet)? + * The main method is region 0. Unlike funGetFuncIdx, this works for an + * arbitrary block (not just a funclet entry), distinguishing a filter + * funclet (FUNC_FILTER) from its filter-handler. Only valid after funclets + * are created. + * + */ +inline bool Compiler::bbIsInSameFunclet(BasicBlock* block1, BasicBlock* block2) +{ + return bbFuncletRegionOf(block1) == bbFuncletRegionOf(block2); } #if HAS_FIXED_REGISTER_SET //------------------------------------------------------------------------------ diff --git a/src/coreclr/jit/fgwasm.cpp b/src/coreclr/jit/fgwasm.cpp index 39ebe5aa9cfd64..afd19800c736d4 100644 --- a/src/coreclr/jit/fgwasm.cpp +++ b/src/coreclr/jit/fgwasm.cpp @@ -1837,6 +1837,36 @@ PhaseStatus Compiler::fgWasmControlFlow() order++; } } + + { + // Verify that each funclet's blocks are contiguous. + // + jitstd::vector regionClosed(compFuncInfoCount, false, getAllocator(CMK_DebugOnly)); + unsigned prevRegion = UINT_MAX; + for (BasicBlock* const block : Blocks()) + { + const unsigned region = bbFuncletRegionOf(block); + assert(region < compFuncInfoCount); + + if (region != prevRegion) + { + if (prevRegion != UINT_MAX) + { + regionClosed[prevRegion] = true; + } + + if (regionClosed[region]) + { + JITDUMP("Wasm function region %u is not contiguous: " FMT_BB " re-enters it\n", region, + block->bbNum); + } + assert(!regionClosed[region] && + "wasm function region (main method / funclet) blocks are not contiguous"); + + prevRegion = region; + } + } + } #endif // DEBUG JITDUMPEXEC(fgDumpWasmControlFlow());