===================================================================
@@ -0,0 +1,21 @@
+int baz (void);
+static int
+foo (int x)
+{
+ if (__builtin_expect (x <= 0, 0))
+ {
+ __builtin_printf ("foo\n");
+ __builtin_printf ("foo\n");
+ __builtin_printf ("foo\n");
+ __builtin_abort ();
+ }
+ return 6;
+}
+
+int a,b,c;
+
+int
+bar (int x)
+{
+ return foo (a) + foo (b) + foo (c);
+}
===================================================================
@@ -1855,9 +1855,6 @@ propagate_freq (basic_block head, bitmap
edge_iterator ei;
int count = 0;
- /* The outermost "loop" includes the exit block, which we can not
- look up via BASIC_BLOCK. Detect this and use EXIT_BLOCK_PTR
- directly. Do the same for the entry block. */
bb = BASIC_BLOCK (i);
FOR_EACH_EDGE (e, ei, bb->preds)
@@ -1872,6 +1869,9 @@ propagate_freq (basic_block head, bitmap
e->src->index, bb->index);
}
BLOCK_INFO (bb)->npredecessors = count;
+ /* When function never returns, we will never process exit block. */
+ if (!count && bb == EXIT_BLOCK_PTR)
+ bb->count = bb->frequency = 0;
}
memcpy (&BLOCK_INFO (head)->frequency, &real_one, sizeof (real_one));
@@ -2282,3 +2282,27 @@ struct gimple_opt_pass pass_strip_predic
TODO_ggc_collect | TODO_verify_ssa /* todo_flags_finish */
}
};
+
+/* Rebuild function frequencies. Passes are in general expected to
+ maintain profile by hand, however in some cases this is not possible:
+ for example when inlining several functions with loops freuqencies might run
+ out of scale and thus needs to be recomputed. */
+
+void
+rebuild_frequencies (void)
+{
+ if (profile_status == PROFILE_GUESSED)
+ {
+ loop_optimizer_init (0);
+ add_noreturn_fake_exit_edges ();
+ mark_irreducible_loops ();
+ connect_infinite_loops_to_exit ();
+ estimate_bb_frequencies ();
+ remove_fake_exit_edges ();
+ loop_optimizer_finalize ();
+ }
+ else if (profile_status == PROFILE_READ)
+ counts_to_freqs ();
+ else
+ gcc_unreachable ();
+}
===================================================================
@@ -42,5 +42,6 @@ extern const char *predictor_name (enum
extern tree build_predict_expr (enum br_predictor, enum prediction);
extern void tree_estimate_probability (void);
extern void compute_function_frequency (void);
+extern void rebuild_frequencies (void);
#endif /* GCC_PREDICT_H */
===================================================================
@@ -2159,6 +2159,8 @@ copy_cfg_body (copy_body_data * id, gcov
bool need_debug_cleanup = false;
gcov_type count_scale;
int last;
+ int incomming_frequency = 0;
+ gcov_type incomming_count = 0;
if (ENTRY_BLOCK_PTR_FOR_FUNCTION (src_cfun)->count)
count_scale = (REG_BR_PROB_BASE * count
@@ -2169,6 +2171,28 @@ copy_cfg_body (copy_body_data * id, gcov
/* Register specific tree functions. */
gimple_register_cfg_hooks ();
+ /* If we are inlining just region of the function, make sure to connect new entry
+ to ENTRY_BLOCK_PTR. Since new entry can be part of loop, we must compute
+ frequency and probability of ENTRY_BLOCK_PTR based on the frequencies and
+ probabilities of edges incomming from nonduplicated region. */
+ if (new_entry)
+ {
+ edge e;
+ edge_iterator ei;
+
+ FOR_EACH_EDGE (e, ei, new_entry->preds)
+ if (!e->src->aux)
+ {
+ incomming_frequency += EDGE_FREQUENCY (e);
+ incomming_count += e->count;
+ }
+ incomming_count = incomming_count * count_scale / REG_BR_PROB_BASE;
+ incomming_frequency
+ = incomming_frequency * frequency_scale / REG_BR_PROB_BASE;
+ ENTRY_BLOCK_PTR->count = incomming_count;
+ ENTRY_BLOCK_PTR->frequency = incomming_frequency;
+ }
+
/* Must have a CFG here at this point. */
gcc_assert (ENTRY_BLOCK_PTR_FOR_FUNCTION
(DECL_STRUCT_FUNCTION (callee_fndecl)));
@@ -2204,10 +2228,9 @@ copy_cfg_body (copy_body_data * id, gcov
if (new_entry)
{
- edge e;
- e = make_edge (entry_block_map, (basic_block)new_entry->aux, EDGE_FALLTHRU);
+ edge e = make_edge (entry_block_map, (basic_block)new_entry->aux, EDGE_FALLTHRU);
e->probability = REG_BR_PROB_BASE;
- e->count = entry_block_map->count;
+ e->count = incomming_count;
}
if (gimple_in_ssa_p (cfun))
@@ -5180,6 +5203,23 @@ tree_function_versioning (tree old_decl,
if (id.dst_node->analyzed)
cgraph_rebuild_references ();
update_ssa (TODO_update_ssa);
+
+ /* After partial cloning we need to rescale frequencies, so they are
+ within proper range in the cloned function. */
+ if (new_entry)
+ {
+ struct cgraph_edge *e;
+ rebuild_frequencies ();
+
+ new_version_node->count = ENTRY_BLOCK_PTR->count;
+ for (e = new_version_node->callees; e; e = e->next_callee)
+ {
+ basic_block bb = gimple_bb (e->call_stmt);
+ e->frequency = compute_call_stmt_bb_frequency (current_function_decl, bb);
+ e->count = bb->count;
+ }
+ }
+
free_dominance_info (CDI_DOMINATORS);
free_dominance_info (CDI_POST_DOMINATORS);
===================================================================
@@ -1243,22 +1243,7 @@ execute_function_todo (void *data)
}
if (flags & TODO_rebuild_frequencies)
- {
- if (profile_status == PROFILE_GUESSED)
- {
- loop_optimizer_init (0);
- add_noreturn_fake_exit_edges ();
- mark_irreducible_loops ();
- connect_infinite_loops_to_exit ();
- estimate_bb_frequencies ();
- remove_fake_exit_edges ();
- loop_optimizer_finalize ();
- }
- else if (profile_status == PROFILE_READ)
- counts_to_freqs ();
- else
- gcc_unreachable ();
- }
+ rebuild_frequencies ();
#if defined ENABLE_CHECKING
if (flags & TODO_verify_ssa