------- Comment #9 from joseph at codesourcery dot com 2005-11-25 02:51 ------- Subject: Patch for sparc-solaris build failure
This patch fixes some of the problems associated with the use of libcalls for unsigned-to-floating conversions (bug 24998). The underlying problem was that my patch did not allow for targets which defined their own libcall names, referring to functions in libc. It does not address the powerpc64-linux problem (where config/rs6000/ppc64-fp.c needs unsigned functions added); I understand from IRC that someone has an unsubmitted patch for that already. It does not address the arm-netbsdelf problem (__floatsidf in libc), which really needs to be addressed by someone who can test that platform; likewise any other platform with the GNU names in libc. Of the platforms using libcalls to libc, it fixes the issue for SPARC (_Q_utoq specified in the ABI, _Q_ulltoq from the Solaris libc) and PowerPC (_q_utoq in the ABI; for some reason glibc's sysdeps/powerpc/soft-fp/q_utoq.c defines _q_uitoq but this looks like a bug given the ABI and given that the Versions file says _q_utoq). It doesn't fix the issue for ia64-hpux, which I intend to address in a followup patch (the HP-UX libc has _U_Qfcnvxuf_dbl_to_quad for unsigned DImode to TFmode conversion, but nothing for unsigned SImode to TFmode conversion so I'll add a C wrapper). I can't test hppa-hpux right now though the issues are probably similar. In the cases of MIPS and FRV I hope the relevant maintainers can help. The MIPS issue seems only to be with mips16.S which needs implementations of the relevant functions. The FRV issue is that there are trivial C implementations of the form double __uitod (unsigned int a) { return a; } but unlike for the signed functions there is nothing to make the compiler call those names; if the intention was for these functions to use the wrapper around a signed libcall the compiler formerly generated, the right approach (given that this seems to be a soft-float target) might be to remove these trivial implementations and instead treat them just like the signed functions. The tests are much bigger than the rest of the patch, and I hope for the most part more thorough than gcc.c-torture/execute/conversion.c which tests similar things (and gets largely optimized away at higher optimization levels). If one of the included testcases fails on your platform because of undefined references to __floatun*, and it does not have a corresponding undefined reference to the corresponding signed conversion function without "un" in the name, add a note to bug 24998. If it fails for any other reason indicating a bug in GCC, open an appropriate new bug if there isn't one already (I filed bug 25028 for a problem with TImode conversions being broken, shown up by the testcases). Some tests may fail because of external issues: the __float128 tests are XFAILed on x86/x86_64 because they need an external library implementing the TFmode functions (but when the fixes are complete they should work OK on ia64-hpux which has enough functions in libc). I've verified that this patch makes a sparc-sun-solaris2.8 build go beyond where it previously failed, and tested the new testcases for syntax and XFAILs on x86_64-unknown-linux-gnu. OK to commit? 2005-11-25 Joseph S. Myers <[EMAIL PROTECTED]> PR middle-end/24998 * config/rs6000/rs6000.c (rs6000_init_libfuncs): Use _q_utoq for unsigned conversions from SImode to TFmode. * config/sparc/sparc.c (sparc_init_libfuncs): Use _Q_utoq and _Q_ulltoq for unsigned conversions from SImode and DImode to TFmode. testsuite: 2005-11-25 Joseph S. Myers <[EMAIL PROTECTED]> PR middle-end/24998 * gcc.dg/torture/fp-int-convert-float.c, gcc.dg/torture/fp-int-convert-double.c, gcc.dg/torture/fp-int-convert-long-double.c, gcc.dg/torture/fp-int-convert-timode.c, gcc.dg/torture/fp-int-convert-float80.c, gcc.dg/torture/fp-int-convert-float80-timode.c, gcc.dg/torture/fp-int-convert-float128.c, gcc.dg/torture/fp-int-convert-float128-timode.c, gcc.dg/torture/fp-int-convert.h: New files. diff -rupN GCC.orig/gcc/config/rs6000/rs6000.c GCC/gcc/config/rs6000/rs6000.c --- GCC.orig/gcc/config/rs6000/rs6000.c 2005-11-23 14:11:11.000000000 +0000 +++ GCC/gcc/config/rs6000/rs6000.c 2005-11-24 23:34:31.000000000 +0000 @@ -9078,6 +9078,7 @@ rs6000_init_libfuncs (void) set_conv_libfunc (sfix_optab, SImode, TFmode, "_q_qtoi"); set_conv_libfunc (ufix_optab, SImode, TFmode, "_q_qtou"); set_conv_libfunc (sfloat_optab, TFmode, SImode, "_q_itoq"); + set_conv_libfunc (ufloat_optab, TFmode, SImode, "_q_utoq"); } } diff -rupN GCC.orig/gcc/config/sparc/sparc.c GCC/gcc/config/sparc/sparc.c --- GCC.orig/gcc/config/sparc/sparc.c 2005-10-28 23:33:40.000000000 +0000 +++ GCC/gcc/config/sparc/sparc.c 2005-11-24 23:40:27.000000000 +0000 @@ -7707,12 +7707,14 @@ sparc_init_libfuncs (void) set_conv_libfunc (sfix_optab, SImode, TFmode, "_Q_qtoi"); set_conv_libfunc (ufix_optab, SImode, TFmode, "_Q_qtou"); set_conv_libfunc (sfloat_optab, TFmode, SImode, "_Q_itoq"); + set_conv_libfunc (ufloat_optab, TFmode, SImode, "_Q_utoq"); if (DITF_CONVERSION_LIBFUNCS) { set_conv_libfunc (sfix_optab, DImode, TFmode, "_Q_qtoll"); set_conv_libfunc (ufix_optab, DImode, TFmode, "_Q_qtoull"); set_conv_libfunc (sfloat_optab, TFmode, DImode, "_Q_lltoq"); + set_conv_libfunc (ufloat_optab, TFmode, DImode, "_Q_ulltoq"); } if (SUN_CONVERSION_LIBFUNCS) diff -rupN GCC.orig/gcc/testsuite/gcc.dg/torture/fp-int-convert-double.c GCC/gcc/testsuite/gcc.dg/torture/fp-int-convert-double.c --- GCC.orig/gcc/testsuite/gcc.dg/torture/fp-int-convert-double.c 1970-01-01 00:00:00.000000000 +0000 +++ GCC/gcc/testsuite/gcc.dg/torture/fp-int-convert-double.c 2005-11-25 02:27:44.000000000 +0000 @@ -0,0 +1,18 @@ +/* Test floating-point conversions. Standard types and double. */ +/* Origin: Joseph Myers <[EMAIL PROTECTED]> */ +/* { dg-do run } */ +/* { dg-options "" } */ + +#include <float.h> +#include "fp-int-convert.h" + +int +main (void) +{ + TEST_I_F(signed char, unsigned char, double, DBL_MANT_DIG); + TEST_I_F(signed short, unsigned short, double, DBL_MANT_DIG); + TEST_I_F(signed int, unsigned int, double, DBL_MANT_DIG); + TEST_I_F(signed long, unsigned long, double, DBL_MANT_DIG); + TEST_I_F(signed long long, unsigned long long, double, DBL_MANT_DIG); + exit (0); +} diff -rupN GCC.orig/gcc/testsuite/gcc.dg/torture/fp-int-convert-float.c GCC/gcc/testsuite/gcc.dg/torture/fp-int-convert-float.c --- GCC.orig/gcc/testsuite/gcc.dg/torture/fp-int-convert-float.c 1970-01-01 00:00:00.000000000 +0000 +++ GCC/gcc/testsuite/gcc.dg/torture/fp-int-convert-float.c 2005-11-25 02:27:44.000000000 +0000 @@ -0,0 +1,18 @@ +/* Test floating-point conversions. Standard types and float. */ +/* Origin: Joseph Myers <[EMAIL PROTECTED]> */ +/* { dg-do run } */ +/* { dg-options "" } */ + +#include <float.h> +#include "fp-int-convert.h" + +int +main (void) +{ + TEST_I_F(signed char, unsigned char, float, FLT_MANT_DIG); + TEST_I_F(signed short, unsigned short, float, FLT_MANT_DIG); + TEST_I_F(signed int, unsigned int, float, FLT_MANT_DIG); + TEST_I_F(signed long, unsigned long, float, FLT_MANT_DIG); + TEST_I_F(signed long long, unsigned long long, float, FLT_MANT_DIG); + exit (0); +} diff -rupN GCC.orig/gcc/testsuite/gcc.dg/torture/fp-int-convert-float128-timode.c GCC/gcc/testsuite/gcc.dg/torture/fp-int-convert-float128-timode.c --- GCC.orig/gcc/testsuite/gcc.dg/torture/fp-int-convert-float128-timode.c 1970-01-01 00:00:00.000000000 +0000 +++ GCC/gcc/testsuite/gcc.dg/torture/fp-int-convert-float128-timode.c 2005-11-25 02:27:44.000000000 +0000 @@ -0,0 +1,18 @@ +/* Test floating-point conversions. __float128 type with TImode. */ +/* Origin: Joseph Myers <[EMAIL PROTECTED]> */ +/* { dg-do run { target i?86-*-* x86_64-*-* ia64-*-* } } */ +/* { dg-xfail-if "" { i?86-*-* x86_64-*-* } { "*" } { "" } } */ +/* { dg-options "" } */ +/* { dg-options "-mmmx" { target { i?86-*-* && ilp32 } } } */ +/* { dg-options "-mmmx" { target { x86_64-*-* && ilp32 } } } */ + +#include "fp-int-convert.h" + +#define FLOAT128_MANT_DIG 113 + +int +main (void) +{ + TEST_I_F(TItype, UTItype, __float128, FLOAT128_MANT_DIG); + exit (0); +} diff -rupN GCC.orig/gcc/testsuite/gcc.dg/torture/fp-int-convert-float128.c GCC/gcc/testsuite/gcc.dg/torture/fp-int-convert-float128.c --- GCC.orig/gcc/testsuite/gcc.dg/torture/fp-int-convert-float128.c 1970-01-01 00:00:00.000000000 +0000 +++ GCC/gcc/testsuite/gcc.dg/torture/fp-int-convert-float128.c 2005-11-25 02:27:44.000000000 +0000 @@ -0,0 +1,22 @@ +/* Test floating-point conversions. __float128 type. */ +/* Origin: Joseph Myers <[EMAIL PROTECTED]> */ +/* { dg-do run { target i?86-*-* x86_64-*-* ia64-*-* } } */ +/* { dg-xfail-if "" { i?86-*-* x86_64-*-* } { "*" } { "" } } */ +/* { dg-options "" } */ +/* { dg-options "-mmmx" { target { i?86-*-* && ilp32 } } } */ +/* { dg-options "-mmmx" { target { x86_64-*-* && ilp32 } } } */ + +#include "fp-int-convert.h" + +#define FLOAT128_MANT_DIG 113 + +int +main (void) +{ + TEST_I_F(signed char, unsigned char, __float128, FLOAT128_MANT_DIG); + TEST_I_F(signed short, unsigned short, __float128, FLOAT128_MANT_DIG); + TEST_I_F(signed int, unsigned int, __float128, FLOAT128_MANT_DIG); + TEST_I_F(signed long, unsigned long, __float128, FLOAT128_MANT_DIG); + TEST_I_F(signed long long, unsigned long long, __float128, FLOAT128_MANT_DIG); + exit (0); +} diff -rupN GCC.orig/gcc/testsuite/gcc.dg/torture/fp-int-convert-float80-timode.c GCC/gcc/testsuite/gcc.dg/torture/fp-int-convert-float80-timode.c --- GCC.orig/gcc/testsuite/gcc.dg/torture/fp-int-convert-float80-timode.c 1970-01-01 00:00:00.000000000 +0000 +++ GCC/gcc/testsuite/gcc.dg/torture/fp-int-convert-float80-timode.c 2005-11-25 02:27:44.000000000 +0000 @@ -0,0 +1,17 @@ +/* Test floating-point conversions. __float80 type with TImode. */ +/* Origin: Joseph Myers <[EMAIL PROTECTED]> */ +/* { dg-do run { target i?86-*-* x86_64-*-* ia64-*-* } } */ +/* { dg-options "" } */ +/* { dg-options "-mmmx" { target { i?86-*-* && ilp32 } } } */ +/* { dg-options "-mmmx" { target { x86_64-*-* && ilp32 } } } */ + +#include "fp-int-convert.h" + +#define FLOAT80_MANT_DIG 64 + +int +main (void) +{ + TEST_I_F(TItype, UTItype, __float80, FLOAT80_MANT_DIG); + exit (0); +} diff -rupN GCC.orig/gcc/testsuite/gcc.dg/torture/fp-int-convert-float80.c GCC/gcc/testsuite/gcc.dg/torture/fp-int-convert-float80.c --- GCC.orig/gcc/testsuite/gcc.dg/torture/fp-int-convert-float80.c 1970-01-01 00:00:00.000000000 +0000 +++ GCC/gcc/testsuite/gcc.dg/torture/fp-int-convert-float80.c 2005-11-25 02:27:44.000000000 +0000 @@ -0,0 +1,21 @@ +/* Test floating-point conversions. __float80 type. */ +/* Origin: Joseph Myers <[EMAIL PROTECTED]> */ +/* { dg-do run { target i?86-*-* x86_64-*-* ia64-*-* } } */ +/* { dg-options "" } */ +/* { dg-options "-mmmx" { target { i?86-*-* && ilp32 } } } */ +/* { dg-options "-mmmx" { target { x86_64-*-* && ilp32 } } } */ + +#include "fp-int-convert.h" + +#define FLOAT80_MANT_DIG 64 + +int +main (void) +{ + TEST_I_F(signed char, unsigned char, __float80, FLOAT80_MANT_DIG); + TEST_I_F(signed short, unsigned short, __float80, FLOAT80_MANT_DIG); + TEST_I_F(signed int, unsigned int, __float80, FLOAT80_MANT_DIG); + TEST_I_F(signed long, unsigned long, __float80, FLOAT80_MANT_DIG); + TEST_I_F(signed long long, unsigned long long, __float80, FLOAT80_MANT_DIG); + exit (0); +} diff -rupN GCC.orig/gcc/testsuite/gcc.dg/torture/fp-int-convert-long-double.c GCC/gcc/testsuite/gcc.dg/torture/fp-int-convert-long-double.c --- GCC.orig/gcc/testsuite/gcc.dg/torture/fp-int-convert-long-double.c 1970-01-01 00:00:00.000000000 +0000 +++ GCC/gcc/testsuite/gcc.dg/torture/fp-int-convert-long-double.c 2005-11-25 02:27:44.000000000 +0000 @@ -0,0 +1,18 @@ +/* Test floating-point conversions. Standard types and long double. */ +/* Origin: Joseph Myers <[EMAIL PROTECTED]> */ +/* { dg-do run } */ +/* { dg-options "" } */ + +#include <float.h> +#include "fp-int-convert.h" + +int +main (void) +{ + TEST_I_F(signed char, unsigned char, long double, LDBL_MANT_DIG); + TEST_I_F(signed short, unsigned short, long double, LDBL_MANT_DIG); + TEST_I_F(signed int, unsigned int, long double, LDBL_MANT_DIG); + TEST_I_F(signed long, unsigned long, long double, LDBL_MANT_DIG); + TEST_I_F(signed long long, unsigned long long, long double, LDBL_MANT_DIG); + exit (0); +} diff -rupN GCC.orig/gcc/testsuite/gcc.dg/torture/fp-int-convert-timode.c GCC/gcc/testsuite/gcc.dg/torture/fp-int-convert-timode.c --- GCC.orig/gcc/testsuite/gcc.dg/torture/fp-int-convert-timode.c 1970-01-01 00:00:00.000000000 +0000 +++ GCC/gcc/testsuite/gcc.dg/torture/fp-int-convert-timode.c 2005-11-25 02:27:44.000000000 +0000 @@ -0,0 +1,16 @@ +/* Test floating-point conversions. TImode types. */ +/* Origin: Joseph Myers <[EMAIL PROTECTED]> */ +/* { dg-do run { xfail *-*-* } } */ +/* { dg-options "" } */ + +#include <float.h> +#include "fp-int-convert.h" + +int +main (void) +{ + TEST_I_F(TItype, UTItype, float, FLT_MANT_DIG); + TEST_I_F(TItype, UTItype, double, DBL_MANT_DIG); + TEST_I_F(TItype, UTItype, long double, LDBL_MANT_DIG); + exit (0); +} diff -rupN GCC.orig/gcc/testsuite/gcc.dg/torture/fp-int-convert.h GCC/gcc/testsuite/gcc.dg/torture/fp-int-convert.h --- GCC.orig/gcc/testsuite/gcc.dg/torture/fp-int-convert.h 1970-01-01 00:00:00.000000000 +0000 +++ GCC/gcc/testsuite/gcc.dg/torture/fp-int-convert.h 2005-11-25 02:27:44.000000000 +0000 @@ -0,0 +1,89 @@ +/* Test floating-point conversions. */ +/* Origin: Joseph Myers <[EMAIL PROTECTED]> */ + +#include <limits.h> +extern void abort (void); +extern void exit (int); + +/* Not all platforms support TImode integers; logic as in + gcc.dg/titype-1.c. */ +#if defined(__LP64__) && !defined(__hppa__) +typedef int TItype __attribute__ ((mode (TI))); +typedef unsigned int UTItype __attribute__ ((mode (TI))); +#else +typedef long TItype; +typedef unsigned long UTItype; +#endif + +/* TEST_I_F(I, U, F, P) tests conversions between the pair of signed + and unsigned integer types I and U and the floating-point type F, + where P is the binary precision of the floating point type. We + test conversions of the values 0, 1, 0x7...f, 0x8...0, 0xf...f. We + also test conversions of values half way inbetween two + representable values (rounding both ways), just above half way, and + just below half way. */ +#define TEST_I_F(I, U, F, P) \ +do { \ + TEST_I_F_VAL (I, F, (I)0, 1); \ + TEST_I_F_VAL (I, F, (I)1, 1); \ + TEST_I_F_VAL (I, F, (I)(((U)~(U)0) >> 1), P_OK1 (P, I)); \ + TEST_I_F_VAL (I, F, (I)(U)~(((U)~(U)0) >> 1), 1); \ + TEST_I_F_VAL (I, F, (I)(U)~(U)0, P_OK (P, I)); \ + TEST_I_F_VAL (I, F, HVAL0S (P, I), P_OK (P, I)); \ + TEST_I_F_VAL (I, F, HVAL0S (P, I) + 1, P_OK (P, I)); \ + TEST_I_F_VAL (I, F, HVAL0S (P, I) - 1, P_OK (P, I)); \ + TEST_I_F_VAL (I, F, HVAL1S (P, I), P_OK (P, I)); \ + TEST_I_F_VAL (I, F, HVAL1S (P, I) + 1, P_OK (P, I)); \ + TEST_I_F_VAL (I, F, HVAL1S (P, I) - 1, P_OK (P, I)); \ + TEST_I_F_VAL (I, F, -HVAL0S (P, I), P_OK (P, I)); \ + TEST_I_F_VAL (I, F, -HVAL0S (P, I) + 1, P_OK (P, I)); \ + TEST_I_F_VAL (I, F, -HVAL0S (P, I) - 1, P_OK (P, I)); \ + TEST_I_F_VAL (I, F, -HVAL1S (P, I), P_OK (P, I)); \ + TEST_I_F_VAL (I, F, -HVAL1S (P, I) + 1, P_OK (P, I)); \ + TEST_I_F_VAL (I, F, -HVAL1S (P, I) - 1, P_OK (P, I)); \ + TEST_I_F_VAL (U, F, (U)0, 1); \ + TEST_I_F_VAL (U, F, (U)1, 1); \ + TEST_I_F_VAL (U, F, (U)(((U)~(U)0) >> 1), P_OK1 (P, U)); \ + TEST_I_F_VAL (U, F, (U)~(((U)~(U)0) >> 1), 1); \ + TEST_I_F_VAL (U, F, (U)~(U)0, P_OK (P, U)); \ + TEST_I_F_VAL (U, F, HVAL0U (P, U), P_OK (P, U)); \ + TEST_I_F_VAL (U, F, HVAL0U (P, U) + 1, P_OK (P, U)); \ + TEST_I_F_VAL (U, F, HVAL0U (P, U) - 1, P_OK (P, U)); \ + TEST_I_F_VAL (U, F, HVAL1U (P, U), P_OK (P, U)); \ + TEST_I_F_VAL (U, F, HVAL1U (P, U) + 1, P_OK (P, U)); \ + TEST_I_F_VAL (U, F, HVAL1U (P, U) - 1, P_OK (P, U)); \ +} while (0) + +#define P_OK(P, T) ((P) >= sizeof(T) * CHAR_BIT) +#define P_OK1(P, T) ((P) >= sizeof(T) * CHAR_BIT - 1) +#define HVAL0U(P, U) (U)(P_OK (P, U) \ + ? (U)1 \ + : (((U)1 << (sizeof(U) * CHAR_BIT - 1)) \ + + ((U)1 << (sizeof(U) * CHAR_BIT - 1 - P)))) +#define HVAL1U(P, U) (U)(P_OK (P, U) \ + ? (U)1 \ + : (((U)1 << (sizeof(U) * CHAR_BIT - 1)) \ + + ((U)3 << (sizeof(U) * CHAR_BIT - 1 - P)))) +#define HVAL0S(P, S) (S)(P_OK1 (P, S) \ + ? (S)1 \ + : (((S)1 << (sizeof(S) * CHAR_BIT - 2)) \ + + ((S)1 << (sizeof(S) * CHAR_BIT - 2 - P)))) +#define HVAL1S(P, S) (S)(P_OK1 (P, S) \ + ? (S)1 \ + : (((S)1 << (sizeof(S) * CHAR_BIT - 2)) \ + + ((S)3 << (sizeof(S) * CHAR_BIT - 2 - P)))) + +#define TEST_I_F_VAL(IT, FT, VAL, PREC_OK) \ +do { \ + static volatile IT ivin, ivout; \ + static volatile FT fv1, fv2; \ + ivin = (VAL); \ + fv1 = (VAL); \ + fv2 = ivin; \ + ivout = fv2; \ + if (ivin != (VAL) \ + || ((PREC_OK) && ivout != ivin) \ + || ((PREC_OK) && ivout != (VAL)) \ + || fv1 != (VAL) || fv2 != (VAL) || fv1 != fv2) \ + abort (); \ +} while (0) -- http://gcc.gnu.org/bugzilla/show_bug.cgi?id=24998