user1244932
user1244932

Reputation: 8082

pure function, why there is no optimisation?

I tried recent versions of gcc (9.2.1) and clang (9.0.1) for such code:

//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));
}

and compile it like this:

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

as result I see:

    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>

as you can see there are two calls of _Z6squarei, but why? I marked function as pure, and use the same argument, why gcc and clang can not remove the second call?

Upvotes: 1

Views: 137

Answers (1)

G. Sliepen
G. Sliepen

Reputation: 7973

The problem is that while square() is marked pure, printf() isn't. So the compiler is not free to assume that all state is the same after a call to printf(), and so square() itself might read different state and thus produce different output. However, it should be fine if you call square() twice without any other function call inbetween:

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);
}

As eerorika mentioned, __attribute__((const)) will work because it adds the further restriction that square() may not read any state except its inputs. See this question about the difference between pure and const.

Upvotes: 5

Related Questions