[PATCH] Add _Float<N>/_Float<N>X rounding built-ins & improve gimple optimization of _Float<N>/_Float<N>X built-in functions
Michael Meissner
meissner@linux.vnet.ibm.com
Fri Dec 29 05:36:00 GMT 2017
On Thu, Dec 21, 2017 at 01:03:26PM -0600, Segher Boessenkool wrote:
> On Thu, Dec 21, 2017 at 06:16:16PM +0000, Joseph Myers wrote:
> > On Fri, 17 Nov 2017, Michael Meissner wrote:
> > The architecture-independent changes are OK. However, I have a comment on
> > the target parts:
> >
> > > +(define_insn "round<mode>2"
> > > + [(set (match_operand:IEEE128 0 "altivec_register_operand" "=v")
> > > + (unspec:IEEE128
> > > + [(match_operand:IEEE128 1 "altivec_register_operand" "v")]
> > > + UNSPEC_FRIN))]
> > > + "TARGET_FLOAT128_HW && FLOAT128_IEEE_P (<MODE>mode)"
> > > + "xsrqpi 0,%0,%1,3"
> > > + [(set_attr "type" "vecfloat")
> > > + (set_attr "size" "128")])
> >
> > My reading of Power ISA 3.0B documentation is that 0,%0,%1,3 means round
> > in the mode specified by FPSCR and you need 0,%0,%1,0 for
> > round-to-nearest-away semantics which are what the round<mode>2
> > instruction has (i.e., what you've written here is actually correct for
> > nearbyint<mode>2, and would be rint<mode>2 if xsrqpix were used instead).
>
> Ah yes, the roundM2 insn is round-away-from-zero, so you are right.
> Tricky, from the name I assumed it would be "current rounding mode" :-/
> Not that "frin" would make sense if that were true.
>
> Thanks! And thanks for all the reviews in general.
Here is the corrected rs6000 part of the patch. I added more round tests and I
checked it on a power9 prototype machine. Roundf128 now produces the correct
answer. Can I check this into the trunk?
[gcc]
2017-12-29 Michael Meissner <meissner@linux.vnet.ibm.com>
* config/rs6000/rs6000.md (floor<mode>2): Add support for IEEE
128-bit round to integer instructions.
(ceil<mode>2): Likewise.
(btrunc<mode>2): Likewise.
(round<mode>2): Likewise.
[gcc/testsuite]
2017-12-29 Michael Meissner <meissner@linux.vnet.ibm.com>
* gcc.target/powerpc/float128-hw2.c: Add tests for ceilf128,
floorf128, truncf128, and roundf128.
* gcc.target/powerpc/float128-hw5.c: New tests for _Float128
optimizations added in match.pd.
* gcc.target/powerpc/float128-hw6.c: Likewise.
* gcc.target/powerpc/float128-hw7.c: Likewise.
* gcc.target/powerpc/float128-hw8.c: Likewise.
* gcc.target/powerpc/float128-hw9.c: Likewise.
* gcc.target/powerpc/float128-hw10.c: Likewise.
* gcc.target/powerpc/float128-hw11.c: Likewise.
--
Michael Meissner, IBM
IBM, M/S 2506R, 550 King Street, Littleton, MA 01460-6245, USA
email: meissner@linux.vnet.ibm.com, phone: +1 (978) 899-4797
-------------- next part --------------
Index: gcc/config/rs6000/rs6000.md
===================================================================
--- gcc/config/rs6000/rs6000.md (revision 256026)
+++ gcc/config/rs6000/rs6000.md (working copy)
@@ -14777,6 +14777,47 @@ (define_insn_and_split "floatuns<QHI:mod
(set_attr "type" "vecfloat")
(set_attr "size" "128")])
+;; IEEE 128-bit round to integer built-in functions
+(define_insn "floor<mode>2"
+ [(set (match_operand:IEEE128 0 "altivec_register_operand" "=v")
+ (unspec:IEEE128
+ [(match_operand:IEEE128 1 "altivec_register_operand" "v")]
+ UNSPEC_FRIM))]
+ "TARGET_FLOAT128_HW && FLOAT128_IEEE_P (<MODE>mode)"
+ "xsrqpi 1,%0,%1,3"
+ [(set_attr "type" "vecfloat")
+ (set_attr "size" "128")])
+
+(define_insn "ceil<mode>2"
+ [(set (match_operand:IEEE128 0 "altivec_register_operand" "=v")
+ (unspec:IEEE128
+ [(match_operand:IEEE128 1 "altivec_register_operand" "v")]
+ UNSPEC_FRIP))]
+ "TARGET_FLOAT128_HW && FLOAT128_IEEE_P (<MODE>mode)"
+ "xsrqpi 1,%0,%1,2"
+ [(set_attr "type" "vecfloat")
+ (set_attr "size" "128")])
+
+(define_insn "btrunc<mode>2"
+ [(set (match_operand:IEEE128 0 "altivec_register_operand" "=v")
+ (unspec:IEEE128
+ [(match_operand:IEEE128 1 "altivec_register_operand" "v")]
+ UNSPEC_FRIZ))]
+ "TARGET_FLOAT128_HW && FLOAT128_IEEE_P (<MODE>mode)"
+ "xsrqpi 1,%0,%1,1"
+ [(set_attr "type" "vecfloat")
+ (set_attr "size" "128")])
+
+(define_insn "round<mode>2"
+ [(set (match_operand:IEEE128 0 "altivec_register_operand" "=v")
+ (unspec:IEEE128
+ [(match_operand:IEEE128 1 "altivec_register_operand" "v")]
+ UNSPEC_FRIN))]
+ "TARGET_FLOAT128_HW && FLOAT128_IEEE_P (<MODE>mode)"
+ "xsrqpi 0,%0,%1,0"
+ [(set_attr "type" "vecfloat")
+ (set_attr "size" "128")])
+
;; IEEE 128-bit instructions with round to odd semantics
(define_insn "add<mode>3_odd"
[(set (match_operand:IEEE128 0 "altivec_register_operand" "=v")
Index: gcc/testsuite/gcc.target/powerpc/float128-hw2.c
===================================================================
--- gcc/testsuite/gcc.target/powerpc/float128-hw2.c (revision 256026)
+++ gcc/testsuite/gcc.target/powerpc/float128-hw2.c (working copy)
@@ -14,6 +14,10 @@
extern _Float128 copysignf128 (_Float128, _Float128);
extern _Float128 sqrtf128 (_Float128);
extern _Float128 fmaf128 (_Float128, _Float128, _Float128);
+extern _Float128 ceilf128 (_Float128);
+extern _Float128 floorf128 (_Float128);
+extern _Float128 truncf128 (_Float128);
+extern _Float128 roundf128 (_Float128);
_Float128
do_copysign (_Float128 a, _Float128 b)
@@ -51,10 +55,35 @@ do_nfms (_Float128 a, _Float128 b, _Floa
return -fmaf128 (a, b, -c);
}
+_Float128
+do_ceil (_Float128 a)
+{
+ return ceilf128 (a);
+}
+
+_Float128
+do_floor (_Float128 a)
+{
+ return floorf128 (a);
+}
+
+_Float128
+do_trunc (_Float128 a)
+{
+ return truncf128 (a);
+}
+
+_Float128
+do_round (_Float128 a)
+{
+ return roundf128 (a);
+}
+
/* { dg-final { scan-assembler {\mxscpsgnqp\M} } } */
/* { dg-final { scan-assembler {\mxssqrtqp\M} } } */
/* { dg-final { scan-assembler {\mxsmaddqp\M} } } */
/* { dg-final { scan-assembler {\mxsmsubqp\M} } } */
/* { dg-final { scan-assembler {\mxsnmaddqp\M} } } */
/* { dg-final { scan-assembler {\mxsnmsubqp\M} } } */
+/* { dg-final { scan-assembler {\mxsrqpi\M} } } */
/* { dg-final { scan-assembler-not {\mbl\M} } } */
Index: gcc/testsuite/gcc.target/powerpc/float128-hw5.c
===================================================================
--- gcc/testsuite/gcc.target/powerpc/float128-hw5.c (nonexistent)
+++ gcc/testsuite/gcc.target/powerpc/float128-hw5.c (working copy)
@@ -0,0 +1,33 @@
+/* { dg-do compile { target { powerpc*-*-* && lp64 } } } */
+/* { dg-require-effective-target powerpc_p9vector_ok } */
+/* { dg-options "-mpower9-vector -O2 -ffast-math" } */
+
+extern _Float128 copysignf128 (_Float128, _Float128);
+
+/* Check copysign optimizations that are done for double are also done for
+ _Float128. */
+
+_Float128
+x_times_cs_one_negx (_Float128 x)
+{
+ return x * copysignf128 (1.0Q, -x); /* XSNABSQP */
+}
+
+_Float128
+x_times_cs_one_x (_Float128 x)
+{
+ return x * copysignf128 (1.0Q, x); /* XSABSQP */
+}
+
+_Float128
+cs_x_x (_Float128 x)
+{
+ return copysignf128 (x, x); /* no operation. */
+}
+
+/* { dg-final { scan-assembler-times {\mxsabsqp\M} 1 } } */
+/* { dg-final { scan-assembler-times {\mxsnabsqp\M} 1 } } */
+/* { dg-final { scan-assembler-not {\mxscpsgnqp\M} } } */
+/* { dg-final { scan-assembler-not {\mlxvx\M} } } */
+/* { dg-final { scan-assembler-not {\mlxv\M} } } */
+/* { dg-final { scan-assembler-not {\mbl\M} } } */
Index: gcc/testsuite/gcc.target/powerpc/float128-hw6.c
===================================================================
--- gcc/testsuite/gcc.target/powerpc/float128-hw6.c (nonexistent)
+++ gcc/testsuite/gcc.target/powerpc/float128-hw6.c (working copy)
@@ -0,0 +1,26 @@
+/* { dg-do compile { target { powerpc*-*-* && lp64 } } } */
+/* { dg-require-effective-target powerpc_p9vector_ok } */
+/* { dg-options "-mpower9-vector -O2" } */
+
+extern _Float128 fabsf128 (_Float128);
+extern _Float128 copysignf128 (_Float128, _Float128);
+
+/* Check copysign optimizations that are done for double are also done for
+ _Float128. */
+
+_Float128
+cs_negx_y (_Float128 x, _Float128 y)
+{
+ return copysignf128 (-x, y); /* eliminate negation. */
+}
+
+_Float128
+cs_absx_y (_Float128 x, _Float128 y)
+{
+ return copysignf128 (fabsf128 (x), y); /* eliminate fabsf128. */
+}
+
+/* { dg-final { scan-assembler-times {\mxscpsgnqp\M} 2 } } */
+/* { dg-final { scan-assembler-not {\mxsnegqp\M} } } */
+/* { dg-final { scan-assembler-not {\mxsabsqp\M} } } */
+/* { dg-final { scan-assembler-not {\mbl\M} } } */
Index: gcc/testsuite/gcc.target/powerpc/float128-hw7.c
===================================================================
--- gcc/testsuite/gcc.target/powerpc/float128-hw7.c (nonexistent)
+++ gcc/testsuite/gcc.target/powerpc/float128-hw7.c (working copy)
@@ -0,0 +1,27 @@
+/* { dg-do compile { target { powerpc*-*-* && lp64 } } } */
+/* { dg-require-effective-target powerpc_p9vector_ok } */
+/* { dg-options "-mpower9-vector -O2" } */
+
+extern _Float128 fabsf128 (_Float128);
+extern _Float128 copysignf128 (_Float128, _Float128);
+
+/* Check copysign optimizations that are done for double are also done for
+ _Float128. */
+
+_Float128
+cs_x_pos1 (_Float128 x)
+{
+ return copysignf128 (x, 1.0Q); /* XSABSQP. */
+}
+
+_Float128 cs_x_neg2 (_Float128 x)
+{
+ return copysignf128 (x, -2.0Q); /* XSNABSQP. */
+}
+
+/* { dg-final { scan-assembler-times {\mxsabsqp\M} 1 } } */
+/* { dg-final { scan-assembler-not {\mxsnabsqp\M} 1 } } */
+/* { dg-final { scan-assembler-not {\mxscpsgnqp\M} } } */
+/* { dg-final { scan-assembler-not {\mlxvx\M} } } */
+/* { dg-final { scan-assembler-not {\mlxv\M} } } */
+/* { dg-final { scan-assembler-not {\mbl\M} } } */
Index: gcc/testsuite/gcc.target/powerpc/float128-hw8.c
===================================================================
--- gcc/testsuite/gcc.target/powerpc/float128-hw8.c (nonexistent)
+++ gcc/testsuite/gcc.target/powerpc/float128-hw8.c (working copy)
@@ -0,0 +1,24 @@
+/* { dg-do compile { target { powerpc*-*-* && lp64 } } } */
+/* { dg-require-effective-target powerpc_p9vector_ok } */
+/* { dg-options "-mpower9-vector -O2" } */
+
+extern _Float128 fminf128 (_Float128, _Float128);
+extern _Float128 fmaxf128 (_Float128, _Float128);
+
+/* Check min/max optimizations that are done for double are also done for
+ _Float128. */
+
+_Float128
+min_x_x (_Float128 x)
+{
+ return fminf128 (x, x);
+}
+
+_Float128
+max_x_x (_Float128 x)
+{
+ return fmaxf128 (x, x);
+}
+
+/* { dg-final { scan-assembler-not {\mxscmpuqp\M} } } */
+/* { dg-final { scan-assembler-not {\mbl\M} } } */
Index: gcc/testsuite/gcc.target/powerpc/float128-hw9.c
===================================================================
--- gcc/testsuite/gcc.target/powerpc/float128-hw9.c (nonexistent)
+++ gcc/testsuite/gcc.target/powerpc/float128-hw9.c (working copy)
@@ -0,0 +1,17 @@
+/* { dg-do compile { target { powerpc*-*-* && lp64 } } } */
+/* { dg-require-effective-target powerpc_p9vector_ok } */
+/* { dg-options "-mpower9-vector -O2 -ffast-math" } */
+
+extern _Float128 sqrtf128 (_Float128);
+
+/* Check sqrt optimizations that are done for double are also done for
+ _Float128. */
+
+_Float128
+sqrt_x_times_sqrt_x (_Float128 x)
+{
+ return sqrtf128 (x) * sqrtf128 (x);
+}
+
+/* { dg-final { scan-assembler-not {\mxssqrtqp\M} } } */
+/* { dg-final { scan-assembler-not {\mbl\M} } } */
Index: gcc/testsuite/gcc.target/powerpc/float128-hw10.c
===================================================================
--- gcc/testsuite/gcc.target/powerpc/float128-hw10.c (nonexistent)
+++ gcc/testsuite/gcc.target/powerpc/float128-hw10.c (working copy)
@@ -0,0 +1,38 @@
+/* { dg-do compile { target { powerpc*-*-* && lp64 } } } */
+/* { dg-require-effective-target powerpc_p9vector_ok } */
+/* { dg-options "-mpower9-vector -O2" } */
+
+extern _Float128 floorf128 (_Float128);
+extern _Float128 ceilf128 (_Float128);
+extern _Float128 roundf128 (_Float128);
+extern _Float128 truncf128 (_Float128);
+
+/* Check rounding optimizations that are done for double are also done for
+ _Float128. */
+
+_Float128
+floor_floor_x (_Float128 x)
+{
+ return floorf128 (floorf128 (x));
+}
+
+_Float128
+ceil_ceil_x (_Float128 x)
+{
+ return ceilf128 (ceilf128 (x));
+}
+
+_Float128
+trunc_trunc_x (_Float128 x)
+{
+ return truncf128 (truncf128 (x));
+}
+
+_Float128
+round_round_x (_Float128 x)
+{
+ return roundf128 (roundf128 (x));
+}
+
+/* { dg-final { scan-assembler-times {\mxsrqpi\M} 4 } } */
+/* { dg-final { scan-assembler-not {\mbl\M} } } */
Index: gcc/testsuite/gcc.target/powerpc/float128-hw11.c
===================================================================
--- gcc/testsuite/gcc.target/powerpc/float128-hw11.c (nonexistent)
+++ gcc/testsuite/gcc.target/powerpc/float128-hw11.c (working copy)
@@ -0,0 +1,85 @@
+/* { dg-do run { target { powerpc*-*-* && lp64 } } } */
+/* { dg-require-effective-target p9vector_hw } */
+/* { dg-options "-mpower9-vector -O2" } */
+
+#define __STDC_WANT_IEC_60559_TYPES_EXT__ 1
+#define __STDC_WANT_IEC_60559_FUNCS_EXT__ 1
+
+#include <math.h>
+#include <stdlib.h>
+#include <stddef.h>
+
+#ifdef DEBUG
+#include <stdio.h>
+#define FAIL(T,G,E) printf ("%s: %g %g\n", (T), (G), (E))
+#else
+#define FAIL(T,G,E) abort ()
+#endif
+
+extern _Float128 roundf128 (_Float128);
+extern _Float128 floorf128 (_Float128);
+extern _Float128 ceilf128 (_Float128);
+extern _Float128 truncf128 (_Float128);
+
+static const _Float128 values[] = {
+ -3.7f128,
+ -3.5f128,
+ -3.3f128,
+ -3.0f128,
+ -2.7f128,
+ -2.5f128,
+ -2.3f128,
+ -2.0f128,
+ -1.7f128,
+ -1.5f128,
+ -1.3f128,
+ -0.7f128,
+ -0.5f128,
+ -0.3f128,
+ +0.0f128,
+ +0.3f128,
+ +0.5f128,
+ +0.7f128,
+ +1.0f128,
+ +1.3f128,
+ +1.5f128,
+ +1.7f128,
+ +2.0f128,
+ +2.3f128,
+ +2.5f128,
+ +2.7f128,
+ +3.0f128,
+ +3.3f128,
+ +3.5f128,
+ +3.7f128,
+};
+
+__attribute__((__noinline__))
+void
+do_test (const char *test, _Float128 got, double expected)
+{
+ double got2 = (double) got;
+ if (got2 != expected)
+ FAIL (test, got2, expected);
+}
+
+int
+main (void)
+{
+ size_t i;
+ _Float128 v;
+ double v2;
+
+ for (i = 0; i < sizeof (values) / sizeof (values[0]); i++)
+ {
+ v = values[i];
+ v2 = (double) v;
+
+ do_test ("roundf128", roundf128 (v), round (v2));
+ do_test ("floorf128", floorf128 (v), floor (v2));
+ do_test ("ceilf128", ceilf128 (v), ceil (v2));
+ do_test ("truncf128", truncf128 (v), trunc (v2));
+ }
+
+ return 0;
+}
More information about the Gcc-patches
mailing list