From 4ea6a68324e371d8b21626776b2afc7b4f6d1d0f Mon Sep 17 00:00:00 2001 From: Dmitry Selyutin Date: Fri, 23 Sep 2022 15:15:43 +0300 Subject: [PATCH] ppc/svp64: disassemble normal mode specifiers --- gas/config/tc-ppc-svp64.c | 2 +- opcodes/ppc-dis.c | 10 +- opcodes/ppc-svp64-dis.c | 348 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 358 insertions(+), 2 deletions(-) diff --git a/gas/config/tc-ppc-svp64.c b/gas/config/tc-ppc-svp64.c index a02815f9e33..e887982b143 100644 --- a/gas/config/tc-ppc-svp64.c +++ b/gas/config/tc-ppc-svp64.c @@ -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; diff --git a/opcodes/ppc-dis.c b/opcodes/ppc-dis.c index 0d17c7a3bad..b40dfe03ebc 100644 --- a/opcodes/ppc-dis.c +++ b/opcodes/ppc-dis.c @@ -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; diff --git a/opcodes/ppc-svp64-dis.c b/opcodes/ppc-svp64-dis.c index 687078e2ff5..a3e94d93cec 100644 --- a/opcodes/ppc-svp64-dis.c +++ b/opcodes/ppc-svp64-dis.c @@ -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<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 (); +} -- 2.30.2