Hi, on some platforms, 26_numerics/complex/13450.cc has been failing for some time. I tracked down the problem to the complex pow builtins. Just run (-O0 suffices) the below: #include <cassert> // libstdc++/13450 int main() { __complex__ long double x; __complex__ long double y; __complex__ long double z; __real__ x = -1.0l; __imag__ x = 0.0l; __real__ y = 0.5l; __imag__ y = 0.0l; z = __builtin_cpowl(x, y); assert( __imag__ z > 0.99l && __imag__ z < 1.01l); } Indeed, if I print z inside gdb: $1 = <invalid float value> + 3.6451995318824746025284059336194198e-4951 * I instead of the expected (3.4 is ok): ~0 + 1 * I. Similar problems affect __builtin_cpowf, just let me know and I can prepare a suited testcase. In any case, in order to double check that everything is finally ok, just run the libstdc++ testsuite ;) ...
I don't see anything on powerpc-darwin but I think this might be target related, it might also be related to changes by RTH or zack with respect to XFmode and TFmode. I really doubt that the builtin is broken at all.
Indeed is target related: x86, s390 and ia64 are ok, for instance; x86_64 and powerpc64 (linux) are broken. About powerpc-darwin, according to testresults, 26_numerics/complex/13450.cc doesn't even build! Why?
Earlier versions of darwin (pre Tiger, aka 8.0) don't have the C99 long double math functions (like cpowl). Looks like a TFmode problem.
Ok, thanks for the info. Please note, however, that 13450 includes tests for float, double and long double and, on x86_64, at -O2 at least, also float fails. This is a *critical* blocker for x86_64 and powerpc64, IMO: among other things, the C++ runtime library cannot be used for serious mathematical work.
Hmm this works for me even with the float version, I really suspect that this glibc bug. The tree level looks right: REALPART_EXPR <x> = -1.0e+0; IMAGPART_EXPR <x> = 0.0; REALPART_EXPR <y> = 5.0e-1; IMAGPART_EXPR <y> = 0.0; z = __builtin_cpow (x, y); D.1119 = IMAGPART_EXPR <z>; So does the Assembly on powerpc-darwin: li r5,0 mflr r31 li r6,0 stw r0,8(r1) lis r3,0xbff0 stwu r1,-96(r1) li r4,0 lis r7,0x3fe0 li r8,0 mr r9,r5 mr r10,r6 I wonder if someone broke the ABI.
Looking at the result here: <http://gcc.gnu.org/ml/gcc-testresults/2004-09/msg01231.html>, libstdc++ passes all its tests.
Andrew, we all know that ia64 is OK (see Comment #2): x86_64 and powerpc64 are *broken*, no news :(
In fact, builtins are not directly responsible. This trivial, pure C, testcase: #include <complex.h> #include <stdio.h> int main() { long double complex b, a, r; b = -1; a = 0.5; r = cpowl(b, a); printf("%Lg, %Lg\n", creall(r), cimagl(r)); return 0; } Suffices to show the problem on x86_64: 3.69315e-4664, 0 instead of the expected (3.3 and 3.4 are ok -> *not* a glibc problem!): -2.71051e-20, 1
The problem is broader. For example, the Fortran 95 abs() intrinsic is also broken for x86_64 when compiled with -O1, as illustrated by the following Fortran 95 program (testing on my Opteron box with cvs-20041101 mainline): program cabs implicit none ! Program works if K = 8, breaks if K = 4 integer, parameter :: K = 4 complex(kind=K) :: z, c real(kind=K) :: a1, a2 z = (2.0_K, 3.0_K) ** 2.0_K c = z - (-5.0_K, 12.0_K) a1 = abs(c) a2 = sqrt(aimag(c) ** 2.0_K + real(c) ** 2.0_K) write (*,*) 'z = ', z write (*,*) 'c = ', c write (*,*) 'a1 = ', a1 write (*,*) 'a2 = ', a2 end program cabs Without optimization, I get the expected results: $ gfortran -o runme cabs.f90 $ ./runme z = ( -5.000000 , 12.00000 ) c = ( 0.000000 ,-9.5367432E-07) a1 = 9.5367432E-07 a2 = 9.5367432E-07 With -O1, the program breaks: $ gfortran -O1 -o runme cabs.f90 $ ./runme z = ( -5.000000 , 12.00000 ) c = ( 0.000000 ,-9.5367432E-07) a1 = 13.00000 a2 = 9.5367432E-07 With -O1 *AND* the unfairly maligned -ffast-math, the result is: $ gfortran -O1 -ffast-math -o runme cabs.f90 $ ./runme z = ( -5.000000 , 12.00000 ) c = ( 0.000000 ,-9.5367432E-07) a1 = 9.5367432E-07 a2 = 9.5367432E-07 The ** operation works with all three compiles; the error appears to be in the call to cabsf(). I don't believe the problem is cabsf() itself, because *both* the unoptimized and -O1 versions call cabsf(). Using -ffast-math changes the code substantially, avoiding the optimizer bug. Note that my Pentium 4 system produces correct code, using -march=pentium4 -mfpmath=sse (to correspond with the x86_64's automatic use of SSE). The code is very similar on the two architectures, save that the x86_64 uses the extended registers (and gets abs() wrong, of course). I *think* the wrong arguments are being passed to cabsf() on the x86_64 -- as evidenced by the fact that the "wrong" output is abs(c), as if the embedded subtraction did not exist. This *may* be the same problem as with the cpowl() in your C example -- incorrect arguments as opposed to bas C lib functions. I'm rather burned out tonight, but I thought I'd pass this along. If no one else runs with this, I'll keep going. I'm learning a lot about GCC internals... ;)
Looking at: <http://gcc.gnu.org/ml/gcc-testresults/2004-12/msg00119.html> it looks likes it is only for -m32 case. I think this is a target problem now. As ppc64 is fixed at least according to <http://gcc.gnu.org/ml/gcc-testresults/2004-12/ msg00183.html>.
> Looking at: > <http://gcc.gnu.org/ml/gcc-testresults/2004-12/msg00119.html> > it looks likes it is only for -m32 case. Look better: is the other way 'round: -m32 is ok, 64-bit is broken (I'm 100% sure because often I build --disable-multilib and the failure is always there :(
There does appear to be some form of ABI change on x86_64. When compiling with gcc-3.4.3 the results of cpowl are assumed to be returned on the x87 stack, but when compiling with 4.0.0 (20041205 experimental) the generated code assumes that the floating point results are returned in memory!! I suspect that an internal change in the representation of complex types, has broken platforms with special parameter passing/returning conventions for complex types.
The bug appears between "2004-07-10 00:00" and "2004-07-10 12:00". I hope to reduce it a bit further to pinpoint the offending patch.
Thanks Steven. This bus is really a show stopper, in my opinion.
Narrowed it down to "2004-07-10 00:00" and "2004-07-10 01:00".
This patch caused it: +2004-07-09 Jan Beulich <jbeulich@novell.com> + + * config/i386/i386.c (classify_argument): Treat V1xx modes the same as + their base modes. CTImode, TCmode, and XCmode must be passed in memory. + TFmode (__float128) must be is an SSE/SSEUP pair. V2SImode, V4HImode, + and V8QI are class SSE. All sufficiently small remaining vector modes + must be passed in one or two integer registers. + (ix86_libcall_value): TFmode must be returned in xmm0, XCmode must be + returned in memory. + (bdesc_2arg, ix86_init_mmx_sse_builtins): __builtin_ia32_pmuludq and + __builtin_ia32_pmuludq128 have non-uniform argument and return types + and must thus be handled explicitly. + * config/i386/i386.md (*movdi_1_rex64): Add cases for moving between + MMX and XMM regs. + (movv8qi_internal, movv4hi_internal, movv2si_internal, + movv2sf_internal): Permit moving between MMX and XMM registers (since + MMX areguments and return values are passed in XMM registers). + (sse2_umulsidi3): Correct type and mode.
The patch which caused it was <http://gcc.gnu.org/ml/gcc-patches/2004-07/msg00468.html>. But if I read the patch, this sounds like GCC before 4.0.0 was not implementing the ABI right.
This happens when the ABI is (was) imprecise. Earlier versions did not special case long double complex, but the current version does. Hence I have a patch ready that partly reverses the original change (actually, implements the original behavior for this type in a form slightly closer matching the ABI definition); expecting to submit this later today or tomorrow (currently building/testing). As to the same(?) problem observed with float complex: I doubt the mentioned patch causes this, since behavior for that type wasn't modified by it.
Patch for the x86-64 long double complex part submitted.
Patch here: <http://gcc.gnu.org/ml/gcc-patches/2004-12/msg01223.html>.
Subject: Bug 17603 CVSROOT: /cvs/gcc Module name: gcc Changes by: jbeulich@gcc.gnu.org 2004-12-17 08:54:02 Modified files: gcc : ChangeLog gcc/config/i386: i386.c Log message: 2004-12-17 Jan Beulich <jbeulich@novell.com> PR target/17603 * config/i386/i386.c (enum x86_64_reg_class): Define X86_64_COMPLEX_X87_CLASS. (x86_64_reg_class_names): Add name for X86_64_COMPLEX_X87_CLASS. (merge_classes): Handle X86_64_COMPLEX_X87_CLASS. (classify_argument): XCmode is X86_64_COMPLEX_X87_CLASS. (examine_argument): X86_64_COMPLEX_X87_CLASS requires two registers when dealing with a return value. (construct_container): Handle X86_64_COMPLEX_X87_CLASS. Eliminate impossible case of two X87/X87UP pairs (this now is being expressed by a single COMPLEX_X87). (x86_libcall_value): XCmode gets returned in st0/st1. Patches: http://gcc.gnu.org/cgi-bin/cvsweb.cgi/gcc/gcc/ChangeLog.diff?cvsroot=gcc&r1=2.6866&r2=2.6867 http://gcc.gnu.org/cgi-bin/cvsweb.cgi/gcc/gcc/config/i386/i386.c.diff?cvsroot=gcc&r1=1.754&r2=1.755
Fixed.