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] (v2) Fix PR 40445: C++ ICE when using __builtin_unreachable() as only statement in a function.


The test case for this PR reveals two problems.

The first and the cause of the initial ICE is that get_last_bb_insn() would return an insn from a different basic block if an empty block followed the block in question. We would then ICE when rtl_delete_block tried to delete an insn that was not part of the block.

To fix this issue, I create a new function, next_nonnote_insn_bb(), and use it instead of next_nonnote_insn() in get_last_bb_insn().

Fixing that led to the case where all basic blocks and edges were being removed. There are many places in the RTL optimizers that assume the ENTRY_BLOCK will have a successor. With the test case, it did not.

The fix for this second problem is to revisit the patch that removes empty blocks with no successors:

http://gcc.gnu.org/ml/gcc-patches/2009-06/msg00912.html

We refine the criteria a little and only remove such blocks that are not the successor of the ENTRY_BLOCK.

As part of looking at all this, I also found that we were missing a 'continue' after removing empty fallthrough blocks. I added it so that all the checks will be done for blocks following the removed empty fallthrough block.


Tested by bootstrapping on x86_64-pc-linux-gnu all default languages (both -m32 and -m64) with no regressions found.


OK to commit?

gcc/
2009-06-25  David Daney  <ddaney@caviumnetworks.com>

	PR rtl-optimization/40445
	* emit-rtl.c (next_nonnote_insn_bb): New function.
	* rtl.h (next_nonnote_insn_bb): Declare new function.
	* cfgcleanup.c (try_optimize_cfg): Don't remove an empty block
	with no successors that is the successor of the ENTRY_BLOCK.
	Continue from the top after removing an empty fallthrough block.
	* cfgrtl.c (get_last_bb_insn): Call next_nonnote_insn_bb instead
	of next_nonnote_insn.

gcc/testsuite
2009-06-25  David Daney  <ddaney@caviumnetworks.com>

	PR rtl-optimization/40445
	* g++.dg/other/builtin-unreachable-1.C: New testcase.
Index: gcc/testsuite/g++.dg/other/builtin-unreachable-1.C
===================================================================
--- gcc/testsuite/g++.dg/other/builtin-unreachable-1.C	(revision 0)
+++ gcc/testsuite/g++.dg/other/builtin-unreachable-1.C	(revision 0)
@@ -0,0 +1,11 @@
+// PR c++/40445
+// Check that a function containing only __builtin_unreachable()
+// doesn't ICE.
+
+// { dg-do compile }
+// { dg-options "-O0" }
+const char *
+f (void)
+{
+  __builtin_unreachable ();
+}
Index: gcc/emit-rtl.c
===================================================================
--- gcc/emit-rtl.c	(revision 148867)
+++ gcc/emit-rtl.c	(working copy)
@@ -3044,6 +3044,25 @@ next_nonnote_insn (rtx insn)
   return insn;
 }
 
+/* Return the next insn after INSN that is not a NOTE, but stop the
+   search before we enter another basic block.  This routine does not
+   look inside SEQUENCEs.  */
+
+rtx
+next_nonnote_insn_bb (rtx insn)
+{
+  while (insn)
+    {
+      insn = NEXT_INSN (insn);
+      if (insn == 0 || !NOTE_P (insn))
+	break;
+      if (NOTE_INSN_BASIC_BLOCK_P (insn))
+	return NULL_RTX;
+    }
+
+  return insn;
+}
+
 /* Return the previous insn before INSN that is not a NOTE.  This routine does
    not look inside SEQUENCEs.  */
 
Index: gcc/cfgcleanup.c
===================================================================
--- gcc/cfgcleanup.c	(revision 148867)
+++ gcc/cfgcleanup.c	(working copy)
@@ -1841,10 +1841,16 @@ try_optimize_cfg (int mode)
 
 	      /* Delete trivially dead basic blocks.  This is either
 		 blocks with no predecessors, or empty blocks with no
-		 successors.  Empty blocks may result from expanding
+		 successors.  However if the empty block with no
+		 successors is the successor of the ENTRY_BLOCK, it is
+		 kept.  This ensures that the ENTRY_BLOCK will have a
+		 successor which is a precondition for many RTL
+		 passes.  Empty blocks may result from expanding
 		 __builtin_unreachable ().  */
 	      if (EDGE_COUNT (b->preds) == 0
-		  || (EDGE_COUNT (b->succs) == 0 && BB_HEAD (b) == BB_END (b)))
+		  || (EDGE_COUNT (b->succs) == 0
+		      && BB_HEAD (b) == BB_END (b)
+		      && single_succ_edge (ENTRY_BLOCK_PTR)->dest != b))
 		{
 		  c = b->prev_bb;
 		  if (dump_file)
@@ -1916,6 +1922,7 @@ try_optimize_cfg (int mode)
 		  delete_basic_block (b);
 		  changed = true;
 		  b = c;
+		  continue;
 		}
 
 	      if (single_succ_p (b)
Index: gcc/rtl.h
===================================================================
--- gcc/rtl.h	(revision 148867)
+++ gcc/rtl.h	(working copy)
@@ -1626,6 +1626,7 @@ extern rtx previous_insn (rtx);
 extern rtx next_insn (rtx);
 extern rtx prev_nonnote_insn (rtx);
 extern rtx next_nonnote_insn (rtx);
+extern rtx next_nonnote_insn_bb (rtx);
 extern rtx prev_real_insn (rtx);
 extern rtx next_real_insn (rtx);
 extern rtx prev_active_insn (rtx);
Index: gcc/cfgrtl.c
===================================================================
--- gcc/cfgrtl.c	(revision 148867)
+++ gcc/cfgrtl.c	(working copy)
@@ -1712,11 +1712,11 @@ get_last_bb_insn (basic_block bb)
     end = tmp;
 
   /* Include any barriers that may follow the basic block.  */
-  tmp = next_nonnote_insn (end);
+  tmp = next_nonnote_insn_bb (end);
   while (tmp && BARRIER_P (tmp))
     {
       end = tmp;
-      tmp = next_nonnote_insn (end);
+      tmp = next_nonnote_insn_bb (end);
     }
 
   return end;

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