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] Fix PR rtl-optimization/17027


Hi,

This is an ICE at -O2 on the SPARC, a regression present on the 3.4 branch 
only.  The testcase is somewhat pathological:

void baz (void)  __attribute__ ((noreturn)); /* noreturn is required */

void foo (void) 
{
  while (bar ()) {
    switch (1) {
      default:
      baz ();
    }
  }
} 

Before the BB reordering pass, the CFG is made up of 3 BBs: the successor of 
ENTRY_BLOCK, the block falling through to EXIT_BLOCK and a block containing 
the call to baz (so with no successor).

At the beginning of the pass, the first two blocks are merged, leading to a 
block both successor of ENTRY_BLOCK and falling through to EXIT_BLOCK.  So 
when fixup_fallthru_exit_predecessor is invoked, it ICEs because it can't 
reorder the blocks as it is meant to:

 /* The block falling through to exit must be the last one in the
    reordered chain.  Ensure that this condition is met.  */
 static void
 fixup_fallthru_exit_predecessor (void)

On the 3.4 branch, this only occurs on targets without RTL prologue/epilogue 
because the epilogue creates a new block falling through to EXIT_BLOCK that 
is not merged.  On the mainline, this can't occur anymore since 
fixup_fallthru_exit_predecessor invokes split_block when necessary.

I've attached two fixes: the first one prevents the merging from happening, 
the second one is a backport from mainline of the bits needed in order to 
split the block (extracted from 2 bigger patches).  Both were 
bootstrapped/regtested on sparc64-sun-solaris2.9 and sparc-sun-solaris2.8.


2004-10-05  Eric Botcazou  <ebotcazou@libertysurf.fr>

	* cfglayout.c (fallthru_exit_predecessor): New function extracted from...
	(fixup_fallthru_exit_predecessor)...here.
	* cfglayout.h (fallthru_exit_predecessor): Declare it.
	* cfgrtl.c (cfg_layout_can_merge_blocks_p): Use it.  If the target doesn't
	have RTL epilogue, prevent two blocks from being merged if the result would
	be both the successor of the entry and the block falling through to exit and
	there are at least 3 blocks.


2004-10-05  Eric Botcazou  <ebotcazou@libertysurf.fr>

	Backport from mainline:
	* cfglayout.c (fixup_fallthru_exit_predecessor): If the first block falls
 	through to exit, split it.
	* cfgrtl.c (rtl_split_block): If no insn is specified, split on the first
	insn in the basic block.


2004-10-05  Christian Ehrhardt  <ehrhardt@mathematik.uni-ulm.de>

	* gcc.c-torture/compile/20041005-1.c: New test.


-- 
Eric Botcazou
Index: cfglayout.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cfglayout.c,v
retrieving revision 1.50.4.1
diff -c -p -r1.50.4.1 cfglayout.c
*** cfglayout.c	26 Jul 2004 14:42:10 -0000	1.50.4.1
--- cfglayout.c	3 Oct 2004 18:07:25 -0000
*************** verify_insn_chain (void)
*** 849,865 ****
      abort ();
  }
  
! /* The block falling through to exit must be the last one in the
!    reordered chain.  Ensure that this condition is met.  */
! static void
! fixup_fallthru_exit_predecessor (void)
  {
    edge e;
-   basic_block bb = NULL;
  
    for (e = EXIT_BLOCK_PTR->pred; e; e = e->pred_next)
      if (e->flags & EDGE_FALLTHRU)
!       bb = e->src;
  
    if (bb && bb->rbi->next)
      {
--- 849,873 ----
      abort ();
  }
  
! /* Return the block falling through to exit if it exists.  */
! basic_block
! fallthru_exit_predecessor (void)
  {
    edge e;
  
    for (e = EXIT_BLOCK_PTR->pred; e; e = e->pred_next)
      if (e->flags & EDGE_FALLTHRU)
!       return e->src;
! 
!   return NULL;
! }
! 
! /* The block falling through to exit must be the last one in the
!    reordered chain.  Ensure that this condition is met.  */
! static void
! fixup_fallthru_exit_predecessor (void)
! {
!   basic_block bb = fallthru_exit_predecessor ();
  
    if (bb && bb->rbi->next)
      {
Index: cfglayout.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cfglayout.h,v
retrieving revision 1.10.4.1
diff -c -p -r1.10.4.1 cfglayout.h
*** cfglayout.h	26 Jul 2004 14:42:10 -0000	1.10.4.1
--- cfglayout.h	3 Oct 2004 18:07:25 -0000
*************** extern void cfg_layout_initialize (unsig
*** 39,44 ****
--- 39,45 ----
  extern void cfg_layout_finalize (void);
  extern bool cfg_layout_can_duplicate_bb_p (basic_block);
  extern basic_block cfg_layout_duplicate_bb (basic_block, edge);
+ extern basic_block fallthru_exit_predecessor (void);
  extern void insn_locators_initialize (void);
  extern void reemit_insn_block_notes (void);
  extern bool can_copy_bbs_p (basic_block *, unsigned);
Index: cfgrtl.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cfgrtl.c,v
retrieving revision 1.103.2.5
diff -c -p -r1.103.2.5 cfgrtl.c
*** cfgrtl.c	11 Aug 2004 20:05:05 -0000	1.103.2.5
--- cfgrtl.c	3 Oct 2004 18:07:30 -0000
*************** cfg_layout_can_merge_blocks_p (basic_blo
*** 2602,2608 ****
--- 2602,2619 ----
  	  && !b->pred->pred_next && a != b
  	  /* Must be simple edge.  */
  	  && !(a->succ->flags & EDGE_COMPLEX)
+ 	  /* Obvious case to be rejected.  */
  	  && a != ENTRY_BLOCK_PTR && b != EXIT_BLOCK_PTR
+ 	  /* Less obvious case to be rejected: if we don't have epilogue,
+ 	     we must always be able to put the block falling through to
+ 	     exit at the end of the chain.  */
+ 	  && (
+ #ifdef HAVE_epilogue
+ 	      HAVE_epilogue ||
+ #endif
+ 			       ! (a == ENTRY_BLOCK_PTR->next_bb
+ 				  && b == fallthru_exit_predecessor ()
+ 				  && n_basic_blocks > 2))
  	  /* If the jump insn has side effects,
  	     we can't kill the edge.  */
  	  && (GET_CODE (BB_END (a)) != JUMP_INSN
Index: cfglayout.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cfglayout.c,v
retrieving revision 1.50.4.1
diff -u -p -r1.50.4.1 cfglayout.c
--- cfglayout.c	26 Jul 2004 14:42:10 -0000	1.50.4.1
+++ cfglayout.c	4 Oct 2004 21:50:22 -0000
@@ -865,6 +865,18 @@ fixup_fallthru_exit_predecessor (void)
     {
       basic_block c = ENTRY_BLOCK_PTR->next_bb;
 
+      /* If the very first block is the one with the fall-through exit
+	 edge, we have to split that block.  */
+      if (c == bb)
+	{
+	  bb = split_block (bb, NULL)->dest;
+	  cfg_layout_initialize_rbi (bb);
+	  bb->rbi->next = c->rbi->next;
+	  c->rbi->next = bb;
+	  bb->rbi->footer = c->rbi->footer;
+	  c->rbi->footer = NULL;
+	}
+
       while (c->rbi->next != bb)
 	c = c->rbi->next;
 
Index: cfgrtl.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cfgrtl.c,v
retrieving revision 1.103.2.5
diff -u -p -r1.103.2.5 cfgrtl.c
--- cfgrtl.c	11 Aug 2004 20:05:05 -0000	1.103.2.5
+++ cfgrtl.c	4 Oct 2004 21:50:27 -0000
@@ -483,9 +483,21 @@ rtl_split_block (basic_block bb, void *i
   edge e;
   rtx insn = insnp;
 
-  /* There is no point splitting the block after its end.  */
-  if (BB_END (bb) == insn)
-    return 0;
+  if (!insn)
+    {
+      insn = first_insn_after_basic_block_note (bb);
+
+      if (insn)
+	insn = PREV_INSN (insn);
+      else
+	insn = get_last_insn ();
+    }
+
+  /* We probably should check type of the insn so that we do not create
+     inconsistent cfg.  It is checked in verify_flow_info anyway, so do not
+     bother.  */
+  if (insn == BB_END (bb))
+    emit_note_after (NOTE_INSN_DELETED, insn);
 
   /* Create the new basic block.  */
   new_bb = create_basic_block (NEXT_INSN (insn), BB_END (bb), bb);
/* PR rtl-optimization/17027 */
/* Origin: dbk <sfc@village.uunet.be> */
/* Testcase by Christian Ehrhardt <ehrhardt@mathematik.uni-ulm.de> */

int bar(void);
void baz (void)  __attribute__ ((noreturn)); /* noreturn is required */

void foo (void) 
{
  while (bar ()) {
    switch (1) {
      default:
      baz ();
    }
  }
} 

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