[subrepo]
remote = https://github.com/pcercuei/lightrec.git
branch = master
- commit = d88760e40c1d2a5698c7b6f6a53cce31fda799f0
- parent = 963f41620dce6ddb2527b7e3dced09564031f783
+ commit = 8d3db1a4e76c7b81301013f18650011b7e5eabf3
+ parent = fcd42d7decc2ed71801e4cbe575c4d2726b2743e
method = merge
cmdver = 0.4.6
cmake_minimum_required(VERSION 3.5)
-project(lightrec LANGUAGES C VERSION 0.8)
-
-set(BUILD_SHARED_LIBS ON CACHE BOOL "Build shared libraries")
-if (NOT BUILD_SHARED_LIBS)
- add_definitions(-DLIGHTREC_STATIC)
-endif (NOT BUILD_SHARED_LIBS)
-
-if (NOT LOG_LEVEL)
- set(LOG_LEVEL Info CACHE STRING "Log level" FORCE)
- set_property(CACHE LOG_LEVEL PROPERTY STRINGS NoLog Error Warning Info Debug)
-endif()
-
-if (NOT CMAKE_BUILD_TYPE)
- set(CMAKE_BUILD_TYPE RelWithDebInfo CACHE STRING
- "Choose the type of build, options are: None(CMAKE_CXX_FLAGS or CMAKE_C_FLAGS used) Debug Release RelWithDebInfo MinSizeRel."
- FORCE)
- set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS None Debug Release RelWithDebInfo MinSizeRel)
-endif()
-
-string(TOUPPER ${LOG_LEVEL} LIGHTREC_LOG_LEVEL)
-add_definitions(-DLOG_LEVEL=${LIGHTREC_LOG_LEVEL}_L)
-
-if (CMAKE_COMPILER_IS_GNUCC)
- add_compile_options(-fvisibility=hidden)
-endif()
-
-set(HAS_DEFAULT_ELM ${CMAKE_COMPILER_IS_GNUCC})
+project(lightrec LANGUAGES C VERSION 0.9)
list(APPEND LIGHTREC_SOURCES
blockcache.c
regcache.h
)
+add_library(lightrec ${LIGHTREC_SOURCES} ${LIGHTREC_HEADERS})
+set_target_properties(lightrec PROPERTIES
+ VERSION ${PROJECT_VERSION}
+ SOVERSION ${PROJECT_VERSION_MAJOR}
+ PUBLIC_HEADER lightrec.h
+ C_STANDARD 11
+ C_STANDARD_REQUIRED ON
+ C_EXTENSIONS OFF
+)
+
+set(BUILD_SHARED_LIBS ON CACHE BOOL "Build shared libraries")
+if (NOT BUILD_SHARED_LIBS)
+ target_compile_definitions(lightrec PRIVATE LIGHTREC_STATIC)
+endif (NOT BUILD_SHARED_LIBS)
+
+if (NOT LOG_LEVEL)
+ set(LOG_LEVEL Info CACHE STRING "Log level" FORCE)
+ set_property(CACHE LOG_LEVEL PROPERTY STRINGS NoLog Error Warning Info Debug)
+endif()
+
+if (NOT CMAKE_BUILD_TYPE)
+ set(CMAKE_BUILD_TYPE RelWithDebInfo CACHE STRING
+ "Choose the type of build, options are: None(CMAKE_CXX_FLAGS or CMAKE_C_FLAGS used) Debug Release RelWithDebInfo MinSizeRel."
+ FORCE)
+ set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS None Debug Release RelWithDebInfo MinSizeRel)
+endif()
+
+string(TOUPPER ${LOG_LEVEL} LIGHTREC_LOG_LEVEL)
+target_compile_definitions(lightrec PRIVATE LOG_LEVEL=${LIGHTREC_LOG_LEVEL}_L)
+
+if (CMAKE_COMPILER_IS_GNUCC)
+ target_compile_options(lightrec PRIVATE -fvisibility=hidden)
+endif()
+
+set(HAS_DEFAULT_ELM ${CMAKE_COMPILER_IS_GNUCC})
+
option(ENABLE_FIRST_PASS "Run the interpreter as first-pass optimization" ON)
option(ENABLE_THREADED_COMPILER "Enable threaded compiler" ON)
if (ENABLE_THREADED_COMPILER)
- list(APPEND LIGHTREC_SOURCES recompiler.c reaper.c)
+ target_sources(lightrec PRIVATE recompiler.c reaper.c)
if (NOT ENABLE_FIRST_PASS)
message(SEND_ERROR "Threaded compiler requires first-pass optimization")
option(OPT_EARLY_UNLOAD "(optimization) Unload registers early" ON)
option(OPT_PRELOAD_PC "(optimization) Preload PC value into register" ON)
-include_directories(${CMAKE_CURRENT_BINARY_DIR})
-
-add_library(${PROJECT_NAME} ${LIGHTREC_SOURCES} ${LIGHTREC_HEADERS})
-set_target_properties(${PROJECT_NAME} PROPERTIES
- VERSION ${PROJECT_VERSION}
- SOVERSION ${PROJECT_VERSION_MAJOR}
- PUBLIC_HEADER lightrec.h
- C_STANDARD 11
- C_STANDARD_REQUIRED ON
- C_EXTENSIONS OFF
-)
+target_include_directories(lightrec PRIVATE ${CMAKE_CURRENT_BINARY_DIR})
if (CMAKE_C_COMPILER_ID MATCHES "GNU|Clang")
- target_compile_options(${PROJECT_NAME} PRIVATE -Wall)
+ target_compile_options(lightrec PRIVATE -Wall)
endif()
if (CMAKE_C_COMPILER_ID STREQUAL "Clang")
- target_compile_options(${PROJECT_NAME} PRIVATE -Wno-initializer-overrides)
+ target_compile_options(lightrec PRIVATE -Wno-initializer-overrides)
endif()
if (ENABLE_THREADED_COMPILER)
- find_library(PTHREAD_LIBRARIES pthread REQUIRED)
- find_path(PTHREAD_INCLUDE_DIR pthread.h REQUIRED)
+ include(FindThreads)
+
+ if (NOT CMAKE_USE_PTHREADS_INIT)
+ message(SEND_ERROR "Could not find compatible threads library")
+ endif()
- include_directories(${PTHREAD_INCLUDE_DIR})
- target_link_libraries(${PROJECT_NAME} PRIVATE ${PTHREAD_LIBRARIES})
+ target_link_libraries(lightrec PUBLIC Threads::Threads)
endif (ENABLE_THREADED_COMPILER)
option(ENABLE_CODE_BUFFER "Enable external code buffer" ON)
if (ENABLE_CODE_BUFFER)
- target_sources(${PROJECT_NAME} PRIVATE tlsf/tlsf.c)
- target_include_directories(${PROJECT_NAME} PRIVATE tlsf)
+ target_sources(lightrec PRIVATE tlsf/tlsf.c)
+ target_include_directories(lightrec PRIVATE tlsf)
endif (ENABLE_CODE_BUFFER)
find_library(LIBLIGHTNING lightning REQUIRED)
find_path(LIBLIGHTNING_INCLUDE_DIR lightning.h REQUIRED)
-include_directories(${LIBLIGHTNING_INCLUDE_DIR})
-target_link_libraries(${PROJECT_NAME} PRIVATE ${LIBLIGHTNING})
+target_include_directories(lightrec PUBLIC ${LIBLIGHTNING_INCLUDE_DIR})
+target_link_libraries(lightrec PUBLIC ${LIBLIGHTNING})
if (LOG_LEVEL STREQUAL Debug)
set(ENABLE_DISASSEMBLER ON)
- target_sources(${PROJECT_NAME} PRIVATE disassembler.c)
+ target_sources(lightrec PRIVATE disassembler.c)
endif()
configure_file(lightrec-config.h.cmakein lightrec-config.h @ONLY)
include(GNUInstallDirs)
-install(TARGETS ${PROJECT_NAME}
+install(TARGETS lightrec
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
lightrec_free_blocks(cache, except, false);
}
-void lightrec_free_block_cache(struct blockcache *cache)
+void lightrec_free_all_blocks(struct blockcache *cache)
{
lightrec_free_blocks(cache, NULL, true);
+}
+
+void lightrec_free_block_cache(struct blockcache *cache)
+{
+ lightrec_free_all_blocks(cache);
lightrec_free(cache->state, MEM_FOR_LIGHTREC, sizeof(*cache), cache);
}
struct blockcache * lightrec_blockcache_init(struct lightrec_state *state);
void lightrec_free_block_cache(struct blockcache *cache);
+void lightrec_free_all_blocks(struct blockcache *cache);
+
u32 lightrec_calculate_block_hash(const struct block *block);
_Bool lightrec_block_is_outdated(struct lightrec_state *state, struct block *block);
case OP_SPECIAL_SRA:
v[c.r.rd].value = (s32)v[c.r.rt].value >> c.r.imm;
+ v[c.r.rd].sign = (s32)(v[c.r.rt].sign
+ | (~v[c.r.rt].known & 0x80000000)) >> c.r.imm;
v[c.r.rd].known = (s32)v[c.r.rt].known >> c.r.imm;
- v[c.r.rd].sign = (s32)v[c.r.rt].sign >> c.r.imm;
break;
case OP_SPECIAL_SLLV:
if ((v[c.r.rs].known & 0x1f) == 0x1f) {
imm = v[c.r.rs].value & 0x1f;
v[c.r.rd].value = (s32)v[c.r.rt].value >> imm;
+ v[c.r.rd].sign = (s32)(v[c.r.rt].sign
+ | (~v[c.r.rt].known & 0x80000000)) >> imm;
v[c.r.rd].known = (s32)v[c.r.rt].known >> imm;
- v[c.r.rd].sign = (s32)v[c.r.rt].sign >> imm;
} else {
v[c.r.rd].known = 0;
v[c.r.rd].sign = 0;
return 0x1f800000 | GENMASK(31 - clz32(length - 1), 0);
}
+static void rec_add_offset(struct lightrec_cstate *cstate,
+ jit_state_t *_jit, u8 reg_out, u8 reg_in,
+ uintptr_t offset)
+{
+ struct regcache *reg_cache = cstate->reg_cache;
+ u8 reg_imm;
+
+ reg_imm = lightrec_alloc_reg_temp_with_value(reg_cache, _jit, offset);
+ jit_addr(reg_out, reg_in, reg_imm);
+
+ lightrec_free_reg(reg_cache, reg_imm);
+}
+
+static void rec_and_mask(struct lightrec_cstate *cstate,
+ jit_state_t *_jit, u8 reg_out, u8 reg_in, u32 mask)
+{
+ struct regcache *reg_cache = cstate->reg_cache;
+ u8 reg_imm;
+
+ reg_imm = lightrec_alloc_reg_temp_with_value(reg_cache, _jit, mask);
+ jit_andr(reg_out, reg_in, reg_imm);
+
+ lightrec_free_reg(reg_cache, reg_imm);
+}
+
static void rec_store_memory(struct lightrec_cstate *cstate,
const struct block *block,
u16 offset, jit_code_t code,
- jit_code_t swap_code,
- uintptr_t addr_offset, u32 addr_mask,
- bool invalidate)
+ jit_code_t swap_code, uintptr_t addr_offset,
+ u32 addr_mask, bool invalidate)
{
const struct lightrec_state *state = cstate->state;
struct regcache *reg_cache = cstate->reg_cache;
bool need_tmp = !no_mask || add_imm || invalidate;
bool swc2 = c.i.op == OP_SWC2;
u8 in_reg = swc2 ? REG_TEMP : c.i.rt;
- s8 reg_imm;
rs = lightrec_alloc_reg_in(reg_cache, _jit, c.i.rs, 0);
if (need_tmp)
}
if (!no_mask) {
- reg_imm = lightrec_alloc_reg_temp_with_value(reg_cache, _jit,
- addr_mask);
-
- jit_andr(tmp, addr_reg, reg_imm);
+ rec_and_mask(cstate, _jit, tmp, addr_reg, addr_mask);
addr_reg = tmp;
-
- lightrec_free_reg(reg_cache, reg_imm);
}
if (addr_offset) {
- reg_imm = lightrec_alloc_reg_temp_with_value(reg_cache, _jit,
- addr_offset);
tmp2 = lightrec_alloc_reg_temp(reg_cache, _jit);
- jit_addr(tmp2, addr_reg, reg_imm);
+ rec_add_offset(cstate, _jit, tmp2, addr_reg, addr_offset);
addr_reg2 = tmp2;
-
- lightrec_free_reg(reg_cache, reg_imm);
} else {
addr_reg2 = addr_reg;
}
jit_code_t swap_code)
{
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;
jit_state_t *_jit = block->_jit;
jit_node_t *to_not_ram, *to_end;
bool swc2 = c.i.op == OP_SWC2;
- u8 tmp, tmp2 = 0, rs, rt, in_reg = swc2 ? REG_TEMP : c.i.rt;
- u32 addr_mask;
- s32 reg_imm;
+ u8 addr_reg, tmp, tmp2 = 0, rs, rt, in_reg = swc2 ? REG_TEMP : c.i.rt;
s16 imm;
jit_note(__FILE__, __LINE__);
rs = lightrec_alloc_reg_in(reg_cache, _jit, c.i.rs, 0);
tmp = lightrec_alloc_reg_temp(reg_cache, _jit);
- if (state->mirrors_mapped)
- addr_mask = 0x1f800000 | (4 * RAM_SIZE - 1);
- else
- addr_mask = 0x1f800000 | (RAM_SIZE - 1);
-
- reg_imm = lightrec_alloc_reg_temp_with_value(reg_cache, _jit, addr_mask);
-
/* Convert to KUNSEG and avoid RAM mirrors */
if ((c.i.op == OP_META_SWU || !state->mirrors_mapped) && c.i.imm) {
imm = 0;
jit_addi(tmp, rs, (s16)c.i.imm);
- jit_andr(tmp, tmp, reg_imm);
+ addr_reg = tmp;
} else {
imm = (s16)c.i.imm;
- jit_andr(tmp, rs, reg_imm);
+ addr_reg = rs;
}
+ rec_and_mask(cstate, _jit, tmp, addr_reg, 0x1f800000 | (ram_size - 1));
+
lightrec_free_reg(reg_cache, rs);
- lightrec_free_reg(reg_cache, reg_imm);
if (state->offset_ram != state->offset_scratch) {
tmp2 = lightrec_alloc_reg_temp(reg_cache, _jit);
jit_state_t *_jit = block->_jit;
jit_node_t *to_not_ram, *to_end;
bool swc2 = c.i.op == OP_SWC2;
- u8 tmp, tmp2, tmp3, masked_reg, rs, rt;
+ u8 addr_reg, tmp, tmp2, tmp3, rs, rt, reg_imm;
u8 in_reg = swc2 ? REG_TEMP : c.i.rt;
- u32 addr_mask = 0x1f800000 | (ram_size - 1);
+ u32 mask;
bool different_offsets = state->offset_ram != state->offset_scratch;
- s32 reg_imm;
jit_note(__FILE__, __LINE__);
tmp2 = lightrec_alloc_reg_temp(reg_cache, _jit);
tmp3 = lightrec_alloc_reg_in(reg_cache, _jit, 0, 0);
- reg_imm = lightrec_alloc_reg_temp_with_value(reg_cache, _jit, addr_mask);
-
/* Convert to KUNSEG and avoid RAM mirrors */
if (c.i.imm) {
jit_addi(tmp2, rs, (s16)c.i.imm);
- jit_andr(tmp2, tmp2, reg_imm);
+ addr_reg = tmp2;
} else {
- jit_andr(tmp2, rs, reg_imm);
+ addr_reg = rs;
}
+ rec_and_mask(cstate, _jit, tmp2, addr_reg, 0x1f800000 | (ram_size - 1));
+
lightrec_free_reg(reg_cache, rs);
- lightrec_free_reg(reg_cache, reg_imm);
tmp = lightrec_alloc_reg_temp(reg_cache, _jit);
+ mask = c.i.op == OP_SW ? RAM_SIZE - 1 : (RAM_SIZE - 1) & ~3;
+ reg_imm = lightrec_alloc_reg_temp_with_value(reg_cache, _jit, mask);
+
if (different_offsets) {
to_not_ram = jit_bgti(tmp2, ram_size);
- masked_reg = tmp2;
+ addr_reg = tmp2;
} else {
jit_lti_u(tmp, tmp2, ram_size);
jit_movnr(tmp, tmp2, tmp);
- masked_reg = tmp;
+ addr_reg = tmp;
}
/* Compute the offset to the code LUT */
- if (c.i.op == OP_SW)
- jit_andi(tmp, masked_reg, RAM_SIZE - 1);
- else
- jit_andi(tmp, masked_reg, (RAM_SIZE - 1) & ~3);
+ jit_andr(tmp, addr_reg, reg_imm);
if (!lut_is_32bit(state))
jit_lshi(tmp, tmp, 1);
lightrec_free_reg(reg_cache, tmp);
lightrec_free_reg(reg_cache, tmp3);
+ lightrec_free_reg(reg_cache, reg_imm);
rt = lightrec_alloc_reg_in(reg_cache, _jit, in_reg, 0);
jit_code_t code, jit_code_t swap_code, bool is_unsigned,
uintptr_t addr_offset, u32 addr_mask)
{
+ 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;
u8 rs, rt, out_reg, addr_reg, flags = REG_EXT;
bool no_mask = op_flag_no_mask(op->flags);
union code c = op->c;
- s8 reg_imm;
s16 imm;
if (load_delay || c.i.op == OP_LWC2)
rt = lightrec_alloc_reg_out(reg_cache, _jit, out_reg, flags);
if ((op->i.op == OP_META_LWU && c.i.imm)
- || (!cstate->state->mirrors_mapped && c.i.imm && !no_mask)) {
+ || (!state->mirrors_mapped && c.i.imm && !no_mask)) {
jit_addi(rt, rs, (s16)c.i.imm);
addr_reg = rt;
imm = 0;
imm = LIGHTNING_UNALIGNED_32BIT;
if (!no_mask) {
- reg_imm = lightrec_alloc_reg_temp_with_value(reg_cache, _jit,
- addr_mask);
-
- jit_andr(rt, addr_reg, reg_imm);
+ rec_and_mask(cstate, _jit, rt, addr_reg, addr_mask);
addr_reg = rt;
-
- lightrec_free_reg(reg_cache, reg_imm);
}
if (addr_offset) {
- reg_imm = lightrec_alloc_reg_temp_with_value(reg_cache, _jit,
- addr_offset);
-
- jit_addr(rt, addr_reg, reg_imm);
+ rec_add_offset(cstate, _jit, rt, addr_reg, addr_offset);
addr_reg = rt;
-
- lightrec_free_reg(reg_cache, reg_imm);
}
jit_new_node_www(code, rt, addr_reg, imm);
#define jit_b() jit_beqr(0, 0)
-#if defined(__sh__)
-#define jit_add_state(u,v) \
- do { \
- jit_new_node_ww(jit_code_movr,_R0,LIGHTREC_REG_STATE); \
- jit_new_node_www(jit_code_addr,u,v,_R0); \
- } while (0)
-#else
#define jit_add_state(u,v) jit_addr(u,v,LIGHTREC_REG_STATE)
-#endif
#endif /* __LIGHTNING_WRAPPER_H__ */
if (has_code_buffer) {
jit_get_code(&code_size);
+
+#ifdef __i386__
+ /* Lightning's code size estimation routine is buggy on x86 and
+ * will return a value that's too small. */
+ code_size *= 2;
+#endif
+
code = lightrec_alloc_code(state, (size_t) code_size);
if (!code) {
}
code = jit_emit();
+ if (!code) {
+ if (has_code_buffer)
+ lightrec_free_code(state, code);
+
+ return NULL;
+ }
jit_get_code(&new_code_size);
lightrec_register(MEM_FOR_CODE, new_code_size);
jit_node_t *to_end[C_WRAPPERS_COUNT - 1];
u8 tmp = JIT_R1;
-#ifdef __sh__
- /* On SH, GBR-relative loads target the r0 register.
- * Use it as the temporary register to factorize the move to
- * JIT_R1. */
- if (LIGHTREC_REG_STATE == _GBR)
- tmp = _R0;
-#endif
-
block = lightrec_malloc(state, MEM_FOR_IR, sizeof(*block));
if (!block)
goto err_no_mem;
block->function = lightrec_emit_code(state, block, _jit,
&block->code_size);
if (!block->function)
- goto err_free_block;
+ goto err_free_jit;
state->wrappers_eps[C_WRAPPERS_COUNT - 1] = block->function;
jit_clear_state();
return block;
+err_free_jit:
+ jit_destroy_state();
err_free_block:
lightrec_free(state, MEM_FOR_IR, sizeof(*block), block);
err_no_mem:
to_end = jit_blei(LIGHTREC_REG_CYCLE, 0);
/* Convert next PC to KUNSEG and avoid mirrors */
- jit_andi(JIT_V1, JIT_V0, 0x10000000 | (RAM_SIZE - 1));
- jit_rshi_u(JIT_R1, JIT_V1, 28);
+ jit_andi(JIT_V1, JIT_V0, RAM_SIZE - 1);
jit_andi(JIT_R2, JIT_V0, BIOS_SIZE - 1);
+ jit_andi(JIT_R1, JIT_V0, BIT(28));
jit_addi(JIT_R2, JIT_R2, RAM_SIZE);
jit_movnr(JIT_V1, JIT_R2, JIT_R1);
block->function = lightrec_emit_code(state, block, _jit,
&block->code_size);
if (!block->function)
- goto err_free_block;
+ goto err_free_jit;
state->eob_wrapper_func = jit_address(addr2);
if (OPT_DETECT_IMPOSSIBLE_BRANCHES)
jit_clear_state();
return block;
+err_free_jit:
+ jit_destroy_state();
err_free_block:
lightrec_free(state, MEM_FOR_IR, sizeof(*block), block);
err_no_mem:
}
struct lightrec_state * lightrec_init(char *argv0,
- const struct lightrec_mem_map *map,
+ const struct lightrec_mem_map *maps,
size_t nb,
const struct lightrec_ops *ops)
{
- const struct lightrec_mem_map *codebuf_map = &map[PSX_MAP_CODE_BUFFER];
+ const struct lightrec_mem_map *codebuf_map = &maps[PSX_MAP_CODE_BUFFER];
+ const struct lightrec_mem_map *map;
struct lightrec_state *state;
uintptr_t addr;
void *tlsf = NULL;
}
state->nb_maps = nb;
- state->maps = map;
+ state->maps = maps;
memcpy(&state->ops, ops, sizeof(*ops));
state->c_wrappers[C_WRAPPER_MTC] = lightrec_mtc_cb;
state->c_wrappers[C_WRAPPER_CP] = lightrec_cp_cb;
- map = &state->maps[PSX_MAP_BIOS];
+ map = &maps[PSX_MAP_BIOS];
state->offset_bios = (uintptr_t)map->address - map->pc;
- map = &state->maps[PSX_MAP_SCRATCH_PAD];
+ map = &maps[PSX_MAP_SCRATCH_PAD];
state->offset_scratch = (uintptr_t)map->address - map->pc;
- map = &state->maps[PSX_MAP_HW_REGISTERS];
+ map = &maps[PSX_MAP_HW_REGISTERS];
state->offset_io = (uintptr_t)map->address - map->pc;
- map = &state->maps[PSX_MAP_KERNEL_USER_RAM];
+ map = &maps[PSX_MAP_KERNEL_USER_RAM];
state->offset_ram = (uintptr_t)map->address - map->pc;
- if (state->maps[PSX_MAP_MIRROR1].address == map->address + 0x200000 &&
- state->maps[PSX_MAP_MIRROR2].address == map->address + 0x400000 &&
- state->maps[PSX_MAP_MIRROR3].address == map->address + 0x600000)
+ if (maps[PSX_MAP_MIRROR1].address == map->address + 0x200000 &&
+ maps[PSX_MAP_MIRROR2].address == map->address + 0x400000 &&
+ maps[PSX_MAP_MIRROR3].address == map->address + 0x600000)
state->mirrors_mapped = true;
if (state->offset_bios == 0 &&
void lightrec_set_cycles_per_opcode(struct lightrec_state *state, u32 cycles)
{
+ if (state->cycles_per_op == cycles)
+ return;
+
state->cycles_per_op = cycles;
+
+ if (ENABLE_THREADED_COMPILER) {
+ lightrec_recompiler_pause(state->rec);
+ lightrec_reaper_reap(state->reaper);
+ }
+
+ lightrec_invalidate_all(state);
+ lightrec_free_all_blocks(state->block_cache);
+
+ if (ENABLE_THREADED_COMPILER)
+ lightrec_recompiler_unpause(state->rec);
}
return;
}
- if (op->i.imm != 0 || op->i.rt == 0 || offset == block->nb_ops - 1)
+ if (op->i.imm != 0 || op->i.rt == 0 || is_delay_slot(list, offset))
return;
reader = find_next_reader(list, offset + 1, op->i.rt);
break;
case OP_LUI:
- if (i == 0 || !has_delay_slot(list[i - 1].c))
+ if (!is_delay_slot(list, i))
lightrec_modify_lui(block, i);
lightrec_remove_useless_lui(block, i, v);
- if (i == 0 || !has_delay_slot(list[i - 1].c))
+ if (!is_delay_slot(list, i))
lightrec_lui_to_movi(block, i);
break;
list->flags &= ~(LIGHTREC_NO_LO | LIGHTREC_NO_HI);
}
- if (reg_lo > 0 && reg_lo != REG_LO) {
+ if (0/* Broken */ && reg_lo > 0 && reg_lo != REG_LO) {
pr_debug("Found register %s to hold LO (rs = %u, rt = %u)\n",
lightrec_reg_name(reg_lo), list->r.rs, list->r.rt);
list->r.rd = 0;
}
- if (reg_hi > 0 && reg_hi != REG_HI) {
+ if (0/* Broken */ && reg_hi > 0 && reg_hi != REG_HI) {
pr_debug("Found register %s to hold HI (rs = %u, rt = %u)\n",
lightrec_reg_name(reg_hi), list->r.rs, list->r.rt);
pthread_cond_t cond;
pthread_cond_t cond2;
pthread_mutex_t mutex;
- bool stop, must_flush;
+ bool stop, pause, must_flush;
struct slist_elm slist;
pthread_mutex_t alloc_mutex;
static unsigned int get_processors_count(void)
{
- unsigned int nb = 1;
+ int nb = 1;
#if defined(PTW32_VERSION)
nb = pthread_num_processors_np();
nb = sysctlbyname("hw.ncpu", &count, &size, NULL, 0) ? 1 : count;
#elif defined(_SC_NPROCESSORS_ONLN)
- nb = sysconf(_SC_NPROCESSORS_ONLN);
+ nb = (int)sysconf(_SC_NPROCESSORS_ONLN);
#endif
return nb < 1 ? 1 : nb;
struct block *block;
int ret;
- while (!!(block_rec = lightrec_get_best_elm(&rec->slist))) {
+ while (!rec->pause &&
+ !!(block_rec = lightrec_get_best_elm(&rec->slist))) {
block_rec->compiling = true;
block = block_rec->block;
if (rec->stop)
goto out_unlock;
- } while (slist_empty(&rec->slist));
+ } while (rec->pause || slist_empty(&rec->slist));
lightrec_compile_list(rec, thd);
}
rec->state = state;
rec->stop = false;
+ rec->pause = false;
rec->must_flush = false;
rec->nb_recs = nb_recs;
slist_init(&rec->slist);
{
pthread_mutex_unlock(&state->rec->alloc_mutex);
}
+
+void lightrec_recompiler_pause(struct recompiler *rec)
+{
+ rec->pause = true;
+
+ pthread_mutex_lock(&rec->mutex);
+ pthread_cond_broadcast(&rec->cond);
+ lightrec_cancel_list(rec);
+ pthread_mutex_unlock(&rec->mutex);
+}
+
+void lightrec_recompiler_unpause(struct recompiler *rec)
+{
+ rec->pause = false;
+}
void * lightrec_recompiler_run_first_pass(struct lightrec_state *state,
struct block *block, u32 *pc);
+void lightrec_recompiler_pause(struct recompiler *rec);
+void lightrec_recompiler_unpause(struct recompiler *rec);
+
void lightrec_code_alloc_lock(struct lightrec_state *state);
void lightrec_code_alloc_unlock(struct lightrec_state *state);
#include "lightning-wrapper.h"
-#if defined(__sh__)
-# define NUM_REGS JIT_V_NUM
-# define LIGHTREC_REG_STATE _GBR
-#else
-# define NUM_REGS (JIT_V_NUM - 1)
-# define LIGHTREC_REG_STATE (JIT_V(JIT_V_NUM - 1))
-#endif
+#define NUM_REGS (JIT_V_NUM - 1)
+#define LIGHTREC_REG_STATE (JIT_V(JIT_V_NUM - 1))
#if defined(__powerpc__)
# define NUM_TEMPS JIT_R_NUM