+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.
}
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)
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",
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. */
#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. */
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);
}
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++)
| 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. */
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.
}
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;
}
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);
}
}
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);
+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*-*-*.
--- /dev/null
+/* { 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 ();
+}
--- /dev/null
+/* 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