/* kvx-dis.c -- Kalray MPPA generic disassembler. Copyright (C) 2009-2023 Free Software Foundation, Inc. Contributed by Kalray SA. This file is part of the GNU opcodes library. This library is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. It is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; see the file COPYING3. If not, see . */ #define STATIC_TABLE #define DEFINE_TABLE #include "sysdep.h" #include "disassemble.h" #include "libiberty.h" #include "opintl.h" #include #include "elf-bfd.h" #include "kvx-dis.h" #include "elf/kvx.h" #include "opcode/kvx.h" /* Steering values for the kvx VLIW architecture. */ typedef enum { Steering_BCU, Steering_LSU, Steering_MAU, Steering_ALU, Steering__ } enum_Steering; typedef uint8_t Steering; /* BundleIssue enumeration. */ typedef enum { BundleIssue_BCU, BundleIssue_TCA, BundleIssue_ALU0, BundleIssue_ALU1, BundleIssue_MAU, BundleIssue_LSU, BundleIssue__, } enum_BundleIssue; typedef uint8_t BundleIssue; /* An IMMX syllable is associated with the BundleIssue Extension_BundleIssue[extension]. */ static const BundleIssue Extension_BundleIssue[] = { BundleIssue_ALU0, BundleIssue_ALU1, BundleIssue_MAU, BundleIssue_LSU }; static inline int kvx_steering (uint32_t x) { return (((x) & 0x60000000) >> 29); } static inline int kvx_extension (uint32_t x) { return (((x) & 0x18000000) >> 27); } static inline int kvx_has_parallel_bit (uint32_t x) { return (((x) & 0x80000000) == 0x80000000); } static inline int kvx_is_tca_opcode (uint32_t x) { unsigned major = ((x) >> 24) & 0x1F; return (major > 1) && (major < 8); } static inline int kvx_is_nop_opcode (uint32_t x) { return ((x) << 1) == 0xFFFFFFFE; } /* A raw instruction. */ struct insn_s { uint32_t syllables[KVXMAXSYLLABLES]; int len; }; typedef struct insn_s insn_t; static uint32_t bundle_words[KVXMAXBUNDLEWORDS]; static insn_t bundle_insn[KVXMAXBUNDLEISSUE]; /* A re-interpreted instruction. */ struct instr_s { int valid; int opcode; int immx[2]; int immx_valid[2]; int immx_count; int nb_syllables; }; /* Option for "pretty printing", ie, not the usual little endian objdump output. */ static int opt_pretty = 0; /* Option for not emiting a new line between all bundles. */ static int opt_compact_assembly = 0; void parse_kvx_dis_option (const char *option) { /* Try to match options that are simple flags. */ if (startswith (option, "pretty")) { opt_pretty = 1; return; } if (startswith (option, "compact-assembly")) { opt_compact_assembly = 1; return; } if (startswith (option, "no-compact-assembly")) { opt_compact_assembly = 0; return; } /* Invalid option. */ opcodes_error_handler (_("unrecognised disassembler option: %s"), option); } static void parse_kvx_dis_options (const char *options) { const char *option_end; if (options == NULL) return; while (*options != '\0') { /* Skip empty options. */ if (*options == ',') { options++; continue; } /* We know that *options is neither NUL or a comma. */ option_end = options + 1; while (*option_end != ',' && *option_end != '\0') option_end++; parse_kvx_dis_option (options); /* Go on to the next one. If option_end points to a comma, it will be skipped above. */ options = option_end; } } struct kvx_dis_env { int kvx_arch_size; struct kvxopc *opc_table; struct kvx_Register *kvx_registers; const char ***kvx_modifiers; int *kvx_dec_registers; int *kvx_regfiles; unsigned int kvx_max_dec_registers; int initialized_p; }; static struct kvx_dis_env env = { .kvx_arch_size = 0, .opc_table = NULL, .kvx_registers = NULL, .kvx_modifiers = NULL, .kvx_dec_registers = NULL, .kvx_regfiles = NULL, .initialized_p = 0, .kvx_max_dec_registers = 0 }; static void kvx_dis_init (struct disassemble_info *info) { env.kvx_arch_size = 32; switch (info->mach) { case bfd_mach_kv3_1_64: env.kvx_arch_size = 64; /* fallthrough */ case bfd_mach_kv3_1_usr: case bfd_mach_kv3_1: default: env.opc_table = kvx_kv3_v1_optab; env.kvx_regfiles = kvx_kv3_v1_regfiles; env.kvx_registers = kvx_kv3_v1_registers; env.kvx_modifiers = kvx_kv3_v1_modifiers; env.kvx_dec_registers = kvx_kv3_v1_dec_registers; break; case bfd_mach_kv3_2_64: env.kvx_arch_size = 64; /* fallthrough */ case bfd_mach_kv3_2_usr: case bfd_mach_kv3_2: env.opc_table = kvx_kv3_v2_optab; env.kvx_regfiles = kvx_kv3_v2_regfiles; env.kvx_registers = kvx_kv3_v2_registers; env.kvx_modifiers = kvx_kv3_v2_modifiers; env.kvx_dec_registers = kvx_kv3_v2_dec_registers; break; case bfd_mach_kv4_1_64: env.kvx_arch_size = 64; /* fallthrough */ case bfd_mach_kv4_1_usr: case bfd_mach_kv4_1: env.opc_table = kvx_kv4_v1_optab; env.kvx_regfiles = kvx_kv4_v1_regfiles; env.kvx_registers = kvx_kv4_v1_registers; env.kvx_modifiers = kvx_kv4_v1_modifiers; env.kvx_dec_registers = kvx_kv4_v1_dec_registers; break; } env.kvx_max_dec_registers = env.kvx_regfiles[KVX_REGFILE_DEC_REGISTERS]; if (info->disassembler_options) parse_kvx_dis_options (info->disassembler_options); env.initialized_p = 1; } static int kvx_reassemble_bundle (int wordcount, int *_insncount) { /* Debugging flag. */ int debug = 0; /* Available resources. */ int bcu_taken = 0; int tca_taken = 0; int alu0_taken = 0; int alu1_taken = 0; int mau_taken = 0; int lsu_taken = 0; int i; unsigned int j; struct instr_s instr[KVXMAXBUNDLEISSUE]; assert (KVXMAXBUNDLEISSUE >= BundleIssue__); memset (instr, 0, sizeof (instr)); if (debug) fprintf (stderr, "kvx_reassemble_bundle: wordcount = %d\n", wordcount); if (wordcount == 0) { if (debug) fprintf (stderr, "wordcount == 0\n"); return 1; } for (i = 0; i < wordcount; i++) { uint32_t syllable = bundle_words[i]; switch (kvx_steering (syllable)) { case Steering_BCU: /* BCU or TCA instruction. */ if (i == 0) { if (kvx_is_tca_opcode (syllable)) { if (tca_taken) { if (debug) fprintf (stderr, "Too many TCA instructions"); return 1; } if (debug) fprintf (stderr, "Syllable 0: Set valid on TCA for instr %d with 0x%x\n", BundleIssue_TCA, syllable); instr[BundleIssue_TCA].valid = 1; instr[BundleIssue_TCA].opcode = syllable; instr[BundleIssue_TCA].nb_syllables = 1; tca_taken = 1; } else { if (debug) fprintf (stderr, "Syllable 0: Set valid on BCU for instr %d with 0x%x\n", BundleIssue_BCU, syllable); instr[BundleIssue_BCU].valid = 1; instr[BundleIssue_BCU].opcode = syllable; instr[BundleIssue_BCU].nb_syllables = 1; bcu_taken = 1; } } else { if (i == 1 && bcu_taken && kvx_is_tca_opcode (syllable)) { if (tca_taken) { if (debug) fprintf (stderr, "Too many TCA instructions"); return 1; } if (debug) fprintf (stderr, "Syllable 0: Set valid on TCA for instr %d with 0x%x\n", BundleIssue_TCA, syllable); instr[BundleIssue_TCA].valid = 1; instr[BundleIssue_TCA].opcode = syllable; instr[BundleIssue_TCA].nb_syllables = 1; tca_taken = 1; } else { /* Not first syllable in bundle, IMMX. */ struct instr_s *instr_p = &(instr[Extension_BundleIssue[kvx_extension (syllable)]]); int immx_count = instr_p->immx_count; if (immx_count > 1) { if (debug) fprintf (stderr, "Too many IMMX syllables"); return 1; } instr_p->immx[immx_count] = syllable; instr_p->immx_valid[immx_count] = 1; instr_p->nb_syllables++; if (debug) fprintf (stderr, "Set IMMX[%d] on instr %d for extension %d @ %d\n", immx_count, Extension_BundleIssue[kvx_extension (syllable)], kvx_extension (syllable), i); instr_p->immx_count = immx_count + 1; } } break; case Steering_ALU: if (alu0_taken == 0) { if (debug) fprintf (stderr, "Set valid on ALU0 for instr %d with 0x%x\n", BundleIssue_ALU0, syllable); instr[BundleIssue_ALU0].valid = 1; instr[BundleIssue_ALU0].opcode = syllable; instr[BundleIssue_ALU0].nb_syllables = 1; alu0_taken = 1; } else if (alu1_taken == 0) { if (debug) fprintf (stderr, "Set valid on ALU1 for instr %d with 0x%x\n", BundleIssue_ALU1, syllable); instr[BundleIssue_ALU1].valid = 1; instr[BundleIssue_ALU1].opcode = syllable; instr[BundleIssue_ALU1].nb_syllables = 1; alu1_taken = 1; } else if (mau_taken == 0) { if (debug) fprintf (stderr, "Set valid on MAU (ALU) for instr %d with 0x%x\n", BundleIssue_MAU, syllable); instr[BundleIssue_MAU].valid = 1; instr[BundleIssue_MAU].opcode = syllable; instr[BundleIssue_MAU].nb_syllables = 1; mau_taken = 1; } else if (lsu_taken == 0) { if (debug) fprintf (stderr, "Set valid on LSU (ALU) for instr %d with 0x%x\n", BundleIssue_LSU, syllable); instr[BundleIssue_LSU].valid = 1; instr[BundleIssue_LSU].opcode = syllable; instr[BundleIssue_LSU].nb_syllables = 1; lsu_taken = 1; } else if (kvx_is_nop_opcode (syllable)) { if (debug) fprintf (stderr, "Ignoring NOP (ALU) syllable\n"); } else { if (debug) fprintf (stderr, "Too many ALU instructions"); return 1; } break; case Steering_MAU: if (mau_taken == 1) { if (debug) fprintf (stderr, "Too many MAU instructions"); return 1; } else { if (debug) fprintf (stderr, "Set valid on MAU for instr %d with 0x%x\n", BundleIssue_MAU, syllable); instr[BundleIssue_MAU].valid = 1; instr[BundleIssue_MAU].opcode = syllable; instr[BundleIssue_MAU].nb_syllables = 1; mau_taken = 1; } break; case Steering_LSU: if (lsu_taken == 1) { if (debug) fprintf (stderr, "Too many LSU instructions"); return 1; } else { if (debug) fprintf (stderr, "Set valid on LSU for instr %d with 0x%x\n", BundleIssue_LSU, syllable); instr[BundleIssue_LSU].valid = 1; instr[BundleIssue_LSU].opcode = syllable; instr[BundleIssue_LSU].nb_syllables = 1; lsu_taken = 1; } } if (!(kvx_has_parallel_bit (syllable))) { if (debug) fprintf (stderr, "Stop! stop bit is set 0x%x\n", syllable); break; } if (debug) fprintf (stderr, "Continue %d < %d?\n", i, wordcount); } if (kvx_has_parallel_bit (bundle_words[i])) { if (debug) fprintf (stderr, "bundle exceeds maximum size"); return 1; } /* Fill bundle_insn and count read syllables. */ int instr_idx = 0; for (i = 0; i < KVXMAXBUNDLEISSUE; i++) { if (instr[i].valid == 1) { int syllable_idx = 0; /* First copy opcode. */ bundle_insn[instr_idx].syllables[syllable_idx++] = instr[i].opcode; bundle_insn[instr_idx].len = 1; for (j = 0; j < 2; j++) { if (instr[i].immx_valid[j]) { if (debug) fprintf (stderr, "Instr %d valid immx[%d] is valid\n", i, j); bundle_insn[instr_idx].syllables[syllable_idx++] = instr[i].immx[j]; bundle_insn[instr_idx].len++; } } if (debug) fprintf (stderr, "Instr %d valid, copying in bundle_insn (%d syllables <-> %d)\n", i, bundle_insn[instr_idx].len, instr[i].nb_syllables); instr_idx++; } } if (debug) fprintf (stderr, "End => %d instructions\n", instr_idx); *_insncount = instr_idx; return 0; } struct decoded_insn { /* The entry in the opc_table. */ struct kvxopc *opc; /* The number of operands. */ int nb_ops; /* The content of an operands. */ struct { enum { CAT_REGISTER, CAT_MODIFIER, CAT_IMMEDIATE, } type; /* The value of the operands. */ unsigned long long val; /* If it is an immediate, its sign. */ int sign; /* If it is an immediate, is it pc relative. */ int pcrel; /* The width of the operand. */ int width; /* If it is a modifier, the modifier category. An index in the modifier table. */ int mod_idx; } operands[KVXMAXOPERANDS]; }; static int decode_insn (bfd_vma memaddr, insn_t * insn, struct decoded_insn *res) { int found = 0; int idx = 0; for (struct kvxopc * op = env.opc_table; op->as_op && (((char) op->as_op[0]) != 0); op++) { /* Find the format of this insn. */ int opcode_match = 1; if (op->wordcount != insn->len) continue; for (int i = 0; i < op->wordcount; i++) if ((op->codewords[i].mask & insn->syllables[i]) != op->codewords[i].opcode) opcode_match = 0; int encoding_space_flags = env.kvx_arch_size == 32 ? kvxOPCODE_FLAG_MODE32 : kvxOPCODE_FLAG_MODE64; for (int i = 0; i < op->wordcount; i++) if (!(op->codewords[i].flags & encoding_space_flags)) opcode_match = 0; if (opcode_match) { res->opc = op; for (int i = 0; op->format[i]; i++) { struct kvx_bitfield *bf = op->format[i]->bfield; int bf_nb = op->format[i]->bitfields; int width = op->format[i]->width; int type = op->format[i]->type; const char *type_name = op->format[i]->tname; int flags = op->format[i]->flags; int shift = op->format[i]->shift; int bias = op->format[i]->bias; unsigned long long value = 0; for (int bf_idx = 0; bf_idx < bf_nb; bf_idx++) { int insn_idx = (int) bf[bf_idx].to_offset / 32; int to_offset = bf[bf_idx].to_offset % 32; unsigned long long encoded_value = insn->syllables[insn_idx] >> to_offset; encoded_value &= (1LL << bf[bf_idx].size) - 1; value |= encoded_value << bf[bf_idx].from_offset; } if (flags & kvxSIGNED) { unsigned long long signbit = 1LL << (width - 1); value = (value ^ signbit) - signbit; } value = (value << shift) + bias; #define KVX_PRINT_REG(regfile,value) \ if(env.kvx_regfiles[regfile]+value < env.kvx_max_dec_registers) { \ res->operands[idx].val = env.kvx_dec_registers[env.kvx_regfiles[regfile]+value]; \ res->operands[idx].type = CAT_REGISTER; \ idx++; \ } else { \ res->operands[idx].val = ~0; \ res->operands[idx].type = CAT_REGISTER; \ idx++; \ } if (env.opc_table == kvx_kv3_v1_optab) { switch (type) { case RegClass_kv3_v1_singleReg: KVX_PRINT_REG (KVX_REGFILE_DEC_GPR, value) break; case RegClass_kv3_v1_pairedReg: KVX_PRINT_REG (KVX_REGFILE_DEC_PGR, value) break; case RegClass_kv3_v1_quadReg: KVX_PRINT_REG (KVX_REGFILE_DEC_QGR, value) break; case RegClass_kv3_v1_systemReg: case RegClass_kv3_v1_aloneReg: case RegClass_kv3_v1_onlyraReg: case RegClass_kv3_v1_onlygetReg: case RegClass_kv3_v1_onlysetReg: case RegClass_kv3_v1_onlyfxReg: KVX_PRINT_REG (KVX_REGFILE_DEC_SFR, value) break; case RegClass_kv3_v1_coproReg0M4: case RegClass_kv3_v1_coproReg1M4: case RegClass_kv3_v1_coproReg2M4: case RegClass_kv3_v1_coproReg3M4: KVX_PRINT_REG (KVX_REGFILE_DEC_XCR, value) break; case RegClass_kv3_v1_blockRegE: case RegClass_kv3_v1_blockRegO: case RegClass_kv3_v1_blockReg0M4: case RegClass_kv3_v1_blockReg1M4: case RegClass_kv3_v1_blockReg2M4: case RegClass_kv3_v1_blockReg3M4: KVX_PRINT_REG (KVX_REGFILE_DEC_XBR, value) break; case RegClass_kv3_v1_vectorReg: case RegClass_kv3_v1_vectorRegE: case RegClass_kv3_v1_vectorRegO: KVX_PRINT_REG (KVX_REGFILE_DEC_XVR, value) break; case RegClass_kv3_v1_tileReg: KVX_PRINT_REG (KVX_REGFILE_DEC_XTR, value) break; case RegClass_kv3_v1_matrixReg: KVX_PRINT_REG (KVX_REGFILE_DEC_XMR, value) break; case Immediate_kv3_v1_sysnumber: case Immediate_kv3_v1_signed10: case Immediate_kv3_v1_signed16: case Immediate_kv3_v1_signed27: case Immediate_kv3_v1_wrapped32: case Immediate_kv3_v1_signed37: case Immediate_kv3_v1_signed43: case Immediate_kv3_v1_signed54: case Immediate_kv3_v1_wrapped64: case Immediate_kv3_v1_unsigned6: res->operands[idx].val = value; res->operands[idx].sign = flags & kvxSIGNED; res->operands[idx].width = width; res->operands[idx].type = CAT_IMMEDIATE; res->operands[idx].pcrel = 0; idx++; break; case Immediate_kv3_v1_pcrel17: case Immediate_kv3_v1_pcrel27: res->operands[idx].val = value + memaddr; res->operands[idx].sign = flags & kvxSIGNED; res->operands[idx].width = width; res->operands[idx].type = CAT_IMMEDIATE; res->operands[idx].pcrel = 1; idx++; break; case Modifier_kv3_v1_column: case Modifier_kv3_v1_comparison: case Modifier_kv3_v1_doscale: case Modifier_kv3_v1_exunum: case Modifier_kv3_v1_floatcomp: case Modifier_kv3_v1_qindex: case Modifier_kv3_v1_rectify: case Modifier_kv3_v1_rounding: case Modifier_kv3_v1_roundint: case Modifier_kv3_v1_saturate: case Modifier_kv3_v1_scalarcond: case Modifier_kv3_v1_silent: case Modifier_kv3_v1_simplecond: case Modifier_kv3_v1_speculate: case Modifier_kv3_v1_splat32: case Modifier_kv3_v1_variant: { int sz = 0; int mod_idx = type - Modifier_kv3_v1_column; for (sz = 0; env.kvx_modifiers[mod_idx][sz]; ++sz); const char *mod = value < (unsigned) sz ? env.kvx_modifiers[mod_idx][value] : NULL; if (!mod) goto retry; res->operands[idx].val = value; res->operands[idx].type = CAT_MODIFIER; res->operands[idx].mod_idx = mod_idx; idx++; } break; default: fprintf (stderr, "error: unexpected operand type (%s)\n", type_name); exit (-1); }; } else if (env.opc_table == kvx_kv3_v2_optab) { switch (type) { case RegClass_kv3_v2_singleReg: KVX_PRINT_REG (KVX_REGFILE_DEC_GPR, value) break; case RegClass_kv3_v2_pairedReg: KVX_PRINT_REG (KVX_REGFILE_DEC_PGR, value) break; case RegClass_kv3_v2_quadReg: KVX_PRINT_REG (KVX_REGFILE_DEC_QGR, value) break; case RegClass_kv3_v2_systemReg: case RegClass_kv3_v2_aloneReg: case RegClass_kv3_v2_onlyraReg: case RegClass_kv3_v2_onlygetReg: case RegClass_kv3_v2_onlysetReg: case RegClass_kv3_v2_onlyfxReg: KVX_PRINT_REG (KVX_REGFILE_DEC_SFR, value) break; case RegClass_kv3_v2_coproReg: case RegClass_kv3_v2_coproReg0M4: case RegClass_kv3_v2_coproReg1M4: case RegClass_kv3_v2_coproReg2M4: case RegClass_kv3_v2_coproReg3M4: KVX_PRINT_REG (KVX_REGFILE_DEC_XCR, value) break; case RegClass_kv3_v2_blockReg: case RegClass_kv3_v2_blockRegE: case RegClass_kv3_v2_blockRegO: KVX_PRINT_REG (KVX_REGFILE_DEC_XBR, value) break; case RegClass_kv3_v2_vectorReg: KVX_PRINT_REG (KVX_REGFILE_DEC_XVR, value) break; case RegClass_kv3_v2_tileReg: KVX_PRINT_REG (KVX_REGFILE_DEC_XTR, value) break; case RegClass_kv3_v2_matrixReg: KVX_PRINT_REG (KVX_REGFILE_DEC_XMR, value) break; case RegClass_kv3_v2_buffer2Reg: KVX_PRINT_REG (KVX_REGFILE_DEC_X2R, value) break; case RegClass_kv3_v2_buffer4Reg: KVX_PRINT_REG (KVX_REGFILE_DEC_X4R, value) break; case RegClass_kv3_v2_buffer8Reg: KVX_PRINT_REG (KVX_REGFILE_DEC_X8R, value) break; case RegClass_kv3_v2_buffer16Reg: KVX_PRINT_REG (KVX_REGFILE_DEC_X16R, value) break; case RegClass_kv3_v2_buffer32Reg: KVX_PRINT_REG (KVX_REGFILE_DEC_X32R, value) break; case RegClass_kv3_v2_buffer64Reg: KVX_PRINT_REG (KVX_REGFILE_DEC_X64R, value) break; case Immediate_kv3_v2_brknumber: case Immediate_kv3_v2_sysnumber: case Immediate_kv3_v2_signed10: case Immediate_kv3_v2_signed16: case Immediate_kv3_v2_signed27: case Immediate_kv3_v2_wrapped32: case Immediate_kv3_v2_signed37: case Immediate_kv3_v2_signed43: case Immediate_kv3_v2_signed54: case Immediate_kv3_v2_wrapped64: case Immediate_kv3_v2_unsigned6: res->operands[idx].val = value; res->operands[idx].sign = flags & kvxSIGNED; res->operands[idx].width = width; res->operands[idx].type = CAT_IMMEDIATE; res->operands[idx].pcrel = 0; idx++; break; case Immediate_kv3_v2_pcrel27: case Immediate_kv3_v2_pcrel17: res->operands[idx].val = value + memaddr; res->operands[idx].sign = flags & kvxSIGNED; res->operands[idx].width = width; res->operands[idx].type = CAT_IMMEDIATE; res->operands[idx].pcrel = 1; idx++; break; case Modifier_kv3_v2_accesses: case Modifier_kv3_v2_boolcas: case Modifier_kv3_v2_cachelev: case Modifier_kv3_v2_channel: case Modifier_kv3_v2_coherency: case Modifier_kv3_v2_comparison: case Modifier_kv3_v2_conjugate: case Modifier_kv3_v2_doscale: case Modifier_kv3_v2_exunum: case Modifier_kv3_v2_floatcomp: case Modifier_kv3_v2_hindex: case Modifier_kv3_v2_lsomask: case Modifier_kv3_v2_lsumask: case Modifier_kv3_v2_lsupack: case Modifier_kv3_v2_qindex: case Modifier_kv3_v2_rounding: case Modifier_kv3_v2_scalarcond: case Modifier_kv3_v2_shuffleV: case Modifier_kv3_v2_shuffleX: case Modifier_kv3_v2_silent: case Modifier_kv3_v2_simplecond: case Modifier_kv3_v2_speculate: case Modifier_kv3_v2_splat32: case Modifier_kv3_v2_transpose: case Modifier_kv3_v2_variant: { int sz = 0; int mod_idx = type - Modifier_kv3_v2_accesses; for (sz = 0; env.kvx_modifiers[mod_idx][sz]; ++sz); const char *mod = value < (unsigned) sz ? env.kvx_modifiers[mod_idx][value] : NULL; if (!mod) goto retry; res->operands[idx].val = value; res->operands[idx].type = CAT_MODIFIER; res->operands[idx].mod_idx = mod_idx; idx++; }; break; default: fprintf (stderr, "error: unexpected operand type (%s)\n", type_name); exit (-1); }; } else if (env.opc_table == kvx_kv4_v1_optab) { switch (type) { case RegClass_kv4_v1_singleReg: KVX_PRINT_REG (KVX_REGFILE_DEC_GPR, value) break; case RegClass_kv4_v1_pairedReg: KVX_PRINT_REG (KVX_REGFILE_DEC_PGR, value) break; case RegClass_kv4_v1_quadReg: KVX_PRINT_REG (KVX_REGFILE_DEC_QGR, value) break; case RegClass_kv4_v1_systemReg: case RegClass_kv4_v1_aloneReg: case RegClass_kv4_v1_onlyraReg: case RegClass_kv4_v1_onlygetReg: case RegClass_kv4_v1_onlysetReg: case RegClass_kv4_v1_onlyfxReg: KVX_PRINT_REG (KVX_REGFILE_DEC_SFR, value) break; case RegClass_kv4_v1_coproReg: case RegClass_kv4_v1_coproReg0M4: case RegClass_kv4_v1_coproReg1M4: case RegClass_kv4_v1_coproReg2M4: case RegClass_kv4_v1_coproReg3M4: KVX_PRINT_REG (KVX_REGFILE_DEC_XCR, value) break; case RegClass_kv4_v1_blockReg: case RegClass_kv4_v1_blockRegE: case RegClass_kv4_v1_blockRegO: KVX_PRINT_REG (KVX_REGFILE_DEC_XBR, value) break; case RegClass_kv4_v1_vectorReg: KVX_PRINT_REG (KVX_REGFILE_DEC_XVR, value) break; case RegClass_kv4_v1_tileReg: KVX_PRINT_REG (KVX_REGFILE_DEC_XTR, value) break; case RegClass_kv4_v1_matrixReg: KVX_PRINT_REG (KVX_REGFILE_DEC_XMR, value) break; case RegClass_kv4_v1_buffer2Reg: KVX_PRINT_REG (KVX_REGFILE_DEC_X2R, value) break; case RegClass_kv4_v1_buffer4Reg: KVX_PRINT_REG (KVX_REGFILE_DEC_X4R, value) break; case RegClass_kv4_v1_buffer8Reg: KVX_PRINT_REG (KVX_REGFILE_DEC_X8R, value) break; case RegClass_kv4_v1_buffer16Reg: KVX_PRINT_REG (KVX_REGFILE_DEC_X16R, value) break; case RegClass_kv4_v1_buffer32Reg: KVX_PRINT_REG (KVX_REGFILE_DEC_X32R, value) break; case RegClass_kv4_v1_buffer64Reg: KVX_PRINT_REG (KVX_REGFILE_DEC_X64R, value) break; case Immediate_kv4_v1_brknumber: case Immediate_kv4_v1_sysnumber: case Immediate_kv4_v1_signed10: case Immediate_kv4_v1_signed16: case Immediate_kv4_v1_signed27: case Immediate_kv4_v1_wrapped32: case Immediate_kv4_v1_signed37: case Immediate_kv4_v1_signed43: case Immediate_kv4_v1_signed54: case Immediate_kv4_v1_wrapped64: case Immediate_kv4_v1_unsigned6: res->operands[idx].val = value; res->operands[idx].sign = flags & kvxSIGNED; res->operands[idx].width = width; res->operands[idx].type = CAT_IMMEDIATE; res->operands[idx].pcrel = 0; idx++; break; case Immediate_kv4_v1_pcrel27: case Immediate_kv4_v1_pcrel17: res->operands[idx].val = value + memaddr; res->operands[idx].sign = flags & kvxSIGNED; res->operands[idx].width = width; res->operands[idx].type = CAT_IMMEDIATE; res->operands[idx].pcrel = 1; idx++; break; case Modifier_kv4_v1_accesses: case Modifier_kv4_v1_boolcas: case Modifier_kv4_v1_cachelev: case Modifier_kv4_v1_channel: case Modifier_kv4_v1_coherency: case Modifier_kv4_v1_comparison: case Modifier_kv4_v1_conjugate: case Modifier_kv4_v1_doscale: case Modifier_kv4_v1_exunum: case Modifier_kv4_v1_floatcomp: case Modifier_kv4_v1_hindex: case Modifier_kv4_v1_lsomask: case Modifier_kv4_v1_lsumask: case Modifier_kv4_v1_lsupack: case Modifier_kv4_v1_qindex: case Modifier_kv4_v1_rounding: case Modifier_kv4_v1_scalarcond: case Modifier_kv4_v1_shuffleV: case Modifier_kv4_v1_shuffleX: case Modifier_kv4_v1_silent: case Modifier_kv4_v1_simplecond: case Modifier_kv4_v1_speculate: case Modifier_kv4_v1_splat32: case Modifier_kv4_v1_transpose: case Modifier_kv4_v1_variant: { int sz = 0; int mod_idx = type - Modifier_kv4_v1_accesses; for (sz = 0; env.kvx_modifiers[mod_idx][sz]; ++sz); const char *mod = value < (unsigned) sz ? env.kvx_modifiers[mod_idx][value] : NULL; if (!mod) goto retry; res->operands[idx].val = value; res->operands[idx].type = CAT_MODIFIER; res->operands[idx].mod_idx = mod_idx; idx++; } break; default: fprintf (stderr, "error: unexpected operand type (%s)\n", type_name); exit (-1); }; } #undef KVX_PRINT_REG } found = 1; break; retry:; idx = 0; continue; } } res->nb_ops = idx; return found; } int print_insn_kvx (bfd_vma memaddr, struct disassemble_info *info) { static int insnindex = 0; static int insncount = 0; insn_t *insn; int readsofar = 0; int found = 0; int invalid_bundle = 0; if (!env.initialized_p) kvx_dis_init (info); /* Clear instruction information field. */ info->insn_info_valid = 0; info->branch_delay_insns = 0; info->data_size = 0; info->insn_type = dis_noninsn; info->target = 0; info->target2 = 0; /* Set line length. */ info->bytes_per_line = 16; /* If this is the beginning of the bundle, read BUNDLESIZE words and apply decentrifugate function. */ if (insnindex == 0) { int wordcount = 0; do { int status; assert (wordcount < KVXMAXBUNDLEWORDS); status = (*info->read_memory_func) (memaddr + 4 * wordcount, (bfd_byte *) (bundle_words + wordcount), 4, info); if (status != 0) { (*info->memory_error_func) (status, memaddr + 4 * wordcount, info); return -1; } wordcount++; } while (kvx_has_parallel_bit (bundle_words[wordcount - 1]) && wordcount < KVXMAXBUNDLEWORDS); invalid_bundle = kvx_reassemble_bundle (wordcount, &insncount); } assert (insnindex < KVXMAXBUNDLEISSUE); insn = &(bundle_insn[insnindex]); readsofar = insn->len * 4; insnindex++; if (opt_pretty) { (*info->fprintf_func) (info->stream, "[ "); for (int i = 0; i < insn->len; i++) (*info->fprintf_func) (info->stream, "%08x ", insn->syllables[i]); (*info->fprintf_func) (info->stream, "] "); } /* Check for extension to right iff this is not the end of bundle. */ struct decoded_insn dec = { 0 }; if (!invalid_bundle && (found = decode_insn (memaddr, insn, &dec))) { int ch; (*info->fprintf_func) (info->stream, "%s", dec.opc->as_op); const char *fmtp = dec.opc->fmtstring; for (int i = 0; i < dec.nb_ops; ++i) { /* Print characters in the format string up to the following % or nul. */ while ((ch = *fmtp) && ch != '%') { (*info->fprintf_func) (info->stream, "%c", ch); fmtp++; } /* Skip past %s. */ if (ch == '%') { ch = *fmtp++; fmtp++; } switch (dec.operands[i].type) { case CAT_REGISTER: (*info->fprintf_func) (info->stream, "%s", env.kvx_registers[dec.operands[i].val].name); break; case CAT_MODIFIER: { const char *mod = env.kvx_modifiers[dec.operands[i].mod_idx][dec.operands[i].val]; (*info->fprintf_func) (info->stream, "%s", !mod || !strcmp (mod, ".") ? "" : mod); } break; case CAT_IMMEDIATE: { if (dec.operands[i].pcrel) { /* Fill in instruction information. */ info->insn_info_valid = 1; info->insn_type = dec.operands[i].width == 17 ? dis_condbranch : dis_branch; info->target = dec.operands[i].val; info->print_address_func (dec.operands[i].val, info); } else if (dec.operands[i].sign) { if (dec.operands[i].width <= 32) { (*info->fprintf_func) (info->stream, "%d (0x%x)", (int) dec.operands[i].val, (int) dec.operands[i].val); } else { (*info->fprintf_func) (info->stream, "%lld (0x%llx)", dec.operands[i].val, dec.operands[i].val); } } else { if (dec.operands[i].width <= 32) { (*info->fprintf_func) (info->stream, "%u (0x%x)", (unsigned int) dec.operands[i]. val, (unsigned int) dec.operands[i]. val); } else { (*info->fprintf_func) (info->stream, "%llu (0x%llx)", (unsigned long long) dec. operands[i].val, (unsigned long long) dec. operands[i].val); } } } break; default: break; } } while ((ch = *fmtp)) { (*info->fprintf_styled_func) (info->stream, dis_style_text, "%c", ch); fmtp++; } } else { (*info->fprintf_func) (info->stream, "*** invalid opcode ***\n"); insnindex = 0; readsofar = 4; } if (found && (insnindex == insncount)) { (*info->fprintf_func) (info->stream, ";;"); if (!opt_compact_assembly) (*info->fprintf_func) (info->stream, "\n"); insnindex = 0; } return readsofar; } /* This function searches in the current bundle for the instructions required by unwinding. For prologue: (1) addd $r12 = $r12, (2) get = $ra (3) sd [$r12] = or sq/so containing (4) sd [$r12] = $r14 or sq/so containing r14 (5) addd $r14 = $r12, or copyd $r14 = $r12 The only difference seen between the code generated by gcc and clang is the setting/resetting r14. gcc could also generate copyd $r14=$r12 instead of add addd $r14 = $r12, when is 0. Vice-versa, is not guaranteed to be 0 for clang, so, clang could also generate addd instead of copyd (6) call, icall, goto, igoto, cb., ret For epilogue: (1) addd $r12 = $r12, (2) addd $r12 = $r14, or copyd $r12 = $r14 Same comment as prologue (5). (3) ret, goto (4) call, icall, igoto, cb. */ int decode_prologue_epilogue_bundle (bfd_vma memaddr, struct disassemble_info *info, struct kvx_prologue_epilogue_bundle *peb) { int i, nb_insn, nb_syl; peb->nb_insn = 0; if (info->arch != bfd_arch_kvx) return -1; if (!env.initialized_p) kvx_dis_init (info); /* Read the bundle. */ nb_syl = 0; do { if (nb_syl >= KVXMAXBUNDLEWORDS) return -1; if ((*info->read_memory_func) (memaddr + 4 * nb_syl, (bfd_byte *) &bundle_words[nb_syl], 4, info)) return -1; nb_syl++; } while (kvx_has_parallel_bit (bundle_words[nb_syl - 1]) && nb_syl < KVXMAXBUNDLEWORDS); if (kvx_reassemble_bundle (nb_syl, &nb_insn)) return -1; /* Check for extension to right if this is not the end of bundle find the format of this insn. */ for (int idx_insn = 0; idx_insn < nb_insn; idx_insn++) { insn_t *insn = &bundle_insn[idx_insn]; int is_add = 0, is_get = 0, is_a_peb_insn = 0, is_copyd = 0; struct decoded_insn dec = { 0 }; if (!decode_insn (memaddr, insn, &dec)) continue; const char *op_name = dec.opc->as_op; struct kvx_prologue_epilogue_insn *crt_peb_insn; crt_peb_insn = &peb->insn[peb->nb_insn]; crt_peb_insn->nb_gprs = 0; if (!strcmp (op_name, "addd")) is_add = 1; else if (!strcmp (op_name, "copyd")) is_copyd = 1; else if (!strcmp (op_name, "get")) is_get = 1; else if (!strcmp (op_name, "sd")) { crt_peb_insn->insn_type = KVX_PROL_EPIL_INSN_SD; is_a_peb_insn = 1; } else if (!strcmp (op_name, "sq")) { crt_peb_insn->insn_type = KVX_PROL_EPIL_INSN_SQ; is_a_peb_insn = 1; } else if (!strcmp (op_name, "so")) { crt_peb_insn->insn_type = KVX_PROL_EPIL_INSN_SO; is_a_peb_insn = 1; } else if (!strcmp (op_name, "ret")) { crt_peb_insn->insn_type = KVX_PROL_EPIL_INSN_RET; is_a_peb_insn = 1; } else if (!strcmp (op_name, "goto")) { crt_peb_insn->insn_type = KVX_PROL_EPIL_INSN_GOTO; is_a_peb_insn = 1; } else if (!strcmp (op_name, "igoto")) { crt_peb_insn->insn_type = KVX_PROL_EPIL_INSN_IGOTO; is_a_peb_insn = 1; } else if (!strcmp (op_name, "call") || !strcmp (op_name, "icall")) { crt_peb_insn->insn_type = KVX_PROL_EPIL_INSN_CALL; is_a_peb_insn = 1; } else if (!strncmp (op_name, "cb", 2)) { crt_peb_insn->insn_type = KVX_PROL_EPIL_INSN_CB; is_a_peb_insn = 1; } else continue; for (i = 0; dec.opc->format[i]; i++) { struct kvx_operand *fmt = dec.opc->format[i]; struct kvx_bitfield *bf = fmt->bfield; int bf_nb = fmt->bitfields; int width = fmt->width; int type = fmt->type; int flags = fmt->flags; int shift = fmt->shift; int bias = fmt->bias; unsigned long long encoded_value, value = 0; for (int bf_idx = 0; bf_idx < bf_nb; bf_idx++) { int insn_idx = (int) bf[bf_idx].to_offset / 32; int to_offset = bf[bf_idx].to_offset % 32; encoded_value = insn->syllables[insn_idx] >> to_offset; encoded_value &= (1LL << bf[bf_idx].size) - 1; value |= encoded_value << bf[bf_idx].from_offset; } if (flags & kvxSIGNED) { unsigned long long signbit = 1LL << (width - 1); value = (value ^ signbit) - signbit; } value = (value << shift) + bias; #define chk_type(core_, val_) \ (env.opc_table == kvx_## core_ ##_optab && type == (val_)) if (chk_type (kv3_v1, RegClass_kv3_v1_singleReg) || chk_type (kv3_v2, RegClass_kv3_v2_singleReg) || chk_type (kv4_v1, RegClass_kv4_v1_singleReg)) { if (env.kvx_regfiles[KVX_REGFILE_DEC_GPR] + value >= env.kvx_max_dec_registers) return -1; if (is_add && i < 2) { if (i == 0) { if (value == KVX_GPR_REG_SP) crt_peb_insn->insn_type = KVX_PROL_EPIL_INSN_ADD_SP; else if (value == KVX_GPR_REG_FP) crt_peb_insn->insn_type = KVX_PROL_EPIL_INSN_ADD_FP; else is_add = 0; } else if (i == 1) { if (value == KVX_GPR_REG_SP) is_a_peb_insn = 1; else if (value == KVX_GPR_REG_FP && crt_peb_insn->insn_type == KVX_PROL_EPIL_INSN_ADD_SP) { crt_peb_insn->insn_type = KVX_PROL_EPIL_INSN_RESTORE_SP_FROM_FP; is_a_peb_insn = 1; } else is_add = 0; } } else if (is_copyd && i < 2) { if (i == 0) { if (value == KVX_GPR_REG_FP) { crt_peb_insn->insn_type = KVX_PROL_EPIL_INSN_ADD_FP; crt_peb_insn->immediate = 0; } else if (value == KVX_GPR_REG_SP) { crt_peb_insn->insn_type = KVX_PROL_EPIL_INSN_RESTORE_SP_FROM_FP; crt_peb_insn->immediate = 0; } else is_copyd = 0; } else if (i == 1) { if (value == KVX_GPR_REG_SP && crt_peb_insn->insn_type == KVX_PROL_EPIL_INSN_ADD_FP) is_a_peb_insn = 1; else if (value == KVX_GPR_REG_FP && crt_peb_insn->insn_type == KVX_PROL_EPIL_INSN_RESTORE_SP_FROM_FP) is_a_peb_insn = 1; else is_copyd = 0; } } else crt_peb_insn->gpr_reg[crt_peb_insn->nb_gprs++] = value; } else if (chk_type (kv3_v1, RegClass_kv3_v1_pairedReg) || chk_type (kv3_v2, RegClass_kv3_v2_pairedReg) || chk_type (kv4_v1, RegClass_kv4_v1_pairedReg)) crt_peb_insn->gpr_reg[crt_peb_insn->nb_gprs++] = value * 2; else if (chk_type (kv3_v1, RegClass_kv3_v1_quadReg) || chk_type (kv3_v2, RegClass_kv3_v2_quadReg) || chk_type (kv4_v1, RegClass_kv4_v1_quadReg)) crt_peb_insn->gpr_reg[crt_peb_insn->nb_gprs++] = value * 4; else if (chk_type (kv3_v1, RegClass_kv3_v1_systemReg) || chk_type (kv3_v2, RegClass_kv3_v2_systemReg) || chk_type (kv4_v1, RegClass_kv4_v1_systemReg) || chk_type (kv3_v1, RegClass_kv3_v1_aloneReg) || chk_type (kv3_v2, RegClass_kv3_v2_aloneReg) || chk_type (kv4_v1, RegClass_kv4_v1_aloneReg) || chk_type (kv3_v1, RegClass_kv3_v1_onlyraReg) || chk_type (kv3_v2, RegClass_kv3_v2_onlyraReg) || chk_type (kv4_v1, RegClass_kv4_v1_onlygetReg) || chk_type (kv3_v1, RegClass_kv3_v1_onlygetReg) || chk_type (kv3_v2, RegClass_kv3_v2_onlygetReg) || chk_type (kv4_v1, RegClass_kv4_v1_onlygetReg) || chk_type (kv3_v1, RegClass_kv3_v1_onlysetReg) || chk_type (kv3_v2, RegClass_kv3_v2_onlysetReg) || chk_type (kv4_v1, RegClass_kv4_v1_onlysetReg) || chk_type (kv3_v1, RegClass_kv3_v1_onlyfxReg) || chk_type (kv3_v2, RegClass_kv3_v2_onlyfxReg) || chk_type (kv4_v1, RegClass_kv4_v1_onlyfxReg)) { if (env.kvx_regfiles[KVX_REGFILE_DEC_GPR] + value >= env.kvx_max_dec_registers) return -1; if (is_get && !strcmp (env.kvx_registers[env.kvx_dec_registers[env.kvx_regfiles[KVX_REGFILE_DEC_SFR] + value]].name, "$ra")) { crt_peb_insn->insn_type = KVX_PROL_EPIL_INSN_GET_RA; is_a_peb_insn = 1; } } else if (chk_type (kv3_v1, RegClass_kv3_v1_coproReg) || chk_type (kv3_v2, RegClass_kv3_v2_coproReg) || chk_type (kv4_v1, RegClass_kv4_v1_coproReg) || chk_type (kv3_v1, RegClass_kv3_v1_blockReg) || chk_type (kv3_v2, RegClass_kv3_v2_blockReg) || chk_type (kv4_v1, RegClass_kv4_v1_blockReg) || chk_type (kv3_v1, RegClass_kv3_v1_vectorReg) || chk_type (kv3_v2, RegClass_kv3_v2_vectorReg) || chk_type (kv4_v1, RegClass_kv4_v1_vectorReg) || chk_type (kv3_v1, RegClass_kv3_v1_tileReg) || chk_type (kv3_v2, RegClass_kv3_v2_tileReg) || chk_type (kv4_v1, RegClass_kv4_v1_tileReg) || chk_type (kv3_v1, RegClass_kv3_v1_matrixReg) || chk_type (kv3_v2, RegClass_kv3_v2_matrixReg) || chk_type (kv4_v1, RegClass_kv4_v1_matrixReg) || chk_type (kv3_v1, Modifier_kv3_v1_scalarcond) || chk_type (kv3_v1, Modifier_kv3_v1_column) || chk_type (kv3_v1, Modifier_kv3_v1_comparison) || chk_type (kv3_v1, Modifier_kv3_v1_doscale) || chk_type (kv3_v1, Modifier_kv3_v1_exunum) || chk_type (kv3_v1, Modifier_kv3_v1_floatcomp) || chk_type (kv3_v1, Modifier_kv3_v1_qindex) || chk_type (kv3_v1, Modifier_kv3_v1_rectify) || chk_type (kv3_v1, Modifier_kv3_v1_rounding) || chk_type (kv3_v1, Modifier_kv3_v1_roundint) || chk_type (kv3_v1, Modifier_kv3_v1_saturate) || chk_type (kv3_v1, Modifier_kv3_v1_scalarcond) || chk_type (kv3_v1, Modifier_kv3_v1_silent) || chk_type (kv3_v1, Modifier_kv3_v1_simplecond) || chk_type (kv3_v1, Modifier_kv3_v1_speculate) || chk_type (kv3_v1, Modifier_kv3_v1_splat32) || chk_type (kv3_v1, Modifier_kv3_v1_variant) || chk_type (kv3_v2, Modifier_kv3_v2_accesses) || chk_type (kv3_v2, Modifier_kv3_v2_boolcas) || chk_type (kv3_v2, Modifier_kv3_v2_cachelev) || chk_type (kv3_v2, Modifier_kv3_v2_channel) || chk_type (kv3_v2, Modifier_kv3_v2_coherency) || chk_type (kv3_v2, Modifier_kv3_v2_comparison) || chk_type (kv3_v2, Modifier_kv3_v2_conjugate) || chk_type (kv3_v2, Modifier_kv3_v2_doscale) || chk_type (kv3_v2, Modifier_kv3_v2_exunum) || chk_type (kv3_v2, Modifier_kv3_v2_floatcomp) || chk_type (kv3_v2, Modifier_kv3_v2_hindex) || chk_type (kv3_v2, Modifier_kv3_v2_lsomask) || chk_type (kv3_v2, Modifier_kv3_v2_lsumask) || chk_type (kv3_v2, Modifier_kv3_v2_lsupack) || chk_type (kv3_v2, Modifier_kv3_v2_qindex) || chk_type (kv3_v2, Modifier_kv3_v2_rounding) || chk_type (kv3_v2, Modifier_kv3_v2_scalarcond) || chk_type (kv3_v2, Modifier_kv3_v2_shuffleV) || chk_type (kv3_v2, Modifier_kv3_v2_shuffleX) || chk_type (kv3_v2, Modifier_kv3_v2_silent) || chk_type (kv3_v2, Modifier_kv3_v2_simplecond) || chk_type (kv3_v2, Modifier_kv3_v2_speculate) || chk_type (kv3_v2, Modifier_kv3_v2_splat32) || chk_type (kv3_v2, Modifier_kv3_v2_transpose) || chk_type (kv3_v2, Modifier_kv3_v2_variant) || chk_type (kv4_v1, Modifier_kv4_v1_accesses) || chk_type (kv4_v1, Modifier_kv4_v1_boolcas) || chk_type (kv4_v1, Modifier_kv4_v1_cachelev) || chk_type (kv4_v1, Modifier_kv4_v1_channel) || chk_type (kv4_v1, Modifier_kv4_v1_coherency) || chk_type (kv4_v1, Modifier_kv4_v1_comparison) || chk_type (kv4_v1, Modifier_kv4_v1_conjugate) || chk_type (kv4_v1, Modifier_kv4_v1_doscale) || chk_type (kv4_v1, Modifier_kv4_v1_exunum) || chk_type (kv4_v1, Modifier_kv4_v1_floatcomp) || chk_type (kv4_v1, Modifier_kv4_v1_hindex) || chk_type (kv4_v1, Modifier_kv4_v1_lsomask) || chk_type (kv4_v1, Modifier_kv4_v1_lsumask) || chk_type (kv4_v1, Modifier_kv4_v1_lsupack) || chk_type (kv4_v1, Modifier_kv4_v1_qindex) || chk_type (kv4_v1, Modifier_kv4_v1_rounding) || chk_type (kv4_v1, Modifier_kv4_v1_scalarcond) || chk_type (kv4_v1, Modifier_kv4_v1_shuffleV) || chk_type (kv4_v1, Modifier_kv4_v1_shuffleX) || chk_type (kv4_v1, Modifier_kv4_v1_silent) || chk_type (kv4_v1, Modifier_kv4_v1_simplecond) || chk_type (kv4_v1, Modifier_kv4_v1_speculate) || chk_type (kv4_v1, Modifier_kv4_v1_splat32) || chk_type (kv4_v1, Modifier_kv4_v1_transpose) || chk_type (kv4_v1, Modifier_kv4_v1_variant)) { /* Do nothing. */ } else if (chk_type (kv3_v1, Immediate_kv3_v1_sysnumber) || chk_type (kv3_v2, Immediate_kv3_v2_sysnumber) || chk_type (kv4_v1, Immediate_kv4_v1_sysnumber) || chk_type (kv3_v2, Immediate_kv3_v2_wrapped8) || chk_type (kv4_v1, Immediate_kv4_v1_wrapped8) || chk_type (kv3_v1, Immediate_kv3_v1_signed10) || chk_type (kv3_v2, Immediate_kv3_v2_signed10) || chk_type (kv4_v1, Immediate_kv4_v1_signed10) || chk_type (kv3_v1, Immediate_kv3_v1_signed16) || chk_type (kv3_v2, Immediate_kv3_v2_signed16) || chk_type (kv4_v1, Immediate_kv4_v1_signed16) || chk_type (kv3_v1, Immediate_kv3_v1_signed27) || chk_type (kv3_v2, Immediate_kv3_v2_signed27) || chk_type (kv4_v1, Immediate_kv4_v1_signed27) || chk_type (kv3_v1, Immediate_kv3_v1_wrapped32) || chk_type (kv3_v2, Immediate_kv3_v2_wrapped32) || chk_type (kv4_v1, Immediate_kv4_v1_wrapped32) || chk_type (kv3_v1, Immediate_kv3_v1_signed37) || chk_type (kv3_v2, Immediate_kv3_v2_signed37) || chk_type (kv4_v1, Immediate_kv4_v1_signed37) || chk_type (kv3_v1, Immediate_kv3_v1_signed43) || chk_type (kv3_v2, Immediate_kv3_v2_signed43) || chk_type (kv4_v1, Immediate_kv4_v1_signed43) || chk_type (kv3_v1, Immediate_kv3_v1_signed54) || chk_type (kv3_v2, Immediate_kv3_v2_signed54) || chk_type (kv4_v1, Immediate_kv4_v1_signed54) || chk_type (kv3_v1, Immediate_kv3_v1_wrapped64) || chk_type (kv3_v2, Immediate_kv3_v2_wrapped64) || chk_type (kv4_v1, Immediate_kv4_v1_wrapped64) || chk_type (kv3_v1, Immediate_kv3_v1_unsigned6) || chk_type (kv3_v2, Immediate_kv3_v2_unsigned6) || chk_type (kv4_v1, Immediate_kv4_v1_unsigned6)) crt_peb_insn->immediate = value; else if (chk_type (kv3_v1, Immediate_kv3_v1_pcrel17) || chk_type (kv3_v2, Immediate_kv3_v2_pcrel17) || chk_type (kv4_v1, Immediate_kv4_v1_pcrel17) || chk_type (kv3_v1, Immediate_kv3_v1_pcrel27) || chk_type (kv3_v2, Immediate_kv3_v2_pcrel27) || chk_type (kv4_v1, Immediate_kv4_v1_pcrel27)) crt_peb_insn->immediate = value + memaddr; else return -1; } if (is_a_peb_insn) peb->nb_insn++; continue; } return nb_syl * 4; #undef chk_type } void print_kvx_disassembler_options (FILE * stream) { fprintf (stream, _("\n\ The following KVX specific disassembler options are supported for use\n\ with the -M switch (multiple options should be separated by commas):\n")); fprintf (stream, _("\n\ pretty Print 32-bit words in natural order corresponding to \ re-ordered instruction.\n")); fprintf (stream, _("\n\ compact-assembly Do not emit a new line between bundles of instructions.\ \n")); fprintf (stream, _("\n\ no-compact-assembly Emit a new line between bundles of instructions.\n")); fprintf (stream, _("\n")); }