mirror of https://gitee.com/openkylin/qemu.git
Queued TCG patches
-----BEGIN PGP SIGNATURE----- Version: GnuPG v1 iQEcBAABAgAGBQJWzKSgAAoJEK0ScMxN0CebjZoH/RhPwMVsBBnl0U0g3xMFiksj 2V/DPc2qDZ+U5yKwaoBmL0wgBNCjMYq+yjiBIlPGV5tETeUflXBlhhJ+SafsvhdG hesp4pYZcf4rRgflqLoS6UcB+35KZPp82hz6h1luhzc6UhxrAfPSouP2ZjaMZsyI gT+/i0VasTnJMcG1jzWFbJ7AcMUE4H6Qhl7IVpXq0/aMXDApv20zHEvIiTieodyv wqzEiEq5rPqAsJxkxGkBPmRvt0VxJgS5NFbriXPSpJDYjQgWBb1IcogvVxr/+XHr DmUTdbmT7FRcDIWPgwvIvZtpGvAq4hsyAVnE5WbcbE/42eycrV2S73IQTuqrJHA= =N1xl -----END PGP SIGNATURE----- Merge remote-tracking branch 'remotes/rth/tags/pull-tcg-20160223' into staging Queued TCG patches # gpg: Signature made Tue 23 Feb 2016 18:27:44 GMT using RSA key ID 4DD0279B # gpg: Good signature from "Richard Henderson <rth7680@gmail.com>" # gpg: aka "Richard Henderson <rth@redhat.com>" # gpg: aka "Richard Henderson <rth@twiddle.net>" * remotes/rth/tags/pull-tcg-20160223: tcg: Remove unnecessary osdep.h includes from tcg-target.inc.c scripts/clean-includes: Ignore .inc.c files tcg: Rename tcg-target.c to tcg-target.inc.c target-sparc: Use global registers for the register window target-sparc: Tidy global register initialization tcg: Allocate indirect_base temporaries in a different order tcg: Implement indirect memory registers tcg: Work around clang bug wrt enum ranges, part 2 Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
commit
7bd57b5150
|
@ -385,7 +385,7 @@ ops (see @code{target-i386/translate.c}). Some optimizations can be
|
|||
performed at this stage, including liveness analysis and trivial
|
||||
constant expression evaluation. TCG ops are then implemented in the
|
||||
host CPU back end, also known as TCG target (see
|
||||
@code{tcg/i386/tcg-target.c}). For more information, please take a
|
||||
@code{tcg/i386/tcg-target.inc.c}). For more information, please take a
|
||||
look at @code{tcg/README}.
|
||||
|
||||
@node Condition code optimisations
|
||||
|
|
|
@ -94,6 +94,11 @@ EOT
|
|||
|
||||
for f in "$@"; do
|
||||
case "$f" in
|
||||
*.inc.c)
|
||||
# These aren't standalone C source files
|
||||
echo "SKIPPING $f (not a standalone source file)"
|
||||
continue
|
||||
;;
|
||||
*.c)
|
||||
MODE=c
|
||||
;;
|
||||
|
|
|
@ -43,7 +43,8 @@ static TCGv_ptr cpu_env, cpu_regwptr;
|
|||
static TCGv cpu_cc_src, cpu_cc_src2, cpu_cc_dst;
|
||||
static TCGv_i32 cpu_cc_op;
|
||||
static TCGv_i32 cpu_psr;
|
||||
static TCGv cpu_fsr, cpu_pc, cpu_npc, cpu_gregs[8];
|
||||
static TCGv cpu_fsr, cpu_pc, cpu_npc;
|
||||
static TCGv cpu_regs[32];
|
||||
static TCGv cpu_y;
|
||||
#ifndef CONFIG_USER_ONLY
|
||||
static TCGv cpu_tbr;
|
||||
|
@ -273,36 +274,31 @@ static inline void gen_address_mask(DisasContext *dc, TCGv addr)
|
|||
|
||||
static inline TCGv gen_load_gpr(DisasContext *dc, int reg)
|
||||
{
|
||||
if (reg == 0 || reg >= 8) {
|
||||
TCGv t = get_temp_tl(dc);
|
||||
if (reg == 0) {
|
||||
tcg_gen_movi_tl(t, 0);
|
||||
} else {
|
||||
tcg_gen_ld_tl(t, cpu_regwptr, (reg - 8) * sizeof(target_ulong));
|
||||
}
|
||||
return t;
|
||||
if (reg > 0) {
|
||||
assert(reg < 32);
|
||||
return cpu_regs[reg];
|
||||
} else {
|
||||
return cpu_gregs[reg];
|
||||
TCGv t = get_temp_tl(dc);
|
||||
tcg_gen_movi_tl(t, 0);
|
||||
return t;
|
||||
}
|
||||
}
|
||||
|
||||
static inline void gen_store_gpr(DisasContext *dc, int reg, TCGv v)
|
||||
{
|
||||
if (reg > 0) {
|
||||
if (reg < 8) {
|
||||
tcg_gen_mov_tl(cpu_gregs[reg], v);
|
||||
} else {
|
||||
tcg_gen_st_tl(v, cpu_regwptr, (reg - 8) * sizeof(target_ulong));
|
||||
}
|
||||
assert(reg < 32);
|
||||
tcg_gen_mov_tl(cpu_regs[reg], v);
|
||||
}
|
||||
}
|
||||
|
||||
static inline TCGv gen_dest_gpr(DisasContext *dc, int reg)
|
||||
{
|
||||
if (reg == 0 || reg >= 8) {
|
||||
return get_temp_tl(dc);
|
||||
if (reg > 0) {
|
||||
assert(reg < 32);
|
||||
return cpu_regs[reg];
|
||||
} else {
|
||||
return cpu_gregs[reg];
|
||||
return get_temp_tl(dc);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2158,9 +2154,13 @@ static inline void gen_ldda_asi(DisasContext *dc, TCGv hi, TCGv addr,
|
|||
tcg_temp_free_i32(r_size);
|
||||
tcg_temp_free_i32(r_asi);
|
||||
|
||||
t = gen_dest_gpr(dc, rd + 1);
|
||||
/* ??? Work around an apparent bug in Ubuntu gcc 4.8.2-10ubuntu2+12,
|
||||
whereby "rd + 1" elicits "error: array subscript is above array".
|
||||
Since we have already asserted that rd is even, the semantics
|
||||
are unchanged. */
|
||||
t = gen_dest_gpr(dc, rd | 1);
|
||||
tcg_gen_trunc_i64_tl(t, t64);
|
||||
gen_store_gpr(dc, rd + 1, t);
|
||||
gen_store_gpr(dc, rd | 1, t);
|
||||
|
||||
tcg_gen_shri_i64(t64, t64, 32);
|
||||
tcg_gen_trunc_i64_tl(hi, t64);
|
||||
|
@ -5329,106 +5329,98 @@ void gen_intermediate_code(CPUSPARCState * env, TranslationBlock * tb)
|
|||
|
||||
void gen_intermediate_code_init(CPUSPARCState *env)
|
||||
{
|
||||
unsigned int i;
|
||||
static int inited;
|
||||
static const char * const gregnames[8] = {
|
||||
NULL, // g0 not used
|
||||
"g1",
|
||||
"g2",
|
||||
"g3",
|
||||
"g4",
|
||||
"g5",
|
||||
"g6",
|
||||
"g7",
|
||||
static const char gregnames[32][4] = {
|
||||
"g0", "g1", "g2", "g3", "g4", "g5", "g6", "g7",
|
||||
"o0", "o1", "o2", "o3", "o4", "o5", "o6", "o7",
|
||||
"l0", "l1", "l2", "l3", "l4", "l5", "l6", "l7",
|
||||
"i0", "i1", "i2", "i3", "i4", "i5", "i6", "i7",
|
||||
};
|
||||
static const char * const fregnames[32] = {
|
||||
static const char fregnames[32][4] = {
|
||||
"f0", "f2", "f4", "f6", "f8", "f10", "f12", "f14",
|
||||
"f16", "f18", "f20", "f22", "f24", "f26", "f28", "f30",
|
||||
"f32", "f34", "f36", "f38", "f40", "f42", "f44", "f46",
|
||||
"f48", "f50", "f52", "f54", "f56", "f58", "f60", "f62",
|
||||
};
|
||||
|
||||
/* init various static tables */
|
||||
if (!inited) {
|
||||
inited = 1;
|
||||
|
||||
cpu_env = tcg_global_reg_new_ptr(TCG_AREG0, "env");
|
||||
cpu_regwptr = tcg_global_mem_new_ptr(cpu_env,
|
||||
offsetof(CPUSPARCState, regwptr),
|
||||
"regwptr");
|
||||
static const struct { TCGv_i32 *ptr; int off; const char *name; } r32[] = {
|
||||
#ifdef TARGET_SPARC64
|
||||
cpu_xcc = tcg_global_mem_new_i32(cpu_env, offsetof(CPUSPARCState, xcc),
|
||||
"xcc");
|
||||
cpu_asi = tcg_global_mem_new_i32(cpu_env, offsetof(CPUSPARCState, asi),
|
||||
"asi");
|
||||
cpu_fprs = tcg_global_mem_new_i32(cpu_env,
|
||||
offsetof(CPUSPARCState, fprs),
|
||||
"fprs");
|
||||
cpu_gsr = tcg_global_mem_new(cpu_env, offsetof(CPUSPARCState, gsr),
|
||||
"gsr");
|
||||
cpu_tick_cmpr = tcg_global_mem_new(cpu_env,
|
||||
offsetof(CPUSPARCState, tick_cmpr),
|
||||
"tick_cmpr");
|
||||
cpu_stick_cmpr = tcg_global_mem_new(cpu_env,
|
||||
offsetof(CPUSPARCState, stick_cmpr),
|
||||
"stick_cmpr");
|
||||
cpu_hstick_cmpr = tcg_global_mem_new(cpu_env,
|
||||
offsetof(CPUSPARCState, hstick_cmpr),
|
||||
"hstick_cmpr");
|
||||
cpu_hintp = tcg_global_mem_new(cpu_env, offsetof(CPUSPARCState, hintp),
|
||||
"hintp");
|
||||
cpu_htba = tcg_global_mem_new(cpu_env, offsetof(CPUSPARCState, htba),
|
||||
"htba");
|
||||
cpu_hver = tcg_global_mem_new(cpu_env, offsetof(CPUSPARCState, hver),
|
||||
"hver");
|
||||
cpu_ssr = tcg_global_mem_new(cpu_env,
|
||||
offsetof(CPUSPARCState, ssr), "ssr");
|
||||
cpu_ver = tcg_global_mem_new(cpu_env,
|
||||
offsetof(CPUSPARCState, version), "ver");
|
||||
cpu_softint = tcg_global_mem_new_i32(cpu_env,
|
||||
offsetof(CPUSPARCState, softint),
|
||||
"softint");
|
||||
{ &cpu_xcc, offsetof(CPUSPARCState, xcc), "xcc" },
|
||||
{ &cpu_asi, offsetof(CPUSPARCState, asi), "asi" },
|
||||
{ &cpu_fprs, offsetof(CPUSPARCState, fprs), "fprs" },
|
||||
{ &cpu_softint, offsetof(CPUSPARCState, softint), "softint" },
|
||||
#else
|
||||
cpu_wim = tcg_global_mem_new(cpu_env, offsetof(CPUSPARCState, wim),
|
||||
"wim");
|
||||
{ &cpu_wim, offsetof(CPUSPARCState, wim), "wim" },
|
||||
#endif
|
||||
cpu_cond = tcg_global_mem_new(cpu_env, offsetof(CPUSPARCState, cond),
|
||||
"cond");
|
||||
cpu_cc_src = tcg_global_mem_new(cpu_env,
|
||||
offsetof(CPUSPARCState, cc_src),
|
||||
"cc_src");
|
||||
cpu_cc_src2 = tcg_global_mem_new(cpu_env,
|
||||
offsetof(CPUSPARCState, cc_src2),
|
||||
"cc_src2");
|
||||
cpu_cc_dst = tcg_global_mem_new(cpu_env,
|
||||
offsetof(CPUSPARCState, cc_dst),
|
||||
"cc_dst");
|
||||
cpu_cc_op = tcg_global_mem_new_i32(cpu_env,
|
||||
offsetof(CPUSPARCState, cc_op),
|
||||
"cc_op");
|
||||
cpu_psr = tcg_global_mem_new_i32(cpu_env, offsetof(CPUSPARCState, psr),
|
||||
"psr");
|
||||
cpu_fsr = tcg_global_mem_new(cpu_env, offsetof(CPUSPARCState, fsr),
|
||||
"fsr");
|
||||
cpu_pc = tcg_global_mem_new(cpu_env, offsetof(CPUSPARCState, pc),
|
||||
"pc");
|
||||
cpu_npc = tcg_global_mem_new(cpu_env, offsetof(CPUSPARCState, npc),
|
||||
"npc");
|
||||
cpu_y = tcg_global_mem_new(cpu_env, offsetof(CPUSPARCState, y), "y");
|
||||
{ &cpu_cc_op, offsetof(CPUSPARCState, cc_op), "cc_op" },
|
||||
{ &cpu_psr, offsetof(CPUSPARCState, psr), "psr" },
|
||||
};
|
||||
|
||||
static const struct { TCGv *ptr; int off; const char *name; } rtl[] = {
|
||||
#ifdef TARGET_SPARC64
|
||||
{ &cpu_gsr, offsetof(CPUSPARCState, gsr), "gsr" },
|
||||
{ &cpu_tick_cmpr, offsetof(CPUSPARCState, tick_cmpr), "tick_cmpr" },
|
||||
{ &cpu_stick_cmpr, offsetof(CPUSPARCState, stick_cmpr), "stick_cmpr" },
|
||||
{ &cpu_hstick_cmpr, offsetof(CPUSPARCState, hstick_cmpr),
|
||||
"hstick_cmpr" },
|
||||
{ &cpu_hintp, offsetof(CPUSPARCState, hintp), "hintp" },
|
||||
{ &cpu_htba, offsetof(CPUSPARCState, htba), "htba" },
|
||||
{ &cpu_hver, offsetof(CPUSPARCState, hver), "hver" },
|
||||
{ &cpu_ssr, offsetof(CPUSPARCState, ssr), "ssr" },
|
||||
{ &cpu_ver, offsetof(CPUSPARCState, version), "ver" },
|
||||
#endif
|
||||
{ &cpu_cond, offsetof(CPUSPARCState, cond), "cond" },
|
||||
{ &cpu_cc_src, offsetof(CPUSPARCState, cc_src), "cc_src" },
|
||||
{ &cpu_cc_src2, offsetof(CPUSPARCState, cc_src2), "cc_src2" },
|
||||
{ &cpu_cc_dst, offsetof(CPUSPARCState, cc_dst), "cc_dst" },
|
||||
{ &cpu_fsr, offsetof(CPUSPARCState, fsr), "fsr" },
|
||||
{ &cpu_pc, offsetof(CPUSPARCState, pc), "pc" },
|
||||
{ &cpu_npc, offsetof(CPUSPARCState, npc), "npc" },
|
||||
{ &cpu_y, offsetof(CPUSPARCState, y), "y" },
|
||||
#ifndef CONFIG_USER_ONLY
|
||||
cpu_tbr = tcg_global_mem_new(cpu_env, offsetof(CPUSPARCState, tbr),
|
||||
"tbr");
|
||||
{ &cpu_tbr, offsetof(CPUSPARCState, tbr), "tbr" },
|
||||
#endif
|
||||
for (i = 1; i < 8; i++) {
|
||||
cpu_gregs[i] = tcg_global_mem_new(cpu_env,
|
||||
offsetof(CPUSPARCState, gregs[i]),
|
||||
gregnames[i]);
|
||||
}
|
||||
for (i = 0; i < TARGET_DPREGS; i++) {
|
||||
cpu_fpr[i] = tcg_global_mem_new_i64(cpu_env,
|
||||
offsetof(CPUSPARCState, fpr[i]),
|
||||
fregnames[i]);
|
||||
}
|
||||
};
|
||||
|
||||
unsigned int i;
|
||||
|
||||
/* init various static tables */
|
||||
if (inited) {
|
||||
return;
|
||||
}
|
||||
inited = 1;
|
||||
|
||||
cpu_env = tcg_global_reg_new_ptr(TCG_AREG0, "env");
|
||||
|
||||
cpu_regwptr = tcg_global_mem_new_ptr(cpu_env,
|
||||
offsetof(CPUSPARCState, regwptr),
|
||||
"regwptr");
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(r32); ++i) {
|
||||
*r32[i].ptr = tcg_global_mem_new_i32(cpu_env, r32[i].off, r32[i].name);
|
||||
}
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(rtl); ++i) {
|
||||
*rtl[i].ptr = tcg_global_mem_new(cpu_env, rtl[i].off, rtl[i].name);
|
||||
}
|
||||
|
||||
TCGV_UNUSED(cpu_regs[0]);
|
||||
for (i = 1; i < 8; ++i) {
|
||||
cpu_regs[i] = tcg_global_mem_new(cpu_env,
|
||||
offsetof(CPUSPARCState, gregs[i]),
|
||||
gregnames[i]);
|
||||
}
|
||||
|
||||
for (i = 8; i < 32; ++i) {
|
||||
cpu_regs[i] = tcg_global_mem_new(cpu_regwptr,
|
||||
(i - 8) * sizeof(target_ulong),
|
||||
gregnames[i]);
|
||||
}
|
||||
|
||||
for (i = 0; i < TARGET_DPREGS; i++) {
|
||||
cpu_fpr[i] = tcg_global_mem_new_i64(cpu_env,
|
||||
offsetof(CPUSPARCState, fpr[i]),
|
||||
fregnames[i]);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -460,8 +460,9 @@ function tcg_gen_xxx(args).
|
|||
|
||||
4) Backend
|
||||
|
||||
tcg-target.h contains the target specific definitions. tcg-target.c
|
||||
contains the target specific code.
|
||||
tcg-target.h contains the target specific definitions. tcg-target.inc.c
|
||||
contains the target specific code; it is #included by tcg/tcg.c, rather
|
||||
than being a standalone C file.
|
||||
|
||||
4.1) Assumptions
|
||||
|
||||
|
|
|
@ -10,7 +10,6 @@
|
|||
* See the COPYING file in the top-level directory for details.
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "tcg-be-ldst.h"
|
||||
#include "qemu/bitops.h"
|
||||
|
|
@ -22,7 +22,6 @@
|
|||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "elf.h"
|
||||
#include "tcg-be-ldst.h"
|
||||
|
|
@ -22,7 +22,6 @@
|
|||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "tcg-be-ldst.h"
|
||||
|
||||
#ifndef NDEBUG
|
|
@ -24,7 +24,6 @@
|
|||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "tcg-be-ldst.h"
|
||||
|
||||
#ifdef HOST_WORDS_BIGENDIAN
|
|
@ -22,7 +22,6 @@
|
|||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "tcg-be-ldst.h"
|
||||
|
||||
#if defined _CALL_DARWIN || defined __APPLE__
|
|
@ -24,7 +24,6 @@
|
|||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "tcg-be-ldst.h"
|
||||
|
||||
/* We only support generating code for 64-bit mode. */
|
|
@ -22,7 +22,6 @@
|
|||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "tcg-be-null.h"
|
||||
|
||||
#ifndef NDEBUG
|
145
tcg/tcg.c
145
tcg/tcg.c
|
@ -62,7 +62,8 @@
|
|||
#include "elf.h"
|
||||
#include "exec/log.h"
|
||||
|
||||
/* Forward declarations for functions declared in tcg-target.c and used here. */
|
||||
/* Forward declarations for functions declared in tcg-target.inc.c and
|
||||
used here. */
|
||||
static void tcg_target_init(TCGContext *s);
|
||||
static void tcg_target_qemu_prologue(TCGContext *s);
|
||||
static void patch_reloc(tcg_insn_unit *code_ptr, int type,
|
||||
|
@ -96,7 +97,7 @@ static void tcg_register_jit_int(void *buf, size_t size,
|
|||
size_t debug_frame_size)
|
||||
__attribute__((unused));
|
||||
|
||||
/* Forward declarations for functions declared and used in tcg-target.c. */
|
||||
/* Forward declarations for functions declared and used in tcg-target.inc.c. */
|
||||
static int target_parse_constraint(TCGArgConstraint *ct, const char **pct_str);
|
||||
static void tcg_out_ld(TCGContext *s, TCGType type, TCGReg ret, TCGReg arg1,
|
||||
intptr_t arg2);
|
||||
|
@ -250,7 +251,7 @@ TCGLabel *gen_new_label(void)
|
|||
return l;
|
||||
}
|
||||
|
||||
#include "tcg-target.c"
|
||||
#include "tcg-target.inc.c"
|
||||
|
||||
/* pool based memory allocation */
|
||||
void *tcg_malloc_internal(TCGContext *s, int size)
|
||||
|
@ -318,6 +319,8 @@ static const TCGHelperInfo all_helpers[] = {
|
|||
#include "exec/helper-tcg.h"
|
||||
};
|
||||
|
||||
static int indirect_reg_alloc_order[ARRAY_SIZE(tcg_target_reg_alloc_order)];
|
||||
|
||||
void tcg_context_init(TCGContext *s)
|
||||
{
|
||||
int op, total_args, n, i;
|
||||
|
@ -360,6 +363,21 @@ void tcg_context_init(TCGContext *s)
|
|||
}
|
||||
|
||||
tcg_target_init(s);
|
||||
|
||||
/* Reverse the order of the saved registers, assuming they're all at
|
||||
the start of tcg_target_reg_alloc_order. */
|
||||
for (n = 0; n < ARRAY_SIZE(tcg_target_reg_alloc_order); ++n) {
|
||||
int r = tcg_target_reg_alloc_order[n];
|
||||
if (tcg_regset_test_reg(tcg_target_call_clobber_regs, r)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
for (i = 0; i < n; ++i) {
|
||||
indirect_reg_alloc_order[i] = tcg_target_reg_alloc_order[n - 1 - i];
|
||||
}
|
||||
for (; i < ARRAY_SIZE(tcg_target_reg_alloc_order); ++i) {
|
||||
indirect_reg_alloc_order[i] = tcg_target_reg_alloc_order[i];
|
||||
}
|
||||
}
|
||||
|
||||
void tcg_prologue_init(TCGContext *s)
|
||||
|
@ -506,17 +524,23 @@ int tcg_global_mem_new_internal(TCGType type, TCGv_ptr base,
|
|||
TCGContext *s = &tcg_ctx;
|
||||
TCGTemp *base_ts = &s->temps[GET_TCGV_PTR(base)];
|
||||
TCGTemp *ts = tcg_global_alloc(s);
|
||||
int bigendian = 0;
|
||||
int indirect_reg = 0, bigendian = 0;
|
||||
#ifdef HOST_WORDS_BIGENDIAN
|
||||
bigendian = 1;
|
||||
#endif
|
||||
|
||||
if (!base_ts->fixed_reg) {
|
||||
indirect_reg = 1;
|
||||
base_ts->indirect_base = 1;
|
||||
}
|
||||
|
||||
if (TCG_TARGET_REG_BITS == 32 && type == TCG_TYPE_I64) {
|
||||
TCGTemp *ts2 = tcg_global_alloc(s);
|
||||
char buf[64];
|
||||
|
||||
ts->base_type = TCG_TYPE_I64;
|
||||
ts->type = TCG_TYPE_I32;
|
||||
ts->indirect_reg = indirect_reg;
|
||||
ts->mem_allocated = 1;
|
||||
ts->mem_base = base_ts;
|
||||
ts->mem_offset = offset + bigendian * 4;
|
||||
|
@ -527,6 +551,7 @@ int tcg_global_mem_new_internal(TCGType type, TCGv_ptr base,
|
|||
tcg_debug_assert(ts2 == ts + 1);
|
||||
ts2->base_type = TCG_TYPE_I64;
|
||||
ts2->type = TCG_TYPE_I32;
|
||||
ts2->indirect_reg = indirect_reg;
|
||||
ts2->mem_allocated = 1;
|
||||
ts2->mem_base = base_ts;
|
||||
ts2->mem_offset = offset + (1 - bigendian) * 4;
|
||||
|
@ -536,6 +561,7 @@ int tcg_global_mem_new_internal(TCGType type, TCGv_ptr base,
|
|||
} else {
|
||||
ts->base_type = type;
|
||||
ts->type = type;
|
||||
ts->indirect_reg = indirect_reg;
|
||||
ts->mem_allocated = 1;
|
||||
ts->mem_base = base_ts;
|
||||
ts->mem_offset = offset;
|
||||
|
@ -1602,7 +1628,7 @@ static void dump_regs(TCGContext *s)
|
|||
|
||||
static void check_regs(TCGContext *s)
|
||||
{
|
||||
TCGReg reg;
|
||||
int reg;
|
||||
int k;
|
||||
TCGTemp *ts;
|
||||
char buf[64];
|
||||
|
@ -1652,8 +1678,10 @@ static void temp_allocate_frame(TCGContext *s, int temp)
|
|||
s->current_frame_offset += sizeof(tcg_target_long);
|
||||
}
|
||||
|
||||
static void temp_load(TCGContext *, TCGTemp *, TCGRegSet, TCGRegSet);
|
||||
|
||||
/* sync register 'reg' by saving it to the corresponding temporary */
|
||||
static inline void tcg_reg_sync(TCGContext *s, TCGReg reg)
|
||||
static void tcg_reg_sync(TCGContext *s, TCGReg reg, TCGRegSet allocated_regs)
|
||||
{
|
||||
TCGTemp *ts = s->reg_to_temp[reg];
|
||||
|
||||
|
@ -1661,6 +1689,11 @@ static inline void tcg_reg_sync(TCGContext *s, TCGReg reg)
|
|||
if (!ts->mem_coherent && !ts->fixed_reg) {
|
||||
if (!ts->mem_allocated) {
|
||||
temp_allocate_frame(s, temp_idx(s, ts));
|
||||
} else if (ts->indirect_reg) {
|
||||
tcg_regset_set_reg(allocated_regs, ts->reg);
|
||||
temp_load(s, ts->mem_base,
|
||||
tcg_target_available_regs[TCG_TYPE_PTR],
|
||||
allocated_regs);
|
||||
}
|
||||
tcg_out_st(s, ts->type, reg, ts->mem_base->reg, ts->mem_offset);
|
||||
}
|
||||
|
@ -1668,38 +1701,41 @@ static inline void tcg_reg_sync(TCGContext *s, TCGReg reg)
|
|||
}
|
||||
|
||||
/* free register 'reg' by spilling the corresponding temporary if necessary */
|
||||
static void tcg_reg_free(TCGContext *s, TCGReg reg)
|
||||
static void tcg_reg_free(TCGContext *s, TCGReg reg, TCGRegSet allocated_regs)
|
||||
{
|
||||
TCGTemp *ts = s->reg_to_temp[reg];
|
||||
|
||||
if (ts != NULL) {
|
||||
tcg_reg_sync(s, reg);
|
||||
tcg_reg_sync(s, reg, allocated_regs);
|
||||
ts->val_type = TEMP_VAL_MEM;
|
||||
s->reg_to_temp[reg] = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/* Allocate a register belonging to reg1 & ~reg2 */
|
||||
static TCGReg tcg_reg_alloc(TCGContext *s, TCGRegSet reg1, TCGRegSet reg2)
|
||||
static TCGReg tcg_reg_alloc(TCGContext *s, TCGRegSet desired_regs,
|
||||
TCGRegSet allocated_regs, bool rev)
|
||||
{
|
||||
int i;
|
||||
int i, n = ARRAY_SIZE(tcg_target_reg_alloc_order);
|
||||
const int *order;
|
||||
TCGReg reg;
|
||||
TCGRegSet reg_ct;
|
||||
|
||||
tcg_regset_andnot(reg_ct, reg1, reg2);
|
||||
tcg_regset_andnot(reg_ct, desired_regs, allocated_regs);
|
||||
order = rev ? indirect_reg_alloc_order : tcg_target_reg_alloc_order;
|
||||
|
||||
/* first try free registers */
|
||||
for(i = 0; i < ARRAY_SIZE(tcg_target_reg_alloc_order); i++) {
|
||||
reg = tcg_target_reg_alloc_order[i];
|
||||
for(i = 0; i < n; i++) {
|
||||
reg = order[i];
|
||||
if (tcg_regset_test_reg(reg_ct, reg) && s->reg_to_temp[reg] == NULL)
|
||||
return reg;
|
||||
}
|
||||
|
||||
/* XXX: do better spill choice */
|
||||
for(i = 0; i < ARRAY_SIZE(tcg_target_reg_alloc_order); i++) {
|
||||
reg = tcg_target_reg_alloc_order[i];
|
||||
for(i = 0; i < n; i++) {
|
||||
reg = order[i];
|
||||
if (tcg_regset_test_reg(reg_ct, reg)) {
|
||||
tcg_reg_free(s, reg);
|
||||
tcg_reg_free(s, reg, allocated_regs);
|
||||
return reg;
|
||||
}
|
||||
}
|
||||
|
@ -1718,12 +1754,18 @@ static void temp_load(TCGContext *s, TCGTemp *ts, TCGRegSet desired_regs,
|
|||
case TEMP_VAL_REG:
|
||||
return;
|
||||
case TEMP_VAL_CONST:
|
||||
reg = tcg_reg_alloc(s, desired_regs, allocated_regs);
|
||||
reg = tcg_reg_alloc(s, desired_regs, allocated_regs, ts->indirect_base);
|
||||
tcg_out_movi(s, ts->type, reg, ts->val);
|
||||
ts->mem_coherent = 0;
|
||||
break;
|
||||
case TEMP_VAL_MEM:
|
||||
reg = tcg_reg_alloc(s, desired_regs, allocated_regs);
|
||||
reg = tcg_reg_alloc(s, desired_regs, allocated_regs, ts->indirect_base);
|
||||
if (ts->indirect_reg) {
|
||||
tcg_regset_set_reg(allocated_regs, reg);
|
||||
temp_load(s, ts->mem_base,
|
||||
tcg_target_available_regs[TCG_TYPE_PTR],
|
||||
allocated_regs);
|
||||
}
|
||||
tcg_out_ld(s, ts->type, reg, ts->mem_base->reg, ts->mem_offset);
|
||||
ts->mem_coherent = 1;
|
||||
break;
|
||||
|
@ -1761,7 +1803,7 @@ static void temp_sync(TCGContext *s, TCGTemp *ts, TCGRegSet allocated_regs)
|
|||
temp_load(s, ts, tcg_target_available_regs[ts->type], allocated_regs);
|
||||
/* fallthrough */
|
||||
case TEMP_VAL_REG:
|
||||
tcg_reg_sync(s, ts->reg);
|
||||
tcg_reg_sync(s, ts->reg, allocated_regs);
|
||||
break;
|
||||
case TEMP_VAL_DEAD:
|
||||
case TEMP_VAL_MEM:
|
||||
|
@ -1777,13 +1819,16 @@ static inline void temp_save(TCGContext *s, TCGTemp *ts,
|
|||
TCGRegSet allocated_regs)
|
||||
{
|
||||
#ifdef USE_LIVENESS_ANALYSIS
|
||||
/* The liveness analysis already ensures that globals are back
|
||||
in memory. Keep an assert for safety. */
|
||||
tcg_debug_assert(ts->val_type == TEMP_VAL_MEM || ts->fixed_reg);
|
||||
#else
|
||||
/* ??? Liveness does not yet incorporate indirect bases. */
|
||||
if (!ts->indirect_base) {
|
||||
/* The liveness analysis already ensures that globals are back
|
||||
in memory. Keep an assert for safety. */
|
||||
tcg_debug_assert(ts->val_type == TEMP_VAL_MEM || ts->fixed_reg);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
temp_sync(s, ts, allocated_regs);
|
||||
temp_dead(s, ts);
|
||||
#endif
|
||||
}
|
||||
|
||||
/* save globals to their canonical location and assume they can be
|
||||
|
@ -1808,12 +1853,15 @@ static void sync_globals(TCGContext *s, TCGRegSet allocated_regs)
|
|||
for (i = 0; i < s->nb_globals; i++) {
|
||||
TCGTemp *ts = &s->temps[i];
|
||||
#ifdef USE_LIVENESS_ANALYSIS
|
||||
tcg_debug_assert(ts->val_type != TEMP_VAL_REG
|
||||
|| ts->fixed_reg
|
||||
|| ts->mem_coherent);
|
||||
#else
|
||||
temp_sync(s, ts, allocated_regs);
|
||||
/* ??? Liveness does not yet incorporate indirect bases. */
|
||||
if (!ts->indirect_base) {
|
||||
tcg_debug_assert(ts->val_type != TEMP_VAL_REG
|
||||
|| ts->fixed_reg
|
||||
|| ts->mem_coherent);
|
||||
continue;
|
||||
}
|
||||
#endif
|
||||
temp_sync(s, ts, allocated_regs);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1829,12 +1877,15 @@ static void tcg_reg_alloc_bb_end(TCGContext *s, TCGRegSet allocated_regs)
|
|||
temp_save(s, ts, allocated_regs);
|
||||
} else {
|
||||
#ifdef USE_LIVENESS_ANALYSIS
|
||||
/* The liveness analysis already ensures that temps are dead.
|
||||
Keep an assert for safety. */
|
||||
assert(ts->val_type == TEMP_VAL_DEAD);
|
||||
#else
|
||||
temp_dead(s, ts);
|
||||
/* ??? Liveness does not yet incorporate indirect bases. */
|
||||
if (!ts->indirect_base) {
|
||||
/* The liveness analysis already ensures that temps are dead.
|
||||
Keep an assert for safety. */
|
||||
assert(ts->val_type == TEMP_VAL_DEAD);
|
||||
continue;
|
||||
}
|
||||
#endif
|
||||
temp_dead(s, ts);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1907,6 +1958,12 @@ static void tcg_reg_alloc_mov(TCGContext *s, const TCGOpDef *def,
|
|||
if (!ots->mem_allocated) {
|
||||
temp_allocate_frame(s, args[0]);
|
||||
}
|
||||
if (ots->indirect_reg) {
|
||||
tcg_regset_set_reg(allocated_regs, ts->reg);
|
||||
temp_load(s, ots->mem_base,
|
||||
tcg_target_available_regs[TCG_TYPE_PTR],
|
||||
allocated_regs);
|
||||
}
|
||||
tcg_out_st(s, otype, ts->reg, ots->mem_base->reg, ots->mem_offset);
|
||||
if (IS_DEAD_ARG(1)) {
|
||||
temp_dead(s, ts);
|
||||
|
@ -1939,7 +1996,7 @@ static void tcg_reg_alloc_mov(TCGContext *s, const TCGOpDef *def,
|
|||
input one. */
|
||||
tcg_regset_set_reg(allocated_regs, ts->reg);
|
||||
ots->reg = tcg_reg_alloc(s, tcg_target_available_regs[otype],
|
||||
allocated_regs);
|
||||
allocated_regs, ots->indirect_base);
|
||||
}
|
||||
tcg_out_mov(s, otype, ots->reg, ts->reg);
|
||||
}
|
||||
|
@ -1947,7 +2004,7 @@ static void tcg_reg_alloc_mov(TCGContext *s, const TCGOpDef *def,
|
|||
ots->mem_coherent = 0;
|
||||
s->reg_to_temp[ots->reg] = ots;
|
||||
if (NEED_SYNC_ARG(0)) {
|
||||
tcg_reg_sync(s, ots->reg);
|
||||
tcg_reg_sync(s, ots->reg, allocated_regs);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2024,7 +2081,8 @@ static void tcg_reg_alloc_op(TCGContext *s,
|
|||
allocate_in_reg:
|
||||
/* 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);
|
||||
reg = tcg_reg_alloc(s, arg_ct->u.regs, allocated_regs,
|
||||
ts->indirect_base);
|
||||
tcg_out_mov(s, ts->type, reg, ts->reg);
|
||||
}
|
||||
new_args[i] = reg;
|
||||
|
@ -2047,7 +2105,7 @@ static void tcg_reg_alloc_op(TCGContext *s,
|
|||
/* XXX: permit generic clobber register list ? */
|
||||
for (i = 0; i < TCG_TARGET_NB_REGS; i++) {
|
||||
if (tcg_regset_test_reg(tcg_target_call_clobber_regs, i)) {
|
||||
tcg_reg_free(s, i);
|
||||
tcg_reg_free(s, i, allocated_regs);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2073,7 +2131,8 @@ static void tcg_reg_alloc_op(TCGContext *s,
|
|||
tcg_regset_test_reg(arg_ct->u.regs, reg)) {
|
||||
goto oarg_end;
|
||||
}
|
||||
reg = tcg_reg_alloc(s, arg_ct->u.regs, allocated_regs);
|
||||
reg = tcg_reg_alloc(s, arg_ct->u.regs, allocated_regs,
|
||||
ts->indirect_base);
|
||||
}
|
||||
tcg_regset_set_reg(allocated_regs, reg);
|
||||
/* if a fixed register is used, then a move will be done afterwards */
|
||||
|
@ -2104,7 +2163,7 @@ static void tcg_reg_alloc_op(TCGContext *s,
|
|||
tcg_out_mov(s, ts->type, ts->reg, reg);
|
||||
}
|
||||
if (NEED_SYNC_ARG(i)) {
|
||||
tcg_reg_sync(s, reg);
|
||||
tcg_reg_sync(s, reg, allocated_regs);
|
||||
}
|
||||
if (IS_DEAD_ARG(i)) {
|
||||
temp_dead(s, ts);
|
||||
|
@ -2175,7 +2234,7 @@ static void tcg_reg_alloc_call(TCGContext *s, int nb_oargs, int nb_iargs,
|
|||
if (arg != TCG_CALL_DUMMY_ARG) {
|
||||
ts = &s->temps[arg];
|
||||
reg = tcg_target_call_iarg_regs[i];
|
||||
tcg_reg_free(s, reg);
|
||||
tcg_reg_free(s, reg, allocated_regs);
|
||||
|
||||
if (ts->val_type == TEMP_VAL_REG) {
|
||||
if (ts->reg != reg) {
|
||||
|
@ -2203,7 +2262,7 @@ static void tcg_reg_alloc_call(TCGContext *s, int nb_oargs, int nb_iargs,
|
|||
/* clobber call registers */
|
||||
for (i = 0; i < TCG_TARGET_NB_REGS; i++) {
|
||||
if (tcg_regset_test_reg(tcg_target_call_clobber_regs, i)) {
|
||||
tcg_reg_free(s, i);
|
||||
tcg_reg_free(s, i, allocated_regs);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2239,7 +2298,7 @@ static void tcg_reg_alloc_call(TCGContext *s, int nb_oargs, int nb_iargs,
|
|||
ts->mem_coherent = 0;
|
||||
s->reg_to_temp[reg] = ts;
|
||||
if (NEED_SYNC_ARG(i)) {
|
||||
tcg_reg_sync(s, reg);
|
||||
tcg_reg_sync(s, reg, allocated_regs);
|
||||
}
|
||||
if (IS_DEAD_ARG(i)) {
|
||||
temp_dead(s, ts);
|
||||
|
|
|
@ -453,6 +453,8 @@ typedef struct TCGTemp {
|
|||
TCGType base_type:8;
|
||||
TCGType type:8;
|
||||
unsigned int fixed_reg:1;
|
||||
unsigned int indirect_reg:1;
|
||||
unsigned int indirect_base:1;
|
||||
unsigned int mem_coherent:1;
|
||||
unsigned int mem_allocated:1;
|
||||
unsigned int temp_local:1; /* If true, the temp is saved across
|
||||
|
@ -566,7 +568,7 @@ struct TCGContext {
|
|||
|
||||
TBContext tb_ctx;
|
||||
|
||||
/* The TCGBackendData structure is private to tcg-target.c. */
|
||||
/* The TCGBackendData structure is private to tcg-target.inc.c. */
|
||||
struct TCGBackendData *be;
|
||||
|
||||
TCGTempSet free_temps[TCG_TYPE_COUNT * 2];
|
||||
|
|
|
@ -21,7 +21,7 @@ This is what TCI (Tiny Code Interpreter) does.
|
|||
2) Implementation
|
||||
|
||||
Like each TCG host frontend, TCI implements the code generator in
|
||||
tcg-target.c, tcg-target.h. Both files are in directory tcg/tci.
|
||||
tcg-target.inc.c, tcg-target.h. Both files are in directory tcg/tci.
|
||||
|
||||
The additional file tcg/tci.c adds the interpreter.
|
||||
|
||||
|
@ -123,7 +123,7 @@ u1 = linux-user-test works
|
|||
would also improve speed for hosts which support byte alignment).
|
||||
|
||||
* A better disassembler for the pseudo code would be nice (a very primitive
|
||||
disassembler is included in tcg-target.c).
|
||||
disassembler is included in tcg-target.inc.c).
|
||||
|
||||
* It might be useful to have a runtime option which selects the native TCG
|
||||
or TCI, so QEMU would have to include two TCGs. Today, selecting TCI
|
||||
|
|
|
@ -22,7 +22,6 @@
|
|||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "tcg-be-null.h"
|
||||
|
||||
/* TODO list:
|
Loading…
Reference in New Issue