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.
>
> 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
>