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.
This commit is contained in:
Kenneth Benzie (Benie) 2015-05-22 18:26:19 +01:00
Коммит 83e5a29b06
49 изменённых файлов: 15509 добавлений и 0 удалений

65
.clang-format Normal file
Просмотреть файл

@ -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
...

2
.gitignore поставляемый Normal file
Просмотреть файл

@ -0,0 +1,2 @@
build*
.ycm_extra_conf.py*

188
CMakeLists.txt Normal file
Просмотреть файл

@ -0,0 +1,188 @@
# Copyright (c) 2015 The Khronos Group Inc.
#
# Permission is hereby granted, free of charge, to any person obtaining a
# copy of this software and/or associated documentation files (the
# "Materials"), to deal in the Materials without restriction, including
# without limitation the rights to use, copy, modify, merge, publish,
# distribute, sublicense, and/or sell copies of the Materials, and to
# permit persons to whom the Materials are furnished to do so, subject to
# the following conditions:
#
# The above copyright notice and this permission notice shall be included
# in all copies or substantial portions of the Materials.
#
# MODIFICATIONS TO THIS FILE MAY MEAN IT NO LONGER ACCURATELY REFLECTS
# KHRONOS STANDARDS. THE UNMODIFIED, NORMATIVE VERSIONS OF KHRONOS
# SPECIFICATIONS AND HEADER INFORMATION ARE LOCATED AT
# https://www.khronos.org/registry/
#
# THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
# IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
# CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
# TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
# MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
cmake_minimum_required(VERSION 2.8)
project(SPIRV)
if("${CMAKE_SYSTEM_NAME}" STREQUAL "Linux")
add_definitions(-DSPIRV_LINUX)
elseif("${CMAKE_SYSTEM_NAME}" STREQUAL "Windows")
add_definitions(-DSPIRV_WINDOWS)
elseif("${CMAKE_SYSTEM_NAME}" STREQUAL "Darwin")
add_definitions(-DSPIRV_MAC)
else()
message(FATAL_ERROR "Your platform '${CMAKE_SYSTEM_NAME}' is not supported!")
endif()
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib)
if (UNIX)
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib)
elseif(WIN32)
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin)
endif()
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin)
if (NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES)
message(STATUS "No build type selected, default to Debug")
set(CMAKE_BUILD_TYPE "Debug")
endif()
if(UNIX)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -fno-exceptions -fno-rtti")
if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fcolor-diagnostics")
set(SPIRV_USE_SANITIZER "" CACHE STRING
"Use the clang sanitizer [address|memory|thread|...]")
if(NOT "${SPIRV_USE_SANITIZER}" STREQUAL "")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fsanitize=${SPIRV_USE_SANITIZER}")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=${SPIRV_USE_SANITIZER}")
endif()
endif()
endif()
if(UNIX)
option(SPIRV_COLOR_TERMINAL "Enable color terminal output" ON)
if(${SPIRV_COLOR_TERMINAL})
add_definitions(-DSPV_COLOR_TERMINAL)
endif()
endif()
if(UNIX)
set(SPIRV_WARNINGS "-Wall -Wextra -Wno-missing-field-initializers")
option(SPIRV_WARN_EVERYTHING "Enable -Weverything for SPIRV library" OFF)
if(${SPIRV_WARN_EVERYTHING})
set(SPIRV_WARNINGS
"${SPIRV_WARNINGS} -Weverything -Wno-c++98-compat -Wno-c++98-compat-pedantic -Wno-padded")
endif()
elseif(WIN32)
set(SPIRV_WARNINGS "-D_CRT_SECURE_NO_WARNINGS /wd4800")
endif()
if(UNIX)
option(SPIRV_WERROR "Enable error on warning" OFF)
if(${SPIRV_WERROR})
set(SPIRV_WARNINGS "${SPIRV_WARNINGS} -Werror")
endif()
endif()
include_directories(SYSTEM
${CMAKE_CURRENT_SOURCE_DIR}/external/include)
include_directories(
${CMAKE_CURRENT_SOURCE_DIR}/include)
set(SPIRV_SOURCES
${CMAKE_CURRENT_SOURCE_DIR}/include/libspirv/libspirv.h
${CMAKE_CURRENT_SOURCE_DIR}/source/binary.h
${CMAKE_CURRENT_SOURCE_DIR}/source/diagnostic.h
${CMAKE_CURRENT_SOURCE_DIR}/source/opcode.h
${CMAKE_CURRENT_SOURCE_DIR}/source/operand.h
${CMAKE_CURRENT_SOURCE_DIR}/source/print.h
${CMAKE_CURRENT_SOURCE_DIR}/source/text.h
${CMAKE_CURRENT_SOURCE_DIR}/source/validate.h
${CMAKE_CURRENT_SOURCE_DIR}/source/binary.cpp
${CMAKE_CURRENT_SOURCE_DIR}/source/diagnostic.cpp
${CMAKE_CURRENT_SOURCE_DIR}/source/ext_inst.cpp
${CMAKE_CURRENT_SOURCE_DIR}/source/opcode.cpp
${CMAKE_CURRENT_SOURCE_DIR}/source/operand.cpp
${CMAKE_CURRENT_SOURCE_DIR}/source/print.cpp
${CMAKE_CURRENT_SOURCE_DIR}/source/text.cpp
${CMAKE_CURRENT_SOURCE_DIR}/source/validate.cpp
${CMAKE_CURRENT_SOURCE_DIR}/source/validate_id.cpp)
add_library(SPIRV ${SPIRV_SOURCES})
target_link_libraries(SPIRV ${SPIRV_LIBS})
set_target_properties(SPIRV PROPERTIES COMPILE_FLAGS ${SPIRV_WARNINGS})
add_executable(spirv-as
${CMAKE_CURRENT_SOURCE_DIR}/include/libspirv/libspirv.h
${CMAKE_CURRENT_SOURCE_DIR}/tools/as/as.cpp)
set_target_properties(spirv-as PROPERTIES COMPILE_FLAGS ${SPIRV_WARNINGS})
target_link_libraries(spirv-as SPIRV)
add_executable(spirv-dis
${CMAKE_CURRENT_SOURCE_DIR}/include/libspirv/libspirv.h
${CMAKE_CURRENT_SOURCE_DIR}/tools/dis/dis.cpp)
set_target_properties(spirv-dis PROPERTIES COMPILE_FLAGS ${SPIRV_WARNINGS})
target_link_libraries(spirv-dis SPIRV)
add_executable(spirv-val
${CMAKE_CURRENT_SOURCE_DIR}/include/libspirv/libspirv.h
${CMAKE_CURRENT_SOURCE_DIR}/tools/val/val.cpp)
set_target_properties(spirv-val PROPERTIES COMPILE_FLAGS ${SPIRV_WARNINGS})
target_link_libraries(spirv-val SPIRV)
set(GTEST_DIR ${CMAKE_CURRENT_SOURCE_DIR}/external/googletest)
if(EXISTS ${GTEST_DIR})
if(WIN32)
option(gtest_force_shared_crt
"Use shared (DLL) run-time lib even when Google Test is built as static lib."
ON)
endif()
message(STATUS "Found googletest, building tests.")
include_directories(SYSTEM
${CMAKE_CURRENT_SOURCE_DIR}/external/googletest
${CMAKE_CURRENT_SOURCE_DIR}/external/googletest/include)
add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/external/googletest)
add_executable(UnitSPIRV
${CMAKE_CURRENT_SOURCE_DIR}/test/UnitSPIRV.h
${CMAKE_CURRENT_SOURCE_DIR}/test/BinaryEndianness.cpp
${CMAKE_CURRENT_SOURCE_DIR}/test/FixWord.cpp
${CMAKE_CURRENT_SOURCE_DIR}/test/BinaryHeaderGet.cpp
${CMAKE_CURRENT_SOURCE_DIR}/test/BinaryToText.cpp
${CMAKE_CURRENT_SOURCE_DIR}/test/NamedId.cpp
${CMAKE_CURRENT_SOURCE_DIR}/test/OpcodeTableGet.cpp
${CMAKE_CURRENT_SOURCE_DIR}/test/OpcodeIsVariable.cpp
${CMAKE_CURRENT_SOURCE_DIR}/test/OpcodeRequiresCapabilities.cpp
${CMAKE_CURRENT_SOURCE_DIR}/test/OpcodeMake.cpp
${CMAKE_CURRENT_SOURCE_DIR}/test/OpcodeSplit.cpp
${CMAKE_CURRENT_SOURCE_DIR}/test/OperandTableGet.cpp
${CMAKE_CURRENT_SOURCE_DIR}/test/TextAdvance.cpp
${CMAKE_CURRENT_SOURCE_DIR}/test/TextWordGet.cpp
${CMAKE_CURRENT_SOURCE_DIR}/test/TextToBinary.cpp
${CMAKE_CURRENT_SOURCE_DIR}/test/TextDestroy.cpp
${CMAKE_CURRENT_SOURCE_DIR}/test/DiagnosticPrint.cpp
${CMAKE_CURRENT_SOURCE_DIR}/test/Validate.cpp
${CMAKE_CURRENT_SOURCE_DIR}/test/ValidateID.cpp
${CMAKE_CURRENT_SOURCE_DIR}/test/main.cpp)
target_link_libraries(UnitSPIRV SPIRV gtest)
else()
message(STATUS "Did not find googletest, tests will not be built."
"To enable tests place googletest in '<spirv-dir>/external/googletest'.")
endif()
set(CMAKE_INSTALL_PREFIX ${CMAKE_CURRENT_BINARY_DIR}/install)
install(TARGETS SPIRV spirv-as spirv-dis spirv-val
RUNTIME DESTINATION bin
LIBRARY DESTINATION lib
ARCHIVE DESTINATION lib)
install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/include/libspirv/libspirv.h
DESTINATION include/libspirv/)

213
external/include/headers/GLSL450Lib.h поставляемый Normal file
Просмотреть файл

@ -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

307
external/include/headers/OpenCLLib.h поставляемый Normal file
Просмотреть файл

@ -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

1354
external/include/headers/spirv.h поставляемый Normal file

Разница между файлами не показана из-за своего большого размера Загрузить разницу

423
include/libspirv/libspirv.h Normal file
Просмотреть файл

@ -0,0 +1,423 @@
// Copyright (c) 2015 The Khronos Group Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and/or associated documentation files (the
// "Materials"), to deal in the Materials without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Materials, and to
// permit persons to whom the Materials are furnished to do so, subject to
// the following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Materials.
//
// MODIFICATIONS TO THIS FILE MAY MEAN IT NO LONGER ACCURATELY REFLECTS
// KHRONOS STANDARDS. THE UNMODIFIED, NORMATIVE VERSIONS OF KHRONOS
// SPECIFICATIONS AND HEADER INFORMATION ARE LOCATED AT
// https://www.khronos.org/registry/
//
// THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
// MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
#ifndef _CODEPLAY_SPIRV_SPIRV_H_
#define _CODEPLAY_SPIRV_SPIRV_H_
#include <headers/spirv.h>
#include <headers/GLSL450Lib.h>
#include <headers/OpenCLLib.h>
#ifdef __cplusplus
using namespace spv;
extern "C" {
#endif
#include <stddef.h>
#include <stdint.h>
// Magic numbers
#define SPV_MAGIC_NUMBER 0x07230203
#define SPV_VERSION_NUMBER 99u
// Header indices
#define SPV_INDEX_MAGIC_NUMBER 0u
#define SPV_INDEX_VERSION_NUMBER 1u
#define SPV_INDEX_GENERATOR_NUMBER 2u
#define SPV_INDEX_BOUND 3u
#define SPV_INDEX_SCHEMA 4u
#define SPV_INDEX_INSTRUCTION 5u
// Universal limits
// NOTE: These are set to the minimum maximum values
#define SPV_LIMIT_LITERAL_NAME_MAX 0x00000400
#define SPV_LIMIT_LITERAL_STRING_MAX 0x00010000
#define SPV_LIMIT_INSTRUCTION_WORD_COUNT_MAX 0x00000108
#define SPV_LIMIT_RESULT_ID_BOUND 0x00400000
#define SPV_LIMIT_CONTROL_FLOW_NEST_DEPTH 0x00000400
#define SPV_LIMIT_GLOBAL_VARIABLES_MAX 0x00010000
#define SPV_LIMIT_LOCAL_VARIABLES_MAX 0x00080000
// TODO: Decorations per target ID max, depends on decoration table size
#define SPV_LIMIT_EXECUTION_MODE_PER_ENTRY_POINT_MAX 0x00000100
#define SPV_LIMIT_INDICIES_MAX_ACCESS_CHAIN_COMPOSITE_MAX 0x00000100
#define SPV_LIMIT_FUNCTION_PARAMETERS_PER_FUNCTION_DECL 0x00000100
#define SPV_LIMIT_FUNCTION_CALL_ARGUMENTS_MAX 0x00000100
#define SPV_LIMIT_EXT_FUNCTION_CALL_ARGUMENTS_MAX 0x00000100
#define SPV_LIMIT_SWITCH_LITERAL_LABEL_PAIRS_MAX 0x00004000
#define SPV_LIMIT_STRUCT_MEMBERS_MAX 0x0000400
#define SPV_LIMIT_STRUCT_NESTING_DEPTH_MAX 0x00000100
// Helpers
#define spvCheck(condition, action) \
if (condition) { \
action; \
}
#define spvCheckReturn(expression) \
{ \
spv_result_t error = (expression); \
if (error) { \
return error; \
} \
}
#define spvIsInBitfield(value, bitfield) (value == (value & bitfield))
#define SPV_BIT(shift) 1 << shift
#define SPV_FORCE_16_BIT_ENUM(name) _##name = 0x7fff
#define SPV_FORCE_32_BIT_ENUM(name) _##name = 0x7fffffff
// Enumerations
typedef enum spv_generator_t {
SPV_GENERATOR_KHRONOS = 0,
SPV_GENERATOR_VALVE = 1,
SPV_GENERATOR_LUNARG = 2,
SPV_GENERATOR_CODEPLAY = 3,
SPV_FORCE_32_BIT_ENUM(spv_generator_t)
} spv_generator_t;
typedef enum spv_result_t {
SPV_SUCCESS = 0,
SPV_UNSUPPORTED = 1,
SPV_END_OF_STREAM = 2,
SPV_WARNING = 3,
SPV_ERROR_INTERNAL = -1,
SPV_ERROR_OUT_OF_MEMORY = -2,
SPV_ERROR_INVALID_POINTER = -3,
SPV_ERROR_INVALID_BINARY = -4,
SPV_ERROR_INVALID_TEXT = -5,
SPV_ERROR_INVALID_TABLE = -6,
SPV_ERROR_INVALID_VALUE = -7,
SPV_ERROR_INVALID_DIAGNOSTIC = -8,
SPV_ERROR_INVALID_LOOKUP = -9,
SPV_ERROR_INVALID_ID = -10,
SPV_FORCE_32_BIT_ENUM(spv_result_t)
} spv_result_t;
typedef enum spv_endianness_t {
SPV_ENDIANNESS_LITTLE,
SPV_ENDIANNESS_BIG,
SPV_FORCE_32_BIT_ENUM(spv_endianness_t)
} spv_endianness_t;
typedef enum spv_opcode_flags_t {
SPV_OPCODE_FLAGS_NONE = 0,
SPV_OPCODE_FLAGS_VARIABLE = 1,
SPV_OPCODE_FLAGS_CAPABILITIES = 2,
SPV_FORCE_32_BIT_ENUM(spv_opcode_flags_t)
} spv_opcode_flags_t;
typedef enum spv_operand_type_t {
SPV_OPERAND_TYPE_NONE,
SPV_OPERAND_TYPE_ID,
SPV_OPERAND_TYPE_RESULT_ID,
SPV_OPERAND_TYPE_LITERAL,
SPV_OPERAND_TYPE_LITERAL_NUMBER,
SPV_OPERAND_TYPE_LITERAL_STRING,
SPV_OPERAND_TYPE_SOURCE_LANGUAGE,
SPV_OPERAND_TYPE_EXECUTION_MODEL,
SPV_OPERAND_TYPE_ADDRESSING_MODEL,
SPV_OPERAND_TYPE_MEMORY_MODEL,
SPV_OPERAND_TYPE_EXECUTION_MODE,
SPV_OPERAND_TYPE_STORAGE_CLASS,
SPV_OPERAND_TYPE_DIMENSIONALITY,
SPV_OPERAND_TYPE_SAMPLER_ADDRESSING_MODE,
SPV_OPERAND_TYPE_SAMPLER_FILTER_MODE,
SPV_OPERAND_TYPE_FP_FAST_MATH_MODE,
SPV_OPERAND_TYPE_FP_ROUNDING_MODE,
SPV_OPERAND_TYPE_LINKAGE_TYPE,
SPV_OPERAND_TYPE_ACCESS_QUALIFIER,
SPV_OPERAND_TYPE_FUNCTION_PARAMETER_ATTRIBUTE,
SPV_OPERAND_TYPE_DECORATION,
SPV_OPERAND_TYPE_BUILT_IN,
SPV_OPERAND_TYPE_SELECTION_CONTROL,
SPV_OPERAND_TYPE_LOOP_CONTROL,
SPV_OPERAND_TYPE_FUNCTION_CONTROL,
SPV_OPERAND_TYPE_MEMORY_SEMANTICS,
SPV_OPERAND_TYPE_MEMORY_ACCESS,
SPV_OPERAND_TYPE_EXECUTION_SCOPE,
SPV_OPERAND_TYPE_GROUP_OPERATION,
SPV_OPERAND_TYPE_KERNEL_ENQ_FLAGS,
SPV_OPERAND_TYPE_KERENL_PROFILING_INFO,
SPV_OPERAND_TYPE_CAPABILITY,
SPV_OPERAND_TYPE_ELLIPSIS, // NOTE: Unspecified variable operands
SPV_FORCE_32_BIT_ENUM(spv_operand_type_t)
} spv_operand_type_t;
typedef enum spv_ext_inst_type_t {
SPV_EXT_INST_TYPE_NONE,
SPV_EXT_INST_TYPE_GLSL_STD_450,
SPV_EXT_INST_TYPE_OPENCL_STD_12,
SPV_EXT_INST_TYPE_OPENCL_STD_20,
SPV_EXT_INST_TYPE_OPENCL_STD_21,
SPV_FORCE_32_BIT_ENUM(spv_ext_inst_type_t)
} spv_ext_inst_type_t;
typedef enum spv_binary_to_text_options_t {
SPV_BINARY_TO_TEXT_OPTION_NONE = SPV_BIT(0),
SPV_BINARY_TO_TEXT_OPTION_PRINT = SPV_BIT(1),
SPV_BINARY_TO_TEXT_OPTION_COLOR = SPV_BIT(2),
SPV_FORCE_32_BIT_ENUM(spv_binary_to_text_options_t)
} spv_binary_to_text_options_t;
typedef enum spv_validate_options_t {
SPV_VALIDATE_BASIC_BIT = SPV_BIT(0),
SPV_VALIDATE_LAYOUT_BIT = SPV_BIT(1),
SPV_VALIDATE_ID_BIT = SPV_BIT(2),
SPV_VALIDATE_RULES_BIT = SPV_BIT(3),
SPV_VALIDATE_ALL = SPV_VALIDATE_BASIC_BIT | SPV_VALIDATE_LAYOUT_BIT |
SPV_VALIDATE_ID_BIT | SPV_VALIDATE_RULES_BIT,
SPV_FORCE_32_BIT_ENUM(spv_validation_options_t)
} spv_validate_options_t;
// Structures
typedef struct spv_header_t {
uint32_t magic;
uint32_t version;
uint32_t generator;
uint32_t bound;
uint32_t schema; // NOTE: Reserved
const uint32_t *instructions; // NOTE: Unfixed pointer to instruciton stream
} spv_header_t;
typedef struct spv_opcode_desc_t {
const char *name;
const uint16_t wordCount;
const Op opcode;
const uint32_t flags; // Bitfield of spv_opcode_flags_t
const uint32_t capabilities; // spv_language_capabilities_t
const spv_operand_type_t operandTypes[16]; // TODO: Smaller/larger?
} spv_opcode_desc_t;
typedef struct spv_opcode_table_t {
const uint32_t count;
const spv_opcode_desc_t *entries;
} spv_opcode_table_t;
typedef struct spv_operand_desc_t {
const char *name;
const uint32_t value;
const uint32_t flags; // Bitfield of spv_opcode_flags_t
const uint32_t capabilities; // spv_language_capabilities_t
const spv_operand_type_t operandTypes[16]; // TODO: Smaller/larger?
} spv_operand_desc_t;
typedef struct spv_operand_desc_group_t {
const spv_operand_type_t type;
const uint32_t count;
const spv_operand_desc_t *entries;
} spv_operand_desc_group_t;
typedef struct spv_operand_table_t {
const uint32_t count;
const spv_operand_desc_group_t *types;
} spv_operand_table_t;
typedef struct spv_ext_inst_desc_t {
const char *name;
const uint32_t ext_inst;
const spv_operand_type_t operandTypes[16]; // TODO: Smaller/larger?
} spv_ext_inst_desc_t;
typedef struct spv_ext_inst_group_t {
const spv_ext_inst_type_t type;
const uint32_t count;
const spv_ext_inst_desc_t *entries;
} spv_ext_inst_group_t;
typedef struct spv_ext_inst_table_t {
const uint32_t count;
const spv_ext_inst_group_t *groups;
} spv_ext_inst_table_t;
typedef struct spv_binary_t {
uint32_t *code;
uint64_t wordCount;
} spv_binary_t;
typedef struct spv_text_t {
const char *str;
uint64_t length;
} spv_text_t;
typedef struct spv_instruction_t {
uint16_t wordCount;
Op opcode;
spv_ext_inst_type_t extInstType;
uint32_t words[SPV_LIMIT_INSTRUCTION_WORD_COUNT_MAX];
} spv_instruction_t;
typedef struct spv_position_t {
uint64_t line;
uint64_t column;
uint64_t index;
} spv_position_t;
typedef struct spv_diagnostic_t {
spv_position_t position;
char *error;
} spv_diagnostic_t;
// Type Definitions
typedef const spv_opcode_desc_t *spv_opcode_desc;
typedef const spv_opcode_table_t *spv_opcode_table;
typedef const spv_operand_desc_t *spv_operand_desc;
typedef const spv_operand_table_t *spv_operand_table;
typedef const spv_ext_inst_desc_t *spv_ext_inst_desc;
typedef const spv_ext_inst_table_t *spv_ext_inst_table;
typedef spv_binary_t *spv_binary;
typedef spv_text_t *spv_text;
typedef spv_position_t *spv_position;
typedef spv_diagnostic_t *spv_diagnostic;
// Platform API
// Opcode API
/// @brief Populate the Opcode table
///
/// @param[out] pOpcodeTable table to be populated
///
/// @return result code
spv_result_t spvOpcodeTableGet(spv_opcode_table *pOpcodeTable);
/// @brief Populate the operand table
///
/// @param[in] pOperandTable table to be populated
///
/// @return result code
spv_result_t spvOperandTableGet(spv_operand_table *pOperandTable);
/// @brief Populate the extended instruction table
///
/// @param pTable table to be populated
///
/// @return result code
spv_result_t spvExtInstTableGet(spv_ext_inst_table *pTable);
// Text API
/// @brief Entry point to covert text form to binary form
///
/// @param[in] text input text
/// @param[in] opcodeTable of specified Opcodes
/// @param[in] operandTable of specified operands
/// @param[in] extInstTable of specified extended instructions
/// @param[out] pBinary the binary module
/// @param[out] pDiagnostic contains diagnostic on failure
///
/// @return result code
spv_result_t spvTextToBinary(const spv_text text,
const spv_opcode_table opcodeTable,
const spv_operand_table operandTable,
const spv_ext_inst_table extInstTable,
spv_binary *pBinary, spv_diagnostic *pDiagnostic);
/// @brief Free an allocated text stream
///
/// @param text the text object to be destored
void spvTextDestroy(spv_text text);
// Binary API
/// @brief Entry point to convert binary to text form
///
/// @param[in] binary the input binary stream
/// @param[in] options bitfield of spv_binary_to_text_options_t values
/// @param[in] opcodeTable table of specified Opcodes
/// @param[in] operandTable table of specified operands
/// @param[in] extInstTable of specified extended instructions
/// @param[out] pText the textual form
/// @param[out] pDiagnostic contains diagnostic on failure
///
/// @return result code
spv_result_t spvBinaryToText(const spv_binary binary, const uint32_t options,
const spv_opcode_table opcodeTable,
const spv_operand_table operandTable,
const spv_ext_inst_table extInstTable,
spv_text *pText, spv_diagnostic *pDiagnostic);
/// @brief Free a binary stream from memory
///
/// @param binary stream to destroy
void spvBinaryDestroy(spv_binary binary);
// Validation API
/// @brief Validate a SPIR-V binary for correctness
///
/// @param[in] binary the input binary stream
/// @param[in] opcodeTable table of specified Opcodes
/// @param[in] operandTable table of specified operands
/// @param[in] extInstTable of specified extended instructions
/// @param[in] options bitfield of spv_validation_options_t
/// @param[out] pDiagnostic contains diagnostic on failure
///
/// @return result code
spv_result_t spvValidate(const spv_binary binary,
const spv_opcode_table opcodeTable,
const spv_operand_table operandTable,
const spv_ext_inst_table extInstTable,
const uint32_t options, spv_diagnostic *pDiagnostic);
// Diagnostic API
/// @brief Create a diagnostic object
///
/// @param position position in the text or binary stream
/// @param message error message to display, is copied
///
/// @return the diagnostic object
spv_diagnostic spvDiagnosticCreate(const spv_position position,
const char *message);
/// @brief Destroy a diagnostic object
///
/// @param diagnostic object to destory
void spvDiagnosticDestroy(spv_diagnostic diagnostic);
/// @brief Print the diagnostic to stderr
///
/// @param[in] diagnostic to print
///
/// @return result code
spv_result_t spvDiagnosticPrint(const spv_diagnostic diagnostic);
#ifdef __cplusplus
}
#endif
#endif

25
licence.txt Normal file
Просмотреть файл

@ -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.

242
readme.md Normal file
Просмотреть файл

@ -0,0 +1,242 @@
# SPIR-V Tools
## Overview
The project includes an assembler, disassembler, and validator for SPIR-V, all
based on a common static library. The library contains all of the implementation
details and is used in the standalone tools whilst also enabling integration
into other code bases directly.
Currently, the assembler and disassembler only support the core SPIR-V
specification (i.e. nothing Vulkan or OpenCL-specific) and the validator is a
work in progress. See the Future Work section for more information.
## Build
The project uses CMake to generate platform-specific build configurations. To
generate these build files issue the following commands.
```
mkdir <spirv-dir>/build
cd <spirv-dir>/build
cmake [-G<platform-generator>] ..
```
Once the build files have been generated, build using your preferred
development environment.
### CMake Options
* `SPIRV_USE_SANITIZER=<sanitizer>` - on UNIX platforms with an appropriate
version of `clang` this option enables the use of the sanitizers documented
[here](http://clang.llvm.org/docs/UsersManual.html#controlling-code-generation),
this should only be used with a debug build, disabled by default
* `SPIRV_COLOR_TERMINAL=ON` - enables color console output, enabled by default
* `SPIRV_WARN_EVERYTHING=OFF` - on UNIX platforms enable the `-Weverything`
compiler front end option, disabled by default
* `SPIRV_WERROR=OFF` - on UNIX platforms enable the `-Werror` compiler front end
option, disabled by default
## Library
### Usage
In order to use the library from an application, the include path should point to
`<spirv-dir>/include`, which will enable the application to include the header
`<spirv-dir>/include/libspirv/libspirv.h` then linking against the static
library in `<spirv-build-dir>/bin/libSPIRV.a` or
`<spirv-build-dir>/bin/SPIRV.lib`. The intention is for this to be a C API,
however currently it relies on the generated header `spirv.h` meaning this is
currently a C++ API.
* `SPIRV` - the static library CMake target outputs `<spirv-dir>/lib/libSPIRV.a`
on Linux/Mac or `<spirv-dir>/lib/SPIRV.lib` on Windows.
#### Entry Points
There are three main entry points into the library.
* `spvTextToBinary` implements the assembler functionality.
* `spvBinaryToText` implements the disassembler functionality.
* `spvValidate` implements the validator functionality.
### Source
In addition to the interface header `<spirv-dir>/include/libspirv/libspirv.h`
the implementation source files reside in `<spirv-dir>/source/*`.
## Tools
### Assembler
The standalone assembler is the binary called `spirv-as` and is located in
`<spirv-build-dir>/bin/spirv-as`. The functionality of the assembler is
implemented by the `spvTextToBinary` library function.
The assembler operates on the textual form.
* `spirv-as` - the standalone assembler
* `<spirv-dir>/bin/spirv-as`
#### Options
* `-o <filename>` is used to specify the output file, otherwise this is set to
`out.spv`.
#### Format
The assembly attempts to adhere to the binary form as closely as possible using
text names from that specification. Here is an example.
```
OpCapability Shader
OpMemoryModel Logical Simple
OpEntryPoint GLCompute $3 "main"
OpExecutionMode $3 LocalSize 64 64 1
OpTypeVoid %1
OpTypeFunction %2 $1
OpFunction $1 %3 None $2
OpLabel %4
OpReturn
OpFunctionEnd
```
Each line encapsulates one and only one instruction, or an OpCode and all of its
operands. OpCodes use the names provided in section 3.28 Instructions of the
SPIR-V specification, immediate values such as Addressing Model, Memory Model,
etc. use the names provided in sections 3.2 Source Language through 3.27
Capability of the SPIR-V specification. Literals strings are enclosed in quotes
`"<string>"` while literal numbers have no special formatting.
##### ID Definitions & Usage
An ID definition pertains to the `Result <id>` of an OpCode, and ID usage is any
input to an OpCode. To differentiate between definitions and uses, all ID
definitions are prefixed with `%` and take the form `%<id>`, meanwhile all ID
uses are prefixed with `$` and take the form `$<id>`. See the above example to
see this in action.
##### Named IDs
The assembler also supports named IDs, or virtual IDs, which greatly improves
the readability of the assembly. The same ID definition and usage prefixes
apply. Names must begin with an character in the range `[a-z|A-Z]`. The
following example will result in identical SPIR-V binary as the example above.
```
OpCapability Shader
OpMemoryModel Logical Simple
OpEntryPoint GLCompute $main "main"
OpExecutionMode $main LocalSize 64 64 1
OpTypeVoid %void
OpTypeFunction %fnMain $void
OpFunction $void %main None $fnMain
OpLabel %lbMain
OpReturn
OpFunctionEnd
```
##### Arbitrary Integers
When writing tests it can be useful to emit an invalid 32 bit word into the
binary stream at arbitrary positions within the assembly. To specify an
arbitrary word into the stream the prefix `!` is used, this takes the form
`!<integer>`. Here is an example.
```
OpCapability !0x0000FF000
```
### Disassembler
The standalone disassembler is the binary called `spirv-dis` and is located in
`<spirv-build-dir>/bin/spirv-dis`. The functionality of the disassembler is
implemented by the `spvBinaryToText` library function.
The disassembler operates on the binary form.
* `spirv-dis` - the standalone disassembler
* `<spirv-dir>/bin/spirv-dis`
#### Options
* `-o <filename>` is used to specify the output file, otherwise this is set to
`out.spvasm`.
* `-p` prints the assembly to the console on stdout, this includes colored
output on Linux, Windows, and Mac.
### Validator
The standalone validator is the binary called `spirv-val` and is located in
`<spirv-build-dir>/bin/spirv-val`. The functionality of the validator is
implemented by the `spvValidate` library function.
The validator operates on the binary form.
* `spirv-val` - the standalone validator
* `<spirv-dir>/bin/spirv-val`
#### Options
* `-basic` performs basic stream validation, currently not implemented.
* `-layout` performs logical layout validation as described in section 2.16
Validation Rules, currently not implemented.
* `-id` performs ID validation according to the instruction rules in sections
3.28.1 through 3.28.22, enabled but is a work in progress.
* `-capability` performs capability validation and or reporting, currently not
implemented.
## Tests
The project contains a number of tests, implemented in the `UnitSPIRV`
executable, used to drive the development and correctness of the tools, these
use the [googletest](https://code.google.com/p/googletest/) framework. The
[googletest](https://code.google.com/p/googletest/) source is not provided with
this project, to enable the tests place the
[googletest](https://code.google.com/p/googletest/) source in the
`<spirv-dir>/external/googletest` directory, rerun CMake if you have already
done so previously, CMake will detect the existence of
`<spirv-dir>/external/googletest` then build as normal.
## Future Work
* Support extension libraries in `spirv-as`, `spirv-dis`, and `spirv-val`.
* Complete implementation of ID validation rules in `spirv-val`.
* Implement section 2.16 Validation Rules in `spirv-val`.
* Implement Capability validation and or report in `spirv-val`.
* Improve assembly output from `spirv-dis`.
* Improve diagnostic reports.
## Known Issues
* Improve literal parsing in the assembler, currently only decimal integers and
floating-point numbers are supported as literal operands and the parser is not
contextually aware of the desired width of the operand.
## Licence
Copyright (c) 2015 The Khronos Group Inc.
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and/or associated documentation files (the
"Materials"), to deal in the Materials without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Materials, and to
permit persons to whom the Materials are furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Materials.
MODIFICATIONS TO THIS FILE MAY MEAN IT NO LONGER ACCURATELY REFLECTS
KHRONOS STANDARDS. THE UNMODIFIED, NORMATIVE VERSIONS OF KHRONOS
SPECIFICATIONS AND HEADER INFORMATION ARE LOCATED AT
https://www.khronos.org/registry/
THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.

469
source/binary.cpp Normal file
Просмотреть файл

@ -0,0 +1,469 @@
// Copyright (c) 2015 The Khronos Group Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and/or associated documentation files (the
// "Materials"), to deal in the Materials without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Materials, and to
// permit persons to whom the Materials are furnished to do so, subject to
// the following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Materials.
//
// MODIFICATIONS TO THIS FILE MAY MEAN IT NO LONGER ACCURATELY REFLECTS
// KHRONOS STANDARDS. THE UNMODIFIED, NORMATIVE VERSIONS OF KHRONOS
// SPECIFICATIONS AND HEADER INFORMATION ARE LOCATED AT
// https://www.khronos.org/registry/
//
// THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
// MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
#include <libspirv/libspirv.h>
#include "binary.h"
#include "diagnostic.h"
#include "ext_inst.h"
#include "opcode.h"
#include "operand.h"
#include <assert.h>
#include <string.h>
#include <sstream>
// Binary API
enum {
I32_ENDIAN_LITTLE = 0x03020100ul,
I32_ENDIAN_BIG = 0x00010203ul,
};
static const union {
unsigned char bytes[4];
uint32_t value;
} o32_host_order = {{0, 1, 2, 3}};
#define I32_ENDIAN_HOST (o32_host_order.value)
spv_result_t spvBinaryEndianness(const spv_binary binary,
spv_endianness_t *pEndian) {
spvCheck(!binary->code || !binary->wordCount,
return SPV_ERROR_INVALID_BINARY);
spvCheck(!pEndian, return SPV_ERROR_INVALID_POINTER);
uint8_t bytes[4];
memcpy(bytes, binary->code, sizeof(uint32_t));
if (0x03 == bytes[0] && 0x02 == bytes[1] && 0x23 == bytes[2] &&
0x07 == bytes[3]) {
*pEndian = SPV_ENDIANNESS_LITTLE;
return SPV_SUCCESS;
}
if (0x07 == bytes[0] && 0x23 == bytes[1] && 0x02 == bytes[2] &&
0x03 == bytes[3]) {
*pEndian = SPV_ENDIANNESS_BIG;
return SPV_SUCCESS;
}
return SPV_ERROR_INVALID_BINARY;
}
uint32_t spvFixWord(const uint32_t word, const spv_endianness_t endian) {
if ((SPV_ENDIANNESS_LITTLE == endian && I32_ENDIAN_HOST == I32_ENDIAN_BIG) ||
(SPV_ENDIANNESS_BIG == endian && I32_ENDIAN_HOST == I32_ENDIAN_LITTLE)) {
return (word & 0x000000ff) << 24 | (word & 0x0000ff00) << 8 |
(word & 0x00ff0000) >> 8 | (word & 0xff000000) >> 24;
}
return word;
}
spv_result_t spvBinaryHeaderGet(const spv_binary binary,
const spv_endianness_t endian,
spv_header_t *pHeader) {
spvCheck(!binary->code || !binary->wordCount,
return SPV_ERROR_INVALID_BINARY);
spvCheck(!pHeader, return SPV_ERROR_INVALID_POINTER);
// TODO: Validation checking?
pHeader->magic = spvFixWord(binary->code[SPV_INDEX_MAGIC_NUMBER], endian);
pHeader->version = spvFixWord(binary->code[SPV_INDEX_VERSION_NUMBER], endian);
pHeader->generator =
spvFixWord(binary->code[SPV_INDEX_GENERATOR_NUMBER], endian);
pHeader->bound = spvFixWord(binary->code[SPV_INDEX_BOUND], endian);
pHeader->schema = spvFixWord(binary->code[SPV_INDEX_SCHEMA], endian);
pHeader->instructions = &binary->code[SPV_INDEX_INSTRUCTION];
return SPV_SUCCESS;
}
spv_result_t spvBinaryHeaderSet(spv_binary_t *binary, const uint32_t bound) {
spvCheck(!binary, return SPV_ERROR_INVALID_BINARY);
spvCheck(!binary->code || !binary->wordCount,
return SPV_ERROR_INVALID_BINARY);
binary->code[SPV_INDEX_MAGIC_NUMBER] = SPV_MAGIC_NUMBER;
binary->code[SPV_INDEX_VERSION_NUMBER] = SPV_VERSION_NUMBER;
binary->code[SPV_INDEX_GENERATOR_NUMBER] = SPV_GENERATOR_CODEPLAY;
binary->code[SPV_INDEX_BOUND] = bound;
binary->code[SPV_INDEX_SCHEMA] = 0; // NOTE: Reserved
return SPV_SUCCESS;
}
spv_result_t spvBinaryEncodeU32(const uint32_t value, spv_instruction_t *pInst,
const spv_position position,
spv_diagnostic *pDiagnostic) {
spvCheck(pInst->wordCount + 1 > SPV_LIMIT_INSTRUCTION_WORD_COUNT_MAX,
DIAGNOSTIC << "Instruction word count '"
<< SPV_LIMIT_INSTRUCTION_WORD_COUNT_MAX << "' exceeded.";
return SPV_ERROR_INVALID_TEXT);
pInst->words[pInst->wordCount++] = (uint32_t)value;
return SPV_SUCCESS;
}
spv_result_t spvBinaryEncodeU64(const uint64_t value, spv_instruction_t *pInst,
const spv_position position,
spv_diagnostic *pDiagnostic) {
spvCheck(pInst->wordCount + 2 > SPV_LIMIT_INSTRUCTION_WORD_COUNT_MAX,
DIAGNOSTIC << "Instruction word count '"
<< SPV_LIMIT_INSTRUCTION_WORD_COUNT_MAX << "' exceeded.";
return SPV_ERROR_INVALID_TEXT);
uint32_t low = (uint32_t)(0x00000000ffffffff & value);
uint32_t high = (uint32_t)((0xffffffff00000000 & value) >> 32);
pInst->words[pInst->wordCount++] = low;
pInst->words[pInst->wordCount++] = high;
return SPV_SUCCESS;
}
spv_result_t spvBinaryEncodeString(const char *str, spv_instruction_t *pInst,
const spv_position position,
spv_diagnostic *pDiagnostic) {
size_t length = strlen(str);
size_t wordCount = (length / 4) + 1;
spvCheck((sizeof(uint32_t) * pInst->wordCount) + length >
sizeof(uint32_t) * SPV_LIMIT_INSTRUCTION_WORD_COUNT_MAX,
DIAGNOSTIC << "Instruction word count '"
<< SPV_LIMIT_INSTRUCTION_WORD_COUNT_MAX << "'exceeded.";
return SPV_ERROR_INVALID_TEXT);
char *dest = (char *)&pInst->words[pInst->wordCount];
strncpy(dest, str, length);
pInst->wordCount += (uint16_t)wordCount;
return SPV_SUCCESS;
}
spv_operand_type_t spvBinaryOperandInfo(const uint32_t word,
const uint16_t operandIndex,
const spv_opcode_desc opcodeEntry,
const spv_operand_table operandTable,
spv_operand_desc *pOperandEntry) {
spv_operand_type_t type;
if (operandIndex < opcodeEntry->wordCount) {
// NOTE: Do operand table lookup to set operandEntry if successful
uint16_t index = operandIndex - 1;
type = opcodeEntry->operandTypes[index];
spv_operand_desc entry = nullptr;
if (!spvOperandTableValueLookup(operandTable, type, word, &entry)) {
if (SPV_OPERAND_TYPE_NONE != entry->operandTypes[0]) {
*pOperandEntry = entry;
}
}
} else if (*pOperandEntry) {
// NOTE: Use specified operand entry operand type for this word
uint16_t index = operandIndex - opcodeEntry->wordCount;
type = (*pOperandEntry)->operandTypes[index];
} else if (OpSwitch == opcodeEntry->opcode) {
// NOTE: OpSwitch is a special case which expects a list of paired extra
// operands
assert(0 &&
"This case is previously untested, remove this assert and ensure it "
"is behaving correctly!");
uint16_t lastIndex = opcodeEntry->wordCount - 1;
uint16_t index = lastIndex + ((operandIndex - lastIndex) % 2);
type = opcodeEntry->operandTypes[index];
} else {
// NOTE: Default to last operand type in opcode entry
uint16_t index = opcodeEntry->wordCount - 1;
type = opcodeEntry->operandTypes[index];
}
return type;
}
spv_result_t spvBinaryDecodeOperand(
const Op opcode, const spv_operand_type_t type, const uint32_t *words,
const spv_endianness_t endian, const uint32_t options,
const spv_operand_table operandTable, const spv_ext_inst_table extInstTable,
spv_ext_inst_type_t *pExtInstType, out_stream &stream,
spv_position position, spv_diagnostic *pDiagnostic) {
spvCheck(!words || !position, return SPV_ERROR_INVALID_POINTER);
spvCheck(!pDiagnostic, return SPV_ERROR_INVALID_DIAGNOSTIC);
bool print = spvIsInBitfield(SPV_BINARY_TO_TEXT_OPTION_PRINT, options);
bool color =
print && spvIsInBitfield(SPV_BINARY_TO_TEXT_OPTION_COLOR, options);
uint64_t index = 0;
switch (type) {
case SPV_OPERAND_TYPE_ID: {
stream.get() << ((color) ? clr::yellow() : "");
stream.get() << "$" << spvFixWord(words[index], endian);
stream.get() << ((color) ? clr::reset() : "");
index++;
position->index++;
} break;
case SPV_OPERAND_TYPE_RESULT_ID: {
stream.get() << (color ? clr::blue() : "");
stream.get() << "%" << spvFixWord(words[index], endian);
stream.get() << (color ? clr::reset() : "");
index++;
position->index++;
} break;
case SPV_OPERAND_TYPE_LITERAL: {
// TODO: Need to support multiple word literals
stream.get() << (color ? clr::red() : "");
stream.get() << spvFixWord(words[index], endian);
stream.get() << (color ? clr::reset() : "");
index++;
position->index++;
} break;
case SPV_OPERAND_TYPE_LITERAL_NUMBER: {
// NOTE: Special case for extended instruction use
if (OpExtInst == opcode) {
spv_ext_inst_desc extInst;
spvCheck(spvExtInstTableValueLookup(extInstTable, *pExtInstType,
words[0], &extInst),
DIAGNOSTIC << "Invalid extended instruction '" << words[0]
<< "'.";
return SPV_ERROR_INVALID_BINARY);
}
stream.get() << (color ? clr::red() : "");
stream.get() << spvFixWord(words[index], endian);
stream.get() << (color ? clr::reset() : "");
index++;
position->index++;
} break;
case SPV_OPERAND_TYPE_LITERAL_STRING: {
const char *string = (const char *)&words[index];
uint64_t stringOperandCount = (strlen(string) / 4) + 1;
// NOTE: Special case for extended instruction import
if (OpExtInstImport == opcode) {
*pExtInstType = spvExtInstImportTypeGet(string);
spvCheck(SPV_EXT_INST_TYPE_NONE == *pExtInstType,
DIAGNOSTIC << "Invalid extended instruction import'" << string
<< "'.";
return SPV_ERROR_INVALID_BINARY);
}
stream.get() << "\"";
stream.get() << (color ? clr::green() : "");
stream.get() << string;
stream.get() << (color ? clr::reset() : "");
stream.get() << "\"";
index += stringOperandCount;
position->index += stringOperandCount;
} break;
case SPV_OPERAND_TYPE_CAPABILITY:
case SPV_OPERAND_TYPE_SOURCE_LANGUAGE:
case SPV_OPERAND_TYPE_EXECUTION_MODEL:
case SPV_OPERAND_TYPE_ADDRESSING_MODEL:
case SPV_OPERAND_TYPE_MEMORY_MODEL:
case SPV_OPERAND_TYPE_EXECUTION_MODE:
case SPV_OPERAND_TYPE_STORAGE_CLASS:
case SPV_OPERAND_TYPE_DIMENSIONALITY:
case SPV_OPERAND_TYPE_SAMPLER_ADDRESSING_MODE:
case SPV_OPERAND_TYPE_SAMPLER_FILTER_MODE:
case SPV_OPERAND_TYPE_FP_FAST_MATH_MODE:
case SPV_OPERAND_TYPE_FP_ROUNDING_MODE:
case SPV_OPERAND_TYPE_LINKAGE_TYPE:
case SPV_OPERAND_TYPE_ACCESS_QUALIFIER:
case SPV_OPERAND_TYPE_FUNCTION_PARAMETER_ATTRIBUTE:
case SPV_OPERAND_TYPE_DECORATION:
case SPV_OPERAND_TYPE_BUILT_IN:
case SPV_OPERAND_TYPE_SELECTION_CONTROL:
case SPV_OPERAND_TYPE_LOOP_CONTROL:
case SPV_OPERAND_TYPE_FUNCTION_CONTROL:
case SPV_OPERAND_TYPE_MEMORY_SEMANTICS:
case SPV_OPERAND_TYPE_MEMORY_ACCESS:
case SPV_OPERAND_TYPE_EXECUTION_SCOPE:
case SPV_OPERAND_TYPE_GROUP_OPERATION:
case SPV_OPERAND_TYPE_KERNEL_ENQ_FLAGS:
case SPV_OPERAND_TYPE_KERENL_PROFILING_INFO: {
spv_operand_desc entry;
spvCheck(
spvOperandTableValueLookup(operandTable, type,
spvFixWord(words[index], endian), &entry),
DIAGNOSTIC << "Invalid " << spvOperandTypeStr(type) << " operand '"
<< words[index] << "'.";
return SPV_ERROR_INVALID_TEXT);
stream.get() << entry->name;
index++;
position->index++;
} break;
default: {
DIAGNOSTIC << "Invalid binary operand '" << type << "'";
return SPV_ERROR_INVALID_BINARY;
}
}
return SPV_SUCCESS;
}
spv_result_t spvBinaryDecodeOpcode(
spv_instruction_t *pInst, const spv_endianness_t endian,
const uint32_t options, const spv_opcode_table opcodeTable,
const spv_operand_table operandTable, const spv_ext_inst_table extInstTable,
out_stream &stream, spv_position position, spv_diagnostic *pDiagnostic) {
spvCheck(!pInst || !position, return SPV_ERROR_INVALID_POINTER);
spvCheck(!opcodeTable || !operandTable || !extInstTable,
return SPV_ERROR_INVALID_TABLE);
spvCheck(!pDiagnostic, return SPV_ERROR_INVALID_DIAGNOSTIC);
uint16_t wordCount;
Op opcode;
spvOpcodeSplit(spvFixWord(pInst->words[0], endian), &wordCount, &opcode);
spv_opcode_desc opcodeEntry;
spvCheck(spvOpcodeTableValueLookup(opcodeTable, opcode, &opcodeEntry),
DIAGNOSTIC << "Invalid Opcode '" << opcode << "'.";
return SPV_ERROR_INVALID_BINARY);
spvCheck(opcodeEntry->wordCount > wordCount,
DIAGNOSTIC << "Invalid instruction word count '" << wordCount
<< "', expected at least '" << opcodeEntry->wordCount
<< "'.";
return SPV_ERROR_INVALID_BINARY);
stream.get() << "Op" << opcodeEntry->name;
position->index++;
spv_operand_desc operandEntry = nullptr;
for (uint16_t index = 1; index < wordCount; ++index) {
const uint32_t word = spvFixWord(pInst->words[index], endian);
const uint64_t currentPosIndex = position->index;
stream.get() << " ";
spv_operand_type_t type = spvBinaryOperandInfo(word, index, opcodeEntry,
operandTable, &operandEntry);
spvCheck(spvBinaryDecodeOperand(
opcodeEntry->opcode, type, pInst->words + index, endian,
options, operandTable, extInstTable, &pInst->extInstType,
stream, position, pDiagnostic),
return SPV_ERROR_INVALID_BINARY);
index += (uint16_t)(position->index - currentPosIndex - 1);
}
return SPV_SUCCESS;
}
spv_result_t spvBinaryToText(const spv_binary binary, const uint32_t options,
const spv_opcode_table opcodeTable,
const spv_operand_table operandTable,
const spv_ext_inst_table extInstTable,
spv_text *pText, spv_diagnostic *pDiagnostic) {
spvCheck(!binary->code || !binary->wordCount,
return SPV_ERROR_INVALID_BINARY);
spvCheck(!opcodeTable || !operandTable || !extInstTable,
return SPV_ERROR_INVALID_TABLE);
spvCheck(pText && spvIsInBitfield(SPV_BINARY_TO_TEXT_OPTION_PRINT, options),
return SPV_ERROR_INVALID_POINTER);
spvCheck(!pText && !spvIsInBitfield(SPV_BINARY_TO_TEXT_OPTION_PRINT, options),
return SPV_ERROR_INVALID_POINTER);
spvCheck(!pDiagnostic, return SPV_ERROR_INVALID_DIAGNOSTIC);
spv_endianness_t endian;
spv_position_t position = {};
spvCheck(spvBinaryEndianness(binary, &endian),
DIAGNOSTIC << "Invalid SPIR-V magic number '" << std::hex
<< binary->code[0] << "'.";
return SPV_ERROR_INVALID_BINARY);
spv_header_t header;
spvCheck(spvBinaryHeaderGet(binary, endian, &header),
DIAGNOSTIC << "Invalid SPIR-V header.";
return SPV_ERROR_INVALID_BINARY);
bool print = spvIsInBitfield(SPV_BINARY_TO_TEXT_OPTION_PRINT, options);
bool color =
print && spvIsInBitfield(SPV_BINARY_TO_TEXT_OPTION_COLOR, options);
std::stringstream sstream;
out_stream stream(sstream);
if (print) {
stream = out_stream();
}
if (color) {
stream.get() << clr::grey();
}
stream.get() << "; SPIR-V\n"
<< "; Version: " << header.version << "\n"
<< "; Generator: " << spvGeneratorStr(header.generator) << "\n"
<< "; Bound: " << header.bound << "\n"
<< "; Schema: " << header.schema << "\n";
if (color) {
stream.get() << clr::reset();
}
const uint32_t *words = binary->code;
position.index = SPV_INDEX_INSTRUCTION;
spv_ext_inst_type_t extInstType = SPV_EXT_INST_TYPE_NONE;
while (position.index < binary->wordCount) {
uint64_t index = position.index;
uint16_t wordCount;
Op opcode;
spvOpcodeSplit(spvFixWord(words[position.index], endian), &wordCount,
&opcode);
spv_instruction_t inst = {};
inst.extInstType = extInstType;
spvInstructionCopy(&words[position.index], opcode, wordCount, endian,
&inst);
spvCheck(
spvBinaryDecodeOpcode(&inst, endian, options, opcodeTable, operandTable,
extInstTable, stream, &position, pDiagnostic),
return SPV_ERROR_INVALID_BINARY);
extInstType = inst.extInstType;
spvCheck((index + wordCount) != position.index,
DIAGNOSTIC << "Invalid word count.";
return SPV_ERROR_INVALID_BINARY);
stream.get() << "\n";
}
if (!print) {
size_t length = sstream.str().size();
char *str = new char[length + 1];
spvCheck(!str, return SPV_ERROR_OUT_OF_MEMORY);
strncpy(str, sstream.str().c_str(), length + 1);
spv_text text = new spv_text_t();
spvCheck(!text, return SPV_ERROR_OUT_OF_MEMORY);
text->str = str;
text->length = length;
*pText = text;
}
return SPV_SUCCESS;
}
void spvBinaryDestroy(spv_binary binary) {
spvCheck(!binary, return );
if (binary->code) {
delete[] binary->code;
}
delete binary;
}

166
source/binary.h Normal file
Просмотреть файл

@ -0,0 +1,166 @@
// Copyright (c) 2015 The Khronos Group Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and/or associated documentation files (the
// "Materials"), to deal in the Materials without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Materials, and to
// permit persons to whom the Materials are furnished to do so, subject to
// the following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Materials.
//
// MODIFICATIONS TO THIS FILE MAY MEAN IT NO LONGER ACCURATELY REFLECTS
// KHRONOS STANDARDS. THE UNMODIFIED, NORMATIVE VERSIONS OF KHRONOS
// SPECIFICATIONS AND HEADER INFORMATION ARE LOCATED AT
// https://www.khronos.org/registry/
//
// THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
// MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
#ifndef _LIBSPIRV_UTIL_BINARY_H_
#define _LIBSPIRV_UTIL_BINARY_H_
#include <libspirv/libspirv.h>
#include "print.h"
// Functions
/// @brief Fix the endianness of a word
///
/// @param[in] word whos endianness should be fixed
/// @param[in] endian the desired endianness
///
/// @return word with host endianness correction
uint32_t spvFixWord(const uint32_t word, const spv_endianness_t endian);
/// @brief Determine the endianness of the SPV binary
///
/// Gets the endianness of the SPV source. Returns SPV_ENDIANNESS_UNKNOWN if
/// the
/// SPV magic number is invalid, otherwise the determined endianness.
///
/// @param[in] binary the binary module
/// @param[out] pEndian return the endianness of the SPV module
///
/// @return result code
spv_result_t spvBinaryEndianness(const spv_binary binary,
spv_endianness_t *pEndian);
/// @brief Grab the header from the SPV module
///
/// @param[in] binary the binary module
/// @param[in] endian the endianness of the module
/// @param[out] pHeader the returned header
///
/// @return result code
spv_result_t spvBinaryHeaderGet(const spv_binary binary,
const spv_endianness_t endian,
spv_header_t *pHeader);
/// @brief Populate a binary stream with this generators header
///
/// @param[in,out] binary the binary stream
/// @param[in] bound the upper ID bound
///
/// @return result code
spv_result_t spvBinaryHeaderSet(spv_binary binary, const uint32_t bound);
/// @brief Append a single word into a binary stream
///
/// @param[in] value the word to encode
/// @param[in] pInst the stream to append to
/// @param[in,out] position position in the binary
/// @param[out] pDiagnostic contains diagnostic on failure
///
/// @return result code
spv_result_t spvBinaryEncodeU32(const uint32_t value, spv_instruction_t *pInst,
const spv_position position,
spv_diagnostic *pDiagnostic);
/// @brief Append two related words into the binary stream
///
/// @param[in] value the two words to encode
/// @param[in] pInst the stream to append to
/// @param[in,out] position position in the binary
/// @param[out] pDiagnostic contains diagnostic on failure
///
/// @return result code
spv_result_t spvBinaryEncodeU64(const uint64_t value, spv_instruction_t *pInst,
const spv_position position,
spv_diagnostic *pDiagnostic);
/// @brief Append a string literal in the binary stream
///
/// @param[in] str the string to encode
/// @param[in] pInst the stream to append to
/// @param[in,out] position position in the binary
/// @param[out] pDiagnostic contains diagnostic on failure
///
/// @return result code
spv_result_t spvBinaryEncodeString(const char *str, spv_instruction_t *pInst,
const spv_position position,
spv_diagnostic *pDiagnostic);
/// @brief Determine the type of the desired operand
///
/// @param[in] word the operand value
/// @param[in] index the word index in the instruction
/// @param[in] opcodeEntry table of specified Opcodes
/// @param[in] operandTable table of specified operands
/// @param[in,out] pOperandEntry the entry in the operand table
///
/// @return type returned
spv_operand_type_t spvBinaryOperandInfo(const uint32_t word,
const uint16_t index,
const spv_opcode_desc opcodeEntry,
const spv_operand_table operandTable,
spv_operand_desc *pOperandEntry);
/// @brief Translate a binary operand to the textual form
///
/// @param[in] opcode of the current instruction
/// @param[in] type type of the operand to decode
/// @param[in] words the binary stream of words
/// @param[in] endian the endianness of the stream
/// @param[in] options bitfield of spv_binary_to_text_options_t values
/// @param[in] operandTable table of specified operands
/// @param[in,out] pExtInstType type of extended instruction library
/// @param[in,out] stream the text output stream
/// @param[in,out] position position in the binary stream
/// @param[out] pDiag return diagnostic on error
///
/// @return result code
spv_result_t spvBinaryDecodeOperand(
const Op opcode, const spv_operand_type_t type, const uint32_t *words,
const spv_endianness_t endian, const uint32_t options,
const spv_operand_table operandTable, const spv_ext_inst_table extInstTable,
spv_ext_inst_type_t *pExtInstType, out_stream &stream,
spv_position position, spv_diagnostic *pDiag);
/// @brief Translate binary Opcode stream to textual form
///
/// @param[in] pInst the Opcode instruction stream
/// @param[in] endian the endianness of the stream
/// @param[in] options bitfield of spv_binary_to_text_options_t values
/// @param[in] opcodeTable table of specified Opcodes
/// @param[in] operandTable table of specified operands
/// @param[out] stream output text stream
/// @param[in,out] position position in the stream
/// @param[out] pDiag return diagnostic on error
///
/// @return result code
spv_result_t spvBinaryDecodeOpcode(
spv_instruction_t *pInst, const spv_endianness_t endian,
const uint32_t options, const spv_opcode_table opcodeTable,
const spv_operand_table operandTable, const spv_ext_inst_table extInstTable,
out_stream &stream, spv_position position, spv_diagnostic *pDiag);
#endif

81
source/diagnostic.cpp Normal file
Просмотреть файл

@ -0,0 +1,81 @@
// Copyright (c) 2015 The Khronos Group Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and/or associated documentation files (the
// "Materials"), to deal in the Materials without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Materials, and to
// permit persons to whom the Materials are furnished to do so, subject to
// the following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Materials.
//
// MODIFICATIONS TO THIS FILE MAY MEAN IT NO LONGER ACCURATELY REFLECTS
// KHRONOS STANDARDS. THE UNMODIFIED, NORMATIVE VERSIONS OF KHRONOS
// SPECIFICATIONS AND HEADER INFORMATION ARE LOCATED AT
// https://www.khronos.org/registry/
//
// THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
// MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
#include <libspirv/libspirv.h>
#include "diagnostic.h"
#include <assert.h>
#include <string.h>
#include <iostream>
// Diagnostic API
spv_diagnostic spvDiagnosticCreate(const spv_position position,
const char *message) {
spv_diagnostic diagnostic = new spv_diagnostic_t;
spvCheck(!diagnostic, return nullptr);
size_t length = strlen(message) + 1;
diagnostic->error = new char[length];
spvCheck(!diagnostic->error, delete diagnostic; return nullptr);
diagnostic->position = *position;
memset(diagnostic->error, 0, length);
strncpy(diagnostic->error, message, length);
return diagnostic;
}
void spvDiagnosticDestroy(spv_diagnostic diagnostic) {
spvCheck(!diagnostic, return );
if (diagnostic->error) {
delete[] diagnostic->error;
}
delete diagnostic;
}
spv_result_t spvDiagnosticPrint(const spv_diagnostic diagnostic) {
spvCheck(!diagnostic, return SPV_ERROR_INVALID_DIAGNOSTIC);
// TODO: Check that the logic choosing between a text or binary diagnostic is
// corrent.
if ((diagnostic->position.line || diagnostic->position.column) &&
diagnostic->position.index) {
// NOTE: This is a text position
// NOTE: add 1 to the line as editors start at line 1, we are counting new
// line characters to start at line 0
std::cerr << "error: " << diagnostic->position.line + 1 << ": "
<< diagnostic->position.column + 1 << ": " << diagnostic->error
<< "\n";
return SPV_SUCCESS;
} else if (!diagnostic->position.line && !diagnostic->position.column &&
diagnostic->position.index) {
// NOTE: This is a binary position
std::cerr << "error: " << diagnostic->position.index << ": "
<< diagnostic->error << "\n";
return SPV_SUCCESS;
}
return SPV_ERROR_INVALID_VALUE;
}

59
source/diagnostic.h Normal file
Просмотреть файл

@ -0,0 +1,59 @@
// Copyright (c) 2015 The Khronos Group Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and/or associated documentation files (the
// "Materials"), to deal in the Materials without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Materials, and to
// permit persons to whom the Materials are furnished to do so, subject to
// the following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Materials.
//
// MODIFICATIONS TO THIS FILE MAY MEAN IT NO LONGER ACCURATELY REFLECTS
// KHRONOS STANDARDS. THE UNMODIFIED, NORMATIVE VERSIONS OF KHRONOS
// SPECIFICATIONS AND HEADER INFORMATION ARE LOCATED AT
// https://www.khronos.org/registry/
//
// THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
// MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
#ifndef _LIBSPIRV_UTIL_DIAGNOSTIC_H_
#define _LIBSPIRV_UTIL_DIAGNOSTIC_H_
#include <libspirv/libspirv.h>
#include <sstream>
#include <iostream>
class diagnostic_helper {
public:
diagnostic_helper(spv_position_t &position, spv_diagnostic *pDiagnostic)
: position(&position), pDiagnostic(pDiagnostic) {}
diagnostic_helper(spv_position position, spv_diagnostic *pDiagnostic)
: position(position), pDiagnostic(pDiagnostic) {}
~diagnostic_helper() {
*pDiagnostic = spvDiagnosticCreate(position, stream.str().c_str());
}
std::stringstream stream;
private:
spv_position position;
spv_diagnostic *pDiagnostic;
};
#define DIAGNOSTIC \
diagnostic_helper helper(position, pDiagnostic); \
helper.stream
#endif

113
source/ext_inst.cpp Normal file
Просмотреть файл

@ -0,0 +1,113 @@
#include <libspirv/libspirv.h>
#include <string.h>
static const spv_ext_inst_desc_t glslStd450Entries[] = {
{
"round", GLSL_STD_450::Round, {SPV_OPERAND_TYPE_ID},
},
// TODO: Add remaining GLSL.std.450 instructions
};
static const spv_ext_inst_desc_t openclStd12Entries[] = {
{"placeholder", 0, {}},
// TODO: Add remaining OpenCL.std.12 instructions
};
static const spv_ext_inst_desc_t openclStd20Entries[] = {
{"placeholder", 0, {}},
// TODO: Add remaining OpenCL.std.20 instructions
};
static const spv_ext_inst_desc_t openclStd21Entries[] = {
{"placeholder", 0, {}},
// TODO: Add remaining OpenCL.std.21 instructions
};
spv_result_t spvExtInstTableGet(spv_ext_inst_table *pExtInstTable) {
spvCheck(!pExtInstTable, return SPV_ERROR_INVALID_POINTER);
static const spv_ext_inst_group_t groups[] = {
{SPV_EXT_INST_TYPE_GLSL_STD_450,
sizeof(glslStd450Entries) / sizeof(spv_ext_inst_desc_t),
glslStd450Entries},
{SPV_EXT_INST_TYPE_OPENCL_STD_12,
sizeof(openclStd12Entries) / sizeof(spv_ext_inst_desc_t),
openclStd12Entries},
{SPV_EXT_INST_TYPE_OPENCL_STD_20,
sizeof(openclStd20Entries) / sizeof(spv_ext_inst_desc_t),
openclStd20Entries},
{SPV_EXT_INST_TYPE_OPENCL_STD_21,
sizeof(openclStd21Entries) / sizeof(spv_ext_inst_desc_t),
openclStd21Entries},
};
static const spv_ext_inst_table_t table = {
sizeof(groups) / sizeof(spv_ext_inst_group_t), groups};
*pExtInstTable = &table;
return SPV_SUCCESS;
}
spv_ext_inst_type_t spvExtInstImportTypeGet(const char *name) {
if (!strcmp("GLSL.std.450", name)) {
return SPV_EXT_INST_TYPE_GLSL_STD_450;
}
if (!strcmp("OpenCL.std.12", name)) {
return SPV_EXT_INST_TYPE_OPENCL_STD_12;
}
if (!strcmp("OpenCL.std.20", name)) {
return SPV_EXT_INST_TYPE_OPENCL_STD_20;
}
if (!strcmp("OpenCL.std.21", name)) {
return SPV_EXT_INST_TYPE_OPENCL_STD_21;
}
return SPV_EXT_INST_TYPE_NONE;
}
spv_result_t spvExtInstTableNameLookup(const spv_ext_inst_table table,
const spv_ext_inst_type_t type,
const char *name,
spv_ext_inst_desc *pEntry) {
spvCheck(!table, return SPV_ERROR_INVALID_TABLE);
spvCheck(!pEntry, return SPV_ERROR_INVALID_POINTER);
for (uint32_t groupIndex = 0; groupIndex < table->count; groupIndex++) {
auto &group = table->groups[groupIndex];
if (type == group.type) {
for (uint32_t index = 0; index < group.count; index++) {
auto &entry = group.entries[index];
if (!strcmp(name, entry.name)) {
*pEntry = &table->groups[groupIndex].entries[index];
return SPV_SUCCESS;
}
}
}
}
return SPV_ERROR_INVALID_LOOKUP;
}
spv_result_t spvExtInstTableValueLookup(const spv_ext_inst_table table,
const spv_ext_inst_type_t type,
const uint32_t value,
spv_ext_inst_desc *pEntry) {
spvCheck(!table, return SPV_ERROR_INVALID_TABLE);
spvCheck(!pEntry, return SPV_ERROR_INVALID_POINTER);
for (uint32_t groupIndex = 0; groupIndex < table->count; groupIndex++) {
auto &group = table->groups[groupIndex];
if (type == group.type) {
for (uint32_t index = 0; index < group.count; index++) {
auto &entry = group.entries[index];
if (value == entry.ext_inst) {
*pEntry = &table->groups[groupIndex].entries[index];
return SPV_SUCCESS;
}
}
}
}
return SPV_ERROR_INVALID_LOOKUP;
}

65
source/ext_inst.h Normal file
Просмотреть файл

@ -0,0 +1,65 @@
// Copyright (c) 2015 The Khronos Group Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and/or associated documentation files (the
// "Materials"), to deal in the Materials without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Materials, and to
// permit persons to whom the Materials are furnished to do so, subject to
// the following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Materials.
//
// MODIFICATIONS TO THIS FILE MAY MEAN IT NO LONGER ACCURATELY REFLECTS
// KHRONOS STANDARDS. THE UNMODIFIED, NORMATIVE VERSIONS OF KHRONOS
// SPECIFICATIONS AND HEADER INFORMATION ARE LOCATED AT
// https://www.khronos.org/registry/
//
// THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
// MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
#ifndef _CODEPLAY_SPIRV_EXT_INST_H_
#define _CODEPLAY_SPIRV_EXT_INST_H_
#include <libspirv/libspirv.h>
/// @brief Get the type from the extended instruction library string
///
/// @param name of the library
///
/// @return type of the extended instruction library
spv_ext_inst_type_t spvExtInstImportTypeGet(const char *name);
/// @brief Find the extented instruction with value in the table
///
/// @param table to lookup
/// @param type of the extended instruction import
/// @param name of the extended instruction to find
/// @param pEntry return the extended instruction entry
///
/// @return result code
spv_result_t spvExtInstTableNameLookup(const spv_ext_inst_table table,
const spv_ext_inst_type_t type,
const char *name,
spv_ext_inst_desc *pEntry);
/// @brief Find the extented instruction with value in the table
///
/// @param table to lookup
/// @param type of the extended instruction import
/// @param value of the extended instruction to find
/// @param pEntry return the extended instruction entry
///
/// @return result code
spv_result_t spvExtInstTableValueLookup(const spv_ext_inst_table table,
const spv_ext_inst_type_t type,
const uint32_t value,
spv_ext_inst_desc *pEntry);
#endif

2476
source/opcode.cpp Normal file

Разница между файлами не показана из-за своего большого размера Загрузить разницу

186
source/opcode.h Normal file
Просмотреть файл

@ -0,0 +1,186 @@
// Copyright (c) 2015 The Khronos Group Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and/or associated documentation files (the
// "Materials"), to deal in the Materials without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Materials, and to
// permit persons to whom the Materials are furnished to do so, subject to
// the following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Materials.
//
// MODIFICATIONS TO THIS FILE MAY MEAN IT NO LONGER ACCURATELY REFLECTS
// KHRONOS STANDARDS. THE UNMODIFIED, NORMATIVE VERSIONS OF KHRONOS
// SPECIFICATIONS AND HEADER INFORMATION ARE LOCATED AT
// https://www.khronos.org/registry/
//
// THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
// MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
#ifndef _LIBSPIRV_UTIL_OPCODE_H_
#define _LIBSPIRV_UTIL_OPCODE_H_
#include <libspirv/libspirv.h>
// Functions
/// @brief Get the name of the SPIR-V generator
///
/// @param[in] generator Khronos SPIR-V generator ID
///
/// @return string name
const char *spvGeneratorStr(uint32_t generator);
/// @brief Combine word count and Opcode enumerant in single word
///
/// @param[in] wordCount Opcode consumes
/// @param[in] opcode enumerant value
///
/// @return Opcode word
uint32_t spvOpcodeMake(uint16_t wordCount, Op opcode);
/// @brief Split the binary opcode into its constituent parts
///
/// @param[in] word binary opcode to split
/// @param[out] wordCount the returned number of words (optional)
/// @param[out] opcode the returned opcode enumerant (optional)
void spvOpcodeSplit(const uint32_t word, uint16_t *wordCount, Op *opcode);
/// @brief Find the named Opcode in the table
///
/// @param[in] table to lookup
/// @param[in] name name of Opcode to find
/// @param[out] pEntry returned Opcode table entry
///
/// @return result code
spv_result_t spvOpcodeTableNameLookup(const spv_opcode_table table,
const char *name, spv_opcode_desc *pEntry);
/// @brief Find the opcode ID in the table
///
/// @param[out] table to lookup
/// @param[in] opcode value of Opcode to fine
/// @param[out] pEntry return Opcode table entry
///
/// @return result code
spv_result_t spvOpcodeTableValueLookup(const spv_opcode_table table,
const Op opcode, spv_opcode_desc *pEntry);
/// @brief Determine if the Opcode has variable word count
///
/// This function does not check if @a entry is valid.
///
/// @param[in] entry the Opcode entry
///
/// @return zero if false, non-zero otherwise
int32_t spvOpcodeIsVariable(spv_opcode_desc entry);
/// @brief Determine if the Opcode has capaspvity requirements
///
/// This function does not check if @a entry is valid.
///
/// @param[in] entry the Opcode entry
///
/// @return zero if false, non-zero otherwise
int32_t spvOpcodeRequiresCapabilities(spv_opcode_desc entry);
/// @brief Copy an instructions word and fix the endianness
///
/// @param[in] words the input instruction stream
/// @param[in] opcode the instructions Opcode
/// @param[in] wordCount the number of words to copy
/// @param[in] endian the endianness of the stream
/// @param[out] pInst the returned instruction
void spvInstructionCopy(const uint32_t *words, const Op opcode,
const uint16_t wordCount, const spv_endianness_t endian,
spv_instruction_t *pInst);
/// @brief Get the string of an OpCode
///
/// @param[in] opcode the opcode
///
/// @return the opcode string
const char *spvOpcodeString(const Op opcode);
/// @brief Determine if the Opcode is a type
///
/// @param[in] opcode the opcode
///
/// @return zero if false, non-zero otherwise
int32_t spvOpcodeIsType(const Op opcode);
/// @brief Determine if the OpCode is a scalar type
///
/// @param[in] opcode the opcode
///
/// @return zero if false, non-zero otherwise
int32_t spvOpcodeIsScalarType(const Op opcode);
/// @brief Determine if the Opcode is a constant
///
/// @param[in] opcode the opcode
///
/// @return zero if false, non-zero otherwise
int32_t spvOpcodeIsConstant(const Op opcode);
/// @brief Determine if the Opcode is a composite type
///
/// @param[in] opcode the opcode
///
/// @return zero if false, non-zero otherwise
int32_t spvOpcodeIsComposite(const Op opcode);
/// @brief Deep comparison of type declaration instructions
///
/// @param[in] pTypeInst0 type definition zero
/// @param[in] pTypeInst1 type definition one
///
/// @return zero if false, non-zero otherwise
int32_t spvOpcodeAreTypesEqual(const spv_instruction_t *pTypeInst0,
const spv_instruction_t *pTypeInst1);
/// @brief Determine if the Opcode results in a pointer
///
/// @param[in] opcode the opcode
///
/// @return zero if false, non-zero otherwise
int32_t spvOpcodeIsPointer(const Op opcode);
/// @brief Determine if the Opcode results in a instantation of a non-void type
///
/// @param[in] opcode the opcode
///
/// @return zero if false, non-zero otherwise
int32_t spvOpcodeIsObject(const Op opcode);
/// @brief Determine if the scalar type Opcode is nullable
///
/// @param[in] opcode the opcode
///
/// @return zero if false, non-zero otherwise
int32_t spvOpcodeIsBasicTypeNullable(Op opcode);
/// @brief Determine if instruction is in a basic block
///
/// @param[in] pFirstInst first instruction in the stream
/// @param[in] pInst current instruction
///
/// @return zero if false, non-zero otherwise
int32_t spvInstructionIsInBasicBlock(const spv_instruction_t *pFirstInst,
const spv_instruction_t *pInst);
/// @brief Determine if the Opcode contains a value
///
/// @param[in] opcode the opcode
///
/// @return zero if false, non-zero otherwise
int32_t spvOpcodeIsValue(Op opcode);
#endif

1519
source/operand.cpp Normal file

Разница между файлами не показана из-за своего большого размера Загрузить разницу

65
source/operand.h Normal file
Просмотреть файл

@ -0,0 +1,65 @@
// Copyright (c) 2015 The Khronos Group Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and/or associated documentation files (the
// "Materials"), to deal in the Materials without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Materials, and to
// permit persons to whom the Materials are furnished to do so, subject to
// the following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Materials.
//
// MODIFICATIONS TO THIS FILE MAY MEAN IT NO LONGER ACCURATELY REFLECTS
// KHRONOS STANDARDS. THE UNMODIFIED, NORMATIVE VERSIONS OF KHRONOS
// SPECIFICATIONS AND HEADER INFORMATION ARE LOCATED AT
// https://www.khronos.org/registry/
//
// THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
// MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
#ifndef _CODEPLAY_SPIRV_OPERAND_H_
#define _CODEPLAY_SPIRV_OPERAND_H_
#include <libspirv/libspirv.h>
/// @brief Find the named operand in the table
///
/// @param[in] table to lookup
/// @param[in] type the operand group's type
/// @param[in] name of the operand to find
/// @param[out] pEntry returned operand table entry
///
/// @return result code
spv_result_t spvOperandTableNameLookup(const spv_operand_table table,
const spv_operand_type_t type,
const char *name,
spv_operand_desc *pEntry);
/// @brief Find the operand with value in the table
///
/// @param[in] table to lookup
/// @param[in] type the operand group's type
/// @param[in] value of the operand to find
/// @param[out] pEntry return operand table entry
///
/// @return result code
spv_result_t spvOperandTableValueLookup(const spv_operand_table table,
const spv_operand_type_t type,
const uint32_t value,
spv_operand_desc *pEntry);
/// @brief Get the name string of the operand type
///
/// @param type the type of the operand
///
/// @return the string name of the operand
const char *spvOperandTypeStr(spv_operand_type_t type);
#endif

103
source/print.cpp Normal file
Просмотреть файл

@ -0,0 +1,103 @@
// Copyright (c) 2015 The Khronos Group Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and/or associated documentation files (the
// "Materials"), to deal in the Materials without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Materials, and to
// permit persons to whom the Materials are furnished to do so, subject to
// the following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Materials.
//
// MODIFICATIONS TO THIS FILE MAY MEAN IT NO LONGER ACCURATELY REFLECTS
// KHRONOS STANDARDS. THE UNMODIFIED, NORMATIVE VERSIONS OF KHRONOS
// SPECIFICATIONS AND HEADER INFORMATION ARE LOCATED AT
// https://www.khronos.org/registry/
//
// THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
// MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
#include "print.h"
#if defined(SPIRV_LINUX) || defined(SPIRV_MAC)
clr::reset::operator const char *() { return "\e[0m"; }
clr::grey::operator const char *() { return "\e[1;30m"; }
clr::red::operator const char *() { return "\e[31m"; }
clr::green::operator const char *() { return "\e[32m"; }
clr::yellow::operator const char *() { return "\e[33m"; }
clr::blue::operator const char *() { return "\e[34m"; }
#elif defined(SPIRV_WINDOWS)
#include <Windows.h>
clr::reset::operator const char *() {
const DWORD color = 0Xf;
HANDLE hConsole;
hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
SetConsoleTextAttribute(hConsole, color);
hConsole = GetStdHandle(STD_ERROR_HANDLE);
SetConsoleTextAttribute(hConsole, color);
return "";
}
clr::grey::operator const char *() {
const DWORD color = 0x8;
HANDLE hConsole;
hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
SetConsoleTextAttribute(hConsole, color);
hConsole = GetStdHandle(STD_ERROR_HANDLE);
SetConsoleTextAttribute(hConsole, color);
return "";
}
clr::red::operator const char *() {
const DWORD color = 0x4;
HANDLE hConsole;
hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
SetConsoleTextAttribute(hConsole, color);
hConsole = GetStdHandle(STD_ERROR_HANDLE);
SetConsoleTextAttribute(hConsole, color);
return "";
}
clr::green::operator const char *() {
const DWORD color = 0x2;
HANDLE hConsole;
hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
SetConsoleTextAttribute(hConsole, color);
hConsole = GetStdHandle(STD_ERROR_HANDLE);
SetConsoleTextAttribute(hConsole, color);
return "";
}
clr::yellow::operator const char *() {
const DWORD color = 0x6;
HANDLE hConsole;
hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
SetConsoleTextAttribute(hConsole, color);
hConsole = GetStdHandle(STD_ERROR_HANDLE);
SetConsoleTextAttribute(hConsole, color);
return "";
}
clr::blue::operator const char *() {
const DWORD color = 0x1;
HANDLE hConsole;
hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
SetConsoleTextAttribute(hConsole, color);
hConsole = GetStdHandle(STD_ERROR_HANDLE);
SetConsoleTextAttribute(hConsole, color);
return "";
}
#endif

77
source/print.h Normal file
Просмотреть файл

@ -0,0 +1,77 @@
// Copyright (c) 2015 The Khronos Group Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and/or associated documentation files (the
// "Materials"), to deal in the Materials without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Materials, and to
// permit persons to whom the Materials are furnished to do so, subject to
// the following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Materials.
//
// MODIFICATIONS TO THIS FILE MAY MEAN IT NO LONGER ACCURATELY REFLECTS
// KHRONOS STANDARDS. THE UNMODIFIED, NORMATIVE VERSIONS OF KHRONOS
// SPECIFICATIONS AND HEADER INFORMATION ARE LOCATED AT
// https://www.khronos.org/registry/
//
// THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
// MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
#ifndef _LIBSPIRV_PRINT_H_
#define _LIBSPIRV_PRINT_H_
#include <iostream>
#include <sstream>
/// @brief Wrapper for out stream selection
class out_stream {
public:
out_stream() : pStream(nullptr) {}
out_stream(std::stringstream &stream) : pStream(&stream) {}
std::ostream &get() {
if (pStream) {
return *pStream;
}
return std::cout;
}
private:
std::stringstream *pStream;
};
namespace clr {
/// @brief Reset console color
struct reset {
operator const char *();
};
/// @brief Set console color to grey
struct grey {
operator const char *();
};
/// @brief Set console color to red
struct red {
operator const char *();
};
/// @brief Set console color to green
struct green {
operator const char *();
};
/// @brief Set console color to yellow
struct yellow {
operator const char *();
};
/// @brief Set console color to blue
struct blue {
operator const char *();
};
}
#endif

667
source/text.cpp Normal file
Просмотреть файл

@ -0,0 +1,667 @@
// Copyright (c) 2015 The Khronos Group Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and/or associated documentation files (the
// "Materials"), to deal in the Materials without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Materials, and to
// permit persons to whom the Materials are furnished to do so, subject to
// the following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Materials.
//
// MODIFICATIONS TO THIS FILE MAY MEAN IT NO LONGER ACCURATELY REFLECTS
// KHRONOS STANDARDS. THE UNMODIFIED, NORMATIVE VERSIONS OF KHRONOS
// SPECIFICATIONS AND HEADER INFORMATION ARE LOCATED AT
// https://www.khronos.org/registry/
//
// THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
// MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
#include <libspirv/libspirv.h>
#include "binary.h"
#include "diagnostic.h"
#include "ext_inst.h"
#include "opcode.h"
#include "operand.h"
#include "text.h"
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <string>
#include <vector>
#include <unordered_map>
// Structures
struct spv_named_id_table_t {
std::unordered_map<std::string, uint32_t> namedIds;
};
// Text API
std::string getWord(const char *str) {
size_t index = 0;
while (true) {
switch (str[index]) {
case '\0':
case '\t':
case '\n':
case ' ':
break;
default:
index++;
}
}
return std::string(str, str + index);
}
spv_named_id_table spvNamedIdTableCreate() {
return new spv_named_id_table_t();
}
void spvNamedIdTableDestory(spv_named_id_table table) { delete table; }
uint32_t spvNamedIdAssignOrGet(spv_named_id_table table, const char *textValue,
uint32_t *pBound) {
if (table->namedIds.end() == table->namedIds.find(textValue)) {
table->namedIds[textValue] = *pBound;
}
return table->namedIds[textValue];
}
int32_t spvTextIsNamedId(const char *textValue) {
// TODO: Strengthen the parsing of textValue to only include allow names that
// match: ([a-z]|[A-Z])(_|[a-z]|[A-Z]|[0-9])*
switch (textValue[0]) {
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
return false;
default:
break;
}
return true;
}
spv_result_t spvTextAdvanceLine(const spv_text text, spv_position position) {
while (true) {
switch (text->str[position->index]) {
case '\0':
return SPV_END_OF_STREAM;
case '\n':
position->column = 0;
position->line++;
position->index++;
return SPV_SUCCESS;
default:
position->line++;
position->index++;
break;
}
}
}
spv_result_t spvTextAdvance(const spv_text text, spv_position position) {
// NOTE: Consume white space, otherwise don't advance.
switch (text->str[position->index]) {
case '\0':
return SPV_END_OF_STREAM;
case ';':
return spvTextAdvanceLine(text, position);
case ' ':
case '\t':
position->column++;
position->index++;
return spvTextAdvance(text, position);
case '\n':
position->column = 0;
position->line++;
position->index++;
return spvTextAdvance(text, position);
default:
break;
}
return SPV_SUCCESS;
}
spv_result_t spvTextWordGet(const spv_text text,
const spv_position startPosition, std::string &word,
spv_position endPosition) {
spvCheck(!text->str || !text->length, return SPV_ERROR_INVALID_TEXT);
spvCheck(!startPosition || !endPosition, return SPV_ERROR_INVALID_POINTER);
*endPosition = *startPosition;
// NOTE: Assumes first character is not white space!
while (true) {
switch (text->str[endPosition->index]) {
case ' ':
case '\t':
case '\n':
case '\0': { // NOTE: End of word found!
word.assign(text->str + startPosition->index,
(size_t)(endPosition->index - startPosition->index));
return SPV_SUCCESS;
}
default:
break;
}
endPosition->column++;
endPosition->index++;
}
}
spv_result_t spvTextStringGet(const spv_text text,
const spv_position startPosition,
std::string &string, spv_position endPosition) {
spvCheck(!text->str || !text->length, return SPV_ERROR_INVALID_TEXT);
spvCheck(!startPosition || !endPosition, return SPV_ERROR_INVALID_POINTER);
spvCheck('"' != text->str[startPosition->index],
return SPV_ERROR_INVALID_TEXT);
*endPosition = *startPosition;
// NOTE: Assumes first character is not white space
while (true) {
endPosition->column++;
endPosition->index++;
switch (text->str[endPosition->index]) {
case '"': {
endPosition->column++;
endPosition->index++;
string.assign(text->str + startPosition->index,
(size_t)(endPosition->index - startPosition->index));
return SPV_SUCCESS;
}
case '\n':
case '\0':
return SPV_ERROR_INVALID_TEXT;
default:
break;
}
}
}
spv_result_t spvTextToUInt32(const char *textValue, uint32_t *pValue) {
char *endPtr = nullptr;
*pValue = strtoul(textValue, &endPtr, 0);
if (0 == *pValue && textValue == endPtr) {
return SPV_ERROR_INVALID_TEXT;
}
return SPV_SUCCESS;
}
spv_result_t spvTextToLiteral(const char *textValue, spv_literal_t *pLiteral) {
bool isSigned = false;
bool isFloat = false;
bool isString = false;
if ('-' == textValue[0]) {
isSigned = true;
}
for (uint64_t index = 0; index < strlen(textValue); ++index) {
switch (textValue[index]) {
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
break;
case '.':
isFloat = true;
break;
default:
isString = true;
break;
}
}
if (isString) {
pLiteral->type = SPV_LITERAL_TYPE_STRING;
strncpy(pLiteral->value.str, textValue, strlen(textValue));
} else if (isFloat) {
double d = strtod(textValue, nullptr);
float f = (float)d;
if (d == (double)f) {
pLiteral->type = SPV_LITERAL_TYPE_FLOAT_32;
pLiteral->value.f = f;
} else {
pLiteral->type = SPV_LITERAL_TYPE_FLOAT_64;
pLiteral->value.d = d;
}
} else if (isSigned) {
int64_t i64 = strtoll(textValue, nullptr, 10);
int32_t i32 = (int32_t)i64;
if (i64 == (int64_t)i32) {
pLiteral->type = SPV_LITERAL_TYPE_INT_32;
pLiteral->value.i32 = i32;
} else {
pLiteral->type = SPV_LITERAL_TYPE_INT_64;
pLiteral->value.i64 = i64;
}
} else {
uint64_t u64 = strtoull(textValue, nullptr, 10);
uint32_t u32 = (uint32_t)u64;
if (u64 == (uint64_t)u32) {
pLiteral->type = SPV_LITERAL_TYPE_UINT_32;
pLiteral->value.u32 = u32;
} else {
pLiteral->type = SPV_LITERAL_TYPE_UINT_64;
pLiteral->value.u64 = u64;
}
}
return SPV_SUCCESS;
}
spv_result_t spvTextEncodeOperand(
const spv_operand_type_t type, const char *textValue,
const spv_operand_table operandTable, const spv_ext_inst_table extInstTable,
spv_named_id_table namedIdTable, spv_instruction_t *pInst,
const spv_operand_type_t **ppExtraOperands, uint32_t *pBound,
const spv_position position, spv_diagnostic *pDiagnostic) {
// NOTE: Handle immediate int in the stream
if ('!' == textValue[0]) {
const char *begin = textValue + 1;
char *end = nullptr;
uint32_t immediateInt = strtoul(begin, &end, 0);
size_t size = strlen(textValue);
size_t length = (end - begin);
spvCheck(size - 1 != length, DIAGNOSTIC << "Invalid immediate integer '"
<< textValue << "'.";
return SPV_ERROR_INVALID_TEXT);
position->column += size;
position->index += size;
pInst->words[pInst->wordCount] = immediateInt;
pInst->wordCount += 1;
return SPV_SUCCESS;
}
switch (type) {
case SPV_OPERAND_TYPE_ID: {
if ('$' == textValue[0]) {
textValue++;
}
// TODO: Force all ID's to be prefixed with '$'.
uint32_t id = 0;
if (spvTextIsNamedId(textValue)) {
id = spvNamedIdAssignOrGet(namedIdTable, textValue, pBound);
} else {
spvCheck(spvTextToUInt32(textValue, &id),
DIAGNOSTIC << "Invalid ID '" << textValue << "'.";
return SPV_ERROR_INVALID_TEXT);
}
pInst->words[pInst->wordCount++] = id;
if (*pBound <= id) {
*pBound = id + 1;
}
} break;
case SPV_OPERAND_TYPE_RESULT_ID: {
if ('%' == textValue[0]) {
textValue++;
}
// TODO: Force all Result ID's to be prefixed with '%'.
uint32_t id = 0;
if (spvTextIsNamedId(textValue)) {
id = spvNamedIdAssignOrGet(namedIdTable, textValue, pBound);
} else {
spvCheck(spvTextToUInt32(textValue, &id),
DIAGNOSTIC << "Invalid result ID '" << textValue << "'.";
return SPV_ERROR_INVALID_TEXT);
}
pInst->words[pInst->wordCount++] = id;
if (*pBound <= id) {
*pBound = id + 1;
}
} break;
case SPV_OPERAND_TYPE_LITERAL_NUMBER: {
// NOTE: Special case for extension instruction lookup
if (OpExtInst == pInst->opcode) {
spv_ext_inst_desc extInst;
spvCheck(spvExtInstTableNameLookup(extInstTable, pInst->extInstType,
textValue, &extInst),
DIAGNOSTIC << "Invalid extended instruction name '"
<< textValue << "'.";
return SPV_ERROR_INVALID_TEXT);
pInst->words[pInst->wordCount++] = extInst->ext_inst;
*ppExtraOperands = extInst->operandTypes;
return SPV_SUCCESS;
}
// TODO: Literal numbers can be any number up to 64 bits wide. This
// includes integers and floating point numbers.
spvCheck(spvTextToUInt32(textValue, &pInst->words[pInst->wordCount++]),
DIAGNOSTIC << "Invalid literal number '" << textValue << "'.";
return SPV_ERROR_INVALID_TEXT);
} break;
case SPV_OPERAND_TYPE_LITERAL: {
spv_literal_t literal = {};
spvCheck(spvTextToLiteral(textValue, &literal),
DIAGNOSTIC << "Invalid literal '" << textValue << "'.";
return SPV_ERROR_INVALID_TEXT);
switch (literal.type) {
case SPV_LITERAL_TYPE_INT_32:
spvCheck(spvBinaryEncodeU32((uint32_t)literal.value.i32, pInst,
position, pDiagnostic),
return SPV_ERROR_INVALID_TEXT);
break;
case SPV_LITERAL_TYPE_INT_64: {
spvCheck(spvBinaryEncodeU64((uint64_t)literal.value.i64, pInst,
position, pDiagnostic),
return SPV_ERROR_INVALID_TEXT);
} break;
case SPV_LITERAL_TYPE_UINT_32: {
spvCheck(spvBinaryEncodeU32(literal.value.u32, pInst, position,
pDiagnostic),
return SPV_ERROR_INVALID_TEXT);
} break;
case SPV_LITERAL_TYPE_UINT_64: {
spvCheck(spvBinaryEncodeU64((uint64_t)literal.value.u64, pInst,
position, pDiagnostic),
return SPV_ERROR_INVALID_TEXT);
} break;
case SPV_LITERAL_TYPE_FLOAT_32: {
spvCheck(spvBinaryEncodeU32((uint32_t)literal.value.f, pInst,
position, pDiagnostic),
return SPV_ERROR_INVALID_TEXT);
} break;
case SPV_LITERAL_TYPE_FLOAT_64: {
spvCheck(spvBinaryEncodeU64((uint64_t)literal.value.d, pInst,
position, pDiagnostic),
return SPV_ERROR_INVALID_TEXT);
} break;
case SPV_LITERAL_TYPE_STRING: {
spvCheck(spvBinaryEncodeString(literal.value.str, pInst, position,
pDiagnostic),
return SPV_ERROR_INVALID_TEXT);
} break;
default:
DIAGNOSTIC << "Invalid literal '" << textValue << "'";
return SPV_ERROR_INVALID_TEXT;
}
} break;
case SPV_OPERAND_TYPE_LITERAL_STRING: {
size_t len = strlen(textValue);
spvCheck('"' != textValue[0] && '"' != textValue[len - 1],
DIAGNOSTIC << "Invalid literal string '" << textValue
<< "', expected quotes.";
return SPV_ERROR_INVALID_TEXT);
// NOTE: Strip quotes
std::string text(textValue + 1, len - 2);
// NOTE: Special case for extended instruction library import
if (OpExtInstImport == pInst->opcode) {
pInst->extInstType = spvExtInstImportTypeGet(text.c_str());
}
spvCheck(
spvBinaryEncodeString(text.c_str(), pInst, position, pDiagnostic),
return SPV_ERROR_INVALID_TEXT);
} break;
default: {
// NOTE: All non literal operands are handled here using the operand
// table.
spv_operand_desc entry;
spvCheck(spvOperandTableNameLookup(operandTable, type, textValue, &entry),
DIAGNOSTIC << "Invalid " << spvOperandTypeStr(type) << " '"
<< textValue << "'.";
return SPV_ERROR_INVALID_TEXT;);
spvCheck(spvBinaryEncodeU32(entry->value, pInst, position, pDiagnostic),
DIAGNOSTIC << "Invalid " << spvOperandTypeStr(type) << " '"
<< textValue << "'.";
return SPV_ERROR_INVALID_TEXT;);
if (ppExtraOperands && entry->operandTypes[0] != SPV_OPERAND_TYPE_NONE) {
*ppExtraOperands = entry->operandTypes;
}
} break;
}
return SPV_SUCCESS;
}
spv_result_t spvTextEncodeOpcode(
const spv_text text, const spv_opcode_table opcodeTable,
const spv_operand_table operandTable, const spv_ext_inst_table extInstTable,
spv_named_id_table namedIdTable, uint32_t *pBound, spv_instruction_t *pInst,
spv_position position, spv_diagnostic *pDiagnostic) {
std::string opcodeName;
spv_position_t nextPosition = {};
spvCheck(spvTextWordGet(text, position, opcodeName, &nextPosition),
return SPV_ERROR_INTERNAL);
bool immediate = false;
spvCheck('!' == text->str[position->index], immediate = true);
if (!immediate) {
spvCheck('O' != opcodeName[0] || 'p' != opcodeName[1],
DIAGNOSTIC << "Invalid Opcode prefix '" << opcodeName << "'.";
return SPV_ERROR_INVALID_TEXT);
}
// NOTE: Handle insertion of an immediate integer into the binary stream
if (immediate) {
const char *begin = opcodeName.data() + 1;
char *end = nullptr;
uint32_t immediateInt = strtoul(begin, &end, 0);
size_t size = opcodeName.size() - 1;
spvCheck(size != (size_t)(end - begin),
DIAGNOSTIC << "Invalid immediate integer '" << opcodeName << "'.";
return SPV_ERROR_INVALID_TEXT);
position->column += opcodeName.size();
position->index += opcodeName.size();
pInst->words[0] = immediateInt;
pInst->wordCount = 1;
return SPV_SUCCESS;
}
// NOTE: The table contains Opcode names without the "Op" prefix.
const char *pInstName = opcodeName.data() + 2;
spv_opcode_desc opcodeEntry;
spv_result_t error =
spvOpcodeTableNameLookup(opcodeTable, pInstName, &opcodeEntry);
spvCheck(error, DIAGNOSTIC << "Invalid Opcode name '"
<< getWord(text->str + position->index) << "'";
return error);
pInst->opcode = opcodeEntry->opcode;
*position = nextPosition;
pInst->wordCount++;
// NOTE: Process the fixed size operands
const spv_operand_type_t *extraOperandTypes = nullptr;
for (int32_t operandIndex = 0; operandIndex < (opcodeEntry->wordCount - 1);
++operandIndex) {
spvCheck(spvTextAdvance(text, position),
DIAGNOSTIC << "Expected operand, found end of stream.";
return SPV_ERROR_INVALID_TEXT);
std::string operandValue;
error = spvTextWordGet(text, position, operandValue, &nextPosition);
spvCheck(error, return error);
error = spvTextEncodeOperand(
opcodeEntry->operandTypes[operandIndex], operandValue.c_str(),
operandTable, extInstTable, namedIdTable, pInst, &extraOperandTypes,
pBound, position, pDiagnostic);
spvCheck(error, return error);
*position = nextPosition;
}
if (spvOpcodeIsVariable(opcodeEntry)) {
if (!extraOperandTypes) {
// NOTE: Handle variable length not defined by an immediate previously
// encountered in the Opcode.
spv_operand_type_t type =
opcodeEntry->operandTypes[opcodeEntry->wordCount - 1];
while (!spvTextAdvance(text, position)) {
std::string textValue;
spvTextWordGet(text, position, textValue, &nextPosition);
// NOTE: Check if the next text word is an Opcode
if ('O' == textValue[0] && 'p' == textValue[1]) {
// NOTE: This is the end of the current instruction stream and we
// break out of this loop
break;
} else {
if (SPV_OPERAND_TYPE_LITERAL_STRING == type) {
spvCheck(spvTextAdvance(text, position),
DIAGNOSTIC << "Invalid string, found end of stream.";
return SPV_ERROR_INVALID_TEXT);
std::string string;
spvCheck(spvTextStringGet(text, position, string, &nextPosition),
DIAGNOSTIC << "Invalid string, new line or end of stream.";
return SPV_ERROR_INVALID_TEXT);
spvCheck(
spvTextEncodeOperand(type, string.c_str(), operandTable,
extInstTable, namedIdTable, pInst, nullptr,
pBound, position, pDiagnostic),
return SPV_ERROR_INVALID_TEXT);
} else {
spvCheck(
spvTextEncodeOperand(type, textValue.c_str(), operandTable,
extInstTable, namedIdTable, pInst, nullptr,
pBound, position, pDiagnostic),
return SPV_ERROR_INVALID_TEXT);
}
*position = nextPosition;
}
}
} else {
// NOTE: Process the variable size operands defined by an immediate
// previously encountered in the Opcode.
uint64_t extraOperandsIndex = 0;
while (extraOperandTypes[extraOperandsIndex]) {
spvCheck(spvTextAdvance(text, position),
DIAGNOSTIC << "Expected operand, found end of stream.";
return SPV_ERROR_INVALID_TEXT);
std::string operandValue;
error = spvTextWordGet(text, position, operandValue, &nextPosition);
error = spvTextEncodeOperand(extraOperandTypes[extraOperandsIndex],
operandValue.c_str(), operandTable,
extInstTable, namedIdTable, pInst, nullptr,
pBound, position, pDiagnostic);
spvCheck(error, return error);
*position = nextPosition;
extraOperandsIndex++;
}
}
}
pInst->words[0] = spvOpcodeMake(pInst->wordCount, opcodeEntry->opcode);
return SPV_SUCCESS;
}
spv_result_t spvTextToBinary(const spv_text text,
const spv_opcode_table opcodeTable,
const spv_operand_table operandTable,
const spv_ext_inst_table extInstTable,
spv_binary *pBinary, spv_diagnostic *pDiagnostic) {
spv_position_t position = {};
spvCheck(!text->str || !text->length, DIAGNOSTIC << "Text stream is empty.";
return SPV_ERROR_INVALID_TEXT);
spvCheck(!opcodeTable || !operandTable || !extInstTable,
return SPV_ERROR_INVALID_TABLE);
spvCheck(!pBinary, return SPV_ERROR_INVALID_POINTER);
spvCheck(!pDiagnostic, return SPV_ERROR_INVALID_DIAGNOSTIC);
// NOTE: Ensure diagnostic is zero initialised
*pDiagnostic = {};
uint32_t bound = 1;
std::vector<spv_instruction_t> instructions;
spvCheck(spvTextAdvance(text, &position), DIAGNOSTIC
<< "Text stream is empty.";
return SPV_ERROR_INVALID_TEXT);
spv_named_id_table namedIdTable = spvNamedIdTableCreate();
spvCheck(!namedIdTable, return SPV_ERROR_OUT_OF_MEMORY);
spv_ext_inst_type_t extInstType = SPV_EXT_INST_TYPE_NONE;
while (text->length > position.index) {
spv_instruction_t inst = {};
inst.extInstType = extInstType;
spvCheck(spvTextEncodeOpcode(text, opcodeTable, operandTable, extInstTable,
namedIdTable, &bound, &inst, &position,
pDiagnostic),
spvNamedIdTableDestory(namedIdTable);
return SPV_ERROR_INVALID_TEXT);
extInstType = inst.extInstType;
instructions.push_back(inst);
spvCheck(spvTextAdvance(text, &position), break);
}
spvNamedIdTableDestory(namedIdTable);
size_t totalSize = SPV_INDEX_INSTRUCTION;
for (auto &inst : instructions) {
totalSize += inst.wordCount;
}
uint32_t *data = new uint32_t[totalSize];
spvCheck(!data, return SPV_ERROR_OUT_OF_MEMORY);
uint64_t currentIndex = SPV_INDEX_INSTRUCTION;
for (auto &inst : instructions) {
memcpy(data + currentIndex, inst.words, sizeof(uint32_t) * inst.wordCount);
currentIndex += inst.wordCount;
}
spv_binary binary = new spv_binary_t();
spvCheck(!binary, delete[] data; return SPV_ERROR_OUT_OF_MEMORY);
binary->code = data;
binary->wordCount = totalSize;
spv_result_t error = spvBinaryHeaderSet(binary, bound);
spvCheck(error, spvBinaryDestroy(binary); return error);
*pBinary = binary;
return SPV_SUCCESS;
}
void spvTextDestroy(spv_text text) {
spvCheck(!text, return );
if (text->str) {
delete[] text->str;
}
delete text;
}

193
source/text.h Normal file
Просмотреть файл

@ -0,0 +1,193 @@
// Copyright (c) 2015 The Khronos Group Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and/or associated documentation files (the
// "Materials"), to deal in the Materials without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Materials, and to
// permit persons to whom the Materials are furnished to do so, subject to
// the following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Materials.
//
// MODIFICATIONS TO THIS FILE MAY MEAN IT NO LONGER ACCURATELY REFLECTS
// KHRONOS STANDARDS. THE UNMODIFIED, NORMATIVE VERSIONS OF KHRONOS
// SPECIFICATIONS AND HEADER INFORMATION ARE LOCATED AT
// https://www.khronos.org/registry/
//
// THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
// MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
#ifndef _LIBSPIRV_UTIL_TEXT_H_
#define _LIBSPIRV_UTIL_TEXT_H_
#include <libspirv/libspirv.h>
#include <string>
// Structures
typedef enum spv_literal_type_t {
SPV_LITERAL_TYPE_INT_32,
SPV_LITERAL_TYPE_INT_64,
SPV_LITERAL_TYPE_UINT_32,
SPV_LITERAL_TYPE_UINT_64,
SPV_LITERAL_TYPE_FLOAT_32,
SPV_LITERAL_TYPE_FLOAT_64,
SPV_LITERAL_TYPE_STRING,
SPV_FORCE_32_BIT_ENUM(spv_literal_type_t)
} spv_literal_type_t;
typedef struct spv_literal_t {
spv_literal_type_t type;
union value_t {
int32_t i32;
int64_t i64;
uint32_t u32;
uint64_t u64;
float f;
double d;
char str[SPV_LIMIT_LITERAL_STRING_MAX];
} value;
} spv_literal_t;
struct spv_named_id_table_t;
// Types
typedef spv_named_id_table_t *spv_named_id_table;
// Functions
/// @brief Advance text to the start of the next line
///
/// @param[in] text to be parsed
/// @param[in,out] pPosition position text has been advanced to
///
/// @return result code
spv_result_t spvTextAdvanceLine(const spv_text text, spv_position_t *pPosition);
/// @brief Advance text to first non white space character
///
/// If a null terminator is found during the text advance SPV_END_OF_STREAM is
/// returned, SPV_SUCCESS otherwise. No error checking is performed on the
/// parameters, its the users responsispvity to ensure these are non null.
///
/// @param[in] text to be parsed
/// @param[in,out] pPosition position text has been advanced to
///
/// @return result code
spv_result_t spvTextAdvance(const spv_text text, spv_position_t *pPosition);
/// @brief Fetch the next word from the text stream
///
/// @param[in] text stream to read from
/// @param[in] startPosition current position in text stream
/// @param[out] word returned word
/// @param[out] endPosition one past the end of the returned word
///
/// @return result code
spv_result_t spvTextWordGet(const spv_text text,
const spv_position startPosition, std::string &word,
spv_position endPosition);
/// @brief Fetch a string, including quotes, from the text stream
///
/// @param[in] text stream to read from
/// @param[in] startPosition current position in text stream
/// @param[out] string returned string
/// @param[out] endPosition one past the end of the return string
///
/// @return result code
spv_result_t spvTextStringGet(const spv_text text,
const spv_position startPosition,
std::string &string, spv_position endPosition);
/// @brief Convert the input text to a unsigned 32 bit integer
///
/// @param[in] textValue input text to parse
/// @param[out] pValue the returned integer
///
/// @return result code
spv_result_t spvTextToUInt32(const char *textValue, uint32_t *pValue);
/// @brief Convert the input text to one of the number types
///
/// @param[in] textValue input text to parse
/// @param[out] pLiteral the returned literal number
///
/// @return result code
spv_result_t spvTextToLiteral(const char *textValue, spv_literal_t *pLiteral);
/// @brief Create a named ID table
///
/// @return named ID table
spv_named_id_table spvNamedIdTableCreate();
/// @brief Free a named ID table
///
/// @param table named ID table
void spvNamedIdTableDestory(spv_named_id_table table);
/// @brief Lookup or assign a named ID
///
/// @param table named ID table
/// @param textValue name value
/// @param pBound upper ID bound, used for assigning new ID's
///
/// @return the new ID assossiated with the named ID
uint32_t spvNamedIdAssignOrGet(spv_named_id_table table, const char *textValue,
uint32_t *pBound);
/// @brief Determine if a name has an assossiated ID
///
/// @param textValue name value
///
/// @return zero on failure, non-zero otherwise
int32_t spvTextIsNamedId(const char *textValue);
/// @brief Translate an Opcode operand to binary form
///
/// @param[in] type of the operand
/// @param[in] textValue word of text to be parsed
/// @param[in] operandTable operand lookup table
/// @param[in,out] namedIdTable table of named ID's
/// @param[out] pInst return binary Opcode
/// @param[out] ppExtraOperands list of extra variable operands, if any
/// @param[in,out] pBound current highest defined ID value
/// @param[in] pPosition used in diagnostic on error
/// @param[out] pDiagnostic populated on error
///
/// @return result code
spv_result_t spvTextEncodeOperand(
const spv_operand_type_t type, const char *textValue,
const spv_operand_table operandTable, const spv_ext_inst_table extInstTable,
spv_named_id_table namedIdTable, spv_instruction_t *pInst,
const spv_operand_type_t **ppExtraOperands, uint32_t *pBound,
const spv_position_t *pPosition, spv_diagnostic *pDiagnostic);
/// @brief Translate single Opcode and operands to binary form
///
/// @param[in] text stream to translate
/// @param[in] opcodeTable Opcode lookup table
/// @param[in] operandTable operand lookup table
/// @param[in,out] namedIdTable table of named ID's
/// @param[in,out] pBound current highest defined ID value
/// @param[out] pInst returned binary Opcode
/// @param[in,out] pPosition in the text stream
/// @param[out] pDiagnostic populated on failure
///
/// @return result code
spv_result_t spvTextEncodeOpcode(
const spv_text text, const spv_opcode_table opcodeTable,
const spv_operand_table operandTable, const spv_ext_inst_table extInstTable,
spv_named_id_table namedIdTable, uint32_t *pBound, spv_instruction_t *pInst,
spv_position_t *pPosition, spv_diagnostic *pDiagnostic);
#endif

300
source/validate.cpp Normal file
Просмотреть файл

@ -0,0 +1,300 @@
// Copyright (c) 2015 The Khronos Group Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and/or associated documentation files (the
// "Materials"), to deal in the Materials without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Materials, and to
// permit persons to whom the Materials are furnished to do so, subject to
// the following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Materials.
//
// MODIFICATIONS TO THIS FILE MAY MEAN IT NO LONGER ACCURATELY REFLECTS
// KHRONOS STANDARDS. THE UNMODIFIED, NORMATIVE VERSIONS OF KHRONOS
// SPECIFICATIONS AND HEADER INFORMATION ARE LOCATED AT
// https://www.khronos.org/registry/
//
// THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
// MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
#include <libspirv/libspirv.h>
#include "binary.h"
#include "diagnostic.h"
#include "opcode.h"
#include "operand.h"
#include "validate.h"
#include <assert.h>
#include <string.h>
#include <stdio.h>
#include <vector>
spv_result_t spvValidateOperandsString(const uint32_t *words,
const uint16_t wordCount,
spv_position position,
spv_diagnostic *pDiagnostic) {
const char *str = (const char *)words;
uint64_t strWordCount = strlen(str) / sizeof(uint32_t) + 1;
spvCheck(strWordCount < wordCount, DIAGNOSTIC << "Instruction word count is "
"too short, string extends "
"past end of instruction.";
return SPV_WARNING);
return SPV_SUCCESS;
}
spv_result_t spvValidateOperandsLiteral(const uint32_t *words,
const uint32_t length,
const uint16_t maxLength,
spv_position position,
spv_diagnostic *pDiagnostic) {
// NOTE: A literal could either be a number consuming up to 2 words or a
// null terminated string.
(void)words;
(void)length;
(void)maxLength;
(void)position;
(void)pDiagnostic;
return SPV_UNSUPPORTED;
}
spv_result_t spvValidateOperandValue(const spv_operand_type_t type,
const uint32_t word,
const spv_operand_table operandTable,
spv_position position,
spv_diagnostic *pDiagnostic) {
switch (type) {
case SPV_OPERAND_TYPE_ID:
case SPV_OPERAND_TYPE_RESULT_ID: {
// NOTE: ID's are validated in SPV_VALIDATION_LEVEL_1, this is
// SPV_VALIDATION_LEVEL_0
} break;
case SPV_OPERAND_TYPE_LITERAL_NUMBER: {
// NOTE: Implicitly valid as they are encoded as 32 bit value
} break;
case SPV_OPERAND_TYPE_SOURCE_LANGUAGE:
case SPV_OPERAND_TYPE_EXECUTION_MODEL:
case SPV_OPERAND_TYPE_ADDRESSING_MODEL:
case SPV_OPERAND_TYPE_MEMORY_MODEL:
case SPV_OPERAND_TYPE_EXECUTION_MODE:
case SPV_OPERAND_TYPE_STORAGE_CLASS:
case SPV_OPERAND_TYPE_DIMENSIONALITY:
case SPV_OPERAND_TYPE_SAMPLER_ADDRESSING_MODE:
case SPV_OPERAND_TYPE_SAMPLER_FILTER_MODE:
case SPV_OPERAND_TYPE_FP_FAST_MATH_MODE:
case SPV_OPERAND_TYPE_FP_ROUNDING_MODE:
case SPV_OPERAND_TYPE_LINKAGE_TYPE:
case SPV_OPERAND_TYPE_ACCESS_QUALIFIER:
case SPV_OPERAND_TYPE_FUNCTION_PARAMETER_ATTRIBUTE:
case SPV_OPERAND_TYPE_DECORATION:
case SPV_OPERAND_TYPE_BUILT_IN:
case SPV_OPERAND_TYPE_SELECTION_CONTROL:
case SPV_OPERAND_TYPE_LOOP_CONTROL:
case SPV_OPERAND_TYPE_FUNCTION_CONTROL:
case SPV_OPERAND_TYPE_MEMORY_SEMANTICS:
case SPV_OPERAND_TYPE_MEMORY_ACCESS:
case SPV_OPERAND_TYPE_EXECUTION_SCOPE:
case SPV_OPERAND_TYPE_GROUP_OPERATION:
case SPV_OPERAND_TYPE_KERNEL_ENQ_FLAGS:
case SPV_OPERAND_TYPE_KERENL_PROFILING_INFO: {
spv_operand_desc operandEntry = nullptr;
spv_result_t error =
spvOperandTableValueLookup(operandTable, type, word, &operandEntry);
spvCheck(error, DIAGNOSTIC << "Invalid '" << spvOperandTypeStr(type)
<< "' operand '" << word << "'.";
return error);
} break;
default:
assert(0 && "Invalid operand types should already have been caught!");
}
return SPV_SUCCESS;
}
spv_result_t spvValidateBasic(const spv_instruction_t *pInsts,
const uint64_t instCount,
const spv_opcode_table opcodeTable,
const spv_operand_table operandTable,
spv_position position,
spv_diagnostic *pDiagnostic) {
for (uint64_t instIndex = 0; instIndex < instCount; ++instIndex) {
const uint32_t *words = pInsts[instIndex].words;
uint16_t wordCount;
Op opcode;
spvOpcodeSplit(words[0], &wordCount, &opcode);
spv_opcode_desc opcodeEntry = nullptr;
spvCheck(spvOpcodeTableValueLookup(opcodeTable, opcode, &opcodeEntry),
DIAGNOSTIC << "Invalid Opcode '" << opcode << "'.";
return SPV_ERROR_INVALID_BINARY);
position->index++;
spvCheck(opcodeEntry->wordCount > wordCount,
DIAGNOSTIC << "Instruction word count '" << wordCount
<< "' is not small, expected at least '"
<< opcodeEntry->wordCount << "'.";
return SPV_ERROR_INVALID_BINARY);
spv_operand_desc operandEntry = nullptr;
for (uint16_t index = 1; index < pInsts[instIndex].wordCount;
++index, position->index++) {
const uint32_t word = words[index];
spv_operand_type_t type = spvBinaryOperandInfo(
word, index, opcodeEntry, operandTable, &operandEntry);
if (SPV_OPERAND_TYPE_LITERAL_STRING == type) {
spvCheckReturn(spvValidateOperandsString(
words + index, wordCount - index, position, pDiagnostic));
// NOTE: String literals are always at the end of Opcodes
break;
} else if (SPV_OPERAND_TYPE_LITERAL == type) {
spvCheckReturn(spvValidateOperandsLiteral(
words + index, wordCount - index, 2, position, pDiagnostic));
} else {
spvCheckReturn(spvValidateOperandValue(type, word, operandTable,
position, pDiagnostic));
}
}
}
return SPV_SUCCESS;
}
spv_result_t spvValidateIDs(const spv_instruction_t *pInsts,
const uint64_t count, const uint32_t bound,
const spv_opcode_table opcodeTable,
const spv_operand_table operandTable,
const spv_ext_inst_table extInstTable,
spv_position position,
spv_diagnostic *pDiagnostic) {
std::vector<spv_id_info_t> idUses;
std::vector<spv_id_info_t> idDefs;
for (uint64_t instIndex = 0; instIndex < count; ++instIndex) {
const uint32_t *words = pInsts[instIndex].words;
Op opcode;
spvOpcodeSplit(words[0], nullptr, &opcode);
spv_opcode_desc opcodeEntry = nullptr;
spvCheck(spvOpcodeTableValueLookup(opcodeTable, opcode, &opcodeEntry),
DIAGNOSTIC << "Invalid Opcode '" << opcode << "'.";
return SPV_ERROR_INVALID_BINARY);
spv_operand_desc operandEntry = nullptr;
position->index++; // NOTE: Account for Opcode word
for (uint16_t index = 1; index < pInsts[instIndex].wordCount;
++index, position->index++) {
const uint32_t word = words[index];
spv_operand_type_t type = spvBinaryOperandInfo(
word, index, opcodeEntry, operandTable, &operandEntry);
if (SPV_OPERAND_TYPE_RESULT_ID == type || SPV_OPERAND_TYPE_ID == type) {
spvCheck(0 == word, DIAGNOSTIC << "Invalid ID of '0' is not allowed.";
return SPV_ERROR_INVALID_ID);
spvCheck(bound < word, DIAGNOSTIC << "Invalid ID '" << word
<< "' exceeds the bound '" << bound
<< "'.";
return SPV_ERROR_INVALID_ID);
}
if (SPV_OPERAND_TYPE_RESULT_ID == type) {
idDefs.push_back(
{word, opcodeEntry->opcode, &pInsts[instIndex], *position});
}
if (SPV_OPERAND_TYPE_ID == type) {
idUses.push_back({word, opcodeEntry->opcode, nullptr, *position});
}
}
}
// NOTE: Error on redefined ID
for (size_t outerIndex = 0; outerIndex < idDefs.size(); ++outerIndex) {
for (size_t innerIndex = 0; innerIndex < idDefs.size(); ++innerIndex) {
if (outerIndex == innerIndex) {
continue;
}
if (idDefs[outerIndex].id == idDefs[innerIndex].id) {
DIAGNOSTIC << "Multiply defined ID '" << idDefs[outerIndex].id << "'.";
return SPV_ERROR_INVALID_ID;
}
}
}
// NOTE: Validate ID usage, including use of undefined ID's
position->index = SPV_INDEX_INSTRUCTION;
spvCheck(spvValidateInstructionIDs(pInsts, count, idUses.data(),
idUses.size(), idDefs.data(),
idDefs.size(), opcodeTable, operandTable,
extInstTable, position, pDiagnostic),
return SPV_ERROR_INVALID_ID);
return SPV_SUCCESS;
}
spv_result_t spvValidate(const spv_binary binary,
const spv_opcode_table opcodeTable,
const spv_operand_table operandTable,
const spv_ext_inst_table extInstTable,
const uint32_t options, spv_diagnostic *pDiagnostic) {
spvCheck(!opcodeTable || !operandTable, return SPV_ERROR_INVALID_TABLE);
spvCheck(!pDiagnostic, return SPV_ERROR_INVALID_DIAGNOSTIC);
spv_endianness_t endian;
spv_position_t position = {};
spvCheck(spvBinaryEndianness(binary, &endian),
DIAGNOSTIC << "Invalid SPIR-V magic number.";
return SPV_ERROR_INVALID_BINARY);
spv_header_t header;
spvCheck(spvBinaryHeaderGet(binary, endian, &header),
DIAGNOSTIC << "Invalid SPIR-V header.";
return SPV_ERROR_INVALID_BINARY);
// NOTE: Copy each instruction for easier processing
std::vector<spv_instruction_t> instructions;
uint64_t index = SPV_INDEX_INSTRUCTION;
while (index < binary->wordCount) {
uint16_t wordCount;
Op opcode;
spvOpcodeSplit(spvFixWord(binary->code[index], endian), &wordCount,
&opcode);
spv_instruction_t inst;
spvInstructionCopy(&binary->code[index], opcode, wordCount, endian, &inst);
instructions.push_back(inst);
index += wordCount;
}
if (spvIsInBitfield(SPV_VALIDATE_BASIC_BIT, options)) {
position.index = SPV_INDEX_INSTRUCTION;
// TODO: Imcomplete implementation
spvCheckReturn(spvValidateBasic(instructions.data(), instructions.size(),
opcodeTable, operandTable, &position,
pDiagnostic));
}
if (spvIsInBitfield(SPV_VALIDATE_LAYOUT_BIT, options)) {
position.index = SPV_INDEX_INSTRUCTION;
// TODO: spvBinaryValidateLayout
}
if (spvIsInBitfield(SPV_VALIDATE_ID_BIT, options)) {
position.index = SPV_INDEX_INSTRUCTION;
spvCheckReturn(spvValidateIDs(instructions.data(), instructions.size(),
header.bound, opcodeTable, operandTable,
extInstTable, &position, pDiagnostic));
}
if (spvIsInBitfield(SPV_VALIDATE_RULES_BIT, options)) {
position.index = SPV_INDEX_INSTRUCTION;
// TODO: Specified validation rules...
}
return SPV_SUCCESS;
}

83
source/validate.h Normal file
Просмотреть файл

@ -0,0 +1,83 @@
// Copyright (c) 2015 The Khronos Group Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and/or associated documentation files (the
// "Materials"), to deal in the Materials without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Materials, and to
// permit persons to whom the Materials are furnished to do so, subject to
// the following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Materials.
//
// MODIFICATIONS TO THIS FILE MAY MEAN IT NO LONGER ACCURATELY REFLECTS
// KHRONOS STANDARDS. THE UNMODIFIED, NORMATIVE VERSIONS OF KHRONOS
// SPECIFICATIONS AND HEADER INFORMATION ARE LOCATED AT
// https://www.khronos.org/registry/
//
// THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
// MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
#ifndef _LIBSPIRV_UTIL_VALIDATE_H_
#define _LIBSPIRV_UTIL_VALIDATE_H_
#include <libspirv/libspirv.h>
// Structures
typedef struct spv_id_info_t {
uint32_t id;
Op opcode;
const spv_instruction_t *inst;
spv_position_t position;
} spv_id_info_t;
// Functions
/// @brief Validate the ID usage of the instruction stream
///
/// @param[in] pInsts stream of instructions
/// @param[in] instCount number of instructions
/// @param[in] pIdUses stream of ID uses
/// @param[in] idUsesCount number of ID uses
/// @param[in] pIdDefs stream of ID uses
/// @param[in] idDefsCount number of ID uses
/// @param[in] opcodeTable table of specified Opcodes
/// @param[in] operandTable table of specified operands
/// @param[in,out] position current position in the stream
/// @param[out] pDiag contains diagnostic on failure
///
/// @return result code
spv_result_t spvValidateInstructionIDs(
const spv_instruction_t *pInsts, const uint64_t instCount,
const spv_id_info_t *pIdUses, const uint64_t idUsesCount,
const spv_id_info_t *pIdDefs, const uint64_t idDefsCount,
const spv_opcode_table opcodeTable, const spv_operand_table operandTable,
const spv_ext_inst_table extInstTable, spv_position position,
spv_diagnostic *pDiag);
/// @brief Validate the ID's within a SPIR-V binary
///
/// @param[in] pInstructions array of instructions
/// @param[in] count number of elements in instruction array
/// @param[in] bound the binary header
/// @param[in] opcodeTable table of specified Opcodes
/// @param[in] operandTable table of specified operands
/// @param[in,out] position current word in the binary
/// @param[out] pDiagnostic contains diagnostic on failure
///
/// @return result code
spv_result_t spvValidateIDs(const spv_instruction_t *pInstructions,
const uint64_t count, const uint32_t bound,
const spv_opcode_table opcodeTable,
const spv_operand_table operandTable,
const spv_ext_inst_table extInstTable,
spv_position position, spv_diagnostic *pDiagnostic);
#endif

2808
source/validate_id.cpp Normal file

Разница между файлами не показана из-за своего большого размера Загрузить разницу

60
test/BinaryEndianness.cpp Normal file
Просмотреть файл

@ -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);
}

76
test/BinaryHeaderGet.cpp Normal file
Просмотреть файл

@ -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));
}

