[AArch64][SVE 23/32] Add SVE pattern and prfop operands
[deliverable/binutils-gdb.git] / opcodes / aarch64-dis.c
index c403be85ca90b9578cda50492299839f67399ea0..ab93234e28afd54630199f2ea7ce35f7b948d070 100644 (file)
@@ -1,5 +1,5 @@
 /* aarch64-dis.c -- AArch64 disassembler.
-   Copyright 2009-2013  Free Software Foundation, Inc.
+   Copyright (C) 2009-2016 Free Software Foundation, Inc.
    Contributed by ARM Ltd.
 
    This file is part of the GNU opcodes library.
@@ -145,6 +145,26 @@ extract_fields (aarch64_insn code, aarch64_insn mask, ...)
   return value;
 }
 
+/* Extract the value of all fields in SELF->fields from instruction CODE.
+   The least significant bit comes from the final field.  */
+
+static aarch64_insn
+extract_all_fields (const aarch64_operand *self, aarch64_insn code)
+{
+  aarch64_insn value;
+  unsigned int i;
+  enum aarch64_field_kind kind;
+
+  value = 0;
+  for (i = 0; i < ARRAY_SIZE (self->fields) && self->fields[i] != FLD_NIL; ++i)
+    {
+      kind = self->fields[i];
+      value <<= fields[kind].width;
+      value |= extract_field (kind, code, 0);
+    }
+  return value;
+}
+
 /* Sign-extend bit I of VALUE.  */
 static inline int32_t
 sign_extend (aarch64_insn value, unsigned i)
@@ -173,12 +193,19 @@ get_greg_qualifier_from_value (aarch64_insn value)
   return qualifier;
 }
 
-/* Given VALUE, return qualifier for a vector register.  */
+/* Given VALUE, return qualifier for a vector register.  This does not support
+   decoding instructions that accept the 2H vector type.  */
+
 static inline enum aarch64_opnd_qualifier
 get_vreg_qualifier_from_value (aarch64_insn value)
 {
   enum aarch64_opnd_qualifier qualifier = AARCH64_OPND_QLF_V_8B + value;
 
+  /* Instructions using vector type 2H should not call this function.  Skip over
+     the 2H qualifier.  */
+  if (qualifier >= AARCH64_OPND_QLF_V_2H)
+    qualifier += 1;
+
   assert (value <= 0x8
          && aarch64_get_qualifier_standard_value (qualifier) == value);
   return qualifier;
@@ -224,6 +251,17 @@ aarch64_ext_regno (const aarch64_operand *self, aarch64_opnd_info *info,
   return 1;
 }
 
+int
+aarch64_ext_regno_pair (const aarch64_operand *self ATTRIBUTE_UNUSED, aarch64_opnd_info *info,
+                  const aarch64_insn code ATTRIBUTE_UNUSED,
+                  const aarch64_inst *inst ATTRIBUTE_UNUSED)
+{
+  assert (info->idx == 1
+         || info->idx ==3);
+  info->reg.regno = inst->operands[info->idx - 1].reg.regno + 1;
+  return 1;
+}
+
 /* e.g. IC <ic_op>{, <Xt>}.  */
 int
 aarch64_ext_regrt_sysins (const aarch64_operand *self, aarch64_opnd_info *info,
@@ -237,7 +275,7 @@ aarch64_ext_regrt_sysins (const aarch64_operand *self, aarch64_opnd_info *info,
   /* This will make the constraint checking happy and more importantly will
      help the disassembler determine whether this operand is optional or
      not.  */
-  info->present = inst->operands[0].sysins_op->has_xt;
+  info->present = aarch64_sys_ins_reg_has_xt (inst->operands[0].sysins_op);
 
   return 1;
 }
@@ -422,11 +460,17 @@ aarch64_ext_ldst_elemlist (const aarch64_operand *self ATTRIBUTE_UNUSED,
       info->reglist.index = QSsize;
       break;
     case 0x1:
+      if (QSsize & 0x1)
+       /* UND.  */
+       return 0;
       info->qualifier = AARCH64_OPND_QLF_S_H;
       /* Index encoded in "Q:S:size<1>".  */
       info->reglist.index = QSsize >> 1;
       break;
     case 0x2:
+      if ((QSsize >> 1) & 0x1)
+       /* UND.  */
+       return 0;
       if ((QSsize & 0x1) == 0)
        {
          info->qualifier = AARCH64_OPND_QLF_S_S;
@@ -435,12 +479,12 @@ aarch64_ext_ldst_elemlist (const aarch64_operand *self ATTRIBUTE_UNUSED,
        }
       else
        {
-         info->qualifier = AARCH64_OPND_QLF_S_D;
-         /* Index encoded in "Q".  */
-         info->reglist.index = QSsize >> 3;
          if (extract_field (FLD_S, code, 0))
            /* UND */
            return 0;
+         info->qualifier = AARCH64_OPND_QLF_S_D;
+         /* Index encoded in "Q".  */
+         info->reglist.index = QSsize >> 3;
        }
       break;
     default:
@@ -551,17 +595,8 @@ aarch64_ext_imm (const aarch64_operand *self, aarch64_opnd_info *info,
                 const aarch64_inst *inst ATTRIBUTE_UNUSED)
 {
   int64_t imm;
-  /* Maximum of two fields to extract.  */
-  assert (self->fields[2] == FLD_NIL);
-
-  if (self->fields[1] == FLD_NIL)
-    imm = extract_field (self->fields[0], code, 0);
-  else
-    /* e.g. TBZ b5:b40.  */
-    imm = extract_fields (code, 0, 2, self->fields[0], self->fields[1]);
 
-  if (info->type == AARCH64_OPND_FPIMM)
-    info->imm.is_fp = 1;
+  imm = extract_all_fields (self, code);
 
   if (operand_need_sign_extension (self))
     imm = sign_extend (imm, get_operand_fields_width (self) - 1);
@@ -657,6 +692,17 @@ aarch64_ext_advsimd_imm_modified (const aarch64_operand *self ATTRIBUTE_UNUSED,
   return 1;
 }
 
+/* Decode an 8-bit floating-point immediate.  */
+int
+aarch64_ext_fpimm (const aarch64_operand *self, aarch64_opnd_info *info,
+                  const aarch64_insn code,
+                  const aarch64_inst *inst ATTRIBUTE_UNUSED)
+{
+  info->imm.value = extract_all_fields (self, code);
+  info->imm.is_fp = 1;
+  return 1;
+}
+
 /* Decode scale for e.g. SCVTF <Dd>, <Wn>, #<fbits>.  */
 int
 aarch64_ext_fbits (const aarch64_operand *self ATTRIBUTE_UNUSED,
@@ -1010,14 +1056,14 @@ aarch64_ext_sysins_op (const aarch64_operand *self ATTRIBUTE_UNUSED,
     default: assert (0); return 0;
     }
 
-  for (i = 0; sysins_ops[i].template != NULL; ++i)
+  for (i = 0; sysins_ops[i].name != NULL; ++i)
     if (sysins_ops[i].value == value)
       {
        info->sysins_op = sysins_ops + i;
        DEBUG_TRACE ("%s found value: %x, has_xt: %d, i: %d.",
-                    info->sysins_op->template,
+                    info->sysins_op->name,
                     (unsigned)info->sysins_op->value,
-                    info->sysins_op->has_xt, i);
+                    aarch64_sys_ins_reg_has_xt (info->sysins_op), i);
        return 1;
       }
 
@@ -1050,6 +1096,33 @@ aarch64_ext_prfop (const aarch64_operand *self ATTRIBUTE_UNUSED,
   return 1;
 }
 
+/* Decode the hint number for an alias taking an operand.  Set info->hint_option
+   to the matching name/value pair in aarch64_hint_options.  */
+
+int
+aarch64_ext_hint (const aarch64_operand *self ATTRIBUTE_UNUSED,
+                 aarch64_opnd_info *info,
+                 aarch64_insn code,
+                 const aarch64_inst *inst ATTRIBUTE_UNUSED)
+{
+  /* CRm:op2.  */
+  unsigned hint_number;
+  int i;
+
+  hint_number = extract_fields (code, 0, 2, FLD_CRm, FLD_op2);
+
+  for (i = 0; aarch64_hint_options[i].name != NULL; i++)
+    {
+      if (hint_number == aarch64_hint_options[i].value)
+       {
+         info->hint_option = &(aarch64_hint_options[i]);
+         return 1;
+       }
+    }
+
+  return 0;
+}
+
 /* Decode the extended register operand for e.g.
      STR <Qt>, [<Xn|SP>, <R><m>{, <extend> {<amount>}}].  */
 int
@@ -1112,6 +1185,40 @@ aarch64_ext_reg_shifted (const aarch64_operand *self ATTRIBUTE_UNUSED,
 
   return 1;
 }
+
+/* Decode Zn[MM], where MM has a 7-bit triangular encoding.  The fields
+   array specifies which field to use for Zn.  MM is encoded in the
+   concatenation of imm5 and SVE_tszh, with imm5 being the less
+   significant part.  */
+int
+aarch64_ext_sve_index (const aarch64_operand *self,
+                      aarch64_opnd_info *info, aarch64_insn code,
+                      const aarch64_inst *inst ATTRIBUTE_UNUSED)
+{
+  int val;
+
+  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)
+    return 0;
+  while ((val & 1) == 0)
+    val /= 2;
+  info->reglane.index = val / 2;
+  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.  */
+int
+aarch64_ext_sve_reglist (const aarch64_operand *self,
+                        aarch64_opnd_info *info, aarch64_insn code,
+                        const aarch64_inst *inst ATTRIBUTE_UNUSED)
+{
+  info->reglist.first_regno = extract_field (self->fields[0], code, 0);
+  info->reglist.num_regs = get_opcode_dependent_value (inst->opcode);
+  return 1;
+}
 \f
 /* Bitfields that are commonly used to encode certain operands' information
    may be partially used as part of the base opcode in some instructions.
@@ -1354,6 +1461,13 @@ do_special_decoding (aarch64_inst *inst)
          && extract_field (FLD_N, inst->value, 0) != value)
        return 0;
     }
+  /* 'sf' field.  */
+  if (inst->opcode->flags & F_LSE_SZ)
+    {
+      idx = select_operand_for_sf_field_coding (inst->opcode);
+      value = extract_field (FLD_lse_sz, inst->value, 0);
+      inst->operands[idx].qualifier = get_greg_qualifier_from_value (value);
+    }
   /* size:Q fields.  */
   if (inst->opcode->flags & F_SIZEQ)
     return decode_sizeq (inst);
@@ -1576,6 +1690,45 @@ convert_bfm_to_bfi (aarch64_inst *inst)
   return 0;
 }
 
+/* The instruction written:
+     BFC <Xd>, #<lsb>, #<width>
+   is equivalent to:
+     BFM <Xd>, XZR, #((64-<lsb>)&0x3f), #(<width>-1).  */
+
+static int
+convert_bfm_to_bfc (aarch64_inst *inst)
+{
+  int64_t immr, imms, val;
+
+  /* Should have been assured by the base opcode value.  */
+  assert (inst->operands[1].reg.regno == 0x1f);
+
+  immr = inst->operands[2].imm.value;
+  imms = inst->operands[3].imm.value;
+  val = inst->operands[2].qualifier == AARCH64_OPND_QLF_imm_0_31 ? 32 : 64;
+  if (imms < immr)
+    {
+      /* Drop XZR from the second operand.  */
+      copy_operand_info (inst, 1, 2);
+      copy_operand_info (inst, 2, 3);
+      inst->operands[3].type = AARCH64_OPND_NIL;
+
+      /* Recalculate the immediates.  */
+      inst->operands[1].imm.value = (val - immr) & (val - 1);
+      inst->operands[2].imm.value = imms + 1;
+
+      /* The two opcodes have different qualifiers for the operands; reset to
+        help the checking.  */
+      reset_operand_qualifier (inst, 1);
+      reset_operand_qualifier (inst, 2);
+      reset_operand_qualifier (inst, 3);
+
+      return 1;
+    }
+
+  return 0;
+}
+
 /* The instruction written:
      LSL <Xd>, <Xn>, #<shift>
    is equivalent to:
@@ -1601,12 +1754,14 @@ convert_ubfm_to_lsl (aarch64_inst *inst)
 
 /* CINC <Wd>, <Wn>, <cond>
      is equivalent to:
-   CSINC <Wd>, <Wn>, <Wn>, invert(<cond>).  */
+   CSINC <Wd>, <Wn>, <Wn>, invert(<cond>)
+     where <cond> is not AL or NV.  */
 
 static int
 convert_from_csel (aarch64_inst *inst)
 {
-  if (inst->operands[1].reg.regno == inst->operands[2].reg.regno)
+  if (inst->operands[1].reg.regno == inst->operands[2].reg.regno
+      && (inst->operands[3].cond->value & 0xe) != 0xe)
     {
       copy_operand_info (inst, 2, 3);
       inst->operands[2].cond = get_inverted_cond (inst->operands[3].cond);
@@ -1618,13 +1773,15 @@ convert_from_csel (aarch64_inst *inst)
 
 /* CSET <Wd>, <cond>
      is equivalent to:
-   CSINC <Wd>, WZR, WZR, invert(<cond>).  */
+   CSINC <Wd>, WZR, WZR, invert(<cond>)
+     where <cond> is not AL or NV.  */
 
 static int
 convert_csinc_to_cset (aarch64_inst *inst)
 {
   if (inst->operands[1].reg.regno == 0x1f
-      && inst->operands[2].reg.regno == 0x1f)
+      && inst->operands[2].reg.regno == 0x1f
+      && (inst->operands[3].cond->value & 0xe) != 0xe)
     {
       copy_operand_info (inst, 1, 3);
       inst->operands[1].cond = get_inverted_cond (inst->operands[3].cond);
@@ -1731,6 +1888,8 @@ convert_to_alias (aarch64_inst *inst, const aarch64_opcode *alias)
     case OP_BFI:
     case OP_UBFIZ:
       return convert_bfm_to_bfi (inst);
+    case OP_BFC:
+      return convert_bfm_to_bfc (inst);
     case OP_MOV_V:
       return convert_orr_to_mov (inst);
     case OP_MOV_IMM_WIDE:
@@ -1838,7 +1997,7 @@ determine_disassembling_preference (struct aarch64_inst *inst)
   for (; alias; alias = aarch64_find_next_alias_opcode (alias))
     {
       DEBUG_TRACE ("try %s", alias->name);
-      assert (alias_opcode_p (alias));
+      assert (alias_opcode_p (alias) || opcode_has_alias (opcode));
 
       /* An alias can be a pseudo opcode which will never be used in the
         disassembly, e.g. BIC logical immediate is such a pseudo opcode
@@ -1944,6 +2103,7 @@ aarch64_opcode_decode (const aarch64_opcode *opcode, const aarch64_insn code,
     {
       const aarch64_operand *opnd;
       enum aarch64_opnd type;
+
       type = opcode->operands[i];
       if (type == AARCH64_OPND_NIL)
        break;
@@ -1956,6 +2116,13 @@ aarch64_opcode_decode (const aarch64_opcode *opcode, const aarch64_insn code,
        }
     }
 
+  /* If the opcode has a verifier, then check it now.  */
+  if (opcode->verifier && ! opcode->verifier (opcode, code))
+    {
+      DEBUG_TRACE ("operand verifier FAIL");
+      goto decode_fail;
+    }
+
   /* Match the qualifiers.  */
   if (aarch64_match_operands_constraint (inst, NULL) == 1)
     {
@@ -2001,11 +2168,13 @@ user_friendly_fixup (aarch64_inst *inst)
     }
 }
 
-/* Decode INSN and fill in *INST the instruction information.  */
+/* Decode INSN and fill in *INST the instruction information.  An alias
+   opcode may be filled in *INSN if NOALIASES_P is FALSE.  Return zero on
+   success.  */
 
-static int
-disas_aarch64_insn (uint64_t pc ATTRIBUTE_UNUSED, uint32_t insn,
-                   aarch64_inst *inst)
+int
+aarch64_decode_insn (aarch64_insn insn, aarch64_inst *inst,
+                    bfd_boolean noaliases_p)
 {
   const aarch64_opcode *opcode = aarch64_opcode_lookup (insn);
 
@@ -2032,7 +2201,7 @@ disas_aarch64_insn (uint64_t pc ATTRIBUTE_UNUSED, uint32_t insn,
     {
       /* But only one opcode can be decoded successfully for, as the
         decoding routine will check the constraint carefully.  */
-      if (aarch64_opcode_decode (opcode, insn, inst, no_aliases) == 1)
+      if (aarch64_opcode_decode (opcode, insn, inst, noaliases_p) == 1)
        return ERR_OK;
       opcode = aarch64_find_next_opcode (opcode);
     }
@@ -2049,8 +2218,7 @@ print_operands (bfd_vma pc, const aarch64_opcode *opcode,
   int i, pcrel_p, num_printed;
   for (i = 0, num_printed = 0; i < AARCH64_MAX_OPND_NUM; ++i)
     {
-      const size_t size = 128;
-      char str[size];
+      char str[128];
       /* We regard the opcode operand info more, however we also look into
         the inst->operands to support the disassembling of the optional
         operand.
@@ -2061,7 +2229,7 @@ print_operands (bfd_vma pc, const aarch64_opcode *opcode,
        break;
 
       /* Generate the operand string in STR.  */
-      aarch64_print_operand (str, size, pc, opcode, opnds, i, &pcrel_p,
+      aarch64_print_operand (str, sizeof (str), pc, opcode, opnds, i, &pcrel_p,
                             &info->target);
 
       /* Print the delimiter (taking account of omitted operand(s)).  */
@@ -2144,7 +2312,7 @@ print_insn_aarch64_word (bfd_vma pc,
        addresses, since the addend is not currently pc-relative.  */
     pc = 0;
 
-  ret = disas_aarch64_insn (pc, word, &inst);
+  ret = aarch64_decode_insn (word, &inst, no_aliases);
 
   if (((word >> 21) & 0x3ff) == 1)
     {
This page took 0.029118 seconds and 4 git commands to generate.