match: Optimize max(a,b) == 0 to (a|b) == 0 for unsigned [PR115275]

For unsigned types, you can optimize `max<a,b> == 0` into
`(a|b) == 0` (that is both have to be zero). A similar thing happens for `!= 0`.
This optimization fixes the missed optimization (g++.dg/tree-ssa/pr115275.C)
that was reported exposed by adding phiprop early.

Bootstrapped and tested on x86_64-linux-gnu.

	PR tree-optimization/115275

gcc/ChangeLog:

	* match.pd (umax(a,b) ==/!= 0): New pattern.

gcc/testsuite/ChangeLog:

	* g++.dg/tree-ssa/pr115275.C: New test.
	* gcc.dg/tree-ssa/max_eqne-1.c: New test.
	* gcc.dg/tree-ssa/max_eqne-2.c: New test.

Signed-off-by: Andrew Pinski <quic_apinski@quicinc.com>
This commit is contained in:
Andrew Pinski 2024-11-15 23:20:42 -08:00
parent 5eadc67336
commit b085fc9965
4 changed files with 83 additions and 0 deletions

View file

@ -4795,6 +4795,14 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
(cmp (minmax @0 INTEGER_CST@1) INTEGER_CST@2)
(comb (cmp @0 @2) (cmp @1 @2))))
/* MAX (A, B) == 0 -> (A|B) == 0 iff unsigned.
MAX (A, B) != 0 -> (A|B) != 0 iff unsigned. */
(for cmp (eq ne)
(simplify
(cmp (max @0 @1) integer_zerop@2)
(if (TYPE_UNSIGNED (TREE_TYPE (@0)))
(cmp (bit_ior @0 @1) @2))))
/* Undo fancy ways of writing max/min or other ?: expressions, like
a - ((a - b) & -(a < b)) and a - (a - b) * (a < b) into (a < b) ? b : a.
People normally use ?: and that is what we actually try to optimize. */

View file

@ -0,0 +1,36 @@
/* { dg-do compile } */
/* { dg-options "-O2 -fdump-tree-optimized" } */
/* PR tree-optimization/115275 */
template<class T>
inline const T &
min(const T &a, const T &b)
{
return a < b ? a : b;
}
template<class T>
inline const T &
max(const T &a, const T &b)
{
return a < b ? b : a;
}
unsigned short m, a, b;
void removeme ();
void fn(unsigned short f) {
if(
(min(max(f, a) ? f : 0U, 84991U))
-
(min(max(f, b) ? f : 0U, 84991U))
)
{
removeme();
}
}
/* removeme call should be optimized out. */
/* { dg-final { scan-tree-dump-not "removeme " "optimized" } } */

View file

@ -0,0 +1,20 @@
/* { dg-do compile } */
/* { dg-options "-O1 -fdump-tree-optimized-raw" } */
/* PR tree-optimization/115275 */
unsigned maxne(unsigned a, unsigned b)
{
unsigned t = a > b ? a : b;
return t != 0;
}
unsigned maxeq(unsigned a, unsigned b)
{
unsigned t = a > b ? a : b;
return t == 0;
}
/* `max(a,b) == 0` should be optimized to `(a|b) == 0` for unsigned types. */
/* { dg-final { scan-tree-dump-not "max_expr, " "optimized" } } */
/* { dg-final { scan-tree-dump-times "bit_ior_expr, " 2 "optimized" } } */
/* { dg-final { scan-tree-dump-times "eq_expr, " 1 "optimized" } } */
/* { dg-final { scan-tree-dump-times "ne_expr, " 1 "optimized" } } */

View file

@ -0,0 +1,19 @@
/* { dg-do compile } */
/* { dg-options "-O1 -fdump-tree-optimized-raw" } */
/* PR tree-optimization/115275 */
signed maxne(signed a, signed b)
{
unsigned t = a > b ? a : b;
return t != 0;
}
signed maxeq(signed a, signed b)
{
unsigned t = a > b ? a : b;
return t == 0;
}
/* For signed types, `max(a,b) == 0` should not optimized to `(a|b) == 0`. */
/* { dg-final { scan-tree-dump-times "max_expr, " 2 "optimized" } } */
/* { dg-final { scan-tree-dump-not "bit_ior_expr, " "optimized" } } */
/* { dg-final { scan-tree-dump-times "eq_expr, " 1 "optimized" } } */
/* { dg-final { scan-tree-dump-times "ne_expr, " 1 "optimized" } } */