mirror of
				https://git.proxmox.com/git/qemu
				synced 2025-10-26 05:20:22 +00:00 
			
		
		
		
	 8ef935b22b
			
		
	
	
		8ef935b22b
		
	
	
	
	
		
			
			Signed-off-by: Stefan Weil <sw@weilnetz.de> Signed-off-by: Stefan Hajnoczi <stefanha@linux.vnet.ibm.com>
		
			
				
	
	
		
			594 lines
		
	
	
		
			18 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			594 lines
		
	
	
		
			18 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /*
 | |
|  * Tiny Code Generator for QEMU
 | |
|  *
 | |
|  * Copyright (c) 2008 Fabrice Bellard
 | |
|  *
 | |
|  * Permission is hereby granted, free of charge, to any person obtaining a copy
 | |
|  * of this software and associated documentation files (the "Software"), to deal
 | |
|  * in the Software without restriction, including without limitation the rights
 | |
|  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 | |
|  * copies of the Software, and to permit persons to whom the Software is
 | |
|  * furnished to do so, subject to the following conditions:
 | |
|  *
 | |
|  * The above copyright notice and this permission notice shall be included in
 | |
|  * all copies or substantial portions of the Software.
 | |
|  *
 | |
|  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 | |
|  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 | |
|  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
 | |
|  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 | |
|  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 | |
|  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 | |
|  * THE SOFTWARE.
 | |
|  */
 | |
| #include "qemu-common.h"
 | |
| 
 | |
| /* Target word size (must be identical to pointer size). */
 | |
| #if UINTPTR_MAX == UINT32_MAX
 | |
| # define TCG_TARGET_REG_BITS 32
 | |
| #elif UINTPTR_MAX == UINT64_MAX
 | |
| # define TCG_TARGET_REG_BITS 64
 | |
| #else
 | |
| # error Unknown pointer size for tcg target
 | |
| #endif
 | |
| 
 | |
| #include "tcg-target.h"
 | |
| #include "tcg-runtime.h"
 | |
| 
 | |
| #if TCG_TARGET_REG_BITS == 32
 | |
| typedef int32_t tcg_target_long;
 | |
| typedef uint32_t tcg_target_ulong;
 | |
| #define TCG_PRIlx PRIx32
 | |
| #define TCG_PRIld PRId32
 | |
| #elif TCG_TARGET_REG_BITS == 64
 | |
| typedef int64_t tcg_target_long;
 | |
| typedef uint64_t tcg_target_ulong;
 | |
| #define TCG_PRIlx PRIx64
 | |
| #define TCG_PRIld PRId64
 | |
| #else
 | |
| #error unsupported
 | |
| #endif
 | |
| 
 | |
| #if TCG_TARGET_NB_REGS <= 32
 | |
| typedef uint32_t TCGRegSet;
 | |
| #elif TCG_TARGET_NB_REGS <= 64
 | |
| typedef uint64_t TCGRegSet;
 | |
| #else
 | |
| #error unsupported
 | |
| #endif
 | |
| 
 | |
| /* Turn some undef macros into false macros.  */
 | |
| #if TCG_TARGET_REG_BITS == 32
 | |
| #define TCG_TARGET_HAS_div_i64          0
 | |
| #define TCG_TARGET_HAS_div2_i64         0
 | |
| #define TCG_TARGET_HAS_rot_i64          0
 | |
| #define TCG_TARGET_HAS_ext8s_i64        0
 | |
| #define TCG_TARGET_HAS_ext16s_i64       0
 | |
| #define TCG_TARGET_HAS_ext32s_i64       0
 | |
| #define TCG_TARGET_HAS_ext8u_i64        0
 | |
| #define TCG_TARGET_HAS_ext16u_i64       0
 | |
| #define TCG_TARGET_HAS_ext32u_i64       0
 | |
| #define TCG_TARGET_HAS_bswap16_i64      0
 | |
| #define TCG_TARGET_HAS_bswap32_i64      0
 | |
| #define TCG_TARGET_HAS_bswap64_i64      0
 | |
| #define TCG_TARGET_HAS_neg_i64          0
 | |
| #define TCG_TARGET_HAS_not_i64          0
 | |
