Can noexcept impair performance?

Hi,

I'm asking this question on this list because answering it requires knowledge of compiler internals and it may be of general interest to C++ programmers, so I hope you don't consider it off-topic.

I know that there are situations where a noexcept declaration can improve performance, because such a declaration may enable specialized code paths in library code or additional compiler optimizations.

I wonder whether there are also situations where a noexcept declaration could impair performance. For example, I could imagine that a noexcept declaration might complicate or even suppress inlining if the compiler can't prove that the function code can never throw. Could this happen with Clang?

Thanks in advance for any hint.

Best regards,
   Stephan

Exception specifications can impair performance in two ways:
1. Exception specifications are required to be enforced, so if a noexcept function calls anything that isn't noexcept, the compiler has to emit exception tables and handlers to ensure that std::terminate is called, increasing code size. (GCC-compatible personality functions support an abbreviation for this handler so that, in theory, the compiler need not use an actual landing pad. However, clang does not currently take advantage of this.)
2. When an operator new is noexcept, new expressions are required to check whether the result is null before calling the constructor. This introduces an extra branch on every allocation. Sadly, this applies even to the special global placement operator new.

John.

Dear all,

I would like to ask if there is any way to enforce the use of globals and locals defined in input C code, in generated .ll assembly.

At first glance, it appears that clang-3.2 is not consistent; in some .ll assembly programs, the original symbol table is reduced to newly defined temporaries (%1, %2, etc).
In others it is, and symbol table variables are used and defined as i would expect.

Any help is appreciated.

Best regards
Nikolaos Kavvadias

[...]

I wonder whether there are also situations where a noexcept declaration could impair performance. For example, I could imagine that a noexcept declaration might complicate or even suppress inlining if the compiler can't prove that the function code can never throw. Could this happen with Clang?

Exception specifications can impair performance in two ways:
1. Exception specifications are required to be enforced, so if a noexcept function calls anything that isn't noexcept, the compiler has to emit exception tables and handlers to ensure that std::terminate is called, increasing code size. (GCC-compatible personality functions support an abbreviation for this handler so that, in theory, the compiler need not use an actual landing pad. However, clang does not currently take advantage of this.)

Thank you for the explanation!

Would it be correct to state that it's the job of LLVM's PruneEH pass (which runs before the inliner) to remove the exception handling overhead associated with a function exception specifications if it detects in a bottom-up traversal of the call-graph that the function can not throw an exception?

2. When an operator new is noexcept, new expressions are required to check whether the result is null before calling the constructor. This introduces an extra branch on every allocation. Sadly, this applies even to the special global placement operator new.

Requiring a low-level primitive like placement new to do an implicit null check indeed seems to be unnecessarily inefficient. If you wanted the null check, you could easily perform it yourself before calling placement new.

- Stephan

[...]

I wonder whether there are also situations where a noexcept declaration could impair performance. For example, I could imagine that a noexcept declaration might complicate or even suppress inlining if the compiler can't prove that the function code can never throw. Could this happen with Clang?

Exception specifications can impair performance in two ways:
1. Exception specifications are required to be enforced, so if a noexcept function calls anything that isn't noexcept, the compiler has to emit exception tables and handlers to ensure that std::terminate is called, increasing code size. (GCC-compatible personality functions support an abbreviation for this handler so that, in theory, the compiler need not use an actual landing pad. However, clang does not currently take advantage of this.)

Thank you for the explanation!

Would it be correct to state that it's the job of LLVM's PruneEH pass (which runs before the inliner) to remove the exception handling overhead associated with a function exception specifications if it detects in a bottom-up traversal of the call-graph that the function can not throw an exception?

The frontend makes a simple first pass, but otherwise yes, I think so. I don't know whether PruneEH actually kills off the dead exception handling code, but it's primarily responsible for making it dead.

2. When an operator new is noexcept, new expressions are required to check whether the result is null before calling the constructor. This introduces an extra branch on every allocation. Sadly, this applies even to the special global placement operator new.

Requiring a low-level primitive like placement new to do an implicit null check indeed seems to be unnecessarily inefficient. If you wanted the null check, you could easily perform it yourself before calling placement new.

Alas, that is how the language is specified. In some common cases, of course, we can eliminate the null-check.

John.