diff options
author | dberlin <dberlin@138bc75d-0d04-0410-961f-82ee72b054a4> | 2006-02-03 00:24:50 +0000 |
---|---|---|
committer | dberlin <dberlin@138bc75d-0d04-0410-961f-82ee72b054a4> | 2006-02-03 00:24:50 +0000 |
commit | 4304657c8c0576eedc28f600ca02f344a96f5b98 (patch) | |
tree | a29bc7c72528536c6d857894bb9932dff5f9d9a1 /gcc/tree-tailcall.c | |
parent | 962cec0dc38054f2610d7b763d216a48ece3bca8 (diff) | |
download | gcc-4304657c8c0576eedc28f600ca02f344a96f5b98.tar.gz |
2006-02-02 Zdenek Dvorak <dvorakz@suse.cz>
Daniel Berlin <dberlin@dberlin.org>
* tree-tailcall.c (arg_needs_copy_p): New function.
(eliminate_tail_call): Use arg_needs_copy_p.
(tree_optimize_tail_calls_1): Ditto. Also call add_virtual_phis.
(add_virtual_phis): New function.
git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@110530 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'gcc/tree-tailcall.c')
-rw-r--r-- | gcc/tree-tailcall.c | 150 |
1 files changed, 80 insertions, 70 deletions
diff --git a/gcc/tree-tailcall.c b/gcc/tree-tailcall.c index 1a3116effad..b0f74ffbc70 100644 --- a/gcc/tree-tailcall.c +++ b/gcc/tree-tailcall.c @@ -690,6 +690,25 @@ decrease_profile (basic_block bb, gcov_type count, int frequency) e->count = 0; } +/* Returns true if argument PARAM of the tail recursive call needs to be copied + when the call is eliminated. */ + +static bool +arg_needs_copy_p (tree param) +{ + tree def; + + if (!is_gimple_reg (param) || !var_ann (param)) + return false; + + /* Parameters that are only defined but never used need not be copied. */ + def = default_def (param); + if (!def) + return false; + + return true; +} + /* Eliminates tail call described by T. TMP_VARS is a list of temporary variables used to copy the function arguments. */ @@ -701,9 +720,6 @@ eliminate_tail_call (struct tailcall *t) edge e; tree phi; block_stmt_iterator bsi; - use_operand_p mayuse; - def_operand_p maydef; - ssa_op_iter iter; tree orig_stmt; stmt = orig_stmt = bsi_stmt (t->call_bsi); @@ -751,65 +767,21 @@ eliminate_tail_call (struct tailcall *t) gcc_assert (e); PENDING_STMT (e) = NULL_TREE; - /* Add phi node entries for arguments. Not every PHI node corresponds to - a function argument (there may be PHI nodes for virtual definitions of the - eliminated calls), so we search for a PHI corresponding to each argument - rather than searching for which argument a PHI node corresponds to. */ - + /* Add phi node entries for arguments. The ordering of the phi nodes should + be the same as the ordering of the arguments. */ for (param = DECL_ARGUMENTS (current_function_decl), - args = TREE_OPERAND (stmt, 1); + args = TREE_OPERAND (stmt, 1), + phi = phi_nodes (first); param; param = TREE_CHAIN (param), args = TREE_CHAIN (args)) { - - for (phi = phi_nodes (first); phi; phi = PHI_CHAIN (phi)) - if (param == SSA_NAME_VAR (PHI_RESULT (phi))) - break; - - /* The phi node indeed does not have to be there, in case the operand is - invariant in the function. */ - if (!phi) + if (!arg_needs_copy_p (param)) continue; + gcc_assert (param == SSA_NAME_VAR (PHI_RESULT (phi))); add_phi_arg (phi, TREE_VALUE (args), e); - } - - /* Add phi nodes for the call clobbered variables. */ - FOR_EACH_SSA_MAYDEF_OPERAND (maydef, mayuse, orig_stmt, iter) - { - param = SSA_NAME_VAR (DEF_FROM_PTR (maydef)); - for (phi = phi_nodes (first); phi; phi = PHI_CHAIN (phi)) - if (param == SSA_NAME_VAR (PHI_RESULT (phi))) - break; - - if (!phi) - { - tree name = default_def (param); - tree new_name; - - if (!name) - { - /* It may happen that the tag does not have a default_def in case - when all uses of it are dominated by a MUST_DEF. This however - means that it is not necessary to add a phi node for this - tag. */ - continue; - } - new_name = make_ssa_name (param, SSA_NAME_DEF_STMT (name)); - - set_default_def (param, new_name); - phi = create_phi_node (name, first); - SSA_NAME_DEF_STMT (name) = phi; - add_phi_arg (phi, new_name, single_succ_edge (ENTRY_BLOCK_PTR)); - - /* For all calls the same set of variables should be clobbered. This - means that there always should be the appropriate phi node except - for the first time we eliminate the call. */ - gcc_assert (EDGE_COUNT (first->preds) <= 2); - } - - add_phi_arg (phi, USE_FROM_PTR (mayuse), e); + phi = PHI_CHAIN (phi); } /* Update the values of accumulators. */ @@ -829,6 +801,38 @@ eliminate_tail_call (struct tailcall *t) release_defs (call); } +/* Add phi nodes for the virtual operands defined in the function to the + header of the loop created by tail recursion elimination. + + Originally, we used to add phi nodes only for call clobbered variables, + as the value of the non-call clobbered ones obviously cannot be used + or changed within the recursive call. However, the local variables + from multiple calls now share the same location, so the virtual ssa form + requires us to say that the location dies on further iterations of the loop, + which requires adding phi nodes. +*/ +static void +add_virtual_phis (void) +{ + referenced_var_iterator rvi; + tree var; + + /* The problematic part is that there is no way how to know what + to put into phi nodes (there in fact does not have to be such + ssa name available). A solution would be to have an artificial + use/kill for all virtual operands in EXIT node. Unless we have + this, we cannot do much better than to rebuild the ssa form for + possibly affected virtual ssa names from scratch. */ + + FOR_EACH_REFERENCED_VAR (var, rvi) + { + if (!is_gimple_reg (var) && default_def (var) != NULL_TREE) + mark_sym_for_renaming (var); + } + + update_ssa (TODO_update_ssa_only_virtuals); +} + /* Optimizes the tailcall described by T. If OPT_TAILCALLS is true, also mark the tailcalls for the sibcall optimization. */ @@ -897,7 +901,6 @@ tree_optimize_tail_calls_1 (bool opt_tailcalls) if (!phis_constructed) { - tree name; /* Ensure that there is only one predecessor of the block. */ if (!single_pred_p (first)) first = split_edge (single_succ_edge (ENTRY_BLOCK_PTR)); @@ -906,21 +909,17 @@ tree_optimize_tail_calls_1 (bool opt_tailcalls) for (param = DECL_ARGUMENTS (current_function_decl); param; param = TREE_CHAIN (param)) - if (is_gimple_reg (param) - && var_ann (param) - /* Also parameters that are only defined but never used need not - be copied. */ - && ((name = default_def (param)) - && TREE_CODE (name) == SSA_NAME)) - { - tree new_name = make_ssa_name (param, SSA_NAME_DEF_STMT (name)); - tree phi; - - set_default_def (param, new_name); - phi = create_phi_node (name, first); - SSA_NAME_DEF_STMT (name) = phi; - add_phi_arg (phi, new_name, single_pred_edge (first)); - } + if (arg_needs_copy_p (param)) + { + tree name = default_def (param); + tree new_name = make_ssa_name (param, SSA_NAME_DEF_STMT (name)); + tree phi; + + set_default_def (param, new_name); + phi = create_phi_node (name, first); + SSA_NAME_DEF_STMT (name) = phi; + add_phi_arg (phi, new_name, single_pred_edge (first)); + } phis_constructed = true; } @@ -957,6 +956,14 @@ tree_optimize_tail_calls_1 (bool opt_tailcalls) } } + + if (phis_constructed) + { + /* Reverse the order of the phi nodes, so that it matches the order + of operands of the function, as assumed by eliminate_tail_call. */ + set_phi_nodes (first, phi_reverse (phi_nodes (first))); + } + for (; tailcalls; tailcalls = next) { next = tailcalls->next; @@ -982,6 +989,9 @@ tree_optimize_tail_calls_1 (bool opt_tailcalls) free_dominance_info (CDI_DOMINATORS); cleanup_tree_cfg (); } + + if (phis_constructed) + add_virtual_phis (); } static void |