[41/57,Arm,OBJDUMP] Add support for MVE instructions: vld[24] and vst[24]

Message ID c59d6737-274a-dc44-d8ff-711ef755da57@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, 5:40 p.m.
Hi,

This patch adds support for the MVE deinterleaving loads and 
interleaving stores.

opcodes/ChangeLog:

2019-05-01  Andre Vieira  <andre.simoesdiasvieira@arm.com>
             Michael Collison <michael.collison@arm.com>

	* arm-dis.c (enum mve_instructions): Add new instructions.
	(enum mve_unpredictable): Add new reasons.
	(is_mve_encoding_conflict): Handle new instructions.
	(is_mve_unpredictable): Likewise.
         (mve_opcodes): Add new instructions.
	(print_mve_unpredictable): Handle new reasons.
	(print_mve_register_blocks): New print function.
	(print_mve_size): Handle new instructions.
	(print_insn_mve): Likewise.

Patch

diff --git a/opcodes/arm-dis.c b/opcodes/arm-dis.c
index 89d15893f648295ae7840217bec9b35129e67922..2b8755ab1b5042562bf4f9c69b9ea5de5ee2011a 100644
--- a/opcodes/arm-dis.c
+++ b/opcodes/arm-dis.c
@@ -99,6 +99,10 @@  enum mve_instructions
   MVE_VHSUB_T1,
   MVE_VHSUB_T2,
   MVE_VRHADD,
+  MVE_VLD2,
+  MVE_VLD4,
+  MVE_VST2,
+  MVE_VST4,
   MVE_NONE
 };
 
@@ -111,6 +115,12 @@  enum mve_unpredictable
   UNPRED_R13,			/* Unpredictable because r13 (sp) or
 				   r15 (sp) used.  */
   UNPRED_R15,			/* Unpredictable because r15 (pc) is used.  */
+  UNPRED_Q_GT_4,		/* Unpredictable because
+				   vec reg start > 4 (vld4/st4).  */
+  UNPRED_Q_GT_6,		/* Unpredictable because
+				   vec reg start > 6 (vld2/st2).  */
+  UNPRED_R13_AND_WB,		/* Unpredictable becase gp reg = r13
+				   and WB bit = 1.  */
   UNPRED_NONE			/* No unpredictable behavior.  */
 };
 
@@ -1833,7 +1843,11 @@  static const struct opcode32 neon_opcodes[] =
    %n			print vector comparison code for predicated instruction
    %v			print vector predicate for instruction in predicated
 			block
+   %w			print writeback mode for MVE v{st,ld}[24]
+   %B			print v{st,ld}[24] any one operands
+
    %<bitfield>r		print as an ARM register
+   %<bitfield>d		print the bitfield in decimal
    %<bitfield>Q		print as a MVE Q register
    %<bitfield>Z		as %<>r but r15 is ZR instead of PC and r13 is
 			UNPREDICTABLE
@@ -2007,6 +2021,42 @@  static const struct mopcode32 mve_opcodes[] =
    0xef000140, 0xef811f51,
    "vrhadd%v.%u%20-21s\t%13-15,22Q, %17-19,7Q, %1-3,5Q"},
 
+  /* Vector VLD2.  */
+  {ARM_FEATURE_COPROC (FPU_MVE),
+   MVE_VLD2,
+   0xfc901e00, 0xff901e5f,
+   "vld2%5d.%7-8s\t%B, [%16-19r]%w"},
+
+  /* Vector VLD4.  */
+  {ARM_FEATURE_COPROC (FPU_MVE),
+   MVE_VLD4,
+   0xfc901e01, 0xff901e1f,
+   "vld4%5-6d.%7-8s\t%B, [%16-19r]%w"},
+
+  /* Vector VST2 no writeback.  */
+  {ARM_FEATURE_COPROC (FPU_MVE),
+   MVE_VST2,
+   0xfc801e00, 0xffb01e5f,
+   "vst2%5d.%7-8s\t%B, [%16-19r]"},
+
+  /* Vector VST2 writeback.  */
+  {ARM_FEATURE_COPROC (FPU_MVE),
+   MVE_VST2,
+   0xfca01e00, 0xffb01e5f,
+   "vst2%5d.%7-8s\t%B, [%16-19r]!"},
+
+  /* Vector VST4 no writeback.  */
+  {ARM_FEATURE_COPROC (FPU_MVE),
+   MVE_VST4,
+   0xfc801e01, 0xffb01e1f,
+   "vst4%5-6d.%7-8s\t%B, [%16-19r]"},
+
+  /* Vector VST4 writeback.  */
+  {ARM_FEATURE_COPROC (FPU_MVE),
+   MVE_VST4,
+   0xfca01e01, 0xffb01e1f,
+   "vst4%5-6d.%7-8s\t%B, [%16-19r]!"},
+
   {ARM_FEATURE_CORE_LOW (0),
    MVE_NONE,
    0x00000000, 0x00000000, 0}
@@ -4025,6 +4075,15 @@  is_mve_encoding_conflict (unsigned long given,
       else
 	return FALSE;
 
+    case MVE_VLD2:
+    case MVE_VLD4:
+    case MVE_VST2:
+    case MVE_VST4:
+      if (arm_decode_field (given, 7, 8) == 3)
+	return TRUE;
+      else
+	return FALSE;
+
     default:
       return FALSE;
 
@@ -4142,6 +4201,58 @@  is_mve_unpredictable (unsigned long given, enum mve_instructions matched_insn,
 	return FALSE;
       }
 
+    case MVE_VLD2:
+    case MVE_VST2:
+      {
+	unsigned long rn = arm_decode_field (given, 16, 19);
+
+	if ((rn == 0xd) && (arm_decode_field (given, 21, 21) == 1))
+	  {
+	    *unpredictable_code = UNPRED_R13_AND_WB;
+	    return TRUE;
+	  }
+
+	if (rn == 0xf)
+	  {
+	    *unpredictable_code = UNPRED_R15;
+	    return TRUE;
+	  }
+
+	if (arm_decode_field_multiple (given, 13, 15, 22, 22) > 6)
+	  {
+	    *unpredictable_code = UNPRED_Q_GT_6;
+	    return TRUE;
+	  }
+	else
+	  return FALSE;
+      }
+
+    case MVE_VLD4:
+    case MVE_VST4:
+      {
+	unsigned long rn = arm_decode_field (given, 16, 19);
+
+	if ((rn == 0xd) && (arm_decode_field (given, 21, 21) == 1))
+	  {
+	    *unpredictable_code = UNPRED_R13_AND_WB;
+	    return TRUE;
+	  }
+
+	if (rn == 0xf)
+	  {
+	    *unpredictable_code = UNPRED_R15;
+	    return TRUE;
+	  }
+
+	if (arm_decode_field_multiple (given, 13, 15, 22, 22) > 4)
+	  {
+	    *unpredictable_code = UNPRED_Q_GT_4;
+	    return TRUE;
+	  }
+	else
+	  return FALSE;
+      }
+
     default:
       return FALSE;
     }
@@ -4195,11 +4306,61 @@  print_mve_unpredictable (struct disassemble_info *info,
       func (stream, "use of r15 (pc)");
       break;
 
+    case UNPRED_Q_GT_4:
+      func (stream, "start register block > r4");
+      break;
+
+    case UNPRED_Q_GT_6:
+      func (stream, "start register block > r6");
+      break;
+
+    case UNPRED_R13_AND_WB:
+      func (stream, "use of r13 and write back");
+      break;
+
     case UNPRED_NONE:
       break;
     }
 }
 
+/* Print register block operand for mve vld2/vld4/vst2/vld4.  */
+
+static void
+print_mve_register_blocks (struct disassemble_info *info,
+			   unsigned long given,
+			   enum mve_instructions matched_insn)
+{
+  void *stream = info->stream;
+  fprintf_ftype func = info->fprintf_func;
+
+  unsigned long q_reg_start = arm_decode_field_multiple (given,
+							 13, 15,
+							 22, 22);
+  switch (matched_insn)
+    {
+    case MVE_VLD2:
+    case MVE_VST2:
+      if (q_reg_start <= 6)
+	func (stream, "{q%ld, q%ld}", q_reg_start, q_reg_start + 1);
+      else
+	func (stream, "<illegal reg q%ld>", q_reg_start);
+      break;
+
+    case MVE_VLD4:
+    case MVE_VST4:
+      if (q_reg_start <= 4)
+	func (stream, "{q%ld, q%ld, q%ld, q%ld}", q_reg_start,
+	      q_reg_start + 1, q_reg_start + 2,
+	      q_reg_start + 3);
+      else
+	func (stream, "<illegal reg q%ld>", q_reg_start);
+      break;
+
+    default:
+      break;
+    }
+}
+
 static void
 print_instruction_predicate (struct disassemble_info *info)
 {
@@ -4232,6 +4393,8 @@  print_mve_size (struct disassemble_info *info,
     case MVE_VHADD_T2:
     case MVE_VHSUB_T1:
     case MVE_VHSUB_T2:
+    case MVE_VLD2:
+    case MVE_VLD4:
     case MVE_VPT_VEC_T1:
     case MVE_VPT_VEC_T2:
     case MVE_VPT_VEC_T3:
@@ -4239,6 +4402,8 @@  print_mve_size (struct disassemble_info *info,
     case MVE_VPT_VEC_T5:
     case MVE_VPT_VEC_T6:
     case MVE_VRHADD:
+    case MVE_VST2:
+    case MVE_VST4:
       if (size <= 3)
 	func (stream, "%s", mve_vec_sizename[size]);
       else
@@ -5752,6 +5917,15 @@  print_insn_mve (struct disassemble_info *info, long given)
 		      print_instruction_predicate (info);
 		      break;
 
+		    case 'w':
+		      if (arm_decode_field (given, 21, 21) == 1)
+			func (stream, "!");
+		      break;
+
+		    case 'B':
+		      print_mve_register_blocks (info, given, insn->mve_op);
+		      break;
+
 		    case '0': case '1': case '2': case '3': case '4':
 		    case '5': case '6': case '7': case '8': case '9':
 		      {
@@ -5778,6 +5952,10 @@  print_insn_mve (struct disassemble_info *info, long given)
 			  case 'r':
 			    func (stream, "%s", arm_regnames[value]);
 			    break;
+			  case 'd':
+			    func (stream, "%ld", value);
+			    value_in_comment = value;
+			    break;
 			  case 'Q':
 			    if (value & 0x8)
 			      func (stream, "<illegal reg q%ld.5>", value);