Generator word now has two 16-bit components
authorDavid Neto <dneto@google.com>
Thu, 12 Nov 2015 23:33:47 +0000 (18:33 -0500)
committerDavid Neto <dneto@google.com>
Fri, 13 Nov 2015 18:35:29 +0000 (12:35 -0600)
The high 16-bits are a registered generator tool.
These are registered at
https://www.khronos.org/registry/spir-v/api/spir-v.xml

The low 16-bits are tool-specific.  It might be a version number,
for example, but is not constrained by the spec or by the registration
process.

The disassembler prints the tool name when we know it.
If we don't, print "Unknown" and then the numeric tool number
in parentheses.
In all cases, the disassembler prints lower 16-bit number on the
same line but after the tool name.

Also add newly registered generators:
  6: Khronos LLVM/SPIR-V Translator
  7: Khronos SPIR-V Tools Assembler

source/disassemble.cpp
source/opcode.cpp
source/spirv_constant.h
source/text.cpp
test/BinaryToText.cpp
test/ExtInstGLSLstd450.cpp
test/GeneratorMagicNumber.cpp

index 5fccf43..c033aae 100644 (file)
@@ -39,6 +39,7 @@
 #include "libspirv/libspirv.h"
 #include "opcode.h"
 #include "print.h"
+#include "spirv_constant.h"
 #include "util/hex_float.h"
 
 namespace {
@@ -131,9 +132,18 @@ spv_result_t Disassembler::HandleHeader(spv_endianness_t endian,
   endian_ = endian;
 
   SetGrey();
+  const char* generator_tool =
+      spvGeneratorStr(SPV_GENERATOR_TOOL_PART(generator));
   stream_ << "; SPIR-V\n"
           << "; Version: " << version << "\n"
-          << "; Generator: " << spvGeneratorStr(generator) << "\n"
+          << "; Generator: " << generator_tool;
+  // For unknown tools, print the numeric tool value.
+  if (0 == strcmp("Unknown", generator_tool)) {
+    stream_ << "(" << SPV_GENERATOR_TOOL_PART(generator) << ")";
+  }
+  // Print the miscellaneous part of the generator word on the same
+  // line as the tool name.
+  stream_ << "; " << SPV_GENERATOR_MISC_PART(generator) << "\n"
           << "; Bound: " << id_bound << "\n"
           << "; Schema: " << schema << "\n";
   ResetColor();
index c2cab6d..0d1161a 100644 (file)
@@ -298,6 +298,10 @@ const char* spvGeneratorStr(uint32_t generator) {
       return "NVIDIA";
     case SPV_GENERATOR_ARM:
       return "ARM";
+    case SPV_GENERATOR_KHRONOS_LLVM_TRANSLATOR:
+      return "Khronos LLVM/SPIR-V Translator";
+    case SPV_GENERATOR_KHRONOS_ASSEMBLER:
+      return "Khronos SPIR-V Tools Assembler";
     default:
       return "Unknown";
   }
index 64ece27..5795d62 100644 (file)
 
 // Enumerations
 
-// Values mapping to registered vendors.  See the registry at
+// Values mapping to registered tools.  See the registry at
 // https://www.khronos.org/registry/spir-v/api/spir-v.xml
+// These values occupy the higher order 16 bits of the generator magic word.
 typedef enum spv_generator_t {
+  // TODO(dneto) Values 0 through 5 were registered only as vendor.
   SPV_GENERATOR_KHRONOS = 0,
   SPV_GENERATOR_LUNARG = 1,
   SPV_GENERATOR_VALVE = 2,
   SPV_GENERATOR_CODEPLAY = 3,
   SPV_GENERATOR_NVIDIA = 4,
   SPV_GENERATOR_ARM = 5,
-  SPV_FORCE_32_BIT_ENUM(spv_generator_t)
+  // These are vendor and tool.
+  SPV_GENERATOR_KHRONOS_LLVM_TRANSLATOR = 6,
+  SPV_GENERATOR_KHRONOS_ASSEMBLER = 7,
+  SPV_GENERATOR_NUM_ENTRIES,
+  SPV_FORCE_16_BIT_ENUM(spv_generator_t)
 } spv_generator_t;
 
+// Evaluates to a well-formed generator magic word from a tool value and
+// miscellaneous 16-bit value.
+#define SPV_GENERATOR_WORD(TOOL, MISC) \
+  ((uint32_t(uint16_t(TOOL)) << 16) | uint16_t(MISC))
+// Returns the tool component of the generator word.
+#define SPV_GENERATOR_TOOL_PART(WORD) (uint32_t(WORD) >> 16)
+// Returns the misc part of the generator word.
+#define SPV_GENERATOR_MISC_PART(WORD) (uint32_t(WORD) & 0xFFFF)
+
 #endif  // LIBSPIRV_SPIRV_CONSTANT_H_
index bc8fd96..7e706a8 100644 (file)
@@ -652,18 +652,24 @@ spv_result_t spvTextEncodeOpcode(const libspirv::AssemblyGrammar& grammar,
 
 namespace {
 
+enum {
+  kAssemblerVersion = 0
+};
+
 /// @brief Populate a binary stream's words with this generator's header.
 ///
 /// @param[in,out] words the array of words
 /// @param[in] bound the upper ID bound
 ///
 /// @return result code
-spv_result_t SetHeader(uint32_t* words, const uint32_t bound) {
+spv_result_t
+SetHeader(uint32_t* words, const uint32_t bound) {
   if (!words) return SPV_ERROR_INVALID_BINARY;
 
   words[SPV_INDEX_MAGIC_NUMBER] = SpvMagicNumber;
   words[SPV_INDEX_VERSION_NUMBER] = SpvVersion;
-  words[SPV_INDEX_GENERATOR_NUMBER] = SPV_GENERATOR_KHRONOS;
+  words[SPV_INDEX_GENERATOR_NUMBER] =
+      SPV_GENERATOR_WORD(SPV_GENERATOR_KHRONOS_ASSEMBLER, kAssemblerVersion);
   words[SPV_INDEX_BOUND] = bound;
   words[SPV_INDEX_SCHEMA] = 0;  // NOTE: Reserved
 
index 5ca8737..7003cec 100644 (file)
 
 #include "gmock/gmock.h"
 
-#include "TestFixture.h"
 #include "../source/spirv_constant.h"
+#include "TestFixture.h"
 
 using ::testing::Eq;
+using ::testing::HasSubstr;
 using spvtest::AutoText;
 using spvtest::TextToBinaryTest;
 
@@ -394,4 +395,51 @@ OpStore %2 %3 Aligned|Volatile 4 ; bogus, but not indented
       expected);
 }
 
+// Test generator string.
+
+// A test case for the generator string.  This allows us to
+// test both of the 16-bit components of the generator word.
+struct GeneratorStringCase {
+  uint16_t generator;
+  uint16_t misc;
+  std::string expected;
+};
+
+using GeneratorStringTest = spvtest::TextToBinaryTestBase<
+    ::testing::TestWithParam<GeneratorStringCase>>;
+
+TEST_P(GeneratorStringTest, Sample) {
+  auto words = CompileSuccessfully("");
+  EXPECT_EQ(SPV_INDEX_GENERATOR_NUMBER, 2);
+  words[SPV_INDEX_GENERATOR_NUMBER] =
+      SPV_GENERATOR_WORD(GetParam().generator, GetParam().misc);
+
+  spv_text decoded_text = nullptr;
+  spv_diagnostic diagnostic = nullptr;
+  EXPECT_THAT(spvBinaryToText(context, words.data(), words.size(),
+                              SPV_BINARY_TO_TEXT_OPTION_NONE, &decoded_text,
+                              &diagnostic),
+              Eq(SPV_SUCCESS));
+  EXPECT_THAT(diagnostic, Eq(nullptr));
+  EXPECT_THAT(std::string(decoded_text->str), HasSubstr(GetParam().expected));
+  spvTextDestroy(decoded_text);
+}
+
+INSTANTIATE_TEST_CASE_P(GeneratorStrings, GeneratorStringTest,
+                        ::testing::ValuesIn(std::vector<GeneratorStringCase>{
+                            {SPV_GENERATOR_KHRONOS, 12, "Khronos; 12"},
+                            {SPV_GENERATOR_LUNARG, 99, "LunarG; 99"},
+                            {SPV_GENERATOR_VALVE, 1, "Valve; 1"},
+                            {SPV_GENERATOR_CODEPLAY, 65535,
+                             "Codeplay Software Ltd.; 65535"},
+                            {SPV_GENERATOR_NVIDIA, 19, "NVIDIA; 19"},
+                            {SPV_GENERATOR_ARM, 1000, "ARM; 1000"},
+                            {SPV_GENERATOR_KHRONOS_LLVM_TRANSLATOR, 38,
+                             "Khronos LLVM/SPIR-V Translator; 38"},
+                            {SPV_GENERATOR_KHRONOS_ASSEMBLER, 2,
+                             "Khronos SPIR-V Tools Assembler; 2"},
+                            {9, 18, "Unknown(9); 18"},
+                            {65535, 32767, "Unknown(65535); 32767"},
+                        }));
+
 }  // anonymous namespace
index 4a7cb52..dc27a96 100644 (file)
@@ -67,7 +67,7 @@ OpFunctionEnd
   const std::string spirv_header =
       R"(; SPIR-V
 ; Version: 100
-; Generator: Khronos
+; Generator: Khronos SPIR-V Tools Assembler; 0
 ; Bound: 9
 ; Schema: 0)";
   spv_binary binary;
index 80f091a..a298d8d 100644 (file)
@@ -52,13 +52,16 @@ INSTANTIATE_TEST_CASE_P(
         {SPV_GENERATOR_CODEPLAY, "Codeplay Software Ltd."},
         {SPV_GENERATOR_NVIDIA, "NVIDIA"},
         {SPV_GENERATOR_ARM, "ARM"},
+        {SPV_GENERATOR_KHRONOS_LLVM_TRANSLATOR,
+         "Khronos LLVM/SPIR-V Translator"},
+        {SPV_GENERATOR_KHRONOS_ASSEMBLER, "Khronos SPIR-V Tools Assembler"},
     }));
 
 INSTANTIATE_TEST_CASE_P(
     Unregistered, GeneratorMagicNumberTest,
     ::testing::ValuesIn(std::vector<EnumCase<spv_generator_t>>{
         // Currently value 6 and beyond are unregiestered.
-        {spv_generator_t(6), "Unknown"},
+        {spv_generator_t(8), "Unknown"},
         {spv_generator_t(9999), "Unknown"},
     }));
 }  // anonymous namespace