add alignment to generated llvm ir
authorJacob Lifshay <programmerjake@gmail.com>
Fri, 11 Aug 2017 22:12:53 +0000 (15:12 -0700)
committerJacob Lifshay <programmerjake@gmail.com>
Fri, 11 Aug 2017 22:12:53 +0000 (15:12 -0700)
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 d30fb513b6e8e5f4dcab0da9f53b9a786adbfa23..68293172df40ca87872ceefc88a05f0953d4227d 100644 (file)
@@ -24,6 +24,7 @@
 #include <llvm/Support/Host.h>
 #include <llvm/ExecutionEngine/SectionMemoryManager.h>
 #include <llvm-c/ExecutionEngine.h>
+#include <llvm/IR/DataLayout.h>
 #include <iostream>
 #include <cstdlib>
 #include <algorithm>
@@ -86,6 +87,11 @@ LLVM_string Target::get_host_cpu_features()
     return LLVM_string::from(retval);
 }
 
+std::size_t Target_data::get_pointer_alignment(::LLVMTargetDataRef td) noexcept
+{
+    return llvm::unwrap(td)->getPointerABIAlignment(0);
+}
+
 Target_machine Target_machine::create_native_target_machine()
 {
     auto target = Target::get_native_target();
index 91ccb0e95e466524197075c052b1ffeb00c812f6..ce81b9eb78b2a0125e3928a207ff3d605d549031 100644 (file)
@@ -241,6 +241,11 @@ struct Target_data : public Wrapper<::LLVMTargetDataRef, Target_data_deleter>
     {
         return Target_data(::LLVMCreateTargetData(str));
     }
+    static std::size_t get_pointer_alignment(::LLVMTargetDataRef td) noexcept;
+    std::size_t get_pointer_alignment() const noexcept
+    {
+        return get_pointer_alignment(get());
+    }
 };
 
 struct Target_machine_deleter
index 1f901fab1ff7a29e44111d65865bd136e3263916..4d3b409abb16146556d4d23dbdfd3b39d6773c0a 100644 (file)
@@ -389,8 +389,8 @@ void Struct_type_descriptor::complete_type()
                                    + 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(::LLVMGetTypeKind(member_type.type) == ::LLVMStructTypeKind
+           && ::LLVMIsOpaqueStruct(member_type.type))
         {
             if(dynamic_cast<const Struct_type_descriptor *>(member.type.get()))
                 throw Parser_error(instruction_start_index,
@@ -400,12 +400,12 @@ void Struct_type_descriptor::complete_type()
                                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(is_power_of_2(member_type.alignment));
+        std::size_t size = ::LLVMABISizeOfType(target_data, member_type.type);
+        if(member_type.alignment > total_alignment)
+            total_alignment = member_type.alignment;
+        member_descriptors.push_back(
+            Member_descriptor(member_type.alignment, size, member_type.type));
     }
     assert(member_descriptors.size() == members.size());
     assert(is_power_of_2(total_alignment));
@@ -436,8 +436,9 @@ void Struct_type_descriptor::complete_type()
     {
         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);
+    constexpr bool is_packed = true;
+    ::LLVMStructSetBody(type.type, member_types.data(), member_types.size(), is_packed);
+    type.alignment = total_alignment;
     is_complete = true;
 }
 
@@ -619,6 +620,7 @@ private:
     util::Enum_set<Capability> enabled_capabilities;
     ::LLVMContextRef context;
     ::LLVMTargetMachineRef target_machine;
+    ::LLVMTargetDataRef target_data;
     [[gnu::unused]] const std::uint64_t shader_id;
     std::string name_prefix_string;
     llvm_wrapper::Module module;
@@ -663,7 +665,7 @@ private:
         if(auto *type = dynamic_cast<Simple_type_descriptor *>(constant->type.get()))
         {
             auto llvm_type = type->get_or_make_type();
-            if(::LLVMGetTypeKind(llvm_type) != ::LLVMIntegerTypeKind)
+            if(::LLVMGetTypeKind(llvm_type.type) != ::LLVMIntegerTypeKind)
                 throw Parser_error(instruction_start_index,
                                    instruction_start_index,
                                    "id is not a constant integer");
@@ -684,7 +686,7 @@ private:
         if(auto *type = dynamic_cast<Simple_type_descriptor *>(constant->type.get()))
         {
             auto llvm_type = type->get_or_make_type();
-            if(::LLVMGetTypeKind(llvm_type) != ::LLVMIntegerTypeKind)
+            if(::LLVMGetTypeKind(llvm_type.type) != ::LLVMIntegerTypeKind)
                 throw Parser_error(instruction_start_index,
                                    instruction_start_index,
                                    "id is not a constant integer");
@@ -753,8 +755,8 @@ public:
         }
         module = llvm_wrapper::Module::create_with_target_machine(
             get_prefixed_name("module").c_str(), context, target_machine);
+        target_data = ::LLVMGetModuleDataLayout(module.get());
         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>(std::vector<Decoration_with_parameters>{},
@@ -765,8 +767,10 @@ public:
         assert(implicit_function_arguments.size() == 1);
         static_assert(io_struct_argument_index == 0, "");
         implicit_function_arguments[io_struct_argument_index] =
-            std::make_shared<Pointer_type_descriptor>(
-                std::vector<Decoration_with_parameters>{}, io_struct, no_instruction_index);
+            std::make_shared<Pointer_type_descriptor>(std::vector<Decoration_with_parameters>{},
+                                                      io_struct,
+                                                      no_instruction_index,
+                                                      target_data);
         inputs_struct =
             std::make_shared<Struct_type_descriptor>(std::vector<Decoration_with_parameters>{},
                                                      context,
@@ -2180,8 +2184,8 @@ void Spirv_to_llvm::handle_instruction_op_type_void(
     case Stage::calculate_types:
     {
         auto &state = get_id_state(instruction.result);
-        state.type = std::make_shared<Simple_type_descriptor>(state.decorations,
-                                                              ::LLVMVoidTypeInContext(context));
+        state.type = std::make_shared<Simple_type_descriptor>(
+            state.decorations, LLVM_type_and_alignment(::LLVMVoidTypeInContext(context), 1));
         break;
     }
     case Stage::generate_code:
@@ -2213,9 +2217,13 @@ void Spirv_to_llvm::handle_instruction_op_type_int(Op_type_int instruction,
         case 16:
         case 32:
         case 64:
+        {
+            auto type = ::LLVMIntTypeInContext(context, instruction.width);
             state.type = std::make_shared<Simple_type_descriptor>(
-                state.decorations, ::LLVMIntTypeInContext(context, instruction.width));
+                state.decorations,
+                LLVM_type_and_alignment(type, ::LLVMPreferredAlignmentOfType(target_data, type)));
             break;
+        }
         default:
             throw Parser_error(
                 instruction_start_index, instruction_start_index, "invalid int width");
@@ -2235,24 +2243,25 @@ void Spirv_to_llvm::handle_instruction_op_type_float(Op_type_float instruction,
     case Stage::calculate_types:
     {
         auto &state = get_id_state(instruction.result);
+        ::LLVMTypeRef type = nullptr;
         switch(instruction.width)
         {
         case 16:
-            state.type = std::make_shared<Simple_type_descriptor>(state.decorations,
-                                                                  ::LLVMHalfTypeInContext(context));
+            type = ::LLVMHalfTypeInContext(context);
             break;
         case 32:
-            state.type = std::make_shared<Simple_type_descriptor>(
-                state.decorations, ::LLVMFloatTypeInContext(context));
+            type = ::LLVMFloatTypeInContext(context);
             break;
         case 64:
-            state.type = std::make_shared<Simple_type_descriptor>(
-                state.decorations, ::LLVMDoubleTypeInContext(context));
+            type = ::LLVMDoubleTypeInContext(context);
             break;
         default:
             throw Parser_error(
                 instruction_start_index, instruction_start_index, "invalid float width");
         }
+        state.type = std::make_shared<Simple_type_descriptor>(
+            state.decorations,
+            LLVM_type_and_alignment(type, ::LLVMPreferredAlignmentOfType(target_data, type)));
         break;
     }
     case Stage::generate_code:
@@ -2271,7 +2280,8 @@ void Spirv_to_llvm::handle_instruction_op_type_vector(Op_type_vector instruction
         state.type = std::make_shared<Vector_type_descriptor>(
             state.decorations,
             get_type<Simple_type_descriptor>(instruction.component_type, instruction_start_index),
-            instruction.component_count);
+            instruction.component_count,
+            target_data);
         break;
     }
     case Stage::generate_code:
@@ -2290,7 +2300,8 @@ void Spirv_to_llvm::handle_instruction_op_type_matrix(Op_type_matrix instruction
         state.type = std::make_shared<Matrix_type_descriptor>(
             state.decorations,
             get_type<Vector_type_descriptor>(instruction.column_type, instruction_start_index),
-            instruction.column_count);
+            instruction.column_count,
+            target_data);
         break;
     }
     case Stage::generate_code:
@@ -2422,7 +2433,8 @@ void Spirv_to_llvm::handle_instruction_op_type_pointer(Op_type_pointer instructi
             state.type = std::make_shared<Pointer_type_descriptor>(
                 state.decorations,
                 get_type(instruction.type, instruction_start_index),
-                instruction_start_index);
+                instruction_start_index,
+                target_data);
         }
         else if(auto *pointer_type = dynamic_cast<Pointer_type_descriptor *>(state.type.get()))
         {
@@ -2464,7 +2476,8 @@ void Spirv_to_llvm::handle_instruction_op_type_function(Op_type_function instruc
             state.decorations,
             get_type(instruction.return_type, instruction_start_index),
             std::move(args),
-            instruction_start_index);
+            instruction_start_index,
+            target_data);
         break;
     }
     case Stage::generate_code:
@@ -2569,7 +2582,7 @@ void Spirv_to_llvm::handle_instruction_op_constant(Op_constant instruction,
         if(auto *simple_type = dynamic_cast<Simple_type_descriptor *>(type.get()))
         {
             auto llvm_type = simple_type->get_or_make_type();
-            switch(::LLVMGetTypeKind(llvm_type))
+            switch(::LLVMGetTypeKind(llvm_type.type))
             {
             case LLVMFloatTypeKind:
             {
@@ -2582,12 +2595,12 @@ void Spirv_to_llvm::handle_instruction_op_constant(Op_constant instruction,
                     ::LLVMConstBitCast(
                         ::LLVMConstInt(
                             ::LLVMInt32TypeInContext(context), instruction.value[0], false),
-                        llvm_type));
+                        llvm_type.type));
                 break;
             }
             case LLVMIntegerTypeKind:
             {
-                switch(::LLVMGetIntTypeWidth(llvm_type))
+                switch(::LLVMGetIntTypeWidth(llvm_type.type))
                 {
                 case 16:
                 {
@@ -2597,7 +2610,7 @@ void Spirv_to_llvm::handle_instruction_op_constant(Op_constant instruction,
                             instruction_start_index,
                             "OpConstant immediate value is wrong size for type int16");
                     state.constant = std::make_shared<Simple_constant_descriptor>(
-                        type, ::LLVMConstInt(llvm_type, instruction.value[0], false));
+                        type, ::LLVMConstInt(llvm_type.type, instruction.value[0], false));
                     break;
                 }
                 case 32:
@@ -2608,7 +2621,7 @@ void Spirv_to_llvm::handle_instruction_op_constant(Op_constant instruction,
                             instruction_start_index,
                             "OpConstant immediate value is wrong size for type int32");
                     state.constant = std::make_shared<Simple_constant_descriptor>(
-                        type, ::LLVMConstInt(llvm_type, instruction.value[0], false));
+                        type, ::LLVMConstInt(llvm_type.type, instruction.value[0], false));
                     break;
                 }
                 case 64:
@@ -2620,7 +2633,7 @@ void Spirv_to_llvm::handle_instruction_op_constant(Op_constant instruction,
                             "OpConstant immediate value is wrong size for type int64");
                     state.constant = std::make_shared<Simple_constant_descriptor>(
                         type,
-                        ::LLVMConstInt(llvm_type,
+                        ::LLVMConstInt(llvm_type.type,
                                        (static_cast<std::uint64_t>(instruction.value[1]) << 32)
                                            | instruction.value[0],
                                        false));
@@ -2632,7 +2645,7 @@ void Spirv_to_llvm::handle_instruction_op_constant(Op_constant instruction,
                         instruction_start_index,
                         instruction_start_index,
                         "unimplemented simple type for OpConstant: "
-                            + std::string(llvm_wrapper::print_type_to_string(llvm_type)));
+                            + std::string(llvm_wrapper::print_type_to_string(llvm_type.type)));
                 }
                 break;
             }
@@ -2649,7 +2662,7 @@ void Spirv_to_llvm::handle_instruction_op_constant(Op_constant instruction,
                                        (static_cast<std::uint64_t>(instruction.value[1]) << 32)
                                            | instruction.value[0],
                                        false),
-                        llvm_type));
+                        llvm_type.type));
                 break;
             }
             case LLVMHalfTypeKind:
@@ -2663,7 +2676,7 @@ void Spirv_to_llvm::handle_instruction_op_constant(Op_constant instruction,
                     ::LLVMConstBitCast(
                         ::LLVMConstInt(
                             ::LLVMInt16TypeInContext(context), instruction.value[0], false),
-                        llvm_type));
+                        llvm_type.type));
                 break;
             }
             default:
@@ -2672,7 +2685,7 @@ void Spirv_to_llvm::handle_instruction_op_constant(Op_constant instruction,
                     instruction_start_index,
                     instruction_start_index,
                     "unimplemented simple type for OpConstant: "
-                        + std::string(llvm_wrapper::print_type_to_string(llvm_type)));
+                        + std::string(llvm_wrapper::print_type_to_string(llvm_type.type)));
             }
             }
         }
@@ -2801,7 +2814,7 @@ void Spirv_to_llvm::handle_instruction_op_function(Op_function instruction,
             function_name = std::string(state.op_entry_points[0].entry_point.name);
         function_name = get_or_make_prefixed_name(std::move(function_name));
         auto function = ::LLVMAddFunction(
-            module.get(), function_name.c_str(), function_type->get_or_make_type());
+            module.get(), function_name.c_str(), function_type->get_or_make_type().type);
         llvm_wrapper::Module::set_function_target_machine(function, target_machine);
         state.function = Function_state(function_type, function, std::move(function_name));
         break;
@@ -3181,9 +3194,10 @@ void Spirv_to_llvm::handle_instruction_op_variable(Op_variable instruction,
             auto type =
                 get_type<Pointer_type_descriptor>(instruction.result_type, instruction_start_index);
             state.value = Value(::LLVMBuildAlloca(builder.get(),
-                                                  type->get_base_type()->get_or_make_type(),
+                                                  type->get_base_type()->get_or_make_type().type,
                                                   get_name(instruction.result).c_str()),
                                 type);
+            ::LLVMSetAlignment(state.value->value, type->get_base_type()->get_or_make_type().alignment);
             return;
         }
         case Storage_class::generic:
@@ -3250,6 +3264,7 @@ void Spirv_to_llvm::handle_instruction_op_load(Op_load instruction,
                                             get_id_state(instruction.pointer).value.value().value,
                                             get_name(instruction.result).c_str()),
                             get_type(instruction.result_type, instruction_start_index));
+        ::LLVMSetAlignment(state.value->value, state.value->type->get_or_make_type().alignment);
         break;
     }
     }
@@ -3278,9 +3293,11 @@ void Spirv_to_llvm::handle_instruction_op_store(Op_store instruction,
             throw Parser_error(instruction_start_index,
                                instruction_start_index,
                                "OpStore nontemporal not implemented");
-        ::LLVMBuildStore(builder.get(),
-                         get_id_state(instruction.object).value.value().value,
-                         get_id_state(instruction.pointer).value.value().value);
+        auto &object_value = get_id_state(instruction.object).value.value();
+        auto &pointer_value = get_id_state(instruction.pointer).value.value();
+        ::LLVMSetAlignment(::LLVMBuildStore(builder.get(),
+                         object_value.value,
+                         pointer_value.value), object_value.type->get_or_make_type().alignment);
         break;
     }
     }
@@ -3568,7 +3585,7 @@ void Spirv_to_llvm::handle_instruction_op_composite_construct(Op_composite_const
                     throw Parser_error(instruction_start_index,
                                        instruction_start_index,
                                        "too few inputs to construct a vector");
-                result_value = ::LLVMGetUndef(type.get_or_make_type());
+                result_value = ::LLVMGetUndef(type.get_or_make_type().type);
                 std::uint32_t insert_index = 0;
                 auto insert_element = [&](::LLVMValueRef element)
                 {
@@ -4017,7 +4034,7 @@ void Spirv_to_llvm::handle_instruction_op_convert_f_to_u(Op_convert_f_to_u instr
         state.value =
             Value(::LLVMBuildFPToUI(builder.get(),
                                     get_id_state(instruction.float_value).value.value().value,
-                                    result_type->get_or_make_type(),
+                                    result_type->get_or_make_type().type,
                                     get_name(instruction.result).c_str()),
                   result_type);
         break;
@@ -4054,7 +4071,7 @@ void Spirv_to_llvm::handle_instruction_op_convert_s_to_f(Op_convert_s_to_f instr
         state.value =
             Value(::LLVMBuildSIToFP(builder.get(),
                                     get_id_state(instruction.signed_value).value.value().value,
-                                    result_type->get_or_make_type(),
+                                    result_type->get_or_make_type().type,
                                     get_name(instruction.result).c_str()),
                   result_type);
         break;
@@ -4089,17 +4106,17 @@ void Spirv_to_llvm::handle_instruction_op_u_convert(Op_u_convert instruction,
                                    + std::string(get_enumerant_name(instruction.get_operation())));
         auto result_type = get_type(instruction.result_type, instruction_start_index);
         auto result_type_int_width = ::LLVMGetIntTypeWidth(
-            llvm_wrapper::get_scalar_or_vector_element_type(result_type->get_or_make_type()));
+            llvm_wrapper::get_scalar_or_vector_element_type(result_type->get_or_make_type().type));
         auto &arg = get_id_state(instruction.unsigned_value).value.value();
         auto arg_int_width = ::LLVMGetIntTypeWidth(
-            llvm_wrapper::get_scalar_or_vector_element_type(arg.type->get_or_make_type()));
+            llvm_wrapper::get_scalar_or_vector_element_type(arg.type->get_or_make_type().type));
         auto opcode = ::LLVMTrunc;
         if(result_type_int_width > arg_int_width)
             opcode = ::LLVMZExt;
         state.value = Value(::LLVMBuildCast(builder.get(),
                                             opcode,
                                             arg.value,
-                                            result_type->get_or_make_type(),
+                                            result_type->get_or_make_type().type,
                                             get_name(instruction.result).c_str()),
                             result_type);
         break;
@@ -4240,7 +4257,7 @@ void Spirv_to_llvm::handle_instruction_op_bitcast(Op_bitcast instruction,
         }
         state.value = Value(::LLVMBuildBitCast(builder.get(),
                                                arg.value,
-                                               result_type->get_or_make_type(),
+                                               result_type->get_or_make_type().type,
                                                get_name(instruction.result).c_str()),
                             result_type);
         break;
@@ -5485,9 +5502,10 @@ 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(), target.part_1, false),
-                          get_or_make_label(target.part_2));
+            ::LLVMAddCase(
+                switch_instruction,
+                ::LLVMConstInt(selector.type->get_or_make_type().type, target.part_1, false),
+                get_or_make_label(target.part_2));
         break;
     }
     }
index 475d521f225c60a6bddb4c62c60fe83b85d01958..cd01c09d74d4e4564e08985bc9ae01d5349d4d9a 100644 (file)
 #include <cassert>
 #include <type_traits>
 #include <utility>
+#include <cstddef>
 #include "llvm_wrapper/llvm_wrapper.h"
 
 namespace vulkan_cpu
 {
 namespace spirv_to_llvm
 {
+struct LLVM_type_and_alignment
+{
+    ::LLVMTypeRef type;
+    std::size_t alignment;
+    constexpr LLVM_type_and_alignment() noexcept : type(nullptr), alignment(0)
+    {
+    }
+    constexpr LLVM_type_and_alignment(::LLVMTypeRef type, std::size_t alignment) noexcept
+        : type(type),
+          alignment(alignment)
+    {
+    }
+};
+
 class Simple_type_descriptor;
 class Vector_type_descriptor;
 class Matrix_type_descriptor;
@@ -71,7 +86,7 @@ public:
     {
     }
     virtual ~Type_descriptor() = default;
-    virtual ::LLVMTypeRef get_or_make_type() = 0;
+    virtual LLVM_type_and_alignment get_or_make_type() = 0;
     virtual void visit(Type_visitor &type_visitor) = 0;
     void visit(Type_visitor &&type_visitor)
     {
@@ -163,16 +178,16 @@ public:
 class Simple_type_descriptor final : public Type_descriptor
 {
 private:
-    ::LLVMTypeRef type;
+    LLVM_type_and_alignment type;
 
 public:
     explicit Simple_type_descriptor(std::vector<spirv::Decoration_with_parameters> decorations,
-                                    ::LLVMTypeRef type) noexcept
+                                    LLVM_type_and_alignment type) noexcept
         : Type_descriptor(std::move(decorations)),
           type(type)
     {
     }
-    virtual ::LLVMTypeRef get_or_make_type() override
+    virtual LLVM_type_and_alignment get_or_make_type() override
     {
         return type;
     }
@@ -185,21 +200,35 @@ public:
 class Vector_type_descriptor final : public Type_descriptor
 {
 private:
-    ::LLVMTypeRef type;
+    LLVM_type_and_alignment type;
     std::shared_ptr<Simple_type_descriptor> element_type;
     std::size_t element_count;
 
 public:
     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
+                                    std::size_t element_count,
+                                    ::LLVMTargetDataRef target_data) noexcept
         : Type_descriptor(std::move(decorations)),
-          type(::LLVMVectorType(element_type->get_or_make_type(), element_count)),
+          type(make_vector_type(element_type, element_count, target_data)),
           element_type(std::move(element_type)),
           element_count(element_count)
     {
     }
-    virtual ::LLVMTypeRef get_or_make_type() override
+    static LLVM_type_and_alignment make_vector_type(
+        const std::shared_ptr<Simple_type_descriptor> &element_type,
+        std::size_t element_count,
+        ::LLVMTargetDataRef target_data)
+    {
+        auto llvm_element_type = element_type->get_or_make_type();
+        auto type = ::LLVMVectorType(llvm_element_type.type, element_count);
+        std::size_t alignment = ::LLVMPreferredAlignmentOfType(target_data, type);
+        constexpr std::size_t max_abi_alignment = alignof(std::max_align_t);
+        if(alignment > max_abi_alignment)
+            alignment = max_abi_alignment;
+        return {type, alignment};
+    }
+    virtual LLVM_type_and_alignment get_or_make_type() override
     {
         return type;
     }
@@ -220,22 +249,25 @@ public:
 class Matrix_type_descriptor final : public Type_descriptor
 {
 private:
-    ::LLVMTypeRef type;
+    LLVM_type_and_alignment type;
     std::shared_ptr<Vector_type_descriptor> column_type;
     std::size_t column_count;
 
 public:
     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
+                                    std::size_t column_count,
+                                    ::LLVMTargetDataRef target_data) noexcept
         : Type_descriptor(std::move(decorations)),
-          type(::LLVMVectorType(column_type->get_element_type()->get_or_make_type(),
-                                column_type->get_element_count() * column_count)),
+          type(Vector_type_descriptor::make_vector_type(column_type->get_element_type(),
+                                                        column_type->get_element_count()
+                                                            * column_count,
+                                                        target_data)),
           column_type(std::move(column_type)),
           column_count(column_count)
     {
     }
-    virtual ::LLVMTypeRef get_or_make_type() override
+    virtual LLVM_type_and_alignment get_or_make_type() override
     {
         return type;
     }
@@ -256,7 +288,7 @@ public:
 class Array_type_descriptor final : public Type_descriptor
 {
 private:
-    ::LLVMTypeRef type;
+    LLVM_type_and_alignment type;
     std::shared_ptr<Type_descriptor> element_type;
     std::size_t element_count;
     std::size_t instruction_start_index;
@@ -268,18 +300,20 @@ public:
                                    std::size_t element_count,
                                    std::size_t instruction_start_index) noexcept
         : Type_descriptor(std::move(decorations)),
-          type(::LLVMVectorType(element_type->get_or_make_type(), element_count)),
+          type(),
           element_type(std::move(element_type)),
           element_count(element_count),
           instruction_start_index(instruction_start_index)
     {
     }
-    virtual ::LLVMTypeRef get_or_make_type() override
+    virtual LLVM_type_and_alignment get_or_make_type() override
     {
-        if(!type)
+        if(!type.type)
         {
             Recursion_checker recursion_checker(recursion_checker_state, instruction_start_index);
-            type = ::LLVMArrayType(element_type->get_or_make_type(), element_count);
+            auto llvm_element_type = element_type->get_or_make_type();
+            type = LLVM_type_and_alignment(::LLVMArrayType(llvm_element_type.type, element_count),
+                                           llvm_element_type.alignment);
         }
         return type;
     }
@@ -302,17 +336,18 @@ class Pointer_type_descriptor final : public Type_descriptor
 private:
     std::shared_ptr<Type_descriptor> base;
     std::size_t instruction_start_index;
-    ::LLVMTypeRef type;
+    LLVM_type_and_alignment type;
     Recursion_checker_state recursion_checker_state;
 
 public:
     Pointer_type_descriptor(std::vector<spirv::Decoration_with_parameters> decorations,
                             std::shared_ptr<Type_descriptor> base,
-                            std::size_t instruction_start_index) noexcept
+                            std::size_t instruction_start_index,
+                            ::LLVMTargetDataRef target_data) noexcept
         : Type_descriptor(std::move(decorations)),
           base(std::move(base)),
           instruction_start_index(instruction_start_index),
-          type(nullptr)
+          type(nullptr, llvm_wrapper::Target_data::get_pointer_alignment(target_data))
     {
     }
     const std::shared_ptr<Type_descriptor> &get_base_type() const noexcept
@@ -326,16 +361,17 @@ public:
         base = std::move(new_base);
     }
     explicit Pointer_type_descriptor(std::vector<spirv::Decoration_with_parameters> decorations,
-                                     std::size_t instruction_start_index) noexcept
+                                     std::size_t instruction_start_index,
+                                     ::LLVMTargetDataRef target_data) noexcept
         : Type_descriptor(std::move(decorations)),
           base(nullptr),
           instruction_start_index(instruction_start_index),
-          type(nullptr)
+          type(nullptr, llvm_wrapper::Target_data::get_pointer_alignment(target_data))
     {
     }
-    virtual ::LLVMTypeRef get_or_make_type() override
+    virtual LLVM_type_and_alignment get_or_make_type() override
     {
-        if(!type)
+        if(!type.type)
         {
             Recursion_checker recursion_checker(recursion_checker_state, instruction_start_index);
             if(!base)
@@ -345,7 +381,7 @@ public:
                     "attempting to create type from pointer forward declaration");
             auto base_type = base->get_or_make_type();
             constexpr unsigned default_address_space = 0;
-            type = ::LLVMPointerType(base_type, default_address_space);
+            type.type = ::LLVMPointerType(base_type.type, default_address_space);
         }
         return type;
     }
@@ -360,7 +396,7 @@ class Function_type_descriptor final : public Type_descriptor
 private:
     std::shared_ptr<Type_descriptor> return_type;
     std::vector<std::shared_ptr<Type_descriptor>> args;
-    ::LLVMTypeRef type;
+    LLVM_type_and_alignment type;
     Recursion_checker_state recursion_checker_state;
     std::size_t instruction_start_index;
     bool is_var_arg;
@@ -370,27 +406,28 @@ public:
                                       std::shared_ptr<Type_descriptor> return_type,
                                       std::vector<std::shared_ptr<Type_descriptor>> args,
                                       std::size_t instruction_start_index,
+                                     ::LLVMTargetDataRef target_data,
                                       bool is_var_arg = false) noexcept
         : Type_descriptor(std::move(decorations)),
           return_type(std::move(return_type)),
           args(std::move(args)),
-          type(nullptr),
+          type(nullptr, llvm_wrapper::Target_data::get_pointer_alignment(target_data)),
           instruction_start_index(instruction_start_index),
           is_var_arg(is_var_arg)
     {
     }
-    virtual ::LLVMTypeRef get_or_make_type() override
+    virtual LLVM_type_and_alignment get_or_make_type() override
     {
-        if(!type)
+        if(!type.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();
             for(auto &arg : args)
-                llvm_args.push_back(arg->get_or_make_type());
-            type = ::LLVMFunctionType(
-                llvm_return_type, llvm_args.data(), llvm_args.size(), is_var_arg);
+                llvm_args.push_back(arg->get_or_make_type().type);
+            type.type = ::LLVMFunctionType(
+                llvm_return_type.type, llvm_args.data(), llvm_args.size(), is_var_arg);
         }
         return type;
     }
@@ -419,7 +456,7 @@ public:
 private:
     std::vector<Member> members;
     util::Enum_map<spirv::Built_in, std::size_t> builtin_members;
-    ::LLVMTypeRef type;
+    LLVM_type_and_alignment type;
     bool is_complete;
     Recursion_checker_state recursion_checker_state;
     std::size_t instruction_start_index;
@@ -460,7 +497,7 @@ public:
         : Type_descriptor(std::move(decorations)),
           members(std::move(members)),
           builtin_members{},
-          type(::LLVMStructCreateNamed(context, name)),
+          type(::LLVMStructCreateNamed(context, name), 0),
           is_complete(false),
           instruction_start_index(instruction_start_index),
           context(context),
@@ -469,7 +506,7 @@ public:
         for(std::size_t member_index = 0; member_index < members.size(); member_index++)
             on_add_member(member_index);
     }
-    virtual ::LLVMTypeRef get_or_make_type() override
+    virtual LLVM_type_and_alignment get_or_make_type() override
     {
         if(!is_complete)
         {