From: Jacob Lifshay Date: Sat, 17 Jun 2017 00:33:33 +0000 (-0700) Subject: code to generate spirv.h is pretty much complete X-Git-Tag: gsoc-2017~93 X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=803c8a316000d587547ea26ff281138b6c456ea6;p=kazan.git code to generate spirv.h is pretty much complete --- diff --git a/.gitignore b/.gitignore index 11f41ba..2244dde 100644 --- a/.gitignore +++ b/.gitignore @@ -6,3 +6,4 @@ Makefile /.settings/ /test-files/test.spv out.json +compile_commands.json diff --git a/src/generate_spirv_parser/ast.cpp b/src/generate_spirv_parser/ast.cpp index 9e14428..12dc6f1 100644 --- a/src/generate_spirv_parser/ast.cpp +++ b/src/generate_spirv_parser/ast.cpp @@ -83,6 +83,8 @@ json::ast::Value Instructions::Instruction::to_json() const retval.values["operands"] = operands.to_json(); if(!capabilities.empty()) retval.values["capabilities"] = capabilities.to_json(); + if(!extensions.empty()) + retval.values["extensions"] = extensions.to_json(); return json::ast::Value(make_empty_location(), std::move(retval)); } diff --git a/src/generate_spirv_parser/ast.h b/src/generate_spirv_parser/ast.h index 81e650e..0d1a1c9 100644 --- a/src/generate_spirv_parser/ast.h +++ b/src/generate_spirv_parser/ast.h @@ -164,13 +164,16 @@ struct Instructions std::uint32_t opcode; Operands operands; Capabilities capabilities; + Extensions extensions; Instruction(std::string opname, std::uint32_t opcode, Operands operands, - Capabilities capabilities) noexcept : opname(std::move(opname)), - opcode(opcode), - operands(std::move(operands)), - capabilities(std::move(capabilities)) + Capabilities capabilities, + 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; @@ -180,6 +183,7 @@ struct Instructions fn(*this); operands.visit(fn); capabilities.visit(fn); + extensions.visit(fn); } }; std::vector instructions; @@ -203,11 +207,13 @@ struct Operand_kinds { enum class Category { - bit_enum, + bit_enum, // enum categories must be first value_enum, + id, literal, - composite, + + composite, // composite must be last }; Category category; static constexpr const char *get_json_name_from_category(Category category) noexcept diff --git a/src/generate_spirv_parser/generate.cpp b/src/generate_spirv_parser/generate.cpp index 115e237..85e3968 100644 --- a/src/generate_spirv_parser/generate.cpp +++ b/src/generate_spirv_parser/generate.cpp @@ -21,9 +21,13 @@ * */ #include "generate.h" -#include "../json/json.h" +#include "json/json.h" +#include "util/string_view.h" +#include "util/optional.h" #include #include +#include +#include namespace vulkan_cpu { @@ -54,6 +58,7 @@ constexpr const char *Generator::spirv_namespace_name; constexpr const char *Generator::spirv_namespace_names[]; constexpr const char *Generator::extension_enum_name; constexpr const char *Generator::capability_enum_name; +constexpr const char *Generator::op_enum_name; std::string Generator::get_guard_macro_name_from_file_name(std::string file_name) { @@ -92,30 +97,79 @@ std::string Generator::get_guard_macro_name_from_file_name(std::string file_name namespace { -constexpr bool is_identifier_start(char ch) noexcept +constexpr bool is_uppercase_letter(char ch) noexcept { if(ch >= 'A' && ch <= 'Z') return true; + return false; +} + +constexpr bool is_lowercase_letter(char ch) noexcept +{ if(ch >= 'a' && ch <= 'z') return true; - return ch == '_'; + return false; +} + +constexpr bool is_letter(char ch) noexcept +{ + return is_uppercase_letter(ch) || is_lowercase_letter(ch); +} + +constexpr bool is_identifier_start(char ch) noexcept +{ + return is_letter(ch) || ch == '_'; +} + +constexpr bool is_digit(char ch) noexcept +{ + if(ch >= '0' && ch <= '9') + return true; + return false; +} + +constexpr bool is_identifier_continue(char ch) noexcept +{ + return is_identifier_start(ch) || is_digit(ch); } } std::string Generator::get_enumerant_name(const char *enumeration_name, std::size_t enumeration_name_size, - std::string enumerant_name) -{ - bool need_prefix; - if(enumerant_name.compare(0, enumeration_name_size, enumeration_name, enumeration_name_size) - == 0) - need_prefix = true; // ensure that we don't end up with name collisions - else if(enumerant_name.empty()) - need_prefix = true; // return something other than the empty string + std::string enumerant_name, + bool input_name_should_have_prefix) +{ + bool starts_with_enumeration_name = + enumerant_name.compare(0, enumeration_name_size, enumeration_name, enumeration_name_size) + == 0; + bool starts_with_doubled_enumeration_name = false; + if(starts_with_enumeration_name) + starts_with_doubled_enumeration_name = enumerant_name.compare(enumeration_name_size, + enumeration_name_size, + enumeration_name, + enumeration_name_size) + == 0; + std::size_t needed_prefix_count; + if(input_name_should_have_prefix) + { + if(!starts_with_enumeration_name) + needed_prefix_count = 2; + else if(starts_with_doubled_enumeration_name) + needed_prefix_count = 1; + else + needed_prefix_count = 0; + } else - need_prefix = !is_identifier_start(enumerant_name[0]); - if(need_prefix) - return std::move(enumerant_name.insert(0, enumeration_name, enumeration_name_size)); + { + if(starts_with_enumeration_name) + needed_prefix_count = 1; // ensure that we don't end up with name collisions + else if(enumerant_name.empty()) + needed_prefix_count = 1; // return something other than the empty string + else + needed_prefix_count = is_identifier_start(enumerant_name[0]) ? 0 : 1; + } + for(std::size_t i = 0; i < needed_prefix_count; i++) + enumerant_name.insert(0, enumeration_name, enumeration_name_size); return enumerant_name; } @@ -260,7 +314,7 @@ void Generator::write_capabilities_set(Generator_state &state, for(auto &capability : capabilities.capabilities) { state << separator << capability_enum_name - << "::" << get_enumerant_name(capability_enum_name, capability); + << "::" << get_enumerant_name(capability_enum_name, capability, false); separator = ", "; } state << "}"; @@ -273,12 +327,204 @@ void Generator::write_extensions_set(Generator_state &state, const ast::Extensio for(auto &extension : extensions.extensions) { state << separator << extension_enum_name - << "::" << get_enumerant_name(extension_enum_name, extension); + << "::" << get_enumerant_name(extension_enum_name, extension, false); separator = ", "; } state << "}"; } +std::string Generator::get_member_name_from_words(const std::string &words) +{ + enum class Char_class + { + Uppercase, + OtherIdentifier, + WordSeparator, + }; + auto get_char_class = [](char ch) -> Char_class + { + if(is_uppercase_letter(ch)) + return Char_class::Uppercase; + if(is_letter(ch) || is_digit(ch)) + return Char_class::OtherIdentifier; + return Char_class::WordSeparator; + }; + auto find_words = [&](auto found_word_callback) -> void + { + util::optional word_start; + auto finish_word = [&](std::size_t index) + { + found_word_callback(util::string_view(words.data() + *word_start, index - *word_start)); + word_start = {}; + }; + auto start_word = [&](std::size_t index) + { + word_start = index; + }; + auto last_char_class = Char_class::WordSeparator; + for(std::size_t i = 0; i < words.size(); i++) + { + auto current_char_class = get_char_class(words[i]); + if(word_start) + { + switch(current_char_class) + { + case Char_class::WordSeparator: + finish_word(i); + break; + case Char_class::Uppercase: + if(last_char_class != Char_class::Uppercase) + { + finish_word(i); + start_word(i); + } + else if(i + 1 < words.size() + && get_char_class(words[i + 1]) == Char_class::OtherIdentifier) + { + finish_word(i); + start_word(i); + } + break; + case Char_class::OtherIdentifier: + break; + } + } + else if(current_char_class != Char_class::WordSeparator) + { + start_word(i); + } + last_char_class = current_char_class; + } + if(word_start) + finish_word(words.size()); + }; + std::size_t retval_size = 0; + bool first = true; + find_words([&](util::string_view word) + { + if(!first) + retval_size++; // separating '_' + first = false; + retval_size += word.size(); + }); + std::string retval; + retval.reserve(retval_size); + first = true; + find_words([&](util::string_view word) + { + if(!first) + retval += '_'; + first = false; + retval += word; + }); + for(char &ch : retval) + { + if(is_uppercase_letter(ch)) + ch = ch - 'A' + 'a'; // to lowercase + } + return retval; +} + +#if 0 +#warning testing Generator::get_member_name_from_words +struct Generator::Tester +{ + struct Test_runner + { + Test_runner() + { + test(); + std::exit(1); + } + }; + static Test_runner test_runner; + static void test() + { + for(auto &input : { + "abc def", "AbcDef", "ABCDef", "'abc, def'", + }) + { + std::cout << "\"" << input << "\" -> " << get_member_name_from_words(input) + << std::endl; + } + } +}; + +Generator::Tester::Test_runner Generator::Tester::test_runner; +#endif + +std::string Generator::get_member_name_from_operand( + const ast::Instructions::Instruction::Operands::Operand &operand) +{ + if(!operand.name.empty()) + return get_member_name_from_words(operand.name); + util::string_view id_str = "Id"; + if(util::string_view(operand.kind).compare(0, id_str.size(), id_str) == 0 + && id_str.size() < operand.kind.size() + && is_uppercase_letter(operand.kind[id_str.size()])) + return get_member_name_from_words(operand.kind.substr(id_str.size())); + return get_member_name_from_words(operand.kind); +} + +void Generator::write_struct_nonstatic_members_and_constructors(Generator_state &state, + const std::string &struct_name, + const std::string *member_types, + const std::string *member_names, + std::size_t member_count) +{ + for(std::size_t i = 0; i < member_count; i++) + state << indent << member_types[i] << " " << member_names[i] << ";\n"; + state << indent << struct_name << "()\n"; + { + auto push_indent = state.pushed_indent(); + for(std::size_t i = 0; i < member_count; i++) + { + state << indent; + if(i == 0) + state << ": "; + else + state << " "; + state << member_names[i] << "()"; + if(i != member_count - 1) + state << ","; + state << "\n"; + } + } + state << indent << "{\n"; + state << indent << "}\n"; + if(member_count != 0) + { + state << indent; + if(member_count == 1) + state << "explicit "; + state << struct_name << "("; + for(std::size_t i = 0; i < member_count; i++) + { + state << member_types[i] << " " << member_names[i]; + if(i != member_count - 1) + state << ", "; + } + state << ")\n"; + { + auto push_indent = state.pushed_indent(); + for(std::size_t i = 0; i < member_count; i++) + { + state << indent; + if(i == 0) + state << ": "; + else + state << " "; + state << member_names[i] << "(std::move(" << member_names[i] << "))"; + if(i != member_count - 1) + state << ","; + state << "\n"; + } + } + state << indent << "{\n"; + state << indent << "}\n"; + } +} + struct Spirv_header_generator final : public Generator { Spirv_header_generator() : Generator("spirv.h") @@ -305,6 +551,20 @@ struct Spirv_header_generator final : public Generator return false; return l < r; } + static bool compare_operand_kinds(const ast::Operand_kinds::Operand_kind &l, + const ast::Operand_kinds::Operand_kind &r) + { + // treat both enum categories as equivalent + auto l_category = l.category == ast::Operand_kinds::Operand_kind::Category::bit_enum ? + ast::Operand_kinds::Operand_kind::Category::value_enum : + l.category; + auto r_category = r.category == ast::Operand_kinds::Operand_kind::Category::bit_enum ? + ast::Operand_kinds::Operand_kind::Category::value_enum : + r.category; + if(l_category != r_category) + return l_category < r_category; + return compare_enum_names(l.kind, r.kind); + } virtual void run(Generator_args &generator_args, const ast::Top_level &top_level) const override { Generator_state state(this, generator_args); @@ -312,10 +572,13 @@ struct Spirv_header_generator final : public Generator write_file_comments(state, top_level.copyright); write_file_guard_start(state); state << "#include \n" - "#include \"util/enum.h\"\n"; + "#include \"util/enum.h\"\n" + "#include \"util/optional.h\"\n" + "#include \n"; state << "\n"; write_namespaces_start(state, spirv_namespace_names); state << "typedef std::uint32_t Word;\n"; + state << "typedef Word Id;\n"; state << "constexpr Word magic_number = " << unsigned_hex_integer_literal(top_level.magic_number, 8) << ";\n"; state << "constexpr std::uint32_t major_version = " @@ -337,7 +600,8 @@ struct Spirv_header_generator final : public Generator { auto push_indent = state.pushed_indent(); for(auto &extension : extensions_list) - state << indent << get_enumerant_name(extension_enum_name, extension) << ",\n"; + state << indent << get_enumerant_name(extension_enum_name, extension, false) + << ",\n"; } state << "};\n" "\n" @@ -347,7 +611,7 @@ struct Spirv_header_generator final : public Generator auto push_indent = state.pushed_indent(); for(auto &extension : extensions_list) state << ",\n" << indent << extension_enum_name - << "::" << get_enumerant_name(extension_enum_name, extension); + << "::" << get_enumerant_name(extension_enum_name, extension, false); state << ");\n"; } state << "\n" @@ -360,7 +624,7 @@ struct Spirv_header_generator final : public Generator for(auto &extension : extensions_list) { state << indent << "case " << extension_enum_name - << "::" << get_enumerant_name(extension_enum_name, extension) << ":\n"; + << "::" << get_enumerant_name(extension_enum_name, extension, false) << ":\n"; auto push_indent2 = state.pushed_indent(); state << indent << "return \"" << extension << "\";\n"; } @@ -376,12 +640,14 @@ struct Spirv_header_generator final : public Generator operand_kinds.end(), [](const ast::Operand_kinds::Operand_kind *a, const ast::Operand_kinds::Operand_kind *b) { - return compare_enum_names(a->kind, b->kind); + return compare_operand_kinds(*a, *b); }); for(auto *operand_kind : operand_kinds) { - if(util::holds_alternative( - operand_kind->value)) + switch(operand_kind->category) + { + case ast::Operand_kinds::Operand_kind::Category::bit_enum: + case ast::Operand_kinds::Operand_kind::Category::value_enum: { bool is_bit_enum = operand_kind->category == ast::Operand_kinds::Operand_kind::Category::bit_enum; @@ -396,7 +662,7 @@ struct Spirv_header_generator final : public Generator for(auto &enumerant : enumerants.enumerants) { state << indent - << get_enumerant_name(operand_kind->kind, enumerant.enumerant) + << get_enumerant_name(operand_kind->kind, enumerant.enumerant, false) << " = "; if(is_bit_enum) state << unsigned_hex_integer_literal(enumerant.value); @@ -414,8 +680,9 @@ struct Spirv_header_generator final : public Generator { auto push_indent = state.pushed_indent(); for(auto &enumerant : enumerants.enumerants) - state << ",\n" << indent << operand_kind->kind << "::" - << get_enumerant_name(operand_kind->kind, enumerant.enumerant); + state << ",\n" << indent << operand_kind->kind + << "::" << get_enumerant_name( + operand_kind->kind, enumerant.enumerant, false); state << ");\n"; } } @@ -428,8 +695,8 @@ struct Spirv_header_generator final : public Generator state << indent << "switch(v)\n" << indent << "{\n"; for(auto &enumerant : enumerants.enumerants) { - state << indent << "case " << operand_kind->kind - << "::" << get_enumerant_name(operand_kind->kind, enumerant.enumerant) + state << indent << "case " << operand_kind->kind << "::" + << get_enumerant_name(operand_kind->kind, enumerant.enumerant, false) << ":\n"; auto push_indent2 = state.pushed_indent(); state << indent << "return \"" << enumerant.enumerant << "\";\n"; @@ -447,8 +714,8 @@ struct Spirv_header_generator final : public Generator state << indent << "switch(v)\n" << indent << "{\n"; for(auto &enumerant : enumerants.enumerants) { - state << indent << "case " << operand_kind->kind - << "::" << get_enumerant_name(operand_kind->kind, enumerant.enumerant) + state << indent << "case " << operand_kind->kind << "::" + << get_enumerant_name(operand_kind->kind, enumerant.enumerant, false) << ":\n"; auto push_indent2 = state.pushed_indent(); state << indent << "return " << enumerant.capabilities << ";\n"; @@ -466,8 +733,8 @@ struct Spirv_header_generator final : public Generator state << indent << "switch(v)\n" << indent << "{\n"; for(auto &enumerant : enumerants.enumerants) { - state << indent << "case " << operand_kind->kind - << "::" << get_enumerant_name(operand_kind->kind, enumerant.enumerant) + state << indent << "case " << operand_kind->kind << "::" + << get_enumerant_name(operand_kind->kind, enumerant.enumerant, false) << ":\n"; auto push_indent2 = state.pushed_indent(); state << indent << "return " << enumerant.extensions << ";\n"; @@ -475,9 +742,223 @@ struct Spirv_header_generator final : public Generator state << indent << "}\n" << indent << "return {};\n"; } state << "}\n"; + break; + } + case ast::Operand_kinds::Operand_kind::Category::composite: + { + auto &bases = + util::get(operand_kind->value); + state << "\n" + "struct " + << operand_kind->kind << "\n" + "{\n"; + auto push_indent = state.pushed_indent(); + std::vector member_names; + member_names.reserve(bases.values.size()); + for(std::size_t i = 0; i < bases.values.size(); i++) + member_names.push_back( + json::ast::Number_value::append_unsigned_integer_to_string(i + 1, "part_")); + write_struct_nonstatic_members_and_constructors(state, + operand_kind->kind, + bases.values.data(), + member_names.data(), + bases.values.size()); + push_indent.finish(); + state << "};\n"; + break; + } + case ast::Operand_kinds::Operand_kind::Category::id: + { + auto &doc = util::get(operand_kind->value); + state << "\n" + "/** "; + bool was_last_star = false; + for(char ch : doc.value) + { + if(was_last_star && ch == '/') + state << ' '; + was_last_star = (ch == '*'); + state << ch; + } + state << " */\n" + "typedef Id " + << operand_kind->kind << ";\n"; + break; + } + case ast::Operand_kinds::Operand_kind::Category::literal: + { + auto &doc = util::get(operand_kind->value); + auto base_type = "std::vector"; + if(operand_kind->kind == "LiteralInteger") + base_type = "std::uint64_t"; + else if(operand_kind->kind == "LiteralString") + base_type = "std::string"; + else if(operand_kind->kind == "LiteralExtInstInteger") + base_type = "Word"; + else if(operand_kind->kind == "LiteralSpecConstantOpInteger") + base_type = "Op"; +#warning finish + state << "\n" + "/** "; + bool was_last_star = false; + for(char ch : doc.value) + { + if(was_last_star && ch == '/') + state << ' '; + was_last_star = (ch == '*'); + state << ch; + } + state << " */\n" + "typedef " + << base_type << " " << operand_kind->kind << ";\n"; + break; + } } } - + std::vector instructions; + instructions.reserve(top_level.instructions.instructions.size()); + for(auto &instruction : top_level.instructions.instructions) + instructions.push_back(&instruction); + std::sort( + instructions.begin(), + instructions.end(), + [](const ast::Instructions::Instruction *a, const ast::Instructions::Instruction *b) + { + return a->opcode < b->opcode; + }); + state << "\n" + "enum class " + << op_enum_name << " : Word\n" + "{\n"; + { + auto push_indent = state.pushed_indent(); + for(auto &instruction : top_level.instructions.instructions) + { + state << indent << get_enumerant_name(op_enum_name, instruction.opname, true) + << " = " << unsigned_dec_integer_literal(instruction.opcode) << ",\n"; + } + } + state << "};\n"; + state << "\n" + "vulkan_cpu_util_generate_enum_traits(" + << op_enum_name; + { + auto push_indent = state.pushed_indent(); + for(auto &instruction : top_level.instructions.instructions) + state << ",\n" << indent << op_enum_name + << "::" << get_enumerant_name(op_enum_name, instruction.opname, true); + state << ");\n"; + } + state << "\n" + "constexpr const char *get_enumerant_name(" + << op_enum_name << " v) noexcept\n" + "{\n"; + { + auto push_indent = state.pushed_indent(); + state << indent << "switch(v)\n" << indent << "{\n"; + for(auto &instruction : top_level.instructions.instructions) + { + state << indent << "case " << op_enum_name + << "::" << get_enumerant_name(op_enum_name, instruction.opname, true) + << ":\n"; + auto push_indent2 = state.pushed_indent(); + state << indent << "return \"" << instruction.opname << "\";\n"; + } + state << indent << "}\n" << indent << "return \"\";\n"; + } + state << "}\n" + "\n" + "constexpr util::Enum_set<" + << capability_enum_name << "> get_directly_required_capability_set(" << op_enum_name + << " v) noexcept\n" + "{\n"; + { + auto push_indent = state.pushed_indent(); + state << indent << "switch(v)\n" << indent << "{\n"; + for(auto &instruction : top_level.instructions.instructions) + { + state << indent << "case " << op_enum_name + << "::" << get_enumerant_name(op_enum_name, instruction.opname, true) + << ":\n"; + auto push_indent2 = state.pushed_indent(); + state << indent << "return " << instruction.capabilities << ";\n"; + } + state << indent << "}\n" << indent << "return {};\n"; + } + state << "}\n" + "\n" + "constexpr util::Enum_set<" + << extension_enum_name << "> get_directly_required_extension_set(" << op_enum_name + << " v) noexcept\n" + "{\n"; + { + auto push_indent = state.pushed_indent(); + state << indent << "switch(v)\n" << indent << "{\n"; + for(auto &instruction : top_level.instructions.instructions) + { + state << indent << "case " << op_enum_name + << "::" << get_enumerant_name(op_enum_name, instruction.opname, true) + << ":\n"; + auto push_indent2 = state.pushed_indent(); + state << indent << "return " << instruction.extensions << ";\n"; + } + state << indent << "}\n" << indent << "return {};\n"; + } + state << "}\n"; + for(auto &instruction : top_level.instructions.instructions) + { + auto struct_name = get_enumerant_name(op_enum_name, instruction.opname, true); + state << "\n" + "struct " + << struct_name << "\n" + "{\n"; + { + auto push_indent = state.pushed_indent(); + state << indent << "static constexpr " << op_enum_name << " get_opcode() noexcept\n" + << indent << "{\n"; + { + auto push_indent2 = state.pushed_indent(); + state << indent << "return " << op_enum_name + << "::" << get_enumerant_name(op_enum_name, instruction.opname, true) + << ";\n"; + } + state << indent << "}\n"; + std::vector member_names; + std::vector member_types; + member_names.reserve(instruction.operands.operands.size()); + member_types.reserve(instruction.operands.operands.size()); + for(auto &operand : instruction.operands.operands) + { + std::string member_type; + switch(operand.quantifier) + { + case ast::Instructions::Instruction::Operands::Operand::Quantifier::none: + { + member_type = operand.kind; + break; + } + case ast::Instructions::Instruction::Operands::Operand::Quantifier::optional: + { + member_type = "util::optional<" + operand.kind + ">"; + break; + } + case ast::Instructions::Instruction::Operands::Operand::Quantifier::variable: + { + member_type = "std::vector<" + operand.kind + ">"; + break; + } + } + member_types.push_back(std::move(member_type)); + member_names.push_back(get_member_name_from_operand(operand)); + } + write_struct_nonstatic_members_and_constructors(state, + struct_name, + member_types.data(), + member_names.data(), + member_types.size()); + } + state << "};\n"; + } #warning finish write_namespaces_end(state, spirv_namespace_names); @@ -489,6 +970,19 @@ std::unique_ptr Generators::make_spirv_header_generator() { return std::unique_ptr(new Spirv_header_generator); } + +std::vector> Generators::make_all_generators() +{ + std::unique_ptr generators_array[] = { + make_spirv_header_generator(), + }; + // use array then move because you can't move out of an std::initializer_list + std::vector> retval; + retval.reserve(sizeof(generators_array) / sizeof(generators_array[0])); + for(auto &generator : generators_array) + retval.push_back(std::move(generator)); + return retval; +} } } } diff --git a/src/generate_spirv_parser/generate.h b/src/generate_spirv_parser/generate.h index 908050c..84d8fbf 100644 --- a/src/generate_spirv_parser/generate.h +++ b/src/generate_spirv_parser/generate.h @@ -32,6 +32,7 @@ #include #include #include +#include namespace vulkan_cpu { @@ -41,6 +42,9 @@ namespace generate { class Generator { +private: + struct Tester; + public: struct Generator_args { @@ -186,20 +190,27 @@ protected: protected: static std::string get_guard_macro_name_from_file_name(std::string file_name); static std::string get_enumerant_name(const std::string &enumeration_name, - std::string enumerant_name) + std::string enumerant_name, + bool input_name_should_have_prefix) { - return get_enumerant_name( - enumeration_name.data(), enumeration_name.size(), std::move(enumerant_name)); + return get_enumerant_name(enumeration_name.data(), + enumeration_name.size(), + std::move(enumerant_name), + input_name_should_have_prefix); } - static std::string get_enumerant_name(const char *enumeration_name, std::string enumerant_name) + static std::string get_enumerant_name(const char *enumeration_name, + std::string enumerant_name, + bool input_name_should_have_prefix) { return get_enumerant_name(enumeration_name, std::char_traits::length(enumeration_name), - std::move(enumerant_name)); + std::move(enumerant_name), + input_name_should_have_prefix); } static std::string get_enumerant_name(const char *enumeration_name, std::size_t enumeration_name_size, - std::string enumerant_name); + std::string enumerant_name, + bool input_name_should_have_prefix); static void write_indent(Generator_state &state); static void write_automatically_generated_file_warning(Generator_state &state); static void write_copyright_comment(Generator_state &state, const ast::Copyright ©right); @@ -299,6 +310,14 @@ protected: static void write_capabilities_set(Generator_state &state, const ast::Capabilities &capabilities); static void write_extensions_set(Generator_state &state, const ast::Extensions &extensions); + static std::string get_member_name_from_words(const std::string &words); + static std::string get_member_name_from_operand( + const ast::Instructions::Instruction::Operands::Operand &operand); + static void write_struct_nonstatic_members_and_constructors(Generator_state &state, + const std::string &struct_name, + const std::string *member_types, + const std::string *member_names, + std::size_t member_count); protected: static constexpr const char *vulkan_cpu_namespace_name = "vulkan_cpu"; @@ -308,6 +327,7 @@ protected: }; static constexpr const char *capability_enum_name = "Capability"; static constexpr const char *extension_enum_name = "Extension"; + static constexpr const char *op_enum_name = "Op"; public: explicit Generator(const char *output_base_file_name) noexcept @@ -334,6 +354,7 @@ struct Spirv_header_generator; struct Generators { static std::unique_ptr make_spirv_header_generator(); + static std::vector> make_all_generators(); }; } } diff --git a/src/generate_spirv_parser/generate_spirv_parser.cpp b/src/generate_spirv_parser/generate_spirv_parser.cpp index 4a88efe..ca8141f 100644 --- a/src/generate_spirv_parser/generate_spirv_parser.cpp +++ b/src/generate_spirv_parser/generate_spirv_parser.cpp @@ -53,9 +53,7 @@ int generate_spirv_parser_main(int argc, char **argv) { auto json_in = json::parse(&source); auto ast = parser::parse(json_in.duplicate()); - for(auto &generator : { - generate::Generators::make_spirv_header_generator(), - }) + for(auto &generator : generate::Generators::make_all_generators()) { generator->run(generate::Generator::Generator_args(output_directory), ast); } diff --git a/src/generate_spirv_parser/parser.cpp b/src/generate_spirv_parser/parser.cpp index 8c96b89..d1bd543 100644 --- a/src/generate_spirv_parser/parser.cpp +++ b/src/generate_spirv_parser/parser.cpp @@ -682,6 +682,7 @@ ast::Instructions::Instruction parse_instructions_instruction( }); ast::Instructions::Instruction::Operands operands; ast::Capabilities capabilities; + ast::Extensions extensions; for(auto &entry : instruction_object.values) { const auto &key = std::get<0>(entry); @@ -696,13 +697,20 @@ ast::Instructions::Instruction parse_instructions_instruction( { capabilities = parse_capabilities(std::move(entry_value), &path_builder); } + else if(key == "extensions") + { + extensions = parse_extensions(std::move(entry_value), &path_builder); + } else if(key != opname_name && key != opcode_name) { throw Parse_error(entry_value.location, path_builder.path(), "unknown key"); } } - return ast::Instructions::Instruction( - std::move(opname), opcode, std::move(operands), std::move(capabilities)); + return ast::Instructions::Instruction(std::move(opname), + opcode, + std::move(operands), + std::move(capabilities), + std::move(extensions)); } ast::Instructions parse_instructions(json::ast::Value value, @@ -823,4 +831,4 @@ struct Test #endif } } -} \ No newline at end of file +}