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 >
