https://gcc.gnu.org/bugzilla/show_bug.cgi?id=55212
--- Comment #365 from Kazumoto Kojima <kkojima at gcc dot gnu.org> ---
(In reply to Oleg Endo from comment #364)
> Notice that it already has the hard-reg GBR assigned. Yet for some reason I
> don't understand, the following LRA pass then pulls that out and replaces
> GBR with R3:
>
> (insn 6 22 9 2 (parallel [
> (set (reg:QI 1 r1 [166])
> (mem/v:QI (plus:SI (reg:SI 3 r3 [171])
> (const_int 4 [0x4])) [-1 S1 A8]))
> (set (mem/v:QI (plus:SI (reg:SI 3 r3 [171])
> (const_int 4 [0x4])) [-1 S1 A8])
> (unspec:QI [
> (and:QI (mem/v:QI (plus:SI (reg:SI 3 r3 [171])
> (const_int 4 [0x4])) [-1 S1 A8])
> (const_int 1 [0x1]))
> ] UNSPEC_ATOMIC))
> (clobber (reg:SI 0 r0))
> (clobber (reg:QI 2 r2 [169]))
> ]) "../gcc/gcc/testsuite/gcc.target/sh/pr64661-0.h":50:173 discrim 1
> 538 {atomic_fetch_andqi_soft_imask}
> (nil))
>
> I've tried adding a constraint to that pattern, which would explicitly allow
> an GBR address, but it still does that transformation. It sounds a bit like
> the sfunc issue before, where it would re-allocate operands that already
> have hard-regs assigned. Why does it do that?
RTL dump .316r.reload says that
Creating newreg=171 from oldreg=144, assigning class GENERAL_REGS to address
r171
...
6: {r166:QI=[r171:SI+0x4];[r171:SI+0x4]=unspec[[r171:SI+0x4]&0x1] 33;clobber
r0:SI;clobber r169:QI;}
...
Inserting insn reload before:
22: r171:SI=gbr:SI
Before reload, the insn 6 was
(insn 6 5 9 2 (parallel [
(set (reg:QI 166)
(mem/v:QI (plus:SI (reg:SI 144 gbr)
(const_int 4 [0x4])) [-1 S1 A8]))
(set (mem/v:QI (plus:SI (reg:SI 144 gbr)
(const_int 4 [0x4])) [-1 S1 A8])
(unspec:QI [
(and:QI (mem/v:QI (plus:SI (reg:SI 144 gbr)
(const_int 4 [0x4])) [-1 S1 A8])
(const_int 1 [0x1]))
] UNSPEC_ATOMIC))
(clobber (reg:SI 0 r0))
(clobber (reg:QI 169))
]) "gbr.c":59:1 discrim 1 550 {atomic_fetch_andqi_soft_imask}
Looks that LRA reloads r144 with the register in more general class and there
is no constraint preventing it in the insn pattern:
(define_insn_and_split "atomic_fetch_<fetchop_name><mode>_soft_imask"
[(set (match_operand:QIHISI 0 "arith_reg_dest" "=&r")
(match_operand:QIHISI 1 "atomic_mem_operand_1" "=SraSdd"))
(set (match_dup 1)
(unspec:QIHISI
[(FETCHOP:QIHISI
(match_dup 1)
(match_operand:QIHISI 2 "<fetchop_predicate_1>"
"<fetchop_constraint_1_imask>"))]
UNSPEC_ATOMIC))
(clobber (reg:SI R0_REG))
(clobber (match_scratch:QIHISI 3 "=&r"))]
"TARGET_ATOMIC_SOFT_IMASK"
I'm not sure why LRA does that, but I suppose that the more general class of
registers usually helps.
Avoiding this may require a pattern that only allows GBR.
A similar problem occurs with extend<mode>si2, for example, and the patch 59158
introduces a new pattern to avoid such reloads:
https://gcc.gnu.org/bugzilla/attachment.cgi?id=59158&action=diff#a/gcc/config/sh/sh.md_sec1
It may be that similar changes are needed even with R0-specific pass.