Commit 74d27244 by Richard Guenther Committed by Richard Biener

re PR middle-end/14187 ([tree-ssa] C restricted pointers are not properly implemented)

2009-06-29  Richard Guenther  <rguenther@suse.de>

	PR middle-end/14187
	* tree-ssa-alias.h (struct pt_solution): Add vars_contains_restrict
	flag.
	(pt_solutions_same_restrict_base): Declare.
	* tree-ssa-structalias.c (struct variable_info): Add is_restrict_var
	flag.
	(new_var_info): Initialize is_global_var properly for SSA_NAMEs.
	(make_constraint_from, make_copy_constraint): Move earlier.
	(make_constraint_from_heapvar): New function.
	(make_constraint_from_restrict): Likewise.
	(handle_lhs_call): Use it.
	(find_func_aliases): Use it to track conversions to restrict
	qualified pointers.
	(struct fieldoff): Add only_restrict_pointers flag.
	(push_fields_onto_fieldstack): Initialize it.
	(create_variable_info_for): Track global restrict qualified pointers.
	(intra_create_variable_infos): Use make_constraint_from_heapvar.
	Track restrict qualified pointer arguments.
	(set_uids_in_ptset): Use varinfo is_global_var flag.
	(find_what_var_points_to): Set the vars_contains_restrict flag.
	Always create the points-to solution for sets including restrict tags.
	(pt_solutions_same_restrict_base): New function.
	* tree-ssa-alias.c (ptr_derefs_may_alias_p): For two restrict
	qualified pointers use pt_solutions_same_restrict_base as
	additional source for disambiguation.

	* gcc.dg/tree-ssa/restrict-1.c: New testcase.
	* gcc.dg/tree-ssa/restrict-2.c: Likewise.
	* gcc.dg/tree-ssa/restrict-3.c: Likewise.
	* gcc.c-torture/execute/20090623-1.c: Likewise.
	* gcc.dg/tree-ssa/ldist-13.c: Likewise.
	* gcc.dg/tree-ssa/ldist-14.c: Likewise.

From-SVN: r149048
parent 5b21f0f3
2009-06-29 Richard Guenther <rguenther@suse.de> 2009-06-29 Richard Guenther <rguenther@suse.de>
PR middle-end/14187
* tree-ssa-alias.h (struct pt_solution): Add vars_contains_restrict
flag.
(pt_solutions_same_restrict_base): Declare.
* tree-ssa-structalias.c (struct variable_info): Add is_restrict_var
flag.
(new_var_info): Initialize is_global_var properly for SSA_NAMEs.
(make_constraint_from, make_copy_constraint): Move earlier.
(make_constraint_from_heapvar): New function.
(make_constraint_from_restrict): Likewise.
(handle_lhs_call): Use it.
(find_func_aliases): Use it to track conversions to restrict
qualified pointers.
(struct fieldoff): Add only_restrict_pointers flag.
(push_fields_onto_fieldstack): Initialize it.
(create_variable_info_for): Track global restrict qualified pointers.
(intra_create_variable_infos): Use make_constraint_from_heapvar.
Track restrict qualified pointer arguments.
(set_uids_in_ptset): Use varinfo is_global_var flag.
(find_what_var_points_to): Set the vars_contains_restrict flag.
Always create the points-to solution for sets including restrict tags.
(pt_solutions_same_restrict_base): New function.
* tree-ssa-alias.c (ptr_derefs_may_alias_p): For two restrict
qualified pointers use pt_solutions_same_restrict_base as
additional source for disambiguation.
2009-06-29 Richard Guenther <rguenther@suse.de>
PR middle-end/38212 PR middle-end/38212
* alias.c (find_base_decl): Remove. * alias.c (find_base_decl): Remove.
(get_deref_alias_set_1): Remove restrict handling. (get_deref_alias_set_1): Remove restrict handling.
......
2009-06-29 Richard Guenther <rguenther@suse.de> 2009-06-29 Richard Guenther <rguenther@suse.de>
PR middle-end/14187
* gcc.dg/tree-ssa/restrict-1.c: New testcase.
* gcc.dg/tree-ssa/restrict-2.c: Likewise.
* gcc.dg/tree-ssa/restrict-3.c: Likewise.
* gcc.c-torture/execute/20090623-1.c: Likewise.
* gcc.dg/tree-ssa/ldist-13.c: Likewise.
* gcc.dg/tree-ssa/ldist-14.c: Likewise.
2009-06-29 Richard Guenther <rguenther@suse.de>
PR middle-end/38212 PR middle-end/38212
* gcc.c-torture/execute/pr38212.c: New testcase. * gcc.c-torture/execute/pr38212.c: New testcase.
......
int * __restrict__ x;
int foo (int y)
{
*x = y;
return *x;
}
extern void abort (void);
int main()
{
int i = 0;
x = &i;
if (foo(1) != 1)
abort ();
return 0;
}
/* { dg-do compile } */
/* { dg-options "-O2 -ftree-loop-distribution -fdump-tree-ldist-details" } */
float * __restrict__ x;
float * __restrict__ y;
float foo (int n)
{
int i;
float tmp = 0.0;
for (i = 0; i < n; ++i)
{
x[i] = 0.0;
tmp += y[i];
}
return tmp;
}
/* We should apply loop distribution. */
/* { dg-final { scan-tree-dump "Loop 1 distributed: split to 2 loops" "ldist" } } */
/* { dg-final { cleanup-tree-dump "ldist" } } */
/* { dg-do compile } */
/* { dg-options "-O2 -fno-strict-aliasing -ftree-loop-distribution -fdump-tree-ldist-details" } */
struct desc {
int i;
void * __restrict__ data;
int j;
} a, b;
float foo (int n)
{
int i;
float * __restrict__ x, * __restrict__ y, tmp = 0.0;
x = (float * __restrict__)a.data;
y = (float * __restrict__)b.data;
for (i = 0; i < n; ++i)
{
x[i] = 0.0;
tmp += y[i];
}
return tmp;
}
/* We should apply loop distribution. */
/* { dg-final { scan-tree-dump "Loop 1 distributed: split to 2 loops" "ldist" } } */
/* { dg-final { cleanup-tree-dump "ldist" } } */
/* { dg-do link } */
/* { dg-options "-O -fno-strict-aliasing -fdump-tree-optimized" } */
extern void link_error (void);
void bar0 (int * __restrict__ arr1, int * __restrict__ arr2)
{
arr1[0] = 1;
arr2[0] = 1;
if (arr1[0] != 1)
link_error ();
}
int main()
{
return 0;
}
/* { dg-final { scan-tree-dump-not "link_error" "optimized" } } */
/* { dg-final { cleanup-tree-dump "optimized" } } */
/* { dg-do compile } */
/* { dg-options "-O -fno-strict-aliasing -fdump-tree-lim-details" } */
void foo (float * __restrict__ a, float * __restrict__ b, int n, int j)
{
int i;
for(i = 0; i < n; ++i)
a[i] = (b[j+50] + b[j-50]) * 0.5f;
}
/* We should move the RHS of the store out of the loop. */
/* { dg-final { scan-tree-dump-times "Moving statement" 11 "lim" } } */
/* { dg-final { cleanup-tree-dump "lim" } } */
/* { dg-do compile } */
/* { dg-options "-O -fno-strict-aliasing -fdump-tree-lim-details" } */
void f(int * __restrict__ r,
int a[__restrict__ 16][16],
int b[__restrict__ 16][16],
int i, int j)
{
int x;
*r = 0;
for (x = 1; x < 16; ++x)
*r = *r + a[i][x] * b[x][j];
}
/* We should apply store motion to the store to *r. */
/* { dg-final { scan-tree-dump "Executing store motion of \\\*r" "lim" } } */
/* { dg-final { cleanup-tree-dump "lim" } } */
...@@ -273,6 +273,13 @@ ptr_derefs_may_alias_p (tree ptr1, tree ptr2) ...@@ -273,6 +273,13 @@ ptr_derefs_may_alias_p (tree ptr1, tree ptr2)
if (!pi1 || !pi2) if (!pi1 || !pi2)
return true; return true;
/* If both pointers are restrict-qualified try to disambiguate
with restrict information. */
if (TYPE_RESTRICT (TREE_TYPE (ptr1))
&& TYPE_RESTRICT (TREE_TYPE (ptr2))
&& !pt_solutions_same_restrict_base (&pi1->pt, &pi2->pt))
return false;
/* ??? This does not use TBAA to prune decls from the intersection /* ??? This does not use TBAA to prune decls from the intersection
that not both pointers may access. */ that not both pointers may access. */
return pt_solutions_intersect (&pi1->pt, &pi2->pt); return pt_solutions_intersect (&pi1->pt, &pi2->pt);
......
...@@ -49,6 +49,9 @@ struct GTY(()) pt_solution ...@@ -49,6 +49,9 @@ struct GTY(()) pt_solution
/* Nonzero if the pt_vars bitmap includes a global variable. */ /* Nonzero if the pt_vars bitmap includes a global variable. */
unsigned int vars_contains_global : 1; unsigned int vars_contains_global : 1;
/* Nonzero if the pt_vars bitmap includes a restrict tag variable. */
unsigned int vars_contains_restrict : 1;
/* Set of variables that this pointer may point to. */ /* Set of variables that this pointer may point to. */
bitmap vars; bitmap vars;
}; };
...@@ -115,6 +118,8 @@ extern void delete_alias_heapvars (void); ...@@ -115,6 +118,8 @@ extern void delete_alias_heapvars (void);
extern bool pt_solution_includes_global (struct pt_solution *); extern bool pt_solution_includes_global (struct pt_solution *);
extern bool pt_solution_includes (struct pt_solution *, const_tree); extern bool pt_solution_includes (struct pt_solution *, const_tree);
extern bool pt_solutions_intersect (struct pt_solution *, struct pt_solution *); extern bool pt_solutions_intersect (struct pt_solution *, struct pt_solution *);
extern bool pt_solutions_same_restrict_base (struct pt_solution *,
struct pt_solution *);
extern void pt_solution_reset (struct pt_solution *); extern void pt_solution_reset (struct pt_solution *);
extern void dump_pta_stats (FILE *); extern void dump_pta_stats (FILE *);
......
...@@ -211,20 +211,23 @@ struct variable_info ...@@ -211,20 +211,23 @@ struct variable_info
/* True if this is a variable created by the constraint analysis, such as /* True if this is a variable created by the constraint analysis, such as
heap variables and constraints we had to break up. */ heap variables and constraints we had to break up. */
unsigned int is_artificial_var:1; unsigned int is_artificial_var : 1;
/* True if this is a special variable whose solution set should not be /* True if this is a special variable whose solution set should not be
changed. */ changed. */
unsigned int is_special_var:1; unsigned int is_special_var : 1;
/* 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. */ /* True for (sub-)fields that represent a whole variable. */
unsigned int is_full_var : 1; 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;
/* True if this is a variable tracking a restrict pointer source. */
unsigned int is_restrict_var : 1;
/* True if this field may contain pointers. */ /* True if this field may contain pointers. */
unsigned int may_have_pointers : 1; unsigned int may_have_pointers : 1;
...@@ -339,7 +342,7 @@ new_var_info (tree t, const char *name) ...@@ -339,7 +342,7 @@ new_var_info (tree t, const char *name)
ret->is_special_var = false; ret->is_special_var = false;
ret->is_unknown_size_var = false; ret->is_unknown_size_var = false;
ret->may_have_pointers = true; ret->may_have_pointers = true;
ret->is_global_var = true; ret->is_global_var = (t == NULL_TREE);
if (t && DECL_P (t)) if (t && DECL_P (t))
ret->is_global_var = is_global_var (t); ret->is_global_var = is_global_var (t);
ret->solution = BITMAP_ALLOC (&pta_obstack); ret->solution = BITMAP_ALLOC (&pta_obstack);
...@@ -3312,6 +3315,40 @@ make_constraint_to (unsigned id, tree op) ...@@ -3312,6 +3315,40 @@ make_constraint_to (unsigned id, tree op)
VEC_free (ce_s, heap, rhsc); VEC_free (ce_s, heap, rhsc);
} }
/* Create a constraint ID = &FROM. */
static void
make_constraint_from (varinfo_t vi, int from)
{
struct constraint_expr lhs, rhs;
lhs.var = vi->id;
lhs.offset = 0;
lhs.type = SCALAR;
rhs.var = from;
rhs.offset = 0;
rhs.type = ADDRESSOF;
process_constraint (new_constraint (lhs, rhs));
}
/* Create a constraint ID = FROM. */
static void
make_copy_constraint (varinfo_t vi, int from)
{
struct constraint_expr lhs, rhs;
lhs.var = vi->id;
lhs.offset = 0;
lhs.type = SCALAR;
rhs.var = from;
rhs.offset = 0;
rhs.type = SCALAR;
process_constraint (new_constraint (lhs, rhs));
}
/* Make constraints necessary to make OP escape. */ /* Make constraints necessary to make OP escape. */
static void static void
...@@ -3320,6 +3357,61 @@ make_escape_constraint (tree op) ...@@ -3320,6 +3357,61 @@ make_escape_constraint (tree op)
make_constraint_to (escaped_id, op); make_constraint_to (escaped_id, op);
} }
/* Create a new artificial heap variable with NAME and make a
constraint from it to LHS. Return the created variable. */
static varinfo_t
make_constraint_from_heapvar (varinfo_t lhs, const char *name)
{
varinfo_t vi;
tree heapvar = heapvar_lookup (lhs->decl);
if (heapvar == NULL_TREE)
{
var_ann_t ann;
heapvar = create_tmp_var_raw (ptr_type_node, name);
DECL_EXTERNAL (heapvar) = 1;
heapvar_insert (lhs->decl, heapvar);
ann = get_var_ann (heapvar);
ann->is_heapvar = 1;
}
/* For global vars we need to add a heapvar to the list of referenced
vars of a different function than it was created for originally. */
if (gimple_referenced_vars (cfun))
add_referenced_var (heapvar);
vi = new_var_info (heapvar, name);
vi->is_artificial_var = true;
vi->is_heap_var = true;
vi->is_unknown_size_var = true;
vi->fullsize = ~0;
vi->size = ~0;
vi->is_full_var = true;
insert_vi_for_tree (heapvar, vi);
make_constraint_from (lhs, vi->id);
return vi;
}
/* Create a new artificial heap variable with NAME and make a
constraint from it to LHS. Set flags according to a tag used
for tracking restrict pointers. */
static void
make_constraint_from_restrict (varinfo_t lhs, const char *name)
{
varinfo_t vi;
vi = make_constraint_from_heapvar (lhs, name);
vi->is_restrict_var = 1;
vi->is_global_var = 0;
vi->is_special_var = 1;
vi->may_have_pointers = 0;
}
/* For non-IPA mode, generate constraints necessary for a call on the /* For non-IPA mode, generate constraints necessary for a call on the
RHS. */ RHS. */
...@@ -3374,39 +3466,14 @@ static void ...@@ -3374,39 +3466,14 @@ static void
handle_lhs_call (tree lhs, int flags, VEC(ce_s, heap) *rhsc) handle_lhs_call (tree lhs, int flags, VEC(ce_s, heap) *rhsc)
{ {
VEC(ce_s, heap) *lhsc = NULL; VEC(ce_s, heap) *lhsc = NULL;
unsigned int j;
struct constraint_expr *lhsp;
get_constraint_for (lhs, &lhsc); get_constraint_for (lhs, &lhsc);
if (flags & ECF_MALLOC) if (flags & ECF_MALLOC)
{ {
struct constraint_expr rhsc;
tree heapvar = heapvar_lookup (lhs);
varinfo_t vi; varinfo_t vi;
vi = make_constraint_from_heapvar (get_vi_for_tree (lhs), "HEAP");
if (heapvar == NULL) make_copy_constraint (vi, nonlocal_id);
{
heapvar = create_tmp_var_raw (ptr_type_node, "HEAP");
DECL_EXTERNAL (heapvar) = 1;
get_var_ann (heapvar)->is_heapvar = 1;
if (gimple_referenced_vars (cfun))
add_referenced_var (heapvar);
heapvar_insert (lhs, heapvar);
}
rhsc.var = create_variable_info_for (heapvar,
alias_get_name (heapvar));
vi = get_varinfo (rhsc.var);
vi->is_artificial_var = 1;
vi->is_heap_var = 1;
vi->is_unknown_size_var = true;
vi->fullsize = ~0;
vi->size = ~0;
rhsc.type = ADDRESSOF;
rhsc.offset = 0;
for (j = 0; VEC_iterate (ce_s, lhsc, j, lhsp); j++)
process_constraint (new_constraint (*lhsp, rhsc));
} }
else if (VEC_length (ce_s, rhsc) > 0) else if (VEC_length (ce_s, rhsc) > 0)
{ {
...@@ -3826,6 +3893,15 @@ find_func_aliases (gimple origt) ...@@ -3826,6 +3893,15 @@ find_func_aliases (gimple origt)
&& DECL_P (lhsop) && DECL_P (lhsop)
&& is_global_var (lhsop)) && is_global_var (lhsop))
make_escape_constraint (rhsop); make_escape_constraint (rhsop);
/* If this is a conversion of a non-restrict pointer to a
restrict pointer track it with a new heapvar. */
else if (gimple_assign_cast_p (t)
&& POINTER_TYPE_P (TREE_TYPE (rhsop))
&& POINTER_TYPE_P (TREE_TYPE (lhsop))
&& !TYPE_RESTRICT (TREE_TYPE (rhsop))
&& TYPE_RESTRICT (TREE_TYPE (lhsop)))
make_constraint_from_restrict (get_vi_for_tree (lhsop),
"CAST_RESTRICT");
} }
/* For conversions of pointers to non-pointers the pointer escapes. */ /* For conversions of pointers to non-pointers the pointer escapes. */
else if (gimple_assign_cast_p (t) else if (gimple_assign_cast_p (t)
...@@ -4017,6 +4093,8 @@ struct fieldoff ...@@ -4017,6 +4093,8 @@ struct fieldoff
unsigned has_unknown_size : 1; unsigned has_unknown_size : 1;
unsigned may_have_pointers : 1; unsigned may_have_pointers : 1;
unsigned only_restrict_pointers : 1;
}; };
typedef struct fieldoff fieldoff_s; typedef struct fieldoff fieldoff_s;
...@@ -4155,6 +4233,10 @@ push_fields_onto_fieldstack (tree type, VEC(fieldoff_s,heap) **fieldstack, ...@@ -4155,6 +4233,10 @@ push_fields_onto_fieldstack (tree type, VEC(fieldoff_s,heap) **fieldstack,
else else
pair->size = -1; pair->size = -1;
pair->may_have_pointers = could_have_pointers (field); pair->may_have_pointers = could_have_pointers (field);
pair->only_restrict_pointers
= (!has_unknown_size
&& POINTER_TYPE_P (TREE_TYPE (field))
&& TYPE_RESTRICT (TREE_TYPE (field)));
count++; count++;
} }
} }
...@@ -4165,40 +4247,6 @@ push_fields_onto_fieldstack (tree type, VEC(fieldoff_s,heap) **fieldstack, ...@@ -4165,40 +4247,6 @@ push_fields_onto_fieldstack (tree type, VEC(fieldoff_s,heap) **fieldstack,
return count; return count;
} }
/* Create a constraint ID = &FROM. */
static void
make_constraint_from (varinfo_t vi, int from)
{
struct constraint_expr lhs, rhs;
lhs.var = vi->id;
lhs.offset = 0;
lhs.type = SCALAR;
rhs.var = from;
rhs.offset = 0;
rhs.type = ADDRESSOF;
process_constraint (new_constraint (lhs, rhs));
}
/* Create a constraint ID = FROM. */
static void
make_copy_constraint (varinfo_t vi, int from)
{
struct constraint_expr lhs, rhs;
lhs.var = vi->id;
lhs.offset = 0;
lhs.type = SCALAR;
rhs.var = from;
rhs.offset = 0;
rhs.type = SCALAR;
process_constraint (new_constraint (lhs, rhs));
}
/* Count the number of arguments DECL has, and set IS_VARARGS to true /* Count the number of arguments DECL has, and set IS_VARARGS to true
if it is a varargs function. */ if it is a varargs function. */
...@@ -4346,17 +4394,12 @@ create_variable_info_for (tree decl, const char *name) ...@@ -4346,17 +4394,12 @@ create_variable_info_for (tree decl, const char *name)
varinfo_t vi; varinfo_t vi;
tree decl_type = TREE_TYPE (decl); tree decl_type = TREE_TYPE (decl);
tree declsize = DECL_P (decl) ? DECL_SIZE (decl) : TYPE_SIZE (decl_type); tree declsize = DECL_P (decl) ? DECL_SIZE (decl) : TYPE_SIZE (decl_type);
bool is_global = DECL_P (decl) ? is_global_var (decl) : false;
VEC (fieldoff_s,heap) *fieldstack = NULL; VEC (fieldoff_s,heap) *fieldstack = NULL;
if (TREE_CODE (decl) == FUNCTION_DECL && in_ipa_mode) if (TREE_CODE (decl) == FUNCTION_DECL && in_ipa_mode)
return create_function_info_for (decl, name); return create_function_info_for (decl, name);
if (var_can_have_subvars (decl) && use_field_sensitive if (var_can_have_subvars (decl) && use_field_sensitive)
&& (!var_ann (decl)
|| var_ann (decl)->noalias_state == 0)
&& (!var_ann (decl)
|| !var_ann (decl)->is_heapvar))
push_fields_onto_fieldstack (decl_type, &fieldstack, 0); push_fields_onto_fieldstack (decl_type, &fieldstack, 0);
/* If the variable doesn't have subvars, we may end up needing to /* If the variable doesn't have subvars, we may end up needing to
...@@ -4379,13 +4422,13 @@ create_variable_info_for (tree decl, const char *name) ...@@ -4379,13 +4422,13 @@ create_variable_info_for (tree decl, const char *name)
} }
insert_vi_for_tree (vi->decl, vi); insert_vi_for_tree (vi->decl, vi);
if (is_global && (!flag_whole_program || !in_ipa_mode) if (vi->is_global_var
&& (!flag_whole_program || !in_ipa_mode)
&& vi->may_have_pointers) && vi->may_have_pointers)
{ {
if (var_ann (decl) if (POINTER_TYPE_P (TREE_TYPE (decl))
&& var_ann (decl)->noalias_state == NO_ALIAS_ANYTHING) && TYPE_RESTRICT (TREE_TYPE (decl)))
make_constraint_from (vi, vi->id); make_constraint_from_restrict (vi, "GLOBAL_RESTRICT");
else
make_copy_constraint (vi, nonlocal_id); make_copy_constraint (vi, nonlocal_id);
} }
...@@ -4463,9 +4506,14 @@ create_variable_info_for (tree decl, const char *name) ...@@ -4463,9 +4506,14 @@ create_variable_info_for (tree decl, const char *name)
newvi->fullsize = vi->fullsize; newvi->fullsize = vi->fullsize;
newvi->may_have_pointers = fo->may_have_pointers; newvi->may_have_pointers = fo->may_have_pointers;
insert_into_field_list (vi, newvi); insert_into_field_list (vi, newvi);
if (is_global && (!flag_whole_program || !in_ipa_mode) if (newvi->is_global_var
&& (!flag_whole_program || !in_ipa_mode)
&& newvi->may_have_pointers) && newvi->may_have_pointers)
{
if (fo->only_restrict_pointers)
make_constraint_from_restrict (newvi, "GLOBAL_RESTRICT");
make_copy_constraint (newvi, nonlocal_id); make_copy_constraint (newvi, nonlocal_id);
}
stats.total_vars++; stats.total_vars++;
} }
...@@ -4518,7 +4566,6 @@ static void ...@@ -4518,7 +4566,6 @@ static void
intra_create_variable_infos (void) intra_create_variable_infos (void)
{ {
tree t; tree t;
struct constraint_expr lhs, rhs;
/* For each incoming pointer argument arg, create the constraint ARG /* For each incoming pointer argument arg, create the constraint ARG
= NONLOCAL or a dummy variable if flag_argument_noalias is set. */ = NONLOCAL or a dummy variable if flag_argument_noalias is set. */
...@@ -4536,51 +4583,29 @@ intra_create_variable_infos (void) ...@@ -4536,51 +4583,29 @@ intra_create_variable_infos (void)
if (POINTER_TYPE_P (TREE_TYPE (t)) && flag_argument_noalias > 0) if (POINTER_TYPE_P (TREE_TYPE (t)) && flag_argument_noalias > 0)
{ {
varinfo_t vi; varinfo_t vi;
tree heapvar = heapvar_lookup (t);
lhs.offset = 0;
lhs.type = SCALAR;
lhs.var = get_vi_for_tree (t)->id;
if (heapvar == NULL_TREE)
{
var_ann_t ann; var_ann_t ann;
heapvar = create_tmp_var_raw (ptr_type_node,
"PARM_NOALIAS");
DECL_EXTERNAL (heapvar) = 1;
if (gimple_referenced_vars (cfun))
add_referenced_var (heapvar);
heapvar_insert (t, heapvar); vi = make_constraint_from_heapvar (get_vi_for_tree (t),
"PARM_NOALIAS");
ann = get_var_ann (heapvar); ann = get_var_ann (vi->decl);
ann->is_heapvar = 1;
if (flag_argument_noalias == 1) if (flag_argument_noalias == 1)
{
ann->noalias_state = NO_ALIAS; ann->noalias_state = NO_ALIAS;
make_copy_constraint (vi, nonlocal_id);
}
else if (flag_argument_noalias == 2) else if (flag_argument_noalias == 2)
{
ann->noalias_state = NO_ALIAS_GLOBAL; ann->noalias_state = NO_ALIAS_GLOBAL;
make_constraint_from (vi, vi->id);
}
else if (flag_argument_noalias == 3) else if (flag_argument_noalias == 3)
{
ann->noalias_state = NO_ALIAS_ANYTHING; ann->noalias_state = NO_ALIAS_ANYTHING;
make_constraint_from (vi, vi->id);
}
else else
gcc_unreachable (); gcc_unreachable ();
} }
vi = get_vi_for_tree (heapvar);
vi->is_artificial_var = 1;
vi->is_heap_var = 1;
vi->is_unknown_size_var = true;
vi->fullsize = ~0;
vi->size = ~0;
rhs.var = vi->id;
rhs.type = ADDRESSOF;
rhs.offset = 0;
for (p = get_varinfo (lhs.var); p; p = p->next)
{
struct constraint_expr temp = lhs;
temp.var = p->id;
process_constraint (new_constraint (temp, rhs));
}
}
else else
{ {
varinfo_t arg_vi = get_vi_for_tree (t); varinfo_t arg_vi = get_vi_for_tree (t);
...@@ -4588,6 +4613,9 @@ intra_create_variable_infos (void) ...@@ -4588,6 +4613,9 @@ intra_create_variable_infos (void)
for (p = arg_vi; p; p = p->next) for (p = arg_vi; p; p = p->next)
make_constraint_from (p, nonlocal_id); make_constraint_from (p, nonlocal_id);
} }
if (POINTER_TYPE_P (TREE_TYPE (t))
&& TYPE_RESTRICT (TREE_TYPE (t)))
make_constraint_from_restrict (get_vi_for_tree (t), "PARM_RESTRICT");
} }
/* Add a constraint for a result decl that is passed by reference. */ /* Add a constraint for a result decl that is passed by reference. */
...@@ -4704,7 +4732,7 @@ set_uids_in_ptset (bitmap into, bitmap from, struct pt_solution *pt) ...@@ -4704,7 +4732,7 @@ set_uids_in_ptset (bitmap into, bitmap from, struct pt_solution *pt)
/* Add the decl to the points-to set. Note that the points-to /* Add the decl to the points-to set. Note that the points-to
set contains global variables. */ set contains global variables. */
bitmap_set_bit (into, DECL_UID (vi->decl)); bitmap_set_bit (into, DECL_UID (vi->decl));
if (is_global_var (vi->decl)) if (vi->is_global_var)
pt->vars_contains_global = true; pt->vars_contains_global = true;
} }
} }
...@@ -4753,11 +4781,15 @@ find_what_var_points_to (varinfo_t vi, struct pt_solution *pt) ...@@ -4753,11 +4781,15 @@ find_what_var_points_to (varinfo_t vi, struct pt_solution *pt)
|| vi->id == integer_id) || vi->id == integer_id)
pt->anything = 1; pt->anything = 1;
} }
if (vi->is_restrict_var)
pt->vars_contains_restrict = true;
} }
/* Instead of doing extra work, simply do not create /* Instead of doing extra work, simply do not create
elaborate points-to information for pt_anything pointers. */ elaborate points-to information for pt_anything pointers. */
if (pt->anything) if (pt->anything
&& (vi->is_artificial_var
|| !pt->vars_contains_restrict))
return; return;
/* Share the final set of variables when possible. */ /* Share the final set of variables when possible. */
...@@ -4967,6 +4999,27 @@ pt_solutions_intersect (struct pt_solution *pt1, struct pt_solution *pt2) ...@@ -4967,6 +4999,27 @@ pt_solutions_intersect (struct pt_solution *pt1, struct pt_solution *pt2)
return res; return res;
} }
/* Return true if both points-to solutions PT1 and PT2 for two restrict
qualified pointers are possibly based on the same pointer. */
bool
pt_solutions_same_restrict_base (struct pt_solution *pt1,
struct pt_solution *pt2)
{
/* If we deal with points-to solutions of two restrict qualified
pointers solely rely on the pointed-to variable bitmap intersection.
For two pointers that are based on each other the bitmaps will
intersect. */
if (pt1->vars_contains_restrict
&& pt2->vars_contains_restrict)
{
gcc_assert (pt1->vars && pt2->vars);
return bitmap_intersect_p (pt1->vars, pt2->vars);
}
return true;
}
/* Dump points-to information to OUTFILE. */ /* Dump points-to information to OUTFILE. */
......
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