aboutsummaryrefslogtreecommitdiff
path: root/gcc/fold-const-call.c
diff options
context:
space:
mode:
authorJakub Jelinek <jakub@redhat.com>2018-05-04 09:19:45 +0200
committerJakub Jelinek <jakub@gcc.gnu.org>2018-05-04 09:19:45 +0200
commit047823853d8324eab7d6ad8f266ee5395c4a76ff (patch)
tree577de47e3f2f5746febab4c2403441ef0d8abd9f /gcc/fold-const-call.c
parent105073e1cc39fbeb03aa40e294ffc3c400cfa844 (diff)
downloadgcc-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.c65
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;
}