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

Reply via email to