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;
+})
 
 ;; 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;
+}
