diff mbox

, PowerPC IEEE 128-bit fp, #12 (default -mfloat128 on PowerPC-Linux)

Message ID 20160121212525.GA18118@ibm-tiger.the-meissners.org
State New
Headers show

Commit Message

Michael Meissner Jan. 21, 2016, 9:25 p.m. UTC
This is the final patch (at least so far) that turns on -mfloat128 by default
for PowerPC Linux systems where the VSX instruction set is enabled.  As I
mentioned in the last email, because we don't build the __float128 emulator on
other systems, I didn't think it would be useful to make it the default.

I did a boostrap build/check with no regressions on a little endian power8
system.  Are the patches ok to check in?

[gcc]
2016-01-21   Michael Meissner  <meissner@linux.vnet.ibm.com>

	* config/rs6000/rs6000.c (rs6000_option_override_internal): Enable
	-mfloat128 by default on PowerPC Linux systems with the VSX
	instruction enabled.

[gcc/testsuite]
2016-01-21   Michael Meissner  <meissner@linux.vnet.ibm.com>

	* gcc.target/powerpc/float128-1.c: New test for IEEE 128-bit
	floating point support.
	* gcc.target/powerpc/float128-2.c: Likewise.

Comments

David Edelsohn Jan. 26, 2016, 2:52 p.m. UTC | #1
On Thu, Jan 21, 2016 at 4:25 PM, Michael Meissner
<meissner@linux.vnet.ibm.com> wrote:
> This is the final patch (at least so far) that turns on -mfloat128 by default
> for PowerPC Linux systems where the VSX instruction set is enabled.  As I
> mentioned in the last email, because we don't build the __float128 emulator on
> other systems, I didn't think it would be useful to make it the default.
>
> I did a boostrap build/check with no regressions on a little endian power8
> system.  Are the patches ok to check in?
>
> [gcc]
> 2016-01-21   Michael Meissner  <meissner@linux.vnet.ibm.com>
>
>         * config/rs6000/rs6000.c (rs6000_option_override_internal): Enable
>         -mfloat128 by default on PowerPC Linux systems with the VSX
>         instruction enabled.
>
> [gcc/testsuite]
> 2016-01-21   Michael Meissner  <meissner@linux.vnet.ibm.com>
>
>         * gcc.target/powerpc/float128-1.c: New test for IEEE 128-bit
>         floating point support.
>         * gcc.target/powerpc/float128-2.c: Likewise.

No.  This is too risky a change during Stage 4.

- David
diff mbox

Patch

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 <stdio.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <inttypes.h>
+#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 <stdio.h>
+#include <math.h>
+#include <stdlib.h>
+#include <stddef.h>
+
+#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;
+}