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

            Bug ID: 94293
           Summary: [missed optimization] Useless statements populating
                    local string not removed
           Product: gcc
           Version: 10.0
            Status: UNCONFIRMED
          Severity: normal
          Priority: P3
         Component: c++
          Assignee: unassigned at gcc dot gnu.org
          Reporter: eyalroz at technion dot ac.il
  Target Milestone: ---

(Relevant Godbolt: https://godbolt.org/z/GygbjZ)

This is the first of two apparent bugs manifesting when compiling the following
program:

#include <string>

int bar() {
    struct poor_mans_pair {
        int first;
        std::string second;
    };
    poor_mans_pair p { 
        123, "Hey... no small-string optimization for me please!" };
    return p.first;
}

For x86_64, this would ideally compile into:

bar():
        mov     eax, 123
        ret

but when compiling this  with GCC 10.0.1 20200322 (or GCC 9.x etc.), we get
assembly which calls operator new[](), populates the string, calls operator
delete[](), then returns 123:

bar():
        sub     rsp, 8
        mov     edi, 51
        call    operator new(unsigned long)
        movdqa  xmm0, XMMWORD PTR .LC0[rip]
        mov     esi, 51
        mov     rdi, rax
        movups  XMMWORD PTR [rax], xmm0
        movdqa  xmm0, XMMWORD PTR .LC1[rip]
        movups  XMMWORD PTR [rax+16], xmm0
        movdqa  xmm0, XMMWORD PTR .LC2[rip]
        movups  XMMWORD PTR [rax+32], xmm0
        mov     eax, 8549
        mov     WORD PTR [rdi+48], ax
        mov     BYTE PTR [rdi+50], 0
        call    operator delete(void*, unsigned long)
        mov     eax, 123
        add     rsp, 8
        ret
.LC0:
        .quad   7935393319309894984
        .quad   3273110194895396975
.LC1:
        .quad   8007513861377913971
        .quad   8386118574366356592
.LC2:
        .quad   2338053640980164457
        .quad   8314037903514690925

 This bug report is about the population of the string, i.e. let's ignore the
question of whether any memory should be allocated at all.

g++ should be aware that the string has no visibility outside `bar()` (except
through access using raw arbitrary memory addresses from another while `bar()`
is executing). Also, IANALL, even if the allocation can be considered
observable behavior which needs to be maintained - values at that memory
location, which may transiently be present, do not constitute such behavior.
Why even set those values, therefore, when they are not used? At least these
string constants and population statements should be optimized away, into
something like (hand-written assembly):

bar():
        sub     rsp, 8
        mov     edi, 51
        call    operator new(unsigned long)
        mov     rdi, rax
        mov     esi, 51
        call    operator delete(void*, unsigned long)
        mov     eax, 123
        add     rsp, 8
        ret

Reply via email to