GCC 优化标志 -O2 使代码比 -O0 慢得多

Bin*_* Wu 6 optimization gcc x86-64

这是我的代码。

foo()很简单。它将参数与一些字符串一一比较。

main()有点复杂。它只是foo()用不同的字符串调用并计时,3 次。

#include <string.h>
#include <time.h>
#include <stdio.h>
int foo(const char *s)
{
    int r = 0;
    if (strcmp(s, "a11111111") == 0) {
        r = 1;
    } else if (strcmp(s, "b11111111") == 0) {
        r = 2;
    } else if (strcmp(s, "c11111111") == 0) {
        r = 3;
    } else if (strcmp(s, "d11111111") == 0) {
        r = 4;
    } else if (strcmp(s, "e11111111") == 0) {
        r = 5;
    } else if (strcmp(s, "f11111111") == 0) {
        r = 6;
    } else if (strcmp(s, "g11111111") == 0) {
        r = 7;
    }
    return r;
}

int main()
{
    char *ss[] = {
        "a11111111",
        "b11111111",
        "c11111111",
        "d11111111",
        "e11111111",
        "f11111111",
        "g11111111",
        "h11111111",
    };

    int r = 0;
    for (int i = 0; i < 3; i++) {
        clock_t begin = clock();
        for (int j = 0; j < 100000; j++) {
            r = foo(ss[r]);
        }
        printf("%lu\n", clock() - begin);
    }

    return r;
}
Run Code Online (Sandbox Code Playgroud)

结果如下:

$ gcc tmp.c
$ ./a.out
3979
4025
4272
$
$ gcc tmp.c -O2
$ ./a.out
20575
14572
13841
$
Run Code Online (Sandbox Code Playgroud)

如您所见,-O2使代码变慢。为什么?

海湾合作委员会版本: gcc version 5.4.0 20160609 (Ubuntu 5.4.0-6ubuntu1~16.04.12)

提前致谢,

==== 编辑 ====

谢谢@Ville Krumlinde。我制作了另一个代码来测试strcmp。有2个文件:

//// main.c
#include <time.h>
#include <stdio.h>

int x_strcmp(const char *a);

int main()
{
    int r = 0;
    for (int i = 0; i < 3; i++) {
        clock_t begin = clock();
        for (int j = 0; j < 100000; j++) {
            r += x_strcmp("a111111111");
        }
        printf("%lu\n", clock() - begin);
    }

    return r;
}
Run Code Online (Sandbox Code Playgroud)
//// tmps.c
#include <string.h>
int x_strcmp(const char *a)
{
    return strcmp(a, "a11111111");
}
Run Code Online (Sandbox Code Playgroud)

结果:

$ gcc main.c -O2 -c
$
$ gcc tmps.c -c && cc main.o tmps.o -o a.out
$ ./a.out
870
896
857
$
$ gcc tmps.c -c -O2 && cc main.o tmps.o -o a.out
$ ./a.out
6290
5191
6382
$
Run Code Online (Sandbox Code Playgroud)

唯一的区别是-O2编译时有或没有tmps.c。并且标志仍然使代码慢得多。

下面是汇编代码:

#without -O2
x_strcmp:
.LFB0:
        .cfi_startproc
        pushq   %rbp
        .cfi_def_cfa_offset 16
        .cfi_offset 6, -16
        movq    %rsp, %rbp
        .cfi_def_cfa_register 6
        subq    $16, %rsp
        movq    %rdi, -8(%rbp)
        movq    -8(%rbp), %rax
        movl    $.LC0, %esi
        movq    %rax, %rdi
        call    strcmp
        leave
        .cfi_def_cfa 7, 8
        ret
        .cfi_endproc
Run Code Online (Sandbox Code Playgroud)
# with -O2
x_strcmp:
.LFB24:
        .cfi_startproc
        movq    %rdi, %rsi
        movl    $10, %ecx
        movl    $.LC0, %edi
        repz cmpsb
        seta    %al
        setb    %dl
        subl    %edx, %eax
        movsbl  %al, %eax
        ret
        .cfi_endproc
Run Code Online (Sandbox Code Playgroud)