169
test/BinaryToText.cpp Normal file
Просмотреть файл

@ -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);
}
}

40
test/DiagnosticPrint.cpp Normal file
Просмотреть файл

@ -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));
}

50
test/FixWord.cpp Normal file
Просмотреть файл

@ -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));
}

69
test/NamedId.cpp Normal file
Просмотреть файл

@ -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);
}

33
test/OpcodeIsVariable.cpp Normal file
Просмотреть файл

@ -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));
}

42
test/OpcodeMake.cpp Normal file
Просмотреть файл

@ -0,0 +1,42 @@
// Copyright (c) 2015 The Khronos Group Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and/or associated documentation files (the
// "Materials"), to deal in the Materials without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Materials, and to
// permit persons to whom the Materials are furnished to do so, subject to
// the following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Materials.
//
// MODIFICATIONS TO THIS FILE MAY MEAN IT NO LONGER ACCURATELY REFLECTS
// KHRONOS STANDARDS. THE UNMODIFIED, NORMATIVE VERSIONS OF KHRONOS
// SPECIFICATIONS AND HEADER INFORMATION ARE LOCATED AT
// https://www.khronos.org/registry/
//
// THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
// MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
#include "UnitSPIRV.h"
#include <limits>
TEST(OpcodeMake, DISABLED_Default) {
for (uint16_t wordCount = 0; wordCount < std::numeric_limits<uint16_t>::max();
++wordCount) {
for (uint16_t code = 0; code < std::numeric_limits<uint16_t>::max();
++code) {
uint32_t opcode = 0;
opcode |= (uint32_t)code;
opcode |= (uint32_t)wordCount << 16;
ASSERT_EQ(opcode, spvOpcodeMake(wordCount, (Op)code));
}
}
}

