working on implementing generate_spirv_parser
authorJacob Lifshay <programmerjake@gmail.com>
Fri, 7 Jul 2017 12:00:17 +0000 (05:00 -0700)
committerJacob Lifshay <programmerjake@gmail.com>
Fri, 7 Jul 2017 12:00:17 +0000 (05:00 -0700)
src/generate_spirv_parser/CMakeLists.txt
src/generate_spirv_parser/ast.h
src/generate_spirv_parser/generate.cpp
src/generate_spirv_parser/instruction_properties.cpp [new file with mode: 0644]
src/generate_spirv_parser/instruction_properties.h [new file with mode: 0644]

index 23beaad311ec9fb9bb44f575eb8db32c4e23a140..14ac6a897dcdad3d5e22fb507f796fe72fb34d6d 100644 (file)
@@ -22,6 +22,7 @@ cmake_minimum_required(VERSION 3.1 FATAL_ERROR)
 set(sources ast.cpp
             generate.cpp
             generate_spirv_parser.cpp
+            instruction_properties.cpp
             parser.cpp
             patch.cpp)
 add_executable(generate_spirv_parser ${sources})
index b5b972b0775942978d454308e21d874b325538a7..331eba4f2bd8708dac7441985d42f823b98c15f0 100644 (file)
@@ -180,11 +180,12 @@ struct Instructions
                     std::uint32_t opcode,
                     Operands operands,
                     Capabilities capabilities,
-                    Extensions extensions) noexcept : opname(std::move(opname)),
-                                                      opcode(opcode),
-                                                      operands(std::move(operands)),
-                                                      capabilities(std::move(capabilities)),
-                                                      extensions(std::move(extensions))
+                    Extensions extensions) noexcept
+            : opname(std::move(opname)),
+              opcode(opcode),
+              operands(std::move(operands)),
+              capabilities(std::move(capabilities)),
+              extensions(std::move(extensions))
         {
         }
         json::ast::Value to_json() const;
index 1f478e97f9b32d38e498de1087bc990e18d94500..e08bd8f8db84dccedb5bccc2afd2024e4f16648a 100644 (file)
@@ -22,6 +22,7 @@
  */
 #include "generate.h"
 #include "json/json.h"
+#include "instruction_properties.h"
 #include <fstream>
 #include <iostream>
 #include <cassert>
@@ -359,6 +360,7 @@ enum class Output_part
     literal_types,
     enum_structs,
     composite_types,
+    instruction_structs,
     namespaces_end,
     include_guard_end,
 
@@ -388,6 +390,7 @@ vulkan_cpu_util_generate_enum_traits(Output_part,
                                      Output_part::literal_types,
                                      Output_part::enum_structs,
                                      Output_part::composite_types,
+                                     Output_part::instruction_structs,
                                      Output_part::namespaces_end,
                                      Output_part::include_guard_end,
                                      Output_part::struct_opening,
@@ -734,6 +737,7 @@ namespace spirv
         detail::Generated_output_stream literal_types;
         std::list<Output_struct> composite_types;
         std::list<Output_struct> enum_structs;
+        std::list<Output_struct> instruction_structs;
         explicit Spirv_h(const util::filesystem::path &file_path)
             : Header_file_base(file_path),
               basic_types(file_path),
@@ -752,6 +756,8 @@ namespace spirv
             register_output_part(Output_part::literal_types, &Spirv_h::literal_types);
             register_output_part(Output_part::enum_structs, &Spirv_h::write_enum_structs);
             register_output_part(Output_part::composite_types, &Spirv_h::write_composite_types);
+            register_output_part(Output_part::instruction_structs,
+                                 &Spirv_h::write_instruction_structs);
         }
         void write_enum_structs(detail::Generated_output_stream &output_stream, Output_part) const
         {
@@ -770,6 +776,15 @@ namespace spirv
                 composite_type.write_whole_output(output_stream);
             }
         }
+        void write_instruction_structs(detail::Generated_output_stream &output_stream,
+                                       Output_part) const
+        {
+            for(auto &instruction_struct : instruction_structs)
+            {
+                output_stream << "\n";
+                instruction_struct.write_whole_output(output_stream);
+            }
+        }
         void write_literal_kinds(State &state)
         {
             for(auto &operand_kind : state.top_level.operand_kinds.operand_kinds)
@@ -1041,6 +1056,41 @@ constexpr util::Enum_set<)" << state.extension_enumeration.value()->cpp_name
                         true);
             }
         }
+        void write_instructions(State &state)
+        {
+            for(auto &instruction_descriptor : state.instruction_descriptor_list)
+            {
+                auto &instruction_struct = *instruction_structs.emplace(
+                    instruction_structs.end(), file_path, instruction_descriptor.cpp_struct_name);
+                instruction_struct.struct_members
+                    << "static constexpr " << instruction_descriptor.enumeration->cpp_name
+                    << R"( get_operation() noexcept
+{
+    return )" << instruction_descriptor.enumeration->cpp_name
+                    << "::" << instruction_descriptor.enumerant->cpp_name << R"(;
+}
+)";
+                for(auto &operand : instruction_descriptor.operands)
+                {
+                    typedef Operand_descriptor::Quantifier Quantifier;
+                    std::string member_type =
+                        state.get_operand_kind(operand.json_kind)->cpp_name_with_parameters;
+                    switch(operand.quantifier)
+                    {
+                    case Quantifier::none:
+                        break;
+                    case Quantifier::optional:
+                        member_type = "util::optional<" + std::move(member_type) + ">";
+                        break;
+                    case Quantifier::variable:
+                        member_type = "std::vector<" + std::move(member_type) + ">";
+                        break;
+                    }
+                    instruction_struct.add_nonstatic_member(member_type, operand.cpp_name, true);
+                }
+#warning finish
+            }
+        }
         virtual void fill_output(State &state) override
         {
             Header_file_base::fill_output(state);
@@ -1055,10 +1105,6 @@ constexpr util::Enum_set<)" << state.extension_enumeration.value()->cpp_name
             write_local_include_string("spirv/word.h");
             write_local_include_string("spirv/literal_string.h");
             basic_types << R"(typedef Word Id;
-)";
-#warning finish
-            include_guard_start << R"(#error generator not finished being implemented
-
 )";
             write_literal_kinds(state);
             write_basic_constants(state);
@@ -1066,6 +1112,7 @@ constexpr util::Enum_set<)" << state.extension_enumeration.value()->cpp_name
             write_id_types(state);
             write_enum_parameters(state);
             write_composite_types(state);
+            write_instructions(state);
         }
     };
     struct Spirv_cpp : public Source_file_base
@@ -1084,6 +1131,10 @@ constexpr util::Enum_set<)" << state.extension_enumeration.value()->cpp_name
         {
             Header_file_base::fill_output(state);
             write_local_include_path(state.spirv_h.file_path);
+#warning finish
+            include_guard_start << R"(#error generator not finished being implemented
+
+)";
         }
     };
     struct Parser_cpp : public Source_file_base
@@ -1223,7 +1274,8 @@ private:
     util::optional<std::list<Enumeration_descriptor>::const_iterator> op_enumeration;
     util::optional<std::list<Enumeration_descriptor>::const_iterator>
         extension_instruction_set_enumeration;
-    std::unordered_map<std::string, std::list<Enumeration_descriptor>::const_iterator>
+    std::unordered_map<const ast::Extension_instruction_set *,
+                       std::list<Enumeration_descriptor>::const_iterator>
         instruction_set_extension_op_enumeration_map;
 
 private:
@@ -1311,7 +1363,7 @@ private:
             }
             auto iter = add_enumeration(
                 Enumeration_descriptor(false, json_enumeration_name, std::move(enumerants)));
-            instruction_set_extension_op_enumeration_map.emplace(instruction_set.import_name, iter);
+            instruction_set_extension_op_enumeration_map.emplace(&instruction_set, iter);
             extension_instruction_set_enumerants.push_back(
                 Enumerant_descriptor(extension_instruction_set_index++,
                                      extension_instruction_set_enum_json_name,
@@ -1532,13 +1584,23 @@ private:
         std::string cpp_name;
         std::string json_kind;
         std::string json_name;
+        static std::string make_cpp_name(util::string_view json_kind, util::string_view json_name)
+        {
+            using detail::name_from_words_all_lowercase;
+            if(!json_name.empty())
+                return name_from_words_all_lowercase(json_name).to_string();
+            constexpr auto id_str = "Id"_sv;
+            if(json_kind.compare(0, id_str.size(), id_str) == 0 && id_str.size() < json_kind.size()
+               && json_kind[id_str.size()] >= 'A'
+               && json_kind[id_str.size()] <= 'Z')
+                return name_from_words_all_lowercase(json_kind.substr(id_str.size())).to_string();
+            return name_from_words_all_lowercase(json_kind).to_string();
+        }
         explicit Enum_parameter(std::list<Enumerant_descriptor>::const_iterator enumerant,
                                 std::string json_kind,
                                 std::string json_name)
             : enumerant(enumerant),
-              cpp_name(json_name.empty() ?
-                           detail::name_from_words_all_lowercase(json_kind).to_string() :
-                           detail::name_from_words_all_lowercase(json_name).to_string()),
+              cpp_name(make_cpp_name(json_kind, json_name)),
               json_kind(std::move(json_kind)),
               json_name(std::move(json_name))
         {
@@ -1594,6 +1656,7 @@ private:
         }
         std::string cpp_name;
         std::string cpp_name_with_parameters;
+        bool needs_integer_literal_size = false;
         explicit Operand_kind_descriptor(std::string json_name)
             : Operand_kind_descriptor(std::move(json_name), util::monostate{})
         {
@@ -1635,6 +1698,61 @@ private:
             throw Generate_error("unknown operand kind: " + json_name);
         return std::get<1>(*iter);
     }
+    /** returns true if operand_kind changed */
+    static bool update_operand_kind(
+        Operand_kind_descriptor &operand_kind,
+        const std::unordered_map<std::string, std::list<Operand_kind_descriptor>::const_iterator>
+            &operand_kind_map)
+    {
+        if(operand_kind.needs_integer_literal_size)
+            return false;
+        bool retval = false;
+        struct Visitor
+        {
+            Operand_kind_descriptor &operand_kind;
+            const std::unordered_map<std::string,
+                                     std::list<Operand_kind_descriptor>::const_iterator>
+                &operand_kind_map;
+            bool &retval;
+            void operator()(util::monostate)
+            {
+            }
+            void operator()(const std::list<Enumeration_descriptor>::const_iterator &)
+            {
+                // FIXME: verify that all LiteralIntegers in enum parameters are 32-bits
+            }
+            void operator()(const std::list<Id_type_descriptor>::const_iterator &)
+            {
+            }
+            void operator()(ast::Operand_kinds::Operand_kind::Literal_kind literal_kind)
+            {
+                if(literal_kind == ast::Operand_kinds::Operand_kind::Literal_kind::literal_integer)
+                {
+                    if(!operand_kind.needs_integer_literal_size)
+                        retval = true;
+                    operand_kind.needs_integer_literal_size = true;
+                }
+            }
+            void operator()(
+                const std::list<Composite_type_descriptor>::const_iterator &composite_iter)
+            {
+                for(auto &base : composite_iter->bases)
+                {
+                    auto iter = operand_kind_map.find(base.json_type);
+                    if(iter == operand_kind_map.end())
+                        throw Generate_error("unknown operand kind: " + base.json_type);
+                    if(std::get<1>(*iter)->needs_integer_literal_size)
+                    {
+                        if(!operand_kind.needs_integer_literal_size)
+                            retval = true;
+                        operand_kind.needs_integer_literal_size = true;
+                    }
+                }
+            }
+        };
+        util::visit(Visitor{operand_kind, operand_kind_map, retval}, operand_kind.value);
+        return retval;
+    }
     void fill_operand_kinds()
     {
         for(auto &operand_kind : top_level.operand_kinds.operand_kinds)
@@ -1683,14 +1801,44 @@ private:
             }
             assert(false);
         }
+        for(bool any_changes = true; any_changes;)
+        {
+            any_changes = false;
+            for(auto &operand_kind : operand_kind_list)
+            {
+                if(update_operand_kind(operand_kind, operand_kind_map))
+                    any_changes = true;
+            }
+        }
     }
 
 private:
     struct Operand_descriptor
     {
+        typedef ast::Instructions::Instruction::Operands::Operand::Quantifier Quantifier;
         std::string cpp_name;
         std::string json_name;
-        std::string json_type;
+        std::string json_kind;
+        Quantifier quantifier;
+        static std::string make_cpp_name(util::string_view json_name, util::string_view json_kind)
+        {
+            using detail::name_from_words_all_lowercase;
+            if(!json_name.empty())
+                return name_from_words_all_lowercase(json_name).to_string();
+            constexpr auto id_str = "Id"_sv;
+            if(json_kind.compare(0, id_str.size(), id_str) == 0 && id_str.size() < json_kind.size()
+               && json_kind[id_str.size()] >= 'A'
+               && json_kind[id_str.size()] <= 'Z')
+                return name_from_words_all_lowercase(json_kind.substr(id_str.size())).to_string();
+            return name_from_words_all_lowercase(json_kind).to_string();
+        }
+        Operand_descriptor(std::string json_name, std::string json_kind, Quantifier quantifier)
+            : cpp_name(make_cpp_name(json_name, json_kind)),
+              json_name(std::move(json_name)),
+              json_kind(std::move(json_kind)),
+              quantifier(quantifier)
+        {
+        }
     };
     struct Instruction_descriptor
     {
@@ -1700,6 +1848,7 @@ private:
         const ast::Extension_instruction_set *extension_instruction_set;
         std::string json_name;
         std::list<Operand_descriptor> operands;
+        const Instruction_properties_descriptor *properties_descriptor;
         static std::string make_cpp_struct_name(
             const ast::Extension_instruction_set *extension_instruction_set,
             util::string_view json_name)
@@ -1715,13 +1864,15 @@ private:
             std::list<Enumerant_descriptor>::const_iterator enumerant,
             const ast::Extension_instruction_set *extension_instruction_set,
             std::string json_name,
-            std::list<Operand_descriptor> operands)
+            std::list<Operand_descriptor> operands,
+            const Instruction_properties_descriptor *properties_descriptor)
             : cpp_struct_name(make_cpp_struct_name(extension_instruction_set, json_name)),
               enumeration(enumeration),
               enumerant(enumerant),
               extension_instruction_set(extension_instruction_set),
               json_name(std::move(json_name)),
