0

See my example here OR the following c++ & matching assembly

IMPLICIT INLINE

#include <iostream>

int func(int i) 
{
    return i * i;
}

int main(int argc, char *argv[])  {

    auto value = atoi(argv[1]);
    std::cout << func(value);  


    value = atoi(argv[2]);
    std::cout << func(value);  

    return 1;
}

results in

func(int):
  imul edi, edi
  mov eax, edi
  ret
main:
  push rbx
  mov rdi, QWORD PTR [rsi+8]
  mov rbx, rsi
  mov edx, 10
  xor esi, esi
  call strtol
  imul eax, eax
  mov edi, OFFSET FLAT:std::cout
  mov esi, eax
  call std::basic_ostream<char, std::char_traits<char> >::operator<<(int)
  mov rdi, QWORD PTR [rbx+16]
  mov edx, 10
  xor esi, esi
  call strtol
  imul eax, eax
  mov edi, OFFSET FLAT:std::cout
  mov esi, eax
  call std::basic_ostream<char, std::char_traits<char> >::operator<<(int)
  mov eax, 1
  pop rbx
  ret
_GLOBAL__sub_I__Z4funci:
  sub rsp, 8
  mov edi, OFFSET FLAT:std::__ioinit
  call std::ios_base::Init::Init()
  mov edx, OFFSET FLAT:__dso_handle
  mov esi, OFFSET FLAT:std::__ioinit
  mov edi, OFFSET FLAT:std::ios_base::Init::~Init()
  add rsp, 8
  jmp __cxa_atexit

EXPLICIT INLINE

#include <iostream>

inline int func(int i)
{
    return i * i;
}

int main(int argc, char *argv[])  {

    auto value = atoi(argv[1]);
    std::cout << func(value);  


    value = atoi(argv[2]);
    std::cout << func(value);  

    return 1;
}

results in

main:
  push rbx
  mov rdi, QWORD PTR [rsi+8]
  mov rbx, rsi
  mov edx, 10
  xor esi, esi
  call strtol
  imul eax, eax
  mov edi, OFFSET FLAT:std::cout
  mov esi, eax
  call std::basic_ostream<char, std::char_traits<char> >::operator<<(int)
  mov rdi, QWORD PTR [rbx+16]
  mov edx, 10
  xor esi, esi
  call strtol
  imul eax, eax
  mov edi, OFFSET FLAT:std::cout
  mov esi, eax
  call std::basic_ostream<char, std::char_traits<char> >::operator<<(int)
  mov eax, 1
  pop rbx
  ret
_GLOBAL__sub_I_main:
  sub rsp, 8
  mov edi, OFFSET FLAT:std::__ioinit
  call std::ios_base::Init::Init()
  mov edx, OFFSET FLAT:__dso_handle
  mov esi, OFFSET FLAT:std::__ioinit
  mov edi, OFFSET FLAT:std::ios_base::Init::~Init()
  add rsp, 8
  jmp __cxa_atexit

In the example, if the line 5 is commented out, optimisation of the code inlines the function 'func' at the two call sites, but it leaves the assembly of func in the produced binary. However, if 'func' is explicitly inlined, the function does not exist in the output assembly.

Why does the GCC optimiser leave implicitly inlined functions in the compiled assembly, even though the operations of the inlined function are truly inlined with the calling code?

tuskcode
  • 317
  • 2
  • 14
  • post your code here in the question please. If you want our help you should do us the courtesy of making it easy for us. – Richard Hodges Jul 30 '17 at 13:40
  • What about the assembly? The reason I used Godbolt is because it is very easy to demonstrate what is happening.. – tuskcode Jul 30 '17 at 13:42
  • Post code directly in the question. Links to external resources like godbolt are nice extras. There's nothing wrong with posting both a piece of code and a link to it. – n. m. could be an AI Jul 30 '17 at 13:44
  • 2
    `inline` affects linkage, _not_ optimization. See, for example, [this question](https://stackoverflow.com/q/1759300/212858). What you're really asking is why functions with global linkage are emitted out-of-line, even if every actual call is inlined. The answer is probably that it's hard to prove, in general, that every call will be inlined. Certainly you can't prove it till after the optimizer runs, and that's ignoring runtime linkers etc. etc. – Useless Jul 30 '17 at 13:44
  • @Useless - really?! So if the linker was better at optimising, func wouldn't be included in the final assembly? – tuskcode Jul 30 '17 at 14:01

1 Answers1

0

The function would go away entirely if it were marked static. Because it is not currently marked static, it may be referenced by another compilation unit, so it can't be eliminated.

Jonathon Reinhart
  • 132,704
  • 33
  • 254
  • 328