GCC is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
-the Free Software Foundation; either version 2, or (at your option)
+the Free Software Foundation; either version 3, or (at your option)
any later version.
GCC is distributed in the hope that it will be useful,
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
-along with GCC; see the file COPYING. If not, write to
-the Free Software Foundation, 51 Franklin Street, Fifth Floor,
-Boston, MA 02110-1301, USA. */
+along with GCC; see the file COPYING3. If not see
+<http://www.gnu.org/licenses/>. */
#include "config.h"
#include "system.h"
#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. */
{
case INTEGER_TYPE:
case REAL_TYPE:
+ case FIXED_POINT_TYPE:
case ENUMERAL_TYPE:
case BOOLEAN_TYPE:
t = TYPE_MIN_VALUE (new);
/* We can not chain the local static declarations into the unexpanded_var_list
as we can't duplicate them or break one decl rule. Go ahead and link
them into unexpanded_var_list. */
- if (!lang_hooks.tree_inlining.auto_var_in_fn_p (old_var, id->src_fn)
+ if (!auto_var_in_fn_p (old_var, id->src_fn)
&& !DECL_EXTERNAL (old_var))
{
cfun->unexpanded_var_list = tree_cons (NULL_TREE, old_var,
variables. We don't want to copy static variables; there's only
one of those, no matter how many times we inline the containing
function. Similarly for globals from an outer function. */
- else if (lang_hooks.tree_inlining.auto_var_in_fn_p (*tp, fn))
+ else if (auto_var_in_fn_p (*tp, fn))
{
tree new_decl;
discarding. */
if (TREE_CODE (*tp) == GIMPLE_MODIFY_STMT
&& GIMPLE_STMT_OPERAND (*tp, 0) == GIMPLE_STMT_OPERAND (*tp, 1)
- && (lang_hooks.tree_inlining.auto_var_in_fn_p
- (GIMPLE_STMT_OPERAND (*tp, 0), fn)))
+ && (auto_var_in_fn_p (GIMPLE_STMT_OPERAND (*tp, 0), fn)))
{
/* Some assignments VAR = VAR; don't generate any rtl code
and thus don't count as variable modification. Avoid
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);
+ }
+
/* Statements produced by inlining can be unfolded, especially
when we constant propagated some operands. We can't fold
them right now for two reasons:
var = get_base_address (TREE_OPERAND (value, 0));
- return var && lang_hooks.tree_inlining.auto_var_in_fn_p (var, fn);
+ return var && auto_var_in_fn_p (var, fn);
}
static void
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);
case OMP_CLAUSE:
case OMP_RETURN:
case OMP_CONTINUE:
+ case OMP_SECTIONS_SWITCH:
break;
/* We don't account constants for now. Assume that the cost is amortized
case IDENTIFIER_NODE:
case INTEGER_CST:
case REAL_CST:
+ case FIXED_CST:
case COMPLEX_CST:
case VECTOR_CST:
case STRING_CST:
case MINUS_EXPR:
case MULT_EXPR:
+ case FIXED_CONVERT_EXPR:
case FIX_TRUNC_EXPR:
case NEGATE_EXPR:
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);
gimple_expand_calls_inline (bb, &id);
pop_gimplify_context (NULL);
- /* Renumber the (code) basic_blocks consecutively. */
- compact_blocks ();
- /* Renumber the lexical scoping (non-code) blocks consecutively. */
- number_blocks (fn);
#ifdef ENABLE_CHECKING
{
gcc_assert (e->inline_failed);
}
#endif
+
+ /* Fold the statements before compacting/renumbering the basic blocks. */
+ fold_marked_statements (last, id.statements_to_fold);
+ pointer_set_destroy (id.statements_to_fold);
+
+ /* Renumber the (code) basic_blocks consecutively. */
+ compact_blocks ();
+ /* Renumber the lexical scoping (non-code) blocks consecutively. */
+ number_blocks (fn);
/* We are not going to maintain the cgraph edges up to date.
Kill it so it won't confuse us. */
cgraph_node_remove_callees (id.dst_node);
- fold_marked_statements (last, id.statements_to_fold);
- pointer_set_destroy (id.statements_to_fold);
fold_cond_expr_cond ();
if (current_function_has_nonlocal_label)
make_nonlocal_label_edges ();