During my attempt to refactor reduction vectorization I ran across
the special casing of inital values for INTEGER_INDUC_COND_REDUCTION
and tried to see what it is about.  So I ended up implementing
cond reduction support for targets w/o REDUC_MAX_EXPR by simply
doing the reduction in scalar code -- while that results in an
expensive epilogue the vector loop should be reasonably fast.

I still didn't run into any exec FAILs in vect.exp with removing
the INTEGER_INDUC_COND_REDUCTION special case thus the following
patch.

Alan -- is there a testcase (maybe full bootstrap & regtest will
unconver one) that shows how this is necessary?

Bootstrap and regtest running on x86_64-unknown-linux-gnu, testing
on arm appreciated.

Thanks,
Richard.

2016-06-21  Richard Biener  <rguent...@suse.de>

        * tree-vect-loop.c (vect_model_reduction_cost): Handle
        COND_REDUCTION and INTEGER_INDUC_COND_REDUCTION without
        REDUC_MAX_EXPR support.
        (vectorizable_reduction): Likewise.
        (vect_create_epilog_for_reduction): Remove special case of
        INTEGER_INDUC_COND_REDUCTION initial value.
        (vect_create_epilog_for_reduction): Handle COND_REDUCTION
        and INTEGER_INDUC_COND_REDUCTION without REDUC_MAX_EXPR support.
        Remove compensation code for initial value special handling
        of INTEGER_INDUC_COND_REDUCTION.

        * gcc.dg/vect/pr65947-1.c: Remove xfail.
        * gcc.dg/vect/pr65947-2.c: Likewise.
        * gcc.dg/vect/pr65947-3.c: Likewise.
        * gcc.dg/vect/pr65947-4.c: Likewise.
        * gcc.dg/vect/pr65947-5.c: Likewise.
        * gcc.dg/vect/pr65947-6.c: Likewise.
        * gcc.dg/vect/pr65947-8.c: Likewise.
        * gcc.dg/vect/pr65947-9.c: Likewise.

Index: gcc/testsuite/gcc.dg/vect/pr65947-1.c
===================================================================
--- gcc/testsuite/gcc.dg/vect/pr65947-1.c       (revision 249446)
+++ gcc/testsuite/gcc.dg/vect/pr65947-1.c       (working copy)
@@ -40,5 +40,5 @@ main (void)
   return 0;
 }
 
-/* { dg-final { scan-tree-dump-times "LOOP VECTORIZED" 2 "vect" { xfail { ! 
vect_max_reduc } } } } */
-/* { dg-final { scan-tree-dump-times "condition expression based on integer 
induction." 4 "vect" { xfail { ! vect_max_reduc } } } } */
+/* { dg-final { scan-tree-dump-times "LOOP VECTORIZED" 2 "vect" } } */
+/* { dg-final { scan-tree-dump-times "condition expression based on integer 
induction." 4 "vect" } } */
Index: gcc/testsuite/gcc.dg/vect/pr65947-2.c
===================================================================
--- gcc/testsuite/gcc.dg/vect/pr65947-2.c       (revision 249446)
+++ gcc/testsuite/gcc.dg/vect/pr65947-2.c       (working copy)
@@ -41,5 +41,5 @@ main (void)
   return 0;
 }
 
-/* { dg-final { scan-tree-dump-times "LOOP VECTORIZED" 2 "vect" { xfail { ! 
vect_max_reduc } } } } */
+/* { dg-final { scan-tree-dump-times "LOOP VECTORIZED" 2 "vect" } } */
 /* { dg-final { scan-tree-dump-not "condition expression based on integer 
induction." "vect" } } */
Index: gcc/testsuite/gcc.dg/vect/pr65947-3.c
===================================================================
--- gcc/testsuite/gcc.dg/vect/pr65947-3.c       (revision 249446)
+++ gcc/testsuite/gcc.dg/vect/pr65947-3.c       (working copy)
@@ -51,5 +51,5 @@ main (void)
   return 0;
 }
 
