diff options
Diffstat (limited to 'gcc')
-rw-r--r-- | gcc/ChangeLog | 16 | ||||
-rw-r--r-- | gcc/testsuite/ChangeLog | 7 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/tree-ssa/pr8781.C | 28 | ||||
-rw-r--r-- | gcc/testsuite/gcc.dg/tree-ssa/ssa-pre-25.c | 23 | ||||
-rw-r--r-- | gcc/tree-ssa-pre.c | 36 | ||||
-rw-r--r-- | gcc/tree-ssa-sccvn.c | 119 | ||||
-rw-r--r-- | gcc/tree-ssa-sccvn.h | 2 |
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); |