Adding --trace_branches.
Simple output right now, can always be enhanced.
This commit is contained in:
parent
4495637616
commit
d6f2a0b3f0
|
@ -14,6 +14,7 @@
|
|||
|
||||
|
||||
DECLARE_bool(trace_instructions);
|
||||
DECLARE_bool(trace_branches);
|
||||
DECLARE_bool(trace_user_calls);
|
||||
DECLARE_bool(trace_kernel_calls);
|
||||
|
||||
|
|
|
@ -13,6 +13,8 @@
|
|||
// Tracing:
|
||||
DEFINE_bool(trace_instructions, false,
|
||||
"Trace all instructions.");
|
||||
DEFINE_bool(trace_branches, false,
|
||||
"Trace all branches.");
|
||||
DEFINE_bool(trace_user_calls, false,
|
||||
"Trace all user function calls.");
|
||||
DEFINE_bool(trace_kernel_calls, false,
|
||||
|
|
|
@ -82,6 +82,20 @@ void _cdecl XeTraceUserCall(
|
|||
(uint32_t)call_ia - 4, (uint32_t)cia, fn->name());
|
||||
}
|
||||
|
||||
void _cdecl XeTraceBranch(
|
||||
xe_ppc_state_t* state, uint64_t cia, uint64_t target_ia) {
|
||||
switch (target_ia) {
|
||||
case kXEPPCRegLR:
|
||||
target_ia = state->lr;
|
||||
break;
|
||||
case kXEPPCRegCTR:
|
||||
target_ia = state->ctr;
|
||||
break;
|
||||
}
|
||||
XELOGCPU("TRACE: %.8X -> b.%.8X",
|
||||
(uint32_t)cia, (uint32_t)target_ia);
|
||||
}
|
||||
|
||||
void _cdecl XeTraceInstruction(
|
||||
xe_ppc_state_t* state, uint64_t cia, uint64_t data) {
|
||||
ppc::InstrType* type = ppc::GetInstrType((uint32_t)data);
|
||||
|
@ -108,5 +122,6 @@ void xe::cpu::GetGlobalExports(GlobalExports* global_exports) {
|
|||
global_exports->XeAccessViolation = XeAccessViolation;
|
||||
global_exports->XeTraceKernelCall = XeTraceKernelCall;
|
||||
global_exports->XeTraceUserCall = XeTraceUserCall;
|
||||
global_exports->XeTraceBranch = XeTraceBranch;
|
||||
global_exports->XeTraceInstruction = XeTraceInstruction;
|
||||
}
|
||||
|
|
|
@ -37,6 +37,8 @@ typedef struct {
|
|||
void (_cdecl *XeTraceUserCall)(
|
||||
xe_ppc_state_t* state, uint64_t cia, uint64_t call_ia,
|
||||
sdb::FunctionSymbol* fn);
|
||||
void (_cdecl *XeTraceBranch)(
|
||||
xe_ppc_state_t* state, uint64_t cia, uint64_t target_ia);
|
||||
void (_cdecl *XeTraceInstruction)(
|
||||
xe_ppc_state_t* state, uint64_t cia, uint64_t data);
|
||||
} GlobalExports;
|
||||
|
|
|
@ -9,6 +9,8 @@
|
|||
|
||||
#include <xenia/cpu/libjit/libjit_emit.h>
|
||||
|
||||
#include <xenia/cpu/cpu-private.h>
|
||||
|
||||
|
||||
using namespace xe::cpu;
|
||||
using namespace xe::cpu::ppc;
|
||||
|
@ -61,15 +63,37 @@ int XeEmitIndirectBranchTo(
|
|||
|
||||
int XeEmitBranchTo(
|
||||
LibjitEmitter& e, jit_function_t f, const char* src, uint32_t cia,
|
||||
bool lk) {
|
||||
// Get the basic block and switch behavior based on outgoing type.
|
||||
bool lk, jit_value_t condition) {
|
||||
FunctionBlock* fn_block = e.fn_block();
|
||||
|
||||
// Fast-path for branches to other blocks.
|
||||
// Only valid when not tracing branches.
|
||||
if (!FLAGS_trace_branches &&
|
||||
fn_block->outgoing_type == FunctionBlock::kTargetBlock) {
|
||||
e.branch_to_block_if(fn_block->outgoing_address, condition);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Only branch of conditionals when we have one.
|
||||
jit_label_t post_jump_label = jit_label_undefined;
|
||||
if (condition) {
|
||||
// TODO(benvanik): add debug info for this?
|
||||
// char name[32];
|
||||
// xesnprintfa(name, XECOUNT(name), "loc_%.8X_bcx", i.address);
|
||||
jit_insn_branch_if_not(f, condition, &post_jump_label);
|
||||
}
|
||||
|
||||
if (FLAGS_trace_branches) {
|
||||
e.TraceBranch(cia);
|
||||
}
|
||||
|
||||
// Get the basic block and switch behavior based on outgoing type.
|
||||
int result = 0;
|
||||
switch (fn_block->outgoing_type) {
|
||||
case FunctionBlock::kTargetBlock:
|
||||
{
|
||||
// Taken care of above usually.
|
||||
e.branch_to_block(fn_block->outgoing_address);
|
||||
break;
|
||||
}
|
||||
case FunctionBlock::kTargetFunction:
|
||||
{
|
||||
// Spill all registers to memory.
|
||||
|
@ -103,20 +127,28 @@ int XeEmitBranchTo(
|
|||
{
|
||||
// An indirect jump.
|
||||
printf("INDIRECT JUMP VIA LR: %.8X\n", cia);
|
||||
return XeEmitIndirectBranchTo(e, f, src, cia, lk, kXEPPCRegLR);
|
||||
result = XeEmitIndirectBranchTo(e, f, src, cia, lk, kXEPPCRegLR);
|
||||
break;
|
||||
}
|
||||
case FunctionBlock::kTargetCTR:
|
||||
{
|
||||
// An indirect jump.
|
||||
printf("INDIRECT JUMP VIA CTR: %.8X\n", cia);
|
||||
return XeEmitIndirectBranchTo(e, f, src, cia, lk, kXEPPCRegCTR);
|
||||
result = XeEmitIndirectBranchTo(e, f, src, cia, lk, kXEPPCRegCTR);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
case FunctionBlock::kTargetNone:
|
||||
XEASSERTALWAYS();
|
||||
return 1;
|
||||
result = 1;
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
|
||||
if (condition) {
|
||||
jit_insn_label(f, &post_jump_label);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
|
@ -138,7 +170,7 @@ XEEMITTER(bx, 0x48000000, I )(LibjitEmitter& e, jit_function_t f, Ins
|
|||
e.update_lr_value(e.get_uint64(i.address + 4));
|
||||
}
|
||||
|
||||
return XeEmitBranchTo(e, f, "bx", i.address, i.I.LK);
|
||||
return XeEmitBranchTo(e, f, "bx", i.address, i.I.LK, NULL);
|
||||
}
|
||||
|
||||
XEEMITTER(bcx, 0x40000000, B )(LibjitEmitter& e, jit_function_t f, InstrData& i) {
|
||||
|
@ -204,36 +236,16 @@ XEEMITTER(bcx, 0x40000000, B )(LibjitEmitter& e, jit_function_t f, Ins
|
|||
ok = cond_ok;
|
||||
}
|
||||
|
||||
// Optimization: if a branch target, inline the conditional branch here.
|
||||
FunctionBlock* fn_block = e.fn_block();
|
||||
if (fn_block->outgoing_type == FunctionBlock::kTargetBlock) {
|
||||
e.branch_to_block_if(fn_block->outgoing_address, ok);
|
||||
} else {
|
||||
// Only branch of conditionals when we have one.
|
||||
jit_label_t post_jump_label = jit_label_undefined;
|
||||
if (ok) {
|
||||
// TODO(benvanik): add debug info for this?
|
||||
// char name[32];
|
||||
// xesnprintfa(name, XECOUNT(name), "loc_%.8X_bcx", i.address);
|
||||
jit_insn_branch_if_not(f, ok, &post_jump_label);
|
||||
}
|
||||
|
||||
// Note that this occurs entirely within the branch true block.
|
||||
uint32_t nia;
|
||||
if (i.B.AA) {
|
||||
nia = XEEXTS26(i.B.BD << 2);
|
||||
} else {
|
||||
nia = i.address + XEEXTS26(i.B.BD << 2);
|
||||
}
|
||||
if (XeEmitBranchTo(e, f, "bcx", i.address, i.B.LK)) {
|
||||
if (XeEmitBranchTo(e, f, "bcx", i.address, i.B.LK, ok)) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (ok) {
|
||||
jit_insn_label(f, &post_jump_label);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -273,30 +285,10 @@ XEEMITTER(bcctrx, 0x4C000420, XL )(LibjitEmitter& e, jit_function_t f, Ins
|
|||
ok = cond_ok;
|
||||
}
|
||||
|
||||
// Optimization: if a branch target, inline the conditional branch here.
|
||||
FunctionBlock* fn_block = e.fn_block();
|
||||
if (fn_block->outgoing_type == FunctionBlock::kTargetBlock) {
|
||||
e.branch_to_block_if(fn_block->outgoing_address, ok);
|
||||
} else {
|
||||
// Only branch of conditionals when we have one.
|
||||
jit_label_t post_jump_label = jit_label_undefined;
|
||||
if (ok) {
|
||||
// TODO(benvanik): add debug info for this?
|
||||
// char name[32];
|
||||
// xesnprintfa(name, XECOUNT(name), "loc_%.8X_bcx", i.address);
|
||||
jit_insn_branch_if_not(f, ok, &post_jump_label);
|
||||
}
|
||||
|
||||
// Note that this occurs entirely within the branch true block.
|
||||
if (XeEmitBranchTo(e, f, "bcctrx", i.address, i.XL.LK)) {
|
||||
if (XeEmitBranchTo(e, f, "bcctrx", i.address, i.XL.LK, ok)) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (ok) {
|
||||
jit_insn_label(f, &post_jump_label);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -359,30 +351,10 @@ XEEMITTER(bclrx, 0x4C000020, XL )(LibjitEmitter& e, jit_function_t f, Ins
|
|||
ok = cond_ok;
|
||||
}
|
||||
|
||||
// Optimization: if a branch target, inline the conditional branch here.
|
||||
FunctionBlock* fn_block = e.fn_block();
|
||||
if (fn_block->outgoing_type == FunctionBlock::kTargetBlock) {
|
||||
e.branch_to_block_if(fn_block->outgoing_address, ok);
|
||||
} else {
|
||||
// Only branch of conditionals when we have one.
|
||||
jit_label_t post_jump_label = jit_label_undefined;
|
||||
if (ok) {
|
||||
// TODO(benvanik): add debug info for this?
|
||||
// char name[32];
|
||||
// xesnprintfa(name, XECOUNT(name), "loc_%.8X_bcx", i.address);
|
||||
jit_insn_branch_if_not(f, ok, &post_jump_label);
|
||||
}
|
||||
|
||||
// Note that this occurs entirely within the branch true block.
|
||||
if (XeEmitBranchTo(e, f, "bclrx", i.address, i.XL.LK)) {
|
||||
if (XeEmitBranchTo(e, f, "bclrx", i.address, i.XL.LK, ok)) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (ok) {
|
||||
jit_insn_label(f, &post_jump_label);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -751,6 +751,44 @@ int LibjitEmitter::call_function(FunctionSymbol* target_symbol,
|
|||
return 1;
|
||||
}
|
||||
|
||||
void LibjitEmitter::TraceBranch(uint32_t cia) {
|
||||
SpillRegisters();
|
||||
|
||||
// Pick target. If it's an indirection the tracing function will handle it.
|
||||
uint64_t target = 0;
|
||||
switch (fn_block_->outgoing_type) {
|
||||
case FunctionBlock::kTargetBlock:
|
||||
target = fn_block_->outgoing_address;
|
||||
break;
|
||||
case FunctionBlock::kTargetFunction:
|
||||
target = fn_block_->outgoing_function->start_address;
|
||||
break;
|
||||
case FunctionBlock::kTargetLR:
|
||||
target = kXEPPCRegLR;
|
||||
break;
|
||||
case FunctionBlock::kTargetCTR:
|
||||
target = kXEPPCRegCTR;
|
||||
break;
|
||||
default:
|
||||
case FunctionBlock::kTargetNone:
|
||||
XEASSERTALWAYS();
|
||||
break;
|
||||
}
|
||||
|
||||
jit_value_t trace_args[] = {
|
||||
jit_value_get_param(fn_, 0),
|
||||
jit_value_create_long_constant(fn_, jit_type_ulong, cia),
|
||||
jit_value_create_long_constant(fn_, jit_type_ulong, target),
|
||||
};
|
||||
jit_insn_call_native(
|
||||
fn_,
|
||||
"XeTraceBranch",
|
||||
global_exports_.XeTraceBranch,
|
||||
global_export_signature_3_,
|
||||
trace_args, XECOUNT(trace_args),
|
||||
0);
|
||||
}
|
||||
|
||||
int LibjitEmitter::GenerateIndirectionBranch(uint32_t cia, jit_value_t target,
|
||||
bool lk, bool likely_local) {
|
||||
// This function is called by the control emitters when they know that an
|
||||
|
|
|
@ -58,6 +58,7 @@ public:
|
|||
int call_function(sdb::FunctionSymbol* target_symbol, jit_value_t lr,
|
||||
bool tail);
|
||||
|
||||
void TraceBranch(uint32_t cia);
|
||||
int GenerateIndirectionBranch(uint32_t cia, jit_value_t target,
|
||||
bool lk, bool likely_local);
|
||||
|
||||
|
|
Loading…
Reference in New Issue