Vadim Chugunov
2014-Dec-03 21:27 UTC
[LLVMdev] RFC: How to represent SEH (__try / __except) in LLVM IR
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>
Reid Kleckner
2014-Dec-03 21:41 UTC
[LLVMdev] RFC: How to represent SEH (__try / __except) in LLVM IR
On Wed, Dec 3, 2014 at 1:27 PM, Vadim Chugunov <vadimcn at gmail.com> wrote:> 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... >Yes. This merely exposes the high cost of what the user is requesting. We could invent a more compact representation for a run of single-instruction bbs that share unwind edges, but *reliable* async exception support is fundamentally bad for optimization. Analysis passes need to see all the implicit edges. 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? >No, the transform is still valid. The block with the switch would contain a massive list of phis between undef and the incoming SSA values that were previously used by successor basic blocks. The incoming undef edge is not actually dynamically reachable, so it's safe to add undef there. -------------- next part -------------- An HTML attachment was scrubbed... URL: <http://lists.llvm.org/pipermail/llvm-dev/attachments/20141203/8b49fc41/attachment.html>
Vadim Chugunov
2014-Dec-03 22:26 UTC
[LLVMdev] RFC: How to represent SEH (__try / __except) in LLVM IR
On Wed, Dec 3, 2014 at 1:41 PM, Reid Kleckner <rnk at google.com> wrote:> On Wed, Dec 3, 2014 at 1:27 PM, Vadim Chugunov <vadimcn at gmail.com> wrote: > >> 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... >> > > Yes. This merely exposes the high cost of what the user is requesting. We > could invent a more compact representation for a run of single-instruction > bbs that share unwind edges, but *reliable* async exception support is > fundamentally bad for optimization. Analysis passes need to see all the > implicit edges. > > 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? >> > > No, the transform is still valid. The block with the switch would contain > a massive list of phis between undef and the incoming SSA values that were > previously used by successor basic blocks. The incoming undef edge is not > actually dynamically reachable, so it's safe to add undef there. >So what's to become of llvm.lifetime.start/end? Are they going to be removed or fixed? -------------- next part -------------- An HTML attachment was scrubbed... URL: <http://lists.llvm.org/pipermail/llvm-dev/attachments/20141203/779a6dce/attachment.html>