-              operands(std::move(operands))
+              operands(std::move(operands)),
+              properties_descriptor(properties_descriptor)
         {
         }
     };
@@ -1732,8 +1883,39 @@ private:
                        std::unordered_map<std::string,
                                           std::list<Instruction_descriptor>::const_iterator>>
         instruction_descriptor_map;
+    std::unordered_map<std::string,
+                       std::unordered_map<std::string, const Instruction_properties_descriptor *>>
+        instruction_properties_descriptors_map = make_instruction_properties_descriptors_map();
 
 private:
+    static std::unordered_map<std::string,
+                              std::unordered_map<std::string,
+                                                 const Instruction_properties_descriptor *>>
+        make_instruction_properties_descriptors_map()
+    {
+        std::unordered_map<std::string,
+                           std::unordered_map<std::string,
+                                              const Instruction_properties_descriptor *>> retval;
+        for(auto &i : Instruction_properties_descriptors::get())
+        {
+            retval[std::string(i.extension_instruction_set_import_name)][std::string(
+                i.instruction_name)] = &i;
+        }
+        return retval;
+    }
+    const Instruction_properties_descriptor *get_instruction_properties_descriptor(
+        const std::string &extension_instruction_set_import_name,
+        const std::string &instruction_name)
+    {
+        auto iter1 =
+            instruction_properties_descriptors_map.find(extension_instruction_set_import_name);
+        if(iter1 == instruction_properties_descriptors_map.end())
+            return nullptr;
+        auto iter2 = std::get<1>(*iter1).find(instruction_name);
+        if(iter2 == std::get<1>(*iter1).end())
+            return nullptr;
+        return std::get<1>(*iter2);
+    }
     static std::string get_instruction_name_for_diagnostics(
         const ast::Extension_instruction_set *extension_instruction_set,
         util::string_view json_name)
