Correct disassembly of dot product instructions.
[deliverable/binutils-gdb.git] / opcodes / aarch64-dis.c
index f84f216f7890817384bf0e4b42b752ef3d84a8e3..aa38adb9020eb916515a1154aa5270db1f090830 100644 (file)
@@ -1,5 +1,5 @@
 /* aarch64-dis.c -- AArch64 disassembler.
-   Copyright (C) 2009-2016 Free Software Foundation, Inc.
+   Copyright (C) 2009-2017 Free Software Foundation, Inc.
    Contributed by ARM Ltd.
 
    This file is part of the GNU opcodes library.
@@ -20,7 +20,7 @@
 
 #include "sysdep.h"
 #include "bfd_stdint.h"
-#include "dis-asm.h"
+#include "disassemble.h"
 #include "libiberty.h"
 #include "opintl.h"
 #include "aarch64-dis.h"
@@ -123,7 +123,7 @@ parse_aarch64_dis_options (const char *options)
    is encoded in H:L:M in some cases, the fields H:L:M should be passed in
    the order of H, L, M.  */
 
-static inline aarch64_insn
+aarch64_insn
 extract_fields (aarch64_insn code, aarch64_insn mask, ...)
 {
   uint32_t num;
@@ -325,6 +325,26 @@ aarch64_ext_reglane (const aarch64_operand *self, aarch64_opnd_info *info,
          info->reglane.index = (unsigned) (value >> 1);
        }
     }
+  else if (inst->opcode->iclass == dotproduct)
+    {
+      /* Need information in other operand(s) to help decoding.  */
+      info->qualifier = get_expected_qualifier (inst, info->idx);
+      switch (info->qualifier)
+       {
+       case AARCH64_OPND_QLF_S_4B:
+         /* L:H */
+         info->reglane.index = extract_fields (code, 0, 2, FLD_H, FLD_L);
+         info->reglane.regno &= 0x1f;
+         break;
+       default:
+         return 0;
+       }
+    }
+  else if (inst->opcode->iclass == cryptosm3)
+    {
+      /* index for e.g. SM3TT2A <Vd>.4S, <Vn>.4S, <Vm>S[<imm2>].  */
+      info->reglane.index = extract_field (FLD_SM3_imm2, code, 0);
+    }
   else
     {
       /* Index only for e.g. SQDMLAL <Va><d>, <Vb><n>, <Vm>.<Ts>[<index>]
@@ -351,6 +371,14 @@ aarch64_ext_reglane (const aarch64_operand *self, aarch64_opnd_info *info,
        default:
          return 0;
        }
+
+      if (inst->opcode->op == OP_FCMLA_ELEM)
+       {
+         /* Complex operand takes two elements.  */
+         if (info->reglane.index & 1)
+           return 0;
+         info->reglane.index /= 2;
+       }
     }
 
   return 1;
@@ -401,6 +429,9 @@ aarch64_ext_ldst_reglist (const aarch64_operand *self ATTRIBUTE_UNUSED,
   info->reglist.first_regno = extract_field (FLD_Rt, code, 0);
   /* opcode */
   value = extract_field (FLD_opcode, code, 0);
+  /* PR 21595: Check for a bogus value.  */
+  if (value >= ARRAY_SIZE (data))
+    return 0;
   if (expected_num != data[value].num_elements || data[value].is_reserved)
     return 0;
   info->reglist.num_regs = data[value].num_regs;
@@ -703,6 +734,30 @@ aarch64_ext_fpimm (const aarch64_operand *self, aarch64_opnd_info *info,
   return 1;
 }
 
+/* Decode a 1-bit rotate immediate (#90 or #270).  */
+int
+aarch64_ext_imm_rotate1 (const aarch64_operand *self, aarch64_opnd_info *info,
+                        const aarch64_insn code,
+                        const aarch64_inst *inst ATTRIBUTE_UNUSED)
+{
+  uint64_t rot = extract_field (self->fields[0], code, 0);
+  assert (rot < 2U);
+  info->imm.value = rot * 180 + 90;
+  return 1;
+}
+
+/* Decode a 2-bit rotate immediate (#0, #90, #180 or #270).  */
+int
+aarch64_ext_imm_rotate2 (const aarch64_operand *self, aarch64_opnd_info *info,
+                        const aarch64_insn code,
+                        const aarch64_inst *inst ATTRIBUTE_UNUSED)
+{
+  uint64_t rot = extract_field (self->fields[0], code, 0);
+  assert (rot < 4U);
+  info->imm.value = rot * 90;
+  return 1;
+}
+
 /* Decode scale for e.g. SCVTF <Dd>, <Wn>, #<fbits>.  */
 int
 aarch64_ext_fbits (const aarch64_operand *self ATTRIBUTE_UNUSED,
@@ -788,10 +843,15 @@ decode_limm (uint32_t esize, aarch64_insn value, int64_t *result)
   switch (simd_size)
     {
     case  2: imm = (imm <<  2) | imm;
+      /* Fall through.  */
     case  4: imm = (imm <<  4) | imm;
+      /* Fall through.  */
     case  8: imm = (imm <<  8) | imm;
+      /* Fall through.  */
     case 16: imm = (imm << 16) | imm;
+      /* Fall through.  */
     case 32: imm = (imm << 32) | imm;
+      /* Fall through.  */
     case 64: break;
     default: assert (0); return 0;
     }
@@ -881,6 +941,28 @@ aarch64_ext_addr_simple (const aarch64_operand *self ATTRIBUTE_UNUSED,
   return 1;
 }
 
+/* Decode the address operand for e.g.
+     stlur <Xt>, [<Xn|SP>{, <amount>}].  */
+int
+aarch64_ext_addr_offset (const aarch64_operand *self ATTRIBUTE_UNUSED,
+                        aarch64_opnd_info *info,
+                        aarch64_insn code, const aarch64_inst *inst)
+{
+  info->qualifier = get_expected_qualifier (inst, info->idx);
+
+  /* Rn */
+  info->addr.base_regno = extract_field (self->fields[0], code, 0);
+
+  /* simm9 */
+  aarch64_insn imm = extract_fields (code, 0, 1, self->fields[1]);
+  info->addr.offset.imm = sign_extend (imm, 8);
+  if (extract_field (self->fields[2], code, 0) == 1) {
+    info->addr.writeback = 1;
+    info->addr.preind = 1;
+  }
+  return 1;
+}
+
 /* Decode the address operand for e.g.
      STR <Qt>, [<Xn|SP>, <R><m>{, <extend> {<amount>}}].  */
 int
@@ -976,6 +1058,27 @@ aarch64_ext_addr_uimm12 (const aarch64_operand *self, aarch64_opnd_info *info,
   return 1;
 }
 
+/* Decode the address operand for e.g. LDRAA <Xt>, [<Xn|SP>{, #<simm>}].  */
+int
+aarch64_ext_addr_simm10 (const aarch64_operand *self, aarch64_opnd_info *info,
+                        aarch64_insn code,
+                        const aarch64_inst *inst ATTRIBUTE_UNUSED)
+{
+  aarch64_insn imm;
+
+  info->qualifier = get_expected_qualifier (inst, info->idx);
+  /* Rn */
+  info->addr.base_regno = extract_field (self->fields[0], code, 0);
+  /* simm10 */
+  imm = extract_fields (code, 0, 2, self->fields[1], self->fields[2]);
+  info->addr.offset.imm = sign_extend (imm, 9) << 3;
+  if (extract_field (self->fields[3], code, 0) == 1) {
+    info->addr.writeback = 1;
+    info->addr.preind = 1;
+  }
+  return 1;
+}
+
 /* Decode the address operand for e.g.
      LD1 {<Vt>.<T>, <Vt2>.<T>, <Vt3>.<T>}, [<Xn|SP>], <Xm|#<amount>>.  */
 int
@@ -1296,6 +1399,18 @@ aarch64_ext_sve_addr_reg_imm (const aarch64_operand *self,
   return 1;
 }
 
+/* Decode an SVE address [X<n>, #<SVE_imm4> << <shift>], where <SVE_imm4>
+   is a 4-bit signed number and where <shift> is SELF's operand-dependent
+   value.  fields[0] specifies the base register field.  */
+int
+aarch64_ext_sve_addr_ri_s4 (const aarch64_operand *self,
+                           aarch64_opnd_info *info, aarch64_insn code,
+                           const aarch64_inst *inst ATTRIBUTE_UNUSED)
+{
+  int offset = sign_extend (extract_field (FLD_SVE_imm4, code, 0), 3);
+  return aarch64_ext_sve_addr_reg_imm (self, info, code, offset);
+}
+
 /* Decode an SVE address [X<n>, #<SVE_imm6> << <shift>], where <SVE_imm6>
    is a 6-bit unsigned number and where <shift> is SELF's operand-dependent
    value.  fields[0] specifies the base register field.  */
@@ -1316,14 +1431,14 @@ aarch64_ext_sve_addr_rr_lsl (const aarch64_operand *self,
                             aarch64_opnd_info *info, aarch64_insn code,
                             const aarch64_inst *inst ATTRIBUTE_UNUSED)
 {
-  int index;
+  int index_regno;
 
-  index = extract_field (self->fields[1], code, 0);
-  if (index == 31 && (self->flags & OPD_F_NO_ZR) != 0)
+  index_regno = extract_field (self->fields[1], code, 0);
+  if (index_regno == 31 && (self->flags & OPD_F_NO_ZR) != 0)
     return 0;
 
   info->addr.base_regno = extract_field (self->fields[0], code, 0);
-  info->addr.offset.regno = index;
+  info->addr.offset.regno = index_regno;
   info->addr.offset.is_reg = TRUE;
   info->addr.writeback = FALSE;
   info->addr.preind = TRUE;
@@ -1523,7 +1638,7 @@ aarch64_ext_sve_index (const aarch64_operand *self,
 
   info->reglane.regno = extract_field (self->fields[0], code, 0);
   val = extract_fields (code, 0, 2, FLD_SVE_tszh, FLD_imm5);
-  if ((val & 15) == 0)
+  if ((val & 31) == 0)
     return 0;
   while ((val & 1) == 0)
     val /= 2;
@@ -1542,6 +1657,21 @@ aarch64_ext_sve_limm_mov (const aarch64_operand *self,
          && aarch64_sve_dupm_mov_immediate_p (info->imm.value, esize));
 }
 
+/* Decode Zn[MM], where Zn occupies the least-significant part of the field
+   and where MM occupies the most-significant part.  The operand-dependent
+   value specifies the number of bits in Zn.  */
+int
+aarch64_ext_sve_quad_index (const aarch64_operand *self,
+                           aarch64_opnd_info *info, aarch64_insn code,
+                           const aarch64_inst *inst ATTRIBUTE_UNUSED)
+{
+  unsigned int reg_bits = get_operand_specific_data (self);
+  unsigned int val = extract_all_fields (self, code);
+  info->reglane.regno = val & ((1 << reg_bits) - 1);
+  info->reglane.index = val >> reg_bits;
+  return 1;
+}
+
 /* Decode {Zn.<T> - Zm.<T>}.  The fields array specifies which field
    to use for Zn.  The opcode-dependent value specifies the number
    of registers in the list.  */
@@ -1811,17 +1941,59 @@ decode_fcvt (aarch64_inst *inst)
 static int
 do_misc_decoding (aarch64_inst *inst)
 {
+  unsigned int value;
   switch (inst->opcode->op)
     {
     case OP_FCVT:
       return decode_fcvt (inst);
+
     case OP_FCVTN:
     case OP_FCVTN2:
     case OP_FCVTL:
     case OP_FCVTL2:
       return decode_asimd_fcvt (inst);
+
     case OP_FCVTXN_S:
       return decode_asisd_fcvtxn (inst);
+
+    case OP_MOV_P_P:
+    case OP_MOVS_P_P:
+      value = extract_field (FLD_SVE_Pn, inst->value, 0);
+      return (value == extract_field (FLD_SVE_Pm, inst->value, 0)
+             && value == extract_field (FLD_SVE_Pg4_10, inst->value, 0));
+
+    case OP_MOV_Z_P_Z:
+      return (extract_field (FLD_SVE_Zd, inst->value, 0)
+             == extract_field (FLD_SVE_Zm_16, inst->value, 0));
+
+    case OP_MOV_Z_V:
+      /* Index must be zero.  */
+      value = extract_fields (inst->value, 0, 2, FLD_SVE_tszh, FLD_imm5);
+      return value > 0 && value <= 16 && value == (value & -value);
+
+    case OP_MOV_Z_Z:
+      return (extract_field (FLD_SVE_Zn, inst->value, 0)
+             == extract_field (FLD_SVE_Zm_16, inst->value, 0));
+
+    case OP_MOV_Z_Zi:
+      /* Index must be nonzero.  */
+      value = extract_fields (inst->value, 0, 2, FLD_SVE_tszh, FLD_imm5);
+      return value > 0 && value != (value & -value);
+
+    case OP_MOVM_P_P_P:
+      return (extract_field (FLD_SVE_Pd, inst->value, 0)
+             == extract_field (FLD_SVE_Pm, inst->value, 0));
+
+    case OP_MOVZS_P_P_P:
+    case OP_MOVZ_P_P_P:
+      return (extract_field (FLD_SVE_Pn, inst->value, 0)
+             == extract_field (FLD_SVE_Pm, inst->value, 0));
+
+    case OP_NOTS_P_P_P_Z:
+    case OP_NOT_P_P_P_Z:
+      return (extract_field (FLD_SVE_Pm, inst->value, 0)
+             == extract_field (FLD_SVE_Pg4_10, inst->value, 0));
+
     default:
       return 0;
     }
@@ -2212,7 +2384,7 @@ convert_movewide_to_mov (aarch64_inst *inst)
       int is32 = inst->operands[0].qualifier == AARCH64_OPND_QLF_W;
       value = ~value;
       /* A MOVN has an immediate that could be encoded by MOVZ.  */
-      if (aarch64_wide_constant_p (value, is32, NULL) == TRUE)
+      if (aarch64_wide_constant_p (value, is32, NULL))
        return 0;
     }
   inst->operands[1].imm.value = value;
@@ -2245,8 +2417,8 @@ convert_movebitmask_to_mov (aarch64_inst *inst)
   /* ORR has an immediate that could be generated by a MOVZ or MOVN
      instruction.  */
   if (inst->operands[0].reg.regno != 0x1f
-      && (aarch64_wide_constant_p (value, is32, NULL) == TRUE
-         || aarch64_wide_constant_p (~value, is32, NULL) == TRUE))
+      && (aarch64_wide_constant_p (value, is32, NULL)
+         || aarch64_wide_constant_p (~value, is32, NULL)))
     return 0;
 
   inst->operands[2].type = AARCH64_OPND_NIL;
@@ -2367,7 +2539,7 @@ determine_disassembling_preference (struct aarch64_inst *inst)
   opcode = inst->opcode;
 
   /* This opcode does not have an alias, so use itself.  */
-  if (opcode_has_alias (opcode) == FALSE)
+  if (!opcode_has_alias (opcode))
     return;
 
   alias = aarch64_find_alias_opcode (opcode);
@@ -2463,8 +2635,8 @@ aarch64_decode_variant_using_iclass (aarch64_inst *inst)
       break;
 
     case sve_index:
-      i = extract_field (FLD_SVE_tsz, inst->value, 0);
-      if (i == 0)
+      i = extract_fields (inst->value, 0, 2, FLD_SVE_tszh, FLD_imm5);
+      if ((i & 31) == 0)
        return FALSE;
       while ((i & 1) == 0)
        {
@@ -2745,6 +2917,22 @@ print_operands (bfd_vma pc, const aarch64_opcode *opcode,
     }
 }
 
+/* Set NAME to a copy of INST's mnemonic with the "." suffix removed.  */
+
+static void
+remove_dot_suffix (char *name, const aarch64_inst *inst)
+{
+  char *ptr;
+  size_t len;
+
+  ptr = strchr (inst->opcode->name, '.');
+  assert (ptr && inst->cond);
+  len = ptr - inst->opcode->name;
+  assert (len < 8);
+  strncpy (name, inst->opcode->name, len);
+  name[len] = '\0';
+}
+
 /* Print the instruction mnemonic name.  */
 
 static void
@@ -2755,21 +2943,35 @@ print_mnemonic_name (const aarch64_inst *inst, struct disassemble_info *info)
       /* For instructions that are truly conditionally executed, e.g. b.cond,
         prepare the full mnemonic name with the corresponding condition
         suffix.  */
-      char name[8], *ptr;
-      size_t len;
-
-      ptr = strchr (inst->opcode->name, '.');
-      assert (ptr && inst->cond);
-      len = ptr - inst->opcode->name;
-      assert (len < 8);
-      strncpy (name, inst->opcode->name, len);
-      name [len] = '\0';
+      char name[8];
+
+      remove_dot_suffix (name, inst);
       (*info->fprintf_func) (info->stream, "%s.%s", name, inst->cond->names[0]);
     }
   else
     (*info->fprintf_func) (info->stream, "%s", inst->opcode->name);
 }
 
+/* Decide whether we need to print a comment after the operands of
+   instruction INST.  */
+
+static void
+print_comment (const aarch64_inst *inst, struct disassemble_info *info)
+{
+  if (inst->opcode->flags & F_COND)
+    {
+      char name[8];
+      unsigned int i, num_conds;
+
+      remove_dot_suffix (name, inst);
+      num_conds = ARRAY_SIZE (inst->cond->names);
+      for (i = 1; i < num_conds && inst->cond->names[i]; ++i)
+       (*info->fprintf_func) (info->stream, "%s %s.%s",
+                              i == 1 ? "  //" : ",",
+                              name, inst->cond->names[i]);
+    }
+}
+
 /* Print the instruction according to *INST.  */
 
 static void
@@ -2778,6 +2980,7 @@ print_aarch64_insn (bfd_vma pc, const aarch64_inst *inst,
 {
   print_mnemonic_name (inst, info);
   print_operands (pc, inst->opcode, inst->operands, info);
+  print_comment (inst, info);
 }
 
 /* Entry-point of the instruction disassembler and printer.  */
@@ -2894,6 +3097,10 @@ get_sym_code_type (struct disassemble_info *info, int n,
   unsigned int type;
   const char *name;
 
+  /* If the symbol is in a different section, ignore it.  */
+  if (info->section != NULL && info->section != info->symtab[n]->section)
+    return FALSE;
+
   es = *(elf_symbol_type **)(info->symtab + n);
   type = ELF_ST_TYPE (es->internal_elf_sym.st_info);
 
@@ -2968,9 +3175,7 @@ print_insn_aarch64 (bfd_vma pc,
          addr = bfd_asymbol_value (info->symtab[n]);
          if (addr > pc)
            break;
-         if ((info->section == NULL
-              || info->section == info->symtab[n]->section)
-             && get_sym_code_type (info, n, &type))
+         if (get_sym_code_type (info, n, &type))
            {
              last_sym = n;
              found = TRUE;
This page took 0.030242 seconds and 4 git commands to generate.