VN: Handle (a | b) !=/== 0 for predicates [PR117414]

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.

Changes since v1:
* v2: Use vn_valueize. Also canonicalize the comparison
      at the begining of insert_predicates_for_cond for
      constants to be on the rhs. Return early for
      non-ssa names on the lhs (after canonicalization).

Bootstrapped and tested on x86_64-linux-gnu.

	PR tree-optimization/117414

gcc/ChangeLog:

	* tree-ssa-sccvn.cc (insert_predicates_for_cond): Canonicalize the comparison.
	Don't insert anything if lhs is not a SSA_NAME. Handle `(a | b) !=/== 0`.

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>
This commit is contained in:
Andrew Pinski 2024-11-01 20:06:30 -07:00
parent b38f8294e4
commit 5780028466
3 changed files with 116 additions and 0 deletions

View File

@ -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" } } */

View File

@ -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" } } */

View File

@ -7901,6 +7901,21 @@ 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;
/* Canonicalize the comparison so the rhs are constants. */
if (CONSTANT_CLASS_P (lhs))
{
std::swap (lhs, rhs);
code = swap_tree_comparison (code);
}
/* If the lhs is not a ssa name, don't record anything. */
if (TREE_CODE (lhs) != SSA_NAME)
return;
tree_code icode = invert_tree_comparison (code, HONOR_NANS (lhs));
tree ops[2];
ops[0] = lhs;
@ -7929,6 +7944,27 @@ 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))
{
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;
tree nlhs;
nlhs = vn_valueize (gimple_assign_rhs1 (def_stmt));
insert_predicates_for_cond (EQ_EXPR, nlhs, rhs, e, nullptr);
nlhs = vn_valueize (gimple_assign_rhs2 (def_stmt));
insert_predicates_for_cond (EQ_EXPR, nlhs, rhs, e, nullptr);
}
}
}
/* Main stmt worker for RPO VN, process BB. */