[2/4] VN: Handle `(a | b) !=/== 0` for predicates [PR117414]
Commit Message
For `(a | b) == 0`, we can "assert" on the true edge that
both `a == 0` and `b == 0` but nothing on the false edge.
For `(a | b) != 0`, we can "assert" on the false edge that
both `a == 0` and `b == 0` but nothing on the true edge.
This adds that predicate and allows us to optimize f0, f1,
and f2 in fre-predicated-[12].c.
Bootstrapped and tested on x86_64-linux-gnu.
PR tree-optimization/117414
gcc/ChangeLog:
* tree-ssa-sccvn.cc (insert_predicates_for_cond): Handle
`(a | b) !=/== 0` also.
gcc/testsuite/ChangeLog:
* gcc.dg/tree-ssa/fre-predicated-1.c: New test.
* gcc.dg/tree-ssa/fre-predicated-2.c: New test.
Signed-off-by: Andrew Pinski <quic_apinski@quicinc.com>
---
.../gcc.dg/tree-ssa/fre-predicated-1.c | 53 +++++++++++++++++++
.../gcc.dg/tree-ssa/fre-predicated-2.c | 27 ++++++++++
gcc/tree-ssa-sccvn.cc | 26 +++++++++
3 files changed, 106 insertions(+)
create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/fre-predicated-1.c
create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/fre-predicated-2.c
Comments
On Sat, Nov 2, 2024 at 4:10 PM Andrew Pinski <quic_apinski@quicinc.com> wrote:
>
> For `(a | b) == 0`, we can "assert" on the true edge that
> both `a == 0` and `b == 0` but nothing on the false edge.
> For `(a | b) != 0`, we can "assert" on the false edge that
> both `a == 0` and `b == 0` but nothing on the true edge.
> This adds that predicate and allows us to optimize f0, f1,
> and f2 in fre-predicated-[12].c.
>
> Bootstrapped and tested on x86_64-linux-gnu.
>
> PR tree-optimization/117414
>
> gcc/ChangeLog:
>
> * tree-ssa-sccvn.cc (insert_predicates_for_cond): Handle
> `(a | b) !=/== 0` also.
>
> gcc/testsuite/ChangeLog:
>
> * gcc.dg/tree-ssa/fre-predicated-1.c: New test.
> * gcc.dg/tree-ssa/fre-predicated-2.c: New test.
>
> Signed-off-by: Andrew Pinski <quic_apinski@quicinc.com>
> ---
> .../gcc.dg/tree-ssa/fre-predicated-1.c | 53 +++++++++++++++++++
> .../gcc.dg/tree-ssa/fre-predicated-2.c | 27 ++++++++++
> gcc/tree-ssa-sccvn.cc | 26 +++++++++
> 3 files changed, 106 insertions(+)
> create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/fre-predicated-1.c
> create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/fre-predicated-2.c
>
> diff --git a/gcc/testsuite/gcc.dg/tree-ssa/fre-predicated-1.c b/gcc/testsuite/gcc.dg/tree-ssa/fre-predicated-1.c
> new file mode 100644
> index 00000000000..d56952f5f24
> --- /dev/null
> +++ b/gcc/testsuite/gcc.dg/tree-ssa/fre-predicated-1.c
> @@ -0,0 +1,53 @@
> +/* { dg-do compile } */
> +/* { dg-options "-O2 -fdump-tree-optimized" } */
> +
> +/* PR tree-optimization/117414 */
> +
> +/* Fre1 should figure out that `*aaa != 0`
> + For f0, f1, and f2. */
> +
> +
> +void foo();
> +int f0(int *aaa, int j, int t)
> +{
> + int b = *aaa;
> + int c = b != 0;
> + int d = t != 0;
> + if (d | c)
> + return 0;
> + for(int i = 0; i < j; i++)
> + {
> + if (*aaa) foo();
> + }
> + return 0;
> +}
> +
> +int f1(int *aaa, int j, int t)
> +{
> + int b = *aaa;
> + if (b != 0 || t != 0)
> + return 0;
> + for(int i = 0; i < j; i++)
> + {
> + if (*aaa) foo();
> + }
> + return 0;
> +}
> +
> +
> +int f2(int *aaa, int j, int t)
> +{
> + int b = *aaa;
> + if (b != 0)
> + return 0;
> + if (t != 0)
> + return 0;
> + for(int i = 0; i < j; i++)
> + {
> + if (*aaa) foo();
> + }
> + return 0;
> +}
> +
> +/* { dg-final { scan-tree-dump-not "foo " "optimized" } } */
> +/* { dg-final { scan-tree-dump "return 0;" "optimized" } } */
> diff --git a/gcc/testsuite/gcc.dg/tree-ssa/fre-predicated-2.c b/gcc/testsuite/gcc.dg/tree-ssa/fre-predicated-2.c
> new file mode 100644
> index 00000000000..0123a5b54f7
> --- /dev/null
> +++ b/gcc/testsuite/gcc.dg/tree-ssa/fre-predicated-2.c
> @@ -0,0 +1,27 @@
> +/* { dg-do compile } */
> +/* { dg-options "-O2 -fdump-tree-optimized" } */
> +
> +/* PR tree-optimization/117414 */
> +
> +/* Fre1 should figure out that `*aaa != 0`
> + For f0, f1, and f2. */
> +
> +
> +void foo();
> +int f0(int *aaa, int j, int t)
> +{
> + int b = *aaa;
> + int d = b | t;
> + if (d == 0)
> + ;
> + else
> + return 0;
> + for(int i = 0; i < j; i++)
> + {
> + if (*aaa) foo();
> + }
> + return 0;
> +}
> +
> +/* { dg-final { scan-tree-dump-not "foo " "optimized" } } */
> +/* { dg-final { scan-tree-dump "return 0;" "optimized" } } */
> diff --git a/gcc/tree-ssa-sccvn.cc b/gcc/tree-ssa-sccvn.cc
> index a11bf968670..b3e6cd09007 100644
> --- a/gcc/tree-ssa-sccvn.cc
> +++ b/gcc/tree-ssa-sccvn.cc
> @@ -7901,6 +7901,9 @@ static void
> insert_predicates_for_cond (tree_code code, tree lhs, tree rhs,
> edge true_e, edge false_e)
> {
> + /* If both edges are null, then there is nothing to be done. */
> + if (!true_e && !false_e)
> + return;
> tree_code icode = invert_tree_comparison (code, HONOR_NANS (lhs));
> tree ops[2];
> ops[0] = lhs;
> @@ -7929,6 +7932,29 @@ insert_predicates_for_cond (tree_code code, tree lhs, tree rhs,
> if (false_e)
> insert_related_predicates_on_edge (icode, ops, false_e);
> }
> + if (integer_zerop (rhs)
> + && (code == NE_EXPR || code == EQ_EXPR)
> + && TREE_CODE (lhs) == SSA_NAME)
> + {
> + gimple *def_stmt = SSA_NAME_DEF_STMT (lhs);
> + /* (a | b) == 0 ->
> + on true edge assert: a == 0 & b == 0. */
> + /* (a | b) != 0 ->
> + on false edge assert: a == 0 & b == 0. */
> + if (is_gimple_assign (def_stmt)
> + && gimple_assign_rhs_code (def_stmt) == BIT_IOR_EXPR)
> + {
> + edge e = code == EQ_EXPR ? true_e : false_e;
> + insert_predicates_for_cond (EQ_EXPR,
> + gimple_assign_rhs1 (def_stmt),
I think you want vn_valueize (gimple_assign_rhs1 (def_stmt)) here.
> + rhs,
> + e, nullptr);
> + insert_predicates_for_cond (EQ_EXPR,
> + gimple_assign_rhs2 (def_stmt),
and here.
I did look at using ranger from VN but I failed to see how I can use
its relation
oracle, esp. when iterating and needing to maintain its cache ... so,
OK with the above change.
Richard.
> + rhs,
> + e, nullptr);
> + }
> + }
> }
>
> /* Main stmt worker for RPO VN, process BB. */
> --
> 2.43.0
>
new file mode 100644
@@ -0,0 +1,53 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-optimized" } */
+
+/* PR tree-optimization/117414 */
+
+/* Fre1 should figure out that `*aaa != 0`
+ For f0, f1, and f2. */
+
+
+void foo();
+int f0(int *aaa, int j, int t)
+{
+ int b = *aaa;
+ int c = b != 0;
+ int d = t != 0;
+ if (d | c)
+ return 0;
+ for(int i = 0; i < j; i++)
+ {
+ if (*aaa) foo();
+ }
+ return 0;
+}
+
+int f1(int *aaa, int j, int t)
+{
+ int b = *aaa;
+ if (b != 0 || t != 0)
+ return 0;
+ for(int i = 0; i < j; i++)
+ {
+ if (*aaa) foo();
+ }
+ return 0;
+}
+
+
+int f2(int *aaa, int j, int t)
+{
+ int b = *aaa;
+ if (b != 0)
+ return 0;
+ if (t != 0)
+ return 0;
+ for(int i = 0; i < j; i++)
+ {
+ if (*aaa) foo();
+ }
+ return 0;
+}
+
+/* { dg-final { scan-tree-dump-not "foo " "optimized" } } */
+/* { dg-final { scan-tree-dump "return 0;" "optimized" } } */
new file mode 100644
@@ -0,0 +1,27 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-optimized" } */
+
+/* PR tree-optimization/117414 */
+
+/* Fre1 should figure out that `*aaa != 0`
+ For f0, f1, and f2. */
+
+
+void foo();
+int f0(int *aaa, int j, int t)
+{
+ int b = *aaa;
+ int d = b | t;
+ if (d == 0)
+ ;
+ else
+ return 0;
+ for(int i = 0; i < j; i++)
+ {
+ if (*aaa) foo();
+ }
+ return 0;
+}
+
+/* { dg-final { scan-tree-dump-not "foo " "optimized" } } */
+/* { dg-final { scan-tree-dump "return 0;" "optimized" } } */
@@ -7901,6 +7901,9 @@ static void
insert_predicates_for_cond (tree_code code, tree lhs, tree rhs,
edge true_e, edge false_e)
{
+ /* If both edges are null, then there is nothing to be done. */
+ if (!true_e && !false_e)
+ return;
tree_code icode = invert_tree_comparison (code, HONOR_NANS (lhs));
tree ops[2];
ops[0] = lhs;
@@ -7929,6 +7932,29 @@ insert_predicates_for_cond (tree_code code, tree lhs, tree rhs,
if (false_e)
insert_related_predicates_on_edge (icode, ops, false_e);
}
+ if (integer_zerop (rhs)
+ && (code == NE_EXPR || code == EQ_EXPR)
+ && TREE_CODE (lhs) == SSA_NAME)
+ {
+ gimple *def_stmt = SSA_NAME_DEF_STMT (lhs);
+ /* (a | b) == 0 ->
+ on true edge assert: a == 0 & b == 0. */
+ /* (a | b) != 0 ->
+ on false edge assert: a == 0 & b == 0. */
+ if (is_gimple_assign (def_stmt)
+ && gimple_assign_rhs_code (def_stmt) == BIT_IOR_EXPR)
+ {
+ edge e = code == EQ_EXPR ? true_e : false_e;
+ insert_predicates_for_cond (EQ_EXPR,
+ gimple_assign_rhs1 (def_stmt),
+ rhs,
+ e, nullptr);
+ insert_predicates_for_cond (EQ_EXPR,
+ gimple_assign_rhs2 (def_stmt),
+ rhs,
+ e, nullptr);
+ }
+ }
}
/* Main stmt worker for RPO VN, process BB. */