diff --git a/gcc/ChangeLog b/gcc/ChangeLog index a59d245124a..a01ee426005 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,13 @@ +2016-04-11 Michael Meissner + + PR target/70381 + * config/rs6000/rs6000.c (rs6000_opt_masks): Disable using the + target attribute and pragma from changing the -mfloat128 + and -mfloat128-hardware options. + + * doc/extend.texi (Additional Floating Types): Document PowerPC + __float128 restrictions. + 2016-04-11 James Greenhalgh PR target/70133 diff --git a/gcc/config/rs6000/rs6000.c b/gcc/config/rs6000/rs6000.c index fd4b7cc5a7e..c63fa06aa1a 100644 --- a/gcc/config/rs6000/rs6000.c +++ b/gcc/config/rs6000/rs6000.c @@ -34381,8 +34381,8 @@ static struct rs6000_opt_mask const rs6000_opt_masks[] = { "dlmzb", OPTION_MASK_DLMZB, false, true }, { "efficient-unaligned-vsx", OPTION_MASK_EFFICIENT_UNALIGNED_VSX, false, true }, - { "float128", OPTION_MASK_FLOAT128, false, true }, - { "float128-hardware", OPTION_MASK_FLOAT128_HW, false, true }, + { "float128", OPTION_MASK_FLOAT128, false, false }, + { "float128-hardware", OPTION_MASK_FLOAT128_HW, false, false }, { "fprnd", OPTION_MASK_FPRND, false, true }, { "hard-dfp", OPTION_MASK_DFP, false, true }, { "htm", OPTION_MASK_HTM, false, true }, diff --git a/gcc/doc/extend.texi b/gcc/doc/extend.texi index 6e2702992c6..a5a8b23df27 100644 --- a/gcc/doc/extend.texi +++ b/gcc/doc/extend.texi @@ -954,9 +954,13 @@ typedef _Complex float __attribute__((mode(TC))) _Complex128; typedef _Complex float __attribute__((mode(XC))) _Complex80; @end smallexample -On PowerPC 64-bit Linux systems there are currently problems in using -the complex @code{__float128} type. When these problems are fixed, -you would use: +In order to use @code{__float128} and @code{__ibm128} on PowerPC Linux +systems, you must use the @option{-mfloat128}. It is expected in +future versions of GCC that @code{__float128} will be enabled +automatically. In addition, there are currently problems in using the +complex @code{__float128} type. When these problems are fixed, you +would use the following syntax to declare @code{_Complex128} to be a +complex @code{__float128} type: @smallexample typedef _Complex float __attribute__((mode(KC))) _Complex128; diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 3a0f142021b..aa5c77c6bc6 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,14 @@ +2016-04-11 Michael Meissner + + PR target/70381 + * gcc.target/powerpc/float128-1.c: New tests to make sure the + __float128 emulator is built and runs. + * gcc.target/powerpc/float128-1.c: Likewise. + + * lib/target-supports.exp (check_ppc_float128_sw_available): + Rework tests for __float128 software and hardware + availability. Fix exit condition to return 0 on success. + 2016-04-11 James Greenhalgh PR target/70133 diff --git a/gcc/testsuite/gcc.target/powerpc/float128-1.c b/gcc/testsuite/gcc.target/powerpc/float128-1.c new file mode 100644 index 00000000000..b8e71ceaaae --- /dev/null +++ b/gcc/testsuite/gcc.target/powerpc/float128-1.c @@ -0,0 +1,147 @@ +/* { dg-do run { target { powerpc*-*-linux* } } } */ +/* { dg-require-effective-target ppc_float128_sw } */ +/* { dg-options "-mcpu=power7 -O2 -mfloat128 -static-libgcc" } */ + +#ifdef DEBUG +#include +#include +#include +#include +#endif + +#if !defined(__FLOAT128__) || !defined(_ARCH_PPC) +static __float128 +pass_through (__float128 x) +{ + return x; +} + +__float128 (*no_optimize) (__float128) = pass_through; +#endif + +#ifdef DEBUG +__attribute__((__noinline__)) +static void +print_f128 (__float128 x) +{ + unsigned sign; + unsigned exponent; + uint64_t mantissa1; + uint64_t mantissa2; + uint64_t upper; + uint64_t lower; + +#if defined(_ARCH_PPC) && defined(__BIG_ENDIAN__) + struct ieee128 { + uint64_t upper; + uint64_t lower; + }; + +#elif (defined(_ARCH_PPC) && defined(__LITTLE_ENDIAN__)) || defined(__x86_64__) + struct ieee128 { + uint64_t lower; + uint64_t upper; + }; + +#else +#error "Unknown system" +#endif + + union { + __float128 f128; + struct ieee128 s128; + } u; + + u.f128 = x; + upper = u.s128.upper; + lower = u.s128.lower; + + sign = (unsigned)((upper >> 63) & 1); + exponent = (unsigned)((upper >> 48) & ((((uint64_t)1) << 16) - 1)); + mantissa1 = (upper & ((((uint64_t)1) << 48) - 1)); + mantissa2 = lower; + + printf ("%c 0x%.4x 0x%.12" PRIx64 " 0x%.16" PRIx64, + sign ? '-' : '+', + exponent, + mantissa1, + mantissa2); +} +#endif + +__attribute__((__noinline__)) +static void +do_test (__float128 expected, __float128 got, const char *name) +{ + int equal_p = (expected == got); + +#ifdef DEBUG + printf ("Test %s, expected: ", name); + print_f128 (expected); + printf (" %5g, got: ", (double) expected); + print_f128 (got); + printf (" %5g, result %s\n", + (double) got, + (equal_p) ? "equal" : "not equal"); +#endif + + if (!equal_p) + __builtin_abort (); +} + + +int +main (void) +{ + __float128 one = 1.0q; + __float128 two = 2.0q; + __float128 three = 3.0q; + __float128 four = 4.0q; + __float128 five = 5.0q; + __float128 add_result = (1.0q + 2.0q); + __float128 mul_result = ((1.0q + 2.0q) * 3.0q); + __float128 div_result = (((1.0q + 2.0q) * 3.0q) / 4.0q); + __float128 sub_result = ((((1.0q + 2.0q) * 3.0q) / 4.0q) - 5.0q); + __float128 neg_result = - sub_result; + __float128 add_xresult; + __float128 mul_xresult; + __float128 div_xresult; + __float128 sub_xresult; + __float128 neg_xresult; + +#if defined(__FLOAT128__) && defined(_ARCH_PPC) + __asm__ (" #prevent constant folding, %x0" : "+wa" (one)); + __asm__ (" #prevent constant folding, %x0" : "+wa" (two)); + __asm__ (" #prevent constant folding, %x0" : "+wa" (three)); + __asm__ (" #prevent constant folding, %x0" : "+wa" (four)); + __asm__ (" #prevent constant folding, %x0" : "+wa" (five)); + +#else + one = no_optimize (one); + two = no_optimize (two); + three = no_optimize (three); + four = no_optimize (four); + five = no_optimize (five); +#endif + + add_xresult = (one + two); + do_test (add_result, add_xresult, "add"); + + mul_xresult = add_xresult * three; + do_test (mul_result, mul_xresult, "mul"); + + div_xresult = mul_xresult / four; + do_test (div_result, div_xresult, "div"); + + sub_xresult = div_xresult - five; + do_test (sub_result, sub_xresult, "sub"); + + neg_xresult = - sub_xresult; + do_test (neg_result, neg_xresult, "neg"); + +#ifdef DEBUG + printf ("Passed\n"); +#endif + + return 0; +} diff --git a/gcc/testsuite/gcc.target/powerpc/float128-2.c b/gcc/testsuite/gcc.target/powerpc/float128-2.c new file mode 100644 index 00000000000..f517686bd25 --- /dev/null +++ b/gcc/testsuite/gcc.target/powerpc/float128-2.c @@ -0,0 +1,226 @@ +/* { dg-do run { target { powerpc*-*-linux* } } } */ +/* { dg-require-effective-target ppc_float128_sw } */ +/* { dg-options "-mcpu=power7 -O2 -mfloat128 -static-libgcc" } */ + +/* + * Test program to make sure we are getting more precision than the 53 bits we + * get with IEEE double. + */ + +#include +#include +#include +#include + +#ifndef TYPE +#define TYPE __float128 +#endif + +#ifndef NO_INLINE +#define NO_INLINE __attribute__((__noinline__)) +#endif + +static TYPE power_of_two (ssize_t) NO_INLINE; +static TYPE calc1 (TYPE) NO_INLINE; +static TYPE calc2 (TYPE) NO_INLINE; +static TYPE calc3 (TYPE) NO_INLINE; + +#ifndef POWER2 +#define POWER2 60 +#endif + + +/* + * Print TYPE in hex. + */ + + +#if defined(DEBUG) || defined(DEBUG2) +static void print_hex (const char *prefix, TYPE, const char *suffix) NO_INLINE; + +#if defined (__i386__) || defined (__x86_64__) || defined (__LITTLE_ENDIAN__) +#define ENDIAN_REVERSE(N, MAX) ((MAX) - 1 - (N)) + +#else +#define ENDIAN_REVERSE(N, MAX) (N) +#endif + +static void +print_hex (const char *prefix, TYPE value, const char *suffix) +{ + union { + TYPE f128; + unsigned char uc[sizeof (TYPE)]; + } u; + + size_t i; + + u.f128 = value; + printf ("%s0x", prefix); + for (i = 0; i < sizeof (TYPE); i++) + printf ("%.2x", u.uc[ ENDIAN_REVERSE (i, sizeof (TYPE)) ]); + + printf (", %24.2Lf%s", (long double)value, suffix); +} +#endif + + +/* + * Return a power of two. + */ + +static TYPE +power_of_two (ssize_t num) +{ + TYPE ret = (TYPE) 1.0; + ssize_t i; + + if (num >= 0) + { + for (i = 0; i < num; i++) + ret *= (TYPE) 2.0; + } + else + { + ssize_t num2 = -num; + for (i = 0; i < num2; i++) + ret /= (TYPE) 2.0; + } + +#ifdef DEBUG + printf ("power_of_two (%2ld) = ", (long) num); + print_hex ("", ret, "\n"); +#endif + + return ret; +} + + +#ifdef ADDSUB +static TYPE add (TYPE a, TYPE b) NO_INLINE; +static TYPE sub (TYPE a, TYPE b) NO_INLINE; + +static TYPE +add (TYPE a, TYPE b) +{ + TYPE c; +#ifdef DEBUG + print_hex ("add, arg1 = ", a, "\n"); + print_hex ("add, arg2 = ", b, "\n"); +#endif + c = a + b; +#ifdef DEBUG + print_hex ("add, result = ", c, "\n"); +#endif + return c; +} + +static TYPE +sub (TYPE a, TYPE b) +{ + TYPE c; +#ifdef DEBUG + print_hex ("sub, arg1 = ", a, "\n"); + print_hex ("sub, arg2 = ", b, "\n"); +#endif + c = a - b; +#ifdef DEBUG + print_hex ("sub, result = ", c, "\n"); +#endif + return c; +} + +#else +#define add(x, y) ((x) + (y)) +#define sub(x, y) ((x) - (y)) +#endif + +/* + * Various calculations. Add in 2**POWER2, and subtract 2**(POWER2-1) twice, and we should + * get the original value. + */ + +static TYPE +calc1 (TYPE num) +{ + TYPE num2 = add (power_of_two (POWER2), num); + TYPE ret; + +#ifdef DEBUG + print_hex ("calc1 (before call) = ", num2, "\n"); +#endif + + ret = calc2 (num2); + +#ifdef DEBUG + print_hex ("calc1 (after call) = ", ret, "\n"); +#endif + + return ret; +} + +static TYPE +calc2 (TYPE num) +{ + TYPE num2 = sub (num, power_of_two (POWER2-1)); + TYPE ret; + +#ifdef DEBUG + print_hex ("calc2 (before call) = ", num2, "\n"); +#endif + + ret = calc3 (num2); + +#ifdef DEBUG + print_hex ("calc2 (after call) = ", ret, "\n"); +#endif + + return ret; +} + +static TYPE +calc3 (TYPE num) +{ + TYPE ret = sub (num, (((TYPE) 2.0) * power_of_two (POWER2-2))); + +#ifdef DEBUG + print_hex ("calc3 = ", ret, "\n"); +#endif + + return ret; +} + + +int +main (void) +{ + TYPE input, output; + +#ifdef DEBUG + printf ("Testing, %ld bytes\n", (long) sizeof (TYPE)); +#endif + + input = power_of_two (-1); + if ((double)input != 0.5) + { +#if defined(DEBUG) || defined(DEBUG2) + print_hex ("Input should be 0.5: ", output, "\n"); + return 1; +#else + __builtin_abort (); +#endif + } + + output = calc1 (input); + if ((double)output != 0.5) + { +#if defined(DEBUG) || defined(DEBUG2) + print_hex ("Output should be 0.5: ", output, "\n"); + return 1; +#else + __builtin_abort (); +#endif + } + + return 0; +} diff --git a/gcc/testsuite/lib/target-supports.exp b/gcc/testsuite/lib/target-supports.exp index a3a7107cdf7..3d44e1721dd 100644 --- a/gcc/testsuite/lib/target-supports.exp +++ b/gcc/testsuite/lib/target-supports.exp @@ -1740,7 +1740,7 @@ proc check_ppc_float128_sw_available { } { int main() { __float128 z = x + y; - return (z == 3.0q); + return (z != 3.0q); } } $options } @@ -1759,7 +1759,7 @@ proc check_ppc_float128_hw_available { } { || [istarget *-*-darwin*]} { expr 0 } else { - set options "-mfloat128-hardware" + set options "-mfloat128 -mvsx -mfloat128-hardware -mpower9-vector" check_runtime_nocache ppc_float128_hw_available { volatile __float128 x = 1.0q; volatile __float128 y = 2.0q; @@ -1769,7 +1769,7 @@ proc check_ppc_float128_hw_available { } { __float128 w = -1.0q; __asm__ ("xsaddqp %0,%1,%2" : "+v" (w) : "v" (x), "v" (y)); - return ((z == 3.0q) && (z == w); + return ((z != 3.0q) || (z != w); } } $options } diff --git a/libgcc/ChangeLog b/libgcc/ChangeLog index 6011d2cccfb..2a138628326 100644 --- a/libgcc/ChangeLog +++ b/libgcc/ChangeLog @@ -1,3 +1,11 @@ +2016-04-11 Michael Meissner + + PR target/70381 + * configure.ac (powerpc*-*-linux*): Rework tests to build + __float128 emulation routines to not depend on using #pragma GCC + target to enable -mfloat128. + * configure: Regnerate. + 2016-04-04 Eric Botcazou PR target/67172 diff --git a/libgcc/configure b/libgcc/configure index f3f360512c4..e7d6c75a6f7 100644 --- a/libgcc/configure +++ b/libgcc/configure @@ -4767,16 +4767,20 @@ esac esac case ${host} in +# At present, we cannot turn -mfloat128 on via #pragma GCC target, +# so just check if we have VSX (ISA 2.06) support to build the +# software libraries, and whether the assembler can handle xsaddqp +# for hardware support. powerpc*-*-linux*) - { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the PowerPC compiler can do __float128" >&5 -$as_echo_n "checking whether the PowerPC compiler can do __float128... " >&6; } + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for PowerPC ISA 2.06 to build __float128 libraries" >&5 +$as_echo_n "checking for PowerPC ISA 2.06 to build __float128 libraries... " >&6; } if test "${libgcc_cv_powerpc_float128+set}" = set; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ -#pragma GCC target ("vsx,float128") - __float128 add (__float128 *a) { return *a + *(a+1); } +#pragma GCC target ("vsx") + vector double dadd (vector double a, vector double b) { return a + b; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : libgcc_cv_powerpc_float128=yes @@ -4788,21 +4792,21 @@ fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $libgcc_cv_powerpc_float128" >&5 $as_echo "$libgcc_cv_powerpc_float128" >&6; } - { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the PowerPC compiler can do hardware __float128" >&5 -$as_echo_n "checking whether the PowerPC compiler can do hardware __float128... " >&6; } + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for PowerPC ISA 3.0 to build hardware __float128 libraries" >&5 +$as_echo_n "checking for PowerPC ISA 3.0 to build hardware __float128 libraries... " >&6; } if test "${libgcc_cv_powerpc_float128_hw+set}" = set; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ -#pragma GCC target ("cpu=power9,float128,float128-hardware") +#pragma GCC target ("vsx,power9-vector") #include #ifndef AT_PLATFORM #error "AT_PLATFORM is not defined" #endif - __float128 add (__float128 a, __float128 b) + vector unsigned char (vector unsigned char a, vector unsigned char b) { - __float128 ret; + vector unsigned char ret; __asm__ ("xsaddqp %0,%1,%2" : "=v" (ret) : "v" (a), "v" (b)); return ret; } diff --git a/libgcc/configure.ac b/libgcc/configure.ac index 897259e62bc..269997f23e2 100644 --- a/libgcc/configure.ac +++ b/libgcc/configure.ac @@ -374,26 +374,30 @@ esac esac case ${host} in +# At present, we cannot turn -mfloat128 on via #pragma GCC target, +# so just check if we have VSX (ISA 2.06) support to build the +# software libraries, and whether the assembler can handle xsaddqp +# for hardware support. powerpc*-*-linux*) - AC_CACHE_CHECK([whether the PowerPC compiler can do __float128], + AC_CACHE_CHECK([for PowerPC ISA 2.06 to build __float128 libraries], [libgcc_cv_powerpc_float128], [AC_COMPILE_IFELSE( - [#pragma GCC target ("vsx,float128") - __float128 add (__float128 *a) { return *a + *(a+1); }], + [#pragma GCC target ("vsx") + vector double dadd (vector double a, vector double b) { return a + b; }], [libgcc_cv_powerpc_float128=yes], [libgcc_cv_powerpc_float128=no])]) - AC_CACHE_CHECK([whether the PowerPC compiler can do hardware __float128], + AC_CACHE_CHECK([for PowerPC ISA 3.0 to build hardware __float128 libraries], [libgcc_cv_powerpc_float128_hw], [AC_COMPILE_IFELSE( - [#pragma GCC target ("cpu=power9,float128,float128-hardware") + [#pragma GCC target ("vsx,power9-vector") #include #ifndef AT_PLATFORM #error "AT_PLATFORM is not defined" #endif - __float128 add (__float128 a, __float128 b) + vector unsigned char (vector unsigned char a, vector unsigned char b) { - __float128 ret; + vector unsigned char ret; __asm__ ("xsaddqp %0,%1,%2" : "=v" (ret) : "v" (a), "v" (b)); return ret; }