git subrepo pull (merge) deps/lightrec

subrepo:
  subdir:   "deps/lightrec"
  merged:   "b9cf86d3"
upstream:
  origin:   "https://github.com/pcercuei/lightrec.git"
  branch:   "master"
  commit:   "9a14de7d"
git-subrepo:
  version:  "0.4.1"
  origin:   "https://github.com/ingydotnet/git-subrepo"
  commit:   "a04d8c2"
This commit is contained in:
Zachary Cook 2020-01-27 11:40:07 -05:00
parent c42a85b2a8
commit 3f7fe0deeb
7 changed files with 69 additions and 29 deletions

View File

@ -6,7 +6,7 @@
[subrepo]
remote = https://github.com/pcercuei/lightrec.git
branch = master
commit = 96b4f0314f1906d78069ec45a18d7cc660e73aeb
commit = 9a14de7dca83b4e52de043b45e7288c87e74a8f2
parent = 9f797430963d9cf0fcef7d963466f9cac7026de2
method = merge
cmdver = 0.4.1

View File

@ -1,5 +1,5 @@
cmake_minimum_required(VERSION 3.0)
project(lightrec LANGUAGES C VERSION 0.2)
project(lightrec LANGUAGES C VERSION 0.3)
set(BUILD_SHARED_LIBS ON CACHE BOOL "Build shared libraries")
if (NOT BUILD_SHARED_LIBS)

View File

@ -21,12 +21,10 @@
#include <stdlib.h>
/* Must be power of two */
#define TINY_LUT_SIZE 0x100
#define LUT_SIZE 0x4000
struct blockcache {
struct lightrec_state *state;
struct block * tiny_lut[TINY_LUT_SIZE];
struct block * lut[LUT_SIZE];
};
@ -36,39 +34,36 @@ struct block * lightrec_find_block(struct blockcache *cache, u32 pc)
pc = kunseg(pc);
block = cache->tiny_lut[(pc >> 2) & (TINY_LUT_SIZE - 1)];
if (likely(block && kunseg(block->pc) == pc))
return block;
block = cache->lut[(pc >> 2) & (LUT_SIZE - 1)];
for (block = cache->lut[(pc >> 2) & (LUT_SIZE - 1)];
block; block = block->next) {
if (kunseg(block->pc) == pc) {
cache->tiny_lut[(pc >> 2) & (TINY_LUT_SIZE - 1)] = block;
block; block = block->next)
if (kunseg(block->pc) == pc)
return block;
}
}
return NULL;
}
static void remove_from_code_lut(struct blockcache *cache, struct block *block)
void remove_from_code_lut(struct blockcache *cache, struct block *block)
{
struct lightrec_state *state = block->state;
const struct opcode *op;
u32 offset = lut_offset(block->pc);
/* Use state->get_next_block in the code LUT, which basically
* calls back get_next_block_func(), until the compiler
* overrides this. This is required, as a NULL value in the code
* LUT means an outdated block. */
state->code_lut[lut_offset(block->pc)] = state->get_next_block;
state->code_lut[offset] = state->get_next_block;
for (op = block->opcode_list; op; op = op->next)
if (op->c.i.op == OP_META_SYNC)
state->code_lut[offset + op->offset] = NULL;
}
void lightrec_mark_for_recompilation(struct blockcache *cache,
struct block *block)
{
block->flags |= BLOCK_SHOULD_RECOMPILE;
remove_from_code_lut(cache, block);
}
void lightrec_register_block(struct blockcache *cache, struct block *block)
@ -81,7 +76,6 @@ void lightrec_register_block(struct blockcache *cache, struct block *block)
block->next = old;
cache->lut[(pc >> 2) & (LUT_SIZE - 1)] = block;
cache->tiny_lut[(pc >> 2) & (TINY_LUT_SIZE - 1)] = block;
remove_from_code_lut(cache, block);
}
@ -91,9 +85,7 @@ void lightrec_unregister_block(struct blockcache *cache, struct block *block)
u32 pc = kunseg(block->pc);
struct block *old = cache->lut[(pc >> 2) & (LUT_SIZE - 1)];
block->state->code_lut[lut_offset(pc)] = NULL;
cache->tiny_lut[(pc >> 2) & (TINY_LUT_SIZE - 1)] = NULL;
remove_from_code_lut(cache, block);
if (old == block) {
cache->lut[(pc >> 2) & (LUT_SIZE - 1)] = old->next;
@ -138,7 +130,51 @@ struct blockcache * lightrec_blockcache_init(struct lightrec_state *state)
return cache;
}
u32 lightrec_calculate_block_hash(const struct block *block)
{
const struct lightrec_mem_map *map = block->map;
u32 pc, hash = 0xffffffff;
const u32 *code;
unsigned int i;
pc = kunseg(block->pc) - map->pc;
while (map->mirror_of)
map = map->mirror_of;
code = map->address + pc;
/* Jenkins one-at-a-time hash algorithm */
for (i = 0; i < block->nb_ops; i++) {
hash += *code++;
hash += (hash << 10);
hash ^= (hash >> 6);
}
hash += (hash << 3);
hash ^= (hash >> 11);
hash += (hash << 15);
return hash;
}
bool lightrec_block_is_outdated(struct block *block)
{
return !block->state->code_lut[lut_offset(block->pc)];
void **lut_entry = &block->state->code_lut[lut_offset(block->pc)];
bool outdated;
if (*lut_entry)
return false;
outdated = block->hash != lightrec_calculate_block_hash(block);
if (likely(!outdated)) {
/* The block was marked as outdated, but the content is still
* the same */
if (block->function)
*lut_entry = block->function;
else
*lut_entry = block->state->get_next_block;
}
return outdated;
}

