(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. */
--- /dev/null
+/* { 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" } } */
--- /dev/null
+/* { 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" } } */
--- /dev/null
+/* { 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" } } */