diff --git a/TODO.md b/TODO.md index 2cb7f9442..35fc81ae9 100644 --- a/TODO.md +++ b/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 diff --git a/include/xenia/cpu/ppc/state.h b/include/xenia/cpu/ppc/state.h index eaceae2e7..ddea042d5 100644 --- a/include/xenia/cpu/ppc/state.h +++ b/include/xenia/cpu/ppc/state.h @@ -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; diff --git a/private/runtest.sh b/private/runtest.sh index f021b5d8b..d00de222e 100755 --- a/private/runtest.sh +++ b/private/runtest.sh @@ -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 diff --git a/src/cpu/codegen/function_generator.cc b/src/cpu/codegen/function_generator.cc index 7f11e370e..162067271 100644 --- a/src/cpu/codegen/function_generator.cc +++ b/src/cpu/codegen/function_generator.cc @@ -11,6 +11,8 @@ #include +#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; diff --git a/src/cpu/codegen/module_generator.cc b/src/cpu/codegen/module_generator.cc index 3e25c5d18..71c6efbca 100644 --- a/src/cpu/codegen/module_generator.cc +++ b/src/cpu/codegen/module_generator.cc @@ -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); diff --git a/src/cpu/cpu-private.h b/src/cpu/cpu-private.h index 95f4f0ace..ccf14ec29 100644 --- a/src/cpu/cpu-private.h +++ b/src/cpu/cpu-private.h @@ -13,6 +13,10 @@ #include +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); diff --git a/src/cpu/cpu.cc b/src/cpu/cpu.cc index c8f1f8db7..5b316212d 100644 --- a/src/cpu/cpu.cc +++ b/src/cpu/cpu.cc @@ -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."); diff --git a/src/cpu/exec_module.cc b/src/cpu/exec_module.cc index 1ec408dd9..a869a9428 100644 --- a/src/cpu/exec_module.cc +++ b/src/cpu/exec_module.cc @@ -30,6 +30,8 @@ #include #include +#include +#include #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 : ""); + + // 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 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 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; }