public inbox for gcc-cvs@sourceware.org
help / color / mirror / Atom feed
* [gcc r12-6848] rtl: builtins: (not just) rs6000: Add builtins for fegetround, feclearexcept and feraiseexcept [PR94
@ 2022-01-24 17:00 Segher Boessenkool
  0 siblings, 0 replies; only message in thread
From: Segher Boessenkool @ 2022-01-24 17:00 UTC (permalink / raw)
  To: gcc-cvs

https://gcc.gnu.org/g:4343f5e256791a5abaaef29fe1f831a03bab129e

commit r12-6848-g4343f5e256791a5abaaef29fe1f831a03bab129e
Author: Raoni Fassina Firmino <raoni@linux.ibm.com>
Date:   Thu Jan 13 14:08:53 2022 -0300

    rtl: builtins: (not just) rs6000: Add builtins for fegetround, feclearexcept and feraiseexcept [PR94193]
    
    This optimizations were originally in glibc, but was removed
    and suggested that they were a good fit as gcc builtins[1].
    
    feclearexcept and feraiseexcept were extended (in comparison to the
    glibc version) to accept any combination of the accepted flags, not
    limited to just one flag bit at a time anymore.
    
    The builtin expanders needs knowledge of the target libc's FE_*
    values, so they are limited to expand only to suitable libcs.
    
    [1] https://sourceware.org/legacy-ml/libc-alpha/2020-03/msg00047.html
        https://sourceware.org/legacy-ml/libc-alpha/2020-03/msg00080.html
    
    2020-08-13  Raoni Fassina Firmino  <raoni@linux.ibm.com>
    
    gcc/
            PR target/94193
            * builtins.cc (expand_builtin_fegetround): New function.
            (expand_builtin_feclear_feraise_except): New function.
            (expand_builtin): Add cases for BUILT_IN_FEGETROUND,
            BUILT_IN_FECLEAREXCEPT and BUILT_IN_FERAISEEXCEPT.
            * config/rs6000/rs6000.md (fegetroundsi): New pattern.
            (feclearexceptsi): New Pattern.
            (feraiseexceptsi): New Pattern.
            * doc/extend.texi: Add a new introductory paragraph about the
            new builtins.
            * doc/md.texi: (fegetround@var{m}): Document new optab.
            (feclearexcept@var{m}): Document new optab.
            (feraiseexcept@var{m}): Document new optab.
            * optabs.def (fegetround_optab): New optab.
            (feclearexcept_optab): New optab.
            (feraiseexcept_optab): New optab.
    
    gcc/testsuite/
            PR target/94193
            * gcc.target/powerpc/builtin-feclearexcept-feraiseexcept-1.c: New test.
            * gcc.target/powerpc/builtin-feclearexcept-feraiseexcept-2.c: New test.
            * gcc.target/powerpc/builtin-fegetround.c: New test.
    
    Signed-off-by: Raoni Fassina Firmino <raoni@linux.ibm.com>

Diff:
---
 gcc/builtins.cc                                    |  76 ++++++++++++++
 gcc/config/rs6000/rs6000.md                        | 111 +++++++++++++++++++++
 gcc/doc/extend.texi                                |   8 ++
 gcc/doc/md.texi                                    |  17 ++++
 gcc/optabs.def                                     |   4 +
 .../builtin-feclearexcept-feraiseexcept-1.c        |  76 ++++++++++++++
 .../builtin-feclearexcept-feraiseexcept-2.c        |  91 +++++++++++++++++
 .../gcc.target/powerpc/builtin-fegetround.c        |  36 +++++++
 8 files changed, 419 insertions(+)

diff --git a/gcc/builtins.cc b/gcc/builtins.cc
index bf07341a036..e84208035da 100644
--- a/gcc/builtins.cc
+++ b/gcc/builtins.cc
@@ -119,6 +119,9 @@ static rtx expand_builtin_mathfn_3 (tree, rtx, rtx);
 static rtx expand_builtin_mathfn_ternary (tree, rtx, rtx);
 static rtx expand_builtin_interclass_mathfn (tree, rtx);
 static rtx expand_builtin_sincos (tree);
+static rtx expand_builtin_fegetround (tree, rtx, machine_mode);
+static rtx expand_builtin_feclear_feraise_except (tree, rtx, machine_mode,
+						  optab);
 static rtx expand_builtin_cexpi (tree, rtx);
 static rtx expand_builtin_int_roundingfn (tree, rtx);
 static rtx expand_builtin_int_roundingfn_2 (tree, rtx);
@@ -2555,6 +2558,59 @@ expand_builtin_sincos (tree exp)
   return const0_rtx;
 }
 
