Thanks,
Srinath
gcc/ChangeLog:
2019-11-11 Andre Vieira <andre.simoesdiasvie...@arm.com>
Mihail Ionescu <mihail.ione...@arm.com>
Srinath Parvathaneni <srinath.parvathan...@arm.com>
* config.gcc (arm_mve.h): Add header file.
* config/arm/aout.h (p0): Add new register name.
* config/arm-builtins.c (ARM_BUILTIN_SIMD_LANE_CHECK): Define.
(ARM_BUILTIN_NEON_LANE_CHECK): Remove.
(arm_init_simd_builtin_types): Add TARGET_HAVE_MVE check.
(arm_init_neon_builtins): Move a check to arm_init_builtins
function.
(arm_init_builtins): Move a check from arm_init_neon_builtins
function.
(mve_dereference_pointer): Add new function.
(arm_expand_builtin_args): Add TARGET_HAVE_MVE check.
(arm_expand_neon_builtin): Move a check to arm_expand_builtin
function.
(arm_expand_builtin): Move a check from
arm_expand_neon_builtin function.
* config/arm/arm-c.c (arm_cpu_builtins): Define macros for MVE.
* config/arm/arm-modes.def (INT_MODE): Add three new integer
modes.
* config/arm/arm-protos.h (neon_immediate_valid_for_move):
Rename function.
(simd_immediate_valid_for_move): Rename
neon_immediate_valid_for_move function.
* config/arm/arm.c
(arm_options_perform_arch_sanity_checks):Enable mve isa bit.
(use_return_insn): Add TARGET_HAVE_MVE check.
(aapcs_vfp_allocate): Add TARGET_HAVE_MVE check.
(aapcs_vfp_allocate_return_reg): Add TARGET_HAVE_MVE check.
(thumb2_legitimate_address_p): Add TARGET_HAVE_MVE check.
(arm_rtx_costs_internal): Add TARGET_HAVE_MVE check.
(neon_valid_immediate): Rename to simd_valid_immediate.
(simd_valid_immediate): Rename from neon_valid_immediate.
(neon_immediate_valid_for_move): Rename to
simd_immediate_valid_for_move.
(simd_immediate_valid_for_move): Rename from
neon_immediate_valid_for_move.
(neon_immediate_valid_for_logic): Modify call to
neon_valid_immediate function.
(neon_make_constant): Modify call to neon_valid_immediate
function.
(neon_vector_mem_operand): Add TARGET_HAVE_MVE check.
(output_move_neon): Add TARGET_HAVE_MVE check.
(arm_compute_frame_layout): Add TARGET_HAVE_MVE check.
(arm_save_coproc_regs): Add TARGET_HAVE_MVE check.
(arm_print_operand): Add case 'E' to print memory operands.
(arm_print_operand_address): Add TARGET_HAVE_MVE check.
(arm_hard_regno_mode_ok): Add TARGET_HAVE_MVE check.
(arm_modes_tieable_p): Add TARGET_HAVE_MVE check.
(arm_regno_class): Add VPR_REGNUM check.
(arm_expand_epilogue_apcs_frame): Add TARGET_HAVE_MVE check.
(arm_expand_epilogue): Add TARGET_HAVE_MVE check.
(arm_vector_mode_supported_p): Add TARGET_HAVE_MVE check for
MVE vector modes.
(arm_array_mode_supported_p): Add TARGET_HAVE_MVE check.
(arm_conditional_register_usage): For TARGET_HAVE_MVE enable
VPR register.
* config/arm/arm.h (IS_VPR_REGNUM): Macro to check for VPR
register.
(FIRST_PSEUDO_REGISTER): Modify.
(VALID_MVE_MODE): Define.
(VALID_MVE_SI_MODE): Define.
(VALID_MVE_SF_MODE): Define.
(VALID_MVE_STRUCT_MODE): Define.
(REG_ALLOC_ORDER): Add VPR_REGNUM entry.
(enum reg_class): Add VPR_REG entry.
(REG_CLASS_NAMES): Add VPR_REG entry.
* config/arm/arm.md (VPR_REGNUM): Define.
(arm_movsf_soft_insn): Add TARGET_HAVE_MVE check to not allow MVE.
(vfp_pop_multiple_with_writeback): Add TARGET_HAVE_MVE check
to allow writeback.
(include "mve.md"): Include mve.md file.
* config/arm/arm_mve.h: New file.
* config/arm/constraints.md (Up): Define.
* config/arm/iterators.md (VNIM1): Define.
(VNINOTM1): Define.
(VSTRUCT): Modify.
* config/arm/mve.md: New file.
* config/arm/neon.md:
(mov<mode>): Add TARGET_HAVE_MVE check.
(movv4hf): Define.
(neon_mov<mode>): Add TARGET_HAVE_MVE check.
(define_split): Add TARGET_HAVE_MVE check.
(vec_init<mode><V_elem_l>): Add TARGET_HAVE_MVE check.
* config/arm/predicates.md (vpr_register_operand): Define.
* config/arm/t-arm: Add mve.md file.
* config/arm/types.md: Add MVE instructions mve_move,
mve_load, mve_store.
* config/arm/vec-common.md (mov<mode>): Add TARGET_HAVE_MVE check.
(mov<mode>): Modify iterator.
(movv8hf): Define
gcc/testsuite/ChangeLog:
2019-11-11 Andre Vieira <andre.simoesdiasvie...@arm.com>
Mihail Ionescu <mihail.ione...@arm.com>
Srinath Parvathaneni <srinath.parvathan...@arm.com>
* gcc.target/arm/mve/intrinsics/mve_vector_float.c: New test.
* gcc.target/arm/mve/intrinsics/mve_vector_float1.c: Likewise.
* gcc.target/arm/mve/intrinsics/mve_vector_float2.c: Likewise.
* gcc.target/arm/mve/intrinsics/mve_vector_int.c: Likewise.
* gcc.target/arm/mve/intrinsics/mve_vector_int1.c: Likewise.
* gcc.target/arm/mve/intrinsics/mve_vector_int2.c: Likewise.
* gcc.target/arm/mve/intrinsics/mve_vector_uint.c: Likewise.
* gcc.target/arm/mve/intrinsics/mve_vector_uint1.c: Likewise.
* gcc.target/arm/mve/intrinsics/mve_vector_uint2.c: Likewise.
* gcc.target/arm/mve/mve.exp: New file.
############### Attachment also inlined for ease of reply
###############
diff --git a/gcc/config.gcc b/gcc/config.gcc
index
72f656408f11802c669c3de953bf3020020ca312..c4a7d984936c531d7dfcce347d56b5931913e68b
100644
--- a/gcc/config.gcc
+++ b/gcc/config.gcc
@@ -344,7 +344,7 @@ arc*-*-*)
arm*-*-*)
cpu_type=arm
extra_objs="arm-builtins.o aarch-common.o"
- extra_headers="mmintrin.h arm_neon.h arm_acle.h arm_fp16.h
arm_cmse.h"
+ extra_headers="mmintrin.h arm_neon.h arm_acle.h arm_fp16.h
arm_cmse.h arm_mve.h"
target_type_format_char='%'
c_target_objs="arm-c.o"
cxx_target_objs="arm-c.o"
diff --git a/gcc/config/arm/aout.h b/gcc/config/arm/aout.h
index
72782758853a869bcb9a9d69f3fa0da979cd711f..28cde153f704748f35c84d072b59e9695a61e661
100644
--- a/gcc/config/arm/aout.h
+++ b/gcc/config/arm/aout.h
@@ -53,7 +53,9 @@
/* The assembler's names for the registers. Note that the ?xx
registers are
there so that VFPv3/NEON registers D16-D31 have the same spacing
as D0-D15
(each of which is overlaid on two S registers), although there are no
- actual single-precision registers which correspond to D16-D31. */
+ actual single-precision registers which correspond to D16-D31.
New register
+ p0 is added which is used for MVE predicated cases. */
+
#ifndef REGISTER_NAMES
#define REGISTER_NAMES \
{ \
@@ -72,7 +74,7 @@
"wr8", "wr9", "wr10", "wr11", \
"wr12", "wr13", "wr14", "wr15", \
"wcgr0", "wcgr1", "wcgr2", "wcgr3", \
- "cc", "vfpcc", "sfp", "afp", "apsrq", "apsrge" \
+ "cc", "vfpcc", "sfp", "afp", "apsrq", "apsrge", "p0" \
}
#endif
diff --git a/gcc/config/arm/arm-builtins.c b/gcc/config/arm/arm-builtins.c
index
650b22c7ad916d9abd587981e9ed5809755ee035..d4cb0ea3deb49b10266d1620c85e243ed34aee4d
100644
--- a/gcc/config/arm/arm-builtins.c
+++ b/gcc/config/arm/arm-builtins.c
@@ -667,6 +667,7 @@ enum arm_builtins
ARM_BUILTIN_SET_FPSCR,
ARM_BUILTIN_CMSE_NONSECURE_CALLER,
+ ARM_BUILTIN_SIMD_LANE_CHECK,
#undef CRYPTO1
#undef CRYPTO2
@@ -692,7 +693,6 @@ enum arm_builtins
#include "arm_vfp_builtins.def"
ARM_BUILTIN_NEON_BASE,
- ARM_BUILTIN_NEON_LANE_CHECK = ARM_BUILTIN_NEON_BASE,
#include "arm_neon_builtins.def"
@@ -948,26 +948,35 @@ arm_init_simd_builtin_types (void)
an entry in our mangling table, consequently, they get default
mangling. As a further gotcha, poly8_t and poly16_t are signed
types, poly64_t and poly128_t are unsigned types. */
- arm_simd_polyQI_type_node
- = build_distinct_type_copy (intQI_type_node);
- (*lang_hooks.types.register_builtin_type) (arm_simd_polyQI_type_node,
- "__builtin_neon_poly8");
- arm_simd_polyHI_type_node
- = build_distinct_type_copy (intHI_type_node);
- (*lang_hooks.types.register_builtin_type) (arm_simd_polyHI_type_node,
- "__builtin_neon_poly16");
- arm_simd_polyDI_type_node
- = build_distinct_type_copy (unsigned_intDI_type_node);
- (*lang_hooks.types.register_builtin_type) (arm_simd_polyDI_type_node,
- "__builtin_neon_poly64");
- arm_simd_polyTI_type_node
- = build_distinct_type_copy (unsigned_intTI_type_node);
- (*lang_hooks.types.register_builtin_type) (arm_simd_polyTI_type_node,
- "__builtin_neon_poly128");
- /* Prevent front-ends from transforming poly vectors into string
- literals. */
- TYPE_STRING_FLAG (arm_simd_polyQI_type_node) = false;
- TYPE_STRING_FLAG (arm_simd_polyHI_type_node) = false;
+ if (!TARGET_HAVE_MVE)
+ {
+ arm_simd_polyQI_type_node
+ = build_distinct_type_copy (intQI_type_node);
+ (*lang_hooks.types.register_builtin_type)
(arm_simd_polyQI_type_node,
+ "__builtin_neon_poly8");
+ arm_simd_polyHI_type_node
+ = build_distinct_type_copy (intHI_type_node);
+ (*lang_hooks.types.register_builtin_type)
(arm_simd_polyHI_type_node,
+ "__builtin_neon_poly16");
+ arm_simd_polyDI_type_node
+ = build_distinct_type_copy (unsigned_intDI_type_node);
+ (*lang_hooks.types.register_builtin_type)
(arm_simd_polyDI_type_node,
+ "__builtin_neon_poly64");
+ arm_simd_polyTI_type_node
+ = build_distinct_type_copy (unsigned_intTI_type_node);
+ (*lang_hooks.types.register_builtin_type)
(arm_simd_polyTI_type_node,
+ "__builtin_neon_poly128");
+ /* Init poly vector element types with scalar poly types. */
+ arm_simd_types[Poly8x8_t].eltype = arm_simd_polyQI_type_node;
+ arm_simd_types[Poly8x16_t].eltype = arm_simd_polyQI_type_node;
+ arm_simd_types[Poly16x4_t].eltype = arm_simd_polyHI_type_node;
+ arm_simd_types[Poly16x8_t].eltype = arm_simd_polyHI_type_node;
+
+ /* Prevent front-ends from transforming poly vectors into string
+ literals. */
+ TYPE_STRING_FLAG (arm_simd_polyQI_type_node) = false;
+ TYPE_STRING_FLAG (arm_simd_polyHI_type_node) = false;
+ }
/* Init all the element types built by the front-end. */
arm_simd_types[Int8x8_t].eltype = intQI_type_node;
@@ -985,11 +994,6 @@ arm_init_simd_builtin_types (void)
arm_simd_types[Uint32x4_t].eltype = unsigned_intSI_type_node;
arm_simd_types[Uint64x2_t].eltype = unsigned_intDI_type_node;
- /* Init poly vector element types with scalar poly types. */
- arm_simd_types[Poly8x8_t].eltype = arm_simd_polyQI_type_node;
- arm_simd_types[Poly8x16_t].eltype = arm_simd_polyQI_type_node;
- arm_simd_types[Poly16x4_t].eltype = arm_simd_polyHI_type_node;
- arm_simd_types[Poly16x8_t].eltype = arm_simd_polyHI_type_node;
/* Note: poly64x2_t is defined in arm_neon.h, to ensure it gets default
mangling. */
@@ -1006,6 +1010,8 @@ arm_init_simd_builtin_types (void)
tree eltype = arm_simd_types[i].eltype;
machine_mode mode = arm_simd_types[i].mode;
+ if (eltype == NULL)
+ continue;
if (arm_simd_types[i].itype == NULL)
arm_simd_types[i].itype =
build_distinct_type_copy
@@ -1231,15 +1237,6 @@ arm_init_neon_builtins (void)
system. */
arm_init_simd_builtin_scalar_types ();
- tree lane_check_fpr = build_function_type_list (void_type_node,
- intSI_type_node,
- intSI_type_node,
- NULL);
- arm_builtin_decls[ARM_BUILTIN_NEON_LANE_CHECK] =
- add_builtin_function ("__builtin_arm_lane_check", lane_check_fpr,
- ARM_BUILTIN_NEON_LANE_CHECK, BUILT_IN_MD,
- NULL, NULL_TREE);
-
for (i = 0; i < ARRAY_SIZE (neon_builtin_data); i++, fcode++)
{
arm_builtin_datum *d = &neon_builtin_data[i];
@@ -1956,6 +1953,15 @@ arm_init_builtins (void)
if (TARGET_MAYBE_HARD_FLOAT)
{
+ tree lane_check_fpr = build_function_type_list (void_type_node,
+ intSI_type_node,
+ intSI_type_node,
+ NULL);
+ arm_builtin_decls[ARM_BUILTIN_SIMD_LANE_CHECK]
+ = add_builtin_function ("__builtin_arm_lane_check", lane_check_fpr,
+ ARM_BUILTIN_SIMD_LANE_CHECK, BUILT_IN_MD,
+ NULL, NULL_TREE);
+
arm_init_neon_builtins ();
arm_init_vfp_builtins ();
arm_init_crypto_builtins ();
@@ -2201,6 +2207,47 @@ neon_dereference_pointer (tree exp, tree type,
machine_mode mem_mode,
build_int_cst (build_pointer_type (array_type),
0));
}
+/* EXP is a pointer argument to a vector scatter store intrinsics.
+
+ Consider the following example:
+ VSTRW<v>.<dt> Qd, [Qm{, #+/-<imm>}]!
+ When <Qm> used as the base register for the target address,
+ this function is used to derive and return an expression for the
+ accessed memory.
+
+ The intrinsic function operates on a block of registers that has mode
+ REG_MODE. This block contains vectors of type TYPE_MODE. The
function
+ references the memory at EXP of type TYPE and in mode MEM_MODE. This
+ mode may be BLKmode if no more suitable mode is available. */
+
+static tree
+mve_dereference_pointer (tree exp, tree type, machine_mode reg_mode,
+ machine_mode vector_mode)
+{
+ HOST_WIDE_INT reg_size, vector_size, nelems;
+ tree elem_type, upper_bound, array_type;
+
+ /* Work out the size of each vector in bytes. */
+ vector_size = GET_MODE_SIZE (vector_mode);
+
+ /* Work out the size of the register block in bytes. */
+ reg_size = GET_MODE_SIZE (reg_mode);
+
+ /* Work out the type of each element. */
+ gcc_assert (POINTER_TYPE_P (type));
+ elem_type = TREE_TYPE (type);
+
+ nelems = reg_size / vector_size;
+
+ /* Create a type that describes the full access. */
+ upper_bound = build_int_cst (size_type_node, nelems - 1);
+ array_type = build_array_type (elem_type, build_index_type
(upper_bound));
+
+ /* Dereference EXP using that type. */
+ return fold_build2 (MEM_REF, array_type, exp,
+ build_int_cst (build_pointer_type (array_type), 0));
+}
+
/* Expand a builtin. */
static rtx
arm_expand_builtin_args (rtx target, machine_mode map_mode, int fcode,
@@ -2239,10 +2286,17 @@ arm_expand_builtin_args (rtx target,
machine_mode map_mode, int fcode,
{
machine_mode other_mode
= insn_data[icode].operand[1 - opno].mode;
- arg[argc] = neon_dereference_pointer (arg[argc],
+ if (TARGET_HAVE_MVE && mode[argc] != other_mode)
+ {
+ arg[argc] = mve_dereference_pointer (arg[argc],
TREE_VALUE (formals),
- mode[argc], other_mode,
- map_mode);
+ other_mode, map_mode);
+ }
+ else
+ arg[argc] = neon_dereference_pointer (arg[argc],
+ TREE_VALUE (formals),
+ mode[argc], other_mode,
+ map_mode);
}
/* Use EXPAND_MEMORY for ARG_BUILTIN_MEMORY and
@@ -2548,22 +2602,6 @@ arm_expand_neon_builtin (int fcode, tree exp,
rtx target)
return const0_rtx;
}
- if (fcode == ARM_BUILTIN_NEON_LANE_CHECK)
- {
- /* Builtin is only to check bounds of the lane passed to some
intrinsics
- that are implemented with gcc vector extensions in
arm_neon.h. */
-
- tree nlanes = CALL_EXPR_ARG (exp, 0);
- gcc_assert (TREE_CODE (nlanes) == INTEGER_CST);
- rtx lane_idx = expand_normal (CALL_EXPR_ARG (exp, 1));
- if (CONST_INT_P (lane_idx))
- neon_lane_bounds (lane_idx, 0, TREE_INT_CST_LOW (nlanes), exp);
- else
- error ("%Klane index must be a constant immediate", exp);
- /* Don't generate any RTL. */
- return const0_rtx;
- }
-
arm_builtin_datum *d
= &neon_builtin_data[fcode - ARM_BUILTIN_NEON_PATTERN_START];
@@ -2625,6 +2663,22 @@ arm_expand_builtin (tree exp,
int mask;
int imm;
+ if (fcode == ARM_BUILTIN_SIMD_LANE_CHECK)
+ {
+ /* Builtin is only to check bounds of the lane passed to some
intrinsics
+ that are implemented with gcc vector extensions in
arm_neon.h. */
+
+ tree nlanes = CALL_EXPR_ARG (exp, 0);
+ gcc_assert (TREE_CODE (nlanes) == INTEGER_CST);
+ rtx lane_idx = expand_normal (CALL_EXPR_ARG (exp, 1));
+ if (CONST_INT_P (lane_idx))
+ neon_lane_bounds (lane_idx, 0, TREE_INT_CST_LOW (nlanes), exp);
+ else
+ error ("%Klane index must be a constant immediate", exp);
+ /* Don't generate any RTL. */
+ return const0_rtx;
+ }
+
if (fcode >= ARM_BUILTIN_ACLE_BASE)
return arm_expand_acle_builtin (fcode, exp, target);
diff --git a/gcc/config/arm/arm-c.c b/gcc/config/arm/arm-c.c
index
34695fa0112e90e4bdf317da0b9fd1d3194bf0a2..0fe7d371c348818f25901c5d84be94589523c9a6
100644
--- a/gcc/config/arm/arm-c.c
+++ b/gcc/config/arm/arm-c.c
@@ -79,6 +79,16 @@ arm_cpu_builtins (struct cpp_reader* pfile)
def_or_undef_macro (pfile, "__ARM_FEATURE_COMPLEX", TARGET_COMPLEX);
def_or_undef_macro (pfile, "__ARM_32BIT_STATE", TARGET_32BIT);
+ cpp_undef (pfile, "__ARM_FEATURE_MVE");
+ if (TARGET_HAVE_MVE && TARGET_HAVE_MVE_FLOAT)
+ {
+ builtin_define_with_int_value ("__ARM_FEATURE_MVE", 3);
+ }
+ else if (TARGET_HAVE_MVE)
+ {
+ builtin_define_with_int_value ("__ARM_FEATURE_MVE", 1);
+ }
+
cpp_undef (pfile, "__ARM_FEATURE_CMSE");
if (arm_arch8 && !arm_arch_notm)
{
diff --git a/gcc/config/arm/arm-protos.h b/gcc/config/arm/arm-protos.h
index
5b49049cc45c0bccfa9d67eac0940250fc5dd95a..d4612ae4553697989611d772f7bb0061a04b98b6
100644
--- a/gcc/config/arm/arm-protos.h
+++ b/gcc/config/arm/arm-protos.h
@@ -85,7 +85,7 @@ extern bool ldm_stm_operation_p (rtx, bool,
machine_mode mode,
extern bool clear_operation_p (rtx, bool);
extern int arm_const_double_rtx (rtx);
extern int vfp3_const_double_rtx (rtx);
-extern int neon_immediate_valid_for_move (rtx, machine_mode, rtx *,
int *);
+extern int simd_immediate_valid_for_move (rtx, machine_mode, rtx *,
int *);
extern int neon_immediate_valid_for_logic (rtx, machine_mode, int, rtx *,
int *);
extern int neon_immediate_valid_for_shift (rtx, machine_mode, rtx *,
diff --git a/gcc/config/arm/arm.h b/gcc/config/arm/arm.h
index
8b07c423fb6b071642fccc48424fe244d97dcbc2..c755df420b52798773ee99f54faf6689d4a16215
100644
--- a/gcc/config/arm/arm.h
+++ b/gcc/config/arm/arm.h
@@ -751,7 +751,8 @@ extern int arm_arch_cmse;
/* s0-s15 VFP scratch (aka d0-d7).
s16-s31 S VFP variable (aka d8-d15).
vfpcc Not a real register. Represents the VFP
condition
- code flags. */
+ code flags.
+ vpr Used to represent MVE VPR predication. */
/* The stack backtrace structure is as follows:
fp points to here: | save code pointer | [fp]
@@ -792,7 +793,7 @@ extern int arm_arch_cmse;
1,1,1,1,1,1,1,1, \
1,1,1,1, \
/* Specials. */ \
- 1,1,1,1,1,1 \
+ 1,1,1,1,1,1,1 \
}
/* 1 for registers not available across function calls.
@@ -822,7 +823,7 @@ extern int arm_arch_cmse;
1,1,1,1,1,1,1,1, \
1,1,1,1, \
/* Specials. */ \
- 1,1,1,1,1,1 \
+ 1,1,1,1,1,1,1 \
}
#ifndef SUBTARGET_CONDITIONAL_REGISTER_USAGE
@@ -998,10 +999,10 @@ extern int arm_arch_cmse;
&& (LAST_VFP_REGNUM - (REGNUM) >= 2 * (N) - 1))
/* The number of hard registers is 16 ARM + 1 CC + 1 SFP + 1 AFP
- + 1 APSRQ + 1 APSRGE. */
+ + 1 APSRQ + 1 APSRGE + 1 VPR. */
/* Intel Wireless MMX Technology registers add 16 + 4 more. */
/* VFP (VFP3) adds 32 (64) + 1 VFPCC. */
-#define FIRST_PSEUDO_REGISTER 106
+#define FIRST_PSEUDO_REGISTER 107
#define DBX_REGISTER_NUMBER(REGNO) arm_dbx_register_number (REGNO)
@@ -1029,11 +1030,26 @@ extern int arm_arch_cmse;
((MODE) == V4SImode || (MODE) == V8HImode || (MODE) == V16QImode \
|| (MODE) == V8HFmode || (MODE) == V4SFmode || (MODE) == V2DImode)
+#define VALID_MVE_MODE(MODE) \
+ ((MODE) == V2DImode ||(MODE) == V4SImode || (MODE) == V8HImode \
+ || (MODE) == V16QImode || (MODE) == V8HFmode || (MODE) == V4SFmode \
+ || (MODE) == V2DFmode)
+
+#define VALID_MVE_SI_MODE(MODE) \
+ ((MODE) == V2DImode ||(MODE) == V4SImode || (MODE) == V8HImode \
+ || (MODE) == V16QImode)
+
+#define VALID_MVE_SF_MODE(MODE) \
+ ((MODE) == V8HFmode || (MODE) == V4SFmode || (MODE) == V2DFmode)
+
/* Structure modes valid for Neon registers. */
#define VALID_NEON_STRUCT_MODE(MODE) \
((MODE) == TImode || (MODE) == EImode || (MODE) == OImode \
|| (MODE) == CImode || (MODE) == XImode)
+#define VALID_MVE_STRUCT_MODE(MODE) \
+ ((MODE) == TImode || (MODE) == OImode || (MODE) == XImode)
+
/* The register numbers in sequence, for passing to
arm_gen_load_multiple. */
extern int arm_regs_in_sequence[];
@@ -1085,9 +1101,13 @@ extern int arm_regs_in_sequence[];
/* Registers not for general use. */ \
CC_REGNUM, VFPCC_REGNUM, \
FRAME_POINTER_REGNUM, ARG_POINTER_REGNUM, \
- SP_REGNUM, PC_REGNUM, APSRQ_REGNUM, APSRGE_REGNUM \
+ SP_REGNUM, PC_REGNUM, APSRQ_REGNUM, APSRGE_REGNUM, \
+ VPR_REGNUM \
}
+#define IS_VPR_REGNUM(REGNUM) \
+ ((REGNUM) == VPR_REGNUM)
+
/* Use different register alloc ordering for Thumb. */
#define ADJUST_REG_ALLOC_ORDER arm_order_regs_for_local_alloc ()
@@ -1124,6 +1144,7 @@ enum reg_class
VFPCC_REG,
SFP_REG,
AFP_REG,
+ VPR_REG,
ALL_REGS,
LIM_REG_CLASSES
};
@@ -1131,7 +1152,7 @@ enum reg_class
#define N_REG_CLASSES (int) LIM_REG_CLASSES
/* Give names of register classes as strings for dump file. */
-#define REG_CLASS_NAMES \
+#define REG_CLASS_NAMES \
{ \
"NO_REGS", \
"LO_REGS", \
@@ -1151,6 +1172,7 @@ enum reg_class
"VFPCC_REG", \
"SFP_REG", \
"AFP_REG", \
+ "VPR_REG", \
"ALL_REGS" \
}
@@ -1177,7 +1199,8 @@ enum reg_class
{ 0x00000000, 0x00000000, 0x00000000, 0x00000020 }, /* VFPCC_REG */ \
{ 0x00000000, 0x00000000, 0x00000000, 0x00000040 }, /* SFP_REG */ \
{ 0x00000000, 0x00000000, 0x00000000, 0x00000080 }, /* AFP_REG */ \
- { 0xFFFF7FFF, 0xFFFFFFFF, 0xFFFFFFFF, 0x0000000F } /* ALL_REGS */ \
+ { 0x00000000, 0x00000000, 0x00000000, 0x00000100 }, /* VPR_REG. */ \
+ { 0xFFFF7FFF, 0xFFFFFFFF, 0xFFFFFFFF, 0x0000010F } /* ALL_REGS. */ \
}
#define FP_SYSREGS \
diff --git a/gcc/config/arm/arm.c b/gcc/config/arm/arm.c
index
883c2a9179d7e6d69225f8d104228d15702ecef7..6faed76206b93c1a9dea048e2f693dc16ee58072
100644
--- a/gcc/config/arm/arm.c
+++ b/gcc/config/arm/arm.c
@@ -3759,7 +3759,8 @@ arm_options_perform_arch_sanity_checks (void)
else if (TARGET_HARD_FLOAT_ABI)
{
arm_pcs_default = ARM_PCS_AAPCS_VFP;
- if (!bitmap_bit_p (arm_active_target.isa, isa_bit_vfpv2))
+ if (!bitmap_bit_p (arm_active_target.isa, isa_bit_vfpv2)
+ && !bitmap_bit_p (arm_active_target.isa, isa_bit_mve))
error ("%<-mfloat-abi=hard%>: selected processor lacks an
FPU");
}
else
@@ -4230,7 +4231,7 @@ use_return_insn (int iscond, rtx sibling)
/* Can't be done if any of the VFP regs are pushed,
since this also requires an insn. */
- if (TARGET_HARD_FLOAT)
+ if (TARGET_HARD_FLOAT || TARGET_HAVE_MVE)
for (regno = FIRST_VFP_REGNUM; regno <= LAST_VFP_REGNUM; regno++)
�� if (df_regs_ever_live_p (regno) && !call_used_or_fixed_reg_p
(regno))
return 0;
@@ -6289,7 +6290,7 @@ aapcs_vfp_allocate (CUMULATIVE_ARGS *pcum,
machine_mode mode,
{
pcum->aapcs_vfp_reg_alloc = mask << regno;
if (mode == BLKmode
- || (mode == TImode && ! TARGET_NEON)
+ || (mode == TImode && ! (TARGET_NEON || TARGET_HAVE_MVE))
|| ! arm_hard_regno_mode_ok (FIRST_VFP_REGNUM + regno, mode))
{
int i;
@@ -6297,7 +6298,7 @@ aapcs_vfp_allocate (CUMULATIVE_ARGS *pcum,
machine_mode mode,
int rshift = shift;
machine_mode rmode = pcum->aapcs_vfp_rmode;
rtx par;
- if (!TARGET_NEON)
+ if (!(TARGET_NEON || TARGET_HAVE_MVE))
{
/* Avoid using unsupported vector modes. */
if (rmode == V2SImode)
@@ -6343,7 +6344,7 @@ aapcs_vfp_allocate_return_reg (enum arm_pcs
pcs_variant ATTRIBUTE_UNUSED,
if (mode == BLKmode
|| (GET_MODE_CLASS (mode) == MODE_INT
&& GET_MODE_SIZE (mode) >= GET_MODE_SIZE (TImode)
- && !TARGET_NEON))
+ && !(TARGET_NEON || TARGET_HAVE_MVE)))
{
int count;
machine_mode ag_mode;
@@ -6354,7 +6355,7 @@ aapcs_vfp_allocate_return_reg (enum arm_pcs
pcs_variant ATTRIBUTE_UNUSED,
aapcs_vfp_is_call_or_return_candidate (pcs_variant, mode, type,
&ag_mode, &count);
- if (!TARGET_NEON)
+ if (!(TARGET_NEON || TARGET_HAVE_MVE))
{
if (ag_mode == V2SImode)
ag_mode = DImode;
@@ -8253,7 +8254,9 @@ thumb2_legitimate_address_p (machine_mode mode,
rtx x, int strict_p)
&& CONST_INT_P (XEXP (XEXP (x, 0), 1)))))
return 1;
- else if (mode == TImode || (TARGET_NEON && VALID_NEON_STRUCT_MODE
(mode)))
+ else if (mode == TImode
+ || (TARGET_NEON && VALID_NEON_STRUCT_MODE (mode))
+ || (TARGET_HAVE_MVE && VALID_MVE_STRUCT_MODE (mode)))
return 0;
else if (code == PLUS)
@@ -9800,7 +9803,7 @@ arm_rtx_costs_internal (rtx x, enum rtx_code
code, enum rtx_code outer_code,
/* Assume that most copies can be done with a single insn,
unless we don't have HW FP, in which case everything
larger than word mode will require two insns. */
- *cost = COSTS_N_INSNS (((!TARGET_HARD_FLOAT
+ *cost = COSTS_N_INSNS (((!(TARGET_HARD_FLOAT || TARGET_HAVE_MVE)
&& GET_MODE_SIZE (mode) > 4)
|| mode == DImode)
? 2 : 1);
@@ -11281,10 +11284,10 @@ arm_rtx_costs_internal (rtx x, enum rtx_code
code, enum rtx_code outer_code,
case CONST_VECTOR:
/* Fixme. */
- if (TARGET_NEON
- && TARGET_HARD_FLOAT
- && (VALID_NEON_DREG_MODE (mode) || VALID_NEON_QREG_MODE (mode))
- && neon_immediate_valid_for_move (x, mode, NULL, NULL))
+ if (((TARGET_NEON && TARGET_HARD_FLOAT
+ && (VALID_NEON_DREG_MODE (mode) || VALID_NEON_QREG_MODE
(mode)))
+ || TARGET_HAVE_MVE)
+ && simd_immediate_valid_for_move (x, mode, NULL, NULL))
*cost = COSTS_N_INSNS (1);
else
*cost = COSTS_N_INSNS (4);
@@ -12328,8 +12331,8 @@ vfp3_const_double_rtx (rtx x)
return vfp3_const_double_index (x) != -1;
}
-/* Recognize immediates which can be used in various Neon
instructions. Legal
- immediates are described by the following table (for VMVN
variants, the
+/* Recognize immediates which can be used in various Neon and MVE
instructions.
+ Legal immediates are described by the following table (for VMVN
variants, the
bitwise inverse of the constant shown is recognized. In either
case, VMOV
is output and the correct instruction to use for a given constant
is chosen
by the assembler). The constant shown is replicated across all
elements of
@@ -12380,7 +12383,7 @@ vfp3_const_double_rtx (rtx x)
-1 if the given value doesn't match any of the listed patterns.
*/
static int
-neon_valid_immediate (rtx op, machine_mode mode, int inverse,
+simd_valid_immediate (rtx op, machine_mode mode, int inverse,
rtx *modconst, int *elementwidth)
{
#define CHECK(STRIDE, ELSIZE, CLASS, TEST) \
@@ -12412,6 +12415,10 @@ neon_valid_immediate (rtx op, machine_mode
mode, int inverse,
innersize = GET_MODE_UNIT_SIZE (mode);
+ /* Only support 128-bit vectors for MVE. */
+ if (TARGET_HAVE_MVE && (!vector || n_elts * innersize != 16))
+ return -1;
+
/* Vectors of float constants. */
if (GET_MODE_CLASS (mode) == MODE_VECTOR_FLOAT)
{
@@ -12560,18 +12567,19 @@ neon_valid_immediate (rtx op, machine_mode
mode, int inverse,
#undef CHECK
}
-/* Return TRUE if rtx X is legal for use as either a Neon VMOV (or,
implicitly,
- VMVN) immediate. Write back width per element to *ELEMENTWIDTH (or
zero for
- float elements), and a modified constant (whatever should be
output for a
- VMOV) in *MODCONST. */
-
+/* Return TRUE if rtx X is legal for use as either a Neon or MVE VMOV
(or,
+ implicitly, VMVN) immediate. Write back width per element to
*ELEMENTWIDTH
+ (or zero for float elements), and a modified constant (whatever
should be
+ output for a VMOV) in *MODCONST. "neon_immediate_valid_for_move"
function is
+ modified to "simd_immediate_valid_for_move" as this function will
be used
+ both by neon and mve. */
int
-neon_immediate_valid_for_move (rtx op, machine_mode mode,
+simd_immediate_valid_for_move (rtx op, machine_mode mode,
rtx *modconst, int *elementwidth)
{
rtx tmpconst;
int tmpwidth;
- int retval = neon_valid_immediate (op, mode, 0, &tmpconst, &tmpwidth);
+ int retval = simd_valid_immediate (op, mode, 0, &tmpconst, &tmpwidth);
if (retval == -1)
return 0;
@@ -12588,7 +12596,7 @@ neon_immediate_valid_for_move (rtx op,
machine_mode mode,
/* Return TRUE if rtx X is legal for use in a VORR or VBIC
instruction. If
the immediate is valid, write a constant suitable for using as an
operand
to VORR/VBIC/VAND/VORN to *MODCONST and the corresponding element
width to
- *ELEMENTWIDTH. See neon_valid_immediate for description of
INVERSE. */
+ *ELEMENTWIDTH. See simd_valid_immediate for description of
INVERSE. */
int
neon_immediate_valid_for_logic (rtx op, machine_mode mode, int inverse,
@@ -12596,7 +12604,7 @@ neon_immediate_valid_for_logic (rtx op,
machine_mode mode, int inverse,
{
rtx tmpconst;
int tmpwidth;
- int retval = neon_valid_immediate (op, mode, inverse, &tmpconst,
&tmpwidth);
+ int retval = simd_valid_immediate (op, mode, inverse, &tmpconst,
&tmpwidth);
if (retval < 0 || retval > 5)
return 0;
@@ -12803,7 +12811,7 @@ neon_make_constant (rtx vals)
gcc_unreachable ();
if (const_vec != NULL
- && neon_immediate_valid_for_move (const_vec, mode, NULL, NULL))
+ && simd_immediate_valid_for_move (const_vec, mode, NULL, NULL))
/* Load using VMOV. On Cortex-A8 this takes one cycle. */
return const_vec;
else if ((target = neon_vdup_constant (vals)) != NULL_RTX)
@@ -13080,6 +13088,15 @@ neon_vector_mem_operand (rtx op, int type,
bool strict)
&& (INTVAL (XEXP (ind, 1)) & 3) == 0)
return TRUE;
+ if (type == 1 && TARGET_HAVE_MVE
+ && (GET_CODE (ind) == POST_INC || GET_CODE (ind) == PRE_DEC))
+ {
+ rtx ind1 = XEXP (ind, 0);
+ if (!REG_P (ind1))
+ return 0;
+ return NEON_REGNO_OK_FOR_QUAD (REGNO (ind1));
+ }
+
return FALSE;
}
@@ -19936,7 +19953,7 @@ output_move_neon (rtx *operands)
{
case POST_INC:
/* We have to use vldm / vstm for too-large modes. */
- if (nregs > 4)
+ if (nregs > 4 || (TARGET_HAVE_MVE && nregs >= 2))
{
templ = "v%smia%%?\t%%0!, %%h1";
ops[0] = XEXP (addr, 0);
@@ -19965,7 +19982,7 @@ output_move_neon (rtx *operands)
/* We have to use vldm / vstm for too-large modes. */
if (nregs > 1)
{
- if (nregs > 4)
+ if (nregs > 4 || (TARGET_HAVE_MVE && nregs >= 2))
templ = "v%smia%%?\t%%m0, %%h1";
else
templ = "v%s1.64\t%%h1, %%A0";
@@ -19980,29 +19997,40 @@ output_move_neon (rtx *operands)
{
int i;
int overlap = -1;
- for (i = 0; i < nregs; i++)
+ if (TARGET_HAVE_MVE && !BYTES_BIG_ENDIAN)
{
- /* We're only using DImode here because it's a convenient
size. */
- ops[0] = gen_rtx_REG (DImode, REGNO (reg) + 2 * i);
- ops[1] = adjust_address (mem, DImode, 8 * i);
- if (reg_overlap_mentioned_p (ops[0], mem))
+ sprintf (buff, "v%srw.32\t%%q0, %%1", load ? "ld" : "st");
+ ops[0] = reg;
+ ops[1] = mem;
+ output_asm_insn (buff, ops);
+ }
+ else
+ {
+ for (i = 0; i < nregs; i++)
{
- gcc_assert (overlap == -1);
- overlap = i;
+ /* We're only using DImode here because it's a convenient
+ size. */
+ ops[0] = gen_rtx_REG (DImode, REGNO (reg) + 2 * i);
+ ops[1] = adjust_address (mem, DImode, 8 * i);
+ if (reg_overlap_mentioned_p (ops[0], mem))
+ {
+ gcc_assert (overlap == -1);
+ overlap = i;
+ }
+ else
+ {
+ sprintf (buff, "v%sr%%?\t%%P0, %%1", load ? "ld" :
"st");
+ output_asm_insn (buff, ops);
+ }
}
- else
+ if (overlap != -1)
{
+ ops[0] = gen_rtx_REG (DImode, REGNO (reg) + 2 * overlap);
+ ops[1] = adjust_address (mem, SImode, 8 * overlap);
sprintf (buff, "v%sr%%?\t%%P0, %%1", load ? "ld" : "st");
output_asm_insn (buff, ops);
}
}
- if (overlap != -1)
- {
- ops[0] = gen_rtx_REG (DImode, REGNO (reg) + 2 * overlap);
- ops[1] = adjust_address (mem, SImode, 8 * overlap);
- sprintf (buff, "v%sr%%?\t%%P0, %%1", load ? "ld" : "st");
- output_asm_insn (buff, ops);
- }
return "";
}
@@ -22223,7 +22251,7 @@ arm_compute_frame_layout (void)
func_type = arm_current_func_type ();
/* Space for saved VFP registers. */
if (! IS_VOLATILE (func_type)
- && TARGET_HARD_FLOAT)
+ && (TARGET_HARD_FLOAT || TARGET_HAVE_MVE))
saved += arm_get_vfp_saved_size ();
/* Allocate space for saving/restoring FPCXTNS in Armv8.1-M
Mainline
@@ -22447,7 +22475,7 @@ arm_save_coproc_regs(void)
saved_size += 8;
}
- if (TARGET_HARD_FLOAT)
+ if (TARGET_HARD_FLOAT || TARGET_HAVE_MVE)
{
start_reg = FIRST_VFP_REGNUM;
@@ -23749,6 +23777,53 @@ arm_print_operand (FILE *stream, rtx x, int code)
}
return;
+ /* To print the memory operand with "Us" constraint. Based on the
rtx_code
+ the memory operands output looks like following.
+ 1. [Rn], #+/-<imm>
+ 2. [Rn, #+/-<imm>]!
+ 3. [Rn]. */
+ case 'E':
+ {
+ rtx addr;
+ rtx postinc_reg = NULL;
+ unsigned inc_val = 0;
+ enum rtx_code code;
+
+ gcc_assert (MEM_P (x));
+ addr = XEXP (x, 0);
+ code = GET_CODE (addr);
+ if (code == POST_INC || code == POST_DEC || code == PRE_INC
+ || code == PRE_DEC)
+ {
+ asm_fprintf (stream, "[%r", REGNO (XEXP (addr, 0)));
+ inc_val = GET_MODE_SIZE (GET_MODE (x));
+ if (code == POST_INC || code == POST_DEC)
+ asm_fprintf (stream, "], #%s%d",(code == POST_INC)
+ ? "": "-", inc_val);
+ else
+ asm_fprintf (stream, ", #%s%d]!",(code == PRE_INC)
+ ? "": "-", inc_val);
+ }
+ else if (code == POST_MODIFY || code == PRE_MODIFY)
+ {
+ asm_fprintf (stream, "[%r", REGNO (XEXP (addr, 0)));
+ postinc_reg = XEXP ( XEXP (x, 1), 1);
+ if (postinc_reg && CONST_INT_P (postinc_reg))
+ {
+ if (code == POST_MODIFY)
+ asm_fprintf (stream, "], #%wd",INTVAL (postinc_reg));
+ else
+ asm_fprintf (stream, ", #%wd]!",INTVAL (postinc_reg));
+ }
+ }
+ else
+ {
+ gcc_assert (REG_P (addr));
+ asm_fprintf (stream, "[%r]",REGNO (addr));
+ }
+ }
+ return;
+
case 'C':
{
rtx addr;
@@ -23926,9 +24001,10 @@ arm_print_operand_address (FILE *stream,
machine_mode mode, rtx x)
REGNO (XEXP (x, 0)),
GET_CODE (x) == PRE_DEC ? "-" : "",
GET_MODE_SIZE (mode));
+ else if (TARGET_HAVE_MVE && (mode == OImode || mode == XImode))
+ asm_fprintf (stream, "[%r]!", REGNO (XEXP (x,0)));
else
- asm_fprintf (stream, "[%r], #%s%d",
- REGNO (XEXP (x, 0)),
+ asm_fprintf (stream, "[%r], #%s%d", REGNO (XEXP (x, 0)),
GET_CODE (x) == POST_DEC ? "-" : "",
GET_MODE_SIZE (mode));
}
@@ -24773,12 +24849,15 @@ arm_hard_regno_mode_ok (unsigned int regno,
machine_mode mode)
{
if (GET_MODE_CLASS (mode) == MODE_CC)
return (regno == CC_REGNUM
- || (TARGET_HARD_FLOAT
+ || ((TARGET_HARD_FLOAT || TARGET_HAVE_MVE)
&& regno == VFPCC_REGNUM));
if (regno == CC_REGNUM && GET_MODE_CLASS (mode) != MODE_CC)
return false;
+ if (IS_VPR_REGNUM (regno))
+ return true;
+
if (TARGET_THUMB1)
/* For the Thumb we only allow values bigger than SImode in
registers 0 - 6, so that there is always a second low
@@ -24787,7 +24866,7 @@ arm_hard_regno_mode_ok (unsigned int regno,
machine_mode mode)
start of an even numbered register pair. */
return (ARM_NUM_REGS (mode) < 2) || (regno < LAST_LO_REGNUM);
- if (TARGET_HARD_FLOAT && IS_VFP_REGNUM (regno))
+ if ((TARGET_HARD_FLOAT || TARGET_HAVE_MVE) && IS_VFP_REGNUM (regno))
{
if (mode == SFmode || mode == SImode)
return VFP_REGNO_OK_FOR_SINGLE (regno);
@@ -24811,6 +24890,10 @@ arm_hard_regno_mode_ok (unsigned int regno,
machine_mode mode)
|| (mode == OImode && NEON_REGNO_OK_FOR_NREGS (regno, 4))
|| (mode == CImode && NEON_REGNO_OK_FOR_NREGS (regno, 6))
|| (mode == XImode && NEON_REGNO_OK_FOR_NREGS (regno, 8));
+ if (TARGET_HAVE_MVE)
+ return ((VALID_MVE_MODE (mode) && NEON_REGNO_OK_FOR_QUAD (regno))
+ || (mode == OImode && NEON_REGNO_OK_FOR_NREGS (regno, 4))
+ || (mode == XImode && NEON_REGNO_OK_FOR_NREGS (regno, 8)));
return false;
}
@@ -24859,13 +24942,18 @@ arm_modes_tieable_p (machine_mode mode1,
machine_mode mode2)
/* We specifically want to allow elements of "structure" modes to
be tieable to the structure. This more general condition allows
other rarer situations too. */
- if (TARGET_NEON
- && (VALID_NEON_DREG_MODE (mode1)
- || VALID_NEON_QREG_MODE (mode1)
- || VALID_NEON_STRUCT_MODE (mode1))
- && (VALID_NEON_DREG_MODE (mode2)
- || VALID_NEON_QREG_MODE (mode2)
- || VALID_NEON_STRUCT_MODE (mode2)))
+ if ((TARGET_NEON
+ && (VALID_NEON_DREG_MODE (mode1)
+ || VALID_NEON_QREG_MODE (mode1)
+ || VALID_NEON_STRUCT_MODE (mode1))
+ && (VALID_NEON_DREG_MODE (mode2)
+ || VALID_NEON_QREG_MODE (mode2)
+ || VALID_NEON_STRUCT_MODE (mode2)))
+ || (TARGET_HAVE_MVE
+ && (VALID_MVE_MODE (mode1)
+ || VALID_MVE_STRUCT_MODE (mode1))
+ && (VALID_MVE_MODE (mode2)
+ || VALID_MVE_STRUCT_MODE (mode2))))
return true;
return false;
@@ -24880,6 +24968,9 @@ arm_regno_class (int regno)
if (regno == PC_REGNUM)
return NO_REGS;
+ if (IS_VPR_REGNUM (regno))
+ return VPR_REG;
+
if (TARGET_THUMB1)
{
if (regno == STACK_POINTER_REGNUM)
@@ -26731,7 +26822,7 @@ arm_expand_epilogue_apcs_frame (bool
really_return)
floats_from_frame += 4;
}
- if (TARGET_HARD_FLOAT)
+ if (TARGET_HARD_FLOAT || TARGET_HAVE_MVE)
{
int start_reg;
rtx ip_rtx = gen_rtx_REG (SImode, IP_REGNUM);
@@ -26977,7 +27068,7 @@ arm_expand_epilogue (bool really_return)
}
}
- if (TARGET_HARD_FLOAT)
+ if (TARGET_HARD_FLOAT || TARGET_HAVE_MVE)
{
/* Generate VFP register multi-pop. */
int end_reg = LAST_VFP_REGNUM + 1;
@@ -27148,7 +27239,7 @@ arm_expand_epilogue (bool really_return)
GEN_INT
(FPCXTNS_ENUM)));
RTX_FRAME_RELATED_P (insn) = 1;
}
- }
+ }
if (!really_return)
return;
@@ -28370,6 +28461,15 @@ arm_vector_mode_supported_p (machine_mode mode)
|| mode == V2HAmode))
return true;
+ if (TARGET_HAVE_MVE
+ && (mode == V2DImode || mode == V4SImode || mode == V8HImode
+ || mode == V16QImode))
+ return true;
+
+ if (TARGET_HAVE_MVE_FLOAT
+ && (mode == V2DFmode || mode == V4SFmode || mode == V8HFmode))
+ return true;
+
return false;
}
@@ -28387,6 +28487,10 @@ arm_array_mode_supported_p (machine_mode mode,
&& (nelems >= 2 && nelems <= 4))
return true;
+ if (TARGET_HAVE_MVE && !BYTES_BIG_ENDIAN
+ && VALID_MVE_MODE (mode) && (nelems == 2 || nelems == 4))
+ return true;
+
return false;
}
@@ -29435,7 +29539,7 @@ arm_conditional_register_usage (void)
if (TARGET_THUMB1)
fixed_regs[LR_REGNUM] = call_used_regs[LR_REGNUM] = 1;
- if (TARGET_32BIT && TARGET_HARD_FLOAT)
+ if (TARGET_32BIT && (TARGET_HARD_FLOAT || TARGET_HAVE_MVE))
{
/* VFPv3 registers are disabled when earlier VFP
versions are selected due to the definition of
@@ -29447,6 +29551,8 @@ arm_conditional_register_usage (void)
call_used_regs[regno] = regno < FIRST_VFP_REGNUM + 16
|| regno >= FIRST_VFP_REGNUM + 32;
}
+ if (TARGET_HAVE_MVE)
+ fixed_regs[VPR_REGNUM] = 0;
}
if (TARGET_REALLY_IWMMXT && !TARGET_GENERAL_REGS_ONLY)
diff --git a/gcc/config/arm/arm.md b/gcc/config/arm/arm.md
index
c62ad1b360ebecd5368e90ea5634488eef22f2fc..689baa0b0ff63ef90f47d2fd844cb98c9a1457a0
100644
--- a/gcc/config/arm/arm.md
+++ b/gcc/config/arm/arm.md
@@ -41,6 +41,7 @@
(VFPCC_REGNUM 101) ; VFP Condition code pseudo register
(APSRQ_REGNUM 104) ; Q bit pseudo register
(APSRGE_REGNUM 105) ; GE bits pseudo register
+ (VPR_REGNUM 106) ; Vector Predication Register - MVE
register.
]
)
;; 3rd operand to select_dominance_cc_mode
@@ -7293,7 +7294,7 @@
[(set (match_operand:SF 0 "nonimmediate_operand" "=r,r,m")
(match_operand:SF 1 "general_operand" "r,mE,r"))]
"TARGET_32BIT
- && TARGET_SOFT_FLOAT
+ && TARGET_SOFT_FLOAT && !TARGET_HAVE_MVE
&& (!MEM_P (operands[0])
|| register_operand (operands[1], SFmode))"
{
@@ -7416,8 +7417,8 @@
(define_insn "*movdf_soft_insn"
[(set (match_operand:DF 0 "nonimmediate_soft_df_operand" "=r,r,r,r,m")
- (match_operand:DF 1 "soft_df_operand" "rDa,Db,Dc,mF,r"))]
- "TARGET_32BIT && TARGET_SOFT_FLOAT
+ (match_operand:DF 1 "soft_df_operand" "rDa,Db,Dc,mF,r"))]
+ "TARGET_32BIT && TARGET_SOFT_FLOAT && !TARGET_HAVE_MVE
&& ( register_operand (operands[0], DFmode)
|| register_operand (operands[1], DFmode))"
"*
@@ -11681,7 +11682,7 @@
(match_operand:SI 2 "const_int_I_operand" "I")))
(set (match_operand:DF 3 "vfp_hard_register_operand" "")
(mem:DF (match_dup 1)))])]
- "TARGET_32BIT && TARGET_HARD_FLOAT"
+ "TARGET_32BIT && (TARGET_HARD_FLOAT || TARGET_HAVE_MVE)"
"*
{
int num_regs = XVECLEN (operands[0], 0);
@@ -12624,7 +12625,7 @@
(set_attr "length" "8")]
)
-;; Vector bits common to IWMMXT and Neon
+;; Vector bits common to IWMMXT, Neon and MVE
(include "vec-common.md")
;; Load the Intel Wireless Multimedia Extension patterns
(include "iwmmxt.md")
@@ -12642,3 +12643,5 @@
(include "sync.md")
;; Fixed-point patterns
(include "arm-fixed.md")
+;; M-profile Vector Extensions
+(include "mve.md")
diff --git a/gcc/config/arm/arm_mve.h b/gcc/config/arm/arm_mve.h
new file mode 100644
index
0000000000000000000000000000000000000000..5ffb466596b5d8fc330616a6fcc7ee37d3e28def
--- /dev/null
+++ b/gcc/config/arm/arm_mve.h
@@ -0,0 +1,59 @@
+/* Arm MVE intrinsics include file.
+
+ Copyright (C) 2019 Free Software Foundation, Inc.
+ Contributed by Arm.
+
+ This file is part of GCC.
+
+ GCC is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 3, or (at your
+ option) any later version.
+
+ GCC is distributed in the hope that it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+ License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GCC; see the file COPYING3. If not see
+ <http://www.gnu.org/licenses/>. */
+
+#ifndef _GCC_ARM_MVE_H
+#define _GCC_ARM_MVE_H
+
+#if !__ARM_FEATURE_MVE
+#error "MVE feature not supported"
+#endif
+
+#include <stdint.h>
+#ifndef __cplusplus
+#include <stdbool.h>
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#if (__ARM_FEATURE_MVE & 2) /* MVE Floating point. */
+typedef __fp16 float16_t;
+typedef float float32_t;
+typedef __simd128_float16_t float16x8_t;
+typedef __simd128_float32_t float32x4_t;
+#endif
+
+typedef uint16_t mve_pred16_t;
+typedef __simd128_uint8_t uint8x16_t;
+typedef __simd128_uint16_t uint16x8_t;
+typedef __simd128_uint32_t uint32x4_t;
+typedef __simd128_uint64_t uint64x2_t;
+typedef __simd128_int8_t int8x16_t;
+typedef __simd128_int16_t int16x8_t;
+typedef __simd128_int32_t int32x4_t;
+typedef __simd128_int64_t int64x2_t;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _GCC_ARM_MVE_H. */
diff --git a/gcc/config/arm/constraints.md b/gcc/config/arm/constraints.md
index
6f309b95cc1874ac7bc69e435781070e0c9cb70a..f77084a0efd489491372bb1dafbc0cd585f0f518
100644
--- a/gcc/config/arm/constraints.md
+++ b/gcc/config/arm/constraints.md
@@ -44,6 +44,8 @@
;; in Thumb state: Uu, Uw
;; in all states: Q
+(define_register_constraint "Up" "TARGET_HAVE_MVE ? VPR_REG : NO_REGS"
+ "MVE VPR register")
(define_register_constraint "t" "TARGET_32BIT ? VFP_LO_REGS : NO_REGS"
"The VFP registers @code{s0}-@code{s31}.")
diff --git a/gcc/config/arm/iterators.md b/gcc/config/arm/iterators.md
index
c412851843f4468c2c18bce264288705e076ac50..e30325bc1652d378be2544fa32269c5c4294d7e9
100644
--- a/gcc/config/arm/iterators.md
+++ b/gcc/config/arm/iterators.md
@@ -62,6 +62,12 @@
;; Integer and float modes supported by Neon and IWMMXT.
(define_mode_iterator VALL [V2DI V2SI V4HI V8QI V2SF V4SI V8HI V16QI
V4SF])
+;; Integer and float modes supported by Neon, IWMMXT and MVE.
+(define_mode_iterator VNIM1 [V16QI V8HI V4SI V4SF V2DI])
+
+;; Integer and float modes supported by Neon and IWMMXT but not MVE.
+(define_mode_iterator VNINOTM1 [V2SI V4HI V8QI V2SF])
+
;; Integer and float modes supported by Neon and IWMMXT, except V2DI.
(define_mode_iterator VALLW [V2SI V4HI V8QI V2SF V4SI V8HI V16QI V4SF])
@@ -105,7 +111,8 @@
(define_mode_iterator VQXMOV [V16QI V8HI V8HF V4SI V4SF V2DI TI])
;; Opaque structure types wider than TImode.
-(define_mode_iterator VSTRUCT [EI OI CI XI])
+(define_mode_iterator VSTRUCT [(EI "!TARGET_HAVE_MVE") OI
+ (CI "!TARGET_HAVE_MVE") XI])
;; Opaque structure types used in table lookups (except vtbl1/vtbx1).
(define_mode_iterator VTAB [TI EI OI])
diff --git a/gcc/config/arm/mve.md b/gcc/config/arm/mve.md
new file mode 100644
index
0000000000000000000000000000000000000000..53334c6d329dedd482615b996232e85ded7a34f8
--- /dev/null
+++ b/gcc/config/arm/mve.md
@@ -0,0 +1,78 @@
+;; Arm M-profile Vector Extension Machine Description
+;; Copyright (C) 2019 Free Software Foundation, Inc.
+;;
+;; This file is part of GCC.
+;;
+;; GCC is free software; you can redistribute it and/or modify it
+;; under the terms of the GNU General Public License as published by
+;; the Free Software Foundation; either version 3, or (at your option)
+;; any later version.
+;;
+;; GCC is distributed in the hope that it will be useful, but
+;; WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+;; General Public License for more details.
+;;
+;; You should have received a copy of the GNU General Public License
+;; along with GCC; see the file COPYING3. If not see
+;; <http://www.gnu.org/licenses/>.
+
+(define_mode_iterator MVE_types [V16QI V8HI V4SI V2DI TI V8HF V4SF V2DF])
+(define_mode_attr V_sz_elem2 [(V16QI "s8") (V8HI "u16") (V4SI "u32")
+ (V2DI "u64")])
+
+(define_insn "*mve_mov<mode>"
+ [(set (match_operand:MVE_types 0 "s_register_operand" "=w,w,r,w,w,r,w")
+ (match_operand:MVE_types 1 "general_operand"
"w,r,w,Dn,Usi,r,Dm"))]
+ "TARGET_HAVE_MVE || TARGET_HAVE_MVE_FLOAT"
+{
+ if (which_alternative == 3 || which_alternative == 6)
+ {
+ int width, is_valid;
+ static char templ[40];
+
+ is_valid = simd_immediate_valid_for_move (operands[1], <MODE>mode,
+ &operands[1], &width);
+
+ gcc_assert (is_valid != 0);
+
+ if (width == 0)
+ return "vmov.f32\t%q0, %1 @ <mode>";
+ else
+ sprintf (templ, "vmov.i%d\t%%q0, %%x1 @ <mode>", width);
+ return templ;
+ }
+ switch (which_alternative)
+ {
+ case 0:
+ return "vmov\t%q0, %q1";
+ case 1:
+ return "vmov\t%e0, %Q1, %R1 @ <mode>\;vmov\t%f0, %J1, %K1";
+ case 2:
+ return "vmov\t%Q0, %R0, %e1 @ <mode>\;vmov\t%J0, %K0, %f1";
+ case 4:
+ if ((TARGET_HAVE_MVE_FLOAT && VALID_MVE_SF_MODE (<MODE>mode))
+ || (MEM_P (operands[1])
+ && GET_CODE (XEXP (operands[1], 0)) == LABEL_REF))
+ return output_move_neon (operands);
+ else
+ return "vldrb.<V_sz_elem2> %q0, %E1";
+ case 5:
+ return output_move_neon (operands);
+ case 6:
+ default:
+ gcc_unreachable ();
+ return "";
+ }
+}
+ [(set_attr "type"
"mve_move,mve_move,mve_move,mve_move,mve_load,mve_move,mve_move")
+ (set_attr "length" "4,8,8,4,8,8,4")
+ (set_attr "thumb2_pool_range" "*,*,*,*,1018,*,*")
+ (set_attr "neg_pool_range" "*,*,*,*,996,*,*")])
+
+(define_insn "*mve_vstr<mode>"
+ [(set (match_operand:MVE_types 0 "memory_operand" "=Us")
+ (match_operand:MVE_types 1 "s_register_operand" "w"))]
+ "TARGET_HAVE_MVE"
+ "vstrb.<V_sz_elem> %q1, %E0"
+ [(set_attr "type" "mve_store")])
diff --git a/gcc/config/arm/neon.md b/gcc/config/arm/neon.md
index
6a0ee28efc9aa9f1fba7b5ae031564f40aa095fe..c23783e0ed914ec21a92828388ada58ada3c6132
100644
--- a/gcc/config/arm/neon.md
+++ b/gcc/config/arm/neon.md
@@ -35,9 +35,9 @@
(define_insn "*neon_mov<mode>"
[(set (match_operand:VDX 0 "nonimmediate_operand"
- "=w,Un,w, w, w, ?r,?w,?r, ?Us,*r")
+ "=w,Un,w, w, w, ?r,?w,?r, ?Us,*r")
(match_operand:VDX 1 "general_operand"
- " w,w, Dm,Dn,Uni, w, r, Usi,r,*r"))]
+ " w,w, Dm,Dn,Uni, w, r, Usi,r,*r"))]
"TARGET_NEON
&& (register_operand (operands[0], <MODE>mode)
|| register_operand (operands[1], <MODE>mode))"
@@ -47,7 +47,7 @@
int width, is_valid;
static char templ[40];
- is_valid = neon_immediate_valid_for_move (operands[1], <MODE>mode,
+ is_valid = simd_immediate_valid_for_move (operands[1], <MODE>mode,
&operands[1], &width);
gcc_assert (is_valid != 0);
@@ -94,7 +94,7 @@
int width, is_valid;
static char templ[40];
- is_valid = neon_immediate_valid_for_move (operands[1], <MODE>mode,
+ is_valid = simd_immediate_valid_for_move (operands[1], <MODE>mode,
&operands[1], &width);
gcc_assert (is_valid != 0);
@@ -147,9 +147,9 @@
})
(define_expand "mov<mode>"
- [(set (match_operand:VSTRUCT 0 "nonimmediate_operand")
- (match_operand:VSTRUCT 1 "general_operand"))]
- "TARGET_NEON"
+ [(set (match_operand:VSTRUCT 0 "nonimmediate_operand" "")
+ (match_operand:VSTRUCT 1 "general_operand" ""))]
+ "TARGET_NEON || TARGET_HAVE_MVE"
{
gcc_checking_assert (aligned_operand (operands[0], <MODE>mode));
gcc_checking_assert (aligned_operand (operands[1], <MODE>mode));
@@ -160,24 +160,28 @@
}
})
-(define_expand "mov<mode>"
- [(set (match_operand:VH 0 "s_register_operand")
- (match_operand:VH 1 "s_register_operand"))]
+;; The pattern mov<mode> where mode is v4hf and v8hf is split into
+;; movv4hf and movv8hf. The pattern movv8hf is common for MVE and
+;; NEON, so it is moved into vec-common.md file.
+(define_expand "movv4hf"
+ [(set (match_operand:V4HF 0 "s_register_operand")
+ (match_operand:V4HF 1 "s_register_operand"))]
"TARGET_NEON"
{
- gcc_checking_assert (aligned_operand (operands[0], <MODE>mode));
- gcc_checking_assert (aligned_operand (operands[1], <MODE>mode));
+ gcc_checking_assert (aligned_operand (operands[0], E_V4HFmode));
+ gcc_checking_assert (aligned_operand (operands[1], E_V4HFmode));
if (can_create_pseudo_p ())
{
if (!REG_P (operands[0]))
- operands[1] = force_reg (<MODE>mode, operands[1]);
+ operands[1] = force_reg (E_V4HFmode, operands[1]);
}
})
+
(define_insn "*neon_mov<mode>"
[(set (match_operand:VSTRUCT 0 "nonimmediate_operand" "=w,Ut,w")
(match_operand:VSTRUCT 1 "general_operand" " w,w, Ut"))]
- "TARGET_NEON
+ "(TARGET_NEON || TARGET_HAVE_MVE)
&& (register_operand (operands[0], <MODE>mode)
|| register_operand (operands[1], <MODE>mode))"
{
@@ -213,7 +217,7 @@
(define_split
[(set (match_operand:OI 0 "s_register_operand" "")
(match_operand:OI 1 "s_register_operand" ""))]
- "TARGET_NEON && reload_completed"
+ "(TARGET_NEON || TARGET_HAVE_MVE) && reload_completed"
[(set (match_dup 0) (match_dup 1))
(set (match_dup 2) (match_dup 3))]
{
@@ -254,7 +258,7 @@
(define_split
[(set (match_operand:XI 0 "s_register_operand" "")
(match_operand:XI 1 "s_register_operand" ""))]
- "TARGET_NEON && reload_completed"
+ "(TARGET_NEON || TARGET_HAVE_MVE) && reload_completed"
[(set (match_dup 0) (match_dup 1))
(set (match_dup 2) (match_dup 3))
(set (match_dup 4) (match_dup 5))
@@ -489,7 +493,7 @@
(define_expand "vec_init<mode><V_elem_l>"
[(match_operand:VDQ 0 "s_register_operand")
(match_operand 1 "" "")]
- "TARGET_NEON"
+ "TARGET_NEON || TARGET_HAVE_MVE"
{
neon_expand_vector_init (operands[0], operands[1]);
DONE;
diff --git a/gcc/config/arm/predicates.md b/gcc/config/arm/predicates.md
index
2f0f532edf40d475e4199aa41bd7803fac8d6143..9d74165fe065b03c77918fe9e4611967799535f1
100644
--- a/gcc/config/arm/predicates.md
+++ b/gcc/config/arm/predicates.md
@@ -48,6 +48,16 @@
return guard_addr_operand (XEXP (op, 0), mode);
})
+(define_predicate "vpr_register_operand"
+ (match_code "reg,subreg")
+{
+ if (GET_CODE (op) == SUBREG)
+ op = SUBREG_REG (op);
+ return REG_P (op)
+ && (REGNO (op) >= FIRST_PSEUDO_REGISTER
+ || IS_VPR_REGNUM (REGNO (op)));
+})
+
(define_predicate "imm_for_neon_inv_logic_operand"
(match_code "const_vector")
{
@@ -706,7 +716,7 @@
(define_predicate "imm_for_neon_mov_operand"
(match_code "const_vector,const_int")
{
- return neon_immediate_valid_for_move (op, mode, NULL, NULL);
+ return simd_immediate_valid_for_move (op, mode, NULL, NULL);
})
(define_predicate "imm_for_neon_lshift_operand"
diff --git a/gcc/config/arm/t-arm b/gcc/config/arm/t-arm
index
af60c8fc285bb536afeb9ec5c21771a4379755fc..fda5e84355b56a20eb9a22919ab1c786120cc8f1
100644
--- a/gcc/config/arm/t-arm
+++ b/gcc/config/arm/t-arm
@@ -55,6 +55,7 @@ MD_INCLUDES= $(srcdir)/config/arm/arm1020e.md \
$(srcdir)/config/arm/ldmstm.md \
$(srcdir)/config/arm/ldrdstrd.md \
$(srcdir)/config/arm/marvell-f-iwmmxt.md \
+ $(srcdir)/config/arm/mve.md \
$(srcdir)/config/arm/neon.md \
$(srcdir)/config/arm/predicates.md \
$(srcdir)/config/arm/sync.md \
diff --git a/gcc/config/arm/types.md b/gcc/config/arm/types.md
index
60faad6597935607ed3c5593f941a04bbc924252..c99b846ab387bac633be8b1631f0e40b3c827850
100644
--- a/gcc/config/arm/types.md
+++ b/gcc/config/arm/types.md
@@ -550,6 +550,11 @@
; The classification below is for TME instructions
;
; tme
+; The classification below is for M-profile Vector Extension instructions
+;
+; mve_move
+; mve_store
+; mve_load
(define_attr "type"
"adc_imm,\
@@ -1096,7 +1101,11 @@
crypto_sm3,\
crypto_sm4,\
coproc,\
- tme"
+ tme,\
+\
+ mve_move,\
+ mve_store,\
+ mve_load"
(const_string "untyped"))
; Is this an (integer side) multiply with a 32-bit (or smaller) result?
diff --git a/gcc/config/arm/vec-common.md b/gcc/config/arm/vec-common.md
index
33ff5627284d7cc898074b562179938982ecc420..5f5c113cf95afafbb733e1bfd2a7c7b8a55651a2
100644
--- a/gcc/config/arm/vec-common.md
+++ b/gcc/config/arm/vec-common.md
@@ -21,8 +21,31 @@
;; Vector Moves
(define_expand "mov<mode>"
- [(set (match_operand:VALL 0 "nonimmediate_operand")
- (match_operand:VALL 1 "general_operand"))]
+ [(set (match_operand:VNIM1 0 "nonimmediate_operand")
+ (match_operand:VNIM1 1 "general_operand"))]
+ "TARGET_NEON
+ || (TARGET_REALLY_IWMMXT && VALID_IWMMXT_REG_MODE (<MODE>mode))
+ || (TARGET_HAVE_MVE && VALID_MVE_SI_MODE (<MODE>mode))
+ || (TARGET_HAVE_MVE_FLOAT && VALID_MVE_SF_MODE (<MODE>mode))"
+ {
+ gcc_checking_assert (aligned_operand (operands[0], <MODE>mode));
+ gcc_checking_assert (aligned_operand (operands[1], <MODE>mode));
+ if (can_create_pseudo_p ())
+ {
+ if (!REG_P (operands[0]))
+ operands[1] = force_reg (<MODE>mode, operands[1]);
+ else if ((TARGET_NEON || TARGET_HAVE_MVE || TARGET_HAVE_MVE_FLOAT)
+ && (CONSTANT_P (operands[1])))
+ {
+ operands[1] = neon_make_constant (operands[1]);
+ gcc_assert (operands[1] != NULL_RTX);
+ }
+ }
+})
+
+(define_expand "mov<mode>"
+ [(set (match_operand:VNINOTM1 0 "nonimmediate_operand")
+ (match_operand:VNINOTM1 1 "general_operand"))]
"TARGET_NEON
|| (TARGET_REALLY_IWMMXT && VALID_IWMMXT_REG_MODE (<MODE>mode))"
{
@@ -40,6 +63,20 @@
}
})
+(define_expand "movv8hf"
+ [(set (match_operand:V8HF 0 "s_register_operand")
+ (match_operand:V8HF 1 "s_register_operand"))]
+ "TARGET_NEON || TARGET_HAVE_MVE_FLOAT"
+{
+ gcc_checking_assert (aligned_operand (operands[0], E_V8HFmode));
+ gcc_checking_assert (aligned_operand (operands[1], E_V8HFmode));
+ if (can_create_pseudo_p ())
+ {
+ if (!REG_P (operands[0]))
+ operands[1] = force_reg (E_V8HFmode, operands[1]);
+ }
+})
+
;; Vector arithmetic. Expanders are blank, then unnamed insns implement
;; patterns separately for IWMMXT and Neon.
diff --git a/gcc/config/arm/vfp.md b/gcc/config/arm/vfp.md
index
573db164f01b4ac9ee4a9ee7414872fb93c9e2ca..6349c0570540ec25a599166f5d427fcbdbf2af68
100644
--- a/gcc/config/arm/vfp.md
+++ b/gcc/config/arm/vfp.md
@@ -311,7 +311,7 @@
&& ( register_operand (operands[0], DImode)
|| register_operand (operands[1], DImode))
&& !(TARGET_NEON && CONST_INT_P (operands[1])
- && neon_immediate_valid_for_move (operands[1], DImode, NULL,
NULL))"
+ && simd_immediate_valid_for_move (operands[1], DImode, NULL,
NULL))"
"*
switch (which_alternative)
{
diff --git
a/gcc/testsuite/gcc.target/arm/mve/intrinsics/mve_vector_float.c
b/gcc/testsuite/gcc.target/arm/mve/intrinsics/mve_vector_float.c
new file mode 100644
index
0000000000000000000000000000000000000000..c3f81546c9f14f2491c6fb134170f17bcba16069
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/mve/intrinsics/mve_vector_float.c
@@ -0,0 +1,27 @@
+/* { dg-do compile } */
+/* { dg-additional-options "-march=armv8.1-m.main+mve.fp
-mfloat-abi=hard" } */
+/* { dg-skip-if "Skip if not auto" {*-*-*} {"-mfpu=*"} {"-mcpu=auto"}
} */
+
+#include "arm_mve.h"
+
+float32x4_t
+foo32 (float32x4_t value)
+{
+ float32x4_t b = value;
+ return b;
+}
+
+/* { dg-final { scan-assembler "vmov\\tq\[0-7\], q\[0-7\]" } } */
+/* { dg-final { scan-assembler "vstrb.*" } } */
+/* { dg-final { scan-assembler "vldmia.*" } } */
+
+float16x8_t
+foo16 (float16x8_t value)
+{
+ float16x8_t b = value;
+ return b;
+}
+
+/* { dg-final { scan-assembler "vmov\\tq\[0-7\], q\[0-7\]" } } */
+/* { dg-final { scan-assembler "vstrb.*" } } */
+/* { dg-final { scan-assembler "vldmia.*" } } */
diff --git
a/gcc/testsuite/gcc.target/arm/mve/intrinsics/mve_vector_float1.c
b/gcc/testsuite/gcc.target/arm/mve/intrinsics/mve_vector_float1.c
new file mode 100644
index
0000000000000000000000000000000000000000..ebee0d2f1ad03b66d044d93bf901e0ce78eccba9
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/mve/intrinsics/mve_vector_float1.c
@@ -0,0 +1,31 @@
+/* { dg-do compile } */
+/* { dg-additional-options "-march=armv8.1-m.main+mve.fp
-mfloat-abi=hard" } */
+/* { dg-skip-if "Skip if not auto" {*-*-*} {"-mfpu=*"} {"-mcpu=auto"}
} */
+
+#include "arm_mve.h"
+
+float32x4_t value;
+
+float32x4_t
+foo32 ()
+{
+ float32x4_t b = value;
+ return b;
+}
+
+/* { dg-final { scan-assembler "vmov\\tq\[0-7\], q\[0-7\]" } } */
+/* { dg-final { scan-assembler "vstrb.*" } } */
+/* { dg-final { scan-assembler "vldmia.*" } } */
+
+float16x8_t value1;
+
+float16x8_t
+foo16 ()
+{
+ float16x8_t b = value1;
+ return b;
+}
+
+/* { dg-final { scan-assembler "vmov\\tq\[0-7\], q\[0-7\]" } } */
+/* { dg-final { scan-assembler "vstrb.*" } } */
+/* { dg-final { scan-assembler "vldmia.*" } } */
diff --git
a/gcc/testsuite/gcc.target/arm/mve/intrinsics/mve_vector_float2.c
b/gcc/testsuite/gcc.target/arm/mve/intrinsics/mve_vector_float2.c
new file mode 100644
index
0000000000000000000000000000000000000000..9b9c84d66ef8fd585a42be1ac7585d8bc6c529bb
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/mve/intrinsics/mve_vector_float2.c
@@ -0,0 +1,27 @@
+/* { dg-do compile } */
+/* { dg-additional-options "-march=armv8.1-m.main+mve.fp
-mfloat-abi=hard" } */
+/* { dg-skip-if "Skip if not auto" {*-*-*} {"-mfpu=*"} {"-mcpu=auto"}
} */
+
+#include "arm_mve.h"
+
+float32x4_t
+foo32 ()
+{
+ float32x4_t b = {10.0, 12.0, 14.0, 16.0};
+ return b;
+}
+
+/* { dg-final { scan-assembler "vmov\\tq\[0-7\], q\[0-7\]" } } */
+/* { dg-final { scan-assembler "vstrb.*" } } */
+/* { dg-final { scan-assembler "vldrw.32*" } } */
+
+float16x8_t
+foo16 ()
+{
+ float16x8_t b = {32.01};
+ return b;
+}
+
+/* { dg-final { scan-assembler "vmov\\tq\[0-7\], q\[0-7\]" } } */
+/* { dg-final { scan-assembler "vstrb.*" } } */
+/* { dg-final { scan-assembler "vldrw.32.*" } } */
diff --git
a/gcc/testsuite/gcc.target/arm/mve/intrinsics/mve_vector_int.c
b/gcc/testsuite/gcc.target/arm/mve/intrinsics/mve_vector_int.c
new file mode 100644
index
0000000000000000000000000000000000000000..6b54c3c61f32cf8e0af30272df63f261def0b8c5
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/mve/intrinsics/mve_vector_int.c
@@ -0,0 +1,49 @@
+/* { dg-do compile } */
+/* { dg-additional-options "-march=armv8.1-m.main+mve
-mfloat-abi=hard" } */
+/* { dg-skip-if "Skip if not auto" {*-*-*} {"-mfpu=*"} {"-mcpu=auto"}
} */
+
+#include "arm_mve.h"
+
+int8x16_t
+foo8 (int8x16_t value)
+{
+ int8x16_t b = value;
+ return b;
+}
+
+/* { dg-final { scan-assembler "vmov\\tq\[0-7\], q\[0-7\]" } } */
+/* { dg-final { scan-assembler "vstrb.*" } } */
+/* { dg-final { scan-assembler "vldrb.s8*" } } */
+
+int16x8_t
+foo16 (int16x8_t value)
+{
+ int16x8_t b = value;
+ return b;
+}
+
+/* { dg-final { scan-assembler "vmov\\tq\[0-7\], q\[0-7\]" } } */
+/* { dg-final { scan-assembler "vstrb.*" } } */
+/* { dg-final { scan-assembler "vldrb.u16*" } } */
+
+int32x4_t
+foo32 (int32x4_t value)
+{
+ int32x4_t b = value;
+ return b;
+}
+
+/* { dg-final { scan-assembler "vmov\\tq\[0-7\], q\[0-7\]" } } */
+/* { dg-final { scan-assembler "vstrb.*" } } */
+/* { dg-final { scan-assembler "vldrb.u32*" } } */
+
+int64x2_t
+foo64 (int64x2_t value)
+{
+ int64x2_t b = value;
+ return b;
+}
+
+/* { dg-final { scan-assembler "vmov\\tq\[0-7\], q\[0-7\]" } } */
+/* { dg-final { scan-assembler "vstrb.*" } } */
+/* { dg-final { scan-assembler "vldrb.u64*" } } */
diff --git
a/gcc/testsuite/gcc.target/arm/mve/intrinsics/mve_vector_int1.c
b/gcc/testsuite/gcc.target/arm/mve/intrinsics/mve_vector_int1.c
new file mode 100644
index
0000000000000000000000000000000000000000..748ddecbd4011bb24058c27cd6a09d66f71ce581
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/mve/intrinsics/mve_vector_int1.c
@@ -0,0 +1,54 @@
+/* { dg-do compile } */
+/* { dg-additional-options "-march=armv8.1-m.main+mve
-mfloat-abi=hard" } */
+/* { dg-skip-if "Skip if not auto" {*-*-*} {"-mfpu=*"} {"-mcpu=auto"}
} */
+
+#include "arm_mve.h"
+
+int8x16_t value1;
+int16x8_t value2;
+int32x4_t value3;
+int64x2_t value4;
+
+int8x16_t
+foo8 ()
+{
+ int8x16_t b = value1;
+ return b;
+}
+
+/* { dg-final { scan-assembler "vmov\\tq\[0-7\], q\[0-7\]" } } */
+/* { dg-final { scan-assembler "vstrb.*" } } */
+/* { dg-final { scan-assembler "vldrb.u8*" } } */
+
+int16x8_t
+foo16 ()
+{
+ int16x8_t b = value2;
+ return b;
+}
+
+/* { dg-final { scan-assembler "vmov\\tq\[0-7\], q\[0-7\]" } } */
+/* { dg-final { scan-assembler "vstrb.*" } } */
+/* { dg-final { scan-assembler "vldrb.u16*" } } */
+
+int32x4_t
+foo32 ()
+{
+ int32x4_t b = value3;
+ return b;
+}
+
+/* { dg-final { scan-assembler "vmov\\tq\[0-7\], q\[0-7\]" } } */
+/* { dg-final { scan-assembler "vstrb.*" } } */
+/* { dg-final { scan-assembler "vldrb.u32" } } */
+
+int64x2_t
+foo64 ()
+{
+ int64x2_t b = value4;
+ return b;
+}
+
+/* { dg-final { scan-assembler "vmov\\tq\[0-7\], q\[0-7\]" } } */
+/* { dg-final { scan-assembler "vstrb.*" } } */
+/* { dg-final { scan-assembler "vldrb.u64" } } */
diff --git
a/gcc/testsuite/gcc.target/arm/mve/intrinsics/mve_vector_int2.c
b/gcc/testsuite/gcc.target/arm/mve/intrinsics/mve_vector_int2.c
new file mode 100644
index
0000000000000000000000000000000000000000..376ec9ee7fc04ddde98719d2605319a378f9a6bb
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/mve/intrinsics/mve_vector_int2.c
@@ -0,0 +1,49 @@
+/* { dg-do compile } */
+/* { dg-additional-options "-march=armv8.1-m.main+mve
-mfloat-abi=hard" } */
+/* { dg-skip-if "Skip if not auto" {*-*-*} {"-mfpu=*"} {"-mcpu=auto"}
} */
+
+#include "arm_mve.h"
+
+int8x16_t
+foo8 ()
+{
+ int8x16_t b = {1, 2, 3, 4};
+ return b;
+}
+
+/* { dg-final { scan-assembler "vmov\\tq\[0-7\], q\[0-7\]" } } */
+/* { dg-final { scan-assembler "vstrb.*" } } */
+/* { dg-final { scan-assembler "vldrw.32.*" } } */
+
+int16x8_t
+foo16 (int16x8_t value)
+{
+ int16x8_t b = {1, 2, 3};
+ return b;
+}
+
+/* { dg-final { scan-assembler "vmov\\tq\[0-7\], q\[0-7\]" } } */
+/* { dg-final { scan-assembler "vstrb.*" } } */
+/* { dg-final { scan-assembler "vldrw.32.*" } } */
+
+int32x4_t
+foo32 (int32x4_t value)
+{
+ int32x4_t b = {1, 2};
+ return b;
+}
+
+/* { dg-final { scan-assembler "vmov\\tq\[0-7\], q\[0-7\]" } } */
+/* { dg-final { scan-assembler "vstrb.*" } } */
+/* { dg-final { scan-assembler "vldrw.32.*" } } */
+
+int64x2_t
+foo64 (int64x2_t value)
+{
+ int64x2_t b = {1};
+ return b;
+}
+
+/* { dg-final { scan-assembler "vmov\\tq\[0-7\], q\[0-7\]" } } */
+/* { dg-final { scan-assembler "vstrb.*" } } */
+/* { dg-final { scan-assembler "vldrw.32.*" } } */
diff --git
a/gcc/testsuite/gcc.target/arm/mve/intrinsics/mve_vector_uint.c
b/gcc/testsuite/gcc.target/arm/mve/intrinsics/mve_vector_uint.c
new file mode 100644
index
0000000000000000000000000000000000000000..f001d14f9ca4c851ed4b3371ae9599d23d2b62ce
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/mve/intrinsics/mve_vector_uint.c
@@ -0,0 +1,49 @@
+/* { dg-do compile } */
+/* { dg-additional-options "-march=armv8.1-m.main+mve
-mfloat-abi=hard" } */
+/* { dg-skip-if "Skip if not auto" {*-*-*} {"-mfpu=*"} {"-mcpu=auto"}
} */
+
+#include "arm_mve.h"
+
+uint8x16_t
+foo8 (uint8x16_t value)
+{
+ uint8x16_t b = value;
+ return b;
+}
+
+/* { dg-final { scan-assembler "vmov\\tq\[0-7\], q\[0-7\]" } } */
+/* { dg-final { scan-assembler "vstrb.*" } } */
+/* { dg-final { scan-assembler "vldrb.s8*" } } */
+
+uint16x8_t
+foo16 (uint16x8_t value)
+{
+ uint16x8_t b = value;
+ return b;
+}
+
+/* { dg-final { scan-assembler "vmov\\tq\[0-7\], q\[0-7\]" } } */
+/* { dg-final { scan-assembler "vstrb.*" } } */
+/* { dg-final { scan-assembler "vldrb.u16*" } } */
+
+uint32x4_t
+foo32 (uint32x4_t value)
+{
+ uint32x4_t b = value;
+ return b;
+}
+
+/* { dg-final { scan-assembler "vmov\\tq\[0-7\], q\[0-7\]" } } */
+/* { dg-final { scan-assembler "vstrb.*" } } */
+/* { dg-final { scan-assembler "vldrb.u32*" } } */
+
+uint64x2_t
+foo64 (uint64x2_t value)
+{
+ uint64x2_t b = value;
+ return b;
+}
+
+/* { dg-final { scan-assembler "vmov\\tq\[0-7\], q\[0-7\]" } } */
+/* { dg-final { scan-assembler "vstrb.*" } } */
+/* { dg-final { scan-assembler "vldrb.u64*" } } */
diff --git
a/gcc/testsuite/gcc.target/arm/mve/intrinsics/mve_vector_uint1.c
b/gcc/testsuite/gcc.target/arm/mve/intrinsics/mve_vector_uint1.c
new file mode 100644
index
0000000000000000000000000000000000000000..56d40668d63ba0b24c08944981c415054494c37d
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/mve/intrinsics/mve_vector_uint1.c
@@ -0,0 +1,54 @@
+/* { dg-do compile } */
+/* { dg-additional-options "-march=armv8.1-m.main+mve
-mfloat-abi=hard" } */
+/* { dg-skip-if "Skip if not auto" {*-*-*} {"-mfpu=*"} {"-mcpu=auto"}
} */
+
+#include "arm_mve.h"
+
+uint8x16_t value1;
+uint16x8_t value2;
+uint32x4_t value3;
+uint64x2_t value4;
+
+uint8x16_t
+foo8 ()
+{
+ uint8x16_t b = value1;
+ return b;
+}
+
+/* { dg-final { scan-assembler "vmov\\tq\[0-7\], q\[0-7\]" } } */
+/* { dg-final { scan-assembler "vstrb.*" } } */
+/* { dg-final { scan-assembler "vldrb.s8*" } } */
+
+uint16x8_t
+foo16 ()
+{
+ uint16x8_t b = value2;
+ return b;
+}
+
+/* { dg-final { scan-assembler "vmov\\tq\[0-7\], q\[0-7\]" } } */
+/* { dg-final { scan-assembler "vstrb.*" } } */
+/* { dg-final { scan-assembler "vldrb.u16*" } } */
+
+uint32x4_t
+foo32 ()
+{
+ uint32x4_t b = value3;
+ return b;
+}
+
+/* { dg-final { scan-assembler "vmov\\tq\[0-7\], q\[0-7\]" } } */
+/* { dg-final { scan-assembler "vstrb.*" } } */
+/* { dg-final { scan-assembler "vldrb.u32*" } } */
+
+uint64x2_t
+foo64 ()
+{
+ uint64x2_t b = value4;
+ return b;
+}
+
+/* { dg-final { scan-assembler "vmov\\tq\[0-7\], q\[0-7\]" } } */
+/* { dg-final { scan-assembler "vstrb.*" } } */
+/* { dg-final { scan-assembler "vldrb.u64*" } } */
diff --git
a/gcc/testsuite/gcc.target/arm/mve/intrinsics/mve_vector_uint2.c
b/gcc/testsuite/gcc.target/arm/mve/intrinsics/mve_vector_uint2.c
new file mode 100644
index
0000000000000000000000000000000000000000..9ff9b67993ac83cf398880cb65510604a37de6a4
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/mve/intrinsics/mve_vector_uint2.c
@@ -0,0 +1,49 @@
+/* { dg-do compile } */
+/* { dg-additional-options "-march=armv8.1-m.main+mve
-mfloat-abi=hard" } */
+/* { dg-skip-if "Skip if not auto" {*-*-*} {"-mfpu=*"} {"-mcpu=auto"}
} */
+
+#include "arm_mve.h"
+
+uint8x16_t
+foo8 (uint8x16_t value)
+{
+ uint8x16_t b = {1, 2, 3, 4};
+ return b;
+}
+
+/* { dg-final { scan-assembler "vmov\\tq\[0-7\], q\[0-7\]" } } */
+/* { dg-final { scan-assembler "vstrb.*" } } */
+/* { dg-final { scan-assembler "vldrw.32.*" } } */
+
+uint16x8_t
+foo16 (uint16x8_t value)
+{
+ uint16x8_t b = {1, 2, 3};
+ return b;
+}
+
+/* { dg-final { scan-assembler "vmov\\tq\[0-7\], q\[0-7\]" } } */
+/* { dg-final { scan-assembler "vstrb.*" } } */
+/* { dg-final { scan-assembler "vldrw.32.*" } } */
+
+uint32x4_t
+foo32 (uint32x4_t value)
+{
+ uint32x4_t b = {1, 2};
+ return b;
+}
+
+/* { dg-final { scan-assembler "vmov\\tq\[0-7\], q\[0-7\]" } } */
+/* { dg-final { scan-assembler "vstrb.*" } } */
+/* { dg-final { scan-assembler "vldrw.32.*" } } */
+
+uint64x2_t
+foo64 (uint64x2_t value)
+{
+ uint64x2_t b = {1};
+ return b;
+}
+
+/* { dg-final { scan-assembler "vmov\\tq\[0-7\], q\[0-7\]" } } */
+/* { dg-final { scan-assembler "vstrb.*" } } */
+/* { dg-final { scan-assembler "vldrw.32.*" } } */
diff --git a/gcc/testsuite/gcc.target/arm/mve/mve.exp
b/gcc/testsuite/gcc.target/arm/mve/mve.exp
new file mode 100644
index
0000000000000000000000000000000000000000..77ae3fa292b2892fb22c2f89223ca19dc16ccc99
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/mve/mve.exp
@@ -0,0 +1,47 @@
+# Copyright (C) 2019 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with GCC; see the file COPYING3. If not see
+# <http://www.gnu.org/licenses/>.
+
+# GCC testsuite that uses the `dg.exp' driver.
+
+# Exit immediately if this isn't an ARM target.
+if ![istarget arm*-*-*] then {
+ return
+}
+
+# Load support procs.
+load_lib gcc-dg.exp
+
+# If a testcase doesn't have special options, use these.
+global DEFAULT_CFLAGS
+if ![info exists DEFAULT_CFLAGS] then {
+ set DEFAULT_CFLAGS " -ansi -pedantic-errors"
+}
+
+# This variable should only apply to tests called in this exp file.
+global dg_runtest_extra_prunes
+set dg_runtest_extra_prunes ""
+lappend dg_runtest_extra_prunes "warning: switch -m(cpu|arch)=.*
conflicts with -m(cpu|arch)=.* switch"
+
+# Initialize `dg'.
+dg-init
+
+# Main loop.
+dg-runtest [lsort [glob -nocomplain
$srcdir/$subdir/intrinsics/*.\[cCS\]]] \
+ "" $DEFAULT_CFLAGS
+
+# All done.
+set dg_runtest_extra_prunes ""
+dg-finish