On Sun, Oct 25, 2026 at 6:55 PM Andrea Pinski <[email protected]> wrote: > > r17-4001-gbbc2517fe41 added support to combine_comparisons for LT/LE/GT/GE > but it assumed unsigned boolean types ([0,1]) which is wrong for signed > boolean types ([0,-1]). For an example, for signed boolean types, > LT is the same as GT for unsigned boolean types. So this was combining > incorrectly and getting the incorrect answer. > This fixes the problem by adding support for signed boolean. Since we > need to pass in a new argument to combine_comparisons, this updates > all of the uses of combine_comparisons which makes the patch > look bigger than it really is. > > Bootstrapped and tested on x86_64-linux-gnu with no regressions.
OK. Richard. > PR tree-optimization/128123 > > gcc/ChangeLog: > > * fold-const.cc (combine_comparisons): Take new argument, > inner_truth_type and look to see if it is signed boolean > and support that for LT/LE/GT/GE. > (fold_truth_andor_1): Update call to combine_comparisons. > * fold-const.h (combine_comparisons): Add new argument. > * gimple-fold.cc (and_comparisons_1): Update call to > combine_comparisons. > (or_comparisons_1): Likewise. > * tree-ssa-ifcombine.cc (ifcombine_ifandif): Likewise. > * tree-ssa-phiopt.cc (comparison_combine): Likewise. > * match.pd (`(CMP) OP (CMP)`): Update call to > combine_comparisons. > > gcc/testsuite/ChangeLog: > > * gcc.dg/tree-ssa/vect-cmp-cmp-1.c: New test. > > Signed-off-by: Andrea Pinski <[email protected]> > --- > gcc/fold-const.cc | 54 ++++++++++++++----- > gcc/fold-const.h | 4 +- > gcc/gimple-fold.cc | 8 +-- > gcc/match.pd | 5 +- > .../gcc.dg/tree-ssa/vect-cmp-cmp-1.c | 34 ++++++++++++ > gcc/tree-ssa-ifcombine.cc | 15 ++++-- > gcc/tree-ssa-phiopt.cc | 2 +- > 7 files changed, 95 insertions(+), 27 deletions(-) > create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/vect-cmp-cmp-1.c > > diff --git a/gcc/fold-const.cc b/gcc/fold-const.cc > index 1fc4941b481..047c7dcada4 100644 > --- a/gcc/fold-const.cc > +++ b/gcc/fold-const.cc > @@ -3010,13 +3010,21 @@ inverse_conditions_p (const_tree cond1, const_tree > cond2) > > enum tree_code > combine_comparisons (enum tree_code code, enum tree_code lcode, > - enum tree_code rcode, tree truth_type, > - bool honor_nans, tree *res) > + enum tree_code rcode, tree truth_type, > + tree inner_truth_type, > + bool honor_nans, tree *res) > { > enum comparison_code lcompcode = comparison_to_compcode (lcode); > enum comparison_code rcompcode = comparison_to_compcode (rcode); > int compcode; > *res = NULL_TREE; > + if (TREE_CODE (inner_truth_type) == VECTOR_TYPE) > + inner_truth_type = TREE_TYPE (inner_truth_type); > + bool signed_bool = false; > + if (TYPE_SIGN (inner_truth_type) == SIGNED > + && (TREE_CODE (inner_truth_type) == BOOLEAN_TYPE > + || TYPE_PRECISION (inner_truth_type) == 1)) > + signed_bool = true; > > switch (code) > { > @@ -3039,24 +3047,40 @@ combine_comparisons (enum tree_code code, enum > tree_code lcode, > compcode = ~(lcompcode ^ rcompcode); > break; > > - //`bool0 < bool1` is `!bool0 & bool1` > + //`bool0 < bool1` is `!bool0 & bool1` for unsigned > + //`bool0 < bool1` is `bool0 & !bool1` for signed > case LT_EXPR: > - compcode = ~lcompcode & rcompcode; > + if (signed_bool) > + compcode = lcompcode & ~rcompcode; > + else > + compcode = ~lcompcode & rcompcode; > break; > > - //`bool0 > bool1` is `bool0 & !bool1` > + //`bool0 > bool1` is `bool0 & !bool1` for unsigned > + //`bool0 > bool1` is `!bool0 & bool1` for signed > case GT_EXPR: > - compcode = lcompcode & ~rcompcode; > + if (signed_bool) > + compcode = ~lcompcode & rcompcode; > + else > + compcode = lcompcode & ~rcompcode; > break; > > - // `bool0 <= bool1` as !bool0 | bool1 > + // `bool0 <= bool1` as !bool0 | bool1 for unsigned > + // `bool0 <= bool1` as bool0 | !bool1 for signed > case LE_EXPR: > - compcode = ~lcompcode | rcompcode; > + if (signed_bool) > + compcode = lcompcode | ~rcompcode; > + else > + compcode = ~lcompcode | rcompcode; > break; > > - //`bool0 >= bool1` is `bool0 | !bool1` > + //`bool0 >= bool1` is `bool0 | !bool1` for unsigned > + //`bool0 >= bool1` is `bool0 | !bool1` for signed > case GE_EXPR: > - compcode = lcompcode | ~rcompcode; > + if (signed_bool) > + compcode = ~lcompcode | rcompcode; > + else > + compcode = lcompcode | ~rcompcode; > break; > > default: > @@ -3136,12 +3160,14 @@ tree > combine_comparisons (location_t loc, > enum tree_code code, enum tree_code lcode, > enum tree_code rcode, tree truth_type, > + tree inner_truth_type, > tree ll_arg, tree lr_arg) > { > bool honor_nans = HONOR_NANS (ll_arg); > tree_code rescode; > tree res; > - rescode = combine_comparisons (code, lcode, rcode, truth_type, > + rescode = combine_comparisons (code, lcode, rcode, > + truth_type, inner_truth_type, > honor_nans, &res); > if (rescode == ERROR_MARK) > return NULL_TREE; > @@ -6504,7 +6530,8 @@ fold_truth_andor_1 (location_t loc, enum tree_code > code, tree truth_type, > && operand_equal_p (lr_arg, rr_arg, 0)) > { > result = combine_comparisons (loc, code, lcode, rcode, > - truth_type, ll_arg, lr_arg); > + truth_type, TREE_TYPE (lhs), > + ll_arg, lr_arg); > if (result) > return result; > } > @@ -6513,7 +6540,8 @@ fold_truth_andor_1 (location_t loc, enum tree_code > code, tree truth_type, > { > result = combine_comparisons (loc, code, lcode, > swap_tree_comparison (rcode), > - truth_type, ll_arg, lr_arg); > + truth_type, TREE_TYPE (lhs), > + ll_arg, lr_arg); > if (result) > return result; > } > diff --git a/gcc/fold-const.h b/gcc/fold-const.h > index 437d8ece021..4e640de725f 100644 > --- a/gcc/fold-const.h > +++ b/gcc/fold-const.h > @@ -180,9 +180,9 @@ extern bool fold_cmp_float_cst_p (const wide_int &lo, > const wide_int &hi, > const wide_int &i, signop isign); > > extern tree combine_comparisons (location_t, enum tree_code, enum tree_code, > - enum tree_code, tree, tree, tree); > + enum tree_code, tree, tree, tree, tree); > extern tree_code combine_comparisons (enum tree_code, enum tree_code, > - enum tree_code, tree, bool, tree*); > + enum tree_code, tree, tree, bool, > tree*); > extern void debug_fold_checksum (const_tree); > extern bool may_negate_without_overflow_p (const_tree); > #define round_up(T,N) round_up_loc (UNKNOWN_LOCATION, T, N) > diff --git a/gcc/gimple-fold.cc b/gcc/gimple-fold.cc > index e0197edece6..ed84dab7f37 100644 > --- a/gcc/gimple-fold.cc > +++ b/gcc/gimple-fold.cc > @@ -7602,7 +7602,7 @@ and_comparisons_1 (tree type, enum tree_code code1, > tree op1a, tree op1b, > /* Result will be either NULL_TREE, or a combined comparison. */ > tree t = combine_comparisons (UNKNOWN_LOCATION, > TRUTH_ANDIF_EXPR, code1, code2, > - truth_type, op1a, op1b); > + truth_type, truth_type, op1a, op1b); > if (t) > return t; > } > @@ -7615,7 +7615,7 @@ and_comparisons_1 (tree type, enum tree_code code1, > tree op1a, tree op1b, > tree t = combine_comparisons (UNKNOWN_LOCATION, > TRUTH_ANDIF_EXPR, code1, > swap_tree_comparison (code2), > - truth_type, op1a, op1b); > + truth_type, truth_type, op1a, op1b); > if (t) > return t; > } > @@ -9574,7 +9574,7 @@ or_comparisons_1 (tree type, enum tree_code code1, tree > op1a, tree op1b, > /* Result will be either NULL_TREE, or a combined comparison. */ > tree t = combine_comparisons (UNKNOWN_LOCATION, > TRUTH_ORIF_EXPR, code1, code2, > - truth_type, op1a, op1b); > + truth_type, truth_type, op1a, op1b); > if (t) > return t; > } > @@ -9587,7 +9587,7 @@ or_comparisons_1 (tree type, enum tree_code code1, tree > op1a, tree op1b, > tree t = combine_comparisons (UNKNOWN_LOCATION, > TRUTH_ORIF_EXPR, code1, > swap_tree_comparison (code2), > - truth_type, op1a, op1b); > + truth_type, truth_type, op1a, op1b); > if (t) > return t; > } > diff --git a/gcc/match.pd b/gcc/match.pd > index 696e69fd980..02941a7dacf 100644 > --- a/gcc/match.pd > +++ b/gcc/match.pd > @@ -3771,14 +3771,15 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT) > (for cmp1 (tcc_comparison) > (for cmp2 (tcc_comparison) > (simplify > - (bitop (cmp1 @0 @1) (cmp2 @0 @1)) > + (bitop (cmp1@2 @0 @1) (cmp2 @0 @1)) > (with rescmpcode (tcc_comparison) > { > tree_code rescmpcode; > tree res; > bool honor_nans = HONOR_NANS (@0); > rescmpcode = combine_comparisons (bitop, cmp1, cmp2, > - type, honor_nans, &res); > + type, TREE_TYPE (@2), > + honor_nans, &res); > } > (if (rescmpcode == INTEGER_CST) > { res; } > diff --git a/gcc/testsuite/gcc.dg/tree-ssa/vect-cmp-cmp-1.c > b/gcc/testsuite/gcc.dg/tree-ssa/vect-cmp-cmp-1.c > new file mode 100644 > index 00000000000..8ccf94df274 > --- /dev/null > +++ b/gcc/testsuite/gcc.dg/tree-ssa/vect-cmp-cmp-1.c > @@ -0,0 +1,34 @@ > +/* { dg-do run } */ > +/* { dg-options "-O -fgimple" } */ > +/* PR tree-optimization/128123 */ > + > +typedef int v4si __attribute__((vector_size (4*sizeof(int)))); > +typedef v4si v4sib __attribute__((vector_mask)); > + > +__attribute__((noipa)) void a(v4si *x, v4si *y, v4si *res) > +{ > + v4sib m1 = *x < *y; > + v4sib m2 = *x > *y; > + *res = (v4si) (m1 < m2); > +} > + > +__attribute__((noipa)) void b(v4si *x, v4si *y, v4si *res) > +{ > + v4sib m1 = *x < *y; > + v4sib m2 = *x > *y; > + *res = (v4si) (m1 <= m2); > +} > + > +int main (void) > +{ > + v4si x = { 1, 2, 3, 4 }, y = { 2, 2, 2, 5 }; > + v4si r; > + a(&x, &y, &r); > + v4si s; > + b(&x, &y, &s); > + for (int i = 0; i < 4; i++) > + if (r[i] != -(x[i] < y[i]) || s[i] != -(x[i] <= y[i])) > + __builtin_abort(); > + return 0; > +} > + > diff --git a/gcc/tree-ssa-ifcombine.cc b/gcc/tree-ssa-ifcombine.cc > index 28bb5bf0998..0d663f4130b 100644 > --- a/gcc/tree-ssa-ifcombine.cc > +++ b/gcc/tree-ssa-ifcombine.cc > @@ -865,14 +865,16 @@ ifcombine_ifandif (basic_block inner_cond_bb, bool > inner_inv, > if (!inner_inv && !outer_inv) > res = combine_comparisons (UNKNOWN_LOCATION, TRUTH_ANDIF_EXPR, > outer_cond_code, inner_cond_code, > - boolean_type_node, larg, rarg); > + boolean_type_node, boolean_type_node, > + larg, rarg); > // If both are inverse, `!a && !b`, then handle it as `!(a || b)` > // As that !a or !b are most likely not producing a comparison code. > else if (inner_inv && outer_inv) > { > res = combine_comparisons (UNKNOWN_LOCATION, TRUTH_ORIF_EXPR, > outer_cond_code, inner_cond_code, > - boolean_type_node, larg, rarg); > + boolean_type_node, boolean_type_node, > + larg, rarg); > if (res) > res = fold_build1 (TRUTH_NOT_EXPR, TREE_TYPE (res), res); > } > @@ -891,7 +893,8 @@ ifcombine_ifandif (basic_block inner_cond_bb, bool > inner_inv, > if (inner_cond_code1 != ERROR_MARK && outer_cond_code1 != > ERROR_MARK) > res = combine_comparisons (UNKNOWN_LOCATION, TRUTH_ANDIF_EXPR, > outer_cond_code1, inner_cond_code1, > - boolean_type_node, larg, rarg); > + boolean_type_node, boolean_type_node, > + larg, rarg); > // Otherwise, we need to try `!(!a || b) > else if (inner_cond_code1 == ERROR_MARK) > { > @@ -901,7 +904,8 @@ ifcombine_ifandif (basic_block inner_cond_bb, bool > inner_inv, > if (outer_cond_code1 != ERROR_MARK) > res = combine_comparisons (UNKNOWN_LOCATION, TRUTH_ORIF_EXPR, > outer_cond_code1, inner_cond_code, > - boolean_type_node, larg, rarg); > + boolean_type_node, > boolean_type_node, > + larg, rarg); > if (res) > res = fold_build1 (TRUTH_NOT_EXPR, TREE_TYPE (res), res); > } > @@ -914,7 +918,8 @@ ifcombine_ifandif (basic_block inner_cond_bb, bool > inner_inv, > if (inner_cond_code1 != ERROR_MARK) > res = combine_comparisons (UNKNOWN_LOCATION, TRUTH_ORIF_EXPR, > outer_cond_code, inner_cond_code1, > - boolean_type_node, larg, rarg); > + boolean_type_node, > boolean_type_node, > + larg, rarg); > if (res) > res = fold_build1 (TRUTH_NOT_EXPR, TREE_TYPE (res), res); > } > diff --git a/gcc/tree-ssa-phiopt.cc b/gcc/tree-ssa-phiopt.cc > index 08b40897a60..51553484226 100644 > --- a/gcc/tree-ssa-phiopt.cc > +++ b/gcc/tree-ssa-phiopt.cc > @@ -1651,7 +1651,7 @@ comparison_combine (basic_block cond_bb, basic_block > middle_bb, > tree result; > tree_code newcmp_code; > newcmp_code = combine_comparisons (logical, outer_code, inner_code, > - boolean_type_node, > + boolean_type_node, boolean_type_node, > HONOR_NANS (larg), &result); > if (newcmp_code == ERROR_MARK) > return false; > -- > 2.43.0 >
