#include "gimple-fold.h"
#define v8qi_UP E_V8QImode
+#define v8di_UP E_V8DImode
#define v4hi_UP E_V4HImode
#define v4hf_UP E_V4HFmode
#define v2si_UP E_V2SImode
AARCH64_MEMTAG_BUILTIN_SET_TAG,
AARCH64_MEMTAG_BUILTIN_GET_TAG,
AARCH64_MEMTAG_BUILTIN_END,
+ /* LS64 builtins. */
+ AARCH64_LS64_BUILTIN_LD64B,
+ AARCH64_LS64_BUILTIN_ST64B,
+ AARCH64_LS64_BUILTIN_ST64BV,
+ AARCH64_LS64_BUILTIN_ST64BV0,
AARCH64_BUILTIN_MAX
};
#undef AARCH64_INIT_MEMTAG_BUILTINS_DECL
}
+/* Add builtins for Load/store 64 Byte instructions. */
+
+typedef struct
+{
+ const char *name;
+ unsigned int code;
+ tree type;
+} ls64_builtins_data;
+
+static GTY(()) tree ls64_arm_data_t = NULL_TREE;
+
+static void
+aarch64_init_ls64_builtins_types (void)
+{
+ /* Synthesize:
+
+ typedef struct {
+ uint64_t val[8];
+ } __arm_data512_t; */
+ const char *tuple_type_name = "__arm_data512_t";
+ tree node_type = get_typenode_from_name (UINT64_TYPE);
+ tree array_type = build_array_type_nelts (node_type, 8);
+ SET_TYPE_MODE (array_type, V8DImode);
+
+ gcc_assert (TYPE_MODE_RAW (array_type) == TYPE_MODE (array_type));
+ gcc_assert (TYPE_ALIGN (array_type) == 64);
+
+ tree field = build_decl (input_location, FIELD_DECL,
+ get_identifier ("val"), array_type);
+
+ ls64_arm_data_t = lang_hooks.types.simulate_record_decl (input_location,
+ tuple_type_name,
+ make_array_slice (&field, 1));
+
+ gcc_assert (TYPE_MODE (ls64_arm_data_t) == V8DImode);
+ gcc_assert (TYPE_MODE_RAW (ls64_arm_data_t) == TYPE_MODE (ls64_arm_data_t));
+ gcc_assert (TYPE_ALIGN (ls64_arm_data_t) == 64);
+}
+
+static void
+aarch64_init_ls64_builtins (void)
+{
+ aarch64_init_ls64_builtins_types ();
+
+ ls64_builtins_data data[4] = {
+ {"__builtin_aarch64_ld64b", AARCH64_LS64_BUILTIN_LD64B,
+ build_function_type_list (ls64_arm_data_t,
+ const_ptr_type_node, NULL_TREE)},
+ {"__builtin_aarch64_st64b", AARCH64_LS64_BUILTIN_ST64B,
+ build_function_type_list (void_type_node, ptr_type_node,
+ ls64_arm_data_t, NULL_TREE)},
+ {"__builtin_aarch64_st64bv", AARCH64_LS64_BUILTIN_ST64BV,
+ build_function_type_list (uint64_type_node, ptr_type_node,
+ ls64_arm_data_t, NULL_TREE)},
+ {"__builtin_aarch64_st64bv0", AARCH64_LS64_BUILTIN_ST64BV0,
+ build_function_type_list (uint64_type_node, ptr_type_node,
+ ls64_arm_data_t, NULL_TREE)},
+ };
+
+ for (size_t i = 0; i < ARRAY_SIZE (data); ++i)
+ aarch64_builtin_decls[data[i].code]
+ = aarch64_general_add_builtin (data[i].name, data[i].type, data[i].code);
+}
+
/* Initialize fpsr fpcr getters and setters. */
static void
if (TARGET_MEMTAG)
aarch64_init_memtag_builtins ();
+
+ if (TARGET_LS64)
+ aarch64_init_ls64_builtins ();
}
/* Implement TARGET_BUILTIN_DECL for the AARCH64_BUILTIN_GENERAL group. */
return target;
}
+/* Function to expand an expression EXP which calls one of the Load/Store
+ 64 Byte extension (LS64) builtins FCODE with the result going to TARGET. */
+static rtx
+aarch64_expand_builtin_ls64 (int fcode, tree exp, rtx target)
+{
+ expand_operand ops[3];
+
+ switch (fcode)
+ {
+ case AARCH64_LS64_BUILTIN_LD64B:
+ {
+ rtx op0 = expand_normal (CALL_EXPR_ARG (exp, 0));
+ create_output_operand (&ops[0], target, V8DImode);
+ create_input_operand (&ops[1], op0, DImode);
+ expand_insn (CODE_FOR_ld64b, 2, ops);
+ return ops[0].value;
+ }
+ case AARCH64_LS64_BUILTIN_ST64B:
+ {
+ rtx op0 = expand_normal (CALL_EXPR_ARG (exp, 0));
+ rtx op1 = expand_normal (CALL_EXPR_ARG (exp, 1));
+ create_output_operand (&ops[0], op0, DImode);
+ create_input_operand (&ops[1], op1, V8DImode);
+ expand_insn (CODE_FOR_st64b, 2, ops);
+ return const0_rtx;
+ }
+ case AARCH64_LS64_BUILTIN_ST64BV:
+ {
+ rtx op0 = expand_normal (CALL_EXPR_ARG (exp, 0));
+ rtx op1 = expand_normal (CALL_EXPR_ARG (exp, 1));
+ create_output_operand (&ops[0], target, DImode);
+ create_input_operand (&ops[1], op0, DImode);
+ create_input_operand (&ops[2], op1, V8DImode);
+ expand_insn (CODE_FOR_st64bv, 3, ops);
+ return ops[0].value;
+ }
+ case AARCH64_LS64_BUILTIN_ST64BV0:
+ {
+ rtx op0 = expand_normal (CALL_EXPR_ARG (exp, 0));
+ rtx op1 = expand_normal (CALL_EXPR_ARG (exp, 1));
+ create_output_operand (&ops[0], target, DImode);
+ create_input_operand (&ops[1], op0, DImode);
+ create_input_operand (&ops[2], op1, V8DImode);
+ expand_insn (CODE_FOR_st64bv0, 3, ops);
+ return ops[0].value;
+ }
+ }
+
+ gcc_unreachable ();
+}
+
/* Expand a random number builtin EXP with code FCODE, putting the result
int TARGET. If IGNORE is true the return value is ignored. */
|| fcode == AARCH64_TME_BUILTIN_TCANCEL)
return aarch64_expand_builtin_tme (fcode, exp, target);
+ if (fcode == AARCH64_LS64_BUILTIN_LD64B
+ || fcode == AARCH64_LS64_BUILTIN_ST64B
+ || fcode == AARCH64_LS64_BUILTIN_ST64BV
+ || fcode == AARCH64_LS64_BUILTIN_ST64BV0)
+ return aarch64_expand_builtin_ls64 (fcode, exp, target);
+
if (fcode >= AARCH64_MEMTAG_BUILTIN_START
&& fcode <= AARCH64_MEMTAG_BUILTIN_END)
return aarch64_expand_builtin_memtag (fcode, exp, target);
"__ARM_FEATURE_BF16_VECTOR_ARITHMETIC", pfile);
aarch64_def_or_undef (TARGET_BF16_FP,
"__ARM_FEATURE_BF16_SCALAR_ARITHMETIC", pfile);
+ aarch64_def_or_undef (TARGET_LS64,
+ "__ARM_FEATURE_LS64", pfile);
/* Not for ACLE, but required to keep "float.h" correct if we switch
target between implementations that do or do not support ARMv8.2-A
}
})
+(define_expand "movv8di"
+ [(set (match_operand:V8DI 0 "nonimmediate_operand")
+ (match_operand:V8DI 1 "general_operand"))]
+ "TARGET_SIMD"
+{
+ if (can_create_pseudo_p () && MEM_P (operands[0]))
+ operands[1] = force_reg (V8DImode, operands[1]);
+})
+
(define_expand "aarch64_ld1x3<vstruct_elt>"
[(match_operand:VSTRUCT_3QD 0 "register_operand")
(match_operand:DI 1 "register_operand")]
(set_attr "length" "<insn_count>,4,4")]
)
+(define_insn "*aarch64_movv8di"
+ [(set (match_operand:V8DI 0 "nonimmediate_operand" "=r,m,r")
+ (match_operand:V8DI 1 "general_operand" " r,r,m"))]
+ "!BYTES_BIG_ENDIAN
+ && (register_operand (operands[0], V8DImode)
+ || register_operand (operands[1], V8DImode))"
+ "#"
+ [(set_attr "type" "multiple,multiple,multiple")
+ (set_attr "length" "32,16,16")]
+)
+
(define_insn "aarch64_be_ld1<mode>"
[(set (match_operand:VALLDI_F16 0 "register_operand" "=w")
(unspec:VALLDI_F16 [(match_operand:VALLDI_F16 1
FAIL;
})
+(define_split
+ [(set (match_operand:V8DI 0 "nonimmediate_operand")
+ (match_operand:V8DI 1 "general_operand"))]
+ "TARGET_SIMD && reload_completed"
+ [(const_int 0)]
+{
+ if (register_operand (operands[0], V8DImode)
+ && register_operand (operands[1], V8DImode))
+ {
+ aarch64_simd_emit_reg_reg_move (operands, DImode, 8);
+ DONE;
+ }
+ else if ((register_operand (operands[0], V8DImode)
+ && memory_operand (operands[1], V8DImode))
+ || (memory_operand (operands[0], V8DImode)
+ && register_operand (operands[1], V8DImode)))
+ {
+ for (int offset = 0; offset < 64; offset += 16)
+ emit_move_insn (simplify_gen_subreg (TImode, operands[0],
+ V8DImode, offset),
+ simplify_gen_subreg (TImode, operands[1],
+ V8DImode, offset));
+ DONE;
+ }
+ else
+ FAIL;
+})
+
(define_expand "aarch64_ld<nregs>r<vstruct_elt>"
[(match_operand:VSTRUCT_QD 0 "register_operand")
(match_operand:DI 1 "register_operand")]
&& (aarch64_offset_9bit_signed_unscaled_p (mode, offset)
|| offset_12bit_unsigned_scaled_p (mode, offset)));
+ if (mode == V8DImode)
+ return (aarch64_offset_7bit_signed_scaled_p (DImode, offset)
+ && aarch64_offset_7bit_signed_scaled_p (DImode, offset + 48));
+
/* A 7bit offset check because OImode will emit a ldp/stp
instruction (only big endian will get here).
For ldp/stp instructions, the offset is scaled for the size of a
#define AARCH64_ISA_PAUTH (aarch64_isa_flags & AARCH64_FL_PAUTH)
#define AARCH64_ISA_V9 (aarch64_isa_flags & AARCH64_FL_V9)
#define AARCH64_ISA_MOPS (aarch64_isa_flags & AARCH64_FL_MOPS)
+#define AARCH64_ISA_LS64 (aarch64_isa_flags & AARCH64_FL_LS64)
/* Crypto is an optional extension to AdvSIMD. */
#define TARGET_CRYPTO (TARGET_SIMD && AARCH64_ISA_CRYPTO)
/* MOPS instructions are enabled through +mops. */
#define TARGET_MOPS (AARCH64_ISA_MOPS)
+/* LS64 instructions are enabled through +ls64. */
+#define TARGET_LS64 (AARCH64_ISA_LS64)
+
/* Make sure this is always defined so we don't have to check for ifdefs
but rather use normal ifs. */
#ifndef TARGET_FIX_ERR_A53_835769_DEFAULT
UNSPEC_LD2_LANE
UNSPEC_LD3_LANE
UNSPEC_LD4_LANE
+ UNSPEC_LD64B
+ UNSPEC_ST64B
+ UNSPEC_ST64BV
+ UNSPEC_ST64BV_RET
+ UNSPEC_ST64BV0
+ UNSPEC_ST64BV0_RET
UNSPEC_MB
UNSPEC_MOVMEM
UNSPEC_NOP
[(set_attr "type" "memtag")]
)
+;; Load/Store 64-bit (LS64) instructions.
+(define_insn "ld64b"
+ [(set (match_operand:V8DI 0 "register_operand" "=r")
+ (unspec_volatile:V8DI
+ [(mem:V8DI (match_operand:DI 1 "register_operand" "r"))]
+ UNSPEC_LD64B)
+ )]
+ "TARGET_LS64"
+ "ld64b\\t%0, [%1]"
+ [(set_attr "type" "ls64")]
+)
+
+(define_insn "st64b"
+ [(set (mem:V8DI (match_operand:DI 0 "register_operand" "=r"))
+ (unspec_volatile:V8DI [(match_operand:V8DI 1 "register_operand" "r")]
+ UNSPEC_ST64B)
+ )]
+ "TARGET_LS64"
+ "st64b\\t%1, [%0]"
+ [(set_attr "type" "ls64")]
+)
+
+(define_insn "st64bv"
+ [(set (match_operand:DI 0 "register_operand" "=r")
+ (unspec_volatile:DI [(const_int 0)] UNSPEC_ST64BV_RET))
+ (set (mem:V8DI (match_operand:DI 1 "register_operand" "r"))
+ (unspec_volatile:V8DI [(match_operand:V8DI 2 "register_operand" "r")]
+ UNSPEC_ST64BV)
+ )]
+ "TARGET_LS64"
+ "st64bv\\t%0, %2, [%1]"
+ [(set_attr "type" "ls64")]
+)
+
+(define_insn "st64bv0"
+ [(set (match_operand:DI 0 "register_operand" "=r")
+ (unspec_volatile:DI [(const_int 0)] UNSPEC_ST64BV0_RET))
+ (set (mem:V8DI (match_operand:DI 1 "register_operand" "r"))
+ (unspec_volatile:V8DI [(match_operand:V8DI 2 "register_operand" "r")]
+ UNSPEC_ST64BV0)
+ )]
+ "TARGET_LS64"
+ "st64bv0\\t%0, %2, [%1]"
+ [(set_attr "type" "ls64")]
+)
+
;; AdvSIMD Stuff
(include "aarch64-simd.md")
#pragma GCC pop_options
#endif
+#ifdef __ARM_FEATURE_LS64
+#pragma GCC push_options
+#pragma GCC target ("+nothing+ls64")
+
+typedef __arm_data512_t data512_t;
+
+__extension__ extern __inline data512_t
+__attribute__ ((__always_inline__, __gnu_inline__, __artificial__))
+__arm_ld64b (const void *__addr)
+{
+ return __builtin_aarch64_ld64b (__addr);
+}
+
+__extension__ extern __inline void
+__attribute__ ((__always_inline__, __gnu_inline__, __artificial__))
+__arm_st64b (void *__addr, data512_t __value)
+{
+ __builtin_aarch64_st64b (__addr, __value);
+}
+
+__extension__ extern __inline uint64_t
+__attribute__ ((__always_inline__, __gnu_inline__, __artificial__))
+__arm_st64bv (void *__addr, data512_t __value)
+{
+ return __builtin_aarch64_st64bv (__addr, __value);
+}
+
+__extension__ extern __inline uint64_t
+__attribute__ ((__always_inline__, __gnu_inline__, __artificial__))
+__arm_st64bv0 (void *__addr, data512_t __value)
+{
+ return __builtin_aarch64_st64bv0 (__addr, __value);
+}
+
+#pragma GCC pop_options
+#endif
+
#pragma GCC push_options
#pragma GCC target ("+nothing+rng")
__extension__ extern __inline int
coproc,\
tme,\
memtag,\
+ ls64,\
mve_move,\
mve_store,\
mve_load"
--- /dev/null
+/* { dg-do compile } */
+/* { dg-options "-march=armv8-a+ls64 -O2" } */
+
+#ifndef __ARM_FEATURE_LS64
+#error "__ARM_FEATURE_LS64 is not defined but should be!"
+#endif
+
+/* Inline assembly for LS64 instructions. */
+
+#include <arm_acle.h>
+
+void
+ls64_load (data512_t *output, const void *addr)
+{
+ __asm__ volatile ("ld64b %0, [%1]"
+ : "=r" (*output)
+ : "r" (addr)
+ : "memory");
+}
+
+/* { dg-final { scan-assembler-times {ld64b } 1 } } */
+
+void
+ls64_store (const data512_t *input, void *addr)
+{
+ __asm__ volatile ("st64b %1, [%0]"
+ : /* No outputs. */
+ : "r" (addr), "r" (*input)
+ : "memory");
+}
+
+/* { dg-final { scan-assembler-times {st64b } 1 } } */
+
+uint64_t
+ls64_store_v (const data512_t *input, void *addr)
+{
+ uint64_t status;
+ __asm__ volatile ("st64bv %0, %2, [%1]"
+ : "=r" (status)
+ : "r" (addr), "r" (*input)
+ : "memory");
+ return status;
+}
+
+/* { dg-final { scan-assembler-times {st64bv } 1 } } */
+
+uint64_t
+ls64_store_v0 (const data512_t *input, void *addr)
+{
+ uint64_t status;
+ __asm__ volatile ("st64bv0 %0, %2, [%1]"
+ : "=r" (status)
+ : "r" (addr), "r" (*input)
+ : "memory");
+ return status;
+}
+
+/* { dg-final { scan-assembler-times {st64bv0 } 1 } } */
--- /dev/null
+/* { dg-do compile } */
+/* { dg-options "-march=armv8-a+ls64 -O2" } */
+
+#ifndef __ARM_FEATURE_LS64
+#error "__ARM_FEATURE_LS64 is not defined but should be!"
+#endif
+
+#include <arm_acle.h>
+
+void
+func (const void * addr) {
+ data512_t ret = __arm_ld64b (addr);
+}
+
+/* { dg-final { scan-assembler-times {ld64b\t} 1 } } */
--- /dev/null
+/* { dg-do compile } */
+/* { dg-options "-march=armv8-a+ls64 -O2" } */
+
+#ifndef __ARM_FEATURE_LS64
+#error "__ARM_FEATURE_LS64 is not defined but should be!"
+#endif
+
+#include <arm_acle.h>
+
+void
+func(const void * addr, data512_t *data) {
+ *data = __arm_ld64b (addr);
+}
+
+/* { dg-final { scan-assembler-times {ld64b\t} 1 } } */
--- /dev/null
+/* { dg-do compile } */
+/* { dg-options "-march=armv8-a+ls64 -O2" } */
+
+#ifndef __ARM_FEATURE_LS64
+#error "__ARM_FEATURE_LS64 is not defined but should be!"
+#endif
+
+#include <arm_acle.h>
+
+data512_t
+func(const void * addr) {
+ return __arm_ld64b (addr);
+}
+
+/* { dg-final { scan-assembler-times {ld64b\t} 1 } } */
--- /dev/null
+/* { dg-do compile } */
+/* { dg-options "-march=armv8-a+ls64 -O0" } */
+
+#ifndef __ARM_FEATURE_LS64
+#error "__ARM_FEATURE_LS64 is not defined but should be!"
+#endif
+
+#include <arm_acle.h>
+
+/* Make sure no issues when compile with -O0. */
+
+data512_t
+func1 (const void * addr) {
+ return __arm_ld64b (addr);
+}
+
+void
+func2 (void *addr, data512_t value) {
+ __arm_st64b (addr, value);
+}
+
+uint64_t
+func3 (void *addr, data512_t value) {
+ return __arm_st64bv (addr, value);
+}
+
+uint64_t
+func4 (void *addr, data512_t value) {
+ return __arm_st64bv0 (addr, value);
+}
--- /dev/null
+/* { dg-do compile } */
+/* { dg-options "-march=armv8-a+ls64 -O2" } */
+
+#ifndef __ARM_FEATURE_LS64
+#error "__ARM_FEATURE_LS64 is not defined but should be!"
+#endif
+
+#include <arm_acle.h>
+
+void
+func(void *addr, data512_t *value) {
+ __arm_st64b (addr, *value);
+}
+
+/* { dg-final { scan-assembler-times {st64b\t} 1 } } */
--- /dev/null
+/* { dg-do compile } */
+/* { dg-options "-march=armv8-a+ls64 -O2" } */
+
+#ifndef __ARM_FEATURE_LS64
+#error "__ARM_FEATURE_LS64 is not defined but should be!"
+#endif
+
+#include <arm_acle.h>
+
+void
+func(void *addr, data512_t value) {
+ __arm_st64b (addr, value);
+}
+
+/* { dg-final { scan-assembler-times {st64b\t} 1 } } */
--- /dev/null
+/* { dg-do compile } */
+/* { dg-options "-march=armv8-a+ls64 -O2" } */
+
+#ifndef __ARM_FEATURE_LS64
+#error "__ARM_FEATURE_LS64 is not defined but should be!"
+#endif
+
+#include <arm_acle.h>
+
+void
+func(void *addr, data512_t value) {
+ __arm_st64bv (addr, value);
+}
+
+/* { dg-final { scan-assembler-times {st64bv\t} 1 } } */
--- /dev/null
+/* { dg-do compile } */
+/* { dg-options "-march=armv8-a+ls64 -O2" } */
+
+#ifndef __ARM_FEATURE_LS64
+#error "__ARM_FEATURE_LS64 is not defined but should be!"
+#endif
+
+#include <arm_acle.h>
+
+void
+func(void *addr, data512_t *value) {
+ __arm_st64bv (addr, *value);
+}
+
+/* { dg-final { scan-assembler-times {st64bv\t} 1 } } */
--- /dev/null
+/* { dg-do compile } */
+/* { dg-options "-march=armv8-a+ls64 -O2" } */
+
+#ifndef __ARM_FEATURE_LS64
+#error "__ARM_FEATURE_LS64 is not defined but should be!"
+#endif
+
+#include <arm_acle.h>
+
+uint64_t
+func(void *addr, data512_t value) {
+ return __arm_st64bv (addr, value);
+}
+
+/* { dg-final { scan-assembler-times {st64bv\t} 1 } } */
--- /dev/null
+/* { dg-do compile } */
+/* { dg-options "-march=armv8-a+ls64 -O2" } */
+
+#ifndef __ARM_FEATURE_LS64
+#error "__ARM_FEATURE_LS64 is not defined but should be!"
+#endif
+
+#include <arm_acle.h>
+
+void
+func(void *addr, data512_t value) {
+ __arm_st64bv0 (addr, value);
+}
+
+/* { dg-final { scan-assembler-times {st64bv0\t} 1 } } */
--- /dev/null
+/* { dg-do compile } */
+/* { dg-options "-march=armv8-a+ls64 -O2" } */
+
+#ifndef __ARM_FEATURE_LS64
+#error "__ARM_FEATURE_LS64 is not defined but should be!"
+#endif
+
+#include <arm_acle.h>
+
+void
+func(void *addr, data512_t *value) {
+ __arm_st64bv0 (addr, *value);
+}
+
+/* { dg-final { scan-assembler-times {st64bv0\t} 1 } } */
--- /dev/null
+/* { dg-do compile } */
+/* { dg-options "-march=armv8-a+ls64 -O2" } */
+
+#ifndef __ARM_FEATURE_LS64
+#error "__ARM_FEATURE_LS64 is not defined but should be!"
+#endif
+
+#include <arm_acle.h>
+
+uint64_t
+func(void *addr, data512_t value) {
+ return __arm_st64bv0 (addr, value);
+}
+
+/* { dg-final { scan-assembler-times {st64bv0\t} 1 } } */
#endif
#pragma GCC pop_options
+#pragma GCC push_options
+#pragma GCC target ("arch=armv8.7-a")
+#ifndef __ARM_FEATURE_LS64
+#error "__ARM_FEATURE_LS64 is not defined but should be!"
+#endif
+#pragma GCC pop_options
+
+#pragma GCC push_options
+#pragma GCC target ("arch=armv8.7-a+ls64")
+#ifndef __ARM_FEATURE_LS64
+#error "__ARM_FEATURE_LS64 is not defined but should be!"
+#endif
+#pragma GCC pop_options
+
#pragma GCC pop_options
int