[5/57,Arm,GAS] Add support for MVE instructions: vmull{b,t}

Message ID 3545f6f6-b1a0-1779-e57d-0b3aec92d750@arm.com
State New
Headers show
Series
  • : Add support for Armv8.1-M Mainline MVE instructions
Related show

Commit Message

Andre Vieira (lists) May 1, 2019, 4:59 p.m.
Hi,

This patch implements support for the MVE VMULL[BT] instruction.  This 
instruction presents a new challenge to the implementation of GAS as 
depending on architecture the same mnemonic can be split in different 
ways because of condition codes. In a NEON context 'vmullt' should be 
parsed as a 'vmul' instruction with 'lt' condition code, whereas in a 
MVE context this same mnemonic should be parsed as a 'vmullt' instruction.

The way we implement this is to catch any 'vmullt' in 'do_mve_vmull' and 
if we detect we are dealing with a NEON context, we set the correct 
condition code, encoding, and call the neon encoding function.

gas/ChangeLog:

2019-05-01  Andre Vieira  <andre.simoesdiasvieira@arm.com>

	* config/tc-arm.c (BAD_MVE_AUTO): New error message.
	(BAD_MVE_SRCDEST): Likewise.
	(mark_feature_used): Diagnose MVE only instructions
         when in auto-detection mode or -march=all.
	(enum operand_parse_code): Define new operand.
	(parse_operands): Handle new operand.
	(M_MNEM_vmullt, M_MNEM_vmullb): New encodings.
	(mve_encode_qqq): New encoding helper function.
	(do_mve_vmull): New encoding function.
	(insns):
	* testsuite/gas/arm/mve-vmullbt-bad.d: New test.
	* testsuite/gas/arm/mve-vmullbt-bad.l: New test.
	* testsuite/gas/arm/mve-vmullbt-bad.s: New test.

Patch

diff --git a/gas/config/tc-arm.c b/gas/config/tc-arm.c
index 1984cf23b7dc2b32dae1958bfac54eebb55584a0..4db934c8594f6660baff7e21c925d4b819e4ccf5 100644
--- a/gas/config/tc-arm.c
+++ b/gas/config/tc-arm.c
@@ -890,6 +890,11 @@  struct asm_opcode
 #define MVE_BAD_SP	_("Warning: instruction is UNPREDICTABLE with SP" \
 			  " operand")
 #define BAD_SIMD_TYPE	_("bad type in SIMD instruction")
+#define BAD_MVE_AUTO	\
+  _("GAS auto-detection mode and -march=all is deprecated for MVE, please" \
+    " use a valid -march or -mcpu option.")
+#define BAD_MVE_SRCDEST	_("Warning: 32-bit element size and same destination "\
+			  "and source operands makes instruction UNPREDICTABLE")
 
 static struct hash_control * arm_ops_hsh;
 static struct hash_control * arm_cond_hsh;
@@ -1541,6 +1546,15 @@  record_feature_use (const arm_feature_set *feature)
 static bfd_boolean
 mark_feature_used (const arm_feature_set *feature)
 {
+
+  /* Do not support the use of MVE only instructions when in auto-detection or
+     -march=all.  */
+  if (((feature == &mve_ext) || (feature == &mve_fp_ext))
+      && ARM_CPU_IS_ANY (cpu_variant))
+    {
+      first_error (BAD_MVE_AUTO);
+      return FALSE;
+    }
   /* Ensure the option is valid on the current architecture.  */
   if (!ARM_CPU_HAS_FEATURE (cpu_variant, *feature))
     return FALSE;
@@ -6743,6 +6757,8 @@  enum operand_parse_code
   OP_RR_RNSC,   /* ARM reg or Neon scalar.  */
   OP_RNSD_RNSC, /* Neon S or D reg, or Neon scalar.  */
   OP_RNSDQ_RNSC, /* Vector S, D or Q reg, or Neon scalar.  */
+  OP_RNSDQ_RNSC_MQ, /* Vector S, D or Q reg, Neon scalar or MVE vector register.
+		     */
   OP_RNDQ_RNSC, /* Neon D or Q reg, or Neon scalar.  */
   OP_RND_RNSC,  /* Neon D reg, or Neon scalar.  */
   OP_VMOV,      /* Neon VMOV operands.  */
@@ -7094,6 +7110,10 @@  parse_operands (char *str, const unsigned int *pattern, bfd_boolean thumb)
 	  }
 	  break;
 
+	case OP_RNSDQ_RNSC_MQ:
+	  po_reg_or_goto (REG_TYPE_MQ, try_rnsdq_rnsc);
+	  break;
+	try_rnsdq_rnsc:
 	case OP_RNSDQ_RNSC:
 	  {
 	    po_scalar_or_goto (8, try_nsdq);
@@ -13836,6 +13856,8 @@  do_t_loloop (void)
 #define M_MNEM_vmlsdava	  0xeef00e21
 #define M_MNEM_vmlsdavx	  0xeef01e01
 #define M_MNEM_vmlsdavax  0xeef01e21
+#define M_MNEM_vmullt	0xee011e00
+#define M_MNEM_vmullb	0xee010e00
 
 /* Neon instruction encoder helpers.  */
 
@@ -15223,6 +15245,23 @@  mve_encode_rqq (unsigned bit28, unsigned size)
   inst.is_neon = 1;
 }
 
+static void
+mve_encode_qqq (int ubit, int size)
+{
+
+  inst.instruction |= (ubit != 0) << 28;
+  inst.instruction |= HI1 (inst.operands[0].reg) << 22;
+  inst.instruction |= neon_logbits (size) << 20;
+  inst.instruction |= LOW4 (inst.operands[1].reg) << 16;
+  inst.instruction |= LOW4 (inst.operands[0].reg) << 12;
+  inst.instruction |= HI1 (inst.operands[1].reg) << 7;
+  inst.instruction |= HI1 (inst.operands[2].reg) << 5;
+  inst.instruction |= LOW4 (inst.operands[2].reg);
+
+  inst.is_neon = 1;
+}
+
+
 /* Encode insns with bit pattern:
 
   |28/24|23|22 |21 20|19 16|15 12|11    8|7|6|5|4|3  0|
@@ -15941,6 +15980,61 @@  do_neon_qdmulh (void)
     }
 }
 
+static void
+do_mve_vmull (void)
+{
+
+  enum neon_shape rs = neon_select_shape (NS_HHH, NS_FFF, NS_DDD, NS_DDS,
+					  NS_QQS, NS_QQQ, NS_QQR, NS_NULL);
+  if (!ARM_CPU_HAS_FEATURE (cpu_variant, mve_ext)
+      && inst.cond == COND_ALWAYS
+      && ((unsigned)inst.instruction) == M_MNEM_vmullt)
+    {
+      if (rs == NS_QQQ)
+	{
+
+	  struct neon_type_el et = neon_check_type (3, rs, N_EQK , N_EQK,
+						    N_SUF_32 | N_F64 | N_P8
+						    | N_P16 | N_I_MVE | N_KEY);
+	  if (((et.type == NT_poly) && et.size == 8
+	       && ARM_CPU_IS_ANY (cpu_variant))
+	      || (et.type == NT_integer) || (et.type == NT_float))
+	    goto neon_vmul;
+	}
+      else
+	goto neon_vmul;
+    }
+
+  constraint (rs != NS_QQQ, BAD_FPU);
+  struct neon_type_el et = neon_check_type (3, rs, N_EQK , N_EQK,
+					    N_SU_32 | N_P8 | N_P16 | N_KEY);
+
+  /* We are dealing with MVE's vmullt.  */
+  if (et.size == 32
+      && (inst.operands[0].reg == inst.operands[1].reg
+	  || inst.operands[0].reg == inst.operands[2].reg))
+    as_tsktsk (BAD_MVE_SRCDEST);
+
+  if (inst.cond > COND_ALWAYS)
+    inst.pred_insn_type = INSIDE_VPT_INSN;
+  else
+    inst.pred_insn_type = MVE_OUTSIDE_PRED_INSN;
+
+  if (et.type == NT_poly)
+    mve_encode_qqq (neon_logbits (et.size), 64);
+  else
+    mve_encode_qqq (et.type == NT_unsigned, et.size);
+
+  return;
+
+neon_vmul:
+  inst.instruction = N_MNEM_vmul;
+  inst.cond = 0xb;
+  if (thumb_mode)
+    inst.pred_insn_type = INSIDE_IT_INSN;
+  do_neon_mul ();
+}
+
 static void
 do_mve_vabav (void)
 {
@@ -22751,6 +22845,7 @@  static const struct asm_opcode insns[] =
  ToC("vpsteee",	fe712f4d, 0, (), mve_vpt),
 
  /* MVE and MVE FP only.  */
+ mCEF(vmullb,	_vmullb,    3, (RMQ, RMQ, RMQ),			  mve_vmull),
  mCEF(vabav,	_vabav,	    3, (RRnpcsp, RMQ, RMQ),		  mve_vabav),
  mCEF(vmladav,	  _vmladav,	3, (RRe, RMQ, RMQ),		mve_vmladav),
  mCEF(vmladava,	  _vmladava,	3, (RRe, RMQ, RMQ),		mve_vmladav),
@@ -22768,8 +22863,9 @@  static const struct asm_opcode insns[] =
 #undef  THUMB_VARIANT
 #define THUMB_VARIANT  & arm_ext_v6t2
 
- mnCEF(vadd,     _vadd,    3, (RNSDQMQ, oRNSDQMQ, RNSDQMQR), neon_addsub_if_i),
- mnCEF(vsub,     _vsub,    3, (RNSDQMQ, oRNSDQMQ, RNSDQMQR), neon_addsub_if_i),
+ mCEF(vmullt, _vmullt,	3, (RNSDQMQ, oRNSDQMQ, RNSDQ_RNSC_MQ),	mve_vmull),
+ mnCEF(vadd,  _vadd,	3, (RNSDQMQ, oRNSDQMQ, RNSDQMQR),	neon_addsub_if_i),
+ mnCEF(vsub,  _vsub,	3, (RNSDQMQ, oRNSDQMQ, RNSDQMQR),	neon_addsub_if_i),
 
  MNCEF(vabs,  1b10300,	2, (RNSDQMQ, RNSDQMQ),	neon_abs_neg),
  MNCEF(vneg,  1b10380,	2, (RNSDQMQ, RNSDQMQ),	neon_abs_neg),
diff --git a/gas/testsuite/gas/arm/mve-vmullbt-bad.d b/gas/testsuite/gas/arm/mve-vmullbt-bad.d
new file mode 100644
index 0000000000000000000000000000000000000000..91cbb1c1b71570595bb64b664489024da0f0722e
--- /dev/null
+++ b/gas/testsuite/gas/arm/mve-vmullbt-bad.d
@@ -0,0 +1,5 @@ 
+#name: bad MVE VMULL instructions
+#as: -march=armv8.1-m.main+mve.fp
+#error_output: mve-vmullbt-bad.l
+
+.*: +file format .*arm.*
diff --git a/gas/testsuite/gas/arm/mve-vmullbt-bad.l b/gas/testsuite/gas/arm/mve-vmullbt-bad.l
new file mode 100644
index 0000000000000000000000000000000000000000..19f99dcc2ea3b04d1ce7ac656c47c1d08718ef26
--- /dev/null
+++ b/gas/testsuite/gas/arm/mve-vmullbt-bad.l
@@ -0,0 +1,33 @@ 
+[^:]*: Assembler messages:
+[^:]*:13: Error: bad type in SIMD instruction -- `vmullb.s64 q0,q1,q2'
+[^:]*:14: Error: bad type in SIMD instruction -- `vmullb.f16 q0,q1,q2'
+[^:]*:15: Error: bad type in SIMD instruction -- `vmullb.f32 q0,q1,q2'
+[^:]*:16: Warning: 32-bit element size and same destination and source operands makes instruction UNPREDICTABLE
+[^:]*:17: Warning: 32-bit element size and same destination and source operands makes instruction UNPREDICTABLE
+[^:]*:18: Warning: instruction is UNPREDICTABLE in an IT block
+[^:]*:18: Warning: instruction is UNPREDICTABLE in an IT block
+[^:]*:18: Warning: instruction is UNPREDICTABLE in an IT block
+[^:]*:18: Warning: instruction is UNPREDICTABLE in an IT block
+[^:]*:18: Warning: instruction is UNPREDICTABLE in an IT block
+[^:]*:18: Warning: instruction is UNPREDICTABLE in an IT block
+[^:]*:19: Error: bad type in SIMD instruction -- `vmullt.s64 q0,q1,q2'
+[^:]*:20: Error: bad type in SIMD instruction -- `vmullt.f16 q0,q1,q2'
+[^:]*:21: Error: bad type in SIMD instruction -- `vmullt.f32 q0,q1,q2'
+[^:]*:22: Warning: 32-bit element size and same destination and source operands makes instruction UNPREDICTABLE
+[^:]*:23: Warning: 32-bit element size and same destination and source operands makes instruction UNPREDICTABLE
+[^:]*: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
+[^:]*:26: Error: syntax error -- `vmullbeq.s32 q0,q1,q2'
+[^:]*:27: Error: syntax error -- `vmullbeq.s32 q0,q1,q2'
+[^:]*:29: Error: syntax error -- `vmullbeq.s32 q0,q1,q2'
+[^:]*:31: Error: instruction missing MVE vector predication code -- `vmullb.s32 q0,q1,q2'
+[^:]*:32: Error: vector predicated instruction should be in VPT/VPST block -- `vmullbt.s32 q0,q1,q2'
+[^:]*:34: Error: syntax error -- `vmullteq.s32 q0,q1,q2'
+[^:]*:35: Error: syntax error -- `vmullteq.s32 q0,q1,q2'
+[^:]*:37: Error: syntax error -- `vmullteq.s32 q0,q1,q2'
+[^:]*:39: Error: instruction missing MVE vector predication code -- `vmullt.s32 q0,q1,q2'
+[^:]*:40: Error: vector predicated instruction should be in VPT/VPST block -- `vmulltt.s32 q0,q1,q2'
diff --git a/gas/testsuite/gas/arm/mve-vmullbt-bad.s b/gas/testsuite/gas/arm/mve-vmullbt-bad.s
new file mode 100644
index 0000000000000000000000000000000000000000..e48269492b65990812abd1e6ab3766dd35723759
--- /dev/null
+++ b/gas/testsuite/gas/arm/mve-vmullbt-bad.s
@@ -0,0 +1,40 @@ 
+.macro cond op
+.irp cond, eq, ne, gt, ge, lt, le
+it \cond
+\op\().s32 q0, q1, q2
+.endr
+.endm
+
+
+
+.syntax unified
+.text
+.thumb
+vmullb.s64 q0, q1, q2
+vmullb.f16 q0, q1, q2
+vmullb.f32 q0, q1, q2
+vmullb.s32  q1, q1, q2
+vmullb.s32  q2, q1, q2
+cond vmullb
+vmullt.s64 q0, q1, q2
+vmullt.f16 q0, q1, q2
+vmullt.f32 q0, q1, q2
+vmullt.u32  q1, q1, q2
+vmullt.u32  q2, q1, q2
+cond vmullt
+it eq
+vmullbeq.s32 q0, q1, q2
+vmullbeq.s32 q0, q1, q2
+vpst
+vmullbeq.s32 q0, q1, q2
+vpst
+vmullb.s32 q0, q1, q2
+vmullbt.s32 q0, q1, q2
+it eq
+vmullteq.s32 q0, q1, q2
+vmullteq.s32 q0, q1, q2
+vpst
+vmullteq.s32 q0, q1, q2
+vpst
+vmullt.s32 q0, q1, q2
+vmulltt.s32 q0, q1, q2