This is an archive of the discontinued LLVM Phabricator instance.

Add eh.begincatch and eh.endcatch intrinsics
ClosedPublic

Authored by andrew.w.kaylor on Feb 3 2015, 6:32 PM.

Details

Summary

This patch adds two new intrinsics, llvm.eh.begincatch and llvm.eh.endcatch, that will be used in the native Windows C++ exception handling implementation and begins the documentation for native Windows exception handling.

These intrinsics are not intended to be generated by any component until the back end code to remove them during the WinEHPrepare pass is complete. In the meantime, I am implementing only lint verification. These intrinsics are not intended to make it through to code generation.

Diff Detail

Repository
rL LLVM

Event Timeline

andrew.w.kaylor retitled this revision from to Add eh.begincatch and eh.endcatch intrinsics.
andrew.w.kaylor updated this object.
andrew.w.kaylor edited the test plan for this revision. (Show Details)
andrew.w.kaylor added reviewers: rnk, rjmccall.
andrew.w.kaylor set the repository for this revision to rL LLVM.
andrew.w.kaylor added a subscriber: Unknown Object (MLST).
rnk edited edge metadata.Feb 4 2015, 11:18 AM

This change is 50% docs and 50% verifier. I'm happy with the docs, but it's not clear to me that we can really have these verifier checks.

docs/ExceptionHandling.rst
328 ↗(On Diff #19297)

"multi"

Would you say this is a two-phase approach? That's how I've always thought of it.

331 ↗(On Diff #19297)

I don't think "unwind handler" is a term used elsewhere in this document. "cleanup" would be consistent with the rest. Can you define the term if you want to use it in this section?

334–335 ↗(On Diff #19297)

maybe "it is necessary to outline these handlers from their original context before code generation"?

338 ↗(On Diff #19297)

I guess the stack pointer is really whatever pointer is established by the Win64 unwind opcodes. If the unwind codes end in .setframe, it's that register plus the specified offset, and otherwise it's the stack pointer. I'm not sure if it's worth writing this down here.

355 ↗(On Diff #19297)

Maybe "... scope, while the runtime" or "and the runtime"? I don't think the second part of the sentence opposes the first.

369–372 ↗(On Diff #19297)

I don't think it's quite clear what's going to be left in the landingpad afterwards. Maybe:

During the WinEHPrepare pass, landingpad code is outlined into handler functions. Only stub landingpad basic blocks are left in the IR. Each landingpad contains a landingpad instruction, a call to @llvm.eh.actions, and an indirectbr to indicate possible catch handler destinations.

Then the bit about what eh.actions holds.

lib/IR/Verifier.cpp
1052–1053 ↗(On Diff #19297)

At a high level, I'm not sure we should be verifying these things. I always try to keep in mind a transform that tries to merge similar basic blocks, like this:

void f() {
  if (b) {
    try {
    } catch (int) {
      g(); g(); g();
    }
  } else {
    g(); g(); g();
  }
}

If we deduplicated the calls to g(), we would end up with a CFG where the begincatch doesn't dominate the endcatch:

g_bb:
  %dst = phi i1 [0, %else], [1, %catch]
  call void @g()
  call void @g()
  call void @g()
  br i1 %dst, label %catch.cont, label %else.cont

Note that the outliner has to leave this bb behind in the parent function, and it will also have to leave behind a call to endcatch which is statically reachable from the entry block. We know after preparation, however, that endcatch is dynamically unreachable, so we could transform it to unreachable and run SimplifyCFG to clean it up.

I agree this is a good check to run on frontend generated, IR, though. Maybe we should move this to the Lint pass? Maybe clang should run the lint pass in asserts mode?

1061 ↗(On Diff #19297)

First, I think it would be clearer to simply hoist this into a static local function. The only state you need is VisitedBlocks.

Second, std::function is more expensive than using auto. std::function will make an unnecessary opaque wrapper class for the lambda, which we don't need.

1068 ↗(On Diff #19297)

I added a predecessors() range-based-for adapter for this.

1071 ↗(On Diff #19297)

You should use a BB worklist. This causes O(n) recursion in the depth of the CFG, which could be large.

I'm happy to move the verification to the lint pass. Its main usefulness is definitely for verifying the output from the front end.

docs/ExceptionHandling.rst
328 ↗(On Diff #19297)

It's certainly reasonable to think of it that way, but the runtime is doing enough behind the curtain that I decided to use this as a sort of hand-waving term. There are essentially two phases that are visible for our purposes, and maybe that's reason enough to describe it that way. I was just thinking of the other things that are going on inside the runtime.

331 ↗(On Diff #19297)

I was thinking that the Microsoft documentation for exception handling (which I should probably link to somewhere) called it an unwind handler, but I just looked and even though the flag is UNW_FLAG_UHANDLER they seem to call it a termination handler. I'll give some thought to how I can best reconcile these things for clarity.

334–335 ↗(On Diff #19297)

OK

338 ↗(On Diff #19297)

I'll take a look and make sure I end up with accurate wording.

355 ↗(On Diff #19297)

This is probably a good reason not to use the term "unwind handler" because it seemed to me like people would be likely to expect the unwind handler to do some unwinding.

369–372 ↗(On Diff #19297)

An example would probably make it clear.

lib/IR/Verifier.cpp
1052–1053 ↗(On Diff #19297)

I see. With a bit of effort I could figure out that the branch was using the phi and make the check work, but I suppose trying to generalize that would take way more code than I can justify for this.

1061 ↗(On Diff #19297)

OK. It seemed like conceptually this was a good place for a lambda, then I had to look up the syntax for making recursion work. I guess I let it get away from me a bit.

1068 ↗(On Diff #19297)

Nice. I'll look that up.

1071 ↗(On Diff #19297)

My thinking was that if the IR is correct we'll find the landing pad within a few blocks and if not then compilation is going to fail anyway, so I just wanted to keep this simple.

andrew.w.kaylor updated this object.
andrew.w.kaylor edited edge metadata.

Updated documentation based on review comments
Moved verification code from Verifier to Lint and revised it based on review comments
Rebased

rnk accepted this revision.Feb 10 2015, 9:52 AM
rnk edited edge metadata.

lgtm

Thanks, sorry I got distracted working on http://reviews.llvm.org/D7520

This revision is now accepted and ready to land.Feb 10 2015, 9:52 AM
This revision was automatically updated to reflect the committed changes.