关键结构
./target-arm/translate.c(DisasContext存在于该文件中,专门为TB块的生成而服务)
typedef struct DisasContext {
target_ulong pc;
int is_jmp;
/* Nonzero if this instruction has been conditionally skipped. */
int condjmp;
/* The label that will be jumped to when the instruction is skipped. */
int condlabel;
/* Thumb-2 conditional execution bits. */
int condexec_mask;
int condexec_cond;
struct TranslationBlock *tb;//包含一个TB块
int singlestep_enabled;
int thumb;
int bswap_code;
#if !defined(CONFIG_USER_ONLY)
int user;
#endif
int vfp_enabled;
int vec_len;
int vec_stride;
} DisasContext;
./include/exec/exec-all.h
struct TranslationBlock {
target_ulong pc; /* simulated PC corresponding to this block (EIP + CS base) */
target_ulong cs_base; /* CS base for this block */
uint64_t flags; /* flags defining in which context the code was generated */
uint16_t size; /* size of target code for this block (1 <=
size <= TARGET_PAGE_SIZE) */
uint16_t cflags; /* compile flags */
#define CF_COUNT_MASK 0x7fff
#define CF_LAST_IO 0x8000 /* Last insn may be an IO access. */
uint8_t *tc_ptr; /* pointer to the translated code */ //指向TB块中正在转换的指令,每个TB包含多条指令
/* next matching tb for physical address. */
struct TranslationBlock *phys_hash_next;
/* first and second physical page containing code. The lower bit
of the pointer tells the index in page_next[] */
struct TranslationBlock *page_next[2];
tb_page_addr_t page_addr[2];
/* the following data are used to directly call another TB from
the code of this one. */
uint16_t tb_next_offset[2]; /* offset of original jump target */
#ifdef USE_DIRECT_JUMP
uint16_t tb_jmp_offset[2]; /* offset of jump instruction */
#else
uintptr_t tb_next[2]; /* address of jump generated code */
#endif
/* list of TBs jumping to this one. This is a circular list using
the two least significant bits of the pointers to tell what is
the next pointer: 0 = jmp_next[0], 1 = jmp_next[1], 2 =
jmp_first */
struct TranslationBlock *jmp_next[2];
struct TranslationBlock *jmp_first;
uint32_t icount;
};
target-arm/cpu.h
typedef struct CPUARMState {
/* Regs for current mode. */
uint32_t regs[16];
/* Frequently accessed CPSR bits are stored separately for efficiency.
This contains all the other bits. Use cpsr_{read,write} to access
the whole CPSR. */
uint32_t uncached_cpsr;
uint32_t spsr;
/* Banked registers. */
uint32_t banked_spsr[6];
uint32_t banked_r13[6];
uint32_t banked_r14[6];
/* These hold r8-r12. */
uint32_t usr_regs[5];
uint32_t fiq_regs[5];
/* cpsr flag cache for faster execution */
uint32_t CF; /* 0 or 1 */
uint32_t VF; /* V is the bit 31. All other bits are undefined */
uint32_t NF; /* N is bit 31. All other bits are undefined. */
uint32_t ZF; /* Z set if zero. */
uint32_t QF; /* 0 or 1 */
uint32_t GE; /* cpsr[19:16] */
uint32_t thumb; /* cpsr[5]. 0 = arm mode, 1 = thumb mode. */
uint32_t condexec_bits; /* IT bits. cpsr[15:10,26:25]. */
/* System control coprocessor (cp15) */
struct {
uint32_t c0_cpuid;
uint32_t c0_cssel; /* Cache size selection. */
uint32_t c1_sys; /* System control register. */
uint32_t c1_coproc; /* Coprocessor access register. */
uint32_t c1_xscaleauxcr; /* XScale auxiliary control register. */
uint32_t c1_scr; /* secure config register. */
uint32_t c2_base0; /* MMU translation table base 0. */
uint32_t c2_base0_hi; /* MMU translation table base 0, high 32 bits */
uint32_t c2_base1; /* MMU translation table base 0. */
uint32_t c2_base1_hi; /* MMU translation table base 1, high 32 bits */
uint32_t c2_control; /* MMU translation table base control. */
uint32_t c2_mask; /* MMU translation table base selection mask. */
uint32_t c2_base_mask; /* MMU translation table base 0 mask. */
uint32_t c2_data; /* MPU data cachable bits. */
uint32_t c2_insn; /* MPU instruction cachable bits. */
uint32_t c3; /* MMU domain access control register
MPU write buffer control. */
uint32_t c5_insn; /* Fault status registers. */
uint32_t c5_data;
uint32_t c6_region[8]; /* MPU base/size registers. */
uint32_t c6_insn; /* Fault address registers. */
uint32_t c6_data;
uint32_t c7_par; /* Translation result. */
uint32_t c7_par_hi; /* Translation result, high 32 bits */
uint32_t c9_insn; /* Cache lockdown registers. */
uint32_t c9_data;
uint32_t c9_pmcr; /* performance monitor control register */
uint32_t c9_pmcnten; /* perf monitor counter enables */
uint32_t c9_pmovsr; /* perf monitor overflow status */
uint32_t c9_pmxevtyper; /* perf monitor event type */
uint32_t c9_pmuserenr; /* perf monitor user enable */
uint32_t c9_pminten; /* perf monitor interrupt enables */
uint32_t c13_fcse; /* FCSE PID. */
uint32_t c13_context; /* Context ID. */
uint32_t c13_tls1; /* User RW Thread register. */
uint32_t c13_tls2; /* User RO Thread register. */
uint32_t c13_tls3; /* Privileged Thread register. */
uint32_t c15_cpar; /* XScale Coprocessor Access Register */
uint32_t c15_ticonfig; /* TI925T configuration byte. */
uint32_t c15_i_max; /* Maximum D-cache dirty line index. */
uint32_t c15_i_min; /* Minimum D-cache dirty line index. */
uint32_t c15_threadid; /* TI debugger thread-ID. */
uint32_t c15_config_base_address; /* SCU base address. */
uint32_t c15_diagnostic; /* diagnostic register */
uint32_t c15_power_diagnostic;
uint32_t c15_power_control; /* power control */
} cp15;
struct {
uint32_t other_sp;
uint32_t vecbase;
uint32_t basepri;
uint32_t control;
int current_sp;
int exception;
int pending_exception;
} v7m;
/* Thumb-2 EE state. */
uint32_t teecr;
uint32_t teehbr;
/* VFP coprocessor state. */
struct {
float64 regs[32];
uint32_t xregs[16];
/* We store these fpcsr fields separately for convenience. */
int vec_len;
int vec_stride;
/* scratch space when Tn are not sufficient. */
uint32_t scratch[8];
/* fp_status is the "normal" fp status. standard_fp_status retains
* values corresponding to the ARM "Standard FPSCR Value", ie
* default-NaN, flush-to-zero, round-to-nearest and is used by
* any operations (generally Neon) which the architecture defines
* as controlled by the standard FPSCR value rather than the FPSCR.
*
* To avoid having to transfer exception bits around, we simply
* say that the FPSCR cumulative exception flags are the logical
* OR of the flags in the two fp statuses. This relies on the
* only thing which needs to read the exception flags being
* an explicit FPSCR read.
*/
float_status fp_status;
float_status standard_fp_status;
} vfp;
uint32_t exclusive_addr;
uint32_t exclusive_val;
uint32_t exclusive_high;
#if defined(CONFIG_USER_ONLY)
uint32_t exclusive_test;
uint32_t exclusive_info;
#endif
/* iwMMXt coprocessor state. */
struct {
uint64_t regs[16];
uint64_t val;
uint32_t cregs[16];
} iwmmxt;
/* For mixed endian mode. */
bool bswap_code;
#if defined(CONFIG_USER_ONLY)
/* For usermode syscall translation. */
int eabi;
#endif
CPU_COMMON
/* These fields after the common ones so they are preserved on reset. */
/* Internal CPU feature flags. */
uint64_t features;
void *nvic;
const struct arm_boot_info *boot_info;
} CPUARMState;
./include/exec/cpu-defs.h
#define CPU_COMMON \
struct TranslationBlock *current_tb; /* currently executing TB */ \
/* soft mmu support */ \
/* in order to avoid passing too many arguments to the MMIO \
helpers, we store some rarely used information in the CPU \
context) */ \
uintptr_t mem_io_pc; /* host pc at which the memory was \
accessed */ \
target_ulong mem_io_vaddr; /* target virtual addr at which the \
memory was accessed */ \
uint32_t halted; /* Nonzero if the CPU is in suspend state */ \
uint32_t interrupt_request; \
volatile sig_atomic_t exit_request; \
CPU_COMMON_TLB \
struct TranslationBlock *tb_jmp_cache[TB_JMP_CACHE_SIZE]; \
/* buffer for temporaries in the code generator */ \
long temp_buf[CPU_TEMP_BUF_NLONGS]; \
\
int64_t icount_extra; /* Instructions until next timer event. */ \
/* Number of cycles left, with interrupt flag in high bit. \
This allows a single read-compare-cbranch-write sequence to test \
for both decrementer underflow and exceptions. */ \
union { \
uint32_t u32; \
icount_decr_u16 u16; \
} icount_decr; \
uint32_t can_do_io; /* nonzero if memory mapped IO is safe. */ \
\
/* from this point: preserved by CPU reset */ \
/* ice debug support */ \
QTAILQ_HEAD(breakpoints_head, CPUBreakpoint) breakpoints; \
int singlestep_enabled; \
\
QTAILQ_HEAD(watchpoints_head, CPUWatchpoint) watchpoints; \
CPUWatchpoint *watchpoint_hit; \
\
struct GDBRegisterState *gdb_regs; \
\
/* Core interrupt code */ \
jmp_buf jmp_env; \
int exception_index; \
\
CPUArchState *next_cpu; /* next CPU sharing TB cache */ \
uint32_t host_tid; /* host thread ID */ \
int running; /* Nonzero if cpu is currently running(usermode). */ \
/* user data */ \
void *opaque; \
\
const char *cpu_model_str;
#endif
tcg/tcg.h
typedef struct TCGContext TCGContext;
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;
/* index of free temps, -1 if none */
int first_free_temp[TCG_TYPE_COUNT * 2];
/* goto_tb support */
uint8_t *code_buf;
uintptr_t *tb_next;
uint16_t *tb_next_offset;
uint16_t *tb_jmp_offset; /* != NULL if USE_DIRECT_JUMP */
/* liveness analysis */
uint16_t *op_dead_args; /* for each operation, each bit tells if the
corresponding argument is dead */
uint8_t *op_sync_args; /* for each operation, each bit tells if the
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;
tcg_target_long current_frame_offset;
tcg_target_long frame_start;
tcg_target_long frame_end;
int frame_reg;
uint8_t *code_ptr;
TCGTemp temps[TCG_MAX_TEMPS]; /* globals first, temps after */
TCGHelperInfo *helpers;
int nb_helpers;
int allocated_helpers;
int helpers_sorted;
#ifdef CONFIG_PROFILER
/* profiling info */
int64_t tb_count1;
int64_t tb_count;
int64_t op_count; /* total insn count */
int op_count_max; /* max insn per TB */
int64_t temp_count;
int temp_count_max;
int64_t del_op_count;
int64_t code_in_len;
int64_t code_out_len;
int64_t interm_time;
int64_t code_time;
int64_t la_time;
int64_t opt_time;
int64_t restore_count;
int64_t restore_time;
#endif
#ifdef CONFIG_DEBUG_TCG
int temps_in_use;
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];
#if defined(CONFIG_QEMU_LDST_OPTIMIZATION) && defined(CONFIG_SOFTMMU)
/* labels info for qemu_ld/st IRs
The labels help to generate TLB miss case codes at the end of TB */
TCGLabelQemuLdst *qemu_ldst_labels;
int nb_qemu_ldst_labels;
#endif
};
extern TCGContext tcg_ctx;
关键函数
参考链接:
//---->tcg/tcg.c
int tcg_gen_code(TCGContext *s, uint8_t *gen_code_buf)
{
#ifdef CONFIG_PROFILER
{
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;
if (s->nb_temps > s->temp_count_max)
s->temp_count_max = s->nb_temps;
}
#endif
tcg_gen_code_common(s, gen_code_buf, -1);
/* flush instruction cache */
flush_icache_range((tcg_target_ulong)gen_code_buf,
(tcg_target_ulong)s->code_ptr);
return s->code_ptr - gen_code_buf;
}
//tcg/tcg.c
static inline int tcg_gen_code_common(TCGContext *s, uint8_t *gen_code_buf,
long search_pc)
{
TCGOpcode opc;
int op_index;
const TCGOpDef *def;
const TCGArg *args;
#ifdef DEBUG_DISAS
if (unlikely(qemu_loglevel_mask(CPU_LOG_TB_OP))) {
qemu_log("OP:\n");
tcg_dump_ops(s);
qemu_log("\n");
}
#endif
#ifdef CONFIG_PROFILER
s->opt_time -= profile_getclock();
#endif
#ifdef USE_TCG_OPTIMIZATIONS
s->gen_opparam_ptr =
tcg_optimize(s, s->gen_opc_ptr, s->gen_opparam_buf, tcg_op_defs);
#endif
#ifdef CONFIG_PROFILER
s->opt_time += profile_getclock();
s->la_time -= profile_getclock();
#endif
tcg_liveness_analysis(s);
#ifdef CONFIG_PROFILER
s->la_time += profile_getclock();
#endif
#ifdef DEBUG_DISAS
if (unlikely(qemu_loglevel_mask(CPU_LOG_TB_OP_OPT))) {
qemu_log("OP after optimization and liveness analysis:\n");
tcg_dump_ops(s);
qemu_log("\n");
}
#endif
tcg_reg_alloc_start(s);
s->code_buf = gen_code_buf;
s->code_ptr = gen_code_buf;
args = s->gen_opparam_buf;
op_index = 0;
for(;;) {
opc = s->gen_opc_buf[op_index];
#ifdef CONFIG_PROFILER
tcg_table_op_count[opc]++;
#endif
def = &tcg_op_defs[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_i64:
tcg_reg_alloc_mov(s, def, args, s->op_dead_args[op_index],
s->op_sync_args[op_index]);
break;
case INDEX_op_movi_i32:
case INDEX_op_movi_i64:
tcg_reg_alloc_movi(s, args, s->op_dead_args[op_index],
s->op_sync_args[op_index]);
break;
case INDEX_op_debug_insn_start:
/* debug instruction */
break;
case INDEX_op_nop:
case INDEX_op_nop1:
case INDEX_op_nop2:
case INDEX_op_nop3:
break;
case INDEX_op_nopn:
args += args[0];
goto next;
case INDEX_op_discard:
temp_dead(s, args[0]);
break;
case INDEX_op_set_label:
tcg_reg_alloc_bb_end(s, s->reserved_regs);
tcg_out_label(s, args[0], s->code_ptr);
break;
case INDEX_op_call:
args += tcg_reg_alloc_call(s, def, opc, args,
s->op_dead_args[op_index],
s->op_sync_args[op_index]);
goto next;
case INDEX_op_end:
goto the_end;
default:
/* Sanity check that we've not introduced any unhandled opcodes. */
if (def->flags & TCG_OPF_NOT_PRESENT) {
tcg_abort();
}
/* Note: in order to speed up the code, it would be much
faster to have specialized register allocator functions for
some common argument patterns */
tcg_reg_alloc_op(s, def, opc, args, s->op_dead_args[op_index],
s->op_sync_args[op_index]);
break;
}
args += def->nb_args;
next:
if (search_pc >= 0 && search_pc < s->code_ptr - gen_code_buf) {
return op_index;
}
op_index++;
#ifndef NDEBUG
check_regs(s);
#endif
}
the_end:
#if defined(CONFIG_QEMU_LDST_OPTIMIZATION) && defined(CONFIG_SOFTMMU)
/* Generate TB finalization at the end of block */
tcg_out_tb_finalize(s);
#endif
return -1;
}
//tcg/i386/tcg-target.c
static inline void tcg_out_op(TCGContext *s, TCGOpcode opc,
const TCGArg *args, const int *const_args)
{
int c, rexw = 0;
#if TCG_TARGET_REG_BITS == 64
# define OP_32_64(x) \
case glue(glue(INDEX_op_, x), _i64): \
rexw = P_REXW; /* FALLTHRU */ \
case glue(glue(INDEX_op_, x), _i32)
#else
# define OP_32_64(x) \
case glue(glue(INDEX_op_, x), _i32)
#endif
switch(opc) {
case INDEX_op_exit_tb:
tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_EAX, args[0]);
tcg_out_jmp(s, (tcg_target_long) tb_ret_addr);
break;
case INDEX_op_goto_tb:
if (s->tb_jmp_offset) {
/* direct jump method */
tcg_out8(s, OPC_JMP_long); /* jmp im */
s->tb_jmp_offset[args[0]] = s->code_ptr - s->code_buf;
tcg_out32(s, 0);
} else {
/* indirect jump method */
tcg_out_modrm_offset(s, OPC_GRP5, EXT5_JMPN_Ev, -1,
(tcg_target_long)(s->tb_next + args[0]));
}
s->tb_next_offset[args[0]] = s->code_ptr - s->code_buf;
break;
case INDEX_op_call:
if (const_args[0]) {
tcg_out_calli(s, args[0]);
} else {
/* call *reg */
tcg_out_modrm(s, OPC_GRP5, EXT5_CALLN_Ev, args[0]);
}
break;
case INDEX_op_br:
tcg_out_jxx(s, JCC_JMP, args[0], 0);
break;
case INDEX_op_movi_i32:
tcg_out_movi(s, TCG_TYPE_I32, args[0], args[1]);
break;
OP_32_64(ld8u):
/* Note that we can ignore REXW for the zero-extend to 64-bit. */
tcg_out_modrm_offset(s, OPC_MOVZBL, args[0], args[1], args[2]);
break;
OP_32_64(ld8s):
tcg_out_modrm_offset(s, OPC_MOVSBL + rexw, args[0], args[1], args[2]);
break;
OP_32_64(ld16u):
/* Note that we can ignore REXW for the zero-extend to 64-bit. */
tcg_out_modrm_offset(s, OPC_MOVZWL, args[0], args[1], args[2]);
break;
OP_32_64(ld16s):
tcg_out_modrm_offset(s, OPC_MOVSWL + rexw, args[0], args[1], args[2]);
break;
#if TCG_TARGET_REG_BITS == 64
case INDEX_op_ld32u_i64:
#endif
case INDEX_op_ld_i32:
tcg_out_ld(s, TCG_TYPE_I32, args[0], args[1], args[2]);
break;
OP_32_64(st8):
if (const_args[0]) {
tcg_out_modrm_offset(s, OPC_MOVB_EvIz,
0, args[1], args[2]);
tcg_out8(s, args[0]);
} else {
tcg_out_modrm_offset(s, OPC_MOVB_EvGv | P_REXB_R,
args[0], args[1], args[2]);
}
break;
OP_32_64(st16):
if (const_args[0]) {
tcg_out_modrm_offset(s, OPC_MOVL_EvIz | P_DATA16,
0, args[1], args[2]);
tcg_out16(s, args[0]);
} else {
tcg_out_modrm_offset(s, OPC_MOVL_EvGv | P_DATA16,
args[0], args[1], args[2]);
}
break;
#if TCG_TARGET_REG_BITS == 64
case INDEX_op_st32_i64:
#endif
case INDEX_op_st_i32:
if (const_args[0]) {
tcg_out_modrm_offset(s, OPC_MOVL_EvIz, 0, args[1], args[2]);
tcg_out32(s, args[0]);
} else {
tcg_out_st(s, TCG_TYPE_I32, args[0], args[1], args[2]);
}
break;
OP_32_64(add):
/* For 3-operand addition, use LEA. */
if (args[0] != args[1]) {
TCGArg a0 = args[0], a1 = args[1], a2 = args[2], c3 = 0;
if (const_args[2]) {
c3 = a2, a2 = -1;
} else if (a0 == a2) {
/* Watch out for dest = src + dest, since we've removed
the matching constraint on the add. */
tgen_arithr(s, ARITH_ADD + rexw, a0, a1);
break;
}
tcg_out_modrm_sib_offset(s, OPC_LEA + rexw, a0, a1, a2, 0, c3);
break;
}
c = ARITH_ADD;
goto gen_arith;
OP_32_64(sub):
c = ARITH_SUB;
goto gen_arith;
OP_32_64(and):
c = ARITH_AND;
goto gen_arith;
OP_32_64(or):
c = ARITH_OR;
goto gen_arith;
OP_32_64(xor):
c = ARITH_XOR;
goto gen_arith;
gen_arith:
if (const_args[2]) {
tgen_arithi(s, c + rexw, args[0], args[2], 0);
} else {
tgen_arithr(s, c + rexw, args[0], args[2]);
}
break;
OP_32_64(mul):
if (const_args[2]) {
int32_t val;
val = args[2];
if (val == (int8_t)val) {
tcg_out_modrm(s, OPC_IMUL_GvEvIb + rexw, args[0], args[0]);
tcg_out8(s, val);
} else {
tcg_out_modrm(s, OPC_IMUL_GvEvIz + rexw, args[0], args[0]);
tcg_out32(s, val);
}
} else {
tcg_out_modrm(s, OPC_IMUL_GvEv + rexw, args[0], args[2]);
}
break;
OP_32_64(div2):
tcg_out_modrm(s, OPC_GRP3_Ev + rexw, EXT3_IDIV, args[4]);
break;
OP_32_64(divu2):
tcg_out_modrm(s, OPC_GRP3_Ev + rexw, EXT3_DIV, args[4]);
break;
OP_32_64(shl):
c = SHIFT_SHL;
goto gen_shift;
OP_32_64(shr):
c = SHIFT_SHR;
goto gen_shift;
OP_32_64(sar):
c = SHIFT_SAR;
goto gen_shift;
OP_32_64(rotl):
c = SHIFT_ROL;
goto gen_shift;
OP_32_64(rotr):
c = SHIFT_ROR;
goto gen_shift;
gen_shift:
if (const_args[2]) {
tcg_out_shifti(s, c + rexw, args[0], args[2]);
} else {
tcg_out_modrm(s, OPC_SHIFT_cl + rexw, c, args[0]);
}
break;
case INDEX_op_brcond_i32:
tcg_out_brcond32(s, args[2], args[0], args[1], const_args[1],
args[3], 0);
break;
case INDEX_op_setcond_i32:
tcg_out_setcond32(s, args[3], args[0], args[1],
args[2], const_args[2]);
break;
case INDEX_op_movcond_i32:
tcg_out_movcond32(s, args[5], args[0], args[1],
args[2], const_args[2], args[3]);
break;
OP_32_64(bswap16):
tcg_out_rolw_8(s, args[0]);
break;
OP_32_64(bswap32):
tcg_out_bswap32(s, args[0]);
break;
OP_32_64(neg):
tcg_out_modrm(s, OPC_GRP3_Ev + rexw, EXT3_NEG, args[0]);
break;
OP_32_64(not):
tcg_out_modrm(s, OPC_GRP3_Ev + rexw, EXT3_NOT, args[0]);
break;
OP_32_64(ext8s):
tcg_out_ext8s(s, args[0], args[1], rexw);
break;
OP_32_64(ext16s):
tcg_out_ext16s(s, args[0], args[1], rexw);
break;
OP_32_64(ext8u):
tcg_out_ext8u(s, args[0], args[1]);
break;
OP_32_64(ext16u):
tcg_out_ext16u(s, args[0], args[1]);
break;
case INDEX_op_qemu_ld8u:
tcg_out_qemu_ld(s, args, 0);
break;
case INDEX_op_qemu_ld8s:
tcg_out_qemu_ld(s, args, 0 | 4);
break;
case INDEX_op_qemu_ld16u:
tcg_out_qemu_ld(s, args, 1);
break;
case INDEX_op_qemu_ld16s:
tcg_out_qemu_ld(s, args, 1 | 4);
break;
#if TCG_TARGET_REG_BITS == 64
case INDEX_op_qemu_ld32u:
#endif
case INDEX_op_qemu_ld32:
tcg_out_qemu_ld(s, args, 2);
break;
case INDEX_op_qemu_ld64:
tcg_out_qemu_ld(s, args, 3);
break;
case INDEX_op_qemu_st8:
tcg_out_qemu_st(s, args, 0);
break;
case INDEX_op_qemu_st16:
tcg_out_qemu_st(s, args, 1);
break;
case INDEX_op_qemu_st32:
tcg_out_qemu_st(s, args, 2);
break;
case INDEX_op_qemu_st64:
tcg_out_qemu_st(s, args, 3);
break;
#if TCG_TARGET_REG_BITS == 32
case INDEX_op_brcond2_i32:
tcg_out_brcond2(s, args, const_args, 0);
break;
case INDEX_op_setcond2_i32:
tcg_out_setcond2(s, args, const_args);
break;
case INDEX_op_mulu2_i32:
tcg_out_modrm(s, OPC_GRP3_Ev, EXT3_MUL, args[3]);
break;
case INDEX_op_add2_i32:
if (const_args[4]) {
tgen_arithi(s, ARITH_ADD, args[0], args[4], 1);
} else {
tgen_arithr(s, ARITH_ADD, args[0], args[4]);
}
if (const_args[5]) {
tgen_arithi(s, ARITH_ADC, args[1], args[5], 1);
} else {
tgen_arithr(s, ARITH_ADC, args[1], args[5]);
}
break;
case INDEX_op_sub2_i32:
if (const_args[4]) {
tgen_arithi(s, ARITH_SUB, args[0], args[4], 1);
} else {
tgen_arithr(s, ARITH_SUB, args[0], args[4]);
}
if (const_args[5]) {
tgen_arithi(s, ARITH_SBB, args[1], args[5], 1);
} else {
tgen_arithr(s, ARITH_SBB, args[1], args[5]);
}
break;
#else /* TCG_TARGET_REG_BITS == 64 */
case INDEX_op_movi_i64:
tcg_out_movi(s, TCG_TYPE_I64, args[0], args[1]);
break;
case INDEX_op_ld32s_i64:
tcg_out_modrm_offset(s, OPC_MOVSLQ, args[0], args[1], args[2]);
break;
case INDEX_op_ld_i64:
tcg_out_ld(s, TCG_TYPE_I64, args[0], args[1], args[2]);
break;
case INDEX_op_st_i64:
if (const_args[0]) {
tcg_out_modrm_offset(s, OPC_MOVL_EvIz | P_REXW,
0, args[1], args[2]);
tcg_out32(s, args[0]);
} else {
tcg_out_st(s, TCG_TYPE_I64, args[0], args[1], args[2]);
}
break;
case INDEX_op_qemu_ld32s:
tcg_out_qemu_ld(s, args, 2 | 4);
break;
case INDEX_op_brcond_i64:
tcg_out_brcond64(s, args[2], args[0], args[1], const_args[1],
args[3], 0);
break;
case INDEX_op_setcond_i64:
tcg_out_setcond64(s, args[3], args[0], args[1],
args[2], const_args[2]);
break;
case INDEX_op_movcond_i64:
tcg_out_movcond64(s, args[5], args[0], args[1],
args[2], const_args[2], args[3]);
break;
case INDEX_op_bswap64_i64:
tcg_out_bswap64(s, args[0]);
break;
case INDEX_op_ext32u_i64:
tcg_out_ext32u(s, args[0], args[1]);
break;
case INDEX_op_ext32s_i64:
tcg_out_ext32s(s, args[0], args[1]);
break;
#endif
OP_32_64(deposit):
if (args[3] == 0 && args[4] == 8) {
/* load bits 0..7 */
tcg_out_modrm(s, OPC_MOVB_EvGv | P_REXB_R | P_REXB_RM,
args[2], args[0]);
} else if (args[3] == 8 && args[4] == 8) {
/* load bits 8..15 */
tcg_out_modrm(s, OPC_MOVB_EvGv, args[2], args[0] + 4);
} else if (args[3] == 0 && args[4] == 16) {
/* load bits 0..15 */
tcg_out_modrm(s, OPC_MOVL_EvGv | P_DATA16, args[2], args[0]);
} else {
tcg_abort();
}
break;
default:
tcg_abort();
}
#undef OP_32_64
}