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:
Peter Maydell 2016-02-23 18:49:30 +00:00
commit 7bd57b5150
16 changed files with 215 additions and 164 deletions

View File

@ -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

View File

@ -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
;;

View File

@ -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) {
if (reg > 0) {
assert(reg < 32);
return cpu_regs[reg];
} else {
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;
} else {
return cpu_gregs[reg];
}
}
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,107 +5329,99 @@ 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",
};
static const struct { TCGv_i32 *ptr; int off; const char *name; } r32[] = {
#ifdef TARGET_SPARC64
{ &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, offsetof(CPUSPARCState, wim), "wim" },
#endif
{ &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, offsetof(CPUSPARCState, tbr), "tbr" },
#endif
};
unsigned int i;
/* init various static tables */
if (!inited) {
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");
#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");
#else
cpu_wim = tcg_global_mem_new(cpu_env, 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");
#ifndef CONFIG_USER_ONLY
cpu_tbr = tcg_global_mem_new(cpu_env, offsetof(CPUSPARCState, tbr),
"tbr");
#endif
for (i = 1; i < 8; i++) {
cpu_gregs[i] = tcg_global_mem_new(cpu_env,
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]);
}
}
}
void restore_state_to_opc(CPUSPARCState *env, TranslationBlock *tb,

View File

@ -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

View File

@ -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"

View File

@ -22,7 +22,6 @@
* THE SOFTWARE.
*/
#include "qemu/osdep.h"
#include "elf.h"
#include "tcg-be-ldst.h"

View File

@ -22,7 +22,6 @@
* THE SOFTWARE.
*/
#include "qemu/osdep.h"
#include "tcg-be-ldst.h"
#ifndef NDEBUG

View File

@ -24,7 +24,6 @@
* THE SOFTWARE.
*/
#include "qemu/osdep.h"
#include "tcg-be-ldst.h"
#ifdef HOST_WORDS_BIGENDIAN

View File

@ -22,7 +22,6 @@
* THE SOFTWARE.
*/
#include "qemu/osdep.h"
#include "tcg-be-ldst.h"
#if defined _CALL_DARWIN || defined __APPLE__

View File

@ -24,7 +24,6 @@
* THE SOFTWARE.
*/
#include "qemu/osdep.h"
#include "tcg-be-ldst.h"
/* We only support generating code for 64-bit mode. */

View File

@ -22,7 +22,6 @@
* THE SOFTWARE.
*/
#include "qemu/osdep.h"
#include "tcg-be-null.h"
#ifndef NDEBUG

127
tcg/tcg.c
View File

@ -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
/* ??? 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);
#else
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
/* ??? 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);
#else
temp_sync(s, ts, allocated_regs);
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
/* ??? 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);
#else
temp_dead(s, ts);
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);

View File

@ -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];

View File

@ -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

View File

@ -22,7 +22,6 @@
* THE SOFTWARE.
*/
#include "qemu/osdep.h"
#include "tcg-be-null.h"
/* TODO list: