diff options
Diffstat (limited to 'src/recompiler/tcg/tcg.c')
-rw-r--r-- | src/recompiler/tcg/tcg.c | 709 |
1 files changed, 372 insertions, 337 deletions
diff --git a/src/recompiler/tcg/tcg.c b/src/recompiler/tcg/tcg.c index e3d1428b3..ef8b1ee9f 100644 --- a/src/recompiler/tcg/tcg.c +++ b/src/recompiler/tcg/tcg.c @@ -22,31 +22,39 @@ * THE SOFTWARE. */ -/* define it to suppress various consistency checks (faster) */ -#define NDEBUG - /* define it to use liveness analysis (better code) */ #define USE_LIVENESS_ANALYSIS +#include "config.h" + +#if !defined(CONFIG_DEBUG_TCG) && !defined(NDEBUG) +/* define it to suppress various consistency checks (faster) */ +#define NDEBUG +#endif + #ifndef VBOX -#include <assert.h> #include <stdarg.h> #include <stdlib.h> #include <stdio.h> #include <string.h> #include <inttypes.h> -#else -#include <stdio.h> -#include "osdep.h" -#endif #ifdef _WIN32 #include <malloc.h> #endif +#ifdef _AIX +#include <alloca.h> +#endif +#else /* VBOX */ +# include <stdio.h> +# include "osdep.h" +#endif /* VBOX */ -#include "config.h" #include "qemu-common.h" +#include "cache-utils.h" +#include "host-utils.h" +#include "qemu-timer.h" -/* Note: the long term plan is to reduce the dependencies on the QEMU +/* Note: the long term plan is to reduce the dependancies on the QEMU CPU definitions. Currently they are used for qemu_ld/st instructions */ #define NO_CPU_IO_DEFS @@ -56,65 +64,51 @@ #include "tcg-op.h" #include "elf.h" +#if defined(CONFIG_USE_GUEST_BASE) && !defined(TCG_TARGET_HAS_GUEST_BASE) +#error GUEST_BASE not supported on this host. +#endif #ifdef VBOX /* * Liveness analysis doesn't work well with 32-bit hosts and 64-bit targets, * second element of the register pair to store 64-bit value is considered - * dead, it seems. - * @todo: fix it in compiler - */ -#if defined(TARGET_X86_64) && (TCG_TARGET_REG_BITS == 32) -#undef USE_LIVENESS_ANALYSIS -#endif -#endif + * dead, it seems. */ + /** @todo re-test this */ +# if defined(TARGET_X86_64) && (TCG_TARGET_REG_BITS == 32) +# undef USE_LIVENESS_ANALYSIS +# endif +#endif /* VBOX */ +static void tcg_target_init(TCGContext *s); +static void tcg_target_qemu_prologue(TCGContext *s); static void patch_reloc(uint8_t *code_ptr, int type, tcg_target_long value, tcg_target_long addend); -TCGOpDef tcg_op_defs[] = { -#define DEF(s, n, copy_size) { #s, 0, 0, n, n, 0, copy_size }, -#ifndef VBOX -#define DEF2(s, iargs, oargs, cargs, flags) { #s, iargs, oargs, cargs, iargs + oargs + cargs, flags, 0 }, -#else -#define DEF2(s, iargs, oargs, cargs, flags) { #s, iargs, oargs, cargs, iargs + oargs + cargs, flags, 0, 0, 0 }, -#endif +static TCGOpDef tcg_op_defs[] = { +#define DEF(s, oargs, iargs, cargs, flags) { #s, oargs, iargs, cargs, iargs + oargs + cargs, flags }, #include "tcg-opc.h" #undef DEF -#undef DEF2 }; -TCGRegSet tcg_target_available_regs[2]; -TCGRegSet tcg_target_call_clobber_regs; +static TCGRegSet tcg_target_available_regs[2]; +static TCGRegSet tcg_target_call_clobber_regs; /* XXX: move that inside the context */ uint16_t *gen_opc_ptr; TCGArg *gen_opparam_ptr; -#ifndef VBOX static inline void tcg_out8(TCGContext *s, uint8_t v) -#else /* VBOX */ -DECLINLINE(void) tcg_out8(TCGContext *s, uint8_t v) -#endif /* VBOX */ { *s->code_ptr++ = v; } -#ifndef VBOX static inline void tcg_out16(TCGContext *s, uint16_t v) -#else /* VBOX */ -DECLINLINE(void) tcg_out16(TCGContext *s, uint16_t v) -#endif /* VBOX */ { *(uint16_t *)s->code_ptr = v; s->code_ptr += 2; } -#ifndef VBOX static inline void tcg_out32(TCGContext *s, uint32_t v) -#else /* VBOX */ -DECLINLINE(void) tcg_out32(TCGContext *s, uint32_t v) -#endif /* VBOX */ { *(uint32_t *)s->code_ptr = v; s->code_ptr += 4; @@ -122,8 +116,8 @@ DECLINLINE(void) tcg_out32(TCGContext *s, uint32_t v) /* label relocation processing */ -void tcg_out_reloc(TCGContext *s, uint8_t *code_ptr, int type, - int label_index, long addend) +static void tcg_out_reloc(TCGContext *s, uint8_t *code_ptr, int type, + int label_index, long addend) { TCGLabel *l; TCGRelocation *r; @@ -262,7 +256,10 @@ void tcg_context_init(TCGContext *s) } tcg_target_init(s); +} +void tcg_prologue_init(TCGContext *s) +{ /* init global prologue and epilogue */ s->code_buf = code_gen_prologue; s->code_ptr = s->code_buf; @@ -294,17 +291,14 @@ void tcg_func_start(TCGContext *s) gen_opparam_ptr = gen_opparam_buf; } -#ifndef VBOX static inline void tcg_temp_alloc(TCGContext *s, int n) -#else /* VBOX */ -DECLINLINE(void) tcg_temp_alloc(TCGContext *s, int n) -#endif /* VBOX */ { if (n > TCG_MAX_TEMPS) tcg_abort(); } -TCGv tcg_global_reg_new(TCGType type, int reg, const char *name) +static inline int tcg_global_reg_new_internal(TCGType type, int reg, + const char *name) { TCGContext *s = &tcg_ctx; TCGTemp *ts; @@ -326,48 +320,28 @@ TCGv tcg_global_reg_new(TCGType type, int reg, const char *name) ts->name = name; s->nb_globals++; tcg_regset_set_reg(s->reserved_regs, reg); - return MAKE_TCGV(idx); + return idx; } -#if TCG_TARGET_REG_BITS == 32 -/* temporary hack to avoid register shortage for tcg_qemu_st64() */ -TCGv tcg_global_reg2_new_hack(TCGType type, int reg1, int reg2, - const char *name) +TCGv_i32 tcg_global_reg_new_i32(int reg, const char *name) { - TCGContext *s = &tcg_ctx; - TCGTemp *ts; int idx; - char buf[64]; - if (type != TCG_TYPE_I64) - tcg_abort(); - idx = s->nb_globals; - tcg_temp_alloc(s, s->nb_globals + 2); - ts = &s->temps[s->nb_globals]; - ts->base_type = type; - ts->type = TCG_TYPE_I32; - ts->fixed_reg = 1; - ts->reg = reg1; - pstrcpy(buf, sizeof(buf), name); - pstrcat(buf, sizeof(buf), "_0"); - ts->name = strdup(buf); + idx = tcg_global_reg_new_internal(TCG_TYPE_I32, reg, name); + return MAKE_TCGV_I32(idx); +} - ts++; - ts->base_type = type; - ts->type = TCG_TYPE_I32; - ts->fixed_reg = 1; - ts->reg = reg2; - pstrcpy(buf, sizeof(buf), name); - pstrcat(buf, sizeof(buf), "_1"); - ts->name = strdup(buf); +TCGv_i64 tcg_global_reg_new_i64(int reg, const char *name) +{ + int idx; - s->nb_globals += 2; - return MAKE_TCGV(idx); + idx = tcg_global_reg_new_internal(TCG_TYPE_I64, reg, name); + return MAKE_TCGV_I64(idx); } -#endif -TCGv tcg_global_mem_new(TCGType type, int reg, tcg_target_long offset, - const char *name) +static inline int tcg_global_mem_new_internal(TCGType type, int reg, + tcg_target_long offset, + const char *name) { TCGContext *s = &tcg_ctx; TCGTemp *ts; @@ -423,10 +397,28 @@ TCGv tcg_global_mem_new(TCGType type, int reg, tcg_target_long offset, ts->name = name; s->nb_globals++; } - return MAKE_TCGV(idx); + return idx; +} + +TCGv_i32 tcg_global_mem_new_i32(int reg, tcg_target_long offset, + const char *name) +{ + int idx; + + idx = tcg_global_mem_new_internal(TCG_TYPE_I32, reg, offset, name); + return MAKE_TCGV_I32(idx); } -TCGv tcg_temp_new_internal(TCGType type, int temp_local) +TCGv_i64 tcg_global_mem_new_i64(int reg, tcg_target_long offset, + const char *name) +{ + int idx; + + idx = tcg_global_mem_new_internal(TCG_TYPE_I64, reg, offset, name); + return MAKE_TCGV_I64(idx); +} + +static inline int tcg_temp_new_internal(TCGType type, int temp_local) { TCGContext *s = &tcg_ctx; TCGTemp *ts; @@ -474,14 +466,29 @@ TCGv tcg_temp_new_internal(TCGType type, int temp_local) s->nb_temps++; } } - return MAKE_TCGV(idx); + return idx; +} + +TCGv_i32 tcg_temp_new_internal_i32(int temp_local) +{ + int idx; + + idx = tcg_temp_new_internal(TCG_TYPE_I32, temp_local); + return MAKE_TCGV_I32(idx); } -void tcg_temp_free(TCGv arg) +TCGv_i64 tcg_temp_new_internal_i64(int temp_local) +{ + int idx; + + idx = tcg_temp_new_internal(TCG_TYPE_I64, temp_local); + return MAKE_TCGV_I64(idx); +} + +static inline void tcg_temp_free_internal(int idx) { TCGContext *s = &tcg_ctx; TCGTemp *ts; - int idx = GET_TCGV(arg); int k; assert(idx >= s->nb_globals && idx < s->nb_temps); @@ -495,19 +502,44 @@ void tcg_temp_free(TCGv arg) s->first_free_temp[k] = idx; } +void tcg_temp_free_i32(TCGv_i32 arg) +{ + tcg_temp_free_internal(GET_TCGV_I32(arg)); +} -TCGv tcg_const_i32(int32_t val) +void tcg_temp_free_i64(TCGv_i64 arg) { - TCGv t0; - t0 = tcg_temp_new(TCG_TYPE_I32); + tcg_temp_free_internal(GET_TCGV_I64(arg)); +} + +TCGv_i32 tcg_const_i32(int32_t val) +{ + TCGv_i32 t0; + t0 = tcg_temp_new_i32(); + tcg_gen_movi_i32(t0, val); + return t0; +} + +TCGv_i64 tcg_const_i64(int64_t val) +{ + TCGv_i64 t0; + t0 = tcg_temp_new_i64(); + tcg_gen_movi_i64(t0, val); + return t0; +} + +TCGv_i32 tcg_const_local_i32(int32_t val) +{ + TCGv_i32 t0; + t0 = tcg_temp_local_new_i32(); tcg_gen_movi_i32(t0, val); return t0; } -TCGv tcg_const_i64(int64_t val) +TCGv_i64 tcg_const_local_i64(int64_t val) { - TCGv t0; - t0 = tcg_temp_new(TCG_TYPE_I64); + TCGv_i64 t0; + t0 = tcg_temp_local_new_i64(); tcg_gen_movi_i64(t0, val); return t0; } @@ -523,7 +555,6 @@ void tcg_register_helper(void *func, const char *name) } else { n *= 2; } - #ifdef VBOX s->helpers = qemu_realloc(s->helpers, n * sizeof(TCGHelperInfo)); #else @@ -536,162 +567,177 @@ void tcg_register_helper(void *func, const char *name) s->nb_helpers++; } -#ifndef VBOX -static inline TCGType tcg_get_base_type(TCGContext *s, TCGv arg) -#else /* VBOX */ -DECLINLINE(TCGType) tcg_get_base_type(TCGContext *s, TCGv arg) -#endif /* VBOX */ -{ - return s->temps[GET_TCGV(arg)].base_type; -} - -static void tcg_gen_call_internal(TCGContext *s, TCGv func, - unsigned int flags, - unsigned int nb_rets, const TCGv *rets, - unsigned int nb_params, const TCGv *params) -{ -#ifndef VBOX - int i; -#else - unsigned int i; -#endif - *gen_opc_ptr++ = INDEX_op_call; - *gen_opparam_ptr++ = (nb_rets << 16) | (nb_params + 1); - for(i = 0; i < nb_rets; i++) { - *gen_opparam_ptr++ = GET_TCGV(rets[i]); - } - for(i = 0; i < nb_params; i++) { - *gen_opparam_ptr++ = GET_TCGV(params[i]); - } - *gen_opparam_ptr++ = GET_TCGV(func); - - *gen_opparam_ptr++ = flags; - /* total parameters, needed to go backward in the instruction stream */ - *gen_opparam_ptr++ = 1 + nb_rets + nb_params + 3; -} - - -#if TCG_TARGET_REG_BITS < 64 /* Note: we convert the 64 bit args to 32 bit and do some alignment and endian swap. Maybe it would be better to do the alignment and endian swap in tcg_reg_alloc_call(). */ -void tcg_gen_call(TCGContext *s, TCGv func, unsigned int flags, - unsigned int nb_rets, const TCGv *rets, - unsigned int nb_params, const TCGv *args1) +void tcg_gen_callN(TCGContext *s, TCGv_ptr func, unsigned int flags, + int sizemask, TCGArg ret, int nargs, TCGArg *args) { - TCGv ret, *args2, rets_2[2], arg; - int j, i, call_type; +#ifdef TCG_TARGET_I386 + int call_type; +#endif + int i; + int real_args; + int nb_rets; + TCGArg *nparam; + +#if defined(TCG_TARGET_EXTEND_ARGS) && TCG_TARGET_REG_BITS == 64 + for (i = 0; i < nargs; ++i) { + int is_64bit = sizemask & (1 << (i+1)*2); + int is_signed = sizemask & (2 << (i+1)*2); + if (!is_64bit) { + TCGv_i64 temp = tcg_temp_new_i64(); + TCGv_i64 orig = MAKE_TCGV_I64(args[i]); + if (is_signed) { + tcg_gen_ext32s_i64(temp, orig); + } else { + tcg_gen_ext32u_i64(temp, orig); + } + args[i] = GET_TCGV_I64(temp); + } + } +#endif /* TCG_TARGET_EXTEND_ARGS */ - if (nb_rets == 1) { - ret = rets[0]; - if (tcg_get_base_type(s, ret) == TCG_TYPE_I64) { - nb_rets = 2; + *gen_opc_ptr++ = INDEX_op_call; + nparam = gen_opparam_ptr++; +#ifdef TCG_TARGET_I386 + call_type = (flags & TCG_CALL_TYPE_MASK); +#endif + if (ret != TCG_CALL_DUMMY_ARG) { +#if TCG_TARGET_REG_BITS < 64 + if (sizemask & 1) { #ifdef TCG_TARGET_WORDS_BIGENDIAN - rets_2[0] = TCGV_HIGH(ret); - rets_2[1] = ret; + *gen_opparam_ptr++ = ret + 1; + *gen_opparam_ptr++ = ret; #else - rets_2[0] = ret; - rets_2[1] = TCGV_HIGH(ret); + *gen_opparam_ptr++ = ret; + *gen_opparam_ptr++ = ret + 1; +#endif + nb_rets = 2; + } else #endif - rets = rets_2; + { + *gen_opparam_ptr++ = ret; + nb_rets = 1; } + } else { + nb_rets = 0; } - args2 = alloca((nb_params * 3) * sizeof(TCGv)); - j = 0; - call_type = (flags & TCG_CALL_TYPE_MASK); - for(i = 0; i < nb_params; i++) { - arg = args1[i]; - if (tcg_get_base_type(s, arg) == TCG_TYPE_I64) { + real_args = 0; + for (i = 0; i < nargs; i++) { +#if TCG_TARGET_REG_BITS < 64 + int is_64bit = sizemask & (1 << (i+1)*2); + if (is_64bit) { #ifdef TCG_TARGET_I386 /* REGPARM case: if the third parameter is 64 bit, it is allocated on the stack */ - if (j == 2 && call_type == TCG_CALL_TYPE_REGPARM) { + if (i == 2 && call_type == TCG_CALL_TYPE_REGPARM) { call_type = TCG_CALL_TYPE_REGPARM_2; flags = (flags & ~TCG_CALL_TYPE_MASK) | call_type; } - args2[j++] = arg; - args2[j++] = TCGV_HIGH(arg); -#else +#endif #ifdef TCG_TARGET_CALL_ALIGN_ARGS /* some targets want aligned 64 bit args */ - if (j & 1) { - args2[j++] = TCG_CALL_DUMMY_ARG; + if (real_args & 1) { + *gen_opparam_ptr++ = TCG_CALL_DUMMY_ARG; + real_args++; } #endif -#ifdef TCG_TARGET_WORDS_BIGENDIAN - args2[j++] = TCGV_HIGH(arg); - args2[j++] = arg; + /* If stack grows up, then we will be placing successive + arguments at lower addresses, which means we need to + reverse the order compared to how we would normally + treat either big or little-endian. For those arguments + that will wind up in registers, this still works for + HPPA (the only current STACK_GROWSUP target) since the + argument registers are *also* allocated in decreasing + order. If another such target is added, this logic may + have to get more complicated to differentiate between + stack arguments and register arguments. */ +#if defined(TCG_TARGET_WORDS_BIGENDIAN) != defined(TCG_TARGET_STACK_GROWSUP) + *gen_opparam_ptr++ = args[i] + 1; + *gen_opparam_ptr++ = args[i]; #else - args2[j++] = arg; - args2[j++] = TCGV_HIGH(arg); + *gen_opparam_ptr++ = args[i]; + *gen_opparam_ptr++ = args[i] + 1; #endif -#endif - } else { - args2[j++] = arg; + real_args += 2; + continue; + } +#endif /* TCG_TARGET_REG_BITS < 64 */ + + *gen_opparam_ptr++ = args[i]; + real_args++; + } + *gen_opparam_ptr++ = GET_TCGV_PTR(func); + + *gen_opparam_ptr++ = flags; + + *nparam = (nb_rets << 16) | (real_args + 1); + + /* total parameters, needed to go backward in the instruction stream */ + *gen_opparam_ptr++ = 1 + nb_rets + real_args + 3; + +#if defined(TCG_TARGET_EXTEND_ARGS) && TCG_TARGET_REG_BITS == 64 + for (i = 0; i < nargs; ++i) { + int is_64bit = sizemask & (1 << (i+1)*2); + if (!is_64bit) { + TCGv_i64 temp = MAKE_TCGV_I64(args[i]); + tcg_temp_free_i64(temp); } } - tcg_gen_call_internal(s, func, flags, - nb_rets, rets, j, args2); +#endif /* TCG_TARGET_EXTEND_ARGS */ } -#else -void tcg_gen_call(TCGContext *s, TCGv func, unsigned int flags, - unsigned int nb_rets, const TCGv *rets, - unsigned int nb_params, const TCGv *args1) -{ - tcg_gen_call_internal(s, func, flags, - nb_rets, rets, nb_params, args1); -} -#endif #if TCG_TARGET_REG_BITS == 32 -void tcg_gen_shifti_i64(TCGv ret, TCGv arg1, +void tcg_gen_shifti_i64(TCGv_i64 ret, TCGv_i64 arg1, int c, int right, int arith) { if (c == 0) { - tcg_gen_mov_i32(ret, arg1); + tcg_gen_mov_i32(TCGV_LOW(ret), TCGV_LOW(arg1)); tcg_gen_mov_i32(TCGV_HIGH(ret), TCGV_HIGH(arg1)); } else if (c >= 32) { c -= 32; if (right) { if (arith) { - tcg_gen_sari_i32(ret, TCGV_HIGH(arg1), c); + tcg_gen_sari_i32(TCGV_LOW(ret), TCGV_HIGH(arg1), c); tcg_gen_sari_i32(TCGV_HIGH(ret), TCGV_HIGH(arg1), 31); } else { - tcg_gen_shri_i32(ret, TCGV_HIGH(arg1), c); + tcg_gen_shri_i32(TCGV_LOW(ret), TCGV_HIGH(arg1), c); tcg_gen_movi_i32(TCGV_HIGH(ret), 0); } } else { - tcg_gen_shli_i32(TCGV_HIGH(ret), arg1, c); - tcg_gen_movi_i32(ret, 0); + tcg_gen_shli_i32(TCGV_HIGH(ret), TCGV_LOW(arg1), c); + tcg_gen_movi_i32(TCGV_LOW(ret), 0); } } else { - TCGv t0, t1; + TCGv_i32 t0, t1; - t0 = tcg_temp_new(TCG_TYPE_I32); - t1 = tcg_temp_new(TCG_TYPE_I32); + t0 = tcg_temp_new_i32(); + t1 = tcg_temp_new_i32(); if (right) { tcg_gen_shli_i32(t0, TCGV_HIGH(arg1), 32 - c); if (arith) tcg_gen_sari_i32(t1, TCGV_HIGH(arg1), c); else tcg_gen_shri_i32(t1, TCGV_HIGH(arg1), c); - tcg_gen_shri_i32(ret, arg1, c); - tcg_gen_or_i32(ret, ret, t0); + tcg_gen_shri_i32(TCGV_LOW(ret), TCGV_LOW(arg1), c); + tcg_gen_or_i32(TCGV_LOW(ret), TCGV_LOW(ret), t0); tcg_gen_mov_i32(TCGV_HIGH(ret), t1); } else { - tcg_gen_shri_i32(t0, arg1, 32 - c); + tcg_gen_shri_i32(t0, TCGV_LOW(arg1), 32 - c); /* Note: ret can be the same as arg1, so we use t1 */ - tcg_gen_shli_i32(t1, arg1, c); + tcg_gen_shli_i32(t1, TCGV_LOW(arg1), c); tcg_gen_shli_i32(TCGV_HIGH(ret), TCGV_HIGH(arg1), c); tcg_gen_or_i32(TCGV_HIGH(ret), TCGV_HIGH(ret), t0); - tcg_gen_mov_i32(ret, t1); + tcg_gen_mov_i32(TCGV_LOW(ret), t1); } - tcg_temp_free(t0); - tcg_temp_free(t1); + tcg_temp_free_i32(t0); + tcg_temp_free_i32(t1); } } #endif + static void tcg_reg_alloc_start(TCGContext *s) { int i; @@ -732,9 +778,14 @@ static char *tcg_get_arg_str_idx(TCGContext *s, char *buf, int buf_size, return buf; } -char *tcg_get_arg_str(TCGContext *s, char *buf, int buf_size, TCGv arg) +char *tcg_get_arg_str_i32(TCGContext *s, char *buf, int buf_size, TCGv_i32 arg) +{ + return tcg_get_arg_str_idx(s, buf, buf_size, GET_TCGV_I32(arg)); +} + +char *tcg_get_arg_str_i64(TCGContext *s, char *buf, int buf_size, TCGv_i64 arg) { - return tcg_get_arg_str_idx(s, buf, buf_size, GET_TCGV(arg)); + return tcg_get_arg_str_idx(s, buf, buf_size, GET_TCGV_I64(arg)); } static int helper_cmp(const void *p1, const void *p2) @@ -785,7 +836,6 @@ static TCGHelperInfo *tcg_find_helper(TCGContext *s, tcg_target_ulong val) return NULL; } -#ifndef VBOX static const char * const cond_name[] = { [TCG_COND_EQ] = "eq", @@ -799,28 +849,14 @@ static const char * const cond_name[] = [TCG_COND_LEU] = "leu", [TCG_COND_GTU] = "gtu" }; -#else -static const char * const cond_name[] = -{ - "eq", - "ne", - "lt", - "ge", - "le", - "gt", - "ltu", - "geu", - "leu", - "gtu" -}; -#endif void tcg_dump_ops(TCGContext *s, FILE *outfile) { const uint16_t *opc_ptr; const TCGArg *args; TCGArg arg; - int c, i, k, nb_oargs, nb_iargs, nb_cargs, first_insn; + TCGOpcode c; + int i, k, nb_oargs, nb_iargs, nb_cargs, first_insn; const TCGOpDef *def; char buf[128]; @@ -893,7 +929,7 @@ void tcg_dump_ops(TCGContext *s, FILE *outfile) val = args[1]; th = tcg_find_helper(s, val); if (th) { - fprintf(outfile, th->name); + fprintf(outfile, "%s", th->name); } else { if (c == INDEX_op_movi_i32) fprintf(outfile, "0x%x", (uint32_t)val); @@ -926,21 +962,29 @@ void tcg_dump_ops(TCGContext *s, FILE *outfile) fprintf(outfile, "%s", tcg_get_arg_str_idx(s, buf, sizeof(buf), args[k++])); } - if (c == INDEX_op_brcond_i32 + switch (c) { + case INDEX_op_brcond_i32: #if TCG_TARGET_REG_BITS == 32 - || c == INDEX_op_brcond2_i32 + case INDEX_op_brcond2_i32: #elif TCG_TARGET_REG_BITS == 64 - || c == INDEX_op_brcond_i64 + case INDEX_op_brcond_i64: +#endif + case INDEX_op_setcond_i32: +#if TCG_TARGET_REG_BITS == 32 + case INDEX_op_setcond2_i32: +#elif TCG_TARGET_REG_BITS == 64 + case INDEX_op_setcond_i64: #endif - ) { if (args[k] < ARRAY_SIZE(cond_name) && cond_name[args[k]]) fprintf(outfile, ",%s", cond_name[args[k++]]); else fprintf(outfile, ",$0x%" TCG_PRIlx, args[k++]); i = 1; - } - else + break; + default: i = 0; + break; + } for(; i < nb_cargs; i++) { if (k != 0) fprintf(outfile, ","); @@ -999,20 +1043,27 @@ static void sort_constraints(TCGOpDef *def, int start, int n) void tcg_add_target_add_op_defs(const TCGTargetOpDef *tdefs) { - int op; + TCGOpcode op; TCGOpDef *def; const char *ct_str; int i, nb_args; for(;;) { - if (tdefs->op < 0) + if (tdefs->op == (TCGOpcode)-1) break; op = tdefs->op; assert(op >= 0 && op < NB_OPS); def = &tcg_op_defs[op]; +#if defined(CONFIG_DEBUG_TCG) + /* Duplicate entry in op definitions? */ + assert(!def->used); + def->used = 1; +#endif nb_args = def->nb_iargs + def->nb_oargs; for(i = 0; i < nb_args; i++) { ct_str = tdefs->args_ct_str[i]; + /* Incomplete TCGTargetOpDef entry? */ + assert(ct_str != NULL); tcg_regset_clear(def->args_ct[i].u.regs); def->args_ct[i].ct = 0; if (ct_str[0] >= '0' && ct_str[0] <= '9') { @@ -1040,10 +1091,10 @@ void tcg_add_target_add_op_defs(const TCGTargetOpDef *tdefs) if (target_parse_constraint(&def->args_ct[i], &ct_str) < 0) { fprintf(stderr, "Invalid constraint '%s' for arg %d of operation '%s'\n", ct_str, i, def->name); -#ifdef VBOX - tcg_exit(1); -#else +#ifndef VBOX exit(1); +#else + tcg_exit(1); #endif } } @@ -1051,6 +1102,9 @@ void tcg_add_target_add_op_defs(const TCGTargetOpDef *tdefs) } } + /* TCGTargetOpDef entry with too much information? */ + assert(i == TCG_MAX_OP_ARGS || tdefs->args_ct_str[i] == NULL); + /* sort the constraints (XXX: this is just an heuristic) */ sort_constraints(def, 0, def->nb_oargs); sort_constraints(def, def->nb_oargs, def->nb_iargs); @@ -1068,16 +1122,35 @@ void tcg_add_target_add_op_defs(const TCGTargetOpDef *tdefs) tdefs++; } +#if defined(CONFIG_DEBUG_TCG) + i = 0; + for (op = 0; op < ARRAY_SIZE(tcg_op_defs); op++) { + if (op < INDEX_op_call || op == INDEX_op_debug_insn_start) { + /* Wrong entry in op definitions? */ + if (tcg_op_defs[op].used) { + fprintf(stderr, "Invalid op definition for %s\n", + tcg_op_defs[op].name); + i = 1; + } + } else { + /* Missing entry in op definitions? */ + if (!tcg_op_defs[op].used) { + fprintf(stderr, "Missing op definition for %s\n", + tcg_op_defs[op].name); + i = 1; + } + } + } + if (i == 1) { + tcg_abort(); + } +#endif } #ifdef USE_LIVENESS_ANALYSIS /* set a nop for an operation using 'nb_args' */ -#ifndef VBOX static inline void tcg_set_nop(TCGContext *s, uint16_t *opc_ptr, -#else /* VBOX */ -DECLINLINE(void) tcg_set_nop(TCGContext *s, uint16_t *opc_ptr, -#endif /* VBOX */ TCGArg *args, int nb_args) { if (nb_args == 0) { @@ -1093,11 +1166,7 @@ DECLINLINE(void) tcg_set_nop(TCGContext *s, uint16_t *opc_ptr, dead. */ /* XXX: at this stage, not used as there would be little gains because most TBs end with a conditional jump. */ -#ifndef VBOX static inline void tcg_la_func_end(TCGContext *s, uint8_t *dead_temps) -#else /* VBOX */ -DECLINLINE(void) tcg_la_func_end(TCGContext *s, uint8_t *dead_temps) -#endif /* VBOX */ { memset(dead_temps, 0, s->nb_globals); memset(dead_temps + s->nb_globals, 1, s->nb_temps - s->nb_globals); @@ -1105,11 +1174,7 @@ DECLINLINE(void) tcg_la_func_end(TCGContext *s, uint8_t *dead_temps) /* liveness analysis: end of basic block: globals are live, temps are dead, local temps are live. */ -#ifndef VBOX static inline void tcg_la_bb_end(TCGContext *s, uint8_t *dead_temps) -#else /* VBOX */ -DECLINLINE(void) tcg_la_bb_end(TCGContext *s, uint8_t *dead_temps) -#endif /* VBOX */ { int i; TCGTemp *ts; @@ -1130,7 +1195,8 @@ DECLINLINE(void) tcg_la_bb_end(TCGContext *s, uint8_t *dead_temps) temporaries are removed. */ static void tcg_liveness_analysis(TCGContext *s) { - int i, op_index, op, nb_args, nb_iargs, nb_oargs, arg, nb_ops; + int i, op_index, nb_args, nb_iargs, nb_oargs, arg, nb_ops; + TCGOpcode op; TCGArg *args; const TCGOpDef *def; uint8_t *dead_temps; @@ -1140,8 +1206,7 @@ static void tcg_liveness_analysis(TCGContext *s) nb_ops = gen_opc_ptr - gen_opc_buf; - /* XXX: make it really dynamic */ - s->op_dead_iargs = tcg_malloc(OPC_BUF_SIZE * sizeof(uint16_t)); + s->op_dead_iargs = tcg_malloc(nb_ops * sizeof(uint16_t)); dead_temps = tcg_malloc(s->nb_temps); memset(dead_temps, 1, s->nb_temps); @@ -1182,8 +1247,10 @@ static void tcg_liveness_analysis(TCGContext *s) dead_temps[arg] = 1; } - /* globals are live (they may be used by the call) */ - memset(dead_temps, 0, s->nb_globals); + if (!(call_flags & TCG_CALL_CONST)) { + /* globals are live (they may be used by the call) */ + memset(dead_temps, 0, s->nb_globals); + } /* input args are live */ dead_iargs = 0; @@ -1222,57 +1289,50 @@ static void tcg_liveness_analysis(TCGContext *s) break; /* XXX: optimize by hardcoding common cases (e.g. triadic ops) */ default: - if (op > INDEX_op_end) { - args -= def->nb_args; - nb_iargs = def->nb_iargs; - nb_oargs = def->nb_oargs; + args -= def->nb_args; + nb_iargs = def->nb_iargs; + nb_oargs = def->nb_oargs; - /* Test if the operation can be removed because all - its outputs are dead. We assume that nb_oargs == 0 - implies side effects */ - if (!(def->flags & TCG_OPF_SIDE_EFFECTS) && nb_oargs != 0) { - for(i = 0; i < nb_oargs; i++) { - arg = args[i]; - if (!dead_temps[arg]) - goto do_not_remove; - } - tcg_set_nop(s, gen_opc_buf + op_index, args, def->nb_args); + /* Test if the operation can be removed because all + its outputs are dead. We assume that nb_oargs == 0 + implies side effects */ + if (!(def->flags & TCG_OPF_SIDE_EFFECTS) && nb_oargs != 0) { + for(i = 0; i < nb_oargs; i++) { + arg = args[i]; + if (!dead_temps[arg]) + goto do_not_remove; + } + tcg_set_nop(s, gen_opc_buf + op_index, args, def->nb_args); #ifdef CONFIG_PROFILER - s->del_op_count++; + s->del_op_count++; #endif - } else { - do_not_remove: + } else { + do_not_remove: - /* output args are dead */ - for(i = 0; i < nb_oargs; i++) { - arg = args[i]; - dead_temps[arg] = 1; - } + /* output args are dead */ + for(i = 0; i < nb_oargs; i++) { + arg = args[i]; + dead_temps[arg] = 1; + } - /* if end of basic block, update */ - if (def->flags & TCG_OPF_BB_END) { - tcg_la_bb_end(s, dead_temps); - } else if (def->flags & TCG_OPF_CALL_CLOBBER) { - /* globals are live */ - memset(dead_temps, 0, s->nb_globals); - } + /* if end of basic block, update */ + if (def->flags & TCG_OPF_BB_END) { + tcg_la_bb_end(s, dead_temps); + } else if (def->flags & TCG_OPF_CALL_CLOBBER) { + /* globals are live */ + memset(dead_temps, 0, s->nb_globals); + } - /* input args are live */ - dead_iargs = 0; - for(i = 0; i < nb_iargs; i++) { - arg = args[i + nb_oargs]; - if (dead_temps[arg]) { - dead_iargs |= (1 << i); - } - dead_temps[arg] = 0; + /* input args are live */ + dead_iargs = 0; + for(i = 0; i < nb_iargs; i++) { + arg = args[i + nb_oargs]; + if (dead_temps[arg]) { + dead_iargs |= (1 << i); } - s->op_dead_iargs[op_index] = dead_iargs; + dead_temps[arg] = 0; } - } else { - /* legacy dyngen operations */ - args -= def->nb_args; - /* mark end of basic block */ - tcg_la_bb_end(s, dead_temps); + s->op_dead_iargs[op_index] = dead_iargs; } break; } @@ -1284,7 +1344,7 @@ static void tcg_liveness_analysis(TCGContext *s) } #else /* dummy liveness analysis */ -void tcg_liveness_analysis(TCGContext *s) +static void tcg_liveness_analysis(TCGContext *s) { int nb_ops; nb_ops = gen_opc_ptr - gen_opc_buf; @@ -1375,7 +1435,7 @@ static void temp_allocate_frame(TCGContext *s, int temp) #ifndef VBOX if (s->current_frame_offset + sizeof(tcg_target_long) > s->frame_end) #else - if ((unsigned)s->current_frame_offset + sizeof(tcg_target_long) > s->frame_end) + if ((tcg_target_long)s->current_frame_offset + sizeof(tcg_target_long) > s->frame_end) #endif tcg_abort(); ts->mem_offset = s->current_frame_offset; @@ -1464,7 +1524,7 @@ static void temp_save(TCGContext *s, int temp, TCGRegSet allocated_regs) } } -/* save globals to their canonical location and assume they can be +/* save globals to their cannonical location and assume they can be modified be the following code. 'allocated_regs' is used in case a temporary registers needs to be allocated to store a constant. */ static void save_globals(TCGContext *s, TCGRegSet allocated_regs) @@ -1549,7 +1609,7 @@ static void tcg_reg_alloc_mov(TCGContext *s, const TCGOpDef *def, reg = tcg_reg_alloc(s, arg_ct->u.regs, s->reserved_regs); } if (ts->reg != reg) { - tcg_out_mov(s, reg, ts->reg); + tcg_out_mov(s, ots->type, reg, ts->reg); } } } else if (ts->val_type == TEMP_VAL_MEM) { @@ -1581,7 +1641,7 @@ static void tcg_reg_alloc_mov(TCGContext *s, const TCGOpDef *def, } static void tcg_reg_alloc_op(TCGContext *s, - const TCGOpDef *def, int opc, + const TCGOpDef *def, TCGOpcode opc, const TCGArg *args, unsigned int dead_iargs) { @@ -1654,7 +1714,7 @@ static void tcg_reg_alloc_op(TCGContext *s, /* allocate a new register matching the constraint and move the temporary register into it */ reg = tcg_reg_alloc(s, arg_ct->u.regs, allocated_regs); - tcg_out_mov(s, reg, ts->reg); + tcg_out_mov(s, ts->type, reg, ts->reg); } new_args[i] = reg; const_args[i] = 0; @@ -1736,7 +1796,7 @@ static void tcg_reg_alloc_op(TCGContext *s, ts = &s->temps[args[i]]; reg = new_args[i]; if (ts->fixed_reg && ts->reg != reg) { - tcg_out_mov(s, ts->reg, reg); + tcg_out_mov(s, ts->type, ts->reg, reg); } } } @@ -1748,7 +1808,7 @@ static void tcg_reg_alloc_op(TCGContext *s, #endif static int tcg_reg_alloc_call(TCGContext *s, const TCGOpDef *def, - int opc, const TCGArg *args, + TCGOpcode opc, const TCGArg *args, unsigned int dead_iargs) { int nb_iargs, nb_oargs, flags, nb_regs, i, reg, nb_params; @@ -1822,7 +1882,7 @@ static int tcg_reg_alloc_call(TCGContext *s, const TCGOpDef *def, tcg_reg_free(s, reg); if (ts->val_type == TEMP_VAL_REG) { if (ts->reg != reg) { - tcg_out_mov(s, reg, ts->reg); + tcg_out_mov(s, ts->type, reg, ts->reg); } } else if (ts->val_type == TEMP_VAL_MEM) { tcg_out_ld(s, ts->type, reg, ts->mem_reg, ts->mem_offset); @@ -1851,7 +1911,7 @@ static int tcg_reg_alloc_call(TCGContext *s, const TCGOpDef *def, reg = ts->reg; if (!tcg_regset_test_reg(arg_ct->u.regs, reg)) { reg = tcg_reg_alloc(s, arg_ct->u.regs, allocated_regs); - tcg_out_mov(s, reg, ts->reg); + tcg_out_mov(s, ts->type, reg, ts->reg); } func_arg = reg; tcg_regset_set_reg(allocated_regs, reg); @@ -1892,7 +1952,9 @@ static int tcg_reg_alloc_call(TCGContext *s, const TCGOpDef *def, /* store globals and free associated registers (we assume the call can modify any global. */ - save_globals(s, allocated_regs); + if (!(flags & TCG_CALL_CONST)) { + save_globals(s, allocated_regs); + } tcg_out_op(s, opc, &func_arg, &const_func_arg); @@ -1908,7 +1970,7 @@ static int tcg_reg_alloc_call(TCGContext *s, const TCGOpDef *def, assert(s->reg_to_temp[reg] == -1); if (ts->fixed_reg) { if (ts->reg != reg) { - tcg_out_mov(s, ts->reg, reg); + tcg_out_mov(s, ts->type, ts->reg, reg); } } else { if (ts->val_type == TEMP_VAL_REG) @@ -1925,43 +1987,35 @@ static int tcg_reg_alloc_call(TCGContext *s, const TCGOpDef *def, #ifdef CONFIG_PROFILER -static int64_t dyngen_table_op_count[NB_OPS]; +static int64_t tcg_table_op_count[NB_OPS]; -void dump_op_count(void) +static void dump_op_count(void) { int i; FILE *f; - f = fopen("/tmp/op1.log", "w"); - for(i = 0; i < INDEX_op_end; i++) { - fprintf(f, "%s %" PRId64 "\n", tcg_op_defs[i].name, dyngen_table_op_count[i]); - } - fclose(f); - f = fopen("/tmp/op2.log", "w"); + f = fopen("/tmp/op.log", "w"); for(i = INDEX_op_end; i < NB_OPS; i++) { - fprintf(f, "%s %" PRId64 "\n", tcg_op_defs[i].name, dyngen_table_op_count[i]); + fprintf(f, "%s %" PRId64 "\n", tcg_op_defs[i].name, tcg_table_op_count[i]); } fclose(f); } #endif -#ifndef VBOX static inline int tcg_gen_code_common(TCGContext *s, uint8_t *gen_code_buf, -#else /* VBOX */ -DECLINLINE(int) tcg_gen_code_common(TCGContext *s, uint8_t *gen_code_buf, -#endif /* VBOX */ long search_pc) { - int opc, op_index; + TCGOpcode opc; + int op_index; const TCGOpDef *def; unsigned int dead_iargs; const TCGArg *args; #ifdef DEBUG_DISAS - if (unlikely(loglevel & CPU_LOG_TB_OP)) { - fprintf(logfile, "OP:\n"); + if (unlikely(qemu_loglevel_mask(CPU_LOG_TB_OP))) { + qemu_log("OP:\n"); tcg_dump_ops(s, logfile); - fprintf(logfile, "\n"); + qemu_log("\n"); } #endif @@ -1974,12 +2028,13 @@ DECLINLINE(int) tcg_gen_code_common(TCGContext *s, uint8_t *gen_code_buf, #endif #ifdef DEBUG_DISAS - if (unlikely(loglevel & CPU_LOG_TB_OP_OPT)) { - fprintf(logfile, "OP after la:\n"); +# ifdef USE_LIVENESS_ANALYSIS /* vbox */ + if (unlikely(qemu_loglevel_mask(CPU_LOG_TB_OP_OPT))) { + qemu_log("OP after liveness analysis:\n"); tcg_dump_ops(s, logfile); - fprintf(logfile, "\n"); - fflush(logfile); + qemu_log("\n"); } +# endif /* USE_LIVENESS_ANALYSIS - vbox */ #endif tcg_reg_alloc_start(s); @@ -1993,7 +2048,7 @@ DECLINLINE(int) tcg_gen_code_common(TCGContext *s, uint8_t *gen_code_buf, for(;;) { opc = gen_opc_buf[op_index]; #ifdef CONFIG_PROFILER - dyngen_table_op_count[opc]++; + tcg_table_op_count[opc]++; #endif def = &tcg_op_defs[opc]; #if 0 @@ -2048,22 +2103,6 @@ DECLINLINE(int) tcg_gen_code_common(TCGContext *s, uint8_t *gen_code_buf, goto next; case INDEX_op_end: goto the_end; - -#ifdef CONFIG_DYNGEN_OP - case 0 ... INDEX_op_end - 1: - /* legacy dyngen ops */ -#ifdef CONFIG_PROFILER - s->old_op_count++; -#endif - tcg_reg_alloc_bb_end(s, s->reserved_regs); - if (search_pc >= 0) { - s->code_ptr += def->copy_size; - args += def->nb_args; - } else { - args = dyngen_op(s, opc, args); - } - goto next; -#endif default: /* Note: in order to speed up the code, it would be much faster to have specialized register allocator functions for @@ -2086,7 +2125,7 @@ DECLINLINE(int) tcg_gen_code_common(TCGContext *s, uint8_t *gen_code_buf, return -1; } -int dyngen_code(TCGContext *s, uint8_t *gen_code_buf) +int tcg_gen_code(TCGContext *s, uint8_t *gen_code_buf) { #ifdef CONFIG_PROFILER { @@ -2114,7 +2153,7 @@ int dyngen_code(TCGContext *s, uint8_t *gen_code_buf) offset bytes from the start of the TB. The contents of gen_code_buf must not be changed, though writing the same values is ok. Return -1 if not found. */ -int dyngen_code_search_pc(TCGContext *s, uint8_t *gen_code_buf, long offset) +int tcg_gen_code_search_pc(TCGContext *s, uint8_t *gen_code_buf, long offset) { return tcg_gen_code_common(s, gen_code_buf, offset); } @@ -2135,8 +2174,6 @@ void tcg_dump_info(FILE *f, s->tb_count1 ? (double)(s->tb_count1 - s->tb_count) / s->tb_count1 * 100.0 : 0); cpu_fprintf(f, "avg ops/TB %0.1f max=%d\n", s->tb_count ? (double)s->op_count / s->tb_count : 0, s->op_count_max); - cpu_fprintf(f, "old ops/total ops %0.1f%%\n", - s->op_count ? (double)s->old_op_count / s->op_count * 100.0 : 0); cpu_fprintf(f, "deleted ops/TB %0.2f\n", s->tb_count ? (double)s->del_op_count / s->tb_count : 0); @@ -2163,10 +2200,8 @@ void tcg_dump_info(FILE *f, s->restore_count); cpu_fprintf(f, " avg cycles %0.1f\n", s->restore_count ? (double)s->restore_time / s->restore_count : 0); - { - extern void dump_op_count(void); - dump_op_count(); - } + + dump_op_count(); } #else void tcg_dump_info(FILE *f, |