[LLVMdev] RFC: Native Windows C++ exception handling

Reid Kleckner rnk at google.com
Thu Jan 29 12:04:11 PST 2015


Nice. This seems like a good starting design for some patches.

I'm not sure exactly how step 3.a works. Does it stem from step 4.b which
assigns the same eh_state to two catch handlers? It seems like these rules
would come into play in these examples:

// 'catch int' and 'catch float' have the same incoming eh_state range
try { f(); }
catch (int) { g(); }
catch (float) { h(); }

// 'catch float' covers more than 'catch int', has different eh_state
range, we need to do step 3.a when we reach 'invoke void @g()'
try {
  try { f(); }
  catch (int) { g(); }
} catch (float) { h(); }

Is that the idea?

> So, I think it makes sense to compute the unwind and catch tables during
the MSVCEHPrepare pass, but I wasn’t sure how best to preserve the
information once it was computed.  Is it reasonable to stick this in
metadata?

I guess we can do the EH state assignment in the preparation pass, so long
as it's resilient to basic block reordering. A good source program to play
with would be:

extern int global;
void g();
void h();
void i();
void f() {
  g();
  try {
    h();
    if (__builtin_unlikely(global))
      i();
    h();
  } catch (int) {
  }
  g();
}

The LLVM IR will preserve source order, but block placement will see the
branch hint and rearrange to:

callq g
callq h
testl global(%rip)
jne .L1
.L2:
callq h
callq g
.L1:
callq i
jmp .L2

Perhaps we can assign landing pads EH states during preparation by placing
a call to something like @llvm.eh.state there, or making it part of the
@llvm.eh.actions call? Then the ip2state table will assign the .L1 block
the same state as the range over the h() calls.

On Wed, Jan 28, 2015 at 4:49 PM, Kaylor, Andrew <andrew.kaylor at intel.com>
wrote:

