]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
match: Add support for `((signed)a </>= 0) ? min/max (a, c) : b` [PR101024]
authorAndrew Pinski <andrew.pinski@oss.qualcomm.com>
Tue, 21 Oct 2025 05:45:47 +0000 (22:45 -0700)
committerAndrew Pinski <andrew.pinski@oss.qualcomm.com>
Thu, 23 Oct 2025 16:09:36 +0000 (09:09 -0700)
This is the last patch that is needed to support to remove minmax_replacement.
This fixes pr101024-1.c which is failing when minmax_replacement is removed.

This next patch will remove it.

Changes since v1:
* v2: Add new version of minmax_from_comparison that takes widest_int.
      Constraint the pattern to constant integers in some cases.
      Use mask to create the SIGNED_MAX and use GT/LE instead.
      Use wi::le_p/wi::ge_p instead of fold_build to do the comparison.

gcc/ChangeLog:

PR tree-optimization/101024
* fold-const.cc (minmax_from_comparison): New version that takes widest_int
instead of tree.
(minmax_from_comparison):  Call minmax_from_comparison for integer cst case.
* fold-const.h (minmax_from_comparison): New declaration.
* match.pd (`((signed)a </>= 0) ? min/max (a, c) : b`): New pattern.

Signed-off-by: Andrew Pinski <andrew.pinski@oss.qualcomm.com>
gcc/fold-const.cc
gcc/fold-const.h
gcc/match.pd

index e8cfee81553e89e930bf40b1a123983a297d31e1..1311c6ed7de12835ce38d71ca09527c269cc1936 100644 (file)
@@ -150,75 +150,90 @@ static tree fold_convert_const (enum tree_code, tree, tree);
 static tree fold_view_convert_expr (tree, tree);
 static tree fold_negate_expr (location_t, tree);
 
+/* This is a helper function to detect min/max for some operands of COND_EXPR.
+   The form is "(exp0 CMP cst1) ? exp0 : cst2". */
+tree_code
+minmax_from_comparison (tree_code cmp, tree exp0,
+                       const widest_int cst1,
+                       const widest_int cst2)
+{
+  if (cst1 == cst2)
+    {
+      if (cmp == LE_EXPR || cmp == LT_EXPR)
+       return MIN_EXPR;
+      if (cmp == GT_EXPR || cmp == GE_EXPR)
+       return MAX_EXPR;
+    }
+  if (cst1 == cst2 - 1)
+    {
+      /* X <= Y - 1 equals to X < Y.  */
+      if (cmp == LE_EXPR)
+       return MIN_EXPR;
+      /* X > Y - 1 equals to X >= Y.  */
+      if (cmp == GT_EXPR)
+       return MAX_EXPR;
+      /* a != MIN_RANGE<a> ? a : MIN_RANGE<a>+1 -> MAX_EXPR<MIN_RANGE<a>+1, a> */
+      if (cmp == NE_EXPR && TREE_CODE (exp0) == SSA_NAME)
+       {
+         int_range_max r;
+         get_range_query (cfun)->range_of_expr (r, exp0);
+         if (r.undefined_p ())
+           r.set_varying (TREE_TYPE (exp0));
+
+         widest_int min = widest_int::from (r.lower_bound (),
+                                            TYPE_SIGN (TREE_TYPE (exp0)));
+         if (min == cst1)
+           return MAX_EXPR;
+       }
+  }
+  if (cst1 == cst2 + 1)
+    {
+      /* X < Y + 1 equals to X <= Y.  */
+      if (cmp == LT_EXPR)
+        return MIN_EXPR;
+      /* X >= Y + 1 equals to X > Y.  */
+      if (cmp == GE_EXPR)
+       return MAX_EXPR;
+      /* a != MAX_RANGE<a> ? a : MAX_RANGE<a>-1 -> MIN_EXPR<MIN_RANGE<a>-1, a> */
+      if (cmp == NE_EXPR && TREE_CODE (exp0) == SSA_NAME)
+       {
+         int_range_max r;
+         get_range_query (cfun)->range_of_expr (r, exp0);
+         if (r.undefined_p ())
+           r.set_varying (TREE_TYPE (exp0));
+
+         widest_int max = widest_int::from (r.upper_bound (),
+                                            TYPE_SIGN (TREE_TYPE (exp0)));
+         if (max == cst1)
+           return MIN_EXPR;
+       }
+    }
+  return ERROR_MARK;
+}
+       
+       
 /* This is a helper function to detect min/max for some operands of COND_EXPR.
    The form is "(EXP0 CMP EXP1) ? EXP2 : EXP3". */
 tree_code
 minmax_from_comparison (tree_code cmp, tree exp0, tree exp1, tree exp2, tree exp3)
 {
-  enum tree_code code = ERROR_MARK;
-
   if (HONOR_NANS (exp0) || HONOR_SIGNED_ZEROS (exp0))
     return ERROR_MARK;
 
   if (!operand_equal_p (exp0, exp2))
     return ERROR_MARK;
 
-  if (TREE_CODE (exp3) == INTEGER_CST && TREE_CODE (exp1) == INTEGER_CST)
-    {
-      if (wi::to_widest (exp1) == (wi::to_widest (exp3) - 1))
-       {
-         /* X <= Y - 1 equals to X < Y.  */
-         if (cmp == LE_EXPR)
-           code = LT_EXPR;
-         /* X > Y - 1 equals to X >= Y.  */
-         if (cmp == GT_EXPR)
-           code = GE_EXPR;
-         /* a != MIN_RANGE<a> ? a : MIN_RANGE<a>+1 -> MAX_EXPR<MIN_RANGE<a>+1, a> */
-         if (cmp == NE_EXPR && TREE_CODE (exp0) == SSA_NAME)
-           {
-             int_range_max r;
-             get_range_query (cfun)->range_of_expr (r, exp0);
-             if (r.undefined_p ())
-               r.set_varying (TREE_TYPE (exp0));
-
-             widest_int min = widest_int::from (r.lower_bound (),
-                                                TYPE_SIGN (TREE_TYPE (exp0)));
-             if (min == wi::to_widest (exp1))
-               code = MAX_EXPR;
-           }
-       }
-      if (wi::to_widest (exp1) == (wi::to_widest (exp3) + 1))
-       {
-         /* X < Y + 1 equals to X <= Y.  */
-         if (cmp == LT_EXPR)
-           code = LE_EXPR;
-         /* X >= Y + 1 equals to X > Y.  */
-         if (cmp == GE_EXPR)
-         code = GT_EXPR;
-         /* a != MAX_RANGE<a> ? a : MAX_RANGE<a>-1 -> MIN_EXPR<MIN_RANGE<a>-1, a> */
-         if (cmp == NE_EXPR && TREE_CODE (exp0) == SSA_NAME)
-           {
-             int_range_max r;
-             get_range_query (cfun)->range_of_expr (r, exp0);
-             if (r.undefined_p ())
-               r.set_varying (TREE_TYPE (exp0));
-
-             widest_int max = widest_int::from (r.upper_bound (),
-                                                TYPE_SIGN (TREE_TYPE (exp0)));
-             if (max == wi::to_widest (exp1))
-               code = MIN_EXPR;
-           }
-       }
-    }
-  if (code != ERROR_MARK
-      || operand_equal_p (exp1, exp3))
+  if (operand_equal_p (exp1, exp3))
     {
       if (cmp == LT_EXPR || cmp == LE_EXPR)
-       code = MIN_EXPR;
+       return MIN_EXPR;
       if (cmp == GT_EXPR || cmp == GE_EXPR)
-       code = MAX_EXPR;
+       return MAX_EXPR;
     }
-  return code;
+  if (TREE_CODE (exp3) == INTEGER_CST
+      && TREE_CODE (exp1) == INTEGER_CST)
+    return minmax_from_comparison (cmp, exp0, wi::to_widest (exp1), wi::to_widest (exp3));
+  return ERROR_MARK;
 }
 
 /* Return EXPR_LOCATION of T if it is not UNKNOWN_LOCATION.
index e95cf48c17665fa3136a902c36de9586140293a5..00975dcddd61510c3c87710b962e89f48da76e39 100644 (file)
@@ -254,6 +254,9 @@ extern tree fold_build_pointer_plus_hwi_loc (location_t loc, tree ptr, HOST_WIDE
 #define fold_build_pointer_plus_hwi(p,o) \
        fold_build_pointer_plus_hwi_loc (UNKNOWN_LOCATION, p, o)
 
+extern tree_code minmax_from_comparison (tree_code, tree,
+                                        const widest_int,
+                                        const widest_int);
 extern tree_code minmax_from_comparison (tree_code, tree, tree,
                                         tree, tree);
 
index f7e074eaa564d955babe7ba0989bfd63efa27427..d00b925416ae38184f7ca315cbe02328e3e377e0 100644 (file)
@@ -6932,6 +6932,35 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
           && integer_nonzerop (fold_build2 (GE_EXPR, boolean_type_node, @3, @4)))
       (max @2 @4))))))
 
+/* Optimize (((signed)a CMP 0) ? max<a,CST2> : CST3 */
+(for cmp    (lt  ge)
+     minmax (min max)
+ (simplify
+  (cond (cmp:c (nop_convert @0) integer_zerop@1) (minmax@2 @0 INTEGER_CST@3) INTEGER_CST@4)
+   (if (!TYPE_UNSIGNED (TREE_TYPE (@1))
+        && TYPE_UNSIGNED (TREE_TYPE (@0)))
+    (with
+     {
+       tree_code code;
+       /* ((signed)a) < 0 -> a > SIGNED_MAX */
+       /* ((signed)a) >= 0 -> a <= SIGNED_MAX */
+       widest_int c1 = wi::mask<widest_int>(TYPE_PRECISION (type) - 1, 0);
+       tree_code ncmp = cmp == GE_EXPR ? LE_EXPR : GT_EXPR;
+       code = minmax_from_comparison (ncmp, @0, c1, wi::to_widest (@4));
+     }
+     (if (ncmp == LE_EXPR
+         && code == MIN_EXPR
+         && wi::le_p (wi::to_wide (@3),
+                      wi::to_wide (@4),
+                      TYPE_SIGN (type)))
+      (min @2 @4)
+      (if (ncmp == GT_EXPR
+          && code == MAX_EXPR
+          && wi::ge_p (wi::to_wide (@3),
+                       wi::to_wide (@4),
+                       TYPE_SIGN (type)))
+       (max @2 @4)))))))
+
 #if GIMPLE
 /* These patterns should be after min/max detection as simplifications
    of `(type)(zero_one ==/!= 0)` to `(type)(zero_one)`