[subrepo]
remote = https://github.com/pcercuei/lightrec.git
branch = master
- commit = 3eee0e1e7e5ada68f2da11b7951def4366caae38
- parent = c9f33835ba76a0578cfd388353e04c6391869e0a
+ commit = b53e0e808d1425d93d3430f526b9f739b1a9c42e
+ parent = fb865ffe3d7e066905271b7b9e678d63dc7b780e
method = merge
cmdver = 0.4.6
}
}
- pr_err("Block at PC 0x%x is not in cache\n", block->pc);
+ pr_err("Block at "PC_FMT" is not in cache\n", block->pc);
}
static bool lightrec_block_is_old(const struct lightrec_state *state,
if (ENABLE_THREADED_COMPILER)
lightrec_recompiler_remove(state->rec, block);
- pr_debug("Freeing outdated block at PC 0x%08x\n", block->pc);
+ pr_debug("Freeing outdated block at "PC_FMT"\n", block->pc);
remove_from_code_lut(cache, block);
lightrec_unregister_block(cache, block);
lightrec_free_block(state, block);
}
}
-static u32 rec_ram_mask(struct lightrec_state *state)
+static u32 rec_ram_mask(const struct lightrec_state *state)
{
return (RAM_SIZE << (state->mirrors_mapped * 2)) - 1;
}
struct opcode *op = &block->opcode_list[offset];
jit_state_t *_jit = block->_jit;
union code c = op->c;
- u8 rs, rt, tmp, tmp2, tmp3, addr_reg, addr_reg2;
+ u8 rs, rt, tmp = 0, tmp2 = 0, tmp3, addr_reg, addr_reg2;
s16 imm = (s16)c.i.imm;
s32 simm = (s32)imm << (1 - lut_is_32bit(state));
s32 lut_offt = offsetof(struct lightrec_state, code_lut);
u16 offset, jit_code_t code,
jit_code_t swap_code, bool invalidate)
{
- struct lightrec_state *state = cstate->state;
+ const struct lightrec_state *state = cstate->state;
_jit_note(block->_jit, __FILE__, __LINE__);
u16 offset, jit_code_t code,
jit_code_t swap_code)
{
- struct lightrec_state *state = cstate->state;
+ const struct lightrec_state *state = cstate->state;
struct regcache *reg_cache = cstate->reg_cache;
union code c = block->opcode_list[offset].c;
jit_state_t *_jit = block->_jit;
static void rec_store_direct(struct lightrec_cstate *cstate, const struct block *block,
u16 offset, jit_code_t code, jit_code_t swap_code)
{
- struct lightrec_state *state = cstate->state;
+ const struct lightrec_state *state = cstate->state;
u32 ram_size = state->mirrors_mapped ? RAM_SIZE * 4 : RAM_SIZE;
struct regcache *reg_cache = cstate->reg_cache;
union code c = block->opcode_list[offset].c;
u8 tmp, tmp2, tmp3, masked_reg, rs, rt;
u8 in_reg = swc2 ? REG_TEMP : c.i.rt;
u32 addr_mask = 0x1f800000 | (ram_size - 1);
+ bool different_offsets = state->offset_ram != state->offset_scratch;
s32 reg_imm;
jit_note(__FILE__, __LINE__);
lightrec_free_reg(reg_cache, reg_imm);
tmp = lightrec_alloc_reg_temp(reg_cache, _jit);
- if (state->offset_ram != state->offset_scratch) {
+ if (different_offsets) {
to_not_ram = jit_bgti(tmp2, ram_size);
masked_reg = tmp2;
} else {
else
jit_stxi(offsetof(struct lightrec_state, code_lut), tmp, tmp3);
- if (state->offset_ram != state->offset_scratch) {
+ if (different_offsets) {
jit_movi(tmp, state->offset_ram);
to_end = jit_b();
if (state->offset_ram || state->offset_scratch)
jit_movi(tmp, state->offset_scratch);
- if (state->offset_ram != state->offset_scratch)
+ if (different_offsets)
jit_patch(to_end);
if (state->offset_ram || state->offset_scratch)
jit_code_t code, jit_code_t swap_code,
bool is_unsigned)
{
- struct lightrec_state *state = cstate->state;
+ const struct lightrec_state *state = cstate->state;
struct regcache *reg_cache = cstate->reg_cache;
struct opcode *op = &block->opcode_list[offset];
bool load_delay = op_flag_load_delay(op->flags) && !cstate->no_load_delay;
jit_state_t *_jit = block->_jit;
jit_node_t *to_not_ram, *to_not_bios, *to_end, *to_end2;
u8 tmp, rs, rt, out_reg, addr_reg, flags = REG_EXT;
+ bool different_offsets = state->offset_bios != state->offset_scratch;
union code c = op->c;
s32 addr_mask;
u32 reg_imm;
jit_patch(to_not_ram);
- if (state->offset_bios != state->offset_scratch)
+ if (different_offsets)
to_not_bios = jit_bmci(addr_reg, BIT(22));
/* Convert to KUNSEG */
jit_movi(tmp, state->offset_bios);
- if (state->offset_bios != state->offset_scratch) {
+ if (different_offsets) {
to_end2 = jit_b();
jit_patch(to_not_bios);
hi = lightrec_alloc_reg_out(reg_cache, _jit,
reg_hi, hiflags);
- if (c.r.op >= 32)
+ if (c.r.op >= 32) {
jit_lshi(hi, rs, c.r.op - 32);
- else if (is_signed)
- jit_rshi(hi, rs, 32 - c.r.op);
- else
- jit_rshi_u(hi, rs, 32 - c.r.op);
+ } else if (is_signed) {
+ if (c.r.op)
+ jit_rshi(hi, rs, 32 - c.r.op);
+ else
+ jit_rshi(hi, rs, 31);
+ } else {
+ if (c.r.op)
+ jit_rshi_u(hi, rs, 32 - c.r.op);
+ else
+ jit_movi(hi, 0);
+ }
lightrec_free_reg(reg_cache, hi);
}
bool run_first_op = false, dummy_ld = false, save_rs = false,
load_in_ds, branch_in_ds = false, branch_at_addr = false,
branch_taken;
- u32 old_rs, new_rt, new_rs = 0;
+ u32 new_rt, old_rs = 0, new_rs = 0;
u32 next_pc, ds_next_pc;
u32 cause, epc;
}
if (!op_flag_no_hi(inter->op->flags)) {
- if (c.r.op >= 32)
+ if (c.r.op >= 32) {
reg_cache[reg_hi] = rs << (c.r.op - 32);
- else if (c.i.op == OP_META_MULT2)
- reg_cache[reg_hi] = (s32) rs >> (32 - c.r.op);
- else
- reg_cache[reg_hi] = rs >> (32 - c.r.op);
+ }
+ else if (c.i.op == OP_META_MULT2) {
+ if (c.r.op)
+ reg_cache[reg_hi] = (s32) rs >> (32 - c.r.op);
+ else
+ reg_cache[reg_hi] = (s32) rs >> 31;
+ } else {
+ if (c.r.op)
+ reg_cache[reg_hi] = rs >> (32 - c.r.op);
+ else
+ reg_cache[reg_hi] = 0;
+ }
}
return jump_next(inter);
if (offset < block->nb_ops)
return lightrec_emulate_block_list(state, block, offset);
- pr_err("PC 0x%x is outside block at PC 0x%x\n", pc, block->pc);
+ pr_err(PC_FMT" is outside block at "PC_FMT"\n", pc, block->pc);
lightrec_set_exit_flags(state, LIGHTREC_EXIT_SEGFAULT);
#include <immintrin.h>
#endif
+#include <inttypes.h>
+#include <stdint.h>
+
+#define PC_FMT "PC 0x%08"PRIx32
+
#define ARRAY_SIZE(x) (sizeof(x) ? sizeof(x) / sizeof((x)[0]) : 0)
#define GENMASK(h, l) \
{
lightrec_set_exit_flags(state, LIGHTREC_EXIT_SEGFAULT);
pr_err("Segmentation fault in recompiled code: invalid "
- "load/store at address 0x%08x\n", addr);
+ "load/store at address "PC_FMT"\n", addr);
if (block)
- pr_err("Was executing block PC 0x%08x\n", block->pc);
+ pr_err("Was executing block "PC_FMT"\n", block->pc);
}
static void lightrec_swl(struct lightrec_state *state,
old_flags = block_set_flags(block, BLOCK_SHOULD_RECOMPILE);
if (!(old_flags & BLOCK_SHOULD_RECOMPILE)) {
- pr_debug("Opcode of block at PC 0x%08x has been tagged"
+ pr_debug("Opcode of block at "PC_FMT" has been tagged"
" - flag for recompilation\n", block->pc);
lut_write(state, lut_offset(block->pc), NULL);
block = lightrec_find_block_from_lut(state->block_cache,
arg >> 16, state->curr_pc);
if (unlikely(!block)) {
- pr_err("rw_generic: No block found in LUT for PC 0x%x offset 0x%x\n",
+ pr_err("rw_generic: No block found in LUT for "PC_FMT" offset 0x%"PRIx16"\n",
state->curr_pc, offset);
lightrec_set_exit_flags(state, LIGHTREC_EXIT_SEGFAULT);
return;
u8 old_flags;
if (block && lightrec_block_is_outdated(state, block)) {
- pr_debug("Block at PC 0x%08x is outdated!\n", block->pc);
+ pr_debug("Block at "PC_FMT" is outdated!\n", block->pc);
old_flags = block_set_flags(block, BLOCK_IS_DEAD);
if (!(old_flags & BLOCK_IS_DEAD)) {
if (!block) {
block = lightrec_precompile_block(state, pc);
if (!block) {
- pr_err("Unable to recompile block at PC 0x%x\n", pc);
+ pr_err("Unable to recompile block at "PC_FMT"\n", pc);
lightrec_set_exit_flags(state, LIGHTREC_EXIT_SEGFAULT);
return NULL;
}
!block_has_flag(block, BLOCK_IS_DEAD);
if (unlikely(should_recompile)) {
- pr_debug("Block at PC 0x%08x should recompile\n", pc);
+ pr_debug("Block at "PC_FMT" should recompile\n", pc);
if (ENABLE_THREADED_COMPILER) {
lightrec_recompiler_add(state->rec, block);
u32 length = state->regs.gpr[5] * 4;
if (!map) {
- pr_err("Unable to find memory map for memset target address "
- "0x%x\n", kunseg_pc);
+ pr_err("Unable to find memory map for memset target address "PC_FMT"\n",
+ kunseg_pc);
return 0;
}
- pr_debug("Calling host memset, PC 0x%x (host address 0x%" PRIxPTR ") for %u bytes\n",
+ pr_debug("Calling host memset, "PC_FMT" (host address 0x%"PRIxPTR") for %u bytes\n",
kunseg_pc, (uintptr_t)host, length);
memset(host, 0, length);
} else {
block = lightrec_get_block(state, pc);
if (unlikely(!block)) {
- pr_err("Unable to get block at PC 0x%08x\n", pc);
+ pr_err("Unable to get block at "PC_FMT"\n", pc);
lightrec_set_exit_flags(state, LIGHTREC_EXIT_SEGFAULT);
pc = 0;
} else {
{
struct block *block = data;
- pr_debug("Reap dead block at PC 0x%08x\n", block->pc);
+ pr_debug("Reap dead block at "PC_FMT"\n", block->pc);
lightrec_unregister_block(state->block_cache, block);
lightrec_free_block(state, block);
}
old_flags = block_set_flags(block, BLOCK_NO_OPCODE_LIST);
if (fully_tagged && !(old_flags & BLOCK_NO_OPCODE_LIST)) {
- pr_debug("Block PC 0x%08x is fully tagged"
+ pr_debug("Block "PC_FMT" is fully tagged"
" - free opcode list\n", block->pc);
if (ENABLE_THREADED_COMPILER) {
}
}
+static void maybe_remove_load_delay(struct opcode *op)
+{
+ if (op_flag_load_delay(op->flags) && opcode_is_load(op->c))
+ op->flags &= ~LIGHTREC_LOAD_DELAY;
+}
+
static int lightrec_transform_ops(struct lightrec_state *state, struct block *block)
{
struct opcode *op, *list = block->opcode_list;
(v[op->i.rs].value ^ v[op->i.rt].value)) {
pr_debug("Found never-taken BEQ\n");
+ if (!op_flag_no_ds(op->flags))
+ maybe_remove_load_delay(&list[i + 1]);
+
local = op_flag_local_branch(op->flags);
op->opcode = 0;
op->flags = 0;
v[op->i.rs].value == v[op->i.rt].value) {
pr_debug("Found never-taken BNE\n");
+ if (!op_flag_no_ds(op->flags))
+ maybe_remove_load_delay(&list[i + 1]);
+
local = op_flag_local_branch(op->flags);
op->opcode = 0;
op->flags = 0;
v[op->i.rs].value & BIT(31)) {
pr_debug("Found never-taken BGTZ\n");
+ if (!op_flag_no_ds(op->flags))
+ maybe_remove_load_delay(&list[i + 1]);
+
local = op_flag_local_branch(op->flags);
op->opcode = 0;
op->flags = 0;
} else {
pr_debug("Found never-taken BLTZ/BGEZ\n");
+ if (!op_flag_no_ds(op->flags))
+ maybe_remove_load_delay(&list[i + 1]);
+
local = op_flag_local_branch(op->flags);
op->opcode = 0;
op->flags = 0;
}
if (ret) {
- pr_err("Unable to compile block at PC 0x%x: %d\n",
+ pr_err("Unable to compile block at "PC_FMT": %d\n",
block->pc, ret);
}
}
goto out_unlock;
}
- pr_debug("Adding block PC 0x%x to recompiler\n", block->pc);
+ pr_debug("Adding block "PC_FMT" to recompiler\n", block->pc);
block_rec->block = block;
block_rec->compiling = false;
old_flags = block_set_flags(block, BLOCK_NO_OPCODE_LIST);
if (!(old_flags & BLOCK_NO_OPCODE_LIST)) {
- pr_debug("Block PC 0x%08x is fully tagged"
+ pr_debug("Block "PC_FMT" is fully tagged"
" - free opcode list\n", block->pc);
/* The block was already compiled but the opcode list
old_flags = block_set_flags(block, BLOCK_NO_OPCODE_LIST);
if (!(old_flags & BLOCK_NO_OPCODE_LIST)) {
- pr_debug("Block PC 0x%08x is fully tagged"
+ pr_debug("Block "PC_FMT" is fully tagged"
" - free opcode list\n", block->pc);
lightrec_free_opcode_list(state, block->opcode_list);