diff mbox series

[2/4,ARC] Propagate uncached type attribute.

Message ID 20200122081452.4710-2-claziss@gmail.com
State New
Headers show
Series [1/4,ARC] Make libgcc compatible with ARC's reduced register set config. | expand

Commit Message

Claudiu Zissulescu Ianculescu Jan. 22, 2020, 8:14 a.m. UTC
Like `packed` type attribute, the ARC's `uncached` type attribute
needs to be propagated to each member of the struct where it is used.
Fix this behavior and add a test.

gcc/
xxxx-xx-xx  Claudiu Zissulescu  <claziss@synopsys.com>

	* config/arc/arc.c (arc_is_uncached_mem_p): Check struct
	attributes if needed.

testsuite/
xxxx-xx-xx  Claudiu Zissulescu  <claziss@synopsys.com>

	* gcc.target/arc/uncached-3.c: New test.

[ARC] Fix pending errors with uncached type attribute.

uncached type attribute applied to a structure needs to be propagated
to its members, triggering the .di flag for any access of the struct
members. Also, 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 (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-4.c: New file.
	* 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.
---
 gcc/config/arc/arc.c                      | 118 ++++++++++++++--------
 gcc/config/arc/arc.md                     |  60 +++++++++++
 gcc/testsuite/gcc.target/arc/arc.exp      |   9 ++
 gcc/testsuite/gcc.target/arc/uncached-1.c |   2 +-
 gcc/testsuite/gcc.target/arc/uncached-2.c |   2 +-
 gcc/testsuite/gcc.target/arc/uncached-3.c |  22 ++++
 gcc/testsuite/gcc.target/arc/uncached-4.c |  42 ++++++++
 gcc/testsuite/gcc.target/arc/uncached-5.c |  29 ++++++
 gcc/testsuite/gcc.target/arc/uncached-6.c |  35 +++++++
 gcc/testsuite/gcc.target/arc/uncached-7.c |  11 ++
 gcc/testsuite/gcc.target/arc/uncached-8.c |  33 ++++++
 11 files changed, 321 insertions(+), 42 deletions(-)
 create mode 100644 gcc/testsuite/gcc.target/arc/uncached-3.c
 create mode 100644 gcc/testsuite/gcc.target/arc/uncached-4.c
 create mode 100644 gcc/testsuite/gcc.target/arc/uncached-5.c
 create mode 100644 gcc/testsuite/gcc.target/arc/uncached-6.c
 create mode 100644 gcc/testsuite/gcc.target/arc/uncached-7.c
 create mode 100644 gcc/testsuite/gcc.target/arc/uncached-8.c

Comments

Jeff Law Jan. 23, 2020, 8:13 p.m. UTC | #1
On Wed, 2020-01-22 at 10:14 +0200, Claudiu Zissulescu wrote:
> Like `packed` type attribute, the ARC's `uncached` type attribute
> needs to be propagated to each member of the struct where it is used.
> Fix this behavior and add a test.
> 
> gcc/
> xxxx-xx-xx  Claudiu Zissulescu  <claziss@synopsys.com>
> 
> 	* config/arc/arc.c (arc_is_uncached_mem_p): Check struct
> 	attributes if needed.
> 
> testsuite/
> xxxx-xx-xx  Claudiu Zissulescu  <claziss@synopsys.com>
> 
> 	* gcc.target/arc/uncached-3.c: New test.
> 
> [ARC] Fix pending errors with uncached type attribute.
> 
> uncached type attribute applied to a structure needs to be propagated
> to its members, triggering the .di flag for any access of the struct
> members. Also, 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 (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-4.c: New file.
> 	* 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.
OK
jeff
>
diff mbox series

Patch

diff --git a/gcc/config/arc/arc.c b/gcc/config/arc/arc.c
index c0b2a8de2f1..25d66e9cac9 100644
--- a/gcc/config/arc/arc.c
+++ b/gcc/config/arc/arc.c
@@ -9208,49 +9208,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;
 	}
     }
@@ -11189,24 +11211,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;
 }
 
diff --git a/gcc/config/arc/arc.md b/gcc/config/arc/arc.md
index 5420f9067f9..32707bc257b 100644
--- a/gcc/config/arc/arc.md
+++ b/gcc/config/arc/arc.md
@@ -164,6 +164,8 @@ 
   VUNSPEC_ARC_BLOCKAGE
   VUNSPEC_ARC_EH_RETURN
   VUNSPEC_ARC_ARC600_RTIE
+  VUNSPEC_ARC_LDDI
+  VUNSPEC_ARC_STDI
   ])
 
 (define_constants
@@ -4695,6 +4697,64 @@  archs4x, archs4xd"
   [(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)]
diff --git a/gcc/testsuite/gcc.target/arc/arc.exp b/gcc/testsuite/gcc.target/arc/arc.exp
index 8f50aba1f5b..93c7d39b2c3 100644
--- a/gcc/testsuite/gcc.target/arc/arc.exp
+++ b/gcc/testsuite/gcc.target/arc/arc.exp
@@ -130,6 +130,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 {
diff --git a/gcc/testsuite/gcc.target/arc/uncached-1.c b/gcc/testsuite/gcc.target/arc/uncached-1.c
index 7a6bade81c4..fa5ecb7b7d3 100644
--- a/gcc/testsuite/gcc.target/arc/uncached-1.c
+++ b/gcc/testsuite/gcc.target/arc/uncached-1.c
@@ -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 } } */
diff --git a/gcc/testsuite/gcc.target/arc/uncached-2.c b/gcc/testsuite/gcc.target/arc/uncached-2.c
index 89eed326e01..9d6bfbbb50e 100644
--- a/gcc/testsuite/gcc.target/arc/uncached-2.c
+++ b/gcc/testsuite/gcc.target/arc/uncached-2.c
@@ -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
index 00000000000..f2a317b2816
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arc/uncached-3.c
@@ -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
index 00000000000..fecb16648b8
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arc/uncached-4.c
@@ -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
index 00000000000..7f8c5181179
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arc/uncached-5.c
@@ -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 "sth\.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
index 00000000000..0111c459f55
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arc/uncached-6.c
@@ -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 "ldh\.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
index 00000000000..4001b8bd821
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arc/uncached-7.c
@@ -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
index 00000000000..060229b11df
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arc/uncached-8.c
@@ -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 } } */