On Thu, Oct 23, 2025 at 5:51 AM Andrew Pinski
<[email protected]> wrote:
>
> 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.

OK.

Thanks,
Richard.

> 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):
>         * match.pd (`((signed)a </>= 0) ? min/max (a, c) : b`): New pattern.
>
> Signed-off-by: Andrew Pinski <[email protected]>
> ---
>  gcc/fold-const.cc | 123 ++++++++++++++++++++++++++--------------------
>  gcc/fold-const.h  |   3 ++
>  gcc/match.pd      |  29 +++++++++++
>  3 files changed, 101 insertions(+), 54 deletions(-)
>
> diff --git a/gcc/fold-const.cc b/gcc/fold-const.cc
> index e8cfee81553..1311c6ed7de 100644
> --- a/gcc/fold-const.cc
> +++ b/gcc/fold-const.cc
> @@ -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.
> diff --git a/gcc/fold-const.h b/gcc/fold-const.h
> index e95cf48c176..00975dcddd6 100644
> --- a/gcc/fold-const.h
> +++ b/gcc/fold-const.h
> @@ -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);
>
> diff --git a/gcc/match.pd b/gcc/match.pd
> index a4248a521cf..cbf03512b71 100644
> --- a/gcc/match.pd
> +++ b/gcc/match.pd
> @@ -6911,6 +6911,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)`
> --
> 2.43.0
>

Reply via email to