https://gcc.gnu.org/g:c13a1b09d938e86b9e9c18588457582cb016087c

commit r17-5591-gc13a1b09d938e86b9e9c18588457582cb016087c
Author: Andrea Pinski <[email protected]>
Date:   Sat Oct 24 12:03:16 2026 -0700

    match/fold: Fix combine_comparisons for vector(signed) boolean types 
[PR128123]
    
    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]>

Diff:
---
 gcc/fold-const.cc                              | 54 +++++++++++++++++++-------
 gcc/fold-const.h                               |  4 +-
 gcc/gimple-fold.cc                             |  8 ++--
 gcc/match.pd                                   |  5 ++-
 gcc/testsuite/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(-)

diff --git a/gcc/fold-const.cc b/gcc/fold-const.cc
index 1fc4941b481a..047c7dcada4d 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 437d8ece0213..4e640de725f3 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 e0197edece65..ed84dab7f378 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 1e5f30e704ae..b91bb0b4f2d7 100644
--- a/gcc/match.pd
+++ b/gcc/match.pd
@@ -3780,14 +3780,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 000000000000..8ccf94df2746
--- /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 28bb5bf09989..0d663f4130bb 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 53256d1f7879..875f8e4af34f 100644
--- a/gcc/tree-ssa-phiopt.cc
+++ b/gcc/tree-ssa-phiopt.cc
@@ -1410,7 +1410,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;

Reply via email to