[PATCH 28/57][Arm][GAS] Add support for MVE instructions: vqdmlah, vqrdmlah, vqdmlash, vqrdmlash, vqdmulh and vqrdmulh

gas/ChangeLog:
2019-05-16  Andre Vieira  <andre.simoesdiasvieira@arm.com>

	* config/tc-arm.c (enum operand_parse_code): Add new operand.
	(parse_operands): Handle new operand.
	(mve_encode_qqr): Handle new instructions.
	(do_neon_qdmulh): Add support for MVE variants.
	(do_neon_qrdmlah): Likewise.
	(do_mve_vqdmlah): New encoding function.
	(insns): Change entries and add new entries for MVE mnemonics.
	* testsuite/gas/arm/mve-vqdmulh-bad.d: New test.
	* testsuite/gas/arm/mve-vqdmulh-bad.l: New test.
	* testsuite/gas/arm/mve-vqdmulh-bad.s: New test.
This commit is contained in:
Andre Vieira 2019-05-16 12:00:54 +01:00
parent 8b8b22a426
commit 42b16635dd
5 changed files with 229 additions and 29 deletions

View File

@ -1,3 +1,16 @@
2019-05-16 Andre Vieira <andre.simoesdiasvieira@arm.com>
* config/tc-arm.c (enum operand_parse_code): Add new operand.
(parse_operands): Handle new operand.
(mve_encode_qqr): Handle new instructions.
(do_neon_qdmulh): Add support for MVE variants.
(do_neon_qrdmlah): Likewise.
(do_mve_vqdmlah): New encoding function.
(insns): Change entries and add new entries for MVE mnemonics.
* testsuite/gas/arm/mve-vqdmulh-bad.d: New test.
* testsuite/gas/arm/mve-vqdmulh-bad.l: New test.
* testsuite/gas/arm/mve-vqdmulh-bad.s: New test.
2019-05-16 Andre Vieira <andre.simoesdiasvieira@arm.com>
* config/tc-arm.c (do_mve_vqdmladh): New encoding function.

View File

