Will compiler unroll "for" loop when iterating a const container?

Viewed 296

In C++11, we can use a much simpler "for" loop when iterating a container like the following:

for (auto i : {1, 2, 3, 4})
    ...;

However, I don't know the efficiency of such code. Specifically:

  • What is the type of {1, 2, 3, 4}? It is an raw array, or converted to other containers such as std::vector?
  • Will compiler unroll the loop?

Update: Suppose we are using -O2, and the codes in the loop are only a few operations. As my case, I want to enumarate four directions UP DOWN LEFT RIGHT and call a function with the direction parameter. I just care if the program can have the best performance.

Thank you very much!

2 Answers

What is the type of {1, 2, 3, 4}?

std::initializer_list will be constructed from that initialiser. That is being iterated. You even need to include <initializer_list> for this to work.

Will compiler unroll the loop?

The language doesn't guarantee loop unrolling. You can find out whether a particular compiler unrolls a particular loop with particular options with particular target CPU by compiling and inspecting the produced assembly.

That said, the number of iterations is known at compile time, and therefore it is possible for the compiler to unroll the entire loop.


Suppose we are using -O2

For what it's worth, -O2 does not enable -funroll-loops. Before you add that option, read its documentation:

-funroll-loops

Unroll loops whose number of iterations can be determined at compile time or upon entry to the loop. -funroll-loops implies -frerun-cse-after-loop. This option makes code larger, and may or may not make it run faster.

In this example, Clang did unroll the loop: https://godbolt.org/z/enKzMh while GCC did not: https://godbolt.org/z/ocfor8

There is no guarantee, but compilers can optimize certain cases, so chances are high that you end up with good code.

For example, that one can be optimized away completely:

#include <initializer_list>

// Type your code here, or load an example.
int sum() {
    int sum = 0;
    for (auto i : {1, 2, 3, 4}) {
        sum += i;
    }
    return sum;
}

int main() {
  return sum();
}

https://godbolt.org/z/racnKf

Compiled with -O3, gcc can deduce that the result of the compuation is 10:

sum():
        mov     eax, 10
        ret
main:
        mov     eax, 10
        ret

In a real world example, the compiler might not be able to optimize it, so you have to verify yourself.

Related