[LLVMdev] RFC: How to represent SEH (__try / __except) in LLVM IR

Vadim Chugunov
Wed, 03 Dec 2014 21:27:48 -0000

If we added unwind target to every potentially throwing instruction (loads,
stores, all binary operations), wouldn't all such instructions have to
become BB terminators?   I'd expect that CFG would then end up consisting
mostly of single-instruction BBs. This can't be good for compilation
performance and optimizations...

Another vague idea: what if lifetime.start() returned some kind of a token,
which lifetime.end() has to consume?   That would prevent transformations
that don't preserve lifetime scopes (such as the one you've described),
wouldn't it?

Vadim

On Wed, Dec 3, 2014 at 12:55 PM, Reid Kleckner <rnk at google.com> wrote:

> On Tue, Dec 2, 2014 at 6:05 PM, Vadim Chugunov <vadimcn at gmail.com>
wrote:
>
>> Sure, but memory access violations are not the only source of
>> asynchronous exceptions.  There are also stack overflows, integer
overflows
>> (on platforms that support that in hardware), signaling NaNs, and so
on...
>>
>> I am curious, what do you think of the following idea: what if instead
of
>> creating landing pads for running destructors, there were intrinsics
for
>> marking start and end of the object's lifetime (along with a
pointer to
>> destructor)?  LLVM could then emit a table of live objects for each PC
>> range into LSDA, and the personality routine would interpret that table
and
>> invoke destructors.  (catch() would still need a landing pad, of
course).
>> /end bike-shedding
>>
>
> I don't think calls to start / end are good enough, because graphs
don't
> have scope. We are seeing problems with lifetime start / end already.
> Consider a transformation which turns every branch into a branch to a
> single basic block which switches over all possible branch targets. This is
> a valid LLVM transformation, even if it is not an optimization, and it
> would be impossible to recover the natural scope-like information from
> start / end call pairs.
>
> I also think that recovering from async exceptions will always be best
> effort. The kinds of exceptions you describe are essentially results of
> undefined behavior in LLVM IR, and can't be handled reliably. Unless we
> introduce specific constructs with defined behavior (trapping integer
> divide, trapping FP ops, trapping alloca), it will never work.
>
> Chris Lattner had a proposal from a long time ago to add 'unwind'
labels
> to every basic block, but it introduces a lot of implicit control flow,
> which we don't like:
> http://nondot.org/sabre/LLVMNotes/ExceptionHandlingChanges.txt
>
> You would do this:
>   %p = call i8* malloc(i32 4)
>   %xp = bitcast i8* %p to i32*
>   ...
>
> mybb: unwind to label %lpad1
>   %x = load i32* %xp  ; edge to lpad1 here
>   store i32 0, i32* %xp ; edge to lpad1 here
>   call void @f() ; edge to lpad1 here
>   br label %mybb2 ; cannot remove branch due to differing lpads
>
> mybb2: unwind to label %lpad2
>   ...
>
> lpad:
>   %xx = load i32* %xp ; we cannot make %xx a phi between %x and 0 due to
> implicit control flow. Maybe we could split mybb and then make the phi,
> but, ew.
>
> This is a mountain. I think you can climb it, but I'm *not* signing up
for
> it. :) Adding and invoking intrinsics for all possibly trapping operations
> seems much more tractable. Simply outlining try bodies is even easier.
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL:
<http://lists.llvm.org/pipermail/llvm-dev/attachments/20141203/d2bf958d/attachment.html>