Index: gcc/config/rs6000/rs6000.c =================================================================== --- gcc/config/rs6000/rs6000.c (revision 232690) +++ gcc/config/rs6000/rs6000.c (working copy) @@ -4236,6 +4236,15 @@ rs6000_option_override_internal (bool gl } } + /* At present, we only build the __float128 emulator on PowerPC Linux. + Enable default __float128 support for PowerPC Linux systems, but not for + others. */ +#ifdef POWERPC_LINUX + if (TARGET_VSX && !TARGET_FLOAT128 + && (rs6000_isa_flags_explicit & OPTION_MASK_FLOAT128) == 0) + rs6000_isa_flags |= OPTION_MASK_FLOAT128; +#endif + /* __float128 requires VSX support. */ if (TARGET_FLOAT128 && !TARGET_VSX) { Index: gcc/testsuite/gcc.target/powerpc/float128-1.c =================================================================== --- gcc/testsuite/gcc.target/powerpc/float128-1.c (revision 0) +++ gcc/testsuite/gcc.target/powerpc/float128-1.c (revision 0) @@ -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; +} Index: gcc/testsuite/gcc.target/powerpc/float128-2.c =================================================================== --- gcc/testsuite/gcc.target/powerpc/float128-2.c (revision 0) +++ gcc/testsuite/gcc.target/powerpc/float128-2.c (revision 0) @@ -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; +}