re PR tree-optimization/47237 (builtin_apply_args broken WRT local ABI changes.)
authorJan Hubicka <hubicka@gcc.gnu.org>
Wed, 26 Jan 2011 14:06:20 +0000 (14:06 +0000)
committerJan Hubicka <hubicka@gcc.gnu.org>
Wed, 26 Jan 2011 14:06:20 +0000 (14:06 +0000)
PR target/47237
* cgraph.h (cgraph_local_info): New field can_change_signature.
* ipa-cp.c (ipcp_update_callgraph): Only compute args_to_skip if callee
signature can change.
(ipcp_estimate_growth): Call sequence simplify only if calle signature
can change.
(ipcp_insert_stage): Only compute args_to_skip if signature can change.
(cgraph_function_versioning): We can not change signature of functions
that don't allow that.
* lto-cgraph.c (lto_output_node): Stream local.can_change_signature.
(lto_input_node): Likewise.
* ipa-inline.c (compute_inline_parameters): Compute local.can_change_signature.
* ipa-split.c (visit_bb): Never split away APPLY_ARGS.
* tree-sra.c (ipa_sra_preliminary_function_checks): Give up on functions
that can not change signature.
* i386.c (ix86_function_regparm, ix86_function_sseregparm,
init_cumulative_args): Do not use local calling conventions for functions
that can not change signature.

From-SVN: r169290

gcc/cgraph.c
gcc/cgraph.h
gcc/cgraphunit.c
gcc/config/i386/i386.c
gcc/ipa-cp.c
gcc/ipa-inline.c
gcc/ipa-split.c
gcc/lto-cgraph.c
gcc/testsuite/gcc.c-torture/execute/pr47237.c [new file with mode: 0644]
gcc/tree-sra.c

index c8f9b04bb1234ea453dcf953461a41250a1bb32d..6176b4d6a45a82c83ae21f3faf49543eaaeaa8bf 100644 (file)
@@ -2300,6 +2300,8 @@ cgraph_create_virtual_clone (struct cgraph_node *old_node,
   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);
index 33b316795353729a3254671295db829a741b1263..2df3fa54d9fd8ce64bae4f268edcf1ae250a4b79 100644 (file)
@@ -114,6 +114,10 @@ struct GTY(()) cgraph_local_info {
      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;
 
index 2eb3285290b77dc0e3c862c08648c3fc45461ef1..2245164c3eb81fe785b158c2eb8a76ffd22a5fdf 100644 (file)
@@ -2014,6 +2014,8 @@ cgraph_function_versioning (struct cgraph_node *old_version_node,
   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)
index ee1790f577a641178299f95bdfa2951d16789b68..4d927c2b259b7e3c2b5691f3791f3ec82b6a8657 100644 (file)
@@ -5493,7 +5493,7 @@ ix86_function_regparm (const_tree type, const_tree decl)
     {
       /* 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;
 
@@ -5570,7 +5570,7 @@ ix86_function_sseregparm (const_tree type, const_tree decl, bool warn)
     {
       /* 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;
     }
 
@@ -5954,7 +5954,7 @@ init_cumulative_args (CUMULATIVE_ARGS *cum,  /* Argument info to initialize */
      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))
index ce6fd598715b7e94404c941fd8b924d7680385e4..b06238d84c892ac045c44710f4a10d205ad9ff8a 100644 (file)
@@ -1040,25 +1040,29 @@ ipcp_update_callgraph (void)
   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)
          {
@@ -1130,17 +1134,18 @@ ipcp_estimate_growth (struct cgraph_node *node)
 
   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
@@ -1386,16 +1391,21 @@ ipcp_insert_stage (void)
       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;
            }
 
@@ -1404,7 +1414,8 @@ ipcp_insert_stage (void)
              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);
            }
        }
 
index 116abd6619ae37857e009b33ff78a7ab4d507c51..8087c81896e3670746c3ca2ca667860f3b8e544e 100644 (file)
@@ -1997,6 +1997,22 @@ compute_inline_parameters (struct cgraph_node *node)
 
   /* 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);
index 30060440fe273b66c5248b50798064abb7f9c1fa..dce57eaeb639b77b670c916ea3593b372db35e19 100644 (file)
@@ -670,6 +670,7 @@ visit_bb (basic_block bb, basic_block return_bb,
             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,
index 18bb83b8ad65100eb48ced51806cc173f2c6f28e..fb05a1d05cb14bbdb6582751f3dca555bf57a6b9 100644 (file)
@@ -499,6 +499,7 @@ lto_output_node (struct lto_simple_output_block *ob, struct cgraph_node *node,
   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);
@@ -950,6 +951,7 @@ input_overwrite_node (struct lto_file_decl_data *file_data,
   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);
diff --git a/gcc/testsuite/gcc.c-torture/execute/pr47237.c b/gcc/testsuite/gcc.c-torture/execute/pr47237.c
new file mode 100644 (file)
index 0000000..2100e15
--- /dev/null
@@ -0,0 +1,22 @@
+#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;
+}
index c2ec20429322f23eba5e7c257bab80e75d9b57d4..47613f6298a6ca559f6949dd5cbb8dc3a53ca296 100644 (file)
@@ -4425,6 +4425,13 @@ ipa_sra_preliminary_function_checks (struct cgraph_node *node)
       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)