[llvm-dev] [RFC] AlwaysInline codegen

Evgenii Stepanov via llvm-dev llvm-dev at lists.llvm.org
Thu Aug 20 17:19:00 PDT 2015


There is a problem with the handling of alwaysinline functions in
Clang: they are not always inlined. AFAIK, this may only happen when
the caller is in the dead code, but then we don't always successfully
remove all dead code.

Because of this, we may end up emitting an undefined reference for an
"inline __attribute__((always_inline))" function. Libc++ relies on the
compiler never doing that - it has lots of functions in the headers
marked this way and does _not_ export them from libc++.so.

Current implementation in clang emits alwaysinline+inline functions as
available_externally definitions. The inliner is an SCC pass, and as
such it does not process unreachable functions at all. This means that
AlwaysInliner may leave some alwaysinline functions not inlined. If
such function has an available_externally linkage, it is not emitted
into the binary, and all calls to it are emitted as undefined symbol

Some time ago I've made an attempt to add a DCE pass before the
AlwaysInliner pass to fix this. Thst
 (a) caused a big churn in the existing tests
 (b) must be done at -O0 as well, which is probably undesirable and
could inflate compilation time
 (c) feels like patching over a bigger problem.

The following, better, idea was suggested by Chandler Carruth and Richard Smith.

Instead of emitting an available_externally definition for an
alwaysinline function, we emit a pair of
 1. internal alwaysinline definition (let's call it F.inlinefunction -
it demangles nicely)
 2a. A stub F() { musttail call F.inlinefunction }
  -- or --
 2b. A declaration of F.

The frontend ensures that F.inlinefunction is only used for direct
calls, and the stub is used for everything else (taking the address of
the function, really). Declaration (2b) is emitted in the case when
"inline" is meant for inlining only (like __gnu_inline__ and some
other cases).

This way has a number of useful properties that are easy to enforce.
1. alwaysinline functions are always internal
2. AlwaysInliner can be split from normal inliner; it would be a super
simple implementation that would ensure that there are no alwaysinline
functions remaining after it's done.
3. alwaysinline functions must never reach backend and can be rejected
before machine code generation (in SelectionDAG?).

As this changes the semantics of alwaysinline attribute in the IR, we
would need to reserve a new attribute ID, rename the current ID to
legacy_alwaysinline or something similar and only enforce the above
properties on the new attribute.

There is a proposed Clang patch here: http://reviews.llvm.org/D12087
The patch only implements the Clang codegen part of the proposal and
does not do any of the backend improvements.

More information about the llvm-dev mailing list