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
This commit is contained in:
parent
cd15ad3e60
commit
aa7069aa9f
7 changed files with 198 additions and 37 deletions
|
@ -1,3 +1,19 @@
|
|||
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
|
||||
|
|
|
@ -1,3 +1,10 @@
|
|||
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
|
||||
|
|
28
gcc/testsuite/g++.dg/tree-ssa/pr8781.C
Normal file
28
gcc/testsuite/g++.dg/tree-ssa/pr8781.C
Normal file
|
@ -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" } } */
|
23
gcc/testsuite/gcc.dg/tree-ssa/ssa-pre-25.c
Normal file
23
gcc/testsuite/gcc.dg/tree-ssa/ssa-pre-25.c
Normal file
|
@ -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" } } */
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -744,37 +744,53 @@ 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;
|
||||
|
||||
/* 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);
|
||||
|
||||
/* 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;
|
||||
}
|
||||
|
||||
/* 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) *
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
/* Transform any SSA_NAME's in a vector of vn_reference_op_s
|
||||
structures into their value numbers. This is done in-place, and
|
||||
the vector passed in is returned. */
|
||||
|
@ -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)
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Add table
Reference in a new issue