* tree.c (build_function_type_skip_args, build_function_decl_skip_args):
authorhubicka <hubicka@138bc75d-0d04-0410-961f-82ee72b054a4>
Fri, 29 Aug 2008 11:31:40 +0000 (11:31 +0000)
committerhubicka <hubicka@138bc75d-0d04-0410-961f-82ee72b054a4>
Fri, 29 Aug 2008 11:31:40 +0000 (11:31 +0000)
New functions.
* tree.h (build_function_type_skip_args, build_function_decl_skip_args):
Declare.
* gimple.c (giple_copy_call_skip_args): New function.
(giple_copy_call_skip_args): Declare.

* cgraph.h (cgraph_function_versioning): Add skip_args arugmnet
* ipa-cp.c (ipcp_node_not_modifiable_p): Rename to ...
(ipcp_node_modifiable_p): ... this one; use tree_versionable_function_p.
(ipcp_create_replace_map): Improve debug output.
(ipcp_need_redirect_p): Return false when not clonning.
(ipcp_update_callgraph): Skip args.
(ipcp_insert_stage): UPdate call of !ipcp_node_modifiable_p;
skip args.
* cgraphunit.c (cgraph_function_versioning): Add skip_args argument.
(save_inline_function_body): Update call of tree_function_versioning.
* ipa-prop.c (ipa_edge_removal_hook): Do not ICE on unanalyzed nodes.
* tree-inline.c (copy_arguments_for_versioning): Add skip_args argument.
(tree_function_versioning): Likewise.
* tree-inline.h (tree_function_versioning): Update prototype.

git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@139761 138bc75d-0d04-0410-961f-82ee72b054a4

gcc/ChangeLog
gcc/cgraph.h
gcc/cgraphunit.c
gcc/gimple.c
gcc/gimple.h
gcc/ipa-cp.c
gcc/ipa-prop.c
gcc/tree-inline.c
gcc/tree-inline.h
gcc/tree.c
gcc/tree.h

index 637a89e..c85ac79 100644 (file)
@@ -1,5 +1,29 @@
 2008-08-29  Jan Hubicka  <jh@suse.cz>
 
+       * tree.c (build_function_type_skip_args, build_function_decl_skip_args):
+       New functions.
+       * tree.h (build_function_type_skip_args, build_function_decl_skip_args):
+       Declare.
+       * gimple.c (giple_copy_call_skip_args): New function.
+       (giple_copy_call_skip_args): Declare.
+
+       * cgraph.h (cgraph_function_versioning): Add skip_args arugmnet
+       * ipa-cp.c (ipcp_node_not_modifiable_p): Rename to ...
+       (ipcp_node_modifiable_p): ... this one; use tree_versionable_function_p.
+       (ipcp_create_replace_map): Improve debug output.
+       (ipcp_need_redirect_p): Return false when not clonning.
+       (ipcp_update_callgraph): Skip args.
+       (ipcp_insert_stage): UPdate call of !ipcp_node_modifiable_p;
+       skip args.
+       * cgraphunit.c (cgraph_function_versioning): Add skip_args argument.
+       (save_inline_function_body): Update call of tree_function_versioning.
+       * ipa-prop.c (ipa_edge_removal_hook): Do not ICE on unanalyzed nodes.
+       * tree-inline.c (copy_arguments_for_versioning): Add skip_args argument.
+       (tree_function_versioning): Likewise.
+       * tree-inline.h (tree_function_versioning): Update prototype.
+
+2008-08-29  Jan Hubicka  <jh@suse.cz>
+
        * loop-unswitch.c (unswitch_single_loop): Use optimize_loop_for_speed_p.
        * tree-ssa-threadupdate.c (mark_threaded_blocks): Use optimize_function_for_size_p.
        * tracer.c (ignore_bb_p): Use optimize_bb_for_size_p.
index 15cbf29..5fe0eea 100644 (file)
@@ -351,7 +351,8 @@ void cgraph_reset_static_var_maps (void);
 void init_cgraph (void);
 struct cgraph_node *cgraph_function_versioning (struct cgraph_node *,
                                                VEC(cgraph_edge_p,heap)*,
-                                               varray_type);
+                                               varray_type,
+                                               bitmap);
 void cgraph_analyze_function (struct cgraph_node *);
 struct cgraph_node *save_inline_function_body (struct cgraph_node *);
 void record_references_in_initializer (tree);
