Commit e78410bf by Jan Hubicka Committed by Jan Hubicka

basic-block.h (RDIV): Define.

	* basic-block.h (RDIV): Define.
	(EDGE_FREQUENCY): Simplify.
	(check_probability, combine_probabilities, apply_probability,
	inverse_probability): New.
	* cfgloop.c (scale_loop_profile): New function.
	* cfgloop.h (scale_loop_profile): Declare.
	(slpeel_add_loop_guard): Add probability parameter.
	(set_prologue_iterations): Add probability parameter.
	(slpeel_tree_peel_loop_to_edge): Add bound1 and bound2 parameters;
	update probabilities correctly.
	(vect_do_peeling_for_alignment, vect_gen_niters_for_prolog_loop): New.

From-SVN: r191839
parent 0380c51f
2012-09-28 Jan Hubicka <jh@suse.cz>
* basic-block.h (RDIV): Define.
(EDGE_FREQUENCY): Simplify.
(check_probability, combine_probabilities, apply_probability,
inverse_probability): New.
* cfgloop.c (scale_loop_profile): New function.
* cfgloop.h (scale_loop_profile): Declare.
(slpeel_add_loop_guard): Add probability parameter.
(set_prologue_iterations): Add probability parameter.
(slpeel_tree_peel_loop_to_edge): Add bound1 and bound2 parameters;
update probabilities correctly.
(vect_do_peeling_for_alignment, vect_gen_niters_for_prolog_loop): New.
2012-09-20 Bernd Schmidt <bernds@codesourcery.com> 2012-09-20 Bernd Schmidt <bernds@codesourcery.com>
PR bootstrap/54688 PR bootstrap/54688
......
...@@ -478,11 +478,10 @@ struct edge_list ...@@ -478,11 +478,10 @@ struct edge_list
#define BRANCH_EDGE(bb) (EDGE_SUCC ((bb), 0)->flags & EDGE_FALLTHRU \ #define BRANCH_EDGE(bb) (EDGE_SUCC ((bb), 0)->flags & EDGE_FALLTHRU \
? EDGE_SUCC ((bb), 1) : EDGE_SUCC ((bb), 0)) ? EDGE_SUCC ((bb), 1) : EDGE_SUCC ((bb), 0))
#define RDIV(X,Y) (((X) + (Y) / 2) / (Y))
/* Return expected execution frequency of the edge E. */ /* Return expected execution frequency of the edge E. */
#define EDGE_FREQUENCY(e) (((e)->src->frequency \ #define EDGE_FREQUENCY(e) RDIV ((e)->src->frequency * (e)->probability, \
* (e)->probability \ REG_BR_PROB_BASE)
+ REG_BR_PROB_BASE / 2) \
/ REG_BR_PROB_BASE)
/* Return nonzero if edge is critical. */ /* Return nonzero if edge is critical. */
#define EDGE_CRITICAL_P(e) (EDGE_COUNT ((e)->src->succs) >= 2 \ #define EDGE_CRITICAL_P(e) (EDGE_COUNT ((e)->src->succs) >= 2 \
...@@ -910,4 +909,40 @@ extern void default_rtl_profile (void); ...@@ -910,4 +909,40 @@ extern void default_rtl_profile (void);
/* In profile.c. */ /* In profile.c. */
extern gcov_working_set_t *find_working_set(unsigned pct_times_10); extern gcov_working_set_t *find_working_set(unsigned pct_times_10);
/* Check tha probability is sane. */
static inline void
check_probability (int prob)
{
gcc_checking_assert (prob >= 0 && prob <= REG_BR_PROB_BASE);
}
/* Given PROB1 and PROB2, return PROB1*PROB2/REG_BR_PROB_BASE.
Used to combine BB probabilities. */
static inline int
combine_probabilities (int prob1, int prob2)
{
check_probability (prob1);
check_probability (prob2);
return RDIV (prob1 * prob2, REG_BR_PROB_BASE);
}
/* Apply probability PROB on frequency or count FREQ. */
static inline gcov_type
apply_probability (gcov_type freq, int prob)
{
check_probability (prob);
return RDIV (freq * prob, REG_BR_PROB_BASE);
}
/* Return inverse probability for PROB. */
static inline int
inverse_probability (int prob1)
{
check_probability (prob1);
return REG_BR_PROB_BASE - prob1;
}
#endif /* GCC_BASIC_BLOCK_H */ #endif /* GCC_BASIC_BLOCK_H */
...@@ -1666,3 +1666,121 @@ loop_exits_from_bb_p (struct loop *loop, basic_block bb) ...@@ -1666,3 +1666,121 @@ loop_exits_from_bb_p (struct loop *loop, basic_block bb)
return false; return false;
} }
/* Scale the profile estiamte within loop by SCALE.
If ITERATION_BOUND is non-zero, scale even further if loop is predicted
to iterate too many times. */
void
scale_loop_profile (struct loop *loop, int scale, int iteration_bound)
{
gcov_type iterations = expected_loop_iterations_unbounded (loop);
basic_block *bbs;
unsigned int i;
edge e;
edge_iterator ei;
if (dump_file && (dump_flags & TDF_DETAILS))
fprintf (dump_file, ";; Scaling loop %i with scale %f, "
"bounding iterations to %i from guessed %i\n",
loop->num, (double)scale / REG_BR_PROB_BASE,
iteration_bound, (int)iterations);
/* See if loop is predicted to iterate too many times. */
if (iteration_bound && iterations > 0
&& RDIV (iterations * scale, REG_BR_PROB_BASE) > iteration_bound)
{
/* Fixing loop profile for different trip count is not trivial; the exit
probabilities has to be updated to match and frequencies propagated down
to the loop body.
We fully update only the simple case of loop with single exit that is
either from the latch or BB just before latch and leads from BB with
simple conditional jump. This is OK for use in vectorizer. */
e = single_exit (loop);
if (e)
{
edge other_e;
int freq_delta;
gcov_type count_delta;
FOR_EACH_EDGE (other_e, ei, e->src->succs)
if (!(other_e->flags & (EDGE_ABNORMAL | EDGE_FAKE))
&& e != other_e)
break;
/* Probability of exit must be 1/iterations. */
freq_delta = EDGE_FREQUENCY (e);
e->probability = REG_BR_PROB_BASE / iteration_bound;
other_e->probability = inverse_probability (e->probability);
freq_delta -= EDGE_FREQUENCY (e);
/* Adjust counts accordingly. */
count_delta = e->count;
e->count = apply_probability (e->src->count, e->probability);
other_e->count = apply_probability (e->src->count, other_e->probability);
count_delta -= e->count;
/* If latch exists, change its frequency and count, since we changed
probability of exit. Theoretically we should update everything from
source of exit edge to latch, but for vectorizer this is enough. */
if (loop->latch
&& loop->latch != e->src)
{
loop->latch->frequency += freq_delta;
if (loop->latch->frequency < 0)
loop->latch->frequency = 0;
loop->latch->count += count_delta;
if (loop->latch->count < 0)
loop->latch->count = 0;
}
}
/* Roughly speaking we want to reduce the loop body profile by the
the difference of loop iterations. We however can do better if
we look at the actual profile, if it is available. */
scale = RDIV (iteration_bound * scale, iterations);
if (loop->header->count)
{
gcov_type count_in = 0;
FOR_EACH_EDGE (e, ei, loop->header->preds)
if (e->src != loop->latch)
count_in += e->count;
if (count_in != 0)
scale = RDIV (count_in * iteration_bound * REG_BR_PROB_BASE, loop->header->count);
}
else if (loop->header->frequency)
{
int freq_in = 0;
FOR_EACH_EDGE (e, ei, loop->header->preds)
if (e->src != loop->latch)
freq_in += EDGE_FREQUENCY (e);
if (freq_in != 0)
scale = RDIV (freq_in * iteration_bound * REG_BR_PROB_BASE, loop->header->frequency);
}
if (!scale)
scale = 1;
}
if (scale == REG_BR_PROB_BASE)
return;
/* Scale the actual probabilities. */
bbs = get_loop_body (loop);
for (i = 0; i < loop->num_nodes; i++)
{
basic_block bb = bbs[i];
bb->count = RDIV (bb->count * scale, REG_BR_PROB_BASE);
bb->frequency = RDIV (bb->frequency * scale, REG_BR_PROB_BASE);
FOR_EACH_EDGE (e, ei, bb->succs)
e->count = RDIV (e->count * scale, REG_BR_PROB_BASE);
}
if (dump_file && (dump_flags & TDF_DETAILS))
fprintf (dump_file, ";; guessed iterations are now %i\n",
(int)expected_loop_iterations_unbounded (loop));
free (bbs);
}
...@@ -713,5 +713,6 @@ extern void unroll_and_peel_loops (int); ...@@ -713,5 +713,6 @@ extern void unroll_and_peel_loops (int);
extern void doloop_optimize_loops (void); extern void doloop_optimize_loops (void);
extern void move_loop_invariants (void); extern void move_loop_invariants (void);
extern bool finite_loop_p (struct loop *); extern bool finite_loop_p (struct loop *);
extern void scale_loop_profile (struct loop *loop, int scale, int iteration_bound);
#endif /* GCC_CFGLOOP_H */ #endif /* GCC_CFGLOOP_H */
...@@ -931,7 +931,8 @@ slpeel_tree_duplicate_loop_to_edge_cfg (struct loop *loop, edge e) ...@@ -931,7 +931,8 @@ slpeel_tree_duplicate_loop_to_edge_cfg (struct loop *loop, edge e)
static edge static edge
slpeel_add_loop_guard (basic_block guard_bb, tree cond, slpeel_add_loop_guard (basic_block guard_bb, tree cond,
gimple_seq cond_expr_stmt_list, gimple_seq cond_expr_stmt_list,
basic_block exit_bb, basic_block dom_bb) basic_block exit_bb, basic_block dom_bb,
int probability)
{ {
gimple_stmt_iterator gsi; gimple_stmt_iterator gsi;
edge new_e, enter_e; edge new_e, enter_e;
...@@ -956,6 +957,12 @@ slpeel_add_loop_guard (basic_block guard_bb, tree cond, ...@@ -956,6 +957,12 @@ slpeel_add_loop_guard (basic_block guard_bb, tree cond,
/* Add new edge to connect guard block to the merge/loop-exit block. */ /* Add new edge to connect guard block to the merge/loop-exit block. */
new_e = make_edge (guard_bb, exit_bb, EDGE_TRUE_VALUE); new_e = make_edge (guard_bb, exit_bb, EDGE_TRUE_VALUE);
new_e->count = guard_bb->count;
new_e->probability = probability;
new_e->count = apply_probability (enter_e->count, probability);
enter_e->count -= new_e->count;
enter_e->probability = inverse_probability (probability);
set_immediate_dominator (CDI_DOMINATORS, exit_bb, dom_bb); set_immediate_dominator (CDI_DOMINATORS, exit_bb, dom_bb);
return new_e; return new_e;
} }
...@@ -1038,7 +1045,8 @@ static void ...@@ -1038,7 +1045,8 @@ static void
set_prologue_iterations (basic_block bb_before_first_loop, set_prologue_iterations (basic_block bb_before_first_loop,
tree *first_niters, tree *first_niters,
struct loop *loop, struct loop *loop,
unsigned int th) unsigned int th,
int probability)
{ {
edge e; edge e;
basic_block cond_bb, then_bb; basic_block cond_bb, then_bb;
...@@ -1067,7 +1075,15 @@ set_prologue_iterations (basic_block bb_before_first_loop, ...@@ -1067,7 +1075,15 @@ set_prologue_iterations (basic_block bb_before_first_loop,
e_true->flags &= ~EDGE_FALLTHRU; e_true->flags &= ~EDGE_FALLTHRU;
e_true->flags |= EDGE_TRUE_VALUE; e_true->flags |= EDGE_TRUE_VALUE;
e_true->probability = probability;
e_false->probability = inverse_probability (probability);
e_true->count = apply_probability (cond_bb->count, probability);
e_false->count = cond_bb->count - e_true->count;
then_bb->frequency = EDGE_FREQUENCY (e_true);
then_bb->count = e_true->count;
e_fallthru = EDGE_SUCC (then_bb, 0); e_fallthru = EDGE_SUCC (then_bb, 0);
e_fallthru->count = then_bb->count;
gsi = gsi_last_bb (cond_bb); gsi = gsi_last_bb (cond_bb);
cost_pre_condition = cost_pre_condition =
...@@ -1126,6 +1142,8 @@ set_prologue_iterations (basic_block bb_before_first_loop, ...@@ -1126,6 +1142,8 @@ set_prologue_iterations (basic_block bb_before_first_loop,
prologue generation or whether cost model check prologue generation or whether cost model check
has not occurred during prologue generation and hence has not occurred during prologue generation and hence
needs to occur during epilogue generation. needs to occur during epilogue generation.
- BOUND1 is the upper bound on number of iterations of the first loop (if known)
- BOUND2 is the upper bound on number of iterations of the second loop (if known)
Output: Output:
...@@ -1153,7 +1171,8 @@ slpeel_tree_peel_loop_to_edge (struct loop *loop, ...@@ -1153,7 +1171,8 @@ slpeel_tree_peel_loop_to_edge (struct loop *loop,
edge e, tree *first_niters, edge e, tree *first_niters,
tree niters, bool update_first_loop_count, tree niters, bool update_first_loop_count,
unsigned int th, bool check_profitability, unsigned int th, bool check_profitability,
tree cond_expr, gimple_seq cond_expr_stmt_list) tree cond_expr, gimple_seq cond_expr_stmt_list,
int bound1, int bound2)
{ {
struct loop *new_loop = NULL, *first_loop, *second_loop; struct loop *new_loop = NULL, *first_loop, *second_loop;
edge skip_e; edge skip_e;
...@@ -1166,6 +1185,13 @@ slpeel_tree_peel_loop_to_edge (struct loop *loop, ...@@ -1166,6 +1185,13 @@ slpeel_tree_peel_loop_to_edge (struct loop *loop,
edge exit_e = single_exit (loop); edge exit_e = single_exit (loop);
LOC loop_loc; LOC loop_loc;
tree cost_pre_condition = NULL_TREE; tree cost_pre_condition = NULL_TREE;
/* There are many aspects to how likely the first loop is going to be executed.
Without histogram we can't really do good job. Simply set it to
2/3, so the first loop is not reordered to the end of function and
the hot path through stays short. */
int first_guard_probability = 2 * REG_BR_PROB_BASE / 3;
int second_guard_probability = 2 * REG_BR_PROB_BASE / 3;
int probability_of_second_loop;
if (!slpeel_can_duplicate_loop_p (loop, e)) if (!slpeel_can_duplicate_loop_p (loop, e))
return NULL; return NULL;
...@@ -1341,6 +1367,21 @@ slpeel_tree_peel_loop_to_edge (struct loop *loop, ...@@ -1341,6 +1367,21 @@ slpeel_tree_peel_loop_to_edge (struct loop *loop,
bb_before_first_loop = split_edge (loop_preheader_edge (first_loop)); bb_before_first_loop = split_edge (loop_preheader_edge (first_loop));
bb_before_second_loop = split_edge (single_exit (first_loop)); bb_before_second_loop = split_edge (single_exit (first_loop));
probability_of_second_loop = (inverse_probability (first_guard_probability)
+ combine_probabilities (second_guard_probability,
first_guard_probability));
/* Theoretically preheader edge of first loop and exit edge should have
same frequencies. Loop exit probablities are however easy to get wrong.
It is safer to copy value from original loop entry. */
bb_before_second_loop->frequency
= apply_probability (bb_before_first_loop->frequency,
probability_of_second_loop);
bb_before_second_loop->count
= apply_probability (bb_before_first_loop->count,
probability_of_second_loop);
single_succ_edge (bb_before_second_loop)->count
= bb_before_second_loop->count;
/* Epilogue peeling. */ /* Epilogue peeling. */
if (!update_first_loop_count) if (!update_first_loop_count)
{ {
...@@ -1374,7 +1415,7 @@ slpeel_tree_peel_loop_to_edge (struct loop *loop, ...@@ -1374,7 +1415,7 @@ slpeel_tree_peel_loop_to_edge (struct loop *loop,
{ {
if (check_profitability) if (check_profitability)
set_prologue_iterations (bb_before_first_loop, first_niters, set_prologue_iterations (bb_before_first_loop, first_niters,
loop, th); loop, th, first_guard_probability);
pre_condition = pre_condition =
fold_build2 (LE_EXPR, boolean_type_node, *first_niters, fold_build2 (LE_EXPR, boolean_type_node, *first_niters,
...@@ -1383,7 +1424,10 @@ slpeel_tree_peel_loop_to_edge (struct loop *loop, ...@@ -1383,7 +1424,10 @@ slpeel_tree_peel_loop_to_edge (struct loop *loop,
skip_e = slpeel_add_loop_guard (bb_before_first_loop, pre_condition, skip_e = slpeel_add_loop_guard (bb_before_first_loop, pre_condition,
cond_expr_stmt_list, cond_expr_stmt_list,
bb_before_second_loop, bb_before_first_loop); bb_before_second_loop, bb_before_first_loop,
inverse_probability (first_guard_probability));
scale_loop_profile (first_loop, first_guard_probability,
check_profitability && (int)th > bound1 ? th : bound1);
slpeel_update_phi_nodes_for_guard1 (skip_e, first_loop, slpeel_update_phi_nodes_for_guard1 (skip_e, first_loop,
first_loop == new_loop, first_loop == new_loop,
&new_exit_bb); &new_exit_bb);
...@@ -1421,7 +1465,9 @@ slpeel_tree_peel_loop_to_edge (struct loop *loop, ...@@ -1421,7 +1465,9 @@ slpeel_tree_peel_loop_to_edge (struct loop *loop,
pre_condition = pre_condition =
fold_build2 (EQ_EXPR, boolean_type_node, *first_niters, niters); fold_build2 (EQ_EXPR, boolean_type_node, *first_niters, niters);
skip_e = slpeel_add_loop_guard (bb_between_loops, pre_condition, NULL, skip_e = slpeel_add_loop_guard (bb_between_loops, pre_condition, NULL,
bb_after_second_loop, bb_before_first_loop); bb_after_second_loop, bb_before_first_loop,
inverse_probability (second_guard_probability));
scale_loop_profile (second_loop, probability_of_second_loop, bound2);
slpeel_update_phi_nodes_for_guard2 (skip_e, second_loop, slpeel_update_phi_nodes_for_guard2 (skip_e, second_loop,
second_loop == new_loop, &new_exit_bb); second_loop == new_loop, &new_exit_bb);
...@@ -1882,7 +1928,8 @@ vect_do_peeling_for_loop_bound (loop_vec_info loop_vinfo, tree *ratio, ...@@ -1882,7 +1928,8 @@ vect_do_peeling_for_loop_bound (loop_vec_info loop_vinfo, tree *ratio,
new_loop = slpeel_tree_peel_loop_to_edge (loop, single_exit (loop), new_loop = slpeel_tree_peel_loop_to_edge (loop, single_exit (loop),
&ratio_mult_vf_name, ni_name, false, &ratio_mult_vf_name, ni_name, false,
th, check_profitability, th, check_profitability,
cond_expr, cond_expr_stmt_list); cond_expr, cond_expr_stmt_list,
0, LOOP_VINFO_VECT_FACTOR (loop_vinfo));
gcc_assert (new_loop); gcc_assert (new_loop);
gcc_assert (loop_num == loop->num); gcc_assert (loop_num == loop->num);
#ifdef ENABLE_CHECKING #ifdef ENABLE_CHECKING
...@@ -1951,7 +1998,7 @@ vect_do_peeling_for_loop_bound (loop_vec_info loop_vinfo, tree *ratio, ...@@ -1951,7 +1998,7 @@ vect_do_peeling_for_loop_bound (loop_vec_info loop_vinfo, tree *ratio,
use TYPE_VECTOR_SUBPARTS. */ use TYPE_VECTOR_SUBPARTS. */
static tree static tree
vect_gen_niters_for_prolog_loop (loop_vec_info loop_vinfo, tree loop_niters) vect_gen_niters_for_prolog_loop (loop_vec_info loop_vinfo, tree loop_niters, int *bound)
{ {
struct data_reference *dr = LOOP_VINFO_UNALIGNED_DR (loop_vinfo); struct data_reference *dr = LOOP_VINFO_UNALIGNED_DR (loop_vinfo);
struct loop *loop = LOOP_VINFO_LOOP (loop_vinfo); struct loop *loop = LOOP_VINFO_LOOP (loop_vinfo);
...@@ -1977,6 +2024,7 @@ vect_gen_niters_for_prolog_loop (loop_vec_info loop_vinfo, tree loop_niters) ...@@ -1977,6 +2024,7 @@ vect_gen_niters_for_prolog_loop (loop_vec_info loop_vinfo, tree loop_niters)
fprintf (vect_dump, "known peeling = %d.", npeel); fprintf (vect_dump, "known peeling = %d.", npeel);
iters = build_int_cst (niters_type, npeel); iters = build_int_cst (niters_type, npeel);
*bound = LOOP_PEELING_FOR_ALIGNMENT (loop_vinfo);
} }
else else
{ {
...@@ -2015,6 +2063,7 @@ vect_gen_niters_for_prolog_loop (loop_vec_info loop_vinfo, tree loop_niters) ...@@ -2015,6 +2063,7 @@ vect_gen_niters_for_prolog_loop (loop_vec_info loop_vinfo, tree loop_niters)
iters = fold_build2 (MINUS_EXPR, type, nelements_tree, elem_misalign); iters = fold_build2 (MINUS_EXPR, type, nelements_tree, elem_misalign);
iters = fold_build2 (BIT_AND_EXPR, type, iters, nelements_minus_1); iters = fold_build2 (BIT_AND_EXPR, type, iters, nelements_minus_1);
iters = fold_convert (niters_type, iters); iters = fold_convert (niters_type, iters);
*bound = nelements;
} }
/* Create: prolog_loop_niters = min (iters, loop_niters) */ /* Create: prolog_loop_niters = min (iters, loop_niters) */
...@@ -2107,6 +2156,7 @@ vect_do_peeling_for_alignment (loop_vec_info loop_vinfo, ...@@ -2107,6 +2156,7 @@ vect_do_peeling_for_alignment (loop_vec_info loop_vinfo,
tree wide_prolog_niters; tree wide_prolog_niters;
struct loop *new_loop; struct loop *new_loop;
int max_iter; int max_iter;
int bound = 0;
if (vect_print_dump_info (REPORT_DETAILS)) if (vect_print_dump_info (REPORT_DETAILS))
fprintf (vect_dump, "=== vect_do_peeling_for_alignment ==="); fprintf (vect_dump, "=== vect_do_peeling_for_alignment ===");
...@@ -2115,13 +2165,16 @@ vect_do_peeling_for_alignment (loop_vec_info loop_vinfo, ...@@ -2115,13 +2165,16 @@ vect_do_peeling_for_alignment (loop_vec_info loop_vinfo,
ni_name = vect_build_loop_niters (loop_vinfo, NULL); ni_name = vect_build_loop_niters (loop_vinfo, NULL);
niters_of_prolog_loop = vect_gen_niters_for_prolog_loop (loop_vinfo, niters_of_prolog_loop = vect_gen_niters_for_prolog_loop (loop_vinfo,
ni_name); ni_name,
&bound);
/* Peel the prolog loop and iterate it niters_of_prolog_loop. */ /* Peel the prolog loop and iterate it niters_of_prolog_loop. */
new_loop = new_loop =
slpeel_tree_peel_loop_to_edge (loop, loop_preheader_edge (loop), slpeel_tree_peel_loop_to_edge (loop, loop_preheader_edge (loop),
&niters_of_prolog_loop, ni_name, true, &niters_of_prolog_loop, ni_name, true,
th, check_profitability, NULL_TREE, NULL); th, check_profitability, NULL_TREE, NULL,
bound,
0);
gcc_assert (new_loop); gcc_assert (new_loop);
#ifdef ENABLE_CHECKING #ifdef ENABLE_CHECKING
......
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