0

Lets have a small class called myClass. I was interested how does look the difference in .asm when method is inlined or not. I made two programs, with and without inline keyword in cpp file, but the .asm output was the same. I know that the inline is just a hint for compiler, and with the high probability I was a victim of an optimization, but is it possible to see the difference on a small cpp example of inlined and not inlined method in asm?

h:

#ifndef CLASS_H
#define CLASS_H

class myClass{
private:
  int a;
public:
  int getA() const;
};

#endif

cpp:

#include <class.h>
inline int myCLass::getA() const{
  return a;
};

main:

#include "class.h"

int main(){
    myClass a;
    a.getA();
    return 0;
}

gcc:

gcc -S -O0 main.cpp

asm output in both cases:

    .section    __TEXT,__text,regular,pure_instructions
    .build_version macos, 10, 14
    .globl  _main                   ## -- Begin function main
    .p2align    4, 0x90
_main:                                  ## @main
    .cfi_startproc
## %bb.0:
    pushq   %rbp
    .cfi_def_cfa_offset 16
    .cfi_offset %rbp, -16
    movq    %rsp, %rbp
    .cfi_def_cfa_register %rbp
    subq    $16, %rsp
    leaq    -8(%rbp), %rdi
    movl    $0, -4(%rbp)
    callq   __ZNK7myClass4getAEv
    xorl    %ecx, %ecx
    movl    %eax, -12(%rbp)         ## 4-byte Spill
    movl    %ecx, %eax
    addq    $16, %rsp
    popq    %rbp
    retq
    .cfi_endproc
                                        ## -- End function

.subsections_via_symbols
wair92
  • 446
  • 11
  • 24
  • 4
    The compiler can ignore the `inline` directive and mostly will do so. The main reason for using `inline` in C++ is to specify linkage, not to tell the compiler what to do. –  Jan 07 '19 at 21:45
  • 1
    You want the gcc-specific `noinline` attribute. https://stackoverflow.com/a/1474050/2945027 – Alex Guteniev Jan 07 '19 at 21:48
  • `inline` in the .cpp file is always wrong. – SergeyA Jan 07 '19 at 21:49
  • @SergeyA nonsense (your *always*). There are many good reasons for `inline`d functions in the .cpp file: those that are not exported (and not part of an interface implemented in that file), mostly living in an anonymous namespace. – Walter Jan 07 '19 at 22:02
  • @Walter if they're in an anonymous namespace they don't need to be marked `inline` as they'll only ever be defined once. – Richard Hodges Jan 08 '19 at 10:26
  • @Walter nonsense, looks like you do not understand the purpose of `inline` keyword. The non-exported functions should either be `static` or defined in anonymous namespace. `inline` keyword does not affect linkage, and as such, doesn't prevent functions from being exported. – SergeyA Jan 08 '19 at 16:27

4 Answers4

3

You didn't give the compiler a chance to inline myClass::getA() (as explained in another answer). To compare inline versus out-of-line methods, compare the usage of getA() and getAlt() in the code below

// file.h    
class myClass
{
    int a=1;
public:
    int getA() const { return a; }   // implicitly inline
    int getAlt() const;
};

// file.cc
#include "file.h"
int myClass::getAlt() const
{ return a; }

// main.cc
#include "file.h"
int main()
{
    myClass x;
    return x.getA() - x.getAlt();
}

You may use full optimizations except inter-procedural optimization (ipo; since that may allow the compiler to even inline myClass::getAlt()).

Walter
  • 44,150
  • 20
  • 113
  • 196
2

For a function to be inlined reliably, the full definition of the function must be available in the translation unit that the call appears in.

Since the definition of myClass::getA() isn't visible to main.c, the function cannot be inlined. It might be inlined in any calls that appeared in myClass.cpp, but you don't have any of those.

To allow this function to be inlined, you will need to declare it as inline in the header file and include its definition, e.g.

class myClass {
  …
  inline int getA() const { return a; }
  …
}
2

The inline keyword has little to do with telling the compiler to inline calls to the function. What inline does is allow the function to be defined inline in a header.

Using the inline keyword in a function definition allows the function to be defined in multiple translation units without violating the One Definition Rule so long as all of the definitions are identical.

Defining a function inline in a header can help the compiler inline calls to the function by allowing the full definition to be visible in multiple translation units, but that's all the inline keyword has to do with inlining calls.

Miles Budnek
  • 28,216
  • 2
  • 35
  • 52
1

gcc -O0 doesn't enable -finline-functions, so even if the functions were in the same file it wouldn't try. See also Why is this C++ wrapper class not being inlined away?. (Don't bother trying to use __attribute__((always_inline)): you'll get inlining, things won't optimize away.

You could get things inlined with gcc -O3 -fwhole-program *.cpp to enable inlining across source files. (Regardless of whether they were declared inline or not, it's just up to the compiler to decide what's best).

The main point of inline is to let the compiler know that it doesn't need to emit a stand-alone definition of a function if it does choose to inline it into all callers. (Because a definition, not just a declaration, of this function will appear in all translation units that use it. So if some other file decides not to inline it, a definition can be emitted there.)

Modern compilers still use their normal heuristics to decide whether it's worth inlining or not. e.g. a large function with multiple callers will probably not be inlined, to avoid code bloat. static tells the compiler that no other translation unit can see the function, so if there's only one caller in this file it will very likely inline there. (If you have a large function, it's a bad idea to make it static inline. You'll get a copy of the definition in each file where it doesn't inline, and too aggressive inlining. For a small function that's probably going to inline everywhere, you should probably still just use inline, not static inline, so in case anything takes the address of the function there will only be one definition shared across all files. inline tells the linker to merge duplicate definitions of a function instead of erroring. This behaviour is one of the more important parts of what inline really does, not the actual hint to the compiler that you want it to inline.)


gcc -fwhole-program (with all the source files on the same command line) gives the compiler enough information to make all these decision itself. It can see if a function only has one caller across the whole program, and inline it instead of creating a stand-alone definition plus arg setup and a call.

gcc -flto allows link-time optimization similar to whole-program, but doesn't require all the .cpp files on the command line at once. Instead it stores GIMPLE code in the .o files and finishes optimizing at link time.

Peter Cordes
  • 328,167
  • 45
  • 605
  • 847