[13/n] PR85694: Try to avoid vectorising casts of invariants
authorRichard Sandiford <richard.sandiford@arm.com>
Sat, 30 Jun 2018 13:56:34 +0000 (13:56 +0000)
committerRichard Sandiford <rsandifo@gcc.gnu.org>
Sat, 30 Jun 2018 13:56:34 +0000 (13:56 +0000)
vect_recog_rotate_pattern had code to prevent operations
on invariants being vectorised unnecessarily:

  if (dt == vect_external_def
      && TREE_CODE (oprnd1) == SSA_NAME
      && is_a <loop_vec_info> (vinfo))
    {
      struct loop *loop = as_a <loop_vec_info> (vinfo)->loop;
      ext_def = loop_preheader_edge (loop);
      if (!SSA_NAME_IS_DEFAULT_DEF (oprnd1))
        {
          basic_block bb = gimple_bb (SSA_NAME_DEF_STMT (oprnd1));
          if (bb == NULL
              || !dominated_by_p (CDI_DOMINATORS, ext_def->dest, bb))
            ext_def = NULL;
        }
    }
  [..]
      if (ext_def)
        {
          basic_block new_bb
            = gsi_insert_on_edge_immediate (ext_def, def_stmt);
          gcc_assert (!new_bb);
        }

This patch reuses the same idea for casts of invariants created
during widening optimisations.

One hitch was that vect_loop_versioning asserted that the vector loop
preheader was still empty, although the cfg transformation it's doing
should be correct either way.

2018-06-30  Richard Sandiford  <richard.sandiford@arm.com>

gcc/
* tree-vect-patterns.c (vect_get_external_def_edge): New function,
split out from...
(vect_recog_rotate_pattern): ...here.
(vect_convert_input): Try to insert casts of invariants in the
preheader.
* tree-vect-loop-manip.c (vect_loop_versioning): Don't require the
preheader to be empty.

gcc/testsuite/
* gcc.dg/vect/vect-widen-mult-extern-1.c: New test.

From-SVN: r262277

gcc/ChangeLog
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.dg/vect/vect-widen-mult-extern-1.c [new file with mode: 0644]
gcc/tree-vect-loop-manip.c
gcc/tree-vect-patterns.c

index 58076bb10153e7367ac206878098bb1e59bd88df..d63e3ba99b9896cbb13ccfd37b417152f9d8aa9d 100644 (file)
@@ -1,3 +1,13 @@
+2018-06-30  Richard Sandiford  <richard.sandiford@arm.com>
+
+       * tree-vect-patterns.c (vect_get_external_def_edge): New function,
+       split out from...
+       (vect_recog_rotate_pattern): ...here.
+       (vect_convert_input): Try to insert casts of invariants in the
+       preheader.
+       * tree-vect-loop-manip.c (vect_loop_versioning): Don't require the
+       preheader to be empty.
+
 2018-06-30  Richard Sandiford  <richard.sandiford@arm.com>
 
        * tree-vect-patterns.c (append_pattern_def_seq): Take an optional
index d70a10fdb6152735033d074ffe86d7c0cdf37580..88fd3c802198a68dc9fb8a6c8ddb08068986afb9 100644 (file)
@@ -1,3 +1,7 @@
+2018-06-30  Richard Sandiford  <richard.sandiford@arm.com>
+
+       * gcc.dg/vect/vect-widen-mult-extern-1.c: New test.
+
 2018-06-30  Richard Sandiford  <richard.sandiford@arm.com>
 
        * gcc.dg/vect/vect-widen-mult-sum.c: Remove xfail.
diff --git a/gcc/testsuite/gcc.dg/vect/vect-widen-mult-extern-1.c b/gcc/testsuite/gcc.dg/vect/vect-widen-mult-extern-1.c
new file mode 100644 (file)
index 0000000..2ac3be0
--- /dev/null
@@ -0,0 +1,15 @@
+/* { dg-do compile } */
+
+#define N 1024
+
+void
+f (unsigned int *x1, unsigned int *x2, unsigned short *y, unsigned char z)
+{
+  unsigned short zu = z;
+  for (int i = 0; i < N; ++i)
+    {
+      unsigned short yi = y[i];
+      x1[i] = x1[i] > 10 ? yi * zu : x1[i] + 1;
+      x2[i] += 1;
+    }
+}
index ea648f27c25878e1edea32638fea4e91a436a5c0..01d1850276bb9d75de58452754ff03b2167e9390 100644 (file)
@@ -3038,8 +3038,9 @@ vect_loop_versioning (loop_vec_info loop_vinfo,
         while we need to move it above LOOP's preheader.  */
       e = loop_preheader_edge (loop);
       scalar_e = loop_preheader_edge (scalar_loop);
-      gcc_assert (empty_block_p (e->src)
-                 && single_pred_p (e->src));
+      /* The vector loop preheader might not be empty, since new
+        invariants could have been created while analyzing the loop.  */
+      gcc_assert (single_pred_p (e->src));
       gcc_assert (empty_block_p (scalar_e->src)
                  && single_pred_p (scalar_e->src));
       gcc_assert (single_pred_p (condition_bb));
index 2ac765e1864b13df19d7226c59ea986590757954..2b1ab7bf57580bb105d40eb5e1b8a3b58a0b382f 100644 (file)
@@ -123,6 +123,30 @@ new_pattern_def_seq (stmt_vec_info stmt_info, gimple *stmt)
   append_pattern_def_seq (stmt_info, stmt);
 }
 
+/* The caller wants to perform new operations on vect_external variable
+   VAR, so that the result of the operations would also be vect_external.
+   Return the edge on which the operations can be performed, if one exists.
+   Return null if the operations should instead be treated as part of
+   the pattern that needs them.  */
+
+static edge
+vect_get_external_def_edge (vec_info *vinfo, tree var)
+{
+  edge e = NULL;
+  if (loop_vec_info loop_vinfo = dyn_cast <loop_vec_info> (vinfo))
+    {
+      e = loop_preheader_edge (loop_vinfo->loop);
+      if (!SSA_NAME_IS_DEFAULT_DEF (var))
+       {
+         basic_block bb = gimple_bb (SSA_NAME_DEF_STMT (var));
+         if (bb == NULL
+             || !dominated_by_p (CDI_DOMINATORS, e->dest, bb))
+           e = NULL;
+       }
+    }
+  return e;
+}
+
 /* Return true if the target supports a vector version of CODE,
    where CODE is known to map to a direct optab.  ITYPE specifies
    the type of (some of) the scalar inputs and OTYPE specifies the
@@ -628,6 +652,16 @@ vect_convert_input (stmt_vec_info stmt_info, tree type,
   tree new_op = vect_recog_temp_ssa_var (type, NULL);
   gassign *new_stmt = gimple_build_assign (new_op, NOP_EXPR, unprom->op);
 
+  /* If OP is an external value, see if we can insert the new statement
+     on an incoming edge.  */
+  if (unprom->dt == vect_external_def)
+    if (edge e = vect_get_external_def_edge (stmt_info->vinfo, unprom->op))
+      {
+       basic_block new_bb = gsi_insert_on_edge_immediate (e, new_stmt);
+       gcc_assert (!new_bb);
+       return new_op;
+      }
+
   /* As a (common) last resort, add the statement to the pattern itself.  */
   append_pattern_def_seq (stmt_info, new_stmt, vectype);
   return new_op;
@@ -1821,19 +1855,8 @@ vect_recog_rotate_pattern (vec<gimple *> *stmts, tree *type_out)
   *type_out = vectype;
 
   if (dt == vect_external_def
-      && TREE_CODE (oprnd1) == SSA_NAME
-      && is_a <loop_vec_info> (vinfo))
-    {
-      struct loop *loop = as_a <loop_vec_info> (vinfo)->loop;
-      ext_def = loop_preheader_edge (loop);
-      if (!SSA_NAME_IS_DEFAULT_DEF (oprnd1))
-       {
-         basic_block bb = gimple_bb (SSA_NAME_DEF_STMT (oprnd1));
-         if (bb == NULL
-             || !dominated_by_p (CDI_DOMINATORS, ext_def->dest, bb))
-           ext_def = NULL;
-       }
-    }
+      && TREE_CODE (oprnd1) == SSA_NAME)
+    ext_def = vect_get_external_def_edge (vinfo, oprnd1);
 
   def = NULL_TREE;
   scalar_int_mode mode = SCALAR_INT_TYPE_MODE (type);