Adding tracing methods.
This commit is contained in:
parent
385a4ee23b
commit
47481fecf7
15
TODO.md
15
TODO.md
|
@ -43,8 +43,6 @@ indicate expected values.
|
|||
|
||||
## Codegen
|
||||
|
||||
Make membase/state constant. Ensure optimized code uses constant value.
|
||||
|
||||
### Branch generation
|
||||
|
||||
Change style to match: http://llvm.org/docs/tutorial/LangImpl5.html
|
||||
|
@ -85,16 +83,9 @@ OurFPM.add(createReassociatePass());
|
|||
|
||||
### Tracing
|
||||
|
||||
Tracing modes:
|
||||
- off (0)
|
||||
- syscalls (1)
|
||||
- fn calls (2)
|
||||
- all instructions (3)
|
||||
|
||||
Inject extern functions into module:
|
||||
- XeTraceKernelCall(caller_ia, cia, name, state)
|
||||
- XeTraceUserCall(caller_ia, cia, name, state)
|
||||
- XeTraceInstruction(cia, state)
|
||||
- Trace kernel export info (missing/present/etc).
|
||||
- Trace user call info (name/?).
|
||||
- Trace instruction info (disasm).
|
||||
|
||||
### Calling convention
|
||||
|
||||
|
|
|
@ -136,6 +136,10 @@ typedef struct XECACHEALIGN64 xe_ppc_state {
|
|||
// void set_fprf(const uint32_t v) {
|
||||
// fpscr.value = (fpscr.value & ~0x000F8000) | v;
|
||||
// }
|
||||
|
||||
// Runtime-specific data pointer. Used on callbacks to get access to the
|
||||
// current runtime and its data.
|
||||
void* runtime_data;
|
||||
} xe_ppc_state_t;
|
||||
|
||||
|
||||
|
|
|
@ -5,8 +5,11 @@ rm build/$1*
|
|||
|
||||
./build/xenia/release/xenia-run \
|
||||
private/$1 \
|
||||
--optimize_ir_modules=false \
|
||||
--optimize_ir_modules=true \
|
||||
--optimize_ir_functions=false \
|
||||
--trace_kernel_calls=true \
|
||||
--trace_user_calls=true \
|
||||
--trace_instructions=false \
|
||||
2>build/run.llvm.txt 1>build/run.txt
|
||||
|
||||
if [ ! -s build/run.llvm.txt ]; then
|
||||
|
|
|
@ -11,6 +11,8 @@
|
|||
|
||||
#include <xenia/cpu/ppc/state.h>
|
||||
|
||||
#include "cpu/cpu-private.h"
|
||||
|
||||
|
||||
using namespace llvm;
|
||||
using namespace xe::cpu::codegen;
|
||||
|
@ -82,10 +84,19 @@ FunctionBlock* FunctionGenerator::fn_block() {
|
|||
void FunctionGenerator::GenerateBasicBlocks() {
|
||||
// Always add an entry block.
|
||||
BasicBlock* entry = BasicBlock::Create(*context_, "entry", gen_fn_);
|
||||
builder_->SetInsertPoint(entry);
|
||||
|
||||
if (FLAGS_trace_user_calls) {
|
||||
Value* traceUserCall = gen_module_->getGlobalVariable("XeTraceUserCall");
|
||||
builder_->CreateCall3(
|
||||
traceUserCall,
|
||||
gen_fn_->arg_begin(),
|
||||
builder_->getInt32(fn_->start_address),
|
||||
builder_->getInt32(0));
|
||||
}
|
||||
|
||||
// If this function is empty, abort!
|
||||
if (!fn_->blocks.size()) {
|
||||
builder_->SetInsertPoint(entry);
|
||||
builder_->CreateRetVoid();
|
||||
return;
|
||||
}
|
||||
|
@ -124,6 +135,9 @@ void FunctionGenerator::GenerateBasicBlock(FunctionBlock* block,
|
|||
builder_->SetInsertPoint(bb);
|
||||
//i->setMetadata("some.name", MDNode::get(context, MDString::get(context, pname)));
|
||||
|
||||
Value* traceInstruction =
|
||||
gen_module_->getGlobalVariable("XeTraceInstruction");
|
||||
|
||||
// Walk instructions in block.
|
||||
uint8_t* p = xe_memory_addr(memory_, 0);
|
||||
for (uint32_t ia = block->start_address; ia <= block->end_address; ia += 4) {
|
||||
|
@ -131,6 +145,15 @@ void FunctionGenerator::GenerateBasicBlock(FunctionBlock* block,
|
|||
i.address = ia;
|
||||
i.code = XEGETUINT32BE(p + ia);
|
||||
i.type = ppc::GetInstrType(i.code);
|
||||
|
||||
if (FLAGS_trace_instructions) {
|
||||
builder_->CreateCall3(
|
||||
traceInstruction,
|
||||
gen_fn_->arg_begin(),
|
||||
builder_->getInt32(i.address),
|
||||
builder_->getInt32(i.code));
|
||||
}
|
||||
|
||||
if (!i.type) {
|
||||
XELOGCPU("Invalid instruction at %.8X: %.8X\n", ia, i.code);
|
||||
continue;
|
||||
|
|
|
@ -177,6 +177,16 @@ void ModuleGenerator::AddMissingImport(FunctionSymbol* fn) {
|
|||
// TODO(benvanik): log errors.
|
||||
BasicBlock* block = BasicBlock::Create(context, "entry", f);
|
||||
IRBuilder<> builder(block);
|
||||
|
||||
if (FLAGS_trace_kernel_calls) {
|
||||
Value* traceKernelCall = m->getGlobalVariable("XeTraceKernelCall");
|
||||
builder.CreateCall3(
|
||||
traceKernelCall,
|
||||
f->arg_begin(),
|
||||
builder.getInt32(fn->start_address),
|
||||
builder.getInt32(0));
|
||||
}
|
||||
|
||||
builder.CreateRetVoid();
|
||||
|
||||
OptimizeFunction(m, f);
|
||||
|
|
|
@ -13,6 +13,10 @@
|
|||
#include <gflags/gflags.h>
|
||||
|
||||
|
||||
DECLARE_bool(trace_instructions);
|
||||
DECLARE_bool(trace_user_calls);
|
||||
DECLARE_bool(trace_kernel_calls);
|
||||
|
||||
DECLARE_string(dump_path);
|
||||
DECLARE_bool(dump_module_bitcode);
|
||||
DECLARE_bool(dump_module_map);
|
||||
|
|
|
@ -13,6 +13,15 @@
|
|||
// Debugging:
|
||||
|
||||
|
||||
// Tracing:
|
||||
DEFINE_bool(trace_instructions, false,
|
||||
"Trace all instructions.");
|
||||
DEFINE_bool(trace_user_calls, false,
|
||||
"Trace all user function calls.");
|
||||
DEFINE_bool(trace_kernel_calls, false,
|
||||
"Trace all kernel function calls.");
|
||||
|
||||
|
||||
// Dumping:
|
||||
DEFINE_string(dump_path, "build/",
|
||||
"Directory that dump files are placed into.");
|
||||
|
|
|
@ -30,6 +30,8 @@
|
|||
|
||||
#include <xenia/cpu/codegen/module_generator.h>
|
||||
#include <xenia/cpu/sdb.h>
|
||||
#include <xenia/cpu/ppc/instr.h>
|
||||
#include <xenia/cpu/ppc/state.h>
|
||||
|
||||
#include "cpu/cpu-private.h"
|
||||
#include "cpu/xethunk/xethunk.h"
|
||||
|
@ -200,6 +202,26 @@ XECLEANUP:
|
|||
return result_code;
|
||||
}
|
||||
|
||||
void XeTraceKernelCall(xe_ppc_state_t* state, uint32_t cia, uint32_t call_ia) {
|
||||
// TODO(benvanik): get names
|
||||
XELOGCPU("TRACE: %.8X -> k.%.8X", call_ia, cia);
|
||||
}
|
||||
|
||||
void XeTraceUserCall(xe_ppc_state_t* state, uint32_t cia, uint32_t call_ia) {
|
||||
// TODO(benvanik): get names
|
||||
XELOGCPU("TRACE: %.8X -> u.%.8X", call_ia, cia);
|
||||
}
|
||||
|
||||
void XeTraceInstruction(xe_ppc_state_t* state, uint32_t cia, uint32_t data) {
|
||||
ppc::InstrType* type = ppc::GetInstrType(data);
|
||||
XELOGCPU("TRACE: %.8X %.8X %s %s",
|
||||
cia, data,
|
||||
type && type->emit ? " " : "X",
|
||||
type ? type->name : "<unknown>");
|
||||
|
||||
// TODO(benvanik): better disassembly, printing of current register values/etc
|
||||
}
|
||||
|
||||
int ExecModule::InjectGlobals() {
|
||||
LLVMContext& context = *context_.get();
|
||||
const DataLayout* dl = engine_->getDataLayout();
|
||||
|
@ -222,6 +244,33 @@ int ExecModule::InjectGlobals() {
|
|||
ConstantInt::get(intPtrTy, (uintptr_t)xe_memory_addr(memory_, 0)),
|
||||
int8PtrTy));
|
||||
|
||||
// Tracing methods:
|
||||
std::vector<Type*> traceCallArgs;
|
||||
traceCallArgs.push_back(int8PtrTy);
|
||||
traceCallArgs.push_back(Type::getInt32Ty(context));
|
||||
traceCallArgs.push_back(Type::getInt32Ty(context));
|
||||
FunctionType* traceCallTy = FunctionType::get(
|
||||
Type::getVoidTy(context), traceCallArgs, false);
|
||||
std::vector<Type*> traceInstructionArgs;
|
||||
traceInstructionArgs.push_back(int8PtrTy);
|
||||
traceInstructionArgs.push_back(Type::getInt32Ty(context));
|
||||
traceInstructionArgs.push_back(Type::getInt32Ty(context));
|
||||
FunctionType* traceInstructionTy = FunctionType::get(
|
||||
Type::getVoidTy(context), traceInstructionArgs, false);
|
||||
|
||||
gv = new GlobalVariable(*gen_module_, traceCallTy, true,
|
||||
GlobalValue::ExternalLinkage, 0,
|
||||
"XeTraceKernelCall");
|
||||
engine_->addGlobalMapping(gv, (void*)&XeTraceKernelCall);
|
||||
gv = new GlobalVariable(*gen_module_, traceCallTy, true,
|
||||
GlobalValue::ExternalLinkage, 0,
|
||||
"XeTraceUserCall");
|
||||
engine_->addGlobalMapping(gv, (void*)&XeTraceUserCall);
|
||||
gv = new GlobalVariable(*gen_module_, traceInstructionTy, true,
|
||||
GlobalValue::ExternalLinkage, 0,
|
||||
"XeTraceInstruction");
|
||||
engine_->addGlobalMapping(gv, (void*)&XeTraceInstruction);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue