aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authorRichard Guenther <rguenther@suse.de>2009-04-04 09:34:32 +0000
committerRichard Biener <rguenth@gcc.gnu.org>2009-04-04 09:34:32 +0000
commitaa7069aa9faf250b01c10bb7c2c442d329c0bab8 (patch)
tree9008d47a69f8bfcbddab1535dfb7516d4a030aff /gcc
parentcd15ad3e604aaa74991b72dcbf74ab61fe2fc9c4 (diff)
downloadgcc-aa7069aa9faf250b01c10bb7c2c442d329c0bab8.zip
gcc-aa7069aa9faf250b01c10bb7c2c442d329c0bab8.tar.gz
gcc-aa7069aa9faf250b01c10bb7c2c442d329c0bab8.tar.bz2
re PR c++/8781 (Pessimization of C++ (functional) code)
2009-04-04 Richard Guenther <rguenther@suse.de> PR tree-optimization/8781 PR tree-optimization/37892 * tree-ssa-sccvn.h (vn_reference_fold_indirect): Declare. * tree-ssa-sccvn.c (vn_reference_fold_indirect): New function. (valueize_refs): Call it for *& valueizations. (shared_reference_ops_from_ref): Rename to ... (valueize_shared_reference_ops_from_ref): ... this and valueize. (shared_reference_ops_from_call): Rename to ... (valueize_shared_reference_ops_from_call): ... this and valueize. (vn_reference_lookup): Update. (visit_reference_op_call): Likewise. * tree-ssa-pre.c (phi_translate_1): Fold *&. (eliminate): Value-replace the call address in call statements. * g++.dg/tree-ssa/pr8781.C: New testcase. * gcc.dg/tree-ssa/ssa-pre-25.c: Likewise. From-SVN: r145533
Diffstat (limited to 'gcc')
-rw-r--r--gcc/ChangeLog16
-rw-r--r--gcc/testsuite/ChangeLog7
-rw-r--r--gcc/testsuite/g++.dg/tree-ssa/pr8781.C28
-rw-r--r--gcc/testsuite/gcc.dg/tree-ssa/ssa-pre-25.c23
-rw-r--r--gcc/tree-ssa-pre.c36
-rw-r--r--gcc/tree-ssa-sccvn.c119
-rw-r--r--gcc/tree-ssa-sccvn.h2
7 files changed, 196 insertions, 35 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 18fb789..69fbfd5 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,5 +1,21 @@
2009-04-04 Richard Guenther <rguenther@suse.de>
+ PR tree-optimization/8781
+ PR tree-optimization/37892
+ * tree-ssa-sccvn.h (vn_reference_fold_indirect): Declare.
+ * tree-ssa-sccvn.c (vn_reference_fold_indirect): New function.
+ (valueize_refs): Call it for *& valueizations.
+ (shared_reference_ops_from_ref): Rename to ...
+ (valueize_shared_reference_ops_from_ref): ... this and valueize.
+ (shared_reference_ops_from_call): Rename to ...
+ (valueize_shared_reference_ops_from_call): ... this and valueize.
+ (vn_reference_lookup): Update.
+ (visit_reference_op_call): Likewise.
+ * tree-ssa-pre.c (phi_translate_1): Fold *&.
+ (eliminate): Value-replace the call address in call statements.
+
+2009-04-04 Richard Guenther <rguenther@suse.de>
+
PR tree-optimization/39636
* tree-ssa-forwprop.c
(forward_propagate_addr_into_variable_array_index): Check for
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index 3e322f5..8289452 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,5 +1,12 @@
2009-04-04 Richard Guenther <rguenther@suse.de>
+ PR tree-optimization/8781
+ PR tree-optimization/37892
+ * g++.dg/tree-ssa/pr8781.C: New testcase.
+ * gcc.dg/tree-ssa/ssa-pre-25.c: Likewise.
+
+2009-04-04 Richard Guenther <rguenther@suse.de>
+
PR tree-optimization/39636
* gcc.c-torture/compile/pr39636.c: New testcase.
diff --git a/gcc/testsuite/g++.dg/tree-ssa/pr8781.C b/gcc/testsuite/g++.dg/tree-ssa/pr8781.C
new file mode 100644
index 0000000..a9d279a
--- /dev/null
+++ b/gcc/testsuite/g++.dg/tree-ssa/pr8781.C
@@ -0,0 +1,28 @@
+/* { dg-do compile } */
+/* { dg-options "-O -fdump-tree-fre-details" } */
+
+int f();
+
+template<typename predicate>
+class noop_t {
+ const predicate &pred;
+public:
+ explicit noop_t(const predicate &p) : pred(p) {}
+
+ int operator()() const { return pred(); }
+};
+
+template<typename predicate>
+inline noop_t<predicate> noop(const predicate pred) {
+ return noop_t<predicate>(pred);
+}
+
+int x()
+{
+ return (noop(noop(noop(noop(noop(noop(noop(noop(noop(f)))))))))());
+}
+
+/* We should optimize this to a direct call. */
+
+/* { dg-final { scan-tree-dump "Replacing call target with f" "fre" } } */
+/* { dg-final { cleanup-tree-dump "fre" } } */
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/ssa-pre-25.c b/gcc/testsuite/gcc.dg/tree-ssa/ssa-pre-25.c
new file mode 100644
index 0000000..32b0682
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/tree-ssa/ssa-pre-25.c
@@ -0,0 +1,23 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-pre-stats" } */
+
+struct X { int i; };
+
+int foo (int x)
+{
+ struct X a;
+ struct X b;
+ struct X *p;
+ a.i = 1;
+ b.i = 2;
+ if (x)
+ p = &a;
+ else
+ p = &b;
+ return p->i;
+}
+
+/* We should eliminate the load from p for a PHI node with values 1 and 2. */
+
+/* { dg-final { scan-tree-dump "Eliminated: 1" "pre" } } */
+/* { dg-final { cleanup-tree-dump "pre" } } */
diff --git a/gcc/tree-ssa-pre.c b/gcc/tree-ssa-pre.c
index c1cbe0c..ed326e4 100644
--- a/gcc/tree-ssa-pre.c
+++ b/gcc/tree-ssa-pre.c
@@ -1563,11 +1563,12 @@ phi_translate_1 (pre_expr expr, bitmap_set_t set1, bitmap_set_t set2,
tree newvuse = vuse;
VEC (vn_reference_op_s, heap) *newoperands = NULL;
bool changed = false;
- unsigned int i;
+ unsigned int i, j;
vn_reference_op_t operand;
vn_reference_t newref;
- for (i = 0; VEC_iterate (vn_reference_op_s, operands, i, operand); i++)
+ for (i = 0, j = 0;
+ VEC_iterate (vn_reference_op_s, operands, i, operand); i++, j++)
{
pre_expr opresult;
pre_expr leader;
@@ -1642,7 +1643,13 @@ phi_translate_1 (pre_expr expr, bitmap_set_t set1, bitmap_set_t set2,
newop.op0 = op0;
newop.op1 = op1;
newop.op2 = op2;
- VEC_replace (vn_reference_op_s, newoperands, i, &newop);
+ VEC_replace (vn_reference_op_s, newoperands, j, &newop);
+ /* If it transforms from an SSA_NAME to an address, fold with
+ a preceding indirect reference. */
+ if (j > 0 && op0 && TREE_CODE (op0) == ADDR_EXPR
+ && VEC_index (vn_reference_op_s,
+ newoperands, j - 1)->opcode == INDIRECT_REF)
+ vn_reference_fold_indirect (&newoperands, &j);
}
if (i != VEC_length (vn_reference_op_s, operands))
{
@@ -4098,6 +4105,29 @@ eliminate (void)
todo = TODO_cleanup_cfg;
}
}
+ /* Visit indirect calls and turn them into direct calls if
+ possible. */
+ if (gimple_code (stmt) == GIMPLE_CALL
+ && TREE_CODE (gimple_call_fn (stmt)) == SSA_NAME)
+ {
+ tree fn = VN_INFO (gimple_call_fn (stmt))->valnum;
+ if (TREE_CODE (fn) == ADDR_EXPR
+ && TREE_CODE (TREE_OPERAND (fn, 0)) == FUNCTION_DECL)
+ {
+ if (dump_file && (dump_flags & TDF_DETAILS))
+ {
+ fprintf (dump_file, "Replacing call target with ");
+ print_generic_expr (dump_file, fn, 0);
+ fprintf (dump_file, " in ");
+ print_gimple_stmt (dump_file, stmt, 0, 0);
+ }
+
+ gimple_call_set_fn (stmt, fn);
+ update_stmt (stmt);
+ if (maybe_clean_or_replace_eh_stmt (stmt, stmt))
+ gimple_purge_dead_eh_edges (b);
+ }
+ }
}
}
diff --git a/gcc/tree-ssa-sccvn.c b/gcc/tree-ssa-sccvn.c
index 8abc306..729787b 100644
--- a/gcc/tree-ssa-sccvn.c
+++ b/gcc/tree-ssa-sccvn.c
@@ -744,36 +744,52 @@ create_reference_ops_from_call (gimple call)
return result;
}
-static VEC(vn_reference_op_s, heap) *shared_lookup_references;
-
-/* Create a vector of vn_reference_op_s structures from REF, a
- REFERENCE_CLASS_P tree. The vector is shared among all callers of
- this function. */
-
-static VEC(vn_reference_op_s, heap) *
-shared_reference_ops_from_ref (tree ref)
+/* Fold *& at position *I_P in a vn_reference_op_s vector *OPS. Updates
+ *I_P to point to the last element of the replacement. */
+void
+vn_reference_fold_indirect (VEC (vn_reference_op_s, heap) **ops,
+ unsigned int *i_p)
{
- if (!ref)
- return NULL;
- VEC_truncate (vn_reference_op_s, shared_lookup_references, 0);
- copy_reference_ops_from_ref (ref, &shared_lookup_references);
- return shared_lookup_references;
-}
+ VEC(vn_reference_op_s, heap) *mem = NULL;
+ vn_reference_op_t op;
+ unsigned int i = *i_p;
+ unsigned int j;
-/* Create a vector of vn_reference_op_s structures from CALL, a
- call statement. The vector is shared among all callers of
- this function. */
+ /* Get ops for the addressed object. */
+ op = VEC_index (vn_reference_op_s, *ops, i);
+ copy_reference_ops_from_ref (TREE_OPERAND (op->op0, 0), &mem);
-static VEC(vn_reference_op_s, heap) *
-shared_reference_ops_from_call (gimple call)
-{
- if (!call)
- return NULL;
- VEC_truncate (vn_reference_op_s, shared_lookup_references, 0);
- copy_reference_ops_from_call (call, &shared_lookup_references);
- return shared_lookup_references;
-}
+ /* Do the replacement - we should have at least one op in mem now. */
+ if (VEC_length (vn_reference_op_s, mem) == 1)
+ {
+ VEC_replace (vn_reference_op_s, *ops, i - 1,
+ VEC_index (vn_reference_op_s, mem, 0));
+ VEC_ordered_remove (vn_reference_op_s, *ops, i);
+ i--;
+ }
+ else if (VEC_length (vn_reference_op_s, mem) == 2)
+ {
+ VEC_replace (vn_reference_op_s, *ops, i - 1,
+ VEC_index (vn_reference_op_s, mem, 0));
+ VEC_replace (vn_reference_op_s, *ops, i,
+ VEC_index (vn_reference_op_s, mem, 1));
+ }
+ else if (VEC_length (vn_reference_op_s, mem) > 2)
+ {
+ VEC_replace (vn_reference_op_s, *ops, i - 1,
+ VEC_index (vn_reference_op_s, mem, 0));
+ VEC_replace (vn_reference_op_s, *ops, i,
+ VEC_index (vn_reference_op_s, mem, 1));
+ /* ??? There is no VEC_splice. */
+ for (j = 2; VEC_iterate (vn_reference_op_s, mem, j, op); j++)
+ VEC_safe_insert (vn_reference_op_s, heap, *ops, ++i, op);
+ }
+ else
+ gcc_unreachable ();
+ VEC_free (vn_reference_op_s, heap, mem);
+ *i_p = i;
+}
/* Transform any SSA_NAME's in a vector of vn_reference_op_s
structures into their value numbers. This is done in-place, and
@@ -783,7 +799,7 @@ static VEC (vn_reference_op_s, heap) *
valueize_refs (VEC (vn_reference_op_s, heap) *orig)
{
vn_reference_op_t vro;
- int i;
+ unsigned int i;
for (i = 0; VEC_iterate (vn_reference_op_s, orig, i, vro); i++)
{
@@ -795,15 +811,54 @@ valueize_refs (VEC (vn_reference_op_s, heap) *orig)
the opcode. */
if (TREE_CODE (vro->op0) != SSA_NAME && vro->opcode == SSA_NAME)
vro->opcode = TREE_CODE (vro->op0);
+ /* If it transforms from an SSA_NAME to an address, fold with
+ a preceding indirect reference. */
+ if (i > 0 && TREE_CODE (vro->op0) == ADDR_EXPR
+ && VEC_index (vn_reference_op_s,
+ orig, i - 1)->opcode == INDIRECT_REF)
+ vn_reference_fold_indirect (&orig, &i);
}
- /* TODO: Do we want to valueize op2 and op1 of
- ARRAY_REF/COMPONENT_REF for Ada */
-
+ if (vro->op1 && TREE_CODE (vro->op1) == SSA_NAME)
+ vro->op1 = SSA_VAL (vro->op1);
+ if (vro->op2 && TREE_CODE (vro->op2) == SSA_NAME)
+ vro->op2 = SSA_VAL (vro->op2);
}
return orig;
}
+static VEC(vn_reference_op_s, heap) *shared_lookup_references;
+
+/* Create a vector of vn_reference_op_s structures from REF, a
+ REFERENCE_CLASS_P tree. The vector is shared among all callers of
+ this function. */
+
+static VEC(vn_reference_op_s, heap) *
+valueize_shared_reference_ops_from_ref (tree ref)
+{
+ if (!ref)
+ return NULL;
+ VEC_truncate (vn_reference_op_s, shared_lookup_references, 0);
+ copy_reference_ops_from_ref (ref, &shared_lookup_references);
+ shared_lookup_references = valueize_refs (shared_lookup_references);
+ return shared_lookup_references;
+}
+
+/* Create a vector of vn_reference_op_s structures from CALL, a
+ call statement. The vector is shared among all callers of
+ this function. */
+
+static VEC(vn_reference_op_s, heap) *
+valueize_shared_reference_ops_from_call (gimple call)
+{
+ if (!call)
+ return NULL;
+ VEC_truncate (vn_reference_op_s, shared_lookup_references, 0);
+ copy_reference_ops_from_call (call, &shared_lookup_references);
+ shared_lookup_references = valueize_refs (shared_lookup_references);
+ return shared_lookup_references;
+}
+
/* Lookup a SCCVN reference operation VR in the current hash table.
Returns the resulting value number if it exists in the hash table,
NULL_TREE otherwise. VNRESULT will be filled in with the actual
@@ -914,7 +969,7 @@ vn_reference_lookup (tree op, tree vuse, bool maywalk,
*vnresult = NULL;
vr1.vuse = vuse ? SSA_VAL (vuse) : NULL_TREE;
- vr1.operands = valueize_refs (shared_reference_ops_from_ref (op));
+ vr1.operands = valueize_shared_reference_ops_from_ref (op);
vr1.hashcode = vn_reference_compute_hash (&vr1);
if (maywalk
@@ -1585,7 +1640,7 @@ visit_reference_op_call (tree lhs, gimple stmt)
tree vuse = gimple_vuse (stmt);
vr1.vuse = vuse ? SSA_VAL (vuse) : NULL_TREE;
- vr1.operands = valueize_refs (shared_reference_ops_from_call (stmt));
+ vr1.operands = valueize_shared_reference_ops_from_call (stmt);
vr1.hashcode = vn_reference_compute_hash (&vr1);
result = vn_reference_lookup_1 (&vr1, NULL);
if (result)
diff --git a/gcc/tree-ssa-sccvn.h b/gcc/tree-ssa-sccvn.h
index 644bc12..c8171c2 100644
--- a/gcc/tree-ssa-sccvn.h
+++ b/gcc/tree-ssa-sccvn.h
@@ -173,6 +173,8 @@ vn_nary_op_t vn_nary_op_insert_stmt (gimple, tree);
vn_nary_op_t vn_nary_op_insert_pieces (unsigned int, enum tree_code,
tree, tree, tree, tree,
tree, tree, unsigned int);
+void vn_reference_fold_indirect (VEC (vn_reference_op_s, heap) **,
+ unsigned int *);
void copy_reference_ops_from_ref (tree, VEC(vn_reference_op_s, heap) **);
void copy_reference_ops_from_call (gimple, VEC(vn_reference_op_s, heap) **);
tree get_ref_from_reference_ops (VEC(vn_reference_op_s, heap) *ops);