Reputation: 3612
In C++, the keyword "inline" serves two purposes. First, it allows a definition to appear in multiple translation units. Second, it's a hint to the compiler that a function should be inlined in the compiled code.
My question: in code generated by GCC and Clang/LLVM, does the keyword "inline" have any bearing on whether a function is inlined? If yes, in what situations? Or is the hint completely ignored? Note this is a not a language question, it is a compiler-specific question.
Upvotes: 19
Views: 8362
Reputation: 428
A lot of information can be gathered on this by reading GCC and the LLVM project's code. Here is some information that has been gathered by reading the code directly. (Note: this is not necessarily fully comprehensive and this doesn't list every single way in which inline
affects inlining in every single detail, it's only to give an overview of most of it)
This information was gathered from GCC and and LLVM's current development HEAD as of 2021/11/13, so it might not be up to date in the future.
On GCC's side:
inline
for early-inlining when neither -finline-small-functions
(implied by -O2
) and -finline-functions
(implied by -O2
) are specifiedinline
when trying to inline a function optimized for size when the caller isn't and inlining wouldn't shrink the callerinline
to be slightly better unless they are also under the inline function instructions threshold (i.e. max-inline-insns-auto
, which is explained later) (the code is complicated so I'm being kind of vague here about what exactly it does)inline
will have their "badness" value divided by 8, such that they will be much more likely to be inlined firstmax-inline-insns-auto
in many more cases when the function is not declared inline (although I can see cases where this isn't the case, such as when GCC's heuristics consider that the "speedup seems big", for example): this value is by default 15, whereas the max-inline-insns-single
value is used when inline is specified, and has a default value of 70, which implies that a function declared inline can be inlined when it is up to 4.6 times bigger than GCC would consider for a function not declared inline (note: the previous hyperlink is only the most important example of those limits being used, they are applied in some other places too)inline
and -finline-small-functions is not specified (implied by -O2)inline
functions at all without -finline-functions
(included in -O2
), unless they are very short, in which case it only just requires -finline-short-functions
(included in -O2
)On LLVM's side:
inline
will have the inlinehint
attribute attached to the LLVM bytecode function by Clanginlinehint-threshold
value for inlinehint
functions, which has a default of 325, whereas otherwise it would use other things (such as whether the callsite is hot or cold and other things like that), and if nothing else is found, will use the inlinedefault-threshold
value, which has a default of 225. This value is compared to a heuristic calculated by LLVM which will calculate for each function call how expensive inlining a given function would be, and if this value is smaller than the threshold, the function will be inlined, which means that inlinehint will essentially diminish the cost of inlining a function by ~1.44 as seen by LLVMIn other words, it looks like this is quite the strong hint, on both GCC and Clang.
Upvotes: 11
Reputation: 6866
[Caveat: not a C++/GCC guru] You'll want to read up on inline here.
The extent to which suggestions made by using the inline function specifier are effective (C99 6.7.4).
- GCC will not inline any functions if the -fno-inline option is used or if -O0 is used. Otherwise, GCC may still be unable to inline a function for many reasons; the -Winline option may be used to determine if a function has not been inlined and why not.
So it appears that unless your compiler settings (like -fno-inline
or -O0
) are used, the compiler takes the hint. I can't comment on Clang/LLVM (or GCC really).'
I recommend using -Winline
if this isn't a code-golf question and you need to know what's going on.
Upvotes: 9
Reputation: 136515
An interesting explanation from gcc: An Inline Function is As Fast As a Macro:
Some calls cannot be integrated for various reasons (in particular, calls that precede the function's definition cannot be integrated, and neither can recursive calls within the definition). If there is a nonintegrated call, then the function is compiled to assembler code as usual. The function must also be compiled as usual if the program refers to its address, because that can't be inlined.
Note that certain usages in a function definition can make it unsuitable for inline substitution. Among these usages are: use of varargs, use of alloca, use of variable sized data types (see Variable Length), use of computed goto (see Labels as Values), use of nonlocal goto, and nested functions (see Nested Functions). Using -Winline will warn when a function marked inline could not be substituted, and will give the reason for the failure.
As required by ISO C++, GCC considers member functions defined within the body of a class to be marked inline even if they are not explicitly declared with the inline keyword. You can override this with -fno-default-inline; see Options Controlling C++ Dialect.
GCC does not inline any functions when not optimizing unless you specify the `always_inline' attribute for the function, like this:
/* Prototype. */ inline void foo (const char) __attribute__((always_inline)); The remainder of this section is specific
to GNU C90 inlining.
When an inline function is not static, then the compiler must assume that there may be calls from other source files; since a global symbol can be defined only once in any program, the function must not be defined in the other source files, so the calls therein cannot be integrated. Therefore, a non-static inline function is always compiled on its own in the usual fashion.
If you specify both inline and extern in the function definition, then the definition is used only for inlining. In no case is the function compiled on its own, not even if you refer to its address explicitly. Such an address becomes an external reference, as if you had only declared the function, and had not defined it.
This combination of inline and extern has almost the effect of a macro. The way to use it is to put a function definition in a header file with these keywords, and put another copy of the definition (lacking inline and extern) in a library file. The definition in the header file will cause most calls to the function to be inlined. If any uses of the function remain, they will refer to the single copy in the library.
Upvotes: 7
Reputation: 92381
How strong the hint is depends entirely on the compile options you use. Most compilers have options to do no inlining, only inline those marked 'inline', or use its best judgement and ignore the hints.
The last one probably works best. :-)
Upvotes: 3