VirtualBox

source: vbox/trunk/src/libs/dxvk-2.3.1/include/spirv/tools/buildHeaders/header.cpp@ 105715

Last change on this file since 105715 was 105107, checked in by vboxsync, 11 months ago

libs/dxvk-2.3.1: Make it build, bugref:10716

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 35.9 KB
Line 
1// Copyright (c) 2014-2024 The Khronos Group Inc.
2//
3// Permission is hereby granted, free of charge, to any person obtaining a copy
4// of this software and/or associated documentation files (the "Materials"),
5// to deal in the Materials without restriction, including without limitation
6// the rights to use, copy, modify, merge, publish, distribute, sublicense,
7// and/or sell copies of the Materials, and to permit persons to whom the
8// Materials are furnished to do so, subject to the following conditions:
9//
10// The above copyright notice and this permission notice shall be included in
11// all copies or substantial portions of the Materials.
12//
13// MODIFICATIONS TO THIS FILE MAY MEAN IT NO LONGER ACCURATELY REFLECTS KHRONOS
14// STANDARDS. THE UNMODIFIED, NORMATIVE VERSIONS OF KHRONOS SPECIFICATIONS AND
15// HEADER INFORMATION ARE LOCATED AT https://www.khronos.org/registry/
16//
17// THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
18// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
20// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
22// FROM,OUT OF OR IN CONNECTION WITH THE MATERIALS OR THE USE OR OTHER DEALINGS
23// IN THE MATERIALS.
24
25//
26// Print headers for SPIR-V in several languages.
27//
28// To change the header information, change the C++-built database in doc.*.
29//
30// Then, use "spriv -h <language>" - e.g, spriv.{h,hpp,lua,py,etc}:
31// replace the auto-generated header, or "spirv -H" to generate all
32// supported language headers to predefined names in the current directory.
33//
34
35#include <string>
36#include <sstream>
37#include <fstream>
38#include <cstring>
39#include <cstdio>
40#include <algorithm>
41#include <memory>
42#include <cctype>
43#include <vector>
44#include <utility>
45#include <set>
46
47#include "jsoncpp/dist/json/json.h"
48
49#include "header.h"
50#include "jsonToSpirv.h"
51
52// snprintf and _snprintf are not quite the same, but close enough
53// for our use.
54#ifdef _MSC_VER
55#pragma warning(disable:4996)
56#define snprintf _snprintf
57#endif
58
59// This file converts SPIR-V definitions to an internal JSON
60// representation, and then generates language specific
61// data from that single internal form.
62
63// Initially, the internal form is created from C++ data,
64// though this can be changed to a JSON master in time.
65
66namespace {
67 class TPrinter {
68 protected:
69 TPrinter();
70
71 static const int DocMagicNumber = 0x07230203;
72 static const int DocVersion = 0x00010600;
73 static const int DocRevision = 1;
74 #define DocRevisionString "1"
75 static const std::string DocCopyright;
76 static const std::string DocComment1;
77 static const std::string DocComment2;
78
79 enum enumStyle_t {
80 enumNoMask,
81 enumCount,
82 enumShift,
83 enumMask,
84 enumHex,
85 };
86
87 static std::string styleStr(enumStyle_t s) {
88 return s == enumShift ? "Shift" :
89 s == enumMask ? "Mask" : "";
90 }
91
92 friend std::ostream& operator<<(std::ostream&, const TPrinter&);
93
94 virtual void printAll(std::ostream&) const;
95 virtual void printComments(std::ostream&) const;
96 virtual void printPrologue(std::ostream&) const { }
97 virtual void printDefs(std::ostream&) const;
98 virtual void printEpilogue(std::ostream&) const { }
99 virtual void printMeta(std::ostream&) const;
100 virtual void printTypes(std::ostream&) const { }
101 virtual void printHasResultType(std::ostream&) const { };
102
103 virtual std::string escapeComment(const std::string& s) const;
104
105 // Default printComments() uses these comment strings
106 virtual std::string commentBeg() const { return ""; }
107 virtual std::string commentEnd(bool isLast) const { return ""; }
108 virtual std::string commentBOL() const { return ""; }
109 virtual std::string commentEOL(bool isLast) const { return ""; }
110
111 typedef std::pair<unsigned, std::string> valpair_t;
112
113 // for printing enum values
114 virtual std::string enumBeg(const std::string&, enumStyle_t) const { return ""; }
115 virtual std::string enumEnd(const std::string&, enumStyle_t, bool isLast = false) const {
116 return "";
117 }
118 virtual std::string enumFmt(const std::string&, const valpair_t&,
119 enumStyle_t, bool isLast = false) const {
120 return "";
121 }
122 virtual std::string maxEnumFmt(const std::string&, const valpair_t&,
123 enumStyle_t) const {
124 return "";
125 }
126
127 virtual std::string fmtConstInt(unsigned val, const std::string& name,
128 const char* fmt, bool isLast = false) const {
129 return "";
130 }
131
132 std::vector<valpair_t> getSortedVals(const Json::Value&) const;
133
134 virtual std::string indent(int count = 1) const {
135 return std::string(count * 4, ' '); // default indent level = 4
136 }
137
138 static std::string fmtNum(const char* fmt, unsigned val) {
139 char buff[16]; // ample for 8 hex digits + 0x
140 snprintf(buff, sizeof(buff), fmt, val);
141 buff[sizeof(buff)-1] = '\0'; // MSVC doesn't promise null termination
142 return buff;
143 }
144
145 static std::string fmtStyleVal(unsigned v, enumStyle_t style);
146
147 // If the enum value name would start with a sigit, prepend the enum name.
148 // E.g, "3D" -> "Dim3D".
149 static std::string prependIfDigit(const std::string& ename, const std::string& vname) {
150 return (std::isdigit(vname[0]) ? ename : std::string("")) + vname;
151 }
152
153 void addComment(Json::Value& node, const std::string& str);
154
155 Json::Value spvRoot; // JSON SPIR-V data
156 };
157
158 // Format value as mask or value
159 std::string TPrinter::fmtStyleVal(unsigned v, enumStyle_t style)
160 {
161 switch (style) {
162 case enumMask:
163 return fmtNum("0x%08x", 1<<v);
164 case enumHex:
165 return fmtNum("0x%08x", v);
166 default:
167 return std::to_string(v);
168 }
169 }
170
171 const std::string TPrinter::DocCopyright =
172R"(Copyright (c) 2014-2024 The Khronos Group Inc.
173
174Permission is hereby granted, free of charge, to any person obtaining a copy
175of this software and/or associated documentation files (the "Materials"),
176to deal in the Materials without restriction, including without limitation
177the rights to use, copy, modify, merge, publish, distribute, sublicense,
178and/or sell copies of the Materials, and to permit persons to whom the
179Materials are furnished to do so, subject to the following conditions:
180
181The above copyright notice and this permission notice shall be included in
182all copies or substantial portions of the Materials.
183
184MODIFICATIONS TO THIS FILE MAY MEAN IT NO LONGER ACCURATELY REFLECTS KHRONOS
185STANDARDS. THE UNMODIFIED, NORMATIVE VERSIONS OF KHRONOS SPECIFICATIONS AND
186HEADER INFORMATION ARE LOCATED AT https://www.khronos.org/registry/
187
188THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
189OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
190FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
191THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
192LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
193FROM,OUT OF OR IN CONNECTION WITH THE MATERIALS OR THE USE OR OTHER DEALINGS
194IN THE MATERIALS.
195)";
196
197 const std::string TPrinter::DocComment1 =
198 "This header is automatically generated by the same tool that creates\n"
199 "the Binary Section of the SPIR-V specification.\n";
200
201 const std::string TPrinter::DocComment2 =
202 "Enumeration tokens for SPIR-V, in various styles:\n"
203 " C, C++, C++11, JSON, Lua, Python, C#, D, Beef\n"
204 "\n"
205 "- C will have tokens with a \"Spv\" prefix, e.g.: SpvSourceLanguageGLSL\n"
206 "- C++ will have tokens in the \"spv\" name space, e.g.: spv::SourceLanguageGLSL\n"
207 "- C++11 will use enum classes in the spv namespace, e.g.: spv::SourceLanguage::GLSL\n"
208 "- Lua will use tables, e.g.: spv.SourceLanguage.GLSL\n"
209 "- Python will use dictionaries, e.g.: spv['SourceLanguage']['GLSL']\n"
210 "- C# will use enum classes in the Specification class located in the \"Spv\" namespace,\n"
211 " e.g.: Spv.Specification.SourceLanguage.GLSL\n"
212 "- D will have tokens under the \"spv\" module, e.g: spv.SourceLanguage.GLSL\n"
213 "- Beef will use enum classes in the Specification class located in the \"Spv\" namespace,\n"
214 " e.g.: Spv.Specification.SourceLanguage.GLSL\n"
215 "\n"
216 "Some tokens act like mask values, which can be OR'd together,\n"
217 "while others are mutually exclusive. The mask-like ones have\n"
218 "\"Mask\" in their name, and a parallel enum that has the shift\n"
219 "amount (1 << x) for each corresponding enumerant.\n";
220
221 // Construct
222 TPrinter::TPrinter()
223 {
224 Json::Value& meta = spvRoot["spv"]["meta"];
225 Json::Value& enums = spvRoot["spv"]["enum"];
226
227 meta["MagicNumber"] = DocMagicNumber;
228 meta["Version"] = DocVersion;
229 meta["Revision"] = DocRevision;
230 meta["OpCodeMask"] = 0xffff;
231 meta["WordCountShift"] = 16;
232
233 int commentId = 0;
234 addComment(meta["Comment"][commentId++], DocCopyright);
235 addComment(meta["Comment"][commentId++], DocComment1);
236 addComment(meta["Comment"][commentId++], DocComment2);
237
238 for (int e = spv::OperandSource; e < spv::OperandOpcode; ++e) {
239 auto& enumSet = spv::OperandClassParams[e];
240 const bool mask = enumSet.bitmask;
241 const std::string enumName = enumSet.codeName;
242
243 for (auto& enumRow : enumSet) {
244 std::string name = enumRow.name;
245 enums[e - spv::OperandSource]["Values"][name] = enumRow.value;
246 }
247
248 enums[e - spv::OperandSource]["Type"] = mask ? "Bit" : "Value";
249 enums[e - spv::OperandSource]["Name"] = enumName;
250 }
251
252 // Instructions are in their own different table
253 {
254 auto& entry = enums[spv::OperandOpcode - spv::OperandSource];
255 for (auto& enumRow : spv::InstructionDesc) {
256 std::string name = enumRow.name;
257 entry["Values"][name] = enumRow.value;
258 }
259 entry["Type"] = "Value";
260 entry["Name"] = "Op";
261 }
262 }
263
264 // Create comment
265 void TPrinter::addComment(Json::Value& node, const std::string& str)
266 {
267 std::istringstream cstream(str);
268 std::string cline;
269
270 int line = 0;
271 while (std::getline(cstream, cline)) // fmt each line
272 node[line++] = cline;
273 }
274
275
276 // Return a list of values sorted by enum value. The std::vector
277 // returned by value is okay in c++11 due to move semantics.
278 std::vector<TPrinter::valpair_t>
279 TPrinter::getSortedVals(const Json::Value& p) const
280 {
281 std::vector<valpair_t> values;
282
283 for (auto e = p.begin(); e != p.end(); ++e)
284 values.push_back(valpair_t(e->asUInt(), e.name()));
285
286 // Use a stable sort because we might have aliases, e.g.
287 // SubgropuBallot (might be in future core) vs. SubgroupBallotKHR.
288 std::stable_sort(values.begin(), values.end());
289
290 return values;
291 }
292
293 // Escape comment characters if needed
294 std::string TPrinter::escapeComment(const std::string& s) const { return s; }
295
296 // Format comments in language specific way
297 void TPrinter::printComments(std::ostream& out) const
298 {
299 const int commentCount = spvRoot["spv"]["meta"]["Comment"].size();
300 int commentNum = 0;
301
302 for (const auto& comment : spvRoot["spv"]["meta"]["Comment"]) {
303 out << commentBeg();
304
305 for (int line = 0; line < int(comment.size()); ++line)
306 out << commentBOL() << escapeComment(comment[line].asString()) <<
307 commentEOL((line+1) == comment.size()) << std::endl;
308
309 out << commentEnd(++commentNum == commentCount) << std::endl;
310 }
311 }
312
313 // Format header metadata
314 void TPrinter::printMeta(std::ostream& out) const
315 {
316 const Json::Value& meta = spvRoot["spv"]["meta"];
317
318 const auto print = [&](const char* name, const char* fmt, bool isLast) {
319 out << fmtConstInt(meta[name].asUInt(), name, fmt, isLast);
320 };
321
322 print("MagicNumber", "0x%08lx", false);
323 print("Version", "0x%08lx", false);
324 print("Revision", "%d", false);
325 print("OpCodeMask", "0x%04x", false);
326 print("WordCountShift", "%d", true);
327 }
328
329 // Format value definitions in language specific way
330 void TPrinter::printDefs(std::ostream& out) const
331 {
332 const Json::Value& enums = spvRoot["spv"]["enum"];
333
334 for (auto opClass = enums.begin(); opClass != enums.end(); ++opClass) {
335 const bool isMask = (*opClass)["Type"].asString() == "Bit";
336 const auto opName = (*opClass)["Name"].asString();
337 const auto opPrefix = opName == "Op" ? "" : opName;
338
339 for (enumStyle_t style = (isMask ? enumShift : enumCount);
340 style <= (isMask ? enumMask : enumCount); style = enumStyle_t(int(style)+1)) {
341
342 out << enumBeg(opName, style);
343
344 if (style == enumMask)
345 out << enumFmt(opPrefix, valpair_t(0, "MaskNone"), enumNoMask);
346
347 const auto sorted = getSortedVals((*opClass)["Values"]);
348
349 std::string maxEnum = maxEnumFmt(opName, valpair_t(0x7FFFFFFF, "Max"), enumHex);
350
351 bool printMax = (style != enumMask && maxEnum.size() > 0);
352
353 for (const auto& v : sorted)
354 out << enumFmt(opPrefix, v, style, !printMax && v.second == sorted.back().second);
355
356 if (printMax)
357 out << maxEnum;
358
359 auto nextOpClass = opClass;
360 out << enumEnd(opName, style, ++nextOpClass == enums.end());
361 }
362 }
363 }
364
365 void TPrinter::printAll(std::ostream& out) const
366 {
367 printComments(out);
368 printPrologue(out);
369 printTypes(out);
370 printMeta(out);
371 printDefs(out);
372 printHasResultType(out);
373 printEpilogue(out);
374 }
375
376 // Stream entire header to output
377 std::ostream& operator<<(std::ostream& out, const TPrinter &p)
378 {
379 p.printAll(out);
380 return out;
381 }
382
383 // JSON printer. Rather than use the default printer, we supply our own so
384 // we can control the printing order within various containers.
385 class TPrinterJSON final : public TPrinter {
386 private:
387 void printPrologue(std::ostream& out) const override { out << "{\n" + indent() + "\"spv\":\n" + indent() + "{\n"; }
388 void printEpilogue(std::ostream& out) const override { out << indent() + "}\n}\n"; }
389
390 std::string escapeComment(const std::string& s) const override {
391 std::string newStr;
392 for (auto c : s) {
393 if (c == '"') {
394 newStr += '\\';
395 newStr += c;
396 } else {
397 newStr += c;
398 }
399 }
400 return newStr;
401 }
402
403 std::string fmtConstInt(unsigned val, const std::string& name,
404 const char* fmt, bool isLast) const override {
405 return indent(3) + '"' + name + "\": " + fmtNum("%d", val) + (isLast ? "\n" : ",\n");
406 }
407
408 void printMeta(std::ostream& out) const override
409 {
410 out << indent(2) + "\"meta\":\n" + indent(2) + "{\n";
411 printComments(out);
412 TPrinter::printMeta(out);
413 out << indent(2) + "},\n";
414 }
415
416 std::string commentBeg() const override { return indent(4) + "[\n"; }
417 std::string commentEnd(bool isLast) const override { return indent(4) + (isLast ? "]" : "],"); }
418 std::string commentBOL() const override { return indent(5) + '"'; }
419 std::string commentEOL(bool isLast) const override { return (isLast ? "\"" : "\","); }
420
421 void printComments(std::ostream& out) const override
422 {
423 out << indent(3) + "\"Comment\":\n" + indent(3) + "[\n";
424 TPrinter::printComments(out);
425 out << indent(3) + "],\n";
426 }
427
428 void printDefs(std::ostream& out) const override
429 {
430 out << indent(2) + "\"enum\":\n" + indent(2) + "[\n";
431 TPrinter::printDefs(out);
432 out << indent(2) + "]\n";
433 }
434
435 void printAll(std::ostream& out) const override
436 {
437 printPrologue(out);
438 printMeta(out);
439 printDefs(out);
440 printEpilogue(out);
441 }
442
443 std::string enumBeg(const std::string& s, enumStyle_t style) const override {
444 if (style == enumMask)
445 return "";
446 return indent(3) + "{\n" +
447 indent(4) + "\"Name\": \"" + s + "\",\n" +
448 indent(4) + "\"Type\": " + (style == enumShift ? "\"Bit\"" : "\"Value\"") + ",\n" +
449 indent(4) + "\"Values\":\n" +
450 indent(4) + "{\n";
451 }
452
453 std::string enumEnd(const std::string& s, enumStyle_t style, bool isLast) const override {
454 if (style == enumMask)
455 return "";
456 return indent(4) + "}\n" +
457 indent(3) + "}" + (isLast ? "" : ",") + "\n";
458 }
459
460 std::string enumFmt(const std::string& s, const valpair_t& v,
461 enumStyle_t style, bool isLast) const override {
462 if (style == enumMask || style == enumNoMask)
463 return "";
464 return indent(5) + '"' + prependIfDigit(s, v.second) + "\": " + fmtNum("%d", v.first) +
465 (isLast ? "\n" : ",\n");
466 }
467 };
468
469 // base for C and C++
470 class TPrinterCBase : public TPrinter {
471 protected:
472 virtual void printPrologue(std::ostream& out) const override {
473 out << "#ifndef spirv_" << headerGuardSuffix() << std::endl
474 << "#define spirv_" << headerGuardSuffix() << std::endl
475 << std::endl;
476 }
477
478 void printMeta(std::ostream& out) const override {
479 out << "#define SPV_VERSION 0x" << std::hex << DocVersion << std::dec << "\n";
480 out << "#define SPV_REVISION " << DocRevision << "\n";
481 out << "\n";
482
483 return TPrinter::printMeta(out);
484 }
485
486 virtual void printEpilogue(std::ostream& out) const override {
487 out << "#endif" << std::endl;
488 }
489
490 virtual void printTypes(std::ostream& out) const override {
491 out << "typedef unsigned int " << pre() << "Id;\n\n";
492 }
493
494 virtual std::string fmtConstInt(unsigned val, const std::string& name,
495 const char* fmt, bool isLast) const override
496 {
497 return std::string("static const unsigned int ") + pre() + name +
498 " = " + fmtNum(fmt, val) + (isLast ? ";\n\n" : ";\n");
499 }
500
501 virtual std::string pre() const { return ""; } // C name prefix
502 virtual std::string headerGuardSuffix() const = 0;
503
504 virtual std::string fmtEnumUse(const std::string& opPrefix, const std::string& name) const { return pre() + name; }
505
506 virtual void printHasResultType(std::ostream& out) const override
507 {
508 const Json::Value& enums = spvRoot["spv"]["enum"];
509
510 std::set<unsigned> seenValues;
511
512 for (auto opClass = enums.begin(); opClass != enums.end(); ++opClass) {
513 const auto opName = (*opClass)["Name"].asString();
514 if (opName != "Op") {
515 continue;
516 }
517
518 out << "#ifdef SPV_ENABLE_UTILITY_CODE" << std::endl;
519 out << "#ifndef __cplusplus" << std::endl;
520 out << "#include <stdbool.h>" << std::endl;
521 out << "#endif" << std::endl;
522 out << "inline void " << pre() << "HasResultAndType(" << pre() << opName << " opcode, bool *hasResult, bool *hasResultType) {" << std::endl;
523 out << " *hasResult = *hasResultType = false;" << std::endl;
524 out << " switch (opcode) {" << std::endl;
525 out << " default: /* unknown opcode */ break;" << std::endl;
526
527 for (auto& inst : spv::InstructionDesc) {
528
529 // Filter out duplicate enum values, which would break the switch statement.
530 // These are probably just extension enums promoted to core.
531 if (seenValues.find(inst.value) != seenValues.end()) {
532 continue;
533 }
534 seenValues.insert(inst.value);
535
536 std::string name = inst.name;
537 out << " case " << fmtEnumUse("Op", name) << ": *hasResult = " << (inst.hasResult() ? "true" : "false") << "; *hasResultType = " << (inst.hasType() ? "true" : "false") << "; break;" << std::endl;
538 }
539
540 out << " }" << std::endl;
541 out << "}" << std::endl;
542 out << "#endif /* SPV_ENABLE_UTILITY_CODE */" << std::endl << std::endl;
543 }
544 }
545 };
546
547 // C printer
548 class TPrinterC final : public TPrinterCBase {
549 private:
550 std::string commentBeg() const override { return "/*\n"; }
551 std::string commentEnd(bool isLast) const override { return "*/\n"; }
552 std::string commentBOL() const override { return "** "; }
553
554 std::string enumBeg(const std::string& s, enumStyle_t style) const override {
555 return std::string("typedef enum ") + pre() + s + styleStr(style) + "_ {\n";
556 }
557
558 std::string enumEnd(const std::string& s, enumStyle_t style, bool isLast) const override {
559 return "} " + pre() + s + styleStr(style) + ";\n\n";
560 }
561
562 std::string enumFmt(const std::string& s, const valpair_t& v,
563 enumStyle_t style, bool isLast) const override {
564 return indent() + pre() + s + v.second + styleStr(style) + " = " + fmtStyleVal(v.first, style) + ",\n";
565 }
566
567 std::string maxEnumFmt(const std::string& s, const valpair_t& v,
568 enumStyle_t style) const override {
569 return enumFmt(s, v, style, true);
570 }
571
572 std::string pre() const override { return "Spv"; } // C name prefix
573 std::string headerGuardSuffix() const override { return "H"; }
574 };
575
576 // C++ printer
577 class TPrinterCPP : public TPrinterCBase {
578 protected:
579 void printMaskOperators(std::ostream& out, const std::string& specifiers) const {
580 const Json::Value& enums = spvRoot["spv"]["enum"];
581
582 out << "// Overload bitwise operators for mask bit combining\n\n";
583
584 for (auto opClass = enums.begin(); opClass != enums.end(); ++opClass) {
585 const bool isMask = (*opClass)["Type"].asString() == "Bit";
586 const auto opName = (*opClass)["Name"].asString();
587
588 if (isMask) {
589 const auto typeName = opName + styleStr(enumMask);
590
591 // Overload operator|
592 out << specifiers << " " << typeName << " operator|(" << typeName << " a, " << typeName << " b) { return " <<
593 typeName << "(unsigned(a) | unsigned(b)); }\n";
594 // Overload operator&
595 out << specifiers << " " << typeName << " operator&(" << typeName << " a, " << typeName << " b) { return " <<
596 typeName << "(unsigned(a) & unsigned(b)); }\n";
597 // Overload operator^
598 out << specifiers << " " << typeName << " operator^(" << typeName << " a, " << typeName << " b) { return " <<
599 typeName << "(unsigned(a) ^ unsigned(b)); }\n";
600 // Overload operator~
601 out << specifiers << " " << typeName << " operator~(" << typeName << " a) { return " <<
602 typeName << "(~unsigned(a)); }\n";
603 }
604 }
605 }
606 private:
607 void printPrologue(std::ostream& out) const override {
608 TPrinterCBase::printPrologue(out);
609 out << "namespace spv {\n\n";
610 }
611
612 void printEpilogue(std::ostream& out) const override {
613 printMaskOperators(out, "inline");
614 out << "\n} // end namespace spv\n\n";
615 out << "#endif // #ifndef spirv_" << headerGuardSuffix() << std::endl;
616 }
617
618 std::string commentBOL() const override { return "// "; }
619
620
621 virtual std::string enumBeg(const std::string& s, enumStyle_t style) const override {
622 return std::string("enum ") + s + styleStr(style) + " {\n";
623 }
624
625 std::string enumEnd(const std::string& s, enumStyle_t style, bool isLast) const override {
626 return "};\n\n";
627 }
628
629 virtual std::string enumFmt(const std::string& s, const valpair_t& v,
630 enumStyle_t style, bool isLast) const override {
631 return indent() + s + v.second + styleStr(style) + " = " + fmtStyleVal(v.first, style) + ",\n";
632 }
633
634 virtual std::string maxEnumFmt(const std::string& s, const valpair_t& v,
635 enumStyle_t style) const override {
636 return enumFmt(s, v, style, true);
637 }
638
639 // The C++ and C++11 headers define types with the same name. So they
640 // should use the same header guard.
641 std::string headerGuardSuffix() const override { return "HPP"; }
642
643 std::string operators;
644 };
645
646 // C++11 printer (uses enum classes)
647 class TPrinterCPP11 final : public TPrinterCPP {
648 private:
649 void printEpilogue(std::ostream& out) const override {
650 printMaskOperators(out, "constexpr");
651 out << "\n} // end namespace spv\n\n";
652 out << "#endif // #ifndef spirv_" << headerGuardSuffix() << std::endl;
653 }
654 std::string enumBeg(const std::string& s, enumStyle_t style) const override {
655 return std::string("enum class ") + s + styleStr(style) + " : unsigned {\n";
656 }
657
658 std::string enumFmt(const std::string& s, const valpair_t& v,
659 enumStyle_t style, bool isLast) const override {
660 return indent() + prependIfDigit(s, v.second) + " = " + fmtStyleVal(v.first, style) + ",\n";
661 }
662
663 std::string maxEnumFmt(const std::string& s, const valpair_t& v,
664 enumStyle_t style) const override {
665 return enumFmt(s, v, style, true);
666 }
667
668 // Add type prefix for scoped enum
669 virtual std::string fmtEnumUse(const std::string& opPrefix, const std::string& name) const override { return opPrefix + "::" + name; }
670
671 std::string headerGuardSuffix() const override { return "HPP"; }
672 };
673
674 // LUA printer
675 class TPrinterLua final : public TPrinter {
676 private:
677 void printPrologue(std::ostream& out) const override { out << "spv = {\n"; }
678
679 void printEpilogue(std::ostream& out) const override { out << "}\n"; }
680
681 std::string commentBOL() const override { return "-- "; }
682
683 std::string enumBeg(const std::string& s, enumStyle_t style) const override {
684 return indent() + s + styleStr(style) + " = {\n";
685 }
686
687 std::string enumEnd(const std::string& s, enumStyle_t style, bool isLast) const override {
688 return indent() + "},\n\n";
689 }
690
691 std::string enumFmt(const std::string& s, const valpair_t& v,
692 enumStyle_t style, bool isLast) const override {
693 return indent(2) + prependIfDigit(s, v.second) + " = " + fmtStyleVal(v.first, style) + ",\n";
694 }
695
696 virtual std::string fmtConstInt(unsigned val, const std::string& name,
697 const char* fmt, bool isLast) const override
698 {
699 return indent() + name + " = " + fmtNum(fmt, val) + (isLast ? ",\n\n" : ",\n");
700 }
701 };
702
703 // Python printer
704 class TPrinterPython final : public TPrinter {
705 private:
706 void printPrologue(std::ostream& out) const override { out << "spv = {\n"; }
707
708 void printEpilogue(std::ostream& out) const override { out << "}\n"; }
709
710 std::string commentBOL() const override { return "# "; }
711
712 std::string enumBeg(const std::string& s, enumStyle_t style) const override {
713 return indent() + "'" + s + styleStr(style) + "'" + " : {\n";
714 }
715
716 std::string enumEnd(const std::string& s, enumStyle_t style, bool isLast) const override {
717 return indent() + "},\n\n";
718 }
719
720 std::string enumFmt(const std::string& s, const valpair_t& v,
721 enumStyle_t style, bool isLast) const override {
722 return indent(2) + "'" + prependIfDigit(s, v.second) + "'" + " : " + fmtStyleVal(v.first, style) + ",\n";
723 }
724
725 std::string fmtConstInt(unsigned val, const std::string& name,
726 const char* fmt, bool isLast) const override
727 {
728 return indent() + "'" + name + "'" + " : " + fmtNum(fmt, val) + (isLast ? ",\n\n" : ",\n");
729 }
730 };
731
732 // C# printer
733 class TPrinterCSharp final : public TPrinter {
734 private:
735 std::string commentBOL() const override { return "// "; }
736
737 void printPrologue(std::ostream& out) const override {
738 out << "namespace Spv\n{\n\n";
739 out << indent() << "public static class Specification\n";
740 out << indent() << "{\n";
741 }
742
743 void printEpilogue(std::ostream& out) const override {
744 out << indent() << "}\n";
745 out << "}\n";
746 }
747
748 std::string enumBeg(const std::string& s, enumStyle_t style) const override {
749 return indent(2) + "public enum " + s + styleStr(style) + "\n" + indent(2) + "{\n";
750 }
751
752 std::string enumEnd(const std::string& s, enumStyle_t style, bool isLast) const override {
753 return indent(2) + "}" + + (isLast ? "\n" : "\n\n");
754 }
755
756 std::string enumFmt(const std::string& s, const valpair_t& v,
757 enumStyle_t style, bool isLast) const override {
758 return indent(3) + prependIfDigit(s, v.second) + " = " + fmtStyleVal(v.first, style) + ",\n";
759 }
760
761 std::string fmtConstInt(unsigned val, const std::string& name,
762 const char* fmt, bool isLast) const override {
763 return indent(2) + std::string("public const uint ") + name +
764 " = " + fmtNum(fmt, val) + (isLast ? ";\n\n" : ";\n");
765 }
766 };
767
768 // D printer
769 class TPrinterD final : public TPrinter {
770 private:
771 std::string commentBeg() const override { return "/+\n"; }
772 std::string commentBOL() const override { return " + "; }
773 std::string commentEnd(bool isLast) const override { return " +/\n"; }
774
775 void printPrologue(std::ostream& out) const override {
776 out << "module spv;\n\n";
777 }
778
779 void printEpilogue(std::ostream& out) const override {
780 }
781
782 std::string enumBeg(const std::string& s, enumStyle_t style) const override {
783 return "enum " + s + styleStr(style) + " : uint\n{\n";
784 }
785
786 std::string enumEnd(const std::string& s, enumStyle_t style, bool isLast) const override {
787 return std::string("}\n\n");
788 }
789
790 std::string enumFmt(const std::string& s, const valpair_t& v,
791 enumStyle_t style, bool isLast) const override {
792 return indent() + prependIfDigit("_", v.second) + " = " + fmtStyleVal(v.first, style) + ",\n";
793 }
794
795 std::string fmtConstInt(unsigned val, const std::string& name,
796 const char* fmt, bool isLast) const override {
797 return std::string("enum uint ") + name +
798 " = " + fmtNum(fmt, val) + (isLast ? ";\n\n" : ";\n");
799 }
800 };
801
802 // Beef printer
803 class TPrinterBeef final : public TPrinter {
804 private:
805 std::string commentBOL() const override { return "// "; }
806
807 void printPrologue(std::ostream& out) const override {
808 out << "namespace Spv\n{\n";
809 out << indent() << "using System;\n\n";
810 out << indent() << "public static class Specification\n";
811 out << indent() << "{\n";
812 }
813
814 void printEpilogue(std::ostream& out) const override {
815 out << indent() << "}\n";
816 out << "}\n";
817 }
818
819 std::string enumBeg(const std::string& s, enumStyle_t style) const override {
820 return indent(2) + "[AllowDuplicates, CRepr] public enum " + s + styleStr(style) + "\n" + indent(2) + "{\n";
821 }
822
823 std::string enumEnd(const std::string& s, enumStyle_t style, bool isLast) const override {
824 return indent(2) + "}" + +(isLast ? "\n" : "\n\n");
825 }
826
827 std::string enumFmt(const std::string& s, const valpair_t& v,
828 enumStyle_t style, bool isLast) const override {
829 return indent(3) + prependIfDigit(s, v.second) + " = " + fmtStyleVal(v.first, style) + ",\n";
830 }
831
832 std::string fmtConstInt(unsigned val, const std::string& name,
833 const char* fmt, bool isLast) const override {
834 return indent(2) + std::string("public const uint32 ") + name +
835 " = " + fmtNum(fmt, val) + (isLast ? ";\n\n" : ";\n");
836 }
837 };
838
839} // namespace
840
841namespace spv {
842 void PrintAllHeaders()
843 {
844 // TODO: Once MSVC 2012 is no longer a factor, use brace initializers here
845 std::vector<std::pair<TLanguage, std::string>> langInfo;
846
847 langInfo.push_back(std::make_pair(ELangC, "spirv.h"));
848 langInfo.push_back(std::make_pair(ELangCPP, "spirv.hpp"));
849 langInfo.push_back(std::make_pair(ELangCPP11, "spirv.hpp11"));
850 langInfo.push_back(std::make_pair(ELangJSON, "spirv.json"));
851 langInfo.push_back(std::make_pair(ELangLua, "spirv.lua"));
852 langInfo.push_back(std::make_pair(ELangPython, "spirv.py"));
853 langInfo.push_back(std::make_pair(ELangCSharp, "spirv.cs"));
854 langInfo.push_back(std::make_pair(ELangD, "spv.d"));
855 langInfo.push_back(std::make_pair(ELangBeef, "spirv.bf"));
856
857 for (const auto& lang : langInfo) {
858 std::ofstream out(lang.second, std::ios::out);
859
860 if ((out.rdstate() & std::ifstream::failbit)) {
861 std::cerr << "Unable to open file: " << lang.second << std::endl;
862 } else {
863 PrintHeader(lang.first, out);
864 }
865 }
866 }
867
868 // Print header for given language to given output stream
869 void PrintHeader(TLanguage lang, std::ostream& out)
870 {
871 typedef std::unique_ptr<TPrinter> TPrinterPtr;
872 TPrinterPtr p;
873
874 switch (lang) {
875 case ELangC: p = TPrinterPtr(new TPrinterC); break;
876 case ELangCPP: p = TPrinterPtr(new TPrinterCPP); break;
877 case ELangCPP11: p = TPrinterPtr(new TPrinterCPP11); break;
878 case ELangJSON: p = TPrinterPtr(new TPrinterJSON); break;
879 case ELangLua: p = TPrinterPtr(new TPrinterLua); break;
880 case ELangPython: p = TPrinterPtr(new TPrinterPython); break;
881 case ELangCSharp: p = TPrinterPtr(new TPrinterCSharp); break;
882 case ELangD: p = TPrinterPtr(new TPrinterD); break;
883 case ELangBeef: p = TPrinterPtr(new TPrinterBeef); break;
884 case ELangAll: PrintAllHeaders(); break;
885 default:
886 std::cerr << "Unknown language." << std::endl;
887 return;
888 }
889
890 // Print the data in the requested format
891 if (p)
892 out << *p << std::endl;
893
894 // object is auto-deleted
895 }
896
897} // namespace spv
Note: See TracBrowser for help on using the repository browser.

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette