From: bellard Date: Sat, 10 May 2008 10:52:05 +0000 (+0000) Subject: fixed global variable handling with qemu load/stores - initial global prologue/epilog... X-Git-Url: http://git.osdn.net/view?a=commitdiff_plain;h=b03cce8e08237bb84735aa86aea5d7d7c4633e2d;p=qmiga%2Fqemu.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 --- diff --git a/tcg/i386/tcg-target.c b/tcg/i386/tcg-target.c index 51eb6dd3ee..c3b7a03b35 100644 --- a/tcg/i386/tcg-target.c +++ b/tcg/i386/tcg-target.c @@ -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_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, tcg_target_long value, tcg_target_long addend) { @@ -879,7 +881,8 @@ static inline void tcg_out_op(TCGContext *s, int opc, switch(opc) { case INDEX_op_exit_tb: 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; case INDEX_op_goto_tb: if (s->tb_jmp_offset) { @@ -1145,6 +1148,53 @@ static const TCGTargetOpDef x86_op_defs[] = { { -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) { /* fail safe */ diff --git a/tcg/tcg.c b/tcg/tcg.c index c62d06a64c..7e499beeef 100644 --- a/tcg/tcg.c +++ b/tcg/tcg.c @@ -242,6 +242,13 @@ void tcg_context_init(TCGContext *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, @@ -680,36 +687,57 @@ void tcg_dump_ops(TCGContext *s, FILE *outfile) nb_oargs = arg >> 16; nb_iargs = arg & 0xffff; 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; - 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, ","); + /* function name */ /* XXX: dump helper name for call */ fprintf(outfile, "%s", - tcg_get_arg_str_idx(s, buf, sizeof(buf), args[k++])); - } - for(i = 0; i < nb_cargs; i++) { - if (k != 0) + tcg_get_arg_str_idx(s, buf, sizeof(buf), args[nb_oargs + nb_iargs - 1])); + /* flags */ + fprintf(outfile, ",$0x%" TCG_PRIlx, + args[nb_oargs + nb_iargs]); + /* nb out args */ + fprintf(outfile, ",$%d", nb_oargs); + for(i = 0; i < nb_oargs; i++) { + fprintf(outfile, ","); + fprintf(outfile, "%s", + tcg_get_arg_str_idx(s, buf, sizeof(buf), args[i])); + } + for(i = 0; i < (nb_iargs - 1); i++) { fprintf(outfile, ","); - arg = args[k++]; - fprintf(outfile, "$0x%" TCG_PRIlx, arg); + 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"); args += nb_iargs + nb_oargs + nb_cargs; @@ -1027,6 +1055,9 @@ void tcg_liveness_analysis(TCGContext *s) /* 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 */ @@ -1119,9 +1150,7 @@ static void check_regs(TCGContext *s) ts->reg != reg) { printf("Inconsistency for register %s:\n", tcg_target_reg_names[reg]); - printf("reg state:\n"); - dump_regs(s); - tcg_abort(); + goto fail; } } } @@ -1132,10 +1161,16 @@ static void check_regs(TCGContext *s) s->reg_to_temp[ts->reg] != k) { printf("Inconsistency for temp %s:\n", tcg_get_arg_str_idx(s, buf, sizeof(buf), k)); + fail: printf("reg state:\n"); dump_regs(s); 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 @@ -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) { + /* XXX: permit generic clobber register list ? */ for(reg = 0; reg < TCG_TARGET_NB_REGS; reg++) { if (tcg_regset_test_reg(tcg_target_call_clobber_regs, 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 */ @@ -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, int opc, const TCGArg *args, unsigned int dead_iargs) @@ -1443,7 +1497,7 @@ static int tcg_reg_alloc_call(TCGContext *s, const TCGOpDef *def, TCGArg arg, func_arg; TCGTemp *ts; tcg_target_long stack_offset, call_stack_size, func_addr; - int const_func_arg; + int const_func_arg, allocate_args; TCGRegSet allocated_regs; 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 = (call_stack_size + TCG_TARGET_STACK_ALIGN - 1) & ~(TCG_TARGET_STACK_ALIGN - 1); -#ifdef TCG_TARGET_STACK_GROWSUP - tcg_out_addi(s, TCG_REG_CALL_STACK, call_stack_size); -#else - tcg_out_addi(s, TCG_REG_CALL_STACK, -call_stack_size); -#endif - + allocate_args = (call_stack_size > TCG_STATIC_CALL_ARGS_SIZE); + if (allocate_args) { + tcg_out_addi(s, TCG_REG_CALL_STACK, -STACK_DIR(call_stack_size)); + } + /* XXX: on some architectures it does not start at zero */ stack_offset = 0; for(i = nb_regs; i < nb_params; i++) { arg = args[nb_oargs + i]; @@ -1491,11 +1544,8 @@ static int tcg_reg_alloc_call(TCGContext *s, const TCGOpDef *def, } else { tcg_abort(); } -#ifdef TCG_TARGET_STACK_GROWSUP - stack_offset -= sizeof(tcg_target_long); -#else - stack_offset += sizeof(tcg_target_long); -#endif + /* XXX: not necessarily in the same order */ + stack_offset += STACK_DIR(sizeof(tcg_target_long)); } /* assign input registers */ @@ -1525,9 +1575,6 @@ static int tcg_reg_alloc_call(TCGContext *s, const TCGOpDef *def, arg_ct = &def->args_ct[0]; ts = &s->temps[func_arg]; func_addr = ts->val; -#ifdef HOST_HPPA - func_addr = (tcg_target_long)__canonicalize_funcptr_for_compare((void *)func_addr); -#endif const_func_arg = 0; if (ts->val_type == TEMP_VAL_MEM) { 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); -#ifdef TCG_TARGET_STACK_GROWSUP - tcg_out_addi(s, TCG_REG_CALL_STACK, -call_stack_size); -#else - tcg_out_addi(s, TCG_REG_CALL_STACK, call_stack_size); -#endif + if (allocate_args) { + tcg_out_addi(s, TCG_REG_CALL_STACK, STACK_DIR(call_stack_size)); + } /* assign output registers and emit moves if needed */ 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; op_index = 0; -#ifdef TCG_TARGET_NEEDS_PROLOGUE - tcg_target_prologue(s); -#endif - for(;;) { opc = gen_opc_buf[op_index]; #ifdef CONFIG_PROFILER diff --git a/tcg/tcg.h b/tcg/tcg.h index d0556ce963..68d8d4420b 100644 --- a/tcg/tcg.h +++ b/tcg/tcg.h @@ -90,6 +90,10 @@ typedef struct TCGPool { #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; #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 block */ -#define TCG_OPF_CALL_CLOBBER 0x02 /* instruction clobbers call registers */ -#define TCG_OPF_SIDE_EFFECTS 0x04 /* instruction has side effects */ +#define TCG_OPF_CALL_CLOBBER 0x02 /* instruction clobbers call registers + 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 { const char *name; @@ -305,6 +312,7 @@ typedef struct TCGTargetOpDef { extern TCGOpDef tcg_op_defs[]; void tcg_target_init(TCGContext *s); +void tcg_target_qemu_prologue(TCGContext *s); #define tcg_abort() \ 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); uint64_t tcg_helper_divu_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) diff --git a/tcg/x86_64/tcg-target.c b/tcg/x86_64/tcg-target.c index 480ffcbc27..a3114e5f99 100644 --- a/tcg/x86_64/tcg-target.c +++ b/tcg/x86_64/tcg-target.c @@ -73,6 +73,8 @@ const int tcg_target_call_oarg_regs[2] = { TCG_REG_RDX }; +static uint8_t *tb_ret_addr; + static void patch_reloc(uint8_t *code_ptr, int type, 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) { case INDEX_op_exit_tb: 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; case INDEX_op_goto_tb: 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[] = { { INDEX_op_exit_tb, { } }, { INDEX_op_goto_tb, { } }, @@ -1212,6 +1267,10 @@ static const TCGTargetOpDef x86_64_op_defs[] = { 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_I64], 0, 0xffff); 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_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); }