| #define TCG_TARGET_HAS_andc_i64         0
 | |
| #define TCG_TARGET_HAS_orc_i64          0
 | |
| #define TCG_TARGET_HAS_eqv_i64          0
 | |
| #define TCG_TARGET_HAS_nand_i64         0
 | |
| #define TCG_TARGET_HAS_nor_i64          0
 | |
| #define TCG_TARGET_HAS_deposit_i64      0
 | |
| #endif
 | |
| 
 | |
| #ifndef TCG_TARGET_deposit_i32_valid
 | |
| #define TCG_TARGET_deposit_i32_valid(ofs, len) 1
 | |
| #endif
 | |
| #ifndef TCG_TARGET_deposit_i64_valid
 | |
| #define TCG_TARGET_deposit_i64_valid(ofs, len) 1
 | |
| #endif
 | |
| 
 | |
| /* Only one of DIV or DIV2 should be defined.  */
 | |
| #if defined(TCG_TARGET_HAS_div_i32)
 | |
| #define TCG_TARGET_HAS_div2_i32         0
 | |
| #elif defined(TCG_TARGET_HAS_div2_i32)
 | |
| #define TCG_TARGET_HAS_div_i32          0
 | |
| #endif
 | |
| #if defined(TCG_TARGET_HAS_div_i64)
 | |
| #define TCG_TARGET_HAS_div2_i64         0
 | |
| #elif defined(TCG_TARGET_HAS_div2_i64)
 | |
| #define TCG_TARGET_HAS_div_i64          0
 | |
| #endif
 | |
| 
 | |
| typedef enum TCGOpcode {
 | |
| #define DEF(name, oargs, iargs, cargs, flags) INDEX_op_ ## name,
 | |
| #include "tcg-opc.h"
 | |
| #undef DEF
 | |
|     NB_OPS,
 | |
| } TCGOpcode;
 | |
| 
 | |
| #define tcg_regset_clear(d) (d) = 0
 | |
| #define tcg_regset_set(d, s) (d) = (s)
 | |
| #define tcg_regset_set32(d, reg, val32) (d) |= (val32) << (reg)
 | |
| #define tcg_regset_set_reg(d, r) (d) |= 1L << (r)
 | |
| #define tcg_regset_reset_reg(d, r) (d) &= ~(1L << (r))
 | |
| #define tcg_regset_test_reg(d, r) (((d) >> (r)) & 1)
 | |
| #define tcg_regset_or(d, a, b) (d) = (a) | (b)
 | |
| #define tcg_regset_and(d, a, b) (d) = (a) & (b)
 | |
| #define tcg_regset_andnot(d, a, b) (d) = (a) & ~(b)
 | |
| #define tcg_regset_not(d, a) (d) = ~(a)
 | |
| 
 | |
| typedef struct TCGRelocation {
 | |
|     struct TCGRelocation *next;
 | |
|     int type;
 | |
|     uint8_t *ptr;
 | |
|     tcg_target_long addend;
 | |
| } TCGRelocation; 
 | |
| 
 | |
| typedef struct TCGLabel {
 | |
|     int has_value;
 | |
|     union {
 | |
|         tcg_target_ulong value;
 | |
|         TCGRelocation *first_reloc;
 | |
|     } u;
 | |
| } TCGLabel;
 | |
| 
 | |
| typedef struct TCGPool {
 | |
|     struct TCGPool *next;
 | |
|     int size;
 | |
|     uint8_t data[0] __attribute__ ((aligned));
 | |
| } TCGPool;
 | |
| 
 | |
| #define TCG_POOL_CHUNK_SIZE 32768
 | |
| 
 | |
| #define TCG_MAX_LABELS 512
 | |
| 
 | |
| #define TCG_MAX_TEMPS 512
 | |
| 
 | |
| /* when the size of the arguments of a called function is smaller than
 | |
|    this value, they are statically allocated in the TB stack frame */
 | |
| #define TCG_STATIC_CALL_ARGS_SIZE 128
 | |
| 
 | |