@@ -1779,14 +1961,96 @@ private:
         const ast::Extension_instruction_set *extension_instruction_set,
         const ast::Instructions &instructions)
     {
-#warning finish
+        auto instruction_enumeration = this->op_enumeration.value();
+        if(extension_instruction_set)
+        {
+            auto iter =
+                instruction_set_extension_op_enumeration_map.find(extension_instruction_set);
+            if(iter == instruction_set_extension_op_enumeration_map.end())
+                throw Generate_error("unknown extension instruction set: "
+                                     + extension_instruction_set->import_name);
+            instruction_enumeration = std::get<1>(*iter);
+        }
+        for(auto &instruction : instructions.instructions)
+        {
+            auto enumerant_iter =
+                instruction_enumeration->json_name_to_enumerant_map.find(instruction.opname);
+            if(enumerant_iter == instruction_enumeration->json_name_to_enumerant_map.end())
+            {
+                std::string error_message = "unknown instruction: ";
+                if(extension_instruction_set)
+                {
+                    error_message += extension_instruction_set->import_name;
+                    error_message += " ";
+                }
+                error_message += instruction.opname;
+                throw Generate_error(error_message);
+            }
+            auto enumerant = std::get<1>(*enumerant_iter);
+            auto *instruction_properties_descriptor =
+                extension_instruction_set ?
+                    get_instruction_properties_descriptor(extension_instruction_set->import_name,
+                                                          instruction.opname) :
+                    get_instruction_properties_descriptor({}, instruction.opname);
+            std::list<Operand_descriptor> operands;
+            util::optional<Instruction_properties_descriptor::Operand_descriptors::const_iterator>
+                operand_properties_iter;
+            if(instruction_properties_descriptor)
+                operand_properties_iter =
+                    instruction_properties_descriptor->operand_descriptors.begin();
+            for(auto &operand : instruction.operands.operands)
+            {
+                operands.push_back(
+                    Operand_descriptor(operand.name, operand.kind, operand.quantifier));
+                bool has_integer_literal_size = false;
+                if(operand_properties_iter)
+                {
+                    if(*operand_properties_iter
+                       == instruction_properties_descriptor->operand_descriptors.end())
+                        throw Generate_error("instruction properties operand count mismatch: "
+                                             + get_instruction_name_for_diagnostics(
+                                                   extension_instruction_set, instruction.opname));
+                    if((*operand_properties_iter)->integer_literal_size
+                       != Instruction_properties_descriptor::Operand_descriptor::
+                              Integer_literal_size::not_implemented)
+                        has_integer_literal_size = true;
+                    ++*operand_properties_iter;
+                }
+                auto operand_kind = get_operand_kind(operand.kind);
+                if(operand_kind->needs_integer_literal_size && !has_integer_literal_size)
+                {
+                    if(!instruction_properties_descriptor)
+                        throw Generate_error(
+                            "instruction has no Instruction_properties_descriptor: "
+                            + get_instruction_name_for_diagnostics(extension_instruction_set,
+                                                                   instruction.opname)
+                            + "\nNeeded because operand needs IntegerLiteral size");
+                    throw Generate_error(
+                        "instruction operand properties has no Integer_literal_size: "
+                        + get_instruction_name_for_diagnostics(extension_instruction_set,
+                                                               instruction.opname));
+                }
+            }
+            if(operand_properties_iter
+               && *operand_properties_iter
+                      != instruction_properties_descriptor->operand_descriptors.end())
+                throw Generate_error("instruction properties operand count mismatch: "
+                                     + get_instruction_name_for_diagnostics(
+                                           extension_instruction_set, instruction.opname));
+            add_instruction_descriptor(Instruction_descriptor(instruction_enumeration,
+                                                              enumerant,
+                                                              extension_instruction_set,
+                                                              instruction.opname,
+                                                              std::move(operands),
+                                                              instruction_properties_descriptor));
+        }
     }
     void fill_instruction_descriptors()
     {
+        fill_instruction_descriptors(nullptr, top_level.instructions);
         for(auto &extension_instruction_set : top_level.extension_instruction_sets)
             fill_instruction_descriptors(&extension_instruction_set,
                                          extension_instruction_set.instructions);
-        fill_instruction_descriptors(nullptr, top_level.instructions);
     }
 
 public:
