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.

Reply via email to