Object generation skeleton

This commit is contained in:
Dani Messerman 2015-04-26 23:56:18 +03:00
parent ba0bfe7d82
commit 5c27161b23
14 changed files with 295 additions and 2 deletions

View File

@ -192,4 +192,12 @@ if(ENABLE_QT)
include_directories(externals/qhexedit) include_directories(externals/qhexedit)
add_subdirectory(externals/qhexedit) add_subdirectory(externals/qhexedit)
endif() endif()
option(ENABLE_BINARY_TRANSLATION "Enable binary translation. Requires LLVM" OFF)
if(ENABLE_BINARY_TRANSLATION)
find_package(LLVM REQUIRED CONFIG)
include_directories(${LLVM_INCLUDE_DIRS})
add_definitions(${LLVM_DEFINITIONS})
llvm_map_components_to_libnames(llvm_libs Core Support X86 Arm ArmCodeGen ArmAsmParser ArmAsmPrinter ArmDisassembler ExecutionEngine MCJIT BitWriter ipo)
endif()
add_subdirectory(src) add_subdirectory(src)

2
externals/nihstro vendored

@ -1 +1 @@
Subproject commit 81f1804a43f625e3a1a20752c0db70a413410380 Subproject commit 4a78588b308564f7ebae193e0ae00d9a0d5741d5

View File

@ -10,3 +10,6 @@ endif()
if (ENABLE_QT) if (ENABLE_QT)
add_subdirectory(citra_qt) add_subdirectory(citra_qt)
endif() endif()
if(ENABLE_BINARY_TRANSLATION)
add_subdirectory(binary_translation)
endif()

View File

@ -0,0 +1,15 @@
set(SRCS
main.cpp
CodeGen.cpp
)
set(HEADERS
CodeGen.h
)
create_directory_groups(${SRCS} ${HEADERS})
add_executable(binary_translate ${SRCS} ${HEADERS})
target_link_libraries(binary_translate ${llvm_libs})
target_link_libraries(binary_translate core common video_core)
target_link_libraries(binary_translate ${GLFW_LIBRARIES} ${OPENGL_gl_LIBRARY} inih)
target_link_libraries(binary_translate ${PLATFORM_LIBRARIES})

View File

@ -0,0 +1,162 @@
#include "CodeGen.h"
#include "core/loader/loader.h"
#include <llvm/Support/TargetSelect.h>
#include <llvm/Support/Host.h>
#include <llvm/Target/TargetSubtargetInfo.h>
#include <llvm/ExecutionEngine/ExecutionEngine.h>
#include <llvm/IR/LLVMContext.h>
#include <llvm/Support/raw_os_ostream.h>
#include <llvm/PassManager.h>
#include <llvm/IR/Verifier.h>
#include <llvm/Target/TargetLibraryInfo.h>
#include <llvm/Transforms/IPO/PassManagerBuilder.h>
#include <llvm/Transforms/IPO.h>
#include <iostream>
using namespace llvm;
CodeGen::CodeGen(const char* output_object_filename, const char* output_debug_filename)
: output_object_filename(output_object_filename),
output_debug_filename(output_debug_filename)
{
}
CodeGen::~CodeGen()
{
}
void CodeGen::Run()
{
if (!Loader::ROMCodeStart)
{
LOG_CRITICAL(BinaryTranslator, "No information from the loader about ROM file.");
return;
}
IntializeLLVM();
GenerateModule();
GenerateDebugFiles();
if (!Verify()) return;
OptimizeAndGenerate();
}
void CodeGen::IntializeLLVM()
{
InitializeNativeTarget();
InitializeNativeTargetAsmPrinter();
auto triple_string = sys::getProcessTriple();
#ifdef _WIN32
// LLVM doesn't know how to load coff files
// It can handle elf files in every platform
triple_string += "-elf";
#endif
triple = llvm::make_unique<Triple>(triple_string);
// This engine builder is needed to get the target machine. It requires a module
// but takes ownership of it so the main module cannot be passed here.
EngineBuilder engine_builder(make_unique<Module>("", getGlobalContext()));
target_machine.reset(engine_builder.selectTarget(*triple, "", "", SmallVector<std::string, 0>()));
module = make_unique<Module>("Module", getGlobalContext());
module->setTargetTriple(triple_string);
ir_builder = make_unique<IRBuilder<>>(getGlobalContext());
}
void CodeGen::GenerateModule()
{
// TODO:
}
void CodeGen::GenerateDebugFiles()
{
if (!output_debug_filename) return;
LOG_INFO(BinaryTranslator, "Writing debug file");
std::ofstream file(output_debug_filename);
if (!file)
{
LOG_ERROR(BinaryTranslator, "Cannot create debug file: %s", output_debug_filename);
return;
}
raw_os_ostream stream(file);
module->print(stream, nullptr);
file.close();
LOG_INFO(BinaryTranslator, "Done");
}
bool CodeGen::Verify()
{
LOG_INFO(BinaryTranslator, "Verifying");
raw_os_ostream os(std::cout);
if (verifyModule(*module, &os))
{
LOG_CRITICAL(BinaryTranslator, "Verify failed");
return false;
}
LOG_INFO(BinaryTranslator, "Done");
return true;
}
void CodeGen::OptimizeAndGenerate()
{
/*
* Taken from opt for O3
*/
PassManagerBuilder pass_manager_builder;
FunctionPassManager function_pass_manager(module.get());
module->setDataLayout(target_machine->getSubtargetImpl()->getDataLayout());
function_pass_manager.add(new DataLayoutPass());
target_machine->addAnalysisPasses(function_pass_manager);
pass_manager_builder.OptLevel = 3;
pass_manager_builder.SizeLevel = 0;
pass_manager_builder.Inliner = createFunctionInliningPass(3, 0);
pass_manager_builder.LoopVectorize = true;
pass_manager_builder.SLPVectorize = true;
pass_manager_builder.populateFunctionPassManager(function_pass_manager);
LOG_INFO(BinaryTranslator, "Optimizing functions");
function_pass_manager.doInitialization();
for (auto &function : *module)
function_pass_manager.run(function);
function_pass_manager.doFinalization();
LOG_INFO(BinaryTranslator, "Done");
PassManager pass_manager;
pass_manager.add(createVerifierPass());
pass_manager.add(new TargetLibraryInfo(*triple));
pass_manager.add(new DataLayoutPass());
target_machine->addAnalysisPasses(pass_manager);
pass_manager_builder.populateModulePassManager(pass_manager);
pass_manager.add(createVerifierPass());
LOG_INFO(BinaryTranslator, "Optimizing module");
pass_manager.run(*module);
LOG_INFO(BinaryTranslator, "Done");
MCContext *context;
std::ofstream file(output_object_filename, std::ios::binary);
if (!file)
{
LOG_CRITICAL(BinaryTranslator, "Cannot create object file: %s", output_object_filename);
return;
}
raw_os_ostream stream(file);
if (target_machine->addPassesToEmitMC(pass_manager, context, stream, false))
{
LOG_CRITICAL(BinaryTranslator, "Target does not support MC emission!");
return;
}
LOG_INFO(BinaryTranslator, "Generating code");
pass_manager.run(*module);
file.close();
LOG_INFO(BinaryTranslator, "Done");
}

