Remove dependency on SPIR-V headers in libspirv.h.
authorLei Zhang <antiagainst@google.com>
Thu, 31 Mar 2016 21:26:31 +0000 (17:26 -0400)
committerLei Zhang <antiagainst@google.com>
Mon, 4 Apr 2016 14:34:28 +0000 (10:34 -0400)
For fulfilling this purpose, the |opcode| field in the
|spv_parsed_instruction_t| struct is changed to of type uint16_t.

Also add functions to query the information of a given SPIR-V
target environment.

31 files changed:
CMakeLists.txt
include/spirv-tools/libspirv.h
source/CMakeLists.txt
source/assembly_grammar.h
source/binary.cpp
source/disassemble.cpp
source/ext_inst.cpp
source/opcode.cpp
source/opcode.h
source/spirv_constant.h
source/spirv_definition.h
source/spirv_target_env.cpp [moved from test/Version.cpp with 57% similarity]
source/table.cpp
source/table.h
source/text.cpp
source/validate.cpp
source/validate_cfg.cpp
source/validate_id.cpp
source/validate_instruction.cpp
source/validate_layout.cpp
source/validate_ssa.cpp
test/BinaryParse.cpp
test/BinaryToText.cpp
test/CMakeLists.txt
test/ExtInst.OpenCL.std.cpp
test/ExtInstGLSLstd450.cpp
test/OpcodeSplit.cpp
test/TextToBinary.Extension.cpp
tools/as/as.cpp
tools/dis/dis.cpp
tools/val/val.cpp

index 161a22e..a2d8eb8 100644 (file)
@@ -159,9 +159,3 @@ add_subdirectory(test)
 
 install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/include/spirv-tools/libspirv.h
   DESTINATION include/spirv-tools/)
-# The installation is broken without these header files from the SPIR-V Registry.
-# The libspirv.h header includes them.
-install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/include/spirv/spirv.h
-              ${CMAKE_CURRENT_SOURCE_DIR}/include/spirv/GLSL.std.450.h
-              ${CMAKE_CURRENT_SOURCE_DIR}/include/spirv/OpenCL.std.h
-  DESTINATION include/spirv/)
index 7de0750..366103e 100644 (file)
 #ifndef SPIRV_TOOLS_LIBSPIRV_H_
 #define SPIRV_TOOLS_LIBSPIRV_H_
 
