Bill's recent exception handling proposal has rules which (if I understand
them right) ensure that you can always find the actions for an invoke without
any trouble (the actions would be listed in a dispatch instruction that is
not allowed to be moved out of the landing pad). Thus with this proposal too
there would also be no problem in teaching the inliner to do the right thing.
If I got it right, you're saying that both proposals are similar in
that they both fix the inlining problem and both specify uniquely the
landing pads for every invoke.
yes, they both make the inlining problem fixable because it is always possible
to find the catch info associated with an invoke (or basic block). In fact any
proposal that has this property would do as far as fixing inlining goes.
In the case of Bill's proposal this property holds because of special rules
about what you are allowed to do with landing pads: you are not allowed to move
a dispatch instruction out of a landing pad etc. These rules could actually
be applied to eh.selector without any IR changes providing much the same effect
without a new instruction. However the reason for not doing this is that it
then makes some optimizations impossible, for example when you inline a call
to _Unwind_Resume through an invoke you would like to turn it into a branch to
the landing pad, but this would result in eh.selector calls that fail the rules.
It's not clear to me if the dispatch instruction has this problem too, I need
to ask Bill about it.
In fact Bill's proposal mostly seems to be about replacing the current explicit
sequence of comparisons that llvm-gcc uses to find which handler to run (I guess
everyone who has looked at LLVM IR with exception handling in it has seen all
the calls to eh.typeid.for, the comparisons and the branching that I'm talking
about here) with a more compact representation that is easier to analyse. As
such, from my point of view it doesn't really have much to do with the inlining
issue, which is not to say it doesn't have merit on other grounds.
An interesting point is that Bill's dispatch instruction is quite analogous to
GCC's gimple_eh_dispatch statement. This statement represents the transfer of
control to the appropriate catch handler for an exception region, and is at a
fairly high level of abstraction. It takes an exception handling try region as
an argument (it can also have an "allowed exceptions" region as an argument,
but there's no added value in discussing that). Since the list of associated
catches is stored in the region info, there is no need for it to explicitly
list tries and where to branch to, while Bill is obliged to put the info that
GCC stores in the region directly into his dispatch instruction.
Once GCC has finished running the inliner it runs the lower_eh_dispatch pass,
which removes all gimple_eh_dispatch statements by turning them into explicit
control flow: a sequence of comparisons and branches (exactly like the code
llvm-gcc/clang produce right now, comparing the selector value with the result
of eh.typeid.for calls). Since my proposal doesn't change this aspect of LLVM,
you can consider that before this pass GCC's representation is like Bill's and
after it is like in my proposal.
So, in view of their equivalence, I think Bill's proposal is better
for two reasons:
1. It eases the future elimination of invoke, or at least, the
treatment of current instruction-level exception (as in Java) in a
I don't see what is cleaner about it, except that it is overall at a higher
level of abstraction (see above).
2. It reinforces the idea of having one personality function for
each EH table (ie. per function), especially when inlining code from
different paradigms (if that's possible).
According to Bill's proposal each dispatch instruction can specify a different
personality function, so it's just the same as my proposal in this respect.
However, your proposal is better in two other accounts:
1. If we do want to support EH tables with multiple personalities in
As mentioned above, Bill's proposal also supports multiple personalities per
2. It's less invasive and closer to the problem it meant to fix in
the first place. So it'll be faster and easier to do that way.
It's more of a design decision, IMO.
Exactly, and this brings up the question of what criteria should be used to
decide which proposal is best. Presumably, all else being equal, whichever
one makes it easiest to optimize the IR. I didn't yet think about the
advantages and disadvantages of each proposal in this respect.