+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
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;
}
}
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;
}
VUNSPEC_ARC_BLOCKAGE
VUNSPEC_ARC_EH_RETURN
VUNSPEC_ARC_ARC600_RTIE
+ VUNSPEC_ARC_LDDI
+ VUNSPEC_ARC_STDI
])
(define_constants
[(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)]
+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.
}]
}
+# 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 {
return *status;
}
-/* { dg-final { scan-assembler-times "ld\.di" 1 } } */
+/* { dg-final { scan-assembler-times "ld\.di" 2 } } */
(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 } } */
--- /dev/null
+/* { 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 } } */
--- /dev/null
+/* { 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 } } */
--- /dev/null
+/* { 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 } } } } } */
--- /dev/null
+/* { 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 } } } } } */
--- /dev/null
+/* { 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 } } */
--- /dev/null
+/* { 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 } } */