aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPeter Maydell <peter.maydell@linaro.org>2016-02-23 18:49:30 +0000
committerPeter Maydell <peter.maydell@linaro.org>2016-02-23 18:49:30 +0000
commit7bd57b515067b355ac997d29b0daf4fb8689e9be (patch)
tree1e08cc4a2cd6e9e34dcaf562d01ae6988905a28a
parent1b1624092d1f1f746adea6e1237a07f6788c2e3d (diff)
parentc3b7f66800fbf9f47fddbcf2e2cd30ea932e0aae (diff)
downloadqemu-7bd57b515067b355ac997d29b0daf4fb8689e9be.zip
qemu-7bd57b515067b355ac997d29b0daf4fb8689e9be.tar.gz
qemu-7bd57b515067b355ac997d29b0daf4fb8689e9be.tar.bz2
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>
-rw-r--r--qemu-tech.texi2
-rwxr-xr-xscripts/clean-includes5
-rw-r--r--target-sparc/translate.c204
-rw-r--r--tcg/README5
-rw-r--r--tcg/aarch64/tcg-target.inc.c (renamed from tcg/aarch64/tcg-target.c)1
-rw-r--r--tcg/arm/tcg-target.inc.c (renamed from tcg/arm/tcg-target.c)1
-rw-r--r--tcg/i386/tcg-target.inc.c (renamed from tcg/i386/tcg-target.c)1
-rw-r--r--tcg/ia64/tcg-target.inc.c (renamed from tcg/ia64/tcg-target.c)0
-rw-r--r--tcg/mips/tcg-target.inc.c (renamed from tcg/mips/tcg-target.c)1
-rw-r--r--tcg/ppc/tcg-target.inc.c (renamed from tcg/ppc/tcg-target.c)1
-rw-r--r--tcg/s390/tcg-target.inc.c (renamed from tcg/s390/tcg-target.c)1
-rw-r--r--tcg/sparc/tcg-target.inc.c (renamed from tcg/sparc/tcg-target.c)1
-rw-r--r--tcg/tcg.c145
-rw-r--r--tcg/tcg.h4
-rw-r--r--tcg/tci/README4
-rw-r--r--tcg/tci/tcg-target.inc.c (renamed from tcg/tci/tcg-target.c)1
16 files changed, 214 insertions, 163 deletions
diff --git a/qemu-tech.texi b/qemu-tech.texi
index 022017d..bdb2285 100644
--- a/qemu-tech.texi
+++ b/qemu-tech.texi
@@ -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
diff --git a/scripts/clean-includes b/scripts/clean-includes
index d2dd7ae..a1faa60 100755
--- a/scripts/clean-includes
+++ b/scripts/clean-includes
@@ -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
;;
diff --git a/target-sparc/translate.c b/target-sparc/translate.c
index 536c4b5..00d61ee 100644
--- a/target-sparc/translate.c
+++ b/target-sparc/translate.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) {
+ 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));
- }
+ tcg_gen_movi_tl(t, 0);
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,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]);
}
}
diff --git a/tcg/README b/tcg/README
index 34c0775..f4a8ac1 100644
--- a/tcg/README
+++ b/tcg/README
@@ -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
diff --git a/tcg/aarch64/tcg-target.c b/tcg/aarch64/tcg-target.inc.c
index 8467d5d..0ed10a9 100644
--- a/tcg/aarch64/tcg-target.c
+++ b/tcg/aarch64/tcg-target.inc.c
@@ -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"
diff --git a/tcg/arm/tcg-target.c b/tcg/arm/tcg-target.inc.c
index 146ac00..3edf6a6 100644
--- a/tcg/arm/tcg-target.c
+++ b/tcg/arm/tcg-target.inc.c
@@ -22,7 +22,6 @@
* THE SOFTWARE.
*/
-#include "qemu/osdep.h"
#include "elf.h"
#include "tcg-be-ldst.h"
diff --git a/tcg/i386/tcg-target.c b/tcg/i386/tcg-target.inc.c
index d90636c..9187d34 100644
--- a/tcg/i386/tcg-target.c
+++ b/tcg/i386/tcg-target.inc.c
@@ -22,7 +22,6 @@
* THE SOFTWARE.
*/
-#include "qemu/osdep.h"
#include "tcg-be-ldst.h"
#ifndef NDEBUG
diff --git a/tcg/ia64/tcg-target.c b/tcg/ia64/tcg-target.inc.c
index 62d6549..62d6549 100644
--- a/tcg/ia64/tcg-target.c
+++ b/tcg/ia64/tcg-target.inc.c
diff --git a/tcg/mips/tcg-target.c b/tcg/mips/tcg-target.inc.c
index 2dc4998..297bd00 100644
--- a/tcg/mips/tcg-target.c
+++ b/tcg/mips/tcg-target.inc.c
@@ -24,7 +24,6 @@
* THE SOFTWARE.
*/
-#include "qemu/osdep.h"
#include "tcg-be-ldst.h"
#ifdef HOST_WORDS_BIGENDIAN
diff --git a/tcg/ppc/tcg-target.c b/tcg/ppc/tcg-target.inc.c
index c593344..8c1c2df 100644
--- a/tcg/ppc/tcg-target.c
+++ b/tcg/ppc/tcg-target.inc.c
@@ -22,7 +22,6 @@
* THE SOFTWARE.
*/
-#include "qemu/osdep.h"
#include "tcg-be-ldst.h"
#if defined _CALL_DARWIN || defined __APPLE__
diff --git a/tcg/s390/tcg-target.c b/tcg/s390/tcg-target.inc.c
index 58520fa..fbf97bb 100644
--- a/tcg/s390/tcg-target.c
+++ b/tcg/s390/tcg-target.inc.c
@@ -24,7 +24,6 @@
* THE SOFTWARE.
*/
-#include "qemu/osdep.h"
#include "tcg-be-ldst.h"
/* We only support generating code for 64-bit mode. */
diff --git a/tcg/sparc/tcg-target.c b/tcg/sparc/tcg-target.inc.c
index d3100ab..54df1bc 100644
--- a/tcg/sparc/tcg-target.c
+++ b/tcg/sparc/tcg-target.inc.c
@@ -22,7 +22,6 @@
* THE SOFTWARE.
*/
-#include "qemu/osdep.h"
#include "tcg-be-null.h"
#ifndef NDEBUG
diff --git a/tcg/tcg.c b/tcg/tcg.c
index 0317c9e..550671b 100644
--- a/tcg/tcg.c
+++ b/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);
diff --git a/tcg/tcg.h b/tcg/tcg.h
index 83da5fb..c45329a 100644
--- a/tcg/tcg.h
+++ b/tcg/tcg.h
@@ -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];
diff --git a/tcg/tci/README b/tcg/tci/README
index dc57f07..3786b09 100644
--- a/tcg/tci/README
+++ b/tcg/tci/README
@@ -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
diff --git a/tcg/tci/tcg-target.c b/tcg/tci/tcg-target.inc.c
index 16ce048..4afe4d7 100644
--- a/tcg/tci/tcg-target.c
+++ b/tcg/tci/tcg-target.inc.c
@@ -22,7 +22,6 @@
* THE SOFTWARE.
*/
-#include "qemu/osdep.h"
#include "tcg-be-null.h"
/* TODO list: