re PR target/9786 (Ice in fixup_abnormal_edges with -fnon-call-exceptions -O2)
authorEric Botcazou <ebotcazou@gcc.gnu.org>
Mon, 22 Sep 2003 06:59:51 +0000 (06:59 +0000)
committerEric Botcazou <ebotcazou@gcc.gnu.org>
Mon, 22 Sep 2003 06:59:51 +0000 (06:59 +0000)
PR target/9786
* reg-stack.c (convert_regs_1): Purge possible dead eh edges
after potential deletion of trapping insn. Avoids later ICE
from call to fixup_abnormal_edges.
(convert_regs_2): Stack the current block successors before
processing this block, that is, before the potential deletion of
dead edges by convert_regs_1, because these edges have been used
to initialize the predecessors count.

From-SVN: r71644

gcc/ChangeLog
gcc/reg-stack.c
gcc/testsuite/ChangeLog
gcc/testsuite/g++.dg/opt/reg-stack2.C [new file with mode: 0644]

index c171f9fa24ac1a5c6f03d60f75aff8c4636e6989..b66b5e43e19957bf3cdb1322512ad3b5194cc13f 100644 (file)
@@ -1,3 +1,14 @@
+2003-09-22  Olivier Hainque  <hainque@act-europe.fr>
+
+       PR target/9786
+       * reg-stack.c (convert_regs_1): Purge possible dead eh edges
+       after potential deletion of trapping insn. Avoids later ICE
+       from call to fixup_abnormal_edges.
+       (convert_regs_2): Stack the current block successors before
+       processing this block, that is, before the potential deletion of
+       dead edges by convert_regs_1, because these edges have been used
+       to initialize the predecessors count.
+
 2003-09-22  Eric Botcazou  <ebotcazou@libertysurf.fr>
 
        * real.c: Fix several nits in the head comment.
index fd707e21e8305c48330542ea8f8c86e2221334fd..f432cf1b54d273a86e95455aeee7df4ae3622a3a 100644 (file)
@@ -2638,11 +2638,12 @@ convert_regs_1 (FILE *file, basic_block block)
 {
   struct stack_def regstack;
   block_info bi = BLOCK_INFO (block);
-  int inserted, reg;
+  int deleted, inserted, reg;
   rtx insn, next;
   edge e, beste = NULL;
 
   inserted = 0;
+  deleted = 0;
   any_malformed_asm = false;
 
   /* Find the edge we will copy stack from.  It should be the most frequent
@@ -2715,6 +2716,7 @@ convert_regs_1 (FILE *file, basic_block block)
              print_stack (file, &regstack);
            }
          subst_stack_regs (insn, &regstack);
+         deleted |= (GET_CODE (insn) == NOTE || INSN_DELETED_P (insn));
        }
     }
   while (next);
@@ -2754,8 +2756,23 @@ convert_regs_1 (FILE *file, basic_block block)
                             nan);
          insn = emit_insn_after (set, insn);
          subst_stack_regs (insn, &regstack);
+         deleted |= (GET_CODE (insn) == NOTE || INSN_DELETED_P (insn));
        }
     }
+  
+  /* Amongst the insns possibly deleted during the substitution process above,
+     might have been the only trapping insn in the block.  We purge the now
+     possibly dead EH edges here to avoid an ICE from fixup_abnormal_edges,
+     called at the end of convert_regs.  The order in which we process the
+     blocks ensures that we never delete an already processed edge.
+
+     ??? We are normally supposed not to delete trapping insns, so we pretend
+     that the insns deleted above don't actually trap.  It would have been
+     better to detect this earlier and avoid creating the EH edge in the first
+     place, still, but we don't have enough information at that time.  */
+
+  if (deleted)
+    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
@@ -2800,6 +2817,10 @@ convert_regs_2 (FILE *file, basic_block block)
   basic_block *stack, *sp;
   int inserted;
 
+  /* 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
+     of every block has already been computed.  */ 
+
   stack = xmalloc (sizeof (*stack) * n_basic_blocks);
   sp = stack;
 
@@ -2811,9 +2832,13 @@ convert_regs_2 (FILE *file, basic_block block)
       edge e;
 
       block = *--sp;
-      inserted |= convert_regs_1 (file, block);
-      BLOCK_INFO (block)->done = 1;
 
+      /* Processing "block" is achieved by convert_regs_1, which may purge
+        some dead EH outgoing edge after the possible deletion of the
+        trapping insn inside the block.  Since the number of predecessors of
+        "block"'s successors has been computed based on the initial edge set,
+        we check for the possiblity to process some of these successors
+        before such an edge deletion may happen.  */
       for (e = block->succ; e ; e = e->succ_next)
        if (! (e->flags & EDGE_DFS_BACK))
          {
@@ -2821,6 +2846,9 @@ convert_regs_2 (FILE *file, basic_block block)
            if (!BLOCK_INFO (e->dest)->predecessors)
               *sp++ = e->dest;
          }
+
+      inserted |= convert_regs_1 (file, block);
+      BLOCK_INFO (block)->done = 1;
     }
   while (sp != stack);
 
index 11c7cff5343072a2745fb603af4f3fac50c7ec3e..5c9c984ed4560af3063fda86b4f691eaaa37511b 100644 (file)
@@ -1,3 +1,7 @@
+2003-09-22  Eric Botcazou  <ebotcazou@libertysurf.fr>
+
+       * g++.dg/opt/reg-stack2.C: New test.
+
 2003-09-21  Christian Ehrhardt  <ehrhardt@mathematik.uni-ulm.de>
 
        * g++.dg/eh/delayslot1.C: New test.
diff --git a/gcc/testsuite/g++.dg/opt/reg-stack2.C b/gcc/testsuite/g++.dg/opt/reg-stack2.C
new file mode 100644 (file)
index 0000000..08cd590
--- /dev/null
@@ -0,0 +1,34 @@
+// PR target/9786
+// Origin: <nick@ilm.com>
+
+// This used to fail on x86 because the reg-stack pass deleted
+// an insn that could seemingly trap (but actually doesn't)
+// without updating the CFG.
+
+// { dg-do compile }
+// { dg-options "-O2 -fnon-call-exceptions" }
+
+struct D1 {
+    float l;
+    D1 GS() const {D1 d;float f=.299*l;d.l=f;return d;}
+    static D1 G() {return D1();}
+};
+
+struct D2 {
+    D1 g;
+    D2(const D1& gi) : g(gi) {}
+    D2 GS() const {return D2(g.GS());}
+};
+
+class A {
+  public:
+    virtual ~A() {}
+};
+
+class B : public A {
+  public:
+    B(const D2& mi);
+    D2 fm;
+};
+
+B::B(const D2 &mi) : fm(mi.GS()) {}