On Fri, Mar 18, 2022 at 7:33 PM Aldy Hernandez <al...@redhat.com> wrote:

> > >>>>> Consider the following interesting example:
> > >>>>>
> > >>>>> int foo(int x, double y) {
> > >>>>>      return (x * 0.0) < y;
> > >>>>> }
> > >>>>>
> > >>>>> Although we know that x (when converted to double) can't be NaN or
> > >>>>> Inf, we still worry that for negative values of x that (x * 0.0) may
> > >>>>> be -0.0 and so perform the multiplication at run-time. But in this
> > >>>>> case, the result of the comparison (-0.0 < y) will be exactly the
> > >>>>> same
> > >>>>> as (+0.0 < y) for any y, hence the above may be safely constant
> > >>>>> folded to "0.0 <
> > >>>> y"
> > >>>>> avoiding the multiplication at run-time.

Ok, once the "frange" infrastructure is in place, it's actually
trivial.  See attached patch and tests.  We can do everything with
small range-op entries and evrp / ranger will handle everything else.

Roger, I believe this is what you described:

+// { dg-do compile }
+// { dg-options "-O2 -fno-tree-forwprop -fno-thread-jumps
-fdump-tree-evrp -fdump-tree-optimized" }
+
+extern void link_error ();
+
+int foo(int x, double y)
+{
+      return (x * 0.0) < y;
+}
+
+// The multiply should be gone by *vrp time.
+// { dg-final { scan-tree-dump-not " \\* " "evrp" } }
+
+// Ultimately, there sound be no references to "x".
+// { dg-final { scan-tree-dump-not "x_" "optimized" } }

With the attached patch (and pending patches), we keep track that a
cast from int to float is guaranteed to not be NaN, which allows us to
fold x*0.0 into 0.0, and DCE to remove x altogether.  Also, as the
other tests show, we are able to resolve __builtin_isnan's for the
operations implemented.  It should be straightforward for someone with
floating point foo to extend this to all operations.

Aldy
From 2a6218e97782f63dfe9836e6024fbb28c8cbb803 Mon Sep 17 00:00:00 2001
From: Aldy Hernandez <al...@redhat.com>
Date: Mon, 21 Mar 2022 16:26:40 +0100
Subject: [PATCH] [frange] Implement NAN aware stubs for FLOAT_EXPR,
 UNORDERED_EXPR, and MULT_EXPR.

---
 gcc/range-op-float.cc                        | 90 ++++++++++++++++++++
 gcc/testsuite/gcc.dg/tree-ssa/vrp-float-01.c | 14 +++
 gcc/testsuite/gcc.dg/tree-ssa/vrp-float-02.c | 14 +++
 gcc/testsuite/gcc.dg/tree-ssa/vrp-float-03.c | 15 ++++
 4 files changed, 133 insertions(+)
 create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/vrp-float-01.c
 create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/vrp-float-02.c
 create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/vrp-float-03.c

diff --git a/gcc/range-op-float.cc b/gcc/range-op-float.cc
index 988a3938959..52aaa01ab0f 100644
--- a/gcc/range-op-float.cc
+++ b/gcc/range-op-float.cc
@@ -922,6 +922,93 @@ foperator_cst::fold_range (frange &r, tree type ATTRIBUTE_UNUSED,
   return true;
 }
 
