After if-conversion, a predicated pack index may wrap in its effective
arithmetic type while still matching the mask ? index + 1 : index shape.
Require a compile-time no-wrap proof before classifying the PHI as
vect_predicated_index_def so compress-style vectorization is not enabled
when the index can wrap.

gcc/ChangeLog:

        * tree-vect-loop.cc (vect_analyze_predicated_index_phi,
        vect_predicated_index_plus_one, vect_predicated_index_compress_legal_p):
        Require no-wrap legality before classifying predicated-index PHIs.

gcc/testsuite/ChangeLog:

        * gcc.dg/vect/vect-predicated-index-3.c: New test.
        * gcc.dg/vect/vect-predicated-index-4.c: New test.
---
 .../gcc.dg/vect/vect-predicated-index-3.c     |  20 +++
 .../gcc.dg/vect/vect-predicated-index-4.c     |  20 +++
 gcc/tree-vect-loop.cc                         | 115 +++++++++++++++++-
 3 files changed, 151 insertions(+), 4 deletions(-)
 create mode 100644 gcc/testsuite/gcc.dg/vect/vect-predicated-index-3.c
 create mode 100644 gcc/testsuite/gcc.dg/vect/vect-predicated-index-4.c

diff --git a/gcc/testsuite/gcc.dg/vect/vect-predicated-index-3.c 
b/gcc/testsuite/gcc.dg/vect/vect-predicated-index-3.c
new file mode 100644
index 00000000000..bb66084adfb
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/vect/vect-predicated-index-3.c
@@ -0,0 +1,20 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target vect_int } */
+/* { dg-additional-options "-mavx512bw" { target { i?86-*-* x86_64-*-* } } } */
+
+/* Bounded unsigned char pack index: trip count provably small enough that
+   the counter cannot wrap.  */
+
+void
+foo (unsigned char *restrict q, const unsigned char *restrict a)
+{
+  unsigned char j = 0;
+
+  for (int i = 0; i < 100; ++i)
+    if (a[i])
+      q[j++] = a[i];
+}
+
+/* { dg-final { scan-tree-dump "Detected predicated-index PHI." "vect" } } */
+/* { dg-final { scan-tree-dump "compress legality ok" "vect" } } */
+/* { dg-final { scan-tree-dump "unsupported: predicated-index PHI." "vect" } } 
*/
diff --git a/gcc/testsuite/gcc.dg/vect/vect-predicated-index-4.c 
b/gcc/testsuite/gcc.dg/vect/vect-predicated-index-4.c
new file mode 100644
index 00000000000..506aa987225
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/vect/vect-predicated-index-4.c
@@ -0,0 +1,20 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target vect_int } */
+/* { dg-additional-options "-mavx512bw" { target { i?86-*-* x86_64-*-* } } } */
+
+/* Unsigned char pack index with constant trip count large enough that the
+   counter would wrap; compress legality must fail and the PHI must not be
+   classified.  */
+
+void
+foo (unsigned char *restrict q, const unsigned char *restrict a)
+{
+  unsigned char j = 0;
+
+  for (int i = 0; i < 300; ++i)
+    if (a[i])
+      q[j++] = a[i];
+}
+
+/* { dg-final { scan-tree-dump-not "Detected predicated-index PHI." "vect" } } 
*/
+/* { dg-final { scan-tree-dump "compress legality unproven \\(wrap 
possible\\)" "vect" } } */
diff --git a/gcc/tree-vect-loop.cc b/gcc/tree-vect-loop.cc
index 8c2392530e7..32b66b76af2 100644
--- a/gcc/tree-vect-loop.cc
+++ b/gcc/tree-vect-loop.cc
@@ -200,6 +200,82 @@ vect_pred_phi_strip_conversion (tree *cur)
   return true;
 }
 
+/* Return the narrower of two integral types for predicated-index legality.
+   When precision matches, prefer unsigned (defined wrap semantics).  */
+
+static tree
+vect_pred_idx_narrower_int_type (tree t1, tree t2)
+{
+  if (TYPE_PRECISION (t1) < TYPE_PRECISION (t2))
+    return t1;
+  if (TYPE_PRECISION (t2) < TYPE_PRECISION (t1))
+    return t2;
+  /* Same width: prefer unsigned, where wrap is defined.  */
+  if (TYPE_UNSIGNED (t1) || TYPE_UNSIGNED (t2))
+    return TYPE_UNSIGNED (t1) ? t1 : t2;
+  return t1;
+}
+
+/* Return true if a predicated pack index with effective type EFF_TYPE and
+   constant start value START cannot wrap during LOOP execution, so
+   compress-style vectorization may be considered later.  Follow the same
+   signed/unsigned split as is_nonwrapping_integer_induction.  At most one
+   +1 occurs per iteration.  */
+
+static bool
+vect_predicated_index_compress_legal_p (class loop *loop, tree pred_phi,
+                                     tree eff_type, tree start)
+{
+  tree phi_type = TREE_TYPE (pred_phi);
+
+  /* Signed counters: overflow is undefined, so treat as safe.  */
+  if (TYPE_OVERFLOW_UNDEFINED (phi_type))
+    {
+      if (dump_enabled_p ())
+       dump_printf_loc (MSG_NOTE, vect_location,
+                        "predicated-index PHI: compress legality ok "
+                        "(signed).\n");
+      return true;
+    }
+
+  widest_int nit;
+
+  /* Need a known upper bound on how many times the loop body can run.  */
+  if (!max_stmt_executions (loop, &nit))
+    {
+      if (dump_enabled_p ())
+       dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
+                        "predicated-index PHI: compress legality unproven "
+                        "(unknown trip count).\n");
+      return false;
+    }
+
+  /* Starting value must be a compile-time constant.  */
+  if (TREE_CODE (start) != INTEGER_CST)
+    return false;
+
+  /* Highest index = start + number of possible increments.  */
+  wi::overflow_type overflow = wi::OVF_NONE;
+  widest_int max_index = wi::add (wi::to_widest (start), nit,
+                                 TYPE_SIGN (eff_type), &overflow);
+  /* Reject if that highest index cannot fit in the counter's type.  */
+  if (overflow
+      || wi::min_precision (max_index, TYPE_SIGN (eff_type))
+        > TYPE_PRECISION (eff_type))
+    {
+      if (dump_enabled_p ())
+       dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
+                        "predicated-index PHI: compress legality unproven "
+                        "(wrap possible).\n");
+      return false;
+    }
+
+  if (dump_enabled_p ())
+    dump_printf_loc (MSG_NOTE, vect_location,
+                    "predicated-index PHI: compress legality ok.\n");
+  return true;
+}
+
 /* Function vect_predicated_index_plus_one.
 
    This function checks if one of the arms of the COND_EXPR,
@@ -217,8 +293,11 @@ vect_pred_phi_strip_conversion (tree *cur)
      n_2 = mask ? n_1 : n;  */
 static bool
 vect_predicated_index_plus_one (tree &pred_phi,
-                          gassign *pred_phi_back_edge_asgn_stmt)
+                          gassign *pred_phi_back_edge_asgn_stmt,
+                          tree *eff_type)
 {
+  *eff_type = TREE_TYPE (pred_phi);
+
   /* Check that one of the arms of COND_EXPR is pred-phi (n) and the other is
      an increment value (n_1 = n + 1).  */
   tree true_val = gimple_assign_rhs2 (pred_phi_back_edge_asgn_stmt);
@@ -233,6 +312,10 @@ vect_predicated_index_plus_one (tree &pred_phi,
   if (TREE_CODE (pred_phi_inc_val) != SSA_NAME)
     return false;
 
+  /* Fold the incremented arm's type into the effective type so far.  */
+  *eff_type = vect_pred_idx_narrower_int_type (*eff_type,
+                                              TREE_TYPE (pred_phi_inc_val));
+
   /* Check if n1 = n + 1?. We may need to strip the cast instructions to reach
      the PLUS_EXPR, traversing until CUR goes out of current basic block.  */
   basic_block bb = gimple_bb (pred_phi_back_edge_asgn_stmt);
@@ -264,6 +347,16 @@ vect_predicated_index_plus_one (tree &pred_phi,
          if (!plus_base)
            return false;
 
+         /* Record types of the +1 result and of any SSA operands.  */
+         tree lhs_type = TREE_TYPE (gimple_assign_lhs (cur_asgn));
+         *eff_type = vect_pred_idx_narrower_int_type (*eff_type, lhs_type);
+         if (TREE_CODE (rhs1) == SSA_NAME)
+           *eff_type = vect_pred_idx_narrower_int_type (*eff_type,
+                                                        TREE_TYPE (rhs1));
+         if (TREE_CODE (rhs2) == SSA_NAME)
+           *eff_type = vect_pred_idx_narrower_int_type (*eff_type,
+                                                        TREE_TYPE (rhs2));
+
          /* Check if plus_base is pred_phi itself.  We may still need to strip
             some casts to reach the actual base, traversing until plus_base
             goes out of the current basic block.  */
@@ -272,6 +365,9 @@ vect_predicated_index_plus_one (tree &pred_phi,
              gimple *base_def = SSA_NAME_DEF_STMT (plus_base);
              if (gimple_bb (base_def) != bb)
                break;
+             tree plus_base_type = TREE_TYPE (plus_base);
+             *eff_type = vect_pred_idx_narrower_int_type (*eff_type,
+                                                          plus_base_type);
              if (!vect_pred_phi_strip_conversion (&plus_base))
                break;
            }
@@ -279,8 +375,13 @@ vect_predicated_index_plus_one (tree &pred_phi,
          if (plus_base == pred_phi)
            {
              if (dump_enabled_p ())
-               dump_printf_loc (MSG_NOTE, vect_location,
-                                "predicated-index PHI: update is +1.\n");
+               {
+                 dump_printf_loc (MSG_NOTE, vect_location,
+                                  "predicated-index PHI: update is +1.\n");
+                 dump_printf_loc (MSG_NOTE, vect_location,
+                                  "predicated-index PHI: effective type "
+                                  "for legality: %T.\n", *eff_type);
+               }
              return true;
            }
          /* We don't have +1 pattern.  */
@@ -523,7 +624,9 @@ vect_analyze_predicated_index_phi (class loop *loop, gphi 
*phi,
 
   /* Check that one of the arms of COND_EXPR is pred-phi (n) and the other is
      an increment value (n_1 = n + 1).  */
-  if (!vect_predicated_index_plus_one (pred_phi, pred_phi_back_edge_asgn_stmt))
+  tree eff_type;
+  if (!vect_predicated_index_plus_one (pred_phi, pred_phi_back_edge_asgn_stmt,
+                                      &eff_type))
     {
       if (dump_enabled_p ())
        dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
@@ -531,6 +634,10 @@ vect_analyze_predicated_index_phi (class loop *loop, gphi 
*phi,
       return false;
     }
 
+  if (!vect_predicated_index_compress_legal_p (loop, pred_phi, eff_type,
+                                              pre_init))
+    return false;
+
   /* The conditional-increment cycle is recognized.  Record the mask governing
      the increment on the PHI's stmt_info.  */
   tree mask = gimple_assign_rhs1 (pred_phi_back_edge_asgn_stmt);
-- 
2.53.0

Reply via email to