I naively assumed, that the complex number multiplication would be inlined by the compiler, for example for this function:
#include <complex>
void mult(std::complex<double> &a, std::complex<double> &b){
a*=b;
}
However, when complied by gcc (with -O2
), the resulting assembler is surprising (at least for me):
mult(std::complex<double>&, std::complex<double>&):
pushq %rbx
movsd 8(%rdi), %xmm3
movsd (%rdi), %xmm2
movq %rdi, %rbx
movsd 8(%rsi), %xmm1
movsd (%rsi), %xmm0
call __muldc3
movsd %xmm0, (%rbx)
movsd %xmm1, 8(%rbx)
popq %rbx
ret
There is a call to this function __multdc3
, which somehow replaced the call to the operator*=
(its mangled name would be _ZNSt7complexIdEmLIdEERS0_RKS_IT_E
and the complex number would be passed per reference).
However, there seems to be nothing special in the implementation of the operator*=
which would explain the magic:
// 26.2.5/13
// XXX: This is a grammar school implementation.
template<typename _Tp>
template<typename _Up>
complex<_Tp>&
complex<_Tp>::operator*=(const complex<_Up>& __z)
{
const _Tp __r = _M_real * __z.real() - _M_imag * __z.imag();
_M_imag = _M_real * __z.imag() + _M_imag * __z.real();
_M_real = __r;
return *this;
}
I must be missing something, thus my question: What is the reason for the resulting assembler?
See Question&Answers more detail:os