[PATCH] D11097: New EH representation for MSVC compatibility

Philip Reames listmail at philipreames.com
Thu Jul 23 16:59:46 PDT 2015

On 07/22/2015 11:29 PM, David Majnemer wrote:
> On Wed, Jul 22, 2015 at 1:40 PM, Philip Reames 
> <listmail at philipreames.com <mailto:listmail at philipreames.com>> wrote:
>     On 07/21/2015 05:45 PM, Reid Kleckner wrote:
>         rnk added a comment.
>         In http://reviews.llvm.org/D11097#209400, @reames wrote:
>             In http://reviews.llvm.org/D11097#209367, @majnemer wrote:
>                 @reames thinking about it a little more, would you be
>                 happier with `CatchPadInst` instead of
>                 `CatchBlockInst`, etc. and `isEHPad` instead of
>                 `isEHBlock`?
>         I like the pad terminology. The block terminology came about
>         because we're really imbuing some special properties on the
>         whole BasicBlock. Currently the landingpad instruction is the
>         only instruction with the power to make an edge unsplittable,
>         for example. Anyway, `pad` sounds good to me.
>             That would help.  Reusing block causes confusion with the
>             widespread use of "block" to refer to a basic block in the
>             code base.
>             More generally, consistency in the terminology would be a
>             good thing.  Let me lay out my current understanding:
>             - A X-"pad" is a place the exceptional control flow might
>             resume.
>             - A catch is a specific type of "pad" which models a
>             language/ABI level catch clause.  A catch is exception
>             type specific.
>             - A cleanup is a specific type of "pad" which models scope
>             exit without an explicit exception type.
>             - Both catch and cleanup are statically scoped. There's a
>             begin and end construct for each.
>                In this context, what is a terminateblock?  It's
>             clearly a "pad", but why is not just a cleanup?
>         Currently, Clang expresses noexcept() as a catch-all clause
>         that simply calls terminate. This is inefficient for both
>         Itanium and MSVC because both LSDA tables can express noexcept
>         with a single bit. We do it because it makes it possible to
>         inline one noexcept function into another EH scope without
>         teaching the inliner that it should transform some function
>         attribute into LLVM IR that makes some C++ runtime function call.
>         Terminatepad solves this all by keeping data as data, allowing
>         late IR preparation passes to expand the IR into code
>         (catch-all or filter) or leave it alone if it can be encoded
>         in the table.
>     Just to be clear, there's no ABI requirement that a terminate
>     block NOT be a cleanup with a terminate call right?  If so, why
>     can't this be expressed via a late pattern match on the MI level? 
>     If it's "just an optimization", I'm really hesitant to complicate
>     the IR for this corner case.
> We need the ability to only cause termination if the personality feels 
> like the terminatepad is worthy of it. For example, it is possible to 
> have a "throw(int)" exception specification which implies that all 
> exceptions thrown, other than those of type int, should result in 
> program termination.  Implementing this requires knowledge of the 
> current exception's type which we don't have access to as code.  
> However, we can encode this as data in the LSDA table.  Given these 
> constraints, I don't see think this could be encoded as a cleanup.
To make sure I understood the problem correctly, you basically said 
there's not a way to describe a catch which catches all but a given type 
of exception right?

Am I correct in believing that you could encode this as a catch for the 
excluded type which rethrows and a catch-all which calls terminate?  Not 
saying you should; just trying to understand the problem.
>             On the topic of motivation, I still feel like I'm missing
>             a lot.  In particular, it feels like the catchpad,
>             cleanuppad, and terminatepad are really close to what's
>             already described by landingpad(*). I get that you need to
>             prevent merging of catch blocks, but why isn't a single
>             "pad fence" at the end of each clause which is unmergeable
>             solve that problem?
>             - We might end up changing how you describe a catch
>             clause, but the idea is already there.  You do seem to
>             need different arguments then the existing catch clause bits.
>         Yeah, they are the same set of clauses. :) However, with the
>         new instructions, we won't need to do impossibly error-prone
>         pattern matching.
>     I really don't get this statement.  How is a landingpad with a
>     catch clause instruction fundamentally different then a catchpad? 
>     Is it the fact that landingpads w/compatible clauses be merged? 
>     Or is there something more here?
> The landingpad model requires comparing against the selector to 
> determine what should happen next.  We don't have that luxury with our 
> personality routine.

>         How would a "pad fence" statically indicate that after running
>         this cleanup, the next EH action is that catch block over
>         there? Right now we try to figure this out by walking the CFG
>         and trying to find the next conditional branch based on a
>         comparison of the EH selector value. I think the primary
>         failure mode of WinEHPrepare today is that we inline a
>         destructor containing control flow, and then this analysis
>         falls over. I'd rather not have to do dataflow analysis to
>         rediscover this very basic nesting property of the C++ source
>         code.
>     I was picturturing something like this:
>     padfence
>     br label %next
>     The control flow would be separate.  We don't currently allow
>     branches to landingpads, but that seems like a smaller change than
>     adding a bunch of new instructions.
>     We'd also need to prevent splitting the padfence from the end of
>     it's block, but that seems workable.  Doing this gives us one new
>     instruction rather than (catchpadend, catchret, cleanupret).
> Does a padfence prevent other instructions from flowing between itself 
> and the branch?  If it does not, where would such instructions go?  
> They cannot be encoded in the LSDA.
"We'd also need to *prevent splitting the padfence from the end of it's 
block*, but that seems workable."  We already do this for PHIs at the 
other end of the block, so restricting a padfence to be immediately 
before the terminator seems entirely feasible.
>         Essentially, the new instructions are exactly that: a really
>         strong "pad fence" that keeps all the data and control flow
>         transfers that we want to know about grouped together.
>     I get that.  I'm mostly just concerned that we need this many new
>     instructions for one new concept in the IR.
>         http://reviews.llvm.org/D11097

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/llvm-commits/attachments/20150723/12daf605/attachment.html>

More information about the llvm-commits mailing list