added per-function target attributes
authorJacob Lifshay <programmerjake@gmail.com>
Fri, 28 Jul 2017 14:40:13 +0000 (07:40 -0700)
committerJacob Lifshay <programmerjake@gmail.com>
Fri, 28 Jul 2017 14:40:13 +0000 (07:40 -0700)
CMakeLists.txt
src/demo/demo.cpp
src/llvm_wrapper/CMakeLists.txt
src/llvm_wrapper/llvm_wrapper.cpp
src/llvm_wrapper/llvm_wrapper.h
src/spirv_to_llvm/spirv_to_llvm.cpp
src/spirv_to_llvm/spirv_to_llvm.h

index ab3670d581e52ad189c663a566ea77d0198a5ffe..4c264ebce451e31b4d27ac9c0a67cb13a37f173f 100644 (file)
@@ -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")
index 13bcec5365eac3a19c1806a928c29be956d81336..2c7ee72b9f05ac2b0893e7164e9e5c502fd6b34a 100644 (file)
@@ -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;
     }
index 4934770bb3421b499bf624c16c9e8ecb7967dfef..a5ea6421404cfcfd10edd70ce2513158f9403d68 100644 (file)
@@ -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)
index e7f609828e14c4080475a2da11cebb451ec03a99..881b5bdc9b3e0d84cb2a3ee3ac1c10bc8429de0f 100644 (file)
  */
 #include "llvm_wrapper.h"
 #include <llvm/Support/Host.h>
+#include <llvm/ExecutionEngine/SectionMemoryManager.h>
 #include <stdexcept>
 #include <iostream>
 #include <cstdlib>
+#include <algorithm>
 
 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<bool> features{};
     if(!llvm::sys::getHostCPUFeatures(features))
         return LLVM_string::from("");
     std::string retval;
-    bool first = true;
+    std::vector<std::string> 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<llvm::SectionMemoryManager>();
+    std::unique_ptr<std::shared_ptr<llvm::SectionMemoryManager>> memory_manager_wrapper;
+    memory_manager_wrapper.reset(new std::shared_ptr<llvm::SectionMemoryManager>(memory_manager));
+    MCJIT_memory_manager mcjit_memory_manager(::LLVMCreateSimpleMCJITMemoryManager(
+        static_cast<void *>(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<std::shared_ptr<llvm::SectionMemoryManager> *>(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<std::shared_ptr<llvm::SectionMemoryManager> *>(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<std::shared_ptr<llvm::SectionMemoryManager> *>(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<std::shared_ptr<llvm::SectionMemoryManager> *>(user_data);
+        }));
+    memory_manager_wrapper.release();
+    return Shared_memory_manager(std::move(mcjit_memory_manager), std::move(memory_manager));
 }
 }
 }
index 7457c7df7c153cfd9339a1ee4515e5d65753f7b3..745f1c39c1e7cb512b3dfd8d1e663508aafdfd7f 100644 (file)
@@ -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<void>(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, LLVM_string> 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<Target>(&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<void> shared_memory_manager;
+    explicit Shared_memory_manager(MCJIT_memory_manager mcjit_memory_manager,
+                                   std::shared_ptr<void> 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;
+};
 }
 }
 
index c1257f9de4df7cd0c1433f6a37cc00f70a122f81..40dedfb386da4be89e68d67e004984b4d581b537 100644 (file)
@@ -613,6 +613,7 @@ private:
     Word input_generator_magic_number = 0;
     util::Enum_set<Capability> 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<Function_type_descriptor>(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);
 }
 }
 }
index 5bc229a3c5f99e862879d2a18051431ec3121581..4888d7d599426ac5ecbccf93935c1d0912a9d0f6 100644 (file)
@@ -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);