Commit b7091901 by Richard Guenther Committed by Richard Biener

re PR tree-optimization/36400 (points-to results wrong)

2008-06-27  Richard Guenther  <rguenther@suse.de>

	PR tree-optimization/36400
	PR tree-optimization/36373
	PR tree-optimization/36344
	* tree-ssa-structalias.c (var_escaped, escaped_tree, escaped_id,
	var_nonlocal, nonlocal_tree, nonlocal_id): New globals
	(update_alias_info): Remove call clobbering code.
	(make_constraint_to): New helper function.
	(make_escape_constraint): Likewise.
	(handle_rhs_call): Use it on all pointer containing arguments.
	Also mark the static chain escaped.
	(handle_lhs_call): Make constraints from NONLOCAL and ESCAPED
	instead of ANYTHING.
	(make_constraint_from): New helper split out from ...
	(make_constraint_from_anything): ... here.
	(find_func_aliases): Add constraints for escape sites.
	(intra_create_variable_infos): Make constraints from NONLOCAL
	for parameters.
	(find_what_p_points_to): Interpret NONLOCAL and ESCAPED the same
	as ANYTHING.
	(clobber_what_p_points_to): Remove.
	(clobber_what_escaped): New function.
	(init_base_vars): Init NONLOCAL and ESCAPED.
	(do_sd_constraint): Do not propagate the solution from ESCAPED
	but use ESCAPED as a placeholder.
	(solve_graph): Likewise.
	* tree-flow.h (clobber_what_p_points_to): Remove.
	(clobber_what_escaped): Declare.
	* tree-ssa-alias.c (set_initial_properties): Call it.
	Remove code clobbering escaped pointers.

	* gcc.dg/torture/pr36373-1.c: New testcase.
	* gcc.dg/torture/pr36373-2.c: Likewise.
	* gcc.dg/torture/pr36373-3.c: Likewise.
	* gcc.dg/torture/pr36373-4.c: Likewise.
	* gcc.dg/torture/pr36373-5.c: Likewise.
	* gcc.dg/torture/pr36373-6.c: Likewise.
	* gcc.dg/torture/pr36373-7.c: Likewise.
	* gcc.dg/torture/pr36373-8.c: Likewise.
	* gcc.dg/torture/pr36373-9.c: Likewise.
	* gcc.dg/torture/pr36373-10.c: Likewise.
	* gcc.dg/torture/pr36400.c: Likewise.
	* gcc.c-torture/execute/pta-field-1.c: Likewise.
	* gcc.c-torture/execute/pta-field-2.c: Likewise.
	* gcc.dg/tree-ssa/loadpre8.c: Remove XFAIL.
	* gcc.dg/tree-ssa/pr24287.c: XFAIL.

From-SVN: r137197
parent 04dbd891
2008-06-27 Richard Guenther <rguenther@suse.de>
PR tree-optimization/36400
PR tree-optimization/36373
PR tree-optimization/36344
* tree-ssa-structalias.c (var_escaped, escaped_tree, escaped_id,
var_nonlocal, nonlocal_tree, nonlocal_id): New globals
(update_alias_info): Remove call clobbering code.
(make_constraint_to): New helper function.
(make_escape_constraint): Likewise.
(handle_rhs_call): Use it on all pointer containing arguments.
Also mark the static chain escaped.
(handle_lhs_call): Make constraints from NONLOCAL and ESCAPED
instead of ANYTHING.
(make_constraint_from): New helper split out from ...
(make_constraint_from_anything): ... here.
(find_func_aliases): Add constraints for escape sites.
(intra_create_variable_infos): Make constraints from NONLOCAL
for parameters.
(find_what_p_points_to): Interpret NONLOCAL and ESCAPED the same
as ANYTHING.
(clobber_what_p_points_to): Remove.
(clobber_what_escaped): New function.
(init_base_vars): Init NONLOCAL and ESCAPED.
(do_sd_constraint): Do not propagate the solution from ESCAPED
but use ESCAPED as a placeholder.
(solve_graph): Likewise.
* tree-flow.h (clobber_what_p_points_to): Remove.
(clobber_what_escaped): Declare.
* tree-ssa-alias.c (set_initial_properties): Call it.
Remove code clobbering escaped pointers.
2008-06-27 Richard Sandiford <rdsandiford@googlemail.com> 2008-06-27 Richard Sandiford <rdsandiford@googlemail.com>
* function.c (allocate_struct_function): Only allocate a unique * function.c (allocate_struct_function): Only allocate a unique
......
2008-06-27 Richard Guenther <rguenther@suse.de>
PR tree-optimization/36400
PR tree-optimization/36373
PR tree-optimization/36344
* gcc.dg/torture/pr36373-1.c: New testcase.
* gcc.dg/torture/pr36373-2.c: Likewise.
* gcc.dg/torture/pr36373-3.c: Likewise.
* gcc.dg/torture/pr36373-4.c: Likewise.
* gcc.dg/torture/pr36373-5.c: Likewise.
* gcc.dg/torture/pr36373-6.c: Likewise.
* gcc.dg/torture/pr36373-7.c: Likewise.
* gcc.dg/torture/pr36373-8.c: Likewise.
* gcc.dg/torture/pr36373-9.c: Likewise.
* gcc.dg/torture/pr36373-10.c: Likewise.
* gcc.dg/torture/pr36400.c: Likewise.
* gcc.c-torture/execute/pta-field-1.c: Likewise.
* gcc.c-torture/execute/pta-field-2.c: Likewise.
* gcc.dg/tree-ssa/loadpre8.c: Remove XFAIL.
* gcc.dg/tree-ssa/pr24287.c: XFAIL.
2008-06-27 Eric Botcazou <ebotcazou@adacore.com> 2008-06-27 Eric Botcazou <ebotcazou@adacore.com>
* gnat.dg/aggr9.ad[sb]: New test. * gnat.dg/aggr9.ad[sb]: New test.
......
...@@ -93,5 +93,5 @@ rewrite_add_phi_arguments (basic_block bb) ...@@ -93,5 +93,5 @@ rewrite_add_phi_arguments (basic_block bb)
get_reaching_def ((get_def_from_ptr (get_phi_result_ptr (phi)))->ssa_name.var); get_reaching_def ((get_def_from_ptr (get_phi_result_ptr (phi)))->ssa_name.var);
} }
} }
/* { dg-final { scan-tree-dump-times "Eliminated: 1" 1 "pre" { xfail *-*-* } } } */ /* { dg-final { scan-tree-dump-times "Eliminated: 1" 1 "pre" } } */
/* { dg-final { cleanup-tree-dump "pre" } } */ /* { dg-final { cleanup-tree-dump "pre" } } */
...@@ -21,5 +21,5 @@ int g(void) ...@@ -21,5 +21,5 @@ int g(void)
link_error (); link_error ();
return t2 == 2; return t2 == 2;
} }
/* { dg-final { scan-tree-dump-times "link_error" 0 "optimized"} } */ /* { dg-final { scan-tree-dump-times "link_error" 0 "optimized" { xfail *-*-* } } } */
/* { dg-final { cleanup-tree-dump "optimized" } } */ /* { dg-final { cleanup-tree-dump "optimized" } } */
...@@ -1173,7 +1173,7 @@ tree gimple_fold_indirect_ref (tree); ...@@ -1173,7 +1173,7 @@ tree gimple_fold_indirect_ref (tree);
/* In tree-ssa-structalias.c */ /* In tree-ssa-structalias.c */
bool find_what_p_points_to (tree); bool find_what_p_points_to (tree);
bool clobber_what_p_points_to (tree); bool clobber_what_escaped (void);
/* In tree-ssa-live.c */ /* In tree-ssa-live.c */
extern void remove_unused_locals (void); extern void remove_unused_locals (void);
......
...@@ -537,6 +537,12 @@ set_initial_properties (struct alias_info *ai) ...@@ -537,6 +537,12 @@ set_initial_properties (struct alias_info *ai)
} }
} }
if (!clobber_what_escaped ())
{
any_pt_anything = true;
pt_anything_mask |= ESCAPE_TO_CALL;
}
for (i = 0; VEC_iterate (tree, ai->processed_ptrs, i, ptr); i++) for (i = 0; VEC_iterate (tree, ai->processed_ptrs, i, ptr); i++)
{ {
struct ptr_info_def *pi = SSA_NAME_PTR_INFO (ptr); struct ptr_info_def *pi = SSA_NAME_PTR_INFO (ptr);
...@@ -557,18 +563,6 @@ set_initial_properties (struct alias_info *ai) ...@@ -557,18 +563,6 @@ set_initial_properties (struct alias_info *ai)
if (tag) if (tag)
mark_call_clobbered (tag, pi->escape_mask); mark_call_clobbered (tag, pi->escape_mask);
/* Defer to points-to analysis if possible, otherwise
clobber all addressable variables. Parameters cannot
point to local memory though.
??? Properly tracking which pointers point to non-local
memory only would make a big difference here. */
if (!clobber_what_p_points_to (ptr)
&& !(pi->escape_mask & ESCAPE_IS_PARM))
{
any_pt_anything = true;
pt_anything_mask |= pi->escape_mask;
}
} }
/* If the name tag is call clobbered, so is the symbol tag /* If the name tag is call clobbered, so is the symbol tag
...@@ -2906,6 +2900,12 @@ is_escape_site (tree stmt) ...@@ -2906,6 +2900,12 @@ is_escape_site (tree stmt)
if (TREE_CODE (lhs) == SSA_NAME) if (TREE_CODE (lhs) == SSA_NAME)
return NO_ESCAPE; return NO_ESCAPE;
/* If the LHS is a non-global decl, it isn't a non-local memory store.
If the LHS escapes, the RHS escape is dealt with in the PTA solver. */
if (DECL_P (lhs)
&& !is_global_var (lhs))
return NO_ESCAPE;
/* FIXME: LHS is not an SSA_NAME. Even if it's an assignment to a /* FIXME: LHS is not an SSA_NAME. Even if it's an assignment to a
local variables we cannot be sure if it will escape, because we local variables we cannot be sure if it will escape, because we
don't have information about objects not in SSA form. Need to don't have information about objects not in SSA form. Need to
......
...@@ -294,26 +294,34 @@ get_varinfo_fc (unsigned int n) ...@@ -294,26 +294,34 @@ get_varinfo_fc (unsigned int n)
return v; return v;
} }
/* Static IDs for the special variables. */
enum { nothing_id = 0, anything_id = 1, readonly_id = 2,
escaped_id = 3, nonlocal_id = 4, integer_id = 5 };
/* Variable that represents the unknown pointer. */ /* Variable that represents the unknown pointer. */
static varinfo_t var_anything; static varinfo_t var_anything;
static tree anything_tree; static tree anything_tree;
static unsigned int anything_id;
/* Variable that represents the NULL pointer. */ /* Variable that represents the NULL pointer. */
static varinfo_t var_nothing; static varinfo_t var_nothing;
static tree nothing_tree; static tree nothing_tree;
static unsigned int nothing_id;
/* Variable that represents read only memory. */ /* Variable that represents read only memory. */
static varinfo_t var_readonly; static varinfo_t var_readonly;
static tree readonly_tree; static tree readonly_tree;
static unsigned int readonly_id;
/* Variable that represents escaped memory. */
static varinfo_t var_escaped;
static tree escaped_tree;
/* Variable that represents nonlocal memory. */
static varinfo_t var_nonlocal;
static tree nonlocal_tree;
/* Variable that represents integers. This is used for when people do things /* Variable that represents integers. This is used for when people do things
like &0->a.b. */ like &0->a.b. */
static varinfo_t var_integer; static varinfo_t var_integer;
static tree integer_tree; static tree integer_tree;
static unsigned int integer_id;
/* Lookup a heap var for FROM, and return it if we find one. */ /* Lookup a heap var for FROM, and return it if we find one. */
...@@ -1399,6 +1407,7 @@ do_sd_constraint (constraint_graph_t graph, constraint_t c, ...@@ -1399,6 +1407,7 @@ do_sd_constraint (constraint_graph_t graph, constraint_t c,
bitmap_set_bit (sol, anything_id); bitmap_set_bit (sol, anything_id);
goto done; goto done;
} }
/* For each variable j in delta (Sol(y)), add /* For each variable j in delta (Sol(y)), add
an edge in the graph from j to x, and union Sol(j) into Sol(x). */ an edge in the graph from j to x, and union Sol(j) into Sol(x). */
EXECUTE_IF_SET_IN_BITMAP (delta, 0, j, bi) EXECUTE_IF_SET_IN_BITMAP (delta, 0, j, bi)
...@@ -1417,8 +1426,16 @@ do_sd_constraint (constraint_graph_t graph, constraint_t c, ...@@ -1417,8 +1426,16 @@ do_sd_constraint (constraint_graph_t graph, constraint_t c,
/* Adding edges from the special vars is pointless. /* Adding edges from the special vars is pointless.
They don't have sets that can change. */ They don't have sets that can change. */
if (get_varinfo (t) ->is_special_var) if (get_varinfo (t)->is_special_var)
flag |= bitmap_ior_into (sol, get_varinfo (t)->solution); flag |= bitmap_ior_into (sol, get_varinfo (t)->solution);
/* Merging the solution from ESCAPED needlessly increases
the set. Use ESCAPED as representative instead. */
else if (get_varinfo (t)->id == escaped_id
&& !bitmap_bit_p (sol, get_varinfo (t)->id))
{
bitmap_set_bit (sol, escaped_id);
flag = true;
}
else if (add_graph_edge (graph, lhs, t)) else if (add_graph_edge (graph, lhs, t))
flag |= bitmap_ior_into (sol, get_varinfo (t)->solution); flag |= bitmap_ior_into (sol, get_varinfo (t)->solution);
} }
...@@ -2351,7 +2368,9 @@ solve_graph (constraint_graph_t graph) ...@@ -2351,7 +2368,9 @@ solve_graph (constraint_graph_t graph)
solution_empty = bitmap_empty_p (solution); solution_empty = bitmap_empty_p (solution);
if (!solution_empty) if (!solution_empty
/* Do not propagate the ESCAPED solution. */
&& i != escaped_id)
{ {
bitmap_iterator bi; bitmap_iterator bi;
...@@ -3271,25 +3290,8 @@ update_alias_info (tree stmt, struct alias_info *ai) ...@@ -3271,25 +3290,8 @@ update_alias_info (tree stmt, struct alias_info *ai)
/* Mark all the variables whose address are taken by the statement. */ /* Mark all the variables whose address are taken by the statement. */
addr_taken = addresses_taken (stmt); addr_taken = addresses_taken (stmt);
if (addr_taken) if (addr_taken)
{
bitmap_ior_into (gimple_addressable_vars (cfun), addr_taken); bitmap_ior_into (gimple_addressable_vars (cfun), addr_taken);
/* If STMT is an escape point, all the addresses taken by it are
call-clobbered. */
if (stmt_escape_type != NO_ESCAPE)
{
bitmap_iterator bi;
unsigned i;
EXECUTE_IF_SET_IN_BITMAP (addr_taken, 0, i, bi)
{
tree rvar = referenced_var (i);
if (!unmodifiable_var_p (rvar))
mark_call_clobbered (rvar, stmt_escape_type);
}
}
}
/* Process each operand use. For pointers, determine whether they /* Process each operand use. For pointers, determine whether they
are dereferenced by the statement, or whether their value are dereferenced by the statement, or whether their value
escapes, etc. */ escapes, etc. */
...@@ -3573,6 +3575,34 @@ handle_ptr_arith (VEC (ce_s, heap) *lhsc, tree expr) ...@@ -3573,6 +3575,34 @@ handle_ptr_arith (VEC (ce_s, heap) *lhsc, tree expr)
return true; return true;
} }
/* Create a constraint ID = OP. */
static void
make_constraint_to (unsigned id, tree op)
{
VEC(ce_s, heap) *rhsc = NULL;
struct constraint_expr *c;
struct constraint_expr includes;
unsigned int j;
includes.var = id;
includes.offset = 0;
includes.type = SCALAR;
get_constraint_for (op, &rhsc);
for (j = 0; VEC_iterate (ce_s, rhsc, j, c); j++)
process_constraint_1 (new_constraint (includes, *c), true);
VEC_free (ce_s, heap, rhsc);
}
/* Make constraints necessary to make OP escape. */
static void
make_escape_constraint (tree op)
{
make_constraint_to (escaped_id, op);
}
/* 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. */
...@@ -3581,51 +3611,95 @@ handle_rhs_call (tree rhs) ...@@ -3581,51 +3611,95 @@ handle_rhs_call (tree rhs)
{ {
tree arg; tree arg;
call_expr_arg_iterator iter; call_expr_arg_iterator iter;
struct constraint_expr rhsc;
rhsc.var = anything_id;
rhsc.offset = 0;
rhsc.type = ADDRESSOF;
FOR_EACH_CALL_EXPR_ARG (arg, iter, rhs) FOR_EACH_CALL_EXPR_ARG (arg, iter, rhs)
{
VEC(ce_s, heap) *lhsc = NULL;
/* Find those pointers being passed, and make sure they end up /* Find those pointers being passed, and make sure they end up
pointing to anything. */ pointing to anything. */
if (POINTER_TYPE_P (TREE_TYPE (arg))) if (could_have_pointers (arg))
{ make_escape_constraint (arg);
/* The static chain escapes as well. */
if (CALL_EXPR_STATIC_CHAIN (rhs))
make_escape_constraint (CALL_EXPR_STATIC_CHAIN (rhs));
}
/* For non-IPA mode, generate constraints necessary for a call
that returns a pointer and assigns it to LHS. This simply makes
the LHS point to global and escaped variables. */
static void
handle_lhs_call (tree lhs)
{
VEC(ce_s, heap) *lhsc = NULL;
struct constraint_expr rhsc;
unsigned int j; unsigned int j;
struct constraint_expr *lhsp; struct constraint_expr *lhsp;
get_constraint_for (arg, &lhsc); get_constraint_for (lhs, &lhsc);
do_deref (&lhsc); rhsc.var = nonlocal_id;
rhsc.offset = 0;
rhsc.type = ADDRESSOF;
for (j = 0; VEC_iterate (ce_s, lhsc, j, lhsp); j++)
process_constraint_1 (new_constraint (*lhsp, rhsc), true);
rhsc.var = escaped_id;
rhsc.offset = 0;
rhsc.type = ADDRESSOF;
for (j = 0; VEC_iterate (ce_s, lhsc, j, lhsp); j++) for (j = 0; VEC_iterate (ce_s, lhsc, j, lhsp); j++)
process_constraint_1 (new_constraint (*lhsp, rhsc), true); process_constraint_1 (new_constraint (*lhsp, rhsc), true);
VEC_free (ce_s, heap, lhsc); VEC_free (ce_s, heap, lhsc);
}
}
} }
/* For non-IPA mode, generate constraints necessary for a call /* For non-IPA mode, generate constraints necessary for a call of a
that returns a pointer and assigns it to LHS. This simply makes const function that returns a pointer in the statement STMT. */
the LHS point to anything. */
static void static void
handle_lhs_call (tree lhs) handle_const_call (tree stmt)
{ {
tree lhs = GIMPLE_STMT_OPERAND (stmt, 0);
tree call = get_call_expr_in (stmt);
VEC(ce_s, heap) *lhsc = NULL; VEC(ce_s, heap) *lhsc = NULL;
struct constraint_expr rhsc; struct constraint_expr rhsc;
unsigned int j; unsigned int j;
struct constraint_expr *lhsp; struct constraint_expr *lhsp;
tree arg;
call_expr_arg_iterator iter;
get_constraint_for (lhs, &lhsc);
/* If this is a nested function then it can return anything. */
if (CALL_EXPR_STATIC_CHAIN (call))
{
rhsc.var = anything_id; rhsc.var = anything_id;
rhsc.offset = 0; rhsc.offset = 0;
rhsc.type = ADDRESSOF; rhsc.type = ADDRESSOF;
get_constraint_for (lhs, &lhsc);
for (j = 0; VEC_iterate (ce_s, lhsc, j, lhsp); j++) for (j = 0; VEC_iterate (ce_s, lhsc, j, lhsp); j++)
process_constraint_1 (new_constraint (*lhsp, rhsc), true); process_constraint_1 (new_constraint (*lhsp, rhsc), true);
VEC_free (ce_s, heap, lhsc); VEC_free (ce_s, heap, lhsc);
return;
}
/* May return addresses of globals. */
rhsc.var = nonlocal_id;
rhsc.offset = 0;
rhsc.type = ADDRESSOF;
for (j = 0; VEC_iterate (ce_s, lhsc, j, lhsp); j++)
process_constraint_1 (new_constraint (*lhsp, rhsc), true);
/* May return arguments. */
FOR_EACH_CALL_EXPR_ARG (arg, iter, call)
if (could_have_pointers (arg))
{
VEC(ce_s, heap) *argc = NULL;
struct constraint_expr *argp;
int i;
get_constraint_for (arg, &argc);
for (i = 0; VEC_iterate (ce_s, argc, i, argp); i++)
for (j = 0; VEC_iterate (ce_s, lhsc, j, lhsp); j++)
process_constraint_1 (new_constraint (*lhsp, *argp), true);
VEC_free (ce_s, heap, argc);
}
VEC_free (ce_s, heap, lhsc);
} }
/* Walk statement T setting up aliasing constraints according to the /* Walk statement T setting up aliasing constraints according to the
...@@ -3636,10 +3710,12 @@ handle_lhs_call (tree lhs) ...@@ -3636,10 +3710,12 @@ handle_lhs_call (tree lhs)
static void static void
find_func_aliases (tree origt) find_func_aliases (tree origt)
{ {
tree t = origt; tree call, t = origt;
VEC(ce_s, heap) *lhsc = NULL; VEC(ce_s, heap) *lhsc = NULL;
VEC(ce_s, heap) *rhsc = NULL; VEC(ce_s, heap) *rhsc = NULL;
struct constraint_expr *c; struct constraint_expr *c;
enum escape_type stmt_escape_type;
int flags;
if (TREE_CODE (t) == RETURN_EXPR && TREE_OPERAND (t, 0)) if (TREE_CODE (t) == RETURN_EXPR && TREE_OPERAND (t, 0))
t = TREE_OPERAND (t, 0); t = TREE_OPERAND (t, 0);
...@@ -3688,17 +3764,26 @@ find_func_aliases (tree origt) ...@@ -3688,17 +3764,26 @@ find_func_aliases (tree origt)
In non-ipa mode, we need to generate constraints for each In non-ipa mode, we need to generate constraints for each
pointer passed by address. */ pointer passed by address. */
else if (((TREE_CODE (t) == GIMPLE_MODIFY_STMT else if ((call = get_call_expr_in (t)) != NULL_TREE
&& TREE_CODE (GIMPLE_STMT_OPERAND (t, 1)) == CALL_EXPR && !((flags = call_expr_flags (call))
&& !(call_expr_flags (GIMPLE_STMT_OPERAND (t, 1))
& (ECF_MALLOC | ECF_MAY_BE_ALLOCA))) & (ECF_MALLOC | ECF_MAY_BE_ALLOCA)))
|| (TREE_CODE (t) == CALL_EXPR
&& !(call_expr_flags (t)
& (ECF_MALLOC | ECF_MAY_BE_ALLOCA)))))
{ {
if (!in_ipa_mode) if (!in_ipa_mode)
{ {
if (TREE_CODE (t) == GIMPLE_MODIFY_STMT) /* Const functions can return their arguments and addresses
of global memory but not of escaped memory. */
if (flags & ECF_CONST)
{
if (TREE_CODE (t) == GIMPLE_MODIFY_STMT
&& could_have_pointers (GIMPLE_STMT_OPERAND (t, 1)))
handle_const_call (t);
}
/* Pure functions can return addresses in and of memory
reachable from their arguments, but they are not an escape
point for reachable memory of their arguments. But as we
do not compute call-used memory separately we cannot do
something special here. */
else if (TREE_CODE (t) == GIMPLE_MODIFY_STMT)
{ {
handle_rhs_call (GIMPLE_STMT_OPERAND (t, 1)); handle_rhs_call (GIMPLE_STMT_OPERAND (t, 1));
if (could_have_pointers (GIMPLE_STMT_OPERAND (t, 1))) if (could_have_pointers (GIMPLE_STMT_OPERAND (t, 1)))
...@@ -3893,6 +3978,57 @@ find_func_aliases (tree origt) ...@@ -3893,6 +3978,57 @@ find_func_aliases (tree origt)
get_varinfo (c->var)->no_tbaa_pruning = true; get_varinfo (c->var)->no_tbaa_pruning = true;
} }
stmt_escape_type = is_escape_site (t);
if (stmt_escape_type == ESCAPE_STORED_IN_GLOBAL)
{
tree rhs;
gcc_assert (TREE_CODE (t) == GIMPLE_MODIFY_STMT);
rhs = GIMPLE_STMT_OPERAND (t, 1);
if (TREE_CODE (rhs) == ADDR_EXPR)
{
tree base = get_base_address (TREE_OPERAND (rhs, 0));
if (base
&& (!DECL_P (base)
|| !is_global_var (base)))
make_escape_constraint (rhs);
}
else if (TREE_CODE (rhs) == SSA_NAME
&& POINTER_TYPE_P (TREE_TYPE (rhs)))
make_escape_constraint (rhs);
else if (could_have_pointers (rhs))
make_escape_constraint (rhs);
}
else if (stmt_escape_type == ESCAPE_BAD_CAST)
{
tree rhs;
gcc_assert (TREE_CODE (t) == GIMPLE_MODIFY_STMT);
rhs = GIMPLE_STMT_OPERAND (t, 1);
gcc_assert (CONVERT_EXPR_P (rhs)
|| TREE_CODE (rhs) == VIEW_CONVERT_EXPR);
rhs = TREE_OPERAND (rhs, 0);
make_escape_constraint (rhs);
}
else if (stmt_escape_type == ESCAPE_TO_ASM)
{
tree link;
int i;
for (i = 0, link = ASM_OUTPUTS (t); link; i++, link = TREE_CHAIN (link))
{
tree op = TREE_VALUE (link);
if (op && could_have_pointers (op))
/* Strictly we'd only need the constraints from ESCAPED and
NONLOCAL. */
make_escape_constraint (op);
}
for (i = 0, link = ASM_INPUTS (t); link; i++, link = TREE_CHAIN (link))
{
tree op = TREE_VALUE (link);
if (op && could_have_pointers (op))
/* Strictly we'd only need the constraint to ESCAPED. */
make_escape_constraint (op);
}
}
/* After promoting variables and computing aliasing we will /* After promoting variables and computing aliasing we will
need to re-scan most statements. FIXME: Try to minimize the need to re-scan most statements. FIXME: Try to minimize the
number of statements re-scanned. It's not really necessary to number of statements re-scanned. It's not really necessary to
...@@ -4118,9 +4254,10 @@ push_fields_onto_fieldstack (tree type, VEC(fieldoff_s,heap) **fieldstack, ...@@ -4118,9 +4254,10 @@ push_fields_onto_fieldstack (tree type, VEC(fieldoff_s,heap) **fieldstack,
return count; return count;
} }
/* Create a constraint from ANYTHING variable to VI. */ /* Create a constraint ID = &FROM. */
static void static void
make_constraint_from_anything (varinfo_t vi) make_constraint_from (varinfo_t vi, int from)
{ {
struct constraint_expr lhs, rhs; struct constraint_expr lhs, rhs;
...@@ -4128,12 +4265,19 @@ make_constraint_from_anything (varinfo_t vi) ...@@ -4128,12 +4265,19 @@ make_constraint_from_anything (varinfo_t vi)
lhs.offset = 0; lhs.offset = 0;
lhs.type = SCALAR; lhs.type = SCALAR;
rhs.var = anything_id; rhs.var = from;
rhs.offset = 0; rhs.offset = 0;
rhs.type = ADDRESSOF; rhs.type = ADDRESSOF;
process_constraint (new_constraint (lhs, rhs)); process_constraint (new_constraint (lhs, rhs));
} }
/* Create a constraint from ANYTHING variable to VI. */
static void
make_constraint_from_anything (varinfo_t vi)
{
make_constraint_from (vi, anything_id);
}
/* 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. */
...@@ -4478,7 +4622,7 @@ intra_create_variable_infos (void) ...@@ -4478,7 +4622,7 @@ intra_create_variable_infos (void)
struct constraint_expr lhs, rhs; 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
= ANYTHING or a dummy variable if flag_argument_noalias is set. */ = NONLOCAL or a dummy variable if flag_argument_noalias is set. */
for (t = DECL_ARGUMENTS (current_function_decl); t; t = TREE_CHAIN (t)) for (t = DECL_ARGUMENTS (current_function_decl); t; t = TREE_CHAIN (t))
{ {
varinfo_t p; varinfo_t p;
...@@ -4539,7 +4683,7 @@ intra_create_variable_infos (void) ...@@ -4539,7 +4683,7 @@ intra_create_variable_infos (void)
varinfo_t arg_vi = get_vi_for_tree (t); varinfo_t arg_vi = get_vi_for_tree (t);
for (p = arg_vi; p; p = p->next) for (p = arg_vi; p; p = p->next)
make_constraint_from_anything (p); make_constraint_from (p, nonlocal_id);
} }
} }
} }
...@@ -4794,7 +4938,9 @@ find_what_p_points_to (tree p) ...@@ -4794,7 +4938,9 @@ find_what_p_points_to (tree p)
aliases. */ aliases. */
if (vi->id == nothing_id) if (vi->id == nothing_id)
pi->pt_null = 1; pi->pt_null = 1;
else if (vi->id == anything_id) else if (vi->id == anything_id
|| vi->id == nonlocal_id
|| vi->id == escaped_id)
was_pt_anything = 1; was_pt_anything = 1;
else if (vi->id == readonly_id) else if (vi->id == readonly_id)
was_pt_anything = 1; was_pt_anything = 1;
...@@ -4843,42 +4989,23 @@ find_what_p_points_to (tree p) ...@@ -4843,42 +4989,23 @@ find_what_p_points_to (tree p)
return false; return false;
} }
/* Mark everything that p points to as call clobbered. Returns true /* Mark the ESCAPED solution as call clobbered. Returns false if
if everything is done and false if all addressable variables need to pt_anything escaped which needs all locals that have their address
be clobbered because p points to anything. */ taken marked call clobbered as well. */
bool bool
clobber_what_p_points_to (tree p) clobber_what_escaped (void)
{ {
tree lookup_p = p;
varinfo_t vi; varinfo_t vi;
struct ptr_info_def *pi;
unsigned int i; unsigned int i;
bitmap_iterator bi; bitmap_iterator bi;
if (!have_alias_info) if (!have_alias_info)
return false; return false;
/* For parameters, get at the points-to set for the actual parm
decl. */
if (TREE_CODE (p) == SSA_NAME
&& TREE_CODE (SSA_NAME_VAR (p)) == PARM_DECL
&& SSA_NAME_IS_DEFAULT_DEF (p))
lookup_p = SSA_NAME_VAR (p);
vi = lookup_vi_for_tree (lookup_p);
if (!vi)
return false;
/* We are asking for the points-to solution of pointers. */
gcc_assert (!vi->is_artificial_var
&& vi->size == vi->fullsize);
pi = get_ptr_info (p);
/* This variable may have been collapsed, let's get the real /* This variable may have been collapsed, let's get the real
variable. */ variable for escaped_id. */
vi = get_varinfo (find (vi->id)); vi = get_varinfo (find (escaped_id));
/* Mark variables in the solution call-clobbered. */ /* Mark variables in the solution call-clobbered. */
EXECUTE_IF_SET_IN_BITMAP (vi->solution, 0, i, bi) EXECUTE_IF_SET_IN_BITMAP (vi->solution, 0, i, bi)
...@@ -4903,12 +5030,13 @@ clobber_what_p_points_to (tree p) ...@@ -4903,12 +5030,13 @@ clobber_what_p_points_to (tree p)
|| TREE_CODE (vi->decl) == PARM_DECL || TREE_CODE (vi->decl) == PARM_DECL
|| TREE_CODE (vi->decl) == RESULT_DECL) || TREE_CODE (vi->decl) == RESULT_DECL)
&& !unmodifiable_var_p (vi->decl)) && !unmodifiable_var_p (vi->decl))
mark_call_clobbered (vi->decl, pi->escape_mask); mark_call_clobbered (vi->decl, ESCAPE_TO_CALL);
} }
return true; return true;
} }
/* Dump points-to information to OUTFILE. */ /* Dump points-to information to OUTFILE. */
void void
...@@ -4959,20 +5087,19 @@ init_base_vars (void) ...@@ -4959,20 +5087,19 @@ init_base_vars (void)
/* Create the NULL variable, used to represent that a variable points /* Create the NULL variable, used to represent that a variable points
to NULL. */ to NULL. */
nothing_tree = create_tmp_var_raw (void_type_node, "NULL"); nothing_tree = create_tmp_var_raw (void_type_node, "NULL");
var_nothing = new_var_info (nothing_tree, 0, "NULL"); var_nothing = new_var_info (nothing_tree, nothing_id, "NULL");
insert_vi_for_tree (nothing_tree, var_nothing); insert_vi_for_tree (nothing_tree, var_nothing);
var_nothing->is_artificial_var = 1; var_nothing->is_artificial_var = 1;
var_nothing->offset = 0; var_nothing->offset = 0;
var_nothing->size = ~0; var_nothing->size = ~0;
var_nothing->fullsize = ~0; var_nothing->fullsize = ~0;
var_nothing->is_special_var = 1; var_nothing->is_special_var = 1;
nothing_id = 0;
VEC_safe_push (varinfo_t, heap, varmap, var_nothing); VEC_safe_push (varinfo_t, heap, varmap, var_nothing);
/* Create the ANYTHING variable, used to represent that a variable /* Create the ANYTHING variable, used to represent that a variable
points to some unknown piece of memory. */ points to some unknown piece of memory. */
anything_tree = create_tmp_var_raw (void_type_node, "ANYTHING"); anything_tree = create_tmp_var_raw (void_type_node, "ANYTHING");
var_anything = new_var_info (anything_tree, 1, "ANYTHING"); var_anything = new_var_info (anything_tree, anything_id, "ANYTHING");
insert_vi_for_tree (anything_tree, var_anything); insert_vi_for_tree (anything_tree, var_anything);
var_anything->is_artificial_var = 1; var_anything->is_artificial_var = 1;
var_anything->size = ~0; var_anything->size = ~0;
...@@ -4980,7 +5107,6 @@ init_base_vars (void) ...@@ -4980,7 +5107,6 @@ init_base_vars (void)
var_anything->next = NULL; var_anything->next = NULL;
var_anything->fullsize = ~0; var_anything->fullsize = ~0;
var_anything->is_special_var = 1; var_anything->is_special_var = 1;
anything_id = 1;
/* Anything points to anything. This makes deref constraints just /* Anything points to anything. This makes deref constraints just
work in the presence of linked list and other p = *p type loops, work in the presence of linked list and other p = *p type loops,
...@@ -5001,7 +5127,7 @@ init_base_vars (void) ...@@ -5001,7 +5127,7 @@ init_base_vars (void)
/* Create the READONLY variable, used to represent that a variable /* Create the READONLY variable, used to represent that a variable
points to readonly memory. */ points to readonly memory. */
readonly_tree = create_tmp_var_raw (void_type_node, "READONLY"); readonly_tree = create_tmp_var_raw (void_type_node, "READONLY");
var_readonly = new_var_info (readonly_tree, 2, "READONLY"); var_readonly = new_var_info (readonly_tree, readonly_id, "READONLY");
var_readonly->is_artificial_var = 1; var_readonly->is_artificial_var = 1;
var_readonly->offset = 0; var_readonly->offset = 0;
var_readonly->size = ~0; var_readonly->size = ~0;
...@@ -5009,7 +5135,6 @@ init_base_vars (void) ...@@ -5009,7 +5135,6 @@ init_base_vars (void)
var_readonly->next = NULL; var_readonly->next = NULL;
var_readonly->is_special_var = 1; var_readonly->is_special_var = 1;
insert_vi_for_tree (readonly_tree, var_readonly); insert_vi_for_tree (readonly_tree, var_readonly);
readonly_id = 2;
VEC_safe_push (varinfo_t, heap, varmap, var_readonly); VEC_safe_push (varinfo_t, heap, varmap, var_readonly);
/* readonly memory points to anything, in order to make deref /* readonly memory points to anything, in order to make deref
...@@ -5020,15 +5145,58 @@ init_base_vars (void) ...@@ -5020,15 +5145,58 @@ init_base_vars (void)
lhs.var = readonly_id; lhs.var = readonly_id;
lhs.offset = 0; lhs.offset = 0;
rhs.type = ADDRESSOF; rhs.type = ADDRESSOF;
rhs.var = anything_id; rhs.var = readonly_id; /* FIXME */
rhs.offset = 0; rhs.offset = 0;
process_constraint (new_constraint (lhs, rhs));
/* Create the ESCAPED variable, used to represent the set of escaped
memory. */
escaped_tree = create_tmp_var_raw (void_type_node, "ESCAPED");
var_escaped = new_var_info (escaped_tree, escaped_id, "ESCAPED");
insert_vi_for_tree (escaped_tree, var_escaped);
var_escaped->is_artificial_var = 1;
var_escaped->offset = 0;
var_escaped->size = ~0;
var_escaped->fullsize = ~0;
var_escaped->is_special_var = 0;
VEC_safe_push (varinfo_t, heap, varmap, var_escaped);
gcc_assert (VEC_index (varinfo_t, varmap, 3) == var_escaped);
/* ESCAPED = *ESCAPED, because escaped is may-deref'd at calls, etc. */
lhs.type = SCALAR;
lhs.var = escaped_id;
lhs.offset = 0;
rhs.type = DEREF;
rhs.var = escaped_id;
rhs.offset = 0;
process_constraint_1 (new_constraint (lhs, rhs), true);
/* Create the NONLOCAL variable, used to represent the set of nonlocal
memory. */
nonlocal_tree = create_tmp_var_raw (void_type_node, "NONLOCAL");
var_nonlocal = new_var_info (nonlocal_tree, nonlocal_id, "NONLOCAL");
insert_vi_for_tree (nonlocal_tree, var_nonlocal);
var_nonlocal->is_artificial_var = 1;
var_nonlocal->offset = 0;
var_nonlocal->size = ~0;
var_nonlocal->fullsize = ~0;
var_nonlocal->is_special_var = 1;
VEC_safe_push (varinfo_t, heap, varmap, var_nonlocal);
/* Nonlocal memory points to escaped (which includes nonlocal),
in order to make deref easier. */
lhs.type = SCALAR;
lhs.var = nonlocal_id;
lhs.offset = 0;
rhs.type = ADDRESSOF;
rhs.var = escaped_id;
rhs.offset = 0;
process_constraint (new_constraint (lhs, rhs)); process_constraint (new_constraint (lhs, rhs));
/* Create the INTEGER variable, used to represent that a variable points /* Create the INTEGER variable, used to represent that a variable points
to an INTEGER. */ to an INTEGER. */
integer_tree = create_tmp_var_raw (void_type_node, "INTEGER"); integer_tree = create_tmp_var_raw (void_type_node, "INTEGER");
var_integer = new_var_info (integer_tree, 3, "INTEGER"); var_integer = new_var_info (integer_tree, integer_id, "INTEGER");
insert_vi_for_tree (integer_tree, var_integer); insert_vi_for_tree (integer_tree, var_integer);
var_integer->is_artificial_var = 1; var_integer->is_artificial_var = 1;
var_integer->size = ~0; var_integer->size = ~0;
...@@ -5036,7 +5204,6 @@ init_base_vars (void) ...@@ -5036,7 +5204,6 @@ init_base_vars (void)
var_integer->offset = 0; var_integer->offset = 0;
var_integer->next = NULL; var_integer->next = NULL;
var_integer->is_special_var = 1; var_integer->is_special_var = 1;
integer_id = 3;
VEC_safe_push (varinfo_t, heap, varmap, var_integer); VEC_safe_push (varinfo_t, heap, varmap, var_integer);
/* INTEGER = ANYTHING, because we don't know where a dereference of /* INTEGER = ANYTHING, because we don't know where a dereference of
...@@ -5048,6 +5215,26 @@ init_base_vars (void) ...@@ -5048,6 +5215,26 @@ init_base_vars (void)
rhs.var = anything_id; rhs.var = anything_id;
rhs.offset = 0; rhs.offset = 0;
process_constraint (new_constraint (lhs, rhs)); process_constraint (new_constraint (lhs, rhs));
/* *ESCAPED = &ESCAPED. This is true because we have to assume
everything pointed to by escaped can also point to escaped. */
lhs.type = DEREF;
lhs.var = escaped_id;
lhs.offset = 0;
rhs.type = ADDRESSOF;
rhs.var = escaped_id;
rhs.offset = 0;
process_constraint_1 (new_constraint (lhs, rhs), true);
/* *ESCAPED = &NONLOCAL. This is true because we have to assume
everything pointed to by escaped can also point to nonlocal. */
lhs.type = DEREF;
lhs.var = escaped_id;
lhs.offset = 0;
rhs.type = ADDRESSOF;
rhs.var = nonlocal_id;
rhs.offset = 0;
process_constraint_1 (new_constraint (lhs, rhs), true);
} }
/* Initialize things necessary to perform PTA */ /* Initialize things necessary to perform PTA */
......
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