+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.
{
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
print_stack (file, ®stack);
}
subst_stack_regs (insn, ®stack);
+ deleted |= (GET_CODE (insn) == NOTE || INSN_DELETED_P (insn));
}
}
while (next);
nan);
insn = emit_insn_after (set, insn);
subst_stack_regs (insn, ®stack);
+ 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
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;
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))
{
if (!BLOCK_INFO (e->dest)->predecessors)
*sp++ = e->dest;
}
+
+ inserted |= convert_regs_1 (file, block);
+ BLOCK_INFO (block)->done = 1;
}
while (sp != stack);
--- /dev/null
+// 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()) {}