/* Tail call optimization on trees.
- Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010
+ Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012
Free Software Foundation, Inc.
This file is part of GCC.
#include "langhooks.h"
#include "dbgcnt.h"
#include "target.h"
+#include "common/common-target.h"
/* The file implements the tail recursion elimination. It is also used to
analyze the tail calls in general, passing the results to the rtl level
/* If we are using sjlj exceptions, we may need to add a call to
_Unwind_SjLj_Unregister at exit of the function. Which means
that we cannot do any sibcall transformations. */
- if (targetm.except_unwind_info (&global_options) == UI_SJLJ
+ if (targetm_common.except_unwind_info (&global_options) == UI_SJLJ
&& current_function_has_exception_handlers ())
return false;
case NEGATE_EXPR:
if (FLOAT_TYPE_P (TREE_TYPE (op0)))
*m = build_real (TREE_TYPE (op0), dconstm1);
- else
+ else if (INTEGRAL_TYPE_P (TREE_TYPE (op0)))
*m = build_int_cst (TREE_TYPE (op0), -1);
+ else
+ return false;
*ass_var = dest;
return true;
{
if (FLOAT_TYPE_P (TREE_TYPE (non_ass_var)))
*m = build_real (TREE_TYPE (non_ass_var), dconstm1);
- else
+ else if (INTEGRAL_TYPE_P (TREE_TYPE (non_ass_var)))
*m = build_int_cst (TREE_TYPE (non_ass_var), -1);
+ else
+ return false;
*a = fold_build1 (NEGATE_EXPR, TREE_TYPE (non_ass_var), non_ass_var);
}
{
stmt = gsi_stmt (gsi);
- /* Ignore labels. */
- if (gimple_code (stmt) == GIMPLE_LABEL || is_gimple_debug (stmt))
+ /* Ignore labels, returns, clobbers and debug stmts. */
+ if (gimple_code (stmt) == GIMPLE_LABEL
+ || gimple_code (stmt) == GIMPLE_RETURN
+ || gimple_clobber_p (stmt)
+ || is_gimple_debug (stmt))
continue;
/* Check for a call. */
/* Make sure the tail invocation of this function does not refer
to local variables. */
- FOR_EACH_REFERENCED_VAR (var, rvi)
+ FOR_EACH_REFERENCED_VAR (cfun, var, rvi)
{
if (TREE_CODE (var) != PARM_DECL
&& auto_var_in_fn_p (var, cfun->decl)
if (gimple_code (stmt) == GIMPLE_RETURN)
break;
+ if (gimple_clobber_p (stmt))
+ continue;
+
if (is_gimple_debug (stmt))
continue;
if (!tail_recursion && (m || a))
return;
+ /* For pointers don't allow additions or multiplications. */
+ if ((m || a)
+ && POINTER_TYPE_P (TREE_TYPE (DECL_RESULT (current_function_decl))))
+ return;
+
nw = XNEW (struct tailcall);
nw->call_gsi = gsi;
}
/* Creates a GIMPLE statement which computes the operation specified by
- CODE, OP0 and OP1 to a new variable with name LABEL and inserts the
- statement in the position specified by GSI and UPDATE. Returns the
+ CODE, ACC and OP1 to a new variable with name LABEL and inserts the
+ statement in the position specified by GSI. Returns the
tree node of the statement's result. */
static tree
fold_convert (TREE_TYPE (op1), acc),
op1));
rhs = force_gimple_operand_gsi (&gsi, rhs,
- false, NULL, true, GSI_CONTINUE_LINKING);
+ false, NULL, true, GSI_SAME_STMT);
stmt = gimple_build_assign (NULL_TREE, rhs);
}
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)
+ FOR_EACH_REFERENCED_VAR (cfun, var, rvi)
{
if (!is_gimple_reg (var) && gimple_default_def (cfun, var) != NULL_TREE)
mark_sym_for_renaming (var);
integer_one_node);
}
+ if (a_acc || m_acc)
+ {
+ /* When the tail call elimination using accumulators is performed,
+ statements adding the accumulated value are inserted at all exits.
+ This turns all other tail calls to non-tail ones. */
+ opt_tailcalls = false;
+ }
+
for (; tailcalls; tailcalls = next)
{
next = tailcalls->next;
0, /* properties_provided */
0, /* properties_destroyed */
0, /* todo_flags_start */
- TODO_dump_func | TODO_verify_ssa /* todo_flags_finish */
+ TODO_verify_ssa /* todo_flags_finish */
}
};
0, /* properties_provided */
0, /* properties_destroyed */
0, /* todo_flags_start */
- TODO_dump_func | TODO_verify_ssa /* todo_flags_finish */
+ TODO_verify_ssa /* todo_flags_finish */
}
};