{
}
json::ast::Value to_json() const;
+ template <typename Fn>
+ void visit(Fn fn) const
+ {
+ fn(*this);
+ }
};
struct Capabilities
return capabilities.empty();
}
json::ast::Value to_json() const;
+ template <typename Fn>
+ void visit(Fn fn) const
+ {
+ fn(*this);
+ }
};
struct Extensions
return extensions.empty();
}
json::ast::Value to_json() const;
+ template <typename Fn>
+ void visit(Fn fn) const
+ {
+ fn(*this);
+ }
};
struct Instructions
{
}
json::ast::Value to_json() const;
+ template <typename Fn>
+ void visit(Fn fn) const
+ {
+ fn(*this);
+ }
};
std::vector<Operand> operands;
Operands() : operands()
return operands.empty();
}
json::ast::Value to_json() const;
+ template <typename Fn>
+ void visit(Fn fn) const
+ {
+ fn(*this);
+ for(auto &operand : operands)
+ operand.visit(fn);
+ }
};
std::string opname;
std::uint32_t opcode;
{
}
json::ast::Value to_json() const;
+ template <typename Fn>
+ void visit(Fn fn) const
+ {
+ fn(*this);
+ operands.visit(fn);
+ capabilities.visit(fn);
+ }
};
std::vector<Instruction> instructions;
explicit Instructions(std::vector<Instruction> instructions) noexcept
{
}
json::ast::Value to_json() const;
+ template <typename Fn>
+ void visit(Fn fn) const
+ {
+ fn(*this);
+ for(auto &instruction : instructions)
+ instruction.visit(fn);
+ }
};
struct Operand_kinds
{
}
json::ast::Value to_json() const;
+ template <typename Fn>
+ void visit(Fn fn) const
+ {
+ fn(*this);
+ }
};
std::vector<Parameter> parameters;
Parameters() : parameters()
{
return parameters.empty();
}
+ template <typename Fn>
+ void visit(Fn fn) const
+ {
+ fn(*this);
+ for(auto ¶meter : parameters)
+ parameter.visit(fn);
+ }
};
Parameters parameters;
Extensions extensions;
{
}
json::ast::Value to_json(bool is_bit_enumerant) const;
+ template <typename Fn>
+ void visit(Fn fn) const
+ {
+ fn(*this);
+ capabilities.visit(fn);
+ parameters.visit(fn);
+ extensions.visit(fn);
+ }
};
std::vector<Enumerant> enumerants;
explicit Enumerants(std::vector<Enumerant> enumerants) noexcept : enumerants(enumerants)
{
return to_json(category == Category::bit_enum);
}
+ template <typename Fn>
+ void visit(Fn fn) const
+ {
+ fn(*this);
+ for(auto &enumerant : enumerants)
+ enumerant.visit(fn);
+ }
};
struct Doc
{
{
return to_json();
}
+ template <typename Fn>
+ void visit(Fn fn) const
+ {
+ fn(*this);
+ }
};
struct Bases
{
{
return to_json();
}
+ template <typename Fn>
+ void visit(Fn fn) const
+ {
+ fn(*this);
+ }
};
typedef util::variant<Enumerants, Doc, Bases> Value;
Value value;
{
}
json::ast::Value to_json() const;
+ template <typename Fn>
+ void visit(Fn fn) const
+ {
+ fn(*this);
+ util::visit(
+ [&](auto &&value)
+ {
+ value.visit(fn);
+ },
+ value);
+ }
};
std::vector<Operand_kind> operand_kinds;
explicit Operand_kinds(std::vector<Operand_kind> operand_kinds) noexcept
{
}
json::ast::Value to_json() const;
+ template <typename Fn>
+ void visit(Fn fn) const
+ {
+ fn(*this);
+ for(auto &operand_kind : operand_kinds)
+ operand_kind.visit(fn);
+ }
};
struct Top_level
{
}
json::ast::Value to_json() const;
+ template <typename Fn>
+ void visit(Fn fn) const
+ {
+ fn(*this);
+ copyright.visit(fn);
+ instructions.visit(fn);
+ operand_kinds.visit(fn);
+ }
};
}
}
*
*/
#include "generate.h"
+#include "../json/json.h"
+#include <limits>
+#include <algorithm>
namespace vulkan_cpu
{
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.exceptions(std::ios::badbit | std::ios::failbit);
}
constexpr Generator::Indent_t Generator::indent;
+constexpr const char *Generator::vulkan_cpu_namespace_name;
+constexpr const char *Generator::spirv_namespace_name;
+constexpr const char *Generator::spirv_namespace_names[];
+
+std::string Generator::get_guard_macro_name_from_file_name(std::string file_name)
+{
+ auto retval = std::move(file_name);
+ for(char &ch : retval)
+ {
+ if(ch >= 'a' && ch <= 'z')
+ {
+ ch = ch - 'a' + 'A'; // convert to uppercase
+ continue;
+ }
+ if(ch >= 'A' && ch <= 'Z')
+ continue;
+ if(ch >= '0' && ch <= '9')
+ continue;
+ ch = '_';
+ }
+ retval += '_';
+ if(retval[0] >= '0' && retval[0] <= '9')
+ retval.insert(0, 1, '_');
+ for(std::size_t double_underline_index = retval.find("__");
+ double_underline_index != std::string::npos;
+ double_underline_index = retval.find("__", double_underline_index + 1))
+ {
+ // insert a u in all pairs of underlines to prevent generating a reserved identifier
+ retval.insert(++double_underline_index, "u");
+ }
+ if(retval.size() >= 2 && retval[0] == '_' && retval[1] >= 'A' && retval[1] <= 'Z')
+ {
+ // insert a u to prevent generating a reserved identifier: starting with an underline and a
+ // capital letter
+ retval.insert(1, "u");
+ }
+ return retval;
+}
void Generator::write_indent(Generator_state &state)
{
state << " */\n";
}
+void Generator::write_file_guard_start(Generator_state &state)
+{
+ state << "#ifdef " << state.guard_macro_name << "\n#define " << state.guard_macro_name
+ << "\n\n";
+}
+
+void Generator::write_file_guard_end(Generator_state &state)
+{
+ state << "#endif /* " << state.guard_macro_name << " */\n";
+}
+
+void Generator::write_namespace_start(Generator_state &state, const char *namespace_name)
+{
+ 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";
+}
+
+void Generator::write_namespace_end(Generator_state &state)
+{
+ state << "}\n";
+}
+
+void Generator::write_unsigned_integer_literal(Generator_state &state,
+ std::uint64_t value,
+ Integer_literal_base base,
+ std::size_t minimum_digit_count)
+{
+ constexpr std::uint64_t max_unsigned_value = std::numeric_limits<std::uint16_t>::max();
+ constexpr std::uint64_t max_unsigned_long_value = std::numeric_limits<std::uint32_t>::max();
+ auto literal_type =
+ value <= max_unsigned_value ? "U" : value <= max_unsigned_long_value ? "UL" : "ULL";
+ auto number_prefix = "";
+ unsigned base_as_number = 10;
+ switch(base)
+ {
+ case Integer_literal_base::dec:
+ minimum_digit_count = 1;
+ break;
+ case Integer_literal_base::hex:
+ base_as_number = 0x10;
+ number_prefix = "0x";
+ break;
+ case Integer_literal_base::oct:
+ base_as_number = 010;
+ number_prefix = "0";
+ break;
+ }
+ auto number_string = json::ast::Number_value::append_unsigned_integer_to_string(
+ value, number_prefix, base_as_number, minimum_digit_count)
+ + literal_type;
+ state << number_string;
+}
+
+void Generator::write_signed_integer_literal(Generator_state &state, std::int64_t value)
+{
+ constexpr std::int64_t max_int_value = std::numeric_limits<std::int16_t>::max();
+ constexpr std::int64_t min_int_value = std::numeric_limits<std::int16_t>::min();
+ constexpr std::int64_t max_long_value = std::numeric_limits<std::int32_t>::max();
+ constexpr std::int64_t min_long_value = std::numeric_limits<std::int32_t>::min();
+ auto literal_type = "";
+ if(value < min_int_value || value > max_int_value)
+ literal_type = "L";
+ if(value < min_long_value || value > max_long_value)
+ literal_type = "LL";
+ state << value << literal_type;
+}
+
+struct Generator::Get_extensions_visitor
+{
+ std::unordered_set<std::string> &retval;
+ constexpr Get_extensions_visitor(std::unordered_set<std::string> &retval) noexcept
+ : retval(retval)
+ {
+ }
+ template <typename T>
+ void operator()(const T &)
+ {
+ }
+ void operator()(const ast::Extensions &extensions)
+ {
+ for(auto &extension : extensions.extensions)
+ retval.insert(extension);
+ }
+};
+
+std::unordered_set<std::string> Generator::get_extensions(const ast::Top_level &top_level)
+{
+ std::unordered_set<std::string> retval;
+ top_level.visit(Get_extensions_visitor(retval));
+ return retval;
+}
+
struct Spirv_header_generator final : public Generator
{
Spirv_header_generator() : Generator("spirv.h")
{
}
+ enum class Enum_priority
+ {
+ default_priority = 0,
+ capability = 1,
+ };
+ static Enum_priority get_enum_priority(const std::string &enum_name) noexcept
+ {
+ if(enum_name == "Capability")
+ return Enum_priority::capability;
+ return Enum_priority::default_priority;
+ }
+ static bool compare_enum_names(const std::string &l, const std::string &r) noexcept
+ {
+ auto l_priority = get_enum_priority(l);
+ auto r_priority = get_enum_priority(r);
+ if(l_priority > r_priority)
+ return true; // higher priority sorts first
+ if(l_priority < r_priority)
+ return false;
+ return l < r;
+ }
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 << "#include <cstdint>\n";
+ state << "\n";
+ write_namespaces_start(state, spirv_namespace_names);
+ state << "typedef std::uint32_t Word;\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 = "
+ << unsigned_dec_integer_literal(top_level.revision) << ";\n";
+ auto extensions_set = get_extensions(top_level);
+ std::vector<std::string> extensions_list;
+ extensions_list.reserve(extensions_set.size());
+ for(auto &extension : extensions_set)
+ extensions_list.push_back(extension);
+ std::sort(extensions_list.begin(), extensions_list.end());
+ state << "\n"
+ "enum class Extension\n"
+ "{\n";
+ {
+ auto push_indent = state.pushed_indent();
+ for(auto &extension : extensions_list)
+ state << indent << extension << ",\n";
+ }
+ state << "};\n"
+ "\n"
+ "constexpr const char *get_extension_name(Extension extension) noexcept\n"
+ "{\n";
+ {
+ auto push_indent = state.pushed_indent();
+ state << indent << "switch(extension)\n" << indent << "{\n";
+ for(auto &extension : extensions_list)
+ {
+ state << indent << "case Extension::" << extension << ":\n";
+ auto push_indent2 = state.pushed_indent();
+ state << indent << "return \"" << extension << "\";\n";
+ }
+ state << indent << "}\n" << indent << "return \"\";\n";
+ }
+ state << "}\n";
+ std::vector<const ast::Operand_kinds::Operand_kind *> operand_kinds;
+ operand_kinds.reserve(top_level.operand_kinds.operand_kinds.size());
+ for(auto &operand_kind : top_level.operand_kinds.operand_kinds)
+ operand_kinds.push_back(&operand_kind);
+ std::sort(
+ operand_kinds.begin(),
+ 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);
+ });
+ for(auto *operand_kind : operand_kinds)
+ {
+ switch(operand_kind->category)
+ {
+ case ast::Operand_kinds::Operand_kind::Category::value_enum:
+ case ast::Operand_kinds::Operand_kind::Category::bit_enum:
+ {
+ auto &enumerants =
+ util::get<ast::Operand_kinds::Operand_kind::Enumerants>(operand_kind->value);
+ state << "\n"
+ "enum class "
+ << operand_kind->kind << " : Word\n"
+ "{\n";
+ auto push_indent = state.pushed_indent();
+ for(auto &enumerant : enumerants.enumerants)
+ {
+ state << indent << enumerant.enumerant << " = ";
+ if(operand_kind->category
+ == ast::Operand_kinds::Operand_kind::Category::bit_enum)
+ state << unsigned_hex_integer_literal(enumerant.value);
+ else
+ state << unsigned_dec_integer_literal(enumerant.value);
+ state << ",\n";
+ }
+ push_indent.finish();
+ state << "};\n";
+ break;
+ }
+#warning finish
+ }
+ }
+
+
#warning finish
+ write_namespaces_end(state, spirv_namespace_names);
+ write_file_guard_end(state);
}
};
#include <string>
#include <cassert>
#include <type_traits>
+#include <cstdint>
+#include <unordered_set>
namespace vulkan_cpu
{
};
protected:
+ class Push_indent;
struct Generator_state
{
Generator_args &generator_args;
std::size_t indent_level;
std::string full_output_file_name;
+ std::string guard_macro_name;
std::ofstream os;
explicit Generator_state(const Generator *generator, Generator_args &generator_args);
void open_output_file();
os << std::forward<T>(v);
return *this;
}
+ Push_indent pushed_indent() noexcept;
};
class Push_indent final
{
}
};
static constexpr Indent_t indent{};
+ enum class Integer_literal_base
+ {
+ dec = 0,
+ hex,
+ oct
+ };
+ struct Unsigned_integer_literal
+ {
+ std::uint64_t value;
+ Integer_literal_base base;
+ std::size_t minimum_digit_count;
+ constexpr Unsigned_integer_literal(std::uint64_t value,
+ Integer_literal_base base,
+ std::size_t minimum_digit_count = 1) noexcept
+ : value(value),
+ base(base),
+ minimum_digit_count(minimum_digit_count)
+ {
+ }
+ friend Generator_state &operator<<(Generator_state &state, Unsigned_integer_literal v)
+ {
+ write_unsigned_integer_literal(state, v.value, v.base, v.minimum_digit_count);
+ return state;
+ }
+ };
+ static constexpr Unsigned_integer_literal unsigned_dec_integer_literal(
+ std::uint64_t value) noexcept
+ {
+ return Unsigned_integer_literal(value, Integer_literal_base::dec);
+ }
+ static constexpr Unsigned_integer_literal unsigned_hex_integer_literal(
+ std::uint64_t value, std::size_t minimum_digit_count = 1) noexcept
+ {
+ return Unsigned_integer_literal(value, Integer_literal_base::hex, minimum_digit_count);
+ }
+ static constexpr Unsigned_integer_literal unsigned_oct_integer_literal(
+ std::uint64_t value, std::size_t minimum_digit_count = 1) noexcept
+ {
+ return Unsigned_integer_literal(value, Integer_literal_base::oct, minimum_digit_count);
+ }
+ struct Signed_integer_literal
+ {
+ std::int64_t value;
+ constexpr explicit Signed_integer_literal(std::int64_t value) noexcept : value(value)
+ {
+ }
+ friend Generator_state &operator<<(Generator_state &state, Signed_integer_literal v)
+ {
+ write_signed_integer_literal(state, v.value);
+ return state;
+ }
+ };
+ static constexpr Signed_integer_literal signed_integer_literal(std::int64_t value) noexcept
+ {
+ return Signed_integer_literal(value);
+ }
protected:
const char *const output_base_file_name;
protected:
+ static std::string get_guard_macro_name_from_file_name(std::string file_name);
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);
write_automatically_generated_file_warning(state);
write_copyright_comment(state, copyright);
}
+ static void write_file_guard_start(Generator_state &state);
+ static void write_file_guard_end(Generator_state &state);
+ static void write_namespace_start(Generator_state &state, const char *namespace_name);
+ static void write_namespace_start(Generator_state &state, const std::string &namespace_name);
+
+private:
+ static void write_namespace_end(Generator_state &state);
+
+protected:
+ static void write_namespace_end(Generator_state &state, const char *namespace_name)
+ {
+ write_namespace_end(state);
+ }
+ static void write_namespace_end(Generator_state &state, const std::string &namespace_name)
+ {
+ write_namespace_end(state);
+ }
+ static void write_namespaces_start(Generator_state &state,
+ const char *const *namespace_names,
+ std::size_t namespace_name_count)
+ {
+ for(std::size_t i = 0; i < namespace_name_count; i++)
+ write_namespace_start(state, namespace_names[i]);
+ }
+ static void write_namespaces_start(Generator_state &state,
+ const std::string *namespace_names,
+ std::size_t namespace_name_count)
+ {
+ for(std::size_t i = 0; i < namespace_name_count; i++)
+ write_namespace_start(state, namespace_names[i]);
+ }
+ static void write_namespaces_end(Generator_state &state,
+ const char *const *namespace_names,
+ std::size_t namespace_name_count)
+ {
+ for(std::size_t i = 0; i < namespace_name_count; i++)
+ write_namespace_end(state, namespace_names[namespace_name_count - i - 1]);
+ state << '\n';
+ }
+ static void write_namespaces_end(Generator_state &state,
+ const std::string *namespace_names,
+ std::size_t namespace_name_count)
+ {
+ for(std::size_t i = 0; i < namespace_name_count; i++)
+ write_namespace_end(state, namespace_names[namespace_name_count - i - 1]);
+ state << '\n';
+ }
+ template <typename T, std::size_t N>
+ static void write_namespaces_start(Generator_state &state, const T(&namespace_names)[N])
+ {
+ write_namespaces_start(state, namespace_names, N);
+ }
+ template <typename T, std::size_t N>
+ static void write_namespaces_end(Generator_state &state, const T(&namespace_names)[N])
+ {
+ write_namespaces_end(state, namespace_names, N);
+ }
+ static void write_namespaces_start(Generator_state &state,
+ std::initializer_list<std::string> namespace_names)
+ {
+ write_namespaces_start(state, namespace_names.begin(), namespace_names.size());
+ }
+ static void write_namespaces_start(Generator_state &state,
+ std::initializer_list<const char *> namespace_names)
+ {
+ write_namespaces_start(state, namespace_names.begin(), namespace_names.size());
+ }
+ static void write_namespaces_end(Generator_state &state,
+ std::initializer_list<std::string> namespace_names)
+ {
+ write_namespaces_end(state, namespace_names.begin(), namespace_names.size());
+ }
+ static void write_namespaces_end(Generator_state &state,
+ std::initializer_list<const char *> namespace_names)
+ {
+ write_namespaces_end(state, namespace_names.begin(), namespace_names.size());
+ }
+ static void write_unsigned_integer_literal(Generator_state &state,
+ std::uint64_t value,
+ Integer_literal_base base,
+ std::size_t minimum_digit_count);
+ static void write_signed_integer_literal(Generator_state &state, std::int64_t value);
+
+private:
+ struct Get_extensions_visitor;
+
+protected:
+ static std::unordered_set<std::string> get_extensions(const ast::Top_level &top_level);
+
+protected:
+ static constexpr const char *vulkan_cpu_namespace_name = "vulkan_cpu";
+ static constexpr const char *spirv_namespace_name = "spirv";
+ static constexpr const char *spirv_namespace_names[] = {
+ vulkan_cpu_namespace_name, spirv_namespace_name,
+ };
public:
explicit Generator(const char *output_base_file_name) noexcept
virtual ~Generator() = default;
};
+inline Generator::Push_indent Generator::Generator_state::pushed_indent() noexcept
+{
+ return Push_indent(*this);
+}
+
struct Spirv_header_generator;
struct Generators
add_custom_command(OUTPUT ${spirv_parser_sources} ${spirv_parser_headers}
COMMAND ${CMAKE_COMMAND} -E make_directory ${spirv_parser_generated_dir}
- COMMAND ${CMAKE_COMMAND} -E chdir ${spirv_parser_generated_dir} $<TARGET_FILE:generate_spirv_parser> ${spirv_core_grammar_json} ${spirv_parser_generated_dir}
+ COMMAND ${CMAKE_COMMAND} -E chdir ${spirv_parser_generated_include_dir} $<TARGET_FILE:generate_spirv_parser> ${spirv_core_grammar_json} spirv
MAIN_DEPENDENCY ${spirv_core_grammar_json}
DEPENDS $<TARGET_FILE:generate_spirv_parser>
VERBATIM