diff options
| author | Xin Li <delphij@google.com> | 2020-09-08 16:54:23 -0700 |
|---|---|---|
| committer | Xin Li <delphij@google.com> | 2020-09-08 16:54:23 -0700 |
| commit | d2ace5d9f01c137c1fbfccda59934bd7abfb8877 (patch) | |
| tree | d004085185210205fb3571a3966ba6b2063f42ca /tools | |
| parent | fd44500f60ca16d4e9ffede30efb945cab3a7240 (diff) | |
| parent | 0e46d4adfc6e2e063a16dea71002c74d3c4f56f8 (diff) | |
| download | platform_external_deqp-deps_SPIRV-Headers-master.tar.gz platform_external_deqp-deps_SPIRV-Headers-master.tar.bz2 platform_external_deqp-deps_SPIRV-Headers-master.zip | |
Bug: 168057903
Merged-In: I0eaecb66e1815442d69d3e0c1e8da1d7e7dc8d58
Change-Id: I411b481e88280b4409a461db3c45fb8548d21718
Diffstat (limited to 'tools')
| -rw-r--r--[-rwxr-xr-x] | tools/buildHeaders/CMakeLists.txt | 0 | ||||
| -rwxr-xr-x | tools/buildHeaders/bin/generate_language_headers.py | 242 | ||||
| -rwxr-xr-x | tools/buildHeaders/bin/makeExtinstHeaders.py | 27 | ||||
| -rwxr-xr-x | tools/buildHeaders/bin/makeHeaders | 4 | ||||
| -rw-r--r--[-rwxr-xr-x] | tools/buildHeaders/header.cpp | 137 | ||||
| -rw-r--r--[-rwxr-xr-x] | tools/buildHeaders/header.h | 13 | ||||
| -rw-r--r--[-rwxr-xr-x] | tools/buildHeaders/jsonToSpirv.cpp | 75 | ||||
| -rw-r--r--[-rwxr-xr-x] | tools/buildHeaders/jsonToSpirv.h | 55 | ||||
| -rw-r--r--[-rwxr-xr-x] | tools/buildHeaders/main.cpp | 20 |
9 files changed, 508 insertions, 65 deletions
diff --git a/tools/buildHeaders/CMakeLists.txt b/tools/buildHeaders/CMakeLists.txt index c624151..c624151 100755..100644 --- a/tools/buildHeaders/CMakeLists.txt +++ b/tools/buildHeaders/CMakeLists.txt diff --git a/tools/buildHeaders/bin/generate_language_headers.py b/tools/buildHeaders/bin/generate_language_headers.py new file mode 100755 index 0000000..c56780c --- /dev/null +++ b/tools/buildHeaders/bin/generate_language_headers.py @@ -0,0 +1,242 @@ +#!/usr/bin/env python3 +# Copyright (c) 2017-2020 Google LLC +# +# Permission is hereby granted, free of charge, to any person obtaining a +# copy of this software and/or associated documentation files (the +# "Materials"), to deal in the Materials without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the Materials, and to +# permit persons to whom the Materials are furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice shall be included +# in all copies or substantial portions of the Materials. +# +# MODIFICATIONS TO THIS FILE MAY MEAN IT NO LONGER ACCURATELY REFLECTS +# KHRONOS STANDARDS. THE UNMODIFIED, NORMATIVE VERSIONS OF KHRONOS +# SPECIFICATIONS AND HEADER INFORMATION ARE LOCATED AT +# https://www.khronos.org/registry/ +# +# THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +# IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +# CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +# TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +# MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS. + +"""Generates a C language headers from a SPIR-V JSON grammar file""" + +import errno +import json +import os.path +import re + +DEFAULT_COPYRIGHT="""Copyright (c) 2020 The Khronos Group Inc. + +Permission is hereby granted, free of charge, to any person obtaining a +copy of this software and/or associated documentation files (the +"Materials"), to deal in the Materials without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Materials, and to +permit persons to whom the Materials are furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Materials. + +MODIFICATIONS TO THIS FILE MAY MEAN IT NO LONGER ACCURATELY REFLECTS +KHRONOS STANDARDS. THE UNMODIFIED, NORMATIVE VERSIONS OF KHRONOS +SPECIFICATIONS AND HEADER INFORMATION ARE LOCATED AT + https://www.khronos.org/registry/ + +THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS. +""".split('\n') + +def make_path_to_file(f): + """Makes all ancestor directories to the given file, if they + don't yet exist. + + Arguments: + f: The file whose ancestor directories are to be created. + """ + dir = os.path.dirname(os.path.abspath(f)) + try: + os.makedirs(dir) + except OSError as e: + if e.errno == errno.EEXIST and os.path.isdir(dir): + pass + else: + raise + +class ExtInstGrammar: + """The grammar for an extended instruction set""" + + def __init__(self, name, copyright, instructions, operand_kinds, version = None, revision = None): + self.name = name + self.copyright = copyright + self.instructions = instructions + self.operand_kinds = operand_kinds + self.version = version + self.revision = revision + + +class LangGenerator: + """A language-specific generator""" + + def __init__(self): + self.upper_case_initial = re.compile('^[A-Z]') + pass + + def comment_prefix(self): + return "" + + def namespace_prefix(self): + return "" + + def uses_guards(self): + return False + + def cpp_guard_preamble(self): + return "" + + def cpp_guard_postamble(self): + return "" + + def enum_value(self, prefix, name, value): + if self.upper_case_initial.match(name): + use_name = name + else: + use_name = '_' + name + + return " {}{} = {},".format(prefix, use_name, value) + + def generate(self, grammar): + """Returns a string that is the language-specific header for the given grammar""" + + parts = [] + if grammar.copyright: + parts.extend(["{}{}".format(self.comment_prefix(), f) for f in grammar.copyright]) + parts.append('') + + guard = 'SPIRV_UNIFIED1_{}_H_'.format(grammar.name) + if self.uses_guards: + parts.append('#ifndef {}'.format(guard)) + parts.append('#define {}'.format(guard)) + parts.append('') + + parts.append(self.cpp_guard_preamble()) + + if grammar.version: + parts.append(self.const_definition(grammar.name, 'Version', grammar.version)) + + if grammar.revision is not None: + parts.append(self.const_definition(grammar.name, 'Revision', grammar.revision)) + + parts.append('') + + if grammar.instructions: + parts.append(self.enum_prefix(grammar.name, 'Instructions')) + for inst in grammar.instructions: + parts.append(self.enum_value(grammar.name, inst['opname'], inst['opcode'])) + parts.append(self.enum_end(grammar.name, 'Instructions')) + parts.append('') + + if grammar.operand_kinds: + for kind in grammar.operand_kinds: + parts.append(self.enum_prefix(grammar.name, kind['kind'])) + for e in kind['enumerants']: + parts.append(self.enum_value(grammar.name, e['enumerant'], e['value'])) + parts.append(self.enum_end(grammar.name, kind['kind'])) + parts.append('') + + parts.append(self.cpp_guard_postamble()) + + if self.uses_guards: + parts.append('#endif // {}'.format(guard)) + + # Ensre the file ends in an end of line + parts.append('') + + return '\n'.join(parts) + + +class CLikeGenerator(LangGenerator): + def uses_guards(self): + return True + + def comment_prefix(self): + return "// " + + def const_definition(self, prefix, var, value): + # Use an anonymous enum. Don't use a static const int variable because + # that can bloat binary size. + return 'enum {0}{1}{2}{3} = {4},{1}{2}{3}_BitWidthPadding = 0x7fffffff{5};'.format( + '{', '\n ', prefix, var, value, '\n}') + + def enum_prefix(self, prefix, name): + return 'enum {}{} {}'.format(prefix, name, '{') + + def enum_end(self, prefix, enum): + return ' {}{}Max = 0x7fffffff\n{};\n'.format(prefix, enum, '}') + + def cpp_guard_preamble(self): + return '#ifdef __cplusplus\nextern "C" {\n#endif\n' + + def cpp_guard_postamble(self): + return '#ifdef __cplusplus\n}\n#endif\n' + + +class CGenerator(CLikeGenerator): + pass + + +def main(): + import argparse + parser = argparse.ArgumentParser(description='Generate language headers from a JSON grammar') + + parser.add_argument('--extinst-name', + type=str, required=True, + help='The name to use in tokens') + parser.add_argument('--extinst-grammar', metavar='<path>', + type=str, required=True, + help='input JSON grammar file for extended instruction set') + parser.add_argument('--extinst-output-base', metavar='<path>', + type=str, required=True, + help='Basename of the language-specific output file.') + args = parser.parse_args() + + with open(args.extinst_grammar) as json_file: + grammar_json = json.loads(json_file.read()) + if 'copyright' in grammar_json: + copyright = grammar_json['copyright'] + else: + copyright = DEFAULT_COPYRIGHT + if 'version' in grammar_json: + version = grammar_json['version'] + else: + version = 0 + if 'operand_kinds' in grammar_json: + operand_kinds = grammar_json['operand_kinds'] + else: + operand_kinds = [] + + grammar = ExtInstGrammar(name = args.extinst_name, + copyright = copyright, + instructions = grammar_json['instructions'], + operand_kinds = operand_kinds, + version = version, + revision = grammar_json['revision']) + make_path_to_file(args.extinst_output_base) + with open(args.extinst_output_base + '.h', 'w') as f: + f.write(CGenerator().generate(grammar)) + + +if __name__ == '__main__': + main() diff --git a/tools/buildHeaders/bin/makeExtinstHeaders.py b/tools/buildHeaders/bin/makeExtinstHeaders.py new file mode 100755 index 0000000..780e479 --- /dev/null +++ b/tools/buildHeaders/bin/makeExtinstHeaders.py @@ -0,0 +1,27 @@ +#!/usr/bin/env python3 +"""Generate C headers for certain extended instruction sets""" + +import subprocess +import os + +# Assume we are running from the tools/buildHeaders directory +os.chdir('../../include/spirv/unified1') + +def mk_extinst(name, grammar_file): + """Generate one C header from a grammar""" + script = '../../../tools/buildHeaders/bin/generate_language_headers.py' + subprocess.check_call(['python3', + script, + '--extinst-name=' + name, + '--extinst-grammar=' + grammar_file, + '--extinst-output-base=' + name]) + subprocess.check_call(['dos2unix', name + '.h']) + + +mk_extinst('DebugInfo', 'extinst.debuginfo.grammar.json') +mk_extinst('OpenCLDebugInfo100', 'extinst.opencl.debuginfo.100.grammar.json') +mk_extinst('AMD_gcn_shader', 'extinst.spv-amd-gcn-shader.grammar.json') +mk_extinst('AMD_shader_ballot', 'extinst.spv-amd-shader-ballot.grammar.json') +mk_extinst('AMD_shader_explicit_vertex_parameter', 'extinst.spv-amd-shader-explicit-vertex-parameter.grammar.json') +mk_extinst('AMD_shader_trinary_minmax', 'extinst.spv-amd-shader-trinary-minmax.grammar.json') +mk_extinst('NonSemanticDebugPrintf', 'extinst.nonsemantic.debugprintf.grammar.json') diff --git a/tools/buildHeaders/bin/makeHeaders b/tools/buildHeaders/bin/makeHeaders index 20b8e04..0ca0b2f 100755 --- a/tools/buildHeaders/bin/makeHeaders +++ b/tools/buildHeaders/bin/makeHeaders @@ -1,5 +1,7 @@ #!/usr/bin/env bash +python3 bin/makeExtinstHeaders.py + cd ../../include/spirv/unified1 ../../../tools/buildHeaders/build/install/bin/buildSpvHeaders -H spirv.core.grammar.json -dos2unix spirv.* SpirV.* +dos2unix spirv.* SpirV.* spv.* diff --git a/tools/buildHeaders/header.cpp b/tools/buildHeaders/header.cpp index 6f96d1c..7e8f668 100755..100644 --- a/tools/buildHeaders/header.cpp +++ b/tools/buildHeaders/header.cpp @@ -1,19 +1,19 @@ -// Copyright (c) 2014-2018 The Khronos Group Inc. -// +// Copyright (c) 2014-2020 The Khronos Group Inc. +// // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and/or associated documentation files (the "Materials"), // to deal in the Materials without restriction, including without limitation // the rights to use, copy, modify, merge, publish, distribute, sublicense, // and/or sell copies of the Materials, and to permit persons to whom the // Materials are furnished to do so, subject to the following conditions: -// +// // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Materials. -// +// // MODIFICATIONS TO THIS FILE MAY MEAN IT NO LONGER ACCURATELY REFLECTS KHRONOS // STANDARDS. THE UNMODIFIED, NORMATIVE VERSIONS OF KHRONOS SPECIFICATIONS AND -// HEADER INFORMATION ARE LOCATED AT https://www.khronos.org/registry/ -// +// HEADER INFORMATION ARE LOCATED AT https://www.khronos.org/registry/ +// // THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL @@ -42,6 +42,7 @@ #include <cctype> #include <vector> #include <utility> +#include <set> #include "jsoncpp/dist/json/json.h" @@ -68,9 +69,9 @@ namespace { TPrinter(); static const int DocMagicNumber = 0x07230203; - static const int DocVersion = 0x00010300; - static const int DocRevision = 6; - #define DocRevisionString "6" + static const int DocVersion = 0x00010500; + static const int DocRevision = 1; + #define DocRevisionString "1" static const std::string DocCopyright; static const std::string DocComment1; static const std::string DocComment2; @@ -97,7 +98,8 @@ namespace { virtual void printEpilogue(std::ostream&) const { } virtual void printMeta(std::ostream&) const; virtual void printTypes(std::ostream&) const { } - + virtual void printHasResultType(std::ostream&) const { }; + virtual std::string escapeComment(const std::string& s) const; // Default printComments() uses these comment strings @@ -107,7 +109,7 @@ namespace { virtual std::string commentEOL(bool isLast) const { return ""; } typedef std::pair<unsigned, std::string> valpair_t; - + // for printing enum values virtual std::string enumBeg(const std::string&, enumStyle_t) const { return ""; } virtual std::string enumEnd(const std::string&, enumStyle_t, bool isLast = false) const { @@ -126,7 +128,7 @@ namespace { const char* fmt, bool isLast = false) const { return ""; } - + std::vector<valpair_t> getSortedVals(const Json::Value&) const; virtual std::string indent(int count = 1) const { @@ -149,7 +151,7 @@ namespace { } void addComment(Json::Value& node, const std::string& str); - + Json::Value spvRoot; // JSON SPIR-V data }; @@ -167,7 +169,7 @@ namespace { } const std::string TPrinter::DocCopyright = - "Copyright (c) 2014-2018 The Khronos Group Inc.\n" + "Copyright (c) 2014-2020 The Khronos Group Inc.\n" "\n" "Permission is hereby granted, free of charge, to any person obtaining a copy\n" "of this software and/or associated documentation files (the \"Materials\"),\n" @@ -197,14 +199,16 @@ namespace { const std::string TPrinter::DocComment2 = "Enumeration tokens for SPIR-V, in various styles:\n" - " C, C++, C++11, JSON, Lua, Python, C#\n" + " C, C++, C++11, JSON, Lua, Python, C#, D\n" "\n" "- C will have tokens with a \"Spv\" prefix, e.g.: SpvSourceLanguageGLSL\n" "- C++ will have tokens in the \"spv\" name space, e.g.: spv::SourceLanguageGLSL\n" "- C++11 will use enum classes in the spv namespace, e.g.: spv::SourceLanguage::GLSL\n" "- Lua will use tables, e.g.: spv.SourceLanguage.GLSL\n" "- Python will use dictionaries, e.g.: spv['SourceLanguage']['GLSL']\n" - "- C# will use enum classes in the Specification class located in the \"Spv\" namespace, e.g.: Spv.Specification.SourceLanguage.GLSL\n" + "- C# will use enum classes in the Specification class located in the \"Spv\" namespace,\n" + " e.g.: Spv.Specification.SourceLanguage.GLSL\n" + "- D will have tokens under the \"spv\" module, e.g: spv.SourceLanguage.GLSL\n" "\n" "Some tokens act like mask values, which can be OR'd together,\n" "while others are mutually exclusive. The mask-like ones have\n" @@ -291,7 +295,7 @@ namespace { { const int commentCount = spvRoot["spv"]["meta"]["Comment"].size(); int commentNum = 0; - + for (const auto& comment : spvRoot["spv"]["meta"]["Comment"]) { out << commentBeg(); @@ -323,7 +327,7 @@ namespace { void TPrinter::printDefs(std::ostream& out) const { const Json::Value& enums = spvRoot["spv"]["enum"]; - + for (auto opClass = enums.begin(); opClass != enums.end(); ++opClass) { const bool isMask = (*opClass)["Type"].asString() == "Bit"; const auto opName = (*opClass)["Name"].asString(); @@ -338,13 +342,13 @@ namespace { out << enumFmt(opPrefix, valpair_t(0, "MaskNone"), enumNoMask); const auto sorted = getSortedVals((*opClass)["Values"]); - - std::string maxEnum = maxEnumFmt(opName, valpair_t(0x7FFFFFFF, "Max"), enumHex); + + std::string maxEnum = maxEnumFmt(opName, valpair_t(0x7FFFFFFF, "Max"), enumHex); bool printMax = (style != enumMask && maxEnum.size() > 0); for (const auto& v : sorted) - out << enumFmt(opPrefix, v, style, !printMax && v.first == sorted.back().first); + out << enumFmt(opPrefix, v, style, !printMax && v.second == sorted.back().second); if (printMax) out << maxEnum; @@ -362,6 +366,7 @@ namespace { printTypes(out); printMeta(out); printDefs(out); + printHasResultType(out); printEpilogue(out); } @@ -391,7 +396,7 @@ namespace { } return newStr; } - + std::string fmtConstInt(unsigned val, const std::string& name, const char* fmt, bool isLast) const override { return indent(3) + '"' + name + "\": " + fmtNum("%d", val) + (isLast ? "\n" : ",\n"); @@ -476,7 +481,7 @@ namespace { } virtual void printEpilogue(std::ostream& out) const override { - out << "#endif // #ifndef spirv_" << headerGuardSuffix() << std::endl; + out << "#endif" << std::endl; } virtual void printTypes(std::ostream& out) const override { @@ -489,9 +494,48 @@ namespace { return std::string("static const unsigned int ") + pre() + name + " = " + fmtNum(fmt, val) + (isLast ? ";\n\n" : ";\n"); } - + virtual std::string pre() const { return ""; } // C name prefix virtual std::string headerGuardSuffix() const = 0; + + virtual std::string fmtEnumUse(const std::string& opPrefix, const std::string& name) const { return pre() + name; } + + virtual void printHasResultType(std::ostream& out) const + { + const Json::Value& enums = spvRoot["spv"]["enum"]; + + std::set<unsigned> seenValues; + + for (auto opClass = enums.begin(); opClass != enums.end(); ++opClass) { + const auto opName = (*opClass)["Name"].asString(); + if (opName != "Op") { + continue; + } + + out << "#ifdef SPV_ENABLE_UTILITY_CODE" << std::endl; + out << "inline void " << pre() << "HasResultAndType(" << pre() << opName << " opcode, bool *hasResult, bool *hasResultType) {" << std::endl; + out << " *hasResult = *hasResultType = false;" << std::endl; + out << " switch (opcode) {" << std::endl; + out << " default: /* unknown opcode */ break;" << std::endl; + + for (auto& inst : spv::InstructionDesc) { + + // Filter out duplicate enum values, which would break the switch statement. + // These are probably just extension enums promoted to core. + if (seenValues.find(inst.value) != seenValues.end()) { + continue; + } + seenValues.insert(inst.value); + + std::string name = inst.name; + out << " case " << fmtEnumUse("Op", name) << ": *hasResult = " << (inst.hasResult() ? "true" : "false") << "; *hasResultType = " << (inst.hasType() ? "true" : "false") << "; break;" << std::endl; + } + + out << " }" << std::endl; + out << "}" << std::endl; + out << "#endif /* SPV_ENABLE_UTILITY_CODE */" << std::endl << std::endl; + } + } }; // C printer @@ -543,19 +587,19 @@ namespace { if (isMask) { const auto typeName = opName + styleStr(enumMask); - + out << "inline " + typeName + " operator|(" + typeName + " a, " + typeName + " b) { return " + typeName + "(unsigned(a) | unsigned(b)); }\n"; } } out << "\n} // end namespace spv\n\n"; - TPrinterCBase::printEpilogue(out); + out << "#endif // #ifndef spirv_" << headerGuardSuffix() << std::endl; } std::string commentBOL() const override { return "// "; } - + virtual std::string enumBeg(const std::string& s, enumStyle_t style) const override { return std::string("enum ") + s + styleStr(style) + " {\n"; } @@ -598,6 +642,9 @@ namespace { return enumFmt(s, v, style, true); } + // Add type prefix for scoped enum + virtual std::string fmtEnumUse(const std::string& opPrefix, const std::string& name) const { return opPrefix + "::" + name; } + std::string headerGuardSuffix() const override { return "HPP"; } }; @@ -695,6 +742,40 @@ namespace { } }; + // D printer + class TPrinterD final : public TPrinter { + private: + std::string commentBeg() const override { return "/+\n"; } + std::string commentBOL() const override { return " + "; } + std::string commentEnd(bool isLast) const override { return " +/\n"; } + + void printPrologue(std::ostream& out) const override { + out << "module spv;\n\n"; + } + + void printEpilogue(std::ostream& out) const override { + } + + std::string enumBeg(const std::string& s, enumStyle_t style) const override { + return "enum " + s + styleStr(style) + " : uint\n{\n"; + } + + std::string enumEnd(const std::string& s, enumStyle_t style, bool isLast) const override { + return std::string("}\n\n"); + } + + std::string enumFmt(const std::string& s, const valpair_t& v, + enumStyle_t style, bool isLast) const override { + return indent() + prependIfDigit("_", v.second) + " = " + fmtStyleVal(v.first, style) + ",\n"; + } + + std::string fmtConstInt(unsigned val, const std::string& name, + const char* fmt, bool isLast) const override { + return std::string("enum uint ") + name + + " = " + fmtNum(fmt, val) + (isLast ? ";\n\n" : ";\n"); + } + }; + } // namespace namespace spv { @@ -710,6 +791,7 @@ namespace spv { langInfo.push_back(std::make_pair(ELangLua, "spirv.lua")); langInfo.push_back(std::make_pair(ELangPython, "spirv.py")); langInfo.push_back(std::make_pair(ELangCSharp, "spirv.cs")); + langInfo.push_back(std::make_pair(ELangD, "spv.d")); for (const auto& lang : langInfo) { std::ofstream out(lang.second, std::ios::out); @@ -736,6 +818,7 @@ namespace spv { case ELangLua: p = TPrinterPtr(new TPrinterLua); break; case ELangPython: p = TPrinterPtr(new TPrinterPython); break; case ELangCSharp: p = TPrinterPtr(new TPrinterCSharp); break; + case ELangD: p = TPrinterPtr(new TPrinterD); break; case ELangAll: PrintAllHeaders(); break; default: std::cerr << "Unknown language." << std::endl; diff --git a/tools/buildHeaders/header.h b/tools/buildHeaders/header.h index 6ab13ce..9c34b21 100755..100644 --- a/tools/buildHeaders/header.h +++ b/tools/buildHeaders/header.h @@ -1,19 +1,19 @@ -// Copyright (c) 2014-2018 The Khronos Group Inc. -// +// Copyright (c) 2014-2019 The Khronos Group Inc. +// // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and/or associated documentation files (the "Materials"), // to deal in the Materials without restriction, including without limitation // the rights to use, copy, modify, merge, publish, distribute, sublicense, // and/or sell copies of the Materials, and to permit persons to whom the // Materials are furnished to do so, subject to the following conditions: -// +// // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Materials. -// +// // MODIFICATIONS TO THIS FILE MAY MEAN IT NO LONGER ACCURATELY REFLECTS KHRONOS // STANDARDS. THE UNMODIFIED, NORMATIVE VERSIONS OF KHRONOS SPECIFICATIONS AND -// HEADER INFORMATION ARE LOCATED AT https://www.khronos.org/registry/ -// +// HEADER INFORMATION ARE LOCATED AT https://www.khronos.org/registry/ +// // THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL @@ -42,6 +42,7 @@ namespace spv { ELangLua, // Lua ELangPython, // Python ELangCSharp, // CSharp + ELangD, // D ELangAll, // print headers in all languages to files }; diff --git a/tools/buildHeaders/jsonToSpirv.cpp b/tools/buildHeaders/jsonToSpirv.cpp index bb32566..5cca0b9 100755..100644 --- a/tools/buildHeaders/jsonToSpirv.cpp +++ b/tools/buildHeaders/jsonToSpirv.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2014-2018 The Khronos Group Inc. +// Copyright (c) 2014-2020 The Khronos Group Inc. // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and/or associated documentation files (the "Materials"), @@ -27,6 +27,7 @@ #include <algorithm> #include <iostream> #include <unordered_map> +#include <unordered_set> #include <utility> #include <fstream> @@ -40,6 +41,10 @@ namespace spv { // parameterization information. InstructionValues InstructionDesc; +// The ordered list (in printing order) of printing classes +// (specification subsections). +PrintingClasses InstructionPrintingClasses; + // Note: There is no entry for OperandOpcode. Use InstructionDesc instead. EnumDefinition OperandClassParams[OperandOpcode]; EnumValues SourceLanguageParams; @@ -72,6 +77,10 @@ EnumValues ScopeParams; EnumValues KernelEnqueueFlagsParams; EnumValues KernelProfilingInfoParams; EnumValues CapabilityParams; +EnumValues RayFlagsParams; +EnumValues RayQueryIntersectionParams; +EnumValues RayQueryCommittedIntersectionTypeParams; +EnumValues RayQueryCandidateIntersectionTypeParams; std::pair<bool, std::string> ReadFile(const std::string& path) { @@ -119,8 +128,7 @@ ClassOptionality ToOperandClassAndOptionality(const std::string& operandKind, co else if (quantifier == "?") return {OperandLiteralString, true}; else { - assert(0 && "this case should not exist"); - return {OperandNone, false}; + return {OperandOptionalLiteralStrings, false}; } } else if (operandKind == "PairLiteralIntegerIdRef") { // Used by OpSwitch in the grammar @@ -142,7 +150,7 @@ ClassOptionality ToOperandClassAndOptionality(const std::string& operandKind, co } else if (operandKind == "LiteralSpecConstantOpInteger") { type = OperandLiteralNumber; } else if (operandKind == "LiteralContextDependentNumber") { - type = OperandVariableLiterals; + type = OperandAnySizeLiteralNumber; } else if (operandKind == "SourceLanguage") { type = OperandSource; } else if (operandKind == "ExecutionModel") { @@ -198,7 +206,15 @@ ClassOptionality ToOperandClassAndOptionality(const std::string& operandKind, co } else if (operandKind == "FunctionControl") { type = OperandFunction; } else if (operandKind == "MemoryAccess") { - type = OperandMemoryAccess; + type = OperandMemoryOperands; + } else if (operandKind == "RayFlags") { + type = OperandRayFlags; + } else if (operandKind == "RayQueryIntersection") { + type = OperandRayQueryIntersection; + } else if (operandKind == "RayQueryCommittedIntersectionType") { + type = OperandRayQueryCommittedIntersectionType; + } else if (operandKind == "RayQueryCandidateIntersectionType") { + type = OperandRayQueryCandidateIntersectionType; } if (type == OperandNone) { @@ -230,7 +246,7 @@ unsigned int NumberStringToBit(const std::string& str) return bit; } -void jsonToSpirv(const std::string& jsonPath) +void jsonToSpirv(const std::string& jsonPath, bool buildingHeaders) { // only do this once. static bool initialized = false; @@ -285,12 +301,40 @@ void jsonToSpirv(const std::string& jsonPath) return result; }; + // set up the printing classes + std::unordered_set<std::string> tags; // short-lived local for error checking below + const Json::Value printingClasses = root["instruction_printing_class"]; + for (const auto& printingClass : printingClasses) { + if (printingClass["tag"].asString().size() > 0) + tags.insert(printingClass["tag"].asString()); // just for error checking + else + std::cerr << "Error: each instruction_printing_class requires a non-empty \"tag\"" << std::endl; + if (buildingHeaders || printingClass["tag"].asString() != "@exclude") { + InstructionPrintingClasses.push_back({printingClass["tag"].asString(), + printingClass["heading"].asString()}); + } + } + + // process the instructions const Json::Value insts = root["instructions"]; for (const auto& inst : insts) { - const unsigned int opcode = inst["opcode"].asUInt(); + const auto printingClass = inst["class"].asString(); + if (printingClass.size() == 0) { + std::cerr << "Error: " << inst["opname"].asString() + << " requires a non-empty printing \"class\" tag" << std::endl; + } + if (!buildingHeaders && printingClass == "@exclude") + continue; + if (tags.find(printingClass) == tags.end()) { + std::cerr << "Error: " << inst["opname"].asString() + << " requires a \"class\" declared as a \"tag\" in \"instruction printing_class\"" + << std::endl; + } + const auto opcode = inst["opcode"].asUInt(); const std::string name = inst["opname"].asString(); EnumCaps caps = getCaps(inst); std::string version = inst["version"].asString(); + std::string lastVersion = inst["lastVersion"].asString(); Extensions exts = getExts(inst); OperandParameters operands; bool defResultId = false; @@ -306,9 +350,9 @@ void jsonToSpirv(const std::string& jsonPath) } InstructionDesc.emplace_back( std::move(EnumValue(opcode, name, - std::move(caps), std::move(version), std::move(exts), + std::move(caps), std::move(version), std::move(lastVersion), std::move(exts), std::move(operands))), - defTypeId, defResultId); + printingClass, defTypeId, defResultId); } // Specific additional context-dependent operands @@ -339,6 +383,7 @@ void jsonToSpirv(const std::string& jsonPath) continue; EnumCaps caps(getCaps(enumerant)); std::string version = enumerant["version"].asString(); + std::string lastVersion = enumerant["lastVersion"].asString(); Extensions exts(getExts(enumerant)); OperandParameters params; const Json::Value& paramsJson = enumerant["parameters"]; @@ -353,7 +398,7 @@ void jsonToSpirv(const std::string& jsonPath) } dest->emplace_back( value, enumerant["enumerant"].asString(), - std::move(caps), std::move(version), std::move(exts), std::move(params)); + std::move(caps), std::move(version), std::move(lastVersion), std::move(exts), std::move(params)); } }; @@ -421,7 +466,7 @@ void jsonToSpirv(const std::string& jsonPath) } else if (enumName == "Dim") { establishOperandClass(enumName, OperandDimensionality, &DimensionalityParams, operandEnum, category); } else if (enumName == "MemoryAccess") { - establishOperandClass(enumName, OperandMemoryAccess, &MemoryAccessParams, operandEnum, category); + establishOperandClass(enumName, OperandMemoryOperands, &MemoryAccessParams, operandEnum, category); } else if (enumName == "Scope") { establishOperandClass(enumName, OperandScope, &ScopeParams, operandEnum, category); } else if (enumName == "GroupOperation") { @@ -430,6 +475,14 @@ void jsonToSpirv(const std::string& jsonPath) establishOperandClass(enumName, OperandKernelEnqueueFlags, &KernelEnqueueFlagsParams, operandEnum, category); } else if (enumName == "KernelProfilingInfo") { establishOperandClass(enumName, OperandKernelProfilingInfo, &KernelProfilingInfoParams, operandEnum, category); + } else if (enumName == "RayFlags") { + establishOperandClass(enumName, OperandRayFlags, &RayFlagsParams, operandEnum, category); + } else if (enumName == "RayQueryIntersection") { + establishOperandClass(enumName, OperandRayQueryIntersection, &RayQueryIntersectionParams, operandEnum, category); + } else if (enumName == "RayQueryCommittedIntersectionType") { + establishOperandClass(enumName, OperandRayQueryCommittedIntersectionType, &RayQueryCommittedIntersectionTypeParams, operandEnum, category); + } else if (enumName == "RayQueryCandidateIntersectionType") { + establishOperandClass(enumName, OperandRayQueryCandidateIntersectionType, &RayQueryCandidateIntersectionTypeParams, operandEnum, category); } } } diff --git a/tools/buildHeaders/jsonToSpirv.h b/tools/buildHeaders/jsonToSpirv.h index 00a2f70..9a5eafd 100755..100644 --- a/tools/buildHeaders/jsonToSpirv.h +++ b/tools/buildHeaders/jsonToSpirv.h @@ -1,4 +1,4 @@ -// Copyright (c) 2014-2018 The Khronos Group Inc. +// Copyright (c) 2014-2020 The Khronos Group Inc. // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and/or associated documentation files (the "Materials"), @@ -38,7 +38,7 @@ namespace spv { std::pair<bool, std::string> ReadFile(const std::string& path); // Fill in all the parameters -void jsonToSpirv(const std::string& jsonPath); +void jsonToSpirv(const std::string& jsonPath, bool buildingHeaders); // For parameterizing operands. enum OperandClass { @@ -47,9 +47,11 @@ enum OperandClass { OperandVariableIds, OperandOptionalLiteral, OperandOptionalLiteralString, + OperandOptionalLiteralStrings, OperandVariableLiterals, OperandVariableIdLiteral, OperandVariableLiteralId, + OperandAnySizeLiteralNumber, OperandLiteralNumber, OperandLiteralString, OperandSource, @@ -76,18 +78,29 @@ enum OperandClass { OperandLoop, OperandFunction, OperandMemorySemantics, - OperandMemoryAccess, + OperandMemoryOperands, OperandScope, OperandGroupOperation, OperandKernelEnqueueFlags, OperandKernelProfilingInfo, OperandCapability, + OperandRayFlags, + OperandRayQueryIntersection, + OperandRayQueryCommittedIntersectionType, + OperandRayQueryCandidateIntersectionType, OperandOpcode, OperandCount }; +// For direct representation of the JSON grammar "instruction_printing_class". +struct PrintingClass { + std::string tag; + std::string heading; +}; +using PrintingClasses = std::vector<PrintingClass>; + // Any specific enum can have a set of capabilities that allow it: typedef std::vector<std::string> EnumCaps; @@ -145,6 +158,12 @@ public: assert((where != end()) && "Could not find enum in the enum list"); return *where; } + // gets *all* entries for the value, including the first one + void gatherAliases(unsigned value, std::vector<EValue*>& aliases) { + std::for_each(begin(), end(), [&](EValue& e) { + if (value == e.value) + aliases.push_back(&e);}); + } // Returns the EValue with the given name. We assume uniqueness // by name. EValue& at(std::string name) { @@ -167,9 +186,11 @@ private: class EnumValue { public: EnumValue() : value(0), desc(nullptr) {} - EnumValue(unsigned int the_value, const std::string& the_name, EnumCaps&& the_caps, const std::string& the_version, - Extensions&& the_extensions, OperandParameters&& the_operands) : - value(the_value), name(the_name), capabilities(std::move(the_caps)), version(std::move(the_version)), + EnumValue(unsigned int the_value, const std::string& the_name, EnumCaps&& the_caps, + const std::string& the_firstVersion, const std::string& the_lastVersion, + Extensions&& the_extensions, OperandParameters&& the_operands) : + value(the_value), name(the_name), capabilities(std::move(the_caps)), + firstVersion(std::move(the_firstVersion)), lastVersion(std::move(the_lastVersion)), extensions(std::move(the_extensions)), operands(std::move(the_operands)), desc(nullptr) { } // For ValueEnum, the value from the JSON file. @@ -178,7 +199,8 @@ public: unsigned value; std::string name; EnumCaps capabilities; - std::string version; + std::string firstVersion; + std::string lastVersion; // A feature only be enabled by certain extensions. // An empty list means the feature does not require an extension. // Normally, only Capability enums are enabled by extension. In turn, @@ -228,28 +250,39 @@ public: // per OperandParameters above. class InstructionValue : public EnumValue { public: - InstructionValue(EnumValue&& e, bool has_type, bool has_result) + InstructionValue(EnumValue&& e, const std::string& printClass, bool has_type, bool has_result) : EnumValue(std::move(e)), + printingClass(printClass), opDesc("TBD"), - opClass(0), typePresent(has_type), - resultPresent(has_result) {} + resultPresent(has_result), + alias(this) { } + InstructionValue(const InstructionValue& v) + { + *this = v; + alias = this; + } bool hasResult() const { return resultPresent != 0; } bool hasType() const { return typePresent != 0; } + void setAlias(const InstructionValue& a) { alias = &a; } + const InstructionValue& getAlias() const { return *alias; } + bool isAlias() const { return alias != this; } + std::string printingClass; const char* opDesc; - int opClass; protected: int typePresent : 1; int resultPresent : 1; + const InstructionValue* alias; // correct only after discovering the aliases; otherwise points to this }; using InstructionValues = EnumValuesContainer<InstructionValue>; // Parameterization info for all instructions. extern InstructionValues InstructionDesc; +extern PrintingClasses InstructionPrintingClasses; // These hold definitions of the enumerants used for operands. // This is indexed by OperandClass, but not including OperandOpcode. diff --git a/tools/buildHeaders/main.cpp b/tools/buildHeaders/main.cpp index e78fd1e..7e5f7f8 100755..100644 --- a/tools/buildHeaders/main.cpp +++ b/tools/buildHeaders/main.cpp @@ -1,19 +1,19 @@ -// Copyright (c) 2014-2018 The Khronos Group Inc. -// +// Copyright (c) 2014-2019 The Khronos Group Inc. +// // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and/or associated documentation files (the "Materials"), // to deal in the Materials without restriction, including without limitation // the rights to use, copy, modify, merge, publish, distribute, sublicense, // and/or sell copies of the Materials, and to permit persons to whom the // Materials are furnished to do so, subject to the following conditions: -// +// // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Materials. -// +// // MODIFICATIONS TO THIS FILE MAY MEAN IT NO LONGER ACCURATELY REFLECTS KHRONOS // STANDARDS. THE UNMODIFIED, NORMATIVE VERSIONS OF KHRONOS SPECIFICATIONS AND -// HEADER INFORMATION ARE LOCATED AT https://www.khronos.org/registry/ -// +// HEADER INFORMATION ARE LOCATED AT https://www.khronos.org/registry/ +// // THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL @@ -51,6 +51,7 @@ void Usage() " Lua - Lua module\n" " Python - Python module (also accepts Py)\n" " C# - C# module (also accepts CSharp)\n" + " D - D module\n" " -H print header in all supported languages to files in current directory\n" ); } @@ -91,9 +92,10 @@ bool ProcessArguments(int argc, char* argv[]) Language = spv::ELangLua; } else if (language == "python" || language == "py") { Language = spv::ELangPython; - } - else if (language == "c#" || language == "csharp") { + } else if (language == "c#" || language == "csharp") { Language = spv::ELangCSharp; + } else if (language == "d") { + Language = spv::ELangD; } else return false; @@ -117,7 +119,7 @@ int main(int argc, char* argv[]) return 1; } - spv::jsonToSpirv(jsonPath); + spv::jsonToSpirv(jsonPath, (Options & EOptionPrintHeader) != 0); if (Options & EOptionPrintHeader) spv::PrintHeader(Language, std::cout); |
