From 95a8be078bc1d86339e14093420a7440df8436f0 Mon Sep 17 00:00:00 2001 From: Ben Vanik Date: Mon, 21 Jan 2013 10:58:52 -0800 Subject: [PATCH] Rearranging code a bit to keep things cleaner. --- .../xenia/cpu/codegen/function_generator.h | 66 +++--- .../{codegen.h => codegen/module_generator.h} | 29 ++- include/xenia/cpu/exec_module.h | 18 +- src/cpu/codegen/function_generator.cc | 192 ++++++++++++++++++ .../module_generator.cc} | 31 +-- src/cpu/codegen/sources.gypi | 7 + src/cpu/exec_module.cc | 6 +- src/cpu/ppc/instr_context.cc | 162 --------------- src/cpu/ppc/sources.gypi | 1 - src/cpu/sources.gypi | 2 +- 10 files changed, 281 insertions(+), 233 deletions(-) rename src/cpu/ppc/instr_context.h => include/xenia/cpu/codegen/function_generator.h (58%) rename include/xenia/cpu/{codegen.h => codegen/module_generator.h} (81%) create mode 100644 src/cpu/codegen/function_generator.cc rename src/cpu/{codegen.cc => codegen/module_generator.cc} (89%) create mode 100644 src/cpu/codegen/sources.gypi delete mode 100644 src/cpu/ppc/instr_context.cc diff --git a/src/cpu/ppc/instr_context.h b/include/xenia/cpu/codegen/function_generator.h similarity index 58% rename from src/cpu/ppc/instr_context.h rename to include/xenia/cpu/codegen/function_generator.h index ca04b271d..e2ea64a55 100644 --- a/src/cpu/ppc/instr_context.h +++ b/include/xenia/cpu/codegen/function_generator.h @@ -7,34 +7,31 @@ ****************************************************************************** */ -#ifndef XENIA_CPU_PPC_INSTR_CONTEXT_H_ -#define XENIA_CPU_PPC_INSTR_CONTEXT_H_ +#ifndef XENIA_CPU_CODEGEN_FUNCTION_GENERATOR_H_ +#define XENIA_CPU_CODEGEN_FUNCTION_GENERATOR_H_ -#include +#include +#include +#include +#include +#include +#include #include - - -namespace llvm { - class LLVMContext; - class Module; - class Function; - class BasicBlock; - class Value; -} +#include namespace xe { namespace cpu { -namespace ppc { +namespace codegen { -class InstrContext { +class FunctionGenerator { public: - InstrContext(xe_memory_ref memory, sdb::FunctionSymbol* fn, - llvm::LLVMContext* context, llvm::Module* gen_module, - llvm::Function* gen_fn); - ~InstrContext(); + FunctionGenerator(xe_memory_ref memory, sdb::FunctionSymbol* fn, + llvm::LLVMContext* context, llvm::Module* gen_module, + llvm::Function* gen_fn); + ~FunctionGenerator(); sdb::FunctionSymbol* fn(); llvm::LLVMContext* context(); @@ -47,13 +44,18 @@ public: llvm::Function* GetFunction(uint32_t addr); llvm::Value* cia_value(); - llvm::Value* nia_value(); - void update_nia_value(llvm::Value* value); - llvm::Value* spr_value(uint32_t n); - void update_spr_value(uint32_t n, llvm::Value* value); - llvm::Value* cr_value(); - void update_cr_value(llvm::Value* value); + void FlushRegisters(); + + llvm::Value* xer_value(); + void update_xer_value(llvm::Value* value); + llvm::Value* lr_value(); + void update_lr_value(llvm::Value* value); + llvm::Value* ctr_value(); + void update_ctr_value(llvm::Value* value); + + llvm::Value* cr_value(uint32_t n); + void update_cr_value(uint32_t n, llvm::Value* value); llvm::Value* gpr_value(uint32_t n); void update_gpr_value(uint32_t n, llvm::Value* value); @@ -70,18 +72,28 @@ private: llvm::LLVMContext* context_; llvm::Module* gen_module_; llvm::Function* gen_fn_; - // TODO(benvanik): IRBuilder/etc + llvm::IRBuilder<>* builder_; std::map bbs_; // Address of the instruction being generated. uint32_t cia_; + + struct { + llvm::Value* xer; + llvm::Value* lr; + llvm::Value* ctr; + + llvm::Value* cr[4]; + + llvm::Value* gpr[32]; + } values_; }; -} // namespace ppc +} // namespace codegen } // namespace cpu } // namespace xe -#endif // XENIA_CPU_PPC_INSTR_CONTEXT_H_ +#endif // XENIA_CPU_CODEGEN_FUNCTION_GENERATOR_H_ diff --git a/include/xenia/cpu/codegen.h b/include/xenia/cpu/codegen/module_generator.h similarity index 81% rename from include/xenia/cpu/codegen.h rename to include/xenia/cpu/codegen/module_generator.h index f78f63683..62ee94028 100644 --- a/include/xenia/cpu/codegen.h +++ b/include/xenia/cpu/codegen/module_generator.h @@ -7,8 +7,8 @@ ****************************************************************************** */ -#ifndef XENIA_CPU_CODEGEN_H_ -#define XENIA_CPU_CODEGEN_H_ +#ifndef XENIA_CPU_CODEGEN_MODULE_GENERATOR_H_ +#define XENIA_CPU_CODEGEN_MODULE_GENERATOR_H_ #include #include @@ -31,25 +31,24 @@ namespace cpu { namespace codegen { -class CodegenFunction { +class ModuleGenerator { public: - sdb::FunctionSymbol* symbol; - llvm::FunctionType* function_type; - llvm::Function* function; -}; - - -class CodegenContext { -public: - CodegenContext( + ModuleGenerator( xe_memory_ref memory, kernel::ExportResolver* export_resolver, kernel::UserModule* module, sdb::SymbolDatabase* sdb, llvm::LLVMContext* context, llvm::Module* gen_module); - ~CodegenContext(); + ~ModuleGenerator(); - int GenerateModule(); + int Generate(); private: + class CodegenFunction { + public: + sdb::FunctionSymbol* symbol; + llvm::FunctionType* function_type; + llvm::Function* function; + }; + CodegenFunction* GetCodegenFunction(uint32_t address); void AddImports(); @@ -78,4 +77,4 @@ private: } // namespace xe -#endif // XENIA_CPU_CODEGEN_H_ +#endif // XENIA_CPU_CODEGEN_MODULE_GENERATOR_H_ diff --git a/include/xenia/cpu/exec_module.h b/include/xenia/cpu/exec_module.h index 9884a2a97..1c21417b6 100644 --- a/include/xenia/cpu/exec_module.h +++ b/include/xenia/cpu/exec_module.h @@ -27,7 +27,7 @@ namespace llvm { namespace xe { namespace cpu { namespace codegen { - class CodegenContext; + class ModuleGenerator; } } } @@ -53,14 +53,14 @@ private: int Init(); int Uninit(); - xe_memory_ref memory_; - shared_ptr export_resolver_; - kernel::UserModule* module_; - shared_ptr engine_; - shared_ptr sdb_; - shared_ptr context_; - shared_ptr gen_module_; - auto_ptr codegen_; + xe_memory_ref memory_; + shared_ptr export_resolver_; + kernel::UserModule* module_; + shared_ptr engine_; + shared_ptr sdb_; + shared_ptr context_; + shared_ptr gen_module_; + auto_ptr codegen_; }; diff --git a/src/cpu/codegen/function_generator.cc b/src/cpu/codegen/function_generator.cc new file mode 100644 index 000000000..001aa2506 --- /dev/null +++ b/src/cpu/codegen/function_generator.cc @@ -0,0 +1,192 @@ +/** + ****************************************************************************** + * Xenia : Xbox 360 Emulator Research Project * + ****************************************************************************** + * Copyright 2013 Ben Vanik. All rights reserved. * + * Released under the BSD license - see LICENSE in the root for more details. * + ****************************************************************************** + */ + +#include + + +using namespace llvm; +using namespace xe::cpu::codegen; +using namespace xe::cpu::ppc; +using namespace xe::cpu::sdb; + + +/** + * This generates function code. + * One context is created for each function to generate. Each basic block in + * the function is created and stashed in one pass, then filled in the next. + * + * This context object is a stateful representation of the current machine state + * and all accessors to registers should occur through it. By doing so it's + * possible to exploit the SSA nature of LLVM to reuse register values within + * a function without needing to flush to memory. + * + * Function calls (any branch outside of the function) will result in an + * expensive flush of registers. + * + * TODO(benvanik): track arguments by looking for register reads without writes + * TODO(benvanik): avoid flushing registers for leaf nodes + * TODO(benvnaik): pass return value in LLVM return, not by memory + */ + + +FunctionGenerator::FunctionGenerator(xe_memory_ref memory, FunctionSymbol* fn, + LLVMContext* context, Module* gen_module, + Function* gen_fn) { + memory_ = memory; + fn_ = fn; + context_ = context; + gen_module_ = gen_module; + gen_fn_ = gen_fn; + builder_ = new IRBuilder<>(*context_); +} + +FunctionGenerator::~FunctionGenerator() { + delete builder_; +} + +FunctionSymbol* FunctionGenerator::fn() { + return fn_; +} + +llvm::LLVMContext* FunctionGenerator::context() { + return context_; +} + +llvm::Module* FunctionGenerator::gen_module() { + return gen_module_; +} + +llvm::Function* FunctionGenerator::gen_fn() { + return gen_fn_; +} + +void FunctionGenerator::GenerateBasicBlocks() { + // Pass 1 creates all of the blocks - this way we can branch to them. + for (std::map::iterator it = fn_->blocks.begin(); + it != fn_->blocks.end(); ++it) { + FunctionBlock* block = it->second; + + char name[32]; + xesnprintfa(name, XECOUNT(name), "loc_%.8X", block->start_address); + BasicBlock* bb = BasicBlock::Create(*context_, name, gen_fn_); + bbs_.insert(std::pair(block->start_address, bb)); + } + + for (std::map::iterator it = fn_->blocks.begin(); + it != fn_->blocks.end(); ++it) { + FunctionBlock* block = it->second; + GenerateBasicBlock(block, GetBasicBlock(block->start_address)); + } +} + +void FunctionGenerator::GenerateBasicBlock(FunctionBlock* block, + BasicBlock* bb) { + printf(" bb %.8X-%.8X:\n", block->start_address, block->end_address); + + // Move the builder to this block and setup. + builder_->SetInsertPoint(bb); + //i->setMetadata("some.name", MDNode::get(context, MDString::get(context, pname))); + + // 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) { + InstrData i; + i.address = ia; + i.code = XEGETUINT32BE(p + ia); + i.type = ppc::GetInstrType(i.code); + if (!i.type) { + XELOGCPU("Invalid instruction at %.8X: %.8X\n", ia, i.code); + continue; + } + printf(" %.8X: %.8X %s\n", ia, i.code, i.type->name); + + // TODO(benvanik): debugging information? source/etc? + // builder_>SetCurrentDebugLocation(DebugLoc::get( + // ia >> 8, ia & 0xFF, ctx->cu)); + + //emit(this, i, builder); + } + + //Value* tmp = builder_->getInt32(0); + builder_->CreateRetVoid(); + + // TODO(benvanik): finish up BB +} + +BasicBlock* FunctionGenerator::GetBasicBlock(uint32_t address) { + std::map::iterator it = bbs_.find(address); + if (it != bbs_.end()) { + return it->second; + } + return NULL; +} + +Function* FunctionGenerator::GetFunction(uint32_t addr) { + return NULL; +} + +Value* FunctionGenerator::cia_value() { + return builder_->getInt32(cia_); +} + +void FunctionGenerator::FlushRegisters() { + +} + +Value* FunctionGenerator::xer_value() { + return NULL; +} + +void FunctionGenerator::update_xer_value(Value* value) { + +} + +Value* FunctionGenerator::lr_value() { + return NULL; +} + +void FunctionGenerator::update_lr_value(Value* value) { + +} + +Value* FunctionGenerator::ctr_value() { + return NULL; +} + +void FunctionGenerator::update_ctr_value(Value* value) { + +} + +Value* FunctionGenerator::cr_value(uint32_t n) { + return NULL; +} + +void FunctionGenerator::update_cr_value(uint32_t n, Value* value) { + // +} + +Value* FunctionGenerator::gpr_value(uint32_t n) { + return NULL; +} + +void FunctionGenerator::update_gpr_value(uint32_t n, Value* value) { + // +} + +Value* FunctionGenerator::memory_addr(uint32_t addr) { + return NULL; +} + +Value* FunctionGenerator::read_memory(Value* addr, uint32_t size, bool extend) { + return NULL; +} + +void FunctionGenerator::write_memory(Value* addr, uint32_t size, Value* value) { + // +} diff --git a/src/cpu/codegen.cc b/src/cpu/codegen/module_generator.cc similarity index 89% rename from src/cpu/codegen.cc rename to src/cpu/codegen/module_generator.cc index 9d272e367..3b4730164 100644 --- a/src/cpu/codegen.cc +++ b/src/cpu/codegen/module_generator.cc @@ -7,7 +7,7 @@ ****************************************************************************** */ -#include +#include #include #include @@ -24,18 +24,18 @@ #include #include -#include "cpu/ppc/instr_context.h" +#include + using namespace llvm; using namespace xe; using namespace xe::cpu; using namespace xe::cpu::codegen; -using namespace xe::cpu::ppc; using namespace xe::cpu::sdb; using namespace xe::kernel; -CodegenContext::CodegenContext( +ModuleGenerator::ModuleGenerator( xe_memory_ref memory, ExportResolver* export_resolver, UserModule* module, SymbolDatabase* sdb, LLVMContext* context, Module* gen_module) { @@ -47,11 +47,11 @@ CodegenContext::CodegenContext( gen_module_ = gen_module; } -CodegenContext::~CodegenContext() { +ModuleGenerator::~ModuleGenerator() { xe_memory_release(memory_); } -int CodegenContext::GenerateModule() { +int ModuleGenerator::Generate() { std::string error_message; // Setup a debug info builder. @@ -111,7 +111,8 @@ int CodegenContext::GenerateModule() { return 0; } -CodegenFunction* CodegenContext::GetCodegenFunction(uint32_t address) { +ModuleGenerator::CodegenFunction* ModuleGenerator::GetCodegenFunction( + uint32_t address) { std::map::iterator it = functions_.find(address); if (it != functions_.end()) { return it->second; @@ -119,7 +120,7 @@ CodegenFunction* CodegenContext::GetCodegenFunction(uint32_t address) { return NULL; } -void CodegenContext::AddMissingImport(FunctionSymbol* fn) { +void ModuleGenerator::AddMissingImport(FunctionSymbol* fn) { Module* m = gen_module_; LLVMContext& context = m->getContext(); @@ -158,14 +159,14 @@ void CodegenContext::AddMissingImport(FunctionSymbol* fn) { // implemented ? " " : "!!", name); } -void CodegenContext::AddPresentImport(FunctionSymbol* fn) { +void ModuleGenerator::AddPresentImport(FunctionSymbol* fn) { // Module *m = gen_module_; // LLVMContext& context = m->getContext(); // TODO(benvanik): add import thunk code. } -void CodegenContext::PrepareFunction(FunctionSymbol* fn) { +void ModuleGenerator::PrepareFunction(FunctionSymbol* fn) { Module* m = gen_module_; LLVMContext& context = m->getContext(); @@ -177,7 +178,7 @@ void CodegenContext::PrepareFunction(FunctionSymbol* fn) { AttributeSet attrs = AttributeSet::get(context, awi); std::vector args; - Type* return_type = Type::getInt32Ty(context); + Type* return_type = Type::getVoidTy(context); char name[64]; char* pname = name; @@ -202,16 +203,16 @@ void CodegenContext::PrepareFunction(FunctionSymbol* fn) { fn->start_address, cgf)); } -void CodegenContext::BuildFunction(CodegenFunction* cgf) { +void ModuleGenerator::BuildFunction(CodegenFunction* cgf) { FunctionSymbol* fn = cgf->symbol; printf("%s:\n", fn->name); // Setup the generation context. - InstrContext ic(memory_, fn, context_, gen_module_, cgf->function); + FunctionGenerator fgen(memory_, fn, context_, gen_module_, cgf->function); // Run through and generate each basic block. - ic.GenerateBasicBlocks(); + fgen.GenerateBasicBlocks(); // Run the optimizer on the function. // Doing this here keeps the size of the IR small and speeds up the later @@ -219,7 +220,7 @@ void CodegenContext::BuildFunction(CodegenFunction* cgf) { OptimizeFunction(gen_module_, cgf->function); } -void CodegenContext::OptimizeFunction(Module* m, Function* fn) { +void ModuleGenerator::OptimizeFunction(Module* m, Function* fn) { FunctionPassManager pm(m); PassManagerBuilder pmb; pmb.OptLevel = 3; diff --git a/src/cpu/codegen/sources.gypi b/src/cpu/codegen/sources.gypi new file mode 100644 index 000000000..f03979925 --- /dev/null +++ b/src/cpu/codegen/sources.gypi @@ -0,0 +1,7 @@ +# Copyright 2013 Ben Vanik. All Rights Reserved. +{ + 'sources': [ + 'function_generator.cc', + 'module_generator.cc', + ], +} diff --git a/src/cpu/exec_module.cc b/src/cpu/exec_module.cc index 1f6e56363..373eeecc2 100644 --- a/src/cpu/exec_module.cc +++ b/src/cpu/exec_module.cc @@ -27,7 +27,7 @@ #include #include -#include +#include #include #include "cpu/xethunk/xethunk.h" @@ -115,10 +115,10 @@ int ExecModule::Prepare() { &error_message); // Build the module from the source code. - codegen_ = auto_ptr(new CodegenContext( + codegen_ = auto_ptr(new ModuleGenerator( memory_, export_resolver_.get(), module_, sdb_.get(), context_.get(), gen_module_.get())); - XEEXPECTZERO(codegen_->GenerateModule()); + XEEXPECTZERO(codegen_->Generate()); // Write to cache. outs = auto_ptr(new raw_fd_ostream( diff --git a/src/cpu/ppc/instr_context.cc b/src/cpu/ppc/instr_context.cc deleted file mode 100644 index 96ce9f9b3..000000000 --- a/src/cpu/ppc/instr_context.cc +++ /dev/null @@ -1,162 +0,0 @@ -/** - ****************************************************************************** - * Xenia : Xbox 360 Emulator Research Project * - ****************************************************************************** - * Copyright 2013 Ben Vanik. All rights reserved. * - * Released under the BSD license - see LICENSE in the root for more details. * - ****************************************************************************** - */ - -#include "cpu/ppc/instr_context.h" - -#include -#include -#include -#include -#include -#include - - -using namespace llvm; -using namespace xe::cpu::ppc; -using namespace xe::cpu::sdb; - - -InstrContext::InstrContext(xe_memory_ref memory, FunctionSymbol* fn, - LLVMContext* context, Module* gen_module, - Function* gen_fn) { - memory_ = memory; - fn_ = fn; - context_ = context; - gen_module_ = gen_module; - gen_fn_ = gen_fn; -} - -InstrContext::~InstrContext() { -} - -FunctionSymbol* InstrContext::fn() { - return fn_; -} - -llvm::LLVMContext* InstrContext::context() { - return context_; -} - -llvm::Module* InstrContext::gen_module() { - return gen_module_; -} - -llvm::Function* InstrContext::gen_fn() { - return gen_fn_; -} - -void InstrContext::GenerateBasicBlocks() { - // Pass 1 creates all of the blocks - this way we can branch to them. - for (std::map::iterator it = fn_->blocks.begin(); - it != fn_->blocks.end(); ++it) { - FunctionBlock* block = it->second; - - char name[32]; - xesnprintfa(name, XECOUNT(name), "loc_%.8X", block->start_address); - BasicBlock* bb = BasicBlock::Create(*context_, name, gen_fn_); - bbs_.insert(std::pair(block->start_address, bb)); - } - - for (std::map::iterator it = fn_->blocks.begin(); - it != fn_->blocks.end(); ++it) { - FunctionBlock* block = it->second; - GenerateBasicBlock(block, GetBasicBlock(block->start_address)); - } -} - -void InstrContext::GenerateBasicBlock(FunctionBlock* block, BasicBlock* bb) { - printf(" bb %.8X-%.8X:\n", block->start_address, block->end_address); - - //builder.SetCurrentDebugLocation(DebugLoc::get(fn->start_address >> 8, fn->start_address & 0xFF, ctx->cu)); - //i->setMetadata("some.name", MDNode::get(context, MDString::get(context, pname))); - - IRBuilder<> builder(bb); - - // 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) { - InstrData i; - i.address = ia; - i.code = XEGETUINT32BE(p + ia); - i.type = ppc::GetInstrType(i.code); - if (!i.type) { - XELOGCPU("Invalid instruction at %.8X: %.8X\n", ia, i.code); - continue; - } - printf(" %.8X: %.8X %s\n", ia, i.code, i.type->name); - // stash current bb? - // stash builder - //emit(this, i); - } - - Value* tmp = builder.getInt32(0); - builder.CreateRet(tmp); - - // TODO(benvanik): finish up BB -} - -BasicBlock* InstrContext::GetBasicBlock(uint32_t address) { - std::map::iterator it = bbs_.find(address); - if (it != bbs_.end()) { - return it->second; - } - return NULL; -} - -Function* InstrContext::GetFunction(uint32_t addr) { - return NULL; -} - -Value* InstrContext::cia_value() { - return NULL; -} - -Value* InstrContext::nia_value() { - return NULL; -} - -void InstrContext::update_nia_value(Value* value) { - // -} - -Value* InstrContext::spr_value(uint32_t n) { - return NULL; -} - -void InstrContext::update_spr_value(uint32_t n, Value* value) { - // -} - -Value* InstrContext::cr_value() { - return NULL; -} - -void InstrContext::update_cr_value(Value* value) { - // -} - -Value* InstrContext::gpr_value(uint32_t n) { - return NULL; -} - -void InstrContext::update_gpr_value(uint32_t n, Value* value) { - // -} - -Value* InstrContext::memory_addr(uint32_t addr) { - return NULL; -} - -Value* InstrContext::read_memory(Value* addr, uint32_t size, bool extend) { - return NULL; -} - -void InstrContext::write_memory(Value* addr, uint32_t size, Value* value) { - // -} diff --git a/src/cpu/ppc/sources.gypi b/src/cpu/ppc/sources.gypi index 964d6ffb2..4acb10332 100644 --- a/src/cpu/ppc/sources.gypi +++ b/src/cpu/ppc/sources.gypi @@ -2,6 +2,5 @@ { 'sources': [ 'instr.cc', - 'instr_context.cc', ], } diff --git a/src/cpu/sources.gypi b/src/cpu/sources.gypi index 560f4adf8..e604f7cac 100644 --- a/src/cpu/sources.gypi +++ b/src/cpu/sources.gypi @@ -1,13 +1,13 @@ # Copyright 2013 Ben Vanik. All Rights Reserved. { 'sources': [ - 'codegen.cc', 'exec_module.cc', 'processor.cc', 'sdb.cc', ], 'includes': [ + 'codegen/sources.gypi', 'ppc/sources.gypi', ], }