aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAldy Hernandez <aldyh@redhat.com>2022-10-10 14:56:42 +0200
committerAldy Hernandez <aldyh@redhat.com>2022-10-11 15:52:24 +0200
commit706d8583706475fb103d1123e507f604dccb8fd3 (patch)
tree5b1b7bef4dba8ee7bf0a8b0b50afe73b6be9ad79
parentfe7371e7f93c247b5d0e257ca2a68064123cd018 (diff)
downloadgcc-706d8583706475fb103d1123e507f604dccb8fd3.zip
gcc-706d8583706475fb103d1123e507f604dccb8fd3.tar.gz
gcc-706d8583706475fb103d1123e507f604dccb8fd3.tar.bz2
Implement ABS_EXPR operator for frange.
Implementing ABS_EXPR allows us to fold certain __builtin_inf calls since they are expanded into calls to involving ABS_EXPR. This is an adaptation of the integer version. gcc/ChangeLog: * range-op-float.cc (class foperator_abs): New. (floating_op_table::floating_op_table): Add ABS_EXPR entry. gcc/testsuite/ChangeLog: * gcc.dg/tree-ssa/vrp-float-abs-1.c: New test.
-rw-r--r--gcc/range-op-float.cc91
-rw-r--r--gcc/testsuite/gcc.dg/tree-ssa/vrp-float-abs-1.c17
2 files changed, 108 insertions, 0 deletions
diff --git a/gcc/range-op-float.cc b/gcc/range-op-float.cc
index ef51b75..283eb13 100644
--- a/gcc/range-op-float.cc
+++ b/gcc/range-op-float.cc
@@ -1132,6 +1132,95 @@ foperator_ordered::op1_range (frange &r, tree type,
return true;
}
+class foperator_abs : public range_operator_float
+{
+ using range_operator_float::fold_range;
+ using range_operator_float::op1_range;
+public:
+ bool fold_range (frange &r, tree type,
+ const frange &op1, const frange &,
+ relation_kind) const final override;
+ bool op1_range (frange &r, tree type,
+ const frange &lhs, const frange &op2,
+ relation_kind rel) const final override;
+} fop_abs;
+
+bool
+foperator_abs::fold_range (frange &r, tree type,
+ const frange &op1, const frange &op2,
+ relation_kind) const
+{
+ if (empty_range_varying (r, type, op1, op2))
+ return true;
+ if (op1.known_isnan ())
+ {
+ r.set_nan (type, /*sign=*/false);
+ return true;
+ }
+
+ const REAL_VALUE_TYPE lh_lb = op1.lower_bound ();
+ const REAL_VALUE_TYPE lh_ub = op1.upper_bound ();
+ // Handle the easy case where everything is positive.
+ if (real_compare (GE_EXPR, &lh_lb, &dconst0)
+ && !real_iszero (&lh_lb, /*sign=*/true)
+ && !op1.maybe_isnan (/*sign=*/true))
+ {
+ r = op1;
+ return true;
+ }
+
+ REAL_VALUE_TYPE min = real_value_abs (&lh_lb);
+ REAL_VALUE_TYPE max = real_value_abs (&lh_ub);
+ // If the range contains zero then we know that the minimum value in the
+ // range will be zero.
+ if (real_compare (LE_EXPR, &lh_lb, &dconst0)
+ && real_compare (GE_EXPR, &lh_ub, &dconst0))
+ {
+ if (real_compare (GT_EXPR, &min, &max))
+ max = min;
+ min = dconst0;
+ }
+ else
+ {
+ // If the range was reversed, swap MIN and MAX.
+ if (real_compare (GT_EXPR, &min, &max))
+ std::swap (min, max);
+ }
+
+ r.set (type, min, max);
+ if (op1.maybe_isnan ())
+ r.update_nan (/*sign=*/false);
+ else
+ r.clear_nan ();
+ return true;
+}
+
+bool
+foperator_abs::op1_range (frange &r, tree type,
+ const frange &lhs, const frange &op2,
+ relation_kind) const
+{
+ if (empty_range_varying (r, type, lhs, op2))
+ return true;
+ if (lhs.known_isnan ())
+ {
+ r.set_nan (type);
+ return true;
+ }
+
+ // Start with the positives because negatives are an impossible result.
+ frange positives (type, dconst0, frange_val_max (type));
+ positives.update_nan (/*sign=*/false);
+ positives.intersect (lhs);
+ r = positives;
+ // Then add the negative of each pair:
+ // ABS(op1) = [5,20] would yield op1 => [-20,-5][5,20].
+ r.union_ (frange (type,
+ real_value_negate (&positives.upper_bound ()),
+ real_value_negate (&positives.lower_bound ())));
+ return true;
+}
+
class foperator_unordered_lt : public range_operator_float
{
using range_operator_float::fold_range;
@@ -1502,6 +1591,8 @@ floating_op_table::floating_op_table ()
set (UNEQ_EXPR, fop_unordered_equal);
set (ORDERED_EXPR, fop_ordered);
set (UNORDERED_EXPR, fop_unordered);
+
+ set (ABS_EXPR, fop_abs);
}
// Return a pointer to the range_operator_float instance, if there is
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/vrp-float-abs-1.c b/gcc/testsuite/gcc.dg/tree-ssa/vrp-float-abs-1.c
new file mode 100644
index 0000000..4b7b758
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/tree-ssa/vrp-float-abs-1.c
@@ -0,0 +1,17 @@
+// { dg-do compile }
+// { dg-options "-O2 -fno-thread-jumps -fdump-tree-evrp" }
+
+void link_error ();
+
+void
+foo (double x, double y)
+{
+ if (x > y && __builtin_signbit (y) == 0)
+ {
+ // y == +INF is impossible.
+ if (__builtin_isinf (y))
+ link_error ();
+ }
+}
+
+// { dg-final { scan-tree-dump-not "link_error" "evrp" } }