diff --git a/gcc/match.pd b/gcc/match.pd index 9370764223237c8f219350cdcfb5941553aa8f74..4bec24a21b29298effaf6cd8c64c72c420af6365 100644 --- a/gcc/match.pd +++ b/gcc/match.pd @@ -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. */ diff --git a/gcc/testsuite/g++.dg/tree-ssa/pr115275.C b/gcc/testsuite/g++.dg/tree-ssa/pr115275.C new file mode 100644 index 0000000000000000000000000000000000000000..1b84766186af8160bde0dec4467f3e7d27a4160e --- /dev/null +++ b/gcc/testsuite/g++.dg/tree-ssa/pr115275.C @@ -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" } } */ diff --git a/gcc/testsuite/gcc.dg/tree-ssa/max_eqne-1.c b/gcc/testsuite/gcc.dg/tree-ssa/max_eqne-1.c new file mode 100644 index 0000000000000000000000000000000000000000..a7f5e0ec7dc92afa846998a717420be330419283 --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/max_eqne-1.c @@ -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" } } */ diff --git a/gcc/testsuite/gcc.dg/tree-ssa/max_eqne-2.c b/gcc/testsuite/gcc.dg/tree-ssa/max_eqne-2.c new file mode 100644 index 0000000000000000000000000000000000000000..50808cc7e02ad3d8cc2bdd6859f3710375a6d1f7 --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/max_eqne-2.c @@ -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" } } */