On Fri, Mar 18, 2022 at 7:33 PM Aldy Hernandez <[email protected]> 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 <[email protected]>
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