if (!flag_wpa)
gcc_checking_assert (tree_versionable_function_p (old_decl));
+ gcc_assert (old_node->local.can_change_signature || !args_to_skip);
+
/* Make a new FUNCTION_DECL tree node */
if (!args_to_skip)
new_decl = copy_node (old_decl);
Currently computed and used only by ipa-cp. */
unsigned versionable : 1;
+ /* False when function calling convention and signature can not be changed.
+ This is the case when __builtin_apply_args is used. */
+ unsigned can_change_signature : 1;
+
/* True when function should be inlined independently on its size. */
unsigned disregard_inline_limits : 1;
if (!tree_versionable_function_p (old_decl))
return NULL;
+ gcc_assert (old_version_node->local.can_change_signature || !args_to_skip);
+
/* Make a new FUNCTION_DECL tree node for the
new version. */
if (!args_to_skip)
{
/* FIXME: remove this CONST_CAST when cgraph.[ch] is constified. */
struct cgraph_local_info *i = cgraph_local_info (CONST_CAST_TREE (decl));
- if (i && i->local)
+ if (i && i->local && i->can_change_signature)
{
int local_regparm, globals = 0, regno;
{
/* FIXME: remove this CONST_CAST when cgraph.[ch] is constified. */
struct cgraph_local_info *i = cgraph_local_info (CONST_CAST_TREE(decl));
- if (i && i->local)
+ if (i && i->local && i->can_change_signature)
return TARGET_SSE2 ? 2 : 1;
}
va_start so for local functions maybe_vaarg can be made aggressive
helping K&R code.
FIXME: once typesytem is fixed, we won't need this code anymore. */
- if (i && i->local)
+ if (i && i->local && i->can_change_signature)
fntype = TREE_TYPE (fndecl);
cum->maybe_vaarg = (fntype
? (!prototype_p (fntype) || stdarg_p (fntype))
for (node = cgraph_nodes; node; node = node->next)
if (node->analyzed && ipcp_node_is_clone (node))
{
- bitmap args_to_skip = BITMAP_ALLOC (NULL);
+ bitmap args_to_skip = NULL;
struct cgraph_node *orig_node = ipcp_get_orig_node (node);
struct ipa_node_params *info = IPA_NODE_REF (orig_node);
int i, count = ipa_get_param_count (info);
struct cgraph_edge *cs, *next;
- for (i = 0; i < count; i++)
+ if (node->local.can_change_signature)
{
- struct ipcp_lattice *lat = ipcp_get_lattice (info, i);
-
- /* We can proactively remove obviously unused arguments. */
- if (!ipa_is_param_used (info, i))
+ args_to_skip = BITMAP_ALLOC (NULL);
+ for (i = 0; i < count; i++)
{
- bitmap_set_bit (args_to_skip, i);
- continue;
- }
+ struct ipcp_lattice *lat = ipcp_get_lattice (info, i);
+
+ /* We can proactively remove obviously unused arguments. */
+ if (!ipa_is_param_used (info, i))
+ {
+ bitmap_set_bit (args_to_skip, i);
+ continue;
+ }
- if (lat->type == IPA_CONST_VALUE)
- bitmap_set_bit (args_to_skip, i);
+ if (lat->type == IPA_CONST_VALUE)
+ bitmap_set_bit (args_to_skip, i);
+ }
}
for (cs = node->callers; cs; cs = next)
{
info = IPA_NODE_REF (node);
count = ipa_get_param_count (info);
- for (i = 0; i < count; i++)
- {
- struct ipcp_lattice *lat = ipcp_get_lattice (info, i);
+ if (node->local.can_change_signature)
+ for (i = 0; i < count; i++)
+ {
+ struct ipcp_lattice *lat = ipcp_get_lattice (info, i);
- /* We can proactively remove obviously unused arguments. */
- if (!ipa_is_param_used (info, i))
- removable_args++;
+ /* We can proactively remove obviously unused arguments. */
+ if (!ipa_is_param_used (info, i))
+ removable_args++;
- if (lat->type == IPA_CONST_VALUE)
- removable_args++;
- }
+ if (lat->type == IPA_CONST_VALUE)
+ removable_args++;
+ }
/* We make just very simple estimate of savings for removal of operand from
call site. Precise cost is dificult to get, as our size metric counts
count = ipa_get_param_count (info);
replace_trees = VEC_alloc (ipa_replace_map_p, gc, 1);
- args_to_skip = BITMAP_GGC_ALLOC ();
+
+ if (node->local.can_change_signature)
+ args_to_skip = BITMAP_GGC_ALLOC ();
+ else
+ args_to_skip = NULL;
for (i = 0; i < count; i++)
{
struct ipcp_lattice *lat = ipcp_get_lattice (info, i);
parm_tree = ipa_get_param (info, i);
/* We can proactively remove obviously unused arguments. */
- if (!ipa_is_param_used (info, i))
+ if (!ipa_is_param_used (info, i))
{
- bitmap_set_bit (args_to_skip, i);
+ if (args_to_skip)
+ bitmap_set_bit (args_to_skip, i);
continue;
}
replace_param =
ipcp_create_replace_map (parm_tree, lat);
VEC_safe_push (ipa_replace_map_p, gc, replace_trees, replace_param);
- bitmap_set_bit (args_to_skip, i);
+ if (args_to_skip)
+ bitmap_set_bit (args_to_skip, i);
}
}
/* Can this function be inlined at all? */
node->local.inlinable = tree_inlinable_function_p (node->decl);
+
+ /* Inlinable functions always can change signature. */
+ if (node->local.inlinable)
+ node->local.can_change_signature = true;
+ else
+ {
+ struct cgraph_edge *e;
+
+ /* Functions calling builtlin_apply can not change signature. */
+ for (e = node->callees; e; e = e->next_callee)
+ if (DECL_BUILT_IN (e->callee->decl)
+ && DECL_BUILT_IN_CLASS (e->callee->decl) == BUILT_IN_NORMAL
+ && DECL_FUNCTION_CODE (e->callee->decl) == BUILT_IN_APPLY_ARGS)
+ break;
+ node->local.can_change_signature = !e;
+ }
if (node->local.inlinable && !node->local.disregard_inline_limits)
node->local.disregard_inline_limits
= DECL_DISREGARD_INLINE_LIMITS (node->decl);
way to store builtin_stack_save result in non-SSA variable
since all calls to those are compiler generated. */
case BUILT_IN_APPLY:
+ case BUILT_IN_APPLY_ARGS:
case BUILT_IN_VA_START:
if (dump_file && (dump_flags & TDF_DETAILS))
fprintf (dump_file,
bp_pack_value (&bp, node->local.finalized, 1);
bp_pack_value (&bp, node->local.inlinable, 1);
bp_pack_value (&bp, node->local.versionable, 1);
+ bp_pack_value (&bp, node->local.can_change_signature, 1);
bp_pack_value (&bp, node->local.disregard_inline_limits, 1);
bp_pack_value (&bp, node->local.redefined_extern_inline, 1);
bp_pack_value (&bp, node->local.vtable_method, 1);
node->local.finalized = bp_unpack_value (bp, 1);
node->local.inlinable = bp_unpack_value (bp, 1);
node->local.versionable = bp_unpack_value (bp, 1);
+ node->local.can_change_signature = bp_unpack_value (bp, 1);
node->local.disregard_inline_limits = bp_unpack_value (bp, 1);
node->local.redefined_extern_inline = bp_unpack_value (bp, 1);
node->local.vtable_method = bp_unpack_value (bp, 1);
--- /dev/null
+#define INTEGER_ARG 5
+
+extern void abort(void);
+
+static void foo(int arg)
+{
+ if (arg != INTEGER_ARG)
+ abort();
+}
+
+static void bar(int arg)
+{
+ foo(arg);
+ __builtin_apply(foo, __builtin_apply_args(), 16);
+}
+
+int main(void)
+{
+ bar(INTEGER_ARG);
+
+ return 0;
+}
return false;
}
+ if (!node->local.can_change_signature)
+ {
+ if (dump_file)
+ fprintf (dump_file, "Function can not change signature.\n");
+ return false;
+ }
+
if (!tree_versionable_function_p (node->decl))
{
if (dump_file)