Search code examples
c++compilationinline

C++ How to determine if function has capability for being inlined and actually was?


I have a question about inline functions in C++. I know that similar questions have appeared many times on this. I hope that mine is a little bit different.

I know that when you specify some function to be inline it is just a "suggestion" to the compiler. So in case:

inline int func1()
{
    return 2;
}

Some code later

cout << func1() << endl; // replaced by cout << 2 << endl;

So there is no mystery there, but what about cases like this:

inline int func1()
{
    return 2;
}

inline int func2()
{
    return func1() * 2;
}

inline int func3()
{
    return func2() * func1() * 2;
}

And so on...

Which of these functions have a chance to become inlined, is it benefitial and how to check what compiler actually did?


Solution

  • Which of these functions have a chance to become inlined

    Any and all functions have a chance to become inlined, if the tool(1) doing the inlining has access to the function's definition (= body) ...

    is it benefitial

    ... and deems it beneficial to do so. Nowadays, it's the job of the optimiser to determine where inlining makes sense, and for 99.9% of programs, the best the programmer can do is stay out of the optimiser's way. The remaining few cases are programs like Facebook, where 0.3% of performance loss is a huge regression. In such cases, manual tweaking of optimisations (along with profiling, profiling, and profiling) is the way to go.

    how to check what compiler actually did

    By inspecting the generated assembly. Every compiler has a flag to make it output assembly in "human-readable" format instead of (or in addition to) object files in binary form.


    (1) Normally, this tool is the compiler and inlining happens as part of the compilation step (turning source code into assembly/object files). That is also the only reason why you may be required to use the inline keyword to actually allow a compiler to inline: because the function's definition must be visible in the translation unit (= source file) being compiled, and quite often that means putting the function definition into a header file. Without inline, this would then lead to multiple-definition errors if the header file was included in more than one translation unit.

    Note that compilation is not the only stage when inlining is possible. When you enable Whole-Program Optimisation (also known as Link-Time Code Generation), one more pass of optimisation happens at link time, once all object files are created. At this point, the inline keyword is totally irrelevant, since linking has access to all the function definitions (the binary wouldn't link successfully otherwise). This is therefore the way to get the most benefit from inlining without having to think about it at all when writing code. The downside is time: WPO takes time to run, and for large projcts, can prolong link times to unacceptable levels (I've personally experienced a somewhat pathological case where enabling WPO took a program's link time from 7 minutes to 46).