Commit 7d36e538 by Richard Guenther Committed by Richard Biener

re PR tree-optimization/44913 (-ftree-vectorize causes FAIL: gcc.dg/pr44838.c execution test)

2010-10-14  Richard Guenther  <rguenther@suse.de>

	PR tree-optimization/44913
	* tree-data-ref.c (disjoint_objects_p): Remove.
	(dr_may_alias_p): Simplify.  Only hand the base object to
	the alias-oracle.
	* tree-ssa-alias.c (ptr_deref_may_alias_decl_p): Handle
	some more trees, bail out instead of asserting.
	(ptr_derefs_may_alias_p): Likewise.  Export.
	(refs_may_alias_p_1): Handle STRING_CSTs.
	* tree-ssa-alias.h (ptr_derefs_may_alias_p): Declare.

	* gcc.dg/torture/pr44913.c: New testcase.

From-SVN: r165473
parent 180f8dbb
2010-10-14 Richard Guenther <rguenther@suse.de>
PR tree-optimization/44913
* tree-data-ref.c (disjoint_objects_p): Remove.
(dr_may_alias_p): Simplify. Only hand the base object to
the alias-oracle.
* tree-ssa-alias.c (ptr_deref_may_alias_decl_p): Handle
some more trees, bail out instead of asserting.
(ptr_derefs_may_alias_p): Likewise. Export.
(refs_may_alias_p_1): Handle STRING_CSTs.
* tree-ssa-alias.h (ptr_derefs_may_alias_p): Declare.
2010-10-14 Joseph Myers <joseph@codesourcery.com> 2010-10-14 Joseph Myers <joseph@codesourcery.com>
PR c/45969 PR c/45969
...@@ -5,6 +5,11 @@ ...@@ -5,6 +5,11 @@
2010-10-14 Richard Guenther <rguenther@suse.de> 2010-10-14 Richard Guenther <rguenther@suse.de>
PR tree-optimization/44913
* gcc.dg/torture/pr44913.c: New testcase.
2010-10-14 Richard Guenther <rguenther@suse.de>
PR lto/45382 PR lto/45382
* g++.dg/lto/20101014-2_0.C: New testcase. * g++.dg/lto/20101014-2_0.C: New testcase.
......
/* { dg-do run } */
void __attribute__((noinline,noclone))
foo (int *a, int n)
{
int *lasta = a + n;
for (; a != lasta; a++)
{
*a *= 2;
a[1] = a[-1] + a[-2];
}
}
extern void abort (void);
int main()
{
int a[16] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 };
int r[16] = { 1, 2, 6, 6, 16, 24, 44, 80, 136, 248, 432, 768, 1360, 2400, 4256, 3760 };
unsigned i;
foo (&a[2], 13);
for (i = 0; i < 8; ++i)
if (a[i] != r[i])
abort ();
return 0;
}
...@@ -1233,154 +1233,20 @@ object_address_invariant_in_loop_p (const struct loop *loop, const_tree obj) ...@@ -1233,154 +1233,20 @@ object_address_invariant_in_loop_p (const struct loop *loop, const_tree obj)
loop->num); loop->num);
} }
/* Returns true if A and B are accesses to different objects, or to different
fields of the same object. */
static bool
disjoint_objects_p (tree a, tree b)
{
tree base_a, base_b;
VEC (tree, heap) *comp_a = NULL, *comp_b = NULL;
bool ret;
base_a = get_base_address (a);
base_b = get_base_address (b);
if (DECL_P (base_a)
&& DECL_P (base_b)
&& base_a != base_b)
return true;
if (!operand_equal_p (base_a, base_b, 0))
return false;
/* Compare the component references of A and B. We must start from the inner
ones, so record them to the vector first. */
while (handled_component_p (a))
{
VEC_safe_push (tree, heap, comp_a, a);
a = TREE_OPERAND (a, 0);
}
while (handled_component_p (b))
{
VEC_safe_push (tree, heap, comp_b, b);
b = TREE_OPERAND (b, 0);
}
ret = false;
while (1)
{
if (VEC_length (tree, comp_a) == 0
|| VEC_length (tree, comp_b) == 0)
break;
a = VEC_pop (tree, comp_a);
b = VEC_pop (tree, comp_b);
/* Real and imaginary part of a variable do not alias. */
if ((TREE_CODE (a) == REALPART_EXPR
&& TREE_CODE (b) == IMAGPART_EXPR)
|| (TREE_CODE (a) == IMAGPART_EXPR
&& TREE_CODE (b) == REALPART_EXPR))
{
ret = true;
break;
}
if (TREE_CODE (a) != TREE_CODE (b))
break;
/* Nothing to do for ARRAY_REFs, as the indices of array_refs in
DR_BASE_OBJECT are always zero. */
if (TREE_CODE (a) == ARRAY_REF)
continue;
else if (TREE_CODE (a) == COMPONENT_REF)
{
if (operand_equal_p (TREE_OPERAND (a, 1), TREE_OPERAND (b, 1), 0))
continue;
/* Different fields of unions may overlap. */
base_a = TREE_OPERAND (a, 0);
if (TREE_CODE (TREE_TYPE (base_a)) == UNION_TYPE)
break;
/* Different fields of structures cannot. */
ret = true;
break;
}
else
break;
}
VEC_free (tree, heap, comp_a);
VEC_free (tree, heap, comp_b);
return ret;
}
/* Returns false if we can prove that data references A and B do not alias, /* Returns false if we can prove that data references A and B do not alias,
true otherwise. */ true otherwise. */
bool bool
dr_may_alias_p (const struct data_reference *a, const struct data_reference *b) dr_may_alias_p (const struct data_reference *a, const struct data_reference *b)
{ {
const_tree addr_a = DR_BASE_ADDRESS (a); tree addr_a = DR_BASE_OBJECT (a);
const_tree addr_b = DR_BASE_ADDRESS (b); tree addr_b = DR_BASE_OBJECT (b);
const_tree type_a, type_b;
const_tree decl_a = NULL_TREE, decl_b = NULL_TREE;
/* If the accessed objects are disjoint, the memory references do not
alias. */
if (disjoint_objects_p (DR_BASE_OBJECT (a), DR_BASE_OBJECT (b)))
return false;
/* Query the alias oracle. */
if (DR_IS_WRITE (a) && DR_IS_WRITE (b)) if (DR_IS_WRITE (a) && DR_IS_WRITE (b))
{ return refs_output_dependent_p (addr_a, addr_b);
if (!refs_output_dependent_p (DR_REF (a), DR_REF (b)))
return false;
}
else if (DR_IS_READ (a) && DR_IS_WRITE (b)) else if (DR_IS_READ (a) && DR_IS_WRITE (b))
{ return refs_anti_dependent_p (addr_a, addr_b);
if (!refs_anti_dependent_p (DR_REF (a), DR_REF (b))) return refs_may_alias_p (addr_a, addr_b);
return false;
}
else if (!refs_may_alias_p (DR_REF (a), DR_REF (b)))
return false;
if (!addr_a || !addr_b)
return true;
/* If the references are based on different static objects, they cannot
alias (PTA should be able to disambiguate such accesses, but often
it fails to). */
if (TREE_CODE (addr_a) == ADDR_EXPR
&& TREE_CODE (addr_b) == ADDR_EXPR)
return TREE_OPERAND (addr_a, 0) == TREE_OPERAND (addr_b, 0);
/* An instruction writing through a restricted pointer is "independent" of any
instruction reading or writing through a different restricted pointer,
in the same block/scope. */
type_a = TREE_TYPE (addr_a);
type_b = TREE_TYPE (addr_b);
gcc_assert (POINTER_TYPE_P (type_a) && POINTER_TYPE_P (type_b));
if (TREE_CODE (addr_a) == SSA_NAME)
decl_a = SSA_NAME_VAR (addr_a);
if (TREE_CODE (addr_b) == SSA_NAME)
decl_b = SSA_NAME_VAR (addr_b);
if (TYPE_RESTRICT (type_a) && TYPE_RESTRICT (type_b)
&& (DR_IS_WRITE (a) || DR_IS_WRITE (b))
&& decl_a && DECL_P (decl_a)
&& decl_b && DECL_P (decl_b)
&& decl_a != decl_b
&& TREE_CODE (DECL_CONTEXT (decl_a)) == FUNCTION_DECL
&& DECL_CONTEXT (decl_a) == DECL_CONTEXT (decl_b))
return false;
return true;
} }
static void compute_self_dependence (struct data_dependence_relation *); static void compute_self_dependence (struct data_dependence_relation *);
......
...@@ -166,17 +166,31 @@ ptr_deref_may_alias_decl_p (tree ptr, tree decl) ...@@ -166,17 +166,31 @@ ptr_deref_may_alias_decl_p (tree ptr, tree decl)
{ {
struct ptr_info_def *pi; struct ptr_info_def *pi;
gcc_assert ((TREE_CODE (ptr) == SSA_NAME /* Conversions are irrelevant for points-to information and
|| TREE_CODE (ptr) == ADDR_EXPR data-dependence analysis can feed us those. */
|| TREE_CODE (ptr) == INTEGER_CST) STRIP_NOPS (ptr);
&& (TREE_CODE (decl) == VAR_DECL
|| TREE_CODE (decl) == PARM_DECL /* Anything we do not explicilty handle aliases. */
|| TREE_CODE (decl) == RESULT_DECL)); if ((TREE_CODE (ptr) != SSA_NAME
&& TREE_CODE (ptr) != ADDR_EXPR
/* Non-aliased variables can not be pointed to. */ && TREE_CODE (ptr) != POINTER_PLUS_EXPR)
if (!may_be_aliased (decl)) || !POINTER_TYPE_P (TREE_TYPE (ptr))
|| (TREE_CODE (decl) != VAR_DECL
&& TREE_CODE (decl) != PARM_DECL
&& TREE_CODE (decl) != RESULT_DECL))
return false; return false;
/* Disregard pointer offsetting. */
if (TREE_CODE (ptr) == POINTER_PLUS_EXPR)
{
do
{
ptr = TREE_OPERAND (ptr, 0);
}
while (TREE_CODE (ptr) == POINTER_PLUS_EXPR);
return ptr_deref_may_alias_decl_p (ptr, decl);
}
/* ADDR_EXPR pointers either just offset another pointer or directly /* ADDR_EXPR pointers either just offset another pointer or directly
specify the pointed-to set. */ specify the pointed-to set. */
if (TREE_CODE (ptr) == ADDR_EXPR) if (TREE_CODE (ptr) == ADDR_EXPR)
...@@ -196,10 +210,9 @@ ptr_deref_may_alias_decl_p (tree ptr, tree decl) ...@@ -196,10 +210,9 @@ ptr_deref_may_alias_decl_p (tree ptr, tree decl)
return true; return true;
} }
/* We can end up with dereferencing constant pointers. /* Non-aliased variables can not be pointed to. */
Just bail out in this case. */ if (!may_be_aliased (decl))
if (TREE_CODE (ptr) == INTEGER_CST) return false;
return true;
/* If we do not have useful points-to information for this pointer /* If we do not have useful points-to information for this pointer
we cannot disambiguate anything else. */ we cannot disambiguate anything else. */
...@@ -222,17 +235,46 @@ ptr_deref_may_alias_decl_p (tree ptr, tree decl) ...@@ -222,17 +235,46 @@ ptr_deref_may_alias_decl_p (tree ptr, tree decl)
The caller is responsible for applying TBAA to see if accesses The caller is responsible for applying TBAA to see if accesses
through PTR1 and PTR2 may conflict at all. */ through PTR1 and PTR2 may conflict at all. */
static bool bool
ptr_derefs_may_alias_p (tree ptr1, tree ptr2) ptr_derefs_may_alias_p (tree ptr1, tree ptr2)
{ {
struct ptr_info_def *pi1, *pi2; struct ptr_info_def *pi1, *pi2;
gcc_assert ((TREE_CODE (ptr1) == SSA_NAME /* Conversions are irrelevant for points-to information and
|| TREE_CODE (ptr1) == ADDR_EXPR data-dependence analysis can feed us those. */
|| TREE_CODE (ptr1) == INTEGER_CST) STRIP_NOPS (ptr1);
&& (TREE_CODE (ptr2) == SSA_NAME STRIP_NOPS (ptr2);
|| TREE_CODE (ptr2) == ADDR_EXPR
|| TREE_CODE (ptr2) == INTEGER_CST)); /* Anything we do not explicilty handle aliases. */
if ((TREE_CODE (ptr1) != SSA_NAME
&& TREE_CODE (ptr1) != ADDR_EXPR
&& TREE_CODE (ptr1) != POINTER_PLUS_EXPR)
|| (TREE_CODE (ptr2) != SSA_NAME
&& TREE_CODE (ptr2) != ADDR_EXPR
&& TREE_CODE (ptr2) != POINTER_PLUS_EXPR)
|| !POINTER_TYPE_P (TREE_TYPE (ptr1))
|| !POINTER_TYPE_P (TREE_TYPE (ptr2)))
return true;
/* Disregard pointer offsetting. */
if (TREE_CODE (ptr1) == POINTER_PLUS_EXPR)
{
do
{
ptr1 = TREE_OPERAND (ptr1, 0);
}
while (TREE_CODE (ptr1) == POINTER_PLUS_EXPR);
return ptr_derefs_may_alias_p (ptr1, ptr2);
}
if (TREE_CODE (ptr2) == POINTER_PLUS_EXPR)
{
do
{
ptr2 = TREE_OPERAND (ptr2, 0);
}
while (TREE_CODE (ptr2) == POINTER_PLUS_EXPR);
return ptr_derefs_may_alias_p (ptr1, ptr2);
}
/* ADDR_EXPR pointers either just offset another pointer or directly /* ADDR_EXPR pointers either just offset another pointer or directly
specify the pointed-to set. */ specify the pointed-to set. */
...@@ -263,12 +305,6 @@ ptr_derefs_may_alias_p (tree ptr1, tree ptr2) ...@@ -263,12 +305,6 @@ ptr_derefs_may_alias_p (tree ptr1, tree ptr2)
return true; return true;
} }
/* We can end up with dereferencing constant pointers.
Just bail out in this case. */
if (TREE_CODE (ptr1) == INTEGER_CST
|| TREE_CODE (ptr2) == INTEGER_CST)
return true;
/* We may end up with two empty points-to solutions for two same pointers. /* We may end up with two empty points-to solutions for two same pointers.
In this case we still want to say both pointers alias, so shortcut In this case we still want to say both pointers alias, so shortcut
that here. */ that here. */
...@@ -938,6 +974,7 @@ refs_may_alias_p_1 (ao_ref *ref1, ao_ref *ref2, bool tbaa_p) ...@@ -938,6 +974,7 @@ refs_may_alias_p_1 (ao_ref *ref1, ao_ref *ref2, bool tbaa_p)
gcc_checking_assert ((!ref1->ref gcc_checking_assert ((!ref1->ref
|| TREE_CODE (ref1->ref) == SSA_NAME || TREE_CODE (ref1->ref) == SSA_NAME
|| DECL_P (ref1->ref) || DECL_P (ref1->ref)
|| TREE_CODE (ref1->ref) == STRING_CST
|| handled_component_p (ref1->ref) || handled_component_p (ref1->ref)
|| INDIRECT_REF_P (ref1->ref) || INDIRECT_REF_P (ref1->ref)
|| TREE_CODE (ref1->ref) == MEM_REF || TREE_CODE (ref1->ref) == MEM_REF
...@@ -945,6 +982,7 @@ refs_may_alias_p_1 (ao_ref *ref1, ao_ref *ref2, bool tbaa_p) ...@@ -945,6 +982,7 @@ refs_may_alias_p_1 (ao_ref *ref1, ao_ref *ref2, bool tbaa_p)
&& (!ref2->ref && (!ref2->ref
|| TREE_CODE (ref2->ref) == SSA_NAME || TREE_CODE (ref2->ref) == SSA_NAME
|| DECL_P (ref2->ref) || DECL_P (ref2->ref)
|| TREE_CODE (ref2->ref) == STRING_CST
|| handled_component_p (ref2->ref) || handled_component_p (ref2->ref)
|| INDIRECT_REF_P (ref2->ref) || INDIRECT_REF_P (ref2->ref)
|| TREE_CODE (ref2->ref) == MEM_REF || TREE_CODE (ref2->ref) == MEM_REF
...@@ -965,6 +1003,8 @@ refs_may_alias_p_1 (ao_ref *ref1, ao_ref *ref2, bool tbaa_p) ...@@ -965,6 +1003,8 @@ refs_may_alias_p_1 (ao_ref *ref1, ao_ref *ref2, bool tbaa_p)
|| TREE_CODE (base2) == SSA_NAME || TREE_CODE (base2) == SSA_NAME
|| TREE_CODE (base1) == CONST_DECL || TREE_CODE (base1) == CONST_DECL
|| TREE_CODE (base2) == CONST_DECL || TREE_CODE (base2) == CONST_DECL
|| TREE_CODE (base1) == STRING_CST
|| TREE_CODE (base2) == STRING_CST
|| is_gimple_min_invariant (base1) || is_gimple_min_invariant (base1)
|| is_gimple_min_invariant (base2)) || is_gimple_min_invariant (base2))
return false; return false;
......
...@@ -97,6 +97,7 @@ extern void ao_ref_init_from_ptr_and_size (ao_ref *, tree, tree); ...@@ -97,6 +97,7 @@ extern void ao_ref_init_from_ptr_and_size (ao_ref *, tree, tree);
extern tree ao_ref_base (ao_ref *); extern tree ao_ref_base (ao_ref *);
extern alias_set_type ao_ref_alias_set (ao_ref *); extern alias_set_type ao_ref_alias_set (ao_ref *);
extern bool ptr_deref_may_alias_global_p (tree); extern bool ptr_deref_may_alias_global_p (tree);
extern bool ptr_derefs_may_alias_p (tree, tree);
extern bool refs_may_alias_p (tree, tree); extern bool refs_may_alias_p (tree, tree);
extern bool refs_may_alias_p_1 (ao_ref *, ao_ref *, bool); extern bool refs_may_alias_p_1 (ao_ref *, ao_ref *, bool);
extern bool refs_anti_dependent_p (tree, tree); extern bool refs_anti_dependent_p (tree, tree);
......
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