View File

@ -0,0 +1,33 @@
#include <memory>
#include <llvm/IR/IRBuilder.h>
namespace llvm
{
class TargetMachine;
class Module;
}
/*
* Holds alls the basic llvm structures
*/
class CodeGen
{
public:
CodeGen(const char *output_object_filename, const char *output_debug_filename);
~CodeGen();
void Run();
void IntializeLLVM();
void GenerateModule();
void GenerateDebugFiles();
bool Verify();
void OptimizeAndGenerate();
private:
const char *output_object_filename;
const char *output_debug_filename;
std::unique_ptr<llvm::Triple> triple;
std::unique_ptr<llvm::TargetMachine> target_machine;
std::unique_ptr<llvm::Module> module;
std::unique_ptr<llvm::IRBuilder<>> ir_builder;
};

View File

@ -0,0 +1,42 @@
#include "common/logging/backend.h"
#include "common/logging/text_formatter.h"
#include "common/scope_exit.h"
#include "core/core.h"
#include "core/mem_map.h"
#include "core/loader/loader.h"
#include "codegen.h"
int main(int argc, const char *const *argv)
{
std::shared_ptr<Log::Logger> logger = Log::InitGlobalLogger();
Log::Filter log_filter(Log::Level::Debug);
Log::SetFilter(&log_filter);
std::thread logging_thread(Log::TextLoggingLoop, logger);
SCOPE_EXIT({
logger->Close();
logging_thread.join();
});
if (argc < 3)
{
LOG_CRITICAL(BinaryTranslator, "Usage: binary_translate <input_rom> <output_object> [<output_debug>]");
return -1;
}
auto input_rom = argv[1];
auto output_object = argv[2];
auto output_debug = argc > 3 ? argv[3] : nullptr;
Core::Init();
Memory::Init();
auto load_result = Loader::LoadFile(input_rom);
if (Loader::ResultStatus::Success != load_result)
{
LOG_CRITICAL(BinaryTranslator, "Failed to load ROM (Error %i)!", load_result);
return -1;
}
CodeGen code_generator(output_object, output_debug);
code_generator.Run();
}

View File

@ -72,5 +72,8 @@ endif()
target_link_libraries(citra-qt core common video_core qhexedit) target_link_libraries(citra-qt core common video_core qhexedit)
target_link_libraries(citra-qt ${OPENGL_gl_LIBRARY} ${CITRA_QT_LIBS}) target_link_libraries(citra-qt ${OPENGL_gl_LIBRARY} ${CITRA_QT_LIBS})
target_link_libraries(citra-qt ${PLATFORM_LIBRARIES}) target_link_libraries(citra-qt ${PLATFORM_LIBRARIES})
if(ENABLE_BINARY_TRANSLATION)
target_link_libraries(citra-qt ${llvm_libs})
endif()
#install(TARGETS citra-qt RUNTIME DESTINATION ${bindir}) #install(TARGETS citra-qt RUNTIME DESTINATION ${bindir})

View File

@ -53,7 +53,8 @@ static std::shared_ptr<Logger> global_logger;
CLS(Render) \ CLS(Render) \
SUB(Render, Software) \ SUB(Render, Software) \
SUB(Render, OpenGL) \ SUB(Render, OpenGL) \
CLS(Loader) CLS(Loader) \
CLS(BinaryTranslator)
Logger::Logger() { Logger::Logger() {
// Register logging classes so that they can be queried at runtime // Register logging classes so that they can be queried at runtime

View File

@ -74,6 +74,7 @@ enum class Class : ClassType {
Render_Software, ///< Software renderer backend Render_Software, ///< Software renderer backend
Render_OpenGL, ///< OpenGL backend Render_OpenGL, ///< OpenGL backend
Loader, ///< ROM loader Loader, ///< ROM loader
BinaryTranslator, ///< Binary translator
Count ///< Total number of logging classes Count ///< Total number of logging classes
}; };

View File

@ -13,6 +13,7 @@
#include "core/loader/elf.h" #include "core/loader/elf.h"
#include "core/loader/ncch.h" #include "core/loader/ncch.h"
#include "core/mem_map.h" #include "core/mem_map.h"
#include "core/loader/loader.h"
#include "3dsx.h" #include "3dsx.h"
@ -203,6 +204,11 @@ static THREEDSX_Error Load3DSXFile(FileUtil::IOFile& file, u32 base_addr)
// Write the data // Write the data
memcpy(Memory::GetPointer(base_addr), &all_mem[0], loadinfo.seg_sizes[0] + loadinfo.seg_sizes[1] + loadinfo.seg_sizes[2]); memcpy(Memory::GetPointer(base_addr), &all_mem[0], loadinfo.seg_sizes[0] + loadinfo.seg_sizes[1] + loadinfo.seg_sizes[2]);
Loader::ROMCodeStart = base_addr;
Loader::ROMCodeSize = loadinfo.seg_sizes[0];
Loader::ROMReadOnlyDataStart = base_addr + loadinfo.seg_sizes[0];
Loader::ROMReadOnlyDataSize = loadinfo.seg_sizes[1];
LOG_DEBUG(Loader, "CODE: %u pages\n", loadinfo.seg_sizes[0] / 0x1000); LOG_DEBUG(Loader, "CODE: %u pages\n", loadinfo.seg_sizes[0] / 0x1000);
LOG_DEBUG(Loader, "RODATA: %u pages\n", loadinfo.seg_sizes[1] / 0x1000); LOG_DEBUG(Loader, "RODATA: %u pages\n", loadinfo.seg_sizes[1] / 0x1000);
LOG_DEBUG(Loader, "DATA: %u pages\n", data_load_size / 0x1000); LOG_DEBUG(Loader, "DATA: %u pages\n", data_load_size / 0x1000);

View File

@ -24,6 +24,10 @@ const std::initializer_list<Kernel::AddressMapping> default_address_mappings = {
{ 0x1FF70000, 0x8000, true }, // part of DSP RAM { 0x1FF70000, 0x8000, true }, // part of DSP RAM
{ 0x1F000000, 0x600000, false }, // entire VRAM { 0x1F000000, 0x600000, false }, // entire VRAM
}; };
u32 ROMCodeStart = 0;
u32 ROMCodeSize = 0;
u32 ROMReadOnlyDataStart = 0;
u32 ROMReadOnlyDataSize = 0;
/** /**
* Identifies the type of a bootable file * Identifies the type of a bootable file

View File

@ -118,4 +118,12 @@ extern const std::initializer_list<Kernel::AddressMapping> default_address_mappi
*/ */
ResultStatus LoadFile(const std::string& filename); ResultStatus LoadFile(const std::string& filename);
/*
* Infomation about ROM
*/
extern u32 ROMCodeStart;
extern u32 ROMCodeSize;
extern u32 ROMReadOnlyDataStart;
extern u32 ROMReadOnlyDataSize;
} // namespace } // namespace

View File

@ -136,6 +136,13 @@ ResultStatus AppLoader_NCCH::LoadExec() const {
s32 priority = exheader_header.arm11_system_local_caps.priority; s32 priority = exheader_header.arm11_system_local_caps.priority;
u32 stack_size = exheader_header.codeset_info.stack_size; u32 stack_size = exheader_header.codeset_info.stack_size;
Kernel::g_current_process->Run(entry_point, priority, stack_size); Kernel::g_current_process->Run(entry_point, priority, stack_size);
Loader::ROMCodeStart = entry_point;
Loader::ROMCodeSize = entry_point + code.size();
// TODO: Don't know where these are
Loader::ROMReadOnlyDataStart = 0;
Loader::ROMReadOnlyDataSize = 0;
return ResultStatus::Success; return ResultStatus::Success;
} }
return ResultStatus::Error; return ResultStatus::Error;