Commit e5bae89b by Richard Guenther Committed by Richard Biener

tree-ssa-structalias.c (struct variable_info): Add is_full_var flag.

2008-07-07  Richard Guenther  <rguenther@suse.de>

	* tree-ssa-structalias.c (struct variable_info): Add is_full_var flag.
	(new_var_info): Set it to false.
	(solution_set_add): Correctly handle pointers outside a var and
	inside a field.
	(type_safe): Treat variables with is_full_var properly.
	(do_sd_constraint): Likewise.
	(do_ds_constraint): Likewise.
	(process_constraint): Remove zeroing offset for !use_field_sensitive.
	(get_constraint_for_ptr_offset): New function.
	(get_constraint_for_component_ref): For addresses at least include
	the last field of the variable.  Handle is_full_vars properly.
	(get_constraint_for_1): Factor common code, handle POINTER_PLUS_EXPR.
	(handle_ptr_arith): Remove.
	(find_func_aliases): Simplify assignment handling.
	(create_function_info_for): For parameter and result varinfos set
	is_full_var flag.
	(create_variable_info_for): Set is_full_var flag whenever we
	just created a single varinfo for a decl.
	(init_alias_vars): Initialize use_field_sensitive from
	max-fields-for-field-sensitive parameter.

	* gcc.dg/torture/pta-ptrarith-1.c: New testcase.
	* gcc.dg/torture/pta-ptrarith-2.c: Likewise.
	* gcc.dg/torture/ipa-pta-1.c: Likewise.

From-SVN: r137573
parent 77092cda
2008-07-07 Richard Guenther <rguenther@suse.de> 2008-07-07 Richard Guenther <rguenther@suse.de>
* tree-ssa-structalias.c (struct variable_info): Add is_full_var flag.
(new_var_info): Set it to false.
(solution_set_add): Correctly handle pointers outside a var and
inside a field.
(type_safe): Treat variables with is_full_var properly.
(do_sd_constraint): Likewise.
(do_ds_constraint): Likewise.
(process_constraint): Remove zeroing offset for !use_field_sensitive.
(get_constraint_for_ptr_offset): New function.
(get_constraint_for_component_ref): For addresses at least include
the last field of the variable. Handle is_full_vars properly.
(get_constraint_for_1): Factor common code, handle POINTER_PLUS_EXPR.
(handle_ptr_arith): Remove.
(find_func_aliases): Simplify assignment handling.
(create_function_info_for): For parameter and result varinfos set
is_full_var flag.
(create_variable_info_for): Set is_full_var flag whenever we
just created a single varinfo for a decl.
(init_alias_vars): Initialize use_field_sensitive from
max-fields-for-field-sensitive parameter.
2008-07-07 Richard Guenther <rguenther@suse.de>
PR tree-optimization/36713 PR tree-optimization/36713
* tree-flow-inline.h (is_call_used): New function. * tree-flow-inline.h (is_call_used): New function.
* tree-nrv.c (dest_safe_for_nrv_p): Use it. * tree-nrv.c (dest_safe_for_nrv_p): Use it.
......
2008-07-07 Richard Guenther <rguenther@suse.de>
* gcc.dg/torture/pta-ptrarith-1.c: New testcase.
* gcc.dg/torture/pta-ptrarith-2.c: Likewise.
* gcc.dg/torture/ipa-pta-1.c: Likewise.
2008-07-07 Jakub Jelinek <jakub@redhat.com> 2008-07-07 Jakub Jelinek <jakub@redhat.com>
PR middle-end/36726 PR middle-end/36726
......
/* { dg-do compile } */
/* { dg-options "-fipa-pta -fdump-ipa-pta" } */
/* { dg-skip-if "" { *-*-* } { "-O0" } { "" } } */
struct X { char x; char y; };
void bar (char *p);
void test1 (char a, char b, char c, char d, char e, char f, char g, char h)
{
char *p = &a;
p++;
bar (p);
}
void test2 (struct X a, char b, char c, char d, char e, char f, char g, char h)
{
char *p = &a.x;
p++;
bar (p);
}
void test3 (struct X a, char b, char c, char d, char e, char f, char g, char h)
{
char *p = &a.y;
bar (p);
}
void test4 (int a, char b, char c, char d, char e, char f, char g, char h)
{
char *p = (char *)&a;
p++;
p++;
p++;
p++;
bar (p);
}
/* { dg-final { scan-ipa-dump "bar.arg0 = { test4.arg0 test3.arg0 test2.arg0 test1.arg0 }" "pta" } } */
/* { dg-final { cleanup-ipa-dump "pta" } } */
/* { dg-do run } */
/* { dg-options "-fdump-tree-alias" } */
/* { dg-skip-if "" { *-*-* } { "-O0" } { "" } } */
struct Foo {
int *p;
};
void __attribute__((noinline))
foo (void *p)
{
struct Foo *f = (struct Foo *)p - 1;
*f->p = 0;
}
int bar (void)
{
struct Foo f;
int i = 1;
f.p = &i;
foo (&f + 1);
return i;
}
extern void abort (void);
int main()
{
if (bar () != 0)
abort ();
return 0;
}
/* { dg-final { scan-tree-dump "ESCAPED = { ESCAPED NONLOCAL f .* i }" "alias" } } */
/* { dg-final { cleanup-tree-dump "alias" } } */
/* { dg-do run } */
/* { dg-options "-fdump-tree-alias" } */
/* { dg-skip-if "" { *-*-* } { "-O0" } { "" } } */
struct Foo {
int **p;
int **q;
};
int __attribute__((noinline))
bar (void)
{
struct Foo f;
int j, i = 1;
char *p;
int *x = &i;
int *y = &j;
f.p = &y;
f.q = &x;
p = (char *)&f;
for (j = 0; j < sizeof (int *); ++j)
p++;
return ***(int ***)p;
}
extern void abort (void);
int main()
{
if (bar () != 1)
abort ();
return 0;
}
/* In theory = { i } is the correct solution. But it's not easy to scan
for that reliably, so just use what we create now. */
/* { dg-final { scan-tree-dump "= { i j }" "alias" } } */
/* { dg-final { cleanup-tree-dump "alias" } } */
...@@ -220,6 +220,9 @@ struct variable_info ...@@ -220,6 +220,9 @@ struct variable_info
/* True for variables whose size is not known or variable. */ /* True for variables whose size is not known or variable. */
unsigned int is_unknown_size_var:1; unsigned int is_unknown_size_var:1;
/* True for (sub-)fields that represent a whole variable. */
unsigned int is_full_var : 1;
/* True if this is a heap variable. */ /* True if this is a heap variable. */
unsigned int is_heap_var:1; unsigned int is_heap_var:1;
...@@ -373,6 +376,7 @@ new_var_info (tree t, unsigned int id, const char *name) ...@@ -373,6 +376,7 @@ new_var_info (tree t, unsigned int id, const char *name)
ret->is_heap_var = false; ret->is_heap_var = false;
ret->is_special_var = false; ret->is_special_var = false;
ret->is_unknown_size_var = false; ret->is_unknown_size_var = false;
ret->is_full_var = false;
var = t; var = t;
if (TREE_CODE (var) == SSA_NAME) if (TREE_CODE (var) == SSA_NAME)
var = SSA_NAME_VAR (var); var = SSA_NAME_VAR (var);
...@@ -752,22 +756,32 @@ solution_set_add (bitmap set, unsigned HOST_WIDE_INT offset) ...@@ -752,22 +756,32 @@ solution_set_add (bitmap set, unsigned HOST_WIDE_INT offset)
EXECUTE_IF_SET_IN_BITMAP (set, 0, i, bi) EXECUTE_IF_SET_IN_BITMAP (set, 0, i, bi)
{ {
/* If this is a properly sized variable, only add offset if it's varinfo_t vi = get_varinfo (i);
less than end. Otherwise, it is globbed to a single
variable. */
if ((get_varinfo (i)->offset + offset) < get_varinfo (i)->fullsize) /* If this is a variable with just one field just set its bit
in the result. */
if (vi->is_artificial_var
|| vi->is_unknown_size_var
|| vi->is_full_var)
bitmap_set_bit (result, i);
else
{ {
unsigned HOST_WIDE_INT fieldoffset = get_varinfo (i)->offset + offset; unsigned HOST_WIDE_INT fieldoffset = vi->offset + offset;
varinfo_t v = first_vi_for_offset (get_varinfo (i), fieldoffset); varinfo_t v = first_vi_for_offset (vi, fieldoffset);
/* If the result is outside of the variable use the last field. */
if (!v) if (!v)
continue; {
v = vi;
while (v->next != NULL)
v = v->next;
}
bitmap_set_bit (result, v->id); bitmap_set_bit (result, v->id);
} /* If the result is not exactly at fieldoffset include the next
else if (get_varinfo (i)->is_artificial_var field as well. See get_constraint_for_ptr_offset for more
|| get_varinfo (i)->is_unknown_size_var) rationale. */
{ if (v->offset != fieldoffset
bitmap_set_bit (result, i); && v->next != NULL)
bitmap_set_bit (result, v->next->id);
} }
} }
...@@ -1375,7 +1389,8 @@ type_safe (unsigned int n, unsigned HOST_WIDE_INT *offset) ...@@ -1375,7 +1389,8 @@ type_safe (unsigned int n, unsigned HOST_WIDE_INT *offset)
0. */ 0. */
if (ninfo->is_special_var if (ninfo->is_special_var
|| ninfo->is_artificial_var || ninfo->is_artificial_var
|| ninfo->is_unknown_size_var) || ninfo->is_unknown_size_var
|| ninfo->is_full_var)
{ {
*offset = 0; *offset = 0;
return true; return true;
...@@ -1415,7 +1430,11 @@ do_sd_constraint (constraint_graph_t graph, constraint_t c, ...@@ -1415,7 +1430,11 @@ do_sd_constraint (constraint_graph_t graph, constraint_t c,
sub-fields off. This avoids quadratic behavior. */ sub-fields off. This avoids quadratic behavior. */
EXECUTE_IF_SET_IN_BITMAP (delta, 0, j, bi) EXECUTE_IF_SET_IN_BITMAP (delta, 0, j, bi)
{ {
varinfo_t v = lookup_vi_for_tree (get_varinfo (j)->decl); varinfo_t v = get_varinfo (j);
if (v->is_full_var)
continue;
v = lookup_vi_for_tree (v->decl);
if (v->next != NULL) if (v->next != NULL)
{ {
if (vars == NULL) if (vars == NULL)
...@@ -1455,6 +1474,7 @@ do_sd_constraint (constraint_graph_t graph, constraint_t c, ...@@ -1455,6 +1474,7 @@ do_sd_constraint (constraint_graph_t graph, constraint_t c,
unsigned int t; unsigned int t;
v = first_vi_for_offset (get_varinfo (j), fieldoffset); v = first_vi_for_offset (get_varinfo (j), fieldoffset);
/* If the access is outside of the variable we can ignore it. */
if (!v) if (!v)
continue; continue;
t = find (v->id); t = find (v->id);
...@@ -1507,9 +1527,14 @@ do_ds_constraint (constraint_t c, bitmap delta) ...@@ -1507,9 +1527,14 @@ do_ds_constraint (constraint_t c, bitmap delta)
unsigned HOST_WIDE_INT fieldoffset = jvi->offset + loff; unsigned HOST_WIDE_INT fieldoffset = jvi->offset + loff;
varinfo_t v; varinfo_t v;
v = first_vi_for_offset (get_varinfo (j), fieldoffset); v = get_varinfo (j);
if (!v) if (!v->is_full_var)
continue; {
v = first_vi_for_offset (v, fieldoffset);
/* If the access is outside of the variable we can ignore it. */
if (!v)
continue;
}
t = find (v->id); t = find (v->id);
if (bitmap_set_bit (get_varinfo (t)->solution, anything_id) if (bitmap_set_bit (get_varinfo (t)->solution, anything_id)
...@@ -1535,6 +1560,7 @@ do_ds_constraint (constraint_t c, bitmap delta) ...@@ -1535,6 +1560,7 @@ do_ds_constraint (constraint_t c, bitmap delta)
bitmap tmp; bitmap tmp;
v = first_vi_for_offset (get_varinfo (j), fieldoffset); v = first_vi_for_offset (get_varinfo (j), fieldoffset);
/* If the access is outside of the variable we can ignore it. */
if (!v) if (!v)
continue; continue;
t = find (v->id); t = find (v->id);
...@@ -2597,12 +2623,6 @@ process_constraint (constraint_t t) ...@@ -2597,12 +2623,6 @@ process_constraint (constraint_t t)
gcc_assert (rhs.var < VEC_length (varinfo_t, varmap)); gcc_assert (rhs.var < VEC_length (varinfo_t, varmap));
gcc_assert (lhs.var < VEC_length (varinfo_t, varmap)); gcc_assert (lhs.var < VEC_length (varinfo_t, varmap));
if (!use_field_sensitive)
{
t->rhs.offset = 0;
t->lhs.offset = 0;
}
/* ANYTHING == ANYTHING is pointless. */ /* ANYTHING == ANYTHING is pointless. */
if (lhs.var == anything_id && rhs.var == anything_id) if (lhs.var == anything_id && rhs.var == anything_id)
return; return;
...@@ -2678,6 +2698,119 @@ bitpos_of_field (const tree fdecl) ...@@ -2678,6 +2698,119 @@ bitpos_of_field (const tree fdecl)
} }
/* Get constraint expressions for offsetting PTR by OFFSET. Stores the
resulting constraint expressions in *RESULTS. */
static void
get_constraint_for_ptr_offset (tree ptr, tree offset,
VEC (ce_s, heap) **results)
{
struct constraint_expr *c;
unsigned int j, n;
unsigned HOST_WIDE_INT rhsunitoffset, rhsoffset;
/* If we do not do field-sensitive PTA adding offsets to pointers
does not change the points-to solution. */
if (!use_field_sensitive)
{
get_constraint_for (ptr, results);
return;
}
/* If the offset is not a non-negative integer constant that fits
in a HOST_WIDE_INT, we have to fall back to a conservative
solution which includes all sub-fields of all pointed-to
variables of ptr.
??? As we do not have the ability to express this, fall back
to anything. */
if (!host_integerp (offset, 1))
{
struct constraint_expr temp;
temp.var = anything_id;
temp.type = SCALAR;
temp.offset = 0;
VEC_safe_push (ce_s, heap, *results, &temp);
return;
}
/* Make sure the bit-offset also fits. */
rhsunitoffset = TREE_INT_CST_LOW (offset);
rhsoffset = rhsunitoffset * BITS_PER_UNIT;
if (rhsunitoffset != rhsoffset / BITS_PER_UNIT)
{
struct constraint_expr temp;
temp.var = anything_id;
temp.type = SCALAR;
temp.offset = 0;
VEC_safe_push (ce_s, heap, *results, &temp);
return;
}
get_constraint_for (ptr, results);
if (rhsoffset == 0)
return;
/* As we are eventually appending to the solution do not use
VEC_iterate here. */
n = VEC_length (ce_s, *results);
for (j = 0; j < n; j++)
{
varinfo_t curr;
c = VEC_index (ce_s, *results, j);
curr = get_varinfo (c->var);
if (c->type == ADDRESSOF
&& !curr->is_full_var)
{
varinfo_t temp, curr = get_varinfo (c->var);
/* Search the sub-field which overlaps with the
pointed-to offset. As we deal with positive offsets
only, we can start the search from the current variable. */
temp = first_vi_for_offset (curr, curr->offset + rhsoffset);
/* If the result is outside of the variable we have to provide
a conservative result, as the variable is still reachable
from the resulting pointer (even though it technically
cannot point to anything). The last sub-field is such
a conservative result.
??? If we always had a sub-field for &object + 1 then
we could represent this in a more precise way. */
if (temp == NULL)
{
temp = curr;
while (temp->next != NULL)
temp = temp->next;
continue;
}
/* If the found variable is not exactly at the pointed to
result, we have to include the next variable in the
solution as well. Otherwise two increments by offset / 2
do not result in the same or a conservative superset
solution. */
if (temp->offset != curr->offset + rhsoffset
&& temp->next != NULL)
{
struct constraint_expr c2;
c2.var = temp->next->id;
c2.type = ADDRESSOF;
c2.offset = 0;
VEC_safe_push (ce_s, heap, *results, &c2);
}
c->var = temp->id;
c->offset = 0;
}
else if (c->type == ADDRESSOF
/* If this varinfo represents a full variable just use it. */
&& curr->is_full_var)
c->offset = 0;
else
c->offset = rhsoffset;
}
}
/* Given a COMPONENT_REF T, return the constraint_expr vector for it. /* Given a COMPONENT_REF T, return the constraint_expr vector for it.
If address_p is true the result will be taken its address of. */ If address_p is true the result will be taken its address of. */
...@@ -2714,15 +2847,18 @@ get_constraint_for_component_ref (tree t, VEC(ce_s, heap) **results, ...@@ -2714,15 +2847,18 @@ get_constraint_for_component_ref (tree t, VEC(ce_s, heap) **results,
/* Pretend to take the address of the base, we'll take care of /* Pretend to take the address of the base, we'll take care of
adding the required subset of sub-fields below. */ adding the required subset of sub-fields below. */
get_constraint_for_1 (t, results, true); get_constraint_for_1 (t, results, true);
result = VEC_last (ce_s, *results);
gcc_assert (VEC_length (ce_s, *results) == 1); gcc_assert (VEC_length (ce_s, *results) == 1);
result = VEC_last (ce_s, *results);
/* This can also happen due to weird offsetof type macros. */ /* This can also happen due to weird offsetof type macros. */
if (TREE_CODE (t) != ADDR_EXPR && result->type == ADDRESSOF) if (TREE_CODE (t) != ADDR_EXPR && result->type == ADDRESSOF)
result->type = SCALAR; result->type = SCALAR;
if (result->type == SCALAR) if (result->type == SCALAR
&& get_varinfo (result->var)->is_full_var)
/* For single-field vars do not bother about the offset. */
result->offset = 0;
else if (result->type == SCALAR)
{ {
/* In languages like C, you can access one past the end of an /* In languages like C, you can access one past the end of an
array. You aren't allowed to dereference it, so we can array. You aren't allowed to dereference it, so we can
...@@ -2751,12 +2887,25 @@ get_constraint_for_component_ref (tree t, VEC(ce_s, heap) **results, ...@@ -2751,12 +2887,25 @@ get_constraint_for_component_ref (tree t, VEC(ce_s, heap) **results,
break; break;
} }
} }
/* assert that we found *some* field there. The user couldn't be /* If we are going to take the address of this field then
accessing *only* padding. */ to be able to compute reachability correctly add at least
/* Still the user could access one past the end of an array the last field of the variable. */
embedded in a struct resulting in accessing *only* padding. */ if (address_p
gcc_assert (VEC_length (ce_s, *results) >= 1 && VEC_length (ce_s, *results) == 0)
|| ref_contains_array_ref (orig_t)); {
curr = get_varinfo (cexpr.var);
while (curr->next != NULL)
curr = curr->next;
cexpr.var = curr->id;
VEC_safe_push (ce_s, heap, *results, &cexpr);
}
else
/* Assert that we found *some* field there. The user couldn't be
accessing *only* padding. */
/* Still the user could access one past the end of an array
embedded in a struct resulting in accessing *only* padding. */
gcc_assert (VEC_length (ce_s, *results) >= 1
|| ref_contains_array_ref (orig_t));
} }
else if (bitmaxsize == 0) else if (bitmaxsize == 0)
{ {
...@@ -2900,24 +3049,10 @@ get_constraint_for_1 (tree t, VEC (ce_s, heap) **results, bool address_p) ...@@ -2900,24 +3049,10 @@ get_constraint_for_1 (tree t, VEC (ce_s, heap) **results, bool address_p)
VEC_safe_push (ce_s, heap, *results, &temp); VEC_safe_push (ce_s, heap, *results, &temp);
return; return;
} }
else
{
temp.var = anything_id;
temp.type = SCALAR;
temp.offset = 0;
VEC_safe_push (ce_s, heap, *results, &temp);
return;
}
break; break;
default: default:;
{
temp.type = ADDRESSOF;
temp.var = anything_id;
temp.offset = 0;
VEC_safe_push (ce_s, heap, *results, &temp);
return;
}
} }
break;
} }
case tcc_reference: case tcc_reference:
{ {
...@@ -2934,15 +3069,9 @@ get_constraint_for_1 (tree t, VEC (ce_s, heap) **results, bool address_p) ...@@ -2934,15 +3069,9 @@ get_constraint_for_1 (tree t, VEC (ce_s, heap) **results, bool address_p)
case COMPONENT_REF: case COMPONENT_REF:
get_constraint_for_component_ref (t, results, address_p); get_constraint_for_component_ref (t, results, address_p);
return; return;
default: default:;
{
temp.type = ADDRESSOF;
temp.var = anything_id;
temp.offset = 0;
VEC_safe_push (ce_s, heap, *results, &temp);
return;
}
} }
break;
} }
case tcc_unary: case tcc_unary:
{ {
...@@ -2963,15 +3092,19 @@ get_constraint_for_1 (tree t, VEC (ce_s, heap) **results, bool address_p) ...@@ -2963,15 +3092,19 @@ get_constraint_for_1 (tree t, VEC (ce_s, heap) **results, bool address_p)
/* FALLTHRU */ /* FALLTHRU */
} }
default: default:;
{
temp.type = ADDRESSOF;
temp.var = anything_id;
temp.offset = 0;
VEC_safe_push (ce_s, heap, *results, &temp);
return;
}
} }
break;
}
case tcc_binary:
{
if (TREE_CODE (t) == POINTER_PLUS_EXPR)
{
get_constraint_for_ptr_offset (TREE_OPERAND (t, 0),
TREE_OPERAND (t, 1), results);
return;
}
break;
} }
case tcc_exceptional: case tcc_exceptional:
{ {
...@@ -2982,37 +3115,28 @@ get_constraint_for_1 (tree t, VEC (ce_s, heap) **results, bool address_p) ...@@ -2982,37 +3115,28 @@ get_constraint_for_1 (tree t, VEC (ce_s, heap) **results, bool address_p)
get_constraint_for_1 (PHI_RESULT (t), results, address_p); get_constraint_for_1 (PHI_RESULT (t), results, address_p);
return; return;
} }
break;
case SSA_NAME: case SSA_NAME:
{ {
get_constraint_for_ssa_var (t, results, address_p); get_constraint_for_ssa_var (t, results, address_p);
return; return;
} }
break; default:;
default:
{
temp.type = ADDRESSOF;
temp.var = anything_id;
temp.offset = 0;
VEC_safe_push (ce_s, heap, *results, &temp);
return;
}
} }
break;
} }
case tcc_declaration: case tcc_declaration:
{ {
get_constraint_for_ssa_var (t, results, address_p); get_constraint_for_ssa_var (t, results, address_p);
return; return;
} }
default: default:;
{
temp.type = ADDRESSOF;
temp.var = anything_id;
temp.offset = 0;
VEC_safe_push (ce_s, heap, *results, &temp);
return;
}
} }
/* The default fallback is a constraint from anything. */
temp.type = ADDRESSOF;
temp.var = anything_id;
temp.offset = 0;
VEC_safe_push (ce_s, heap, *results, &temp);
} }
/* Given a gimple tree T, return the constraint expression vector for it. */ /* Given a gimple tree T, return the constraint expression vector for it. */
...@@ -3298,80 +3422,6 @@ do_structure_copy (tree lhsop, tree rhsop) ...@@ -3298,80 +3422,6 @@ do_structure_copy (tree lhsop, tree rhsop)
} }
} }
/* Handle pointer arithmetic EXPR when creating aliasing constraints.
Expressions of the type PTR + CST can be handled in two ways:
1- If the constraint for PTR is ADDRESSOF for a non-structure
variable, then we can use it directly because adding or
subtracting a constant may not alter the original ADDRESSOF
constraint (i.e., pointer arithmetic may not legally go outside
an object's boundaries).
2- If the constraint for PTR is ADDRESSOF for a structure variable,
then if CST is a compile-time constant that can be used as an
offset, we can determine which sub-variable will be pointed-to
by the expression.
Return true if the expression is handled. For any other kind of
expression, return false so that each operand can be added as a
separate constraint by the caller. */
static bool
handle_ptr_arith (VEC (ce_s, heap) *lhsc, tree expr)
{
tree op0, op1;
struct constraint_expr *c, *c2;
unsigned int i = 0;
unsigned int j = 0;
VEC (ce_s, heap) *temp = NULL;
unsigned HOST_WIDE_INT rhsunitoffset, rhsoffset;
if (TREE_CODE (expr) != POINTER_PLUS_EXPR)
return false;
op0 = TREE_OPERAND (expr, 0);
op1 = TREE_OPERAND (expr, 1);
gcc_assert (POINTER_TYPE_P (TREE_TYPE (op0)));
/* If the offset is not a non-negative integer constant that fits
in a HOST_WIDE_INT, we cannot handle it here. */
if (!host_integerp (op1, 1))
return false;
/* Make sure the bit-offset also fits. */
rhsunitoffset = TREE_INT_CST_LOW (op1);
rhsoffset = rhsunitoffset * BITS_PER_UNIT;
if (rhsunitoffset != rhsoffset / BITS_PER_UNIT)
return false;
get_constraint_for (op0, &temp);
for (i = 0; VEC_iterate (ce_s, lhsc, i, c); i++)
for (j = 0; VEC_iterate (ce_s, temp, j, c2); j++)
{
if (c2->type == ADDRESSOF && rhsoffset != 0)
{
varinfo_t temp = get_varinfo (c2->var);
/* An access one after the end of an array is valid,
so simply punt on accesses we cannot resolve. */
temp = first_vi_for_offset (temp, rhsoffset);
if (temp == NULL)
continue;
c2->var = temp->id;
c2->offset = 0;
}
else
c2->offset = rhsoffset;
process_constraint (new_constraint (*c, *c2));
}
VEC_free (ce_s, heap, temp);
return true;
}
/* Create a constraint ID = OP. */ /* Create a constraint ID = OP. */
static void static void
...@@ -3771,89 +3821,29 @@ find_func_aliases (tree origt) ...@@ -3771,89 +3821,29 @@ find_func_aliases (tree origt)
} }
} }
} }
/* Otherwise, just a regular assignment statement. */ /* Otherwise, just a regular assignment statement. Only care about
else if (TREE_CODE (t) == GIMPLE_MODIFY_STMT) operations with pointer result, others are dealt with as escape
points if they have pointer operands. */
else if (TREE_CODE (t) == GIMPLE_MODIFY_STMT
&& could_have_pointers (GIMPLE_STMT_OPERAND (t, 0)))
{ {
tree lhsop = GIMPLE_STMT_OPERAND (t, 0); tree lhsop = GIMPLE_STMT_OPERAND (t, 0);
tree rhsop = GIMPLE_STMT_OPERAND (t, 1); tree rhsop = GIMPLE_STMT_OPERAND (t, 1);
int i;
if (AGGREGATE_TYPE_P (TREE_TYPE (lhsop)) if (AGGREGATE_TYPE_P (TREE_TYPE (lhsop)))
&& AGGREGATE_TYPE_P (TREE_TYPE (rhsop))) do_structure_copy (lhsop, rhsop);
{
do_structure_copy (lhsop, rhsop);
}
else else
{ {
/* Only care about operations with pointers, structures unsigned int j;
containing pointers, dereferences, and call expressions. */ get_constraint_for (lhsop, &lhsc);
if (could_have_pointers (lhsop) get_constraint_for (rhsop, &rhsc);
|| TREE_CODE (rhsop) == CALL_EXPR) for (j = 0; VEC_iterate (ce_s, lhsc, j, c); j++)
{ {
get_constraint_for (lhsop, &lhsc); struct constraint_expr *c2;
switch (TREE_CODE_CLASS (TREE_CODE (rhsop))) unsigned int k;
{
/* RHS that consist of unary operations,
exceptional types, or bare decls/constants, get
handled directly by get_constraint_for. */
case tcc_reference:
case tcc_declaration:
case tcc_constant:
case tcc_exceptional:
case tcc_expression:
case tcc_vl_exp:
case tcc_unary:
{
unsigned int j;
get_constraint_for (rhsop, &rhsc);
for (j = 0; VEC_iterate (ce_s, lhsc, j, c); j++)
{
struct constraint_expr *c2;
unsigned int k;
for (k = 0; VEC_iterate (ce_s, rhsc, k, c2); k++)
process_constraint (new_constraint (*c, *c2));
}
}
break;
case tcc_binary: for (k = 0; VEC_iterate (ce_s, rhsc, k, c2); k++)
{ process_constraint (new_constraint (*c, *c2));
/* For pointer arithmetic of the form
PTR + CST, we can simply use PTR's
constraint because pointer arithmetic is
not allowed to go out of bounds. */
if (handle_ptr_arith (lhsc, rhsop))
break;
}
/* FALLTHRU */
/* Otherwise, walk each operand. Notice that we
can't use the operand interface because we need
to process expressions other than simple operands
(e.g. INDIRECT_REF, ADDR_EXPR, CALL_EXPR). */
default:
for (i = 0; i < TREE_OPERAND_LENGTH (rhsop); i++)
{
tree op = TREE_OPERAND (rhsop, i);
unsigned int j;
gcc_assert (VEC_length (ce_s, rhsc) == 0);
get_constraint_for (op, &rhsc);
for (j = 0; VEC_iterate (ce_s, lhsc, j, c); j++)
{
struct constraint_expr *c2;
while (VEC_length (ce_s, rhsc) > 0)
{
c2 = VEC_last (ce_s, rhsc);
process_constraint (new_constraint (*c, *c2));
VEC_pop (ce_s, rhsc);
}
}
}
}
} }
} }
} }
...@@ -4222,8 +4212,7 @@ create_function_info_for (tree decl, const char *name) ...@@ -4222,8 +4212,7 @@ create_function_info_for (tree decl, const char *name)
stats.total_vars++; stats.total_vars++;
/* If it's varargs, we don't know how many arguments it has, so we /* If it's varargs, we don't know how many arguments it has, so we
can't do much. can't do much. */
*/
if (is_varargs) if (is_varargs)
{ {
vi->fullsize = ~0; vi->fullsize = ~0;
...@@ -4257,6 +4246,7 @@ create_function_info_for (tree decl, const char *name) ...@@ -4257,6 +4246,7 @@ create_function_info_for (tree decl, const char *name)
VEC_safe_push (varinfo_t, heap, varmap, argvi); VEC_safe_push (varinfo_t, heap, varmap, argvi);
argvi->offset = i; argvi->offset = i;
argvi->size = 1; argvi->size = 1;
argvi->is_full_var = true;
argvi->fullsize = vi->fullsize; argvi->fullsize = vi->fullsize;
insert_into_field_list_sorted (vi, argvi); insert_into_field_list_sorted (vi, argvi);
stats.total_vars ++; stats.total_vars ++;
...@@ -4293,6 +4283,7 @@ create_function_info_for (tree decl, const char *name) ...@@ -4293,6 +4283,7 @@ create_function_info_for (tree decl, const char *name)
resultvi->offset = i; resultvi->offset = i;
resultvi->size = 1; resultvi->size = 1;
resultvi->fullsize = vi->fullsize; resultvi->fullsize = vi->fullsize;
resultvi->is_full_var = true;
insert_into_field_list_sorted (vi, resultvi); insert_into_field_list_sorted (vi, resultvi);
stats.total_vars ++; stats.total_vars ++;
if (DECL_RESULT (decl)) if (DECL_RESULT (decl))
...@@ -4411,6 +4402,7 @@ create_variable_info_for (tree decl, const char *name) ...@@ -4411,6 +4402,7 @@ create_variable_info_for (tree decl, const char *name)
vi->is_unknown_size_var = 1; vi->is_unknown_size_var = 1;
vi->fullsize = ~0; vi->fullsize = ~0;
vi->size = ~0; vi->size = ~0;
vi->is_full_var = true;
VEC_free (fieldoff_s, heap, fieldstack); VEC_free (fieldoff_s, heap, fieldstack);
return index; return index;
} }
...@@ -4447,6 +4439,8 @@ create_variable_info_for (tree decl, const char *name) ...@@ -4447,6 +4439,8 @@ create_variable_info_for (tree decl, const char *name)
stats.total_vars++; stats.total_vars++;
} }
} }
else
vi->is_full_var = true;
VEC_free (fieldoff_s, heap, fieldstack); VEC_free (fieldoff_s, heap, fieldstack);
...@@ -5198,6 +5192,8 @@ init_base_vars (void) ...@@ -5198,6 +5192,8 @@ init_base_vars (void)
static void static void
init_alias_vars (void) init_alias_vars (void)
{ {
use_field_sensitive = (MAX_FIELDS_FOR_FIELD_SENSITIVE > 1);
bitmap_obstack_initialize (&pta_obstack); bitmap_obstack_initialize (&pta_obstack);
bitmap_obstack_initialize (&oldpta_obstack); bitmap_obstack_initialize (&oldpta_obstack);
bitmap_obstack_initialize (&predbitmap_obstack); bitmap_obstack_initialize (&predbitmap_obstack);
......
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