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

            Bug ID: 119120
           Summary: Unnecessary fld when assigning real or imaginary part
                    of a complex variable
           Product: gcc
           Version: 14.2.1
            Status: UNCONFIRMED
          Severity: normal
          Priority: P3
         Component: c++
          Assignee: unassigned at gcc dot gnu.org
          Reporter: vajdaz at protonmail dot com
  Target Milestone: ---

Following C++ code generates the assembly underneath when compiling with -O0
for x86 architecture (32 bit).

C++ source:

#include <complex>

void foo(const std::complex<double>& z) {
    _Complex double __t;
    __real__ __t = z.real();
    __imag__ __t = z.imag();
}

Generated asm code:

foo(std::complex<double> const&):
        pushl   %ebp
        movl    %esp, %ebp
        subl    $40, %esp
        subl    $12, %esp
        pushl   8(%ebp)
        call    std::complex<double>::real[abi:cxx11]() const
        addl    $16, %esp
        fstpl   -16(%ebp)
        fldl    -24(%ebp)  ; <= here an uninitialized load happens
        fldl    -16(%ebp)
        fstpl   -40(%ebp)
        fstpl   -32(%ebp)
        subl    $12, %esp
        pushl   8(%ebp)
        call    std::complex<double>::imag[abi:cxx11]() const
        addl    $16, %esp
        fstpl   -24(%ebp)
        fldl    -24(%ebp)
        fldl    -16(%ebp)
        fstpl   -40(%ebp)
        fstpl   -32(%ebp)
        nop
        leave
        ret

At the marked position loading of an uninitialized floating point value is done
unnecessarily. This may cause an unintended FPU exception if that value
accidentally is a signaling NaN.

The expected code here would be this one (no unnecessary load/store pairs):

foo(std::complex<double> const&):
        pushl   %ebp
        movl    %esp, %ebp
        subl    $40, %esp
        movl    8(%ebp), %eax
        movl    %eax, (%esp)
        call    std::complex<double>::real() const
        fldl    (%eax)
        fstpl   -24(%ebp)
        movl    8(%ebp), %eax
        movl    %eax, (%esp)
        call    std::complex<double>::imag() const
        fldl    (%eax)
        fstpl   -16(%ebp)
        leave
        ret

And this is the code which is generated by GCC 4.5.3 and earlier. Later GCCs
generate the (in my opinion) wrong code.

This is not an academic problem. The implementation of operator /= of
std::complex has this behavior until GCC 8.5 (inclusive).

Reply via email to