Просмотреть файл

@ -0,0 +1,60 @@
// Copyright (c) 2015 The Khronos Group Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and/or associated documentation files (the
// "Materials"), to deal in the Materials without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Materials, and to
// permit persons to whom the Materials are furnished to do so, subject to
// the following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Materials.
//
// MODIFICATIONS TO THIS FILE MAY MEAN IT NO LONGER ACCURATELY REFLECTS
// KHRONOS STANDARDS. THE UNMODIFIED, NORMATIVE VERSIONS OF KHRONOS
// SPECIFICATIONS AND HEADER INFORMATION ARE LOCATED AT
// https://www.khronos.org/registry/
//
// THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
// MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
#include "UnitSPIRV.h"
class Requires : public ::testing::TestWithParam<Capability> {
public:
Requires()
: entry({nullptr,
0,
(Op)0,
SPV_OPCODE_FLAGS_CAPABILITIES,
GetParam(),
{}}) {}
virtual void SetUp() {}
virtual void TearDown() {}
spv_opcode_desc_t entry;
};
TEST_P(Requires, Capabilityabilities) {
ASSERT_NE(0, spvOpcodeRequiresCapabilities(&entry));
}
INSTANTIATE_TEST_CASE_P(Op, Requires,
::testing::Values(CapabilityMatrix, CapabilityShader,
CapabilityGeometry,
CapabilityTessellation,
CapabilityAddresses,
CapabilityLinkage, CapabilityKernel));
TEST(OpcodeRequiresCapabilityaspvities, None) {
spv_opcode_desc_t entry = {nullptr, 0, (Op)0, SPV_OPCODE_FLAGS_NONE, 0, {}};
ASSERT_EQ(0, spvOpcodeRequiresCapabilities(&entry));
}

