Commit aa7069aa by Richard Guenther Committed by Richard Biener

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
parent cd15ad3e
2009-04-04 Richard Guenther <rguenther@suse.de> 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 PR tree-optimization/39636
* tree-ssa-forwprop.c * tree-ssa-forwprop.c
(forward_propagate_addr_into_variable_array_index): Check for (forward_propagate_addr_into_variable_array_index): Check for
......
2009-04-04 Richard Guenther <rguenther@suse.de> 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 PR tree-optimization/39636
* gcc.c-torture/compile/pr39636.c: New testcase. * gcc.c-torture/compile/pr39636.c: New testcase.
......
/* { 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" } } */
/* { 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, ...@@ -1563,11 +1563,12 @@ phi_translate_1 (pre_expr expr, bitmap_set_t set1, bitmap_set_t set2,
tree newvuse = vuse; tree newvuse = vuse;
VEC (vn_reference_op_s, heap) *newoperands = NULL; VEC (vn_reference_op_s, heap) *newoperands = NULL;
bool changed = false; bool changed = false;
unsigned int i; unsigned int i, j;
vn_reference_op_t operand; vn_reference_op_t operand;
vn_reference_t newref; 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 opresult;
pre_expr leader; pre_expr leader;
...@@ -1642,7 +1643,13 @@ phi_translate_1 (pre_expr expr, bitmap_set_t set1, bitmap_set_t set2, ...@@ -1642,7 +1643,13 @@ phi_translate_1 (pre_expr expr, bitmap_set_t set1, bitmap_set_t set2,
newop.op0 = op0; newop.op0 = op0;
newop.op1 = op1; newop.op1 = op1;
newop.op2 = op2; 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)) if (i != VEC_length (vn_reference_op_s, operands))
{ {
...@@ -4098,6 +4105,29 @@ eliminate (void) ...@@ -4098,6 +4105,29 @@ eliminate (void)
todo = TODO_cleanup_cfg; 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,36 +744,52 @@ create_reference_ops_from_call (gimple call) ...@@ -744,36 +744,52 @@ create_reference_ops_from_call (gimple call)
return result; return result;
} }
static VEC(vn_reference_op_s, heap) *shared_lookup_references; /* 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. */
/* Create a vector of vn_reference_op_s structures from REF, a void
REFERENCE_CLASS_P tree. The vector is shared among all callers of vn_reference_fold_indirect (VEC (vn_reference_op_s, heap) **ops,
this function. */ unsigned int *i_p)
static VEC(vn_reference_op_s, heap) *
shared_reference_ops_from_ref (tree ref)
{ {
if (!ref) VEC(vn_reference_op_s, heap) *mem = NULL;
return NULL; vn_reference_op_t op;
VEC_truncate (vn_reference_op_s, shared_lookup_references, 0); unsigned int i = *i_p;
copy_reference_ops_from_ref (ref, &shared_lookup_references); unsigned int j;
return shared_lookup_references;
}
/* Create a vector of vn_reference_op_s structures from CALL, a /* Get ops for the addressed object. */
call statement. The vector is shared among all callers of op = VEC_index (vn_reference_op_s, *ops, i);
this function. */ copy_reference_ops_from_ref (TREE_OPERAND (op->op0, 0), &mem);
static VEC(vn_reference_op_s, heap) * /* Do the replacement - we should have at least one op in mem now. */
shared_reference_ops_from_call (gimple call) if (VEC_length (vn_reference_op_s, mem) == 1)
{ {
if (!call) VEC_replace (vn_reference_op_s, *ops, i - 1,
return NULL; VEC_index (vn_reference_op_s, mem, 0));
VEC_truncate (vn_reference_op_s, shared_lookup_references, 0); VEC_ordered_remove (vn_reference_op_s, *ops, i);
copy_reference_ops_from_call (call, &shared_lookup_references); i--;
return shared_lookup_references; }
} 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 /* Transform any SSA_NAME's in a vector of vn_reference_op_s
structures into their value numbers. This is done in-place, and structures into their value numbers. This is done in-place, and
...@@ -783,7 +799,7 @@ static VEC (vn_reference_op_s, heap) * ...@@ -783,7 +799,7 @@ static VEC (vn_reference_op_s, heap) *
valueize_refs (VEC (vn_reference_op_s, heap) *orig) valueize_refs (VEC (vn_reference_op_s, heap) *orig)
{ {
vn_reference_op_t vro; vn_reference_op_t vro;
int i; unsigned int i;
for (i = 0; VEC_iterate (vn_reference_op_s, orig, i, vro); 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) ...@@ -795,15 +811,54 @@ valueize_refs (VEC (vn_reference_op_s, heap) *orig)
the opcode. */ the opcode. */
if (TREE_CODE (vro->op0) != SSA_NAME && vro->opcode == SSA_NAME) if (TREE_CODE (vro->op0) != SSA_NAME && vro->opcode == SSA_NAME)
vro->opcode = TREE_CODE (vro->op0); 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 if (vro->op1 && TREE_CODE (vro->op1) == SSA_NAME)
ARRAY_REF/COMPONENT_REF for Ada */ vro->op1 = SSA_VAL (vro->op1);
if (vro->op2 && TREE_CODE (vro->op2) == SSA_NAME)
vro->op2 = SSA_VAL (vro->op2);
} }
return orig; 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. /* Lookup a SCCVN reference operation VR in the current hash table.
Returns the resulting value number if it exists in the 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 NULL_TREE otherwise. VNRESULT will be filled in with the actual
...@@ -914,7 +969,7 @@ vn_reference_lookup (tree op, tree vuse, bool maywalk, ...@@ -914,7 +969,7 @@ vn_reference_lookup (tree op, tree vuse, bool maywalk,
*vnresult = NULL; *vnresult = NULL;
vr1.vuse = vuse ? SSA_VAL (vuse) : NULL_TREE; 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); vr1.hashcode = vn_reference_compute_hash (&vr1);
if (maywalk if (maywalk
...@@ -1585,7 +1640,7 @@ visit_reference_op_call (tree lhs, gimple stmt) ...@@ -1585,7 +1640,7 @@ visit_reference_op_call (tree lhs, gimple stmt)
tree vuse = gimple_vuse (stmt); tree vuse = gimple_vuse (stmt);
vr1.vuse = vuse ? SSA_VAL (vuse) : NULL_TREE; 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); vr1.hashcode = vn_reference_compute_hash (&vr1);
result = vn_reference_lookup_1 (&vr1, NULL); result = vn_reference_lookup_1 (&vr1, NULL);
if (result) if (result)
......
...@@ -173,6 +173,8 @@ vn_nary_op_t vn_nary_op_insert_stmt (gimple, tree); ...@@ -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, vn_nary_op_t vn_nary_op_insert_pieces (unsigned int, enum tree_code,
tree, tree, tree, tree, tree, tree, tree, tree,
tree, tree, unsigned int); 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_ref (tree, VEC(vn_reference_op_s, heap) **);
void copy_reference_ops_from_call (gimple, 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); tree get_ref_from_reference_ops (VEC(vn_reference_op_s, heap) *ops);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment