This is the mail archive of the
gcc@gcc.gnu.org
mailing list for the GCC project.
Re: Using and clobbering hard regs in parallel
- To: gcc at gcc dot gnu dot org
- Subject: Re: Using and clobbering hard regs in parallel
- From: Stephen Clarke <Stephen dot Clarke at st dot com>
- Date: Thu, 19 Jul 2001 19:39:01 -0700
- Cc: geoffk at geoffk dot org
- Organization: STMicroelectronics
- References: <jmvgkocqjq.fsf@geoffk.org>
geoffk@geoffk.org wrote:
>
> Stephen Clarke <Stephen.Clarke@st.com> writes:
>
> > Is it valid in RTL to read a hard reg in one branch of a parallel,
> > and clobber the same hard reg in another branch?
> >
> Yes, what this means is that r4 holds an input at the start of the
> insn but some other (unspecified) value at the end of the insn.
Okay, good, so here's the main problem.
I'm getting an abort in the instruction scheduler,
divtest.c:9: Internal compiler error in schedule_insns, at sched-rgn.c:3070
which appears to be related to an instruction that both reads and
clobbers a hard reg.
After lifetime analysis, I have the following sequence. Notice
that lifetime analysis has put a REG_DEAD (reg:SI 4 r4) note on insn 20.
--- after lifetime analysis
(insn 15 7 17 (set (reg/f:DI 161)
(symbol_ref:DI ("__udivsi3"))) 126 {*movdi} (nil)
(expr_list:REG_EQUAL (symbol_ref:DI ("__udivsi3"))
(nil)))
(insn 17 15 19 (set (reg:SI 4 r4)
(subreg/s:SI (reg/v:DI 158) 0)) 116 {*movsi} (insn_list 4 (nil))
(expr_list:REG_DEAD (reg/v:DI 158)
(insn_list:REG_LIBCALL 20 (nil))))
(insn 19 17 20 (set (reg:SI 5 r5)
(subreg/s:SI (reg/v:DI 159) 0)) 116 {*movsi} (insn_list 6 (nil))
(expr_list:REG_DEAD (reg/v:DI 159)
(nil)))
(insn 20 19 21 (parallel[
(set (reg:SI 160)
(udiv:SI (reg:SI 4 r4)
(reg:SI 5 r5)))
(clobber (reg:SI 19 r19))
(clobber (reg:SI 18 r18))
(clobber (reg:SI 4 r4))
(clobber (reg:DI 128 tr0))
(clobber (reg:DI 129 tr1))
(clobber (reg:DI 130 tr2))
(use (reg/f:DI 161))
] ) 32 {udivsi3_i1_media} (insn_list 15 (insn_list 17 (insn_list 19 (nil))))
(expr_list:REG_DEAD (reg/f:DI 161)
(expr_list:REG_DEAD (reg:SI 4 r4)
(expr_list:REG_DEAD (reg:SI 5 r5)
(expr_list:REG_UNUSED (reg:SI 19 r19)
(expr_list:REG_UNUSED (reg:SI 18 r18)
(expr_list:REG_UNUSED (reg:SI 4 r4)
(expr_list:REG_UNUSED (reg:DI 128 tr0)
(expr_list:REG_UNUSED (reg:DI 129 tr1)
(expr_list:REG_UNUSED (reg:DI 130 tr2)
(expr_list:REG_EQUAL (udiv:SI (subreg/s:SI (reg/v:DI 158) 0)
(subreg/s:SI (reg/v:DI 159) 0))
(insn_list:REG_RETVAL 17 (nil)))))))))))))
---
Later on, combine.c combines insns 15 and 20, as follows.
Note that the REG_DEAD (reg:SI 4 r4) note has been discarded from the
combined insn 20.
--- after combination
(note 15 7 17 NOTE_INSN_DELETED 0)
(insn 17 15 19 (set (reg:SI 4 r4)
(subreg/s:SI (reg/v:DI 158) 0)) 116 {*movsi} (insn_list 4 (nil))
(expr_list:REG_DEAD (reg/v:DI 158)
(insn_list:REG_LIBCALL 20 (nil))))
(insn 19 17 20 (set (reg:SI 5 r5)
(subreg/s:SI (reg/v:DI 159) 0)) 116 {*movsi} (insn_list 6 (nil))
(expr_list:REG_DEAD (reg/v:DI 159)
(nil)))
(insn 20 19 21 (parallel[
(set (reg:SI 160)
(udiv:SI (reg:SI 4 r4)
(reg:SI 5 r5)))
(clobber (reg:SI 19 r19))
(clobber (reg:SI 18 r18))
(clobber (reg:SI 4 r4))
(clobber (reg:DI 128 tr0))
(clobber (reg:DI 129 tr1))
(clobber (reg:DI 130 tr2))
(use (symbol_ref:DI ("__udivsi3")))
] ) 32 {udivsi3_i1_media} (insn_list 19 (insn_list 17 (nil)))
(insn_list:REG_RETVAL 17 (expr_list:REG_UNUSED (reg:DI 130 tr2)
(expr_list:REG_UNUSED (reg:DI 129 tr1)
(expr_list:REG_UNUSED (reg:DI 128 tr0)
(expr_list:REG_UNUSED (reg:SI 4 r4)
(expr_list:REG_UNUSED (reg:SI 18 r18)
(expr_list:REG_UNUSED (reg:SI 19 r19)
(expr_list:REG_DEAD (reg:SI 5 r5)
(nil))))))))))
---
Later again, the instruction scheduler schedules these instructions,
and calls update_life_info() in flow.c to recreate all the REG_DEAD notes -
this call adds the REG_DEAD (reg:SI 4 r4) back to insn 20.
The instruction scheduler (schedule_insns()) then calls
count_or_remove_death_notes() to verify that the number of REG_DEAD notes is
the same before and after scheduling: it isn't, because of the note that
update_life_info() has added, and so the instruction scheduler aborts.
I can think of three possible reasons for the problem, but
I have no objective idea which is correct, or whether there are
other reasons:
1. flow.c should not put the REG_DEAD (reg:SI 4 r4) note on insn 20.
Rationale: the comment at the top of flow.c states that the REG_DEAD
note should only be added if the instruction does not replace the
value in the register - is a clobber considered to have replaced
the value?
2. combine.c should preserve the REG_DEAD (reg:SI 4 r4) note on insn 20.
Rationale: ummm, not sure -- maybe because if flow.c thinks
the REG_DEAD note should be there, then combine.c should think so too.
3. The instruction scheduler should not assume that the number of
REG_DEAD notes should be exactly the same before and after scheduling.
Rationale: REG_DEAD notes are optional in a situation like insn 20,
so the assumption is invalid.
Can anyone provide opinions on this?
Thanks,
Steve.
--
Stephen Clarke, Micro Cores & Development Tools, STMicroelectronics
Phone:1-408-922-4062, Fax:1-408-895-3069, mailto:Stephen.Clarke@st.com
Mail: STMicroelectronics, 1060 E. Brokaw Rd., San Jose, CA 95131.