Stop forced compilation when entering a new JIT execution level.

This commit is contained in:
gbeauche 2004-06-15 21:27:46 +00:00
parent aeab320c3f
commit 72b26d7ff7
4 changed files with 78 additions and 34 deletions

View File

@ -82,6 +82,9 @@ public:
dyngen_cpu_base cpu() const
{ return parent_cpu; }
// Align on ALIGN byte boundaries, ALIGN must be a power of 2
uint8 *gen_align(int align = 16);
// Start code generation of a new block
// Align on 16-byte boundaries
// Returns pointer to entry point
@ -231,7 +234,8 @@ public:
#undef DEFINE_ALIAS_RAW
// Address of jump offset to patch for direct chaining
uint8 *jmp_addr[2];
static const int MAX_JUMPS = 2;
uint8 *jmp_addr[MAX_JUMPS];
};
inline bool
@ -294,12 +298,20 @@ basic_dyngen::direct_call_possible(uintptr target) const
return false;
}
inline uint8 *
basic_dyngen::gen_align(int align)
{
while ((uintptr)code_ptr() & (align - 1))
inc_code_ptr(1);
return code_ptr();
}
inline uint8 *
basic_dyngen::gen_start()
{
while ((uintptr)code_ptr() & 15)
inc_code_ptr(1);
gen_code_start = code_ptr();
for (int i = 0; i < MAX_JUMPS; i++)
jmp_addr[i] = NULL;
gen_code_start = gen_align();
return gen_code_start;
}

View File

