mirror of https://github.com/xemu-project/xemu.git
fixed global variable handling with qemu load/stores - initial global prologue/epilogue implementation
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@4406 c046a42c-6fe2-441c-8c8c-71466251a162
This commit is contained in:
parent
4d7a0880ca
commit
b03cce8e08
|
@ -46,6 +46,8 @@ int tcg_target_reg_alloc_order[] = {
|
||||||
const int tcg_target_call_iarg_regs[3] = { TCG_REG_EAX, TCG_REG_EDX, TCG_REG_ECX };
|
const int tcg_target_call_iarg_regs[3] = { TCG_REG_EAX, TCG_REG_EDX, TCG_REG_ECX };
|
||||||
const int tcg_target_call_oarg_regs[2] = { TCG_REG_EAX, TCG_REG_EDX };
|
const int tcg_target_call_oarg_regs[2] = { TCG_REG_EAX, TCG_REG_EDX };
|
||||||
|
|
||||||
|
static uint8_t *tb_ret_addr;
|
||||||
|
|
||||||
static void patch_reloc(uint8_t *code_ptr, int type,
|
static void patch_reloc(uint8_t *code_ptr, int type,
|
||||||
tcg_target_long value, tcg_target_long addend)
|
tcg_target_long value, tcg_target_long addend)
|
||||||
{
|
{
|
||||||
|
@ -879,7 +881,8 @@ static inline void tcg_out_op(TCGContext *s, int opc,
|
||||||
switch(opc) {
|
switch(opc) {
|
||||||
case INDEX_op_exit_tb:
|
case INDEX_op_exit_tb:
|
||||||
tcg_out_movi(s, TCG_TYPE_I32, TCG_REG_EAX, args[0]);
|
tcg_out_movi(s, TCG_TYPE_I32, TCG_REG_EAX, args[0]);
|
||||||
tcg_out8(s, 0xc3); /* ret */
|
tcg_out8(s, 0xe9); /* jmp tb_ret_addr */
|
||||||
|
tcg_out32(s, tb_ret_addr - s->code_ptr - 4);
|
||||||
break;
|
break;
|
||||||
case INDEX_op_goto_tb:
|
case INDEX_op_goto_tb:
|
||||||
if (s->tb_jmp_offset) {
|
if (s->tb_jmp_offset) {
|
||||||
|
@ -1145,6 +1148,53 @@ static const TCGTargetOpDef x86_op_defs[] = {
|
||||||
{ -1 },
|
{ -1 },
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static int tcg_target_callee_save_regs[] = {
|
||||||
|
/* TCG_REG_EBP, */ /* currently used for the global env, so no
|
||||||
|
need to save */
|
||||||
|
TCG_REG_EBX,
|
||||||
|
TCG_REG_ESI,
|
||||||
|
TCG_REG_EDI,
|
||||||
|
};
|
||||||
|
|
||||||
|
static inline void tcg_out_push(TCGContext *s, int reg)
|
||||||
|
{
|
||||||
|
tcg_out_opc(s, 0x50 + reg);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void tcg_out_pop(TCGContext *s, int reg)
|
||||||
|
{
|
||||||
|
tcg_out_opc(s, 0x58 + reg);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Generate global QEMU prologue and epilogue code */
|
||||||
|
void tcg_target_qemu_prologue(TCGContext *s)
|
||||||
|
{
|
||||||
|
int i, frame_size, push_size, stack_addend;
|
||||||
|
|
||||||
|
/* TB prologue */
|
||||||
|
/* save all callee saved registers */
|
||||||
|
for(i = 0; i < ARRAY_SIZE(tcg_target_callee_save_regs); i++) {
|
||||||
|
tcg_out_push(s, tcg_target_callee_save_regs[i]);
|
||||||
|
}
|
||||||
|
/* reserve some stack space */
|
||||||
|
push_size = 4 + ARRAY_SIZE(tcg_target_callee_save_regs) * 4;
|
||||||
|
frame_size = push_size + TCG_STATIC_CALL_ARGS_SIZE;
|
||||||
|
frame_size = (frame_size + TCG_TARGET_STACK_ALIGN - 1) &
|
||||||
|
~(TCG_TARGET_STACK_ALIGN - 1);
|
||||||
|
stack_addend = frame_size - push_size;
|
||||||
|
tcg_out_addi(s, TCG_REG_ESP, -stack_addend);
|
||||||
|
|
||||||
|
tcg_out_modrm(s, 0xff, 4, TCG_REG_EAX); /* jmp *%eax */
|
||||||
|
|
||||||
|
/* TB epilogue */
|
||||||
|
tb_ret_addr = s->code_ptr;
|
||||||
|
tcg_out_addi(s, TCG_REG_ESP, stack_addend);
|
||||||
|
for(i = ARRAY_SIZE(tcg_target_callee_save_regs) - 1; i >= 0; i--) {
|
||||||
|
tcg_out_pop(s, tcg_target_callee_save_regs[i]);
|
||||||
|
}
|
||||||
|
tcg_out8(s, 0xc3); /* ret */
|
||||||
|
}
|
||||||
|
|
||||||
void tcg_target_init(TCGContext *s)
|
void tcg_target_init(TCGContext *s)
|
||||||
{
|
{
|
||||||
/* fail safe */
|
/* fail safe */
|
||||||
|
|
149
tcg/tcg.c
149
tcg/tcg.c
|
@ -242,6 +242,13 @@ void tcg_context_init(TCGContext *s)
|
||||||
}
|
}
|
||||||
|
|
||||||
tcg_target_init(s);
|
tcg_target_init(s);
|
||||||
|
|
||||||
|
/* init global prologue and epilogue */
|
||||||
|
s->code_buf = code_gen_prologue;
|
||||||
|
s->code_ptr = s->code_buf;
|
||||||
|
tcg_target_qemu_prologue(s);
|
||||||
|
flush_icache_range((unsigned long)s->code_buf,
|
||||||
|
(unsigned long)s->code_ptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
void tcg_set_frame(TCGContext *s, int reg,
|
void tcg_set_frame(TCGContext *s, int reg,
|
||||||
|
@ -680,36 +687,57 @@ void tcg_dump_ops(TCGContext *s, FILE *outfile)
|
||||||
nb_oargs = arg >> 16;
|
nb_oargs = arg >> 16;
|
||||||
nb_iargs = arg & 0xffff;
|
nb_iargs = arg & 0xffff;
|
||||||
nb_cargs = def->nb_cargs;
|
nb_cargs = def->nb_cargs;
|
||||||
} else if (c == INDEX_op_nopn) {
|
|
||||||
/* variable number of arguments */
|
|
||||||
nb_cargs = *args;
|
|
||||||
nb_oargs = 0;
|
|
||||||
nb_iargs = 0;
|
|
||||||
} else {
|
|
||||||
nb_oargs = def->nb_oargs;
|
|
||||||
nb_iargs = def->nb_iargs;
|
|
||||||
nb_cargs = def->nb_cargs;
|
|
||||||
}
|
|
||||||
|
|
||||||
k = 0;
|
/* function name */
|
||||||
for(i = 0; i < nb_oargs; i++) {
|
|
||||||
if (k != 0)
|
|
||||||
fprintf(outfile, ",");
|
|
||||||
fprintf(outfile, "%s",
|
|
||||||
tcg_get_arg_str_idx(s, buf, sizeof(buf), args[k++]));
|
|
||||||
}
|
|
||||||
for(i = 0; i < nb_iargs; i++) {
|
|
||||||
if (k != 0)
|
|
||||||
fprintf(outfile, ",");
|
|
||||||
/* XXX: dump helper name for call */
|
/* XXX: dump helper name for call */
|
||||||
fprintf(outfile, "%s",
|
fprintf(outfile, "%s",
|
||||||
tcg_get_arg_str_idx(s, buf, sizeof(buf), args[k++]));
|
tcg_get_arg_str_idx(s, buf, sizeof(buf), args[nb_oargs + nb_iargs - 1]));
|
||||||
}
|
/* flags */
|
||||||
for(i = 0; i < nb_cargs; i++) {
|
fprintf(outfile, ",$0x%" TCG_PRIlx,
|
||||||
if (k != 0)
|
args[nb_oargs + nb_iargs]);
|
||||||
|
/* nb out args */
|
||||||
|
fprintf(outfile, ",$%d", nb_oargs);
|
||||||
|
for(i = 0; i < nb_oargs; i++) {
|
||||||
fprintf(outfile, ",");
|
fprintf(outfile, ",");
|
||||||
arg = args[k++];
|
fprintf(outfile, "%s",
|
||||||
fprintf(outfile, "$0x%" TCG_PRIlx, arg);
|
tcg_get_arg_str_idx(s, buf, sizeof(buf), args[i]));
|
||||||
|
}
|
||||||
|
for(i = 0; i < (nb_iargs - 1); i++) {
|
||||||
|
fprintf(outfile, ",");
|
||||||
|
fprintf(outfile, "%s",
|
||||||
|
tcg_get_arg_str_idx(s, buf, sizeof(buf), args[nb_oargs + i]));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (c == INDEX_op_nopn) {
|
||||||
|
/* variable number of arguments */
|
||||||
|
nb_cargs = *args;
|
||||||
|
nb_oargs = 0;
|
||||||
|
nb_iargs = 0;
|
||||||
|
} else {
|
||||||
|
nb_oargs = def->nb_oargs;
|
||||||
|
nb_iargs = def->nb_iargs;
|
||||||
|
nb_cargs = def->nb_cargs;
|
||||||
|
}
|
||||||
|
|
||||||
|
k = 0;
|
||||||
|
for(i = 0; i < nb_oargs; i++) {
|
||||||
|
if (k != 0)
|
||||||
|
fprintf(outfile, ",");
|
||||||
|
fprintf(outfile, "%s",
|
||||||
|
tcg_get_arg_str_idx(s, buf, sizeof(buf), args[k++]));
|
||||||
|
}
|
||||||
|
for(i = 0; i < nb_iargs; i++) {
|
||||||
|
if (k != 0)
|
||||||
|
fprintf(outfile, ",");
|
||||||
|
fprintf(outfile, "%s",
|
||||||
|
tcg_get_arg_str_idx(s, buf, sizeof(buf), args[k++]));
|
||||||
|
}
|
||||||
|
for(i = 0; i < nb_cargs; i++) {
|
||||||
|
if (k != 0)
|
||||||
|
fprintf(outfile, ",");
|
||||||
|
arg = args[k++];
|
||||||
|
fprintf(outfile, "$0x%" TCG_PRIlx, arg);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
fprintf(outfile, "\n");
|
fprintf(outfile, "\n");
|
||||||
args += nb_iargs + nb_oargs + nb_cargs;
|
args += nb_iargs + nb_oargs + nb_cargs;
|
||||||
|
@ -1027,6 +1055,9 @@ void tcg_liveness_analysis(TCGContext *s)
|
||||||
/* if end of basic block, update */
|
/* if end of basic block, update */
|
||||||
if (def->flags & TCG_OPF_BB_END) {
|
if (def->flags & TCG_OPF_BB_END) {
|
||||||
tcg_la_bb_end(s, dead_temps);
|
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 */
|
/* input args are live */
|
||||||
|
@ -1119,9 +1150,7 @@ static void check_regs(TCGContext *s)
|
||||||
ts->reg != reg) {
|
ts->reg != reg) {
|
||||||
printf("Inconsistency for register %s:\n",
|
printf("Inconsistency for register %s:\n",
|
||||||
tcg_target_reg_names[reg]);
|
tcg_target_reg_names[reg]);
|
||||||
printf("reg state:\n");
|
goto fail;
|
||||||
dump_regs(s);
|
|
||||||
tcg_abort();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1132,10 +1161,16 @@ static void check_regs(TCGContext *s)
|
||||||
s->reg_to_temp[ts->reg] != k) {
|
s->reg_to_temp[ts->reg] != k) {
|
||||||
printf("Inconsistency for temp %s:\n",
|
printf("Inconsistency for temp %s:\n",
|
||||||
tcg_get_arg_str_idx(s, buf, sizeof(buf), k));
|
tcg_get_arg_str_idx(s, buf, sizeof(buf), k));
|
||||||
|
fail:
|
||||||
printf("reg state:\n");
|
printf("reg state:\n");
|
||||||
dump_regs(s);
|
dump_regs(s);
|
||||||
tcg_abort();
|
tcg_abort();
|
||||||
}
|
}
|
||||||
|
if (ts->val_type == TEMP_VAL_CONST && k < s->nb_globals) {
|
||||||
|
printf("constant forbidden in global %s\n",
|
||||||
|
tcg_get_arg_str_idx(s, buf, sizeof(buf), k));
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@ -1376,13 +1411,26 @@ static void tcg_reg_alloc_op(TCGContext *s,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* XXX: permit generic clobber register list ? */
|
|
||||||
if (def->flags & TCG_OPF_CALL_CLOBBER) {
|
if (def->flags & TCG_OPF_CALL_CLOBBER) {
|
||||||
|
/* XXX: permit generic clobber register list ? */
|
||||||
for(reg = 0; reg < TCG_TARGET_NB_REGS; reg++) {
|
for(reg = 0; reg < TCG_TARGET_NB_REGS; reg++) {
|
||||||
if (tcg_regset_test_reg(tcg_target_call_clobber_regs, reg)) {
|
if (tcg_regset_test_reg(tcg_target_call_clobber_regs, reg)) {
|
||||||
tcg_reg_free(s, reg);
|
tcg_reg_free(s, reg);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
/* XXX: for load/store we could do that only for the slow path
|
||||||
|
(i.e. when a memory callback is called) */
|
||||||
|
|
||||||
|
/* store globals and free associated registers (we assume the insn
|
||||||
|
can modify any global. */
|
||||||
|
for(i = 0; i < s->nb_globals; i++) {
|
||||||
|
ts = &s->temps[i];
|
||||||
|
if (!ts->fixed_reg) {
|
||||||
|
if (ts->val_type == TEMP_VAL_REG) {
|
||||||
|
tcg_reg_free(s, ts->reg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* satisfy the output constraints */
|
/* satisfy the output constraints */
|
||||||
|
@ -1435,6 +1483,12 @@ static void tcg_reg_alloc_op(TCGContext *s,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef TCG_TARGET_STACK_GROWSUP
|
||||||
|
#define STACK_DIR(x) (-(x))
|
||||||
|
#else
|
||||||
|
#define STACK_DIR(x) (x)
|
||||||
|
#endif
|
||||||
|
|
||||||
static int tcg_reg_alloc_call(TCGContext *s, const TCGOpDef *def,
|
static int tcg_reg_alloc_call(TCGContext *s, const TCGOpDef *def,
|
||||||
int opc, const TCGArg *args,
|
int opc, const TCGArg *args,
|
||||||
unsigned int dead_iargs)
|
unsigned int dead_iargs)
|
||||||
|
@ -1443,7 +1497,7 @@ static int tcg_reg_alloc_call(TCGContext *s, const TCGOpDef *def,
|
||||||
TCGArg arg, func_arg;
|
TCGArg arg, func_arg;
|
||||||
TCGTemp *ts;
|
TCGTemp *ts;
|
||||||
tcg_target_long stack_offset, call_stack_size, func_addr;
|
tcg_target_long stack_offset, call_stack_size, func_addr;
|
||||||
int const_func_arg;
|
int const_func_arg, allocate_args;
|
||||||
TCGRegSet allocated_regs;
|
TCGRegSet allocated_regs;
|
||||||
const TCGArgConstraint *arg_ct;
|
const TCGArgConstraint *arg_ct;
|
||||||
|
|
||||||
|
@ -1464,12 +1518,11 @@ static int tcg_reg_alloc_call(TCGContext *s, const TCGOpDef *def,
|
||||||
call_stack_size = (nb_params - nb_regs) * sizeof(tcg_target_long);
|
call_stack_size = (nb_params - nb_regs) * sizeof(tcg_target_long);
|
||||||
call_stack_size = (call_stack_size + TCG_TARGET_STACK_ALIGN - 1) &
|
call_stack_size = (call_stack_size + TCG_TARGET_STACK_ALIGN - 1) &
|
||||||
~(TCG_TARGET_STACK_ALIGN - 1);
|
~(TCG_TARGET_STACK_ALIGN - 1);
|
||||||
#ifdef TCG_TARGET_STACK_GROWSUP
|
allocate_args = (call_stack_size > TCG_STATIC_CALL_ARGS_SIZE);
|
||||||
tcg_out_addi(s, TCG_REG_CALL_STACK, call_stack_size);
|
if (allocate_args) {
|
||||||
#else
|
tcg_out_addi(s, TCG_REG_CALL_STACK, -STACK_DIR(call_stack_size));
|
||||||
tcg_out_addi(s, TCG_REG_CALL_STACK, -call_stack_size);
|
}
|
||||||
#endif
|
/* XXX: on some architectures it does not start at zero */
|
||||||
|
|
||||||
stack_offset = 0;
|
stack_offset = 0;
|
||||||
for(i = nb_regs; i < nb_params; i++) {
|
for(i = nb_regs; i < nb_params; i++) {
|
||||||
arg = args[nb_oargs + i];
|
arg = args[nb_oargs + i];
|
||||||
|
@ -1491,11 +1544,8 @@ static int tcg_reg_alloc_call(TCGContext *s, const TCGOpDef *def,
|
||||||
} else {
|
} else {
|
||||||
tcg_abort();
|
tcg_abort();
|
||||||
}
|
}
|
||||||
#ifdef TCG_TARGET_STACK_GROWSUP
|
/* XXX: not necessarily in the same order */
|
||||||
stack_offset -= sizeof(tcg_target_long);
|
stack_offset += STACK_DIR(sizeof(tcg_target_long));
|
||||||
#else
|
|
||||||
stack_offset += sizeof(tcg_target_long);
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* assign input registers */
|
/* assign input registers */
|
||||||
|
@ -1525,9 +1575,6 @@ static int tcg_reg_alloc_call(TCGContext *s, const TCGOpDef *def,
|
||||||
arg_ct = &def->args_ct[0];
|
arg_ct = &def->args_ct[0];
|
||||||
ts = &s->temps[func_arg];
|
ts = &s->temps[func_arg];
|
||||||
func_addr = ts->val;
|
func_addr = ts->val;
|
||||||
#ifdef HOST_HPPA
|
|
||||||
func_addr = (tcg_target_long)__canonicalize_funcptr_for_compare((void *)func_addr);
|
|
||||||
#endif
|
|
||||||
const_func_arg = 0;
|
const_func_arg = 0;
|
||||||
if (ts->val_type == TEMP_VAL_MEM) {
|
if (ts->val_type == TEMP_VAL_MEM) {
|
||||||
reg = tcg_reg_alloc(s, arg_ct->u.regs, allocated_regs);
|
reg = tcg_reg_alloc(s, arg_ct->u.regs, allocated_regs);
|
||||||
|
@ -1586,11 +1633,9 @@ static int tcg_reg_alloc_call(TCGContext *s, const TCGOpDef *def,
|
||||||
|
|
||||||
tcg_out_op(s, opc, &func_arg, &const_func_arg);
|
tcg_out_op(s, opc, &func_arg, &const_func_arg);
|
||||||
|
|
||||||
#ifdef TCG_TARGET_STACK_GROWSUP
|
if (allocate_args) {
|
||||||
tcg_out_addi(s, TCG_REG_CALL_STACK, -call_stack_size);
|
tcg_out_addi(s, TCG_REG_CALL_STACK, STACK_DIR(call_stack_size));
|
||||||
#else
|
}
|
||||||
tcg_out_addi(s, TCG_REG_CALL_STACK, call_stack_size);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* assign output registers and emit moves if needed */
|
/* assign output registers and emit moves if needed */
|
||||||
for(i = 0; i < nb_oargs; i++) {
|
for(i = 0; i < nb_oargs; i++) {
|
||||||
|
@ -1672,10 +1717,6 @@ static inline int tcg_gen_code_common(TCGContext *s, uint8_t *gen_code_buf,
|
||||||
args = gen_opparam_buf;
|
args = gen_opparam_buf;
|
||||||
op_index = 0;
|
op_index = 0;
|
||||||
|
|
||||||
#ifdef TCG_TARGET_NEEDS_PROLOGUE
|
|
||||||
tcg_target_prologue(s);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
for(;;) {
|
for(;;) {
|
||||||
opc = gen_opc_buf[op_index];
|
opc = gen_opc_buf[op_index];
|
||||||
#ifdef CONFIG_PROFILER
|
#ifdef CONFIG_PROFILER
|
||||||
|
|
15
tcg/tcg.h
15
tcg/tcg.h
|
@ -90,6 +90,10 @@ typedef struct TCGPool {
|
||||||
|
|
||||||
#define TCG_MAX_TEMPS 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 int TCGType;
|
typedef int TCGType;
|
||||||
|
|
||||||
#define TCG_TYPE_I32 0
|
#define TCG_TYPE_I32 0
|
||||||
|
@ -285,8 +289,11 @@ typedef struct TCGArgConstraint {
|
||||||
|
|
||||||
#define TCG_OPF_BB_END 0x01 /* instruction defines the end of a basic
|
#define TCG_OPF_BB_END 0x01 /* instruction defines the end of a basic
|
||||||
block */
|
block */
|
||||||
#define TCG_OPF_CALL_CLOBBER 0x02 /* instruction clobbers call registers */
|
#define TCG_OPF_CALL_CLOBBER 0x02 /* instruction clobbers call registers
|
||||||
#define TCG_OPF_SIDE_EFFECTS 0x04 /* instruction has side effects */
|
and potentially update globals. */
|
||||||
|
#define TCG_OPF_SIDE_EFFECTS 0x04 /* instruction has side effects : it
|
||||||
|
cannot be removed if its output
|
||||||
|
are not used */
|
||||||
|
|
||||||
typedef struct TCGOpDef {
|
typedef struct TCGOpDef {
|
||||||
const char *name;
|
const char *name;
|
||||||
|
@ -305,6 +312,7 @@ typedef struct TCGTargetOpDef {
|
||||||
extern TCGOpDef tcg_op_defs[];
|
extern TCGOpDef tcg_op_defs[];
|
||||||
|
|
||||||
void tcg_target_init(TCGContext *s);
|
void tcg_target_init(TCGContext *s);
|
||||||
|
void tcg_target_qemu_prologue(TCGContext *s);
|
||||||
|
|
||||||
#define tcg_abort() \
|
#define tcg_abort() \
|
||||||
do {\
|
do {\
|
||||||
|
@ -358,3 +366,6 @@ int64_t tcg_helper_div_i64(int64_t arg1, int64_t arg2);
|
||||||
int64_t tcg_helper_rem_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_divu_i64(uint64_t arg1, uint64_t arg2);
|
||||||
uint64_t tcg_helper_remu_i64(uint64_t arg1, uint64_t arg2);
|
uint64_t tcg_helper_remu_i64(uint64_t arg1, uint64_t arg2);
|
||||||
|
|
||||||
|
extern uint8_t code_gen_prologue[];
|
||||||
|
#define tcg_qemu_tb_exec(tb_ptr) ((long REGPARM (*)(void *))code_gen_prologue)(tb_ptr)
|
||||||
|
|
|
@ -73,6 +73,8 @@ const int tcg_target_call_oarg_regs[2] = {
|
||||||
TCG_REG_RDX
|
TCG_REG_RDX
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static uint8_t *tb_ret_addr;
|
||||||
|
|
||||||
static void patch_reloc(uint8_t *code_ptr, int type,
|
static void patch_reloc(uint8_t *code_ptr, int type,
|
||||||
tcg_target_long value, tcg_target_long addend)
|
tcg_target_long value, tcg_target_long addend)
|
||||||
{
|
{
|
||||||
|
@ -841,7 +843,8 @@ static inline void tcg_out_op(TCGContext *s, int opc, const TCGArg *args,
|
||||||
switch(opc) {
|
switch(opc) {
|
||||||
case INDEX_op_exit_tb:
|
case INDEX_op_exit_tb:
|
||||||
tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_RAX, args[0]);
|
tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_RAX, args[0]);
|
||||||
tcg_out8(s, 0xc3); /* ret */
|
tcg_out8(s, 0xe9); /* jmp tb_ret_addr */
|
||||||
|
tcg_out32(s, tb_ret_addr - s->code_ptr - 4);
|
||||||
break;
|
break;
|
||||||
case INDEX_op_goto_tb:
|
case INDEX_op_goto_tb:
|
||||||
if (s->tb_jmp_offset) {
|
if (s->tb_jmp_offset) {
|
||||||
|
@ -1129,6 +1132,58 @@ static inline void tcg_out_op(TCGContext *s, int opc, const TCGArg *args,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int tcg_target_callee_save_regs[] = {
|
||||||
|
TCG_REG_R10,
|
||||||
|
TCG_REG_R11,
|
||||||
|
TCG_REG_RBP,
|
||||||
|
TCG_REG_RBX,
|
||||||
|
TCG_REG_R12,
|
||||||
|
TCG_REG_R13,
|
||||||
|
/* TCG_REG_R14, */ /* currently used for the global env, so no
|
||||||
|
need to save */
|
||||||
|
TCG_REG_R15,
|
||||||
|
};
|
||||||
|
|
||||||
|
static inline void tcg_out_push(TCGContext *s, int reg)
|
||||||
|
{
|
||||||
|
tcg_out_opc(s, (0x50 + (reg & 7)), 0, reg, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void tcg_out_pop(TCGContext *s, int reg)
|
||||||
|
{
|
||||||
|
tcg_out_opc(s, (0x58 + (reg & 7)), 0, reg, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Generate global QEMU prologue and epilogue code */
|
||||||
|
void tcg_target_qemu_prologue(TCGContext *s)
|
||||||
|
{
|
||||||
|
int i, frame_size, push_size, stack_addend;
|
||||||
|
|
||||||
|
/* TB prologue */
|
||||||
|
/* save all callee saved registers */
|
||||||
|
for(i = 0; i < ARRAY_SIZE(tcg_target_callee_save_regs); i++) {
|
||||||
|
tcg_out_push(s, tcg_target_callee_save_regs[i]);
|
||||||
|
|
||||||
|
}
|
||||||
|
/* reserve some stack space */
|
||||||
|
push_size = 8 + ARRAY_SIZE(tcg_target_callee_save_regs) * 8;
|
||||||
|
frame_size = push_size + TCG_STATIC_CALL_ARGS_SIZE;
|
||||||
|
frame_size = (frame_size + TCG_TARGET_STACK_ALIGN - 1) &
|
||||||
|
~(TCG_TARGET_STACK_ALIGN - 1);
|
||||||
|
stack_addend = frame_size - push_size;
|
||||||
|
tcg_out_addi(s, TCG_REG_RSP, -stack_addend);
|
||||||
|
|
||||||
|
tcg_out_modrm(s, 0xff, 4, TCG_REG_RDI); /* jmp *%rdi */
|
||||||
|
|
||||||
|
/* TB epilogue */
|
||||||
|
tb_ret_addr = s->code_ptr;
|
||||||
|
tcg_out_addi(s, TCG_REG_RSP, stack_addend);
|
||||||
|
for(i = ARRAY_SIZE(tcg_target_callee_save_regs) - 1; i >= 0; i--) {
|
||||||
|
tcg_out_pop(s, tcg_target_callee_save_regs[i]);
|
||||||
|
}
|
||||||
|
tcg_out8(s, 0xc3); /* ret */
|
||||||
|
}
|
||||||
|
|
||||||
static const TCGTargetOpDef x86_64_op_defs[] = {
|
static const TCGTargetOpDef x86_64_op_defs[] = {
|
||||||
{ INDEX_op_exit_tb, { } },
|
{ INDEX_op_exit_tb, { } },
|
||||||
{ INDEX_op_goto_tb, { } },
|
{ INDEX_op_goto_tb, { } },
|
||||||
|
@ -1212,6 +1267,10 @@ static const TCGTargetOpDef x86_64_op_defs[] = {
|
||||||
|
|
||||||
void tcg_target_init(TCGContext *s)
|
void tcg_target_init(TCGContext *s)
|
||||||
{
|
{
|
||||||
|
/* fail safe */
|
||||||
|
if ((1 << CPU_TLB_ENTRY_BITS) != sizeof(CPUTLBEntry))
|
||||||
|
tcg_abort();
|
||||||
|
|
||||||
tcg_regset_set32(tcg_target_available_regs[TCG_TYPE_I32], 0, 0xffff);
|
tcg_regset_set32(tcg_target_available_regs[TCG_TYPE_I32], 0, 0xffff);
|
||||||
tcg_regset_set32(tcg_target_available_regs[TCG_TYPE_I64], 0, 0xffff);
|
tcg_regset_set32(tcg_target_available_regs[TCG_TYPE_I64], 0, 0xffff);
|
||||||
tcg_regset_set32(tcg_target_call_clobber_regs, 0,
|
tcg_regset_set32(tcg_target_call_clobber_regs, 0,
|
||||||
|
@ -1227,10 +1286,6 @@ void tcg_target_init(TCGContext *s)
|
||||||
|
|
||||||
tcg_regset_clear(s->reserved_regs);
|
tcg_regset_clear(s->reserved_regs);
|
||||||
tcg_regset_set_reg(s->reserved_regs, TCG_REG_RSP);
|
tcg_regset_set_reg(s->reserved_regs, TCG_REG_RSP);
|
||||||
/* XXX: will be suppresed when proper global TB entry code will be
|
|
||||||
generated */
|
|
||||||
tcg_regset_set_reg(s->reserved_regs, TCG_REG_RBX);
|
|
||||||
tcg_regset_set_reg(s->reserved_regs, TCG_REG_RBP);
|
|
||||||
|
|
||||||
tcg_add_target_add_op_defs(x86_64_op_defs);
|
tcg_add_target_add_op_defs(x86_64_op_defs);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue