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.