This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
[PATCH] Another fix for PR54838
- From: Marek Polacek <polacek at redhat dot com>
- To: GCC Patches <gcc-patches at gcc dot gnu dot org>
- Date: Mon, 17 Dec 2012 01:21:57 +0100
- Subject: [PATCH] Another fix for PR54838
Here's a fix for the C++ TC part of this PR. The issue was
that we had a loop with header and two latches, and via delete_basic_block
we deleted both latches, but we weren't removing the loop properly.
This ICEd later on because in merge_latch_edges there's an assert:
gcc_assert (latches.length () > 0);
[Unfortunately this still not fixes profiledbootstrap with ada
mentioned in the PR (it seems to be a different issue, namely something
in cleanup_cfg in .into_cfglayout: we have a loop consisting of one
BB--its outcoming edge is at the same time its incoming edge--and we
remove this edge, but this "loop" is not removed). The interim
workaround is to filter-out -fprofile-generate switch on targparm.o
in gcc/ada/gcc-interface/Make-lang.in. I hope I will fix this one
during this week.]
Fixed thusly, bootstrapped/regtested on x86_64-linux, ok for trunk?
2012-12-15 Marek Polacek <polacek@redhat.com>
PR middle-end/54838
* cfghooks.c (delete_basic_block): Remove loop if all the
latches are gone.
* cfgcleanup.c (delete_unreachable_blocks): Call
mark_dfs_back_edges.
* g++.dg/pr54838.C: New test.
--- gcc/cfghooks.c.mp 2012-12-15 04:03:18.388050403 +0100
+++ gcc/cfghooks.c 2012-12-15 04:03:35.313102810 +0100
@@ -541,11 +541,31 @@ delete_basic_block (basic_block bb)
if (current_loops != NULL)
{
struct loop *loop = bb->loop_father;
+ bool is_last_latch = false;
+
+ /* We can get into situation where we have multiple latches. We
+ have to cancel the loop, if we remove all the latches--then
+ the header won't have any incoming back edges. */
+ if (loop->header
+ && bb->loop_father != current_loops->tree_root)
+ {
+ edge e;
+ edge_iterator ei;
+ unsigned int n_back_edges = 0;
+ /* Check whether there's only one latch edge... */
+ FOR_EACH_EDGE (e, ei, loop->header->preds)
+ if (e->flags & EDGE_DFS_BACK)
+ n_back_edges++;
+ /* ... and whether we're deleting its latch. */
+ is_last_latch = n_back_edges == 1
+ && find_edge (bb, loop->header);
+ }
/* If we remove the header or the latch of a loop, mark the loop for
removal by setting its header and latch to NULL. */
if (loop->latch == bb
- || loop->header == bb)
+ || loop->header == bb
+ || is_last_latch)
{
loop->header = NULL;
loop->latch = NULL;
--- gcc/testsuite/g++.dg/pr54838.C.mp 2012-12-15 03:52:52.436371725 +0100
+++ gcc/testsuite/g++.dg/pr54838.C 2012-12-15 03:52:36.962330626 +0100
@@ -0,0 +1,117 @@
+// PR middle-end/54838
+// { dg-do compile }
+// { dg-options "-O2 -ftracer -fno-tree-dce -fno-tree-sra" }
+
+ struct bidirectional_iterator_tag
+ {};
+ struct random_access_iterator_tag:bidirectional_iterator_tag
+ {};
+ template < typename _Category, typename, typename _Distance, typename > struct iterator
+ {
+ typedef _Distance difference_type;
+ };
+ template < typename _Iterator > struct iterator_traits
+ {
+ typedef typename _Iterator::difference_type difference_type;
+ };
+ template < typename _Tp > struct iterator_traits <_Tp * >
+ {
+ typedef random_access_iterator_tag iterator_category;
+ typedef _Tp value_type;
+ typedef int difference_type;
+ typedef _Tp reference;
+ };
+template < typename _Iterator > class reverse_iterator:
+ public
+ iterator
+ <
+ typename
+ iterator_traits
+ <
+ _Iterator
+ >::iterator_category,
+ typename
+ iterator_traits
+ <
+ _Iterator
+ >::value_type,
+ typename
+ iterator_traits
+ <
+ _Iterator
+ >::difference_type, typename iterator_traits < _Iterator >::reference >
+ {
+ _Iterator current;
+ public:
+ typedef _Iterator iterator_type;
+ reverse_iterator (const reverse_iterator & __x):current (__x.current)
+ {}
+ iterator_type base ()
+ {
+ return current;
+ }
+ reverse_iterator operator++ ()
+ {
+ --current;
+ }
+ };
+ template
+ <
+ typename
+ _Iterator
+ >
+ bool
+ operator
+ ==
+ (reverse_iterator < _Iterator > __x, reverse_iterator < _Iterator > __y)
+ {
+ return __x.base () == __y.base ();
+ }
+
+ template
+ <
+ typename
+ _Iterator
+ >
+ typename
+ reverse_iterator
+ <
+ _Iterator
+ >::difference_type
+ operator
+ - (reverse_iterator < _Iterator >, reverse_iterator < _Iterator >)
+ {}
+ template
+ <
+ typename
+ _RandomAccessIterator
+ >
+ _RandomAccessIterator
+ __find
+ (_RandomAccessIterator
+ __first, _RandomAccessIterator __last)
+ {
+ typename
+ iterator_traits
+ <
+ _RandomAccessIterator
+ >::difference_type __trip_count (__last - __first);
+ for (; __trip_count; --__trip_count)
+++__first;
+ return __last;
+ }
+ typedef reverse_iterator < int* > _ForwardIterator1;
+ _ForwardIterator1
+ search
+ (_ForwardIterator1
+ __first1,
+ _ForwardIterator1
+ __last1)
+ {
+ for (;;)
+ {
+ __first1 = __find (__first1, __last1);
+ if (__first1 == __last1)
+ return __last1;
+ }
+ }
--- gcc/cfgcleanup.c.mp 2012-12-15 04:03:24.144068226 +0100
+++ gcc/cfgcleanup.c 2012-12-15 04:03:35.313102810 +0100
@@ -2836,6 +2836,7 @@ delete_unreachable_blocks (void)
bool changed = false;
basic_block b, prev_bb;
+ mark_dfs_back_edges ();
find_unreachable_blocks ();
/* When we're in GIMPLE mode and there may be debug insns, we should
Marek