[PATCH, BINUTILS, AARCH64, 4/9] Add Execution and Data Restriction instructions
[deliverable/binutils-gdb.git] / opcodes / aarch64-opc.c
index 9d7f941184594131feec5abca8d7ffbec0b1f793..f3c436cf4d6e97334b3d724447767c1b3c4581df 100644 (file)
@@ -832,6 +832,25 @@ dump_match_qualifiers (const struct aarch64_opnd_info *opnd,
 }
 #endif /* DEBUG_AARCH64 */
 
+/* This function checks if the given instruction INSN is a destructive
+   instruction based on the usage of the registers.  It does not recognize
+   unary destructive instructions.  */
+bfd_boolean
+aarch64_is_destructive_by_operands (const aarch64_opcode *opcode)
+{
+  int i = 0;
+  const enum aarch64_opnd *opnds = opcode->operands;
+
+  if (opnds[0] == AARCH64_OPND_NIL)
+    return FALSE;
+
+  while (opnds[++i] != AARCH64_OPND_NIL)
+    if (opnds[i] == opnds[0])
+      return TRUE;
+
+  return FALSE;
+}
+
 /* TODO improve this, we can have an extra field at the runtime to
    store the number of operands rather than calculating it every time.  */
 
@@ -2516,7 +2535,7 @@ operand_general_constraint_met_p (const aarch64_opnd_info *opnds, int idx,
         01             0:Rm
         10             M:Rm
         11             RESERVED  */
-      if (type == AARCH64_OPND_Em && qualifier == AARCH64_OPND_QLF_S_H
+      if (type == AARCH64_OPND_Em16 && qualifier == AARCH64_OPND_QLF_S_H
          && !value_in_range_p (opnd->reglane.regno, 0, 15))
        {
          set_regno_out_of_range_error (mismatch_detail, idx, 0, 15);
@@ -3033,7 +3052,7 @@ void
 aarch64_print_operand (char *buf, size_t size, bfd_vma pc,
                       const aarch64_opcode *opcode,
                       const aarch64_opnd_info *opnds, int idx, int *pcrel_p,
-                      bfd_vma *address, char** notes ATTRIBUTE_UNUSED)
+                      bfd_vma *address, char** notes)
 {
   unsigned int i, num_conds;
   const char *name = NULL;
@@ -3161,6 +3180,7 @@ aarch64_print_operand (char *buf, size_t size, bfd_vma pc,
     case AARCH64_OPND_Ed:
     case AARCH64_OPND_En:
     case AARCH64_OPND_Em:
+    case AARCH64_OPND_Em16:
     case AARCH64_OPND_SM3_IMM2:
       snprintf (buf, size, "v%d.%s[%" PRIi64 "]", opnd->reglane.regno,
                aarch64_get_qualifier_name (opnd->qualifier),
@@ -3556,11 +3576,38 @@ aarch64_print_operand (char *buf, size_t size, bfd_vma pc,
 
     case AARCH64_OPND_SYSREG:
       for (i = 0; aarch64_sys_regs[i].name; ++i)
-       if (aarch64_sys_regs[i].value == opnd->sysreg.value
-           && ! aarch64_sys_reg_deprecated_p (&aarch64_sys_regs[i]))
-         break;
-      if (aarch64_sys_regs[i].name)
-       snprintf (buf, size, "%s", aarch64_sys_regs[i].name);
+       {
+         bfd_boolean exact_match
+           = (aarch64_sys_regs[i].flags & opnd->sysreg.flags)
+              == opnd->sysreg.flags;
+
+         /* Try and find an exact match, But if that fails, return the first
+            partial match that was found.  */
+         if (aarch64_sys_regs[i].value == opnd->sysreg.value
+             && ! aarch64_sys_reg_deprecated_p (&aarch64_sys_regs[i])
+             && (name == NULL || exact_match))
+           {
+             name = aarch64_sys_regs[i].name;
+             if (exact_match)
+               {
+                 if (notes)
+                   *notes = NULL;
+                 break;
+               }
+
+             /* If we didn't match exactly, that means the presense of a flag
+                indicates what we didn't want for this instruction.  e.g. If
+                F_REG_READ is there, that means we were looking for a write
+                register.  See aarch64_ext_sysreg.  */
+             if (aarch64_sys_regs[i].flags & F_REG_WRITE)
+               *notes = _("reading from a write-only register");
+             else if (aarch64_sys_regs[i].flags & F_REG_READ)
+               *notes = _("writing to a read-only register");
+           }
+       }
+
+      if (name)
+       snprintf (buf, size, "%s", name);
       else
        {
          /* Implementation defined system register.  */
@@ -3583,6 +3630,7 @@ aarch64_print_operand (char *buf, size_t size, bfd_vma pc,
     case AARCH64_OPND_SYSREG_DC:
     case AARCH64_OPND_SYSREG_IC:
     case AARCH64_OPND_SYSREG_TLBI:
+    case AARCH64_OPND_SYSREG_SR:
       snprintf (buf, size, "%s", opnd->sysins_op->name);
       break;
 
@@ -3638,26 +3686,8 @@ aarch64_print_operand (char *buf, size_t size, bfd_vma pc,
 #define C14 14
 #define C15 15
 
-#ifdef F_DEPRECATED
-#undef F_DEPRECATED
-#endif
-#define F_DEPRECATED   0x1     /* Deprecated system register.  */
-
-#ifdef F_ARCHEXT
-#undef F_ARCHEXT
-#endif
-#define F_ARCHEXT      0x2     /* Architecture dependent system register.  */
-
-#ifdef F_HASXT
-#undef F_HASXT
-#endif
-#define F_HASXT                0x4     /* System instruction register <Xt>
-                                  operand.  */
-
-
-/* TODO there are two more issues need to be resolved
-   1. handle read-only and write-only system registers
-   2. handle cpu-implementation-defined system registers.  */
+/* TODO there is one more issues need to be resolved
+   1. handle cpu-implementation-defined system registers.  */
 const aarch64_sys_reg aarch64_sys_regs [] =
 {
   { "spsr_el1",         CPEN_(0,C0,0), 0 }, /* = spsr_svc */
@@ -3667,7 +3697,7 @@ const aarch64_sys_reg aarch64_sys_regs [] =
   { "sp_el0",           CPEN_(0,C1,0), 0 },
   { "spsel",            CPEN_(0,C2,0), 0 },
   { "daif",             CPEN_(3,C2,1), 0 },
-  { "currentel",        CPEN_(0,C2,2), 0 }, /* RO */
+  { "currentel",        CPEN_(0,C2,2), F_REG_READ }, /* RO */
   { "pan",             CPEN_(0,C2,3),  F_ARCHEXT },
   { "uao",             CPEN_ (0, C2, 4), F_ARCHEXT },
   { "nzcv",             CPEN_(3,C2,0), 0 },
@@ -3687,45 +3717,45 @@ const aarch64_sys_reg aarch64_sys_regs [] =
   { "sp_el2",           CPEN_(6,C1,0), 0 },
   { "spsr_svc",         CPEN_(0,C0,0), F_DEPRECATED }, /* = spsr_el1 */
   { "spsr_hyp",         CPEN_(4,C0,0), F_DEPRECATED }, /* = spsr_el2 */
-  { "midr_el1",         CPENC(3,0,C0,C0,0),    0 }, /* RO */
-  { "ctr_el0",          CPENC(3,3,C0,C0,1),    0 }, /* RO */
-  { "mpidr_el1",        CPENC(3,0,C0,C0,5),    0 }, /* RO */
-  { "revidr_el1",       CPENC(3,0,C0,C0,6),    0 }, /* RO */
-  { "aidr_el1",         CPENC(3,1,C0,C0,7),    0 }, /* RO */
-  { "dczid_el0",        CPENC(3,3,C0,C0,7),    0 }, /* RO */
-  { "id_dfr0_el1",      CPENC(3,0,C0,C1,2),    0 }, /* RO */
-  { "id_pfr0_el1",      CPENC(3,0,C0,C1,0),    0 }, /* RO */
-  { "id_pfr1_el1",      CPENC(3,0,C0,C1,1),    0 }, /* RO */
-  { "id_afr0_el1",      CPENC(3,0,C0,C1,3),    0 }, /* RO */
-  { "id_mmfr0_el1",     CPENC(3,0,C0,C1,4),    0 }, /* RO */
-  { "id_mmfr1_el1",     CPENC(3,0,C0,C1,5),    0 }, /* RO */
-  { "id_mmfr2_el1",     CPENC(3,0,C0,C1,6),    0 }, /* RO */
-  { "id_mmfr3_el1",     CPENC(3,0,C0,C1,7),    0 }, /* RO */
-  { "id_mmfr4_el1",     CPENC(3,0,C0,C2,6),    0 }, /* RO */
-  { "id_isar0_el1",     CPENC(3,0,C0,C2,0),    0 }, /* RO */
-  { "id_isar1_el1",     CPENC(3,0,C0,C2,1),    0 }, /* RO */
-  { "id_isar2_el1",     CPENC(3,0,C0,C2,2),    0 }, /* RO */
-  { "id_isar3_el1",     CPENC(3,0,C0,C2,3),    0 }, /* RO */
-  { "id_isar4_el1",     CPENC(3,0,C0,C2,4),    0 }, /* RO */
-  { "id_isar5_el1",     CPENC(3,0,C0,C2,5),    0 }, /* RO */
-  { "mvfr0_el1",        CPENC(3,0,C0,C3,0),    0 }, /* RO */
-  { "mvfr1_el1",        CPENC(3,0,C0,C3,1),    0 }, /* RO */
-  { "mvfr2_el1",        CPENC(3,0,C0,C3,2),    0 }, /* RO */
-  { "ccsidr_el1",       CPENC(3,1,C0,C0,0),    0 }, /* RO */
-  { "id_aa64pfr0_el1",  CPENC(3,0,C0,C4,0),    0 }, /* RO */
-  { "id_aa64pfr1_el1",  CPENC(3,0,C0,C4,1),    0 }, /* RO */
-  { "id_aa64dfr0_el1",  CPENC(3,0,C0,C5,0),    0 }, /* RO */
-  { "id_aa64dfr1_el1",  CPENC(3,0,C0,C5,1),    0 }, /* RO */
-  { "id_aa64isar0_el1", CPENC(3,0,C0,C6,0),    0 }, /* RO */
-  { "id_aa64isar1_el1", CPENC(3,0,C0,C6,1),    0 }, /* RO */
-  { "id_aa64mmfr0_el1", CPENC(3,0,C0,C7,0),    0 }, /* RO */
-  { "id_aa64mmfr1_el1", CPENC(3,0,C0,C7,1),    0 }, /* RO */
-  { "id_aa64mmfr2_el1", CPENC (3, 0, C0, C7, 2), F_ARCHEXT }, /* RO */
-  { "id_aa64afr0_el1",  CPENC(3,0,C0,C5,4),    0 }, /* RO */
-  { "id_aa64afr1_el1",  CPENC(3,0,C0,C5,5),    0 }, /* RO */
-  { "id_aa64zfr0_el1",  CPENC (3, 0, C0, C4, 4), F_ARCHEXT }, /* RO */
-  { "clidr_el1",        CPENC(3,1,C0,C0,1),    0 }, /* RO */
-  { "csselr_el1",       CPENC(3,2,C0,C0,0),    0 }, /* RO */
+  { "midr_el1",         CPENC(3,0,C0,C0,0),    F_REG_READ }, /* RO */
+  { "ctr_el0",          CPENC(3,3,C0,C0,1),    F_REG_READ }, /* RO */
+  { "mpidr_el1",        CPENC(3,0,C0,C0,5),    F_REG_READ }, /* RO */
+  { "revidr_el1",       CPENC(3,0,C0,C0,6),    F_REG_READ }, /* RO */
+  { "aidr_el1",         CPENC(3,1,C0,C0,7),    F_REG_READ }, /* RO */
+  { "dczid_el0",        CPENC(3,3,C0,C0,7),    F_REG_READ }, /* RO */
+  { "id_dfr0_el1",      CPENC(3,0,C0,C1,2),    F_REG_READ }, /* RO */
+  { "id_pfr0_el1",      CPENC(3,0,C0,C1,0),    F_REG_READ }, /* RO */
+  { "id_pfr1_el1",      CPENC(3,0,C0,C1,1),    F_REG_READ }, /* RO */
+  { "id_afr0_el1",      CPENC(3,0,C0,C1,3),    F_REG_READ }, /* RO */
+  { "id_mmfr0_el1",     CPENC(3,0,C0,C1,4),    F_REG_READ }, /* RO */
+  { "id_mmfr1_el1",     CPENC(3,0,C0,C1,5),    F_REG_READ }, /* RO */
+  { "id_mmfr2_el1",     CPENC(3,0,C0,C1,6),    F_REG_READ }, /* RO */
+  { "id_mmfr3_el1",     CPENC(3,0,C0,C1,7),    F_REG_READ }, /* RO */
+  { "id_mmfr4_el1",     CPENC(3,0,C0,C2,6),    F_REG_READ }, /* RO */
+  { "id_isar0_el1",     CPENC(3,0,C0,C2,0),    F_REG_READ }, /* RO */
+  { "id_isar1_el1",     CPENC(3,0,C0,C2,1),    F_REG_READ }, /* RO */
+  { "id_isar2_el1",     CPENC(3,0,C0,C2,2),    F_REG_READ }, /* RO */
+  { "id_isar3_el1",     CPENC(3,0,C0,C2,3),    F_REG_READ }, /* RO */
+  { "id_isar4_el1",     CPENC(3,0,C0,C2,4),    F_REG_READ }, /* RO */
+  { "id_isar5_el1",     CPENC(3,0,C0,C2,5),    F_REG_READ }, /* RO */
+  { "mvfr0_el1",        CPENC(3,0,C0,C3,0),    F_REG_READ }, /* RO */
+  { "mvfr1_el1",        CPENC(3,0,C0,C3,1),    F_REG_READ }, /* RO */
+  { "mvfr2_el1",        CPENC(3,0,C0,C3,2),    F_REG_READ }, /* RO */
+  { "ccsidr_el1",       CPENC(3,1,C0,C0,0),    F_REG_READ }, /* RO */
+  { "id_aa64pfr0_el1",  CPENC(3,0,C0,C4,0),    F_REG_READ }, /* RO */
+  { "id_aa64pfr1_el1",  CPENC(3,0,C0,C4,1),    F_REG_READ }, /* RO */
+  { "id_aa64dfr0_el1",  CPENC(3,0,C0,C5,0),    F_REG_READ }, /* RO */
+  { "id_aa64dfr1_el1",  CPENC(3,0,C0,C5,1),    F_REG_READ }, /* RO */
+  { "id_aa64isar0_el1", CPENC(3,0,C0,C6,0),    F_REG_READ }, /* RO */
+  { "id_aa64isar1_el1", CPENC(3,0,C0,C6,1),    F_REG_READ }, /* RO */
+  { "id_aa64mmfr0_el1", CPENC(3,0,C0,C7,0),    F_REG_READ }, /* RO */
+  { "id_aa64mmfr1_el1", CPENC(3,0,C0,C7,1),    F_REG_READ }, /* RO */
+  { "id_aa64mmfr2_el1", CPENC (3, 0, C0, C7, 2), F_ARCHEXT | F_REG_READ }, /* RO */
+  { "id_aa64afr0_el1",  CPENC(3,0,C0,C5,4),    F_REG_READ }, /* RO */
+  { "id_aa64afr1_el1",  CPENC(3,0,C0,C5,5),    F_REG_READ }, /* RO */
+  { "id_aa64zfr0_el1",  CPENC (3, 0, C0, C4, 4), F_ARCHEXT | F_REG_READ }, /* RO */
+  { "clidr_el1",        CPENC(3,1,C0,C0,1),    F_REG_READ }, /* RO */
+  { "csselr_el1",       CPENC(3,2,C0,C0,0),    0 },
   { "vpidr_el2",        CPENC(3,4,C0,C0,0),    0 },
   { "vmpidr_el2",       CPENC(3,4,C0,C0,5),    0 },
   { "sctlr_el1",        CPENC(3,0,C1,C0,0),    0 },
@@ -3785,11 +3815,11 @@ const aarch64_sys_reg aarch64_sys_regs [] =
   { "esr_el2",          CPENC(3,4,C5,C2,0),    0 },
   { "esr_el3",          CPENC(3,6,C5,C2,0),    0 },
   { "esr_el12",                CPENC (3, 5, C5, C2, 0), F_ARCHEXT },
-  { "vsesr_el2",       CPENC (3, 4, C5, C2, 3), F_ARCHEXT }, /* RO */
+  { "vsesr_el2",       CPENC (3, 4, C5, C2, 3), F_ARCHEXT },
   { "fpexc32_el2",      CPENC(3,4,C5,C3,0),    0 },
-  { "erridr_el1",      CPENC (3, 0, C5, C3, 0), F_ARCHEXT }, /* RO */
+  { "erridr_el1",      CPENC (3, 0, C5, C3, 0), F_ARCHEXT | F_REG_READ }, /* RO */
   { "errselr_el1",     CPENC (3, 0, C5, C3, 1), F_ARCHEXT },
-  { "erxfr_el1",       CPENC (3, 0, C5, C4, 0), F_ARCHEXT }, /* RO */
+  { "erxfr_el1",       CPENC (3, 0, C5, C4, 0), F_ARCHEXT | F_REG_READ }, /* RO */
   { "erxctlr_el1",     CPENC (3, 0, C5, C4, 1), F_ARCHEXT },
   { "erxstatus_el1",   CPENC (3, 0, C5, C4, 2), F_ARCHEXT },
   { "erxaddr_el1",     CPENC (3, 0, C5, C4, 3), F_ARCHEXT },
@@ -3813,27 +3843,27 @@ const aarch64_sys_reg aarch64_sys_regs [] =
   { "vbar_el2",         CPENC(3,4,C12,C0,0),   0 },
   { "vbar_el3",         CPENC(3,6,C12,C0,0),   0 },
   { "vbar_el12",       CPENC (3, 5, C12, C0, 0), F_ARCHEXT },
-  { "rvbar_el1",        CPENC(3,0,C12,C0,1),   0 }, /* RO */
-  { "rvbar_el2",        CPENC(3,4,C12,C0,1),   0 }, /* RO */
-  { "rvbar_el3",        CPENC(3,6,C12,C0,1),   0 }, /* RO */
+  { "rvbar_el1",        CPENC(3,0,C12,C0,1),   F_REG_READ }, /* RO */
+  { "rvbar_el2",        CPENC(3,4,C12,C0,1),   F_REG_READ }, /* RO */
+  { "rvbar_el3",        CPENC(3,6,C12,C0,1),   F_REG_READ }, /* RO */
   { "rmr_el1",          CPENC(3,0,C12,C0,2),   0 },
   { "rmr_el2",          CPENC(3,4,C12,C0,2),   0 },
   { "rmr_el3",          CPENC(3,6,C12,C0,2),   0 },
-  { "isr_el1",          CPENC(3,0,C12,C1,0),   0 }, /* RO */
+  { "isr_el1",          CPENC(3,0,C12,C1,0),   F_REG_READ }, /* RO */
   { "disr_el1",                CPENC (3, 0, C12, C1, 1), F_ARCHEXT },
   { "vdisr_el2",       CPENC (3, 4, C12, C1, 1), F_ARCHEXT },
   { "contextidr_el1",   CPENC(3,0,C13,C0,1),   0 },
   { "contextidr_el2",  CPENC (3, 4, C13, C0, 1), F_ARCHEXT },
   { "contextidr_el12", CPENC (3, 5, C13, C0, 1), F_ARCHEXT },
   { "tpidr_el0",        CPENC(3,3,C13,C0,2),   0 },
-  { "tpidrro_el0",      CPENC(3,3,C13,C0,3),   0 }, /* RO */
+  { "tpidrro_el0",      CPENC(3,3,C13,C0,3),   0 }, /* RW */
   { "tpidr_el1",        CPENC(3,0,C13,C0,4),   0 },
   { "tpidr_el2",        CPENC(3,4,C13,C0,2),   0 },
   { "tpidr_el3",        CPENC(3,6,C13,C0,2),   0 },
   { "teecr32_el1",      CPENC(2,2,C0, C0,0),   0 }, /* See section 3.9.7.1 */
-  { "cntfrq_el0",       CPENC(3,3,C14,C0,0),   0 }, /* RO */
-  { "cntpct_el0",       CPENC(3,3,C14,C0,1),   0 }, /* RO */
-  { "cntvct_el0",       CPENC(3,3,C14,C0,2),   0 }, /* RO */
+  { "cntfrq_el0",       CPENC(3,3,C14,C0,0),   0 }, /* RW */
+  { "cntpct_el0",       CPENC(3,3,C14,C0,1),   F_REG_READ }, /* RO */
+  { "cntvct_el0",       CPENC(3,3,C14,C0,2),   F_REG_READ }, /* RO */
   { "cntvoff_el2",      CPENC(3,4,C14,C0,3),   0 },
   { "cntkctl_el1",      CPENC(3,0,C14,C1,0),   0 },
   { "cntkctl_el12",    CPENC (3, 5, C14, C1, 0), F_ARCHEXT },
@@ -3864,13 +3894,13 @@ const aarch64_sys_reg aarch64_sys_regs [] =
   { "teehbr32_el1",     CPENC(2,2,C1,C0,0),    0 },
   { "sder32_el3",       CPENC(3,6,C1,C1,1),    0 },
   { "mdscr_el1",         CPENC(2,0,C0, C2, 2), 0 },
-  { "mdccsr_el0",        CPENC(2,3,C0, C1, 0), 0 },  /* r */
+  { "mdccsr_el0",        CPENC(2,3,C0, C1, 0), F_REG_READ  },  /* r */
   { "mdccint_el1",       CPENC(2,0,C0, C2, 0), 0 },
   { "dbgdtr_el0",        CPENC(2,3,C0, C4, 0), 0 },
-  { "dbgdtrrx_el0",      CPENC(2,3,C0, C5, 0), 0 },  /* r */
-  { "dbgdtrtx_el0",      CPENC(2,3,C0, C5, 0), 0 },  /* w */
-  { "osdtrrx_el1",       CPENC(2,0,C0, C0, 2), 0 },  /* r */
-  { "osdtrtx_el1",       CPENC(2,0,C0, C3, 2), 0 },  /* w */
+  { "dbgdtrrx_el0",      CPENC(2,3,C0, C5, 0), F_REG_READ  },  /* r */
+  { "dbgdtrtx_el0",      CPENC(2,3,C0, C5, 0), F_REG_WRITE },  /* w */
+  { "osdtrrx_el1",       CPENC(2,0,C0, C0, 2), 0 },
+  { "osdtrtx_el1",       CPENC(2,0,C0, C3, 2), 0 },
   { "oseccr_el1",        CPENC(2,0,C0, C6, 2), 0 },
   { "dbgvcr32_el2",      CPENC(2,4,C0, C7, 0), 0 },
   { "dbgbvr0_el1",       CPENC(2,0,C0, C0, 4), 0 },
@@ -3937,35 +3967,35 @@ const aarch64_sys_reg aarch64_sys_regs [] =
   { "dbgwcr13_el1",      CPENC(2,0,C0, C13,7), 0 },
   { "dbgwcr14_el1",      CPENC(2,0,C0, C14,7), 0 },
   { "dbgwcr15_el1",      CPENC(2,0,C0, C15,7), 0 },
-  { "mdrar_el1",         CPENC(2,0,C1, C0, 0), 0 },  /* r */
-  { "oslar_el1",         CPENC(2,0,C1, C0, 4), 0 },  /* w */
-  { "oslsr_el1",         CPENC(2,0,C1, C1, 4), 0 },  /* r */
+  { "mdrar_el1",         CPENC(2,0,C1, C0, 0), F_REG_READ  },  /* r */
+  { "oslar_el1",         CPENC(2,0,C1, C0, 4), F_REG_WRITE },  /* w */
+  { "oslsr_el1",         CPENC(2,0,C1, C1, 4), F_REG_READ  },  /* r */
   { "osdlr_el1",         CPENC(2,0,C1, C3, 4), 0 },
   { "dbgprcr_el1",       CPENC(2,0,C1, C4, 4), 0 },
   { "dbgclaimset_el1",   CPENC(2,0,C7, C8, 6), 0 },
   { "dbgclaimclr_el1",   CPENC(2,0,C7, C9, 6), 0 },
-  { "dbgauthstatus_el1", CPENC(2,0,C7, C14,6), 0 },  /* r */
+  { "dbgauthstatus_el1", CPENC(2,0,C7, C14,6), F_REG_READ  },  /* r */
   { "pmblimitr_el1",    CPENC (3, 0, C9, C10, 0), F_ARCHEXT },  /* rw */
   { "pmbptr_el1",       CPENC (3, 0, C9, C10, 1), F_ARCHEXT },  /* rw */
   { "pmbsr_el1",        CPENC (3, 0, C9, C10, 3), F_ARCHEXT },  /* rw */
-  { "pmbidr_el1",       CPENC (3, 0, C9, C10, 7), F_ARCHEXT },  /* ro */
+  { "pmbidr_el1",       CPENC (3, 0, C9, C10, 7), F_ARCHEXT | F_REG_READ },  /* ro */
   { "pmscr_el1",        CPENC (3, 0, C9, C9, 0),  F_ARCHEXT },  /* rw */
   { "pmsicr_el1",       CPENC (3, 0, C9, C9, 2),  F_ARCHEXT },  /* rw */
   { "pmsirr_el1",       CPENC (3, 0, C9, C9, 3),  F_ARCHEXT },  /* rw */
   { "pmsfcr_el1",       CPENC (3, 0, C9, C9, 4),  F_ARCHEXT },  /* rw */
   { "pmsevfr_el1",      CPENC (3, 0, C9, C9, 5),  F_ARCHEXT },  /* rw */
   { "pmslatfr_el1",     CPENC (3, 0, C9, C9, 6),  F_ARCHEXT },  /* rw */
-  { "pmsidr_el1",       CPENC (3, 0, C9, C9, 7),  F_ARCHEXT },  /* ro */
+  { "pmsidr_el1",       CPENC (3, 0, C9, C9, 7),  F_ARCHEXT },  /* rw */
   { "pmscr_el2",        CPENC (3, 4, C9, C9, 0),  F_ARCHEXT },  /* rw */
   { "pmscr_el12",       CPENC (3, 5, C9, C9, 0),  F_ARCHEXT },  /* rw */
   { "pmcr_el0",          CPENC(3,3,C9,C12, 0), 0 },
   { "pmcntenset_el0",    CPENC(3,3,C9,C12, 1), 0 },
   { "pmcntenclr_el0",    CPENC(3,3,C9,C12, 2), 0 },
   { "pmovsclr_el0",      CPENC(3,3,C9,C12, 3), 0 },
-  { "pmswinc_el0",       CPENC(3,3,C9,C12, 4), 0 },  /* w */
+  { "pmswinc_el0",       CPENC(3,3,C9,C12, 4), F_REG_WRITE },  /* w */
   { "pmselr_el0",        CPENC(3,3,C9,C12, 5), 0 },
-  { "pmceid0_el0",       CPENC(3,3,C9,C12, 6), 0 },  /* r */
-  { "pmceid1_el0",       CPENC(3,3,C9,C12, 7), 0 },  /* r */
+  { "pmceid0_el0",       CPENC(3,3,C9,C12, 6), F_REG_READ  },  /* r */
+  { "pmceid1_el0",       CPENC(3,3,C9,C12, 7), F_REG_READ  },  /* r */
   { "pmccntr_el0",       CPENC(3,3,C9,C13, 0), 0 },
   { "pmxevtyper_el0",    CPENC(3,3,C9,C13, 1), 0 },
   { "pmxevcntr_el0",     CPENC(3,3,C9,C13, 2), 0 },
@@ -4429,6 +4459,17 @@ const aarch64_sys_ins_reg aarch64_sys_regs_tlbi[] =
     { 0,       CPENS(0,0,0,0), 0 }
 };
 
+const aarch64_sys_ins_reg aarch64_sys_regs_sr[] =
+{
+    /* RCTX is somewhat unique in a way that it has different values
+       (op2) based on the instruction in which it is used (cfp/dvp/cpp).
+       Thus op2 is masked out and instead encoded directly in the
+       aarch64_opcode_table entries for the respective instructions.  */
+    { "rctx",   CPENS(3,C7,C3,0), F_HASXT | F_ARCHEXT | F_REG_WRITE}, /* WO */
+
+    { 0,       CPENS(0,0,0,0), 0 }
+};
+
 bfd_boolean
 aarch64_sys_ins_reg_has_xt (const aarch64_sys_ins_reg *sys_ins_reg)
 {
@@ -4453,6 +4494,11 @@ aarch64_sys_ins_reg_supported_p (const aarch64_feature_set features,
       && !AARCH64_CPU_HAS_FEATURE (features, AARCH64_FEATURE_V8_2))
     return FALSE;
 
+  /* CFP/DVP/CPP RCTX : Value are from aarch64_sys_regs_sr. */
+  if (reg->value == CPENS (3, C7, C3, 0)
+      && !AARCH64_CPU_HAS_FEATURE (features, AARCH64_FEATURE_PREDRES))
+    return FALSE;
+
   return TRUE;
 }
 
@@ -4476,9 +4522,12 @@ aarch64_sys_ins_reg_supported_p (const aarch64_feature_set features,
 #define BIT(INSN,BT)     (((INSN) >> (BT)) & 1)
 #define BITS(INSN,HI,LO) (((INSN) >> (LO)) & ((1 << (((HI) - (LO)) + 1)) - 1))
 
-static bfd_boolean
-verify_ldpsw (const struct aarch64_opcode * opcode ATTRIBUTE_UNUSED,
-             const aarch64_insn insn)
+static enum err_type
+verify_ldpsw (const struct aarch64_inst *inst ATTRIBUTE_UNUSED,
+             const aarch64_insn insn, bfd_vma pc ATTRIBUTE_UNUSED,
+             bfd_boolean encoding ATTRIBUTE_UNUSED,
+             aarch64_operand_error *mismatch_detail ATTRIBUTE_UNUSED,
+             aarch64_instr_sequence *insn_sequence ATTRIBUTE_UNUSED)
 {
   int t  = BITS (insn, 4, 0);
   int n  = BITS (insn, 9, 5);
@@ -4488,19 +4537,349 @@ verify_ldpsw (const struct aarch64_opcode * opcode ATTRIBUTE_UNUSED,
     {
       /* Write back enabled.  */
       if ((t == n || t2 == n) && n != 31)
-       return FALSE;
+       return ERR_UND;
     }
 
   if (BIT (insn, 22))
     {
       /* Load */
       if (t == t2)
-       return FALSE;
+       return ERR_UND;
     }
 
-  return TRUE;
+  return ERR_OK;
+}
+
+/* Initialize an instruction sequence insn_sequence with the instruction INST.
+   If INST is NULL the given insn_sequence is cleared and the sequence is left
+   uninitialized.  */
+
+void
+init_insn_sequence (const struct aarch64_inst *inst,
+                   aarch64_instr_sequence *insn_sequence)
+{
+  int num_req_entries = 0;
+  insn_sequence->next_insn = 0;
+  insn_sequence->num_insns = num_req_entries;
+  if (insn_sequence->instr)
+    XDELETE (insn_sequence->instr);
+  insn_sequence->instr = NULL;
+
+  if (inst)
+    {
+      insn_sequence->instr = XNEW (aarch64_inst);
+      memcpy (insn_sequence->instr, inst, sizeof (aarch64_inst));
+    }
+
+  /* Handle all the cases here.  May need to think of something smarter than
+     a giant if/else chain if this grows.  At that time, a lookup table may be
+     best.  */
+  if (inst && inst->opcode->constraints & C_SCAN_MOVPRFX)
+    num_req_entries = 1;
+
+  if (insn_sequence->current_insns)
+    XDELETEVEC (insn_sequence->current_insns);
+  insn_sequence->current_insns = NULL;
+
+  if (num_req_entries != 0)
+    {
+      size_t size = num_req_entries * sizeof (aarch64_inst);
+      insn_sequence->current_insns
+       = (aarch64_inst**) XNEWVEC (aarch64_inst, num_req_entries);
+      memset (insn_sequence->current_insns, 0, size);
+    }
 }
 
+
+/*  This function verifies that the instruction INST adheres to its specified
+    constraints.  If it does then ERR_OK is returned, if not then ERR_VFI is
+    returned and MISMATCH_DETAIL contains the reason why verification failed.
+
+    The function is called both during assembly and disassembly.  If assembling
+    then ENCODING will be TRUE, else FALSE.  If dissassembling PC will be set
+    and will contain the PC of the current instruction w.r.t to the section.
+
+    If ENCODING and PC=0 then you are at a start of a section.  The constraints
+    are verified against the given state insn_sequence which is updated as it
+    transitions through the verification.  */
+
+enum err_type
+verify_constraints (const struct aarch64_inst *inst,
+                   const aarch64_insn insn ATTRIBUTE_UNUSED,
+                   bfd_vma pc,
+                   bfd_boolean encoding,
+                   aarch64_operand_error *mismatch_detail,
+                   aarch64_instr_sequence *insn_sequence)
+{
+  assert (inst);
+  assert (inst->opcode);
+
+  const struct aarch64_opcode *opcode = inst->opcode;
+  if (!opcode->constraints && !insn_sequence->instr)
+    return ERR_OK;
+
+  assert (insn_sequence);
+
+  enum err_type res = ERR_OK;
+
+  /* This instruction puts a constraint on the insn_sequence.  */
+  if (opcode->flags & F_SCAN)
+    {
+      if (insn_sequence->instr)
+       {
+         mismatch_detail->kind = AARCH64_OPDE_SYNTAX_ERROR;
+         mismatch_detail->error = _("instruction opens new dependency "
+                                    "sequence without ending previous one");
+         mismatch_detail->index = -1;
+         mismatch_detail->non_fatal = TRUE;
+         res = ERR_VFI;
+       }
+
+      init_insn_sequence (inst, insn_sequence);
+      return res;
+    }
+
+  /* Verify constraints on an existing sequence.  */
+  if (insn_sequence->instr)
+    {
+      const struct aarch64_opcode* inst_opcode = insn_sequence->instr->opcode;
+      /* If we're decoding and we hit PC=0 with an open sequence then we haven't
+        closed a previous one that we should have.  */
+      if (!encoding && pc == 0)
+       {
+         mismatch_detail->kind = AARCH64_OPDE_SYNTAX_ERROR;
+         mismatch_detail->error = _("previous `movprfx' sequence not closed");
+         mismatch_detail->index = -1;
+         mismatch_detail->non_fatal = TRUE;
+         res = ERR_VFI;
+         /* Reset the sequence.  */
+         init_insn_sequence (NULL, insn_sequence);
+         return res;
+       }
+
+      /* Validate C_SCAN_MOVPRFX constraints.  Move this to a lookup table.  */
+      if (inst_opcode->constraints & C_SCAN_MOVPRFX)
+       {
+         /* Check to see if the MOVPRFX SVE instruction is followed by an SVE
+            instruction for better error messages.  */
+         if (!opcode->avariant || !(*opcode->avariant & AARCH64_FEATURE_SVE))
+           {
+             mismatch_detail->kind = AARCH64_OPDE_SYNTAX_ERROR;
+             mismatch_detail->error = _("SVE instruction expected after "
+                                        "`movprfx'");
+             mismatch_detail->index = -1;
+             mismatch_detail->non_fatal = TRUE;
+             res = ERR_VFI;
+             goto done;
+           }
+
+         /* Check to see if the MOVPRFX SVE instruction is followed by an SVE
+            instruction that is allowed to be used with a MOVPRFX.  */
+         if (!(opcode->constraints & C_SCAN_MOVPRFX))
+           {
+             mismatch_detail->kind = AARCH64_OPDE_SYNTAX_ERROR;
+             mismatch_detail->error = _("SVE `movprfx' compatible instruction "
+                                        "expected");
+             mismatch_detail->index = -1;
+             mismatch_detail->non_fatal = TRUE;
+             res = ERR_VFI;
+             goto done;
+           }
+
+         /* Next check for usage of the predicate register.  */
+         aarch64_opnd_info blk_dest = insn_sequence->instr->operands[0];
+         aarch64_opnd_info blk_pred, inst_pred;
+         memset (&blk_pred, 0, sizeof (aarch64_opnd_info));
+         memset (&inst_pred, 0, sizeof (aarch64_opnd_info));
+         bfd_boolean predicated = FALSE;
+         assert (blk_dest.type == AARCH64_OPND_SVE_Zd);
+
+         /* Determine if the movprfx instruction used is predicated or not.  */
+         if (insn_sequence->instr->operands[1].type == AARCH64_OPND_SVE_Pg3)
+           {
+             predicated = TRUE;
+             blk_pred = insn_sequence->instr->operands[1];
+           }
+
+         unsigned char max_elem_size = 0;
+         unsigned char current_elem_size;
+         int num_op_used = 0, last_op_usage = 0;
+         int i, inst_pred_idx = -1;
+         int num_ops = aarch64_num_of_operands (opcode);
+         for (i = 0; i < num_ops; i++)
+           {
+             aarch64_opnd_info inst_op = inst->operands[i];
+             switch (inst_op.type)
+               {
+                 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:
+                 case AARCH64_OPND_SVE_Vm:
+                 case AARCH64_OPND_SVE_Vn:
+                 case AARCH64_OPND_Va:
+                 case AARCH64_OPND_Vn:
+                 case AARCH64_OPND_Vm:
+                 case AARCH64_OPND_Sn:
+                 case AARCH64_OPND_Sm:
+                 case AARCH64_OPND_Rn:
+                 case AARCH64_OPND_Rm:
+                 case AARCH64_OPND_Rn_SP:
+                 case AARCH64_OPND_Rm_SP:
+                   if (inst_op.reg.regno == blk_dest.reg.regno)
+                     {
+                       num_op_used++;
+                       last_op_usage = i;
+                     }
+                   current_elem_size
+                     = aarch64_get_qualifier_esize (inst_op.qualifier);
+                   if (current_elem_size > max_elem_size)
+                     max_elem_size = current_elem_size;
+                   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:
+                   inst_pred = inst_op;
+                   inst_pred_idx = i;
+                   break;
+                 default:
+                   break;
+               }
+           }
+
+          assert (max_elem_size != 0);
+          aarch64_opnd_info inst_dest = inst->operands[0];
+          /* Determine the size that should be used to compare against the
+             movprfx size.  */
+          current_elem_size
+            = opcode->constraints & C_MAX_ELEM
+              ? max_elem_size
+              : aarch64_get_qualifier_esize (inst_dest.qualifier);
+
+         /* If movprfx is predicated do some extra checks.  */
+         if (predicated)
+           {
+             /* The instruction must be predicated.  */
+             if (inst_pred_idx < 0)
+               {
+                 mismatch_detail->kind = AARCH64_OPDE_SYNTAX_ERROR;
+                 mismatch_detail->error = _("predicated instruction expected "
+                                            "after `movprfx'");
+                 mismatch_detail->index = -1;
+                 mismatch_detail->non_fatal = TRUE;
+                 res = ERR_VFI;
+                 goto done;
+               }
+
+             /* The instruction must have a merging predicate.  */
+             if (inst_pred.qualifier != AARCH64_OPND_QLF_P_M)
+               {
+                 mismatch_detail->kind = AARCH64_OPDE_SYNTAX_ERROR;
+                 mismatch_detail->error = _("merging predicate expected due "
+                                            "to preceding `movprfx'");
+                 mismatch_detail->index = inst_pred_idx;
+                 mismatch_detail->non_fatal = TRUE;
+                 res = ERR_VFI;
+                 goto done;
+               }
+
+             /* The same register must be used in instruction.  */
+             if (blk_pred.reg.regno != inst_pred.reg.regno)
+               {
+                 mismatch_detail->kind = AARCH64_OPDE_SYNTAX_ERROR;
+                 mismatch_detail->error = _("predicate register differs "
+                                            "from that in preceding "
+                                            "`movprfx'");
+                 mismatch_detail->index = inst_pred_idx;
+                 mismatch_detail->non_fatal = TRUE;
+                 res = ERR_VFI;
+                 goto done;
+               }
+           }
+
+         /* Destructive operations by definition must allow one usage of the
+            same register.  */
+         int allowed_usage
+           = aarch64_is_destructive_by_operands (opcode) ? 2 : 1;
+
+         /* Operand is not used at all.  */
+         if (num_op_used == 0)
+           {
+             mismatch_detail->kind = AARCH64_OPDE_SYNTAX_ERROR;
+             mismatch_detail->error = _("output register of preceding "
+                                        "`movprfx' not used in current "
+                                        "instruction");
+             mismatch_detail->index = 0;
+             mismatch_detail->non_fatal = TRUE;
+             res = ERR_VFI;
+             goto done;
+           }
+
+         /* We now know it's used, now determine exactly where it's used.  */
+         if (blk_dest.reg.regno != inst_dest.reg.regno)
+           {
+             mismatch_detail->kind = AARCH64_OPDE_SYNTAX_ERROR;
+             mismatch_detail->error = _("output register of preceding "
+                                        "`movprfx' expected as output");
+             mismatch_detail->index = 0;
+             mismatch_detail->non_fatal = TRUE;
+             res = ERR_VFI;
+             goto done;
+           }
+
+         /* Operand used more than allowed for the specific opcode type.  */
+         if (num_op_used > allowed_usage)
+           {
+             mismatch_detail->kind = AARCH64_OPDE_SYNTAX_ERROR;
+             mismatch_detail->error = _("output register of preceding "
+                                        "`movprfx' used as input");
+             mismatch_detail->index = last_op_usage;
+             mismatch_detail->non_fatal = TRUE;
+             res = ERR_VFI;
+             goto done;
+           }
+
+         /* Now the only thing left is the qualifiers checks.  The register
+            must have the same maximum element size.  */
+         if (inst_dest.qualifier
+             && blk_dest.qualifier
+             && current_elem_size
+                != aarch64_get_qualifier_esize (blk_dest.qualifier))
+           {
+             mismatch_detail->kind = AARCH64_OPDE_SYNTAX_ERROR;
+             mismatch_detail->error = _("register size not compatible with "
+                                        "previous `movprfx'");
+             mismatch_detail->index = 0;
+             mismatch_detail->non_fatal = TRUE;
+             res = ERR_VFI;
+             goto done;
+           }
+       }
+
+done:
+      /* Add the new instruction to the sequence.  */
+      memcpy (insn_sequence->current_insns + insn_sequence->next_insn++,
+             inst, sizeof (aarch64_inst));
+
+      /* Check if sequence is now full.  */
+      if (insn_sequence->next_insn >= insn_sequence->num_insns)
+       {
+         /* Sequence is full, but we don't have anything special to do for now,
+            so clear and reset it.  */
+         init_insn_sequence (NULL, insn_sequence);
+       }
+    }
+
+  return res;
+}
+
+
 /* Return true if VALUE cannot be moved into an SVE register using DUP
    (with any element size, not just ESIZE) and if using DUPM would
    therefore be OK.  ESIZE is the number of bytes in the immediate.  */
This page took 0.034561 seconds and 4 git commands to generate.