From: Jacob Lifshay Date: Fri, 21 Jul 2017 19:35:45 +0000 (-0700) Subject: working on implementing Spirv_to_llvm -- need to fix SIGSEGV bug X-Git-Tag: gsoc-2017~63 X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=c8d06fe0b2aef60709d26e170e9dd3ab5e94b3d6;p=kazan.git working on implementing Spirv_to_llvm -- need to fix SIGSEGV bug --- diff --git a/src/llvm_wrapper/CMakeLists.txt b/src/llvm_wrapper/CMakeLists.txt index 03f5ad9..0509ad7 100644 --- a/src/llvm_wrapper/CMakeLists.txt +++ b/src/llvm_wrapper/CMakeLists.txt @@ -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}) diff --git a/src/llvm_wrapper/llvm_wrapper.cpp b/src/llvm_wrapper/llvm_wrapper.cpp index 2d65604..e7f6098 100644 --- a/src/llvm_wrapper/llvm_wrapper.cpp +++ b/src/llvm_wrapper/llvm_wrapper.cpp @@ -21,7 +21,10 @@ * */ #include "llvm_wrapper.h" +#include #include +#include +#include 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 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()); +} } } diff --git a/src/llvm_wrapper/llvm_wrapper.h b/src/llvm_wrapper/llvm_wrapper.h index 94d0121..565c335 100644 --- a/src/llvm_wrapper/llvm_wrapper.h +++ b/src/llvm_wrapper/llvm_wrapper.h @@ -24,12 +24,16 @@ #define LLVM_WRAPPER_LLVM_WRAPPER_H_ #include +#include +#include +#include #include #include #include #include #include #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 +{ +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(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_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(&retval); + if(!target) + throw std::runtime_error( + "can't find target for native triple (" + std::string(native_triple) + "): " + + util::get(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 +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()); } }; diff --git a/src/spirv_to_llvm/spirv_to_llvm.cpp b/src/spirv_to_llvm/spirv_to_llvm.cpp index 9ef798d..581545a 100644 --- a/src/spirv_to_llvm/spirv_to_llvm.cpp +++ b/src/spirv_to_llvm/spirv_to_llvm.cpp @@ -24,6 +24,8 @@ #include "util/optional.h" #include "util/variant.h" #include "util/enum.h" +#include +#include 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_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(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(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; + std::list> 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( - context, (name_prefix + "Io_struct").c_str(), no_instruction_index); + io_struct = + std::make_shared(std::vector{}, + 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( - context, (name_prefix + "Inputs").c_str(), no_instruction_index); + inputs_struct = + std::make_shared(std::vector{}, + 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( - context, (name_prefix + "Outputs").c_str(), no_instruction_index); + outputs_struct = + std::make_shared(std::vector{}, + 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(::LLVMVoidTypeInContext(context)); + { + auto &state = get_id_state(instruction.result); + state.type = std::make_shared(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( - ::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(::LLVMHalfTypeInContext(context)); + state.type = std::make_shared(state.decorations, + ::LLVMHalfTypeInContext(context)); break; case 32: - state.type = - std::make_shared(::LLVMFloatTypeInContext(context)); + state.type = std::make_shared( + state.decorations, ::LLVMFloatTypeInContext(context)); break; case 64: - state.type = - std::make_shared(::LLVMDoubleTypeInContext(context)); + state.type = std::make_shared( + 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( + { + auto &state = get_id_state(instruction.result); + state.type = std::make_shared( + state.decorations, get_type(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( + { + auto &state = get_id_state(instruction.result); + state.type = std::make_shared( + state.decorations, get_type(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( + 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( - 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(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( + auto &state = get_id_state(instruction.result); + state.type = std::make_shared( + 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(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(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(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(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(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; } } diff --git a/src/spirv_to_llvm/spirv_to_llvm.h b/src/spirv_to_llvm/spirv_to_llvm.h index c568323..5bc229a 100644 --- a/src/spirv_to_llvm/spirv_to_llvm.h +++ b/src/spirv_to_llvm/spirv_to_llvm.h @@ -61,9 +61,15 @@ public: }; public: - Type_descriptor() noexcept = default; + const std::vector decorations; + +public: + explicit Type_descriptor(std::vector 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 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 element_type, + explicit Vector_type_descriptor(std::vector decorations, + std::shared_ptr 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 column_type, + explicit Matrix_type_descriptor(std::vector decorations, + std::shared_ptr 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 base, + Pointer_type_descriptor(std::vector decorations, + std::shared_ptr 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 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 return_type, + explicit Function_type_descriptor(std::vector decorations, + std::shared_ptr return_type, std::vector> 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 &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 decorations, + ::LLVMContextRef context, + ::LLVMTargetDataRef target_data, const char *name, std::size_t instruction_start_index, std::vector 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; }