]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
tree-if-conv.c (is_cond_scalar_reduction): New function.
authorYuri Rumyantsev <ysrumyan@gmail.com>
Thu, 1 May 2014 07:23:06 +0000 (07:23 +0000)
committerKirill Yukhin <kyukhin@gcc.gnu.org>
Thu, 1 May 2014 07:23:06 +0000 (07:23 +0000)
gcc/
* tree-if-conv.c (is_cond_scalar_reduction): New function.
(convert_scalar_cond_reduction): Likewise.
(predicate_scalar_phi): Add recognition and transformation
of simple conditioanl reduction to be vectorizable.

gcc/testsuite/
* gcc.dg/cond-reduc-1.c: New test.
* gcc.dg/cond-reduc-2.c: Likewise.

From-SVN: r209972

gcc/ChangeLog
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.dg/vect/cond-reduc-1.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/vect/cond-reduc-2.c [new file with mode: 0644]
gcc/tree-if-conv.c

index 2d2b7878c4c7856585a68648de12a98c56773956..c34080b4879b736bfe6a6631a423a3857d791fb2 100644 (file)
@@ -1,3 +1,10 @@
+2014-05-01  Yuri Rumyantsev  <ysrumyan@gmail.com>
+
+       * tree-if-conv.c (is_cond_scalar_reduction): New function.
+       (convert_scalar_cond_reduction): Likewise.
+       (predicate_scalar_phi): Add recognition and transformation
+       of simple conditioanl reduction to be vectorizable.
+
 2014-05-01  Marek Polacek  <polacek@redhat.com>
 
        PR c/43245
index 3be6253969a7ae8d66689850df5a0d2547ad0ebc..05e92409df1dc94b65d5fbc1078cf3ea9f7bdd10 100644 (file)
@@ -1,3 +1,8 @@
+2014-05-01  Yuri Rumyantsev  <ysrumyan@gmail.com>
+
+       * gcc.dg/cond-reduc-1.c: New test.
+       * gcc.dg/cond-reduc-2.c: Likewise.
+
 2014-05-01  Marek Polacek  <polacek@redhat.com>
 
        PR c/29467
diff --git a/gcc/testsuite/gcc.dg/vect/cond-reduc-1.c b/gcc/testsuite/gcc.dg/vect/cond-reduc-1.c
new file mode 100644 (file)
index 0000000..981f6b0
--- /dev/null
@@ -0,0 +1,19 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target vect_int } */
+
+#define N 512
+int a[N];
+int foo()
+{
+  int i, res = 0;
+  for (i=0; i<N; i++)
+  {
+    if (a[i] != 0)
+      res += 1;
+  }
+  return res;
+}
+
+/* { dg-final { scan-tree-dump-times "vectorized 1 loops" 1 "vect" } } */
+/* { dg-final { cleanup-tree-dump "vect" } } */
+
diff --git a/gcc/testsuite/gcc.dg/vect/cond-reduc-2.c b/gcc/testsuite/gcc.dg/vect/cond-reduc-2.c
new file mode 100644 (file)
index 0000000..c329861
--- /dev/null
@@ -0,0 +1,19 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target vect_int } */
+
+#define N 512
+int a[N], b[N];
+void foo(int k)
+{
+  int i, res = 0;
+  for (i=0; i<N; i++)
+  {
+    if (b[i] != 0)
+      res += b[i];
+  }
+  a[k] = sum;
+}
+
+/* { dg-final { scan-tree-dump-times "vectorized 1 loops" 1 "vect" } } */
+/* { dg-final { cleanup-tree-dump "vect" } } */
+
index 21a9f05c78bfa0f62b0ca651addb7d27f715f627..5b08669f456d8cd23e5e578e864e4d3e5ff964b2 100644 (file)
@@ -1386,6 +1386,144 @@ find_phi_replacement_condition (basic_block bb, tree *cond,
   return first_edge->src;
 }
 