index 371e17c..43cdfda 100644 (file)
@@ -1496,12 +1496,15 @@ cgraph_copy_node_for_versioning (struct cgraph_node *old_version,
     TREE_MAP is a mapping of tree nodes we want to replace with
     new ones (according to results of prior analysis).
     OLD_VERSION_NODE is the node that is versioned.
-    It returns the new version's cgraph node.  */
+    It returns the new version's cgraph node. 
+    ARGS_TO_SKIP lists arguments to be omitted from functions
+    */
 
 struct cgraph_node *
 cgraph_function_versioning (struct cgraph_node *old_version_node,
                            VEC(cgraph_edge_p,heap) *redirect_callers,
-                           varray_type tree_map)
+                           varray_type tree_map,
+                           bitmap args_to_skip)
 {
   tree old_decl = old_version_node->decl;
   struct cgraph_node *new_version_node = NULL;
@@ -1512,7 +1515,10 @@ cgraph_function_versioning (struct cgraph_node *old_version_node,
 
   /* Make a new FUNCTION_DECL tree node for the
      new version. */
-  new_decl = copy_node (old_decl);
+  if (!args_to_skip)
+    new_decl = copy_node (old_decl);
+  else
+    new_decl = build_function_decl_skip_args (old_decl, args_to_skip);
 
   /* Create the new version's call-graph node.
      and update the edges of the new node. */
@@ -1521,7 +1527,7 @@ cgraph_function_versioning (struct cgraph_node *old_version_node,
                                     redirect_callers);
 
   /* Copy the OLD_VERSION_NODE function tree to the new version.  */
-  tree_function_versioning (old_decl, new_decl, tree_map, false);
+  tree_function_versioning (old_decl, new_decl, tree_map, false, args_to_skip);
   /* Update the call_expr on the edges to call the new version node. */
   update_call_expr (new_version_node);
 
@@ -1560,7 +1566,7 @@ save_inline_function_body (struct cgraph_node *node)
   gcc_assert (first_clone == cgraph_node (first_clone->decl));
 
   /* Copy the OLD_VERSION_NODE function tree to the new version.  */
-  tree_function_versioning (node->decl, first_clone->decl, NULL, true);
+  tree_function_versioning (node->decl, first_clone->decl, NULL, true, NULL);
 
   DECL_EXTERNAL (first_clone->decl) = 0;
   DECL_ONE_ONLY (first_clone->decl) = 0;
index c651f0d..6e203b7 100644 (file)
@@ -3180,4 +3180,37 @@ canonicalize_cond_expr_cond (tree t)
   return NULL_TREE;
 }
 
+/* Build call same as STMT but skipping arguments ARGS_TO_SKIP.  */
+gimple
+giple_copy_call_skip_args (gimple stmt, bitmap args_to_skip)
+{
+  int i;
+  tree fn = gimple_call_fn (stmt);
+  int nargs = gimple_call_num_args (stmt);
+  VEC(tree, heap) *vargs = VEC_alloc (tree, heap, nargs);
+  gimple new_stmt;
+
+  for (i = 0; i < nargs; i++)
+    if (!bitmap_bit_p (args_to_skip, i))
+      VEC_quick_push (tree, vargs, gimple_call_arg (stmt, i));
+
+  new_stmt = gimple_build_call_vec (fn, vargs);
+  VEC_free (tree, heap, vargs);
+  if (gimple_call_lhs (stmt))
+    gimple_call_set_lhs (new_stmt, gimple_call_lhs (stmt));
+
+  gimple_set_block (new_stmt, gimple_block (stmt));
+  if (gimple_has_location (stmt))
+    gimple_set_location (new_stmt, gimple_location (stmt));
+
+  /* Carry all the flags to the new GIMPLE_CALL.  */
+  gimple_call_set_chain (new_stmt, gimple_call_chain (stmt));
+  gimple_call_set_tail (new_stmt, gimple_call_tail_p (stmt));
+  gimple_call_set_cannot_inline (new_stmt, gimple_call_cannot_inline_p (stmt));
+  gimple_call_set_return_slot_opt (new_stmt, gimple_call_return_slot_opt_p (stmt));
+  gimple_call_set_from_thunk (new_stmt, gimple_call_from_thunk_p (stmt));
+  gimple_call_set_va_arg_pack (new_stmt, gimple_call_va_arg_pack_p (stmt));
+  return new_stmt;
+}
+
 #include "gt-gimple.h"
index ebb8eeb..e8c0ad6 100644 (file)
@@ -4471,6 +4471,7 @@ basic_block gsi_insert_on_edge_immediate (edge, gimple);
 basic_block gsi_insert_seq_on_edge_immediate (edge, gimple_seq);
 void gsi_commit_one_edge_insert (edge, basic_block *);
 void gsi_commit_edge_inserts (void);
+gimple giple_copy_call_skip_args (gimple, bitmap);
 
 
 /* Convenience routines to walk all statements of a gimple function.
index ca7e231..4b0a5f2 100644 (file)
@@ -560,12 +560,11 @@ ipcp_iterate_stage (void)
 /* Check conditions to forbid constant insertion to function described by
    NODE.  */
 static inline bool
-ipcp_node_not_modifiable_p (struct cgraph_node *node)
+ipcp_node_modifiable_p (struct cgraph_node *node)
 {
-  /* ??? Handle pending sizes case.  */
-  if (DECL_UNINLINABLE (node->decl))
-    return true;
-  return false;
+  /* Once we will be able to do in-place replacement, we can be more
+     lax here.  */
+  return tree_versionable_function_p (node->decl);
 }
 
 /* Print count scale data structures.  */
@@ -745,9 +744,15 @@ ipcp_create_replace_map (tree parm_tree, struct ipcp_lattice *lat)
   tree const_val;
 
   replace_map = XCNEW (struct ipa_replace_map);
-  if (dump_file)
-    fprintf (dump_file, "replacing param with const\n");
   const_val = build_const_val (lat, TREE_TYPE (parm_tree));
+  if (dump_file)
+    {
+      fprintf (dump_file, "  replacing param ");
+      print_generic_expr (dump_file, parm_tree, 0);
+      fprintf (dump_file, " with const ");
+      print_generic_expr (dump_file, const_val, 0);
+      fprintf (dump_file, "\n");
+    }
   replace_map->old_tree = parm_tree;
   replace_map->new_tree = const_val;
   replace_map->replace_p = true;
@@ -766,6 +771,9 @@ ipcp_need_redirect_p (struct cgraph_edge *cs)
   struct ipa_jump_func *jump_func;
   struct cgraph_node *node = cs->callee, *orig;
 
+  if (!flag_ipa_cp_clone)
+    return false;
+
   if ((orig = ipcp_get_orig_node (node)) != NULL)
     node = orig;
   if (ipcp_get_orig_node (cs->caller))
@@ -791,26 +799,59 @@ ipcp_need_redirect_p (struct cgraph_edge *cs)
 static void
 ipcp_update_callgraph (void)
 {
-  struct cgraph_node *node, *orig_callee;
-  struct cgraph_edge *cs;
+  struct cgraph_node *node;
 
   for (node = cgraph_nodes; node; node = node->next)
-    {
-      /* want to fix only original nodes  */
-      if (!node->analyzed || ipcp_node_is_clone (node))
-       continue;
-      for (cs = node->callees; cs; cs = cs->next_callee)
-       if (ipcp_node_is_clone (cs->callee))
+    if (node->analyzed && ipcp_node_is_clone (node))
+      {
+       bitmap args_to_skip = BITMAP_ALLOC (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++)
          {
-           /* Callee is a cloned node  */
-           orig_callee = ipcp_get_orig_node (cs->callee);
-           if (ipcp_need_redirect_p (cs))
+           struct ipcp_lattice *lat = ipcp_get_ith_lattice (info, i);
+           tree parm_tree = ipa_get_ith_param (info, i);
+
+           /* We can proactively remove obviously unused arguments.  */
+           if (is_gimple_reg (parm_tree)
+               && !gimple_default_def (DECL_STRUCT_FUNCTION (orig_node->decl),
+                                       parm_tree))
              {
-               cgraph_redirect_edge_callee (cs, orig_callee);
-               gimple_call_set_fndecl (cs->call_stmt, orig_callee->decl);
+               bitmap_set_bit (args_to_skip, i);
+               continue;
              }
+
+           if (lat->type == IPA_CONST_VALUE)
+             bitmap_set_bit (args_to_skip, i);
          }
-    }
+       for (cs = node->callers; cs; cs = next)
+         {
+           next = cs->next_caller;
+           if (ipcp_node_is_clone (cs->caller) || !ipcp_need_redirect_p (cs))
+             {
+               gimple new_stmt;
+               gimple_stmt_iterator gsi;
+
+               current_function_decl = cs->caller->decl;
+               push_cfun (DECL_STRUCT_FUNCTION (cs->caller->decl));
+               
+               new_stmt = giple_copy_call_skip_args (cs->call_stmt, args_to_skip);
+               gsi = gsi_for_stmt (cs->call_stmt);
+               gsi_replace (&gsi, new_stmt, true);
+               cgraph_set_call_stmt (cs, new_stmt);
+               pop_cfun ();
+               current_function_decl = NULL;
+             }
+           else
+             {
+               cgraph_redirect_edge_callee (cs, orig_node);
+               gimple_call_set_fndecl (cs->call_stmt, orig_node->decl);
+             }
+         }
+      }
 }
 
 /* Update all cfg basic blocks in NODE according to SCALE.  */
@@ -989,7 +1030,7 @@ ipcp_insert_stage (void)
     {
       struct ipa_node_params *info;
       /* Propagation of the constant is forbidden in certain conditions.  */
-      if (!node->analyzed || ipcp_node_not_modifiable_p (node))
+      if (!node->analyzed || !ipcp_node_modifiable_p (node))
          continue;
       info = IPA_NODE_REF (node);
       if (ipa_is_called_with_var_arguments (info))
@@ -1004,6 +1045,7 @@ ipcp_insert_stage (void)
     {
       struct ipa_node_params *info;
       int growth = 0;
+      bitmap args_to_skip;
 
       node = (struct cgraph_node *)fibheap_extract_min (heap);
       node->aux = NULL;
@@ -1033,20 +1075,27 @@ ipcp_insert_stage (void)
 
       VARRAY_GENERIC_PTR_INIT (replace_trees, ipcp_const_param_count (node),
                                "replace_trees");
+      args_to_skip = BITMAP_ALLOC (NULL);
       for (i = 0; i < count; i++)
        {
          struct ipcp_lattice *lat = ipcp_get_ith_lattice (info, i);
          parm_tree = ipa_get_ith_param (info, i);
 
-         if (lat->type == IPA_CONST_VALUE
-             /* Do not count obviously unused arguments.  */
-             && (!is_gimple_reg (parm_tree)
-                 || gimple_default_def (DECL_STRUCT_FUNCTION (node->decl),
-                                        parm_tree)))
+         /* We can proactively remove obviously unused arguments.  */
+         if (is_gimple_reg (parm_tree)
+             && !gimple_default_def (DECL_STRUCT_FUNCTION (node->decl),
+                                     parm_tree))
+           {
+             bitmap_set_bit (args_to_skip, i);
+             continue;
+           }
+
+         if (lat->type == IPA_CONST_VALUE)
            {
              replace_param =
                ipcp_create_replace_map (parm_tree, lat);
              VARRAY_PUSH_GENERIC_PTR (replace_trees, replace_param);
+             bitmap_set_bit (args_to_skip, i);
            }
        }
 
@@ -1061,7 +1110,9 @@ ipcp_insert_stage (void)
       /* Redirecting all the callers of the node to the
          new versioned node.  */
       node1 =
-       cgraph_function_versioning (node, redirect_callers, replace_trees);
+       cgraph_function_versioning (node, redirect_callers, replace_trees,
+                                   args_to_skip);
+      BITMAP_FREE (args_to_skip);
       VEC_free (cgraph_edge_p, heap, redirect_callers);
       VARRAY_CLEAR (replace_trees);
       if (node1 == NULL)
index 506a940..9a31b02 100644 (file)
@@ -1057,6 +1057,10 @@ static void
 ipa_edge_removal_hook (struct cgraph_edge *cs,
                       void *data __attribute__ ((unused)))
 {
+  /* During IPA-CP updating we can be called on not-yet analyze clones.  */
+  if (VEC_length (ipa_edge_args_t, ipa_edge_args_vector)
+      <= (unsigned)cs->uid)
+    return;
   ipa_free_edge_args_substructures (IPA_EDGE_REF (cs));
 }
 
index 4fb28fe..eb95cc6 100644 (file)
@@ -4089,19 +4089,37 @@ copy_decl_maybe_to_var (tree decl, copy_body_data *id)
 
 /* Return a copy of the function's argument tree.  */
 static tree
-copy_arguments_for_versioning (tree orig_parm, copy_body_data * id)
+copy_arguments_for_versioning (tree orig_parm, copy_body_data * id,
+                              bitmap args_to_skip, tree *vars)
 {
-  tree *arg_copy, *parg;
+  tree arg, *parg;
+  tree new_parm = NULL;
+  int i = 0;
 
-  arg_copy = &orig_parm;
-  for (parg = arg_copy; *parg; parg = &TREE_CHAIN (*parg))
-    {
-      tree new_tree = remap_decl (*parg, id);
-      lang_hooks.dup_lang_specific_decl (new_tree);
-      TREE_CHAIN (new_tree) = TREE_CHAIN (*parg);
-      *parg = new_tree;
-    }
-  return orig_parm;
+  parg = &new_parm;
+
+  for (arg = orig_parm; arg; arg = TREE_CHAIN (arg), i++)
+    if (!args_to_skip || !bitmap_bit_p (args_to_skip, i))
+      {
+        tree new_tree = remap_decl (arg, id);
+        lang_hooks.dup_lang_specific_decl (new_tree);
+        *parg = new_tree;
+       parg = &TREE_CHAIN (new_tree);
+      }
+    else
+      {
+       /* Make an equivalent VAR_DECL.  If the argument was used
+          as temporary variable later in function, the uses will be
+          replaced by local variable.  */
+       tree var = copy_decl_to_var (arg, id);
+       get_var_ann (var);
+       add_referenced_var (var);
+       insert_decl_map (id, arg, var);
+        /* Declare this new variable.  */
+        TREE_CHAIN (var) = *vars;
+        *vars = var;
+      }
+  return new_parm;
 }
 
 /* Return a copy of the function's static chain.  */
@@ -4146,7 +4164,7 @@ tree_versionable_function_p (tree fndecl)
    of edges of clones of the function will be updated.  */
 void
 tree_function_versioning (tree old_decl, tree new_decl, varray_type tree_map,
-                         bool update_clones)
+                         bool update_clones, bitmap args_to_skip)
 {
   struct cgraph_node *old_version_node;
   struct cgraph_node *new_version_node;
@@ -4214,7 +4232,8 @@ tree_function_versioning (tree old_decl, tree new_decl, varray_type tree_map,
   /* Copy the function's arguments.  */
   if (DECL_ARGUMENTS (old_decl) != NULL_TREE)
     DECL_ARGUMENTS (new_decl) =
-      copy_arguments_for_versioning (DECL_ARGUMENTS (old_decl), &id);
+      copy_arguments_for_versioning (DECL_ARGUMENTS (old_decl), &id,
+                                    args_to_skip, &vars);
   
   DECL_INITIAL (new_decl) = remap_blocks (DECL_INITIAL (id.src_fn), &id);
   
index e590e14..5fb4f63 100644 (file)
@@ -156,7 +156,7 @@ int estimate_num_insns (gimple, eni_weights *);
 int estimate_num_insns_fn (tree, eni_weights *);
 int count_insns_seq (gimple_seq, eni_weights *);
 bool tree_versionable_function_p (tree);
-void tree_function_versioning (tree, tree, varray_type, bool);
+void tree_function_versioning (tree, tree, varray_type, bool, bitmap);
 bool tree_can_inline_p (tree, tree);
 
 extern gimple_seq remap_gimple_seq (gimple_seq, copy_body_data *);
index f058fd7..5b92459 100644 (file)
@@ -5878,6 +5878,81 @@ build_function_type (tree value_type, tree arg_types)
   return t;
 }
 
+/* Build variant of function type ORIG_TYPE skipping ARGS_TO_SKIP.  */
+
+tree
+build_function_type_skip_args (tree orig_type, bitmap args_to_skip)
+{
+  tree new_type = NULL;
+  tree args, new_args = NULL, t;
+  tree new_reversed;
+  int i = 0;
+
+  for (args = TYPE_ARG_TYPES (orig_type); args && args != void_list_node;
+       args = TREE_CHAIN (args), i++)
+    if (!bitmap_bit_p (args_to_skip, i))
+      new_args = tree_cons (NULL_TREE, TREE_VALUE (args), new_args);
+
+  new_reversed = nreverse (new_args);
+  if (args)
+    {
+      if (new_reversed)
+        TREE_CHAIN (new_args) = void_list_node;
+      else
+       new_reversed = void_list_node;
+    }
+    gcc_assert (new_reversed);
+
+  /* Use copy_node to preserve as much as possible from original type
+     (debug info, attribute lists etc.)
+     Exception is METHOD_TYPEs must have THIS argument.
+     When we are asked to remove it, we need to build new FUNCTION_TYPE
+     instead.  */
+  if (TREE_CODE (orig_type) != METHOD_TYPE
+      || !bitmap_bit_p (args_to_skip, 0))
+    {
+      new_type = copy_node (orig_type);
+      TYPE_ARG_TYPES (new_type) = new_reversed;
+    }
+  else
+    new_type = build_function_type (TREE_TYPE (orig_type), new_reversed);
+
+  /* This is a new type, not a copy of an old type.  Need to reassociate
+     variants.  We can handle everything except the main variant lazily.  */
+  t = TYPE_MAIN_VARIANT (orig_type);
+  if (orig_type != t)
+    {
+      TYPE_MAIN_VARIANT (new_type) = t;
+      TYPE_NEXT_VARIANT (new_type) = TYPE_NEXT_VARIANT (t);
+      TYPE_NEXT_VARIANT (t) = new_type;
+    }
+  else
+    {
+      TYPE_MAIN_VARIANT (new_type) = new_type;
+      TYPE_NEXT_VARIANT (new_type) = NULL;
+    }
+  return new_type;
+}
+
+/* Build variant of function type ORIG_TYPE skipping ARGS_TO_SKIP.  
+  
+   Arguments from DECL_ARGUMENTS list can't be removed now, since they are
+   linked by TREE_CHAIN directly.  It is caller responsibility to eliminate
+   them when they are being duplicated (i.e. copy_arguments_for_versioning).  */
+
+tree
+build_function_decl_skip_args (tree orig_decl, bitmap args_to_skip)
+{
+  tree new_decl = copy_node (orig_decl);
+  tree new_type;
+
+  new_type = TREE_TYPE (orig_decl);
+  if (prototype_p (new_type))
+    new_type = build_function_type_skip_args (new_type, args_to_skip);
+  TREE_TYPE (orig_decl) = new_type;
+  return new_decl;
+}
+
 /* Build a function type.  The RETURN_TYPE is the type returned by the
    function. If VAARGS is set, no void_type_node is appended to the
    the list. ARGP muse be alway be terminated be a NULL_TREE.  */
@@ -5893,9 +5968,9 @@ build_function_type_list_1 (bool vaargs, tree return_type, va_list argp)
 
   if (vaargs)
     {
-         last = args;
-         if (args != NULL_TREE)
-           args = nreverse (args);
+      last = args;
+      if (args != NULL_TREE)
+       args = nreverse (args);
       gcc_assert (args != NULL_TREE && last != void_list_node);
     }
   else if (args == NULL_TREE)
index 487dd9e..775d281 100644 (file)
@@ -3994,6 +3994,8 @@ extern tree build_index_2_type (tree, tree);
 extern tree build_array_type (tree, tree);
 extern tree build_function_type (tree, tree);
 extern tree build_function_type_list (tree, ...);
+extern tree build_function_type_skip_args (tree, bitmap);
+extern tree build_function_decl_skip_args (tree, bitmap);
 extern tree build_varargs_function_type_list (tree, ...);
 extern tree build_method_type_directly (tree, tree, tree);
 extern tree build_method_type (tree, tree);