While nowadays SimplifyCFG knows how to hoist code from then-else blocks,
sink code from unconditional predecessors, and even promote the latter
by tail-merging ret/resume function terminators, that isn't everything.
While i (& others) have been trying to deal with merging/sinking unreachable,
apparently perhaps the more impactful remaining problem is merging the throw
calls.
If we start at the landingpad, all the predecessors are unwind edges of invokes,
and in some cases some of the invokes are mergeable.
/// This is a weird mix of hoisting and sinking. Visually, it goes from: /// [...] [...] /// | | /// [invoke0] [invoke1] /// / \ / \ /// [cont0] [landingpad] [cont1] /// to: /// [...] [...] /// \ / /// [invoke] /// / \ /// [cont] [landingpad]
This simplifies the IR/CFG, at the cost of debug info and extra PHI nodes.
Note that we don't require for *all* the invokes of the landingpad
to be mergeable, they can form more than a single set, we gracefully handle that.
For now, i completely disallowed normal destination, PHI nodes and indirect invokes
but that can be supported.
Out of all the CTMark projects, only 7zip is C++, so there isn't much impact:
https://llvm-compile-time-tracker.com/compare.php?from=ba8eb31bd9542828f6424e15a3014f80f14522c8&to=722fc871c84f14157d45c2159bc9c8c7e2825785&stat=size-total
... but there it currently causes size-total decrease.