JIT: add pass to merge common throw helper calls (dotnet/coreclr#27113)
Look for blocks with single statement noreturn calls, and try to reroute
flow so there's just one block call that all predecessors target.
Resolves dotnet/coreclr#14770.
Note this impairs debuggability of optimized code a bit, as it can change which
line of code apparently invokes a throw helper in a backtrace. But since we're
already commoning jit-inserted throw helpers (like array index OOB) this is not
breaking any new ground.
We could also handle commoning BBJ_THROW blocks, with some extra effort,
but prototyping indicates duplicate throws are pretty rare.
This phase runs just before `optOptimizeFlow`, so that we can leverage
the ref counts and predecessor lists to ensure we make correct flow updates.
It doesn't bother trying to clean out IR, that happens naturally as blocks
become unreferenced.
In some cases nothrow helpers end up being tail call candidates. We now suppress
tail calling noreturn methods if there is more than one such call site in the method,
hoping that instead we can merge the calls.
Commit migrated from https://github.com/dotnet/coreclr/commit/
b962c97257400bee07805ccee66cd85d97195b40