return cgraph_fnver_htab->find (&key);
}
-/* Scale profile by NUM/DEN. Walk into inlined clones. */
+/* If profile is IPA, turn it into local one. */
+void
+cgraph_node::make_profile_local ()
+{
+ if (!count.ipa ().initialized_p ())
+ return;
+ if (!(count == profile_count::zero ()))
+ count = count.guessed_local ();
+ for (cgraph_edge *e = callees; e; e = e->next_callee)
+ {
+ if (!e->inline_failed)
+ e->callee->make_profile_local ();
+ if (!(e->count == profile_count::zero ()))
+ e->count = e->count.guessed_local ();
+ }
+ for (cgraph_edge *e = indirect_calls; e; e = e->next_callee)
+ if (!(e->count == profile_count::zero ()))
+ e->count = e->count.guessed_local ();
+}
+/* Turn profile to global0. Walk into inlined functions.
+ QUALITY must be GUESSED_GLOBAL0 or GUESSED_GLOBAL0_ADJUSTED */
void
-cgraph_node::apply_scale (profile_count num, profile_count den)
+cgraph_node::make_profile_global0 (profile_quality quality)
{
- struct cgraph_edge *e;
+ if (count == profile_count::zero ())
+ ;
+ else if (quality == GUESSED_GLOBAL0)
+ {
+ if (count.quality () == GUESSED_GLOBAL0)
+ return;
+ count = count.global0 ();
+ }
+ else if (quality == GUESSED_GLOBAL0_ADJUSTED)
+ {
+ if (count.quality () == GUESSED_GLOBAL0
+ || count.quality () == GUESSED_GLOBAL0_ADJUSTED)
+ return;
+ count = count.global0adjusted ();
+ }
+ else
+ gcc_unreachable ();
+ for (cgraph_edge *e = callees; e; e = e->next_callee)
+ {
+ if (!e->inline_failed)
+ e->callee->make_profile_global0 (quality);
+ if (e->count == profile_count::zero ())
+ ;
+ else if (quality == GUESSED_GLOBAL0)
+ e->count = e->count.global0 ();
+ else if (quality == GUESSED_GLOBAL0_ADJUSTED)
+ e->count = e->count.global0adjusted ();
+ else
+ gcc_unreachable ();
+ }
+ for (cgraph_edge *e = indirect_calls; e; e = e->next_callee)
+ if (e->count == profile_count::zero ())
+ ;
+ else if (quality == GUESSED_GLOBAL0)
+ e->count = e->count.global0 ();
+ else if (quality == GUESSED_GLOBAL0_ADJUSTED)
+ e->count = e->count.global0adjusted ();
+ else
+ gcc_unreachable ();
+}
- profile_count::adjust_for_ipa_scaling (&num, &den);
+/* Scale profile by NUM/DEN. Walk into inlined functions. */
- for (e = callees; e; e = e->next_callee)
+void
+cgraph_node::apply_scale (profile_count num, profile_count den)
+{
+ if (num == den)
+ return;
+
+ for (cgraph_edge *e = callees; e; e = e->next_callee)
{
if (!e->inline_failed)
e->callee->apply_scale (num, den);
e->count = e->count.apply_scale (num, den);
}
- for (e = indirect_calls; e; e = e->next_callee)
+ for (cgraph_edge *e = indirect_calls; e; e = e->next_callee)
e->count = e->count.apply_scale (num, den);
count = count.apply_scale (num, den);
}
+/* Scale profile to given IPA_COUNT.
+ IPA_COUNT should pass ipa_p () with a single exception.
+ It can be also GUESSED_LOCAL in case we want to
+ drop any IPA info about the profile. */
+
+void
+cgraph_node::scale_profile_to (profile_count ipa_count)
+{
+ /* If we do not know the adjustment, it is better to keep profile
+ as it is. */
+ if (!ipa_count.initialized_p ()
+ || ipa_count == count)
+ return;
+ /* ipa-cp converts value to guessed-local in case it believes
+ that we lost track of IPA profile. */
+ if (ipa_count.quality () == GUESSED_LOCAL)
+ {
+ make_profile_local ();
+ return;
+ }
+ if (ipa_count == profile_count::zero ())
+ {
+ make_profile_global0 (GUESSED_GLOBAL0);
+ return;
+ }
+ if (ipa_count == profile_count::adjusted_zero ())
+ {
+ make_profile_global0 (GUESSED_GLOBAL0_ADJUSTED);
+ return;
+ }
+ gcc_assert (ipa_count.ipa () == ipa_count
+ && !inlined_to);
+ profile_count num = count.combine_with_ipa_count (ipa_count);
+ profile_count den = count;
+ profile_count::adjust_for_ipa_scaling (&num, &den);
+}
+
/* Insert a new cgraph_function_version_info node into cgraph_fnver_htab
corresponding to cgraph_node NODE. */
cgraph_function_version_info *
it is not used in any other non-standard way. */
bool only_called_directly_p (void);
- /* Scale profile by NUM/DEN. Walk into inlined clones. */
+ /* Turn profile to global0. Walk into inlined functions. */
+ void make_profile_local ();
+
+ /* Turn profile to global0. Walk into inlined functions. */
+ void make_profile_global0 (profile_quality quality);
+
+ /* Scale profile by NUM/DEN. Walk into inlined funtion. */
void apply_scale (profile_count num, profile_count den);
+ /* Scale profile to given IPA_COUNT.
+ IPA_COUNT should pass ipa_p () with a single exception.
+ It can be also GUESSED_LOCAL in case we want to
+ drop any IPA info about the profile. */
+ void scale_profile_to (profile_count ipa_count);
+
/* Return true when function is only called directly or it has alias.
i.e. it is not externally visible, address was not taken and
it is not used in any other non-standard way. */
if (remainder.ipa_p () && !remainder.ipa ().nonzero_p ()
&& orig_node->count.ipa_p () && orig_node->count.ipa ().nonzero_p ()
&& opt_for_fn (orig_node->decl, flag_profile_partial_training))
- remainder = remainder.guessed_local ();
+ remainder = orig_node->count.guessed_local ();
return remainder;
}
profile_count new_count
= (redist_sum / self_gen_clones.length () + other_edges_count[i]);
new_count = lenient_count_portion_handling (new_count, orig_node);
- n->apply_scale (new_count, n->count);
+ n->scale_profile_to (new_count);
for (cgraph_edge *cs = n->callees; cs; cs = cs->next_callee)
processed_edges.add (cs);
bool orig_edges_processed = false;
if (new_sum > orig_node_count)
{
- /* TODO: Profile has alreay gone astray, keep what we have but lower it
- to global0 category. */
- remainder = orig_node->count.global0 ();
-
- for (cgraph_edge *cs = orig_node->callees; cs; cs = cs->next_callee)
- cs->count = cs->count.global0 ();
- for (cgraph_edge *cs = orig_node->indirect_calls;
- cs;
- cs = cs->next_callee)
- cs->count = cs->count.global0 ();
+ /* Profile has alreay gone astray, keep what we have but lower it
+ to global0adjusted or to local if we have partial training. */
+ if (opt_for_fn (orig_node->decl, flag_profile_partial_training))
+ orig_node->make_profile_local ();
+ else
+ orig_node->make_profile_global0 (GUESSED_GLOBAL0_ADJUSTED);
orig_edges_processed = true;
}
else if (stats.rec_count_sum.nonzero_p ())
are still unmodified copies of ORIG_NODE's. Just clear
the latter and bail out. */
if (opt_for_fn (orig_node->decl, flag_profile_partial_training))
- orig_node->count = orig_node->count.guessed_local ();
+ orig_node->make_profile_local ();
else
- orig_node->count = orig_node->count.global0adjusted ();
- for (cgraph_edge *cs = orig_node->callees;
- cs;
- cs = cs->next_callee)
- if (opt_for_fn (orig_node->decl, flag_profile_partial_training))
- cs->count = orig_node->count.guessed_local ();
- else
- cs->count = orig_node->count.global0adjusted ();
- for (cgraph_edge *cs = orig_node->indirect_calls;
- cs;
- cs = cs->next_callee)
- if (opt_for_fn (orig_node->decl, flag_profile_partial_training))
- cs->count = orig_node->count.guessed_local ();
- else
- cs->count = orig_node->count.global0adjusted ();
+ orig_node->make_profile_global0 (GUESSED_GLOBAL0_ADJUSTED);
return;
}
}
remainder = lenient_count_portion_handling (orig_node_count - new_sum,
orig_node);
- new_sum = orig_node_count.combine_with_ipa_count (new_sum);
- orig_node->count = remainder;
-
- new_node->apply_scale (new_sum, new_node->count);
+ new_node->scale_profile_to (new_sum);
if (!orig_edges_processed)
- orig_node->apply_scale (remainder, orig_node->count);
+ orig_node->scale_profile_to (remainder);
if (dump_file)
{
|| !redirected_sum.nonzero_p ())
return;
- orig_node->apply_scale
+ orig_node->scale_profile_to
(lenient_count_portion_handling (orig_node->count.ipa () - redirected_sum,
- orig_node),
- orig_node->count);
+ orig_node));
- new_node->apply_scale (new_node->count.ipa () + redirected_sum,
- new_node->count);
+ new_node->scale_profile_to (new_node->count.ipa () + redirected_sum);
if (dump_file)
{
}
duplicate = false;
e->callee->externally_visible = false;
- e->callee->apply_scale (e->count, e->callee->count);
+ profile_count num = e->count;
+ profile_count den = e->callee->count;
+ profile_count::adjust_for_ipa_scaling (&num, &den);
+ e->callee->apply_scale (num, den);
dump_callgraph_transformation (e->callee, inlining_into,
"inlining to");