/* Tail call optimization on trees.
- Copyright (C) 2003-2020 Free Software Foundation, Inc.
+ Copyright (C) 2003-2021 Free Software Foundation, Inc.
This file is part of GCC.
static bitmap tailr_arg_needs_copy;
-static bool optimize_tail_call (struct tailcall *, bool);
-static void eliminate_tail_call (struct tailcall *);
-
/* Returns false when the function is not suitable for tail call optimization
from some reason (e.g. if it takes variable number of arguments). */
&& (non_ass_var = independent_of_stmt_p (op1, stmt, call,
to_move)))
;
- else if (op1 == *ass_var
+ else if (*ass_var
+ && op1 == *ass_var
&& (non_ass_var = independent_of_stmt_p (op0, stmt, call,
to_move)))
;
tree result_decl = DECL_RESULT (cfun->decl);
if (result_decl
&& may_be_aliased (result_decl)
- && ref_maybe_used_by_stmt_p (call, result_decl))
+ && ref_maybe_used_by_stmt_p (call, result_decl, false))
return;
/* We found the call, check whether it is suitable. */
if (TREE_CODE (var) != PARM_DECL
&& auto_var_in_fn_p (var, cfun->decl)
&& may_be_aliased (var)
- && (ref_maybe_used_by_stmt_p (call, var)
- || call_may_clobber_ref_p (call, var)))
+ && (ref_maybe_used_by_stmt_p (call, var, false)
+ || call_may_clobber_ref_p (call, var, false)))
{
if (!VAR_P (var))
{
ret_var = gimple_return_retval (as_a <greturn *> (stmt));
/* We may proceed if there either is no return value, or the return value
- is identical to the call's return. */
+ is identical to the call's return or if the return decl is an empty type
+ variable and the call's return was not assigned. */
if (ret_var
- && (ret_var != ass_var))
+ && (ret_var != ass_var
+ && !(is_empty_type (TREE_TYPE (ret_var)) && !ass_var)))
return;
/* If this is not a tail recursive call, we cannot handle addends or
}
/* Eliminates tail call described by T. TMP_VARS is a list of
- temporary variables used to copy the function arguments. */
+ temporary variables used to copy the function arguments.
+ Allocates *NEW_LOOP if not already done and initializes it. */
static void
-eliminate_tail_call (struct tailcall *t)
+eliminate_tail_call (struct tailcall *t, class loop *&new_loop)
{
tree param, rslt;
gimple *stmt, *call;
gcc_assert (e);
PENDING_STMT (e) = NULL;
+ /* Add the new loop. */
+ if (!new_loop)
+ {
+ new_loop = alloc_loop ();
+ new_loop->header = first;
+ new_loop->finite_p = true;
+ }
+ else
+ gcc_assert (new_loop->header == first);
+
/* 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),
mark the tailcalls for the sibcall optimization. */
static bool
-optimize_tail_call (struct tailcall *t, bool opt_tailcalls)
+optimize_tail_call (struct tailcall *t, bool opt_tailcalls,
+ class loop *&new_loop)
{
if (t->tail_recursion)
{
- eliminate_tail_call (t);
+ eliminate_tail_call (t, new_loop);
return true;
}
gphi *phi;
phi = create_phi_node (tmp, bb);
- /* RET_TYPE can be a float when -ffast-maths is enabled. */
- add_phi_arg (phi, fold_convert (ret_type, init), single_pred_edge (bb),
+ add_phi_arg (phi, init, single_pred_edge (bb),
UNKNOWN_LOCATION);
return PHI_RESULT (phi);
}
}
phis_constructed = true;
}
+ tree ret_type = TREE_TYPE (DECL_RESULT (current_function_decl));
+ if (POINTER_TYPE_P (ret_type))
+ ret_type = sizetype;
if (act->add && !a_acc)
a_acc = create_tailcall_accumulator ("add_acc", first,
- integer_zero_node);
+ build_zero_cst (ret_type));
if (act->mult && !m_acc)
m_acc = create_tailcall_accumulator ("mult_acc", first,
- integer_one_node);
+ build_one_cst (ret_type));
}
if (a_acc || m_acc)
opt_tailcalls = false;
}
+ class loop *new_loop = NULL;
for (; tailcalls; tailcalls = next)
{
next = tailcalls->next;
- changed |= optimize_tail_call (tailcalls, opt_tailcalls);
+ changed |= optimize_tail_call (tailcalls, opt_tailcalls, new_loop);
free (tailcalls);
}
+ if (new_loop)
+ add_loop (new_loop, loops_for_fn (cfun)->tree_root);
if (a_acc || m_acc)
{
}
if (changed)
- {
- /* We may have created new loops. Make them magically appear. */
- loops_state_set (LOOPS_NEED_FIXUP);
- free_dominance_info (CDI_DOMINATORS);
- }
+ free_dominance_info (CDI_DOMINATORS);
/* Add phi nodes for the virtual operands defined in the function to the
header of the loop created by tail recursion elimination. Do so