This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
[PATCH][RFC] Keep per call-stmt information about clobbers/uses
- From: Richard Guenther <rguenther at suse dot de>
- To: gcc-patches at gcc dot gnu dot org
- Date: Thu, 19 Nov 2009 17:08:39 +0100 (CET)
- Subject: [PATCH][RFC] Keep per call-stmt information about clobbers/uses
This transitions away from using the global escaped and callused
points-to sets for call clobber/use analysis. This is required
both for IPA-PTA and for annotating calls with information about
what arguments escape, are clobbered, etc.
This first patch just does the transition to per-call information
and should be a no-op functionality wise. It enlarges all call
statements by effectively 4 pointers (well, 2 pointers and some
flags, but as they are two struct pt_solutions we get the
flags padded to pointer size).
A followup patch making pure/const call handling context sensitive
is already done.
Bootstrapped on x86_64-unknown-linux-gnu, testing in progress,
queued for stage1.
Richard.
2009-11-19 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.
Index: trunk/gcc/gimple.def
===================================================================
*** trunk.orig/gcc/gimple.def 2009-11-18 15:54:37.000000000 +0100
--- trunk/gcc/gimple.def 2009-11-19 12:08:35.000000000 +0100
*************** DEFGSCODE(GIMPLE_ASM, "gimple_asm", GSS_
*** 122,128 ****
is_gimple_operand.
CHAIN is the optional static chain link for nested functions. */
! DEFGSCODE(GIMPLE_CALL, "gimple_call", GSS_WITH_MEM_OPS)
/* GIMPLE_RETURN <RETVAL> represents return statements.
--- 122,128 ----
is_gimple_operand.
CHAIN is the optional static chain link for nested functions. */
! DEFGSCODE(GIMPLE_CALL, "gimple_call", GSS_CALL)
/* GIMPLE_RETURN <RETVAL> represents return statements.
Index: trunk/gcc/gimple.h
===================================================================
*** trunk.orig/gcc/gimple.h 2009-11-18 15:54:17.000000000 +0100
--- trunk/gcc/gimple.h 2009-11-19 13:14:16.000000000 +0100
*************** along with GCC; see the file COPYING3.
*** 29,34 ****
--- 29,35 ----
#include "hard-reg-set.h"
#include "basic-block.h"
#include "tree-ssa-operands.h"
+ #include "tree-ssa-alias.h"
DEF_VEC_P(gimple);
DEF_VEC_ALLOC_P(gimple,heap);
*************** struct GTY(()) gimple_statement_with_mem
*** 390,395 ****
--- 391,415 ----
};
+ /* 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). */
struct GTY(()) gimple_statement_omp {
*************** union GTY ((desc ("gimple_statement_stru
*** 739,744 ****
--- 759,765 ----
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 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_bind GTY ((tag ("GSS_BIND"))) gimple_bind;
struct gimple_statement_catch GTY ((tag ("GSS_CATCH"))) gimple_catch;
*************** void gimple_seq_free (gimple_seq);
*** 832,837 ****
--- 853,859 ----
void gimple_seq_add_seq (gimple_seq *, gimple_seq);
gimple_seq gimple_seq_copy (gimple_seq);
int gimple_call_flags (const_gimple);
+ void gimple_call_reset_alias_info (gimple);
bool gimple_assign_copy_p (gimple);
bool gimple_assign_ssa_name_copy_p (gimple);
bool gimple_assign_single_p (gimple);
*************** gimple_call_copy_flags (gimple dest_call
*** 2214,2219 ****
--- 2236,2263 ----
}
+ /* 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
non-NULL lhs. */
Index: trunk/gcc/gsstruct.def
===================================================================
*** trunk.orig/gcc/gsstruct.def 2009-11-18 15:54:23.000000000 +0100
--- trunk/gcc/gsstruct.def 2009-11-19 12:09:03.000000000 +0100
*************** DEFGSSTRUCT(GSS_BASE, gimple_statement_b
*** 29,34 ****
--- 29,35 ----
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, gimple_statement_with_memory_ops, true)
+ DEFGSSTRUCT(GSS_CALL, gimple_statement_call, true)
DEFGSSTRUCT(GSS_ASM, gimple_statement_asm, true)
DEFGSSTRUCT(GSS_BIND, gimple_statement_bind, false)
DEFGSSTRUCT(GSS_PHI, gimple_statement_phi, false)
Index: trunk/gcc/Makefile.in
===================================================================
*** trunk.orig/gcc/Makefile.in 2009-11-17 16:12:38.000000000 +0100
--- trunk/gcc/Makefile.in 2009-11-19 12:49:39.000000000 +0100
*************** BASIC_BLOCK_H = basic-block.h $(BITMAP_H
*** 859,865 ****
hard-reg-set.h $(PREDICT_H) vec.h $(FUNCTION_H) \
cfghooks.h $(OBSTACK_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
GCOV_IO_H = gcov-io.h gcov-iov.h auto-host.h
COVERAGE_H = coverage.h $(GCOV_IO_H)
DEMANGLE_H = $(srcdir)/../include/demangle.h
--- 859,866 ----
hard-reg-set.h $(PREDICT_H) vec.h $(FUNCTION_H) \
cfghooks.h $(OBSTACK_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 \
! tree-ssa-alias.h
GCOV_IO_H = gcov-io.h gcov-iov.h auto-host.h
COVERAGE_H = coverage.h $(GCOV_IO_H)
DEMANGLE_H = $(srcdir)/../include/demangle.h
Index: trunk/gcc/cfgexpand.c
===================================================================
*** trunk.orig/gcc/cfgexpand.c 2009-11-18 12:49:55.000000000 +0100
--- trunk/gcc/cfgexpand.c 2009-11-19 13:55:35.000000000 +0100
*************** update_alias_info_with_stack_vars (void)
*** 591,598 ****
add_partitioned_vars_to_ptset (&cfun->gimple_df->escaped,
decls_to_partitions, visited, temp);
- add_partitioned_vars_to_ptset (&cfun->gimple_df->callused,
- decls_to_partitions, visited, temp);
pointer_set_destroy (visited);
pointer_map_destroy (decls_to_partitions);
--- 591,596 ----
Index: trunk/gcc/gimple.c
===================================================================
*** trunk.orig/gcc/gimple.c 2009-11-18 15:53:50.000000000 +0100
--- trunk/gcc/gimple.c 2009-11-19 13:13:16.000000000 +0100
*************** gimple_build_return (tree retval)
*** 198,203 ****
--- 198,218 ----
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
gimple_build_call_from_tree. Build the basic components of a
GIMPLE_CALL statement to function FN with NARGS arguments. */
*************** gimple_build_call_1 (tree fn, unsigned n
*** 209,214 ****
--- 224,230 ----
if (TREE_CODE (fn) == FUNCTION_DECL)
fn = build_fold_addr_expr (fn);
gimple_set_op (s, 1, fn);
+ gimple_call_reset_alias_info (s);
return s;
}
Index: trunk/gcc/lto-streamer-in.c
===================================================================
*** trunk.orig/gcc/lto-streamer-in.c 2009-11-18 12:33:52.000000000 +0100
--- trunk/gcc/lto-streamer-in.c 2009-11-19 12:46:29.000000000 +0100
*************** input_gimple_stmt (struct lto_input_bloc
*** 1136,1141 ****
--- 1136,1145 ----
}
}
+ /* Reset alias information. */
+ if (code == GIMPLE_CALL)
+ gimple_call_reset_alias_info (stmt);
+
/* Fixup reference tree operands for substituted prevailing decls
with mismatched types. */
maybe_fixup_decls (stmt);
Index: trunk/gcc/tree-dfa.c
===================================================================
*** trunk.orig/gcc/tree-dfa.c 2009-11-18 12:49:55.000000000 +0100
--- trunk/gcc/tree-dfa.c 2009-11-19 14:11:31.000000000 +0100
*************** dump_variable (FILE *file, tree var)
*** 302,309 ****
if (is_call_clobbered (var))
fprintf (file, ", call clobbered");
- else if (is_call_used (var))
- fprintf (file, ", call used");
if (ann && ann->noalias_state == NO_ALIAS)
fprintf (file, ", NO_ALIAS (does not alias other NO_ALIAS symbols)");
--- 302,307 ----
Index: trunk/gcc/tree-flow-inline.h
===================================================================
*** trunk.orig/gcc/tree-flow-inline.h 2009-09-15 16:51:21.000000000 +0200
--- trunk/gcc/tree-flow-inline.h 2009-11-19 14:12:31.000000000 +0100
*************** is_call_clobbered (const_tree var)
*** 669,683 ****
&& 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)));
- }
-
/* Return the common annotation for T. Return NULL if the annotation
doesn't already exist. */
static inline tree_ann_common_t
--- 669,674 ----
Index: trunk/gcc/tree-flow.h
===================================================================
*** trunk.orig/gcc/tree-flow.h 2009-11-18 12:49:55.000000000 +0100
--- trunk/gcc/tree-flow.h 2009-11-19 13:54:38.000000000 +0100
*************** struct GTY(()) gimple_df {
*** 60,68 ****
/* The PTA solution for the ESCAPED artificial variable. */
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
of the decl. */
struct pointer_map_t * GTY((skip(""))) decls_to_pointers;
--- 60,65 ----
Index: trunk/gcc/tree-inline.c
===================================================================
*** trunk.orig/gcc/tree-inline.c 2009-11-18 12:49:55.000000000 +0100
--- trunk/gcc/tree-inline.c 2009-11-19 13:56:11.000000000 +0100
*************** remap_gimple_stmt (gimple stmt, copy_bod
*** 1401,1406 ****
--- 1401,1413 ----
default:
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;
*************** expand_call_inline (basic_block bb, gimp
*** 3761,3772 ****
cg_edge->frequency * REG_BR_PROB_BASE / CGRAPH_FREQ_BASE,
bb, return_block);
! /* Reset the escaped and callused solutions. */
if (cfun->gimple_df)
! {
! pt_solution_reset (&cfun->gimple_df->escaped);
! pt_solution_reset (&cfun->gimple_df->callused);
! }
/* Clean up. */
if (id->debug_map)
--- 3768,3776 ----
cg_edge->frequency * REG_BR_PROB_BASE / CGRAPH_FREQ_BASE,
bb, return_block);
! /* Reset the escaped solution. */
if (cfun->gimple_df)
! pt_solution_reset (&cfun->gimple_df->escaped);
/* Clean up. */
if (id->debug_map)
Index: trunk/gcc/tree-nrv.c
===================================================================
*** trunk.orig/gcc/tree-nrv.c 2009-05-11 14:17:29.000000000 +0200
--- trunk/gcc/tree-nrv.c 2009-11-19 14:12:19.000000000 +0100
*************** dest_safe_for_nrv_p (tree dest)
*** 301,307 ****
if (TREE_CODE (dest) == SSA_NAME)
dest = SSA_NAME_VAR (dest);
! if (is_call_used (dest))
return false;
return true;
--- 301,307 ----
if (TREE_CODE (dest) == SSA_NAME)
dest = SSA_NAME_VAR (dest);
! if (is_call_clobbered (dest))
return false;
return true;
Index: trunk/gcc/tree-parloops.c
===================================================================
*** trunk.orig/gcc/tree-parloops.c 2009-10-22 17:35:05.000000000 +0200
--- trunk/gcc/tree-parloops.c 2009-11-19 13:56:02.000000000 +0100
*************** parallelize_loops (void)
*** 1972,1984 ****
htab_delete (reduction_list);
/* Parallelization will cause new function calls to be inserted through
! which local variables will escape. Reset the points-to solutions
! for ESCAPED and CALLUSED. */
if (changed)
! {
! pt_solution_reset (&cfun->gimple_df->escaped);
! pt_solution_reset (&cfun->gimple_df->callused);
! }
return changed;
}
--- 1972,1981 ----
htab_delete (reduction_list);
/* Parallelization will cause new function calls to be inserted through
! which local variables will escape. Reset the points-to solution
! for ESCAPED. */
if (changed)
! pt_solution_reset (&cfun->gimple_df->escaped);
return changed;
}
Index: trunk/gcc/tree-ssa-alias.c
===================================================================
*** trunk.orig/gcc/tree-ssa-alias.c 2009-11-18 15:53:50.000000000 +0100
--- trunk/gcc/tree-ssa-alias.c 2009-11-19 13:56:28.000000000 +0100
*************** dump_alias_info (FILE *file)
*** 336,343 ****
fprintf (file, "\nESCAPED");
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");
--- 336,341 ----
*************** ref_maybe_used_by_call_p_1 (gimple call,
*** 1006,1056 ****
goto process_args;
}
! /* If the base variable is call-used or call-clobbered then
! it may be used. */
! if (flags & (ECF_PURE|ECF_CONST|ECF_LOOPING_CONST_OR_PURE|ECF_NOVOPS))
{
! if (DECL_P (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;
}
! else
{
! if (DECL_P (base))
! {
! if (is_call_clobbered (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->escaped, &pi->pt))
! return true;
! }
! else
return true;
}
/* Inspect call arguments for passed-by-value aliases. */
process_args:
--- 1004,1027 ----
goto process_args;
}
! /* Check if the base variable is call-used. */
! if (DECL_P (base))
{
! if (pt_solution_includes (gimple_call_use_set (call), 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_solutions_intersect (gimple_call_use_set (call), &pi->pt))
return true;
}
+ else
+ return true;
/* Inspect call arguments for passed-by-value aliases. */
process_args:
*************** call_may_clobber_ref_p_1 (gimple call, a
*** 1261,1268 ****
return false;
}
if (DECL_P (base))
! return is_call_clobbered (base);
else if (INDIRECT_REF_P (base)
&& TREE_CODE (TREE_OPERAND (base, 0)) == SSA_NAME)
{
--- 1232,1240 ----
return false;
}
+ /* Check if the base variable is call-clobbered. */
if (DECL_P (base))
! return pt_solution_includes (gimple_call_clobber_set (call), base);
else if (INDIRECT_REF_P (base)
&& TREE_CODE (TREE_OPERAND (base, 0)) == SSA_NAME)
{
*************** call_may_clobber_ref_p_1 (gimple call, a
*** 1270,1277 ****
if (!pi)
return true;
! return (pt_solution_includes_global (&pi->pt)
! || pt_solutions_intersect (&cfun->gimple_df->escaped, &pi->pt));
}
return true;
--- 1242,1248 ----
if (!pi)
return true;
! return pt_solutions_intersect (gimple_call_clobber_set (call), &pi->pt);
}
return true;
Index: trunk/gcc/tree-ssa-structalias.c
===================================================================
*** trunk.orig/gcc/tree-ssa-structalias.c 2009-11-18 15:53:50.000000000 +0100
--- trunk/gcc/tree-ssa-structalias.c 2009-11-19 13:55:23.000000000 +0100
*************** compute_points_to_sets (void)
*** 5478,5483 ****
--- 5478,5484 ----
basic_block bb;
unsigned i;
varinfo_t vi;
+ struct pt_solution callused;
timevar_push (TV_TREE_PTA);
*************** compute_points_to_sets (void)
*** 5514,5521 ****
call-clobber analysis. */
find_what_var_points_to (get_varinfo (escaped_id),
&cfun->gimple_df->escaped);
! find_what_var_points_to (get_varinfo (callused_id),
! &cfun->gimple_df->callused);
/* Make sure the ESCAPED solution (which is used as placeholder in
other solutions) does not reference itself. This simplifies
--- 5515,5521 ----
call-clobber analysis. */
find_what_var_points_to (get_varinfo (escaped_id),
&cfun->gimple_df->escaped);
! find_what_var_points_to (get_varinfo (callused_id), &callused);
/* Make sure the ESCAPED solution (which is used as placeholder in
other solutions) does not reference itself. This simplifies
*************** compute_points_to_sets (void)
*** 5539,5544 ****
--- 5539,5586 ----
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);
}
Index: trunk/gcc/tree-ssa.c
===================================================================
*** trunk.orig/gcc/tree-ssa.c 2009-11-18 12:49:55.000000000 +0100
--- trunk/gcc/tree-ssa.c 2009-11-19 13:57:16.000000000 +0100
*************** init_tree_ssa (struct function *fn)
*** 1112,1118 ****
fn->gimple_df->default_defs = htab_create_ggc (20, uid_ssaname_map_hash,
uid_ssaname_map_eq, NULL);
pt_solution_reset (&fn->gimple_df->escaped);
- pt_solution_reset (&fn->gimple_df->callused);
init_ssanames (fn, 0);
init_phinodes ();
}
--- 1112,1117 ----
*************** delete_tree_ssa (void)
*** 1150,1156 ****
htab_delete (cfun->gimple_df->default_defs);
cfun->gimple_df->default_defs = NULL;
pt_solution_reset (&cfun->gimple_df->escaped);
- pt_solution_reset (&cfun->gimple_df->callused);
if (cfun->gimple_df->decls_to_pointers != NULL)
pointer_map_destroy (cfun->gimple_df->decls_to_pointers);
cfun->gimple_df->decls_to_pointers = NULL;
--- 1149,1154 ----
Index: trunk/gcc/tree-tailcall.c
===================================================================
*** trunk.orig/gcc/tree-tailcall.c 2009-09-22 10:27:45.000000000 +0200
--- trunk/gcc/tree-tailcall.c 2009-11-19 14:42:47.000000000 +0100
*************** suitable_for_tail_opt_p (void)
*** 136,146 ****
if (cfun->stdarg)
return false;
! /* No local variable nor structure field should be call-used. */
FOR_EACH_REFERENCED_VAR (var, rvi)
{
if (!is_global_var (var)
! && is_call_used (var))
return false;
}
--- 136,158 ----
if (cfun->stdarg)
return false;
! /* No local variable nor structure field should escape to callees. */
FOR_EACH_REFERENCED_VAR (var, rvi)
{
if (!is_global_var (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;
}
*************** find_tail_calls (basic_block bb, struct
*** 430,436 ****
func = gimple_call_fndecl (call);
if (func == current_function_decl)
{
! tree arg;
for (param = DECL_ARGUMENTS (func), idx = 0;
param && idx < gimple_call_num_args (call);
param = TREE_CHAIN (param), idx ++)
--- 442,450 ----
func = gimple_call_fndecl (call);
if (func == current_function_decl)
{
! tree arg, var;
! referenced_var_iterator rvi;
!
for (param = DECL_ARGUMENTS (func), idx = 0;
param && idx < gimple_call_num_args (call);
param = TREE_CHAIN (param), idx ++)
*************** find_tail_calls (basic_block bb, struct
*** 460,465 ****
--- 474,488 ----
}
if (idx == gimple_call_num_args (call) && !param)
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