https://gcc.gnu.org/g:ca5cffec066fb8a7edd13dd12792505739381b42
commit r17-4751-gca5cffec066fb8a7edd13dd12792505739381b42 Author: Michiel Derhaeg <[email protected]> Date: Wed Jun 24 21:45:30 2026 +0000 arc: Fix invalid register index addressing for uncached stores [PR126157] `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]> Diff: --- 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(-) diff --git a/gcc/config/arc/arc.cc b/gcc/config/arc/arc.cc index 28e6f0b97296..e1a4aa6cfc26 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 fb905cfef058..b4b4a6a3e8e2 100644 --- a/gcc/config/arc/arc.md +++ b/gcc/config/arc/arc.md @@ -4786,7 +4786,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)] "" @@ -4795,7 +4795,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 1b7f53a70ff9..382012dc68df 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 000000000000..767cd484fb66 --- /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 000000000000..44efeb2cb054 --- /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]+\]} } } */
