ppc/svp64: disassemble normal mode specifiers svp64-ng
authorDmitry Selyutin <ghostmansd@gmail.com>
Fri, 23 Sep 2022 12:15:43 +0000 (15:15 +0300)
committerDmitry Selyutin <ghostmansd@gmail.com>
Fri, 23 Sep 2022 18:13:33 +0000 (21:13 +0300)
gas/config/tc-ppc-svp64.c
opcodes/ppc-dis.c
opcodes/ppc-svp64-dis.c

index a02815f9e3315410e471ea591df1ef260bce52c3..e887982b143806cbcce7ba541967ae1170e01a18 100644 (file)
@@ -362,7 +362,7 @@ svp64_decode_m (char *str, struct svp64_ctx *svp64)
   pmmode = (cr ? 1 : 0);
   svp64->pmmode = pmmode;
   svp64->pmask = pmask;
-  svp64->smmode = pmmode;
+  svp64->mmode = pmmode;
   svp64->smask = pmask;
   svp64->mmode = pmmode;
   svp64->mask_m_specified = 1;
index 0d17c7a3badc9455c7f80c7ed28dd04462797d09..b40dfe03ebc93a403d56e3e94449621fde484e4b 100644 (file)
@@ -872,6 +872,7 @@ print_insn_powerpc_opcode (struct disassemble_info *info,
                           const struct powerpc_opcode *opcode,
                           const struct svp64_ctx *svp64)
 {
+  size_t len = 0;
   const ppc_opindex_t *opindex;
   const struct powerpc_operand *operand;
   enum {
@@ -894,8 +895,15 @@ print_insn_powerpc_opcode (struct disassemble_info *info,
                                "%s%s",
                                (svp64 ? "sv." : ""),
                                opcode->name);
+  len = strlen (opcode->name);
+  if (svp64)
+    {
+      len += (sizeof ("sv.") - 1);
+      len += svp64_print_spec (svp64, info);
+    }
+
   /* gdb fprintf_styled_func doesn't return count printed.  */
-  blanks = (8 - (int)strlen (opcode->name) - (svp64 ? 3 : 2));
+  blanks = (8 - len);
   if (blanks <= 0)
     blanks = 1;
 
index 687078e2ff5ad369674027f3e9236272aac881d1..a3e94d93cec9bf90e2225b311daa4bea88eeefdc 100644 (file)
@@ -196,3 +196,351 @@ svp64_operand_value (const struct svp64_ctx *svp64,
   else
     return value;
 }
+
+struct svp64_spec_table;
+struct svp64_spec_subtable;
+
+struct svp64_spec_table {
+  const struct svp64_spec_subtable *subtables;
+  size_t size;
+};
+
+struct svp64_spec_subtable {
+  uint32_t value;
+  uint32_t mask;
+  size_t (*hook) (const struct svp64_ctx *svp64,
+    struct disassemble_info *info, uint64_t mode);
+};
+
+static inline uint64_t
+svp64_spec_bit (uint64_t value, size_t size, size_t idx)
+{
+  return ((value >> (size - 1 - idx)) & 0x1);
+}
+
+static size_t
+svp64_spec_printf (struct disassemble_info *info, const char *fmt, ...)
+{
+  va_list ap;
+  ssize_t len;
+  char spec[32];
+
+  va_start (ap, fmt);
+
+  len = vsnprintf (spec, sizeof (spec), fmt, ap);
+  if ((len < 0) || (len > (ssize_t)sizeof (spec)))
+    abort ();
+
+  (*info->fprintf_styled_func) (info->stream,
+                               dis_style_sub_mnemonic,
+                               "/%s", spec);
+
+  va_end (ap);
+
+  return (size_t)(len + 1);
+}
+
+static size_t
+svp64_spec_dz_sz_zz (struct disassemble_info *info, bool dz, bool sz)
+{
+  size_t len = 0;
+
+  if (dz != sz)
+    {
+      if (dz)
+       len += svp64_spec_printf (info, "dz");
+      if (sz)
+       len += svp64_spec_printf (info, "sz");
+    }
+  else if (dz)
+    len += svp64_spec_printf (info, "zz");
+
+  return len;
+}
+
+static size_t
+svp64_spec_mr (struct disassemble_info *info, bool RG)
+{
+  if (RG)
+    return svp64_spec_printf (info, "mrr");
+  else
+    return svp64_spec_printf (info, "mr");
+}
+
+static inline const char *
+svp64_predicate (bool CR, uint64_t mask)
+{
+  static const char *const table[] = {
+    /* integer (0x1..0x7; 0x0 not allowed) */
+    NULL, "1<<r3", "r3", "~r3", "r10", "~r10", "r30", "~r30",
+    /* CRs (0x8..0xf) */
+    "lt", "ge", "gt", "le", "eq", "ne", "so", "ns",
+  };
+  uint64_t idx = (((uint64_t)CR << 3) | (mask << 0));
+
+  return table[idx];
+}
+
+static inline const char *
+svp64_width (uint64_t width)
+{
+  static const char *const table[] = {NULL, "32", "16", "8"};
+
+  return table[width];
+}
+
+static size_t
+svp64_spec_ffprrc1 (struct disassemble_info *info,
+  bool ff, bool inv, uint64_t CR)
+{
+  uint64_t mask = (((uint64_t)inv << 2) | (CR << 0));
+  const char *predicate = svp64_predicate (true, mask);
+
+  if (ff)
+    return svp64_spec_printf (info, "ff=%s", predicate);
+  else
+    return svp64_spec_printf (info, "pr=%s", predicate);
+}
+
+static size_t
+svp64_spec_ffprrc0 (struct disassemble_info *info, bool ff, bool inv, bool RC1)
+{
+  if (RC1)
+    {
+      if (ff)
+       return svp64_spec_printf (info, "ff=%sRC1", (inv ? "~" : ""));
+      else
+       return svp64_spec_printf (info, "pr=%sRC1", (inv ? "~" : ""));
+    }
+
+  return 0;
+}
+
+static size_t
+svp64_spec_sat (struct disassemble_info *info, bool N)
+{
+  return svp64_spec_printf (info, (N ? "sats" : "satu"));
+}
+
+static size_t
+svp64_spec_vec (const struct svp64_ctx *svp64,
+  struct disassemble_info *info)
+{
+  uint64_t subvl = svp64_insn_get_prefix_rm_subvl (&svp64->insn);
+  static const char *const table[] = {NULL, "vec2", "vec3", "vec4"};
+
+  if (subvl != 0)
+    return svp64_spec_printf (info, table[subvl]);
+
+  return 0;
+}
+
+static size_t
+svp64_spec_mask (const struct svp64_ctx *svp64,
+  struct disassemble_info *info)
+{
+  size_t len = 0;
+  uint64_t CR = svp64_insn_get_prefix_rm_mmode (&svp64->insn);
+  uint64_t dm = svp64_insn_get_prefix_rm_mask (&svp64->insn);
+  uint64_t sm = dm;
+
+  if (svp64->desc->ptype == SVP64_PTYPE_P2)
+    sm = svp64_insn_get_prefix_rm_smask (&svp64->insn);
+
+  if ((dm == sm) && dm)
+    len += svp64_spec_printf (info, "m=%s", svp64_predicate (CR, dm));
+  else
+    {
+      if (dm)
+       len += svp64_spec_printf (info, "dm=%s", svp64_predicate (CR, dm));
+      if (sm)
+       len += svp64_spec_printf (info, "sm=%s", svp64_predicate (CR, sm));
+    }
+
+  return len;
+}
+
+static size_t
+svp64_spec_width (const struct svp64_ctx *svp64,
+  struct disassemble_info *info)
+{
+  size_t len = 0;
+  uint64_t dw = svp64_insn_get_prefix_rm_elwidth (&svp64->insn);
+  uint64_t sw = svp64_insn_get_prefix_rm_ewsrc (&svp64->insn);
+
+  if ((dw == sw) && dw)
+    len += svp64_spec_printf (info, "w=%s", svp64_width (dw));
+  else
+    {
+      if (dw)
+       len += svp64_spec_printf (info, "dw=%s", svp64_width (dw));
+      if (sw)
+       len += svp64_spec_printf (info, "sw=%s", svp64_width (sw));
+    }
+
+  return len;
+}
+
+static size_t
+svp64_spec_normal (const struct svp64_ctx *svp64,
+  struct disassemble_info *info)
+{
+  size_t len = 0;
+
+  len += svp64_spec_width (svp64, info);
+  len += svp64_spec_mask (svp64, info);
+  len += svp64_spec_vec (svp64, info);
+
+  return len;
+}
+
+static size_t
+svp64_spec_normal_simple (const struct svp64_ctx *svp64,
+  struct disassemble_info *info, uint64_t mode)
+{
+  size_t len = 0;
+  uint64_t dz = svp64_spec_bit (mode, 5, 3);
+  uint64_t sz = svp64_spec_bit (mode, 5, 4);
+
+  len += svp64_spec_dz_sz_zz (info, dz, sz);
+  len += svp64_spec_normal (svp64, info);
+
+  return len;
+}
+
+static size_t
+svp64_spec_normal_mr (const struct svp64_ctx *svp64,
+  struct disassemble_info *info, uint64_t mode)
+{
+  size_t len = 0;
+  uint64_t RG = svp64_spec_bit (mode, 5, 3);
+
+  len += svp64_spec_mr (info, RG);
+  len += svp64_spec_normal (svp64, info);
+
+  return len;
+}
+
+static size_t
+svp64_spec_normal_ffrc1 (const struct svp64_ctx *svp64,
+  struct disassemble_info *info, uint64_t mode)
+{
+  size_t len = 0;
+  uint64_t inv = svp64_spec_bit (mode, 5, 2);
+  uint64_t CR0 = svp64_spec_bit (mode, 5, 3);
+  uint64_t CR1 = svp64_spec_bit (mode, 5, 4);
+  uint64_t CR = ((CR1 << 1) | (CR0 << 0));
+
+  len += svp64_spec_ffprrc1 (info, true, inv, CR);
+  len += svp64_spec_normal (svp64, info);
+
+  return len;
+}
+
+static size_t
+svp64_spec_normal_ffrc0 (const struct svp64_ctx *svp64,
+  struct disassemble_info *info, uint64_t mode)
+{
+  size_t len = 0;
+  uint64_t inv = svp64_spec_bit (mode, 5, 2);
+  uint64_t VLi = svp64_spec_bit (mode, 5, 3);
+  uint64_t RC1 = svp64_spec_bit (mode, 5, 4);
+
+  if (VLi)
+    len += svp64_spec_printf (info, "vli");
+  len += svp64_spec_ffprrc0 (info, true, inv, RC1);
+  len += svp64_spec_normal (svp64, info);
+
+  return len;
+}
+
+static size_t
+svp64_spec_normal_sat (const struct svp64_ctx *svp64,
+  struct disassemble_info *info, uint64_t mode)
+{
+  size_t len = 0;
+  uint64_t N = svp64_spec_bit (mode, 5, 2);
+  uint64_t dz = svp64_spec_bit (mode, 5, 3);
+  uint64_t sz = svp64_spec_bit (mode, 5, 4);
+
+  len += svp64_spec_sat (info, N);
+  len += svp64_spec_dz_sz_zz (info, dz, sz);
+  len += svp64_spec_normal (svp64, info);
+
+  return len;
+}
+
+static size_t
+svp64_spec_normal_prrc1 (const struct svp64_ctx *svp64,
+  struct disassemble_info *info, uint64_t mode)
+{
+  size_t len = 0;
+  uint64_t inv = svp64_spec_bit (mode, 5, 2);
+  uint64_t CR0 = svp64_spec_bit (mode, 5, 3);
+  uint64_t CR1 = svp64_spec_bit (mode, 5, 4);
+  uint64_t CR = ((CR1 << 1) | (CR0 << 0));
+
+  len += svp64_spec_ffprrc1 (info, false, inv, CR);
+  len += svp64_spec_normal (svp64, info);
+
+  return len;
+}
+
+static size_t
+svp64_spec_normal_prrc0 (const struct svp64_ctx *svp64,
+  struct disassemble_info *info, uint64_t mode)
+{
+  size_t len = 0;
+  uint64_t inv = svp64_spec_bit (mode, 5, 2);
+  uint64_t zz = svp64_spec_bit (mode, 5, 3);
+  uint64_t RC1 = svp64_spec_bit (mode, 5, 4);
+
+  len += svp64_spec_ffprrc0 (info, true, inv, RC1);
+  len += svp64_spec_dz_sz_zz (info, zz, zz);
+  len += svp64_spec_normal (svp64, info);
+
+  return len;
+}
+
+static size_t
+svp64_print_spec (const struct svp64_ctx *svp64,
+  struct disassemble_info *info)
+{
+  size_t idx;
+  uint64_t match;
+  static const struct svp64_spec_subtable normal[] = {
+    {0x00, 0x38, svp64_spec_normal_simple},   /* simple     (no Rc)  */
+    {0x08, 0x38, svp64_spec_normal_mr},      /* mapreduce  (no Rc)  */
+    {0x11, 0x31, svp64_spec_normal_ffrc1},    /* ffirst,     Rc=1    */
+    {0x10, 0x31, svp64_spec_normal_ffrc0},    /* ffirst,     Rc=0    */
+    {0x20, 0x30, svp64_spec_normal_sat},      /* saturation (no Rc)  */
+    {0x31, 0x31, svp64_spec_normal_prrc1},    /* predicate,  Rc=1    */
+    {0x30, 0x31, svp64_spec_normal_prrc0},    /* predicate,  Rc=0    */
+  };
+  static const struct svp64_spec_table tables[] = {
+    {normal  , ARRAY_SIZE (normal)},
+/*
+    {ldst_imm, ARRAY_SIZE (ldst_imm)},
+    {ldst_idx, ARRAY_SIZE (ldst_idx)},
+    {cr_op   , ARRAY_SIZE (cr_op)},
+    {branch  , ARRAY_SIZE (branch)},
+*/
+  };
+  const struct svp64_spec_table *table = &tables[svp64->desc->mode];
+  uint64_t mode = svp64_insn_get_prefix_rm_mode (&svp64->insn);
+
+  if (svp64->desc->mode != SVP64_MODE_BRANCH)
+    match = ((mode << 1) | /* (uint64_t)svp64->desc->Rc */ 1);
+  else
+    match = (mode >> 3);
+
+  for (idx = 0; idx < table->size; ++idx)
+    {
+      const struct svp64_spec_subtable *subtable = &table->subtables[idx];
+
+      if ((subtable->value & match) == (subtable->mask & match))
+       return (*subtable->hook) (svp64, info, mode);
+    }
+
+  abort ();
+}