aboutsummaryrefslogtreecommitdiffstats
path: root/tools
diff options
context:
space:
mode:
authorXin Li <delphij@google.com>2020-09-08 16:54:23 -0700
committerXin Li <delphij@google.com>2020-09-08 16:54:23 -0700
commitd2ace5d9f01c137c1fbfccda59934bd7abfb8877 (patch)
treed004085185210205fb3571a3966ba6b2063f42ca /tools
parentfd44500f60ca16d4e9ffede30efb945cab3a7240 (diff)
parent0e46d4adfc6e2e063a16dea71002c74d3c4f56f8 (diff)
downloadplatform_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
Merge Android RHEADmaster
Bug: 168057903 Merged-In: I0eaecb66e1815442d69d3e0c1e8da1d7e7dc8d58 Change-Id: I411b481e88280b4409a461db3c45fb8548d21718
Diffstat (limited to 'tools')
-rw-r--r--[-rwxr-xr-x]tools/buildHeaders/CMakeLists.txt0
-rwxr-xr-xtools/buildHeaders/bin/generate_language_headers.py242
-rwxr-xr-xtools/buildHeaders/bin/makeExtinstHeaders.py27
-rwxr-xr-xtools/buildHeaders/bin/makeHeaders4
-rw-r--r--[-rwxr-xr-x]tools/buildHeaders/header.cpp137
-rw-r--r--[-rwxr-xr-x]tools/buildHeaders/header.h13
-rw-r--r--[-rwxr-xr-x]tools/buildHeaders/jsonToSpirv.cpp75
-rw-r--r--[-rwxr-xr-x]tools/buildHeaders/jsonToSpirv.h55
-rw-r--r--[-rwxr-xr-x]tools/buildHeaders/main.cpp20
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);