diff options
author | Richard Biener <rguenther@suse.de> | 2017-05-02 11:24:52 +0000 |
---|---|---|
committer | Richard Biener <rguenth@gcc.gnu.org> | 2017-05-02 11:24:52 +0000 |
commit | e7d70c6c3bccb2a1abed2683d436423cc5484704 (patch) | |
tree | e56c29c23fc33760f44125bb7e3dfbcb3cb8fffa /gcc/tree-cfgcleanup.c | |
parent | 51956afe2766a248dc0c876f4140d7a79009cf5a (diff) | |
download | gcc-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.c | 63 |
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)); |