Commit b69d9ac6 by Jan Hubicka Committed by Jan Hubicka

predict.c (maybe_hot_bb_p): Do not check profile status.


	* predict.c (maybe_hot_bb_p): Do not check profile status.
	(maybe_hot_edge_p): Likewise.
	(probably_never_executed): Check for zero counts even if profile
	is not read.
	(unlikely_executed_edge_p): New function.
	(unlikely_executed_stmt_p): New function.
	(unlikely_executed_bb_p): New function.
	(set_even_probabilities): Use unlikely predicates.
	(combine_predictions_for_bb): Likewise.
	(predict_paths_for_bb): Likewise.
	(predict_paths_leading_to_edge): Likewise.
	(determine_unlikely_bbs): New function.
	(estimate_bb_frequencies): Use it.
	(compute_function_frequency): Use zero counts even if profile is
	not read.
	* profile-count.h: Fix typo.

	* g++.dg/tree-ssa/counts-1.C: New testcase.
	* gcc.dg/tree-ssa/counts-1.c: New testcase.

From-SVN: r249013
parent c46f9051
2017-06-08 Jan Hubicka <hubicka@ucw.cz>
* predict.c (maybe_hot_bb_p): Do not check profile status.
(maybe_hot_edge_p): Likewise.
(probably_never_executed): Check for zero counts even if profile
is not read.
(unlikely_executed_edge_p): New function.
(unlikely_executed_stmt_p): New function.
(unlikely_executed_bb_p): New function.
(set_even_probabilities): Use unlikely predicates.
(combine_predictions_for_bb): Likewise.
(predict_paths_for_bb): Likewise.
(predict_paths_leading_to_edge): Likewise.
(determine_unlikely_bbs): New function.
(estimate_bb_frequencies): Use it.
(compute_function_frequency): Use zero counts even if profile is
not read.
* profile-count.h: Fix typo.
2017-08-08 Julia Koval <julia.koval@intel.com> 2017-08-08 Julia Koval <julia.koval@intel.com>
* config/i386/avx512bwintrin.h (_mm512_mask_cvtepi16_storeu_epi8, * config/i386/avx512bwintrin.h (_mm512_mask_cvtepi16_storeu_epi8,
......
...@@ -189,8 +189,8 @@ bool ...@@ -189,8 +189,8 @@ bool
maybe_hot_bb_p (struct function *fun, const_basic_block bb) maybe_hot_bb_p (struct function *fun, const_basic_block bb)
{ {
gcc_checking_assert (fun); gcc_checking_assert (fun);
if (profile_status_for_fn (fun) == PROFILE_READ) if (!maybe_hot_count_p (fun, bb->count))
return maybe_hot_count_p (fun, bb->count); return false;
return maybe_hot_frequency_p (fun, bb->frequency); return maybe_hot_frequency_p (fun, bb->frequency);
} }
...@@ -200,8 +200,8 @@ maybe_hot_bb_p (struct function *fun, const_basic_block bb) ...@@ -200,8 +200,8 @@ maybe_hot_bb_p (struct function *fun, const_basic_block bb)
bool bool
maybe_hot_edge_p (edge e) maybe_hot_edge_p (edge e)
{ {
if (profile_status_for_fn (cfun) == PROFILE_READ) if (!maybe_hot_count_p (cfun, e->count))
return maybe_hot_count_p (cfun, e->count); return false;
return maybe_hot_frequency_p (cfun, EDGE_FREQUENCY (e)); return maybe_hot_frequency_p (cfun, EDGE_FREQUENCY (e));
} }
...@@ -213,11 +213,10 @@ probably_never_executed (struct function *fun, ...@@ -213,11 +213,10 @@ probably_never_executed (struct function *fun,
profile_count count, int) profile_count count, int)
{ {
gcc_checking_assert (fun); gcc_checking_assert (fun);
if (count == profile_count::zero ())
return true;
if (count.initialized_p () && profile_status_for_fn (fun) == PROFILE_READ) if (count.initialized_p () && profile_status_for_fn (fun) == PROFILE_READ)
{ {
if (count == profile_count::zero ())
return true;
int unlikely_count_fraction = PARAM_VALUE (UNLIKELY_BB_COUNT_FRACTION); int unlikely_count_fraction = PARAM_VALUE (UNLIKELY_BB_COUNT_FRACTION);
if (count.apply_scale (unlikely_count_fraction, 1) >= profile_info->runs) if (count.apply_scale (unlikely_count_fraction, 1) >= profile_info->runs)
return false; return false;
...@@ -763,6 +762,69 @@ dump_prediction (FILE *file, enum br_predictor predictor, int probability, ...@@ -763,6 +762,69 @@ dump_prediction (FILE *file, enum br_predictor predictor, int probability,
fprintf (file, "\n"); fprintf (file, "\n");
} }
/* Return true if E is unlikely executed. */
static bool
unlikely_executed_edge_p (edge e)
{
return e->count == profile_count::zero ()
|| (e->flags & (EDGE_EH | EDGE_FAKE));
}
/* Return true if STMT is known to be unlikely executed. */
static bool
unlikely_executed_stmt_p (gimple *stmt)
{
if (!is_gimple_call (stmt))
return false;
/* NORETURN attribute enough is not strong enough: exit() may be quite
likely executed once during program run. */
if (gimple_call_fntype (stmt)
&& lookup_attribute ("cold",
TYPE_ATTRIBUTES (gimple_call_fntype (stmt)))
&& !lookup_attribute ("cold", DECL_ATTRIBUTES (current_function_decl)))
return true;
tree decl = gimple_call_fndecl (stmt);
if (!decl)
return false;
if (lookup_attribute ("cold", DECL_ATTRIBUTES (decl))
&& !lookup_attribute ("cold", DECL_ATTRIBUTES (current_function_decl)))
return true;
cgraph_node *n = cgraph_node::get (decl);
if (!n)
return false;
enum availability avail;
n = n->ultimate_alias_target (&avail);
if (avail < AVAIL_AVAILABLE)
return NULL;
if (!n->analyzed
|| n->decl == current_function_decl)
return false;
return n->frequency == NODE_FREQUENCY_UNLIKELY_EXECUTED;
}
/* Return true if BB is unlikely executed. */
static bool
unlikely_executed_bb_p (basic_block bb)
{
if (bb->count == profile_count::zero ())
return true;
if (bb == ENTRY_BLOCK_PTR_FOR_FN (cfun) || bb == EXIT_BLOCK_PTR_FOR_FN (cfun))
return false;
for (gimple_stmt_iterator gsi = gsi_start_bb (bb);
!gsi_end_p (gsi); gsi_next (&gsi))
{
if (unlikely_executed_stmt_p (gsi_stmt (gsi)))
return true;
if (stmt_can_terminate_bb_p (gsi_stmt (gsi)))
return false;
}
return false;
}
/* We can not predict the probabilities of outgoing edges of bb. Set them /* We can not predict the probabilities of outgoing edges of bb. Set them
evenly and hope for the best. If UNLIKELY_EDGES is not null, distribute evenly and hope for the best. If UNLIKELY_EDGES is not null, distribute
even probability for all edges not mentioned in the set. These edges even probability for all edges not mentioned in the set. These edges
...@@ -777,7 +839,7 @@ set_even_probabilities (basic_block bb, ...@@ -777,7 +839,7 @@ set_even_probabilities (basic_block bb,
edge_iterator ei; edge_iterator ei;
FOR_EACH_EDGE (e, ei, bb->succs) FOR_EACH_EDGE (e, ei, bb->succs)
if (!(e->flags & (EDGE_EH | EDGE_FAKE))) if (!unlikely_executed_edge_p (e))
nedges ++; nedges ++;
/* Make the distribution even if all edges are unlikely. */ /* Make the distribution even if all edges are unlikely. */
...@@ -791,7 +853,7 @@ set_even_probabilities (basic_block bb, ...@@ -791,7 +853,7 @@ set_even_probabilities (basic_block bb,
unsigned c = nedges - unlikely_count; unsigned c = nedges - unlikely_count;
FOR_EACH_EDGE (e, ei, bb->succs) FOR_EACH_EDGE (e, ei, bb->succs)
if (!(e->flags & (EDGE_EH | EDGE_FAKE))) if (!unlikely_executed_edge_p (e))
{ {
if (unlikely_edges != NULL && unlikely_edges->contains (e)) if (unlikely_edges != NULL && unlikely_edges->contains (e))
e->probability = PROB_VERY_UNLIKELY; e->probability = PROB_VERY_UNLIKELY;
...@@ -1056,7 +1118,7 @@ combine_predictions_for_bb (basic_block bb, bool dry_run) ...@@ -1056,7 +1118,7 @@ combine_predictions_for_bb (basic_block bb, bool dry_run)
edge_iterator ei; edge_iterator ei;
FOR_EACH_EDGE (e, ei, bb->succs) FOR_EACH_EDGE (e, ei, bb->succs)
if (!(e->flags & (EDGE_EH | EDGE_FAKE))) if (!unlikely_executed_edge_p (e))
{ {
nedges ++; nedges ++;
if (first && !second) if (first && !second)
...@@ -1107,7 +1169,7 @@ combine_predictions_for_bb (basic_block bb, bool dry_run) ...@@ -1107,7 +1169,7 @@ combine_predictions_for_bb (basic_block bb, bool dry_run)
"%i edges in bb %i predicted with some unlikely edges\n", "%i edges in bb %i predicted with some unlikely edges\n",
nedges, bb->index); nedges, bb->index);
FOR_EACH_EDGE (e, ei, bb->succs) FOR_EACH_EDGE (e, ei, bb->succs)
if (!(e->flags & (EDGE_EH | EDGE_FAKE))) if (!unlikely_executed_edge_p (e))
dump_prediction (dump_file, PRED_COMBINED, e->probability, dump_prediction (dump_file, PRED_COMBINED, e->probability,
bb, REASON_NONE, e); bb, REASON_NONE, e);
} }
...@@ -1758,7 +1820,7 @@ predict_loops (void) ...@@ -1758,7 +1820,7 @@ predict_loops (void)
exits = get_loop_exit_edges (loop); exits = get_loop_exit_edges (loop);
FOR_EACH_VEC_ELT (exits, j, ex) FOR_EACH_VEC_ELT (exits, j, ex)
if (!(ex->flags & (EDGE_EH | EDGE_ABNORMAL_CALL | EDGE_FAKE))) if (!unlikely_executed_edge_p (ex) && !(ex->flags & EDGE_ABNORMAL_CALL))
n_exits ++; n_exits ++;
if (!n_exits) if (!n_exits)
{ {
...@@ -1792,7 +1854,8 @@ predict_loops (void) ...@@ -1792,7 +1854,8 @@ predict_loops (void)
enum br_predictor predictor; enum br_predictor predictor;
widest_int nit; widest_int nit;
if (ex->flags & (EDGE_EH | EDGE_ABNORMAL_CALL | EDGE_FAKE)) if (unlikely_executed_edge_p (ex)
|| (ex->flags & EDGE_ABNORMAL_CALL))
continue; continue;
/* Loop heuristics do not expect exit conditional to be inside /* Loop heuristics do not expect exit conditional to be inside
inner loop. We predict from innermost to outermost loop. */ inner loop. We predict from innermost to outermost loop. */
...@@ -2609,7 +2672,7 @@ tree_bb_level_predictions (void) ...@@ -2609,7 +2672,7 @@ tree_bb_level_predictions (void)
edge_iterator ei; edge_iterator ei;
FOR_EACH_EDGE (e, ei, EXIT_BLOCK_PTR_FOR_FN (cfun)->preds) FOR_EACH_EDGE (e, ei, EXIT_BLOCK_PTR_FOR_FN (cfun)->preds)
if (!(e->flags & (EDGE_ABNORMAL | EDGE_FAKE | EDGE_EH))) if (!unlikely_executed_edge_p (e) && !(e->flags & EDGE_ABNORMAL_CALL))
{ {
has_return_edges = true; has_return_edges = true;
break; break;
...@@ -2863,7 +2926,7 @@ predict_paths_for_bb (basic_block cur, basic_block bb, ...@@ -2863,7 +2926,7 @@ predict_paths_for_bb (basic_block cur, basic_block bb,
bool found = false; bool found = false;
/* Ignore fake edges and eh, we predict them as not taken anyway. */ /* Ignore fake edges and eh, we predict them as not taken anyway. */
if (e->flags & (EDGE_EH | EDGE_FAKE)) if (unlikely_executed_edge_p (e))
continue; continue;
gcc_assert (bb == cur || dominated_by_p (CDI_POST_DOMINATORS, cur, bb)); gcc_assert (bb == cur || dominated_by_p (CDI_POST_DOMINATORS, cur, bb));
...@@ -2871,7 +2934,7 @@ predict_paths_for_bb (basic_block cur, basic_block bb, ...@@ -2871,7 +2934,7 @@ predict_paths_for_bb (basic_block cur, basic_block bb,
and does not lead to BB and does not exit the loop. */ and does not lead to BB and does not exit the loop. */
FOR_EACH_EDGE (e2, ei2, e->src->succs) FOR_EACH_EDGE (e2, ei2, e->src->succs)
if (e2 != e if (e2 != e
&& !(e2->flags & (EDGE_EH | EDGE_FAKE)) && !unlikely_executed_edge_p (e2)
&& !dominated_by_p (CDI_POST_DOMINATORS, e2->dest, bb) && !dominated_by_p (CDI_POST_DOMINATORS, e2->dest, bb)
&& (!in_loop || !loop_exit_edge_p (in_loop, e2))) && (!in_loop || !loop_exit_edge_p (in_loop, e2)))
{ {
...@@ -2923,7 +2986,7 @@ predict_paths_leading_to_edge (edge e, enum br_predictor pred, ...@@ -2923,7 +2986,7 @@ predict_paths_leading_to_edge (edge e, enum br_predictor pred,
basic_block bb = e->src; basic_block bb = e->src;
FOR_EACH_EDGE (e2, ei, bb->succs) FOR_EACH_EDGE (e2, ei, bb->succs)
if (e2->dest != e->src && e2->dest != e->dest if (e2->dest != e->src && e2->dest != e->dest
&& !(e->flags & (EDGE_EH | EDGE_FAKE)) && !unlikely_executed_edge_p (e)
&& !dominated_by_p (CDI_POST_DOMINATORS, e->src, e2->dest)) && !dominated_by_p (CDI_POST_DOMINATORS, e->src, e2->dest))
{ {
has_nonloop_edge = true; has_nonloop_edge = true;
...@@ -3341,6 +3404,142 @@ expensive_function_p (int threshold) ...@@ -3341,6 +3404,142 @@ expensive_function_p (int threshold)
return false; return false;
} }
/* Determine basic blocks/edges that are known to be unlikely executed and set
their counters to zero.
This is done with first identifying obviously unlikely BBs/edges and then
propagating in both directions. */
static void
determine_unlikely_bbs ()
{
basic_block bb;
auto_vec<basic_block, 64> worklist;
edge_iterator ei;
edge e;
FOR_EACH_BB_FN (bb, cfun)
{
if (!(bb->count == profile_count::zero ())
&& unlikely_executed_bb_p (bb))
{
if (dump_file && (dump_flags & TDF_DETAILS))
fprintf (dump_file, "Basic block %i is locally unlikely\n",
bb->index);
bb->count = profile_count::zero ();
}
if (bb->count == profile_count::zero ())
{
bb->frequency = 0;
FOR_EACH_EDGE (e, ei, bb->preds)
e->count = profile_count::zero ();
}
FOR_EACH_EDGE (e, ei, bb->succs)
if (!(e->count == profile_count::zero ())
&& unlikely_executed_edge_p (e))
{
if (dump_file && (dump_flags & TDF_DETAILS))
fprintf (dump_file, "Edge %i->%i is locally unlikely\n",
bb->index, e->dest->index);
e->count = profile_count::zero ();
}
gcc_checking_assert (!bb->aux);
}
if (!(ENTRY_BLOCK_PTR_FOR_FN (cfun)->count == profile_count::zero ()))
{
ENTRY_BLOCK_PTR_FOR_FN (cfun)->aux = (void *)(size_t) 1;
worklist.safe_push (ENTRY_BLOCK_PTR_FOR_FN (cfun));
while (worklist.length () > 0)
{
bb = worklist.pop ();
FOR_EACH_EDGE (e, ei, bb->succs)
if (!(e->count == profile_count::zero ())
&& !(e->dest->count == profile_count::zero ())
&& !e->dest->aux)
{
e->dest->aux = (void *)(size_t) 1;
worklist.safe_push (e->dest);
}
}
}
FOR_ALL_BB_FN (bb, cfun)
{
if (!bb->aux)
{
if (!(bb->count == profile_count::zero ())
&& (dump_file && (dump_flags & TDF_DETAILS)))
fprintf (dump_file,
"Basic block %i is marked unlikely by forward prop\n",
bb->index);
bb->count = profile_count::zero ();
bb->frequency = 0;
FOR_EACH_EDGE (e, ei, bb->succs)
e->count = profile_count::zero ();
}
else
bb->aux = NULL;
}
auto_vec<int, 64> nsuccs;
nsuccs.safe_grow_cleared (last_basic_block_for_fn (cfun));
FOR_ALL_BB_FN (bb, cfun)
if (!(bb->count == profile_count::zero ())
&& bb != EXIT_BLOCK_PTR_FOR_FN (cfun))
{
nsuccs[bb->index] = 0;
FOR_EACH_EDGE (e, ei, bb->succs)
if (!(e->count == profile_count::zero ()))
nsuccs[bb->index]++;
if (!nsuccs[bb->index])
worklist.safe_push (bb);
}
while (worklist.length () > 0)
{
bb = worklist.pop ();
if (bb != ENTRY_BLOCK_PTR_FOR_FN (cfun))
{
bool found = false;
for (gimple_stmt_iterator gsi = gsi_start_bb (bb);
!gsi_end_p (gsi); gsi_next (&gsi))
if (stmt_can_terminate_bb_p (gsi_stmt (gsi))
/* stmt_can_terminate_bb_p special cases noreturns because it
assumes that fake edges are created. We want to know that
noreturn alone does not imply BB to be unlikely. */
|| (is_gimple_call (gsi_stmt (gsi))
&& (gimple_call_flags (gsi_stmt (gsi)) & ECF_NORETURN)))
{
found = true;
break;
}
if (found)
continue;
}
if (!(bb->count == profile_count::zero ())
&& (dump_file && (dump_flags & TDF_DETAILS)))
fprintf (dump_file,
"Basic block %i is marked unlikely by backward prop\n",
bb->index);
bb->count = profile_count::zero ();
bb->frequency = 0;
FOR_EACH_EDGE (e, ei, bb->preds)
if (!(e->count == profile_count::zero ()))
{
e->count = profile_count::zero ();
if (!(e->src->count == profile_count::zero ()))
{
nsuccs[e->src->index]--;
if (!nsuccs[e->src->index])
worklist.safe_push (e->src);
}
}
}
}
/* Estimate and propagate basic block frequencies using the given branch /* Estimate and propagate basic block frequencies using the given branch
probabilities. If FORCE is true, the frequencies are used to estimate probabilities. If FORCE is true, the frequencies are used to estimate
the counts even when there are already non-zero profile counts. */ the counts even when there are already non-zero profile counts. */
...@@ -3351,7 +3550,10 @@ estimate_bb_frequencies (bool force) ...@@ -3351,7 +3550,10 @@ estimate_bb_frequencies (bool force)
basic_block bb; basic_block bb;
sreal freq_max; sreal freq_max;
if (force || profile_status_for_fn (cfun) != PROFILE_READ || !counts_to_freqs ()) determine_unlikely_bbs ();
if (force || profile_status_for_fn (cfun) != PROFILE_READ
|| !counts_to_freqs ())
{ {
static int real_values_initialized = 0; static int real_values_initialized = 0;
...@@ -3423,8 +3625,9 @@ compute_function_frequency (void) ...@@ -3423,8 +3625,9 @@ compute_function_frequency (void)
if (profile_status_for_fn (cfun) != PROFILE_READ) if (profile_status_for_fn (cfun) != PROFILE_READ)
{ {
int flags = flags_from_decl_or_type (current_function_decl); int flags = flags_from_decl_or_type (current_function_decl);
if (lookup_attribute ("cold", DECL_ATTRIBUTES (current_function_decl)) if (ENTRY_BLOCK_PTR_FOR_FN (cfun)->count == profile_count::zero ()
!= NULL) || lookup_attribute ("cold", DECL_ATTRIBUTES (current_function_decl))
!= NULL)
node->frequency = NODE_FREQUENCY_UNLIKELY_EXECUTED; node->frequency = NODE_FREQUENCY_UNLIKELY_EXECUTED;
else if (lookup_attribute ("hot", DECL_ATTRIBUTES (current_function_decl)) else if (lookup_attribute ("hot", DECL_ATTRIBUTES (current_function_decl))
!= NULL) != NULL)
......
...@@ -36,7 +36,7 @@ along with GCC; see the file COPYING3. If not see ...@@ -36,7 +36,7 @@ along with GCC; see the file COPYING3. If not see
profile counts known while other do not - for example when LTO optimizing profile counts known while other do not - for example when LTO optimizing
partly profiled program or when profile was lost due to COMDAT merging. partly profiled program or when profile was lost due to COMDAT merging.
For this information profile_count tracks more information than For this reason profile_count tracks more information than
just unsigned integer and it is also ready for profile mismatches. just unsigned integer and it is also ready for profile mismatches.
The API of this data type represent operations that are natural The API of this data type represent operations that are natural
on profile counts - sum, difference and operation with scales and on profile counts - sum, difference and operation with scales and
......
2017-06-08 Jan Hubicka <hubicka@ucw.cz>
* g++.dg/tree-ssa/counts-1.C: New testcase.
* gcc.dg/tree-ssa/counts-1.c: New testcase.
2017-08-08 Julia Koval <julia.koval@intel.com> 2017-08-08 Julia Koval <julia.koval@intel.com>
* gcc.target/i386/avx512bw-vpmovswb-1.c: Add new intrinsics to test. * gcc.target/i386/avx512bw-vpmovswb-1.c: Add new intrinsics to test.
......
/* { dg-do compile } */
/* { dg-options "-O2 -fdump-tree-optimized" } */
void foo();
extern void abort (void);
static __attribute__ ((noinline))
void mark_me_unlikely ()
{
foo();
foo();
foo();
foo();
}
void i_am_not_unlikely()
{
try { foo(); }
catch (int) {mark_me_unlikely ();}
}
/* { dg-final { scan-tree-dump "mark_me_unlikely\[^\r\n\]*(unlikely executed)" "optimized"} } */
/* { dg-final { scan-tree-dump-not "i_am_not_unlikely\[^\r\n\]*(unlikely executed)" "optimized"} } */
/* { dg-do compile } */
/* { dg-options "-O2 -fdump-tree-optimized" } */
void unlikely () __attribute__ ((cold));
void unlikely2 () __attribute__ ((cold));
__attribute__ ((noinline)) void
i_am_also_unlikely (int a)
{
if (a)
unlikely ();
else
unlikely2 ();
}
void
i_am_also_unlikely2 (int a,int b)
{
if (b)
i_am_also_unlikely (a);
else
unlikely ();
}
void
i_am_not_unlikely (int a,int b,int c)
{
if (c)
__builtin_exit (0);
i_am_also_unlikely2 (a,b);
}
/* Detect i_am_also_unlikely i_am_also_unlikely2 as unlikely. */
/* { dg-final { scan-tree-dump "i_am_also_unlikely\[^\r\n\]*(unlikely executed)" "optimized"} } */
/* { dg-final { scan-tree-dump "i_am_also_unlikely2\[^\r\n\]*(unlikely executed)" "optimized"} } */
/* { dg-final { scan-tree-dump-not "i_am_not_unlikely\[^\r\n\]*(unlikely executed)" "optimized"} } */
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment