2

In c++, considering a single compilation unit, does the definition of a function has to come above the call(s) to it in order to be inlined, or is it enought that the definition is somewhere in the compilation unit?

In other words, is there any difference between :

class A {
public:
    void f();
};

class B {
    A a;
public:
    void g();
};

inline void A::f() {
    printf("Func'ing A!\n");
}

void B::g() {
    //...
    a.f();
}

and

class A {
public:
    void f();
};

class B {
    A a;
public:
    void g();
};

void B::g() {
    //...
    a.f();
}

inline void A::f() {
    printf("Func'ing A!\n");
}

regarding A::f() being inlined inside B::g() ?

Thanks

elad
  • 349
  • 2
  • 11
  • `inline` keyword is simply a hint, not a guarantee. Good compiler/linker with the right options can optimize code regardless of the keyword. (It will often optimize the code well beyond simple inlining.) – Petr Vepřek Nov 20 '15 at 08:36

2 Answers2

2

I think this is a reasonable question. There are several cases in C++ where order of text in the file does matter. This fortunately is not one of them - your two code samples are equivalent. As covered by Claudio, writing 'inline' in the source makes no difference either way.

Questions of the variety of "does this optimisation happen" are usually compiler dependent, so can best be answered by asking the compiler, for example:

# clang++ -c first.cpp -O3 -S -emit-llvm -o first.ll

; ModuleID = 'first.cpp'
target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
target triple = "x86_64-pc-linux-gnu"

%class.B = type { %class.A }
%class.A = type { i8 }

@str = private unnamed_addr constant [12 x i8] c"Func'ing A!\00"

; Function Attrs: nounwind uwtable
define void @_ZN1B1gEv(%class.B* nocapture readnone %this) #0 align 2 {
  %puts.i = tail call i32 @puts(i8* getelementptr inbounds ([12 x i8]* @str, i64 0, i64 0)) #1
  ret void
}

; Function Attrs: nounwind
declare i32 @puts(i8* nocapture readonly) #1

attributes #0 = { nounwind uwtable "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" }
attributes #1 = { nounwind }

!llvm.ident = !{!0}

!0 = metadata !{metadata !"Debian clang version 3.5.0-10 (tags/RELEASE_350/final) (based on LLVM 3.5.0)"}

Or, if you prefer x86-64,

# clang++ -c first.cpp -O3 -S -o first.s
    .text
    .file   "first.cpp"
    .globl  _ZN1B1gEv
    .align  16, 0x90
    .type   _ZN1B1gEv,@function
_ZN1B1gEv:                              # @_ZN1B1gEv
    .cfi_startproc
# BB#0:
    movl    $.Lstr, %edi
    jmp puts                    # TAILCALL
.Ltmp0:
    .size   _ZN1B1gEv, .Ltmp0-_ZN1B1gEv
    .cfi_endproc

    .type   .Lstr,@object           # @str
    .section    .rodata.str1.1,"aMS",@progbits,1
.Lstr:
    .asciz  "Func'ing A!"
    .size   .Lstr, 12


    .ident  "Debian clang version 3.5.0-10 (tags/RELEASE_350/final) (based on LLVM 3.5.0)"
    .section    ".note.GNU-stack","",@progbits

Both snippets compile to exactly the same intermediate representation with clang 3.5 - most easily verified using a diff tool - so we can be confident that relative position in the source made no difference.

This is actually the case without optimisation as well (using -O0), at least for the compiler I'm using.

Jon Chesterfield
  • 2,251
  • 1
  • 20
  • 30
0

inline is a hint for the compiler, which can choose if actually inlining or not. You may want to have a look at this answer.

Community
  • 1
  • 1
Claudio
  • 10,614
  • 4
  • 31
  • 71
  • 1
    I know that, and am familiar with most of what's writen in the link.. This was a side question regarding ommiting this "suggestion", but the main question is about the ability of the compiler to inline when the definition is not above the call.. – elad Nov 18 '15 at 22:43
  • The compiler is even free to inline functions that you've not declared as inline. – Claudio Nov 18 '15 at 22:59
  • 1
    Again, I know that, that's not the question... =\ – elad Nov 19 '15 at 05:30