sjiamnocna
sjiamnocna

Reputation: 315

Constant folding in G++

I wondered, how far does the constant folding go in G++ compiler?

I know it can fold all these values into one mov command (ASM), but does it work with arrays and another expressions?

constexpr short A = 40;
constexpr short B = 2;
int main (){
        short theAnswer = A + B;
        return 0;
}

moves just the resulting value

movw    $42, -4(%rbp)

But can it do on arrays as well? Like

constexpr short values[2] = [40, 2];
int main (){
        short theAnswer = values[0] + values[1];
        return 0;
}

g++ -S main.cpp


Yes, it did!

movl    $42, -4(%rbp)

I'm not working with CPP often, I'm just interested. Thanks :)

What other optimizations are done with C++ code using G++? And why did it movl instead movw?

Upvotes: 2

Views: 579

Answers (1)

Eldinur the Kolibri
Eldinur the Kolibri

Reputation: 562

String-concatenation for example is also very common when applied to constant folding. Therefore, string literals, such as: "Hello" + " World" might be substituted at compile time with "Hello World". Personally, I think constant folding applied to numeric values is incredibly clever. Look at this code sample:

#include <iostream>

    int main() {
        int x{};
        std::cin >> x;
    
        int y = x * 0;
    
        return 0;
    }

y = 0 is obvious. But the compiler is smart enough to figure it out at compile time (most compilers, g++ anyway)! There is no actual cumbersome arithmetic that happens there (which is great for performance). The value of y "constant folds" to 0. Any other complicated expression that has 0 as a multiplicative operand can be substituted this way. For example: z = 0 * (a+b+c+d+e+f+g+h+i+j+k); As you might imagine, this could even save memory (because in actual fact, none of these variables are used) and so dead-code-optimization could possibly occur (freeing all the resources utilized by theses variables).

Constant folding also occurs for boolean expressions involving constant. Look at this code sample:

if (true || true || false)

This folds to simply this: if(true). At runtime, this is great, because now this expression doesn't have to be evaluated and the code inside the if-clause can just be executed.

Constant folding applies to loop optimization as well. It helps in unrolling loops by evaluating loop-invariant expressions at compile-time, reducing the number of iterations (which is a performance improvement).

A closely related compiler optimization is constant propagation: During constant propagation, the compiler analyzes the program's code and determines if a variable's value is always the same at a particular point in the program. If it can be determined, that the variable is constant, the compiler is able to reduce the amount of memory accesses which leads to more efficient code.

There are many other compiler optimizations done by the C++ compiler and I can only list a few: You could do your own research on them and see what everything does:

  1. Dead code elimination (described above)
  2. Common subexpression elimination (eliminate redundant computations)
  3. Function inlining (also called inline expansion) Moves the code to where it is called from.
  4. Memory Optimization (Memory alignment: improve cache performance)
  5. Strength reduction (replacing expensive operations with cheaper equivalents)

There are quite a bit more, but I have no idea what they do and I leave it up to your own research if you are interested.

You can never be certain though, if the compiler really applies this to your code, unless you try to enforce it by using explicit compiler optimization flags: '-O3'. Using g++ however, every reasonable compiler optimization is supported (because g++ is obviously the best. :^) I hope this helps :)

Upvotes: 2

Related Questions