commit 83e5a29b06e8e5b379b8fbc261d909457179c995 Author: Kenneth Benzie (Benie) Date: Fri May 22 18:26:19 2015 +0100 Code drop of the Codeplay spirv-tools source. This commit contains the source for the SPIRV static library, spirv-as, spirv-dis, and spirv-val tools. diff --git a/.clang-format b/.clang-format new file mode 100644 index 000000000..38804f78c --- /dev/null +++ b/.clang-format @@ -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 index 000000000..927d9335b --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +build* +.ycm_extra_conf.py* diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 000000000..9f08b837e --- /dev/null +++ b/CMakeLists.txt @@ -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 '/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 index 000000000..49107c877 --- /dev/null +++ b/external/include/headers/GLSL450Lib.h @@ -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 index 000000000..89a570812 --- /dev/null +++ b/external/include/headers/OpenCLLib.h @@ -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 index 000000000..a75bf18a1 --- /dev/null +++ b/external/include/headers/spirv.h @@ -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 index 000000000..fcb24b434 --- /dev/null +++ b/include/libspirv/libspirv.h @@ -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 +#include +#include + +#ifdef __cplusplus +using namespace spv; +extern "C" { +#endif + +#include +#include + +// 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 index 000000000..4675d329f --- /dev/null +++ b/licence.txt @@ -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 index 000000000..f03b58bc8 --- /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 /build +cd /build +cmake [-G] .. +``` + +Once the build files have been generated, build using your preferred +development environment. + +### CMake Options + +* `SPIRV_USE_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 +`/include`, which will enable the application to include the header +`/include/libspirv/libspirv.h` then linking against the static +library in `/bin/libSPIRV.a` or +`/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 `/lib/libSPIRV.a` + on Linux/Mac or `/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 `/include/libspirv/libspirv.h` +the implementation source files reside in `/source/*`. + +## Tools + +### Assembler + +The standalone assembler is the binary called `spirv-as` and is located in +`/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 + * `/bin/spirv-as` + +#### Options + +* `-o ` 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 +`""` while literal numbers have no special formatting. + +##### ID Definitions & Usage + +An ID definition pertains to the `Result ` 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 `%`, meanwhile all ID +uses are prefixed with `$` and take the form `$`. 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 +`!`. Here is an example. + +``` +OpCapability !0x0000FF000 +``` + +### Disassembler + +The standalone disassembler is the binary called `spirv-dis` and is located in +`/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 + * `/bin/spirv-dis` + +#### Options + +* `-o ` 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 +`/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 + * `/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 +`/external/googletest` directory, rerun CMake if you have already +done so previously, CMake will detect the existence of +`/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 index 000000000..3b33109fb --- /dev/null +++ b/source/binary.cpp @@ -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 +#include "binary.h" +#include "diagnostic.h" +#include "ext_inst.h" +#include "opcode.h" +#include "operand.h" + +#include +#include + +#include + +// 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 index 000000000..2ab5c66ca --- /dev/null +++ b/source/binary.h @@ -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 +#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 index 000000000..a6f87aa62 --- /dev/null +++ b/source/diagnostic.cpp @@ -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 +#include "diagnostic.h" + +#include +#include + +#include + +// 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 index 000000000..f2e4db245 --- /dev/null +++ b/source/diagnostic.h @@ -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 + +#include + +#include + +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 index 000000000..04e1bba9b --- /dev/null +++ b/source/ext_inst.cpp @@ -0,0 +1,113 @@ +#include + +#include + +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 index 000000000..341547b52 --- /dev/null +++ b/source/ext_inst.h @@ -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 + +/// @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 index 000000000..bf203ac49 --- /dev/null +++ b/source/opcode.cpp @@ -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 +#include "binary.h" +#include "opcode.h" + +#include +#include + +// 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 index 000000000..32c225e26 --- /dev/null +++ b/source/opcode.h @@ -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 + +// 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 index 000000000..73eb4b992 --- /dev/null +++ b/source/operand.cpp @@ -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 +#include + +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 index 000000000..3482a4dc9 --- /dev/null +++ b/source/operand.h @@ -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 + +/// @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 index 000000000..6ee3b01d4 --- /dev/null +++ b/source/print.cpp @@ -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 + +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 index 000000000..6e20da5d1 --- /dev/null +++ b/source/print.h @@ -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 +#include + +/// @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 index 000000000..e2c1d8932 --- /dev/null +++ b/source/text.cpp @@ -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 +#include "binary.h" +#include "diagnostic.h" +#include "ext_inst.h" +#include "opcode.h" +#include "operand.h" +#include "text.h" + +#include +#include +#include +#include + +#include +#include +#include + +// Structures + +struct spv_named_id_table_t { + std::unordered_map 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 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 index 000000000..df26532a6 --- /dev/null +++ b/source/text.h @@ -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 + +#include + +// 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 index 000000000..07ecb79fa --- /dev/null +++ b/source/validate.cpp @@ -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 +#include "binary.h" +#include "diagnostic.h" +#include "opcode.h" +#include "operand.h" +#include "validate.h" + +#include +#include +#include + +#include + +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 idUses; + std::vector 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 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 index 000000000..661c84f6b --- /dev/null +++ b/source/validate.h @@ -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 + +// 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 index 000000000..9f2a260ef --- /dev/null +++ b/source/validate_id.cpp @@ -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 +#include "diagnostic.h" +#include "opcode.h" +#include "validate.h" + +#include + +#include +#include +#include + +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 + bool isValid(const spv_instruction_t *inst, const spv_opcode_desc); + + std::unordered_map::iterator find( + const uint32_t &id) { + return idDefs.find(id); + } + std::unordered_map::const_iterator find( + const uint32_t &id) const { + return idDefs.find(id); + } + + bool found(std::unordered_map::iterator item) { + return idDefs.end() != item; + } + bool found(std::unordered_map::const_iterator item) { + return idDefs.end() != item; + } + + std::unordered_map>::iterator findUses( + const uint32_t &id) { + return idUses.find(id); + } + std::unordered_map>::const_iterator + findUses(const uint32_t &id) const { + return idUses.find(id); + } + + bool foundUses( + std::unordered_map>::iterator item) { + return idUses.end() != item; + } + bool foundUses(std::unordered_map< + uint32_t, std::vector>::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> idUses; + std::unordered_map idDefs; +}; + +#define DIAG(INDEX) \ + position->index += INDEX; \ + DIAGNOSTIC + +#if 0 +template <> +bool idUsage::isValid(const spv_instruction_t *inst, + const spv_opcode_desc) { + assert(0 && "Unimplemented!"); + return false; +} +#endif + +template <> +bool idUsage::isValid(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 '" + << inst->words[targetIndex] + << "' is not defined."; + return false); + return true; +} + +template <> +bool idUsage::isValid(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 '" + << inst->words[typeIndex] + << "' is not defined."; + return false); + spvCheck(OpTypeStruct != type->second.opcode, + DIAG(typeIndex) << "OpMemberName Type '" + << 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 '" + << inst->words[memberIndex] + << "' index is larger than Type '" + << type->second.id << "'s member count."; + return false); + return true; +} + +template <> +bool idUsage::isValid(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 '" + << inst->words[targetIndex] + << "' is not defined."; + return false); + auto fileIndex = 2; + auto file = find(inst->words[fileIndex]); + spvCheck(!found(file), DIAG(fileIndex) << "OpLine Target '" + << inst->words[fileIndex] + << "' is not defined."; + return false); + spvCheck(OpString != file->second.opcode, + DIAG(fileIndex) << "OpLine Target '" << inst->words[fileIndex] + << "' is not an OpString."; + return false); + return true; +} + +template <> +bool idUsage::isValid(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 '" + << inst->words[targetIndex] + << "' is not defined."; + return false); + return true; +} + +template <> +bool idUsage::isValid(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 '" + << inst->words[structTypeIndex] + << "' is not defined."; + return false); + spvCheck(OpTypeStruct != structType->second.inst->opcode, + DIAG(structTypeIndex) << "OpMemberDecorate Structure type '" + << 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 '" + << inst->words[memberIndex] + << "' member count is less than Member"; + return false); + return true; +} + +template <> +bool idUsage::isValid(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 '" + << inst->words[decorationGroupIndex] << "' is not defined."; + return false); + spvCheck(OpDecorationGroup != decorationGroup->second.opcode, + DIAG(decorationGroupIndex) + << "OpGroupDecorate Decoration group '" + << 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 '" + << inst->words[targetIndex] + << "' is not defined."; + return false); + } + return true; +} + +#if 0 +template <> +bool idUsage::isValid( + const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {} +#endif + +#if 0 +template <> +bool idUsage::isValid(const spv_instruction_t *inst, + const spv_opcode_desc opcodeEntry) {} +#endif + +template <> +bool idUsage::isValid(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 '" + << inst->words[entryPointIndex] + << "' is not defined."; + return false); + spvCheck(OpFunction != entryPoint->second.opcode, + DIAG(entryPointIndex) << "OpEntryPoint Entry Point '" + << 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 '" + << 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 '" + << inst->words[entryPointIndex] + << "'s function return type is not void."; + return false); + return true; +} + +template <> +bool idUsage::isValid(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 '" + << 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 '" + << inst->words[entryPointIndex] + << "' is not the Entry Point " + "operand of an OpEntryPoint."; + return false); + return true; +} + +template <> +bool idUsage::isValid(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 '" + << inst->words[componentIndex] + << "' is not defined."; + return false); + spvCheck(!spvOpcodeIsScalarType(componentType->second.opcode), + DIAG(componentIndex) << "OpTypeVector Component Type '" + << inst->words[componentIndex] + << "' is not a scalar type."; + return false); + return true; +} + +template <> +bool idUsage::isValid(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 '" + << inst->words[columnTypeIndex] + << "' is not defined."; + return false); + spvCheck(OpTypeVector != columnType->second.opcode, + DIAG(columnTypeIndex) << "OpTypeMatrix Column Type '" + << inst->words[columnTypeIndex] + << "' is not a vector."; + return false); + return true; +} + +template <> +bool idUsage::isValid(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 '" + << inst->words[sampledTypeIndex] + << "' is not defined."; + return false); + spvCheck(!spvOpcodeIsScalarType(sampledType->second.opcode), + DIAG(sampledTypeIndex) << "OpTypeSampler Sampled Type '" + << inst->words[sampledTypeIndex] + << "' is not a scalar type."; + return false); + return true; +} + +template <> +bool idUsage::isValid(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 '" + << inst->words[elementTypeIndex] + << "' is not defined."; + return false); + spvCheck(!spvOpcodeIsType(elementType->second.opcode), + DIAG(elementTypeIndex) << "OpTypeArray Element Type '" + << 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 '" + << inst->words[lengthIndex] + << "' is not defined."; + return false); + spvCheck(OpConstant != length->second.opcode && + OpSpecConstant != length->second.opcode, + DIAG(lengthIndex) << "OpTypeArray Length '" + << 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 '" + << inst->words[constResultTypeIndex] + << "' result type is not defined."; + return false); + spvCheck(OpTypeInt != constResultType->second.opcode, + DIAG(lengthIndex) << "OpTypeArray Length '" + << inst->words[lengthIndex] + << "' is not a constant integer type."; + return false); + if (4 == constInst->wordCount) { + spvCheck(1 > constInst->words[3], DIAG(lengthIndex) + << "OpTypeArray Length '" + << 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 '" + << inst->words[lengthIndex] + << "' value must be at least 1."; + return false); + } else { + spvCheck(1 > value, DIAG(lengthIndex) << "OpTypeArray Length '" + << inst->words[lengthIndex] + << "' value must be at least 1."; + return false); + } + } + return true; +} + +template <> +bool idUsage::isValid(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 '" + << inst->words[elementTypeIndex] + << "' is not defined."; + return false); + spvCheck(!spvOpcodeIsType(elementType->second.opcode), + DIAG(elementTypeIndex) << "OpTypeRuntimeArray Element Type '" + << inst->words[elementTypeIndex] + << "' is not a type."; + return false); + return true; +} + +template <> +bool idUsage::isValid(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 '" + << inst->words[memberTypeIndex] + << "' is not defined."; + return false); + spvCheck(!spvOpcodeIsType(memberType->second.opcode), + DIAG(memberTypeIndex) << "OpTypeStruct Member Type '" + << inst->words[memberTypeIndex] + << "' is not a type."; + return false); + } + return true; +} + +template <> +bool idUsage::isValid(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 '" + << inst->words[typeIndex] + << "' is not defined."; + return false); + spvCheck(!spvOpcodeIsType(type->second.opcode), + DIAG(typeIndex) << "OpTypePointer Type '" + << inst->words[typeIndex] << "' is not a type."; + return false); + return true; +} + +template <> +bool idUsage::isValid(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 '" + << inst->words[returnTypeIndex] + << "' is not defined"; + return false); + spvCheck(!spvOpcodeIsType(returnType->second.opcode), + DIAG(returnTypeIndex) << "OpTypeFunction Return Type '" + << 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 '" + << inst->words[paramTypeIndex] + << "' is not defined."; + return false); + spvCheck(!spvOpcodeIsType(paramType->second.opcode), + DIAG(paramTypeIndex) << "OpTypeFunction Parameter Type '" + << inst->words[paramTypeIndex] + << "' is not a type."; + return false); + } + return true; +} + +template <> +bool idUsage::isValid(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 '" + << inst->words[typeIndex] + << "' is not defined."; + return false); + spvCheck(!spvOpcodeIsType(type->second.opcode), + DIAG(typeIndex) << "OpTypePipe Type '" << inst->words[typeIndex] + << "' is not a type."; + return false); + return true; +} + +template <> +bool idUsage::isValid(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 '" + << inst->words[resultTypeIndex] + << "' is not defined."; + return false); + spvCheck(OpTypeBool != resultType->second.opcode, + DIAG(resultTypeIndex) << "OpConstantTrue Result Type '" + << inst->words[resultTypeIndex] + << "' is not a boolean type."; + return false); + return true; +} + +template <> +bool idUsage::isValid(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 '" + << inst->words[resultTypeIndex] + << "' is not defined."; + return false); + spvCheck(OpTypeBool != resultType->second.opcode, + DIAG(resultTypeIndex) << "OpConstantFalse Result Type '" + << inst->words[resultTypeIndex] + << "' is not a boolean type."; + return false); + return true; +} + +template <> +bool idUsage::isValid(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 '" + << inst->words[resultTypeIndex] + << "' is not defined."; + return false); + spvCheck(!spvOpcodeIsScalarType(resultType->second.opcode), + DIAG(resultTypeIndex) + << "OpConstant Result Type '" + << inst->words[resultTypeIndex] + << "' is not a scalar integer or floating point type."; + return false); + return true; +} + +template <> +bool idUsage::isValid(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 '" + << inst->words[resultTypeIndex] + << "' is not defined."; + return false); + spvCheck(!spvOpcodeIsComposite(resultType->second.opcode), + DIAG(resultTypeIndex) << "OpConstantComposite Result Type '" + << 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 count does not match " + "Result Type '" << 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 '" + << 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 '" + << inst->words[constituentIndex] + << "'s type does not match Result Type '" + << 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 count does not match " + "Result Type '" << 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 '" + << inst->words[constituentIndex] << "' is not defined."; + return false); + spvCheck(OpConstantComposite != constituent->second.opcode, + DIAG(constituentIndex) + << "OpConstantComposite Constituent '" + << 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 '" + << inst->words[constituentIndex] + << "' type does not match Result Type '" + << 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 '" + << inst->words[constituentIndex] + << "' component type does not match Result Type '" + << resultType->second.id + << "'s matrix column component type."; + return false); + spvCheck( + componentCount != vector->second.inst->words[3], + DIAG(constituentIndex) + << "OpConstantComposite Constituent '" + << inst->words[constituentIndex] + << "' vector component count does not match Result Type '" + << 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 '" << 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 '" + << inst->words[constituentIndex] << "' is not defined."; + return false); + spvCheck(!spvOpcodeIsConstant(constituent->second.opcode), + DIAG(constituentIndex) + << "OpConstantComposite Constituent '" + << 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 '" + << inst->words[constituentIndex] + << "'s type does not match Result Type '" + << 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 '" + << inst->words[resultTypeIndex] + << "' count does not match Result Type '" + << 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 '" + << inst->words[constituentIndex] << "' is not define."; + return false); + spvCheck(!spvOpcodeIsConstant(constituent->second.opcode), + DIAG(constituentIndex) + << "OpConstantComposite Constituent '" + << 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 '" + << inst->words[constituentIndex] + << "' type does not match the Result Type '" + << resultType->second.id << "'s member type."; + return false); + } + } break; + default: { assert(0 && "Unreachable!"); } break; + } + return true; +} + +template <> +bool idUsage::isValid(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 '" + << inst->words[resultTypeIndex] + << "' is not defined."; + return false); + spvCheck(OpTypeSampler != resultType->second.opcode, + DIAG(resultTypeIndex) << "OpConstantSampler Result Type '" + << inst->words[resultTypeIndex] + << "' is not a sampler type."; + return false); + return true; +} + +template <> +bool idUsage::isValid(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 '" + << 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 '" + << 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 '" + << 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 '" + << 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 '" + << 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 '" + << inst->words[resultTypeIndex] + << "'s struct element type can not be null."; + return false); + } + } break; + } + return true; +} + +template <> +bool idUsage::isValid(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 '" + << inst->words[resultTypeIndex] + << "' is not defined."; + return false); + spvCheck(OpTypeBool != resultType->second.opcode, + DIAG(resultTypeIndex) << "OpSpecConstantTrue Result Type '" + << inst->words[resultTypeIndex] + << "' is not a boolean type."; + return false); + return true; +} + +template <> +bool idUsage::isValid(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 '" + << inst->words[resultTypeIndex] + << "' is not defined."; + return false); + spvCheck(OpTypeBool != resultType->second.opcode, + DIAG(resultTypeIndex) << "OpSpecConstantFalse Result Type '" + << inst->words[resultTypeIndex] + << "' is not a boolean type."; + return false); + return true; +} + +template <> +bool idUsage::isValid(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 '" + << inst->words[resultTypeIndex] + << "' is not defined."; + return false); + spvCheck(!spvOpcodeIsScalarType(resultType->second.opcode), + DIAG(resultTypeIndex) << "OpSpecConstant Result Type '" + << inst->words[resultTypeIndex] + << "' is not a scalar type."; + return false); + return true; +} + +#if 0 +template <> +bool idUsage::isValid( + const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {} +#endif + +#if 0 +template <> +bool idUsage::isValid(const spv_instruction_t *inst) {} +#endif + +template <> +bool idUsage::isValid(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 '" + << inst->words[resultTypeIndex] + << "' is not defined."; + return false); + spvCheck(OpTypePointer != resultType->second.opcode, + DIAG(resultTypeIndex) << "OpVariable Result Type '" + << 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 '" + << inst->words[initialiserIndex] + << "' is not defined."; + return false); + spvCheck(!spvOpcodeIsConstant(initialiser->second.opcode), + DIAG(initialiserIndex) << "OpVariable Initializer '" + << inst->words[initialiserIndex] + << "' is not a constant."; + return false); + } + return true; +} + +template <> +bool idUsage::isValid(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 '" + << inst->words[resultTypeIndex] + << "' is not defind."; + return false); + auto pointerIndex = 3; + auto pointer = find(inst->words[pointerIndex]); + spvCheck(!found(pointer), DIAG(pointerIndex) << "OpLoad Pointer '" + << inst->words[pointerIndex] + << "' is not defined."; + return false); + spvCheck(!spvOpcodeIsPointer(pointer->second.opcode), + DIAG(pointerIndex) << "OpLoad Pointer '" + << 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 '" + << inst->words[resultTypeIndex] + << " does not match Pointer '" + << pointer->second.id << "'s type."; + return false); + return true; +} + +template <> +bool idUsage::isValid(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 '" + << inst->words[pointerIndex] + << "' is not defined."; + return false); + spvCheck(!spvOpcodeIsPointer(pointer->second.opcode), + DIAG(pointerIndex) << "OpStore Pointer '" + << 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 '" + << 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 '" + << inst->words[objectIndex] + << "' is not defined."; + return false); + spvCheck(!spvOpcodeIsObject(object->second.opcode), + DIAG(objectIndex) << "OpStore Object '" + << 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 '" + << inst->words[objectIndex] << "'s type is void."; + return false); + + spvCheck(!spvOpcodeAreTypesEqual(type->second.inst, objectType->second.inst), + DIAG(pointerIndex) << "OpStore Pointer '" + << inst->words[pointerIndex] + << "'s type does not match Object '" + << objectType->second.id << "'s type."; + return false); + return true; +} + +template <> +bool idUsage::isValid(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 '" + << inst->words[targetIndex] + << "' is not defined."; + return false); + auto sourceIndex = 2; + auto source = find(inst->words[sourceIndex]); + spvCheck(!found(source), DIAG(targetIndex) << "OpCopyMemory Source '" + << 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 '" + << inst->words[sourceIndex] + << "'s type does not match Source '" + << sourceType->second.id << "'s type."; + return false); + return true; +} + +template <> +bool idUsage::isValid(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 '" + << inst->words[targetIndex] << "' is not defined."; + return false); + auto sourceIndex = 2; + auto source = find(inst->words[sourceIndex]); + spvCheck(!found(source), + DIAG(sourceIndex) << "OpCopyMemorySized Source '" + << inst->words[sourceIndex] << "' is not defined."; + return false); + auto sizeIndex = 3; + auto size = find(inst->words[sizeIndex]); + spvCheck(!found(size), DIAG(sizeIndex) << "OpCopyMemorySized, Size '" + << 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 '" + << 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 '" + << 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 '" + << 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 '" + << inst->words[sizeIndex] + << "'s variable type is not an integer type."; + return false); + } break; + default: + DIAG(sizeIndex) << "OpCopyMemorySized Size '" + << 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(const spv_instruction_t *inst, + const spv_opcode_desc opcodeEntry) {} +#endif + +#if 0 +template <> +bool idUsage::isValid( + const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {} +#endif + +#if 0 +template <> +bool idUsage::isValid(const spv_instruction_t *inst, + const spv_opcode_desc opcodeEntry) {} +#endif + +#if 0 +template <> +bool idUsage::isValid(const spv_instruction_t *inst, + const spv_opcode_desc opcodeEntry) {} +#endif + +#if 0 +template <> +bool idUsage::isValid( + const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {} +#endif + +template <> +bool idUsage::isValid(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 '" + << 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 '" + << inst->words[functionTypeIndex] + << "' is not defined."; + return false); + spvCheck(OpTypeFunction != functionType->second.opcode, + DIAG(functionTypeIndex) << "OpFunction Function Type '" + << 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 '" + << inst->words[resultTypeIndex] + << "' does not match the Function Type '" + << resultType->second.id << "'s return type."; + return false); + return true; +} + +template <> +bool idUsage::isValid(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 '" + << 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 '" + << inst->words[resultTypeIndex] + << "' does not match the OpTypeFunction parameter " + "type of the same index."; + return false); + return true; +} + +template <> +bool idUsage::isValid(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 '" + << inst->words[resultTypeIndex] + << "' is not defined."; + return false); + auto functionIndex = 3; + auto function = find(inst->words[functionIndex]); + spvCheck(!found(function), DIAG(functionIndex) + << "OpFunctionCall Function '" + << inst->words[functionIndex] + << "' is not defined."; + return false); + spvCheck(OpFunction != function->second.opcode, + DIAG(functionIndex) << "OpFunctionCall Function '" + << 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 '" << inst->words[resultTypeIndex] + << "'s type does not match Function '" << 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 '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 '" + << 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 '" + << inst->words[argumentIndex] + << "'s type does not match Function '" + << parameterType->second.id + << "'s parameter type."; + return false); + } + return true; +} + +#if 0 +template <> +bool idUsage::isValid(const spv_instruction_t *inst, + const spv_opcode_desc opcodeEntry) {} +#endif + +#if 0 +template <> +bool idUsage::isValid(const spv_instruction_t *inst, + const spv_opcode_desc opcodeEntry) { +} +#endif + +#if 0 +template <> +bool idUsage::isValid( + const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {} +#endif + +#if 0 +template <> +bool idUsage::isValid( + const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {} +#endif + +#if 0 +template <> +bool idUsage::isValid( + const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {} +#endif + +#if 0 +template <> +bool idUsage::isValid( + const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {} +#endif + +#if 0 +template <> +bool idUsage::isValid( + const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {} +#endif + +#if 0 +template <> +bool idUsage::isValid( + const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {} +#endif + +#if 0 +template <> +bool idUsage::isValid( + const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {} +#endif + +#if 0 +template <> +bool idUsage::isValid( + const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {} +#endif + +#if 0 +template <> +bool idUsage::isValid( + const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {} +#endif + +#if 0 +template <> +bool idUsage::isValid( + const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {} +#endif + +#if 0 +template <> +bool idUsage::isValid( + const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {} +#endif + +#if 0 +template <> +bool idUsage::isValid( + const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {} +#endif + +#if 0 +template <> +bool idUsage::isValid(const spv_instruction_t *inst) {} +#endif + +#if 0 +template <> +bool idUsage::isValid( + const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {} +#endif + +#if 0 +template <> +bool idUsage::isValid( + const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {} +#endif + +#if 0 +template <> +bool idUsage::isValid( + const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {} +#endif + +#if 0 +template <> +bool idUsage::isValid(const spv_instruction_t *inst, + const spv_opcode_desc opcodeEntry) { +} +#endif + +#if 0 +template <> +bool idUsage::isValid( + const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {} +#endif + +#if 0 +template <> +bool idUsage::isValid( + const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {} +#endif + +#if 0 +template <> +bool idUsage::isValid( + const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {} +#endif + +#if 0 +template <> +bool idUsage::isValid( + const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {} +#endif + +#if 0 +template <> +bool idUsage::isValid( + const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {} +#endif + +#if 0 +template <> +bool idUsage::isValid( + const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {} +#endif + +#if 0 +template <> +bool idUsage::isValid(const spv_instruction_t *inst, + const spv_opcode_desc opcodeEntry) {} +#endif + +#if 0 +template <> +bool idUsage::isValid(const spv_instruction_t *inst, + const spv_opcode_desc opcodeEntry) {} +#endif + +#if 0 +template <> +bool idUsage::isValid(const spv_instruction_t *inst, + const spv_opcode_desc opcodeEntry) {} +#endif + +#if 0 +template <> +bool idUsage::isValid(const spv_instruction_t *inst, + const spv_opcode_desc opcodeEntry) {} +#endif + +#if 0 +template <> +bool idUsage::isValid(const spv_instruction_t *inst, + const spv_opcode_desc opcodeEntry) {} +#endif + +#if 0 +template <> +bool idUsage::isValid(const spv_instruction_t *inst, + const spv_opcode_desc opcodeEntry) {} +#endif + +#if 0 +template <> +bool idUsage::isValid(const spv_instruction_t *inst, + const spv_opcode_desc opcodeEntry) {} +#endif + +#if 0 +template <> +bool idUsage::isValid(const spv_instruction_t *inst, + const spv_opcode_desc opcodeEntry) { +} +#endif + +#if 0 +template <> +bool idUsage::isValid(const spv_instruction_t *inst, + const spv_opcode_desc opcodeEntry) { +} +#endif + +#if 0 +template <> +bool idUsage::isValid( + const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {} +#endif + +#if 0 +template <> +bool idUsage::isValid( + const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {} +#endif + +#if 0 +template <> +bool idUsage::isValid(const spv_instruction_t *inst, + const spv_opcode_desc opcodeEntry) {} +#endif + +#if 0 +template <> +bool idUsage::isValid( + const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {} +#endif + +#if 0 +template <> +bool idUsage::isValid(const spv_instruction_t *inst) {} +#endif + +#if 0 +template <> +bool idUsage::isValid(const spv_instruction_t *inst) {} +#endif + +#if 0 +template <> +bool idUsage::isValid( + const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {} +#endif + +#if 0 +template <> +bool idUsage::isValid( + const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {} +#endif + +#if 0 +template <> +bool idUsage::isValid(const spv_instruction_t *inst, + const spv_opcode_desc opcodeEntry) { +} +#endif + +#if 0 +template <> +bool idUsage::isValid( + const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {} +#endif + +#if 0 +template <> +bool idUsage::isValid( + const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {} +#endif + +#if 0 +template <> +bool idUsage::isValid( + const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {} +#endif + +#if 0 +template <> +bool idUsage::isValid(const spv_instruction_t *inst, + const spv_opcode_desc opcodeEntry) {} +#endif + +#if 0 +template <> +bool idUsage::isValid(const spv_instruction_t *inst, + const spv_opcode_desc opcodeEntry) {} +#endif + +#if 0 +template <> +bool idUsage::isValid(const spv_instruction_t *inst, + const spv_opcode_desc opcodeEntry) {} +#endif + +#if 0 +template <> +bool idUsage::isValid(const spv_instruction_t *inst, + const spv_opcode_desc opcodeEntry) {} +#endif + +#if 0 +template <> +bool idUsage::isValid(const spv_instruction_t *inst, + const spv_opcode_desc opcodeEntry) {} +#endif + +#if 0 +template <> +bool idUsage::isValid(const spv_instruction_t *inst, + const spv_opcode_desc opcodeEntry) {} +#endif + +#if 0 +template <> +bool idUsage::isValid(const spv_instruction_t *inst, + const spv_opcode_desc opcodeEntry) {} +#endif + +#if 0 +template <> +bool idUsage::isValid(const spv_instruction_t *inst, + const spv_opcode_desc opcodeEntry) {} +#endif + +#if 0 +template <> +bool idUsage::isValid(const spv_instruction_t *inst, + const spv_opcode_desc opcodeEntry) {} +#endif + +#if 0 +template <> +bool idUsage::isValid(const spv_instruction_t *inst, + const spv_opcode_desc opcodeEntry) {} +#endif + +#if 0 +template <> +bool idUsage::isValid(const spv_instruction_t *inst, + const spv_opcode_desc opcodeEntry) {} +#endif + +#if 0 +template <> +bool idUsage::isValid(const spv_instruction_t *inst, + const spv_opcode_desc opcodeEntry) {} +#endif + +#if 0 +template <> +bool idUsage::isValid(const spv_instruction_t *inst, + const spv_opcode_desc opcodeEntry) {} +#endif + +#if 0 +template <> +bool idUsage::isValid(const spv_instruction_t *inst, + const spv_opcode_desc opcodeEntry) {} +#endif + +#if 0 +template <> +bool idUsage::isValid(const spv_instruction_t *inst, + const spv_opcode_desc opcodeEntry) {} +#endif + +#if 0 +template <> +bool idUsage::isValid(const spv_instruction_t *inst, + const spv_opcode_desc opcodeEntry) {} +#endif + +#if 0 +template <> +bool idUsage::isValid(const spv_instruction_t *inst, + const spv_opcode_desc opcodeEntry) {} +#endif + +#if 0 +template <> +bool idUsage::isValid(const spv_instruction_t *inst, + const spv_opcode_desc opcodeEntry) {} +#endif + +#if 0 +template <> +bool idUsage::isValid(const spv_instruction_t *inst, + const spv_opcode_desc opcodeEntry) {} +#endif + +#if 0 +template <> +bool idUsage::isValid( + const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {} +#endif + +#if 0 +template <> +bool idUsage::isValid( + const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {} +#endif + +#if 0 +template <> +bool idUsage::isValid( + const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {} +#endif + +#if 0 +template <> +bool idUsage::isValid( + const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {} +#endif + +#if 0 +template <> +bool idUsage::isValid( + const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {} +#endif + +#if 0 +template <> +bool idUsage::isValid(const spv_instruction_t *inst, + const spv_opcode_desc opcodeEntry) {} +#endif + +#if 0 +template <> +bool idUsage::isValid(const spv_instruction_t *inst, + const spv_opcode_desc opcodeEntry) {} +#endif + +#if 0 +template <> +bool idUsage::isValid( + const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {} +#endif + +#if 0 +template <> +bool idUsage::isValid( + const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {} +#endif + +#if 0 +template <> +bool idUsage::isValid( + const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {} +#endif + +#if 0 +template <> +bool idUsage::isValid(const spv_instruction_t *inst, + const spv_opcode_desc opcodeEntry) {} +#endif + +#if 0 +template <> +bool idUsage::isValid(const spv_instruction_t *inst, + const spv_opcode_desc opcodeEntry) {} +#endif + +#if 0 +template <> +bool idUsage::isValid(const spv_instruction_t *inst, + const spv_opcode_desc opcodeEntry) {} +#endif + +#if 0 +template <> +bool idUsage::isValid(const spv_instruction_t *inst, + const spv_opcode_desc opcodeEntry) {} +#endif + +#if 0 +template <> +bool idUsage::isValid(const spv_instruction_t *inst, + const spv_opcode_desc opcodeEntry) {} +#endif + +#if 0 +template <> +bool idUsage::isValid(const spv_instruction_t *inst, + const spv_opcode_desc opcodeEntry) {} +#endif + +#if 0 +template <> +bool idUsage::isValid(const spv_instruction_t *inst, + const spv_opcode_desc opcodeEntry) {} +#endif + +#if 0 +template <> +bool idUsage::isValid(const spv_instruction_t *inst, + const spv_opcode_desc opcodeEntry) {} +#endif + +#if 0 +template <> +bool idUsage::isValid(const spv_instruction_t *inst, + const spv_opcode_desc opcodeEntry) {} +#endif + +#if 0 +template <> +bool idUsage::isValid(const spv_instruction_t *inst, + const spv_opcode_desc opcodeEntry) {} +#endif + +#if 0 +template <> +bool idUsage::isValid(const spv_instruction_t *inst, + const spv_opcode_desc opcodeEntry) { +} +#endif + +#if 0 +template <> +bool idUsage::isValid(const spv_instruction_t *inst, + const spv_opcode_desc opcodeEntry) {} +#endif + +#if 0 +template <> +bool idUsage::isValid(const spv_instruction_t *inst, + const spv_opcode_desc opcodeEntry) {} +#endif + +#if 0 +template <> +bool idUsage::isValid(const spv_instruction_t *inst, + const spv_opcode_desc opcodeEntry) {} +#endif + +#if 0 +template <> +bool idUsage::isValid(const spv_instruction_t *inst, + const spv_opcode_desc opcodeEntry) {} +#endif + +#if 0 +template <> +bool idUsage::isValid(const spv_instruction_t *inst, + const spv_opcode_desc opcodeEntry) {} +#endif + +#if 0 +template <> +bool idUsage::isValid(const spv_instruction_t *inst, + const spv_opcode_desc opcodeEntry) {} +#endif + +#if 0 +template <> +bool idUsage::isValid(const spv_instruction_t *inst, + const spv_opcode_desc opcodeEntry) {} +#endif + +#if 0 +template <> +bool idUsage::isValid(const spv_instruction_t *inst, + const spv_opcode_desc opcodeEntry) {} +#endif + +#if 0 +template <> +bool idUsage::isValid(const spv_instruction_t *inst, + const spv_opcode_desc opcodeEntry) {} +#endif + +#if 0 +template <> +bool idUsage::isValid(const spv_instruction_t *inst, + const spv_opcode_desc opcodeEntry) {} +#endif + +#if 0 +template <> +bool idUsage::isValid(const spv_instruction_t *inst, + const spv_opcode_desc opcodeEntry) {} +#endif + +#if 0 +template <> +bool idUsage::isValid( + const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {} +#endif + +#if 0 +template <> +bool idUsage::isValid(const spv_instruction_t *inst, + const spv_opcode_desc opcodeEntry) {} +#endif + +#if 0 +template <> +bool idUsage::isValid(const spv_instruction_t *inst, + const spv_opcode_desc opcodeEntry) {} +#endif + +#if 0 +template <> +bool idUsage::isValid(const spv_instruction_t *inst, + const spv_opcode_desc opcodeEntry) {} +#endif + +#if 0 +template <> +bool idUsage::isValid( + const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {} +#endif + +#if 0 +template <> +bool idUsage::isValid(const spv_instruction_t *inst, + const spv_opcode_desc opcodeEntry) {} +#endif + +#if 0 +template <> +bool idUsage::isValid(const spv_instruction_t *inst, + const spv_opcode_desc opcodeEntry) {} +#endif + +#if 0 +template <> +bool idUsage::isValid( + const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {} +#endif + +#if 0 +template <> +bool idUsage::isValid( + const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {} +#endif + +#if 0 +template <> +bool idUsage::isValid( + const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {} +#endif + +#if 0 +template <> +bool idUsage::isValid( + const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {} +#endif + +#if 0 +template <> +bool idUsage::isValid( + const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {} +#endif + +#if 0 +template <> +bool idUsage::isValid( + const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {} +#endif + +#if 0 +template <> +bool idUsage::isValid( + const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {} +#endif + +#if 0 +template <> +bool idUsage::isValid( + const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {} +#endif + +#if 0 +template <> +bool idUsage::isValid( + const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {} +#endif + +#if 0 +template <> +bool idUsage::isValid( + const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {} +#endif + +#if 0 +template <> +bool idUsage::isValid(const spv_instruction_t *inst, + const spv_opcode_desc opcodeEntry) {} +#endif + +#if 0 +template <> +bool idUsage::isValid(const spv_instruction_t *inst, + const spv_opcode_desc opcodeEntry) {} +#endif + +#if 0 +template <> +bool idUsage::isValid(const spv_instruction_t *inst, + const spv_opcode_desc opcodeEntry) {} +#endif + +#if 0 +template <> +bool idUsage::isValid(const spv_instruction_t *inst, + const spv_opcode_desc opcodeEntry) {} +#endif + +#if 0 +template <> +bool idUsage::isValid(const spv_instruction_t *inst, + const spv_opcode_desc opcodeEntry) {} +#endif + +#if 0 +template <> +bool idUsage::isValid(const spv_instruction_t *inst, + const spv_opcode_desc opcodeEntry) {} +#endif + +#if 0 +template <> +bool idUsage::isValid(const spv_instruction_t *inst, + const spv_opcode_desc opcodeEntry) {} +#endif + +#if 0 +template <> +bool idUsage::isValid(const spv_instruction_t *inst, + const spv_opcode_desc opcodeEntry) {} +#endif + +#if 0 +template <> +bool idUsage::isValid(const spv_instruction_t *inst, + const spv_opcode_desc opcodeEntry) {} +#endif + +#if 0 +template <> +bool idUsage::isValid(const spv_instruction_t *inst, + const spv_opcode_desc opcodeEntry) {} +#endif + +#if 0 +template <> +bool idUsage::isValid(const spv_instruction_t *inst, + const spv_opcode_desc opcodeEntry) {} +#endif + +#if 0 +template <> +bool idUsage::isValid( + const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {} +#endif + +#if 0 +template <> +bool idUsage::isValid(const spv_instruction_t *inst, + const spv_opcode_desc opcodeEntry) {} +#endif + +#if 0 +template <> +bool idUsage::isValid( + const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {} +#endif + +#if 0 +template <> +bool idUsage::isValid(const spv_instruction_t *inst, + const spv_opcode_desc opcodeEntry) {} +#endif + +template <> +bool idUsage::isValid(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 '" + << inst->words[valueIndex] + << "' is not defined."; + return false); + spvCheck(!spvOpcodeIsValue(value->second.opcode), + DIAG(valueIndex) << "OpReturnValue Value '" + << 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 '" << 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 '" << inst->words[valueIndex] + << "'s type does not match OpFunction's return type."; + return false); + } + return true; +} + +#if 0 +template <> +bool idUsage::isValid(const spv_instruction_t *inst, + const spv_opcode_desc opcodeEntry) { +} +#endif + +#if 0 +template <> +bool idUsage::isValid(const spv_instruction_t *inst, + const spv_opcode_desc opcodeEntry) {} +#endif + +#if 0 +template <> +bool idUsage::isValid(const spv_instruction_t *inst, + const spv_opcode_desc opcodeEntry) {} +#endif + +#if 0 +template <> +bool idUsage::isValid(const spv_instruction_t *inst, + const spv_opcode_desc opcodeEntry) {} +#endif + +#if 0 +template <> +bool idUsage::isValid(const spv_instruction_t *inst, + const spv_opcode_desc opcodeEntry) {} +#endif + +#if 0 +template <> +bool idUsage::isValid( + const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {} +#endif + +#if 0 +template <> +bool idUsage::isValid( + const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {} +#endif + +#if 0 +template <> +bool idUsage::isValid( + const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {} +#endif + +#if 0 +template <> +bool idUsage::isValid( + const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {} +#endif + +#if 0 +template <> +bool idUsage::isValid( + const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {} +#endif + +#if 0 +template <> +bool idUsage::isValid(const spv_instruction_t *inst, + const spv_opcode_desc opcodeEntry) {} +#endif + +#if 0 +template <> +bool idUsage::isValid(const spv_instruction_t *inst, + const spv_opcode_desc opcodeEntry) {} +#endif + +#if 0 +template <> +bool idUsage::isValid(const spv_instruction_t *inst, + const spv_opcode_desc opcodeEntry) {} +#endif + +#if 0 +template <> +bool idUsage::isValid(const spv_instruction_t *inst, + const spv_opcode_desc opcodeEntry) {} +#endif + +#if 0 +template <> +bool idUsage::isValid(const spv_instruction_t *inst, + const spv_opcode_desc opcodeEntry) {} +#endif + +#if 0 +template <> +bool idUsage::isValid(const spv_instruction_t *inst, + const spv_opcode_desc opcodeEntry) {} +#endif + +#if 0 +template <> +bool idUsage::isValid(const spv_instruction_t *inst, + const spv_opcode_desc opcodeEntry) {} +#endif + +#if 0 +template <> +bool idUsage::isValid(const spv_instruction_t *inst, + const spv_opcode_desc opcodeEntry) {} +#endif + +#if 0 +template <> +bool idUsage::isValid(const spv_instruction_t *inst, + const spv_opcode_desc opcodeEntry) {} +#endif + +#if 0 +template <> +bool idUsage::isValid( + const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {} +#endif + +#if 0 +template <> +bool idUsage::isValid( + const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {} +#endif + +#if 0 +template <> +bool idUsage::isValid( + const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {} +#endif + +#if 0 +template <> +bool idUsage::isValid( + const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {} +#endif + +#if 0 +template <> +bool idUsage::isValid(const spv_instruction_t *inst, + const spv_opcode_desc opcodeEntry) {} +#endif + +#if 0 +template <> +bool idUsage::isValid(const spv_instruction_t *inst, + const spv_opcode_desc opcodeEntry) {} +#endif + +#if 0 +template <> +bool idUsage::isValid( + const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {} +#endif + +#if 0 +template <> +bool idUsage::isValid(const spv_instruction_t *inst, + const spv_opcode_desc opcodeEntry) {} +#endif + +#if 0 +template <> +bool idUsage::isValid(const spv_instruction_t *inst, + const spv_opcode_desc opcodeEntry) {} +#endif + +#if 0 +template <> +bool idUsage::isValid(const spv_instruction_t *inst, + const spv_opcode_desc opcodeEntry) {} +#endif + +#if 0 +template <> +bool idUsage::isValid(const spv_instruction_t *inst, + const spv_opcode_desc opcodeEntry) {} +#endif + +#if 0 +template <> +bool idUsage::isValid(const spv_instruction_t *inst, + const spv_opcode_desc opcodeEntry) {} +#endif + +#if 0 +template <> +bool idUsage::isValid(const spv_instruction_t *inst, + const spv_opcode_desc opcodeEntry) {} +#endif + +#if 0 +template <> +bool idUsage::isValid(const spv_instruction_t *inst, + const spv_opcode_desc opcodeEntry) {} +#endif + +#if 0 +template <> +bool idUsage::isValid(const spv_instruction_t *inst, + const spv_opcode_desc opcodeEntry) {} +#endif + +#if 0 +template <> +bool idUsage::isValid(const spv_instruction_t *inst, + const spv_opcode_desc opcodeEntry) { +} +#endif + +#if 0 +template <> +bool idUsage::isValid(const spv_instruction_t *inst, + const spv_opcode_desc opcodeEntry) { +} +#endif + +#if 0 +template <> +bool idUsage::isValid( + const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {} +#endif + +#if 0 +template <> +bool idUsage::isValid( + const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {} +#endif + +#if 0 +template <> +bool idUsage::isValid( + const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {} +#endif + +#if 0 +template <> +bool idUsage::isValid( + const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {} +#endif + +#if 0 +template <> +bool idUsage::isValid(const spv_instruction_t *inst, + const spv_opcode_desc opcodeEntry) {} +#endif + +#if 0 +template <> +bool idUsage::isValid(const spv_instruction_t *inst, + const spv_opcode_desc opcodeEntry) {} +#endif + +#if 0 +template <> +bool idUsage::isValid( + const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {} +#endif + +#if 0 +template <> +bool idUsage::isValid(const spv_instruction_t *inst, + const spv_opcode_desc opcodeEntry) {} +#endif + +#if 0 +template <> +bool idUsage::isValid( + const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {} +#endif + +#if 0 +template <> +bool idUsage::isValid( + const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {} +#endif + +#if 0 +template <> +bool idUsage::isValid( + const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {} +#endif + +#if 0 +template <> +bool idUsage::isValid(const spv_instruction_t *inst, + const spv_opcode_desc opcodeEntry) {} +#endif + +#if 0 +template <> +bool idUsage::isValid(const spv_instruction_t *inst, + const spv_opcode_desc opcodeEntry) {} +#endif + +#if 0 +template <> +bool idUsage::isValid(const spv_instruction_t *inst, + const spv_opcode_desc opcodeEntry) {} +#endif + +#if 0 +template <> +bool idUsage::isValid( + const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {} +#endif + +#if 0 +template <> +bool idUsage::isValid( + const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {} +#endif + +#if 0 +template <> +bool idUsage::isValid( + const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {} +#endif + +#if 0 +template <> +bool idUsage::isValid( + const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {} +#endif + +#if 0 +template <> +bool idUsage::isValid( + const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {} +#endif + +#if 0 +template <> +bool idUsage::isValid( + const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {} +#endif + +#if 0 +template <> +bool idUsage::isValid( + const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {} +#endif + +#if 0 +template <> +bool idUsage::isValid( + const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {} +#endif + +#if 0 +template <> +bool idUsage::isValid( + const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {} +#endif + +#if 0 +template <> +bool idUsage::isValid( + const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {} +#endif + +#if 0 +template <> +bool idUsage::isValid( + const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {} +#endif + +#if 0 +template <> +bool idUsage::isValid( + const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {} +#endif + +#if 0 +template <> +bool idUsage::isValid( + 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(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 index 000000000..64da85165 --- /dev/null +++ b/test/BinaryEndianness.cpp @@ -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 index 000000000..0cab66b75 --- /dev/null +++ b/test/BinaryHeaderGet.cpp @@ -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 index 000000000..b2f5efe83 --- /dev/null +++ b/test/BinaryToText.cpp @@ -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 index 000000000..bcbe6c252 --- /dev/null +++ b/test/DiagnosticPrint.cpp @@ -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 index 000000000..500ca6427 --- /dev/null +++ b/test/FixWord.cpp @@ -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 index 000000000..bae3a9162 --- /dev/null +++ b/test/NamedId.cpp @@ -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 index 000000000..bb0b5934c --- /dev/null +++ b/test/OpcodeIsVariable.cpp @@ -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 index 000000000..755dd1ad6 --- /dev/null +++ b/test/OpcodeMake.cpp @@ -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 + +TEST(OpcodeMake, DISABLED_Default) { + for (uint16_t wordCount = 0; wordCount < std::numeric_limits::max(); + ++wordCount) { + for (uint16_t code = 0; code < std::numeric_limits::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 index 000000000..be808f3d0 --- /dev/null +++ b/test/OpcodeRequiresCapabilities.cpp @@ -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 { + 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 index 000000000..142823261 --- /dev/null +++ b/test/OpcodeSplit.cpp @@ -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 index 000000000..99eab3da8 --- /dev/null +++ b/test/OpcodeTableGet.cpp @@ -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 index 000000000..b7c7bd59d --- /dev/null +++ b/test/OperandTableGet.cpp @@ -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 index 000000000..969a8699f --- /dev/null +++ b/test/TextAdvance.cpp @@ -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 index 000000000..289ce9cad --- /dev/null +++ b/test/TextDestroy.cpp @@ -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 index 000000000..e36d10ae1 --- /dev/null +++ b/test/TextToBinary.cpp @@ -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 index 000000000..b67b78850 --- /dev/null +++ b/test/TextWordGet.cpp @@ -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 index 000000000..60b48895a --- /dev/null +++ b/test/UnitSPIRV.h @@ -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 +#include "../source/binary.h" +#include "../source/diagnostic.h" +#include "../source/opcode.h" +#include "../source/text.h" +#include "../source/validate.h" + +#include + +#include + +// 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 index 000000000..351bb504d --- /dev/null +++ b/test/Validate.cpp @@ -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 index 000000000..13c0f3148 --- /dev/null +++ b/test/ValidateID.cpp @@ -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 index 000000000..6a241cdd0 --- /dev/null +++ b/test/main.cpp @@ -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 + +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 index 000000000..b36a1d98d --- /dev/null +++ b/tools/as/as.cpp @@ -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 + +#include +#include + +void print_usage(char *argv0) { + printf( + "Assemble a *.svasm file into a *.sv binary.\n\n" + "USAGE: %s [options] \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 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 index 000000000..55550735f --- /dev/null +++ b/tools/dis/dis.cpp @@ -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 + +#include +#include + +void print_usage(char *argv0) { + printf( + "Dissassemble a *.sv file into a *.svasm text file.\n\n" + "USAGE: %s [options] \n\n" + " -o 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 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 index 000000000..2d11d9206 --- /dev/null +++ b/tools/val/val.cpp @@ -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 + +#include +#include +#include + +#include + +void print_usage(char *argv0) { + printf( + "Validate a SPIR-V binary file.\n\n" + "USAGE: %s [options] \n\n" + " -basic Perform basic validation (disabled)\n" + " -layout Perform layout validation " + "(disabled)\n" + " -id Perform id validation (default ON)\n" + " -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 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; +}