summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorjakub <jakub@138bc75d-0d04-0410-961f-82ee72b054a4>2010-11-03 15:18:50 +0000
committerjakub <jakub@138bc75d-0d04-0410-961f-82ee72b054a4>2010-11-03 15:18:50 +0000
commit91cf53d57229fde78340ed7c24e3d07cc5b524eb (patch)
tree059bf88d3d7061144003b1f54c1c90062b165a56
parenta1ce652b477210d1723fbe22abbe7842380cca3f (diff)
downloadgcc-91cf53d57229fde78340ed7c24e3d07cc5b524eb.tar.gz
PR tree-optimization/46009
* tree-ssa-phiopt.c (tree_ssa_phiopt_worker): Call cond_if_else_store_replacement if bb1 and bb2 have the same single successor. (cond_store_replacement): Use gimple_assign_single_p, don't check if rhs is SSA_NAME or invariant. Call release_defs for assign. (cond_if_else_store_replacement): New function. * gcc.dg/vect/pr46009.c: New function. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@166251 138bc75d-0d04-0410-961f-82ee72b054a4
-rw-r--r--gcc/ChangeLog11
-rw-r--r--gcc/testsuite/ChangeLog5
-rw-r--r--gcc/testsuite/gcc.dg/vect/pr46009.c74
-rw-r--r--gcc/tree-ssa-phiopt.c152
4 files changed, 227 insertions, 15 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 87db9f81269..73198e3dc7a 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,14 @@
+2010-11-03 Jakub Jelinek <jakub@redhat.com>
+
+ PR tree-optimization/46009
+ * tree-ssa-phiopt.c (tree_ssa_phiopt_worker): Call
+ cond_if_else_store_replacement if bb1 and bb2 have the same
+ single successor.
+ (cond_store_replacement): Use gimple_assign_single_p, don't
+ check if rhs is SSA_NAME or invariant. Call release_defs for
+ assign.
+ (cond_if_else_store_replacement): New function.
+
2010-11-03 Richard Guenther <rguenther@suse.de>
* opts.c (finish_options): Properly check for all WHOPR
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index 53b1b48b24d..c9ca8a361ca 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,3 +1,8 @@
+2010-11-03 Jakub Jelinek <jakub@redhat.com>
+
+ PR tree-optimization/46009
+ * gcc.dg/vect/pr46009.c: New function.
+
2010-11-03 Nicola Pero <nicola.pero@meta-innovation.com>
Implemented -fobjc-std=objc1 flag.
diff --git a/gcc/testsuite/gcc.dg/vect/pr46009.c b/gcc/testsuite/gcc.dg/vect/pr46009.c
new file mode 100644
index 00000000000..457dd37907a
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/vect/pr46009.c
@@ -0,0 +1,74 @@
+/* PR tree-optimization/46009 */
+/* { dg-require-effective-target vect_int } */
+
+#include "tree-vect.h"
+
+int a[1024] __attribute__((aligned));
+int b[1024] __attribute__((aligned));
+int c[1024] __attribute__((aligned));
+int d[1024] __attribute__((aligned));
+int e[1024] __attribute__((aligned));
+
+void __attribute__((noinline))
+foo (void)
+{
+ int i, g;
+ for (i = 0; i < 1024; i++)
+ {
+ g = a[i] + b[i] + c[i] * d[i];;
+ e[i] = g < 10 ? 1 : g;
+ }
+}
+
+void __attribute__((noinline))
+bar (void)
+{
+ int i, g;
+ for (i = 0; i < 1024; i++)
+ {
+ g = a[i] + b[i] + c[i] * d[i];;
+ if (g < 10)
+ e[i] = 1;
+ else
+ e[i] = g;
+ }
+}
+
+int
+main (void)
+{
+ int i;
+ check_vect ();
+ for (i = 0; i < 1024; i++)
+ {
+ asm volatile ("" : "+r" (i));
+ a[i] = i % 10;
+ b[i] = i % 10;
+ c[i] = 1;
+ d[i] = -1;
+ e[i] = -1;
+ }
+ foo ();
+ for (i = 0; i < 1024; i++)
+ {
+ int g;
+ asm volatile ("" : "+r" (i));
+ g = 2 * (i % 10) - 1;
+ if (e[i] != (g < 10 ? 1 : g))
+ abort ();
+ e[i] = -1;
+ }
+ bar ();
+ for (i = 0; i < 1024; i++)
+ {
+ int g;
+ asm volatile ("" : "+r" (i));
+ g = 2 * (i % 10) - 1;
+ if (e[i] != (g < 10 ? 1 : g))
+ abort ();
+ }
+ return 0;
+}
+
+/* { dg-final { scan-tree-dump-times "vectorized 1 loops" 2 "vect" } } */
+/* { dg-final { cleanup-tree-dump "vect" } } */
diff --git a/gcc/tree-ssa-phiopt.c b/gcc/tree-ssa-phiopt.c
index 8555bc1ef6f..d197bdd207a 100644
--- a/gcc/tree-ssa-phiopt.c
+++ b/gcc/tree-ssa-phiopt.c
@@ -1,6 +1,6 @@
/* Optimization of PHI nodes by converting them into straightline code.
- Copyright (C) 2004, 2005, 2006, 2007, 2008 Free Software Foundation,
- Inc.
+ Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2010
+ Free Software Foundation, Inc.
This file is part of GCC.
@@ -47,6 +47,7 @@ static bool abs_replacement (basic_block, basic_block,
edge, edge, gimple, tree, tree);
static bool cond_store_replacement (basic_block, basic_block, edge, edge,
struct pointer_set_t *);
+static bool cond_if_else_store_replacement (basic_block, basic_block, basic_block);
static struct pointer_set_t * get_non_trapping (void);
static void replace_phi_edge_with_variable (basic_block, edge, gimple, tree);
@@ -149,7 +150,7 @@ tree_ssa_phiopt (void)
bb0:
if (cond) goto bb2; else goto bb1;
bb1:
- *p = RHS
+ *p = RHS;
bb2:
with
@@ -160,10 +161,28 @@ tree_ssa_phiopt (void)
condtmp' = *p;
bb2:
condtmp = PHI <RHS, condtmp'>
- *p = condtmp
+ *p = condtmp;
This transformation can only be done under several constraints,
- documented below. */
+ documented below. It also replaces:
+
+ bb0:
+ if (cond) goto bb2; else goto bb1;
+ bb1:
+ *p = RHS1;
+ goto bb3;
+ bb2:
+ *p = RHS2;
+ bb3:
+
+ with
+
+ bb0:
+ if (cond) goto bb3; else goto bb1;
+ bb1:
+ bb3:
+ condtmp = PHI <RHS1, RHS2>
+ *p = condtmp; */
static unsigned int
tree_ssa_cs_elim (void)
@@ -248,8 +267,23 @@ tree_ssa_phiopt_worker (bool do_store_elim)
e1 = e2;
e2 = e_tmp;
}
+ else if (do_store_elim
+ && EDGE_SUCC (bb1, 0)->dest == EDGE_SUCC (bb2, 0)->dest)
+ {
+ basic_block bb3 = EDGE_SUCC (bb1, 0)->dest;
+
+ if (!single_succ_p (bb1)
+ || (EDGE_SUCC (bb1, 0)->flags & EDGE_FALLTHRU) == 0
+ || !single_succ_p (bb2)
+ || (EDGE_SUCC (bb2, 0)->flags & EDGE_FALLTHRU) == 0
+ || EDGE_COUNT (bb3->preds) != 2)
+ continue;
+ if (cond_if_else_store_replacement (bb1, bb2, bb3))
+ cfgchanged = true;
+ continue;
+ }
else
- continue;
+ continue;
e1 = EDGE_SUCC (bb1, 0);
@@ -1190,26 +1224,20 @@ cond_store_replacement (basic_block middle_bb, basic_block join_bb,
gimple newphi, new_stmt;
gimple_stmt_iterator gsi;
source_location locus;
- enum tree_code code;
/* Check if middle_bb contains of only one store. */
if (!assign
- || gimple_code (assign) != GIMPLE_ASSIGN)
+ || !gimple_assign_single_p (assign))
return false;
locus = gimple_location (assign);
lhs = gimple_assign_lhs (assign);
rhs = gimple_assign_rhs1 (assign);
if (TREE_CODE (lhs) != MEM_REF
- || TREE_CODE (TREE_OPERAND (lhs, 0)) != SSA_NAME)
- return false;
-
- /* RHS is either a single SSA_NAME or a constant of register type. */
- code = gimple_assign_rhs_code (assign);
- if (get_gimple_rhs_class (code) != GIMPLE_SINGLE_RHS
- || (code != SSA_NAME && !is_gimple_min_invariant (rhs))
+ || TREE_CODE (TREE_OPERAND (lhs, 0)) != SSA_NAME
|| !is_gimple_reg_type (TREE_TYPE (lhs)))
return false;
+
/* Prove that we can move the store down. We could also check
TREE_THIS_NOTRAP here, but in that case we also could move stores,
whose value is not available readily, which we want to avoid. */
@@ -1221,6 +1249,7 @@ cond_store_replacement (basic_block middle_bb, basic_block join_bb,
gsi = gsi_for_stmt (assign);
unlink_stmt_vdef (assign);
gsi_remove (&gsi, true);
+ release_defs (assign);
/* 2) Create a temporary where we can store the old content
of the memory touched by the store, if we need to. */
@@ -1263,6 +1292,99 @@ cond_store_replacement (basic_block middle_bb, basic_block join_bb,
return true;
}
+/* Do the main work of conditional store replacement. We already know
+ that the recognized pattern looks like so:
+
+ split:
+ if (cond) goto THEN_BB; else goto ELSE_BB (edge E1)
+ THEN_BB:
+ X = Y;
+ goto JOIN_BB;
+ ELSE_BB:
+ X = Z;
+ fallthrough (edge E0)
+ JOIN_BB:
+ some more
+
+ We check that THEN_BB and ELSE_BB contain only one store
+ that the stores have a "simple" RHS. */
+
+static bool
+cond_if_else_store_replacement (basic_block then_bb, basic_block else_bb,
+ basic_block join_bb)
+{
+ gimple then_assign = last_and_only_stmt (then_bb);
+ gimple else_assign = last_and_only_stmt (else_bb);
+ tree lhs_base, lhs, then_rhs, else_rhs;
+ source_location then_locus, else_locus;
+ gimple_stmt_iterator gsi;
+ gimple newphi, new_stmt;
+
+ /* Check if then_bb and else_bb contain only one store each. */
+ if (then_assign == NULL
+ || !gimple_assign_single_p (then_assign)
+ || else_assign == NULL
+ || !gimple_assign_single_p (else_assign))
+ return false;
+
+ lhs = gimple_assign_lhs (then_assign);
+ if (!is_gimple_reg_type (TREE_TYPE (lhs))
+ || !operand_equal_p (lhs, gimple_assign_lhs (else_assign), 0))
+ return false;
+
+ lhs_base = get_base_address (lhs);
+ if (lhs_base == NULL_TREE
+ || (!DECL_P (lhs_base) && TREE_CODE (lhs_base) != MEM_REF))
+ return false;
+
+ then_rhs = gimple_assign_rhs1 (then_assign);
+ else_rhs = gimple_assign_rhs1 (else_assign);
+ then_locus = gimple_location (then_assign);
+ else_locus = gimple_location (else_assign);
+
+ /* Now we've checked the constraints, so do the transformation:
+ 1) Remove the stores. */
+ gsi = gsi_for_stmt (then_assign);
+ unlink_stmt_vdef (then_assign);
+ gsi_remove (&gsi, true);
+ release_defs (then_assign);
+
+ gsi = gsi_for_stmt (else_assign);
+ unlink_stmt_vdef (else_assign);
+ gsi_remove (&gsi, true);
+ release_defs (else_assign);
+
+ /* 2) Create a temporary where we can store the old content
+ of the memory touched by the store, if we need to. */
+ if (!condstoretemp || TREE_TYPE (lhs) != TREE_TYPE (condstoretemp))
+ {
+ condstoretemp = create_tmp_reg (TREE_TYPE (lhs), "cstore");
+ get_var_ann (condstoretemp);
+ }
+ add_referenced_var (condstoretemp);
+
+ /* 3) Create a PHI node at the join block, with one argument
+ holding the old RHS, and the other holding the temporary
+ where we stored the old memory contents. */
+ newphi = create_phi_node (condstoretemp, join_bb);
+ add_phi_arg (newphi, then_rhs, EDGE_SUCC (then_bb, 0), then_locus);
+ add_phi_arg (newphi, else_rhs, EDGE_SUCC (else_bb, 0), else_locus);
+
+ new_stmt = gimple_build_assign (lhs, PHI_RESULT (newphi));
+
+ /* 4) Insert that PHI node. */
+ gsi = gsi_after_labels (join_bb);
+ if (gsi_end_p (gsi))
+ {
+ gsi = gsi_last_bb (join_bb);
+ gsi_insert_after (&gsi, new_stmt, GSI_NEW_STMT);
+ }
+ else
+ gsi_insert_before (&gsi, new_stmt, GSI_NEW_STMT);
+
+ return true;
+}
+
/* Always do these optimizations if we have SSA
trees to work on. */
static bool