From 9ddd9f6f968afca1c0a5b0274a5817cc6edb8026 Mon Sep 17 00:00:00 2001 From: Dmitry Selyutin Date: Mon, 29 May 2023 01:04:57 +0300 Subject: [PATCH] ppc/svp64: disassemble normal mode --- opcodes/ppc-dis.c | 10 +- opcodes/ppc-svp64-dis.c | 299 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 308 insertions(+), 1 deletion(-) diff --git a/opcodes/ppc-dis.c b/opcodes/ppc-dis.c index adfd19d44ee..08ccc8ecaef 100644 --- a/opcodes/ppc-dis.c +++ b/opcodes/ppc-dis.c @@ -955,6 +955,7 @@ print_insn_powerpc_opcode (struct disassemble_info *info, const struct powerpc_opcode *opcode, const struct svp64_ctx *svp64 ATTRIBUTE_UNUSED) { + size_t len = 0; const ppc_opindex_t *opindex; const struct powerpc_operand *operand; enum { @@ -977,8 +978,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; diff --git a/opcodes/ppc-svp64-dis.c b/opcodes/ppc-svp64-dis.c index 9e6f96b8fa8..d3c5b843408 100644 --- a/opcodes/ppc-svp64-dis.c +++ b/opcodes/ppc-svp64-dis.c @@ -197,3 +197,302 @@ 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); +}; + +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 inline const char * +svp64_predicate (bool CR, uint64_t mask) +{ + static const char *const table[] = { + /* integer (0x1..0x7; 0x0 not allowed) */ + NULL, "1<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) +{ + size_t len = 0; + uint64_t dz = svp64_insn_get_prefix_rm_normal_simple_dz (&svp64->insn); + uint64_t sz = svp64_insn_get_prefix_rm_normal_simple_sz (&svp64->insn); + + 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) +{ + size_t len = 0; + uint64_t RG = svp64_insn_get_prefix_rm_normal_mr_RG (&svp64->insn); + + 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) +{ + size_t len = 0; + uint64_t inv = svp64_insn_get_prefix_rm_normal_ffrc1_inv (&svp64->insn); + uint64_t CR = svp64_insn_get_prefix_rm_normal_ffrc1_CR (&svp64->insn); + + len += svp64_spec_ffrc1 (info, 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) +{ + size_t len = 0; + uint64_t inv = svp64_insn_get_prefix_rm_normal_ffrc0_inv (&svp64->insn); + uint64_t VLi = svp64_insn_get_prefix_rm_normal_ffrc0_VLi (&svp64->insn); + uint64_t RC1 = svp64_insn_get_prefix_rm_normal_ffrc0_RC1 (&svp64->insn); + + len += svp64_spec_VLi (info, VLi); + len += svp64_spec_ffrc0 (info, 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) +{ + size_t len = 0; + uint64_t N = svp64_insn_get_prefix_rm_normal_sat_N (&svp64->insn); + uint64_t dz = svp64_insn_get_prefix_rm_normal_sat_dz (&svp64->insn); + uint64_t sz = svp64_insn_get_prefix_rm_normal_sat_sz (&svp64->insn); + + 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_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) */ + }; + static const struct svp64_spec_table tables[] = { + [SVP64_MODE_NORMAL] = {normal, ARRAY_SIZE (normal)}, + }; + 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); + else + match = (mode >> 3); + + for (idx = 0; idx < table->size; ++idx) + { + const struct svp64_spec_subtable *subtable = &table->subtables[idx]; + + if ((subtable->value & subtable->mask) == (match & subtable->mask)) + return (*subtable->hook) (svp64, info); + } + + abort (); +} -- 2.30.2