rtl: builtins: (not just) rs6000: Add builtins for fegetround, feclearexcept and feraiseexcept [PR94193]
This optimizations were originally in glibc, but was removed and suggested that they were a good fit as gcc builtins[1]. feclearexcept and feraiseexcept were extended (in comparison to the glibc version) to accept any combination of the accepted flags, not limited to just one flag bit at a time anymore. The builtin expanders needs knowledge of the target libc's FE_* values, so they are limited to expand only to suitable libcs. [1] https://sourceware.org/legacy-ml/libc-alpha/2020-03/msg00047.html https://sourceware.org/legacy-ml/libc-alpha/2020-03/msg00080.html 2020-08-13 Raoni Fassina Firmino <raoni@linux.ibm.com> gcc/ PR target/94193 * builtins.cc (expand_builtin_fegetround): New function. (expand_builtin_feclear_feraise_except): New function. (expand_builtin): Add cases for BUILT_IN_FEGETROUND, BUILT_IN_FECLEAREXCEPT and BUILT_IN_FERAISEEXCEPT. * config/rs6000/rs6000.md (fegetroundsi): New pattern. (feclearexceptsi): New Pattern. (feraiseexceptsi): New Pattern. * doc/extend.texi: Add a new introductory paragraph about the new builtins. * doc/md.texi: (fegetround@var{m}): Document new optab. (feclearexcept@var{m}): Document new optab. (feraiseexcept@var{m}): Document new optab. * optabs.def (fegetround_optab): New optab. (feclearexcept_optab): New optab. (feraiseexcept_optab): New optab. gcc/testsuite/ PR target/94193 * gcc.target/powerpc/builtin-feclearexcept-feraiseexcept-1.c: New test. * gcc.target/powerpc/builtin-feclearexcept-feraiseexcept-2.c: New test. * gcc.target/powerpc/builtin-fegetround.c: New test. Signed-off-by: Raoni Fassina Firmino <raoni@linux.ibm.com>
This commit is contained in:
parent
b1aa2a3cf1
commit
4343f5e256
@ -119,6 +119,9 @@ static rtx expand_builtin_mathfn_3 (tree, rtx, rtx);
|
||||
static rtx expand_builtin_mathfn_ternary (tree, rtx, rtx);
|
||||
static rtx expand_builtin_interclass_mathfn (tree, rtx);
|
||||
static rtx expand_builtin_sincos (tree);
|
||||
static rtx expand_builtin_fegetround (tree, rtx, machine_mode);
|
||||
static rtx expand_builtin_feclear_feraise_except (tree, rtx, machine_mode,
|
||||
optab);
|
||||
static rtx expand_builtin_cexpi (tree, rtx);
|
||||
static rtx expand_builtin_int_roundingfn (tree, rtx);
|
||||
static rtx expand_builtin_int_roundingfn_2 (tree, rtx);
|
||||
@ -2555,6 +2558,59 @@ expand_builtin_sincos (tree exp)
|
||||
return const0_rtx;
|
||||
}
|
||||
|
||||
/* Expand call EXP to the fegetround builtin (from C99 fenv.h), returning the
|
||||
result and setting it in TARGET. Otherwise return NULL_RTX on failure. */
|
||||
static rtx
|
||||
expand_builtin_fegetround (tree exp, rtx target, machine_mode target_mode)
|
||||
{
|
||||
if (!validate_arglist (exp, VOID_TYPE))
|
||||
return NULL_RTX;
|
||||
|
||||
insn_code icode = direct_optab_handler (fegetround_optab, SImode);
|
||||
if (icode == CODE_FOR_nothing)
|
||||
return NULL_RTX;
|
||||
|
||||
if (target == 0
|
||||
|| GET_MODE (target) != target_mode
|
||||
|| !(*insn_data[icode].operand[0].predicate) (target, target_mode))
|
||||
target = gen_reg_rtx (target_mode);
|
||||
|
||||
rtx pat = GEN_FCN (icode) (target);
|
||||
if (!pat)
|
||||
return NULL_RTX;
|
||||
emit_insn (pat);
|
||||
|
||||
return target;
|
||||
}
|
||||
|
||||
/* Expand call EXP to either feclearexcept or feraiseexcept builtins (from C99
|
||||
fenv.h), returning the result and setting it in TARGET. Otherwise return
|
||||
NULL_RTX on failure. */
|
||||
static rtx
|
||||
expand_builtin_feclear_feraise_except (tree exp, rtx target,
|
||||
machine_mode target_mode, optab op_optab)
|
||||
{
|
||||
if (!validate_arglist (exp, INTEGER_TYPE, VOID_TYPE))
|
||||
return NULL_RTX;
|
||||
rtx op0 = expand_normal (CALL_EXPR_ARG (exp, 0));
|
||||
|
||||
insn_code icode = direct_optab_handler (op_optab, SImode);
|
||||
if (icode == CODE_FOR_nothing)
|
||||
return NULL_RTX;
|
||||
|
||||
if (target == 0
|
||||
|| GET_MODE (target) != target_mode
|
||||
|| !(*insn_data[icode].operand[0].predicate) (target, target_mode))
|
||||
target = gen_reg_rtx (target_mode);
|
||||
|
||||
rtx pat = GEN_FCN (icode) (target, op0);
|
||||
if (!pat)
|
||||
return NULL_RTX;
|
||||
emit_insn (pat);
|
||||
|
||||
return target;
|
||||
}
|
||||
|
||||
/* Expand a call to the internal cexpi builtin to the sincos math function.
|
||||
EXP is the expression that is a call to the builtin function; if convenient,
|
||||
the result should be placed in TARGET. */
|
||||
@ -7056,6 +7112,26 @@ expand_builtin (tree exp, rtx target, rtx subtarget, machine_mode mode,
|
||||
return target;
|
||||
break;
|
||||
|
||||
case BUILT_IN_FEGETROUND:
|
||||
target = expand_builtin_fegetround (exp, target, target_mode);
|
||||
if (target)
|
||||
return target;
|
||||
break;
|
||||
|
||||
case BUILT_IN_FECLEAREXCEPT:
|
||||
target = expand_builtin_feclear_feraise_except (exp, target, target_mode,
|
||||
feclearexcept_optab);
|
||||
if (target)
|
||||
return target;
|
||||
break;
|
||||
|
||||
case BUILT_IN_FERAISEEXCEPT:
|
||||
target = expand_builtin_feclear_feraise_except (exp, target, target_mode,
|
||||
feraiseexcept_optab);
|
||||
if (target)
|
||||
return target;
|
||||
break;
|
||||
|
||||
case BUILT_IN_APPLY_ARGS:
|
||||
return expand_builtin_apply_args ();
|
||||
|
||||
|
@ -6912,6 +6912,117 @@
|
||||
[(set_attr "type" "fpload")
|
||||
(set_attr "length" "8")
|
||||
(set_attr "isa" "*,p8v,p8v")])
|
||||
|
||||
;; int fegetround(void)
|
||||
;;
|
||||
;; This expansion for the C99 function only expands for compatible
|
||||
;; target libcs, because it needs to return one of FE_DOWNWARD,
|
||||
;; FE_TONEAREST, FE_TOWARDZERO or FE_UPWARD with the values as defined
|
||||
;; by the target libc, and since the libc is free to choose the values
|
||||
;; (and they may differ from the hardware) and the expander needs to
|
||||
;; know then beforehand, this expanded only expands for target libcs
|
||||
;; that it can handle the values is knows.
|
||||
;; Because of these restriction, this only expands on the desired
|
||||
;; case and fallback to a call to libc otherwise.
|
||||
(define_expand "fegetroundsi"
|
||||
[(set (match_operand:SI 0 "gpc_reg_operand")
|
||||
(unspec_volatile:SI [(const_int 0)] UNSPECV_MFFSL))]
|
||||
"TARGET_HARD_FLOAT"
|
||||
{
|
||||
if (!OPTION_GLIBC)
|
||||
FAIL;
|
||||
|
||||
rtx tmp_df = gen_reg_rtx (DFmode);
|
||||
emit_insn (gen_rs6000_mffsl (tmp_df));
|
||||
|
||||
rtx tmp_di = simplify_gen_subreg (DImode, tmp_df, DFmode, 0);
|
||||
rtx tmp_di_2 = gen_reg_rtx (DImode);
|
||||
emit_insn (gen_anddi3 (tmp_di_2, tmp_di, GEN_INT (3)));
|
||||
rtx tmp_si = gen_reg_rtx (SImode);
|
||||
tmp_si = gen_lowpart (SImode, tmp_di_2);
|
||||
emit_move_insn (operands[0], tmp_si);
|
||||
DONE;
|
||||
})
|
||||
|
||||
;; int feclearexcept(int excepts)
|
||||
;;
|
||||
;; This expansion for the C99 function only works when EXCEPTS is a
|
||||
;; constant known at compile time and specifies any one of
|
||||
;; FE_INEXACT, FE_DIVBYZERO, FE_UNDERFLOW and FE_OVERFLOW flags.
|
||||
;; It doesn't handle values out of range, and always returns 0.
|
||||
;; Note that FE_INVALID is unsupported because it maps to more than
|
||||
;; one bit of the FPSCR register.
|
||||
;; The FE_* are defined in the target libc, and since they are free to
|
||||
;; choose the values and the expand needs to know them beforehand,
|
||||
;; this expander only expands for target libcs that it can handle the
|
||||
;; values it knows.
|
||||
;; Because of these restrictions, this only expands on the desired
|
||||
;; cases and fallback to a call to libc on any other case.
|
||||
(define_expand "feclearexceptsi"
|
||||
[(use (match_operand:SI 1 "const_int_operand" "n"))
|
||||
(set (match_operand:SI 0 "gpc_reg_operand")
|
||||
(const_int 0))]
|
||||
"TARGET_HARD_FLOAT"
|
||||
{
|
||||
if (!OPTION_GLIBC)
|
||||
FAIL;
|
||||
|
||||
unsigned int fe = INTVAL (operands[1]);
|
||||
if (fe != (fe & 0x1e000000))
|
||||
FAIL;
|
||||
|
||||
if (fe & 0x02000000) /* FE_INEXACT */
|
||||
emit_insn (gen_rs6000_mtfsb0 (gen_rtx_CONST_INT (SImode, 6)));
|
||||
if (fe & 0x04000000) /* FE_DIVBYZERO */
|
||||
emit_insn (gen_rs6000_mtfsb0 (gen_rtx_CONST_INT (SImode, 5)));
|
||||
if (fe & 0x08000000) /* FE_UNDERFLOW */
|
||||
emit_insn (gen_rs6000_mtfsb0 (gen_rtx_CONST_INT (SImode, 4)));
|
||||
if (fe & 0x10000000) /* FE_OVERFLOW */
|
||||
emit_insn (gen_rs6000_mtfsb0 (gen_rtx_CONST_INT (SImode, 3)));
|
||||
|
||||
emit_move_insn (operands[0], const0_rtx);
|
||||
DONE;
|
||||
})
|
||||
|
||||
;; int feraiseexcept(int excepts)
|
||||
;;
|
||||
;; This expansion for the C99 function only works when excepts is a
|
||||
;; constant known at compile time and specifies any one of
|
||||
;; FE_INEXACT, FE_DIVBYZERO, FE_UNDERFLOW and FE_OVERFLOW flags.
|
||||
;; It doesn't handle values out of range, and always returns 0.
|
||||
;; Note that FE_INVALID is unsupported because it maps to more than
|
||||
;; one bit of the FPSCR register.
|
||||
;; The FE_* are defined in the target libc, and since they are free to
|
||||
;; choose the values and the expand needs to know them beforehand,
|
||||
;; this expander only expands for target libcs that it can handle the
|
||||
;; values it knows.
|
||||
;; Because of these restrictions, this only expands on the desired
|
||||
;; cases and fallback to a call to libc on any other case.
|
||||
(define_expand "feraiseexceptsi"
|
||||
[(use (match_operand:SI 1 "const_int_operand" "n"))
|
||||
(set (match_operand:SI 0 "gpc_reg_operand")
|
||||
(const_int 0))]
|
||||
"TARGET_HARD_FLOAT"
|
||||
{
|
||||
if (!OPTION_GLIBC)
|
||||
FAIL;
|
||||
|
||||
unsigned int fe = INTVAL (operands[1]);
|
||||
if (fe != (fe & 0x1e000000))
|
||||
FAIL;
|
||||
|
||||
if (fe & 0x02000000) /* FE_INEXACT */
|
||||
emit_insn (gen_rs6000_mtfsb1 (gen_rtx_CONST_INT (SImode, 6)));
|
||||
if (fe & 0x04000000) /* FE_DIVBYZERO */
|
||||
emit_insn (gen_rs6000_mtfsb1 (gen_rtx_CONST_INT (SImode, 5)));
|
||||
if (fe & 0x08000000) /* FE_UNDERFLOW */
|
||||
emit_insn (gen_rs6000_mtfsb1 (gen_rtx_CONST_INT (SImode, 4)));
|
||||
if (fe & 0x10000000) /* FE_OVERFLOW */
|
||||
emit_insn (gen_rs6000_mtfsb1 (gen_rtx_CONST_INT (SImode, 3)));
|
||||
|
||||
emit_move_insn (operands[0], const0_rtx);
|
||||
DONE;
|
||||
})
|
||||
|
||||
;; Define the TImode operations that can be done in a small number
|
||||
;; of instructions. The & constraints are to prevent the register
|
||||
|
@ -13506,6 +13506,14 @@ In the same fashion, GCC provides @code{fpclassify}, @code{isfinite},
|
||||
@code{__builtin_} prefixed. The @code{isinf} and @code{isnan}
|
||||
built-in functions appear both with and without the @code{__builtin_} prefix.
|
||||
|
||||
GCC provides built-in versions of the ISO C99 floating-point rounding and
|
||||
exceptions handling functions @code{fegetround}, @code{feclearexcept} and
|
||||
@code{feraiseexcept}. They may not be available for all targets, and because
|
||||
they need close interaction with libc internal values, they may not be available
|
||||
for all target libcs, but in all cases they will gracefully fallback to libc
|
||||
calls. This built-in functions appear both with and without the
|
||||
@code{__builtin_} prefix.
|
||||
|
||||
@deftypefn {Built-in Function} void *__builtin_alloca (size_t size)
|
||||
The @code{__builtin_alloca} function must be called at block scope.
|
||||
The function allocates an object @var{size} bytes large on the stack
|
||||
|
@ -6087,6 +6087,23 @@ mode @var{m}, which is a scalar or vector floating-point mode.
|
||||
|
||||
This pattern is not allowed to @code{FAIL}.
|
||||
|
||||
@cindex @code{fegetround@var{m}} instruction pattern
|
||||
@item @samp{fegetround@var{m}}
|
||||
Store the current machine floating-point rounding mode into operand 0.
|
||||
Operand 0 has mode @var{m}, which is scalar. This pattern is used to
|
||||
implement the @code{fegetround} function from the ISO C99 standard.
|
||||
|
||||
@cindex @code{feclearexcept@var{m}} instruction pattern
|
||||
@cindex @code{feraiseexcept@var{m}} instruction pattern
|
||||
@item @samp{feclearexcept@var{m}}
|
||||
@item @samp{feraiseexcept@var{m}}
|
||||
Clears or raises the supported machine floating-point exceptions
|
||||
represented by the bits in operand 1. Error status is stored as
|
||||
nonzero value in operand 0. Both operands have mode @var{m}, which is
|
||||
a scalar. These patterns are used to implement the
|
||||
@code{feclearexcept} and @code{feraiseexcept} functions from the ISO
|
||||
C99 standard.
|
||||
|
||||
@cindex @code{exp@var{m}2} instruction pattern
|
||||
@item @samp{exp@var{m}2}
|
||||
Raise e (the base of natural logarithms) to the power of operand 1
|
||||
|
@ -331,6 +331,10 @@ OPTAB_D (sinh_optab, "sinh$a2")
|
||||
OPTAB_D (tan_optab, "tan$a2")
|
||||
OPTAB_D (tanh_optab, "tanh$a2")
|
||||
|
||||
OPTAB_D (fegetround_optab, "fegetround$a")
|
||||
OPTAB_D (feclearexcept_optab, "feclearexcept$a")
|
||||
OPTAB_D (feraiseexcept_optab, "feraiseexcept$a")
|
||||
|
||||
/* C99 implementations of fmax/fmin. */
|
||||
OPTAB_D (fmax_optab, "fmax$a3")
|
||||
OPTAB_D (fmin_optab, "fmin$a3")
|
||||
|
@ -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;
|
||||
}
|
@ -0,0 +1,91 @@
|
||||
/* { dg-do run } */
|
||||
/* { dg-require-effective-target fenv_exceptions } */
|
||||
/* { dg-options "-lm -fno-builtin" } */
|
||||
|
||||
/* This testcase ensures that the builtins are correctly expanded and match the
|
||||
expected result.
|
||||
"-fno-builtin" option is used to enable calls to libc implementation of the
|
||||
gcc builtins tested when not using __builtin_ prefix.
|
||||
The excepts parameter needs to be passed as constant to
|
||||
__builtin_feclearexcept and __builtin_feraiseexcept because some bultins only
|
||||
expand on constant input. */
|
||||
|
||||
#include <fenv.h>
|
||||
|
||||
#ifdef DEBUG
|
||||
#include <stdio.h>
|
||||
#define INFO(...) printf(__VA_ARGS__)
|
||||
#define FAIL(ret, raised, expected, excepts, excepts_str, func) \
|
||||
printf("ERROR [l %d] testing %s (%x): %s returned %d." \
|
||||
" Raised except bits %x, expecected %x\n", \
|
||||
__LINE__, excepts_str, excepts, func, ret, raised, expected)
|
||||
#else
|
||||
void abort (void);
|
||||
#define INFO(...)
|
||||
#define FAIL(ret, raised, expected, excepts, excepts_str, func) abort()
|
||||
#endif
|
||||
|
||||
#define TEST(excepts) \
|
||||
do { \
|
||||
int ret = 0; \
|
||||
int raised = 0; \
|
||||
\
|
||||
INFO("test: %s (%x)\n", #excepts, excepts); \
|
||||
\
|
||||
feclearexcept(FE_ALL_EXCEPT); \
|
||||
ret = __builtin_feraiseexcept(excepts); \
|
||||
raised = fetestexcept(FE_ALL_EXCEPT); \
|
||||
if (ret != 0 || raised != (excepts)) \
|
||||
FAIL(ret, raised, excepts, excepts, #excepts, \
|
||||
"__builtin_feraiseexcept"); \
|
||||
\
|
||||
feraiseexcept(FE_ALL_EXCEPT); \
|
||||
ret = __builtin_feclearexcept(excepts); \
|
||||
raised = fetestexcept(FE_ALL_EXCEPT); \
|
||||
if (ret != 0 || raised != (FE_ALL_EXCEPT & ~(excepts))) \
|
||||
FAIL(ret, raised, FE_ALL_EXCEPT & ~(excepts), excepts, #excepts, \
|
||||
"__builtin_feclearexcept"); \
|
||||
} while (0)
|
||||
|
||||
int
|
||||
main ()
|
||||
{
|
||||
TEST(0);
|
||||
TEST(FE_ALL_EXCEPT);
|
||||
|
||||
TEST(FE_INVALID);
|
||||
TEST(FE_DIVBYZERO);
|
||||
TEST(FE_INEXACT);
|
||||
TEST(FE_OVERFLOW);
|
||||
TEST(FE_UNDERFLOW);
|
||||
|
||||
TEST(FE_INVALID | FE_DIVBYZERO);
|
||||
TEST(FE_INVALID | FE_INEXACT);
|
||||
TEST(FE_INVALID | FE_OVERFLOW);
|
||||
TEST(FE_INVALID | FE_UNDERFLOW);
|
||||
TEST(FE_DIVBYZERO | FE_INEXACT);
|
||||
TEST(FE_DIVBYZERO | FE_OVERFLOW);
|
||||
TEST(FE_DIVBYZERO | FE_UNDERFLOW);
|
||||
TEST(FE_INEXACT | FE_OVERFLOW);
|
||||
TEST(FE_INEXACT | FE_UNDERFLOW);
|
||||
TEST(FE_OVERFLOW | FE_UNDERFLOW);
|
||||
|
||||
TEST(FE_INVALID | FE_DIVBYZERO | FE_INEXACT);
|
||||
TEST(FE_INVALID | FE_DIVBYZERO | FE_OVERFLOW);
|
||||
TEST(FE_INVALID | FE_DIVBYZERO | FE_UNDERFLOW);
|
||||
TEST(FE_INVALID | FE_INEXACT | FE_OVERFLOW);
|
||||
TEST(FE_INVALID | FE_INEXACT | FE_UNDERFLOW);
|
||||
TEST(FE_INVALID | FE_OVERFLOW | FE_UNDERFLOW);
|
||||
TEST(FE_DIVBYZERO | FE_INEXACT | FE_OVERFLOW);
|
||||
TEST(FE_DIVBYZERO | FE_INEXACT | FE_UNDERFLOW);
|
||||
TEST(FE_DIVBYZERO | FE_OVERFLOW | FE_UNDERFLOW);
|
||||
TEST(FE_INEXACT | FE_OVERFLOW | FE_UNDERFLOW);
|
||||
|
||||
TEST(FE_INVALID | FE_DIVBYZERO | FE_INEXACT | FE_UNDERFLOW);
|
||||
TEST(FE_INVALID | FE_DIVBYZERO | FE_INEXACT | FE_OVERFLOW);
|
||||
TEST(FE_INVALID | FE_DIVBYZERO | FE_UNDERFLOW | FE_OVERFLOW);
|
||||
TEST(FE_INVALID | FE_INEXACT | FE_UNDERFLOW | FE_OVERFLOW);
|
||||
TEST(FE_DIVBYZERO | FE_INEXACT | FE_UNDERFLOW | FE_OVERFLOW);
|
||||
|
||||
return 0;
|
||||
}
|
36
gcc/testsuite/gcc.target/powerpc/builtin-fegetround.c
Normal file
36
gcc/testsuite/gcc.target/powerpc/builtin-fegetround.c
Normal file
@ -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;
|
||||
}
|
Loading…
Reference in New Issue
Block a user