2 * Copyright 2017 Jacob Lifshay
4 * Permission is hereby granted, free of charge, to any person obtaining a copy
5 * of this software and associated documentation files (the "Software"), to deal
6 * in the Software without restriction, including without limitation the rights
7 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 * copies of the Software, and to permit persons to whom the Software is
9 * furnished to do so, subject to the following conditions:
11 * The above copyright notice and this permission notice shall be included in all
12 * copies or substantial portions of the Software.
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24 #include "json/json.h"
25 #include "util/optional.h"
30 #include <unordered_set>
32 #error finish converting to use get_enum_with_parameters_struct_name
36 namespace generate_spirv_parser
40 Generator::Generator_state::Generator_state(const Generator
*generator
,
41 Generator_args
&generator_args
,
42 const ast::Top_level
&top_level
)
43 : generator_args(generator_args
),
45 full_output_file_name(generator_args
.output_directory
+ "/"
46 + generator
->output_base_file_name
),
47 guard_macro_name(get_guard_macro_name_from_file_name(full_output_file_name
)),
51 operand_has_any_parameters_map()
53 os
.exceptions(std::ios::badbit
| std::ios::failbit
);
54 for(auto &operand_kind
: top_level
.operand_kinds
.operand_kinds
)
56 operand_kind_map
.emplace(operand_kind
.kind
, &operand_kind
);
57 bool &has_any_parameters
= operand_has_any_parameters_map
[&operand_kind
];
58 has_any_parameters
= false;
59 if(util::holds_alternative
<ast::Operand_kinds::Operand_kind::Enumerants
>(
63 util::get
<ast::Operand_kinds::Operand_kind::Enumerants
>(operand_kind
.value
);
64 for(auto &enumerant
: enumerants
.enumerants
)
66 if(!enumerant
.parameters
.empty())
68 has_any_parameters
= true;
76 void Generator::Generator_state::open_output_file()
78 os
.open(full_output_file_name
);
81 constexpr Generator::Indent_t
Generator::indent
;
82 constexpr const char *Generator::vulkan_cpu_namespace_name
;
83 constexpr const char *Generator::spirv_namespace_name
;
84 constexpr const char *Generator::spirv_namespace_names
[];
85 constexpr const char *Generator::extension_enum_name
;
86 constexpr const char *Generator::capability_enum_name
;
87 constexpr const char *Generator::op_enum_name
;
89 std::string
Generator::get_guard_macro_name_from_file_name(std::string file_name
)
91 auto retval
= std::move(file_name
);
92 for(char &ch
: retval
)
94 if(ch
>= 'a' && ch
<= 'z')
96 ch
= ch
- 'a' + 'A'; // convert to uppercase
99 if(ch
>= 'A' && ch
<= 'Z')
101 if(ch
>= '0' && ch
<= '9')
106 if(retval
[0] >= '0' && retval
[0] <= '9')
107 retval
.insert(0, 1, '_');
108 for(std::size_t double_underline_index
= retval
.find("__");
109 double_underline_index
!= std::string::npos
;
110 double_underline_index
= retval
.find("__", double_underline_index
+ 1))
112 // insert a u in all pairs of underlines to prevent generating a reserved identifier
113 retval
.insert(++double_underline_index
, "u");
115 if(retval
.size() >= 2 && retval
[0] == '_' && retval
[1] >= 'A' && retval
[1] <= 'Z')
117 // insert a u to prevent generating a reserved identifier: starting with an underline and a
119 retval
.insert(1, "u");
126 constexpr bool is_uppercase_letter(char ch
) noexcept
128 if(ch
>= 'A' && ch
<= 'Z')
133 constexpr bool is_lowercase_letter(char ch
) noexcept
135 if(ch
>= 'a' && ch
<= 'z')
140 constexpr bool is_letter(char ch
) noexcept
142 return is_uppercase_letter(ch
) || is_lowercase_letter(ch
);
145 constexpr bool is_identifier_start(char ch
) noexcept
147 return is_letter(ch
) || ch
== '_';
150 constexpr bool is_digit(char ch
) noexcept
152 if(ch
>= '0' && ch
<= '9')
157 constexpr bool is_identifier_continue(char ch
) noexcept
159 return is_identifier_start(ch
) || is_digit(ch
);
163 std::string
Generator::get_enumerant_name(const char *enumeration_name
,
164 std::size_t enumeration_name_size
,
165 std::string enumerant_name
,
166 bool input_name_should_have_prefix
)
168 bool starts_with_enumeration_name
=
169 enumerant_name
.compare(0, enumeration_name_size
, enumeration_name
, enumeration_name_size
)
171 bool starts_with_doubled_enumeration_name
= false;
172 if(starts_with_enumeration_name
)
173 starts_with_doubled_enumeration_name
= enumerant_name
.compare(enumeration_name_size
,
174 enumeration_name_size
,
176 enumeration_name_size
)
178 std::size_t needed_prefix_count
;
179 if(input_name_should_have_prefix
)
181 if(!starts_with_enumeration_name
)
182 needed_prefix_count
= 2;
183 else if(starts_with_doubled_enumeration_name
)
184 needed_prefix_count
= 1;
186 needed_prefix_count
= 0;
190 if(starts_with_enumeration_name
)
191 needed_prefix_count
= 1; // ensure that we don't end up with name collisions
192 else if(enumerant_name
.empty())
193 needed_prefix_count
= 1; // return something other than the empty string
195 needed_prefix_count
= is_identifier_start(enumerant_name
[0]) ? 0 : 1;
197 for(std::size_t i
= 0; i
< needed_prefix_count
; i
++)
198 enumerant_name
.insert(0, enumeration_name
, enumeration_name_size
);
199 return enumerant_name
;
202 void Generator::write_indent_absolute(Generator_state
&state
, std::size_t amount
)
204 static constexpr auto indent_string
= " ";
205 for(std::size_t i
= 0; i
< amount
; i
++)
206 state
<< indent_string
;
209 void Generator::write_indent_interpreted_text(Generator_state
&state
,
211 std::ptrdiff_t offset
,
214 bool did_indent
= start_indented
;
215 std::size_t indent_amount
= offset
+ state
.indent_level
;
223 indent_amount
= offset
+ state
.indent_level
;
225 else if(!did_indent
&& ch
== '`')
234 write_indent_absolute(state
, indent_amount
);
241 void Generator::write_automatically_generated_file_warning(Generator_state
&state
)
244 << "/* This file is automatically generated by generate_spirv_parser. DO NOT MODIFY. */\n";
247 void Generator::write_copyright_comment(Generator_state
&state
, const ast::Copyright
©right
)
250 for(auto &line
: copyright
.lines
)
258 bool was_last_star
= false;
261 if(was_last_star
&& ch
== '/')
263 was_last_star
= (ch
== '*');
271 void Generator::write_file_guard_start(Generator_state
&state
)
273 state
<< "#ifndef " << state
.guard_macro_name
<< R
"(
275 << state
.guard_macro_name
<< "\n"
279 void Generator::write_file_guard_end(Generator_state
&state
)
281 state
<< "#endif /* " << state
.guard_macro_name
<< " */\n";
284 void Generator::write_namespace_start(Generator_state
&state
, const char *namespace_name
)
286 state
<< "namespace " << namespace_name
<< "\n"
290 void Generator::write_namespace_start(Generator_state
&state
, const std::string
&namespace_name
)
292 state
<< "namespace " << namespace_name
<< "\n"
296 void Generator::write_namespace_end(Generator_state
&state
)
301 void Generator::write_unsigned_integer_literal(Generator_state
&state
,
303 Integer_literal_base base
,
304 std::size_t minimum_digit_count
)
306 constexpr std::uint64_t max_unsigned_value
= std::numeric_limits
<std::uint16_t>::max();
307 constexpr std::uint64_t max_unsigned_long_value
= std::numeric_limits
<std::uint32_t>::max();
309 value
<= max_unsigned_value
? "U" : value
<= max_unsigned_long_value
? "UL" : "ULL";
310 auto number_prefix
= "";
311 unsigned base_as_number
= 10;
314 case Integer_literal_base::dec
:
315 minimum_digit_count
= 1;
317 case Integer_literal_base::hex
:
318 base_as_number
= 0x10;
319 number_prefix
= "0x";
321 case Integer_literal_base::oct
:
322 base_as_number
= 010;
326 auto number_string
= json::ast::Number_value::append_unsigned_integer_to_string(
327 value
, number_prefix
, base_as_number
, minimum_digit_count
)
329 state
<< number_string
;
332 void Generator::write_signed_integer_literal(Generator_state
&state
, std::int64_t value
)
334 constexpr std::int64_t max_int_value
= std::numeric_limits
<std::int16_t>::max();
335 constexpr std::int64_t min_int_value
= std::numeric_limits
<std::int16_t>::min();
336 constexpr std::int64_t max_long_value
= std::numeric_limits
<std::int32_t>::max();
337 constexpr std::int64_t min_long_value
= std::numeric_limits
<std::int32_t>::min();
338 auto literal_type
= "";
339 if(value
< min_int_value
|| value
> max_int_value
)
341 if(value
< min_long_value
|| value
> max_long_value
)
343 state
<< value
<< literal_type
;
346 struct Generator::Get_extensions_visitor
348 std::unordered_set
<std::string
> &retval
;
349 constexpr Get_extensions_visitor(std::unordered_set
<std::string
> &retval
) noexcept
353 template <typename T
>
354 void operator()(const T
&)
357 void operator()(const ast::Extensions
&extensions
)
359 for(auto &extension
: extensions
.extensions
)
360 retval
.insert(extension
);
364 std::unordered_set
<std::string
> Generator::get_extensions(const ast::Top_level
&top_level
)
366 std::unordered_set
<std::string
> retval
;
367 top_level
.visit(Get_extensions_visitor(retval
));
371 void Generator::write_capabilities_set(Generator_state
&state
,
372 const ast::Capabilities
&capabilities
)
374 state
<< "util::Enum_set<" << capability_enum_name
<< ">{";
376 for(auto &capability
: capabilities
.capabilities
)
378 state
<< separator
<< capability_enum_name
379 << "::" << get_enumerant_name(capability_enum_name
, capability
, false);
385 void Generator::write_extensions_set(Generator_state
&state
, const ast::Extensions
&extensions
)
387 state
<< "util::Enum_set<" << extension_enum_name
<< ">{";
389 for(auto &extension
: extensions
.extensions
)
391 state
<< separator
<< extension_enum_name
392 << "::" << get_enumerant_name(extension_enum_name
, extension
, false);
398 std::string
Generator::get_member_name_from_words(const std::string
&words
)
400 enum class Char_class
406 auto get_char_class
= [](char ch
) -> Char_class
408 if(is_uppercase_letter(ch
))
409 return Char_class::Uppercase
;
410 if(is_letter(ch
) || is_digit(ch
))
411 return Char_class::OtherIdentifier
;
412 return Char_class::WordSeparator
;
414 auto find_words
= [&](auto found_word_callback
) -> void
416 util::optional
<std::size_t> word_start
;
417 auto finish_word
= [&](std::size_t index
)
419 found_word_callback(util::string_view(words
.data() + *word_start
, index
- *word_start
));
422 auto start_word
= [&](std::size_t index
)
426 auto last_char_class
= Char_class::WordSeparator
;
427 for(std::size_t i
= 0; i
< words
.size(); i
++)
429 auto current_char_class
= get_char_class(words
[i
]);
432 switch(current_char_class
)
434 case Char_class::WordSeparator
:
437 case Char_class::Uppercase
:
438 if(last_char_class
!= Char_class::Uppercase
)
443 else if(i
+ 1 < words
.size()
444 && get_char_class(words
[i
+ 1]) == Char_class::OtherIdentifier
)
450 case Char_class::OtherIdentifier
:
454 else if(current_char_class
!= Char_class::WordSeparator
)
458 last_char_class
= current_char_class
;
461 finish_word(words
.size());
463 std::size_t retval_size
= 0;
465 find_words([&](util::string_view word
)
468 retval_size
++; // separating '_'
470 retval_size
+= word
.size();
473 retval
.reserve(retval_size
);
475 find_words([&](util::string_view word
)
482 for(char &ch
: retval
)
484 if(is_uppercase_letter(ch
))
485 ch
= ch
- 'A' + 'a'; // to lowercase
487 static constexpr const char *const reserved_words
[] = {
583 for(const char *reserved_word
: reserved_words
)
585 if(retval
== reserved_word
)
595 #warning testing Generator::get_member_name_from_words
596 struct Generator::Tester
606 static Test_runner test_runner
;
610 "abc def", "AbcDef", "ABCDef", "'abc, def'",
613 std::cout
<< "\"" << input
<< "\" -> " << get_member_name_from_words(input
)
619 Generator::Tester::Test_runner
Generator::Tester::test_runner
;
622 std::string
Generator::get_member_name_from_operand(
623 const ast::Instructions::Instruction::Operands::Operand
&operand
)
625 if(!operand
.name
.empty())
626 return get_member_name_from_words(operand
.name
);
627 util::string_view id_str
= "Id";
628 if(util::string_view(operand
.kind
).compare(0, id_str
.size(), id_str
) == 0
629 && id_str
.size() < operand
.kind
.size()
630 && is_uppercase_letter(operand
.kind
[id_str
.size()]))
631 return get_member_name_from_words(operand
.kind
.substr(id_str
.size()));
632 return get_member_name_from_words(operand
.kind
);
635 std::string
Generator::get_enum_with_parameters_struct_name(
636 Generator_state
&state
, const ast::Operand_kinds::Operand_kind
&operand_kind
)
638 if(get_operand_has_any_parameters(state
, operand_kind
))
639 return operand_kind
.kind
+ "_with_parameters";
640 return operand_kind
.kind
;
643 void Generator::write_struct_nonstatic_members_and_constructors(Generator_state
&state
,
644 const std::string
&struct_name
,
645 const std::string
*member_types
,
646 const std::string
*member_names
,
647 std::size_t member_count
)
649 for(std::size_t i
= 0; i
< member_count
; i
++)
650 state
<< indent
<< member_types
[i
] << " " << member_names
[i
] << ";\n";
651 state
<< indent
<< struct_name
<< "()\n";
653 auto push_indent
= state
.pushed_indent();
654 for(std::size_t i
= 0; i
< member_count
; i
++)
661 state
<< member_names
[i
] << "()";
662 if(i
!= member_count
- 1)
670 if(member_count
!= 0)
673 if(member_count
== 1)
674 state
<< "explicit ";
675 state
<< struct_name
<< "(";
676 for(std::size_t i
= 0; i
< member_count
; i
++)
678 state
<< member_types
[i
] << " " << member_names
[i
];
679 if(i
!= member_count
- 1)
684 auto push_indent
= state
.pushed_indent();
685 for(std::size_t i
= 0; i
< member_count
; i
++)
692 state
<< member_names
[i
] << "(std::move(" << member_names
[i
] << "))";
693 if(i
!= member_count
- 1)
704 std::vector
<ast::Operand_kinds::Operand_kind::Enumerants::Enumerant
>
705 Generator::get_unique_enumerants(
706 std::vector
<ast::Operand_kinds::Operand_kind::Enumerants::Enumerant
> enumerants
)
708 std::unordered_set
<std::uint32_t> values
;
709 std::size_t output_index
= 0;
710 for(std::size_t input_index
= 0; input_index
< enumerants
.size(); input_index
++)
712 if(std::get
<1>(values
.insert(enumerants
[input_index
].value
)))
714 if(output_index
!= input_index
)
715 enumerants
[output_index
] = std::move(enumerants
[input_index
]);
719 enumerants
.erase(enumerants
.begin() + output_index
, enumerants
.end());
723 struct Spirv_header_generator final
: public Generator
725 Spirv_header_generator() : Generator("spirv.h")
728 enum class Enum_priority
730 default_priority
= 0,
733 static Enum_priority
get_enum_priority(const std::string
&enum_name
) noexcept
735 if(enum_name
== capability_enum_name
)
736 return Enum_priority::capability
;
737 return Enum_priority::default_priority
;
739 static bool compare_enum_names(const std::string
&l
, const std::string
&r
) noexcept
741 auto l_priority
= get_enum_priority(l
);
742 auto r_priority
= get_enum_priority(r
);
743 if(l_priority
> r_priority
)
744 return true; // higher priority sorts first
745 if(l_priority
< r_priority
)
749 static bool compare_operand_kinds(const ast::Operand_kinds::Operand_kind
&l
,
750 const ast::Operand_kinds::Operand_kind
&r
)
752 // treat both enum categories as equivalent
753 auto l_category
= l
.category
== ast::Operand_kinds::Operand_kind::Category::bit_enum
?
754 ast::Operand_kinds::Operand_kind::Category::value_enum
:
756 auto r_category
= r
.category
== ast::Operand_kinds::Operand_kind::Category::bit_enum
?
757 ast::Operand_kinds::Operand_kind::Category::value_enum
:
759 if(l_category
!= r_category
)
760 return l_category
< r_category
;
761 return compare_enum_names(l
.kind
, r
.kind
);
763 virtual void run(Generator_args
&generator_args
, const ast::Top_level
&top_level
) const override
765 Generator_state
state(this, generator_args
, top_level
);
766 state
.open_output_file();
767 write_file_comments(state
, top_level
.copyright
);
768 write_file_guard_start(state
);
769 state
<< indent(R
"(#include <cstdint>
770 #include "util
/enum.h
"
771 #include "util
/optional
.h
"
774 write_namespaces_start(state
, spirv_namespace_names
);
775 state
<< indent(R
"(typedef std::uint32_t Word;
777 enum class Op : Word;
778 constexpr Word magic_number = )")
779 << unsigned_hex_integer_literal(top_level
.magic_number
, 8)
782 "constexpr std::uint32_t major_version = ")
783 << unsigned_dec_integer_literal(top_level
.major_version
)
786 "constexpr std::uint32_t minor_version = ")
787 << unsigned_dec_integer_literal(top_level
.minor_version
)
790 "constexpr std::uint32_t revision = ")
791 << unsigned_dec_integer_literal(top_level
.revision
) << ";\n";
792 auto extensions_set
= get_extensions(top_level
);
793 std::vector
<std::string
> extensions_list
;
794 extensions_list
.reserve(extensions_set
.size());
795 for(auto &extension
: extensions_set
)
796 extensions_list
.push_back(extension
);
797 std::sort(extensions_list
.begin(), extensions_list
.end());
801 << extension_enum_name
<< indent(true,
805 auto push_indent
= state
.pushed_indent();
806 for(auto &extension
: extensions_list
)
807 state
<< indent
<< get_enumerant_name(extension_enum_name
, extension
, false)
813 "vulkan_cpu_util_generate_enum_traits(")
814 << extension_enum_name
;
816 auto push_indent
= state
.pushed_indent();
817 for(auto &extension
: extensions_list
)
818 state
<< ",\n" << indent
<< extension_enum_name
819 << "::" << get_enumerant_name(extension_enum_name
, extension
, false);
824 "constexpr const char *get_enumerant_name(")
825 << extension_enum_name
<< indent(true,
829 auto push_indent
= state
.pushed_indent();
833 for(auto &extension
: extensions_list
)
835 state
<< indent("case ") << extension_enum_name
836 << "::" << get_enumerant_name(extension_enum_name
, extension
, false)
840 << extension
<< "\";\n";
847 std::vector
<const ast::Operand_kinds::Operand_kind
*> operand_kinds
;
848 operand_kinds
.reserve(top_level
.operand_kinds
.operand_kinds
.size());
849 for(auto &operand_kind
: top_level
.operand_kinds
.operand_kinds
)
850 operand_kinds
.push_back(&operand_kind
);
852 operand_kinds
.begin(),
854 [](const ast::Operand_kinds::Operand_kind
*a
, const ast::Operand_kinds::Operand_kind
*b
)
856 return compare_operand_kinds(*a
, *b
);
858 for(auto *operand_kind
: operand_kinds
)
860 switch(operand_kind
->category
)
862 case ast::Operand_kinds::Operand_kind::Category::bit_enum
:
863 case ast::Operand_kinds::Operand_kind::Category::value_enum
:
866 operand_kind
->category
== ast::Operand_kinds::Operand_kind::Category::bit_enum
;
868 util::get
<ast::Operand_kinds::Operand_kind::Enumerants
>(operand_kind
->value
);
869 auto unique_enumerants
= get_unique_enumerants(enumerants
.enumerants
);
872 << operand_kind
->kind
<< " : Word\n"
875 auto push_indent
= state
.pushed_indent();
876 for(auto &enumerant
: enumerants
.enumerants
)
879 << get_enumerant_name(operand_kind
->kind
, enumerant
.enumerant
, false)
882 state
<< unsigned_hex_integer_literal(enumerant
.value
);
884 state
<< unsigned_dec_integer_literal(enumerant
.value
);
890 "vulkan_cpu_util_generate_enum_traits("
891 << operand_kind
->kind
;
893 auto push_indent
= state
.pushed_indent();
894 for(auto &enumerant
: unique_enumerants
)
895 state
<< ",\n" << indent
<< operand_kind
->kind
<< "::"
896 << get_enumerant_name(operand_kind
->kind
, enumerant
.enumerant
, false);
900 "constexpr const char *get_enumerant_name("
901 << operand_kind
->kind
<< " v) noexcept\n"
904 auto push_indent
= state
.pushed_indent();
908 for(auto &enumerant
: unique_enumerants
)
910 state
<< indent("case ") << operand_kind
->kind
<< "::"
911 << get_enumerant_name(operand_kind
->kind
, enumerant
.enumerant
, false)
915 << enumerant
.enumerant
<< "\";\n";
923 "constexpr util::Enum_set<"
924 << capability_enum_name
<< "> get_directly_required_capability_set("
925 << operand_kind
->kind
<< " v) noexcept\n"
928 auto push_indent
= state
.pushed_indent();
932 for(auto &enumerant
: unique_enumerants
)
934 state
<< indent("case ") << operand_kind
->kind
<< "::"
935 << get_enumerant_name(operand_kind
->kind
, enumerant
.enumerant
, false)
939 << enumerant
.capabilities
<< ";\n";
947 "constexpr util::Enum_set<"
948 << extension_enum_name
<< "> get_directly_required_extension_set("
949 << operand_kind
->kind
<< " v) noexcept\n"
952 auto push_indent
= state
.pushed_indent();
956 for(auto &enumerant
: unique_enumerants
)
958 state
<< indent("case ") << operand_kind
->kind
<< "::"
959 << get_enumerant_name(operand_kind
->kind
, enumerant
.enumerant
, false)
963 << enumerant
.extensions
<< ";\n";
972 case ast::Operand_kinds::Operand_kind::Category::composite
:
975 util::get
<ast::Operand_kinds::Operand_kind::Bases
>(operand_kind
->value
);
978 << operand_kind
->kind
<< "\n"
980 auto push_indent
= state
.pushed_indent();
981 std::vector
<std::string
> member_names
;
982 member_names
.reserve(bases
.values
.size());
983 for(std::size_t i
= 0; i
< bases
.values
.size(); i
++)
984 member_names
.push_back(
985 json::ast::Number_value::append_unsigned_integer_to_string(i
+ 1, "part_"));
986 write_struct_nonstatic_members_and_constructors(state
,
990 bases
.values
.size());
991 push_indent
.finish();
995 case ast::Operand_kinds::Operand_kind::Category::id
:
997 auto &doc
= util::get
<ast::Operand_kinds::Operand_kind::Doc
>(operand_kind
->value
);
1000 bool was_last_star
= false;
1001 for(char ch
: doc
.value
)
1003 if(was_last_star
&& ch
== '/')
1005 was_last_star
= (ch
== '*');
1010 << operand_kind
->kind
<< ";\n";
1013 case ast::Operand_kinds::Operand_kind::Category::literal
:
1015 auto &doc
= util::get
<ast::Operand_kinds::Operand_kind::Doc
>(operand_kind
->value
);
1016 auto base_type
= "std::vector<Word>";
1017 if(operand_kind
->kind
== "LiteralInteger")
1018 base_type
= "std::uint32_t"; // TODO: fix after determining if LiteralInteger
1019 // can be multiple words
1020 else if(operand_kind
->kind
== "LiteralString")
1021 base_type
= "std::string";
1022 else if(operand_kind
->kind
== "LiteralExtInstInteger")
1024 else if(operand_kind
->kind
== "LiteralSpecConstantOpInteger")
1029 bool was_last_star
= false;
1030 for(char ch
: doc
.value
)
1032 if(was_last_star
&& ch
== '/')
1034 was_last_star
= (ch
== '*');
1039 << base_type
<< " " << operand_kind
->kind
<< ";\n";
1044 std::vector
<const ast::Instructions::Instruction
*> instructions
;
1045 instructions
.reserve(top_level
.instructions
.instructions
.size());
1046 for(auto &instruction
: top_level
.instructions
.instructions
)
1047 instructions
.push_back(&instruction
);
1049 instructions
.begin(),
1051 [](const ast::Instructions::Instruction
*a
, const ast::Instructions::Instruction
*b
)
1053 return a
->opcode
< b
->opcode
;
1057 << op_enum_name
<< " : Word\n"
1060 auto push_indent
= state
.pushed_indent();
1061 for(auto &instruction
: top_level
.instructions
.instructions
)
1063 state
<< indent
<< get_enumerant_name(op_enum_name
, instruction
.opname
, true)
1064 << " = " << unsigned_dec_integer_literal(instruction
.opcode
) << ",\n";
1069 "vulkan_cpu_util_generate_enum_traits("
1072 auto push_indent
= state
.pushed_indent();
1073 for(auto &instruction
: top_level
.instructions
.instructions
)
1074 state
<< ",\n" << indent
<< op_enum_name
1075 << "::" << get_enumerant_name(op_enum_name
, instruction
.opname
, true);
1079 "constexpr const char *get_enumerant_name("
1080 << op_enum_name
<< " v) noexcept\n"
1083 auto push_indent
= state
.pushed_indent();
1087 for(auto &instruction
: top_level
.instructions
.instructions
)
1089 state
<< indent("case ") << op_enum_name
1090 << "::" << get_enumerant_name(op_enum_name
, instruction
.opname
, true)
1094 << instruction
.opname
<< "\";\n";
1102 "constexpr util::Enum_set<"
1103 << capability_enum_name
<< "> get_directly_required_capability_set(" << op_enum_name
1107 auto push_indent
= state
.pushed_indent();
1111 for(auto &instruction
: top_level
.instructions
.instructions
)
1113 state
<< indent("case ") << op_enum_name
1114 << "::" << get_enumerant_name(op_enum_name
, instruction
.opname
, true)
1118 << instruction
.capabilities
<< ";\n";
1126 "constexpr util::Enum_set<"
1127 << extension_enum_name
<< "> get_directly_required_extension_set(" << op_enum_name
1131 auto push_indent
= state
.pushed_indent();
1135 for(auto &instruction
: top_level
.instructions
.instructions
)
1137 state
<< indent("case ") << op_enum_name
1138 << "::" << get_enumerant_name(op_enum_name
, instruction
.opname
, true)
1140 auto push_indent2
= state
.pushed_indent();
1141 state
<< indent("return ") << instruction
.extensions
<< ";\n";
1148 for(auto &instruction
: top_level
.instructions
.instructions
)
1150 auto struct_name
= get_enumerant_name(op_enum_name
, instruction
.opname
, true);
1153 << struct_name
<< "\n"
1156 auto push_indent
= state
.pushed_indent();
1157 state
<< indent("static constexpr ") << op_enum_name
<< " get_opcode() noexcept\n"
1160 auto push_indent2
= state
.pushed_indent();
1161 state
<< indent("return ") << op_enum_name
1162 << "::" << get_enumerant_name(op_enum_name
, instruction
.opname
, true)
1165 state
<< indent("}\n");
1166 std::vector
<std::string
> member_names
;
1167 std::vector
<std::string
> member_types
;
1168 member_names
.reserve(instruction
.operands
.operands
.size());
1169 member_types
.reserve(instruction
.operands
.operands
.size());
1170 for(auto &operand
: instruction
.operands
.operands
)
1172 std::string member_type
;
1173 switch(operand
.quantifier
)
1175 case ast::Instructions::Instruction::Operands::Operand::Quantifier::none
:
1177 member_type
= operand
.kind
;
1180 case ast::Instructions::Instruction::Operands::Operand::Quantifier::optional
:
1182 member_type
= "util::optional<" + operand
.kind
+ ">";
1185 case ast::Instructions::Instruction::Operands::Operand::Quantifier::variable
:
1187 member_type
= "std::vector<" + operand
.kind
+ ">";
1191 member_types
.push_back(std::move(member_type
));
1192 member_names
.push_back(get_member_name_from_operand(operand
));
1194 write_struct_nonstatic_members_and_constructors(state
,
1196 member_types
.data(),
1197 member_names
.data(),
1198 member_types
.size());
1204 write_namespaces_end(state
, spirv_namespace_names
);
1205 write_file_guard_end(state
);
1209 struct Spirv_source_generator final
: public Generator
1211 Spirv_source_generator() : Generator("spirv.cpp")
1214 virtual void run(Generator_args
&generator_args
, const ast::Top_level
&top_level
) const override
1216 Generator_state
state(this, generator_args
, top_level
);
1217 state
.open_output_file();
1218 write_file_comments(state
, top_level
.copyright
);
1219 state
<< "#include \"spirv.h\"\n";
1223 struct Parser_header_generator final
: public Generator
1225 Parser_header_generator() : Generator("parser.h")
1228 static std::string
get_dump_operand_function_name(std::string kind
)
1230 return "dump_operand_" + std::move(kind
);
1232 static std::string
get_parse_operand_function_name(std::string kind
)
1234 return "parse_operand_" + std::move(kind
);
1236 static std::string
get_parse_instruction_function_name(std::string opname
)
1238 return "parse_instruction_" + get_enumerant_name(op_enum_name
, opname
, true);
1240 virtual void run(Generator_args
&generator_args
, const ast::Top_level
&top_level
) const override
1242 Generator_state
state(this, generator_args
, top_level
);
1243 state
.open_output_file();
1244 write_file_comments(state
, top_level
.copyright
);
1245 write_file_guard_start(state
);
1246 state
<< R
"(#include "spirv
.h
"
1249 #include "util
/optional
.h
"
1250 #include "json
/json
.h
"
1254 write_namespaces_start(state
, spirv_namespace_names
);
1255 state
<< indent(R
"(struct Parse_error
1257 `std::size_t word_index;
1258 `std::size_t instruction_word_index;
1259 `std::string message;
1260 `Parse_error(std::size_t word_index, std::size_t instruction_word_index, std::string message) noexcept
1261 ``: word_index(word_index),
1262 `` instruction_word_index(instruction_word_index),
1263 `` message(std::move(message))
1266 `virtual ~Parse_error() = default;
1270 state
<< "struct Parse_semantics_generic\n"
1273 auto push_indent
= state
.pushed_indent();
1274 state
<< indent(R
"(virtual ~Parse_semantics_generic() = default;
1275 virtual std::unique_ptr<Parse_error> handle_error(std::size_t word_index, std::size_t instruction_word_index, std::string message) = 0;
1276 virtual void handle_spirv_version(unsigned major, unsigned minor) = 0;
1277 virtual void handle_generator_magic_number(Word value) = 0;
1278 virtual void handle_id_bound(Word id_bound) = 0;
1280 for(auto &instruction
: top_level
.instructions
.instructions
)
1282 auto struct_name
= get_enumerant_name(op_enum_name
, instruction
.opname
, true);
1283 state
<< indent("virtual void handle_instruction(") << struct_name
1284 << " instruction) = 0;\n";
1288 state
<< indent(R
"(};
1290 struct Parse_dump final : public Parse_semantics_generic
1293 `explicit constexpr Parse_dump(std::ostream &os) noexcept : os(os)
1298 auto push_indent
= state
.pushed_indent();
1300 R
"(virtual std::unique_ptr<Parse_error> handle_error(std::size_t word_index, std::size_t instruction_word_index, std::string message) override;
1301 virtual void handle_spirv_version(unsigned major, unsigned minor) override;
1302 virtual void handle_generator_magic_number(Word value) override;
1303 virtual void handle_id_bound(Word id_bound) override;
1305 for(auto &instruction
: top_level
.instructions
.instructions
)
1307 auto struct_name
= get_enumerant_name(op_enum_name
, instruction
.opname
, true);
1308 state
<< indent("virtual void handle_instruction(") << struct_name
1309 << " instruction) override;\n";
1311 for(auto &operand_kind
: top_level
.operand_kinds
.operand_kinds
)
1313 auto dump_function_name
= get_dump_operand_function_name(operand_kind
.kind
);
1314 state
<< indent("void ") << dump_function_name
<< "(const " << operand_kind
.kind
1316 state
<< indent("void ") << dump_function_name
<< "(const util::optional<"
1317 << operand_kind
.kind
<< "> &v);\n";
1318 state
<< indent("void ") << dump_function_name
<< "(const std::vector<"
1319 << operand_kind
.kind
<< "> &v);\n";
1325 "template <typename Semantics = Parse_semantics_generic>\n"
1329 auto push_indent
= state
.pushed_indent();
1330 for(auto &operand_kind
: top_level
.operand_kinds
.operand_kinds
)
1332 auto parse_function_name
= get_parse_operand_function_name(operand_kind
.kind
);
1334 << indent(R
"(static std::unique_ptr<Parse_error> )") << parse_function_name
1337 R
"((const Word *words, std::size_t word_count, Semantics &semantics, std::size_t error_instruction_index, std::size_t &word_index, )")
1338 << operand_kind
.kind
<< indent(true,
1341 `if(word_index >= word_count)
1342 ``return semantics.handle_error(error_instruction_index + word_index, error_instruction_index, "instruction missing operand
");
1344 auto push_indent
= state
.pushed_indent();
1345 switch(operand_kind
.category
)
1347 case ast::Operand_kinds::Operand_kind::Category::bit_enum
:
1349 state
<< indent(R
"(value = static_cast<)") << operand_kind
.kind
1350 << indent(true, R
"(>(words[word_index++]);
1354 case ast::Operand_kinds::Operand_kind::Category::value_enum
:
1356 state
<< indent(R
"(value = static_cast<)") << operand_kind
.kind
1357 << indent(true, R
"(>(words[word_index]);
1358 if(util::Enum_traits<)") << operand_kind
.kind
1359 << indent(true, R
"(>::find_value(value) == util::Enum_traits<)")
1360 << operand_kind
.kind
<< indent(true, R
"(>::npos)
1361 `return semantics.handle_error(error_instruction_index + word_index, error_instruction_index, "invalid
enum value
");
1366 case ast::Operand_kinds::Operand_kind::Category::composite
:
1369 util::get
<ast::Operand_kinds::Operand_kind::Bases
>(operand_kind
.value
);
1370 for(std::size_t i
= 0; i
< bases
.values
.size(); i
++)
1374 state
<< indent(true, "auto ");
1375 state
<< indent(true, "parse_error = ")
1376 << get_parse_operand_function_name(bases
.values
[i
])
1377 << "(words, word_count, semantics, error_instruction_index, "
1378 "word_index, value."
1379 << json::ast::Number_value::append_unsigned_integer_to_string(i
+ 1,
1381 << indent(true, R
"();
1383 `return parse_error;
1388 case ast::Operand_kinds::Operand_kind::Category::id
:
1390 state
<< indent(R
"(value = static_cast<Id>(words[word_index++]);
1394 case ast::Operand_kinds::Operand_kind::Category::literal
:
1396 if(operand_kind
.kind
== "LiteralInteger")
1398 // TODO: fix after determining if LiteralInteger can be multiple words
1399 state
<< indent(R
"(value = words[word_index++];
1402 else if(operand_kind
.kind
== "LiteralExtInstInteger")
1404 state
<< indent(R
"(value = words[word_index++];
1407 else if(operand_kind
.kind
== "LiteralString")
1414 `if(word_index >= word_count)
1415 ``return semantics.handle_error(error_instruction_index + word_index, error_instruction_index, "string missing terminating null
");
1416 `Word word = words[word_index++];
1417 `for(std::size_t i = 0; i < 4; i++)
1419 ``unsigned char ch = word & 0xFFU;
1425 ````return semantics.handle_error(error_instruction_index + word_index, error_instruction_index, "string has non
-zero padding
");
1435 else if(operand_kind
.kind
== "LiteralSpecConstantOpInteger")
1438 state
<< indent(R
"(value = static_cast<)") << op_enum_name
1439 << indent(true, R
"(>(words[word_index++]);
1445 R
"(static_assert(std::is_same<decltype(value), std::vector<Word> &>::value, "missing parse code
for operand kind
");
1447 value.reserve(word_count - word_index);
1448 while(word_index < word_count)
1449 `value.push_back(words[word_index++]);
1455 push_indent
.finish();
1456 state
<< indent(R
"(`return nullptr;
1460 for(auto &instruction
: top_level
.instructions
.instructions
)
1462 auto struct_name
= get_enumerant_name(op_enum_name
, instruction
.opname
, true);
1463 auto parse_function_name
= get_parse_instruction_function_name(instruction
.opname
);
1465 << indent(R
"(static std::unique_ptr<Parse_error> )") << parse_function_name
1468 R
"((const Word *words, std::size_t word_count, Semantics &semantics, std::size_t error_instruction_index)
1470 `std::size_t word_index = 1; // skip opcode
1472 auto push_indent2
= state
.pushed_indent();
1473 state
<< indent
<< struct_name
<< " instruction;\n";
1474 if(!instruction
.operands
.empty())
1475 state
<< indent("std::unique_ptr<Parse_error> parse_error;\n");
1476 for(auto &operand
: instruction
.operands
.operands
)
1478 auto parse_operand_function_name
=
1479 get_parse_operand_function_name(operand
.kind
);
1480 auto member_name
= get_member_name_from_operand(operand
);
1481 switch(operand
.quantifier
)
1483 case ast::Instructions::Instruction::Operands::Operand::Quantifier::none
:
1486 << indent(R
"(parse_error = )") << parse_operand_function_name
1489 R
"((words, word_count, semantics, error_instruction_index, word_index, instruction.)")
1490 << member_name
<< indent(true, R
"();
1492 `return parse_error;
1496 case ast::Instructions::Instruction::Operands::Operand::Quantifier::optional
:
1499 << indent(R
"(if(word_index < word_count)
1501 `instruction.)") << member_name
1502 << indent(true, R
"(.emplace();
1503 `parse_error = )") << parse_operand_function_name
1506 R
"((words, word_count, semantics, error_instruction_index, word_index, *instruction.)")
1507 << member_name
<< indent(true, R
"();
1509 ``return parse_error;
1514 case ast::Instructions::Instruction::Operands::Operand::Quantifier::variable
:
1517 << indent(R
"(while(word_index < word_count)
1519 `instruction.)") << member_name
1520 << indent(true, R
"(.emplace_back();
1521 `parse_error = )") << parse_operand_function_name
1524 R
"((words, word_count, semantics, error_instruction_index, word_index, instruction.)")
1525 << member_name
<< indent(true, R
"(.back());
1527 ``return parse_error;
1533 push_indent2
.finish();
1534 state
<< indent(R
"(`if(word_index < word_count)
1535 ``return semantics.handle_error(error_instruction_index + word_index, error_instruction_index, "extra words at end of instruction
");
1536 `semantics.handle_instruction(std::move(instruction));
1542 R
"(static std::unique_ptr<Parse_error> parse_instruction(const Word *words, std::size_t word_count, Semantics &semantics, std::size_t error_instruction_index)
1544 `Op op = static_cast<Op>(words[0] & 0xFFFFU);
1548 for(auto &instruction
: top_level
.instructions
.instructions
)
1550 auto push_indent2
= state
.pushed_indent(2);
1551 auto enumerant_name
= get_enumerant_name(op_enum_name
, instruction
.opname
, true);
1552 auto parse_function_name
= get_parse_instruction_function_name(instruction
.opname
);
1553 state
<< indent("case ") << op_enum_name
<< "::" << enumerant_name
1554 << indent(true, R
"(:
1555 `return )") << parse_function_name
1556 << indent(true, R
"((words, word_count, semantics, error_instruction_index);
1559 state
<< indent(R
"(`}
1560 `return semantics.handle_error(error_instruction_index, error_instruction_index, json::ast::Number_value::append_unsigned_integer_to_string(static_cast<Word>(op), "unknown instruction
: 0x
", 0x10));
1563 static std::unique_ptr<Parse_error> parse(const Word *words, std::size_t word_count, Semantics &semantics)
1565 `std::size_t word_index = 0;
1566 `if(word_index >= word_count)
1567 ``return semantics.handle_error(word_index, 0, "hit EOF when parsing magic number
");
1568 `if(words[word_index] != magic_number)
1569 ``return semantics.handle_error(word_index, 0, "invalid magic number
");
1571 `if(word_index >= word_count)
1572 ``return semantics.handle_error(word_index, 0, "hit EOF when parsing SPIR
-V version
");
1573 `if(words[word_index] & ~0xFFFF00UL)
1574 ``return semantics.handle_error(word_index, 0, "invalid SPIR
-V version
");
1575 `auto input_major_version = words[word_index] >> 16;
1576 `auto input_minor_version = (words[word_index] >> 8) & 0xFFU;
1577 `semantics.handle_spirv_version(input_major_version, input_minor_version);
1578 `if(input_major_version != major_version || input_minor_version > minor_version)
1579 ``return semantics.handle_error(word_index, 0, "SPIR
-V version
not supported
");
1581 `if(word_index >= word_count)
1582 ``return semantics.handle_error(word_index, 0, "hit EOF when parsing generator
's magic number");
1583 `semantics.handle_generator_magic_number(words[word_index++]);
1584 `if(word_index >= word_count)
1585 ``return semantics.handle_error(word_index, 0, "hit EOF when parsing id bound");
1586 `semantics.handle_id_bound(words[word_index++]);
1587 `if(word_index >= word_count)
1588 ``return semantics.handle_error(word_index, 0, "hit EOF when parsing SPIR-V shader header");
1589 `if(words[word_index] != 0)
1590 ``return semantics.handle_error(word_index, 0, "nonzero reserved word in SPIR-V shader header");
1592 `// now we've finished reading the shader header
, the rest of the shader is just instructions
1593 `
while(word_index
< word_count
)
1595 ``
auto instruction_word_count
= words
[word_index
] >> 16;
1596 ``
if(instruction_word_count
== 0)
1597 ```
return semantics
.handle_error(word_index
, word_index
, "invalid instruction");
1598 ``
if(word_index
+ instruction_word_count
> word_count
)
1599 ```
return semantics
.handle_error(word_index
, word_index
, "instruction longer than rest of shader");
1600 ``
auto parse_error
= parse_instruction(words
+ word_index
, instruction_word_count
, semantics
, word_index
);
1602 ```
return parse_error
;
1603 ``word_index
+= instruction_word_count
;
1612 write_namespaces_end(state, spirv_namespace_names);
1613 write_file_guard_end(state);
1617 struct Parser_source_generator final : public Generator
1619 Parser_source_generator() : Generator("parser
.cpp
")
1622 virtual void run(Generator_args &generator_args, const ast::Top_level &top_level) const override
1624 Generator_state state(this, generator_args, top_level);
1625 state.open_output_file();
1626 write_file_comments(state, top_level.copyright);
1627 state << "#include \"parser.h\"\n"
1628 "#include <type_traits>\n"
1630 write_namespaces_start(state, spirv_namespace_names);
1631 state << indent(R"(namespace
1633 /** instantiate Parser with Parse_semantics_generic to help catch bugs */
1634 [[gnu::unused
]] auto parser_test(const Word
*words
, std::size_t word_count
, Parse_semantics_generic
&semantics
)
1636 `
return Parser
<>::parse(words
, word_count
, semantics
);
1640 std::unique_ptr
<Parse_error
> Parse_dump::handle_error(std::size_t word_index
, std::size_t instruction_word_index
, std::string message
)
1642 `
return std::unique_ptr
<Parse_error
>(new Parse_error(word_index
, instruction_word_index
, std::move(message
)));
1645 void Parse_dump::handle_spirv_version(unsigned major
, unsigned minor
)
1647 `os
<< "SPIR-V version " << major
<< "." << minor
<< "\n";
1650 void Parse_dump::handle_generator_magic_number(Word value
)
1652 `os
<< "generator magic number: " << json::ast::Number_value::append_unsigned_integer_to_string(value
, "0x", 0x10) << "\n";
1655 void Parse_dump::handle_id_bound(Word id_bound
)
1657 `os
<< "id bound: " << json::ast::Number_value::unsigned_integer_to_string(id_bound
) << "\n";
1660 for(auto &operand_kind : top_level.operand_kinds.operand_kinds)
1662 auto dump_function_name =
1663 Parser_header_generator::get_dump_operand_function_name(operand_kind.kind);
1666 void Parse_dump::)") << dump_function_name
1667 << "(const " << operand_kind.kind << R"( &v
)
1670 auto push_indent = state.pushed_indent();
1671 switch(operand_kind.category)
1673 case ast::Operand_kinds::Operand_kind::Category::bit_enum:
1675 state << indent(R"(Word bits
= static_cast<Word
>(v
);
1676 util::Enum_set
<)") << operand_kind.kind
1677 << indent(true, R"(> enum_set
{};
1678 for(auto value
: util::Enum_traits
<)")
1679 << operand_kind.kind << indent(true, R"(>::values
)
1681 `
if(static_cast<Word
>(value
) == 0)
1684 ```enum_set
.insert(value
);
1687 `
if((bits
& static_cast<Word
>(value
)) == static_cast<Word
>(value
))
1689 ``bits
&= ~static_cast<Word
>(value
);
1690 ``enum_set
.insert(value
);
1694 for(auto value
: enum_set
)
1700 `os
<< get_enumerant_name(value
);
1706 `os
<< json::ast::Number_value::append_unsigned_integer_to_string(bits
, "0x", 0x10);
1715 case ast::Operand_kinds::Operand_kind::Category::value_enum:
1717 state << indent(R"(if(util::Enum_traits
<)") << operand_kind.kind
1718 << indent(true, R"(>::find_value(v
) == util::Enum_traits
<)")
1719 << operand_kind.kind << indent(true, R"(>::npos
)
1720 `os
<< json::ast::Number_value::unsigned_integer_to_string(static_cast<Word
>(v
));
1722 `os
<< get_enumerant_name(v
);
1726 case ast::Operand_kinds::Operand_kind::Category::composite:
1729 util::get<ast::Operand_kinds::Operand_kind::Bases>(operand_kind.value);
1730 state << indent("os
<< \"{\";\n");
1731 for(std::size_t i = 0; i < bases.values.size(); i++)
1735 state << indent("os
<< \", \";\n");
1737 state << indent << Parser_header_generator::get_dump_operand_function_name(
1740 << json::ast::Number_value::append_unsigned_integer_to_string(i + 1,
1744 state << indent("os
<< \"}\";\n");
1747 case ast::Operand_kinds::Operand_kind::Category::id:
1750 R"(os
<< json::ast::Number_value::append_unsigned_integer_to_string(v
, "#");
1754 case ast::Operand_kinds::Operand_kind::Category::literal:
1756 if(operand_kind.kind == "LiteralInteger
")
1759 R"(os
<< json::ast::Number_value::append_unsigned_integer_to_string(v
, "0x");
1762 else if(operand_kind.kind == "LiteralExtInstInteger
")
1765 R"(os
<< json::ast::Number_value::append_unsigned_integer_to_string(v
, "0x");
1768 else if(operand_kind.kind == "LiteralString
")
1771 R"(json::ast::String_value::write(os
, v
);
1774 else if(operand_kind.kind == "LiteralSpecConstantOpInteger
")
1776 state << indent(R"(if(util::Enum_traits
<)") << op_enum_name
1777 << indent(true, R"(>::find_value(v
) == util::Enum_traits
<)")
1778 << op_enum_name << indent(true, R"(>::npos
)
1779 `os
<< json::ast::Number_value::unsigned_integer_to_string(static_cast<Word
>(v
));
1781 `os
<< get_enumerant_name(v
);
1787 R"(static_assert(std::is_same
<decltype(v
), const std::vector
<Word
> &>::value
, "missing dump code for operand kind");
1788 auto separator
= "";
1794 `os
<< json::ast::Number_value::append_unsigned_integer_to_string(value
, "0x", 0x10, 8);
1802 push_indent.finish();
1803 state << indent("}\n");
1806 void Parse_dump::)")
1807 << dump_function_name << "(const util::optional
<" << operand_kind.kind
1808 << indent(true, R"(> &v
)
1811 )") << indent(2) << dump_function_name
1812 << indent(true, R"((*v
);
1817 void Parse_dump::)")
1818 << dump_function_name << "(const std::vector
<" << operand_kind.kind
1819 << indent(true, R"(> &v
)
1821 `
auto separator
= "";
1823 `
for(auto &value
: v
)
1827 )") << indent(2) << dump_function_name
1828 << indent(true, R"((value
);
1834 for(auto &instruction : top_level.instructions.instructions)
1836 auto struct_name = get_enumerant_name(op_enum_name, instruction.opname, true);
1839 "void Parse_dump::handle_instruction(")
1840 << struct_name << indent(true, R"( instruction
)
1842 `os
<< ")") << instruction
.opname
1843 << indent(true, R
"(\n";
1845 for(auto &operand : instruction.operands.operands)
1847 auto push_indent = state.pushed_indent();
1848 auto member_name = get_member_name_from_operand(operand);
1849 state << indent("os
<< \" ") << member_name << indent(true, R"(:";
1850 )") << indent
<< Parser_header_generator::get_dump_operand_function_name(operand
.kind
)
1851 << indent(true, R
"((instruction.)") << member_name
<< indent(true, R
"();
1855 state
<< indent("}\n");
1857 write_namespaces_end(state
, spirv_namespace_names
);
1861 std::unique_ptr
<Generator
> Generators::make_spirv_header_generator()
1863 return std::unique_ptr
<Generator
>(new Spirv_header_generator
);
1866 std::unique_ptr
<Generator
> Generators::make_spirv_source_generator()
1868 return std::unique_ptr
<Generator
>(new Spirv_source_generator
);
1871 std::unique_ptr
<Generator
> Generators::make_parser_header_generator()
1873 return std::unique_ptr
<Generator
>(new Parser_header_generator
);
1876 std::unique_ptr
<Generator
> Generators::make_parser_source_generator()
1878 return std::unique_ptr
<Generator
>(new Parser_source_generator
);
1881 std::vector
<std::unique_ptr
<Generator
>> Generators::make_all_generators()
1883 std::unique_ptr
<Generator
> generators_array
[] = {
1884 make_spirv_header_generator(),
1885 make_spirv_source_generator(),
1886 make_parser_header_generator(),
1887 make_parser_source_generator(),
1889 // use array then move because you can't move out of an std::initializer_list
1890 std::vector
<std::unique_ptr
<Generator
>> retval
;
1891 retval
.reserve(sizeof(generators_array
) / sizeof(generators_array
[0]));
1892 for(auto &generator
: generators_array
)
1893 retval
.push_back(std::move(generator
));