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):
* 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