[ARC] Propagate uncached type attribute to each member of a struct.
authorClaudiu Zissulescu <claziss@gmail.com>
Mon, 27 Jan 2020 12:51:03 +0000 (14:51 +0200)
committerClaudiu Zissulescu <claziss@gmail.com>
Mon, 27 Jan 2020 12:51:03 +0000 (14:51 +0200)
Like `packed` type attribute, the ARC's `uncached` type attribute
needs to be propagated to each member of the struct where it is used,
triggering the .di flag for any access of the struct members. However,
any complex CFG manipulation may drop memory pointer type attributes,
leading to the impossibility to discriminate the direct accesses from
normal ones. To solve this issue, we will treat the direct memory
accessed specially via unspecs.

gcc/
xxxx-xx-xx  Claudiu Zissulescu  <claziss@synopsys.com>
Petro Karashchenko  <petro.karashchenko@ring.com>

* config/arc/arc.c (arc_is_uncached_mem_p): Check struct
attributes if needed.
(prepare_move_operands): Generate special
unspec instruction for direct access.
(arc_isuncached_mem_p): Propagate uncached attribute to each
structure member.
* config/arc/arc.md (VUNSPEC_ARC_LDDI): Define.
(VUNSPEC_ARC_STDI): Likewise.
(ALLI): New mode iterator.
(mALLI): New mode attribute.
(lddi): New instruction pattern.
(stdi): Likewise.
(stdidi_split): Split instruction for architectures which are not
supporting ll64 option.
(lddidi_split): Likewise.

testsuite/
xxxx-xx-xx  Claudiu Zissulescu  <claziss@synopsys.com>
Petro Karashchenko  <petro.karashchenko@ring.com>

* gcc.target/arc/uncached-1.c: Update test.
* gcc.target/arc/uncached-2.c: Likewise.
* gcc.target/arc/uncached-3.c: New test.
* gcc.target/arc/uncached-4.c: Likewise.
* gcc.target/arc/uncached-5.c: Likewise.
* gcc.target/arc/uncached-6.c: Likewise.
* gcc.target/arc/uncached-7.c: Likewise.
* gcc.target/arc/uncached-8.c: Likewise.
* gcc.target/arc/arc.exp (ll64): New predicate.

13 files changed:
gcc/ChangeLog
gcc/config/arc/arc.c
gcc/config/arc/arc.md
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.target/arc/arc.exp
gcc/testsuite/gcc.target/arc/uncached-1.c
gcc/testsuite/gcc.target/arc/uncached-2.c
gcc/testsuite/gcc.target/arc/uncached-3.c [new file with mode: 0644]
gcc/testsuite/gcc.target/arc/uncached-4.c [new file with mode: 0644]
gcc/testsuite/gcc.target/arc/uncached-5.c [new file with mode: 0644]
gcc/testsuite/gcc.target/arc/uncached-6.c [new file with mode: 0644]
gcc/testsuite/gcc.target/arc/uncached-7.c [new file with mode: 0644]
gcc/testsuite/gcc.target/arc/uncached-8.c [new file with mode: 0644]

index 91dfcd71a4b213de59d5153ec53e664eac3c900c..2cc61d68cf35f031f4c3b1bd68c21c281d91e74b 100644 (file)
@@ -1,3 +1,22 @@
+2020-01-27  Claudiu Zissulescu  <claziss@synopsys.com>
+           Petro Karashchenko  <petro.karashchenko@ring.com>
+
+       * config/arc/arc.c (arc_is_uncached_mem_p): Check struct
+       attributes if needed.
+       (prepare_move_operands): Generate special unspec instruction for
+       direct access.
+       (arc_isuncached_mem_p): Propagate uncached attribute to each
+       structure member.
+       * config/arc/arc.md (VUNSPEC_ARC_LDDI): Define.
+       (VUNSPEC_ARC_STDI): Likewise.
+       (ALLI): New mode iterator.
+       (mALLI): New mode attribute.
+       (lddi): New instruction pattern.
+       (stdi): Likewise.
+       (stdidi_split): Split instruction for architectures which are not
+       supporting ll64 option.
+       (lddidi_split): Likewise.
+
 2020-01-27  Richard Sandiford  <richard.sandiford@arm.com>
 
        PR rtl-optimization/92989