-/* { dg-final { scan-tree-dump-times "LOOP VECTORIZED" 2 "vect" { xfail { ! 
vect_max_reduc } } } } */
+/* { dg-final { scan-tree-dump-times "LOOP VECTORIZED" 2 "vect" } } */
 /* { dg-final { scan-tree-dump-not "condition expression based on integer 
induction." "vect" } } */
Index: gcc/testsuite/gcc.dg/vect/pr65947-4.c
===================================================================
--- gcc/testsuite/gcc.dg/vect/pr65947-4.c       (revision 249446)
+++ gcc/testsuite/gcc.dg/vect/pr65947-4.c       (working copy)
@@ -40,6 +40,6 @@ main (void)
   return 0;
 }
 
-/* { dg-final { scan-tree-dump-times "LOOP VECTORIZED" 2 "vect" { xfail { ! 
vect_max_reduc } } } } */
-/* { dg-final { scan-tree-dump-times "condition expression based on integer 
induction." 4 "vect" { xfail { ! vect_max_reduc } } } } */
+/* { dg-final { scan-tree-dump-times "LOOP VECTORIZED" 2 "vect" } } */
+/* { dg-final { scan-tree-dump-times "condition expression based on integer 
induction." 4 "vect" } } */
 
Index: gcc/testsuite/gcc.dg/vect/pr65947-5.c
===================================================================
--- gcc/testsuite/gcc.dg/vect/pr65947-5.c       (revision 249446)
+++ gcc/testsuite/gcc.dg/vect/pr65947-5.c       (working copy)
@@ -41,6 +41,6 @@ main (void)
   return 0;
 }
 
-/* { dg-final { scan-tree-dump-times "LOOP VECTORIZED" 1 "vect" { xfail { ! 
vect_max_reduc } } } } */
-/* { dg-final { scan-tree-dump "loop size is greater than data size" "vect" { 
xfail { ! vect_max_reduc } } } } */
+/* { dg-final { scan-tree-dump-times "LOOP VECTORIZED" 1 "vect" } } */
+/* { dg-final { scan-tree-dump "loop size is greater than data size" "vect" } 
} */
 /* { dg-final { scan-tree-dump-not "condition expression based on integer 
induction." "vect" } } */
Index: gcc/testsuite/gcc.dg/vect/pr65947-6.c
===================================================================
--- gcc/testsuite/gcc.dg/vect/pr65947-6.c       (revision 249446)
+++ gcc/testsuite/gcc.dg/vect/pr65947-6.c       (working copy)
@@ -40,5 +40,5 @@ main (void)
   return 0;
 }
 
-/* { dg-final { scan-tree-dump-times "LOOP VECTORIZED" 2 "vect" { xfail { ! 
vect_max_reduc } } } } */
+/* { dg-final { scan-tree-dump-times "LOOP VECTORIZED" 2 "vect" } } */
 /* { dg-final { scan-tree-dump-not "condition expression based on integer 
induction." "vect" } } */
Index: gcc/testsuite/gcc.dg/vect/pr65947-8.c
===================================================================
--- gcc/testsuite/gcc.dg/vect/pr65947-8.c       (revision 249446)
+++ gcc/testsuite/gcc.dg/vect/pr65947-8.c       (working copy)
@@ -42,4 +42,4 @@ main (void)
 }
 
 /* { dg-final { scan-tree-dump-not "LOOP VECTORIZED" "vect" } } */
-/* { dg-final { scan-tree-dump "multiple types in double reduction or 
condition reduction" "vect" { xfail { ! vect_max_reduc } } } } */
+/* { dg-final { scan-tree-dump "multiple types in double reduction or 
condition reduction" "vect" } } */
Index: gcc/testsuite/gcc.dg/vect/pr65947-9.c
===================================================================
--- gcc/testsuite/gcc.dg/vect/pr65947-9.c       (revision 249446)
+++ gcc/testsuite/gcc.dg/vect/pr65947-9.c       (working copy)
@@ -46,4 +46,4 @@ main ()
 }
 
 /* { dg-final { scan-tree-dump-not "LOOP VECTORIZED" "vect" } } */
