#include "ipa-prop.h"
#include "value-prof.h"
#include "tree-pass.h"
+#include "target.h"
+#include "integrate.h"
/* I'm not real happy about this, but we need to handle gimple and
non-gimple trees. */
{
t = remap_type (t, id);
TYPE_MAIN_VARIANT (new) = t;
- TYPE_NEXT_VARIANT (new) = TYPE_MAIN_VARIANT (t);
+ TYPE_NEXT_VARIANT (new) = TYPE_NEXT_VARIANT (t);
TYPE_NEXT_VARIANT (t) = new;
}
else
into multiple statements, we need to process all of them. */
while (!bsi_end_p (copy_bsi))
{
- stmt = bsi_stmt (copy_bsi);
+ tree *stmtp = bsi_stmt_ptr (copy_bsi);
+ tree stmt = *stmtp;
call = get_call_expr_in (stmt);
+ if (call && CALL_EXPR_VA_ARG_PACK (call) && id->call_expr)
+ {
+ /* __builtin_va_arg_pack () should be replaced by
+ all arguments corresponding to ... in the caller. */
+ tree p, *argarray, new_call, *call_ptr;
+ int nargs = call_expr_nargs (id->call_expr);
+
+ for (p = DECL_ARGUMENTS (id->src_fn); p; p = TREE_CHAIN (p))
+ nargs--;
+
+ argarray = (tree *) alloca ((nargs + call_expr_nargs (call))
+ * sizeof (tree));
+
+ memcpy (argarray, CALL_EXPR_ARGP (call),
+ call_expr_nargs (call) * sizeof (*argarray));
+ memcpy (argarray + call_expr_nargs (call),
+ CALL_EXPR_ARGP (id->call_expr)
+ + (call_expr_nargs (id->call_expr) - nargs),
+ nargs * sizeof (*argarray));
+
+ new_call = build_call_array (TREE_TYPE (call),
+ CALL_EXPR_FN (call),
+ nargs + call_expr_nargs (call),
+ argarray);
+ /* Copy all CALL_EXPR flags, locus and block, except
+ CALL_EXPR_VA_ARG_PACK flag. */
+ CALL_EXPR_STATIC_CHAIN (new_call)
+ = CALL_EXPR_STATIC_CHAIN (call);
+ CALL_EXPR_TAILCALL (new_call) = CALL_EXPR_TAILCALL (call);
+ CALL_EXPR_RETURN_SLOT_OPT (new_call)
+ = CALL_EXPR_RETURN_SLOT_OPT (call);
+ CALL_FROM_THUNK_P (new_call) = CALL_FROM_THUNK_P (call);
+ CALL_CANNOT_INLINE_P (new_call)
+ = CALL_CANNOT_INLINE_P (call);
+ TREE_NOTHROW (new_call) = TREE_NOTHROW (call);
+ SET_EXPR_LOCUS (new_call, EXPR_LOCUS (call));
+ TREE_BLOCK (new_call) = TREE_BLOCK (call);
+
+ call_ptr = stmtp;
+ if (TREE_CODE (*call_ptr) == GIMPLE_MODIFY_STMT)
+ call_ptr = &GIMPLE_STMT_OPERAND (*call_ptr, 1);
+ if (TREE_CODE (*call_ptr) == WITH_SIZE_EXPR)
+ call_ptr = &TREE_OPERAND (*call_ptr, 0);
+ gcc_assert (*call_ptr == call);
+ *call_ptr = new_call;
+ stmt = *stmtp;
+ update_stmt (stmt);
+ }
+ else if (call
+ && id->call_expr
+ && (decl = get_callee_fndecl (call))
+ && DECL_BUILT_IN_CLASS (decl) == BUILT_IN_NORMAL
+ && DECL_FUNCTION_CODE (decl)
+ == BUILT_IN_VA_ARG_PACK_LEN)
+ {
+ /* __builtin_va_arg_pack_len () should be replaced by
+ the number of anonymous arguments. */
+ int nargs = call_expr_nargs (id->call_expr);
+ tree count, *call_ptr, p;
+
+ for (p = DECL_ARGUMENTS (id->src_fn); p; p = TREE_CHAIN (p))
+ nargs--;
+
+ count = build_int_cst (integer_type_node, nargs);
+ call_ptr = stmtp;
+ if (TREE_CODE (*call_ptr) == GIMPLE_MODIFY_STMT)
+ call_ptr = &GIMPLE_STMT_OPERAND (*call_ptr, 1);
+ if (TREE_CODE (*call_ptr) == WITH_SIZE_EXPR)
+ call_ptr = &TREE_OPERAND (*call_ptr, 0);
+ gcc_assert (*call_ptr == call && call_ptr != stmtp);
+ *call_ptr = count;
+ stmt = *stmtp;
+ update_stmt (stmt);
+ call = NULL_TREE;
+ }
+
/* Statements produced by inlining can be unfolded, especially
when we constant propagated some operands. We can't fold
them right now for two reasons:
inlinable_function_p (tree fn)
{
bool inlinable = true;
+ bool do_warning;
+ tree always_inline;
/* If we've already decided this function shouldn't be inlined,
there's no need to check again. */
if (DECL_UNINLINABLE (fn))
return false;
- /* See if there is any language-specific reason it cannot be
- inlined. (It is important that this hook be called early because
- in C++ it may result in template instantiation.)
- If the function is not inlinable for language-specific reasons,
- it is left up to the langhook to explain why. */
- inlinable = !lang_hooks.tree_inlining.cannot_inline_tree_fn (&fn);
+ /* We only warn for functions declared `inline' by the user. */
+ do_warning = (warn_inline
+ && DECL_INLINE (fn)
+ && DECL_DECLARED_INLINE_P (fn)
+ && !DECL_IN_SYSTEM_HEADER (fn));
+
+ always_inline = lookup_attribute ("always_inline", DECL_ATTRIBUTES (fn));
+
+ if (flag_really_no_inline
+ && always_inline == NULL)
+ {
+ if (do_warning)
+ warning (OPT_Winline, "function %q+F can never be inlined because it "
+ "is suppressed using -fno-inline", fn);
+ inlinable = false;
+ }
+
+ /* Don't auto-inline anything that might not be bound within
+ this unit of translation. */
+ else if (!DECL_DECLARED_INLINE_P (fn)
+ && DECL_REPLACEABLE_P (fn))
+ inlinable = false;
+
+ else if (!function_attribute_inlinable_p (fn))
+ {
+ if (do_warning)
+ warning (OPT_Winline, "function %q+F can never be inlined because it "
+ "uses attributes conflicting with inlining", fn);
+ inlinable = false;
+ }
/* If we don't have the function body available, we can't inline it.
However, this should not be recorded since we also get here for
about functions that would for example call alloca. But since
this a property of the function, just one warning is enough.
As a bonus we can now give more details about the reason why a
- function is not inlinable.
- We only warn for functions declared `inline' by the user. */
- bool do_warning = (warn_inline
- && DECL_INLINE (fn)
- && DECL_DECLARED_INLINE_P (fn)
- && !DECL_IN_SYSTEM_HEADER (fn));
-
- if (lookup_attribute ("always_inline", DECL_ATTRIBUTES (fn)))
+ function is not inlinable. */
+ if (always_inline)
sorry (inline_forbidden_reason, fn);
else if (do_warning)
warning (OPT_Winline, inline_forbidden_reason, fn);
{
tree decl = get_callee_fndecl (x);
- cost = d->weights->call_cost;
+ if (decl && DECL_BUILT_IN_CLASS (decl) == BUILT_IN_MD)
+ cost = d->weights->target_builtin_call_cost;
+ else
+ cost = d->weights->call_cost;
+
if (decl && DECL_BUILT_IN_CLASS (decl) == BUILT_IN_NORMAL)
switch (DECL_FUNCTION_CODE (decl))
{
init_inline_once (void)
{
eni_inlining_weights.call_cost = PARAM_VALUE (PARAM_INLINE_CALL_COST);
+ eni_inlining_weights.target_builtin_call_cost = 1;
eni_inlining_weights.div_mod_cost = 10;
eni_inlining_weights.switch_cost = 1;
eni_inlining_weights.omp_cost = 40;
eni_size_weights.call_cost = 1;
+ eni_size_weights.target_builtin_call_cost = 1;
eni_size_weights.div_mod_cost = 1;
eni_size_weights.switch_cost = 10;
eni_size_weights.omp_cost = 40;
underestimating the cost does less harm than overestimating it, so
we choose a rather small value here. */
eni_time_weights.call_cost = 10;
+ eni_time_weights.target_builtin_call_cost = 10;
eni_time_weights.div_mod_cost = 10;
eni_time_weights.switch_cost = 4;
eni_time_weights.omp_cost = 40;
}
-typedef struct function *function_p;
-
-DEF_VEC_P(function_p);
-DEF_VEC_ALLOC_P(function_p,heap);
-
-/* Initialized with NOGC, making this poisonous to the garbage collector. */
-static VEC(function_p,heap) *cfun_stack;
-
-void
-push_cfun (struct function *new_cfun)
-{
- VEC_safe_push (function_p, heap, cfun_stack, cfun);
- cfun = new_cfun;
-}
-
-void
-pop_cfun (void)
-{
- cfun = VEC_pop (function_p, cfun_stack);
-}
-
/* Install new lexical TREE_BLOCK underneath 'current_block'. */
static void
add_lexical_block (tree current_block, tree new_block)
id->src_fn = fn;
id->src_node = cg_edge->callee;
id->src_cfun = DECL_STRUCT_FUNCTION (fn);
+ id->call_expr = t;
initialize_inlined_parameters (id, t, fn, bb);