LGTM, please commit it. Claudiu
On Fri, Sep 11, 2026 at 1:01 PM Michiel Derhaeg <[email protected]> wrote: > > From: Michiel Derhaeg <[email protected]> > > `stdi<mode>` incorrectly uses a too liberal predicate for the > destination operand, producing something like this: stb.di r2,[r13,r1] > These [reg,reg] operands are not valid. > > This bug appeared because the introduction of > `-ffuse-ops-with-volatile-access` in r16-5947-ga6c50ec2c6ebcb. Before > its existence, recog/combine would've disallowed `(plus (reg) (reg))` as > the destination operand. > > POST_INC (and friends) is now produced as well. Didn't try implementing > that for *stdidi_split and simply disallowed it instead. > > PR target/126157 > > gcc/ChangeLog: > > * config/arc/arc.cc (prepare_move_operands): Force the address of > an uncached store into a register when it is not a valid store > destination. > * config/arc/arc.md (stdi<mode>): Use move_dest_operand for the > destination operand. > (*stdidi_split): Use non_mod_move_dest_operand for the destination > operand. > * config/arc/predicates.md (non_mod_move_dest_operand): New > predicate that disallows PRE/POST_INC/DEC. > > gcc/testsuite/ChangeLog: > > * gcc.target/arc/uncached-10.c: New test. > * gcc.target/arc/uncached-11.c: New test. > > Signed-off-by: Alexandru Turjan <[email protected]> > Signed-off-by: Michiel Derhaeg <[email protected]> > --- > gcc/config/arc/arc.cc | 9 ++++ > gcc/config/arc/arc.md | 4 +- > gcc/config/arc/predicates.md | 17 ++++++++ > gcc/testsuite/gcc.target/arc/uncached-10.c | 50 ++++++++++++++++++++++ > gcc/testsuite/gcc.target/arc/uncached-11.c | 50 ++++++++++++++++++++++ > 5 files changed, 128 insertions(+), 2 deletions(-) > create mode 100644 gcc/testsuite/gcc.target/arc/uncached-10.c > create mode 100644 gcc/testsuite/gcc.target/arc/uncached-11.c > > diff --git a/gcc/config/arc/arc.cc b/gcc/config/arc/arc.cc > index 32e358d2fd4..de6982f5c4c 100644 > --- a/gcc/config/arc/arc.cc > +++ b/gcc/config/arc/arc.cc > @@ -9286,6 +9286,15 @@ prepare_move_operands (rtx *operands, machine_mode > mode) > { > if (!REG_P (operands[1])) > operands[1] = force_reg (mode, operands[1]); > + > + if (!move_dest_operand (operands[0], mode)) > + { > + rtx tmp0 = copy_to_mode_reg (Pmode, XEXP (operands[0], 0)); > + rtx tmp1 = change_address (operands[0], mode, tmp0); > + MEM_COPY_ATTRIBUTES (tmp1, operands[0]); > + operands[0] = tmp1; > + } > + > emit_insn (gen_rtx_UNSPEC_VOLATILE > (VOIDmode, gen_rtvec (2, operands[0], operands[1]), > VUNSPEC_ARC_STDI)); > diff --git a/gcc/config/arc/arc.md b/gcc/config/arc/arc.md > index 54b65fefe6a..d080143c45d 100644 > --- a/gcc/config/arc/arc.md > +++ b/gcc/config/arc/arc.md > @@ -4955,7 +4955,7 @@ archs4x, archs4xd" > [(set_attr "type" "load")]) > > (define_insn "stdi<mode>" > - [(unspec_volatile [(match_operand:ALLI 0 "memory_operand" "m,m,Usc") > + [(unspec_volatile [(match_operand:ALLI 0 "move_dest_operand" "m,m,Usc") > (match_operand:ALLI 1 "nonmemory_operand" "r,Cm3,i")] > VUNSPEC_ARC_STDI)] > "" > @@ -4964,7 +4964,7 @@ archs4x, archs4xd" > (set_attr "type" "store")]) > > (define_insn_and_split "*stdidi_split" > - [(unspec_volatile [(match_operand:DI 0 "memory_operand" "m") > + [(unspec_volatile [(match_operand:DI 0 "non_mod_move_dest_operand" "m") > (match_operand:DI 1 "register_operand" "r")] > VUNSPEC_ARC_STDI)] > "!TARGET_LL64" > diff --git a/gcc/config/arc/predicates.md b/gcc/config/arc/predicates.md > index 1b7f53a70ff..382012dc68d 100644 > --- a/gcc/config/arc/predicates.md > +++ b/gcc/config/arc/predicates.md > @@ -775,3 +775,20 @@ > (ior (match_test "register_operand (op, mode)") > (and (match_code "const_int, symbol_ref") > (match_test "!optimize_size")))) > + > +(define_predicate "non_mod_move_dest_operand" > + (match_operand 0 "move_dest_operand") > +{ > + rtx addr = XEXP (op, 0); > + enum rtx_code code = GET_CODE (addr); > + > + if (code == POST_INC > + || code == PRE_INC > + || code == POST_DEC > + || code == PRE_DEC > + || code == POST_MODIFY > + || code == PRE_MODIFY) > + return false; > + > + return true; > +}) > diff --git a/gcc/testsuite/gcc.target/arc/uncached-10.c > b/gcc/testsuite/gcc.target/arc/uncached-10.c > new file mode 100644 > index 00000000000..767cd484fb6 > --- /dev/null > +++ b/gcc/testsuite/gcc.target/arc/uncached-10.c > @@ -0,0 +1,50 @@ > +/* { dg-do compile } */ > +/* { dg-options "-O2 -mno-ll64" } */ > + > +#ifndef __uncached > +#define __uncached __attribute__((uncached)) > +#endif > + > +volatile char * > +pack_byte_ptr (volatile char *p, const void *s, int len) > +{ > + volatile __uncached char *buf = p + 4; > + for (int i = 0; i < len; i++) > + buf[i] = ((const char *)s)[i]; > + return p; > +} > + > +volatile short * > +pack_halfword_ptr (volatile short *p, const void *s, int len) > +{ > + volatile __uncached short *buf = p + 4; > + for (int i = 0; i < len; i++) > + buf[i] = ((const short *)s)[i]; > + return p; > +} > + > +volatile int * > +pack_word_ptr (volatile int *p, const void *s, int len) > +{ > + volatile __uncached int *buf = p + 4; > + for (int i = 0; i < len; i++) > + buf[i] = ((const int *)s)[i]; > + return p; > +} > + > +volatile long long * > +pack_doubleword_ptr (volatile long long *p, const void *s, int len) > +{ > + volatile __uncached long long *buf = p + 4; > + for (int i = 0; i < len; i++) > + buf[i] = ((const long long *)s)[i]; > + return p; > +} > + > +/* { dg-final { scan-assembler "stb.*\\.di" } } */ > +/* { dg-final { scan-assembler "\\m(sth|stw).*\\.di" } } */ > +/* { dg-final { scan-assembler "st.*\\.di" } } */ > + > +/* { dg-final { scan-assembler-not > {stb.*\.di\s+r[0-9]+,\s*\[r[0-9]+,\s*r[0-9]+\]} } } */ > +/* { dg-final { scan-assembler-not > {\m(sth|stw).*\.di\s+r[0-9]+,\s*\[r[0-9]+,\s*r[0-9]+\]} } } */ > +/* { dg-final { scan-assembler-not > {st.*\.di\s+r[0-9]+,\s*\[r[0-9]+,\s*r[0-9]+\]} } } */ > diff --git a/gcc/testsuite/gcc.target/arc/uncached-11.c > b/gcc/testsuite/gcc.target/arc/uncached-11.c > new file mode 100644 > index 00000000000..44efeb2cb05 > --- /dev/null > +++ b/gcc/testsuite/gcc.target/arc/uncached-11.c > @@ -0,0 +1,50 @@ > +/* { dg-do compile } */ > +/* { dg-options "-Os -mno-ll64" } */ > + > +#ifndef __uncached > +#define __uncached __attribute__((uncached)) > +#endif > + > +volatile char * > +pack_byte_ptr (volatile char *p, const void *s, int len) > +{ > + volatile __uncached char *buf = p + 4; > + for (int i = 0; i < len; i++) > + buf[i] = ((const char *)s)[i]; > + return p; > +} > + > +volatile short * > +pack_halfword_ptr (volatile short *p, const void *s, int len) > +{ > + volatile __uncached short *buf = p + 4; > + for (int i = 0; i < len; i++) > + buf[i] = ((const short *)s)[i]; > + return p; > +} > + > +volatile int * > +pack_word_ptr (volatile int *p, const void *s, int len) > +{ > + volatile __uncached int *buf = p + 4; > + for (int i = 0; i < len; i++) > + buf[i] = ((const int *)s)[i]; > + return p; > +} > + > +volatile long long * > +pack_doubleword_ptr (volatile long long *p, const void *s, int len) > +{ > + volatile __uncached long long *buf = p + 4; > + for (int i = 0; i < len; i++) > + buf[i] = ((const long long *)s)[i]; > + return p; > +} > + > +/* { dg-final { scan-assembler "stb.*\\.di" } } */ > +/* { dg-final { scan-assembler "\\m(sth|stw).*\\.di" } } */ > +/* { dg-final { scan-assembler "st.*\\.di" } } */ > + > +/* { dg-final { scan-assembler-not > {stb.*\.di\s+r[0-9]+,\s*\[r[0-9]+,\s*r[0-9]+\]} } } */ > +/* { dg-final { scan-assembler-not > {\m(sth|stw).*\.di\s+r[0-9]+,\s*\[r[0-9]+,\s*r[0-9]+\]} } } */ > +/* { dg-final { scan-assembler-not > {st.*\.di\s+r[0-9]+,\s*\[r[0-9]+,\s*r[0-9]+\]} } } */ > -- > 2.54.0 >