-/* { dg-final { scan-tree-dump "loop size is greater than data size" "vect" { 
xfail { ! vect_max_reduc } } } } */
+/* { dg-final { scan-tree-dump "loop size is greater than data size" "vect" } 
} */
Index: gcc/tree-vect-loop.c
===================================================================
--- gcc/tree-vect-loop.c        (revision 249446)
+++ gcc/tree-vect-loop.c        (working copy)
@@ -3772,6 +3772,31 @@ vect_model_reduction_cost (stmt_vec_info
                                              vect_epilogue);
            }
        }
+      else if (STMT_VINFO_VEC_REDUCTION_TYPE (stmt_info) == COND_REDUCTION)
+       {
+         unsigned nunits = TYPE_VECTOR_SUBPARTS (vectype);
+         /* Extraction of scalar elements.  */
+         epilogue_cost += add_stmt_cost (target_cost_data, 2 * nunits,
+                                         vec_to_scalar, stmt_info, 0,
+                                         vect_epilogue);
+         /* Scalar max reductions via COND_EXPR / MAX_EXPR.  */
+         epilogue_cost += add_stmt_cost (target_cost_data, 2 * nunits - 3,
+                                         scalar_stmt, stmt_info, 0,
+                                         vect_epilogue);
+       }
+      else if (STMT_VINFO_VEC_REDUCTION_TYPE (stmt_info)
+              == INTEGER_INDUC_COND_REDUCTION)
+       {
+         unsigned nunits = TYPE_VECTOR_SUBPARTS (vectype);
+         /* Extraction of scalar elements.  */
+         epilogue_cost += add_stmt_cost (target_cost_data, nunits,
+                                         vec_to_scalar, stmt_info, 0,
+                                         vect_epilogue);
+         /* Scalar max reductions via MAX_EXPRs.  */
+         epilogue_cost += add_stmt_cost (target_cost_data, nunits - 1,
+                                         scalar_stmt, stmt_info, 0,
+                                         vect_epilogue);
+       }
       else
        {
          int vec_size_in_bits = tree_to_uhwi (TYPE_SIZE (vectype));
@@ -3783,7 +3808,8 @@ vect_model_reduction_cost (stmt_vec_info
          optab = optab_for_tree_code (code, vectype, optab_default);
 
          /* We have a whole vector shift available.  */
-         if (VECTOR_MODE_P (mode)
+         if (optab != unknown_optab
+             && VECTOR_MODE_P (mode)
              && optab_handler (optab, mode) != CODE_FOR_nothing
              && have_whole_vector_shift (mode))
            {
@@ -4212,24 +4238,8 @@ vect_create_epilog_for_reduction (vec<tr
            }
 
          /* Set the loop-entry arg of the reduction-phi.  */
-
-         if (STMT_VINFO_VEC_REDUCTION_TYPE (stmt_info)
-             == INTEGER_INDUC_COND_REDUCTION)
-           {
-             /* Initialise the reduction phi to zero.  This prevents initial
-                values of non-zero interferring with the reduction op.  */
-             gcc_assert (ncopies == 1);
-             gcc_assert (i == 0);
-
-             tree vec_init_def_type = TREE_TYPE (vec_init_def);
-             tree zero_vec = build_zero_cst (vec_init_def_type);
-
-             add_phi_arg (as_a <gphi *> (phi), zero_vec,
-                          loop_preheader_edge (loop), UNKNOWN_LOCATION);
-           }
-         else
-           add_phi_arg (as_a <gphi *> (phi), vec_init_def,
-                        loop_preheader_edge (loop), UNKNOWN_LOCATION);
+         add_phi_arg (as_a <gphi *> (phi), vec_init_def,
+                      loop_preheader_edge (loop), UNKNOWN_LOCATION);
 
           /* Set the loop-latch arg for the reduction-phi.  */
           if (j > 0)
@@ -4424,7 +4434,8 @@ vect_create_epilog_for_reduction (vec<tr
   else
     new_phi_result = PHI_RESULT (new_phis[0]);
 
-  if (STMT_VINFO_VEC_REDUCTION_TYPE (stmt_info) == COND_REDUCTION)
+  if (STMT_VINFO_VEC_REDUCTION_TYPE (stmt_info) == COND_REDUCTION
+      && reduc_code != ERROR_MARK)
     {
       /* For condition reductions, we have a vector (NEW_PHI_RESULT) containing
         various data values where the condition matched and another vector
@@ -4536,6 +4547,88 @@ vect_create_epilog_for_reduction (vec<tr
       gsi_insert_before (&exit_gsi, epilog_stmt, GSI_SAME_STMT);
       scalar_results.safe_push (new_temp);
     }
+  else if (STMT_VINFO_VEC_REDUCTION_TYPE (stmt_info) == COND_REDUCTION
+          || (STMT_VINFO_VEC_REDUCTION_TYPE (stmt_info)
+              == INTEGER_INDUC_COND_REDUCTION))
+    {
+      /* Condition redution without supported REDUC_MAX_EXPR.  Generate
+        idx = 0;
+         idx_val = induction_index[0];
+        val = data_reduc[0];
+         for (idx = 0, val = init, i = 0; i < nelts; ++i)
+          if (induction_index[i] > idx_val)
+            val = data_reduc[i], idx_val = induction_index[i];
+        return val;  */
+
+      tree data_eltype = NULL_TREE;
+      if (!induction_index)
+       std::swap (induction_index, new_phi_result);
+      else
+       data_eltype = TREE_TYPE (TREE_TYPE (new_phi_result));
+      tree idx_eltype = TREE_TYPE (TREE_TYPE (induction_index));
+      unsigned HOST_WIDE_INT el_size = tree_to_uhwi (TYPE_SIZE (idx_eltype));
+      unsigned HOST_WIDE_INT v_size
+       = el_size * TYPE_VECTOR_SUBPARTS (TREE_TYPE (induction_index));
+      tree idx_val = NULL_TREE, val = NULL_TREE;
+      for (unsigned HOST_WIDE_INT off = 0; off < v_size; off += el_size)
+       {
+         tree old_idx_val = idx_val;
+         tree old_val = val;
+         idx_val = make_ssa_name (idx_eltype);
+         epilog_stmt = gimple_build_assign (idx_val, BIT_FIELD_REF,
+                                            build3 (BIT_FIELD_REF, idx_eltype,
+                                                    induction_index,
+                                                    bitsize_int (el_size),
+                                                    bitsize_int (off)));
+         gsi_insert_before (&exit_gsi, epilog_stmt, GSI_SAME_STMT);
+         if (new_phi_result)
+           {
+             val = make_ssa_name (data_eltype);
+             epilog_stmt = gimple_build_assign (val, BIT_FIELD_REF,
+                                                build3 (BIT_FIELD_REF,
+                                                        data_eltype,
+                                                        new_phi_result,
+                                                        bitsize_int (el_size),
+                                                        bitsize_int (off)));
+             gsi_insert_before (&exit_gsi, epilog_stmt, GSI_SAME_STMT);
+           }
+         if (off != 0)
+           {
+             tree new_idx_val = idx_val;
+             tree new_val = val;
+             if (! new_phi_result
+                 || off != v_size - el_size)
+               {
+                 new_idx_val = make_ssa_name (idx_eltype);
+                 epilog_stmt = gimple_build_assign (new_idx_val,
+                                                    MAX_EXPR, idx_val,
+                                                    old_idx_val);
+                 gsi_insert_before (&exit_gsi, epilog_stmt, GSI_SAME_STMT);
+               }
+             if (new_phi_result)
+               {
+                 new_val = make_ssa_name (data_eltype);
+                 epilog_stmt = gimple_build_assign (new_val,
+                                                    COND_EXPR,
+                                                    build2 (GT_EXPR,
+                                                            boolean_type_node,
+                                                            idx_val,
+                                                            old_idx_val),
+                                                    val, old_val);
+                 gsi_insert_before (&exit_gsi, epilog_stmt, GSI_SAME_STMT);
+               }
+             idx_val = new_idx_val;
+             val = new_val;
+           }
+       }
+      if (new_phi_result)
+       scalar_results.safe_push (val);
+      else
+       {
+         scalar_results.safe_push (idx_val);
+         std::swap (induction_index, new_phi_result);
+       }
+    }
 
   /* 2.3 Create the reduction code, using one of the three schemes described
          above. In SLP we simply need to extract all the elements from the 
@@ -4572,23 +4665,6 @@ vect_create_epilog_for_reduction (vec<tr
       new_temp = make_ssa_name (new_scalar_dest, epilog_stmt);
       gimple_assign_set_lhs (epilog_stmt, new_temp);
       gsi_insert_before (&exit_gsi, epilog_stmt, GSI_SAME_STMT);
-
-      if (STMT_VINFO_VEC_REDUCTION_TYPE (stmt_info)
-         == INTEGER_INDUC_COND_REDUCTION)
-       {
-         /* Earlier we set the initial value to be zero.  Check the result
-            and if it is zero then replace with the original initial
-            value.  */
-         tree zero = build_zero_cst (scalar_type);
-         tree zcompare = build2 (EQ_EXPR, boolean_type_node, new_temp, zero);
-
-         tmp = make_ssa_name (new_scalar_dest);
-         epilog_stmt = gimple_build_assign (tmp, COND_EXPR, zcompare,
-                                            initial_def, new_temp);
-         gsi_insert_before (&exit_gsi, epilog_stmt, GSI_SAME_STMT);
-         new_temp = tmp;
-       }
-
       scalar_results.safe_push (new_temp);
     }
   else
@@ -5639,21 +5715,6 @@ vectorizable_reduction (gimple *stmt, gi
 
              epilog_reduc_code = ERROR_MARK;
            }
-
-         /* When epilog_reduc_code is ERROR_MARK then a reduction will be
-            generated in the epilog using multiple expressions.  This does not
-            work for condition reductions.  */
-         if (epilog_reduc_code == ERROR_MARK
-             && (STMT_VINFO_VEC_REDUCTION_TYPE (stmt_info)
-                       == INTEGER_INDUC_COND_REDUCTION
-                 || STMT_VINFO_VEC_REDUCTION_TYPE (stmt_info)
-                       == CONST_COND_REDUCTION))
-           {
-             if (dump_enabled_p ())
-               dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
-                                "no reduc code for scalar code.\n");
-             return false;
-           }
        }
       else
        {
@@ -5674,17 +5735,11 @@ vectorizable_reduction (gimple *stmt, gi
       cr_index_vector_type = build_vector_type
        (cr_index_scalar_type, TYPE_VECTOR_SUBPARTS (vectype_out));
 
-      epilog_reduc_code = REDUC_MAX_EXPR;
       optab = optab_for_tree_code (REDUC_MAX_EXPR, cr_index_vector_type,
                                   optab_default);
       if (optab_handler (optab, TYPE_MODE (cr_index_vector_type))
-         == CODE_FOR_nothing)
-       {
-         if (dump_enabled_p ())
-           dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
-                            "reduc max op not supported by target.\n");
-         return false;
-       }
+         != CODE_FOR_nothing)
+       epilog_reduc_code = REDUC_MAX_EXPR;
     }
 
   if ((double_reduc

Reply via email to