[llvm-dev] Inline function not eventually inlined is removed

Nick Desaulniers via llvm-dev llvm-dev at lists.llvm.org
Mon Aug 9 11:16:19 PDT 2021


On Wed, Aug 4, 2021 at 4:46 AM David Chisnall via llvm-dev
<llvm-dev at lists.llvm.org> wrote:
>
>
> On 02/08/2021 18:05, Mariusz Sikora via llvm-dev wrote:
>  > I'm just trying to understand is this _Code_ undefined behavior or
> this is a bug in LLVM? Because why LLVM is removing functions without
> inlining it? For example GCC is not removing function event after
> inlining it.
>
> C++ `inline` means 'the definition is provided in line with the
> declaration, the compiler and linker are responsible for ensuring that
> exactly one definition exists in the final binary'
>
> C `inline` means 'this definition is provided in line with a declaration
> and may be used by the compiler in preference to one that a linker finds'
>
> C `inline extern` means 'a definition of this may appear in line with
> the declaration but please provide a canonical definition here for when
> the compiler decides not to emit it'
>
> C `inline static` means 'a definition exists here inline and it is not
> an error if this is not used.  If it is, then it is private to this
> compilation unit and it is not an error for the same static function to
> exist in multiple compilation units'.
>
> *None* of these say anything about whether the compiler is required to
> inline the function, but they all specify what must happen to the
> original definition:
>
>   - C++ `inline`: Must exist in at least one compilation unit and the
> linker must discard duplicates.
>   - C `inline`: Must be eliminated
>   - C `inline extern`: must be emitted, the linker should error if two
> definitions of the same inline extern function exist in different
> compilation units.

Also, note that the meaning of `extern inline` changed between C90 and
C99; it's one of the few semantic changes that are drastic changes
that I know of between C standard revisions.  You can get the previous
behavior by either compiling with -std=c89/c90/gnu89, -fgnu89-inline,
or using __attribute__((gnu_inline)) on function definitions.  The
behavior of the prior standard and gnu_inline was to NOT emit any
symbol; a definition was provided only for the purposes of inline
substitution.

We've actually used this in the Linux kernel to provide two
definitions of a function; one in C for inlining, one in assembler to
avoid stack protectors and other compiler instrumentation (such as
coverage and sanitizers), though now we have better constructs for
describing these intents.

>   - C `inline static`: It must be emitted if references to it exist in
> the object code but it may be eliminated if it is unused (including if
> all uses of it are inlined).
>
> Clang is generating IR that makes LLVM do exactly what the language
> semantics require: eliminate the definition.
>
> The `inline` keyword is probably the most confusingly named keyword in
> C/C++, though `static` comes close.  The general rule of thumb for C is:
>
>   - If you think you mean `inline` you probably mean `inline static`.
>   - If you're really sure you mean `inline`, you almost certainly mean
> `__attribute__((always_inline))` or `__forceinline` (depending on
> whether you're writing GNU or Microsoft-flavoured C)

It's also useful to note that always (in always_inline) doesn't mean
always. The machinery handling inline substitution can still bail. Use
-Rpass-missed=inline (or maybe -Rpass-missed=always-inline) to learn
*why*.

>   - If you're not sure but think you might mean `inline`, you really
> mean to be writing C++ and not C.
>
> David

-- 
Thanks,
~Nick Desaulniers


More information about the llvm-dev mailing list