This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
Do not merge blocks when profile would be lost
- From: Jan Hubicka <hubicka at ucw dot cz>
- To: gcc-patches at gcc dot gnu dot org
- Date: Mon, 3 Jul 2017 12:40:53 +0200
- Subject: Do not merge blocks when profile would be lost
- Authentication-results: sourceware.org; auth=none
Hi,
consider function
test ()
{
do_something_that_will_call_exit ();
report_catastrophic_failure ();
}
No while profile estimation we know that do_something_that_will_call_exit may
end execution and thus split BBs and introduce fake edges. After fake edges
are removed we however merge BBs and in htat case report_catastrophic_failure
gets non-zero profile.
Theresa added code to drop poroflies when sum of counts is non-zero and we also
keep preporting profile inconsistencies. The following patch fixes it by not
merging the BBs during the tree optimization. After RTL expansion we merge them
but I think that is quite OK.
Bootstrapped/regtested x86_64-linux, plan to commit it later today.
Honza
* tree-cfgcleanup.c (want_merge_blocks_p): New function.
(cleanup_tree_cfg_bb): Use it.
* profile-count.h (profile_count::of_for_merging, profile_count::merge):
New functions.
* tree-cfg.c (gimple_merge_blocks): Use profile_count::merge.
Index: tree-cfgcleanup.c
===================================================================
--- tree-cfgcleanup.c (revision 249885)
+++ tree-cfgcleanup.c (working copy)
@@ -636,6 +636,19 @@ fixup_noreturn_call (gimple *stmt)
return changed;
}
+/* Return true if we want to merge BB1 and BB2 into a single block. */
+
+static bool
+want_merge_blocks_p (basic_block bb1, basic_block bb2)
+{
+ if (!can_merge_blocks_p (bb1, bb2))
+ return false;
+ gimple_stmt_iterator gsi = gsi_last_nondebug_bb (bb1);
+ if (gsi_end_p (gsi) || !stmt_can_terminate_bb_p (gsi_stmt (gsi)))
+ return true;
+ return bb1->count.ok_for_merging (bb2->count);
+}
+
/* Tries to cleanup cfg in basic block BB. Returns true if anything
changes. */
@@ -652,7 +665,7 @@ cleanup_tree_cfg_bb (basic_block bb)
This happens when we visit BBs in a non-optimal order and
avoids quadratic behavior with adjusting stmts BB pointer. */
if (single_pred_p (bb)
- && can_merge_blocks_p (single_pred (bb), bb))
+ && want_merge_blocks_p (single_pred (bb), bb))
/* But make sure we _do_ visit it. When we remove unreachable paths
ending in a backedge we fail to mark the destinations predecessors
as changed. */
@@ -662,7 +675,7 @@ cleanup_tree_cfg_bb (basic_block bb)
conditional branches (due to the elimination of single-valued PHI
nodes). */
else if (single_succ_p (bb)
- && can_merge_blocks_p (bb, single_succ (bb)))
+ && want_merge_blocks_p (bb, single_succ (bb)))
{
merge_blocks (bb, single_succ (bb));
return true;
Index: profile-count.h
===================================================================
--- profile-count.h (revision 249885)
+++ profile-count.h (working copy)
@@ -565,6 +565,31 @@ public:
return initialized_p ();
}
+ /* When merging basic blocks, the two different profile counts are unified.
+ Return true if this can be done without losing info about profile.
+ The only case we care about here is when first BB contains something
+ that makes it terminate in a way not visible in CFG. */
+ bool ok_for_merging (profile_count other) const
+ {
+ if (m_quality < profile_adjusted
+ || other.m_quality < profile_adjusted)
+ return true;
+ return !(other < *this);
+ }
+
+ /* When merging two BBs with different counts, pick common count that looks
+ most representative. */
+ profile_count merge (profile_count other) const
+ {
+ if (*this == other || !other.initialized_p ()
+ || m_quality > other.m_quality)
+ return *this;
+ if (other.m_quality > m_quality
+ || other > *this)
+ return other;
+ return *this;
+ }
+
/* Basic operations. */
bool operator== (const profile_count &other) const
{
Index: tree-cfg.c
===================================================================
--- tree-cfg.c (revision 249887)
+++ tree-cfg.c (working copy)
@@ -2076,7 +2081,7 @@ gimple_merge_blocks (basic_block a, basi
profiles. */
if (a->loop_father == b->loop_father)
{
- a->count = MAX (a->count, b->count);
+ a->count = a->count.merge (b->count);
a->frequency = MAX (a->frequency, b->frequency);
}