| typedef enum TCGType {
 | |
|     TCG_TYPE_I32,
 | |
|     TCG_TYPE_I64,
 | |
|     TCG_TYPE_COUNT, /* number of different types */
 | |
| 
 | |
|     /* An alias for the size of the host register.  */
 | |
| #if TCG_TARGET_REG_BITS == 32
 | |
|     TCG_TYPE_REG = TCG_TYPE_I32,
 | |
| #else
 | |
|     TCG_TYPE_REG = TCG_TYPE_I64,
 | |
| #endif
 | |
| 
 | |
|     /* An alias for the size of the native pointer.  We don't currently
 | |
|        support any hosts with 64-bit registers and 32-bit pointers.  */
 | |
|     TCG_TYPE_PTR = TCG_TYPE_REG,
 | |
| 
 | |
|     /* An alias for the size of the target "long", aka register.  */
 | |
| #if TARGET_LONG_BITS == 64
 | |
|     TCG_TYPE_TL = TCG_TYPE_I64,
 | |
| #else
 | |
|     TCG_TYPE_TL = TCG_TYPE_I32,
 | |
| #endif
 | |
| } TCGType;
 | |
| 
 | |
| typedef tcg_target_ulong TCGArg;
 | |
| 
 | |
| /* Define a type and accessor macros for variables.  Using a struct is
 | |
|    nice because it gives some level of type safely.  Ideally the compiler
 | |
|    be able to see through all this.  However in practice this is not true,
 | |
|    expecially on targets with braindamaged ABIs (e.g. i386).
 | |
|    We use plain int by default to avoid this runtime overhead.
 | |
|    Users of tcg_gen_* don't need to know about any of this, and should
 | |
|    treat TCGv as an opaque type.
 | |
|    In addition we do typechecking for different types of variables.  TCGv_i32
 | |
|    and TCGv_i64 are 32/64-bit variables respectively.  TCGv and TCGv_ptr
 | |
|    are aliases for target_ulong and host pointer sized values respectively.
 | |
|  */
 | |
| 
 | |
| #ifdef CONFIG_DEBUG_TCG
 | |
| #define DEBUG_TCGV 1
 | |
| #endif
 | |
| 
 | |
| #ifdef DEBUG_TCGV
 | |
| 
 | |
| typedef struct
 | |
| {
 | |
|     int i32;
 | |
| } TCGv_i32;
 | |
| 
 | |
| typedef struct
 | |
| {
 | |
|     int i64;
 | |
| } TCGv_i64;
 | |
| 
 | |
| typedef struct {
 | |
|     int iptr;
 | |
| } TCGv_ptr;
 | |
| 
 | |
| #define MAKE_TCGV_I32(i) __extension__                  \
 | |
|     ({ TCGv_i32 make_tcgv_tmp = {i}; make_tcgv_tmp;})
 | |
| #define MAKE_TCGV_I64(i) __extension__                  \
 | |
|     ({ TCGv_i64 make_tcgv_tmp = {i}; make_tcgv_tmp;})
 | |
| #define MAKE_TCGV_PTR(i) __extension__                  \
 | |
|     ({ TCGv_ptr make_tcgv_tmp = {i}; make_tcgv_tmp; })
 | |
| #define GET_TCGV_I32(t) ((t).i32)
 | |
| #define GET_TCGV_I64(t) ((t).i64)
 | |
| #define GET_TCGV_PTR(t) ((t).iptr)
 | |
| #if TCG_TARGET_REG_BITS == 32
 | |
| #define TCGV_LOW(t) MAKE_TCGV_I32(GET_TCGV_I64(t))
 | |
| #define TCGV_HIGH(t) MAKE_TCGV_I32(GET_TCGV_I64(t) + 1)
 | |
| #endif
 | |
| 
 | |
| #else /* !DEBUG_TCGV */
 | |
| 
 | |
| typedef int TCGv_i32;
 | |
| typedef int TCGv_i64;
 | |
| #if TCG_TARGET_REG_BITS == 32
 | |
| #define TCGv_ptr TCGv_i32
 | |
| #else
 | |
| #define TCGv_ptr TCGv_i64
 | |
| #endif
 | |
| #define MAKE_TCGV_I32(x) (x)
 | |
| #define MAKE_TCGV_I64(x) (x)
 | |
