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
This commit is contained in:
parent
77092cda69
commit
e5bae89b99
@ -1,3 +1,26 @@
|
||||
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
|
||||
|
@ -1,3 +1,9 @@
|
||||
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>
|
||||
|
||||
PR middle-end/36726
|
||||
|
40
gcc/testsuite/gcc.dg/torture/ipa-pta-1.c
Normal file
40
gcc/testsuite/gcc.dg/torture/ipa-pta-1.c
Normal file
@ -0,0 +1,40 @@
|
||||
/* { 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" } } */
|
33
gcc/testsuite/gcc.dg/torture/pta-ptrarith-1.c
Normal file
33
gcc/testsuite/gcc.dg/torture/pta-ptrarith-1.c
Normal file
@ -0,0 +1,33 @@
|
||||
/* { 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" } } */
|
36
gcc/testsuite/gcc.dg/torture/pta-ptrarith-2.c
Normal file
36
gcc/testsuite/gcc.dg/torture/pta-ptrarith-2.c
Normal file
@ -0,0 +1,36 @@
|
||||
/* { 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
|
||||
/* True for variables whose size is not known or variable. */
|
||||
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. */
|
||||
unsigned int is_heap_var:1;
|
||||
|
||||
@ -373,6 +376,7 @@ new_var_info (tree t, unsigned int id, const char *name)
|
||||
ret->is_heap_var = false;
|
||||
ret->is_special_var = false;
|
||||
ret->is_unknown_size_var = false;
|
||||
ret->is_full_var = false;
|
||||
var = t;
|
||||
if (TREE_CODE (var) == SSA_NAME)
|
||||
var = SSA_NAME_VAR (var);
|
||||
@ -752,22 +756,32 @@ solution_set_add (bitmap set, unsigned HOST_WIDE_INT offset)
|
||||
|
||||
EXECUTE_IF_SET_IN_BITMAP (set, 0, i, bi)
|
||||
{
|
||||
/* If this is a properly sized variable, only add offset if it's
|
||||
less than end. Otherwise, it is globbed to a single
|
||||
variable. */
|
||||
varinfo_t vi = get_varinfo (i);
|
||||
|
||||
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;
|
||||
varinfo_t v = first_vi_for_offset (get_varinfo (i), fieldoffset);
|
||||
unsigned HOST_WIDE_INT fieldoffset = vi->offset + offset;
|
||||
varinfo_t v = first_vi_for_offset (vi, fieldoffset);
|
||||
/* If the result is outside of the variable use the last field. */
|
||||
if (!v)
|
||||
continue;
|
||||
{
|
||||
v = vi;
|
||||
while (v->next != NULL)
|
||||
v = v->next;
|
||||
}
|
||||
bitmap_set_bit (result, v->id);
|
||||
}
|
||||
else if (get_varinfo (i)->is_artificial_var
|
||||
|| get_varinfo (i)->is_unknown_size_var)
|
||||
{
|
||||
bitmap_set_bit (result, i);
|
||||
/* If the result is not exactly at fieldoffset include the next
|
||||
field as well. See get_constraint_for_ptr_offset for more
|
||||
rationale. */
|
||||
if (v->offset != fieldoffset
|
||||
&& v->next != NULL)
|
||||
bitmap_set_bit (result, v->next->id);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1375,7 +1389,8 @@ type_safe (unsigned int n, unsigned HOST_WIDE_INT *offset)
|
||||
0. */
|
||||
if (ninfo->is_special_var
|
||||
|| ninfo->is_artificial_var
|
||||
|| ninfo->is_unknown_size_var)
|
||||
|| ninfo->is_unknown_size_var
|
||||
|| ninfo->is_full_var)
|
||||
{
|
||||
*offset = 0;
|
||||
return true;
|
||||
@ -1415,7 +1430,11 @@ do_sd_constraint (constraint_graph_t graph, constraint_t c,
|
||||
sub-fields off. This avoids quadratic behavior. */
|
||||
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 (vars == NULL)
|
||||
@ -1455,6 +1474,7 @@ do_sd_constraint (constraint_graph_t graph, constraint_t c,
|
||||
unsigned int t;
|
||||
|
||||
v = first_vi_for_offset (get_varinfo (j), fieldoffset);
|
||||
/* If the access is outside of the variable we can ignore it. */
|
||||
if (!v)
|
||||
continue;
|
||||
t = find (v->id);
|
||||
@ -1507,9 +1527,14 @@ do_ds_constraint (constraint_t c, bitmap delta)
|
||||
unsigned HOST_WIDE_INT fieldoffset = jvi->offset + loff;
|
||||
varinfo_t v;
|
||||
|
||||
v = first_vi_for_offset (get_varinfo (j), fieldoffset);
|
||||
if (!v)
|
||||
continue;
|
||||
v = get_varinfo (j);
|
||||
if (!v->is_full_var)
|
||||
{
|
||||
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);
|
||||
|
||||
if (bitmap_set_bit (get_varinfo (t)->solution, anything_id)
|
||||
@ -1535,6 +1560,7 @@ do_ds_constraint (constraint_t c, bitmap delta)
|
||||
bitmap tmp;
|
||||
|
||||
v = first_vi_for_offset (get_varinfo (j), fieldoffset);
|
||||
/* If the access is outside of the variable we can ignore it. */
|
||||
if (!v)
|
||||
continue;
|
||||
t = find (v->id);
|
||||
@ -2597,12 +2623,6 @@ process_constraint (constraint_t t)
|
||||
gcc_assert (rhs.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. */
|
||||
if (lhs.var == anything_id && rhs.var == anything_id)
|
||||
return;
|
||||
@ -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.
|
||||
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,
|
||||
/* Pretend to take the address of the base, we'll take care of
|
||||
adding the required subset of sub-fields below. */
|
||||
get_constraint_for_1 (t, results, true);
|
||||
result = VEC_last (ce_s, *results);
|
||||
|
||||
gcc_assert (VEC_length (ce_s, *results) == 1);
|
||||
result = VEC_last (ce_s, *results);
|
||||
|
||||
/* This can also happen due to weird offsetof type macros. */
|
||||
if (TREE_CODE (t) != ADDR_EXPR && result->type == ADDRESSOF)
|
||||
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
|
||||
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,
|
||||
break;
|
||||
}
|
||||
}
|
||||
/* 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));
|
||||
/* If we are going to take the address of this field then
|
||||
to be able to compute reachability correctly add at least
|
||||
the last field of the variable. */
|
||||
if (address_p
|
||||
&& VEC_length (ce_s, *results) == 0)
|
||||
{
|
||||
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)
|
||||
{
|
||||
@ -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);
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
temp.var = anything_id;
|
||||
temp.type = SCALAR;
|
||||
temp.offset = 0;
|
||||
VEC_safe_push (ce_s, heap, *results, &temp);
|
||||
return;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
{
|
||||
temp.type = ADDRESSOF;
|
||||
temp.var = anything_id;
|
||||
temp.offset = 0;
|
||||
VEC_safe_push (ce_s, heap, *results, &temp);
|
||||
return;
|
||||
}
|
||||
default:;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case tcc_reference:
|
||||
{
|
||||
@ -2934,15 +3069,9 @@ get_constraint_for_1 (tree t, VEC (ce_s, heap) **results, bool address_p)
|
||||
case COMPONENT_REF:
|
||||
get_constraint_for_component_ref (t, results, address_p);
|
||||
return;
|
||||
default:
|
||||
{
|
||||
temp.type = ADDRESSOF;
|
||||
temp.var = anything_id;
|
||||
temp.offset = 0;
|
||||
VEC_safe_push (ce_s, heap, *results, &temp);
|
||||
return;
|
||||
}
|
||||
default:;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case tcc_unary:
|
||||
{
|
||||
@ -2963,15 +3092,19 @@ get_constraint_for_1 (tree t, VEC (ce_s, heap) **results, bool address_p)
|
||||
|
||||
/* FALLTHRU */
|
||||
}
|
||||
default:
|
||||
{
|
||||
temp.type = ADDRESSOF;
|
||||
temp.var = anything_id;
|
||||
temp.offset = 0;
|
||||
VEC_safe_push (ce_s, heap, *results, &temp);
|
||||
return;
|
||||
}
|
||||
default:;
|
||||
}
|
||||
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:
|
||||
{
|
||||
@ -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);
|
||||
return;
|
||||
}
|
||||
break;
|
||||
case SSA_NAME:
|
||||
{
|
||||
get_constraint_for_ssa_var (t, results, address_p);
|
||||
return;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
{
|
||||
temp.type = ADDRESSOF;
|
||||
temp.var = anything_id;
|
||||
temp.offset = 0;
|
||||
VEC_safe_push (ce_s, heap, *results, &temp);
|
||||
return;
|
||||
}
|
||||
default:;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case tcc_declaration:
|
||||
{
|
||||
get_constraint_for_ssa_var (t, results, address_p);
|
||||
return;
|
||||
}
|
||||
default:
|
||||
{
|
||||
temp.type = ADDRESSOF;
|
||||
temp.var = anything_id;
|
||||
temp.offset = 0;
|
||||
VEC_safe_push (ce_s, heap, *results, &temp);
|
||||
return;
|
||||
}
|
||||
default:;
|
||||
}
|
||||
|
||||
/* 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. */
|
||||
@ -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. */
|
||||
|
||||
static void
|
||||
@ -3771,89 +3821,29 @@ find_func_aliases (tree origt)
|
||||
}
|
||||
}
|
||||
}
|
||||
/* Otherwise, just a regular assignment statement. */
|
||||
else if (TREE_CODE (t) == GIMPLE_MODIFY_STMT)
|
||||
/* Otherwise, just a regular assignment statement. Only care about
|
||||
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 rhsop = GIMPLE_STMT_OPERAND (t, 1);
|
||||
int i;
|
||||
|
||||
if (AGGREGATE_TYPE_P (TREE_TYPE (lhsop))
|
||||
&& AGGREGATE_TYPE_P (TREE_TYPE (rhsop)))
|
||||
{
|
||||
do_structure_copy (lhsop, rhsop);
|
||||
}
|
||||
if (AGGREGATE_TYPE_P (TREE_TYPE (lhsop)))
|
||||
do_structure_copy (lhsop, rhsop);
|
||||
else
|
||||
{
|
||||
/* Only care about operations with pointers, structures
|
||||
containing pointers, dereferences, and call expressions. */
|
||||
if (could_have_pointers (lhsop)
|
||||
|| TREE_CODE (rhsop) == CALL_EXPR)
|
||||
unsigned int j;
|
||||
get_constraint_for (lhsop, &lhsc);
|
||||
get_constraint_for (rhsop, &rhsc);
|
||||
for (j = 0; VEC_iterate (ce_s, lhsc, j, c); j++)
|
||||
{
|
||||
get_constraint_for (lhsop, &lhsc);
|
||||
switch (TREE_CODE_CLASS (TREE_CODE (rhsop)))
|
||||
{
|
||||
/* 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;
|
||||
struct constraint_expr *c2;
|
||||
unsigned int k;
|
||||
|
||||
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 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
for (k = 0; VEC_iterate (ce_s, rhsc, k, c2); k++)
|
||||
process_constraint (new_constraint (*c, *c2));
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -4222,8 +4212,7 @@ create_function_info_for (tree decl, const char *name)
|
||||
stats.total_vars++;
|
||||
|
||||
/* 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)
|
||||
{
|
||||
vi->fullsize = ~0;
|
||||
@ -4257,6 +4246,7 @@ create_function_info_for (tree decl, const char *name)
|
||||
VEC_safe_push (varinfo_t, heap, varmap, argvi);
|
||||
argvi->offset = i;
|
||||
argvi->size = 1;
|
||||
argvi->is_full_var = true;
|
||||
argvi->fullsize = vi->fullsize;
|
||||
insert_into_field_list_sorted (vi, argvi);
|
||||
stats.total_vars ++;
|
||||
@ -4293,6 +4283,7 @@ create_function_info_for (tree decl, const char *name)
|
||||
resultvi->offset = i;
|
||||
resultvi->size = 1;
|
||||
resultvi->fullsize = vi->fullsize;
|
||||
resultvi->is_full_var = true;
|
||||
insert_into_field_list_sorted (vi, resultvi);
|
||||
stats.total_vars ++;
|
||||
if (DECL_RESULT (decl))
|
||||
@ -4411,6 +4402,7 @@ create_variable_info_for (tree decl, const char *name)
|
||||
vi->is_unknown_size_var = 1;
|
||||
vi->fullsize = ~0;
|
||||
vi->size = ~0;
|
||||
vi->is_full_var = true;
|
||||
VEC_free (fieldoff_s, heap, fieldstack);
|
||||
return index;
|
||||
}
|
||||
@ -4447,6 +4439,8 @@ create_variable_info_for (tree decl, const char *name)
|
||||
stats.total_vars++;
|
||||
}
|
||||
}
|
||||
else
|
||||
vi->is_full_var = true;
|
||||
|
||||
VEC_free (fieldoff_s, heap, fieldstack);
|
||||
|
||||
@ -5198,6 +5192,8 @@ init_base_vars (void)
|
||||
static void
|
||||
init_alias_vars (void)
|
||||
{
|
||||
use_field_sensitive = (MAX_FIELDS_FOR_FIELD_SENSITIVE > 1);
|
||||
|
||||
bitmap_obstack_initialize (&pta_obstack);
|
||||
bitmap_obstack_initialize (&oldpta_obstack);
|
||||
bitmap_obstack_initialize (&predbitmap_obstack);
|
||||
|
Loading…
Reference in New Issue
Block a user