[LLVMdev] RFC: Exception Handling Proposal II
Bill Wendling
wendling at apple.com
Wed Nov 24 17:07:26 PST 2010
On Nov 24, 2010, at 11:18 AM, John McCall wrote:
> On Nov 24, 2010, at 5:36 AM, Bill Wendling wrote:
>> Ah ha! I think I had a different mental model than you did. Or at least I remembered things differently from the discussion. :-) For me, there is one dispatch per region, which is why I had the region number associated with the invokes as well as the "unwind to" edge coming from them. (See my response to Renato for a description.) I'll think more about your model...
>
> Hmm. The difference between our models is actually in what we're calling a region. In your model, adding a cleanup doesn't require a new region; you just create a new landing pad which does the cleanup and then branches to (I guess) the landing pad of its containing cleanup. So landing pads are many-to-one with regions and dispatch instructions. In my model, every independent landing pad is necessarily a region. So in my model, there is also one dispatch per region, but there are more regions.
>
> So, in this example:
> A { A(); ~A() throw(); };
> void foo() throw() {
> A x;
> b();
> }
>
> Your model has this as follows, modulo syntax:
> entry:
> %x = alloca %A
> invoke void @A::A(%A* %x) to label %succ0 unwind label %lp0 region 0
> succ0:
> invoke void @b() to label %succ1 unwind label %lp1 region 0
> succ1:
> call void @A::~A(%A* %x) nounwind
> ret void
> lp0:
> call void @A::~A(%A* %x) nounwind
> br label %lp1
> lp1:
> dispatch region 0 [filter i8* null] # no resume edge
>
> Whereas my model has this as follows:
> entry:
> %x = alloca %A
> invoke void @A::A(%A* %x) to label %succ0 unwind label %lp0 region 0
> succ0:
> invoke void @b() to label %succ1 unwind label %lp1 region 1
> succ1:
> call void @A::~A(%A* %x) nounwind
> ret void
> lp0:
> call void @A::~A(%A* %x) nounwind
> dispatch region 0 [], resume label %lp1
> lp1:
> dispatch region 1 [filter i8* null] # no resume edge
>
> I think my model has some nice conceptual advantages; for one, it gives you the constraint that only EH edges and dispatch instructions can lead to landing pads, which I think will simplify what EH preparation has to do. But I could be convinced.
>
Notice though that we would need to keep both the EH edge from the invoke and the region numbers, which you said was redundant (in your first email). :-) Consider if there were several cleanup landing pads leading in a chain, through successive dispatches, down to the last dispatch that decides which catch to execute:
lp0:
call void @A::~A(%A* %x)
dispatch region 0 [], resume label %lp1
lp1:
call void @B::~B(%B* %y)
dispatch region 1 [], resume label %lp2
lp2:
call void @C::~C(%C* %z)
dispatch region 2 [], resume label %lp3
lp3:
dispatch region 3 [filter i8* null] # no resume edge
If we have inlining of any of those d'tor calls, we may lose the fact that the dispatch in, say, lp1 is a cleanup that lands onto the region 2 dispatch in lp2. We know from experience that once this information is lost, it's *really* hard to get it back again. That's what DwarfEHPrepare.cpp is all about, and I want to get rid of that pass because it's a series of hacks to get around our poor EH support.
On a personal level, I'm not a big fan of forcing constraints on code when they aren't needed. We had problems in the past (with inlining into a cleanup part of an EH region) with enforcing the invariant that only unwind edges may jump to a landing pad. If we go back to the example above, if @C::~C() were inlined, it could come to pass that the dispatch is placed into a separate basic block and that the inlined code branches into that new basic block thus violating the constraint.
-bw
More information about the llvm-dev
mailing list