This is the mail archive of the gcc-bugs@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[Bug c++/86276] New: Poor codegen when returning a std::vector


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

            Bug ID: 86276
           Summary: Poor codegen when returning a std::vector
           Product: gcc
           Version: 9.0
            Status: UNCONFIRMED
          Severity: normal
          Priority: P3
         Component: c++
          Assignee: unassigned at gcc dot gnu.org
          Reporter: redbeard0531 at gmail dot com
  Target Milestone: ---

https://godbolt.org/g/aCiuAy

While I'm a bit sad that good() isn't just "ret", I think that the current
rules for allocation elision require something like that codegen.

I'd expect bad() to codegen to roughly the same as good(), but then rather than
calling operator delete, it should store [rax, rax + 1, rax + 22] to the three
qwords starting at the out pointer. Instead, it does things like checking if
the vector pointer it just zeroed is still zero to see if it needs to be
deleted. It also seems to register an exception landing pad (I'm guessing to
cover the operator new call) to handle freeing the vector's memory, even though
it should know it isn't holding any. 

If I had to guess, I'd say the problem is that it thinks the hidden return out
pointer has escaped when it hasn't really until a successful return. I'm pretty
sure nothing in the language allows any way to access the return value before a
function returns like that, but I'm now really curious if I'm wrong. If there
is, is there any way to tell gcc that I promise I'm not doing anything quite
that stupid?

PS- is it helpful to include the code and asm here in addition to the godbolt
links?

#include <vector>
#include <cstdint>

auto good() {
std::vector<uint8_t> something;
something.reserve(22);
something = {0x02};
//return something; Only difference from bad
}


auto bad() {
std::vector<uint8_t> something;
something.reserve(22);
something = {0x02};
return something;
}

good():
        sub     rsp, 8
        mov     edi, 22
        call    operator new(unsigned long)
        mov     BYTE PTR [rax], 2
        mov     rdi, rax
        add     rsp, 8
        jmp     operator delete(void*)
bad():
        push    rbp
        pxor    xmm0, xmm0
        push    rbx
        mov     rbx, rdi
        sub     rsp, 24
        mov     QWORD PTR [rdi+16], 0
        movups  XMMWORD PTR [rdi], xmm0
        mov     edi, 22
        call    operator new(unsigned long)
        mov     rdi, QWORD PTR [rbx]
        test    rdi, rdi
        je      .L5
        mov     QWORD PTR [rsp+8], rax
        call    operator delete(void*)
        mov     rax, QWORD PTR [rsp+8]
.L5:
        mov     BYTE PTR [rax], 2
        lea     rdx, [rax+22]
        mov     QWORD PTR [rbx], rax
        add     rax, 1
        mov     QWORD PTR [rbx+8], rax
        mov     rax, rbx
        mov     QWORD PTR [rbx+16], rdx
        add     rsp, 24
        pop     rbx
        pop     rbp
        ret
        mov     rbp, rax
        jmp     .L6
bad() [clone .cold.25]:
.L6:
        mov     rdi, QWORD PTR [rbx]
        test    rdi, rdi
        je      .L7
        call    operator delete(void*)
.L7:
        mov     rdi, rbp
        call    _Unwind_Resume

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]