[LLVMdev] LLVM Exception Handling

Eugene Toder eltoder at gmail.com
Sun Sep 26 05:08:13 PDT 2010


I may me wrong, but I think Nathan used ints for demonstration
purposes only. unwind always takes i8* argument that ideally should be
a pointer to exception structure, variable %x in invoke is also typed
i8*, it's not "untyped". Probably more llvm-ish syntax would be

unwind i8* %x to label %catch

to show the type explicitly.
However throwing a pointer to a structure raises questions about
structure's ownership, so I think Nathan cheated a bit and threw an
int to make the code snippet simpler. Landing pad code then checked
the int, whereas real code would expect exception object.
"Real" code would look more like:

define i32 @v(i32 %o) {

  %r = icmp eq i32 %o, 0
	
  br i1 %r, label %raise, label %ok

ok:
  %m = mul i32 %o, 2
  ret i32 %m

raise:
  %ex = call i8* @allocate_exception()
  call void @init_div_by_0_eh(i8* %ex)

  ; unwind now takes an i8* "exception" pointer
  unwind i8* %ex
}

define i32 @g(i32 %o) {
entry:
  ; invoke produces a different value depending on whether if
  ; branches to the success case or the failure case.
  %s = invoke i32 @v(i32 %o) to label %ok
                   unwind %x to label %catch
ok:
  ret i32 %s

catch:
  %type = call i32 @exception_type(i8* %x)
  %r = icmp eq i32 %type, 255 ; 255 is DivisionByZeroException type
  br i1 %r, label %bad, label %worse
	
bad:
  ret i32 -1

worse:
  ret i32 -2
}


Nathan -- is this approach simpler than using intrinsics @eh.throw
(assuming it's added) and @eh.exception? The latter seems more
flexible in supporting various levels of ABI (I think ideally LLVM
exception handling should follow general platform ABI and also allow
front-ends for specific languages generate code in accordance with
language specific ABI).
I going with invoke instruction that returns exception pointer (which
feels right to me) maybe this is a good candidate for using union type
-- invoke can produce a single result which is either normal return
value or an exception pointer, since only one of the two values can be
actually produced. This sounds logical but may be taking us too far
from ABIs.

Eugene

On Sun, Sep 26, 2010 at 12:19 PM, Renato Golin <rengolin at systemcall.org> wrote:
> On 25 September 2010 23:46, Nathan Jeffords <blunted2night at gmail.com> wrote:
>> catch:
>>   %v = ptrtoint i8 * %x to i32
>>   %r = icmp eq i32 %v, 255
>>   br i1 %r, label %bad, label %worse
>> bad:
>>   ret i32 -1
>> worse:
>>   ret i32 -2
>> }
>
> If I understood correctly, you're trying to pass the clean-up flag
> through %x directly on the invoke call. But later avoid the
> eh.exception call, assuming that was in %x.
>
> The problem is that you're mixing two concepts: The exception
> structure contains information about the object that was thrown and
> not a "good" number. That's the role of the clean-up flag (in case the
> catch blocks can't deal with the exception) or the landing pads (that
> should reflect the return values the user asked for in their
> programs).
>
> It's the users role to tell what's good and what's not (return values
> included). the only thing you (compiler) can do is to explode
> prematurely in case you can't properly catch the error (ie. throw
> inside throw, throw inside delete, etc).
>
> If that's the case, your implementation will not work for dwarf
> exceptions, and I wouldn't recommend having an *invoke* syntax for
> each type of exception handling mechanism.
>
> Other question: why are you passing untyped %x? I haven't seen any
> untyped variable in LLVM, so far, and I think it's good to be
> redundant in this case. That alone would have caught the mistake. If
> you need an i32 (for your bad/worse comparison), throwing i8* would
> have hinted that you crossed the concepts.
>
>
> On a side note...
>
> Exception handling was designed by the devil himself. Part of the flow
> control is designed by the user (try/catch blocks, throw
> specifications), part of it is designed by the compiler, in exception
> tables (specific unwinding instructions and types), and part by the
> library writers (unwinding and personality routines). All that,
> decided in three different time frames, by three different kinds of
> developers, have to communicate perfectly in run time.
>
> It'd be very difficult for the compiler to optimize automatically
> without breaking run-time assumptions. All of that is controlled by
> different ABIs, that make sure all three universes are talking the
> same language. You can't change one without changing all the others...
>
> To be honest, I'm still surprised that it actually works at all! ;)
>
> --
> cheers,
> --renato
>
> http://systemcall.org/
>
> Reclaim your digital rights, eliminate DRM, learn more at
> http://www.defectivebydesign.org/what_is_drm
>
> _______________________________________________
> LLVM Developers mailing list
> LLVMdev at cs.uiuc.edu         http://llvm.cs.uiuc.edu
> http://lists.cs.uiuc.edu/mailman/listinfo/llvmdev
>




More information about the llvm-dev mailing list