[LLVMdev] Alternative exception handling proposal

John McCall rjmccall at apple.com
Thu Dec 2 03:44:35 PST 2010


On Dec 2, 2010, at 1:40 AM, Duncan Sands wrote:
> Two amendments:
> 
>> The semantics of the invoke instruction are slightly modified: if an exception
>> unwinds and it doesn't match anything in the list of catches and filters,
>> and there is no cleanup, then control doesn't branch to the unwind label,
>> unwinding simply continues out of the function.
> 
> in fact the new semantics would be that if an exception doesn't match then
> it is unspecified whether it just unwinds straight through the invoke or
> branches to the landing pad.  This forces front-ends to output code to
> continue unwinding ("rewind" instruction, see below) if the selector does
> not match any of the catches on the invoke.  This in turn ensures that inlining
> works correctly.

Okay, this is at least workable, and it has the advantage of requiring less invasive
changes to IR structure.  It has the disadvantage of requiring us to emit a cleanup
path for every handling scope, which is a code size pessimization, but catches are
rare relative to cleanups, so that's probably not a problem in practice — and
it should be easy to optimize if we really care, since by definition we're talking
about a landing pad which doesn't do anything interesting before it tests the selector
value.

I haven't really thought about how to actually make the data flow correctly, though,
so I might let you and Bill fight out the best representation.

>> The rewind instruction
>> ----------------------
>> 
>> For extra goodness, I propose introducing a new instruction "rewind" that takes
>> an exception pointer and selector value as arguments:
>>    rewind<ptr>,<i32>
> 
> Actually the existing "unwind" instruction can be repurposed for this, as there
> was no real need for rewind to take any arguments.  All that is needed is that
> unwind be lowered to a call of eh.exception, which is then passed as the
> argument to _Unwind_Resume,  In fact codegen already does this!

I'm unhappy about how this bakes _Unwind_Resume into the backend, particularly
since that prevents us from using better alternatives when they're available
(e.g. the ARM EH ABI's _cxa_end_cleanup(), which saves code size by not requiring
the exception pointer, but which we can only use if we're linking in the C++ standard
library).

One idea that comes to mind is that we could make Yet Another call-like instruction,
a terminator like 'invoke' but with no successors and with the special
replaced-with-a-branch behavior when inlined through an invoke.  So the front-end
could call whatever function it pleases, taking responsibility for passing in the right
information.

That is, instead of:
  rewind i8* %saved_exception_ptr
you'd have:
  rewind void @_Unwind_Resume(i8* %saved_exception_ptr)
or:
  rewind void @_cxa_end_cleanup()
or, for targets that want special code sequences for resuming, something like:
  rewind void @llvm.crazytarget.end_cleanup()

This also handily eliminates the problem of EHPrepare having to calculate data flow
itself to the rewind instruction.

Since Gabor already made most of the world use CallSite, adding a third
call-like wouldn't be the end of the world, although I think most operations on calls
(inlining, etc.) wouldn't apply to rewinds anyway.

John.



More information about the llvm-dev mailing list