纯函数,为什么没有优化?

use*_*932 1 c++ gcc clang

我为这样的代码尝试了 gcc (9.2.1) 和 clang (9.0.1) 的最新版本:

//pure.cpp
int square (int x) __attribute__ ((pure));

int square (int x)
{
        return  x * x;
}

//test.cpp
#include <stdio.h>

int square (int x) __attribute__ ((pure));

int main(int argc, char *argv[])
{
        const int same = argc;
        printf("result: %d\n", square(same));
        printf("result2: %d\n", square(same));
}
Run Code Online (Sandbox Code Playgroud)

并像这样编译它:

g++ -ggdb -Ofast -c test.cpp
g++ -ggdb -Ofast -c pure.cpp
g++ -ggdb -Ofast -o test test.o pure.o
Run Code Online (Sandbox Code Playgroud)

结果我看到:

    1043:       e8 58 01 00 00          callq  11a0 <_Z6squarei>
    1048:       48 8d 3d b5 0f 00 00    lea    0xfb5(%rip),%rdi        # 2004 <_IO_stdin_used+0x4>
    104f:       89 c6                   mov    %eax,%esi
    1051:       31 c0                   xor    %eax,%eax
    1053:       e8 d8 ff ff ff          callq  1030 <printf@plt>
        printf("result2: %d\n", square(same));
    1058:       89 ef                   mov    %ebp,%edi
    105a:       e8 41 01 00 00          callq  11a0 <_Z6squarei>
    105f:       48 8d 3d aa 0f 00 00    lea    0xfaa(%rip),%rdi        # 2010 <_IO_stdin_used+0x10>
    1066:       89 c6                   mov    %eax,%esi
    1068:       31 c0                   xor    %eax,%eax
    106a:       e8 c1 ff ff ff          callq  1030 <printf@plt>
Run Code Online (Sandbox Code Playgroud)

正如你所看到的,有两个调用_Z6squarei,但为什么呢?我将函数标记为纯函数,并使用相同的参数,为什么 gcc 和 clang 无法删除第二个调用?

G. *_*pen 5

问题是,虽然square()标记为纯,但printf()不是。因此,编译器不能随意假设调用 后所有状态都相同printf(),因此square()它本身可能会读取不同的状态,从而产生不同的输出。但是,如果您调用square()两次而中间没有任何其他函数调用,应该没问题:

int main(int argc, char *argv[])
{
        const int same = argc;
        int x = square(same);
        int y = square(same);
        printf("result: %d\n", x);
        printf("result2: %d\n", y);
}
Run Code Online (Sandbox Code Playgroud)

正如 eerorika 所提到的,__attribute__((const))它将起作用,因为它增加了进一步的限制,square()除了其输入外,可能无法读取任何状态。请参阅有关 pure 和 const 之间区别的问题