Commit d086d311 by Richard Guenther Committed by Richard Biener

gsstruct.def (GSS_CALL): New.

2010-04-12  Richard Guenther  <rguenther@suse.de>

	* gsstruct.def (GSS_CALL): New.
	* gimple.def (GIMPLE_CALL): Change to GSS_CALL.
	* gimple.h: Include tree-ssa-alias.h.
	(struct gimple_statement_call): New.
	(union gimple_statement_struct_d): Add gimple_call member.
	(gimple_call_reset_alias_info): Declare.
	(gimple_call_use_set): New function.
	(gimple_call_clobber_set): Likewise.
	* Makefile.in (GIMPLE_H): Add tree-ssa-alias.h.
	* gimple.c (gimple_call_reset_alias_info): New function.
	(gimple_build_call_1): Call it.
	* lto-streamer-in.c (input_gimple_stmt): Likewise.
	* tree-inline.c (remap_gimple_stmt): Likewise.
	(expand_call_inline): Remove callused handling.
	* cfgexpand.c (update_alias_info_with_stack_vars): Likewise.
	* tree-dfa.c (dump_variable): Likewise.
	* tree-parloops.c (parallelize_loops): Likewise.
	* tree-ssa.c (init_tree_ssa): Likewise.
	(delete_tree_ssa): Likewise.
	* tree-flow-inline.h (is_call_used): Remove.
	* tree-flow.h (struct gimple_df): Remove callused member.
	* tree-nrv.c (dest_safe_for_nrv_p): Adjust predicate.
	* tree-ssa-alias.c (dump_alias_info): Remove callused handling.
	(ref_maybe_used_by_call_p_1): Simplify.
	(call_may_clobber_ref_p_1): Likewise.
	* tree-ssa-structalias.c (compute_points_to_sets): Set
	the call stmt used and clobbered sets.
	* tree-tailcall.c (suitable_for_tail_opt_p): Adjust predicate.
	(find_tail_calls): Verify the tail call.

