This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
[RFC/PATCH] Broken flow info for EH landing pads after reload (Re: [Ada/4.1] Fix PR ada/18819 on s390x)
- From: Ulrich Weigand <uweigand at de dot ibm dot com>
- To: gcc-patches at gcc dot gnu dot org
- Cc: Ulrich dot Weigand at de dot ibm dot com (Ulrich Weigand), ebotcazou at adacore dot com (Eric Botcazou), richard dot guenther at gmail dot com
- Date: Thu, 26 Jan 2006 19:46:33 +0100 (CET)
- Subject: [RFC/PATCH] Broken flow info for EH landing pads after reload (Re: [Ada/4.1] Fix PR ada/18819 on s390x)
Hello,
with current GCC 4.1, when compiling the Ada runtime with -mtune=z990,
building g-spipat.adb fails with an ICE in sched2:
live_at_start mismatch in bb 146, aborting
New:
first = 0x81559eb0 current = 0x81559eb0 indx = 0
0x81559eb0 next = (nil) prev = (nil) indx = 0
bits = { 1 2 11 13 15 }
Old:
;; basic block 146, loop depth 1, count 0
;; prev block 145, next block 147
;; pred: 145 [100.0%] (fallthru,can_fallthru)
;; succ: 980 (ab,eh,loop_exit) 147 [100.0%] (fallthru,can_fallthru)
;; Registers live at start: 1 [%r1] 2 [%r2] 6 [%r6] 11 [%r11] 13 [%r13] 15 [%r15]
(note 4969 4968 4970 146 [bb 146] NOTE_INSN_BASIC_BLOCK)
(note 4970 4969 4972 146 NOTE_INSN_DELETED)
(note 4972 4970 4971 146 NOTE_INSN_DELETED)
(insn:TI 4971 4972 10891 146 (set (reg:DI 1 %r1 [2395])
(ashift:DI (reg:DI 1 %r1 [orig:686 D.15470 ] [686])
(const_int 4 [0x4]))) 326 {*ashldi3_64} (nil)
(nil))
(insn 10891 4971 10892 146 (set (reg:DI 6 %r6)
(const_int 38368 [0x95e0])) 47 {*movdi_64} (nil)
(nil))
(insn:TI 10892 10891 4973 146 (set (reg:DI 7 %r7)
(plus:DI (reg:DI 1 %r1 [2395])
(reg:DI 6 %r6))) 49 {*la_64} (insn_list:REG_DEP_TRUE 10891 (insn_list:REG_DEP_TRUE 4971 (nil)))
(expr_list:REG_DEAD (reg:DI 1 %r1 [2395])
(nil)))
(insn 4973 10892 4974 146 (set (mem/s/j:DI (plus:DI (reg:DI 7 %r7)
(reg/f:DI 15 %r15 [ saved_stack.690 ])) [44 <variable>.node+0 S8 A64])
(reg:DI 2 %r2 [8])) 47 {*movdi_64} (insn_list:REG_DEP_ANTI 10891 (insn_list:REG_DEP_ANTI 4971 (insn_list:REG_DEP_ANTI 10892 (nil))))
(expr_list:REG_DEAD (reg:DI 2 %r2 [8])
(expr_list:REG_DEAD (reg:DI 7 %r7)
(expr_list:REG_EH_REGION (const_int 1 [0x1])
(nil)))))
;; Registers live at end: 6 [%r6] 11 [%r11] 13 [%r13] 15 [%r15]
This is caused by %r6 having been erroneously marked live_at_end
in csa (rest_of_handle_stack_adjustments):
;; Start of basic block 698, registers live: 1 [%r1] 2 [%r2] 6 [%r6] 11 [%r11] 13 [%r13] 15 [%r15]
(note 4969 4968 4970 698 [bb 698] NOTE_INSN_BASIC_BLOCK)
(note 4970 4969 4972 698 NOTE_INSN_DELETED)
(note 4972 4970 4971 698 NOTE_INSN_DELETED)
(insn 4971 4972 10893 698 (set (reg:DI 1 %r1 [2395])
(ashift:DI (reg:DI 1 %r1 [orig:686 D.15470 ] [686])
(const_int 4 [0x4]))) 326 {*ashldi3_64} (nil)
(nil))
(insn 10893 4971 11362 698 (set (reg:DI 8 %r8)
(reg:DI 2 %r2 [orig:1144 D.14409 ] [1144])) 47 {*movdi_64} (nil)
(expr_list:REG_DEAD (reg:DI 2 %r2 [orig:1144 D.14409 ] [1144])
(expr_list:REG_EH_REGION (const_int 1 [0x1])
(nil))))
;; End of basic block 698, registers live:
1 [%r1] 6 [%r6] 8 [%r8] 11 [%r11] 13 [%r13] 15 [%r15]
;; Start of basic block 699, registers live: 1 [%r1] 8 [%r8] 11 [%r11] 13 [%r13] 15 [%r15]
(note 11362 10893 10891 699 [bb 699] NOTE_INSN_BASIC_BLOCK)
(insn 10891 11362 10892 699 (set (reg:DI 6 %r6)
(const_int 38368 [0x95e0])) 47 {*movdi_64} (nil)
(nil))
(insn 10892 10891 4973 699 (set (reg:DI 7 %r7)
(plus:DI (reg:DI 1 %r1 [2395])
(reg:DI 6 %r6))) 49 {*la_64} (nil)
(expr_list:REG_DEAD (reg:DI 1 %r1 [2395])
(nil)))
(insn 4973 10892 4974 699 (set (mem/s/j:DI (plus:DI (reg:DI 7 %r7)
(reg/f:DI 15 %r15 [ saved_stack.690 ])) [44 <variable>.node+0 S8 A64])
(reg:DI 8 %r8)) 47 {*movdi_64} (insn_list:REG_DEP_ANTI 4971 (nil))
(expr_list:REG_DEAD (reg:DI 8 %r8)
(expr_list:REG_DEAD (reg:DI 7 %r7)
(expr_list:REG_EH_REGION (const_int 1 [0x1])
(nil)))))
;; End of basic block 699, registers live:
6 [%r6] 11 [%r11] 13 [%r13] 15 [%r15]
Now, regrename replaces register 8 by register 2, making insn 10893
obsolete. Subsequently, bbro merges the two basic blocks into:
;; Start of basic block 146, registers live: 1 [%r1] 2 [%r2] 6 [%r6] 11 [%r11] 13 [%r13] 15 [%r15]
(note 4969 4968 4970 146 [bb 146] NOTE_INSN_BASIC_BLOCK)
(note 4970 4969 4972 146 NOTE_INSN_DELETED)
(note 4972 4970 4971 146 NOTE_INSN_DELETED)
(insn 4971 4972 10891 146 (set (reg:DI 1 %r1 [2395])
(ashift:DI (reg:DI 1 %r1 [orig:686 D.15470 ] [686])
(const_int 4 [0x4]))) 326 {*ashldi3_64} (nil)
(nil))
(insn 10891 4971 10892 146 (set (reg:DI 6 %r6)
(const_int 38368 [0x95e0])) 47 {*movdi_64} (nil)
(nil))
(insn 10892 10891 4973 146 (set (reg:DI 7 %r7)
(plus:DI (reg:DI 1 %r1 [2395])
(reg:DI 6 %r6))) 49 {*la_64} (nil)
(expr_list:REG_DEAD (reg:DI 1 %r1 [2395])
(nil)))
(insn 4973 10892 4974 146 (set (mem/s/j:DI (plus:DI (reg:DI 7 %r7)
(reg/f:DI 15 %r15 [ saved_stack.690 ])) [44 <variable>.node+0 S8 A64])
(reg:DI 2 %r2 [8])) 47 {*movdi_64} (insn_list:REG_DEP_ANTI 4971 (nil))
(expr_list:REG_DEAD (reg:DI 2 %r2 [8])
(expr_list:REG_DEAD (reg:DI 7 %r7)
(expr_list:REG_EH_REGION (const_int 1 [0x1])
(nil)))))
;; End of basic block 146, registers live:
6 [%r6] 11 [%r11] 13 [%r13] 15 [%r15]
Note how now the live_at_start info is actually even locally incorrect
(since %r6 is killed in 10891), but this is apparently not noticed by
the basic block merging code.
When sched2 subsequently tries to validate the local life info, it
(correctly) recomputes the fact that %r6 is not live_at_start, and
aborts.
Now, the question is why is %r6 marked live_at_start in the first place?
This is because %r6 is one of the EH_RETURN_DATA_REGNOs, and gets implicitly
set by the exception handling runtime. Thus, even though the landing pad
code uses %r6, and the landing pad is a successor block of the block holding
insn 10893 above, that block should *not* be considered as requiring register
%r6 live at end.
The exception expanders apparently try to achieve this by emitting raw
CLOBBER insns at the beginning of the landing pad code. Flow analysis
before reload sees these CLOBBERs and stops propagating live info for
%r6.
However, these days there are additional flow analysis passes *after* reload,
in particular in csa (as mentioned above). At this point in time, the
CLOBBER insns emitted by the landing pad expander are simply gone. This is
not an accident -- reload deliberately removes any raw CLOBBER of any
register (that is not used to hold the return value). Thus, the late flow
passes propagate %r6 as live through most of the program, even where it
actually isn't.
I'm not sure I understand what's going on here -- why is reload removing
CLOBBERs in the first place? There's special code excepting return value
registers, so I guess there should be special code excepting landing pad
registers as well? However, those aren't easy to identify.
On the other hand, what *other* places do in fact use a raw CLOBBER
(and why shouldn't such ones stay after reload)?
As a wild guess, the patch below continues to remove CLOBBER insns
for registers that used to be pseudos before reload, but keeps all
CLOBBERs that originally mentioned a hard reg (automatically including
all return value registers, of course).
This fixes the Ada g-spipat compile failure. Full bootstrap and
regression test is still going on.
Is this the right way to do? Any hints would be appreciated!
Bye,
Ulrich
ChangeLog:
* reload1.c (reload): Do not remove CLOBBER insns originally
mentioning a hard register.
Index: gcc/reload1.c
===================================================================
*** gcc/reload1.c (revision 110212)
--- gcc/reload1.c (working copy)
*************** reload (rtx first, int global)
*** 1145,1152 ****
/* Make a pass over all the insns and delete all USEs which we inserted
only to tag a REG_EQUAL note on them. Remove all REG_DEAD and REG_UNUSED
! notes. Delete all CLOBBER insns, except those that refer to the return
! value and the special mem:BLK CLOBBERs added to prevent the scheduler
from misarranging variable-array code, and simplify (subreg (reg))
operands. Also remove all REG_RETVAL and REG_LIBCALL notes since they
are no longer useful or accurate. Strip and regenerate REG_INC notes
--- 1145,1152 ----
/* Make a pass over all the insns and delete all USEs which we inserted
only to tag a REG_EQUAL note on them. Remove all REG_DEAD and REG_UNUSED
! notes. Delete all CLOBBER insns, except those that originally refered to
! hard regs and the special mem:BLK CLOBBERs added to prevent the scheduler
from misarranging variable-array code, and simplify (subreg (reg))
operands. Also remove all REG_RETVAL and REG_LIBCALL notes since they
are no longer useful or accurate. Strip and regenerate REG_INC notes
*************** reload (rtx first, int global)
*** 1172,1178 ****
&& XEXP (XEXP (PATTERN (insn), 0), 0)
!= stack_pointer_rtx))
&& (!REG_P (XEXP (PATTERN (insn), 0))
! || ! REG_FUNCTION_VALUE_P (XEXP (PATTERN (insn), 0)))))
{
delete_insn (insn);
continue;
--- 1172,1179 ----
&& XEXP (XEXP (PATTERN (insn), 0), 0)
!= stack_pointer_rtx))
&& (!REG_P (XEXP (PATTERN (insn), 0))
! || ORIGINAL_REGNO (XEXP (PATTERN (insn), 0))
! >= FIRST_PSEUDO_REGISTER)))
{
delete_insn (insn);
continue;
--
Dr. Ulrich Weigand
Linux on zSeries Development
Ulrich.Weigand@de.ibm.com