Skip to content

Commit

Permalink
tcg/tci: Implement the disassembler properly
Browse files Browse the repository at this point in the history
Actually print arguments as opposed to simply the opcodes
and, uselessly, the argument counts.  Reuse all of the helpers
developed as part of the interpreter.

Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
  • Loading branch information
rth7680 committed Mar 17, 2021
1 parent 65f1b6c commit 59964b4
Show file tree
Hide file tree
Showing 4 changed files with 284 additions and 64 deletions.
61 changes: 0 additions & 61 deletions disas/tci.c

This file was deleted.

2 changes: 0 additions & 2 deletions include/tcg/tcg-opc.h
Expand Up @@ -278,10 +278,8 @@ DEF(last_generic, 0, 0, 0, TCG_OPF_NOT_PRESENT)
#ifdef TCG_TARGET_INTERPRETER
/* These opcodes are only for use between the tci generator and interpreter. */
DEF(tci_movi_i32, 1, 0, 1, TCG_OPF_NOT_PRESENT)
#if TCG_TARGET_REG_BITS == 64
DEF(tci_movi_i64, 1, 0, 1, TCG_OPF_64BIT | TCG_OPF_NOT_PRESENT)
#endif
#endif

#undef TLADDR_ARGS
#undef DATA64_ARGS
Expand Down
2 changes: 1 addition & 1 deletion meson.build
Expand Up @@ -1943,7 +1943,7 @@ specific_ss.add(when: 'CONFIG_TCG', if_true: files(
'tcg/tcg-op.c',
'tcg/tcg.c',
))
specific_ss.add(when: 'CONFIG_TCG_INTERPRETER', if_true: files('disas/tci.c', 'tcg/tci.c'))
specific_ss.add(when: 'CONFIG_TCG_INTERPRETER', if_true: files('tcg/tci.c'))

subdir('backends')
subdir('disas')
Expand Down
283 changes: 283 additions & 0 deletions tcg/tci.c
Expand Up @@ -1061,3 +1061,286 @@ uintptr_t QEMU_DISABLE_CFI tcg_qemu_tb_exec(CPUArchState *env,
}
}
}

/*
* Disassembler that matches the interpreter
*/

static const char *str_r(TCGReg r)
{
static const char regs[TCG_TARGET_NB_REGS][4] = {
"r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
"r8", "r9", "r10", "r11", "r12", "r13", "env", "sp"
};

QEMU_BUILD_BUG_ON(TCG_AREG0 != TCG_REG_R14);
QEMU_BUILD_BUG_ON(TCG_REG_CALL_STACK != TCG_REG_R15);

assert((unsigned)r < TCG_TARGET_NB_REGS);
return regs[r];
}

static const char *str_c(TCGCond c)
{
static const char cond[16][8] = {
[TCG_COND_NEVER] = "never",
[TCG_COND_ALWAYS] = "always",
[TCG_COND_EQ] = "eq",
[TCG_COND_NE] = "ne",
[TCG_COND_LT] = "lt",
[TCG_COND_GE] = "ge",
[TCG_COND_LE] = "le",
[TCG_COND_GT] = "gt",
[TCG_COND_LTU] = "ltu",
[TCG_COND_GEU] = "geu",
[TCG_COND_LEU] = "leu",
[TCG_COND_GTU] = "gtu",
};

assert((unsigned)c < ARRAY_SIZE(cond));
assert(cond[c][0] != 0);
return cond[c];
}

/* Disassemble TCI bytecode. */
int print_insn_tci(bfd_vma addr, disassemble_info *info)
{
uint8_t buf[256];
int length, status;
const TCGOpDef *def;
const char *op_name;
TCGOpcode op;
TCGReg r0, r1, r2, r3;
#if TCG_TARGET_REG_BITS == 32
TCGReg r4, r5;
#endif
tcg_target_ulong i1;
int32_t s2;
TCGCond c;
TCGMemOpIdx oi;
uint8_t pos, len;
void *ptr;
const uint8_t *tb_ptr;

status = info->read_memory_func(addr, buf, 2, info);
if (status != 0) {
info->memory_error_func(status, addr, info);
return -1;
}
op = buf[0];
length = buf[1];

if (length < 2) {
info->fprintf_func(info->stream, "invalid length %d", length);
return 1;
}

status = info->read_memory_func(addr + 2, buf + 2, length - 2, info);
if (status != 0) {
info->memory_error_func(status, addr + 2, info);
return -1;
}

def = &tcg_op_defs[op];
op_name = def->name;
tb_ptr = buf + 2;

switch (op) {
case INDEX_op_br:
case INDEX_op_call:
case INDEX_op_exit_tb:
case INDEX_op_goto_tb:
tci_args_l(&tb_ptr, &ptr);
info->fprintf_func(info->stream, "%-12s %p", op_name, ptr);
break;

case INDEX_op_brcond_i32:
case INDEX_op_brcond_i64:
tci_args_rrcl(&tb_ptr, &r0, &r1, &c, &ptr);
info->fprintf_func(info->stream, "%-12s %s, %s, %s, %p",
op_name, str_r(r0), str_r(r1), str_c(c), ptr);
break;

case INDEX_op_setcond_i32:
case INDEX_op_setcond_i64:
tci_args_rrrc(&tb_ptr, &r0, &r1, &r2, &c);
info->fprintf_func(info->stream, "%-12s %s, %s, %s, %s",
op_name, str_r(r0), str_r(r1), str_r(r2), str_c(c));
break;

case INDEX_op_tci_movi_i32:
tci_args_ri(&tb_ptr, &r0, &i1);
info->fprintf_func(info->stream, "%-12s %s, 0x%" TCG_PRIlx,
op_name, str_r(r0), i1);
break;

#if TCG_TARGET_REG_BITS == 64
case INDEX_op_tci_movi_i64:
tci_args_rI(&tb_ptr, &r0, &i1);
info->fprintf_func(info->stream, "%-12s %s, 0x%" TCG_PRIlx,
op_name, str_r(r0), i1);
break;
#endif

case INDEX_op_ld8u_i32:
case INDEX_op_ld8u_i64:
case INDEX_op_ld8s_i32:
case INDEX_op_ld8s_i64:
case INDEX_op_ld16u_i32:
case INDEX_op_ld16u_i64:
case INDEX_op_ld16s_i32:
case INDEX_op_ld16s_i64:
case INDEX_op_ld32u_i64:
case INDEX_op_ld32s_i64:
case INDEX_op_ld_i32:
case INDEX_op_ld_i64:
case INDEX_op_st8_i32:
case INDEX_op_st8_i64:
case INDEX_op_st16_i32:
case INDEX_op_st16_i64:
case INDEX_op_st32_i64:
case INDEX_op_st_i32:
case INDEX_op_st_i64:
tci_args_rrs(&tb_ptr, &r0, &r1, &s2);
info->fprintf_func(info->stream, "%-12s %s, %s, %d",
op_name, str_r(r0), str_r(r1), s2);
break;

case INDEX_op_mov_i32:
case INDEX_op_mov_i64:
case INDEX_op_ext8s_i32:
case INDEX_op_ext8s_i64:
case INDEX_op_ext8u_i32:
case INDEX_op_ext8u_i64:
case INDEX_op_ext16s_i32:
case INDEX_op_ext16s_i64:
case INDEX_op_ext16u_i32:
case INDEX_op_ext32s_i64:
case INDEX_op_ext32u_i64:
case INDEX_op_ext_i32_i64:
case INDEX_op_extu_i32_i64:
case INDEX_op_bswap16_i32:
case INDEX_op_bswap16_i64:
case INDEX_op_bswap32_i32:
case INDEX_op_bswap32_i64:
case INDEX_op_bswap64_i64:
case INDEX_op_not_i32:
case INDEX_op_not_i64:
case INDEX_op_neg_i32:
case INDEX_op_neg_i64:
tci_args_rr(&tb_ptr, &r0, &r1);
info->fprintf_func(info->stream, "%-12s %s, %s",
op_name, str_r(r0), str_r(r1));
break;

case INDEX_op_add_i32:
case INDEX_op_add_i64:
case INDEX_op_sub_i32:
case INDEX_op_sub_i64:
case INDEX_op_mul_i32:
case INDEX_op_mul_i64:
case INDEX_op_and_i32:
case INDEX_op_and_i64:
case INDEX_op_or_i32:
case INDEX_op_or_i64:
case INDEX_op_xor_i32:
case INDEX_op_xor_i64:
case INDEX_op_div_i32:
case INDEX_op_div_i64:
case INDEX_op_rem_i32:
case INDEX_op_rem_i64:
case INDEX_op_divu_i32:
case INDEX_op_divu_i64:
case INDEX_op_remu_i32:
case INDEX_op_remu_i64:
case INDEX_op_shl_i32:
case INDEX_op_shl_i64:
case INDEX_op_shr_i32:
case INDEX_op_shr_i64:
case INDEX_op_sar_i32:
case INDEX_op_sar_i64:
case INDEX_op_rotl_i32:
case INDEX_op_rotl_i64:
case INDEX_op_rotr_i32:
case INDEX_op_rotr_i64:
tci_args_rrr(&tb_ptr, &r0, &r1, &r2);
info->fprintf_func(info->stream, "%-12s %s, %s, %s",
op_name, str_r(r0), str_r(r1), str_r(r2));
break;

case INDEX_op_deposit_i32:
case INDEX_op_deposit_i64:
tci_args_rrrbb(&tb_ptr, &r0, &r1, &r2, &pos, &len);
info->fprintf_func(info->stream, "%-12s %s, %s, %s, %d, %d",
op_name, str_r(r0), str_r(r1), str_r(r2), pos, len);
break;

#if TCG_TARGET_REG_BITS == 32
case INDEX_op_setcond2_i32:
tci_args_rrrrrc(&tb_ptr, &r0, &r1, &r2, &r3, &r4, &c);
info->fprintf_func(info->stream, "%-12s %s, %s, %s, %s, %s, %s",
op_name, str_r(r0), str_r(r1), str_r(r2),
str_r(r3), str_r(r4), str_c(c));
break;

case INDEX_op_brcond2_i32:
tci_args_rrrrcl(&tb_ptr, &r0, &r1, &r2, &r3, &c, &ptr);
info->fprintf_func(info->stream, "%-12s %s, %s, %s, %s, %s, %p",
op_name, str_r(r0), str_r(r1),
str_r(r2), str_r(r3), str_c(c), ptr);
break;

case INDEX_op_mulu2_i32:
tci_args_rrrr(&tb_ptr, &r0, &r1, &r2, &r3);
info->fprintf_func(info->stream, "%-12s %s, %s, %s, %s",
op_name, str_r(r0), str_r(r1),
str_r(r2), str_r(r3));
break;

case INDEX_op_add2_i32:
case INDEX_op_sub2_i32:
tci_args_rrrrrr(&tb_ptr, &r0, &r1, &r2, &r3, &r4, &r5);
info->fprintf_func(info->stream, "%-12s %s, %s, %s, %s, %s, %s",
op_name, str_r(r0), str_r(r1), str_r(r2),
str_r(r3), str_r(r4), str_r(r5));
break;
#endif

case INDEX_op_qemu_ld_i64:
case INDEX_op_qemu_st_i64:
len = DIV_ROUND_UP(64, TCG_TARGET_REG_BITS);
goto do_qemu_ldst;
case INDEX_op_qemu_ld_i32:
case INDEX_op_qemu_st_i32:
len = 1;
do_qemu_ldst:
len += DIV_ROUND_UP(TARGET_LONG_BITS, TCG_TARGET_REG_BITS);
switch (len) {
case 2:
tci_args_rrm(&tb_ptr, &r0, &r1, &oi);
info->fprintf_func(info->stream, "%-12s %s, %s, %x",
op_name, str_r(r0), str_r(r1), oi);
break;
case 3:
tci_args_rrrm(&tb_ptr, &r0, &r1, &r2, &oi);
info->fprintf_func(info->stream, "%-12s %s, %s, %s, %x",
op_name, str_r(r0), str_r(r1), str_r(r2), oi);
break;
case 4:
tci_args_rrrrm(&tb_ptr, &r0, &r1, &r2, &r3, &oi);
info->fprintf_func(info->stream, "%-12s %s, %s, %s, %s, %x",
op_name, str_r(r0), str_r(r1),
str_r(r2), str_r(r3), oi);
break;
default:
g_assert_not_reached();
}
break;

default:
info->fprintf_func(info->stream, "illegal opcode %d", op);
break;
}

return length;
}

0 comments on commit 59964b4

Please sign in to comment.