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 ();
+}