ICE in fixup_abnormal_edges after deletion of trapping insn on x86
Olivier Hainque
hainque@act-europe.fr
Thu Jun 26 16:07:00 GMT 2003
Hello,
On x86, we hit an ICE from fixup_abnormal_edges, called from convert_regs.
The basic reason is that convert_regs has removed the (only) potentially
trapping insn in a basic block and left the corresponding abnormal edge
attached to the block. fixup_abnormal_edges scans this block up to the head
INSN_BASIC_BLOCK note and aborts.
I have a couple of ideas as to how this could be fixed, but would appreciate
some input from others first, as I may well be overlooking something.
Additional details on the problem and fix ideas follow.
Thanks in advance for your help.
Olivier
--
Upon entry in convert_regs, we have a bb like:
;; Basic block 2, loop depth 0, count 0
;; Registers live at start: 6 [bp] 7 [sp] 8 [st] 16 [] 20 [frame]
(note 86 17 18 2 [bb 2] NOTE_INSN_BASIC_BLOCK)
(insn 18 86 19 2 (parallel [
(set (reg/f:SI 7 esp)
(plus:SI (reg/f:SI 7 esp)
(const_int 4 [0x4])))
(clobber (reg:CC 17 flags))
]) 215 {*addsi_1} (nil)
(expr_list:REG_UNUSED (reg:CC 17 flags)
(nil)))
(note 19 18 21 2 NOTE_INSN_DELETED)
(insn 21 19 87 2 (set (reg:DF 8 st(0) [63])
(float_extend:DF (reg:SF 8 st(0)))) 136 {*extendsfdf2_1} (nil)
==> (expr_list:REG_EH_REGION (const_int 1 [0x1])
(nil)))
;; Registers live at end: 6 [bp] 7 [sp] 8 [st] 16 [] 20 [frame]
;; Successors: 3 [50.0%] (fallthru) 5 [50.0%] (ab,eh)
insn 21 is removed by move_for_stack_reg:
/* The source reg does not die. */
/* If this appears to be a no-op move, delete it, or else it
will confuse the machine description output patterns. But if
it is REG_UNUSED, we must pop the reg now, as per-insn processing
for REG_UNUSED will not work for deleted insns. */
if (REGNO (src) == REGNO (dest))
{
if (find_regno_note (insn, REG_UNUSED, REGNO (dest)))
emit_pop_insn (insn, regstack, dest, EMIT_AFTER);
delete_insn (insn);
return;
}
fixup_abnormal_edges later sees:
;; Basic block 2, loop depth 0, count 0
;; Registers live at start: 6 [bp] 7 [sp] 8 [st] 16 [] 20 [frame]
(note 86 17 18 2 [bb 2] NOTE_INSN_BASIC_BLOCK)
(insn 18 86 19 2 (parallel [
(set (reg/f:SI 7 esp)
(plus:SI (reg/f:SI 7 esp)
(const_int 4 [0x4])))
(clobber (reg:CC 17 flags))
]) 215 {*addsi_1} (nil)
(expr_list:REG_UNUSED (reg:CC 17 flags)
(nil)))
(note 19 18 87 2 NOTE_INSN_DELETED)
;; Registers live at end: 6 [bp] 7 [sp] 8 [st] 16 [] 20 [frame]
;; Successors: 3 [50.0%] (fallthru) 5 [50.0%] (ab,eh)
It aborts on:
/* Get past the new insns generated. Allow notes, as the insns may
be already deleted. */
[...]
if (GET_CODE (insn) != CALL_INSN && !can_throw_internal (insn))
abort ();
with insn beeing (note 86 17 18 2 [bb 2] NOTE_INSN_BASIC_BLOCK).
A couple of possible ways out first came to mind:
1/ Teach fixup_abnormal_edges about these cases,
2/ Avoid the deletion of can_throw_internal insns from convert_regs,
3/ Arrange for convert_regs to remove the abnormal eh edge in the right
conditions.
I'm unclear which alternative makes the more sense/would be preferrable. There
may of course also be others that I did not see.
2/ Might not be an option, btw, since according to the comment above it, the
"culprit" deletion is there to avoid some other troubles. I don't know
reg-stack well enough to evaluate further at this point.
More information about the Gcc
mailing list