diff --git a/src/generate_spirv_parser/instruction_properties.cpp b/src/generate_spirv_parser/instruction_properties.cpp
new file mode 100644 (file)
index 0000000..9bbdf1b
--- /dev/null
@@ -0,0 +1,41 @@
+/*
+ * 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 "instruction_properties.h"
+
+namespace vulkan_cpu
+{
+namespace generate_spirv_parser
+{
+Instruction_properties_descriptors Instruction_properties_descriptors::get() noexcept
+{
+    using namespace util::string_view_literals;
+    typedef Instruction_properties_descriptor::Operand_descriptor Operand_descriptor;
+    typedef Operand_descriptor::Integer_literal_size Integer_literal_size;
+    static constexpr Instruction_properties_descriptor descriptors[] = {
+        {""_sv, "OpSwitch"_sv, {{}, {}, {Integer_literal_size::matches_type_of_operand_0}}},
+    };
+    return Instruction_properties_descriptors(descriptors,
+                                              sizeof(descriptors) / sizeof(descriptors[0]));
+}
+}
+}
diff --git a/src/generate_spirv_parser/instruction_properties.h b/src/generate_spirv_parser/instruction_properties.h
new file mode 100644 (file)
index 0000000..bf2cad9
--- /dev/null
@@ -0,0 +1,146 @@
+/*
+ * 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 GENERATE_SPIRV_PARSER_INSTRUCTION_PROPERTIES_H_
+#define GENERATE_SPIRV_PARSER_INSTRUCTION_PROPERTIES_H_
+
+#include "util/string_view.h"
+#include <initializer_list>
+#include <cstdint>
+#include <cassert>
+
+namespace vulkan_cpu
+{
+namespace generate_spirv_parser
+{
+struct Instruction_properties_descriptor
+{
+    struct Operand_descriptor
+    {
+        enum class Integer_literal_size : std::uint_least8_t // to save space
+        {
+            not_implemented,
+            always_32bits,
+            always_64bits,
+            matches_type_of_operand_0,
+        };
+        Integer_literal_size integer_literal_size;
+        constexpr Operand_descriptor() noexcept
+            : integer_literal_size(Integer_literal_size::not_implemented)
+        {
+        }
+        constexpr Operand_descriptor(Integer_literal_size integer_literal_size) noexcept
+            : integer_literal_size(integer_literal_size)
+        {
+        }
+    };
+    struct Operand_descriptors
+    {
+        static constexpr std::size_t allocated_size = 7; // increase if we run out of room
+    private:
+        std::size_t used_size;
+        Operand_descriptor operands[allocated_size];
+
+    public:
+        constexpr Operand_descriptors(
+            std::initializer_list<Operand_descriptor> initializer) noexcept
+            : used_size(initializer.size()),
+              operands{}
+        {
+            assert(initializer.size() <= allocated_size);
+            for(std::size_t i = 0; i < initializer.size(); i++)
+                operands[i] = initializer.begin()[i];
+        }
+        constexpr Operand_descriptors() noexcept : used_size(0), operands{}
+        {
+        }
+        typedef Operand_descriptor *iterator;
+        typedef const Operand_descriptor *const_iterator;
+        constexpr iterator begin() noexcept
+        {
+            return operands;
+        }
+        constexpr const_iterator begin() const noexcept
+        {
+            return operands;
+        }
+        constexpr iterator end() noexcept
+        {
+            return operands + used_size;
+        }
+        constexpr const_iterator end() const noexcept
+        {
+            return operands + used_size;
+        }
+        constexpr std::size_t size() const noexcept
+        {
+            return used_size;
+        }
+        constexpr Operand_descriptor *data() noexcept
+        {
+            return operands;
+        }
+        constexpr const Operand_descriptor *data() const noexcept
+        {
+            return operands;
+        }
+    };
+    util::string_view extension_instruction_set_import_name;
+    util::string_view instruction_name;
+    Operand_descriptors operand_descriptors;
+    constexpr Instruction_properties_descriptor(
+        util::string_view extension_instruction_set_import_name,
+        util::string_view instruction_name,
+        Operand_descriptors operand_descriptors) noexcept
+        : extension_instruction_set_import_name(extension_instruction_set_import_name),
+          instruction_name(instruction_name),
+          operand_descriptors(operand_descriptors)
+    {
+    }
+};
+
+struct Instruction_properties_descriptors
+{
+    const Instruction_properties_descriptor *descriptors;
+    std::size_t descriptor_count;
+    constexpr explicit Instruction_properties_descriptors(
+        const Instruction_properties_descriptor *descriptors, std::size_t descriptor_count) noexcept
+        : descriptors(descriptors),
+          descriptor_count(descriptor_count)
+    {
+    }
+    typedef const Instruction_properties_descriptor *iterator;
+    typedef const Instruction_properties_descriptor *const_iterator;
+    constexpr const_iterator begin() const noexcept
+    {
+        return descriptors;
+    }
+    constexpr const_iterator end() const noexcept
+    {
+        return descriptors + descriptor_count;
+    }
+    static Instruction_properties_descriptors get() noexcept;
+};
+}
+}
+
+#endif /* GENERATE_SPIRV_PARSER_INSTRUCTION_PROPERTIES_H_ */