tcg.h revision 4af48bf7c72ef1e201c64bd475377b5af9d8e8a1
1N/A/*
1N/A * Tiny Code Generator for QEMU
1N/A *
1N/A * Copyright (c) 2008 Fabrice Bellard
1N/A *
1N/A * Permission is hereby granted, free of charge, to any person obtaining a copy
1N/A * of this software and associated documentation files (the "Software"), to deal
1N/A * in the Software without restriction, including without limitation the rights
1N/A * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
1N/A * copies of the Software, and to permit persons to whom the Software is
1N/A * furnished to do so, subject to the following conditions:
1N/A *
1N/A * The above copyright notice and this permission notice shall be included in
1N/A * all copies or substantial portions of the Software.
1N/A *
1N/A * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
1N/A * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
1N/A * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
1N/A * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
1N/A * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
1N/A * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
1N/A * THE SOFTWARE.
1N/A */
1N/A#include "tcg-target.h"
1N/A
1N/A#if TCG_TARGET_REG_BITS == 32
1N/Atypedef int32_t tcg_target_long;
1N/Atypedef uint32_t tcg_target_ulong;
1N/A#define TCG_PRIlx PRIx32
1N/A#define TCG_PRIld PRId32
1N/A#elif TCG_TARGET_REG_BITS == 64
1N/Atypedef int64_t tcg_target_long;
1N/Atypedef uint64_t tcg_target_ulong;
1N/A#define TCG_PRIlx PRIx64
1N/A#define TCG_PRIld PRId64
1N/A#else
1N/A#error unsupported
1N/A#endif
1N/A
1N/A#if TCG_TARGET_NB_REGS <= 32
1N/Atypedef uint32_t TCGRegSet;
1N/A#elif TCG_TARGET_NB_REGS <= 64
1N/Atypedef uint64_t TCGRegSet;
1N/A#else
1N/A#error unsupported
1N/A#endif
1N/A
1N/Aenum {
1N/A#define DEF(s, n, copy_size) INDEX_op_ ## s,
1N/A#include "tcg-opc.h"
1N/A#undef DEF
1N/A NB_OPS,
1N/A};
1N/A
1N/A#define tcg_regset_clear(d) (d) = 0
1N/A#define tcg_regset_set(d, s) (d) = (s)
1N/A#define tcg_regset_set32(d, reg, val32) (d) |= (val32) << (reg)
1N/A#define tcg_regset_set_reg(d, r) (d) |= 1 << (r)
1N/A#define tcg_regset_reset_reg(d, r) (d) &= ~(1 << (r))
1N/A#define tcg_regset_test_reg(d, r) (((d) >> (r)) & 1)
1N/A#define tcg_regset_or(d, a, b) (d) = (a) | (b)
1N/A#define tcg_regset_and(d, a, b) (d) = (a) & (b)
1N/A#define tcg_regset_andnot(d, a, b) (d) = (a) & ~(b)
1N/A#define tcg_regset_not(d, a) (d) = ~(a)
1N/A
1N/Atypedef struct TCGRelocation {
1N/A struct TCGRelocation *next;
1N/A int type;
1N/A uint8_t *ptr;
1N/A tcg_target_long addend;
1N/A} TCGRelocation;
1N/A
1N/Atypedef struct TCGLabel {
1N/A int has_value;
1N/A union {
1N/A tcg_target_ulong value;
1N/A TCGRelocation *first_reloc;
1N/A } u;
1N/A} TCGLabel;
1N/A
1N/Atypedef struct TCGPool {
1N/A struct TCGPool *next;
1N/A int size;
1N/A uint8_t data[0] __attribute__ ((aligned));
1N/A} TCGPool;
1N/A
1N/A#define TCG_POOL_CHUNK_SIZE 32768
1N/A
1N/A#define TCG_MAX_LABELS 512
1N/A
1N/A#define TCG_MAX_TEMPS 512
1N/A
1N/A/* when the size of the arguments of a called function is smaller than
1N/A this value, they are statically allocated in the TB stack frame */
1N/A#define TCG_STATIC_CALL_ARGS_SIZE 128
1N/A
1N/Atypedef int TCGType;
1N/A
1N/A#define TCG_TYPE_I32 0
1N/A#define TCG_TYPE_I64 1
1N/A#define TCG_TYPE_COUNT 2 /* number of different types */
1N/A
1N/A#if TCG_TARGET_REG_BITS == 32
1N/A#define TCG_TYPE_PTR TCG_TYPE_I32
1N/A#else
1N/A#define TCG_TYPE_PTR TCG_TYPE_I64
1N/A#endif
1N/A
1N/Atypedef tcg_target_ulong TCGArg;
1N/A
1N/A/* Define a type and accessor macros for varables. Using a struct is
1N/A nice because it gives some level of type safely. Ideally the compiler
1N/A be able to see through all this. However in practice this is not true,
1N/A expecially on targets with braindamaged ABIs (e.g. i386).
1N/A We use plain int by default to avoid this runtime overhead.
1N/A Users of tcg_gen_* don't need to know about any of this, and should
1N/A treat TCGv as an opaque type.
1N/A In additon we do typechecking for different types of variables. TCGv_i32
1N/A and TCGv_i64 are 32/64-bit variables respectively. TCGv and TCGv_ptr
1N/A are aliases for target_ulong and host pointer sized values respectively.
1N/A */
1N/A
1N/A//#define DEBUG_TCGV 1
1N/A
1N/A#ifdef DEBUG_TCGV
1N/A
1N/Atypedef struct
1N/A{
1N/A int i32;
1N/A} TCGv_i32;
1N/A
1N/Atypedef struct
1N/A{
1N/A int i64;
1N/A} TCGv_i64;
1N/A
1N/A#define MAKE_TCGV_I32(i) __extension__ \
1N/A ({ TCGv_i32 make_tcgv_tmp = {i}; make_tcgv_tmp;})
1N/A#define MAKE_TCGV_I64(i) __extension__ \
1N/A ({ TCGv_i64 make_tcgv_tmp = {i}; make_tcgv_tmp;})
1N/A#define GET_TCGV_I32(t) ((t).i32)
1N/A#define GET_TCGV_I64(t) ((t).i64)
1N/A#if TCG_TARGET_REG_BITS == 32
1N/A#define TCGV_LOW(t) MAKE_TCGV_I32(GET_TCGV_I64(t))
1N/A#define TCGV_HIGH(t) MAKE_TCGV_I32(GET_TCGV_I64(t) + 1)
1N/A#endif
1N/A
1N/A#else /* !DEBUG_TCGV */
1N/A
1N/Atypedef int TCGv_i32;
1N/Atypedef int TCGv_i64;
1N/A#define MAKE_TCGV_I32(x) (x)
1N/A#define MAKE_TCGV_I64(x) (x)
1N/A#define GET_TCGV_I32(t) (t)
1N/A#define GET_TCGV_I64(t) (t)
1N/A#if TCG_TARGET_REG_BITS == 32
1N/A#define TCGV_LOW(t) (t)
1N/A#define TCGV_HIGH(t) ((t) + 1)
1N/A#endif
1N/A
1N/A#endif /* DEBUG_TCGV */
1N/A
1N/A/* Dummy definition to avoid compiler warnings. */
1N/A#define TCGV_UNUSED_I32(x) x = MAKE_TCGV_I32(-1)
1N/A#define TCGV_UNUSED_I64(x) x = MAKE_TCGV_I64(-1)
1N/A
1N/A/* call flags */
1N/A#define TCG_CALL_TYPE_MASK 0x000f
1N/A#define TCG_CALL_TYPE_STD 0x0000 /* standard C call */
1N/A#define TCG_CALL_TYPE_REGPARM_1 0x0001 /* i386 style regparm call (1 reg) */
1N/A#define TCG_CALL_TYPE_REGPARM_2 0x0002 /* i386 style regparm call (2 regs) */
1N/A#define TCG_CALL_TYPE_REGPARM 0x0003 /* i386 style regparm call (3 regs) */
1N/A/* A pure function only reads its arguments and globals variables and
1N/A cannot raise exceptions. Hence a call to a pure function can be
1N/A safely suppressed if the return value is not used. */
1N/A#define TCG_CALL_PURE 0x0010
1N/A
1N/A/* used to align parameters */
1N/A#define TCG_CALL_DUMMY_TCGV MAKE_TCGV_I32(-1)
1N/A#define TCG_CALL_DUMMY_ARG ((TCGArg)(-1))
1N/A
1N/Atypedef enum {
1N/A TCG_COND_EQ,
1N/A TCG_COND_NE,
1N/A TCG_COND_LT,
1N/A TCG_COND_GE,
1N/A TCG_COND_LE,
1N/A TCG_COND_GT,
1N/A /* unsigned */
1N/A TCG_COND_LTU,
1N/A TCG_COND_GEU,
1N/A TCG_COND_LEU,
1N/A TCG_COND_GTU,
1N/A} TCGCond;
1N/A
1N/A#define TEMP_VAL_DEAD 0
1N/A#define TEMP_VAL_REG 1
1N/A#define TEMP_VAL_MEM 2
1N/A#define TEMP_VAL_CONST 3
1N/A
1N/A/* XXX: optimize memory layout */
1N/Atypedef struct TCGTemp {
1N/A TCGType base_type;
1N/A TCGType type;
1N/A int val_type;
1N/A int reg;
1N/A tcg_target_long val;
1N/A int mem_reg;
1N/A tcg_target_long mem_offset;
1N/A unsigned int fixed_reg:1;
1N/A unsigned int mem_coherent:1;
1N/A unsigned int mem_allocated:1;
1N/A unsigned int temp_local:1; /* If true, the temp is saved accross
1N/A basic blocks. Otherwise, it is not
1N/A preserved accross basic blocks. */
1N/A unsigned int temp_allocated:1; /* never used for code gen */
1N/A /* index of next free temp of same base type, -1 if end */
1N/A int next_free_temp;
1N/A const char *name;
1N/A} TCGTemp;
1N/A
1N/Atypedef struct TCGHelperInfo {
1N/A tcg_target_ulong func;
1N/A const char *name;
1N/A} TCGHelperInfo;
1N/A
1N/Atypedef struct TCGContext TCGContext;
1N/A
1N/Astruct TCGContext {
1N/A uint8_t *pool_cur, *pool_end;
1N/A TCGPool *pool_first, *pool_current;
1N/A TCGLabel *labels;
1N/A int nb_labels;
1N/A TCGTemp *temps; /* globals first, temps after */
1N/A int nb_globals;
1N/A int nb_temps;
1N/A /* index of free temps, -1 if none */
1N/A int first_free_temp[TCG_TYPE_COUNT * 2];
1N/A
1N/A /* goto_tb support */
1N/A uint8_t *code_buf;
1N/A unsigned long *tb_next;
1N/A uint16_t *tb_next_offset;
1N/A uint16_t *tb_jmp_offset; /* != NULL if USE_DIRECT_JUMP */
1N/A
1N/A /* liveness analysis */
1N/A uint16_t *op_dead_iargs; /* for each operation, each bit tells if the
1N/A corresponding input argument is dead */
1N/A
1N/A /* tells in which temporary a given register is. It does not take
1N/A into account fixed registers */
1N/A int reg_to_temp[TCG_TARGET_NB_REGS];
1N/A TCGRegSet reserved_regs;
1N/A tcg_target_long current_frame_offset;
1N/A tcg_target_long frame_start;
1N/A tcg_target_long frame_end;
1N/A int frame_reg;
1N/A
1N/A uint8_t *code_ptr;
1N/A TCGTemp static_temps[TCG_MAX_TEMPS];
1N/A
1N/A TCGHelperInfo *helpers;
1N/A int nb_helpers;
1N/A int allocated_helpers;
1N/A int helpers_sorted;
1N/A
1N/A#ifdef CONFIG_PROFILER
1N/A /* profiling info */
1N/A int64_t tb_count1;
1N/A int64_t tb_count;
1N/A int64_t op_count; /* total insn count */
1N/A int op_count_max; /* max insn per TB */
1N/A int64_t temp_count;
1N/A int temp_count_max;
1N/A int64_t del_op_count;
1N/A int64_t code_in_len;
1N/A int64_t code_out_len;
1N/A int64_t interm_time;
1N/A int64_t code_time;
1N/A int64_t la_time;
1N/A int64_t restore_count;
1N/A int64_t restore_time;
1N/A#endif
1N/A};
1N/A
1N/Aextern TCGContext tcg_ctx;
1N/Aextern uint16_t *gen_opc_ptr;
1N/Aextern TCGArg *gen_opparam_ptr;
1N/Aextern uint16_t gen_opc_buf[];
1N/Aextern TCGArg gen_opparam_buf[];
1N/A
1N/A/* pool based memory allocation */
1N/A
1N/Avoid *tcg_malloc_internal(TCGContext *s, int size);
1N/Avoid tcg_pool_reset(TCGContext *s);
1N/Avoid tcg_pool_delete(TCGContext *s);
1N/A
1N/Astatic inline void *tcg_malloc(int size)
1N/A{
1N/A TCGContext *s = &tcg_ctx;
1N/A uint8_t *ptr, *ptr_end;
1N/A size = (size + sizeof(long) - 1) & ~(sizeof(long) - 1);
1N/A ptr = s->pool_cur;
1N/A ptr_end = ptr + size;
1N/A if (unlikely(ptr_end > s->pool_end)) {
1N/A return tcg_malloc_internal(&tcg_ctx, size);
1N/A } else {
1N/A s->pool_cur = ptr_end;
1N/A return ptr;
1N/A }
1N/A}
1N/A
1N/Avoid tcg_context_init(TCGContext *s);
1N/Avoid tcg_func_start(TCGContext *s);
1N/A
1N/Aint tcg_gen_code(TCGContext *s, uint8_t *gen_code_buf);
1N/Aint tcg_gen_code_search_pc(TCGContext *s, uint8_t *gen_code_buf, long offset);
1N/A
1N/Avoid tcg_set_frame(TCGContext *s, int reg,
1N/A tcg_target_long start, tcg_target_long size);
1N/A
1N/ATCGv_i32 tcg_global_reg_new_i32(int reg, const char *name);
1N/ATCGv_i32 tcg_global_mem_new_i32(int reg, tcg_target_long offset,
1N/A const char *name);
1N/ATCGv_i32 tcg_temp_new_internal_i32(int temp_local);
1N/Astatic inline TCGv_i32 tcg_temp_new_i32(void)
1N/A{
1N/A return tcg_temp_new_internal_i32(0);
1N/A}
1N/Astatic inline TCGv_i32 tcg_temp_local_new_i32(void)
1N/A{
1N/A return tcg_temp_new_internal_i32(1);
1N/A}
1N/Avoid tcg_temp_free_i32(TCGv_i32 arg);
1N/Achar *tcg_get_arg_str_i32(TCGContext *s, char *buf, int buf_size, TCGv_i32 arg);
1N/A
1N/ATCGv_i64 tcg_global_reg_new_i64(int reg, const char *name);
1N/ATCGv_i64 tcg_global_mem_new_i64(int reg, tcg_target_long offset,
1N/A const char *name);
1N/ATCGv_i64 tcg_temp_new_internal_i64(int temp_local);
1N/Astatic inline TCGv_i64 tcg_temp_new_i64(void)
1N/A{
1N/A return tcg_temp_new_internal_i64(0);
1N/A}
1N/Astatic inline TCGv_i64 tcg_temp_local_new_i64(void)
1N/A{
1N/A return tcg_temp_new_internal_i64(1);
1N/A}
1N/Avoid tcg_temp_free_i64(TCGv_i64 arg);
1N/Achar *tcg_get_arg_str_i64(TCGContext *s, char *buf, int buf_size, TCGv_i64 arg);
1N/A
1N/Avoid tcg_dump_info(FILE *f,
1N/A int (*cpu_fprintf)(FILE *f, const char *fmt, ...));
1N/A
1N/A#define TCG_CT_ALIAS 0x80
1N/A#define TCG_CT_IALIAS 0x40
1N/A#define TCG_CT_REG 0x01
1N/A#define TCG_CT_CONST 0x02 /* any constant of register size */
1N/A
1N/Atypedef struct TCGArgConstraint {
1N/A uint16_t ct;
1N/A uint8_t alias_index;
1N/A union {
1N/A TCGRegSet regs;
1N/A } u;
1N/A} TCGArgConstraint;
1N/A
1N/A#define TCG_MAX_OP_ARGS 16
1N/A
1N/A#define TCG_OPF_BB_END 0x01 /* instruction defines the end of a basic
1N/A block */
1N/A#define TCG_OPF_CALL_CLOBBER 0x02 /* instruction clobbers call registers
1N/A and potentially update globals. */
1N/A#define TCG_OPF_SIDE_EFFECTS 0x04 /* instruction has side effects : it
1N/A cannot be removed if its output
1N/A are not used */
1N/A
1N/Atypedef struct TCGOpDef {
1N/A const char *name;
1N/A uint8_t nb_oargs, nb_iargs, nb_cargs, nb_args;
1N/A uint8_t flags;
1N/A uint16_t copy_size;
1N/A TCGArgConstraint *args_ct;
1N/A int *sorted_args;
1N/A} TCGOpDef;
1N/A
1N/Atypedef struct TCGTargetOpDef {
1N/A int op;
1N/A const char *args_ct_str[TCG_MAX_OP_ARGS];
1N/A} TCGTargetOpDef;
1N/A
1N/Avoid tcg_target_init(TCGContext *s);
1N/Avoid tcg_target_qemu_prologue(TCGContext *s);
1N/A
1N/A#ifndef VBOX
1N/A#define tcg_abort() \
1N/Ado {\
1N/A fprintf(stderr, "%s:%d: tcg fatal error\n", __FILE__, __LINE__);\
1N/A abort();\
1N/A} while (0)
1N/A#else /* VBOX */
1N/A# define tcg_abort() \
1N/A do {\
1N/A remAbort(-1, "TCG fatal error: "__FILE__":" RT_XSTR(__LINE__)); \
1N/A } while (0)
1N/Aextern void qemu_qsort(void* base, size_t nmemb, size_t size,
1N/A int(*compar)(const void*, const void*));
1N/A#define tcg_exit(status) \
1N/A do {\
1N/A remAbort(-1, "TCG exit: "__FILE__":" RT_XSTR(__LINE__));\
1N/A } while (0)
1N/A#endif /* VBOX */
1N/A
1N/Avoid tcg_add_target_add_op_defs(const TCGTargetOpDef *tdefs);
1N/A
1N/A#if TCG_TARGET_REG_BITS == 32
1N/A#define tcg_const_ptr tcg_const_i32
#define tcg_add_ptr tcg_add_i32
#define tcg_sub_ptr tcg_sub_i32
#define TCGv_ptr TCGv_i32
#define GET_TCGV_PTR GET_TCGV_I32
#define tcg_global_reg_new_ptr tcg_global_reg_new_i32
#define tcg_global_mem_new_ptr tcg_global_mem_new_i32
#define tcg_temp_new_ptr tcg_temp_new_i32
#define tcg_temp_free_ptr tcg_temp_free_i32
#else
#define tcg_const_ptr tcg_const_i64
#define tcg_add_ptr tcg_add_i64
#define tcg_sub_ptr tcg_sub_i64
#define TCGv_ptr TCGv_i64
#define GET_TCGV_PTR GET_TCGV_I64
#define tcg_global_reg_new_ptr tcg_global_reg_new_i64
#define tcg_global_mem_new_ptr tcg_global_mem_new_i64
#define tcg_temp_new_ptr tcg_temp_new_i64
#define tcg_temp_free_ptr tcg_temp_free_i64
#endif
void tcg_gen_callN(TCGContext *s, TCGv_ptr func, unsigned int flags,
int sizemask, TCGArg ret, int nargs, TCGArg *args);
void tcg_gen_shifti_i64(TCGv_i64 ret, TCGv_i64 arg1,
int c, int right, int arith);
/* only used for debugging purposes */
void tcg_register_helper(void *func, const char *name);
const char *tcg_helper_get_name(TCGContext *s, void *func);
void tcg_dump_ops(TCGContext *s, FILE *outfile);
void dump_ops(const uint16_t *opc_buf, const TCGArg *opparam_buf);
TCGv_i32 tcg_const_i32(int32_t val);
TCGv_i64 tcg_const_i64(int64_t val);
TCGv_i32 tcg_const_local_i32(int32_t val);
TCGv_i64 tcg_const_local_i64(int64_t val);
void tcg_out_reloc(TCGContext *s, uint8_t *code_ptr, int type,
int label_index, long addend);
const TCGArg *tcg_gen_code_op(TCGContext *s, int opc, const TCGArg *args1,
unsigned int dead_iargs);
/* tcg-runtime.c */
int64_t tcg_helper_shl_i64(int64_t arg1, int64_t arg2);
int64_t tcg_helper_shr_i64(int64_t arg1, int64_t arg2);
int64_t tcg_helper_sar_i64(int64_t arg1, int64_t arg2);
int64_t tcg_helper_div_i64(int64_t arg1, int64_t arg2);
int64_t tcg_helper_rem_i64(int64_t arg1, int64_t arg2);
uint64_t tcg_helper_divu_i64(uint64_t arg1, uint64_t arg2);
uint64_t tcg_helper_remu_i64(uint64_t arg1, uint64_t arg2);
#ifndef VBOX
extern uint8_t code_gen_prologue[];
#else
extern uint8_t* code_gen_prologue;
#endif
#if defined(_ARCH_PPC) && !defined(_ARCH_PPC64)
#define tcg_qemu_tb_exec(tb_ptr) \
((long REGPARM __attribute__ ((longcall)) (*)(void *))code_gen_prologue)(tb_ptr)
#else
# if defined(VBOX) && defined(GCC_WITH_BUGGY_REGPARM)
# define tcg_qemu_tb_exec(tb_ptr, ret) \
__asm__ __volatile__("call *%%ecx" : "=a"(ret) : "a"(tb_ptr), "c" (&code_gen_prologue[0]) : "memory", "%edx", "cc")
# else /* !VBOX || !GCC_WITH_BUGGY_REG_PARAM */
#define tcg_qemu_tb_exec(tb_ptr) ((long REGPARM (*)(void *))code_gen_prologue)(tb_ptr)
# endif /* !VBOX || !GCC_WITH_BUGGY_REG_PARAM */
#endif