@ -6954,6 +6954,9 @@ enum operand_parse_code
OP_RNSDQ_RNSC_MQ_RR, /* Vector S, D or Q reg, or MVE vector reg , or Neon
scalar, or ARM register. */
OP_RNDQ_RNSC, /* Neon D or Q reg, or Neon scalar. */
OP_RNDQ_RNSC_RR, /* Neon D or Q reg, Neon scalar, or ARM register. */
OP_RNDQMQ_RNSC_RR, /* Neon D or Q reg, Neon scalar, MVE vector or ARM
register. */
OP_RNDQMQ_RNSC, /* Neon D, Q or MVE vector reg, or Neon scalar. */
OP_RND_RNSC, /* Neon D reg, or Neon scalar. */
OP_VMOV, /* Neon VMOV operands. */
@ -7358,6 +7361,13 @@ parse_operands (char *str, const unsigned int *pattern, bfd_boolean thumb)
}
break;
case OP_RNDQMQ_RNSC_RR:
po_reg_or_goto (REG_TYPE_MQ, try_rndq_rnsc_rr);
break;
try_rndq_rnsc_rr:
case OP_RNDQ_RNSC_RR:
po_reg_or_goto (REG_TYPE_RN, try_rndq_rnsc);
break;
case OP_RNDQMQ_RNSC:
po_reg_or_goto (REG_TYPE_MQ, try_rndq_rnsc);
break;
@ -15993,6 +16003,15 @@ mve_encode_qqr (int size, int U, int fp)
/* vqsub. */
else if (((unsigned)inst.instruction) == 0x210)
inst.instruction = 0xee001f60;
/* vqrdmlah. */
else if (((unsigned)inst.instruction) == 0x3000b10)
inst.instruction = 0xee000e40;
/* vqdmulh. */
else if (((unsigned)inst.instruction) == 0x0000b00)
inst.instruction = 0xee010e60;
/* vqrdmulh. */
else if (((unsigned)inst.instruction) == 0x1000b00)
inst.instruction = 0xfe010e60;
/* Set U-bit. */
inst.instruction |= U << 28;
@ -17181,8 +17200,12 @@ do_neon_mul (void)
static void
do_neon_qdmulh (void)
{
if (check_simd_pred_availability (0, NEON_CHECK_ARCH | NEON_CHECK_CC))
return;
if (inst.operands[2].isscalar)
{
constraint (ARM_CPU_HAS_FEATURE (cpu_variant, mve_ext), BAD_FPU);
enum neon_shape rs = neon_select_shape (NS_DDS, NS_QQS, NS_NULL);
struct neon_type_el et = neon_check_type (3, rs,
N_EQK, N_EQK, N_S16 | N_S32 | N_KEY);
@ -17191,12 +17214,27 @@ do_neon_qdmulh (void)
}
else
{
enum neon_shape rs = neon_select_shape (NS_DDD, NS_QQQ, NS_NULL);
struct neon_type_el et = neon_check_type (3, rs,
N_EQK, N_EQK, N_S16 | N_S32 | N_KEY);
enum neon_shape rs;
struct neon_type_el et;
if (ARM_CPU_HAS_FEATURE (cpu_variant, mve_ext))
{
rs = neon_select_shape (NS_QQR, NS_QQQ, NS_NULL);
et = neon_check_type (3, rs,
N_EQK, N_EQK, N_S8 | N_S16 | N_S32 | N_KEY);
}
else
{
rs = neon_select_shape (NS_DDD, NS_QQQ, NS_NULL);
et = neon_check_type (3, rs,
N_EQK, N_EQK, N_S16 | N_S32 | N_KEY);
}
NEON_ENCODE (INTEGER, inst);
/* The U bit (rounding) comes from bit mask. */
neon_three_same (neon_quad (rs), 0, et.size);
if (rs == NS_QQR)
mve_encode_qqr (et.size, 0, 0);
else
/* The U bit (rounding) comes from bit mask. */
neon_three_same (neon_quad (rs), 0, et.size);
}
}
@ -17305,6 +17343,20 @@ do_mve_vmulh (void)
mve_encode_qqq (et.type == NT_unsigned, et.size);
}
static void
do_mve_vqdmlah (void)
{
enum neon_shape rs = neon_select_shape (NS_QQR, NS_NULL);
struct neon_type_el et
= neon_check_type (3, rs, N_EQK, N_EQK, N_SU_MVE | N_KEY);
if (inst.cond > COND_ALWAYS)
inst.pred_insn_type = INSIDE_VPT_INSN;
else
inst.pred_insn_type = MVE_OUTSIDE_PRED_INSN;
mve_encode_qqr (et.size, et.type == NT_unsigned, 0);
}
static void
do_mve_vqdmladh (void)
@ -17556,32 +17608,45 @@ do_mve_vmaxv (void)
static void
do_neon_qrdmlah (void)
{
/* Check we're on the correct architecture. */
if (!mark_feature_used (&fpu_neon_ext_armv8))
inst.error =
_("instruction form not available on this architecture.");
else if (!mark_feature_used (&fpu_neon_ext_v8_1))
if (check_simd_pred_availability (0, NEON_CHECK_ARCH | NEON_CHECK_CC))
return;
if (!ARM_CPU_HAS_FEATURE (cpu_variant, mve_ext))
{
as_warn (_("this instruction implies use of ARMv8.1 AdvSIMD."));
record_feature_use (&fpu_neon_ext_v8_1);
}
if (inst.operands[2].isscalar)
{
enum neon_shape rs = neon_select_shape (NS_DDS, NS_QQS, NS_NULL);
struct neon_type_el et = neon_check_type (3, rs,
N_EQK, N_EQK, N_S16 | N_S32 | N_KEY);
NEON_ENCODE (SCALAR, inst);
neon_mul_mac (et, neon_quad (rs));
/* Check we're on the correct architecture. */
if (!mark_feature_used (&fpu_neon_ext_armv8))
inst.error
= _("instruction form not available on this architecture.");
else if (!mark_feature_used (&fpu_neon_ext_v8_1))
{
as_warn (_("this instruction implies use of ARMv8.1 AdvSIMD."));
record_feature_use (&fpu_neon_ext_v8_1);
}
if (inst.operands[2].isscalar)
{
enum neon_shape rs = neon_select_shape (NS_DDS, NS_QQS, NS_NULL);
struct neon_type_el et = neon_check_type (3, rs,
N_EQK, N_EQK, N_S16 | N_S32 | N_KEY);
NEON_ENCODE (SCALAR, inst);
neon_mul_mac (et, neon_quad (rs));
}
else
{
enum neon_shape rs = neon_select_shape (NS_DDD, NS_QQQ, NS_NULL);
struct neon_type_el et = neon_check_type (3, rs,
N_EQK, N_EQK, N_S16 | N_S32 | N_KEY);
NEON_ENCODE (INTEGER, inst);
/* The U bit (rounding) comes from bit mask. */
neon_three_same (neon_quad (rs), 0, et.size);
}
}
else
{
enum neon_shape rs = neon_select_shape (NS_DDD, NS_QQQ, NS_NULL);
struct neon_type_el et = neon_check_type (3, rs,
N_EQK, N_EQK, N_S16 | N_S32 | N_KEY);
enum neon_shape rs = neon_select_shape (NS_QQR, NS_NULL);
struct neon_type_el et
= neon_check_type (3, rs, N_EQK, N_EQK, N_SU_MVE | N_KEY);
NEON_ENCODE (INTEGER, inst);
/* The U bit (rounding) comes from bit mask. */
neon_three_same (neon_quad (rs), 0, et.size);
mve_encode_qqr (et.size, et.type == NT_unsigned, 0);
}
}
@ -24068,9 +24133,7 @@ static const struct asm_opcode insns[] =
/* VMUL takes I8 I16 I32 F32 P8. */
nUF(vmulq, _vmul, 3, (RNQ, oRNQ, RNDQ_RNSC), neon_mul),
/* VQD{R}MULH takes S16 S32. */
nUF(vqdmulh, _vqdmulh, 3, (RNDQ, oRNDQ, RNDQ_RNSC), neon_qdmulh),
nUF(vqdmulhq, _vqdmulh, 3, (RNQ, oRNQ, RNDQ_RNSC), neon_qdmulh),
nUF(vqrdmulh, _vqrdmulh, 3, (RNDQ, oRNDQ, RNDQ_RNSC), neon_qdmulh),
nUF(vqrdmulhq, _vqrdmulh, 3, (RNQ, oRNQ, RNDQ_RNSC), neon_qdmulh),
NUF(vacge, 0000e10, 3, (RNDQ, oRNDQ, RNDQ), neon_fcmp_absolute),
NUF(vacgeq, 0000e10, 3, (RNQ, oRNQ, RNQ), neon_fcmp_absolute),
@ -24085,7 +24148,6 @@ static const struct asm_opcode insns[] =
NUF(vrsqrts, 0200f10, 3, (RNDQ, oRNDQ, RNDQ), neon_step),
NUF(vrsqrtsq, 0200f10, 3, (RNQ, oRNQ, RNQ), neon_step),
/* ARM v8.1 extension. */
nUF (vqrdmlah, _vqrdmlah, 3, (RNDQ, oRNDQ, RNDQ_RNSC), neon_qrdmlah),
nUF (vqrdmlahq, _vqrdmlah, 3, (RNQ, oRNQ, RNDQ_RNSC), neon_qrdmlah),
nUF (vqrdmlsh, _vqrdmlsh, 3, (RNDQ, oRNDQ, RNDQ_RNSC), neon_qrdmlah),
nUF (vqrdmlshq, _vqrdmlsh, 3, (RNQ, oRNQ, RNDQ_RNSC), neon_qrdmlah),
@ -24773,6 +24835,9 @@ static const struct asm_opcode insns[] =
mToC("vqdmlsdhx", fe001e00, 3, (RMQ, RMQ, RMQ), mve_vqdmladh),
mToC("vqrdmlsdh", fe000e01, 3, (RMQ, RMQ, RMQ), mve_vqdmladh),
mToC("vqrdmlsdhx",fe001e01, 3, (RMQ, RMQ, RMQ), mve_vqdmladh),
mToC("vqdmlah", ee000e60, 3, (RMQ, RMQ, RR), mve_vqdmlah),
mToC("vqdmlash", ee001e60, 3, (RMQ, RMQ, RR), mve_vqdmlah),
mToC("vqrdmlash", ee001e40, 3, (RMQ, RMQ, RR), mve_vqdmlah),
#undef THUMB_VARIANT
#define THUMB_VARIANT & mve_fp_ext
@ -24856,6 +24921,9 @@ static const struct asm_opcode insns[] =
mnUF(vmvn, _vmvn, 2, (RNDQMQ, RNDQMQ_Ibig), neon_mvn),
MNUF(vqabs, 1b00700, 2, (RNDQMQ, RNDQMQ), neon_sat_abs_neg),
MNUF(vqneg, 1b00780, 2, (RNDQMQ, RNDQMQ), neon_sat_abs_neg),
mnUF(vqrdmlah, _vqrdmlah,3, (RNDQMQ, oRNDQMQ, RNDQ_RNSC_RR), neon_qrdmlah),
mnUF(vqdmulh, _vqdmulh, 3, (RNDQMQ, oRNDQMQ, RNDQMQ_RNSC_RR), neon_qdmulh),
mnUF(vqrdmulh, _vqrdmulh,3, (RNDQMQ, oRNDQMQ, RNDQMQ_RNSC_RR), neon_qdmulh),
#undef ARM_VARIANT
#define ARM_VARIANT & arm_ext_v8_3