36
test/OpcodeSplit.cpp Normal file
Просмотреть файл

@ -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);
}

38
test/OpcodeTableGet.cpp Normal file
Просмотреть файл

@ -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));
}

38
test/OperandTableGet.cpp Normal file
Просмотреть файл

@ -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));
}

74
test/TextAdvance.cpp Normal file
Просмотреть файл

@ -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));
}

85
test/TextDestroy.cpp Normal file
Просмотреть файл

@ -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);
}

354
test/TextToBinary.cpp Normal file
Просмотреть файл

@ -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);
}
}

97
test/TextWordGet.cpp Normal file
Просмотреть файл

@ -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));
}
}
}

54
test/UnitSPIRV.h Normal file
Просмотреть файл

@ -0,0 +1,54 @@
// Copyright (c) 2015 The Khronos Group Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and/or associated documentation files (the
// "Materials"), to deal in the Materials without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Materials, and to
// permit persons to whom the Materials are furnished to do so, subject to
// the following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Materials.
//
// MODIFICATIONS TO THIS FILE MAY MEAN IT NO LONGER ACCURATELY REFLECTS
// KHRONOS STANDARDS. THE UNMODIFIED, NORMATIVE VERSIONS OF KHRONOS
// SPECIFICATIONS AND HEADER INFORMATION ARE LOCATED AT
// https://www.khronos.org/registry/
//
// THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
// MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
#ifndef _CODEPLAY_UNITBIL_H_
#define _CODEPLAY_UNITBIL_H_
#include <libspirv/libspirv.h>
#include "../source/binary.h"
#include "../source/diagnostic.h"
#include "../source/opcode.h"
#include "../source/text.h"
#include "../source/validate.h"
#include <gtest/gtest.h>
#include <stdint.h>
// Determine endianness & predicate tests on it
enum {
I32_ENDIAN_LITTLE = 0x03020100ul,
I32_ENDIAN_BIG = 0x00010203ul,
};
static const union {
unsigned char bytes[4];
uint32_t value;
} o32_host_order = {{0, 1, 2, 3}};
#define I32_ENDIAN_HOST (o32_host_order.value)
#endif

