start adding graphics pipeline
authorJacob Lifshay <programmerjake@gmail.com>
Sat, 12 Aug 2017 00:34:28 +0000 (17:34 -0700)
committerJacob Lifshay <programmerjake@gmail.com>
Sat, 12 Aug 2017 00:34:28 +0000 (17:34 -0700)
src/CMakeLists.txt
src/demo/demo.cpp
src/llvm_wrapper/llvm_wrapper.h
src/pipeline/CMakeLists.txt [new file with mode: 0644]
src/pipeline/pipeline.cpp [new file with mode: 0644]
src/pipeline/pipeline.h [new file with mode: 0644]
src/spirv_to_llvm/CMakeLists.txt
src/spirv_to_llvm/spirv_to_llvm.cpp
src/spirv_to_llvm/spirv_to_llvm.h

index 70d3010eaf9421b8620ff05da414859bc157a928..5b8ffa1de171f41efefbf9a1e422eaf7d8c89a8d 100644 (file)
 #
 cmake_minimum_required(VERSION 3.1 FATAL_ERROR)
 include_directories(${CMAKE_CURRENT_SOURCE_DIR})
-add_subdirectory(spirv)
 add_subdirectory(demo)
-add_subdirectory(json)
-add_subdirectory(util)
 add_subdirectory(generate_spirv_parser)
+add_subdirectory(json)
 add_subdirectory(llvm_wrapper)
+add_subdirectory(pipeline)
+add_subdirectory(spirv)
 add_subdirectory(spirv_to_llvm)
+add_subdirectory(util)
index 0e50f9526c9f1097819fa660b2677a5b6755460c..e5e2b48b956e41defed27add0b10f925684065c9 100644 (file)
@@ -245,7 +245,9 @@ int test_main(int argc, char **argv)
                                                             llvm_target_machine.get(),
                                                             file->data(),
                                                             file->size(),
-                                                            next_module_id++);
+                                                            next_module_id++,
+                                                            spirv::Execution_model::vertex,
+                                                            "main");
         }
         catch(spirv::Parser_error &e)
         {
@@ -268,13 +270,10 @@ int test_main(int argc, char **argv)
                 return reinterpret_cast<std::uintptr_t>(symbol);
             },
             nullptr);
-        for(auto &entry_point : converted_module.entry_points)
-        {
-            auto function = reinterpret_cast<void *>(
-                orc_jit_stack.get_symbol_address(entry_point.entry_function_name.c_str()));
-            std::cerr << "entry point \"" << entry_point.name << "\": &"
-                      << entry_point.entry_function_name << " == " << function << std::endl;
-        }
+        auto function = reinterpret_cast<void *>(
+            orc_jit_stack.get_symbol_address(converted_module.entry_function_name.c_str()));
+        std::cerr << "entry point: " << converted_module.entry_function_name << ": " << function
+                  << std::endl;
     }
     else
     {
index ce81b9eb78b2a0125e3928a207ff3d605d549031..4f2b2068bf8bb4578c557960a467367fcc092310 100644 (file)
@@ -489,6 +489,177 @@ struct Orc_jit_stack : public Wrapper<::LLVMOrcJITStackRef, Orc_jit_stack_delete
         return get_symbol<T>(get(), symbol_name);
     }
 };
+
+template <typename T>
+struct Create_llvm_type
+{
+    static_assert(!std::is_same<T, T>::value, "Create_llvm_type not implemented for type T");
+    ::LLVMTypeRef operator()(::LLVMContextRef context) const = delete;
+};
+
+template <typename T>
+struct Create_llvm_type<const T> : public Create_llvm_type<T>
+{
+};
+
+template <>
+struct Create_llvm_type<void>
+{
+    ::LLVMTypeRef operator()(::LLVMContextRef context) const
+    {
+        return ::LLVMVoidTypeInContext(context);
+    }
+};
+
+template <>
+struct Create_llvm_type<bool>
+{
+    ::LLVMTypeRef operator()(::LLVMContextRef context) const
+    {
+        return ::LLVMIntTypeInContext(context,
+                                      std::numeric_limits<unsigned char>::digits * sizeof(bool));
+    }
+};
+
+template <>
+struct Create_llvm_type<char>
+{
+    ::LLVMTypeRef operator()(::LLVMContextRef context) const
+    {
+        return ::LLVMIntTypeInContext(context, std::numeric_limits<unsigned char>::digits);
+    }
+};
+
+template <>
+struct Create_llvm_type<unsigned char>
+{
+    ::LLVMTypeRef operator()(::LLVMContextRef context) const
+    {
+        return ::LLVMIntTypeInContext(context, std::numeric_limits<unsigned char>::digits);
+    }
+};
+
+template <>
+struct Create_llvm_type<signed char>
+{
+    ::LLVMTypeRef operator()(::LLVMContextRef context) const
+    {
+        return ::LLVMIntTypeInContext(context, std::numeric_limits<unsigned char>::digits);
+    }
+};
+
+template <>
+struct Create_llvm_type<short>
+{
+    ::LLVMTypeRef operator()(::LLVMContextRef context) const
+    {
+        return ::LLVMIntTypeInContext(context, std::numeric_limits<unsigned short>::digits);
+    }
+};
+
+template <>
+struct Create_llvm_type<unsigned short>
+{
+    ::LLVMTypeRef operator()(::LLVMContextRef context) const
+    {
+        return ::LLVMIntTypeInContext(context, std::numeric_limits<unsigned short>::digits);
+    }
+};
+
+template <>
+struct Create_llvm_type<int>
+{
+    ::LLVMTypeRef operator()(::LLVMContextRef context) const
+    {
+        return ::LLVMIntTypeInContext(context, std::numeric_limits<unsigned>::digits);
+    }
+};
+
+template <>
+struct Create_llvm_type<unsigned>
+{
+    ::LLVMTypeRef operator()(::LLVMContextRef context) const
+    {
+        return ::LLVMIntTypeInContext(context, std::numeric_limits<unsigned>::digits);
+    }
+};
+
+template <>
+struct Create_llvm_type<long>
+{
+    ::LLVMTypeRef operator()(::LLVMContextRef context) const
+    {
+        return ::LLVMIntTypeInContext(context, std::numeric_limits<unsigned long>::digits);
+    }
+};
+
+template <>
+struct Create_llvm_type<unsigned long>
+{
+    ::LLVMTypeRef operator()(::LLVMContextRef context) const
+    {
+        return ::LLVMIntTypeInContext(context, std::numeric_limits<unsigned long>::digits);
+    }
+};
+
+template <>
+struct Create_llvm_type<long long>
+{
+    ::LLVMTypeRef operator()(::LLVMContextRef context) const
+    {
+        return ::LLVMIntTypeInContext(context, std::numeric_limits<unsigned long long>::digits);
+    }
+};
+
+template <>
+struct Create_llvm_type<unsigned long long>
+{
+    ::LLVMTypeRef operator()(::LLVMContextRef context) const
+    {
+        return ::LLVMIntTypeInContext(context, std::numeric_limits<unsigned long long>::digits);
+    }
+};
+
+template <typename T>
+struct Create_llvm_type<T *>
+{
+    ::LLVMTypeRef operator()(::LLVMContextRef context) const
+    {
+        constexpr unsigned default_address_space = 0;
+        return ::LLVMPointerType(Create_llvm_type<T>()(context), default_address_space);
+    }
+};
+
+template <>
+struct Create_llvm_type<void *> : public Create_llvm_type<unsigned char *>
+{
+};
+
+template <>
+struct Create_llvm_type<const void *> : public Create_llvm_type<const unsigned char *>
+{
+};
+
+template <typename T, std::size_t N>
+struct Create_llvm_type<T[N]>
+{
+    ::LLVMTypeRef operator()(::LLVMContextRef context) const
+    {
+        return ::LLVMArrayType(Create_llvm_type<T>()(context), N);
+    }
+};
+
+template <typename Return_type, typename ...Args>
+struct Create_llvm_type<Return_type (*)(Args...)>
+{
+    ::LLVMTypeRef operator()(::LLVMContextRef context) const
+    {
+        ::LLVMTypeRef arguments[] = {Create_llvm_type<Args>()(context)...};
+        constexpr bool is_var_arg = false;
+        return ::LLVMFunctionType(
+            Create_llvm_type<Return_type>()(context), arguments, sizeof...(Args), is_var_arg);
+    }
+};
 }
 }
 
