[PATCH v8] rtl: builtins: (not just) rs6000: Add builtins for fegetround, feclearexcept and feraiseexcept [PR94193]
Raoni Fassina Firmino
raoni@linux.ibm.com
Fri Dec 24 23:28:40 GMT 2021
Changes since v7[7]:
- Fixed an array indexing bug on fegeround testcase.
- Fixed typos and spelling mistakes spread trouout the added comments.
- Reworded header comment/description for fegetround expander.
- Fixed changelog in the commit message.
After taking a look to add support for FE_INVALID I decided to not
include it in this patch. It is a little more nuanced case and it may be
the case that another type of treatment may be better suited for a case
that includes FE_INVALID, like a read-modify-write to FPSCR instead of
multiple mtfsb0/mtfsb1 instructions.
Tested on top of master (ef26c151c14a87177d46fd3d725e7f82e040e89f)
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.
==
I'm repeating the "changelog" from past versions here for convenience:
Changes since v6[6] and v5[5]:
- Based this version on the v5 one.
- Reworked all builtins back to the way they are in v5 and added the
following changes:
+ Added a test to target libc, only expanding with glibc as the
target libc.
+ Updated all three expanders header comment to reflect the added
behavior (fegetround got a full header as it had none).
+ Added extra documentation for the builtins on doc/extend.texi,
similar to v6 version, but only the introductory paragraph,
without a dedicated entry for each, since now they behavior and
signature match the C99 ones.
- Changed the description for the return operand in the RTL template
of the fegetround expander. Using "(set )", the same way as
rs6000_mffsl expander (this change was taken from v6).
- Updated the commit message mentioning the target libc restriction
and updated changelog.
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.
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 counterpart;
- 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 suggested 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/pipermail/gcc-patches/2021-October/581837.html
[7] https://gcc.gnu.org/pipermail/gcc-patches/2021-November/585375.html
---- 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.
The builtin expanders needs knowledge of the target libc's FE_*
values, so they are limited to expand only to suitable libcs.
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:
* 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.
* 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/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/builtins.c | 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 | 203 ++++++++++++++++++
.../gcc.target/powerpc/builtin-fegetround.c | 36 ++++
8 files changed, 531 insertions(+)
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/builtins.c b/gcc/builtins.c
index 00f6c5552bf5..510ed9b3fab0 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);
@@ -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. */
@@ -7035,6 +7091,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 9be484c7cf83..15d4f1c9ad8b 100644
--- a/gcc/config/rs6000/rs6000.md
+++ b/gcc/config/rs6000/rs6000.md
@@ -6865,6 +6865,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;
+})
;; 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 1f6af5d773e5..08a6d9c7dcce 100644
--- a/gcc/doc/extend.texi
+++ b/gcc/doc/extend.texi
@@ -13440,6 +13440,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 9ec051e94e10..c5ee85e97811 100644
--- a/gcc/doc/md.texi
+++ b/gcc/doc/md.texi
@@ -6069,6 +6069,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 cef6054b3781..fedb0aa68c71 100644
--- a/gcc/optabs.def
+++ b/gcc/optabs.def
@@ -330,6 +330,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..4482e89b0db9
--- /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 000000000000..62eab592ea35
--- /dev/null
+++ b/gcc/testsuite/gcc.target/powerpc/builtin-feclearexcept-feraiseexcept-2.c
@@ -0,0 +1,203 @@
+/* { 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>
+
+#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..56ffc50e3ee3
--- /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;
+}
--
2.31.1
More information about the Gcc-patches
mailing list