This is the mail archive of the libstdc++@gcc.gnu.org mailing list for the libstdc++ 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]

[Patch/RFC] libstdc++/20610


Hi,

Fredrik noticed that the code we produce for complex * real is
suboptimal. The primary template for operator*= is:

 template<typename _Tp>
   complex<_Tp>&
   complex<_Tp>::operator*=(const _Tp& __t)
   {
     _M_real *= __t;
     _M_imag *= __t;
     return *this;
   }

whereas the specializations read (f.i., for double):

 inline complex<double>&
 complex<double>::operator*=(double __d)
 {
   _M_value *= __d;
   return *this;
 }

A simple fix for this issue is expanding the latter to:

 inline complex<double>&
 complex<double>::operator*=(double __d)
 {
   __real__ _M_value *= __d;
   __imag__ _M_value *= __d;
   return *this;
 }

To give you an example, the assembly (for -O3 -march=pentium4
-mfpmath=sse) goes from:

_Z1fv:
.LFB1859:
       pushl   %ebp
.LCFI0:
       movl    %esp, %ebp
.LCFI1:
       movsd   b+8, %xmm3
       movsd   b, %xmm2
       movsd   c, %xmm4
       pxor    %xmm5, %xmm5
       movapd  %xmm2, %xmm0
       mulsd   %xmm5, %xmm0
       movapd  %xmm4, %xmm1
       mulsd   %xmm3, %xmm1
       addsd   %xmm1, %xmm0
       movsd   %xmm0, a+8
       mulsd   %xmm4, %xmm2
       mulsd   %xmm5, %xmm3
       subsd   %xmm3, %xmm2
       movsd   %xmm2, a
       popl    %ebp
       ret

to:

_Z1fv:
.LFB1859:
       pushl   %ebp
.LCFI0:
       movl    %esp, %ebp
.LCFI1:
       movsd   b, %xmm0
       movsd   c, %xmm2
       movapd  %xmm2, %xmm1
       mulsd   b+8, %xmm1
       movsd   %xmm1, a+8
       mulsd   %xmm2, %xmm0
       movsd   %xmm0, a
       popl    %ebp
       ret

Indeed, we have also a compiler problem here, because in principle,
for builtin complex types, the compiler should be able to expand
efficiently complex * real, still, while making sure that the issue
is investigated by the middle-end maintainers, the above change
probably cannot hurt (would be 4.0 material).

Comments?

In case, probably we should prepare something similar for
operator/= too.

Tested x86-linux.

Paolo.

////////////////
	PR libstdc++/20610
	* include/std/std_complex.h (operator*=(float), operator*=(double),
	operator*=(long double)): Implement consistently with the primary
	template, splitting real and imaginary parts of this.
diff -urN libstdc++-v3-orig/include/std/std_complex.h libstdc++-v3/include/std/std_complex.h
--- libstdc++-v3-orig/include/std/std_complex.h	2005-03-16 00:38:54.000000000 +0100
+++ libstdc++-v3/include/std/std_complex.h	2005-03-24 11:03:18.000000000 +0100
@@ -1088,7 +1088,8 @@
   inline complex<float>&
   complex<float>::operator*=(float __f)
   {
-    _M_value *= __f;
+    __real__ _M_value *= __f;
+    __imag__ _M_value *= __f;
     return *this;
   }
 
@@ -1241,7 +1242,8 @@
   inline complex<double>&
   complex<double>::operator*=(double __d)
   {
-    _M_value *= __d;
+    __real__ _M_value *= __d;
+    __imag__ _M_value *= __d;
     return *this;
   }
 
@@ -1394,7 +1396,8 @@
   inline complex<long double>&
   complex<long double>::operator*=(long double __r)
   {
-    _M_value *= __r;
+    __real__ _M_value *= __r;
+    __imag__ _M_value *= __r;   
     return *this;
   }
 

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