diff --git a/src/pipeline/CMakeLists.txt b/src/pipeline/CMakeLists.txt
new file mode 100644 (file)
index 0000000..e4dc438
--- /dev/null
@@ -0,0 +1,25 @@
+# Copyright 2017 Jacob Lifshay
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to deal
+# in the Software without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in all
+# copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+# SOFTWARE.
+#
+cmake_minimum_required(VERSION 3.1 FATAL_ERROR)
+
+set(sources pipeline.cpp)
+add_library(vulkan_cpu_pipeline STATIC ${sources})
+target_link_libraries(vulkan_cpu_pipeline vulkan_cpu_spirv_to_llvm vulkan_cpu_util vulkan_cpu_spirv vulkan_cpu_llvm_wrapper)
diff --git a/src/pipeline/pipeline.cpp b/src/pipeline/pipeline.cpp
new file mode 100644 (file)
index 0000000..fccfeb3
--- /dev/null
@@ -0,0 +1,23 @@
+/*
+ * Copyright 2017 Jacob Lifshay
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ */
+#include "pipeline.h"
diff --git a/src/pipeline/pipeline.h b/src/pipeline/pipeline.h
new file mode 100644 (file)
index 0000000..c31a8dd
--- /dev/null
@@ -0,0 +1,119 @@
+/*
+ * Copyright 2017 Jacob Lifshay
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ */
+#ifndef PIPELINE_PIPELINE_H_
+#define PIPELINE_PIPELINE_H_
+
+#include <memory>
+#include <cstdint>
+#include "llvm_wrapper/llvm_wrapper.h"
+
+namespace vulkan_cpu
+{
+namespace pipeline
+{
+class Pipeline
+{
+    Pipeline(const Pipeline &) = delete;
+    Pipeline &operator=(const Pipeline &) = delete;
+
+public:
+    typedef std::uintptr_t Handle;
+
+public:
+    constexpr Pipeline() noexcept
+    {
+    }
+    virtual ~Pipeline() = default;
+    static std::unique_ptr<Pipeline> move_from_handle(Handle pipeline) noexcept
+    {
+        return std::unique_ptr<Pipeline>(from_handle(pipeline));
+    }
+    static Pipeline *from_handle(Handle pipeline) noexcept
+    {
+        return reinterpret_cast<Pipeline *>(pipeline);
+    }
+};
+
+inline Pipeline::Handle to_handle(Pipeline *pipeline) noexcept
+{
+    return reinterpret_cast<Pipeline::Handle>(pipeline);
+}
+
+inline Pipeline::Handle move_to_handle(std::unique_ptr<Pipeline> pipeline) noexcept
+{
+    return to_handle(pipeline.release());
+}
+
+class Graphics_pipeline final : public Pipeline
+{
+public:
+#warning finish adding draw function parameters
+    typedef void (*Vertex_shader_function)(std::uint32_t vertex_start_index,
+                                           std::uint32_t vertex_count,
+                                           std::uint32_t instance_id,
+                                           void *output_buffer);
+
+public:
+    const Vertex_shader_function get_vertex_shader_function() const noexcept
+    {
+        return vertex_shader_function;
+    }
+#warning finish implementing Graphics_pipeline::make
+    static std::unique_ptr<Graphics_pipeline> make();
+    static std::unique_ptr<Graphics_pipeline> move_from_handle(Handle pipeline) noexcept
+    {
+        return std::unique_ptr<Graphics_pipeline>(from_handle(pipeline));
+    }
+    static Graphics_pipeline *from_handle(Handle pipeline) noexcept
+    {
+        auto *retval = reinterpret_cast<Pipeline *>(pipeline);
+        assert(!retval || dynamic_cast<Graphics_pipeline *>(retval));
+        return static_cast<Graphics_pipeline *>(retval);
+    }
+
+private:
+    Graphics_pipeline(std::shared_ptr<void> state,
+                      Vertex_shader_function vertex_shader_function) noexcept
+        : state(std::move(state)),
+          vertex_shader_function(vertex_shader_function)
+    {
+    }
+
+private:
+    std::shared_ptr<void> state;
+    Vertex_shader_function vertex_shader_function;
+};
+
+inline Pipeline::Handle to_handle(Graphics_pipeline *pipeline) noexcept
+{
+    return to_handle(static_cast<Pipeline *>(pipeline));
+}
+
+inline Pipeline::Handle move_to_handle(std::unique_ptr<Graphics_pipeline> pipeline) noexcept
+{
+    return to_handle(pipeline.release());
+}
+}
+}
+
+#endif // PIPELINE_PIPELINE_H_
index 64eb3cf44bcb2fcfcdb580ff22803bd6695ac67f..631cb15aade141e7bc68a248f2775d0747df941d 100644 (file)
@@ -22,4 +22,4 @@ cmake_minimum_required(VERSION 3.1 FATAL_ERROR)
 
 set(sources spirv_to_llvm.cpp)
 add_library(vulkan_cpu_spirv_to_llvm STATIC ${sources})
