[AArch64][SVE 21/32] Add Zn and Pn registers
[external/binutils.git] / opcodes / aarch64-opc.c
index 6eac70a..56a0169 100644 (file)
@@ -199,6 +199,22 @@ const aarch64_field fields[] =
     { 31,  1 },        /* b5: in the test bit and branch instructions.  */
     { 19,  5 },        /* b40: in the test bit and branch instructions.  */
     { 10,  6 },        /* scale: in the fixed-point scalar to fp converting inst.  */
+    {  0,  4 }, /* SVE_Pd: p0-p15, bits [3,0].  */
+    { 10,  3 }, /* SVE_Pg3: p0-p7, bits [12,10].  */
+    {  5,  4 }, /* SVE_Pg4_5: p0-p15, bits [8,5].  */
+    { 10,  4 }, /* SVE_Pg4_10: p0-p15, bits [13,10].  */
+    { 16,  4 }, /* SVE_Pg4_16: p0-p15, bits [19,16].  */
+    { 16,  4 }, /* SVE_Pm: p0-p15, bits [19,16].  */
+    {  5,  4 }, /* SVE_Pn: p0-p15, bits [8,5].  */
+    {  0,  4 }, /* SVE_Pt: p0-p15, bits [3,0].  */
+    {  5,  5 }, /* SVE_Za_5: SVE vector register, bits [9,5].  */
+    { 16,  5 }, /* SVE_Za_16: SVE vector register, bits [20,16].  */
+    {  0,  5 }, /* SVE_Zd: SVE vector register. bits [4,0].  */
+    {  5,  5 }, /* SVE_Zm_5: SVE vector register, bits [9,5].  */
+    { 16,  5 }, /* SVE_Zm_16: SVE vector register, bits [20,16]. */
+    {  5,  5 }, /* SVE_Zn: SVE vector register, bits [9,5].  */
+    {  0,  5 }, /* SVE_Zt: SVE vector register, bits [4,0].  */
+    { 22,  2 }, /* SVE_tszh: triangular size select high, bits [23,22].  */
 };
 
 enum aarch64_operand_class
@@ -1332,6 +1348,43 @@ operand_general_constraint_met_p (const aarch64_opnd_info *opnds, int idx,
        }
       break;
 
+    case AARCH64_OPND_CLASS_SVE_REG:
+      switch (type)
+       {
+       case AARCH64_OPND_SVE_Zn_INDEX:
+         size = aarch64_get_qualifier_esize (opnd->qualifier);
+         if (!value_in_range_p (opnd->reglane.index, 0, 64 / size - 1))
+           {
+             set_elem_idx_out_of_range_error (mismatch_detail, idx,
+                                              0, 64 / size - 1);
+             return 0;
+           }
+         break;
+
+       case AARCH64_OPND_SVE_ZnxN:
+       case AARCH64_OPND_SVE_ZtxN:
+         if (opnd->reglist.num_regs != get_opcode_dependent_value (opcode))
+           {
+             set_other_error (mismatch_detail, idx,
+                              _("invalid register list"));
+             return 0;
+           }
+         break;
+
+       default:
+         break;
+       }
+      break;
+
+    case AARCH64_OPND_CLASS_PRED_REG:
+      if (opnd->reg.regno >= 8
+         && get_operand_fields_width (get_operand_from_code (type)) == 3)
+       {
+         set_other_error (mismatch_detail, idx, _("p0-p7 expected"));
+         return 0;
+       }
+      break;
+
     case AARCH64_OPND_CLASS_COND:
       if (type == AARCH64_OPND_COND1
          && (opnds[idx].cond->value & 0xe) == 0xe)
