#define LO_OFF (MIPS_BE * 4)
#define HI_OFF (4 - LO_OFF)
-#ifndef NDEBUG
+#ifdef CONFIG_DEBUG_TCG
static const char * const tcg_target_reg_names[TCG_TARGET_NB_REGS] = {
"zero",
"at",
#define TCG_TMP1 TCG_REG_T9
/* check if we really need so many registers :P */
-static const TCGReg tcg_target_reg_alloc_order[] = {
+static const int tcg_target_reg_alloc_order[] = {
/* Call saved registers. */
TCG_REG_S0,
TCG_REG_S1,
{
/* Let the compiler perform the right-shift as part of the arithmetic. */
ptrdiff_t disp = target - (pc + 1);
- assert(disp == (int16_t)disp);
+ tcg_debug_assert(disp == (int16_t)disp);
return disp & 0xffff;
}
static inline uint32_t reloc_26_val(tcg_insn_unit *pc, tcg_insn_unit *target)
{
- assert((((uintptr_t)pc ^ (uintptr_t)target) & 0xf0000000) == 0);
+ tcg_debug_assert((((uintptr_t)pc ^ (uintptr_t)target) & 0xf0000000) == 0);
return ((uintptr_t)target >> 2) & 0x3ffffff;
}
static void patch_reloc(tcg_insn_unit *code_ptr, int type,
intptr_t value, intptr_t addend)
{
- assert(type == R_MIPS_PC16);
- assert(addend == 0);
+ tcg_debug_assert(type == R_MIPS_PC16);
+ tcg_debug_assert(addend == 0);
reloc_pc16(code_ptr, (tcg_insn_unit *)value);
}
OPC_JALR = OPC_SPECIAL | 0x09,
OPC_MOVZ = OPC_SPECIAL | 0x0A,
OPC_MOVN = OPC_SPECIAL | 0x0B,
+ OPC_SYNC = OPC_SPECIAL | 0x0F,
OPC_MFHI = OPC_SPECIAL | 0x10,
OPC_MFLO = OPC_SPECIAL | 0x12,
OPC_MULT = OPC_SPECIAL | 0x18,
* backwards-compatible at the assembly level.
*/
OPC_MUL = use_mips32r6_instructions ? OPC_MUL_R6 : OPC_MUL_R5,
+
+ /* MIPS r6 introduced names for weaker variants of SYNC. These are
+ backward compatible to previous architecture revisions. */
+ OPC_SYNC_WMB = OPC_SYNC | 0x04 << 5,
+ OPC_SYNC_MB = OPC_SYNC | 0x10 << 5,
+ OPC_SYNC_ACQUIRE = OPC_SYNC | 0x11 << 5,
+ OPC_SYNC_RELEASE = OPC_SYNC | 0x12 << 5,
+ OPC_SYNC_RMB = OPC_SYNC | 0x13 << 5,
} MIPSInsn;
/*
if ((from ^ dest) & -(1 << 28)) {
return false;
}
- assert((dest & 3) == 0);
+ tcg_debug_assert((dest & 3) == 0);
inst = opc;
inst |= (dest >> 2) & 0x3ffffff;
tcg_out_ldst(s, OPC_SW, arg, arg1, arg2);
}
+static inline bool tcg_out_sti(TCGContext *s, TCGType type, TCGArg val,
+ TCGReg base, intptr_t ofs)
+{
+ if (val == 0) {
+ tcg_out_st(s, type, TCG_REG_ZERO, base, ofs);
+ return true;
+ }
+ return false;
+}
+
static inline void tcg_out_addi(TCGContext *s, TCGReg reg, TCGArg val)
{
if (val == (int16_t)val) {
TCGReg tmp0 = TCG_TMP0;
TCGReg tmp1 = ret;
- assert(ret != TCG_TMP0);
+ tcg_debug_assert(ret != TCG_TMP0);
if (ret == ah || ret == bh) {
- assert(ret != TCG_TMP1);
+ tcg_debug_assert(ret != TCG_TMP1);
tmp1 = TCG_TMP1;
}
TCGReg addrh, TCGMemOpIdx oi,
tcg_insn_unit *label_ptr[2], bool is_load)
{
- TCGMemOp s_bits = get_memop(oi) & MO_SIZE;
+ TCGMemOp opc = get_memop(oi);
+ unsigned s_bits = opc & MO_SIZE;
+ unsigned a_bits = get_alignment_bits(opc);
int mem_index = get_mmuidx(oi);
int cmp_off
= (is_load
tcg_out_opc_imm(s, OPC_LW, TCG_TMP0, TCG_REG_A0,
cmp_off + (TARGET_LONG_BITS == 64 ? LO_OFF : 0));
+ /* We don't currently support unaligned accesses.
+ We could do so with mips32r6. */
+ if (a_bits < s_bits) {
+ a_bits = s_bits;
+ }
/* Mask the page bits, keeping the alignment bits to compare against.
In between on 32-bit targets, load the tlb addend for the fast path. */
tcg_out_movi(s, TCG_TYPE_I32, TCG_TMP1,
- TARGET_PAGE_MASK | ((1 << s_bits) - 1));
+ TARGET_PAGE_MASK | ((1 << a_bits) - 1));
if (TARGET_LONG_BITS == 32) {
tcg_out_opc_imm(s, OPC_LW, TCG_REG_A0, TCG_REG_A0, add_off);
}
#endif
}
+static void tcg_out_mb(TCGContext *s, TCGArg a0)
+{
+ static const MIPSInsn sync[] = {
+ /* Note that SYNC_MB is a slightly weaker than SYNC 0,
+ as the former is an ordering barrier and the latter
+ is a completion barrier. */
+ [0 ... TCG_MO_ALL] = OPC_SYNC_MB,
+ [TCG_MO_LD_LD] = OPC_SYNC_RMB,
+ [TCG_MO_ST_ST] = OPC_SYNC_WMB,
+ [TCG_MO_LD_ST] = OPC_SYNC_RELEASE,
+ [TCG_MO_LD_ST | TCG_MO_ST_ST] = OPC_SYNC_RELEASE,
+ [TCG_MO_LD_ST | TCG_MO_LD_LD] = OPC_SYNC_ACQUIRE,
+ };
+ tcg_out32(s, sync[a0 & TCG_MO_ALL]);
+}
+
static inline void tcg_out_op(TCGContext *s, TCGOpcode opc,
const TCGArg *args, const int *const_args)
{
}
break;
case INDEX_op_goto_tb:
- if (s->tb_jmp_offset) {
+ if (s->tb_jmp_insn_offset) {
/* direct jump method */
- s->tb_jmp_offset[a0] = tcg_current_code_size(s);
+ s->tb_jmp_insn_offset[a0] = tcg_current_code_size(s);
/* Avoid clobbering the address during retranslation. */
tcg_out32(s, OPC_J | (*(uint32_t *)s->code_ptr & 0x3ffffff));
} else {
/* indirect jump method */
tcg_out_ld(s, TCG_TYPE_PTR, TCG_TMP0, TCG_REG_ZERO,
- (uintptr_t)(s->tb_next + a0));
+ (uintptr_t)(s->tb_jmp_target_addr + a0));
tcg_out_opc_reg(s, OPC_JR, 0, TCG_TMP0, 0);
}
tcg_out_nop(s);
- s->tb_next_offset[a0] = tcg_current_code_size(s);
+ s->tb_jmp_reset_offset[a0] = tcg_current_code_size(s);
break;
case INDEX_op_br:
tcg_out_brcond(s, TCG_COND_EQ, TCG_REG_ZERO, TCG_REG_ZERO,
case INDEX_op_and_i32:
if (c2 && a2 != (uint16_t)a2) {
int msb = ctz32(~a2) - 1;
- assert(use_mips32r2_instructions);
- assert(is_p2m1(a2));
+ tcg_debug_assert(use_mips32r2_instructions);
+ tcg_debug_assert(is_p2m1(a2));
tcg_out_opc_bf(s, OPC_EXT, a0, a1, msb, 0);
break;
}
const_args[4], const_args[5], true);
break;
+ case INDEX_op_mb:
+ tcg_out_mb(s, a0);
+ break;
case INDEX_op_mov_i32: /* Always emitted via tcg_out_mov. */
case INDEX_op_movi_i32: /* Always emitted via tcg_out_movi. */
case INDEX_op_call: /* Always emitted via tcg_out_call. */
{ INDEX_op_qemu_ld_i64, { "L", "L", "lZ", "lZ" } },
{ INDEX_op_qemu_st_i64, { "SZ", "SZ", "SZ", "SZ" } },
#endif
+
+ { INDEX_op_mb, { } },
{ -1 },
};
void tb_set_jmp_target1(uintptr_t jmp_addr, uintptr_t addr)
{
- uint32_t *ptr = (uint32_t *)jmp_addr;
- *ptr = deposit32(*ptr, 0, 26, addr >> 2);
+ atomic_set((uint32_t *)jmp_addr, deposit32(OPC_J, 0, 26, addr >> 2));
flush_icache_range(jmp_addr, jmp_addr + 4);
}