Commit 896c8b96 by Richard Guenther Committed by Richard Biener

re PR tree-optimization/34172 (Missed store ccp optimization)

2008-03-14  Richard Guenther  <rguenther@suse.de>

	PR tree-optimization/34172
	* tree-flow.h (refs_may_alias_p): Declare.
	(get_single_def_stmt): Likewise.
	(get_single_def_stmt_from_phi): Likewise.
	(get_single_def_stmt_with_phi): Likewise.
	* tree-dfa.c (refs_may_alias_p): New function.
	(get_single_def_stmt): Likewise.
	(get_single_def_stmt_from_phi): Likewise.
	(get_single_def_stmt_with_phi): Likewise.
	* tree-ssa-sccvn.c (get_def_ref_stmt_vuses): New function.
	(vn_reference_lookup_1): New helper function.
	(vn_reference_lookup): Walk the virtual use-def chain to
	continue searching for a match if the def does not alias the
	reference we are looking for.

	* gcc.dg/tree-ssa/ssa-fre-11.c: New testcase.
	* gcc.dg/tree-ssa/ssa-fre-12.c: Likewise.
	* gcc.dg/tree-ssa/ssa-fre-13.c: Likewise.
	* gcc.dg/tree-ssa/ssa-fre-14.c: Likewise.
	* gcc.dg/tree-ssa/ssa-fre-15.c: Likewise.
	* gcc.dg/tree-ssa/20031106-4.c: Remove XFAIL.

From-SVN: r133222
parent 15535043
2008-03-14 Richard Guenther <rguenther@suse.de>
PR tree-optimization/34172
* tree-flow.h (refs_may_alias_p): Declare.
(get_single_def_stmt): Likewise.
(get_single_def_stmt_from_phi): Likewise.
(get_single_def_stmt_with_phi): Likewise.
* tree-dfa.c (refs_may_alias_p): New function.
(get_single_def_stmt): Likewise.
(get_single_def_stmt_from_phi): Likewise.
(get_single_def_stmt_with_phi): Likewise.
* tree-ssa-sccvn.c (get_def_ref_stmt_vuses): New function.
(vn_reference_lookup_1): New helper function.
(vn_reference_lookup): Walk the virtual use-def chain to
continue searching for a match if the def does not alias the
reference we are looking for.
2008-03-14 David Edelsohn <edelsohn@gnu.org>
* doc/install.texi (Binaries): Remove UCLA archive. Add HVCC
......
2008-03-14 Richard Guenther <rguenther@suse.de>
PR tree-optimization/34172
* gcc.dg/tree-ssa/ssa-fre-11.c: New testcase.
* gcc.dg/tree-ssa/ssa-fre-12.c: Likewise.
* gcc.dg/tree-ssa/ssa-fre-13.c: Likewise.
* gcc.dg/tree-ssa/ssa-fre-14.c: Likewise.
* gcc.dg/tree-ssa/ssa-fre-15.c: Likewise.
* gcc.dg/tree-ssa/20031106-4.c: Remove XFAIL.
2008-03-14 Uros Bizjak <ubizjak@gmail.com>
PR libcpp/35322:
......@@ -26,5 +26,5 @@ void foo (struct s* r)
}
/* There should be no link_error calls. */
/* { dg-final { scan-tree-dump-times "link_error" 0 "optimized" { xfail *-*-* } } } */
/* { dg-final { scan-tree-dump-times "link_error" 0 "optimized" } } */
/* { dg-final { cleanup-tree-dump "optimized" } } */
/* { dg-do compile } */
/* { dg-options "-O -fdump-tree-fre-details" } */
struct
{
int x;
int y;
} S[100];
int z[100];
int
foo (int y)
{
int x;
S[5].x = 4;
S[5].y = 0;
x = S[5].x;
return (x);
}
/* { dg-final { scan-tree-dump "Replaced S\\\[5\\\].x with 4" "fre" } } */
/* { dg-final { cleanup-tree-dump "fre" } } */
/* { dg-do compile } */
/* { dg-options "-O -fdump-tree-fre-details" } */
struct
{
int x;
int y;
} S[100];
int z[100];
int
foo (int y)
{
int x;
S[5].x = 4;
S[5].y = 0;
x = S[5].x;
return (x);
}
/* { dg-final { scan-tree-dump "Replaced S\\\[5\\\].x with 4" "fre" } } */
/* { dg-final { cleanup-tree-dump "fre" } } */
/* { dg-do compile } */
/* { dg-options "-O -fstrict-aliasing -fno-tree-sra --param max-aliased-vops=0 --param max-fields-for-field-sensitive=0 -fdump-tree-fre-details" } */
/* Should be optimized, propagating &a into (*p)[i] with parameters
--param max-aliased-vops=0 --param max-fields-for-field-sensitive=0
which means max 1 VOP per stmt and no SFTs. */
/* For this testcase we need TBAA to work. */
struct Foo
{
void *data;
int size;
};
void foo(double (*q)[4], struct Foo *tmp1)
{
double a[4];
int i;
tmp1->data = &a;
tmp1->size = 4;
for (i=0; i<4; ++i)
{
double (*p)[4] = tmp1->data;
(*p)[i] = (*q)[i];
}
}
/* { dg-final { scan-tree-dump "Inserted .* &a" "fre" } } */
/* { dg-final { scan-tree-dump "Replaced tmp1_.\\\(D\\\)->data" "fre" } } */
/* { dg-final { cleanup-tree-dump "fre" } } */
/* { dg-do compile } */
/* { dg-options "-O -fno-tree-sra --param max-aliased-vops=0 --param max-fields-for-field-sensitive=0 -fdump-tree-fre-details" } */
/* Should be optimized, propagating &a into (*p)[i] with parameters
--param max-aliased-vops=0 --param max-fields-for-field-sensitive=0
which means max 1 VOP per stmt and no SFTs. */
struct Foo
{
void *data;
double size;
};
void foo(double (*q)[4])
{
struct Foo tmp1;
double a[4];
int i;
tmp1.data = &a;
tmp1.size = 4;
for (i=0; i<4; ++i)
{
double (*p)[4] = tmp1.data;
(*p)[i] = (*q)[i];
/* We want a PHI for the VOP for accessing tmp1.data, so place
this store to tmp1 here. */
tmp1.size -= 1.0;
}
}
/* { dg-final { scan-tree-dump "Inserted .* &a" "fre" } } */
/* { dg-final { scan-tree-dump "Replaced tmp1.data" "fre" } } */
/* { dg-final { cleanup-tree-dump "fre" } } */
/* { dg-do compile } */
/* { dg-options "-O -fno-tree-sra --param max-aliased-vops=0 --param max-fields-for-field-sensitive=0 -fdump-tree-fre-details" } */
/* Should be optimized, propagating &a into (*p)[i] with parameters
--param max-aliased-vops=0 --param max-fields-for-field-sensitive=0
which means max 1 VOP per stmt and no SFTs. */
struct Foo
{
void *data;
double size;
};
void foo(double (*q)[4])
{
struct Foo tmp1;
double a[4];
int i;
tmp1.data = &a;
for (i=0; i<4; ++i)
{
double (*p)[4] = tmp1.data;
(*p)[i] = (*q)[i];
/* We want a PHI for the VOP for accessing tmp1.data, so place
this store to tmp1 here. */
tmp1.size -= 1.0;
}
}
/* { dg-final { scan-tree-dump "Replaced" "fre" } } */
/* { dg-final { cleanup-tree-dump "fre" } } */
......@@ -1046,3 +1046,165 @@ stmt_references_abnormal_ssa_name (tree stmt)
return false;
}
/* Return true, if the two memory references REF1 and REF2 may alias. */
bool
refs_may_alias_p (tree ref1, tree ref2)
{
tree base1, base2;
HOST_WIDE_INT offset1 = 0, offset2 = 0;
HOST_WIDE_INT size1 = -1, size2 = -1;
HOST_WIDE_INT max_size1 = -1, max_size2 = -1;
gcc_assert ((SSA_VAR_P (ref1)
|| handled_component_p (ref1)
|| TREE_CODE (ref1) == INDIRECT_REF)
&& (SSA_VAR_P (ref2)
|| handled_component_p (ref2)
|| TREE_CODE (ref2) == INDIRECT_REF));
/* Defer to TBAA if possible. */
if (flag_strict_aliasing
&& !alias_sets_conflict_p (get_alias_set (ref1), get_alias_set (ref2)))
return false;
/* Decompose the references into their base objects and the access. */
base1 = ref1;
if (handled_component_p (ref1))
base1 = get_ref_base_and_extent (ref1, &offset1, &size1, &max_size1);
base2 = ref2;
if (handled_component_p (ref2))
base2 = get_ref_base_and_extent (ref2, &offset2, &size2, &max_size2);
/* If both references are based on different variables, they cannot alias.
If both references are based on the same variable, they cannot alias if
if the accesses do not overlap. */
if (SSA_VAR_P (base1)
&& SSA_VAR_P (base2)
&& (!operand_equal_p (base1, base2, 0)
|| !ranges_overlap_p (offset1, max_size1, offset2, max_size2)))
return false;
/* If both references are through pointers and both pointers are equal
then they do not alias if the accesses do not overlap. */
if (TREE_CODE (base1) == INDIRECT_REF
&& TREE_CODE (base2) == INDIRECT_REF
&& operand_equal_p (TREE_OPERAND (base1, 0),
TREE_OPERAND (base2, 0), 0)
&& !ranges_overlap_p (offset1, max_size1, offset2, max_size2))
return false;
return true;
}
/* Given a stmt STMT that references memory, return the single stmt
that is reached by following the VUSE -> VDEF link. Returns
NULL_TREE, if there is no single stmt that defines all VUSEs of
STMT.
Note that for a stmt with a single virtual operand this may return
a PHI node as well. Note that if all VUSEs are default definitions
this function will return an empty statement. */
tree
get_single_def_stmt (tree stmt)
{
tree def_stmt = NULL_TREE;
tree use;
ssa_op_iter iter;
FOR_EACH_SSA_TREE_OPERAND (use, stmt, iter, SSA_OP_VIRTUAL_USES)
{
tree tmp = SSA_NAME_DEF_STMT (use);
/* ??? This is too simplistic for multiple virtual operands
reaching different PHI nodes of the same basic blocks or for
reaching all default definitions. */
if (def_stmt
&& def_stmt != tmp
&& !(IS_EMPTY_STMT (def_stmt)
&& IS_EMPTY_STMT (tmp)))
return NULL_TREE;
def_stmt = tmp;
}
return def_stmt;
}
/* Given a PHI node of virtual operands, tries to eliminate cyclic
reached definitions if they do not alias REF and returns the
defining statement of the single virtual operand that flows in
from a non-backedge. Returns NULL_TREE if such statement within
the above conditions cannot be found. */
tree
get_single_def_stmt_from_phi (tree ref, tree phi)
{
tree def_arg = NULL_TREE;
int i;
/* Find the single PHI argument that is not flowing in from a
back edge and verify that the loop-carried definitions do
not alias the reference we look for. */
for (i = 0; i < PHI_NUM_ARGS (phi); ++i)
{
tree arg = PHI_ARG_DEF (phi, i);
tree def_stmt;
if (!(PHI_ARG_EDGE (phi, i)->flags & EDGE_DFS_BACK))
{
/* Multiple non-back edges? Do not try to handle this. */
if (def_arg)
return NULL_TREE;
def_arg = arg;
continue;
}
/* Follow the definitions back to the original PHI node. Bail
out once a definition is found that may alias REF. */
def_stmt = SSA_NAME_DEF_STMT (arg);
do
{
if (TREE_CODE (def_stmt) != GIMPLE_MODIFY_STMT
|| refs_may_alias_p (ref, GIMPLE_STMT_OPERAND (def_stmt, 0)))
return NULL_TREE;
/* ??? This will only work, reaching the PHI node again if
there is a single virtual operand on def_stmt. */
def_stmt = get_single_def_stmt (def_stmt);
if (!def_stmt)
return NULL_TREE;
}
while (def_stmt != phi);
}
return SSA_NAME_DEF_STMT (def_arg);
}
/* Return the single reference statement defining all virtual uses
on STMT or NULL_TREE, if there are multiple defining statements.
Take into account only definitions that alias REF if following
back-edges when looking through a loop PHI node. */
tree
get_single_def_stmt_with_phi (tree ref, tree stmt)
{
switch (NUM_SSA_OPERANDS (stmt, SSA_OP_VIRTUAL_USES))
{
case 0:
gcc_unreachable ();
case 1:
{
tree def_stmt = SSA_NAME_DEF_STMT (SINGLE_SSA_TREE_OPERAND
(stmt, SSA_OP_VIRTUAL_USES));
/* We can handle lookups over PHI nodes only for a single
virtual operand. */
if (TREE_CODE (def_stmt) == PHI_NODE)
return get_single_def_stmt_from_phi (ref, def_stmt);
return def_stmt;
}
default:
return get_single_def_stmt (stmt);
}
}
......@@ -824,6 +824,10 @@ extern tree make_rename_temp (tree, const char *);
extern void set_default_def (tree, tree);
extern tree gimple_default_def (struct function *, tree);
extern bool stmt_references_abnormal_ssa_name (tree);
extern bool refs_may_alias_p (tree, tree);
extern tree get_single_def_stmt (tree);
extern tree get_single_def_stmt_from_phi (tree, tree);
extern tree get_single_def_stmt_with_phi (tree, tree);
/* In tree-phinodes.c */
extern void reserve_phi_args_for_new_edge (basic_block);
......
......@@ -662,6 +662,74 @@ valueize_vuses (VEC (tree, gc) *orig)
return orig;
}
/* Return the single reference statement defining all virtual uses
in VUSES or NULL_TREE, if there are multiple defining statements.
Take into account only definitions that alias REF if following
back-edges. */
static tree
get_def_ref_stmt_vuses (tree ref, VEC (tree, gc) *vuses)
{
tree def_stmt, vuse;
unsigned int i;
gcc_assert (VEC_length (tree, vuses) >= 1);
def_stmt = SSA_NAME_DEF_STMT (VEC_index (tree, vuses, 0));
if (TREE_CODE (def_stmt) == PHI_NODE)
{
/* We can only handle lookups over PHI nodes for a single
virtual operand. */
if (VEC_length (tree, vuses) == 1)
{
def_stmt = get_single_def_stmt_from_phi (ref, def_stmt);
goto cont;
}
else
return NULL_TREE;
}
/* Verify each VUSE reaches the same defining stmt. */
for (i = 1; VEC_iterate (tree, vuses, i, vuse); ++i)
{
tree tmp = SSA_NAME_DEF_STMT (vuse);
if (tmp != def_stmt)
return NULL_TREE;
}
/* Now see if the definition aliases ref, and loop until it does. */
cont:
while (def_stmt
&& TREE_CODE (def_stmt) == GIMPLE_MODIFY_STMT
&& !get_call_expr_in (def_stmt)
&& !refs_may_alias_p (ref, GIMPLE_STMT_OPERAND (def_stmt, 0)))
def_stmt = get_single_def_stmt_with_phi (ref, def_stmt);
return def_stmt;
}
/* 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. */
static tree
vn_reference_lookup_1 (vn_reference_t vr)
{
void **slot;
hashval_t hash;
hash = vr->hashcode;
slot = htab_find_slot_with_hash (current_info->references, vr,
hash, NO_INSERT);
if (!slot && current_info == optimistic_info)
slot = htab_find_slot_with_hash (valid_info->references, vr,
hash, NO_INSERT);
if (slot)
return ((vn_reference_t)*slot)->result;
return NULL_TREE;
}
/* Lookup OP in the current hash table, and return the resulting
value number if it exists in the hash table. Return NULL_TREE if
it does not exist in the hash table. */
......@@ -669,21 +737,35 @@ valueize_vuses (VEC (tree, gc) *orig)
tree
vn_reference_lookup (tree op, VEC (tree, gc) *vuses)
{
void **slot;
struct vn_reference_s vr1;
tree result, def_stmt;
vr1.vuses = valueize_vuses (vuses);
vr1.operands = valueize_refs (shared_reference_ops_from_ref (op));
vr1.hashcode = vn_reference_compute_hash (&vr1);
slot = htab_find_slot_with_hash (current_info->references, &vr1, vr1.hashcode,
NO_INSERT);
if (!slot && current_info == optimistic_info)
slot = htab_find_slot_with_hash (valid_info->references, &vr1, vr1.hashcode,
NO_INSERT);
if (!slot)
return NULL_TREE;
result = vn_reference_lookup_1 (&vr1);
/* If there is a single defining statement for all virtual uses, we can
use that, following virtual use-def chains. */
if (!result
&& vr1.vuses
&& VEC_length (tree, vr1.vuses) >= 1
&& !get_call_expr_in (op)
&& (def_stmt = get_def_ref_stmt_vuses (op, vr1.vuses))
&& TREE_CODE (def_stmt) == GIMPLE_MODIFY_STMT
/* If there is a call involved, op must be assumed to
be clobbered. */
&& !get_call_expr_in (def_stmt))
{
/* We are now at an aliasing definition for the vuses we want to
look up. Re-do the lookup with the vdefs for this stmt. */
vdefs_to_vec (def_stmt, &vuses);
vr1.vuses = valueize_vuses (vuses);
vr1.hashcode = vn_reference_compute_hash (&vr1);
result = vn_reference_lookup_1 (&vr1);
}
return ((vn_reference_t)*slot)->result;
return result;
}
/* Insert OP into the current hash table with a value number of
......@@ -1632,10 +1714,9 @@ visit_use (tree use)
print_generic_expr (dump_file, simplified, 0);
if (TREE_CODE (lhs) == SSA_NAME)
fprintf (dump_file, " has constants %d\n",
VN_INFO (lhs)->has_constants);
expr_has_constants (simplified));
else
fprintf (dump_file, "\n");
}
}
/* Setting value numbers to constants will occasionally
......
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