I strongly believe we need some variant of this.
The main problem is e.g. that the glibc's assert has 4 parameters,
but the profitability check is only okay with one extra phi node,
so D116692 doesn't even trigger on most of the expected cases.
While that restriction probably makes sense in normal code, if we
are about to run off of a cliff (into an unreachable), this
successor block is unlikely so the cost to setup these PHI nodes
should not be on the hotpath, and shouldn't matter performance-wise.
Likewise, we don't sink if there are unconditional predecessors
UNLESS we'd sink at least one non-speculatable instruction,
which is a performance workaround, but if we are about to run into
unreachable, it shouldn't matter.
One open question is whether to only allow simple control flow
that directly unconditionally leads to unreachable,
or instead check that all the function terminator blocks
that post-dominate the block into which we are sinking
are unreachable (i.e. allow loops).
Where is the implementation of IsBlockPostDominatedByDeoptOrUnreachable?
In any case, just from the name, I'm not sure this quite captures the property you want here. There's a difference between sinking into a block that ends in unreachable, vs. a block where the control flow eventually leads to unreachable. There could be a non-trivial amount of code between the code you're transforming, and the actual unreachable instruction. (e.g. the main loop of a program likely ends with a call to exit(), so all blocks in the main function are post-dominated by unreachable).