From 55ae691337f0685bd27703fe88c7b89c65254b4c Mon Sep 17 00:00:00 2001 From: Jacob Lifshay Date: Fri, 28 Jul 2017 07:40:13 -0700 Subject: [PATCH] added per-function target attributes --- CMakeLists.txt | 4 +- src/demo/demo.cpp | 10 +++- src/llvm_wrapper/CMakeLists.txt | 2 +- src/llvm_wrapper/llvm_wrapper.cpp | 87 +++++++++++++++++++++++---- src/llvm_wrapper/llvm_wrapper.h | 92 +++++++++++++++++++++++++++-- src/spirv_to_llvm/spirv_to_llvm.cpp | 23 +++++--- src/spirv_to_llvm/spirv_to_llvm.h | 1 + 7 files changed, 189 insertions(+), 30 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index ab3670d..4c264eb 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -32,8 +32,8 @@ if(NOT ${CMAKE_C_COMPILER_ID} MATCHES "Clang") endif() find_package(LLVM REQUIRED CONFIG) -if(LLVM_PACKAGE_VERSION VERSION_LESS 3.8) - message(FATAL_ERROR "unsupported version of llvm; requires version 3.8 or greater") +if(LLVM_PACKAGE_VERSION VERSION_LESS 4.0) + message(FATAL_ERROR "unsupported version of llvm; requires version 4.0 or greater") endif() if(NOT LLVM_ENABLE_THREADS) message(FATAL_ERROR "llvm was not built multi-threaded") diff --git a/src/demo/demo.cpp b/src/demo/demo.cpp index 13bcec5..2c7ee72 100644 --- a/src/demo/demo.cpp +++ b/src/demo/demo.cpp @@ -235,12 +235,17 @@ int test_main(int argc, char **argv) } std::cerr << dump_callbacks.ss.str() << std::endl; } + auto llvm_target_machine = llvm_wrapper::Target_machine::create_native_target_machine(); auto llvm_context = llvm_wrapper::Context::create(); std::uint64_t next_module_id = 1; spirv_to_llvm::Converted_module converted_module; try { - converted_module = spirv_to_llvm::spirv_to_llvm(llvm_context.get(), file->data(), file->size(), next_module_id++); + converted_module = spirv_to_llvm::spirv_to_llvm(llvm_context.get(), + llvm_target_machine.get(), + file->data(), + file->size(), + next_module_id++); } catch(spirv::Parser_error &e) { @@ -249,7 +254,8 @@ int test_main(int argc, char **argv) } std::cerr << "Translation to LLVM succeeded." << std::endl; ::LLVMDumpModule(converted_module.module.get()); - bool failed = ::LLVMVerifyModule(converted_module.module.get(), ::LLVMPrintMessageAction, nullptr); + bool failed = + ::LLVMVerifyModule(converted_module.module.get(), ::LLVMPrintMessageAction, nullptr); if(failed) return 1; } diff --git a/src/llvm_wrapper/CMakeLists.txt b/src/llvm_wrapper/CMakeLists.txt index 4934770..a5ea642 100644 --- a/src/llvm_wrapper/CMakeLists.txt +++ b/src/llvm_wrapper/CMakeLists.txt @@ -22,7 +22,7 @@ cmake_minimum_required(VERSION 3.1 FATAL_ERROR) set(sources llvm_wrapper.cpp) add_library(llvm_wrapper STATIC ${sources}) -if(0) +if(1) llvm_map_components_to_libnames(llvm_libraries core mcjit native analysis) else() set(llvm_libraries LLVM) diff --git a/src/llvm_wrapper/llvm_wrapper.cpp b/src/llvm_wrapper/llvm_wrapper.cpp index e7f6098..881b5bd 100644 --- a/src/llvm_wrapper/llvm_wrapper.cpp +++ b/src/llvm_wrapper/llvm_wrapper.cpp @@ -22,52 +22,61 @@ */ #include "llvm_wrapper.h" #include +#include #include #include #include +#include namespace vulkan_cpu { namespace llvm_wrapper { -Context Context::create() +void Context::init_helper() { if(!::LLVMIsMultithreaded()) throw std::runtime_error("LLVM is not multithreaded"); ::LLVMLinkInMCJIT(); if(::LLVMInitializeNativeTarget() != 0) throw std::runtime_error("LLVMInitializeNativeTarget failed"); - return Context(::LLVMContextCreate()); } LLVM_string Target::get_process_target_triple() { + Context::init(); return LLVM_string::from(llvm::sys::getProcessTriple()); } LLVM_string Target::get_host_cpu_name() { + Context::init(); return LLVM_string::from(llvm::sys::getHostCPUName()); } LLVM_string Target::get_host_cpu_features() { + Context::init(); llvm::StringMap features{}; if(!llvm::sys::getHostCPUFeatures(features)) return LLVM_string::from(""); std::string retval; - bool first = true; + std::vector names; + names.reserve(features.size()); for(auto &entry : features) + names.push_back(entry.first()); + std::sort(names.begin(), names.end()); + bool first = true; + for(auto &name : names) { if(first) first = false; else retval += ','; - if(entry.second) + if(features[name]) retval += '+'; else retval += '-'; - retval += entry.first(); + retval += name; } return LLVM_string::from(retval); } @@ -84,12 +93,70 @@ Target_machine Target_machine::create_native_target_machine() ::LLVMCodeModelJITDefault)); } -void Module::set_target_to_native(::LLVMModuleRef module) +void Module::set_target_machine(::LLVMModuleRef module, ::LLVMTargetMachineRef target_machine) +{ + ::LLVMSetTarget(module, Target_machine::get_target_triple(target_machine).get()); + ::LLVMSetModuleDataLayout(module, + Target_machine::create_target_data_layout(target_machine).get()); +} + +void Module::set_function_target_machine(::LLVMValueRef function, + ::LLVMTargetMachineRef target_machine) +{ + ::LLVMAddTargetDependentFunctionAttr( + function, "target-cpu", Target_machine::get_cpu(target_machine).get()); + ::LLVMAddTargetDependentFunctionAttr( + function, "target-features", Target_machine::get_feature_string(target_machine).get()); +} + +Shared_memory_manager Shared_memory_manager::create() { - auto target_machine = Target_machine::create_native_target_machine(); - ::LLVMSetTarget(module, target_machine.get_target_triple().get()); - auto target_data_string = target_machine.create_target_data_layout().to_string(); - ::LLVMSetModuleDataLayout(module, target_machine.create_target_data_layout().get()); + Context::init(); + auto memory_manager = std::make_shared(); + std::unique_ptr> memory_manager_wrapper; + memory_manager_wrapper.reset(new std::shared_ptr(memory_manager)); + MCJIT_memory_manager mcjit_memory_manager(::LLVMCreateSimpleMCJITMemoryManager( + static_cast(memory_manager_wrapper.get()), + [](void *user_data, + std::uintptr_t size, + unsigned alignment, + unsigned section_id, + const char *section_name) -> std::uint8_t * + { + auto &memory_manager = + *static_cast *>(user_data); + return memory_manager->allocateCodeSection(size, alignment, section_id, section_name); + }, + [](void *user_data, + std::uintptr_t size, + unsigned alignment, + unsigned section_id, + const char *section_name, + LLVMBool is_read_only) -> std::uint8_t * + { + auto &memory_manager = + *static_cast *>(user_data); + return memory_manager->allocateDataSection( + size, alignment, section_id, section_name, is_read_only); + }, + [](void *user_data, char **error_message_out) -> LLVMBool + { + auto &memory_manager = + *static_cast *>(user_data); + if(!error_message_out) + return memory_manager->finalizeMemory(nullptr); + std::string error_message; + bool failed = memory_manager->finalizeMemory(&error_message); + if(failed) + *error_message_out = LLVM_string::from(error_message).release(); + return failed; + }, + [](void *user_data) noexcept + { + delete static_cast *>(user_data); + })); + memory_manager_wrapper.release(); + return Shared_memory_manager(std::move(mcjit_memory_manager), std::move(memory_manager)); } } } diff --git a/src/llvm_wrapper/llvm_wrapper.h b/src/llvm_wrapper/llvm_wrapper.h index 7457c7d..745f1c3 100644 --- a/src/llvm_wrapper/llvm_wrapper.h +++ b/src/llvm_wrapper/llvm_wrapper.h @@ -157,7 +157,21 @@ struct Context_deleter struct Context : public Wrapper<::LLVMContextRef, Context_deleter> { using Wrapper::Wrapper; - static Context create(); + +private: + static void init_helper(); + +public: + static void init() + { + static int v = (init_helper(), 0); + static_cast(v); + } + static Context create() + { + init(); + return Context(::LLVMContextCreate()); + } }; struct Target_deleter @@ -173,6 +187,7 @@ struct Target : public Wrapper<::LLVMTargetRef, Target_deleter> using Wrapper::Wrapper; static LLVM_string get_default_target_triple() { + Context::init(); return LLVM_string::wrap(::LLVMGetDefaultTargetTriple()); } static LLVM_string get_process_target_triple(); @@ -181,6 +196,7 @@ struct Target : public Wrapper<::LLVMTargetRef, Target_deleter> typedef util::variant Target_or_error_message; static Target_or_error_message get_target_from_target_triple(const char *triple) { + Context::init(); ::LLVMTargetRef target = nullptr; char *error_message = nullptr; if(::LLVMGetTargetFromTriple(triple, &target, &error_message) == 0) @@ -189,6 +205,7 @@ struct Target : public Wrapper<::LLVMTargetRef, Target_deleter> } static Target get_native_target() { + Context::init(); auto native_triple = get_process_target_triple(); auto retval = get_target_from_target_triple(native_triple.get()); auto *target = util::get_if(&retval); @@ -261,6 +278,22 @@ struct Target_machine : public Wrapper<::LLVMTargetMachineRef, Target_machine_de { return create_target_data_layout(get()); } + static LLVM_string get_cpu(::LLVMTargetMachineRef tm) + { + return LLVM_string::wrap(::LLVMGetTargetMachineCPU(tm)); + } + LLVM_string get_cpu() const + { + return get_cpu(get()); + } + static LLVM_string get_feature_string(::LLVMTargetMachineRef tm) + { + return LLVM_string::wrap(::LLVMGetTargetMachineFeatureString(tm)); + } + LLVM_string get_feature_string() const + { + return get_feature_string(get()); + } }; struct Module_deleter @@ -278,16 +311,20 @@ struct Module : public Wrapper<::LLVMModuleRef, Module_deleter> { return Module(::LLVMModuleCreateWithNameInContext(id, context)); } - static Module create_native(const char *id, ::LLVMContextRef context) + static Module create_with_target_machine(const char *id, + ::LLVMContextRef context, + ::LLVMTargetMachineRef target_machine) { Module retval = create(id, context); - retval.set_target_to_native(); + retval.set_target_machine(target_machine); return retval; } - static void set_target_to_native(::LLVMModuleRef module); - void set_target_to_native() + static void set_target_machine(::LLVMModuleRef module, ::LLVMTargetMachineRef target_machine); + static void set_function_target_machine(::LLVMValueRef function, + ::LLVMTargetMachineRef target_machine); + void set_target_machine(::LLVMTargetMachineRef target_machine) { - set_target_to_native(get()); + set_target_machine(get(), target_machine); } }; @@ -319,6 +356,49 @@ inline ::LLVMTypeRef get_scalar_or_vector_element_type(::LLVMTypeRef type) return ::LLVMGetElementType(type); return type; } + +struct MCJIT_memory_manager_deleter +{ + void operator()(::LLVMMCJITMemoryManagerRef v) noexcept + { + ::LLVMDisposeMCJITMemoryManager(v); + } +}; + +struct MCJIT_memory_manager + : public Wrapper<::LLVMMCJITMemoryManagerRef, MCJIT_memory_manager_deleter> +{ + using Wrapper::Wrapper; +}; + +struct Shared_memory_manager +{ + MCJIT_memory_manager mcjit_memory_manager; + std::shared_ptr shared_memory_manager; + explicit Shared_memory_manager(MCJIT_memory_manager mcjit_memory_manager, + std::shared_ptr shared_memory_manager) noexcept + : mcjit_memory_manager(std::move(mcjit_memory_manager)), + shared_memory_manager(std::move(shared_memory_manager)) + { + } + Shared_memory_manager() noexcept + { + } + static Shared_memory_manager create(); +}; + +struct Execution_engine_deleter +{ + void operator()(::LLVMExecutionEngineRef v) noexcept + { + ::LLVMDisposeExecutionEngine(v); + } +}; + +struct Execution_engine : public Wrapper<::LLVMExecutionEngineRef, Execution_engine_deleter> +{ + using Wrapper::Wrapper; +}; } } diff --git a/src/spirv_to_llvm/spirv_to_llvm.cpp b/src/spirv_to_llvm/spirv_to_llvm.cpp index c1257f9..40dedfb 100644 --- a/src/spirv_to_llvm/spirv_to_llvm.cpp +++ b/src/spirv_to_llvm/spirv_to_llvm.cpp @@ -613,6 +613,7 @@ private: Word input_generator_magic_number = 0; util::Enum_set enabled_capabilities; ::LLVMContextRef context; + ::LLVMTargetMachineRef target_machine; [[gnu::unused]] const std::uint64_t shader_id; std::string name_prefix_string; llvm_wrapper::Module module; @@ -674,15 +675,18 @@ private: } public: - explicit Spirv_to_llvm(::LLVMContextRef context, std::uint64_t shader_id) - : context(context), shader_id(shader_id), stage() + explicit Spirv_to_llvm(::LLVMContextRef context, + ::LLVMTargetMachineRef target_machine, + std::uint64_t shader_id) + : context(context), target_machine(target_machine), shader_id(shader_id), stage() { { std::ostringstream ss; ss << "shader_" << shader_id << "_"; name_prefix_string = ss.str(); } - module = llvm_wrapper::Module::create_native(get_prefixed_name("module").c_str(), context); + module = llvm_wrapper::Module::create_with_target_machine( + get_prefixed_name("module").c_str(), context, target_machine); builder = llvm_wrapper::Builder::create(context); auto target_data = ::LLVMGetModuleDataLayout(module.get()); constexpr std::size_t no_instruction_index = 0; @@ -2706,11 +2710,11 @@ void Spirv_to_llvm::handle_instruction_op_function(Op_function instruction, + std::string(get_enumerant_name(instruction.get_operation()))); auto function_type = get_type(instruction.function_type, instruction_start_index); - state.function = Function_state( - function_type, - ::LLVMAddFunction(module.get(), - get_prefixed_name(get_name(current_function_id)).c_str(), - function_type->get_or_make_type())); + auto function = ::LLVMAddFunction(module.get(), + get_prefixed_name(get_name(current_function_id)).c_str(), + function_type->get_or_make_type()); + llvm_wrapper::Module::set_function_target_machine(function, target_machine); + state.function = Function_state(function_type, function); break; } } @@ -8588,11 +8592,12 @@ void Spirv_to_llvm::handle_instruction_glsl_std_450_op_n_clamp(Glsl_std_450_op_n } Converted_module spirv_to_llvm(::LLVMContextRef context, + ::LLVMTargetMachineRef target_machine, const Word *shader_words, std::size_t shader_size, std::uint64_t shader_id) { - return Spirv_to_llvm(context, shader_id).run(shader_words, shader_size); + return Spirv_to_llvm(context, target_machine, shader_id).run(shader_words, shader_size); } } } diff --git a/src/spirv_to_llvm/spirv_to_llvm.h b/src/spirv_to_llvm/spirv_to_llvm.h index 5bc229a..4888d7d 100644 --- a/src/spirv_to_llvm/spirv_to_llvm.h +++ b/src/spirv_to_llvm/spirv_to_llvm.h @@ -511,6 +511,7 @@ struct Converted_module class Spirv_to_llvm; Converted_module spirv_to_llvm(::LLVMContextRef context, + ::LLVMTargetMachineRef target_machine, const spirv::Word *shader_words, std::size_t shader_size, std::uint64_t shader_id); -- 2.30.2