[PATCH 37/57][Arm][OBJDUMP] Add framework for MVE instructions
authorAndre Vieira <andre.simoesdiasvieira@arm.com>
Thu, 16 May 2019 12:54:24 +0000 (13:54 +0100)
committerAndre Vieira <andre.simoesdiasvieira@arm.com>
Thu, 16 May 2019 15:36:58 +0000 (16:36 +0100)
opcodes/ChangeLog:
2019-05-16  Andre Vieira  <andre.simoesdiasvieira@arm.com>
    Michael Collison <michael.collison@arm.com>

* arm-dis.c (enum mve_instructions): New enum.
(enum mve_unpredictable): Likewise.
(enum mve_undefined): Likewise.
(struct mopcode32): New struct.
(is_mve_okay_in_it): New function.
(is_mve_architecture): Likewise.
(arm_decode_field): Likewise.
(arm_decode_field_multiple): Likewise.
(is_mve_encoding_conflict): Likewise.
(is_mve_undefined): Likewise.
(is_mve_unpredictable): Likewise.
(print_mve_undefined): Likewise.
(print_mve_unpredictable): Likewise.
(print_insn_coprocessor_1): Use arm_decode_field_multiple.
(print_insn_mve): New function.
(print_insn_thumb32): Handle MVE architecture.
(select_arm_features): Force thumb for Armv8.1-m Mainline.

opcodes/ChangeLog
opcodes/arm-dis.c

index c648a2c..ad73bdf 100644 (file)
@@ -1,3 +1,24 @@
+2019-05-16  Andre Vieira  <andre.simoesdiasvieira@arm.com>
+           Michael Collison <michael.collison@arm.com>
+
+       * arm-dis.c (enum mve_instructions): New enum.
+       (enum mve_unpredictable): Likewise.
+       (enum mve_undefined): Likewise.
+       (struct mopcode32): New struct.
+       (is_mve_okay_in_it): New function.
+       (is_mve_architecture): Likewise.
+       (arm_decode_field): Likewise.
+       (arm_decode_field_multiple): Likewise.
+       (is_mve_encoding_conflict): Likewise.
+       (is_mve_undefined): Likewise.
+       (is_mve_unpredictable): Likewise.
+       (print_mve_undefined): Likewise.
+       (print_mve_unpredictable): Likewise.
+       (print_insn_coprocessor_1): Use arm_decode_field_multiple.
+       (print_insn_mve): New function.
+       (print_insn_thumb32): Handle MVE architecture.
+       (select_arm_features): Force thumb for Armv8.1-m Mainline.
+
 2019-05-10  Nick Clifton  <nickc@redhat.com>
 
        PR 24538
index c2a8a5f..615f34f 100644 (file)
@@ -67,6 +67,23 @@ struct arm_private_data
   bfd_vma last_mapping_addr;
 };
 
+enum mve_instructions
+{
+  MVE_NONE
+};
+
+enum mve_unpredictable
+{
+  UNPRED_IT_BLOCK,             /* Unpredictable because mve insn in it block.
+                                */
+  UNPRED_NONE                  /* No unpredictable behavior.  */
+};
+
+enum mve_undefined
+{
+  UNDEF_NONE                   /* no undefined behavior.  */
+};
+
 struct opcode32
 {
   arm_feature_set arch;                /* Architecture defining this insn.  */
@@ -75,6 +92,18 @@ struct opcode32
   const char *  assembler;     /* How to disassemble this insn.  */
 };
 
+/* MVE opcodes.  */
+
+struct mopcode32
+{
+  arm_feature_set arch;                /* Architecture defining this insn.  */
+  enum mve_instructions mve_op;  /* Specific mve instruction for faster
+                                   decoding.  */
+  unsigned long value;         /* If arch is 0 then value is a sentinel.  */
+  unsigned long mask;          /* Recognise insn if (op & mask) == value.  */
+  const char *  assembler;     /* How to disassemble this insn.  */
+};
+
 enum isa {
   ANY,
   T32,
@@ -1746,6 +1775,18 @@ static const struct opcode32 neon_opcodes[] =
   {ARM_FEATURE_CORE_LOW (0), 0 ,0, 0}
 };
 
+/* mve opcode table.  */
+
+/* print_insn_mve recognizes the following format control codes:
+
+   %%                  %
+
+   */
+
+static const struct mopcode32 mve_opcodes[] =
+{
+};
+
 /* Opcode tables: ARM, 16-bit Thumb, 32-bit Thumb.  All three are partially
    ordered: they must be searched linearly from the top to obtain a correct
    match.  */
@@ -3439,6 +3480,105 @@ arm_decode_shift (long given, fprintf_ftype func, void *stream,
     }
 }
 
+/* Return TRUE if the MATCHED_INSN can be inside an IT block.  */
+
+static bfd_boolean
+is_mve_okay_in_it (enum mve_instructions matched_insn)
+{
+  return FALSE;
+}
+
+static bfd_boolean
+is_mve_architecture (struct disassemble_info *info)
+{
+  struct arm_private_data *private_data = info->private_data;
+  arm_feature_set allowed_arches = private_data->features;
+
+  arm_feature_set arm_ext_v8_1m_main
+    = ARM_FEATURE_CORE_HIGH (ARM_EXT2_V8_1M_MAIN);
+
+  if (ARM_CPU_HAS_FEATURE (arm_ext_v8_1m_main, allowed_arches)
+      && !ARM_CPU_IS_ANY (allowed_arches))
+    return TRUE;
+  else
+    return FALSE;
+}
+
+/* Decode a bitfield from opcode GIVEN, with starting bitfield = START
+   and ending bitfield = END.  END must be greater than START.  */
+
+static unsigned long
+arm_decode_field (unsigned long given, unsigned int start, unsigned int end)
+{
+  int bits = end - start;
+
+  if (bits < 0)
+    abort ();
+
+  return ((given >> start) & ((2ul << bits) - 1));
+}
+
+/* Decode a bitfield from opcode GIVEN, with multiple bitfields:
+   START:END and START2:END2.  END/END2 must be greater than
+   START/START2.  */
+
+static unsigned long
+arm_decode_field_multiple (unsigned long given, unsigned int start,
+                          unsigned int end, unsigned int start2,
+                          unsigned int end2)
+{
+  int bits = end - start;
+  int bits2 = end2 - start2;
+  unsigned long value = 0;
+  int width = 0;
+
+  if (bits2 < 0)
+    abort ();
+
+  value = arm_decode_field (given, start, end);
+  width += bits + 1;
+
+  value |= ((given >> start2) & ((2ul << bits2) - 1)) << width;
+  return value;
+}
+
+/* Return TRUE if the GIVEN encoding should not be decoded as MATCHED_INSN.
+   This helps us decode instructions that change mnemonic depending on specific
+   operand values/encodings.  */
+
+static bfd_boolean
+is_mve_encoding_conflict (unsigned long given,
+                         enum mve_instructions matched_insn)
+{
+  return FALSE;
+}
+
+/* Return FALSE if GIVEN is not an undefined encoding for MATCHED_INSN.
+   Otherwise, return TRUE and set UNDEFINED_CODE to give a reason as to why
+   this encoding is undefined.  */
+
+static bfd_boolean
+is_mve_undefined (unsigned long given, enum mve_instructions matched_insn,
+                 enum mve_undefined *undefined_code)
+{
+  *undefined_code = UNDEF_NONE;
+
+  return FALSE;
+}
+
+/* Return FALSE if GIVEN is not an unpredictable encoding for MATCHED_INSN.
+   Otherwise, return TRUE and set UNPREDICTABLE_CODE to give a reason as to
+   why this encoding is unpredictable.  */
+
+static bfd_boolean
+is_mve_unpredictable (unsigned long given, enum mve_instructions matched_insn,
+                     enum mve_unpredictable *unpredictable_code)
+{
+  *unpredictable_code = UNPRED_NONE;
+
+  return FALSE;
+}
+
 #define W_BIT 21
 #define I_BIT 22
 #define U_BIT 23
@@ -3449,6 +3589,43 @@ arm_decode_shift (long given, fprintf_ftype func, void *stream,
 #define NEGATIVE_BIT_SET   ((given & (1 << U_BIT)) == 0)
 #define PRE_BIT_SET         (given & (1 << P_BIT))
 
+static void
+print_mve_undefined (struct disassemble_info *info,
+                    enum mve_undefined undefined_code)
+{
+  void *stream = info->stream;
+  fprintf_ftype func = info->fprintf_func;
+
+  func (stream, "\t\tundefined instruction: ");
+
+  switch (undefined_code)
+    {
+    case UNDEF_NONE:
+      break;
+    }
+
+}
+
+static void
+print_mve_unpredictable (struct disassemble_info *info,
+                        enum mve_unpredictable unpredict_code)
+{
+  void *stream = info->stream;
+  fprintf_ftype func = info->fprintf_func;
+
+  func (stream, "%s: ", UNPREDICTABLE_INSTRUCTION);
+
+  switch (unpredict_code)
+    {
+    case UNPRED_IT_BLOCK:
+      func (stream, "mve instruction in it block");
+      break;
+
+    case UNPRED_NONE:
+      break;
+    }
+}
+
 /* Print one coprocessor instruction on INFO->STREAM.
    Return TRUE if the instuction matched, FALSE if this is not a
    recognised coprocessor instruction.  */
@@ -3726,7 +3903,8 @@ print_insn_coprocessor (bfd_vma pc,
 
                case 'J':
                  {
-                   int regno = ((given >> 19) & 0x8) | ((given >> 13) & 0x7);
+                   unsigned long regno
+                     = arm_decode_field_multiple (given, 13, 15, 22, 22);
 
                    switch (regno)
                      {
@@ -3749,7 +3927,7 @@ print_insn_coprocessor (bfd_vma pc,
                        func (stream, "FPCXTS");
                        break;
                      default:
-                       func (stream, "<invalid reg %d>", regno);
+                       func (stream, "<invalid reg %lu>", regno);
                        break;
                      }
                  }
@@ -4743,6 +4921,75 @@ print_insn_neon (struct disassemble_info *info, long given, bfd_boolean thumb)
   return FALSE;
 }
 
+/* Print one mve instruction on INFO->STREAM.
+   Return TRUE if the instuction matched, FALSE if this is not a
+   recognised mve instruction.  */
+
+static bfd_boolean
+print_insn_mve (struct disassemble_info *info, long given)
+{
+  const struct mopcode32 *insn;
+  void *stream = info->stream;
+  fprintf_ftype func = info->fprintf_func;
+
+  for (insn = mve_opcodes; insn->assembler; insn++)
+    {
+      if (((given & insn->mask) == insn->value)
+         && !is_mve_encoding_conflict (given, insn->mve_op))
+       {
+         signed long value_in_comment = 0;
+         bfd_boolean is_unpredictable = FALSE;
+         bfd_boolean is_undefined = FALSE;
+         const char *c;
+         enum mve_unpredictable unpredictable_cond = UNPRED_NONE;
+         enum mve_undefined undefined_cond = UNDEF_NONE;
+
+         /* Most vector mve instruction are illegal in a it block.
+            There are a few exceptions; check for them.  */
+         if (ifthen_state && !is_mve_okay_in_it (insn->mve_op))
+           {
+             is_unpredictable = TRUE;
+             unpredictable_cond = UNPRED_IT_BLOCK;
+           }
+         else if (is_mve_unpredictable (given, insn->mve_op,
+                                        &unpredictable_cond))
+           is_unpredictable = TRUE;
+
+         if (is_mve_undefined (given, insn->mve_op, &undefined_cond))
+           is_undefined = TRUE;
+
+         for (c = insn->assembler; *c; c++)
+           {
+             if (*c == '%')
+               {
+                 switch (*++c)
+                   {
+                   case '%':
+                     func (stream, "%%");
+                     break;
+
+                   }
+               }
+             else
+               func (stream, "%c", *c);
+           }
+
+         if (value_in_comment > 32 || value_in_comment < -16)
+           func (stream, "\t; 0x%lx", value_in_comment);
+
+         if (is_unpredictable)
+           print_mve_unpredictable (info, unpredictable_cond);
+
+         if (is_undefined)
+           print_mve_undefined (info, undefined_cond);
+
+         return TRUE;
+       }
+    }
+  return FALSE;
+}
+
+
 /* Return the name of a v7A special register.  */
 
 static const char *
@@ -5653,11 +5900,15 @@ print_insn_thumb32 (bfd_vma pc, struct disassemble_info *info, long given)
   const struct opcode32 *insn;
   void *stream = info->stream;
   fprintf_ftype func = info->fprintf_func;
+  bfd_boolean is_mve = is_mve_architecture (info);
 
   if (print_insn_coprocessor (pc, info, given, TRUE))
     return;
 
-  if (print_insn_neon (info, given, TRUE))
+  if ((is_mve == FALSE) && print_insn_neon (info, given, TRUE))
+    return;
+
+  if (is_mve && print_insn_mve (info, given))
     return;
 
   for (insn = thumb32_opcodes; insn->assembler; insn++)
@@ -6764,7 +7015,10 @@ select_arm_features (unsigned long mach,
     case bfd_mach_arm_8R:       ARM_SET_FEATURES (ARM_ARCH_V8R); break;
     case bfd_mach_arm_8M_BASE:  ARM_SET_FEATURES (ARM_ARCH_V8M_BASE); break;
     case bfd_mach_arm_8M_MAIN:  ARM_SET_FEATURES (ARM_ARCH_V8M_MAIN); break;
-    case bfd_mach_arm_8_1M_MAIN: ARM_SET_FEATURES (ARM_ARCH_V8_1M_MAIN); break;
+    case bfd_mach_arm_8_1M_MAIN:
+      ARM_SET_FEATURES (ARM_ARCH_V8_1M_MAIN);
+      force_thumb = 1;
+      break;
       /* If the machine type is unknown allow all architecture types and all
         extensions.  */
     case bfd_mach_arm_unknown:  ARM_SET_FEATURES (ARM_FEATURE_ALL); break;