>  Hi Reid,
>
>
>
> I’ve worked through a few scenarios, and I think this is converging.  I’m
> attaching a new example, which extends the one we’ve been working through
> to handle a few more cases.
>
>
>
> I wasn’t sure what you intended the first i32 argument in an
> llvm.eh.actions entry to be.  I’ve been using it as a place to store the eh
> state that I’m associating with the action, but that’s kind of circular
> because I’m using the information in these tables to calculate that value.
> I’ll be able to do this calculation in the MSVCEHPrepare pass before these
> instructions are added, so I can put it there (it’s nice for readability),
> but the later pass that generates the tables (assuming we leave that in a
> later pass) will need information not represented in the action table (at
> least as I’ve been using it).  I’m not 100% sure that this is necessary,
> but it seemed like the way things ought to be.  I’ll experiment more before
> anything gets set in stone.
>
>
>
> In addition to the IP-to-state table that we’ve talked about, we also need
> an unwind table (which has each state, the state it transitions to when it
> expires and the unwind handler, if any) and a catch handler table (which
> has the range of states that can throw to the handlers, the state of the
> handlers and a map of types handled to their handlers).  I’ve got examples
> of these in the attached example.
>
>
>
> So I now have a firm plan for how to compute these tables from the
> outlined IR.
>
>
>
> I think the algorithm you proposed for computing eh states doesn’t quite
> work.  In particular, if multiple catch handlers get added by the same
> landing pad we’ll want to start by assuming that they have the same state.
> If they end up getting popped at different times then we’ll need to update
> the eh state of the one that gets popped first.  Unfortunately my example
> doesn’t cover this case, but I worked through it and my new algorithm
> (based on your but slightly tweaked) works for that case.  Also, unwind
> handlers get discrete states (they happen when a transition crosses the
> state, but in the .xdata tables they are represented with a single state).
> Catch handlers, on the other hand, do get a range.
>
>
>
> Anyway, here’s what I’m doing (by hand so far, I don’t have it coded yet).
>
>
>
> 1. Start with an empty stack of actions and an empty master list of eh
> state.
>
> 2. Visit each landing pad in succession, processing the actions at that
> landing pad back to front.
>
> 3. Pop actions from the current stack that aren’t in the current landing
> pad’s action table
>
>    a. If a catch is popped that had been assumed to have the same state as
> a catch that isn’t being popped
>
>            its state number and all state numbers above it need to be
> incremented
>
>    b. When a catch is popped, the next available eh_state is assigned to
> its handler
>
> 4. As an action is pushed to the current stack, it is assigned an eh_state
> in the master list
>
>    a. If the action was an unwind or if it was a cacth after an unwind,
> the next available eh_state is incremented
>
>    b. If the action was a catch following a catch that was also just
> added, it gets the same eh_state as the previous catch
>
> 5. When all landing pads have been handled, the remaining actions are
> popped and processed as above.
>
>
>
> The “next” state for each eh_state can also be computed during the above
> process by observing the state of the action on the top of the current
> action stack when the action associated with the state is popped.  In the
> case of catch handlers, I think the next state will always be the same as
> the next state of the corresponding catch action.
>
>
>
> So, I think it makes sense to compute the unwind and catch tables during
> the MSVCEHPrepare pass, but I wasn’t sure how best to preserve the
> information once it was computed.  Is it reasonable to stick this in
> metadata?
>
>
>
> We can keep fine tuning this if you like, but I think it’s looking solid
> enough that I’m going to start revising my outlining patch to produce the
> results in the attached example.
>
>
>
> -Andy
>
>
>
>
>
> *From:* Reid Kleckner [mailto:rnk at google.com]
> *Sent:* Tuesday, January 27, 2015 1:55 PM
> *To:* Kaylor, Andrew
> *Cc:* Bataev, Alexey; Reid Kleckner (reid at kleckner.net); LLVM Developers
> Mailing List; Anton Korobeynikov; Kreitzer, David L
> *Subject:* Re: [LLVMdev] RFC: Native Windows C++ exception handling
>
>
>
> On Tue, Jan 27, 2015 at 12:58 PM, Kaylor, Andrew <andrew.kaylor at intel.com>
> wrote:
>
> Thanks, Reid.   These are good points.
>
>
>
> So I guess that does take us back to something more like my original
> proposal.
>
>
>
> I like your suggestion of having some kind of “eh.actions” intrinsic to
> represent the outlining rather than the extension to landingpad that I had
> proposed.  I was just working on something like that in conjunction with my
> second alternative idea.
>
>
>
> Great!
>
>
>
>  What I’d really like is to have the “eh.actions” intrinsic take a shape
> that makes it really easy to construct the .xdata table directly from these
> calls.  As I think I mentioned in my original post, I think I have any idea
> for how to reconstruct functionally correct eh states (at least for
> synchronous EH purposes) from the invoke and landingpad instructions.  I
> would like to continue, as in my original proposal, limiting the unwind
> representations to those that are unique to a given landing pad.  I think
> with enough documentation I can make that seem sensible.
>
>
>
> My thinking is that the "eh.actions" list can be transformed into a
> compact xdata table later, after we've done machine basic block layout.
>
>
>
> I think the algorithm will be something like
>
>
>
> 1. Input: already laid out MachineFunction
>
> 2. Call EHStreamer::computeCallSiteTable to populate a LandingPadInfo
> vector sorted by ascending PC values
>
> 4. Iterate the LandingPadInfos, comparing the action list of each landing
> pad with the previous landing pad, assuming an empty action list at
> function start and end.
>
> 5. Model the action list as a stack, and compute the common suffix of the
> landing pad action lists
>
> 6. Each new action pushed represents a new EH state number
>
> 7. Pushing a cleanup action adds a state table entry that transitions from
> the current EH state to the previous with a cleanup handler
>
> 8. Pushing a catch action adds a new unwind table entry with an open range
> from the current EH state to an unknown EH state. The state after catching
> is... ???
>
> 9. Popping a catch action closes an open unwind table range
>
>
>
> So, I think the action list is at least not totally crazy. =)
>
>
>
>  I’ll start working on a revised proposal.  Let me know if you have any
> more solid ideas.
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/llvm-dev/attachments/20150129/9f755401/attachment.html>


More information about the llvm-dev mailing list