This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[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


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]