Value Range: Add range op for builtin isinf
Checks
Context |
Check |
Description |
linaro-tcwg-bot/tcwg_gcc_build--master-arm |
success
|
Testing passed
|
linaro-tcwg-bot/tcwg_gcc_check--master-arm |
success
|
Testing passed
|
linaro-tcwg-bot/tcwg_gcc_build--master-aarch64 |
success
|
Testing passed
|
linaro-tcwg-bot/tcwg_gcc_check--master-aarch64 |
success
|
Testing passed
|
Commit Message
Hi,
The builtin isinf is not folded at front end if the corresponding optab
exists. It causes the range evaluation failed on the targets which has
optab_isinf. For instance, range-sincos.c will fail on the targets which
has optab_isinf as it calls builtin_isinf.
This patch fixed the problem by adding range op for builtin isinf.
Bootstrapped and tested on x86 and powerpc64-linux BE and LE with no
regressions. Is it OK for the trunk?
Thanks
Gui Haochen
ChangeLog
Value Range: Add range op for builtin isinf
The builtin isinf is not folded at front end if the corresponding optab
exists. So the range op fro isinf is needed for value range analysis. This
patch adds range op for builtin isinf.
gcc/
* gimple-range-op.cc (class cfn_isinf): New.
(op_cfn_isinf): New variables.
(gimple_range_op_handler::maybe_builtin_call): Handle
CASE_FLT_FN (BUILT_IN_ISINF).
gcc/testsuite/
* gcc/testsuite/gcc.dg/tree-ssa/range-isinf.c: New test.
patch.diff
@@ -1140,6 +1140,57 @@ private:
bool m_is_pos;
} op_cfn_goacc_dim_size (false), op_cfn_goacc_dim_pos (true);
+// Implement range operator for CFN_BUILT_IN_ISINF
+class cnf_isinf : public range_operator
+{
+public:
+ using range_operator::fold_range;
+ using range_operator::op1_range;
+ virtual bool fold_range (irange &r, tree type, const frange &op1,
+ const irange &, relation_trio) const override
+ {
+ if (op1.undefined_p ())
+ return false;
+
+ if (op1.known_isinf ())
+ {
+ r.set_nonzero (type);
+ return true;
+ }
+
+ if (op1.known_isnan ()
+ || (!real_isinf (&op1.lower_bound ())
+ && !real_isinf (&op1.upper_bound ())))
+ {
+ r.set_zero (type);
+ return true;
+ }
+
+ return false;
+ }
+ virtual bool op1_range (frange &r, tree type, const irange &lhs,
+ const frange &, relation_trio) const override
+ {
+ if (lhs.zero_p ())
+ {
+ nan_state nan (true);
+ r.set (type, real_min_representable (type),
+ real_max_representable (type), nan);
+ return true;
+ }
+
+ if (!range_includes_zero_p (&lhs))
+ {
+ // The range is [-INF,-INF][+INF,+INF], but it can't be represented.
+ // Set range to [-INF,+INF]
+ r.set_varying (type);
+ r.clear_nan ();
+ return true;
+ }
+
+ return false;
+ }
+} op_cfn_isinf;
// Implement range operator for CFN_BUILT_IN_
class cfn_parity : public range_operator
@@ -1232,6 +1283,11 @@ gimple_range_op_handler::maybe_builtin_call ()
m_operator = &op_cfn_signbit;
break;
+ CASE_FLT_FN (BUILT_IN_ISINF):
+ m_op1 = gimple_call_arg (call, 0);
+ m_operator = &op_cfn_isinf;
+ break;
+
CASE_CFN_COPYSIGN_ALL:
m_op1 = gimple_call_arg (call, 0);
m_op2 = gimple_call_arg (call, 1);
new file mode 100644
@@ -0,0 +1,44 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-evrp" } */
+
+#include <math.h>
+void link_error();
+
+void
+test1 (double x)
+{
+ if (x > __DBL_MAX__ && !__builtin_isinf (x))
+ link_error ();
+ if (x < -__DBL_MAX__ && !__builtin_isinf (x))
+ link_error ();
+}
+
+void
+test2 (float x)
+{
+ if (x > __FLT_MAX__ && !__builtin_isinf (x))
+ link_error ();
+ if (x < -__FLT_MAX__ && !__builtin_isinf (x))
+ link_error ();
+}
+
+void
+test3 (double x)
+{
+ if (!__builtin_isinf (x) && !__builtin_isnan (x) && x > __DBL_MAX__)
+ link_error ();
+ if (!__builtin_isinf (x) && !__builtin_isnan (x) && x < -__DBL_MAX__)
+ link_error ();
+}
+
+void
+test4 (float x)
+{
+ if (!__builtin_isinf (x) && !__builtin_isnan (x) && x > __FLT_MAX__)
+ link_error ();
+ if (!__builtin_isinf (x) && !__builtin_isnan (x) && x < -__FLT_MAX__)
+ link_error ();
+}
+
+/* { dg-final { scan-tree-dump-not "link_error" "evrp" } } */
+