| #define MAKE_TCGV_PTR(x) (x)
 | |
| #define GET_TCGV_I32(t) (t)
 | |
| #define GET_TCGV_I64(t) (t)
 | |
| #define GET_TCGV_PTR(t) (t)
 | |
| 
 | |
| #if TCG_TARGET_REG_BITS == 32
 | |
| #define TCGV_LOW(t) (t)
 | |
| #define TCGV_HIGH(t) ((t) + 1)
 | |
| #endif
 | |
| 
 | |
| #endif /* DEBUG_TCGV */
 | |
| 
 | |
| #define TCGV_EQUAL_I32(a, b) (GET_TCGV_I32(a) == GET_TCGV_I32(b))
 | |
| #define TCGV_EQUAL_I64(a, b) (GET_TCGV_I64(a) == GET_TCGV_I64(b))
 | |
| 
 | |
| /* Dummy definition to avoid compiler warnings.  */
 | |
| #define TCGV_UNUSED_I32(x) x = MAKE_TCGV_I32(-1)
 | |
| #define TCGV_UNUSED_I64(x) x = MAKE_TCGV_I64(-1)
 | |
| 
 | |
| /* call flags */
 | |
| #define TCG_CALL_TYPE_MASK      0x000f
 | |
| #define TCG_CALL_TYPE_STD       0x0000 /* standard C call */
 | |
| #define TCG_CALL_TYPE_REGPARM_1 0x0001 /* i386 style regparm call (1 reg) */
 | |
| #define TCG_CALL_TYPE_REGPARM_2 0x0002 /* i386 style regparm call (2 regs) */
 | |
| #define TCG_CALL_TYPE_REGPARM   0x0003 /* i386 style regparm call (3 regs) */
 | |
| /* A pure function only reads its arguments and TCG global variables
 | |
|    and cannot raise exceptions. Hence a call to a pure function can be
 | |
|    safely suppressed if the return value is not used. */
 | |
| #define TCG_CALL_PURE           0x0010 
 | |
| /* A const function only reads its arguments and does not use TCG
 | |
|    global variables. Hence a call to such a function does not
 | |
|    save TCG global variables back to their canonical location. */
 | |
| #define TCG_CALL_CONST          0x0020
 | |
| 
 | |
| /* used to align parameters */
 | |
| #define TCG_CALL_DUMMY_TCGV     MAKE_TCGV_I32(-1)
 | |
| #define TCG_CALL_DUMMY_ARG      ((TCGArg)(-1))
 | |
| 
 | |
| typedef enum {
 | |
|     TCG_COND_EQ,
 | |
|     TCG_COND_NE,
 | |
|     TCG_COND_LT,
 | |
|     TCG_COND_GE,
 | |
|     TCG_COND_LE,
 | |
|     TCG_COND_GT,
 | |
|     /* unsigned */
 | |
|     TCG_COND_LTU,
 | |
|     TCG_COND_GEU,
 | |
|     TCG_COND_LEU,
 | |
|     TCG_COND_GTU,
 | |
| } TCGCond;
 | |
| 
 | |
| /* Invert the sense of the comparison.  */
 | |
| static inline TCGCond tcg_invert_cond(TCGCond c)
 | |
| {
 | |
|     return (TCGCond)(c ^ 1);
 | |
| }
 | |
| 
 | |
| /* Swap the operands in a comparison.  */
 | |
| static inline TCGCond tcg_swap_cond(TCGCond c)
 | |
| {
 | |
|     int mask = (c < TCG_COND_LT ? 0 : c < TCG_COND_LTU ? 7 : 15);
 | |
|     return (TCGCond)(c ^ mask);
 | |
| }
 | |
| 
 | |
| static inline TCGCond tcg_unsigned_cond(TCGCond c)
 | |
| {
 | |
|     return (c >= TCG_COND_LT && c <= TCG_COND_GT ? c + 4 : c);
 | |
| }
 | |
| 
 | |
| #define TEMP_VAL_DEAD  0
 | |
| #define TEMP_VAL_REG   1
 | |
| #define TEMP_VAL_MEM   2
 | |
| #define TEMP_VAL_CONST 3
 | |
| 
 | |
| /* XXX: optimize memory layout */
 | |
| typedef struct TCGTemp {
 | |
|     TCGType base_type;
 | |
|     TCGType type;
 | |
|     int val_type;
 | |
|     int reg;
 | |
|     tcg_target_long val;
 | |
|     int mem_reg;
 | |
|     tcg_target_long mem_offset;
 | |
|     unsigned int fixed_reg:1;
 | |
|     unsigned int mem_coherent:1;
 | |
|     unsigned int mem_allocated:1;
 | |
|     unsigned int temp_local:1; /* If true, the temp is saved across
 | |
|                                   basic blocks. Otherwise, it is not
 | |
|                                   preserved across basic blocks. */
 | |
|     unsigned int temp_allocated:1; /* never used for code gen */
 | |
|     /* index of next free temp of same base type, -1 if end */
 | |
|     int next_free_temp;
 | |
|     const char *name;
 | |
| } TCGTemp;
 | |
| 
 | |
| typedef struct TCGHelperInfo {
 | |
|     tcg_target_ulong func;
 | |
|     const char *name;
 | |
| } TCGHelperInfo;
 | |
| 
 | |
| typedef struct TCGContext TCGContext;
 | |
| 
 | |
| struct TCGContext {
 | |
|     uint8_t *pool_cur, *pool_end;
 | |
|     TCGPool *pool_first, *pool_current;
 | |
|     TCGLabel *labels;
 | |
|     int nb_labels;
 | |
|     TCGTemp *temps; /* globals first, temps after */
 | |
|     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;
 | |
|     unsigned long *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 */
 | |
|     
 | |
|     /* 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 static_temps[TCG_MAX_TEMPS];
 | |
| 
 | |
|     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 restore_count;
 | |
|     int64_t restore_time;
 | |
| #endif
 | |
| 
 | |
| #ifdef CONFIG_DEBUG_TCG
 | |
|     int temps_in_use;
 | |
| #endif
 | |
| };
 | |
| 
 | |
| extern TCGContext tcg_ctx;
 | |
| extern uint16_t *gen_opc_ptr;
 | |
| extern TCGArg *gen_opparam_ptr;
 | |
| extern uint16_t gen_opc_buf[];
 | |
| extern TCGArg gen_opparam_buf[];
 | |
| 
 | |
| /* pool based memory allocation */
 | |
| 
 | |
| void *tcg_malloc_internal(TCGContext *s, int size);
 | |
| void tcg_pool_reset(TCGContext *s);
 | |
| void tcg_pool_delete(TCGContext *s);
 | |
| 
 | |
| static inline void *tcg_malloc(int size)
 | |
| {
 | |
|     TCGContext *s = &tcg_ctx;
 | |
|     uint8_t *ptr, *ptr_end;
 | |
|     size = (size + sizeof(long) - 1) & ~(sizeof(long) - 1);
 | |
|     ptr = s->pool_cur;
 | |
|     ptr_end = ptr + size;
 | |
|     if (unlikely(ptr_end > s->pool_end)) {
 | |
|         return tcg_malloc_internal(&tcg_ctx, size);
 | |
|     } else {
 | |
|         s->pool_cur = ptr_end;
 | |
|         return ptr;
 | |
|     }
 | |
| }
 | |
| 
 | |
| void tcg_context_init(TCGContext *s);
 | |
| void tcg_prologue_init(TCGContext *s);
 | |
| void tcg_func_start(TCGContext *s);
 | |
| 
 | |
| int tcg_gen_code(TCGContext *s, uint8_t *gen_code_buf);
 | |
| int tcg_gen_code_search_pc(TCGContext *s, uint8_t *gen_code_buf, long offset);
 | |
| 
 | |
| void tcg_set_frame(TCGContext *s, int reg,
 | |
|                    tcg_target_long start, tcg_target_long size);
 | |
| 
 | |
| TCGv_i32 tcg_global_reg_new_i32(int reg, const char *name);
 | |
| TCGv_i32 tcg_global_mem_new_i32(int reg, tcg_target_long offset,
 | |
|                                 const char *name);
 | |
| TCGv_i32 tcg_temp_new_internal_i32(int temp_local);
 | |
| static inline TCGv_i32 tcg_temp_new_i32(void)
 | |
| {
 | |
|     return tcg_temp_new_internal_i32(0);
 | |
| }
 | |
| static inline TCGv_i32 tcg_temp_local_new_i32(void)
 | |
| {
 | |
|     return tcg_temp_new_internal_i32(1);
 | |
| }
 | |
| void tcg_temp_free_i32(TCGv_i32 arg);
 | |
| char *tcg_get_arg_str_i32(TCGContext *s, char *buf, int buf_size, TCGv_i32 arg);
 | |
| 
 | |
| TCGv_i64 tcg_global_reg_new_i64(int reg, const char *name);
 | |
| TCGv_i64 tcg_global_mem_new_i64(int reg, tcg_target_long offset,
 | |
|                                 const char *name);
 | |
| TCGv_i64 tcg_temp_new_internal_i64(int temp_local);
 | |
| static inline TCGv_i64 tcg_temp_new_i64(void)
 | |
| {
 | |
|     return tcg_temp_new_internal_i64(0);
 | |
| }
 | |
| static inline TCGv_i64 tcg_temp_local_new_i64(void)
 | |
| {
 | |
|     return tcg_temp_new_internal_i64(1);
 | |
| }
 | |
| void tcg_temp_free_i64(TCGv_i64 arg);
 | |
| char *tcg_get_arg_str_i64(TCGContext *s, char *buf, int buf_size, TCGv_i64 arg);
 | |
| 
 | |
| static inline bool tcg_arg_is_local(TCGContext *s, TCGArg arg)
 | |
| {
 | |
|     return s->temps[arg].temp_local;
 | |
| }
 | |
| 
 | |
| #if defined(CONFIG_DEBUG_TCG)
 | |
| /* If you call tcg_clear_temp_count() at the start of a section of
 | |
|  * code which is not supposed to leak any TCG temporaries, then
 | |
|  * calling tcg_check_temp_count() at the end of the section will
 | |
|  * return 1 if the section did in fact leak a temporary.
 | |
|  */
 | |
| void tcg_clear_temp_count(void);
 | |
| int tcg_check_temp_count(void);
 | |
| #else
 | |
| #define tcg_clear_temp_count() do { } while (0)
 | |
| #define tcg_check_temp_count() 0
 | |
| #endif
 | |
| 
 | |
| void tcg_dump_info(FILE *f, fprintf_function cpu_fprintf);
 | |
| 
 | |
| #define TCG_CT_ALIAS  0x80
 | |
| #define TCG_CT_IALIAS 0x40
 | |
| #define TCG_CT_REG    0x01
 | |
| #define TCG_CT_CONST  0x02 /* any constant of register size */
 | |
| 
 | |
| typedef struct TCGArgConstraint {
 | |
|     uint16_t ct;
 | |
|     uint8_t alias_index;
 | |
|     union {
 | |
|         TCGRegSet regs;
 | |
|     } u;
 | |
| } TCGArgConstraint;
 | |
| 
 | |
| #define TCG_MAX_OP_ARGS 16
 | |
| 
 | |
| /* Bits for TCGOpDef->flags, 8 bits available.  */
 | |
| enum {
 | |
|     /* Instruction defines the end of a basic block.  */
 | |
|     TCG_OPF_BB_END       = 0x01,
 | |
|     /* Instruction clobbers call registers and potentially update globals.  */
 | |
|     TCG_OPF_CALL_CLOBBER = 0x02,
 | |
|     /* Instruction has side effects: it cannot be removed
 | |
|        if its outputs are not used.  */
 | |
|     TCG_OPF_SIDE_EFFECTS = 0x04,
 | |
|     /* Instruction operands are 64-bits (otherwise 32-bits).  */
 | |
|     TCG_OPF_64BIT        = 0x08,
 | |
|     /* Instruction is optional and not implemented by the host.  */
 | |
|     TCG_OPF_NOT_PRESENT  = 0x10,
 | |
| };
 | |
| 
 | |
| typedef struct TCGOpDef {
 | |
|     const char *name;
 | |
|     uint8_t nb_oargs, nb_iargs, nb_cargs, nb_args;
 | |
|     uint8_t flags;
 | |
|     TCGArgConstraint *args_ct;
 | |
|     int *sorted_args;
 | |
| #if defined(CONFIG_DEBUG_TCG)
 | |
|     int used;
 | |
| #endif
 | |
| } TCGOpDef;
 | |
| 
 | |
| extern TCGOpDef tcg_op_defs[];
 | |
|         
 | |
| typedef struct TCGTargetOpDef {
 | |
|     TCGOpcode op;
 | |
|     const char *args_ct_str[TCG_MAX_OP_ARGS];
 | |
| } TCGTargetOpDef;
 | |
| 
 | |
| #define tcg_abort() \
 | |
| do {\
 | |
|     fprintf(stderr, "%s:%d: tcg fatal error\n", __FILE__, __LINE__);\
 | |
|     abort();\
 | |
| } while (0)
 | |
| 
 | |
| void tcg_add_target_add_op_defs(const TCGTargetOpDef *tdefs);
 | |
| 
 | |
| #if TCG_TARGET_REG_BITS == 32
 | |
| #define TCGV_NAT_TO_PTR(n) MAKE_TCGV_PTR(GET_TCGV_I32(n))
 | |
| #define TCGV_PTR_TO_NAT(n) MAKE_TCGV_I32(GET_TCGV_PTR(n))
 | |
| 
 | |
| #define tcg_const_ptr(V) TCGV_NAT_TO_PTR(tcg_const_i32(V))
 | |
| #define tcg_global_reg_new_ptr(R, N) \
 | |
|     TCGV_NAT_TO_PTR(tcg_global_reg_new_i32((R), (N)))
 | |
| #define tcg_global_mem_new_ptr(R, O, N) \
 | |
|     TCGV_NAT_TO_PTR(tcg_global_mem_new_i32((R), (O), (N)))
 | |
| #define tcg_temp_new_ptr() TCGV_NAT_TO_PTR(tcg_temp_new_i32())
 | |
| #define tcg_temp_free_ptr(T) tcg_temp_free_i32(TCGV_PTR_TO_NAT(T))
 | |
| #else
 | |
| #define TCGV_NAT_TO_PTR(n) MAKE_TCGV_PTR(GET_TCGV_I64(n))
 | |
| #define TCGV_PTR_TO_NAT(n) MAKE_TCGV_I64(GET_TCGV_PTR(n))
 | |
| 
 | |
| #define tcg_const_ptr(V) TCGV_NAT_TO_PTR(tcg_const_i64(V))
 | |
| #define tcg_global_reg_new_ptr(R, N) \
 | |
|     TCGV_NAT_TO_PTR(tcg_global_reg_new_i64((R), (N)))
 | |
| #define tcg_global_mem_new_ptr(R, O, N) \
 | |
|     TCGV_NAT_TO_PTR(tcg_global_mem_new_i64((R), (O), (N)))
 | |
| #define tcg_temp_new_ptr() TCGV_NAT_TO_PTR(tcg_temp_new_i64())
 | |
| #define tcg_temp_free_ptr(T) tcg_temp_free_i64(TCGV_PTR_TO_NAT(T))
 | |
| #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);
 | |
| 
 | |
| TCGArg *tcg_optimize(TCGContext *s, uint16_t *tcg_opc_ptr, TCGArg *args,
 | |
|                      TCGOpDef *tcg_op_def);
 | |
| 
 | |
| /* 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);
 | |
| 
 | |
| extern uint8_t code_gen_prologue[];
 | |
| #if defined(_ARCH_PPC) && !defined(_ARCH_PPC64)
 | |
| #define tcg_qemu_tb_exec(env, tb_ptr)                                    \
 | |
|     ((long REGPARM __attribute__ ((longcall)) (*)(void *, void *))code_gen_prologue)(env, tb_ptr)
 | |
| #else
 | |
| #define tcg_qemu_tb_exec(env, tb_ptr)                                    \
 | |
|     ((long REGPARM (*)(void *, void *))code_gen_prologue)(env, tb_ptr)
 | |
| #endif
 |