From: Stefan Schulze Frielinghaus <[email protected]>

For clz/ctz, scalar and vectorized defined-at-zero values may differ.
Statements of the form
  B = (A != 0) ? OP : N
may still be vectorized without a zero test in case the defined-at-zero
value for vector modes equals N.

gcc/ChangeLog:

        * tree-vect-patterns.cc
        (vect_recog_popcount_clz_ctz_ffs_pattern): Fold zero test for
        clz/ctz and vector modes.

gcc/testsuite/ChangeLog:

        * gcc.target/s390/clz-ctz-1.c: Remove zero test for ctzv4si_z13.
---
 gcc/testsuite/gcc.target/s390/clz-ctz-1.c |  8 +--
 gcc/tree-vect-patterns.cc                 | 67 +++++++++++++++++++++++
 2 files changed, 69 insertions(+), 6 deletions(-)

diff --git a/gcc/testsuite/gcc.target/s390/clz-ctz-1.c 
b/gcc/testsuite/gcc.target/s390/clz-ctz-1.c
index 4d3fc148a0a..e97772143b0 100644
--- a/gcc/testsuite/gcc.target/s390/clz-ctz-1.c
+++ b/gcc/testsuite/gcc.target/s390/clz-ctz-1.c
@@ -267,15 +267,11 @@ v8hi ctzv8hi_z13 (v8hi x)
   return x;
 }
 
-/* Prior z17 we do not have a defined value for scalar zero.  Although, value
-   at zero is defined for vector modes, this isn't fixed up by vectorizer.
+/* Prior z17 we do not have a defined zero value for scalars.  Verify that
+   vectorizer still recognizes that vctz has a defined zero value.
 
 ** ctzv4si_z13:
-**     vzero   (%v[0-9]+)
-**     vceqf   (%v[0-9]+),%v24,\1
-**     vgm     (%v[0-9]+),26,26,2
 **     vctzf   %v24,%v24
-**     vsel    %v24,\3,%v24,\2
 **     br      %r14
 */
 
diff --git a/gcc/tree-vect-patterns.cc b/gcc/tree-vect-patterns.cc
index 38f65c0dafa..41d63de0b68 100644
--- a/gcc/tree-vect-patterns.cc
+++ b/gcc/tree-vect-patterns.cc
@@ -2151,6 +2151,50 @@ vect_recog_popcount_clz_ctz_ffs_pattern (vec_info *vinfo,
   if (!last_stmt)
     return NULL;
   tree_code code = gimple_assign_rhs_code (last_stmt);
+
+  /* For clz/ctz, scalar and vectorized defined-at-zero values may differ.  For
+     scalars we might end up here with LAST_STMT of the form
+       B = (A != 0) ? op_result : N
+     if there is no defined-at-zero value or the value differs from N.  Still
+     we might vectorize here without a zero test, if the defined-at-zero value
+     equals N for the vector mode.
+
+     Here we only look through the COND_EXPR.  The test whether the vectorized
+     defined-at-zero value equals N is done later on.  */
+  gassign *outer_cond_stmt = NULL;
+  tree outer_cond_ne_op0 = NULL;
+  if (code == COND_EXPR)
+    {
+      tree cond = gimple_assign_rhs1 (last_stmt);
+      tree true_val = gimple_assign_rhs2 (last_stmt);
+      tree false_val = gimple_assign_rhs3 (last_stmt);
+
+      if (TREE_CODE (false_val) != INTEGER_CST)
+       return NULL;
+
+      if (TREE_CODE (cond) != SSA_NAME)
+       return NULL;
+      gimple *cond_def = SSA_NAME_DEF_STMT (cond);
+      if (!is_gimple_assign (cond_def)
+         || gimple_assign_rhs_code (cond_def) != NE_EXPR)
+       return NULL;
+      outer_cond_ne_op0 = gimple_assign_rhs1 (cond_def);
+      tree outer_cond_ne_op1 = gimple_assign_rhs2 (cond_def);
+      if (TREE_CODE (outer_cond_ne_op0) != SSA_NAME
+         || !integer_zerop (outer_cond_ne_op1))
+       return NULL;
+
+      if (TREE_CODE (true_val) != SSA_NAME || !has_single_use (true_val))
+       return NULL;
+      gassign *inner = dyn_cast <gassign *> (SSA_NAME_DEF_STMT (true_val));
+      if (!inner)
+       return NULL;
+
+      outer_cond_stmt = last_stmt;
+      last_stmt = inner;
+      code = gimple_assign_rhs_code (last_stmt);
+    }
+
   if (!CONVERT_EXPR_CODE_P (code))
     return NULL;
 
@@ -2172,6 +2216,10 @@ vect_recog_popcount_clz_ctz_ffs_pattern (vec_info *vinfo,
     {
       int val;
     CASE_CFN_POPCOUNT:
+      /* Bail out if there is an outer statement which means we are looking for
+        clz/ctz pattern.  */
+      if (outer_cond_stmt)
+       return NULL;
       ifn = IFN_POPCOUNT;
       break;
     CASE_CFN_CLZ:
@@ -2197,6 +2245,10 @@ vect_recog_popcount_clz_ctz_ffs_pattern (vec_info *vinfo,
        return NULL;
       break;
     CASE_CFN_FFS:
+      /* Bail out if there is an outer statement which means we are looking for
+        clz/ctz pattern.  */
+      if (outer_cond_stmt)
+       return NULL;
       ifn = IFN_FFS;
       break;
     default:
@@ -2215,6 +2267,12 @@ vect_recog_popcount_clz_ctz_ffs_pattern (vec_info *vinfo,
   if (!rhs_origin)
     return NULL;
 
+  /* Verify that for
+       B = (A != 0) ? .CLZ (C) : N
+     A equals C.  */
+  if (outer_cond_stmt && outer_cond_ne_op0 != rhs_oprnd)
+    return NULL;
+
   /* Input and output of .POPCOUNT should be same-precision integer.  */
   if (TYPE_PRECISION (unprom_diff.type) != TYPE_PRECISION (lhs_type))
     return NULL;
@@ -2339,6 +2397,15 @@ vect_recog_popcount_clz_ctz_ffs_pattern (vec_info *vinfo,
           && CTZ_DEFINED_VALUE_AT_ZERO (TYPE_MODE (vec_type),
                                         val) == 2)
     arg2 = build_int_cst (integer_type_node, val);
+
+  /* For pattern clz/ctz, reaching this point we have
+       B = (A != 0) ? .CLZ (A) : N
+     Now verify that the defined-at-zero value equals N.  */
+  if (outer_cond_stmt
+      && (arg2 == NULL
+         || !tree_int_cst_equal (gimple_assign_rhs3 (outer_cond_stmt), arg2)))
+    return NULL;
+
   if (arg2)
     pattern_stmt = gimple_build_call_internal (ifn, 2, unprom_diff.op, arg2);
   else
-- 
2.55.0

Reply via email to