-#include "spirv/GLSL.std.450.h"
-#include "spirv/OpenCL.std.h"
-#include "spirv/spirv.h"
-
 #ifdef __cplusplus
 extern "C" {
 #else
@@ -40,18 +36,8 @@ extern "C" {
 #include <stddef.h>
 #include <stdint.h>
 
-// Versions
-// This library is based on SPIR-V 1.0 Rev2
-// TODO(dneto): Use the values from the SPIR-V header, when it's updated for
-// SPIR-V 1.0 public release.
-#define SPV_SPIRV_VERSION_MAJOR (SPV_VERSION >> 16)
-#define SPV_SPIRV_VERSION_MINOR (SPV_VERSION & 0xffff)
-#define SPV_SPIRV_VERSION_REVISION (SPV_REVISION)
-
 // Helpers
 
-#define spvIsInBitfield(value, bitfield) ((value) == ((value)&bitfield))
-
 #define SPV_BIT(shift) (1 << (shift))
 
 #define SPV_FORCE_16_BIT_ENUM(name) _##name = 0x7fff
@@ -287,7 +273,7 @@ typedef struct spv_parsed_instruction_t {
   const uint32_t* words;
   // The number of words in this instruction.
   uint16_t num_words;
-  SpvOp opcode;
+  uint16_t opcode;
   // The extended instruction type, if opcode is OpExtInst.  Otherwise
   // this is the "none" value.
   spv_ext_inst_type_t ext_inst_type;
@@ -353,6 +339,9 @@ typedef enum {
   SPV_ENV_VULKAN_1_0_7      // Vulkan 1.0 revision 7.
 } spv_target_env;
 
+// Returns a string describing the given SPIR-V target environment.
+const char* spvTargetEnvDescription(spv_target_env env);
+
 // Creates a context object.  Returns null if env is invalid.
 spv_context spvContextCreate(spv_target_env env);
 
index 25026bf..e3b14a7 100644 (file)
@@ -29,6 +29,7 @@ set(SPIRV_SOURCES
   ${spirv-tools_SOURCE_DIR}/include/spirv/spirv.h
   ${spirv-tools_SOURCE_DIR}/include/spirv/GLSL.std.450.h
   ${spirv-tools_SOURCE_DIR}/include/spirv/OpenCL.std.h
+
   ${CMAKE_CURRENT_SOURCE_DIR}/util/bitutils.h
   ${CMAKE_CURRENT_SOURCE_DIR}/util/hex_float.h
   ${CMAKE_CURRENT_SOURCE_DIR}/assembly_grammar.h
@@ -46,16 +47,18 @@ set(SPIRV_SOURCES
   ${CMAKE_CURRENT_SOURCE_DIR}/text.h
   ${CMAKE_CURRENT_SOURCE_DIR}/text_handler.h
   ${CMAKE_CURRENT_SOURCE_DIR}/validate.h
+
   ${CMAKE_CURRENT_SOURCE_DIR}/assembly_grammar.cpp
   ${CMAKE_CURRENT_SOURCE_DIR}/binary.cpp
-  ${CMAKE_CURRENT_SOURCE_DIR}/disassemble.cpp
   ${CMAKE_CURRENT_SOURCE_DIR}/diagnostic.cpp
+  ${CMAKE_CURRENT_SOURCE_DIR}/disassemble.cpp
   ${CMAKE_CURRENT_SOURCE_DIR}/ext_inst.cpp
   ${CMAKE_CURRENT_SOURCE_DIR}/instruction.cpp
   ${CMAKE_CURRENT_SOURCE_DIR}/opcode.cpp
   ${CMAKE_CURRENT_SOURCE_DIR}/operand.cpp
   ${CMAKE_CURRENT_SOURCE_DIR}/print.cpp
   ${CMAKE_CURRENT_SOURCE_DIR}/spirv_endian.cpp
+  ${CMAKE_CURRENT_SOURCE_DIR}/spirv_target_env.cpp
   ${CMAKE_CURRENT_SOURCE_DIR}/table.cpp
   ${CMAKE_CURRENT_SOURCE_DIR}/text.cpp
   ${CMAKE_CURRENT_SOURCE_DIR}/text_handler.cpp
index 3364f71..56ff226 100644 (file)
@@ -29,6 +29,7 @@
 
 #include "operand.h"
 #include "spirv-tools/libspirv.h"
+#include "spirv/spirv.h"
 #include "table.h"
 
 namespace libspirv {
@@ -38,13 +39,17 @@ namespace libspirv {
 class AssemblyGrammar {
  public:
   explicit AssemblyGrammar(const spv_const_context context)
-      : operandTable_(context->operand_table),
+      : target_env_(context->target_env),
+        operandTable_(context->operand_table),
         opcodeTable_(context->opcode_table),
         extInstTable_(context->ext_inst_table) {}
 
   // Returns true if the internal tables have been initialized with valid data.
   bool isValid() const;
 
+  // Returns the SPIR-V target environment.
+  spv_target_env target_env() const { return target_env_; }
+
   // Fills in the desc parameter with the information about the opcode
   // of the given name. Returns SPV_SUCCESS if the opcode was found, and
   // SPV_ERROR_INVALID_LOOKUP if the opcode does not exist.
@@ -115,6 +120,7 @@ class AssemblyGrammar {
                                   spv_operand_pattern_t* pattern) const;
 
  private:
+  const spv_target_env target_env_;
   const spv_operand_table operandTable_;
   const spv_opcode_table opcodeTable_;
   const spv_ext_inst_table extInstTable_;
index 281038f..b3cdc33 100644 (file)
@@ -300,8 +300,8 @@ spv_result_t Parser::parseInstruction() {
                         << inst_word_count;
   }
   spv_opcode_desc opcode_desc;
-  if (grammar_.lookupOpcode(inst.opcode, &opcode_desc))
-    return diagnostic() << "Invalid opcode: " << int(inst.opcode);
+  if (grammar_.lookupOpcode(static_cast<SpvOp>(inst.opcode), &opcode_desc))
+    return diagnostic() << "Invalid opcode: " << inst.opcode;
 
   // Advance past the opcode word.  But remember the of the start
   // of the instruction.
@@ -397,6 +397,7 @@ spv_result_t Parser::parseOperand(size_t inst_offset,
                                   std::vector<uint32_t>* words,
                                   std::vector<spv_parsed_operand_t>* operands,
                                   spv_operand_pattern_t* expected_operands) {
+  const SpvOp opcode = static_cast<SpvOp>(inst->opcode);
   // We'll fill in this result as we go along.
   spv_parsed_operand_t parsed_operand;
   parsed_operand.offset = uint16_t(_.word_index - inst_offset);
@@ -414,7 +415,7 @@ spv_result_t Parser::parseOperand(size_t inst_offset,
   parsed_operand.number_bit_width = 0;
 
   if (_.word_index >= _.num_words)
-    return exhaustedInputDiagnostic(inst_offset, inst->opcode, type);
+    return exhaustedInputDiagnostic(inst_offset, opcode, type);
 
   const uint32_t word = peek();
 
@@ -442,9 +443,8 @@ spv_result_t Parser::parseOperand(size_t inst_offset,
       // A regular value maps to its type.  Some instructions (e.g. OpLabel)
       // have no type Id, and will map to 0.  The result Id for a
       // type-generating instruction (e.g. OpTypeInt) maps to itself.
-      _.id_to_type_id[inst->result_id] = spvOpcodeGeneratesType(inst->opcode)
-                                             ? inst->result_id
-                                             : inst->type_id;
+      _.id_to_type_id[inst->result_id] =
+          spvOpcodeGeneratesType(opcode) ? inst->result_id : inst->type_id;
       break;
 
     case SPV_OPERAND_TYPE_ID:
@@ -452,7 +452,7 @@ spv_result_t Parser::parseOperand(size_t inst_offset,
       if (!word) return diagnostic(SPV_ERROR_INVALID_ID) << "Id is 0";
       parsed_operand.type = SPV_OPERAND_TYPE_ID;
 
-      if (inst->opcode == SpvOpExtInst && parsed_operand.offset == 3) {
+      if (opcode == SpvOpExtInst && parsed_operand.offset == 3) {
         // The current word is the extended instruction set Id.
         // Set the extended instruction set type for the current instruction.
         auto ext_inst_type_iter = _.import_id_to_ext_inst_type.find(word);
@@ -473,7 +473,7 @@ spv_result_t Parser::parseOperand(size_t inst_offset,
       break;
 
     case SPV_OPERAND_TYPE_EXTENSION_INSTRUCTION_NUMBER: {
-      assert(SpvOpExtInst == inst->opcode);
+      assert(SpvOpExtInst == opcode);
       assert(inst->ext_inst_type != SPV_EXT_INST_TYPE_NONE);
       spv_ext_inst_desc ext_inst;
       if (grammar_.lookupExtInst(inst->ext_inst_type, word, &ext_inst))
@@ -482,7 +482,7 @@ spv_result_t Parser::parseOperand(size_t inst_offset,
     } break;
 
     case SPV_OPERAND_TYPE_SPEC_CONSTANT_OP_NUMBER: {
-      assert(SpvOpSpecConstantOp == inst->opcode);
+      assert(SpvOpSpecConstantOp == opcode);
       if (grammar_.lookupSpecConstantOpcode(SpvOp(word))) {
         return diagnostic() << "Invalid " << spvOperandTypeStr(type) << ": "
                             << word;
@@ -514,7 +514,7 @@ spv_result_t Parser::parseOperand(size_t inst_offset,
     case SPV_OPERAND_TYPE_TYPED_LITERAL_NUMBER:
     case SPV_OPERAND_TYPE_OPTIONAL_TYPED_LITERAL_INTEGER:
       parsed_operand.type = SPV_OPERAND_TYPE_TYPED_LITERAL_NUMBER;
-      if (inst->opcode == SpvOpSwitch) {
+      if (opcode == SpvOpSwitch) {
         // The literal operands have the same type as the value
         // referenced by the selector Id.
         const uint32_t selector_id = peekAt(inst_offset + 1);
@@ -540,8 +540,7 @@ spv_result_t Parser::parseOperand(size_t inst_offset,
                               << " is not a scalar integer";
         }
       } else {
-        assert(inst->opcode == SpvOpConstant ||
-               inst->opcode == SpvOpSpecConstant);
+        assert(opcode == SpvOpConstant || opcode == SpvOpSpecConstant);
         // The literal number type is determined by the type Id for the
         // constant.
         assert(inst->type_id);
@@ -565,7 +564,7 @@ spv_result_t Parser::parseOperand(size_t inst_offset,
       // If there was no terminating null byte, then that's an end-of-input
       // error.
       if (string_num_content_bytes == remaining_input_bytes)
-        return exhaustedInputDiagnostic(inst_offset, inst->opcode, type);
+        return exhaustedInputDiagnostic(inst_offset, opcode, type);
       // Account for null in the word length, so add 1 for null, then add 3 to
       // make sure we round up.  The following is equivalent to:
       //    (string_num_content_bytes + 1 + 3) / 4
@@ -582,7 +581,7 @@ spv_result_t Parser::parseOperand(size_t inst_offset,
       parsed_operand.num_words = uint16_t(string_num_words);
       parsed_operand.type = SPV_OPERAND_TYPE_LITERAL_STRING;
 
-      if (SpvOpExtInstImport == inst->opcode) {
+      if (SpvOpExtInstImport == opcode) {
         // Record the extended instruction type for the ID for this import.
         // There is only one string literal argument to OpExtInstImport,
         // so it's sufficient to guard this just on the opcode.
@@ -696,7 +695,7 @@ spv_result_t Parser::parseOperand(size_t inst_offset,
   // handled earlier.)  For example, this error can occur for a multi-word
   // argument to OpConstant, or a multi-word case literal operand for OpSwitch.
   if (_.num_words < index_after_operand)
-    return exhaustedInputDiagnostic(inst_offset, inst->opcode, type);
+    return exhaustedInputDiagnostic(inst_offset, opcode, type);
 
   if (_.requires_endian_conversion) {
     // Copy instruction words.  Translate to native endianness as needed.
@@ -742,13 +741,14 @@ spv_result_t Parser::setNumericTypeInfoForType(
 
 void Parser::recordNumberType(size_t inst_offset,
                               const spv_parsed_instruction_t* inst) {
-  if (spvOpcodeGeneratesType(inst->opcode)) {
+  const SpvOp opcode = static_cast<SpvOp>(inst->opcode);
+  if (spvOpcodeGeneratesType(opcode)) {
     NumberType info = {SPV_NUMBER_NONE, 0};
-    if (SpvOpTypeInt == inst->opcode) {
+    if (SpvOpTypeInt == opcode) {
       const bool is_signed = peekAt(inst_offset + 3) != 0;
       info.type = is_signed ? SPV_NUMBER_SIGNED_INT : SPV_NUMBER_UNSIGNED_INT;
       info.bit_width = peekAt(inst_offset + 2);
-    } else if (SpvOpTypeFloat == inst->opcode) {
+    } else if (SpvOpTypeFloat == opcode) {
       info.type = SPV_NUMBER_FLOATING;
       info.bit_width = peekAt(inst_offset + 2);
     }
index 9fae7e5..53e07cb 100644 (file)
@@ -182,7 +182,7 @@ spv_result_t Disassembler::HandleInstruction(
     stream_ << std::string(indent_, ' ');
   }
 
-  stream_ << "Op" << spvOpcodeString(inst.opcode);
+  stream_ << "Op" << spvOpcodeString(static_cast<SpvOp>(inst.opcode));
 
   for (uint16_t i = 0; i < inst.num_operands; i++) {
     const spv_operand_type_t type = inst.operands[i].type;
index 7ae384e..67366de 100644 (file)
 
 #include <string.h>
 
+#include "spirv/GLSL.std.450.h"
+#include "spirv/OpenCL.std.h"
 #include "spirv_definition.h"
 
 /// Generate a spv_ext_inst_desc_t literal for a GLSL std450 extended
 /// instruction with one/two/three <id> parameter(s).
 #define GLSL450Inst1(name) \
   #name, GLSLstd450::GLSLstd450##name, 0, { SPV_OPERAND_TYPE_ID }
-#define GLSL450Inst1Cap(name, cap)                        \
-  #name, GLSLstd450::GLSLstd450##name,                    \
-          SPV_CAPABILITY_AS_MASK(SpvCapability##cap), { \
-    SPV_OPERAND_TYPE_ID                                   \
+#define GLSL450Inst1Cap(name, cap)                  \
+  #name, GLSLstd450::GLSLstd450##name,              \
+      SPV_CAPABILITY_AS_MASK(SpvCapability##cap), { \
+    SPV_OPERAND_TYPE_ID                             \
   }
 #define GLSL450Inst2(name)                   \
   #name, GLSLstd450::GLSLstd450##name, 0, {  \
@@ -138,9 +140,7 @@ static const spv_ext_inst_desc_t glslStd450Entries[] = {
 };
 
 static const spv_ext_inst_desc_t openclEntries[] = {
-#define ExtInst(Name, Opcode, OperandList) \
-  { #Name, Opcode, 0, OperandList }           \
-  ,
+#define ExtInst(Name, Opcode, OperandList) {#Name, Opcode, 0, OperandList},
 #define EmptyList \
   {}
 #define List(...) \
index fda3ff0..8749618 100644 (file)
@@ -82,12 +82,13 @@ uint32_t spvOpcodeMake(uint16_t wordCount, SpvOp opcode) {
   return ((uint32_t)opcode) | (((uint32_t)wordCount) << 16);
 }
 
-void spvOpcodeSplit(const uint32_t word, uint16_t* pWordCount, SpvOp* pOpcode) {
+void spvOpcodeSplit(const uint32_t word, uint16_t* pWordCount,
+                    uint16_t* pOpcode) {
   if (pWordCount) {
     *pWordCount = (uint16_t)((0xffff0000 & word) >> 16);
   }
   if (pOpcode) {
-    *pOpcode = (SpvOp)(0x0000ffff & word);
+    *pOpcode = 0x0000ffff & word;
   }
 }
 
@@ -162,10 +163,10 @@ void spvInstructionCopy(const uint32_t* words, const SpvOp opcode,
     pInst->words[wordIndex] = spvFixWord(words[wordIndex], endian);
     if (!wordIndex) {
       uint16_t thisWordCount;
-      SpvOp thisOpcode;
+      uint16_t thisOpcode;
       spvOpcodeSplit(pInst->words[wordIndex], &thisWordCount, &thisOpcode);
-      assert(opcode == thisOpcode && wordCount == thisWordCount &&
-             "Endianness failed!");
+      assert(opcode == static_cast<SpvOp>(thisOpcode) &&
+             wordCount == thisWordCount && "Endianness failed!");
     }
   }
 }
index 786c1f4..737af8c 100644 (file)
@@ -29,6 +29,7 @@
 
 #include "instruction.h"
 #include "spirv-tools/libspirv.h"
+#include "spirv/spirv.h"
 #include "table.h"
 
 // Returns the name of a registered SPIR-V generator as a null-terminated
@@ -43,7 +44,8 @@ const char* spvGeneratorStr(uint32_t generator);
 uint32_t spvOpcodeMake(uint16_t word_count, SpvOp opcode);
 
 // Splits word into into two constituent parts: word_count and opcode.
-void spvOpcodeSplit(const uint32_t word, uint16_t* word_count, SpvOp* opcode);
+void spvOpcodeSplit(const uint32_t word, uint16_t* word_count,
+                    uint16_t* opcode);
 
 // Finds the named opcode in the given opcode table. On success, returns
 // SPV_SUCCESS and writes a handle of the table entry into *entry.
index 3ade7cc..a53ce0d 100644 (file)
@@ -28,6 +28,7 @@
 #define LIBSPIRV_SPIRV_CONSTANT_H_
 
 #include "spirv-tools/libspirv.h"
+#include "spirv/spirv.h"
 
 // Version number macros.
 
@@ -40,6 +41,9 @@
 // Returns the minor version extracted from a version header word.
 #define SPV_SPIRV_VERSION_MINOR_PART(WORD) ((uint32_t(WORD) >> 8) & 0xff)
 
+// Returns the version number for the given SPIR-V target environment.
+uint32_t spvVersionForTargetEnv(spv_target_env env);
+
 // Header indices
 
 #define SPV_INDEX_MAGIC_NUMBER 0u
index 65d2d54..088ae96 100644 (file)
@@ -31,6 +31,8 @@
 
 #include "spirv-tools/libspirv.h"
 
+#define spvIsInBitfield(value, bitfield) ((value) == ((value)&bitfield))
+
 // A bit mask representing a set of capabilities.
 // Currently there are 57 distinct capabilities, so 64 bits
 // should be enough.
similarity index 57%
rename from test/Version.cpp
rename to source/spirv_target_env.cpp
index 23ac42c..3edacbe 100644 (file)
@@ -1,4 +1,4 @@
-// Copyright 2016 Google Inc. All Rights Reserved.
+// Copyright (c) 2015-2016 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
 // TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
 // MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
 
-#include "gmock/gmock.h"
+#include <assert.h>
 
-#include "UnitSPIRV.h"
+#include "spirv-tools/libspirv.h"
+#include "spirv_constant.h"
 
-namespace {
-
-TEST(LibspirvMacros, Version) {
-  EXPECT_EQ(1, SPV_SPIRV_VERSION_MAJOR);
-  EXPECT_EQ(0, SPV_SPIRV_VERSION_MINOR);
-  EXPECT_EQ(3, SPV_SPIRV_VERSION_REVISION);
+const char* spvTargetEnvDescription(spv_target_env env) {
+  switch (env) {
+    case SPV_ENV_UNIVERSAL_1_0:
+      return "SPIR-V 1.0";
+    case SPV_ENV_UNIVERSAL_1_0_4:
+      return "SPIR-V 1.0 rev 4";
+    case SPV_ENV_VULKAN_1_0:
+      return "SPIR-V 1.0 (under Vulkan 1.0 semantics)";
+    case SPV_ENV_VULKAN_1_0_7:
+      return "SPIR-V 1.0 (under Vulkan 1.0.7 semantics)";
+    default:
+      break;
+  }
+  assert(0 && "Unhandled SPIR-V target environment");
+  return "";
 }
 
-}  // anonymous namespace
+uint32_t spvVersionForTargetEnv(spv_target_env env) {
+  switch (env) {
+    case SPV_ENV_UNIVERSAL_1_0:
+    case SPV_ENV_UNIVERSAL_1_0_4:
+    case SPV_ENV_VULKAN_1_0:
+    case SPV_ENV_VULKAN_1_0_7:
+      return SPV_SPIRV_VERSION_WORD(1, 0);
+    default:
+      break;
+  }
+  assert(0 && "Unhandled SPIR-V target environment");
+  return SPV_SPIRV_VERSION_WORD(0, 0);
+}
index 4e728e3..10de1e0 100644 (file)
@@ -47,7 +47,7 @@ spv_context spvContextCreate(spv_target_env env) {
   spvOperandTableGet(&operand_table);
   spvExtInstTableGet(&ext_inst_table);
 
-  return new spv_context_t{opcode_table, operand_table, ext_inst_table};
+  return new spv_context_t{env, opcode_table, operand_table, ext_inst_table};
 }
 
 void spvContextDestroy(spv_context context) { delete context; }
index 4e881b9..93270df 100644 (file)
@@ -28,6 +28,7 @@
 #define LIBSPIRV_TABLE_H_
 
 #include "spirv-tools/libspirv.h"
+#include "spirv/spirv.h"
 #include "spirv_definition.h"
 
 typedef struct spv_opcode_desc_t {
@@ -96,6 +97,7 @@ typedef const spv_operand_table_t* spv_operand_table;
 typedef const spv_ext_inst_table_t* spv_ext_inst_table;
 
 struct spv_context_t {
+  const spv_target_env target_env;
   const spv_opcode_table opcode_table;
   const spv_operand_table operand_table;
   const spv_ext_inst_table ext_inst_table;
index ee90689..7d1d756 100644 (file)
@@ -653,22 +653,18 @@ spv_result_t spvTextEncodeOpcode(const libspirv::AssemblyGrammar& grammar,
 
 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) {
-  if (!words) return SPV_ERROR_INVALID_BINARY;
-
-  words[SPV_INDEX_MAGIC_NUMBER] = SpvMagicNumber;
-  words[SPV_INDEX_VERSION_NUMBER] =
-      SPV_SPIRV_VERSION_WORD(SPV_SPIRV_VERSION_MAJOR, SPV_SPIRV_VERSION_MINOR);
-  words[SPV_INDEX_GENERATOR_NUMBER] =
+// Populates a binary stream's |header|. The target environment is specified via
+// |env| and Id bound is via |bound|.
+spv_result_t SetHeader(spv_target_env env, const uint32_t bound,
+                       uint32_t* header) {
+  if (!header) return SPV_ERROR_INVALID_BINARY;
+
+  header[SPV_INDEX_MAGIC_NUMBER] = SpvMagicNumber;
+  header[SPV_INDEX_VERSION_NUMBER] = spvVersionForTargetEnv(env);
+  header[SPV_INDEX_GENERATOR_NUMBER] =
       SPV_GENERATOR_WORD(SPV_GENERATOR_KHRONOS_ASSEMBLER, kAssemblerVersion);
-  words[SPV_INDEX_BOUND] = bound;
-  words[SPV_INDEX_SCHEMA] = 0;  // NOTE: Reserved
+  header[SPV_INDEX_BOUND] = bound;
+  header[SPV_INDEX_SCHEMA] = 0;  // NOTE: Reserved
 
   return SPV_SUCCESS;
 }
@@ -721,7 +717,8 @@ spv_result_t spvTextToBinaryInternal(const libspirv::AssemblyGrammar& grammar,
     currentIndex += inst.words.size();
   }
 
-  if (auto error = SetHeader(data, context.getBound())) return error;
+  if (auto error = SetHeader(grammar.target_env(), context.getBound(), data))
+    return error;
 
   spv_binary binary = new spv_binary_t();
   if (!binary) {
index e706541..ab4de21 100644 (file)
@@ -128,7 +128,7 @@ void DebugInstructionPass(ValidationState_t& _,
 void ProcessIds(ValidationState_t& _, const spv_parsed_instruction_t& inst) {
   if (inst.result_id) {
     _.usedefs().AddDef(
-        {inst.result_id, inst.type_id, inst.opcode,
+        {inst.result_id, inst.type_id, static_cast<SpvOp>(inst.opcode),
          std::vector<uint32_t>(inst.words, inst.words + inst.num_words)});
   }
   for (auto op = inst.operands; op != inst.operands + inst.num_operands; ++op) {
@@ -140,7 +140,7 @@ spv_result_t ProcessInstruction(void* user_data,
                                 const spv_parsed_instruction_t* inst) {
   ValidationState_t& _ = *(reinterpret_cast<ValidationState_t*>(user_data));
   _.incrementInstructionCount();
-  if (inst->opcode == SpvOpEntryPoint)
+  if (static_cast<SpvOp>(inst->opcode) == SpvOpEntryPoint)
     _.entry_points().push_back(inst->words[2]);
 
   DebugInstructionPass(_, inst);
@@ -203,11 +203,12 @@ spv_result_t spvValidate(const spv_const_context context,
   uint64_t index = SPV_INDEX_INSTRUCTION;
   while (index < binary->wordCount) {
     uint16_t wordCount;
-    SpvOp opcode;
+    uint16_t opcode;
     spvOpcodeSplit(spvFixWord(binary->code[index], endian), &wordCount,
                    &opcode);
     spv_instruction_t inst;
-    spvInstructionCopy(&binary->code[index], opcode, wordCount, endian, &inst);
+    spvInstructionCopy(&binary->code[index], static_cast<SpvOp>(opcode),
+                       wordCount, endian, &inst);
     instructions.push_back(inst);
     index += wordCount;
   }
index 50dc2b6..0f8e980 100644 (file)
@@ -33,25 +33,24 @@ namespace libspirv {
 spv_result_t CfgPass(ValidationState_t& _,
                      const spv_parsed_instruction_t* inst) {
   if (_.getLayoutSection() == kLayoutFunctionDefinitions) {
-    SpvOp opcode = inst->opcode;
+    SpvOp opcode = static_cast<SpvOp>(inst->opcode);
     switch (opcode) {
-    case SpvOpLabel:
-      spvCheckReturn(_.get_functions().RegisterBlock(inst->result_id));
-      break;
-    case SpvOpBranch:
-    case SpvOpBranchConditional:
-    case SpvOpSwitch:
-    case SpvOpKill:
-    case SpvOpReturn:
-    case SpvOpReturnValue:
-    case SpvOpUnreachable:
-      spvCheckReturn(_.get_functions().RegisterBlockEnd());
-      break;
-    default:
-      break;
+      case SpvOpLabel:
+        spvCheckReturn(_.get_functions().RegisterBlock(inst->result_id));
+        break;
+      case SpvOpBranch:
+      case SpvOpBranchConditional:
+      case SpvOpSwitch:
+      case SpvOpKill:
+      case SpvOpReturn:
+      case SpvOpReturnValue:
+      case SpvOpUnreachable:
+        spvCheckReturn(_.get_functions().RegisterBlockEnd());
+        break;
+      default:
+        break;
     }
   }
   return SPV_SUCCESS;
 }
-
 }
index 513f257..f963cdc 100644 (file)
@@ -618,10 +618,10 @@ bool idUsage::isValid<SpvOpConstantSampler>(const spv_instruction_t* inst,
 // nullability transitively.
 bool IsTypeNullable(const std::vector<uint32_t>& instruction,
                     const UseDefTracker& usedefs) {
-  SpvOp opcode;
+  uint16_t opcode;
   uint16_t word_count;
   spvOpcodeSplit(instruction[0], &word_count, &opcode);
-  switch (opcode) {
+  switch (static_cast<SpvOp>(opcode)) {
     case SpvOpTypeBool:
     case SpvOpTypeInt:
     case SpvOpTypeFloat:
index 87e1998..8ecb715 100644 (file)
@@ -83,10 +83,11 @@ namespace libspirv {
 spv_result_t CapCheck(ValidationState_t& _,
                       const spv_parsed_instruction_t* inst) {
   spv_opcode_desc opcode_desc;
-  if (SPV_SUCCESS == _.grammar().lookupOpcode(inst->opcode, &opcode_desc) &&
+  const SpvOp opcode = static_cast<SpvOp>(inst->opcode);
+  if (SPV_SUCCESS == _.grammar().lookupOpcode(opcode, &opcode_desc) &&
       !_.HasAnyOf(opcode_desc->capabilities))
     return _.diag(SPV_ERROR_INVALID_CAPABILITY)
-           << "Opcode " << spvOpcodeString(inst->opcode)
+           << "Opcode " << spvOpcodeString(opcode)
            << " requires one of these capabilities: "
            << ToString(opcode_desc->capabilities, _.grammar());
   for (int i = 0; i < inst->num_operands; ++i) {
@@ -99,7 +100,7 @@ spv_result_t CapCheck(ValidationState_t& _,
           const auto caps =
               RequiredCapabilities(_.grammar(), operand.type, mask_bit);
           if (!_.HasAnyOf(caps)) {
-            return CapabilityError(_, i + 1, inst->opcode,
+            return CapabilityError(_, i + 1, opcode,
                                    ToString(caps, _.grammar()));
           }
         }
@@ -108,8 +109,7 @@ spv_result_t CapCheck(ValidationState_t& _,
       // Check the operand word as a whole.
       const auto caps = RequiredCapabilities(_.grammar(), operand.type, word);
       if (!_.HasAnyOf(caps)) {
-        return CapabilityError(_, i + 1, inst->opcode,
-                               ToString(caps, _.grammar()));
+        return CapabilityError(_, i + 1, opcode, ToString(caps, _.grammar()));
       }
     }
   }
@@ -118,10 +118,11 @@ spv_result_t CapCheck(ValidationState_t& _,
 
 spv_result_t InstructionPass(ValidationState_t& _,
                              const spv_parsed_instruction_t* inst) {
-  if (inst->opcode == SpvOpCapability)
+  const SpvOp opcode = static_cast<SpvOp>(inst->opcode);
+  if (opcode == SpvOpCapability)
     _.registerCapability(
         static_cast<SpvCapability>(inst->words[inst->operands[0].offset]));
-  if (inst->opcode == SpvOpVariable) {
+  if (opcode == SpvOpVariable) {
     const auto storage_class =
         static_cast<SpvStorageClass>(inst->words[inst->operands[2].offset]);
     if (storage_class == SpvStorageClassGeneric)
index 38f4d8b..2bb6db2 100644 (file)
@@ -182,7 +182,7 @@ namespace libspirv {
 // Performs logical layout validation. See Section 2.4
 spv_result_t ModuleLayoutPass(ValidationState_t& _,
                               const spv_parsed_instruction_t* inst) {
-  SpvOp opcode = inst->opcode;
+  const SpvOp opcode = static_cast<SpvOp>(inst->opcode);
 
   switch (_.getLayoutSection()) {
     case kLayoutCapabilities:
index 75cbddc..38250bf 100644 (file)
@@ -99,7 +99,7 @@ namespace libspirv {
 spv_result_t SsaPass(ValidationState_t& _,
                      const spv_parsed_instruction_t* inst) {
   auto can_have_forward_declared_ids =
-      getCanBeForwardDeclaredFunction(inst->opcode);
+      getCanBeForwardDeclaredFunction(static_cast<SpvOp>(inst->opcode));
 
   for (unsigned i = 0; i < inst->num_operands; i++) {
     const spv_parsed_operand_t& operand = inst->operands[i];
index d6df8e7..9cd5bc9 100644 (file)
 #include <string>
 #include <vector>
 
-#include "gmock/gmock.h"
-
 #include "TestFixture.h"
 #include "UnitSPIRV.h"
+#include "gmock/gmock.h"
+#include "spirv/OpenCL.std.h"
 
 // Returns true if two spv_parsed_operand_t values are equal.
 // To use this operator, this definition must appear in the same namespace
@@ -60,7 +60,7 @@ using ::testing::_;
 struct ParsedInstruction {
   explicit ParsedInstruction(const spv_parsed_instruction_t& inst)
       : words(inst.words, inst.words + inst.num_words),
-        opcode(inst.opcode),
+        opcode(static_cast<SpvOp>(inst.opcode)),
         ext_inst_type(inst.ext_inst_type),
         type_id(inst.type_id),
         result_id(inst.result_id),
@@ -463,7 +463,7 @@ INSTANTIATE_TEST_CASE_P(
          "Module has incomplete header: only 3 words instead of 5"},
         {kHeaderForBound1, 4,
          "Module has incomplete header: only 4 words instead of 5"},
-    }),);
+    }), );
 
 // A binary parser diagnostic test case where a vector of words is
 // provided.  We'll use this to express cases that can't be created
@@ -696,7 +696,7 @@ INSTANTIATE_TEST_CASE_P(
              MakeInstruction(SpvOpConstant, {1, 2, 42}),
          }),
          "Type Id 1 is not a scalar numeric type"},
-    }),);
+    }), );
 
 // A binary parser diagnostic case generated from an assembly text input.
 struct AssemblyDiagnosticCase {
@@ -766,6 +766,6 @@ INSTANTIATE_TEST_CASE_P(
          "Invalid image operand: 511 has invalid mask component 256"},
         {"OpSelectionMerge %1 !7",
          "Invalid selection control operand: 7 has invalid mask component 4"},
-    }),);
+    }), );
 
 }  // anonymous namespace
index 8503705..bfb8887 100644 (file)
@@ -421,8 +421,6 @@ TEST_F(TextToBinaryTest, VersionString) {
               Eq(SPV_SUCCESS));
   EXPECT_EQ(nullptr, diagnostic);
 
-  EXPECT_EQ(1, SPV_SPIRV_VERSION_MAJOR);
-  EXPECT_EQ(0, SPV_SPIRV_VERSION_MINOR);
   EXPECT_THAT(decoded_text->str, HasSubstr("Version: 1.0\n"))
       << EncodeAndDecodeSuccessfully("");
   spvTextDestroy(decoded_text);
index 481f6ca..078febd 100644 (file)
@@ -88,7 +88,6 @@ if (NOT ${SPIRV_SKIP_EXECUTABLES})
       ${CMAKE_CURRENT_SOURCE_DIR}/Validate.SSA.cpp
       ${CMAKE_CURRENT_SOURCE_DIR}/ValidateID.cpp
       ${CMAKE_CURRENT_SOURCE_DIR}/ValidationState.cpp
-      ${CMAKE_CURRENT_SOURCE_DIR}/Version.cpp
       ${CMAKE_CURRENT_SOURCE_DIR}/main.cpp)
 
     add_executable(UnitSPIRV ${TEST_SOURCES})
index 8b9556e..1140678 100644 (file)
@@ -28,6 +28,7 @@
 
 #include <gmock/gmock.h>
 #include "TestFixture.h"
+#include "spirv/OpenCL.std.h"
 
 namespace {
 
index 9934e59..8f4039a 100644 (file)
@@ -28,6 +28,7 @@
 #include <vector>
 
 #include "UnitSPIRV.h"
+#include "spirv/GLSL.std.450.h"
 
 namespace {
 
index 2e6a8ae..976708c 100644 (file)
@@ -31,7 +31,7 @@ namespace {
 TEST(OpcodeSplit, Default) {
   uint32_t word = spvOpcodeMake(42, (SpvOp)23);
   uint16_t wordCount = 0;
-  SpvOp opcode;
+  uint16_t opcode;
   spvOpcodeSplit(word, &wordCount, &opcode);
   ASSERT_EQ(42, wordCount);
   ASSERT_EQ(23, opcode);
index 437736d..420f0d3 100644 (file)
@@ -31,6 +31,8 @@
 
 #include "TestFixture.h"
 #include "gmock/gmock.h"
+#include "spirv/GLSL.std.450.h"
+#include "spirv/OpenCL.std.h"
 
 namespace {
 
index b297610..82f7432 100644 (file)
@@ -54,7 +54,7 @@ Options:
 
 const char kBuildVersion[] =
 #include "build-version.inc"
-;
+    ;
 
 int main(int argc, char** argv) {
   const char* inFile = nullptr;
@@ -88,8 +88,8 @@ int main(int argc, char** argv) {
           // Long options
           if (0 == strcmp(argv[argi], "--version")) {
             printf("%s\n", kBuildVersion);
-            printf("Target: SPIR-V %d.%d rev %d\n", SPV_SPIRV_VERSION_MAJOR,
-                   SPV_SPIRV_VERSION_MINOR, SPV_SPIRV_VERSION_REVISION);
+            printf("Target: %s\n",
+                   spvTargetEnvDescription(SPV_ENV_UNIVERSAL_1_0_4));
             return 0;
           }
           if (0 == strcmp(argv[argi], "--help")) {
index 9fbaed5..3383995 100644 (file)
@@ -61,7 +61,7 @@ Options:
 
 const char kBuildVersion[] =
 #include "build-version.inc"
-;
+    ;
 
 int main(int argc, char** argv) {
   const char* inFile = nullptr;
@@ -101,8 +101,8 @@ int main(int argc, char** argv) {
             return 0;
           } else if (0 == strcmp(argv[argi], "--version")) {
             printf("%s\n", kBuildVersion);
-            printf("Target: SPIR-V %d.%d rev %d\n", SPV_SPIRV_VERSION_MAJOR,
-                   SPV_SPIRV_VERSION_MINOR, SPV_SPIRV_VERSION_REVISION);
+            printf("Target: %s\n",
+                   spvTargetEnvDescription(SPV_ENV_UNIVERSAL_1_0_4));
             return 0;
           } else {
             print_usage(argv[0]);
@@ -174,8 +174,7 @@ int main(int argc, char** argv) {
   // into the output stream.
   // If the printing option is off, then save the text in memory, so
   // it can be emitted later in this function.
-  const bool print_to_stdout =
-      spvIsInBitfield(SPV_BINARY_TO_TEXT_OPTION_PRINT, options);
+  const bool print_to_stdout = SPV_BINARY_TO_TEXT_OPTION_PRINT & options;
   spv_text text;
   spv_text* textOrNull = print_to_stdout ? nullptr : &text;
   spv_diagnostic diagnostic = nullptr;
index d3ebfb7..3182a86 100644 (file)
@@ -63,8 +63,9 @@ int main(int argc, char** argv) {
     if ('-' == cur_arg[0]) {
       if (0 == strcmp(cur_arg, "--version")) {
         printf("%s\n", kBuildVersion);
-        printf("Target: SPIR-V %d.%d rev %d\n", SPV_SPIRV_VERSION_MAJOR,
-               SPV_SPIRV_VERSION_MINOR, SPV_SPIRV_VERSION_REVISION);
+        printf("Targets:\n  %s\n  %s\n",
+               spvTargetEnvDescription(SPV_ENV_UNIVERSAL_1_0_4),
+               spvTargetEnvDescription(SPV_ENV_VULKAN_1_0_7));
         return 0;
       } else if (0 == strcmp(cur_arg, "--help") || 0 == strcmp(cur_arg, "-h")) {
         print_usage(argv[0]);