]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
* cgraph.c (cgraph_resolve_speculation): Cut frequency to
authorhubicka <hubicka@138bc75d-0d04-0410-961f-82ee72b054a4>
Fri, 9 Aug 2013 22:53:00 +0000 (22:53 +0000)
committerhubicka <hubicka@138bc75d-0d04-0410-961f-82ee72b054a4>
Fri, 9 Aug 2013 22:53:00 +0000 (22:53 +0000)
CGRAPH_FREQ_MAX.
(dump_cgraph_node): Dump profile-id.
* cgraph.h (cgraph_indirect_call_info): Add common_target_id
and common_target_probability.
* lto-cgraph.c (lto_output_edge): Stream common targets.
(lto_output_node): Stream profile ids.
(input_node): Stream profile ids.
(input_edge): Stream common targets.
* lto-streamer-in.c (fixup_call_stmt_edges_1): Fix formatting.
* ipa.c: Include value-prof.h
(ipa_profile_generate_summary): Turn indirect call statement histograms
into common targets.
(ipa_profile): Turn common targets into speculative edges.

* gcc.dg/tree-prof/crossmodule-indircall-1.c: New testcase.
* gcc.dg/tree-prof/crossmodule-indircall-1a.c: New testcase.

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

gcc/ChangeLog
gcc/cgraph.c
gcc/cgraph.h
gcc/ipa.c
gcc/lto-cgraph.c
gcc/lto-streamer-in.c
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.dg/tree-prof/crossmodule-indircall-1.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/tree-prof/crossmodule-indircall-1a.c [new file with mode: 0644]

index bca5102de92bca1eb673dc0b45a46e5efb71b197..83b73b72c25040c5e6d63462e1606e13e52c0620 100644 (file)
@@ -1,3 +1,20 @@
+2013-08-09  Jan Hubicka  <jh@suse.cz>
+
+       * cgraph.c (cgraph_resolve_speculation): Cut frequency to
+       CGRAPH_FREQ_MAX.
+       (dump_cgraph_node): Dump profile-id.
+       * cgraph.h (cgraph_indirect_call_info): Add common_target_id
+       and common_target_probability.
+       * lto-cgraph.c (lto_output_edge): Stream common targets.
+       (lto_output_node): Stream profile ids.
+       (input_node): Stream profile ids.
+       (input_edge): Stream common targets.
+       * lto-streamer-in.c (fixup_call_stmt_edges_1): Fix formatting.
+       * ipa.c: Include value-prof.h
+       (ipa_profile_generate_summary): Turn indirect call statement histograms
+       into common targets.
+       (ipa_profile): Turn common targets into speculative edges.
+
 2013-08-09  Jan Hubicka  <jh@suse.cz>
 
        * cgraph.h (cgraph_node): Add profile_id.
index 43b499489f905b8c726ea823d9b4b509e5d1cf68..b3b9e25862876bdbe83ecdc396da6c5626e571ec 100644 (file)
@@ -1176,6 +1176,8 @@ cgraph_resolve_speculation (struct cgraph_edge *edge, tree callee_decl)
     }
   edge->count += e2->count;
   edge->frequency += e2->frequency;
+  if (edge->frequency > CGRAPH_FREQ_MAX)
+    edge->frequency = CGRAPH_FREQ_MAX;
   edge->speculative = false;
   e2->speculative = false;
   if (e2->indirect_unknown_callee || e2->inline_failed)
@@ -1801,6 +1803,9 @@ dump_cgraph_node (FILE *f, struct cgraph_node *node)
     fprintf (f, "  Availability: %s\n",
             cgraph_availability_names [cgraph_function_body_availability (node)]);
 
+  if (node->profile_id)
+    fprintf (f, "  Profile id: %i\n",
+            node->profile_id);
   fprintf (f, "  Function flags:");
   if (node->count)
     fprintf (f, " executed "HOST_WIDEST_INT_PRINT_DEC"x",
index f67287fc78dd4ee333160e1cdd0a3178c1f50d58..e430533338302f366f571228f4323c8644455c2c 100644 (file)
@@ -435,6 +435,10 @@ struct GTY(()) cgraph_indirect_call_info
   int param_index;
   /* ECF flags determined from the caller.  */
   int ecf_flags;
+  /* Profile_id of common target obtrained from profile.  */
+  int common_target_id;
+  /* Probability that call will land in function with COMMON_TARGET_ID.  */
+  int common_target_probability;
 
   /* Set when the call is a virtual call with the parameter being the
      associated object pointer rather than a simple direct call.  */
index 9905ba78d665a66fa688c7cc4cdc3d2659270fdb..c870a6f067849073b7819a232924c482e2b36e9f 100644 (file)
--- a/gcc/ipa.c
+++ b/gcc/ipa.c
@@ -38,6 +38,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "params.h"
 #include "lto-streamer.h"
 #include "data-streamer.h"
+#include "value-prof.h"
 
 /* Return true when NODE can not be local. Worker for cgraph_local_node_p.  */
 
@@ -1291,8 +1292,40 @@ ipa_profile_generate_summary (void)
        int size = 0;
         for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi))
          {
-           time += estimate_num_insns (gsi_stmt (gsi), &eni_time_weights);
-           size += estimate_num_insns (gsi_stmt (gsi), &eni_size_weights);
+           gimple stmt = gsi_stmt (gsi);
+           if (gimple_code (stmt) == GIMPLE_CALL
+               && !gimple_call_fndecl (stmt))
+             {
+               histogram_value h;
+               h = gimple_histogram_value_of_type
+                     (DECL_STRUCT_FUNCTION (node->symbol.decl),
+                      stmt, HIST_TYPE_INDIR_CALL);
+               /* No need to do sanity check: gimple_ic_transform already
+                  takes away bad histograms.  */
+               if (h)
+                 {
+                   /* counter 0 is target, counter 1 is number of execution we called target,
+                      counter 2 is total number of executions.  */
+                   if (h->hvalue.counters[2])
+                     {
+                       struct cgraph_edge * e = cgraph_edge (node, stmt);
+                       e->indirect_info->common_target_id
+                         = h->hvalue.counters [0];
+                       e->indirect_info->common_target_probability
+                         = GCOV_COMPUTE_SCALE (h->hvalue.counters [1], h->hvalue.counters [2]);
+                       if (e->indirect_info->common_target_probability > REG_BR_PROB_BASE)
+                         {
+                           if (dump_file)
+                             fprintf (dump_file, "Probability capped to 1\n");
+                           e->indirect_info->common_target_probability = REG_BR_PROB_BASE;
+                         }
+                     }
+                   gimple_remove_histogram_value (DECL_STRUCT_FUNCTION (node->symbol.decl),
+                                                   stmt, h);
+                 }
+             }
+           time += estimate_num_insns (stmt, &eni_time_weights);
+           size += estimate_num_insns (stmt, &eni_size_weights);
          }
        account_time_size (hashtable, histogram, bb->count, time, size);
       }
@@ -1375,6 +1408,53 @@ ipa_profile (void)
   int i;
   gcov_type overall_time = 0, cutoff = 0, cumulated = 0, overall_size = 0;
 
+  /* Produce speculative calls: we saved common traget from porfiling into
+     e->common_target_id.  Now, at link time, we can look up corresponding
+     function node and produce speculative call.  */
+  if (in_lto_p)
+    {
+      struct cgraph_edge *e;
+      struct cgraph_node *n,*n2;
+
+      init_node_map (false);
+      FOR_EACH_DEFINED_FUNCTION (n)
+       {
+         bool update = false;
+
+         for (e = n->indirect_calls; e; e = e->next_callee)
+           if (e->indirect_info->common_target_id)
+             {
+               n2 = find_func_by_profile_id (e->indirect_info->common_target_id);
+               if (n2)
+                 {
+                   if (dump_file)
+                     {
+                       fprintf (dump_file, "Indirect call -> direct call from"
+                                " other module %s/%i => %s/%i, prob %3.2f\n",
+                                xstrdup (cgraph_node_name (n)), n->symbol.order,
+                                xstrdup (cgraph_node_name (n2)), n2->symbol.order,
+                                e->indirect_info->common_target_probability
+                                / (float)REG_BR_PROB_BASE);
+                     }
+                   cgraph_turn_edge_to_speculative
+                     (e, n2,
+                      apply_scale (e->count,
+                                   e->indirect_info->common_target_probability),
+                      apply_scale (e->frequency,
+                                   e->indirect_info->common_target_probability));
+                   update = true;
+                 }
+               else
+                 if (dump_file)
+                   fprintf (dump_file, "Function with profile-id %i not found.\n",
+                            e->indirect_info->common_target_id);
+              }
+            if (update)
+              inline_update_overall_summary (n);
+          }
+       del_node_map ();
+    }
+
   if (dump_file)
     dump_histogram (dump_file, histogram);
   for (i = 0; i < (int)histogram.length (); i++)
index e0d09913ae75954e49225086419a1cbd754c87f1..fcba1b92acd0b9dbbd697164b7fafc09b042275f 100644 (file)
@@ -299,6 +299,14 @@ lto_output_edge (struct lto_simple_output_block *ob, struct cgraph_edge *edge,
                             | ECF_NOVOPS)));
     }
   streamer_write_bitpack (&bp);
+  if (edge->indirect_unknown_callee)
+    {
+      streamer_write_hwi_stream (ob->main_stream,
+                                edge->indirect_info->common_target_id);
+      if (edge->indirect_info->common_target_id)
+       streamer_write_hwi_stream
+          (ob->main_stream, edge->indirect_info->common_target_probability);
+    }
 }
 
 /* Return if LIST contain references from other partitions.  */
@@ -519,6 +527,7 @@ lto_output_node (struct lto_simple_output_block *ob, struct cgraph_node *node,
       streamer_write_uhwi_stream (ob->main_stream, node->thunk.fixed_offset);
       streamer_write_uhwi_stream (ob->main_stream, node->thunk.virtual_value);
     }
+  streamer_write_hwi_stream (ob->main_stream, node->profile_id);
 }
 
 /* Output the varpool NODE to OB. 
@@ -1057,6 +1066,7 @@ input_node (struct lto_file_decl_data *file_data,
     }
   if (node->symbol.alias && !node->symbol.analyzed && node->symbol.weakref)
     node->symbol.alias_target = get_alias_symbol (node->symbol.decl);
+  node->profile_id = streamer_read_hwi (ib);
   return node;
 }
 
@@ -1205,6 +1215,9 @@ input_edge (struct lto_input_block *ib, vec<symtab_node> nodes,
       if (bp_unpack_value (&bp, 1))
        ecf_flags |= ECF_RETURNS_TWICE;
       edge->indirect_info->ecf_flags = ecf_flags;
+      edge->indirect_info->common_target_id = streamer_read_hwi (ib);
+      if (edge->indirect_info->common_target_id)
+        edge->indirect_info->common_target_probability = streamer_read_hwi (ib);
     }
 }
 
index 0684cdaa7bad4bade829410ecf3373f09008cad2..643035932722bb8a8bce281e2d71a4b4ed34ce7c 100644 (file)
@@ -765,18 +765,18 @@ fixup_call_stmt_edges_1 (struct cgraph_node *node, gimple *stmts,
   for (cedge = node->callees; cedge; cedge = cedge->next_callee)
     {
       if (gimple_stmt_max_uid (fn) < cedge->lto_stmt_uid)
-      fatal_error ("Cgraph edge statement index out of range");
+        fatal_error ("Cgraph edge statement index out of range");
       cedge->call_stmt = stmts[cedge->lto_stmt_uid - 1];
       if (!cedge->call_stmt)
-      fatal_error ("Cgraph edge statement index not found");
+        fatal_error ("Cgraph edge statement index not found");
     }
   for (cedge = node->indirect_calls; cedge; cedge = cedge->next_callee)
     {
       if (gimple_stmt_max_uid (fn) < cedge->lto_stmt_uid)
-      fatal_error ("Cgraph edge statement index out of range");
+        fatal_error ("Cgraph edge statement index out of range");
       cedge->call_stmt = stmts[cedge->lto_stmt_uid - 1];
       if (!cedge->call_stmt)
-      fatal_error ("Cgraph edge statement index not found");
+        fatal_error ("Cgraph edge statement index not found");
     }
   for (i = 0;
        ipa_ref_list_reference_iterate (&node->symbol.ref_list, i, ref);
index e44040390893ca8b336fcc55071c11e607223dba..39fee31b1e684115fff99099490768bedac0248f 100644 (file)
@@ -1,3 +1,8 @@
+2013-08-09  Jan Hubicka  <jh@suse.cz>
+
+       * gcc.dg/tree-prof/crossmodule-indircall-1.c: New testcase.
+       * gcc.dg/tree-prof/crossmodule-indircall-1a.c: New testcase.
+
 2013-08-09  Yufeng Zhang  <yufeng.zhang@arm.com>
 
        * gcc.dg/lower-subreg-1.c: Skip aarch64*-*-*.
diff --git a/gcc/testsuite/gcc.dg/tree-prof/crossmodule-indircall-1.c b/gcc/testsuite/gcc.dg/tree-prof/crossmodule-indircall-1.c
new file mode 100644 (file)
index 0000000..3021425
--- /dev/null
@@ -0,0 +1,19 @@
+/* { dg-require-effective-target lto } */
+/* { dg-additional-sources "crossmodule-indircall-1a.c" } */
+/* { dg-options "-O3 -flto -DDOJOB=1" } */
+
+int a;
+extern void (*p[2])(int n);
+void abort (void);
+main()
+{ int i;
+
+  /* This call shall be converted.  */
+  for (i = 0;i<1000;i++)
+    p[0](1);
+  /* This call shall not be converted.  */
+  for (i = 0;i<1000;i++)
+    p[i%2](2);
+  if (a != 1000)
+    abort ();
+}
diff --git a/gcc/testsuite/gcc.dg/tree-prof/crossmodule-indircall-1a.c b/gcc/testsuite/gcc.dg/tree-prof/crossmodule-indircall-1a.c
new file mode 100644 (file)
index 0000000..a94195c
--- /dev/null
@@ -0,0 +1,40 @@
+/* It seems there is no way to avoid the other source of mulitple
+   source testcase from being compiled independently.  Just avoid
+   error.  */
+#ifdef DOJOB
+extern int a;
+void abort (void);
+
+#ifdef _PROFILE_USE
+__attribute__ ((externally_visible))
+int constval=1,constval2=2;
+#else
+__attribute__ ((externally_visible))
+int constval=3,constval2=2;
+#endif
+
+
+void
+add(int i)
+{
+  /* Verify that inlining happens for first case.  */
+  if (i==constval && !__builtin_constant_p (i))
+    abort ();
+  /* Second case has no dominating target; it should not inline.  */
+  if (i==constval2 && __builtin_constant_p (i))
+    abort ();
+  a += i;
+}
+void
+sub(int i)
+{
+  a -= i;
+}
+__attribute__ ((externally_visible))
+void (*p[2])(int)={add, sub};
+#else
+main()
+{
+  return 0;
+}
+#endif