From-SVN: r158226
parent af961c7f
2010-04-12 Richard Guenther <rguenther@suse.de> 2010-04-12 Richard Guenther <rguenther@suse.de>
* gsstruct.def (GSS_CALL): New.
* gimple.def (GIMPLE_CALL): Change to GSS_CALL.
* gimple.h: Include tree-ssa-alias.h.
(struct gimple_statement_call): New.
(union gimple_statement_struct_d): Add gimple_call member.
(gimple_call_reset_alias_info): Declare.
(gimple_call_use_set): New function.
(gimple_call_clobber_set): Likewise.
* Makefile.in (GIMPLE_H): Add tree-ssa-alias.h.
* gimple.c (gimple_call_reset_alias_info): New function.
(gimple_build_call_1): Call it.
* lto-streamer-in.c (input_gimple_stmt): Likewise.
* tree-inline.c (remap_gimple_stmt): Likewise.
(expand_call_inline): Remove callused handling.
* cfgexpand.c (update_alias_info_with_stack_vars): Likewise.
* tree-dfa.c (dump_variable): Likewise.
* tree-parloops.c (parallelize_loops): Likewise.
* tree-ssa.c (init_tree_ssa): Likewise.
(delete_tree_ssa): Likewise.
* tree-flow-inline.h (is_call_used): Remove.
* tree-flow.h (struct gimple_df): Remove callused member.
* tree-nrv.c (dest_safe_for_nrv_p): Adjust predicate.
* tree-ssa-alias.c (dump_alias_info): Remove callused handling.
(ref_maybe_used_by_call_p_1): Simplify.
(call_may_clobber_ref_p_1): Likewise.
* tree-ssa-structalias.c (compute_points_to_sets): Set
the call stmt used and clobbered sets.
* tree-tailcall.c (suitable_for_tail_opt_p): Adjust predicate.
(find_tail_calls): Verify the tail call.
2010-04-12 Richard Guenther <rguenther@suse.de>
* ipa.c (cgraph_postorder): Adjust postorder to guarantee * ipa.c (cgraph_postorder): Adjust postorder to guarantee
single-iteration always-inline inlining. single-iteration always-inline inlining.
* ipa-inline.c (cgraph_mark_inline): Do not return anything. * ipa-inline.c (cgraph_mark_inline): Do not return anything.
......
...@@ -876,7 +876,8 @@ BASIC_BLOCK_H = basic-block.h $(BITMAP_H) sbitmap.h varray.h $(PARTITION_H) \ ...@@ -876,7 +876,8 @@ BASIC_BLOCK_H = basic-block.h $(BITMAP_H) sbitmap.h varray.h $(PARTITION_H) \
hard-reg-set.h $(PREDICT_H) vec.h $(FUNCTION_H) \ hard-reg-set.h $(PREDICT_H) vec.h $(FUNCTION_H) \
cfghooks.h $(OBSTACK_H) cfghooks.h $(OBSTACK_H)
GIMPLE_H = gimple.h gimple.def gsstruct.def pointer-set.h vec.h \ GIMPLE_H = gimple.h gimple.def gsstruct.def pointer-set.h vec.h \
$(GGC_H) $(BASIC_BLOCK_H) $(TM_H) $(TARGET_H) tree-ssa-operands.h $(GGC_H) $(BASIC_BLOCK_H) $(TM_H) $(TARGET_H) tree-ssa-operands.h \
tree-ssa-alias.h
GCOV_IO_H = gcov-io.h gcov-iov.h auto-host.h GCOV_IO_H = gcov-io.h gcov-iov.h auto-host.h
COVERAGE_H = coverage.h $(GCOV_IO_H) COVERAGE_H = coverage.h $(GCOV_IO_H)
DEMANGLE_H = $(srcdir)/../include/demangle.h DEMANGLE_H = $(srcdir)/../include/demangle.h
......
...@@ -198,6 +198,21 @@ gimple_build_return (tree retval) ...@@ -198,6 +198,21 @@ gimple_build_return (tree retval)
return s; return s;
} }
/* Reset alias information on call S. */
void
gimple_call_reset_alias_info (gimple s)
{
if (gimple_call_flags (s) & ECF_CONST)
memset (gimple_call_use_set (s), 0, sizeof (struct pt_solution));
else
pt_solution_reset (gimple_call_use_set (s));
if (gimple_call_flags (s) & (ECF_CONST|ECF_PURE|ECF_NOVOPS))
memset (gimple_call_clobber_set (s), 0, sizeof (struct pt_solution));
else
pt_solution_reset (gimple_call_clobber_set (s));
}
/* Helper for gimple_build_call, gimple_build_call_vec and /* Helper for gimple_build_call, gimple_build_call_vec and
gimple_build_call_from_tree. Build the basic components of a gimple_build_call_from_tree. Build the basic components of a
GIMPLE_CALL statement to function FN with NARGS arguments. */ GIMPLE_CALL statement to function FN with NARGS arguments. */
...@@ -209,6 +224,7 @@ gimple_build_call_1 (tree fn, unsigned nargs) ...@@ -209,6 +224,7 @@ gimple_build_call_1 (tree fn, unsigned nargs)
if (TREE_CODE (fn) == FUNCTION_DECL) if (TREE_CODE (fn) == FUNCTION_DECL)
fn = build_fold_addr_expr (fn); fn = build_fold_addr_expr (fn);
gimple_set_op (s, 1, fn); gimple_set_op (s, 1, fn);
gimple_call_reset_alias_info (s);
return s; return s;
} }
......
...@@ -122,7 +122,7 @@ DEFGSCODE(GIMPLE_ASM, "gimple_asm", GSS_ASM) ...@@ -122,7 +122,7 @@ DEFGSCODE(GIMPLE_ASM, "gimple_asm", GSS_ASM)
is_gimple_operand. is_gimple_operand.
CHAIN is the optional static chain link for nested functions. */ CHAIN is the optional static chain link for nested functions. */
DEFGSCODE(GIMPLE_CALL, "gimple_call", GSS_WITH_MEM_OPS) DEFGSCODE(GIMPLE_CALL, "gimple_call", GSS_CALL)
/* GIMPLE_RETURN <RETVAL> represents return statements. /* GIMPLE_RETURN <RETVAL> represents return statements.
......
...@@ -29,6 +29,7 @@ along with GCC; see the file COPYING3. If not see ...@@ -29,6 +29,7 @@ along with GCC; see the file COPYING3. If not see
#include "hard-reg-set.h" #include "hard-reg-set.h"
#include "basic-block.h" #include "basic-block.h"
#include "tree-ssa-operands.h" #include "tree-ssa-operands.h"
#include "tree-ssa-alias.h"
DEF_VEC_P(gimple); DEF_VEC_P(gimple);
DEF_VEC_ALLOC_P(gimple,heap); DEF_VEC_ALLOC_P(gimple,heap);
...@@ -390,6 +391,25 @@ struct GTY(()) gimple_statement_with_memory_ops ...@@ -390,6 +391,25 @@ struct GTY(()) gimple_statement_with_memory_ops
}; };
/* Call statements that take both memory and register operands. */
struct GTY(()) gimple_statement_call
{
/* [ WORD 1-8 ] */
struct gimple_statement_with_memory_ops_base membase;
/* [ WORD 9-12 ] */
struct pt_solution call_used;
struct pt_solution call_clobbered;
/* [ WORD 13 ]
Operand vector. NOTE! This must always be the last field
of this structure. In particular, this means that this
structure cannot be embedded inside another one. */
tree GTY((length ("%h.membase.opbase.gsbase.num_ops"))) op[1];
};
/* OpenMP statements (#pragma omp). */ /* OpenMP statements (#pragma omp). */
struct GTY(()) gimple_statement_omp { struct GTY(()) gimple_statement_omp {
...@@ -739,6 +759,7 @@ union GTY ((desc ("gimple_statement_structure (&%h)"))) gimple_statement_d { ...@@ -739,6 +759,7 @@ union GTY ((desc ("gimple_statement_structure (&%h)"))) gimple_statement_d {
struct gimple_statement_with_ops GTY ((tag ("GSS_WITH_OPS"))) gsops; struct gimple_statement_with_ops GTY ((tag ("GSS_WITH_OPS"))) gsops;
struct gimple_statement_with_memory_ops_base GTY ((tag ("GSS_WITH_MEM_OPS_BASE"))) gsmembase; struct gimple_statement_with_memory_ops_base GTY ((tag ("GSS_WITH_MEM_OPS_BASE"))) gsmembase;
struct gimple_statement_with_memory_ops GTY ((tag ("GSS_WITH_MEM_OPS"))) gsmem; struct gimple_statement_with_memory_ops GTY ((tag ("GSS_WITH_MEM_OPS"))) gsmem;
struct gimple_statement_call GTY ((tag ("GSS_CALL"))) gimple_call;
struct gimple_statement_omp GTY ((tag ("GSS_OMP"))) omp; struct gimple_statement_omp GTY ((tag ("GSS_OMP"))) omp;
struct gimple_statement_bind GTY ((tag ("GSS_BIND"))) gimple_bind; struct gimple_statement_bind GTY ((tag ("GSS_BIND"))) gimple_bind;
struct gimple_statement_catch GTY ((tag ("GSS_CATCH"))) gimple_catch; struct gimple_statement_catch GTY ((tag ("GSS_CATCH"))) gimple_catch;
...@@ -836,6 +857,7 @@ void gimple_seq_free (gimple_seq); ...@@ -836,6 +857,7 @@ void gimple_seq_free (gimple_seq);
void gimple_seq_add_seq (gimple_seq *, gimple_seq); void gimple_seq_add_seq (gimple_seq *, gimple_seq);
gimple_seq gimple_seq_copy (gimple_seq); gimple_seq gimple_seq_copy (gimple_seq);
int gimple_call_flags (const_gimple); int gimple_call_flags (const_gimple);
void gimple_call_reset_alias_info (gimple);
bool gimple_assign_copy_p (gimple); bool gimple_assign_copy_p (gimple);
bool gimple_assign_ssa_name_copy_p (gimple); bool gimple_assign_ssa_name_copy_p (gimple);
bool gimple_assign_single_p (gimple); bool gimple_assign_single_p (gimple);
...@@ -2200,6 +2222,28 @@ gimple_call_copy_flags (gimple dest_call, gimple orig_call) ...@@ -2200,6 +2222,28 @@ gimple_call_copy_flags (gimple dest_call, gimple orig_call)
} }
/* Return a pointer to the points-to solution for the set of call-used
variables of the call CALL. */
static inline struct pt_solution *
gimple_call_use_set (gimple call)
{
GIMPLE_CHECK (call, GIMPLE_CALL);
return &call->gimple_call.call_used;
}
/* Return a pointer to the points-to solution for the set of call-used
variables of the call CALL. */
static inline struct pt_solution *
gimple_call_clobber_set (gimple call)
{
GIMPLE_CHECK (call, GIMPLE_CALL);
return &call->gimple_call.call_clobbered;
}
/* Returns true if this is a GIMPLE_ASSIGN or a GIMPLE_CALL with a /* Returns true if this is a GIMPLE_ASSIGN or a GIMPLE_CALL with a
non-NULL lhs. */ non-NULL lhs. */
......
...@@ -29,6 +29,7 @@ DEFGSSTRUCT(GSS_BASE, gimple_statement_base, false) ...@@ -29,6 +29,7 @@ DEFGSSTRUCT(GSS_BASE, gimple_statement_base, false)
DEFGSSTRUCT(GSS_WITH_OPS, gimple_statement_with_ops, true) DEFGSSTRUCT(GSS_WITH_OPS, gimple_statement_with_ops, true)
DEFGSSTRUCT(GSS_WITH_MEM_OPS_BASE, gimple_statement_with_memory_ops_base, false) DEFGSSTRUCT(GSS_WITH_MEM_OPS_BASE, gimple_statement_with_memory_ops_base, false)
DEFGSSTRUCT(GSS_WITH_MEM_OPS, gimple_statement_with_memory_ops, true) DEFGSSTRUCT(GSS_WITH_MEM_OPS, gimple_statement_with_memory_ops, true)
DEFGSSTRUCT(GSS_CALL, gimple_statement_call, true)
DEFGSSTRUCT(GSS_ASM, gimple_statement_asm, true) DEFGSSTRUCT(GSS_ASM, gimple_statement_asm, true)
DEFGSSTRUCT(GSS_BIND, gimple_statement_bind, false) DEFGSSTRUCT(GSS_BIND, gimple_statement_bind, false)
DEFGSSTRUCT(GSS_PHI, gimple_statement_phi, false) DEFGSSTRUCT(GSS_PHI, gimple_statement_phi, false)
......
...@@ -1157,6 +1157,10 @@ input_gimple_stmt (struct lto_input_block *ib, struct data_in *data_in, ...@@ -1157,6 +1157,10 @@ input_gimple_stmt (struct lto_input_block *ib, struct data_in *data_in,
} }
} }
/* Reset alias information. */
if (code == GIMPLE_CALL)
gimple_call_reset_alias_info (stmt);
/* Fixup reference tree operands for substituted prevailing decls /* Fixup reference tree operands for substituted prevailing decls
with mismatched types. */ with mismatched types. */
maybe_fixup_decls (stmt); maybe_fixup_decls (stmt);
......
...@@ -284,8 +284,6 @@ dump_variable (FILE *file, tree var) ...@@ -284,8 +284,6 @@ dump_variable (FILE *file, tree var)
if (is_call_clobbered (var)) if (is_call_clobbered (var))
fprintf (file, ", call clobbered"); fprintf (file, ", call clobbered");
else if (is_call_used (var))
fprintf (file, ", call used");
if (ann && ann->noalias_state == NO_ALIAS) if (ann && ann->noalias_state == NO_ALIAS)
fprintf (file, ", NO_ALIAS (does not alias other NO_ALIAS symbols)"); fprintf (file, ", NO_ALIAS (does not alias other NO_ALIAS symbols)");
......
...@@ -633,15 +633,6 @@ is_call_clobbered (const_tree var) ...@@ -633,15 +633,6 @@ is_call_clobbered (const_tree var)
&& pt_solution_includes (&cfun->gimple_df->escaped, var))); && pt_solution_includes (&cfun->gimple_df->escaped, var)));
} }
/* Return true if VAR is used by function calls. */
static inline bool
is_call_used (const_tree var)
{
return (is_call_clobbered (var)
|| (may_be_aliased (var)
&& pt_solution_includes (&cfun->gimple_df->callused, var)));
}
/* ----------------------------------------------------------------------- */ /* ----------------------------------------------------------------------- */
/* The following set of routines are used to iterator over various type of /* The following set of routines are used to iterator over various type of
......
...@@ -56,9 +56,6 @@ struct GTY(()) gimple_df { ...@@ -56,9 +56,6 @@ struct GTY(()) gimple_df {
/* The PTA solution for the ESCAPED artificial variable. */ /* The PTA solution for the ESCAPED artificial variable. */
struct pt_solution escaped; struct pt_solution escaped;
/* The PTA solution for the CALLUSED artificial variable. */
struct pt_solution callused;
/* A map of decls to artificial ssa-names that point to the partition /* A map of decls to artificial ssa-names that point to the partition
of the decl. */ of the decl. */
struct pointer_map_t * GTY((skip(""))) decls_to_pointers; struct pointer_map_t * GTY((skip(""))) decls_to_pointers;
......
...@@ -1391,6 +1391,13 @@ remap_gimple_stmt (gimple stmt, copy_body_data *id) ...@@ -1391,6 +1391,13 @@ remap_gimple_stmt (gimple stmt, copy_body_data *id)
default: default:
break; break;
} }
/* Reset alias info.
??? By maintaining DECL_PT_UID this should not
be necessary, but the plan is to only maintain
it when IPA-PTA was run. It's not too easy to
detect this here ... */
gimple_call_reset_alias_info (copy);
} }
break; break;
...@@ -3724,12 +3731,9 @@ expand_call_inline (basic_block bb, gimple stmt, copy_body_data *id) ...@@ -3724,12 +3731,9 @@ expand_call_inline (basic_block bb, gimple stmt, copy_body_data *id)
cg_edge->frequency * REG_BR_PROB_BASE / CGRAPH_FREQ_BASE, cg_edge->frequency * REG_BR_PROB_BASE / CGRAPH_FREQ_BASE,
bb, return_block); bb, return_block);
/* Reset the escaped and callused solutions. */ /* Reset the escaped solution. */
if (cfun->gimple_df) if (cfun->gimple_df)
{ pt_solution_reset (&cfun->gimple_df->escaped);
pt_solution_reset (&cfun->gimple_df->escaped);
pt_solution_reset (&cfun->gimple_df->callused);
}
/* Clean up. */ /* Clean up. */
if (id->debug_map) if (id->debug_map)
......
...@@ -307,7 +307,7 @@ dest_safe_for_nrv_p (tree dest) ...@@ -307,7 +307,7 @@ dest_safe_for_nrv_p (tree dest)
if (TREE_CODE (dest) == SSA_NAME) if (TREE_CODE (dest) == SSA_NAME)
dest = SSA_NAME_VAR (dest); dest = SSA_NAME_VAR (dest);
if (is_call_used (dest)) if (is_call_clobbered (dest))
return false; return false;
return true; return true;
......
...@@ -1977,13 +1977,10 @@ parallelize_loops (void) ...@@ -1977,13 +1977,10 @@ parallelize_loops (void)
htab_delete (reduction_list); htab_delete (reduction_list);
/* Parallelization will cause new function calls to be inserted through /* Parallelization will cause new function calls to be inserted through
which local variables will escape. Reset the points-to solutions which local variables will escape. Reset the points-to solution
for ESCAPED and CALLUSED. */ for ESCAPED. */
if (changed) if (changed)
{ pt_solution_reset (&cfun->gimple_df->escaped);
pt_solution_reset (&cfun->gimple_df->escaped);
pt_solution_reset (&cfun->gimple_df->callused);
}
return changed; return changed;
} }
......
...@@ -336,8 +336,6 @@ dump_alias_info (FILE *file) ...@@ -336,8 +336,6 @@ dump_alias_info (FILE *file)
fprintf (file, "\nESCAPED"); fprintf (file, "\nESCAPED");
dump_points_to_solution (file, &cfun->gimple_df->escaped); dump_points_to_solution (file, &cfun->gimple_df->escaped);
fprintf (file, "\nCALLUSED");
dump_points_to_solution (file, &cfun->gimple_df->callused);
fprintf (file, "\n\nFlow-insensitive points-to information\n\n"); fprintf (file, "\n\nFlow-insensitive points-to information\n\n");
...@@ -1070,51 +1068,24 @@ ref_maybe_used_by_call_p_1 (gimple call, ao_ref *ref) ...@@ -1070,51 +1068,24 @@ ref_maybe_used_by_call_p_1 (gimple call, ao_ref *ref)
goto process_args; goto process_args;
} }
/* If the base variable is call-used or call-clobbered then /* Check if the base variable is call-used. */
it may be used. */ if (DECL_P (base))
if (flags & (ECF_PURE|ECF_CONST|ECF_LOOPING_CONST_OR_PURE|ECF_NOVOPS))
{ {
if (DECL_P (base)) if (pt_solution_includes (gimple_call_use_set (call), base))
{
if (is_call_used (base))
return true;
}
else if (INDIRECT_REF_P (base)
&& TREE_CODE (TREE_OPERAND (base, 0)) == SSA_NAME)
{
struct ptr_info_def *pi = SSA_NAME_PTR_INFO (TREE_OPERAND (base, 0));
if (!pi)
return true;
if (pt_solution_includes_global (&pi->pt)
|| pt_solutions_intersect (&cfun->gimple_df->callused, &pi->pt)
|| pt_solutions_intersect (&cfun->gimple_df->escaped, &pi->pt))
return true;
}
else
return true; return true;
} }
else else if (INDIRECT_REF_P (base)
&& TREE_CODE (TREE_OPERAND (base, 0)) == SSA_NAME)
{ {
if (DECL_P (base)) struct ptr_info_def *pi = SSA_NAME_PTR_INFO (TREE_OPERAND (base, 0));
{ if (!pi)
if (is_call_clobbered (base)) return true;
return true;
}
else if (INDIRECT_REF_P (base)
&& TREE_CODE (TREE_OPERAND (base, 0)) == SSA_NAME)
{
struct ptr_info_def *pi = SSA_NAME_PTR_INFO (TREE_OPERAND (base, 0));
if (!pi)
return true;
if (pt_solution_includes_global (&pi->pt) if (pt_solutions_intersect (gimple_call_use_set (call), &pi->pt))
|| pt_solutions_intersect (&cfun->gimple_df->escaped, &pi->pt))
return true;
}
else
return true; return true;
} }
else
return true;
/* Inspect call arguments for passed-by-value aliases. */ /* Inspect call arguments for passed-by-value aliases. */
process_args: process_args:
...@@ -1347,8 +1318,9 @@ call_may_clobber_ref_p_1 (gimple call, ao_ref *ref) ...@@ -1347,8 +1318,9 @@ call_may_clobber_ref_p_1 (gimple call, ao_ref *ref)
return false; return false;
} }
/* Check if the base variable is call-clobbered. */
if (DECL_P (base)) if (DECL_P (base))
return is_call_clobbered (base); return pt_solution_includes (gimple_call_clobber_set (call), base);
else if (INDIRECT_REF_P (base) else if (INDIRECT_REF_P (base)
&& TREE_CODE (TREE_OPERAND (base, 0)) == SSA_NAME) && TREE_CODE (TREE_OPERAND (base, 0)) == SSA_NAME)
{ {
...@@ -1356,8 +1328,7 @@ call_may_clobber_ref_p_1 (gimple call, ao_ref *ref) ...@@ -1356,8 +1328,7 @@ call_may_clobber_ref_p_1 (gimple call, ao_ref *ref)
if (!pi) if (!pi)
return true; return true;
return (pt_solution_includes_global (&pi->pt) return pt_solutions_intersect (gimple_call_clobber_set (call), &pi->pt);
|| pt_solutions_intersect (&cfun->gimple_df->escaped, &pi->pt));
} }
return true; return true;
......
...@@ -5480,6 +5480,7 @@ compute_points_to_sets (void) ...@@ -5480,6 +5480,7 @@ compute_points_to_sets (void)
basic_block bb; basic_block bb;
unsigned i; unsigned i;
varinfo_t vi; varinfo_t vi;
struct pt_solution callused;
timevar_push (TV_TREE_PTA); timevar_push (TV_TREE_PTA);
...@@ -5516,8 +5517,7 @@ compute_points_to_sets (void) ...@@ -5516,8 +5517,7 @@ compute_points_to_sets (void)
call-clobber analysis. */ call-clobber analysis. */
find_what_var_points_to (get_varinfo (escaped_id), find_what_var_points_to (get_varinfo (escaped_id),
&cfun->gimple_df->escaped); &cfun->gimple_df->escaped);
find_what_var_points_to (get_varinfo (callused_id), find_what_var_points_to (get_varinfo (callused_id), &callused);
&cfun->gimple_df->callused);
/* Make sure the ESCAPED solution (which is used as placeholder in /* Make sure the ESCAPED solution (which is used as placeholder in
other solutions) does not reference itself. This simplifies other solutions) does not reference itself. This simplifies
...@@ -5541,6 +5541,48 @@ compute_points_to_sets (void) ...@@ -5541,6 +5541,48 @@ compute_points_to_sets (void)
find_what_p_points_to (ptr); find_what_p_points_to (ptr);
} }
/* Compute the call-used/clobbered sets. */
FOR_EACH_BB (bb)
{
gimple_stmt_iterator gsi;
for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi))
{
gimple stmt = gsi_stmt (gsi);
struct pt_solution *pt;
if (!is_gimple_call (stmt))
continue;
pt = gimple_call_use_set (stmt);
if (gimple_call_flags (stmt) & ECF_CONST)
memset (pt, 0, sizeof (struct pt_solution));
else if (gimple_call_flags (stmt) & ECF_PURE)
{
/* For const calls we should now be able to compute the
call-used set per function. */
*pt = callused;
/* ??? ESCAPED can be empty even though NONLOCAL
always escaped. */
pt->nonlocal = 1;
pt->escaped = 1;
}
else
{
*pt = cfun->gimple_df->escaped;
pt->nonlocal = 1;
}
pt = gimple_call_clobber_set (stmt);
if (gimple_call_flags (stmt) & (ECF_CONST|ECF_PURE|ECF_NOVOPS))
memset (pt, 0, sizeof (struct pt_solution));
else
{
*pt = cfun->gimple_df->escaped;
pt->nonlocal = 1;
}
}
}
timevar_pop (TV_TREE_PTA); timevar_pop (TV_TREE_PTA);
} }
......
...@@ -1123,7 +1123,6 @@ init_tree_ssa (struct function *fn) ...@@ -1123,7 +1123,6 @@ init_tree_ssa (struct function *fn)
fn->gimple_df->default_defs = htab_create_ggc (20, uid_ssaname_map_hash, fn->gimple_df->default_defs = htab_create_ggc (20, uid_ssaname_map_hash,
uid_ssaname_map_eq, NULL); uid_ssaname_map_eq, NULL);
pt_solution_reset (&fn->gimple_df->escaped); pt_solution_reset (&fn->gimple_df->escaped);
pt_solution_reset (&fn->gimple_df->callused);
init_ssanames (fn, 0); init_ssanames (fn, 0);
init_phinodes (); init_phinodes ();
} }
...@@ -1163,7 +1162,6 @@ delete_tree_ssa (void) ...@@ -1163,7 +1162,6 @@ delete_tree_ssa (void)
htab_delete (cfun->gimple_df->default_defs); htab_delete (cfun->gimple_df->default_defs);
cfun->gimple_df->default_defs = NULL; cfun->gimple_df->default_defs = NULL;
pt_solution_reset (&cfun->gimple_df->escaped); pt_solution_reset (&cfun->gimple_df->escaped);
pt_solution_reset (&cfun->gimple_df->callused);
if (cfun->gimple_df->decls_to_pointers != NULL) if (cfun->gimple_df->decls_to_pointers != NULL)
pointer_map_destroy (cfun->gimple_df->decls_to_pointers); pointer_map_destroy (cfun->gimple_df->decls_to_pointers);
cfun->gimple_df->decls_to_pointers = NULL; cfun->gimple_df->decls_to_pointers = NULL;
......
...@@ -136,11 +136,23 @@ suitable_for_tail_opt_p (void) ...@@ -136,11 +136,23 @@ suitable_for_tail_opt_p (void)
if (cfun->stdarg) if (cfun->stdarg)
return false; return false;
/* No local variable nor structure field should be call-used. */ /* No local variable nor structure field should escape to callees. */
FOR_EACH_REFERENCED_VAR (var, rvi) FOR_EACH_REFERENCED_VAR (var, rvi)
{ {
if (!is_global_var (var) if (!is_global_var (var)
&& is_call_used (var)) /* ??? We do not have a suitable predicate for escaping to
callees. With IPA-PTA the following might be incorrect.
We want to catch
foo {
int i;
bar (&i);
foo ();
}
where bar might store &i somewhere and in the next
recursion should not be able to tell if it got the
same (with tail-recursion applied) or a different
address. */
&& is_call_clobbered (var))
return false; return false;
} }
...@@ -430,7 +442,9 @@ find_tail_calls (basic_block bb, struct tailcall **ret) ...@@ -430,7 +442,9 @@ find_tail_calls (basic_block bb, struct tailcall **ret)
func = gimple_call_fndecl (call); func = gimple_call_fndecl (call);
if (func == current_function_decl) if (func == current_function_decl)
{ {
tree arg; tree arg, var;
referenced_var_iterator rvi;
for (param = DECL_ARGUMENTS (func), idx = 0; for (param = DECL_ARGUMENTS (func), idx = 0;
param && idx < gimple_call_num_args (call); param && idx < gimple_call_num_args (call);
param = TREE_CHAIN (param), idx ++) param = TREE_CHAIN (param), idx ++)
...@@ -460,6 +474,15 @@ find_tail_calls (basic_block bb, struct tailcall **ret) ...@@ -460,6 +474,15 @@ find_tail_calls (basic_block bb, struct tailcall **ret)
} }
if (idx == gimple_call_num_args (call) && !param) if (idx == gimple_call_num_args (call) && !param)
tail_recursion = true; tail_recursion = true;
/* Make sure the tail invocation of this function does not refer
to local variables. */
FOR_EACH_REFERENCED_VAR (var, rvi)
{
if (!is_global_var (var)
&& ref_maybe_used_by_stmt_p (call, var))
return;
}
} }
/* Now check the statements after the call. None of them has virtual /* Now check the statements after the call. None of them has virtual
......
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