Search code examples
cprintfcompiler-optimizationfputs

Why is `printf("%s", "foo")` not being optimized to `fputs("foo", stdout)`?


So both GCC and Clang are smart enough to optimize printf("%s\n", "foo") to puts("foo") (GCC, Clang). That's good and all.

But when I run this function through Compiler Explorer:

#include <stdio.h>

void foo(void) {
    printf("%s", "foo");
}

Neither GCC nor Clang optimize printf("%s", "foo") to fputs("foo", stdout), which I believe should be identical (since fputs doesn't put the newline like puts) to the printf and faster.

x86-64 GCC 11.1 (link):

.LC0:
        .string "foo"
.LC1:
        .string "%s"
foo:
        mov     esi, OFFSET FLAT:.LC0
        mov     edi, OFFSET FLAT:.LC1
        xor     eax, eax
        jmp     printf

x86-64 Clang 12.0.0 (link):

foo:                                    # @foo
        mov     edi, offset .L.str
        mov     esi, offset .L.str.1
        xor     eax, eax
        jmp     printf                          # TAILCALL
.L.str:
        .asciz  "%s"

.L.str.1:
        .asciz  "foo"

Is there any reason specific reason for no optimization to fputs, or is the compiler not smart enough?


Solution

  • Some very specific situations are optimized, like the one you showed, but it's very superficial, if you add something to your format string, even a space, it immediately discards the puts and goes back to printf.

    I guess that there would be nothing to stop a more broad optimization, my speculation is that, since the performance gains are not that great, further adding more special cases was deemed as not being worth it.

    In my speculation, the lack of fputs optimization would fall in that not being worth it category.

    This old gcc printf optimization document sheds some light on these optimizations, I doubt that it would much different today.

    Specifically:

    2.3 %s\n

    A printf call with the format string %s\n [line 4679-4687] is converted to a puts() call.

     printf("%s\n", "hello world"); // converted to puts("hello world");
    

    2.8 The string not ending with \n

    No optimization if the string is not ending with \n [line 4721-4739].

    2.9 The string ending with \n

    A printf call with a simple format string ending with \n [line 4721-4739] is converted to a puts() call.

     printf("hello world\n"); // converted to puts("hello world");