The following patch implements $subject which means condition reduction
support for x86_64 which lacks a horizontal max vector operation.

Bootstrapped and tested on x86_64-unknown-linux-gnu, applied to trunk.

Richard.

2016-06-22  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): Likewise.

        * 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.
        * gcc.dg/vect/pr65947-10.c: Likewise.
        * gcc.dg/vect/pr65947-12.c: Likewise.
        * gcc.dg/vect/pr65947-13.c: Likewise.
        * gcc.dg/vect/pr65947-14.c: Likewise.
        * gcc.dg/vect/vect-cond-2.c: Likewise.
        * gcc.dg/vect/vect-pr69848.c: Likewise.

Index: gcc/testsuite/gcc.dg/vect/pr65947-1.c
===================================================================
--- gcc/testsuite/gcc.dg/vect/pr65947-1.c       (revision 249552)
+++ 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-10.c
===================================================================
--- gcc/testsuite/gcc.dg/vect/pr65947-10.c      (revision 249552)
+++ gcc/testsuite/gcc.dg/vect/pr65947-10.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 "LOOP VECTORIZED" 2 "vect" } } */
 /* { dg-final { scan-tree-dump-not "condition expression based on integer 
induction." "vect" } } */
 
Index: gcc/testsuite/gcc.dg/vect/pr65947-12.c
===================================================================
--- gcc/testsuite/gcc.dg/vect/pr65947-12.c      (revision 249552)
+++ gcc/testsuite/gcc.dg/vect/pr65947-12.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-13.c
===================================================================
--- gcc/testsuite/gcc.dg/vect/pr65947-13.c      (revision 249552)
+++ gcc/testsuite/gcc.dg/vect/pr65947-13.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-14.c
===================================================================
--- gcc/testsuite/gcc.dg/vect/pr65947-14.c      (revision 249552)
+++ gcc/testsuite/gcc.dg/vect/pr65947-14.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-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 249552)
+++ 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 249552)
+++ 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 249552)
+++ 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 249552)
+++ 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 249552)
+++ 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 249552)
+++ 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 249552)
+++ 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/testsuite/gcc.dg/vect/vect-cond-2.c
===================================================================
--- gcc/testsuite/gcc.dg/vect/vect-cond-2.c     (revision 249552)
+++ gcc/testsuite/gcc.dg/vect/vect-cond-2.c     (working copy)
@@ -39,6 +39,4 @@ int main (void)
   return 0;
 }
 
-/* { dg-final { scan-tree-dump-times "vectorized 1 loops" 1 "vect" { xfail { ! 
vect_max_reduc } } } } */
-
-
+/* { dg-final { scan-tree-dump-times "vectorized 1 loops" 1 "vect" } } */
Index: gcc/testsuite/gcc.dg/vect/vect-pr69848.c
===================================================================
--- gcc/testsuite/gcc.dg/vect/vect-pr69848.c    (revision 249552)
+++ gcc/testsuite/gcc.dg/vect/vect-pr69848.c    (working copy)
@@ -34,4 +34,4 @@ int main (void)
 
   return 0;
 }
-/* { dg-final { scan-tree-dump "vectorized 1 loops" "vect" { xfail { ! 
vect_max_reduc } } } } */
+/* { dg-final { scan-tree-dump "vectorized 1 loops" "vect" } } */
Index: gcc/tree-vect-loop.c
===================================================================
--- gcc/tree-vect-loop.c        (revision 249552)
+++ gcc/tree-vect-loop.c        (working copy)
@@ -3772,6 +3772,18 @@ 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
        {
          int vec_size_in_bits = tree_to_uhwi (TYPE_SIZE (vectype));
@@ -3780,10 +3792,14 @@ vect_model_reduction_cost (stmt_vec_info
          int element_bitsize = tree_to_uhwi (bitsize);
          int nelements = vec_size_in_bits / element_bitsize;
 
+         if (code == COND_EXPR)
+           code = MAX_EXPR;
+
          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))
            {
@@ -4424,7 +4440,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 +4553,70 @@ 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
+          && reduc_code == ERROR_MARK)
+    {
+      /* 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 = 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);
+         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 (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);
+               }
+             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;
+           }
+       }
+      scalar_results.safe_push (val);
+    }
 
   /* 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 
@@ -4598,6 +4679,10 @@ vect_create_epilog_for_reduction (vec<tr
       int vec_size_in_bits = tree_to_uhwi (TYPE_SIZE (vectype));
       tree vec_temp;
 
+      /* COND reductions all do the final reduction with MAX_EXPR.  */
+      if (code == COND_EXPR)
+       code = MAX_EXPR;
+
       /* Regardless of whether we have a whole vector shift, if we're
          emulating the operation via tree-vect-generic, we don't want
          to use it.  Only the first round of the reduction is likely
@@ -4763,6 +4848,22 @@ vect_create_epilog_for_reduction (vec<tr
             /* Not SLP - we have one scalar to keep in SCALAR_RESULTS.  */
             scalar_results.safe_push (new_temp);
         }
+
+      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);
+
+         tree 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);
+         scalar_results[0] = tmp;
+       }
     }
   
 vect_finalize_reduction:
@@ -5639,21 +5740,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 +5760,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