diff mbox

, PowerPC IEEE 128-bit patch #9 (enable __float128 by default on VSX systems)

Message ID 20151027223141.GB16546@ibm-tiger.the-meissners.org
State New
Headers show

Commit Message

Michael Meissner Oct. 27, 2015, 10:31 p.m. UTC
This is the final patch that enables __float128 by default on systems that
support the VSX instruction set (power7, power8).  In addition, I added two
runtime tests to verify that __float128 runs, and gives more precision than
double.

Once all of the sub-patches for patch #7 for gcc and patch #8 for libgcc are
installed, is this patch ok to check into trunk?

[gcc]
2015-10-27  Michael Meissner  <meissner@linux.vnet.ibm.com>

	* config/rs6000/rs6000-cpus.def (ISA_2_6_MASKS_SERVER): Add
	-mfloat128.

[gcc/testsuite]
2015-10-27  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

Segher Boessenkool Oct. 29, 2015, 2:02 p.m. UTC | #1
Hi!

On Tue, Oct 27, 2015 at 06:31:41PM -0400, Michael Meissner wrote:
> 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,149 @@
> +/* { dg-do run { target { powerpc*-*-linux* } } } */
> +/* { dg-skip-if "" { powerpc*-*-darwin* } { "*" } { "" } } */
> +/* { dg-skip-if "" { powerpc*-*-*spe* } { "*" } { "" } } */

Some of this is redundant.  Should this really be linux-only?
The second line doesn't do anything then.  { "*" } { "" } isn't
needed either.

In general, please only add dg-skip-if if you know it is needed.

There probably should be an effective-target for float128.


Segher
Joseph Myers Oct. 29, 2015, 6:47 p.m. UTC | #2
On Thu, 29 Oct 2015, Segher Boessenkool wrote:

> There probably should be an effective-target for float128.

Yes, as I said in 
<https://gcc.gnu.org/ml/gcc-patches/2015-10/msg02991.html> there needs to 
be standard test boilerplate to: disable a test if __float128 isn't 
supported at all even with extra options added; add those options on 
targets that support it provided the right options are added; and turn a 
run test to a compile test if the options are supported but the hardware 
support (for VSX in this case) is missing.  Then the tests that run for 
x86 and possibly ia64 targets (some of which may be under gcc.target at 
present) need to have their target restrictions replaced, being moved out 
of gcc.target as needed.

The tests using feenableexcept would then *also* require some suitable 
effective-target (or restriction to *-*-*gnu*) to restrict them to glibc 
targets.
Michael Meissner Oct. 29, 2015, 8:50 p.m. UTC | #3
On Thu, Oct 29, 2015 at 09:02:22AM -0500, Segher Boessenkool wrote:
> Hi!
> 
> On Tue, Oct 27, 2015 at 06:31:41PM -0400, Michael Meissner wrote:
> > 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,149 @@
> > +/* { dg-do run { target { powerpc*-*-linux* } } } */
> > +/* { dg-skip-if "" { powerpc*-*-darwin* } { "*" } { "" } } */
> > +/* { dg-skip-if "" { powerpc*-*-*spe* } { "*" } { "" } } */
> 
> Some of this is redundant.  Should this really be linux-only?
> The second line doesn't do anything then.  { "*" } { "" } isn't
> needed either.
> 
> In general, please only add dg-skip-if if you know it is needed.
> 
> There probably should be an effective-target for float128.

Well the normal VSX target should work.

Back when I was doing power7 development, there were problems with Darwin
and/or SPE ignoring the -mcpu=<xxx> option, so I've just cloned the code on
these tests ever since.
diff mbox

Patch

Index: gcc/config/rs6000/rs6000-cpus.def
===================================================================
--- gcc/config/rs6000/rs6000-cpus.def	(revision 229203)
+++ gcc/config/rs6000/rs6000-cpus.def	(working copy)
@@ -46,6 +46,7 @@ 
 				 | OPTION_MASK_ALTIVEC			\
 				 | OPTION_MASK_FLOAT128			\
 				 | OPTION_MASK_VSX			\
+				 | OPTION_MASK_FLOAT128			\
 				 | OPTION_MASK_UPPER_REGS_DF)
 
 /* For now, don't provide an embedded version of ISA 2.07.  */
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,149 @@ 
+/* { dg-do run { target { powerpc*-*-linux* } } } */
+/* { dg-skip-if "" { powerpc*-*-darwin* } { "*" } { "" } } */
+/* { dg-skip-if "" { powerpc*-*-*spe* } { "*" } { "" } } */
+/* { dg-require-effective-target vsx_hw } */
+/* { 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,228 @@ 
+/* { dg-do run { target { powerpc*-*-linux* } } } */
+/* { dg-skip-if "" { powerpc*-*-darwin* } { "*" } { "" } } */
+/* { dg-skip-if "" { powerpc*-*-*spe* } { "*" } { "" } } */
+/* { dg-require-effective-target vsx_hw } */
+/* { 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;
+}