index 22475f2732e6a4eb2604b89587a05fb3e104d3e8..e1a865f02e699a8ed477e842ef4480d5f1e26d10 100644 (file)
@@ -9091,49 +9091,71 @@ arc_get_aux_arg (rtx pat, int *auxr)
 bool
 prepare_move_operands (rtx *operands, machine_mode mode)
 {
-  /* First handle aux attribute.  */
-  if (mode == SImode
-      && (MEM_P (operands[0]) || MEM_P (operands[1])))
+  if ((MEM_P (operands[0]) || MEM_P (operands[1]))
+      && SCALAR_INT_MODE_P (mode))
     {
-      rtx tmp;
-      int auxr = 0;
-      if (MEM_P (operands[0]) && arc_is_aux_reg_p (operands[0]))
+      /* First handle aux attribute.  */
+      if (mode == SImode)
        {
-         /* Save operation.  */
-         if (arc_get_aux_arg (operands[0], &auxr))
+         rtx tmp;
+         int auxr = 0;
+         if (MEM_P (operands[0]) && arc_is_aux_reg_p (operands[0]))
            {
-             tmp = gen_reg_rtx (SImode);
-             emit_move_insn (tmp, GEN_INT (auxr));
+             /* Save operation.  */
+             if (arc_get_aux_arg (operands[0], &auxr))
+               {
+                 tmp = gen_reg_rtx (SImode);
+                 emit_move_insn (tmp, GEN_INT (auxr));
+               }
+             else
+               tmp = XEXP (operands[0], 0);
+
+             operands[1] = force_reg (SImode, operands[1]);
+             emit_insn (gen_rtx_UNSPEC_VOLATILE
+                        (VOIDmode, gen_rtvec (2, operands[1], tmp),
+                         VUNSPEC_ARC_SR));
+             return true;
            }
-         else
+         if (MEM_P (operands[1]) && arc_is_aux_reg_p (operands[1]))
            {
-             tmp = XEXP (operands[0], 0);
+             if (arc_get_aux_arg (operands[1], &auxr))
+               {
+                 tmp = gen_reg_rtx (SImode);
+                 emit_move_insn (tmp, GEN_INT (auxr));
+               }
+             else
+               {
+                 tmp = XEXP (operands[1], 0);
+                 gcc_assert (GET_CODE (tmp) == SYMBOL_REF);
+               }
+             /* Load operation.  */
+             gcc_assert (REG_P (operands[0]));
+             emit_insn (gen_rtx_SET (operands[0],
+                                     gen_rtx_UNSPEC_VOLATILE
+                                     (SImode, gen_rtvec (1, tmp),
+                                      VUNSPEC_ARC_LR)));
+             return true;
            }
-
-         operands[1] = force_reg (SImode, operands[1]);
+       }
+      /* Second, we check for the uncached.  */
+      if (arc_is_uncached_mem_p (operands[0]))
+       {
+         if (!REG_P (operands[1]))
+           operands[1] = force_reg (mode, operands[1]);
          emit_insn (gen_rtx_UNSPEC_VOLATILE
-                    (VOIDmode, gen_rtvec (2, operands[1], tmp),
-                     VUNSPEC_ARC_SR));
+                    (VOIDmode, gen_rtvec (2, operands[0], operands[1]),
+                     VUNSPEC_ARC_STDI));
          return true;
        }
-      if (MEM_P (operands[1]) && arc_is_aux_reg_p (operands[1]))
+      if (arc_is_uncached_mem_p (operands[1]))
        {
-         if (arc_get_aux_arg (operands[1], &auxr))
-           {
-             tmp = gen_reg_rtx (SImode);
-             emit_move_insn (tmp, GEN_INT (auxr));
-           }
-         else
-           {
-             tmp = XEXP (operands[1], 0);
-             gcc_assert (GET_CODE (tmp) == SYMBOL_REF);
-           }
-         /* Load operation.  */
-         gcc_assert (REG_P (operands[0]));
-         emit_insn (gen_rtx_SET (operands[0],
-                                 gen_rtx_UNSPEC_VOLATILE
-                                 (SImode, gen_rtvec (1, tmp),
-                                  VUNSPEC_ARC_LR)));
+         if (MEM_P (operands[0]))
+           operands[0] = force_reg (mode, operands[0]);
+         emit_insn (gen_rtx_SET
+                    (operands[0],
+                     gen_rtx_UNSPEC_VOLATILE
+                     (mode, gen_rtvec (1, operands[1]),
+                      VUNSPEC_ARC_LDDI)));
          return true;
        }
     }
@@ -11162,24 +11184,40 @@ arc_is_uncached_mem_p (rtx pat)
     return false;
 
   /* Get the attributes.  */
-  if (TREE_CODE (addr) == MEM_REF)
+  if (TREE_CODE (addr) == MEM_REF
+      || TREE_CODE (addr) == VAR_DECL)
     {
       attrs = TYPE_ATTRIBUTES (TREE_TYPE (addr));
       if (lookup_attribute ("uncached", attrs))
        return true;
-
+    }
+  if (TREE_CODE (addr) == MEM_REF)
+    {
       attrs = TYPE_ATTRIBUTES (TREE_TYPE (TREE_OPERAND (addr, 0)));
       if (lookup_attribute ("uncached", attrs))
        return true;
-    }
-
-  /* For COMPONENT_REF, use the FIELD_DECL from tree operand 1.  */
-  if (TREE_CODE (addr) == COMPONENT_REF)
-    {
       attrs = TYPE_ATTRIBUTES (TREE_TYPE (TREE_OPERAND (addr, 1)));
       if (lookup_attribute ("uncached", attrs))
        return true;
     }
+
+  /* Check the definitions of the structs.  */
+  while (handled_component_p (addr))
+    {
+      if (TREE_CODE (addr) == COMPONENT_REF)
+       {
+         attrs = TYPE_ATTRIBUTES (TREE_TYPE (addr));
+         if (lookup_attribute ("uncached", attrs))
+           return true;
+         attrs = TYPE_ATTRIBUTES (TREE_TYPE (TREE_OPERAND (addr, 0)));
+         if (lookup_attribute ("uncached", attrs))
+           return true;
+         attrs = TYPE_ATTRIBUTES (TREE_TYPE (TREE_OPERAND (addr, 1)));
+         if (lookup_attribute ("uncached", attrs))
+           return true;
+       }
+      addr = TREE_OPERAND (addr, 0);
+    }
   return false;
 }
 
index cf7aa8d83c989ec9a3060543c1bff6eab0efbf07..46cb254ed28e805f62ee764cb9bf3814bf923fb8 100644 (file)
   VUNSPEC_ARC_BLOCKAGE
   VUNSPEC_ARC_EH_RETURN
   VUNSPEC_ARC_ARC600_RTIE
+  VUNSPEC_ARC_LDDI
+  VUNSPEC_ARC_STDI
   ])
 
 (define_constants
@@ -4682,6 +4684,64 @@ core_3, archs4x, archs4xd, archs4xd_slow"
   [(set_attr "length" "8,4,8,4")
    (set_attr "type" "sr,sr,sr,sr")])
 
+(define_mode_iterator ALLI [QI HI SI (DI "TARGET_LL64")])
+(define_mode_attr mALLI [(QI "b") (HI "%_") (SI "") (DI "d")])
+
+(define_insn "lddi<mode>"
+  [(set (match_operand:ALLI 0 "register_operand" "=r")
+       (unspec_volatile:ALLI [(match_operand:ALLI 1 "memory_operand" "m")]
+                             VUNSPEC_ARC_LDDI))]
+  ""
+  "ld<mALLI>%U1.di\\t%0,%1"
+  [(set_attr "type" "load")])
+
+(define_insn "stdi<mode>"
+  [(unspec_volatile [(match_operand:ALLI 0 "memory_operand"    "m,m,Usc")
+                    (match_operand:ALLI 1 "nonmemory_operand" "r,Cm3,i")]
+                   VUNSPEC_ARC_STDI)]
+  ""
+  "st<mALLI>%U0.di\\t%1,%0"
+  [(set_attr "length" "*,*,8")
+   (set_attr "type" "store")])
+
+(define_insn_and_split "*stdidi_split"
+  [(unspec_volatile [(match_operand:DI 0 "memory_operand"   "m")
+                    (match_operand:DI 1 "register_operand" "r")]
+                   VUNSPEC_ARC_STDI)]
+  "!TARGET_LL64"
+  "#"
+  "&& reload_completed"
+  [(unspec_volatile:SI [(match_dup 2) (match_dup 3)] VUNSPEC_ARC_STDI)
+   (unspec_volatile:SI [(match_dup 4) (match_dup 5)] VUNSPEC_ARC_STDI)]
+  "
+  {
+   operands[3] = gen_lowpart (SImode, operands[1]);
+   operands[5] = gen_highpart_mode (SImode, DImode, operands[1]);
+   operands[2] = gen_lowpart (SImode, operands[0]);
+   operands[4] = gen_highpart (SImode, operands[0]);
+  }
+  "
+  )
+
+(define_insn_and_split "*lddidi_split"
+  [(set (match_operand:DI 0 "register_operand" "=r")
+       (unspec_volatile:DI [(match_operand:DI 1 "memory_operand" "m")]
+                           VUNSPEC_ARC_LDDI))]
+  "!TARGET_LL64"
+  "#"
+  "&& reload_completed"
+  [(set (match_dup 2) (unspec_volatile:SI [(match_dup 3)] VUNSPEC_ARC_LDDI))
+   (set (match_dup 4) (unspec_volatile:SI [(match_dup 5)] VUNSPEC_ARC_LDDI))]
+  "
+  {
+   operands[3] = gen_lowpart (SImode, operands[1]);
+   operands[5] = gen_highpart (SImode, operands[1]);
+   operands[2] = gen_lowpart (SImode, operands[0]);
+   operands[4] = gen_highpart (SImode, operands[0]);
+  }
+  "
+  )
+
 (define_insn "trap_s"
   [(unspec_volatile [(match_operand:SI 0 "immediate_operand" "L,Cal")]
                   VUNSPEC_ARC_TRAP_S)]
index 16ddef07516a4d0579efcfb90137f499a3506d2f..991934272e06c7c9c1680f975988c40c46b2df55 100644 (file)
@@ -1,3 +1,14 @@
+2020-01-27  Claudiu Zissulescu  <claziss@synopsys.com>
+           Petro Karashchenko  <petro.karashchenko@ring.com>
+
+       * gcc.target/arc/uncached-3.c: New test.
+       * gcc.target/arc/uncached-4.c: Likewise.
+       * gcc.target/arc/uncached-5.c: Likewise.
+       * gcc.target/arc/uncached-6.c: Likewise.
+       * gcc.target/arc/uncached-7.c: Likewise.
+       * gcc.target/arc/uncached-8.c: Likewise.
+       * gcc.target/arc/arc.exp (ll64): New predicate.
+
 2020-01-27  Richard Sandiford  <richard.sandiford@arm.com>
 
        * gcc.dg/torture/pr93170.c: New test.
index 8d1844edd22da4676644f6e2d08ebec5004e077b..501d4589c53c622d2af5092b7c28bdac9b462893 100644 (file)
@@ -122,6 +122,15 @@ proc check_effective_target_dpfp { } {
     }]
 }
 
