basic-block.h (REG_BR_PROB_BASE): Define.
authorJan Hubicka <jh@suse.cz>
Thu, 19 May 2005 10:38:42 +0000 (12:38 +0200)
committerJan Hubicka <hubicka@gcc.gnu.org>
Thu, 19 May 2005 10:38:42 +0000 (10:38 +0000)
* basic-block.h (REG_BR_PROB_BASE): Define.
* cgraph.c (cgraph_create_edge): Initialize loop_nest and count.
(dump_cgraph_node): Dump count.
(cgraph_clone_edge): Rescale counts.
(cgraph_clone_node): Likewise.
* cgraph.h: Include basic-block.h
(cgraph_node): Add count.
(cgraph_edge): Add count and loop_nest.
(cgraph_node, cgraph_edge, cgraph_clone_edge, cgraph_clone_node):
Update prototypes.
* cgraphunit.c: Kill now redundant inlining comment.
(cgraph_create_edges): Make static, maintain current basic block;
fix pasto.
(record_call_1): Fill in new fields.
* ipa-inline.c (cgraph_clone_inlined_nodes): Update call of
cgraph_clone_node.
(cgraph_decide_recursive_inlining): Likewise.
* rtl.h (REG_BR_PROB_BASE): Kill.
* tree-inline.c (copy_body_r): Update call of cgraph_clone_edge.
(expand_call_inline): Update call of cgraph_create_edge.
* tree-optimize.c (tree_rest_of_compilation): Likewise.

From-SVN: r99976

gcc/ChangeLog
gcc/basic-block.h
gcc/cgraph.c
gcc/cgraph.h
gcc/cgraphunit.c
gcc/ipa-inline.c
gcc/rtl.h
gcc/tree-inline.c
gcc/tree-optimize.c

index ac2ac51a264ac4c33b2631c06627e831f6a84470..51df4dc1950686ee0e18f88f70f0a35073f3086c 100644 (file)
@@ -1,3 +1,27 @@
+2005-05-19  Jan Hubicka  <jh@suse.cz>
+
+       * basic-block.h (REG_BR_PROB_BASE): Define.
+       * cgraph.c (cgraph_create_edge): Initialize loop_nest and count.
+       (dump_cgraph_node): Dump count.
+       (cgraph_clone_edge): Rescale counts.
+       (cgraph_clone_node): Likewise.
+       * cgraph.h: Include basic-block.h
+       (cgraph_node): Add count.
+       (cgraph_edge): Add count and loop_nest.
+       (cgraph_node, cgraph_edge, cgraph_clone_edge, cgraph_clone_node):
+       Update prototypes.
+       * cgraphunit.c: Kill now redundant inlining comment.
+       (cgraph_create_edges): Make static, maintain current basic block;
+       fix pasto.
+       (record_call_1): Fill in new fields.
+       * ipa-inline.c (cgraph_clone_inlined_nodes): Update call of
+       cgraph_clone_node.
+       (cgraph_decide_recursive_inlining): Likewise.
+       * rtl.h (REG_BR_PROB_BASE): Kill.
+       * tree-inline.c (copy_body_r): Update call of cgraph_clone_edge.
+       (expand_call_inline): Update call of cgraph_create_edge.
+       * tree-optimize.c (tree_rest_of_compilation): Likewise.
+
 2005-05-19  Nick Clifton  <nickc@redhat.com>
 
        * config/rs6000/eabispe.h (SUBSUBTARGET_OVERRIDE_OPTIONS): Use the
index 5565053337a876a6651d3ee69e66f88b01e13b9e..4deeb8997550f8029bc7507ca1e43a8ff0df4a38 100644 (file)
@@ -555,6 +555,9 @@ struct edge_list
   edge *index_to_edge;
 };
 
+/* The base value for branch probability notes and edge probabilities.  */
+#define REG_BR_PROB_BASE  10000
+
 /* This is the value which indicates no edge is present.  */
 #define EDGE_INDEX_NO_EDGE     -1
 
index adef0bd09ce2a25709363f46a27b7f7d90802196..c2509ffc033fbc34cd159069eadca13fe3f9382c 100644 (file)
@@ -275,7 +275,7 @@ cgraph_edge (struct cgraph_node *node, tree call_expr)
 
 struct cgraph_edge *
 cgraph_create_edge (struct cgraph_node *caller, struct cgraph_node *callee,
-                   tree call_expr)
+                   tree call_expr, gcov_type count, int nest)
 {
   struct cgraph_edge *edge = ggc_alloc (sizeof (struct cgraph_edge));
 #ifdef ENABLE_CHECKING
@@ -312,6 +312,8 @@ cgraph_create_edge (struct cgraph_node *caller, struct cgraph_node *callee,
     caller->callees->prev_callee = edge;
   caller->callees = edge;
   callee->callers = edge;
+  edge->count = count;
+  edge->loop_nest = nest;
   return edge;
 }
 
@@ -559,6 +561,9 @@ dump_cgraph_node (FILE *f, struct cgraph_node *node)
     fprintf (f, " (inline copy in %s/%i)",
             cgraph_node_name (node->global.inlined_to),
             node->global.inlined_to->uid);
+  if (node->count)
+    fprintf (f, " executed "HOST_WIDEST_INT_PRINT_DEC"x",
+            (HOST_WIDEST_INT)node->count);
   if (node->local.self_insns)
     fprintf (f, " %i insns", node->local.self_insns);
   if (node->global.insns && node->global.insns != node->local.self_insns)
@@ -587,6 +592,9 @@ dump_cgraph_node (FILE *f, struct cgraph_node *node)
     {
       fprintf (f, "%s/%i ", cgraph_node_name (edge->caller),
               edge->caller->uid);
+      if (edge->count)
+       fprintf (f, "("HOST_WIDEST_INT_PRINT_DEC"x) ",
+                (HOST_WIDEST_INT)edge->count);
       if (!edge->inline_failed)
        fprintf(f, "(inlined) ");
     }
@@ -829,20 +837,28 @@ cgraph_function_possibly_inlined_p (tree decl)
 
 /* Create clone of E in the node N represented by CALL_EXPR the callgraph.  */
 struct cgraph_edge *
-cgraph_clone_edge (struct cgraph_edge *e, struct cgraph_node *n, tree call_expr)
+cgraph_clone_edge (struct cgraph_edge *e, struct cgraph_node *n,
+                  tree call_expr, int count_scale, int loop_nest)
 {
-  struct cgraph_edge *new = cgraph_create_edge (n, e->callee, call_expr);
+  struct cgraph_edge *new;
+
+  new = cgraph_create_edge (n, e->callee, call_expr,
+                            e->count * count_scale / REG_BR_PROB_BASE,
+                           e->loop_nest + loop_nest);
 
   new->inline_failed = e->inline_failed;
+  e->count -= new->count;
   return new;
 }
 
-/* Create node representing clone of N.  */
+/* Create node representing clone of N executed COUNT times.  Decrease
+   the execution counts from original node too.  */
 struct cgraph_node *
-cgraph_clone_node (struct cgraph_node *n)
+cgraph_clone_node (struct cgraph_node *n, gcov_type count, int loop_nest)
 {
   struct cgraph_node *new = cgraph_create_node ();
   struct cgraph_edge *e;
+  int count_scale;
 
   new->decl = n->decl;
   new->origin = n->origin;
@@ -855,9 +871,15 @@ cgraph_clone_node (struct cgraph_node *n)
   new->local = n->local;
   new->global = n->global;
   new->rtl = n->rtl;
+  new->count = count;
+  if (n->count)
+    count_scale = new->count * REG_BR_PROB_BASE / n->count;
+  else
+    count_scale = 0;
+  n->count -= count;
 
   for (e = n->callees;e; e=e->next_callee)
-    cgraph_clone_edge (e, new, e->call_expr);
+    cgraph_clone_edge (e, new, e->call_expr, count_scale, loop_nest);
 
   new->next_clone = n->next_clone;
   new->prev_clone = n;
index 6f3864cfcad624f81ea5e06a59397da8fb7e0b05..294b690787b3601149df1887c9e8a9a0e939170d 100644 (file)
@@ -22,6 +22,7 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
 #ifndef GCC_CGRAPH_H
 #define GCC_CGRAPH_H
 #include "tree.h"
+#include "basic-block.h"
 
 /* Information about the function collected locally.
    Available after function is analyzed.  */
@@ -109,6 +110,8 @@ struct cgraph_node GTY((chain_next ("%h.next"), chain_prev ("%h.previous")))
   struct cgraph_global_info global;
   struct cgraph_rtl_info rtl;
   
+  /* Expected number of executions: calculated in profile.c.  */
+  gcov_type count;
   /* Unique id of the node.  */
   int uid;
   /* Set when function must be output - it is externally visible
@@ -141,6 +144,10 @@ struct cgraph_edge GTY((chain_next ("%h.next_caller"), chain_prev ("%h.prev_call
   /* When NULL, inline this call.  When non-NULL, points to the explanation
      why function was not inlined.  */
   const char *inline_failed;
+  /* Expected number of executions: calculated in profile.c.  */
+  gcov_type count;
+  /* Depth of loop nest, 1 means no loop nest.  */
+  int loop_nest;
 };
 
 /* The cgraph_varpool data structure.
@@ -190,25 +197,25 @@ void cgraph_remove_node (struct cgraph_node *);
 void cgraph_node_remove_callees (struct cgraph_node *node);
 struct cgraph_edge *cgraph_create_edge (struct cgraph_node *,
                                        struct cgraph_node *,
-                                       tree);
-struct cgraph_node *cgraph_node (tree decl);
+                                       tree, gcov_type, int);
+struct cgraph_node *cgraph_node (tree);
 struct cgraph_node *cgraph_node_for_asm (tree asmname);
-struct cgraph_edge *cgraph_edge (struct cgraph_node *, tree call_expr);
+struct cgraph_edge *cgraph_edge (struct cgraph_node *, tree);
 struct cgraph_local_info *cgraph_local_info (tree);
 struct cgraph_global_info *cgraph_global_info (tree);
 struct cgraph_rtl_info *cgraph_rtl_info (tree);
 const char * cgraph_node_name (struct cgraph_node *);
-struct cgraph_edge * cgraph_clone_edge (struct cgraph_edge *, struct cgraph_node *, tree);
-struct cgraph_node * cgraph_clone_node (struct cgraph_node *);
+struct cgraph_edge * cgraph_clone_edge (struct cgraph_edge *, struct cgraph_node *, tree, int, int);
+struct cgraph_node * cgraph_clone_node (struct cgraph_node *, gcov_type, int);
 
-struct cgraph_varpool_node *cgraph_varpool_node (tree decl);
+struct cgraph_varpool_node *cgraph_varpool_node (tree);
 struct cgraph_varpool_node *cgraph_varpool_node_for_asm (tree asmname);
 void cgraph_varpool_mark_needed_node (struct cgraph_varpool_node *);
 void cgraph_varpool_finalize_decl (tree);
 void cgraph_redirect_edge_callee (struct cgraph_edge *, struct cgraph_node *);
 
 bool cgraph_function_possibly_inlined_p (tree);
-void cgraph_unnest_node (struct cgraph_node *node);
+void cgraph_unnest_node (struct cgraph_node *);
 void cgraph_varpool_enqueue_needed_node (struct cgraph_varpool_node *);
 void cgraph_varpool_reset_queue (void);
 bool decide_is_variable_needed (struct cgraph_varpool_node *, tree);
@@ -219,7 +226,6 @@ bool cgraph_varpool_assemble_pending_decls (void);
 void cgraph_finalize_function (tree, bool);
 void cgraph_lower_function (struct cgraph_node *);
 void cgraph_finalize_compilation_unit (void);
-void cgraph_create_edges (struct cgraph_node *, tree);
 void cgraph_optimize (void);
 void cgraph_mark_needed_node (struct cgraph_node *);
 void cgraph_mark_reachable_node (struct cgraph_node *);
index 548a5fcb17737637926d06381fb8b1485d0c0e69..14eb46b22c0f6bb8b89cebb409fb8de213e3c379 100644 (file)
@@ -136,33 +136,7 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
        decision on whether function is needed is made more conservative so
        uninlininable static functions are needed too.  During the call-graph
        construction the edge destinations are not marked as reachable and it
-       is completely relied upn assemble_variable to mark them.
-       
-     Inlining decision heuristics
-        ??? Move this to separate file after tree-ssa merge.
-
-       We separate inlining decisions from the inliner itself and store it
-       inside callgraph as so called inline plan.  Refer to cgraph.c
-       documentation about particular representation of inline plans in the
-       callgraph
-
-       The implementation of particular heuristics is separated from
-       the rest of code to make it easier to replace it with more complicated
-       implementation in the future.  The rest of inlining code acts as a
-       library aimed to modify the callgraph and verify that the parameters
-       on code size growth fits.
-
-       To mark given call inline, use cgraph_mark_inline function, the
-       verification is performed by cgraph_default_inline_p and
-       cgraph_check_inline_limits.
-
-       The heuristics implements simple knapsack style algorithm ordering
-       all functions by their "profitability" (estimated by code size growth)
-       and inlining them in priority order.
-
-       cgraph_decide_inlining implements heuristics taking whole callgraph
-       into account, while cgraph_decide_inlining_incrementally considers
-       only one function at a time and is used in non-unit-at-a-time mode.  */
+       is completely relied upn assemble_variable to mark them.  */
 
 
 #include "config.h"
@@ -198,6 +172,7 @@ static void cgraph_expand_function (struct cgraph_node *);
 static tree record_call_1 (tree *, int *, void *);
 static void cgraph_mark_local_functions (void);
 static void cgraph_analyze_function (struct cgraph_node *node);
+static void cgraph_create_edges (struct cgraph_node *node, tree body);
 
 /* Records tree nodes seen in cgraph_create_edges.  Simply using
    walk_tree_without_duplicates doesn't guarantee each node is visited
@@ -460,6 +435,9 @@ cgraph_finalize_function (tree decl, bool nested)
     do_warn_unused_parameter (decl);
 }
 
+/* Used only while constructing the callgraph.  */
+static basic_block current_basic_block;
+
 void
 cgraph_lower_function (struct cgraph_node *node)
 {
@@ -469,7 +447,6 @@ cgraph_lower_function (struct cgraph_node *node)
   node->lowered = true;
 }
 
-
 /* Walk tree and record all calls.  Called via walk_tree.  */
 static tree
 record_call_1 (tree *tp, int *walk_subtrees, void *data)
@@ -508,7 +485,9 @@ record_call_1 (tree *tp, int *walk_subtrees, void *data)
        tree decl = get_callee_fndecl (*tp);
        if (decl && TREE_CODE (decl) == FUNCTION_DECL)
          {
-           cgraph_create_edge (data, cgraph_node (decl), *tp);
+           cgraph_create_edge (data, cgraph_node (decl), *tp,
+                               current_basic_block->count,
+                               current_basic_block->loop_depth);
 
            /* When we see a function call, we don't want to look at the
               function reference in the ADDR_EXPR that is hanging from
@@ -543,24 +522,25 @@ record_call_1 (tree *tp, int *walk_subtrees, void *data)
 
 /* Create cgraph edges for function calls inside BODY from NODE.  */
 
-void
+static void
 cgraph_create_edges (struct cgraph_node *node, tree body)
 {
   /* The nodes we're interested in are never shared, so walk
      the tree ignoring duplicates.  */
   visited_nodes = pointer_set_create ();
+  gcc_assert (current_basic_block == NULL);
   if (TREE_CODE (body) == FUNCTION_DECL)
     {
       struct function *this_cfun = DECL_STRUCT_FUNCTION (body);
-      basic_block this_block;
       block_stmt_iterator bsi;
       tree step;
 
       /* Reach the trees by walking over the CFG, and note the 
         enclosing basic-blocks in the call edges.  */
-      FOR_EACH_BB_FN (this_block, this_cfun)
-        for (bsi = bsi_start (this_block); !bsi_end_p (bsi); bsi_next (&bsi))
+      FOR_EACH_BB_FN (current_basic_block, this_cfun)
+        for (bsi = bsi_start (current_basic_block); !bsi_end_p (bsi); bsi_next (&bsi))
          walk_tree (bsi_stmt_ptr (bsi), record_call_1, node, visited_nodes);
+      current_basic_block = NULL;
 
       /* Walk over any private statics that may take addresses of functions.  */
       if (TREE_CODE (DECL_INITIAL (body)) == BLOCK)
@@ -586,7 +566,6 @@ cgraph_create_edges (struct cgraph_node *node, tree body)
   else
     walk_tree (&body, record_call_1, node, visited_nodes);
     
-  walk_tree (&body, record_call_1, node, visited_nodes);
   pointer_set_destroy (visited_nodes);
   visited_nodes = NULL;
 }
index f1236eac5f47a9199ecfa40ad8ff83d24fd2eef5..79150d2ba9a339923c83e50c65b26705bb808047 100644 (file)
@@ -123,7 +123,7 @@ cgraph_clone_inlined_nodes (struct cgraph_edge *e, bool duplicate)
     }
    else if (duplicate)
     {
-      n = cgraph_clone_node (e->callee);
+      n = cgraph_clone_node (e->callee, e->count, e->loop_nest);
       cgraph_redirect_edge_callee (e, n);
     }
 
@@ -369,7 +369,7 @@ cgraph_decide_recursive_inlining (struct cgraph_node *node)
             cgraph_node_name (node));
 
   /* We need original clone to copy around.  */
-  master_clone = cgraph_clone_node (node);
+  master_clone = cgraph_clone_node (node, 0, 1);
   master_clone->needed = true;
   for (e = master_clone->callees; e; e = e->next_callee)
     if (!e->inline_failed)
index c162393a74e9db12711423807a5409544720c52e..2eb5d9c84b814bf37e151c52b1a85b8feeb59bfe 100644 (file)
--- a/gcc/rtl.h
+++ b/gcc/rtl.h
@@ -706,9 +706,6 @@ enum reg_note
   REG_NOTE_MAX
 };
 
-/* The base value for branch probability notes.  */
-#define REG_BR_PROB_BASE  10000
-
 /* Define macros to extract and insert the reg-note kind in an EXPR_LIST.  */
 #define REG_NOTE_KIND(LINK) ((enum reg_note) GET_MODE (LINK))
 #define PUT_REG_NOTE_KIND(LINK, KIND) \
index d9654f4d52c4481f5c6b7e382758f37afc537b95..118f493e2992529f167139dd54675546725a7a10 100644 (file)
@@ -656,7 +656,8 @@ copy_body_r (tree *tp, int *walk_subtrees, void *data)
                 associate callgraph nodes.  */
              edge = cgraph_edge (id->current_node, old_node);
              if (edge)
-                cgraph_clone_edge (edge, id->node, *tp);
+                cgraph_clone_edge (edge, id->node, *tp,
+                                   REG_BR_PROB_BASE, 1);
            }
        }
       else if (TREE_CODE (*tp) == RESX_EXPR && id->eh_region_offset)
@@ -1922,7 +1923,8 @@ expand_call_inline (basic_block bb, tree stmt, tree *tp, void *data)
          constant propagating arguments.  In all other cases we hit a bug
          (incorrect node sharing is most common reason for missing edges.  */
       gcc_assert (dest->needed || !flag_unit_at_a_time);
-      cgraph_create_edge (id->node, dest, t)->inline_failed
+      cgraph_create_edge (id->node, dest, t,
+                         bb->count, bb->loop_depth)->inline_failed
        = N_("originally indirect function call not considered for inlining");
       goto egress;
     }
index 109c5bc1c0e6fce09913288b6e0d3e323eaf3011..7c9beb812dccd0a329bb39e11f869a32692ee35a 100644 (file)
@@ -741,7 +741,7 @@ tree_rest_of_compilation (tree fndecl)
        {
          struct cgraph_edge *e;
 
-         saved_node = cgraph_clone_node (node);
+         saved_node = cgraph_clone_node (node, node->count, 1);
          for (e = saved_node->callees; e; e = e->next_callee)
            if (!e->inline_failed)
              cgraph_clone_inlined_nodes (e, true);