@ -44,18 +44,37 @@ struct powerpc_block_info
#if PPC_ENABLE_JIT
uint8 * entry_point;
#if DYNGEN_DIRECT_BLOCK_CHAINING
uint8 * jmp_resolve_addr[2]; // Address of default code to resolve target addr
uint8 * jmp_addr[2]; // Address of target native branch offset to patch
uint32 jmp_pc[2]; // Target jump addresses in emulated address space
struct link_info {
uint8 * jmp_resolve_addr; // Address of default code to resolve target addr
uint8 * jmp_addr; // Address of target native branch offset to patch
uint32 jmp_pc; // Target jump addresses in emulated address space
};
static const uint32 INVALID_PC = 0xffffffff; // An invalid PC address to mark jmp_pc[] as stale
link_info li[MAX_TARGETS];
#endif
#endif
uintptr min_pc, max_pc;
void init(uintptr start_pc);
bool intersect(uintptr start, uintptr end);
void invalidate();
};
inline void
powerpc_block_info::init(uintptr start_pc)
{
basic_block_info::init(start_pc);
#if PPC_DECODE_CACHE
di = NULL;
#endif
#if PPC_ENABLE_JIT
#if DYNGEN_DIRECT_BLOCK_CHAINING
for (int i = 0; i < MAX_TARGETS; i++)
li[i].jmp_pc = INVALID_PC;
#endif
#endif
}
inline bool
powerpc_block_info::intersect(uintptr start, uintptr end)
{

View File

@ -440,13 +440,13 @@ void *powerpc_cpu::compile_chain_block(block_info *sbi)
sbi = (block_info *)(((uintptr)sbi) & ~3L);
const uint32 bpc = sbi->pc;
const uint32 tpc = sbi->jmp_pc[n];
const uint32 tpc = sbi->li[n].jmp_pc;
block_info *tbi = block_cache.find(tpc);
if (tbi == NULL)
tbi = compile_block(tpc);
assert(tbi && tbi->pc == tpc);
dg_set_jmp_target(sbi->jmp_addr[n], tbi->entry_point);
dg_set_jmp_target(sbi->li[n].jmp_addr, tbi->entry_point);
return tbi->entry_point;
}
#endif
@ -462,9 +462,10 @@ void powerpc_cpu::execute(uint32 entry)
if (execute_depth == 1 || PPC_REENTRANT_JIT) {
#if PPC_ENABLE_JIT
if (use_jit) {
block_info *bi = block_cache.find(pc());
if (bi == NULL)
bi = compile_block(pc());
for (;;) {
block_info *bi = compile_block(pc());
// Execute all cached blocks
for (;;) {
codegen.execute(bi->entry_point);
@ -486,23 +487,33 @@ void powerpc_cpu::execute(uint32 entry)
if ((bi = block_cache.find(pc())) == NULL)
break;
}
// Compile new block
bi = compile_block(pc());
}
goto return_site;
}
#endif
#if PPC_DECODE_CACHE
block_info *bi = block_cache.find(pc());
if (bi != NULL)
goto pdi_execute;
for (;;) {
pdi_compile:
#if PPC_PROFILE_COMPILE_TIME
compile_count++;
clock_t start_time = clock();
#endif
block_info *bi = block_cache.new_blockinfo();
bi = block_cache.new_blockinfo();
bi->init(pc());
// Predecode a new block
block_info::decode_info *di = bi->di = decode_cache_p;
pdi_decode:
block_info::decode_info *di;
const instr_info_t *ii;
uint32 dpc = pc() - 4;
uint32 dpc;
di = bi->di = decode_cache_p;
dpc = pc() - 4;
do {
uint32 opcode = vm_read_memory_4(dpc += 4);
ii = decode(opcode);
@ -551,6 +562,7 @@ void powerpc_cpu::execute(uint32 entry)
#endif
// Execute all cached blocks
pdi_execute:
for (;;) {
const int r = bi->size % 4;
di = bi->di + r;
@ -647,6 +659,7 @@ void powerpc_cpu::kill_decode_cache()
void powerpc_cpu::invalidate_cache()
{
D(bug("Invalidate all cache blocks\n"));
#if PPC_DECODE_CACHE || PPC_ENABLE_JIT
block_cache.clear();
block_cache.initialize();
@ -662,13 +675,19 @@ void powerpc_cpu::invalidate_cache()
inline void powerpc_block_info::invalidate()
{
#if PPC_DECODE_CACHE
// Don't do anything if this is a predecoded block
if (di)
return;
#endif
#if DYNGEN_DIRECT_BLOCK_CHAINING
for (int i = 0; i < 2; i++) {
uint32 tpc = jmp_pc[i];
for (int i = 0; i < MAX_TARGETS; i++) {
link_info * const tli = &li[i];
uint32 tpc = tli->jmp_pc;
// For any jump within page boundaries, reset the jump address
// to the target block resolver (trampoline)
if (tpc != INVALID_PC && ((tpc ^ pc) >> 12) == 0)
dg_set_jmp_target(jmp_addr[i], jmp_resolve_addr[i]);
dg_set_jmp_target(tli->jmp_addr, tli->jmp_resolve_addr);
}
#endif
}
@ -682,6 +701,7 @@ void powerpc_cpu::invalidate_cache_range(uintptr start, uintptr end)
// Invalidate on page boundaries
start &= -4096;
end = (end + 4095) & -4096;
D(bug(" at page boundaries [%08x - %08x]\n", start, end));
}
#endif
block_cache.clear_range(start, end);

View File

@ -138,12 +138,6 @@ powerpc_cpu::compile_block(uint32 entry_point)
block_info *bi = block_cache.new_blockinfo();
bi->init(entry_point);
bi->entry_point = dg.gen_start();
#if DYNGEN_DIRECT_BLOCK_CHAINING
for (int i = 0; i < 2; i++) {
dg.jmp_addr[i] = NULL;
bi->jmp_pc[i] = block_info::INVALID_PC;
}
#endif
// Direct block chaining support variables
bool use_direct_block_chaining = false;
@ -484,10 +478,10 @@ powerpc_cpu::compile_block(uint32 entry_point)
// Use direct block chaining for in-page jumps or jumps to ROM area
if (direct_chaining_possible(bi->pc, tpc)) {
use_direct_block_chaining = true;
bi->jmp_pc[0] = tpc;
bi->li[0].jmp_pc = tpc;
// Make sure it's a conditional branch
if (BO_CONDITIONAL_BRANCH(bo) || BO_DECREMENT_CTR(bo))
bi->jmp_pc[1] = npc;
bi->li[1].jmp_pc = npc;
}
#endif
@ -547,7 +541,7 @@ powerpc_cpu::compile_block(uint32 entry_point)
// Use direct block chaining, addresses will be resolved at execution
if (direct_chaining_possible(bi->pc, tpc)) {
use_direct_block_chaining = true;
bi->jmp_pc[0] = tpc;
bi->li[0].jmp_pc = tpc;
}
#endif
@ -1507,7 +1501,6 @@ powerpc_cpu::compile_block(uint32 entry_point)
}
dg.gen_exec_return();
}
dg.gen_end();
bi->end_pc = dpc;
if (dpc < min_pc)
min_pc = dpc;
@ -1524,22 +1517,22 @@ powerpc_cpu::compile_block(uint32 entry_point)
if (use_direct_block_chaining) {
typedef void *(*func_t)(dyngen_cpu_base);
func_t func = (func_t)nv_mem_fun(&powerpc_cpu::compile_chain_block).ptr();
for (int i = 0; i < 2; i++) {
if (bi->jmp_pc[i] != block_info::INVALID_PC) {
uint8 *p = dg.gen_start();
for (int i = 0; i < block_info::MAX_TARGETS; i++) {
if (bi->li[i].jmp_pc != block_info::INVALID_PC) {
uint8 *p = dg.gen_align(16);
dg.gen_mov_ad_T0_im(((uintptr)bi) | i);
dg.gen_invoke_CPU_T0_ret_A0(func);
dg.gen_jmp_A0();
dg.gen_end();
assert(dg.jmp_addr[i] != NULL);
bi->jmp_addr[i] = dg.jmp_addr[i];
bi->jmp_resolve_addr[i] = p;
dg_set_jmp_target(bi->jmp_addr[i], bi->jmp_resolve_addr[i]);
bi->li[i].jmp_addr = dg.jmp_addr[i];
bi->li[i].jmp_resolve_addr = p;
dg_set_jmp_target(bi->li[i].jmp_addr, bi->li[i].jmp_resolve_addr);
}
}
}
#endif
dg.gen_end();
block_cache.add_to_cl_list(bi);
if (is_read_only_memory(bi->pc))
block_cache.add_to_dormant_list(bi);