diff --git a/.gitmodules b/.gitmodules index 3863f7082..6f513e47b 100644 --- a/.gitmodules +++ b/.gitmodules @@ -7,3 +7,6 @@ [submodule "third_party/gyp"] path = third_party/gyp url = https://github.com/benvanik/gyp.git +[submodule "third_party/gflags"] + path = third_party/gflags + url = https://github.com/benvanik/gflags.git diff --git a/common.gypi b/common.gypi index 795da2f9c..5699206b0 100644 --- a/common.gypi +++ b/common.gypi @@ -60,6 +60,7 @@ 'release': { 'defines': [ 'RELEASE', + 'NDEBUG', ], 'msvs_configuration_attributes': { 'OutputDirectory': '<(DEPTH)\\build\\xenia\\release', diff --git a/include/xenia/cpu/sdb.h b/include/xenia/cpu/sdb.h index ffd9a088a..078f0f84b 100644 --- a/include/xenia/cpu/sdb.h +++ b/include/xenia/cpu/sdb.h @@ -157,6 +157,7 @@ public: int GetAllFunctions(vector& functions); + void Write(const char* file_name); void Dump(); void DumpFunctionBlocks(FunctionSymbol* fn); diff --git a/src/cpu/codegen/module_generator.cc b/src/cpu/codegen/module_generator.cc index c8f22ce84..620e3c420 100644 --- a/src/cpu/codegen/module_generator.cc +++ b/src/cpu/codegen/module_generator.cc @@ -26,6 +26,8 @@ #include #include +#include "cpu/cpu-private.h" + using namespace llvm; using namespace xe; @@ -234,15 +236,15 @@ void ModuleGenerator::BuildFunction(CodegenFunction* cgf) { void ModuleGenerator::OptimizeFunction(Module* m, Function* fn) { FunctionPassManager pm(m); -#if XE_OPTION(OPTIMIZED) - PassManagerBuilder pmb; - pmb.OptLevel = 3; - pmb.SizeLevel = 0; - pmb.Inliner = createFunctionInliningPass(); - pmb.Vectorize = true; - pmb.LoopVectorize = true; - pmb.populateFunctionPassManager(pm); -#endif // XE_OPTION(OPTIMIZED) + if (FLAGS_optimize_ir_functions) { + PassManagerBuilder pmb; + pmb.OptLevel = 3; + pmb.SizeLevel = 0; + pmb.Inliner = createFunctionInliningPass(); + pmb.Vectorize = true; + pmb.LoopVectorize = true; + pmb.populateFunctionPassManager(pm); + } pm.add(createVerifierPass()); pm.run(*fn); } diff --git a/src/cpu/cpu-private.h b/src/cpu/cpu-private.h new file mode 100644 index 000000000..95f4f0ace --- /dev/null +++ b/src/cpu/cpu-private.h @@ -0,0 +1,24 @@ +/** + ****************************************************************************** + * 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. * + ****************************************************************************** + */ + +#ifndef XENIA_CPU_PRIVATE_H_ +#define XENIA_CPU_PRIVATE_H_ + +#include + + +DECLARE_string(dump_path); +DECLARE_bool(dump_module_bitcode); +DECLARE_bool(dump_module_map); + +DECLARE_bool(optimize_ir_modules); +DECLARE_bool(optimize_ir_functions); + + +#endif // XENIA_CPU_PRIVATE_H_ diff --git a/src/cpu/cpu.cc b/src/cpu/cpu.cc new file mode 100644 index 000000000..147704bf9 --- /dev/null +++ b/src/cpu/cpu.cc @@ -0,0 +1,26 @@ +/** + ****************************************************************************** + * 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/cpu-private.h" + + +// Dumping: +DEFINE_string(dump_path, "build/", + "Directory that dump files are placed into."); +DEFINE_bool(dump_module_bitcode, true, + "Writes the module bitcode both before and after optimizations."); +DEFINE_bool(dump_module_map, true, + "Dumps the module symbol database."); + + +// Optimizations: +DEFINE_bool(optimize_ir_modules, true, + "Whether to run LLVM optimizations on modules."); +DEFINE_bool(optimize_ir_functions, true, + "Whether to run LLVM optimizations on functions."); diff --git a/src/cpu/exec_module.cc b/src/cpu/exec_module.cc index 2d19d3f4e..158ac1a6f 100644 --- a/src/cpu/exec_module.cc +++ b/src/cpu/exec_module.cc @@ -31,6 +31,7 @@ #include #include +#include "cpu/cpu-private.h" #include "cpu/xethunk/xethunk.h" @@ -67,6 +68,8 @@ int ExecModule::Prepare() { int result_code = 1; std::string error_message; + char file_name[2048]; + OwningPtr shared_module_buffer; auto_ptr shared_module; auto_ptr outs; @@ -80,7 +83,7 @@ int ExecModule::Prepare() { // Calculate a cache path based on the module, the CPU version, and other // bits. // TODO(benvanik): cache path calculation. - const char *cache_path = "build/generated.bc"; + //const char *cache_path = "build/generated.bc"; // Check the cache to see if the bitcode exists. // If it does, load that module directly. In the future we could also cache @@ -104,6 +107,13 @@ int ExecModule::Prepare() { // Analyze the module and add its symbols to the symbol database. XEEXPECTZERO(sdb_->Analyze()); + // Dump the symbol database. + if (FLAGS_dump_module_map) { + xesnprintf(file_name, XECOUNT(file_name), + "%s%s.map", FLAGS_dump_path.c_str(), module_->name()); + sdb_->Write(file_name); + } + // Initialize the module. gen_module_ = shared_ptr( new Module(module_->name(), *context_.get())); @@ -126,13 +136,18 @@ int ExecModule::Prepare() { context_.get(), gen_module_.get())); XEEXPECTZERO(codegen_->Generate()); - gen_module_->dump(); - // Write to cache. - outs = auto_ptr(new raw_fd_ostream( - cache_path, error_message, raw_fd_ostream::F_Binary)); - XEEXPECTTRUE(error_message.empty()); - WriteBitcodeToFile(gen_module_.get(), *outs); + // TODO(benvanik): cache stuff + + // Dump pre-optimized module to disk. + if (FLAGS_dump_module_bitcode) { + xesnprintf(file_name, XECOUNT(file_name), + "%s%s-preopt.bc", FLAGS_dump_path.c_str(), module_->name()); + outs = auto_ptr(new raw_fd_ostream( + file_name, error_message, raw_fd_ostream::F_Binary)); + XEEXPECTTRUE(error_message.empty()); + WriteBitcodeToFile(gen_module_.get(), *outs); + } } // Link optimizations. @@ -143,19 +158,29 @@ int ExecModule::Prepare() { // Run full module optimizations. pm.add(new DataLayout(gen_module_.get())); -#if XE_OPTION(OPTIMIZED) - pm.add(createVerifierPass()); - pmb.OptLevel = 3; - pmb.SizeLevel = 0; - pmb.Inliner = createFunctionInliningPass(); - pmb.Vectorize = true; - pmb.LoopVectorize = true; - pmb.populateModulePassManager(pm); - pmb.populateLTOPassManager(pm, false, true); -#endif // XE_OPTION(OPTIMIZED) + if (FLAGS_optimize_ir_modules) { + pm.add(createVerifierPass()); + pmb.OptLevel = 3; + pmb.SizeLevel = 0; + pmb.Inliner = createFunctionInliningPass(); + pmb.Vectorize = true; + pmb.LoopVectorize = true; + pmb.populateModulePassManager(pm); + pmb.populateLTOPassManager(pm, false, true); + } pm.add(createVerifierPass()); pm.run(*gen_module_); + // Dump post-optimized module to disk. + if (FLAGS_optimize_ir_modules && FLAGS_dump_module_bitcode) { + xesnprintf(file_name, XECOUNT(file_name), + "%s%s.bc", FLAGS_dump_path.c_str(), module_->name()); + outs = auto_ptr(new raw_fd_ostream( + file_name, error_message, raw_fd_ostream::F_Binary)); + XEEXPECTTRUE(error_message.empty()); + WriteBitcodeToFile(gen_module_.get(), *outs); + } + // TODO(benvanik): experiment with LLD to see if we can write out a dll. // Initialize the module. @@ -225,6 +250,6 @@ int ExecModule::Uninit() { } void ExecModule::Dump() { - // sdb_->Dump(); - // gen_module_->dump(); + sdb_->Dump(); + gen_module_->dump(); } diff --git a/src/cpu/sdb.cc b/src/cpu/sdb.cc index 93fc778ee..629c9a02a 100644 --- a/src/cpu/sdb.cc +++ b/src/cpu/sdb.cc @@ -241,6 +241,10 @@ int SymbolDatabase::GetAllFunctions(vector& functions) { return 0; } +void SymbolDatabase::Write(const char* file_name) { + // TODO(benvanik): write to file. +} + void SymbolDatabase::Dump() { uint32_t previous = 0; for (SymbolMap::iterator it = symbols_.begin(); it != symbols_.end(); ++it) { diff --git a/src/cpu/sources.gypi b/src/cpu/sources.gypi index e604f7cac..6aa30e68d 100644 --- a/src/cpu/sources.gypi +++ b/src/cpu/sources.gypi @@ -1,6 +1,7 @@ # Copyright 2013 Ben Vanik. All Rights Reserved. { 'sources': [ + 'cpu.cc', 'exec_module.cc', 'processor.cc', 'sdb.cc', diff --git a/third_party/gflags b/third_party/gflags new file mode 160000 index 000000000..56e77c6a2 --- /dev/null +++ b/third_party/gflags @@ -0,0 +1 @@ +Subproject commit 56e77c6a2f10020f775cb68022f92fbb38e61804 diff --git a/third_party/gflags.gypi b/third_party/gflags.gypi new file mode 100644 index 000000000..9a511fd72 --- /dev/null +++ b/third_party/gflags.gypi @@ -0,0 +1,34 @@ +# Copyright 2013 Ben Vanik. All Rights Reserved. +{ + 'targets': [ + { + 'target_name': 'gflags', + 'type': 'static_library', + + 'direct_dependent_settings': { + 'include_dirs': [ + 'gflags/src/', + ], + }, + + 'include_dirs': [ + 'gflags/src/', + ], + + 'sources': [ + 'gflags/src/gflags.cc', + 'gflags/src/gflags_completions.cc', + 'gflags/src/gflags_nc.cc', + 'gflags/src/gflags_reporting.cc', + ], + + 'conditions': [ + ['OS == "win"', { + 'sources!': [ + 'gflags/src/windows/port.cc', + ], + }], + ], + } + ] +} diff --git a/tools/xenia-info/xenia-info.cc b/tools/xenia-info/xenia-info.cc index 7337ed70a..742c8bf80 100644 --- a/tools/xenia-info/xenia-info.cc +++ b/tools/xenia-info/xenia-info.cc @@ -9,6 +9,8 @@ #include +#include + using namespace xe; using namespace xe::cpu; @@ -16,6 +18,12 @@ using namespace xe::kernel; int xenia_info(int argc, xechar_t **argv) { + std::string usage = "usage: "; + usage = usage + argv[0] + " some.xex"; + google::SetUsageMessage(usage); + google::SetVersionString("1.0"); + google::ParseCommandLineFlags(&argc, &argv, true); + int result_code = 1; xe_pal_ref pal = NULL; @@ -23,9 +31,9 @@ int xenia_info(int argc, xechar_t **argv) { shared_ptr processor; shared_ptr runtime; - // TODO(benvanik): real command line parsing. + // Grab path. if (argc < 2) { - printf("usage: xenia-info some.xex\n"); + google::ShowUsageWithFlags(argv[0]); return 1; } const xechar_t *path = argv[1]; @@ -51,6 +59,8 @@ int xenia_info(int argc, xechar_t **argv) { XECLEANUP: xe_memory_release(memory); xe_pal_release(pal); + + google::ShutDownCommandLineFlags(); return result_code; } XE_MAIN_THUNK(xenia_info); diff --git a/tools/xenia-run/xenia-run.cc b/tools/xenia-run/xenia-run.cc index 0ef8cda1c..56eeb4c34 100644 --- a/tools/xenia-run/xenia-run.cc +++ b/tools/xenia-run/xenia-run.cc @@ -9,6 +9,8 @@ #include +#include + using namespace xe; using namespace xe::cpu; @@ -70,14 +72,20 @@ int Run::Launch() { } int xenia_run(int argc, xechar_t **argv) { + std::string usage = "usage: "; + usage = usage + argv[0] + " some.xex"; + google::SetUsageMessage(usage); + google::SetVersionString("1.0"); + google::ParseCommandLineFlags(&argc, &argv, true); + // Dummy call to keep the GPU code linking in to ensure it's working. do_gpu_stuff(); int result_code = 1; - // TODO(benvanik): real command line parsing. + // Grab path. if (argc < 2) { - printf("usage: xenia-run some.xex\n"); + google::ShowUsageWithFlags(argv[0]); return 1; } const xechar_t *path = argv[1]; @@ -91,9 +99,10 @@ int xenia_run(int argc, xechar_t **argv) { run->Launch(); - return 0; - + result_code = 0; XECLEANUP: + + google::ShutDownCommandLineFlags(); return result_code; } XE_MAIN_THUNK(xenia_run); diff --git a/xenia.gyp b/xenia.gyp index c66e8d514..66ba61203 100644 --- a/xenia.gyp +++ b/xenia.gyp @@ -3,6 +3,7 @@ 'includes': [ 'common.gypi', 'tools/tools.gypi', + 'third_party/gflags.gypi', ], 'targets': [ @@ -11,6 +12,13 @@ 'product_name': 'xeniacore', 'type': 'static_library', + 'dependencies': [ + 'gflags', + ], + 'export_dependent_settings': [ + 'gflags', + ], + 'direct_dependent_settings': { 'include_dirs': [ 'include/', @@ -36,7 +44,6 @@ 'dependencies': [ 'xeniacore', ], - 'export_dependent_settings': [ 'xeniacore', ],