-target_link_libraries(vulkan_cpu_spirv_to_llvm vulkan_cpu_util vulkan_cpu_spirv vulkan_cpu_llvm_wrapper)
+target_link_libraries(vulkan_cpu_spirv_to_llvm vulkan_cpu_util vulkan_cpu_spirv vulkan_cpu_llvm_wrapper vulkan_cpu_pipeline)
index 560ed8ab4c9bd7a87f276e04598222208e994ae3..09ea92e758d217277f651dd7088706059f26ec3f 100644 (file)
@@ -24,6 +24,7 @@
 #include "util/optional.h"
 #include "util/variant.h"
 #include "util/enum.h"
+#include "pipeline/pipeline.h"
 #include <functional>
 #include <list>
 #include <iostream>
@@ -637,6 +638,8 @@ private:
     llvm_wrapper::Builder builder;
     util::optional<Last_merge_instruction> last_merge_instruction;
     std::list<std::function<void()>> function_entry_block_handlers;
+    spirv::Execution_model execution_model;
+    util::string_view entry_point_name;
 
 private:
     Id_state &get_id_state(Id id)
@@ -712,11 +715,11 @@ private:
         {
             auto &function = get_id_state(current_function_id).function.value();
             state.label = Label_state(::LLVMAppendBasicBlockInContext(
-                context, function.function, get_prefixed_name(get_name(id)).c_str()));
+                context, function.function, get_prefixed_name(get_name(id), false).c_str()));
         }
         return state.label->basic_block;
     }
-    std::string get_prefixed_name(std::string name) const
+    std::string get_prefixed_name(std::string name, bool is_builtin_name) const
     {
         if(!name.empty())
         {
@@ -727,11 +730,13 @@ private:
                 // ensure name doesn't conflict with names generated by get_or_make_prefixed_name
                 name.insert(0, "_");
             }
+            if(!is_builtin_name)
+                name.insert(0, "_"); // ensure user names don't conflict with builtin names
             return name_prefix_string + std::move(name);
         }
         return name;
     }
