4

I have these two simple classes:

#include <type_traits>

struct trivial {
    int m;
};
 
struct non_trivial {
    non_trivial() {}
};

static_assert(std::is_trivial<trivial>::value, "");
static_assert(!std::is_trivial<non_trivial>::value, "");

and I'm measuring compilation time of this simple code with respect to the std::array size, using non_trivial as type:

#include <array>

void foo() {
    std::array<non_trivial, 1000> v;
}

and everything is fine: the compilation time, measured by godbolt, seems to be constant changing the size, and pretty similar between clang 12, GCC 11 and MSVC 19.28. The time is about 800 ms for all the compilers of the test.

But if I add the aggregate initialization to v:

#include <array>

void foo() {
    std::array<non_trivial, 1000> v{};
}

then the compilation time of GCC seems to grow faster than linearly with the size:

  • 1000: 676 ms
  • 2000: 877 ms
  • 4000: 1228 ms
  • 8000: 2083 ms
  • 16000: 5544 ms
  • 32000: 17862 ms

while clang and MSVC compilation times seem not sensitive to the aggregate initialization.

Also, if I replace non_trivial with trivial as array type, the effect has not been detected. The effect seems not to depend on the optimization level used.

According to this question, my two cases should be equivalent because the default initialization of std::array of non-trivial types should invoke the default constructor on all elements, that is exactly the same of an empty aggregate initialization.

It seems to me a bug in the GCC, present in every version supporting at least c++11. Do you have any suggestion about it?

You may find my test here.

Giovanni Cerretani
  • 1,693
  • 1
  • 16
  • 30
  • 2
    Suggestion? Sure. File the bug. – n. m. could be an AI May 06 '21 at 13:15
  • 1
    Kind-of a more minimal example: https://godbolt.org/z/Toj6Y5a54. (BTW, I wouldn't call it a bug. Slow doesn't mean wrong.) – Daniel Langr May 06 '21 at 13:17
  • 3
    I tried with an array of size 16 only. Compiling with GCC `-O0` seems to generate 16 calls to the non trivial constructor, which (I guess) are then optimized away in a later stage using `-O2`. clang instead uses a loop. It looks like GCC is unrolling the loop too early. – chi May 06 '21 at 13:49
  • This is using aggregate initialization, not value initialization. It seems like the array initialization is always unrolled here regardless of size and optimization settings. It's even unrolled with `-Os` which I would consider an optimization bug. It does use a loop if aggregate initialization is not used. https://godbolt.org/z/K7xrTrMez – interjay May 06 '21 at 14:45
  • Updated to aggregate initialization. Thanks @interjay. – Giovanni Cerretani May 06 '21 at 14:50
  • Searching "aggregate initialization" on GCC bugtracker I've found that it has already been reported in 2016 and is not fixed (https://gcc.gnu.org/bugzilla/show_bug.cgi?id=71165). This question is actually a duplicate of https://stackoverflow.com/q/37260097/3287591. – Giovanni Cerretani May 07 '21 at 06:52

0 Answers0