diff options
author | Jakub Jelinek <jakub@redhat.com> | 2018-05-04 09:19:45 +0200 |
---|---|---|
committer | Jakub Jelinek <jakub@gcc.gnu.org> | 2018-05-04 09:19:45 +0200 |
commit | 047823853d8324eab7d6ad8f266ee5395c4a76ff (patch) | |
tree | 577de47e3f2f5746febab4c2403441ef0d8abd9f /gcc/fold-const-call.c | |
parent | 105073e1cc39fbeb03aa40e294ffc3c400cfa844 (diff) | |
download | gcc-047823853d8324eab7d6ad8f266ee5395c4a76ff.zip gcc-047823853d8324eab7d6ad8f266ee5395c4a76ff.tar.gz gcc-047823853d8324eab7d6ad8f266ee5395c4a76ff.tar.bz2 |
re PR tree-optimization/85466 (Performance is slow when doing 'branchless' conditional style math operations)
PR libstdc++/85466
* real.h (real_nextafter): Declare.
* real.c (real_nextafter): New function.
* fold-const-call.c (fold_const_nextafter): New function.
(fold_const_call_sss): Call it for CASE_CFN_NEXTAFTER and
CASE_CFN_NEXTTOWARD.
(fold_const_call_1): For CASE_CFN_NEXTTOWARD call fold_const_call_sss
even when arg1_mode is different from arg0_mode.
* gcc.dg/nextafter-1.c: New test.
* gcc.dg/nextafter-2.c: New test.
* gcc.dg/nextafter-3.c: New test.
* gcc.dg/nextafter-4.c: New test.
From-SVN: r259921
Diffstat (limited to 'gcc/fold-const-call.c')
-rw-r--r-- | gcc/fold-const-call.c | 65 |
1 files changed, 62 insertions, 3 deletions
diff --git a/gcc/fold-const-call.c b/gcc/fold-const-call.c index fcf4a14..4969492 100644 --- a/gcc/fold-const-call.c +++ b/gcc/fold-const-call.c @@ -529,6 +529,48 @@ fold_const_pow (real_value *result, const real_value *arg0, /* Try to evaluate: + *RESULT = nextafter (*ARG0, *ARG1) + + or + + *RESULT = nexttoward (*ARG0, *ARG1) + + in format FORMAT. Return true on success. */ + +static bool +fold_const_nextafter (real_value *result, const real_value *arg0, + const real_value *arg1, const real_format *format) +{ + if (REAL_VALUE_ISSIGNALING_NAN (*arg0) + || REAL_VALUE_ISSIGNALING_NAN (*arg1)) + return false; + + /* Don't handle composite modes, nor decimal, nor modes without + inf or denorm at least for now. */ + if (format->pnan < format->p + || format->b == 10 + || !format->has_inf + || !format->has_denorm) + return false; + + if (real_nextafter (result, format, arg0, arg1) + /* If raising underflow or overflow and setting errno to ERANGE, + fail if we care about those side-effects. */ + && (flag_trapping_math || flag_errno_math)) + return false; + /* Similarly for nextafter (0, 1) raising underflow. */ + else if (flag_trapping_math + && arg0->cl == rvc_zero + && result->cl != rvc_zero) + return false; + + real_convert (result, format, result); + + return true; +} + +/* Try to evaluate: + *RESULT = ldexp (*ARG0, ARG1) in format FORMAT. Return true on success. */ @@ -1260,6 +1302,10 @@ fold_const_call_sss (real_value *result, combined_fn fn, CASE_CFN_POW: return fold_const_pow (result, arg0, arg1, format); + CASE_CFN_NEXTAFTER: + CASE_CFN_NEXTTOWARD: + return fold_const_nextafter (result, arg0, arg1, format); + default: return false; } @@ -1365,20 +1411,33 @@ fold_const_call_1 (combined_fn fn, tree type, tree arg0, tree arg1) machine_mode arg0_mode = TYPE_MODE (TREE_TYPE (arg0)); machine_mode arg1_mode = TYPE_MODE (TREE_TYPE (arg1)); - if (arg0_mode == arg1_mode + if (mode == arg0_mode && real_cst_p (arg0) && real_cst_p (arg1)) { gcc_checking_assert (SCALAR_FLOAT_MODE_P (arg0_mode)); - if (mode == arg0_mode) + REAL_VALUE_TYPE result; + if (arg0_mode == arg1_mode) { /* real, real -> real. */ - REAL_VALUE_TYPE result; if (fold_const_call_sss (&result, fn, TREE_REAL_CST_PTR (arg0), TREE_REAL_CST_PTR (arg1), REAL_MODE_FORMAT (mode))) return build_real (type, result); } + else if (arg1_mode == TYPE_MODE (long_double_type_node)) + switch (fn) + { + CASE_CFN_NEXTTOWARD: + /* real, long double -> real. */ + if (fold_const_call_sss (&result, fn, TREE_REAL_CST_PTR (arg0), + TREE_REAL_CST_PTR (arg1), + REAL_MODE_FORMAT (mode))) + return build_real (type, result); + break; + default: + break; + } return NULL_TREE; } |