[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