aboutsummaryrefslogtreecommitdiff
path: root/gcc/tree-cfgcleanup.c
diff options
context:
space:
mode:
authorRichard Biener <rguenther@suse.de>2017-05-02 11:24:52 +0000
committerRichard Biener <rguenth@gcc.gnu.org>2017-05-02 11:24:52 +0000
commite7d70c6c3bccb2a1abed2683d436423cc5484704 (patch)
treee56c29c23fc33760f44125bb7e3dfbcb3cb8fffa /gcc/tree-cfgcleanup.c
parent51956afe2766a248dc0c876f4140d7a79009cf5a (diff)
downloadgcc-e7d70c6c3bccb2a1abed2683d436423cc5484704.zip
gcc-e7d70c6c3bccb2a1abed2683d436423cc5484704.tar.gz
gcc-e7d70c6c3bccb2a1abed2683d436423cc5484704.tar.bz2
re PR tree-optimization/80549 (wrong code at -O2 and -O3 in both 32-bit and 64-bit modes on x86_64-linux-gnu (executable does not terminate))
2017-05-02 Richard Biener <rguenther@suse.de> PR tree-optimization/80549 * tree-cfgcleanup.c (mfb_keep_latches): New helper. (cleanup_tree_cfg_noloop): Create forwarders to known loop headers if they do not have a preheader. * gcc.dg/torture/pr80549.c: New testcase. From-SVN: r247486
Diffstat (limited to 'gcc/tree-cfgcleanup.c')
-rw-r--r--gcc/tree-cfgcleanup.c63
1 files changed, 63 insertions, 0 deletions
diff --git a/gcc/tree-cfgcleanup.c b/gcc/tree-cfgcleanup.c
index 7eb7172..94a172f 100644
--- a/gcc/tree-cfgcleanup.c
+++ b/gcc/tree-cfgcleanup.c
@@ -739,6 +739,11 @@ cleanup_tree_cfg_1 (void)
return retval;
}
+static bool
+mfb_keep_latches (edge e)
+{
+ return ! dominated_by_p (CDI_DOMINATORS, e->src, e->dest);
+}
/* Remove unreachable blocks and other miscellaneous clean up work.
Return true if the flowgraph was modified, false otherwise. */
@@ -766,6 +771,64 @@ cleanup_tree_cfg_noloop (void)
changed = false;
}
+ /* Ensure that we have single entries into loop headers. Otherwise
+ if one of the entries is becoming a latch due to CFG cleanup
+ (from formerly being part of an irreducible region) then we mess
+ up loop fixup and associate the old loop with a different region
+ which makes niter upper bounds invalid. See for example PR80549.
+ This needs to be done before we remove trivially dead edges as
+ we need to capture the dominance state before the pending transform. */
+ if (current_loops)
+ {
+ loop_p loop;
+ unsigned i;
+ FOR_EACH_VEC_ELT (*get_loops (cfun), i, loop)
+ if (loop && loop->header)
+ {
+ basic_block bb = loop->header;
+ edge_iterator ei;
+ edge e;
+ bool found_latch = false;
+ bool any_abnormal = false;
+ unsigned n = 0;
+ /* We are only interested in preserving existing loops, but
+ we need to check whether they are still real and of course
+ if we need to add a preheader at all. */
+ FOR_EACH_EDGE (e, ei, bb->preds)
+ {
+ if (e->flags & EDGE_ABNORMAL)
+ {
+ any_abnormal = true;
+ break;
+ }
+ if (dominated_by_p (CDI_DOMINATORS, e->src, bb))
+ {
+ found_latch = true;
+ continue;
+ }
+ n++;
+ }
+ /* If we have more than one entry to the loop header
+ create a forwarder. */
+ if (found_latch && ! any_abnormal && n > 1)
+ {
+ edge fallthru = make_forwarder_block (bb, mfb_keep_latches,
+ NULL);
+ loop->header = fallthru->dest;
+ if (! loops_state_satisfies_p (LOOPS_NEED_FIXUP))
+ {
+ /* The loop updating from the CFG hook is incomplete
+ when we have multiple latches, fixup manually. */
+ remove_bb_from_loops (fallthru->src);
+ loop_p cloop = loop;
+ FOR_EACH_EDGE (e, ei, fallthru->src->preds)
+ cloop = find_common_loop (cloop, e->src->loop_father);
+ add_bb_to_loop (fallthru->src, cloop);
+ }
+ }
+ }
+ }
+
changed |= cleanup_tree_cfg_1 ();
gcc_assert (dom_info_available_p (CDI_DOMINATORS));