tree-ssa-structalias.c (callused_id, [...]): Add.

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

	* tree-ssa-structalias.c (callused_id, var_callused,
	callused_tree): Add.
	(handle_pure_call): New function.
	(find_func_aliases): Call it.
	(find_what_p_points_to): Handle the call-used set.
	(clobber_what_escaped): Likewise.
	(compute_call_used_vars): New function.
	(init_base_vars): Init the call-used variable.
	(do_sd_constraint): Do not propagate the solution from CALLUSED
	but use CALLUSED as a placeholder.
	(solve_graph): Likewise.
	* tree-flow-inline.h (gimple_call_used_vars): New function.
	* tree-flow.h (struct gimple_df): Add call_used_vars bitmap.
	(compute_call_used_vars): Declare.
	* tree-ssa-alias.c (set_initial_properties): Call
	compute_call_used_vars.
	(reset_alias_info): Clear call-used variables.
	(add_call_clobber_ops): Assert we are not called for const/pure
	functions.  Remove handling of them.
	(add_call_read_ops): Handle pure functions by adding the
	call-used set of variables as VUSEs.
	* tree-ssa.c (init_tree_ssa): Allocate call-used bitmap.
	(delete_tree_ssa): Free it.
	* tree-dfa.c (remove_referenced_var): Clear the var from the
	call-used bitmap.

	* gcc.dg/tree-ssa/pr24287.c: Remove XFAIL.

From-SVN: r137222
This commit is contained in:
Richard Guenther 2008-06-28 13:17:20 +00:00 committed by Richard Biener
parent ff1c393bd3
commit 15c151967d
10 changed files with 249 additions and 35 deletions

View file

@ -1,3 +1,31 @@
2008-06-28 Richard Guenther <rguenther@suse.de>
* tree-ssa-structalias.c (callused_id, var_callused,
callused_tree): Add.
(handle_pure_call): New function.
(find_func_aliases): Call it.
(find_what_p_points_to): Handle the call-used set.
(clobber_what_escaped): Likewise.
(compute_call_used_vars): New function.
(init_base_vars): Init the call-used variable.
(do_sd_constraint): Do not propagate the solution from CALLUSED
but use CALLUSED as a placeholder.
(solve_graph): Likewise.
* tree-flow-inline.h (gimple_call_used_vars): New function.
* tree-flow.h (struct gimple_df): Add call_used_vars bitmap.
(compute_call_used_vars): Declare.
* tree-ssa-alias.c (set_initial_properties): Call
compute_call_used_vars.
(reset_alias_info): Clear call-used variables.
(add_call_clobber_ops): Assert we are not called for const/pure
functions. Remove handling of them.
(add_call_read_ops): Handle pure functions by adding the
call-used set of variables as VUSEs.
* tree-ssa.c (init_tree_ssa): Allocate call-used bitmap.
(delete_tree_ssa): Free it.
* tree-dfa.c (remove_referenced_var): Clear the var from the
call-used bitmap.
2008-06-28 Kai Tietz <kai.tietz@onevision.com>
* tree.c (build_varargs_function_type_list): New.

View file

@ -1,3 +1,7 @@
2008-06-28 Richard Guenther <rguenther@suse.de>
* gcc.dg/tree-ssa/pr24287.c: Remove XFAIL.
2008-06-27 Mark Mitchell <mark@codesourcery.com>
* g++.dg/abi/arm_cxa_vec2.C: New test.

View file

@ -21,5 +21,5 @@ int g(void)
link_error ();
return t2 == 2;
}
/* { dg-final { scan-tree-dump-times "link_error" 0 "optimized" { xfail *-*-* } } } */
/* { dg-final { scan-tree-dump-times "link_error" 0 "optimized" } } */
/* { dg-final { cleanup-tree-dump "optimized" } } */

View file

