I am testing the following patch to fix the regression in min/max detection introduced by comparison canonicalization like a < 267 to a <= 266. The patch allows us to identify all four min/max cases in the testcase below.
Bootstrap and regtest running on x86_64-unknown-linux-gnu. Richard. 2016-03-14 Richard Biener <rguent...@suse.de> PR tree-optimization/56365 * tree-ssa-phiopt.c (minmax_replacement): Handle alternate constants to compare against. * gcc.dg/tree-ssa/phi-opt-14.c: New testcase. Index: gcc/tree-ssa-phiopt.c =================================================================== *** gcc/tree-ssa-phiopt.c (revision 234180) --- gcc/tree-ssa-phiopt.c (working copy) *************** minmax_replacement (basic_block cond_bb, *** 1045,1051 **** gassign *new_stmt; edge true_edge, false_edge; enum tree_code cmp, minmax, ass_code; ! tree smaller, larger, arg_true, arg_false; gimple_stmt_iterator gsi, gsi_from; type = TREE_TYPE (PHI_RESULT (phi)); --- 1045,1051 ---- gassign *new_stmt; edge true_edge, false_edge; enum tree_code cmp, minmax, ass_code; ! tree smaller, alt_smaller, larger, alt_larger, arg_true, arg_false; gimple_stmt_iterator gsi, gsi_from; type = TREE_TYPE (PHI_RESULT (phi)); *************** minmax_replacement (basic_block cond_bb, *** 1059,1073 **** --- 1059,1117 ---- /* This transformation is only valid for order comparisons. Record which operand is smaller/larger if the result of the comparison is true. */ + alt_smaller = NULL_TREE; + alt_larger = NULL_TREE; if (cmp == LT_EXPR || cmp == LE_EXPR) { smaller = gimple_cond_lhs (cond); larger = gimple_cond_rhs (cond); + /* If we have smaller < CST it is equivalent to smaller <= CST-1. + Likewise smaller <= CST is equivalent to smaller < CST+1. */ + if (TREE_CODE (larger) == INTEGER_CST) + { + if (cmp == LT_EXPR) + { + bool overflow; + wide_int alt = wi::sub (larger, 1, TYPE_SIGN (TREE_TYPE (larger)), + &overflow); + if (! overflow) + alt_larger = wide_int_to_tree (TREE_TYPE (larger), alt); + } + else + { + bool overflow; + wide_int alt = wi::add (larger, 1, TYPE_SIGN (TREE_TYPE (larger)), + &overflow); + if (! overflow) + alt_larger = wide_int_to_tree (TREE_TYPE (larger), alt); + } + } } else if (cmp == GT_EXPR || cmp == GE_EXPR) { smaller = gimple_cond_rhs (cond); larger = gimple_cond_lhs (cond); + /* If we have larger > CST it is equivalent to larger >= CST+1. + Likewise larger >= CST is equivalent to larger > CST-1. */ + if (TREE_CODE (smaller) == INTEGER_CST) + { + if (cmp == GT_EXPR) + { + bool overflow; + wide_int alt = wi::add (smaller, 1, TYPE_SIGN (TREE_TYPE (smaller)), + &overflow); + if (! overflow) + alt_smaller = wide_int_to_tree (TREE_TYPE (smaller), alt); + } + else + { + bool overflow; + wide_int alt = wi::sub (smaller, 1, TYPE_SIGN (TREE_TYPE (smaller)), + &overflow); + if (! overflow) + alt_smaller = wide_int_to_tree (TREE_TYPE (smaller), alt); + } + } } else return false; *************** minmax_replacement (basic_block cond_bb, *** 1098,1105 **** if (empty_block_p (middle_bb)) { ! if (operand_equal_for_phi_arg_p (arg_true, smaller) ! && operand_equal_for_phi_arg_p (arg_false, larger)) { /* Case --- 1142,1153 ---- if (empty_block_p (middle_bb)) { ! if ((operand_equal_for_phi_arg_p (arg_true, smaller) ! || (alt_smaller ! && operand_equal_for_phi_arg_p (arg_true, alt_smaller))) ! && (operand_equal_for_phi_arg_p (arg_false, larger) ! || (alt_larger ! && operand_equal_for_phi_arg_p (arg_true, alt_larger)))) { /* Case *************** minmax_replacement (basic_block cond_bb, *** 1109,1116 **** rslt = larger; */ minmax = MIN_EXPR; } ! else if (operand_equal_for_phi_arg_p (arg_false, smaller) ! && operand_equal_for_phi_arg_p (arg_true, larger)) minmax = MAX_EXPR; else return false; --- 1157,1168 ---- rslt = larger; */ minmax = MIN_EXPR; } ! else if ((operand_equal_for_phi_arg_p (arg_false, smaller) ! || (alt_smaller ! && operand_equal_for_phi_arg_p (arg_false, alt_smaller))) ! && (operand_equal_for_phi_arg_p (arg_true, larger) ! || (alt_larger ! && operand_equal_for_phi_arg_p (arg_true, alt_larger)))) minmax = MAX_EXPR; else return false; *************** minmax_replacement (basic_block cond_bb, *** 1148,1154 **** if (!operand_equal_for_phi_arg_p (lhs, arg_true)) return false; ! if (operand_equal_for_phi_arg_p (arg_false, larger)) { /* Case --- 1200,1208 ---- if (!operand_equal_for_phi_arg_p (lhs, arg_true)) return false; ! if (operand_equal_for_phi_arg_p (arg_false, larger) ! || (alt_larger ! && operand_equal_for_phi_arg_p (arg_false, alt_larger))) { /* Case *************** minmax_replacement (basic_block cond_bb, *** 1161,1169 **** return false; minmax = MIN_EXPR; ! if (operand_equal_for_phi_arg_p (op0, smaller)) bound = op1; ! else if (operand_equal_for_phi_arg_p (op1, smaller)) bound = op0; else return false; --- 1215,1227 ---- return false; minmax = MIN_EXPR; ! if (operand_equal_for_phi_arg_p (op0, smaller) ! || (alt_smaller ! && operand_equal_for_phi_arg_p (op0, alt_smaller))) bound = op1; ! else if (operand_equal_for_phi_arg_p (op1, smaller) ! || (alt_smaller ! && operand_equal_for_phi_arg_p (op1, alt_smaller))) bound = op0; else return false; *************** minmax_replacement (basic_block cond_bb, *** 1173,1179 **** bound, larger))) return false; } ! else if (operand_equal_for_phi_arg_p (arg_false, smaller)) { /* Case --- 1231,1239 ---- bound, larger))) return false; } ! else if (operand_equal_for_phi_arg_p (arg_false, smaller) ! || (alt_smaller ! && operand_equal_for_phi_arg_p (arg_false, alt_smaller))) { /* Case *************** minmax_replacement (basic_block cond_bb, *** 1186,1194 **** return false; minmax = MAX_EXPR; ! if (operand_equal_for_phi_arg_p (op0, larger)) bound = op1; ! else if (operand_equal_for_phi_arg_p (op1, larger)) bound = op0; else return false; --- 1246,1258 ---- return false; minmax = MAX_EXPR; ! if (operand_equal_for_phi_arg_p (op0, larger) ! || (alt_larger ! && operand_equal_for_phi_arg_p (op0, alt_larger))) bound = op1; ! else if (operand_equal_for_phi_arg_p (op1, larger) ! || (alt_larger ! && operand_equal_for_phi_arg_p (op1, alt_larger))) bound = op0; else return false; *************** minmax_replacement (basic_block cond_bb, *** 1207,1213 **** if (!operand_equal_for_phi_arg_p (lhs, arg_false)) return false; ! if (operand_equal_for_phi_arg_p (arg_true, larger)) { /* Case --- 1271,1279 ---- if (!operand_equal_for_phi_arg_p (lhs, arg_false)) return false; ! if (operand_equal_for_phi_arg_p (arg_true, larger) ! || (alt_larger ! && operand_equal_for_phi_arg_p (arg_true, alt_larger))) { /* Case *************** minmax_replacement (basic_block cond_bb, *** 1220,1228 **** return false; minmax = MAX_EXPR; ! if (operand_equal_for_phi_arg_p (op0, smaller)) bound = op1; ! else if (operand_equal_for_phi_arg_p (op1, smaller)) bound = op0; else return false; --- 1286,1298 ---- return false; minmax = MAX_EXPR; ! if (operand_equal_for_phi_arg_p (op0, smaller) ! || (alt_smaller ! && operand_equal_for_phi_arg_p (op0, alt_smaller))) bound = op1; ! else if (operand_equal_for_phi_arg_p (op1, smaller) ! || (alt_smaller ! && operand_equal_for_phi_arg_p (op1, alt_smaller))) bound = op0; else return false; *************** minmax_replacement (basic_block cond_bb, *** 1232,1238 **** bound, larger))) return false; } ! else if (operand_equal_for_phi_arg_p (arg_true, smaller)) { /* Case --- 1302,1310 ---- bound, larger))) return false; } ! else if (operand_equal_for_phi_arg_p (arg_true, smaller) ! || (alt_smaller ! && operand_equal_for_phi_arg_p (arg_true, alt_smaller))) { /* Case Index: gcc/testsuite/gcc.dg/tree-ssa/phi-opt-14.c =================================================================== *** gcc/testsuite/gcc.dg/tree-ssa/phi-opt-14.c (revision 0) --- gcc/testsuite/gcc.dg/tree-ssa/phi-opt-14.c (working copy) *************** *** 0 **** --- 1,37 ---- + /* { dg-do compile } */ + /* { dg-options "-O -fdump-tree-phiopt1" } */ + + int test_01 (int a) + { + if (127 <= a) + a = 127; + else if (a <= -128) + a = -128; + return a; + } + int test_02 (int a) + { + if (127 < a) + a = 127; + else if (a <= -128) + a = -128; + return a; + } + int test_03 (int a) + { + if (127 <= a) + a = 127; + else if (a < -128) + a = -128; + return a; + } + int test_04 (int a) + { + if (127 < a) + a = 127; + else if (a < -128) + a = -128; + return a; + } + + /* { dg-final { scan-tree-dump-not "if" "phiopt1" } } */