public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
From: Raoni Fassina Firmino <raoni@linux.ibm.com>
To: gcc-patches@gcc.gnu.org
Cc: segher@kernel.crashing.org, joseph@codesourcery.com,
	jakub@redhat.com, rguenther@suse.de, hp@bitrange.com,
	law@redhat.com, will_schmidt@vnet.ibm.com
Subject: [PATCH v6] rtl: builtins: (not just) rs6000: Add builtins for fegetround, feclearexcept and feraiseexcept [PR94193]
Date: Sat, 16 Oct 2021 21:04:15 -0300	[thread overview]
Message-ID: <20211017000415.vqt5yyrq7j7kg5c4@work-tp> (raw)

Changes since v5[5]:
  - Reworked all builtins to accept the FE_* macros as parameters and
    so be agnostic to libc implementations.  Largely based of
    fpclassify.  To that end, there is some new files changed:
    + Change the argument list for the builtins declarations in
      builtins.def
    + Added new types in builtin-types.def to use in the buitins
      declarations.
    + Added extra documentation for the builtins on doc/extend.texi,
      similar to fpclassify.
  - Updated doc/md.texi documentation with the new optab behaviors.
  - Updated comments to the expanders and expand handlers to try to
    explain whats is going on.
  - Changed the description for the return operand in the RTL template
    of the fegetround expander.  Using "(set )", the same way as
    rs6000_mffsl expander.
  - Updated testcases with helper macros with the new argument list.

Tested on top of master (f7571527a44808cd7062c77bb9570c13f4f6a126)
on the following plataforms with no regression:
  - powerpc64le-linux-gnu (Power 9)
  - powerpc64le-linux-gnu (Power 8)
  - powerpc64-linux-gnu (Power 9, with 32 and 64 bits tests)

Documentation changes tested on x86_64-redhat-linux.

This approach left me with some hanging problems that I am not quite
sure how to go about it.

First is the different arguments from the C99 functions.  I think the
solution is a macro to correct this, like so:

    #define feclearexcept(excepts) \
        __builtin_feclearexcept(excepts, FE_DIVBYZERO, FE_INEXACT, \
                                FE_INVALID, FE_OVERFLOW, FE_UNDERFLOW)

That is automatically always included or included when fenv.h is
included.  Does the preprocessor have this ability? If so, where
should I put it?

But this solution seems to have a problem that it will bypass
-fno-builtin, unless there can be a conditional check for it on the
preprocessor.

Second is the fallback of the expanders.  When the expanders fail it
will leave the function call, which is great, but since the argument
list is different, well, it not is pretty.  There is no execution
problem, since the builtins only having extra arguments, but it
generate extra unnecessary code. Here is an example, a snipped of the
generated assembly from the builtin-feclearexcept-feraiseexcept-1.c
testcase:

    # builtin-feclearexcept-feraiseexcept-1.c:36: __builtin_feclearexcept(FE_INVALID);  // CALL
    lis %r8,0x800
    lis %r7,0x1000
    lis %r6,0x2000
    lis %r5,0x200
    lis %r4,0x400
    lis %r3,0x2000
    bl feclearexcept

I assume I can modify the RTL to remove the unneeded arguments.  If
so, there is pointer where this is done or how I can do it?

I'm also adding some extra documentation for the builtins section, the
doc/extend.texi, close to where the fpclassify documentation is[6],
but I don't know if I'm doing it right, especially changing such a
front facing documentation.

I'm repeating the "changelog" from past versions here for convenience:

Changes since v4[4]:
  - Fixed more spelling and code style.
  - Add more clarification on  comments for feraiseexcept and
    feclearexcept expands;

Changes since v3[3]:
  - Fixed fegetround bug on powerpc64 (big endian) that Segher
    spotted;

Changes since v2[2]:
  - Added documentation for the new optabs;
  - Remove use of non portable __builtin_clz;
  - Changed feclearexcept and feraiseexcept to accept all 4 valid
    flags at the same time and added more test for that case;
  - Extended feclearexcept and feraiseexcept testcases to match
    accepting multiple flags;
  - Fixed builtin-feclearexcept-feraiseexcept-2.c testcase comparison
    after feclearexcept tests;
  - Updated commit message to reflect change in feclearexcept and
    feraiseexcept from the glibc conterpart;
  - Fixed English spelling and typos;
  - Fixed code-style;
  - Changed subject line tag to make clear it is not just rs6000 code.

Changes since v1[1]:
  - Fixed english spelling;
  - Fixed code-style;
  - Changed match operand predicate in feclearexcept and feraiseexcept;
  - Changed testcase options;
  - Minor changes in test code to be C90 compatible;
  - Other minor changes sugested by Segher;
  - Changed subject line tag (not sure if I tagged correctly or should
    include optabs: also)

