чистая функция, почему нет оптимизации? - PullRequest
1 голос
/ 18 февраля 2020

Я попробовал последние версии g cc (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));
}

и скомпилировал его так:

g++ -ggdb -Ofast -c test.cpp
g++ -ggdb -Ofast -c pure.cpp
g++ -ggdb -Ofast -o test test.o pure.o

в результате я вижу:

    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>

как вы можете видеть, есть два вызова _Z6squarei, но почему? Я пометил функцию как чистую и использую тот же аргумент, почему g cc и clang не могут удалить второй вызов?

1 Ответ

4 голосов
/ 18 февраля 2020

Проблема в том, что 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);
}

Как упоминалось в eerorika, __attribute__((const)) будет работать, потому что добавляет дополнительное ограничение, которое square() может не выполнять читать любое состояние, кроме его входов. См. этот вопрос о разнице между чистым и постоянным.

...