From 06ba65933a89a4da96e3dd0776a9581c9f8e8c30 Mon Sep 17 00:00:00 2001 From: Jacob Lifshay Date: Mon, 19 Jun 2017 23:06:56 -0700 Subject: [PATCH] working on generate_spirv_parser -- generates parser cpp/h --- .gitignore | 2 + src/demo/demo.cpp | 17 + src/generate_spirv_parser/generate.cpp | 653 +++++++++++++++--- src/generate_spirv_parser/generate.h | 79 ++- .../generate_spirv_parser.cpp | 2 +- src/spirv/CMakeLists.txt | 4 +- src/spirv/spirv.cpp | 23 - src/util/constexpr_array.h | 84 ++- src/util/enum.h | 48 +- 9 files changed, 752 insertions(+), 160 deletions(-) delete mode 100644 src/spirv/spirv.cpp diff --git a/.gitignore b/.gitignore index 2244dde..fd1cf38 100644 --- a/.gitignore +++ b/.gitignore @@ -7,3 +7,5 @@ Makefile /test-files/test.spv out.json compile_commands.json +/.kdev4/ +*.kdev4 diff --git a/src/demo/demo.cpp b/src/demo/demo.cpp index 2ef3616..616ef95 100644 --- a/src/demo/demo.cpp +++ b/src/demo/demo.cpp @@ -22,11 +22,13 @@ */ #include #include +#include #include #include #include #include #include "spirv/spirv.h" +#include "spirv/parser.h" #include "util/optional.h" namespace vulkan_cpu @@ -202,7 +204,22 @@ int test_main(int argc, char **argv) { auto file = load_file("test-files/test.spv"); if(file) + { dump_words(*file); + std::ostringstream os; + spirv::Parse_dump semantics(os); + 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; + 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 85e3968..4389960 100644 --- a/src/generate_spirv_parser/generate.cpp +++ b/src/generate_spirv_parser/generate.cpp @@ -28,6 +28,7 @@ #include #include #include +#include namespace vulkan_cpu { @@ -173,17 +174,49 @@ std::string Generator::get_enumerant_name(const char *enumeration_name, return enumerant_name; } -void Generator::write_indent(Generator_state &state) +void Generator::write_indent_absolute(Generator_state &state, std::size_t amount) { static constexpr auto indent_string = " "; - for(std::size_t i = state.indent_level; i > 0; i--) + for(std::size_t i = 0; i < amount; i++) state << indent_string; } +void Generator::write_indent_interpreted_text(Generator_state &state, + const char *text, + std::ptrdiff_t offset, + bool start_indented) +{ + bool did_indent = start_indented; + std::size_t indent_amount = offset + state.indent_level; + for(; *text; text++) + { + auto &ch = *text; + if(ch == '\n') + { + state << ch; + did_indent = false; + indent_amount = offset + state.indent_level; + } + else if(!did_indent && ch == '`') + { + indent_amount++; + } + else + { + if(!did_indent) + { + did_indent = true; + write_indent_absolute(state, indent_amount); + } + state << ch; + } + } +} + void Generator::write_automatically_generated_file_warning(Generator_state &state) { - state << "/* This file is automatically generated by " - "generate_spirv_parser. DO NOT MODIFY. */\n"; + state << R"(/* This file is automatically generated by generate_spirv_parser. DO NOT MODIFY. */ +)"; } void Generator::write_copyright_comment(Generator_state &state, const ast::Copyright ©right) @@ -212,8 +245,10 @@ void Generator::write_copyright_comment(Generator_state &state, const ast::Copyr void Generator::write_file_guard_start(Generator_state &state) { - state << "#ifdef " << state.guard_macro_name << "\n#define " << state.guard_macro_name - << "\n\n"; + state << "#ifndef " << state.guard_macro_name << R"( +#define )" + << state.guard_macro_name << "\n" + "\n"; } void Generator::write_file_guard_end(Generator_state &state) @@ -223,12 +258,14 @@ void Generator::write_file_guard_end(Generator_state &state) void Generator::write_namespace_start(Generator_state &state, const char *namespace_name) { - state << "namespace " << namespace_name << "\n{\n"; + state << "namespace " << namespace_name << "\n" + "{\n"; } void Generator::write_namespace_start(Generator_state &state, const std::string &namespace_name) { - state << "namespace " << namespace_name << "\n{\n"; + state << "namespace " << namespace_name << "\n" + "{\n"; } void Generator::write_namespace_end(Generator_state &state) @@ -422,6 +459,109 @@ 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", + }) + { + if(retval == reserved_word) + { + retval += '_'; + break; + } + } return retval; } @@ -490,8 +630,9 @@ void Generator::write_struct_nonstatic_members_and_constructors(Generator_state state << "\n"; } } - state << indent << "{\n"; - state << indent << "}\n"; + state << indent(R"({ +} +)"); if(member_count != 0) { state << indent; @@ -520,11 +661,31 @@ void Generator::write_struct_nonstatic_members_and_constructors(Generator_state state << "\n"; } } - state << indent << "{\n"; - state << indent << "}\n"; + state << indent(R"({ +} +)"); } } +std::vector + Generator::get_unique_enumerants( + std::vector enumerants) +{ + std::unordered_set values; + std::size_t output_index = 0; + for(std::size_t input_index = 0; input_index < enumerants.size(); input_index++) + { + if(std::get<1>(values.insert(enumerants[input_index].value))) + { + if(output_index != input_index) + enumerants[output_index] = std::move(enumerants[input_index]); + output_index++; + } + } + enumerants.erase(enumerants.begin() + output_index, enumerants.end()); + return enumerants; +} + struct Spirv_header_generator final : public Generator { Spirv_header_generator() : Generator("spirv.h") @@ -571,21 +732,28 @@ struct Spirv_header_generator final : public Generator state.open_output_file(); write_file_comments(state, top_level.copyright); write_file_guard_start(state); - state << "#include \n" - "#include \"util/enum.h\"\n" - "#include \"util/optional.h\"\n" - "#include \n"; - state << "\n"; + state << indent(R"(#include +#include "util/enum.h" +#include "util/optional.h" +#include +)"); 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 = " - << unsigned_dec_integer_literal(top_level.major_version) << ";\n"; - state << "constexpr std::uint32_t minor_version = " - << unsigned_dec_integer_literal(top_level.minor_version) << ";\n"; - state << "constexpr std::uint32_t revision = " + state << indent(R"(typedef std::uint32_t Word; +typedef Word Id; +enum class Op : Word; +constexpr Word magic_number = )") + << unsigned_hex_integer_literal(top_level.magic_number, 8) + << indent(true, + ";\n" + "constexpr std::uint32_t major_version = ") + << unsigned_dec_integer_literal(top_level.major_version) + << indent(true, + ";\n" + "constexpr std::uint32_t minor_version = ") + << unsigned_dec_integer_literal(top_level.minor_version) + << indent(true, + ";\n" + "constexpr std::uint32_t revision = ") << unsigned_dec_integer_literal(top_level.revision) << ";\n"; auto extensions_set = get_extensions(top_level); std::vector extensions_list; @@ -593,19 +761,22 @@ struct Spirv_header_generator final : public Generator for(auto &extension : extensions_set) extensions_list.push_back(extension); std::sort(extensions_list.begin(), extensions_list.end()); - state << "\n" - "enum class " - << extension_enum_name << " : std::size_t\n" - "{\n"; + state << indent( + "\n" + "enum class ") + << extension_enum_name << indent(true, + " : std::size_t\n" + "{\n"); { auto push_indent = state.pushed_indent(); for(auto &extension : extensions_list) state << indent << get_enumerant_name(extension_enum_name, extension, false) << ",\n"; } - state << "};\n" - "\n" - "vulkan_cpu_util_generate_enum_traits(" + state << indent( + "};\n" + "\n" + "vulkan_cpu_util_generate_enum_traits(") << extension_enum_name; { auto push_indent = state.pushed_indent(); @@ -614,21 +785,29 @@ struct Spirv_header_generator final : public Generator << "::" << get_enumerant_name(extension_enum_name, extension, false); state << ");\n"; } - state << "\n" - "constexpr const char *get_enumerant_name(" - << extension_enum_name << " v) noexcept\n" - "{\n"; + state << indent( + "\n" + "constexpr const char *get_enumerant_name(") + << extension_enum_name << indent(true, + " v) noexcept\n" + "{\n"); { auto push_indent = state.pushed_indent(); - state << indent << "switch(v)\n" << indent << "{\n"; + state << indent( + "switch(v)\n" + "{\n"); for(auto &extension : extensions_list) { - state << indent << "case " << extension_enum_name - << "::" << get_enumerant_name(extension_enum_name, extension, false) << ":\n"; - auto push_indent2 = state.pushed_indent(); - state << indent << "return \"" << extension << "\";\n"; + state << indent("case ") << extension_enum_name + << "::" << get_enumerant_name(extension_enum_name, extension, false) + << indent(true, + ":\n" + "`return \"") + << extension << "\";\n"; } - state << indent << "}\n" << indent << "return \"\";\n"; + state << indent( + "}\n" + "return \"\";\n"); } state << "}\n"; std::vector operand_kinds; @@ -653,6 +832,7 @@ struct Spirv_header_generator final : public Generator operand_kind->category == ast::Operand_kinds::Operand_kind::Category::bit_enum; auto &enumerants = util::get(operand_kind->value); + auto unique_enumerants = get_unique_enumerants(enumerants.enumerants); state << "\n" "enum class " << operand_kind->kind << " : Word\n" @@ -679,7 +859,7 @@ struct Spirv_header_generator final : public Generator << operand_kind->kind; { auto push_indent = state.pushed_indent(); - for(auto &enumerant : enumerants.enumerants) + for(auto &enumerant : unique_enumerants) state << ",\n" << indent << operand_kind->kind << "::" << get_enumerant_name( operand_kind->kind, enumerant.enumerant, false); @@ -692,16 +872,21 @@ struct Spirv_header_generator final : public Generator "{\n"; { auto push_indent = state.pushed_indent(); - state << indent << "switch(v)\n" << indent << "{\n"; - for(auto &enumerant : enumerants.enumerants) + state << indent( + "switch(v)\n" + "{\n"); + for(auto &enumerant : unique_enumerants) { - state << indent << "case " << operand_kind->kind << "::" + 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"; + << indent(true, + ":\n" + "`return \"") + << enumerant.enumerant << "\";\n"; } - state << indent << "}\n" << indent << "return \"\";\n"; + state << indent( + "}\n" + "return \"\";\n"); } state << "}\n" "\n" @@ -711,16 +896,21 @@ struct Spirv_header_generator final : public Generator "{\n"; { auto push_indent = state.pushed_indent(); - state << indent << "switch(v)\n" << indent << "{\n"; - for(auto &enumerant : enumerants.enumerants) + state << indent( + "switch(v)\n" + "{\n"); + for(auto &enumerant : unique_enumerants) { - state << indent << "case " << operand_kind->kind << "::" + 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"; + << indent(true, + ":\n" + "return ") + << enumerant.capabilities << ";\n"; } - state << indent << "}\n" << indent << "return {};\n"; + state << indent( + "}\n" + "return {};\n"); } state << "}\n" "\n" @@ -730,16 +920,21 @@ struct Spirv_header_generator final : public Generator "{\n"; { auto push_indent = state.pushed_indent(); - state << indent << "switch(v)\n" << indent << "{\n"; - for(auto &enumerant : enumerants.enumerants) + state << indent( + "switch(v)\n" + "{\n"); + for(auto &enumerant : unique_enumerants) { - state << indent << "case " << operand_kind->kind << "::" + 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"; + << indent(true, + ":\n" + "return ") + << enumerant.extensions << ";\n"; } - state << indent << "}\n" << indent << "return {};\n"; + state << indent( + "}\n" + "return {};\n"); } state << "}\n"; break; @@ -855,16 +1050,21 @@ struct Spirv_header_generator final : public Generator "{\n"; { auto push_indent = state.pushed_indent(); - state << indent << "switch(v)\n" << indent << "{\n"; + state << indent( + "switch(v)\n" + "{\n"); for(auto &instruction : top_level.instructions.instructions) { - state << indent << "case " << op_enum_name + 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"; + << indent(true, + ":\n" + "return \"") + << instruction.opname << "\";\n"; } - state << indent << "}\n" << indent << "return \"\";\n"; + state << indent( + "}\n" + "return \"\";\n"); } state << "}\n" "\n" @@ -874,16 +1074,21 @@ struct Spirv_header_generator final : public Generator "{\n"; { auto push_indent = state.pushed_indent(); - state << indent << "switch(v)\n" << indent << "{\n"; + state << indent( + "switch(v)\n" + "{\n"); for(auto &instruction : top_level.instructions.instructions) { - state << indent << "case " << op_enum_name + 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"; + << indent(true, + ":\n" + "return ") + << instruction.capabilities << ";\n"; } - state << indent << "}\n" << indent << "return {};\n"; + state << indent( + "}\n" + "return {};\n"); } state << "}\n" "\n" @@ -893,16 +1098,20 @@ struct Spirv_header_generator final : public Generator "{\n"; { auto push_indent = state.pushed_indent(); - state << indent << "switch(v)\n" << indent << "{\n"; + state << indent( + "switch(v)\n" + "{\n"); for(auto &instruction : top_level.instructions.instructions) { - state << indent << "case " << op_enum_name + 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("return ") << instruction.extensions << ";\n"; } - state << indent << "}\n" << indent << "return {};\n"; + state << indent( + "}\n" + "return {};\n"); } state << "}\n"; for(auto &instruction : top_level.instructions.instructions) @@ -914,15 +1123,15 @@ struct Spirv_header_generator final : public Generator "{\n"; { auto push_indent = state.pushed_indent(); - state << indent << "static constexpr " << op_enum_name << " get_opcode() noexcept\n" - << indent << "{\n"; + 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 + state << indent("return ") << op_enum_name << "::" << get_enumerant_name(op_enum_name, instruction.opname, true) << ";\n"; } - state << indent << "}\n"; + state << indent("}\n"); std::vector member_names; std::vector member_types; member_names.reserve(instruction.operands.operands.size()); @@ -966,15 +1175,289 @@ struct Spirv_header_generator final : public Generator } }; +struct Spirv_source_generator final : public Generator +{ + Spirv_source_generator() : Generator("spirv.cpp") + { + } + virtual void run(Generator_args &generator_args, const ast::Top_level &top_level) const override + { + Generator_state state(this, generator_args); + state.open_output_file(); + write_file_comments(state, top_level.copyright); + state << "#include \"spirv.h\"\n"; + } +}; + +struct Parser_header_generator final : public Generator +{ + Parser_header_generator() : Generator("parser.h") + { + } + static std::string get_dump_function_name(std::string kind) + { + return "dump_operand_" + std::move(kind); + } + virtual void run(Generator_args &generator_args, const ast::Top_level &top_level) const override + { + Generator_state state(this, generator_args); + state.open_output_file(); + write_file_comments(state, top_level.copyright); + write_file_guard_start(state); + state << R"(#include "spirv.h" +#include +#include +#include "util/optional.h" +#include + +)"; + write_namespaces_start(state, spirv_namespace_names); + state << indent(R"(struct Parse_error +{ +`std::size_t word_index; +`std::string message; +`Parse_error(std::size_t word_index, std::string message) noexcept +``: word_index(word_index), +`` message(std::move(message)) +`{ +`} +`virtual ~Parse_error() = default; +}; + +)"); + state << "struct Parse_semantics_generic\n" + "{\n"; + { + 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; +)"); + for(auto &instruction : top_level.instructions.instructions) + { + auto struct_name = get_enumerant_name(op_enum_name, instruction.opname, true); + state << indent("virtual void handle_instruction(") << struct_name + << " instruction) = 0;\n"; + } +#warning finish + } + state << indent(R"(}; + +struct Parse_dump final : public Parse_semantics_generic +{ +`std::ostream &os; +`explicit constexpr Parse_dump(std::ostream &os) noexcept : os(os) +`{ +`} +)"); + { + auto push_indent = state.pushed_indent(); + state << indent( + R"(virtual std::unique_ptr handle_error(std::size_t word_index, std::string message) override; +)"); + for(auto &instruction : top_level.instructions.instructions) + { + auto struct_name = get_enumerant_name(op_enum_name, instruction.opname, true); + state << indent("virtual void handle_instruction(") << struct_name + << " instruction) override;\n"; + } + for(auto &operand_kind : top_level.operand_kinds.operand_kinds) + { + auto dump_function_name = get_dump_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<" + << operand_kind.kind << "> &v);\n"; + state << indent("void ") << dump_function_name << "(const std::vector<" + << operand_kind.kind << "> &v);\n"; + } +#warning finish + } + state << "};\n" + "\n" + "template \n" + "struct Parser\n" + "{\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) +{ +)"); + { + 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("}\n"); +#warning finish + } + state << "};\n"; +#warning finish + write_namespaces_end(state, spirv_namespace_names); + write_file_guard_end(state); + } +}; + +struct Parser_source_generator final : public Generator +{ + Parser_source_generator() : Generator("parser.cpp") + { + } + virtual void run(Generator_args &generator_args, const ast::Top_level &top_level) const override + { + Generator_state state(this, generator_args); + state.open_output_file(); + write_file_comments(state, top_level.copyright); + state << "#include \"parser.h\"\n" + "\n"; + write_namespaces_start(state, spirv_namespace_names); + state << indent(R"(namespace +{ +/** instantiate Parser with Parse_semantics_generic to help catch bugs */ +[[gnu::unused]] auto parser_test(const Word *words, std::size_t word_count, Parse_semantics_generic &semantics) +{ +`return Parser<>::parse(words, word_count, semantics); +} +} + +std::unique_ptr Parse_dump::handle_error(std::size_t word_index, std::string message) +{ +`return std::unique_ptr(new Parse_error(word_index, std::move(message))); +} +)"); + for(auto &operand_kind : top_level.operand_kinds.operand_kinds) + { + auto dump_function_name = + Parser_header_generator::get_dump_function_name(operand_kind.kind); + { + state << indent(R"( +void Parse_dump::)") << dump_function_name + << "(const " << operand_kind.kind << R"( &v) +{ +)"; + auto push_indent = state.pushed_indent(); + switch(operand_kind.category) + { + case ast::Operand_kinds::Operand_kind::Category::bit_enum: + { + auto &enumerants = + util::get(operand_kind.value); +#warning finish + break; + } + case ast::Operand_kinds::Operand_kind::Category::value_enum: + { +#warning finish + break; + } + case ast::Operand_kinds::Operand_kind::Category::composite: + { +#warning finish + break; + } + case ast::Operand_kinds::Operand_kind::Category::id: + { +#warning finish + break; + } + case ast::Operand_kinds::Operand_kind::Category::literal: + { +#warning finish + break; + } + } + push_indent.finish(); + state << indent("}\n"); + } + state << indent(R"( +void Parse_dump::)") + << dump_function_name << "(const util::optional<" << operand_kind.kind + << indent(true, R"(> &v) +{ +`if(v) +)") << indent(2) << dump_function_name + << indent(true, R"((*v); +`else +``os << "nullopt"; +} + +void Parse_dump::)") + << dump_function_name << "(const std::vector<" << operand_kind.kind + << indent(true, R"(> &v) +{ +`auto separator = ""; +`os << "{"; +`for(auto &value : v) +`{ +``os << separator; +``separator = ", "; +)") << indent(2) << dump_function_name + << indent(true, R"((value); +`} +`os << "}"; +} +)"); +#warning finish + } + for(auto &instruction : top_level.instructions.instructions) + { + auto struct_name = get_enumerant_name(op_enum_name, instruction.opname, true); + state << indent( + "\n" + "void Parse_dump::handle_instruction(") + << struct_name << indent(true, R"( instruction) +{ +`os << ")") << instruction.opname + << indent(true, R"(\n"; +)"); + for(auto &operand : instruction.operands.operands) + { + 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(true, R"((instruction.)") << member_name << indent(true, R"(); +os << "\n"; +)"); + } + state << indent("}\n"); + } + write_namespaces_end(state, spirv_namespace_names); + } +}; + std::unique_ptr Generators::make_spirv_header_generator() { return std::unique_ptr(new Spirv_header_generator); } +std::unique_ptr Generators::make_spirv_source_generator() +{ + return std::unique_ptr(new Spirv_source_generator); +} + +std::unique_ptr Generators::make_parser_header_generator() +{ + return std::unique_ptr(new Parser_header_generator); +} + +std::unique_ptr Generators::make_parser_source_generator() +{ + return std::unique_ptr(new Parser_source_generator); +} + std::vector> Generators::make_all_generators() { std::unique_ptr generators_array[] = { make_spirv_header_generator(), + make_spirv_source_generator(), + make_parser_header_generator(), + make_parser_source_generator(), }; // use array then move because you can't move out of an std::initializer_list std::vector> retval; diff --git a/src/generate_spirv_parser/generate.h b/src/generate_spirv_parser/generate.h index 84d8fbf..04aadfc 100644 --- a/src/generate_spirv_parser/generate.h +++ b/src/generate_spirv_parser/generate.h @@ -86,7 +86,7 @@ protected: write_extensions_set(*this, v); return *this; } - Push_indent pushed_indent() noexcept; + Push_indent pushed_indent(std::ptrdiff_t amount = 1) noexcept; }; class Push_indent final { @@ -95,38 +95,75 @@ protected: private: Generator_state *state; + std::ptrdiff_t amount; public: - explicit Push_indent(Generator_state &state) noexcept : state(&state) + explicit Push_indent(Generator_state &state, std::ptrdiff_t amount = 1) noexcept + : state(&state), + amount(amount) { - state.indent_level++; + state.indent_level += amount; } - Push_indent(Push_indent &&rt) noexcept : state(rt.state) + Push_indent(Push_indent &&rt) noexcept : state(rt.state), amount(rt.amount) { rt.state = nullptr; } void finish() noexcept { assert(state); - state->indent_level--; + state->indent_level -= amount; state = nullptr; } ~Push_indent() { if(state) - state->indent_level--; + state->indent_level -= amount; + } + }; + // translates initial '`' (backtick) characters to indentations + struct Indent_interpreted_text + { + const char *text; + std::ptrdiff_t indent_offset; + bool start_indented; + constexpr explicit Indent_interpreted_text(const char *text, + std::ptrdiff_t indent_offset, + bool start_indented) noexcept + : text(text), + indent_offset(indent_offset), + start_indented(start_indented) + { + } + friend Generator_state &operator<<(Generator_state &state, Indent_interpreted_text v) + { + write_indent_interpreted_text(state, v.text, v.indent_offset, v.start_indented); + return state; } }; struct Indent_t { + std::ptrdiff_t offset; explicit Indent_t() = default; - friend Generator_state &operator<<(Generator_state &state, Indent_t) + constexpr Indent_t operator()(std::ptrdiff_t additional_offset) const noexcept { - write_indent(state); + return Indent_t{offset + additional_offset}; + } + constexpr Indent_interpreted_text operator()(const char *text) const noexcept + { + return Indent_interpreted_text(text, offset, false); + } + constexpr Indent_interpreted_text operator()(bool start_indented, const char *text) const + noexcept + { + return Indent_interpreted_text(text, offset, start_indented); + } + friend Generator_state &operator<<(Generator_state &state, Indent_t indent) + { + write_indent(state, indent.offset); return state; } }; - static constexpr Indent_t indent{}; + static constexpr auto indent = Indent_t{0}; enum class Integer_literal_base { dec = 0, @@ -211,7 +248,15 @@ protected: std::size_t enumeration_name_size, std::string enumerant_name, bool input_name_should_have_prefix); - static void write_indent(Generator_state &state); + static void write_indent_absolute(Generator_state &state, std::size_t amount); + static void write_indent(Generator_state &state, std::ptrdiff_t offset) + { + write_indent_absolute(state, state.indent_level + offset); + } + static void write_indent_interpreted_text(Generator_state &state, + const char *text, + std::ptrdiff_t offset, + bool start_indented); static void write_automatically_generated_file_warning(Generator_state &state); static void write_copyright_comment(Generator_state &state, const ast::Copyright ©right); static void write_file_comments(Generator_state &state, const ast::Copyright ©right) @@ -318,6 +363,9 @@ protected: const std::string *member_types, const std::string *member_names, std::size_t member_count); + static std::vector + get_unique_enumerants( + std::vector enumerants); protected: static constexpr const char *vulkan_cpu_namespace_name = "vulkan_cpu"; @@ -344,16 +392,23 @@ public: virtual ~Generator() = default; }; -inline Generator::Push_indent Generator::Generator_state::pushed_indent() noexcept +inline Generator::Push_indent Generator::Generator_state::pushed_indent( + std::ptrdiff_t amount) noexcept { - return Push_indent(*this); + return Push_indent(*this, amount); } struct Spirv_header_generator; +struct Spirv_source_generator; +struct Parser_header_generator; +struct Parser_source_generator; struct Generators { static std::unique_ptr make_spirv_header_generator(); + static std::unique_ptr make_spirv_source_generator(); + static std::unique_ptr make_parser_header_generator(); + static std::unique_ptr make_parser_source_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 ca8141f..05e1579 100644 --- a/src/generate_spirv_parser/generate_spirv_parser.cpp +++ b/src/generate_spirv_parser/generate_spirv_parser.cpp @@ -59,7 +59,7 @@ int generate_spirv_parser_main(int argc, char **argv) } #warning finish std::cerr << "generate_spirv_parser is not finished being implemented" << std::endl; - return 1; + return 0; } catch(parser::Parse_error &e) { diff --git a/src/spirv/CMakeLists.txt b/src/spirv/CMakeLists.txt index 5e0542f..31995bc 100644 --- a/src/spirv/CMakeLists.txt +++ b/src/spirv/CMakeLists.txt @@ -20,11 +20,11 @@ # cmake_minimum_required(VERSION 3.1 FATAL_ERROR) -set(sources spirv.cpp) +set(sources) set(spirv_parser_generated_include_dir ${CMAKE_CURRENT_BINARY_DIR}/generated) set(spirv_parser_generated_dir ${spirv_parser_generated_include_dir}/spirv) -set(spirv_parser_sources ${spirv_parser_generated_dir}/parser.cpp) +set(spirv_parser_sources ${spirv_parser_generated_dir}/parser.cpp ${spirv_parser_generated_dir}/spirv.cpp) set(spirv_parser_headers ${spirv_parser_generated_dir}/parser.h ${spirv_parser_generated_dir}/spirv.h) set(spirv_core_grammar_json ${CMAKE_CURRENT_SOURCE_DIR}/../khronos-spirv/spirv.core.grammar.json) message(STATUS "spirv_parser_generated_dir: " ${spirv_parser_generated_dir}) diff --git a/src/spirv/spirv.cpp b/src/spirv/spirv.cpp deleted file mode 100644 index 1abdc51..0000000 --- a/src/spirv/spirv.cpp +++ /dev/null @@ -1,23 +0,0 @@ -/* - * 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 "spirv.h" diff --git a/src/util/constexpr_array.h b/src/util/constexpr_array.h index 14e62f7..5182c1e 100644 --- a/src/util/constexpr_array.h +++ b/src/util/constexpr_array.h @@ -34,10 +34,56 @@ namespace vulkan_cpu { namespace util { +namespace detail +{ +template +struct Constexpr_array_helper +{ + typedef T values_type[N]; + static constexpr T *get_values_pointer(values_type &values) noexcept + { + return values; + } + static constexpr const T *get_values_pointer(const values_type &values) noexcept + { + return values; + } +}; + +template +struct Constexpr_array_helper +{ + struct values_type + { + }; + static constexpr T *get_values_pointer(values_type &values) noexcept + { + return nullptr; + } + static constexpr const T *get_values_pointer(const values_type &values) noexcept + { + return nullptr; + } +}; +} + template struct Constexpr_array { - T values[N]; +private: + typedef detail::Constexpr_array_helper Helper; + typedef typename Helper::values_type values_type; + constexpr T *get_values_pointer() noexcept + { + return Helper::get_values_pointer(values); + } + constexpr const T *get_values_pointer() const noexcept + { + return Helper::get_values_pointer(values); + } + +public: + values_type values; typedef T value_type; typedef std::size_t size_type; typedef std::ptrdiff_t difference_type; @@ -53,69 +99,69 @@ struct Constexpr_array { if(index >= N) throw std::out_of_range("Constexpr_array::at"); - return values[index]; + return get_values_pointer()[index]; } constexpr const T &at(std::size_t index) const { if(index >= N) throw std::out_of_range("Constexpr_array::at"); - return values[index]; + return get_values_pointer()[index]; } constexpr T &operator[](std::size_t index) noexcept { - return values[index]; + return get_values_pointer()[index]; } constexpr const T &operator[](std::size_t index) const noexcept { - return values[index]; + return get_values_pointer()[index]; } constexpr T &front() noexcept { - return values[0]; + return get_values_pointer()[0]; } constexpr const T &front() const noexcept { - return values[0]; + return get_values_pointer()[0]; } constexpr T &back() noexcept { - return values[N - 1]; + return get_values_pointer()[N - 1]; } constexpr const T &back() const noexcept { - return values[N - 1]; + return get_values_pointer()[N - 1]; } constexpr T *data() noexcept { - return values; + return get_values_pointer(); } constexpr const T *data() const noexcept { - return values; + return get_values_pointer(); } constexpr iterator begin() noexcept { - return values; + return get_values_pointer(); } constexpr const_iterator begin() const noexcept { - return values; + return get_values_pointer(); } constexpr const_iterator cbegin() const noexcept { - return values; + return get_values_pointer(); } constexpr iterator end() noexcept { - return values + N; + return get_values_pointer() + N; } constexpr const_iterator end() const noexcept { - return values + N; + return get_values_pointer() + N; } constexpr const_iterator cend() const noexcept { - return values + N; + return get_values_pointer() + N; } constexpr reverse_iterator rbegin() noexcept { @@ -155,14 +201,14 @@ struct Constexpr_array } constexpr void fill(const T &value) noexcept(std::is_nothrow_copy_assignable::value) { - for(auto &i : values) + for(auto &i : *this) i = value; } constexpr void swap(Constexpr_array &other) noexcept(is_nothrow_swappable_v) { using std::swap; for(std::size_t index = 0; index < size(); index++) - swap(values[index], other.values[index]); + swap(get_values_pointer()[index], other.get_values_pointer()[index]); } }; diff --git a/src/util/enum.h b/src/util/enum.h index e063a9e..51e0826 100644 --- a/src/util/enum.h +++ b/src/util/enum.h @@ -61,26 +61,37 @@ private: public: static constexpr bool is_compact = is_compact_helper(); + struct Value_and_index + { + T value; + std::size_t index; + constexpr Value_and_index() noexcept : value(), index() + { + } + constexpr Value_and_index(T value, std::size_t index) noexcept : value(value), index(index) + { + } + }; private: template - static constexpr Constexpr_array, N> sort_value_index_map( - const std::pair *value_index_map) noexcept + static constexpr Constexpr_array sort_value_index_map( + const Value_and_index *value_index_map) noexcept { // uses merge sort algorithm if(N == 0) return {}; - Constexpr_array, N> retval{}; + Constexpr_array retval{}; if(N == 1) { retval[0] = value_index_map[0]; - return; + return retval; } // split - constexpr std::size_t split_index = N2 / 2; + constexpr std::size_t split_index = N / 2; constexpr std::size_t part1_size = split_index; - constexpr std::size_t part2_size = N2 - part1_size; + constexpr std::size_t part2_size = N - part1_size; auto part1 = sort_value_index_map(value_index_map); auto part2 = sort_value_index_map(value_index_map + split_index); @@ -91,8 +102,8 @@ private: while(part1_index < part1_size && part2_index < part2_size) { // we want to copy from part1 if values are equal - if(static_cast(std::get<0>(part2[part2_index])) - < static_cast(std::get<0>(part1[part1_index]))) + if(static_cast(part2[part2_index].value) + < static_cast(part1[part1_index].value)) retval[retval_index++] = part2[part2_index++]; else retval[retval_index++] = part1[part1_index++]; @@ -103,19 +114,19 @@ private: retval[retval_index++] = part2[part2_index++]; return retval; } - static constexpr Constexpr_array, value_count> + static constexpr Constexpr_array make_sorted_value_index_map() noexcept { - Constexpr_array, N> retval{}; + Constexpr_array retval{}; for(std::size_t i = 0; i < value_count; i++) retval[i] = {values[i], i}; - retval = sort_value_index_map(retval.data()); + retval = sort_value_index_map(retval.data()); return retval; } public: - static constexpr Constexpr_array, value_count> - sorted_value_index_map = make_sorted_value_index_map(); + static constexpr Constexpr_array sorted_value_index_map = + make_sorted_value_index_map(); static constexpr std::size_t npos = -1; /** find first occurrence of value in values and return index if found, otherwise return npos */ static constexpr std::size_t find_value(T value) noexcept @@ -127,7 +138,7 @@ public: retval = static_cast(static_cast(value)) - static_cast(static_cast(values.front())); } - else if(value_count < 8) + else if(value_count < binary_search_transition) { retval = -1; for(std::size_t i = 0; i < value_count; i++) @@ -174,7 +185,7 @@ template constexpr bool Enum_traits::is_compact; template -constexpr Constexpr_array, Enum_traits::value_count> +constexpr Constexpr_array::Value_and_index, Enum_traits::value_count> Enum_traits::sorted_value_index_map; template @@ -189,12 +200,13 @@ struct Default_enum_traits }; template -static constexpr Enum_values Default_enum_traits::values; +constexpr Constexpr_array Default_enum_traits::values; /** generate code for Enum_traits instantiation; use like * vulkan_cpu_util_generate_enum_traits(Enum, Enum::Value1, Enum::Value2, Enum::Value3, * <...>); */ -#define vulkan_cpu_util_generate_enum_traits(...) \ - ::vulkan_cpu::util::detail::Default_enum_traits<__VA_ARGS__> enum_traits_resolve_function(Enum) +#define vulkan_cpu_util_generate_enum_traits(Enum, ...) \ + ::vulkan_cpu::util::detail::Default_enum_traits \ + enum_traits_resolve_function(Enum) } /** behaves like a std::set */ -- 2.30.2