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).