Patchwork Fix ICE on dangling unreachable block

login
register
mail settings
Submitter Eric Botcazou
Date Oct. 24, 2010, 8:45 p.m.
Message ID <201010242245.45305.ebotcazou@adacore.com>
Download mbox | patch
Permalink /patch/69052/
State New
Headers show

Comments

Eric Botcazou - Oct. 24, 2010, 8:45 p.m.
This is a regression present on the mainline and 4.5 branch: the attached 
testcase yields an ICE in pre_and_rev_post_order_compute when compiled 
at -Os -g on the x86.  It's the assertion verifying that all the blocks have 
been invisited by the DFS algorithm:

    /* The number of nodes visited should be the number of blocks minus
       the entry and exit blocks which are not visited here.  */
    gcc_assert (pre_order_num == n_basic_blocks - NUM_FIXED_BLOCKS);

This is a latent issue in reg-stack.c: it purges dead edges but doesn't clean 
up the CFG afterward.  Then pre_and_rev_post_order_compute is invoked from 
var-tracking.c and chokes.

Fixed by cleaning up the CFG at the end of the pass if edges have been purged.
Note that this should only affect the Ada and Java compilers.

Tested on i586-suse-linux, applied on the mainline and 4.5 branch.


2010-10-24  Eric Botcazou  <ebotcazou@adacore.com>

	* reg-stack.c (convert_regs_1): Return boolean value, true if the CFG
	has been modified.
	(convert_regs_2): Likewise.  Adjust calls to convert_regs_1.
	(convert_regs): Adjust calls to convert_regs_2.  Clean up the CFG if
	it has been modified.


2010-10-24  Eric Botcazou  <ebotcazou@adacore.com>

	* gnat.dg/opt7.ad[sb]: New test.
	* gnat.dg/opt7_pkg.ads: New helper.

Patch

Index: reg-stack.c
===================================================================
--- reg-stack.c	(revision 165881)
+++ reg-stack.c	(working copy)
@@ -2876,9 +2876,10 @@  better_edge (edge e1, edge e2)
   return (e1->src->index < e2->src->index) ? e1 : e2;
 }
 
-/* Convert stack register references in one block.  */
+/* Convert stack register references in one block.  Return true if the CFG
+   has been modified in the process.  */
 
-static void
+static bool
 convert_regs_1 (basic_block block)
 {
   struct stack_def regstack;
@@ -2886,6 +2887,7 @@  convert_regs_1 (basic_block block)
   int reg;
   rtx insn, next;
   bool control_flow_insn_deleted = false;
+  bool cfg_altered = false;
   int debug_insns_with_starting_stack = 0;
 
   any_malformed_asm = false;
@@ -3041,7 +3043,7 @@  convert_regs_1 (basic_block block)
      place, still, but we don't have enough information at that time.  */
 
   if (control_flow_insn_deleted)
-    purge_dead_edges (block);
+    cfg_altered |= purge_dead_edges (block);
 
   /* Something failed if the stack lives don't match.  If we had malformed
      asms, we zapped the instruction itself, but that didn't produce the
@@ -3051,14 +3053,18 @@  convert_regs_1 (basic_block block)
 	      || any_malformed_asm);
   bi->stack_out = regstack;
   bi->done = true;
+
+  return cfg_altered;
 }
 
-/* Convert registers in all blocks reachable from BLOCK.  */
+/* Convert registers in all blocks reachable from BLOCK.  Return true if the
+   CFG has been modified in the process.  */
 
-static void
+static bool
 convert_regs_2 (basic_block block)
 {
   basic_block *stack, *sp;
+  bool cfg_altered = false;
 
   /* We process the blocks in a top-down manner, in a way such that one block
      is only processed after all its predecessors.  The number of predecessors
@@ -3097,11 +3103,13 @@  convert_regs_2 (basic_block block)
 	      *sp++ = e->dest;
 	  }
 
-      convert_regs_1 (block);
+      cfg_altered |= convert_regs_1 (block);
     }
   while (sp != stack);
 
   free (stack);
+
+  return cfg_altered;
 }
 
 /* Traverse all basic blocks in a function, converting the register
@@ -3111,6 +3119,7 @@  convert_regs_2 (basic_block block)
 static void
 convert_regs (void)
 {
+  bool cfg_altered = false;
   int inserted;
   basic_block b;
   edge e;
@@ -3129,7 +3138,7 @@  convert_regs (void)
 
   /* Process all blocks reachable from all entry points.  */
   FOR_EACH_EDGE (e, ei, ENTRY_BLOCK_PTR->succs)
-    convert_regs_2 (e->dest);
+    cfg_altered |= convert_regs_2 (e->dest);
 
   /* ??? Process all unreachable blocks.  Though there's no excuse
      for keeping these even when not optimizing.  */
@@ -3138,7 +3147,7 @@  convert_regs (void)
       block_info bi = BLOCK_INFO (b);
 
       if (! bi->done)
-	convert_regs_2 (b);
+	cfg_altered |= convert_regs_2 (b);
     }
 
   inserted |= compensate_edges ();
@@ -3149,6 +3158,9 @@  convert_regs (void)
   if (inserted)
     commit_edge_insertions ();
 
+  if (cfg_altered)
+    cleanup_cfg (0);
+
   if (dump_file)
     fputc ('\n', dump_file);
 }