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:
Richard Henderson
2015-02-12 21:21:38 -08:00
parent fe700adb3d
commit c45cb8bb89
5 changed files with 438 additions and 508 deletions
+16 -6
View File
@@ -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
View File
File diff suppressed because it is too large Load Diff
+106 -94
View File
@@ -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);
}
+159 -221
View File
File diff suppressed because it is too large Load Diff
+41 -17
View File
@@ -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);