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