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>
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
* alias.c (find_base_decl): Remove.
(get_deref_alias_set_1): Remove restrict handling.
......
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
* 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)
if (!pi1 || !pi2)
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
that not both pointers may access. */
return pt_solutions_intersect (&pi1->pt, &pi2->pt);
......
......@@ -49,6 +49,9 @@ struct GTY(()) pt_solution
/* Nonzero if the pt_vars bitmap includes a global variable. */
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. */
bitmap vars;
};
......@@ -115,6 +118,8 @@ extern void delete_alias_heapvars (void);
extern bool pt_solution_includes_global (struct pt_solution *);
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_same_restrict_base (struct pt_solution *,
struct pt_solution *);
extern void pt_solution_reset (struct pt_solution *);
extern void dump_pta_stats (FILE *);
......
......@@ -211,20 +211,23 @@ struct variable_info
/* True if this is a variable created by the constraint analysis, such as
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
changed. */
unsigned int is_special_var:1;
unsigned int is_special_var : 1;
/* 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. */
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. */
unsigned int may_have_pointers : 1;
......@@ -339,7 +342,7 @@ new_var_info (tree t, const char *name)
ret->is_special_var = false;
ret->is_unknown_size_var = false;
ret->may_have_pointers = true;
ret->is_global_var = true;
ret->is_global_var = (t == NULL_TREE);
if (t && DECL_P (t))
ret->is_global_var = is_global_var (t);
ret->solution = BITMAP_ALLOC (&pta_obstack);
......@@ -3312,6 +3315,40 @@ make_constraint_to (unsigned id, tree op)
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. */
static void
......@@ -3320,6 +3357,61 @@ make_escape_constraint (tree 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
RHS. */
......@@ -3374,39 +3466,14 @@ static void
handle_lhs_call (tree lhs, int flags, VEC(ce_s, heap) *rhsc)
{
VEC(ce_s, heap) *lhsc = NULL;
unsigned int j;
struct constraint_expr *lhsp;
get_constraint_for (lhs, &lhsc);
if (flags & ECF_MALLOC)
{
struct constraint_expr rhsc;
tree heapvar = heapvar_lookup (lhs);
varinfo_t vi;
if (heapvar == NULL)
{
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));
vi = make_constraint_from_heapvar (get_vi_for_tree (lhs), "HEAP");
make_copy_constraint (vi, nonlocal_id);
}
else if (VEC_length (ce_s, rhsc) > 0)
{
......@@ -3826,6 +3893,15 @@ find_func_aliases (gimple origt)
&& DECL_P (lhsop)
&& is_global_var (lhsop))
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. */
else if (gimple_assign_cast_p (t)
......@@ -4017,6 +4093,8 @@ struct fieldoff
unsigned has_unknown_size : 1;
unsigned may_have_pointers : 1;
unsigned only_restrict_pointers : 1;
};
typedef struct fieldoff fieldoff_s;
......@@ -4155,6 +4233,10 @@ push_fields_onto_fieldstack (tree type, VEC(fieldoff_s,heap) **fieldstack,
else
pair->size = -1;
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++;
}
}
......@@ -4165,40 +4247,6 @@ push_fields_onto_fieldstack (tree type, VEC(fieldoff_s,heap) **fieldstack,
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
if it is a varargs function. */
......@@ -4346,17 +4394,12 @@ create_variable_info_for (tree decl, const char *name)
varinfo_t vi;
tree decl_type = TREE_TYPE (decl);
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;
if (TREE_CODE (decl) == FUNCTION_DECL && in_ipa_mode)
return create_function_info_for (decl, name);
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))
if (var_can_have_subvars (decl) && use_field_sensitive)
push_fields_onto_fieldstack (decl_type, &fieldstack, 0);
/* 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)
}
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)
{
if (var_ann (decl)
&& var_ann (decl)->noalias_state == NO_ALIAS_ANYTHING)
make_constraint_from (vi, vi->id);
else
if (POINTER_TYPE_P (TREE_TYPE (decl))
&& TYPE_RESTRICT (TREE_TYPE (decl)))
make_constraint_from_restrict (vi, "GLOBAL_RESTRICT");
make_copy_constraint (vi, nonlocal_id);
}
......@@ -4463,9 +4506,14 @@ create_variable_info_for (tree decl, const char *name)
newvi->fullsize = vi->fullsize;
newvi->may_have_pointers = fo->may_have_pointers;
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)
{
if (fo->only_restrict_pointers)
make_constraint_from_restrict (newvi, "GLOBAL_RESTRICT");
make_copy_constraint (newvi, nonlocal_id);
}
stats.total_vars++;
}
......@@ -4518,7 +4566,6 @@ static void
intra_create_variable_infos (void)
{
tree t;
struct constraint_expr lhs, rhs;
/* For each incoming pointer argument arg, create the constraint ARG
= NONLOCAL or a dummy variable if flag_argument_noalias is set. */
......@@ -4536,51 +4583,29 @@ intra_create_variable_infos (void)
if (POINTER_TYPE_P (TREE_TYPE (t)) && flag_argument_noalias > 0)
{
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;
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);
ann = get_var_ann (heapvar);
ann->is_heapvar = 1;
vi = make_constraint_from_heapvar (get_vi_for_tree (t),
"PARM_NOALIAS");
ann = get_var_ann (vi->decl);
if (flag_argument_noalias == 1)
{
ann->noalias_state = NO_ALIAS;
make_copy_constraint (vi, nonlocal_id);
}
else if (flag_argument_noalias == 2)
{
ann->noalias_state = NO_ALIAS_GLOBAL;
make_constraint_from (vi, vi->id);
}
else if (flag_argument_noalias == 3)
{
ann->noalias_state = NO_ALIAS_ANYTHING;
make_constraint_from (vi, vi->id);
}
else
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
{
varinfo_t arg_vi = get_vi_for_tree (t);
......@@ -4588,6 +4613,9 @@ intra_create_variable_infos (void)
for (p = arg_vi; p; p = p->next)
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. */
......@@ -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
set contains global variables. */
bitmap_set_bit (into, DECL_UID (vi->decl));
if (is_global_var (vi->decl))
if (vi->is_global_var)
pt->vars_contains_global = true;
}
}
......@@ -4753,11 +4781,15 @@ find_what_var_points_to (varinfo_t vi, struct pt_solution *pt)
|| vi->id == integer_id)
pt->anything = 1;
}
if (vi->is_restrict_var)
pt->vars_contains_restrict = true;
}
/* Instead of doing extra work, simply do not create
elaborate points-to information for pt_anything pointers. */
if (pt->anything)
if (pt->anything
&& (vi->is_artificial_var
|| !pt->vars_contains_restrict))
return;
/* Share the final set of variables when possible. */
......@@ -4967,6 +4999,27 @@ pt_solutions_intersect (struct pt_solution *pt1, struct pt_solution *pt2)
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. */
......
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