@@ -2058,6 +2111,23 @@ aarch64_match_operands_constraint (aarch64_inst *inst,
 
   DEBUG_TRACE ("enter");
 
+  /* Check for cases where a source register needs to be the same as the
+     destination register.  Do this before matching qualifiers since if
+     an instruction has both invalid tying and invalid qualifiers,
+     the error about qualifiers would suggest several alternative
+     instructions that also have invalid tying.  */
+  i = inst->opcode->tied_operand;
+  if (i > 0 && (inst->operands[0].reg.regno != inst->operands[i].reg.regno))
+    {
+      if (mismatch_detail)
+       {
+         mismatch_detail->kind = AARCH64_OPDE_UNTIED_OPERAND;
+         mismatch_detail->index = i;
+         mismatch_detail->error = NULL;
+       }
+      return 0;
+    }
+
   /* Match operands' qualifier.
      *INST has already had qualifier establish for some, if not all, of
      its operands; we need to find out whether these established
@@ -2149,32 +2219,25 @@ aarch64_operand_index (const enum aarch64_opnd *operands, enum aarch64_opnd oper
   return -1;
 }
 \f
+/* R0...R30, followed by FOR31.  */
+#define BANK(R, FOR31) \
+  { R  (0), R  (1), R  (2), R  (3), R  (4), R  (5), R  (6), R  (7), \
+    R  (8), R  (9), R (10), R (11), R (12), R (13), R (14), R (15), \
+    R (16), R (17), R (18), R (19), R (20), R (21), R (22), R (23), \
+    R (24), R (25), R (26), R (27), R (28), R (29), R (30),  FOR31 }
 /* [0][0]  32-bit integer regs with sp   Wn
    [0][1]  64-bit integer regs with sp   Xn  sf=1
    [1][0]  32-bit integer regs with #0   Wn
    [1][1]  64-bit integer regs with #0   Xn  sf=1 */
 static const char *int_reg[2][2][32] = {
-#define R32 "w"
-#define R64 "x"
-  { { R32  "0", R32  "1", R32  "2", R32  "3", R32  "4", R32  "5", R32  "6", R32  "7",
-      R32  "8", R32  "9", R32 "10", R32 "11", R32 "12", R32 "13", R32 "14", R32 "15",
-      R32 "16", R32 "17", R32 "18", R32 "19", R32 "20", R32 "21", R32 "22", R32 "23",
-      R32 "24", R32 "25", R32 "26", R32 "27", R32 "28", R32 "29", R32 "30",    "wsp" },
-    { R64  "0", R64  "1", R64  "2", R64  "3", R64  "4", R64  "5", R64  "6", R64  "7",
-      R64  "8", R64  "9", R64 "10", R64 "11", R64 "12", R64 "13", R64 "14", R64 "15",
-      R64 "16", R64 "17", R64 "18", R64 "19", R64 "20", R64 "21", R64 "22", R64 "23",
-      R64 "24", R64 "25", R64 "26", R64 "27", R64 "28", R64 "29", R64 "30",     "sp" } },
-  { { R32  "0", R32  "1", R32  "2", R32  "3", R32  "4", R32  "5", R32  "6", R32  "7",
-      R32  "8", R32  "9", R32 "10", R32 "11", R32 "12", R32 "13", R32 "14", R32 "15",
-      R32 "16", R32 "17", R32 "18", R32 "19", R32 "20", R32 "21", R32 "22", R32 "23",
-      R32 "24", R32 "25", R32 "26", R32 "27", R32 "28", R32 "29", R32 "30", R32 "zr" },
-    { R64  "0", R64  "1", R64  "2", R64  "3", R64  "4", R64  "5", R64  "6", R64  "7",
-      R64  "8", R64  "9", R64 "10", R64 "11", R64 "12", R64 "13", R64 "14", R64 "15",
-      R64 "16", R64 "17", R64 "18", R64 "19", R64 "20", R64 "21", R64 "22", R64 "23",
-      R64 "24", R64 "25", R64 "26", R64 "27", R64 "28", R64 "29", R64 "30", R64 "zr" } }
+#define R32(X) "w" #X
+#define R64(X) "x" #X
+  { BANK (R32, "wsp"), BANK (R64, "sp") },
+  { BANK (R32, "wzr"), BANK (R64, "xzr") }
 #undef R64
 #undef R32
 };
+#undef BANK
 
 /* Return the integer register name.
    if SP_REG_P is not 0, R31 is an SP reg, other R31 is the zero reg.  */
@@ -2196,6 +2259,27 @@ get_64bit_int_reg_name (int regno, int sp_reg_p)
   return int_reg[has_zr][1][regno];
 }
 
+/* Get the name of the integer offset register in OPND, using the shift type
+   to decide whether it's a word or doubleword.  */
+
+static inline const char *
+get_offset_int_reg_name (const aarch64_opnd_info *opnd)
+{
+  switch (opnd->shifter.kind)
+    {
+    case AARCH64_MOD_UXTW:
+    case AARCH64_MOD_SXTW:
+      return get_int_reg_name (opnd->addr.offset.regno, AARCH64_OPND_QLF_W, 0);
+
+    case AARCH64_MOD_LSL:
+    case AARCH64_MOD_SXTX:
+      return get_int_reg_name (opnd->addr.offset.regno, AARCH64_OPND_QLF_X, 0);
+
+    default:
+      abort ();
+    }
+}
+
 /* Types for expanding an encoded 8-bit value to a floating-point value.  */
 
 typedef union
@@ -2318,28 +2402,43 @@ print_register_list (char *buf, size_t size, const aarch64_opnd_info *opnd,
     }
 }
 
+/* Print the register+immediate address in OPND to BUF, which has SIZE
+   characters.  BASE is the name of the base register.  */
+
+static void
+print_immediate_offset_address (char *buf, size_t size,
+                               const aarch64_opnd_info *opnd,
+                               const char *base)
+{
+  if (opnd->addr.writeback)
+    {
+      if (opnd->addr.preind)
+       snprintf (buf, size, "[%s,#%d]!", base, opnd->addr.offset.imm);
+      else
+       snprintf (buf, size, "[%s],#%d", base, opnd->addr.offset.imm);
+    }
+  else
+    {
+      if (opnd->addr.offset.imm)
+       snprintf (buf, size, "[%s,#%d]", base, opnd->addr.offset.imm);
+      else
+       snprintf (buf, size, "[%s]", base);
+    }
+}
+
 /* Produce the string representation of the register offset address operand
-   *OPND in the buffer pointed by BUF of size SIZE.  */
+   *OPND in the buffer pointed by BUF of size SIZE.  BASE and OFFSET are
+   the names of the base and offset registers.  */
 static void
 print_register_offset_address (char *buf, size_t size,
-                              const aarch64_opnd_info *opnd)
+                              const aarch64_opnd_info *opnd,
+                              const char *base, const char *offset)
 {
   char tb[16];                 /* Temporary buffer.  */
-  bfd_boolean lsl_p = FALSE;   /* Is LSL shift operator?  */
-  bfd_boolean wm_p = FALSE;    /* Should Rm be Wm?  */
   bfd_boolean print_extend_p = TRUE;
   bfd_boolean print_amount_p = TRUE;
   const char *shift_name = aarch64_operand_modifiers[opnd->shifter.kind].name;
 
-  switch (opnd->shifter.kind)
-    {
-    case AARCH64_MOD_UXTW: wm_p = TRUE; break;
-    case AARCH64_MOD_LSL : lsl_p = TRUE; break;
-    case AARCH64_MOD_SXTW: wm_p = TRUE; break;
-    case AARCH64_MOD_SXTX: break;
-    default: assert (0);
-    }
-
   if (!opnd->shifter.amount && (opnd->qualifier != AARCH64_OPND_QLF_S_B
                                || !opnd->shifter.amount_present))
     {
@@ -2348,7 +2447,7 @@ print_register_offset_address (char *buf, size_t size,
       print_amount_p = FALSE;
       /* Likewise, no need to print the shift operator LSL in such a
         situation.  */
-      if (lsl_p)
+      if (opnd->shifter.kind == AARCH64_MOD_LSL)
        print_extend_p = FALSE;
     }
 
@@ -2363,12 +2462,7 @@ print_register_offset_address (char *buf, size_t size,
   else
     tb[0] = '\0';
 
-  snprintf (buf, size, "[%s,%s%s]",
-           get_64bit_int_reg_name (opnd->addr.base_regno, 1),
-           get_int_reg_name (opnd->addr.offset.regno,
-                             wm_p ? AARCH64_OPND_QLF_W : AARCH64_OPND_QLF_X,
-                             0 /* sp_reg_p */),
-           tb);
+  snprintf (buf, size, "[%s,%s%s]", base, offset, tb);
 }
 
 /* Generate the string representation of the operand OPNDS[IDX] for OPCODE
@@ -2519,6 +2613,46 @@ aarch64_print_operand (char *buf, size_t size, bfd_vma pc,
       print_register_list (buf, size, opnd, "v");
       break;
 
+    case AARCH64_OPND_SVE_Pd:
+    case AARCH64_OPND_SVE_Pg3:
+    case AARCH64_OPND_SVE_Pg4_5:
+    case AARCH64_OPND_SVE_Pg4_10:
+    case AARCH64_OPND_SVE_Pg4_16:
+    case AARCH64_OPND_SVE_Pm:
+    case AARCH64_OPND_SVE_Pn:
+    case AARCH64_OPND_SVE_Pt:
+      if (opnd->qualifier == AARCH64_OPND_QLF_NIL)
+       snprintf (buf, size, "p%d", opnd->reg.regno);
+      else
+       snprintf (buf, size, "p%d.%s", opnd->reg.regno,
+                 aarch64_get_qualifier_name (opnd->qualifier));
+      break;
+
+    case AARCH64_OPND_SVE_Za_5:
+    case AARCH64_OPND_SVE_Za_16:
+    case AARCH64_OPND_SVE_Zd:
+    case AARCH64_OPND_SVE_Zm_5:
+    case AARCH64_OPND_SVE_Zm_16:
+    case AARCH64_OPND_SVE_Zn:
+    case AARCH64_OPND_SVE_Zt:
+      if (opnd->qualifier == AARCH64_OPND_QLF_NIL)
+       snprintf (buf, size, "z%d", opnd->reg.regno);
+      else
+       snprintf (buf, size, "z%d.%s", opnd->reg.regno,
+                 aarch64_get_qualifier_name (opnd->qualifier));
+      break;
+
+    case AARCH64_OPND_SVE_ZnxN:
+    case AARCH64_OPND_SVE_ZtxN:
+      print_register_list (buf, size, opnd, "z");
+      break;
+
+    case AARCH64_OPND_SVE_Zn_INDEX:
+      snprintf (buf, size, "z%d.%s[%" PRIi64 "]", opnd->reglane.regno,
+               aarch64_get_qualifier_name (opnd->qualifier),
+               opnd->reglane.index);
+      break;
+
     case AARCH64_OPND_Cn:
     case AARCH64_OPND_Cm:
       snprintf (buf, size, "C%d", opnd->reg.regno);
@@ -2675,27 +2809,16 @@ aarch64_print_operand (char *buf, size_t size, bfd_vma pc,
       break;
 
     case AARCH64_OPND_ADDR_REGOFF:
-      print_register_offset_address (buf, size, opnd);
+      print_register_offset_address
+       (buf, size, opnd, get_64bit_int_reg_name (opnd->addr.base_regno, 1),
+        get_offset_int_reg_name (opnd));
       break;
 
     case AARCH64_OPND_ADDR_SIMM7:
     case AARCH64_OPND_ADDR_SIMM9:
     case AARCH64_OPND_ADDR_SIMM9_2:
-      name = get_64bit_int_reg_name (opnd->addr.base_regno, 1);
-      if (opnd->addr.writeback)
-       {
-         if (opnd->addr.preind)
-           snprintf (buf, size, "[%s,#%d]!", name, opnd->addr.offset.imm);
-         else
-           snprintf (buf, size, "[%s],#%d", name, opnd->addr.offset.imm);
-       }
-      else
-       {
-         if (opnd->addr.offset.imm)
-           snprintf (buf, size, "[%s,#%d]", name, opnd->addr.offset.imm);
-         else
-           snprintf (buf, size, "[%s]", name);
-       }
+      print_immediate_offset_address
+       (buf, size, opnd, get_64bit_int_reg_name (opnd->addr.base_regno, 1));
       break;
 
     case AARCH64_OPND_ADDR_UIMM12: