working on implementing Spirv_to_llvm -- need to fix SIGSEGV bug
authorJacob Lifshay <programmerjake@gmail.com>
Fri, 21 Jul 2017 19:35:45 +0000 (12:35 -0700)
committerJacob Lifshay <programmerjake@gmail.com>
Fri, 21 Jul 2017 19:35:45 +0000 (12:35 -0700)
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 03f5ad90014f9b5e412584c60f5f037a07cd11c4..0509ad7c563531fbb00f8217ad836b6508aa9eb8 100644 (file)
@@ -22,5 +22,5 @@ cmake_minimum_required(VERSION 3.1 FATAL_ERROR)
 
 set(sources llvm_wrapper.cpp)
 add_library(llvm_wrapper STATIC ${sources})
-llvm_map_components_to_libnames(llvm_libraries core)
+llvm_map_components_to_libnames(llvm_libraries core mcjit native)
 target_link_libraries(llvm_wrapper util ${llvm_libraries})
index 2d656048f500a1aedfb5a54f914fe99ca4950537..e7f609828e14c4080475a2da11cebb451ec03a99 100644 (file)
  *
  */
 #include "llvm_wrapper.h"
+#include <llvm/Support/Host.h>
 #include <stdexcept>
+#include <iostream>
+#include <cstdlib>
 
 namespace vulkan_cpu
 {
@@ -31,7 +34,62 @@ Context Context::create()
 {
     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()
+{
+    return LLVM_string::from(llvm::sys::getProcessTriple());
+}
+
+LLVM_string Target::get_host_cpu_name()
+{
+    return LLVM_string::from(llvm::sys::getHostCPUName());
+}
+
+LLVM_string Target::get_host_cpu_features()
+{
+    llvm::StringMap<bool> features{};
+    if(!llvm::sys::getHostCPUFeatures(features))
+        return LLVM_string::from("");
+    std::string retval;
+    bool first = true;
+    for(auto &entry : features)
+    {
+        if(first)
+            first = false;
+        else
+            retval += ',';
+        if(entry.second)
+            retval += '+';
+        else
+            retval += '-';
+        retval += entry.first();
+    }
+    return LLVM_string::from(retval);
+}
+
+Target_machine Target_machine::create_native_target_machine()
+{
+    auto target = Target::get_native_target();
+    return Target_machine(::LLVMCreateTargetMachine(target.get(),
+                                                    Target::get_process_target_triple().get(),
+                                                    Target::get_host_cpu_name().get(),
+                                                    Target::get_host_cpu_features().get(),
+                                                    ::LLVMCodeGenLevelDefault,
+                                                    ::LLVMRelocDefault,
+                                                    ::LLVMCodeModelJITDefault));
+}
+
+void Module::set_target_to_native(::LLVMModuleRef module)
+{
+    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());
+}
 }
 }
index 94d0121f1a07987cdf2de1a5de004a16535a3166..565c335ce201ed8f72cca218b1796f0c506dfd2f 100644 (file)
 #define LLVM_WRAPPER_LLVM_WRAPPER_H_
 
 #include <llvm-c/Core.h>
+#include <llvm-c/Target.h>
+#include <llvm-c/TargetMachine.h>
+#include <llvm-c/ExecutionEngine.h>
 #include <memory>
 #include <type_traits>
 #include <utility>
 #include <string>
 #include <cassert>
 #include "util/string_view.h"
+#include "util/variant.h"
 
 namespace vulkan_cpu
 {
@@ -93,6 +97,54 @@ public:
     }
 };
 
+struct LLVM_string_deleter
+{
+    void operator()(char *str)
+    {
+        ::LLVMDisposeMessage(str);
+    }
+};
+
+class LLVM_string : public Wrapper<char *, LLVM_string_deleter>
+{
+public:
+    constexpr LLVM_string() noexcept : Wrapper()
+    {
+    }
+    static LLVM_string wrap(char *value) noexcept
+    {
+        LLVM_string retval;
+        retval.reset(value);
+        return retval;
+    }
+    static LLVM_string from(const char *value)
+    {
+        return wrap(::LLVMCreateMessage(value));
+    }
+    static LLVM_string from(const std::string &value)
+    {
+        return from(value.c_str());
+    }
+    static LLVM_string from(util::string_view value)
+    {
+        return from(std::string(value));
+    }
+    operator util::string_view() const
+    {
+        assert(*this);
+        return util::string_view(get());
+    }
+    explicit operator std::string() const
+    {
+        assert(*this);
+        return get();
+    }
+    explicit operator char *() const // override non-explicit operator
+    {
+        return get();
+    }
+};
+
 struct Context_deleter
 {
     void operator()(::LLVMContextRef context) noexcept
@@ -107,68 +159,134 @@ struct Context : public Wrapper<::LLVMContextRef, Context_deleter>
     static Context create();
 };
 
-struct Module_deleter
+struct Target_deleter
 {
-    void operator()(::LLVMModuleRef module) noexcept
+    void operator()(::LLVMTargetRef target) noexcept
     {
-        ::LLVMDisposeModule(module);
+        static_cast<void>(target);
     }
 };
 
-struct Module : public Wrapper<::LLVMModuleRef, Module_deleter>
+struct Target : public Wrapper<::LLVMTargetRef, Target_deleter>
 {
     using Wrapper::Wrapper;
-    static Module create(const char *id, ::LLVMContextRef context)
+    static LLVM_string get_default_target_triple()
     {
-        return Module(::LLVMModuleCreateWithNameInContext(id, context));
+        return LLVM_string::wrap(::LLVMGetDefaultTargetTriple());
+    }
+    static LLVM_string get_process_target_triple();
+    static LLVM_string get_host_cpu_name();
+    static LLVM_string get_host_cpu_features();
+    typedef util::variant<Target, LLVM_string> Target_or_error_message;
+    static Target_or_error_message get_target_from_target_triple(const char *triple)
+    {
+        ::LLVMTargetRef target = nullptr;
+        char *error_message = nullptr;
+        if(::LLVMGetTargetFromTriple(triple, &target, &error_message) == 0)
+            return Target(target);
+        return LLVM_string::wrap(error_message);
+    }
+    static Target get_native_target()
+    {
+        auto native_triple = get_process_target_triple();
+        auto retval = get_target_from_target_triple(native_triple.get());
+        auto *target = util::get_if<Target>(&retval);
+        if(!target)
+            throw std::runtime_error(
+                "can't find target for native triple (" + std::string(native_triple) + "): "
+                + util::get<LLVM_string>(retval).get());
+        return std::move(*target);
     }
 };
 
-struct LLVM_string_deleter
+struct Target_data_deleter
 {
-    void operator()(char *str)
+    void operator()(::LLVMTargetDataRef v) noexcept
     {
-        ::LLVMDisposeMessage(str);
+        ::LLVMDisposeTargetData(v);
     }
 };
 
-class LLVM_string : public Wrapper<char *, LLVM_string_deleter>
+struct Target_data : public Wrapper<::LLVMTargetDataRef, Target_data_deleter>
 {
-public:
-    constexpr LLVM_string() noexcept : Wrapper()
+    using Wrapper::Wrapper;
+    static LLVM_string to_string(::LLVMTargetDataRef td)
     {
+        return LLVM_string::wrap(::LLVMCopyStringRepOfTargetData(td));
     }
-    static LLVM_string wrap(char *value) noexcept
+    LLVM_string to_string() const
     {
-        LLVM_string retval;
-        retval.reset(value);
-        return retval;
+        return to_string(get());
     }
-    static LLVM_string from(const char *value)
+    static Target_data from_string(const char *str)
     {
-        return wrap(::LLVMCreateMessage(value));
+        return Target_data(::LLVMCreateTargetData(str));
     }
-    static LLVM_string from(const std::string &value)
+};
+
+struct Target_machine_deleter
+{
+    void operator()(::LLVMTargetMachineRef tm) noexcept
     {
-        return from(value.c_str());
+        ::LLVMDisposeTargetMachine(tm);
     }
-    static LLVM_string from(util::string_view value)
+};
+
+struct Target_machine : public Wrapper<::LLVMTargetMachineRef, Target_machine_deleter>
+{
+    using Wrapper::Wrapper;
+    static Target_machine create_native_target_machine();
+    static Target get_target(::LLVMTargetMachineRef tm)
     {
-        return from(std::string(value));
+        return Target(::LLVMGetTargetMachineTarget(tm));
     }
-    operator util::string_view() const
+    Target get_target() const
     {
-        assert(*this);
-        return util::string_view(get());
+        return get_target(get());
     }
-    explicit operator std::string() const
+    static LLVM_string get_target_triple(::LLVMTargetMachineRef tm)
     {
-        assert(*this);
-        return get();
+        return LLVM_string::wrap(::LLVMGetTargetMachineTriple(tm));
     }
-    explicit operator char *() const // override non-explicit operator
+    LLVM_string get_target_triple() const
     {
-        return get();
+        return get_target_triple(get());
+    }
+    static Target_data create_target_data_layout(::LLVMTargetMachineRef tm)
+    {
+        return Target_data(::LLVMCreateTargetDataLayout(tm));
+    }
+    Target_data create_target_data_layout() const
+    {
+        return create_target_data_layout(get());
+    }
+};
+
+struct Module_deleter
+{
+    void operator()(::LLVMModuleRef module) noexcept
+    {
+        ::LLVMDisposeModule(module);
+    }
+};
+
+struct Module : public Wrapper<::LLVMModuleRef, Module_deleter>
+{
+    using Wrapper::Wrapper;
+    static Module create(const char *id, ::LLVMContextRef context)
+    {
+        return Module(::LLVMModuleCreateWithNameInContext(id, context));
+    }
+    static Module create_native(const char *id, ::LLVMContextRef context)
+    {
+        Module retval = create(id, context);
+        retval.set_target_to_native();
+        return retval;
+    }
+    static void set_target_to_native(::LLVMModuleRef module);
+    void set_target_to_native()
+    {
+        set_target_to_native(get());
     }
 };
 
index 9ef798dc86d80cdafb9f6f46bb06cab8689bb3f6..581545a690f811bf64b1d64f26b07d6698b979df 100644 (file)
@@ -24,6 +24,8 @@
 #include "util/optional.h"
 #include "util/variant.h"
 #include "util/enum.h"
+#include <functional>
+#include <list>
 
 namespace vulkan_cpu
 {
@@ -31,11 +33,411 @@ namespace spirv_to_llvm
 {
 using namespace spirv;
 
-void Struct_type_descriptor::complete_type(bool need_complete_structs)
+namespace
+{
+constexpr bool is_power_of_2(std::uint64_t v) noexcept
+{
+    return (v & (v - 1)) == 0 && v != 0;
+}
+
+constexpr std::size_t get_padding_size(std::size_t current_position,
+                                       std::size_t needed_alignment) noexcept
+{
+    assert(is_power_of_2(needed_alignment));
+    return ~current_position & (needed_alignment - 1);
+}
+}
+
+void Struct_type_descriptor::complete_type()
 {
+    for(auto &decoration : decorations)
+    {
+        switch(decoration.value)
+        {
+        case Decoration::relaxed_precision:
+#warning finish implementing Decoration::relaxed_precision
+            break;
+        case Decoration::spec_id:
+#warning finish implementing Decoration::spec_id
+            break;
+        case Decoration::block:
+#warning finish implementing Decoration::block
+            continue;
+        case Decoration::buffer_block:
+#warning finish implementing Decoration::buffer_block
+            break;
+        case Decoration::row_major:
+#warning finish implementing Decoration::row_major
+            break;
+        case Decoration::col_major:
+#warning finish implementing Decoration::col_major
+            break;
+        case Decoration::array_stride:
+#warning finish implementing Decoration::array_stride
+            break;
+        case Decoration::matrix_stride:
+#warning finish implementing Decoration::matrix_stride
+            break;
+        case Decoration::glsl_shared:
+#warning finish implementing Decoration::glsl_shared
+            break;
+        case Decoration::glsl_packed:
+#warning finish implementing Decoration::glsl_packed
+            break;
+        case Decoration::c_packed:
+#warning finish implementing Decoration::c_packed
+            break;
+        case Decoration::built_in:
+#warning finish implementing Decoration::built_in
+            break;
+        case Decoration::no_perspective:
+#warning finish implementing Decoration::no_perspective
+            break;
+        case Decoration::flat:
+#warning finish implementing Decoration::flat
+            break;
+        case Decoration::patch:
+#warning finish implementing Decoration::patch
+            break;
+        case Decoration::centroid:
+#warning finish implementing Decoration::centroid
+            break;
+        case Decoration::sample:
+#warning finish implementing Decoration::sample
+            break;
+        case Decoration::invariant:
+#warning finish implementing Decoration::invariant
+            break;
+        case Decoration::restrict:
+#warning finish implementing Decoration::restrict
+            break;
+        case Decoration::aliased:
+#warning finish implementing Decoration::aliased
+            break;
+        case Decoration::volatile_:
+#warning finish implementing Decoration::volatile_
+            break;
+        case Decoration::constant:
+#warning finish implementing Decoration::constant
+            break;
+        case Decoration::coherent:
+#warning finish implementing Decoration::coherent
+            break;
+        case Decoration::non_writable:
+#warning finish implementing Decoration::non_writable
+            break;
+        case Decoration::non_readable:
+#warning finish implementing Decoration::non_readable
+            break;
+        case Decoration::uniform:
+#warning finish implementing Decoration::uniform
+            break;
+        case Decoration::saturated_conversion:
+#warning finish implementing Decoration::saturated_conversion
+            break;
+        case Decoration::stream:
+#warning finish implementing Decoration::stream
+            break;
+        case Decoration::location:
+#warning finish implementing Decoration::location
+            break;
+        case Decoration::component:
+#warning finish implementing Decoration::component
+            break;
+        case Decoration::index:
+#warning finish implementing Decoration::index
+            break;
+        case Decoration::binding:
+#warning finish implementing Decoration::binding
+            break;
+        case Decoration::descriptor_set:
+#warning finish implementing Decoration::descriptor_set
+            break;
+        case Decoration::offset:
+#warning finish implementing Decoration::offset
+            break;
+        case Decoration::xfb_buffer:
+#warning finish implementing Decoration::xfb_buffer
+            break;
+        case Decoration::xfb_stride:
+#warning finish implementing Decoration::xfb_stride
+            break;
+        case Decoration::func_param_attr:
+#warning finish implementing Decoration::func_param_attr
+            break;
+        case Decoration::fp_rounding_mode:
+#warning finish implementing Decoration::fp_rounding_mode
+            break;
+        case Decoration::fp_fast_math_mode:
+#warning finish implementing Decoration::fp_fast_math_mode
+            break;
+        case Decoration::linkage_attributes:
+#warning finish implementing Decoration::linkage_attributes
+            break;
+        case Decoration::no_contraction:
+#warning finish implementing Decoration::no_contraction
+            break;
+        case Decoration::input_attachment_index:
+#warning finish implementing Decoration::input_attachment_index
+            break;
+        case Decoration::alignment:
+#warning finish implementing Decoration::alignment
+            break;
+        case Decoration::max_byte_offset:
+#warning finish implementing Decoration::max_byte_offset
+            break;
+        case Decoration::alignment_id:
+#warning finish implementing Decoration::alignment_id
+            break;
+        case Decoration::max_byte_offset_id:
+#warning finish implementing Decoration::max_byte_offset_id
+            break;
+        case Decoration::override_coverage_nv:
+#warning finish implementing Decoration::override_coverage_nv
+            break;
+        case Decoration::passthrough_nv:
+#warning finish implementing Decoration::passthrough_nv
+            break;
+        case Decoration::viewport_relative_nv:
+#warning finish implementing Decoration::viewport_relative_nv
+            break;
+        case Decoration::secondary_viewport_relative_nv:
+#warning finish implementing Decoration::secondary_viewport_relative_nv
+            break;
+        }
+        throw Parser_error(instruction_start_index,
+                           instruction_start_index,
+                           "unimplemented decoration on OpTypeStruct: "
+                               + std::string(get_enumerant_name(decoration.value)));
+    }
+    struct Member_descriptor
+    {
+        std::size_t alignment;
+        std::size_t size;
+        ::LLVMTypeRef type;
+        explicit Member_descriptor(std::size_t alignment,
+                                   std::size_t size,
+                                   ::LLVMTypeRef type) noexcept : alignment(alignment),
+                                                                  size(size),
+                                                                  type(type)
+        {
+        }
+    };
+    std::vector<Member_descriptor> member_descriptors;
+    member_descriptors.reserve(members.size());
+    std::size_t total_alignment = 1;
+    for(auto &member : members)
+    {
+        for(auto &decoration : member.decorations)
+        {
+            switch(decoration.value)
+            {
+            case Decoration::relaxed_precision:
+#warning finish implementing Decoration::relaxed_precision
+                break;
+            case Decoration::spec_id:
+#warning finish implementing Decoration::spec_id
+                break;
+            case Decoration::block:
+#warning finish implementing Decoration::block
+                break;
+            case Decoration::buffer_block:
+#warning finish implementing Decoration::buffer_block
+                break;
+            case Decoration::row_major:
+#warning finish implementing Decoration::row_major
+                break;
+            case Decoration::col_major:
+#warning finish implementing Decoration::col_major
+                break;
+            case Decoration::array_stride:
+#warning finish implementing Decoration::array_stride
+                break;
+            case Decoration::matrix_stride:
+#warning finish implementing Decoration::matrix_stride
+                break;
+            case Decoration::glsl_shared:
+#warning finish implementing Decoration::glsl_shared
+                break;
+            case Decoration::glsl_packed:
+#warning finish implementing Decoration::glsl_packed
+                break;
+            case Decoration::c_packed:
+#warning finish implementing Decoration::c_packed
+                break;
+            case Decoration::built_in:
+#warning finish implementing Decoration::built_in
+                continue;
+            case Decoration::no_perspective:
+#warning finish implementing Decoration::no_perspective
+                break;
+            case Decoration::flat:
+#warning finish implementing Decoration::flat
+                break;
+            case Decoration::patch:
+#warning finish implementing Decoration::patch
+                break;
+            case Decoration::centroid:
+#warning finish implementing Decoration::centroid
+                break;
+            case Decoration::sample:
+#warning finish implementing Decoration::sample
+                break;
+            case Decoration::invariant:
+#warning finish implementing Decoration::invariant
+                break;
+            case Decoration::restrict:
+#warning finish implementing Decoration::restrict
+                break;
+            case Decoration::aliased:
+#warning finish implementing Decoration::aliased
+                break;
+            case Decoration::volatile_:
+#warning finish implementing Decoration::volatile_
+                break;
+            case Decoration::constant:
+#warning finish implementing Decoration::constant
+                break;
+            case Decoration::coherent:
+#warning finish implementing Decoration::coherent
+                break;
+            case Decoration::non_writable:
+#warning finish implementing Decoration::non_writable
+                break;
+            case Decoration::non_readable:
+#warning finish implementing Decoration::non_readable
+                break;
+            case Decoration::uniform:
+#warning finish implementing Decoration::uniform
+                break;
+            case Decoration::saturated_conversion:
+#warning finish implementing Decoration::saturated_conversion
+                break;
+            case Decoration::stream:
+#warning finish implementing Decoration::stream
+                break;
+            case Decoration::location:
+                continue;
+            case Decoration::component:
+#warning finish implementing Decoration::component
+                break;
+            case Decoration::index:
+#warning finish implementing Decoration::index
+                break;
+            case Decoration::binding:
+#warning finish implementing Decoration::binding
+                break;
+            case Decoration::descriptor_set:
+#warning finish implementing Decoration::descriptor_set
+                break;
+            case Decoration::offset:
+#warning finish implementing Decoration::offset
+                break;
+            case Decoration::xfb_buffer:
+#warning finish implementing Decoration::xfb_buffer
+                break;
+            case Decoration::xfb_stride:
+#warning finish implementing Decoration::xfb_stride
+                break;
+            case Decoration::func_param_attr:
+#warning finish implementing Decoration::func_param_attr
+                break;
+            case Decoration::fp_rounding_mode:
+#warning finish implementing Decoration::fp_rounding_mode
+                break;
+            case Decoration::fp_fast_math_mode:
+#warning finish implementing Decoration::fp_fast_math_mode
+                break;
+            case Decoration::linkage_attributes:
+#warning finish implementing Decoration::linkage_attributes
+                break;
+            case Decoration::no_contraction:
+#warning finish implementing Decoration::no_contraction
+                break;
+            case Decoration::input_attachment_index:
+#warning finish implementing Decoration::input_attachment_index
+                break;
+            case Decoration::alignment:
+#warning finish implementing Decoration::alignment
+                break;
+            case Decoration::max_byte_offset:
+#warning finish implementing Decoration::max_byte_offset
+                break;
+            case Decoration::alignment_id:
+#warning finish implementing Decoration::alignment_id
+                break;
+            case Decoration::max_byte_offset_id:
+#warning finish implementing Decoration::max_byte_offset_id
+                break;
+            case Decoration::override_coverage_nv:
+#warning finish implementing Decoration::override_coverage_nv
+                break;
+            case Decoration::passthrough_nv:
+#warning finish implementing Decoration::passthrough_nv
+                break;
+            case Decoration::viewport_relative_nv:
+#warning finish implementing Decoration::viewport_relative_nv
+                break;
+            case Decoration::secondary_viewport_relative_nv:
+#warning finish implementing Decoration::secondary_viewport_relative_nv
+                break;
+            }
+            throw Parser_error(instruction_start_index,
+                               instruction_start_index,
+                               "unimplemented member decoration on OpTypeStruct: "
+                                   + std::string(get_enumerant_name(decoration.value)));
+        }
+        auto member_type = member.type->get_or_make_type();
+        if(::LLVMGetTypeKind(member_type) == ::LLVMStructTypeKind
+           && ::LLVMIsOpaqueStruct(member_type))
+        {
+            if(dynamic_cast<const Struct_type_descriptor *>(member.type.get()))
+                throw Parser_error(instruction_start_index,
+                                   instruction_start_index,
+                                   "recursive struct has infinite size");
+            throw Parser_error(instruction_start_index,
+                               instruction_start_index,
+                               "struct can't have opaque struct members");
+        }
+        std::size_t alignment = ::LLVMPreferredAlignmentOfType(target_data, member_type);
+        assert(is_power_of_2(alignment));
+        std::size_t size = ::LLVMABISizeOfType(target_data, member_type);
+        if(alignment > total_alignment)
+            total_alignment = alignment;
+        member_descriptors.push_back(Member_descriptor(alignment, size, member_type));
+    }
+    assert(member_descriptors.size() == members.size());
+    assert(is_power_of_2(total_alignment));
+    std::size_t current_offset = 0;
+    std::vector<::LLVMTypeRef> member_types;
+    member_types.reserve(members.size() * 2);
+    if(!members.empty())
+    {
+        for(std::size_t member_index = 0; member_index < members.size(); member_index++)
+        {
+            members[member_index].llvm_member_index = member_types.size();
 #warning finish Struct_type_descriptor::complete_type
-    static_cast<void>(need_complete_structs);
-    throw Parser_error(0, 0, "not implemented: Struct_descriptor::complete_type");
+            member_types.push_back(member_descriptors[member_index].type);
+            current_offset += member_descriptors[member_index].size;
+            std::size_t next_alignment = member_index + 1 < members.size() ?
+                                             member_descriptors[member_index + 1].alignment :
+                                             total_alignment;
+            auto padding_size = get_padding_size(current_offset, next_alignment);
+            if(padding_size != 0)
+            {
+                member_types.push_back(
+                    ::LLVMArrayType(::LLVMInt8TypeInContext(context), padding_size));
+                current_offset += padding_size;
+            }
+        }
+    }
+    else
+    {
+        member_types.push_back(::LLVMInt8TypeInContext(context)); // so it isn't empty
+    }
+    constexpr bool is_packed = false;
+    ::LLVMStructSetBody(type, member_types.data(), member_types.size(), is_packed);
+    is_complete = true;
 }
 
 namespace
@@ -225,6 +627,7 @@ private:
     Id current_basic_block_id = 0;
     llvm_wrapper::Builder builder;
     util::optional<Last_merge_instruction> last_merge_instruction;
+    std::list<std::function<void()>> function_entry_block_handlers;
 
 private:
     Id_state &get_id_state(Id id)
@@ -272,19 +675,32 @@ public:
             ss << "shader_" << shader_id << "_";
             name_prefix = ss.str();
         }
-        module = llvm_wrapper::Module::create((name_prefix + "module").c_str(), context);
+        module = llvm_wrapper::Module::create_native((name_prefix + "module").c_str(), context);
         builder = llvm_wrapper::Builder::create(context);
+        auto target_data = ::LLVMGetModuleDataLayout(module.get());
         constexpr std::size_t no_instruction_index = 0;
-        io_struct = std::make_shared<Struct_type_descriptor>(
-            context, (name_prefix + "Io_struct").c_str(), no_instruction_index);
+        io_struct =
+            std::make_shared<Struct_type_descriptor>(std::vector<Decoration_with_parameters>{},
+                                                     context,
+                                                     target_data,
+                                                     (name_prefix + "Io_struct").c_str(),
+                                                     no_instruction_index);
         assert(implicit_function_arguments.size() == 1);
         static_assert(io_struct_argument_index == 0, "");
         implicit_function_arguments[io_struct_argument_index] = io_struct;
-        inputs_struct = std::make_shared<Struct_type_descriptor>(
-            context, (name_prefix + "Inputs").c_str(), no_instruction_index);
+        inputs_struct =
+            std::make_shared<Struct_type_descriptor>(std::vector<Decoration_with_parameters>{},
+                                                     context,
+                                                     target_data,
+                                                     (name_prefix + "Inputs").c_str(),
+                                                     no_instruction_index);
         inputs_member = io_struct->add_member(Struct_type_descriptor::Member({}, inputs_struct));
-        outputs_struct = std::make_shared<Struct_type_descriptor>(
-            context, (name_prefix + "Outputs").c_str(), no_instruction_index);
+        outputs_struct =
+            std::make_shared<Struct_type_descriptor>(std::vector<Decoration_with_parameters>{},
+                                                     context,
+                                                     target_data,
+                                                     (name_prefix + "Outputs").c_str(),
+                                                     no_instruction_index);
         outputs_member = io_struct->add_member(Struct_type_descriptor::Member({}, outputs_struct));
     }
     Converted_module run(const Word *shader_words, std::size_t shader_size)
@@ -293,9 +709,9 @@ public:
         spirv::parse(*this, shader_words, shader_size);
         for(auto &id_state : id_states)
             if(id_state.type)
-                id_state.type->get_or_make_type(true);
+                id_state.type->get_or_make_type();
         for(auto &arg : implicit_function_arguments)
-            arg->get_or_make_type(true);
+            arg->get_or_make_type();
 #warning finish Spirv_to_llvm::run
         stage = Stage::generate_code;
         spirv::parse(*this, shader_words, shader_size);
@@ -1678,9 +2094,12 @@ void Spirv_to_llvm::handle_instruction_op_type_void(
     switch(stage)
     {
     case Stage::calculate_types:
-        get_id_state(instruction.result).type =
-            std::make_shared<Simple_type_descriptor>(::LLVMVoidTypeInContext(context));
+    {
+        auto &state = get_id_state(instruction.result);
+        state.type = std::make_shared<Simple_type_descriptor>(state.decorations,
+                                                              ::LLVMVoidTypeInContext(context));
         break;
+    }
     case Stage::generate_code:
         break;
     }
@@ -1711,7 +2130,7 @@ void Spirv_to_llvm::handle_instruction_op_type_int(Op_type_int instruction,
         case 32:
         case 64:
             state.type = std::make_shared<Simple_type_descriptor>(
-                ::LLVMIntTypeInContext(context, instruction.width));
+                state.decorations, ::LLVMIntTypeInContext(context, instruction.width));
             break;
         default:
             throw Parser_error(
@@ -1735,15 +2154,16 @@ void Spirv_to_llvm::handle_instruction_op_type_float(Op_type_float instruction,
         switch(instruction.width)
         {
         case 16:
-            state.type = std::make_shared<Simple_type_descriptor>(::LLVMHalfTypeInContext(context));
+            state.type = std::make_shared<Simple_type_descriptor>(state.decorations,
+                                                                  ::LLVMHalfTypeInContext(context));
             break;
         case 32:
-            state.type =
-                std::make_shared<Simple_type_descriptor>(::LLVMFloatTypeInContext(context));
+            state.type = std::make_shared<Simple_type_descriptor>(
+                state.decorations, ::LLVMFloatTypeInContext(context));
             break;
         case 64:
-            state.type =
-                std::make_shared<Simple_type_descriptor>(::LLVMDoubleTypeInContext(context));
+            state.type = std::make_shared<Simple_type_descriptor>(
+                state.decorations, ::LLVMDoubleTypeInContext(context));
             break;
         default:
             throw Parser_error(
@@ -1762,10 +2182,14 @@ void Spirv_to_llvm::handle_instruction_op_type_vector(Op_type_vector instruction
     switch(stage)
     {
     case Stage::calculate_types:
-        get_id_state(instruction.result).type = std::make_shared<Vector_type_descriptor>(
+    {
+        auto &state = get_id_state(instruction.result);
+        state.type = std::make_shared<Vector_type_descriptor>(
+            state.decorations,
             get_type<Simple_type_descriptor>(instruction.component_type, instruction_start_index),
             instruction.component_count);
         break;
+    }
     case Stage::generate_code:
         break;
     }
@@ -1777,10 +2201,14 @@ void Spirv_to_llvm::handle_instruction_op_type_matrix(Op_type_matrix instruction
     switch(stage)
     {
     case Stage::calculate_types:
-        get_id_state(instruction.result).type = std::make_shared<Matrix_type_descriptor>(
+    {
+        auto &state = get_id_state(instruction.result);
+        state.type = std::make_shared<Matrix_type_descriptor>(
+            state.decorations,
             get_type<Vector_type_descriptor>(instruction.column_type, instruction_start_index),
             instruction.column_count);
         break;
+    }
     case Stage::generate_code:
         break;
     }
@@ -1859,7 +2287,9 @@ void Spirv_to_llvm::handle_instruction_op_type_struct(Op_type_struct instruction
             member.decorations.push_back(decoration.decoration);
         }
         state.type = std::make_shared<Struct_type_descriptor>(
+            state.decorations,
             context,
+            ::LLVMGetModuleDataLayout(module.get()),
             (name_prefix + get_name(instruction.result)).c_str(),
             instruction_start_index,
             std::move(members));
@@ -1891,7 +2321,9 @@ void Spirv_to_llvm::handle_instruction_op_type_pointer(Op_type_pointer instructi
         if(!state.type)
         {
             state.type = std::make_shared<Pointer_type_descriptor>(
-                get_type(instruction.type, instruction_start_index), instruction_start_index);
+                state.decorations,
+                get_type(instruction.type, instruction_start_index),
+                instruction_start_index);
         }
         else if(auto *pointer_type = dynamic_cast<Pointer_type_descriptor *>(state.type.get()))
         {
@@ -1928,7 +2360,9 @@ void Spirv_to_llvm::handle_instruction_op_type_function(Op_type_function instruc
             args.push_back(arg);
         for(Id_ref type : instruction.parameter_0_type_parameter_1_type)
             args.push_back(get_type(type, instruction_start_index));
-        get_id_state(instruction.result).type = std::make_shared<Function_type_descriptor>(
+        auto &state = get_id_state(instruction.result);
+        state.type = std::make_shared<Function_type_descriptor>(
+            state.decorations,
             get_type(instruction.return_type, instruction_start_index),
             std::move(args),
             instruction_start_index);
@@ -2030,7 +2464,7 @@ void Spirv_to_llvm::handle_instruction_op_constant(Op_constant instruction,
         auto type = get_type(instruction.result_type, instruction_start_index);
         if(auto *simple_type = dynamic_cast<Simple_type_descriptor *>(type.get()))
         {
-            auto llvm_type = simple_type->get_or_make_type(true);
+            auto llvm_type = simple_type->get_or_make_type();
             switch(::LLVMGetTypeKind(llvm_type))
             {
             case LLVMFloatTypeKind:
@@ -2257,7 +2691,7 @@ void Spirv_to_llvm::handle_instruction_op_function(Op_function instruction,
             Function_state(function_type,
                            ::LLVMAddFunction(module.get(),
                                              (name_prefix + get_name(current_function_id)).c_str(),
-                                             function_type->get_or_make_type(true)));
+                                             function_type->get_or_make_type()));
         break;
     }
     }
@@ -2564,14 +2998,21 @@ void Spirv_to_llvm::handle_instruction_op_variable(Op_variable instruction,
                 throw Parser_error(instruction_start_index,
                                    instruction_start_index,
                                    "shader input variable initializers are not implemented");
-            auto &variable = util::get<Input_variable_state>(state.variable);
-            state.value =
-                Value(::LLVMBuildStructGEP(
-                          builder.get(),
-                          get_id_state(current_function_id).function->entry_block->inputs_struct,
-                          inputs_struct->get_members(true)[variable.member_index].llvm_member_index,
-                          get_name(instruction.result).c_str()),
-                      get_type(instruction.result_type, instruction_start_index));
+            auto set_value_fn = [this, instruction, &state, instruction_start_index]()
+            {
+                auto &variable = util::get<Input_variable_state>(state.variable);
+                state.value = Value(
+                    ::LLVMBuildStructGEP(
+                        builder.get(),
+                        get_id_state(current_function_id).function->entry_block->inputs_struct,
+                        inputs_struct->get_members(true)[variable.member_index].llvm_member_index,
+                        get_name(instruction.result).c_str()),
+                    get_type(instruction.result_type, instruction_start_index));
+            };
+            if(current_function_id)
+                set_value_fn();
+            else
+                function_entry_block_handlers.push_back(set_value_fn);
             return;
         }
         case Storage_class::uniform:
@@ -2583,14 +3024,21 @@ void Spirv_to_llvm::handle_instruction_op_variable(Op_variable instruction,
                 throw Parser_error(instruction_start_index,
                                    instruction_start_index,
                                    "shader output variable initializers are not implemented");
-            auto &variable = util::get<Output_variable_state>(state.variable);
-            state.value = Value(
-                ::LLVMBuildStructGEP(
-                    builder.get(),
-                    get_id_state(current_function_id).function->entry_block->outputs_struct,
-                    outputs_struct->get_members(true)[variable.member_index].llvm_member_index,
-                    get_name(instruction.result).c_str()),
-                get_type(instruction.result_type, instruction_start_index));
+            auto set_value_fn = [this, instruction, &state, instruction_start_index]()
+            {
+                auto &variable = util::get<Output_variable_state>(state.variable);
+                state.value = Value(
+                    ::LLVMBuildStructGEP(
+                        builder.get(),
+                        get_id_state(current_function_id).function->entry_block->outputs_struct,
+                        outputs_struct->get_members(true)[variable.member_index].llvm_member_index,
+                        get_name(instruction.result).c_str()),
+                    get_type(instruction.result_type, instruction_start_index));
+            };
+            if(current_function_id)
+                set_value_fn();
+            else
+                function_entry_block_handlers.push_back(set_value_fn);
             return;
         }
         case Storage_class::workgroup:
@@ -4561,6 +5009,12 @@ void Spirv_to_llvm::handle_instruction_op_label(Op_label instruction,
         if(!function.entry_block)
         {
             auto io_struct_value = ::LLVMGetParam(function.function, io_struct_argument_index);
+#if 1
+            if(block) // always true, but not constant so clang doesn't warn
+                throw Parser_error(
+                    instruction_start_index, instruction_start_index, "finish fixing OpLabel");
+#endif
+#warning finish fixing SIGSEGV here
             auto inputs_struct_value = ::LLVMBuildStructGEP(
                 builder.get(),
                 io_struct_value,
@@ -4571,9 +5025,15 @@ void Spirv_to_llvm::handle_instruction_op_label(Op_label instruction,
                 io_struct_value,
                 io_struct->get_members(true)[this->outputs_member].llvm_member_index,
                 "outputs");
-#warning finish adding function entry instructions
             function.entry_block = Function_state::Entry_block(
                 block, io_struct_value, inputs_struct_value, outputs_struct_value);
+            for(auto iter = function_entry_block_handlers.begin();
+                iter != function_entry_block_handlers.end();)
+            {
+                auto fn = *iter++;
+                // increment before calling in case the hander removes itself
+                fn();
+            }
         }
         break;
     }
@@ -4628,10 +5088,9 @@ void Spirv_to_llvm::handle_instruction_op_switch(
                                                     get_or_make_label(instruction.default_),
                                                     instruction.target.size());
         for(auto &target : instruction.target)
-            ::LLVMAddCase(
-                switch_instruction,
-                ::LLVMConstInt(selector.type->get_or_make_type(true), target.part_1, false),
-                get_or_make_label(target.part_2));
+            ::LLVMAddCase(switch_instruction,
+                          ::LLVMConstInt(selector.type->get_or_make_type(), target.part_1, false),
+                          get_or_make_label(target.part_2));
         break;
     }
     }
index c568323222811c9b557f127542355099034dbda4..5bc229a3c5f99e862879d2a18051431ec3121581 100644 (file)
@@ -61,9 +61,15 @@ public:
     };
 
 public:
-    Type_descriptor() noexcept = default;
+    const std::vector<spirv::Decoration_with_parameters> decorations;
+
+public:
+    explicit Type_descriptor(std::vector<spirv::Decoration_with_parameters> decorations) noexcept
+        : decorations(std::move(decorations))
+    {
+    }
     virtual ~Type_descriptor() = default;
-    virtual ::LLVMTypeRef get_or_make_type(bool need_complete_structs) = 0;
+    virtual ::LLVMTypeRef get_or_make_type() = 0;
     virtual void visit(Type_visitor &type_visitor) = 0;
     void visit(Type_visitor &&type_visitor)
     {
@@ -154,10 +160,13 @@ private:
     ::LLVMTypeRef type;
 
 public:
-    explicit Simple_type_descriptor(::LLVMTypeRef type) noexcept : type(type)
+    explicit Simple_type_descriptor(std::vector<spirv::Decoration_with_parameters> decorations,
+                                    ::LLVMTypeRef type) noexcept
+        : Type_descriptor(std::move(decorations)),
+          type(type)
     {
     }
-    virtual ::LLVMTypeRef get_or_make_type([[gnu::unused]] bool need_complete_structs) override
+    virtual ::LLVMTypeRef get_or_make_type() override
     {
         return type;
     }
@@ -175,14 +184,16 @@ private:
     std::size_t element_count;
 
 public:
-    explicit Vector_type_descriptor(std::shared_ptr<Simple_type_descriptor> element_type,
+    explicit Vector_type_descriptor(std::vector<spirv::Decoration_with_parameters> decorations,
+                                    std::shared_ptr<Simple_type_descriptor> element_type,
                                     std::size_t element_count) noexcept
-        : type(::LLVMVectorType(element_type->get_or_make_type(true), element_count)),
+        : Type_descriptor(std::move(decorations)),
+          type(::LLVMVectorType(element_type->get_or_make_type(), element_count)),
           element_type(std::move(element_type)),
           element_count(element_count)
     {
     }
-    virtual ::LLVMTypeRef get_or_make_type([[gnu::unused]] bool need_complete_structs) override
+    virtual ::LLVMTypeRef get_or_make_type() override
     {
         return type;
     }
@@ -208,15 +219,17 @@ private:
     std::size_t column_count;
 
 public:
-    explicit Matrix_type_descriptor(std::shared_ptr<Vector_type_descriptor> column_type,
+    explicit Matrix_type_descriptor(std::vector<spirv::Decoration_with_parameters> decorations,
+                                    std::shared_ptr<Vector_type_descriptor> column_type,
                                     std::size_t column_count) noexcept
-        : type(::LLVMVectorType(column_type->get_element_type()->get_or_make_type(true),
+        : Type_descriptor(std::move(decorations)),
+          type(::LLVMVectorType(column_type->get_element_type()->get_or_make_type(),
                                 column_type->get_element_count() * column_count)),
           column_type(std::move(column_type)),
           column_count(column_count)
     {
     }
-    virtual ::LLVMTypeRef get_or_make_type([[gnu::unused]] bool need_complete_structs) override
+    virtual ::LLVMTypeRef get_or_make_type() override
     {
         return type;
     }
@@ -243,9 +256,11 @@ private:
     Recursion_checker_state recursion_checker_state;
 
 public:
-    Pointer_type_descriptor(std::shared_ptr<Type_descriptor> base,
+    Pointer_type_descriptor(std::vector<spirv::Decoration_with_parameters> decorations,
+                            std::shared_ptr<Type_descriptor> base,
                             std::size_t instruction_start_index) noexcept
-        : base(std::move(base)),
+        : Type_descriptor(std::move(decorations)),
+          base(std::move(base)),
           instruction_start_index(instruction_start_index),
           type(nullptr)
     {
@@ -260,13 +275,15 @@ public:
         assert(new_base);
         base = std::move(new_base);
     }
-    explicit Pointer_type_descriptor(std::size_t instruction_start_index) noexcept
-        : base(nullptr),
+    explicit Pointer_type_descriptor(std::vector<spirv::Decoration_with_parameters> decorations,
+                                     std::size_t instruction_start_index) noexcept
+        : Type_descriptor(std::move(decorations)),
+          base(nullptr),
           instruction_start_index(instruction_start_index),
           type(nullptr)
     {
     }
-    virtual ::LLVMTypeRef get_or_make_type(bool need_complete_structs) override
+    virtual ::LLVMTypeRef get_or_make_type() override
     {
         if(!type)
         {
@@ -276,7 +293,7 @@ public:
                     instruction_start_index,
                     instruction_start_index,
                     "attempting to create type from pointer forward declaration");
-            auto base_type = base->get_or_make_type(need_complete_structs);
+            auto base_type = base->get_or_make_type();
             constexpr unsigned default_address_space = 0;
             type = ::LLVMPointerType(base_type, default_address_space);
         }
@@ -299,27 +316,29 @@ private:
     bool is_var_arg;
 
 public:
-    explicit Function_type_descriptor(std::shared_ptr<Type_descriptor> return_type,
+    explicit Function_type_descriptor(std::vector<spirv::Decoration_with_parameters> decorations,
+                                      std::shared_ptr<Type_descriptor> return_type,
                                       std::vector<std::shared_ptr<Type_descriptor>> args,
                                       std::size_t instruction_start_index,
                                       bool is_var_arg = false) noexcept
-        : return_type(std::move(return_type)),
+        : Type_descriptor(std::move(decorations)),
+          return_type(std::move(return_type)),
           args(std::move(args)),
           type(nullptr),
           instruction_start_index(instruction_start_index),
           is_var_arg(is_var_arg)
     {
     }
-    virtual ::LLVMTypeRef get_or_make_type(bool need_complete_structs) override
+    virtual ::LLVMTypeRef get_or_make_type() override
     {
         if(!type)
         {
             Recursion_checker recursion_checker(recursion_checker_state, instruction_start_index);
             std::vector<::LLVMTypeRef> llvm_args;
             llvm_args.reserve(args.size());
-            auto llvm_return_type = return_type->get_or_make_type(need_complete_structs);
+            auto llvm_return_type = return_type->get_or_make_type();
             for(auto &arg : args)
-                llvm_args.push_back(arg->get_or_make_type(need_complete_structs));
+                llvm_args.push_back(arg->get_or_make_type());
             type = ::LLVMFunctionType(
                 llvm_return_type, llvm_args.data(), llvm_args.size(), is_var_arg);
         }
@@ -354,7 +373,9 @@ private:
     bool is_complete;
     Recursion_checker_state recursion_checker_state;
     std::size_t instruction_start_index;
-    void complete_type(bool need_complete_structs);
+    ::LLVMContextRef context;
+    ::LLVMTargetDataRef target_data;
+    void complete_type();
     void on_add_member(std::size_t added_member_index) noexcept
     {
         assert(!is_complete);
@@ -377,30 +398,34 @@ public:
     const std::vector<Member> &get_members(bool need_llvm_member_indexes)
     {
         if(need_llvm_member_indexes)
-            get_or_make_type(true);
+            get_or_make_type();
         return members;
     }
-    explicit Struct_type_descriptor(::LLVMContextRef context,
+    explicit Struct_type_descriptor(std::vector<spirv::Decoration_with_parameters> decorations,
+                                    ::LLVMContextRef context,
+                                    ::LLVMTargetDataRef target_data,
                                     const char *name,
                                     std::size_t instruction_start_index,
                                     std::vector<Member> members = {})
-        : members(std::move(members)),
+        : Type_descriptor(std::move(decorations)),
+          members(std::move(members)),
           builtin_members{},
           type(::LLVMStructCreateNamed(context, name)),
           is_complete(false),
-          instruction_start_index(instruction_start_index)
+          instruction_start_index(instruction_start_index),
+          context(context),
+          target_data(target_data)
     {
         for(std::size_t member_index = 0; member_index < members.size(); member_index++)
             on_add_member(member_index);
     }
-    virtual ::LLVMTypeRef get_or_make_type(bool need_complete_structs) override
+    virtual ::LLVMTypeRef get_or_make_type() override
     {
-        if(need_complete_structs && !is_complete)
+        if(!is_complete)
         {
             Recursion_checker recursion_checker(recursion_checker_state, instruction_start_index);
-            if(recursion_checker.is_nested_recursion())
-                need_complete_structs = false;
-            complete_type(need_complete_structs);
+            if(!recursion_checker.is_nested_recursion())
+                complete_type();
         }
         return type;
     }