-    std::string get_or_make_prefixed_name(std::string name)
+    std::string get_or_make_prefixed_name(std::string name, bool is_builtin_name)
     {
         if(name.empty())
         {
@@ -739,14 +744,21 @@ private:
             ss << name_prefix_string << next_name_index++;
             return ss.str();
         }
-        return get_prefixed_name(std::move(name));
+        return get_prefixed_name(std::move(name), is_builtin_name);
     }
 
 public:
     explicit Spirv_to_llvm(::LLVMContextRef context,
                            ::LLVMTargetMachineRef target_machine,
-                           std::uint64_t shader_id)
-        : context(context), target_machine(target_machine), shader_id(shader_id), stage()
+                           std::uint64_t shader_id,
+                           spirv::Execution_model execution_model,
+                           util::string_view entry_point_name)
+        : context(context),
+          target_machine(target_machine),
+          shader_id(shader_id),
+          stage(),
+          execution_model(execution_model),
+          entry_point_name(entry_point_name)
     {
         {
             std::ostringstream ss;
@@ -754,7 +766,7 @@ public:
             name_prefix_string = ss.str();
         }
         module = llvm_wrapper::Module::create_with_target_machine(
-            get_prefixed_name("module").c_str(), context, target_machine);
+            get_prefixed_name("module", true).c_str(), context, target_machine);
         target_data = ::LLVMGetModuleDataLayout(module.get());
         builder = llvm_wrapper::Builder::create(context);
         constexpr std::size_t no_instruction_index = 0;
@@ -762,7 +774,7 @@ public:
             std::make_shared<Struct_type_descriptor>(std::vector<Decoration_with_parameters>{},
                                                      context,
                                                      target_data,
-                                                     get_prefixed_name("Io_struct").c_str(),
+                                                     get_prefixed_name("Io_struct", true).c_str(),
                                                      no_instruction_index);
         assert(implicit_function_arguments.size() == 1);
         static_assert(io_struct_argument_index == 0, "");
@@ -775,17 +787,86 @@ public:
             std::make_shared<Struct_type_descriptor>(std::vector<Decoration_with_parameters>{},
                                                      context,
                                                      target_data,
-                                                     get_prefixed_name("Inputs").c_str(),
+                                                     get_prefixed_name("Inputs", true).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>(std::vector<Decoration_with_parameters>{},
                                                      context,
                                                      target_data,
-                                                     get_prefixed_name("Outputs").c_str(),
+                                                     get_prefixed_name("Outputs", true).c_str(),
                                                      no_instruction_index);
         outputs_member = io_struct->add_member(Struct_type_descriptor::Member({}, outputs_struct));
     }
+    std::string generate_entry_function(Op_entry_point_state &entry_point)
+    {
+        ::LLVMValueRef function = nullptr;
+        switch(execution_model)
+        {
+        case spirv::Execution_model::vertex:
+        {
+            typedef void (*Vertex_shader_function)(std::uint32_t vertex_start_index,
+                                                   std::uint32_t vertex_count,
+                                                   std::uint32_t instance_id,
+                                                   void *output_buffer);
+            constexpr std::size_t arg_vertex_start_index = 0;
+            constexpr std::size_t arg_vertex_count = 1;
+            constexpr std::size_t arg_instance_id = 2;
+            constexpr std::size_t arg_output_buffer = 3;
+            static_assert(std::is_same<Vertex_shader_function,
+                                       pipeline::Graphics_pipeline::Vertex_shader_function>::value,
+                          "vertex shader function signature mismatch");
+            auto function_type = llvm_wrapper::Create_llvm_type<Vertex_shader_function>()(context);
+            function = ::LLVMAddFunction(
+                module.get(), get_prefixed_name("vertex_entry_point", true).c_str(), function_type);
+            llvm_wrapper::Module::set_function_target_machine(function, target_machine);
+            static_cast<void>(arg_vertex_start_index);
+            static_cast<void>(arg_vertex_count);
+            static_cast<void>(arg_instance_id);
+            static_cast<void>(arg_output_buffer);
+#warning finish implementing vertex execution model
+            break;
+        }
+        case spirv::Execution_model::tessellation_control:
+#warning implement execution model
+            throw Parser_error(entry_point.instruction_start_index,
+                               entry_point.instruction_start_index,
+                               "unimplemented execution model: "
+                                   + std::string(spirv::get_enumerant_name(execution_model)));
+        case spirv::Execution_model::tessellation_evaluation:
+#warning implement execution model
+            throw Parser_error(entry_point.instruction_start_index,
+                               entry_point.instruction_start_index,
+                               "unimplemented execution model: "
+                                   + std::string(spirv::get_enumerant_name(execution_model)));
+        case spirv::Execution_model::geometry:
+#warning implement execution model
+            throw Parser_error(entry_point.instruction_start_index,
+                               entry_point.instruction_start_index,
+                               "unimplemented execution model: "
+                                   + std::string(spirv::get_enumerant_name(execution_model)));
+        case spirv::Execution_model::fragment:
+#warning implement execution model
+            throw Parser_error(entry_point.instruction_start_index,
+                               entry_point.instruction_start_index,
+                               "unimplemented execution model: "
+                                   + std::string(spirv::get_enumerant_name(execution_model)));
+        case spirv::Execution_model::gl_compute:
+#warning implement execution model
+            throw Parser_error(entry_point.instruction_start_index,
+                               entry_point.instruction_start_index,
+                               "unimplemented execution model: "
+                                   + std::string(spirv::get_enumerant_name(execution_model)));
+        case spirv::Execution_model::kernel:
+            // TODO: implement execution model as extension
+            throw Parser_error(entry_point.instruction_start_index,
+                               entry_point.instruction_start_index,
+                               "unimplemented execution model: "
+                                   + std::string(spirv::get_enumerant_name(execution_model)));
+        }
+        assert(function);
+        return ::LLVMGetValueName(function);
+    }
     Converted_module run(const Word *shader_words, std::size_t shader_size)
     {
         stage = Stage::calculate_types;
@@ -798,7 +879,7 @@ public:
 #warning finish Spirv_to_llvm::run
         stage = Stage::generate_code;
         spirv::parse(*this, shader_words, shader_size);
-        std::vector<Converted_module::Entry_point> entry_points;
+        std::string entry_function_name;
         for(auto &id_state : id_states)
         {
             for(auto &entry_point : id_state.op_entry_points)
@@ -807,19 +888,35 @@ public:
                     throw Parser_error(entry_point.instruction_start_index,
                                        entry_point.instruction_start_index,
                                        "No definition for function referenced in OpEntryPoint");
-                entry_points.push_back(
-                    Converted_module::Entry_point(std::string(entry_point.entry_point.name),
-                                                  id_state.function->output_function_name));
+                if(entry_point.entry_point.name != entry_point_name
+                   || entry_point.entry_point.execution_model != execution_model)
+                    continue;
+                if(!entry_function_name.empty())
+                    throw Parser_error(entry_point.instruction_start_index,
+                                       entry_point.instruction_start_index,
+                                       "duplicate entry point: "
+                                           + std::string(spirv::get_enumerant_name(execution_model))
+                                           + " \""
+                                           + std::string(entry_point_name)
+                                           + "\"");
+                entry_function_name = generate_entry_function(entry_point);
             }
         }
-        Converted_module retval(std::move(module),
-                                std::move(entry_points),
+        if(entry_function_name.empty())
+            throw Parser_error(0,
+                               0,
+                               "can't find entry point: "
+                                   + std::string(spirv::get_enumerant_name(execution_model))
+                                   + " \""
+                                   + std::string(entry_point_name)
+                                   + "\"");
+        return Converted_module(std::move(module),
+                                std::move(entry_function_name),
                                 std::move(io_struct),
                                 inputs_member,
                                 std::move(inputs_struct),
                                 outputs_member,
                                 std::move(outputs_struct));
-        return retval;
     }
     virtual void handle_header(unsigned version_number_major,
                                unsigned version_number_minor,
@@ -2430,7 +2527,7 @@ void Spirv_to_llvm::handle_instruction_op_type_struct(Op_type_struct instruction
             state.decorations,
             context,
             ::LLVMGetModuleDataLayout(module.get()),
-            get_prefixed_name(get_name(instruction.result)).c_str(),
+            get_prefixed_name(get_name(instruction.result), false).c_str(),
             instruction_start_index,
             std::move(members));
         break;
@@ -2852,7 +2949,7 @@ void Spirv_to_llvm::handle_instruction_op_function(Op_function instruction,
         auto function_name = get_name(current_function_id);
         if(function_name.empty() && state.op_entry_points.size() == 1)
             function_name = std::string(state.op_entry_points[0].entry_point.name);
-        function_name = get_or_make_prefixed_name(std::move(function_name));
+        function_name = get_or_make_prefixed_name(std::move(function_name), false);
         auto function = ::LLVMAddFunction(
             module.get(), function_name.c_str(), function_type->get_or_make_type().type);
         llvm_wrapper::Module::set_function_target_machine(function, target_machine);
@@ -8810,11 +8907,14 @@ void Spirv_to_llvm::handle_instruction_glsl_std_450_op_n_clamp(Glsl_std_450_op_n
 
 Converted_module spirv_to_llvm(::LLVMContextRef context,
                                ::LLVMTargetMachineRef target_machine,
-                               const Word *shader_words,
+                               const spirv::Word *shader_words,
                                std::size_t shader_size,
-                               std::uint64_t shader_id)
+                               std::uint64_t shader_id,
+                               spirv::Execution_model execution_model,
+                               util::string_view entry_point_name)
 {
-    return Spirv_to_llvm(context, target_machine, shader_id).run(shader_words, shader_size);
+    return Spirv_to_llvm(context, target_machine, shader_id, execution_model, entry_point_name)
+        .run(shader_words, shader_size);
 }
 }
 }
index cd01c09d74d4e4564e08985bc9ae01d5349d4d9a..602ed09b2914b30bba954d7611112cbe880d79ac 100644 (file)
@@ -406,7 +406,7 @@ 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,
+                                      ::LLVMTargetDataRef target_data,
                                       bool is_var_arg = false) noexcept
         : Type_descriptor(std::move(decorations)),
           return_type(std::move(return_type)),
@@ -559,36 +559,23 @@ public:
 
 struct Converted_module
 {
-    struct Entry_point
-    {
-        std::string name;
-        std::string entry_function_name;
-#warning finish filling in Entry_point
-        explicit Entry_point(std::string name, std::string entry_function_name) noexcept
-            : name(std::move(name)),
-              entry_function_name(std::move(entry_function_name))
-        {
-        }
-    };
     llvm_wrapper::Module module;
-    std::vector<Entry_point> entry_points;
+    std::string entry_function_name;
     std::shared_ptr<Struct_type_descriptor> io_struct;
     std::size_t inputs_member;
     std::shared_ptr<Struct_type_descriptor> inputs_struct;
     std::size_t outputs_member;
     std::shared_ptr<Struct_type_descriptor> outputs_struct;
-    Converted_module() : module(), entry_points()
-    {
-    }
+    Converted_module() = default;
     explicit Converted_module(llvm_wrapper::Module module,
-                              std::vector<Entry_point> entry_points,
+                              std::string entry_function_name,
                               std::shared_ptr<Struct_type_descriptor> io_struct,
                               std::size_t inputs_member,
                               std::shared_ptr<Struct_type_descriptor> inputs_struct,
                               std::size_t outputs_member,
                               std::shared_ptr<Struct_type_descriptor> outputs_struct) noexcept
         : module(std::move(module)),
-          entry_points(std::move(entry_points)),
+          entry_function_name(std::move(entry_function_name)),
           io_struct(std::move(io_struct)),
           inputs_member(inputs_member),
           inputs_struct(std::move(inputs_struct)),
@@ -604,7 +591,9 @@ Converted_module spirv_to_llvm(::LLVMContextRef context,
                                ::LLVMTargetMachineRef target_machine,
                                const spirv::Word *shader_words,
                                std::size_t shader_size,
-                               std::uint64_t shader_id);
+                               std::uint64_t shader_id,
+                               spirv::Execution_model execution_model,
+                               util::string_view entry_point_name);
 }
 }