Declare a function to be side-effect free

EventHelix
Dec 18, 2018 · 2 min read

C++ is not a functional programming language. Functions causing side-effects is the norm. If a compiler does not see the body of a function, it assumes that the function causes side effects. This can result in missed optimization opportunities.

A missed opportunity for optimization

Consider the following code. Here the main function (for some reason) computes the square of the total number of arguments twice and returns the sum of the squares.

int square(int x);int main(int argc, char *argv[])
{
auto x = square(argc);
auto y = square(argc);
return x+y;
}

Here the compiler does not see the body for the square function so it assumes that the function can cause side effects. The following assembly code shows two calls to the add function.

The compiler could not optimize away the second call, as it cannot assume that the square function does not have side effects.

main:
push rbp
mov ebp, edi
push rbx
sub rsp, 8
call square(int)
mov edi, ebp
mov ebx, eax
call square(int)
add rsp, 8
add eax, ebx
pop rbx
pop rbp
ret

Optimization with the pure function attribute

If there was a way to tell the compiler that a function is pure (i.e. no side-effects), the compiler could use this information to optimize the code.

If we just add the [[gnu::pure]] attribute to the square function, the compiler will assume that the function does not cause side effects.

When a function is declared pure, the compiler will also ensure that:

  • The function does not access or update any global variables.
  • The return value of the function just depends upon the input parameters.
[[gnu::pure]] int square(int x);int main(int argc, char *argv[])
{
auto x = square(argc);
auto y = square(argc);
return x+y;
}

This results in a significant optimization and the compiler can just call the square function once and just double the result — add eax, eax. The pure declaration guarantees that multiple calls to the function with the same parameters will always result in the same return value.

main:
sub rsp, 8
call square(int)
add rsp, 8
add eax, eax
ret

At the time of this writing, the [[gnu::pure]] attribute is supported by GCC and Clang compilers.

Learn more

Jason Turner’s C++ weekly video that forms the basis of this post.

Compiler explorer links for the example presented above:

Software Design

Architecture | Design | Coding

EventHelix

Written by

@EventHelix — 5G | LTE | Networking

Software Design

Architecture | Design | Coding

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch
Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore
Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade