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.
This commit is contained in:
Lioncash 2018-02-09 09:54:01 -05:00
parent a41b9acc0c
commit 0273e6ae18
No known key found for this signature in database
GPG key ID: 4E3C3CC1031BA9C7
11 changed files with 461 additions and 527 deletions

View file

@ -10,8 +10,9 @@
static inline void gen_tb_start(TCGContext *tcg_ctx) static inline void gen_tb_start(TCGContext *tcg_ctx)
{ {
// TCGv_i32 count; //TCGv_i32 count, flag, imm;
TCGv_i32 flag; TCGv_i32 flag;
//int i;
tcg_ctx->exitreq_label = gen_new_label(tcg_ctx); tcg_ctx->exitreq_label = gen_new_label(tcg_ctx);
flag = tcg_temp_new_i32(tcg_ctx); flag = tcg_temp_new_i32(tcg_ctx);
@ -21,21 +22,31 @@ static inline void gen_tb_start(TCGContext *tcg_ctx)
tcg_temp_free_i32(tcg_ctx, flag); tcg_temp_free_i32(tcg_ctx, flag);
#if 0 #if 0
if (!use_icount) if (!(s->tb->cflags & CF_USE_ICOUNT)) {
return; return;
}
icount_label = gen_new_label(); icount_label = gen_new_label(tcg_ctx);
count = tcg_temp_local_new_i32(); count = tcg_temp_local_new_i32(tcg_ctx);
tcg_gen_ld_i32(count, cpu_env, tcg_gen_ld_i32(tcg_ctx, count, cpu_env,
-ENV_OFFSET + offsetof(CPUState, icount_decr.u32)); -ENV_OFFSET + offsetof(CPUState, icount_decr.u32));
/* This is a horrid hack to allow fixing up the value later. */ imm = tcg_temp_new_i32(tcg_ctx);
icount_arg = tcg_ctx.gen_opparam_ptr + 1; tcg_gen_movi_i32(tcg_ctx, imm, 0xdeadbeef);
tcg_gen_subi_i32(count, count, 0xdeadbeef);
tcg_gen_brcondi_i32(TCG_COND_LT, count, 0, icount_label);
tcg_gen_st16_i32(count, cpu_env, /* This is a horrid hack to allow fixing up the value later. */
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(tcg_ctx, count, count, imm);
tcg_temp_free_i32(tcg_ctx, imm);
tcg_gen_brcondi_i32(tcg_ctx, TCG_COND_LT, count, 0, icount_label);
tcg_gen_st16_i32(tcg_ctx, count, cpu_env,
-ENV_OFFSET + offsetof(CPUState, icount_decr.u16.low)); -ENV_OFFSET + offsetof(CPUState, icount_decr.u16.low));
tcg_temp_free_i32(count); tcg_temp_free_i32(tcg_ctx, count);
#endif #endif
} }
@ -52,7 +63,8 @@ static inline void gen_tb_end(TCGContext *tcg_ctx, TranslationBlock *tb, int num
} }
#endif #endif
*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;
} }
#if 0 #if 0

View file

@ -11166,7 +11166,7 @@ void gen_intermediate_code_internal_a64(ARMCPU *cpu,
if (!env->uc->block_full && HOOK_EXISTS_BOUNDED(env->uc, UC_HOOK_BLOCK, pc_start)) { if (!env->uc->block_full && HOOK_EXISTS_BOUNDED(env->uc, UC_HOOK_BLOCK, pc_start)) {
// save block address to see if we need to patch block size later // save block address to see if we need to patch block size later
env->uc->block_addr = pc_start; env->uc->block_addr = pc_start;
env->uc->size_arg = tcg_ctx->gen_opparam_buf - tcg_ctx->gen_opparam_ptr + 1; env->uc->size_arg = tcg_ctx->gen_op_buf[tcg_ctx->gen_last_op_idx].args;
gen_uc_tracecode(tcg_ctx, 0xf8f8f8f8, UC_HOOK_BLOCK_IDX, env->uc, pc_start); gen_uc_tracecode(tcg_ctx, 0xf8f8f8f8, UC_HOOK_BLOCK_IDX, env->uc, pc_start);
} else { } else {
env->uc->size_arg = -1; env->uc->size_arg = -1;

View file

@ -11354,7 +11354,7 @@ static inline void gen_intermediate_code_internal(ARMCPU *cpu,
if (!env->uc->block_full && HOOK_EXISTS_BOUNDED(env->uc, UC_HOOK_BLOCK, pc_start)) { if (!env->uc->block_full && HOOK_EXISTS_BOUNDED(env->uc, UC_HOOK_BLOCK, pc_start)) {
// save block address to see if we need to patch block size later // save block address to see if we need to patch block size later
env->uc->block_addr = pc_start; env->uc->block_addr = pc_start;
env->uc->size_arg = tcg_ctx->gen_opparam_buf - tcg_ctx->gen_opparam_ptr + 1; env->uc->size_arg = tcg_ctx->gen_op_buf[tcg_ctx->gen_last_op_idx].args;
gen_uc_tracecode(tcg_ctx, 0xf8f8f8f8, UC_HOOK_BLOCK_IDX, env->uc, pc_start); gen_uc_tracecode(tcg_ctx, 0xf8f8f8f8, UC_HOOK_BLOCK_IDX, env->uc, pc_start);
} else { } else {
env->uc->size_arg = -1; env->uc->size_arg = -1;

View file

@ -5003,7 +5003,7 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s,
TCGv cpu_tmp4 = *(TCGv *)tcg_ctx->cpu_tmp4; TCGv cpu_tmp4 = *(TCGv *)tcg_ctx->cpu_tmp4;
TCGv **cpu_T = (TCGv **)tcg_ctx->cpu_T; TCGv **cpu_T = (TCGv **)tcg_ctx->cpu_T;
TCGv **cpu_regs = (TCGv **)tcg_ctx->cpu_regs; TCGv **cpu_regs = (TCGv **)tcg_ctx->cpu_regs;
TCGArg *save_opparam_ptr = tcg_ctx->gen_opparam_ptr; TCGArg* save_opparam_ptr = tcg_ctx->gen_opparam_buf + tcg_ctx->gen_op_buf[tcg_ctx->gen_last_op_idx].args;
bool cc_op_dirty = s->cc_op_dirty; bool cc_op_dirty = s->cc_op_dirty;
bool changed_cc_op = false; bool changed_cc_op = false;
@ -8702,8 +8702,9 @@ static inline void gen_intermediate_code_internal(uint8_t *gen_opc_cc_op,
// Unicorn: trace this block on request // Unicorn: trace this block on request
// Only hook this block if the previous block was not truncated due to space // Only hook this block if the previous block was not truncated due to space
if (!env->uc->block_full && HOOK_EXISTS_BOUNDED(env->uc, UC_HOOK_BLOCK, pc_start)) { if (!env->uc->block_full && HOOK_EXISTS_BOUNDED(env->uc, UC_HOOK_BLOCK, pc_start)) {
int arg_i = tcg_ctx->gen_op_buf[tcg_ctx->gen_last_op_idx].args;
env->uc->block_addr = pc_start; env->uc->block_addr = pc_start;
env->uc->size_arg = tcg_ctx->gen_opparam_buf - tcg_ctx->gen_opparam_ptr + 1; env->uc->size_arg = arg_i + 1;
gen_uc_tracecode(tcg_ctx, 0xf8f8f8f8, UC_HOOK_BLOCK_IDX, env->uc, pc_start); gen_uc_tracecode(tcg_ctx, 0xf8f8f8f8, UC_HOOK_BLOCK_IDX, env->uc, pc_start);
} else { } else {
env->uc->size_arg = -1; env->uc->size_arg = -1;

View file

@ -3109,7 +3109,7 @@ gen_intermediate_code_internal(M68kCPU *cpu, TranslationBlock *tb,
if (!env->uc->block_full && HOOK_EXISTS_BOUNDED(env->uc, UC_HOOK_BLOCK, pc_start)) { if (!env->uc->block_full && HOOK_EXISTS_BOUNDED(env->uc, UC_HOOK_BLOCK, pc_start)) {
// save block address to see if we need to patch block size later // save block address to see if we need to patch block size later
env->uc->block_addr = pc_start; env->uc->block_addr = pc_start;
env->uc->size_arg = tcg_ctx->gen_opparam_buf - tcg_ctx->gen_opparam_ptr + 1; env->uc->size_arg = tcg_ctx->gen_op_buf[tcg_ctx->gen_last_op_idx].args;
gen_uc_tracecode(tcg_ctx, 0xf8f8f8f8, UC_HOOK_BLOCK_IDX, env->uc, pc_start); gen_uc_tracecode(tcg_ctx, 0xf8f8f8f8, UC_HOOK_BLOCK_IDX, env->uc, pc_start);
} else { } else {
env->uc->size_arg = -1; env->uc->size_arg = -1;

View file

@ -19168,7 +19168,7 @@ gen_intermediate_code_internal(MIPSCPU *cpu, TranslationBlock *tb,
int insn_bytes; int insn_bytes;
int is_slot = 0; int is_slot = 0;
TCGContext *tcg_ctx = env->uc->tcg_ctx; TCGContext *tcg_ctx = env->uc->tcg_ctx;
TCGArg *save_opparam_ptr = NULL; int save_opparam_idx = -1;
bool block_full = false; bool block_full = false;
if (search_pc) if (search_pc)
@ -19215,9 +19215,10 @@ gen_intermediate_code_internal(MIPSCPU *cpu, TranslationBlock *tb,
// Only hook this block if it is not broken from previous translation due to // Only hook this block if it is not broken from previous translation due to
// full translation cache // full translation cache
if (!env->uc->block_full && HOOK_EXISTS_BOUNDED(env->uc, UC_HOOK_BLOCK, pc_start)) { if (!env->uc->block_full && HOOK_EXISTS_BOUNDED(env->uc, UC_HOOK_BLOCK, pc_start)) {
int arg_i = tcg_ctx->gen_op_buf[tcg_ctx->gen_last_op_idx].args;
// save block address to see if we need to patch block size later // save block address to see if we need to patch block size later
env->uc->block_addr = pc_start; env->uc->block_addr = pc_start;
env->uc->size_arg = tcg_ctx->gen_opparam_buf - tcg_ctx->gen_opparam_ptr + 1; env->uc->size_arg = arg_i + 1;
gen_uc_tracecode(tcg_ctx, 0xf8f8f8f8, UC_HOOK_BLOCK_IDX, env->uc, pc_start); gen_uc_tracecode(tcg_ctx, 0xf8f8f8f8, UC_HOOK_BLOCK_IDX, env->uc, pc_start);
} else { } else {
env->uc->size_arg = -1; env->uc->size_arg = -1;
@ -19266,8 +19267,9 @@ gen_intermediate_code_internal(MIPSCPU *cpu, TranslationBlock *tb,
int insn_patch_offset = 1; int insn_patch_offset = 1;
// Unicorn: save param buffer // Unicorn: save param buffer
if (HOOK_EXISTS(env->uc, UC_HOOK_CODE)) if (HOOK_EXISTS(env->uc, UC_HOOK_CODE)) {
save_opparam_ptr = tcg_ctx->gen_opparam_ptr; save_opparam_idx = tcg_ctx->gen_next_parm_idx;
}
is_slot = ctx.hflags & MIPS_HFLAG_BMASK; is_slot = ctx.hflags & MIPS_HFLAG_BMASK;
@ -19295,7 +19297,7 @@ gen_intermediate_code_internal(MIPSCPU *cpu, TranslationBlock *tb,
printf("[%u] = %x\n", i, *(save_opparam_ptr + i)); printf("[%u] = %x\n", i, *(save_opparam_ptr + i));
printf("\n"); printf("\n");
*/ */
*(save_opparam_ptr + insn_patch_offset) = insn_bytes; tcg_ctx->gen_opparam_buf[save_opparam_idx + insn_patch_offset] = insn_bytes;
} }
} }

View file

@ -5418,7 +5418,7 @@ static inline void gen_intermediate_code_internal(SPARCCPU *cpu,
if (!env->uc->block_full && HOOK_EXISTS_BOUNDED(env->uc, UC_HOOK_BLOCK, pc_start)) { if (!env->uc->block_full && HOOK_EXISTS_BOUNDED(env->uc, UC_HOOK_BLOCK, pc_start)) {
// save block address to see if we need to patch block size later // save block address to see if we need to patch block size later
env->uc->block_addr = pc_start; env->uc->block_addr = pc_start;
env->uc->size_arg = tcg_ctx->gen_opparam_buf - tcg_ctx->gen_opparam_ptr + 1; env->uc->size_arg = tcg_ctx->gen_op_buf[tcg_ctx->gen_last_op_idx].args;
gen_uc_tracecode(tcg_ctx, 0xf8f8f8f8, UC_HOOK_BLOCK_IDX, env->uc, pc_start); gen_uc_tracecode(tcg_ctx, 0xf8f8f8f8, UC_HOOK_BLOCK_IDX, env->uc, pc_start);
} }

View file

@ -152,14 +152,14 @@ static bool temps_are_copies(TCGContext *s, TCGArg arg1, TCGArg arg2)
return false; return false;
} }
static void tcg_opt_gen_mov(TCGContext *s, int op_index, TCGArg *gen_args, static void tcg_opt_gen_mov(TCGContext *s, TCGOp *op, TCGArg *args,
TCGOpcode old_op, TCGArg dst, TCGArg src) TCGOpcode old_op, TCGArg dst, TCGArg src)
{ {
struct tcg_temp_info *temps = s->temps2; struct tcg_temp_info *temps = s->temps2;
TCGOpcode new_op = op_to_mov(s, old_op); TCGOpcode new_op = op_to_mov(s, old_op);
tcg_target_ulong mask; tcg_target_ulong mask;
s->gen_opc_buf[op_index] = new_op; op->opc = new_op;
reset_temp(s, dst); reset_temp(s, dst);
mask = temps[src].mask; mask = temps[src].mask;
@ -184,18 +184,18 @@ static void tcg_opt_gen_mov(TCGContext *s, int op_index, TCGArg *gen_args,
temps[src].next_copy = dst; temps[src].next_copy = dst;
} }
gen_args[0] = dst; args[0] = dst;
gen_args[1] = src; args[1] = src;
} }
static void tcg_opt_gen_movi(TCGContext *s, int op_index, TCGArg *gen_args, static void tcg_opt_gen_movi(TCGContext *s, TCGOp *op, TCGArg *args,
TCGOpcode old_op, TCGArg dst, TCGArg val) TCGOpcode old_op, TCGArg dst, TCGArg val)
{ {
struct tcg_temp_info *temps = s->temps2; struct tcg_temp_info *temps = s->temps2;
TCGOpcode new_op = op_to_movi(s, old_op); TCGOpcode new_op = op_to_movi(s, old_op);
tcg_target_ulong mask; tcg_target_ulong mask;
s->gen_opc_buf[op_index] = new_op; op->opc = new_op;
reset_temp(s, dst); reset_temp(s, dst);
temps[dst].state = TCG_TEMP_CONST; temps[dst].state = TCG_TEMP_CONST;
@ -207,8 +207,8 @@ static void tcg_opt_gen_movi(TCGContext *s, int op_index, TCGArg *gen_args,
} }
temps[dst].mask = mask; temps[dst].mask = mask;
gen_args[0] = dst; args[0] = dst;
gen_args[1] = val; args[1] = val;
} }
static TCGArg do_constant_folding_2(TCGOpcode op, TCGArg x, TCGArg y) static TCGArg do_constant_folding_2(TCGOpcode op, TCGArg x, TCGArg y)
@ -533,12 +533,10 @@ static bool swap_commutative2(TCGContext *s, TCGArg *p1, TCGArg *p2)
} }
/* Propagate constants and copies, fold constant expressions. */ /* Propagate constants and copies, fold constant expressions. */
static TCGArg *tcg_constant_folding(TCGContext *s, uint16_t *tcg_opc_ptr, static void tcg_constant_folding(TCGContext *s)
TCGArg *args, TCGOpDef *tcg_op_defs)
{ {
struct tcg_temp_info *temps = s->temps2; struct tcg_temp_info *temps = s->temps2;
int nb_ops, op_index, nb_temps, nb_globals; int oi, oi_next, nb_temps, nb_globals;
TCGArg *gen_args;
/* Array VALS has an element for each temp. /* Array VALS has an element for each temp.
If this temp holds a constant then its value is kept in VALS' element. If this temp holds a constant then its value is kept in VALS' element.
@ -549,24 +547,23 @@ static TCGArg *tcg_constant_folding(TCGContext *s, uint16_t *tcg_opc_ptr,
nb_globals = s->nb_globals; nb_globals = s->nb_globals;
reset_all_temps(s, nb_temps); reset_all_temps(s, nb_temps);
nb_ops = tcg_opc_ptr - s->gen_opc_buf; for (oi = s->gen_first_op_idx; oi >= 0; oi = oi_next) {
gen_args = args;
for (op_index = 0; op_index < nb_ops; op_index++) {
TCGOpcode op = s->gen_opc_buf[op_index];
const TCGOpDef *def = &tcg_op_defs[op];
tcg_target_ulong mask, partmask, affected; tcg_target_ulong mask, partmask, affected;
int nb_oargs, nb_iargs, nb_args, i; int nb_oargs, nb_iargs, i;
TCGArg tmp; TCGArg tmp;
if (op == INDEX_op_call) { TCGOp * const op = &s->gen_op_buf[oi];
*gen_args++ = tmp = *args++; TCGArg * const args = &s->gen_opparam_buf[op->args];
nb_oargs = tmp >> 16; TCGOpcode opc = op->opc;
nb_iargs = tmp & 0xffff; const TCGOpDef *def = &s->tcg_op_defs[opc];
nb_args = nb_oargs + nb_iargs + def->nb_cargs;
oi_next = op->next;
if (opc == INDEX_op_call) {
nb_oargs = op->callo;
nb_iargs = op->calli;
} else { } else {
nb_oargs = def->nb_oargs; nb_oargs = def->nb_oargs;
nb_iargs = def->nb_iargs; nb_iargs = def->nb_iargs;
nb_args = def->nb_args;
} }
/* Do copy propagation */ /* Do copy propagation */
@ -577,7 +574,7 @@ static TCGArg *tcg_constant_folding(TCGContext *s, uint16_t *tcg_opc_ptr,
} }
/* For commutative operations make constant second argument */ /* For commutative operations make constant second argument */
switch (op) { switch (opc) {
CASE_OP_32_64(add): CASE_OP_32_64(add):
CASE_OP_32_64(mul): CASE_OP_32_64(mul):
CASE_OP_32_64(and): CASE_OP_32_64(and):
@ -635,7 +632,7 @@ static TCGArg *tcg_constant_folding(TCGContext *s, uint16_t *tcg_opc_ptr,
/* Simplify expressions for "shift/rot r, 0, a => movi r, 0", /* Simplify expressions for "shift/rot r, 0, a => movi r, 0",
and "sub r, 0, a => neg r, a" case. */ and "sub r, 0, a => neg r, a" case. */
switch (op) { switch (opc) {
CASE_OP_32_64(shl): CASE_OP_32_64(shl):
CASE_OP_32_64(shr): CASE_OP_32_64(shr):
CASE_OP_32_64(sar): CASE_OP_32_64(sar):
@ -643,9 +640,7 @@ static TCGArg *tcg_constant_folding(TCGContext *s, uint16_t *tcg_opc_ptr,
CASE_OP_32_64(rotr): CASE_OP_32_64(rotr):
if (temps[args[1]].state == TCG_TEMP_CONST if (temps[args[1]].state == TCG_TEMP_CONST
&& temps[args[1]].val == 0) { && temps[args[1]].val == 0) {
tcg_opt_gen_movi(s, op_index, gen_args, op, args[0], 0); tcg_opt_gen_movi(s, op, args, opc, args[0], 0);
args += 3;
gen_args += 2;
continue; continue;
} }
break; break;
@ -658,7 +653,7 @@ static TCGArg *tcg_constant_folding(TCGContext *s, uint16_t *tcg_opc_ptr,
/* Proceed with possible constant folding. */ /* Proceed with possible constant folding. */
break; break;
} }
if (op == INDEX_op_sub_i32) { if (opc == INDEX_op_sub_i32) {
neg_op = INDEX_op_neg_i32; neg_op = INDEX_op_neg_i32;
have_neg = TCG_TARGET_HAS_neg_i32; have_neg = TCG_TARGET_HAS_neg_i32;
} else { } else {
@ -670,12 +665,9 @@ static TCGArg *tcg_constant_folding(TCGContext *s, uint16_t *tcg_opc_ptr,
} }
if (temps[args[1]].state == TCG_TEMP_CONST if (temps[args[1]].state == TCG_TEMP_CONST
&& temps[args[1]].val == 0) { && temps[args[1]].val == 0) {
s->gen_opc_buf[op_index] = neg_op; op->opc = neg_op;
reset_temp(s, args[0]); reset_temp(s, args[0]);
gen_args[0] = args[0]; args[1] = args[2];
gen_args[1] = args[2];
args += 3;
gen_args += 2;
continue; continue;
} }
} }
@ -729,12 +721,9 @@ static TCGArg *tcg_constant_folding(TCGContext *s, uint16_t *tcg_opc_ptr,
if (!have_not) { if (!have_not) {
break; break;
} }
s->gen_opc_buf[op_index] = not_op; op->opc = not_op;
reset_temp(s, args[0]); reset_temp(s, args[0]);
gen_args[0] = args[0]; args[1] = args[i];
gen_args[1] = args[i];
args += 3;
gen_args += 2;
continue; continue;
} }
default: default:
@ -742,7 +731,7 @@ static TCGArg *tcg_constant_folding(TCGContext *s, uint16_t *tcg_opc_ptr,
} }
/* Simplify expression for "op r, a, const => mov r, a" cases */ /* Simplify expression for "op r, a, const => mov r, a" cases */
switch (op) { switch (opc) {
CASE_OP_32_64(add): CASE_OP_32_64(add):
CASE_OP_32_64(sub): CASE_OP_32_64(sub):
CASE_OP_32_64(shl): CASE_OP_32_64(shl):
@ -770,12 +759,10 @@ static TCGArg *tcg_constant_folding(TCGContext *s, uint16_t *tcg_opc_ptr,
break; break;
do_mov3: do_mov3:
if (temps_are_copies(s, args[0], args[1])) { if (temps_are_copies(s, args[0], args[1])) {
s->gen_opc_buf[op_index] = INDEX_op_nop; op->opc = INDEX_op_nop;
} else { } else {
tcg_opt_gen_mov(s, op_index, gen_args, op, args[0], args[1]); tcg_opt_gen_mov(s, op, args, opc, args[0], args[1]);
gen_args += 2;
} }
args += 3;
continue; continue;
default: default:
break; break;
@ -785,7 +772,7 @@ static TCGArg *tcg_constant_folding(TCGContext *s, uint16_t *tcg_opc_ptr,
output argument is supported. */ output argument is supported. */
mask = -1; mask = -1;
affected = -1; affected = -1;
switch (op) { switch (opc) {
CASE_OP_32_64(ext8s): CASE_OP_32_64(ext8s):
if ((temps[args[1]].mask & 0x80) != 0) { if ((temps[args[1]].mask & 0x80) != 0) {
break; break;
@ -924,38 +911,31 @@ static TCGArg *tcg_constant_folding(TCGContext *s, uint16_t *tcg_opc_ptr,
if (partmask == 0) { if (partmask == 0) {
assert(nb_oargs == 1); assert(nb_oargs == 1);
tcg_opt_gen_movi(s, op_index, gen_args, op, args[0], 0); tcg_opt_gen_movi(s, op, args, opc, args[0], 0);
args += nb_args;
gen_args += 2;
continue; continue;
} }
if (affected == 0) { if (affected == 0) {
assert(nb_oargs == 1); assert(nb_oargs == 1);
if (temps_are_copies(s, args[0], args[1])) { if (temps_are_copies(s, args[0], args[1])) {
s->gen_opc_buf[op_index] = INDEX_op_nop; op->opc = INDEX_op_nop;
} else if (temps[args[1]].state != TCG_TEMP_CONST) { } else if (temps[args[1]].state != TCG_TEMP_CONST) {
tcg_opt_gen_mov(s, op_index, gen_args, op, args[0], args[1]); tcg_opt_gen_mov(s, op, args, opc, args[0], args[1]);
gen_args += 2;
} else { } else {
tcg_opt_gen_movi(s, op_index, gen_args, op, tcg_opt_gen_movi(s, op, args, opc,
args[0], temps[args[1]].val); args[0], temps[args[1]].val);
gen_args += 2;
} }
args += nb_args;
continue; continue;
} }
/* Simplify expression for "op r, a, 0 => movi r, 0" cases */ /* Simplify expression for "op r, a, 0 => movi r, 0" cases */
switch (op) { switch (opc) {
CASE_OP_32_64(and): CASE_OP_32_64(and):
CASE_OP_32_64(mul): CASE_OP_32_64(mul):
CASE_OP_32_64(muluh): CASE_OP_32_64(muluh):
CASE_OP_32_64(mulsh): CASE_OP_32_64(mulsh):
if ((temps[args[2]].state == TCG_TEMP_CONST if ((temps[args[2]].state == TCG_TEMP_CONST
&& temps[args[2]].val == 0)) { && temps[args[2]].val == 0)) {
tcg_opt_gen_movi(s, op_index, gen_args, op, args[0], 0); tcg_opt_gen_movi(s, op, args, opc, args[0], 0);
args += 3;
gen_args += 2;
continue; continue;
} }
break; break;
@ -964,18 +944,15 @@ static TCGArg *tcg_constant_folding(TCGContext *s, uint16_t *tcg_opc_ptr,
} }
/* Simplify expression for "op r, a, a => mov r, a" cases */ /* Simplify expression for "op r, a, a => mov r, a" cases */
switch (op) { switch (opc) {
CASE_OP_32_64(or): CASE_OP_32_64(or):
CASE_OP_32_64(and): CASE_OP_32_64(and):
if (temps_are_copies(s, args[1], args[2])) { if (temps_are_copies(s, args[1], args[2])) {
if (temps_are_copies(s, args[0], args[1])) { if (temps_are_copies(s, args[0], args[1])) {
s->gen_opc_buf[op_index] = INDEX_op_nop; op->opc = INDEX_op_nop;
} else { } else {
tcg_opt_gen_mov(s, op_index, gen_args, op, tcg_opt_gen_mov(s, op, args, opc, args[0], args[1]);
args[0], args[1]);
gen_args += 2;
} }
args += 3;
continue; continue;
} }
break; break;
@ -984,14 +961,12 @@ static TCGArg *tcg_constant_folding(TCGContext *s, uint16_t *tcg_opc_ptr,
} }
/* Simplify expression for "op r, a, a => movi r, 0" cases */ /* Simplify expression for "op r, a, a => movi r, 0" cases */
switch (op) { switch (opc) {
CASE_OP_32_64(andc): CASE_OP_32_64(andc):
CASE_OP_32_64(sub): CASE_OP_32_64(sub):
CASE_OP_32_64(xor): CASE_OP_32_64(xor):
if (temps_are_copies(s, args[1], args[2])) { if (temps_are_copies(s, args[1], args[2])) {
tcg_opt_gen_movi(s, op_index, gen_args, op, args[0], 0); tcg_opt_gen_movi(s, op, args, opc, args[0], 0);
gen_args += 2;
args += 3;
continue; continue;
} }
break; break;
@ -1002,17 +977,14 @@ static TCGArg *tcg_constant_folding(TCGContext *s, uint16_t *tcg_opc_ptr,
/* Propagate constants through copy operations and do constant /* Propagate constants through copy operations and do constant
folding. Constants will be substituted to arguments by register folding. Constants will be substituted to arguments by register
allocator where needed and possible. Also detect copies. */ allocator where needed and possible. Also detect copies. */
switch (op) { switch (opc) {
CASE_OP_32_64(mov): CASE_OP_32_64(mov):
if (temps_are_copies(s, args[0], args[1])) { if (temps_are_copies(s, args[0], args[1])) {
args += 2; op->opc = INDEX_op_nop;
s->gen_opc_buf[op_index] = INDEX_op_nop;
break; break;
} }
if (temps[args[1]].state != TCG_TEMP_CONST) { if (temps[args[1]].state != TCG_TEMP_CONST) {
tcg_opt_gen_mov(s, op_index, gen_args, op, args[0], args[1]); tcg_opt_gen_mov(s, op, args, opc, args[0], args[1]);
gen_args += 2;
args += 2;
break; break;
} }
/* Source argument is constant. Rewrite the operation and /* Source argument is constant. Rewrite the operation and
@ -1020,9 +992,7 @@ static TCGArg *tcg_constant_folding(TCGContext *s, uint16_t *tcg_opc_ptr,
args[1] = temps[args[1]].val; args[1] = temps[args[1]].val;
/* fallthrough */ /* fallthrough */
CASE_OP_32_64(movi): CASE_OP_32_64(movi):
tcg_opt_gen_movi(s, op_index, gen_args, op, args[0], args[1]); tcg_opt_gen_movi(s, op, args, opc, args[0], args[1]);
gen_args += 2;
args += 2;
break; break;
CASE_OP_32_64(not): CASE_OP_32_64(not):
@ -1034,20 +1004,16 @@ static TCGArg *tcg_constant_folding(TCGContext *s, uint16_t *tcg_opc_ptr,
case INDEX_op_ext32s_i64: case INDEX_op_ext32s_i64:
case INDEX_op_ext32u_i64: case INDEX_op_ext32u_i64:
if (temps[args[1]].state == TCG_TEMP_CONST) { if (temps[args[1]].state == TCG_TEMP_CONST) {
tmp = do_constant_folding(s, op, temps[args[1]].val, 0); tmp = do_constant_folding(s, opc, temps[args[1]].val, 0);
tcg_opt_gen_movi(s, op_index, gen_args, op, args[0], tmp); tcg_opt_gen_movi(s, op, args, opc, args[0], tmp);
gen_args += 2;
args += 2;
break; break;
} }
goto do_default; goto do_default;
case INDEX_op_trunc_shr_i32: case INDEX_op_trunc_shr_i32:
if (temps[args[1]].state == TCG_TEMP_CONST) { if (temps[args[1]].state == TCG_TEMP_CONST) {
tmp = do_constant_folding(s, op, temps[args[1]].val, args[2]); tmp = do_constant_folding(s, opc, temps[args[1]].val, args[2]);
tcg_opt_gen_movi(s, op_index, gen_args, op, args[0], tmp); tcg_opt_gen_movi(s, op, args, opc, args[0], tmp);
gen_args += 2;
args += 3;
break; break;
} }
goto do_default; goto do_default;
@ -1076,11 +1042,9 @@ static TCGArg *tcg_constant_folding(TCGContext *s, uint16_t *tcg_opc_ptr,
CASE_OP_32_64(remu): CASE_OP_32_64(remu):
if (temps[args[1]].state == TCG_TEMP_CONST if (temps[args[1]].state == TCG_TEMP_CONST
&& temps[args[2]].state == TCG_TEMP_CONST) { && temps[args[2]].state == TCG_TEMP_CONST) {
tmp = do_constant_folding(s, op, temps[args[1]].val, tmp = do_constant_folding(s, opc, temps[args[1]].val,
temps[args[2]].val); temps[args[2]].val);
tcg_opt_gen_movi(s, op_index, gen_args, op, args[0], tmp); tcg_opt_gen_movi(s, op, args, opc, args[0], tmp);
gen_args += 2;
args += 3;
break; break;
} }
goto do_default; goto do_default;
@ -1090,54 +1054,44 @@ static TCGArg *tcg_constant_folding(TCGContext *s, uint16_t *tcg_opc_ptr,
&& temps[args[2]].state == TCG_TEMP_CONST) { && temps[args[2]].state == TCG_TEMP_CONST) {
tmp = (TCGArg)deposit64(temps[args[1]].val, args[3], args[4], tmp = (TCGArg)deposit64(temps[args[1]].val, args[3], args[4],
temps[args[2]].val); temps[args[2]].val);
tcg_opt_gen_movi(s, op_index, gen_args, op, args[0], tmp); tcg_opt_gen_movi(s, op, args, opc, args[0], tmp);
gen_args += 2;
args += 5;
break; break;
} }
goto do_default; goto do_default;
CASE_OP_32_64(setcond): CASE_OP_32_64(setcond):
tmp = do_constant_folding_cond(s, op, args[1], args[2], args[3]); tmp = do_constant_folding_cond(s, opc, args[1], args[2], args[3]);
if (tmp != 2) { if (tmp != 2) {
tcg_opt_gen_movi(s, op_index, gen_args, op, args[0], tmp); tcg_opt_gen_movi(s, op, args, opc, args[0], tmp);
gen_args += 2;
args += 4;
break; break;
} }
goto do_default; goto do_default;
CASE_OP_32_64(brcond): CASE_OP_32_64(brcond):
tmp = do_constant_folding_cond(s, op, args[0], args[1], args[2]); tmp = do_constant_folding_cond(s, opc, args[0], args[1], args[2]);
if (tmp != 2) { if (tmp != 2) {
if (tmp) { if (tmp) {
reset_all_temps(s, nb_temps); reset_all_temps(s, nb_temps);
s->gen_opc_buf[op_index] = INDEX_op_br; op->opc = INDEX_op_br;
gen_args[0] = args[3]; args[0] = args[3];
gen_args += 1;
} else { } else {
s->gen_opc_buf[op_index] = INDEX_op_nop; op->opc = INDEX_op_nop;
} }
args += 4;
break; break;
} }
goto do_default; goto do_default;
CASE_OP_32_64(movcond): CASE_OP_32_64(movcond):
tmp = do_constant_folding_cond(s, op, args[1], args[2], args[5]); tmp = do_constant_folding_cond(s, opc, args[1], args[2], args[5]);
if (tmp != 2) { if (tmp != 2) {
if (temps_are_copies(s, args[0], args[4-tmp])) { if (temps_are_copies(s, args[0], args[4-tmp])) {
s->gen_opc_buf[op_index] = INDEX_op_nop; op->opc = INDEX_op_nop;
} else if (temps[args[4-tmp]].state == TCG_TEMP_CONST) { } else if (temps[args[4-tmp]].state == TCG_TEMP_CONST) {
tcg_opt_gen_movi(s, op_index, gen_args, op, tcg_opt_gen_movi(s, op, args, opc,
args[0], temps[args[4-tmp]].val); args[0], temps[args[4-tmp]].val);
gen_args += 2;
} else { } else {
tcg_opt_gen_mov(s, op_index, gen_args, op, tcg_opt_gen_mov(s, op, args, opc, args[0], args[4-tmp]);
args[0], args[4-tmp]);
gen_args += 2;
} }
args += 6;
break; break;
} }
goto do_default; goto do_default;
@ -1155,24 +1109,31 @@ static TCGArg *tcg_constant_folding(TCGContext *s, uint16_t *tcg_opc_ptr,
uint64_t a = ((uint64_t)ah << 32) | al; uint64_t a = ((uint64_t)ah << 32) | al;
uint64_t b = ((uint64_t)bh << 32) | bl; uint64_t b = ((uint64_t)bh << 32) | bl;
TCGArg rl, rh; TCGArg rl, rh;
TCGOp *op2;
TCGArg *args2;
if (op == INDEX_op_add2_i32) { if (opc == INDEX_op_add2_i32) {
a += b; a += b;
} else { } else {
a -= b; a -= b;
} }
/* We emit the extra nop when we emit the add2/sub2. */ /* We emit the extra nop when we emit the add2/sub2. */
assert(s->gen_opc_buf[op_index + 1] == INDEX_op_nop); op2 = &s->gen_op_buf[oi_next];
assert(op2->opc == INDEX_op_nop);
/* But we still have to allocate args for the op. */
op2->args = s->gen_next_parm_idx;
s->gen_next_parm_idx += 2;
args2 = &s->gen_opparam_buf[op2->args];
rl = args[0]; rl = args[0];
rh = args[1]; rh = args[1];
tcg_opt_gen_movi(s, op_index, &gen_args[0], tcg_opt_gen_movi(s, op, args, opc, rl, (uint32_t)a);
op, rl, (uint32_t)a); tcg_opt_gen_movi(s, op2, args2, opc, rh, (uint32_t)(a >> 32));
tcg_opt_gen_movi(s, ++op_index, &gen_args[2],
op, rh, (uint32_t)(a >> 32)); /* We've done all we need to do with the movi. Skip it. */
gen_args += 4; oi_next = op2->next;
args += 6;
break; break;
} }
goto do_default; goto do_default;
@ -1184,18 +1145,25 @@ static TCGArg *tcg_constant_folding(TCGContext *s, uint16_t *tcg_opc_ptr,
uint32_t b = temps[args[3]].val; uint32_t b = temps[args[3]].val;
uint64_t r = (uint64_t)a * b; uint64_t r = (uint64_t)a * b;
TCGArg rl, rh; TCGArg rl, rh;
TCGOp *op2;
TCGArg *args2;
/* We emit the extra nop when we emit the mulu2. */ /* We emit the extra nop when we emit the mulu2. */
assert(s->gen_opc_buf[op_index + 1] == INDEX_op_nop); op2 = &s->gen_op_buf[oi_next];
assert(op2->opc == INDEX_op_nop);
/* But we still have to allocate args for the op. */
op2->args = s->gen_next_parm_idx;
s->gen_next_parm_idx += 2;
args2 = &s->gen_opparam_buf[op2->args];
rl = args[0]; rl = args[0];
rh = args[1]; rh = args[1];
tcg_opt_gen_movi(s, op_index, &gen_args[0], tcg_opt_gen_movi(s, op, args, opc, rl, (uint32_t)r);
op, rl, (uint32_t)r); tcg_opt_gen_movi(s, op2, args2, opc, rh, (uint32_t)(r >> 32));
tcg_opt_gen_movi(s, ++op_index, &gen_args[2],
op, rh, (uint32_t)(r >> 32)); /* We've done all we need to do with the movi. Skip it. */
gen_args += 4; oi_next = op2->next;
args += 4;
break; break;
} }
goto do_default; goto do_default;
@ -1206,12 +1174,11 @@ static TCGArg *tcg_constant_folding(TCGContext *s, uint16_t *tcg_opc_ptr,
if (tmp) { if (tmp) {
do_brcond_true: do_brcond_true:
reset_all_temps(s, nb_temps); reset_all_temps(s, nb_temps);
s->gen_opc_buf[op_index] = INDEX_op_br; op->opc = INDEX_op_br;
gen_args[0] = args[5]; args[0] = args[5];
gen_args += 1;
} else { } else {
do_brcond_false: do_brcond_false:
s->gen_opc_buf[op_index] = INDEX_op_nop; op->opc = INDEX_op_nop;
} }
} else if ((args[4] == TCG_COND_LT || args[4] == TCG_COND_GE) } else if ((args[4] == TCG_COND_LT || args[4] == TCG_COND_GE)
&& temps[args[2]].state == TCG_TEMP_CONST && temps[args[2]].state == TCG_TEMP_CONST
@ -1222,12 +1189,11 @@ static TCGArg *tcg_constant_folding(TCGContext *s, uint16_t *tcg_opc_ptr,
vs the high word of the input. */ vs the high word of the input. */
do_brcond_high: do_brcond_high:
reset_all_temps(s, nb_temps); reset_all_temps(s, nb_temps);
s->gen_opc_buf[op_index] = INDEX_op_brcond_i32; op->opc = INDEX_op_brcond_i32;
gen_args[0] = args[1]; args[0] = args[1];
gen_args[1] = args[3]; args[1] = args[3];
gen_args[2] = args[4]; args[2] = args[4];
gen_args[3] = args[5]; args[3] = args[5];
gen_args += 4;
} else if (args[4] == TCG_COND_EQ) { } else if (args[4] == TCG_COND_EQ) {
/* Simplify EQ comparisons where one of the pairs /* Simplify EQ comparisons where one of the pairs
can be simplified. */ can be simplified. */
@ -1247,12 +1213,10 @@ static TCGArg *tcg_constant_folding(TCGContext *s, uint16_t *tcg_opc_ptr,
} }
do_brcond_low: do_brcond_low:
reset_all_temps(s, nb_temps); reset_all_temps(s, nb_temps);
s->gen_opc_buf[op_index] = INDEX_op_brcond_i32; op->opc = INDEX_op_brcond_i32;
gen_args[0] = args[0]; args[1] = args[2];
gen_args[1] = args[2]; args[2] = args[4];
gen_args[2] = args[4]; args[3] = args[5];
gen_args[3] = args[5];
gen_args += 4;
} else if (args[4] == TCG_COND_NE) { } else if (args[4] == TCG_COND_NE) {
/* Simplify NE comparisons where one of the pairs /* Simplify NE comparisons where one of the pairs
can be simplified. */ can be simplified. */
@ -1274,15 +1238,13 @@ static TCGArg *tcg_constant_folding(TCGContext *s, uint16_t *tcg_opc_ptr,
} else { } else {
goto do_default; goto do_default;
} }
args += 6;
break; break;
case INDEX_op_setcond2_i32: case INDEX_op_setcond2_i32:
tmp = do_constant_folding_cond2(s, &args[1], &args[3], args[5]); tmp = do_constant_folding_cond2(s, &args[1], &args[3], args[5]);
if (tmp != 2) { if (tmp != 2) {
do_setcond_const: do_setcond_const:
tcg_opt_gen_movi(s, op_index, gen_args, op, args[0], tmp); tcg_opt_gen_movi(s, op, args, opc, args[0], tmp);
gen_args += 2;
} else if ((args[5] == TCG_COND_LT || args[5] == TCG_COND_GE) } else if ((args[5] == TCG_COND_LT || args[5] == TCG_COND_GE)
&& temps[args[3]].state == TCG_TEMP_CONST && temps[args[3]].state == TCG_TEMP_CONST
&& temps[args[4]].state == TCG_TEMP_CONST && temps[args[4]].state == TCG_TEMP_CONST
@ -1291,14 +1253,12 @@ static TCGArg *tcg_constant_folding(TCGContext *s, uint16_t *tcg_opc_ptr,
/* Simplify LT/GE comparisons vs zero to a single compare /* Simplify LT/GE comparisons vs zero to a single compare
vs the high word of the input. */ vs the high word of the input. */
do_setcond_high: do_setcond_high:
s->gen_opc_buf[op_index] = INDEX_op_setcond_i32;
reset_temp(s, args[0]); reset_temp(s, args[0]);
temps[args[0]].mask = 1; temps[args[0]].mask = 1;
gen_args[0] = args[0]; op->opc = INDEX_op_setcond_i32;
gen_args[1] = args[2]; args[1] = args[2];
gen_args[2] = args[4]; args[2] = args[4];
gen_args[3] = args[5]; args[3] = args[5];
gen_args += 4;
} else if (args[5] == TCG_COND_EQ) { } else if (args[5] == TCG_COND_EQ) {
/* Simplify EQ comparisons where one of the pairs /* Simplify EQ comparisons where one of the pairs
can be simplified. */ can be simplified. */
@ -1319,12 +1279,9 @@ static TCGArg *tcg_constant_folding(TCGContext *s, uint16_t *tcg_opc_ptr,
do_setcond_low: do_setcond_low:
reset_temp(s, args[0]); reset_temp(s, args[0]);
temps[args[0]].mask = 1; temps[args[0]].mask = 1;
s->gen_opc_buf[op_index] = INDEX_op_setcond_i32; op->opc = INDEX_op_setcond_i32;
gen_args[0] = args[0]; args[2] = args[3];
gen_args[1] = args[1]; args[3] = args[5];
gen_args[2] = args[3];
gen_args[3] = args[5];
gen_args += 4;
} else if (args[5] == TCG_COND_NE) { } else if (args[5] == TCG_COND_NE) {
/* Simplify NE comparisons where one of the pairs /* Simplify NE comparisons where one of the pairs
can be simplified. */ can be simplified. */
@ -1346,7 +1303,6 @@ static TCGArg *tcg_constant_folding(TCGContext *s, uint16_t *tcg_opc_ptr,
} else { } else {
goto do_default; goto do_default;
} }
args += 6;
break; break;
case INDEX_op_call: case INDEX_op_call:
@ -1378,22 +1334,12 @@ static TCGArg *tcg_constant_folding(TCGContext *s, uint16_t *tcg_opc_ptr,
} }
} }
} }
for (i = 0; i < nb_args; i++) {
gen_args[i] = args[i];
}
args += nb_args;
gen_args += nb_args;
break; break;
} }
} }
return gen_args;
} }
TCGArg *tcg_optimize(TCGContext *s, uint16_t *tcg_opc_ptr, void tcg_optimize(TCGContext *s)
TCGArg *args, TCGOpDef *tcg_op_defs)
{ {
TCGArg *res; tcg_constant_folding(s);
res = tcg_constant_folding(s, tcg_opc_ptr, args, tcg_op_defs);
return res;
} }

View file

@ -35,100 +35,117 @@ extern TCGv_i32 TCGV_HIGH_link_error(TCGv_i64);
#define TCGV_HIGH TCGV_HIGH_link_error #define TCGV_HIGH TCGV_HIGH_link_error
#endif #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;
TCGOp op = {0};
tcg_debug_assert(oi < OPC_BUF_SIZE);
ctx->gen_last_op_idx = oi;
ctx->gen_next_op_idx = ni;
op.opc = opc;
op.args = args;
op.prev = pi;
op.next = ni;
ctx->gen_op_buf[oi] = op;
}
void tcg_gen_op0(TCGContext *ctx, TCGOpcode opc) 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) void tcg_gen_op1(TCGContext *ctx, TCGOpcode opc, TCGArg a1)
{ {
uint16_t *op = ctx->gen_opc_ptr; int pi = ctx->gen_next_parm_idx;
TCGArg *opp = ctx->gen_opparam_ptr;
op[0] = opc; tcg_debug_assert(pi + 1 <= OPPARAM_BUF_SIZE);
opp[0] = a1; ctx->gen_next_parm_idx = pi + 1;
ctx->gen_opparam_buf[pi] = a1;
ctx->gen_opc_ptr = op + 1; tcg_emit_op(ctx, opc, pi);
ctx->gen_opparam_ptr = opp + 1;
} }
void tcg_gen_op2(TCGContext *ctx, TCGOpcode opc, TCGArg a1, TCGArg a2) void tcg_gen_op2(TCGContext *ctx, TCGOpcode opc, TCGArg a1, TCGArg a2)
{ {
uint16_t *op = ctx->gen_opc_ptr; int pi = ctx->gen_next_parm_idx;
TCGArg *opp = ctx->gen_opparam_ptr;
op[0] = opc; tcg_debug_assert(pi + 2 <= OPPARAM_BUF_SIZE);
opp[0] = a1; ctx->gen_next_parm_idx = pi + 2;
opp[1] = a2; ctx->gen_opparam_buf[pi + 0] = a1;
ctx->gen_opparam_buf[pi + 1] = a2;
ctx->gen_opc_ptr = op + 1; tcg_emit_op(ctx, opc, pi);
ctx->gen_opparam_ptr = opp + 2;
} }
void tcg_gen_op3(TCGContext *ctx, TCGOpcode opc, TCGArg a1, void tcg_gen_op3(TCGContext *ctx, TCGOpcode opc, TCGArg a1,
TCGArg a2, TCGArg a3) TCGArg a2, TCGArg a3)
{ {
uint16_t *op = ctx->gen_opc_ptr; int pi = ctx->gen_next_parm_idx;
TCGArg *opp = ctx->gen_opparam_ptr;
op[0] = opc; tcg_debug_assert(pi + 3 <= OPPARAM_BUF_SIZE);
opp[0] = a1; ctx->gen_next_parm_idx = pi + 3;
opp[1] = a2; ctx->gen_opparam_buf[pi + 0] = a1;
opp[2] = a3; ctx->gen_opparam_buf[pi + 1] = a2;
ctx->gen_opparam_buf[pi + 2] = a3;
ctx->gen_opc_ptr = op + 1; tcg_emit_op(ctx, opc, pi);
ctx->gen_opparam_ptr = opp + 3;
} }
void tcg_gen_op4(TCGContext *ctx, TCGOpcode opc, TCGArg a1, void tcg_gen_op4(TCGContext *ctx, TCGOpcode opc, TCGArg a1,
TCGArg a2, TCGArg a3, TCGArg a4) TCGArg a2, TCGArg a3, TCGArg a4)
{ {
uint16_t *op = ctx->gen_opc_ptr; int pi = ctx->gen_next_parm_idx;
TCGArg *opp = ctx->gen_opparam_ptr;
op[0] = opc; tcg_debug_assert(pi + 4 <= OPPARAM_BUF_SIZE);
opp[0] = a1; ctx->gen_next_parm_idx = pi + 4;
opp[1] = a2; ctx->gen_opparam_buf[pi + 0] = a1;
opp[2] = a3; ctx->gen_opparam_buf[pi + 1] = a2;
opp[3] = a4; ctx->gen_opparam_buf[pi + 2] = a3;
ctx->gen_opparam_buf[pi + 3] = a4;
ctx->gen_opc_ptr = op + 1; tcg_emit_op(ctx, opc, pi);
ctx->gen_opparam_ptr = opp + 4;
} }
void tcg_gen_op5(TCGContext *ctx, TCGOpcode opc, TCGArg a1, void tcg_gen_op5(TCGContext *ctx, TCGOpcode opc, TCGArg a1,
TCGArg a2, TCGArg a3, TCGArg a4, TCGArg a5) TCGArg a2, TCGArg a3, TCGArg a4, TCGArg a5)
{ {
uint16_t *op = ctx->gen_opc_ptr; int pi = ctx->gen_next_parm_idx;
TCGArg *opp = ctx->gen_opparam_ptr;
op[0] = opc; tcg_debug_assert(pi + 5 <= OPPARAM_BUF_SIZE);
opp[0] = a1; ctx->gen_next_parm_idx = pi + 5;
opp[1] = a2; ctx->gen_opparam_buf[pi + 0] = a1;
opp[2] = a3; ctx->gen_opparam_buf[pi + 1] = a2;
opp[3] = a4; ctx->gen_opparam_buf[pi + 2] = a3;
opp[4] = a5; ctx->gen_opparam_buf[pi + 3] = a4;
ctx->gen_opparam_buf[pi + 4] = a5;
ctx->gen_opc_ptr = op + 1; tcg_emit_op(ctx, opc, pi);
ctx->gen_opparam_ptr = opp + 5;
} }
void tcg_gen_op6(TCGContext *ctx, TCGOpcode opc, TCGArg a1, TCGArg a2, void tcg_gen_op6(TCGContext *ctx, TCGOpcode opc, TCGArg a1, TCGArg a2,
TCGArg a3, TCGArg a4, TCGArg a5, TCGArg a6) TCGArg a3, TCGArg a4, TCGArg a5, TCGArg a6)
{ {
uint16_t *op = ctx->gen_opc_ptr; int pi = ctx->gen_next_parm_idx;
TCGArg *opp = ctx->gen_opparam_ptr;
op[0] = opc; tcg_debug_assert(pi + 6 <= OPPARAM_BUF_SIZE);
opp[0] = a1; ctx->gen_next_parm_idx = pi + 6;
opp[1] = a2; ctx->gen_opparam_buf[pi + 0] = a1;
opp[2] = a3; ctx->gen_opparam_buf[pi + 1] = a2;
opp[3] = a4; ctx->gen_opparam_buf[pi + 2] = a3;
opp[4] = a5; ctx->gen_opparam_buf[pi + 3] = a4;
opp[5] = a6; ctx->gen_opparam_buf[pi + 4] = a5;
ctx->gen_opparam_buf[pi + 5] = a6;
ctx->gen_opc_ptr = op + 1; tcg_emit_op(ctx, opc, pi);
ctx->gen_opparam_ptr = opp + 6;
} }
/* 32 bit ops */ /* 32 bit ops */
@ -1862,26 +1879,42 @@ static inline TCGMemOp tcg_canonicalize_memop(TCGMemOp op, bool is64, bool st)
return op; return op;
} }
static inline void tcg_add_param_i32(TCGContext *tcg_ctx, TCGv_i32 val) static void gen_ldst_i32(TCGContext *s, 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(TCGContext *tcg_ctx, 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 #if TARGET_LONG_BITS == 32
# define tcg_add_param_tl tcg_add_param_i32 tcg_gen_op4ii_i32(s, opc, val, addr, memop, idx);
#else #else
# define tcg_add_param_tl tcg_add_param_i64 if (TCG_TARGET_REG_BITS == 32) {
tcg_gen_op5ii_i32(s, opc, val, TCGV_LOW(addr), TCGV_HIGH(addr),
memop, idx);
} else {
tcg_gen_op4(s, opc, GET_TCGV_I32(val), GET_TCGV_I64(addr),
memop, idx);
}
#endif #endif
}
static void gen_ldst_i64(TCGContext *s, 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(s, opc, TCGV_LOW(val), TCGV_HIGH(val),
addr, memop, idx);
} else {
tcg_gen_op4(s, opc, GET_TCGV_I64(val), GET_TCGV_I32(addr),
memop, idx);
}
#else
if (TCG_TARGET_REG_BITS == 32) {
tcg_gen_op6ii_i32(s, opc, TCGV_LOW(val), TCGV_HIGH(val),
TCGV_LOW(addr), TCGV_HIGH(addr), memop, idx);
} else {
tcg_gen_op4ii_i64(s, opc, val, addr, memop, idx);
}
#endif
}
// Unicorn engine // Unicorn engine
// check if the last memory access was invalid // check if the last memory access was invalid
@ -1902,13 +1935,7 @@ void tcg_gen_qemu_ld_i32(struct uc_struct *uc, TCGv_i32 val, TCGv addr, TCGArg i
TCGContext *tcg_ctx = uc->tcg_ctx; TCGContext *tcg_ctx = uc->tcg_ctx;
memop = tcg_canonicalize_memop(memop, 0, 0); memop = tcg_canonicalize_memop(memop, 0, 0);
gen_ldst_i32(tcg_ctx, INDEX_op_qemu_ld_i32, val, addr, memop, idx);
*tcg_ctx->gen_opc_ptr++ = INDEX_op_qemu_ld_i32;
tcg_add_param_i32(tcg_ctx, val);
tcg_add_param_tl(tcg_ctx, addr);
*tcg_ctx->gen_opparam_ptr++ = memop;
*tcg_ctx->gen_opparam_ptr++ = idx;
check_exit_request(tcg_ctx); check_exit_request(tcg_ctx);
} }
@ -1917,13 +1944,7 @@ void tcg_gen_qemu_st_i32(struct uc_struct *uc, TCGv_i32 val, TCGv addr, TCGArg i
TCGContext *tcg_ctx = uc->tcg_ctx; TCGContext *tcg_ctx = uc->tcg_ctx;
memop = tcg_canonicalize_memop(memop, 0, 1); memop = tcg_canonicalize_memop(memop, 0, 1);
gen_ldst_i32(tcg_ctx, INDEX_op_qemu_st_i32, val, addr, memop, idx);
*tcg_ctx->gen_opc_ptr++ = INDEX_op_qemu_st_i32;
tcg_add_param_i32(tcg_ctx, val);
tcg_add_param_tl(tcg_ctx, addr);
*tcg_ctx->gen_opparam_ptr++ = memop;
*tcg_ctx->gen_opparam_ptr++ = idx;
check_exit_request(tcg_ctx); check_exit_request(tcg_ctx);
} }
@ -1931,8 +1952,6 @@ void tcg_gen_qemu_ld_i64(struct uc_struct *uc, TCGv_i64 val, TCGv addr, TCGArg i
{ {
TCGContext *tcg_ctx = uc->tcg_ctx; TCGContext *tcg_ctx = uc->tcg_ctx;
memop = tcg_canonicalize_memop(memop, 1, 0);
if (TCG_TARGET_REG_BITS == 32 && (memop & MO_SIZE) < MO_64) { if (TCG_TARGET_REG_BITS == 32 && (memop & MO_SIZE) < MO_64) {
tcg_gen_qemu_ld_i32(uc, TCGV_LOW(val), addr, idx, memop); tcg_gen_qemu_ld_i32(uc, TCGV_LOW(val), addr, idx, memop);
if (memop & MO_SIGN) { if (memop & MO_SIGN) {
@ -1945,12 +1964,8 @@ void tcg_gen_qemu_ld_i64(struct uc_struct *uc, TCGv_i64 val, TCGv addr, TCGArg i
return; return;
} }
*tcg_ctx->gen_opc_ptr++ = INDEX_op_qemu_ld_i64; memop = tcg_canonicalize_memop(memop, 1, 0);
tcg_add_param_i64(tcg_ctx, val); gen_ldst_i64(tcg_ctx, INDEX_op_qemu_ld_i64, val, addr, memop, idx);
tcg_add_param_tl(tcg_ctx, addr);
*tcg_ctx->gen_opparam_ptr++ = memop;
*tcg_ctx->gen_opparam_ptr++ = idx;
check_exit_request(tcg_ctx); check_exit_request(tcg_ctx);
} }
@ -1958,19 +1973,13 @@ void tcg_gen_qemu_st_i64(struct uc_struct *uc, TCGv_i64 val, TCGv addr, TCGArg i
{ {
TCGContext *tcg_ctx = uc->tcg_ctx; TCGContext *tcg_ctx = uc->tcg_ctx;
memop = tcg_canonicalize_memop(memop, 1, 1);
if (TCG_TARGET_REG_BITS == 32 && (memop & MO_SIZE) < MO_64) { if (TCG_TARGET_REG_BITS == 32 && (memop & MO_SIZE) < MO_64) {
tcg_gen_qemu_st_i32(uc, TCGV_LOW(val), addr, idx, memop); tcg_gen_qemu_st_i32(uc, TCGV_LOW(val), addr, idx, memop);
check_exit_request(tcg_ctx); check_exit_request(tcg_ctx);
return; return;
} }
*tcg_ctx->gen_opc_ptr++ = INDEX_op_qemu_st_i64; memop = tcg_canonicalize_memop(memop, 1, 1);
tcg_add_param_i64(tcg_ctx, val); gen_ldst_i64(tcg_ctx, INDEX_op_qemu_st_i64, val, addr, memop, idx);
tcg_add_param_tl(tcg_ctx, addr);
*tcg_ctx->gen_opparam_ptr++ = memop;
*tcg_ctx->gen_opparam_ptr++ = idx;
check_exit_request(tcg_ctx); check_exit_request(tcg_ctx);
} }

View file

@ -395,7 +395,6 @@ void tcg_func_start(TCGContext *s)
/* No temps have been previously allocated for size or locality. */ /* No temps have been previously allocated for size or locality. */
memset(s->free_temps, 0, sizeof(s->free_temps)); memset(s->free_temps, 0, sizeof(s->free_temps));
s->labels = tcg_malloc(s, sizeof(TCGLabel) * TCG_MAX_LABELS);
s->nb_labels = 0; s->nb_labels = 0;
s->current_frame_offset = s->frame_start; s->current_frame_offset = s->frame_start;
@ -403,8 +402,10 @@ void tcg_func_start(TCGContext *s)
s->goto_tb_issue_mask = 0; s->goto_tb_issue_mask = 0;
#endif #endif
s->gen_opc_ptr = s->gen_opc_buf; s->gen_first_op_idx = 0;
s->gen_opparam_ptr = s->gen_opparam_buf; s->gen_last_op_idx = -1;
s->gen_next_op_idx = 0;
s->gen_next_parm_idx = 0;
s->be = tcg_malloc(s, sizeof(TCGBackendData)); s->be = tcg_malloc(s, sizeof(TCGBackendData));
} }
@ -686,9 +687,8 @@ int tcg_check_temp_count(TCGContext *s)
void tcg_gen_callN(TCGContext *s, void *func, TCGArg ret, void tcg_gen_callN(TCGContext *s, void *func, TCGArg ret,
int nargs, TCGArg *args) int nargs, TCGArg *args)
{ {
int i, real_args, nb_rets; int i, real_args, nb_rets, pi, pi_first;
unsigned sizemask, flags; unsigned sizemask, flags;
TCGArg *nparam;
TCGHelperInfo *info; TCGHelperInfo *info;
info = g_hash_table_lookup(s->helpers, (gpointer)func); info = g_hash_table_lookup(s->helpers, (gpointer)func);
@ -741,8 +741,7 @@ void tcg_gen_callN(TCGContext *s, void *func, TCGArg ret,
} }
#endif /* TCG_TARGET_EXTEND_ARGS */ #endif /* TCG_TARGET_EXTEND_ARGS */
*s->gen_opc_ptr++ = INDEX_op_call; pi_first = pi = s->gen_next_parm_idx;
nparam = s->gen_opparam_ptr++;
if (ret != TCG_CALL_DUMMY_ARG) { if (ret != TCG_CALL_DUMMY_ARG) {
#if defined(__sparc__) && !defined(__arch64__) \ #if defined(__sparc__) && !defined(__arch64__) \
&& !defined(CONFIG_TCG_INTERPRETER) && !defined(CONFIG_TCG_INTERPRETER)
@ -752,25 +751,25 @@ void tcg_gen_callN(TCGContext *s, void *func, TCGArg ret,
two return temporaries, and reassemble below. */ two return temporaries, and reassemble below. */
retl = tcg_temp_new_i64(s); retl = tcg_temp_new_i64(s);
reth = tcg_temp_new_i64(s); reth = tcg_temp_new_i64(s);
*s->gen_opparam_ptr++ = GET_TCGV_I64(reth); s->gen_opparam_buf[pi++] = GET_TCGV_I64(reth);
*s->gen_opparam_ptr++ = GET_TCGV_I64(retl); s->gen_opparam_buf[pi++] = GET_TCGV_I64(retl);
nb_rets = 2; nb_rets = 2;
} else { } else {
*s->gen_opparam_ptr++ = ret; s->gen_opparam_buf[pi++] = ret;
nb_rets = 1; nb_rets = 1;
} }
#else #else
if (TCG_TARGET_REG_BITS < 64 && (sizemask & 1)) { if (TCG_TARGET_REG_BITS < 64 && (sizemask & 1)) {
#ifdef HOST_WORDS_BIGENDIAN #ifdef HOST_WORDS_BIGENDIAN
*s->gen_opparam_ptr++ = ret + 1; s->gen_opparam_buf[pi++] = ret + 1;
*s->gen_opparam_ptr++ = ret; s->gen_opparam_buf[pi++] = ret;
#else #else
*s->gen_opparam_ptr++ = ret; s->gen_opparam_buf[pi++] = ret;
*s->gen_opparam_ptr++ = ret + 1; s->gen_opparam_buf[pi++] = ret + 1;
#endif #endif
nb_rets = 2; nb_rets = 2;
} else { } else {
*s->gen_opparam_ptr++ = ret; s->gen_opparam_buf[pi++] = ret;
nb_rets = 1; nb_rets = 1;
} }
#endif #endif
@ -784,7 +783,7 @@ void tcg_gen_callN(TCGContext *s, void *func, TCGArg ret,
#ifdef TCG_TARGET_CALL_ALIGN_ARGS #ifdef TCG_TARGET_CALL_ALIGN_ARGS
/* some targets want aligned 64 bit args */ /* some targets want aligned 64 bit args */
if (real_args & 1) { if (real_args & 1) {
*s->gen_opparam_ptr++ = TCG_CALL_DUMMY_ARG; s->gen_opparam_buf[pi++] = TCG_CALL_DUMMY_ARG;
real_args++; real_args++;
} }
#endif #endif
@ -799,26 +798,42 @@ void tcg_gen_callN(TCGContext *s, void *func, TCGArg ret,
have to get more complicated to differentiate between have to get more complicated to differentiate between
stack arguments and register arguments. */ stack arguments and register arguments. */
#if defined(HOST_WORDS_BIGENDIAN) != defined(TCG_TARGET_STACK_GROWSUP) #if defined(HOST_WORDS_BIGENDIAN) != defined(TCG_TARGET_STACK_GROWSUP)
*s->gen_opparam_ptr++ = args[i] + 1; s->gen_opparam_buf[pi++] = args[i] + 1;
*s->gen_opparam_ptr++ = args[i]; s->gen_opparam_buf[pi++] = args[i];
#else #else
*s->gen_opparam_ptr++ = args[i]; s->gen_opparam_buf[pi++] = args[i];
*s->gen_opparam_ptr++ = args[i] + 1; s->gen_opparam_buf[pi++] = args[i] + 1;
#endif #endif
real_args += 2; real_args += 2;
continue; continue;
} }
*s->gen_opparam_ptr++ = args[i]; s->gen_opparam_buf[pi++] = args[i];
real_args++; real_args++;
} }
*s->gen_opparam_ptr++ = (uintptr_t)func; s->gen_opparam_buf[pi++] = (uintptr_t)func;
*s->gen_opparam_ptr++ = flags; s->gen_opparam_buf[pi++] = flags;
*nparam = (nb_rets << 16) | real_args; i = s->gen_next_op_idx;
tcg_debug_assert(i < OPC_BUF_SIZE);
tcg_debug_assert(pi <= OPPARAM_BUF_SIZE);
/* total parameters, needed to go backward in the instruction stream */ /* Set links for sequential allocation during translation. */
*s->gen_opparam_ptr++ = 1 + nb_rets + real_args + 3; TCGOp op = {0};
op.opc = INDEX_op_call;
op.callo = nb_rets;
op.calli = real_args;
op.args = pi_first;
op.prev = i - 1;
op.next = i + 1;
s->gen_op_buf[i] = op;
/* Make sure the calli field didn't overflow. */
tcg_debug_assert(s->gen_op_buf[i].calli == real_args);
s->gen_last_op_idx = i;
s->gen_next_op_idx = i + 1;
s->gen_next_parm_idx = pi;
#if defined(__sparc__) && !defined(__arch64__) \ #if defined(__sparc__) && !defined(__arch64__) \
&& !defined(CONFIG_TCG_INTERPRETER) && !defined(CONFIG_TCG_INTERPRETER)
@ -1012,20 +1027,21 @@ static const char * const ldst_name[] =
void tcg_dump_ops(TCGContext *s) void tcg_dump_ops(TCGContext *s)
{ {
const uint16_t *opc_ptr;
const TCGArg *args;
TCGArg arg;
TCGOpcode c;
int i, k, nb_oargs, nb_iargs, nb_cargs, first_insn;
const TCGOpDef *def;
char buf[128]; char buf[128];
TCGOp *op;
int oi;
first_insn = 1; for (oi = s->gen_first_op_idx; oi >= 0; oi = op->next) {
opc_ptr = s->gen_opc_buf; int i, k, nb_oargs, nb_iargs, nb_cargs;
args = s->gen_opparam_buf; const TCGOpDef *def;
while (opc_ptr < s->gen_opc_ptr) { const TCGArg *args;
c = *opc_ptr++; TCGOpcode c;
op = &s->gen_op_buf[oi];
c = op->opc;
def = &s->tcg_op_defs[c]; def = &s->tcg_op_defs[c];
args = &s->gen_opparam_buf[op->args];
if (c == INDEX_op_debug_insn_start) { if (c == INDEX_op_debug_insn_start) {
uint64_t pc; uint64_t pc;
#if TARGET_LONG_BITS > TCG_TARGET_REG_BITS #if TARGET_LONG_BITS > TCG_TARGET_REG_BITS
@ -1033,21 +1049,14 @@ void tcg_dump_ops(TCGContext *s)
#else #else
pc = args[0]; pc = args[0];
#endif #endif
if (!first_insn) { if (oi != s->gen_first_op_idx) {
printf("\n"); printf("\n");
} }
printf(" ---- 0x%" PRIx64, pc); printf(" ---- 0x%" PRIx64, pc);
first_insn = 0;
nb_oargs = def->nb_oargs;
nb_iargs = def->nb_iargs;
nb_cargs = def->nb_cargs;
} else if (c == INDEX_op_call) { } else if (c == INDEX_op_call) {
TCGArg arg;
/* variable number of arguments */ /* variable number of arguments */
arg = *args++; nb_oargs = op->callo;
nb_oargs = arg >> 16; nb_iargs = op->calli;
nb_iargs = arg & 0xffff;
nb_cargs = def->nb_cargs; nb_cargs = def->nb_cargs;
/* function name, flags, out args */ /* function name, flags, out args */
@ -1068,26 +1077,20 @@ void tcg_dump_ops(TCGContext *s)
} }
} else { } else {
printf(" %s ", def->name); printf(" %s ", def->name);
if (c == INDEX_op_nopn) {
/* variable number of arguments */ nb_oargs = def->nb_oargs;
nb_cargs = *args; nb_iargs = def->nb_iargs;
nb_oargs = 0; nb_cargs = def->nb_cargs;
nb_iargs = 0;
} else {
nb_oargs = def->nb_oargs;
nb_iargs = def->nb_iargs;
nb_cargs = def->nb_cargs;
}
k = 0; k = 0;
for(i = 0; i < nb_oargs; i++) { for (i = 0; i < nb_oargs; i++) {
if (k != 0) { if (k != 0) {
printf(","); printf(",");
} }
printf("%s", tcg_get_arg_str_idx(s, buf, sizeof(buf), printf("%s", tcg_get_arg_str_idx(s, buf, sizeof(buf),
args[k++])); args[k++]));
} }
for(i = 0; i < nb_iargs; i++) { for (i = 0; i < nb_iargs; i++) {
if (k != 0) { if (k != 0) {
printf(","); printf(",");
} }
@ -1125,16 +1128,15 @@ void tcg_dump_ops(TCGContext *s)
i = 0; i = 0;
break; break;
} }
for(; i < nb_cargs; i++) { for (; i < nb_cargs; i++) {
if (k != 0) { if (k != 0) {
printf(","); printf(",");
} }
arg = args[k++];
printf("$0x%" TCG_PRIlx, arg); printf("$0x%" TCG_PRIlx, args[k++]);
} }
} }
printf("\n"); printf("\n");
args += nb_iargs + nb_oargs + nb_cargs;
} }
printf("###########\n"); printf("###########\n");
} }
@ -1286,19 +1288,6 @@ void tcg_add_target_add_op_defs(TCGContext *s, const TCGTargetOpDef *tdefs)
#ifdef USE_LIVENESS_ANALYSIS #ifdef USE_LIVENESS_ANALYSIS
/* set a nop for an operation using 'nb_args' */
static inline void tcg_set_nop(TCGContext *s, uint16_t *opc_ptr,
TCGArg *args, int nb_args)
{
if (nb_args == 0) {
*opc_ptr = INDEX_op_nop;
} else {
*opc_ptr = INDEX_op_nopn;
args[0] = nb_args;
args[nb_args - 1] = nb_args;
}
}
/* liveness analysis: end of function: all temps are dead, and globals /* liveness analysis: end of function: all temps are dead, and globals
should be in memory. */ should be in memory. */
static inline void tcg_la_func_end(TCGContext *s, uint8_t *dead_temps, static inline void tcg_la_func_end(TCGContext *s, uint8_t *dead_temps,
@ -1340,18 +1329,10 @@ static inline void tcg_la_br_end(TCGContext *s, uint8_t *mem_temps)
temporaries are removed. */ temporaries are removed. */
static void tcg_liveness_analysis(TCGContext *s) static void tcg_liveness_analysis(TCGContext *s)
{ {
int i, op_index, nb_args, nb_iargs, nb_oargs, nb_ops;
TCGOpcode op, op_new, op_new2;
TCGArg *args, arg;
const TCGOpDef *def;
uint8_t *dead_temps, *mem_temps; uint8_t *dead_temps, *mem_temps;
uint16_t dead_args; int oi, oi_prev, nb_ops;
uint8_t sync_args;
bool have_op_new2;
s->gen_opc_ptr++; /* skip end */ nb_ops = s->gen_next_op_idx;
nb_ops = s->gen_opc_ptr - s->gen_opc_buf;
s->op_dead_args = tcg_malloc(s, nb_ops * sizeof(uint16_t)); s->op_dead_args = tcg_malloc(s, nb_ops * sizeof(uint16_t));
s->op_sync_args = tcg_malloc(s, nb_ops * sizeof(uint8_t)); s->op_sync_args = tcg_malloc(s, nb_ops * sizeof(uint8_t));
@ -1360,25 +1341,31 @@ static void tcg_liveness_analysis(TCGContext *s)
mem_temps = tcg_malloc(s, s->nb_temps); mem_temps = tcg_malloc(s, s->nb_temps);
tcg_la_func_end(s, dead_temps, mem_temps); tcg_la_func_end(s, dead_temps, mem_temps);
args = s->gen_opparam_ptr; for (oi = s->gen_last_op_idx; oi >= 0; oi = oi_prev) {
op_index = nb_ops - 1; int i, nb_iargs, nb_oargs;
while (op_index >= 0) { TCGOpcode opc_new, opc_new2;
op = s->gen_opc_buf[op_index]; bool have_opc_new2;
def = &s->tcg_op_defs[op]; uint16_t dead_args;
switch(op) { uint8_t sync_args;
TCGArg arg;
TCGOp * const op = &s->gen_op_buf[oi];
TCGArg * const args = &s->gen_opparam_buf[op->args];
TCGOpcode opc = op->opc;
const TCGOpDef *def = &s->tcg_op_defs[opc];
oi_prev = op->prev;
switch(opc) {
case INDEX_op_call: case INDEX_op_call:
{ {
int call_flags; int call_flags;
nb_args = args[-1]; nb_oargs = op->callo;
args -= nb_args; nb_iargs = op->calli;
arg = *args++;
nb_iargs = arg & 0xffff;
nb_oargs = arg >> 16;
call_flags = args[nb_oargs + nb_iargs + 1]; call_flags = args[nb_oargs + nb_iargs + 1];
/* pure functions can be removed if their result is not /* pure functions can be removed if their result is unused */
used */
if (call_flags & TCG_CALL_NO_SIDE_EFFECTS) { if (call_flags & TCG_CALL_NO_SIDE_EFFECTS) {
for (i = 0; i < nb_oargs; i++) { for (i = 0; i < nb_oargs; i++) {
arg = args[i]; arg = args[i];
@ -1386,8 +1373,7 @@ static void tcg_liveness_analysis(TCGContext *s)
goto do_not_remove_call; goto do_not_remove_call;
} }
} }
tcg_set_nop(s, s->gen_opc_buf + op_index, goto do_remove;
args - 1, nb_args);
} else { } else {
do_not_remove_call: do_not_remove_call:
@ -1426,41 +1412,33 @@ static void tcg_liveness_analysis(TCGContext *s)
dead_temps[arg] = 0; dead_temps[arg] = 0;
} }
} }
s->op_dead_args[op_index] = dead_args; s->op_dead_args[oi] = dead_args;
s->op_sync_args[op_index] = sync_args; s->op_sync_args[oi] = sync_args;
} }
args--;
} }
break; break;
case INDEX_op_debug_insn_start: case INDEX_op_debug_insn_start:
args -= def->nb_args; case INDEX_op_nop:
break; case INDEX_op_end:
case INDEX_op_nopn:
nb_args = args[-1];
args -= nb_args;
break; break;
case INDEX_op_discard: case INDEX_op_discard:
args--;
/* mark the temporary as dead */ /* mark the temporary as dead */
dead_temps[args[0]] = 1; dead_temps[args[0]] = 1;
mem_temps[args[0]] = 0; mem_temps[args[0]] = 0;
break; break;
case INDEX_op_end:
break;
case INDEX_op_add2_i32: case INDEX_op_add2_i32:
op_new = INDEX_op_add_i32; opc_new = INDEX_op_add_i32;
goto do_addsub2; goto do_addsub2;
case INDEX_op_sub2_i32: case INDEX_op_sub2_i32:
op_new = INDEX_op_sub_i32; opc_new = INDEX_op_sub_i32;
goto do_addsub2; goto do_addsub2;
case INDEX_op_add2_i64: case INDEX_op_add2_i64:
op_new = INDEX_op_add_i64; opc_new = INDEX_op_add_i64;
goto do_addsub2; goto do_addsub2;
case INDEX_op_sub2_i64: case INDEX_op_sub2_i64:
op_new = INDEX_op_sub_i64; opc_new = INDEX_op_sub_i64;
do_addsub2: do_addsub2:
args -= 6;
nb_iargs = 4; nb_iargs = 4;
nb_oargs = 2; nb_oargs = 2;
/* Test if the high part of the operation is dead, but not /* Test if the high part of the operation is dead, but not
@ -1471,12 +1449,11 @@ static void tcg_liveness_analysis(TCGContext *s)
if (dead_temps[args[0]] && !mem_temps[args[0]]) { if (dead_temps[args[0]] && !mem_temps[args[0]]) {
goto do_remove; goto do_remove;
} }
/* Create the single operation plus nop. */ /* Replace the opcode and adjust the args in place,
s->gen_opc_buf[op_index] = op = op_new; leaving 3 unused args at the end. */
op->opc = opc = opc_new;
args[1] = args[2]; args[1] = args[2];
args[2] = args[4]; args[2] = args[4];
assert(s->gen_opc_buf[op_index + 1] == INDEX_op_nop);
tcg_set_nop(s, s->gen_opc_buf + op_index + 1, args + 3, 3);
/* Fall through and mark the single-word operation live. */ /* Fall through and mark the single-word operation live. */
nb_iargs = 2; nb_iargs = 2;
nb_oargs = 1; nb_oargs = 1;
@ -1484,27 +1461,26 @@ static void tcg_liveness_analysis(TCGContext *s)
goto do_not_remove; goto do_not_remove;
case INDEX_op_mulu2_i32: case INDEX_op_mulu2_i32:
op_new = INDEX_op_mul_i32; opc_new = INDEX_op_mul_i32;
op_new2 = INDEX_op_muluh_i32; opc_new2 = INDEX_op_muluh_i32;
have_op_new2 = TCG_TARGET_HAS_muluh_i32; have_opc_new2 = TCG_TARGET_HAS_muluh_i32;
goto do_mul2; goto do_mul2;
case INDEX_op_muls2_i32: case INDEX_op_muls2_i32:
op_new = INDEX_op_mul_i32; opc_new = INDEX_op_mul_i32;
op_new2 = INDEX_op_mulsh_i32; opc_new2 = INDEX_op_mulsh_i32;
have_op_new2 = TCG_TARGET_HAS_mulsh_i32; have_opc_new2 = TCG_TARGET_HAS_mulsh_i32;
goto do_mul2; goto do_mul2;
case INDEX_op_mulu2_i64: case INDEX_op_mulu2_i64:
op_new = INDEX_op_mul_i64; opc_new = INDEX_op_mul_i64;
op_new2 = INDEX_op_muluh_i64; opc_new2 = INDEX_op_muluh_i64;
have_op_new2 = TCG_TARGET_HAS_muluh_i64; have_opc_new2 = TCG_TARGET_HAS_muluh_i64;
goto do_mul2; goto do_mul2;
case INDEX_op_muls2_i64: case INDEX_op_muls2_i64:
op_new = INDEX_op_mul_i64; opc_new = INDEX_op_mul_i64;
op_new2 = INDEX_op_mulsh_i64; opc_new2 = INDEX_op_mulsh_i64;
have_op_new2 = TCG_TARGET_HAS_mulsh_i64; have_opc_new2 = TCG_TARGET_HAS_mulsh_i64;
goto do_mul2; goto do_mul2;
do_mul2: do_mul2:
args -= 4;
nb_iargs = 2; nb_iargs = 2;
nb_oargs = 2; nb_oargs = 2;
if (dead_temps[args[1]] && !mem_temps[args[1]]) { if (dead_temps[args[1]] && !mem_temps[args[1]]) {
@ -1513,28 +1489,25 @@ static void tcg_liveness_analysis(TCGContext *s)
goto do_remove; goto do_remove;
} }
/* The high part of the operation is dead; generate the low. */ /* The high part of the operation is dead; generate the low. */
s->gen_opc_buf[op_index] = op = op_new; op->opc = opc = opc_new;
args[1] = args[2]; args[1] = args[2];
args[2] = args[3]; args[2] = args[3];
} else if (have_op_new2 && dead_temps[args[0]] } else if (have_opc_new2 && dead_temps[args[0]]
&& !mem_temps[args[0]]) { && !mem_temps[args[0]]) {
/* The low part of the operation is dead; generate the high. */ /* The low part of the operation is dead; generate the high. */
s->gen_opc_buf[op_index] = op = op_new2; op->opc = opc = opc_new2;
args[0] = args[1]; args[0] = args[1];
args[1] = args[2]; args[1] = args[2];
args[2] = args[3]; args[2] = args[3];
} else { } else {
goto do_not_remove; goto do_not_remove;
} }
assert(s->gen_opc_buf[op_index + 1] == INDEX_op_nop);
tcg_set_nop(s, s->gen_opc_buf + op_index + 1, args + 3, 1);
/* Mark the single-word operation live. */ /* Mark the single-word operation live. */
nb_oargs = 1; nb_oargs = 1;
goto do_not_remove; goto do_not_remove;
default: default:
/* XXX: optimize by hardcoding common cases (e.g. triadic ops) */ /* XXX: optimize by hardcoding common cases (e.g. triadic ops) */
args -= def->nb_args;
nb_iargs = def->nb_iargs; nb_iargs = def->nb_iargs;
nb_oargs = def->nb_oargs; nb_oargs = def->nb_oargs;
@ -1542,24 +1515,23 @@ static void tcg_liveness_analysis(TCGContext *s)
its outputs are dead. We assume that nb_oargs == 0 its outputs are dead. We assume that nb_oargs == 0
implies side effects */ implies side effects */
if (!(def->flags & TCG_OPF_SIDE_EFFECTS) && nb_oargs != 0) { if (!(def->flags & TCG_OPF_SIDE_EFFECTS) && nb_oargs != 0) {
for(i = 0; i < nb_oargs; i++) { for (i = 0; i < nb_oargs; i++) {
arg = args[i]; arg = args[i];
if (!dead_temps[arg] || mem_temps[arg]) { if (!dead_temps[arg] || mem_temps[arg]) {
goto do_not_remove; goto do_not_remove;
} }
} }
do_remove: do_remove:
tcg_set_nop(s, s->gen_opc_buf + op_index, args, def->nb_args); op->opc = INDEX_op_nop;
#ifdef CONFIG_PROFILER #ifdef CONFIG_PROFILER
s->del_op_count++; s->del_op_count++;
#endif #endif
} else { } else {
do_not_remove: do_not_remove:
/* output args are dead */ /* output args are dead */
dead_args = 0; dead_args = 0;
sync_args = 0; sync_args = 0;
for(i = 0; i < nb_oargs; i++) { for (i = 0; i < nb_oargs; i++) {
arg = args[i]; arg = args[i];
if (dead_temps[arg]) { if (dead_temps[arg]) {
dead_args |= (1 << i); dead_args |= (1 << i);
@ -1577,7 +1549,7 @@ static void tcg_liveness_analysis(TCGContext *s)
// this causes problem because check_exit_request() inserts // this causes problem because check_exit_request() inserts
// brcond instruction in the middle of the TB, // brcond instruction in the middle of the TB,
// which incorrectly flags end-of-block // which incorrectly flags end-of-block
if (op != INDEX_op_brcond_i32) if (opc != INDEX_op_brcond_i32)
tcg_la_bb_end(s, dead_temps, mem_temps); tcg_la_bb_end(s, dead_temps, mem_temps);
// Unicorn: we do not touch dead temps for brcond, // Unicorn: we do not touch dead temps for brcond,
// but we should refresh TCG globals In-Memory states, // but we should refresh TCG globals In-Memory states,
@ -1592,23 +1564,18 @@ static void tcg_liveness_analysis(TCGContext *s)
} }
/* input args are live */ /* input args are live */
for(i = nb_oargs; i < nb_oargs + nb_iargs; i++) { for (i = nb_oargs; i < nb_oargs + nb_iargs; i++) {
arg = args[i]; arg = args[i];
if (dead_temps[arg]) { if (dead_temps[arg]) {
dead_args |= (1 << i); dead_args |= (1 << i);
} }
dead_temps[arg] = 0; dead_temps[arg] = 0;
} }
s->op_dead_args[op_index] = dead_args; s->op_dead_args[oi] = dead_args;
s->op_sync_args[op_index] = sync_args; s->op_sync_args[oi] = sync_args;
} }
break; break;
} }
op_index--;
}
if (args != s->gen_opparam_buf) {
tcg_abort();
} }
} }
#else #else
@ -2177,11 +2144,11 @@ static void tcg_reg_alloc_op(TCGContext *s,
#define STACK_DIR(x) (x) #define STACK_DIR(x) (x)
#endif #endif
static int tcg_reg_alloc_call(TCGContext *s, const TCGOpDef *def, static void tcg_reg_alloc_call(TCGContext *s, int nb_oargs, int nb_iargs,
TCGOpcode opc, const TCGArg *args, const TCGArg * const args, uint16_t dead_args,
uint16_t dead_args, uint8_t sync_args) uint8_t sync_args)
{ {
int nb_iargs, nb_oargs, flags, nb_regs, i, reg, nb_params; int flags, nb_regs, i, reg;
TCGArg arg; TCGArg arg;
TCGTemp *ts; TCGTemp *ts;
intptr_t stack_offset; intptr_t stack_offset;
@ -2190,12 +2157,6 @@ static int tcg_reg_alloc_call(TCGContext *s, const TCGOpDef *def,
int allocate_args; int allocate_args;
TCGRegSet allocated_regs; TCGRegSet allocated_regs;
arg = *args++;
nb_oargs = arg >> 16;
nb_iargs = arg & 0xffff;
nb_params = nb_iargs;
func_addr = (tcg_insn_unit *)(intptr_t)args[nb_oargs + nb_iargs]; func_addr = (tcg_insn_unit *)(intptr_t)args[nb_oargs + nb_iargs];
flags = args[nb_oargs + nb_iargs + 1]; flags = args[nb_oargs + nb_iargs + 1];
@ -2204,12 +2165,12 @@ static int tcg_reg_alloc_call(TCGContext *s, const TCGOpDef *def,
// do this because msvc cannot have arrays with 0 entries. // do this because msvc cannot have arrays with 0 entries.
nb_regs = 0; nb_regs = 0;
#endif #endif
if (nb_regs > nb_params) { if (nb_regs > nb_iargs) {
nb_regs = nb_params; nb_regs = nb_iargs;
} }
/* assign stack slots first */ /* assign stack slots first */
call_stack_size = (nb_params - nb_regs) * sizeof(tcg_target_long); call_stack_size = (nb_iargs - nb_regs) * sizeof(tcg_target_long);
call_stack_size = (call_stack_size + TCG_TARGET_STACK_ALIGN - 1) & call_stack_size = (call_stack_size + TCG_TARGET_STACK_ALIGN - 1) &
~(TCG_TARGET_STACK_ALIGN - 1); ~(TCG_TARGET_STACK_ALIGN - 1);
allocate_args = (call_stack_size > TCG_STATIC_CALL_ARGS_SIZE); allocate_args = (call_stack_size > TCG_STATIC_CALL_ARGS_SIZE);
@ -2220,7 +2181,7 @@ static int tcg_reg_alloc_call(TCGContext *s, const TCGOpDef *def,
} }
stack_offset = TCG_TARGET_CALL_STACK_OFFSET; stack_offset = TCG_TARGET_CALL_STACK_OFFSET;
for(i = nb_regs; i < nb_params; i++) { for(i = nb_regs; i < nb_iargs; i++) {
arg = args[nb_oargs + i]; arg = args[nb_oargs + i];
#ifdef TCG_TARGET_STACK_GROWSUP #ifdef TCG_TARGET_STACK_GROWSUP
stack_offset -= sizeof(tcg_target_long); stack_offset -= sizeof(tcg_target_long);
@ -2327,8 +2288,6 @@ static int tcg_reg_alloc_call(TCGContext *s, const TCGOpDef *def,
} }
} }
} }
return nb_iargs + nb_oargs + def->nb_cargs + 1;
} }
#ifdef CONFIG_PROFILER #ifdef CONFIG_PROFILER
@ -2348,10 +2307,7 @@ static inline int tcg_gen_code_common(TCGContext *s,
tcg_insn_unit *gen_code_buf, tcg_insn_unit *gen_code_buf,
long search_pc) long search_pc)
{ {
TCGOpcode opc; int oi, oi_next;
int op_index;
const TCGOpDef *def;
const TCGArg *args;
#ifdef DEBUG_DISAS #ifdef DEBUG_DISAS
if (unlikely(qemu_loglevel_mask(CPU_LOG_TB_OP))) { if (unlikely(qemu_loglevel_mask(CPU_LOG_TB_OP))) {
@ -2366,8 +2322,7 @@ static inline int tcg_gen_code_common(TCGContext *s,
#endif #endif
#ifdef USE_TCG_OPTIMIZATIONS #ifdef USE_TCG_OPTIMIZATIONS
s->gen_opparam_ptr = tcg_optimize(s);
tcg_optimize(s, s->gen_opc_ptr, s->gen_opparam_buf, s->tcg_op_defs);
#endif #endif
#ifdef CONFIG_PROFILER #ifdef CONFIG_PROFILER
@ -2396,42 +2351,30 @@ static inline int tcg_gen_code_common(TCGContext *s,
tcg_out_tb_init(s); tcg_out_tb_init(s);
args = s->gen_opparam_buf; for (oi = s->gen_first_op_idx; oi >= 0; oi = oi_next) {
op_index = 0; TCGOp * const op = &s->gen_op_buf[oi];
TCGArg * const args = &s->gen_opparam_buf[op->args];
TCGOpcode opc = op->opc;
const TCGOpDef *def = &s->tcg_op_defs[opc];
uint16_t dead_args = s->op_dead_args[oi];
uint8_t sync_args = s->op_sync_args[oi];
for(;;) { oi_next = op->next;
opc = s->gen_opc_buf[op_index];
#ifdef CONFIG_PROFILER #ifdef CONFIG_PROFILER
tcg_table_op_count[opc]++; tcg_table_op_count[opc]++;
#endif #endif
def = &s->tcg_op_defs[opc]; switch (opc) {
#if 0
printf("%s: %d %d %d\n", def->name,
def->nb_oargs, def->nb_iargs, def->nb_cargs);
// dump_regs(s);
#endif
switch(opc) {
case INDEX_op_mov_i32: case INDEX_op_mov_i32:
case INDEX_op_mov_i64: case INDEX_op_mov_i64:
tcg_reg_alloc_mov(s, def, args, s->op_dead_args[op_index], tcg_reg_alloc_mov(s, def, args, dead_args, sync_args);
s->op_sync_args[op_index]);
break; break;
case INDEX_op_movi_i32: case INDEX_op_movi_i32:
case INDEX_op_movi_i64: case INDEX_op_movi_i64:
tcg_reg_alloc_movi(s, args, s->op_dead_args[op_index], tcg_reg_alloc_movi(s, args, dead_args, sync_args);
s->op_sync_args[op_index]);
break; break;
case INDEX_op_debug_insn_start: case INDEX_op_debug_insn_start:
/* debug instruction */
break;
case INDEX_op_nop: case INDEX_op_nop:
case INDEX_op_nop1:
case INDEX_op_nop2:
case INDEX_op_nop3:
break; break;
case INDEX_op_nopn:
args += args[0];
goto next;
case INDEX_op_discard: case INDEX_op_discard:
temp_dead(s, args[0]); temp_dead(s, args[0]);
break; break;
@ -2440,12 +2383,9 @@ static inline int tcg_gen_code_common(TCGContext *s,
tcg_out_label(s, args[0], s->code_ptr); tcg_out_label(s, args[0], s->code_ptr);
break; break;
case INDEX_op_call: case INDEX_op_call:
args += tcg_reg_alloc_call(s, def, opc, args, tcg_reg_alloc_call(s, op->callo, op->calli, args,
s->op_dead_args[op_index], dead_args, sync_args);
s->op_sync_args[op_index]); break;
goto next;
case INDEX_op_end:
goto the_end;
default: default:
/* Sanity check that we've not introduced any unhandled opcodes. */ /* Sanity check that we've not introduced any unhandled opcodes. */
if (def->flags & TCG_OPF_NOT_PRESENT) { if (def->flags & TCG_OPF_NOT_PRESENT) {
@ -2454,21 +2394,17 @@ static inline int tcg_gen_code_common(TCGContext *s,
/* Note: in order to speed up the code, it would be much /* Note: in order to speed up the code, it would be much
faster to have specialized register allocator functions for faster to have specialized register allocator functions for
some common argument patterns */ some common argument patterns */
tcg_reg_alloc_op(s, def, opc, args, s->op_dead_args[op_index], tcg_reg_alloc_op(s, def, opc, args, dead_args, sync_args);
s->op_sync_args[op_index]);
break; break;
} }
args += def->nb_args;
next:
if (search_pc >= 0 && (size_t)search_pc < tcg_current_code_size(s)) { if (search_pc >= 0 && (size_t)search_pc < tcg_current_code_size(s)) {
return op_index; return oi;
} }
op_index++;
#ifndef NDEBUG #ifndef NDEBUG
check_regs(s); check_regs(s);
#endif #endif
} }
the_end:
/* Generate TB finalization at the end of block */ /* Generate TB finalization at the end of block */
tcg_out_tb_finalize(s); tcg_out_tb_finalize(s);
return -1; return -1;
@ -2479,14 +2415,18 @@ int tcg_gen_code(TCGContext *s, tcg_insn_unit *gen_code_buf) // qq
#ifdef CONFIG_PROFILER #ifdef CONFIG_PROFILER
{ {
int n; int n;
n = (s->gen_opc_ptr - s->gen_opc_buf);
s->op_count += n;
if (n > s->op_count_max)
s->op_count_max = n;
s->temp_count += s->nb_temps; n = s->gen_last_op_idx + 1;
if (s->nb_temps > s->temp_count_max) s->op_count += n;
s->temp_count_max = s->nb_temps; if (n > s->op_count_max) {
s->op_count_max = n;
}
n = s->nb_temps;
s->temp_count += n;
if (s->nb_temps > s->temp_count_max) {
s->temp_count_max = n;
}
} }
#endif #endif

View file

@ -451,6 +451,25 @@ typedef struct TCGTempSet {
unsigned long l[BITS_TO_LONGS(TCG_MAX_TEMPS)]; unsigned long l[BITS_TO_LONGS(TCG_MAX_TEMPS)];
} TCGTempSet; } 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);
/* pool based memory allocation */ /* pool based memory allocation */
void *tcg_malloc_internal(TCGContext *s, int size); void *tcg_malloc_internal(TCGContext *s, int size);
@ -590,7 +609,6 @@ struct tcg_temp_info {
struct TCGContext { struct TCGContext {
uint8_t *pool_cur, *pool_end; uint8_t *pool_cur, *pool_end;
TCGPool *pool_first, *pool_current, *pool_first_large; TCGPool *pool_first, *pool_current, *pool_first_large;
TCGLabel *labels;
int nb_labels; int nb_labels;
int nb_globals; int nb_globals;
int nb_temps; int nb_temps;
@ -607,10 +625,7 @@ struct TCGContext {
uint8_t *op_sync_args; /* for each operation, each bit tells if the uint8_t *op_sync_args; /* for each operation, each bit tells if the
corresponding output argument needs to be corresponding output argument needs to be
sync to memory. */ 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; TCGRegSet reserved_regs;
intptr_t current_frame_offset; intptr_t current_frame_offset;
intptr_t frame_start; intptr_t frame_start;
@ -618,8 +633,6 @@ struct TCGContext {
TCGTemp *frame_temp; TCGTemp *frame_temp;
tcg_insn_unit *code_ptr; tcg_insn_unit *code_ptr;
TCGTemp temps[TCG_MAX_TEMPS]; /* globals first, temps after */
TCGTempSet free_temps[TCG_TYPE_COUNT * 2];
GHashTable *helpers; GHashTable *helpers;
@ -647,14 +660,10 @@ struct TCGContext {
int goto_tb_issue_mask; int goto_tb_issue_mask;
#endif #endif
uint16_t gen_opc_buf[OPC_BUF_SIZE]; int gen_first_op_idx;
TCGArg gen_opparam_buf[OPPARAM_BUF_SIZE]; int gen_last_op_idx;
int gen_next_op_idx;
uint16_t *gen_opc_ptr; int gen_next_parm_idx;
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];
/* Code generation. Note that we specifically do not use tcg_insn_unit /* Code generation. Note that we specifically do not use tcg_insn_unit
here, because there's too much arithmetic throughout that relies here, because there's too much arithmetic throughout that relies
@ -673,6 +682,22 @@ struct TCGContext {
/* The TCGBackendData structure is private to tcg-target.c. */ /* The TCGBackendData structure is private to tcg-target.c. */
struct TCGBackendData *be; 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];
// Unicorn engine variables // Unicorn engine variables
struct uc_struct *uc; struct uc_struct *uc;
/* qemu/target-i386/translate.c: global register indexes */ /* qemu/target-i386/translate.c: global register indexes */
@ -783,7 +808,7 @@ struct TCGContext {
/* The number of opcodes emitted so far. */ /* The number of opcodes emitted so far. */
static inline int tcg_op_buf_count(TCGContext *tcg_ctx) static inline int tcg_op_buf_count(TCGContext *tcg_ctx)
{ {
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. */ /* Test for whether to terminate the TB for using too many opcodes. */
@ -841,8 +866,7 @@ void tcg_add_target_add_op_defs(TCGContext *s, const TCGTargetOpDef *tdefs);
void tcg_gen_callN(TCGContext *s, void *func, void tcg_gen_callN(TCGContext *s, void *func,
TCGArg ret, int nargs, TCGArg *args); TCGArg ret, int nargs, TCGArg *args);
TCGArg *tcg_optimize(TCGContext *s, uint16_t *tcg_opc_ptr, TCGArg *args, void tcg_optimize(TCGContext *s);
TCGOpDef *tcg_op_def);
static inline void *tcg_malloc(TCGContext *s, int size) static inline void *tcg_malloc(TCGContext *s, int size)
{ {