2

Here are some simple tests run on a x86_64 to show assembler code generated when using inline statement :

TEST 1

static inline void
show_text(void)
{
  printf("Hello\n");
}

int main(int argc, char *argv[])
{
  show_text();
  return 0;
}

And assembler :

gcc -O0 -fno-asynchronous-unwind-tables -S -masm=att main.c  && less main.s

        .file   "main.c"
        .text
        .section        .rodata
.LC0:
        .string "Hello"
        .text
        .type   show_text, @function
show_text:
        pushq   %rbp
        movq    %rsp, %rbp
        leaq    .LC0(%rip), %rdi
        call    puts@PLT
        nop
        popq    %rbp
        ret
        .size   show_text, .-show_text
        .globl  main
        .type   main, @function
main:
        pushq   %rbp
        movq    %rsp, %rbp
        subq    $16, %rsp
        movl    %edi, -4(%rbp)
        movq    %rsi, -16(%rbp)
        call    show_text
        movl    $0, %eax
        leave
        ret
        .size   main, .-main
        .ident  "GCC: (GNU) 7.3.1 20180312"
        .section        .note.GNU-stack,"",@progbits

Test 1 result : inline suggestion not taken into account by compiler

Test 2

Same code as test 1, but with -O1 optimization flag

gcc -O1 -fno-asynchronous-unwind-tables -S -masm=att main.c  && less main.s

        .file   "main.c"
        .text
        .section        .rodata.str1.1,"aMS",@progbits,1
.LC0:
        .string "Hello"
        .text
        .globl  main
        .type   main, @function
main:
        subq    $8, %rsp
        leaq    .LC0(%rip), %rdi
        call    puts@PLT
        movl    $0, %eax
        addq    $8, %rsp
        ret
        .size   main, .-main
        .ident  "GCC: (GNU) 7.3.1 20180312"
        .section        .note.GNU-stack,"",@progbits

Test 2 result : no more show_text function defined in assembler

Test 3 show_text not declared as inline, -O1 optimization flag

Test 3 result : no more show_text function defined in assembler, with or without inline : same generated code

Test 4

#include <stdio.h>
static inline void
show_text(void)
{
  printf("Hello\n");
  printf("Hello\n");
  printf("Hello\n");
  printf("Hello\n");
  printf("Hello\n");
  printf("Hello\n");
}

int main(int argc, char *argv[])
{
  show_text();
  show_text();
  return 0;
}

produces :

gcc -O1 -fno-asynchronous-unwind-tables -S -masm=att main.c  && less main.s

       .file   "main.c"
        .text
        .section        .rodata
.LC0:
        .string "Hello"
        .text
        .type   show_text, @function
show_text:
        pushq   %rbp
        movq    %rsp, %rbp
        leaq    .LC0(%rip), %rdi
        call    puts@PLT
        leaq    .LC0(%rip), %rdi
        call    puts@PLT
        leaq    .LC0(%rip), %rdi
        call    puts@PLT
        leaq    .LC0(%rip), %rdi
        call    puts@PLT
        leaq    .LC0(%rip), %rdi
        call    puts@PLT
        leaq    .LC0(%rip), %rdi
        call    puts@PLT
        nop
        popq    %rbp
        ret
        .size   show_text, .-show_text
        .globl  main
        .type   main, @function
main:
        pushq   %rbp
        movq    %rsp, %rbp
        subq    $16, %rsp
        movl    %edi, -4(%rbp)
        movq    %rsi, -16(%rbp)
        call    show_text
        call    show_text
        movl    $0, %eax
        leave
        ret
        .size   main, .-main
        .ident  "GCC: (GNU) 7.3.1 20180312"
        .section        .note.GNU-stack,"",@progbits

Test 4 result : show_text defined in assembler, inline suggestion not taken into account

I understand inline keyword does not force inlining. But for Test 1 results, what can prevent show_text code replacement in main?

So far, I used to inline some small static functions in my C source code. But from these results it seems quite useless. Why should I declare some of my small functions static inline when using some modern compilers (and possibly compiling optimized code)?

rem
  • 1,131
  • 10
  • 15
  • When optimizing, GCC can and does generate inline code instead of calls to (small enough) static functions without the `inline` keyword. In fact, it can even do that for quite big functions if the function is only called once. That's what you're seeing in Test 3. – Jonathan Leffler Jul 18 '18 at 15:29
  • Have you tried higher levels of optimization (`-O2` or `-O3`) for Test 4? Do the results change? – Jonathan Leffler Jul 18 '18 at 15:29
  • Amongst other questions, see: https://stackoverflow.com/questions/7762731/whats-the-difference-between-static-and-static-inline-function, https://stackoverflow.com/questions/6312597/is-inline-without-static-or-extern-ever-useful-in-c99, https://stackoverflow.com/questions/1137575/inline-functions-vs-preprocessor-macros, https://stackoverflow.com/questions/216510/extern-inline. – Jonathan Leffler Jul 18 '18 at 16:03

2 Answers2

0

It is one of those questionable decisions of the C Language Standards people... use of inline does not guarantee a function to be inlined... the keyword only suggests to the compiler that the function could be inlined.

I've had lengthy exchanges on this topic with the ISO WG; this followed a MISRA guideline that requires all inline functions to be declared at module scope using the static keyword. Their logic is that there may be circumstances where the compiler needs to not inline the function... and equally, there may be cases where that non-inlined function needs to have global scope!

IMHO, if a programmer adds the inline keyword, then the suggestion is that they know what they are doing, and that function should be inline.

As you suggest, in its current form, the inline keyword is effectively pointless, unless a compiler treats it seriously.

Andrew
  • 2,046
  • 1
  • 24
  • 37
  • How bizarre. There are places in the Linux Kernel where not honoring inline causes incorrect code generation. – Joshua Jul 18 '18 at 14:16
  • @Joshua: The Linux kernel is not a generic C program. It depends on the GNU C Compiler in places — it won't compile unless the C compiler is compatible with GCC. GCC had `inline` long before standard C did. It's version had different semantics. It now follows the (C99) standard semantics, though, for `inline`. – Jonathan Leffler Jul 18 '18 at 15:26
0

In your first test you disable optimizations. Inlining is an optimization method. Do not expect it to happen.

Also inline keyword doesn't work nowadays as it used to in the past. I'd say it's only purpose is to have functions in headers without having linker errors about duplicated symbols (when more than one cpp file uses such a header).

Let your compiler do its work. Just enable optimizations (including LTO) and do not worry about details.

Michał Walenciak
  • 4,257
  • 4
  • 33
  • 61