#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
{
}
};
+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
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());
}
};
#include "util/optional.h"
#include "util/variant.h"
#include "util/enum.h"
+#include <functional>
+#include <list>
namespace vulkan_cpu
{
{
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
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)
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)
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);
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;
}
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(
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(
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;
}
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;
}
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));
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()))
{
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);
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:
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;
}
}
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:
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:
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,
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;
}
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;
}
}
};
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)
{
::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;
}
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;
}
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;
}
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)
{
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)
{
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);
}
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);
}
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);
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;
}