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

View File

@ -44,18 +44,37 @@ struct powerpc_block_info
#if PPC_ENABLE_JIT #if PPC_ENABLE_JIT
uint8 * entry_point; uint8 * entry_point;
#if DYNGEN_DIRECT_BLOCK_CHAINING #if DYNGEN_DIRECT_BLOCK_CHAINING
uint8 * jmp_resolve_addr[2]; // Address of default code to resolve target addr struct link_info {
uint8 * jmp_addr[2]; // Address of target native branch offset to patch uint8 * jmp_resolve_addr; // Address of default code to resolve target addr
uint32 jmp_pc[2]; // Target jump addresses in emulated address space 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 static const uint32 INVALID_PC = 0xffffffff; // An invalid PC address to mark jmp_pc[] as stale
link_info li[MAX_TARGETS];
#endif #endif
#endif #endif
uintptr min_pc, max_pc; uintptr min_pc, max_pc;
void init(uintptr start_pc);
bool intersect(uintptr start, uintptr end); bool intersect(uintptr start, uintptr end);
void invalidate(); 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 inline bool
powerpc_block_info::intersect(uintptr start, uintptr end) 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); sbi = (block_info *)(((uintptr)sbi) & ~3L);
const uint32 bpc = sbi->pc; 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); block_info *tbi = block_cache.find(tpc);
if (tbi == NULL) if (tbi == NULL)
tbi = compile_block(tpc); tbi = compile_block(tpc);
assert(tbi && tbi->pc == 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; return tbi->entry_point;
} }
#endif #endif
@ -462,9 +462,10 @@ void powerpc_cpu::execute(uint32 entry)
if (execute_depth == 1 || PPC_REENTRANT_JIT) { if (execute_depth == 1 || PPC_REENTRANT_JIT) {
#if PPC_ENABLE_JIT #if PPC_ENABLE_JIT
if (use_jit) { if (use_jit) {
block_info *bi = block_cache.find(pc());
if (bi == NULL)
bi = compile_block(pc());
for (;;) { for (;;) {
block_info *bi = compile_block(pc());
// Execute all cached blocks // Execute all cached blocks
for (;;) { for (;;) {
codegen.execute(bi->entry_point); codegen.execute(bi->entry_point);
@ -486,23 +487,33 @@ void powerpc_cpu::execute(uint32 entry)
if ((bi = block_cache.find(pc())) == NULL) if ((bi = block_cache.find(pc())) == NULL)
break; break;
} }
// Compile new block
bi = compile_block(pc());
} }
goto return_site; goto return_site;
} }
#endif #endif
#if PPC_DECODE_CACHE #if PPC_DECODE_CACHE
block_info *bi = block_cache.find(pc());
if (bi != NULL)
goto pdi_execute;
for (;;) { for (;;) {
pdi_compile:
#if PPC_PROFILE_COMPILE_TIME #if PPC_PROFILE_COMPILE_TIME
compile_count++; compile_count++;
clock_t start_time = clock(); clock_t start_time = clock();
#endif #endif
block_info *bi = block_cache.new_blockinfo(); bi = block_cache.new_blockinfo();
bi->init(pc()); bi->init(pc());
// Predecode a new block // 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; const instr_info_t *ii;
uint32 dpc = pc() - 4; uint32 dpc;
di = bi->di = decode_cache_p;
dpc = pc() - 4;
do { do {
uint32 opcode = vm_read_memory_4(dpc += 4); uint32 opcode = vm_read_memory_4(dpc += 4);
ii = decode(opcode); ii = decode(opcode);
@ -551,6 +562,7 @@ void powerpc_cpu::execute(uint32 entry)
#endif #endif
// Execute all cached blocks // Execute all cached blocks
pdi_execute:
for (;;) { for (;;) {
const int r = bi->size % 4; const int r = bi->size % 4;
di = bi->di + r; di = bi->di + r;
@ -647,6 +659,7 @@ void powerpc_cpu::kill_decode_cache()
void powerpc_cpu::invalidate_cache() void powerpc_cpu::invalidate_cache()
{ {
D(bug("Invalidate all cache blocks\n"));
#if PPC_DECODE_CACHE || PPC_ENABLE_JIT #if PPC_DECODE_CACHE || PPC_ENABLE_JIT
block_cache.clear(); block_cache.clear();
block_cache.initialize(); block_cache.initialize();
@ -662,13 +675,19 @@ void powerpc_cpu::invalidate_cache()
inline void powerpc_block_info::invalidate() 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 #if DYNGEN_DIRECT_BLOCK_CHAINING
for (int i = 0; i < 2; i++) { for (int i = 0; i < MAX_TARGETS; i++) {
uint32 tpc = jmp_pc[i]; link_info * const tli = &li[i];
uint32 tpc = tli->jmp_pc;
// For any jump within page boundaries, reset the jump address // For any jump within page boundaries, reset the jump address
// to the target block resolver (trampoline) // to the target block resolver (trampoline)
if (tpc != INVALID_PC && ((tpc ^ pc) >> 12) == 0) 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 #endif
} }
@ -682,6 +701,7 @@ void powerpc_cpu::invalidate_cache_range(uintptr start, uintptr end)
// Invalidate on page boundaries // Invalidate on page boundaries
start &= -4096; start &= -4096;
end = (end + 4095) & -4096; end = (end + 4095) & -4096;
D(bug(" at page boundaries [%08x - %08x]\n", start, end));
} }
#endif #endif
block_cache.clear_range(start, end); 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(); block_info *bi = block_cache.new_blockinfo();
bi->init(entry_point); bi->init(entry_point);
bi->entry_point = dg.gen_start(); 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 // Direct block chaining support variables
bool use_direct_block_chaining = false; 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 // Use direct block chaining for in-page jumps or jumps to ROM area
if (direct_chaining_possible(bi->pc, tpc)) { if (direct_chaining_possible(bi->pc, tpc)) {
use_direct_block_chaining = true; use_direct_block_chaining = true;
bi->jmp_pc[0] = tpc; bi->li[0].jmp_pc = tpc;
// Make sure it's a conditional branch // Make sure it's a conditional branch
if (BO_CONDITIONAL_BRANCH(bo) || BO_DECREMENT_CTR(bo)) if (BO_CONDITIONAL_BRANCH(bo) || BO_DECREMENT_CTR(bo))
bi->jmp_pc[1] = npc; bi->li[1].jmp_pc = npc;
} }
#endif #endif
@ -547,7 +541,7 @@ powerpc_cpu::compile_block(uint32 entry_point)
// Use direct block chaining, addresses will be resolved at execution // Use direct block chaining, addresses will be resolved at execution
if (direct_chaining_possible(bi->pc, tpc)) { if (direct_chaining_possible(bi->pc, tpc)) {
use_direct_block_chaining = true; use_direct_block_chaining = true;
bi->jmp_pc[0] = tpc; bi->li[0].jmp_pc = tpc;
} }
#endif #endif
@ -1507,7 +1501,6 @@ powerpc_cpu::compile_block(uint32 entry_point)
} }
dg.gen_exec_return(); dg.gen_exec_return();
} }
dg.gen_end();
bi->end_pc = dpc; bi->end_pc = dpc;
if (dpc < min_pc) if (dpc < min_pc)
min_pc = dpc; min_pc = dpc;
@ -1524,22 +1517,22 @@ powerpc_cpu::compile_block(uint32 entry_point)
if (use_direct_block_chaining) { if (use_direct_block_chaining) {
typedef void *(*func_t)(dyngen_cpu_base); typedef void *(*func_t)(dyngen_cpu_base);
func_t func = (func_t)nv_mem_fun(&powerpc_cpu::compile_chain_block).ptr(); func_t func = (func_t)nv_mem_fun(&powerpc_cpu::compile_chain_block).ptr();
for (int i = 0; i < 2; i++) { for (int i = 0; i < block_info::MAX_TARGETS; i++) {
if (bi->jmp_pc[i] != block_info::INVALID_PC) { if (bi->li[i].jmp_pc != block_info::INVALID_PC) {
uint8 *p = dg.gen_start(); uint8 *p = dg.gen_align(16);
dg.gen_mov_ad_T0_im(((uintptr)bi) | i); dg.gen_mov_ad_T0_im(((uintptr)bi) | i);
dg.gen_invoke_CPU_T0_ret_A0(func); dg.gen_invoke_CPU_T0_ret_A0(func);
dg.gen_jmp_A0(); dg.gen_jmp_A0();
dg.gen_end();
assert(dg.jmp_addr[i] != NULL); assert(dg.jmp_addr[i] != NULL);
bi->jmp_addr[i] = dg.jmp_addr[i]; bi->li[i].jmp_addr = dg.jmp_addr[i];
bi->jmp_resolve_addr[i] = p; bi->li[i].jmp_resolve_addr = p;
dg_set_jmp_target(bi->jmp_addr[i], bi->jmp_resolve_addr[i]); dg_set_jmp_target(bi->li[i].jmp_addr, bi->li[i].jmp_resolve_addr);
} }
} }
} }
#endif #endif
dg.gen_end();
block_cache.add_to_cl_list(bi); block_cache.add_to_cl_list(bi);
if (is_read_only_memory(bi->pc)) if (is_read_only_memory(bi->pc))
block_cache.add_to_dormant_list(bi); block_cache.add_to_dormant_list(bi);