Skip to content

Commit

Permalink
Break out profile updating code from gimple_duplicate_sese_region
Browse files Browse the repository at this point in the history
Move profile updating to tree-ssa-loop-ch.cc since it is
now quite ch specific. There are no functional changes.

Boostrapped/regtesed x86_64-linux, comitted.

gcc/ChangeLog:

	* tree-cfg.cc (gimple_duplicate_sese_region): Rename to ...
	(gimple_duplicate_seme_region): ... this; break out profile updating
	code to ...
	* tree-ssa-loop-ch.cc (update_profile_after_ch): ... here.
	(ch_base::copy_headers): Update.
	* tree-cfg.h (gimple_duplicate_sese_region): Rename to ...
	(gimple_duplicate_seme_region): ... this.
  • Loading branch information
Jan Hubicka committed Jul 12, 2023
1 parent 7a5e476 commit 7df810d
Show file tree
Hide file tree
Showing 3 changed files with 134 additions and 150 deletions.
148 changes: 4 additions & 144 deletions gcc/tree-cfg.cc
Original file line number Diff line number Diff line change
Expand Up @@ -6662,25 +6662,19 @@ add_phi_args_after_copy (basic_block *region_copy, unsigned n_region,
The function returns false if it is unable to copy the region,
true otherwise.
ELIMINATED_EDGE is an edge that is known to be removed in the dupicated
region. ORIG_ELIMINATED_EDGES, if non-NULL is set of edges known to be
removed from the original region. */
It is callers responsibility to update profile. */

bool
gimple_duplicate_sese_region (edge entry, edge exit,
gimple_duplicate_seme_region (edge entry, edge exit,
basic_block *region, unsigned n_region,
basic_block *region_copy,
bool update_dominance,
edge eliminated_edge,
hash_set <edge> *orig_eliminated_edges)
bool update_dominance)
{
unsigned i;
bool free_region_copy = false, copying_header = false;
class loop *loop = entry->dest->loop_father;
edge exit_copy;
edge redirected;
profile_count total_count = profile_count::uninitialized ();
profile_count entry_count = profile_count::uninitialized ();

if (!can_copy_bbs_p (region, n_region))
return false;
Expand Down Expand Up @@ -6733,144 +6727,10 @@ gimple_duplicate_sese_region (edge entry, edge exit,
inside. */
auto_vec<basic_block> doms;
if (update_dominance)
{
doms = get_dominated_by_region (CDI_DOMINATORS, region, n_region);
}

if (entry->dest->count.initialized_p ())
{
total_count = entry->dest->count;
entry_count = entry->count ();
/* Fix up corner cases, to avoid division by zero or creation of negative
frequencies. */
if (entry_count > total_count)
entry_count = total_count;
}
doms = get_dominated_by_region (CDI_DOMINATORS, region, n_region);

copy_bbs (region, n_region, region_copy, &exit, 1, &exit_copy, loop,
split_edge_bb_loc (entry), update_dominance);
if (total_count.initialized_p () && entry_count.initialized_p ())
{
if (!eliminated_edge
&& (!orig_eliminated_edges || orig_eliminated_edges->is_empty ()))
{
scale_bbs_frequencies_profile_count (region, n_region,
total_count - entry_count,
total_count);
scale_bbs_frequencies_profile_count (region_copy, n_region,
entry_count, total_count);
}
else
{
/* We only support only case where eliminated_edge is one and it
exists first BB. We also assume that the duplicated region is
acyclic. So we expect the following:
// region_copy_start entry will be scaled to entry_count
if (cond1) <- this condition will become false
and we update probabilities
goto loop_exit;
if (cond2) <- this condition is loop invariant
goto loop_exit;
goto loop_header <- this will be redirected to loop.
// region_copy_end
loop:
<body>
// region start
loop_header:
if (cond1) <- we need to update probabbility here
goto loop_exit;
if (cond2) <- and determine scaling factor here.
moreover cond2 is now always true
goto loop_exit;
else
goto loop;
// region end
Adding support for more exits can be done similarly,
but only consumer so far is tree-ssa-loop-ch and it uses only this
to handle the common case of peeling headers which have
conditionals known to be always true upon entry. */
gcc_checking_assert (copying_header);
for (unsigned int i = 0; i < n_region; i++)
{
edge exit_e, exit_e_copy, e, e_copy;
if (EDGE_COUNT (region[i]->succs) == 1)
{
region_copy[i]->count = entry_count;
region[i]->count -= entry_count;
continue;
}

gcc_checking_assert (EDGE_COUNT (region[i]->succs) == 2);
if (loop_exit_edge_p (region[0]->loop_father,
EDGE_SUCC (region[i], 0)))
{
exit_e = EDGE_SUCC (region[i], 0);
exit_e_copy = EDGE_SUCC (region_copy[i], 0);
e = EDGE_SUCC (region[i], 1);
e_copy = EDGE_SUCC (region_copy[i], 1);
}
else
{
exit_e = EDGE_SUCC (region[i], 1);
exit_e_copy = EDGE_SUCC (region_copy[i], 1);
e = EDGE_SUCC (region[i], 0);
e_copy = EDGE_SUCC (region_copy[i], 0);
}
gcc_assert (i == n_region - 1
|| (e->dest == region[i + 1]
&& e_copy->dest == region_copy[i + 1]));
region_copy[i]->count = entry_count;
profile_count exit_e_count = exit_e->count ();
if (eliminated_edge == exit_e)
{
/* Update profile and the conditional.
CFG update is done by caller. */
e_copy->probability = profile_probability::always ();
exit_e_copy->probability = profile_probability::never ();
gcond *cond_stmt
= as_a <gcond *>(*gsi_last_bb (region_copy[i]));
if (e_copy->flags & EDGE_TRUE_VALUE)
gimple_cond_make_true (cond_stmt);
else
gimple_cond_make_false (cond_stmt);
update_stmt (cond_stmt);
/* Header copying is a special case of jump threading, so use
common code to update loop body exit condition. */
update_bb_profile_for_threading (region[i], entry_count, e);
eliminated_edge = NULL;
}
else
region[i]->count -= region_copy[i]->count;
if (orig_eliminated_edges->contains (exit_e))
{
orig_eliminated_edges->remove (exit_e);
/* All exits will happen in exit_e_copy which is out of the
loop, so increase probability accordingly.
If the edge is eliminated_edge we already corrected
profile above. */
if (entry_count.nonzero_p () && eliminated_edge != exit_e)
set_edge_probability_and_rescale_others
(exit_e_copy, exit_e_count.probability_in
(entry_count));
/* Eliminate in-loop conditional. */
e->probability = profile_probability::always ();
exit_e->probability = profile_probability::never ();
gcond *cond_stmt = as_a <gcond *>(*gsi_last_bb (region[i]));
if (e->flags & EDGE_TRUE_VALUE)
gimple_cond_make_true (cond_stmt);
else
gimple_cond_make_false (cond_stmt);
update_stmt (cond_stmt);
}
entry_count = e_copy->count ();
}
/* Be sure that we seen all edges we are supposed to update. */
gcc_checking_assert (!eliminated_edge
&& orig_eliminated_edges->is_empty ());
}
}

if (copying_header)
{
Expand Down
5 changes: 2 additions & 3 deletions gcc/tree-cfg.h
Original file line number Diff line number Diff line change
Expand Up @@ -69,9 +69,8 @@ extern tree gimple_block_label (basic_block);
extern void add_phi_args_after_copy_bb (basic_block);
extern void add_phi_args_after_copy (basic_block *, unsigned, edge);
extern basic_block split_edge_bb_loc (edge);
extern bool gimple_duplicate_sese_region (edge, edge, basic_block *, unsigned,
basic_block *, bool, edge,
hash_set <edge> *);
extern bool gimple_duplicate_seme_region (edge, edge, basic_block *, unsigned,
basic_block *, bool);
extern bool gimple_duplicate_sese_tail (edge, edge, basic_block *, unsigned,
basic_block *);
extern void gather_blocks_in_sese_region (basic_block entry, basic_block exit,
Expand Down
131 changes: 128 additions & 3 deletions gcc/tree-ssa-loop-ch.cc
Original file line number Diff line number Diff line change
Expand Up @@ -347,6 +347,128 @@ do_while_loop_p (class loop *loop)
return true;
}

/* Update profile after header copying of LOOP.
REGION is the original (in loop) sequence, REGION_COPY is the
duplicated header (now outside of loop). N_REGION is number of
bbs duplicated.
ELIMINATED_EDGE is edge to be removed from duplicated sequence.
INVARIANT_EXITS are edges in the loop body to be elimianted
since they are loop invariants
So We expect the following:
// region_copy_start entry will be scaled to entry_count
if (cond1) <- this condition will become false
and we update probabilities
goto loop_exit;
if (cond2) <- this condition is loop invariant
goto loop_exit;
goto loop_header <- this will be redirected to loop.
// region_copy_end
loop:
<body>
// region start
loop_header:
if (cond1) <- we need to update probabbility here
goto loop_exit;
if (cond2) <- and determine scaling factor here.
moreover cond2 is now always true
goto loop_exit;
else
goto loop;
// region end
Adding support for more exits can be done similarly,
but only consumer so far is tree-ssa-loop-ch and it uses only this
to handle the common case of peeling headers which have
conditionals known to be always true upon entry. */

static void
update_profile_after_ch (class loop *loop,
basic_block *region, basic_block *region_copy,
unsigned n_region, edge eliminated_edge,
hash_set <edge> *invariant_exits,
profile_count entry_count)
{
for (unsigned int i = 0; i < n_region; i++)
{
edge exit_e, exit_e_copy, e, e_copy;
if (EDGE_COUNT (region[i]->succs) == 1)
{
region_copy[i]->count = entry_count;
region[i]->count -= entry_count;
continue;
}

gcc_checking_assert (EDGE_COUNT (region[i]->succs) == 2);
if (loop_exit_edge_p (loop,
EDGE_SUCC (region[i], 0)))
{
exit_e = EDGE_SUCC (region[i], 0);
exit_e_copy = EDGE_SUCC (region_copy[i], 0);
e = EDGE_SUCC (region[i], 1);
e_copy = EDGE_SUCC (region_copy[i], 1);
}
else
{
exit_e = EDGE_SUCC (region[i], 1);
exit_e_copy = EDGE_SUCC (region_copy[i], 1);
e = EDGE_SUCC (region[i], 0);
e_copy = EDGE_SUCC (region_copy[i], 0);
}
gcc_assert (i == n_region - 1
|| (e->dest == region[i + 1]
&& e_copy->dest == region_copy[i + 1]));
region_copy[i]->count = entry_count;
profile_count exit_e_count = exit_e->count ();
if (eliminated_edge == exit_e)
{
/* Update profile and the conditional.
CFG update is done by caller. */
e_copy->probability = profile_probability::always ();
exit_e_copy->probability = profile_probability::never ();
gcond *cond_stmt
= as_a <gcond *>(*gsi_last_bb (region_copy[i]));
if (e_copy->flags & EDGE_TRUE_VALUE)
gimple_cond_make_true (cond_stmt);
else
gimple_cond_make_false (cond_stmt);
update_stmt (cond_stmt);
/* Header copying is a special case of jump threading, so use
common code to update loop body exit condition. */
update_bb_profile_for_threading (region[i], entry_count, e);
eliminated_edge = NULL;
}
else
region[i]->count -= region_copy[i]->count;
if (invariant_exits->contains (exit_e))
{
invariant_exits->remove (exit_e);
/* All exits will happen in exit_e_copy which is out of the
loop, so increase probability accordingly.
If the edge is eliminated_edge we already corrected
profile above. */
if (entry_count.nonzero_p () && eliminated_edge != exit_e)
set_edge_probability_and_rescale_others
(exit_e_copy, exit_e_count.probability_in
(entry_count));
/* Eliminate in-loop conditional. */
e->probability = profile_probability::always ();
exit_e->probability = profile_probability::never ();
gcond *cond_stmt = as_a <gcond *>(*gsi_last_bb (region[i]));
if (e->flags & EDGE_TRUE_VALUE)
gimple_cond_make_true (cond_stmt);
else
gimple_cond_make_false (cond_stmt);
update_stmt (cond_stmt);
}
entry_count = e_copy->count ();
}
/* Be sure that we seen all edges we are supposed to update. */
gcc_checking_assert (!eliminated_edge
&& invariant_exits->is_empty ());
}

namespace {

/* Common superclass for both header-copying phases. */
Expand Down Expand Up @@ -593,14 +715,17 @@ ch_base::copy_headers (function *fun)
entry = loop_preheader_edge (loop);

propagate_threaded_block_debug_into (exit->dest, entry->dest);
if (!gimple_duplicate_sese_region (entry, exit, bbs, n_bbs, copied_bbs,
true, candidate.static_exit,
&invariant_exits))
if (!gimple_duplicate_seme_region (entry, exit, bbs, n_bbs, copied_bbs,
true))
{
if (dump_file && (dump_flags & TDF_DETAILS))
fprintf (dump_file, "Duplication failed.\n");
continue;
}
if (loop->header->count.initialized_p ())
update_profile_after_ch (loop, bbs, copied_bbs, n_bbs,
candidate.static_exit, &invariant_exits,
entry_count);
copied.safe_push (std::make_pair (entry, loop));

/* If the loop has the form "for (i = j; i < j + 10; i++)" then
Expand Down

0 comments on commit 7df810d

Please sign in to comment.