aboutsummaryrefslogtreecommitdiff
path: root/gcc/builtins.c
diff options
context:
space:
mode:
authorRichard Sandiford <richard.sandiford@arm.com>2015-11-17 18:51:55 +0000
committerRichard Sandiford <rsandifo@gcc.gnu.org>2015-11-17 18:51:55 +0000
commit883cabdecdb052865f68bb910aef86fbb75cc925 (patch)
tree6dcadb07c42281f307350b2580b0ef025f6a79a7 /gcc/builtins.c
parent4cfe7a6c3569019e33dc86a54ec03aef87ad5d83 (diff)
downloadgcc-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.c331
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);