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