From 123a5312531c8a7956b11abe0a1c9a2cc4eb2690 Mon Sep 17 00:00:00 2001 From: Jacob Lifshay Date: Tue, 20 Jun 2017 20:56:45 -0700 Subject: [PATCH] working on adding enum parameters to generated parser --- src/demo/demo.cpp | 16 +- src/generate_spirv_parser/generate.cpp | 721 ++++++++++++++++++++----- src/generate_spirv_parser/generate.h | 54 +- src/spirv/CMakeLists.txt | 2 +- src/util/enum.h | 2 +- 5 files changed, 627 insertions(+), 168 deletions(-) diff --git a/src/demo/demo.cpp b/src/demo/demo.cpp index 616ef95..d94f438 100644 --- a/src/demo/demo.cpp +++ b/src/demo/demo.cpp @@ -206,19 +206,19 @@ int test_main(int argc, char **argv) if(file) { dump_words(*file); - std::ostringstream os; - spirv::Parse_dump semantics(os); + spirv::Parse_dump semantics(std::cout); auto parse_error = spirv::Parser<>::parse(file->data(), file->size(), semantics); if(parse_error) { - std::cerr << "error: " << std::hex << std::uppercase << std::showbase - << parse_error->word_index << ": " << parse_error->message << std::endl; + std::cerr << std::hex << std::uppercase; + std::cerr << "error: "; + if(parse_error->instruction_word_index != 0) + std::cerr << "in instruction starting at 0x" << parse_error->instruction_word_index + << ": "; + std::cerr << "at 0x" << parse_error->word_index << ": " << parse_error->message + << std::endl; return 1; } - else - { - std::cout << os.str() << std::flush; - } } return 0; } diff --git a/src/generate_spirv_parser/generate.cpp b/src/generate_spirv_parser/generate.cpp index 4389960..fd48e25 100644 --- a/src/generate_spirv_parser/generate.cpp +++ b/src/generate_spirv_parser/generate.cpp @@ -22,7 +22,6 @@ */ #include "generate.h" #include "json/json.h" -#include "util/string_view.h" #include "util/optional.h" #include #include @@ -30,6 +29,8 @@ #include #include +#error finish converting to use get_enum_with_parameters_struct_name + namespace vulkan_cpu { namespace generate_spirv_parser @@ -37,15 +38,39 @@ namespace generate_spirv_parser namespace generate { Generator::Generator_state::Generator_state(const Generator *generator, - Generator_args &generator_args) + Generator_args &generator_args, + const ast::Top_level &top_level) : generator_args(generator_args), indent_level(0), full_output_file_name(generator_args.output_directory + "/" + generator->output_base_file_name), guard_macro_name(get_guard_macro_name_from_file_name(full_output_file_name)), - os() + os(), + top_level(top_level), + operand_kind_map(), + operand_has_any_parameters_map() { os.exceptions(std::ios::badbit | std::ios::failbit); + for(auto &operand_kind : top_level.operand_kinds.operand_kinds) + { + operand_kind_map.emplace(operand_kind.kind, &operand_kind); + bool &has_any_parameters = operand_has_any_parameters_map[&operand_kind]; + has_any_parameters = false; + if(util::holds_alternative( + operand_kind.value)) + { + auto &enumerants = + util::get(operand_kind.value); + for(auto &enumerant : enumerants.enumerants) + { + if(!enumerant.parameters.empty()) + { + has_any_parameters = true; + break; + } + } + } + } } void Generator::Generator_state::open_output_file() @@ -215,8 +240,8 @@ void Generator::write_indent_interpreted_text(Generator_state &state, void Generator::write_automatically_generated_file_warning(Generator_state &state) { - state << R"(/* This file is automatically generated by generate_spirv_parser. DO NOT MODIFY. */ -)"; + state + << "/* This file is automatically generated by generate_spirv_parser. DO NOT MODIFY. */\n"; } void Generator::write_copyright_comment(Generator_state &state, const ast::Copyright ©right) @@ -459,102 +484,103 @@ std::string Generator::get_member_name_from_words(const std::string &words) if(is_uppercase_letter(ch)) ch = ch - 'A' + 'a'; // to lowercase } - for(const char *reserved_word : { - "alignas", - "alignof", - "and", - "and_eq", - "asm", - "atomic_cancel", - "atomic_commit", - "atomic_noexcept", - "auto", - "bitand", - "bitor", - "bool", - "break", - "case", - "catch", - "char", - "char16_t", - "char32_t", - "class", - "compl", - "concept", - "concepts", - "const", - "const_cast", - "constexpr", - "continue", - "decltype", - "default", - "delete", - "do", - "double", - "dynamic_cast", - "else", - "enum", - "explicit", - "export", - "extern", - "false", - "float", - "for", - "friend", - "goto", - "if", - "import", - "inline", - "int", - "long", - "module", - "modules", - "mutable", - "namespace", - "new", - "noexcept", - "not", - "not_eq", - "nullptr", - "operator", - "or", - "or_eq", - "private", - "protected", - "public", - "register", - "reinterpret_cast", - "requires", - "return", - "short", - "signed", - "sizeof", - "static", - "static_assert", - "static_cast", - "struct", - "switch", - "synchronized", - "template", - "this", - "thread_local", - "throw", - "true", - "try", - "typedef", - "typeid", - "typename", - "union", - "unsigned", - "using", - "virtual", - "void", - "volatile", - "wchar_t", - "while", - "xor", - "xor_eq", - }) + static constexpr const char *const reserved_words[] = { + "alignas", + "alignof", + "and", + "and_eq", + "asm", + "atomic_cancel", + "atomic_commit", + "atomic_noexcept", + "auto", + "bitand", + "bitor", + "bool", + "break", + "case", + "catch", + "char", + "char16_t", + "char32_t", + "class", + "compl", + "concept", + "concepts", + "const", + "const_cast", + "constexpr", + "continue", + "decltype", + "default", + "delete", + "do", + "double", + "dynamic_cast", + "else", + "enum", + "explicit", + "export", + "extern", + "false", + "float", + "for", + "friend", + "goto", + "if", + "import", + "inline", + "int", + "long", + "module", + "modules", + "mutable", + "namespace", + "new", + "noexcept", + "not", + "not_eq", + "nullptr", + "operator", + "or", + "or_eq", + "private", + "protected", + "public", + "register", + "reinterpret_cast", + "requires", + "return", + "short", + "signed", + "sizeof", + "static", + "static_assert", + "static_cast", + "struct", + "switch", + "synchronized", + "template", + "this", + "thread_local", + "throw", + "true", + "try", + "typedef", + "typeid", + "typename", + "union", + "unsigned", + "using", + "virtual", + "void", + "volatile", + "wchar_t", + "while", + "xor", + "xor_eq", + }; + for(const char *reserved_word : reserved_words) { if(retval == reserved_word) { @@ -581,8 +607,8 @@ struct Generator::Tester static void test() { for(auto &input : { - "abc def", "AbcDef", "ABCDef", "'abc, def'", - }) + "abc def", "AbcDef", "ABCDef", "'abc, def'", + }) { std::cout << "\"" << input << "\" -> " << get_member_name_from_words(input) << std::endl; @@ -606,6 +632,14 @@ std::string Generator::get_member_name_from_operand( return get_member_name_from_words(operand.kind); } +std::string Generator::get_enum_with_parameters_struct_name( + Generator_state &state, const ast::Operand_kinds::Operand_kind &operand_kind) +{ + if(get_operand_has_any_parameters(state, operand_kind)) + return operand_kind.kind + "_with_parameters"; + return operand_kind.kind; +} + void Generator::write_struct_nonstatic_members_and_constructors(Generator_state &state, const std::string &struct_name, const std::string *member_types, @@ -728,7 +762,7 @@ struct Spirv_header_generator final : public Generator } virtual void run(Generator_args &generator_args, const ast::Top_level &top_level) const override { - Generator_state state(this, generator_args); + Generator_state state(this, generator_args, top_level); state.open_output_file(); write_file_comments(state, top_level.copyright); write_file_guard_start(state); @@ -851,20 +885,16 @@ constexpr Word magic_number = )") state << ",\n"; } } - state << "};\n"; - if(!is_bit_enum) + state << "};\n" + "\n" + "vulkan_cpu_util_generate_enum_traits(" + << operand_kind->kind; { - state << "\n" - "vulkan_cpu_util_generate_enum_traits(" - << operand_kind->kind; - { - auto push_indent = state.pushed_indent(); - for(auto &enumerant : unique_enumerants) - state << ",\n" << indent << operand_kind->kind - << "::" << get_enumerant_name( - operand_kind->kind, enumerant.enumerant, false); - state << ");\n"; - } + auto push_indent = state.pushed_indent(); + for(auto &enumerant : unique_enumerants) + state << ",\n" << indent << operand_kind->kind << "::" + << get_enumerant_name(operand_kind->kind, enumerant.enumerant, false); + state << ");\n"; } state << "\n" "constexpr const char *get_enumerant_name(" @@ -985,7 +1015,8 @@ constexpr Word magic_number = )") auto &doc = util::get(operand_kind->value); auto base_type = "std::vector"; if(operand_kind->kind == "LiteralInteger") - base_type = "std::uint64_t"; + base_type = "std::uint32_t"; // TODO: fix after determining if LiteralInteger + // can be multiple words else if(operand_kind->kind == "LiteralString") base_type = "std::string"; else if(operand_kind->kind == "LiteralExtInstInteger") @@ -1182,7 +1213,7 @@ struct Spirv_source_generator final : public Generator } virtual void run(Generator_args &generator_args, const ast::Top_level &top_level) const override { - Generator_state state(this, generator_args); + Generator_state state(this, generator_args, top_level); state.open_output_file(); write_file_comments(state, top_level.copyright); state << "#include \"spirv.h\"\n"; @@ -1194,13 +1225,21 @@ struct Parser_header_generator final : public Generator Parser_header_generator() : Generator("parser.h") { } - static std::string get_dump_function_name(std::string kind) + static std::string get_dump_operand_function_name(std::string kind) { return "dump_operand_" + std::move(kind); } + static std::string get_parse_operand_function_name(std::string kind) + { + return "parse_operand_" + std::move(kind); + } + static std::string get_parse_instruction_function_name(std::string opname) + { + return "parse_instruction_" + get_enumerant_name(op_enum_name, opname, true); + } virtual void run(Generator_args &generator_args, const ast::Top_level &top_level) const override { - Generator_state state(this, generator_args); + Generator_state state(this, generator_args, top_level); state.open_output_file(); write_file_comments(state, top_level.copyright); write_file_guard_start(state); @@ -1208,6 +1247,7 @@ struct Parser_header_generator final : public Generator #include #include #include "util/optional.h" +#include "json/json.h" #include )"; @@ -1215,9 +1255,11 @@ struct Parser_header_generator final : public Generator state << indent(R"(struct Parse_error { `std::size_t word_index; +`std::size_t instruction_word_index; `std::string message; -`Parse_error(std::size_t word_index, std::string message) noexcept +`Parse_error(std::size_t word_index, std::size_t instruction_word_index, std::string message) noexcept ``: word_index(word_index), +`` instruction_word_index(instruction_word_index), `` message(std::move(message)) `{ `} @@ -1230,7 +1272,10 @@ struct Parser_header_generator final : public Generator { auto push_indent = state.pushed_indent(); state << indent(R"(virtual ~Parse_semantics_generic() = default; -virtual std::unique_ptr handle_error(std::size_t word_index, std::string message) = 0; +virtual std::unique_ptr handle_error(std::size_t word_index, std::size_t instruction_word_index, std::string message) = 0; +virtual void handle_spirv_version(unsigned major, unsigned minor) = 0; +virtual void handle_generator_magic_number(Word value) = 0; +virtual void handle_id_bound(Word id_bound) = 0; )"); for(auto &instruction : top_level.instructions.instructions) { @@ -1252,7 +1297,10 @@ struct Parse_dump final : public Parse_semantics_generic { auto push_indent = state.pushed_indent(); state << indent( - R"(virtual std::unique_ptr handle_error(std::size_t word_index, std::string message) override; + R"(virtual std::unique_ptr handle_error(std::size_t word_index, std::size_t instruction_word_index, std::string message) override; +virtual void handle_spirv_version(unsigned major, unsigned minor) override; +virtual void handle_generator_magic_number(Word value) override; +virtual void handle_id_bound(Word id_bound) override; )"); for(auto &instruction : top_level.instructions.instructions) { @@ -1262,7 +1310,7 @@ struct Parse_dump final : public Parse_semantics_generic } for(auto &operand_kind : top_level.operand_kinds.operand_kinds) { - auto dump_function_name = get_dump_function_name(operand_kind.kind); + auto dump_function_name = get_dump_operand_function_name(operand_kind.kind); state << indent("void ") << dump_function_name << "(const " << operand_kind.kind << " &v);\n"; state << indent("void ") << dump_function_name << "(const util::optional<" @@ -1279,21 +1327,284 @@ struct Parse_dump final : public Parse_semantics_generic "{\n"; { auto push_indent = state.pushed_indent(); - state << indent( - R"(static std::unique_ptr parse(const Word *words, std::size_t word_count, Semantics &semantics) + for(auto &operand_kind : top_level.operand_kinds.operand_kinds) + { + auto parse_function_name = get_parse_operand_function_name(operand_kind.kind); + state + << indent(R"(static std::unique_ptr )") << parse_function_name + << indent( + true, + R"((const Word *words, std::size_t word_count, Semantics &semantics, std::size_t error_instruction_index, std::size_t &word_index, )") + << operand_kind.kind << indent(true, + R"( &value) +{ +`if(word_index >= word_count) +``return semantics.handle_error(error_instruction_index + word_index, error_instruction_index, "instruction missing operand"); +)"); + auto push_indent = state.pushed_indent(); + switch(operand_kind.category) + { + case ast::Operand_kinds::Operand_kind::Category::bit_enum: + { + state << indent(R"(value = static_cast<)") << operand_kind.kind + << indent(true, R"(>(words[word_index++]); +)"); + break; + } + case ast::Operand_kinds::Operand_kind::Category::value_enum: + { + state << indent(R"(value = static_cast<)") << operand_kind.kind + << indent(true, R"(>(words[word_index]); +if(util::Enum_traits<)") << operand_kind.kind + << indent(true, R"(>::find_value(value) == util::Enum_traits<)") + << operand_kind.kind << indent(true, R"(>::npos) +`return semantics.handle_error(error_instruction_index + word_index, error_instruction_index, "invalid enum value"); +word_index++; +)"); + break; + } + case ast::Operand_kinds::Operand_kind::Category::composite: + { + auto &bases = + util::get(operand_kind.value); + for(std::size_t i = 0; i < bases.values.size(); i++) + { + state << indent; + if(i == 0) + state << indent(true, "auto "); + state << indent(true, "parse_error = ") + << get_parse_operand_function_name(bases.values[i]) + << "(words, word_count, semantics, error_instruction_index, " + "word_index, value." + << json::ast::Number_value::append_unsigned_integer_to_string(i + 1, + "part_") + << indent(true, R"(); +if(parse_error) +`return parse_error; +)"); + } + break; + } + case ast::Operand_kinds::Operand_kind::Category::id: + { + state << indent(R"(value = static_cast(words[word_index++]); +)"); + break; + } + case ast::Operand_kinds::Operand_kind::Category::literal: + { + if(operand_kind.kind == "LiteralInteger") + { + // TODO: fix after determining if LiteralInteger can be multiple words + state << indent(R"(value = words[word_index++]; +)"); + } + else if(operand_kind.kind == "LiteralExtInstInteger") + { + state << indent(R"(value = words[word_index++]; +)"); + } + else if(operand_kind.kind == "LiteralString") + { + state << indent( + R"(value.clear(); +bool done = false; +while(!done) { +`if(word_index >= word_count) +``return semantics.handle_error(error_instruction_index + word_index, error_instruction_index, "string missing terminating null"); +`Word word = words[word_index++]; +`for(std::size_t i = 0; i < 4; i++) +`{ +``unsigned char ch = word & 0xFFU; +``word >>= 8; +``if(ch == '\0') +``{ +```done = true; +```if(word != 0) +````return semantics.handle_error(error_instruction_index + word_index, error_instruction_index, "string has non-zero padding"); +``} +``else +``{ +```value += ch; +``} +`} +} )"); + } + else if(operand_kind.kind == "LiteralSpecConstantOpInteger") + { +#warning finish + state << indent(R"(value = static_cast<)") << op_enum_name + << indent(true, R"(>(words[word_index++]); +)"); + } + else + { + state << indent( + R"(static_assert(std::is_same &>::value, "missing parse code for operand kind"); +value.clear(); +value.reserve(word_count - word_index); +while(word_index < word_count) +`value.push_back(words[word_index++]); +)"); + } + break; + } + } + push_indent.finish(); + state << indent(R"(`return nullptr; +} +)"); + } + for(auto &instruction : top_level.instructions.instructions) { + auto struct_name = get_enumerant_name(op_enum_name, instruction.opname, true); + auto parse_function_name = get_parse_instruction_function_name(instruction.opname); + state + << indent(R"(static std::unique_ptr )") << parse_function_name + << indent( + true, + R"((const Word *words, std::size_t word_count, Semantics &semantics, std::size_t error_instruction_index) +{ +`std::size_t word_index = 1; // skip opcode +)"); auto push_indent2 = state.pushed_indent(); - state << indent(R"(std::size_t word_index = 0; -if(word_index >= word_count) -`return semantics.handle_error(word_index, "hit EOF when parsing magic number"); -if(words[word_index] != magic_number) -`return semantics.handle_error(word_index, "invalid magic number"); -return nullptr; + state << indent << struct_name << " instruction;\n"; + if(!instruction.operands.empty()) + state << indent("std::unique_ptr parse_error;\n"); + for(auto &operand : instruction.operands.operands) + { + auto parse_operand_function_name = + get_parse_operand_function_name(operand.kind); + auto member_name = get_member_name_from_operand(operand); + switch(operand.quantifier) + { + case ast::Instructions::Instruction::Operands::Operand::Quantifier::none: + { + state + << indent(R"(parse_error = )") << parse_operand_function_name + << indent( + true, + R"((words, word_count, semantics, error_instruction_index, word_index, instruction.)") + << member_name << indent(true, R"(); +if(parse_error) +`return parse_error; +)"); + break; + } + case ast::Instructions::Instruction::Operands::Operand::Quantifier::optional: + { + state + << indent(R"(if(word_index < word_count) +{ +`instruction.)") << member_name + << indent(true, R"(.emplace(); +`parse_error = )") << parse_operand_function_name + << indent( + true, + R"((words, word_count, semantics, error_instruction_index, word_index, *instruction.)") + << member_name << indent(true, R"(); +`if(parse_error) +``return parse_error; +} +)"); + break; + } + case ast::Instructions::Instruction::Operands::Operand::Quantifier::variable: + { + state + << indent(R"(while(word_index < word_count) +{ +`instruction.)") << member_name + << indent(true, R"(.emplace_back(); +`parse_error = )") << parse_operand_function_name + << indent( + true, + R"((words, word_count, semantics, error_instruction_index, word_index, instruction.)") + << member_name << indent(true, R"(.back()); +`if(parse_error) +``return parse_error; +} +)"); + } + } + } + push_indent2.finish(); + state << indent(R"(`if(word_index < word_count) +``return semantics.handle_error(error_instruction_index + word_index, error_instruction_index, "extra words at end of instruction"); +`semantics.handle_instruction(std::move(instruction)); +`return nullptr; +} )"); } - state << indent("}\n"); + state << indent( + R"(static std::unique_ptr parse_instruction(const Word *words, std::size_t word_count, Semantics &semantics, std::size_t error_instruction_index) +{ +`Op op = static_cast(words[0] & 0xFFFFU); +`switch(op) +`{ +)"); + for(auto &instruction : top_level.instructions.instructions) + { + auto push_indent2 = state.pushed_indent(2); + auto enumerant_name = get_enumerant_name(op_enum_name, instruction.opname, true); + auto parse_function_name = get_parse_instruction_function_name(instruction.opname); + state << indent("case ") << op_enum_name << "::" << enumerant_name + << indent(true, R"(: +`return )") << parse_function_name + << indent(true, R"((words, word_count, semantics, error_instruction_index); +)"); + } + state << indent(R"(`} +`return semantics.handle_error(error_instruction_index, error_instruction_index, json::ast::Number_value::append_unsigned_integer_to_string(static_cast(op), "unknown instruction: 0x", 0x10)); +} + +static std::unique_ptr parse(const Word *words, std::size_t word_count, Semantics &semantics) +{ +`std::size_t word_index = 0; +`if(word_index >= word_count) +``return semantics.handle_error(word_index, 0, "hit EOF when parsing magic number"); +`if(words[word_index] != magic_number) +``return semantics.handle_error(word_index, 0, "invalid magic number"); +`word_index++; +`if(word_index >= word_count) +``return semantics.handle_error(word_index, 0, "hit EOF when parsing SPIR-V version"); +`if(words[word_index] & ~0xFFFF00UL) +``return semantics.handle_error(word_index, 0, "invalid SPIR-V version"); +`auto input_major_version = words[word_index] >> 16; +`auto input_minor_version = (words[word_index] >> 8) & 0xFFU; +`semantics.handle_spirv_version(input_major_version, input_minor_version); +`if(input_major_version != major_version || input_minor_version > minor_version) +``return semantics.handle_error(word_index, 0, "SPIR-V version not supported"); +`word_index++; +`if(word_index >= word_count) +``return semantics.handle_error(word_index, 0, "hit EOF when parsing generator's magic number"); +`semantics.handle_generator_magic_number(words[word_index++]); +`if(word_index >= word_count) +``return semantics.handle_error(word_index, 0, "hit EOF when parsing id bound"); +`semantics.handle_id_bound(words[word_index++]); +`if(word_index >= word_count) +``return semantics.handle_error(word_index, 0, "hit EOF when parsing SPIR-V shader header"); +`if(words[word_index] != 0) +``return semantics.handle_error(word_index, 0, "nonzero reserved word in SPIR-V shader header"); +`word_index++; +`// now we've finished reading the shader header, the rest of the shader is just instructions +`while(word_index < word_count) +`{ +``auto instruction_word_count = words[word_index] >> 16; +``if(instruction_word_count == 0) +```return semantics.handle_error(word_index, word_index, "invalid instruction"); +``if(word_index + instruction_word_count > word_count) +```return semantics.handle_error(word_index, word_index, "instruction longer than rest of shader"); +``auto parse_error = parse_instruction(words + word_index, instruction_word_count, semantics, word_index); +``if(parse_error) +```return parse_error; +``word_index += instruction_word_count; +`} +`return nullptr; +} +)"); #warning finish } state << "};\n"; @@ -1310,10 +1621,11 @@ struct Parser_source_generator final : public Generator } virtual void run(Generator_args &generator_args, const ast::Top_level &top_level) const override { - Generator_state state(this, generator_args); + Generator_state state(this, generator_args, top_level); state.open_output_file(); write_file_comments(state, top_level.copyright); state << "#include \"parser.h\"\n" + "#include \n" "\n"; write_namespaces_start(state, spirv_namespace_names); state << indent(R"(namespace @@ -1325,15 +1637,30 @@ struct Parser_source_generator final : public Generator } } -std::unique_ptr Parse_dump::handle_error(std::size_t word_index, std::string message) +std::unique_ptr Parse_dump::handle_error(std::size_t word_index, std::size_t instruction_word_index, std::string message) { -`return std::unique_ptr(new Parse_error(word_index, std::move(message))); +`return std::unique_ptr(new Parse_error(word_index, instruction_word_index, std::move(message))); +} + +void Parse_dump::handle_spirv_version(unsigned major, unsigned minor) +{ +`os << "SPIR-V version " << major << "." << minor << "\n"; +} + +void Parse_dump::handle_generator_magic_number(Word value) +{ +`os << "generator magic number: " << json::ast::Number_value::append_unsigned_integer_to_string(value, "0x", 0x10) << "\n"; +} + +void Parse_dump::handle_id_bound(Word id_bound) +{ +`os << "id bound: " << json::ast::Number_value::unsigned_integer_to_string(id_bound) << "\n"; } )"); for(auto &operand_kind : top_level.operand_kinds.operand_kinds) { auto dump_function_name = - Parser_header_generator::get_dump_function_name(operand_kind.kind); + Parser_header_generator::get_dump_operand_function_name(operand_kind.kind); { state << indent(R"( void Parse_dump::)") << dump_function_name @@ -1345,29 +1672,130 @@ void Parse_dump::)") << dump_function_name { case ast::Operand_kinds::Operand_kind::Category::bit_enum: { - auto &enumerants = - util::get(operand_kind.value); -#warning finish + state << indent(R"(Word bits = static_cast(v); +util::Enum_set<)") << operand_kind.kind + << indent(true, R"(> enum_set{}; +for(auto value : util::Enum_traits<)") + << operand_kind.kind << indent(true, R"(>::values) +{ +`if(static_cast(value) == 0) +`{ +``if(v == value) +```enum_set.insert(value); +``continue; +`} +`if((bits & static_cast(value)) == static_cast(value)) +`{ +``bits &= ~static_cast(value); +``enum_set.insert(value); +`} +} +bool first = true; +for(auto value : enum_set) +{ +`if(first) +``first = false; +`else +``os << " | "; +`os << get_enumerant_name(value); +} +if(bits) +{ +`if(!first) +``os << " | "; +`os << json::ast::Number_value::append_unsigned_integer_to_string(bits, "0x", 0x10); +} +else if(first) +{ +`os << "0"; +} +)"); break; } case ast::Operand_kinds::Operand_kind::Category::value_enum: { -#warning finish + state << indent(R"(if(util::Enum_traits<)") << operand_kind.kind + << indent(true, R"(>::find_value(v) == util::Enum_traits<)") + << operand_kind.kind << indent(true, R"(>::npos) +`os << json::ast::Number_value::unsigned_integer_to_string(static_cast(v)); +else +`os << get_enumerant_name(v); +)"); break; } case ast::Operand_kinds::Operand_kind::Category::composite: { -#warning finish + auto &bases = + util::get(operand_kind.value); + state << indent("os << \"{\";\n"); + for(std::size_t i = 0; i < bases.values.size(); i++) + { + if(i != 0) + { + state << indent("os << \", \";\n"); + } + state << indent << Parser_header_generator::get_dump_operand_function_name( + bases.values[i]) + << "(v." + << json::ast::Number_value::append_unsigned_integer_to_string(i + 1, + "part_") + << ");\n"; + } + state << indent("os << \"}\";\n"); break; } case ast::Operand_kinds::Operand_kind::Category::id: { -#warning finish + state << indent( + R"(os << json::ast::Number_value::append_unsigned_integer_to_string(v, "#"); +)"); break; } case ast::Operand_kinds::Operand_kind::Category::literal: { -#warning finish + if(operand_kind.kind == "LiteralInteger") + { + state << indent( + R"(os << json::ast::Number_value::append_unsigned_integer_to_string(v, "0x"); +)"); + } + else if(operand_kind.kind == "LiteralExtInstInteger") + { + state << indent( + R"(os << json::ast::Number_value::append_unsigned_integer_to_string(v, "0x"); +)"); + } + else if(operand_kind.kind == "LiteralString") + { + state << indent( + R"(json::ast::String_value::write(os, v); +)"); + } + else if(operand_kind.kind == "LiteralSpecConstantOpInteger") + { + state << indent(R"(if(util::Enum_traits<)") << op_enum_name + << indent(true, R"(>::find_value(v) == util::Enum_traits<)") + << op_enum_name << indent(true, R"(>::npos) +`os << json::ast::Number_value::unsigned_integer_to_string(static_cast(v)); +else +`os << get_enumerant_name(v); +)"); + } + else + { + state << indent( + R"(static_assert(std::is_same &>::value, "missing dump code for operand kind"); +auto separator = ""; +os << "{"; +for(Word value : v) +{ +`os << separator; +`separator = ", "; +`os << json::ast::Number_value::append_unsigned_integer_to_string(value, "0x", 0x10, 8); +} +os << "}"; +)"); + } break; } } @@ -1402,7 +1830,6 @@ void Parse_dump::)") `os << "}"; } )"); -#warning finish } for(auto &instruction : top_level.instructions.instructions) { @@ -1420,7 +1847,7 @@ void Parse_dump::)") auto push_indent = state.pushed_indent(); auto member_name = get_member_name_from_operand(operand); state << indent("os << \" ") << member_name << indent(true, R"(:"; -)") << indent << Parser_header_generator::get_dump_function_name(operand.kind) +)") << indent << Parser_header_generator::get_dump_operand_function_name(operand.kind) << indent(true, R"((instruction.)") << member_name << indent(true, R"(); os << "\n"; )"); diff --git a/src/generate_spirv_parser/generate.h b/src/generate_spirv_parser/generate.h index 04aadfc..7a76acb 100644 --- a/src/generate_spirv_parser/generate.h +++ b/src/generate_spirv_parser/generate.h @@ -25,6 +25,7 @@ #define GENERATE_SPIRV_PARSER_GENERATE_H_ #include "ast.h" +#include "util/string_view.h" #include #include #include @@ -32,7 +33,9 @@ #include #include #include +#include #include +#include namespace vulkan_cpu { @@ -40,6 +43,11 @@ namespace generate_spirv_parser { namespace generate { +struct Generate_error : public std::runtime_error +{ + using runtime_error::runtime_error; +}; + class Generator { private: @@ -68,7 +76,13 @@ protected: std::string full_output_file_name; std::string guard_macro_name; std::ofstream os; - explicit Generator_state(const Generator *generator, Generator_args &generator_args); + const ast::Top_level &top_level; + std::unordered_map operand_kind_map; + std::unordered_map + operand_has_any_parameters_map; + explicit Generator_state(const Generator *generator, + Generator_args &generator_args, + const ast::Top_level &top_level); void open_output_file(); template ())> Generator_state &operator<<(T &&v) @@ -226,7 +240,7 @@ 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, + static std::string get_enumerant_name(util::string_view enumeration_name, std::string enumerant_name, bool input_name_should_have_prefix) { @@ -235,15 +249,6 @@ protected: std::move(enumerant_name), input_name_should_have_prefix); } - 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), - 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, @@ -358,6 +363,33 @@ protected: 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 const ast::Operand_kinds::Operand_kind &get_operand_kind_from_string( + Generator_state &state, const std::string &operand_kind_str) + { + auto *retval = state.operand_kind_map[operand_kind_str]; + if(!retval) + throw Generate_error("operand kind not found: " + operand_kind_str); + return *retval; + } + static bool get_operand_has_any_parameters(Generator_state &state, + const ast::Operand_kinds::Operand_kind &operand_kind) + { + return state.operand_has_any_parameters_map[&operand_kind]; + } + static std::string get_enumerant_parameters_struct_name(util::string_view enumeration_name, std::string enumerant_name, bool input_name_should_have_prefix) + { + auto retval = "_" + get_enumerant_name(enumeration_name, enumerant_name, input_name_should_have_prefix) + "_parameters"; + retval.insert(retval.begin(), enumeration_name.begin(), enumeration_name.end()); + return retval; + } + static std::string get_enum_with_parameters_struct_name( + Generator_state &state, const ast::Operand_kinds::Operand_kind &operand_kind); + static std::string get_enum_with_parameters_struct_name(Generator_state &state, + const std::string &operand_kind_str) + { + return get_enum_with_parameters_struct_name( + state, get_operand_kind_from_string(state, operand_kind_str)); + } static void write_struct_nonstatic_members_and_constructors(Generator_state &state, const std::string &struct_name, const std::string *member_types, diff --git a/src/spirv/CMakeLists.txt b/src/spirv/CMakeLists.txt index 31995bc..f85af00 100644 --- a/src/spirv/CMakeLists.txt +++ b/src/spirv/CMakeLists.txt @@ -38,5 +38,5 @@ add_custom_command(OUTPUT ${spirv_parser_sources} ${spirv_parser_headers} COMMENT "Generating SPIR-V Parser") set(sources ${sources} ${spirv_parser_sources}) add_library(spirv STATIC ${sources}) -target_link_libraries(spirv util) +target_link_libraries(spirv util json) target_include_directories(spirv PUBLIC ${spirv_parser_generated_include_dir}) diff --git a/src/util/enum.h b/src/util/enum.h index 51e0826..11e7bc2 100644 --- a/src/util/enum.h +++ b/src/util/enum.h @@ -140,7 +140,7 @@ public: } else if(value_count < binary_search_transition) { - retval = -1; + retval = npos; for(std::size_t i = 0; i < value_count; i++) { if(values[i] == value) -- 2.30.2