@@ -1,3 +1,10 @@
+2014-04-23 Cong Hou <congh@google.com>
+
+ * tree-vect-patterns.c (vect_recog_reload_rewrite_pattern):
+ New function.
+ (vect_vect_recog_func_ptrs): Add new pattern.
+ * tree-vectorizer.h (NUM_PATTERNS): Update the pattern count.
+
2014-04-23 David Malcolm <dmalcolm@redhat.com>
* is-a.h: Update comments to reflect the following changes to the
@@ -1,3 +1,7 @@
+2014-04-23 Cong Hou <congh@google.com>
+
+ * gcc.dg/vect/vect-reload-rewrite-pattern.c: New test.
+
2014-04-23 Jeff Law <law@redhat.com>
PR tree-optimization/60902
new file mode 100644
@@ -0,0 +1,61 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target vect_int } */
+
+#define N 1000
+int a[N];
+
+void test1 (int *b, int *c)
+{
+ int i;
+ for (i = 0; i < N; ++i)
+ {
+ a[i] = c[i];
+ /* Reload of c[i]. */
+ b[i] = c[i];
+ }
+}
+
+void test2 (int *b, int *c)
+{
+ int i;
+ for (i = 0; i < N; ++i)
+ {
+ c[i] = a[i] + 10;
+ /* Reload of a[i]. */
+ a[i]++;
+ /* Reload of c[i]. */
+ b[i] = c[i];
+ }
+}
+
+void test3 (int *b, int *c)
+{
+ int i;
+ for (i = 0; i < N; ++i)
+ {
+ c[i] = a[i] & 63;
+ /* Reload of a[i]. */
+ a[i]++;
+ /* Reload of c[i]. */
+ /* Rewrite to c[i]. */
+ c[i]--;
+ }
+}
+
+void test4 (_Complex int *b, _Complex int *c, _Complex int *d)
+{
+ int i;
+ for (i = 0; i < N; ++i)
+ {
+ b[i] = c[i] + d[i];
+ /* Reload of REALPART_EXPR (c[i]). */
+ /* Reload of IMAGPART_EXPR (c[i]). */
+ /* Reload of REALPART_EXPR (d[i]). */
+ /* Reload of IMAGPART_EXPR (d[i]). */
+ c[i] = c[i] - d[i];
+ }
+}
+
+/* { dg-final { scan-tree-dump-times "vectorized 1 loops" 4 "vect"} } */
+/* { dg-final { scan-tree-dump-times "vect_recog_reload_rewrite_pattern: detected" 10 "vect" } } */
+/* { dg-final { cleanup-tree-dump "vect" } } */
@@ -40,6 +40,7 @@ along with GCC; see the file COPYING3. If not see
#include "ssa-iterators.h"
#include "stringpool.h"
#include "tree-ssanames.h"
+#include "tree-ssa-sccvn.h"
#include "cfgloop.h"
#include "expr.h"
#include "optabs.h"
@@ -70,6 +71,7 @@ static gimple vect_recog_divmod_pattern (vec<gimple> *,
static gimple vect_recog_mixed_size_cond_pattern (vec<gimple> *,
tree *, tree *);
static gimple vect_recog_bool_pattern (vec<gimple> *, tree *, tree *);
+static gimple vect_recog_reload_rewrite_pattern (vec<gimple> *, tree *, tree *);
static vect_recog_func_ptr vect_vect_recog_func_ptrs[NUM_PATTERNS] = {
vect_recog_widen_mult_pattern,
vect_recog_widen_sum_pattern,
@@ -81,6 +83,7 @@ static vect_recog_func_ptr vect_vect_recog_func_ptrs[NUM_PATTERNS] = {
vect_recog_vector_vector_shift_pattern,
vect_recog_divmod_pattern,
vect_recog_mixed_size_cond_pattern,
+ vect_recog_reload_rewrite_pattern,
vect_recog_bool_pattern};
static inline void
@@ -3019,6 +3022,160 @@ vect_recog_bool_pattern (vec<gimple> *stmts, tree *type_in,
return NULL;
}
+/* Function vect_recog_reload_rewrite_pattern
+
+ Try to find the following reload pattern:
+
+ x = *p;
+ ...
+ y = *p;
+
+ or
+
+ *p = x;
+ ...
+ y = *p;
+
+ In both cases, *p is reloaded because there may exist other defs to another
+ memref that may alias with p. However, aliasing is eliminated with alias
+ checks. Then we can safely replace the last statement in above cases by
+ y = x.
+
+ Also try to detect rewrite pattern:
+
+ *p = x;
+ ...
+ *p = y;
+
+ The first write is redundant due to the fact that there is no aliasing
+ between p and other pointers. In this case we don't need to vectorize
+ the first write. Here we replace it by a dummy statement z = x.
+
+ Input:
+
+ * STMTS: Contains a stmt from which the pattern search begins.
+
+ Output:
+
+ * TYPE_IN: The type of the input arguments to the pattern.
+
+ * TYPE_OUT: The type of the output of this pattern.
+
+ * Return value: A new stmt that will be used to replace the sequence of
+ stmts that constitute the pattern. In this case it will be y = x;
+ for reload pattern, and z = x; for rewrite pattern. */
+
+static gimple
+vect_recog_reload_rewrite_pattern (vec<gimple> *stmts, tree *type_in,
+ tree *type_out)
+{
+ gimple last_stmt = (*stmts)[0];
+
+ /* We only consider this pattern for loops (alias checks are only
+ done for loops). */
+ stmt_vec_info stmt_vinfo = vinfo_for_stmt (last_stmt);
+ loop_vec_info loop_vinfo = STMT_VINFO_LOOP_VINFO (stmt_vinfo);
+ if (!loop_vinfo)
+ return NULL;
+
+ if (!is_gimple_assign (last_stmt))
+ return NULL;
+
+ /* Check if LAST_STMT is a load or write. */
+ bool load = false;
+ tree lhs_oprnd = gimple_assign_lhs (last_stmt);
+ enum tree_code code = gimple_assign_rhs_code (last_stmt);
+
+ if (TREE_CODE (lhs_oprnd) == SSA_NAME
+ && (code == ARRAY_REF
+ || code == BIT_FIELD_REF
+ || code == INDIRECT_REF
+ || code == COMPONENT_REF
+ || code == IMAGPART_EXPR
+ || code == REALPART_EXPR
+ || code == MEM_REF))
+ load = true;
+ else if (TREE_CODE (lhs_oprnd) != ARRAY_REF
+ && TREE_CODE (lhs_oprnd) != BIT_FIELD_REF
+ && TREE_CODE (lhs_oprnd) != INDIRECT_REF
+ && TREE_CODE (lhs_oprnd) != COMPONENT_REF
+ && TREE_CODE (lhs_oprnd) != IMAGPART_EXPR
+ && TREE_CODE (lhs_oprnd) != REALPART_EXPR
+ && TREE_CODE (lhs_oprnd) != MEM_REF)
+ return NULL;
+
+ tree new_val = NULL_TREE;
+
+ if (load)
+ {
+ /* If LAST_STMT is a load, check if there is any load or write to
+ the same memref before LAST_STMT. */
+
+ tree memref = gimple_assign_rhs1 (last_stmt);
+ basic_block bb = gimple_bb (last_stmt);
+
+ for (gimple_stmt_iterator si = gsi_start_bb (bb);
+ !gsi_end_p (si); gsi_next (&si))
+ {
+ gimple stmt = gsi_stmt (si);
+ if (stmt == last_stmt)
+ break;
+ if (!is_gimple_assign (stmt))
+ continue;
+
+ if (expressions_equal_p (memref, gimple_assign_rhs1 (stmt)))
+ new_val = gimple_assign_lhs (stmt);
+ else if (expressions_equal_p (memref, gimple_assign_lhs (stmt)))
+ new_val = gimple_assign_rhs1 (stmt);
+ }
+ }
+ else
+ {
+ /* If LAST_STMT is a write, check if there is any write to
+ the same memref after LAST_STMT. */
+
+ tree memref = gimple_assign_lhs (last_stmt);
+ basic_block bb = gimple_bb (last_stmt);
+
+ gimple_stmt_iterator si = gsi_start_bb (bb);
+ while (gsi_stmt (si) != last_stmt)
+ gsi_next (&si);
+ gsi_next (&si);
+
+ for (; !gsi_end_p (si); gsi_next (&si))
+ {
+ gimple stmt = gsi_stmt (si);
+ if (is_gimple_assign (stmt)
+ && expressions_equal_p (memref, gimple_assign_lhs (stmt)))
+ {
+ new_val = gimple_assign_rhs1 (last_stmt);
+ break;
+ }
+ }
+ }
+
+ if (new_val == NULL_TREE)
+ return NULL;
+
+ *type_in = *type_out = STMT_VINFO_VECTYPE (stmt_vinfo);
+
+ tree type = gimple_expr_type (last_stmt);
+ tree new_var = vect_recog_temp_ssa_var (type, NULL);
+ /* Pattern detected. Create a stmt to be used to replace the pattern. */
+ gimple pattern_stmt = gimple_build_assign_with_ops (NOP_EXPR, new_var,
+ new_val, NULL);
+
+ if (dump_enabled_p ())
+ {
+ dump_printf_loc (MSG_NOTE, vect_location,
+ "vect_recog_reload_rewrite_pattern: detected: ");
+ dump_gimple_stmt (MSG_NOTE, TDF_SLIM, pattern_stmt, 0);
+ dump_printf (MSG_NOTE, "\n");
+ dump_gimple_stmt_loc (MSG_NOTE, vect_location, TDF_SLIM, pattern_stmt, 0);
+ }
+
+ return pattern_stmt;
+}
/* Mark statements that are involved in a pattern. */
@@ -1123,7 +1123,7 @@ extern void vect_slp_transform_bb (basic_block);
Additional pattern recognition functions can (and will) be added
in the future. */
typedef gimple (* vect_recog_func_ptr) (vec<gimple> *, tree *, tree *);
-#define NUM_PATTERNS 11
+#define NUM_PATTERNS 12
void vect_pattern_recog (loop_vec_info, bb_vec_info);
/* In tree-vectorizer.c. */