The following test program works fine with current trunk on i686 and x86_64-linux: #include <quadmath.h> #include <stdio.h> int main (void) { char buf[100]; quadmath_snprintf (buf, sizeof buf, "%.60Qg", (__float128) 3.14); puts (buf); } It outputs "3.140000000000000124344978758017532527446746826171875". When compiled and run on MinGW, it gives an incorrect output (on my test system, "1.9163987915738935076000483121420225908698150840344985584492e-4932"). I confirmed with both a native MinGW build (i586-pc-mingw32) and a cross-compiler for i586-pc-mingw32, running on x86_64-apple-darwin11, and running the result under either Wine or a real Windows. The cross-compiler is configured as such: ../../gcc/trunk/configure --target=i586-pc-mingw32 --disable-werror --enable-languages=c,fortran
I don't know if it's related, or two different bugs, but hexadecimal printing has the correct mantissa with a wrong exponent. See below the same testcase compile on my mac (native compiler) and cross-compiled to mingw: $ cat v.c #include <quadmath.h> #include <stdio.h> int main (void) { char buf[100]; quadmath_snprintf (buf, sizeof buf, "%.60Qa", (__float128) 3.14); puts (buf); } $ gcc-4.6 v.c -lquadmath && ./a.out 0x1.91eb851eb851f00000000000000000000000000000000000000000000000p+1 $ ./cross/bin/i586-pc-mingw32-gcc v.c -static -lquadmath $ /opt/wine/bin/wine ./a.exe 0x1.91eb851eb851f00000000000000000000000000000000000000000000000p-5318
The bug is not in the I/O routine, it can be reproduce by this simple self-contained testcase (which doesn't need libquadmath). #include <stdint.h> typedef union { __float128 value; struct { #if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ unsigned negative:1; unsigned exponent:15; uint64_t mant_high:48; uint64_t mant_low:64; #else uint64_t mant_low:64; uint64_t mant_high:48; unsigned exponent:15; unsigned negative:1; #endif } ieee; } ieee854_float128; int main (void) { ieee854_float128 d; d.value = (__float128) 3.14; __builtin_printf ("%u\n", (unsigned) d.ieee.exponent); } On darwin, this program consistently outputs 16384. When cross-compiled to mingw, and run on Windows XP, it consistently outputs 6448. When the same executable is run under Wine on darwin, it outputs inconsistent, wrong values (the last few invocations here show: 4755, 12947, 21139).
Going further: I tried to compare the trees generated by the simple function below: #include <stdint.h> typedef union { __float128 value; struct { #if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ unsigned negative:1; unsigned exponent:15; uint64_t mant_high:48; uint64_t mant_low:64; #else uint64_t mant_low:64; uint64_t mant_high:48; unsigned exponent:15; unsigned negative:1; #endif } ieee; } ieee854_float128; unsigned foo (__float128 x) { ieee854_float128 d; d.value = x; return d.ieee.exponent; } AFAICT, both the original and the optimized tree for darwin and mingw are identical. The assembly code generated for a common arch (-march=core2 -O0) differs: ***** on mingw ***** _foo: pushl %ebp movl %esp, %ebp subl $40, %esp movdqa 8(%ebp), %xmm0 movdqa %xmm0, -40(%ebp) movzwl -24(%ebp), %eax andw $32767, %ax movzwl %ax, %eax leave ret ***** on darwin ***** _foo: pushq %rbp movq %rsp, %rbp movdqa %xmm0, -32(%rbp) movdqa -32(%rbp), %xmm0 movdqa %xmm0, -16(%rbp) movzwl -2(%rbp), %eax andw $32767, %ax movzwl %ax, %eax popq %rbp ret Now, my assembly skills are pretty close to nil, so I can't figure out if the differences are meaningful, and what they mean. I only hope that I got it close enough that someone can, from here, understand where this code generation come from and how to fix it.
The issue is caused by bitfield layout. For mingw targets the -mms-bitfields option is for 4.7 active by default. So the mixture of different sized types in union is leading to this behavior. You can see that result becomes ok, if you are specifying to union/struct the attribute gcc_struct. Cheers, Kai
Suggested patch for this issue ChangeLog * quadmath-imp.h (ieee854_float128): Adjust for ms-bitfield layout. Index: quadmath-imp.h =================================================================== --- quadmath-imp.h (revision 180840) +++ quadmath-imp.h (working copy) @@ -48,6 +48,11 @@ __float128 value; struct +#ifdef __MINGW32__ + /* On mingw targets ms-bitfields option is active by default. + Therefore enforce gnu-bitfield style. */ + __attribute__ ((gcc_struct)) +#endif { #if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ unsigned negative:1; @@ -89,6 +94,10 @@ } words32; struct +#ifdef __MINGW32__ + /* Make sure we are using gnu-style bitfield handling. */ + __attribute__ ((gcc_struct)) +#endif { #if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ unsigned negative:1;
(In reply to comment #4) > So the mixture of different sized types in union is leading to this behavior. > You can see that result becomes ok, if you are specifying to union/struct the > attribute gcc_struct. Indeed, I confirm that your patch fixes the issue (and the original Fortran testcase reported on comp.lang.fortran now works fine). Both Tobias and Jakub (Cc'ed) are libquadmath maintainers and can approve it.
(In reply to comment #5) > ChangeLog > > * quadmath-imp.h (ieee854_float128): Adjust > for ms-bitfield layout. > > +#ifdef __MINGW32__ > + /* On mingw targets ms-bitfields option is active by default. > + Therefore enforce gnu-bitfield style. */ > + __attribute__ ((gcc_struct)) > +#endif The patch looks fine to me - except that I would put an "the" before "ms-bitfields option".
Author: ktietz Date: Mon Nov 7 22:03:51 2011 New Revision: 181125 URL: http://gcc.gnu.org/viewcvs?root=gcc&view=rev&rev=181125 Log: PR target/51007 * quadmath-imp.h (ieee854_float128): Adjust for ms-bitfield layout. Modified: trunk/libquadmath/ChangeLog trunk/libquadmath/quadmath-imp.h
Applied with suggested "the" before ms-bitfield option. Fixed.
Author: bkoz Date: Thu May 31 18:51:27 2012 New Revision: 188076 URL: http://gcc.gnu.org/viewcvs?root=gcc&view=rev&rev=188076 Log: 2012-05-31 Benjamin Kosnik <bkoz@redhat.com> PR libstdc++/51007 * configure.ac: Allow gnu, gnu* variants for --enable-symvers argument. * configure: Regenerated. Modified: trunk/libgfortran/ChangeLog trunk/libgfortran/configure trunk/libgfortran/configure.ac trunk/libquadmath/ChangeLog trunk/libquadmath/configure trunk/libquadmath/configure.ac trunk/libssp/ChangeLog trunk/libssp/configure trunk/libssp/configure.ac