diff options
Diffstat (limited to 'gcc/builtins.c')
-rw-r--r-- | gcc/builtins.c | 60 |
1 files changed, 54 insertions, 6 deletions
diff --git a/gcc/builtins.c b/gcc/builtins.c index 4211e62..3060f80 100644 --- a/gcc/builtins.c +++ b/gcc/builtins.c @@ -1669,10 +1669,15 @@ expand_builtin_classify_type (tree exp) fcodel = BUILT_IN_MATHFN##L_R ; break; /* Return mathematic function equivalent to FN but operating directly - on TYPE, if available. If we can't do the conversion, return zero. */ -tree -mathfn_built_in (tree type, enum built_in_function fn) + on TYPE, if available. If IMPLICIT is true find the function in + implicit_built_in_decls[], otherwise use built_in_decls[]. If we + can't do the conversion, return zero. */ + +static tree +mathfn_built_in_1 (tree type, enum built_in_function fn, bool implicit) { + tree const *const fn_arr + = implicit ? implicit_built_in_decls : built_in_decls; enum built_in_function fcode, fcodef, fcodel; switch (fn) @@ -1747,6 +1752,7 @@ mathfn_built_in (tree type, enum built_in_function fn) CASE_MATHFN (BUILT_IN_SCALB) CASE_MATHFN (BUILT_IN_SCALBLN) CASE_MATHFN (BUILT_IN_SCALBN) + CASE_MATHFN (BUILT_IN_SIGNBIT) CASE_MATHFN (BUILT_IN_SIGNIFICAND) CASE_MATHFN (BUILT_IN_SIN) CASE_MATHFN (BUILT_IN_SINCOS) @@ -1765,15 +1771,23 @@ mathfn_built_in (tree type, enum built_in_function fn) } if (TYPE_MAIN_VARIANT (type) == double_type_node) - return implicit_built_in_decls[fcode]; + return fn_arr[fcode]; else if (TYPE_MAIN_VARIANT (type) == float_type_node) - return implicit_built_in_decls[fcodef]; + return fn_arr[fcodef]; else if (TYPE_MAIN_VARIANT (type) == long_double_type_node) - return implicit_built_in_decls[fcodel]; + return fn_arr[fcodel]; else return NULL_TREE; } +/* Like mathfn_built_in_1(), but always use the implicit array. */ + +tree +mathfn_built_in (tree type, enum built_in_function fn) +{ + return mathfn_built_in_1 (type, fn, /*implicit=*/ 1); +} + /* If errno must be maintained, expand the RTL to check if the result, TARGET, of a built-in function call, EXP, is NaN, and if so set errno to EDOM. */ @@ -9668,6 +9682,37 @@ fold_builtin_classify (tree fndecl, tree arg, int builtin_index) return NULL_TREE; + case BUILT_IN_ISINF_SIGN: + { + /* isinf_sign(x) -> isinf(x) ? (signbit(x) ? -1 : 1) : 0 */ + /* In a boolean context, GCC will fold the inner COND_EXPR to + 1. So e.g. "if (isinf_sign(x))" would be folded to just + "if (isinf(x) ? 1 : 0)" which becomes "if (isinf(x))". */ + tree signbit_fn = mathfn_built_in_1 (TREE_TYPE (arg), BUILT_IN_SIGNBIT, 0); + tree isinf_fn = built_in_decls[BUILT_IN_ISINF]; + tree tmp = NULL_TREE; + + arg = builtin_save_expr (arg); + + if (signbit_fn && isinf_fn) + { + tree signbit_call = build_call_expr (signbit_fn, 1, arg); + tree isinf_call = build_call_expr (isinf_fn, 1, arg); + + signbit_call = fold_build2 (NE_EXPR, integer_type_node, + signbit_call, integer_zero_node); + isinf_call = fold_build2 (NE_EXPR, integer_type_node, + isinf_call, integer_zero_node); + + tmp = fold_build3 (COND_EXPR, integer_type_node, signbit_call, + integer_minus_one_node, integer_one_node); + tmp = fold_build3 (COND_EXPR, integer_type_node, isinf_call, tmp, + integer_zero_node); + } + + return tmp; + } + case BUILT_IN_ISFINITE: if (!HONOR_NANS (TYPE_MODE (TREE_TYPE (arg))) && !HONOR_INFINITIES (TYPE_MODE (TREE_TYPE (arg)))) @@ -10074,6 +10119,9 @@ fold_builtin_1 (tree fndecl, tree arg0, bool ignore) case BUILT_IN_ISINFD128: return fold_builtin_classify (fndecl, arg0, BUILT_IN_ISINF); + case BUILT_IN_ISINF_SIGN: + return fold_builtin_classify (fndecl, arg0, BUILT_IN_ISINF_SIGN); + CASE_FLT_FN (BUILT_IN_ISNAN): case BUILT_IN_ISNAND32: case BUILT_IN_ISNAND64: |