fd48e25819e6ab42472001d74684196df4d94753
[kazan.git] / src / generate_spirv_parser / generate.cpp
1 /*
2 * Copyright 2017 Jacob Lifshay
3 *
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:
10 *
11 * The above copyright notice and this permission notice shall be included in all
12 * copies or substantial portions of the Software.
13 *
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
20 * SOFTWARE.
21 *
22 */
23 #include "generate.h"
24 #include "json/json.h"
25 #include "util/optional.h"
26 #include <limits>
27 #include <algorithm>
28 #include <cstdlib>
29 #include <iostream>
30 #include <unordered_set>
31
32 #error finish converting to use get_enum_with_parameters_struct_name
33
34 namespace vulkan_cpu
35 {
36 namespace generate_spirv_parser
37 {
38 namespace generate
39 {
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),
44 indent_level(0),
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)),
48 os(),
49 top_level(top_level),
50 operand_kind_map(),
51 operand_has_any_parameters_map()
52 {
53 os.exceptions(std::ios::badbit | std::ios::failbit);
54 for(auto &operand_kind : top_level.operand_kinds.operand_kinds)
55 {
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>(
60 operand_kind.value))
61 {
62 auto &enumerants =
63 util::get<ast::Operand_kinds::Operand_kind::Enumerants>(operand_kind.value);
64 for(auto &enumerant : enumerants.enumerants)
65 {
66 if(!enumerant.parameters.empty())
67 {
68 has_any_parameters = true;
69 break;
70 }
71 }
72 }
73 }
74 }
75
76 void Generator::Generator_state::open_output_file()
77 {
78 os.open(full_output_file_name);
79 }
80
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;
88
89 std::string Generator::get_guard_macro_name_from_file_name(std::string file_name)
90 {
91 auto retval = std::move(file_name);
92 for(char &ch : retval)
93 {
94 if(ch >= 'a' && ch <= 'z')
95 {
96 ch = ch - 'a' + 'A'; // convert to uppercase
97 continue;
98 }
99 if(ch >= 'A' && ch <= 'Z')
100 continue;
101 if(ch >= '0' && ch <= '9')
102 continue;
103 ch = '_';
104 }
105 retval += '_';
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))
111 {
112 // insert a u in all pairs of underlines to prevent generating a reserved identifier
113 retval.insert(++double_underline_index, "u");
114 }
115 if(retval.size() >= 2 && retval[0] == '_' && retval[1] >= 'A' && retval[1] <= 'Z')
116 {
117 // insert a u to prevent generating a reserved identifier: starting with an underline and a
118 // capital letter
119 retval.insert(1, "u");
120 }
121 return retval;
122 }
123
124 namespace
125 {
126 constexpr bool is_uppercase_letter(char ch) noexcept
127 {
128 if(ch >= 'A' && ch <= 'Z')
129 return true;
130 return false;
131 }
132
133 constexpr bool is_lowercase_letter(char ch) noexcept
134 {
135 if(ch >= 'a' && ch <= 'z')
136 return true;
137 return false;
138 }
139
140 constexpr bool is_letter(char ch) noexcept
141 {
142 return is_uppercase_letter(ch) || is_lowercase_letter(ch);
143 }
144
145 constexpr bool is_identifier_start(char ch) noexcept
146 {
147 return is_letter(ch) || ch == '_';
148 }
149
150 constexpr bool is_digit(char ch) noexcept
151 {
152 if(ch >= '0' && ch <= '9')
153 return true;
154 return false;
155 }
156
157 constexpr bool is_identifier_continue(char ch) noexcept
158 {
159 return is_identifier_start(ch) || is_digit(ch);
160 }
161 }
162
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)
167 {
168 bool starts_with_enumeration_name =
169 enumerant_name.compare(0, enumeration_name_size, enumeration_name, enumeration_name_size)
170 == 0;
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,
175 enumeration_name,
176 enumeration_name_size)
177 == 0;
178 std::size_t needed_prefix_count;
179 if(input_name_should_have_prefix)
180 {
181 if(!starts_with_enumeration_name)
182 needed_prefix_count = 2;
183 else if(starts_with_doubled_enumeration_name)
184 needed_prefix_count = 1;
185 else
186 needed_prefix_count = 0;
187 }
188 else
189 {
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
194 else
195 needed_prefix_count = is_identifier_start(enumerant_name[0]) ? 0 : 1;
196 }
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;
200 }
201
202 void Generator::write_indent_absolute(Generator_state &state, std::size_t amount)
203 {
204 static constexpr auto indent_string = " ";
205 for(std::size_t i = 0; i < amount; i++)
206 state << indent_string;
207 }
208
209 void Generator::write_indent_interpreted_text(Generator_state &state,
210 const char *text,
211 std::ptrdiff_t offset,
212 bool start_indented)
213 {
214 bool did_indent = start_indented;
215 std::size_t indent_amount = offset + state.indent_level;
216 for(; *text; text++)
217 {
218 auto &ch = *text;
219 if(ch == '\n')
220 {
221 state << ch;
222 did_indent = false;
223 indent_amount = offset + state.indent_level;
224 }
225 else if(!did_indent && ch == '`')
226 {
227 indent_amount++;
228 }
229 else
230 {
231 if(!did_indent)
232 {
233 did_indent = true;
234 write_indent_absolute(state, indent_amount);
235 }
236 state << ch;
237 }
238 }
239 }
240
241 void Generator::write_automatically_generated_file_warning(Generator_state &state)
242 {
243 state
244 << "/* This file is automatically generated by generate_spirv_parser. DO NOT MODIFY. */\n";
245 }
246
247 void Generator::write_copyright_comment(Generator_state &state, const ast::Copyright &copyright)
248 {
249 state << "/*\n";
250 for(auto &line : copyright.lines)
251 {
252 if(line.empty())
253 {
254 state << " *\n";
255 continue;
256 }
257 state << " * ";
258 bool was_last_star = false;
259 for(char ch : line)
260 {
261 if(was_last_star && ch == '/')
262 state << ' ';
263 was_last_star = (ch == '*');
264 state << ch;
265 }
266 state << "\n";
267 }
268 state << " */\n";
269 }
270
271 void Generator::write_file_guard_start(Generator_state &state)
272 {
273 state << "#ifndef " << state.guard_macro_name << R"(
274 #define )"
275 << state.guard_macro_name << "\n"
276 "\n";
277 }
278
279 void Generator::write_file_guard_end(Generator_state &state)
280 {
281 state << "#endif /* " << state.guard_macro_name << " */\n";
282 }
283
284 void Generator::write_namespace_start(Generator_state &state, const char *namespace_name)
285 {
286 state << "namespace " << namespace_name << "\n"
287 "{\n";
288 }
289
290 void Generator::write_namespace_start(Generator_state &state, const std::string &namespace_name)
291 {
292 state << "namespace " << namespace_name << "\n"
293 "{\n";
294 }
295
296 void Generator::write_namespace_end(Generator_state &state)
297 {
298 state << "}\n";
299 }
300
301 void Generator::write_unsigned_integer_literal(Generator_state &state,
302 std::uint64_t value,
303 Integer_literal_base base,
304 std::size_t minimum_digit_count)
305 {
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();
308 auto literal_type =
309 value <= max_unsigned_value ? "U" : value <= max_unsigned_long_value ? "UL" : "ULL";
310 auto number_prefix = "";
311 unsigned base_as_number = 10;
312 switch(base)
313 {
314 case Integer_literal_base::dec:
315 minimum_digit_count = 1;
316 break;
317 case Integer_literal_base::hex:
318 base_as_number = 0x10;
319 number_prefix = "0x";
320 break;
321 case Integer_literal_base::oct:
322 base_as_number = 010;
323 number_prefix = "0";
324 break;
325 }
326 auto number_string = json::ast::Number_value::append_unsigned_integer_to_string(
327 value, number_prefix, base_as_number, minimum_digit_count)
328 + literal_type;
329 state << number_string;
330 }
331
332 void Generator::write_signed_integer_literal(Generator_state &state, std::int64_t value)
333 {
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)
340 literal_type = "L";
341 if(value < min_long_value || value > max_long_value)
342 literal_type = "LL";
343 state << value << literal_type;
344 }
345
346 struct Generator::Get_extensions_visitor
347 {
348 std::unordered_set<std::string> &retval;
349 constexpr Get_extensions_visitor(std::unordered_set<std::string> &retval) noexcept
350 : retval(retval)
351 {
352 }
353 template <typename T>
354 void operator()(const T &)
355 {
356 }
357 void operator()(const ast::Extensions &extensions)
358 {
359 for(auto &extension : extensions.extensions)
360 retval.insert(extension);
361 }
362 };
363
364 std::unordered_set<std::string> Generator::get_extensions(const ast::Top_level &top_level)
365 {
366 std::unordered_set<std::string> retval;
367 top_level.visit(Get_extensions_visitor(retval));
368 return retval;
369 }
370
371 void Generator::write_capabilities_set(Generator_state &state,
372 const ast::Capabilities &capabilities)
373 {
374 state << "util::Enum_set<" << capability_enum_name << ">{";
375 auto separator = "";
376 for(auto &capability : capabilities.capabilities)
377 {
378 state << separator << capability_enum_name
379 << "::" << get_enumerant_name(capability_enum_name, capability, false);
380 separator = ", ";
381 }
382 state << "}";
383 }
384
385 void Generator::write_extensions_set(Generator_state &state, const ast::Extensions &extensions)
386 {
387 state << "util::Enum_set<" << extension_enum_name << ">{";
388 auto separator = "";
389 for(auto &extension : extensions.extensions)
390 {
391 state << separator << extension_enum_name
392 << "::" << get_enumerant_name(extension_enum_name, extension, false);
393 separator = ", ";
394 }
395 state << "}";
396 }
397
398 std::string Generator::get_member_name_from_words(const std::string &words)
399 {
400 enum class Char_class
401 {
402 Uppercase,
403 OtherIdentifier,
404 WordSeparator,
405 };
406 auto get_char_class = [](char ch) -> Char_class
407 {
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;
413 };
414 auto find_words = [&](auto found_word_callback) -> void
415 {
416 util::optional<std::size_t> word_start;
417 auto finish_word = [&](std::size_t index)
418 {
419 found_word_callback(util::string_view(words.data() + *word_start, index - *word_start));
420 word_start = {};
421 };
422 auto start_word = [&](std::size_t index)
423 {
424 word_start = index;
425 };
426 auto last_char_class = Char_class::WordSeparator;
427 for(std::size_t i = 0; i < words.size(); i++)
428 {
429 auto current_char_class = get_char_class(words[i]);
430 if(word_start)
431 {
432 switch(current_char_class)
433 {
434 case Char_class::WordSeparator:
435 finish_word(i);
436 break;
437 case Char_class::Uppercase:
438 if(last_char_class != Char_class::Uppercase)
439 {
440 finish_word(i);
441 start_word(i);
442 }
443 else if(i + 1 < words.size()
444 && get_char_class(words[i + 1]) == Char_class::OtherIdentifier)
445 {
446 finish_word(i);
447 start_word(i);
448 }
449 break;
450 case Char_class::OtherIdentifier:
451 break;
452 }
453 }
454 else if(current_char_class != Char_class::WordSeparator)
455 {
456 start_word(i);
457 }
458 last_char_class = current_char_class;
459 }
460 if(word_start)
461 finish_word(words.size());
462 };
463 std::size_t retval_size = 0;
464 bool first = true;
465 find_words([&](util::string_view word)
466 {
467 if(!first)
468 retval_size++; // separating '_'
469 first = false;
470 retval_size += word.size();
471 });
472 std::string retval;
473 retval.reserve(retval_size);
474 first = true;
475 find_words([&](util::string_view word)
476 {
477 if(!first)
478 retval += '_';
479 first = false;
480 retval += word;
481 });
482 for(char &ch : retval)
483 {
484 if(is_uppercase_letter(ch))
485 ch = ch - 'A' + 'a'; // to lowercase
486 }
487 static constexpr const char *const reserved_words[] = {
488 "alignas",
489 "alignof",
490 "and",
491 "and_eq",
492 "asm",
493 "atomic_cancel",
494 "atomic_commit",
495 "atomic_noexcept",
496 "auto",
497 "bitand",
498 "bitor",
499 "bool",
500 "break",
501 "case",
502 "catch",
503 "char",
504 "char16_t",
505 "char32_t",
506 "class",
507 "compl",
508 "concept",
509 "concepts",
510 "const",
511 "const_cast",
512 "constexpr",
513 "continue",
514 "decltype",
515 "default",
516 "delete",
517 "do",
518 "double",
519 "dynamic_cast",
520 "else",
521 "enum",
522 "explicit",
523 "export",
524 "extern",
525 "false",
526 "float",
527 "for",
528 "friend",
529 "goto",
530 "if",
531 "import",
532 "inline",
533 "int",
534 "long",
535 "module",
536 "modules",
537 "mutable",
538 "namespace",
539 "new",
540 "noexcept",
541 "not",
542 "not_eq",
543 "nullptr",
544 "operator",
545 "or",
546 "or_eq",
547 "private",
548 "protected",
549 "public",
550 "register",
551 "reinterpret_cast",
552 "requires",
553 "return",
554 "short",
555 "signed",
556 "sizeof",
557 "static",
558 "static_assert",
559 "static_cast",
560 "struct",
561 "switch",
562 "synchronized",
563 "template",
564 "this",
565 "thread_local",
566 "throw",
567 "true",
568 "try",
569 "typedef",
570 "typeid",
571 "typename",
572 "union",
573 "unsigned",
574 "using",
575 "virtual",
576 "void",
577 "volatile",
578 "wchar_t",
579 "while",
580 "xor",
581 "xor_eq",
582 };
583 for(const char *reserved_word : reserved_words)
584 {
585 if(retval == reserved_word)
586 {
587 retval += '_';
588 break;
589 }
590 }
591 return retval;
592 }
593
594 #if 0
595 #warning testing Generator::get_member_name_from_words
596 struct Generator::Tester
597 {
598 struct Test_runner
599 {
600 Test_runner()
601 {
602 test();
603 std::exit(1);
604 }
605 };
606 static Test_runner test_runner;
607 static void test()
608 {
609 for(auto &input : {
610 "abc def", "AbcDef", "ABCDef", "'abc, def'",
611 })
612 {
613 std::cout << "\"" << input << "\" -> " << get_member_name_from_words(input)
614 << std::endl;
615 }
616 }
617 };
618
619 Generator::Tester::Test_runner Generator::Tester::test_runner;
620 #endif
621
622 std::string Generator::get_member_name_from_operand(
623 const ast::Instructions::Instruction::Operands::Operand &operand)
624 {
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);
633 }
634
635 std::string Generator::get_enum_with_parameters_struct_name(
636 Generator_state &state, const ast::Operand_kinds::Operand_kind &operand_kind)
637 {
638 if(get_operand_has_any_parameters(state, operand_kind))
639 return operand_kind.kind + "_with_parameters";
640 return operand_kind.kind;
641 }
642
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)
648 {
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";
652 {
653 auto push_indent = state.pushed_indent();
654 for(std::size_t i = 0; i < member_count; i++)
655 {
656 state << indent;
657 if(i == 0)
658 state << ": ";
659 else
660 state << " ";
661 state << member_names[i] << "()";
662 if(i != member_count - 1)
663 state << ",";
664 state << "\n";
665 }
666 }
667 state << indent(R"({
668 }
669 )");
670 if(member_count != 0)
671 {
672 state << indent;
673 if(member_count == 1)
674 state << "explicit ";
675 state << struct_name << "(";
676 for(std::size_t i = 0; i < member_count; i++)
677 {
678 state << member_types[i] << " " << member_names[i];
679 if(i != member_count - 1)
680 state << ", ";
681 }
682 state << ")\n";
683 {
684 auto push_indent = state.pushed_indent();
685 for(std::size_t i = 0; i < member_count; i++)
686 {
687 state << indent;
688 if(i == 0)
689 state << ": ";
690 else
691 state << " ";
692 state << member_names[i] << "(std::move(" << member_names[i] << "))";
693 if(i != member_count - 1)
694 state << ",";
695 state << "\n";
696 }
697 }
698 state << indent(R"({
699 }
700 )");
701 }
702 }
703
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)
707 {
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++)
711 {
712 if(std::get<1>(values.insert(enumerants[input_index].value)))
713 {
714 if(output_index != input_index)
715 enumerants[output_index] = std::move(enumerants[input_index]);
716 output_index++;
717 }
718 }
719 enumerants.erase(enumerants.begin() + output_index, enumerants.end());
720 return enumerants;
721 }
722
723 struct Spirv_header_generator final : public Generator
724 {
725 Spirv_header_generator() : Generator("spirv.h")
726 {
727 }
728 enum class Enum_priority
729 {
730 default_priority = 0,
731 capability = 1,
732 };
733 static Enum_priority get_enum_priority(const std::string &enum_name) noexcept
734 {
735 if(enum_name == capability_enum_name)
736 return Enum_priority::capability;
737 return Enum_priority::default_priority;
738 }
739 static bool compare_enum_names(const std::string &l, const std::string &r) noexcept
740 {
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)
746 return false;
747 return l < r;
748 }
749 static bool compare_operand_kinds(const ast::Operand_kinds::Operand_kind &l,
750 const ast::Operand_kinds::Operand_kind &r)
751 {
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 :
755 l.category;
756 auto r_category = r.category == ast::Operand_kinds::Operand_kind::Category::bit_enum ?
757 ast::Operand_kinds::Operand_kind::Category::value_enum :
758 r.category;
759 if(l_category != r_category)
760 return l_category < r_category;
761 return compare_enum_names(l.kind, r.kind);
762 }
763 virtual void run(Generator_args &generator_args, const ast::Top_level &top_level) const override
764 {
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"
772 #include <vector>
773 )");
774 write_namespaces_start(state, spirv_namespace_names);
775 state << indent(R"(typedef std::uint32_t Word;
776 typedef Word Id;
777 enum class Op : Word;
778 constexpr Word magic_number = )")
779 << unsigned_hex_integer_literal(top_level.magic_number, 8)
780 << indent(true,
781 ";\n"
782 "constexpr std::uint32_t major_version = ")
783 << unsigned_dec_integer_literal(top_level.major_version)
784 << indent(true,
785 ";\n"
786 "constexpr std::uint32_t minor_version = ")
787 << unsigned_dec_integer_literal(top_level.minor_version)
788 << indent(true,
789 ";\n"
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());
798 state << indent(
799 "\n"
800 "enum class ")
801 << extension_enum_name << indent(true,
802 " : std::size_t\n"
803 "{\n");
804 {
805 auto push_indent = state.pushed_indent();
806 for(auto &extension : extensions_list)
807 state << indent << get_enumerant_name(extension_enum_name, extension, false)
808 << ",\n";
809 }
810 state << indent(
811 "};\n"
812 "\n"
813 "vulkan_cpu_util_generate_enum_traits(")
814 << extension_enum_name;
815 {
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);
820 state << ");\n";
821 }
822 state << indent(
823 "\n"
824 "constexpr const char *get_enumerant_name(")
825 << extension_enum_name << indent(true,
826 " v) noexcept\n"
827 "{\n");
828 {
829 auto push_indent = state.pushed_indent();
830 state << indent(
831 "switch(v)\n"
832 "{\n");
833 for(auto &extension : extensions_list)
834 {
835 state << indent("case ") << extension_enum_name
836 << "::" << get_enumerant_name(extension_enum_name, extension, false)
837 << indent(true,
838 ":\n"
839 "`return \"")
840 << extension << "\";\n";
841 }
842 state << indent(
843 "}\n"
844 "return \"\";\n");
845 }
846 state << "}\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);
851 std::sort(
852 operand_kinds.begin(),
853 operand_kinds.end(),
854 [](const ast::Operand_kinds::Operand_kind *a, const ast::Operand_kinds::Operand_kind *b)
855 {
856 return compare_operand_kinds(*a, *b);
857 });
858 for(auto *operand_kind : operand_kinds)
859 {
860 switch(operand_kind->category)
861 {
862 case ast::Operand_kinds::Operand_kind::Category::bit_enum:
863 case ast::Operand_kinds::Operand_kind::Category::value_enum:
864 {
865 bool is_bit_enum =
866 operand_kind->category == ast::Operand_kinds::Operand_kind::Category::bit_enum;
867 auto &enumerants =
868 util::get<ast::Operand_kinds::Operand_kind::Enumerants>(operand_kind->value);
869 auto unique_enumerants = get_unique_enumerants(enumerants.enumerants);
870 state << "\n"
871 "enum class "
872 << operand_kind->kind << " : Word\n"
873 "{\n";
874 {
875 auto push_indent = state.pushed_indent();
876 for(auto &enumerant : enumerants.enumerants)
877 {
878 state << indent
879 << get_enumerant_name(operand_kind->kind, enumerant.enumerant, false)
880 << " = ";
881 if(is_bit_enum)
882 state << unsigned_hex_integer_literal(enumerant.value);
883 else
884 state << unsigned_dec_integer_literal(enumerant.value);
885 state << ",\n";
886 }
887 }
888 state << "};\n"
889 "\n"
890 "vulkan_cpu_util_generate_enum_traits("
891 << operand_kind->kind;
892 {
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);
897 state << ");\n";
898 }
899 state << "\n"
900 "constexpr const char *get_enumerant_name("
901 << operand_kind->kind << " v) noexcept\n"
902 "{\n";
903 {
904 auto push_indent = state.pushed_indent();
905 state << indent(
906 "switch(v)\n"
907 "{\n");
908 for(auto &enumerant : unique_enumerants)
909 {
910 state << indent("case ") << operand_kind->kind << "::"
911 << get_enumerant_name(operand_kind->kind, enumerant.enumerant, false)
912 << indent(true,
913 ":\n"
914 "`return \"")
915 << enumerant.enumerant << "\";\n";
916 }
917 state << indent(
918 "}\n"
919 "return \"\";\n");
920 }
921 state << "}\n"
922 "\n"
923 "constexpr util::Enum_set<"
924 << capability_enum_name << "> get_directly_required_capability_set("
925 << operand_kind->kind << " v) noexcept\n"
926 "{\n";
927 {
928 auto push_indent = state.pushed_indent();
929 state << indent(
930 "switch(v)\n"
931 "{\n");
932 for(auto &enumerant : unique_enumerants)
933 {
934 state << indent("case ") << operand_kind->kind << "::"
935 << get_enumerant_name(operand_kind->kind, enumerant.enumerant, false)
936 << indent(true,
937 ":\n"
938 "return ")
939 << enumerant.capabilities << ";\n";
940 }
941 state << indent(
942 "}\n"
943 "return {};\n");
944 }
945 state << "}\n"
946 "\n"
947 "constexpr util::Enum_set<"
948 << extension_enum_name << "> get_directly_required_extension_set("
949 << operand_kind->kind << " v) noexcept\n"
950 "{\n";
951 {
952 auto push_indent = state.pushed_indent();
953 state << indent(
954 "switch(v)\n"
955 "{\n");
956 for(auto &enumerant : unique_enumerants)
957 {
958 state << indent("case ") << operand_kind->kind << "::"
959 << get_enumerant_name(operand_kind->kind, enumerant.enumerant, false)
960 << indent(true,
961 ":\n"
962 "return ")
963 << enumerant.extensions << ";\n";
964 }
965 state << indent(
966 "}\n"
967 "return {};\n");
968 }
969 state << "}\n";
970 break;
971 }
972 case ast::Operand_kinds::Operand_kind::Category::composite:
973 {
974 auto &bases =
975 util::get<ast::Operand_kinds::Operand_kind::Bases>(operand_kind->value);
976 state << "\n"
977 "struct "
978 << operand_kind->kind << "\n"
979 "{\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,
987 operand_kind->kind,
988 bases.values.data(),
989 member_names.data(),
990 bases.values.size());
991 push_indent.finish();
992 state << "};\n";
993 break;
994 }
995 case ast::Operand_kinds::Operand_kind::Category::id:
996 {
997 auto &doc = util::get<ast::Operand_kinds::Operand_kind::Doc>(operand_kind->value);
998 state << "\n"
999 "/** ";
1000 bool was_last_star = false;
1001 for(char ch : doc.value)
1002 {
1003 if(was_last_star && ch == '/')
1004 state << ' ';
1005 was_last_star = (ch == '*');
1006 state << ch;
1007 }
1008 state << " */\n"
1009 "typedef Id "
1010 << operand_kind->kind << ";\n";
1011 break;
1012 }
1013 case ast::Operand_kinds::Operand_kind::Category::literal:
1014 {
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")
1023 base_type = "Word";
1024 else if(operand_kind->kind == "LiteralSpecConstantOpInteger")
1025 base_type = "Op";
1026 #warning finish
1027 state << "\n"
1028 "/** ";
1029 bool was_last_star = false;
1030 for(char ch : doc.value)
1031 {
1032 if(was_last_star && ch == '/')
1033 state << ' ';
1034 was_last_star = (ch == '*');
1035 state << ch;
1036 }
1037 state << " */\n"
1038 "typedef "
1039 << base_type << " " << operand_kind->kind << ";\n";
1040 break;
1041 }
1042 }
1043 }
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);
1048 std::sort(
1049 instructions.begin(),
1050 instructions.end(),
1051 [](const ast::Instructions::Instruction *a, const ast::Instructions::Instruction *b)
1052 {
1053 return a->opcode < b->opcode;
1054 });
1055 state << "\n"
1056 "enum class "
1057 << op_enum_name << " : Word\n"
1058 "{\n";
1059 {
1060 auto push_indent = state.pushed_indent();
1061 for(auto &instruction : top_level.instructions.instructions)
1062 {
1063 state << indent << get_enumerant_name(op_enum_name, instruction.opname, true)
1064 << " = " << unsigned_dec_integer_literal(instruction.opcode) << ",\n";
1065 }
1066 }
1067 state << "};\n";
1068 state << "\n"
1069 "vulkan_cpu_util_generate_enum_traits("
1070 << op_enum_name;
1071 {
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);
1076 state << ");\n";
1077 }
1078 state << "\n"
1079 "constexpr const char *get_enumerant_name("
1080 << op_enum_name << " v) noexcept\n"
1081 "{\n";
1082 {
1083 auto push_indent = state.pushed_indent();
1084 state << indent(
1085 "switch(v)\n"
1086 "{\n");
1087 for(auto &instruction : top_level.instructions.instructions)
1088 {
1089 state << indent("case ") << op_enum_name
1090 << "::" << get_enumerant_name(op_enum_name, instruction.opname, true)
1091 << indent(true,
1092 ":\n"
1093 "return \"")
1094 << instruction.opname << "\";\n";
1095 }
1096 state << indent(
1097 "}\n"
1098 "return \"\";\n");
1099 }
1100 state << "}\n"
1101 "\n"
1102 "constexpr util::Enum_set<"
1103 << capability_enum_name << "> get_directly_required_capability_set(" << op_enum_name
1104 << " v) noexcept\n"
1105 "{\n";
1106 {
1107 auto push_indent = state.pushed_indent();
1108 state << indent(
1109 "switch(v)\n"
1110 "{\n");
1111 for(auto &instruction : top_level.instructions.instructions)
1112 {
1113 state << indent("case ") << op_enum_name
1114 << "::" << get_enumerant_name(op_enum_name, instruction.opname, true)
1115 << indent(true,
1116 ":\n"
1117 "return ")
1118 << instruction.capabilities << ";\n";
1119 }
1120 state << indent(
1121 "}\n"
1122 "return {};\n");
1123 }
1124 state << "}\n"
1125 "\n"
1126 "constexpr util::Enum_set<"
1127 << extension_enum_name << "> get_directly_required_extension_set(" << op_enum_name
1128 << " v) noexcept\n"
1129 "{\n";
1130 {
1131 auto push_indent = state.pushed_indent();
1132 state << indent(
1133 "switch(v)\n"
1134 "{\n");
1135 for(auto &instruction : top_level.instructions.instructions)
1136 {
1137 state << indent("case ") << op_enum_name
1138 << "::" << get_enumerant_name(op_enum_name, instruction.opname, true)
1139 << ":\n";
1140 auto push_indent2 = state.pushed_indent();
1141 state << indent("return ") << instruction.extensions << ";\n";
1142 }
1143 state << indent(
1144 "}\n"
1145 "return {};\n");
1146 }
1147 state << "}\n";
1148 for(auto &instruction : top_level.instructions.instructions)
1149 {
1150 auto struct_name = get_enumerant_name(op_enum_name, instruction.opname, true);
1151 state << "\n"
1152 "struct "
1153 << struct_name << "\n"
1154 "{\n";
1155 {
1156 auto push_indent = state.pushed_indent();
1157 state << indent("static constexpr ") << op_enum_name << " get_opcode() noexcept\n"
1158 << indent("{\n");
1159 {
1160 auto push_indent2 = state.pushed_indent();
1161 state << indent("return ") << op_enum_name
1162 << "::" << get_enumerant_name(op_enum_name, instruction.opname, true)
1163 << ";\n";
1164 }
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)
1171 {
1172 std::string member_type;
1173 switch(operand.quantifier)
1174 {
1175 case ast::Instructions::Instruction::Operands::Operand::Quantifier::none:
1176 {
1177 member_type = operand.kind;
1178 break;
1179 }
1180 case ast::Instructions::Instruction::Operands::Operand::Quantifier::optional:
1181 {
1182 member_type = "util::optional<" + operand.kind + ">";
1183 break;
1184 }
1185 case ast::Instructions::Instruction::Operands::Operand::Quantifier::variable:
1186 {
1187 member_type = "std::vector<" + operand.kind + ">";
1188 break;
1189 }
1190 }
1191 member_types.push_back(std::move(member_type));
1192 member_names.push_back(get_member_name_from_operand(operand));
1193 }
1194 write_struct_nonstatic_members_and_constructors(state,
1195 struct_name,
1196 member_types.data(),
1197 member_names.data(),
1198 member_types.size());
1199 }
1200 state << "};\n";
1201 }
1202
1203 #warning finish
1204 write_namespaces_end(state, spirv_namespace_names);
1205 write_file_guard_end(state);
1206 }
1207 };
1208
1209 struct Spirv_source_generator final : public Generator
1210 {
1211 Spirv_source_generator() : Generator("spirv.cpp")
1212 {
1213 }
1214 virtual void run(Generator_args &generator_args, const ast::Top_level &top_level) const override
1215 {
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";
1220 }
1221 };
1222
1223 struct Parser_header_generator final : public Generator
1224 {
1225 Parser_header_generator() : Generator("parser.h")
1226 {
1227 }
1228 static std::string get_dump_operand_function_name(std::string kind)
1229 {
1230 return "dump_operand_" + std::move(kind);
1231 }
1232 static std::string get_parse_operand_function_name(std::string kind)
1233 {
1234 return "parse_operand_" + std::move(kind);
1235 }
1236 static std::string get_parse_instruction_function_name(std::string opname)
1237 {
1238 return "parse_instruction_" + get_enumerant_name(op_enum_name, opname, true);
1239 }
1240 virtual void run(Generator_args &generator_args, const ast::Top_level &top_level) const override
1241 {
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"
1247 #include <memory>
1248 #include <ostream>
1249 #include "util/optional.h"
1250 #include "json/json.h"
1251 #include <vector>
1252
1253 )";
1254 write_namespaces_start(state, spirv_namespace_names);
1255 state << indent(R"(struct Parse_error
1256 {
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))
1264 `{
1265 `}
1266 `virtual ~Parse_error() = default;
1267 };
1268
1269 )");
1270 state << "struct Parse_semantics_generic\n"
1271 "{\n";
1272 {
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;
1279 )");
1280 for(auto &instruction : top_level.instructions.instructions)
1281 {
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";
1285 }
1286 #warning finish
1287 }
1288 state << indent(R"(};
1289
1290 struct Parse_dump final : public Parse_semantics_generic
1291 {
1292 `std::ostream &os;
1293 `explicit constexpr Parse_dump(std::ostream &os) noexcept : os(os)
1294 `{
1295 `}
1296 )");
1297 {
1298 auto push_indent = state.pushed_indent();
1299 state << 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;
1304 )");
1305 for(auto &instruction : top_level.instructions.instructions)
1306 {
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";
1310 }
1311 for(auto &operand_kind : top_level.operand_kinds.operand_kinds)
1312 {
1313 auto dump_function_name = get_dump_operand_function_name(operand_kind.kind);
1314 state << indent("void ") << dump_function_name << "(const " << operand_kind.kind
1315 << " &v);\n";
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";
1320 }
1321 #warning finish
1322 }
1323 state << "};\n"
1324 "\n"
1325 "template <typename Semantics = Parse_semantics_generic>\n"
1326 "struct Parser\n"
1327 "{\n";
1328 {
1329 auto push_indent = state.pushed_indent();
1330 for(auto &operand_kind : top_level.operand_kinds.operand_kinds)
1331 {
1332 auto parse_function_name = get_parse_operand_function_name(operand_kind.kind);
1333 state
1334 << indent(R"(static std::unique_ptr<Parse_error> )") << parse_function_name
1335 << indent(
1336 true,
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,
1339 R"( &value)
1340 {
1341 `if(word_index >= word_count)
1342 ``return semantics.handle_error(error_instruction_index + word_index, error_instruction_index, "instruction missing operand");
1343 )");
1344 auto push_indent = state.pushed_indent();
1345 switch(operand_kind.category)
1346 {
1347 case ast::Operand_kinds::Operand_kind::Category::bit_enum:
1348 {
1349 state << indent(R"(value = static_cast<)") << operand_kind.kind
1350 << indent(true, R"(>(words[word_index++]);
1351 )");
1352 break;
1353 }
1354 case ast::Operand_kinds::Operand_kind::Category::value_enum:
1355 {
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");
1362 word_index++;
1363 )");
1364 break;
1365 }
1366 case ast::Operand_kinds::Operand_kind::Category::composite:
1367 {
1368 auto &bases =
1369 util::get<ast::Operand_kinds::Operand_kind::Bases>(operand_kind.value);
1370 for(std::size_t i = 0; i < bases.values.size(); i++)
1371 {
1372 state << indent;
1373 if(i == 0)
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,
1380 "part_")
1381 << indent(true, R"();
1382 if(parse_error)
1383 `return parse_error;
1384 )");
1385 }
1386 break;
1387 }
1388 case ast::Operand_kinds::Operand_kind::Category::id:
1389 {
1390 state << indent(R"(value = static_cast<Id>(words[word_index++]);
1391 )");
1392 break;
1393 }
1394 case ast::Operand_kinds::Operand_kind::Category::literal:
1395 {
1396 if(operand_kind.kind == "LiteralInteger")
1397 {
1398 // TODO: fix after determining if LiteralInteger can be multiple words
1399 state << indent(R"(value = words[word_index++];
1400 )");
1401 }
1402 else if(operand_kind.kind == "LiteralExtInstInteger")
1403 {
1404 state << indent(R"(value = words[word_index++];
1405 )");
1406 }
1407 else if(operand_kind.kind == "LiteralString")
1408 {
1409 state << indent(
1410 R"(value.clear();
1411 bool done = false;
1412 while(!done)
1413 {
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++)
1418 `{
1419 ``unsigned char ch = word & 0xFFU;
1420 ``word >>= 8;
1421 ``if(ch == '\0')
1422 ``{
1423 ```done = true;
1424 ```if(word != 0)
1425 ````return semantics.handle_error(error_instruction_index + word_index, error_instruction_index, "string has non-zero padding");
1426 ``}
1427 ``else
1428 ``{
1429 ```value += ch;
1430 ``}
1431 `}
1432 }
1433 )");
1434 }
1435 else if(operand_kind.kind == "LiteralSpecConstantOpInteger")
1436 {
1437 #warning finish
1438 state << indent(R"(value = static_cast<)") << op_enum_name
1439 << indent(true, R"(>(words[word_index++]);
1440 )");
1441 }
1442 else
1443 {
1444 state << indent(
1445 R"(static_assert(std::is_same<decltype(value), std::vector<Word> &>::value, "missing parse code for operand kind");
1446 value.clear();
1447 value.reserve(word_count - word_index);
1448 while(word_index < word_count)
1449 `value.push_back(words[word_index++]);
1450 )");
1451 }
1452 break;
1453 }
1454 }
1455 push_indent.finish();
1456 state << indent(R"(`return nullptr;
1457 }
1458 )");
1459 }
1460 for(auto &instruction : top_level.instructions.instructions)
1461 {
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);
1464 state
1465 << indent(R"(static std::unique_ptr<Parse_error> )") << parse_function_name
1466 << indent(
1467 true,
1468 R"((const Word *words, std::size_t word_count, Semantics &semantics, std::size_t error_instruction_index)
1469 {
1470 `std::size_t word_index = 1; // skip opcode
1471 )");
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)
1477 {
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)
1482 {
1483 case ast::Instructions::Instruction::Operands::Operand::Quantifier::none:
1484 {
1485 state
1486 << indent(R"(parse_error = )") << parse_operand_function_name
1487 << indent(
1488 true,
1489 R"((words, word_count, semantics, error_instruction_index, word_index, instruction.)")
1490 << member_name << indent(true, R"();
1491 if(parse_error)
1492 `return parse_error;
1493 )");
1494 break;
1495 }
1496 case ast::Instructions::Instruction::Operands::Operand::Quantifier::optional:
1497 {
1498 state
1499 << indent(R"(if(word_index < word_count)
1500 {
1501 `instruction.)") << member_name
1502 << indent(true, R"(.emplace();
1503 `parse_error = )") << parse_operand_function_name
1504 << indent(
1505 true,
1506 R"((words, word_count, semantics, error_instruction_index, word_index, *instruction.)")
1507 << member_name << indent(true, R"();
1508 `if(parse_error)
1509 ``return parse_error;
1510 }
1511 )");
1512 break;
1513 }
1514 case ast::Instructions::Instruction::Operands::Operand::Quantifier::variable:
1515 {
1516 state
1517 << indent(R"(while(word_index < word_count)
1518 {
1519 `instruction.)") << member_name
1520 << indent(true, R"(.emplace_back();
1521 `parse_error = )") << parse_operand_function_name
1522 << indent(
1523 true,
1524 R"((words, word_count, semantics, error_instruction_index, word_index, instruction.)")
1525 << member_name << indent(true, R"(.back());
1526 `if(parse_error)
1527 ``return parse_error;
1528 }
1529 )");
1530 }
1531 }
1532 }
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));
1537 `return nullptr;
1538 }
1539 )");
1540 }
1541 state << indent(
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)
1543 {
1544 `Op op = static_cast<Op>(words[0] & 0xFFFFU);
1545 `switch(op)
1546 `{
1547 )");
1548 for(auto &instruction : top_level.instructions.instructions)
1549 {
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);
1557 )");
1558 }
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));
1561 }
1562
1563 static std::unique_ptr<Parse_error> parse(const Word *words, std::size_t word_count, Semantics &semantics)
1564 {
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");
1570 `word_index++;
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");
1580 `word_index++;
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");
1591 `word_index++;
1592 `// now we've finished reading the shader header, the rest of the shader is just instructions
1593 `while(word_index < word_count)
1594 `{
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);
1601 ``if(parse_error)
1602 ```return parse_error;
1603 ``word_index += instruction_word_count;
1604 `}
1605 `return nullptr;
1606 }
1607 )");
1608 #warning finish
1609 }
1610 state << "};\n";
1611 #warning finish
1612 write_namespaces_end(state, spirv_namespace_names);
1613 write_file_guard_end(state);
1614 }
1615 };
1616
1617 struct Parser_source_generator final : public Generator
1618 {
1619 Parser_source_generator() : Generator("parser.cpp")
1620 {
1621 }
1622 virtual void run(Generator_args &generator_args, const ast::Top_level &top_level) const override
1623 {
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"
1629 "\n";
1630 write_namespaces_start(state, spirv_namespace_names);
1631 state << indent(R"(namespace
1632 {
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)
1635 {
1636 `return Parser<>::parse(words, word_count, semantics);
1637 }
1638 }
1639
1640 std::unique_ptr<Parse_error> Parse_dump::handle_error(std::size_t word_index, std::size_t instruction_word_index, std::string message)
1641 {
1642 `return std::unique_ptr<Parse_error>(new Parse_error(word_index, instruction_word_index, std::move(message)));
1643 }
1644
1645 void Parse_dump::handle_spirv_version(unsigned major, unsigned minor)
1646 {
1647 `os << "SPIR-V version " << major << "." << minor << "\n";
1648 }
1649
1650 void Parse_dump::handle_generator_magic_number(Word value)
1651 {
1652 `os << "generator magic number: " << json::ast::Number_value::append_unsigned_integer_to_string(value, "0x", 0x10) << "\n";
1653 }
1654
1655 void Parse_dump::handle_id_bound(Word id_bound)
1656 {
1657 `os << "id bound: " << json::ast::Number_value::unsigned_integer_to_string(id_bound) << "\n";
1658 }
1659 )");
1660 for(auto &operand_kind : top_level.operand_kinds.operand_kinds)
1661 {
1662 auto dump_function_name =
1663 Parser_header_generator::get_dump_operand_function_name(operand_kind.kind);
1664 {
1665 state << indent(R"(
1666 void Parse_dump::)") << dump_function_name
1667 << "(const " << operand_kind.kind << R"( &v)
1668 {
1669 )";
1670 auto push_indent = state.pushed_indent();
1671 switch(operand_kind.category)
1672 {
1673 case ast::Operand_kinds::Operand_kind::Category::bit_enum:
1674 {
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)
1680 {
1681 `if(static_cast<Word>(value) == 0)
1682 `{
1683 ``if(v == value)
1684 ```enum_set.insert(value);
1685 ``continue;
1686 `}
1687 `if((bits & static_cast<Word>(value)) == static_cast<Word>(value))
1688 `{
1689 ``bits &= ~static_cast<Word>(value);
1690 ``enum_set.insert(value);
1691 `}
1692 }
1693 bool first = true;
1694 for(auto value : enum_set)
1695 {
1696 `if(first)
1697 ``first = false;
1698 `else
1699 ``os << " | ";
1700 `os << get_enumerant_name(value);
1701 }
1702 if(bits)
1703 {
1704 `if(!first)
1705 ``os << " | ";
1706 `os << json::ast::Number_value::append_unsigned_integer_to_string(bits, "0x", 0x10);
1707 }
1708 else if(first)
1709 {
1710 `os << "0";
1711 }
1712 )");
1713 break;
1714 }
1715 case ast::Operand_kinds::Operand_kind::Category::value_enum:
1716 {
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));
1721 else
1722 `os << get_enumerant_name(v);
1723 )");
1724 break;
1725 }
1726 case ast::Operand_kinds::Operand_kind::Category::composite:
1727 {
1728 auto &bases =
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++)
1732 {
1733 if(i != 0)
1734 {
1735 state << indent("os << \", \";\n");
1736 }
1737 state << indent << Parser_header_generator::get_dump_operand_function_name(
1738 bases.values[i])
1739 << "(v."
1740 << json::ast::Number_value::append_unsigned_integer_to_string(i + 1,
1741 "part_")
1742 << ");\n";
1743 }
1744 state << indent("os << \"}\";\n");
1745 break;
1746 }
1747 case ast::Operand_kinds::Operand_kind::Category::id:
1748 {
1749 state << indent(
1750 R"(os << json::ast::Number_value::append_unsigned_integer_to_string(v, "#");
1751 )");
1752 break;
1753 }
1754 case ast::Operand_kinds::Operand_kind::Category::literal:
1755 {
1756 if(operand_kind.kind == "LiteralInteger")
1757 {
1758 state << indent(
1759 R"(os << json::ast::Number_value::append_unsigned_integer_to_string(v, "0x");
1760 )");
1761 }
1762 else if(operand_kind.kind == "LiteralExtInstInteger")
1763 {
1764 state << indent(
1765 R"(os << json::ast::Number_value::append_unsigned_integer_to_string(v, "0x");
1766 )");
1767 }
1768 else if(operand_kind.kind == "LiteralString")
1769 {
1770 state << indent(
1771 R"(json::ast::String_value::write(os, v);
1772 )");
1773 }
1774 else if(operand_kind.kind == "LiteralSpecConstantOpInteger")
1775 {
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));
1780 else
1781 `os << get_enumerant_name(v);
1782 )");
1783 }
1784 else
1785 {
1786 state << indent(
1787 R"(static_assert(std::is_same<decltype(v), const std::vector<Word> &>::value, "missing dump code for operand kind");
1788 auto separator = "";
1789 os << "{";
1790 for(Word value : v)
1791 {
1792 `os << separator;
1793 `separator = ", ";
1794 `os << json::ast::Number_value::append_unsigned_integer_to_string(value, "0x", 0x10, 8);
1795 }
1796 os << "}";
1797 )");
1798 }
1799 break;
1800 }
1801 }
1802 push_indent.finish();
1803 state << indent("}\n");
1804 }
1805 state << indent(R"(
1806 void Parse_dump::)")
1807 << dump_function_name << "(const util::optional<" << operand_kind.kind
1808 << indent(true, R"(> &v)
1809 {
1810 `if(v)
1811 )") << indent(2) << dump_function_name
1812 << indent(true, R"((*v);
1813 `else
1814 ``os << "nullopt";
1815 }
1816
1817 void Parse_dump::)")
1818 << dump_function_name << "(const std::vector<" << operand_kind.kind
1819 << indent(true, R"(> &v)
1820 {
1821 `auto separator = "";
1822 `os << "{";
1823 `for(auto &value : v)
1824 `{
1825 ``os << separator;
1826 ``separator = ", ";
1827 )") << indent(2) << dump_function_name
1828 << indent(true, R"((value);
1829 `}
1830 `os << "}";
1831 }
1832 )");
1833 }
1834 for(auto &instruction : top_level.instructions.instructions)
1835 {
1836 auto struct_name = get_enumerant_name(op_enum_name, instruction.opname, true);
1837 state << indent(
1838 "\n"
1839 "void Parse_dump::handle_instruction(")
1840 << struct_name << indent(true, R"( instruction)
1841 {
1842 `os << ")") << instruction.opname
1843 << indent(true, R"(\n";
1844 )");
1845 for(auto &operand : instruction.operands.operands)
1846 {
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"();
1852 os << "\n";
1853 )");
1854 }
1855 state << indent("}\n");
1856 }
1857 write_namespaces_end(state, spirv_namespace_names);
1858 }
1859 };
1860
1861 std::unique_ptr<Generator> Generators::make_spirv_header_generator()
1862 {
1863 return std::unique_ptr<Generator>(new Spirv_header_generator);
1864 }
1865
1866 std::unique_ptr<Generator> Generators::make_spirv_source_generator()
1867 {
1868 return std::unique_ptr<Generator>(new Spirv_source_generator);
1869 }
1870
1871 std::unique_ptr<Generator> Generators::make_parser_header_generator()
1872 {
1873 return std::unique_ptr<Generator>(new Parser_header_generator);
1874 }
1875
1876 std::unique_ptr<Generator> Generators::make_parser_source_generator()
1877 {
1878 return std::unique_ptr<Generator>(new Parser_source_generator);
1879 }
1880
1881 std::vector<std::unique_ptr<Generator>> Generators::make_all_generators()
1882 {
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(),
1888 };
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));
1894 return retval;
1895 }
1896 }
1897 }
1898 }