diff options
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 |