diff --git a/gcc/ChangeLog b/gcc/ChangeLog index f06b1baa0fc2d09a963cd2ef145670a3309d6125..bd2dc3c56bf9b22575e7475c3d69ee215b639ccf 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,18 @@ +2010-04-16 Richard Guenther <rguenther@suse.de> + + PR tree-optimization/43572 + * tree-ssa-alias.h (call_may_clobber_ref_p): Declare. + * tree-ssa-alias.c (call_may_clobber_ref_p): Export. + * tree-flow.h (is_call_clobbered): Remove. + * tree-flow-inline.h (is_call_clobbered): Likewise. + * tree-dfa.c (dump_variable): Do not dump call clobber state. + * tree-nrv.c (dest_safe_for_nrv_p): Use the alias oracle. + (execute_return_slot_opt): Adjust. + * tree-tailcall.c (suitable_for_tail_opt_p): Remove + check for call clobbered vars here. + (find_tail_calls): Move tailcall verification to the + proper place. + 2010-04-16 Diego Novillo <dnovillo@google.com> * doc/invoke.texi: Explain how are unrecognized -Wno- warnings diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 589e80f89c0616abc6dce284c93a6fce74f23dae..b58bb508e8812b3f4d5493362169cbbf13a67929 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,8 @@ +2010-04-16 Richard Guenther <rguenther@suse.de> + + PR tree-optimization/43572 + * gcc.dg/tree-ssa/tailcall-5.c: New testcase. + 2010-04-16 Olivier Hainque <hainque@adacore.com> * gnat.dg/specs/discr_private.ads: New test. diff --git a/gcc/testsuite/gcc.dg/tree-ssa/tailcall-5.c b/gcc/testsuite/gcc.dg/tree-ssa/tailcall-5.c new file mode 100644 index 0000000000000000000000000000000000000000..7aa433ecf7a47c04df583d22cef608c021f8e5c2 --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/tailcall-5.c @@ -0,0 +1,12 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -fdump-tree-tailc" } */ + +void +set_integer (void *dest, int value, int length) +{ + int tmp = value; + __builtin_memcpy (dest, (void *) &tmp, length); +} + +/* { dg-final { scan-tree-dump-not "tail call" "tailc" } } */ +/* { dg-final { cleanup-tree-dump "tailc" } } */ diff --git a/gcc/tree-dfa.c b/gcc/tree-dfa.c index a8415b5a825ef279cd32debab7b31d7864fa8459..5475d79254b8aaa4037b6f707aaf4a78f658dddb 100644 --- a/gcc/tree-dfa.c +++ b/gcc/tree-dfa.c @@ -284,9 +284,6 @@ dump_variable (FILE *file, tree var) if (TREE_THIS_VOLATILE (var)) fprintf (file, ", is volatile"); - if (is_call_clobbered (var)) - fprintf (file, ", call clobbered"); - if (ann && ann->noalias_state == NO_ALIAS) fprintf (file, ", NO_ALIAS (does not alias other NO_ALIAS symbols)"); else if (ann && ann->noalias_state == NO_ALIAS_GLOBAL) diff --git a/gcc/tree-flow-inline.h b/gcc/tree-flow-inline.h index 2430f0355f7b4aca833bf9ce796886d3b8dda831..f7609ea7911cc51e7108586bbe3ccb283c4f9610 100644 --- a/gcc/tree-flow-inline.h +++ b/gcc/tree-flow-inline.h @@ -624,15 +624,6 @@ loop_containing_stmt (gimple stmt) } -/* Return true if VAR is clobbered by function calls. */ -static inline bool -is_call_clobbered (const_tree var) -{ - return (is_global_var (var) - || (may_be_aliased (var) - && pt_solution_includes (&cfun->gimple_df->escaped, var))); -} - /* ----------------------------------------------------------------------- */ /* The following set of routines are used to iterator over various type of diff --git a/gcc/tree-flow.h b/gcc/tree-flow.h index fda7a86f2d03905bb97b5da38af920b4ecacde94..8f9ab5de0f1e7f711ed8f1bfea3f4b92b167c980 100644 --- a/gcc/tree-flow.h +++ b/gcc/tree-flow.h @@ -774,7 +774,6 @@ extern enum move_pos movement_possibility (gimple); char *get_lsm_tmp_name (tree, unsigned); /* In tree-flow-inline.h */ -static inline bool is_call_clobbered (const_tree); static inline void set_is_used (tree); static inline bool unmodifiable_var_p (const_tree); static inline bool ref_contains_array_ref (const_tree); diff --git a/gcc/tree-nrv.c b/gcc/tree-nrv.c index b85c5a76c67481716f2bd818ccaac146cf06b15b..c2e49d32c170a3aa1dffed1465c518f9c7a251f3 100644 --- a/gcc/tree-nrv.c +++ b/gcc/tree-nrv.c @@ -291,23 +291,21 @@ struct gimple_opt_pass pass_nrv = optimization, where DEST is expected to be the LHS of a modify expression where the RHS is a function returning an aggregate. - We search for a base VAR_DECL and look to see if it is call clobbered. - Note that we could do better, for example, by - attempting to doing points-to analysis on INDIRECT_REFs. */ + DEST is available if it is not clobbered by the call. */ static bool -dest_safe_for_nrv_p (tree dest) +dest_safe_for_nrv_p (gimple call) { - while (handled_component_p (dest)) - dest = TREE_OPERAND (dest, 0); + tree dest = gimple_call_lhs (call); - if (! SSA_VAR_P (dest)) + dest = get_base_address (dest); + if (! dest) return false; if (TREE_CODE (dest) == SSA_NAME) - dest = SSA_NAME_VAR (dest); + return true; - if (is_call_clobbered (dest)) + if (call_may_clobber_ref_p (call, dest)) return false; return true; @@ -346,8 +344,8 @@ execute_return_slot_opt (void) ) { /* Check if the location being assigned to is - call-clobbered. */ - slot_opt_p = dest_safe_for_nrv_p (gimple_call_lhs (stmt)); + clobbered by the call. */ + slot_opt_p = dest_safe_for_nrv_p (stmt); gimple_call_set_return_slot_opt (stmt, slot_opt_p); } } diff --git a/gcc/tree-ssa-alias.c b/gcc/tree-ssa-alias.c index 8b1fdc37556574baa41ce47f24869360f39b55a9..67c669e8b4b59fe358e9406a7a870a8fc35b8330 100644 --- a/gcc/tree-ssa-alias.c +++ b/gcc/tree-ssa-alias.c @@ -1339,7 +1339,10 @@ call_may_clobber_ref_p_1 (gimple call, ao_ref *ref) return true; } -static bool ATTRIBUTE_UNUSED +/* If the call in statement CALL may clobber the memory reference REF + return true, otherwise return false. */ + +bool call_may_clobber_ref_p (gimple call, tree ref) { bool res; diff --git a/gcc/tree-ssa-alias.h b/gcc/tree-ssa-alias.h index 147f368843488de9f6c71280f1c440b5fbaaeb25..a2b532747c6dfe70890c7611ea9350cb41524b77 100644 --- a/gcc/tree-ssa-alias.h +++ b/gcc/tree-ssa-alias.h @@ -104,6 +104,7 @@ extern bool refs_output_dependent_p (tree, tree); extern bool ref_maybe_used_by_stmt_p (gimple, tree); extern bool stmt_may_clobber_ref_p (gimple, tree); extern bool stmt_may_clobber_ref_p_1 (gimple, ao_ref *); +extern bool call_may_clobber_ref_p (gimple, tree); extern tree get_continuation_for_phi (gimple, ao_ref *, bitmap *); extern void *walk_non_aliased_vuses (ao_ref *, tree, void *(*)(ao_ref *, tree, void *), diff --git a/gcc/tree-tailcall.c b/gcc/tree-tailcall.c index e0d3f4844e98f006d59b71726f319eb53f65e310..ca3dffadc75981a18d707fb36db3c4116facacfd 100644 --- a/gcc/tree-tailcall.c +++ b/gcc/tree-tailcall.c @@ -130,32 +130,9 @@ static void find_tail_calls (basic_block, struct tailcall **); static bool suitable_for_tail_opt_p (void) { - referenced_var_iterator rvi; - tree var; - 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; - } - return true; } /* Returns false when the function is not suitable for tail call optimization @@ -387,6 +364,8 @@ find_tail_calls (basic_block bb, struct tailcall **ret) tree m, a; basic_block abb; size_t idx; + tree var; + referenced_var_iterator rvi; if (!single_succ_p (bb)) return; @@ -442,8 +421,7 @@ find_tail_calls (basic_block bb, struct tailcall **ret) func = gimple_call_fndecl (call); if (func == current_function_decl) { - tree arg, var; - referenced_var_iterator rvi; + tree arg; for (param = DECL_ARGUMENTS (func), idx = 0; param && idx < gimple_call_num_args (call); @@ -474,15 +452,15 @@ find_tail_calls (basic_block bb, struct tailcall **ret) } 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; - } + /* 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