+/* Expand call EXP to the fegetround builtin (from C99 fenv.h), returning the
+   result and setting it in TARGET.  Otherwise return NULL_RTX on failure.  */
+static rtx
+expand_builtin_fegetround (tree exp, rtx target, machine_mode target_mode)
+{
+  if (!validate_arglist (exp, VOID_TYPE))
+    return NULL_RTX;
+
+  insn_code icode = direct_optab_handler (fegetround_optab, SImode);
+  if (icode == CODE_FOR_nothing)
+    return NULL_RTX;
+
+  if (target == 0
+      || GET_MODE (target) != target_mode
+      || !(*insn_data[icode].operand[0].predicate) (target, target_mode))
+    target = gen_reg_rtx (target_mode);
+
+  rtx pat = GEN_FCN (icode) (target);
+  if (!pat)
+    return NULL_RTX;
+  emit_insn (pat);
+
+  return target;
+}
+
+/* Expand call EXP to either feclearexcept or feraiseexcept builtins (from C99
+   fenv.h), returning the result and setting it in TARGET.  Otherwise return
+   NULL_RTX on failure.  */
+static rtx
+expand_builtin_feclear_feraise_except (tree exp, rtx target,
+				       machine_mode target_mode, optab op_optab)
+{
+  if (!validate_arglist (exp, INTEGER_TYPE, VOID_TYPE))
+    return NULL_RTX;
+  rtx op0 = expand_normal (CALL_EXPR_ARG (exp, 0));
+
+  insn_code icode = direct_optab_handler (op_optab, SImode);
+  if (icode == CODE_FOR_nothing)
+    return NULL_RTX;
+
+  if (target == 0
+      || GET_MODE (target) != target_mode
+      || !(*insn_data[icode].operand[0].predicate) (target, target_mode))
+    target = gen_reg_rtx (target_mode);
+
+  rtx pat = GEN_FCN (icode) (target, op0);
+  if (!pat)
+    return NULL_RTX;
+  emit_insn (pat);
+
+  return target;
+}
+
 /* Expand a call to the internal cexpi builtin to the sincos math function.
    EXP is the expression that is a call to the builtin function; if convenient,
    the result should be placed in TARGET.  */
@@ -7056,6 +7112,26 @@ expand_builtin (tree exp, rtx target, rtx subtarget, machine_mode mode,
 	return target;
       break;
 
+    case BUILT_IN_FEGETROUND:
+      target = expand_builtin_fegetround (exp, target, target_mode);
+      if (target)
+	return target;
+      break;
+
+    case BUILT_IN_FECLEAREXCEPT:
+      target = expand_builtin_feclear_feraise_except (exp, target, target_mode,
+						      feclearexcept_optab);
+      if (target)
+	return target;
+      break;
+
+    case BUILT_IN_FERAISEEXCEPT:
+      target = expand_builtin_feclear_feraise_except (exp, target, target_mode,
+						      feraiseexcept_optab);
+      if (target)
+	return target;
+      break;
+
     case BUILT_IN_APPLY_ARGS:
       return expand_builtin_apply_args ();
 
diff --git a/gcc/config/rs6000/rs6000.md b/gcc/config/rs6000/rs6000.md
index 4e221189028..fdfbc6566a5 100644
--- a/gcc/config/rs6000/rs6000.md
+++ b/gcc/config/rs6000/rs6000.md
@@ -6912,6 +6912,117 @@
   [(set_attr "type" "fpload")
    (set_attr "length" "8")
    (set_attr "isa" "*,p8v,p8v")])
+
+;; int fegetround(void)
+;;
+;; This expansion for the C99 function only expands for compatible
+;; target libcs, because it needs to return one of FE_DOWNWARD,
+;; FE_TONEAREST, FE_TOWARDZERO or FE_UPWARD with the values as defined
+;; by the target libc, and since the libc is free to choose the values
+;; (and they may differ from the hardware) and the expander needs to
+;; know then beforehand, this expanded only expands for target libcs
+;; that it can handle the values is knows.
+;; Because of these restriction, this only expands on the desired
+;; case and fallback to a call to libc otherwise.
+(define_expand "fegetroundsi"
+  [(set (match_operand:SI 0 "gpc_reg_operand")
+	(unspec_volatile:SI [(const_int 0)] UNSPECV_MFFSL))]
+  "TARGET_HARD_FLOAT"
+{
+  if (!OPTION_GLIBC)
+    FAIL;
+
+  rtx tmp_df = gen_reg_rtx (DFmode);
+  emit_insn (gen_rs6000_mffsl (tmp_df));
+
+  rtx tmp_di = simplify_gen_subreg (DImode, tmp_df, DFmode, 0);
+  rtx tmp_di_2 = gen_reg_rtx (DImode);
+  emit_insn (gen_anddi3 (tmp_di_2, tmp_di, GEN_INT (3)));
+  rtx tmp_si = gen_reg_rtx (SImode);
+  tmp_si = gen_lowpart (SImode, tmp_di_2);
+  emit_move_insn (operands[0], tmp_si);
+  DONE;
+})
+
+;; int feclearexcept(int excepts)
+;;
+;; This expansion for the C99 function only works when EXCEPTS is a
+;; constant known at compile time and specifies any one of
+;; FE_INEXACT, FE_DIVBYZERO, FE_UNDERFLOW and FE_OVERFLOW flags.
+;; It doesn't handle values out of range, and always returns 0.
+;; Note that FE_INVALID is unsupported because it maps to more than
+;; one bit of the FPSCR register.
+;; The FE_* are defined in the target libc, and since they are free to
+;; choose the values and the expand needs to know them beforehand,
+;; this expander only expands for target libcs that it can handle the
+;; values it knows.
+;; Because of these restrictions, this only expands on the desired
+;; cases and fallback to a call to libc on any other case.
+(define_expand "feclearexceptsi"
+  [(use (match_operand:SI 1 "const_int_operand" "n"))
+   (set (match_operand:SI 0 "gpc_reg_operand")
+	(const_int 0))]
+  "TARGET_HARD_FLOAT"
+{
+  if (!OPTION_GLIBC)
+    FAIL;
+
+  unsigned int fe = INTVAL (operands[1]);
+  if (fe != (fe & 0x1e000000))
+    FAIL;
+
+  if (fe & 0x02000000)  /* FE_INEXACT */
+    emit_insn (gen_rs6000_mtfsb0 (gen_rtx_CONST_INT (SImode, 6)));
+  if (fe & 0x04000000)  /* FE_DIVBYZERO */
+    emit_insn (gen_rs6000_mtfsb0 (gen_rtx_CONST_INT (SImode, 5)));
+  if (fe & 0x08000000)  /* FE_UNDERFLOW */
+    emit_insn (gen_rs6000_mtfsb0 (gen_rtx_CONST_INT (SImode, 4)));
+  if (fe & 0x10000000)  /* FE_OVERFLOW */
+    emit_insn (gen_rs6000_mtfsb0 (gen_rtx_CONST_INT (SImode, 3)));
+
+  emit_move_insn (operands[0], const0_rtx);
+  DONE;
+})
+
+;; int feraiseexcept(int excepts)
+;;
+;; This expansion for the C99 function only works when excepts is a
+;; constant known at compile time and specifies any one of
+;; FE_INEXACT, FE_DIVBYZERO, FE_UNDERFLOW and FE_OVERFLOW flags.
+;; It doesn't handle values out of range, and always returns 0.
+;; Note that FE_INVALID is unsupported because it maps to more than
+;; one bit of the FPSCR register.
+;; The FE_* are defined in the target libc, and since they are free to
+;; choose the values and the expand needs to know them beforehand,
+;; this expander only expands for target libcs that it can handle the
+;; values it knows.
+;; Because of these restrictions, this only expands on the desired
+;; cases and fallback to a call to libc on any other case.
+(define_expand "feraiseexceptsi"
+  [(use (match_operand:SI 1 "const_int_operand" "n"))
+   (set (match_operand:SI 0 "gpc_reg_operand")
+	(const_int 0))]
+  "TARGET_HARD_FLOAT"
+{
+  if (!OPTION_GLIBC)
+    FAIL;
+
+  unsigned int fe = INTVAL (operands[1]);
+  if (fe != (fe & 0x1e000000))
+    FAIL;
+
+  if (fe & 0x02000000)  /* FE_INEXACT */
+    emit_insn (gen_rs6000_mtfsb1 (gen_rtx_CONST_INT (SImode, 6)));
+  if (fe & 0x04000000)  /* FE_DIVBYZERO */
+    emit_insn (gen_rs6000_mtfsb1 (gen_rtx_CONST_INT (SImode, 5)));
+  if (fe & 0x08000000)  /* FE_UNDERFLOW */
+    emit_insn (gen_rs6000_mtfsb1 (gen_rtx_CONST_INT (SImode, 4)));
+  if (fe & 0x10000000)  /* FE_OVERFLOW */
+    emit_insn (gen_rs6000_mtfsb1 (gen_rtx_CONST_INT (SImode, 3)));
+
+  emit_move_insn (operands[0], const0_rtx);
+  DONE;
+})
 \f
 ;; Define the TImode operations that can be done in a small number
 ;; of instructions.  The & constraints are to prevent the register
diff --git a/gcc/doc/extend.texi b/gcc/doc/extend.texi
index 0775d977285..a961fc4e0a2 100644
--- a/gcc/doc/extend.texi
+++ b/gcc/doc/extend.texi
@@ -13506,6 +13506,14 @@ In the same fashion, GCC provides @code{fpclassify}, @code{isfinite},
 @code{__builtin_} prefixed.  The @code{isinf} and @code{isnan}
 built-in functions appear both with and without the @code{__builtin_} prefix.
 
+GCC provides built-in versions of the ISO C99 floating-point rounding and
+exceptions handling functions @code{fegetround}, @code{feclearexcept} and
+@code{feraiseexcept}.  They may not be available for all targets, and because
+they need close interaction with libc internal values, they may not be available
+for all target libcs, but in all cases they will gracefully fallback to libc
+calls.  This built-in functions appear both with and without the
+@code{__builtin_} prefix.
+
 @deftypefn {Built-in Function} void *__builtin_alloca (size_t size)
 The @code{__builtin_alloca} function must be called at block scope.
 The function allocates an object @var{size} bytes large on the stack
diff --git a/gcc/doc/md.texi b/gcc/doc/md.texi
index 7f0aab9243f..feacb12e589 100644
--- a/gcc/doc/md.texi
+++ b/gcc/doc/md.texi
@@ -6087,6 +6087,23 @@ mode @var{m}, which is a scalar or vector floating-point mode.
 
 This pattern is not allowed to @code{FAIL}.
 
+@cindex @code{fegetround@var{m}} instruction pattern
+@item @samp{fegetround@var{m}}
+Store the current machine floating-point rounding mode into operand 0.
+Operand 0 has mode @var{m}, which is scalar.  This pattern is used to
+implement the @code{fegetround} function from the ISO C99 standard.
+
+@cindex @code{feclearexcept@var{m}} instruction pattern
+@cindex @code{feraiseexcept@var{m}} instruction pattern
+@item @samp{feclearexcept@var{m}}
+@item @samp{feraiseexcept@var{m}}
+Clears or raises the supported machine floating-point exceptions
+represented by the bits in operand 1.  Error status is stored as
+nonzero value in operand 0.  Both operands have mode @var{m}, which is
+a scalar.  These patterns are used to implement the
+@code{feclearexcept} and @code{feraiseexcept} functions from the ISO
+C99 standard.
+
 @cindex @code{exp@var{m}2} instruction pattern
 @item @samp{exp@var{m}2}
 Raise e (the base of natural logarithms) to the power of operand 1
diff --git a/gcc/optabs.def b/gcc/optabs.def
index bb46083b904..801310ebaa7 100644
--- a/gcc/optabs.def
+++ b/gcc/optabs.def
@@ -331,6 +331,10 @@ OPTAB_D (sinh_optab, "sinh$a2")
 OPTAB_D (tan_optab, "tan$a2")
 OPTAB_D (tanh_optab, "tanh$a2")
 
