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