+/* Returns true if def-stmt for phi argument ARG is simple increment/decrement
+   which is in predicated basic block.
+   In fact, the following PHI pattern is searching:
+      loop-header:
+       reduc_1 = PHI <..., reduc_2>
+      ...
+       if (...)
+         reduc_3 = ...
+       reduc_2 = PHI <reduc_1, reduc_3>
+
+   REDUC, OP0 and OP1 contain reduction stmt and its operands.  */
+
+static bool
+is_cond_scalar_reduction (gimple phi, gimple *reduc,
+                         tree *op0, tree *op1)
+{
+  tree lhs, r_op1, r_op2;
+  tree arg_0, arg_1;
+  gimple stmt;
+  gimple header_phi = NULL;
+  enum tree_code reduction_op;
+  struct loop *loop = gimple_bb (phi)->loop_father;
+  edge latch_e = loop_latch_edge (loop);
+
+  arg_0 = PHI_ARG_DEF (phi, 0);
+  arg_1 = PHI_ARG_DEF (phi, 1);
+  if (TREE_CODE (arg_0) != SSA_NAME || TREE_CODE (arg_1) != SSA_NAME)
+    return false;
+
+  if (gimple_code (SSA_NAME_DEF_STMT (arg_0)) == GIMPLE_PHI)
+    {
+      lhs = arg_1;
+      header_phi = SSA_NAME_DEF_STMT (arg_0);
+      stmt = SSA_NAME_DEF_STMT (arg_1);
+    }
+  else if (gimple_code (SSA_NAME_DEF_STMT (arg_1)) == GIMPLE_PHI)
+    {
+      lhs = arg_0;
+      header_phi = SSA_NAME_DEF_STMT (arg_1);
+      stmt = SSA_NAME_DEF_STMT (arg_0);
+    }
+  else
+    return false;
+  if (gimple_bb (header_phi) != loop->header)
+    return false;
+
+  if (PHI_ARG_DEF_FROM_EDGE (header_phi, latch_e) != PHI_RESULT (phi))
+    return false;
+
+  if (gimple_code (stmt) != GIMPLE_ASSIGN
+      || gimple_has_volatile_ops (stmt))
+    return false;
+
+  if (!is_predicated (gimple_bb (stmt)))
+    return false;
+
+  if (!has_single_use (lhs))
+    return false;
+
+  reduction_op = gimple_assign_rhs_code (stmt);
+  if (reduction_op != PLUS_EXPR && reduction_op != MINUS_EXPR)
+    return false;
+  r_op1 = gimple_assign_rhs1 (stmt);
+  r_op2 = gimple_assign_rhs2 (stmt);
+
+  /* Make R_OP1 to hold reduction variable.  */
+  if (r_op2 == PHI_RESULT (header_phi)
+      && reduction_op == PLUS_EXPR)
+    {
+      tree tmp = r_op1;
+      r_op1 = r_op2;
+      r_op2 = tmp;
+    }
+  else if (r_op1 != PHI_RESULT (header_phi))
+    return false;
+
+  *op0 = r_op1; *op1 = r_op2;
+  *reduc = stmt;
+  return true;
+}
+
+/* Converts conditional scalar reduction into unconditional form, e.g.
+     bb_4
+       if (_5 != 0) goto bb_5 else goto bb_6
+     end_bb_4
+     bb_5
+       res_6 = res_13 + 1;
+     end_bb_5
+     bb_6
+       # res_2 = PHI <res_13(4), res_6(5)>
+     end_bb_6
+
+   will be converted into sequence
+    _ifc__1 = _5 != 0 ? 1 : 0;
+    res_2 = res_13 + _ifc__1;
+  Argument SWAP tells that arguments of conditional expression should be
+  swapped.
+  Returns rhs of resulting PHI assignment.  */
+
+static tree
+convert_scalar_cond_reduction (gimple reduc, gimple_stmt_iterator *gsi,
+                              tree cond, tree op0, tree op1, bool swap)
+{
+  gimple_stmt_iterator stmt_it;
+  gimple new_assign;
+  tree rhs;
+  tree rhs1 = gimple_assign_rhs1 (reduc);
+  tree tmp = make_temp_ssa_name (TREE_TYPE (rhs1), NULL, "_ifc_");
+  tree c;
+  tree zero = build_zero_cst (TREE_TYPE (rhs1));
+
+  if (dump_file && (dump_flags & TDF_DETAILS))
+    {
+      fprintf (dump_file, "Found cond scalar reduction.\n");
+      print_gimple_stmt (dump_file, reduc, 0, TDF_SLIM);
+    }
+
+  /* Build cond expression using COND and constant operand
+     of reduction rhs.  */
+  c = fold_build_cond_expr (TREE_TYPE (rhs1),
+                           unshare_expr (cond),
+                           swap ? zero : op1,
+                           swap ? op1 : zero);
+
+  /* Create assignment stmt and insert it at GSI.  */
+  new_assign = gimple_build_assign (tmp, c);
+  gsi_insert_before (gsi, new_assign, GSI_SAME_STMT);
+  /* Build rhs for unconditional increment/decrement.  */
+  rhs = fold_build2 (gimple_assign_rhs_code (reduc),
+                    TREE_TYPE (rhs1), op0, tmp);
+
+  /* Delete original reduction stmt.  */
+  stmt_it = gsi_for_stmt (reduc);
+  gsi_remove (&stmt_it, true);
+  release_defs (reduc);
+  return rhs;
+}
+
 /* Replace a scalar PHI node with a COND_EXPR using COND as condition.
    This routine does not handle PHI nodes with more than two
    arguments.
@@ -1428,6 +1566,9 @@ predicate_scalar_phi (gimple phi, tree cond,
   else
     {
       tree arg_0, arg_1;
+      tree op0, op1;
+      gimple reduc;
+
       /* Use condition that is not TRUTH_NOT_EXPR in conditional modify expr.  */
       if (EDGE_PRED (bb, 1)->src == true_bb)
        {
@@ -1439,10 +1580,14 @@ predicate_scalar_phi (gimple phi, tree cond,
          arg_0 = gimple_phi_arg_def (phi, 0);
          arg_1 = gimple_phi_arg_def (phi, 1);
        }
-
-      /* Build new RHS using selected condition and arguments.  */
-      rhs = fold_build_cond_expr (TREE_TYPE (res), unshare_expr (cond),
-                                 arg_0, arg_1);
+      if (is_cond_scalar_reduction (phi, &reduc, &op0, &op1))
+       /* Convert reduction stmt into vectorizable form.  */
+       rhs = convert_scalar_cond_reduction (reduc, gsi, cond, op0, op1,
+                                            true_bb != gimple_bb (reduc));
+      else
+       /* Build new RHS using selected condition and arguments.  */
+       rhs = fold_build_cond_expr (TREE_TYPE (res), unshare_expr (cond),
+                                   arg_0, arg_1);
     }
 
   new_stmt = gimple_build_assign (res, rhs);