This is for https://gcc.gnu.org/PR126664 where an invariant condition in
a loop is estimated to have 0% and 100% edge probabilities. One can argue
about the 0% vs. 1000% in the loop, but, in any case, after hoisting the
condition, the probability is surely wrong as 41% and 59% are expected.
The 0% leads to count 0, which prevents vectorization; with vectorization,
the mentioned code in the PR runs, respectively, 9 or 40 times faster on
an AMD GPU with OpenMP and OpenACC offloading. (cf. PR)
* * *
For the question about the 100% and 0% see Richard's comment in the PR
in general and, additionally, his question whether the following is
a bug - fix by:
update_profile (epath, EDGE_SUCC (rd->dup_blocks[count], 0),
- path_out_count, path_out_count);
+ path_in_count, path_out_count);
* * *
Back to the attached patch:
The patch is based on the assumption that the probability can be
different when moved outside of the loop - and just re-guesses it
makes sense, which yields the expected 41% and 59% edge probabilities.
Is the patch OK – or at least like the right approach?
[At least for now, i.e. if it turned out that with other fixes,
it is no longer needed, then it could be still reverted.]
And: Any suggestion how to create a testcase for it?
I could package the testcase from the PR and check in the 'unswitch'
tree dump for the following:
if (l_params$hphb_187 < 0.0)
goto <bb 17>; [0.00%]
else
goto <bb 36>; [100.00%]
But not with 0% and 100% but with a probability between 10% and
90% for either edge. - Any better idea?
Tobias
Re-guess probability when unswitch hoists a condition before the loop [PR126664]
In the testcase in PR126664, the edge probabilities associated with the if
condition were 0% and 100%. The condition was loop invariant and the
'unswitch' pass hoisted it before the loop and created two loop variants.
However, the flow that lead to the 0% vs. 100% no longer holds after
hoisting and the 0% lead to a 0 count that hampered vectorization and
a severe performance penality.
The solution taken in this commit is to re-guess the branch probability -
which is now the expected 41% and 59%.
gcc/ChangeLog:
PR tree-optimization/126664
* cfgloopmanip.cc (lv_adjust_loop_entry_edge): If THEN_PROB or
ELSE_PROB is uninitialized, get the probability by calling
tree_guess_outgoing_edge_probabilities.
(loop_version): If THEN_PROB or ELSE_PROB are uninitialized,
scale by associated edge probability.
* tree-ssa-loop-unswitch.cc (tree_unswitch_loop): Pass an
uninitialized probability to loop_version.
Co-authored-by: Arsen Arsenović <[email protected]>
gcc/cfgloopmanip.cc | 36 +++++++++++++++++++++++++++++++-----
gcc/tree-ssa-loop-unswitch.cc | 11 +++++------
2 files changed, 36 insertions(+), 11 deletions(-)
diff --git a/gcc/cfgloopmanip.cc b/gcc/cfgloopmanip.cc
index f7551d5f30d..32ef907024f 100644
--- a/gcc/cfgloopmanip.cc
+++ b/gcc/cfgloopmanip.cc
@@ -1828,7 +1828,8 @@ force_single_succ_latches (void)
THEN_PROB is the probability of then branch of the condition.
ELSE_PROB is the probability of else branch. Note that they may be both
REG_BR_PROB_BASE when condition is IFN_LOOP_VECTORIZED or
- IFN_LOOP_DIST_ALIAS. */
+ IFN_LOOP_DIST_ALIAS. If either probability is uninitialized, the
+ edge probabilities are guessed. */
static basic_block
lv_adjust_loop_entry_edge (basic_block first_head, basic_block second_head,
@@ -1852,8 +1853,20 @@ lv_adjust_loop_entry_edge (basic_block first_head, basic_block second_head,
e = single_succ_edge (new_head);
e1 = make_edge (new_head, first_head,
current_ir_type () == IR_GIMPLE ? EDGE_TRUE_VALUE : 0);
- e1->probability = then_prob;
- e->probability = else_prob;
+
+ if (!then_prob.initialized_p () || !else_prob.initialized_p ())
+ {
+ edge e2;
+ edge_iterator ei;
+ FOR_EACH_EDGE (e2, ei, new_head->succs)
+ e2->probability = profile_probability::uninitialized ();
+ tree_guess_outgoing_edge_probabilities (new_head);
+ }
+ else
+ {
+ e1->probability = then_prob;
+ e->probability = else_prob;
+ }
set_immediate_dominator (CDI_DOMINATORS, first_head, new_head);
set_immediate_dominator (CDI_DOMINATORS, second_head, new_head);
@@ -1880,6 +1893,9 @@ lv_adjust_loop_entry_edge (basic_block first_head, basic_block second_head,
is the ratio by that the frequencies in the original loop should
be scaled. ELSE_SCALE is the ratio by that the frequencies in the
new loop should be scaled.
+ If THEN_PROB or ELSE_PROB are uninitialized, the edge probabilities
+ are guessed. If THEN_SCALE or ELSE_SCALE are uninitialized, the
+ scaling is based on the edge probability.
If PLACE_AFTER is true, we place the new loop after LOOP in the
instruction stream, otherwise it is placed before LOOP. */
@@ -1952,8 +1968,18 @@ loop_version (class loop *loop,
add_bb_to_loop (cond_bb, outer);
/* 4) Scale the original loop and new loop frequency. */
- scale_loop_frequencies (loop, then_scale);
- scale_loop_frequencies (nloop, else_scale);
+ if (then_scale.initialized_p () && else_scale.initialized_p ())
+ {
+ scale_loop_frequencies (loop, then_scale);
+ scale_loop_frequencies (nloop, else_scale);
+ }
+ else
+ {
+ edge te = EDGE_SUCC (cond_bb, 0);
+ edge ee = EDGE_SUCC (cond_bb, 1);
+ scale_loop_frequencies (loop, te->probability);
+ scale_loop_frequencies (nloop, ee->probability);
+ }
update_dominators_in_loop (loop);
update_dominators_in_loop (nloop);
diff --git a/gcc/tree-ssa-loop-unswitch.cc b/gcc/tree-ssa-loop-unswitch.cc
index a34c5385c7c..5dab8328f7c 100644
--- a/gcc/tree-ssa-loop-unswitch.cc
+++ b/gcc/tree-ssa-loop-unswitch.cc
@@ -1094,12 +1094,11 @@ tree_unswitch_loop (class loop *loop, edge edge_true, tree cond)
gcc_assert (flow_bb_inside_loop_p (loop, edge_true->src));
gcc_assert (EDGE_COUNT (edge_true->src->succs) >= 2);
- profile_probability prob_true = edge_true->probability;
- return loop_version (loop, unshare_expr (cond),
- NULL, prob_true,
- prob_true.invert (),
- prob_true, prob_true.invert (),
- false);
+ /* Let loop_version re-guess the probability of the condition as hoisting
+ might have changed the probability. */
+ profile_probability prob_uninit = profile_probability::uninitialized ();
+ return loop_version (loop, unshare_expr (cond), NULL, prob_uninit,
+ prob_uninit, prob_uninit, prob_uninit, false);
}
/* Unswitch outer loops by hoisting invariant guard on