Code drop of the Codeplay spirv-tools source.
authorKenneth Benzie (Benie) <k.benzie@codeplay.com>
Fri, 22 May 2015 17:26:19 +0000 (18:26 +0100)
committerKenneth Benzie (Benie) <k.benzie@codeplay.com>
Fri, 22 May 2015 17:26:19 +0000 (18:26 +0100)
This commit contains the source for the SPIRV static library, spirv-as,
spirv-dis, and spirv-val tools.

49 files changed:
.clang-format [new file with mode: 0644]
.gitignore [new file with mode: 0644]
CMakeLists.txt [new file with mode: 0644]
external/include/headers/GLSL450Lib.h [new file with mode: 0644]
external/include/headers/OpenCLLib.h [new file with mode: 0644]
external/include/headers/spirv.h [new file with mode: 0644]
include/libspirv/libspirv.h [new file with mode: 0644]
licence.txt [new file with mode: 0644]
readme.md [new file with mode: 0644]
source/binary.cpp [new file with mode: 0644]
source/binary.h [new file with mode: 0644]
source/diagnostic.cpp [new file with mode: 0644]
source/diagnostic.h [new file with mode: 0644]
source/ext_inst.cpp [new file with mode: 0644]
source/ext_inst.h [new file with mode: 0644]
source/opcode.cpp [new file with mode: 0644]
source/opcode.h [new file with mode: 0644]
source/operand.cpp [new file with mode: 0644]
source/operand.h [new file with mode: 0644]
source/print.cpp [new file with mode: 0644]
source/print.h [new file with mode: 0644]
source/text.cpp [new file with mode: 0644]
source/text.h [new file with mode: 0644]
source/validate.cpp [new file with mode: 0644]
source/validate.h [new file with mode: 0644]
source/validate_id.cpp [new file with mode: 0644]
test/BinaryEndianness.cpp [new file with mode: 0644]
test/BinaryHeaderGet.cpp [new file with mode: 0644]
test/BinaryToText.cpp [new file with mode: 0644]
test/DiagnosticPrint.cpp [new file with mode: 0644]
test/FixWord.cpp [new file with mode: 0644]
test/NamedId.cpp [new file with mode: 0644]
test/OpcodeIsVariable.cpp [new file with mode: 0644]
test/OpcodeMake.cpp [new file with mode: 0644]
test/OpcodeRequiresCapabilities.cpp [new file with mode: 0644]
test/OpcodeSplit.cpp [new file with mode: 0644]
test/OpcodeTableGet.cpp [new file with mode: 0644]
test/OperandTableGet.cpp [new file with mode: 0644]
test/TextAdvance.cpp [new file with mode: 0644]
test/TextDestroy.cpp [new file with mode: 0644]
test/TextToBinary.cpp [new file with mode: 0644]
test/TextWordGet.cpp [new file with mode: 0644]
test/UnitSPIRV.h [new file with mode: 0644]
test/Validate.cpp [new file with mode: 0644]
test/ValidateID.cpp [new file with mode: 0644]
test/main.cpp [new file with mode: 0644]
tools/as/as.cpp [new file with mode: 0644]
tools/dis/dis.cpp [new file with mode: 0644]
tools/val/val.cpp [new file with mode: 0644]

diff --git a/.clang-format b/.clang-format
new file mode 100644 (file)
index 0000000..38804f7
--- /dev/null
@@ -0,0 +1,65 @@
+---
+Language:        Cpp
+# BasedOnStyle:  Google
+AccessModifierOffset: -1
+AlignAfterOpenBracket: true
+AlignEscapedNewlinesLeft: true
+AlignOperands:   true
+AlignTrailingComments: true
+AllowAllParametersOfDeclarationOnNextLine: true
+AllowShortBlocksOnASingleLine: false
+AllowShortCaseLabelsOnASingleLine: false
+AllowShortIfStatementsOnASingleLine: true
+AllowShortLoopsOnASingleLine: true
+AllowShortFunctionsOnASingleLine: All
+AlwaysBreakAfterDefinitionReturnType: false
+AlwaysBreakTemplateDeclarations: true
+AlwaysBreakBeforeMultilineStrings: true
+BreakBeforeBinaryOperators: None
+BreakBeforeTernaryOperators: true
+BreakConstructorInitializersBeforeComma: false
+BinPackParameters: true
+BinPackArguments: true
+ColumnLimit:     80
+ConstructorInitializerAllOnOneLineOrOnePerLine: true
+ConstructorInitializerIndentWidth: 4
+DerivePointerAlignment: true
+ExperimentalAutoDetectBinPacking: false
+IndentCaseLabels: true
+IndentWrappedFunctionNames: false
+IndentFunctionDeclarationAfterType: false
+MaxEmptyLinesToKeep: 1
+KeepEmptyLinesAtTheStartOfBlocks: false
+NamespaceIndentation: None
+ObjCBlockIndentWidth: 2
+ObjCSpaceAfterProperty: false
+ObjCSpaceBeforeProtocolList: false
+PenaltyBreakBeforeFirstCallParameter: 1
+PenaltyBreakComment: 300
+PenaltyBreakString: 1000
+PenaltyBreakFirstLessLess: 120
+PenaltyExcessCharacter: 1000000
+PenaltyReturnTypeOnItsOwnLine: 200
+PointerAlignment: Left
+SpacesBeforeTrailingComments: 2
+Cpp11BracedListStyle: true
+Standard:        Auto
+IndentWidth:     2
+TabWidth:        8
+UseTab:          Never
+BreakBeforeBraces: Attach
+SpacesInParentheses: false
+SpacesInSquareBrackets: false
+SpacesInAngles:  false
+SpaceInEmptyParentheses: false
+SpacesInCStyleCastParentheses: false
+SpaceAfterCStyleCast: false
+SpacesInContainerLiterals: true
+SpaceBeforeAssignmentOperators: true
+ContinuationIndentWidth: 4
+CommentPragmas:  '^ IWYU pragma:'
+ForEachMacros:   [ foreach, Q_FOREACH, BOOST_FOREACH ]
+SpaceBeforeParens: ControlStatements
+DisableFormat:   false
+...
+
diff --git a/.gitignore b/.gitignore
new file mode 100644 (file)
index 0000000..927d933
--- /dev/null
@@ -0,0 +1,2 @@
+build*
+.ycm_extra_conf.py*
diff --git a/CMakeLists.txt b/CMakeLists.txt
new file mode 100644 (file)
index 0000000..9f08b83
--- /dev/null
@@ -0,0 +1,188 @@
+# Copyright (c) 2015 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.
+
+cmake_minimum_required(VERSION 2.8)
+project(SPIRV)
+
+if("${CMAKE_SYSTEM_NAME}" STREQUAL "Linux")
+  add_definitions(-DSPIRV_LINUX)
+elseif("${CMAKE_SYSTEM_NAME}" STREQUAL "Windows")
+  add_definitions(-DSPIRV_WINDOWS)
+elseif("${CMAKE_SYSTEM_NAME}" STREQUAL "Darwin")
+  add_definitions(-DSPIRV_MAC)
+else()
+  message(FATAL_ERROR "Your platform '${CMAKE_SYSTEM_NAME}' is not supported!")
+endif()
+
+set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib)
+if (UNIX)
+  set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib)
+elseif(WIN32)
+  set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin)
+endif()
+set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin)
+
+if (NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES)
+  message(STATUS "No build type selected, default to Debug")
+  set(CMAKE_BUILD_TYPE "Debug")
+endif()
+
+if(UNIX)
+  set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -fno-exceptions -fno-rtti")
+  if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang")
+    set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fcolor-diagnostics")
+    set(SPIRV_USE_SANITIZER "" CACHE STRING
+      "Use the clang sanitizer [address|memory|thread|...]")
+    if(NOT "${SPIRV_USE_SANITIZER}" STREQUAL "")
+      set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fsanitize=${SPIRV_USE_SANITIZER}")
+      set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=${SPIRV_USE_SANITIZER}")
+    endif()
+  endif()
+endif()
+
+if(UNIX)
+  option(SPIRV_COLOR_TERMINAL "Enable color terminal output" ON)
+  if(${SPIRV_COLOR_TERMINAL})
+    add_definitions(-DSPV_COLOR_TERMINAL)
+  endif()
+endif()
+
+if(UNIX)
+  set(SPIRV_WARNINGS "-Wall -Wextra -Wno-missing-field-initializers")
+  option(SPIRV_WARN_EVERYTHING "Enable -Weverything for SPIRV library" OFF)
+  if(${SPIRV_WARN_EVERYTHING})
+    set(SPIRV_WARNINGS
+      "${SPIRV_WARNINGS} -Weverything -Wno-c++98-compat -Wno-c++98-compat-pedantic -Wno-padded")
+  endif()
+elseif(WIN32)
+  set(SPIRV_WARNINGS "-D_CRT_SECURE_NO_WARNINGS /wd4800")
+endif()
+
+if(UNIX)
+  option(SPIRV_WERROR "Enable error on warning" OFF)
+  if(${SPIRV_WERROR})
+    set(SPIRV_WARNINGS "${SPIRV_WARNINGS} -Werror")
+  endif()
+endif()
+
+include_directories(SYSTEM
+  ${CMAKE_CURRENT_SOURCE_DIR}/external/include)
+
+include_directories(
+  ${CMAKE_CURRENT_SOURCE_DIR}/include)
+
+set(SPIRV_SOURCES
+  ${CMAKE_CURRENT_SOURCE_DIR}/include/libspirv/libspirv.h
+  ${CMAKE_CURRENT_SOURCE_DIR}/source/binary.h
+  ${CMAKE_CURRENT_SOURCE_DIR}/source/diagnostic.h
+  ${CMAKE_CURRENT_SOURCE_DIR}/source/opcode.h
+  ${CMAKE_CURRENT_SOURCE_DIR}/source/operand.h
+  ${CMAKE_CURRENT_SOURCE_DIR}/source/print.h
+  ${CMAKE_CURRENT_SOURCE_DIR}/source/text.h
+  ${CMAKE_CURRENT_SOURCE_DIR}/source/validate.h
+  ${CMAKE_CURRENT_SOURCE_DIR}/source/binary.cpp
+  ${CMAKE_CURRENT_SOURCE_DIR}/source/diagnostic.cpp
+  ${CMAKE_CURRENT_SOURCE_DIR}/source/ext_inst.cpp
+  ${CMAKE_CURRENT_SOURCE_DIR}/source/opcode.cpp
+  ${CMAKE_CURRENT_SOURCE_DIR}/source/operand.cpp
+  ${CMAKE_CURRENT_SOURCE_DIR}/source/print.cpp
+  ${CMAKE_CURRENT_SOURCE_DIR}/source/text.cpp
+  ${CMAKE_CURRENT_SOURCE_DIR}/source/validate.cpp
+  ${CMAKE_CURRENT_SOURCE_DIR}/source/validate_id.cpp)
+
+add_library(SPIRV ${SPIRV_SOURCES})
+target_link_libraries(SPIRV ${SPIRV_LIBS})
+set_target_properties(SPIRV PROPERTIES COMPILE_FLAGS ${SPIRV_WARNINGS})
+
+add_executable(spirv-as
+  ${CMAKE_CURRENT_SOURCE_DIR}/include/libspirv/libspirv.h
+  ${CMAKE_CURRENT_SOURCE_DIR}/tools/as/as.cpp)
+set_target_properties(spirv-as PROPERTIES COMPILE_FLAGS ${SPIRV_WARNINGS})
+target_link_libraries(spirv-as SPIRV)
+
+add_executable(spirv-dis
+  ${CMAKE_CURRENT_SOURCE_DIR}/include/libspirv/libspirv.h
+  ${CMAKE_CURRENT_SOURCE_DIR}/tools/dis/dis.cpp)
+set_target_properties(spirv-dis PROPERTIES COMPILE_FLAGS ${SPIRV_WARNINGS})
+target_link_libraries(spirv-dis SPIRV)
+
+add_executable(spirv-val
+  ${CMAKE_CURRENT_SOURCE_DIR}/include/libspirv/libspirv.h
+  ${CMAKE_CURRENT_SOURCE_DIR}/tools/val/val.cpp)
+set_target_properties(spirv-val PROPERTIES COMPILE_FLAGS ${SPIRV_WARNINGS})
+target_link_libraries(spirv-val SPIRV)
+
+set(GTEST_DIR ${CMAKE_CURRENT_SOURCE_DIR}/external/googletest)
+if(EXISTS ${GTEST_DIR})
+  if(WIN32)
+    option(gtest_force_shared_crt
+      "Use shared (DLL) run-time lib even when Google Test is built as static lib."
+      ON)
+  endif()
+
+  message(STATUS "Found googletest, building tests.")
+
+  include_directories(SYSTEM
+    ${CMAKE_CURRENT_SOURCE_DIR}/external/googletest
+    ${CMAKE_CURRENT_SOURCE_DIR}/external/googletest/include)
+
+  add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/external/googletest)
+
+  add_executable(UnitSPIRV
+    ${CMAKE_CURRENT_SOURCE_DIR}/test/UnitSPIRV.h
+    ${CMAKE_CURRENT_SOURCE_DIR}/test/BinaryEndianness.cpp
+    ${CMAKE_CURRENT_SOURCE_DIR}/test/FixWord.cpp
+    ${CMAKE_CURRENT_SOURCE_DIR}/test/BinaryHeaderGet.cpp
+    ${CMAKE_CURRENT_SOURCE_DIR}/test/BinaryToText.cpp
+    ${CMAKE_CURRENT_SOURCE_DIR}/test/NamedId.cpp
+    ${CMAKE_CURRENT_SOURCE_DIR}/test/OpcodeTableGet.cpp
+    ${CMAKE_CURRENT_SOURCE_DIR}/test/OpcodeIsVariable.cpp
+    ${CMAKE_CURRENT_SOURCE_DIR}/test/OpcodeRequiresCapabilities.cpp
+    ${CMAKE_CURRENT_SOURCE_DIR}/test/OpcodeMake.cpp
+    ${CMAKE_CURRENT_SOURCE_DIR}/test/OpcodeSplit.cpp
+    ${CMAKE_CURRENT_SOURCE_DIR}/test/OperandTableGet.cpp
+    ${CMAKE_CURRENT_SOURCE_DIR}/test/TextAdvance.cpp
+    ${CMAKE_CURRENT_SOURCE_DIR}/test/TextWordGet.cpp
+    ${CMAKE_CURRENT_SOURCE_DIR}/test/TextToBinary.cpp
+    ${CMAKE_CURRENT_SOURCE_DIR}/test/TextDestroy.cpp
+    ${CMAKE_CURRENT_SOURCE_DIR}/test/DiagnosticPrint.cpp
+    ${CMAKE_CURRENT_SOURCE_DIR}/test/Validate.cpp
+    ${CMAKE_CURRENT_SOURCE_DIR}/test/ValidateID.cpp
+    ${CMAKE_CURRENT_SOURCE_DIR}/test/main.cpp)
+  target_link_libraries(UnitSPIRV SPIRV gtest)
+else()
+  message(STATUS "Did not find googletest, tests will not be built."
+    "To enable tests place googletest in '<spirv-dir>/external/googletest'.")
+endif()
+
+set(CMAKE_INSTALL_PREFIX ${CMAKE_CURRENT_BINARY_DIR}/install)
+install(TARGETS SPIRV spirv-as spirv-dis spirv-val
+  RUNTIME DESTINATION bin
+  LIBRARY DESTINATION lib
+  ARCHIVE DESTINATION lib)
+
+install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/include/libspirv/libspirv.h
+  DESTINATION include/libspirv/)
diff --git a/external/include/headers/GLSL450Lib.h b/external/include/headers/GLSL450Lib.h
new file mode 100644 (file)
index 0000000..49107c8
--- /dev/null
@@ -0,0 +1,213 @@
+/*
+** Copyright (c) 2015 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.
+*/
+
+//
+// Author: John Kessenich, LunarG
+//
+
+namespace GLSL_STD_450 {
+
+enum Entrypoints {
+    Round = 0,
+    RoundEven = 1,
+    Trunc = 2,
+    Abs = 3,
+    Sign = 4,
+    Floor = 5,
+    Ceil = 6,
+    Fract = 7,
+
+    Radians = 8,
+    Degrees = 9,
+    Sin = 10,
+    Cos = 11,
+    Tan = 12,
+    Asin = 13,
+    Acos = 14,
+    Atan = 15,
+    Sinh = 16,
+    Cosh = 17,
+    Tanh = 18,
+    Asinh = 19,
+    Acosh = 20,
+    Atanh = 21,
+    Atan2 = 22,
+
+    Pow = 23,
+    Exp = 24,
+    Log = 25,
+    Exp2 = 26,
+    Log2 = 27,
+    Sqrt = 28,
+    InverseSqrt = 29,
+
+    Determinant = 30,
+    MatrixInverse = 31,
+
+    Modf = 32,            // second argument needs the OpVariable = , not an OpLoad
+    Min = 33,
+    Max = 34,
+    Clamp = 35,
+    Mix = 36,
+    Step = 37,
+    SmoothStep = 38,
+
+    FloatBitsToInt = 39,
+    FloatBitsToUint = 40,
+    IntBitsToFloat = 41,
+    UintBitsToFloat = 42,
+
+    Fma = 43,
+    Frexp = 44,
+    Ldexp = 45,
+
+    PackSnorm4x8 = 46,
+    PackUnorm4x8 = 47,
+    PackSnorm2x16 = 48,
+    PackUnorm2x16 = 49,
+    PackHalf2x16 = 50,
+    PackDouble2x32 = 51,
+    UnpackSnorm2x16 = 52,
+    UnpackUnorm2x16 = 53,
+    UnpackHalf2x16 = 54,
+    UnpackSnorm4x8 = 55,
+    UnpackUnorm4x8 = 56,
+    UnpackDouble2x32 = 57,
+
+    Length = 58,
+    Distance = 59,
+    Cross = 60,
+    Normalize = 61,
+    Ftransform = 62,
+    FaceForward = 63,
+    Reflect = 64,
+    Refract = 65,
+
+    UaddCarry = 66,
+    UsubBorrow = 67,
+    UmulExtended = 68,
+    ImulExtended = 69,
+    BitfieldExtract = 70,
+    BitfieldInsert = 71,
+    BitfieldReverse = 72,
+    BitCount = 73,
+    FindLSB = 74,
+    FindMSB = 75,
+
+    InterpolateAtCentroid = 76,
+    InterpolateAtSample = 77,
+    InterpolateAtOffset = 78,
+
+    Count
+};
+
+inline void GetDebugNames(const char** names)
+{
+    for (int i = 0; i < Count; ++i)
+        names[i] = "Unknown";
+
+    names[Round]                   = "round";
+    names[RoundEven]               = "roundEven";
+    names[Trunc]                   = "trunc";
+    names[Abs]                     = "abs";
+    names[Sign]                    = "sign";
+    names[Floor]                   = "floor";
+    names[Ceil]                    = "ceil";
+    names[Fract]                   = "fract";
+    names[Radians]                 = "radians";
+    names[Degrees]                 = "degrees";
+    names[Sin]                     = "sin";
+    names[Cos]                     = "cos";
+    names[Tan]                     = "tan";
+    names[Asin]                    = "asin";
+    names[Acos]                    = "acos";
+    names[Atan]                    = "atan";
+    names[Sinh]                    = "sinh";
+    names[Cosh]                    = "cosh";
+    names[Tanh]                    = "tanh";
+    names[Asinh]                   = "asinh";
+    names[Acosh]                   = "acosh";
+    names[Atanh]                   = "atanh";
+    names[Atan2]                   = "atan2";
+    names[Pow]                     = "pow";
+    names[Exp]                     = "exp";
+    names[Log]                     = "log";
+    names[Exp2]                    = "exp2";
+    names[Log2]                    = "log2";
+    names[Sqrt]                    = "sqrt";
+    names[InverseSqrt]             = "inversesqrt";
+    names[Determinant]             = "determinant";
+    names[MatrixInverse]           = "inverse";
+    names[Modf]                    = "modf";
+    names[Min]                     = "min";
+    names[Max]                     = "max";
+    names[Clamp]                   = "clamp";
+    names[Mix]                     = "mix";
+    names[Step]                    = "step";
+    names[SmoothStep]              = "smoothstep";
+    names[FloatBitsToInt]          = "floatBitsToInt";
+    names[FloatBitsToUint]         = "floatBitsToUint";
+    names[IntBitsToFloat]          = "intBitsToFloat";
+    names[UintBitsToFloat]         = "uintBitsToFloat";
+    names[Fma]                     = "fma";
+    names[Frexp]                   = "frexp";
+    names[Ldexp]                   = "ldexp";
+    names[PackSnorm4x8]            = "packSnorm4x8";
+    names[PackUnorm4x8]            = "packUnorm4x8";
+    names[PackSnorm2x16]           = "packSnorm2x16";
+    names[PackUnorm2x16]           = "packUnorm2x16";
+    names[PackHalf2x16]            = "packHalf2x16";
+    names[PackDouble2x32]          = "packDouble2x32";
+    names[UnpackSnorm2x16]         = "unpackSnorm2x16";
+    names[UnpackUnorm2x16]         = "unpackUnorm2x16";
+    names[UnpackHalf2x16]          = "unpackHalf2x16";
+    names[UnpackSnorm4x8]          = "unpackSnorm4x8";
+    names[UnpackUnorm4x8]          = "unpackUnorm4x8";
+    names[UnpackDouble2x32]        = "unpackDouble2x32";
+    names[Length]                  = "length";
+    names[Distance]                = "distance";
+    names[Cross]                   = "cross";
+    names[Normalize]               = "normalize";
+    names[Ftransform]              = "ftransform";
+    names[FaceForward]             = "faceforward";
+    names[Reflect]                 = "reflect";
+    names[Refract]                 = "refract";
+    names[UaddCarry]               = "uaddCarry";
+    names[UsubBorrow]              = "usubBorrow";
+    names[UmulExtended]            = "umulExtended";
+    names[ImulExtended]            = "imulExtended";
+    names[BitfieldExtract]         = "bitfieldExtract";
+    names[BitfieldInsert]          = "bitfieldInsert";
+    names[BitfieldReverse]         = "bitfieldReverse";
+    names[BitCount]                = "bitCount";
+    names[FindLSB]                 = "findLSB";
+    names[FindMSB]                 = "findMSB";
+    names[InterpolateAtCentroid]   = "interpolateAtCentroid";
+    names[InterpolateAtSample]     = "interpolateAtSample";
+    names[InterpolateAtOffset]     = "interpolateAtOffset";
+}
+
+}; // end namespace GLSL_STD_450
diff --git a/external/include/headers/OpenCLLib.h b/external/include/headers/OpenCLLib.h
new file mode 100644 (file)
index 0000000..89a5708
--- /dev/null
@@ -0,0 +1,307 @@
+/*
+** Copyright (c) 2015 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.
+*/
+
+//
+// Author: Boaz Ouriel, Intel
+//
+
+namespace OpenCLLIB {
+
+enum Entrypoints {
+
+    // math functions
+    Acos = 0,
+    Acosh = 1,
+    Acospi = 2,
+    Asin = 3,
+    Asinh = 4,
+    Asinpi = 5,
+    Atan = 6,
+    Atan2 = 7,
+    Atanh = 8,
+    Atanpi = 9,
+    Atan2pi = 10,
+    Cbrt = 11,
+    Ceil = 12,
+    Copysign = 13,
+    Cos = 14,
+    Cosh = 15,
+    Cospi = 16,
+    Erfc = 17,
+    Erf = 18,
+    Exp = 19,
+    Exp2 = 20,
+    Exp10 = 21,
+    Expm1 = 22,
+    Fabs = 23,
+    Fdim = 24,
+    Floor = 25,
+    Fma = 26,
+    Fmax = 27,
+    Fmin = 28,
+    Fmod = 29,
+    Fract = 30, 
+    Frexp = 31,
+    Hypot = 32,
+    Ilogb = 33,
+    Ldexp = 34,
+    Lgamma = 35,
+    Lgamma_r = 36,
+    Log = 37,
+    Log2 = 38,
+    Log10 = 39,
+    Log1p = 40,
+    Logb = 41,
+    Mad = 42,
+    Maxmag = 43,
+    Minmag = 44,
+    Modf = 45,
+    Nan = 46,
+    Nextafter = 47,
+    Pow = 48,
+    Pown = 49,
+    Powr = 50,
+    Remainder = 51,
+    Remquo = 52,
+    Rint = 53,
+    Rootn = 54,
+    Round = 55,
+    Rsqrt = 56,
+    Sin = 57,
+    Sincos = 58,
+    Sinh = 59,
+    Sinpi = 60,
+    Sqrt = 61,
+    Tan = 62,
+    Tanh = 63,
+    Tanpi = 64,
+    Tgamma = 65,
+    Trunc = 66,
+    Half_cos = 67,
+    Half_divide = 68,
+    Half_exp = 69,
+    Half_exp2 = 70,
+    Half_exp10 = 71,
+    Half_log = 72,
+    Half_log2 = 73,
+    Half_log10 = 74,
+    Half_powr = 75,
+    Half_recip = 76,
+    Half_rsqrt = 77,
+    Half_sin = 78,
+    Half_sqrt = 79,
+    Half_tan = 80,
+    Native_cos = 81,
+    Native_divide = 82,
+    Native_exp = 83,
+    Native_exp2 = 84,
+    Native_exp10 = 85,
+    Native_log = 86,
+    Native_log2 = 87,
+    Native_log10 = 88,
+    Native_powr = 89,
+    Native_recip = 90,
+    Native_rsqrt = 91,
+    Native_sin = 92,
+    Native_sqrt = 93,
+    Native_tan = 94,
+    
+    // Common
+    FClamp = 95,
+    Degrees = 96,
+    FMax_common = 97,
+    FMin_common = 98, 
+    Mix = 99,
+    Radians = 100,
+    Step = 101,
+    Smoothstep = 102,
+    Sign = 103,
+    
+    // Geometrics
+    Cross = 104,
+    Distance = 105, 
+    Length = 106,
+    Normalize = 107,
+    Fast_distance = 108,
+    Fast_length = 109,
+    Fast_normalize = 110,
+
+    // Images
+    Read_imagef = 111,
+    Read_imagei = 112,
+    Read_imageui = 113,
+    Read_imageh = 114,
+
+    Read_imagef_samplerless = 115,
+    Read_imagei_samplerless = 116,
+    Read_imageui_samplerless = 117,
+    Read_imageh_samplerless = 118,
+
+    Write_imagef = 119,
+    Write_imagei = 120,
+    Write_imageui = 121,
+    Write_imageh = 122,
+    Read_imagef_mipmap_lod = 123,
+    Read_imagei_mipmap_lod = 124,
+    Read_imageui_mipmap_lod = 125,
+    Read_imagef_mipmap_grad = 126,
+    Read_imagei_mipmap_grad = 127,
+    Read_imageui_mipmap_grad = 128,
+    Write_imagef_mipmap_lod = 129,
+    Write_imagei_mipmap_lod = 130,
+    Write_imageui_mipmap_lod = 131,
+    Get_image_width = 132,
+    Get_image_height = 133,
+    Get_image_depth = 134,
+    Get_image_channel_data_type = 135,
+    Get_image_channel_order = 136,
+    Get_image_dim = 137,
+    Get_image_array_size = 138,
+    Get_image_num_samples = 139,
+    Get_image_num_mip_levels = 140,
+    
+    // Integers
+    SAbs = 141,
+    SAbs_diff = 142,
+    SAdd_sat = 143,
+    UAdd_sat = 144,
+    SHadd = 145,
+    UHadd = 146,
+    SRhadd = 147,
+    URhadd = 148,
+    SClamp = 149,
+    UClamp = 150, 
+    Clz = 151,
+    Ctz = 152,    
+    SMad_hi = 153,
+    UMad_sat = 154,
+    SMad_sat = 155,
+    SMax = 156,
+    UMax = 157,
+    SMin = 158,
+    UMin = 159,
+    SMul_hi = 160,
+    Rotate = 161,
+    SSub_sat = 162,
+    USub_sat = 163,
+    U_Upsample = 164,
+    S_Upsample = 165,
+    Popcount = 166,
+    SMad24 = 167,
+    UMad24 = 168,
+    SMul24 = 169,
+    UMul24 = 170,
+
+    // Vector Loads/Stores
+    Vloadn = 171,
+    Vstoren = 172,
+    Vload_half = 173,
+    Vload_halfn = 174,
+    Vstore_half = 175,
+    Vstore_half_r = 176,
+    Vstore_halfn = 177,
+    Vstore_halfn_r = 178,
+    Vloada_halfn = 179,
+    Vstorea_halfn = 180,
+    Vstorea_halfn_r = 181,
+
+    // Vector Misc 
+    Shuffle = 182,
+    Shuffle2 = 183,
+
+    // 
+    Printf = 184,
+    Prefetch = 185,
+    
+    // Relationals
+    Bitselect = 186,
+    Select = 187,
+        
+    // pipes
+    Read_pipe = 188,
+    Write_pipe = 189,
+    Reserve_read_pipe = 190,
+    Reserve_write_pipe = 191,
+    Commit_read_pipe = 192,
+    Commit_write_pipe = 193,
+    Is_valid_reserve_id = 194,
+    Work_group_reserve_read_pipe = 195,
+    Work_group_reserve_write_pipe = 196,
+    Work_group_commit_read_pipe = 197,
+    Work_group_commit_write_pipe = 198,
+    Get_pipe_num_packets = 199,
+    Get_pipe_max_packets = 200,
+    
+    // more integers
+    UAbs = 201,
+    UAbs_diff = 202,
+    UMul_hi = 203,
+    UMad_hi = 204,
+};
+
+enum ImageChannelOrder {
+    R_ChannelOrder          = 0x10B0,
+    A_ChannelOrder          = 0x10B1,
+    RG_ChannelOrder         = 0x10B2,
+    RA_ChannelOrder         = 0x10B3,
+    RGB_ChannelOrder        = 0x10B4,
+    RGBA_ChannelOrder       = 0x10B5,
+    BGRA_ChannelOrder       = 0x10B6,
+    ARGB_ChannelOrder       = 0x10B7,
+    INTENSITY_ChannelOrder  = 0x10B8,
+    LUMINANCE_ChannelOrder  = 0x10B9,
+    Rx_ChannelOrder         = 0x10BA,
+    RGx_ChannelOrder        = 0x10BB,
+    RGBx_ChannelOrder       = 0x10BC,
+    DEPTH_ChannelOrder      = 0x10BD,
+    DEPTH_STENCIL_ChannelOrder = 0x10BE,
+    sRGB_ChannelOrder       = 0x10BF,
+    sRGBx_ChannelOrder      = 0x10C0,
+    sRGBA_ChannelOrder      = 0x10C1,
+    sBGRA_ChannelOrder      = 0x10C2,
+};
+
+enum ImageChannelType {
+    SNORM_INT8_ChannelType          = 0x10D0,
+    SNORM_INT16_ChannelType         = 0x10D1,
+    UNORM_INT8_ChannelType          = 0x10D2,
+    UNORM_INT16_ChannelType         = 0x10D3,
+    UNORM_SHORT_565_ChannelType     = 0x10D4,
+    UNORM_SHORT_555_ChannelType     = 0x10D5,
+    UNORM_INT_101010_ChannelType    = 0x10D6,
+    SIGNED_INT8_ChannelType         = 0x10D7,
+    SIGNED_INT16_ChannelType        = 0x10D8,
+    SIGNED_INT32_ChannelType        = 0x10D9,
+    UNSIGNED_INT8_ChannelType       = 0x10DA,
+    UNSIGNED_INT16_ChannelType      = 0x10DB,
+    UNSIGNED_INT32_ChannelType      = 0x10DC,
+    HALF_FLOAT_ChannelType          = 0x10DD,
+    FLOAT_ChannelType               = 0x10DE,
+    UNORM_INT24_ChannelType         = 0x10DF,
+};
+
+}; // end namespace OpenCL20
+
diff --git a/external/include/headers/spirv.h b/external/include/headers/spirv.h
new file mode 100644 (file)
index 0000000..a75bf18
--- /dev/null
@@ -0,0 +1,1354 @@
+/*
+** Copyright (c) 2015 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.
+*/
+
+/*
+** This header is automatically generated by the same tool that creates
+** the Binary Section of the SPIR-V specification.
+*/
+
+/*
+** Specification revision 30.
+** Enumeration tokens for SPIR-V, in three styles: C, C++, generic.
+** - C++ will have the tokens in the "spv" name space, with no prefix.
+** - C will have tokens with as "Spv" prefix.
+**
+** Some tokens act like mask values, which can be OR'd together,
+** while others are mutually exclusive.  The mask-like ones have
+** "Mask" in their name, and a parallel enum that has the shift
+** amount (1 << x) for each corresponding enumerant.
+*/
+
+#ifndef spirv_H
+#define spirv_H
+
+#ifdef __cplusplus
+
+namespace spv {
+
+static const int MagicNumber = 0x07230203;
+static const int Version = 99;
+
+typedef unsigned int Id;
+
+static const unsigned int OpCodeMask = 0xFFFF;
+static const unsigned int WordCountShift = 16;
+
+enum SourceLanguage {
+    SourceLanguageUnknown = 0,
+    SourceLanguageESSL = 1,
+    SourceLanguageGLSL = 2,
+    SourceLanguageOpenCL = 3,
+};
+
+enum ExecutionModel {
+    ExecutionModelVertex = 0,
+    ExecutionModelTessellationControl = 1,
+    ExecutionModelTessellationEvaluation = 2,
+    ExecutionModelGeometry = 3,
+    ExecutionModelFragment = 4,
+    ExecutionModelGLCompute = 5,
+    ExecutionModelKernel = 6,
+};
+
+enum AddressingModel {
+    AddressingModelLogical = 0,
+    AddressingModelPhysical32 = 1,
+    AddressingModelPhysical64 = 2,
+};
+
+enum MemoryModel {
+    MemoryModelSimple = 0,
+    MemoryModelGLSL450 = 1,
+    MemoryModelOpenCL12 = 2,
+    MemoryModelOpenCL20 = 3,
+    MemoryModelOpenCL21 = 4,
+};
+
+enum ExecutionMode {
+    ExecutionModeInvocations = 0,
+    ExecutionModeSpacingEqual = 1,
+    ExecutionModeSpacingFractionalEven = 2,
+    ExecutionModeSpacingFractionalOdd = 3,
+    ExecutionModeVertexOrderCw = 4,
+    ExecutionModeVertexOrderCcw = 5,
+    ExecutionModePixelCenterInteger = 6,
+    ExecutionModeOriginUpperLeft = 7,
+    ExecutionModeEarlyFragmentTests = 8,
+    ExecutionModePointMode = 9,
+    ExecutionModeXfb = 10,
+    ExecutionModeDepthReplacing = 11,
+    ExecutionModeDepthAny = 12,
+    ExecutionModeDepthGreater = 13,
+    ExecutionModeDepthLess = 14,
+    ExecutionModeDepthUnchanged = 15,
+    ExecutionModeLocalSize = 16,
+    ExecutionModeLocalSizeHint = 17,
+    ExecutionModeInputPoints = 18,
+    ExecutionModeInputLines = 19,
+    ExecutionModeInputLinesAdjacency = 20,
+    ExecutionModeInputTriangles = 21,
+    ExecutionModeInputTrianglesAdjacency = 22,
+    ExecutionModeInputQuads = 23,
+    ExecutionModeInputIsolines = 24,
+    ExecutionModeOutputVertices = 25,
+    ExecutionModeOutputPoints = 26,
+    ExecutionModeOutputLineStrip = 27,
+    ExecutionModeOutputTriangleStrip = 28,
+    ExecutionModeVecTypeHint = 29,
+    ExecutionModeContractionOff = 30,
+    ExecutionModeOriginLowerLeft = 31,
+};
+
+enum StorageClass {
+    StorageClassUniformConstant = 0,
+    StorageClassInput = 1,
+    StorageClassUniform = 2,
+    StorageClassOutput = 3,
+    StorageClassWorkgroupLocal = 4,
+    StorageClassWorkgroupGlobal = 5,
+    StorageClassPrivateGlobal = 6,
+    StorageClassFunction = 7,
+    StorageClassGeneric = 8,
+    StorageClassAtomicCounter = 10,
+};
+
+enum Dim {
+    Dim1D = 0,
+    Dim2D = 1,
+    Dim3D = 2,
+    DimCube = 3,
+    DimRect = 4,
+    DimBuffer = 5,
+};
+
+enum SamplerAddressingMode {
+    SamplerAddressingModeNone = 0,
+    SamplerAddressingModeClampToEdge = 1,
+    SamplerAddressingModeClamp = 2,
+    SamplerAddressingModeRepeat = 3,
+    SamplerAddressingModeRepeatMirrored = 4,
+};
+
+enum SamplerFilterMode {
+    SamplerFilterModeNearest = 0,
+    SamplerFilterModeLinear = 1,
+};
+
+enum FPFastMathModeShift {
+    FPFastMathModeNotNaNShift = 0,
+    FPFastMathModeNotInfShift = 1,
+    FPFastMathModeNSZShift = 2,
+    FPFastMathModeAllowRecipShift = 3,
+    FPFastMathModeFastShift = 4,
+};
+
+enum FPFastMathModeMask {
+    FPFastMathModeMaskNone = 0,
+    FPFastMathModeNotNaNMask = 0x00000001,
+    FPFastMathModeNotInfMask = 0x00000002,
+    FPFastMathModeNSZMask = 0x00000004,
+    FPFastMathModeAllowRecipMask = 0x00000008,
+    FPFastMathModeFastMask = 0x00000010,
+};
+
+enum FPRoundingMode {
+    FPRoundingModeRTE = 0,
+    FPRoundingModeRTZ = 1,
+    FPRoundingModeRTP = 2,
+    FPRoundingModeRTN = 3,
+};
+
+enum LinkageType {
+    LinkageTypeExport = 0,
+    LinkageTypeImport = 1,
+};
+
+enum AccessQualifier {
+    AccessQualifierReadOnly = 0,
+    AccessQualifierWriteOnly = 1,
+    AccessQualifierReadWrite = 2,
+};
+
+enum FunctionParameterAttribute {
+    FunctionParameterAttributeZext = 0,
+    FunctionParameterAttributeSext = 1,
+    FunctionParameterAttributeByVal = 2,
+    FunctionParameterAttributeSret = 3,
+    FunctionParameterAttributeNoAlias = 4,
+    FunctionParameterAttributeNoCapture = 5,
+    FunctionParameterAttributeSVM = 6,
+    FunctionParameterAttributeNoWrite = 7,
+    FunctionParameterAttributeNoReadWrite = 8,
+};
+
+enum Decoration {
+    DecorationPrecisionLow = 0,
+    DecorationPrecisionMedium = 1,
+    DecorationPrecisionHigh = 2,
+    DecorationBlock = 3,
+    DecorationBufferBlock = 4,
+    DecorationRowMajor = 5,
+    DecorationColMajor = 6,
+    DecorationGLSLShared = 7,
+    DecorationGLSLStd140 = 8,
+    DecorationGLSLStd430 = 9,
+    DecorationGLSLPacked = 10,
+    DecorationSmooth = 11,
+    DecorationNoperspective = 12,
+    DecorationFlat = 13,
+    DecorationPatch = 14,
+    DecorationCentroid = 15,
+    DecorationSample = 16,
+    DecorationInvariant = 17,
+    DecorationRestrict = 18,
+    DecorationAliased = 19,
+    DecorationVolatile = 20,
+    DecorationConstant = 21,
+    DecorationCoherent = 22,
+    DecorationNonwritable = 23,
+    DecorationNonreadable = 24,
+    DecorationUniform = 25,
+    DecorationNoStaticUse = 26,
+    DecorationCPacked = 27,
+    DecorationSaturatedConversion = 28,
+    DecorationStream = 29,
+    DecorationLocation = 30,
+    DecorationComponent = 31,
+    DecorationIndex = 32,
+    DecorationBinding = 33,
+    DecorationDescriptorSet = 34,
+    DecorationOffset = 35,
+    DecorationAlignment = 36,
+    DecorationXfbBuffer = 37,
+    DecorationStride = 38,
+    DecorationBuiltIn = 39,
+    DecorationFuncParamAttr = 40,
+    DecorationFPRoundingMode = 41,
+    DecorationFPFastMathMode = 42,
+    DecorationLinkageAttributes = 43,
+    DecorationSpecId = 44,
+};
+
+enum BuiltIn {
+    BuiltInPosition = 0,
+    BuiltInPointSize = 1,
+    BuiltInClipVertex = 2,
+    BuiltInClipDistance = 3,
+    BuiltInCullDistance = 4,
+    BuiltInVertexId = 5,
+    BuiltInInstanceId = 6,
+    BuiltInPrimitiveId = 7,
+    BuiltInInvocationId = 8,
+    BuiltInLayer = 9,
+    BuiltInViewportIndex = 10,
+    BuiltInTessLevelOuter = 11,
+    BuiltInTessLevelInner = 12,
+    BuiltInTessCoord = 13,
+    BuiltInPatchVertices = 14,
+    BuiltInFragCoord = 15,
+    BuiltInPointCoord = 16,
+    BuiltInFrontFacing = 17,
+    BuiltInSampleId = 18,
+    BuiltInSamplePosition = 19,
+    BuiltInSampleMask = 20,
+    BuiltInFragColor = 21,
+    BuiltInFragDepth = 22,
+    BuiltInHelperInvocation = 23,
+    BuiltInNumWorkgroups = 24,
+    BuiltInWorkgroupSize = 25,
+    BuiltInWorkgroupId = 26,
+    BuiltInLocalInvocationId = 27,
+    BuiltInGlobalInvocationId = 28,
+    BuiltInLocalInvocationIndex = 29,
+    BuiltInWorkDim = 30,
+    BuiltInGlobalSize = 31,
+    BuiltInEnqueuedWorkgroupSize = 32,
+    BuiltInGlobalOffset = 33,
+    BuiltInGlobalLinearId = 34,
+    BuiltInWorkgroupLinearId = 35,
+    BuiltInSubgroupSize = 36,
+    BuiltInSubgroupMaxSize = 37,
+    BuiltInNumSubgroups = 38,
+    BuiltInNumEnqueuedSubgroups = 39,
+    BuiltInSubgroupId = 40,
+    BuiltInSubgroupLocalInvocationId = 41,
+};
+
+enum SelectionControlShift {
+    SelectionControlFlattenShift = 0,
+    SelectionControlDontFlattenShift = 1,
+};
+
+enum SelectionControlMask {
+    SelectionControlMaskNone = 0,
+    SelectionControlFlattenMask = 0x00000001,
+    SelectionControlDontFlattenMask = 0x00000002,
+};
+
+enum LoopControlShift {
+    LoopControlUnrollShift = 0,
+    LoopControlDontUnrollShift = 1,
+};
+
+enum LoopControlMask {
+    LoopControlMaskNone = 0,
+    LoopControlUnrollMask = 0x00000001,
+    LoopControlDontUnrollMask = 0x00000002,
+};
+
+enum FunctionControlShift {
+    FunctionControlInlineShift = 0,
+    FunctionControlDontInlineShift = 1,
+    FunctionControlPureShift = 2,
+    FunctionControlConstShift = 3,
+};
+
+enum FunctionControlMask {
+    FunctionControlMaskNone = 0,
+    FunctionControlInlineMask = 0x00000001,
+    FunctionControlDontInlineMask = 0x00000002,
+    FunctionControlPureMask = 0x00000004,
+    FunctionControlConstMask = 0x00000008,
+};
+
+enum MemorySemanticsShift {
+    MemorySemanticsRelaxedShift = 0,
+    MemorySemanticsSequentiallyConsistentShift = 1,
+    MemorySemanticsAcquireShift = 2,
+    MemorySemanticsReleaseShift = 3,
+    MemorySemanticsUniformMemoryShift = 4,
+    MemorySemanticsSubgroupMemoryShift = 5,
+    MemorySemanticsWorkgroupLocalMemoryShift = 6,
+    MemorySemanticsWorkgroupGlobalMemoryShift = 7,
+    MemorySemanticsAtomicCounterMemoryShift = 8,
+    MemorySemanticsImageMemoryShift = 9,
+};
+
+enum MemorySemanticsMask {
+    MemorySemanticsMaskNone = 0,
+    MemorySemanticsRelaxedMask = 0x00000001,
+    MemorySemanticsSequentiallyConsistentMask = 0x00000002,
+    MemorySemanticsAcquireMask = 0x00000004,
+    MemorySemanticsReleaseMask = 0x00000008,
+    MemorySemanticsUniformMemoryMask = 0x00000010,
+    MemorySemanticsSubgroupMemoryMask = 0x00000020,
+    MemorySemanticsWorkgroupLocalMemoryMask = 0x00000040,
+    MemorySemanticsWorkgroupGlobalMemoryMask = 0x00000080,
+    MemorySemanticsAtomicCounterMemoryMask = 0x00000100,
+    MemorySemanticsImageMemoryMask = 0x00000200,
+};
+
+enum MemoryAccessShift {
+    MemoryAccessVolatileShift = 0,
+    MemoryAccessAlignedShift = 1,
+};
+
+enum MemoryAccessMask {
+    MemoryAccessMaskNone = 0,
+    MemoryAccessVolatileMask = 0x00000001,
+    MemoryAccessAlignedMask = 0x00000002,
+};
+
+enum Scope {
+    ScopeCrossDevice = 0,
+    ScopeDevice = 1,
+    ScopeWorkgroup = 2,
+    ScopeSubgroup = 3,
+    ScopeInvocation = 4,
+};
+
+enum GroupOperation {
+    GroupOperationReduce = 0,
+    GroupOperationInclusiveScan = 1,
+    GroupOperationExclusiveScan = 2,
+};
+
+enum KernelEnqueueFlags {
+    KernelEnqueueFlagsNoWait = 0,
+    KernelEnqueueFlagsWaitKernel = 1,
+    KernelEnqueueFlagsWaitWorkGroup = 2,
+};
+
+enum KernelProfilingInfoShift {
+    KernelProfilingInfoCmdExecTimeShift = 0,
+};
+
+enum KernelProfilingInfoMask {
+    KernelProfilingInfoMaskNone = 0,
+    KernelProfilingInfoCmdExecTimeMask = 0x00000001,
+};
+
+enum Capability {
+    CapabilityMatrix = 0,
+    CapabilityShader = 1,
+    CapabilityGeometry = 2,
+    CapabilityTessellation = 3,
+    CapabilityAddresses = 4,
+    CapabilityLinkage = 5,
+    CapabilityKernel = 6,
+    CapabilityVector16 = 7,
+    CapabilityFloat16Buffer = 8,
+    CapabilityFloat16 = 9,
+    CapabilityFloat64 = 10,
+    CapabilityInt64 = 11,
+    CapabilityInt64Atomics = 12,
+    CapabilityImageBasic = 13,
+    CapabilityImageReadWrite = 14,
+    CapabilityImageMipmap = 15,
+    CapabilityImageSRGBWrite = 16,
+    CapabilityPipes = 17,
+    CapabilityGroups = 18,
+    CapabilityDeviceEnqueue = 19,
+};
+
+enum Op {
+    OpNop = 0,
+    OpSource = 1,
+    OpSourceExtension = 2,
+    OpExtension = 3,
+    OpExtInstImport = 4,
+    OpMemoryModel = 5,
+    OpEntryPoint = 6,
+    OpExecutionMode = 7,
+    OpTypeVoid = 8,
+    OpTypeBool = 9,
+    OpTypeInt = 10,
+    OpTypeFloat = 11,
+    OpTypeVector = 12,
+    OpTypeMatrix = 13,
+    OpTypeSampler = 14,
+    OpTypeFilter = 15,
+    OpTypeArray = 16,
+    OpTypeRuntimeArray = 17,
+    OpTypeStruct = 18,
+    OpTypeOpaque = 19,
+    OpTypePointer = 20,
+    OpTypeFunction = 21,
+    OpTypeEvent = 22,
+    OpTypeDeviceEvent = 23,
+    OpTypeReserveId = 24,
+    OpTypeQueue = 25,
+    OpTypePipe = 26,
+    OpConstantTrue = 27,
+    OpConstantFalse = 28,
+    OpConstant = 29,
+    OpConstantComposite = 30,
+    OpConstantSampler = 31,
+    OpConstantNull = 32,
+    OpSpecConstantTrue = 34,
+    OpSpecConstantFalse = 35,
+    OpSpecConstant = 36,
+    OpSpecConstantComposite = 37,
+    OpVariable = 38,
+    OpVariableArray = 39,
+    OpFunction = 40,
+    OpFunctionParameter = 41,
+    OpFunctionEnd = 42,
+    OpFunctionCall = 43,
+    OpExtInst = 44,
+    OpUndef = 45,
+    OpLoad = 46,
+    OpStore = 47,
+    OpPhi = 48,
+    OpDecorationGroup = 49,
+    OpDecorate = 50,
+    OpMemberDecorate = 51,
+    OpGroupDecorate = 52,
+    OpGroupMemberDecorate = 53,
+    OpName = 54,
+    OpMemberName = 55,
+    OpString = 56,
+    OpLine = 57,
+    OpVectorExtractDynamic = 58,
+    OpVectorInsertDynamic = 59,
+    OpVectorShuffle = 60,
+    OpCompositeConstruct = 61,
+    OpCompositeExtract = 62,
+    OpCompositeInsert = 63,
+    OpCopyObject = 64,
+    OpCopyMemory = 65,
+    OpCopyMemorySized = 66,
+    OpSampler = 67,
+    OpTextureSample = 68,
+    OpTextureSampleDref = 69,
+    OpTextureSampleLod = 70,
+    OpTextureSampleProj = 71,
+    OpTextureSampleGrad = 72,
+    OpTextureSampleOffset = 73,
+    OpTextureSampleProjLod = 74,
+    OpTextureSampleProjGrad = 75,
+    OpTextureSampleLodOffset = 76,
+    OpTextureSampleProjOffset = 77,
+    OpTextureSampleGradOffset = 78,
+    OpTextureSampleProjLodOffset = 79,
+    OpTextureSampleProjGradOffset = 80,
+    OpTextureFetchTexelLod = 81,
+    OpTextureFetchTexelOffset = 82,
+    OpTextureFetchSample = 83,
+    OpTextureFetchTexel = 84,
+    OpTextureGather = 85,
+    OpTextureGatherOffset = 86,
+    OpTextureGatherOffsets = 87,
+    OpTextureQuerySizeLod = 88,
+    OpTextureQuerySize = 89,
+    OpTextureQueryLod = 90,
+    OpTextureQueryLevels = 91,
+    OpTextureQuerySamples = 92,
+    OpAccessChain = 93,
+    OpInBoundsAccessChain = 94,
+    OpSNegate = 95,
+    OpFNegate = 96,
+    OpNot = 97,
+    OpAny = 98,
+    OpAll = 99,
+    OpConvertFToU = 100,
+    OpConvertFToS = 101,
+    OpConvertSToF = 102,
+    OpConvertUToF = 103,
+    OpUConvert = 104,
+    OpSConvert = 105,
+    OpFConvert = 106,
+    OpConvertPtrToU = 107,
+    OpConvertUToPtr = 108,
+    OpPtrCastToGeneric = 109,
+    OpGenericCastToPtr = 110,
+    OpBitcast = 111,
+    OpTranspose = 112,
+    OpIsNan = 113,
+    OpIsInf = 114,
+    OpIsFinite = 115,
+    OpIsNormal = 116,
+    OpSignBitSet = 117,
+    OpLessOrGreater = 118,
+    OpOrdered = 119,
+    OpUnordered = 120,
+    OpArrayLength = 121,
+    OpIAdd = 122,
+    OpFAdd = 123,
+    OpISub = 124,
+    OpFSub = 125,
+    OpIMul = 126,
+    OpFMul = 127,
+    OpUDiv = 128,
+    OpSDiv = 129,
+    OpFDiv = 130,
+    OpUMod = 131,
+    OpSRem = 132,
+    OpSMod = 133,
+    OpFRem = 134,
+    OpFMod = 135,
+    OpVectorTimesScalar = 136,
+    OpMatrixTimesScalar = 137,
+    OpVectorTimesMatrix = 138,
+    OpMatrixTimesVector = 139,
+    OpMatrixTimesMatrix = 140,
+    OpOuterProduct = 141,
+    OpDot = 142,
+    OpShiftRightLogical = 143,
+    OpShiftRightArithmetic = 144,
+    OpShiftLeftLogical = 145,
+    OpLogicalOr = 146,
+    OpLogicalXor = 147,
+    OpLogicalAnd = 148,
+    OpBitwiseOr = 149,
+    OpBitwiseXor = 150,
+    OpBitwiseAnd = 151,
+    OpSelect = 152,
+    OpIEqual = 153,
+    OpFOrdEqual = 154,
+    OpFUnordEqual = 155,
+    OpINotEqual = 156,
+    OpFOrdNotEqual = 157,
+    OpFUnordNotEqual = 158,
+    OpULessThan = 159,
+    OpSLessThan = 160,
+    OpFOrdLessThan = 161,
+    OpFUnordLessThan = 162,
+    OpUGreaterThan = 163,
+    OpSGreaterThan = 164,
+    OpFOrdGreaterThan = 165,
+    OpFUnordGreaterThan = 166,
+    OpULessThanEqual = 167,
+    OpSLessThanEqual = 168,
+    OpFOrdLessThanEqual = 169,
+    OpFUnordLessThanEqual = 170,
+    OpUGreaterThanEqual = 171,
+    OpSGreaterThanEqual = 172,
+    OpFOrdGreaterThanEqual = 173,
+    OpFUnordGreaterThanEqual = 174,
+    OpDPdx = 175,
+    OpDPdy = 176,
+    OpFwidth = 177,
+    OpDPdxFine = 178,
+    OpDPdyFine = 179,
+    OpFwidthFine = 180,
+    OpDPdxCoarse = 181,
+    OpDPdyCoarse = 182,
+    OpFwidthCoarse = 183,
+    OpEmitVertex = 184,
+    OpEndPrimitive = 185,
+    OpEmitStreamVertex = 186,
+    OpEndStreamPrimitive = 187,
+    OpControlBarrier = 188,
+    OpMemoryBarrier = 189,
+    OpImagePointer = 190,
+    OpAtomicInit = 191,
+    OpAtomicLoad = 192,
+    OpAtomicStore = 193,
+    OpAtomicExchange = 194,
+    OpAtomicCompareExchange = 195,
+    OpAtomicCompareExchangeWeak = 196,
+    OpAtomicIIncrement = 197,
+    OpAtomicIDecrement = 198,
+    OpAtomicIAdd = 199,
+    OpAtomicISub = 200,
+    OpAtomicUMin = 201,
+    OpAtomicUMax = 202,
+    OpAtomicAnd = 203,
+    OpAtomicOr = 204,
+    OpAtomicXor = 205,
+    OpLoopMerge = 206,
+    OpSelectionMerge = 207,
+    OpLabel = 208,
+    OpBranch = 209,
+    OpBranchConditional = 210,
+    OpSwitch = 211,
+    OpKill = 212,
+    OpReturn = 213,
+    OpReturnValue = 214,
+    OpUnreachable = 215,
+    OpLifetimeStart = 216,
+    OpLifetimeStop = 217,
+    OpCompileFlag = 218,
+    OpAsyncGroupCopy = 219,
+    OpWaitGroupEvents = 220,
+    OpGroupAll = 221,
+    OpGroupAny = 222,
+    OpGroupBroadcast = 223,
+    OpGroupIAdd = 224,
+    OpGroupFAdd = 225,
+    OpGroupFMin = 226,
+    OpGroupUMin = 227,
+    OpGroupSMin = 228,
+    OpGroupFMax = 229,
+    OpGroupUMax = 230,
+    OpGroupSMax = 231,
+    OpGenericCastToPtrExplicit = 232,
+    OpGenericPtrMemSemantics = 233,
+    OpReadPipe = 234,
+    OpWritePipe = 235,
+    OpReservedReadPipe = 236,
+    OpReservedWritePipe = 237,
+    OpReserveReadPipePackets = 238,
+    OpReserveWritePipePackets = 239,
+    OpCommitReadPipe = 240,
+    OpCommitWritePipe = 241,
+    OpIsValidReserveId = 242,
+    OpGetNumPipePackets = 243,
+    OpGetMaxPipePackets = 244,
+    OpGroupReserveReadPipePackets = 245,
+    OpGroupReserveWritePipePackets = 246,
+    OpGroupCommitReadPipe = 247,
+    OpGroupCommitWritePipe = 248,
+    OpEnqueueMarker = 249,
+    OpEnqueueKernel = 250,
+    OpGetKernelNDrangeSubGroupCount = 251,
+    OpGetKernelNDrangeMaxSubGroupSize = 252,
+    OpGetKernelWorkGroupSize = 253,
+    OpGetKernelPreferredWorkGroupSizeMultiple = 254,
+    OpRetainEvent = 255,
+    OpReleaseEvent = 256,
+    OpCreateUserEvent = 257,
+    OpIsValidEvent = 258,
+    OpSetUserEventStatus = 259,
+    OpCaptureEventProfilingInfo = 260,
+    OpGetDefaultQueue = 261,
+    OpBuildNDRange = 262,
+    OpSatConvertSToU = 263,
+    OpSatConvertUToS = 264,
+    OpAtomicIMin = 265,
+    OpAtomicIMax = 266,
+    OpSpecConstantOp = 267,
+    OpCapability = 268,
+};
+
+};  // end namespace spv
+
+#endif  // #ifdef __cplusplus
+
+
+#ifndef __cplusplus
+
+static const int SpvMagicNumber = 0x07230203;
+static const int SpvVersion = 99;
+
+typedef unsigned int SpvId;
+
+static const unsigned int SpvOpCodeMask = 0xFFFF;
+static const unsigned int SpvWordCountShift = 16;
+
+typedef enum SpvSourceLanguage_ {
+    SpvSourceLanguageUnknown = 0,
+    SpvSourceLanguageESSL = 1,
+    SpvSourceLanguageGLSL = 2,
+    SpvSourceLanguageOpenCL = 3,
+} SpvSourceLanguage;
+
+typedef enum SpvExecutionModel_ {
+    SpvExecutionModelVertex = 0,
+    SpvExecutionModelTessellationControl = 1,
+    SpvExecutionModelTessellationEvaluation = 2,
+    SpvExecutionModelGeometry = 3,
+    SpvExecutionModelFragment = 4,
+    SpvExecutionModelGLCompute = 5,
+    SpvExecutionModelKernel = 6,
+} SpvExecutionModel;
+
+typedef enum SpvAddressingModel_ {
+    SpvAddressingModelLogical = 0,
+    SpvAddressingModelPhysical32 = 1,
+    SpvAddressingModelPhysical64 = 2,
+} SpvAddressingModel;
+
+typedef enum SpvMemoryModel_ {
+    SpvMemoryModelSimple = 0,
+    SpvMemoryModelGLSL450 = 1,
+    SpvMemoryModelOpenCL12 = 2,
+    SpvMemoryModelOpenCL20 = 3,
+    SpvMemoryModelOpenCL21 = 4,
+} SpvMemoryModel;
+
+typedef enum SpvExecutionMode_ {
+    SpvExecutionModeInvocations = 0,
+    SpvExecutionModeSpacingEqual = 1,
+    SpvExecutionModeSpacingFractionalEven = 2,
+    SpvExecutionModeSpacingFractionalOdd = 3,
+    SpvExecutionModeVertexOrderCw = 4,
+    SpvExecutionModeVertexOrderCcw = 5,
+    SpvExecutionModePixelCenterInteger = 6,
+    SpvExecutionModeOriginUpperLeft = 7,
+    SpvExecutionModeEarlyFragmentTests = 8,
+    SpvExecutionModePointMode = 9,
+    SpvExecutionModeXfb = 10,
+    SpvExecutionModeDepthReplacing = 11,
+    SpvExecutionModeDepthAny = 12,
+    SpvExecutionModeDepthGreater = 13,
+    SpvExecutionModeDepthLess = 14,
+    SpvExecutionModeDepthUnchanged = 15,
+    SpvExecutionModeLocalSize = 16,
+    SpvExecutionModeLocalSizeHint = 17,
+    SpvExecutionModeInputPoints = 18,
+    SpvExecutionModeInputLines = 19,
+    SpvExecutionModeInputLinesAdjacency = 20,
+    SpvExecutionModeInputTriangles = 21,
+    SpvExecutionModeInputTrianglesAdjacency = 22,
+    SpvExecutionModeInputQuads = 23,
+    SpvExecutionModeInputIsolines = 24,
+    SpvExecutionModeOutputVertices = 25,
+    SpvExecutionModeOutputPoints = 26,
+    SpvExecutionModeOutputLineStrip = 27,
+    SpvExecutionModeOutputTriangleStrip = 28,
+    SpvExecutionModeVecTypeHint = 29,
+    SpvExecutionModeContractionOff = 30,
+    SpvExecutionModeOriginLowerLeft = 31,
+} SpvExecutionMode;
+
+typedef enum SpvStorageClass_ {
+    SpvStorageClassUniformConstant = 0,
+    SpvStorageClassInput = 1,
+    SpvStorageClassUniform = 2,
+    SpvStorageClassOutput = 3,
+    SpvStorageClassWorkgroupLocal = 4,
+    SpvStorageClassWorkgroupGlobal = 5,
+    SpvStorageClassPrivateGlobal = 6,
+    SpvStorageClassFunction = 7,
+    SpvStorageClassGeneric = 8,
+    SpvStorageClassAtomicCounter = 10,
+} SpvStorageClass;
+
+typedef enum SpvDim_ {
+    SpvDim1D = 0,
+    SpvDim2D = 1,
+    SpvDim3D = 2,
+    SpvDimCube = 3,
+    SpvDimRect = 4,
+    SpvDimBuffer = 5,
+} SpvDim;
+
+typedef enum SpvSamplerAddressingMode_ {
+    SpvSamplerAddressingModeNone = 0,
+    SpvSamplerAddressingModeClampToEdge = 1,
+    SpvSamplerAddressingModeClamp = 2,
+    SpvSamplerAddressingModeRepeat = 3,
+    SpvSamplerAddressingModeRepeatMirrored = 4,
+} SpvSamplerAddressingMode;
+
+typedef enum SpvSamplerFilterMode_ {
+    SpvSamplerFilterModeNearest = 0,
+    SpvSamplerFilterModeLinear = 1,
+} SpvSamplerFilterMode;
+
+typedef enum SpvFPFastMathModeShift_ {
+    SpvFPFastMathModeNotNaNShift = 0,
+    SpvFPFastMathModeNotInfShift = 1,
+    SpvFPFastMathModeNSZShift = 2,
+    SpvFPFastMathModeAllowRecipShift = 3,
+    SpvFPFastMathModeFastShift = 4,
+} SpvFPFastMathModeShift;
+
+typedef enum SpvFPFastMathModeMask_ {
+    SpvFPFastMathModeMaskNone = 0,
+    SpvFPFastMathModeNotNaNMask = 0x00000001,
+    SpvFPFastMathModeNotInfMask = 0x00000002,
+    SpvFPFastMathModeNSZMask = 0x00000004,
+    SpvFPFastMathModeAllowRecipMask = 0x00000008,
+    SpvFPFastMathModeFastMask = 0x00000010,
+} SpvFPFastMathModeMask;
+
+typedef enum SpvFPRoundingMode_ {
+    SpvFPRoundingModeRTE = 0,
+    SpvFPRoundingModeRTZ = 1,
+    SpvFPRoundingModeRTP = 2,
+    SpvFPRoundingModeRTN = 3,
+} SpvFPRoundingMode;
+
+typedef enum SpvLinkageType_ {
+    SpvLinkageTypeExport = 0,
+    SpvLinkageTypeImport = 1,
+} SpvLinkageType;
+
+typedef enum SpvAccessQualifier_ {
+    SpvAccessQualifierReadOnly = 0,
+    SpvAccessQualifierWriteOnly = 1,
+    SpvAccessQualifierReadWrite = 2,
+} SpvAccessQualifier;
+
+typedef enum SpvFunctionParameterAttribute_ {
+    SpvFunctionParameterAttributeZext = 0,
+    SpvFunctionParameterAttributeSext = 1,
+    SpvFunctionParameterAttributeByVal = 2,
+    SpvFunctionParameterAttributeSret = 3,
+    SpvFunctionParameterAttributeNoAlias = 4,
+    SpvFunctionParameterAttributeNoCapture = 5,
+    SpvFunctionParameterAttributeSVM = 6,
+    SpvFunctionParameterAttributeNoWrite = 7,
+    SpvFunctionParameterAttributeNoReadWrite = 8,
+} SpvFunctionParameterAttribute;
+
+typedef enum SpvDecoration_ {
+    SpvDecorationPrecisionLow = 0,
+    SpvDecorationPrecisionMedium = 1,
+    SpvDecorationPrecisionHigh = 2,
+    SpvDecorationBlock = 3,
+    SpvDecorationBufferBlock = 4,
+    SpvDecorationRowMajor = 5,
+    SpvDecorationColMajor = 6,
+    SpvDecorationGLSLShared = 7,
+    SpvDecorationGLSLStd140 = 8,
+    SpvDecorationGLSLStd430 = 9,
+    SpvDecorationGLSLPacked = 10,
+    SpvDecorationSmooth = 11,
+    SpvDecorationNoperspective = 12,
+    SpvDecorationFlat = 13,
+    SpvDecorationPatch = 14,
+    SpvDecorationCentroid = 15,
+    SpvDecorationSample = 16,
+    SpvDecorationInvariant = 17,
+    SpvDecorationRestrict = 18,
+    SpvDecorationAliased = 19,
+    SpvDecorationVolatile = 20,
+    SpvDecorationConstant = 21,
+    SpvDecorationCoherent = 22,
+    SpvDecorationNonwritable = 23,
+    SpvDecorationNonreadable = 24,
+    SpvDecorationUniform = 25,
+    SpvDecorationNoStaticUse = 26,
+    SpvDecorationCPacked = 27,
+    SpvDecorationSaturatedConversion = 28,
+    SpvDecorationStream = 29,
+    SpvDecorationLocation = 30,
+    SpvDecorationComponent = 31,
+    SpvDecorationIndex = 32,
+    SpvDecorationBinding = 33,
+    SpvDecorationDescriptorSet = 34,
+    SpvDecorationOffset = 35,
+    SpvDecorationAlignment = 36,
+    SpvDecorationXfbBuffer = 37,
+    SpvDecorationStride = 38,
+    SpvDecorationBuiltIn = 39,
+    SpvDecorationFuncParamAttr = 40,
+    SpvDecorationFPRoundingMode = 41,
+    SpvDecorationFPFastMathMode = 42,
+    SpvDecorationLinkageAttributes = 43,
+    SpvDecorationSpecId = 44,
+} SpvDecoration;
+
+typedef enum SpvBuiltIn_ {
+    SpvBuiltInPosition = 0,
+    SpvBuiltInPointSize = 1,
+    SpvBuiltInClipVertex = 2,
+    SpvBuiltInClipDistance = 3,
+    SpvBuiltInCullDistance = 4,
+    SpvBuiltInVertexId = 5,
+    SpvBuiltInInstanceId = 6,
+    SpvBuiltInPrimitiveId = 7,
+    SpvBuiltInInvocationId = 8,
+    SpvBuiltInLayer = 9,
+    SpvBuiltInViewportIndex = 10,
+    SpvBuiltInTessLevelOuter = 11,
+    SpvBuiltInTessLevelInner = 12,
+    SpvBuiltInTessCoord = 13,
+    SpvBuiltInPatchVertices = 14,
+    SpvBuiltInFragCoord = 15,
+    SpvBuiltInPointCoord = 16,
+    SpvBuiltInFrontFacing = 17,
+    SpvBuiltInSampleId = 18,
+    SpvBuiltInSamplePosition = 19,
+    SpvBuiltInSampleMask = 20,
+    SpvBuiltInFragColor = 21,
+    SpvBuiltInFragDepth = 22,
+    SpvBuiltInHelperInvocation = 23,
+    SpvBuiltInNumWorkgroups = 24,
+    SpvBuiltInWorkgroupSize = 25,
+    SpvBuiltInWorkgroupId = 26,
+    SpvBuiltInLocalInvocationId = 27,
+    SpvBuiltInGlobalInvocationId = 28,
+    SpvBuiltInLocalInvocationIndex = 29,
+    SpvBuiltInWorkDim = 30,
+    SpvBuiltInGlobalSize = 31,
+    SpvBuiltInEnqueuedWorkgroupSize = 32,
+    SpvBuiltInGlobalOffset = 33,
+    SpvBuiltInGlobalLinearId = 34,
+    SpvBuiltInWorkgroupLinearId = 35,
+    SpvBuiltInSubgroupSize = 36,
+    SpvBuiltInSubgroupMaxSize = 37,
+    SpvBuiltInNumSubgroups = 38,
+    SpvBuiltInNumEnqueuedSubgroups = 39,
+    SpvBuiltInSubgroupId = 40,
+    SpvBuiltInSubgroupLocalInvocationId = 41,
+} SpvBuiltIn;
+
+typedef enum SpvSelectionControlShift_ {
+    SpvSelectionControlFlattenShift = 0,
+    SpvSelectionControlDontFlattenShift = 1,
+} SpvSelectionControlShift;
+
+typedef enum SpvSelectionControlMask_ {
+    SpvSelectionControlMaskNone = 0,
+    SpvSelectionControlFlattenMask = 0x00000001,
+    SpvSelectionControlDontFlattenMask = 0x00000002,
+} SpvSelectionControlMask;
+
+typedef enum SpvLoopControlShift_ {
+    SpvLoopControlUnrollShift = 0,
+    SpvLoopControlDontUnrollShift = 1,
+} SpvLoopControlShift;
+
+typedef enum SpvLoopControlMask_ {
+    SpvLoopControlMaskNone = 0,
+    SpvLoopControlUnrollMask = 0x00000001,
+    SpvLoopControlDontUnrollMask = 0x00000002,
+} SpvLoopControlMask;
+
+typedef enum SpvFunctionControlShift_ {
+    SpvFunctionControlInlineShift = 0,
+    SpvFunctionControlDontInlineShift = 1,
+    SpvFunctionControlPureShift = 2,
+    SpvFunctionControlConstShift = 3,
+} SpvFunctionControlShift;
+
+typedef enum SpvFunctionControlMask_ {
+    SpvFunctionControlMaskNone = 0,
+    SpvFunctionControlInlineMask = 0x00000001,
+    SpvFunctionControlDontInlineMask = 0x00000002,
+    SpvFunctionControlPureMask = 0x00000004,
+    SpvFunctionControlConstMask = 0x00000008,
+} SpvFunctionControlMask;
+
+typedef enum SpvMemorySemanticsShift_ {
+    SpvMemorySemanticsRelaxedShift = 0,
+    SpvMemorySemanticsSequentiallyConsistentShift = 1,
+    SpvMemorySemanticsAcquireShift = 2,
+    SpvMemorySemanticsReleaseShift = 3,
+    SpvMemorySemanticsUniformMemoryShift = 4,
+    SpvMemorySemanticsSubgroupMemoryShift = 5,
+    SpvMemorySemanticsWorkgroupLocalMemoryShift = 6,
+    SpvMemorySemanticsWorkgroupGlobalMemoryShift = 7,
+    SpvMemorySemanticsAtomicCounterMemoryShift = 8,
+    SpvMemorySemanticsImageMemoryShift = 9,
+} SpvMemorySemanticsShift;
+
+typedef enum SpvMemorySemanticsMask_ {
+    SpvMemorySemanticsMaskNone = 0,
+    SpvMemorySemanticsRelaxedMask = 0x00000001,
+    SpvMemorySemanticsSequentiallyConsistentMask = 0x00000002,
+    SpvMemorySemanticsAcquireMask = 0x00000004,
+    SpvMemorySemanticsReleaseMask = 0x00000008,
+    SpvMemorySemanticsUniformMemoryMask = 0x00000010,
+    SpvMemorySemanticsSubgroupMemoryMask = 0x00000020,
+    SpvMemorySemanticsWorkgroupLocalMemoryMask = 0x00000040,
+    SpvMemorySemanticsWorkgroupGlobalMemoryMask = 0x00000080,
+    SpvMemorySemanticsAtomicCounterMemoryMask = 0x00000100,
+    SpvMemorySemanticsImageMemoryMask = 0x00000200,
+} SpvMemorySemanticsMask;
+
+typedef enum SpvMemoryAccessShift_ {
+    SpvMemoryAccessVolatileShift = 0,
+    SpvMemoryAccessAlignedShift = 1,
+} SpvMemoryAccessShift;
+
+typedef enum SpvMemoryAccessMask_ {
+    SpvMemoryAccessMaskNone = 0,
+    SpvMemoryAccessVolatileMask = 0x00000001,
+    SpvMemoryAccessAlignedMask = 0x00000002,
+} SpvMemoryAccessMask;
+
+typedef enum SpvScope_ {
+    SpvScopeCrossDevice = 0,
+    SpvScopeDevice = 1,
+    SpvScopeWorkgroup = 2,
+    SpvScopeSubgroup = 3,
+    SpvScopeInvocation = 4,
+} SpvScope;
+
+typedef enum SpvGroupOperation_ {
+    SpvGroupOperationReduce = 0,
+    SpvGroupOperationInclusiveScan = 1,
+    SpvGroupOperationExclusiveScan = 2,
+} SpvGroupOperation;
+
+typedef enum SpvKernelEnqueueFlags_ {
+    SpvKernelEnqueueFlagsNoWait = 0,
+    SpvKernelEnqueueFlagsWaitKernel = 1,
+    SpvKernelEnqueueFlagsWaitWorkGroup = 2,
+} SpvKernelEnqueueFlags;
+
+typedef enum SpvKernelProfilingInfoShift_ {
+    SpvKernelProfilingInfoCmdExecTimeShift = 0,
+} SpvKernelProfilingInfoShift;
+
+typedef enum SpvKernelProfilingInfoMask_ {
+    SpvKernelProfilingInfoMaskNone = 0,
+    SpvKernelProfilingInfoCmdExecTimeMask = 0x00000001,
+} SpvKernelProfilingInfoMask;
+
+typedef enum SpvCapability_ {
+    SpvCapabilityMatrix = 0,
+    SpvCapabilityShader = 1,
+    SpvCapabilityGeometry = 2,
+    SpvCapabilityTessellation = 3,
+    SpvCapabilityAddresses = 4,
+    SpvCapabilityLinkage = 5,
+    SpvCapabilityKernel = 6,
+    SpvCapabilityVector16 = 7,
+    SpvCapabilityFloat16Buffer = 8,
+    SpvCapabilityFloat16 = 9,
+    SpvCapabilityFloat64 = 10,
+    SpvCapabilityInt64 = 11,
+    SpvCapabilityInt64Atomics = 12,
+    SpvCapabilityImageBasic = 13,
+    SpvCapabilityImageReadWrite = 14,
+    SpvCapabilityImageMipmap = 15,
+    SpvCapabilityImageSRGBWrite = 16,
+    SpvCapabilityPipes = 17,
+    SpvCapabilityGroups = 18,
+    SpvCapabilityDeviceEnqueue = 19,
+} SpvCapability;
+
+typedef enum SpvOp_ {
+    SpvOpNop = 0,
+    SpvOpSource = 1,
+    SpvOpSourceExtension = 2,
+    SpvOpExtension = 3,
+    SpvOpExtInstImport = 4,
+    SpvOpMemoryModel = 5,
+    SpvOpEntryPoint = 6,
+    SpvOpExecutionMode = 7,
+    SpvOpTypeVoid = 8,
+    SpvOpTypeBool = 9,
+    SpvOpTypeInt = 10,
+    SpvOpTypeFloat = 11,
+    SpvOpTypeVector = 12,
+    SpvOpTypeMatrix = 13,
+    SpvOpTypeSampler = 14,
+    SpvOpTypeFilter = 15,
+    SpvOpTypeArray = 16,
+    SpvOpTypeRuntimeArray = 17,
+    SpvOpTypeStruct = 18,
+    SpvOpTypeOpaque = 19,
+    SpvOpTypePointer = 20,
+    SpvOpTypeFunction = 21,
+    SpvOpTypeEvent = 22,
+    SpvOpTypeDeviceEvent = 23,
+    SpvOpTypeReserveId = 24,
+    SpvOpTypeQueue = 25,
+    SpvOpTypePipe = 26,
+    SpvOpConstantTrue = 27,
+    SpvOpConstantFalse = 28,
+    SpvOpConstant = 29,
+    SpvOpConstantComposite = 30,
+    SpvOpConstantSampler = 31,
+    SpvOpConstantNull = 32,
+    SpvOpSpecConstantTrue = 34,
+    SpvOpSpecConstantFalse = 35,
+    SpvOpSpecConstant = 36,
+    SpvOpSpecConstantComposite = 37,
+    SpvOpVariable = 38,
+    SpvOpVariableArray = 39,
+    SpvOpFunction = 40,
+    SpvOpFunctionParameter = 41,
+    SpvOpFunctionEnd = 42,
+    SpvOpFunctionCall = 43,
+    SpvOpExtInst = 44,
+    SpvOpUndef = 45,
+    SpvOpLoad = 46,
+    SpvOpStore = 47,
+    SpvOpPhi = 48,
+    SpvOpDecorationGroup = 49,
+    SpvOpDecorate = 50,
+    SpvOpMemberDecorate = 51,
+    SpvOpGroupDecorate = 52,
+    SpvOpGroupMemberDecorate = 53,
+    SpvOpName = 54,
+    SpvOpMemberName = 55,
+    SpvOpString = 56,
+    SpvOpLine = 57,
+    SpvOpVectorExtractDynamic = 58,
+    SpvOpVectorInsertDynamic = 59,
+    SpvOpVectorShuffle = 60,
+    SpvOpCompositeConstruct = 61,
+    SpvOpCompositeExtract = 62,
+    SpvOpCompositeInsert = 63,
+    SpvOpCopyObject = 64,
+    SpvOpCopyMemory = 65,
+    SpvOpCopyMemorySized = 66,
+    SpvOpSampler = 67,
+    SpvOpTextureSample = 68,
+    SpvOpTextureSampleDref = 69,
+    SpvOpTextureSampleLod = 70,
+    SpvOpTextureSampleProj = 71,
+    SpvOpTextureSampleGrad = 72,
+    SpvOpTextureSampleOffset = 73,
+    SpvOpTextureSampleProjLod = 74,
+    SpvOpTextureSampleProjGrad = 75,
+    SpvOpTextureSampleLodOffset = 76,
+    SpvOpTextureSampleProjOffset = 77,
+    SpvOpTextureSampleGradOffset = 78,
+    SpvOpTextureSampleProjLodOffset = 79,
+    SpvOpTextureSampleProjGradOffset = 80,
+    SpvOpTextureFetchTexelLod = 81,
+    SpvOpTextureFetchTexelOffset = 82,
+    SpvOpTextureFetchSample = 83,
+    SpvOpTextureFetchTexel = 84,
+    SpvOpTextureGather = 85,
+    SpvOpTextureGatherOffset = 86,
+    SpvOpTextureGatherOffsets = 87,
+    SpvOpTextureQuerySizeLod = 88,
+    SpvOpTextureQuerySize = 89,
+    SpvOpTextureQueryLod = 90,
+    SpvOpTextureQueryLevels = 91,
+    SpvOpTextureQuerySamples = 92,
+    SpvOpAccessChain = 93,
+    SpvOpInBoundsAccessChain = 94,
+    SpvOpSNegate = 95,
+    SpvOpFNegate = 96,
+    SpvOpNot = 97,
+    SpvOpAny = 98,
+    SpvOpAll = 99,
+    SpvOpConvertFToU = 100,
+    SpvOpConvertFToS = 101,
+    SpvOpConvertSToF = 102,
+    SpvOpConvertUToF = 103,
+    SpvOpUConvert = 104,
+    SpvOpSConvert = 105,
+    SpvOpFConvert = 106,
+    SpvOpConvertPtrToU = 107,
+    SpvOpConvertUToPtr = 108,
+    SpvOpPtrCastToGeneric = 109,
+    SpvOpGenericCastToPtr = 110,
+    SpvOpBitcast = 111,
+    SpvOpTranspose = 112,
+    SpvOpIsNan = 113,
+    SpvOpIsInf = 114,
+    SpvOpIsFinite = 115,
+    SpvOpIsNormal = 116,
+    SpvOpSignBitSet = 117,
+    SpvOpLessOrGreater = 118,
+    SpvOpOrdered = 119,
+    SpvOpUnordered = 120,
+    SpvOpArrayLength = 121,
+    SpvOpIAdd = 122,
+    SpvOpFAdd = 123,
+    SpvOpISub = 124,
+    SpvOpFSub = 125,
+    SpvOpIMul = 126,
+    SpvOpFMul = 127,
+    SpvOpUDiv = 128,
+    SpvOpSDiv = 129,
+    SpvOpFDiv = 130,
+    SpvOpUMod = 131,
+    SpvOpSRem = 132,
+    SpvOpSMod = 133,
+    SpvOpFRem = 134,
+    SpvOpFMod = 135,
+    SpvOpVectorTimesScalar = 136,
+    SpvOpMatrixTimesScalar = 137,
+    SpvOpVectorTimesMatrix = 138,
+    SpvOpMatrixTimesVector = 139,
+    SpvOpMatrixTimesMatrix = 140,
+    SpvOpOuterProduct = 141,
+    SpvOpDot = 142,
+    SpvOpShiftRightLogical = 143,
+    SpvOpShiftRightArithmetic = 144,
+    SpvOpShiftLeftLogical = 145,
+    SpvOpLogicalOr = 146,
+    SpvOpLogicalXor = 147,
+    SpvOpLogicalAnd = 148,
+    SpvOpBitwiseOr = 149,
+    SpvOpBitwiseXor = 150,
+    SpvOpBitwiseAnd = 151,
+    SpvOpSelect = 152,
+    SpvOpIEqual = 153,
+    SpvOpFOrdEqual = 154,
+    SpvOpFUnordEqual = 155,
+    SpvOpINotEqual = 156,
+    SpvOpFOrdNotEqual = 157,
+    SpvOpFUnordNotEqual = 158,
+    SpvOpULessThan = 159,
+    SpvOpSLessThan = 160,
+    SpvOpFOrdLessThan = 161,
+    SpvOpFUnordLessThan = 162,
+    SpvOpUGreaterThan = 163,
+    SpvOpSGreaterThan = 164,
+    SpvOpFOrdGreaterThan = 165,
+    SpvOpFUnordGreaterThan = 166,
+    SpvOpULessThanEqual = 167,
+    SpvOpSLessThanEqual = 168,
+    SpvOpFOrdLessThanEqual = 169,
+    SpvOpFUnordLessThanEqual = 170,
+    SpvOpUGreaterThanEqual = 171,
+    SpvOpSGreaterThanEqual = 172,
+    SpvOpFOrdGreaterThanEqual = 173,
+    SpvOpFUnordGreaterThanEqual = 174,
+    SpvOpDPdx = 175,
+    SpvOpDPdy = 176,
+    SpvOpFwidth = 177,
+    SpvOpDPdxFine = 178,
+    SpvOpDPdyFine = 179,
+    SpvOpFwidthFine = 180,
+    SpvOpDPdxCoarse = 181,
+    SpvOpDPdyCoarse = 182,
+    SpvOpFwidthCoarse = 183,
+    SpvOpEmitVertex = 184,
+    SpvOpEndPrimitive = 185,
+    SpvOpEmitStreamVertex = 186,
+    SpvOpEndStreamPrimitive = 187,
+    SpvOpControlBarrier = 188,
+    SpvOpMemoryBarrier = 189,
+    SpvOpImagePointer = 190,
+    SpvOpAtomicInit = 191,
+    SpvOpAtomicLoad = 192,
+    SpvOpAtomicStore = 193,
+    SpvOpAtomicExchange = 194,
+    SpvOpAtomicCompareExchange = 195,
+    SpvOpAtomicCompareExchangeWeak = 196,
+    SpvOpAtomicIIncrement = 197,
+    SpvOpAtomicIDecrement = 198,
+    SpvOpAtomicIAdd = 199,
+    SpvOpAtomicISub = 200,
+    SpvOpAtomicUMin = 201,
+    SpvOpAtomicUMax = 202,
+    SpvOpAtomicAnd = 203,
+    SpvOpAtomicOr = 204,
+    SpvOpAtomicXor = 205,
+    SpvOpLoopMerge = 206,
+    SpvOpSelectionMerge = 207,
+    SpvOpLabel = 208,
+    SpvOpBranch = 209,
+    SpvOpBranchConditional = 210,
+    SpvOpSwitch = 211,
+    SpvOpKill = 212,
+    SpvOpReturn = 213,
+    SpvOpReturnValue = 214,
+    SpvOpUnreachable = 215,
+    SpvOpLifetimeStart = 216,
+    SpvOpLifetimeStop = 217,
+    SpvOpCompileFlag = 218,
+    SpvOpAsyncGroupCopy = 219,
+    SpvOpWaitGroupEvents = 220,
+    SpvOpGroupAll = 221,
+    SpvOpGroupAny = 222,
+    SpvOpGroupBroadcast = 223,
+    SpvOpGroupIAdd = 224,
+    SpvOpGroupFAdd = 225,
+    SpvOpGroupFMin = 226,
+    SpvOpGroupUMin = 227,
+    SpvOpGroupSMin = 228,
+    SpvOpGroupFMax = 229,
+    SpvOpGroupUMax = 230,
+    SpvOpGroupSMax = 231,
+    SpvOpGenericCastToPtrExplicit = 232,
+    SpvOpGenericPtrMemSemantics = 233,
+    SpvOpReadPipe = 234,
+    SpvOpWritePipe = 235,
+    SpvOpReservedReadPipe = 236,
+    SpvOpReservedWritePipe = 237,
+    SpvOpReserveReadPipePackets = 238,
+    SpvOpReserveWritePipePackets = 239,
+    SpvOpCommitReadPipe = 240,
+    SpvOpCommitWritePipe = 241,
+    SpvOpIsValidReserveId = 242,
+    SpvOpGetNumPipePackets = 243,
+    SpvOpGetMaxPipePackets = 244,
+    SpvOpGroupReserveReadPipePackets = 245,
+    SpvOpGroupReserveWritePipePackets = 246,
+    SpvOpGroupCommitReadPipe = 247,
+    SpvOpGroupCommitWritePipe = 248,
+    SpvOpEnqueueMarker = 249,
+    SpvOpEnqueueKernel = 250,
+    SpvOpGetKernelNDrangeSubGroupCount = 251,
+    SpvOpGetKernelNDrangeMaxSubGroupSize = 252,
+    SpvOpGetKernelWorkGroupSize = 253,
+    SpvOpGetKernelPreferredWorkGroupSizeMultiple = 254,
+    SpvOpRetainEvent = 255,
+    SpvOpReleaseEvent = 256,
+    SpvOpCreateUserEvent = 257,
+    SpvOpIsValidEvent = 258,
+    SpvOpSetUserEventStatus = 259,
+    SpvOpCaptureEventProfilingInfo = 260,
+    SpvOpGetDefaultQueue = 261,
+    SpvOpBuildNDRange = 262,
+    SpvOpSatConvertSToU = 263,
+    SpvOpSatConvertUToS = 264,
+    SpvOpAtomicIMin = 265,
+    SpvOpAtomicIMax = 266,
+    SpvOpSpecConstantOp = 267,
+    SpvOpCapability = 268,
+} SpvOp;
+
+#endif  // #ifndef __cplusplus
+
+#endif  // #ifndef spirv_H
diff --git a/include/libspirv/libspirv.h b/include/libspirv/libspirv.h
new file mode 100644 (file)
index 0000000..fcb24b4
--- /dev/null
@@ -0,0 +1,423 @@
+// Copyright (c) 2015 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.
+
+#ifndef _CODEPLAY_SPIRV_SPIRV_H_
+#define _CODEPLAY_SPIRV_SPIRV_H_
+
+#include <headers/spirv.h>
+#include <headers/GLSL450Lib.h>
+#include <headers/OpenCLLib.h>
+
+#ifdef __cplusplus
+using namespace spv;
+extern "C" {
+#endif
+
+#include <stddef.h>
+#include <stdint.h>
+
+// Magic numbers
+
+#define SPV_MAGIC_NUMBER 0x07230203
+#define SPV_VERSION_NUMBER 99u
+
+// Header indices
+
+#define SPV_INDEX_MAGIC_NUMBER 0u
+#define SPV_INDEX_VERSION_NUMBER 1u
+#define SPV_INDEX_GENERATOR_NUMBER 2u
+#define SPV_INDEX_BOUND 3u
+#define SPV_INDEX_SCHEMA 4u
+#define SPV_INDEX_INSTRUCTION 5u
+
+// Universal limits
+
+// NOTE: These are set to the minimum maximum values
+#define SPV_LIMIT_LITERAL_NAME_MAX 0x00000400
+#define SPV_LIMIT_LITERAL_STRING_MAX 0x00010000
+#define SPV_LIMIT_INSTRUCTION_WORD_COUNT_MAX 0x00000108
+#define SPV_LIMIT_RESULT_ID_BOUND 0x00400000
+#define SPV_LIMIT_CONTROL_FLOW_NEST_DEPTH 0x00000400
+#define SPV_LIMIT_GLOBAL_VARIABLES_MAX 0x00010000
+#define SPV_LIMIT_LOCAL_VARIABLES_MAX 0x00080000
+// TODO: Decorations per target ID max, depends on decoration table size
+#define SPV_LIMIT_EXECUTION_MODE_PER_ENTRY_POINT_MAX 0x00000100
+#define SPV_LIMIT_INDICIES_MAX_ACCESS_CHAIN_COMPOSITE_MAX 0x00000100
+#define SPV_LIMIT_FUNCTION_PARAMETERS_PER_FUNCTION_DECL 0x00000100
+#define SPV_LIMIT_FUNCTION_CALL_ARGUMENTS_MAX 0x00000100
+#define SPV_LIMIT_EXT_FUNCTION_CALL_ARGUMENTS_MAX 0x00000100
+#define SPV_LIMIT_SWITCH_LITERAL_LABEL_PAIRS_MAX 0x00004000
+#define SPV_LIMIT_STRUCT_MEMBERS_MAX 0x0000400
+#define SPV_LIMIT_STRUCT_NESTING_DEPTH_MAX 0x00000100
+
+// Helpers
+
+#define spvCheck(condition, action) \
+  if (condition) {                  \
+    action;                         \
+  }
+
+#define spvCheckReturn(expression)     \
+  {                                    \
+    spv_result_t error = (expression); \
+    if (error) {                       \
+      return error;                    \
+    }                                  \
+  }
+
+#define spvIsInBitfield(value, bitfield) (value == (value & bitfield))
+
+#define SPV_BIT(shift) 1 << shift
+
+#define SPV_FORCE_16_BIT_ENUM(name) _##name = 0x7fff
+#define SPV_FORCE_32_BIT_ENUM(name) _##name = 0x7fffffff
+
+// Enumerations
+
+typedef enum spv_generator_t {
+  SPV_GENERATOR_KHRONOS = 0,
+  SPV_GENERATOR_VALVE = 1,
+  SPV_GENERATOR_LUNARG = 2,
+  SPV_GENERATOR_CODEPLAY = 3,
+  SPV_FORCE_32_BIT_ENUM(spv_generator_t)
+} spv_generator_t;
+
+typedef enum spv_result_t {
+  SPV_SUCCESS = 0,
+  SPV_UNSUPPORTED = 1,
+  SPV_END_OF_STREAM = 2,
+  SPV_WARNING = 3,
+  SPV_ERROR_INTERNAL = -1,
+  SPV_ERROR_OUT_OF_MEMORY = -2,
+  SPV_ERROR_INVALID_POINTER = -3,
+  SPV_ERROR_INVALID_BINARY = -4,
+  SPV_ERROR_INVALID_TEXT = -5,
+  SPV_ERROR_INVALID_TABLE = -6,
+  SPV_ERROR_INVALID_VALUE = -7,
+  SPV_ERROR_INVALID_DIAGNOSTIC = -8,
+  SPV_ERROR_INVALID_LOOKUP = -9,
+  SPV_ERROR_INVALID_ID = -10,
+  SPV_FORCE_32_BIT_ENUM(spv_result_t)
+} spv_result_t;
+
+typedef enum spv_endianness_t {
+  SPV_ENDIANNESS_LITTLE,
+  SPV_ENDIANNESS_BIG,
+  SPV_FORCE_32_BIT_ENUM(spv_endianness_t)
+} spv_endianness_t;
+
+typedef enum spv_opcode_flags_t {
+  SPV_OPCODE_FLAGS_NONE = 0,
+  SPV_OPCODE_FLAGS_VARIABLE = 1,
+  SPV_OPCODE_FLAGS_CAPABILITIES = 2,
+  SPV_FORCE_32_BIT_ENUM(spv_opcode_flags_t)
+} spv_opcode_flags_t;
+
+typedef enum spv_operand_type_t {
+  SPV_OPERAND_TYPE_NONE,
+  SPV_OPERAND_TYPE_ID,
+  SPV_OPERAND_TYPE_RESULT_ID,
+  SPV_OPERAND_TYPE_LITERAL,
+  SPV_OPERAND_TYPE_LITERAL_NUMBER,
+  SPV_OPERAND_TYPE_LITERAL_STRING,
+  SPV_OPERAND_TYPE_SOURCE_LANGUAGE,
+  SPV_OPERAND_TYPE_EXECUTION_MODEL,
+  SPV_OPERAND_TYPE_ADDRESSING_MODEL,
+  SPV_OPERAND_TYPE_MEMORY_MODEL,
+  SPV_OPERAND_TYPE_EXECUTION_MODE,
+  SPV_OPERAND_TYPE_STORAGE_CLASS,
+  SPV_OPERAND_TYPE_DIMENSIONALITY,
+  SPV_OPERAND_TYPE_SAMPLER_ADDRESSING_MODE,
+  SPV_OPERAND_TYPE_SAMPLER_FILTER_MODE,
+  SPV_OPERAND_TYPE_FP_FAST_MATH_MODE,
+  SPV_OPERAND_TYPE_FP_ROUNDING_MODE,
+  SPV_OPERAND_TYPE_LINKAGE_TYPE,
+  SPV_OPERAND_TYPE_ACCESS_QUALIFIER,
+  SPV_OPERAND_TYPE_FUNCTION_PARAMETER_ATTRIBUTE,
+  SPV_OPERAND_TYPE_DECORATION,
+  SPV_OPERAND_TYPE_BUILT_IN,
+  SPV_OPERAND_TYPE_SELECTION_CONTROL,
+  SPV_OPERAND_TYPE_LOOP_CONTROL,
+  SPV_OPERAND_TYPE_FUNCTION_CONTROL,
+  SPV_OPERAND_TYPE_MEMORY_SEMANTICS,
+  SPV_OPERAND_TYPE_MEMORY_ACCESS,
+  SPV_OPERAND_TYPE_EXECUTION_SCOPE,
+  SPV_OPERAND_TYPE_GROUP_OPERATION,
+  SPV_OPERAND_TYPE_KERNEL_ENQ_FLAGS,
+  SPV_OPERAND_TYPE_KERENL_PROFILING_INFO,
+  SPV_OPERAND_TYPE_CAPABILITY,
+
+  SPV_OPERAND_TYPE_ELLIPSIS,  // NOTE: Unspecified variable operands
+  SPV_FORCE_32_BIT_ENUM(spv_operand_type_t)
+} spv_operand_type_t;
+
+typedef enum spv_ext_inst_type_t {
+  SPV_EXT_INST_TYPE_NONE,
+  SPV_EXT_INST_TYPE_GLSL_STD_450,
+  SPV_EXT_INST_TYPE_OPENCL_STD_12,
+  SPV_EXT_INST_TYPE_OPENCL_STD_20,
+  SPV_EXT_INST_TYPE_OPENCL_STD_21,
+
+  SPV_FORCE_32_BIT_ENUM(spv_ext_inst_type_t)
+} spv_ext_inst_type_t;
+
+typedef enum spv_binary_to_text_options_t {
+  SPV_BINARY_TO_TEXT_OPTION_NONE = SPV_BIT(0),
+  SPV_BINARY_TO_TEXT_OPTION_PRINT = SPV_BIT(1),
+  SPV_BINARY_TO_TEXT_OPTION_COLOR = SPV_BIT(2),
+  SPV_FORCE_32_BIT_ENUM(spv_binary_to_text_options_t)
+} spv_binary_to_text_options_t;
+
+typedef enum spv_validate_options_t {
+  SPV_VALIDATE_BASIC_BIT = SPV_BIT(0),
+  SPV_VALIDATE_LAYOUT_BIT = SPV_BIT(1),
+  SPV_VALIDATE_ID_BIT = SPV_BIT(2),
+  SPV_VALIDATE_RULES_BIT = SPV_BIT(3),
+  SPV_VALIDATE_ALL = SPV_VALIDATE_BASIC_BIT | SPV_VALIDATE_LAYOUT_BIT |
+                     SPV_VALIDATE_ID_BIT | SPV_VALIDATE_RULES_BIT,
+  SPV_FORCE_32_BIT_ENUM(spv_validation_options_t)
+} spv_validate_options_t;
+
+// Structures
+
+typedef struct spv_header_t {
+  uint32_t magic;
+  uint32_t version;
+  uint32_t generator;
+  uint32_t bound;
+  uint32_t schema;               // NOTE: Reserved
+  const uint32_t *instructions;  // NOTE: Unfixed pointer to instruciton stream
+} spv_header_t;
+
+typedef struct spv_opcode_desc_t {
+  const char *name;
+  const uint16_t wordCount;
+  const Op opcode;
+  const uint32_t flags;                       // Bitfield of spv_opcode_flags_t
+  const uint32_t capabilities;                // spv_language_capabilities_t
+  const spv_operand_type_t operandTypes[16];  // TODO: Smaller/larger?
+} spv_opcode_desc_t;
+
+typedef struct spv_opcode_table_t {
+  const uint32_t count;
+  const spv_opcode_desc_t *entries;
+} spv_opcode_table_t;
+
+typedef struct spv_operand_desc_t {
+  const char *name;
+  const uint32_t value;
+  const uint32_t flags;                       // Bitfield of spv_opcode_flags_t
+  const uint32_t capabilities;                // spv_language_capabilities_t
+  const spv_operand_type_t operandTypes[16];  // TODO: Smaller/larger?
+} spv_operand_desc_t;
+
+typedef struct spv_operand_desc_group_t {
+  const spv_operand_type_t type;
+  const uint32_t count;
+  const spv_operand_desc_t *entries;
+} spv_operand_desc_group_t;
+
+typedef struct spv_operand_table_t {
+  const uint32_t count;
+  const spv_operand_desc_group_t *types;
+} spv_operand_table_t;
+
+typedef struct spv_ext_inst_desc_t {
+  const char *name;
+  const uint32_t ext_inst;
+  const spv_operand_type_t operandTypes[16];  // TODO: Smaller/larger?
+} spv_ext_inst_desc_t;
+
+typedef struct spv_ext_inst_group_t {
+  const spv_ext_inst_type_t type;
+  const uint32_t count;
+  const spv_ext_inst_desc_t *entries;
+} spv_ext_inst_group_t;
+
+typedef struct spv_ext_inst_table_t {
+  const uint32_t count;
+  const spv_ext_inst_group_t *groups;
+} spv_ext_inst_table_t;
+
+typedef struct spv_binary_t {
+  uint32_t *code;
+  uint64_t wordCount;
+} spv_binary_t;
+
+typedef struct spv_text_t {
+  const char *str;
+  uint64_t length;
+} spv_text_t;
+
+typedef struct spv_instruction_t {
+  uint16_t wordCount;
+  Op opcode;
+  spv_ext_inst_type_t extInstType;
+  uint32_t words[SPV_LIMIT_INSTRUCTION_WORD_COUNT_MAX];
+} spv_instruction_t;
+
+typedef struct spv_position_t {
+  uint64_t line;
+  uint64_t column;
+  uint64_t index;
+} spv_position_t;
+
+typedef struct spv_diagnostic_t {
+  spv_position_t position;
+  char *error;
+} spv_diagnostic_t;
+
+// Type Definitions
+
+typedef const spv_opcode_desc_t *spv_opcode_desc;
+typedef const spv_opcode_table_t *spv_opcode_table;
+typedef const spv_operand_desc_t *spv_operand_desc;
+typedef const spv_operand_table_t *spv_operand_table;
+typedef const spv_ext_inst_desc_t *spv_ext_inst_desc;
+typedef const spv_ext_inst_table_t *spv_ext_inst_table;
+typedef spv_binary_t *spv_binary;
+typedef spv_text_t *spv_text;
+typedef spv_position_t *spv_position;
+typedef spv_diagnostic_t *spv_diagnostic;
+
+// Platform API
+
+// Opcode API
+
+/// @brief Populate the Opcode table
+///
+/// @param[out] pOpcodeTable table to be populated
+///
+/// @return result code
+spv_result_t spvOpcodeTableGet(spv_opcode_table *pOpcodeTable);
+
+/// @brief Populate the operand table
+///
+/// @param[in] pOperandTable table to be populated
+///
+/// @return result code
+spv_result_t spvOperandTableGet(spv_operand_table *pOperandTable);
+
+/// @brief Populate the extended instruction table
+///
+/// @param pTable table to be populated
+///
+/// @return result code
+spv_result_t spvExtInstTableGet(spv_ext_inst_table *pTable);
+
+// Text API
+
+/// @brief Entry point to covert text form to binary form
+///
+/// @param[in] text input text
+/// @param[in] opcodeTable of specified Opcodes
+/// @param[in] operandTable of specified operands
+/// @param[in] extInstTable of specified extended instructions
+/// @param[out] pBinary the binary module
+/// @param[out] pDiagnostic contains diagnostic on failure
+///
+/// @return result code
+spv_result_t spvTextToBinary(const spv_text text,
+                             const spv_opcode_table opcodeTable,
+                             const spv_operand_table operandTable,
+                             const spv_ext_inst_table extInstTable,
+                             spv_binary *pBinary, spv_diagnostic *pDiagnostic);
+
+/// @brief Free an allocated text stream
+///
+/// @param text the text object to be destored
+void spvTextDestroy(spv_text text);
+
+// Binary API
+
+/// @brief Entry point to convert binary to text form
+///
+/// @param[in] binary the input binary stream
+/// @param[in] options bitfield of spv_binary_to_text_options_t values
+/// @param[in] opcodeTable table of specified Opcodes
+/// @param[in] operandTable table of specified operands
+/// @param[in] extInstTable of specified extended instructions
+/// @param[out] pText the textual form
+/// @param[out] pDiagnostic contains diagnostic on failure
+///
+/// @return result code
+spv_result_t spvBinaryToText(const spv_binary binary, const uint32_t options,
+                             const spv_opcode_table opcodeTable,
+                             const spv_operand_table operandTable,
+                             const spv_ext_inst_table extInstTable,
+                             spv_text *pText, spv_diagnostic *pDiagnostic);
+
+/// @brief Free a binary stream from memory
+///
+/// @param binary stream to destroy
+void spvBinaryDestroy(spv_binary binary);
+
+// Validation API
+
+/// @brief Validate a SPIR-V binary for correctness
+///
+/// @param[in] binary the input binary stream
+/// @param[in] opcodeTable table of specified Opcodes
+/// @param[in] operandTable table of specified operands
+/// @param[in] extInstTable of specified extended instructions
+/// @param[in] options bitfield of spv_validation_options_t
+/// @param[out] pDiagnostic contains diagnostic on failure
+///
+/// @return result code
+spv_result_t spvValidate(const spv_binary binary,
+                         const spv_opcode_table opcodeTable,
+                         const spv_operand_table operandTable,
+                         const spv_ext_inst_table extInstTable,
+                         const uint32_t options, spv_diagnostic *pDiagnostic);
+
+// Diagnostic API
+
+/// @brief Create a diagnostic object
+///
+/// @param position position in the text or binary stream
+/// @param message error message to display, is copied
+///
+/// @return the diagnostic object
+spv_diagnostic spvDiagnosticCreate(const spv_position position,
+                                   const char *message);
+
+/// @brief Destroy a diagnostic object
+///
+/// @param diagnostic object to destory
+void spvDiagnosticDestroy(spv_diagnostic diagnostic);
+
+/// @brief Print the diagnostic to stderr
+///
+/// @param[in] diagnostic to print
+///
+/// @return result code
+spv_result_t spvDiagnosticPrint(const spv_diagnostic diagnostic);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/licence.txt b/licence.txt
new file mode 100644 (file)
index 0000000..4675d32
--- /dev/null
@@ -0,0 +1,25 @@
+Copyright (c) 2015 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.
diff --git a/readme.md b/readme.md
new file mode 100644 (file)
index 0000000..f03b58b
--- /dev/null
+++ b/readme.md
@@ -0,0 +1,242 @@
+# SPIR-V Tools
+
+## Overview
+
+The project includes an assembler, disassembler, and validator for SPIR-V, all
+based on a common static library. The library contains all of the implementation
+details and is used in the standalone tools whilst also enabling integration
+into other code bases directly.
+
+Currently, the assembler and disassembler only support the core SPIR-V
+specification (i.e. nothing Vulkan or OpenCL-specific) and the validator is a
+work in progress. See the Future Work section for more information.
+
+## Build
+
+The project uses CMake to generate platform-specific build configurations. To
+generate these build files issue the following commands.
+
+```
+mkdir <spirv-dir>/build
+cd <spirv-dir>/build
+cmake [-G<platform-generator>] ..
+```
+
+Once the build files have been generated, build using your preferred
+development environment.
+
+### CMake Options
+
+* `SPIRV_USE_SANITIZER=<sanitizer>` - on UNIX platforms with an appropriate
+  version of `clang` this option enables the use of the sanitizers documented
+  [here](http://clang.llvm.org/docs/UsersManual.html#controlling-code-generation),
+  this should only be used with a debug build, disabled by default
+* `SPIRV_COLOR_TERMINAL=ON` - enables color console output, enabled by default
+* `SPIRV_WARN_EVERYTHING=OFF` - on UNIX platforms enable the `-Weverything`
+  compiler front end option, disabled by default
+* `SPIRV_WERROR=OFF` - on UNIX platforms enable the `-Werror` compiler front end
+  option, disabled by default
+
+## Library
+
+### Usage
+
+In order to use the library from an application, the include path should point to
+`<spirv-dir>/include`, which will enable the application to include the header
+`<spirv-dir>/include/libspirv/libspirv.h` then linking against the static
+library in `<spirv-build-dir>/bin/libSPIRV.a` or
+`<spirv-build-dir>/bin/SPIRV.lib`. The intention is for this to be a C API,
+however currently it relies on the generated header `spirv.h` meaning this is
+currently a C++ API.
+
+* `SPIRV` - the static library CMake target outputs `<spirv-dir>/lib/libSPIRV.a`
+  on Linux/Mac or `<spirv-dir>/lib/SPIRV.lib` on Windows.
+
+#### Entry Points
+
+There are three main entry points into the library.
+
+* `spvTextToBinary` implements the assembler functionality.
+* `spvBinaryToText` implements the disassembler functionality.
+* `spvValidate` implements the validator functionality.
+
+### Source
+
+In addition to the interface header `<spirv-dir>/include/libspirv/libspirv.h`
+the implementation source files reside in `<spirv-dir>/source/*`.
+
+## Tools
+
+### Assembler
+
+The standalone assembler is the binary called `spirv-as` and is located in
+`<spirv-build-dir>/bin/spirv-as`. The functionality of the assembler is
+implemented by the `spvTextToBinary` library function.
+
+The assembler operates on the textual form.
+
+* `spirv-as` - the standalone assembler
+  * `<spirv-dir>/bin/spirv-as`
+
+#### Options
+
+* `-o <filename>` is used to specify the output file, otherwise this is set to
+  `out.spv`.
+
+#### Format
+
+The assembly attempts to adhere to the binary form as closely as possible using
+text names from that specification. Here is an example.
+
+```
+OpCapability Shader
+OpMemoryModel Logical Simple
+OpEntryPoint GLCompute $3 "main"
+OpExecutionMode $3 LocalSize 64 64 1
+OpTypeVoid %1
+OpTypeFunction %2 $1
+OpFunction $1 %3 None $2
+OpLabel %4
+OpReturn
+OpFunctionEnd
+```
+
+Each line encapsulates one and only one instruction, or an OpCode and all of its
+operands. OpCodes use the names provided in section 3.28 Instructions of the
+SPIR-V specification, immediate values such as Addressing Model, Memory Model,
+etc. use the names provided in sections 3.2 Source Language through 3.27
+Capability of the SPIR-V specification. Literals strings are enclosed in quotes
+`"<string>"` while literal numbers have no special formatting.
+
+##### ID Definitions & Usage
+
+An ID definition pertains to the `Result <id>` of an OpCode, and ID usage is any
+input to an OpCode. To differentiate between definitions and uses, all ID
+definitions are prefixed with `%` and take the form `%<id>`, meanwhile all ID
+uses are prefixed with `$` and take the form `$<id>`. See the above example to
+see this in action.
+
+##### Named IDs
+
+The assembler also supports named IDs, or virtual IDs, which greatly improves
+the readability of the assembly. The same ID definition and usage prefixes
+apply. Names must begin with an character in the range `[a-z|A-Z]`. The
+following example will result in identical SPIR-V binary as the example above.
+
+```
+OpCapability Shader
+OpMemoryModel Logical Simple
+OpEntryPoint GLCompute $main "main"
+OpExecutionMode $main LocalSize 64 64 1
+OpTypeVoid %void
+OpTypeFunction %fnMain $void
+OpFunction $void %main None $fnMain
+OpLabel %lbMain
+OpReturn
+OpFunctionEnd
+```
+
+##### Arbitrary Integers
+
+When writing tests it can be useful to emit an invalid 32 bit word into the
+binary stream at arbitrary positions within the assembly. To specify an
+arbitrary word into the stream the prefix `!` is used, this takes the form
+`!<integer>`. Here is an example.
+
+```
+OpCapability !0x0000FF000
+```
+
+### Disassembler
+
+The standalone disassembler is the binary called `spirv-dis` and is located in
+`<spirv-build-dir>/bin/spirv-dis`. The functionality of the disassembler is
+implemented by the `spvBinaryToText` library function.
+
+The disassembler operates on the binary form.
+
+* `spirv-dis` - the standalone disassembler
+  * `<spirv-dir>/bin/spirv-dis`
+
+#### Options
+
+* `-o <filename>` is used to specify the output file, otherwise this is set to
+  `out.spvasm`.
+* `-p` prints the assembly to the console on stdout, this includes colored
+  output on Linux, Windows, and Mac.
+
+### Validator
+
+The standalone validator is the binary called `spirv-val` and is located in
+`<spirv-build-dir>/bin/spirv-val`. The functionality of the validator is
+implemented by the `spvValidate` library function.
+
+The validator operates on the binary form.
+
+* `spirv-val` - the standalone validator
+  * `<spirv-dir>/bin/spirv-val`
+
+#### Options
+
+* `-basic` performs basic stream validation, currently not implemented.
+* `-layout` performs logical layout validation as described in section 2.16
+  Validation Rules, currently not implemented.
+* `-id` performs ID validation according to the instruction rules in sections
+  3.28.1 through 3.28.22, enabled but is a work in progress.
+* `-capability` performs capability validation and or reporting, currently not
+  implemented.
+
+## Tests
+
+The project contains a number of tests, implemented in the `UnitSPIRV`
+executable, used to drive the development and correctness of the tools, these
+use the [googletest](https://code.google.com/p/googletest/) framework. The
+[googletest](https://code.google.com/p/googletest/) source is not provided with
+this project, to enable the tests place the
+[googletest](https://code.google.com/p/googletest/) source in the
+`<spirv-dir>/external/googletest` directory, rerun CMake if you have already
+done so previously, CMake will detect the existence of
+`<spirv-dir>/external/googletest` then build as normal.
+
+## Future Work
+
+* Support extension libraries in `spirv-as`, `spirv-dis`, and `spirv-val`.
+* Complete implementation of ID validation rules in `spirv-val`.
+* Implement section 2.16 Validation Rules in `spirv-val`.
+* Implement Capability validation and or report in `spirv-val`.
+* Improve assembly output from `spirv-dis`.
+* Improve diagnostic reports.
+
+## Known Issues
+
+* Improve literal parsing in the assembler, currently only decimal integers and
+  floating-point numbers are supported as literal operands and the parser is not
+  contextually aware of the desired width of the operand.
+
+## Licence
+
+Copyright (c) 2015 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.
diff --git a/source/binary.cpp b/source/binary.cpp
new file mode 100644 (file)
index 0000000..3b33109
--- /dev/null
@@ -0,0 +1,469 @@
+// Copyright (c) 2015 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.
+
+#include <libspirv/libspirv.h>
+#include "binary.h"
+#include "diagnostic.h"
+#include "ext_inst.h"
+#include "opcode.h"
+#include "operand.h"
+
+#include <assert.h>
+#include <string.h>
+
+#include <sstream>
+
+// Binary API
+
+enum {
+  I32_ENDIAN_LITTLE = 0x03020100ul,
+  I32_ENDIAN_BIG = 0x00010203ul,
+};
+
+static const union {
+  unsigned char bytes[4];
+  uint32_t value;
+} o32_host_order = {{0, 1, 2, 3}};
+
+#define I32_ENDIAN_HOST (o32_host_order.value)
+
+spv_result_t spvBinaryEndianness(const spv_binary binary,
+                                 spv_endianness_t *pEndian) {
+  spvCheck(!binary->code || !binary->wordCount,
+           return SPV_ERROR_INVALID_BINARY);
+  spvCheck(!pEndian, return SPV_ERROR_INVALID_POINTER);
+
+  uint8_t bytes[4];
+  memcpy(bytes, binary->code, sizeof(uint32_t));
+
+  if (0x03 == bytes[0] && 0x02 == bytes[1] && 0x23 == bytes[2] &&
+      0x07 == bytes[3]) {
+    *pEndian = SPV_ENDIANNESS_LITTLE;
+    return SPV_SUCCESS;
+  }
+
+  if (0x07 == bytes[0] && 0x23 == bytes[1] && 0x02 == bytes[2] &&
+      0x03 == bytes[3]) {
+    *pEndian = SPV_ENDIANNESS_BIG;
+    return SPV_SUCCESS;
+  }
+
+  return SPV_ERROR_INVALID_BINARY;
+}
+
+uint32_t spvFixWord(const uint32_t word, const spv_endianness_t endian) {
+  if ((SPV_ENDIANNESS_LITTLE == endian && I32_ENDIAN_HOST == I32_ENDIAN_BIG) ||
+      (SPV_ENDIANNESS_BIG == endian && I32_ENDIAN_HOST == I32_ENDIAN_LITTLE)) {
+    return (word & 0x000000ff) << 24 | (word & 0x0000ff00) << 8 |
+           (word & 0x00ff0000) >> 8 | (word & 0xff000000) >> 24;
+  }
+
+  return word;
+}
+
+spv_result_t spvBinaryHeaderGet(const spv_binary binary,
+                                const spv_endianness_t endian,
+                                spv_header_t *pHeader) {
+  spvCheck(!binary->code || !binary->wordCount,
+           return SPV_ERROR_INVALID_BINARY);
+  spvCheck(!pHeader, return SPV_ERROR_INVALID_POINTER);
+
+  // TODO: Validation checking?
+  pHeader->magic = spvFixWord(binary->code[SPV_INDEX_MAGIC_NUMBER], endian);
+  pHeader->version = spvFixWord(binary->code[SPV_INDEX_VERSION_NUMBER], endian);
+  pHeader->generator =
+      spvFixWord(binary->code[SPV_INDEX_GENERATOR_NUMBER], endian);
+  pHeader->bound = spvFixWord(binary->code[SPV_INDEX_BOUND], endian);
+  pHeader->schema = spvFixWord(binary->code[SPV_INDEX_SCHEMA], endian);
+  pHeader->instructions = &binary->code[SPV_INDEX_INSTRUCTION];
+
+  return SPV_SUCCESS;
+}
+
+spv_result_t spvBinaryHeaderSet(spv_binary_t *binary, const uint32_t bound) {
+  spvCheck(!binary, return SPV_ERROR_INVALID_BINARY);
+  spvCheck(!binary->code || !binary->wordCount,
+           return SPV_ERROR_INVALID_BINARY);
+
+  binary->code[SPV_INDEX_MAGIC_NUMBER] = SPV_MAGIC_NUMBER;
+  binary->code[SPV_INDEX_VERSION_NUMBER] = SPV_VERSION_NUMBER;
+  binary->code[SPV_INDEX_GENERATOR_NUMBER] = SPV_GENERATOR_CODEPLAY;
+  binary->code[SPV_INDEX_BOUND] = bound;
+  binary->code[SPV_INDEX_SCHEMA] = 0;  // NOTE: Reserved
+
+  return SPV_SUCCESS;
+}
+
+spv_result_t spvBinaryEncodeU32(const uint32_t value, spv_instruction_t *pInst,
+                                const spv_position position,
+                                spv_diagnostic *pDiagnostic) {
+  spvCheck(pInst->wordCount + 1 > SPV_LIMIT_INSTRUCTION_WORD_COUNT_MAX,
+           DIAGNOSTIC << "Instruction word count '"
+                      << SPV_LIMIT_INSTRUCTION_WORD_COUNT_MAX << "' exceeded.";
+           return SPV_ERROR_INVALID_TEXT);
+
+  pInst->words[pInst->wordCount++] = (uint32_t)value;
+  return SPV_SUCCESS;
+}
+
+spv_result_t spvBinaryEncodeU64(const uint64_t value, spv_instruction_t *pInst,
+                                const spv_position position,
+                                spv_diagnostic *pDiagnostic) {
+  spvCheck(pInst->wordCount + 2 > SPV_LIMIT_INSTRUCTION_WORD_COUNT_MAX,
+           DIAGNOSTIC << "Instruction word count '"
+                      << SPV_LIMIT_INSTRUCTION_WORD_COUNT_MAX << "' exceeded.";
+           return SPV_ERROR_INVALID_TEXT);
+
+  uint32_t low = (uint32_t)(0x00000000ffffffff & value);
+  uint32_t high = (uint32_t)((0xffffffff00000000 & value) >> 32);
+  pInst->words[pInst->wordCount++] = low;
+  pInst->words[pInst->wordCount++] = high;
+  return SPV_SUCCESS;
+}
+
+spv_result_t spvBinaryEncodeString(const char *str, spv_instruction_t *pInst,
+                                   const spv_position position,
+                                   spv_diagnostic *pDiagnostic) {
+  size_t length = strlen(str);
+  size_t wordCount = (length / 4) + 1;
+  spvCheck((sizeof(uint32_t) * pInst->wordCount) + length >
+               sizeof(uint32_t) * SPV_LIMIT_INSTRUCTION_WORD_COUNT_MAX,
+           DIAGNOSTIC << "Instruction word count '"
+                      << SPV_LIMIT_INSTRUCTION_WORD_COUNT_MAX << "'exceeded.";
+           return SPV_ERROR_INVALID_TEXT);
+
+  char *dest = (char *)&pInst->words[pInst->wordCount];
+  strncpy(dest, str, length);
+  pInst->wordCount += (uint16_t)wordCount;
+
+  return SPV_SUCCESS;
+}
+
+spv_operand_type_t spvBinaryOperandInfo(const uint32_t word,
+                                        const uint16_t operandIndex,
+                                        const spv_opcode_desc opcodeEntry,
+                                        const spv_operand_table operandTable,
+                                        spv_operand_desc *pOperandEntry) {
+  spv_operand_type_t type;
+  if (operandIndex < opcodeEntry->wordCount) {
+    // NOTE: Do operand table lookup to set operandEntry if successful
+    uint16_t index = operandIndex - 1;
+    type = opcodeEntry->operandTypes[index];
+    spv_operand_desc entry = nullptr;
+    if (!spvOperandTableValueLookup(operandTable, type, word, &entry)) {
+      if (SPV_OPERAND_TYPE_NONE != entry->operandTypes[0]) {
+        *pOperandEntry = entry;
+      }
+    }
+  } else if (*pOperandEntry) {
+    // NOTE: Use specified operand entry operand type for this word
+    uint16_t index = operandIndex - opcodeEntry->wordCount;
+    type = (*pOperandEntry)->operandTypes[index];
+  } else if (OpSwitch == opcodeEntry->opcode) {
+    // NOTE: OpSwitch is a special case which expects a list of paired extra
+    // operands
+    assert(0 &&
+           "This case is previously untested, remove this assert and ensure it "
+           "is behaving correctly!");
+    uint16_t lastIndex = opcodeEntry->wordCount - 1;
+    uint16_t index = lastIndex + ((operandIndex - lastIndex) % 2);
+    type = opcodeEntry->operandTypes[index];
+  } else {
+    // NOTE: Default to last operand type in opcode entry
+    uint16_t index = opcodeEntry->wordCount - 1;
+    type = opcodeEntry->operandTypes[index];
+  }
+  return type;
+}
+
+spv_result_t spvBinaryDecodeOperand(
+    const Op opcode, const spv_operand_type_t type, const uint32_t *words,
+    const spv_endianness_t endian, const uint32_t options,
+    const spv_operand_table operandTable, const spv_ext_inst_table extInstTable,
+    spv_ext_inst_type_t *pExtInstType, out_stream &stream,
+    spv_position position, spv_diagnostic *pDiagnostic) {
+  spvCheck(!words || !position, return SPV_ERROR_INVALID_POINTER);
+  spvCheck(!pDiagnostic, return SPV_ERROR_INVALID_DIAGNOSTIC);
+
+  bool print = spvIsInBitfield(SPV_BINARY_TO_TEXT_OPTION_PRINT, options);
+  bool color =
+      print && spvIsInBitfield(SPV_BINARY_TO_TEXT_OPTION_COLOR, options);
+
+  uint64_t index = 0;
+  switch (type) {
+    case SPV_OPERAND_TYPE_ID: {
+      stream.get() << ((color) ? clr::yellow() : "");
+      stream.get() << "$" << spvFixWord(words[index], endian);
+      stream.get() << ((color) ? clr::reset() : "");
+      index++;
+      position->index++;
+    } break;
+    case SPV_OPERAND_TYPE_RESULT_ID: {
+      stream.get() << (color ? clr::blue() : "");
+      stream.get() << "%" << spvFixWord(words[index], endian);
+      stream.get() << (color ? clr::reset() : "");
+      index++;
+      position->index++;
+    } break;
+    case SPV_OPERAND_TYPE_LITERAL: {
+      // TODO: Need to support multiple word literals
+      stream.get() << (color ? clr::red() : "");
+      stream.get() << spvFixWord(words[index], endian);
+      stream.get() << (color ? clr::reset() : "");
+      index++;
+      position->index++;
+    } break;
+    case SPV_OPERAND_TYPE_LITERAL_NUMBER: {
+      // NOTE: Special case for extended instruction use
+      if (OpExtInst == opcode) {
+        spv_ext_inst_desc extInst;
+        spvCheck(spvExtInstTableValueLookup(extInstTable, *pExtInstType,
+                                            words[0], &extInst),
+                 DIAGNOSTIC << "Invalid extended instruction '" << words[0]
+                            << "'.";
+                 return SPV_ERROR_INVALID_BINARY);
+      }
+
+      stream.get() << (color ? clr::red() : "");
+      stream.get() << spvFixWord(words[index], endian);
+      stream.get() << (color ? clr::reset() : "");
+      index++;
+      position->index++;
+    } break;
+    case SPV_OPERAND_TYPE_LITERAL_STRING: {
+      const char *string = (const char *)&words[index];
+      uint64_t stringOperandCount = (strlen(string) / 4) + 1;
+
+      // NOTE: Special case for extended instruction import
+      if (OpExtInstImport == opcode) {
+        *pExtInstType = spvExtInstImportTypeGet(string);
+        spvCheck(SPV_EXT_INST_TYPE_NONE == *pExtInstType,
+                 DIAGNOSTIC << "Invalid extended instruction import'" << string
+                            << "'.";
+                 return SPV_ERROR_INVALID_BINARY);
+      }
+
+      stream.get() << "\"";
+      stream.get() << (color ? clr::green() : "");
+      stream.get() << string;
+      stream.get() << (color ? clr::reset() : "");
+      stream.get() << "\"";
+      index += stringOperandCount;
+      position->index += stringOperandCount;
+    } break;
+    case SPV_OPERAND_TYPE_CAPABILITY:
+    case SPV_OPERAND_TYPE_SOURCE_LANGUAGE:
+    case SPV_OPERAND_TYPE_EXECUTION_MODEL:
+    case SPV_OPERAND_TYPE_ADDRESSING_MODEL:
+    case SPV_OPERAND_TYPE_MEMORY_MODEL:
+    case SPV_OPERAND_TYPE_EXECUTION_MODE:
+    case SPV_OPERAND_TYPE_STORAGE_CLASS:
+    case SPV_OPERAND_TYPE_DIMENSIONALITY:
+    case SPV_OPERAND_TYPE_SAMPLER_ADDRESSING_MODE:
+    case SPV_OPERAND_TYPE_SAMPLER_FILTER_MODE:
+    case SPV_OPERAND_TYPE_FP_FAST_MATH_MODE:
+    case SPV_OPERAND_TYPE_FP_ROUNDING_MODE:
+    case SPV_OPERAND_TYPE_LINKAGE_TYPE:
+    case SPV_OPERAND_TYPE_ACCESS_QUALIFIER:
+    case SPV_OPERAND_TYPE_FUNCTION_PARAMETER_ATTRIBUTE:
+    case SPV_OPERAND_TYPE_DECORATION:
+    case SPV_OPERAND_TYPE_BUILT_IN:
+    case SPV_OPERAND_TYPE_SELECTION_CONTROL:
+    case SPV_OPERAND_TYPE_LOOP_CONTROL:
+    case SPV_OPERAND_TYPE_FUNCTION_CONTROL:
+    case SPV_OPERAND_TYPE_MEMORY_SEMANTICS:
+    case SPV_OPERAND_TYPE_MEMORY_ACCESS:
+    case SPV_OPERAND_TYPE_EXECUTION_SCOPE:
+    case SPV_OPERAND_TYPE_GROUP_OPERATION:
+    case SPV_OPERAND_TYPE_KERNEL_ENQ_FLAGS:
+    case SPV_OPERAND_TYPE_KERENL_PROFILING_INFO: {
+      spv_operand_desc entry;
+      spvCheck(
+          spvOperandTableValueLookup(operandTable, type,
+                                     spvFixWord(words[index], endian), &entry),
+          DIAGNOSTIC << "Invalid " << spvOperandTypeStr(type) << " operand '"
+                     << words[index] << "'.";
+          return SPV_ERROR_INVALID_TEXT);
+      stream.get() << entry->name;
+      index++;
+      position->index++;
+    } break;
+    default: {
+      DIAGNOSTIC << "Invalid binary operand '" << type << "'";
+      return SPV_ERROR_INVALID_BINARY;
+    }
+  }
+
+  return SPV_SUCCESS;
+}
+
+spv_result_t spvBinaryDecodeOpcode(
+    spv_instruction_t *pInst, const spv_endianness_t endian,
+    const uint32_t options, const spv_opcode_table opcodeTable,
+    const spv_operand_table operandTable, const spv_ext_inst_table extInstTable,
+    out_stream &stream, spv_position position, spv_diagnostic *pDiagnostic) {
+  spvCheck(!pInst || !position, return SPV_ERROR_INVALID_POINTER);
+  spvCheck(!opcodeTable || !operandTable || !extInstTable,
+           return SPV_ERROR_INVALID_TABLE);
+  spvCheck(!pDiagnostic, return SPV_ERROR_INVALID_DIAGNOSTIC);
+
+  uint16_t wordCount;
+  Op opcode;
+  spvOpcodeSplit(spvFixWord(pInst->words[0], endian), &wordCount, &opcode);
+
+  spv_opcode_desc opcodeEntry;
+  spvCheck(spvOpcodeTableValueLookup(opcodeTable, opcode, &opcodeEntry),
+           DIAGNOSTIC << "Invalid Opcode '" << opcode << "'.";
+           return SPV_ERROR_INVALID_BINARY);
+
+  spvCheck(opcodeEntry->wordCount > wordCount,
+           DIAGNOSTIC << "Invalid instruction word count '" << wordCount
+                      << "', expected at least '" << opcodeEntry->wordCount
+                      << "'.";
+           return SPV_ERROR_INVALID_BINARY);
+
+  stream.get() << "Op" << opcodeEntry->name;
+
+  position->index++;
+
+  spv_operand_desc operandEntry = nullptr;
+  for (uint16_t index = 1; index < wordCount; ++index) {
+    const uint32_t word = spvFixWord(pInst->words[index], endian);
+    const uint64_t currentPosIndex = position->index;
+
+    stream.get() << " ";
+    spv_operand_type_t type = spvBinaryOperandInfo(word, index, opcodeEntry,
+                                                   operandTable, &operandEntry);
+    spvCheck(spvBinaryDecodeOperand(
+                 opcodeEntry->opcode, type, pInst->words + index, endian,
+                 options, operandTable, extInstTable, &pInst->extInstType,
+                 stream, position, pDiagnostic),
+             return SPV_ERROR_INVALID_BINARY);
+    index += (uint16_t)(position->index - currentPosIndex - 1);
+  }
+
+  return SPV_SUCCESS;
+}
+
+spv_result_t spvBinaryToText(const spv_binary binary, const uint32_t options,
+                             const spv_opcode_table opcodeTable,
+                             const spv_operand_table operandTable,
+                             const spv_ext_inst_table extInstTable,
+                             spv_text *pText, spv_diagnostic *pDiagnostic) {
+  spvCheck(!binary->code || !binary->wordCount,
+           return SPV_ERROR_INVALID_BINARY);
+  spvCheck(!opcodeTable || !operandTable || !extInstTable,
+           return SPV_ERROR_INVALID_TABLE);
+  spvCheck(pText && spvIsInBitfield(SPV_BINARY_TO_TEXT_OPTION_PRINT, options),
+           return SPV_ERROR_INVALID_POINTER);
+  spvCheck(!pText && !spvIsInBitfield(SPV_BINARY_TO_TEXT_OPTION_PRINT, options),
+           return SPV_ERROR_INVALID_POINTER);
+  spvCheck(!pDiagnostic, return SPV_ERROR_INVALID_DIAGNOSTIC);
+
+  spv_endianness_t endian;
+  spv_position_t position = {};
+  spvCheck(spvBinaryEndianness(binary, &endian),
+           DIAGNOSTIC << "Invalid SPIR-V magic number '" << std::hex
+                      << binary->code[0] << "'.";
+           return SPV_ERROR_INVALID_BINARY);
+
+  spv_header_t header;
+  spvCheck(spvBinaryHeaderGet(binary, endian, &header),
+           DIAGNOSTIC << "Invalid SPIR-V header.";
+           return SPV_ERROR_INVALID_BINARY);
+
+  bool print = spvIsInBitfield(SPV_BINARY_TO_TEXT_OPTION_PRINT, options);
+  bool color =
+      print && spvIsInBitfield(SPV_BINARY_TO_TEXT_OPTION_COLOR, options);
+
+  std::stringstream sstream;
+  out_stream stream(sstream);
+  if (print) {
+    stream = out_stream();
+  }
+
+  if (color) {
+    stream.get() << clr::grey();
+  }
+  stream.get() << "; SPIR-V\n"
+               << "; Version: " << header.version << "\n"
+               << "; Generator: " << spvGeneratorStr(header.generator) << "\n"
+               << "; Bound: " << header.bound << "\n"
+               << "; Schema: " << header.schema << "\n";
+  if (color) {
+    stream.get() << clr::reset();
+  }
+
+  const uint32_t *words = binary->code;
+  position.index = SPV_INDEX_INSTRUCTION;
+  spv_ext_inst_type_t extInstType = SPV_EXT_INST_TYPE_NONE;
+  while (position.index < binary->wordCount) {
+    uint64_t index = position.index;
+    uint16_t wordCount;
+    Op opcode;
+    spvOpcodeSplit(spvFixWord(words[position.index], endian), &wordCount,
+                   &opcode);
+
+    spv_instruction_t inst = {};
+    inst.extInstType = extInstType;
+    spvInstructionCopy(&words[position.index], opcode, wordCount, endian,
+                       &inst);
+
+    spvCheck(
+        spvBinaryDecodeOpcode(&inst, endian, options, opcodeTable, operandTable,
+                              extInstTable, stream, &position, pDiagnostic),
+        return SPV_ERROR_INVALID_BINARY);
+    extInstType = inst.extInstType;
+
+    spvCheck((index + wordCount) != position.index,
+             DIAGNOSTIC << "Invalid word count.";
+             return SPV_ERROR_INVALID_BINARY);
+
+    stream.get() << "\n";
+  }
+
+  if (!print) {
+    size_t length = sstream.str().size();
+    char *str = new char[length + 1];
+    spvCheck(!str, return SPV_ERROR_OUT_OF_MEMORY);
+    strncpy(str, sstream.str().c_str(), length + 1);
+    spv_text text = new spv_text_t();
+    spvCheck(!text, return SPV_ERROR_OUT_OF_MEMORY);
+    text->str = str;
+    text->length = length;
+    *pText = text;
+  }
+
+  return SPV_SUCCESS;
+}
+
+void spvBinaryDestroy(spv_binary binary) {
+  spvCheck(!binary, return );
+  if (binary->code) {
+    delete[] binary->code;
+  }
+  delete binary;
+}
diff --git a/source/binary.h b/source/binary.h
new file mode 100644 (file)
index 0000000..2ab5c66
--- /dev/null
@@ -0,0 +1,166 @@
+// Copyright (c) 2015 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.
+
+#ifndef _LIBSPIRV_UTIL_BINARY_H_
+#define _LIBSPIRV_UTIL_BINARY_H_
+
+#include <libspirv/libspirv.h>
+#include "print.h"
+
+// Functions
+
+/// @brief Fix the endianness of a word
+///
+/// @param[in] word whos endianness should be fixed
+/// @param[in] endian the desired endianness
+///
+/// @return word with host endianness correction
+uint32_t spvFixWord(const uint32_t word, const spv_endianness_t endian);
+
+/// @brief Determine the endianness of the SPV binary
+///
+/// Gets the endianness of the SPV source. Returns SPV_ENDIANNESS_UNKNOWN if
+/// the
+/// SPV magic number is invalid, otherwise the determined endianness.
+///
+/// @param[in] binary the binary module
+/// @param[out] pEndian return the endianness of the SPV module
+///
+/// @return result code
+spv_result_t spvBinaryEndianness(const spv_binary binary,
+                                 spv_endianness_t *pEndian);
+
+/// @brief Grab the header from the SPV module
+///
+/// @param[in] binary the binary module
+/// @param[in] endian the endianness of the module
+/// @param[out] pHeader the returned header
+///
+/// @return result code
+spv_result_t spvBinaryHeaderGet(const spv_binary binary,
+                                const spv_endianness_t endian,
+                                spv_header_t *pHeader);
+
+/// @brief Populate a binary stream with this generators header
+///
+/// @param[in,out] binary the binary stream
+/// @param[in] bound the upper ID bound
+///
+/// @return result code
+spv_result_t spvBinaryHeaderSet(spv_binary binary, const uint32_t bound);
+
+/// @brief Append a single word into a binary stream
+///
+/// @param[in] value the word to encode
+/// @param[in] pInst the stream to append to
+/// @param[in,out] position position in the binary
+/// @param[out] pDiagnostic contains diagnostic on failure
+///
+/// @return result code
+spv_result_t spvBinaryEncodeU32(const uint32_t value, spv_instruction_t *pInst,
+                                const spv_position position,
+                                spv_diagnostic *pDiagnostic);
+
+/// @brief Append two related words into the binary stream
+///
+/// @param[in] value the two words to encode
+/// @param[in] pInst the stream to append to
+/// @param[in,out] position position in the binary
+/// @param[out] pDiagnostic contains diagnostic on failure
+///
+/// @return result code
+spv_result_t spvBinaryEncodeU64(const uint64_t value, spv_instruction_t *pInst,
+                                const spv_position position,
+                                spv_diagnostic *pDiagnostic);
+
+/// @brief Append a string literal in the binary stream
+///
+/// @param[in] str the string to encode
+/// @param[in] pInst the stream to append to
+/// @param[in,out] position position in the binary
+/// @param[out] pDiagnostic contains diagnostic on failure
+///
+/// @return result code
+spv_result_t spvBinaryEncodeString(const char *str, spv_instruction_t *pInst,
+                                   const spv_position position,
+                                   spv_diagnostic *pDiagnostic);
+
+/// @brief Determine the type of the desired operand
+///
+/// @param[in] word the operand value
+/// @param[in] index the word index in the instruction
+/// @param[in] opcodeEntry table of specified Opcodes
+/// @param[in] operandTable table of specified operands
+/// @param[in,out] pOperandEntry the entry in the operand table
+///
+/// @return type returned
+spv_operand_type_t spvBinaryOperandInfo(const uint32_t word,
+                                        const uint16_t index,
+                                        const spv_opcode_desc opcodeEntry,
+                                        const spv_operand_table operandTable,
+                                        spv_operand_desc *pOperandEntry);
+
+/// @brief Translate a binary operand to the textual form
+///
+/// @param[in] opcode of the current instruction
+/// @param[in] type type of the operand to decode
+/// @param[in] words the binary stream of words
+/// @param[in] endian the endianness of the stream
+/// @param[in] options bitfield of spv_binary_to_text_options_t values
+/// @param[in] operandTable table of specified operands
+/// @param[in,out] pExtInstType type of extended instruction library
+/// @param[in,out] stream the text output stream
+/// @param[in,out] position position in the binary stream
+/// @param[out] pDiag return diagnostic on error
+///
+/// @return result code
+spv_result_t spvBinaryDecodeOperand(
+    const Op opcode, const spv_operand_type_t type, const uint32_t *words,
+    const spv_endianness_t endian, const uint32_t options,
+    const spv_operand_table operandTable, const spv_ext_inst_table extInstTable,
+    spv_ext_inst_type_t *pExtInstType, out_stream &stream,
+    spv_position position, spv_diagnostic *pDiag);
+
+/// @brief Translate binary Opcode stream to textual form
+///
+/// @param[in] pInst the Opcode instruction stream
+/// @param[in] endian the endianness of the stream
+/// @param[in] options bitfield of spv_binary_to_text_options_t values
+/// @param[in] opcodeTable table of specified Opcodes
+/// @param[in] operandTable table of specified operands
+/// @param[out] stream output text stream
+/// @param[in,out] position position in the stream
+/// @param[out] pDiag return diagnostic on error
+///
+/// @return result code
+spv_result_t spvBinaryDecodeOpcode(
+    spv_instruction_t *pInst, const spv_endianness_t endian,
+    const uint32_t options, const spv_opcode_table opcodeTable,
+    const spv_operand_table operandTable, const spv_ext_inst_table extInstTable,
+    out_stream &stream, spv_position position, spv_diagnostic *pDiag);
+
+#endif
+
diff --git a/source/diagnostic.cpp b/source/diagnostic.cpp
new file mode 100644 (file)
index 0000000..a6f87aa
--- /dev/null
@@ -0,0 +1,81 @@
+// Copyright (c) 2015 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.
+
+#include <libspirv/libspirv.h>
+#include "diagnostic.h"
+
+#include <assert.h>
+#include <string.h>
+
+#include <iostream>
+
+// Diagnostic API
+
+spv_diagnostic spvDiagnosticCreate(const spv_position position,
+                                   const char *message) {
+  spv_diagnostic diagnostic = new spv_diagnostic_t;
+  spvCheck(!diagnostic, return nullptr);
+  size_t length = strlen(message) + 1;
+  diagnostic->error = new char[length];
+  spvCheck(!diagnostic->error, delete diagnostic; return nullptr);
+  diagnostic->position = *position;
+  memset(diagnostic->error, 0, length);
+  strncpy(diagnostic->error, message, length);
+  return diagnostic;
+}
+
+void spvDiagnosticDestroy(spv_diagnostic diagnostic) {
+  spvCheck(!diagnostic, return );
+  if (diagnostic->error) {
+    delete[] diagnostic->error;
+  }
+  delete diagnostic;
+}
+
+spv_result_t spvDiagnosticPrint(const spv_diagnostic diagnostic) {
+  spvCheck(!diagnostic, return SPV_ERROR_INVALID_DIAGNOSTIC);
+
+  // TODO: Check that the logic choosing between a text or binary diagnostic is
+  // corrent.
+  if ((diagnostic->position.line || diagnostic->position.column) &&
+      diagnostic->position.index) {
+    // NOTE: This is a text position
+    // NOTE: add 1 to the line as editors start at line 1, we are counting new
+    // line characters to start at line 0
+    std::cerr << "error: " << diagnostic->position.line + 1 << ": "
+              << diagnostic->position.column + 1 << ": " << diagnostic->error
+              << "\n";
+    return SPV_SUCCESS;
+  } else if (!diagnostic->position.line && !diagnostic->position.column &&
+             diagnostic->position.index) {
+    // NOTE: This is a binary position
+    std::cerr << "error: " << diagnostic->position.index << ": "
+              << diagnostic->error << "\n";
+    return SPV_SUCCESS;
+  }
+
+  return SPV_ERROR_INVALID_VALUE;
+}
diff --git a/source/diagnostic.h b/source/diagnostic.h
new file mode 100644 (file)
index 0000000..f2e4db2
--- /dev/null
@@ -0,0 +1,59 @@
+// Copyright (c) 2015 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.
+
+#ifndef _LIBSPIRV_UTIL_DIAGNOSTIC_H_
+#define _LIBSPIRV_UTIL_DIAGNOSTIC_H_
+
+#include <libspirv/libspirv.h>
+
+#include <sstream>
+
+#include <iostream>
+
+class diagnostic_helper {
+ public:
+  diagnostic_helper(spv_position_t &position, spv_diagnostic *pDiagnostic)
+      : position(&position), pDiagnostic(pDiagnostic) {}
+
+  diagnostic_helper(spv_position position, spv_diagnostic *pDiagnostic)
+      : position(position), pDiagnostic(pDiagnostic) {}
+
+  ~diagnostic_helper() {
+    *pDiagnostic = spvDiagnosticCreate(position, stream.str().c_str());
+  }
+
+  std::stringstream stream;
+
+ private:
+  spv_position position;
+  spv_diagnostic *pDiagnostic;
+};
+
+#define DIAGNOSTIC                                 \
+  diagnostic_helper helper(position, pDiagnostic); \
+  helper.stream
+
+#endif
diff --git a/source/ext_inst.cpp b/source/ext_inst.cpp
new file mode 100644 (file)
index 0000000..04e1bba
--- /dev/null
@@ -0,0 +1,113 @@
+#include <libspirv/libspirv.h>
+
+#include <string.h>
+
+static const spv_ext_inst_desc_t glslStd450Entries[] = {
+    {
+     "round", GLSL_STD_450::Round, {SPV_OPERAND_TYPE_ID},
+    },
+    // TODO: Add remaining GLSL.std.450 instructions
+};
+
+static const spv_ext_inst_desc_t openclStd12Entries[] = {
+    {"placeholder", 0, {}},
+    // TODO: Add remaining OpenCL.std.12 instructions
+};
+
+static const spv_ext_inst_desc_t openclStd20Entries[] = {
+    {"placeholder", 0, {}},
+    // TODO: Add remaining OpenCL.std.20 instructions
+};
+
+static const spv_ext_inst_desc_t openclStd21Entries[] = {
+    {"placeholder", 0, {}},
+    // TODO: Add remaining OpenCL.std.21 instructions
+};
+
+spv_result_t spvExtInstTableGet(spv_ext_inst_table *pExtInstTable) {
+  spvCheck(!pExtInstTable, return SPV_ERROR_INVALID_POINTER);
+
+  static const spv_ext_inst_group_t groups[] = {
+      {SPV_EXT_INST_TYPE_GLSL_STD_450,
+       sizeof(glslStd450Entries) / sizeof(spv_ext_inst_desc_t),
+       glslStd450Entries},
+      {SPV_EXT_INST_TYPE_OPENCL_STD_12,
+       sizeof(openclStd12Entries) / sizeof(spv_ext_inst_desc_t),
+       openclStd12Entries},
+      {SPV_EXT_INST_TYPE_OPENCL_STD_20,
+       sizeof(openclStd20Entries) / sizeof(spv_ext_inst_desc_t),
+       openclStd20Entries},
+      {SPV_EXT_INST_TYPE_OPENCL_STD_21,
+       sizeof(openclStd21Entries) / sizeof(spv_ext_inst_desc_t),
+       openclStd21Entries},
+  };
+
+  static const spv_ext_inst_table_t table = {
+      sizeof(groups) / sizeof(spv_ext_inst_group_t), groups};
+
+  *pExtInstTable = &table;
+
+  return SPV_SUCCESS;
+}
+
+spv_ext_inst_type_t spvExtInstImportTypeGet(const char *name) {
+  if (!strcmp("GLSL.std.450", name)) {
+    return SPV_EXT_INST_TYPE_GLSL_STD_450;
+  }
+  if (!strcmp("OpenCL.std.12", name)) {
+    return SPV_EXT_INST_TYPE_OPENCL_STD_12;
+  }
+  if (!strcmp("OpenCL.std.20", name)) {
+    return SPV_EXT_INST_TYPE_OPENCL_STD_20;
+  }
+  if (!strcmp("OpenCL.std.21", name)) {
+    return SPV_EXT_INST_TYPE_OPENCL_STD_21;
+  }
+  return SPV_EXT_INST_TYPE_NONE;
+}
+
+spv_result_t spvExtInstTableNameLookup(const spv_ext_inst_table table,
+                                       const spv_ext_inst_type_t type,
+                                       const char *name,
+                                       spv_ext_inst_desc *pEntry) {
+  spvCheck(!table, return SPV_ERROR_INVALID_TABLE);
+  spvCheck(!pEntry, return SPV_ERROR_INVALID_POINTER);
+
+  for (uint32_t groupIndex = 0; groupIndex < table->count; groupIndex++) {
+    auto &group = table->groups[groupIndex];
+    if (type == group.type) {
+      for (uint32_t index = 0; index < group.count; index++) {
+        auto &entry = group.entries[index];
+        if (!strcmp(name, entry.name)) {
+          *pEntry = &table->groups[groupIndex].entries[index];
+          return SPV_SUCCESS;
+        }
+      }
+    }
+  }
+
+  return SPV_ERROR_INVALID_LOOKUP;
+}
+
+spv_result_t spvExtInstTableValueLookup(const spv_ext_inst_table table,
+                                        const spv_ext_inst_type_t type,
+                                        const uint32_t value,
+                                        spv_ext_inst_desc *pEntry) {
+  spvCheck(!table, return SPV_ERROR_INVALID_TABLE);
+  spvCheck(!pEntry, return SPV_ERROR_INVALID_POINTER);
+
+  for (uint32_t groupIndex = 0; groupIndex < table->count; groupIndex++) {
+    auto &group = table->groups[groupIndex];
+    if (type == group.type) {
+      for (uint32_t index = 0; index < group.count; index++) {
+        auto &entry = group.entries[index];
+        if (value == entry.ext_inst) {
+          *pEntry = &table->groups[groupIndex].entries[index];
+          return SPV_SUCCESS;
+        }
+      }
+    }
+  }
+
+  return SPV_ERROR_INVALID_LOOKUP;
+}
diff --git a/source/ext_inst.h b/source/ext_inst.h
new file mode 100644 (file)
index 0000000..341547b
--- /dev/null
@@ -0,0 +1,65 @@
+// Copyright (c) 2015 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.
+
+#ifndef _CODEPLAY_SPIRV_EXT_INST_H_
+#define _CODEPLAY_SPIRV_EXT_INST_H_
+
+#include <libspirv/libspirv.h>
+
+/// @brief Get the type from the extended instruction library string
+///
+/// @param name of the library
+///
+/// @return type of the extended instruction library
+spv_ext_inst_type_t spvExtInstImportTypeGet(const char *name);
+
+/// @brief Find the extented instruction with value in the table
+///
+/// @param table to lookup
+/// @param type of the extended instruction import
+/// @param name of the extended instruction to find
+/// @param pEntry return the extended instruction entry
+///
+/// @return result code
+spv_result_t spvExtInstTableNameLookup(const spv_ext_inst_table table,
+                                       const spv_ext_inst_type_t type,
+                                       const char *name,
+                                       spv_ext_inst_desc *pEntry);
+
+/// @brief Find the extented instruction with value in the table
+///
+/// @param table to lookup
+/// @param type of the extended instruction import
+/// @param value of the extended instruction to find
+/// @param pEntry return the extended instruction entry
+///
+/// @return result code
+spv_result_t spvExtInstTableValueLookup(const spv_ext_inst_table table,
+                                        const spv_ext_inst_type_t type,
+                                        const uint32_t value,
+                                        spv_ext_inst_desc *pEntry);
+
+#endif
diff --git a/source/opcode.cpp b/source/opcode.cpp
new file mode 100644 (file)
index 0000000..bf203ac
--- /dev/null
@@ -0,0 +1,2476 @@
+// Copyright (c) 2015 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.
+
+#include <libspirv/libspirv.h>
+#include "binary.h"
+#include "opcode.h"
+
+#include <assert.h>
+#include <string.h>
+
+// Opcode API
+
+const char *spvGeneratorStr(uint32_t generator) {
+  switch (generator) {
+    case SPV_GENERATOR_KHRONOS:
+      return "Khronos";
+    case SPV_GENERATOR_VALVE:
+      return "Valve";
+    case SPV_GENERATOR_LUNARG:
+      return "LunarG";
+    case SPV_GENERATOR_CODEPLAY:
+      return "Codeplay Software Ltd.";
+    default:
+      return "Unknown";
+  }
+}
+
+uint32_t spvOpcodeMake(uint16_t wordCount, Op opcode) {
+  return ((uint32_t)opcode) | (((uint32_t)wordCount) << 16);
+}
+
+void spvOpcodeSplit(const uint32_t word, uint16_t *pWordCount, Op *pOpcode) {
+  if (pWordCount) {
+    *pWordCount = (uint16_t)((0xffff0000 & word) >> 16);
+  }
+  if (pOpcode) {
+    *pOpcode = (Op)(0x0000ffff & word);
+  }
+}
+
+static const spv_opcode_desc_t opcodeTableEntries[] = {
+    {"Nop", 1, OpNop, SPV_OPCODE_FLAGS_NONE, 0, {}},
+    {"Undef",
+     3,
+     OpUndef,
+     SPV_OPCODE_FLAGS_NONE,
+     0,
+     {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID}},
+    {
+     "Source",
+     3,
+     OpSource,
+     SPV_OPCODE_FLAGS_NONE,
+     0,
+     {SPV_OPERAND_TYPE_SOURCE_LANGUAGE, SPV_OPERAND_TYPE_LITERAL_NUMBER},
+    },
+    {"SourceExtension",
+     1,
+     OpSourceExtension,
+     SPV_OPCODE_FLAGS_VARIABLE,
+     0,
+     {SPV_OPERAND_TYPE_LITERAL_STRING}},
+    {"Name",
+     2,
+     OpName,
+     SPV_OPCODE_FLAGS_VARIABLE,
+     0,
+     {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_LITERAL_STRING}},
+    {"MemberName",
+     3,
+     OpMemberName,
+     SPV_OPCODE_FLAGS_VARIABLE,
+     0,
+     {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_LITERAL_NUMBER,
+      SPV_OPERAND_TYPE_LITERAL_STRING}},
+    {"String",
+     2,
+     OpString,
+     SPV_OPCODE_FLAGS_VARIABLE,
+     0,
+     {SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_LITERAL_STRING}},
+    {"Line",
+     5,
+     OpLine,
+     SPV_OPCODE_FLAGS_NONE,
+     0,
+     {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_LITERAL_NUMBER,
+      SPV_OPERAND_TYPE_LITERAL_NUMBER}},
+    {"DecorationGroup",
+     2,
+     OpDecorationGroup,
+     SPV_OPCODE_FLAGS_NONE,
+     0,
+     {SPV_OPERAND_TYPE_RESULT_ID}},
+    {"Decorate",
+     3,
+     OpDecorate,
+     SPV_OPCODE_FLAGS_VARIABLE,
+     0,
+     {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_DECORATION,
+      SPV_OPERAND_TYPE_LITERAL, SPV_OPERAND_TYPE_LITERAL,
+      SPV_OPERAND_TYPE_ELLIPSIS}},
+    {"MemberDecorate",
+     4,
+     OpMemberDecorate,
+     SPV_OPCODE_FLAGS_VARIABLE,
+     0,
+     {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_LITERAL_NUMBER,
+      SPV_OPERAND_TYPE_DECORATION, SPV_OPERAND_TYPE_LITERAL,
+      SPV_OPERAND_TYPE_LITERAL, SPV_OPERAND_TYPE_ELLIPSIS}},
+    {"GroupDecorate",
+     2,
+     OpGroupDecorate,
+     SPV_OPCODE_FLAGS_VARIABLE,
+     0,
+     {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID,
+      SPV_OPERAND_TYPE_ELLIPSIS}},
+    {"GroupMemberDecorate",
+     2,
+     OpGroupMemberDecorate,
+     SPV_OPCODE_FLAGS_VARIABLE,
+     0,
+     {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID,
+      SPV_OPERAND_TYPE_ELLIPSIS}},
+    {"Extension",
+     1,
+     OpExtension,
+     SPV_OPCODE_FLAGS_VARIABLE,
+     0,
+     {SPV_OPERAND_TYPE_LITERAL_STRING}},
+    {"ExtInstImport",
+     2,
+     OpExtInstImport,
+     SPV_OPCODE_FLAGS_VARIABLE,
+     0,
+     {SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_LITERAL_STRING}},
+    {"ExtInst",
+     5,
+     OpExtInst,
+     SPV_OPCODE_FLAGS_VARIABLE,
+     0,
+     {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_ID,
+      SPV_OPERAND_TYPE_LITERAL_NUMBER, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID,
+      SPV_OPERAND_TYPE_ELLIPSIS}},
+    {"MemoryModel",
+     3,
+     OpMemoryModel,
+     SPV_OPCODE_FLAGS_NONE,
+     0,
+     {SPV_OPERAND_TYPE_ADDRESSING_MODEL, SPV_OPERAND_TYPE_MEMORY_MODEL}},
+    {"EntryPoint",
+     3,
+     OpEntryPoint,
+     SPV_OPCODE_FLAGS_VARIABLE,
+     0,
+     {SPV_OPERAND_TYPE_EXECUTION_MODEL, SPV_OPERAND_TYPE_ID,
+      SPV_OPERAND_TYPE_LITERAL_STRING}},
+    {"ExecutionMode",
+     3,
+     OpExecutionMode,
+     SPV_OPCODE_FLAGS_VARIABLE,
+     0,
+     {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_EXECUTION_MODE,
+      SPV_OPERAND_TYPE_LITERAL, SPV_OPERAND_TYPE_LITERAL,
+      SPV_OPERAND_TYPE_ELLIPSIS}},
+    {"CompileFlag",
+     1,
+     OpCompileFlag,
+     SPV_OPCODE_FLAGS_VARIABLE | SPV_OPCODE_FLAGS_CAPABILITIES,
+     CapabilityKernel,
+     {SPV_OPERAND_TYPE_LITERAL_STRING}},
+    {"Capability",
+     2,
+     OpCapability,
+     SPV_OPCODE_FLAGS_NONE,
+     0,
+     {SPV_OPERAND_TYPE_CAPABILITY}},
+    {"TypeVoid",
+     2,
+     OpTypeVoid,
+     SPV_OPCODE_FLAGS_NONE,
+     0,
+     {SPV_OPERAND_TYPE_RESULT_ID}},
+    {"TypeBool",
+     2,
+     OpTypeBool,
+     SPV_OPCODE_FLAGS_NONE,
+     0,
+     {SPV_OPERAND_TYPE_RESULT_ID}},
+    {"TypeInt",
+     4,
+     OpTypeInt,
+     SPV_OPCODE_FLAGS_NONE,
+     0,
+     {SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_LITERAL_NUMBER,
+      SPV_OPERAND_TYPE_LITERAL_NUMBER}},
+    {"TypeFloat",
+     3,
+     OpTypeFloat,
+     SPV_OPCODE_FLAGS_NONE,
+     0,
+     {SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_LITERAL_NUMBER}},
+    {"TypeVector",
+     4,
+     OpTypeVector,
+     SPV_OPCODE_FLAGS_NONE,
+     0,
+     {SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_ID,
+      SPV_OPERAND_TYPE_LITERAL_NUMBER}},
+    {"TypeMatrix",
+     4,
+     OpTypeMatrix,
+     SPV_OPCODE_FLAGS_CAPABILITIES,
+     CapabilityMatrix,
+     {SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_ID,
+      SPV_OPERAND_TYPE_LITERAL_NUMBER}},
+    {"TypeSampler",
+     8,
+     OpTypeSampler,
+     SPV_OPCODE_FLAGS_VARIABLE,
+     0,
+     {
+      SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_ID,
+      SPV_OPERAND_TYPE_DIMENSIONALITY, SPV_OPERAND_TYPE_LITERAL_NUMBER,
+      SPV_OPERAND_TYPE_LITERAL_NUMBER, SPV_OPERAND_TYPE_LITERAL_NUMBER,
+      SPV_OPERAND_TYPE_LITERAL_NUMBER,
+      SPV_OPERAND_TYPE_ID  // TODO: See Khronos bug 13755
+     }},
+    {"TypeFilter",
+     2,
+     OpTypeFilter,
+     SPV_OPCODE_FLAGS_NONE,
+     0,
+     {SPV_OPERAND_TYPE_RESULT_ID}},
+    {"TypeArray",
+     4,
+     OpTypeArray,
+     SPV_OPCODE_FLAGS_NONE,
+     0,
+     {SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID}},
+    {"TypeRuntimeArray",
+     3,
+     OpTypeRuntimeArray,
+     SPV_OPCODE_FLAGS_CAPABILITIES,
+     CapabilityShader,
+     {SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_ID}},
+    {"TypeStruct",
+     2,
+     OpTypeStruct,
+     SPV_OPCODE_FLAGS_VARIABLE,
+     0,
+     {SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID,
+      SPV_OPERAND_TYPE_ELLIPSIS}},
+    {"TypeOpaque",
+     2,
+     OpTypeOpaque,
+     SPV_OPCODE_FLAGS_VARIABLE | SPV_OPCODE_FLAGS_CAPABILITIES,
+     CapabilityKernel,
+     {SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_LITERAL_STRING}},
+    {"TypePointer",
+     4,
+     OpTypePointer,
+     SPV_OPCODE_FLAGS_NONE,
+     0,
+     {SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_STORAGE_CLASS,
+      SPV_OPERAND_TYPE_ID}},
+    {"TypeFunction",
+     3,
+     OpTypeFunction,
+     SPV_OPCODE_FLAGS_VARIABLE,
+     0,
+     {SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID,
+      SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ELLIPSIS}},
+    {"TypeEvent",
+     2,
+     OpTypeEvent,
+     SPV_OPCODE_FLAGS_CAPABILITIES,
+     CapabilityKernel,
+     {SPV_OPERAND_TYPE_RESULT_ID}},
+    {"TypeDeviceEvent",
+     2,
+     OpTypeDeviceEvent,
+     SPV_OPCODE_FLAGS_CAPABILITIES,
+     CapabilityKernel,
+     {SPV_OPERAND_TYPE_RESULT_ID}},
+    {"TypeReserveId",
+     2,
+     OpTypeReserveId,
+     SPV_OPCODE_FLAGS_CAPABILITIES,
+     CapabilityKernel,
+     {SPV_OPERAND_TYPE_RESULT_ID}},
+    {"TypeQueue",
+     2,
+     OpTypeQueue,
+     SPV_OPCODE_FLAGS_CAPABILITIES,
+     CapabilityKernel,
+     {SPV_OPERAND_TYPE_RESULT_ID}},
+    {"TypePipe",
+     4,
+     OpTypePipe,
+     SPV_OPCODE_FLAGS_CAPABILITIES,
+     CapabilityPipes,
+     {SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_ID,
+      SPV_OPERAND_TYPE_ACCESS_QUALIFIER}},
+    {"ConstantTrue",
+     3,
+     OpConstantTrue,
+     SPV_OPCODE_FLAGS_NONE,
+     0,
+     {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID}},
+    {"ConstantFalse",
+     3,
+     OpConstantFalse,
+     SPV_OPCODE_FLAGS_NONE,
+     0,
+     {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID}},
+    {"Constant",
+     3,
+     OpConstant,
+     SPV_OPCODE_FLAGS_VARIABLE,
+     0,
+     {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_LITERAL,
+      SPV_OPERAND_TYPE_LITERAL, SPV_OPERAND_TYPE_ELLIPSIS}},
+    {"ConstantComposite",
+     3,
+     OpConstantComposite,
+     SPV_OPCODE_FLAGS_VARIABLE,
+     0,
+     {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_ID,
+      SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ELLIPSIS}},
+    {"ConstantSampler",
+     6,
+     OpConstantSampler,
+     SPV_OPCODE_FLAGS_CAPABILITIES,
+     CapabilityKernel,
+     {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID,
+      SPV_OPERAND_TYPE_SAMPLER_ADDRESSING_MODE, SPV_OPERAND_TYPE_LITERAL_NUMBER,
+      SPV_OPERAND_TYPE_SAMPLER_FILTER_MODE}},
+    {"ConstantNull",
+     3,
+     OpConstantNull,
+     SPV_OPCODE_FLAGS_NONE,
+     0,
+     {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID}},
+    {"SpecConstantTrue",
+     3,
+     OpSpecConstantTrue,
+     SPV_OPCODE_FLAGS_CAPABILITIES,
+     CapabilityShader,
+     {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID}},
+    {"SpecConstantFalse",
+     3,
+     OpSpecConstantFalse,
+     SPV_OPCODE_FLAGS_CAPABILITIES,
+     CapabilityKernel,
+     {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID}},
+    {"SpecConstant",
+     3,
+     OpSpecConstant,
+     SPV_OPCODE_FLAGS_VARIABLE | SPV_OPCODE_FLAGS_CAPABILITIES,
+     CapabilityShader,
+     {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_LITERAL,
+      SPV_OPERAND_TYPE_LITERAL, SPV_OPERAND_TYPE_ELLIPSIS}},
+    {"SpecConstantComposite",
+     3,
+     OpSpecConstantComposite,
+     SPV_OPCODE_FLAGS_VARIABLE | SPV_OPCODE_FLAGS_CAPABILITIES,
+     CapabilityShader,
+     {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_ID,
+      SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ELLIPSIS}},
+    {
+     "SpecConstantOp",
+     4,
+     OpSpecConstantOp,
+     SPV_OPCODE_FLAGS_VARIABLE,
+     0,
+     {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID,
+      SPV_OPERAND_TYPE_LITERAL_NUMBER, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID,
+      SPV_OPERAND_TYPE_ELLIPSIS},
+
+    },
+    {"Variable",
+     4,
+     OpVariable,
+     SPV_OPCODE_FLAGS_VARIABLE,
+     0,
+     {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID,
+      SPV_OPERAND_TYPE_STORAGE_CLASS, SPV_OPERAND_TYPE_ID}},
+    {"VariableArray",
+     5,
+     OpVariableArray,
+     SPV_OPCODE_FLAGS_CAPABILITIES,
+     CapabilityAddresses,
+     {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID,
+      SPV_OPERAND_TYPE_STORAGE_CLASS, SPV_OPERAND_TYPE_ID}},
+    {"Load",
+     4,
+     OpLoad,
+     SPV_OPCODE_FLAGS_VARIABLE,
+     0,
+     {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_ID,
+      SPV_OPERAND_TYPE_MEMORY_ACCESS, SPV_OPERAND_TYPE_MEMORY_ACCESS,
+      SPV_OPERAND_TYPE_ELLIPSIS}},
+    {"Store",
+     3,
+     OpStore,
+     SPV_OPCODE_FLAGS_VARIABLE,
+     0,
+     {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_MEMORY_ACCESS,
+      SPV_OPERAND_TYPE_MEMORY_ACCESS, SPV_OPERAND_TYPE_ELLIPSIS}},
+    {"CopyMemory",
+     3,
+     OpCopyMemory,
+     SPV_OPCODE_FLAGS_VARIABLE,
+     0,
+     {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_MEMORY_ACCESS,
+      SPV_OPERAND_TYPE_MEMORY_ACCESS, SPV_OPERAND_TYPE_ELLIPSIS}},
+    {"CopyMemorySized",
+     4,
+     OpCopyMemorySized,
+     SPV_OPCODE_FLAGS_VARIABLE | SPV_OPCODE_FLAGS_CAPABILITIES,
+     CapabilityAddresses,
+     {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID,
+      SPV_OPERAND_TYPE_MEMORY_ACCESS, SPV_OPERAND_TYPE_MEMORY_ACCESS,
+      SPV_OPERAND_TYPE_ELLIPSIS}},
+    {"AccessChain",
+     4,
+     OpAccessChain,
+     SPV_OPCODE_FLAGS_VARIABLE,
+     0,
+     {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_ID,
+      SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ELLIPSIS}},
+    {"InBoundsAccessChain",
+     4,
+     OpInBoundsAccessChain,
+     SPV_OPCODE_FLAGS_VARIABLE,
+     0,
+     {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_ID,
+      SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ELLIPSIS}},
+    {"ArrayLength",
+     5,
+     OpArrayLength,
+     SPV_OPCODE_FLAGS_CAPABILITIES,
+     CapabilityShader,
+     {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_ID,
+      SPV_OPERAND_TYPE_LITERAL_NUMBER}},
+    {"ImagePointer",
+     6,
+     OpImagePointer,
+     SPV_OPCODE_FLAGS_NONE,
+     0,
+     {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_ID,
+      SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID}},
+    {"GenericPtrMemSemantics",
+     4,
+     OpGenericPtrMemSemantics,
+     SPV_OPCODE_FLAGS_CAPABILITIES,
+     CapabilityKernel,
+     {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_ID}},
+    {"Function",
+     5,
+     OpFunction,
+     SPV_OPCODE_FLAGS_NONE,
+     0,
+     {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID,
+      SPV_OPERAND_TYPE_FUNCTION_CONTROL, SPV_OPERAND_TYPE_ID}},
+    {"FunctionParameter",
+     3,
+     OpFunctionParameter,
+     SPV_OPCODE_FLAGS_NONE,
+     0,
+     {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID}},
+    {"FunctionEnd", 1, OpFunctionEnd, SPV_OPCODE_FLAGS_NONE, 0, {}},
+    {"FunctionCall",
+     4,
+     OpFunctionCall,
+     SPV_OPCODE_FLAGS_VARIABLE,
+     0,
+     {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_ID,
+      SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ELLIPSIS}},
+    {"Sampler",
+     5,
+     OpSampler,
+     SPV_OPCODE_FLAGS_NONE,
+     0,
+     {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_ID,
+      SPV_OPERAND_TYPE_ID}},
+    {"TextureSample",
+     5,
+     OpTextureSample,
+     SPV_OPCODE_FLAGS_VARIABLE | SPV_OPCODE_FLAGS_CAPABILITIES,
+     CapabilityShader,
+     {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_ID,
+      SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID}},
+    {"TextureSampleDref",
+     6,
+     OpTextureSampleDref,
+     SPV_OPCODE_FLAGS_CAPABILITIES,
+     CapabilityShader,
+     {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_ID,
+      SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID}},
+    {"TextureSampleLod",
+     6,
+     OpTextureSampleLod,
+     SPV_OPCODE_FLAGS_CAPABILITIES,
+     CapabilityShader,
+     {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_ID,
+      SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID}},
+    {"TextureSampleProj",
+     5,
+     OpTextureSampleProj,
+     SPV_OPCODE_FLAGS_VARIABLE | SPV_OPCODE_FLAGS_CAPABILITIES,
+     CapabilityShader,
+     {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_ID,
+      SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID}},
+    {"TextureSampleGrad",
+     7,
+     OpTextureSampleGrad,
+     SPV_OPCODE_FLAGS_CAPABILITIES,
+     CapabilityShader,
+     {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_ID,
+      SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID}},
+    {"TextureSampleOffset",
+     6,
+     OpTextureSampleOffset,
+     SPV_OPCODE_FLAGS_VARIABLE | SPV_OPCODE_FLAGS_CAPABILITIES,
+     CapabilityShader,
+     {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_ID,
+      SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID}},
+    {"TextureSampleProjLod",
+     6,
+     OpTextureSampleProjLod,
+     SPV_OPCODE_FLAGS_CAPABILITIES,
+     CapabilityShader,
+     {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_ID,
+      SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID}},
+    {"TextureSampleProjGrad",
+     7,
+     OpTextureSampleProjGrad,
+     SPV_OPCODE_FLAGS_CAPABILITIES,
+     CapabilityShader,
+     {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_ID,
+      SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID}},
+    {"TextureSampleLodOffset",
+     7,
+     OpTextureSampleLodOffset,
+     SPV_OPCODE_FLAGS_CAPABILITIES,
+     CapabilityShader,
+     {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_ID,
+      SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID}},
+    {"TextureSampleProjOffset",
+     6,
+     OpTextureSampleProjOffset,
+     SPV_OPCODE_FLAGS_VARIABLE | SPV_OPCODE_FLAGS_CAPABILITIES,
+     CapabilityShader,
+     {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_ID,
+      SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID}},
+    {"TextureSampleGradOffset",
+     8,
+     OpTextureSampleGradOffset,
+     SPV_OPCODE_FLAGS_CAPABILITIES,
+     CapabilityShader,
+     {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_ID,
+      SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID,
+      SPV_OPERAND_TYPE_ID}},
+    {"TextureSampleProjLodOffset",
+     7,
+     OpTextureSampleProjLodOffset,
+     SPV_OPCODE_FLAGS_CAPABILITIES,
+     CapabilityShader,
+     {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_ID,
+      SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID}},
+    {"TextureSampleProjGradOffset",
+     8,
+     OpTextureSampleProjGradOffset,
+     SPV_OPCODE_FLAGS_CAPABILITIES,
+     CapabilityShader,
+     {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_ID,
+      SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID,
+      SPV_OPERAND_TYPE_ID}},
+    {"TextureFetchTexel",
+     6,
+     OpTextureFetchTexel,
+     SPV_OPCODE_FLAGS_CAPABILITIES,
+     CapabilityShader,
+     {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_ID,
+      SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID}},
+    {"TextureFetchTexelOffset",
+     6,
+     OpTextureFetchTexelOffset,
+     SPV_OPCODE_FLAGS_CAPABILITIES,
+     CapabilityShader,
+     {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_ID,
+      SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID}},
+    {"TextureFetchSample",
+     6,
+     OpTextureFetchSample,
+     SPV_OPCODE_FLAGS_CAPABILITIES,
+     CapabilityShader,
+     {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_ID,
+      SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID}},
+    {"TextureFetchTexel",
+     5,
+     OpTextureFetchTexel,
+     SPV_OPCODE_FLAGS_CAPABILITIES,
+     CapabilityShader,
+     {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_ID,
+      SPV_OPERAND_TYPE_ID}},
+    {"TextureGather",
+     6,
+     OpTextureGather,
+     SPV_OPCODE_FLAGS_CAPABILITIES,
+     CapabilityShader,
+     {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_ID,
+      SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID}},
+    {"TextureGatherOffset",
+     7,
+     OpTextureGatherOffset,
+     SPV_OPCODE_FLAGS_CAPABILITIES,
+     CapabilityShader,
+     {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_ID,
+      SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID,
+      SPV_OPERAND_TYPE_ID}},
+    {"TextureGatherOffsets",
+     7,
+     OpTextureGatherOffsets,
+     SPV_OPCODE_FLAGS_CAPABILITIES,
+     CapabilityShader,
+     {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_ID,
+      SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID}},
+    {"TextureQuerySizeLod",
+     5,
+     OpTextureQuerySizeLod,
+     SPV_OPCODE_FLAGS_CAPABILITIES,
+     CapabilityShader,
+     {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_ID,
+      SPV_OPERAND_TYPE_ID}},
+    {"TextureQuerySize",
+     4,
+     OpTextureQuerySize,
+     SPV_OPCODE_FLAGS_CAPABILITIES,
+     CapabilityShader,
+     {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_ID}},
+    {"TextureQueryLod",
+     5,
+     OpTextureQueryLod,
+     SPV_OPCODE_FLAGS_CAPABILITIES,
+     CapabilityShader,
+     {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_ID,
+      SPV_OPERAND_TYPE_ID}},
+    {"TextureQueryLevels",
+     4,
+     OpTextureQueryLevels,
+     SPV_OPCODE_FLAGS_CAPABILITIES,
+     CapabilityShader,
+     {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_ID}},
+    {"TextureQuerySamples",
+     4,
+     OpTextureQuerySamples,
+     SPV_OPCODE_FLAGS_CAPABILITIES,
+     CapabilityShader,
+     {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_ID}},
+    {"ConvertFToU",
+     4,
+     OpConvertFToU,
+     SPV_OPCODE_FLAGS_NONE,
+     0,
+     {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_ID}},
+    {"ConvertFToS",
+     4,
+     OpConvertFToS,
+     SPV_OPCODE_FLAGS_NONE,
+     0,
+     {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_ID}},
+    {"ConvertSToF",
+     4,
+     OpConvertSToF,
+     SPV_OPCODE_FLAGS_NONE,
+     0,
+     {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_ID}},
+    {"ConvertUToF",
+     4,
+     OpConvertUToF,
+     SPV_OPCODE_FLAGS_NONE,
+     0,
+     {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_ID}},
+    {"UConvert",
+     4,
+     OpUConvert,
+     SPV_OPCODE_FLAGS_NONE,
+     0,
+     {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_ID}},
+    {"SConvert",
+     4,
+     OpSConvert,
+     SPV_OPCODE_FLAGS_NONE,
+     0,
+     {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_ID}},
+    {"FConvert",
+     4,
+     OpFConvert,
+     SPV_OPCODE_FLAGS_NONE,
+     0,
+     {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_ID}},
+    {"ConvertPtrToU",
+     4,
+     OpConvertPtrToU,
+     SPV_OPCODE_FLAGS_CAPABILITIES,
+     CapabilityAddresses,
+     {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_ID}},
+    {"ConvertUToPtr",
+     4,
+     OpConvertUToPtr,
+     SPV_OPCODE_FLAGS_CAPABILITIES,
+     CapabilityAddresses,
+     {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_ID}},
+    {"PtrCastToGeneric",
+     4,
+     OpPtrCastToGeneric,
+     SPV_OPCODE_FLAGS_CAPABILITIES,
+     CapabilityKernel,
+     {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_ID}},
+    {"GenericCastToPtr",
+     4,
+     OpGenericCastToPtr,
+     SPV_OPCODE_FLAGS_CAPABILITIES,
+     CapabilityKernel,
+     {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_ID}},
+    {"Bitcast",
+     4,
+     OpBitcast,
+     SPV_OPCODE_FLAGS_NONE,
+     0,
+     {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_ID}},
+    {"GenericCastToPtrExplicit",
+     5,
+     OpGenericCastToPtrExplicit,
+     SPV_OPCODE_FLAGS_CAPABILITIES,
+     CapabilityKernel,
+     {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_ID,
+      SPV_OPERAND_TYPE_STORAGE_CLASS}},
+    {"SatConvertSToU",
+     4,
+     OpSatConvertSToU,
+     SPV_OPCODE_FLAGS_CAPABILITIES,
+     CapabilityKernel,
+     {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_ID}},
+    {"SatConvertUToS",
+     4,
+     OpSatConvertUToS,
+     SPV_OPCODE_FLAGS_CAPABILITIES,
+     CapabilityKernel,
+     {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_ID}},
+    {"VectorExtractDynamic",
+     5,
+     OpVectorExtractDynamic,
+     SPV_OPCODE_FLAGS_NONE,
+     0,
+     {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_ID,
+      SPV_OPERAND_TYPE_ID}},
+    {"VectorInsertDynamic",
+     6,
+     OpVectorInsertDynamic,
+     SPV_OPCODE_FLAGS_NONE,
+     0,
+     {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_ID,
+      SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID}},
+    {"VectorShuffle",
+     5,
+     OpVectorShuffle,
+     SPV_OPCODE_FLAGS_VARIABLE,
+     0,
+     {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_ID,
+      SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_LITERAL, SPV_OPERAND_TYPE_LITERAL,
+      SPV_OPERAND_TYPE_ELLIPSIS}},
+    {"CompositeConstruct",
+     3,
+     OpCompositeConstruct,
+     SPV_OPCODE_FLAGS_VARIABLE,
+     0,
+     {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_ID,
+      SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ELLIPSIS}},
+    {"CompositeExtract",
+     4,
+     OpCompositeExtract,
+     SPV_OPCODE_FLAGS_VARIABLE,
+     0,
+     {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_ID,
+      SPV_OPERAND_TYPE_LITERAL, SPV_OPERAND_TYPE_LITERAL,
+      SPV_OPERAND_TYPE_ELLIPSIS}},
+    {"CompositeInsert",
+     5,
+     OpCompositeInsert,
+     SPV_OPCODE_FLAGS_VARIABLE,
+     0,
+     {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_ID,
+      SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_LITERAL, SPV_OPERAND_TYPE_LITERAL,
+      SPV_OPERAND_TYPE_ELLIPSIS}},
+    {"CopyObject",
+     4,
+     OpCopyObject,
+     SPV_OPCODE_FLAGS_NONE,
+     0,
+     {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_ID}},
+    {"Transpose",
+     4,
+     OpTranspose,
+     SPV_OPCODE_FLAGS_CAPABILITIES,
+     CapabilityMatrix,
+     {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_ID}},
+    {"SNegate",
+     4,
+     OpSNegate,
+     SPV_OPCODE_FLAGS_NONE,
+     0,
+     {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_ID}},
+    {"FNegate",
+     4,
+     OpFNegate,
+     SPV_OPCODE_FLAGS_NONE,
+     0,
+     {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_ID}},
+    {"Not",
+     4,
+     OpNot,
+     SPV_OPCODE_FLAGS_NONE,
+     0,
+     {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_ID}},
+    {"IAdd",
+     5,
+     OpIAdd,
+     SPV_OPCODE_FLAGS_NONE,
+     0,
+     {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_ID,
+      SPV_OPERAND_TYPE_ID}},
+    {"FAdd",
+     5,
+     OpFAdd,
+     SPV_OPCODE_FLAGS_NONE,
+     0,
+     {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_ID,
+      SPV_OPERAND_TYPE_ID}},
+    {"ISub",
+     5,
+     OpISub,
+     SPV_OPCODE_FLAGS_NONE,
+     0,
+     {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_ID,
+      SPV_OPERAND_TYPE_ID}},
+    {"FSub",
+     5,
+     OpFSub,
+     SPV_OPCODE_FLAGS_NONE,
+     0,
+     {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_ID,
+      SPV_OPERAND_TYPE_ID}},
+    {"IMul",
+     5,
+     OpIMul,
+     SPV_OPCODE_FLAGS_NONE,
+     0,
+     {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_ID,
+      SPV_OPERAND_TYPE_ID}},
+    {"FMul",
+     5,
+     OpFMul,
+     SPV_OPCODE_FLAGS_NONE,
+     0,
+     {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_ID,
+      SPV_OPERAND_TYPE_ID}},
+    {"UDiv",
+     5,
+     OpUDiv,
+     SPV_OPCODE_FLAGS_NONE,
+     0,
+     {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_ID,
+      SPV_OPERAND_TYPE_ID}},
+    {"SDiv",
+     5,
+     OpSDiv,
+     SPV_OPCODE_FLAGS_NONE,
+     0,
+     {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_ID,
+      SPV_OPERAND_TYPE_ID}},
+    {"FDiv",
+     5,
+     OpFDiv,
+     SPV_OPCODE_FLAGS_NONE,
+     0,
+     {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_ID,
+      SPV_OPERAND_TYPE_ID}},
+    {"UMod",
+     5,
+     OpUMod,
+     SPV_OPCODE_FLAGS_NONE,
+     0,
+     {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_ID,
+      SPV_OPERAND_TYPE_ID}},
+    {"SRem",
+     5,
+     OpSRem,
+     SPV_OPCODE_FLAGS_NONE,
+     0,
+     {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_ID,
+      SPV_OPERAND_TYPE_ID}},
+    {"SMod",
+     5,
+     OpSMod,
+     SPV_OPCODE_FLAGS_NONE,
+     0,
+     {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_ID,
+      SPV_OPERAND_TYPE_ID}},
+    {"FRem",
+     5,
+     OpFRem,
+     SPV_OPCODE_FLAGS_NONE,
+     0,
+     {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_ID,
+      SPV_OPERAND_TYPE_ID}},
+    {"FMod",
+     5,
+     OpFMod,
+     SPV_OPCODE_FLAGS_NONE,
+     0,
+     {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_ID,
+      SPV_OPERAND_TYPE_ID}},
+    {"VectorTimesScalar",
+     5,
+     OpVectorTimesScalar,
+     SPV_OPCODE_FLAGS_NONE,
+     0,
+     {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_ID,
+      SPV_OPERAND_TYPE_ID}},
+    {"MatrixTimesScalar",
+     5,
+     OpMatrixTimesScalar,
+     SPV_OPCODE_FLAGS_CAPABILITIES,
+     CapabilityMatrix,
+     {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_ID,
+      SPV_OPERAND_TYPE_ID}},
+    {"VectorTimesMatrix",
+     5,
+     OpVectorTimesMatrix,
+     SPV_OPCODE_FLAGS_CAPABILITIES,
+     CapabilityMatrix,
+     {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_ID,
+      SPV_OPERAND_TYPE_ID}},
+    {"MatrixTimesVector",
+     5,
+     OpMatrixTimesVector,
+     SPV_OPCODE_FLAGS_CAPABILITIES,
+     CapabilityMatrix,
+     {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_ID,
+      SPV_OPERAND_TYPE_ID}},
+    {"MatrixTimesMatrix",
+     5,
+     OpMatrixTimesMatrix,
+     SPV_OPCODE_FLAGS_CAPABILITIES,
+     CapabilityMatrix,
+     {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_ID,
+      SPV_OPERAND_TYPE_ID}},
+    {"OuterProduct",
+     5,
+     OpOuterProduct,
+     SPV_OPCODE_FLAGS_CAPABILITIES,
+     CapabilityMatrix,
+     {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_ID,
+      SPV_OPERAND_TYPE_ID}},
+    {"Dot",
+     5,
+     OpDot,
+     SPV_OPCODE_FLAGS_NONE,
+     0,
+     {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_ID,
+      SPV_OPERAND_TYPE_ID}},
+    {"ShiftRightLogical",
+     5,
+     OpShiftRightLogical,
+     SPV_OPCODE_FLAGS_NONE,
+     0,
+     {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_ID,
+      SPV_OPERAND_TYPE_ID}},
+    {"ShiftRightArithmetic",
+     5,
+     OpShiftRightArithmetic,
+     SPV_OPCODE_FLAGS_NONE,
+     0,
+     {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_ID,
+      SPV_OPERAND_TYPE_ID}},
+    {"ShiftLeftLogical",
+     5,
+     OpShiftLeftLogical,
+     SPV_OPCODE_FLAGS_NONE,
+     0,
+     {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_ID,
+      SPV_OPERAND_TYPE_ID}},
+    {"BitwiseOr",
+     5,
+     OpBitwiseOr,
+     SPV_OPCODE_FLAGS_NONE,
+     0,
+     {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_ID,
+      SPV_OPERAND_TYPE_ID}},
+    {"BitwiseXor",
+     5,
+     OpBitwiseXor,
+     SPV_OPCODE_FLAGS_NONE,
+     0,
+     {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_ID,
+      SPV_OPERAND_TYPE_ID}},
+    {"BitwiseAnd",
+     5,
+     OpBitwiseAnd,
+     SPV_OPCODE_FLAGS_NONE,
+     0,
+     {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_ID,
+      SPV_OPERAND_TYPE_ID}},
+    {"Any",
+     4,
+     OpAny,
+     SPV_OPCODE_FLAGS_NONE,
+     0,
+     {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_ID}},
+    {"All",
+     4,
+     OpAll,
+     SPV_OPCODE_FLAGS_NONE,
+     0,
+     {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_ID}},
+    {"IsNan",
+     4,
+     OpIsNan,
+     SPV_OPCODE_FLAGS_NONE,
+     0,
+     {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_ID}},
+    {"IsInf",
+     4,
+     OpIsInf,
+     SPV_OPCODE_FLAGS_NONE,
+     0,
+     {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_ID}},
+    {"IsFinite",
+     4,
+     OpIsFinite,
+     SPV_OPCODE_FLAGS_CAPABILITIES,
+     CapabilityKernel,
+     {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_ID}},
+    {"IsNormal",
+     4,
+     OpIsNormal,
+     SPV_OPCODE_FLAGS_CAPABILITIES,
+     CapabilityKernel,
+     {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_ID}},
+    {"SignBitSet",
+     4,
+     OpSignBitSet,
+     SPV_OPCODE_FLAGS_CAPABILITIES,
+     CapabilityKernel,
+     {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_ID}},
+    {"LessOrGreater",
+     5,
+     OpLessOrGreater,
+     SPV_OPCODE_FLAGS_CAPABILITIES,
+     CapabilityKernel,
+     {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_ID,
+      SPV_OPERAND_TYPE_ID}},
+    {"Ordered",
+     5,
+     OpOrdered,
+     SPV_OPCODE_FLAGS_CAPABILITIES,
+     CapabilityKernel,
+     {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_ID,
+      SPV_OPERAND_TYPE_ID}},
+    {"Unordered",
+     5,
+     OpUnordered,
+     SPV_OPCODE_FLAGS_CAPABILITIES,
+     CapabilityKernel,
+     {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_ID,
+      SPV_OPERAND_TYPE_ID}},
+    {"LogicalOr",
+     5,
+     OpLogicalOr,
+     SPV_OPCODE_FLAGS_NONE,
+     0,
+     {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_ID,
+      SPV_OPERAND_TYPE_ID}},
+    {"LogicalXor",
+     5,
+     OpLogicalXor,
+     SPV_OPCODE_FLAGS_NONE,
+     0,
+     {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_ID,
+      SPV_OPERAND_TYPE_ID}},
+    {"LogicalAnd",
+     5,
+     OpLogicalAnd,
+     SPV_OPCODE_FLAGS_NONE,
+     0,
+     {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_ID,
+      SPV_OPERAND_TYPE_ID}},
+    {"Select",
+     6,
+     OpSelect,
+     SPV_OPCODE_FLAGS_NONE,
+     0,
+     {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_ID,
+      SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID}},
+    {"IEqual",
+     5,
+     OpIEqual,
+     SPV_OPCODE_FLAGS_NONE,
+     0,
+     {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_ID,
+      SPV_OPERAND_TYPE_ID}},
+    {"FOrdEqual",
+     5,
+     OpFOrdEqual,
+     SPV_OPCODE_FLAGS_NONE,
+     0,
+     {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_ID,
+      SPV_OPERAND_TYPE_ID}},
+    {"FUnordEqual",
+     5,
+     OpFUnordEqual,
+     SPV_OPCODE_FLAGS_NONE,
+     0,
+     {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_ID,
+      SPV_OPERAND_TYPE_ID}},
+    {"INotEqual",
+     5,
+     OpINotEqual,
+     SPV_OPCODE_FLAGS_NONE,
+     0,
+     {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_ID,
+      SPV_OPERAND_TYPE_ID}},
+    {"FOrdNotEqual",
+     5,
+     OpFOrdNotEqual,
+     SPV_OPCODE_FLAGS_NONE,
+     0,
+     {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_ID,
+      SPV_OPERAND_TYPE_ID}},
+    {"FUnordNotEqual",
+     5,
+     OpFUnordNotEqual,
+     SPV_OPCODE_FLAGS_NONE,
+     0,
+     {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_ID,
+      SPV_OPERAND_TYPE_ID}},
+    {"ULessThan",
+     5,
+     OpULessThan,
+     SPV_OPCODE_FLAGS_NONE,
+     0,
+     {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_ID,
+      SPV_OPERAND_TYPE_ID}},
+    {"SLessThan",
+     5,
+     OpSLessThan,
+     SPV_OPCODE_FLAGS_NONE,
+     0,
+     {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_ID,
+      SPV_OPERAND_TYPE_ID}},
+    {"FOrdLessThan",
+     5,
+     OpFOrdLessThan,
+     SPV_OPCODE_FLAGS_NONE,
+     0,
+     {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_ID,
+      SPV_OPERAND_TYPE_ID}},
+    {"FUnordLessThan",
+     5,
+     OpFUnordLessThan,
+     SPV_OPCODE_FLAGS_NONE,
+     0,
+     {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_ID,
+      SPV_OPERAND_TYPE_ID}},
+    {"UGreaterThan",
+     5,
+     OpUGreaterThan,
+     SPV_OPCODE_FLAGS_NONE,
+     0,
+     {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_ID,
+      SPV_OPERAND_TYPE_ID}},
+    {"SGreaterThan",
+     5,
+     OpSGreaterThan,
+     SPV_OPCODE_FLAGS_NONE,
+     0,
+     {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_ID,
+      SPV_OPERAND_TYPE_ID}},
+    {"FOrdGreaterThan",
+     5,
+     OpFOrdGreaterThan,
+     SPV_OPCODE_FLAGS_NONE,
+     0,
+     {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_ID,
+      SPV_OPERAND_TYPE_ID}},
+    {"FUnordGreaterThan",
+     5,
+     OpFUnordGreaterThan,
+     SPV_OPCODE_FLAGS_NONE,
+     0,
+     {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_ID,
+      SPV_OPERAND_TYPE_ID}},
+    {"ULessThanEqual",
+     5,
+     OpULessThanEqual,
+     SPV_OPCODE_FLAGS_NONE,
+     0,
+     {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_ID,
+      SPV_OPERAND_TYPE_ID}},
+    {"SLessThanEqual",
+     5,
+     OpSLessThanEqual,
+     SPV_OPCODE_FLAGS_NONE,
+     0,
+     {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_ID,
+      SPV_OPERAND_TYPE_ID}},
+    {"FOrdLessThanEqual",
+     5,
+     OpFOrdLessThanEqual,
+     SPV_OPCODE_FLAGS_NONE,
+     0,
+     {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_ID,
+      SPV_OPERAND_TYPE_ID}},
+    {"FUnordLessThanEqual",
+     5,
+     OpFUnordLessThanEqual,
+     SPV_OPCODE_FLAGS_NONE,
+     0,
+     {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_ID,
+      SPV_OPERAND_TYPE_ID}},
+    {"UGreaterThanEqual",
+     5,
+     OpUGreaterThanEqual,
+     SPV_OPCODE_FLAGS_NONE,
+     0,
+     {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_ID,
+      SPV_OPERAND_TYPE_ID}},
+    {"SGreaterThanEqual",
+     5,
+     OpSGreaterThanEqual,
+     SPV_OPCODE_FLAGS_NONE,
+     0,
+     {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_ID,
+      SPV_OPERAND_TYPE_ID}},
+    {"FOrdGreaterThanEqual",
+     5,
+     OpFOrdGreaterThanEqual,
+     SPV_OPCODE_FLAGS_NONE,
+     0,
+     {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_ID,
+      SPV_OPERAND_TYPE_ID}},
+    {"FUnordGreaterThanEqual",
+     5,
+     OpFUnordGreaterThanEqual,
+     SPV_OPCODE_FLAGS_NONE,
+     0,
+     {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_ID,
+      SPV_OPERAND_TYPE_ID}},
+    {"DPdx",
+     4,
+     OpDPdx,
+     SPV_OPCODE_FLAGS_CAPABILITIES,
+     CapabilityShader,
+     {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_ID}},
+    {"DPdy",
+     4,
+     OpDPdy,
+     SPV_OPCODE_FLAGS_CAPABILITIES,
+     CapabilityShader,
+     {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_ID}},
+    {
+     "Fwidth",
+     4,
+     OpFwidth,
+     SPV_OPCODE_FLAGS_CAPABILITIES,
+     CapabilityShader,
+     {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_ID},
+    },
+    {"DPdxFine",
+     4,
+     OpDPdxFine,
+     SPV_OPCODE_FLAGS_CAPABILITIES,
+     CapabilityShader,
+     {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_ID}},
+    {"DPdyFine",
+     4,
+     OpDPdyFine,
+     SPV_OPCODE_FLAGS_CAPABILITIES,
+     CapabilityShader,
+     {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_ID}},
+    {
+     "FwidthFine",
+     4,
+     OpFwidthFine,
+     SPV_OPCODE_FLAGS_CAPABILITIES,
+     CapabilityShader,
+     {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_ID},
+    },
+    {"DPdxCoarse",
+     4,
+     OpDPdxCoarse,
+     SPV_OPCODE_FLAGS_CAPABILITIES,
+     CapabilityShader,
+     {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_ID}},
+    {"DPdyCoarse",
+     4,
+     OpDPdyCoarse,
+     SPV_OPCODE_FLAGS_CAPABILITIES,
+     CapabilityShader,
+     {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_ID}},
+    {
+     "FwidthCoarse",
+     4,
+     OpFwidthCoarse,
+     SPV_OPCODE_FLAGS_CAPABILITIES,
+     CapabilityShader,
+     {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_ID},
+    },
+    {"Phi",
+     3,
+     OpPhi,
+     SPV_OPCODE_FLAGS_VARIABLE,
+     0,
+     {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_ID,
+      SPV_OPERAND_TYPE_ID}},
+    {"LoopMerge",
+     3,
+     OpLoopMerge,
+     SPV_OPCODE_FLAGS_NONE,
+     0,
+     {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_LOOP_CONTROL}},
+    {"SelectionMerge",
+     3,
+     OpSelectionMerge,
+     SPV_OPCODE_FLAGS_NONE,
+     0,
+     {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_SELECTION_CONTROL}},
+    {"Label",
+     2,
+     OpLabel,
+     SPV_OPCODE_FLAGS_NONE,
+     0,
+     {SPV_OPERAND_TYPE_RESULT_ID}},
+    {"Branch", 2, OpBranch, SPV_OPCODE_FLAGS_NONE, 0, {SPV_OPERAND_TYPE_ID}},
+    {"BranchConditional",
+     4,
+     OpBranchConditional,
+     SPV_OPCODE_FLAGS_VARIABLE,
+     0,
+     {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID,
+      SPV_OPERAND_TYPE_LITERAL, SPV_OPERAND_TYPE_LITERAL,
+      SPV_OPERAND_TYPE_ELLIPSIS}},
+    {"Switch",
+     3,
+     OpSwitch,
+     SPV_OPCODE_FLAGS_VARIABLE,
+     0,
+     {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID,
+      SPV_OPERAND_TYPE_LITERAL, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_LITERAL,
+      SPV_OPERAND_TYPE_ID}},
+    {"Kill", 1, OpKill, SPV_OPCODE_FLAGS_CAPABILITIES, CapabilityShader, {}},
+    {"Return", 1, OpReturn, SPV_OPCODE_FLAGS_NONE, 0, {}},
+    {"ReturnValue",
+     2,
+     OpReturnValue,
+     SPV_OPCODE_FLAGS_NONE,
+     0,
+     {SPV_OPERAND_TYPE_ID}},
+    {"Unreachable",
+     1,
+     OpUnreachable,
+     SPV_OPCODE_FLAGS_CAPABILITIES,
+     CapabilityKernel,
+     {}},
+    {"LifetimeStart",
+     3,
+     OpLifetimeStart,
+     SPV_OPCODE_FLAGS_NONE,
+     0,
+     {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_LITERAL_NUMBER}},
+    {"LifetimeStop",
+     3,
+     OpLifetimeStop,
+     SPV_OPCODE_FLAGS_NONE,
+     0,
+     {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_LITERAL_NUMBER}},
+    {"AtomicInit",
+     3,
+     OpAtomicInit,
+     SPV_OPCODE_FLAGS_NONE,
+     0,
+     {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID}},
+    {"AtomicLoad",
+     6,
+     OpAtomicLoad,
+     SPV_OPCODE_FLAGS_NONE,
+     0,
+     {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_ID,
+      SPV_OPERAND_TYPE_EXECUTION_SCOPE, SPV_OPERAND_TYPE_MEMORY_SEMANTICS}},
+    {"AtomicStore",
+     5,
+     OpAtomicStore,
+     SPV_OPCODE_FLAGS_NONE,
+     0,
+     {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_EXECUTION_SCOPE,
+      SPV_OPERAND_TYPE_MEMORY_SEMANTICS, SPV_OPERAND_TYPE_ID}},
+    {"AtomicExchange",
+     7,
+     OpAtomicExchange,
+     SPV_OPCODE_FLAGS_NONE,
+     0,
+     {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_ID,
+      SPV_OPERAND_TYPE_EXECUTION_SCOPE, SPV_OPERAND_TYPE_MEMORY_SEMANTICS,
+      SPV_OPERAND_TYPE_ID}},
+    {"AtomicCompareExchange",
+     8,
+     OpAtomicCompareExchange,
+     SPV_OPCODE_FLAGS_NONE,
+     0,
+     {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_ID,
+      SPV_OPERAND_TYPE_EXECUTION_SCOPE, SPV_OPERAND_TYPE_MEMORY_SEMANTICS,
+      SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID}},
+    {"AtomicCompareExchangeWeak",
+     8,
+     OpAtomicCompareExchangeWeak,
+     SPV_OPCODE_FLAGS_NONE,
+     0,
+     {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_ID,
+      SPV_OPERAND_TYPE_EXECUTION_SCOPE, SPV_OPERAND_TYPE_MEMORY_SEMANTICS,
+      SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID}},
+    {"AtomicIIncrement",
+     6,
+     OpAtomicIIncrement,
+     SPV_OPCODE_FLAGS_NONE,
+     0,
+     {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_ID,
+      SPV_OPERAND_TYPE_EXECUTION_SCOPE, SPV_OPERAND_TYPE_MEMORY_SEMANTICS}},
+    {"AtomicIDecrement",
+     6,
+     OpAtomicIDecrement,
+     SPV_OPCODE_FLAGS_NONE,
+     0,
+     {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_ID,
+      SPV_OPERAND_TYPE_EXECUTION_SCOPE, SPV_OPERAND_TYPE_MEMORY_SEMANTICS}},
+    {"AtomicIAdd",
+     7,
+     OpAtomicIAdd,
+     SPV_OPCODE_FLAGS_NONE,
+     0,
+     {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_ID,
+      SPV_OPERAND_TYPE_EXECUTION_SCOPE, SPV_OPERAND_TYPE_MEMORY_SEMANTICS,
+      SPV_OPERAND_TYPE_ID}},
+    {"AtomicISub",
+     7,
+     OpAtomicISub,
+     SPV_OPCODE_FLAGS_NONE,
+     0,
+     {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_ID,
+      SPV_OPERAND_TYPE_EXECUTION_SCOPE, SPV_OPERAND_TYPE_MEMORY_SEMANTICS,
+      SPV_OPERAND_TYPE_ID}},
+    {"AtomicUMin",
+     7,
+     OpAtomicUMin,
+     SPV_OPCODE_FLAGS_NONE,
+     0,
+     {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_ID,
+      SPV_OPERAND_TYPE_EXECUTION_SCOPE, SPV_OPERAND_TYPE_MEMORY_SEMANTICS,
+      SPV_OPERAND_TYPE_ID}},
+    {"AtomicUMax",
+     7,
+     OpAtomicUMax,
+     SPV_OPCODE_FLAGS_NONE,
+     0,
+     {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_ID,
+      SPV_OPERAND_TYPE_EXECUTION_SCOPE, SPV_OPERAND_TYPE_MEMORY_SEMANTICS,
+      SPV_OPERAND_TYPE_ID}},
+    {"AtomicAnd",
+     7,
+     OpAtomicAnd,
+     SPV_OPCODE_FLAGS_NONE,
+     0,
+     {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_ID,
+      SPV_OPERAND_TYPE_EXECUTION_SCOPE, SPV_OPERAND_TYPE_MEMORY_SEMANTICS,
+      SPV_OPERAND_TYPE_ID}},
+    {"AtomicOr",
+     7,
+     OpAtomicOr,
+     SPV_OPCODE_FLAGS_NONE,
+     0,
+     {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_ID,
+      SPV_OPERAND_TYPE_EXECUTION_SCOPE, SPV_OPERAND_TYPE_MEMORY_SEMANTICS,
+      SPV_OPERAND_TYPE_ID}},
+    {"AtomicXor",
+     7,
+     OpAtomicXor,
+     SPV_OPCODE_FLAGS_NONE,
+     0,
+     {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_ID,
+      SPV_OPERAND_TYPE_EXECUTION_SCOPE, SPV_OPERAND_TYPE_MEMORY_SEMANTICS,
+      SPV_OPERAND_TYPE_ID}},
+    {"AtomicIMin",
+     7,
+     OpAtomicIMin,
+     SPV_OPCODE_FLAGS_NONE,
+     0,
+     {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_ID,
+      SPV_OPERAND_TYPE_EXECUTION_SCOPE, SPV_OPERAND_TYPE_MEMORY_SEMANTICS,
+      SPV_OPERAND_TYPE_ID}},
+    {"AtomicIMax",
+     7,
+     OpAtomicIMax,
+     SPV_OPCODE_FLAGS_NONE,
+     0,
+     {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_ID,
+      SPV_OPERAND_TYPE_EXECUTION_SCOPE, SPV_OPERAND_TYPE_MEMORY_SEMANTICS,
+      SPV_OPERAND_TYPE_ID}},
+    {"EmitVertex",
+     1,
+     OpEmitVertex,
+     SPV_OPCODE_FLAGS_CAPABILITIES,
+     CapabilityGeometry,
+     {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_LITERAL_STRING}},
+    {"EndPrimitive",
+     1,
+     OpEndPrimitive,
+     SPV_OPCODE_FLAGS_CAPABILITIES,
+     CapabilityGeometry,
+     {}},
+    {"EmitStreamVertex",
+     2,
+     OpEmitStreamVertex,
+     SPV_OPCODE_FLAGS_CAPABILITIES,
+     CapabilityGeometry,
+     {SPV_OPERAND_TYPE_ID}},
+    {"EndStreamPrimitive",
+     2,
+     OpEndStreamPrimitive,
+     SPV_OPCODE_FLAGS_CAPABILITIES,
+     CapabilityGeometry,
+     {SPV_OPERAND_TYPE_ID}},
+    {"ControlBarrier",
+     2,
+     OpControlBarrier,
+     SPV_OPCODE_FLAGS_NONE,
+     0,
+     {SPV_OPERAND_TYPE_EXECUTION_SCOPE}},
+    {"MemoryBarrier",
+     3,
+     OpMemoryBarrier,
+     SPV_OPCODE_FLAGS_NONE,
+     0,
+     {SPV_OPERAND_TYPE_EXECUTION_SCOPE, SPV_OPERAND_TYPE_MEMORY_SEMANTICS}},
+    {"AsyncGroupCopy",
+     9,
+     OpAsyncGroupCopy,
+     SPV_OPCODE_FLAGS_CAPABILITIES,
+     CapabilityKernel,
+     {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID,
+      SPV_OPERAND_TYPE_EXECUTION_SCOPE, SPV_OPERAND_TYPE_ID,
+      SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID,
+      SPV_OPERAND_TYPE_ID}},
+    {"WaitGroupEvents",
+     6,
+     OpWaitGroupEvents,
+     SPV_OPCODE_FLAGS_CAPABILITIES,
+     CapabilityKernel,
+     {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID,
+      SPV_OPERAND_TYPE_EXECUTION_SCOPE, SPV_OPERAND_TYPE_ID,
+      SPV_OPERAND_TYPE_ID}},
+    {"GroupAll",
+     5,
+     OpGroupAll,
+     SPV_OPCODE_FLAGS_CAPABILITIES,
+     CapabilityGroups,
+     {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID,
+      SPV_OPERAND_TYPE_EXECUTION_SCOPE, SPV_OPERAND_TYPE_ID}},
+    {"GroupAny",
+     5,
+     OpGroupAny,
+     SPV_OPCODE_FLAGS_CAPABILITIES,
+     CapabilityGroups,
+     {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID,
+      SPV_OPERAND_TYPE_EXECUTION_SCOPE, SPV_OPERAND_TYPE_ID}},
+    {"GroupBroadcast",
+     6,
+     OpGroupBroadcast,
+     SPV_OPCODE_FLAGS_CAPABILITIES,
+     CapabilityGroups,
+     {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID,
+      SPV_OPERAND_TYPE_EXECUTION_SCOPE, SPV_OPERAND_TYPE_ID,
+      SPV_OPERAND_TYPE_ID}},
+    {"GroupIAdd",
+     6,
+     OpGroupIAdd,
+     SPV_OPCODE_FLAGS_CAPABILITIES,
+     CapabilityGroups,
+     {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID,
+      SPV_OPERAND_TYPE_EXECUTION_SCOPE, SPV_OPERAND_TYPE_GROUP_OPERATION,
+      SPV_OPERAND_TYPE_ID}},
+    {"GroupFAdd",
+     6,
+     OpGroupFAdd,
+     SPV_OPCODE_FLAGS_CAPABILITIES,
+     CapabilityGroups,
+     {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID,
+      SPV_OPERAND_TYPE_EXECUTION_SCOPE, SPV_OPERAND_TYPE_GROUP_OPERATION,
+      SPV_OPERAND_TYPE_ID}},
+    {"GroupFMin",
+     6,
+     OpGroupFMin,
+     SPV_OPCODE_FLAGS_CAPABILITIES,
+     CapabilityGroups,
+     {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID,
+      SPV_OPERAND_TYPE_EXECUTION_SCOPE, SPV_OPERAND_TYPE_GROUP_OPERATION,
+      SPV_OPERAND_TYPE_ID}},
+    {"GroupUMin",
+     6,
+     OpGroupUMin,
+     SPV_OPCODE_FLAGS_CAPABILITIES,
+     CapabilityGroups,
+     {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID,
+      SPV_OPERAND_TYPE_EXECUTION_SCOPE, SPV_OPERAND_TYPE_GROUP_OPERATION,
+      SPV_OPERAND_TYPE_ID}},
+    {"GroupSMin",
+     6,
+     OpGroupSMin,
+     SPV_OPCODE_FLAGS_CAPABILITIES,
+     CapabilityGroups,
+     {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID,
+      SPV_OPERAND_TYPE_EXECUTION_SCOPE, SPV_OPERAND_TYPE_GROUP_OPERATION,
+      SPV_OPERAND_TYPE_ID}},
+    {"GroupFMax",
+     6,
+     OpGroupFMax,
+     SPV_OPCODE_FLAGS_CAPABILITIES,
+     CapabilityGroups,
+     {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID,
+      SPV_OPERAND_TYPE_EXECUTION_SCOPE, SPV_OPERAND_TYPE_GROUP_OPERATION,
+      SPV_OPERAND_TYPE_ID}},
+    {"GroupUMax",
+     6,
+     OpGroupUMax,
+     SPV_OPCODE_FLAGS_CAPABILITIES,
+     CapabilityGroups,
+     {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID,
+      SPV_OPERAND_TYPE_EXECUTION_SCOPE, SPV_OPERAND_TYPE_GROUP_OPERATION,
+      SPV_OPERAND_TYPE_ID}},
+    {"GroupSMax",
+     6,
+     OpGroupSMax,
+     SPV_OPCODE_FLAGS_CAPABILITIES,
+     CapabilityGroups,
+     {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID,
+      SPV_OPERAND_TYPE_EXECUTION_SCOPE, SPV_OPERAND_TYPE_GROUP_OPERATION,
+      SPV_OPERAND_TYPE_ID}},
+    {"EnqueueMarker",
+     7,
+     OpEnqueueMarker,
+     SPV_OPCODE_FLAGS_CAPABILITIES,
+     CapabilityDeviceEnqueue,
+     {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_ID,
+      SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID}},
+    {"EnqueueKernel",
+     13,
+     OpEnqueueKernel,
+     SPV_OPCODE_FLAGS_VARIABLE | SPV_OPCODE_FLAGS_CAPABILITIES,
+     CapabilityDeviceEnqueue,
+     {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_ID,
+      SPV_OPERAND_TYPE_KERNEL_ENQ_FLAGS, SPV_OPERAND_TYPE_ID,
+      SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID,
+      SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID,
+      SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID,
+      SPV_OPERAND_TYPE_ELLIPSIS}},
+    {"GetKernelNDrangeSubGroupCount",
+     5,
+     OpGetKernelNDrangeSubGroupCount,
+     SPV_OPCODE_FLAGS_CAPABILITIES,
+     CapabilityDeviceEnqueue,
+     {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_ID,
+      SPV_OPERAND_TYPE_ID}},
+    {"GetKernelNDrangeMaxSubGroupSize",
+     5,
+     OpGetKernelNDrangeMaxSubGroupSize,
+     SPV_OPCODE_FLAGS_CAPABILITIES,
+     CapabilityDeviceEnqueue,
+     {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_ID,
+      SPV_OPERAND_TYPE_ID}},
+    {"GetKernelWorkGroupSize",
+     4,
+     OpGetKernelWorkGroupSize,
+     SPV_OPCODE_FLAGS_CAPABILITIES,
+     CapabilityDeviceEnqueue,
+     {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_ID}},
+    {"GetKernelPreferredWorkGroupSizeMultiple",
+     4,
+     OpGetKernelPreferredWorkGroupSizeMultiple,
+     SPV_OPCODE_FLAGS_CAPABILITIES,
+     CapabilityDeviceEnqueue,
+     {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_ID}},
+    {"RetainEvent",
+     2,
+     OpRetainEvent,
+     SPV_OPCODE_FLAGS_CAPABILITIES,
+     CapabilityDeviceEnqueue,
+     {SPV_OPERAND_TYPE_ID}},
+    {"ReleaseEvent",
+     2,
+     OpRetainEvent,
+     SPV_OPCODE_FLAGS_CAPABILITIES,
+     CapabilityDeviceEnqueue,
+     {SPV_OPERAND_TYPE_ID}},
+    {"CreateUserEvent",
+     3,
+     OpCreateUserEvent,
+     SPV_OPCODE_FLAGS_CAPABILITIES,
+     CapabilityDeviceEnqueue,
+     {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID}},
+    {"IsValidEvent",
+     4,
+     OpIsValidEvent,
+     SPV_OPCODE_FLAGS_CAPABILITIES,
+     CapabilityDeviceEnqueue,
+     {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_ID}},
+    {"SetUserEventStatus",
+     3,
+     OpSetUserEventStatus,
+     SPV_OPCODE_FLAGS_CAPABILITIES,
+     CapabilityDeviceEnqueue,
+     {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID}},
+    {"CapabilitytureEventProfilingInfo",
+     4,
+     OpCaptureEventProfilingInfo,
+     SPV_OPCODE_FLAGS_CAPABILITIES,
+     CapabilityDeviceEnqueue,
+     {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_KERENL_PROFILING_INFO,
+      SPV_OPERAND_TYPE_ID}},
+    {"GetDefaultQueue",
+     3,
+     OpGetDefaultQueue,
+     SPV_OPCODE_FLAGS_CAPABILITIES,
+     CapabilityDeviceEnqueue,
+     {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID}},
+    {"BuildNDRange",
+     6,
+     OpBuildNDRange,
+     SPV_OPCODE_FLAGS_CAPABILITIES,
+     CapabilityDeviceEnqueue,
+     {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_ID,
+      SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID}},
+    {"ReadPipe",
+     5,
+     OpReadPipe,
+     SPV_OPCODE_FLAGS_CAPABILITIES,
+     CapabilityPipes,
+     {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_ID,
+      SPV_OPERAND_TYPE_ID}},
+    {"WritePipe",
+     5,
+     OpWritePipe,
+     SPV_OPCODE_FLAGS_CAPABILITIES,
+     CapabilityPipes,
+     {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_ID,
+      SPV_OPERAND_TYPE_ID}},
+    {"ReservedReadPipe",
+     7,
+     OpReservedReadPipe,
+     SPV_OPCODE_FLAGS_CAPABILITIES,
+     CapabilityPipes,
+     {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_ID,
+      SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID}},
+    {"ReservedWritePipe",
+     7,
+     OpReservedWritePipe,
+     SPV_OPCODE_FLAGS_CAPABILITIES,
+     CapabilityPipes,
+     {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_ID,
+      SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID}},
+    {"ReserveReadPipePackets",
+     5,
+     OpReserveReadPipePackets,
+     SPV_OPCODE_FLAGS_CAPABILITIES,
+     CapabilityPipes,
+     {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_ID,
+      SPV_OPERAND_TYPE_ID}},
+    {"ReserveWritePipePackets",
+     5,
+     OpReserveWritePipePackets,
+     SPV_OPCODE_FLAGS_CAPABILITIES,
+     CapabilityPipes,
+     {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_ID,
+      SPV_OPERAND_TYPE_ID}},
+    {"CommitReadPipe",
+     3,
+     OpCommitReadPipe,
+     SPV_OPCODE_FLAGS_CAPABILITIES,
+     CapabilityPipes,
+     {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID}},
+    {"CommitWritePipe",
+     3,
+     OpCommitWritePipe,
+     SPV_OPCODE_FLAGS_CAPABILITIES,
+     CapabilityPipes,
+     {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID}},
+    {"IsValidReserveId",
+     4,
+     OpIsValidReserveId,
+     SPV_OPCODE_FLAGS_CAPABILITIES,
+     CapabilityPipes,
+     {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_ID}},
+    {"GetNumPipePackets",
+     4,
+     OpGetNumPipePackets,
+     SPV_OPCODE_FLAGS_CAPABILITIES,
+     CapabilityPipes,
+     {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_ID}},
+    {"GetMaxPipePackets",
+     4,
+     OpGetMaxPipePackets,
+     SPV_OPCODE_FLAGS_CAPABILITIES,
+     CapabilityPipes,
+     {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_ID}},
+    {"GroupReserveReadPipePackets",
+     6,
+     OpGroupReserveReadPipePackets,
+     SPV_OPCODE_FLAGS_CAPABILITIES,
+     CapabilityPipes,
+     {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID,
+      SPV_OPERAND_TYPE_EXECUTION_SCOPE, SPV_OPERAND_TYPE_ID,
+      SPV_OPERAND_TYPE_ID}},
+    {"GroupReserveWritePipePackets",
+     6,
+     OpGroupReserveWritePipePackets,
+     SPV_OPCODE_FLAGS_CAPABILITIES,
+     CapabilityPipes,
+     {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID,
+      SPV_OPERAND_TYPE_EXECUTION_SCOPE, SPV_OPERAND_TYPE_ID,
+      SPV_OPERAND_TYPE_ID}},
+    {"GroupCommitReadPipe",
+     4,
+     OpGroupCommitReadPipe,
+     SPV_OPCODE_FLAGS_CAPABILITIES,
+     CapabilityPipes,
+     {SPV_OPERAND_TYPE_EXECUTION_SCOPE, SPV_OPERAND_TYPE_ID,
+      SPV_OPERAND_TYPE_ID}},
+    {"GroupCommitWritePipe",
+     4,
+     OpGroupCommitWritePipe,
+     SPV_OPCODE_FLAGS_CAPABILITIES,
+     CapabilityPipes,
+     {SPV_OPERAND_TYPE_EXECUTION_SCOPE, SPV_OPERAND_TYPE_ID,
+      SPV_OPERAND_TYPE_ID}}};
+
+spv_result_t spvOpcodeTableGet(spv_opcode_table *pInstTable) {
+  spvCheck(!pInstTable, return SPV_ERROR_INVALID_POINTER);
+
+  static const spv_opcode_table_t table = {
+      sizeof(opcodeTableEntries) / sizeof(spv_opcode_desc_t),
+      opcodeTableEntries};
+
+  *pInstTable = &table;
+
+  return SPV_SUCCESS;
+}
+
+spv_result_t spvOpcodeTableNameLookup(const spv_opcode_table table,
+                                      const char *name,
+                                      spv_opcode_desc *pEntry) {
+  spvCheck(!name || !pEntry, return SPV_ERROR_INVALID_POINTER);
+  spvCheck(!table, return SPV_ERROR_INVALID_TABLE);
+
+  // TODO: This lookup of the Opcode table is suboptimal! Binary sort would be
+  // preferable but the table requires sorting on the Opcode name, but it's
+  // static
+  // const initialized and matches the order of the spec.
+  const size_t nameLength = strlen(name);
+  for (uint64_t opcodeIndex = 0; opcodeIndex < table->count; ++opcodeIndex) {
+    if (nameLength == strlen(table->entries[opcodeIndex].name) &&
+        !strncmp(name, table->entries[opcodeIndex].name, nameLength)) {
+      // NOTE: Found out Opcode!
+      *pEntry = &table->entries[opcodeIndex];
+      return SPV_SUCCESS;
+    }
+  }
+
+  return SPV_ERROR_INVALID_LOOKUP;
+}
+
+spv_result_t spvOpcodeTableValueLookup(const spv_opcode_table table,
+                                       const Op opcode,
+                                       spv_opcode_desc *pEntry) {
+  spvCheck(!table, return SPV_ERROR_INVALID_TABLE);
+  spvCheck(!pEntry, return SPV_ERROR_INVALID_POINTER);
+
+  // TODO: As above this lookup is not optimal.
+  for (uint64_t opcodeIndex = 0; opcodeIndex < table->count; ++opcodeIndex) {
+    if (opcode == table->entries[opcodeIndex].opcode) {
+      // NOTE: Found the Opcode!
+      *pEntry = &table->entries[opcodeIndex];
+      return SPV_SUCCESS;
+    }
+  }
+
+  return SPV_ERROR_INVALID_LOOKUP;
+}
+
+int32_t spvOpcodeIsVariable(spv_opcode_desc entry) {
+  return SPV_OPCODE_FLAGS_VARIABLE ==
+         (SPV_OPCODE_FLAGS_VARIABLE & entry->flags);
+}
+
+int32_t spvOpcodeRequiresCapabilities(spv_opcode_desc entry) {
+  return SPV_OPCODE_FLAGS_CAPABILITIES ==
+         (SPV_OPCODE_FLAGS_CAPABILITIES & entry->flags);
+}
+
+void spvInstructionCopy(const uint32_t *words, const Op opcode,
+                        const uint16_t wordCount, const spv_endianness_t endian,
+                        spv_instruction_t *pInst) {
+  pInst->opcode = opcode;
+  pInst->wordCount = wordCount;
+  for (uint16_t wordIndex = 0; wordIndex < wordCount; ++wordIndex) {
+    pInst->words[wordIndex] = spvFixWord(words[wordIndex], endian);
+    if (!wordIndex) {
+      uint16_t thisWordCount;
+      Op thisOpcode;
+      spvOpcodeSplit(pInst->words[wordIndex], &thisWordCount, &thisOpcode);
+      assert(opcode == thisOpcode && wordCount == thisWordCount &&
+             "Endianness failed!");
+    }
+  }
+}
+
+const char *spvOpcodeString(const Op opcode) {
+#define CASE(OPCODE) \
+  case OPCODE:       \
+    return #OPCODE;
+  switch (opcode) {
+    CASE(OpNop)
+    CASE(OpSource)
+    CASE(OpSourceExtension)
+    CASE(OpExtension)
+    CASE(OpExtInstImport)
+    CASE(OpMemoryModel)
+    CASE(OpEntryPoint)
+    CASE(OpExecutionMode)
+    CASE(OpTypeVoid)
+    CASE(OpTypeBool)
+    CASE(OpTypeInt)
+    CASE(OpTypeFloat)
+    CASE(OpTypeVector)
+    CASE(OpTypeMatrix)
+    CASE(OpTypeSampler)
+    CASE(OpTypeFilter)
+    CASE(OpTypeArray)
+    CASE(OpTypeRuntimeArray)
+    CASE(OpTypeStruct)
+    CASE(OpTypeOpaque)
+    CASE(OpTypePointer)
+    CASE(OpTypeFunction)
+    CASE(OpTypeEvent)
+    CASE(OpTypeDeviceEvent)
+    CASE(OpTypeReserveId)
+    CASE(OpTypeQueue)
+    CASE(OpTypePipe)
+    CASE(OpConstantTrue)
+    CASE(OpConstantFalse)
+    CASE(OpConstant)
+    CASE(OpConstantComposite)
+    CASE(OpConstantSampler)
+    CASE(OpConstantNull)
+    CASE(OpSpecConstantTrue)
+    CASE(OpSpecConstantFalse)
+    CASE(OpSpecConstant)
+    CASE(OpSpecConstantComposite)
+    CASE(OpVariable)
+    CASE(OpVariableArray)
+    CASE(OpFunction)
+    CASE(OpFunctionParameter)
+    CASE(OpFunctionEnd)
+    CASE(OpFunctionCall)
+    CASE(OpExtInst)
+    CASE(OpUndef)
+    CASE(OpLoad)
+    CASE(OpStore)
+    CASE(OpPhi)
+    CASE(OpDecorationGroup)
+    CASE(OpDecorate)
+    CASE(OpMemberDecorate)
+    CASE(OpGroupDecorate)
+    CASE(OpGroupMemberDecorate)
+    CASE(OpName)
+    CASE(OpMemberName)
+    CASE(OpString)
+    CASE(OpLine)
+    CASE(OpVectorExtractDynamic)
+    CASE(OpVectorInsertDynamic)
+    CASE(OpVectorShuffle)
+    CASE(OpCompositeConstruct)
+    CASE(OpCompositeExtract)
+    CASE(OpCompositeInsert)
+    CASE(OpCopyObject)
+    CASE(OpCopyMemory)
+    CASE(OpCopyMemorySized)
+    CASE(OpSampler)
+    CASE(OpTextureSample)
+    CASE(OpTextureSampleDref)
+    CASE(OpTextureSampleLod)
+    CASE(OpTextureSampleProj)
+    CASE(OpTextureSampleGrad)
+    CASE(OpTextureSampleOffset)
+    CASE(OpTextureSampleProjLod)
+    CASE(OpTextureSampleProjGrad)
+    CASE(OpTextureSampleLodOffset)
+    CASE(OpTextureSampleProjOffset)
+    CASE(OpTextureSampleGradOffset)
+    CASE(OpTextureSampleProjLodOffset)
+    CASE(OpTextureSampleProjGradOffset)
+    CASE(OpTextureFetchTexelOffset)
+    CASE(OpTextureFetchSample)
+    CASE(OpTextureFetchTexel)
+    CASE(OpTextureGather)
+    CASE(OpTextureGatherOffset)
+    CASE(OpTextureGatherOffsets)
+    CASE(OpTextureQuerySizeLod)
+    CASE(OpTextureQuerySize)
+    CASE(OpTextureQueryLod)
+    CASE(OpTextureQueryLevels)
+    CASE(OpTextureQuerySamples)
+    CASE(OpAccessChain)
+    CASE(OpInBoundsAccessChain)
+    CASE(OpSNegate)
+    CASE(OpFNegate)
+    CASE(OpNot)
+    CASE(OpAny)
+    CASE(OpAll)
+    CASE(OpConvertFToU)
+    CASE(OpConvertFToS)
+    CASE(OpConvertSToF)
+    CASE(OpConvertUToF)
+    CASE(OpUConvert)
+    CASE(OpSConvert)
+    CASE(OpFConvert)
+    CASE(OpConvertPtrToU)
+    CASE(OpConvertUToPtr)
+    CASE(OpPtrCastToGeneric)
+    CASE(OpGenericCastToPtr)
+    CASE(OpBitcast)
+    CASE(OpTranspose)
+    CASE(OpIsNan)
+    CASE(OpIsInf)
+    CASE(OpIsFinite)
+    CASE(OpIsNormal)
+    CASE(OpSignBitSet)
+    CASE(OpLessOrGreater)
+    CASE(OpOrdered)
+    CASE(OpUnordered)
+    CASE(OpArrayLength)
+    CASE(OpIAdd)
+    CASE(OpFAdd)
+    CASE(OpISub)
+    CASE(OpFSub)
+    CASE(OpIMul)
+    CASE(OpFMul)
+    CASE(OpUDiv)
+    CASE(OpSDiv)
+    CASE(OpFDiv)
+    CASE(OpUMod)
+    CASE(OpSRem)
+    CASE(OpSMod)
+    CASE(OpFRem)
+    CASE(OpFMod)
+    CASE(OpVectorTimesScalar)
+    CASE(OpMatrixTimesScalar)
+    CASE(OpVectorTimesMatrix)
+    CASE(OpMatrixTimesVector)
+    CASE(OpMatrixTimesMatrix)
+    CASE(OpOuterProduct)
+    CASE(OpDot)
+    CASE(OpShiftRightLogical)
+    CASE(OpShiftRightArithmetic)
+    CASE(OpShiftLeftLogical)
+    CASE(OpLogicalOr)
+    CASE(OpLogicalXor)
+    CASE(OpLogicalAnd)
+    CASE(OpBitwiseOr)
+    CASE(OpBitwiseXor)
+    CASE(OpBitwiseAnd)
+    CASE(OpSelect)
+    CASE(OpIEqual)
+    CASE(OpFOrdEqual)
+    CASE(OpFUnordEqual)
+    CASE(OpINotEqual)
+    CASE(OpFOrdNotEqual)
+    CASE(OpFUnordNotEqual)
+    CASE(OpULessThan)
+    CASE(OpSLessThan)
+    CASE(OpFOrdLessThan)
+    CASE(OpFUnordLessThan)
+    CASE(OpUGreaterThan)
+    CASE(OpSGreaterThan)
+    CASE(OpFOrdGreaterThan)
+    CASE(OpFUnordGreaterThan)
+    CASE(OpULessThanEqual)
+    CASE(OpSLessThanEqual)
+    CASE(OpFOrdLessThanEqual)
+    CASE(OpFUnordLessThanEqual)
+    CASE(OpUGreaterThanEqual)
+    CASE(OpSGreaterThanEqual)
+    CASE(OpFOrdGreaterThanEqual)
+    CASE(OpFUnordGreaterThanEqual)
+    CASE(OpDPdx)
+    CASE(OpDPdy)
+    CASE(OpFwidth)
+    CASE(OpDPdxFine)
+    CASE(OpDPdyFine)
+    CASE(OpFwidthFine)
+    CASE(OpDPdxCoarse)
+    CASE(OpDPdyCoarse)
+    CASE(OpFwidthCoarse)
+    CASE(OpEmitVertex)
+    CASE(OpEndPrimitive)
+    CASE(OpEmitStreamVertex)
+    CASE(OpEndStreamPrimitive)
+    CASE(OpControlBarrier)
+    CASE(OpMemoryBarrier)
+    CASE(OpImagePointer)
+    CASE(OpAtomicInit)
+    CASE(OpAtomicLoad)
+    CASE(OpAtomicStore)
+    CASE(OpAtomicExchange)
+    CASE(OpAtomicCompareExchange)
+    CASE(OpAtomicCompareExchangeWeak)
+    CASE(OpAtomicIIncrement)
+    CASE(OpAtomicIDecrement)
+    CASE(OpAtomicIAdd)
+    CASE(OpAtomicISub)
+    CASE(OpAtomicUMin)
+    CASE(OpAtomicUMax)
+    CASE(OpAtomicAnd)
+    CASE(OpAtomicOr)
+    CASE(OpAtomicXor)
+    CASE(OpLoopMerge)
+    CASE(OpSelectionMerge)
+    CASE(OpLabel)
+    CASE(OpBranch)
+    CASE(OpBranchConditional)
+    CASE(OpSwitch)
+    CASE(OpKill)
+    CASE(OpReturn)
+    CASE(OpReturnValue)
+    CASE(OpUnreachable)
+    CASE(OpLifetimeStart)
+    CASE(OpLifetimeStop)
+    CASE(OpCompileFlag)
+    CASE(OpAsyncGroupCopy)
+    CASE(OpWaitGroupEvents)
+    CASE(OpGroupAll)
+    CASE(OpGroupAny)
+    CASE(OpGroupBroadcast)
+    CASE(OpGroupIAdd)
+    CASE(OpGroupFAdd)
+    CASE(OpGroupFMin)
+    CASE(OpGroupUMin)
+    CASE(OpGroupSMin)
+    CASE(OpGroupFMax)
+    CASE(OpGroupUMax)
+    CASE(OpGroupSMax)
+    CASE(OpGenericCastToPtrExplicit)
+    CASE(OpGenericPtrMemSemantics)
+    CASE(OpReadPipe)
+    CASE(OpWritePipe)
+    CASE(OpReservedReadPipe)
+    CASE(OpReservedWritePipe)
+    CASE(OpReserveReadPipePackets)
+    CASE(OpReserveWritePipePackets)
+    CASE(OpCommitReadPipe)
+    CASE(OpCommitWritePipe)
+    CASE(OpIsValidReserveId)
+    CASE(OpGetNumPipePackets)
+    CASE(OpGetMaxPipePackets)
+    CASE(OpGroupReserveReadPipePackets)
+    CASE(OpGroupReserveWritePipePackets)
+    CASE(OpGroupCommitReadPipe)
+    CASE(OpGroupCommitWritePipe)
+    CASE(OpEnqueueMarker)
+    CASE(OpEnqueueKernel)
+    CASE(OpGetKernelNDrangeSubGroupCount)
+    CASE(OpGetKernelNDrangeMaxSubGroupSize)
+    CASE(OpGetKernelWorkGroupSize)
+    CASE(OpGetKernelPreferredWorkGroupSizeMultiple)
+    CASE(OpRetainEvent)
+    CASE(OpReleaseEvent)
+    CASE(OpCreateUserEvent)
+    CASE(OpIsValidEvent)
+    CASE(OpSetUserEventStatus)
+    CASE(OpCaptureEventProfilingInfo)
+    CASE(OpGetDefaultQueue)
+    CASE(OpBuildNDRange)
+    default:
+      assert(0 && "Unreachable!");
+  }
+#undef CASE
+  return "unknown";
+}
+
+int32_t spvOpcodeIsType(const Op opcode) {
+  switch (opcode) {
+    case OpTypeVoid:
+    case OpTypeBool:
+    case OpTypeInt:
+    case OpTypeFloat:
+    case OpTypeVector:
+    case OpTypeMatrix:
+    case OpTypeSampler:
+    case OpTypeFilter:
+    case OpTypeArray:
+    case OpTypeRuntimeArray:
+    case OpTypeStruct:
+    case OpTypeOpaque:
+    case OpTypePointer:
+    case OpTypeFunction:
+    case OpTypeEvent:
+    case OpTypeDeviceEvent:
+    case OpTypeReserveId:
+    case OpTypeQueue:
+    case OpTypePipe:
+      return true;
+    default:
+      return false;
+  }
+}
+
+int32_t spvOpcodeIsScalarType(const Op opcode) {
+  switch (opcode) {
+    case OpTypeInt:
+    case OpTypeFloat:
+      return true;
+    default:
+      return false;
+  }
+}
+
+int32_t spvOpcodeIsConstant(const Op opcode) {
+  switch (opcode) {
+    case OpConstantTrue:
+    case OpConstantFalse:
+    case OpConstant:
+    case OpConstantComposite:
+    case OpConstantSampler:
+    // case OpConstantNull:
+    case OpConstantNull:
+    case OpSpecConstantTrue:
+    case OpSpecConstantFalse:
+    case OpSpecConstant:
+    case OpSpecConstantComposite:
+      // case OpSpecConstantOp:
+      return true;
+    default:
+      return false;
+  }
+}
+
+int32_t spvOpcodeIsComposite(const Op opcode) {
+  switch (opcode) {
+    case OpTypeVector:
+    case OpTypeMatrix:
+    case OpTypeArray:
+    case OpTypeStruct:
+      return true;
+    default:
+      return false;
+  }
+}
+
+int32_t spvOpcodeAreTypesEqual(const spv_instruction_t *pTypeInst0,
+                               const spv_instruction_t *pTypeInst1) {
+  spvCheck(pTypeInst0->opcode != pTypeInst1->opcode, return false);
+  spvCheck(pTypeInst0->words[1] != pTypeInst1->words[1], return false);
+  return true;
+}
+
+int32_t spvOpcodeIsPointer(const Op opcode) {
+  switch (opcode) {
+    case OpVariable:
+    case OpVariableArray:
+    case OpAccessChain:
+    case OpInBoundsAccessChain:
+    // TODO: case OpImagePointer:
+    case OpFunctionParameter:
+      return true;
+    default:
+      return false;
+  }
+}
+
+int32_t spvOpcodeIsObject(const Op opcode) {
+  switch (opcode) {
+    case OpConstantTrue:
+    case OpConstantFalse:
+    case OpConstant:
+    case OpConstantComposite:
+    // TODO: case OpConstantSampler:
+    case OpConstantNull:
+    case OpSpecConstantTrue:
+    case OpSpecConstantFalse:
+    case OpSpecConstant:
+    case OpSpecConstantComposite:
+    // TODO: case OpSpecConstantOp:
+    case OpVariable:
+    case OpVariableArray:
+    case OpAccessChain:
+    case OpInBoundsAccessChain:
+    case OpConvertFToU:
+    case OpConvertFToS:
+    case OpConvertSToF:
+    case OpConvertUToF:
+    case OpUConvert:
+    case OpSConvert:
+    case OpFConvert:
+    case OpConvertPtrToU:
+    // TODO: case OpConvertUToPtr:
+    case OpPtrCastToGeneric:
+    // TODO: case OpGenericCastToPtr:
+    case OpBitcast:
+    // TODO: case OpGenericCastToPtrExplicit:
+    case OpSatConvertSToU:
+    case OpSatConvertUToS:
+    case OpVectorExtractDynamic:
+    case OpCompositeConstruct:
+    case OpCompositeExtract:
+    case OpCopyObject:
+    case OpTranspose:
+    case OpSNegate:
+    case OpFNegate:
+    case OpNot:
+    case OpIAdd:
+    case OpFAdd:
+    case OpISub:
+    case OpFSub:
+    case OpIMul:
+    case OpFMul:
+    case OpUDiv:
+    case OpSDiv:
+    case OpFDiv:
+    case OpUMod:
+    case OpSRem:
+    case OpSMod:
+    case OpVectorTimesScalar:
+    case OpMatrixTimesScalar:
+    case OpVectorTimesMatrix:
+    case OpMatrixTimesVector:
+    case OpMatrixTimesMatrix:
+    case OpOuterProduct:
+    case OpDot:
+    case OpShiftRightLogical:
+    case OpShiftRightArithmetic:
+    case OpShiftLeftLogical:
+    case OpBitwiseOr:
+    case OpBitwiseXor:
+    case OpBitwiseAnd:
+    case OpAny:
+    case OpAll:
+    case OpIsNan:
+    case OpIsInf:
+    case OpIsFinite:
+    case OpIsNormal:
+    case OpSignBitSet:
+    case OpLessOrGreater:
+    case OpOrdered:
+    case OpUnordered:
+    case OpLogicalOr:
+    case OpLogicalXor:
+    case OpLogicalAnd:
+    case OpSelect:
+    case OpIEqual:
+    case OpFOrdEqual:
+    case OpFUnordEqual:
+    case OpINotEqual:
+    case OpFOrdNotEqual:
+    case OpFUnordNotEqual:
+    case OpULessThan:
+    case OpSLessThan:
+    case OpFOrdLessThan:
+    case OpFUnordLessThan:
+    case OpUGreaterThan:
+    case OpSGreaterThan:
+    case OpFOrdGreaterThan:
+    case OpFUnordGreaterThan:
+    case OpULessThanEqual:
+    case OpSLessThanEqual:
+    case OpFOrdLessThanEqual:
+    case OpFUnordLessThanEqual:
+    case OpUGreaterThanEqual:
+    case OpSGreaterThanEqual:
+    case OpFOrdGreaterThanEqual:
+    case OpFUnordGreaterThanEqual:
+    case OpDPdx:
+    case OpDPdy:
+    case OpFwidth:
+    case OpDPdxFine:
+    case OpDPdyFine:
+    case OpFwidthFine:
+    case OpDPdxCoarse:
+    case OpDPdyCoarse:
+    case OpFwidthCoarse:
+    case OpReturnValue:
+      return true;
+    default:
+      return false;
+  }
+}
+
+int32_t spvOpcodeIsBasicTypeNullable(Op opcode) {
+  switch (opcode) {
+    case OpTypeBool:
+    case OpTypeInt:
+    case OpTypeFloat:
+    case OpTypePointer:
+    case OpTypeEvent:
+    case OpTypeDeviceEvent:
+    case OpTypeReserveId:
+    case OpTypeQueue:
+      return true;
+    default:
+      return false;
+  }
+}
+
+int32_t spvInstructionIsInBasicBlock(const spv_instruction_t *pFirstInst,
+                                     const spv_instruction_t *pInst) {
+  while (pFirstInst != pInst) {
+    spvCheck(OpFunction == pInst->opcode, break);
+    pInst--;
+  }
+  spvCheck(OpFunction != pInst->opcode, return false);
+  return true;
+}
+
+int32_t spvOpcodeIsValue(Op opcode) {
+  spvCheck(spvOpcodeIsPointer(opcode), return true);
+  spvCheck(spvOpcodeIsConstant(opcode), return true);
+  switch (opcode) {
+    case OpLoad:
+      // TODO: Other Opcode's resulting in a value
+      return true;
+    default:
+      return false;
+  }
+}
diff --git a/source/opcode.h b/source/opcode.h
new file mode 100644 (file)
index 0000000..32c225e
--- /dev/null
@@ -0,0 +1,186 @@
+// Copyright (c) 2015 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.
+
+#ifndef _LIBSPIRV_UTIL_OPCODE_H_
+#define _LIBSPIRV_UTIL_OPCODE_H_
+
+#include <libspirv/libspirv.h>
+
+// Functions
+
+/// @brief Get the name of the SPIR-V generator
+///
+/// @param[in] generator Khronos SPIR-V generator ID
+///
+/// @return string name
+const char *spvGeneratorStr(uint32_t generator);
+
+/// @brief Combine word count and Opcode enumerant in single word
+///
+/// @param[in] wordCount Opcode consumes
+/// @param[in] opcode enumerant value
+///
+/// @return Opcode word
+uint32_t spvOpcodeMake(uint16_t wordCount, Op opcode);
+
+/// @brief Split the binary opcode into its constituent parts
+///
+/// @param[in] word binary opcode to split
+/// @param[out] wordCount the returned number of words (optional)
+/// @param[out] opcode the returned opcode enumerant (optional)
+void spvOpcodeSplit(const uint32_t word, uint16_t *wordCount, Op *opcode);
+
+/// @brief Find the named Opcode in the table
+///
+/// @param[in] table to lookup
+/// @param[in] name name of Opcode to find
+/// @param[out] pEntry returned Opcode table entry
+///
+/// @return result code
+spv_result_t spvOpcodeTableNameLookup(const spv_opcode_table table,
+                                    const char *name, spv_opcode_desc *pEntry);
+
+/// @brief Find the opcode ID in the table
+///
+/// @param[out] table to lookup
+/// @param[in] opcode value of Opcode to fine
+/// @param[out] pEntry return Opcode table entry
+///
+/// @return result code
+spv_result_t spvOpcodeTableValueLookup(const spv_opcode_table table,
+                                     const Op opcode, spv_opcode_desc *pEntry);
+
+/// @brief Determine if the Opcode has variable word count
+///
+/// This function does not check if @a entry is valid.
+///
+/// @param[in] entry the Opcode entry
+///
+/// @return zero if false, non-zero otherwise
+int32_t spvOpcodeIsVariable(spv_opcode_desc entry);
+
+/// @brief Determine if the Opcode has capaspvity requirements
+///
+/// This function does not check if @a entry is valid.
+///
+/// @param[in] entry the Opcode entry
+///
+/// @return zero if false, non-zero otherwise
+int32_t spvOpcodeRequiresCapabilities(spv_opcode_desc entry);
+
+/// @brief Copy an instructions word and fix the endianness
+///
+/// @param[in] words the input instruction stream
+/// @param[in] opcode the instructions Opcode
+/// @param[in] wordCount the number of words to copy
+/// @param[in] endian the endianness of the stream
+/// @param[out] pInst the returned instruction
+void spvInstructionCopy(const uint32_t *words, const Op opcode,
+                        const uint16_t wordCount, const spv_endianness_t endian,
+                        spv_instruction_t *pInst);
+
+/// @brief Get the string of an OpCode
+///
+/// @param[in] opcode the opcode
+///
+/// @return the opcode string
+const char *spvOpcodeString(const Op opcode);
+
+/// @brief Determine if the Opcode is a type
+///
+/// @param[in] opcode the opcode
+///
+/// @return zero if false, non-zero otherwise
+int32_t spvOpcodeIsType(const Op opcode);
+
+/// @brief Determine if the OpCode is a scalar type
+///
+/// @param[in] opcode the opcode
+///
+/// @return zero if false, non-zero otherwise
+int32_t spvOpcodeIsScalarType(const Op opcode);
+
+/// @brief Determine if the Opcode is a constant
+///
+/// @param[in] opcode the opcode
+///
+/// @return zero if false, non-zero otherwise
+int32_t spvOpcodeIsConstant(const Op opcode);
+
+/// @brief Determine if the Opcode is a composite type
+///
+/// @param[in] opcode the opcode
+///
+/// @return zero if false, non-zero otherwise
+int32_t spvOpcodeIsComposite(const Op opcode);
+
+/// @brief Deep comparison of type declaration instructions
+///
+/// @param[in] pTypeInst0 type definition zero
+/// @param[in] pTypeInst1 type definition one
+///
+/// @return zero if false, non-zero otherwise
+int32_t spvOpcodeAreTypesEqual(const spv_instruction_t *pTypeInst0,
+                               const spv_instruction_t *pTypeInst1);
+
+/// @brief Determine if the Opcode results in a pointer
+///
+/// @param[in] opcode the opcode
+///
+/// @return zero if false, non-zero otherwise
+int32_t spvOpcodeIsPointer(const Op opcode);
+
+/// @brief Determine if the Opcode results in a instantation of a non-void type
+///
+/// @param[in] opcode the opcode
+///
+/// @return zero if false, non-zero otherwise
+int32_t spvOpcodeIsObject(const Op opcode);
+
+/// @brief Determine if the scalar type Opcode is nullable
+///
+/// @param[in] opcode the opcode
+///
+/// @return zero if false, non-zero otherwise
+int32_t spvOpcodeIsBasicTypeNullable(Op opcode);
+
+/// @brief Determine if instruction is in a basic block
+///
+/// @param[in] pFirstInst first instruction in the stream
+/// @param[in] pInst current instruction
+///
+/// @return zero if false, non-zero otherwise
+int32_t spvInstructionIsInBasicBlock(const spv_instruction_t *pFirstInst,
+                                     const spv_instruction_t *pInst);
+
+/// @brief Determine if the Opcode contains a value
+///
+/// @param[in] opcode the opcode
+///
+/// @return zero if false, non-zero otherwise
+int32_t spvOpcodeIsValue(Op opcode);
+
+#endif
diff --git a/source/operand.cpp b/source/operand.cpp
new file mode 100644 (file)
index 0000000..73eb4b9
--- /dev/null
@@ -0,0 +1,1519 @@
+// Copyright (c) 2015 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.
+
+#include "operand.h"
+
+#include <assert.h>
+#include <string.h>
+
+static const spv_operand_desc_t sourceLanguageEntries[] = {
+    {"Unknown",
+     SourceLanguageUnknown,
+     SPV_OPCODE_FLAGS_NONE,
+     0,
+     {SPV_OPERAND_TYPE_NONE}},
+    {"ESSL",
+     SourceLanguageESSL,
+     SPV_OPCODE_FLAGS_NONE,
+     0,
+     {SPV_OPERAND_TYPE_NONE}},
+    {"GLSL",
+     SourceLanguageGLSL,
+     SPV_OPCODE_FLAGS_NONE,
+     0,
+     {SPV_OPERAND_TYPE_NONE}},
+    {"OpenCL",
+     SourceLanguageOpenCL,
+     SPV_OPCODE_FLAGS_NONE,
+     0,
+     {SPV_OPERAND_TYPE_NONE}},
+};
+
+static const spv_operand_desc_t executionModelEntries[] = {
+    {"Vertex",
+     ExecutionModelVertex,
+     SPV_OPCODE_FLAGS_CAPABILITIES,
+     CapabilityShader,
+     {SPV_OPERAND_TYPE_NONE}},
+    {"TessellationControl",
+     ExecutionModelTessellationControl,
+     SPV_OPCODE_FLAGS_CAPABILITIES,
+     CapabilityTessellation,
+     {SPV_OPERAND_TYPE_NONE}},
+    {"TessellationEvaluation",
+     ExecutionModelTessellationEvaluation,
+     SPV_OPCODE_FLAGS_CAPABILITIES,
+     CapabilityTessellation,
+     {SPV_OPERAND_TYPE_NONE}},
+    {"Geometry",
+     ExecutionModelGeometry,
+     SPV_OPCODE_FLAGS_CAPABILITIES,
+     CapabilityGeometry,
+     {SPV_OPERAND_TYPE_NONE}},
+    {"Fragment",
+     ExecutionModelFragment,
+     SPV_OPCODE_FLAGS_CAPABILITIES,
+     CapabilityShader,
+     {SPV_OPERAND_TYPE_NONE}},
+    {"GLCompute",
+     ExecutionModelGLCompute,
+     SPV_OPCODE_FLAGS_CAPABILITIES,
+     CapabilityShader,
+     {SPV_OPERAND_TYPE_NONE}},
+    {"Kernel",
+     ExecutionModelKernel,
+     SPV_OPCODE_FLAGS_CAPABILITIES,
+     CapabilityKernel,
+     {SPV_OPERAND_TYPE_NONE}},
+};
+
+static const spv_operand_desc_t addressingModelEntries[] = {
+    {"Logical",
+     AddressingModelLogical,
+     SPV_OPCODE_FLAGS_NONE,
+     0,
+     {SPV_OPERAND_TYPE_NONE}},
+    {"Physical32",
+     AddressingModelPhysical32,
+     SPV_OPCODE_FLAGS_CAPABILITIES,
+     CapabilityAddresses,
+     {SPV_OPERAND_TYPE_NONE}},
+    {"Physical64",
+     AddressingModelPhysical64,
+     SPV_OPCODE_FLAGS_CAPABILITIES,
+     CapabilityAddresses,
+     {SPV_OPERAND_TYPE_NONE}},
+};
+
+static const spv_operand_desc_t memoryModelEntries[] = {
+    {"Simple",
+     MemoryModelSimple,
+     SPV_OPCODE_FLAGS_CAPABILITIES,
+     CapabilityShader,
+     {SPV_OPERAND_TYPE_NONE}},
+    {"GLSL450",
+     MemoryModelGLSL450,
+     SPV_OPCODE_FLAGS_CAPABILITIES,
+     CapabilityShader,
+     {SPV_OPERAND_TYPE_NONE}},
+    {"OpenCL1.2",
+     MemoryModelOpenCL12,
+     SPV_OPCODE_FLAGS_CAPABILITIES,
+     CapabilityKernel,
+     {SPV_OPERAND_TYPE_NONE}},
+    {"OpenCL2.0",
+     MemoryModelOpenCL20,
+     SPV_OPCODE_FLAGS_CAPABILITIES,
+     CapabilityKernel,
+     {SPV_OPERAND_TYPE_NONE}},
+    {"OpenCL2.1",
+     MemoryModelOpenCL21,
+     SPV_OPCODE_FLAGS_CAPABILITIES,
+     CapabilityKernel,
+     {SPV_OPERAND_TYPE_NONE}},
+};
+
+static const spv_operand_desc_t executionModeEntries[] = {
+    {"Invocations",
+     ExecutionModeInvocations,
+     SPV_OPCODE_FLAGS_CAPABILITIES,
+     CapabilityGeometry,
+     {SPV_OPERAND_TYPE_LITERAL_NUMBER, SPV_OPERAND_TYPE_NONE}},
+    {"SpacingEqual",
+     ExecutionModeSpacingEqual,
+     SPV_OPCODE_FLAGS_CAPABILITIES,
+     CapabilityTessellation,
+     {SPV_OPERAND_TYPE_NONE}},
+    {"SpacingFractionalEven",
+     ExecutionModeSpacingFractionalEven,
+     SPV_OPCODE_FLAGS_CAPABILITIES,
+     CapabilityTessellation,
+     {SPV_OPERAND_TYPE_NONE}},
+    {"SpacingFractionalOdd",
+     ExecutionModeSpacingFractionalOdd,
+     SPV_OPCODE_FLAGS_CAPABILITIES,
+     CapabilityTessellation,
+     {SPV_OPERAND_TYPE_NONE}},
+    {"VertexOrderCw",
+     ExecutionModeVertexOrderCw,
+     SPV_OPCODE_FLAGS_CAPABILITIES,
+     CapabilityTessellation,
+     {SPV_OPERAND_TYPE_NONE}},
+    {"VertexOrderCcw",
+     ExecutionModeVertexOrderCcw,
+     SPV_OPCODE_FLAGS_CAPABILITIES,
+     CapabilityTessellation,
+     {SPV_OPERAND_TYPE_NONE}},
+    {"PixelCenterInteger",
+     ExecutionModePixelCenterInteger,
+     SPV_OPCODE_FLAGS_CAPABILITIES,
+     CapabilityShader,
+     {SPV_OPERAND_TYPE_NONE}},
+    {"OriginUpperLeft",
+     ExecutionModeOriginUpperLeft,
+     SPV_OPCODE_FLAGS_CAPABILITIES,
+     CapabilityShader,
+     {SPV_OPERAND_TYPE_NONE}},
+    {"EarlyFragmentTests",
+     ExecutionModeEarlyFragmentTests,
+     SPV_OPCODE_FLAGS_CAPABILITIES,
+     CapabilityShader,
+     {SPV_OPERAND_TYPE_NONE}},
+    {"PointMode",
+     ExecutionModePointMode,
+     SPV_OPCODE_FLAGS_CAPABILITIES,
+     CapabilityTessellation,
+     {SPV_OPERAND_TYPE_NONE}},
+    {"Xfb",
+     ExecutionModeXfb,
+     SPV_OPCODE_FLAGS_CAPABILITIES,
+     CapabilityShader,
+     {SPV_OPERAND_TYPE_NONE}},
+    {"DepthReplacing",
+     ExecutionModeDepthReplacing,
+     SPV_OPCODE_FLAGS_CAPABILITIES,
+     CapabilityShader,
+     {SPV_OPERAND_TYPE_NONE}},
+    {"DepthAny",
+     ExecutionModeDepthAny,
+     SPV_OPCODE_FLAGS_CAPABILITIES,
+     CapabilityShader,
+     {SPV_OPERAND_TYPE_NONE}},
+    {"DepthGreater",
+     ExecutionModeDepthGreater,
+     SPV_OPCODE_FLAGS_CAPABILITIES,
+     CapabilityShader,
+     {SPV_OPERAND_TYPE_NONE}},
+    {"DepthLess",
+     ExecutionModeDepthLess,
+     SPV_OPCODE_FLAGS_CAPABILITIES,
+     CapabilityShader,
+     {SPV_OPERAND_TYPE_NONE}},
+    {"DepthUnchanged",
+     ExecutionModeDepthUnchanged,
+     SPV_OPCODE_FLAGS_CAPABILITIES,
+     CapabilityShader,
+     {SPV_OPERAND_TYPE_NONE}},
+    {"LocalSize",
+     ExecutionModeLocalSize,
+     SPV_OPCODE_FLAGS_NONE,
+     0,
+     {SPV_OPERAND_TYPE_LITERAL_NUMBER, SPV_OPERAND_TYPE_LITERAL_NUMBER,
+      SPV_OPERAND_TYPE_LITERAL_NUMBER, SPV_OPERAND_TYPE_NONE}},
+    {"LocalSizeHint",
+     ExecutionModeLocalSizeHint,
+     SPV_OPCODE_FLAGS_CAPABILITIES,
+     CapabilityKernel,
+     {SPV_OPERAND_TYPE_LITERAL_NUMBER, SPV_OPERAND_TYPE_LITERAL_NUMBER,
+      SPV_OPERAND_TYPE_LITERAL_NUMBER, SPV_OPERAND_TYPE_NONE}},
+    {"InputPoints",
+     ExecutionModeInputPoints,
+     SPV_OPCODE_FLAGS_CAPABILITIES,
+     CapabilityGeometry,
+     {SPV_OPERAND_TYPE_NONE}},
+    {"InputLines",
+     ExecutionModeInputLines,
+     SPV_OPCODE_FLAGS_CAPABILITIES,
+     CapabilityGeometry,
+     {SPV_OPERAND_TYPE_NONE}},
+    {"InputLinesAdjacency",
+     ExecutionModeInputLinesAdjacency,
+     SPV_OPCODE_FLAGS_CAPABILITIES,
+     CapabilityGeometry,
+     {SPV_OPERAND_TYPE_NONE}},
+    {"InputTriangles",
+     ExecutionModeInputTriangles,
+     SPV_OPCODE_FLAGS_CAPABILITIES,
+     CapabilityGeometry | CapabilityTessellation,
+     {SPV_OPERAND_TYPE_NONE}},
+    {"InputTrianglesAdjacency",
+     ExecutionModeInputTrianglesAdjacency,
+     SPV_OPCODE_FLAGS_CAPABILITIES,
+     CapabilityGeometry,
+     {SPV_OPERAND_TYPE_NONE}},
+    {"InputQuads",
+     ExecutionModeInputQuads,
+     SPV_OPCODE_FLAGS_CAPABILITIES,
+     CapabilityTessellation,
+     {SPV_OPERAND_TYPE_NONE}},
+    {"InputIsolines",
+     ExecutionModeInputIsolines,
+     SPV_OPCODE_FLAGS_CAPABILITIES,
+     CapabilityTessellation,
+     {SPV_OPERAND_TYPE_NONE}},
+    {"OutputVertices",
+     ExecutionModeOutputVertices,
+     SPV_OPCODE_FLAGS_CAPABILITIES,
+     CapabilityGeometry | CapabilityTessellation,
+     {SPV_OPERAND_TYPE_LITERAL_NUMBER, SPV_OPERAND_TYPE_NONE}},
+    {"OutputPoints",
+     ExecutionModeOutputPoints,
+     SPV_OPCODE_FLAGS_CAPABILITIES,
+     CapabilityGeometry,
+     {SPV_OPERAND_TYPE_NONE}},
+    {"OutputLineStrip",
+     ExecutionModeOutputLineStrip,
+     SPV_OPCODE_FLAGS_CAPABILITIES,
+     CapabilityGeometry,
+     {SPV_OPERAND_TYPE_NONE}},
+    {"OutputTriangleStrip",
+     ExecutionModeOutputTriangleStrip,
+     SPV_OPCODE_FLAGS_CAPABILITIES,
+     CapabilityGeometry,
+     {SPV_OPERAND_TYPE_NONE}},
+    {"VecTypeHint",
+     ExecutionModeVecTypeHint,
+     SPV_OPCODE_FLAGS_CAPABILITIES,
+     CapabilityKernel,
+     {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_NONE}},
+    {"ContractionOff",
+     ExecutionModeContractionOff,
+     SPV_OPCODE_FLAGS_CAPABILITIES,
+     CapabilityKernel,
+     {SPV_OPERAND_TYPE_NONE}},
+    {
+     "OriginLowerLeft",
+     ExecutionModeOriginLowerLeft,
+     SPV_OPCODE_FLAGS_CAPABILITIES,
+     CapabilityShader,
+     {SPV_OPERAND_TYPE_NONE},
+    },
+};
+
+static const spv_operand_desc_t storageClassEntries[] = {
+    {"UniformConstant",
+     StorageClassUniformConstant,
+     SPV_OPCODE_FLAGS_NONE,
+     0,
+     {SPV_OPERAND_TYPE_NONE}},
+    {"Input",
+     StorageClassInput,
+     SPV_OPCODE_FLAGS_CAPABILITIES,
+     CapabilityShader,
+     {SPV_OPERAND_TYPE_NONE}},
+    {"Uniform",
+     StorageClassUniform,
+     SPV_OPCODE_FLAGS_CAPABILITIES,
+     CapabilityShader,
+     {SPV_OPERAND_TYPE_NONE}},
+    {"Output",
+     StorageClassOutput,
+     SPV_OPCODE_FLAGS_CAPABILITIES,
+     CapabilityShader,
+     {SPV_OPERAND_TYPE_NONE}},
+    {"WorkgroupLocal",
+     StorageClassWorkgroupLocal,
+     SPV_OPCODE_FLAGS_NONE,
+     0,
+     {SPV_OPERAND_TYPE_NONE}},
+    {"WorkgroupGlobal",
+     StorageClassWorkgroupGlobal,
+     SPV_OPCODE_FLAGS_NONE,
+     0,
+     {SPV_OPERAND_TYPE_NONE}},
+    {"PrivateGlobal",
+     StorageClassPrivateGlobal,
+     SPV_OPCODE_FLAGS_CAPABILITIES,
+     CapabilityShader,
+     {SPV_OPERAND_TYPE_NONE}},
+    {"Function",
+     StorageClassFunction,
+     SPV_OPCODE_FLAGS_NONE,
+     0,
+     {SPV_OPERAND_TYPE_NONE}},
+    {"Generic",
+     StorageClassGeneric,
+     SPV_OPCODE_FLAGS_CAPABILITIES,
+     CapabilityKernel,
+     {SPV_OPERAND_TYPE_NONE}},
+    {"AtomicCounter",
+     StorageClassAtomicCounter,
+     SPV_OPCODE_FLAGS_CAPABILITIES,
+     CapabilityShader,
+     {SPV_OPERAND_TYPE_NONE}},
+};
+
+static const spv_operand_desc_t dimensionalityEntries[] = {
+    {"1D", Dim1D, SPV_OPCODE_FLAGS_NONE, 0, {SPV_OPERAND_TYPE_NONE}},
+    {"2D", Dim2D, SPV_OPCODE_FLAGS_NONE, 0, {SPV_OPERAND_TYPE_NONE}},
+    {"3D", Dim3D, SPV_OPCODE_FLAGS_NONE, 0, {SPV_OPERAND_TYPE_NONE}},
+    {"Cube",
+     DimCube,
+     SPV_OPCODE_FLAGS_CAPABILITIES,
+     CapabilityShader,
+     {SPV_OPERAND_TYPE_NONE}},
+    {"Rect",
+     DimRect,
+     SPV_OPCODE_FLAGS_CAPABILITIES,
+     CapabilityShader,
+     {SPV_OPERAND_TYPE_NONE}},
+    {"Buffer", DimBuffer, SPV_OPCODE_FLAGS_NONE, 0, {SPV_OPERAND_TYPE_NONE}},
+};
+
+static const spv_operand_desc_t samplerAddressingModeEntries[] = {
+    {"None",
+     SamplerAddressingModeNone,
+     SPV_OPCODE_FLAGS_CAPABILITIES,
+     CapabilityKernel,
+     {SPV_OPERAND_TYPE_NONE}},
+    {"ClampToEdge",
+     SamplerAddressingModeClampToEdge,
+     SPV_OPCODE_FLAGS_CAPABILITIES,
+     CapabilityKernel,
+     {SPV_OPERAND_TYPE_NONE}},
+    {"Clamp",
+     SamplerAddressingModeClamp,
+     SPV_OPCODE_FLAGS_CAPABILITIES,
+     CapabilityKernel,
+     {SPV_OPERAND_TYPE_NONE}},
+    {"Repeat",
+     SamplerAddressingModeRepeat,
+     SPV_OPCODE_FLAGS_CAPABILITIES,
+     CapabilityKernel,
+     {SPV_OPERAND_TYPE_NONE}},
+    {"RepeatMirrored",
+     SamplerAddressingModeRepeatMirrored,
+     SPV_OPCODE_FLAGS_CAPABILITIES,
+     CapabilityKernel,
+     {SPV_OPERAND_TYPE_NONE}},
+};
+
+static const spv_operand_desc_t samplerFilterModeEntries[] = {
+    {"Nearest",
+     SamplerFilterModeNearest,
+     SPV_OPCODE_FLAGS_CAPABILITIES,
+     CapabilityKernel,
+     {SPV_OPERAND_TYPE_NONE}},
+    {"Linear",
+     SamplerFilterModeLinear,
+     SPV_OPCODE_FLAGS_CAPABILITIES,
+     CapabilityKernel,
+     {SPV_OPERAND_TYPE_NONE}},
+};
+
+static const spv_operand_desc_t fpFastMathModeEntries[] = {
+    {"None",
+     FPFastMathModeMaskNone,
+     SPV_OPCODE_FLAGS_NONE,
+     0,
+     {SPV_OPERAND_TYPE_NONE}},
+    {"NotNaN",
+     FPFastMathModeNotNaNMask,
+     SPV_OPCODE_FLAGS_CAPABILITIES,
+     CapabilityKernel,
+     {SPV_OPERAND_TYPE_NONE}},
+    {"NotInf",
+     FPFastMathModeNotInfMask,
+     SPV_OPCODE_FLAGS_CAPABILITIES,
+     CapabilityKernel,
+     {SPV_OPERAND_TYPE_NONE}},
+    {"NSZ",
+     FPFastMathModeNSZMask,
+     SPV_OPCODE_FLAGS_CAPABILITIES,
+     CapabilityKernel,
+     {SPV_OPERAND_TYPE_NONE}},
+    {"AllowRecip",
+     FPFastMathModeAllowRecipMask,
+     SPV_OPCODE_FLAGS_CAPABILITIES,
+     CapabilityKernel,
+     {SPV_OPERAND_TYPE_NONE}},
+    {"Fast",
+     FPFastMathModeFastMask,
+     SPV_OPCODE_FLAGS_CAPABILITIES,
+     CapabilityKernel,
+     {SPV_OPERAND_TYPE_NONE}},
+};
+
+static const spv_operand_desc_t fpRoundingModeEntries[] = {
+    {"RTE",
+     FPRoundingModeRTE,
+     SPV_OPCODE_FLAGS_CAPABILITIES,
+     CapabilityKernel,
+     {SPV_OPERAND_TYPE_NONE}},
+    {"RTZ",
+     FPRoundingModeRTZ,
+     SPV_OPCODE_FLAGS_CAPABILITIES,
+     CapabilityKernel,
+     {SPV_OPERAND_TYPE_NONE}},
+    {"RTP",
+     FPRoundingModeRTP,
+     SPV_OPCODE_FLAGS_CAPABILITIES,
+     CapabilityKernel,
+     {SPV_OPERAND_TYPE_NONE}},
+    {"RTN",
+     FPRoundingModeRTN,
+     SPV_OPCODE_FLAGS_CAPABILITIES,
+     CapabilityKernel,
+     {SPV_OPERAND_TYPE_NONE}},
+};
+
+static const spv_operand_desc_t linkageTypeEntries[] = {
+    {"Export",
+     LinkageTypeExport,
+     SPV_OPCODE_FLAGS_CAPABILITIES,
+     CapabilityLinkage,
+     {SPV_OPERAND_TYPE_NONE}},
+    {"Import",
+     LinkageTypeImport,
+     SPV_OPCODE_FLAGS_CAPABILITIES,
+     CapabilityLinkage,
+     {SPV_OPERAND_TYPE_NONE}},
+};
+
+static const spv_operand_desc_t accessQualifierEntries[] = {
+    {"ReadOnly",
+     AccessQualifierReadOnly,
+     SPV_OPCODE_FLAGS_CAPABILITIES,
+     CapabilityKernel,
+     {SPV_OPERAND_TYPE_NONE}},
+    {"WriteOnly",
+     AccessQualifierWriteOnly,
+     SPV_OPCODE_FLAGS_CAPABILITIES,
+     CapabilityKernel,
+     {SPV_OPERAND_TYPE_NONE}},
+    {"ReadWrite",
+     AccessQualifierReadWrite,
+     SPV_OPCODE_FLAGS_CAPABILITIES,
+     CapabilityKernel,
+     {SPV_OPERAND_TYPE_NONE}},
+};
+
+static const spv_operand_desc_t functionParameterAttributeEntries[] = {
+    {"Zext",
+     FunctionParameterAttributeZext,
+     SPV_OPCODE_FLAGS_CAPABILITIES,
+     CapabilityKernel,
+     {SPV_OPERAND_TYPE_NONE}},
+    {"Sext",
+     FunctionParameterAttributeSext,
+     SPV_OPCODE_FLAGS_CAPABILITIES,
+     CapabilityKernel,
+     {SPV_OPERAND_TYPE_NONE}},
+    {"ByVal",
+     FunctionParameterAttributeByVal,
+     SPV_OPCODE_FLAGS_CAPABILITIES,
+     CapabilityKernel,
+     {SPV_OPERAND_TYPE_NONE}},
+    {"Sret",
+     FunctionParameterAttributeSret,
+     SPV_OPCODE_FLAGS_CAPABILITIES,
+     CapabilityKernel,
+     {SPV_OPERAND_TYPE_NONE}},
+    {"NoAlias",
+     FunctionParameterAttributeNoAlias,
+     SPV_OPCODE_FLAGS_CAPABILITIES,
+     CapabilityKernel,
+     {SPV_OPERAND_TYPE_NONE}},
+    {"NoCapabilityture",
+     FunctionParameterAttributeNoCapture,
+     SPV_OPCODE_FLAGS_CAPABILITIES,
+     CapabilityKernel,
+     {SPV_OPERAND_TYPE_NONE}},
+    {"SVM",
+     FunctionParameterAttributeSVM,
+     SPV_OPCODE_FLAGS_CAPABILITIES,
+     CapabilityKernel,
+     {SPV_OPERAND_TYPE_NONE}},
+    {"NoWrite",
+     FunctionParameterAttributeNoWrite,
+     SPV_OPCODE_FLAGS_CAPABILITIES,
+     CapabilityKernel,
+     {SPV_OPERAND_TYPE_NONE}},
+    {"NoReadWrite",
+     FunctionParameterAttributeNoReadWrite,
+     SPV_OPCODE_FLAGS_CAPABILITIES,
+     CapabilityKernel,
+     {SPV_OPERAND_TYPE_NONE}},
+};
+
+static const spv_operand_desc_t decorationEntries[] = {
+    {"PrecisionLow",
+     DecorationPrecisionLow,
+     SPV_OPCODE_FLAGS_CAPABILITIES,
+     CapabilityShader,
+     {SPV_OPERAND_TYPE_NONE}},
+    {"PrecisionMedium",
+     DecorationPrecisionMedium,
+     SPV_OPCODE_FLAGS_CAPABILITIES,
+     CapabilityShader,
+     {SPV_OPERAND_TYPE_NONE}},
+    {"PrecisionHigh",
+     DecorationPrecisionHigh,
+     SPV_OPCODE_FLAGS_CAPABILITIES,
+     CapabilityShader,
+     {SPV_OPERAND_TYPE_NONE}},
+    {"Block",
+     DecorationBlock,
+     SPV_OPCODE_FLAGS_CAPABILITIES,
+     CapabilityShader,
+     {SPV_OPERAND_TYPE_NONE}},
+    {"BufferBlock",
+     DecorationBufferBlock,
+     SPV_OPCODE_FLAGS_CAPABILITIES,
+     CapabilityShader,
+     {SPV_OPERAND_TYPE_NONE}},
+    {"RowMajor",
+     DecorationRowMajor,
+     SPV_OPCODE_FLAGS_CAPABILITIES,
+     CapabilityMatrix,
+     {SPV_OPERAND_TYPE_NONE}},
+    {"ColMajor",
+     DecorationColMajor,
+     SPV_OPCODE_FLAGS_CAPABILITIES,
+     CapabilityMatrix,
+     {SPV_OPERAND_TYPE_NONE}},
+    {"GLSLShared",
+     DecorationGLSLShared,
+     SPV_OPCODE_FLAGS_CAPABILITIES,
+     CapabilityShader,
+     {SPV_OPERAND_TYPE_NONE}},
+    {"GLSLStd140",
+     DecorationGLSLStd140,
+     SPV_OPCODE_FLAGS_CAPABILITIES,
+     CapabilityShader,
+     {SPV_OPERAND_TYPE_NONE}},
+    {"GLSLStd430",
+     DecorationGLSLStd430,
+     SPV_OPCODE_FLAGS_CAPABILITIES,
+     CapabilityShader,
+     {SPV_OPERAND_TYPE_NONE}},
+    {"GLSLPacked",
+     DecorationGLSLPacked,
+     SPV_OPCODE_FLAGS_CAPABILITIES,
+     CapabilityShader,
+     {SPV_OPERAND_TYPE_NONE}},
+    {"Smooth",
+     DecorationSmooth,
+     SPV_OPCODE_FLAGS_CAPABILITIES,
+     CapabilityShader,
+     {SPV_OPERAND_TYPE_NONE}},
+    {"Noperspective",
+     DecorationNoperspective,
+     SPV_OPCODE_FLAGS_CAPABILITIES,
+     CapabilityShader,
+     {SPV_OPERAND_TYPE_NONE}},
+    {"Flat",
+     DecorationFlat,
+     SPV_OPCODE_FLAGS_CAPABILITIES,
+     CapabilityShader,
+     {SPV_OPERAND_TYPE_NONE}},
+    {"Patch",
+     DecorationPatch,
+     SPV_OPCODE_FLAGS_CAPABILITIES,
+     CapabilityTessellation,
+     {SPV_OPERAND_TYPE_NONE}},
+    {"Centroid",
+     DecorationCentroid,
+     SPV_OPCODE_FLAGS_CAPABILITIES,
+     CapabilityShader,
+     {SPV_OPERAND_TYPE_NONE}},
+    {"Sample",
+     DecorationSample,
+     SPV_OPCODE_FLAGS_CAPABILITIES,
+     CapabilityShader,
+     {SPV_OPERAND_TYPE_NONE}},
+    {"Invariant",
+     DecorationInvariant,
+     SPV_OPCODE_FLAGS_CAPABILITIES,
+     CapabilityShader,
+     {SPV_OPERAND_TYPE_NONE}},
+    {"Restrict",
+     DecorationRestrict,
+     SPV_OPCODE_FLAGS_NONE,
+     0,
+     {SPV_OPERAND_TYPE_NONE}},
+    {"Aliased",
+     DecorationAliased,
+     SPV_OPCODE_FLAGS_NONE,
+     0,
+     {SPV_OPERAND_TYPE_NONE}},
+    {"Volatile",
+     DecorationVolatile,
+     SPV_OPCODE_FLAGS_NONE,
+     0,
+     {SPV_OPERAND_TYPE_NONE}},
+    {"Constant",
+     DecorationConstant,
+     SPV_OPCODE_FLAGS_CAPABILITIES,
+     CapabilityKernel,
+     {SPV_OPERAND_TYPE_NONE}},
+    {"Coherent",
+     DecorationCoherent,
+     SPV_OPCODE_FLAGS_NONE,
+     0,
+     {SPV_OPERAND_TYPE_NONE}},
+    {"Nonwritable",
+     DecorationNonwritable,
+     SPV_OPCODE_FLAGS_NONE,
+     0,
+     {SPV_OPERAND_TYPE_NONE}},
+    {"Nonreadable",
+     DecorationNonreadable,
+     SPV_OPCODE_FLAGS_NONE,
+     0,
+     {SPV_OPERAND_TYPE_NONE}},
+    {"Uniform",
+     DecorationUniform,
+     SPV_OPCODE_FLAGS_CAPABILITIES,
+     CapabilityShader,
+     {SPV_OPERAND_TYPE_NONE}},
+    {"NoStaticUse",
+     DecorationNoStaticUse,
+     SPV_OPCODE_FLAGS_NONE,
+     0,
+     {SPV_OPERAND_TYPE_NONE}},
+    {"CPacked",
+     DecorationCPacked,
+     SPV_OPCODE_FLAGS_CAPABILITIES,
+     CapabilityKernel,
+     {SPV_OPERAND_TYPE_NONE}},
+    {"FPSaturatedConversion",
+     DecorationSaturatedConversion,
+     SPV_OPCODE_FLAGS_CAPABILITIES,
+     CapabilityKernel,
+     {SPV_OPERAND_TYPE_NONE}},
+    {"Stream",
+     DecorationStream,
+     SPV_OPCODE_FLAGS_CAPABILITIES,
+     CapabilityGeometry,
+     {SPV_OPERAND_TYPE_LITERAL_NUMBER, SPV_OPERAND_TYPE_NONE}},
+    {"Location",
+     DecorationLocation,
+     SPV_OPCODE_FLAGS_CAPABILITIES,
+     CapabilityShader,
+     {SPV_OPERAND_TYPE_LITERAL_NUMBER, SPV_OPERAND_TYPE_NONE}},
+    {"Component",
+     DecorationComponent,
+     SPV_OPCODE_FLAGS_CAPABILITIES,
+     CapabilityShader,
+     {SPV_OPERAND_TYPE_LITERAL_NUMBER, SPV_OPERAND_TYPE_NONE}},
+    {"Index",
+     DecorationIndex,
+     SPV_OPCODE_FLAGS_CAPABILITIES,
+     CapabilityShader,
+     {SPV_OPERAND_TYPE_LITERAL_NUMBER, SPV_OPERAND_TYPE_NONE}},
+    {"Binding",
+     DecorationBinding,
+     SPV_OPCODE_FLAGS_CAPABILITIES,
+     CapabilityShader,
+     {SPV_OPERAND_TYPE_LITERAL_NUMBER, SPV_OPERAND_TYPE_NONE}},
+    {"DescriptorSet",
+     DecorationDescriptorSet,
+     SPV_OPCODE_FLAGS_CAPABILITIES,
+     CapabilityShader,
+     {SPV_OPERAND_TYPE_LITERAL_NUMBER, SPV_OPERAND_TYPE_NONE}},
+    {"Offset",
+     DecorationOffset,
+     SPV_OPCODE_FLAGS_NONE,
+     0,
+     {SPV_OPERAND_TYPE_LITERAL_NUMBER, SPV_OPERAND_TYPE_NONE}},
+    {"Alignment",
+     DecorationAlignment,
+     SPV_OPCODE_FLAGS_NONE,
+     0,
+     {SPV_OPERAND_TYPE_LITERAL_NUMBER, SPV_OPERAND_TYPE_NONE}},
+    {"XfbBuffer",
+     DecorationXfbBuffer,
+     SPV_OPCODE_FLAGS_CAPABILITIES,
+     CapabilityShader,
+     {SPV_OPERAND_TYPE_LITERAL_NUMBER, SPV_OPERAND_TYPE_NONE}},
+    {"Stride",
+     DecorationStride,
+     SPV_OPCODE_FLAGS_CAPABILITIES,
+     CapabilityShader,
+     {SPV_OPERAND_TYPE_LITERAL_NUMBER, SPV_OPERAND_TYPE_NONE}},
+    {"BuiltIn",
+     DecorationBuiltIn,
+     SPV_OPCODE_FLAGS_CAPABILITIES,
+     CapabilityShader,
+     {SPV_OPERAND_TYPE_BUILT_IN, SPV_OPERAND_TYPE_NONE}},
+    {"FuncParamAttr",
+     DecorationFuncParamAttr,
+     SPV_OPCODE_FLAGS_CAPABILITIES,
+     CapabilityKernel,
+     {SPV_OPERAND_TYPE_FUNCTION_PARAMETER_ATTRIBUTE, SPV_OPERAND_TYPE_NONE}},
+    {"FPRoundingMode",
+     DecorationFPRoundingMode,
+     SPV_OPCODE_FLAGS_CAPABILITIES,
+     CapabilityKernel,
+     {SPV_OPERAND_TYPE_FP_ROUNDING_MODE, SPV_OPERAND_TYPE_NONE}},
+    {"FPFastMathMode",
+     DecorationFPRoundingMode,
+     SPV_OPCODE_FLAGS_CAPABILITIES,
+     CapabilityKernel,
+     {SPV_OPERAND_TYPE_FP_FAST_MATH_MODE, SPV_OPERAND_TYPE_NONE}},
+    {"LinkageAttributes",
+     DecorationLinkageAttributes,
+     SPV_OPCODE_FLAGS_CAPABILITIES,
+     CapabilityLinkage,
+     {SPV_OPERAND_TYPE_LINKAGE_TYPE, SPV_OPERAND_TYPE_NONE}},
+    {
+     "SpecId",
+     DecorationSpecId,
+     SPV_OPCODE_FLAGS_CAPABILITIES,
+     CapabilityShader,
+     {SPV_OPERAND_TYPE_LITERAL_NUMBER},
+    },
+};
+
+static const spv_operand_desc_t builtInEntries[] = {
+    {"Position",
+     BuiltInPosition,
+     SPV_OPCODE_FLAGS_CAPABILITIES,
+     CapabilityShader,
+     {SPV_OPERAND_TYPE_NONE}},
+    {"PointSize",
+     BuiltInPointSize,
+     SPV_OPCODE_FLAGS_CAPABILITIES,
+     CapabilityShader,
+     {SPV_OPERAND_TYPE_NONE}},
+    {"ClipVertex",
+     BuiltInClipVertex,
+     SPV_OPCODE_FLAGS_CAPABILITIES,
+     CapabilityShader,
+     {SPV_OPERAND_TYPE_NONE}},
+    {"ClipDistance",
+     BuiltInClipDistance,
+     SPV_OPCODE_FLAGS_CAPABILITIES,
+     CapabilityShader,
+     {SPV_OPERAND_TYPE_NONE}},
+    {"CullDistance",
+     BuiltInCullDistance,
+     SPV_OPCODE_FLAGS_CAPABILITIES,
+     CapabilityShader,
+     {SPV_OPERAND_TYPE_NONE}},
+    {"VertexId",
+     BuiltInVertexId,
+     SPV_OPCODE_FLAGS_CAPABILITIES,
+     CapabilityShader,
+     {SPV_OPERAND_TYPE_NONE}},
+    {"InstanceId",
+     BuiltInInstanceId,
+     SPV_OPCODE_FLAGS_CAPABILITIES,
+     CapabilityShader,
+     {SPV_OPERAND_TYPE_NONE}},
+    {"PrimitiveId",
+     BuiltInPrimitiveId,
+     SPV_OPCODE_FLAGS_CAPABILITIES,
+     CapabilityGeometry | CapabilityTessellation,
+     {SPV_OPERAND_TYPE_NONE}},
+    {"InvocationId",
+     BuiltInInvocationId,
+     SPV_OPCODE_FLAGS_CAPABILITIES,
+     CapabilityGeometry | CapabilityTessellation,
+     {SPV_OPERAND_TYPE_NONE}},
+    {"Layer",
+     BuiltInLayer,
+     SPV_OPCODE_FLAGS_CAPABILITIES,
+     CapabilityGeometry,
+     {SPV_OPERAND_TYPE_NONE}},
+    {"ViewportIndex",
+     BuiltInViewportIndex,
+     SPV_OPCODE_FLAGS_CAPABILITIES,
+     CapabilityGeometry,
+     {SPV_OPERAND_TYPE_NONE}},
+    {"TessLevelOuter",
+     BuiltInTessLevelOuter,
+     SPV_OPCODE_FLAGS_CAPABILITIES,
+     CapabilityTessellation,
+     {SPV_OPERAND_TYPE_NONE}},
+    {"TessLevelInner",
+     BuiltInTessLevelInner,
+     SPV_OPCODE_FLAGS_CAPABILITIES,
+     CapabilityTessellation,
+     {SPV_OPERAND_TYPE_NONE}},
+    {"TessCoord",
+     BuiltInTessCoord,
+     SPV_OPCODE_FLAGS_CAPABILITIES,
+     CapabilityTessellation,
+     {SPV_OPERAND_TYPE_NONE}},
+    {"PatchVertices",
+     BuiltInPatchVertices,
+     SPV_OPCODE_FLAGS_CAPABILITIES,
+     CapabilityTessellation,
+     {SPV_OPERAND_TYPE_NONE}},
+    {"FragCoord",
+     BuiltInFragCoord,
+     SPV_OPCODE_FLAGS_CAPABILITIES,
+     CapabilityShader,
+     {SPV_OPERAND_TYPE_NONE}},
+    {"PointCoord",
+     BuiltInPointCoord,
+     SPV_OPCODE_FLAGS_CAPABILITIES,
+     CapabilityShader,
+     {SPV_OPERAND_TYPE_NONE}},
+    {"FrontFacing",
+     BuiltInFrontFacing,
+     SPV_OPCODE_FLAGS_CAPABILITIES,
+     CapabilityShader,
+     {SPV_OPERAND_TYPE_NONE}},
+    {"SampleId",
+     BuiltInSampleId,
+     SPV_OPCODE_FLAGS_CAPABILITIES,
+     CapabilityShader,
+     {SPV_OPERAND_TYPE_NONE}},
+    {"SamplePosition",
+     BuiltInSamplePosition,
+     SPV_OPCODE_FLAGS_CAPABILITIES,
+     CapabilityShader,
+     {SPV_OPERAND_TYPE_NONE}},
+    {"SampleMask",
+     BuiltInSampleMask,
+     SPV_OPCODE_FLAGS_CAPABILITIES,
+     CapabilityShader,
+     {SPV_OPERAND_TYPE_NONE}},
+    {"FragColor",
+     BuiltInFragColor,
+     SPV_OPCODE_FLAGS_CAPABILITIES,
+     CapabilityShader,
+     {SPV_OPERAND_TYPE_NONE}},
+    {"FragDepth",
+     BuiltInFragDepth,
+     SPV_OPCODE_FLAGS_CAPABILITIES,
+     CapabilityShader,
+     {SPV_OPERAND_TYPE_NONE}},
+    {"HelperInvocation",
+     BuiltInHelperInvocation,
+     SPV_OPCODE_FLAGS_CAPABILITIES,
+     CapabilityShader,
+     {SPV_OPERAND_TYPE_NONE}},
+    {"NumWorkgroups",
+     BuiltInNumWorkgroups,
+     SPV_OPCODE_FLAGS_NONE,
+     0,
+     {SPV_OPERAND_TYPE_NONE}},
+    {"WorkgroupSize",
+     BuiltInWorkgroupSize,
+     SPV_OPCODE_FLAGS_NONE,
+     0,
+     {SPV_OPERAND_TYPE_NONE}},
+    {"WorkgroupId",
+     BuiltInWorkgroupId,
+     SPV_OPCODE_FLAGS_NONE,
+     0,
+     {SPV_OPERAND_TYPE_NONE}},
+    {"LocalInvocationId",
+     BuiltInLocalInvocationId,
+     SPV_OPCODE_FLAGS_NONE,
+     0,
+     {SPV_OPERAND_TYPE_NONE}},
+    {"GlobalInvocationId",
+     BuiltInGlobalInvocationId,
+     SPV_OPCODE_FLAGS_NONE,
+     0,
+     {SPV_OPERAND_TYPE_NONE}},
+    {"LocalInvocationIndex",
+     BuiltInLocalInvocationId,
+     SPV_OPCODE_FLAGS_CAPABILITIES,
+     CapabilityShader,
+     {SPV_OPERAND_TYPE_NONE}},
+    {"WorkDim",
+     BuiltInWorkDim,
+     SPV_OPCODE_FLAGS_CAPABILITIES,
+     CapabilityKernel,
+     {SPV_OPERAND_TYPE_NONE}},
+    {"GlobalSize",
+     BuiltInGlobalSize,
+     SPV_OPCODE_FLAGS_CAPABILITIES,
+     CapabilityKernel,
+     {SPV_OPERAND_TYPE_NONE}},
+    {"EnqueuedWorkgroupSize",
+     BuiltInEnqueuedWorkgroupSize,
+     SPV_OPCODE_FLAGS_CAPABILITIES,
+     CapabilityKernel,
+     {SPV_OPERAND_TYPE_NONE}},
+    {"GlobalOffset",
+     BuiltInGlobalOffset,
+     SPV_OPCODE_FLAGS_CAPABILITIES,
+     CapabilityKernel,
+     {SPV_OPERAND_TYPE_NONE}},
+    {"GlobalLinearId",
+     BuiltInGlobalLinearId,
+     SPV_OPCODE_FLAGS_CAPABILITIES,
+     CapabilityKernel,
+     {SPV_OPERAND_TYPE_NONE}},
+    {"WorkgroupLinearId",
+     BuiltInWorkgroupLinearId,
+     SPV_OPCODE_FLAGS_CAPABILITIES,
+     CapabilityKernel,
+     {SPV_OPERAND_TYPE_NONE}},
+    {"SubgroupSize",
+     BuiltInSubgroupSize,
+     SPV_OPCODE_FLAGS_CAPABILITIES,
+     CapabilityKernel,
+     {SPV_OPERAND_TYPE_NONE}},
+    {"SubgroupMaxSize",
+     BuiltInSubgroupMaxSize,
+     SPV_OPCODE_FLAGS_CAPABILITIES,
+     CapabilityKernel,
+     {SPV_OPERAND_TYPE_NONE}},
+    {"NumSubgroups",
+     BuiltInNumSubgroups,
+     SPV_OPCODE_FLAGS_CAPABILITIES,
+     CapabilityKernel,
+     {SPV_OPERAND_TYPE_NONE}},
+    {"NumEnqueuedSubgroups",
+     BuiltInNumEnqueuedSubgroups,
+     SPV_OPCODE_FLAGS_CAPABILITIES,
+     CapabilityKernel,
+     {SPV_OPERAND_TYPE_NONE}},
+    {"SubgroupId",
+     BuiltInSampleId,
+     SPV_OPCODE_FLAGS_CAPABILITIES,
+     CapabilityKernel,
+     {SPV_OPERAND_TYPE_NONE}},
+    {"SubgroupLocalInvocationId",
+     BuiltInSubgroupLocalInvocationId,
+     SPV_OPCODE_FLAGS_CAPABILITIES,
+     CapabilityKernel,
+     {SPV_OPERAND_TYPE_NONE}},
+};
+
+static const spv_operand_desc_t selectionControlEntries[] = {
+    {"None",
+     SelectionControlMaskNone,
+     SPV_OPCODE_FLAGS_NONE,
+     0,
+     {SPV_OPERAND_TYPE_NONE}},
+    {"Flatten",
+     SelectionControlFlattenMask,
+     SPV_OPCODE_FLAGS_NONE,
+     0,
+     {SPV_OPERAND_TYPE_NONE}},
+    {"DontFlatten",
+     SelectionControlDontFlattenMask,
+     SPV_OPCODE_FLAGS_NONE,
+     0,
+     {SPV_OPERAND_TYPE_NONE}},
+};
+
+static const spv_operand_desc_t loopControlEntries[] = {
+    {"None",
+     LoopControlMaskNone,
+     SPV_OPCODE_FLAGS_NONE,
+     0,
+     {SPV_OPERAND_TYPE_NONE}},
+    {"Unroll",
+     LoopControlUnrollMask,
+     SPV_OPCODE_FLAGS_NONE,
+     0,
+     {SPV_OPERAND_TYPE_NONE}},
+    {"DontUnroll",
+     LoopControlDontUnrollMask,
+     SPV_OPCODE_FLAGS_NONE,
+     0,
+     {SPV_OPERAND_TYPE_NONE}},
+};
+
+static const spv_operand_desc_t functionControlEntries[] = {
+    {"None",
+     FunctionControlMaskNone,
+     SPV_OPCODE_FLAGS_NONE,
+     0,
+     {SPV_OPERAND_TYPE_NONE}},
+    {"InLine",
+     FunctionControlInlineMask,
+     SPV_OPCODE_FLAGS_NONE,
+     0,
+     {SPV_OPERAND_TYPE_NONE}},
+    {"DontInline",
+     FunctionControlDontInlineMask,
+     SPV_OPCODE_FLAGS_NONE,
+     0,
+     {SPV_OPERAND_TYPE_NONE}},
+    {"Pure",
+     FunctionControlPureMask,
+     SPV_OPCODE_FLAGS_NONE,
+     0,
+     {SPV_OPERAND_TYPE_NONE}},
+    {"Const",
+     FunctionControlConstMask,
+     SPV_OPCODE_FLAGS_NONE,
+     0,
+     {SPV_OPERAND_TYPE_NONE}},
+};
+
+static const spv_operand_desc_t memorySemanticsEntries[] = {
+    {"None",
+     MemorySemanticsMaskNone,
+     SPV_OPCODE_FLAGS_NONE,
+     0,
+     {SPV_OPERAND_TYPE_NONE}},
+    {"Relaxed",
+     MemorySemanticsRelaxedMask,
+     SPV_OPCODE_FLAGS_NONE,
+     0,
+     {SPV_OPERAND_TYPE_NONE}},
+    {"SequentiallyConsistent",
+     MemorySemanticsSequentiallyConsistentMask,
+     SPV_OPCODE_FLAGS_NONE,
+     0,
+     {SPV_OPERAND_TYPE_NONE}},
+    {"Acquire",
+     MemorySemanticsAcquireMask,
+     SPV_OPCODE_FLAGS_NONE,
+     0,
+     {SPV_OPERAND_TYPE_NONE}},
+    {"Release",
+     MemorySemanticsReleaseMask,
+     SPV_OPCODE_FLAGS_NONE,
+     0,
+     {SPV_OPERAND_TYPE_NONE}},
+    {"UniformMemory",
+     MemorySemanticsUniformMemoryMask,
+     SPV_OPCODE_FLAGS_CAPABILITIES,
+     CapabilityShader,
+     {SPV_OPERAND_TYPE_NONE}},
+    {"SubgroupMemory",
+     MemorySemanticsSubgroupMemoryMask,
+     SPV_OPCODE_FLAGS_NONE,
+     0,
+     {SPV_OPERAND_TYPE_NONE}},
+    {"WorkgroupLocalMemory",
+     MemorySemanticsWorkgroupLocalMemoryMask,
+     SPV_OPCODE_FLAGS_NONE,
+     0,
+     {SPV_OPERAND_TYPE_NONE}},
+    {"WorkgroupGlobalMemory",
+     MemorySemanticsWorkgroupGlobalMemoryMask,
+     SPV_OPCODE_FLAGS_NONE,
+     0,
+     {SPV_OPERAND_TYPE_NONE}},
+    {"AtomicCounterMemory",
+     MemorySemanticsAtomicCounterMemoryMask,
+     SPV_OPCODE_FLAGS_CAPABILITIES,
+     CapabilityShader,
+     {SPV_OPERAND_TYPE_NONE}},
+    {
+     "ImageMemory",
+     MemorySemanticsImageMemoryMask,
+     SPV_OPCODE_FLAGS_NONE,
+     0,
+     {SPV_OPERAND_TYPE_NONE},
+    },
+};
+
+static const spv_operand_desc_t memoryAccessEntries[] = {
+    {"None",
+     MemoryAccessMaskNone,
+     SPV_OPCODE_FLAGS_NONE,
+     0,
+     {SPV_OPERAND_TYPE_NONE}},
+    {"Volatile",
+     MemoryAccessVolatileMask,
+     SPV_OPCODE_FLAGS_NONE,
+     0,
+     {SPV_OPERAND_TYPE_NONE}},
+    {
+     "Aligned",
+     MemoryAccessAlignedMask,
+     SPV_OPCODE_FLAGS_NONE,
+     0,
+     {SPV_OPERAND_TYPE_NONE},
+    },
+};
+
+static const spv_operand_desc_t scopeEntries[] = {
+    {"CrossDevice",
+     ScopeCrossDevice,
+     SPV_OPCODE_FLAGS_NONE,
+     0,
+     {SPV_OPERAND_TYPE_NONE}},
+    {"Device", ScopeDevice, SPV_OPCODE_FLAGS_NONE, 0, {SPV_OPERAND_TYPE_NONE}},
+    {"Workgroup",
+     ScopeWorkgroup,
+     SPV_OPCODE_FLAGS_NONE,
+     0,
+     {SPV_OPERAND_TYPE_NONE}},
+    {"Subgroup",
+     ScopeSubgroup,
+     SPV_OPCODE_FLAGS_NONE,
+     0,
+     {SPV_OPERAND_TYPE_NONE}},
+    {
+     "Invocation",
+     ScopeInvocation,
+     SPV_OPCODE_FLAGS_NONE,
+     0,
+     {SPV_OPERAND_TYPE_NONE},
+    },
+};
+
+static const spv_operand_desc_t groupOperationEntries[] = {
+    {"Reduce",
+     GroupOperationReduce,
+     SPV_OPCODE_FLAGS_CAPABILITIES,
+     CapabilityKernel,
+     {SPV_OPERAND_TYPE_NONE}},
+    {"InclusiveScan",
+     GroupOperationInclusiveScan,
+     SPV_OPCODE_FLAGS_CAPABILITIES,
+     CapabilityKernel,
+     {SPV_OPERAND_TYPE_NONE}},
+    {"ExclusiveScan",
+     GroupOperationExclusiveScan,
+     SPV_OPCODE_FLAGS_CAPABILITIES,
+     CapabilityKernel,
+     {SPV_OPERAND_TYPE_NONE}},
+};
+
+static const spv_operand_desc_t kernelKernelEnqueueFlagssEntries[] = {
+    {"NoWait",
+     KernelEnqueueFlagsNoWait,
+     SPV_OPCODE_FLAGS_CAPABILITIES,
+     CapabilityKernel,
+     {SPV_OPERAND_TYPE_NONE}},
+    {"WaitKernel",
+     KernelEnqueueFlagsWaitKernel,
+     SPV_OPCODE_FLAGS_CAPABILITIES,
+     CapabilityKernel,
+     {SPV_OPERAND_TYPE_NONE}},
+    {"WaitWorkGroup",
+     KernelEnqueueFlagsWaitWorkGroup,
+     SPV_OPCODE_FLAGS_CAPABILITIES,
+     CapabilityKernel,
+     {SPV_OPERAND_TYPE_NONE}},
+};
+
+static const spv_operand_desc_t kernelProfilingInfoEntries[] = {
+    {"None",
+     KernelProfilingInfoMaskNone,
+     SPV_OPCODE_FLAGS_NONE,
+     0,
+     {SPV_OPERAND_TYPE_NONE}},
+    {"CmdExecTime",
+     KernelProfilingInfoCmdExecTimeMask,
+     SPV_OPCODE_FLAGS_CAPABILITIES,
+     CapabilityKernel,
+     {SPV_OPERAND_TYPE_NONE}},
+};
+
+static const spv_operand_desc_t capabilityInfoEntries[] = {
+    {"Matrix",
+     CapabilityMatrix,
+     SPV_OPCODE_FLAGS_NONE,
+     0,
+     {SPV_OPERAND_TYPE_NONE}},
+    {"Shader",
+     CapabilityShader,
+     SPV_OPCODE_FLAGS_CAPABILITIES,
+     CapabilityMatrix,
+     {SPV_OPERAND_TYPE_NONE}},
+    {"Geometry",
+     CapabilityGeometry,
+     SPV_OPCODE_FLAGS_CAPABILITIES,
+     CapabilityShader,
+     {SPV_OPERAND_TYPE_NONE}},
+    {"Tessellation",
+     CapabilityTessellation,
+     SPV_OPCODE_FLAGS_CAPABILITIES,
+     CapabilityShader,
+     {SPV_OPERAND_TYPE_NONE}},
+    {"Addresses",
+     CapabilityAddresses,
+     SPV_OPCODE_FLAGS_NONE,
+     0,
+     {SPV_OPERAND_TYPE_NONE}},
+    {"Linkage",
+     CapabilityLinkage,
+     SPV_OPCODE_FLAGS_NONE,
+     0,
+     {SPV_OPERAND_TYPE_NONE}},
+    {"Kernel",
+     CapabilityKernel,
+     SPV_OPCODE_FLAGS_NONE,
+     0,
+     {SPV_OPERAND_TYPE_NONE}},
+    {"Vector16",
+     CapabilityVector16,
+     SPV_OPCODE_FLAGS_NONE,
+     0,
+     {SPV_OPERAND_TYPE_NONE}},
+    {"Float16Buffer",
+     CapabilityFloat16Buffer,
+     SPV_OPCODE_FLAGS_NONE,
+     0,
+     {SPV_OPERAND_TYPE_NONE}},
+    {"Float16",
+     CapabilityFloat16,
+     SPV_OPCODE_FLAGS_NONE,
+     0,
+     {SPV_OPERAND_TYPE_NONE}},
+    {"Float64",
+     CapabilityFloat64,
+     SPV_OPCODE_FLAGS_NONE,
+     0,
+     {SPV_OPERAND_TYPE_NONE}},
+    {"Int64",
+     CapabilityInt64,
+     SPV_OPCODE_FLAGS_NONE,
+     0,
+     {SPV_OPERAND_TYPE_NONE}},
+    {"Int64Atomics",
+     CapabilityInt64Atomics,
+     SPV_OPCODE_FLAGS_NONE,
+     0,
+     {SPV_OPERAND_TYPE_NONE}},
+    {"ImageBasic",
+     CapabilityImageBasic,
+     SPV_OPCODE_FLAGS_NONE,
+     0,
+     {SPV_OPERAND_TYPE_NONE}},
+    {"ImageReadWrite",
+     CapabilityImageReadWrite,
+     SPV_OPCODE_FLAGS_NONE,
+     0,
+     {SPV_OPERAND_TYPE_NONE}},
+    {"ImageSRGBWrite",
+     CapabilityImageSRGBWrite,
+     SPV_OPCODE_FLAGS_NONE,
+     0,
+     {SPV_OPERAND_TYPE_NONE}},
+    {"Pipes",
+     CapabilityPipes,
+     SPV_OPCODE_FLAGS_NONE,
+     0,
+     {SPV_OPERAND_TYPE_NONE}},
+    {"Groups",
+     CapabilityGroups,
+     SPV_OPCODE_FLAGS_NONE,
+     0,
+     {SPV_OPERAND_TYPE_NONE}},
+    {"DeviceEnqueue",
+     CapabilityDeviceEnqueue,
+     SPV_OPCODE_FLAGS_NONE,
+     0,
+     {SPV_OPERAND_TYPE_NONE}},
+};
+
+static const spv_operand_desc_group_t opcodeEntryTypes[] = {
+    {SPV_OPERAND_TYPE_SOURCE_LANGUAGE,
+     sizeof(sourceLanguageEntries) / sizeof(spv_operand_desc_t),
+     sourceLanguageEntries},
+    {SPV_OPERAND_TYPE_EXECUTION_MODEL,
+     sizeof(executionModelEntries) / sizeof(spv_operand_desc_t),
+     executionModelEntries},
+    {SPV_OPERAND_TYPE_ADDRESSING_MODEL,
+     sizeof(addressingModelEntries) / sizeof(spv_operand_desc_t),
+     addressingModelEntries},
+    {SPV_OPERAND_TYPE_MEMORY_MODEL,
+     sizeof(memoryModelEntries) / sizeof(spv_operand_desc_t),
+     memoryModelEntries},
+    {SPV_OPERAND_TYPE_EXECUTION_MODE,
+     sizeof(executionModeEntries) / sizeof(spv_operand_desc_t),
+     executionModeEntries},
+    {SPV_OPERAND_TYPE_STORAGE_CLASS,
+     sizeof(storageClassEntries) / sizeof(spv_operand_desc_t),
+     storageClassEntries},
+    {SPV_OPERAND_TYPE_DIMENSIONALITY,
+     sizeof(dimensionalityEntries) / sizeof(spv_operand_desc_t),
+     dimensionalityEntries},
+    {SPV_OPERAND_TYPE_SAMPLER_ADDRESSING_MODE,
+     sizeof(samplerAddressingModeEntries) / sizeof(spv_operand_desc_t),
+     samplerAddressingModeEntries},
+    {SPV_OPERAND_TYPE_SAMPLER_FILTER_MODE,
+     sizeof(samplerFilterModeEntries) / sizeof(spv_operand_desc_t),
+     samplerFilterModeEntries},
+    {SPV_OPERAND_TYPE_FP_FAST_MATH_MODE,
+     sizeof(fpFastMathModeEntries) / sizeof(spv_operand_desc_t),
+     fpFastMathModeEntries},
+    {SPV_OPERAND_TYPE_FP_ROUNDING_MODE,
+     sizeof(fpRoundingModeEntries) / sizeof(spv_operand_desc_t),
+     fpRoundingModeEntries},
+    {SPV_OPERAND_TYPE_LINKAGE_TYPE,
+     sizeof(linkageTypeEntries) / sizeof(spv_operand_desc_t),
+     linkageTypeEntries},
+    {SPV_OPERAND_TYPE_ACCESS_QUALIFIER,
+     sizeof(accessQualifierEntries) / sizeof(spv_operand_desc_t),
+     accessQualifierEntries},
+    {SPV_OPERAND_TYPE_FUNCTION_PARAMETER_ATTRIBUTE,
+     sizeof(functionParameterAttributeEntries) / sizeof(spv_operand_desc_t),
+     functionParameterAttributeEntries},
+    {SPV_OPERAND_TYPE_DECORATION,
+     sizeof(decorationEntries) / sizeof(spv_operand_desc_t), decorationEntries},
+    {SPV_OPERAND_TYPE_BUILT_IN,
+     sizeof(builtInEntries) / sizeof(spv_operand_desc_t), builtInEntries},
+    {SPV_OPERAND_TYPE_SELECTION_CONTROL,
+     sizeof(selectionControlEntries) / sizeof(spv_operand_desc_t),
+     selectionControlEntries},
+    {SPV_OPERAND_TYPE_LOOP_CONTROL,
+     sizeof(loopControlEntries) / sizeof(spv_operand_desc_t),
+     loopControlEntries},
+    {SPV_OPERAND_TYPE_FUNCTION_CONTROL,
+     sizeof(functionControlEntries) / sizeof(spv_operand_desc_t),
+     functionControlEntries},
+    {SPV_OPERAND_TYPE_MEMORY_SEMANTICS,
+     sizeof(memorySemanticsEntries) / sizeof(spv_operand_desc_t),
+     memorySemanticsEntries},
+    {SPV_OPERAND_TYPE_MEMORY_ACCESS,
+     sizeof(memoryAccessEntries) / sizeof(spv_operand_desc_t),
+     memoryAccessEntries},
+    {SPV_OPERAND_TYPE_EXECUTION_SCOPE,
+     sizeof(scopeEntries) / sizeof(spv_operand_desc_t), scopeEntries},
+    {SPV_OPERAND_TYPE_GROUP_OPERATION,
+     sizeof(groupOperationEntries) / sizeof(spv_operand_desc_t),
+     groupOperationEntries},
+    {SPV_OPERAND_TYPE_KERNEL_ENQ_FLAGS,
+     sizeof(kernelKernelEnqueueFlagssEntries) / sizeof(spv_operand_desc_t),
+     kernelKernelEnqueueFlagssEntries},
+    {SPV_OPERAND_TYPE_KERENL_PROFILING_INFO,
+     sizeof(kernelProfilingInfoEntries) / sizeof(spv_operand_desc_t),
+     kernelProfilingInfoEntries},
+    {SPV_OPERAND_TYPE_CAPABILITY,
+     sizeof(capabilityInfoEntries) / sizeof(spv_operand_desc_t),
+     capabilityInfoEntries},
+};
+
+spv_result_t spvOperandTableGet(spv_operand_table *pOperandTable) {
+  spvCheck(!pOperandTable, return SPV_ERROR_INVALID_POINTER);
+
+  static const spv_operand_table_t table = {
+      sizeof(opcodeEntryTypes) / sizeof(spv_operand_desc_group_t),
+      opcodeEntryTypes};
+
+  *pOperandTable = &table;
+
+  return SPV_SUCCESS;
+}
+
+spv_result_t spvOperandTableNameLookup(const spv_operand_table table,
+                                       const spv_operand_type_t type,
+                                       const char *name,
+                                       spv_operand_desc *pEntry) {
+  spvCheck(!table, return SPV_ERROR_INVALID_TABLE);
+  spvCheck(!name || !pEntry, return SPV_ERROR_INVALID_POINTER);
+
+  const uint64_t nameLength = strlen(name);
+  for (uint64_t typeIndex = 0; typeIndex < table->count; ++typeIndex) {
+    if (type == table->types[typeIndex].type) {
+      for (uint64_t operandIndex = 0;
+           operandIndex < table->types[typeIndex].count; ++operandIndex) {
+        if (nameLength ==
+                strlen(table->types[typeIndex].entries[operandIndex].name) &&
+            !strncmp(table->types[typeIndex].entries[operandIndex].name, name,
+                     strlen(name))) {
+          *pEntry = &table->types[typeIndex].entries[operandIndex];
+          return SPV_SUCCESS;
+        }
+      }
+    }
+  }
+
+  return SPV_ERROR_INVALID_LOOKUP;
+}
+
+spv_result_t spvOperandTableValueLookup(const spv_operand_table table,
+                                        const spv_operand_type_t type,
+                                        const uint32_t value,
+                                        spv_operand_desc *pEntry) {
+  spvCheck(!table, return SPV_ERROR_INVALID_TABLE);
+  spvCheck(!pEntry, return SPV_ERROR_INVALID_POINTER);
+
+  for (uint64_t typeIndex = 0; typeIndex < table->count; ++typeIndex) {
+    if (type == table->types[typeIndex].type) {
+      for (uint64_t operandIndex = 0;
+           operandIndex < table->types[typeIndex].count; ++operandIndex) {
+        if (value == table->types[typeIndex].entries[operandIndex].value) {
+          *pEntry = &table->types[typeIndex].entries[operandIndex];
+          return SPV_SUCCESS;
+        }
+      }
+    }
+  }
+
+  return SPV_ERROR_INVALID_LOOKUP;
+}
+
+const char *spvOperandTypeStr(spv_operand_type_t type) {
+  switch (type) {
+    case SPV_OPERAND_TYPE_ID:
+      return "id";
+    case SPV_OPERAND_TYPE_RESULT_ID:
+      return "result ID";
+    case SPV_OPERAND_TYPE_LITERAL:
+      return "literal";
+    case SPV_OPERAND_TYPE_LITERAL_NUMBER:
+      return "literal number";
+    case SPV_OPERAND_TYPE_LITERAL_STRING:
+      return "literal string";
+    case SPV_OPERAND_TYPE_SOURCE_LANGUAGE:
+      return "source langauge";
+    case SPV_OPERAND_TYPE_EXECUTION_MODEL:
+      return "execution model";
+    case SPV_OPERAND_TYPE_ADDRESSING_MODEL:
+      return "addressing model";
+    case SPV_OPERAND_TYPE_MEMORY_MODEL:
+      return "memory model";
+    case SPV_OPERAND_TYPE_EXECUTION_MODE:
+      return "execution mode";
+    case SPV_OPERAND_TYPE_STORAGE_CLASS:
+      return "storage class";
+    case SPV_OPERAND_TYPE_DIMENSIONALITY:
+      return "dimensionality";
+    case SPV_OPERAND_TYPE_SAMPLER_ADDRESSING_MODE:
+      return "addressing mode";
+    case SPV_OPERAND_TYPE_SAMPLER_FILTER_MODE:
+      return "sampler filter mode";
+    case SPV_OPERAND_TYPE_FP_FAST_MATH_MODE:
+      return "floating pointer fast math mode";
+    case SPV_OPERAND_TYPE_FP_ROUNDING_MODE:
+      return "floating point rounding mode";
+    case SPV_OPERAND_TYPE_LINKAGE_TYPE:
+      return "linkage type";
+    case SPV_OPERAND_TYPE_ACCESS_QUALIFIER:
+      return "access qualifier";
+    case SPV_OPERAND_TYPE_FUNCTION_PARAMETER_ATTRIBUTE:
+      return "function parameter attribute";
+    case SPV_OPERAND_TYPE_DECORATION:
+      return "decoration";
+    case SPV_OPERAND_TYPE_BUILT_IN:
+      return "built in";
+    case SPV_OPERAND_TYPE_SELECTION_CONTROL:
+      return "selection control";
+    case SPV_OPERAND_TYPE_LOOP_CONTROL:
+      return "loop control";
+    case SPV_OPERAND_TYPE_FUNCTION_CONTROL:
+      return "function control";
+    case SPV_OPERAND_TYPE_MEMORY_SEMANTICS:
+      return "memory semantics";
+    case SPV_OPERAND_TYPE_MEMORY_ACCESS:
+      return "memory access";
+    case SPV_OPERAND_TYPE_EXECUTION_SCOPE:
+      return "execution scope";
+    case SPV_OPERAND_TYPE_GROUP_OPERATION:
+      return "group operation";
+    case SPV_OPERAND_TYPE_KERNEL_ENQ_FLAGS:
+      return "kernel enqeue flags";
+    case SPV_OPERAND_TYPE_KERENL_PROFILING_INFO:
+      return "kernel profiling info";
+    case SPV_OPERAND_TYPE_CAPABILITY:
+      return "capability";
+    default:
+      assert(0 && "Unhandled operand type!");
+      break;
+  }
+  return "unknown";
+}
diff --git a/source/operand.h b/source/operand.h
new file mode 100644 (file)
index 0000000..3482a4d
--- /dev/null
@@ -0,0 +1,65 @@
+// Copyright (c) 2015 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.
+
+#ifndef _CODEPLAY_SPIRV_OPERAND_H_
+#define _CODEPLAY_SPIRV_OPERAND_H_
+
+#include <libspirv/libspirv.h>
+
+/// @brief Find the named operand in the table
+///
+/// @param[in] table to lookup
+/// @param[in] type the operand group's type
+/// @param[in] name of the operand to find
+/// @param[out] pEntry returned operand table entry
+///
+/// @return result code
+spv_result_t spvOperandTableNameLookup(const spv_operand_table table,
+                                       const spv_operand_type_t type,
+                                       const char *name,
+                                       spv_operand_desc *pEntry);
+
+/// @brief Find the operand with value in the table
+///
+/// @param[in] table to lookup
+/// @param[in] type the operand group's type
+/// @param[in] value of the operand to find
+/// @param[out] pEntry return operand table entry
+///
+/// @return result code
+spv_result_t spvOperandTableValueLookup(const spv_operand_table table,
+                                        const spv_operand_type_t type,
+                                        const uint32_t value,
+                                        spv_operand_desc *pEntry);
+
+/// @brief Get the name string of the operand type
+///
+/// @param type the type of the operand
+///
+/// @return the string name of the operand
+const char *spvOperandTypeStr(spv_operand_type_t type);
+
+#endif
diff --git a/source/print.cpp b/source/print.cpp
new file mode 100644 (file)
index 0000000..6ee3b01
--- /dev/null
@@ -0,0 +1,103 @@
+// Copyright (c) 2015 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.
+
+#include "print.h"
+
+#if defined(SPIRV_LINUX) || defined(SPIRV_MAC)
+clr::reset::operator const char *() { return "\e[0m"; }
+
+clr::grey::operator const char *() { return "\e[1;30m"; }
+
+clr::red::operator const char *() { return "\e[31m"; }
+
+clr::green::operator const char *() { return "\e[32m"; }
+
+clr::yellow::operator const char *() { return "\e[33m"; }
+
+clr::blue::operator const char *() { return "\e[34m"; }
+#elif defined(SPIRV_WINDOWS)
+#include <Windows.h>
+
+clr::reset::operator const char *() {
+  const DWORD color = 0Xf;
+  HANDLE hConsole;
+  hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
+  SetConsoleTextAttribute(hConsole, color);
+  hConsole = GetStdHandle(STD_ERROR_HANDLE);
+  SetConsoleTextAttribute(hConsole, color);
+  return "";
+}
+
+clr::grey::operator const char *() {
+  const DWORD color = 0x8;
+  HANDLE hConsole;
+  hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
+  SetConsoleTextAttribute(hConsole, color);
+  hConsole = GetStdHandle(STD_ERROR_HANDLE);
+  SetConsoleTextAttribute(hConsole, color);
+  return "";
+}
+
+clr::red::operator const char *() {
+  const DWORD color = 0x4;
+  HANDLE hConsole;
+  hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
+  SetConsoleTextAttribute(hConsole, color);
+  hConsole = GetStdHandle(STD_ERROR_HANDLE);
+  SetConsoleTextAttribute(hConsole, color);
+  return "";
+}
+
+clr::green::operator const char *() {
+  const DWORD color = 0x2;
+  HANDLE hConsole;
+  hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
+  SetConsoleTextAttribute(hConsole, color);
+  hConsole = GetStdHandle(STD_ERROR_HANDLE);
+  SetConsoleTextAttribute(hConsole, color);
+  return "";
+}
+
+clr::yellow::operator const char *() {
+  const DWORD color = 0x6;
+  HANDLE hConsole;
+  hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
+  SetConsoleTextAttribute(hConsole, color);
+  hConsole = GetStdHandle(STD_ERROR_HANDLE);
+  SetConsoleTextAttribute(hConsole, color);
+  return "";
+}
+
+clr::blue::operator const char *() {
+  const DWORD color = 0x1;
+  HANDLE hConsole;
+  hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
+  SetConsoleTextAttribute(hConsole, color);
+  hConsole = GetStdHandle(STD_ERROR_HANDLE);
+  SetConsoleTextAttribute(hConsole, color);
+  return "";
+}
+#endif
diff --git a/source/print.h b/source/print.h
new file mode 100644 (file)
index 0000000..6e20da5
--- /dev/null
@@ -0,0 +1,77 @@
+// Copyright (c) 2015 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.
+
+#ifndef _LIBSPIRV_PRINT_H_
+#define _LIBSPIRV_PRINT_H_
+
+#include <iostream>
+#include <sstream>
+
+/// @brief Wrapper for out stream selection
+class out_stream {
+ public:
+  out_stream() : pStream(nullptr) {}
+  out_stream(std::stringstream &stream) : pStream(&stream) {}
+
+  std::ostream &get() {
+    if (pStream) {
+      return *pStream;
+    }
+    return std::cout;
+  }
+
+ private:
+  std::stringstream *pStream;
+};
+
+namespace clr {
+/// @brief Reset console color
+struct reset {
+  operator const char *();
+};
+/// @brief Set console color to grey
+struct grey {
+  operator const char *();
+};
+/// @brief Set console color to red
+struct red {
+  operator const char *();
+};
+/// @brief Set console color to green
+struct green {
+  operator const char *();
+};
+/// @brief Set console color to yellow
+struct yellow {
+  operator const char *();
+};
+/// @brief Set console color to blue
+struct blue {
+  operator const char *();
+};
+}
+
+#endif
diff --git a/source/text.cpp b/source/text.cpp
new file mode 100644 (file)
index 0000000..e2c1d89
--- /dev/null
@@ -0,0 +1,667 @@
+// Copyright (c) 2015 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.
+
+#include <libspirv/libspirv.h>
+#include "binary.h"
+#include "diagnostic.h"
+#include "ext_inst.h"
+#include "opcode.h"
+#include "operand.h"
+#include "text.h"
+
+#include <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <string>
+#include <vector>
+#include <unordered_map>
+
+// Structures
+
+struct spv_named_id_table_t {
+  std::unordered_map<std::string, uint32_t> namedIds;
+};
+
+// Text API
+
+std::string getWord(const char *str) {
+  size_t index = 0;
+  while (true) {
+    switch (str[index]) {
+      case '\0':
+      case '\t':
+      case '\n':
+      case ' ':
+        break;
+      default:
+        index++;
+    }
+  }
+  return std::string(str, str + index);
+}
+
+spv_named_id_table spvNamedIdTableCreate() {
+  return new spv_named_id_table_t();
+}
+
+void spvNamedIdTableDestory(spv_named_id_table table) { delete table; }
+
+uint32_t spvNamedIdAssignOrGet(spv_named_id_table table, const char *textValue,
+                               uint32_t *pBound) {
+  if (table->namedIds.end() == table->namedIds.find(textValue)) {
+    table->namedIds[textValue] = *pBound;
+  }
+  return table->namedIds[textValue];
+}
+
+int32_t spvTextIsNamedId(const char *textValue) {
+  // TODO: Strengthen the parsing of textValue to only include allow names that
+  // match: ([a-z]|[A-Z])(_|[a-z]|[A-Z]|[0-9])*
+  switch (textValue[0]) {
+    case '0':
+    case '1':
+    case '2':
+    case '3':
+    case '4':
+    case '5':
+    case '6':
+    case '7':
+    case '8':
+    case '9':
+      return false;
+    default:
+      break;
+  }
+  return true;
+}
+
+spv_result_t spvTextAdvanceLine(const spv_text text, spv_position position) {
+  while (true) {
+    switch (text->str[position->index]) {
+      case '\0':
+        return SPV_END_OF_STREAM;
+      case '\n':
+        position->column = 0;
+        position->line++;
+        position->index++;
+        return SPV_SUCCESS;
+      default:
+        position->line++;
+        position->index++;
+        break;
+    }
+  }
+}
+
+spv_result_t spvTextAdvance(const spv_text text, spv_position position) {
+  // NOTE: Consume white space, otherwise don't advance.
+  switch (text->str[position->index]) {
+    case '\0':
+      return SPV_END_OF_STREAM;
+    case ';':
+      return spvTextAdvanceLine(text, position);
+    case ' ':
+    case '\t':
+      position->column++;
+      position->index++;
+      return spvTextAdvance(text, position);
+    case '\n':
+      position->column = 0;
+      position->line++;
+      position->index++;
+      return spvTextAdvance(text, position);
+    default:
+      break;
+  }
+
+  return SPV_SUCCESS;
+}
+
+spv_result_t spvTextWordGet(const spv_text text,
+                            const spv_position startPosition, std::string &word,
+                            spv_position endPosition) {
+  spvCheck(!text->str || !text->length, return SPV_ERROR_INVALID_TEXT);
+  spvCheck(!startPosition || !endPosition, return SPV_ERROR_INVALID_POINTER);
+
+  *endPosition = *startPosition;
+
+  // NOTE: Assumes first character is not white space!
+  while (true) {
+    switch (text->str[endPosition->index]) {
+      case ' ':
+      case '\t':
+      case '\n':
+      case '\0': {  // NOTE: End of word found!
+        word.assign(text->str + startPosition->index,
+                    (size_t)(endPosition->index - startPosition->index));
+        return SPV_SUCCESS;
+      }
+      default:
+        break;
+    }
+
+    endPosition->column++;
+    endPosition->index++;
+  }
+}
+
+spv_result_t spvTextStringGet(const spv_text text,
+                              const spv_position startPosition,
+                              std::string &string, spv_position endPosition) {
+  spvCheck(!text->str || !text->length, return SPV_ERROR_INVALID_TEXT);
+  spvCheck(!startPosition || !endPosition, return SPV_ERROR_INVALID_POINTER);
+
+  spvCheck('"' != text->str[startPosition->index],
+           return SPV_ERROR_INVALID_TEXT);
+
+  *endPosition = *startPosition;
+
+  // NOTE: Assumes first character is not white space
+  while (true) {
+    endPosition->column++;
+    endPosition->index++;
+
+    switch (text->str[endPosition->index]) {
+      case '"': {
+        endPosition->column++;
+        endPosition->index++;
+
+        string.assign(text->str + startPosition->index,
+                      (size_t)(endPosition->index - startPosition->index));
+
+        return SPV_SUCCESS;
+      }
+      case '\n':
+      case '\0':
+        return SPV_ERROR_INVALID_TEXT;
+      default:
+        break;
+    }
+  }
+}
+
+spv_result_t spvTextToUInt32(const char *textValue, uint32_t *pValue) {
+  char *endPtr = nullptr;
+  *pValue = strtoul(textValue, &endPtr, 0);
+  if (0 == *pValue && textValue == endPtr) {
+    return SPV_ERROR_INVALID_TEXT;
+  }
+  return SPV_SUCCESS;
+}
+
+spv_result_t spvTextToLiteral(const char *textValue, spv_literal_t *pLiteral) {
+  bool isSigned = false;
+  bool isFloat = false;
+  bool isString = false;
+
+  if ('-' == textValue[0]) {
+    isSigned = true;
+  }
+
+  for (uint64_t index = 0; index < strlen(textValue); ++index) {
+    switch (textValue[index]) {
+      case '0':
+      case '1':
+      case '2':
+      case '3':
+      case '4':
+      case '5':
+      case '6':
+      case '7':
+      case '8':
+      case '9':
+        break;
+      case '.':
+        isFloat = true;
+        break;
+      default:
+        isString = true;
+        break;
+    }
+  }
+
+  if (isString) {
+    pLiteral->type = SPV_LITERAL_TYPE_STRING;
+    strncpy(pLiteral->value.str, textValue, strlen(textValue));
+  } else if (isFloat) {
+    double d = strtod(textValue, nullptr);
+    float f = (float)d;
+    if (d == (double)f) {
+      pLiteral->type = SPV_LITERAL_TYPE_FLOAT_32;
+      pLiteral->value.f = f;
+    } else {
+      pLiteral->type = SPV_LITERAL_TYPE_FLOAT_64;
+      pLiteral->value.d = d;
+    }
+  } else if (isSigned) {
+    int64_t i64 = strtoll(textValue, nullptr, 10);
+    int32_t i32 = (int32_t)i64;
+    if (i64 == (int64_t)i32) {
+      pLiteral->type = SPV_LITERAL_TYPE_INT_32;
+      pLiteral->value.i32 = i32;
+    } else {
+      pLiteral->type = SPV_LITERAL_TYPE_INT_64;
+      pLiteral->value.i64 = i64;
+    }
+  } else {
+    uint64_t u64 = strtoull(textValue, nullptr, 10);
+    uint32_t u32 = (uint32_t)u64;
+    if (u64 == (uint64_t)u32) {
+      pLiteral->type = SPV_LITERAL_TYPE_UINT_32;
+      pLiteral->value.u32 = u32;
+    } else {
+      pLiteral->type = SPV_LITERAL_TYPE_UINT_64;
+      pLiteral->value.u64 = u64;
+    }
+  }
+
+  return SPV_SUCCESS;
+}
+
+spv_result_t spvTextEncodeOperand(
+    const spv_operand_type_t type, const char *textValue,
+    const spv_operand_table operandTable, const spv_ext_inst_table extInstTable,
+    spv_named_id_table namedIdTable, spv_instruction_t *pInst,
+    const spv_operand_type_t **ppExtraOperands, uint32_t *pBound,
+    const spv_position position, spv_diagnostic *pDiagnostic) {
+  // NOTE: Handle immediate int in the stream
+  if ('!' == textValue[0]) {
+    const char *begin = textValue + 1;
+    char *end = nullptr;
+    uint32_t immediateInt = strtoul(begin, &end, 0);
+    size_t size = strlen(textValue);
+    size_t length = (end - begin);
+    spvCheck(size - 1 != length, DIAGNOSTIC << "Invalid immediate integer '"
+                                            << textValue << "'.";
+             return SPV_ERROR_INVALID_TEXT);
+    position->column += size;
+    position->index += size;
+    pInst->words[pInst->wordCount] = immediateInt;
+    pInst->wordCount += 1;
+    return SPV_SUCCESS;
+  }
+
+  switch (type) {
+    case SPV_OPERAND_TYPE_ID: {
+      if ('$' == textValue[0]) {
+        textValue++;
+      }
+      // TODO: Force all ID's to be prefixed with '$'.
+      uint32_t id = 0;
+      if (spvTextIsNamedId(textValue)) {
+        id = spvNamedIdAssignOrGet(namedIdTable, textValue, pBound);
+      } else {
+        spvCheck(spvTextToUInt32(textValue, &id),
+                 DIAGNOSTIC << "Invalid ID '" << textValue << "'.";
+                 return SPV_ERROR_INVALID_TEXT);
+      }
+      pInst->words[pInst->wordCount++] = id;
+      if (*pBound <= id) {
+        *pBound = id + 1;
+      }
+    } break;
+    case SPV_OPERAND_TYPE_RESULT_ID: {
+      if ('%' == textValue[0]) {
+        textValue++;
+      }
+      // TODO: Force all Result ID's to be prefixed with '%'.
+      uint32_t id = 0;
+      if (spvTextIsNamedId(textValue)) {
+        id = spvNamedIdAssignOrGet(namedIdTable, textValue, pBound);
+      } else {
+        spvCheck(spvTextToUInt32(textValue, &id),
+                 DIAGNOSTIC << "Invalid result ID '" << textValue << "'.";
+                 return SPV_ERROR_INVALID_TEXT);
+      }
+      pInst->words[pInst->wordCount++] = id;
+      if (*pBound <= id) {
+        *pBound = id + 1;
+      }
+    } break;
+    case SPV_OPERAND_TYPE_LITERAL_NUMBER: {
+      // NOTE: Special case for extension instruction lookup
+      if (OpExtInst == pInst->opcode) {
+        spv_ext_inst_desc extInst;
+        spvCheck(spvExtInstTableNameLookup(extInstTable, pInst->extInstType,
+                                           textValue, &extInst),
+                 DIAGNOSTIC << "Invalid extended instruction name '"
+                            << textValue << "'.";
+                 return SPV_ERROR_INVALID_TEXT);
+        pInst->words[pInst->wordCount++] = extInst->ext_inst;
+        *ppExtraOperands = extInst->operandTypes;
+        return SPV_SUCCESS;
+      }
+
+      // TODO: Literal numbers can be any number up to 64 bits wide. This
+      // includes integers and floating point numbers.
+      spvCheck(spvTextToUInt32(textValue, &pInst->words[pInst->wordCount++]),
+               DIAGNOSTIC << "Invalid literal number '" << textValue << "'.";
+               return SPV_ERROR_INVALID_TEXT);
+    } break;
+    case SPV_OPERAND_TYPE_LITERAL: {
+      spv_literal_t literal = {};
+      spvCheck(spvTextToLiteral(textValue, &literal),
+               DIAGNOSTIC << "Invalid literal '" << textValue << "'.";
+               return SPV_ERROR_INVALID_TEXT);
+      switch (literal.type) {
+        case SPV_LITERAL_TYPE_INT_32:
+          spvCheck(spvBinaryEncodeU32((uint32_t)literal.value.i32, pInst,
+                                      position, pDiagnostic),
+                   return SPV_ERROR_INVALID_TEXT);
+          break;
+        case SPV_LITERAL_TYPE_INT_64: {
+          spvCheck(spvBinaryEncodeU64((uint64_t)literal.value.i64, pInst,
+                                      position, pDiagnostic),
+                   return SPV_ERROR_INVALID_TEXT);
+        } break;
+        case SPV_LITERAL_TYPE_UINT_32: {
+          spvCheck(spvBinaryEncodeU32(literal.value.u32, pInst, position,
+                                      pDiagnostic),
+                   return SPV_ERROR_INVALID_TEXT);
+        } break;
+        case SPV_LITERAL_TYPE_UINT_64: {
+          spvCheck(spvBinaryEncodeU64((uint64_t)literal.value.u64, pInst,
+                                      position, pDiagnostic),
+                   return SPV_ERROR_INVALID_TEXT);
+        } break;
+        case SPV_LITERAL_TYPE_FLOAT_32: {
+          spvCheck(spvBinaryEncodeU32((uint32_t)literal.value.f, pInst,
+                                      position, pDiagnostic),
+                   return SPV_ERROR_INVALID_TEXT);
+        } break;
+        case SPV_LITERAL_TYPE_FLOAT_64: {
+          spvCheck(spvBinaryEncodeU64((uint64_t)literal.value.d, pInst,
+                                      position, pDiagnostic),
+                   return SPV_ERROR_INVALID_TEXT);
+        } break;
+        case SPV_LITERAL_TYPE_STRING: {
+          spvCheck(spvBinaryEncodeString(literal.value.str, pInst, position,
+                                         pDiagnostic),
+                   return SPV_ERROR_INVALID_TEXT);
+        } break;
+        default:
+          DIAGNOSTIC << "Invalid literal '" << textValue << "'";
+          return SPV_ERROR_INVALID_TEXT;
+      }
+    } break;
+    case SPV_OPERAND_TYPE_LITERAL_STRING: {
+      size_t len = strlen(textValue);
+      spvCheck('"' != textValue[0] && '"' != textValue[len - 1],
+               DIAGNOSTIC << "Invalid literal string '" << textValue
+                          << "', expected quotes.";
+               return SPV_ERROR_INVALID_TEXT);
+      // NOTE: Strip quotes
+      std::string text(textValue + 1, len - 2);
+
+      // NOTE: Special case for extended instruction library import
+      if (OpExtInstImport == pInst->opcode) {
+        pInst->extInstType = spvExtInstImportTypeGet(text.c_str());
+      }
+
+      spvCheck(
+          spvBinaryEncodeString(text.c_str(), pInst, position, pDiagnostic),
+          return SPV_ERROR_INVALID_TEXT);
+    } break;
+    default: {
+      // NOTE: All non literal operands are handled here using the operand
+      // table.
+      spv_operand_desc entry;
+      spvCheck(spvOperandTableNameLookup(operandTable, type, textValue, &entry),
+               DIAGNOSTIC << "Invalid " << spvOperandTypeStr(type) << " '"
+                          << textValue << "'.";
+               return SPV_ERROR_INVALID_TEXT;);
+      spvCheck(spvBinaryEncodeU32(entry->value, pInst, position, pDiagnostic),
+               DIAGNOSTIC << "Invalid " << spvOperandTypeStr(type) << " '"
+                          << textValue << "'.";
+               return SPV_ERROR_INVALID_TEXT;);
+      if (ppExtraOperands && entry->operandTypes[0] != SPV_OPERAND_TYPE_NONE) {
+        *ppExtraOperands = entry->operandTypes;
+      }
+    } break;
+  }
+  return SPV_SUCCESS;
+}
+
+spv_result_t spvTextEncodeOpcode(
+    const spv_text text, const spv_opcode_table opcodeTable,
+    const spv_operand_table operandTable, const spv_ext_inst_table extInstTable,
+    spv_named_id_table namedIdTable, uint32_t *pBound, spv_instruction_t *pInst,
+    spv_position position, spv_diagnostic *pDiagnostic) {
+  std::string opcodeName;
+  spv_position_t nextPosition = {};
+  spvCheck(spvTextWordGet(text, position, opcodeName, &nextPosition),
+           return SPV_ERROR_INTERNAL);
+
+  bool immediate = false;
+  spvCheck('!' == text->str[position->index], immediate = true);
+  if (!immediate) {
+    spvCheck('O' != opcodeName[0] || 'p' != opcodeName[1],
+             DIAGNOSTIC << "Invalid Opcode prefix '" << opcodeName << "'.";
+             return SPV_ERROR_INVALID_TEXT);
+  }
+
+  // NOTE: Handle insertion of an immediate integer into the binary stream
+  if (immediate) {
+    const char *begin = opcodeName.data() + 1;
+    char *end = nullptr;
+    uint32_t immediateInt = strtoul(begin, &end, 0);
+    size_t size = opcodeName.size() - 1;
+    spvCheck(size != (size_t)(end - begin),
+             DIAGNOSTIC << "Invalid immediate integer '" << opcodeName << "'.";
+             return SPV_ERROR_INVALID_TEXT);
+    position->column += opcodeName.size();
+    position->index += opcodeName.size();
+    pInst->words[0] = immediateInt;
+    pInst->wordCount = 1;
+    return SPV_SUCCESS;
+  }
+
+  // NOTE: The table contains Opcode names without the "Op" prefix.
+  const char *pInstName = opcodeName.data() + 2;
+
+  spv_opcode_desc opcodeEntry;
+  spv_result_t error =
+      spvOpcodeTableNameLookup(opcodeTable, pInstName, &opcodeEntry);
+  spvCheck(error, DIAGNOSTIC << "Invalid Opcode name '"
+                             << getWord(text->str + position->index) << "'";
+           return error);
+  pInst->opcode = opcodeEntry->opcode;
+  *position = nextPosition;
+  pInst->wordCount++;
+
+  // NOTE: Process the fixed size operands
+  const spv_operand_type_t *extraOperandTypes = nullptr;
+  for (int32_t operandIndex = 0; operandIndex < (opcodeEntry->wordCount - 1);
+       ++operandIndex) {
+    spvCheck(spvTextAdvance(text, position),
+             DIAGNOSTIC << "Expected operand, found end of stream.";
+             return SPV_ERROR_INVALID_TEXT);
+
+    std::string operandValue;
+    error = spvTextWordGet(text, position, operandValue, &nextPosition);
+    spvCheck(error, return error);
+
+    error = spvTextEncodeOperand(
+        opcodeEntry->operandTypes[operandIndex], operandValue.c_str(),
+        operandTable, extInstTable, namedIdTable, pInst, &extraOperandTypes,
+        pBound, position, pDiagnostic);
+    spvCheck(error, return error);
+
+    *position = nextPosition;
+  }
+
+  if (spvOpcodeIsVariable(opcodeEntry)) {
+    if (!extraOperandTypes) {
+      // NOTE: Handle variable length not defined by an immediate previously
+      // encountered in the Opcode.
+      spv_operand_type_t type =
+          opcodeEntry->operandTypes[opcodeEntry->wordCount - 1];
+
+      while (!spvTextAdvance(text, position)) {
+        std::string textValue;
+        spvTextWordGet(text, position, textValue, &nextPosition);
+
+        // NOTE: Check if the next text word is an Opcode
+        if ('O' == textValue[0] && 'p' == textValue[1]) {
+          // NOTE: This is the end of the current instruction stream and we
+          // break out of this loop
+          break;
+        } else {
+          if (SPV_OPERAND_TYPE_LITERAL_STRING == type) {
+            spvCheck(spvTextAdvance(text, position),
+                     DIAGNOSTIC << "Invalid string, found end of stream.";
+                     return SPV_ERROR_INVALID_TEXT);
+
+            std::string string;
+            spvCheck(spvTextStringGet(text, position, string, &nextPosition),
+                     DIAGNOSTIC << "Invalid string, new line or end of stream.";
+                     return SPV_ERROR_INVALID_TEXT);
+            spvCheck(
+                spvTextEncodeOperand(type, string.c_str(), operandTable,
+                                     extInstTable, namedIdTable, pInst, nullptr,
+                                     pBound, position, pDiagnostic),
+                return SPV_ERROR_INVALID_TEXT);
+          } else {
+            spvCheck(
+                spvTextEncodeOperand(type, textValue.c_str(), operandTable,
+                                     extInstTable, namedIdTable, pInst, nullptr,
+                                     pBound, position, pDiagnostic),
+                return SPV_ERROR_INVALID_TEXT);
+          }
+          *position = nextPosition;
+        }
+      }
+    } else {
+      // NOTE: Process the variable size operands defined by an immediate
+      // previously encountered in the Opcode.
+      uint64_t extraOperandsIndex = 0;
+      while (extraOperandTypes[extraOperandsIndex]) {
+        spvCheck(spvTextAdvance(text, position),
+                 DIAGNOSTIC << "Expected operand, found end of stream.";
+                 return SPV_ERROR_INVALID_TEXT);
+
+        std::string operandValue;
+        error = spvTextWordGet(text, position, operandValue, &nextPosition);
+
+        error = spvTextEncodeOperand(extraOperandTypes[extraOperandsIndex],
+                                     operandValue.c_str(), operandTable,
+                                     extInstTable, namedIdTable, pInst, nullptr,
+                                     pBound, position, pDiagnostic);
+        spvCheck(error, return error);
+
+        *position = nextPosition;
+
+        extraOperandsIndex++;
+      }
+    }
+  }
+
+  pInst->words[0] = spvOpcodeMake(pInst->wordCount, opcodeEntry->opcode);
+
+  return SPV_SUCCESS;
+}
+
+spv_result_t spvTextToBinary(const spv_text text,
+                             const spv_opcode_table opcodeTable,
+                             const spv_operand_table operandTable,
+                             const spv_ext_inst_table extInstTable,
+                             spv_binary *pBinary, spv_diagnostic *pDiagnostic) {
+  spv_position_t position = {};
+  spvCheck(!text->str || !text->length, DIAGNOSTIC << "Text stream is empty.";
+           return SPV_ERROR_INVALID_TEXT);
+  spvCheck(!opcodeTable || !operandTable || !extInstTable,
+           return SPV_ERROR_INVALID_TABLE);
+  spvCheck(!pBinary, return SPV_ERROR_INVALID_POINTER);
+  spvCheck(!pDiagnostic, return SPV_ERROR_INVALID_DIAGNOSTIC);
+
+  // NOTE: Ensure diagnostic is zero initialised
+  *pDiagnostic = {};
+
+  uint32_t bound = 1;
+
+  std::vector<spv_instruction_t> instructions;
+
+  spvCheck(spvTextAdvance(text, &position), DIAGNOSTIC
+                                                << "Text stream is empty.";
+           return SPV_ERROR_INVALID_TEXT);
+
+  spv_named_id_table namedIdTable = spvNamedIdTableCreate();
+  spvCheck(!namedIdTable, return SPV_ERROR_OUT_OF_MEMORY);
+
+  spv_ext_inst_type_t extInstType = SPV_EXT_INST_TYPE_NONE;
+  while (text->length > position.index) {
+    spv_instruction_t inst = {};
+    inst.extInstType = extInstType;
+
+    spvCheck(spvTextEncodeOpcode(text, opcodeTable, operandTable, extInstTable,
+                                 namedIdTable, &bound, &inst, &position,
+                                 pDiagnostic),
+             spvNamedIdTableDestory(namedIdTable);
+             return SPV_ERROR_INVALID_TEXT);
+    extInstType = inst.extInstType;
+
+    instructions.push_back(inst);
+
+    spvCheck(spvTextAdvance(text, &position), break);
+  }
+
+  spvNamedIdTableDestory(namedIdTable);
+
+  size_t totalSize = SPV_INDEX_INSTRUCTION;
+  for (auto &inst : instructions) {
+    totalSize += inst.wordCount;
+  }
+
+  uint32_t *data = new uint32_t[totalSize];
+  spvCheck(!data, return SPV_ERROR_OUT_OF_MEMORY);
+  uint64_t currentIndex = SPV_INDEX_INSTRUCTION;
+  for (auto &inst : instructions) {
+    memcpy(data + currentIndex, inst.words, sizeof(uint32_t) * inst.wordCount);
+    currentIndex += inst.wordCount;
+  }
+
+  spv_binary binary = new spv_binary_t();
+  spvCheck(!binary, delete[] data; return SPV_ERROR_OUT_OF_MEMORY);
+  binary->code = data;
+  binary->wordCount = totalSize;
+
+  spv_result_t error = spvBinaryHeaderSet(binary, bound);
+  spvCheck(error, spvBinaryDestroy(binary); return error);
+
+  *pBinary = binary;
+
+  return SPV_SUCCESS;
+}
+
+void spvTextDestroy(spv_text text) {
+  spvCheck(!text, return );
+  if (text->str) {
+    delete[] text->str;
+  }
+  delete text;
+}
diff --git a/source/text.h b/source/text.h
new file mode 100644 (file)
index 0000000..df26532
--- /dev/null
@@ -0,0 +1,193 @@
+// Copyright (c) 2015 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.
+
+#ifndef _LIBSPIRV_UTIL_TEXT_H_
+#define _LIBSPIRV_UTIL_TEXT_H_
+
+#include <libspirv/libspirv.h>
+
+#include <string>
+
+// Structures
+
+typedef enum spv_literal_type_t {
+  SPV_LITERAL_TYPE_INT_32,
+  SPV_LITERAL_TYPE_INT_64,
+  SPV_LITERAL_TYPE_UINT_32,
+  SPV_LITERAL_TYPE_UINT_64,
+  SPV_LITERAL_TYPE_FLOAT_32,
+  SPV_LITERAL_TYPE_FLOAT_64,
+  SPV_LITERAL_TYPE_STRING,
+  SPV_FORCE_32_BIT_ENUM(spv_literal_type_t)
+} spv_literal_type_t;
+
+typedef struct spv_literal_t {
+  spv_literal_type_t type;
+  union value_t {
+    int32_t i32;
+    int64_t i64;
+    uint32_t u32;
+    uint64_t u64;
+    float f;
+    double d;
+    char str[SPV_LIMIT_LITERAL_STRING_MAX];
+  } value;
+} spv_literal_t;
+
+struct spv_named_id_table_t;
+
+// Types
+
+typedef spv_named_id_table_t *spv_named_id_table;
+
+// Functions
+
+/// @brief Advance text to the start of the next line
+///
+/// @param[in] text to be parsed
+/// @param[in,out] pPosition position text has been advanced to
+///
+/// @return result code
+spv_result_t spvTextAdvanceLine(const spv_text text, spv_position_t *pPosition);
+
+/// @brief Advance text to first non white space character
+///
+/// If a null terminator is found during the text advance SPV_END_OF_STREAM is
+/// returned, SPV_SUCCESS otherwise. No error checking is performed on the
+/// parameters, its the users responsispvity to ensure these are non null.
+///
+/// @param[in] text to be parsed
+/// @param[in,out] pPosition position text has been advanced to
+///
+/// @return result code
+spv_result_t spvTextAdvance(const spv_text text, spv_position_t *pPosition);
+
+/// @brief Fetch the next word from the text stream
+///
+/// @param[in] text stream to read from
+/// @param[in] startPosition current position in text stream
+/// @param[out] word returned word
+/// @param[out] endPosition one past the end of the returned word
+///
+/// @return result code
+spv_result_t spvTextWordGet(const spv_text text,
+                            const spv_position startPosition, std::string &word,
+                            spv_position endPosition);
+
+/// @brief Fetch a string, including quotes, from the text stream
+///
+/// @param[in] text stream to read from
+/// @param[in] startPosition current position in text stream
+/// @param[out] string returned string
+/// @param[out] endPosition one past the end of the return string
+///
+/// @return result code
+spv_result_t spvTextStringGet(const spv_text text,
+                              const spv_position startPosition,
+                              std::string &string, spv_position endPosition);
+
+/// @brief Convert the input text to a unsigned 32 bit integer
+///
+/// @param[in] textValue input text to parse
+/// @param[out] pValue the returned integer
+///
+/// @return result code
+spv_result_t spvTextToUInt32(const char *textValue, uint32_t *pValue);
+
+/// @brief Convert the input text to one of the number types
+///
+/// @param[in] textValue input text to parse
+/// @param[out] pLiteral the returned literal number
+///
+/// @return result code
+spv_result_t spvTextToLiteral(const char *textValue, spv_literal_t *pLiteral);
+
+/// @brief Create a named ID table
+///
+/// @return named ID table
+spv_named_id_table spvNamedIdTableCreate();
+
+/// @brief Free a named ID table
+///
+/// @param table named ID table
+void spvNamedIdTableDestory(spv_named_id_table table);
+
+/// @brief Lookup or assign a named ID
+///
+/// @param table named ID table
+/// @param textValue name value
+/// @param pBound upper ID bound, used for assigning new ID's
+///
+/// @return the new ID assossiated with the named ID
+uint32_t spvNamedIdAssignOrGet(spv_named_id_table table, const char *textValue,
+                               uint32_t *pBound);
+
+/// @brief Determine if a name has an assossiated ID
+///
+/// @param textValue name value
+///
+/// @return zero on failure, non-zero otherwise
+int32_t spvTextIsNamedId(const char *textValue);
+
+/// @brief Translate an Opcode operand to binary form
+///
+/// @param[in] type of the operand
+/// @param[in] textValue word of text to be parsed
+/// @param[in] operandTable operand lookup table
+/// @param[in,out] namedIdTable table of named ID's
+/// @param[out] pInst return binary Opcode
+/// @param[out] ppExtraOperands list of extra variable operands, if any
+/// @param[in,out] pBound current highest defined ID value
+/// @param[in] pPosition used in diagnostic on error
+/// @param[out] pDiagnostic populated on error
+///
+/// @return result code
+spv_result_t spvTextEncodeOperand(
+    const spv_operand_type_t type, const char *textValue,
+    const spv_operand_table operandTable, const spv_ext_inst_table extInstTable,
+    spv_named_id_table namedIdTable, spv_instruction_t *pInst,
+    const spv_operand_type_t **ppExtraOperands, uint32_t *pBound,
+    const spv_position_t *pPosition, spv_diagnostic *pDiagnostic);
+
+/// @brief Translate single Opcode and operands to binary form
+///
+/// @param[in] text stream to translate
+/// @param[in] opcodeTable Opcode lookup table
+/// @param[in] operandTable operand lookup table
+/// @param[in,out] namedIdTable table of named ID's
+/// @param[in,out] pBound current highest defined ID value
+/// @param[out] pInst returned binary Opcode
+/// @param[in,out] pPosition in the text stream
+/// @param[out] pDiagnostic populated on failure
+///
+/// @return result code
+spv_result_t spvTextEncodeOpcode(
+    const spv_text text, const spv_opcode_table opcodeTable,
+    const spv_operand_table operandTable, const spv_ext_inst_table extInstTable,
+    spv_named_id_table namedIdTable, uint32_t *pBound, spv_instruction_t *pInst,
+    spv_position_t *pPosition, spv_diagnostic *pDiagnostic);
+
+#endif
diff --git a/source/validate.cpp b/source/validate.cpp
new file mode 100644 (file)
index 0000000..07ecb79
--- /dev/null
@@ -0,0 +1,300 @@
+// Copyright (c) 2015 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.
+
+#include <libspirv/libspirv.h>
+#include "binary.h"
+#include "diagnostic.h"
+#include "opcode.h"
+#include "operand.h"
+#include "validate.h"
+
+#include <assert.h>
+#include <string.h>
+#include <stdio.h>
+
+#include <vector>
+
+spv_result_t spvValidateOperandsString(const uint32_t *words,
+                                       const uint16_t wordCount,
+                                       spv_position position,
+                                       spv_diagnostic *pDiagnostic) {
+  const char *str = (const char *)words;
+  uint64_t strWordCount = strlen(str) / sizeof(uint32_t) + 1;
+  spvCheck(strWordCount < wordCount, DIAGNOSTIC << "Instruction word count is "
+                                                   "too short, string extends "
+                                                   "past end of instruction.";
+           return SPV_WARNING);
+  return SPV_SUCCESS;
+}
+
+spv_result_t spvValidateOperandsLiteral(const uint32_t *words,
+                                        const uint32_t length,
+                                        const uint16_t maxLength,
+                                        spv_position position,
+                                        spv_diagnostic *pDiagnostic) {
+  // NOTE: A literal could either be a number consuming up to 2 words or a
+  // null terminated string.
+  (void)words;
+  (void)length;
+  (void)maxLength;
+  (void)position;
+  (void)pDiagnostic;
+  return SPV_UNSUPPORTED;
+}
+
+spv_result_t spvValidateOperandValue(const spv_operand_type_t type,
+                                     const uint32_t word,
+                                     const spv_operand_table operandTable,
+                                     spv_position position,
+                                     spv_diagnostic *pDiagnostic) {
+  switch (type) {
+    case SPV_OPERAND_TYPE_ID:
+    case SPV_OPERAND_TYPE_RESULT_ID: {
+      // NOTE: ID's are validated in SPV_VALIDATION_LEVEL_1, this is
+      // SPV_VALIDATION_LEVEL_0
+    } break;
+    case SPV_OPERAND_TYPE_LITERAL_NUMBER: {
+      // NOTE: Implicitly valid as they are encoded as 32 bit value
+    } break;
+    case SPV_OPERAND_TYPE_SOURCE_LANGUAGE:
+    case SPV_OPERAND_TYPE_EXECUTION_MODEL:
+    case SPV_OPERAND_TYPE_ADDRESSING_MODEL:
+    case SPV_OPERAND_TYPE_MEMORY_MODEL:
+    case SPV_OPERAND_TYPE_EXECUTION_MODE:
+    case SPV_OPERAND_TYPE_STORAGE_CLASS:
+    case SPV_OPERAND_TYPE_DIMENSIONALITY:
+    case SPV_OPERAND_TYPE_SAMPLER_ADDRESSING_MODE:
+    case SPV_OPERAND_TYPE_SAMPLER_FILTER_MODE:
+    case SPV_OPERAND_TYPE_FP_FAST_MATH_MODE:
+    case SPV_OPERAND_TYPE_FP_ROUNDING_MODE:
+    case SPV_OPERAND_TYPE_LINKAGE_TYPE:
+    case SPV_OPERAND_TYPE_ACCESS_QUALIFIER:
+    case SPV_OPERAND_TYPE_FUNCTION_PARAMETER_ATTRIBUTE:
+    case SPV_OPERAND_TYPE_DECORATION:
+    case SPV_OPERAND_TYPE_BUILT_IN:
+    case SPV_OPERAND_TYPE_SELECTION_CONTROL:
+    case SPV_OPERAND_TYPE_LOOP_CONTROL:
+    case SPV_OPERAND_TYPE_FUNCTION_CONTROL:
+    case SPV_OPERAND_TYPE_MEMORY_SEMANTICS:
+    case SPV_OPERAND_TYPE_MEMORY_ACCESS:
+    case SPV_OPERAND_TYPE_EXECUTION_SCOPE:
+    case SPV_OPERAND_TYPE_GROUP_OPERATION:
+    case SPV_OPERAND_TYPE_KERNEL_ENQ_FLAGS:
+    case SPV_OPERAND_TYPE_KERENL_PROFILING_INFO: {
+      spv_operand_desc operandEntry = nullptr;
+      spv_result_t error =
+          spvOperandTableValueLookup(operandTable, type, word, &operandEntry);
+      spvCheck(error, DIAGNOSTIC << "Invalid '" << spvOperandTypeStr(type)
+                                 << "' operand '" << word << "'.";
+               return error);
+    } break;
+    default:
+      assert(0 && "Invalid operand types should already have been caught!");
+  }
+  return SPV_SUCCESS;
+}
+
+spv_result_t spvValidateBasic(const spv_instruction_t *pInsts,
+                              const uint64_t instCount,
+                              const spv_opcode_table opcodeTable,
+                              const spv_operand_table operandTable,
+                              spv_position position,
+                              spv_diagnostic *pDiagnostic) {
+  for (uint64_t instIndex = 0; instIndex < instCount; ++instIndex) {
+    const uint32_t *words = pInsts[instIndex].words;
+    uint16_t wordCount;
+    Op opcode;
+    spvOpcodeSplit(words[0], &wordCount, &opcode);
+
+    spv_opcode_desc opcodeEntry = nullptr;
+    spvCheck(spvOpcodeTableValueLookup(opcodeTable, opcode, &opcodeEntry),
+             DIAGNOSTIC << "Invalid Opcode '" << opcode << "'.";
+             return SPV_ERROR_INVALID_BINARY);
+    position->index++;
+
+    spvCheck(opcodeEntry->wordCount > wordCount,
+             DIAGNOSTIC << "Instruction word count '" << wordCount
+                        << "' is not small, expected at least '"
+                        << opcodeEntry->wordCount << "'.";
+             return SPV_ERROR_INVALID_BINARY);
+
+    spv_operand_desc operandEntry = nullptr;
+    for (uint16_t index = 1; index < pInsts[instIndex].wordCount;
+         ++index, position->index++) {
+      const uint32_t word = words[index];
+      spv_operand_type_t type = spvBinaryOperandInfo(
+          word, index, opcodeEntry, operandTable, &operandEntry);
+      if (SPV_OPERAND_TYPE_LITERAL_STRING == type) {
+        spvCheckReturn(spvValidateOperandsString(
+            words + index, wordCount - index, position, pDiagnostic));
+        // NOTE: String literals are always at the end of Opcodes
+        break;
+      } else if (SPV_OPERAND_TYPE_LITERAL == type) {
+        spvCheckReturn(spvValidateOperandsLiteral(
+            words + index, wordCount - index, 2, position, pDiagnostic));
+      } else {
+        spvCheckReturn(spvValidateOperandValue(type, word, operandTable,
+                                               position, pDiagnostic));
+      }
+    }
+  }
+
+  return SPV_SUCCESS;
+}
+
+spv_result_t spvValidateIDs(const spv_instruction_t *pInsts,
+                            const uint64_t count, const uint32_t bound,
+                            const spv_opcode_table opcodeTable,
+                            const spv_operand_table operandTable,
+                            const spv_ext_inst_table extInstTable,
+                            spv_position position,
+                            spv_diagnostic *pDiagnostic) {
+  std::vector<spv_id_info_t> idUses;
+  std::vector<spv_id_info_t> idDefs;
+
+  for (uint64_t instIndex = 0; instIndex < count; ++instIndex) {
+    const uint32_t *words = pInsts[instIndex].words;
+    Op opcode;
+    spvOpcodeSplit(words[0], nullptr, &opcode);
+
+    spv_opcode_desc opcodeEntry = nullptr;
+    spvCheck(spvOpcodeTableValueLookup(opcodeTable, opcode, &opcodeEntry),
+             DIAGNOSTIC << "Invalid Opcode '" << opcode << "'.";
+             return SPV_ERROR_INVALID_BINARY);
+
+    spv_operand_desc operandEntry = nullptr;
+    position->index++;  // NOTE: Account for Opcode word
+    for (uint16_t index = 1; index < pInsts[instIndex].wordCount;
+         ++index, position->index++) {
+      const uint32_t word = words[index];
+
+      spv_operand_type_t type = spvBinaryOperandInfo(
+          word, index, opcodeEntry, operandTable, &operandEntry);
+
+      if (SPV_OPERAND_TYPE_RESULT_ID == type || SPV_OPERAND_TYPE_ID == type) {
+        spvCheck(0 == word, DIAGNOSTIC << "Invalid ID of '0' is not allowed.";
+                 return SPV_ERROR_INVALID_ID);
+        spvCheck(bound < word, DIAGNOSTIC << "Invalid ID '" << word
+                                          << "' exceeds the bound '" << bound
+                                          << "'.";
+                 return SPV_ERROR_INVALID_ID);
+      }
+
+      if (SPV_OPERAND_TYPE_RESULT_ID == type) {
+        idDefs.push_back(
+            {word, opcodeEntry->opcode, &pInsts[instIndex], *position});
+      }
+
+      if (SPV_OPERAND_TYPE_ID == type) {
+        idUses.push_back({word, opcodeEntry->opcode, nullptr, *position});
+      }
+    }
+  }
+
+  // NOTE: Error on redefined ID
+  for (size_t outerIndex = 0; outerIndex < idDefs.size(); ++outerIndex) {
+    for (size_t innerIndex = 0; innerIndex < idDefs.size(); ++innerIndex) {
+      if (outerIndex == innerIndex) {
+        continue;
+      }
+      if (idDefs[outerIndex].id == idDefs[innerIndex].id) {
+        DIAGNOSTIC << "Multiply defined ID '" << idDefs[outerIndex].id << "'.";
+        return SPV_ERROR_INVALID_ID;
+      }
+    }
+  }
+
+  // NOTE: Validate ID usage, including use of undefined ID's
+  position->index = SPV_INDEX_INSTRUCTION;
+  spvCheck(spvValidateInstructionIDs(pInsts, count, idUses.data(),
+                                     idUses.size(), idDefs.data(),
+                                     idDefs.size(), opcodeTable, operandTable,
+                                     extInstTable, position, pDiagnostic),
+           return SPV_ERROR_INVALID_ID);
+
+  return SPV_SUCCESS;
+}
+
+spv_result_t spvValidate(const spv_binary binary,
+                         const spv_opcode_table opcodeTable,
+                         const spv_operand_table operandTable,
+                         const spv_ext_inst_table extInstTable,
+                         const uint32_t options, spv_diagnostic *pDiagnostic) {
+  spvCheck(!opcodeTable || !operandTable, return SPV_ERROR_INVALID_TABLE);
+  spvCheck(!pDiagnostic, return SPV_ERROR_INVALID_DIAGNOSTIC);
+
+  spv_endianness_t endian;
+  spv_position_t position = {};
+  spvCheck(spvBinaryEndianness(binary, &endian),
+           DIAGNOSTIC << "Invalid SPIR-V magic number.";
+           return SPV_ERROR_INVALID_BINARY);
+
+  spv_header_t header;
+  spvCheck(spvBinaryHeaderGet(binary, endian, &header),
+           DIAGNOSTIC << "Invalid SPIR-V header.";
+           return SPV_ERROR_INVALID_BINARY);
+
+  // NOTE: Copy each instruction for easier processing
+  std::vector<spv_instruction_t> instructions;
+  uint64_t index = SPV_INDEX_INSTRUCTION;
+  while (index < binary->wordCount) {
+    uint16_t wordCount;
+    Op opcode;
+    spvOpcodeSplit(spvFixWord(binary->code[index], endian), &wordCount,
+                   &opcode);
+    spv_instruction_t inst;
+    spvInstructionCopy(&binary->code[index], opcode, wordCount, endian, &inst);
+    instructions.push_back(inst);
+    index += wordCount;
+  }
+
+  if (spvIsInBitfield(SPV_VALIDATE_BASIC_BIT, options)) {
+    position.index = SPV_INDEX_INSTRUCTION;
+    // TODO: Imcomplete implementation
+    spvCheckReturn(spvValidateBasic(instructions.data(), instructions.size(),
+                                    opcodeTable, operandTable, &position,
+                                    pDiagnostic));
+  }
+
+  if (spvIsInBitfield(SPV_VALIDATE_LAYOUT_BIT, options)) {
+    position.index = SPV_INDEX_INSTRUCTION;
+    // TODO: spvBinaryValidateLayout
+  }
+
+  if (spvIsInBitfield(SPV_VALIDATE_ID_BIT, options)) {
+    position.index = SPV_INDEX_INSTRUCTION;
+    spvCheckReturn(spvValidateIDs(instructions.data(), instructions.size(),
+                                  header.bound, opcodeTable, operandTable,
+                                  extInstTable, &position, pDiagnostic));
+  }
+
+  if (spvIsInBitfield(SPV_VALIDATE_RULES_BIT, options)) {
+    position.index = SPV_INDEX_INSTRUCTION;
+    // TODO: Specified validation rules...
+  }
+
+  return SPV_SUCCESS;
+}
diff --git a/source/validate.h b/source/validate.h
new file mode 100644 (file)
index 0000000..661c84f
--- /dev/null
@@ -0,0 +1,83 @@
+// Copyright (c) 2015 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.
+
+#ifndef _LIBSPIRV_UTIL_VALIDATE_H_
+#define _LIBSPIRV_UTIL_VALIDATE_H_
+
+#include <libspirv/libspirv.h>
+
+// Structures
+
+typedef struct spv_id_info_t {
+  uint32_t id;
+  Op opcode;
+  const spv_instruction_t *inst;
+  spv_position_t position;
+} spv_id_info_t;
+
+// Functions
+
+/// @brief Validate the ID usage of the instruction stream
+///
+/// @param[in] pInsts stream of instructions
+/// @param[in] instCount number of instructions
+/// @param[in] pIdUses stream of ID uses
+/// @param[in] idUsesCount number of ID uses
+/// @param[in] pIdDefs stream of ID uses
+/// @param[in] idDefsCount number of ID uses
+/// @param[in] opcodeTable table of specified Opcodes
+/// @param[in] operandTable table of specified operands
+/// @param[in,out] position current position in the stream
+/// @param[out] pDiag contains diagnostic on failure
+///
+/// @return result code
+spv_result_t spvValidateInstructionIDs(
+    const spv_instruction_t *pInsts, const uint64_t instCount,
+    const spv_id_info_t *pIdUses, const uint64_t idUsesCount,
+    const spv_id_info_t *pIdDefs, const uint64_t idDefsCount,
+    const spv_opcode_table opcodeTable, const spv_operand_table operandTable,
+    const spv_ext_inst_table extInstTable, spv_position position,
+    spv_diagnostic *pDiag);
+
+/// @brief Validate the ID's within a SPIR-V binary
+///
+/// @param[in] pInstructions array of instructions
+/// @param[in] count number of elements in instruction array
+/// @param[in] bound the binary header
+/// @param[in] opcodeTable table of specified Opcodes
+/// @param[in] operandTable table of specified operands
+/// @param[in,out] position current word in the binary
+/// @param[out] pDiagnostic contains diagnostic on failure
+///
+/// @return result code
+spv_result_t spvValidateIDs(const spv_instruction_t *pInstructions,
+                            const uint64_t count, const uint32_t bound,
+                            const spv_opcode_table opcodeTable,
+                            const spv_operand_table operandTable,
+                            const spv_ext_inst_table extInstTable,
+                            spv_position position, spv_diagnostic *pDiagnostic);
+
+#endif
diff --git a/source/validate_id.cpp b/source/validate_id.cpp
new file mode 100644 (file)
index 0000000..9f2a260
--- /dev/null
@@ -0,0 +1,2808 @@
+// Copyright (c) 2015 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.
+
+#include <libspirv/libspirv.h>
+#include "diagnostic.h"
+#include "opcode.h"
+#include "validate.h"
+
+#include <assert.h>
+
+#include <iostream>
+#include <unordered_map>
+#include <vector>
+
+namespace {
+class idUsage {
+ public:
+  idUsage(const spv_opcode_table opcodeTable,
+          const spv_operand_table operandTable,
+          const spv_ext_inst_table extInstTable, const spv_id_info_t *pIdUses,
+          const uint64_t idUsesCount, const spv_id_info_t *pIdDefs,
+          const uint64_t idDefsCount, const spv_instruction_t *pInsts,
+          const uint64_t instCount, spv_position position,
+          spv_diagnostic *pDiagnostic)
+      : opcodeTable(opcodeTable),
+        operandTable(operandTable),
+        extInstTable(extInstTable),
+        firstInst(pInsts),
+        instCount(instCount),
+        position(position),
+        pDiagnostic(pDiagnostic) {
+    for (uint64_t idUsesIndex = 0; idUsesIndex < idUsesCount; ++idUsesIndex) {
+      idUses[pIdUses[idUsesIndex].id].push_back(pIdUses[idUsesIndex]);
+    }
+    for (uint64_t idDefsIndex = 0; idDefsIndex < idDefsCount; ++idDefsIndex) {
+      idDefs[pIdDefs[idDefsIndex].id] = pIdDefs[idDefsIndex];
+    }
+  }
+
+  bool isValid(const spv_instruction_t *inst);
+
+  template <Op>
+  bool isValid(const spv_instruction_t *inst, const spv_opcode_desc);
+
+  std::unordered_map<uint32_t, spv_id_info_t>::iterator find(
+      const uint32_t &id) {
+    return idDefs.find(id);
+  }
+  std::unordered_map<uint32_t, spv_id_info_t>::const_iterator find(
+      const uint32_t &id) const {
+    return idDefs.find(id);
+  }
+
+  bool found(std::unordered_map<uint32_t, spv_id_info_t>::iterator item) {
+    return idDefs.end() != item;
+  }
+  bool found(std::unordered_map<uint32_t, spv_id_info_t>::const_iterator item) {
+    return idDefs.end() != item;
+  }
+
+  std::unordered_map<uint32_t, std::vector<spv_id_info_t>>::iterator findUses(
+      const uint32_t &id) {
+    return idUses.find(id);
+  }
+  std::unordered_map<uint32_t, std::vector<spv_id_info_t>>::const_iterator
+  findUses(const uint32_t &id) const {
+    return idUses.find(id);
+  }
+
+  bool foundUses(
+      std::unordered_map<uint32_t, std::vector<spv_id_info_t>>::iterator item) {
+    return idUses.end() != item;
+  }
+  bool foundUses(std::unordered_map<
+      uint32_t, std::vector<spv_id_info_t>>::const_iterator item) {
+    return idUses.end() != item;
+  }
+
+ private:
+  const spv_opcode_table opcodeTable;
+  const spv_operand_table operandTable;
+  const spv_ext_inst_table extInstTable;
+  const spv_instruction_t *const firstInst;
+  const uint64_t instCount;
+  spv_position position;
+  spv_diagnostic *pDiagnostic;
+  std::unordered_map<uint32_t, std::vector<spv_id_info_t>> idUses;
+  std::unordered_map<uint32_t, spv_id_info_t> idDefs;
+};
+
+#define DIAG(INDEX)         \
+  position->index += INDEX; \
+  DIAGNOSTIC
+
+#if 0
+template <>
+bool idUsage::isValid<OpUndef>(const spv_instruction_t *inst,
+                               const spv_opcode_desc) {
+  assert(0 && "Unimplemented!");
+  return false;
+}
+#endif
+
+template <>
+bool idUsage::isValid<OpName>(const spv_instruction_t *inst,
+                              const spv_opcode_desc) {
+  auto targetIndex = 1;
+  auto target = find(inst->words[targetIndex]);
+  spvCheck(!found(target), DIAG(targetIndex) << "OpName Target <id> '"
+                                             << inst->words[targetIndex]
+                                             << "' is not defined.";
+           return false);
+  return true;
+}
+
+template <>
+bool idUsage::isValid<OpMemberName>(const spv_instruction_t *inst,
+                                    const spv_opcode_desc) {
+  auto typeIndex = 1;
+  auto type = find(inst->words[typeIndex]);
+  spvCheck(!found(type), DIAG(typeIndex) << "OpMemberName Type <id> '"
+                                         << inst->words[typeIndex]
+                                         << "' is not defined.";
+           return false);
+  spvCheck(OpTypeStruct != type->second.opcode,
+           DIAG(typeIndex) << "OpMemberName Type <id> '"
+                           << inst->words[typeIndex]
+                           << "' is not a struct type.";
+           return false);
+  auto memberIndex = 2;
+  auto member = inst->words[memberIndex];
+  auto memberCount = (uint32_t)(type->second.inst->wordCount - 2);
+  spvCheck(memberCount <= member, DIAG(memberIndex)
+                                      << "OpMemberName Member <id> '"
+                                      << inst->words[memberIndex]
+                                      << "' index is larger than Type <id> '"
+                                      << type->second.id << "'s member count.";
+           return false);
+  return true;
+}
+
+template <>
+bool idUsage::isValid<OpLine>(const spv_instruction_t *inst,
+                              const spv_opcode_desc) {
+  auto targetIndex = 1;
+  auto target = find(inst->words[targetIndex]);
+  spvCheck(!found(target), DIAG(targetIndex) << "OpLine Target <id> '"
+                                             << inst->words[targetIndex]
+                                             << "' is not defined.";
+           return false);
+  auto fileIndex = 2;
+  auto file = find(inst->words[fileIndex]);
+  spvCheck(!found(file), DIAG(fileIndex) << "OpLine Target <id> '"
+                                         << inst->words[fileIndex]
+                                         << "' is not defined.";
+           return false);
+  spvCheck(OpString != file->second.opcode,
+           DIAG(fileIndex) << "OpLine Target <id> '" << inst->words[fileIndex]
+                           << "' is not an OpString.";
+           return false);
+  return true;
+}
+
+template <>
+bool idUsage::isValid<OpDecorate>(const spv_instruction_t *inst,
+                                  const spv_opcode_desc) {
+  auto targetIndex = 1;
+  auto target = find(inst->words[targetIndex]);
+  spvCheck(!found(target), DIAG(targetIndex) << "OpDecorate Target <id> '"
+                                             << inst->words[targetIndex]
+                                             << "' is not defined.";
+           return false);
+  return true;
+}
+
+template <>
+bool idUsage::isValid<OpMemberDecorate>(const spv_instruction_t *inst,
+                                        const spv_opcode_desc) {
+  auto structTypeIndex = 1;
+  auto structType = find(inst->words[structTypeIndex]);
+  spvCheck(!found(structType), DIAG(structTypeIndex)
+                                   << "OpMemberDecorate Structure type <id> '"
+                                   << inst->words[structTypeIndex]
+                                   << "' is not defined.";
+           return false);
+  spvCheck(OpTypeStruct != structType->second.inst->opcode,
+           DIAG(structTypeIndex) << "OpMemberDecorate Structure type <id> '"
+                                 << inst->words[structTypeIndex]
+                                 << "' is not a struct type.";
+           return false);
+  auto memberIndex = 2;
+  auto member = inst->words[memberIndex];
+  auto memberCount = (uint32_t)(structType->second.inst->wordCount - 2);
+  spvCheck(memberCount < member, DIAG(memberIndex)
+                                     << "OpMemberDecorate Structure type <id> '"
+                                     << inst->words[memberIndex]
+                                     << "' member count is less than Member";
+           return false);
+  return true;
+}
+
+template <>
+bool idUsage::isValid<OpGroupDecorate>(const spv_instruction_t *inst,
+                                       const spv_opcode_desc) {
+  auto decorationGroupIndex = 1;
+  auto decorationGroup = find(inst->words[decorationGroupIndex]);
+  spvCheck(!found(decorationGroup),
+           DIAG(decorationGroupIndex)
+               << "OpGroupDecorate Decoration group <id> '"
+               << inst->words[decorationGroupIndex] << "' is not defined.";
+           return false);
+  spvCheck(OpDecorationGroup != decorationGroup->second.opcode,
+           DIAG(decorationGroupIndex)
+               << "OpGroupDecorate Decoration group <id> '"
+               << inst->words[decorationGroupIndex]
+               << "' is not a decoration group.";
+           return false);
+  for (uint64_t targetIndex = 2; targetIndex < inst->wordCount; ++targetIndex) {
+    auto target = find(inst->words[targetIndex]);
+    spvCheck(!found(target), DIAG(targetIndex)
+                                 << "OpGroupDecorate Target <id> '"
+                                 << inst->words[targetIndex]
+                                 << "' is not defined.";
+             return false);
+  }
+  return true;
+}
+
+#if 0
+template <>
+bool idUsage::isValid<OpGroupMemberDecorate>(
+    const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {}
+#endif
+
+#if 0
+template <>
+bool idUsage::isValid<OpExtInst>(const spv_instruction_t *inst,
+                                 const spv_opcode_desc opcodeEntry) {}
+#endif
+
+template <>
+bool idUsage::isValid<OpEntryPoint>(const spv_instruction_t *inst,
+                                    const spv_opcode_desc) {
+  auto entryPointIndex = 2;
+  auto entryPoint = find(inst->words[entryPointIndex]);
+  spvCheck(!found(entryPoint), DIAG(entryPointIndex)
+                                   << "OpEntryPoint Entry Point <id> '"
+                                   << inst->words[entryPointIndex]
+                                   << "' is not defined.";
+           return false);
+  spvCheck(OpFunction != entryPoint->second.opcode,
+           DIAG(entryPointIndex) << "OpEntryPoint Entry Point <id> '"
+                                 << inst->words[entryPointIndex]
+                                 << "' is not a function.";
+           return false);
+  // TODO: Check the entry point signature is void main(void), may be subject
+  // to change
+  auto entryPointType = find(entryPoint->second.inst->words[4]);
+  spvCheck(!found(entryPointType), assert(0 && "Unreachable!"));
+  spvCheck(3 != entryPointType->second.inst->wordCount,
+           DIAG(entryPointIndex) << "OpEntryPoint Entry Point <id> '"
+                                 << inst->words[entryPointIndex]
+                                 << "'s function parameter count is not zero.";
+           return false);
+  auto returnType = find(entryPoint->second.inst->words[1]);
+  spvCheck(!found(returnType), assert(0 && "Unreachable!"));
+  spvCheck(OpTypeVoid != returnType->second.opcode,
+           DIAG(entryPointIndex) << "OpEntryPoint Entry Point <id> '"
+                                 << inst->words[entryPointIndex]
+                                 << "'s function return type is not void.";
+           return false);
+  return true;
+}
+
+template <>
+bool idUsage::isValid<OpExecutionMode>(const spv_instruction_t *inst,
+                                       const spv_opcode_desc) {
+  auto entryPointIndex = 1;
+  auto entryPoint = find(inst->words[entryPointIndex]);
+  spvCheck(!found(entryPoint), DIAG(entryPointIndex)
+                                   << "OpExecutionMode Entry Point <id> '"
+                                   << inst->words[entryPointIndex]
+                                   << "' is not defined.";
+           return false);
+  auto entryPointUses = findUses(inst->words[entryPointIndex]);
+  spvCheck(!foundUses(entryPointUses), assert(0 && "Unreachable!"));
+  bool foundEntryPointUse = false;
+  for (auto use : entryPointUses->second) {
+    if (OpEntryPoint == use.opcode) {
+      foundEntryPointUse = true;
+    }
+  }
+  spvCheck(!foundEntryPointUse, DIAG(entryPointIndex)
+                                    << "OpExecutionMode Entry Point <id> '"
+                                    << inst->words[entryPointIndex]
+                                    << "' is not the Entry Point "
+                                       "operand of an OpEntryPoint.";
+           return false);
+  return true;
+}
+
+template <>
+bool idUsage::isValid<OpTypeVector>(const spv_instruction_t *inst,
+                                    const spv_opcode_desc) {
+  auto componentIndex = 2;
+  auto componentType = find(inst->words[componentIndex]);
+  spvCheck(!found(componentType), DIAG(componentIndex)
+                                      << "OpTypeVector Component Type <id> '"
+                                      << inst->words[componentIndex]
+                                      << "' is not defined.";
+           return false);
+  spvCheck(!spvOpcodeIsScalarType(componentType->second.opcode),
+           DIAG(componentIndex) << "OpTypeVector Component Type <id> '"
+                                << inst->words[componentIndex]
+                                << "' is not a scalar type.";
+           return false);
+  return true;
+}
+
+template <>
+bool idUsage::isValid<OpTypeMatrix>(const spv_instruction_t *inst,
+                                    const spv_opcode_desc) {
+  auto columnTypeIndex = 2;
+  auto columnType = find(inst->words[columnTypeIndex]);
+  spvCheck(!found(columnType), DIAG(columnTypeIndex)
+                                   << "OpTypeMatrix Column Type <id> '"
+                                   << inst->words[columnTypeIndex]
+                                   << "' is not defined.";
+           return false);
+  spvCheck(OpTypeVector != columnType->second.opcode,
+           DIAG(columnTypeIndex) << "OpTypeMatrix Column Type <id> '"
+                                 << inst->words[columnTypeIndex]
+                                 << "' is not a vector.";
+           return false);
+  return true;
+}
+
+template <>
+bool idUsage::isValid<OpTypeSampler>(const spv_instruction_t *inst,
+                                     const spv_opcode_desc) {
+  auto sampledTypeIndex = 2;
+  auto sampledType = find(inst->words[sampledTypeIndex]);
+  spvCheck(!found(sampledType), DIAG(sampledTypeIndex)
+                                    << "OpTypeSampler Sampled Type <id> '"
+                                    << inst->words[sampledTypeIndex]
+                                    << "' is not defined.";
+           return false);
+  spvCheck(!spvOpcodeIsScalarType(sampledType->second.opcode),
+           DIAG(sampledTypeIndex) << "OpTypeSampler Sampled Type <id> '"
+                                  << inst->words[sampledTypeIndex]
+                                  << "' is not a scalar type.";
+           return false);
+  return true;
+}
+
+template <>
+bool idUsage::isValid<OpTypeArray>(const spv_instruction_t *inst,
+                                   const spv_opcode_desc) {
+  auto elementTypeIndex = 2;
+  auto elementType = find(inst->words[elementTypeIndex]);
+  spvCheck(!found(elementType), DIAG(elementTypeIndex)
+                                    << "OpTypeArray Element Type <id> '"
+                                    << inst->words[elementTypeIndex]
+                                    << "' is not defined.";
+           return false);
+  spvCheck(!spvOpcodeIsType(elementType->second.opcode),
+           DIAG(elementTypeIndex) << "OpTypeArray Element Type <id> '"
+                                  << inst->words[elementTypeIndex]
+                                  << "' is not a type.";
+           return false);
+  auto lengthIndex = 3;
+  auto length = find(inst->words[lengthIndex]);
+  spvCheck(!found(length), DIAG(lengthIndex) << "OpTypeArray Length <id> '"
+                                             << inst->words[lengthIndex]
+                                             << "' is not defined.";
+           return false);
+  spvCheck(OpConstant != length->second.opcode &&
+               OpSpecConstant != length->second.opcode,
+           DIAG(lengthIndex) << "OpTypeArray Length <id> '"
+                             << inst->words[lengthIndex]
+                             << "' is not a scalar constant type.";
+           return false);
+
+  // NOTE: Check the initialiser value of the constant
+  auto constInst = length->second.inst;
+  auto constResultTypeIndex = 1;
+  auto constResultType = find(constInst->words[constResultTypeIndex]);
+  spvCheck(!found(constResultType), DIAG(lengthIndex)
+                                        << "OpTypeArray Length <id> '"
+                                        << inst->words[constResultTypeIndex]
+                                        << "' result type is not defined.";
+           return false);
+  spvCheck(OpTypeInt != constResultType->second.opcode,
+           DIAG(lengthIndex) << "OpTypeArray Length <id> '"
+                             << inst->words[lengthIndex]
+                             << "' is not a constant integer type.";
+           return false);
+  if (4 == constInst->wordCount) {
+    spvCheck(1 > constInst->words[3], DIAG(lengthIndex)
+                                          << "OpTypeArray Length <id> '"
+                                          << inst->words[lengthIndex]
+                                          << "' value must be at least 1.";
+             return false);
+  } else if (5 == constInst->wordCount) {
+    uint64_t value =
+        constInst->words[3] | ((uint64_t)constInst->words[4]) << 32;
+    bool signedness = constResultType->second.inst->words[3];
+    if (signedness) {
+      spvCheck(1 > (int64_t)value, DIAG(lengthIndex)
+                                       << "OpTypeArray Length <id> '"
+                                       << inst->words[lengthIndex]
+                                       << "' value must be at least 1.";
+               return false);
+    } else {
+      spvCheck(1 > value, DIAG(lengthIndex) << "OpTypeArray Length <id> '"
+                                            << inst->words[lengthIndex]
+                                            << "' value must be at least 1.";
+               return false);
+    }
+  }
+  return true;
+}
+
+template <>
+bool idUsage::isValid<OpTypeRuntimeArray>(const spv_instruction_t *inst,
+                                          const spv_opcode_desc) {
+  auto elementTypeIndex = 2;
+  auto elementType = find(inst->words[elementTypeIndex]);
+  spvCheck(!found(elementType), DIAG(elementTypeIndex)
+                                    << "OpTypeRuntimeArray Element Type <id> '"
+                                    << inst->words[elementTypeIndex]
+                                    << "' is not defined.";
+           return false);
+  spvCheck(!spvOpcodeIsType(elementType->second.opcode),
+           DIAG(elementTypeIndex) << "OpTypeRuntimeArray Element Type <id> '"
+                                  << inst->words[elementTypeIndex]
+                                  << "' is not a type.";
+           return false);
+  return true;
+}
+
+template <>
+bool idUsage::isValid<OpTypeStruct>(const spv_instruction_t *inst,
+                                    const spv_opcode_desc) {
+  for (uint64_t memberTypeIndex = 2; memberTypeIndex < inst->wordCount;
+       ++memberTypeIndex) {
+    auto memberType = find(inst->words[memberTypeIndex]);
+    spvCheck(!found(memberType), DIAG(memberTypeIndex)
+                                     << "OpTypeStruct Member Type <id> '"
+                                     << inst->words[memberTypeIndex]
+                                     << "' is not defined.";
+             return false);
+    spvCheck(!spvOpcodeIsType(memberType->second.opcode),
+             DIAG(memberTypeIndex) << "OpTypeStruct Member Type <id> '"
+                                   << inst->words[memberTypeIndex]
+                                   << "' is not a type.";
+             return false);
+  }
+  return true;
+}
+
+template <>
+bool idUsage::isValid<OpTypePointer>(const spv_instruction_t *inst,
+                                     const spv_opcode_desc) {
+  auto typeIndex = 3;
+  auto type = find(inst->words[typeIndex]);
+  spvCheck(!found(type), DIAG(typeIndex) << "OpTypePointer Type <id> '"
+                                         << inst->words[typeIndex]
+                                         << "' is not defined.";
+           return false);
+  spvCheck(!spvOpcodeIsType(type->second.opcode),
+           DIAG(typeIndex) << "OpTypePointer Type <id> '"
+                           << inst->words[typeIndex] << "' is not a type.";
+           return false);
+  return true;
+}
+
+template <>
+bool idUsage::isValid<OpTypeFunction>(const spv_instruction_t *inst,
+                                      const spv_opcode_desc) {
+  auto returnTypeIndex = 2;
+  auto returnType = find(inst->words[returnTypeIndex]);
+  spvCheck(!found(returnType), DIAG(returnTypeIndex)
+                                   << "OpTypeFunction Return Type <id> '"
+                                   << inst->words[returnTypeIndex]
+                                   << "' is not defined";
+           return false);
+  spvCheck(!spvOpcodeIsType(returnType->second.opcode),
+           DIAG(returnTypeIndex) << "OpTypeFunction Return Type <id> '"
+                                 << inst->words[returnTypeIndex]
+                                 << "' is not a type.";
+           return false);
+  for (uint64_t paramTypeIndex = 3; paramTypeIndex < inst->wordCount;
+       ++paramTypeIndex) {
+    auto paramType = find(inst->words[paramTypeIndex]);
+    spvCheck(!found(paramType), DIAG(paramTypeIndex)
+                                    << "OpTypeFunction Parameter Type <id> '"
+                                    << inst->words[paramTypeIndex]
+                                    << "' is not defined.";
+             return false);
+    spvCheck(!spvOpcodeIsType(paramType->second.opcode),
+             DIAG(paramTypeIndex) << "OpTypeFunction Parameter Type <id> '"
+                                  << inst->words[paramTypeIndex]
+                                  << "' is not a type.";
+             return false);
+  }
+  return true;
+}
+
+template <>
+bool idUsage::isValid<OpTypePipe>(const spv_instruction_t *inst,
+                                  const spv_opcode_desc) {
+  auto typeIndex = 2;
+  auto type = find(inst->words[typeIndex]);
+  spvCheck(!found(type), DIAG(typeIndex) << "OpTypePipe Type <id> '"
+                                         << inst->words[typeIndex]
+                                         << "' is not defined.";
+           return false);
+  spvCheck(!spvOpcodeIsType(type->second.opcode),
+           DIAG(typeIndex) << "OpTypePipe Type <id> '" << inst->words[typeIndex]
+                           << "' is not a type.";
+           return false);
+  return true;
+}
+
+template <>
+bool idUsage::isValid<OpConstantTrue>(const spv_instruction_t *inst,
+                                      const spv_opcode_desc) {
+  auto resultTypeIndex = 1;
+  auto resultType = find(inst->words[resultTypeIndex]);
+  spvCheck(!found(resultType), DIAG(resultTypeIndex)
+                                   << "OpConstantTrue Result Type <id> '"
+                                   << inst->words[resultTypeIndex]
+                                   << "' is not defined.";
+           return false);
+  spvCheck(OpTypeBool != resultType->second.opcode,
+           DIAG(resultTypeIndex) << "OpConstantTrue Result Type <id> '"
+                                 << inst->words[resultTypeIndex]
+                                 << "' is not a boolean type.";
+           return false);
+  return true;
+}
+
+template <>
+bool idUsage::isValid<OpConstantFalse>(const spv_instruction_t *inst,
+                                       const spv_opcode_desc) {
+  auto resultTypeIndex = 1;
+  auto resultType = find(inst->words[resultTypeIndex]);
+  spvCheck(!found(resultType), DIAG(resultTypeIndex)
+                                   << "OpConstantFalse Result Type <id> '"
+                                   << inst->words[resultTypeIndex]
+                                   << "' is not defined.";
+           return false);
+  spvCheck(OpTypeBool != resultType->second.opcode,
+           DIAG(resultTypeIndex) << "OpConstantFalse Result Type <id> '"
+                                 << inst->words[resultTypeIndex]
+                                 << "' is not a boolean type.";
+           return false);
+  return true;
+}
+
+template <>
+bool idUsage::isValid<OpConstant>(const spv_instruction_t *inst,
+                                  const spv_opcode_desc) {
+  auto resultTypeIndex = 1;
+  auto resultType = find(inst->words[resultTypeIndex]);
+  spvCheck(!found(resultType), DIAG(resultTypeIndex)
+                                   << "OpConstant Result Type <id> '"
+                                   << inst->words[resultTypeIndex]
+                                   << "' is not defined.";
+           return false);
+  spvCheck(!spvOpcodeIsScalarType(resultType->second.opcode),
+           DIAG(resultTypeIndex)
+               << "OpConstant Result Type <id> '"
+               << inst->words[resultTypeIndex]
+               << "' is not a scalar integer or floating point type.";
+           return false);
+  return true;
+}
+
+template <>
+bool idUsage::isValid<OpConstantComposite>(const spv_instruction_t *inst,
+                                           const spv_opcode_desc) {
+  auto resultTypeIndex = 1;
+  auto resultType = find(inst->words[resultTypeIndex]);
+  spvCheck(!found(resultType), DIAG(resultTypeIndex)
+                                   << "OpConstantComposite Result Type <id> '"
+                                   << inst->words[resultTypeIndex]
+                                   << "' is not defined.";
+           return false);
+  spvCheck(!spvOpcodeIsComposite(resultType->second.opcode),
+           DIAG(resultTypeIndex) << "OpConstantComposite Result Type <id> '"
+                                 << inst->words[resultTypeIndex]
+                                 << "' is not a composite type.";
+           return false);
+
+  uint32_t constituentCount = inst->wordCount - 3;
+  switch (resultType->second.opcode) {
+    case OpTypeVector: {
+      auto componentCount = resultType->second.inst->words[3];
+      spvCheck(
+          componentCount != constituentCount,
+          // TODO: Output ID's on diagnostic
+          DIAG(inst->wordCount - 1)
+              << "OpConstantComposite Constituent <id> count does not match "
+                 "Result Type <id> '" << resultType->second.id
+              << "'s vector component count.";
+          return false);
+      auto componentType = find(resultType->second.inst->words[2]);
+      spvCheck(!found(componentType), assert(0 && "Unreachable!"));
+      for (uint64_t constituentIndex = 3; constituentIndex < inst->wordCount;
+           constituentIndex++) {
+        auto constituent = find(inst->words[constituentIndex]);
+        spvCheck(!found(constituent), assert(0 && "Unreachable!"));
+        spvCheck(!spvOpcodeIsConstant(constituent->second.opcode),
+                 DIAG(constituentIndex)
+                     << "OpConstantComposite Constituent <id> '"
+                     << inst->words[constituentIndex] << "' is not a constant.";
+                 return false);
+        auto constituentResultType = find(constituent->second.inst->words[1]);
+        spvCheck(!found(constituentResultType), assert(0 && "Unreachable!"));
+        spvCheck(componentType->second.opcode !=
+                     constituentResultType->second.opcode,
+                 DIAG(constituentIndex)
+                     << "OpConstantComposite Constituent <id> '"
+                     << inst->words[constituentIndex]
+                     << "'s type does not match Result Type <id> '"
+                     << resultType->second.id << "'s vector element type.";
+                 return false);
+      }
+    } break;
+    case OpTypeMatrix: {
+      auto columnCount = resultType->second.inst->words[3];
+      spvCheck(
+          columnCount != constituentCount,
+          // TODO: Output ID's on diagnostic
+          DIAG(inst->wordCount - 1)
+              << "OpConstantComposite Constituent <id> count does not match "
+                 "Result Type <id> '" << resultType->second.id
+              << "'s matrix column count.";
+          return false);
+
+      auto columnType = find(resultType->second.inst->words[2]);
+      spvCheck(!found(columnType), assert(0 && "Unreachable!"));
+      auto componentCount = columnType->second.inst->words[3];
+      auto componentType = find(columnType->second.inst->words[2]);
+      spvCheck(!found(componentType), assert(0 && "Unreachable!"));
+
+      for (uint64_t constituentIndex = 3; constituentIndex < inst->wordCount;
+           constituentIndex++) {
+        auto constituent = find(inst->words[constituentIndex]);
+        spvCheck(!found(constituent),
+                 DIAG(constituentIndex)
+                     << "OpConstantComposite Constituent <id> '"
+                     << inst->words[constituentIndex] << "' is not defined.";
+                 return false);
+        spvCheck(OpConstantComposite != constituent->second.opcode,
+                 DIAG(constituentIndex)
+                     << "OpConstantComposite Constituent <id> '"
+                     << inst->words[constituentIndex]
+                     << "' is not a constant composite.";
+                 return false);
+        auto vector = find(constituent->second.inst->words[1]);
+        spvCheck(!found(vector), assert(0 && "Unreachable!"));
+        spvCheck(columnType->second.opcode != vector->second.opcode,
+                 DIAG(constituentIndex)
+                     << "OpConstantComposite Constituent <id> '"
+                     << inst->words[constituentIndex]
+                     << "' type does not match Result Type <id> '"
+                     << resultType->second.id << "'s matrix column type.";
+                 return false);
+        auto vectorComponentType = find(vector->second.inst->words[2]);
+        spvCheck(!found(vectorComponentType), assert(0 && "Unreachable!"));
+        spvCheck(!spvOpcodeAreTypesEqual(componentType->second.inst,
+                                         vectorComponentType->second.inst),
+                 DIAG(constituentIndex)
+                     << "OpConstantComposite Constituent <id> '"
+                     << inst->words[constituentIndex]
+                     << "' component type does not match Result Type <id> '"
+                     << resultType->second.id
+                     << "'s matrix column component type.";
+                 return false);
+        spvCheck(
+            componentCount != vector->second.inst->words[3],
+            DIAG(constituentIndex)
+                << "OpConstantComposite Constituent <id> '"
+                << inst->words[constituentIndex]
+                << "' vector component count does not match Result Type <id> '"
+                << resultType->second.id << "'s vector component count.";
+            return false);
+      }
+    } break;
+    case OpTypeArray: {
+      auto elementType = find(resultType->second.inst->words[2]);
+      spvCheck(!found(elementType), assert(0 && "Unreachable!"));
+      auto length = find(resultType->second.inst->words[3]);
+      spvCheck(!found(length), assert(0 && "Unreachable!"));
+      spvCheck(length->second.inst->words[3] != constituentCount,
+               DIAG(inst->wordCount - 1)
+                   << "OpConstantComposite Constituent count does not match "
+                      "Result Type <id> '" << resultType->second.id
+                   << "'s array length.";
+               return false);
+      for (uint64_t constituentIndex = 3; constituentIndex < inst->wordCount;
+           constituentIndex++) {
+        auto constituent = find(inst->words[constituentIndex]);
+        spvCheck(!found(constituent),
+                 DIAG(constituentIndex)
+                     << "OpConstantComposite Constituent <id> '"
+                     << inst->words[constituentIndex] << "' is not defined.";
+                 return false);
+        spvCheck(!spvOpcodeIsConstant(constituent->second.opcode),
+                 DIAG(constituentIndex)
+                     << "OpConstantComposite Constituent <id> '"
+                     << inst->words[constituentIndex] << "' is not a constant.";
+                 return false);
+        auto constituentType = find(constituent->second.inst->words[1]);
+        spvCheck(!found(constituentType), assert(0 && "Unreachable!"));
+        spvCheck(!spvOpcodeAreTypesEqual(elementType->second.inst,
+                                         constituentType->second.inst),
+                 DIAG(constituentIndex)
+                     << "OpConstantComposite Constituent <id> '"
+                     << inst->words[constituentIndex]
+                     << "'s type does not match Result Type <id> '"
+                     << resultType->second.id << "'s array element type.";
+                 return false);
+      }
+    } break;
+    case OpTypeStruct: {
+      uint32_t memberCount = resultType->second.inst->wordCount - 2;
+      spvCheck(memberCount != constituentCount,
+               DIAG(resultTypeIndex)
+                   << "OpConstantComposite Constituent <id> '"
+                   << inst->words[resultTypeIndex]
+                   << "' count does not match Result Type <id> '"
+                   << resultType->second.id << "'s struct member count.";
+               return false);
+      for (uint32_t constituentIndex = 3, memberIndex = 2;
+           constituentIndex < inst->wordCount;
+           constituentIndex++, memberIndex++) {
+        auto constituent = find(inst->words[constituentIndex]);
+        spvCheck(!found(constituent),
+                 DIAG(constituentIndex)
+                     << "OpConstantComposite Constituent <id> '"
+                     << inst->words[constituentIndex] << "' is not define.";
+                 return false);
+        spvCheck(!spvOpcodeIsConstant(constituent->second.opcode),
+                 DIAG(constituentIndex)
+                     << "OpConstantComposite Constituent <id> '"
+                     << inst->words[constituentIndex] << "' is not a constant.";
+                 return false);
+        auto constituentType = find(constituent->second.inst->words[1]);
+        spvCheck(!found(constituentType), assert(0 && "Unreachable!"));
+
+        auto memberType = find(resultType->second.inst->words[memberIndex]);
+        spvCheck(!found(memberType), assert(0 && "Unreachable!"));
+        spvCheck(!spvOpcodeAreTypesEqual(memberType->second.inst,
+                                         constituentType->second.inst),
+                 DIAG(constituentIndex)
+                     << "OpConstantComposite Constituent <id> '"
+                     << inst->words[constituentIndex]
+                     << "' type does not match the Result Type <id> '"
+                     << resultType->second.id << "'s member type.";
+                 return false);
+      }
+    } break;
+    default: { assert(0 && "Unreachable!"); } break;
+  }
+  return true;
+}
+
+template <>
+bool idUsage::isValid<OpConstantSampler>(const spv_instruction_t *inst,
+                                         const spv_opcode_desc) {
+  auto resultTypeIndex = 1;
+  auto resultType = find(inst->words[resultTypeIndex]);
+  spvCheck(!found(resultType), DIAG(resultTypeIndex)
+                                   << "OpConstantSampler Result Type <id> '"
+                                   << inst->words[resultTypeIndex]
+                                   << "' is not defined.";
+           return false);
+  spvCheck(OpTypeSampler != resultType->second.opcode,
+           DIAG(resultTypeIndex) << "OpConstantSampler Result Type <id> '"
+                                 << inst->words[resultTypeIndex]
+                                 << "' is not a sampler type.";
+           return false);
+  return true;
+}
+
+template <>
+bool idUsage::isValid<OpConstantNull>(const spv_instruction_t *inst,
+                                      const spv_opcode_desc) {
+  auto resultTypeIndex = 1;
+  auto resultType = find(inst->words[resultTypeIndex]);
+  spvCheck(!found(resultType), DIAG(resultTypeIndex)
+                                   << "OpConstantNull Result Type <id> '"
+                                   << inst->words[resultTypeIndex]
+                                   << "' is not defined.";
+           return false);
+  switch (resultType->second.inst->opcode) {
+    default: {
+      spvCheck(!spvOpcodeIsBasicTypeNullable(resultType->second.inst->opcode),
+               DIAG(resultTypeIndex) << "OpConstantNull Result Type <id> '"
+                                     << inst->words[resultTypeIndex]
+                                     << "' can not be null.";
+               return false);
+    } break;
+    case OpTypeVector: {
+      auto type = find(resultType->second.inst->words[2]);
+      spvCheck(!found(type), assert(0 && "Unreachable!"));
+      spvCheck(!spvOpcodeIsBasicTypeNullable(type->second.inst->opcode),
+               DIAG(resultTypeIndex)
+                   << "OpConstantNull Result Type <id> '"
+                   << inst->words[resultTypeIndex]
+                   << "'s vector component type can not be null.";
+               return false);
+    } break;
+    case OpTypeArray: {
+      auto type = find(resultType->second.inst->words[2]);
+      spvCheck(!found(type), assert(0 && "Unreachable!"));
+      spvCheck(!spvOpcodeIsBasicTypeNullable(type->second.inst->opcode),
+               DIAG(resultTypeIndex)
+                   << "OpConstantNull Result Type <id> '"
+                   << inst->words[resultTypeIndex]
+                   << "'s array element type can not be null.";
+               return false);
+    } break;
+    case OpTypeMatrix: {
+      auto columnType = find(resultType->second.inst->words[2]);
+      spvCheck(!found(columnType), assert(0 && "Unreachable!"));
+      auto type = find(columnType->second.inst->words[2]);
+      spvCheck(!found(type), assert(0 && "Unreachable!"));
+      spvCheck(!spvOpcodeIsBasicTypeNullable(type->second.inst->opcode),
+               DIAG(resultTypeIndex)
+                   << "OpConstantNull Result Type <id> '"
+                   << inst->words[resultTypeIndex]
+                   << "'s matrix component type cna not be null.";
+               return false);
+    } break;
+    case OpTypeStruct: {
+      for (uint64_t elementIndex = 2;
+           elementIndex < resultType->second.inst->wordCount; ++elementIndex) {
+        auto element = find(resultType->second.inst->words[elementIndex]);
+        spvCheck(!found(element), assert(0 && "Unreachable!"));
+        spvCheck(!spvOpcodeIsBasicTypeNullable(element->second.inst->opcode),
+                 DIAG(resultTypeIndex)
+                     << "OpConstantNull Result Type <id> '"
+                     << inst->words[resultTypeIndex]
+                     << "'s struct element type can not be null.";
+                 return false);
+      }
+    } break;
+  }
+  return true;
+}
+
+template <>
+bool idUsage::isValid<OpSpecConstantTrue>(const spv_instruction_t *inst,
+                                          const spv_opcode_desc) {
+  auto resultTypeIndex = 1;
+  auto resultType = find(inst->words[resultTypeIndex]);
+  spvCheck(!found(resultType), DIAG(resultTypeIndex)
+                                   << "OpSpecConstantTrue Result Type <id> '"
+                                   << inst->words[resultTypeIndex]
+                                   << "' is not defined.";
+           return false);
+  spvCheck(OpTypeBool != resultType->second.opcode,
+           DIAG(resultTypeIndex) << "OpSpecConstantTrue Result Type <id> '"
+                                 << inst->words[resultTypeIndex]
+                                 << "' is not a boolean type.";
+           return false);
+  return true;
+}
+
+template <>
+bool idUsage::isValid<OpSpecConstantFalse>(const spv_instruction_t *inst,
+                                           const spv_opcode_desc) {
+  auto resultTypeIndex = 1;
+  auto resultType = find(inst->words[resultTypeIndex]);
+  spvCheck(!found(resultType), DIAG(resultTypeIndex)
+                                   << "OpSpecConstantFalse Result Type <id> '"
+                                   << inst->words[resultTypeIndex]
+                                   << "' is not defined.";
+           return false);
+  spvCheck(OpTypeBool != resultType->second.opcode,
+           DIAG(resultTypeIndex) << "OpSpecConstantFalse Result Type <id> '"
+                                 << inst->words[resultTypeIndex]
+                                 << "' is not a boolean type.";
+           return false);
+  return true;
+}
+
+template <>
+bool idUsage::isValid<OpSpecConstant>(const spv_instruction_t *inst,
+                                      const spv_opcode_desc) {
+  auto resultTypeIndex = 1;
+  auto resultType = find(inst->words[resultTypeIndex]);
+  spvCheck(!found(resultType), DIAG(resultTypeIndex)
+                                   << "OpSpecConstant Result Type <id> '"
+                                   << inst->words[resultTypeIndex]
+                                   << "' is not defined.";
+           return false);
+  spvCheck(!spvOpcodeIsScalarType(resultType->second.opcode),
+           DIAG(resultTypeIndex) << "OpSpecConstant Result Type <id> '"
+                                 << inst->words[resultTypeIndex]
+                                 << "' is not a scalar type.";
+           return false);
+  return true;
+}
+
+#if 0
+template <>
+bool idUsage::isValid<OpSpecConstantComposite>(
+    const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {}
+#endif
+
+#if 0
+template <>
+bool idUsage::isValid<OpSpecConstantOp>(const spv_instruction_t *inst) {}
+#endif
+
+template <>
+bool idUsage::isValid<OpVariable>(const spv_instruction_t *inst,
+                                  const spv_opcode_desc opcodeEntry) {
+  auto resultTypeIndex = 1;
+  auto resultType = find(inst->words[resultTypeIndex]);
+  spvCheck(!found(resultType), DIAG(resultTypeIndex)
+                                   << "OpVariable Result Type <id> '"
+                                   << inst->words[resultTypeIndex]
+                                   << "' is not defined.";
+           return false);
+  spvCheck(OpTypePointer != resultType->second.opcode,
+           DIAG(resultTypeIndex) << "OpVariable Result Type <id> '"
+                                 << inst->words[resultTypeIndex]
+                                 << "' is not a pointer type.";
+           return false);
+  if (opcodeEntry->wordCount < inst->wordCount) {
+    auto initialiserIndex = 4;
+    auto initialiser = find(inst->words[initialiserIndex]);
+    spvCheck(!found(initialiser), DIAG(initialiserIndex)
+                                      << "OpVariable Initializer <id> '"
+                                      << inst->words[initialiserIndex]
+                                      << "' is not defined.";
+             return false);
+    spvCheck(!spvOpcodeIsConstant(initialiser->second.opcode),
+             DIAG(initialiserIndex) << "OpVariable Initializer <id> '"
+                                    << inst->words[initialiserIndex]
+                                    << "' is not a constant.";
+             return false);
+  }
+  return true;
+}
+
+template <>
+bool idUsage::isValid<OpLoad>(const spv_instruction_t *inst,
+                              const spv_opcode_desc) {
+  auto resultTypeIndex = 1;
+  auto resultType = find(inst->words[resultTypeIndex]);
+  spvCheck(!found(resultType), DIAG(resultTypeIndex)
+                                   << "OpLoad Result Type <id> '"
+                                   << inst->words[resultTypeIndex]
+                                   << "' is not defind.";
+           return false);
+  auto pointerIndex = 3;
+  auto pointer = find(inst->words[pointerIndex]);
+  spvCheck(!found(pointer), DIAG(pointerIndex) << "OpLoad Pointer <id> '"
+                                               << inst->words[pointerIndex]
+                                               << "' is not defined.";
+           return false);
+  spvCheck(!spvOpcodeIsPointer(pointer->second.opcode),
+           DIAG(pointerIndex) << "OpLoad Pointer <id> '"
+                              << inst->words[pointerIndex]
+                              << "' is not a pointer.";
+           return false);
+  auto type = find(pointer->second.inst->words[1]);
+  spvCheck(!found(type), assert(0 && "Unreachable!"));
+  spvCheck(resultType != type, DIAG(resultTypeIndex)
+                                   << "OpLoad Result Type <id> '"
+                                   << inst->words[resultTypeIndex]
+                                   << " does not match Pointer <id> '"
+                                   << pointer->second.id << "'s type.";
+           return false);
+  return true;
+}
+
+template <>
+bool idUsage::isValid<OpStore>(const spv_instruction_t *inst,
+                               const spv_opcode_desc) {
+  auto pointerIndex = 1;
+  auto pointer = find(inst->words[pointerIndex]);
+  spvCheck(!found(pointer), DIAG(pointerIndex) << "OpStore Pointer <id> '"
+                                               << inst->words[pointerIndex]
+                                               << "' is not defined.";
+           return false);
+  spvCheck(!spvOpcodeIsPointer(pointer->second.opcode),
+           DIAG(pointerIndex) << "OpStore Pointer <id> '"
+                              << inst->words[pointerIndex]
+                              << "' is not a pointer.";
+           return false);
+  auto pointerType = find(pointer->second.inst->words[1]);
+  spvCheck(!found(pointerType), assert(0 && "Unreachable!"));
+  auto type = find(pointerType->second.inst->words[3]);
+  spvCheck(!found(type), assert(0 && "Unreachable!"));
+  spvCheck(OpTypeVoid == type->second.opcode, DIAG(pointerIndex)
+                                                  << "OpStore Pointer <id> '"
+                                                  << inst->words[pointerIndex]
+                                                  << "'s type is void.";
+           return false);
+
+  auto objectIndex = 2;
+  auto object = find(inst->words[objectIndex]);
+  spvCheck(!found(object), DIAG(objectIndex) << "OpStore Object <id> '"
+                                             << inst->words[objectIndex]
+                                             << "' is not defined.";
+           return false);
+  spvCheck(!spvOpcodeIsObject(object->second.opcode),
+           DIAG(objectIndex) << "OpStore Object <id> '"
+                             << inst->words[objectIndex]
+                             << "' in not an object.";
+           return false);
+  auto objectType = find(object->second.inst->words[1]);
+  spvCheck(!found(objectType), assert(0 && "Unreachable!"));
+  spvCheck(OpTypeVoid == objectType->second.opcode,
+           DIAG(objectIndex) << "OpStore Object <id> '"
+                             << inst->words[objectIndex] << "'s type is void.";
+           return false);
+
+  spvCheck(!spvOpcodeAreTypesEqual(type->second.inst, objectType->second.inst),
+           DIAG(pointerIndex) << "OpStore Pointer <id> '"
+                              << inst->words[pointerIndex]
+                              << "'s type does not match Object <id> '"
+                              << objectType->second.id << "'s type.";
+           return false);
+  return true;
+}
+
+template <>
+bool idUsage::isValid<OpCopyMemory>(const spv_instruction_t *inst,
+                                    const spv_opcode_desc) {
+  auto targetIndex = 1;
+  auto target = find(inst->words[targetIndex]);
+  spvCheck(!found(target), DIAG(targetIndex) << "OpCopyMemory Target <id> '"
+                                             << inst->words[targetIndex]
+                                             << "' is not defined.";
+           return false);
+  auto sourceIndex = 2;
+  auto source = find(inst->words[sourceIndex]);
+  spvCheck(!found(source), DIAG(targetIndex) << "OpCopyMemory Source <id> '"
+                                             << inst->words[targetIndex]
+                                             << "' is not defined.";
+           return false);
+  auto targetPointerType = find(target->second.inst->words[1]);
+  spvCheck(!found(targetPointerType), assert(0 && "Unreachable!"));
+  auto targetType = find(targetPointerType->second.inst->words[3]);
+  spvCheck(!found(targetType), assert(0 && "Unreachable!"));
+  auto sourcePointerType = find(source->second.inst->words[1]);
+  spvCheck(!found(sourcePointerType), assert(0 && "Unreachable!"));
+  auto sourceType = find(sourcePointerType->second.inst->words[3]);
+  spvCheck(!found(sourceType), assert(0 && "Unreachable!"));
+  spvCheck(
+      !spvOpcodeAreTypesEqual(targetType->second.inst, sourceType->second.inst),
+      DIAG(sourceIndex) << "OpCopyMemory Target <id> '"
+                        << inst->words[sourceIndex]
+                        << "'s type does not match Source <id> '"
+                        << sourceType->second.id << "'s type.";
+      return false);
+  return true;
+}
+
+template <>
+bool idUsage::isValid<OpCopyMemorySized>(const spv_instruction_t *inst,
+                                         const spv_opcode_desc) {
+  auto targetIndex = 1;
+  auto target = find(inst->words[targetIndex]);
+  spvCheck(!found(target),
+           DIAG(targetIndex) << "OpCopyMemorySized Target <id> '"
+                             << inst->words[targetIndex] << "' is not defined.";
+           return false);
+  auto sourceIndex = 2;
+  auto source = find(inst->words[sourceIndex]);
+  spvCheck(!found(source),
+           DIAG(sourceIndex) << "OpCopyMemorySized Source <id> '"
+                             << inst->words[sourceIndex] << "' is not defined.";
+           return false);
+  auto sizeIndex = 3;
+  auto size = find(inst->words[sizeIndex]);
+  spvCheck(!found(size), DIAG(sizeIndex) << "OpCopyMemorySized, Size <id> '"
+                                         << inst->words[sizeIndex]
+                                         << "' is not defined.";
+           return false);
+  auto targetPointerType = find(target->second.inst->words[1]);
+  spvCheck(!found(targetPointerType), assert(0 && "Unreachable!"));
+  spvCheck(OpTypePointer != targetPointerType->second.opcode,
+           DIAG(targetIndex) << "OpCopyMemorySized Target <id> '"
+                             << inst->words[targetIndex]
+                             << "' is not a pointer.";
+           return false);
+  auto sourcePointerType = find(source->second.inst->words[1]);
+  spvCheck(!found(sourcePointerType), assert(0 && "Unreachable!"));
+  spvCheck(OpTypePointer != sourcePointerType->second.opcode,
+           DIAG(sourceIndex) << "OpCopyMemorySized Source <id> '"
+                             << inst->words[sourceIndex]
+                             << "' is not a pointer.";
+           return false);
+  switch (size->second.opcode) {
+    // TODO: The following opcode's are assumed to be valid, refer to the
+    // following bug https://cvs.khronos.org/bugzilla/show_bug.cgi?id=13871 for
+    // clarification
+    case OpConstant:
+    case OpSpecConstant: {
+      auto sizeType = find(size->second.inst->words[1]);
+      spvCheck(!found(sizeType), assert(0 && "Unreachable!"));
+      spvCheck(OpTypeInt != sizeType->second.opcode,
+               DIAG(sizeIndex) << "OpCopyMemorySized Size <id> '"
+                               << inst->words[sizeIndex]
+                               << "'s type is not an integer type.";
+               return false);
+    } break;
+    case OpVariable: {
+      auto pointerType = find(size->second.inst->words[1]);
+      spvCheck(!found(pointerType), assert(0 && "Unreachable!"));
+      auto sizeType = find(pointerType->second.inst->words[1]);
+      spvCheck(!found(sizeType), assert(0 && "Unreachable!"));
+      spvCheck(OpTypeInt != sizeType->second.opcode,
+               DIAG(sizeIndex) << "OpCopyMemorySized Size <id> '"
+                               << inst->words[sizeIndex]
+                               << "'s variable type is not an integer type.";
+               return false);
+    } break;
+    default:
+      DIAG(sizeIndex) << "OpCopyMemorySized Size <id> '"
+                      << inst->words[sizeIndex]
+                      << "' is not a constant or variable.";
+      return false;
+  }
+  // TODO: Check that consant is a least size 1, see the same bug as above for
+  // clarification?
+  return true;
+}
+
+#if 0
+template <>
+bool idUsage::isValid<OpAccessChain>(const spv_instruction_t *inst,
+                                     const spv_opcode_desc opcodeEntry) {}
+#endif
+
+#if 0
+template <>
+bool idUsage::isValid<OpInBoundsAccessChain>(
+    const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {}
+#endif
+
+#if 0
+template <>
+bool idUsage::isValid<OpArrayLength>(const spv_instruction_t *inst,
+                                     const spv_opcode_desc opcodeEntry) {}
+#endif
+
+#if 0
+template <>
+bool idUsage::isValid<OpImagePointer>(const spv_instruction_t *inst,
+                                      const spv_opcode_desc opcodeEntry) {}
+#endif
+
+#if 0
+template <>
+bool idUsage::isValid<OpGenericPtrMemSemantics>(
+    const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {}
+#endif
+
+template <>
+bool idUsage::isValid<OpFunction>(const spv_instruction_t *inst,
+                                  const spv_opcode_desc) {
+  auto resultTypeIndex = 1;
+  auto resultType = find(inst->words[resultTypeIndex]);
+  spvCheck(!found(resultType), DIAG(resultTypeIndex)
+                                   << "OpFunction Result Type <id> '"
+                                   << inst->words[resultTypeIndex]
+                                   << "' is not defined.";
+           return false);
+  auto functionTypeIndex = 4;
+  auto functionType = find(inst->words[functionTypeIndex]);
+  spvCheck(!found(functionType), DIAG(functionTypeIndex)
+                                     << "OpFunction Function Type <id> '"
+                                     << inst->words[functionTypeIndex]
+                                     << "' is not defined.";
+           return false);
+  spvCheck(OpTypeFunction != functionType->second.opcode,
+           DIAG(functionTypeIndex) << "OpFunction Function Type <id> '"
+                                   << inst->words[functionTypeIndex]
+                                   << "' is not a function type.";
+           return false);
+  auto returnType = find(functionType->second.inst->words[2]);
+  spvCheck(!found(returnType), assert(0 && "Unreachable!"));
+  spvCheck(returnType != resultType,
+           DIAG(resultTypeIndex) << "OpFunction Result Type <id> '"
+                                 << inst->words[resultTypeIndex]
+                                 << "' does not match the Function Type <id> '"
+                                 << resultType->second.id << "'s return type.";
+           return false);
+  return true;
+}
+
+template <>
+bool idUsage::isValid<OpFunctionParameter>(const spv_instruction_t *inst,
+                                           const spv_opcode_desc) {
+  auto resultTypeIndex = 1;
+  auto resultType = find(inst->words[resultTypeIndex]);
+  spvCheck(!found(resultType), DIAG(resultTypeIndex)
+                                   << "OpFunctionParameter Result Type <id> '"
+                                   << inst->words[resultTypeIndex]
+                                   << "' is not defined.";
+           return false);
+  auto function = inst - 1;
+  // NOTE: Find OpFunction & ensure OpFunctionParameter is not out of place.
+  uint64_t paramIndex = 0;
+  while (firstInst != function) {
+    spvCheck(OpFunction != function->opcode &&
+                 OpFunctionParameter != function->opcode,
+             DIAG(0) << "OpFunctionParameter is not preceded by OpFunction or "
+                        "OpFunctionParameter sequence.";
+             return false);
+    if (OpFunction == function->opcode) {
+      break;
+    } else {
+      paramIndex++;
+    }
+  }
+  auto functionType = find(function->words[4]);
+  spvCheck(!found(functionType), assert(0 && "Unreachable!"));
+  auto paramType = find(functionType->second.inst->words[paramIndex + 3]);
+  spvCheck(!found(paramType), assert(0 && "Unreachable!"));
+  spvCheck(
+      !spvOpcodeAreTypesEqual(resultType->second.inst, paramType->second.inst),
+      DIAG(resultTypeIndex) << "OpFunctionParameter Result Type <id> '"
+                            << inst->words[resultTypeIndex]
+                            << "' does not match the OpTypeFunction parameter "
+                               "type of the same index.";
+      return false);
+  return true;
+}
+
+template <>
+bool idUsage::isValid<OpFunctionCall>(const spv_instruction_t *inst,
+                                      const spv_opcode_desc) {
+  auto resultTypeIndex = 1;
+  auto resultType = find(inst->words[resultTypeIndex]);
+  spvCheck(!found(resultType), DIAG(resultTypeIndex)
+                                   << "OpFunctionCall Result Type <id> '"
+                                   << inst->words[resultTypeIndex]
+                                   << "' is not defined.";
+           return false);
+  auto functionIndex = 3;
+  auto function = find(inst->words[functionIndex]);
+  spvCheck(!found(function), DIAG(functionIndex)
+                                 << "OpFunctionCall Function <id> '"
+                                 << inst->words[functionIndex]
+                                 << "' is not defined.";
+           return false);
+  spvCheck(OpFunction != function->second.opcode,
+           DIAG(functionIndex) << "OpFunctionCall Function <id> '"
+                               << inst->words[functionIndex]
+                               << "' is not a function.";
+           return false);
+  auto returnType = find(function->second.inst->words[1]);
+  spvCheck(!found(returnType), assert(0 && "Unreachable!"));
+  spvCheck(
+      !spvOpcodeAreTypesEqual(returnType->second.inst, resultType->second.inst),
+      DIAG(resultTypeIndex)
+          << "OpFunctionCall Result Type <id> '" << inst->words[resultTypeIndex]
+          << "'s type does not match Function <id> '" << returnType->second.id
+          << "'s return type.";
+      return false);
+  auto functionType = find(function->second.inst->words[4]);
+  spvCheck(!found(functionType), assert(0 && "Unreachable!"));
+  auto functionCallArgCount = inst->wordCount - 4;
+  auto functionParamCount = functionType->second.inst->wordCount - 3;
+  spvCheck(
+      functionParamCount != functionCallArgCount,
+      DIAG(inst->wordCount - 1)
+          << "OpFunctionCall Function <id>'s parameter count does not match "
+             "the argument count.";
+      return false);
+  for (uint64_t argumentIndex = 4, paramIndex = 3;
+       argumentIndex < inst->wordCount; argumentIndex++, paramIndex++) {
+    auto argument = find(inst->words[argumentIndex]);
+    spvCheck(!found(argument), DIAG(argumentIndex)
+                                   << "OpFunctionCall Argument <id> '"
+                                   << inst->words[argumentIndex]
+                                   << "' is not defined.";
+             return false);
+    auto argumentType = find(argument->second.inst->words[1]);
+    spvCheck(!found(argumentType), assert(0 && "Unreachable!"));
+    auto parameterType = find(functionType->second.inst->words[paramIndex]);
+    spvCheck(!found(parameterType), assert(0 && "Unreachable!"));
+    spvCheck(!spvOpcodeAreTypesEqual(argumentType->second.inst,
+                                     parameterType->second.inst),
+             DIAG(argumentIndex) << "OpFunctionCall Argument <id> '"
+                                 << inst->words[argumentIndex]
+                                 << "'s type does not match Function <id> '"
+                                 << parameterType->second.id
+                                 << "'s parameter type.";
+             return false);
+  }
+  return true;
+}
+
+#if 0
+template <>
+bool idUsage::isValid<OpSampler>(const spv_instruction_t *inst,
+                                 const spv_opcode_desc opcodeEntry) {}
+#endif
+
+#if 0
+template <>
+bool idUsage::isValid<OpTextureSample>(const spv_instruction_t *inst,
+                                       const spv_opcode_desc opcodeEntry) {
+}
+#endif
+
+#if 0
+template <>
+bool idUsage::isValid<OpTextureSampleDref>(
+    const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {}
+#endif
+
+#if 0
+template <>
+bool idUsage::isValid<OpTextureSampleLod>(
+    const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {}
+#endif
+
+#if 0
+template <>
+bool idUsage::isValid<OpTextureSampleProj>(
+    const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {}
+#endif
+
+#if 0
+template <>
+bool idUsage::isValid<OpTextureSampleGrad>(
+    const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {}
+#endif
+
+#if 0
+template <>
+bool idUsage::isValid<OpTextureSampleOffset>(
+    const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {}
+#endif
+
+#if 0
+template <>
+bool idUsage::isValid<OpTextureSampleProjLod>(
+    const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {}
+#endif
+
+#if 0
+template <>
+bool idUsage::isValid<OpTextureSampleProjGrad>(
+    const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {}
+#endif
+
+#if 0
+template <>
+bool idUsage::isValid<OpTextureSampleLodOffset>(
+    const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {}
+#endif
+
+#if 0
+template <>
+bool idUsage::isValid<OpTextureSampleProjOffset>(
+    const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {}
+#endif
+
+#if 0
+template <>
+bool idUsage::isValid<OpTextureSampleGradOffset>(
+    const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {}
+#endif
+
+#if 0
+template <>
+bool idUsage::isValid<OpTextureSampleProjLodOffset>(
+    const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {}
+#endif
+
+#if 0
+template <>
+bool idUsage::isValid<OpTextureSampleProjGradOffset>(
+    const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {}
+#endif
+
+#if 0
+template <>
+bool idUsage::isValid<OpTextureFetchTexelLod>(const spv_instruction_t *inst) {}
+#endif
+
+#if 0
+template <>
+bool idUsage::isValid<OpTextureFetchTexelOffset>(
+    const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {}
+#endif
+
+#if 0
+template <>
+bool idUsage::isValid<OpTextureFetchSample>(
+    const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {}
+#endif
+
+#if 0
+template <>
+bool idUsage::isValid<OpTextureFetchTexel>(
+    const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {}
+#endif
+
+#if 0
+template <>
+bool idUsage::isValid<OpTextureGather>(const spv_instruction_t *inst,
+                                       const spv_opcode_desc opcodeEntry) {
+}
+#endif
+
+#if 0
+template <>
+bool idUsage::isValid<OpTextureGatherOffset>(
+    const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {}
+#endif
+
+#if 0
+template <>
+bool idUsage::isValid<OpTextureGatherOffsets>(
+    const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {}
+#endif
+
+#if 0
+template <>
+bool idUsage::isValid<OpTextureQuerySizeLod>(
+    const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {}
+#endif
+
+#if 0
+template <>
+bool idUsage::isValid<OpTextureQuerySize>(
+    const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {}
+#endif
+
+#if 0
+template <>
+bool idUsage::isValid<OpTextureQueryLevels>(
+    const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {}
+#endif
+
+#if 0
+template <>
+bool idUsage::isValid<OpTextureQuerySamples>(
+    const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {}
+#endif
+
+#if 0
+template <>
+bool idUsage::isValid<OpConvertUToF>(const spv_instruction_t *inst,
+                                     const spv_opcode_desc opcodeEntry) {}
+#endif
+
+#if 0
+template <>
+bool idUsage::isValid<OpConvertFToS>(const spv_instruction_t *inst,
+                                     const spv_opcode_desc opcodeEntry) {}
+#endif
+
+#if 0
+template <>
+bool idUsage::isValid<OpConvertSToF>(const spv_instruction_t *inst,
+                                     const spv_opcode_desc opcodeEntry) {}
+#endif
+
+#if 0
+template <>
+bool idUsage::isValid<OpConvertUToF>(const spv_instruction_t *inst,
+                                     const spv_opcode_desc opcodeEntry) {}
+#endif
+
+#if 0
+template <>
+bool idUsage::isValid<OpUConvert>(const spv_instruction_t *inst,
+                                  const spv_opcode_desc opcodeEntry) {}
+#endif
+
+#if 0
+template <>
+bool idUsage::isValid<OpSConvert>(const spv_instruction_t *inst,
+                                  const spv_opcode_desc opcodeEntry) {}
+#endif
+
+#if 0
+template <>
+bool idUsage::isValid<OpFConvert>(const spv_instruction_t *inst,
+                                  const spv_opcode_desc opcodeEntry) {}
+#endif
+
+#if 0
+template <>
+bool idUsage::isValid<OpConvertPtrToU>(const spv_instruction_t *inst,
+                                       const spv_opcode_desc opcodeEntry) {
+}
+#endif
+
+#if 0
+template <>
+bool idUsage::isValid<OpConvertUToPtr>(const spv_instruction_t *inst,
+                                       const spv_opcode_desc opcodeEntry) {
+}
+#endif
+
+#if 0
+template <>
+bool idUsage::isValid<OpPtrCastToGeneric>(
+    const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {}
+#endif
+
+#if 0
+template <>
+bool idUsage::isValid<OpGenericCastToPtr>(
+    const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {}
+#endif
+
+#if 0
+template <>
+bool idUsage::isValid<OpBitcast>(const spv_instruction_t *inst,
+                                 const spv_opcode_desc opcodeEntry) {}
+#endif
+
+#if 0
+template <>
+bool idUsage::isValid<OpGenericCastToPtrExplicit>(
+    const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {}
+#endif
+
+#if 0
+template <>
+bool idUsage::isValid<OpSatConvertSToU>(const spv_instruction_t *inst) {}
+#endif
+
+#if 0
+template <>
+bool idUsage::isValid<OpSatConvertUToS>(const spv_instruction_t *inst) {}
+#endif
+
+#if 0
+template <>
+bool idUsage::isValid<OpVectorExtractDynamic>(
+    const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {}
+#endif
+
+#if 0
+template <>
+bool idUsage::isValid<OpVectorInsertDynamic>(
+    const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {}
+#endif
+
+#if 0
+template <>
+bool idUsage::isValid<OpVectorShuffle>(const spv_instruction_t *inst,
+                                       const spv_opcode_desc opcodeEntry) {
+}
+#endif
+
+#if 0
+template <>
+bool idUsage::isValid<OpCompositeConstruct>(
+    const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {}
+#endif
+
+#if 0
+template <>
+bool idUsage::isValid<OpCompositeExtract>(
+    const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {}
+#endif
+
+#if 0
+template <>
+bool idUsage::isValid<OpCompositeInsert>(
+    const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {}
+#endif
+
+#if 0
+template <>
+bool idUsage::isValid<OpCopyObject>(const spv_instruction_t *inst,
+                                    const spv_opcode_desc opcodeEntry) {}
+#endif
+
+#if 0
+template <>
+bool idUsage::isValid<OpTranspose>(const spv_instruction_t *inst,
+                                   const spv_opcode_desc opcodeEntry) {}
+#endif
+
+#if 0
+template <>
+bool idUsage::isValid<OpSNegate>(const spv_instruction_t *inst,
+                                 const spv_opcode_desc opcodeEntry) {}
+#endif
+
+#if 0
+template <>
+bool idUsage::isValid<OpFNegate>(const spv_instruction_t *inst,
+                                 const spv_opcode_desc opcodeEntry) {}
+#endif
+
+#if 0
+template <>
+bool idUsage::isValid<OpNot>(const spv_instruction_t *inst,
+                             const spv_opcode_desc opcodeEntry) {}
+#endif
+
+#if 0
+template <>
+bool idUsage::isValid<OpIAdd>(const spv_instruction_t *inst,
+                              const spv_opcode_desc opcodeEntry) {}
+#endif
+
+#if 0
+template <>
+bool idUsage::isValid<OpFAdd>(const spv_instruction_t *inst,
+                              const spv_opcode_desc opcodeEntry) {}
+#endif
+
+#if 0
+template <>
+bool idUsage::isValid<OpISub>(const spv_instruction_t *inst,
+                              const spv_opcode_desc opcodeEntry) {}
+#endif
+
+#if 0
+template <>
+bool idUsage::isValid<OpFSub>(const spv_instruction_t *inst,
+                              const spv_opcode_desc opcodeEntry) {}
+#endif
+
+#if 0
+template <>
+bool idUsage::isValid<OpIMul>(const spv_instruction_t *inst,
+                              const spv_opcode_desc opcodeEntry) {}
+#endif
+
+#if 0
+template <>
+bool idUsage::isValid<OpFMul>(const spv_instruction_t *inst,
+                              const spv_opcode_desc opcodeEntry) {}
+#endif
+
+#if 0
+template <>
+bool idUsage::isValid<OpUDiv>(const spv_instruction_t *inst,
+                              const spv_opcode_desc opcodeEntry) {}
+#endif
+
+#if 0
+template <>
+bool idUsage::isValid<OpSDiv>(const spv_instruction_t *inst,
+                              const spv_opcode_desc opcodeEntry) {}
+#endif
+
+#if 0
+template <>
+bool idUsage::isValid<OpFDiv>(const spv_instruction_t *inst,
+                              const spv_opcode_desc opcodeEntry) {}
+#endif
+
+#if 0
+template <>
+bool idUsage::isValid<OpUMod>(const spv_instruction_t *inst,
+                              const spv_opcode_desc opcodeEntry) {}
+#endif
+
+#if 0
+template <>
+bool idUsage::isValid<OpSRem>(const spv_instruction_t *inst,
+                              const spv_opcode_desc opcodeEntry) {}
+#endif
+
+#if 0
+template <>
+bool idUsage::isValid<OpSMod>(const spv_instruction_t *inst,
+                              const spv_opcode_desc opcodeEntry) {}
+#endif
+
+#if 0
+template <>
+bool idUsage::isValid<OpFRem>(const spv_instruction_t *inst,
+                              const spv_opcode_desc opcodeEntry) {}
+#endif
+
+#if 0
+template <>
+bool idUsage::isValid<OpFMod>(const spv_instruction_t *inst,
+                              const spv_opcode_desc opcodeEntry) {}
+#endif
+
+#if 0
+template <>
+bool idUsage::isValid<OpVectorTimesScalar>(
+    const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {}
+#endif
+
+#if 0
+template <>
+bool idUsage::isValid<OpMatrixTimesScalar>(
+    const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {}
+#endif
+
+#if 0
+template <>
+bool idUsage::isValid<OpVectorTimesMatrix>(
+    const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {}
+#endif
+
+#if 0
+template <>
+bool idUsage::isValid<OpMatrixTimesVector>(
+    const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {}
+#endif
+
+#if 0
+template <>
+bool idUsage::isValid<OpMatrixTimesMatrix>(
+    const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {}
+#endif
+
+#if 0
+template <>
+bool idUsage::isValid<OpOuterProduct>(const spv_instruction_t *inst,
+                                      const spv_opcode_desc opcodeEntry) {}
+#endif
+
+#if 0
+template <>
+bool idUsage::isValid<OpDot>(const spv_instruction_t *inst,
+                             const spv_opcode_desc opcodeEntry) {}
+#endif
+
+#if 0
+template <>
+bool idUsage::isValid<OpShiftRightLogical>(
+    const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {}
+#endif
+
+#if 0
+template <>
+bool idUsage::isValid<OpShiftRightArithmetic>(
+    const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {}
+#endif
+
+#if 0
+template <>
+bool idUsage::isValid<OpShiftLeftLogical>(
+    const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {}
+#endif
+
+#if 0
+template <>
+bool idUsage::isValid<OpBitwiseOr>(const spv_instruction_t *inst,
+                                   const spv_opcode_desc opcodeEntry) {}
+#endif
+
+#if 0
+template <>
+bool idUsage::isValid<OpBitwiseXor>(const spv_instruction_t *inst,
+                                    const spv_opcode_desc opcodeEntry) {}
+#endif
+
+#if 0
+template <>
+bool idUsage::isValid<OpBitwiseAnd>(const spv_instruction_t *inst,
+                                    const spv_opcode_desc opcodeEntry) {}
+#endif
+
+#if 0
+template <>
+bool idUsage::isValid<OpAny>(const spv_instruction_t *inst,
+                             const spv_opcode_desc opcodeEntry) {}
+#endif
+
+#if 0
+template <>
+bool idUsage::isValid<OpAll>(const spv_instruction_t *inst,
+                             const spv_opcode_desc opcodeEntry) {}
+#endif
+
+#if 0
+template <>
+bool idUsage::isValid<OpIsNan>(const spv_instruction_t *inst,
+                               const spv_opcode_desc opcodeEntry) {}
+#endif
+
+#if 0
+template <>
+bool idUsage::isValid<OpIsInf>(const spv_instruction_t *inst,
+                               const spv_opcode_desc opcodeEntry) {}
+#endif
+
+#if 0
+template <>
+bool idUsage::isValid<OpIsFinite>(const spv_instruction_t *inst,
+                                  const spv_opcode_desc opcodeEntry) {}
+#endif
+
+#if 0
+template <>
+bool idUsage::isValid<OpIsNormal>(const spv_instruction_t *inst,
+                                  const spv_opcode_desc opcodeEntry) {}
+#endif
+
+#if 0
+template <>
+bool idUsage::isValid<OpSignBitSet>(const spv_instruction_t *inst,
+                                    const spv_opcode_desc opcodeEntry) {}
+#endif
+
+#if 0
+template <>
+bool idUsage::isValid<OpLessOrGreater>(const spv_instruction_t *inst,
+                                       const spv_opcode_desc opcodeEntry) {
+}
+#endif
+
+#if 0
+template <>
+bool idUsage::isValid<OpOrdered>(const spv_instruction_t *inst,
+                                 const spv_opcode_desc opcodeEntry) {}
+#endif
+
+#if 0
+template <>
+bool idUsage::isValid<OpUnordered>(const spv_instruction_t *inst,
+                                   const spv_opcode_desc opcodeEntry) {}
+#endif
+
+#if 0
+template <>
+bool idUsage::isValid<OpLogicalOr>(const spv_instruction_t *inst,
+                                   const spv_opcode_desc opcodeEntry) {}
+#endif
+
+#if 0
+template <>
+bool idUsage::isValid<OpLogicalXor>(const spv_instruction_t *inst,
+                                    const spv_opcode_desc opcodeEntry) {}
+#endif
+
+#if 0
+template <>
+bool idUsage::isValid<OpLogicalAnd>(const spv_instruction_t *inst,
+                                    const spv_opcode_desc opcodeEntry) {}
+#endif
+
+#if 0
+template <>
+bool idUsage::isValid<OpSelect>(const spv_instruction_t *inst,
+                                const spv_opcode_desc opcodeEntry) {}
+#endif
+
+#if 0
+template <>
+bool idUsage::isValid<OpIEqual>(const spv_instruction_t *inst,
+                                const spv_opcode_desc opcodeEntry) {}
+#endif
+
+#if 0
+template <>
+bool idUsage::isValid<OpFOrdEqual>(const spv_instruction_t *inst,
+                                   const spv_opcode_desc opcodeEntry) {}
+#endif
+
+#if 0
+template <>
+bool idUsage::isValid<OpFUnordEqual>(const spv_instruction_t *inst,
+                                     const spv_opcode_desc opcodeEntry) {}
+#endif
+
+#if 0
+template <>
+bool idUsage::isValid<OpINotEqual>(const spv_instruction_t *inst,
+                                   const spv_opcode_desc opcodeEntry) {}
+#endif
+
+#if 0
+template <>
+bool idUsage::isValid<OpFOrdNotEqual>(const spv_instruction_t *inst,
+                                      const spv_opcode_desc opcodeEntry) {}
+#endif
+
+#if 0
+template <>
+bool idUsage::isValid<OpFUnordNotEqual>(
+    const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {}
+#endif
+
+#if 0
+template <>
+bool idUsage::isValid<OpULessThan>(const spv_instruction_t *inst,
+                                   const spv_opcode_desc opcodeEntry) {}
+#endif
+
+#if 0
+template <>
+bool idUsage::isValid<OpSLessThan>(const spv_instruction_t *inst,
+                                   const spv_opcode_desc opcodeEntry) {}
+#endif
+
+#if 0
+template <>
+bool idUsage::isValid<OpFOrdLessThan>(const spv_instruction_t *inst,
+                                      const spv_opcode_desc opcodeEntry) {}
+#endif
+
+#if 0
+template <>
+bool idUsage::isValid<OpFUnordLessThan>(
+    const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {}
+#endif
+
+#if 0
+template <>
+bool idUsage::isValid<OpUGreaterThan>(const spv_instruction_t *inst,
+                                      const spv_opcode_desc opcodeEntry) {}
+#endif
+
+#if 0
+template <>
+bool idUsage::isValid<OpSGreaterThan>(const spv_instruction_t *inst,
+                                      const spv_opcode_desc opcodeEntry) {}
+#endif
+
+#if 0
+template <>
+bool idUsage::isValid<OpFOrdGreaterThan>(
+    const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {}
+#endif
+
+#if 0
+template <>
+bool idUsage::isValid<OpFUnordGreaterThan>(
+    const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {}
+#endif
+
+#if 0
+template <>
+bool idUsage::isValid<OpULessThanEqual>(
+    const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {}
+#endif
+
+#if 0
+template <>
+bool idUsage::isValid<OpSLessThanEqual>(
+    const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {}
+#endif
+
+#if 0
+template <>
+bool idUsage::isValid<OpFOrdLessThanEqual>(
+    const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {}
+#endif
+
+#if 0
+template <>
+bool idUsage::isValid<OpFUnordLessThanEqual>(
+    const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {}
+#endif
+
+#if 0
+template <>
+bool idUsage::isValid<OpUGreaterThanEqual>(
+    const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {}
+#endif
+
+#if 0
+template <>
+bool idUsage::isValid<OpSGreaterThanEqual>(
+    const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {}
+#endif
+
+#if 0
+template <>
+bool idUsage::isValid<OpFOrdGreaterThanEqual>(
+    const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {}
+#endif
+
+#if 0
+template <>
+bool idUsage::isValid<OpFUnordGreaterThanEqual>(
+    const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {}
+#endif
+
+#if 0
+template <>
+bool idUsage::isValid<OpDPdx>(const spv_instruction_t *inst,
+                              const spv_opcode_desc opcodeEntry) {}
+#endif
+
+#if 0
+template <>
+bool idUsage::isValid<OpDPdy>(const spv_instruction_t *inst,
+                              const spv_opcode_desc opcodeEntry) {}
+#endif
+
+#if 0
+template <>
+bool idUsage::isValid<OpFWidth>(const spv_instruction_t *inst,
+                                const spv_opcode_desc opcodeEntry) {}
+#endif
+
+#if 0
+template <>
+bool idUsage::isValid<OpDPdxFine>(const spv_instruction_t *inst,
+                                  const spv_opcode_desc opcodeEntry) {}
+#endif
+
+#if 0
+template <>
+bool idUsage::isValid<OpDPdyFine>(const spv_instruction_t *inst,
+                                  const spv_opcode_desc opcodeEntry) {}
+#endif
+
+#if 0
+template <>
+bool idUsage::isValid<OpFwidthFine>(const spv_instruction_t *inst,
+                                    const spv_opcode_desc opcodeEntry) {}
+#endif
+
+#if 0
+template <>
+bool idUsage::isValid<OpDPdxCoarse>(const spv_instruction_t *inst,
+                                    const spv_opcode_desc opcodeEntry) {}
+#endif
+
+#if 0
+template <>
+bool idUsage::isValid<OpDPdyCoarse>(const spv_instruction_t *inst,
+                                    const spv_opcode_desc opcodeEntry) {}
+#endif
+
+#if 0
+template <>
+bool idUsage::isValid<OpFwidthCoarse>(const spv_instruction_t *inst,
+                                      const spv_opcode_desc opcodeEntry) {}
+#endif
+
+#if 0
+template <>
+bool idUsage::isValid<OpPhi>(const spv_instruction_t *inst,
+                             const spv_opcode_desc opcodeEntry) {}
+#endif
+
+#if 0
+template <>
+bool idUsage::isValid<OpLoopMerge>(const spv_instruction_t *inst,
+                                   const spv_opcode_desc opcodeEntry) {}
+#endif
+
+#if 0
+template <>
+bool idUsage::isValid<OpSelectionMerge>(
+    const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {}
+#endif
+
+#if 0
+template <>
+bool idUsage::isValid<OpBranch>(const spv_instruction_t *inst,
+                                const spv_opcode_desc opcodeEntry) {}
+#endif
+
+#if 0
+template <>
+bool idUsage::isValid<OpBranchConditional>(
+    const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {}
+#endif
+
+#if 0
+template <>
+bool idUsage::isValid<OpSwitch>(const spv_instruction_t *inst,
+                                const spv_opcode_desc opcodeEntry) {}
+#endif
+
+template <>
+bool idUsage::isValid<OpReturnValue>(const spv_instruction_t *inst,
+                                     const spv_opcode_desc) {
+  auto valueIndex = 1;
+  auto value = find(inst->words[valueIndex]);
+  spvCheck(!found(value), DIAG(valueIndex) << "OpReturnValue Value <id> '"
+                                           << inst->words[valueIndex]
+                                           << "' is not defined.";
+           return false);
+  spvCheck(!spvOpcodeIsValue(value->second.opcode),
+           DIAG(valueIndex) << "OpReturnValue Value <id> '"
+                            << inst->words[valueIndex]
+                            << "' does not represent a value.";
+           return false);
+  auto valueType = find(value->second.inst->words[1]);
+  spvCheck(!found(valueType), assert(0 && "Unreachable!"));
+  // NOTE: Find OpFunction
+  const spv_instruction_t *function = inst - 1;
+  while (firstInst != function) {
+    spvCheck(OpFunction == function->opcode, break);
+    function--;
+  }
+  spvCheck(OpFunction != function->opcode,
+           DIAG(valueIndex) << "OpReturnValue is not in a basic block.";
+           return false);
+  auto returnType = find(function->words[1]);
+  spvCheck(!found(returnType), assert(0 && "Unreachable!"));
+  if (OpTypePointer == valueType->second.opcode) {
+    auto pointerValueType = find(valueType->second.inst->words[3]);
+    spvCheck(!found(pointerValueType), assert(0 && "Unreachable!"));
+    spvCheck(!spvOpcodeAreTypesEqual(returnType->second.inst,
+                                     pointerValueType->second.inst),
+             DIAG(valueIndex)
+                 << "OpReturnValue Value <id> '" << inst->words[valueIndex]
+                 << "'s pointer type does not match OpFunction's return type.";
+             return false);
+  } else {
+    spvCheck(!spvOpcodeAreTypesEqual(returnType->second.inst,
+                                     valueType->second.inst),
+             DIAG(valueIndex)
+                 << "OpReturnValue Value <id> '" << inst->words[valueIndex]
+                 << "'s type does not match OpFunction's return type.";
+             return false);
+  }
+  return true;
+}
+
+#if 0
+template <>
+bool idUsage::isValid<OpLifetimeStart>(const spv_instruction_t *inst,
+                                       const spv_opcode_desc opcodeEntry) {
+}
+#endif
+
+#if 0
+template <>
+bool idUsage::isValid<OpLifetimeStop>(const spv_instruction_t *inst,
+                                      const spv_opcode_desc opcodeEntry) {}
+#endif
+
+#if 0
+template <>
+bool idUsage::isValid<OpAtomicInit>(const spv_instruction_t *inst,
+                                    const spv_opcode_desc opcodeEntry) {}
+#endif
+
+#if 0
+template <>
+bool idUsage::isValid<OpAtomicLoad>(const spv_instruction_t *inst,
+                                    const spv_opcode_desc opcodeEntry) {}
+#endif
+
+#if 0
+template <>
+bool idUsage::isValid<OpAtomicStore>(const spv_instruction_t *inst,
+                                     const spv_opcode_desc opcodeEntry) {}
+#endif
+
+#if 0
+template <>
+bool idUsage::isValid<OpAtomicExchange>(
+    const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {}
+#endif
+
+#if 0
+template <>
+bool idUsage::isValid<OpAtomicCompareExchange>(
+    const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {}
+#endif
+
+#if 0
+template <>
+bool idUsage::isValid<OpAtomicCompareExchangeWeak>(
+    const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {}
+#endif
+
+#if 0
+template <>
+bool idUsage::isValid<OpAtomicIIncrement>(
+    const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {}
+#endif
+
+#if 0
+template <>
+bool idUsage::isValid<OpAtomicIDecrement>(
+    const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {}
+#endif
+
+#if 0
+template <>
+bool idUsage::isValid<OpAtomicIAdd>(const spv_instruction_t *inst,
+                                    const spv_opcode_desc opcodeEntry) {}
+#endif
+
+#if 0
+template <>
+bool idUsage::isValid<OpAtomicISub>(const spv_instruction_t *inst,
+                                    const spv_opcode_desc opcodeEntry) {}
+#endif
+
+#if 0
+template <>
+bool idUsage::isValid<OpAtomicUMin>(const spv_instruction_t *inst,
+                                    const spv_opcode_desc opcodeEntry) {}
+#endif
+
+#if 0
+template <>
+bool idUsage::isValid<OpAtomicUMax>(const spv_instruction_t *inst,
+                                    const spv_opcode_desc opcodeEntry) {}
+#endif
+
+#if 0
+template <>
+bool idUsage::isValid<OpAtomicAnd>(const spv_instruction_t *inst,
+                                   const spv_opcode_desc opcodeEntry) {}
+#endif
+
+#if 0
+template <>
+bool idUsage::isValid<OpAtomicOr>(const spv_instruction_t *inst,
+                                  const spv_opcode_desc opcodeEntry) {}
+#endif
+
+#if 0
+template <>
+bool idUsage::isValid<OpAtomicXor>(const spv_instruction_t *inst,
+                                   const spv_opcode_desc opcodeEntry) {}
+#endif
+
+#if 0
+template <>
+bool idUsage::isValid<OpAtomicIMin>(const spv_instruction_t *inst,
+                                    const spv_opcode_desc opcodeEntry) {}
+#endif
+
+#if 0
+template <>
+bool idUsage::isValid<OpAtomicIMax>(const spv_instruction_t *inst,
+                                    const spv_opcode_desc opcodeEntry) {}
+#endif
+
+#if 0
+template <>
+bool idUsage::isValid<OpEmitStreamVertex>(
+    const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {}
+#endif
+
+#if 0
+template <>
+bool idUsage::isValid<OpEndStreamPrimitive>(
+    const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {}
+#endif
+
+#if 0
+template <>
+bool idUsage::isValid<OpAsyncGroupCopy>(
+    const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {}
+#endif
+
+#if 0
+template <>
+bool idUsage::isValid<OpWaitGroupEvents>(
+    const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {}
+#endif
+
+#if 0
+template <>
+bool idUsage::isValid<OpGroupAll>(const spv_instruction_t *inst,
+                                  const spv_opcode_desc opcodeEntry) {}
+#endif
+
+#if 0
+template <>
+bool idUsage::isValid<OpGroupAny>(const spv_instruction_t *inst,
+                                  const spv_opcode_desc opcodeEntry) {}
+#endif
+
+#if 0
+template <>
+bool idUsage::isValid<OpGroupBroadcast>(
+    const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {}
+#endif
+
+#if 0
+template <>
+bool idUsage::isValid<OpGroupIAdd>(const spv_instruction_t *inst,
+                                   const spv_opcode_desc opcodeEntry) {}
+#endif
+
+#if 0
+template <>
+bool idUsage::isValid<OpGroupFAdd>(const spv_instruction_t *inst,
+                                   const spv_opcode_desc opcodeEntry) {}
+#endif
+
+#if 0
+template <>
+bool idUsage::isValid<OpGroupFMin>(const spv_instruction_t *inst,
+                                   const spv_opcode_desc opcodeEntry) {}
+#endif
+
+#if 0
+template <>
+bool idUsage::isValid<OpGroupUMin>(const spv_instruction_t *inst,
+                                   const spv_opcode_desc opcodeEntry) {}
+#endif
+
+#if 0
+template <>
+bool idUsage::isValid<OpGroupSMin>(const spv_instruction_t *inst,
+                                   const spv_opcode_desc opcodeEntry) {}
+#endif
+
+#if 0
+template <>
+bool idUsage::isValid<OpGroupFMax>(const spv_instruction_t *inst,
+                                   const spv_opcode_desc opcodeEntry) {}
+#endif
+
+#if 0
+template <>
+bool idUsage::isValid<OpGroupUMax>(const spv_instruction_t *inst,
+                                   const spv_opcode_desc opcodeEntry) {}
+#endif
+
+#if 0
+template <>
+bool idUsage::isValid<OpGroupSMax>(const spv_instruction_t *inst,
+                                   const spv_opcode_desc opcodeEntry) {}
+#endif
+
+#if 0
+template <>
+bool idUsage::isValid<OpEnqueueMarker>(const spv_instruction_t *inst,
+                                       const spv_opcode_desc opcodeEntry) {
+}
+#endif
+
+#if 0
+template <>
+bool idUsage::isValid<OpEnqueueKernel>(const spv_instruction_t *inst,
+                                       const spv_opcode_desc opcodeEntry) {
+}
+#endif
+
+#if 0
+template <>
+bool idUsage::isValid<OpGetKernelNDrangeSubGroupCount>(
+    const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {}
+#endif
+
+#if 0
+template <>
+bool idUsage::isValid<OpGetKernelNDrangeMaxSubGroupSize>(
+    const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {}
+#endif
+
+#if 0
+template <>
+bool idUsage::isValid<OpGetKernelWorkGroupSize>(
+    const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {}
+#endif
+
+#if 0
+template <>
+bool idUsage::isValid<OpGetKernelPreferredWorkGroupSizeMultiple>(
+    const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {}
+#endif
+
+#if 0
+template <>
+bool idUsage::isValid<OpRetainEvent>(const spv_instruction_t *inst,
+                                     const spv_opcode_desc opcodeEntry) {}
+#endif
+
+#if 0
+template <>
+bool idUsage::isValid<OpReleaseEvent>(const spv_instruction_t *inst,
+                                      const spv_opcode_desc opcodeEntry) {}
+#endif
+
+#if 0
+template <>
+bool idUsage::isValid<OpCreateUserEvent>(
+    const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {}
+#endif
+
+#if 0
+template <>
+bool idUsage::isValid<OpIsValidEvent>(const spv_instruction_t *inst,
+                                      const spv_opcode_desc opcodeEntry) {}
+#endif
+
+#if 0
+template <>
+bool idUsage::isValid<OpSetUserEventStatus>(
+    const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {}
+#endif
+
+#if 0
+template <>
+bool idUsage::isValid<OpCaptureEventProfilingInfo>(
+    const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {}
+#endif
+
+#if 0
+template <>
+bool idUsage::isValid<OpGetDefaultQueue>(
+    const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {}
+#endif
+
+#if 0
+template <>
+bool idUsage::isValid<OpBuildNDRange>(const spv_instruction_t *inst,
+                                      const spv_opcode_desc opcodeEntry) {}
+#endif
+
+#if 0
+template <>
+bool idUsage::isValid<OpReadPipe>(const spv_instruction_t *inst,
+                                  const spv_opcode_desc opcodeEntry) {}
+#endif
+
+#if 0
+template <>
+bool idUsage::isValid<OpWritePipe>(const spv_instruction_t *inst,
+                                   const spv_opcode_desc opcodeEntry) {}
+#endif
+
+#if 0
+template <>
+bool idUsage::isValid<OpReservedReadPipe>(
+    const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {}
+#endif
+
+#if 0
+template <>
+bool idUsage::isValid<OpReservedWritePipe>(
+    const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {}
+#endif
+
+#if 0
+template <>
+bool idUsage::isValid<OpReserveReadPipePackets>(
+    const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {}
+#endif
+
+#if 0
+template <>
+bool idUsage::isValid<OpReserveWritePipePackets>(
+    const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {}
+#endif
+
+#if 0
+template <>
+bool idUsage::isValid<OpCommitReadPipe>(
+    const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {}
+#endif
+
+#if 0
+template <>
+bool idUsage::isValid<OpCommitWritePipe>(
+    const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {}
+#endif
+
+#if 0
+template <>
+bool idUsage::isValid<OpIsValidReserveId>(
+    const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {}
+#endif
+
+#if 0
+template <>
+bool idUsage::isValid<OpGetNumPipePackets>(
+    const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {}
+#endif
+
+#if 0
+template <>
+bool idUsage::isValid<OpGetMaxPipePackets>(
+    const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {}
+#endif
+
+#if 0
+template <>
+bool idUsage::isValid<OpGroupReserveReadPipePackets>(
+    const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {}
+#endif
+
+#if 0
+template <>
+bool idUsage::isValid<OpGroupReserveWritePipePackets>(
+    const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {}
+#endif
+
+#if 0
+template <>
+bool idUsage::isValid<OpGroupCommitReadPipe>(
+    const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {}
+#endif
+
+#if 0
+template <>
+bool idUsage::isValid<OpGroupCommitWritePipe>(
+    const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {}
+#endif
+
+#undef DIAG
+
+bool idUsage::isValid(const spv_instruction_t *inst) {
+  spv_opcode_desc opcodeEntry = nullptr;
+  spvCheck(spvOpcodeTableValueLookup(opcodeTable, inst->opcode, &opcodeEntry),
+           return false);
+#define CASE(OpCode) \
+  case OpCode:       \
+    return isValid<OpCode>(inst, opcodeEntry);
+#define FAIL(OpCode)                                     \
+  case OpCode:                                           \
+    std::cerr << "Not implemented: " << #OpCode << "\n"; \
+    return false;
+  switch (inst->opcode) {
+    FAIL(OpUndef)
+    CASE(OpName)
+    CASE(OpMemberName)
+    CASE(OpLine)
+    CASE(OpDecorate)
+    CASE(OpMemberDecorate)
+    CASE(OpGroupDecorate)
+    FAIL(OpGroupMemberDecorate)
+    FAIL(OpExtInst)
+    CASE(OpEntryPoint)
+    CASE(OpExecutionMode)
+    CASE(OpTypeVector)
+    CASE(OpTypeMatrix)
+    CASE(OpTypeSampler)
+    CASE(OpTypeArray)
+    CASE(OpTypeRuntimeArray)
+    CASE(OpTypeStruct)
+    CASE(OpTypePointer)
+    CASE(OpTypeFunction)
+    CASE(OpTypePipe)
+    CASE(OpConstantTrue)
+    CASE(OpConstantFalse)
+    CASE(OpConstant)
+    CASE(OpConstantComposite)
+    CASE(OpConstantSampler)
+    CASE(OpConstantNull)
+    CASE(OpSpecConstantTrue)
+    CASE(OpSpecConstantFalse)
+    CASE(OpSpecConstant)
+    FAIL(OpSpecConstantComposite)
+    FAIL(OpSpecConstantOp)
+    CASE(OpVariable)
+    CASE(OpLoad)
+    CASE(OpStore)
+    CASE(OpCopyMemory)
+    CASE(OpCopyMemorySized)
+    FAIL(OpAccessChain)
+    FAIL(OpInBoundsAccessChain)
+    FAIL(OpArrayLength)
+    FAIL(OpImagePointer)
+    FAIL(OpGenericPtrMemSemantics)
+    CASE(OpFunction)
+    CASE(OpFunctionParameter)
+    CASE(OpFunctionCall)
+    FAIL(OpSampler)
+    FAIL(OpTextureSample)
+    FAIL(OpTextureSampleDref)
+    FAIL(OpTextureSampleLod)
+    FAIL(OpTextureSampleProj)
+    FAIL(OpTextureSampleGrad)
+    FAIL(OpTextureSampleOffset)
+    FAIL(OpTextureSampleProjLod)
+    FAIL(OpTextureSampleProjGrad)
+    FAIL(OpTextureSampleLodOffset)
+    FAIL(OpTextureSampleProjOffset)
+    FAIL(OpTextureSampleGradOffset)
+    FAIL(OpTextureSampleProjLodOffset)
+    FAIL(OpTextureSampleProjGradOffset)
+    FAIL(OpTextureFetchTexelLod)
+    FAIL(OpTextureFetchTexelOffset)
+    FAIL(OpTextureFetchSample)
+    FAIL(OpTextureFetchTexel)
+    FAIL(OpTextureGather)
+    FAIL(OpTextureGatherOffset)
+    FAIL(OpTextureGatherOffsets)
+    FAIL(OpTextureQuerySizeLod)
+    FAIL(OpTextureQuerySize)
+    FAIL(OpTextureQueryLevels)
+    FAIL(OpTextureQuerySamples)
+    FAIL(OpConvertUToF)
+    FAIL(OpConvertFToS)
+    FAIL(OpConvertSToF)
+    FAIL(OpUConvert)
+    FAIL(OpSConvert)
+    FAIL(OpFConvert)
+    FAIL(OpConvertPtrToU)
+    FAIL(OpConvertUToPtr)
+    FAIL(OpPtrCastToGeneric)
+    FAIL(OpGenericCastToPtr)
+    FAIL(OpBitcast)
+    FAIL(OpGenericCastToPtrExplicit)
+    FAIL(OpSatConvertSToU)
+    FAIL(OpSatConvertUToS)
+    FAIL(OpVectorExtractDynamic)
+    FAIL(OpVectorInsertDynamic)
+    FAIL(OpVectorShuffle)
+    FAIL(OpCompositeConstruct)
+    FAIL(OpCompositeExtract)
+    FAIL(OpCompositeInsert)
+    FAIL(OpCopyObject)
+    FAIL(OpTranspose)
+    FAIL(OpSNegate)
+    FAIL(OpFNegate)
+    FAIL(OpNot)
+    FAIL(OpIAdd)
+    FAIL(OpFAdd)
+    FAIL(OpISub)
+    FAIL(OpFSub)
+    FAIL(OpIMul)
+    FAIL(OpFMul)
+    FAIL(OpUDiv)
+    FAIL(OpSDiv)
+    FAIL(OpFDiv)
+    FAIL(OpUMod)
+    FAIL(OpSRem)
+    FAIL(OpSMod)
+    FAIL(OpFRem)
+    FAIL(OpFMod)
+    FAIL(OpVectorTimesScalar)
+    FAIL(OpMatrixTimesScalar)
+    FAIL(OpVectorTimesMatrix)
+    FAIL(OpMatrixTimesVector)
+    FAIL(OpMatrixTimesMatrix)
+    FAIL(OpOuterProduct)
+    FAIL(OpDot)
+    FAIL(OpShiftRightLogical)
+    FAIL(OpShiftRightArithmetic)
+    FAIL(OpShiftLeftLogical)
+    FAIL(OpBitwiseOr)
+    FAIL(OpBitwiseXor)
+    FAIL(OpBitwiseAnd)
+    FAIL(OpAny)
+    FAIL(OpAll)
+    FAIL(OpIsNan)
+    FAIL(OpIsInf)
+    FAIL(OpIsFinite)
+    FAIL(OpIsNormal)
+    FAIL(OpSignBitSet)
+    FAIL(OpLessOrGreater)
+    FAIL(OpOrdered)
+    FAIL(OpUnordered)
+    FAIL(OpLogicalOr)
+    FAIL(OpLogicalXor)
+    FAIL(OpLogicalAnd)
+    FAIL(OpSelect)
+    FAIL(OpIEqual)
+    FAIL(OpFOrdEqual)
+    FAIL(OpFUnordEqual)
+    FAIL(OpINotEqual)
+    FAIL(OpFOrdNotEqual)
+    FAIL(OpFUnordNotEqual)
+    FAIL(OpULessThan)
+    FAIL(OpSLessThan)
+    FAIL(OpFOrdLessThan)
+    FAIL(OpFUnordLessThan)
+    FAIL(OpUGreaterThan)
+    FAIL(OpSGreaterThan)
+    FAIL(OpFOrdGreaterThan)
+    FAIL(OpFUnordGreaterThan)
+    FAIL(OpULessThanEqual)
+    FAIL(OpSLessThanEqual)
+    FAIL(OpFOrdLessThanEqual)
+    FAIL(OpFUnordLessThanEqual)
+    FAIL(OpUGreaterThanEqual)
+    FAIL(OpSGreaterThanEqual)
+    FAIL(OpFOrdGreaterThanEqual)
+    FAIL(OpFUnordGreaterThanEqual)
+    FAIL(OpDPdx)
+    FAIL(OpDPdy)
+    FAIL(OpFwidth)
+    FAIL(OpDPdxFine)
+    FAIL(OpDPdyFine)
+    FAIL(OpFwidthFine)
+    FAIL(OpDPdxCoarse)
+    FAIL(OpDPdyCoarse)
+    FAIL(OpFwidthCoarse)
+    FAIL(OpPhi)
+    FAIL(OpLoopMerge)
+    FAIL(OpSelectionMerge)
+    FAIL(OpBranch)
+    FAIL(OpBranchConditional)
+    FAIL(OpSwitch)
+    CASE(OpReturnValue)
+    FAIL(OpLifetimeStart)
+    FAIL(OpLifetimeStop)
+    FAIL(OpAtomicInit)
+    FAIL(OpAtomicLoad)
+    FAIL(OpAtomicStore)
+    FAIL(OpAtomicExchange)
+    FAIL(OpAtomicCompareExchange)
+    FAIL(OpAtomicCompareExchangeWeak)
+    FAIL(OpAtomicIIncrement)
+    FAIL(OpAtomicIDecrement)
+    FAIL(OpAtomicIAdd)
+    FAIL(OpAtomicISub)
+    FAIL(OpAtomicUMin)
+    FAIL(OpAtomicUMax)
+    FAIL(OpAtomicAnd)
+    FAIL(OpAtomicOr)
+    FAIL(OpAtomicXor)
+    FAIL(OpAtomicIMin)
+    FAIL(OpAtomicIMax)
+    FAIL(OpEmitStreamVertex)
+    FAIL(OpEndStreamPrimitive)
+    FAIL(OpAsyncGroupCopy)
+    FAIL(OpWaitGroupEvents)
+    FAIL(OpGroupAll)
+    FAIL(OpGroupAny)
+    FAIL(OpGroupBroadcast)
+    FAIL(OpGroupIAdd)
+    FAIL(OpGroupFAdd)
+    FAIL(OpGroupFMin)
+    FAIL(OpGroupUMin)
+    FAIL(OpGroupSMin)
+    FAIL(OpGroupFMax)
+    FAIL(OpGroupUMax)
+    FAIL(OpGroupSMax)
+    FAIL(OpEnqueueMarker)
+    FAIL(OpEnqueueKernel)
+    FAIL(OpGetKernelNDrangeSubGroupCount)
+    FAIL(OpGetKernelNDrangeMaxSubGroupSize)
+    FAIL(OpGetKernelWorkGroupSize)
+    FAIL(OpGetKernelPreferredWorkGroupSizeMultiple)
+    FAIL(OpRetainEvent)
+    FAIL(OpReleaseEvent)
+    FAIL(OpCreateUserEvent)
+    FAIL(OpIsValidEvent)
+    FAIL(OpSetUserEventStatus)
+    FAIL(OpCaptureEventProfilingInfo)
+    FAIL(OpGetDefaultQueue)
+    FAIL(OpBuildNDRange)
+    FAIL(OpReadPipe)
+    FAIL(OpWritePipe)
+    FAIL(OpReservedReadPipe)
+    FAIL(OpReservedWritePipe)
+    FAIL(OpReserveReadPipePackets)
+    FAIL(OpReserveWritePipePackets)
+    FAIL(OpCommitReadPipe)
+    FAIL(OpCommitWritePipe)
+    FAIL(OpIsValidReserveId)
+    FAIL(OpGetNumPipePackets)
+    FAIL(OpGetMaxPipePackets)
+    FAIL(OpGroupReserveReadPipePackets)
+    FAIL(OpGroupReserveWritePipePackets)
+    FAIL(OpGroupCommitReadPipe)
+    FAIL(OpGroupCommitWritePipe)
+    default:
+      return true;
+  }
+#undef FAIL
+#undef CASE
+}
+}//anonymous namespace
+
+spv_result_t spvValidateInstructionIDs(
+    const spv_instruction_t *pInsts, const uint64_t instCount,
+    const spv_id_info_t *pIdUses, const uint64_t idUsesCount,
+    const spv_id_info_t *pIdDefs, const uint64_t idDefsCount,
+    const spv_opcode_table opcodeTable, const spv_operand_table operandTable,
+    const spv_ext_inst_table extInstTable, spv_position position,
+    spv_diagnostic *pDiag) {
+  idUsage idUsage(opcodeTable, operandTable, extInstTable, pIdUses, idUsesCount,
+                  pIdDefs, idDefsCount, pInsts, instCount, position, pDiag);
+  for (uint64_t instIndex = 0; instIndex < instCount; ++instIndex) {
+    spvCheck(!idUsage.isValid(&pInsts[instIndex]), return SPV_ERROR_INVALID_ID);
+    position->index += pInsts[instIndex].wordCount;
+  }
+  return SPV_SUCCESS;
+}
diff --git a/test/BinaryEndianness.cpp b/test/BinaryEndianness.cpp
new file mode 100644 (file)
index 0000000..64da851
--- /dev/null
@@ -0,0 +1,60 @@
+// Copyright (c) 2015 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.
+
+#include "UnitSPIRV.h"
+
+TEST(BinaryEndianness, InvalidCode) {
+  uint32_t invalidMagicNumber[] = {0};
+  spv_binary_t binary = {invalidMagicNumber, 1};
+  spv_endianness_t endian;
+  ASSERT_EQ(SPV_ERROR_INVALID_BINARY, spvBinaryEndianness(&binary, &endian));
+}
+
+TEST(BinaryEndianness, Little) {
+  uint32_t magicNumber;
+  if (I32_ENDIAN_HOST == I32_ENDIAN_LITTLE) {
+    magicNumber = 0x07230203;
+  } else {
+    magicNumber = 0x03022307;
+  }
+  spv_binary_t binary = {&magicNumber, 1};
+  spv_endianness_t endian;
+  ASSERT_EQ(SPV_SUCCESS, spvBinaryEndianness(&binary, &endian));
+  ASSERT_EQ(SPV_ENDIANNESS_LITTLE, endian);
+}
+
+TEST(BinaryEndianness, Big) {
+  uint32_t magicNumber;
+  if (I32_ENDIAN_HOST == I32_ENDIAN_BIG) {
+    magicNumber = 0x07230203;
+  } else {
+    magicNumber = 0x03022307;
+  }
+  spv_binary_t binary = {&magicNumber, 1};
+  spv_endianness_t endian;
+  ASSERT_EQ(SPV_SUCCESS, spvBinaryEndianness(&binary, &endian));
+  ASSERT_EQ(SPV_ENDIANNESS_BIG, endian);
+}
diff --git a/test/BinaryHeaderGet.cpp b/test/BinaryHeaderGet.cpp
new file mode 100644 (file)
index 0000000..0cab66b
--- /dev/null
@@ -0,0 +1,76 @@
+// Copyright (c) 2015 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.
+
+#include "UnitSPIRV.h"
+
+class BinaryHeaderGet : public ::testing::Test {
+ public:
+  BinaryHeaderGet() { memset(code, 0, sizeof(code)); }
+
+  virtual void SetUp() {
+    code[0] = SPV_MAGIC_NUMBER;
+    code[1] = SPV_VERSION_NUMBER;
+    code[2] = SPV_GENERATOR_CODEPLAY;
+    code[3] = 1;  // NOTE: Bound
+    code[4] = 0;  // NOTE: Schema; reserved
+    code[5] = 0;  // NOTE: Instructions
+
+    binary.code = code;
+    binary.wordCount = 6;
+  }
+
+  virtual void TearDown() {}
+
+  uint32_t code[6];
+  spv_binary_t binary;
+};
+
+TEST_F(BinaryHeaderGet, Default) {
+  spv_endianness_t endian;
+  ASSERT_EQ(SPV_SUCCESS, spvBinaryEndianness(&binary, &endian));
+
+  spv_header_t header;
+  ASSERT_EQ(SPV_SUCCESS, spvBinaryHeaderGet(&binary, endian, &header));
+
+  ASSERT_EQ((uint32_t)SPV_MAGIC_NUMBER, header.magic);
+  ASSERT_EQ(99u, header.version);
+  ASSERT_EQ((uint32_t)SPV_GENERATOR_CODEPLAY, header.generator);
+  ASSERT_EQ(1u, header.bound);
+  ASSERT_EQ(0u, header.schema);
+  ASSERT_EQ(&code[5], header.instructions);
+}
+
+TEST_F(BinaryHeaderGet, InvalidCode) {
+  spv_binary_t binary = {nullptr, 0};
+  spv_header_t header;
+  ASSERT_EQ(SPV_ERROR_INVALID_BINARY,
+            spvBinaryHeaderGet(&binary, SPV_ENDIANNESS_LITTLE, &header));
+}
+
+TEST_F(BinaryHeaderGet, InvalidPointerHeader) {
+  ASSERT_EQ(SPV_ERROR_INVALID_POINTER,
+            spvBinaryHeaderGet(&binary, SPV_ENDIANNESS_LITTLE, nullptr));
+}
diff --git a/test/BinaryToText.cpp b/test/BinaryToText.cpp
new file mode 100644 (file)
index 0000000..b2f5efe
--- /dev/null
@@ -0,0 +1,169 @@
+// Copyright (c) 2015 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.
+
+#include "UnitSPIRV.h"
+
+class BinaryToText : public ::testing::Test {
+ public:
+  BinaryToText() : binary(), opcodeTable(nullptr), operandTable(nullptr) {}
+
+  virtual void SetUp() {
+    ASSERT_EQ(SPV_SUCCESS, spvOpcodeTableGet(&opcodeTable));
+    ASSERT_EQ(SPV_SUCCESS, spvOperandTableGet(&operandTable));
+    ASSERT_EQ(SPV_SUCCESS, spvExtInstTableGet(&extInstTable));
+
+    const char *textStr = R"(
+OpSource OpenCL 12
+OpMemoryModel Physical64 OpenCL1.2
+OpSourceExtension "PlaceholderExtensionName"
+OpEntryPoint Kernel $1
+OpExecutionMode $1 LocalSizeHint 1 1 1
+OpTypeVoid %2
+OpTypeBool %3
+OpTypeInt %4 8 0
+OpTypeInt %5 8 1
+OpTypeInt %6 16 0
+OpTypeInt %7 16 1
+OpTypeInt %8 32 0
+OpTypeInt %9 32 1
+OpTypeInt %10 64 0
+OpTypeInt %11 64 1
+OpTypeFloat %12 16
+OpTypeFloat %13 32
+OpTypeFloat %14 64
+OpTypeVector %15 4 2
+)";
+    spv_text_t text = {textStr, strlen(textStr)};
+    spv_diagnostic diagnostic = nullptr;
+    spv_result_t error = spvTextToBinary(&text, opcodeTable, operandTable,
+                                         extInstTable, &binary, &diagnostic);
+    if (error) {
+      spvDiagnosticPrint(diagnostic);
+      spvDiagnosticDestroy(diagnostic);
+      ASSERT_EQ(SPV_SUCCESS, error);
+    }
+  }
+
+  virtual void TearDown() { spvBinaryDestroy(binary); }
+
+  spv_binary binary;
+  spv_opcode_table opcodeTable;
+  spv_operand_table operandTable;
+  spv_ext_inst_table extInstTable;
+};
+
+TEST_F(BinaryToText, Default) {
+  spv_text text = nullptr;
+  spv_diagnostic diagnostic = nullptr;
+  ASSERT_EQ(SPV_SUCCESS,
+            spvBinaryToText(binary, SPV_BINARY_TO_TEXT_OPTION_NONE, opcodeTable,
+                            operandTable, extInstTable, &text, &diagnostic));
+  printf("%s", text->str);
+  spvTextDestroy(text);
+}
+
+TEST_F(BinaryToText, InvalidCode) {
+  spv_binary_t binary = {nullptr, 42};
+  spv_text text;
+  spv_diagnostic diagnostic = nullptr;
+  ASSERT_EQ(
+      SPV_ERROR_INVALID_BINARY,
+      spvBinaryToText(&binary, SPV_BINARY_TO_TEXT_OPTION_NONE, opcodeTable,
+                      operandTable, extInstTable, &text, &diagnostic));
+  if (diagnostic) {
+    spvDiagnosticPrint(diagnostic);
+    spvDiagnosticDestroy(diagnostic);
+  }
+}
+
+TEST_F(BinaryToText, InvalidTable) {
+  spv_text text;
+  spv_diagnostic diagnostic = nullptr;
+  ASSERT_EQ(SPV_ERROR_INVALID_TABLE,
+            spvBinaryToText(binary, 0, nullptr, operandTable, extInstTable,
+                            &text, &diagnostic));
+  ASSERT_EQ(SPV_ERROR_INVALID_TABLE,
+            spvBinaryToText(binary, SPV_BINARY_TO_TEXT_OPTION_NONE, opcodeTable,
+                            nullptr, extInstTable, &text, &diagnostic));
+  ASSERT_EQ(SPV_ERROR_INVALID_TABLE,
+            spvBinaryToText(binary, SPV_BINARY_TO_TEXT_OPTION_NONE, opcodeTable,
+                            operandTable, nullptr, &text, &diagnostic));
+  if (diagnostic) {
+    spvDiagnosticPrint(diagnostic);
+    spvDiagnosticDestroy(diagnostic);
+  }
+}
+
+TEST_F(BinaryToText, InvalidDiagnostic) {
+  spv_text text;
+  ASSERT_EQ(SPV_ERROR_INVALID_DIAGNOSTIC,
+            spvBinaryToText(binary, SPV_BINARY_TO_TEXT_OPTION_NONE, opcodeTable,
+                            operandTable, extInstTable, &text, nullptr));
+}
+
+TEST(BinaryToTextExtInst, Default) {
+  spv_opcode_table opcodeTable;
+  ASSERT_EQ(SPV_SUCCESS, spvOpcodeTableGet(&opcodeTable));
+  spv_operand_table operandTable;
+  ASSERT_EQ(SPV_SUCCESS, spvOperandTableGet(&operandTable));
+  spv_ext_inst_table extInstTable;
+  ASSERT_EQ(SPV_SUCCESS, spvExtInstTableGet(&extInstTable));
+  const char *spirv = R"(
+OpCapability Shader
+OpExtInstImport %glsl450 "GLSL.std.450"
+OpMemoryModel Logical Simple
+OpEntryPoint Vertex $main "main"
+OpTypeVoid %void
+OpTypeFloat %float 32
+OpConstant $float %const1.5 1.5
+OpTypeFunction %fnMain %void
+OpFunction $void %main None $fnMain
+OpLabel %lbMain
+OpExtInst $float %result $glsl450 round $const1.5
+OpReturn
+OpFunctionEnd
+)";
+  spv_text_t text = {spirv, strlen(spirv)};
+  spv_binary binary;
+  spv_diagnostic diagnostic;
+  spv_result_t error = spvTextToBinary(&text, opcodeTable, operandTable,
+                                       extInstTable, &binary, &diagnostic);
+  if (error) {
+    spvDiagnosticPrint(diagnostic);
+    spvDiagnosticDestroy(diagnostic);
+    ASSERT_EQ(SPV_SUCCESS, error);
+  }
+
+  error = spvBinaryToText(
+      binary, SPV_BINARY_TO_TEXT_OPTION_COLOR | SPV_BINARY_TO_TEXT_OPTION_PRINT,
+      opcodeTable, operandTable, extInstTable, nullptr, &diagnostic);
+
+  if (error) {
+    spvDiagnosticPrint(diagnostic);
+    spvDiagnosticDestroy(diagnostic);
+    ASSERT_EQ(SPV_SUCCESS, error);
+  }
+}
diff --git a/test/DiagnosticPrint.cpp b/test/DiagnosticPrint.cpp
new file mode 100644 (file)
index 0000000..bcbe6c2
--- /dev/null
@@ -0,0 +1,40 @@
+// Copyright (c) 2015 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.
+
+#include "UnitSPIRV.h"
+
+TEST(DiagnosticPrint, Default) {
+  char message[] = "Test Diagnostic!";
+  spv_diagnostic_t diagnostic = {{2, 3, 5}, message};
+  // TODO: Redirect stderr
+  ASSERT_EQ(SPV_SUCCESS, spvDiagnosticPrint(&diagnostic));
+  // TODO: Validate the output of spvDiagnosticPrint()
+  // TODO: Remove the redirection of stderr
+}
+
+TEST(DiagnosticPrint, InvalidDiagnostic) {
+  ASSERT_EQ(SPV_ERROR_INVALID_DIAGNOSTIC, spvDiagnosticPrint(nullptr));
+}
diff --git a/test/FixWord.cpp b/test/FixWord.cpp
new file mode 100644 (file)
index 0000000..500ca64
--- /dev/null
@@ -0,0 +1,50 @@
+// Copyright (c) 2015 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.
+
+#include "UnitSPIRV.h"
+
+TEST(FixWord, Default) {
+  spv_endianness_t endian;
+  if (I32_ENDIAN_HOST == I32_ENDIAN_LITTLE) {
+    endian = SPV_ENDIANNESS_LITTLE;
+  } else {
+    endian = SPV_ENDIANNESS_BIG;
+  }
+  uint32_t word = 0x53780921;
+  ASSERT_EQ(word, spvFixWord(word, endian));
+}
+
+TEST(FixWord, Reorder) {
+  spv_endianness_t endian;
+  if (I32_ENDIAN_HOST == I32_ENDIAN_LITTLE) {
+    endian = SPV_ENDIANNESS_BIG;
+  } else {
+    endian = SPV_ENDIANNESS_LITTLE;
+  }
+  uint32_t word = 0x53780921;
+  uint32_t result = 0x21097853;
+  ASSERT_EQ(result, spvFixWord(word, endian));
+}
diff --git a/test/NamedId.cpp b/test/NamedId.cpp
new file mode 100644 (file)
index 0000000..bae3a91
--- /dev/null
@@ -0,0 +1,69 @@
+// Copyright (c) 2015 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.
+
+#include "UnitSPIRV.h"
+
+TEST(NamedId, Default) {
+  const char *spirv = R"(
+OpCapability Shader
+OpMemoryModel Logical Simple
+OpEntryPoint Vertex $main
+OpTypeVoid %void
+OpTypeFunction %fnMain $void
+OpFunction $void %main None $fnMain
+OpLabel %lbMain
+OpReturn
+OpFunctionEnd)";
+  spv_text_t text;
+  text.str = spirv;
+  text.length = strlen(spirv);
+  spv_opcode_table opcodeTable;
+  ASSERT_EQ(SPV_SUCCESS, spvOpcodeTableGet(&opcodeTable));
+  spv_operand_table operandTable;
+  ASSERT_EQ(SPV_SUCCESS, spvOperandTableGet(&operandTable));
+  spv_ext_inst_table extInstTable;
+  ASSERT_EQ(SPV_SUCCESS, spvExtInstTableGet(&extInstTable));
+  spv_binary binary;
+  spv_diagnostic diagnostic;
+  spv_result_t error = spvTextToBinary(&text, opcodeTable, operandTable,
+                                       extInstTable, &binary, &diagnostic);
+  if (error) {
+    spvDiagnosticPrint(diagnostic);
+    spvDiagnosticDestroy(diagnostic);
+    spvBinaryDestroy(binary);
+    ASSERT_EQ(SPV_SUCCESS, error);
+  }
+  error = spvBinaryToText(
+      binary, SPV_BINARY_TO_TEXT_OPTION_PRINT | SPV_BINARY_TO_TEXT_OPTION_COLOR,
+      opcodeTable, operandTable, extInstTable, nullptr, &diagnostic);
+  if (error) {
+    spvDiagnosticPrint(diagnostic);
+    spvDiagnosticDestroy(diagnostic);
+    spvBinaryDestroy(binary);
+    ASSERT_EQ(SPV_SUCCESS, error);
+  }
+  spvBinaryDestroy(binary);
+}
diff --git a/test/OpcodeIsVariable.cpp b/test/OpcodeIsVariable.cpp
new file mode 100644 (file)
index 0000000..bb0b593
--- /dev/null
@@ -0,0 +1,33 @@
+// Copyright (c) 2015 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.
+
+#include "UnitSPIRV.h"
+
+TEST(OpcodeIsVariable, Default) {
+  spv_opcode_desc_t entry = {
+      nullptr, 0, (Op)0, SPV_OPCODE_FLAGS_VARIABLE, 0, {}};
+  ASSERT_NE(0, spvOpcodeIsVariable(&entry));
+}
diff --git a/test/OpcodeMake.cpp b/test/OpcodeMake.cpp
new file mode 100644 (file)
index 0000000..755dd1a
--- /dev/null
@@ -0,0 +1,42 @@
+// Copyright (c) 2015 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.
+
+#include "UnitSPIRV.h"
+
+#include <limits>
+
+TEST(OpcodeMake, DISABLED_Default) {
+  for (uint16_t wordCount = 0; wordCount < std::numeric_limits<uint16_t>::max();
+       ++wordCount) {
+    for (uint16_t code = 0; code < std::numeric_limits<uint16_t>::max();
+         ++code) {
+      uint32_t opcode = 0;
+      opcode |= (uint32_t)code;
+      opcode |= (uint32_t)wordCount << 16;
+      ASSERT_EQ(opcode, spvOpcodeMake(wordCount, (Op)code));
+    }
+  }
+}
diff --git a/test/OpcodeRequiresCapabilities.cpp b/test/OpcodeRequiresCapabilities.cpp
new file mode 100644 (file)
index 0000000..be808f3
--- /dev/null
@@ -0,0 +1,60 @@
+// Copyright (c) 2015 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.
+
+#include "UnitSPIRV.h"
+
+class Requires : public ::testing::TestWithParam<Capability> {
+ public:
+  Requires()
+      : entry({nullptr,
+               0,
+               (Op)0,
+               SPV_OPCODE_FLAGS_CAPABILITIES,
+               GetParam(),
+               {}}) {}
+
+  virtual void SetUp() {}
+
+  virtual void TearDown() {}
+
+  spv_opcode_desc_t entry;
+};
+
+TEST_P(Requires, Capabilityabilities) {
+  ASSERT_NE(0, spvOpcodeRequiresCapabilities(&entry));
+}
+
+INSTANTIATE_TEST_CASE_P(Op, Requires,
+                        ::testing::Values(CapabilityMatrix, CapabilityShader,
+                                          CapabilityGeometry,
+                                          CapabilityTessellation,
+                                          CapabilityAddresses,
+                                          CapabilityLinkage, CapabilityKernel));
+
+TEST(OpcodeRequiresCapabilityaspvities, None) {
+  spv_opcode_desc_t entry = {nullptr, 0, (Op)0, SPV_OPCODE_FLAGS_NONE, 0, {}};
+  ASSERT_EQ(0, spvOpcodeRequiresCapabilities(&entry));
+}
diff --git a/test/OpcodeSplit.cpp b/test/OpcodeSplit.cpp
new file mode 100644 (file)
index 0000000..1428232
--- /dev/null
@@ -0,0 +1,36 @@
+// Copyright (c) 2015 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.
+
+#include "UnitSPIRV.h"
+
+TEST(OpcodeSplit, Default) {
+  uint32_t word = spvOpcodeMake(42, (Op)23);
+  uint16_t wordCount = 0;
+  Op opcode;
+  spvOpcodeSplit(word, &wordCount, &opcode);
+  ASSERT_EQ(42, wordCount);
+  ASSERT_EQ(23, opcode);
+}
diff --git a/test/OpcodeTableGet.cpp b/test/OpcodeTableGet.cpp
new file mode 100644 (file)
index 0000000..99eab3d
--- /dev/null
@@ -0,0 +1,38 @@
+// Copyright (c) 2015 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.
+
+#include "UnitSPIRV.h"
+
+TEST(OpcodeTableGet, Default) {
+  spv_opcode_table table;
+  ASSERT_EQ(SPV_SUCCESS, spvOpcodeTableGet(&table));
+  ASSERT_NE(0, table->count);
+  ASSERT_NE(nullptr, table->entries);
+}
+
+TEST(OpcodeTableGet, InvalidPointerTable) {
+  ASSERT_EQ(SPV_ERROR_INVALID_POINTER, spvOpcodeTableGet(nullptr));
+}
diff --git a/test/OperandTableGet.cpp b/test/OperandTableGet.cpp
new file mode 100644 (file)
index 0000000..b7c7bd5
--- /dev/null
@@ -0,0 +1,38 @@
+// Copyright (c) 2015 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.
+
+#include "UnitSPIRV.h"
+
+TEST(OperandTableGet, Default) {
+  spv_operand_table table;
+  ASSERT_EQ(SPV_SUCCESS, spvOperandTableGet(&table));
+  ASSERT_NE(0, table->count);
+  ASSERT_NE(nullptr, table->types);
+}
+
+TEST(OperandTableGet, InvalidPointerTable) {
+  ASSERT_EQ(SPV_ERROR_INVALID_POINTER, spvOperandTableGet(nullptr));
+}
diff --git a/test/TextAdvance.cpp b/test/TextAdvance.cpp
new file mode 100644 (file)
index 0000000..969a869
--- /dev/null
@@ -0,0 +1,74 @@
+// Copyright (c) 2015 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.
+
+#include "UnitSPIRV.h"
+
+TEST(TextAdvance, LeadingNewLines) {
+  char textStr[] = "\n\nWord";
+  spv_text_t text = {textStr, strlen(textStr)};
+  spv_position_t position = {};
+  ASSERT_EQ(SPV_SUCCESS, spvTextAdvance(&text, &position));
+  ASSERT_EQ(0, position.column);
+  ASSERT_EQ(2, position.line);
+  ASSERT_EQ(2, position.index);
+}
+
+TEST(TextAdvance, LeadingSpaces) {
+  char textStr[] = "    Word";
+  spv_text_t text = {textStr, strlen(textStr)};
+  spv_position_t position = {};
+  ASSERT_EQ(SPV_SUCCESS, spvTextAdvance(&text, &position));
+  ASSERT_EQ(4, position.column);
+  ASSERT_EQ(0, position.line);
+  ASSERT_EQ(4, position.index);
+}
+
+TEST(TextAdvance, LeadingTabs) {
+  char textStr[] = "\t\t\tWord";
+  spv_text_t text = {textStr, strlen(textStr)};
+  spv_position_t position = {};
+  ASSERT_EQ(SPV_SUCCESS, spvTextAdvance(&text, &position));
+  ASSERT_EQ(3, position.column);
+  ASSERT_EQ(0, position.line);
+  ASSERT_EQ(3, position.index);
+}
+
+TEST(TextAdvance, LeadingNewLinesSpacesAndTabs) {
+  char textStr[] = "\n\n\t  Word";
+  spv_text_t text = {textStr, strlen(textStr)};
+  spv_position_t position = {};
+  ASSERT_EQ(SPV_SUCCESS, spvTextAdvance(&text, &position));
+  ASSERT_EQ(3, position.column);
+  ASSERT_EQ(2, position.line);
+  ASSERT_EQ(5, position.index);
+}
+
+TEST(TextAdvance, NullTerminator) {
+  char textStr[] = "";
+  spv_text_t text = {textStr, strlen(textStr)};
+  spv_position_t position = {};
+  ASSERT_EQ(SPV_END_OF_STREAM, spvTextAdvance(&text, &position));
+}
diff --git a/test/TextDestroy.cpp b/test/TextDestroy.cpp
new file mode 100644 (file)
index 0000000..289ce9c
--- /dev/null
@@ -0,0 +1,85 @@
+// Copyright (c) 2015 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.
+
+#include "UnitSPIRV.h"
+
+TEST(TextDestroy, Default) {
+  spv_opcode_table opcodeTable;
+  ASSERT_EQ(SPV_SUCCESS, spvOpcodeTableGet(&opcodeTable));
+
+  spv_operand_table operandTable;
+  ASSERT_EQ(SPV_SUCCESS, spvOperandTableGet(&operandTable));
+
+  spv_ext_inst_table extInstTable;
+  ASSERT_EQ(SPV_SUCCESS, spvExtInstTableGet(&extInstTable));
+
+  char textStr[] =
+      "OpSource OpenCL 12\n"
+      "OpMemoryModel Physical64 OpenCL1.2\n"
+      "OpSourceExtension \"PlaceholderExtensionName\"\n"
+      "OpEntryPoint Kernel 0\n"
+      "OpExecutionMode 0 LocalSizeHint 1 1 1\n"
+      "OpTypeVoid 1\n"
+      "OpTypeBool 2\n"
+      "OpTypeInt 3 8 0\n"
+      "OpTypeInt 4 8 1\n"
+      "OpTypeInt 5 16 0\n"
+      "OpTypeInt 6 16 1\n"
+      "OpTypeInt 7 32 0\n"
+      "OpTypeInt 8 32 1\n"
+      "OpTypeInt 9 64 0\n"
+      "OpTypeInt 10 64 1\n"
+      "OpTypeFloat 11 16\n"
+      "OpTypeFloat 12 32\n"
+      "OpTypeFloat 13 64\n"
+      "OpTypeVector 14 3 2\n";
+  spv_text_t text = {textStr, strlen(textStr)};
+  spv_binary binary = nullptr;
+  spv_diagnostic diagnostic = nullptr;
+  EXPECT_EQ(SPV_SUCCESS, spvTextToBinary(&text, opcodeTable, operandTable,
+                                         extInstTable, &binary, &diagnostic));
+  EXPECT_NE(nullptr, binary);
+  EXPECT_NE(nullptr, binary->code);
+  EXPECT_NE(0, binary->wordCount);
+  if (diagnostic) {
+    spvDiagnosticPrint(diagnostic);
+    ASSERT_TRUE(false);
+  }
+
+  spv_text resultText = nullptr;
+  EXPECT_EQ(SPV_SUCCESS,
+            spvBinaryToText(binary, 0, opcodeTable, operandTable, extInstTable,
+                            &resultText, &diagnostic));
+  spvBinaryDestroy(binary);
+  if (diagnostic) {
+    spvDiagnosticPrint(diagnostic);
+    spvDiagnosticDestroy(diagnostic);
+    ASSERT_TRUE(false);
+  }
+  EXPECT_NE(nullptr, text.str);
+  EXPECT_NE(0, text.length);
+  spvTextDestroy(resultText);
+}
diff --git a/test/TextToBinary.cpp b/test/TextToBinary.cpp
new file mode 100644 (file)
index 0000000..e36d10a
--- /dev/null
@@ -0,0 +1,354 @@
+// Copyright (c) 2015 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.
+
+#include "UnitSPIRV.h"
+
+union char_word_t {
+  char cs[4];
+  uint32_t u;
+};
+
+TEST(TextToBinary, Default) {
+  // TODO: Ensure that on big endian systems that this converts the word to
+  // little endian for encoding comparison!
+  spv_endianness_t endian = SPV_ENDIANNESS_LITTLE;
+
+  const char *textStr = R"(
+OpSource OpenCL 12
+OpMemoryModel Physical64 OpenCL1.2
+OpSourceExtension "PlaceholderExtensionName"
+OpEntryPoint Kernel $1
+OpExecutionMode $1 LocalSizeHint 1 1 1
+OpTypeVoid %2
+OpTypeBool %3
+; commment
+OpTypeInt %4 8 0 ; comment
+OpTypeInt %5 8 1
+OpTypeInt %6 16 0
+OpTypeInt %7 16 1
+OpTypeInt %8 32 0
+OpTypeInt %9 32 1
+OpTypeInt %10 64 0
+OpTypeInt %11 64 1
+OpTypeFloat %12 16
+OpTypeFloat %13 32
+OpTypeFloat %14 64
+OpTypeVector %15 4 2
+)";
+  spv_text_t text = {textStr, strlen(textStr)};
+
+  spv_opcode_table opcodeTable;
+  ASSERT_EQ(SPV_SUCCESS, spvOpcodeTableGet(&opcodeTable));
+
+  spv_operand_table operandTable;
+  ASSERT_EQ(SPV_SUCCESS, spvOperandTableGet(&operandTable));
+
+  spv_ext_inst_table extInstTable;
+  ASSERT_EQ(SPV_SUCCESS, spvExtInstTableGet(&extInstTable));
+
+  spv_binary binary;
+  spv_diagnostic diagnostic = nullptr;
+  spv_result_t error = spvTextToBinary(&text, opcodeTable, operandTable,
+                                       extInstTable, &binary, &diagnostic);
+
+  if (error) {
+    spvDiagnosticPrint(diagnostic);
+    spvDiagnosticDestroy(diagnostic);
+    ASSERT_EQ(SPV_SUCCESS, error);
+  }
+
+  struct bin {
+    bin(spv_binary binary) : binary(binary) {}
+    ~bin() { spvBinaryDestroy(binary); }
+    spv_binary binary;
+  } bin(binary);
+
+  EXPECT_NE(nullptr, text.str);
+  EXPECT_NE(0, text.length);
+
+  // TODO: Verify binary
+  ASSERT_EQ(SPV_MAGIC_NUMBER, binary->code[SPV_INDEX_MAGIC_NUMBER]);
+  ASSERT_EQ(SPV_VERSION_NUMBER, binary->code[SPV_INDEX_VERSION_NUMBER]);
+  ASSERT_EQ(SPV_GENERATOR_CODEPLAY, binary->code[SPV_INDEX_GENERATOR_NUMBER]);
+  ASSERT_EQ(16, binary->code[SPV_INDEX_BOUND]);  // TODO: Bound?
+  ASSERT_EQ(0, binary->code[SPV_INDEX_SCHEMA]);  // Reserved: schema
+
+  uint64_t instIndex = SPV_INDEX_INSTRUCTION;
+
+  ASSERT_EQ(spvOpcodeMake(3, OpSource), binary->code[instIndex++]);
+  ASSERT_EQ(SourceLanguageOpenCL, binary->code[instIndex++]);
+  ASSERT_EQ(12, binary->code[instIndex++]);
+
+  ASSERT_EQ(spvOpcodeMake(3, OpMemoryModel), binary->code[instIndex++]);
+  ASSERT_EQ(AddressingModelPhysical64, binary->code[instIndex++]);
+  ASSERT_EQ(MemoryModelOpenCL12, binary->code[instIndex++]);
+
+  uint16_t sourceExtensionWordCount =
+      (uint16_t)((strlen("PlaceholderExtensionName") / sizeof(uint32_t)) + 2);
+  ASSERT_EQ(spvOpcodeMake(sourceExtensionWordCount, OpSourceExtension),
+            binary->code[instIndex++]);
+  // TODO: This only works on little endian systems!
+  char_word_t cw = {{'P', 'l', 'a', 'c'}};
+  ASSERT_EQ(spvFixWord(cw.u, endian), binary->code[instIndex++]);
+  cw = {{'e', 'h', 'o', 'l'}};
+  ASSERT_EQ(spvFixWord(cw.u, endian), binary->code[instIndex++]);
+  cw = {{'d', 'e', 'r', 'E'}};
+  ASSERT_EQ(spvFixWord(cw.u, endian), binary->code[instIndex++]);
+  cw = {{'x', 't', 'e', 'n'}};
+  ASSERT_EQ(spvFixWord(cw.u, endian), binary->code[instIndex++]);
+  cw = {{'s', 'i', 'o', 'n'}};
+  ASSERT_EQ(spvFixWord(cw.u, endian), binary->code[instIndex++]);
+  cw = {{'N', 'a', 'm', 'e'}};
+  ASSERT_EQ(spvFixWord(cw.u, endian), binary->code[instIndex++]);
+  ASSERT_EQ(0, binary->code[instIndex++]);
+
+  ASSERT_EQ(spvOpcodeMake(3, OpEntryPoint), binary->code[instIndex++]);
+  ASSERT_EQ(ExecutionModelKernel, binary->code[instIndex++]);
+  ASSERT_EQ(1, binary->code[instIndex++]);
+
+  ASSERT_EQ(spvOpcodeMake(6, OpExecutionMode), binary->code[instIndex++]);
+  ASSERT_EQ(1, binary->code[instIndex++]);
+  ASSERT_EQ(ExecutionModeLocalSizeHint, binary->code[instIndex++]);
+  ASSERT_EQ(1, binary->code[instIndex++]);
+  ASSERT_EQ(1, binary->code[instIndex++]);
+  ASSERT_EQ(1, binary->code[instIndex++]);
+
+  ASSERT_EQ(spvOpcodeMake(2, OpTypeVoid), binary->code[instIndex++]);
+  ASSERT_EQ(2, binary->code[instIndex++]);
+
+  ASSERT_EQ(spvOpcodeMake(2, OpTypeBool), binary->code[instIndex++]);
+  ASSERT_EQ(3, binary->code[instIndex++]);
+
+  ASSERT_EQ(spvOpcodeMake(4, OpTypeInt), binary->code[instIndex++]);
+  ASSERT_EQ(4, binary->code[instIndex++]);
+  ASSERT_EQ(8, binary->code[instIndex++]);  // NOTE: 8 bits wide
+  ASSERT_EQ(0, binary->code[instIndex++]);  // NOTE: Unsigned
+
+  ASSERT_EQ(spvOpcodeMake(4, OpTypeInt), binary->code[instIndex++]);
+  ASSERT_EQ(5, binary->code[instIndex++]);
+  ASSERT_EQ(8, binary->code[instIndex++]);  // NOTE: 8 bits wide
+  ASSERT_EQ(1, binary->code[instIndex++]);  // NOTE: Signed
+
+  ASSERT_EQ(spvOpcodeMake(4, OpTypeInt), binary->code[instIndex++]);
+  ASSERT_EQ(6, binary->code[instIndex++]);
+  ASSERT_EQ(16, binary->code[instIndex++]);  // NOTE: 16 bits wide
+  ASSERT_EQ(0, binary->code[instIndex++]);   // NOTE: Unsigned
+
+  ASSERT_EQ(spvOpcodeMake(4, OpTypeInt), binary->code[instIndex++]);
+  ASSERT_EQ(7, binary->code[instIndex++]);
+  ASSERT_EQ(16, binary->code[instIndex++]);  // NOTE: 16 bits wide
+  ASSERT_EQ(1, binary->code[instIndex++]);   // NOTE: Signed
+
+  ASSERT_EQ(spvOpcodeMake(4, OpTypeInt), binary->code[instIndex++]);
+  ASSERT_EQ(8, binary->code[instIndex++]);
+  ASSERT_EQ(32, binary->code[instIndex++]);  // NOTE: 32 bits wide
+  ASSERT_EQ(0, binary->code[instIndex++]);   // NOTE: Unsigned
+
+  ASSERT_EQ(spvOpcodeMake(4, OpTypeInt), binary->code[instIndex++]);
+  ASSERT_EQ(9, binary->code[instIndex++]);
+  ASSERT_EQ(32, binary->code[instIndex++]);  // NOTE: 32 bits wide
+  ASSERT_EQ(1, binary->code[instIndex++]);   // NOTE: Signed
+
+  ASSERT_EQ(spvOpcodeMake(4, OpTypeInt), binary->code[instIndex++]);
+  ASSERT_EQ(10, binary->code[instIndex++]);
+  ASSERT_EQ(64, binary->code[instIndex++]);  // NOTE: 64 bits wide
+  ASSERT_EQ(0, binary->code[instIndex++]);   // NOTE: Unsigned
+
+  ASSERT_EQ(spvOpcodeMake(4, OpTypeInt), binary->code[instIndex++]);
+  ASSERT_EQ(11, binary->code[instIndex++]);
+  ASSERT_EQ(64, binary->code[instIndex++]);  // NOTE: 64 bits wide
+  ASSERT_EQ(1, binary->code[instIndex++]);   // NOTE: Signed
+
+  ASSERT_EQ(spvOpcodeMake(3, OpTypeFloat), binary->code[instIndex++]);
+  ASSERT_EQ(12, binary->code[instIndex++]);
+  ASSERT_EQ(16, binary->code[instIndex++]);  // NOTE: 16 bits wide
+
+  ASSERT_EQ(spvOpcodeMake(3, OpTypeFloat), binary->code[instIndex++]);
+  ASSERT_EQ(13, binary->code[instIndex++]);
+  ASSERT_EQ(32, binary->code[instIndex++]);  // NOTE: 32 bits wide
+
+  ASSERT_EQ(spvOpcodeMake(3, OpTypeFloat), binary->code[instIndex++]);
+  ASSERT_EQ(14, binary->code[instIndex++]);
+  ASSERT_EQ(64, binary->code[instIndex++]);  // NOTE: 64 bits wide
+
+  ASSERT_EQ(spvOpcodeMake(4, OpTypeVector), binary->code[instIndex++]);
+  ASSERT_EQ(15, binary->code[instIndex++]);
+  ASSERT_EQ(4, binary->code[instIndex++]);
+  ASSERT_EQ(2, binary->code[instIndex++]);
+}
+
+class TextToBinaryTest : public ::testing::Test {
+ public:
+  TextToBinaryTest()
+      : binary(nullptr),
+        text(),
+        opcodeTable(nullptr),
+        operandTable(nullptr),
+        diagnostic(nullptr) {}
+
+  virtual void SetUp() {
+    char textStr[] =
+        "OpEntryPoint Kernel 0\n"
+        "OpExecutionMode 0 LocalSizeHint 1 1 1\n";
+    text.str = textStr;
+    text.length = strlen(textStr);
+    ASSERT_EQ(SPV_SUCCESS, spvOpcodeTableGet(&opcodeTable));
+    ASSERT_EQ(SPV_SUCCESS, spvOperandTableGet(&operandTable));
+    ASSERT_EQ(SPV_SUCCESS, spvExtInstTableGet(&extInstTable));
+  }
+
+  virtual void TearDown() {
+    if (diagnostic) {
+      spvDiagnosticDestroy(diagnostic);
+    }
+  }
+
+  spv_binary binary;
+  spv_text_t text;
+  spv_opcode_table opcodeTable;
+  spv_operand_table operandTable;
+  spv_ext_inst_table extInstTable;
+  spv_diagnostic diagnostic;
+};
+
+TEST_F(TextToBinaryTest, InvalidText) {
+  spv_text_t text = {nullptr, 0};
+  spv_binary binary;
+  ASSERT_EQ(SPV_ERROR_INVALID_TEXT,
+            spvTextToBinary(&text, opcodeTable, operandTable, extInstTable,
+                            &binary, &diagnostic));
+}
+
+TEST_F(TextToBinaryTest, InvalidTable) {
+  ASSERT_EQ(SPV_ERROR_INVALID_TABLE,
+            spvTextToBinary(&text, nullptr, operandTable, extInstTable, &binary,
+                            &diagnostic));
+  ASSERT_EQ(SPV_ERROR_INVALID_TABLE,
+            spvTextToBinary(&text, opcodeTable, nullptr, extInstTable, &binary,
+                            &diagnostic));
+  ASSERT_EQ(SPV_ERROR_INVALID_TABLE,
+            spvTextToBinary(&text, opcodeTable, operandTable, nullptr, &binary,
+                            &diagnostic));
+}
+
+TEST_F(TextToBinaryTest, InvalidPointer) {
+  ASSERT_EQ(SPV_ERROR_INVALID_POINTER,
+            spvTextToBinary(&text, opcodeTable, operandTable, extInstTable,
+                            nullptr, &diagnostic));
+}
+
+TEST_F(TextToBinaryTest, InvalidDiagnostic) {
+  spv_binary binary;
+  ASSERT_EQ(SPV_ERROR_INVALID_DIAGNOSTIC,
+            spvTextToBinary(&text, opcodeTable, operandTable, extInstTable,
+                            &binary, nullptr));
+}
+
+TEST_F(TextToBinaryTest, InvalidPrefix) {
+  const char *spirv = R"(
+Invalid)";
+  text.str = spirv;
+  text.length = strlen(spirv);
+  ASSERT_EQ(SPV_ERROR_INVALID_TEXT,
+            spvTextToBinary(&text, opcodeTable, operandTable, extInstTable,
+                            &binary, &diagnostic));
+  if (diagnostic) {
+    spvDiagnosticPrint(diagnostic);
+  }
+}
+
+TEST_F(TextToBinaryTest, ImmediateIntOpCode) {
+  const char *spirv = R"(
+!0x00FF00FF
+)";
+  text.str = spirv;
+  text.length = strlen(spirv);
+  ASSERT_EQ(SPV_SUCCESS, spvTextToBinary(&text, opcodeTable, operandTable,
+                                         extInstTable, &binary, &diagnostic));
+  EXPECT_EQ(0x00FF00FF, binary->code[5]);
+  spvBinaryDestroy(binary);
+  if (diagnostic) {
+    spvDiagnosticPrint(diagnostic);
+  }
+}
+
+TEST_F(TextToBinaryTest, ImmediateIntOperand) {
+  const char *spirv = R"(
+OpCapability !0x00FF00FF)";
+  text.str = spirv;
+  text.length = strlen(spirv);
+  EXPECT_EQ(SPV_SUCCESS, spvTextToBinary(&text, opcodeTable, operandTable,
+                                         extInstTable, &binary, &diagnostic));
+  EXPECT_EQ(0x00FF00FF, binary->code[6]);
+  spvBinaryDestroy(binary);
+  if (diagnostic) {
+    spvDiagnosticPrint(diagnostic);
+  }
+}
+
+TEST_F(TextToBinaryTest, ExtInst) {
+  const char *spirv = R"(
+OpCapability Shader
+OpExtInstImport %glsl450 "GLSL.std.450"
+OpMemoryModel Logical Simple
+OpEntryPoint Vertex $main "main"
+OpTypeVoid %void
+OpTypeFloat %float 32
+OpConstant $float %const1.5 1.5
+OpTypeFunction %fnMain %void
+OpFunction $void %main None $fnMain
+OpLabel %lbMain
+OpExtInst $float %result $glsl450 round $const1.5
+OpReturn
+OpFunctionEnd
+)";
+  text.str = spirv;
+  text.length = strlen(spirv);
+  EXPECT_EQ(SPV_SUCCESS, spvTextToBinary(&text, opcodeTable, operandTable,
+                                         extInstTable, &binary, &diagnostic));
+  if (binary) {
+    spvBinaryDestroy(binary);
+  }
+  if (diagnostic) {
+    spvDiagnosticPrint(diagnostic);
+  }
+}
+
+TEST_F(TextToBinaryTest, StringSpace) {
+  const char *spirv = R"(
+OpSourceExtension "string with spaces"
+)";
+  text.str = spirv;
+  text.length = strlen(spirv);
+  EXPECT_EQ(SPV_SUCCESS, spvTextToBinary(&text, opcodeTable, operandTable,
+                                         extInstTable, &binary, &diagnostic));
+  if (binary) {
+    spvBinaryDestroy(binary);
+  }
+  if (diagnostic) {
+    spvDiagnosticPrint(diagnostic);
+  }
+}
diff --git a/test/TextWordGet.cpp b/test/TextWordGet.cpp
new file mode 100644 (file)
index 0000000..b67b788
--- /dev/null
@@ -0,0 +1,97 @@
+// Copyright (c) 2015 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.
+
+#include "UnitSPIRV.h"
+
+TEST(TextWordGet, NullTerminator) {
+  char textStr[] = "Word";
+  spv_text_t text = {textStr, strlen(textStr)};
+  spv_position_t startPosition = {};
+  std::string word;
+  spv_position_t endPosition = {};
+  ASSERT_EQ(SPV_SUCCESS,
+            spvTextWordGet(&text, &startPosition, word, &endPosition));
+  ASSERT_EQ(4, endPosition.column);
+  ASSERT_EQ(0, endPosition.line);
+  ASSERT_EQ(4, endPosition.index);
+  ASSERT_STREQ("Word", word.c_str());
+}
+
+TEST(TextWordGet, TabTerminator) {
+  char textStr[] = "Word\t";
+  spv_text_t text = {textStr, strlen(textStr)};
+  spv_position_t startPosition = {};
+  std::string word;
+  spv_position_t endPosition = {};
+  ASSERT_EQ(SPV_SUCCESS,
+            spvTextWordGet(&text, &startPosition, word, &endPosition));
+  ASSERT_EQ(4, endPosition.column);
+  ASSERT_EQ(0, endPosition.line);
+  ASSERT_EQ(4, endPosition.index);
+  ASSERT_STREQ("Word", word.c_str());
+}
+
+TEST(TextWordGet, SpaceTerminator) {
+  char textStr[] = "Word ";
+  spv_text_t text = {textStr, strlen(textStr)};
+  spv_position_t startPosition = {};
+  std::string word;
+  spv_position_t endPosition = {};
+  ASSERT_EQ(SPV_SUCCESS,
+            spvTextWordGet(&text, &startPosition, word, &endPosition));
+  ASSERT_EQ(4, endPosition.column);
+  ASSERT_EQ(0, endPosition.line);
+  ASSERT_EQ(4, endPosition.index);
+  ASSERT_STREQ("Word", word.c_str());
+}
+
+TEST(TextWordGet, MultipleWords) {
+  char textStr[] = "Words in a sentence";
+  spv_text_t text = {textStr, strlen(textStr)};
+  const char *words[] = {"Words", "in", "a", "sentence"};
+
+  spv_position_t startPosition = {};
+  spv_position_t endPosition = {};
+
+  std::string word;
+  for (uint32_t wordIndex = 0; wordIndex < 4; ++wordIndex) {
+    ASSERT_EQ(SPV_SUCCESS,
+              spvTextWordGet(&text, &startPosition, word, &endPosition));
+    ASSERT_EQ(strlen(words[wordIndex]),
+              endPosition.column - startPosition.column);
+    ASSERT_EQ(0, endPosition.line);
+    ASSERT_EQ(strlen(words[wordIndex]),
+              endPosition.index - startPosition.index);
+    ASSERT_STREQ(words[wordIndex], word.c_str());
+
+    startPosition = endPosition;
+    if (3 != wordIndex) {
+      ASSERT_EQ(SPV_SUCCESS, spvTextAdvance(&text, &startPosition));
+    } else {
+      ASSERT_EQ(SPV_END_OF_STREAM, spvTextAdvance(&text, &startPosition));
+    }
+  }
+}
diff --git a/test/UnitSPIRV.h b/test/UnitSPIRV.h
new file mode 100644 (file)
index 0000000..60b4889
--- /dev/null
@@ -0,0 +1,54 @@
+// Copyright (c) 2015 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.
+
+#ifndef _CODEPLAY_UNITBIL_H_
+#define _CODEPLAY_UNITBIL_H_
+
+#include <libspirv/libspirv.h>
+#include "../source/binary.h"
+#include "../source/diagnostic.h"
+#include "../source/opcode.h"
+#include "../source/text.h"
+#include "../source/validate.h"
+
+#include <gtest/gtest.h>
+
+#include <stdint.h>
+
+// Determine endianness & predicate tests on it
+enum {
+  I32_ENDIAN_LITTLE = 0x03020100ul,
+  I32_ENDIAN_BIG = 0x00010203ul,
+};
+
+static const union {
+  unsigned char bytes[4];
+  uint32_t value;
+} o32_host_order = {{0, 1, 2, 3}};
+
+#define I32_ENDIAN_HOST (o32_host_order.value)
+
+#endif
diff --git a/test/Validate.cpp b/test/Validate.cpp
new file mode 100644 (file)
index 0000000..351bb50
--- /dev/null
@@ -0,0 +1,119 @@
+// Copyright (c) 2015 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.
+
+#include "UnitSPIRV.h"
+
+class Validate : public ::testing::Test {
+ public:
+  Validate() : binary(), opcodeTable(nullptr), operandTable(nullptr) {}
+
+  virtual void SetUp() {
+    ASSERT_EQ(SPV_SUCCESS, spvOpcodeTableGet(&opcodeTable));
+    ASSERT_EQ(SPV_SUCCESS, spvOperandTableGet(&operandTable));
+    ASSERT_EQ(SPV_SUCCESS, spvExtInstTableGet(&extInstTable));
+  }
+
+  virtual void TearDown() { spvBinaryDestroy(binary); }
+
+  spv_binary binary;
+  spv_opcode_table opcodeTable;
+  spv_operand_table operandTable;
+  spv_ext_inst_table extInstTable;
+};
+
+TEST_F(Validate, DISABLED_Default) {
+  char str[] = R"(
+OpMemoryModel Logical GLSL450
+OpEntryPoint GLCompute 1
+OpExecutionMode 1 LocalSize 1 1 1
+OpTypeVoid 2
+OpTypeFunction 3 2
+OpFunction 2 1 NoControl 3
+OpLabel 4
+OpReturn
+OpFunctionEnd
+)";
+  spv_text_t text = {str, strlen(str)};
+  spv_diagnostic diagnostic = nullptr;
+  ASSERT_EQ(SPV_SUCCESS, spvTextToBinary(&text, opcodeTable, operandTable,
+                                         extInstTable, &binary, &diagnostic));
+  ASSERT_EQ(SPV_SUCCESS,
+            spvValidate(binary, opcodeTable, operandTable, extInstTable,
+                        SPV_VALIDATE_ALL, &diagnostic));
+  if (diagnostic) {
+    spvDiagnosticPrint(diagnostic);
+    spvDiagnosticDestroy(diagnostic);
+  }
+}
+
+TEST_F(Validate, DISABLED_InvalidIdUndefined) {
+  char str[] = R"(
+OpMemoryModel Logical GLSL450
+OpEntryPoint GLCompute 1
+OpExecutionMode 5 LocalSize 1 1 1
+OpTypeVoid 2
+OpTypeFunction 3 2
+OpFunction 2 1 NoControl 3
+OpLabel 4
+OpReturn
+OpFunctionEnd
+)";
+  spv_text_t text = {str, strlen(str)};
+  spv_diagnostic diagnostic = nullptr;
+  ASSERT_EQ(SPV_SUCCESS, spvTextToBinary(&text, opcodeTable, operandTable,
+                                         extInstTable, &binary, &diagnostic));
+  ASSERT_EQ(SPV_ERROR_INVALID_ID,
+            spvValidate(binary, opcodeTable, operandTable, extInstTable,
+                        SPV_VALIDATE_ALL, &diagnostic));
+  ASSERT_NE(nullptr, diagnostic);
+  spvDiagnosticPrint(diagnostic);
+  spvDiagnosticDestroy(diagnostic);
+}
+
+TEST_F(Validate, DISABLED_InvalidIdRedefined) {
+  char str[] = R"(
+OpMemoryModel Logical GLSL450
+OpEntryPoint GLCompute 1
+OpExecutionMode 1 LocalSize 1 1 1
+OpTypeVoid 2
+OpTypeFunction 2 2
+OpFunction 2 1 NoControl 3
+OpLabel 4
+OpReturn
+OpFunctionEnd
+)";
+  spv_text_t text = {str, strlen(str)};
+  spv_diagnostic diagnostic = nullptr;
+  ASSERT_EQ(SPV_SUCCESS, spvTextToBinary(&text, opcodeTable, operandTable,
+                                         extInstTable, &binary, &diagnostic));
+  // TODO: Fix setting of bound in spvTextTo, then remove this!
+  ASSERT_EQ(SPV_ERROR_INVALID_ID,
+            spvValidate(binary, opcodeTable, operandTable, extInstTable,
+                        SPV_VALIDATE_ALL, &diagnostic));
+  ASSERT_NE(nullptr, diagnostic);
+  spvDiagnosticPrint(diagnostic);
+  spvDiagnosticDestroy(diagnostic);
+}
diff --git a/test/ValidateID.cpp b/test/ValidateID.cpp
new file mode 100644 (file)
index 0000000..13c0f31
--- /dev/null
@@ -0,0 +1,1342 @@
+// Copyright (c) 2015 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.
+
+#include "UnitSPIRV.h"
+
+// NOTE: The tests in this file are ONLY testing ID usage, there for the input
+// SPIR-V does not follow the logical layout rules from the spec in all cases in
+// order to makes the tests smaller. Validation of the whole module is handled
+// in stages, ID validation is only one of these stages. All validation stages
+// are stand alone.
+
+class ValidateID : public ::testing::Test {
+ public:
+  ValidateID() : opcodeTable(nullptr), operandTable(nullptr), binary() {}
+
+  virtual void SetUp() {
+    ASSERT_EQ(SPV_SUCCESS, spvOpcodeTableGet(&opcodeTable));
+    ASSERT_EQ(SPV_SUCCESS, spvOperandTableGet(&operandTable));
+    ASSERT_EQ(SPV_SUCCESS, spvExtInstTableGet(&extInstTable));
+  }
+
+  virtual void TearDown() { spvBinaryDestroy(binary); }
+
+  spv_opcode_table opcodeTable;
+  spv_operand_table operandTable;
+  spv_ext_inst_table extInstTable;
+  spv_binary binary;
+};
+
+#define CHECK(str, expected)                                                \
+  spv_text_t text = {str, strlen(str)};                                     \
+  spv_diagnostic diagnostic;                                                \
+  spv_result_t error = spvTextToBinary(&text, opcodeTable, operandTable,    \
+                                       extInstTable, &binary, &diagnostic); \
+  if (error) {                                                              \
+    spvDiagnosticPrint(diagnostic);                                         \
+    spvDiagnosticDestroy(diagnostic);                                       \
+    ASSERT_EQ(SPV_SUCCESS, error);                                          \
+  }                                                                         \
+  spv_result_t result =                                                     \
+      spvValidate(binary, opcodeTable, operandTable, extInstTable,          \
+                  SPV_VALIDATE_ID_BIT, &diagnostic);                        \
+  if (SPV_SUCCESS != result) {                                              \
+    spvDiagnosticPrint(diagnostic);                                         \
+    spvDiagnosticDestroy(diagnostic);                                       \
+  }                                                                         \
+  ASSERT_EQ(expected, result);
+
+// TODO: OpUndef
+
+TEST_F(ValidateID, OpName) {
+  const char *spirv = R"(
+OpName $2 "name"
+OpTypeInt %1 32 0
+OpTypePointer %2 UniformConstant $1
+OpVariable $2 %3 UniformConstant)";
+  CHECK(spirv, SPV_SUCCESS);
+}
+
+TEST_F(ValidateID, OpMemberNameGood) {
+  const char *spirv = R"(
+OpMemberName $2 0 "foo"
+OpTypeInt %1 32 0
+OpTypeStruct %2 $1)";
+  CHECK(spirv, SPV_SUCCESS);
+}
+TEST_F(ValidateID, OpMemberNameTypeBad) {
+  const char *spirv = R"(
+OpMemberName $1 0 "foo"
+OpTypeInt %1 32 0)";
+  CHECK(spirv, SPV_ERROR_INVALID_ID);
+}
+TEST_F(ValidateID, OpMemberNameMemberBad) {
+  const char *spirv = R"(
+OpMemberName $2 1 "foo"
+OpTypeInt %1 32 0
+OpTypeStruct %2 $1)";
+  CHECK(spirv, SPV_ERROR_INVALID_ID);
+}
+
+TEST_F(ValidateID, OpLineGood) {
+  const char *spirv = R"(
+OpString %1 "/path/to/source.file"
+OpLine $4 $1 0 0
+OpTypeInt %2 32 0
+OpTypePointer %3 Generic $2
+OpVariable $3 %4 Generic)";
+  CHECK(spirv, SPV_SUCCESS);
+}
+TEST_F(ValidateID, OpLineFileBad) {
+  const char *spirv = R"(
+OpLine $4 $2 0 0
+OpTypeInt %2 32 0
+OpTypePointer %3 Generic $2
+OpVariable $3 %4 Generic)";
+  CHECK(spirv, SPV_ERROR_INVALID_ID);
+}
+
+TEST_F(ValidateID, OpDecorateGood) {
+  const char *spirv = R"(
+OpDecorate $2 GLSLShared
+OpTypeInt %1 64 0
+OpTypeStruct %2 $1 $1)";
+  CHECK(spirv, SPV_SUCCESS);
+}
+TEST_F(ValidateID, OpDecorateBad) {
+  const char *spirv = R"(
+OpDecorate $1 GLSLShared)";
+  CHECK(spirv, SPV_ERROR_INVALID_ID);
+}
+
+TEST_F(ValidateID, OpMemberDecorateGood) {
+  const char *spirv = R"(
+OpMemberDecorate $2 0 Uniform
+OpTypeInt %1 32 0
+OpTypeStruct %2 $1 $1)";
+  CHECK(spirv, SPV_SUCCESS);
+}
+TEST_F(ValidateID, OpMemberDecorateBad) {
+  const char *spirv = R"(
+OpMemberDecorate $1 0 Uniform
+OpTypeInt %1 32 0)";
+  CHECK(spirv, SPV_ERROR_INVALID_ID);
+}
+TEST_F(ValidateID, OpMemberDecorateMemberBad) {
+  const char *spirv = R"(
+OpMemberDecorate $2 3 Uniform
+OpTypeInt %1 32 0
+OpTypeStruct %2 $1 $1)";
+  CHECK(spirv, SPV_ERROR_INVALID_ID);
+}
+
+TEST_F(ValidateID, OpGroupDecorateGood) {
+  const char *spirv = R"(
+OpDecorationGroup %1
+OpDecorate $1 Uniform
+OpDecorate $1 GLSLStd430
+OpGroupDecorate $1 $3 $4
+OpTypeInt %2 32 0
+OpConstant $2 %3 42
+OpConstant $2 %4 23)";
+  CHECK(spirv, SPV_SUCCESS);
+}
+TEST_F(ValidateID, OpGroupDecorateDecorationGroupBad) {
+  const char *spirv = R"(
+OpGroupDecorate $2 $3 $4
+OpTypeInt %2 32 0
+OpConstant $2 %3 42
+OpConstant $2 %4 23)";
+  CHECK(spirv, SPV_ERROR_INVALID_ID);
+}
+TEST_F(ValidateID, OpGroupDecorateTargetBad) {
+  const char *spirv = R"(
+OpDecorationGroup %1
+OpDecorate $1 Uniform
+OpDecorate $1 GLSLStd430
+OpGroupDecorate $1 $3
+OpTypeInt %2 32 0)";
+  CHECK(spirv, SPV_ERROR_INVALID_ID);
+}
+
+// TODO: OpGroupMemberDecorate
+// TODO: OpExtInst
+
+TEST_F(ValidateID, OpEntryPointGood) {
+  const char *spirv = R"(
+OpEntryPoint GLCompute $3
+OpTypeVoid %1
+OpTypeFunction %2 $1
+OpFunction $1 %3 None $2
+OpLabel %4
+OpReturn
+OpFunctionEnd
+)";
+  CHECK(spirv, SPV_SUCCESS);
+}
+TEST_F(ValidateID, OpEntryPointFunctionBad) {
+  const char *spirv = R"(
+OpEntryPoint GLCompute $1
+OpTypeVoid %1)";
+  CHECK(spirv, SPV_ERROR_INVALID_ID);
+}
+TEST_F(ValidateID, OpEntryPointParameterCountBad) {
+  const char *spirv = R"(
+OpEntryPoint GLCompute $3
+OpTypeVoid %1
+OpTypeFunction %2 $1 $1
+OpFunction $1 %3 None $2
+OpLabel %4
+OpReturn
+OpFunctionEnd)";
+  CHECK(spirv, SPV_ERROR_INVALID_ID);
+}
+TEST_F(ValidateID, OpEntryPointReturnTypeBad) {
+  const char *spirv = R"(
+OpEntryPoint GLCompute $3
+OpTypeInt %1 32 0
+OpTypeFunction %2 $1
+OpFunction $1 %3 None $2
+OpLabel %4
+OpReturn
+OpFunctionEnd)";
+  CHECK(spirv, SPV_ERROR_INVALID_ID);
+}
+
+TEST_F(ValidateID, OpExecutionModeGood) {
+  const char *spirv = R"(
+OpEntryPoint GLCompute $3
+OpExecutionMode $3 LocalSize 1 1 1
+OpTypeVoid %1
+OpTypeFunction %2 $1
+OpFunction $1 %3 None $2
+OpLabel %4
+OpReturn
+OpFunctionEnd)";
+  CHECK(spirv, SPV_SUCCESS);
+}
+TEST_F(ValidateID, OpExecutionModeEntryPointBad) {
+  const char *spirv = R"(
+OpExecutionMode $3 LocalSize 1 1 1
+OpTypeVoid %1
+OpTypeFunction %2 $1
+OpFunction $1 %3 None $2
+OpLabel %4
+OpReturn
+OpFunctionEnd)";
+  CHECK(spirv, SPV_ERROR_INVALID_ID);
+}
+
+TEST_F(ValidateID, OpTypeVectorGood) {
+  const char *spirv = R"(
+OpTypeFloat %1 32
+OpTypeVector %2 $1 4)";
+  CHECK(spirv, SPV_SUCCESS);
+}
+TEST_F(ValidateID, OpTypeVectorComponentTypeBad) {
+  const char *spirv = R"(
+OpTypeFloat %1 32
+OpTypePointer %2 UniformConstant $1
+OpTypeVector %3 $2 4)";
+  CHECK(spirv, SPV_ERROR_INVALID_ID);
+}
+
+TEST_F(ValidateID, OpTypeMatrixGood) {
+  const char *spirv = R"(
+OpTypeInt %1 32 0
+OpTypeVector %2 $1 2
+OpTypeMatrix %3 $2 3)";
+  CHECK(spirv, SPV_SUCCESS);
+}
+TEST_F(ValidateID, OpTypeMatrixColumnTypeBad) {
+  const char *spirv = R"(
+OpTypeInt %1 32 0
+OpTypeMatrix %2 $1 3)";
+  CHECK(spirv, SPV_ERROR_INVALID_ID);
+}
+
+TEST_F(ValidateID, OpTypeSamplerGood) {
+  const char *spirv = R"(
+OpTypeFloat %1 32
+OpTypeSampler %2 $1 2D 0 0 0 0)";
+  CHECK(spirv, SPV_SUCCESS);
+}
+TEST_F(ValidateID, OpTypeSamplerSampledTypeBad) {
+  const char *spirv = R"(
+OpTypeVoid %1
+OpTypeSampler %2 $1 2D 0 0 0 0)";
+  CHECK(spirv, SPV_ERROR_INVALID_ID);
+}
+
+TEST_F(ValidateID, OpTypeArrayGood) {
+  const char *spirv = R"(
+OpTypeInt %1 32 0
+OpConstant $1 %2 1
+OpTypeArray %3 $1 $2)";
+  CHECK(spirv, SPV_SUCCESS);
+}
+TEST_F(ValidateID, OpTypeArrayElementTypeBad) {
+  const char *spirv = R"(
+OpTypeInt %1 32 0
+OpConstant $1 %2 1
+OpTypeArray %3 $2 $2)";
+  CHECK(spirv, SPV_ERROR_INVALID_ID);
+}
+TEST_F(ValidateID, OpTypeArrayLengthBad) {
+  const char *spirv = R"(
+OpTypeInt %1 32 0
+OpConstant $1 %2 0
+OpTypeArray %3 $1 $2)";
+  CHECK(spirv, SPV_ERROR_INVALID_ID);
+}
+
+TEST_F(ValidateID, OpTypeRuntimeArrayGood) {
+  const char *spirv = R"(
+OpTypeInt %1 32 0
+OpTypeRuntimeArray %2 $1)";
+  CHECK(spirv, SPV_SUCCESS);
+}
+TEST_F(ValidateID, OpTypeRuntimeArrayBad) {
+  const char *spirv = R"(
+OpTypeInt %1 32 0
+OpConstant $1 %2 0
+OpTypeRuntimeArray %3 $2)";
+  CHECK(spirv, SPV_ERROR_INVALID_ID);
+}
+// TODO: Object of this type can only be created with OpVariable using the
+// Unifrom Storage Class
+
+TEST_F(ValidateID, OpTypeStructGood) {
+  const char *spirv = R"(
+OpTypeInt %1 32 0
+OpTypeFloat %2 64
+OpTypePointer %3 Generic $1
+OpTypeStruct %4 $1 $2 $3)";
+  CHECK(spirv, SPV_SUCCESS);
+}
+TEST_F(ValidateID, OpTypeStructMemberTypeBad) {
+  const char *spirv = R"(
+OpTypeInt %1 32 0
+OpTypeFloat %2 64
+OpConstant $2 %3 0.0
+OpTypeStruct %4 $1 $2 $3)";
+  CHECK(spirv, SPV_ERROR_INVALID_ID);
+}
+
+TEST_F(ValidateID, OpTypePointerGood) {
+  const char *spirv = R"(
+OpTypeInt %1 32 0
+OpTypePointer %2 Generic $1)";
+  CHECK(spirv, SPV_SUCCESS);
+}
+TEST_F(ValidateID, OpTypePointerBad) {
+  const char *spirv = R"(
+OpTypeInt %1 32 0
+OpConstant $1 %2 0
+OpTypePointer %3 Generic $2)";
+  CHECK(spirv, SPV_ERROR_INVALID_ID);
+}
+
+TEST_F(ValidateID, OpTypeFunctionGood) {
+  const char *spirv = R"(
+OpTypeVoid %1
+OpTypeFunction %2 $1)";
+  CHECK(spirv, SPV_SUCCESS);
+}
+TEST_F(ValidateID, OpTypeFunctionReturnTypeBad) {
+  const char *spirv = R"(
+OpTypeInt %1 32 0
+OpConstant $1 %2 0
+OpTypeFunction %3 $2)";
+  CHECK(spirv, SPV_ERROR_INVALID_ID);
+}
+TEST_F(ValidateID, OpTypeFunctionParameterBad) {
+  const char *spirv = R"(
+OpTypeVoid %1
+OpTypeInt %2 32 0
+OpConstant $2 %3 0
+OpTypeFunction %4 $1 $2 $3)";
+  CHECK(spirv, SPV_ERROR_INVALID_ID);
+}
+
+TEST_F(ValidateID, OpTypePipeGood) {
+  const char *spirv = R"(
+OpTypeFloat %1 32
+OpTypeVector %2 $1 16
+OpTypePipe %3 $2 ReadOnly)";
+  CHECK(spirv, SPV_SUCCESS);
+}
+TEST_F(ValidateID, OpTypePipeBad) {
+  const char *spirv = R"(
+OpTypeFloat %1 32
+OpConstant $1 %2 0
+OpTypePipe %3 $2 ReadOnly)";
+  CHECK(spirv, SPV_ERROR_INVALID_ID);
+}
+
+TEST_F(ValidateID, OpConstantTrueGood) {
+  const char *spirv = R"(
+OpTypeBool %1
+OpConstantTrue $1 %2)";
+  CHECK(spirv, SPV_SUCCESS);
+}
+TEST_F(ValidateID, OpConstantTrueBad) {
+  const char *spirv = R"(
+OpTypeVoid %1
+OpConstantTrue $1 %2)";
+  CHECK(spirv, SPV_ERROR_INVALID_ID);
+}
+
+TEST_F(ValidateID, OpConstantFalseGood) {
+  const char *spirv = R"(
+OpTypeBool %1
+OpConstantFalse $1 %2)";
+  CHECK(spirv, SPV_SUCCESS);
+}
+TEST_F(ValidateID, OpConstantFalseBad) {
+  const char *spirv = R"(
+OpTypeVoid %1
+OpConstantFalse $1 %2)";
+  CHECK(spirv, SPV_ERROR_INVALID_ID);
+}
+
+TEST_F(ValidateID, OpConstantGood) {
+  const char *spirv = R"(
+OpTypeInt %1 32 0
+OpConstant $1 %2 1)";
+  CHECK(spirv, SPV_SUCCESS);
+}
+TEST_F(ValidateID, OpConstantBad) {
+  const char *spirv = R"(
+OpTypeVoid %1
+OpConstant $1 %2 0)";
+  CHECK(spirv, SPV_ERROR_INVALID_ID);
+}
+
+TEST_F(ValidateID, OpConstantCompositeVectorGood) {
+  const char *spirv = R"(
+OpTypeFloat %1 32
+OpTypeVector %2 $1 4
+OpConstant $1 %3 3.14
+OpConstantComposite $2 %4 $3 $3 $3 $3)";
+  CHECK(spirv, SPV_SUCCESS);
+}
+TEST_F(ValidateID, OpConstantCompositeVectorResultTypeBad) {
+  const char *spirv = R"(
+OpTypeFloat %1 32
+OpTypeVector %2 $1 4
+OpConstant $1 %3 3.14
+OpConstantComposite $1 %4 $3 $3 $3 $3)";
+  CHECK(spirv, SPV_ERROR_INVALID_ID);
+}
+TEST_F(ValidateID, OpConstantCompositeVectorConstituentBad) {
+  const char *spirv = R"(
+OpTypeFloat %1 32
+OpTypeVector %2 $1 4
+OpTypeInt %4 32 0
+OpConstant $1 %3 3.14
+OpConstant $4 %5 42
+OpConstantComposite $2 %6 $3 $5 $3 $3)";
+  CHECK(spirv, SPV_ERROR_INVALID_ID);
+}
+TEST_F(ValidateID, OpConstantCompositeMatrixGood) {
+  const char *spirv = R"(
+OpTypeFloat %1 32
+OpTypeVector %2 $1 4
+OpTypeMatrix %3 $2 4
+OpConstant $1 %4 1.0
+OpConstant $1 %5 0.0
+OpConstantComposite $2 %6 $4 $5 $5 $5
+OpConstantComposite $2 %7 $5 $4 $5 $5
+OpConstantComposite $2 %8 $5 $5 $4 $5
+OpConstantComposite $2 %9 $5 $5 $5 $4
+OpConstantComposite $3 %10 $6 $7 $8 $9)";
+  CHECK(spirv, SPV_SUCCESS);
+}
+TEST_F(ValidateID, OpConstantCompositeMatrixConstituentBad) {
+  const char *spirv = R"(
+OpTypeFloat %1 32
+OpTypeVector %2 $1 4
+OpTypeVector %11 $1 3
+OpTypeMatrix %3 $2 4
+OpConstant $1 %4 1.0
+OpConstant $1 %5 0.0
+OpConstantComposite $2 %6 $4 $5 $5 $5
+OpConstantComposite $2 %7 $5 $4 $5 $5
+OpConstantComposite $2 %8 $5 $5 $4 $5
+OpConstantComposite $11 %9 $5 $5 $5
+OpConstantComposite $3 %10 $6 $7 $8 $9)";
+  CHECK(spirv, SPV_ERROR_INVALID_ID);
+}
+TEST_F(ValidateID, OpConstantCompositeMatrixColumnTypeBad) {
+  const char *spirv = R"(
+OpTypeInt %1 32 0
+OpTypeFloat %2 32
+OpTypeVector %3 $1 2
+OpTypeVector %4 $3 2
+OpTypeMatrix %5 $2 2
+OpConstant $1 %6 42
+OpConstant $2 %7 3.14
+OpConstantComposite $3 %8 $6 $6
+OpConstantComposite $4 %9 $7 $7
+OpConstantComposite $5 %10 $8 $9)";
+  CHECK(spirv, SPV_ERROR_INVALID_ID);
+}
+TEST_F(ValidateID, OpConstantCompositeArrayGood) {
+  const char *spirv = R"(
+OpTypeInt %1 32 0
+OpConstant $1 %2 4
+OpTypeArray %3 $1 $2
+OpConstantComposite $3 %4 $2 $2 $2 $2)";
+  CHECK(spirv, SPV_SUCCESS);
+}
+TEST_F(ValidateID, OpConstantCompositeArrayConstConstituentBad) {
+  const char *spirv = R"(
+OpTypeInt %1 32 0
+OpConstant $1 %2 4
+OpTypeArray %3 $1 $2
+OpConstantComposite $3 %4 $2 $2 $2 $1)";
+  CHECK(spirv, SPV_ERROR_INVALID_ID);
+}
+TEST_F(ValidateID, OpConstantCompositeArrayConstituentBad) {
+  const char *spirv = R"(
+OpTypeInt %1 32 0
+OpConstant $1 %2 4
+OpTypeArray %3 $1 $2
+OpTypeFloat %5 32
+OpConstant $5 %6 3.14
+OpConstantComposite $3 %4 $2 $2 $2 $6)";
+  CHECK(spirv, SPV_ERROR_INVALID_ID);
+}
+TEST_F(ValidateID, OpConstantCompositeStructGood) {
+  const char *spirv = R"(
+OpTypeInt %1 32 0
+OpTypeInt %2 64 1
+OpTypeStruct %3 $1 $1 $2
+OpConstant $1 %4 42
+OpConstant $2 %5 4300000000
+OpConstantComposite $3 %6 $4 $4 $5)";
+  CHECK(spirv, SPV_SUCCESS);
+}
+TEST_F(ValidateID, OpConstantCompositeStructMemberBad) {
+  const char *spirv = R"(
+OpTypeInt %1 32 0
+OpTypeInt %2 64 1
+OpTypeStruct %3 $1 $1 $2
+OpConstant $1 %4 42
+OpConstant $2 %5 4300000000
+OpConstantComposite $3 %6 $4 $5 $4)";
+  CHECK(spirv, SPV_ERROR_INVALID_ID);
+}
+
+TEST_F(ValidateID, OpConstantSamplerGood) {
+  const char *spirv = R"(
+OpTypeFloat %1 32
+OpTypeSampler %2 $1 2D 1 0 1 0
+OpConstantSampler $2 %3 ClampToEdge 0 Nearest)";
+  CHECK(spirv, SPV_SUCCESS);
+}
+TEST_F(ValidateID, OpConstantSamplerResultTypeBad) {
+  const char *spirv = R"(
+OpTypeFloat %1 32
+OpConstantSampler $1 %2 Clamp 0 Nearest)";
+  CHECK(spirv, SPV_ERROR_INVALID_ID);
+}
+
+TEST_F(ValidateID, OpConstantNullGood) {
+  const char *spirv = R"(
+OpTypeBool %1
+OpConstantNull $1 %2
+OpTypeInt %3 32 0
+OpConstantNull $3 %4
+OpTypeFloat %5 32
+OpConstantNull $5 %6
+OpTypePointer %7 UniformConstant $3
+OpConstantNull $7 %8
+OpTypeEvent %9
+OpConstantNull $9 %10
+OpTypeDeviceEvent %11
+OpConstantNull $11 %12
+OpTypeReserveId %13
+OpConstantNull $13 %14
+OpTypeQueue %15
+OpConstantNull $15 %16
+OpTypeVector %17 $3 2
+OpConstantNull $17 %18
+OpTypeMatrix %19 $17 2
+OpConstantNull $19 %20
+OpConstant $3 %25 8
+OpTypeArray %21 $3 $25
+OpConstantNull $21 %22
+OpTypeStruct %23 $3 $5 $1
+OpConstantNull $23 %24
+)";
+  CHECK(spirv, SPV_SUCCESS);
+}
+TEST_F(ValidateID, OpConstantNullBasicBad) {
+  const char *spirv = R"(
+OpTypeVoid %1
+OpConstantNull $1 %2)";
+  CHECK(spirv, SPV_ERROR_INVALID_ID);
+}
+TEST_F(ValidateID, OpConstantNullArrayBad) {
+  const char *spirv = R"(
+OpTypeInt %1 8 0
+OpTypeInt %2 32 0
+OpTypeSampler %3 $1 2D 0 0 0 0
+OpConstant $2 %4 4
+OpTypeArray %5 $3 $4
+OpConstantNull $5 %6)";
+  CHECK(spirv, SPV_ERROR_INVALID_ID);
+}
+TEST_F(ValidateID, OpConstantNullStructBad) {
+  const char *spirv = R"(
+OpTypeInt %1 8 0
+OpTypeSampler %2 $1 2D 0 0 0 0
+OpTypeStruct %3 $2 $2
+OpConstantNull $3 %4)";
+  CHECK(spirv, SPV_ERROR_INVALID_ID);
+}
+
+TEST_F(ValidateID, OpSpecConstantTrueGood) {
+  const char *spirv = R"(
+OpTypeBool %1
+OpSpecConstantTrue $1 %2)";
+  CHECK(spirv, SPV_SUCCESS);
+}
+TEST_F(ValidateID, OpSpecConstantTrueBad) {
+  const char *spirv = R"(
+OpTypeVoid %1
+OpSpecConstantTrue $1 %2)";
+  CHECK(spirv, SPV_ERROR_INVALID_ID);
+}
+
+TEST_F(ValidateID, OpSpecConstantFalseGood) {
+  const char *spirv = R"(
+OpTypeBool %1
+OpSpecConstantFalse $1 %2)";
+  CHECK(spirv, SPV_SUCCESS);
+}
+TEST_F(ValidateID, OpSpecConstantFalseBad) {
+  const char *spirv = R"(
+OpTypeVoid %1
+OpSpecConstantFalse $1 %2)";
+  CHECK(spirv, SPV_ERROR_INVALID_ID);
+}
+
+TEST_F(ValidateID, OpSpecConstantGood) {
+  const char *spirv = R"(
+OpTypeFloat %1 32
+OpSpecConstant $1 %2 42)";
+  CHECK(spirv, SPV_SUCCESS);
+}
+TEST_F(ValidateID, OpSpecConstantBad) {
+  const char *spirv = R"(
+OpTypeVoid %1
+OpSpecConstant $1 %2 3.14)";
+  CHECK(spirv, SPV_ERROR_INVALID_ID);
+}
+
+// TODO: OpSpecConstantComposite
+// TODO: OpSpecConstantOp
+
+TEST_F(ValidateID, OpVariableGood) {
+  const char *spirv = R"(
+OpTypeInt %1 32 1
+OpTypePointer %2 Generic $1
+OpVariable $2 %3 Generic)";
+  CHECK(spirv, SPV_SUCCESS);
+}
+TEST_F(ValidateID, OpVariableInitializerGood) {
+  const char *spirv = R"(
+OpTypeInt %1 32 1
+OpTypePointer %2 Generic $1
+OpConstant $1 %3 42
+OpVariable $2 %4 Generic $3)";
+  CHECK(spirv, SPV_SUCCESS);
+}
+// TODO: Positive test OpVariable with OpConstantNull of OpTypePointer
+TEST_F(ValidateID, OpVariableResultTypeBad) {
+  const char *spirv = R"(
+OpTypeInt %1 32 1
+OpVariable $1 %2 Generic)";
+  CHECK(spirv, SPV_ERROR_INVALID_ID);
+}
+TEST_F(ValidateID, OpVariableInitializerBad) {
+  const char *spirv = R"(
+OpTypeInt %1 32 1
+OpTypePointer %2 Generic $1
+OpVariable $2 %3 Generic $2)";
+  CHECK(spirv, SPV_ERROR_INVALID_ID);
+}
+
+TEST_F(ValidateID, OpLoadGood) {
+  const char *spirv = R"(
+OpTypeVoid %1
+OpTypeInt %2 32 1
+OpTypePointer %3 UniformConstant $2
+OpTypeFunction %4 $1
+OpVariable $3 %5 UniformConstant
+OpFunction $1 %6 None $4
+OpLabel %7
+OpLoad $3 %8 $5
+OpReturn
+OpFunctionEnd
+)";
+  CHECK(spirv, SPV_SUCCESS);
+}
+TEST_F(ValidateID, OpLoadResultTypeBad) {
+  const char *spirv = R"(
+OpTypeVoid %1
+OpTypeInt %2 32 1
+OpTypePointer %3 UniformConstant $2
+OpTypeFunction %4 $1
+OpVariable $3 %5 UniformConstant
+OpFunction $1 %6 None $4
+OpLabel %7
+OpLoad $2 %8 $5
+OpReturn
+OpFunctionEnd
+)";
+  CHECK(spirv, SPV_ERROR_INVALID_ID);
+}
+TEST_F(ValidateID, OpLoadPointerBad) {
+  const char *spirv = R"(
+OpTypeVoid %1
+OpTypeInt %2 32 1
+OpTypeFloat %9 32
+OpTypePointer %3 UniformConstant $2
+OpTypeFunction %4 $1
+OpFunction $1 %6 None $4
+OpLabel %7
+OpLoad $9 %8 $3
+OpReturn
+OpFunctionEnd
+)";
+  CHECK(spirv, SPV_ERROR_INVALID_ID);
+}
+
+TEST_F(ValidateID, OpStoreGood) {
+  const char *spirv = R"(
+OpTypeVoid %1
+OpTypeInt %2 32 1
+OpTypePointer %3 UniformConstant $2
+OpTypeFunction %4 $1
+OpConstant $2 %5 42
+OpVariable $3 %6 UniformConstant
+OpFunction $1 %7 None $4
+OpLabel %8
+OpStore $6 $5
+OpReturn
+OpFunctionEnd)";
+  CHECK(spirv, SPV_SUCCESS);
+}
+TEST_F(ValidateID, OpStorePointerBad) {
+  const char *spirv = R"(
+OpTypeVoid %1
+OpTypeInt %2 32 1
+OpTypePointer %3 UniformConstant $2
+OpTypeFunction %4 $1
+OpConstant $2 %5 42
+OpVariable $3 %6 UniformConstant
+OpFunction $1 %7 None $4
+OpLabel %8
+OpStore $3 $5
+OpReturn
+OpFunctionEnd)";
+  CHECK(spirv, SPV_ERROR_INVALID_ID);
+}
+TEST_F(ValidateID, OpStoreObjectGood) {
+  const char *spirv = R"(
+OpTypeVoid %1
+OpTypeInt %2 32 1
+OpTypePointer %3 UniformConstant $2
+OpTypeFunction %4 $1
+OpConstant $2 %5 42
+OpVariable $3 %6 UniformConstant
+OpFunction $1 %7 None $4
+OpLabel %8
+OpStore $6 $7
+OpReturn
+OpFunctionEnd)";
+  CHECK(spirv, SPV_ERROR_INVALID_ID);
+}
+TEST_F(ValidateID, OpStoreTypeBad) {
+  const char *spirv = R"(
+OpTypeVoid %1
+OpTypeInt %2 32 1
+OpTypeFloat %9 32
+OpTypePointer %3 UniformConstant $2
+OpTypeFunction %4 $1
+OpConstant $9 %5 3.14
+OpVariable $3 %6 UniformConstant
+OpFunction $1 %7 None $4
+OpLabel %8
+OpStore $6 $5
+OpReturn
+OpFunctionEnd)";
+  CHECK(spirv, SPV_ERROR_INVALID_ID);
+}
+
+TEST_F(ValidateID, OpCopyMemoryGood) {
+  const char *spirv = R"(
+OpTypeVoid %1
+OpTypeInt %2 32 0
+OpTypePointer %3 UniformConstant $2
+OpConstant $2 %4 42
+OpVariable $3 %5 UniformConstant $4
+OpTypePointer %6 Function $2
+OpTypeFunction %7 $1
+OpFunction $1 %8 None $7
+OpLabel %9
+OpVariable $6 %10 Function
+OpCopyMemory $10 $5 None
+OpReturn
+OpFunctionEnd
+)";
+  CHECK(spirv, SPV_SUCCESS);
+}
+TEST_F(ValidateID, OpCopyMemoryBad) {
+  const char *spirv = R"(
+OpTypeVoid %1
+OpTypeInt %2 32 0
+OpTypePointer %3 UniformConstant $2
+OpConstant $2 %4 42
+OpVariable $3 %5 UniformConstant $4
+OpTypeFloat %11 32
+OpTypePointer %6 Function $11
+OpTypeFunction %7 $1
+OpFunction $1 %8 None $7
+OpLabel %9
+OpVariable $6 %10 Function
+OpCopyMemory $10 $5 None
+OpReturn
+OpFunctionEnd
+)";
+  CHECK(spirv, SPV_ERROR_INVALID_ID);
+}
+
+// TODO: OpCopyMemorySized
+TEST_F(ValidateID, OpCopyMemorySizedGood) {
+  const char *spirv = R"(
+OpTypeVoid %1
+OpTypeInt %2 32 0
+OpTypePointer %3 UniformConstant $2
+OpTypePointer %4 Function $2
+OpConstant $2 %5 4
+OpVariable $3 %6 UniformConstant $5
+OpTypeFunction %7 $1
+OpFunction $1 %8 None $7
+OpLabel %9
+OpVariable $4 %10 Function
+OpCopyMemorySized $10 $6 $5 None
+OpReturn
+OpFunctionEnd)";
+  CHECK(spirv, SPV_SUCCESS);
+}
+TEST_F(ValidateID, OpCopyMemorySizedTargetBad) {
+  const char *spirv = R"(
+OpTypeVoid %1
+OpTypeInt %2 32 0
+OpTypePointer %3 UniformConstant $2
+OpTypePointer %4 Function $2
+OpConstant $2 %5 4
+OpVariable $3 %6 UniformConstant $5
+OpTypeFunction %7 $1
+OpFunction $1 %8 None $7
+OpLabel %9
+OpCopyMemorySized $9 $6 $5 None
+OpReturn
+OpFunctionEnd)";
+  CHECK(spirv, SPV_ERROR_INVALID_ID);
+}
+TEST_F(ValidateID, OpCopyMemorySizedSourceBad) {
+  const char *spirv = R"(
+OpTypeVoid %1
+OpTypeInt %2 32 0
+OpTypePointer %3 UniformConstant $2
+OpTypePointer %4 Function $2
+OpConstant $2 %5 4
+OpTypeFunction %6 $1
+OpFunction $1 %7 None $6
+OpLabel %8
+OpVariable $4 %9 Function
+OpCopyMemorySized $9 $6 $5 None
+OpReturn
+OpFunctionEnd)";
+  CHECK(spirv, SPV_ERROR_INVALID_ID);
+}
+TEST_F(ValidateID, OpCopyMemorySizedSizeBad) {
+  const char *spirv = R"(
+OpTypeVoid %1
+OpTypeInt %2 32 0
+OpTypePointer %3 UniformConstant $2
+OpTypePointer %4 Function $2
+OpConstant $2 %5 4
+OpVariable $3 %6 UniformConstant $5
+OpTypeFunction %7 $1
+OpFunction $1 %8 None $7
+OpLabel %9
+OpVariable $4 %10 Function
+OpCopyMemorySized $10 $6 $6 None
+OpReturn
+OpFunctionEnd)";
+  CHECK(spirv, SPV_ERROR_INVALID_ID);
+}
+TEST_F(ValidateID, OpCopyMemorySizedSizeTypeBad) {
+  const char *spirv = R"(
+OpTypeVoid %1
+OpTypeInt %2 32 0
+OpTypePointer %3 UniformConstant $2
+OpTypePointer %4 Function $2
+OpConstant $2 %5 4
+OpVariable $3 %6 UniformConstant $5
+OpTypeFunction %7 $1
+OpTypeFloat %11 32
+OpConstant $11 %12 1.0
+OpFunction $1 %8 None $7
+OpLabel %9
+OpVariable $4 %10 Function
+OpCopyMemorySized $10 $6 $12 None
+OpReturn
+OpFunctionEnd)";
+  CHECK(spirv, SPV_ERROR_INVALID_ID);
+}
+
+// TODO: OpAccessChain
+// TODO: OpInBoundsAccessChain
+// TODO: OpArrayLength
+// TODO: OpImagePointer
+// TODO: OpGenericPtrMemSemantics
+
+TEST_F(ValidateID, OpFunctionGood) {
+  const char *spirv = R"(
+OpTypeVoid %1
+OpTypeInt %2 32 1
+OpTypeFunction %3 $1 $2 $2
+OpFunction $1 %4 None $3
+OpFunctionEnd)";
+  CHECK(spirv, SPV_SUCCESS);
+}
+TEST_F(ValidateID, OpFunctionResultTypeBad) {
+  const char *spirv = R"(
+OpTypeVoid %1
+OpTypeInt %2 32 1
+OpConstant $2 %5 42
+OpTypeFunction %3 $1 $2 $2
+OpFunction $2 %4 None $3
+OpFunctionEnd)";
+  CHECK(spirv, SPV_ERROR_INVALID_ID);
+}
+TEST_F(ValidateID, OpFunctionFunctionTypeBad) {
+  const char *spirv = R"(
+OpTypeVoid %1
+OpTypeInt %2 32 1
+OpFunction $1 %4 None $2
+OpFunctionEnd)";
+  CHECK(spirv, SPV_ERROR_INVALID_ID);
+}
+
+TEST_F(ValidateID, OpFunctionParameterGood) {
+  const char *spirv = R"(
+OpTypeVoid %1
+OpTypeInt %2 32 0
+OpTypeFunction %3 $1 $2
+OpFunction $1 %4 None $3
+OpFunctionParameter $2 %5
+OpLabel %6
+OpReturn
+OpFunctionEnd)";
+  CHECK(spirv, SPV_SUCCESS);
+}
+TEST_F(ValidateID, OpFunctionParameterResultTypeBad) {
+  const char *spirv = R"(
+OpTypeVoid %1
+OpTypeInt %2 32 0
+OpTypeFunction %3 $1 $2
+OpFunction $1 %4 None $3
+OpFunctionParameter $1 %5
+OpLabel %6
+OpReturn
+OpFunctionEnd)";
+  CHECK(spirv, SPV_ERROR_INVALID_ID);
+}
+TEST_F(ValidateID, OpFunctionParameterOrderBad) {
+  const char *spirv = R"(
+OpTypeVoid %1
+OpTypeInt %2 32 0
+OpTypeFunction %3 $1 $2
+OpTypePointer %7 Function $2
+OpFunction $1 %4 None $3
+OpVariable $7 %8 Function
+OpFunctionParameter $2 %5
+OpLabel %6
+OpReturn
+OpFunctionEnd)";
+  CHECK(spirv, SPV_ERROR_INVALID_ID);
+}
+
+TEST_F(ValidateID, OpFunctionCallGood) {
+  const char *spirv = R"(
+OpTypeVoid %1
+OpTypeInt %2 32 0
+OpTypeFunction %3 $2 $2
+OpTypeFunction %4 $1
+OpConstant $2 %5 42 ;21
+
+OpFunction $2 %6 None $3
+OpFunctionParameter $2 %7
+OpLabel %8
+OpLoad $2 %9 $7
+OpReturnValue $9
+OpFunctionEnd
+
+OpFunction $1 %10 None $4
+OpLabel %11
+OpReturn
+OpFunctionCall $2 %12 $6 $5
+OpFunctionEnd)";
+  CHECK(spirv, SPV_SUCCESS);
+}
+TEST_F(ValidateID, OpFunctionCallResultTypeBad) {
+  const char *spirv = R"(
+OpTypeVoid %1
+OpTypeInt %2 32 0
+OpTypeFunction %3 $2 $2
+OpTypeFunction %4 $1
+OpConstant $2 %5 42 ;21
+
+OpFunction $2 %6 None $3
+OpFunctionParameter $2 %7
+OpLabel %8
+OpLoad $2 %9 $7
+OpReturnValue $9
+OpFunctionEnd
+
+OpFunction $1 %10 None $4
+OpLabel %11
+OpReturn
+OpFunctionCall $1 %12 $6 $5
+OpFunctionEnd)";
+  CHECK(spirv, SPV_ERROR_INVALID_ID);
+}
+TEST_F(ValidateID, OpFunctionCallFunctionBad) {
+  const char *spirv = R"(
+OpTypeVoid %1
+OpTypeInt %2 32 0
+OpTypeFunction %3 $2 $2
+OpTypeFunction %4 $1
+OpConstant $2 %5 42 ;21
+
+OpFunction $1 %10 None $4
+OpLabel %11
+OpReturn
+OpFunctionCall $2 %12 $5 $5
+OpFunctionEnd)";
+  CHECK(spirv, SPV_ERROR_INVALID_ID);
+}
+TEST_F(ValidateID, OpFunctionCallArgumentTypeBad) {
+  const char *spirv = R"(
+OpTypeVoid %1
+OpTypeInt %2 32 0
+OpTypeFunction %3 $2 $2
+OpTypeFunction %4 $1
+OpConstant $2 %5 42
+
+OpTypeFloat %13 32
+OpConstant $13 %14 3.14
+
+OpFunction $2 %6 None $3
+OpFunctionParameter $2 %7
+OpLabel %8
+OpLoad $2 %9 $7
+OpReturnValue $9
+OpFunctionEnd
+
+OpFunction $1 %10 None $4
+OpLabel %11
+OpReturn
+OpFunctionCall $2 %12 $6 $14
+OpFunctionEnd)";
+  CHECK(spirv, SPV_ERROR_INVALID_ID);
+}
+#if 0
+TEST_F(ValidateID, OpFunctionCallArgumentCountBar) {
+  const char *spirv = R"(
+OpTypeVoid %1
+OpTypeInt %2 32 0
+OpTypeFunction %3 $2 $2
+OpTypeFunction %4 $1
+OpConstant $2 %5 42 ;21
+
+OpFunction $2 %6 None $3
+OpFunctionParameter $2 %7
+OpLabel %8
+OpLoad $2 %9 $7
+OpReturnValue $9
+OpFunctionEnd
+
+OpFunction $1 %10 None $4
+OpLabel %11
+OpReturn
+OpFunctionCall $2 %12 $6 $5
+OpFunctionEnd)";
+  CHECK(spirv, SPV_ERROR_INVALID_ID);
+}
+#endif
+
+// TODO: OpSampler
+// TODO: OpTextureSample
+// TODO: OpTextureSampleDref
+// TODO: OpTextureSampleLod
+// TODO: OpTextureSampleProj
+// TODO: OpTextureSampleGrad
+// TODO: OpTextureSampleOffset
+// TODO: OpTextureSampleProjLod
+// TODO: OpTextureSampleProjGrad
+// TODO: OpTextureSampleLodOffset
+// TODO: OpTextureSampleProjOffset
+// TODO: OpTextureSampleGradOffset
+// TODO: OpTextureSampleProjLodOffset
+// TODO: OpTextureSampleProjGradOffset
+// TODO: OpTextureFetchTexelLod
+// TODO: OpTextureFetchTexelOffset
+// TODO: OpTextureFetchSample
+// TODO: OpTextureFetchTexel
+// TODO: OpTextureGather
+// TODO: OpTextureGatherOffset
+// TODO: OpTextureGatherOffsets
+// TODO: OpTextureQuerySizeLod
+// TODO: OpTextureQuerySize
+// TODO: OpTextureQueryLevels
+// TODO: OpTextureQuerySamples
+// TODO: OpConvertUToF
+// TODO: OpConvertFToS
+// TODO: OpConvertSToF
+// TODO: OpConvertUToF
+// TODO: OpUConvert
+// TODO: OpSConvert
+// TODO: OpFConvert
+// TODO: OpConvertPtrToU
+// TODO: OpConvertUToPtr
+// TODO: OpPtrCastToGeneric
+// TODO: OpGenericCastToPtr
+// TODO: OpBitcast
+// TODO: OpGenericCastToPtrExplicit
+// TODO: OpSatConvertSToU
+// TODO: OpSatConvertUToS
+// TODO: OpVectorExtractDynamic
+// TODO: OpVectorInsertDynamic
+// TODO: OpVectorShuffle
+// TODO: OpCompositeConstruct
+// TODO: OpCompositeExtract
+// TODO: OpCompositeInsert
+// TODO: OpCopyObject
+// TODO: OpTranspose
+// TODO: OpSNegate
+// TODO: OpFNegate
+// TODO: OpNot
+// TODO: OpIAdd
+// TODO: OpFAdd
+// TODO: OpISub
+// TODO: OpFSub
+// TODO: OpIMul
+// TODO: OpFMul
+// TODO: OpUDiv
+// TODO: OpSDiv
+// TODO: OpFDiv
+// TODO: OpUMod
+// TODO: OpSRem
+// TODO: OpSMod
+// TODO: OpFRem
+// TODO: OpFMod
+// TODO: OpVectorTimesScalar
+// TODO: OpMatrixTimesScalar
+// TODO: OpVectorTimesMatrix
+// TODO: OpMatrixTimesVector
+// TODO: OpMatrixTimesMatrix
+// TODO: OpOuterProduct
+// TODO: OpDot
+// TODO: OpShiftRightLogical
+// TODO: OpShiftRightArithmetic
+// TODO: OpShiftLeftLogical
+// TODO: OpBitwiseOr
+// TODO: OpBitwiseXor
+// TODO: OpBitwiseAnd
+// TODO: OpAny
+// TODO: OpAll
+// TODO: OpIsNan
+// TODO: OpIsInf
+// TODO: OpIsFinite
+// TODO: OpIsNormal
+// TODO: OpSignBitSet
+// TODO: OpLessOrGreater
+// TODO: OpOrdered
+// TODO: OpUnordered
+// TODO: OpLogicalOr
+// TODO: OpLogicalXor
+// TODO: OpLogicalAnd
+// TODO: OpSelect
+// TODO: OpIEqual
+// TODO: OpFOrdEqual
+// TODO: OpFUnordEqual
+// TODO: OpINotEqual
+// TODO: OpFOrdNotEqual
+// TODO: OpFUnordNotEqual
+// TODO: OpULessThan
+// TODO: OpSLessThan
+// TODO: OpFOrdLessThan
+// TODO: OpFUnordLessThan
+// TODO: OpUGreaterThan
+// TODO: OpSGreaterThan
+// TODO: OpFOrdGreaterThan
+// TODO: OpFUnordGreaterThan
+// TODO: OpULessThanEqual
+// TODO: OpSLessThanEqual
+// TODO: OpFOrdLessThanEqual
+// TODO: OpFUnordLessThanEqual
+// TODO: OpUGreaterThanEqual
+// TODO: OpSGreaterThanEqual
+// TODO: OpFOrdGreaterThanEqual
+// TODO: OpFUnordGreaterThanEqual
+// TODO: OpDPdx
+// TODO: OpDPdy
+// TODO: OpFWidth
+// TODO: OpDPdxFine
+// TODO: OpDPdyFine
+// TODO: OpFwidthFine
+// TODO: OpDPdxCoarse
+// TODO: OpDPdyCoarse
+// TODO: OpFwidthCoarse
+// TODO: OpPhi
+// TODO: OpLoopMerge
+// TODO: OpSelectionMerge
+// TODO: OpBranch
+// TODO: OpBranchConditional
+// TODO: OpSwitch
+
+TEST_F(ValidateID, OpReturnValueConstantGood) {
+  const char *spirv = R"(
+OpTypeVoid %1
+OpTypeInt %2 32 0
+OpTypeFunction %3 $2 $2
+OpConstant $2 %4 42
+OpFunction $2 %5 None $3
+OpLabel %6
+OpReturnValue $4
+OpFunctionEnd)";
+  CHECK(spirv, SPV_SUCCESS);
+}
+TEST_F(ValidateID, OpReturnValueVariableGood) {
+  const char *spirv = R"(
+OpTypeVoid %1
+OpTypeInt %2 32 0 ;10
+OpTypeFunction %3 $2 $2 ;14
+OpTypePointer %8 Function $2 ;18
+OpConstant $2 %4 42 ;22
+OpFunction $2 %5 None $3 ;27
+OpLabel %6 ;29
+OpVariable $8 %7 Function $4 ;34
+OpReturnValue $7 ;36
+OpFunctionEnd)";
+  CHECK(spirv, SPV_SUCCESS);
+}
+TEST_F(ValidateID, OpReturnValueBad) {
+  const char *spirv = R"(
+OpTypeVoid %1
+OpTypeInt %2 32 0
+OpTypeFunction %3 $2 $2
+OpConstant $2 %4 42
+OpFunction $2 %5 None $3
+OpLabel %6
+OpReturnValue $1
+OpFunctionEnd)";
+  CHECK(spirv, SPV_ERROR_INVALID_ID);
+}
+
+// TODO: OpLifetimeStart
+// TODO: OpLifetimeStop
+// TODO: OpAtomicInit
+// TODO: OpAtomicLoad
+// TODO: OpAtomicStore
+// TODO: OpAtomicExchange
+// TODO: OpAtomicCompareExchange
+// TODO: OpAtomicCompareExchangeWeak
+// TODO: OpAtomicIIncrement
+// TODO: OpAtomicIDecrement
+// TODO: OpAtomicIAdd
+// TODO: OpAtomicISub
+// TODO: OpAtomicUMin
+// TODO: OpAtomicUMax
+// TODO: OpAtomicAnd
+// TODO: OpAtomicOr
+// TODO: OpAtomicXor
+// TODO: OpAtomicIMin
+// TODO: OpAtomicIMax
+// TODO: OpEmitStreamVertex
+// TODO: OpEndStreamPrimitive
+// TODO: OpAsyncGroupCopy
+// TODO: OpWaitGroupEvents
+// TODO: OpGroupAll
+// TODO: OpGroupAny
+// TODO: OpGroupBroadcast
+// TODO: OpGroupIAdd
+// TODO: OpGroupFAdd
+// TODO: OpGroupFMin
+// TODO: OpGroupUMin
+// TODO: OpGroupSMin
+// TODO: OpGroupFMax
+// TODO: OpGroupUMax
+// TODO: OpGroupSMax
+// TODO: OpEnqueueMarker
+// TODO: OpEnqueueKernel
+// TODO: OpGetKernelNDrangeSubGroupCount
+// TODO: OpGetKernelNDrangeMaxSubGroupSize
+// TODO: OpGetKernelWorkGroupSize
+// TODO: OpGetKernelPreferredWorkGroupSizeMultiple
+// TODO: OpRetainEvent
+// TODO: OpReleaseEvent
+// TODO: OpCreateUserEvent
+// TODO: OpIsValidEvent
+// TODO: OpSetUserEventStatus
+// TODO: OpCaptureEventProfilingInfo
+// TODO: OpGetDefaultQueue
+// TODO: OpBuildNDRange
+// TODO: OpReadPipe
+// TODO: OpWritePipe
+// TODO: OpReservedReadPipe
+// TODO: OpReservedWritePipe
+// TODO: OpReserveReadPipePackets
+// TODO: OpReserveWritePipePackets
+// TODO: OpCommitReadPipe
+// TODO: OpCommitWritePipe
+// TODO: OpIsValidReserveId
+// TODO: OpGetNumPipePackets
+// TODO: OpGetMaxPipePackets
+// TODO: OpGroupReserveReadPipePackets
+// TODO: OpGroupReserveWritePipePackets
+// TODO: OpGroupCommitReadPipe
+// TODO: OpGroupCommitWritePipe
diff --git a/test/main.cpp b/test/main.cpp
new file mode 100644 (file)
index 0000000..6a241cd
--- /dev/null
@@ -0,0 +1,32 @@
+// Copyright (c) 2015 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.
+
+#include <gtest/gtest.h>
+
+int main(int argc, char **argv) {
+  ::testing::InitGoogleTest(&argc, argv);
+  return RUN_ALL_TESTS();
+}
diff --git a/tools/as/as.cpp b/tools/as/as.cpp
new file mode 100644 (file)
index 0000000..b36a1d9
--- /dev/null
@@ -0,0 +1,129 @@
+// Copyright (c) 2015 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.
+
+#include <libspirv/libspirv.h>
+
+#include <stdio.h>
+#include <vector>
+
+void print_usage(char *argv0) {
+  printf(
+      "Assemble a *.svasm file into a *.sv binary.\n\n"
+      "USAGE: %s [options] <filename>\n\n"
+      "        -o    Set the output filename\n",
+      argv0);
+}
+
+int main(int argc, char **argv) {
+  if (2 > argc) {
+    print_usage(argv[0]);
+    return 1;
+  }
+
+  const char *inFile = nullptr;
+  const char *outFile = nullptr;
+
+  for (int argi = 1; argi < argc; ++argi) {
+    if ('-' == argv[argi][0]) {
+      switch (argv[argi][1]) {
+        case 'o': {
+          if (!outFile && argi + 1 < argc) {
+            outFile = argv[++argi];
+          } else {
+            print_usage(argv[0]);
+            return 1;
+          }
+        } break;
+        default:
+          print_usage(argv[0]);
+          return 1;
+      }
+    } else {
+      if (!inFile) {
+        inFile = argv[argi];
+      } else {
+        print_usage(argv[0]);
+        return 1;
+      }
+    }
+  }
+
+  if (!outFile) {
+    outFile = "out.spv";
+  }
+
+  spvCheck(!inFile, fprintf(stderr, "error: input file is empty.\n"); return 1);
+
+  std::vector<char> contents;
+  if (FILE *fp = fopen(inFile, "r")) {
+    char buf[1024];
+    while (size_t len = fread(buf, 1, sizeof(buf), fp))
+      contents.insert(contents.end(), buf, buf + len);
+    fclose(fp);
+  } else {
+    fprintf(stderr, "error: file does not exist '%s'\n", inFile);
+    return 1;
+  }
+
+  spv_text_t text = {contents.data(), contents.size()};
+
+  spv_opcode_table opcodeTable;
+  spv_result_t error = spvOpcodeTableGet(&opcodeTable);
+  spvCheck(error, fprintf(stderr, "error: internal malfunction\n");
+           return error);
+
+  spv_operand_table operandTable;
+  error = spvOperandTableGet(&operandTable);
+  spvCheck(error, fprintf(stderr, "error: internal malfunction\n");
+           return error);
+
+  spv_ext_inst_table extInstTable;
+  error = spvExtInstTableGet(&extInstTable);
+  spvCheck(error, fprintf(stderr, "error: Internal malfunction.\n"));
+
+  spv_binary binary;
+  spv_diagnostic diagnostic = nullptr;
+  error = spvTextToBinary(&text, opcodeTable, operandTable, extInstTable,
+                          &binary, &diagnostic);
+  spvCheck(error, spvDiagnosticPrint(diagnostic);
+           spvDiagnosticDestroy(diagnostic); return error);
+
+  if (FILE *fp = fopen(outFile, "wb")) {
+    size_t written =
+        fwrite(binary->code, sizeof(uint32_t), (size_t)binary->wordCount, fp);
+    if (binary->wordCount != written) {
+      fprintf(stderr, "error: could not write to file '%s'\n", outFile);
+      return 1;
+    }
+  } else {
+    fprintf(stderr, "error: could not open file '%s'\n", outFile);
+    return 1;
+  }
+
+  spvBinaryDestroy(binary);
+
+  return 0;
+}
diff --git a/tools/dis/dis.cpp b/tools/dis/dis.cpp
new file mode 100644 (file)
index 0000000..5555073
--- /dev/null
@@ -0,0 +1,144 @@
+// Copyright (c) 2015 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.
+
+#include <libspirv/libspirv.h>
+
+#include <stdio.h>
+#include <vector>
+
+void print_usage(char *argv0) {
+  printf(
+      "Dissassemble a *.sv file into a *.svasm text file.\n\n"
+      "USAGE: %s [options] <filename>\n\n"
+      "        -o <filename>   Set the output filename\n"
+      "        -p              Print dissassembly to stdout, this\n"
+      "                        overrides file output\n",
+      argv0);
+}
+
+int main(int argc, char **argv) {
+  if (2 > argc) {
+    print_usage(argv[0]);
+    return 1;
+  }
+
+  uint32_t options = SPV_BINARY_TO_TEXT_OPTION_NONE;
+  const char *inFile = nullptr;
+  const char *outFile = nullptr;
+
+  for (int argi = 1; argi < argc; ++argi) {
+    if ('-' == argv[argi][0]) {
+      switch (argv[argi][1]) {
+        case 'o': {
+          if (!outFile && argi + 1 < argc) {
+            outFile = argv[++argi];
+          } else {
+            print_usage(argv[0]);
+            return 1;
+          }
+        } break;
+        case 'p': {
+          options |= SPV_BINARY_TO_TEXT_OPTION_PRINT;
+#ifdef SPV_COLOR_TERMINAL
+          options |= SPV_BINARY_TO_TEXT_OPTION_COLOR;
+#endif
+        } break;
+        default:
+          print_usage(argv[0]);
+          return 1;
+      }
+    } else {
+      if (!inFile) {
+        inFile = argv[argi];
+      } else {
+        print_usage(argv[0]);
+        return 1;
+      }
+    }
+  }
+
+  if (!outFile) {
+    outFile = "out.spvasm";
+  }
+
+  spvCheck(!inFile, fprintf(stderr, "error: input file is empty.\n"); return 1);
+
+  std::vector<uint32_t> contents;
+  if (FILE *fp = fopen(inFile, "rb")) {
+    uint32_t buf[1024];
+    while (size_t len = fread(buf, sizeof(uint32_t), 1024, fp)) {
+      contents.insert(contents.end(), buf, buf + len);
+    }
+    fclose(fp);
+  } else {
+    fprintf(stderr, "error: file does not exist '%s'\n", inFile);
+    return 1;
+  }
+
+  spv_binary_t binary = {contents.data(), contents.size()};
+
+  spv_opcode_table opcodeTable;
+  spv_result_t error = spvOpcodeTableGet(&opcodeTable);
+  spvCheck(error, fprintf(stderr, "error: internal malfunction\n");
+           return error);
+
+  spv_operand_table operandTable;
+  error = spvOperandTableGet(&operandTable);
+  spvCheck(error, fprintf(stderr, "error: internal malfunction\n");
+           return error);
+
+  spv_ext_inst_table extInstTable;
+  error = spvExtInstTableGet(&extInstTable);
+  spvCheck(error, fprintf(stderr, "error: Internal malfunction.\n"));
+
+  spv_text text;
+  spv_diagnostic diagnostic = nullptr;
+  error = spvBinaryToText(&binary, options, opcodeTable, operandTable,
+                          extInstTable, &text, &diagnostic);
+  spvCheck(error, spvDiagnosticPrint(diagnostic);
+           spvDiagnosticDestroy(diagnostic); return error);
+
+  if (spvIsInBitfield(SPV_BINARY_TO_TEXT_OPTION_PRINT, options)) {
+    printf("%s", text->str);
+  } else {
+    if (FILE *fp = fopen(outFile, "w")) {
+      size_t written = fwrite(text->str, sizeof(char), (size_t)text->length, fp);
+      if (text->length != written) {
+        spvTextDestroy(text);
+        fprintf(stderr, "error: could not write to file '%s'\n", outFile);
+        return 1;
+      }
+    } else {
+      spvTextDestroy(text);
+      fprintf(stderr, "error: could not open file '%s'\n", outFile);
+      return 1;
+    }
+  }
+
+  spvTextDestroy(text);
+
+  return 0;
+}
diff --git a/tools/val/val.cpp b/tools/val/val.cpp
new file mode 100644 (file)
index 0000000..2d11d92
--- /dev/null
@@ -0,0 +1,119 @@
+// Copyright (c) 2015 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.
+
+#include <libspirv/libspirv.h>
+
+#include <assert.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <vector>
+
+void print_usage(char *argv0) {
+  printf(
+      "Validate a SPIR-V binary file.\n\n"
+      "USAGE: %s [options] <filename>\n\n"
+      "        -basic                     Perform basic validation (disabled)\n"
+      "        -layout                    Perform layout validation "
+      "(disabled)\n"
+      "        -id                        Perform id validation (default ON)\n"
+      "        -capability <capability>   Performs OpCode validation "
+      "(disabled)\n",
+      argv0);
+}
+
+int main(int argc, char **argv) {
+  if (2 > argc) {
+    print_usage(argv[0]);
+    return 1;
+  }
+
+  const char *inFile = nullptr;
+  uint32_t options = 0;
+
+  for (int argi = 1; argi < argc; ++argi) {
+    if ('-' == argv[argi][0]) {
+      if (!strcmp("basic", argv[argi] + 1)) {
+        options |= SPV_VALIDATE_BASIC_BIT;
+      } else if (!strcmp("layout", argv[argi] + 1)) {
+        options |= SPV_VALIDATE_LAYOUT_BIT;
+      } else if (!strcmp("id", argv[argi] + 1)) {
+        options |= SPV_VALIDATE_ID_BIT;
+      } else if (!strcmp("rules", argv[argi] + 1)) {
+        options |= SPV_VALIDATE_RULES_BIT;
+      } else {
+        print_usage(argv[0]);
+        return 1;
+      }
+    } else {
+      if (!inFile) {
+        inFile = argv[argi];
+      } else {
+        print_usage(argv[0]);
+        return 1;
+      }
+    }
+  }
+
+  spvCheck(!inFile, fprintf(stderr, "error: input file is empty.\n"); return 1);
+
+  std::vector<uint32_t> contents;
+  if (FILE *fp = fopen(inFile, "rb")) {
+    uint32_t buf[1024];
+    while (size_t len = fread(buf, sizeof(uint32_t),
+                              sizeof(buf) / sizeof(uint32_t), fp)) {
+      contents.insert(contents.end(), buf, buf + len);
+    }
+    fclose(fp);
+  } else {
+    fprintf(stderr, "error: file does not exist '%s'\n", inFile);
+    return 1;
+  }
+
+  spv_binary_t binary = {contents.data(), contents.size()};
+
+  spv_opcode_table opcodeTable;
+  spv_result_t error = spvOpcodeTableGet(&opcodeTable);
+  spvCheck(error, fprintf(stderr, "error: internal malfunction\n");
+           return error);
+
+  spv_operand_table operandTable;
+  error = spvOperandTableGet(&operandTable);
+  spvCheck(error, fprintf(stderr, "error: internal malfunction\n");
+           return error);
+
+  spv_ext_inst_table extInstTable;
+  error = spvExtInstTableGet(&extInstTable);
+  spvCheck(error, fprintf(stderr, "error: Internal malfunction.\n"));
+
+  spv_diagnostic diagnostic = nullptr;
+  error = spvValidate(&binary, opcodeTable, operandTable, extInstTable, options,
+                      &diagnostic);
+  spvCheck(error, spvDiagnosticPrint(diagnostic);
+           spvDiagnosticDestroy(diagnostic); return error);
+
+  return 0;
+}