119
test/Validate.cpp Normal file
Просмотреть файл

@ -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);
}

1342
test/ValidateID.cpp Normal file

Разница между файлами не показана из-за своего большого размера Загрузить разницу

32
test/main.cpp Normal file
Просмотреть файл

@ -0,0 +1,32 @@
// Copyright (c) 2015 The Khronos Group Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and/or associated documentation files (the
// "Materials"), to deal in the Materials without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Materials, and to
// permit persons to whom the Materials are furnished to do so, subject to
// the following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Materials.
//
// MODIFICATIONS TO THIS FILE MAY MEAN IT NO LONGER ACCURATELY REFLECTS
// KHRONOS STANDARDS. THE UNMODIFIED, NORMATIVE VERSIONS OF KHRONOS
// SPECIFICATIONS AND HEADER INFORMATION ARE LOCATED AT
// https://www.khronos.org/registry/
//
// THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
// MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
#include <gtest/gtest.h>
int main(int argc, char **argv) {
::testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}

129
tools/as/as.cpp Normal file
Просмотреть файл

@ -0,0 +1,129 @@
// Copyright (c) 2015 The Khronos Group Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and/or associated documentation files (the
// "Materials"), to deal in the Materials without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Materials, and to
// permit persons to whom the Materials are furnished to do so, subject to
// the following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Materials.
//
// MODIFICATIONS TO THIS FILE MAY MEAN IT NO LONGER ACCURATELY REFLECTS
// KHRONOS STANDARDS. THE UNMODIFIED, NORMATIVE VERSIONS OF KHRONOS
// SPECIFICATIONS AND HEADER INFORMATION ARE LOCATED AT
// https://www.khronos.org/registry/
//
// THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
// MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
#include <libspirv/libspirv.h>
#include <stdio.h>
#include <vector>
void print_usage(char *argv0) {
printf(
"Assemble a *.svasm file into a *.sv binary.\n\n"
"USAGE: %s [options] <filename>\n\n"
" -o Set the output filename\n",
argv0);
}
int main(int argc, char **argv) {
if (2 > argc) {
print_usage(argv[0]);
return 1;
}
const char *inFile = nullptr;
const char *outFile = nullptr;
for (int argi = 1; argi < argc; ++argi) {
if ('-' == argv[argi][0]) {
switch (argv[argi][1]) {
case 'o': {
if (!outFile && argi + 1 < argc) {
outFile = argv[++argi];
} else {
print_usage(argv[0]);
return 1;
}
} break;
default:
print_usage(argv[0]);
return 1;
}
} else {
if (!inFile) {
inFile = argv[argi];
} else {
print_usage(argv[0]);
return 1;
}
}
}
if (!outFile) {
outFile = "out.spv";
}
spvCheck(!inFile, fprintf(stderr, "error: input file is empty.\n"); return 1);
std::vector<char> contents;
if (FILE *fp = fopen(inFile, "r")) {
char buf[1024];
while (size_t len = fread(buf, 1, sizeof(buf), fp))
contents.insert(contents.end(), buf, buf + len);
fclose(fp);
} else {
fprintf(stderr, "error: file does not exist '%s'\n", inFile);
return 1;
}
spv_text_t text = {contents.data(), contents.size()};
spv_opcode_table opcodeTable;
spv_result_t error = spvOpcodeTableGet(&opcodeTable);
spvCheck(error, fprintf(stderr, "error: internal malfunction\n");
return error);
spv_operand_table operandTable;
error = spvOperandTableGet(&operandTable);
spvCheck(error, fprintf(stderr, "error: internal malfunction\n");
return error);
spv_ext_inst_table extInstTable;
error = spvExtInstTableGet(&extInstTable);
spvCheck(error, fprintf(stderr, "error: Internal malfunction.\n"));
spv_binary binary;
spv_diagnostic diagnostic = nullptr;
error = spvTextToBinary(&text, opcodeTable, operandTable, extInstTable,
&binary, &diagnostic);
spvCheck(error, spvDiagnosticPrint(diagnostic);
spvDiagnosticDestroy(diagnostic); return error);
if (FILE *fp = fopen(outFile, "wb")) {
size_t written =
fwrite(binary->code, sizeof(uint32_t), (size_t)binary->wordCount, fp);
if (binary->wordCount != written) {
fprintf(stderr, "error: could not write to file '%s'\n", outFile);
return 1;
}
} else {
fprintf(stderr, "error: could not open file '%s'\n", outFile);
return 1;
}
spvBinaryDestroy(binary);
return 0;
}

