C ++ `inline` keyword and compiler optimization

I keep hearing that the inline no longer useful as a hint to the modern compiler, but is used to avoid multiple definition errors in a multi-source project.

But today I came across an example that the compiler obeys the keyword.

Without the inline following code

 #include <iostream> using namespace std; void func(const int x){ if(x > 3) cout << "HAHA\n"; else cout << "KKK\n"; } int main(){ func(5); } 

using the g++ -O3 -S a.cpp , generates assembly code with func not nested.

However, if I add the inline keyword before the definition of func , func inserted into main .

Part of the generated assembly code

 .LC0: .string "HAHA\n" .LC1: .string "KKK\n" .text .p2align 4,,15 .globl _Z4funci .type _Z4funci, @function _Z4funci: .LFB975: .cfi_startproc cmpl $3, %edi jg .L6 movl $4, %edx movl $.LC1, %esi movl $_ZSt4cout, %edi jmp _ZSt16__ostream_insertIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_PKS3_l .p2align 4,,10 .p2align 3 main: .LFB976: .cfi_startproc subq $8, %rsp .cfi_def_cfa_offset 16 movl $5, %edi call _Z4funci xorl %eax, %eax addq $8, %rsp .cfi_def_cfa_offset 8 ret .cfi_endproc 

My compiler is gcc 4.8.1 / x86-64.

I suspect that the function may be included in the binding process, but I'm not sure if this will happen, and if so, how can I find out?

My question is why this piece of code seems to contradict modern guidelines, for example When should I write the keyword 'inline' for a function / method?

+4
source share
4 answers

The inline has several effects. One of them is to hint to the compiler that you want the function to be inlined - however this does not mean that the compiler needs to inline it [there is an extension in several compilers that says "inline", whatever, if generally possible ", for example MS __forceinline and gcc __attribute__(always_inline) ].

The inline also allows you to have multiple instances of a function with the same name if the function is built in without getting errors for "multiple definitions of the same function." [But the function must be the same source every time].

In this case, I am a little surprised to see the NOT inline func compiler. However, adding static to func makes it go to the string too. It is so clear that the compiler solves this on the basis of the fact that “some other function can use func too, so we need a copy anyway, and there is no benefit from embedding it. In fact, if you create a static function, and it only called once, even if the function is very large, gcc / g ++ will almost certainly embed it.

If you want the compiler to embed something, it never hurts to add inline . However, in many cases, the compiler will make a decent choice anyway. For example, if I changed the code to this:

 const char* func(const int x){ if(x > 3) return "HAHA\n"; else return "KKK\n"; } int main(){ cout << func(5); } 

it inserts the return "HAHA\n"; part return "HAHA\n"; left over from func .

The compiler logic for solving built-in or non-built-in is complex, and part of them is “how much we get, compared to how much more code space is occupied” - it is likely that the overhead of calling operator<<(ostream& ,const char *) was too much for inliner in this case. Unfortunately, it is not always easy to understand why the compiler makes a certain decision ...

+3
source

Firstly, it is not so black or white. The only absolute effect of the inline is to suppress the ODR rule and avoid multiple definition errors. In addition, the compiler can certainly take the keyword as a hint about embedding, but it may or may not. (And from what I saw, in practice, the compiler ignores this hint of optimization altogether, because most people have no idea how often to embed, or what to do inline, and the compiler can just do it better). But does not have to ignore the prompt.

Secondly, there may well be another reason why the call is associated with the inline , but not without it.

Without the inline a function definition must be exported, since another TU may need to be associated with it. And since we need to export the definition of the function, the code is already there, and the attachment of the call simply means that you have effectively duplicated the body of the function. More general code, larger executable file size, location of command cache.

But with the inline compiler does not need to export the function definition so that it can inline call and completely remove the original definition. Then the total code size does not increase (instead of generating a function definition and a call to it, we simply move the function body to the call site).

As an experiment, try marking the function as static instead of inline . It also means that the compiler should not export the definition, and most likely this will also lead to it deciding what inlining is worth.

+2
source

What you keep hearing is false or should be. The standard clearly indicates the intent of inline : tell the compiler that it would be preferable if the compiler can generate this code in a line. Until compilers can do a better job than a programmer judging when inlay is needed, it takes into account the "hint". Maybe one day, inline will become irrelevant for him (for example, register has become), but we are still far from it.

Having said that, I am very surprised that g ++ is not built into your case. g ++ is usually quite aggressive about nesting, even when a function is not marked inline . Maybe I just thought that since the function was not in the loop, it was not worth the bother.

0
source

Today (in 2018) the inline attribute is still used for optimization. Even in modern compilers.

The claim that they will ignore this and instead rely only on their own cost models is not true, at least in the open-source compilers GCC and Clang. Simon Brand wrote a good blog post (do the compilers take this as a hint? ), Where did he refute this by looking at the source code of the compiler.

But the point is not that these compilers will blindly follow the instructions of the programmer. If they have enough evidence that it will hurt performance, they will reject you.

There are vendor-specific extensions that force-embed even if compilers consider this a bad idea. For example, in Visual Studio this is called __forceinline :

__forceinline word __forceinline redefines cost-benefit analysis and relies on the opinion of the programmer. __forceinline caution when using __forceinline . Indiscriminate use of __forceinline can lead to an increase in code size with a minimal increase in performance or, in some cases, even to __forceinline performance (for example, due to increased swapping of a large executable file).

GCC and Clang call it inline __attribute__ ((__always_inline__)) .

In general, it is recommended that you trust the compiler with the solution, especially if you can use profile optimization . One notable exception to the high-quality codebase that uses forced embedding is Boost (look for BOOST_FORCEINLINE ).

0
source

All Articles