+class foperator_cast : public range_operator
+{
+  using range_operator::fold_range;
+public:
+  virtual bool fold_range (frange &r, tree type,
+			   const irange &inner,
+			   const frange &outer,
+			   relation_kind rel = VREL_NONE) const override;
+} fop_convert;
+
+bool
+foperator_cast::fold_range (frange &r, tree type,
+			    const irange &inner,
+			    const frange &outer,
+			    relation_kind) const
+{
+  if (empty_range_varying (r, type, inner, outer))
+    return true;
+
+  r.set_varying (type);
+
+  // Some flags can be cleared when converting from ints.
+  r.clear_prop (FRANGE_PROP_NAN);
+
+  return true;
+}
+
+class foperator_unordered : public range_operator
+{
+  using range_operator::fold_range;
+public:
+  virtual bool fold_range (irange &r, tree type,
+			   const frange &lh,
+			   const frange &rh,
+			   relation_kind rel = VREL_NONE) const override;
+} fop_unordered;
+
+bool
+foperator_unordered::fold_range (irange &r, tree type,
+				 const frange &lh,
+				 const frange &rh,
+				 relation_kind) const
+{
+  if (empty_range_varying (r, type, lh, rh))
+    return true;
+
+  // Return FALSE if both operands are !NaN.
+  if (!lh.get_prop (FRANGE_PROP_NAN) && !rh.get_prop (FRANGE_PROP_NAN))
+    {
+      r = range_false (type);
+      return true;
+    }
+
+  return false;
+}
+
+class foperator_mult : public range_operator
+{
+  using range_operator::fold_range;
+public:
+  virtual bool fold_range (frange &r, tree type,
+			   const frange &lh,
+			   const frange &rh,
+			   relation_kind rel = VREL_NONE) const override;
+} fop_mult;
+
+bool
+foperator_mult::fold_range (frange &r, tree type,
+			    const frange &lh,
+			    const frange &rh,
+			    relation_kind) const
+{
+  if (empty_range_varying (r, type, lh, rh))
+    return true;
+
+  // When x is !Nan, x * 0.0 = 0.0
+  if (rh.zero_p ()
+      && !rh.get_prop (FRANGE_PROP_NAN)
+      && !lh.get_prop (FRANGE_PROP_NAN))
+    {
+      r.set_zero (type);
+      return true;
+    }
+
+  return false;
+}
+
 class floating_table : public range_op_table
 {
 public:
@@ -944,6 +1031,9 @@ floating_table::floating_table ()
   set (PAREN_EXPR, fop_identity);
   set (OBJ_TYPE_REF, fop_identity);
   set (REAL_CST, fop_real_cst);
+  set (FLOAT_EXPR, fop_convert);
+  set (UNORDERED_EXPR, fop_unordered);
+  set (MULT_EXPR, fop_mult);
 }
 
 #if CHECKING_P
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/vrp-float-01.c b/gcc/testsuite/gcc.dg/tree-ssa/vrp-float-01.c
new file mode 100644
index 00000000000..92af87091a8
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/tree-ssa/vrp-float-01.c
@@ -0,0 +1,14 @@
+// { dg-do compile }
+// { dg-options "-O2 -fno-tree-forwprop -fno-tree-ccp -fno-tree-fre -fdump-tree-evrp" }
+
+extern void link_error ();
+
+void
+foo ()
+{
+  float z = 0.0;
+  if (__builtin_isnan (z))
+    link_error ();
+}
+
+// { dg-final { scan-tree-dump-not "link_error" "evrp" } }
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/vrp-float-02.c b/gcc/testsuite/gcc.dg/tree-ssa/vrp-float-02.c
new file mode 100644
index 00000000000..d38ea523bea
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/tree-ssa/vrp-float-02.c
@@ -0,0 +1,14 @@
+// { dg-do compile }
+// { dg-options "-O2 -fno-tree-forwprop -fno-thread-jumps -fdump-tree-evrp" }
+
+extern void link_error ();
+
+void
+foo (int i)
+{
+  float z = i;
+  if (__builtin_isnan (z))
+    link_error ();
+}
+
+// { dg-final { scan-tree-dump-not "link_error" "evrp" } }
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/vrp-float-03.c b/gcc/testsuite/gcc.dg/tree-ssa/vrp-float-03.c
new file mode 100644
index 00000000000..6c26a295f94
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/tree-ssa/vrp-float-03.c
@@ -0,0 +1,15 @@
+// { dg-do compile }
+// { dg-options "-O2 -fno-tree-forwprop -fno-thread-jumps -fdump-tree-evrp -fdump-tree-optimized" }
+
+extern void link_error ();
+
+int foo(int x, double y) 
+{
+      return (x * 0.0) < y;
+}
+
+// The multiply should be gone by *vrp time.
+// { dg-final { scan-tree-dump-not " \\* " "evrp" } }
+
+// Ultimately, there sound be no references to "x".
+// { dg-final { scan-tree-dump-not "x_" "optimized" } }
-- 
2.35.1

Reply via email to