View File

@ -0,0 +1,5 @@
#name: bad MVE VQDMULH and VQRDMULH instructions
#as: -march=armv8.1-m.main+mve.fp
#error_output: mve-vqdmulh-bad.l
.*: +file format .*arm.*

View File

@ -0,0 +1,57 @@
[^:]*: Assembler messages:
[^:]*:10: Error: bad type in SIMD instruction -- `vqdmulh.s64 q0,q1,q2'
[^:]*:11: Error: bad type in SIMD instruction -- `vqdmulh.u8 q0,q1,q2'
[^:]*:12: Error: bad type in SIMD instruction -- `vqrdmulh.s64 q0,q1,q2'
[^:]*:13: Error: bad type in SIMD instruction -- `vqrdmulh.u8 q0,q1,q2'
[^:]*:14: Error: bad type in SIMD instruction -- `vqdmulh.s64 q0,q1,r2'
[^:]*:15: Error: bad type in SIMD instruction -- `vqdmulh.u8 q0,q1,r2'
[^:]*:16: Error: bad type in SIMD instruction -- `vqrdmulh.s64 q0,q1,r2'
[^:]*:17: Error: bad type in SIMD instruction -- `vqrdmulh.u8 q0,q1,r2'
[^:]*:18: Warning: instruction is UNPREDICTABLE with SP operand
[^:]*:19: Warning: instruction is UNPREDICTABLE with PC operand
[^:]*:20: Warning: instruction is UNPREDICTABLE with SP operand
[^:]*:21: Warning: instruction is UNPREDICTABLE with PC operand
[^:]*:22: Warning: instruction is UNPREDICTABLE in an IT block
[^:]*:22: Warning: instruction is UNPREDICTABLE in an IT block
[^:]*:22: Warning: instruction is UNPREDICTABLE in an IT block
[^:]*:22: Warning: instruction is UNPREDICTABLE in an IT block
[^:]*:22: Warning: instruction is UNPREDICTABLE in an IT block
[^:]*:22: Warning: instruction is UNPREDICTABLE in an IT block
[^:]*:23: Warning: instruction is UNPREDICTABLE in an IT block
[^:]*:23: Warning: instruction is UNPREDICTABLE in an IT block
[^:]*:23: Warning: instruction is UNPREDICTABLE in an IT block
[^:]*:23: Warning: instruction is UNPREDICTABLE in an IT block
[^:]*:23: Warning: instruction is UNPREDICTABLE in an IT block
[^:]*:23: Warning: instruction is UNPREDICTABLE in an IT block
[^:]*:24: Warning: instruction is UNPREDICTABLE in an IT block
[^:]*:24: Warning: instruction is UNPREDICTABLE in an IT block
[^:]*:24: Warning: instruction is UNPREDICTABLE in an IT block
[^:]*:24: Warning: instruction is UNPREDICTABLE in an IT block
[^:]*:24: Warning: instruction is UNPREDICTABLE in an IT block
[^:]*:24: Warning: instruction is UNPREDICTABLE in an IT block
[^:]*:25: Warning: instruction is UNPREDICTABLE in an IT block
[^:]*:25: Warning: instruction is UNPREDICTABLE in an IT block
[^:]*:25: Warning: instruction is UNPREDICTABLE in an IT block
[^:]*:25: Warning: instruction is UNPREDICTABLE in an IT block
[^:]*:25: Warning: instruction is UNPREDICTABLE in an IT block
[^:]*:25: Warning: instruction is UNPREDICTABLE in an IT block
[^:]*:27: Error: syntax error -- `vqdmulheq.s8 q0,q1,q2'
[^:]*:28: Error: syntax error -- `vqdmulheq.s8 q0,q1,q2'
[^:]*:30: Error: syntax error -- `vqdmulheq.s8 q0,q1,q2'
[^:]*:31: Error: vector predicated instruction should be in VPT/VPST block -- `vqdmulht.s8 q0,q1,q2'
[^:]*:33: Error: instruction missing MVE vector predication code -- `vqdmulh.s8 q0,q1,q2'
[^:]*:35: Error: syntax error -- `vqrdmulheq.s8 q0,q1,q2'
[^:]*:36: Error: syntax error -- `vqrdmulheq.s8 q0,q1,q2'
[^:]*:38: Error: syntax error -- `vqrdmulheq.s8 q0,q1,q2'
[^:]*:39: Error: vector predicated instruction should be in VPT/VPST block -- `vqrdmulht.s8 q0,q1,q2'
[^:]*:41: Error: instruction missing MVE vector predication code -- `vqrdmulh.s8 q0,q1,q2'
[^:]*:43: Error: syntax error -- `vqdmulheq.s8 q0,q1,r2'
[^:]*:44: Error: syntax error -- `vqdmulheq.s8 q0,q1,r2'
[^:]*:46: Error: syntax error -- `vqdmulheq.s8 q0,q1,r2'
[^:]*:47: Error: vector predicated instruction should be in VPT/VPST block -- `vqdmulht.s8 q0,q1,r2'
[^:]*:49: Error: instruction missing MVE vector predication code -- `vqdmulh.s8 q0,q1,r2'
[^:]*:51: Error: syntax error -- `vqrdmulheq.s8 q0,q1,r2'
[^:]*:52: Error: syntax error -- `vqrdmulheq.s8 q0,q1,r2'
[^:]*:54: Error: syntax error -- `vqrdmulheq.s8 q0,q1,r2'
[^:]*:55: Error: vector predicated instruction should be in VPT/VPST block -- `vqrdmulht.s8 q0,q1,r2'
[^:]*:57: Error: instruction missing MVE vector predication code -- `vqrdmulh.s8 q0,q1,r2'