@ -746,6 +746,7 @@ remove_referenced_var (tree var)
unsigned int uid = DECL_UID (var);
clear_call_clobbered (var);
bitmap_clear_bit (gimple_call_used_vars (cfun), uid);
if ((v_ann = var_ann (var)))
{
/* Preserve var_anns of globals, but clear their alias info. */

View file

@ -66,6 +66,15 @@ gimple_call_clobbered_vars (const struct function *fun)
return fun->gimple_df->call_clobbered_vars;
}
/* Call-used variables in the function. If bit I is set, then
REFERENCED_VARS (I) is call-used at pure function call-sites. */
static inline bitmap
gimple_call_used_vars (const struct function *fun)
{
gcc_assert (fun && fun->gimple_df);
return fun->gimple_df->call_used_vars;
}
/* Array of all variables referenced in the function. */
static inline htab_t
gimple_referenced_vars (const struct function *fun)

View file

@ -162,6 +162,10 @@ struct gimple_df GTY(())
REFERENCED_VARS (I) is call-clobbered. */
bitmap call_clobbered_vars;
/* Call-used variables in the function. If bit I is set, then
REFERENCED_VARS (I) is call-used at pure function call-sites. */
bitmap call_used_vars;
/* Addressable variables in the function. If bit I is set, then
REFERENCED_VARS (I) has had its address taken. Note that
CALL_CLOBBERED_VARS and ADDRESSABLE_VARS are not related. An
@ -1174,6 +1178,7 @@ tree gimple_fold_indirect_ref (tree);
/* In tree-ssa-structalias.c */
bool find_what_p_points_to (tree);
bool clobber_what_escaped (void);
void compute_call_used_vars (void);
/* In tree-ssa-live.c */
extern void remove_unused_locals (void);

View file

@ -505,7 +505,7 @@ compute_tag_properties (void)
VEC_free (tree, heap, taglist);
}
/* Set up the initial variable clobbers and globalness.
/* Set up the initial variable clobbers, call-uses and globalness.
When this function completes, only tags whose aliases need to be
clobbered will be set clobbered. Tags clobbered because they
contain call clobbered vars are handled in compute_tag_properties. */
@ -543,6 +543,8 @@ set_initial_properties (struct alias_info *ai)
pt_anything_mask |= ESCAPE_TO_CALL;
}
compute_call_used_vars ();
for (i = 0; VEC_iterate (tree, ai->processed_ptrs, i, ptr); i++)
{
struct ptr_info_def *pi = SSA_NAME_PTR_INFO (ptr);
@ -2000,6 +2002,9 @@ reset_alias_info (void)
/* There should be no call-clobbered variable left. */
gcc_assert (bitmap_empty_p (gimple_call_clobbered_vars (cfun)));
/* Clear the call-used variables. */
bitmap_clear (gimple_call_used_vars (cfun));
/* Clear flow-sensitive points-to information from each SSA name. */
for (i = 1; i < num_ssa_names; i++)
{

View file

@ -1660,7 +1660,10 @@ add_call_clobber_ops (tree stmt, tree callee)
bitmap_iterator bi;
stmt_ann_t s_ann = stmt_ann (stmt);
bitmap not_read_b, not_written_b;
tree call = get_call_expr_in (stmt);
gcc_assert (!(call_expr_flags (call) & (ECF_PURE | ECF_CONST)));
/* If we created .GLOBAL_VAR earlier, just use it. */
if (gimple_global_var (cfun))
{
@ -1674,12 +1677,10 @@ add_call_clobber_ops (tree stmt, tree callee)
or write that variable. */
not_read_b = callee ? ipa_reference_get_not_read_global (callee) : NULL;
not_written_b = callee ? ipa_reference_get_not_written_global (callee) : NULL;
/* Add a VDEF operand for every call clobbered variable. */
EXECUTE_IF_SET_IN_BITMAP (gimple_call_clobbered_vars (cfun), 0, u, bi)
{
tree var = referenced_var_lookup (u);
unsigned int escape_mask = var_ann (var)->escape_mask;
tree real_var = var;
bool not_read;
bool not_written;
@ -1697,24 +1698,6 @@ add_call_clobber_ops (tree stmt, tree callee)
/* See if this variable is really clobbered by this function. */
/* Trivial case: Things escaping only to pure/const are not
clobbered by non-pure-const, and only read by pure/const. */
if ((escape_mask & ~(ESCAPE_TO_PURE_CONST)) == 0)
{
tree call = get_call_expr_in (stmt);
if (call_expr_flags (call) & (ECF_CONST | ECF_PURE))
{
add_virtual_operand (var, s_ann, opf_use, NULL, 0, -1, true);
clobber_stats.unescapable_clobbers_avoided++;
continue;
}
else
{
clobber_stats.unescapable_clobbers_avoided++;
continue;
}
}
if (not_written)
{
clobber_stats.static_write_clobbers_avoided++;
@ -1739,18 +1722,47 @@ add_call_read_ops (tree stmt, tree callee)
bitmap_iterator bi;
stmt_ann_t s_ann = stmt_ann (stmt);
bitmap not_read_b;
tree call = get_call_expr_in (stmt);
/* if the function is not pure, it may reference memory. Add
a VUSE for .GLOBAL_VAR if it has been created. See add_referenced_var
for the heuristic used to decide whether to create .GLOBAL_VAR. */
/* Const functions do not reference memory. */
if (call_expr_flags (call) & ECF_CONST)
return;
not_read_b = callee ? ipa_reference_get_not_read_global (callee) : NULL;
/* For pure functions we compute non-escaped uses separately. */
if (call_expr_flags (call) & ECF_PURE)
EXECUTE_IF_SET_IN_BITMAP (gimple_call_used_vars (cfun), 0, u, bi)
{
tree var = referenced_var_lookup (u);
tree real_var = var;
bool not_read;
if (unmodifiable_var_p (var))
continue;
not_read = not_read_b
? bitmap_bit_p (not_read_b, DECL_UID (real_var))
: false;
clobber_stats.readonly_clobbers++;
/* See if this variable is really used by this function. */
if (!not_read)
add_virtual_operand (var, s_ann, opf_use, NULL, 0, -1, true);
else
clobber_stats.static_readonly_clobbers_avoided++;
}
/* Add a VUSE for .GLOBAL_VAR if it has been created. See
add_referenced_var for the heuristic used to decide whether to
create .GLOBAL_VAR. */
if (gimple_global_var (cfun))
{
tree var = gimple_global_var (cfun);
add_virtual_operand (var, s_ann, opf_use, NULL, 0, -1, true);
return;
}
not_read_b = callee ? ipa_reference_get_not_read_global (callee) : NULL;
/* Add a VUSE for each call-clobbered variable. */
EXECUTE_IF_SET_IN_BITMAP (gimple_call_clobbered_vars (cfun), 0, u, bi)

View file

@ -296,7 +296,7 @@ get_varinfo_fc (unsigned int n)
/* 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 };
escaped_id = 3, nonlocal_id = 4, callused_id = 5, integer_id = 6 };
/* Variable that represents the unknown pointer. */
static varinfo_t var_anything;
@ -318,6 +318,10 @@ static tree escaped_tree;
static varinfo_t var_nonlocal;
static tree nonlocal_tree;
/* Variable that represents call-used memory. */
static varinfo_t var_callused;
static tree callused_tree;
/* Variable that represents integers. This is used for when people do things
like &0->a.b. */
static varinfo_t var_integer;
@ -1429,11 +1433,13 @@ do_sd_constraint (constraint_graph_t graph, constraint_t c,
if (get_varinfo (t)->is_special_var)
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
the set. Use ESCAPED as representative instead.
Same for CALLUSED. */
else if ((get_varinfo (t)->id == escaped_id
|| get_varinfo (t)->id == callused_id)
&& !bitmap_bit_p (sol, get_varinfo (t)->id))
{
bitmap_set_bit (sol, escaped_id);
bitmap_set_bit (sol, get_varinfo (t)->id);
flag = true;
}
else if (add_graph_edge (graph, lhs, t))
@ -2369,8 +2375,9 @@ solve_graph (constraint_graph_t graph)
solution_empty = bitmap_empty_p (solution);
if (!solution_empty
/* Do not propagate the ESCAPED solution. */
&& i != escaped_id)
/* Do not propagate the ESCAPED/CALLUSED solutions. */
&& i != escaped_id
&& i != callused_id)
{
bitmap_iterator bi;
@ -3702,6 +3709,61 @@ handle_const_call (tree stmt)
VEC_free (ce_s, heap, lhsc);
}
/* For non-IPA mode, generate constraints necessary for a call to a
pure function in statement STMT. */
static void
handle_pure_call (tree stmt)
{
tree call = get_call_expr_in (stmt);
tree arg;
call_expr_arg_iterator iter;
/* Memory reached from pointer arguments is call-used. */
FOR_EACH_CALL_EXPR_ARG (arg, iter, call)
if (could_have_pointers (arg))
make_constraint_to (callused_id, arg);
/* The static chain is used as well. */
if (CALL_EXPR_STATIC_CHAIN (call))
make_constraint_to (callused_id, CALL_EXPR_STATIC_CHAIN (call));
/* If the call returns a pointer it may point to reachable memory
from the arguments. */
if (TREE_CODE (stmt) == GIMPLE_MODIFY_STMT
&& could_have_pointers (GIMPLE_STMT_OPERAND (stmt, 0)))
{
tree lhs = GIMPLE_STMT_OPERAND (stmt, 0);
VEC(ce_s, heap) *lhsc = NULL;
struct constraint_expr rhsc;
struct constraint_expr *lhsp;
unsigned j;
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.offset = 0;
rhsc.type = ADDRESSOF;
for (j = 0; VEC_iterate (ce_s, lhsc, j, lhsp); j++)
process_constraint_1 (new_constraint (*lhsp, rhsc), true);
VEC_free (ce_s, heap, lhsc);
return;
}
/* Else just add the call-used memory here. Escaped variables
and globals will be dealt with in handle_lhs_call. */
rhsc.var = callused_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);
VEC_free (ce_s, heap, lhsc);
}
}
/* Walk statement T setting up aliasing constraints according to the
references found in T. This function is the main part of the
constraint builder. AI points to auxiliary alias information used
@ -3778,6 +3840,13 @@ find_func_aliases (tree origt)
&& could_have_pointers (GIMPLE_STMT_OPERAND (t, 1)))
handle_const_call (t);
}
else if (flags & ECF_PURE)
{
handle_pure_call (t);
if (TREE_CODE (t) == GIMPLE_MODIFY_STMT
&& could_have_pointers (GIMPLE_STMT_OPERAND (t, 1)))
handle_lhs_call (GIMPLE_STMT_OPERAND (t, 0));
}
/* 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
@ -4940,7 +5009,8 @@ find_what_p_points_to (tree p)
pi->pt_null = 1;
else if (vi->id == anything_id
|| vi->id == nonlocal_id
|| vi->id == escaped_id)
|| vi->id == escaped_id
|| vi->id == callused_id)
was_pt_anything = 1;
else if (vi->id == readonly_id)
was_pt_anything = 1;
@ -5007,6 +5077,15 @@ clobber_what_escaped (void)
variable for escaped_id. */
vi = get_varinfo (find (escaped_id));
/* If call-used memory escapes we need to include it in the
set of escaped variables. This can happen if a pure
function returns a pointer and this pointer escapes. */
if (bitmap_bit_p (vi->solution, callused_id))
{
varinfo_t cu_vi = get_varinfo (find (callused_id));
bitmap_ior_into (vi->solution, cu_vi->solution);
}
/* Mark variables in the solution call-clobbered. */
EXECUTE_IF_SET_IN_BITMAP (vi->solution, 0, i, bi)
{
@ -5036,6 +5115,54 @@ clobber_what_escaped (void)
return true;
}
/* Compute the call-used variables. */
void
compute_call_used_vars (void)
{
varinfo_t vi;
unsigned int i;
bitmap_iterator bi;
bool has_anything_id = false;
if (!have_alias_info)
return;
/* This variable may have been collapsed, let's get the real
variable for escaped_id. */
vi = get_varinfo (find (callused_id));
/* Mark variables in the solution call-clobbered. */
EXECUTE_IF_SET_IN_BITMAP (vi->solution, 0, i, bi)
{
varinfo_t vi = get_varinfo (i);
if (vi->is_artificial_var)
{
/* For anything_id and integer_id we need to make
all local addressable vars call-used. */
if (vi->id == anything_id
|| vi->id == integer_id)
has_anything_id = true;
}
/* Only artificial heap-vars are further interesting. */
if (vi->is_artificial_var && !vi->is_heap_var)
continue;
if ((TREE_CODE (vi->decl) == VAR_DECL
|| TREE_CODE (vi->decl) == PARM_DECL
|| TREE_CODE (vi->decl) == RESULT_DECL)
&& !unmodifiable_var_p (vi->decl))
bitmap_set_bit (gimple_call_used_vars (cfun), DECL_UID (vi->decl));
}
/* If anything is call-used, add all addressable locals to the set. */
if (has_anything_id)
bitmap_ior_into (gimple_call_used_vars (cfun),
gimple_addressable_vars (cfun));
}
/* Dump points-to information to OUTFILE. */
@ -5193,6 +5320,27 @@ init_base_vars (void)
rhs.offset = 0;
process_constraint (new_constraint (lhs, rhs));
/* Create the CALLUSED variable, used to represent the set of call-used
memory. */
callused_tree = create_tmp_var_raw (void_type_node, "CALLUSED");
var_callused = new_var_info (callused_tree, callused_id, "CALLUSED");
insert_vi_for_tree (callused_tree, var_callused);
var_callused->is_artificial_var = 1;
var_callused->offset = 0;
var_callused->size = ~0;
var_callused->fullsize = ~0;
var_callused->is_special_var = 0;
VEC_safe_push (varinfo_t, heap, varmap, var_callused);
/* CALLUSED = *CALLUSED, because call-used is may-deref'd at calls, etc. */
lhs.type = SCALAR;
lhs.var = callused_id;
lhs.offset = 0;
rhs.type = DEREF;
rhs.var = callused_id;
rhs.offset = 0;
process_constraint_1 (new_constraint (lhs, rhs), true);
/* Create the INTEGER variable, used to represent that a variable points
to an INTEGER. */
integer_tree = create_tmp_var_raw (void_type_node, "INTEGER");

View file

@ -937,6 +937,7 @@ init_tree_ssa (struct function *fn)
fn->gimple_df->default_defs = htab_create_ggc (20, uid_ssaname_map_hash,
uid_ssaname_map_eq, NULL);
fn->gimple_df->call_clobbered_vars = BITMAP_GGC_ALLOC ();
fn->gimple_df->call_used_vars = BITMAP_GGC_ALLOC ();
fn->gimple_df->addressable_vars = BITMAP_GGC_ALLOC ();
init_ssanames (fn, 0);
init_phinodes ();
@ -1009,6 +1010,7 @@ delete_tree_ssa (void)
htab_delete (cfun->gimple_df->default_defs);
cfun->gimple_df->default_defs = NULL;
cfun->gimple_df->call_clobbered_vars = NULL;
cfun->gimple_df->call_used_vars = NULL;
cfun->gimple_df->addressable_vars = NULL;
cfun->gimple_df->modified_noreturn_calls = NULL;
if (gimple_aliases_computed_p (cfun))