+OPTAB_D (fegetround_optab, "fegetround$a")
+OPTAB_D (feclearexcept_optab, "feclearexcept$a")
+OPTAB_D (feraiseexcept_optab, "feraiseexcept$a")
+
 /* C99 implementations of fmax/fmin.  */
 OPTAB_D (fmax_optab, "fmax$a3")
 OPTAB_D (fmin_optab, "fmin$a3")
diff --git a/gcc/testsuite/gcc.target/powerpc/builtin-feclearexcept-feraiseexcept-1.c b/gcc/testsuite/gcc.target/powerpc/builtin-feclearexcept-feraiseexcept-1.c
new file mode 100644
index 00000000000..4482e89b0db
--- /dev/null
+++ b/gcc/testsuite/gcc.target/powerpc/builtin-feclearexcept-feraiseexcept-1.c
@@ -0,0 +1,76 @@
+/* { dg-do run } */
+/* { dg-require-effective-target fenv_exceptions } */
+/* { dg-options "-lm -fno-builtin" } */
+
+/* This testcase ensures that the builtins expand with the matching arguments
+   or otherwise fallback gracefully to a function call, and don't ICE during
+   compilation.
+   "-fno-builtin" option is used to enable calls to libc implementation of the
+   gcc builtins tested when not using __builtin_ prefix. */
+
+#include <fenv.h>
+
+int
+main ()
+{
+  int   rsi = 0;
+  long  rsl = 0;
+  short rss = 0;
+  char  rsc = 0;
+
+  unsigned int   rui = 0;
+  unsigned long  rul = 0;
+  unsigned short rus = 0;
+  unsigned char  ruc = 0;
+
+  int e = FE_DIVBYZERO;
+
+  __builtin_feclearexcept(e);                          // CALL
+  __builtin_feclearexcept(FE_ALL_EXCEPT);              // CALL
+  __builtin_feclearexcept(FE_INVALID);                 // CALL
+  __builtin_feclearexcept(FE_INVALID | FE_INEXACT);    // CALL
+
+  __builtin_feclearexcept(FE_INEXACT | FE_DIVBYZERO |
+                          FE_UNDERFLOW | FE_OVERFLOW);  // EXPAND
+  __builtin_feclearexcept(FE_INEXACT | FE_OVERFLOW);    // EXPAND
+  __builtin_feclearexcept(FE_INEXACT);                  // EXPAND
+  __builtin_feclearexcept(FE_DIVBYZERO);                // EXPAND
+  __builtin_feclearexcept(FE_UNDERFLOW);                // EXPAND
+  __builtin_feclearexcept(FE_OVERFLOW);                 // EXPAND
+  __builtin_feclearexcept(0);                           // EXPAND
+
+  rsi = __builtin_feclearexcept(FE_DIVBYZERO);  // EXPAND
+  rsl = __builtin_feclearexcept(FE_DIVBYZERO);  // EXPAND
+  rss = __builtin_feclearexcept(FE_DIVBYZERO);  // EXPAND
+  rsc = __builtin_feclearexcept(FE_DIVBYZERO);  // EXPAND
+  rui = __builtin_feclearexcept(FE_DIVBYZERO);  // EXPAND
+  rul = __builtin_feclearexcept(FE_DIVBYZERO);  // EXPAND
+  rus = __builtin_feclearexcept(FE_DIVBYZERO);  // EXPAND
+  ruc = __builtin_feclearexcept(FE_DIVBYZERO);  // EXPAND
+
+
+  __builtin_feraiseexcept(e);                          // CALL
+  __builtin_feraiseexcept(FE_ALL_EXCEPT);              // CALL
+  __builtin_feraiseexcept(FE_INVALID);                 // CALL
+  __builtin_feraiseexcept(FE_INVALID | FE_INEXACT);    // CALL
+
+  __builtin_feraiseexcept(FE_INEXACT | FE_DIVBYZERO |
+                          FE_UNDERFLOW | FE_OVERFLOW);  // EXPAND
+  __builtin_feraiseexcept(FE_INEXACT | FE_OVERFLOW);    // EXPAND
+  __builtin_feraiseexcept(FE_INEXACT);                  // EXPAND
+  __builtin_feraiseexcept(FE_DIVBYZERO);                // EXPAND
+  __builtin_feraiseexcept(FE_UNDERFLOW);                // EXPAND
+  __builtin_feraiseexcept(FE_OVERFLOW);                 // EXPAND
+  __builtin_feraiseexcept(0);                           // EXPAND
+
+  rsi = __builtin_feraiseexcept(FE_DIVBYZERO);  // EXPAND
+  rsl = __builtin_feraiseexcept(FE_DIVBYZERO);  // EXPAND
+  rss = __builtin_feraiseexcept(FE_DIVBYZERO);  // EXPAND
+  rsc = __builtin_feraiseexcept(FE_DIVBYZERO);  // EXPAND
+  rui = __builtin_feraiseexcept(FE_DIVBYZERO);  // EXPAND
+  rul = __builtin_feraiseexcept(FE_DIVBYZERO);  // EXPAND
+  rus = __builtin_feraiseexcept(FE_DIVBYZERO);  // EXPAND
+  ruc = __builtin_feraiseexcept(FE_DIVBYZERO);  // EXPAND
+
+  return 0;
+}
diff --git a/gcc/testsuite/gcc.target/powerpc/builtin-feclearexcept-feraiseexcept-2.c b/gcc/testsuite/gcc.target/powerpc/builtin-feclearexcept-feraiseexcept-2.c
new file mode 100644
index 00000000000..28c2a00ec52
--- /dev/null
+++ b/gcc/testsuite/gcc.target/powerpc/builtin-feclearexcept-feraiseexcept-2.c
@@ -0,0 +1,91 @@
+/* { dg-do run } */
+/* { dg-require-effective-target fenv_exceptions } */
+/* { dg-options "-lm -fno-builtin" } */
+
+/* This testcase ensures that the builtins are correctly expanded and match the
+   expected result.
+   "-fno-builtin" option is used to enable calls to libc implementation of the
+   gcc builtins tested when not using __builtin_ prefix.
+   The excepts parameter needs to be passed as constant to
+   __builtin_feclearexcept and __builtin_feraiseexcept because some bultins only
+   expand on constant input. */
+
+#include <fenv.h>
+
+#ifdef DEBUG
+#include <stdio.h>
+#define INFO(...) printf(__VA_ARGS__)
+#define FAIL(ret, raised, expected, excepts, excepts_str, func) \
+        printf("ERROR [l %d] testing %s (%x): %s returned %d."  \
+	       " Raised except bits %x, expecected %x\n",       \
+	       __LINE__, excepts_str, excepts, func, ret, raised, expected)
+#else
+void abort (void);
+#define INFO(...)
+#define FAIL(ret, raised, expected, excepts, excepts_str, func) abort()
+#endif
+
+#define TEST(excepts)                                                          \
+    do {                                                                       \
+      int ret = 0;                                                             \
+      int raised = 0;                                                          \
+                                                                               \
+      INFO("test: %s (%x)\n", #excepts, excepts);                              \
+                                                                               \
+      feclearexcept(FE_ALL_EXCEPT);                                            \
+      ret = __builtin_feraiseexcept(excepts);                                  \
+      raised = fetestexcept(FE_ALL_EXCEPT);                                    \
+      if (ret != 0 || raised != (excepts))                                     \
+        FAIL(ret, raised, excepts, excepts, #excepts,                          \
+	     "__builtin_feraiseexcept");                                       \
+                                                                               \
+      feraiseexcept(FE_ALL_EXCEPT);                                            \
+      ret = __builtin_feclearexcept(excepts);                                  \
+      raised = fetestexcept(FE_ALL_EXCEPT);                                    \
+      if (ret != 0 || raised != (FE_ALL_EXCEPT & ~(excepts)))                  \
+        FAIL(ret, raised, FE_ALL_EXCEPT & ~(excepts), excepts, #excepts,       \
+	     "__builtin_feclearexcept");                                       \
+    } while (0)
+
+int
+main ()
+{
+    TEST(0);
+    TEST(FE_ALL_EXCEPT);
+
+    TEST(FE_INVALID);
+    TEST(FE_DIVBYZERO);
+    TEST(FE_INEXACT);
+    TEST(FE_OVERFLOW);
+    TEST(FE_UNDERFLOW);
+
+    TEST(FE_INVALID | FE_DIVBYZERO);
+    TEST(FE_INVALID | FE_INEXACT);
+    TEST(FE_INVALID | FE_OVERFLOW);
+    TEST(FE_INVALID | FE_UNDERFLOW);
+    TEST(FE_DIVBYZERO | FE_INEXACT);
+    TEST(FE_DIVBYZERO | FE_OVERFLOW);
+    TEST(FE_DIVBYZERO | FE_UNDERFLOW);
+    TEST(FE_INEXACT | FE_OVERFLOW);
+    TEST(FE_INEXACT | FE_UNDERFLOW);
+    TEST(FE_OVERFLOW | FE_UNDERFLOW);
+
+    TEST(FE_INVALID | FE_DIVBYZERO | FE_INEXACT);
+    TEST(FE_INVALID | FE_DIVBYZERO | FE_OVERFLOW);
+    TEST(FE_INVALID | FE_DIVBYZERO | FE_UNDERFLOW);
+    TEST(FE_INVALID | FE_INEXACT | FE_OVERFLOW);
+    TEST(FE_INVALID | FE_INEXACT | FE_UNDERFLOW);
+    TEST(FE_INVALID | FE_OVERFLOW | FE_UNDERFLOW);
+    TEST(FE_DIVBYZERO | FE_INEXACT | FE_OVERFLOW);
+    TEST(FE_DIVBYZERO | FE_INEXACT | FE_UNDERFLOW);
+    TEST(FE_DIVBYZERO | FE_OVERFLOW | FE_UNDERFLOW);
+    TEST(FE_INEXACT | FE_OVERFLOW | FE_UNDERFLOW);
+
+    TEST(FE_INVALID | FE_DIVBYZERO | FE_INEXACT | FE_UNDERFLOW);
+    TEST(FE_INVALID | FE_DIVBYZERO | FE_INEXACT | FE_OVERFLOW);
+    TEST(FE_INVALID | FE_DIVBYZERO | FE_UNDERFLOW | FE_OVERFLOW);
+    TEST(FE_INVALID | FE_INEXACT | FE_UNDERFLOW | FE_OVERFLOW);
+    TEST(FE_DIVBYZERO | FE_INEXACT | FE_UNDERFLOW | FE_OVERFLOW);
+
+  return 0;
+}
diff --git a/gcc/testsuite/gcc.target/powerpc/builtin-fegetround.c b/gcc/testsuite/gcc.target/powerpc/builtin-fegetround.c
new file mode 100644
index 00000000000..56ffc50e3ee
--- /dev/null
+++ b/gcc/testsuite/gcc.target/powerpc/builtin-fegetround.c
@@ -0,0 +1,36 @@
+/* { dg-do run } */
+/* { dg-require-effective-target fenv_exceptions } */
+/* { dg-options "-lm -fno-builtin" } */
+
+/* This testcase ensures that the builtins is correctly expanded and match the
+   expected result from the standard function.
+   "-fno-builtin" option is used to enable calls to libc implementation of the
+   gcc builtins tested when not using __builtin_ prefix. */
+
+#include <fenv.h>
+
+#ifdef DEBUG
+#include <stdio.h>
+#define FAIL(v, e) printf("ERROR, __builtin_fegetround() returned %d," \
+                          " not the expecected value %d\n", v, e);
+#else
+void abort (void);
+#define FAIL(v, e) abort()
+#endif
+
+int
+main ()
+{
+  int i, rounding, expected;
+  const int rm[] = {FE_TONEAREST, FE_TOWARDZERO, FE_UPWARD, FE_DOWNWARD};
+  for (i = 0; i < sizeof rm / sizeof rm[0]; i++)
+    {
+      fesetround(rm[i]);
+      rounding = __builtin_fegetround();
+      expected = fegetround();
+      if (rounding != expected)
+        FAIL(rounding, expected);
+    }
+
+  return 0;
+}


^ permalink raw reply	[flat|nested] only message in thread

only message in thread, other threads:[~2022-01-24 17:00 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-01-24 17:00 [gcc r12-6848] rtl: builtins: (not just) rs6000: Add builtins for fegetround, feclearexcept and feraiseexcept [PR94 Segher Boessenkool

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).