/* define it to use liveness analysis (better code) */
#define USE_LIVENESS_ANALYSIS
+#define USE_TCG_OPTIMIZATIONS
#include "config.h"
-#ifndef CONFIG_DEBUG_TCG
+#if !defined(CONFIG_DEBUG_TCG) && !defined(NDEBUG)
/* define it to suppress various consistency checks (faster) */
#define NDEBUG
#endif
-#include <stdarg.h>
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-#include <inttypes.h>
-#ifdef _WIN32
-#include <malloc.h>
-#endif
-#ifdef _AIX
-#include <alloca.h>
-#endif
-
#include "qemu-common.h"
#include "cache-utils.h"
#include "host-utils.h"
+#include "qemu-timer.h"
/* Note: the long term plan is to reduce the dependancies on the QEMU
CPU definitions. Currently they are used for qemu_ld/st
instructions */
#define NO_CPU_IO_DEFS
#include "cpu.h"
-#include "exec-all.h"
#include "tcg-op.h"
#include "elf.h"
#error GUEST_BASE not supported on this host.
#endif
+/* Forward declarations for functions declared in tcg-target.c and used here. */
+static void tcg_target_init(TCGContext *s);
+static void tcg_target_qemu_prologue(TCGContext *s);
static void patch_reloc(uint8_t *code_ptr, int type,
tcg_target_long value, tcg_target_long addend);
-static TCGOpDef tcg_op_defs[] = {
-#define DEF(s, n, copy_size) { #s, 0, 0, n, n, 0, copy_size },
-#define DEF2(s, oargs, iargs, cargs, flags) { #s, oargs, iargs, cargs, iargs + oargs + cargs, flags, 0 },
+/* Forward declarations for functions declared and used in tcg-target.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,
+ tcg_target_long arg2);
+static void tcg_out_mov(TCGContext *s, TCGType type, TCGReg ret, TCGReg arg);
+static void tcg_out_movi(TCGContext *s, TCGType type,
+ TCGReg ret, tcg_target_long arg);
+static void tcg_out_op(TCGContext *s, TCGOpcode opc, const TCGArg *args,
+ const int *const_args);
+static void tcg_out_st(TCGContext *s, TCGType type, TCGReg arg, TCGReg arg1,
+ tcg_target_long arg2);
+static int tcg_target_const_match(tcg_target_long val,
+ const TCGArgConstraint *arg_ct);
+static int tcg_target_get_call_iarg_regs_count(int flags);
+
+TCGOpDef tcg_op_defs[] = {
+#define DEF(s, oargs, iargs, cargs, flags) { #s, oargs, iargs, cargs, iargs + oargs + cargs, flags },
#include "tcg-opc.h"
#undef DEF
-#undef DEF2
};
+const size_t tcg_op_defs_max = ARRAY_SIZE(tcg_op_defs);
static TCGRegSet tcg_target_available_regs[2];
static TCGRegSet tcg_target_call_clobber_regs;
/* label relocation processing */
-void tcg_out_reloc(TCGContext *s, uint8_t *code_ptr, int type,
- int label_index, long addend)
+static void tcg_out_reloc(TCGContext *s, uint8_t *code_ptr, int type,
+ int label_index, long addend)
{
TCGLabel *l;
TCGRelocation *r;
}
}
-static void tcg_out_label(TCGContext *s, int label_index,
- tcg_target_long value)
+static void tcg_out_label(TCGContext *s, int label_index, void *ptr)
{
TCGLabel *l;
TCGRelocation *r;
+ tcg_target_long value = (tcg_target_long)ptr;
l = &s->labels[label_index];
if (l->has_value)
if (size > TCG_POOL_CHUNK_SIZE) {
/* big malloc: insert a new pool (XXX: could optimize) */
- p = qemu_malloc(sizeof(TCGPool) + size);
+ p = g_malloc(sizeof(TCGPool) + size);
p->size = size;
if (s->pool_current)
s->pool_current->next = p;
if (!p->next) {
new_pool:
pool_size = TCG_POOL_CHUNK_SIZE;
- p = qemu_malloc(sizeof(TCGPool) + pool_size);
+ p = g_malloc(sizeof(TCGPool) + pool_size);
p->size = pool_size;
p->next = NULL;
if (s->pool_current)
total_args += n;
}
- args_ct = qemu_malloc(sizeof(TCGArgConstraint) * total_args);
- sorted_args = qemu_malloc(sizeof(int) * total_args);
+ args_ct = g_malloc(sizeof(TCGArgConstraint) * total_args);
+ sorted_args = g_malloc(sizeof(int) * total_args);
for(op = 0; op < NB_OPS; op++) {
def = &tcg_op_defs[op];
}
tcg_target_init(s);
+}
+void tcg_prologue_init(TCGContext *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);
+ flush_icache_range((tcg_target_ulong)s->code_buf,
+ (tcg_target_ulong)s->code_ptr);
}
void tcg_set_frame(TCGContext *s, int reg,
s->nb_temps++;
}
}
+
+#if defined(CONFIG_DEBUG_TCG)
+ s->temps_in_use++;
+#endif
return idx;
}
TCGTemp *ts;
int k;
+#if defined(CONFIG_DEBUG_TCG)
+ s->temps_in_use--;
+ if (s->temps_in_use < 0) {
+ fprintf(stderr, "More temporaries freed than allocated!\n");
+ }
+#endif
+
assert(idx >= s->nb_globals && idx < s->nb_temps);
ts = &s->temps[idx];
assert(ts->temp_allocated != 0);
return t0;
}
+#if defined(CONFIG_DEBUG_TCG)
+void tcg_clear_temp_count(void)
+{
+ TCGContext *s = &tcg_ctx;
+ s->temps_in_use = 0;
+}
+
+int tcg_check_temp_count(void)
+{
+ TCGContext *s = &tcg_ctx;
+ if (s->temps_in_use) {
+ /* Clear the count so that we don't give another
+ * warning immediately next time around.
+ */
+ s->temps_in_use = 0;
+ return 1;
+ }
+ return 0;
+}
+#endif
+
void tcg_register_helper(void *func, const char *name)
{
TCGContext *s = &tcg_ctx;
void tcg_gen_callN(TCGContext *s, TCGv_ptr func, unsigned int flags,
int sizemask, TCGArg ret, int nargs, TCGArg *args)
{
+#if defined(TCG_TARGET_I386) && TCG_TARGET_REG_BITS < 64
int call_type;
+#endif
int i;
int real_args;
int nb_rets;
TCGArg *nparam;
+
+#if defined(TCG_TARGET_EXTEND_ARGS) && TCG_TARGET_REG_BITS == 64
+ for (i = 0; i < nargs; ++i) {
+ int is_64bit = sizemask & (1 << (i+1)*2);
+ int is_signed = sizemask & (2 << (i+1)*2);
+ if (!is_64bit) {
+ TCGv_i64 temp = tcg_temp_new_i64();
+ TCGv_i64 orig = MAKE_TCGV_I64(args[i]);
+ if (is_signed) {
+ tcg_gen_ext32s_i64(temp, orig);
+ } else {
+ tcg_gen_ext32u_i64(temp, orig);
+ }
+ args[i] = GET_TCGV_I64(temp);
+ }
+ }
+#endif /* TCG_TARGET_EXTEND_ARGS */
+
*gen_opc_ptr++ = INDEX_op_call;
nparam = gen_opparam_ptr++;
+#if defined(TCG_TARGET_I386) && TCG_TARGET_REG_BITS < 64
call_type = (flags & TCG_CALL_TYPE_MASK);
+#endif
if (ret != TCG_CALL_DUMMY_ARG) {
#if TCG_TARGET_REG_BITS < 64
if (sizemask & 1) {
real_args = 0;
for (i = 0; i < nargs; i++) {
#if TCG_TARGET_REG_BITS < 64
- if (sizemask & (2 << i)) {
+ int is_64bit = sizemask & (1 << (i+1)*2);
+ if (is_64bit) {
#ifdef TCG_TARGET_I386
/* REGPARM case: if the third parameter is 64 bit, it is
allocated on the stack */
real_args++;
}
#endif
-#ifdef TCG_TARGET_WORDS_BIGENDIAN
+ /* If stack grows up, then we will be placing successive
+ arguments at lower addresses, which means we need to
+ reverse the order compared to how we would normally
+ treat either big or little-endian. For those arguments
+ that will wind up in registers, this still works for
+ HPPA (the only current STACK_GROWSUP target) since the
+ argument registers are *also* allocated in decreasing
+ order. If another such target is added, this logic may
+ have to get more complicated to differentiate between
+ stack arguments and register arguments. */
+#if defined(TCG_TARGET_WORDS_BIGENDIAN) != defined(TCG_TARGET_STACK_GROWSUP)
*gen_opparam_ptr++ = args[i] + 1;
*gen_opparam_ptr++ = args[i];
#else
*gen_opparam_ptr++ = args[i] + 1;
#endif
real_args += 2;
- } else
-#endif
- {
- *gen_opparam_ptr++ = args[i];
- real_args++;
+ continue;
}
+#endif /* TCG_TARGET_REG_BITS < 64 */
+
+ *gen_opparam_ptr++ = args[i];
+ real_args++;
}
*gen_opparam_ptr++ = GET_TCGV_PTR(func);
/* total parameters, needed to go backward in the instruction stream */
*gen_opparam_ptr++ = 1 + nb_rets + real_args + 3;
+
+#if defined(TCG_TARGET_EXTEND_ARGS) && TCG_TARGET_REG_BITS == 64
+ for (i = 0; i < nargs; ++i) {
+ int is_64bit = sizemask & (1 << (i+1)*2);
+ if (!is_64bit) {
+ TCGv_i64 temp = MAKE_TCGV_I64(args[i]);
+ tcg_temp_free_i64(temp);
+ }
+ }
+#endif /* TCG_TARGET_EXTEND_ARGS */
}
#if TCG_TARGET_REG_BITS == 32
}
#endif
+
static void tcg_reg_alloc_start(TCGContext *s)
{
int i;
{
TCGTemp *ts;
+ assert(idx >= 0 && idx < s->nb_temps);
ts = &s->temps[idx];
+ assert(ts);
if (idx < s->nb_globals) {
pstrcpy(buf, buf_size, ts->name);
} else {
const uint16_t *opc_ptr;
const TCGArg *args;
TCGArg arg;
- int c, i, k, nb_oargs, nb_iargs, nb_cargs, first_insn;
+ TCGOpcode c;
+ int i, k, nb_oargs, nb_iargs, nb_cargs, first_insn;
const TCGOpDef *def;
char buf[128];
fprintf(outfile, "%s",
tcg_get_arg_str_idx(s, buf, sizeof(buf), args[k++]));
}
- if (c == INDEX_op_brcond_i32
+ switch (c) {
+ case INDEX_op_brcond_i32:
+#if TCG_TARGET_REG_BITS == 32
+ case INDEX_op_brcond2_i32:
+#elif TCG_TARGET_REG_BITS == 64
+ case INDEX_op_brcond_i64:
+#endif
+ case INDEX_op_setcond_i32:
#if TCG_TARGET_REG_BITS == 32
- || c == INDEX_op_brcond2_i32
+ case INDEX_op_setcond2_i32:
#elif TCG_TARGET_REG_BITS == 64
- || c == INDEX_op_brcond_i64
+ case INDEX_op_setcond_i64:
#endif
- ) {
if (args[k] < ARRAY_SIZE(cond_name) && cond_name[args[k]])
fprintf(outfile, ",%s", cond_name[args[k++]]);
else
fprintf(outfile, ",$0x%" TCG_PRIlx, args[k++]);
i = 1;
- }
- else
+ break;
+ default:
i = 0;
+ break;
+ }
for(; i < nb_cargs; i++) {
if (k != 0)
fprintf(outfile, ",");
void tcg_add_target_add_op_defs(const TCGTargetOpDef *tdefs)
{
- int op;
+ TCGOpcode op;
TCGOpDef *def;
const char *ct_str;
int i, nb_args;
for(;;) {
- if (tdefs->op < 0)
+ if (tdefs->op == (TCGOpcode)-1)
break;
op = tdefs->op;
- assert(op >= 0 && op < NB_OPS);
+ assert((unsigned)op < NB_OPS);
def = &tcg_op_defs[op];
+#if defined(CONFIG_DEBUG_TCG)
+ /* Duplicate entry in op definitions? */
+ assert(!def->used);
+ def->used = 1;
+#endif
nb_args = def->nb_iargs + def->nb_oargs;
for(i = 0; i < nb_args; i++) {
ct_str = tdefs->args_ct_str[i];
+ /* Incomplete TCGTargetOpDef entry? */
+ assert(ct_str != NULL);
tcg_regset_clear(def->args_ct[i].u.regs);
def->args_ct[i].ct = 0;
if (ct_str[0] >= '0' && ct_str[0] <= '9') {
}
}
+ /* TCGTargetOpDef entry with too much information? */
+ assert(i == TCG_MAX_OP_ARGS || tdefs->args_ct_str[i] == NULL);
+
/* sort the constraints (XXX: this is just an heuristic) */
sort_constraints(def, 0, def->nb_oargs);
sort_constraints(def, def->nb_oargs, def->nb_iargs);
tdefs++;
}
+#if defined(CONFIG_DEBUG_TCG)
+ i = 0;
+ for (op = 0; op < ARRAY_SIZE(tcg_op_defs); op++) {
+ const TCGOpDef *def = &tcg_op_defs[op];
+ if (op < INDEX_op_call
+ || op == INDEX_op_debug_insn_start
+ || (def->flags & TCG_OPF_NOT_PRESENT)) {
+ /* Wrong entry in op definitions? */
+ if (def->used) {
+ fprintf(stderr, "Invalid op definition for %s\n", def->name);
+ i = 1;
+ }
+ } else {
+ /* Missing entry in op definitions? */
+ if (!def->used) {
+ fprintf(stderr, "Missing op definition for %s\n", def->name);
+ i = 1;
+ }
+ }
+ }
+ if (i == 1) {
+ tcg_abort();
+ }
+#endif
}
#ifdef USE_LIVENESS_ANALYSIS
}
}
-/* Liveness analysis : update the opc_dead_iargs array to tell if a
+/* Liveness analysis : update the opc_dead_args array to tell if a
given input arguments is dead. Instructions updating dead
temporaries are removed. */
static void tcg_liveness_analysis(TCGContext *s)
{
- int i, op_index, op, nb_args, nb_iargs, nb_oargs, arg, nb_ops;
+ int i, op_index, nb_args, nb_iargs, nb_oargs, arg, nb_ops;
+ TCGOpcode op;
TCGArg *args;
const TCGOpDef *def;
uint8_t *dead_temps;
- unsigned int dead_iargs;
+ unsigned int dead_args;
gen_opc_ptr++; /* skip end */
nb_ops = gen_opc_ptr - gen_opc_buf;
- /* XXX: make it really dynamic */
- s->op_dead_iargs = tcg_malloc(OPC_BUF_SIZE * sizeof(uint16_t));
+ s->op_dead_args = tcg_malloc(nb_ops * sizeof(uint16_t));
dead_temps = tcg_malloc(s->nb_temps);
memset(dead_temps, 1, s->nb_temps);
do_not_remove_call:
/* output args are dead */
+ dead_args = 0;
for(i = 0; i < nb_oargs; i++) {
arg = args[i];
+ if (dead_temps[arg]) {
+ dead_args |= (1 << i);
+ }
dead_temps[arg] = 1;
}
}
/* input args are live */
- dead_iargs = 0;
- for(i = 0; i < nb_iargs; i++) {
- arg = args[i + nb_oargs];
+ for(i = nb_oargs; i < nb_iargs + nb_oargs; i++) {
+ arg = args[i];
if (arg != TCG_CALL_DUMMY_ARG) {
if (dead_temps[arg]) {
- dead_iargs |= (1 << i);
+ dead_args |= (1 << i);
}
dead_temps[arg] = 0;
}
}
- s->op_dead_iargs[op_index] = dead_iargs;
+ s->op_dead_args[op_index] = dead_args;
}
args--;
}
do_not_remove:
/* output args are dead */
+ dead_args = 0;
for(i = 0; i < nb_oargs; i++) {
arg = args[i];
+ if (dead_temps[arg]) {
+ dead_args |= (1 << i);
+ }
dead_temps[arg] = 1;
}
}
/* input args are live */
- dead_iargs = 0;
- for(i = 0; i < nb_iargs; i++) {
- arg = args[i + nb_oargs];
+ for(i = nb_oargs; i < nb_oargs + nb_iargs; i++) {
+ arg = args[i];
if (dead_temps[arg]) {
- dead_iargs |= (1 << i);
+ dead_args |= (1 << i);
}
dead_temps[arg] = 0;
}
- s->op_dead_iargs[op_index] = dead_iargs;
+ s->op_dead_args[op_index] = dead_args;
}
break;
}
}
#else
/* dummy liveness analysis */
-void tcg_liveness_analysis(TCGContext *s)
+static void tcg_liveness_analysis(TCGContext *s)
{
int nb_ops;
nb_ops = gen_opc_ptr - gen_opc_buf;
- s->op_dead_iargs = tcg_malloc(nb_ops * sizeof(uint16_t));
- memset(s->op_dead_iargs, 0, nb_ops * sizeof(uint16_t));
+ s->op_dead_args = tcg_malloc(nb_ops * sizeof(uint16_t));
+ memset(s->op_dead_args, 0, nb_ops * sizeof(uint16_t));
}
#endif
{
TCGTemp *ts;
ts = &s->temps[temp];
- s->current_frame_offset = (s->current_frame_offset + sizeof(tcg_target_long) - 1) & ~(sizeof(tcg_target_long) - 1);
- if (s->current_frame_offset + sizeof(tcg_target_long) > s->frame_end)
+#ifndef __sparc_v9__ /* Sparc64 stack is accessed with offset of 2047 */
+ s->current_frame_offset = (s->current_frame_offset +
+ (tcg_target_long)sizeof(tcg_target_long) - 1) &
+ ~(sizeof(tcg_target_long) - 1);
+#endif
+ if (s->current_frame_offset + (tcg_target_long)sizeof(tcg_target_long) >
+ s->frame_end) {
tcg_abort();
+ }
ts->mem_offset = s->current_frame_offset;
ts->mem_reg = s->frame_reg;
ts->mem_allocated = 1;
- s->current_frame_offset += sizeof(tcg_target_long);
+ s->current_frame_offset += (tcg_target_long)sizeof(tcg_target_long);
}
/* free register 'reg' by spilling the corresponding temporary if necessary */
ts->val_type = TEMP_VAL_MEM;
break;
case TEMP_VAL_CONST:
+ reg = tcg_reg_alloc(s, tcg_target_available_regs[ts->type],
+ allocated_regs);
if (!ts->mem_allocated)
temp_allocate_frame(s, temp);
- if (ts->type == TCG_TYPE_I32) {
- tcg_out_sti(s, ts->type, ts->val, ts->mem_reg, ts->mem_offset);
- } else {
- reg = tcg_reg_alloc(s, tcg_target_available_regs[ts->type],
- allocated_regs);
- tcg_out_movi(s, ts->type, reg, ts->val);
- tcg_out_st(s, ts->type, reg, ts->mem_reg, ts->mem_offset);
- }
+ tcg_out_movi(s, ts->type, reg, ts->val);
+ tcg_out_st(s, ts->type, reg, ts->mem_reg, ts->mem_offset);
ts->val_type = TEMP_VAL_MEM;
break;
case TEMP_VAL_MEM:
}
}
-/* save globals to their cannonical location and assume they can be
+/* save globals to their canonical location and assume they can be
modified be the following code. 'allocated_regs' is used in case a
temporary registers needs to be allocated to store a constant. */
static void save_globals(TCGContext *s, TCGRegSet allocated_regs)
save_globals(s, allocated_regs);
}
-#define IS_DEAD_IARG(n) ((dead_iargs >> (n)) & 1)
+#define IS_DEAD_ARG(n) ((dead_args >> (n)) & 1)
static void tcg_reg_alloc_movi(TCGContext *s, const TCGArg *args)
{
static void tcg_reg_alloc_mov(TCGContext *s, const TCGOpDef *def,
const TCGArg *args,
- unsigned int dead_iargs)
+ unsigned int dead_args)
{
TCGTemp *ts, *ots;
int reg;
ts = &s->temps[args[1]];
arg_ct = &def->args_ct[0];
- /* XXX: always mark arg dead if IS_DEAD_IARG(0) */
+ /* XXX: always mark arg dead if IS_DEAD_ARG(1) */
if (ts->val_type == TEMP_VAL_REG) {
- if (IS_DEAD_IARG(0) && !ts->fixed_reg && !ots->fixed_reg) {
+ if (IS_DEAD_ARG(1) && !ts->fixed_reg && !ots->fixed_reg) {
/* the mov can be suppressed */
if (ots->val_type == TEMP_VAL_REG)
s->reg_to_temp[ots->reg] = -1;
reg = tcg_reg_alloc(s, arg_ct->u.regs, s->reserved_regs);
}
if (ts->reg != reg) {
- tcg_out_mov(s, reg, ts->reg);
+ tcg_out_mov(s, ots->type, reg, ts->reg);
}
}
} else if (ts->val_type == TEMP_VAL_MEM) {
}
static void tcg_reg_alloc_op(TCGContext *s,
- const TCGOpDef *def, int opc,
+ const TCGOpDef *def, TCGOpcode opc,
const TCGArg *args,
- unsigned int dead_iargs)
+ unsigned int dead_args)
{
TCGRegSet allocated_regs;
int i, k, nb_iargs, nb_oargs, reg;
/* if the input is aliased to an output and if it is
not dead after the instruction, we must allocate
a new register and move it */
- if (!IS_DEAD_IARG(i - nb_oargs))
+ if (!IS_DEAD_ARG(i)) {
goto allocate_in_reg;
+ }
}
}
reg = ts->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);
- tcg_out_mov(s, reg, ts->reg);
+ tcg_out_mov(s, ts->type, reg, ts->reg);
}
new_args[i] = reg;
const_args[i] = 0;
tcg_reg_alloc_bb_end(s, allocated_regs);
} else {
/* mark dead temporaries and free the associated registers */
- for(i = 0; i < nb_iargs; i++) {
- arg = args[nb_oargs + i];
- if (IS_DEAD_IARG(i)) {
+ for(i = nb_oargs; i < nb_oargs + nb_iargs; i++) {
+ arg = args[i];
+ if (IS_DEAD_ARG(i)) {
ts = &s->temps[arg];
if (!ts->fixed_reg) {
if (ts->val_type == TEMP_VAL_REG)
if (!ts->fixed_reg) {
if (ts->val_type == TEMP_VAL_REG)
s->reg_to_temp[ts->reg] = -1;
- ts->val_type = TEMP_VAL_REG;
- ts->reg = reg;
- /* temp value is modified, so the value kept in memory is
- potentially not the same */
- ts->mem_coherent = 0;
- s->reg_to_temp[reg] = arg;
+ if (IS_DEAD_ARG(i)) {
+ ts->val_type = TEMP_VAL_DEAD;
+ } else {
+ ts->val_type = TEMP_VAL_REG;
+ ts->reg = reg;
+ /* temp value is modified, so the value kept in memory is
+ potentially not the same */
+ ts->mem_coherent = 0;
+ s->reg_to_temp[reg] = arg;
+ }
}
oarg_end:
new_args[i] = reg;
ts = &s->temps[args[i]];
reg = new_args[i];
if (ts->fixed_reg && ts->reg != reg) {
- tcg_out_mov(s, ts->reg, reg);
+ tcg_out_mov(s, ts->type, ts->reg, reg);
}
}
}
#endif
static int tcg_reg_alloc_call(TCGContext *s, const TCGOpDef *def,
- int opc, const TCGArg *args,
- unsigned int dead_iargs)
+ TCGOpcode opc, const TCGArg *args,
+ unsigned int dead_args)
{
int nb_iargs, nb_oargs, flags, nb_regs, i, reg, nb_params;
TCGArg arg, func_arg;
nb_regs = nb_params;
/* assign stack slots first */
- /* XXX: preallocate call stack */
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);
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: if more than TCG_STATIC_CALL_ARGS_SIZE is needed,
+ preallocate call stack */
+ tcg_abort();
}
stack_offset = TCG_TARGET_CALL_STACK_OFFSET;
tcg_reg_free(s, reg);
if (ts->val_type == TEMP_VAL_REG) {
if (ts->reg != reg) {
- tcg_out_mov(s, reg, ts->reg);
+ tcg_out_mov(s, ts->type, reg, ts->reg);
}
} else if (ts->val_type == TEMP_VAL_MEM) {
tcg_out_ld(s, ts->type, reg, ts->mem_reg, ts->mem_offset);
reg = ts->reg;
if (!tcg_regset_test_reg(arg_ct->u.regs, reg)) {
reg = tcg_reg_alloc(s, arg_ct->u.regs, allocated_regs);
- tcg_out_mov(s, reg, ts->reg);
+ tcg_out_mov(s, ts->type, reg, ts->reg);
}
func_arg = reg;
tcg_regset_set_reg(allocated_regs, reg);
/* mark dead temporaries and free the associated registers */
- for(i = 0; i < nb_iargs; i++) {
- arg = args[nb_oargs + i];
- if (IS_DEAD_IARG(i)) {
+ for(i = nb_oargs; i < nb_iargs + nb_oargs; i++) {
+ arg = args[i];
+ if (IS_DEAD_ARG(i)) {
ts = &s->temps[arg];
if (!ts->fixed_reg) {
if (ts->val_type == TEMP_VAL_REG)
}
tcg_out_op(s, opc, &func_arg, &const_func_arg);
-
- 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++) {
assert(s->reg_to_temp[reg] == -1);
if (ts->fixed_reg) {
if (ts->reg != reg) {
- tcg_out_mov(s, ts->reg, reg);
+ tcg_out_mov(s, ts->type, ts->reg, reg);
}
} else {
if (ts->val_type == TEMP_VAL_REG)
s->reg_to_temp[ts->reg] = -1;
- ts->val_type = TEMP_VAL_REG;
- ts->reg = reg;
- ts->mem_coherent = 0;
- s->reg_to_temp[reg] = arg;
+ if (IS_DEAD_ARG(i)) {
+ ts->val_type = TEMP_VAL_DEAD;
+ } else {
+ ts->val_type = TEMP_VAL_REG;
+ ts->reg = reg;
+ ts->mem_coherent = 0;
+ s->reg_to_temp[reg] = arg;
+ }
}
}
static inline int tcg_gen_code_common(TCGContext *s, uint8_t *gen_code_buf,
long search_pc)
{
- int opc, op_index;
+ TCGOpcode opc;
+ int op_index;
const TCGOpDef *def;
- unsigned int dead_iargs;
+ unsigned int dead_args;
const TCGArg *args;
#ifdef DEBUG_DISAS
}
#endif
+#ifdef USE_TCG_OPTIMIZATIONS
+ gen_opparam_ptr =
+ tcg_optimize(s, gen_opc_ptr, gen_opparam_buf, tcg_op_defs);
+#endif
+
#ifdef CONFIG_PROFILER
s->la_time -= profile_getclock();
#endif
#ifdef DEBUG_DISAS
if (unlikely(qemu_loglevel_mask(CPU_LOG_TB_OP_OPT))) {
- qemu_log("OP after la:\n");
+ qemu_log("OP after liveness analysis:\n");
tcg_dump_ops(s, logfile);
qemu_log("\n");
}
#if TCG_TARGET_REG_BITS == 64
case INDEX_op_mov_i64:
#endif
- dead_iargs = s->op_dead_iargs[op_index];
- tcg_reg_alloc_mov(s, def, args, dead_iargs);
+ dead_args = s->op_dead_args[op_index];
+ tcg_reg_alloc_mov(s, def, args, dead_args);
break;
case INDEX_op_movi_i32:
#if TCG_TARGET_REG_BITS == 64
break;
case INDEX_op_set_label:
tcg_reg_alloc_bb_end(s, s->reserved_regs);
- tcg_out_label(s, args[0], (long)s->code_ptr);
+ tcg_out_label(s, args[0], s->code_ptr);
break;
case INDEX_op_call:
- dead_iargs = s->op_dead_iargs[op_index];
- args += tcg_reg_alloc_call(s, def, opc, args, dead_iargs);
+ dead_args = s->op_dead_args[op_index];
+ args += tcg_reg_alloc_call(s, def, opc, args, dead_args);
goto next;
case INDEX_op_end:
goto the_end;
default:
+ /* Sanity check that we've not introduced any unhandled opcodes. */
+ if (def->flags & TCG_OPF_NOT_PRESENT) {
+ tcg_abort();
+ }
/* Note: in order to speed up the code, it would be much
faster to have specialized register allocator functions for
some common argument patterns */
- dead_iargs = s->op_dead_iargs[op_index];
- tcg_reg_alloc_op(s, def, opc, args, dead_iargs);
+ dead_args = s->op_dead_args[op_index];
+ tcg_reg_alloc_op(s, def, opc, args, dead_args);
break;
}
args += def->nb_args;
tcg_gen_code_common(s, gen_code_buf, -1);
/* flush instruction cache */
- flush_icache_range((unsigned long)gen_code_buf,
- (unsigned long)s->code_ptr);
+ flush_icache_range((tcg_target_ulong)gen_code_buf,
+ (tcg_target_ulong)s->code_ptr);
+
return s->code_ptr - gen_code_buf;
}
}
#ifdef CONFIG_PROFILER
-void tcg_dump_info(FILE *f,
- int (*cpu_fprintf)(FILE *f, const char *fmt, ...))
+void tcg_dump_info(FILE *f, fprintf_function cpu_fprintf)
{
TCGContext *s = &tcg_ctx;
int64_t tot;
dump_op_count();
}
#else
-void tcg_dump_info(FILE *f,
- int (*cpu_fprintf)(FILE *f, const char *fmt, ...))
+void tcg_dump_info(FILE *f, fprintf_function cpu_fprintf)
{
cpu_fprintf(f, "[TCG profiler not compiled]\n");
}