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

            Bug ID: 96945
           Summary: optimizations regression when defaulting copy
                    constructor
           Product: gcc
           Version: 10.2.0
            Status: UNCONFIRMED
          Severity: normal
          Priority: P3
         Component: c++
          Assignee: unassigned at gcc dot gnu.org
          Reporter: federico.kircheis at gmail dot com
  Target Milestone: ---

While toying with a piece of code, I've noticed that the code did not get
optimized as expected.

All snippets where compiled with -O3.

A)
----
#include <vector>
struct c {
};
void foo(){
    std::vector<c> vi = {c(),c(),c()};
}
----

gets compiled to: https://godbolt.org/z/s7YaEf

----
foo():
        sub     rsp, 24
        mov     edi, 3
        call    operator new(unsigned long)
        mov     esi, 3
        mov     rdi, rax
        movzx   eax, WORD PTR [rsp+13]
        mov     WORD PTR [rdi], ax
        movzx   eax, BYTE PTR [rsp+15]
        mov     BYTE PTR [rdi+2], al
        add     rsp, 24
        jmp     operator delete(void*, unsigned long)
----

Adding and defaulting the constructors produces even more optimized code (the
whole vector is optimized out(!): https://godbolt.org/z/E4GT9x

B)
----
#include <vector>
struct c {
    c() = default;
    c(const c&) =default;
    c(c&&) = default;
};
void foo(){
    std::vector<c> vi = {c(),c(),c()};
}
----

----
foo():
        ret
----


Adding and defaulting the constructors, except the move constructor produces
the same code as A): https://godbolt.org/z/ch71fb

B)
----
#include <vector>
struct c {
    c() = default;
    c(const c&) =default;
    c(c&&) = default;
};
void foo(){
    std::vector<c> vi = {c(),c(),c()};
}
----


If the copy or default constructor is implemented and not defaulted, then the
code is optimized as B): https://godbolt.org/z/v8E37b,
https://godbolt.org/z/v3EY69, #include <vector>
struct c {
    c() {};
};
void foo(){
    std::vector<c> vi = {c(),c(),c()};
}

C)
----
#include <vector>
struct c {
    c() = default;
    c(const c&) {};
};
void foo(){
    std::vector<c> vi = {c(),c(),c()};
}
----

D)
----
#include <vector>
struct c {
    c() = default;
    c(const c&) {};
    c(c&&) = default;
};
void foo(){
    std::vector<c> vi = {c(),c(),c()};
}
----

E)

----
#include <vector>
struct c {
    c() {}
};
void foo(){
    std::vector<c> vi = {c(),c(),c()};
}
----



While ideally the code for those cases is equivalent (as c has no state and all
snippets are functionally equivalent), I would have expected the class with
compiler-defined operators have the best codegen, followed by the class with
defaulted operators, and last the class with a non-defaulted implementation.

Strangely all constructor calls of `c` are always optimized away, but depending
how the class is defined g++ does or does not optimize the whole vector away.

Reply via email to