https://gcc.gnu.org/bugzilla/show_bug.cgi?id=106151

            Bug ID: 106151
           Summary: Inconsistent optimization when defaulting aggregate vs
                    non-aggregate
           Product: gcc
           Version: 12.0
            Status: UNCONFIRMED
          Severity: normal
          Priority: P3
         Component: c++
          Assignee: unassigned at gcc dot gnu.org
          Reporter: barry.revzin at gmail dot com
  Target Milestone: ---

Consider this example:

using size_t = decltype(sizeof(0));

struct string_view {
    // string_view() : ptr(nullptr), len(0) { }
    string_view() = default;

    char const* ptr = nullptr;
    size_t len = 0;
};

struct Fields
{
    string_view a;
    string_view b;
    string_view c;
    string_view d;
    string_view e;
    string_view f;
};

struct Foo : Fields
{
    void clear();

    Foo() = default;
};

void Foo::clear() {
    *this = Foo{};
}

struct Bar : Fields
{
    // No constructor, not even defaulted.

    void clear();
};

void Bar::clear() {
    *this = Bar{};
}


On gcc 12.1 -std=c++20 -O2 -mavx2, this emits:

Foo::clear():
        mov     QWORD PTR [rdi], 0
        mov     QWORD PTR [rdi+8], 0
        mov     QWORD PTR [rdi+16], 0
        mov     QWORD PTR [rdi+24], 0
        mov     QWORD PTR [rdi+32], 0
        mov     QWORD PTR [rdi+40], 0
        mov     QWORD PTR [rdi+48], 0
        mov     QWORD PTR [rdi+56], 0
        mov     QWORD PTR [rdi+64], 0
        mov     QWORD PTR [rdi+72], 0
        mov     QWORD PTR [rdi+80], 0
        mov     QWORD PTR [rdi+88], 0
        ret
Bar::clear():
        mov     ecx, 12
        xor     eax, eax
        rep stosq
        ret

There are a lot of subtle changes you can make to change the generated code:

* if Fields has 3 members or fewer, it's a bunch of mov's either way
* if Fields has 4 or 5 members, Bar::clear uses vmov insead of mov. 
* if Fields has 6+ members, Bar::clear uses stosq
* if Fields has an array of string_view, Foo::clear and Bar::clear are
identical for sizes 2, 3, and >= 9.

If string_view uses the constructor I have commented out (with the member
initializer list, instead of defaulted and using the default member
initializers, then:
* if Fields holds an array of string_view with at least 4 string_views, both
Foo::clear and Bar::clear emit a loop.
* otherwise, it's always a bunch of mov's for both Foo and Bar, regardless of
how many members. 


Feels like something is up here.

Reply via email to