Unlike ret/resume, for unreachable currently no such tail-merging
is being performed by clang. There has been at least one previous attempt
at this - D29428.
@rnk noted in D104445, this may be somewhat problematic for certain backends
that "form regions later in the backend", but as per the feedback in D104870
this appears to be a non-problem.
As for the motivation for this, the goal basically is to de-pessimize(*)
the source code that either uses exceptions, and/or is built with assertions,
and/or with ASAN/UBSan instrumentation in warnings-as-errors more.
In all of these cases there's a few function-terminating IR patterns,
but they are repeated over and over again, bloating the function size,
which naturally counts towards inlining cost, which naturally lowers
the chances of the functions compiled under such conditions from being inlined.
(* the insufficient inlining is the pessimization)
As discussed in D101231, while we could technically teach inliner to exempt
such function-terminating blocks from the cost calculation,
we don't really want to do that, because we'd end with even more cold code.
But instead we can achieve much the same goal by decreasing the inline cost
via tail-merging & sinking common code.
All that being said, this is expected to result in *bigger* codesizes,
both because the inliner actually did something now,
and because ultimately the tail duplication in backend might have
undone what we have done here..
I expected your code to fire on this test case. Can you explain why this example isn't getting tail merged?
Consider this example: https://gcc.godbolt.org/z/ox16a9P1z
I think it is more canonical to leave these unreachable terminators in place after the calls to noreturn functions, rather than merging the unreachables together.
I just want to make sure your transform isn't firing, creating BBs, and then a later part of simplifycfg rolls the unreachables back up into place after the calls.