diff options
author | Richard Sandiford <richard.sandiford@arm.com> | 2015-11-17 18:51:55 +0000 |
---|---|---|
committer | Richard Sandiford <rsandifo@gcc.gnu.org> | 2015-11-17 18:51:55 +0000 |
commit | 883cabdecdb052865f68bb910aef86fbb75cc925 (patch) | |
tree | 6dcadb07c42281f307350b2580b0ef025f6a79a7 /gcc/builtins.c | |
parent | 4cfe7a6c3569019e33dc86a54ec03aef87ad5d83 (diff) | |
download | gcc-883cabdecdb052865f68bb910aef86fbb75cc925.zip gcc-883cabdecdb052865f68bb910aef86fbb75cc925.tar.gz gcc-883cabdecdb052865f68bb910aef86fbb75cc925.tar.bz2 |
Extend tree-call-cdce to calls whose result is used
For -fmath-errno, builtins.c currently expands calls to sqrt to:
y = sqrt_optab (x);
if (y != y)
[ sqrt (x); or errno = EDOM; ]
The drawbacks of this are:
- the call to sqrt is protected by the result of the optab rather
than the input. It would be better to check __builtin_isless (x, 0),
like tree-call-cdce.c does.
- the branch isn't exposed at the gimple level and so gets little
high-level optimisation.
- we do this for log too, but for log a zero input produces
-inf rather than a NaN, and sets errno to ERANGE rather than EDOM.
This patch moves the code to tree-call-cdce.c instead, with the optab
operation being represented as an internal function. This means that
we can use the existing argument-based range checks rather than the
result-based checks and that we get more gimple optimisation of
the branch.
Previously the pass was only enabled by default at -O2 or above,
but the old builtins.c code was enabled at -O. The patch therefore
enables the pass at -O as well.
The previous patch to cfgexpand.c handled cases where functions
don't (or are assumed not to) set errno, so this patch makes
the builtins.c code dead.
Tested on x86_64-linux-gnu, aarch64-linux-gnu, arm-linux-gnueabi
and visium-elf (for the EDOM stuff).
gcc/
* builtins.c (expand_errno_check, expand_builtin_mathfn)
(expand_builtin_mathfn_2): Delete.
(expand_builtin): Remove handling of functions with
internal function equivalents.
* internal-fn.def (SET_EDOM): New internal function.
* internal-fn.h (set_edom_supported_p): Declare.
* internal-fn.c (expand_SET_EDOM): New function.
(set_edom_supported_p): Likewise.
* tree-call-cdce.c: Include builtins.h and internal-fn.h.
Rewrite comment at head of file.
(is_call_dce_candidate): Rename to...
(can_test_argument_range): ...this. Don't check gimple_call_lhs
or gimple_call_builtin_p here.
(edom_only_function): New function.
(shrink_wrap_one_built_in_call_with_conds): New function, split out
from...
(shrink_wrap_one_built_in_call): ...here.
(can_use_internal_fn, use_internal_fn): New functions.
(shrink_wrap_conditional_dead_built_in_calls): Call use_internal_fn
for calls that have an lhs.
(pass_call_cdce::gate): Remove optimize_function_for_speed_p check.
(pass_call_cdce::execute): Skip blocks that are optimized for size.
Check gimple_call_builtin_p here. Use can_use_internal_fn for
calls with an lhs.
* opts.c (default_options_table): Enable -ftree-builtin-call-cdce
at -O and above.
From-SVN: r230488
Diffstat (limited to 'gcc/builtins.c')
-rw-r--r-- | gcc/builtins.c | 331 |
1 files changed, 0 insertions, 331 deletions
diff --git a/gcc/builtins.c b/gcc/builtins.c index c422d0d..df5c493 100644 --- a/gcc/builtins.c +++ b/gcc/builtins.c @@ -101,9 +101,6 @@ static rtx expand_builtin_apply (rtx, rtx, rtx); static void expand_builtin_return (rtx); static enum type_class type_to_class (tree); static rtx expand_builtin_classify_type (tree); -static void expand_errno_check (tree, rtx); -static rtx expand_builtin_mathfn (tree, rtx, rtx); -static rtx expand_builtin_mathfn_2 (tree, rtx, rtx); static rtx expand_builtin_mathfn_3 (tree, rtx, rtx); static rtx expand_builtin_mathfn_ternary (tree, rtx, rtx); static rtx expand_builtin_interclass_mathfn (tree, rtx); @@ -1972,286 +1969,6 @@ replacement_internal_fn (gcall *call) return IFN_LAST; } -/* 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. */ - -static void -expand_errno_check (tree exp, rtx target) -{ - rtx_code_label *lab = gen_label_rtx (); - - /* Test the result; if it is NaN, set errno=EDOM because - the argument was not in the domain. */ - do_compare_rtx_and_jump (target, target, EQ, 0, GET_MODE (target), - NULL_RTX, NULL, lab, - /* The jump is very likely. */ - REG_BR_PROB_BASE - (REG_BR_PROB_BASE / 2000 - 1)); - -#ifdef TARGET_EDOM - /* If this built-in doesn't throw an exception, set errno directly. */ - if (TREE_NOTHROW (TREE_OPERAND (CALL_EXPR_FN (exp), 0))) - { -#ifdef GEN_ERRNO_RTX - rtx errno_rtx = GEN_ERRNO_RTX; -#else - rtx errno_rtx - = gen_rtx_MEM (word_mode, gen_rtx_SYMBOL_REF (Pmode, "errno")); -#endif - emit_move_insn (errno_rtx, - gen_int_mode (TARGET_EDOM, GET_MODE (errno_rtx))); - emit_label (lab); - return; - } -#endif - - /* Make sure the library call isn't expanded as a tail call. */ - CALL_EXPR_TAILCALL (exp) = 0; - - /* We can't set errno=EDOM directly; let the library call do it. - Pop the arguments right away in case the call gets deleted. */ - NO_DEFER_POP; - expand_call (exp, target, 0); - OK_DEFER_POP; - emit_label (lab); -} - -/* Expand a call to one of the builtin math functions (sqrt, exp, or log). - Return NULL_RTX 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. - SUBTARGET may be used as the target for computing one of EXP's operands. */ - -static rtx -expand_builtin_mathfn (tree exp, rtx target, rtx subtarget) -{ - optab builtin_optab; - rtx op0; - rtx_insn *insns; - tree fndecl = get_callee_fndecl (exp); - machine_mode mode; - bool errno_set = false; - bool try_widening = false; - tree arg; - - if (!validate_arglist (exp, REAL_TYPE, VOID_TYPE)) - return NULL_RTX; - - arg = CALL_EXPR_ARG (exp, 0); - - switch (DECL_FUNCTION_CODE (fndecl)) - { - CASE_FLT_FN (BUILT_IN_SQRT): - errno_set = ! tree_expr_nonnegative_p (arg); - try_widening = true; - builtin_optab = sqrt_optab; - break; - CASE_FLT_FN (BUILT_IN_EXP): - errno_set = true; builtin_optab = exp_optab; break; - CASE_FLT_FN (BUILT_IN_EXP10): - CASE_FLT_FN (BUILT_IN_POW10): - errno_set = true; builtin_optab = exp10_optab; break; - CASE_FLT_FN (BUILT_IN_EXP2): - errno_set = true; builtin_optab = exp2_optab; break; - CASE_FLT_FN (BUILT_IN_EXPM1): - errno_set = true; builtin_optab = expm1_optab; break; - CASE_FLT_FN (BUILT_IN_LOGB): - errno_set = true; builtin_optab = logb_optab; break; - CASE_FLT_FN (BUILT_IN_LOG): - errno_set = true; builtin_optab = log_optab; break; - CASE_FLT_FN (BUILT_IN_LOG10): - errno_set = true; builtin_optab = log10_optab; break; - CASE_FLT_FN (BUILT_IN_LOG2): - errno_set = true; builtin_optab = log2_optab; break; - CASE_FLT_FN (BUILT_IN_LOG1P): - errno_set = true; builtin_optab = log1p_optab; break; - CASE_FLT_FN (BUILT_IN_ASIN): - builtin_optab = asin_optab; break; - CASE_FLT_FN (BUILT_IN_ACOS): - builtin_optab = acos_optab; break; - CASE_FLT_FN (BUILT_IN_TAN): - builtin_optab = tan_optab; break; - CASE_FLT_FN (BUILT_IN_ATAN): - builtin_optab = atan_optab; break; - CASE_FLT_FN (BUILT_IN_FLOOR): - builtin_optab = floor_optab; break; - CASE_FLT_FN (BUILT_IN_CEIL): - builtin_optab = ceil_optab; break; - CASE_FLT_FN (BUILT_IN_TRUNC): - builtin_optab = btrunc_optab; break; - CASE_FLT_FN (BUILT_IN_ROUND): - builtin_optab = round_optab; break; - CASE_FLT_FN (BUILT_IN_NEARBYINT): - builtin_optab = nearbyint_optab; - if (flag_trapping_math) - break; - /* Else fallthrough and expand as rint. */ - CASE_FLT_FN (BUILT_IN_RINT): - builtin_optab = rint_optab; break; - CASE_FLT_FN (BUILT_IN_SIGNIFICAND): - builtin_optab = significand_optab; break; - default: - gcc_unreachable (); - } - - /* Make a suitable register to place result in. */ - mode = TYPE_MODE (TREE_TYPE (exp)); - - if (! flag_errno_math || ! HONOR_NANS (mode)) - errno_set = false; - - /* Before working hard, check whether the instruction is available, but try - to widen the mode for specific operations. */ - if ((optab_handler (builtin_optab, mode) != CODE_FOR_nothing - || (try_widening && !excess_precision_type (TREE_TYPE (exp)))) - && (!errno_set || !optimize_insn_for_size_p ())) - { - rtx result = gen_reg_rtx (mode); - - /* Wrap the computation of the argument in a SAVE_EXPR, as we may - need to expand the argument again. This way, we will not perform - side-effects more the once. */ - CALL_EXPR_ARG (exp, 0) = arg = builtin_save_expr (arg); - - op0 = expand_expr (arg, subtarget, VOIDmode, EXPAND_NORMAL); - - start_sequence (); - - /* Compute into RESULT. - Set RESULT to wherever the result comes back. */ - result = expand_unop (mode, builtin_optab, op0, result, 0); - - if (result != 0) - { - if (errno_set) - expand_errno_check (exp, result); - - /* Output the entire sequence. */ - insns = get_insns (); - end_sequence (); - emit_insn (insns); - return result; - } - - /* If we were unable to expand via the builtin, stop the sequence - (without outputting the insns) and call to the library function - with the stabilized argument list. */ - end_sequence (); - } - - return expand_call (exp, target, target == const0_rtx); -} - -/* Expand a call to the builtin binary math functions (pow and atan2). - Return NULL_RTX 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. - SUBTARGET may be used as the target for computing one of EXP's - operands. */ - -static rtx -expand_builtin_mathfn_2 (tree exp, rtx target, rtx subtarget) -{ - optab builtin_optab; - rtx op0, op1, result; - rtx_insn *insns; - int op1_type = REAL_TYPE; - tree fndecl = get_callee_fndecl (exp); - tree arg0, arg1; - machine_mode mode; - bool errno_set = true; - - switch (DECL_FUNCTION_CODE (fndecl)) - { - CASE_FLT_FN (BUILT_IN_SCALBN): - CASE_FLT_FN (BUILT_IN_SCALBLN): - CASE_FLT_FN (BUILT_IN_LDEXP): - op1_type = INTEGER_TYPE; - default: - break; - } - - if (!validate_arglist (exp, REAL_TYPE, op1_type, VOID_TYPE)) - return NULL_RTX; - - arg0 = CALL_EXPR_ARG (exp, 0); - arg1 = CALL_EXPR_ARG (exp, 1); - - switch (DECL_FUNCTION_CODE (fndecl)) - { - CASE_FLT_FN (BUILT_IN_POW): - builtin_optab = pow_optab; break; - CASE_FLT_FN (BUILT_IN_ATAN2): - builtin_optab = atan2_optab; break; - CASE_FLT_FN (BUILT_IN_SCALB): - if (REAL_MODE_FORMAT (TYPE_MODE (TREE_TYPE (exp)))->b != 2) - return 0; - builtin_optab = scalb_optab; break; - CASE_FLT_FN (BUILT_IN_SCALBN): - CASE_FLT_FN (BUILT_IN_SCALBLN): - if (REAL_MODE_FORMAT (TYPE_MODE (TREE_TYPE (exp)))->b != 2) - return 0; - /* Fall through... */ - CASE_FLT_FN (BUILT_IN_LDEXP): - builtin_optab = ldexp_optab; break; - CASE_FLT_FN (BUILT_IN_FMOD): - builtin_optab = fmod_optab; break; - CASE_FLT_FN (BUILT_IN_REMAINDER): - CASE_FLT_FN (BUILT_IN_DREM): - builtin_optab = remainder_optab; break; - default: - gcc_unreachable (); - } - - /* Make a suitable register to place result in. */ - mode = TYPE_MODE (TREE_TYPE (exp)); - - /* Before working hard, check whether the instruction is available. */ - if (optab_handler (builtin_optab, mode) == CODE_FOR_nothing) - return NULL_RTX; - - result = gen_reg_rtx (mode); - - if (! flag_errno_math || ! HONOR_NANS (mode)) - errno_set = false; - - if (errno_set && optimize_insn_for_size_p ()) - return 0; - - /* Always stabilize the argument list. */ - CALL_EXPR_ARG (exp, 0) = arg0 = builtin_save_expr (arg0); - CALL_EXPR_ARG (exp, 1) = arg1 = builtin_save_expr (arg1); - - op0 = expand_expr (arg0, subtarget, VOIDmode, EXPAND_NORMAL); - op1 = expand_normal (arg1); - - start_sequence (); - - /* Compute into RESULT. - Set RESULT to wherever the result comes back. */ - result = expand_binop (mode, builtin_optab, op0, op1, - result, 0, OPTAB_DIRECT); - - /* If we were unable to expand via the builtin, stop the sequence - (without outputting the insns) and call to the library function - with the stabilized argument list. */ - if (result == 0) - { - end_sequence (); - return expand_call (exp, target, target == const0_rtx); - } - - if (errno_set) - expand_errno_check (exp, result); - - /* Output the entire sequence. */ - insns = get_insns (); - end_sequence (); - emit_insn (insns); - - return result; -} - /* Expand a call to the builtin trinary math functions (fma). Return NULL_RTX 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 @@ -5984,37 +5701,6 @@ expand_builtin (tree exp, rtx target, rtx subtarget, machine_mode mode, CASE_FLT_FN (BUILT_IN_CABS): break; - CASE_FLT_FN (BUILT_IN_EXP): - CASE_FLT_FN (BUILT_IN_EXP10): - CASE_FLT_FN (BUILT_IN_POW10): - CASE_FLT_FN (BUILT_IN_EXP2): - CASE_FLT_FN (BUILT_IN_EXPM1): - CASE_FLT_FN (BUILT_IN_LOGB): - CASE_FLT_FN (BUILT_IN_LOG): - CASE_FLT_FN (BUILT_IN_LOG10): - CASE_FLT_FN (BUILT_IN_LOG2): - CASE_FLT_FN (BUILT_IN_LOG1P): - CASE_FLT_FN (BUILT_IN_TAN): - CASE_FLT_FN (BUILT_IN_ASIN): - CASE_FLT_FN (BUILT_IN_ACOS): - CASE_FLT_FN (BUILT_IN_ATAN): - CASE_FLT_FN (BUILT_IN_SIGNIFICAND): - /* Treat these like sqrt only if unsafe math optimizations are allowed, - because of possible accuracy problems. */ - if (! flag_unsafe_math_optimizations) - break; - CASE_FLT_FN (BUILT_IN_SQRT): - CASE_FLT_FN (BUILT_IN_FLOOR): - CASE_FLT_FN (BUILT_IN_CEIL): - CASE_FLT_FN (BUILT_IN_TRUNC): - CASE_FLT_FN (BUILT_IN_ROUND): - CASE_FLT_FN (BUILT_IN_NEARBYINT): - CASE_FLT_FN (BUILT_IN_RINT): - target = expand_builtin_mathfn (exp, target, subtarget); - if (target) - return target; - break; - CASE_FLT_FN (BUILT_IN_FMA): target = expand_builtin_mathfn_ternary (exp, target, subtarget); if (target) @@ -6061,23 +5747,6 @@ expand_builtin (tree exp, rtx target, rtx subtarget, machine_mode mode, return target; break; - CASE_FLT_FN (BUILT_IN_ATAN2): - CASE_FLT_FN (BUILT_IN_LDEXP): - CASE_FLT_FN (BUILT_IN_SCALB): - CASE_FLT_FN (BUILT_IN_SCALBN): - CASE_FLT_FN (BUILT_IN_SCALBLN): - if (! flag_unsafe_math_optimizations) - break; - - CASE_FLT_FN (BUILT_IN_FMOD): - CASE_FLT_FN (BUILT_IN_REMAINDER): - CASE_FLT_FN (BUILT_IN_DREM): - CASE_FLT_FN (BUILT_IN_POW): - target = expand_builtin_mathfn_2 (exp, target, subtarget); - if (target) - return target; - break; - CASE_FLT_FN (BUILT_IN_CEXPI): target = expand_builtin_cexpi (exp, target); gcc_assert (target); |