diff options
author | Tamar Christina <tamar.christina@arm.com> | 2017-06-08 07:38:42 +0000 |
---|---|---|
committer | Tamar Christina <tnfchris@gcc.gnu.org> | 2017-06-08 07:38:42 +0000 |
commit | 94fc87ecdf45e2455deb7ee50e13765c98d4e904 (patch) | |
tree | 01e590119900d4a8b6df6a832bb5456d8a7fd03c /gcc/builtins.c | |
parent | fb4bc6ff6c08f4e5524fa5e1881b478b0f689155 (diff) | |
download | gcc-94fc87ecdf45e2455deb7ee50e13765c98d4e904.zip gcc-94fc87ecdf45e2455deb7ee50e13765c98d4e904.tar.gz gcc-94fc87ecdf45e2455deb7ee50e13765c98d4e904.tar.bz2 |
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
Diffstat (limited to 'gcc/builtins.c')
-rw-r--r-- | gcc/builtins.c | 374 |
1 files changed, 25 insertions, 349 deletions
diff --git a/gcc/builtins.c b/gcc/builtins.c index 30462ad..254dab6 100644 --- a/gcc/builtins.c +++ b/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 |