View File

@ -0,0 +1,57 @@
.macro cond op, lastreg
.irp cond, eq, ne, gt, ge, lt, le
it \cond
\op\().s16 q0, q1, \lastreg
.endr
.endm
.syntax unified
.thumb
vqdmulh.s64 q0, q1, q2
vqdmulh.u8 q0, q1, q2
vqrdmulh.s64 q0, q1, q2
vqrdmulh.u8 q0, q1, q2
vqdmulh.s64 q0, q1, r2
vqdmulh.u8 q0, q1, r2
vqrdmulh.s64 q0, q1, r2
vqrdmulh.u8 q0, q1, r2
vqdmulh.s8 q0, q1, sp
vqdmulh.s8 q0, q1, pc
vqrdmulh.s8 q0, q1, sp
vqrdmulh.s8 q0, q1, pc
cond vqdmulh, q2
cond vqrdmulh, q2
cond vqdmulh, r2
cond vqrdmulh, r2
it eq
vqdmulheq.s8 q0, q1, q2
vqdmulheq.s8 q0, q1, q2
vpst
vqdmulheq.s8 q0, q1, q2
vqdmulht.s8 q0, q1, q2
vpst
vqdmulh.s8 q0, q1, q2
it eq
vqrdmulheq.s8 q0, q1, q2
vqrdmulheq.s8 q0, q1, q2
vpst
vqrdmulheq.s8 q0, q1, q2
vqrdmulht.s8 q0, q1, q2
vpst
vqrdmulh.s8 q0, q1, q2
it eq
vqdmulheq.s8 q0, q1, r2
vqdmulheq.s8 q0, q1, r2
vpst
vqdmulheq.s8 q0, q1, r2
vqdmulht.s8 q0, q1, r2
vpst
vqdmulh.s8 q0, q1, r2
it eq
vqrdmulheq.s8 q0, q1, r2
vqrdmulheq.s8 q0, q1, r2
vpst
vqrdmulheq.s8 q0, q1, r2
vqrdmulht.s8 q0, q1, r2
vpst
vqrdmulh.s8 q0, q1, r2