mirror of git://gcc.gnu.org/git/gcc.git
re PR middle-end/77925 (Add __builtin_issubnormal)
2017-06-08 Tamar Christina <tamar.christina@arm.com> PR middle-end/77925 PR middle-end/77926 PR middle-end/66462 * gcc/builtins.c (fold_builtin_fpclassify): Remove. (fold_builtin_interclass_mathfn): Remove. (expand_builtin): Add builtins to lowering list. (fold_builtin_n): Remove fold_builtin_varargs. (fold_builtin_varargs): Remove. * gcc/builtins.def (BUILT_IN_ISZERO, BUILT_IN_ISSUBNORMAL): New. * gcc/real.h (get_min_float): New. (real_format): Add is_ieee_compatible field. * gcc/real.c (get_min_float): New. (ieee_single_format): Set is_ieee_compatible flag. * gcc/gimple-low.c (lower_stm): Define BUILT_IN_FPCLASSIFY, CASE_FLT_FN (BUILT_IN_ISINF), BUILT_IN_ISINFD32, BUILT_IN_ISINFD64, BUILT_IN_ISINFD128, BUILT_IN_ISNAND32, BUILT_IN_ISNAND64, BUILT_IN_ISNAND128, BUILT_IN_ISNAN, BUILT_IN_ISNORMAL, BUILT_IN_ISZERO, BUILT_IN_ISSUBNORMAL, CASE_FLT_FN (BUILT_IN_FINITE), BUILT_IN_FINITED32 BUILT_IN_FINITED64, BUILT_IN_FINITED128, BUILT_IN_ISFINITE. (lower_builtin_fpclassify, is_nan, is_normal, is_infinity): New. (is_zero, is_subnormal, is_finite, use_ieee_int_mode): Likewise. (lower_builtin_isnan, lower_builtin_isinfinite): Likewise. (lower_builtin_isnormal, lower_builtin_iszero): Likewise. (lower_builtin_issubnormal, lower_builtin_isfinite): Likewise. (emit_tree_cond, get_num_as_int, emit_tree_and_return_var): New. (mips_single_format): Likewise. (motorola_single_format): Likewise. (spu_single_format): Likewise. (ieee_double_format): Likewise. (mips_double_format): Likewise. (motorola_double_format): Likewise. (ieee_extended_motorola_format): Likewise. (ieee_extended_intel_128_format): Likewise. (ieee_extended_intel_96_round_53_format): Likewise. (ibm_extended_format): Likewise. (mips_extended_format): Likewise. (ieee_quad_format): Likewise. (mips_quad_format): Likewise. (vax_f_format): Likewise. (vax_d_format): Likewise. (vax_g_format): Likewise. (decimal_single_format): Likewise. (decimal_quad_format): Likewise. (iee_half_format): Likewise. (mips_single_format): Likewise. (arm_half_format): Likewise. (real_internal_format): Likewise. * gcc/doc/extend.texi: Add documentation for built-ins. * gcc/c/c-typeck.c (convert_arguments): Add BUILT_IN_ISZERO and BUILT_IN_ISSUBNORMAL. gcc/testsuite/ 2017-06-08 Tamar Christina <tamar.christina@arm.com> * gcc.target/aarch64/builtin-fpclassify.c: New codegen test. * gcc.dg/fold-notunord.c: Removed. * gcc.dg/torture/floatn-tg-4.h: Add tests for iszero and issubnormal. * gcc.dg/torture/float128-tg-4.c: Likewise. * gcc.dg/torture/float128x-tg-4: Likewise. * gcc.dg/torture/float16-tg-4.c: Likewise. * gcc.dg/torture/float32-tg-4.c: Likewise. * gcc.dg/torture/float32x-tg-4.c: Likewise. * gcc.dg/torture/float64-tg-4.c: Likewise. * gcc.dg/torture/float64x-tg-4.c: Likewise. * gcc.dg/pr28796-1.c: Add -O2. * gcc.dg/builtins-43.c: Check lower instead of gimple. * gcc.dg/tg-tests.h: Add iszero and issubnormal. * gcc.dg/pr77925.c: Add to test safe cases. From-SVN: r249005
This commit is contained in:
parent
fb4bc6ff6c
commit
94fc87ecdf
|
|
@ -1,3 +1,57 @@
|
|||
2017-06-08 Tamar Christina <tamar.christina@arm.com>
|
||||
|
||||
PR middle-end/77925
|
||||
PR middle-end/77926
|
||||
PR middle-end/66462
|
||||
|
||||
* gcc/builtins.c (fold_builtin_fpclassify): Remove.
|
||||
(fold_builtin_interclass_mathfn): Remove.
|
||||
(expand_builtin): Add builtins to lowering list.
|
||||
(fold_builtin_n): Remove fold_builtin_varargs.
|
||||
(fold_builtin_varargs): Remove.
|
||||
* gcc/builtins.def (BUILT_IN_ISZERO, BUILT_IN_ISSUBNORMAL): New.
|
||||
* gcc/real.h (get_min_float): New.
|
||||
(real_format): Add is_ieee_compatible field.
|
||||
* gcc/real.c (get_min_float): New.
|
||||
(ieee_single_format): Set is_ieee_compatible flag.
|
||||
* gcc/gimple-low.c (lower_stm): Define BUILT_IN_FPCLASSIFY,
|
||||
CASE_FLT_FN (BUILT_IN_ISINF), BUILT_IN_ISINFD32, BUILT_IN_ISINFD64,
|
||||
BUILT_IN_ISINFD128, BUILT_IN_ISNAND32, BUILT_IN_ISNAND64,
|
||||
BUILT_IN_ISNAND128, BUILT_IN_ISNAN, BUILT_IN_ISNORMAL, BUILT_IN_ISZERO,
|
||||
BUILT_IN_ISSUBNORMAL, CASE_FLT_FN (BUILT_IN_FINITE), BUILT_IN_FINITED32
|
||||
BUILT_IN_FINITED64, BUILT_IN_FINITED128, BUILT_IN_ISFINITE.
|
||||
(lower_builtin_fpclassify, is_nan, is_normal, is_infinity): New.
|
||||
(is_zero, is_subnormal, is_finite, use_ieee_int_mode): Likewise.
|
||||
(lower_builtin_isnan, lower_builtin_isinfinite): Likewise.
|
||||
(lower_builtin_isnormal, lower_builtin_iszero): Likewise.
|
||||
(lower_builtin_issubnormal, lower_builtin_isfinite): Likewise.
|
||||
(emit_tree_cond, get_num_as_int, emit_tree_and_return_var): New.
|
||||
(mips_single_format): Likewise.
|
||||
(motorola_single_format): Likewise.
|
||||
(spu_single_format): Likewise.
|
||||
(ieee_double_format): Likewise.
|
||||
(mips_double_format): Likewise.
|
||||
(motorola_double_format): Likewise.
|
||||
(ieee_extended_motorola_format): Likewise.
|
||||
(ieee_extended_intel_128_format): Likewise.
|
||||
(ieee_extended_intel_96_round_53_format): Likewise.
|
||||
(ibm_extended_format): Likewise.
|
||||
(mips_extended_format): Likewise.
|
||||
(ieee_quad_format): Likewise.
|
||||
(mips_quad_format): Likewise.
|
||||
(vax_f_format): Likewise.
|
||||
(vax_d_format): Likewise.
|
||||
(vax_g_format): Likewise.
|
||||
(decimal_single_format): Likewise.
|
||||
(decimal_quad_format): Likewise.
|
||||
(iee_half_format): Likewise.
|
||||
(mips_single_format): Likewise.
|
||||
(arm_half_format): Likewise.
|
||||
(real_internal_format): Likewise.
|
||||
* gcc/doc/extend.texi: Add documentation for built-ins.
|
||||
* gcc/c/c-typeck.c (convert_arguments): Add BUILT_IN_ISZERO
|
||||
and BUILT_IN_ISSUBNORMAL.
|
||||
|
||||
2017-06-07 Carl Love <cel@us.ibm.com>
|
||||
|
||||
* config/rs6000/rs6000-c: The return type of the following
|
||||
|
|
|
|||
374
gcc/builtins.c
374
gcc/builtins.c
|
|
@ -165,7 +165,6 @@ static tree fold_builtin_0 (location_t, tree);
|
|||
static tree fold_builtin_1 (location_t, tree, tree);
|
||||
static tree fold_builtin_2 (location_t, tree, tree, tree);
|
||||
static tree fold_builtin_3 (location_t, tree, tree, tree, tree);
|
||||
static tree fold_builtin_varargs (location_t, tree, tree*, int);
|
||||
|
||||
static tree fold_builtin_strpbrk (location_t, tree, tree, tree);
|
||||
static tree fold_builtin_strspn (location_t, tree, tree);
|
||||
|
|
@ -2227,19 +2226,8 @@ interclass_mathfn_icode (tree arg, tree fndecl)
|
|||
switch (DECL_FUNCTION_CODE (fndecl))
|
||||
{
|
||||
CASE_FLT_FN (BUILT_IN_ILOGB):
|
||||
errno_set = true; builtin_optab = ilogb_optab; break;
|
||||
CASE_FLT_FN (BUILT_IN_ISINF):
|
||||
builtin_optab = isinf_optab; break;
|
||||
case BUILT_IN_ISNORMAL:
|
||||
case BUILT_IN_ISFINITE:
|
||||
CASE_FLT_FN (BUILT_IN_FINITE):
|
||||
case BUILT_IN_FINITED32:
|
||||
case BUILT_IN_FINITED64:
|
||||
case BUILT_IN_FINITED128:
|
||||
case BUILT_IN_ISINFD32:
|
||||
case BUILT_IN_ISINFD64:
|
||||
case BUILT_IN_ISINFD128:
|
||||
/* These builtins have no optabs (yet). */
|
||||
errno_set = true;
|
||||
builtin_optab = ilogb_optab;
|
||||
break;
|
||||
default:
|
||||
gcc_unreachable ();
|
||||
|
|
@ -2258,8 +2246,7 @@ interclass_mathfn_icode (tree arg, tree fndecl)
|
|||
}
|
||||
|
||||
/* Expand a call to one of the builtin math functions that operate on
|
||||
floating point argument and output an integer result (ilogb, isinf,
|
||||
isnan, etc).
|
||||
floating point argument and output an integer result (ilogb, etc).
|
||||
Return 0 if a normal call should be emitted rather than expanding the
|
||||
function in-line. EXP is the expression that is a call to the builtin
|
||||
function; if convenient, the result should be placed in TARGET. */
|
||||
|
|
@ -6605,11 +6592,7 @@ expand_builtin (tree exp, rtx target, rtx subtarget, machine_mode mode,
|
|||
CASE_FLT_FN (BUILT_IN_ILOGB):
|
||||
if (! flag_unsafe_math_optimizations)
|
||||
break;
|
||||
gcc_fallthrough ();
|
||||
CASE_FLT_FN (BUILT_IN_ISINF):
|
||||
CASE_FLT_FN (BUILT_IN_FINITE):
|
||||
case BUILT_IN_ISFINITE:
|
||||
case BUILT_IN_ISNORMAL:
|
||||
|
||||
target = expand_builtin_interclass_mathfn (exp, target);
|
||||
if (target)
|
||||
return target;
|
||||
|
|
@ -6917,8 +6900,25 @@ expand_builtin (tree exp, rtx target, rtx subtarget, machine_mode mode,
|
|||
}
|
||||
break;
|
||||
|
||||
CASE_FLT_FN (BUILT_IN_ISINF):
|
||||
case BUILT_IN_ISNAND32:
|
||||
case BUILT_IN_ISNAND64:
|
||||
case BUILT_IN_ISNAND128:
|
||||
case BUILT_IN_ISNAN:
|
||||
case BUILT_IN_ISINFD32:
|
||||
case BUILT_IN_ISINFD64:
|
||||
case BUILT_IN_ISINFD128:
|
||||
case BUILT_IN_ISNORMAL:
|
||||
case BUILT_IN_ISZERO:
|
||||
case BUILT_IN_ISSUBNORMAL:
|
||||
case BUILT_IN_FPCLASSIFY:
|
||||
case BUILT_IN_SETJMP:
|
||||
/* This should have been lowered to the builtins below. */
|
||||
CASE_FLT_FN (BUILT_IN_FINITE):
|
||||
case BUILT_IN_FINITED32:
|
||||
case BUILT_IN_FINITED64:
|
||||
case BUILT_IN_FINITED128:
|
||||
case BUILT_IN_ISFINITE:
|
||||
/* These should have been lowered to the builtins in gimple-low.c. */
|
||||
gcc_unreachable ();
|
||||
|
||||
case BUILT_IN_SETJMP_SETUP:
|
||||
|
|
@ -8258,184 +8258,19 @@ fold_builtin_modf (location_t loc, tree arg0, tree arg1, tree rettype)
|
|||
return NULL_TREE;
|
||||
}
|
||||
|
||||
/* Given a location LOC, an interclass builtin function decl FNDECL
|
||||
and its single argument ARG, return an folded expression computing
|
||||
the same, or NULL_TREE if we either couldn't or didn't want to fold
|
||||
(the latter happen if there's an RTL instruction available). */
|
||||
|
||||
static tree
|
||||
fold_builtin_interclass_mathfn (location_t loc, tree fndecl, tree arg)
|
||||
{
|
||||
machine_mode mode;
|
||||
|
||||
if (!validate_arg (arg, REAL_TYPE))
|
||||
return NULL_TREE;
|
||||
|
||||
if (interclass_mathfn_icode (arg, fndecl) != CODE_FOR_nothing)
|
||||
return NULL_TREE;
|
||||
|
||||
mode = TYPE_MODE (TREE_TYPE (arg));
|
||||
|
||||
bool is_ibm_extended = MODE_COMPOSITE_P (mode);
|
||||
|
||||
/* If there is no optab, try generic code. */
|
||||
switch (DECL_FUNCTION_CODE (fndecl))
|
||||
{
|
||||
tree result;
|
||||
|
||||
CASE_FLT_FN (BUILT_IN_ISINF):
|
||||
{
|
||||
/* isinf(x) -> isgreater(fabs(x),DBL_MAX). */
|
||||
tree const isgr_fn = builtin_decl_explicit (BUILT_IN_ISGREATER);
|
||||
tree type = TREE_TYPE (arg);
|
||||
REAL_VALUE_TYPE r;
|
||||
char buf[128];
|
||||
|
||||
if (is_ibm_extended)
|
||||
{
|
||||
/* NaN and Inf are encoded in the high-order double value
|
||||
only. The low-order value is not significant. */
|
||||
type = double_type_node;
|
||||
mode = DFmode;
|
||||
arg = fold_build1_loc (loc, NOP_EXPR, type, arg);
|
||||
}
|
||||
get_max_float (REAL_MODE_FORMAT (mode), buf, sizeof (buf));
|
||||
real_from_string (&r, buf);
|
||||
result = build_call_expr (isgr_fn, 2,
|
||||
fold_build1_loc (loc, ABS_EXPR, type, arg),
|
||||
build_real (type, r));
|
||||
return result;
|
||||
}
|
||||
CASE_FLT_FN (BUILT_IN_FINITE):
|
||||
case BUILT_IN_ISFINITE:
|
||||
{
|
||||
/* isfinite(x) -> islessequal(fabs(x),DBL_MAX). */
|
||||
tree const isle_fn = builtin_decl_explicit (BUILT_IN_ISLESSEQUAL);
|
||||
tree type = TREE_TYPE (arg);
|
||||
REAL_VALUE_TYPE r;
|
||||
char buf[128];
|
||||
|
||||
if (is_ibm_extended)
|
||||
{
|
||||
/* NaN and Inf are encoded in the high-order double value
|
||||
only. The low-order value is not significant. */
|
||||
type = double_type_node;
|
||||
mode = DFmode;
|
||||
arg = fold_build1_loc (loc, NOP_EXPR, type, arg);
|
||||
}
|
||||
get_max_float (REAL_MODE_FORMAT (mode), buf, sizeof (buf));
|
||||
real_from_string (&r, buf);
|
||||
result = build_call_expr (isle_fn, 2,
|
||||
fold_build1_loc (loc, ABS_EXPR, type, arg),
|
||||
build_real (type, r));
|
||||
/*result = fold_build2_loc (loc, UNGT_EXPR,
|
||||
TREE_TYPE (TREE_TYPE (fndecl)),
|
||||
fold_build1_loc (loc, ABS_EXPR, type, arg),
|
||||
build_real (type, r));
|
||||
result = fold_build1_loc (loc, TRUTH_NOT_EXPR,
|
||||
TREE_TYPE (TREE_TYPE (fndecl)),
|
||||
result);*/
|
||||
return result;
|
||||
}
|
||||
case BUILT_IN_ISNORMAL:
|
||||
{
|
||||
/* isnormal(x) -> isgreaterequal(fabs(x),DBL_MIN) &
|
||||
islessequal(fabs(x),DBL_MAX). */
|
||||
tree const isle_fn = builtin_decl_explicit (BUILT_IN_ISLESSEQUAL);
|
||||
tree type = TREE_TYPE (arg);
|
||||
tree orig_arg, max_exp, min_exp;
|
||||
machine_mode orig_mode = mode;
|
||||
REAL_VALUE_TYPE rmax, rmin;
|
||||
char buf[128];
|
||||
|
||||
orig_arg = arg = builtin_save_expr (arg);
|
||||
if (is_ibm_extended)
|
||||
{
|
||||
/* Use double to test the normal range of IBM extended
|
||||
precision. Emin for IBM extended precision is
|
||||
different to emin for IEEE double, being 53 higher
|
||||
since the low double exponent is at least 53 lower
|
||||
than the high double exponent. */
|
||||
type = double_type_node;
|
||||
mode = DFmode;
|
||||
arg = fold_build1_loc (loc, NOP_EXPR, type, arg);
|
||||
}
|
||||
arg = fold_build1_loc (loc, ABS_EXPR, type, arg);
|
||||
|
||||
get_max_float (REAL_MODE_FORMAT (mode), buf, sizeof (buf));
|
||||
real_from_string (&rmax, buf);
|
||||
sprintf (buf, "0x1p%d", REAL_MODE_FORMAT (orig_mode)->emin - 1);
|
||||
real_from_string (&rmin, buf);
|
||||
max_exp = build_real (type, rmax);
|
||||
min_exp = build_real (type, rmin);
|
||||
|
||||
max_exp = build_call_expr (isle_fn, 2, arg, max_exp);
|
||||
if (is_ibm_extended)
|
||||
{
|
||||
/* Testing the high end of the range is done just using
|
||||
the high double, using the same test as isfinite().
|
||||
For the subnormal end of the range we first test the
|
||||
high double, then if its magnitude is equal to the
|
||||
limit of 0x1p-969, we test whether the low double is
|
||||
non-zero and opposite sign to the high double. */
|
||||
tree const islt_fn = builtin_decl_explicit (BUILT_IN_ISLESS);
|
||||
tree const isgt_fn = builtin_decl_explicit (BUILT_IN_ISGREATER);
|
||||
tree gt_min = build_call_expr (isgt_fn, 2, arg, min_exp);
|
||||
tree eq_min = fold_build2 (EQ_EXPR, integer_type_node,
|
||||
arg, min_exp);
|
||||
tree as_complex = build1 (VIEW_CONVERT_EXPR,
|
||||
complex_double_type_node, orig_arg);
|
||||
tree hi_dbl = build1 (REALPART_EXPR, type, as_complex);
|
||||
tree lo_dbl = build1 (IMAGPART_EXPR, type, as_complex);
|
||||
tree zero = build_real (type, dconst0);
|
||||
tree hilt = build_call_expr (islt_fn, 2, hi_dbl, zero);
|
||||
tree lolt = build_call_expr (islt_fn, 2, lo_dbl, zero);
|
||||
tree logt = build_call_expr (isgt_fn, 2, lo_dbl, zero);
|
||||
tree ok_lo = fold_build1 (TRUTH_NOT_EXPR, integer_type_node,
|
||||
fold_build3 (COND_EXPR,
|
||||
integer_type_node,
|
||||
hilt, logt, lolt));
|
||||
eq_min = fold_build2 (TRUTH_ANDIF_EXPR, integer_type_node,
|
||||
eq_min, ok_lo);
|
||||
min_exp = fold_build2 (TRUTH_ORIF_EXPR, integer_type_node,
|
||||
gt_min, eq_min);
|
||||
}
|
||||
else
|
||||
{
|
||||
tree const isge_fn
|
||||
= builtin_decl_explicit (BUILT_IN_ISGREATEREQUAL);
|
||||
min_exp = build_call_expr (isge_fn, 2, arg, min_exp);
|
||||
}
|
||||
result = fold_build2 (BIT_AND_EXPR, integer_type_node,
|
||||
max_exp, min_exp);
|
||||
return result;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return NULL_TREE;
|
||||
}
|
||||
|
||||
/* Fold a call to __builtin_isnan(), __builtin_isinf, __builtin_finite.
|
||||
/* Fold a call to __builtin_isinf_sign.
|
||||
ARG is the argument for the call. */
|
||||
|
||||
static tree
|
||||
fold_builtin_classify (location_t loc, tree fndecl, tree arg, int builtin_index)
|
||||
fold_builtin_classify (location_t loc, tree arg, int builtin_index)
|
||||
{
|
||||
tree type = TREE_TYPE (TREE_TYPE (fndecl));
|
||||
|
||||
if (!validate_arg (arg, REAL_TYPE))
|
||||
return NULL_TREE;
|
||||
|
||||
switch (builtin_index)
|
||||
{
|
||||
case BUILT_IN_ISINF:
|
||||
if (!HONOR_INFINITIES (arg))
|
||||
return omit_one_operand_loc (loc, type, integer_zero_node, arg);
|
||||
|
||||
return NULL_TREE;
|
||||
|
||||
case BUILT_IN_ISINF_SIGN:
|
||||
{
|
||||
/* isinf_sign(x) -> isinf(x) ? (signbit(x) ? -1 : 1) : 0 */
|
||||
|
|
@ -8468,106 +8303,11 @@ fold_builtin_classify (location_t loc, tree fndecl, tree arg, int builtin_index)
|
|||
return tmp;
|
||||
}
|
||||
|
||||
case BUILT_IN_ISFINITE:
|
||||
if (!HONOR_NANS (arg)
|
||||
&& !HONOR_INFINITIES (arg))
|
||||
return omit_one_operand_loc (loc, type, integer_one_node, arg);
|
||||
|
||||
return NULL_TREE;
|
||||
|
||||
case BUILT_IN_ISNAN:
|
||||
if (!HONOR_NANS (arg))
|
||||
return omit_one_operand_loc (loc, type, integer_zero_node, arg);
|
||||
|
||||
{
|
||||
bool is_ibm_extended = MODE_COMPOSITE_P (TYPE_MODE (TREE_TYPE (arg)));
|
||||
if (is_ibm_extended)
|
||||
{
|
||||
/* NaN and Inf are encoded in the high-order double value
|
||||
only. The low-order value is not significant. */
|
||||
arg = fold_build1_loc (loc, NOP_EXPR, double_type_node, arg);
|
||||
}
|
||||
}
|
||||
arg = builtin_save_expr (arg);
|
||||
return fold_build2_loc (loc, UNORDERED_EXPR, type, arg, arg);
|
||||
|
||||
default:
|
||||
gcc_unreachable ();
|
||||
}
|
||||
}
|
||||
|
||||
/* Fold a call to __builtin_fpclassify(int, int, int, int, int, ...).
|
||||
This builtin will generate code to return the appropriate floating
|
||||
point classification depending on the value of the floating point
|
||||
number passed in. The possible return values must be supplied as
|
||||
int arguments to the call in the following order: FP_NAN, FP_INFINITE,
|
||||
FP_NORMAL, FP_SUBNORMAL and FP_ZERO. The ellipses is for exactly
|
||||
one floating point argument which is "type generic". */
|
||||
|
||||
static tree
|
||||
fold_builtin_fpclassify (location_t loc, tree *args, int nargs)
|
||||
{
|
||||
tree fp_nan, fp_infinite, fp_normal, fp_subnormal, fp_zero,
|
||||
arg, type, res, tmp;
|
||||
machine_mode mode;
|
||||
REAL_VALUE_TYPE r;
|
||||
char buf[128];
|
||||
|
||||
/* Verify the required arguments in the original call. */
|
||||
if (nargs != 6
|
||||
|| !validate_arg (args[0], INTEGER_TYPE)
|
||||
|| !validate_arg (args[1], INTEGER_TYPE)
|
||||
|| !validate_arg (args[2], INTEGER_TYPE)
|
||||
|| !validate_arg (args[3], INTEGER_TYPE)
|
||||
|| !validate_arg (args[4], INTEGER_TYPE)
|
||||
|| !validate_arg (args[5], REAL_TYPE))
|
||||
return NULL_TREE;
|
||||
|
||||
fp_nan = args[0];
|
||||
fp_infinite = args[1];
|
||||
fp_normal = args[2];
|
||||
fp_subnormal = args[3];
|
||||
fp_zero = args[4];
|
||||
arg = args[5];
|
||||
type = TREE_TYPE (arg);
|
||||
mode = TYPE_MODE (type);
|
||||
arg = builtin_save_expr (fold_build1_loc (loc, ABS_EXPR, type, arg));
|
||||
|
||||
/* fpclassify(x) ->
|
||||
isnan(x) ? FP_NAN :
|
||||
(fabs(x) == Inf ? FP_INFINITE :
|
||||
(fabs(x) >= DBL_MIN ? FP_NORMAL :
|
||||
(x == 0 ? FP_ZERO : FP_SUBNORMAL))). */
|
||||
|
||||
tmp = fold_build2_loc (loc, EQ_EXPR, integer_type_node, arg,
|
||||
build_real (type, dconst0));
|
||||
res = fold_build3_loc (loc, COND_EXPR, integer_type_node,
|
||||
tmp, fp_zero, fp_subnormal);
|
||||
|
||||
sprintf (buf, "0x1p%d", REAL_MODE_FORMAT (mode)->emin - 1);
|
||||
real_from_string (&r, buf);
|
||||
tmp = fold_build2_loc (loc, GE_EXPR, integer_type_node,
|
||||
arg, build_real (type, r));
|
||||
res = fold_build3_loc (loc, COND_EXPR, integer_type_node, tmp, fp_normal, res);
|
||||
|
||||
if (HONOR_INFINITIES (mode))
|
||||
{
|
||||
real_inf (&r);
|
||||
tmp = fold_build2_loc (loc, EQ_EXPR, integer_type_node, arg,
|
||||
build_real (type, r));
|
||||
res = fold_build3_loc (loc, COND_EXPR, integer_type_node, tmp,
|
||||
fp_infinite, res);
|
||||
}
|
||||
|
||||
if (HONOR_NANS (mode))
|
||||
{
|
||||
tmp = fold_build2_loc (loc, ORDERED_EXPR, integer_type_node, arg, arg);
|
||||
res = fold_build3_loc (loc, COND_EXPR, integer_type_node, tmp, res, fp_nan);
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
/* Fold a call to an unordered comparison function such as
|
||||
__builtin_isgreater(). FNDECL is the FUNCTION_DECL for the function
|
||||
being called and ARG0 and ARG1 are the arguments for the call.
|
||||
|
|
@ -8868,40 +8608,8 @@ fold_builtin_1 (location_t loc, tree fndecl, tree arg0)
|
|||
case BUILT_IN_ISDIGIT:
|
||||
return fold_builtin_isdigit (loc, arg0);
|
||||
|
||||
CASE_FLT_FN (BUILT_IN_FINITE):
|
||||
case BUILT_IN_FINITED32:
|
||||
case BUILT_IN_FINITED64:
|
||||
case BUILT_IN_FINITED128:
|
||||
case BUILT_IN_ISFINITE:
|
||||
{
|
||||
tree ret = fold_builtin_classify (loc, fndecl, arg0, BUILT_IN_ISFINITE);
|
||||
if (ret)
|
||||
return ret;
|
||||
return fold_builtin_interclass_mathfn (loc, fndecl, arg0);
|
||||
}
|
||||
|
||||
CASE_FLT_FN (BUILT_IN_ISINF):
|
||||
case BUILT_IN_ISINFD32:
|
||||
case BUILT_IN_ISINFD64:
|
||||
case BUILT_IN_ISINFD128:
|
||||
{
|
||||
tree ret = fold_builtin_classify (loc, fndecl, arg0, BUILT_IN_ISINF);
|
||||
if (ret)
|
||||
return ret;
|
||||
return fold_builtin_interclass_mathfn (loc, fndecl, arg0);
|
||||
}
|
||||
|
||||
case BUILT_IN_ISNORMAL:
|
||||
return fold_builtin_interclass_mathfn (loc, fndecl, arg0);
|
||||
|
||||
case BUILT_IN_ISINF_SIGN:
|
||||
return fold_builtin_classify (loc, fndecl, arg0, BUILT_IN_ISINF_SIGN);
|
||||
|
||||
CASE_FLT_FN (BUILT_IN_ISNAN):
|
||||
case BUILT_IN_ISNAND32:
|
||||
case BUILT_IN_ISNAND64:
|
||||
case BUILT_IN_ISNAND128:
|
||||
return fold_builtin_classify (loc, fndecl, arg0, BUILT_IN_ISNAN);
|
||||
return fold_builtin_classify (loc, arg0, BUILT_IN_ISINF_SIGN);
|
||||
|
||||
case BUILT_IN_FREE:
|
||||
if (integer_zerop (arg0))
|
||||
|
|
@ -9098,7 +8806,6 @@ fold_builtin_n (location_t loc, tree fndecl, tree *args, int nargs, bool)
|
|||
ret = fold_builtin_3 (loc, fndecl, args[0], args[1], args[2]);
|
||||
break;
|
||||
default:
|
||||
ret = fold_builtin_varargs (loc, fndecl, args, nargs);
|
||||
break;
|
||||
}
|
||||
if (ret)
|
||||
|
|
@ -9989,37 +9696,6 @@ fold_builtin_object_size (tree ptr, tree ost)
|
|||
return NULL_TREE;
|
||||
}
|
||||
|
||||
/* Builtins with folding operations that operate on "..." arguments
|
||||
need special handling; we need to store the arguments in a convenient
|
||||
data structure before attempting any folding. Fortunately there are
|
||||
only a few builtins that fall into this category. FNDECL is the
|
||||
function, EXP is the CALL_EXPR for the call. */
|
||||
|
||||
static tree
|
||||
fold_builtin_varargs (location_t loc, tree fndecl, tree *args, int nargs)
|
||||
{
|
||||
enum built_in_function fcode = DECL_FUNCTION_CODE (fndecl);
|
||||
tree ret = NULL_TREE;
|
||||
|
||||
switch (fcode)
|
||||
{
|
||||
case BUILT_IN_FPCLASSIFY:
|
||||
ret = fold_builtin_fpclassify (loc, args, nargs);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if (ret)
|
||||
{
|
||||
ret = build1 (NOP_EXPR, TREE_TYPE (ret), ret);
|
||||
SET_EXPR_LOCATION (ret, loc);
|
||||
TREE_NO_WARNING (ret) = 1;
|
||||
return ret;
|
||||
}
|
||||
return NULL_TREE;
|
||||
}
|
||||
|
||||
/* Initialize format string characters in the target charset. */
|
||||
|
||||
bool
|
||||
|
|
|
|||
|
|
@ -845,6 +845,8 @@ DEF_EXT_LIB_BUILTIN (BUILT_IN_ISINFL, "isinfl", BT_FN_INT_LONGDOUBLE, ATTR_CO
|
|||
DEF_EXT_LIB_BUILTIN (BUILT_IN_ISINFD32, "isinfd32", BT_FN_INT_DFLOAT32, ATTR_CONST_NOTHROW_LEAF_LIST)
|
||||
DEF_EXT_LIB_BUILTIN (BUILT_IN_ISINFD64, "isinfd64", BT_FN_INT_DFLOAT64, ATTR_CONST_NOTHROW_LEAF_LIST)
|
||||
DEF_EXT_LIB_BUILTIN (BUILT_IN_ISINFD128, "isinfd128", BT_FN_INT_DFLOAT128, ATTR_CONST_NOTHROW_LEAF_LIST)
|
||||
DEF_GCC_BUILTIN (BUILT_IN_ISZERO, "iszero", BT_FN_INT_VAR, ATTR_CONST_NOTHROW_TYPEGENERIC_LEAF)
|
||||
DEF_GCC_BUILTIN (BUILT_IN_ISSUBNORMAL, "issubnormal", BT_FN_INT_VAR, ATTR_CONST_NOTHROW_TYPEGENERIC_LEAF)
|
||||
DEF_C99_C90RES_BUILTIN (BUILT_IN_ISNAN, "isnan", BT_FN_INT_VAR, ATTR_CONST_NOTHROW_TYPEGENERIC_LEAF)
|
||||
DEF_EXT_LIB_BUILTIN (BUILT_IN_ISNANF, "isnanf", BT_FN_INT_FLOAT, ATTR_CONST_NOTHROW_LEAF_LIST)
|
||||
DEF_EXT_LIB_BUILTIN (BUILT_IN_ISNANL, "isnanl", BT_FN_INT_LONGDOUBLE, ATTR_CONST_NOTHROW_LEAF_LIST)
|
||||
|
|
|
|||
|
|
@ -3241,6 +3241,8 @@ convert_arguments (location_t loc, vec<location_t> arg_loc, tree typelist,
|
|||
case BUILT_IN_ISINF_SIGN:
|
||||
case BUILT_IN_ISNAN:
|
||||
case BUILT_IN_ISNORMAL:
|
||||
case BUILT_IN_ISZERO:
|
||||
case BUILT_IN_ISSUBNORMAL:
|
||||
case BUILT_IN_FPCLASSIFY:
|
||||
type_generic_remove_excess_precision = true;
|
||||
break;
|
||||
|
|
|
|||
|
|
@ -10501,6 +10501,10 @@ in the Cilk Plus language manual which can be found at
|
|||
@findex __builtin_isgreater
|
||||
@findex __builtin_isgreaterequal
|
||||
@findex __builtin_isinf_sign
|
||||
@findex __builtin_isinf
|
||||
@findex __builtin_isnan
|
||||
@findex __builtin_iszero
|
||||
@findex __builtin_issubnormal
|
||||
@findex __builtin_isless
|
||||
@findex __builtin_islessequal
|
||||
@findex __builtin_islessgreater
|
||||
|
|
@ -11564,7 +11568,54 @@ constant values and they must appear in this order: @code{FP_NAN},
|
|||
@code{FP_INFINITE}, @code{FP_NORMAL}, @code{FP_SUBNORMAL} and
|
||||
@code{FP_ZERO}. The ellipsis is for exactly one floating-point value
|
||||
to classify. GCC treats the last argument as type-generic, which
|
||||
means it does not do default promotion from float to double.
|
||||
means it does not do default promotion from @code{float} to @code{double}.
|
||||
@end deftypefn
|
||||
|
||||
@deftypefn {Built-in Function} int __builtin_isnan (...)
|
||||
This built-in implements the C99 isnan functionality which checks if
|
||||
the given argument represents a NaN. The return value of the
|
||||
function will either be a 0 (false) or a 1 (true).
|
||||
On most systems, when an IEEE 754 floating-point type is used this
|
||||
built-in does not produce a signal when a signaling NaN is used.
|
||||
|
||||
GCC treats the argument as type-generic, which means it does
|
||||
not do default promotion from @code{float} to @code{double}.
|
||||
@end deftypefn
|
||||
|
||||
@deftypefn {Built-in Function} int __builtin_isinf (...)
|
||||
This built-in implements the C99 isinf functionality which checks if
|
||||
the given argument represents an infinite number. The return
|
||||
value of the function will either be a 0 (false) or a 1 (true).
|
||||
|
||||
GCC treats the argument as type-generic, which means it does
|
||||
not do default promotion from @code{float} to @code{double}.
|
||||
@end deftypefn
|
||||
|
||||
@deftypefn {Built-in Function} int __builtin_isnormal (...)
|
||||
This built-in implements the C99 isnormal functionality which checks if
|
||||
the given argument represents a normal number. The return
|
||||
value of the function will either be a 0 (false) or a 1 (true).
|
||||
|
||||
GCC treats the argument as type-generic, which means it does
|
||||
not do default promotion from @code{float} to @code{double}.
|
||||
@end deftypefn
|
||||
|
||||
@deftypefn {Built-in Function} int __builtin_iszero (...)
|
||||
This built-in implements the TS 18661-1:2014 iszero functionality which checks if
|
||||
the given argument represents the number 0 or -0. The return
|
||||
value of the function will either be a 0 (false) or a 1 (true).
|
||||
|
||||
GCC treats the argument as type-generic, which means it does
|
||||
not do default promotion from @code{float} to @code{double}.
|
||||
@end deftypefn
|
||||
|
||||
@deftypefn {Built-in Function} int __builtin_issubnormal (...)
|
||||
This built-in implements the TS 18661-1:2014 issubnormal functionality which checks if
|
||||
the given argument represents a subnormal number. The return
|
||||
value of the function will either be a 0 (false) or a 1 (true).
|
||||
|
||||
GCC treats the argument as type-generic, which means it does
|
||||
not do default promotion from @code{float} to @code{double}.
|
||||
@end deftypefn
|
||||
|
||||
@deftypefn {Built-in Function} double __builtin_inf (void)
|
||||
|
|
|
|||
910
gcc/gimple-low.c
910
gcc/gimple-low.c
|
|
@ -30,6 +30,9 @@ along with GCC; see the file COPYING3. If not see
|
|||
#include "calls.h"
|
||||
#include "gimple-iterator.h"
|
||||
#include "gimple-low.h"
|
||||
#include "stor-layout.h"
|
||||
#include "target.h"
|
||||
#include "gimplify.h"
|
||||
|
||||
/* The differences between High GIMPLE and Low GIMPLE are the
|
||||
following:
|
||||
|
|
@ -72,6 +75,13 @@ static void lower_gimple_bind (gimple_stmt_iterator *, struct lower_data *);
|
|||
static void lower_try_catch (gimple_stmt_iterator *, struct lower_data *);
|
||||
static void lower_gimple_return (gimple_stmt_iterator *, struct lower_data *);
|
||||
static void lower_builtin_setjmp (gimple_stmt_iterator *);
|
||||
static void lower_builtin_fpclassify (gimple_stmt_iterator *);
|
||||
static void lower_builtin_isnan (gimple_stmt_iterator *);
|
||||
static void lower_builtin_isinfinite (gimple_stmt_iterator *);
|
||||
static void lower_builtin_isnormal (gimple_stmt_iterator *);
|
||||
static void lower_builtin_iszero (gimple_stmt_iterator *);
|
||||
static void lower_builtin_issubnormal (gimple_stmt_iterator *);
|
||||
static void lower_builtin_isfinite (gimple_stmt_iterator *);
|
||||
static void lower_builtin_posix_memalign (gimple_stmt_iterator *);
|
||||
|
||||
|
||||
|
|
@ -330,18 +340,69 @@ lower_stmt (gimple_stmt_iterator *gsi, struct lower_data *data)
|
|||
if (decl
|
||||
&& DECL_BUILT_IN_CLASS (decl) == BUILT_IN_NORMAL)
|
||||
{
|
||||
if (DECL_FUNCTION_CODE (decl) == BUILT_IN_SETJMP)
|
||||
switch (DECL_FUNCTION_CODE (decl))
|
||||
{
|
||||
case BUILT_IN_SETJMP:
|
||||
lower_builtin_setjmp (gsi);
|
||||
data->cannot_fallthru = false;
|
||||
return;
|
||||
}
|
||||
else if (DECL_FUNCTION_CODE (decl) == BUILT_IN_POSIX_MEMALIGN
|
||||
&& flag_tree_bit_ccp
|
||||
&& gimple_builtin_call_types_compatible_p (stmt, decl))
|
||||
{
|
||||
lower_builtin_posix_memalign (gsi);
|
||||
|
||||
case BUILT_IN_POSIX_MEMALIGN:
|
||||
if (flag_tree_bit_ccp
|
||||
&& gimple_builtin_call_types_compatible_p (stmt, decl))
|
||||
{
|
||||
lower_builtin_posix_memalign (gsi);
|
||||
return;
|
||||
}
|
||||
break;
|
||||
|
||||
case BUILT_IN_FPCLASSIFY:
|
||||
lower_builtin_fpclassify (gsi);
|
||||
data->cannot_fallthru = false;
|
||||
return;
|
||||
|
||||
CASE_FLT_FN (BUILT_IN_ISINF):
|
||||
case BUILT_IN_ISINFD32:
|
||||
case BUILT_IN_ISINFD64:
|
||||
case BUILT_IN_ISINFD128:
|
||||
lower_builtin_isinfinite (gsi);
|
||||
data->cannot_fallthru = false;
|
||||
return;
|
||||
|
||||
case BUILT_IN_ISNAND32:
|
||||
case BUILT_IN_ISNAND64:
|
||||
case BUILT_IN_ISNAND128:
|
||||
CASE_FLT_FN (BUILT_IN_ISNAN):
|
||||
lower_builtin_isnan (gsi);
|
||||
data->cannot_fallthru = false;
|
||||
return;
|
||||
|
||||
case BUILT_IN_ISNORMAL:
|
||||
lower_builtin_isnormal (gsi);
|
||||
data->cannot_fallthru = false;
|
||||
return;
|
||||
|
||||
case BUILT_IN_ISZERO:
|
||||
lower_builtin_iszero (gsi);
|
||||
data->cannot_fallthru = false;
|
||||
return;
|
||||
|
||||
case BUILT_IN_ISSUBNORMAL:
|
||||
lower_builtin_issubnormal (gsi);
|
||||
data->cannot_fallthru = false;
|
||||
return;
|
||||
|
||||
CASE_FLT_FN (BUILT_IN_FINITE):
|
||||
case BUILT_IN_FINITED32:
|
||||
case BUILT_IN_FINITED64:
|
||||
case BUILT_IN_FINITED128:
|
||||
case BUILT_IN_ISFINITE:
|
||||
lower_builtin_isfinite (gsi);
|
||||
data->cannot_fallthru = false;
|
||||
return;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -822,6 +883,841 @@ lower_builtin_setjmp (gimple_stmt_iterator *gsi)
|
|||
gsi_remove (gsi, false);
|
||||
}
|
||||
|
||||
/* This function will if ARG is not already a variable or SSA_NAME,
|
||||
create a new temporary TMP and bind ARG to TMP. This new binding is then
|
||||
emitted into SEQ and TMP is returned. */
|
||||
static tree
|
||||
emit_tree_and_return_var (gimple_seq *seq, tree arg)
|
||||
{
|
||||
if (TREE_CODE (arg) == SSA_NAME || VAR_P (arg))
|
||||
return arg;
|
||||
|
||||
tree tmp = create_tmp_reg (TREE_TYPE (arg));
|
||||
gassign *stm = gimple_build_assign (tmp, arg);
|
||||
gimple_seq_add_stmt (seq, stm);
|
||||
return tmp;
|
||||
}
|
||||
|
||||
/* This function builds an if statement that ends up using explicit branches
|
||||
instead of becoming a ternary conditional select. This function assumes you
|
||||
will fall through to the next statements after the condition for the false
|
||||
branch. The code emitted looks like:
|
||||
|
||||
if (COND)
|
||||
RESULT_VARIABLE = TRUE_BRANCH
|
||||
GOTO EXIT_LABEL
|
||||
else
|
||||
...
|
||||
|
||||
SEQ is the gimple sequence/buffer to emit any new bindings to.
|
||||
RESULT_VARIABLE is the value to set if COND.
|
||||
EXIT_LABEL is the label to jump to in case COND.
|
||||
COND is condition to use in the conditional statement of the if.
|
||||
TRUE_BRANCH is the value to set RESULT_VARIABLE to if COND. */
|
||||
static void
|
||||
emit_tree_cond (gimple_seq *seq, tree result_variable, tree exit_label,
|
||||
tree cond, tree true_branch)
|
||||
{
|
||||
/* Create labels for fall through. */
|
||||
tree true_label = create_artificial_label (UNKNOWN_LOCATION);
|
||||
tree false_label = create_artificial_label (UNKNOWN_LOCATION);
|
||||
gcond *stmt = gimple_build_cond_from_tree (cond, true_label, false_label);
|
||||
gimple_seq_add_stmt (seq, stmt);
|
||||
|
||||
/* Build the true case. */
|
||||
gimple_seq_add_stmt (seq, gimple_build_label (true_label));
|
||||
tree value = TREE_CONSTANT (true_branch)
|
||||
? true_branch
|
||||
: emit_tree_and_return_var (seq, true_branch);
|
||||
gimple_seq_add_stmt (seq, gimple_build_assign (result_variable, value));
|
||||
gimple_seq_add_stmt (seq, gimple_build_goto (exit_label));
|
||||
|
||||
/* Build the false case. */
|
||||
gimple_seq_add_stmt (seq, gimple_build_label (false_label));
|
||||
}
|
||||
|
||||
/* This function returns a variable containing an reinterpreted ARG as an
|
||||
integer.
|
||||
|
||||
SEQ is the gimple sequence/buffer to write any new bindings to.
|
||||
ARG is the floating point number to reinterpret as an integer.
|
||||
LOC is the location to use when doing folding operations. */
|
||||
static tree
|
||||
get_num_as_int (gimple_seq *seq, tree arg, location_t loc)
|
||||
{
|
||||
tree type = TREE_TYPE (arg);
|
||||
|
||||
const HOST_WIDE_INT type_width = TYPE_PRECISION (type);
|
||||
|
||||
/* Re-interpret the float as an unsigned integer type
|
||||
with equal precision. */
|
||||
tree int_arg_type = build_nonstandard_integer_type (type_width, true);
|
||||
tree conv_arg = fold_build1_loc (loc, VIEW_CONVERT_EXPR, int_arg_type, arg);
|
||||
return emit_tree_and_return_var (seq, conv_arg);
|
||||
}
|
||||
|
||||
/* Check if ARG which is the floating point number being classified is close
|
||||
enough to IEEE 754 format to be able to go in the early exit code. */
|
||||
static bool
|
||||
use_ieee_int_mode (tree arg)
|
||||
{
|
||||
tree type = TREE_TYPE (arg);
|
||||
machine_mode mode = TYPE_MODE (type);
|
||||
|
||||
const real_format *format = REAL_MODE_FORMAT (mode);
|
||||
machine_mode imode = int_mode_for_mode (mode);
|
||||
bool is_ibm_extended = MODE_COMPOSITE_P (mode);
|
||||
|
||||
return (format->is_binary_ieee_compatible
|
||||
&& FLOAT_WORDS_BIG_ENDIAN == WORDS_BIG_ENDIAN
|
||||
/* Check if there's a usable integer mode. */
|
||||
&& imode != BLKmode
|
||||
&& targetm.scalar_mode_supported_p (imode)
|
||||
&& !is_ibm_extended);
|
||||
}
|
||||
|
||||
/* Perform some IBM extended format fixups on ARG for use by FP functions.
|
||||
This is done by ignoring the lower 64 bits of the number.
|
||||
|
||||
MODE is the machine mode of ARG.
|
||||
TYPE is the type of ARG.
|
||||
LOC is the location to be used in fold functions. Usually is the location
|
||||
of the definition of ARG. */
|
||||
static bool
|
||||
perform_ibm_extended_fixups (tree *arg, machine_mode *mode,
|
||||
tree *type, location_t loc)
|
||||
{
|
||||
bool is_ibm_extended = MODE_COMPOSITE_P (*mode);
|
||||
if (is_ibm_extended)
|
||||
{
|
||||
/* NaN and Inf are encoded in the high-order double value
|
||||
only. The low-order value is not significant. */
|
||||
*type = double_type_node;
|
||||
*mode = DFmode;
|
||||
*arg = fold_build1_loc (loc, NOP_EXPR, *type, *arg);
|
||||
}
|
||||
|
||||
return is_ibm_extended;
|
||||
}
|
||||
|
||||
/* Generates code to check if ARG is a normal number. For the FP case we check
|
||||
MIN_VALUE(ARG) <= ABS(ARG) > INF and for the INT value we check the exp and
|
||||
mantissa bits. Returns a variable containing a boolean which has the result
|
||||
of the check.
|
||||
|
||||
SEQ is the buffer to use to emit the gimple instructions into.
|
||||
LOC is the location to use during fold calls. */
|
||||
static tree
|
||||
is_normal (gimple_seq *seq, tree arg, location_t loc)
|
||||
{
|
||||
tree type = TREE_TYPE (arg);
|
||||
|
||||
machine_mode mode = TYPE_MODE (type);
|
||||
const real_format *format = REAL_MODE_FORMAT (mode);
|
||||
const tree bool_type = boolean_type_node;
|
||||
|
||||
|
||||
/* If not using optimized route then exit early. */
|
||||
if (!use_ieee_int_mode (arg))
|
||||
{
|
||||
tree orig_arg = arg;
|
||||
machine_mode orig_mode = mode;
|
||||
if (TREE_CODE (arg) != SSA_NAME
|
||||
&& (TREE_ADDRESSABLE (arg) != 0
|
||||
|| (TREE_CODE (arg) != PARM_DECL
|
||||
&& (!VAR_P (arg) || TREE_STATIC (arg)))))
|
||||
orig_arg = save_expr (arg);
|
||||
|
||||
/* Perform IBM extended format fixups if required. */
|
||||
bool is_ibm_extended = perform_ibm_extended_fixups (&arg, &mode,
|
||||
&type, loc);
|
||||
|
||||
REAL_VALUE_TYPE rinf, rmin;
|
||||
tree arg_p = fold_build1_loc (loc, ABS_EXPR, type, arg);
|
||||
|
||||
tree const islt_fn = builtin_decl_explicit (BUILT_IN_ISLESS);
|
||||
tree const isgt_fn = builtin_decl_explicit (BUILT_IN_ISGREATER);
|
||||
tree const isge_fn = builtin_decl_explicit (BUILT_IN_ISGREATEREQUAL);
|
||||
|
||||
char buf[128];
|
||||
real_inf (&rinf);
|
||||
get_min_float (REAL_MODE_FORMAT (orig_mode), buf, sizeof (buf));
|
||||
real_from_string (&rmin, buf);
|
||||
|
||||
tree inf_exp = build_call_expr (islt_fn, 2, arg_p,
|
||||
build_real (type, rinf));
|
||||
tree min_exp = build_real (type, rmin);
|
||||
if (is_ibm_extended)
|
||||
{
|
||||
/* Testing the high end of the range is done just using
|
||||
the high double, using the same test as isfinite().
|
||||
For the subnormal end of the range we first test the
|
||||
high double, then if its magnitude is equal to the
|
||||
limit of 0x1p-969, we test whether the low double is
|
||||
non-zero and opposite sign to the high double. */
|
||||
tree gt_min = build_call_expr (isgt_fn, 2, arg_p, min_exp);
|
||||
tree eq_min = fold_build2 (EQ_EXPR, integer_type_node,
|
||||
arg_p, min_exp);
|
||||
tree as_complex = build1 (VIEW_CONVERT_EXPR,
|
||||
complex_double_type_node, orig_arg);
|
||||
tree hi_dbl = build1 (REALPART_EXPR, type, as_complex);
|
||||
tree lo_dbl = build1 (IMAGPART_EXPR, type, as_complex);
|
||||
tree zero = build_real (type, dconst0);
|
||||
tree hilt = build_call_expr (islt_fn, 2, hi_dbl, zero);
|
||||
tree lolt = build_call_expr (islt_fn, 2, lo_dbl, zero);
|
||||
tree logt = build_call_expr (isgt_fn, 2, lo_dbl, zero);
|
||||
tree ok_lo = fold_build1 (TRUTH_NOT_EXPR, integer_type_node,
|
||||
fold_build3 (COND_EXPR,
|
||||
integer_type_node,
|
||||
hilt, logt, lolt));
|
||||
eq_min = fold_build2 (TRUTH_ANDIF_EXPR, integer_type_node,
|
||||
eq_min, ok_lo);
|
||||
min_exp = fold_build2 (TRUTH_ORIF_EXPR, integer_type_node,
|
||||
gt_min, eq_min);
|
||||
}
|
||||
else
|
||||
{
|
||||
min_exp = build_call_expr (isge_fn, 2, arg_p, min_exp);
|
||||
}
|
||||
|
||||
push_gimplify_context ();
|
||||
gimplify_expr (&min_exp, seq, NULL, is_gimple_val, fb_either);
|
||||
gimplify_expr (&inf_exp, seq, NULL, is_gimple_val, fb_either);
|
||||
|
||||
tree res
|
||||
= fold_build2_loc (loc, BIT_AND_EXPR, bool_type,
|
||||
emit_tree_and_return_var (seq,
|
||||
gimple_boolify (min_exp)),
|
||||
emit_tree_and_return_var (seq,
|
||||
gimple_boolify (inf_exp)));
|
||||
pop_gimplify_context (NULL);
|
||||
|
||||
return emit_tree_and_return_var (seq, res);
|
||||
}
|
||||
|
||||
const tree int_type = unsigned_type_node;
|
||||
const int exp_bits = (GET_MODE_SIZE (mode) * BITS_PER_UNIT) - format->p;
|
||||
const int exp_mask = (1 << exp_bits) - 1;
|
||||
|
||||
/* Get the number reinterpreted as an integer. */
|
||||
tree int_arg = get_num_as_int (seq, arg, loc);
|
||||
|
||||
/* Extract exp bits from the float, where we expect the exponent to be.
|
||||
We create a new type because BIT_FIELD_REF does not allow you to
|
||||
extract less bits than the precision of the storage variable. */
|
||||
tree exp_tmp
|
||||
= fold_build3_loc (loc, BIT_FIELD_REF,
|
||||
build_nonstandard_integer_type (exp_bits, true),
|
||||
int_arg,
|
||||
build_int_cstu (int_type, exp_bits),
|
||||
build_int_cstu (int_type, format->p - 1));
|
||||
tree exp_bitfield = emit_tree_and_return_var (seq, exp_tmp);
|
||||
|
||||
/* Re-interpret the extracted exponent bits as a 32 bit int.
|
||||
This allows us to continue doing operations as int_type. */
|
||||
tree exp
|
||||
= emit_tree_and_return_var (seq, fold_build1_loc (loc, NOP_EXPR, int_type,
|
||||
exp_bitfield));
|
||||
|
||||
/* exp_mask & ~1. */
|
||||
tree mask_check
|
||||
= fold_build2_loc (loc, BIT_AND_EXPR, int_type,
|
||||
build_int_cstu (int_type, exp_mask),
|
||||
fold_build1_loc (loc, BIT_NOT_EXPR, int_type,
|
||||
build_int_cstu (int_type, 1)));
|
||||
|
||||
/* (exp + 1) & mask_check.
|
||||
Check to see if exp is not all 0 or all 1. */
|
||||
tree exp_check
|
||||
= fold_build2_loc (loc, BIT_AND_EXPR, int_type,
|
||||
emit_tree_and_return_var (seq,
|
||||
fold_build2_loc (loc, PLUS_EXPR, int_type, exp,
|
||||
build_int_cstu (int_type, 1))),
|
||||
mask_check);
|
||||
|
||||
tree res = fold_build2_loc (loc, NE_EXPR, boolean_type_node,
|
||||
build_int_cstu (int_type, 0),
|
||||
emit_tree_and_return_var (seq, exp_check));
|
||||
|
||||
return emit_tree_and_return_var (seq, res);
|
||||
}
|
||||
|
||||
/* Generates code to check if ARG is a zero. For both the FP and INT case we
|
||||
check if ARG == 0 (modulo sign bit). Returns a variable containing a boolean
|
||||
which has the result of the check.
|
||||
|
||||
SEQ is the buffer to use to emit the gimple instructions into.
|
||||
LOC is the location to use during fold calls. */
|
||||
static tree
|
||||
is_zero (gimple_seq *seq, tree arg, location_t loc)
|
||||
{
|
||||
tree type = TREE_TYPE (arg);
|
||||
|
||||
/* If not using optimized route then exit early. */
|
||||
if (!use_ieee_int_mode (arg))
|
||||
{
|
||||
machine_mode mode = TYPE_MODE (type);
|
||||
/* Perform IBM extended format fixups if required. */
|
||||
perform_ibm_extended_fixups (&arg, &mode, &type, loc);
|
||||
|
||||
tree res = fold_build2_loc (loc, EQ_EXPR, boolean_type_node, arg,
|
||||
build_real (type, dconst0));
|
||||
return emit_tree_and_return_var (seq, res);
|
||||
}
|
||||
|
||||
const HOST_WIDE_INT type_width = TYPE_PRECISION (type);
|
||||
|
||||
tree int_arg_type = build_nonstandard_integer_type (type_width, true);
|
||||
|
||||
/* Get the number reinterpreted as an integer.
|
||||
Shift left to remove the sign. */
|
||||
tree int_arg
|
||||
= fold_build2_loc (loc, LSHIFT_EXPR, int_arg_type,
|
||||
get_num_as_int (seq, arg, loc),
|
||||
build_int_cstu (int_arg_type, 1));
|
||||
|
||||
/* num << 1 == 0.
|
||||
This checks to see if the number is zero. */
|
||||
tree zero_check
|
||||
= fold_build2_loc (loc, EQ_EXPR, boolean_type_node,
|
||||
build_int_cstu (int_arg_type, 0),
|
||||
emit_tree_and_return_var (seq, int_arg));
|
||||
|
||||
return emit_tree_and_return_var (seq, zero_check);
|
||||
}
|
||||
|
||||
/* Generates code to check if ARG is a subnormal number. In the FP case we test
|
||||
fabs (ARG) != 0 && fabs (ARG) < MIN_VALUE (ARG) and in the INT case we check
|
||||
the exp and mantissa bits on ARG. Returns a variable containing a boolean
|
||||
which has the result of the check.
|
||||
|
||||
SEQ is the buffer to use to emit the gimple instructions into.
|
||||
LOC is the location to use during fold calls. */
|
||||
static tree
|
||||
is_subnormal (gimple_seq *seq, tree arg, location_t loc)
|
||||
{
|
||||
const tree bool_type = boolean_type_node;
|
||||
|
||||
tree type = TREE_TYPE (arg);
|
||||
|
||||
machine_mode mode = TYPE_MODE (type);
|
||||
const real_format *format = REAL_MODE_FORMAT (mode);
|
||||
const HOST_WIDE_INT type_width = TYPE_PRECISION (type);
|
||||
|
||||
tree int_arg_type = build_nonstandard_integer_type (type_width, true);
|
||||
|
||||
/* If not using optimized route then exit early. */
|
||||
if (!use_ieee_int_mode (arg))
|
||||
{
|
||||
tree const islt_fn = builtin_decl_explicit (BUILT_IN_ISLESS);
|
||||
tree const isgt_fn = builtin_decl_explicit (BUILT_IN_ISGREATER);
|
||||
|
||||
tree arg_p
|
||||
= emit_tree_and_return_var (seq, fold_build1_loc (loc, ABS_EXPR, type,
|
||||
arg));
|
||||
REAL_VALUE_TYPE r;
|
||||
char buf[128];
|
||||
get_min_float (REAL_MODE_FORMAT (mode), buf, sizeof (buf));
|
||||
real_from_string (&r, buf);
|
||||
tree subnorm = build_call_expr (islt_fn, 2, arg_p, build_real (type, r));
|
||||
|
||||
tree zero = build_call_expr (isgt_fn, 2, arg_p,
|
||||
build_real (type, dconst0));
|
||||
|
||||
push_gimplify_context ();
|
||||
gimplify_expr (&subnorm, seq, NULL, is_gimple_val, fb_either);
|
||||
gimplify_expr (&zero, seq, NULL, is_gimple_val, fb_either);
|
||||
|
||||
tree res
|
||||
= fold_build2_loc (loc, BIT_AND_EXPR, bool_type,
|
||||
emit_tree_and_return_var (seq,
|
||||
gimple_boolify (subnorm)),
|
||||
emit_tree_and_return_var (seq,
|
||||
gimple_boolify (zero)));
|
||||
pop_gimplify_context (NULL);
|
||||
|
||||
return emit_tree_and_return_var (seq, res);
|
||||
}
|
||||
|
||||
/* Get the number reinterpreted as an integer.
|
||||
Shift left to remove the sign. */
|
||||
tree int_arg
|
||||
= fold_build2_loc (loc, LSHIFT_EXPR, int_arg_type,
|
||||
get_num_as_int (seq, arg, loc),
|
||||
build_int_cstu (int_arg_type, 1));
|
||||
|
||||
/* Check for a zero exponent and non-zero mantissa.
|
||||
This can be done with two comparisons by first apply a
|
||||
removing the sign bit and checking if the value is larger
|
||||
than the mantissa mask. */
|
||||
|
||||
/* This creates a mask to be used to check the mantissa value in the shifted
|
||||
integer representation of the fpnum. */
|
||||
tree significant_bit = build_int_cstu (int_arg_type, format->p - 1);
|
||||
tree mantissa_mask
|
||||
= fold_build2_loc (loc, MINUS_EXPR, int_arg_type,
|
||||
fold_build2_loc (loc, LSHIFT_EXPR, int_arg_type,
|
||||
build_int_cstu (int_arg_type, 2),
|
||||
significant_bit),
|
||||
build_int_cstu (int_arg_type, 1));
|
||||
|
||||
/* Check if exponent is zero and mantissa is not. */
|
||||
tree subnorm_cond_tmp
|
||||
= fold_build2_loc (loc, LE_EXPR, bool_type,
|
||||
emit_tree_and_return_var (seq, int_arg),
|
||||
mantissa_mask);
|
||||
|
||||
tree subnorm_cond = emit_tree_and_return_var (seq, subnorm_cond_tmp);
|
||||
|
||||
tree zero_cond
|
||||
= fold_build2_loc (loc, GT_EXPR, boolean_type_node,
|
||||
emit_tree_and_return_var (seq, int_arg),
|
||||
build_int_cstu (int_arg_type, 0));
|
||||
|
||||
tree subnorm_check
|
||||
= fold_build2_loc (loc, BIT_AND_EXPR, boolean_type_node,
|
||||
emit_tree_and_return_var (seq, subnorm_cond),
|
||||
emit_tree_and_return_var (seq, zero_cond));
|
||||
|
||||
return emit_tree_and_return_var (seq, subnorm_check);
|
||||
}
|
||||
|
||||
/* Generates code to check if ARG is an infinity. In the FP case we test
|
||||
FABS(ARG) == INF and in the INT case we check the bits on the exp and
|
||||
mantissa. Returns a variable containing a boolean which has the result
|
||||
of the check.
|
||||
|
||||
SEQ is the buffer to use to emit the gimple instructions into.
|
||||
LOC is the location to use during fold calls. */
|
||||
static tree
|
||||
is_infinity (gimple_seq *seq, tree arg, location_t loc)
|
||||
{
|
||||
tree type = TREE_TYPE (arg);
|
||||
|
||||
machine_mode mode = TYPE_MODE (type);
|
||||
const tree bool_type = boolean_type_node;
|
||||
|
||||
if (!HONOR_INFINITIES (mode))
|
||||
{
|
||||
return build_int_cst (bool_type, false);
|
||||
}
|
||||
|
||||
/* If not using optimized route then exit early. */
|
||||
if (!use_ieee_int_mode (arg))
|
||||
{
|
||||
/* Perform IBM extended format fixups if required. */
|
||||
perform_ibm_extended_fixups (&arg, &mode, &type, loc);
|
||||
|
||||
tree arg_p
|
||||
= emit_tree_and_return_var (seq, fold_build1_loc (loc, ABS_EXPR, type,
|
||||
arg));
|
||||
REAL_VALUE_TYPE r;
|
||||
real_inf (&r);
|
||||
tree res = fold_build2_loc (loc, EQ_EXPR, bool_type, arg_p,
|
||||
build_real (type, r));
|
||||
|
||||
return emit_tree_and_return_var (seq, res);
|
||||
}
|
||||
|
||||
const real_format *format = REAL_MODE_FORMAT (mode);
|
||||
const HOST_WIDE_INT type_width = TYPE_PRECISION (type);
|
||||
|
||||
tree int_arg_type = build_nonstandard_integer_type (type_width, true);
|
||||
|
||||
/* This creates a mask to be used to check the exp value in the shifted
|
||||
integer representation of the fpnum. */
|
||||
const int exp_bits = (GET_MODE_SIZE (mode) * BITS_PER_UNIT) - format->p;
|
||||
gcc_assert (format->p > 0);
|
||||
|
||||
tree significant_bit = build_int_cstu (int_arg_type, format->p);
|
||||
tree exp_mask
|
||||
= fold_build2_loc (loc, MINUS_EXPR, int_arg_type,
|
||||
fold_build2_loc (loc, LSHIFT_EXPR, int_arg_type,
|
||||
build_int_cstu (int_arg_type, 2),
|
||||
build_int_cstu (int_arg_type,
|
||||
exp_bits - 1)),
|
||||
build_int_cstu (int_arg_type, 1));
|
||||
|
||||
/* Get the number reinterpreted as an integer.
|
||||
Shift left to remove the sign. */
|
||||
tree int_arg
|
||||
= fold_build2_loc (loc, LSHIFT_EXPR, int_arg_type,
|
||||
get_num_as_int (seq, arg, loc),
|
||||
build_int_cstu (int_arg_type, 1));
|
||||
|
||||
/* This mask checks to see if the exp has all bits set and mantissa no
|
||||
bits set. */
|
||||
tree inf_mask
|
||||
= fold_build2_loc (loc, LSHIFT_EXPR, int_arg_type,
|
||||
exp_mask, significant_bit);
|
||||
|
||||
/* Check if exponent has all bits set and mantissa is 0. */
|
||||
tree inf_check
|
||||
= emit_tree_and_return_var(seq,
|
||||
fold_build2_loc (loc, EQ_EXPR, bool_type,
|
||||
emit_tree_and_return_var(seq, int_arg),
|
||||
inf_mask));
|
||||
|
||||
return emit_tree_and_return_var (seq, inf_check);
|
||||
}
|
||||
|
||||
/* Generates code to check if ARG is a finite number. In the FP case we check
|
||||
if FABS(ARG) <= MAX_VALUE(ARG) and in the INT case we check the exp and
|
||||
mantissa bits. Returns a variable containing a boolean which has the result
|
||||
of the check.
|
||||
|
||||
SEQ is the buffer to use to emit the gimple instructions into.
|
||||
LOC is the location to use during fold calls. */
|
||||
static tree
|
||||
is_finite (gimple_seq *seq, tree arg, location_t loc)
|
||||
{
|
||||
tree type = TREE_TYPE (arg);
|
||||
|
||||
machine_mode mode = TYPE_MODE (type);
|
||||
const tree bool_type = boolean_type_node;
|
||||
|
||||
if (!HONOR_NANS (arg) && !HONOR_INFINITIES (arg))
|
||||
{
|
||||
return build_int_cst (bool_type, true);
|
||||
}
|
||||
|
||||
/* If not using optimized route then exit early. */
|
||||
if (!use_ieee_int_mode (arg))
|
||||
{
|
||||
|
||||
/* Perform IBM extended format fixups if required. */
|
||||
perform_ibm_extended_fixups (&arg, &mode, &type, loc);
|
||||
|
||||
tree const isle_fn = builtin_decl_explicit (BUILT_IN_ISLESSEQUAL);
|
||||
|
||||
tree arg_p
|
||||
= emit_tree_and_return_var (seq, fold_build1_loc (loc, ABS_EXPR, type,
|
||||
arg));
|
||||
REAL_VALUE_TYPE rmax;
|
||||
char buf[128];
|
||||
get_max_float (REAL_MODE_FORMAT (mode), buf, sizeof (buf));
|
||||
real_from_string (&rmax, buf);
|
||||
|
||||
tree res = build_call_expr (isle_fn, 2, arg_p, build_real (type, rmax));
|
||||
|
||||
push_gimplify_context ();
|
||||
gimplify_expr (&res, seq, NULL, is_gimple_val, fb_either);
|
||||
pop_gimplify_context (NULL);
|
||||
|
||||
return emit_tree_and_return_var (seq, gimple_boolify(res));
|
||||
}
|
||||
|
||||
const real_format *format = REAL_MODE_FORMAT (mode);
|
||||
const HOST_WIDE_INT type_width = TYPE_PRECISION (type);
|
||||
|
||||
tree int_arg_type = build_nonstandard_integer_type (type_width, true);
|
||||
|
||||
/* This creates a mask to be used to check the exp value in the shifted
|
||||
integer representation of the fpnum. */
|
||||
const int exp_bits = (GET_MODE_SIZE (mode) * BITS_PER_UNIT) - format->p;
|
||||
gcc_assert (format->p > 0);
|
||||
|
||||
tree significant_bit = build_int_cstu (int_arg_type, format->p);
|
||||
tree exp_mask
|
||||
= fold_build2_loc (loc, MINUS_EXPR, int_arg_type,
|
||||
fold_build2_loc (loc, LSHIFT_EXPR, int_arg_type,
|
||||
build_int_cstu (int_arg_type, 2),
|
||||
build_int_cstu (int_arg_type,
|
||||
exp_bits - 1)),
|
||||
build_int_cstu (int_arg_type, 1));
|
||||
|
||||
/* Get the number reinterpreted as an integer.
|
||||
Shift left to remove the sign. */
|
||||
tree int_arg
|
||||
= fold_build2_loc (loc, LSHIFT_EXPR, int_arg_type,
|
||||
get_num_as_int (seq, arg, loc),
|
||||
build_int_cstu (int_arg_type, 1));
|
||||
|
||||
/* This mask checks to see if the exp has all bits set and mantissa no
|
||||
bits set. */
|
||||
tree inf_mask
|
||||
= fold_build2_loc (loc, LSHIFT_EXPR, int_arg_type,
|
||||
exp_mask, significant_bit);
|
||||
|
||||
/* Check if exponent has all bits set and mantissa is 0. */
|
||||
tree inf_check_tmp
|
||||
= fold_build2_loc (loc, LT_EXPR, bool_type,
|
||||
emit_tree_and_return_var (seq, int_arg),
|
||||
inf_mask);
|
||||
|
||||
tree inf_check = emit_tree_and_return_var (seq, inf_check_tmp);
|
||||
|
||||
return emit_tree_and_return_var (seq, inf_check);
|
||||
}
|
||||
|
||||
/* Generates code to check if ARG is a NaN. In the FP case we simply check if
|
||||
ARG != ARG and in the INT case we check the bits in the exp and mantissa.
|
||||
Returns a variable containing a boolean which has the result of the check.
|
||||
|
||||
SEQ is the buffer to use to emit the gimple instructions into.
|
||||
LOC is the location to use during fold calls. */
|
||||
static tree
|
||||
is_nan (gimple_seq *seq, tree arg, location_t loc)
|
||||
{
|
||||
tree type = TREE_TYPE (arg);
|
||||
|
||||
machine_mode mode = TYPE_MODE (type);
|
||||
const tree bool_type = boolean_type_node;
|
||||
|
||||
if (!HONOR_NANS (mode))
|
||||
{
|
||||
return build_int_cst (bool_type, false);
|
||||
}
|
||||
|
||||
const real_format *format = REAL_MODE_FORMAT (mode);
|
||||
|
||||
/* If not using optimized route then exit early. */
|
||||
if (!use_ieee_int_mode (arg))
|
||||
{
|
||||
/* Perform IBM extended format fixups if required. */
|
||||
perform_ibm_extended_fixups (&arg, &mode, &type, loc);
|
||||
|
||||
tree arg_p
|
||||
= emit_tree_and_return_var (seq, fold_build1_loc (loc, ABS_EXPR, type,
|
||||
arg));
|
||||
tree res
|
||||
= fold_build2_loc (loc, UNORDERED_EXPR, bool_type,arg_p, arg_p);
|
||||
|
||||
return emit_tree_and_return_var (seq, res);
|
||||
}
|
||||
|
||||
const HOST_WIDE_INT type_width = TYPE_PRECISION (type);
|
||||
tree int_arg_type = build_nonstandard_integer_type (type_width, true);
|
||||
|
||||
/* This creates a mask to be used to check the exp value in the shifted
|
||||
integer representation of the fpnum. */
|
||||
const int exp_bits = (GET_MODE_SIZE (mode) * BITS_PER_UNIT) - format->p;
|
||||
tree significant_bit = build_int_cstu (int_arg_type, format->p);
|
||||
tree exp_mask
|
||||
= fold_build2_loc (loc, MINUS_EXPR, int_arg_type,
|
||||
fold_build2_loc (loc, LSHIFT_EXPR, int_arg_type,
|
||||
build_int_cstu (int_arg_type, 2),
|
||||
build_int_cstu (int_arg_type,
|
||||
exp_bits - 1)),
|
||||
build_int_cstu (int_arg_type, 1));
|
||||
|
||||
/* Get the number reinterpreted as an integer.
|
||||
Shift left to remove the sign. */
|
||||
tree int_arg
|
||||
= fold_build2_loc (loc, LSHIFT_EXPR, int_arg_type,
|
||||
get_num_as_int (seq, arg, loc),
|
||||
build_int_cstu (int_arg_type, 1));
|
||||
|
||||
/* This mask checks to see if the exp has all bits set and mantissa no
|
||||
bits set. */
|
||||
tree inf_mask
|
||||
= fold_build2_loc (loc, LSHIFT_EXPR, int_arg_type,
|
||||
exp_mask, significant_bit);
|
||||
|
||||
/* Check if exponent has all bits set and mantissa is not 0. */
|
||||
tree nan_check
|
||||
= emit_tree_and_return_var(seq,
|
||||
fold_build2_loc (loc, GT_EXPR, bool_type,
|
||||
emit_tree_and_return_var(seq, int_arg),
|
||||
inf_mask));
|
||||
|
||||
return emit_tree_and_return_var (seq, nan_check);
|
||||
}
|
||||
|
||||
/* Validates a single argument from the arguments list CALL at position INDEX.
|
||||
The extracted parameter is compared against the expected type CODE.
|
||||
|
||||
A boolean is returned indicating if the parameter exist and if of the
|
||||
expected type. */
|
||||
static bool
|
||||
gimple_validate_arg (gimple* call, int index, enum tree_code code)
|
||||
{
|
||||
const tree arg = gimple_call_arg (call, index);
|
||||
if (!arg)
|
||||
return false;
|
||||
else if (code == POINTER_TYPE)
|
||||
return POINTER_TYPE_P (TREE_TYPE (arg));
|
||||
else if (code == INTEGER_TYPE)
|
||||
return INTEGRAL_TYPE_P (TREE_TYPE (arg));
|
||||
return code == TREE_CODE (TREE_TYPE (arg));
|
||||
}
|
||||
|
||||
/* Lowers calls to __builtin_fpclassify to
|
||||
fpclassify (x) ->
|
||||
isnormal(x) ? FP_NORMAL :
|
||||
iszero (x) ? FP_ZERO :
|
||||
isnan (x) ? FP_NAN :
|
||||
isinfinite (x) ? FP_INFINITE :
|
||||
FP_SUBNORMAL.
|
||||
|
||||
The code may use integer arithmentic if it decides
|
||||
that the produced assembly would be faster. This can only be done
|
||||
for numbers that are similar to IEEE-754 in format.
|
||||
|
||||
This builtin will generate code to return the appropriate floating
|
||||
point classification depending on the value of the floating point
|
||||
number passed in. The possible return values must be supplied as
|
||||
int arguments to the call in the following order: FP_NAN, FP_INFINITE,
|
||||
FP_NORMAL, FP_SUBNORMAL and FP_ZERO. The ellipses is for exactly
|
||||
one floating point argument which is "type generic".
|
||||
|
||||
GSI is the gimple iterator containing the fpclassify call to lower.
|
||||
The call will be expanded and replaced inline in the given GSI. */
|
||||
static void
|
||||
lower_builtin_fpclassify (gimple_stmt_iterator *gsi)
|
||||
{
|
||||
gimple *call = gsi_stmt (*gsi);
|
||||
location_t loc = gimple_location (call);
|
||||
|
||||
/* Verify the required arguments in the original call. */
|
||||
if (gimple_call_num_args (call) != 6
|
||||
|| !gimple_validate_arg (call, 0, INTEGER_TYPE)
|
||||
|| !gimple_validate_arg (call, 1, INTEGER_TYPE)
|
||||
|| !gimple_validate_arg (call, 2, INTEGER_TYPE)
|
||||
|| !gimple_validate_arg (call, 3, INTEGER_TYPE)
|
||||
|| !gimple_validate_arg (call, 4, INTEGER_TYPE)
|
||||
|| !gimple_validate_arg (call, 5, REAL_TYPE))
|
||||
return;
|
||||
|
||||
/* Collect the arguments from the call. */
|
||||
tree fp_nan = gimple_call_arg (call, 0);
|
||||
tree fp_infinite = gimple_call_arg (call, 1);
|
||||
tree fp_normal = gimple_call_arg (call, 2);
|
||||
tree fp_subnormal = gimple_call_arg (call, 3);
|
||||
tree fp_zero = gimple_call_arg (call, 4);
|
||||
tree arg = gimple_call_arg (call, 5);
|
||||
|
||||
gimple_seq body = NULL;
|
||||
|
||||
/* Create label to jump to to exit. */
|
||||
tree done_label = create_artificial_label (UNKNOWN_LOCATION);
|
||||
tree dest;
|
||||
tree orig_dest = dest = gimple_call_lhs (call);
|
||||
if (orig_dest && TREE_CODE (orig_dest) == SSA_NAME)
|
||||
dest = create_tmp_reg (TREE_TYPE (orig_dest));
|
||||
|
||||
emit_tree_cond (&body, dest, done_label,
|
||||
is_normal (&body, arg, loc), fp_normal);
|
||||
emit_tree_cond (&body, dest, done_label,
|
||||
is_zero (&body, arg, loc), fp_zero);
|
||||
emit_tree_cond (&body, dest, done_label,
|
||||
is_nan (&body, arg, loc), fp_nan);
|
||||
emit_tree_cond (&body, dest, done_label,
|
||||
is_infinity (&body, arg, loc), fp_infinite);
|
||||
|
||||
/* And finally, emit the default case if nothing else matches.
|
||||
This replaces the call to is_subnormal. */
|
||||
gimple_seq_add_stmt (&body, gimple_build_assign (dest, fp_subnormal));
|
||||
gimple_seq_add_stmt (&body, gimple_build_label (done_label));
|
||||
|
||||
/* Build orig_dest = dest if necessary. */
|
||||
if (dest != orig_dest)
|
||||
{
|
||||
gimple_seq_add_stmt (&body, gimple_build_assign (orig_dest, dest));
|
||||
}
|
||||
|
||||
gsi_insert_seq_before (gsi, body, GSI_SAME_STMT);
|
||||
|
||||
|
||||
/* Remove the call to __builtin_fpclassify. */
|
||||
gsi_remove (gsi, false);
|
||||
}
|
||||
|
||||
/* Generic wrapper for the is_nan, is_normal, is_subnormal, is_zero, etc.
|
||||
All these functions have the same setup. The wrapper validates the parameter
|
||||
and also creates the branches and labels required to properly invoke.
|
||||
This has been generalize and the function to call is passed as argument FNDECL.
|
||||
|
||||
GSI is the gimple iterator containing the fpclassify call to lower.
|
||||
The call will be expanded and replaced inline in the given GSI. */
|
||||
static void
|
||||
gen_call_fp_builtin (gimple_stmt_iterator *gsi,
|
||||
tree (*fndecl)(gimple_seq *, tree, location_t))
|
||||
{
|
||||
gimple *call = gsi_stmt (*gsi);
|
||||
location_t loc = gimple_location (call);
|
||||
|
||||
/* Verify the required arguments in the original call. */
|
||||
if (gimple_call_num_args (call) != 1
|
||||
|| !gimple_validate_arg (call, 0, REAL_TYPE))
|
||||
return;
|
||||
|
||||
tree arg = gimple_call_arg (call, 0);
|
||||
gimple_seq body = NULL;
|
||||
|
||||
/* Create label to jump to to exit. */
|
||||
tree done_label = create_artificial_label (UNKNOWN_LOCATION);
|
||||
tree dest;
|
||||
tree orig_dest = dest = gimple_call_lhs (call);
|
||||
tree type = TREE_TYPE (orig_dest);
|
||||
if (orig_dest && TREE_CODE (orig_dest) == SSA_NAME)
|
||||
dest = create_tmp_reg (type);
|
||||
|
||||
tree t_true = build_int_cst (type, true);
|
||||
tree t_false = build_int_cst (type, false);
|
||||
|
||||
emit_tree_cond (&body, dest, done_label,
|
||||
fndecl (&body, arg, loc), t_true);
|
||||
|
||||
/* And finally, emit the default case if nothing else matches.
|
||||
This replaces the call to false. */
|
||||
gimple_seq_add_stmt (&body, gimple_build_assign (dest, t_false));
|
||||
gimple_seq_add_stmt (&body, gimple_build_label (done_label));
|
||||
|
||||
/* Build orig_dest = dest if necessary. */
|
||||
if (dest != orig_dest)
|
||||
{
|
||||
gimple_seq_add_stmt (&body, gimple_build_assign (orig_dest, dest));
|
||||
}
|
||||
|
||||
gsi_insert_seq_before (gsi, body, GSI_SAME_STMT);
|
||||
|
||||
/* Remove the call to the builtin. */
|
||||
gsi_remove (gsi, false);
|
||||
}
|
||||
|
||||
/* Lower and expand calls to __builtin_isnan in GSI. */
|
||||
static void
|
||||
lower_builtin_isnan (gimple_stmt_iterator *gsi)
|
||||
{
|
||||
gen_call_fp_builtin (gsi, &is_nan);
|
||||
}
|
||||
|
||||
/* Lower and expand calls to __builtin_isinfinite in GSI. */
|
||||
static void
|
||||
lower_builtin_isinfinite (gimple_stmt_iterator *gsi)
|
||||
{
|
||||
gen_call_fp_builtin (gsi, &is_infinity);
|
||||
}
|
||||
|
||||
/* Lower and expand calls to __builtin_isnormal in GSI. */
|
||||
static void
|
||||
lower_builtin_isnormal (gimple_stmt_iterator *gsi)
|
||||
{
|
||||
gen_call_fp_builtin (gsi, &is_normal);
|
||||
}
|
||||
|
||||
/* Lower and expand calls to __builtin_iszero in GSI. */
|
||||
static void
|
||||
lower_builtin_iszero (gimple_stmt_iterator *gsi)
|
||||
{
|
||||
gen_call_fp_builtin (gsi, &is_zero);
|
||||
}
|
||||
|
||||
/* Lower and expand calls to __builtin_issubnormal in GSI. */
|
||||
static void
|
||||
lower_builtin_issubnormal (gimple_stmt_iterator *gsi)
|
||||
{
|
||||
gen_call_fp_builtin (gsi, &is_subnormal);
|
||||
}
|
||||
|
||||
/* Lower and expand calls to __builtin_isfinite in GSI. */
|
||||
static void
|
||||
lower_builtin_isfinite (gimple_stmt_iterator *gsi)
|
||||
{
|
||||
gen_call_fp_builtin (gsi, &is_finite);
|
||||
}
|
||||
|
||||
/* Lower calls to posix_memalign to
|
||||
res = posix_memalign (ptr, align, size);
|
||||
if (res == 0)
|
||||
|
|
|
|||
34
gcc/real.c
34
gcc/real.c
|
|
@ -3052,6 +3052,7 @@ const struct real_format ieee_single_format =
|
|||
true,
|
||||
true,
|
||||
false,
|
||||
true,
|
||||
"ieee_single"
|
||||
};
|
||||
|
||||
|
|
@ -3075,6 +3076,7 @@ const struct real_format mips_single_format =
|
|||
true,
|
||||
false,
|
||||
true,
|
||||
true,
|
||||
"mips_single"
|
||||
};
|
||||
|
||||
|
|
@ -3098,6 +3100,7 @@ const struct real_format motorola_single_format =
|
|||
true,
|
||||
true,
|
||||
true,
|
||||
true,
|
||||
"motorola_single"
|
||||
};
|
||||
|
||||
|
|
@ -3132,6 +3135,7 @@ const struct real_format spu_single_format =
|
|||
true,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
"spu_single"
|
||||
};
|
||||
|
||||
|
|
@ -3343,6 +3347,7 @@ const struct real_format ieee_double_format =
|
|||
true,
|
||||
true,
|
||||
false,
|
||||
true,
|
||||
"ieee_double"
|
||||
};
|
||||
|
||||
|
|
@ -3366,6 +3371,7 @@ const struct real_format mips_double_format =
|
|||
true,
|
||||
false,
|
||||
true,
|
||||
true,
|
||||
"mips_double"
|
||||
};
|
||||
|
||||
|
|
@ -3389,6 +3395,7 @@ const struct real_format motorola_double_format =
|
|||
true,
|
||||
true,
|
||||
true,
|
||||
true,
|
||||
"motorola_double"
|
||||
};
|
||||
|
||||
|
|
@ -3735,6 +3742,7 @@ const struct real_format ieee_extended_motorola_format =
|
|||
true,
|
||||
true,
|
||||
true,
|
||||
false,
|
||||
"ieee_extended_motorola"
|
||||
};
|
||||
|
||||
|
|
@ -3758,6 +3766,7 @@ const struct real_format ieee_extended_intel_96_format =
|
|||
true,
|
||||
true,
|
||||
false,
|
||||
false,
|
||||
"ieee_extended_intel_96"
|
||||
};
|
||||
|
||||
|
|
@ -3781,6 +3790,7 @@ const struct real_format ieee_extended_intel_128_format =
|
|||
true,
|
||||
true,
|
||||
false,
|
||||
false,
|
||||
"ieee_extended_intel_128"
|
||||
};
|
||||
|
||||
|
|
@ -3806,6 +3816,7 @@ const struct real_format ieee_extended_intel_96_round_53_format =
|
|||
true,
|
||||
true,
|
||||
false,
|
||||
false,
|
||||
"ieee_extended_intel_96_round_53"
|
||||
};
|
||||
|
||||
|
|
@ -3896,6 +3907,7 @@ const struct real_format ibm_extended_format =
|
|||
true,
|
||||
true,
|
||||
false,
|
||||
false,
|
||||
"ibm_extended"
|
||||
};
|
||||
|
||||
|
|
@ -3919,6 +3931,7 @@ const struct real_format mips_extended_format =
|
|||
true,
|
||||
false,
|
||||
true,
|
||||
false,
|
||||
"mips_extended"
|
||||
};
|
||||
|
||||
|
|
@ -4184,6 +4197,7 @@ const struct real_format ieee_quad_format =
|
|||
true,
|
||||
true,
|
||||
false,
|
||||
true,
|
||||
"ieee_quad"
|
||||
};
|
||||
|
||||
|
|
@ -4207,6 +4221,7 @@ const struct real_format mips_quad_format =
|
|||
true,
|
||||
false,
|
||||
true,
|
||||
true,
|
||||
"mips_quad"
|
||||
};
|
||||
|
||||
|
|
@ -4509,6 +4524,7 @@ const struct real_format vax_f_format =
|
|||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
"vax_f"
|
||||
};
|
||||
|
||||
|
|
@ -4532,6 +4548,7 @@ const struct real_format vax_d_format =
|
|||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
"vax_d"
|
||||
};
|
||||
|
||||
|
|
@ -4555,6 +4572,7 @@ const struct real_format vax_g_format =
|
|||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
"vax_g"
|
||||
};
|
||||
|
||||
|
|
@ -4633,6 +4651,7 @@ const struct real_format decimal_single_format =
|
|||
true,
|
||||
true,
|
||||
false,
|
||||
false,
|
||||
"decimal_single"
|
||||
};
|
||||
|
||||
|
|
@ -4657,6 +4676,7 @@ const struct real_format decimal_double_format =
|
|||
true,
|
||||
true,
|
||||
false,
|
||||
false,
|
||||
"decimal_double"
|
||||
};
|
||||
|
||||
|
|
@ -4681,6 +4701,7 @@ const struct real_format decimal_quad_format =
|
|||
true,
|
||||
true,
|
||||
false,
|
||||
false,
|
||||
"decimal_quad"
|
||||
};
|
||||
|
||||
|
|
@ -4820,6 +4841,7 @@ const struct real_format ieee_half_format =
|
|||
true,
|
||||
true,
|
||||
false,
|
||||
true,
|
||||
"ieee_half"
|
||||
};
|
||||
|
||||
|
|
@ -4846,6 +4868,7 @@ const struct real_format arm_half_format =
|
|||
true,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
"arm_half"
|
||||
};
|
||||
|
||||
|
|
@ -4893,6 +4916,7 @@ const struct real_format real_internal_format =
|
|||
true,
|
||||
true,
|
||||
false,
|
||||
false,
|
||||
"real_internal"
|
||||
};
|
||||
|
||||
|
|
@ -5080,6 +5104,16 @@ get_max_float (const struct real_format *fmt, char *buf, size_t len)
|
|||
gcc_assert (strlen (buf) < len);
|
||||
}
|
||||
|
||||
/* Write into BUF the minimum negative representable finite floating-point
|
||||
number, x, such that b**(x-1) is normalized.
|
||||
BUF must be large enough to contain the result. */
|
||||
void
|
||||
get_min_float (const struct real_format *fmt, char *buf, size_t len)
|
||||
{
|
||||
sprintf (buf, "0x1p%d", fmt->emin - 1);
|
||||
gcc_assert (strlen (buf) < len);
|
||||
}
|
||||
|
||||
/* True if mode M has a NaN representation and
|
||||
the treatment of NaN operands is important. */
|
||||
|
||||
|
|
|
|||
18
gcc/real.h
18
gcc/real.h
|
|
@ -161,6 +161,19 @@ struct real_format
|
|||
bool has_signed_zero;
|
||||
bool qnan_msb_set;
|
||||
bool canonical_nan_lsbs_set;
|
||||
|
||||
/* This flag indicates whether the format is suitable for the optimized
|
||||
code paths for the __builtin_fpclassify function and friends. For
|
||||
this, the format must be a base 2 representation with the sign bit as
|
||||
the most-significant bit followed by (exp <= 32) exponent bits
|
||||
followed by the mantissa bits. It must be possible to interpret the
|
||||
bits of the floating-point representation as an integer. NaNs and
|
||||
INFs (if available) must be represented by the same schema used by
|
||||
IEEE 754. (NaNs must be represented by an exponent with all bits 1,
|
||||
any mantissa except all bits 0 and any sign bit. +INF and -INF must be
|
||||
represented by an exponent with all bits 1, a mantissa with all bits 0 and
|
||||
a sign bit of 0 and 1 respectively.) */
|
||||
bool is_binary_ieee_compatible;
|
||||
const char *name;
|
||||
};
|
||||
|
||||
|
|
@ -511,6 +524,11 @@ extern bool real_isinteger (const REAL_VALUE_TYPE *, HOST_WIDE_INT *);
|
|||
float string. BUF must be large enough to contain the result. */
|
||||
extern void get_max_float (const struct real_format *, char *, size_t);
|
||||
|
||||
/* Write into BUF the smallest positive normalized number x,
|
||||
such that b**(x-1) is normalized. BUF must be large enough
|
||||
to contain the result. */
|
||||
extern void get_min_float (const struct real_format *, char *, size_t);
|
||||
|
||||
#ifndef GENERATOR_FILE
|
||||
/* real related routines. */
|
||||
extern wide_int real_to_integer (const REAL_VALUE_TYPE *, bool *, int);
|
||||
|
|
|
|||
|
|
@ -1,3 +1,20 @@
|
|||
2017-06-08 Tamar Christina <tamar.christina@arm.com>
|
||||
|
||||
* gcc.target/aarch64/builtin-fpclassify.c: New codegen test.
|
||||
* gcc.dg/fold-notunord.c: Removed.
|
||||
* gcc.dg/torture/floatn-tg-4.h: Add tests for iszero and issubnormal.
|
||||
* gcc.dg/torture/float128-tg-4.c: Likewise.
|
||||
* gcc.dg/torture/float128x-tg-4: Likewise.
|
||||
* gcc.dg/torture/float16-tg-4.c: Likewise.
|
||||
* gcc.dg/torture/float32-tg-4.c: Likewise.
|
||||
* gcc.dg/torture/float32x-tg-4.c: Likewise.
|
||||
* gcc.dg/torture/float64-tg-4.c: Likewise.
|
||||
* gcc.dg/torture/float64x-tg-4.c: Likewise.
|
||||
* gcc.dg/pr28796-1.c: Add -O2.
|
||||
* gcc.dg/builtins-43.c: Check lower instead of gimple.
|
||||
* gcc.dg/tg-tests.h: Add iszero and issubnormal.
|
||||
* gcc.dg/pr77925.c: Add to test safe cases.
|
||||
|
||||
2017-06-08 Richard Biener <rguenther@suse.de>
|
||||
|
||||
PR tree-optimization/80928
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/* { dg-do compile } */
|
||||
/* { dg-options "-O1 -fno-trapping-math -fno-finite-math-only -fdump-tree-gimple -fdump-tree-optimized" } */
|
||||
/* { dg-options "-O1 -fno-trapping-math -fno-finite-math-only -fdump-tree-lower -fdump-tree-optimized" } */
|
||||
|
||||
extern void f(int);
|
||||
extern void link_error ();
|
||||
|
|
@ -51,7 +51,7 @@ main ()
|
|||
|
||||
|
||||
/* Check that all instances of __builtin_isnan were folded. */
|
||||
/* { dg-final { scan-tree-dump-times "isnan" 0 "gimple" } } */
|
||||
/* { dg-final { scan-tree-dump-times "isnan" 0 "lower" } } */
|
||||
|
||||
/* Check that all instances of link_error were subject to DCE. */
|
||||
/* { dg-final { scan-tree-dump-times "link_error" 0 "optimized" } } */
|
||||
|
|
|
|||
|
|
@ -1,9 +0,0 @@
|
|||
/* { dg-do compile } */
|
||||
/* { dg-options "-O -ftrapping-math -fdump-tree-optimized" } */
|
||||
|
||||
int f (double d)
|
||||
{
|
||||
return !__builtin_isnan (d);
|
||||
}
|
||||
|
||||
/* { dg-final { scan-tree-dump " ord " "optimized" } } */
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
/* { dg-do link } */
|
||||
/* { dg-options "-ffinite-math-only" } */
|
||||
/* { dg-options "-ffinite-math-only -O2" } */
|
||||
|
||||
extern void link_error(void);
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,11 @@
|
|||
/* { dg-do run } */
|
||||
/* { dg-options "-O2" } */
|
||||
/* { dg-add-options ieee } */
|
||||
/* { dg-skip-if "No Inf/NaN support" { spu-*-* } } */
|
||||
|
||||
#include "tg-tests.h"
|
||||
|
||||
int main(void)
|
||||
{
|
||||
return main_tests ();
|
||||
}
|
||||
|
|
@ -11,6 +11,7 @@ void __attribute__ ((__noinline__))
|
|||
foo_1 (float f, double d, long double ld,
|
||||
int res_unord, int res_isnan, int res_isinf,
|
||||
int res_isinf_sign, int res_isfin, int res_isnorm,
|
||||
int res_iszero, int res_issubnorm,
|
||||
int res_signbit, int classification)
|
||||
{
|
||||
if (__builtin_isunordered (f, 0) != res_unord)
|
||||
|
|
@ -80,6 +81,29 @@ foo_1 (float f, double d, long double ld,
|
|||
if (__builtin_finitel (ld) != res_isfin)
|
||||
__builtin_abort ();
|
||||
|
||||
/* On CPUs which flush denormals to zero these tests can never work one
|
||||
denormals for the floating point version of the implementation. The integer
|
||||
versions would work fine but we can't detect which version we have here. */
|
||||
#ifdef UNSAFE
|
||||
if (!res_issubnorm) {
|
||||
#endif
|
||||
if (__builtin_iszero (f) != res_iszero)
|
||||
__builtin_abort ();
|
||||
if (__builtin_iszero (d) != res_iszero)
|
||||
__builtin_abort ();
|
||||
if (__builtin_iszero (ld) != res_iszero)
|
||||
__builtin_abort ();
|
||||
|
||||
if (__builtin_issubnormal (f) != res_issubnorm)
|
||||
__builtin_abort ();
|
||||
if (__builtin_issubnormal (d) != res_issubnorm)
|
||||
__builtin_abort ();
|
||||
if (__builtin_issubnormal (ld) != res_issubnorm)
|
||||
__builtin_abort ();
|
||||
#ifdef UNSAFE
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Sign bit of zeros and nans is not preserved in unsafe math mode. */
|
||||
#ifdef UNSAFE
|
||||
if (!res_isnan && f != 0 && d != 0 && ld != 0)
|
||||
|
|
@ -115,12 +139,13 @@ foo_1 (float f, double d, long double ld,
|
|||
void __attribute__ ((__noinline__))
|
||||
foo (float f, double d, long double ld,
|
||||
int res_unord, int res_isnan, int res_isinf,
|
||||
int res_isfin, int res_isnorm, int classification)
|
||||
int res_isfin, int res_isnorm, int res_iszero,
|
||||
int res_issubnorm, int classification)
|
||||
{
|
||||
foo_1 (f, d, ld, res_unord, res_isnan, res_isinf, res_isinf, res_isfin, res_isnorm, 0, classification);
|
||||
foo_1 (f, d, ld, res_unord, res_isnan, res_isinf, res_isinf, res_isfin, res_isnorm, res_iszero, res_issubnorm, 0, classification);
|
||||
/* Try all the values negated as well. All will have the sign bit set,
|
||||
except for the nan. */
|
||||
foo_1 (-f, -d, -ld, res_unord, res_isnan, res_isinf, -res_isinf, res_isfin, res_isnorm, 1, classification);
|
||||
foo_1 (-f, -d, -ld, res_unord, res_isnan, res_isinf, -res_isinf, res_isfin, res_isnorm, res_iszero, res_issubnorm, 1, classification);
|
||||
}
|
||||
|
||||
int __attribute__ ((__noinline__))
|
||||
|
|
@ -132,35 +157,35 @@ main_tests (void)
|
|||
|
||||
/* Test NaN. */
|
||||
f = __builtin_nanf(""); d = __builtin_nan(""); ld = __builtin_nanl("");
|
||||
foo(f, d, ld, /*unord=*/ 1, /*isnan=*/ 1, /*isinf=*/ 0, /*isfin=*/ 0, /*isnorm=*/ 0, FP_NAN);
|
||||
foo(f, d, ld, /*unord=*/ 1, /*isnan=*/ 1, /*isinf=*/ 0, /*isfin=*/ 0, /*isnorm=*/ 0, /*iszero=*/0, /*issubnorm=*/0, FP_NAN);
|
||||
|
||||
/* Test infinity. */
|
||||
f = __builtin_inff(); d = __builtin_inf(); ld = __builtin_infl();
|
||||
foo(f, d, ld, /*unord=*/ 0, /*isnan=*/ 0, /*isinf=*/ 1, /*isfin=*/ 0, /*isnorm=*/ 0, FP_INFINITE);
|
||||
foo(f, d, ld, /*unord=*/ 0, /*isnan=*/ 0, /*isinf=*/ 1, /*isfin=*/ 0, /*isnorm=*/ 0, /*iszero=*/0, /*issubnorm=*/0, FP_INFINITE);
|
||||
|
||||
/* Test zero. */
|
||||
f = 0; d = 0; ld = 0;
|
||||
foo(f, d, ld, /*unord=*/ 0, /*isnan=*/ 0, /*isinf=*/ 0, /*isfin=*/ 1, /*isnorm=*/ 0, FP_ZERO);
|
||||
foo(f, d, ld, /*unord=*/ 0, /*isnan=*/ 0, /*isinf=*/ 0, /*isfin=*/ 1, /*isnorm=*/ 0, /*iszero=*/1, /*issubnorm=*/0, FP_ZERO);
|
||||
|
||||
/* Test one. */
|
||||
f = 1; d = 1; ld = 1;
|
||||
foo(f, d, ld, /*unord=*/ 0, /*isnan=*/ 0, /*isinf=*/ 0, /*isfin=*/ 1, /*isnorm=*/ 1, FP_NORMAL);
|
||||
foo(f, d, ld, /*unord=*/ 0, /*isnan=*/ 0, /*isinf=*/ 0, /*isfin=*/ 1, /*isnorm=*/ 1, /*iszero=*/0, /*issubnorm=*/0, FP_NORMAL);
|
||||
|
||||
/* Test minimum values. */
|
||||
f = __FLT_MIN__; d = __DBL_MIN__; ld = __LDBL_MIN__;
|
||||
foo(f, d, ld, /*unord=*/ 0, /*isnan=*/ 0, /*isinf=*/ 0, /*isfin=*/ 1, /*isnorm=*/ 1, FP_NORMAL);
|
||||
foo(f, d, ld, /*unord=*/ 0, /*isnan=*/ 0, /*isinf=*/ 0, /*isfin=*/ 1, /*isnorm=*/ 1, /*iszero=*/0, /*issubnorm=*/0, FP_NORMAL);
|
||||
|
||||
/* Test subnormal values. */
|
||||
f = __FLT_MIN__/2; d = __DBL_MIN__/2; ld = __LDBL_MIN__/2;
|
||||
foo(f, d, ld, /*unord=*/ 0, /*isnan=*/ 0, /*isinf=*/ 0, /*isfin=*/ 1, /*isnorm=*/ 0, FP_SUBNORMAL);
|
||||
foo(f, d, ld, /*unord=*/ 0, /*isnan=*/ 0, /*isinf=*/ 0, /*isfin=*/ 1, /*isnorm=*/ 0, /*iszero=*/0, /*issubnorm=*/1, FP_SUBNORMAL);
|
||||
|
||||
/* Test maximum values. */
|
||||
f = __FLT_MAX__; d = __DBL_MAX__; ld = __LDBL_MAX__;
|
||||
foo(f, d, ld, /*unord=*/ 0, /*isnan=*/ 0, /*isinf=*/ 0, /*isfin=*/ 1, /*isnorm=*/ 1, FP_NORMAL);
|
||||
foo(f, d, ld, /*unord=*/ 0, /*isnan=*/ 0, /*isinf=*/ 0, /*isfin=*/ 1, /*isnorm=*/ 1, /*iszero=*/0, /*issubnorm=*/0, FP_NORMAL);
|
||||
|
||||
/* Test overflow values. */
|
||||
f = __FLT_MAX__*2; d = __DBL_MAX__*2; ld = __LDBL_MAX__*2;
|
||||
foo(f, d, ld, /*unord=*/ 0, /*isnan=*/ 0, /*isinf=*/ 1, /*isfin=*/ 0, /*isnorm=*/ 0, FP_INFINITE);
|
||||
foo(f, d, ld, /*unord=*/ 0, /*isnan=*/ 0, /*isinf=*/ 1, /*isfin=*/ 0, /*isnorm=*/ 0, /*iszero=*/0, /*issubnorm=*/0, FP_INFINITE);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,11 @@
|
|||
/* Test _Float128 type-generic built-in functions: __builtin_iszero,
|
||||
__builtin_issubnormal. */
|
||||
/* { dg-do run } */
|
||||
/* { dg-options "" } */
|
||||
/* { dg-add-options float128 } */
|
||||
/* { dg-add-options ieee } */
|
||||
/* { dg-require-effective-target float128_runtime } */
|
||||
|
||||
#define WIDTH 128
|
||||
#define EXT 0
|
||||
#include "floatn-tg-4.h"
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
/* Test _Float128x type-generic built-in functions: __builtin_iszero,
|
||||
__builtin_issubnormal. */
|
||||
/* { dg-do run } */
|
||||
/* { dg-options "" } */
|
||||
/* { dg-add-options float128x } */
|
||||
/* { dg-add-options ieee } */
|
||||
/* { dg-require-effective-target float128x_runtime } */
|
||||
|
||||
#define WIDTH 128
|
||||
#define EXT 1
|
||||
#include "floatn-tg-4.h"
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
/* Test _Float16 type-generic built-in functions: __builtin_iszero,
|
||||
__builtin_issubnormal. */
|
||||
/* { dg-do run } */
|
||||
/* { dg-options "" } */
|
||||
/* { dg-add-options float16 } */
|
||||
/* { dg-add-options ieee } */
|
||||
/* { dg-require-effective-target float16_runtime } */
|
||||
|
||||
#define WIDTH 16
|
||||
#define EXT 0
|
||||
#include "floatn-tg-4.h"
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
/* Test _Float32 type-generic built-in functions: __builtin_f__builtin_iszero,
|
||||
__builtin_issubnormal. */
|
||||
/* { dg-do run } */
|
||||
/* { dg-options "" } */
|
||||
/* { dg-add-options float32 } */
|
||||
/* { dg-add-options ieee } */
|
||||
/* { dg-require-effective-target float32_runtime } */
|
||||
|
||||
#define WIDTH 32
|
||||
#define EXT 0
|
||||
#include "floatn-tg-4.h"
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
/* Test _Float32x type-generic built-in functions: __builtin_iszero,
|
||||
__builtin_issubnormal. */
|
||||
/* { dg-do run } */
|
||||
/* { dg-options "" } */
|
||||
/* { dg-add-options float32x } */
|
||||
/* { dg-add-options ieee } */
|
||||
/* { dg-require-effective-target float32x_runtime } */
|
||||
|
||||
#define WIDTH 32
|
||||
#define EXT 1
|
||||
#include "floatn-tg-4.h"
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
/* Test _Float64 type-generic built-in functions: __builtin_iszero,
|
||||
__builtin_issubnormal */
|
||||
/* { dg-do run } */
|
||||
/* { dg-options "" } */
|
||||
/* { dg-add-options float64 } */
|
||||
/* { dg-add-options ieee } */
|
||||
/* { dg-require-effective-target float64_runtime } */
|
||||
|
||||
#define WIDTH 64
|
||||
#define EXT 0
|
||||
#include "floatn-tg-4.h"
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
/* Test _Float64x type-generic built-in functions: __builtin_iszero,
|
||||
__builtin_issubnormal. */
|
||||
/* { dg-do run } */
|
||||
/* { dg-options "" } */
|
||||
/* { dg-add-options float64x } */
|
||||
/* { dg-add-options ieee } */
|
||||
/* { dg-require-effective-target float64x_runtime } */
|
||||
|
||||
#define WIDTH 64
|
||||
#define EXT 1
|
||||
#include "floatn-tg-4.h"
|
||||
|
|
@ -0,0 +1,99 @@
|
|||
/* Tests for _FloatN / _FloatNx types: compile and execution tests for
|
||||
type-generic built-in functions: __builtin_iszero, __builtin_issubnormal.
|
||||
Before including this file, define WIDTH as the value N; define EXT to 1
|
||||
for _FloatNx and 0 for _FloatN. */
|
||||
|
||||
#define __STDC_WANT_IEC_60559_TYPES_EXT__
|
||||
#include <float.h>
|
||||
|
||||
#define CONCATX(X, Y) X ## Y
|
||||
#define CONCAT(X, Y) CONCATX (X, Y)
|
||||
#define CONCAT3(X, Y, Z) CONCAT (CONCAT (X, Y), Z)
|
||||
#define CONCAT4(W, X, Y, Z) CONCAT (CONCAT (CONCAT (W, X), Y), Z)
|
||||
|
||||
#if EXT
|
||||
# define TYPE CONCAT3 (_Float, WIDTH, x)
|
||||
# define CST(C) CONCAT4 (C, f, WIDTH, x)
|
||||
# define MAX CONCAT3 (FLT, WIDTH, X_MAX)
|
||||
# define MIN CONCAT3 (FLT, WIDTH, X_MIN)
|
||||
# define TRUE_MIN CONCAT3 (FLT, WIDTH, X_TRUE_MIN)
|
||||
#else
|
||||
# define TYPE CONCAT (_Float, WIDTH)
|
||||
# define CST(C) CONCAT3 (C, f, WIDTH)
|
||||
# define MAX CONCAT3 (FLT, WIDTH, _MAX)
|
||||
# define MIN CONCAT3 (FLT, WIDTH, _MIN)
|
||||
# define TRUE_MIN CONCAT3 (FLT, WIDTH, _TRUE_MIN)
|
||||
#endif
|
||||
|
||||
extern void exit (int);
|
||||
extern void abort (void);
|
||||
|
||||
volatile TYPE inf = __builtin_inf (), nanval = __builtin_nan ("");
|
||||
volatile TYPE neginf = -__builtin_inf (), negnanval = -__builtin_nan ("");
|
||||
volatile TYPE zero = CST (0.0), negzero = -CST (0.0), one = CST (1.0);
|
||||
volatile TYPE max = MAX, negmax = -MAX, min = MIN, negmin = -MIN;
|
||||
volatile TYPE true_min = TRUE_MIN, negtrue_min = -TRUE_MIN;
|
||||
volatile TYPE sub_norm = MIN / 2.0;
|
||||
|
||||
int
|
||||
main (void)
|
||||
{
|
||||
if (__builtin_iszero (inf) == 1)
|
||||
abort ();
|
||||
if (__builtin_iszero (nanval) == 1)
|
||||
abort ();
|
||||
if (__builtin_iszero (neginf) == 1)
|
||||
abort ();
|
||||
if (__builtin_iszero (negnanval) == 1)
|
||||
abort ();
|
||||
if (__builtin_iszero (zero) != 1)
|
||||
abort ();
|
||||
if (__builtin_iszero (negzero) != 1)
|
||||
abort ();
|
||||
if (__builtin_iszero (one) == 1)
|
||||
abort ();
|
||||
if (__builtin_iszero (max) == 1)
|
||||
abort ();
|
||||
if (__builtin_iszero (negmax) == 1)
|
||||
abort ();
|
||||
if (__builtin_iszero (min) == 1)
|
||||
abort ();
|
||||
if (__builtin_iszero (negmin) == 1)
|
||||
abort ();
|
||||
if (__builtin_iszero (true_min) == 1)
|
||||
abort ();
|
||||
if (__builtin_iszero (negtrue_min) == 1)
|
||||
abort ();
|
||||
if (__builtin_iszero (sub_norm) == 1)
|
||||
abort ();
|
||||
|
||||
if (__builtin_issubnormal (inf) == 1)
|
||||
abort ();
|
||||
if (__builtin_issubnormal (nanval) == 1)
|
||||
abort ();
|
||||
if (__builtin_issubnormal (neginf) == 1)
|
||||
abort ();
|
||||
if (__builtin_issubnormal (negnanval) == 1)
|
||||
abort ();
|
||||
if (__builtin_issubnormal (zero) == 1)
|
||||
abort ();
|
||||
if (__builtin_issubnormal (negzero) == 1)
|
||||
abort ();
|
||||
if (__builtin_issubnormal (one) == 1)
|
||||
abort ();
|
||||
if (__builtin_issubnormal (max) == 1)
|
||||
abort ();
|
||||
if (__builtin_issubnormal (negmax) == 1)
|
||||
abort ();
|
||||
if (__builtin_issubnormal (min) == 1)
|
||||
abort ();
|
||||
if (__builtin_issubnormal (negmin) == 1)
|
||||
abort ();
|
||||
if (__builtin_issubnormal (true_min) != 1)
|
||||
abort ();
|
||||
if (__builtin_issubnormal (negtrue_min) != 1)
|
||||
abort ();
|
||||
if (__builtin_issubnormal (sub_norm) != 1)
|
||||
abort ();
|
||||
exit (0);
|
||||
}
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
/* This file checks the code generation for the new __builtin_fpclassify.
|
||||
because checking the exact assembly isn't very useful, we'll just be checking
|
||||
for the presence of certain instructions and the omition of others. */
|
||||
/* { dg-options "-O2" } */
|
||||
/* { dg-do compile } */
|
||||
/* { dg-final { scan-assembler-not "\[ \t\]?fabs\[ \t\]?" } } */
|
||||
/* { dg-final { scan-assembler-not "\[ \t\]?fcmp\[ \t\]?" } } */
|
||||
/* { dg-final { scan-assembler-not "\[ \t\]?fcmpe\[ \t\]?" } } */
|
||||
/* { dg-final { scan-assembler "\[ \t\]?ubfx\[ \t\]?" } } */
|
||||
|
||||
#include <stdio.h>
|
||||
#include <math.h>
|
||||
|
||||
/*
|
||||
fp_nan = args[0];
|
||||
fp_infinite = args[1];
|
||||
fp_normal = args[2];
|
||||
fp_subnormal = args[3];
|
||||
fp_zero = args[4];
|
||||
*/
|
||||
|
||||
int f(double x) { return __builtin_fpclassify(0, 1, 4, 3, 2, x); }
|
||||
Loading…
Reference in New Issue