View File

@ -26,7 +26,7 @@ void lightrec_unregister_block(struct blockcache *cache, struct block *block);
struct blockcache * lightrec_blockcache_init(struct lightrec_state *state);
void lightrec_free_block_cache(struct blockcache *cache);
u32 calculate_block_hash(const struct block *block);
u32 lightrec_calculate_block_hash(const struct block *block);
_Bool lightrec_block_is_outdated(struct block *block);
void lightrec_mark_for_recompilation(struct blockcache *cache,

View File

@ -86,7 +86,8 @@ static void lightrec_emit_end_of_block(const struct block *block,
pr_debug("EOB: %u cycles\n", cycles);
}
state->branches[state->nb_branches++] = jit_jmpi();
if (op->next && ((op->flags & LIGHTREC_NO_DS) || op->next->next))
state->branches[state->nb_branches++] = jit_jmpi();
}
void lightrec_emit_eob(const struct block *block,
@ -1365,15 +1366,12 @@ static void rec_meta_unload(const struct block *block,
struct lightrec_state *state = block->state;
struct regcache *reg_cache = state->reg_cache;
jit_state_t *_jit = block->_jit;
u8 reg;
jit_name(__func__);
jit_note(__FILE__, __LINE__);
reg = lightrec_alloc_reg_in(reg_cache, _jit, op->i.rs);
pr_debug("Unloading reg %s\n", lightrec_reg_name(op->i.rs));
lightrec_unload_reg(reg_cache, _jit, reg);
lightrec_clean_reg_if_loaded(reg_cache, _jit, op->i.rs, true);
}
static void rec_meta_BEQZ(const struct block *block,

View File

@ -73,6 +73,7 @@ struct block {
struct opcode *opcode_list;
void (*function)(void);
u32 pc;
u32 hash;
#if ENABLE_THREADED_COMPILER
atomic_flag op_list_freed;
#endif
@ -131,6 +132,8 @@ u32 lightrec_rw(struct lightrec_state *state, union code op,
void lightrec_free_block(struct block *block);
void remove_from_code_lut(struct blockcache *cache, struct block *block);
static inline u32 kunseg(u32 addr)
{
if (unlikely(addr >= 0xa0000000))

View File

@ -396,6 +396,7 @@ static void * get_next_block_func(struct lightrec_state *state, u32 pc)
if (ENABLE_THREADED_COMPILER)
lightrec_recompiler_remove(state->rec, block);
remove_from_code_lut(state->block_cache, block);
lightrec_unregister(MEM_FOR_CODE, block->code_size);
if (block->_jit)
_jit_destroy_state(block->_jit);
@ -784,6 +785,8 @@ static struct block * lightrec_precompile_block(struct lightrec_state *state,
if (list->flags & LIGHTREC_EMULATE_BRANCH)
block->flags |= BLOCK_NEVER_COMPILE;
block->hash = lightrec_calculate_block_hash(block);
return block;
}