+# Return 1 if this is a compiler supporting LL64 option.
+proc check_effective_target_ll64 { } {
+    return [check_no_compiler_messages ll64 assembly {
+       #if !defined(__ARC_LL64__)
+       #error No ARC LL64
+       #endif
+    }]
+}
+
 # If a testcase doesn't have special options, use these.
 global DEFAULT_CFLAGS
 if ![info exists DEFAULT_CFLAGS] then {
index 7a6bade81c4b0fc1aee9514065cdd8bf9447990d..fa5ecb7b7d395921306e548523b74ac7aa7164fe 100644 (file)
@@ -8,4 +8,4 @@ int get_stat (void)
   return *status;
 }
 
-/* { dg-final { scan-assembler-times "ld\.di" 1 } } */
+/* { dg-final { scan-assembler-times "ld\.di" 2 } } */
index 89eed326e01a41015ddc73995c524e81f7bc9a59..9d6bfbbb50e5c55097f5082fe63e19abc96b9c75 100644 (file)
@@ -6,4 +6,4 @@ void clkgen_switch(unsigned int base, unsigned int offset, int val)
     (volatile unsigned int __attribute__ ((uncached)) *) (base + offset);
   *dest = val;
 }
-/* { dg-final { scan-assembler-times "st\.di" 1 } } */
+/* { dg-final { scan-assembler-times "st\.di" 2 } } */
diff --git a/gcc/testsuite/gcc.target/arc/uncached-3.c b/gcc/testsuite/gcc.target/arc/uncached-3.c
new file mode 100644 (file)
index 0000000..f2a317b
--- /dev/null
@@ -0,0 +1,22 @@
+/* { dg-do compile } */
+
+typedef volatile struct {
+    int a;
+    char *b;
+} __attribute__((uncached)) my_type_t;
+
+my_type_t x;
+
+void foo (my_type_t *p)
+{
+    p->a = 10;
+    p->b = 0;
+}
+
+void bar (void)
+{
+    x.a = 10;
+    x.b = 0;
+}
+
+/* { dg-final { scan-assembler-times "st\.di" 4 } } */
diff --git a/gcc/testsuite/gcc.target/arc/uncached-4.c b/gcc/testsuite/gcc.target/arc/uncached-4.c
new file mode 100644 (file)
index 0000000..fecb166
--- /dev/null
@@ -0,0 +1,42 @@
+/* { dg-do compile } */
+
+#include <stddef.h>
+
+typedef enum
+{
+ e1,
+ e2
+} my_enum_t;
+
+typedef struct
+{
+  int a;
+  int *p;
+} my_struct_t;
+
+typedef volatile struct
+{
+  my_enum_t a;
+  my_struct_t b;
+} __attribute__((uncached)) my_type_t;
+
+my_type_t x;
+
+void foo (my_type_t *p)
+{
+  p->a = e2;
+  p->b.a = 10;
+  p->b.p = NULL;
+  *p->b.p = 10;
+}
+
+void bar (void)
+{
+  x.a = e2;
+  x.b.a = 10;
+  x.b.p = NULL;
+  *x.b.p = 10;
+}
+
+/* { dg-final { scan-assembler-times "st\.di" 6 } } */
+/* { dg-final { scan-assembler-times "ld\.di" 2 } } */
diff --git a/gcc/testsuite/gcc.target/arc/uncached-5.c b/gcc/testsuite/gcc.target/arc/uncached-5.c
new file mode 100644 (file)
index 0000000..4fe0464
--- /dev/null
@@ -0,0 +1,29 @@
+/* { dg-options "-O1" } */
+/* { dg-do compile } */
+
+#define RegWrSI(a,v)  (*(volatile __attribute__((uncached)) int *)(a)=(v))
+#define RegWrQI(a,v)  (*(volatile __attribute__((uncached)) char *)(a)=(v))
+#define RegWrHI(a,v)  (*(volatile __attribute__((uncached)) short *)(a)=(v))
+#define RegWrDI(a,v)  (*(volatile __attribute__((uncached)) long long *)(a)=(v))
+
+void foo (int arg, void *p)
+{
+  RegWrDI (p  , arg);
+  RegWrHI (p++, arg);
+  RegWrSI (p++, arg);
+  RegWrQI (p++, arg);
+}
+
+void bar (void)
+{
+  RegWrQI (0x40000, 1);
+  RegWrHI (0x40010, 2);
+  RegWrSI (0x40020, 4);
+  RegWrDI (0x40040, 8);
+}
+
+/* { dg-final { scan-assembler-times "stb\.di" 2 } } */
+/* { dg-final { scan-assembler-times "st\[hw\]\.di" 2 } } */
+/* { dg-final { scan-assembler-times "std\.di" 2 { target { ll64 } } } } */
+/* { dg-final { scan-assembler-times "st\.di" 2 { target { ll64 } } } } */
+/* { dg-final { scan-assembler-times "st\.di" 6 { target { ! { ll64 } } } } } */
diff --git a/gcc/testsuite/gcc.target/arc/uncached-6.c b/gcc/testsuite/gcc.target/arc/uncached-6.c
new file mode 100644 (file)
index 0000000..581a9ec
--- /dev/null
@@ -0,0 +1,35 @@
+/* { dg-options "-O1" } */
+/* { dg-do compile } */
+
+#define RegRdSI(v,a) ((v) = *(volatile __attribute__((uncached)) int *)(a))
+#define RegRdQI(v,a) ((v) = *(volatile __attribute__((uncached)) char *)(a))
+#define RegRdHI(v,a) ((v) = *(volatile __attribute__((uncached)) short *)(a))
+#define RegRdDI(v,a) \
+  ((v) = *(volatile __attribute__((uncached)) long long *)(a))
+
+char a0;
+short a1;
+int a2;
+long long a3;
+
+void foox (void *p)
+{
+  RegRdQI (a0, p++);
+  RegRdHI (a1, p++);
+  RegRdSI (a2, p++);
+  RegRdDI (a3, p  );
+}
+
+void barx (int arg)
+{
+  RegRdQI (a0, 0x40000);
+  RegRdHI (a1, 0x40010);
+  RegRdSI (a2, 0x40020);
+  RegRdDI (a3, 0x40040);
+}
+
+/* { dg-final { scan-assembler-times "ldb\.di" 2 } } */
+/* { dg-final { scan-assembler-times "ld\[hw\]\.di" 2 } } */
+/* { dg-final { scan-assembler-times "ldd\.di" 2 { target { ll64 } } } } */
+/* { dg-final { scan-assembler-times "ld\.di" 2 { target { ll64 } } } } */
+/* { dg-final { scan-assembler-times "ld\.di" 6 { target { ! { ll64 } } } } } */
diff --git a/gcc/testsuite/gcc.target/arc/uncached-7.c b/gcc/testsuite/gcc.target/arc/uncached-7.c
new file mode 100644 (file)
index 0000000..4001b8b
--- /dev/null
@@ -0,0 +1,11 @@
+/* { dg-options "-O1" } */
+/* { dg-do compile } */
+
+volatile __attribute__((uncached)) int s[20];
+
+void s_acc(void)
+{
+    s[10] = 15;
+}
+
+/* { dg-final { scan-assembler-times "st\.di" 1 } } */
diff --git a/gcc/testsuite/gcc.target/arc/uncached-8.c b/gcc/testsuite/gcc.target/arc/uncached-8.c
new file mode 100644 (file)
index 0000000..060229b
--- /dev/null
@@ -0,0 +1,33 @@
+/* { dg-do compile } */
+
+#include <stddef.h>
+
+typedef struct
+{
+  int a;
+} my_structB_t;
+
+typedef struct
+{
+  my_structB_t b;
+} __attribute__((uncached))  my_structA_t;
+
+typedef volatile struct
+{
+  my_structA_t c;
+} my_type_t;
+
+my_type_t x;
+
+void foo (my_type_t *p)
+{
+  p->c.b.a = 10;
+}
+
+void bar (void)
+{
+  x.c.b.a = 10;
+}
+
+/* { dg-final { scan-assembler-times "st\.di" 1 } } */
+/* { dg-final { scan-assembler-times "st\.as\.di" 1 } } */