Adding --trace_branches.

Simple output right now, can always be enhanced.
This commit is contained in:
Ben Vanik 2013-05-23 01:31:41 -07:00
parent 4495637616
commit d6f2a0b3f0
7 changed files with 111 additions and 80 deletions

View File

@ -14,6 +14,7 @@
DECLARE_bool(trace_instructions);
DECLARE_bool(trace_branches);
DECLARE_bool(trace_user_calls);
DECLARE_bool(trace_kernel_calls);

View File

@ -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,

View File

@ -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;
}

View File

@ -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;

View File

@ -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,34 +236,14 @@ 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);
uint32_t nia;
if (i.B.AA) {
nia = XEEXTS26(i.B.BD << 2);
} 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)) {
return 1;
}
if (ok) {
jit_insn_label(f, &post_jump_label);
}
nia = i.address + XEEXTS26(i.B.BD << 2);
}
if (XeEmitBranchTo(e, f, "bcx", i.address, i.B.LK, ok)) {
return 1;
}
return 0;
@ -273,28 +285,8 @@ 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)) {
return 1;
}
if (ok) {
jit_insn_label(f, &post_jump_label);
}
if (XeEmitBranchTo(e, f, "bcctrx", i.address, i.XL.LK, ok)) {
return 1;
}
return 0;
@ -359,28 +351,8 @@ 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)) {
return 1;
}
if (ok) {
jit_insn_label(f, &post_jump_label);
}
if (XeEmitBranchTo(e, f, "bclrx", i.address, i.XL.LK, ok)) {
return 1;
}
return 0;

View File

@ -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

View File

@ -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);