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
|
## Codegen
|
||||||
|
|
||||||
Make membase/state constant. Ensure optimized code uses constant value.
|
|
||||||
|
|
||||||
### Branch generation
|
### Branch generation
|
||||||
|
|
||||||
Change style to match: http://llvm.org/docs/tutorial/LangImpl5.html
|
Change style to match: http://llvm.org/docs/tutorial/LangImpl5.html
|
||||||
|
@ -85,16 +83,9 @@ OurFPM.add(createReassociatePass());
|
||||||
|
|
||||||
### Tracing
|
### Tracing
|
||||||
|
|
||||||
Tracing modes:
|
- Trace kernel export info (missing/present/etc).
|
||||||
- off (0)
|
- Trace user call info (name/?).
|
||||||
- syscalls (1)
|
- Trace instruction info (disasm).
|
||||||
- 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)
|
|
||||||
|
|
||||||
### Calling convention
|
### Calling convention
|
||||||
|
|
||||||
|
|
|
@ -136,6 +136,10 @@ typedef struct XECACHEALIGN64 xe_ppc_state {
|
||||||
// void set_fprf(const uint32_t v) {
|
// void set_fprf(const uint32_t v) {
|
||||||
// fpscr.value = (fpscr.value & ~0x000F8000) | 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;
|
} xe_ppc_state_t;
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -5,8 +5,11 @@ rm build/$1*
|
||||||
|
|
||||||
./build/xenia/release/xenia-run \
|
./build/xenia/release/xenia-run \
|
||||||
private/$1 \
|
private/$1 \
|
||||||
--optimize_ir_modules=false \
|
--optimize_ir_modules=true \
|
||||||
--optimize_ir_functions=false \
|
--optimize_ir_functions=false \
|
||||||
|
--trace_kernel_calls=true \
|
||||||
|
--trace_user_calls=true \
|
||||||
|
--trace_instructions=false \
|
||||||
2>build/run.llvm.txt 1>build/run.txt
|
2>build/run.llvm.txt 1>build/run.txt
|
||||||
|
|
||||||
if [ ! -s build/run.llvm.txt ]; then
|
if [ ! -s build/run.llvm.txt ]; then
|
||||||
|
|
|
@ -11,6 +11,8 @@
|
||||||
|
|
||||||
#include <xenia/cpu/ppc/state.h>
|
#include <xenia/cpu/ppc/state.h>
|
||||||
|
|
||||||
|
#include "cpu/cpu-private.h"
|
||||||
|
|
||||||
|
|
||||||
using namespace llvm;
|
using namespace llvm;
|
||||||
using namespace xe::cpu::codegen;
|
using namespace xe::cpu::codegen;
|
||||||
|
@ -82,10 +84,19 @@ FunctionBlock* FunctionGenerator::fn_block() {
|
||||||
void FunctionGenerator::GenerateBasicBlocks() {
|
void FunctionGenerator::GenerateBasicBlocks() {
|
||||||
// Always add an entry block.
|
// Always add an entry block.
|
||||||
BasicBlock* entry = BasicBlock::Create(*context_, "entry", gen_fn_);
|
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 this function is empty, abort!
|
||||||
if (!fn_->blocks.size()) {
|
if (!fn_->blocks.size()) {
|
||||||
builder_->SetInsertPoint(entry);
|
|
||||||
builder_->CreateRetVoid();
|
builder_->CreateRetVoid();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -124,6 +135,9 @@ void FunctionGenerator::GenerateBasicBlock(FunctionBlock* block,
|
||||||
builder_->SetInsertPoint(bb);
|
builder_->SetInsertPoint(bb);
|
||||||
//i->setMetadata("some.name", MDNode::get(context, MDString::get(context, pname)));
|
//i->setMetadata("some.name", MDNode::get(context, MDString::get(context, pname)));
|
||||||
|
|
||||||
|
Value* traceInstruction =
|
||||||
|
gen_module_->getGlobalVariable("XeTraceInstruction");
|
||||||
|
|
||||||
// Walk instructions in block.
|
// Walk instructions in block.
|
||||||
uint8_t* p = xe_memory_addr(memory_, 0);
|
uint8_t* p = xe_memory_addr(memory_, 0);
|
||||||
for (uint32_t ia = block->start_address; ia <= block->end_address; ia += 4) {
|
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.address = ia;
|
||||||
i.code = XEGETUINT32BE(p + ia);
|
i.code = XEGETUINT32BE(p + ia);
|
||||||
i.type = ppc::GetInstrType(i.code);
|
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) {
|
if (!i.type) {
|
||||||
XELOGCPU("Invalid instruction at %.8X: %.8X\n", ia, i.code);
|
XELOGCPU("Invalid instruction at %.8X: %.8X\n", ia, i.code);
|
||||||
continue;
|
continue;
|
||||||
|
|
|
@ -177,6 +177,16 @@ void ModuleGenerator::AddMissingImport(FunctionSymbol* fn) {
|
||||||
// TODO(benvanik): log errors.
|
// TODO(benvanik): log errors.
|
||||||
BasicBlock* block = BasicBlock::Create(context, "entry", f);
|
BasicBlock* block = BasicBlock::Create(context, "entry", f);
|
||||||
IRBuilder<> builder(block);
|
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();
|
builder.CreateRetVoid();
|
||||||
|
|
||||||
OptimizeFunction(m, f);
|
OptimizeFunction(m, f);
|
||||||
|
|
|
@ -13,6 +13,10 @@
|
||||||
#include <gflags/gflags.h>
|
#include <gflags/gflags.h>
|
||||||
|
|
||||||
|
|
||||||
|
DECLARE_bool(trace_instructions);
|
||||||
|
DECLARE_bool(trace_user_calls);
|
||||||
|
DECLARE_bool(trace_kernel_calls);
|
||||||
|
|
||||||
DECLARE_string(dump_path);
|
DECLARE_string(dump_path);
|
||||||
DECLARE_bool(dump_module_bitcode);
|
DECLARE_bool(dump_module_bitcode);
|
||||||
DECLARE_bool(dump_module_map);
|
DECLARE_bool(dump_module_map);
|
||||||
|
|
|
@ -13,6 +13,15 @@
|
||||||
// Debugging:
|
// 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:
|
// Dumping:
|
||||||
DEFINE_string(dump_path, "build/",
|
DEFINE_string(dump_path, "build/",
|
||||||
"Directory that dump files are placed into.");
|
"Directory that dump files are placed into.");
|
||||||
|
|
|
@ -30,6 +30,8 @@
|
||||||
|
|
||||||
#include <xenia/cpu/codegen/module_generator.h>
|
#include <xenia/cpu/codegen/module_generator.h>
|
||||||
#include <xenia/cpu/sdb.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/cpu-private.h"
|
||||||
#include "cpu/xethunk/xethunk.h"
|
#include "cpu/xethunk/xethunk.h"
|
||||||
|
@ -200,6 +202,26 @@ XECLEANUP:
|
||||||
return result_code;
|
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() {
|
int ExecModule::InjectGlobals() {
|
||||||
LLVMContext& context = *context_.get();
|
LLVMContext& context = *context_.get();
|
||||||
const DataLayout* dl = engine_->getDataLayout();
|
const DataLayout* dl = engine_->getDataLayout();
|
||||||
|
@ -222,6 +244,33 @@ int ExecModule::InjectGlobals() {
|
||||||
ConstantInt::get(intPtrTy, (uintptr_t)xe_memory_addr(memory_, 0)),
|
ConstantInt::get(intPtrTy, (uintptr_t)xe_memory_addr(memory_, 0)),
|
||||||
int8PtrTy));
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue