[llvm-dev] help me understand how nounwind attribute on functions works?

John McCall via llvm-dev llvm-dev at lists.llvm.org
Thu Feb 9 13:06:17 PST 2017


On Thu, Feb 9, 2017 at 1:32 PM, Reid Kleckner <rnk at google.com> wrote:

> I'll defend the LLVM IR representation that was chosen for noexcept. The
> design of LLVM's EH constructs is all about representing EH metadata as
> real instructions with real semantics that normal program transformations
> can analyze. LLVM doesn't have any EH side tables, it's all part of the IR.
> This is a huge design win.
>
> This includes terminating after noexcept. It's a very literal
> implementation: if an exception is thrown from any call site in a noexcept
> function, then we call terminate. This is easy to analyze, and *most*
> importantly, easy to inline. We don't need to reason about wacky function
> attributes conjuring up new calls to target-specific runtime functions
> (i.e. what is std::terminate called on your platform) from the middle-end.
> If we represented noexcept as data or a function attribute, inlining would
> not be a simple matter of chaining return to the invoke/call successor and
> resume to the invoke unwind destination.
>
> For Windows EH, we had to walk some things back to turn some things that
> were code back into data, and by and large that has been a Bad Thing for
> the middle end. It likes code. It's easy for GVN to reason about
> llvm.eh.typeid.for and eliminate duplicate catch clauses. We miss some of
> these optimizations on Windows as a result today.
>
> Considering all that, I really think that the committee made a mistake to
> make throwing through noexcept terminate the program. Making it UB would
> have been fine. We could have done as you suggest, where throwing from a
> non-inlined nounwind function terminates the program as a QoI matter
> without pessimizing inlining of noexcept functions.
>
> The world as it is today kind of sucks. I would say that we should just
> pattern match away our calls to std::terminate in the backend and emit the
> more compact tables, but that is actually a behavior change. It will cause
> cleanups between the thrown exception and the noexcept function to stop
> running. Changing that behavior would require an opt-out mechanism. That's
> not a big deal, but what it really requires is someone who cares. Maybe you
> can be that person. :)
>

I don't mind changing that behavior, and the opt-out mechanism can just be
to use a catch in the source.

The easiest way to do this pattern-matching would be to just allow
landingpad to encode that a handler is a catch-all terminate handler, and
say that the semantics of that allow the handler to not actually be
executed.  We do fairly similar things already with filters, I think.

John.


> ---
>
> On the subject of making LLVM EH more efficient, we should restart
> Amaury's project to move all code only reachable from landingpads to
> .text.cold. It would require emitting more .eh_frame tables for the
> out-of-line cold code, but I think it would be a nice win.
>
> On Thu, Feb 9, 2017 at 9:40 AM, James Y Knight <jyknight at google.com>
> wrote:
>
>> It is my belief that all functions compiled with -fno-exceptions (which
>> is the default for C code, but notably not the ONLY option) *ought to* (for
>> QoI reasons, not a standards requirement) get the equivalent of noexcept
>> behavior. That is: guaranteed to abort if an exception is thrown through it.
>>
>> This doesn't happen now on x86-64, due to the default async unwind tables
>> as you mention. That used to be the case on x86-32...although it seems that
>> async unwind tables are now on by default there too, in some cases.
>>
>> Unfortunately, clang implements noexcept very inefficiently, and so doing
>> that in clang right now would have a huge amount of overhead.
>>
>> Clang implements C++ noexcept by inserting explicit catch code, which
>> then calls terminate. GCC, on the other hand, just sets up the exception
>> table appropriately to make the unwinder itself do that. It would be really
>> good to fix that, but it's my understanding that it'd be somewhat difficult
>> in llvm's current exceptions model.
>>
>>
>> On Thu, Feb 9, 2017 at 12:12 PM, David Chisnall via llvm-dev <
>> llvm-dev at lists.llvm.org> wrote:
>>
>>> On 9 Feb 2017, at 08:41, Reid Kleckner via llvm-dev <
>>> llvm-dev at lists.llvm.org> wrote:
>>> >
>>> > On Wed, Feb 8, 2017 at 5:45 PM, Mehdi Amini <mehdi.amini at apple.com>
>>> wrote:
>>> > What isn’t clear to me still is : why shouldn't this be transitive?
>>> > In the example you’re showing, for a caller of f() in bar, what is the
>>> advantage of knowing that f() is nounwind if it an exception can still be
>>> thrown? What does it allow?
>>> >
>>> > We know an exception cannot unwind out of f. An exception can be
>>> thrown inside something that f calls, but it must be caught before it
>>> unwinds beyond f.
>>>
>>> Why?  With the x86-64 ABI, for example, f is required to emit async
>>> unwind tables.  It has a personality function that knows how to handle
>>> cleanups, but there are none here, so the generic unwinder will happily
>>> unwind through the code.  The only ways to prevent exceptions from being
>>> propagated are to explicitly catch them, or to use something like a C++
>>> exception specifier so that the personality function will explicitly block
>>> exception propagation.
>>>
>>> In this example, given that doThing is not marked as noexcept, we will
>>> emit unwind tables that explicitly allow unwinding through f; however, when
>>> the unwinder tries to unwind into the next stack frame it will find that
>>> there is no unwind record.  Depending on how lazy we are in defining the PC
>>> ranges in the unwind table, this will either cause stack corruption or a
>>> run-time abort from well-formed code.
>>>
>>> David
>>>
>>> _______________________________________________
>>> LLVM Developers mailing list
>>> llvm-dev at lists.llvm.org
>>> http://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-dev
>>>
>>
>>
>


-- 
I suppose you'd like my real thoughts as well.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/llvm-dev/attachments/20170209/60eb4a73/attachment-0001.html>


More information about the llvm-dev mailing list