144
tools/dis/dis.cpp Normal file
Просмотреть файл

@ -0,0 +1,144 @@
// Copyright (c) 2015 The Khronos Group Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and/or associated documentation files (the
// "Materials"), to deal in the Materials without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Materials, and to
// permit persons to whom the Materials are furnished to do so, subject to
// the following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Materials.
//
// MODIFICATIONS TO THIS FILE MAY MEAN IT NO LONGER ACCURATELY REFLECTS
// KHRONOS STANDARDS. THE UNMODIFIED, NORMATIVE VERSIONS OF KHRONOS
// SPECIFICATIONS AND HEADER INFORMATION ARE LOCATED AT
// https://www.khronos.org/registry/
//
// THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
// MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
#include <libspirv/libspirv.h>
#include <stdio.h>
#include <vector>
void print_usage(char *argv0) {
printf(
"Dissassemble a *.sv file into a *.svasm text file.\n\n"
"USAGE: %s [options] <filename>\n\n"
" -o <filename> Set the output filename\n"
" -p Print dissassembly to stdout, this\n"
" overrides file output\n",
argv0);
}
int main(int argc, char **argv) {
if (2 > argc) {
print_usage(argv[0]);
return 1;
}
uint32_t options = SPV_BINARY_TO_TEXT_OPTION_NONE;
const char *inFile = nullptr;
const char *outFile = nullptr;
for (int argi = 1; argi < argc; ++argi) {
if ('-' == argv[argi][0]) {
switch (argv[argi][1]) {
case 'o': {
if (!outFile && argi + 1 < argc) {
outFile = argv[++argi];
} else {
print_usage(argv[0]);
return 1;
}
} break;
case 'p': {
options |= SPV_BINARY_TO_TEXT_OPTION_PRINT;
#ifdef SPV_COLOR_TERMINAL
options |= SPV_BINARY_TO_TEXT_OPTION_COLOR;
#endif
} break;
default:
print_usage(argv[0]);
return 1;
}
} else {
if (!inFile) {
inFile = argv[argi];
} else {
print_usage(argv[0]);
return 1;
}
}
}
if (!outFile) {
outFile = "out.spvasm";
}
spvCheck(!inFile, fprintf(stderr, "error: input file is empty.\n"); return 1);
std::vector<uint32_t> contents;
if (FILE *fp = fopen(inFile, "rb")) {
uint32_t buf[1024];
while (size_t len = fread(buf, sizeof(uint32_t), 1024, fp)) {
contents.insert(contents.end(), buf, buf + len);
}
fclose(fp);
} else {
fprintf(stderr, "error: file does not exist '%s'\n", inFile);
return 1;
}
spv_binary_t binary = {contents.data(), contents.size()};
spv_opcode_table opcodeTable;
spv_result_t error = spvOpcodeTableGet(&opcodeTable);
spvCheck(error, fprintf(stderr, "error: internal malfunction\n");
return error);
spv_operand_table operandTable;
error = spvOperandTableGet(&operandTable);
spvCheck(error, fprintf(stderr, "error: internal malfunction\n");
return error);
spv_ext_inst_table extInstTable;
error = spvExtInstTableGet(&extInstTable);
spvCheck(error, fprintf(stderr, "error: Internal malfunction.\n"));
spv_text text;
spv_diagnostic diagnostic = nullptr;
error = spvBinaryToText(&binary, options, opcodeTable, operandTable,
extInstTable, &text, &diagnostic);
spvCheck(error, spvDiagnosticPrint(diagnostic);
spvDiagnosticDestroy(diagnostic); return error);
if (spvIsInBitfield(SPV_BINARY_TO_TEXT_OPTION_PRINT, options)) {
printf("%s", text->str);
} else {
if (FILE *fp = fopen(outFile, "w")) {
size_t written = fwrite(text->str, sizeof(char), (size_t)text->length, fp);
if (text->length != written) {
spvTextDestroy(text);
fprintf(stderr, "error: could not write to file '%s'\n", outFile);
return 1;
}
} else {
spvTextDestroy(text);
fprintf(stderr, "error: could not open file '%s'\n", outFile);
return 1;
}
}
spvTextDestroy(text);
return 0;
}

119
tools/val/val.cpp Normal file
Просмотреть файл

@ -0,0 +1,119 @@
// Copyright (c) 2015 The Khronos Group Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and/or associated documentation files (the
// "Materials"), to deal in the Materials without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Materials, and to
// permit persons to whom the Materials are furnished to do so, subject to
// the following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Materials.
//
// MODIFICATIONS TO THIS FILE MAY MEAN IT NO LONGER ACCURATELY REFLECTS
// KHRONOS STANDARDS. THE UNMODIFIED, NORMATIVE VERSIONS OF KHRONOS
// SPECIFICATIONS AND HEADER INFORMATION ARE LOCATED AT
// https://www.khronos.org/registry/
//
// THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
// MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
#include <libspirv/libspirv.h>
#include <assert.h>
#include <stdio.h>
#include <string.h>
#include <vector>
void print_usage(char *argv0) {
printf(
"Validate a SPIR-V binary file.\n\n"
"USAGE: %s [options] <filename>\n\n"
" -basic Perform basic validation (disabled)\n"
" -layout Perform layout validation "
"(disabled)\n"
" -id Perform id validation (default ON)\n"
" -capability <capability> Performs OpCode validation "
"(disabled)\n",
argv0);
}
int main(int argc, char **argv) {
if (2 > argc) {
print_usage(argv[0]);
return 1;
}
const char *inFile = nullptr;
uint32_t options = 0;
for (int argi = 1; argi < argc; ++argi) {
if ('-' == argv[argi][0]) {
if (!strcmp("basic", argv[argi] + 1)) {
options |= SPV_VALIDATE_BASIC_BIT;
} else if (!strcmp("layout", argv[argi] + 1)) {
options |= SPV_VALIDATE_LAYOUT_BIT;
} else if (!strcmp("id", argv[argi] + 1)) {
options |= SPV_VALIDATE_ID_BIT;
} else if (!strcmp("rules", argv[argi] + 1)) {
options |= SPV_VALIDATE_RULES_BIT;
} else {
print_usage(argv[0]);
return 1;
}
} else {
if (!inFile) {
inFile = argv[argi];
} else {
print_usage(argv[0]);
return 1;
}
}
}
spvCheck(!inFile, fprintf(stderr, "error: input file is empty.\n"); return 1);
std::vector<uint32_t> contents;
if (FILE *fp = fopen(inFile, "rb")) {
uint32_t buf[1024];
while (size_t len = fread(buf, sizeof(uint32_t),
sizeof(buf) / sizeof(uint32_t), fp)) {
contents.insert(contents.end(), buf, buf + len);
}
fclose(fp);
} else {
fprintf(stderr, "error: file does not exist '%s'\n", inFile);
return 1;
}
spv_binary_t binary = {contents.data(), contents.size()};
spv_opcode_table opcodeTable;
spv_result_t error = spvOpcodeTableGet(&opcodeTable);
spvCheck(error, fprintf(stderr, "error: internal malfunction\n");
return error);
spv_operand_table operandTable;
error = spvOperandTableGet(&operandTable);
spvCheck(error, fprintf(stderr, "error: internal malfunction\n");
return error);
spv_ext_inst_table extInstTable;
error = spvExtInstTableGet(&extInstTable);
spvCheck(error, fprintf(stderr, "error: Internal malfunction.\n"));
spv_diagnostic diagnostic = nullptr;
error = spvValidate(&binary, opcodeTable, operandTable, extInstTable, options,
&diagnostic);
spvCheck(error, spvDiagnosticPrint(diagnostic);
spvDiagnosticDestroy(diagnostic); return error);
return 0;
}