mirror of
https://github.com/izzy2lost/xemu.git
synced 2026-07-06 00:20:22 -07:00
tcg: Put opcodes in a linked list
The previous setup required ops and args to be completely sequential, and was error prone when it came to both iteration and optimization. Reviewed-by: Bastian Koppelmann <kbastian@mail.uni-paderborn.de> Signed-off-by: Richard Henderson <rth@twiddle.net>
This commit is contained in:
@@ -11,8 +11,8 @@ static int exitreq_label;
|
||||
|
||||
static inline void gen_tb_start(TranslationBlock *tb)
|
||||
{
|
||||
TCGv_i32 count;
|
||||
TCGv_i32 flag;
|
||||
TCGv_i32 count, flag, imm;
|
||||
int i;
|
||||
|
||||
exitreq_label = gen_new_label();
|
||||
flag = tcg_temp_new_i32();
|
||||
@@ -21,16 +21,25 @@ static inline void gen_tb_start(TranslationBlock *tb)
|
||||
tcg_gen_brcondi_i32(TCG_COND_NE, flag, 0, exitreq_label);
|
||||
tcg_temp_free_i32(flag);
|
||||
|
||||
if (!(tb->cflags & CF_USE_ICOUNT))
|
||||
if (!(tb->cflags & CF_USE_ICOUNT)) {
|
||||
return;
|
||||
}
|
||||
|
||||
icount_label = gen_new_label();
|
||||
count = tcg_temp_local_new_i32();
|
||||
tcg_gen_ld_i32(count, cpu_env,
|
||||
-ENV_OFFSET + offsetof(CPUState, icount_decr.u32));
|
||||
|
||||
imm = tcg_temp_new_i32();
|
||||
tcg_gen_movi_i32(imm, 0xdeadbeef);
|
||||
|
||||
/* This is a horrid hack to allow fixing up the value later. */
|
||||
icount_arg = tcg_ctx.gen_opparam_ptr + 1;
|
||||
tcg_gen_subi_i32(count, count, 0xdeadbeef);
|
||||
i = tcg_ctx.gen_last_op_idx;
|
||||
i = tcg_ctx.gen_op_buf[i].args;
|
||||
icount_arg = &tcg_ctx.gen_opparam_buf[i + 1];
|
||||
|
||||
tcg_gen_sub_i32(count, count, imm);
|
||||
tcg_temp_free_i32(imm);
|
||||
|
||||
tcg_gen_brcondi_i32(TCG_COND_LT, count, 0, icount_label);
|
||||
tcg_gen_st16_i32(count, cpu_env,
|
||||
@@ -49,7 +58,8 @@ static void gen_tb_end(TranslationBlock *tb, int num_insns)
|
||||
tcg_gen_exit_tb((uintptr_t)tb + TB_EXIT_ICOUNT_EXPIRED);
|
||||
}
|
||||
|
||||
*tcg_ctx.gen_opc_ptr = INDEX_op_end;
|
||||
/* Terminate the linked list. */
|
||||
tcg_ctx.gen_op_buf[tcg_ctx.gen_last_op_idx].next = -1;
|
||||
}
|
||||
|
||||
static inline void gen_io_start(void)
|
||||
|
||||
+116
-170
File diff suppressed because it is too large
Load Diff
+106
-94
@@ -35,100 +35,116 @@ extern TCGv_i32 TCGV_HIGH_link_error(TCGv_i64);
|
||||
#define TCGV_HIGH TCGV_HIGH_link_error
|
||||
#endif
|
||||
|
||||
/* Note that this is optimized for sequential allocation during translate.
|
||||
Up to and including filling in the forward link immediately. We'll do
|
||||
proper termination of the end of the list after we finish translation. */
|
||||
|
||||
static void tcg_emit_op(TCGContext *ctx, TCGOpcode opc, int args)
|
||||
{
|
||||
int oi = ctx->gen_next_op_idx;
|
||||
int ni = oi + 1;
|
||||
int pi = oi - 1;
|
||||
|
||||
tcg_debug_assert(oi < OPC_BUF_SIZE);
|
||||
ctx->gen_last_op_idx = oi;
|
||||
ctx->gen_next_op_idx = ni;
|
||||
|
||||
ctx->gen_op_buf[oi] = (TCGOp){
|
||||
.opc = opc,
|
||||
.args = args,
|
||||
.prev = pi,
|
||||
.next = ni
|
||||
};
|
||||
}
|
||||
|
||||
void tcg_gen_op0(TCGContext *ctx, TCGOpcode opc)
|
||||
{
|
||||
*ctx->gen_opc_ptr++ = opc;
|
||||
tcg_emit_op(ctx, opc, -1);
|
||||
}
|
||||
|
||||
void tcg_gen_op1(TCGContext *ctx, TCGOpcode opc, TCGArg a1)
|
||||
{
|
||||
uint16_t *op = ctx->gen_opc_ptr;
|
||||
TCGArg *opp = ctx->gen_opparam_ptr;
|
||||
int pi = ctx->gen_next_parm_idx;
|
||||
|
||||
op[0] = opc;
|
||||
opp[0] = a1;
|
||||
tcg_debug_assert(pi + 1 <= OPPARAM_BUF_SIZE);
|
||||
ctx->gen_next_parm_idx = pi + 1;
|
||||
ctx->gen_opparam_buf[pi] = a1;
|
||||
|
||||
ctx->gen_opc_ptr = op + 1;
|
||||
ctx->gen_opparam_ptr = opp + 1;
|
||||
tcg_emit_op(ctx, opc, pi);
|
||||
}
|
||||
|
||||
void tcg_gen_op2(TCGContext *ctx, TCGOpcode opc, TCGArg a1, TCGArg a2)
|
||||
{
|
||||
uint16_t *op = ctx->gen_opc_ptr;
|
||||
TCGArg *opp = ctx->gen_opparam_ptr;
|
||||
int pi = ctx->gen_next_parm_idx;
|
||||
|
||||
op[0] = opc;
|
||||
opp[0] = a1;
|
||||
opp[1] = a2;
|
||||
tcg_debug_assert(pi + 2 <= OPPARAM_BUF_SIZE);
|
||||
ctx->gen_next_parm_idx = pi + 2;
|
||||
ctx->gen_opparam_buf[pi + 0] = a1;
|
||||
ctx->gen_opparam_buf[pi + 1] = a2;
|
||||
|
||||
ctx->gen_opc_ptr = op + 1;
|
||||
ctx->gen_opparam_ptr = opp + 2;
|
||||
tcg_emit_op(ctx, opc, pi);
|
||||
}
|
||||
|
||||
void tcg_gen_op3(TCGContext *ctx, TCGOpcode opc, TCGArg a1,
|
||||
TCGArg a2, TCGArg a3)
|
||||
{
|
||||
uint16_t *op = ctx->gen_opc_ptr;
|
||||
TCGArg *opp = ctx->gen_opparam_ptr;
|
||||
int pi = ctx->gen_next_parm_idx;
|
||||
|
||||
op[0] = opc;
|
||||
opp[0] = a1;
|
||||
opp[1] = a2;
|
||||
opp[2] = a3;
|
||||
tcg_debug_assert(pi + 3 <= OPPARAM_BUF_SIZE);
|
||||
ctx->gen_next_parm_idx = pi + 3;
|
||||
ctx->gen_opparam_buf[pi + 0] = a1;
|
||||
ctx->gen_opparam_buf[pi + 1] = a2;
|
||||
ctx->gen_opparam_buf[pi + 2] = a3;
|
||||
|
||||
ctx->gen_opc_ptr = op + 1;
|
||||
ctx->gen_opparam_ptr = opp + 3;
|
||||
tcg_emit_op(ctx, opc, pi);
|
||||
}
|
||||
|
||||
void tcg_gen_op4(TCGContext *ctx, TCGOpcode opc, TCGArg a1,
|
||||
TCGArg a2, TCGArg a3, TCGArg a4)
|
||||
{
|
||||
uint16_t *op = ctx->gen_opc_ptr;
|
||||
TCGArg *opp = ctx->gen_opparam_ptr;
|
||||
int pi = ctx->gen_next_parm_idx;
|
||||
|
||||
op[0] = opc;
|
||||
opp[0] = a1;
|
||||
opp[1] = a2;
|
||||
opp[2] = a3;
|
||||
opp[3] = a4;
|
||||
tcg_debug_assert(pi + 4 <= OPPARAM_BUF_SIZE);
|
||||
ctx->gen_next_parm_idx = pi + 4;
|
||||
ctx->gen_opparam_buf[pi + 0] = a1;
|
||||
ctx->gen_opparam_buf[pi + 1] = a2;
|
||||
ctx->gen_opparam_buf[pi + 2] = a3;
|
||||
ctx->gen_opparam_buf[pi + 3] = a4;
|
||||
|
||||
ctx->gen_opc_ptr = op + 1;
|
||||
ctx->gen_opparam_ptr = opp + 4;
|
||||
tcg_emit_op(ctx, opc, pi);
|
||||
}
|
||||
|
||||
void tcg_gen_op5(TCGContext *ctx, TCGOpcode opc, TCGArg a1,
|
||||
TCGArg a2, TCGArg a3, TCGArg a4, TCGArg a5)
|
||||
{
|
||||
uint16_t *op = ctx->gen_opc_ptr;
|
||||
TCGArg *opp = ctx->gen_opparam_ptr;
|
||||
int pi = ctx->gen_next_parm_idx;
|
||||
|
||||
op[0] = opc;
|
||||
opp[0] = a1;
|
||||
opp[1] = a2;
|
||||
opp[2] = a3;
|
||||
opp[3] = a4;
|
||||
opp[4] = a5;
|
||||
tcg_debug_assert(pi + 5 <= OPPARAM_BUF_SIZE);
|
||||
ctx->gen_next_parm_idx = pi + 5;
|
||||
ctx->gen_opparam_buf[pi + 0] = a1;
|
||||
ctx->gen_opparam_buf[pi + 1] = a2;
|
||||
ctx->gen_opparam_buf[pi + 2] = a3;
|
||||
ctx->gen_opparam_buf[pi + 3] = a4;
|
||||
ctx->gen_opparam_buf[pi + 4] = a5;
|
||||
|
||||
ctx->gen_opc_ptr = op + 1;
|
||||
ctx->gen_opparam_ptr = opp + 5;
|
||||
tcg_emit_op(ctx, opc, pi);
|
||||
}
|
||||
|
||||
void tcg_gen_op6(TCGContext *ctx, TCGOpcode opc, TCGArg a1, TCGArg a2,
|
||||
TCGArg a3, TCGArg a4, TCGArg a5, TCGArg a6)
|
||||
{
|
||||
uint16_t *op = ctx->gen_opc_ptr;
|
||||
TCGArg *opp = ctx->gen_opparam_ptr;
|
||||
int pi = ctx->gen_next_parm_idx;
|
||||
|
||||
op[0] = opc;
|
||||
opp[0] = a1;
|
||||
opp[1] = a2;
|
||||
opp[2] = a3;
|
||||
opp[3] = a4;
|
||||
opp[4] = a5;
|
||||
opp[5] = a6;
|
||||
tcg_debug_assert(pi + 6 <= OPPARAM_BUF_SIZE);
|
||||
ctx->gen_next_parm_idx = pi + 6;
|
||||
ctx->gen_opparam_buf[pi + 0] = a1;
|
||||
ctx->gen_opparam_buf[pi + 1] = a2;
|
||||
ctx->gen_opparam_buf[pi + 2] = a3;
|
||||
ctx->gen_opparam_buf[pi + 3] = a4;
|
||||
ctx->gen_opparam_buf[pi + 4] = a5;
|
||||
ctx->gen_opparam_buf[pi + 5] = a6;
|
||||
|
||||
ctx->gen_opc_ptr = op + 1;
|
||||
ctx->gen_opparam_ptr = opp + 6;
|
||||
tcg_emit_op(ctx, opc, pi);
|
||||
}
|
||||
|
||||
/* 32 bit ops */
|
||||
@@ -1862,53 +1878,57 @@ static inline TCGMemOp tcg_canonicalize_memop(TCGMemOp op, bool is64, bool st)
|
||||
return op;
|
||||
}
|
||||
|
||||
static inline void tcg_add_param_i32(TCGv_i32 val)
|
||||
static void gen_ldst_i32(TCGOpcode opc, TCGv_i32 val, TCGv addr,
|
||||
TCGMemOp memop, TCGArg idx)
|
||||
{
|
||||
*tcg_ctx.gen_opparam_ptr++ = GET_TCGV_I32(val);
|
||||
}
|
||||
|
||||
static inline void tcg_add_param_i64(TCGv_i64 val)
|
||||
{
|
||||
if (TCG_TARGET_REG_BITS == 32) {
|
||||
*tcg_ctx.gen_opparam_ptr++ = GET_TCGV_I32(TCGV_LOW(val));
|
||||
*tcg_ctx.gen_opparam_ptr++ = GET_TCGV_I32(TCGV_HIGH(val));
|
||||
} else {
|
||||
*tcg_ctx.gen_opparam_ptr++ = GET_TCGV_I64(val);
|
||||
}
|
||||
}
|
||||
|
||||
#if TARGET_LONG_BITS == 32
|
||||
# define tcg_add_param_tl tcg_add_param_i32
|
||||
tcg_gen_op4ii_i32(opc, val, addr, memop, idx);
|
||||
#else
|
||||
# define tcg_add_param_tl tcg_add_param_i64
|
||||
if (TCG_TARGET_REG_BITS == 32) {
|
||||
tcg_gen_op5ii_i32(opc, val, TCGV_LOW(addr), TCGV_HIGH(addr),
|
||||
memop, idx);
|
||||
} else {
|
||||
tcg_gen_op4(&tcg_ctx, opc, GET_TCGV_I32(val), GET_TCGV_I64(addr),
|
||||
memop, idx);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
static void gen_ldst_i64(TCGOpcode opc, TCGv_i64 val, TCGv addr,
|
||||
TCGMemOp memop, TCGArg idx)
|
||||
{
|
||||
#if TARGET_LONG_BITS == 32
|
||||
if (TCG_TARGET_REG_BITS == 32) {
|
||||
tcg_gen_op5ii_i32(opc, TCGV_LOW(val), TCGV_HIGH(val),
|
||||
addr, memop, idx);
|
||||
} else {
|
||||
tcg_gen_op4(&tcg_ctx, opc, GET_TCGV_I64(val), GET_TCGV_I32(addr),
|
||||
memop, idx);
|
||||
}
|
||||
#else
|
||||
if (TCG_TARGET_REG_BITS == 32) {
|
||||
tcg_gen_op6ii_i32(opc, TCGV_LOW(val), TCGV_HIGH(val),
|
||||
TCGV_LOW(addr), TCGV_HIGH(addr), memop, idx);
|
||||
} else {
|
||||
tcg_gen_op4ii_i64(opc, val, addr, memop, idx);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void tcg_gen_qemu_ld_i32(TCGv_i32 val, TCGv addr, TCGArg idx, TCGMemOp memop)
|
||||
{
|
||||
memop = tcg_canonicalize_memop(memop, 0, 0);
|
||||
|
||||
*tcg_ctx.gen_opc_ptr++ = INDEX_op_qemu_ld_i32;
|
||||
tcg_add_param_i32(val);
|
||||
tcg_add_param_tl(addr);
|
||||
*tcg_ctx.gen_opparam_ptr++ = memop;
|
||||
*tcg_ctx.gen_opparam_ptr++ = idx;
|
||||
gen_ldst_i32(INDEX_op_qemu_ld_i32, val, addr, memop, idx);
|
||||
}
|
||||
|
||||
void tcg_gen_qemu_st_i32(TCGv_i32 val, TCGv addr, TCGArg idx, TCGMemOp memop)
|
||||
{
|
||||
memop = tcg_canonicalize_memop(memop, 0, 1);
|
||||
|
||||
*tcg_ctx.gen_opc_ptr++ = INDEX_op_qemu_st_i32;
|
||||
tcg_add_param_i32(val);
|
||||
tcg_add_param_tl(addr);
|
||||
*tcg_ctx.gen_opparam_ptr++ = memop;
|
||||
*tcg_ctx.gen_opparam_ptr++ = idx;
|
||||
gen_ldst_i32(INDEX_op_qemu_st_i32, val, addr, memop, idx);
|
||||
}
|
||||
|
||||
void tcg_gen_qemu_ld_i64(TCGv_i64 val, TCGv addr, TCGArg idx, TCGMemOp memop)
|
||||
{
|
||||
memop = tcg_canonicalize_memop(memop, 1, 0);
|
||||
|
||||
if (TCG_TARGET_REG_BITS == 32 && (memop & MO_SIZE) < MO_64) {
|
||||
tcg_gen_qemu_ld_i32(TCGV_LOW(val), addr, idx, memop);
|
||||
if (memop & MO_SIGN) {
|
||||
@@ -1919,25 +1939,17 @@ void tcg_gen_qemu_ld_i64(TCGv_i64 val, TCGv addr, TCGArg idx, TCGMemOp memop)
|
||||
return;
|
||||
}
|
||||
|
||||
*tcg_ctx.gen_opc_ptr++ = INDEX_op_qemu_ld_i64;
|
||||
tcg_add_param_i64(val);
|
||||
tcg_add_param_tl(addr);
|
||||
*tcg_ctx.gen_opparam_ptr++ = memop;
|
||||
*tcg_ctx.gen_opparam_ptr++ = idx;
|
||||
memop = tcg_canonicalize_memop(memop, 1, 0);
|
||||
gen_ldst_i64(INDEX_op_qemu_ld_i64, val, addr, memop, idx);
|
||||
}
|
||||
|
||||
void tcg_gen_qemu_st_i64(TCGv_i64 val, TCGv addr, TCGArg idx, TCGMemOp memop)
|
||||
{
|
||||
memop = tcg_canonicalize_memop(memop, 1, 1);
|
||||
|
||||
if (TCG_TARGET_REG_BITS == 32 && (memop & MO_SIZE) < MO_64) {
|
||||
tcg_gen_qemu_st_i32(TCGV_LOW(val), addr, idx, memop);
|
||||
return;
|
||||
}
|
||||
|
||||
*tcg_ctx.gen_opc_ptr++ = INDEX_op_qemu_st_i64;
|
||||
tcg_add_param_i64(val);
|
||||
tcg_add_param_tl(addr);
|
||||
*tcg_ctx.gen_opparam_ptr++ = memop;
|
||||
*tcg_ctx.gen_opparam_ptr++ = idx;
|
||||
memop = tcg_canonicalize_memop(memop, 1, 1);
|
||||
gen_ldst_i64(INDEX_op_qemu_st_i64, val, addr, memop, idx);
|
||||
}
|
||||
|
||||
@@ -448,10 +448,28 @@ typedef struct TCGTempSet {
|
||||
unsigned long l[BITS_TO_LONGS(TCG_MAX_TEMPS)];
|
||||
} TCGTempSet;
|
||||
|
||||
typedef struct TCGOp {
|
||||
TCGOpcode opc : 8;
|
||||
|
||||
/* The number of out and in parameter for a call. */
|
||||
unsigned callo : 2;
|
||||
unsigned calli : 6;
|
||||
|
||||
/* Index of the arguments for this op, or -1 for zero-operand ops. */
|
||||
signed args : 16;
|
||||
|
||||
/* Index of the prex/next op, or -1 for the end of the list. */
|
||||
signed prev : 16;
|
||||
signed next : 16;
|
||||
} TCGOp;
|
||||
|
||||
QEMU_BUILD_BUG_ON(NB_OPS > 0xff);
|
||||
QEMU_BUILD_BUG_ON(OPC_BUF_SIZE >= 0x7fff);
|
||||
QEMU_BUILD_BUG_ON(OPPARAM_BUF_SIZE >= 0x7fff);
|
||||
|
||||
struct TCGContext {
|
||||
uint8_t *pool_cur, *pool_end;
|
||||
TCGPool *pool_first, *pool_current, *pool_first_large;
|
||||
TCGLabel *labels;
|
||||
int nb_labels;
|
||||
int nb_globals;
|
||||
int nb_temps;
|
||||
@@ -469,9 +487,6 @@ struct TCGContext {
|
||||
corresponding output argument needs to be
|
||||
sync to memory. */
|
||||
|
||||
/* tells in which temporary a given register is. It does not take
|
||||
into account fixed registers */
|
||||
int reg_to_temp[TCG_TARGET_NB_REGS];
|
||||
TCGRegSet reserved_regs;
|
||||
intptr_t current_frame_offset;
|
||||
intptr_t frame_start;
|
||||
@@ -479,8 +494,6 @@ struct TCGContext {
|
||||
int frame_reg;
|
||||
|
||||
tcg_insn_unit *code_ptr;
|
||||
TCGTemp temps[TCG_MAX_TEMPS]; /* globals first, temps after */
|
||||
TCGTempSet free_temps[TCG_TYPE_COUNT * 2];
|
||||
|
||||
GHashTable *helpers;
|
||||
|
||||
@@ -508,14 +521,10 @@ struct TCGContext {
|
||||
int goto_tb_issue_mask;
|
||||
#endif
|
||||
|
||||
uint16_t gen_opc_buf[OPC_BUF_SIZE];
|
||||
TCGArg gen_opparam_buf[OPPARAM_BUF_SIZE];
|
||||
|
||||
uint16_t *gen_opc_ptr;
|
||||
TCGArg *gen_opparam_ptr;
|
||||
target_ulong gen_opc_pc[OPC_BUF_SIZE];
|
||||
uint16_t gen_opc_icount[OPC_BUF_SIZE];
|
||||
uint8_t gen_opc_instr_start[OPC_BUF_SIZE];
|
||||
int gen_first_op_idx;
|
||||
int gen_last_op_idx;
|
||||
int gen_next_op_idx;
|
||||
int gen_next_parm_idx;
|
||||
|
||||
/* Code generation. Note that we specifically do not use tcg_insn_unit
|
||||
here, because there's too much arithmetic throughout that relies
|
||||
@@ -533,6 +542,22 @@ struct TCGContext {
|
||||
|
||||
/* The TCGBackendData structure is private to tcg-target.c. */
|
||||
struct TCGBackendData *be;
|
||||
|
||||
TCGTempSet free_temps[TCG_TYPE_COUNT * 2];
|
||||
TCGTemp temps[TCG_MAX_TEMPS]; /* globals first, temps after */
|
||||
|
||||
/* tells in which temporary a given register is. It does not take
|
||||
into account fixed registers */
|
||||
int reg_to_temp[TCG_TARGET_NB_REGS];
|
||||
|
||||
TCGOp gen_op_buf[OPC_BUF_SIZE];
|
||||
TCGArg gen_opparam_buf[OPPARAM_BUF_SIZE];
|
||||
|
||||
target_ulong gen_opc_pc[OPC_BUF_SIZE];
|
||||
uint16_t gen_opc_icount[OPC_BUF_SIZE];
|
||||
uint8_t gen_opc_instr_start[OPC_BUF_SIZE];
|
||||
|
||||
TCGLabel labels[TCG_MAX_LABELS];
|
||||
};
|
||||
|
||||
extern TCGContext tcg_ctx;
|
||||
@@ -540,7 +565,7 @@ extern TCGContext tcg_ctx;
|
||||
/* The number of opcodes emitted so far. */
|
||||
static inline int tcg_op_buf_count(void)
|
||||
{
|
||||
return tcg_ctx.gen_opc_ptr - tcg_ctx.gen_opc_buf;
|
||||
return tcg_ctx.gen_next_op_idx;
|
||||
}
|
||||
|
||||
/* Test for whether to terminate the TB for using too many opcodes. */
|
||||
@@ -718,8 +743,7 @@ void tcg_add_target_add_op_defs(const TCGTargetOpDef *tdefs);
|
||||
void tcg_gen_callN(TCGContext *s, void *func,
|
||||
TCGArg ret, int nargs, TCGArg *args);
|
||||
|
||||
TCGArg *tcg_optimize(TCGContext *s, uint16_t *tcg_opc_ptr, TCGArg *args,
|
||||
TCGOpDef *tcg_op_def);
|
||||
void tcg_optimize(TCGContext *s);
|
||||
|
||||
/* only used for debugging purposes */
|
||||
void tcg_dump_ops(TCGContext *s);
|
||||
|
||||
Reference in New Issue
Block a user