[1] https://gcc.gnu.org/pipermail/gcc-patches/2020-August/552024.html
[2] https://gcc.gnu.org/pipermail/gcc-patches/2020-September/553297.html
[3] https://gcc.gnu.org/pipermail/gcc-patches/2020-October/557109.html
[4] https://gcc.gnu.org/pipermail/gcc-patches/2020-October/557349.html
[5] https://gcc.gnu.org/pipermail/gcc-patches/2020-November/557984.html
[6] https://gcc.gnu.org/onlinedocs/gcc/Other-Builtins.html#Other-Builtins

---- 8< ----

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.

There is signature changes to all three builtins relative to the
correspondent libc function, the extra arguments add a way to make the
builtins work agnostic of the libc implementations.

The associated bugreport: PR target/94193

[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/ChangeLog:

        * builtin-types.def (BT_FN_INT_INT_INT_INT_INT): New type.
        (BT_FN_INT_INT_INT_INT_INT_INT_INT): New type.
        * builtins.c (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
        * builtins.def (BUILT_IN_FECLEAREXCEPT): Change type.
        (BUILT_IN_FEGETROUND): Change type.
        (BUILT_IN_FERAISEEXCEPT): Change type.
        * 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.
        (__builtin_feclearexcept): Document new builtin.
        (__builtin_feclearexcept): Document new builtin.
        (__builtin_feraiseexcept): Document new builtin.
        * 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/ChangeLog:

        * 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>
---
 gcc/builtin-types.def                         |   4 +
 gcc/builtins.c                                | 100 +++++++++
 gcc/builtins.def                              |   6 +-
 gcc/config/rs6000/rs6000.md                   | 163 ++++++++++++++
 gcc/doc/extend.texi                           |  51 +++++
 gcc/doc/md.texi                               |  21 ++
 gcc/optabs.def                                |   4 +
 .../builtin-feclearexcept-feraiseexcept-1.c   |  82 +++++++
 .../builtin-feclearexcept-feraiseexcept-2.c   | 209 ++++++++++++++++++
 .../gcc.target/powerpc/builtin-fegetround.c   |  39 ++++
 10 files changed, 676 insertions(+), 3 deletions(-)
 create mode 100644 gcc/testsuite/gcc.target/powerpc/builtin-feclearexcept-feraiseexcept-1.c
 create mode 100644 gcc/testsuite/gcc.target/powerpc/builtin-feclearexcept-feraiseexcept-2.c
 create mode 100644 gcc/testsuite/gcc.target/powerpc/builtin-fegetround.c

diff --git a/gcc/builtin-types.def b/gcc/builtin-types.def
index d160826e1d4f..0520772801e6 100644
--- a/gcc/builtin-types.def
+++ b/gcc/builtin-types.def
@@ -680,6 +680,8 @@ DEF_FUNCTION_TYPE_4 (BT_FN_BOOL_UINT_ULLPTR_ULLPTR_ULLPTR,
 		     BT_PTR_ULONGLONG)
 DEF_FUNCTION_TYPE_4 (BT_FN_VOID_UINT_PTR_INT_PTR, BT_VOID, BT_INT, BT_PTR,
 		     BT_INT, BT_PTR)
+DEF_FUNCTION_TYPE_4 (BT_FN_INT_INT_INT_INT_INT,
+		     BT_INT, BT_INT, BT_INT, BT_INT, BT_INT)
 
 DEF_FUNCTION_TYPE_5 (BT_FN_INT_STRING_INT_SIZE_CONST_STRING_VALIST_ARG,
 		     BT_INT, BT_STRING, BT_INT, BT_SIZE, BT_CONST_STRING,
@@ -737,6 +739,8 @@ DEF_FUNCTION_TYPE_6 (BT_FN_BOOL_VPTR_PTR_I16_BOOL_INT_INT,
 		     BT_INT)
 DEF_FUNCTION_TYPE_6 (BT_FN_BOOL_SIZE_VPTR_PTR_PTR_INT_INT, BT_BOOL, BT_SIZE,
 		     BT_VOLATILE_PTR, BT_PTR, BT_PTR, BT_INT, BT_INT)
+DEF_FUNCTION_TYPE_6 (BT_FN_INT_INT_INT_INT_INT_INT_INT,
+		     BT_INT, BT_INT, BT_INT, BT_INT, BT_INT, BT_INT, BT_INT)
 
 DEF_FUNCTION_TYPE_7 (BT_FN_VOID_OMPFN_PTR_UINT_LONG_LONG_LONG_UINT,
 		     BT_VOID, BT_PTR_FN_VOID_PTR, BT_PTR, BT_UINT,
diff --git a/gcc/builtins.c b/gcc/builtins.c
index f1c3fea3583d..da51ed25711a 100644
--- a/gcc/builtins.c
+++ b/gcc/builtins.c
@@ -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);
@@ -2527,6 +2530,83 @@ expand_builtin_sincos (tree exp)
   return const0_rtx;
 }
 
+/* Expand call EXP to __builtin_fegetround(int, int, int, int), returning the
+   result and setting it in TARGET.  Otherwise return NULL_RTX on failure.
+   This builtin implements fegetround (from C99 fenv.h) and will generate code
+   to return the current floating point rounding mode.  The possible return
+   values must be supplied as int arguments to the call in the following order:
+   FE_DOWNWARD, FE_TONEAREST, FE_TOWARDZERO and FE_UPWARD. This enables the
+   builtin to work agnostic of the c library's values for the rounding modes. */
+static rtx
+expand_builtin_fegetround (tree exp, rtx target, machine_mode target_mode)
+{
+  if (!validate_arglist (exp, INTEGER_TYPE, INTEGER_TYPE,
+			 INTEGER_TYPE, INTEGER_TYPE, 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 op0 = expand_normal (CALL_EXPR_ARG (exp, 0));
+  rtx op1 = expand_normal (CALL_EXPR_ARG (exp, 1));
+  rtx op2 = expand_normal (CALL_EXPR_ARG (exp, 2));
+  rtx op3 = expand_normal (CALL_EXPR_ARG (exp, 3));
+
+  rtx pat = GEN_FCN (icode) (target, op0, op1, op2, op3);
+  if (!pat)
+    return NULL_RTX;
+  emit_insn (pat);
+
+  return target;
+}
+
+/* Expand call EXP to __builtin_feclearexcept(int, int, int, int, int, int) or
+   or __builtin_feraiseexcept(int, int, int, int, int, int), returning the
+   result and setting it in TARGET.  Otherwise return NULL_RTX on failure.
+   This builtins implements feclearexcept and feraiseexcept (from C99 fenv.h)
+   and will generate code to clear or raise floating point exceptions supplied
+   as the first argument.  The possible exceptions values must be supplied as
+   the last five int arguments to the call in the following order: FE_DIVBYZERO,
+   FE_INEXACT, FE_INVALID, FE_OVERFLOW, FE_UNDERFLOW. This enables the
+   builtin work agnostic of the c library's values for the exceptions. */
+static rtx
+expand_builtin_feclear_feraise_except (tree exp, rtx target,
+				       machine_mode target_mode, optab op_optab)
+{
+  if (!validate_arglist (exp, INTEGER_TYPE, INTEGER_TYPE, INTEGER_TYPE,
+			 INTEGER_TYPE, INTEGER_TYPE, INTEGER_TYPE, VOID_TYPE))
+    return NULL_RTX;
+
+  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 op0 = expand_normal (CALL_EXPR_ARG (exp, 0));
+  rtx op1 = expand_normal (CALL_EXPR_ARG (exp, 1));
+  rtx op2 = expand_normal (CALL_EXPR_ARG (exp, 2));
+  rtx op3 = expand_normal (CALL_EXPR_ARG (exp, 3));
+  rtx op4 = expand_normal (CALL_EXPR_ARG (exp, 4));
+  rtx op5 = expand_normal (CALL_EXPR_ARG (exp, 5));
+
+  rtx pat = GEN_FCN (icode) (target, op0, op1, op2, op3, op4, op5);
+  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.  */
@@ -7033,6 +7113,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/builtins.def b/gcc/builtins.def
index 45a09b4d42de..65157f3e21c0 100644
--- a/gcc/builtins.def
+++ b/gcc/builtins.def
@@ -364,12 +364,12 @@ DEF_C2X_BUILTIN        (BUILT_IN_FABSD128, "fabsd128", BT_FN_DFLOAT128_DFLOAT128
 DEF_C99_BUILTIN        (BUILT_IN_FDIM, "fdim", BT_FN_DOUBLE_DOUBLE_DOUBLE, ATTR_MATHFN_FPROUNDING_ERRNO)
 DEF_C99_BUILTIN        (BUILT_IN_FDIMF, "fdimf", BT_FN_FLOAT_FLOAT_FLOAT, ATTR_MATHFN_FPROUNDING_ERRNO)
 DEF_C99_BUILTIN        (BUILT_IN_FDIML, "fdiml", BT_FN_LONGDOUBLE_LONGDOUBLE_LONGDOUBLE, ATTR_MATHFN_FPROUNDING_ERRNO)
-DEF_C99_BUILTIN        (BUILT_IN_FECLEAREXCEPT, "feclearexcept", BT_FN_INT_INT, ATTR_NOTHROW_LEAF_LIST)
+DEF_C99_BUILTIN        (BUILT_IN_FECLEAREXCEPT, "feclearexcept", BT_FN_INT_INT_INT_INT_INT_INT_INT, ATTR_NOTHROW_LEAF_LIST)
 DEF_C99_BUILTIN        (BUILT_IN_FEGETENV, "fegetenv", BT_FN_INT_FENV_T_PTR, ATTR_NOTHROW_LEAF_LIST)
 DEF_C99_BUILTIN        (BUILT_IN_FEGETEXCEPTFLAG, "fegetexceptflag", BT_FN_INT_FEXCEPT_T_PTR_INT, ATTR_NOTHROW_LEAF_LIST)
-DEF_C99_BUILTIN        (BUILT_IN_FEGETROUND, "fegetround", BT_FN_INT, ATTR_PURE_NOTHROW_LEAF_LIST)
+DEF_C99_BUILTIN        (BUILT_IN_FEGETROUND, "fegetround", BT_FN_INT_INT_INT_INT_INT, ATTR_PURE_NOTHROW_LEAF_LIST)
 DEF_C99_BUILTIN        (BUILT_IN_FEHOLDEXCEPT, "feholdexcept", BT_FN_INT_FENV_T_PTR, ATTR_NOTHROW_LEAF_LIST)
-DEF_C99_BUILTIN        (BUILT_IN_FERAISEEXCEPT, "feraiseexcept", BT_FN_INT_INT, ATTR_NULL)
+DEF_C99_BUILTIN        (BUILT_IN_FERAISEEXCEPT, "feraiseexcept", BT_FN_INT_INT_INT_INT_INT_INT_INT, ATTR_NULL)
 DEF_C99_BUILTIN        (BUILT_IN_FESETENV, "fesetenv", BT_FN_INT_CONST_FENV_T_PTR, ATTR_NOTHROW_LEAF_LIST)
 DEF_C99_BUILTIN        (BUILT_IN_FESETEXCEPTFLAG, "fesetexceptflag", BT_FN_INT_CONST_FEXCEPT_T_PTR_INT, ATTR_NULL)
 DEF_C99_BUILTIN        (BUILT_IN_FESETROUND, "fesetround", BT_FN_INT_INT, ATTR_NOTHROW_LEAF_LIST)
diff --git a/gcc/config/rs6000/rs6000.md b/gcc/config/rs6000/rs6000.md
index 6bec2bddbdee..1161aa831258 100644
--- a/gcc/config/rs6000/rs6000.md
+++ b/gcc/config/rs6000/rs6000.md
@@ -6860,6 +6860,169 @@
   [(set_attr "type" "fpload")
    (set_attr "length" "8")
    (set_attr "isa" "*,p8v,p8v")])
+
+;; int __builtin_fegetround(int, int, int, int)
+;;
+;; This built-in implements the C99 fegetround functionality.
+;; The four int arguments should be the target library's notion of the
+;; possible FP rouding modes.  They must be constant values and they
+;; must appear in this order: FE_DOWNWARD, FE_TONEAREST,
+;; FE_TOWARDZERO, FE_UPWARD.  In other words:
+;;
+;;     __builtin_fegetround(FE_DOWNWARD, FE_TONEAREST,
+;;                          FE_TOWARDZERO, FE_UPWARD)
+;;
+;; This values are used to match the processor values for the rounding
+;; mode with the target library's.  For now, to avoid the cost of
+;; converting between them, the behavior is to not expand if they are
+;; different and fallback to a call to libc.
+(define_expand "fegetroundsi"
+  [(use (match_operand:SI 4 "const_int_operand" "n"))
+   (use (match_operand:SI 3 "const_int_operand" "n"))
+   (use (match_operand:SI 2 "const_int_operand" "n"))
+   (use (match_operand:SI 1 "const_int_operand" "n"))
+   (set (match_operand:SI 0 "gpc_reg_operand")
+	(unspec_volatile:SI [(const_int 0)] UNSPECV_MFFSL))]
+  "TARGET_HARD_FLOAT"
+{
+  unsigned int fe_downward = INTVAL (operands[1]);
+  unsigned int fe_tonearest = INTVAL (operands[2]);
+  unsigned int fe_towardzero = INTVAL (operands[3]);
+  unsigned int fe_upward = INTVAL (operands[4]);
+
+  if (fe_downward != 3
+      || fe_tonearest != 0
+      || fe_towardzero != 1
+      || fe_upward != 2)
+    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 __builtin_feclearexcept(int, int, int, int, int, int)
+;;
+;; This built-in implements the C99 feclearexcept functionality.  The
+;; first argument is the original feclearexcept() EXCEPTS argument.
+;; The other five int arguments should be the target library's notion
+;; of the possible FP exceptions.  They must be constant values and
+;; they must appear in this order: FE_DIVBYZERO, FE_INEXACT,
+;; FE_INVALID, FE_OVERFLOW, FE_UNDERFLOW.  In other words:
+;;
+;;     __builtin_feclearexcept(excepts, FE_DIVBYZERO, FE_INEXACT,
+;;                             FE_INVALID, FE_OVERFLOW, FE_UNDERFLOW)
+;;
+;; This values are used to match the processor values for the
+;; exception with the target library's.
+;; This expansion for the builtin only works when EXCEPTS (the last
+;; argument) 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.
+;; 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 6 "const_int_operand" "n"))
+   (use (match_operand:SI 5 "const_int_operand" "n"))
+   (use (match_operand:SI 4 "const_int_operand" "n"))
+   (use (match_operand:SI 3 "const_int_operand" "n"))
+   (use (match_operand:SI 2 "const_int_operand" "n"))
+   (use (match_operand:SI 1 "const_int_operand" "n"))
+   (set (match_operand:SI 0 "gpc_reg_operand") (const_int 0))]
+  "TARGET_HARD_FLOAT"
+{
+  unsigned int excepts = INTVAL (operands[1]);
+  unsigned int fe_divbyzero = INTVAL (operands[2]);
+  unsigned int fe_inexact = INTVAL (operands[3]);
+  unsigned int fe_overflow = INTVAL (operands[5]);
+  unsigned int fe_underflow = INTVAL (operands[6]);
+  unsigned int valid_excepts = fe_divbyzero
+			       | fe_inexact
+			       | fe_overflow
+			       | fe_underflow;
+
+  if (excepts != (excepts & valid_excepts))
+    FAIL;
+
+  if (excepts & fe_divbyzero)
+    emit_insn (gen_rs6000_mtfsb0 (gen_rtx_CONST_INT (SImode, 5)));
+  if (excepts & fe_inexact)
+    emit_insn (gen_rs6000_mtfsb0 (gen_rtx_CONST_INT (SImode, 6)));
+  if (excepts & fe_underflow)
+    emit_insn (gen_rs6000_mtfsb0 (gen_rtx_CONST_INT (SImode, 4)));
+  if (excepts & fe_overflow)
+    emit_insn (gen_rs6000_mtfsb0 (gen_rtx_CONST_INT (SImode, 3)));
+
+  emit_move_insn (operands[0], const0_rtx);
+  DONE;
+})
+
+;; int __builtin_feraiseexcept(int, int, int, int, int, int)
+;;
+;; This built-in implements the C99 feraiseexcept functionality.  The
+;; first argument is the original feraiseexcept() EXCEPTS argument.
+;; The other five int arguments should be the target library's notion
+;; of the possible FP exceptions.  They must be constant values and
+;; they must appear in this order: FE_DIVBYZERO, FE_INEXACT,
+;; FE_INVALID, FE_OVERFLOW, FE_UNDERFLOW.  In other words:
+;;
+;;     __builtin_feraiseexcept(excepts, FE_DIVBYZERO, FE_INEXACT,
+;;                             FE_INVALID, FE_OVERFLOW, FE_UNDERFLOW)
+;;
+;; This values are used to match the processor values for the
+;; exception with the target library's.
+;; This expansion for the builtin only works when EXCEPTS (the last
+;; argument) 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.
+;; 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 6 "const_int_operand" "n"))
+   (use (match_operand:SI 5 "const_int_operand" "n"))
+   (use (match_operand:SI 4 "const_int_operand" "n"))
+   (use (match_operand:SI 3 "const_int_operand" "n"))
+   (use (match_operand:SI 2 "const_int_operand" "n"))
+   (use (match_operand:SI 1 "const_int_operand" "n"))
+   (set (match_operand:SI 0 "gpc_reg_operand") (const_int 0))]
+  "TARGET_HARD_FLOAT"
+{
+  unsigned int excepts = INTVAL (operands[1]);
+  unsigned int fe_divbyzero = INTVAL (operands[2]);
+  unsigned int fe_inexact = INTVAL (operands[3]);
+  unsigned int fe_overflow = INTVAL (operands[5]);
+  unsigned int fe_underflow = INTVAL (operands[6]);
+  unsigned int valid_excepts = fe_divbyzero
+			       | fe_inexact
+			       | fe_overflow
+			       | fe_underflow;
+
+  if (excepts != (excepts & valid_excepts))
+    FAIL;
+
+  if (excepts & fe_divbyzero)
+    emit_insn (gen_rs6000_mtfsb1 (gen_rtx_CONST_INT (SImode, 5)));
+  if (excepts & fe_inexact)
+    emit_insn (gen_rs6000_mtfsb1 (gen_rtx_CONST_INT (SImode, 6)));
+  if (excepts & fe_underflow)
+    emit_insn (gen_rs6000_mtfsb1 (gen_rtx_CONST_INT (SImode, 4)));
+  if (excepts & 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 10d466fae9a4..fdd76579ce33 100644
--- a/gcc/doc/extend.texi
+++ b/gcc/doc/extend.texi
@@ -12858,6 +12858,9 @@ is called and the @var{flag} argument passed to it.
 @findex __builtin_alloca_with_align_and_max
 @findex __builtin_call_with_static_chain
 @findex __builtin_extend_pointer
+@findex __builtin_feclearexcept
+@findex __builtin_fegetround
+@findex __builtin_feraiseexcept
 @findex __builtin_fpclassify
 @findex __builtin_has_attribute
 @findex __builtin_isfinite
@@ -13424,6 +13427,16 @@ 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}. This built-in versions take extra arguments to describe
+the c library's notion of the possible rounding modes and exceptions values and
+are used internally to enable an transparent approach independent of the c
+library used.  We intend for a library implementer to be able to simply
+@code{#define} each function to its built-in equivalent with the extra
+arguments.  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
@@ -14197,6 +14210,44 @@ Similar to @code{__builtin_huge_val}, except the return type is
 @code{_Float@var{n}x}.
 @end deftypefn
 
+@deftypefn {Built-in Function} int __builtin_fegetround (int, int, int, int)
+This built-in implements the C99 fegetround functionality.  The four int
+arguments should be the target library's notion of the possible FP rouding
+modes.  They must be constant values and they must appear in this order:
+@code{FE_DOWNWARD}, @code{FE_TONEAREST}, @code{FE_TOWARDZERO},
+@code{FE_UPWARD}.  In other words:
+
+@smallexample
+__builtin_fegetround(FE_DOWNWARD, FE_TONEAREST,
+                     FE_TOWARDZERO, FE_UPWARD)
+@end smallexample
+
+This values are used to match the processor values for the rounding
+mode with the target library's.
+@end deftypefn
+
+@deftypefn {Built-in Function} int __builtin_feclearexcept (int, int, int, int, int, int)
+This built-in implements the C99 feclearexcept functionality.  The first
+argument is the original feclearexcept() EXCEPTS argument.  The other five int
+arguments should be the target library's notion of the possible FP exceptions.
+They must be constant values and they must appear in this order:
+@code{FE_DIVBYZERO}, @code{FE_INEXACT}, @code{FE_INVALID}, @code{FE_OVERFLOW},
+@code{FE_UNDERFLOW}.  In other words:
+
+@smallexample
+__builtin_feclearexcept(excepts, FE_DIVBYZERO, FE_INEXACT,
+                        FE_INVALID, FE_OVERFLOW, FE_UNDERFLOW)
+@end smallexample
+
+This values are used to match the processor values for the exception with the
+target library's.
+@end deftypefn
+
+@deftypefn {Built-in Function} int __builtin_feraiseexcept (int, int, int, int, int, int)
+Analogous to @code{__builtin_feclearexcept}, except to raise excepts instead of
+clearing and all arguments have the same semantics.
+@end deftypefn
+
 @deftypefn {Built-in Function} int __builtin_fpclassify (int, int, int, int, int, ...)
 This built-in implements the C99 fpclassify functionality.  The first
 five int arguments should be the target library's notion of the
diff --git a/gcc/doc/md.texi b/gcc/doc/md.texi
index 41f1850bf6e9..9b39a09f1892 100644
--- a/gcc/doc/md.texi
+++ b/gcc/doc/md.texi
@@ -6053,6 +6053,27 @@ 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.
+Libc values for FE_DOWNWARD, FE_TONEAREST, FE_TOWARDZERO and FE_UPWARD
+are passed to operands 1, 2, 3 and 4 respectively.  All operands have
+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.  Libc values for FE_DIVBYZERO,
+FE_INEXACT, FE_INVALID, FE_OVERFLOW and FE_UNDERFLOW are passed to
+operands 2, 3, 4, 5 and 6 respectively.  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 f02c7b729a51..49f8d33bcf0d 100644
--- a/gcc/optabs.def
+++ b/gcc/optabs.def
@@ -327,6 +327,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 000000000000..f8c3b072fe3f
--- /dev/null
+++ b/gcc/testsuite/gcc.target/powerpc/builtin-feclearexcept-feraiseexcept-1.c
@@ -0,0 +1,82 @@
+/* { 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>
+
+#define __builtin_feraiseexcept(x) \
+        __builtin_feraiseexcept(x, FE_DIVBYZERO, FE_INEXACT, FE_INVALID, FE_OVERFLOW, FE_UNDERFLOW)
+
+#define __builtin_feclearexcept(x) \
+        __builtin_feclearexcept(x, FE_DIVBYZERO, FE_INEXACT, FE_INVALID, FE_OVERFLOW, FE_UNDERFLOW)
+
+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 000000000000..397396623532
--- /dev/null
+++ b/gcc/testsuite/gcc.target/powerpc/builtin-feclearexcept-feraiseexcept-2.c
@@ -0,0 +1,209 @@
+/* { 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. */
+
+#include <fenv.h>
+
+#define __builtin_feraiseexcept(x) \
+        __builtin_feraiseexcept(x, FE_DIVBYZERO, FE_INEXACT, FE_INVALID, FE_OVERFLOW, FE_UNDERFLOW)
+
+#define __builtin_feclearexcept(x) \
+        __builtin_feclearexcept(x, FE_DIVBYZERO, FE_INEXACT, FE_INVALID, FE_OVERFLOW, FE_UNDERFLOW)
+
+#ifdef DEBUG
+#include <stdio.h>
+#define INFO(...) printf(__VA_ARGS__)
+#define FAIL(v, e, x, s, f) \
+        printf("ERROR [l %d] testing %s(%x): %s returned %x," \
+               " expecected %x\n", __LINE__, s, x, f, v, e)
+#else
+void abort (void);
+#define INFO(...)
+#define FAIL(v, e, x, s, f) abort()
+#endif
+
+int
+main ()
+{
+  char *s = 0;
+  int e = 0;
+  int raised = 0;
+
+  s = "FE_ALL_EXCEPT";
+  e = FE_ALL_EXCEPT;
+  INFO("test: %s(%x)\n", s, e);
+
+  feclearexcept(FE_ALL_EXCEPT);
+  __builtin_feraiseexcept(FE_ALL_EXCEPT);
+  raised = fetestexcept(FE_ALL_EXCEPT);
+  if (raised != e)
+    FAIL(raised, e, e, s, "__builtin_feraiseexcept");
+
+  feraiseexcept(FE_ALL_EXCEPT);
+  __builtin_feclearexcept(FE_ALL_EXCEPT);
+  raised = fetestexcept(FE_ALL_EXCEPT);
+  if (raised != (FE_ALL_EXCEPT & ~e))
+    FAIL(raised, FE_ALL_EXCEPT & ~e, e, s, "__builtin_feclearexcept");
+
+
+  s = "NONE";
+  e = 0;
+  INFO("test: %s(%x)\n", s, e);
+
+  feclearexcept(FE_ALL_EXCEPT);
+  __builtin_feraiseexcept(0);
+  raised = fetestexcept(FE_ALL_EXCEPT);
+  if (raised != e)
+    FAIL(raised, e, e, s, "__builtin_feraiseexcept");
+
+  feraiseexcept(FE_ALL_EXCEPT);
+  __builtin_feclearexcept(0);
+  raised = fetestexcept(FE_ALL_EXCEPT);
+  if (raised != (FE_ALL_EXCEPT & ~e))
+    FAIL(raised, FE_ALL_EXCEPT & ~e, e, s, "__builtin_feclearexcept");
+
+
+  s = "FE_DIVBYZERO";
+  e = FE_DIVBYZERO;
+  INFO("test: %s(%x)\n", s, e);
+
+  feclearexcept(FE_ALL_EXCEPT);
+  __builtin_feraiseexcept(FE_DIVBYZERO);
+  raised = fetestexcept(FE_ALL_EXCEPT);
+  if (raised != e)
+    FAIL(raised, e, e, s, "__builtin_feraiseexcept");
+
+  feraiseexcept(FE_ALL_EXCEPT);
+  __builtin_feclearexcept(FE_DIVBYZERO);
+  raised = fetestexcept(FE_ALL_EXCEPT);
+  if (raised != (FE_ALL_EXCEPT & ~e))
+    FAIL(raised, FE_ALL_EXCEPT & ~e, e, s, "__builtin_feclearexcept");
+
+
+  s = "FE_INEXACT";
+  e = FE_INEXACT;
+  INFO("test: %s(%x)\n", s, e);
+
+  feclearexcept(FE_ALL_EXCEPT);
+  __builtin_feraiseexcept(FE_INEXACT);
+  raised = fetestexcept(FE_ALL_EXCEPT);
+  if (raised != e)
+    FAIL(raised, e, e, s, "__builtin_feraiseexcept");
+
+  feraiseexcept(FE_ALL_EXCEPT);
+  __builtin_feclearexcept(FE_INEXACT);
+  raised = fetestexcept(FE_ALL_EXCEPT);
+  if (raised != (FE_ALL_EXCEPT & ~e))
+    FAIL(raised, FE_ALL_EXCEPT & ~e, e, s, "__builtin_feclearexcept");
+
+
+  s = "FE_OVERFLOW";
+  e = FE_OVERFLOW;
+  INFO("test: %s(%x)\n", s, e);
+
+  feclearexcept(FE_ALL_EXCEPT);
+  __builtin_feraiseexcept(FE_OVERFLOW);
+  raised = fetestexcept(FE_ALL_EXCEPT);
+  if (raised != e)
+    FAIL(raised, e, e, s, "__builtin_feraiseexcept");
+
+  feraiseexcept(FE_ALL_EXCEPT);
+  __builtin_feclearexcept(FE_OVERFLOW);
+  raised = fetestexcept(FE_ALL_EXCEPT);
+  if (raised != (FE_ALL_EXCEPT & ~e))
+    FAIL(raised, FE_ALL_EXCEPT & ~e, e, s, "__builtin_feclearexcept");
+
+
+  s = "FE_UNDERFLOW";
+  e = FE_UNDERFLOW;
+  INFO("test: %s(%x)\n", s, e);
+
+  feclearexcept(FE_ALL_EXCEPT);
+  __builtin_feraiseexcept(FE_UNDERFLOW);
+  raised = fetestexcept(FE_ALL_EXCEPT);
+  if (raised != e)
+    FAIL(raised, e, e, s, "__builtin_feraiseexcept");
+
+  feraiseexcept(FE_ALL_EXCEPT);
+  __builtin_feclearexcept(FE_UNDERFLOW);
+  raised = fetestexcept(FE_ALL_EXCEPT);
+  if (raised != (FE_ALL_EXCEPT & ~e))
+    FAIL(raised, FE_ALL_EXCEPT & ~e, e, s, "__builtin_feclearexcept");
+
+
+  s = "FE_INVALID";
+  e = FE_INVALID;
+  INFO("test: %s(%x)\n", s, e);
+
+  feclearexcept(FE_ALL_EXCEPT);
+  __builtin_feraiseexcept(FE_INVALID);
+  raised = fetestexcept(FE_ALL_EXCEPT);
+  if (raised != e)
+    FAIL(raised, e, e, s, "__builtin_feraiseexcept");
+
+  feraiseexcept(FE_ALL_EXCEPT);
+  __builtin_feclearexcept(FE_INVALID);
+  raised = fetestexcept(FE_ALL_EXCEPT);
+  if (raised != (FE_ALL_EXCEPT & ~e))
+    FAIL(raised, FE_ALL_EXCEPT & ~e, e, s, "__builtin_feclearexcept");
+
+
+  s = "FE_INVALID | FE_INEXACT";
+  e = FE_INVALID | FE_INEXACT;
+  INFO("test: %s(%x)\n", s, e);
+
+  feclearexcept(FE_ALL_EXCEPT);
+  __builtin_feraiseexcept(FE_INVALID | FE_INEXACT);
+  raised = fetestexcept(FE_ALL_EXCEPT);
+  if (raised != e)
+    FAIL(raised, e, e, s, "__builtin_feraiseexcept");
+
+  feraiseexcept(FE_ALL_EXCEPT);
+  __builtin_feclearexcept(FE_INVALID | FE_INEXACT);
+  raised = fetestexcept(FE_ALL_EXCEPT);
+  if (raised != (FE_ALL_EXCEPT & ~e))
+    FAIL(raised, FE_ALL_EXCEPT & ~e, e, s, "__builtin_feclearexcept");
+
+
+  s = "FE_INEXACT | FE_OVERFLOW";
+  e = FE_INEXACT | FE_OVERFLOW;
+  INFO("test: %s(%x)\n", s, e);
+
+  feclearexcept(FE_ALL_EXCEPT);
+  __builtin_feraiseexcept(FE_INEXACT | FE_OVERFLOW);
+  raised = fetestexcept(FE_ALL_EXCEPT);
+  if (raised != e)
+    FAIL(raised, e, e, s, "__builtin_feraiseexcept");
+
+  feraiseexcept(FE_ALL_EXCEPT);
+  __builtin_feclearexcept(FE_INEXACT | FE_OVERFLOW);
+  raised = fetestexcept(FE_ALL_EXCEPT);
+  if (raised != (FE_ALL_EXCEPT & ~e))
+    FAIL(raised, FE_ALL_EXCEPT & ~e, e, s, "__builtin_feclearexcept");
+
+
+  s = "FE_INEXACT | FE_DIVBYZERO | FE_UNDERFLOW | FE_OVERFLOW";
+  e = FE_INEXACT | FE_DIVBYZERO | FE_UNDERFLOW | FE_OVERFLOW;
+  INFO("test: %s(%x)\n", s, e);
+
+  feclearexcept(FE_ALL_EXCEPT);
+  __builtin_feraiseexcept(FE_INEXACT | FE_DIVBYZERO |
+                          FE_UNDERFLOW | FE_OVERFLOW);
+  raised = fetestexcept(FE_ALL_EXCEPT);
+  if (raised != e)
+    FAIL(raised, e, e, s, "__builtin_feraiseexcept");
+
+  feraiseexcept(FE_ALL_EXCEPT);
+  __builtin_feclearexcept(FE_INEXACT | FE_DIVBYZERO |
+                          FE_UNDERFLOW | FE_OVERFLOW);
+  raised = fetestexcept(FE_ALL_EXCEPT);
+  if (raised != (FE_ALL_EXCEPT & ~e))
+    FAIL(raised, FE_ALL_EXCEPT & ~e, e, s, "__builtin_feclearexcept");
+
+  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 000000000000..94238af6c287
--- /dev/null
+++ b/gcc/testsuite/gcc.target/powerpc/builtin-fegetround.c
@@ -0,0 +1,39 @@
+/* { 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>
+
+#define __builtin_fegetround(x) \
+        __builtin_fegetround(FE_DOWNWARD, FE_TONEAREST, FE_TOWARDZERO, FE_UPWARD)
+
+#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); i++)
+    {
+      fesetround(rm[i]);
+      rounding = __builtin_fegetround();
+      expected = fegetround();
+      if (rounding != expected)
+        FAIL(rounding, expected);
+    }
+
+  return 0;
+}
-- 
2.31.1


             reply	other threads:[~2021-10-17  0:04 UTC|newest]

Thread overview: 4+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2021-10-17  0:04 Raoni Fassina Firmino [this message]
2021-10-18 15:54 ` Joseph Myers
2021-11-24 20:22   ` Raoni Fassina Firmino
2021-11-24 21:32     ` Segher Boessenkool

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20211017000415.vqt5yyrq7j7kg5c4@work-tp \
    --to=raoni@linux.ibm.com \
    --cc=gcc-patches@gcc.gnu.org \
    --cc=hp@bitrange.com \
    --cc=jakub@redhat.com \
    --cc=joseph@codesourcery.com \
    --cc=law@redhat.com \
    --cc=rguenther@suse.de \
    --cc=segher@kernel.crashing.org \
    --cc=will_schmidt@vnet.ibm.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
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).