-This directory contains a Linux binary for the glslang validator.\r
-\r
-Installation: The executable in this directory is self sufficient, and can be \r
-placed where desired; in a test directory, or in a system path, etc.\r
-\r
-Usage: Execute glslangValidator with no arguments to get a usage statement.\r
+This directory contains a Linux binary for the glslang validator.
+
+Installation: The executable in this directory is self sufficient, and can be
+placed where desired; in a test directory, or in a system path, etc.
+
+Usage: Execute glslangValidator with no arguments to get a usage statement.
-This directory contains a Windows binary for the glslang validator.\r
-\r
-Installation: The executable in this directory is self sufficient, and can be \r
-placed where desired; in a test directory, or in a system path, etc.\r
-\r
-Usage: Execute glslangValidator with no arguments to get a usage statement.\r
+This directory contains a Windows binary for the glslang validator.
+
+Installation: The executable in this directory is self sufficient, and can be
+placed where desired; in a test directory, or in a system path, etc.
+
+Usage: Execute glslangValidator with no arguments to get a usage statement.
-cmake_minimum_required(VERSION 2.8)\r
-\r
-include_directories(. ../glslang)\r
-if(WIN32)\r
- include_directories(${include_directories} ../glslang/OSDependent/Windows)\r
-elseif(UNIX)\r
- include_directories(${include_directories} ../glslang/OSDependent/Linux)\r
-else(WIN32)\r
- message("unknown platform")\r
-endif(WIN32)\r
-\r
-set(SOURCES InitializeDll.cpp InitializeDll.h)\r
-\r
-add_library(OGLCompiler STATIC ${SOURCES})\r
-\r
-if(WIN32)\r
- source_group("Source" FILES ${SOURCES})\r
-endif(WIN32)\r
-\r
-install(TARGETS OGLCompiler \r
- ARCHIVE DESTINATION lib)\r
+cmake_minimum_required(VERSION 2.8)
+
+include_directories(. ../glslang)
+if(WIN32)
+ include_directories(${include_directories} ../glslang/OSDependent/Windows)
+elseif(UNIX)
+ include_directories(${include_directories} ../glslang/OSDependent/Linux)
+else(WIN32)
+ message("unknown platform")
+endif(WIN32)
+
+set(SOURCES InitializeDll.cpp InitializeDll.h)
+
+add_library(OGLCompiler STATIC ${SOURCES})
+
+if(WIN32)
+ source_group("Source" FILES ${SOURCES})
+endif(WIN32)
+
+install(TARGETS OGLCompiler
+ ARCHIVE DESTINATION lib)
-cmake_minimum_required(VERSION 2.8)\r
-\r
-include_directories(.. ${CMAKE_CURRENT_BINARY_DIR})\r
-\r
-set(SOURCES\r
- GlslangToSpv.cpp\r
- SpvBuilder.cpp\r
- SPVRemapper.cpp\r
- doc.cpp\r
- disassemble.cpp)\r
-\r
-set(HEADERS\r
- spirv.h\r
- GlslangToSpv.h\r
- SpvBuilder.h\r
- SPVRemapper.h\r
- spvIR.h\r
- doc.h\r
- disassemble.h)\r
-\r
-add_library(SPIRV STATIC ${SOURCES} ${HEADERS})\r
-\r
-if(WIN32)\r
- source_group("Source" FILES ${SOURCES} ${HEADERS})\r
-endif(WIN32)\r
-\r
-install(TARGETS SPIRV\r
- ARCHIVE DESTINATION lib)\r
+cmake_minimum_required(VERSION 2.8)
+
+include_directories(.. ${CMAKE_CURRENT_BINARY_DIR})
+
+set(SOURCES
+ GlslangToSpv.cpp
+ SpvBuilder.cpp
+ SPVRemapper.cpp
+ doc.cpp
+ disassemble.cpp)
+
+set(HEADERS
+ spirv.h
+ GlslangToSpv.h
+ SpvBuilder.h
+ SPVRemapper.h
+ spvIR.h
+ doc.h
+ disassemble.h)
+
+add_library(SPIRV STATIC ${SOURCES} ${HEADERS})
+
+if(WIN32)
+ source_group("Source" FILES ${SOURCES} ${HEADERS})
+endif(WIN32)
+
+install(TARGETS SPIRV
+ ARCHIVE DESTINATION lib)
-/*\r
-** Copyright (c) 2014-2015 The Khronos Group Inc.\r
-**\r
-** Permission is hereby granted, free of charge, to any person obtaining a\r
-** copy of this software and/or associated documentation files (the\r
-** "Materials"), to deal in the Materials without restriction, including\r
-** without limitation the rights to use, copy, modify, merge, publish,\r
-** distribute, sublicense, and/or sell copies of the Materials, and to\r
-** permit persons to whom the Materials are furnished to do so, subject to\r
-** the following conditions:\r
-**\r
-** The above copyright notice and this permission notice shall be included\r
-** in all copies or substantial portions of the Materials.\r
-**\r
-** THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
-** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
-** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\r
-** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY\r
-** CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,\r
-** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE\r
-** MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.\r
-*/\r
-\r
-//\r
-// Author: John Kessenich, LunarG\r
-//\r
-\r
-namespace GLSL_STD_450 {\r
-\r
-enum Entrypoints {\r
- Round = 0,\r
- RoundEven = 1,\r
- Trunc = 2,\r
- Abs = 3,\r
- Sign = 4,\r
- Floor = 5,\r
- Ceil = 6,\r
- Fract = 7,\r
-\r
- Radians = 8,\r
- Degrees = 9,\r
- Sin = 10,\r
- Cos = 11,\r
- Tan = 12,\r
- Asin = 13,\r
- Acos = 14,\r
- Atan = 15,\r
- Sinh = 16,\r
- Cosh = 17,\r
- Tanh = 18,\r
- Asinh = 19,\r
- Acosh = 20,\r
- Atanh = 21,\r
- Atan2 = 22,\r
-\r
- Pow = 23,\r
- Exp = 24,\r
- Log = 25,\r
- Exp2 = 26,\r
- Log2 = 27,\r
- Sqrt = 28,\r
- InverseSqrt = 29,\r
-\r
- Determinant = 30,\r
- MatrixInverse = 31,\r
-\r
- Modf = 32, // second argument needs the OpVariable = , not an OpLoad\r
- Min = 33,\r
- Max = 34,\r
- Clamp = 35,\r
- Mix = 36,\r
- Step = 37,\r
- SmoothStep = 38,\r
-\r
- FloatBitsToInt = 39,\r
- FloatBitsToUint = 40,\r
- IntBitsToFloat = 41,\r
- UintBitsToFloat = 42,\r
-\r
- Fma = 43,\r
- Frexp = 44,\r
- Ldexp = 45,\r
-\r
- PackSnorm4x8 = 46,\r
- PackUnorm4x8 = 47,\r
- PackSnorm2x16 = 48,\r
- PackUnorm2x16 = 49,\r
- PackHalf2x16 = 50,\r
- PackDouble2x32 = 51,\r
- UnpackSnorm2x16 = 52,\r
- UnpackUnorm2x16 = 53,\r
- UnpackHalf2x16 = 54,\r
- UnpackSnorm4x8 = 55,\r
- UnpackUnorm4x8 = 56,\r
- UnpackDouble2x32 = 57,\r
-\r
- Length = 58,\r
- Distance = 59,\r
- Cross = 60,\r
- Normalize = 61,\r
- Ftransform = 62,\r
- FaceForward = 63,\r
- Reflect = 64,\r
- Refract = 65,\r
-\r
- UaddCarry = 66,\r
- UsubBorrow = 67,\r
- UmulExtended = 68,\r
- ImulExtended = 69,\r
- BitfieldExtract = 70,\r
- BitfieldInsert = 71,\r
- BitfieldReverse = 72,\r
- BitCount = 73,\r
- FindLSB = 74,\r
- FindMSB = 75,\r
-\r
- InterpolateAtCentroid = 76,\r
- InterpolateAtSample = 77,\r
- InterpolateAtOffset = 78,\r
-\r
- Count\r
-};\r
-\r
-inline void GetDebugNames(const char** names)\r
-{\r
- for (int i = 0; i < Count; ++i)\r
- names[i] = "Unknown";\r
-\r
- names[Round] = "round";\r
- names[RoundEven] = "roundEven";\r
- names[Trunc] = "trunc";\r
- names[Abs] = "abs";\r
- names[Sign] = "sign";\r
- names[Floor] = "floor";\r
- names[Ceil] = "ceil";\r
- names[Fract] = "fract";\r
- names[Radians] = "radians";\r
- names[Degrees] = "degrees";\r
- names[Sin] = "sin";\r
- names[Cos] = "cos";\r
- names[Tan] = "tan";\r
- names[Asin] = "asin";\r
- names[Acos] = "acos";\r
- names[Atan] = "atan";\r
- names[Sinh] = "sinh";\r
- names[Cosh] = "cosh";\r
- names[Tanh] = "tanh";\r
- names[Asinh] = "asinh";\r
- names[Acosh] = "acosh";\r
- names[Atanh] = "atanh";\r
- names[Atan2] = "atan2";\r
- names[Pow] = "pow";\r
- names[Exp] = "exp";\r
- names[Log] = "log";\r
- names[Exp2] = "exp2";\r
- names[Log2] = "log2";\r
- names[Sqrt] = "sqrt";\r
- names[InverseSqrt] = "inverseSqrt";\r
- names[Determinant] = "determinant";\r
- names[MatrixInverse] = "matrixInverse";\r
- names[Modf] = "modf";\r
- names[Min] = "min";\r
- names[Max] = "max";\r
- names[Clamp] = "clamp";\r
- names[Mix] = "mix";\r
- names[Step] = "step";\r
- names[SmoothStep] = "smoothStep";\r
- names[FloatBitsToInt] = "floatBitsToInt";\r
- names[FloatBitsToUint] = "floatBitsToUint";\r
- names[IntBitsToFloat] = "intBitsToFloat";\r
- names[UintBitsToFloat] = "uintBitsToFloat";\r
- names[Fma] = "fma";\r
- names[Frexp] = "frexp";\r
- names[Ldexp] = "ldexp";\r
- names[PackSnorm4x8] = "packSnorm4x8";\r
- names[PackUnorm4x8] = "packUnorm4x8";\r
- names[PackSnorm2x16] = "packSnorm2x16";\r
- names[PackUnorm2x16] = "packUnorm2x16";\r
- names[PackHalf2x16] = "packHalf2x16";\r
- names[PackDouble2x32] = "packDouble2x32";\r
- names[UnpackSnorm2x16] = "unpackSnorm2x16";\r
- names[UnpackUnorm2x16] = "unpackUnorm2x16";\r
- names[UnpackHalf2x16] = "unpackHalf2x16";\r
- names[UnpackSnorm4x8] = "unpackSnorm4x8";\r
- names[UnpackUnorm4x8] = "unpackUnorm4x8";\r
- names[UnpackDouble2x32] = "unpackDouble2x32";\r
- names[Length] = "length";\r
- names[Distance] = "distance";\r
- names[Cross] = "cross";\r
- names[Normalize] = "normalize";\r
- names[Ftransform] = "ftransform";\r
- names[FaceForward] = "faceForward";\r
- names[Reflect] = "reflect";\r
- names[Refract] = "refract";\r
- names[UaddCarry] = "uaddCarry";\r
- names[UsubBorrow] = "usubBorrow";\r
- names[UmulExtended] = "umulExtended";\r
- names[ImulExtended] = "imulExtended";\r
- names[BitfieldExtract] = "bitfieldExtract";\r
- names[BitfieldInsert] = "bitfieldInsert";\r
- names[BitfieldReverse] = "bitfieldReverse";\r
- names[BitCount] = "bitCount";\r
- names[FindLSB] = "findLSB";\r
- names[FindMSB] = "findMSB";\r
- names[InterpolateAtCentroid] = "interpolateAtCentroid";\r
- names[InterpolateAtSample] = "interpolateAtSample";\r
- names[InterpolateAtOffset] = "interpolateAtOffset";\r
-}\r
-\r
-}; // end namespace GLSL_STD_450\r
+/*
+** Copyright (c) 2014-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.
+**
+** 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] = "matrixInverse";
+ 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
-//\r
-//Copyright (C) 2014 LunarG, Inc.\r
-//\r
-//All rights reserved.\r
-//\r
-//Redistribution and use in source and binary forms, with or without\r
-//modification, are permitted provided that the following conditions\r
-//are met:\r
-//\r
-// Redistributions of source code must retain the above copyright\r
-// notice, this list of conditions and the following disclaimer.\r
-//\r
-// Redistributions in binary form must reproduce the above\r
-// copyright notice, this list of conditions and the following\r
-// disclaimer in the documentation and/or other materials provided\r
-// with the distribution.\r
-//\r
-// Neither the name of 3Dlabs Inc. Ltd. nor the names of its\r
-// contributors may be used to endorse or promote products derived\r
-// from this software without specific prior written permission.\r
-//\r
-//THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\r
-//"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\r
-//LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS\r
-//FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE\r
-//COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,\r
-//INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,\r
-//BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\r
-//LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER\r
-//CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\r
-//LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN\r
-//ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE\r
-//POSSIBILITY OF SUCH DAMAGE.\r
-\r
-//\r
-// Author: John Kessenich, LunarG\r
-//\r
-// Visit the nodes in the glslang intermediate tree representation to\r
-// translate them to SPIR-V.\r
-//\r
-\r
-#include "spirv.h"\r
-#include "GlslangToSpv.h"\r
-#include "SpvBuilder.h"\r
-#include "GLSL450Lib.h"\r
-\r
-// Glslang includes\r
-#include "glslang/MachineIndependent/localintermediate.h"\r
-#include "glslang/MachineIndependent/SymbolTable.h"\r
-\r
-#include <string>\r
-#include <map>\r
-#include <list>\r
-#include <vector>\r
-#include <stack>\r
-#include <fstream>\r
-\r
-namespace {\r
-\r
-const int GlslangMagic = 0x51a;\r
-\r
-//\r
-// The main holder of information for translating glslang to SPIR-V.\r
-//\r
-// Derives from the AST walking base class.\r
-//\r
-class TGlslangToSpvTraverser : public glslang::TIntermTraverser {\r
-public:\r
- TGlslangToSpvTraverser(const glslang::TIntermediate*);\r
- virtual ~TGlslangToSpvTraverser();\r
-\r
- bool visitAggregate(glslang::TVisit, glslang::TIntermAggregate*);\r
- bool visitBinary(glslang::TVisit, glslang::TIntermBinary*);\r
- void visitConstantUnion(glslang::TIntermConstantUnion*);\r
- bool visitSelection(glslang::TVisit, glslang::TIntermSelection*);\r
- bool visitSwitch(glslang::TVisit, glslang::TIntermSwitch*);\r
- void visitSymbol(glslang::TIntermSymbol* symbol);\r
- bool visitUnary(glslang::TVisit, glslang::TIntermUnary*);\r
- bool visitLoop(glslang::TVisit, glslang::TIntermLoop*);\r
- bool visitBranch(glslang::TVisit visit, glslang::TIntermBranch*);\r
-\r
- void dumpSpv(std::vector<unsigned int>& out) { builder.dump(out); }\r
-\r
-protected:\r
- spv::Id createSpvVariable(const glslang::TIntermSymbol*);\r
- spv::Id getSampledType(const glslang::TSampler&);\r
- spv::Id convertGlslangToSpvType(const glslang::TType& type);\r
-\r
- bool isShaderEntrypoint(const glslang::TIntermAggregate* node);\r
- void makeFunctions(const glslang::TIntermSequence&);\r
- void makeGlobalInitializers(const glslang::TIntermSequence&);\r
- void visitFunctions(const glslang::TIntermSequence&);\r
- void handleFunctionEntry(const glslang::TIntermAggregate* node);\r
- void translateArguments(const glslang::TIntermSequence& glslangArguments, std::vector<spv::Id>& arguments);\r
- spv::Id handleBuiltInFunctionCall(const glslang::TIntermAggregate*);\r
- spv::Id handleUserFunctionCall(const glslang::TIntermAggregate*);\r
-\r
- spv::Id createBinaryOperation(glslang::TOperator op, spv::Decoration precision, spv::Id typeId, spv::Id left, spv::Id right, glslang::TBasicType typeProxy, bool reduceComparison = true);\r
- spv::Id createUnaryOperation(glslang::TOperator op, spv::Decoration precision, spv::Id typeId, spv::Id operand, bool isFloat);\r
- spv::Id createConversion(glslang::TOperator op, spv::Decoration precision, spv::Id destTypeId, spv::Id operand);\r
- spv::Id makeSmearedConstant(spv::Id constant, int vectorSize);\r
- spv::Id createMiscOperation(glslang::TOperator op, spv::Decoration precision, spv::Id typeId, std::vector<spv::Id>& operands);\r
- spv::Id createNoArgOperation(glslang::TOperator op);\r
- spv::Id getSymbolId(const glslang::TIntermSymbol* node);\r
- void addDecoration(spv::Id id, spv::Decoration dec);\r
- void addMemberDecoration(spv::Id id, int member, spv::Decoration dec);\r
- spv::Id createSpvConstant(const glslang::TType& type, const glslang::TConstUnionArray&, int& nextConst);\r
-\r
- spv::Function* shaderEntry;\r
- int sequenceDepth;\r
-\r
- // There is a 1:1 mapping between a spv builder and a module; this is thread safe\r
- spv::Builder builder;\r
- bool inMain;\r
- bool mainTerminated;\r
- bool linkageOnly;\r
- const glslang::TIntermediate* glslangIntermediate;\r
- spv::Id stdBuiltins;\r
-\r
- std::map<int, spv::Id> symbolValues;\r
- std::set<int> constReadOnlyParameters; // set of formal function parameters that have glslang qualifier constReadOnly, so we know they are not local function "const" that are write-once\r
- std::map<std::string, spv::Function*> functionMap;\r
- std::map<const glslang::TTypeList*, spv::Id> structMap;\r
- std::map<const glslang::TTypeList*, std::vector<int> > memberRemapper; // for mapping glslang block indices to spv indices (e.g., due to hidden members)\r
- std::stack<bool> breakForLoop; // false means break for switch\r
- std::stack<glslang::TIntermTyped*> loopTerminal; // code from the last part of a for loop: for(...; ...; terminal), needed for e.g., continue };\r
-};\r
-\r
-//\r
-// Helper functions for translating glslang representations to SPIR-V enumerants.\r
-//\r
-\r
-// Translate glslang profile to SPIR-V source language.\r
-spv::SourceLanguage TranslateSourceLanguage(EProfile profile)\r
-{\r
- switch (profile) {\r
- case ENoProfile:\r
- case ECoreProfile:\r
- case ECompatibilityProfile:\r
- return spv::SourceLanguageGLSL;\r
- case EEsProfile:\r
- return spv::SourceLanguageESSL;\r
- default:\r
- return spv::SourceLanguageUnknown;\r
- }\r
-}\r
-\r
-// Translate glslang language (stage) to SPIR-V execution model.\r
-spv::ExecutionModel TranslateExecutionModel(EShLanguage stage)\r
-{\r
- switch (stage) {\r
- case EShLangVertex: return spv::ExecutionModelVertex;\r
- case EShLangTessControl: return spv::ExecutionModelTessellationControl;\r
- case EShLangTessEvaluation: return spv::ExecutionModelTessellationEvaluation;\r
- case EShLangGeometry: return spv::ExecutionModelGeometry;\r
- case EShLangFragment: return spv::ExecutionModelFragment;\r
- case EShLangCompute: return spv::ExecutionModelGLCompute;\r
- default:\r
- spv::MissingFunctionality("GLSL stage");\r
- return spv::ExecutionModelFragment;\r
- }\r
-}\r
-\r
-// Translate glslang type to SPIR-V storage class.\r
-spv::StorageClass TranslateStorageClass(const glslang::TType& type)\r
-{\r
- if (type.getQualifier().isPipeInput())\r
- return spv::StorageClassInput;\r
- else if (type.getQualifier().isPipeOutput())\r
- return spv::StorageClassOutput;\r
- else if (type.getQualifier().isUniformOrBuffer()) {\r
- if (type.getBasicType() == glslang::EbtBlock)\r
- return spv::StorageClassUniform;\r
- else\r
- return spv::StorageClassUniformConstant;\r
- // TODO: how are we distuingishing between default and non-default non-writable uniforms? Do default uniforms even exist?\r
- } else {\r
- switch (type.getQualifier().storage) {\r
- case glslang::EvqShared: return spv::StorageClassWorkgroupLocal; break;\r
- case glslang::EvqGlobal: return spv::StorageClassPrivateGlobal;\r
- case glslang::EvqConstReadOnly: return spv::StorageClassFunction;\r
- case glslang::EvqTemporary: return spv::StorageClassFunction;\r
- default: \r
- spv::MissingFunctionality("unknown glslang storage class");\r
- return spv::StorageClassFunction;\r
- }\r
- }\r
-}\r
-\r
-// Translate glslang sampler type to SPIR-V dimensionality.\r
-spv::Dim TranslateDimensionality(const glslang::TSampler& sampler)\r
-{\r
- switch (sampler.dim) {\r
- case glslang::Esd1D: return spv::Dim1D;\r
- case glslang::Esd2D: return spv::Dim2D;\r
- case glslang::Esd3D: return spv::Dim3D;\r
- case glslang::EsdCube: return spv::DimCube;\r
- case glslang::EsdRect: return spv::DimRect;\r
- case glslang::EsdBuffer: return spv::DimBuffer;\r
- default:\r
- spv::MissingFunctionality("unknown sampler dimension");\r
- return spv::Dim2D;\r
- }\r
-}\r
-\r
-// Translate glslang type to SPIR-V precision decorations.\r
-spv::Decoration TranslatePrecisionDecoration(const glslang::TType& type)\r
-{\r
- switch (type.getQualifier().precision) {\r
- case glslang::EpqLow: return spv::DecorationPrecisionLow;\r
- case glslang::EpqMedium: return spv::DecorationPrecisionMedium;\r
- case glslang::EpqHigh: return spv::DecorationPrecisionHigh;\r
- default:\r
- return spv::NoPrecision;\r
- }\r
-}\r
-\r
-// Translate glslang type to SPIR-V block decorations.\r
-spv::Decoration TranslateBlockDecoration(const glslang::TType& type)\r
-{\r
- if (type.getBasicType() == glslang::EbtBlock) {\r
- switch (type.getQualifier().storage) {\r
- case glslang::EvqUniform: return spv::DecorationBlock;\r
- case glslang::EvqBuffer: return spv::DecorationBufferBlock;\r
- case glslang::EvqVaryingIn: return spv::DecorationBlock;\r
- case glslang::EvqVaryingOut: return spv::DecorationBlock;\r
- default:\r
- spv::MissingFunctionality("kind of block");\r
- break;\r
- }\r
- }\r
-\r
- return (spv::Decoration)spv::BadValue;\r
-}\r
-\r
-// Translate glslang type to SPIR-V layout decorations.\r
-spv::Decoration TranslateLayoutDecoration(const glslang::TType& type)\r
-{\r
- if (type.isMatrix()) {\r
- switch (type.getQualifier().layoutMatrix) {\r
- case glslang::ElmRowMajor:\r
- return spv::DecorationRowMajor;\r
- default:\r
- return spv::DecorationColMajor;\r
- }\r
- } else {\r
- switch (type.getBasicType()) {\r
- default:\r
- return (spv::Decoration)spv::BadValue;\r
- break;\r
- case glslang::EbtBlock:\r
- switch (type.getQualifier().storage) {\r
- case glslang::EvqUniform:\r
- case glslang::EvqBuffer:\r
- switch (type.getQualifier().layoutPacking) {\r
- case glslang::ElpShared: return spv::DecorationGLSLShared;\r
- case glslang::ElpStd140: return spv::DecorationGLSLStd140;\r
- case glslang::ElpStd430: return spv::DecorationGLSLStd430;\r
- case glslang::ElpPacked: return spv::DecorationGLSLPacked;\r
- default:\r
- spv::MissingFunctionality("uniform block layout");\r
- return spv::DecorationGLSLShared;\r
- }\r
- case glslang::EvqVaryingIn:\r
- case glslang::EvqVaryingOut:\r
- if (type.getQualifier().layoutPacking != glslang::ElpNone)\r
- spv::MissingFunctionality("in/out block layout");\r
- return (spv::Decoration)spv::BadValue;\r
- default:\r
- spv::MissingFunctionality("block storage qualification");\r
- return (spv::Decoration)spv::BadValue;\r
- }\r
- }\r
- }\r
-}\r
-\r
-// Translate glslang type to SPIR-V interpolation decorations.\r
-spv::Decoration TranslateInterpolationDecoration(const glslang::TType& type)\r
-{\r
- if (type.getQualifier().smooth)\r
- return spv::DecorationSmooth;\r
- if (type.getQualifier().nopersp)\r
- return spv::DecorationNoperspective;\r
- else if (type.getQualifier().patch)\r
- return spv::DecorationPatch;\r
- else if (type.getQualifier().flat)\r
- return spv::DecorationFlat;\r
- else if (type.getQualifier().centroid)\r
- return spv::DecorationCentroid;\r
- else if (type.getQualifier().sample)\r
- return spv::DecorationSample;\r
- else\r
- return (spv::Decoration)spv::BadValue;\r
-}\r
-\r
-// If glslang type is invaraiant, return SPIR-V invariant decoration.\r
-spv::Decoration TranslateInvariantDecoration(const glslang::TType& type)\r
-{\r
- if (type.getQualifier().invariant)\r
- return spv::DecorationInvariant;\r
- else\r
- return (spv::Decoration)spv::BadValue;\r
-}\r
-\r
-// Translate glslang built-in variable to SPIR-V built in decoration.\r
-spv::BuiltIn TranslateBuiltInDecoration(glslang::TBuiltInVariable builtIn)\r
-{\r
- switch (builtIn) {\r
- case glslang::EbvPosition: return spv::BuiltInPosition;\r
- case glslang::EbvPointSize: return spv::BuiltInPointSize;\r
- case glslang::EbvClipVertex: return spv::BuiltInClipVertex;\r
- case glslang::EbvClipDistance: return spv::BuiltInClipDistance;\r
- case glslang::EbvCullDistance: return spv::BuiltInCullDistance;\r
- case glslang::EbvVertexId: return spv::BuiltInVertexId;\r
- case glslang::EbvInstanceId: return spv::BuiltInInstanceId;\r
- case glslang::EbvPrimitiveId: return spv::BuiltInPrimitiveId;\r
- case glslang::EbvInvocationId: return spv::BuiltInInvocationId;\r
- case glslang::EbvLayer: return spv::BuiltInLayer;\r
- case glslang::EbvViewportIndex: return spv::BuiltInViewportIndex;\r
- case glslang::EbvTessLevelInner: return spv::BuiltInTessLevelInner;\r
- case glslang::EbvTessLevelOuter: return spv::BuiltInTessLevelOuter;\r
- case glslang::EbvTessCoord: return spv::BuiltInTessCoord;\r
- case glslang::EbvPatchVertices: return spv::BuiltInPatchVertices;\r
- case glslang::EbvFragCoord: return spv::BuiltInFragCoord;\r
- case glslang::EbvPointCoord: return spv::BuiltInPointCoord;\r
- case glslang::EbvFace: return spv::BuiltInFrontFacing;\r
- case glslang::EbvSampleId: return spv::BuiltInSampleId;\r
- case glslang::EbvSamplePosition: return spv::BuiltInSamplePosition;\r
- case glslang::EbvSampleMask: return spv::BuiltInSampleMask;\r
- case glslang::EbvFragColor: return spv::BuiltInFragColor;\r
- case glslang::EbvFragData: return spv::BuiltInFragColor;\r
- case glslang::EbvFragDepth: return spv::BuiltInFragDepth;\r
- case glslang::EbvHelperInvocation: return spv::BuiltInHelperInvocation;\r
- case glslang::EbvNumWorkGroups: return spv::BuiltInNumWorkgroups;\r
- case glslang::EbvWorkGroupSize: return spv::BuiltInWorkgroupSize;\r
- case glslang::EbvWorkGroupId: return spv::BuiltInWorkgroupId;\r
- case glslang::EbvLocalInvocationId: return spv::BuiltInLocalInvocationId;\r
- case glslang::EbvLocalInvocationIndex: return spv::BuiltInLocalInvocationIndex;\r
- case glslang::EbvGlobalInvocationId: return spv::BuiltInGlobalInvocationId;\r
- default: return (spv::BuiltIn)spv::BadValue;\r
- }\r
-}\r
-\r
-//\r
-// Implement the TGlslangToSpvTraverser class.\r
-//\r
-\r
-TGlslangToSpvTraverser::TGlslangToSpvTraverser(const glslang::TIntermediate* glslangIntermediate)\r
- : TIntermTraverser(true, false, true), shaderEntry(0), sequenceDepth(0),\r
- builder(GlslangMagic),\r
- inMain(false), mainTerminated(false), linkageOnly(false),\r
- glslangIntermediate(glslangIntermediate)\r
-{\r
- spv::ExecutionModel executionModel = TranslateExecutionModel(glslangIntermediate->getStage());\r
-\r
- builder.clearAccessChain();\r
- builder.setSource(TranslateSourceLanguage(glslangIntermediate->getProfile()), glslangIntermediate->getVersion());\r
- stdBuiltins = builder.import("GLSL.std.450");\r
- builder.setMemoryModel(spv::AddressingModelLogical, spv::MemoryModelGLSL450);\r
- shaderEntry = builder.makeMain();\r
- builder.addEntryPoint(executionModel, shaderEntry);\r
-\r
- // Add the source extensions\r
- const std::set<std::string>& sourceExtensions = glslangIntermediate->getRequestedExtensions();\r
- for (std::set<std::string>::const_iterator it = sourceExtensions.begin(); it != sourceExtensions.end(); ++it)\r
- builder.addSourceExtension(it->c_str());\r
-\r
- // Add the top-level modes for this shader.\r
-\r
- if (glslangIntermediate->getXfbMode())\r
- builder.addExecutionMode(shaderEntry, spv::ExecutionModeXfb);\r
-\r
- unsigned int mode;\r
- switch (glslangIntermediate->getStage()) {\r
- case EShLangVertex:\r
- break;\r
-\r
- case EShLangTessControl:\r
- builder.addExecutionMode(shaderEntry, spv::ExecutionModeOutputVertices, glslangIntermediate->getVertices());\r
- break;\r
-\r
- case EShLangTessEvaluation:\r
- switch (glslangIntermediate->getInputPrimitive()) {\r
- case glslang::ElgTriangles: mode = spv::ExecutionModeInputTriangles; break;\r
- case glslang::ElgQuads: mode = spv::ExecutionModeInputQuads; break;\r
- case glslang::ElgIsolines: mode = spv::ExecutionModeInputIsolines; break;\r
- default: mode = spv::BadValue; break;\r
- }\r
- if (mode != spv::BadValue)\r
- builder.addExecutionMode(shaderEntry, (spv::ExecutionMode)mode);\r
-\r
- // TODO\r
- //builder.addExecutionMode(spv::VertexSpacingMdName, glslangIntermediate->getVertexSpacing());\r
- //builder.addExecutionMode(spv::VertexOrderMdName, glslangIntermediate->getVertexOrder());\r
- //builder.addExecutionMode(spv::PointModeMdName, glslangIntermediate->getPointMode());\r
- break;\r
-\r
- case EShLangGeometry:\r
- switch (glslangIntermediate->getInputPrimitive()) {\r
- case glslang::ElgPoints: mode = spv::ExecutionModeInputPoints; break;\r
- case glslang::ElgLines: mode = spv::ExecutionModeInputLines; break;\r
- case glslang::ElgLinesAdjacency: mode = spv::ExecutionModeInputLinesAdjacency; break;\r
- case glslang::ElgTriangles: mode = spv::ExecutionModeInputTriangles; break;\r
- case glslang::ElgTrianglesAdjacency: mode = spv::ExecutionModeInputTrianglesAdjacency; break;\r
- default: mode = spv::BadValue; break;\r
- }\r
- if (mode != spv::BadValue)\r
- builder.addExecutionMode(shaderEntry, (spv::ExecutionMode)mode);\r
- builder.addExecutionMode(shaderEntry, spv::ExecutionModeInvocations, glslangIntermediate->getInvocations());\r
-\r
- switch (glslangIntermediate->getOutputPrimitive()) {\r
- case glslang::ElgPoints: mode = spv::ExecutionModeOutputPoints; break;\r
- case glslang::ElgLineStrip: mode = spv::ExecutionModeOutputLineStrip; break;\r
- case glslang::ElgTriangleStrip: mode = spv::ExecutionModeOutputTriangleStrip; break;\r
- default: mode = spv::BadValue; break;\r
- }\r
- if (mode != spv::BadValue)\r
- builder.addExecutionMode(shaderEntry, (spv::ExecutionMode)mode);\r
- builder.addExecutionMode(shaderEntry, spv::ExecutionModeOutputVertices, glslangIntermediate->getVertices());\r
- break;\r
-\r
- case EShLangFragment:\r
- if (glslangIntermediate->getPixelCenterInteger())\r
- builder.addExecutionMode(shaderEntry, spv::ExecutionModePixelCenterInteger);\r
- if (glslangIntermediate->getOriginUpperLeft())\r
- builder.addExecutionMode(shaderEntry, spv::ExecutionModeOriginUpperLeft);\r
- break;\r
-\r
- case EShLangCompute:\r
- break;\r
-\r
- default:\r
- break;\r
- }\r
-\r
-}\r
-\r
-TGlslangToSpvTraverser::~TGlslangToSpvTraverser()\r
-{\r
- if (! mainTerminated) {\r
- spv::Block* lastMainBlock = shaderEntry->getLastBlock();\r
- builder.setBuildPoint(lastMainBlock);\r
- builder.leaveFunction(true);\r
- }\r
-}\r
-\r
-//\r
-// Implement the traversal functions.\r
-//\r
-// Return true from interior nodes to have the external traversal\r
-// continue on to children. Return false if children were\r
-// already processed.\r
-//\r
-\r
-//\r
-// Symbols can turn into \r
-// - uniform/input reads\r
-// - output writes\r
-// - complex lvalue base setups: foo.bar[3].... , where we see foo and start up an access chain\r
-// - something simple that degenerates into the last bullet\r
-//\r
-void TGlslangToSpvTraverser::visitSymbol(glslang::TIntermSymbol* symbol)\r
-{\r
- // getSymbolId() will set up all the IO decorations on the first call.\r
- // Formal function parameters were mapped during makeFunctions().\r
- spv::Id id = getSymbolId(symbol);\r
- \r
- if (! linkageOnly) {\r
- // Prepare to generate code for the access\r
-\r
- // L-value chains will be computed left to right. We're on the symbol now,\r
- // which is the left-most part of the access chain, so now is "clear" time,\r
- // followed by setting the base.\r
- builder.clearAccessChain();\r
-\r
- // For now, we consider all user variables as being in memory, so they are pointers,\r
- // except for "const in" arguments to a function, which are an intermediate object.\r
- // See comments in handleUserFunctionCall().\r
- glslang::TStorageQualifier qualifier = symbol->getQualifier().storage;\r
- if (qualifier == glslang::EvqConstReadOnly && constReadOnlyParameters.find(symbol->getId()) != constReadOnlyParameters.end())\r
- builder.setAccessChainRValue(id);\r
- else\r
- builder.setAccessChainLValue(id);\r
- }\r
-}\r
-\r
-bool TGlslangToSpvTraverser::visitBinary(glslang::TVisit /* visit */, glslang::TIntermBinary* node)\r
-{\r
- // First, handle special cases\r
- switch (node->getOp()) {\r
- case glslang::EOpAssign:\r
- case glslang::EOpAddAssign:\r
- case glslang::EOpSubAssign:\r
- case glslang::EOpMulAssign:\r
- case glslang::EOpVectorTimesMatrixAssign:\r
- case glslang::EOpVectorTimesScalarAssign:\r
- case glslang::EOpMatrixTimesScalarAssign:\r
- case glslang::EOpMatrixTimesMatrixAssign:\r
- case glslang::EOpDivAssign:\r
- case glslang::EOpModAssign:\r
- case glslang::EOpAndAssign:\r
- case glslang::EOpInclusiveOrAssign:\r
- case glslang::EOpExclusiveOrAssign:\r
- case glslang::EOpLeftShiftAssign:\r
- case glslang::EOpRightShiftAssign:\r
- // A bin-op assign "a += b" means the same thing as "a = a + b"\r
- // where a is evaluated before b. For a simple assignment, GLSL\r
- // says to evaluate the left before the right. So, always, left\r
- // node then right node.\r
- {\r
- // get the left l-value, save it away\r
- builder.clearAccessChain();\r
- node->getLeft()->traverse(this);\r
- spv::Builder::AccessChain lValue = builder.getAccessChain();\r
-\r
- // evaluate the right\r
- builder.clearAccessChain();\r
- node->getRight()->traverse(this);\r
- spv::Id rValue = builder.accessChainLoad(TranslatePrecisionDecoration(node->getRight()->getType()));\r
-\r
- if (node->getOp() != glslang::EOpAssign) {\r
- // the left is also an r-value\r
- builder.setAccessChain(lValue);\r
- spv::Id leftRValue = builder.accessChainLoad(TranslatePrecisionDecoration(node->getLeft()->getType()));\r
-\r
- // do the operation\r
- rValue = createBinaryOperation(node->getOp(), TranslatePrecisionDecoration(node->getType()), \r
- convertGlslangToSpvType(node->getType()), leftRValue, rValue,\r
- node->getType().getBasicType());\r
-\r
- // these all need their counterparts in createBinaryOperation()\r
- if (rValue == 0)\r
- spv::MissingFunctionality("createBinaryOperation");\r
- }\r
-\r
- // store the result\r
- builder.setAccessChain(lValue);\r
- builder.accessChainStore(rValue);\r
-\r
- // assignments are expressions having an rValue after they are evaluated...\r
- builder.clearAccessChain();\r
- builder.setAccessChainRValue(rValue);\r
- }\r
- return false;\r
- case glslang::EOpIndexDirect:\r
- case glslang::EOpIndexDirectStruct:\r
- {\r
- // Get the left part of the access chain.\r
- node->getLeft()->traverse(this);\r
-\r
- // Add the next element in the chain\r
-\r
- int index = 0;\r
- if (node->getRight()->getAsConstantUnion() == 0)\r
- spv::MissingFunctionality("direct index without a constant node");\r
- else \r
- index = node->getRight()->getAsConstantUnion()->getConstArray()[0].getIConst();\r
-\r
- if (node->getLeft()->getBasicType() == glslang::EbtBlock && node->getOp() == glslang::EOpIndexDirectStruct) {\r
- // This may be, e.g., an anonymous block-member selection, which generally need\r
- // index remapping due to hidden members in anonymous blocks.\r
- std::vector<int>& remapper = memberRemapper[node->getLeft()->getType().getStruct()];\r
- if (remapper.size() == 0)\r
- spv::MissingFunctionality("block without member remapping");\r
- else\r
- index = remapper[index];\r
- }\r
-\r
- if (! node->getLeft()->getType().isArray() &&\r
- node->getLeft()->getType().isVector() &&\r
- node->getOp() == glslang::EOpIndexDirect) {\r
- // This is essentially a hard-coded vector swizzle of size 1,\r
- // so short circuit the access-chain stuff with a swizzle.\r
- std::vector<unsigned> swizzle;\r
- swizzle.push_back(node->getRight()->getAsConstantUnion()->getConstArray()[0].getIConst());\r
- builder.accessChainPushSwizzle(swizzle);\r
- } else {\r
- // normal case for indexing array or structure or block\r
- builder.accessChainPush(builder.makeIntConstant(index), convertGlslangToSpvType(node->getType()));\r
- }\r
- }\r
- return false;\r
- case glslang::EOpIndexIndirect:\r
- {\r
- // Structure or array or vector indirection.\r
- // Will use native SPIR-V access-chain for struct and array indirection;\r
- // matrices are arrays of vectors, so will also work for a matrix.\r
- // Will use the access chain's 'component' for variable index into a vector.\r
-\r
- // This adapter is building access chains left to right.\r
- // Set up the access chain to the left.\r
- node->getLeft()->traverse(this);\r
-\r
- // save it so that computing the right side doesn't trash it\r
- spv::Builder::AccessChain partial = builder.getAccessChain();\r
-\r
- // compute the next index in the chain\r
- builder.clearAccessChain();\r
- node->getRight()->traverse(this);\r
- spv::Id index = builder.accessChainLoad(TranslatePrecisionDecoration(node->getRight()->getType()));\r
-\r
- // restore the saved access chain\r
- builder.setAccessChain(partial);\r
-\r
- if (! node->getLeft()->getType().isArray() && node->getLeft()->getType().isVector())\r
- builder.accessChainPushComponent(index);\r
- else\r
- builder.accessChainPush(index, convertGlslangToSpvType(node->getType()));\r
- }\r
- return false;\r
- case glslang::EOpVectorSwizzle:\r
- {\r
- node->getLeft()->traverse(this);\r
- glslang::TIntermSequence& swizzleSequence = node->getRight()->getAsAggregate()->getSequence();\r
- std::vector<unsigned> swizzle;\r
- for (int i = 0; i < (int)swizzleSequence.size(); ++i)\r
- swizzle.push_back(swizzleSequence[i]->getAsConstantUnion()->getConstArray()[0].getIConst());\r
- builder.accessChainPushSwizzle(swizzle);\r
- }\r
- return false;\r
- default:\r
- break;\r
- }\r
-\r
- // Assume generic binary op...\r
-\r
- // Get the operands\r
- builder.clearAccessChain();\r
- node->getLeft()->traverse(this);\r
- spv::Id left = builder.accessChainLoad(TranslatePrecisionDecoration(node->getLeft()->getType()));\r
-\r
- builder.clearAccessChain();\r
- node->getRight()->traverse(this);\r
- spv::Id right = builder.accessChainLoad(TranslatePrecisionDecoration(node->getRight()->getType()));\r
-\r
- spv::Id result;\r
- spv::Decoration precision = TranslatePrecisionDecoration(node->getType());\r
-\r
- result = createBinaryOperation(node->getOp(), precision, \r
- convertGlslangToSpvType(node->getType()), left, right,\r
- node->getLeft()->getType().getBasicType());\r
-\r
- if (! result) {\r
- spv::MissingFunctionality("glslang binary operation");\r
- } else {\r
- builder.clearAccessChain();\r
- builder.setAccessChainRValue(result);\r
-\r
- return false;\r
- }\r
-\r
- return true;\r
-}\r
-\r
-bool TGlslangToSpvTraverser::visitUnary(glslang::TVisit /* visit */, glslang::TIntermUnary* node)\r
-{\r
- builder.clearAccessChain();\r
- node->getOperand()->traverse(this);\r
- spv::Id operand = builder.accessChainLoad(TranslatePrecisionDecoration(node->getOperand()->getType()));\r
-\r
- spv::Decoration precision = TranslatePrecisionDecoration(node->getType());\r
-\r
- // it could be a conversion\r
- spv::Id result = createConversion(node->getOp(), precision, convertGlslangToSpvType(node->getType()), operand);\r
-\r
- // if not, then possibly an operation\r
- if (! result)\r
- result = createUnaryOperation(node->getOp(), precision, convertGlslangToSpvType(node->getType()), operand, node->getBasicType() == glslang::EbtFloat || node->getBasicType() == glslang::EbtDouble);\r
-\r
- if (result) {\r
- builder.clearAccessChain();\r
- builder.setAccessChainRValue(result);\r
-\r
- return false; // done with this node\r
- }\r
-\r
- // it must be a special case, check...\r
- switch (node->getOp()) {\r
- case glslang::EOpPostIncrement:\r
- case glslang::EOpPostDecrement:\r
- case glslang::EOpPreIncrement:\r
- case glslang::EOpPreDecrement:\r
- {\r
- // we need the integer value "1" or the floating point "1.0" to add/subtract\r
- spv::Id one = node->getBasicType() == glslang::EbtFloat ?\r
- builder.makeFloatConstant(1.0F) :\r
- builder.makeIntConstant(1);\r
- glslang::TOperator op;\r
- if (node->getOp() == glslang::EOpPreIncrement ||\r
- node->getOp() == glslang::EOpPostIncrement)\r
- op = glslang::EOpAdd;\r
- else\r
- op = glslang::EOpSub;\r
-\r
- spv::Id result = createBinaryOperation(op, TranslatePrecisionDecoration(node->getType()), \r
- convertGlslangToSpvType(node->getType()), operand, one, \r
- node->getType().getBasicType());\r
- if (result == 0)\r
- spv::MissingFunctionality("createBinaryOperation for unary");\r
-\r
- // The result of operation is always stored, but conditionally the\r
- // consumed result. The consumed result is always an r-value.\r
- builder.accessChainStore(result);\r
- builder.clearAccessChain();\r
- if (node->getOp() == glslang::EOpPreIncrement ||\r
- node->getOp() == glslang::EOpPreDecrement)\r
- builder.setAccessChainRValue(result);\r
- else\r
- builder.setAccessChainRValue(operand);\r
- }\r
-\r
- return false;\r
-\r
- case glslang::EOpEmitStreamVertex:\r
- builder.createNoResultOp(spv::OpEmitStreamVertex, operand);\r
- return false;\r
- case glslang::EOpEndStreamPrimitive:\r
- builder.createNoResultOp(spv::OpEndStreamPrimitive, operand);\r
- return false;\r
-\r
- default:\r
- spv::MissingFunctionality("glslang unary");\r
- break;\r
- }\r
-\r
- return true;\r
-}\r
-\r
-bool TGlslangToSpvTraverser::visitAggregate(glslang::TVisit visit, glslang::TIntermAggregate* node)\r
-{\r
- spv::Id result;\r
- glslang::TOperator binOp = glslang::EOpNull;\r
- bool reduceComparison = true;\r
- bool isMatrix = false;\r
- bool noReturnValue = false;\r
-\r
- assert(node->getOp());\r
-\r
- spv::Decoration precision = TranslatePrecisionDecoration(node->getType());\r
-\r
- switch (node->getOp()) {\r
- case glslang::EOpSequence:\r
- {\r
- if (preVisit)\r
- ++sequenceDepth;\r
- else\r
- --sequenceDepth;\r
-\r
- if (sequenceDepth == 1) {\r
- // If this is the parent node of all the functions, we want to see them\r
- // early, so all call points have actual SPIR-V functions to reference.\r
- // In all cases, still let the traverser visit the children for us.\r
- makeFunctions(node->getAsAggregate()->getSequence());\r
-\r
- // Also, we want all globals initializers to go into the entry of main(), before\r
- // anything else gets there, so visit out of order, doing them all now.\r
- makeGlobalInitializers(node->getAsAggregate()->getSequence());\r
-\r
- // Initializers are done, don't want to visit again, but functions link objects need to be processed,\r
- // so do them manually.\r
- visitFunctions(node->getAsAggregate()->getSequence());\r
-\r
- return false;\r
- }\r
-\r
- return true;\r
- }\r
- case glslang::EOpLinkerObjects:\r
- {\r
- if (visit == glslang::EvPreVisit)\r
- linkageOnly = true;\r
- else\r
- linkageOnly = false;\r
-\r
- return true;\r
- }\r
- case glslang::EOpComma:\r
- {\r
- // processing from left to right naturally leaves the right-most\r
- // lying around in the access chain\r
- glslang::TIntermSequence& glslangOperands = node->getSequence();\r
- for (int i = 0; i < (int)glslangOperands.size(); ++i)\r
- glslangOperands[i]->traverse(this);\r
-\r
- return false;\r
- }\r
- case glslang::EOpFunction:\r
- if (visit == glslang::EvPreVisit) {\r
- if (isShaderEntrypoint(node)) {\r
- inMain = true;\r
- builder.setBuildPoint(shaderEntry->getLastBlock());\r
- } else {\r
- handleFunctionEntry(node);\r
- }\r
- } else {\r
- if (inMain)\r
- mainTerminated = true;\r
- builder.leaveFunction(inMain);\r
- inMain = false;\r
- }\r
-\r
- return true;\r
- case glslang::EOpParameters:\r
- // Parameters will have been consumed by EOpFunction processing, but not\r
- // the body, so we still visited the function node's children, making this\r
- // child redundant.\r
- return false;\r
- case glslang::EOpFunctionCall:\r
- {\r
- if (node->isUserDefined())\r
- result = handleUserFunctionCall(node);\r
- else\r
- result = handleBuiltInFunctionCall(node);\r
-\r
- if (! result) {\r
- spv::MissingFunctionality("glslang function call");\r
- glslang::TConstUnionArray emptyConsts;\r
- int nextConst = 0;\r
- result = createSpvConstant(node->getType(), emptyConsts, nextConst);\r
- }\r
- builder.clearAccessChain();\r
- builder.setAccessChainRValue(result);\r
-\r
- return false;\r
- }\r
- case glslang::EOpConstructMat2x2:\r
- case glslang::EOpConstructMat2x3:\r
- case glslang::EOpConstructMat2x4:\r
- case glslang::EOpConstructMat3x2:\r
- case glslang::EOpConstructMat3x3:\r
- case glslang::EOpConstructMat3x4:\r
- case glslang::EOpConstructMat4x2:\r
- case glslang::EOpConstructMat4x3:\r
- case glslang::EOpConstructMat4x4:\r
- case glslang::EOpConstructDMat2x2:\r
- case glslang::EOpConstructDMat2x3:\r
- case glslang::EOpConstructDMat2x4:\r
- case glslang::EOpConstructDMat3x2:\r
- case glslang::EOpConstructDMat3x3:\r
- case glslang::EOpConstructDMat3x4:\r
- case glslang::EOpConstructDMat4x2:\r
- case glslang::EOpConstructDMat4x3:\r
- case glslang::EOpConstructDMat4x4:\r
- isMatrix = true;\r
- // fall through\r
- case glslang::EOpConstructFloat:\r
- case glslang::EOpConstructVec2:\r
- case glslang::EOpConstructVec3:\r
- case glslang::EOpConstructVec4:\r
- case glslang::EOpConstructDouble:\r
- case glslang::EOpConstructDVec2:\r
- case glslang::EOpConstructDVec3:\r
- case glslang::EOpConstructDVec4:\r
- case glslang::EOpConstructBool:\r
- case glslang::EOpConstructBVec2:\r
- case glslang::EOpConstructBVec3:\r
- case glslang::EOpConstructBVec4:\r
- case glslang::EOpConstructInt:\r
- case glslang::EOpConstructIVec2:\r
- case glslang::EOpConstructIVec3:\r
- case glslang::EOpConstructIVec4:\r
- case glslang::EOpConstructUint:\r
- case glslang::EOpConstructUVec2:\r
- case glslang::EOpConstructUVec3:\r
- case glslang::EOpConstructUVec4:\r
- case glslang::EOpConstructStruct:\r
- {\r
- std::vector<spv::Id> arguments;\r
- translateArguments(node->getSequence(), arguments);\r
- spv::Id resultTypeId = convertGlslangToSpvType(node->getType());\r
- spv::Id constructed;\r
- if (node->getOp() == glslang::EOpConstructStruct || node->getType().isArray()) {\r
- std::vector<spv::Id> constituents;\r
- for (int c = 0; c < (int)arguments.size(); ++c)\r
- constituents.push_back(arguments[c]);\r
- constructed = builder.createCompositeConstruct(resultTypeId, constituents);\r
- } else {\r
- if (isMatrix)\r
- constructed = builder.createMatrixConstructor(precision, arguments, resultTypeId);\r
- else\r
- constructed = builder.createConstructor(precision, arguments, resultTypeId);\r
- }\r
-\r
- builder.clearAccessChain();\r
- builder.setAccessChainRValue(constructed);\r
-\r
- return false;\r
- }\r
-\r
- // These six are component-wise compares with component-wise results.\r
- // Forward on to createBinaryOperation(), requesting a vector result.\r
- case glslang::EOpLessThan:\r
- case glslang::EOpGreaterThan:\r
- case glslang::EOpLessThanEqual:\r
- case glslang::EOpGreaterThanEqual:\r
- case glslang::EOpVectorEqual:\r
- case glslang::EOpVectorNotEqual:\r
- {\r
- // Map the operation to a binary\r
- binOp = node->getOp();\r
- reduceComparison = false;\r
- switch (node->getOp()) {\r
- case glslang::EOpVectorEqual: binOp = glslang::EOpVectorEqual; break;\r
- case glslang::EOpVectorNotEqual: binOp = glslang::EOpVectorNotEqual; break;\r
- default: binOp = node->getOp(); break;\r
- }\r
-\r
- break;\r
- }\r
- case glslang::EOpMul:\r
- // compontent-wise matrix multiply \r
- binOp = glslang::EOpMul;\r
- break;\r
- case glslang::EOpOuterProduct:\r
- // two vectors multiplied to make a matrix\r
- binOp = glslang::EOpOuterProduct;\r
- break;\r
- case glslang::EOpDot:\r
- {\r
- // for scalar dot product, use multiply \r
- glslang::TIntermSequence& glslangOperands = node->getSequence();\r
- if (! glslangOperands[0]->getAsTyped()->isVector())\r
- binOp = glslang::EOpMul;\r
- break;\r
- }\r
- case glslang::EOpMod:\r
- // when an aggregate, this is the floating-point mod built-in function,\r
- // which can be emitted by the one in createBinaryOperation()\r
- binOp = glslang::EOpMod;\r
- break;\r
- case glslang::EOpArrayLength:\r
- {\r
- glslang::TIntermTyped* typedNode = node->getSequence()[0]->getAsTyped();\r
- assert(typedNode);\r
- spv::Id length = builder.makeIntConstant(typedNode->getType().getArraySize());\r
-\r
- builder.clearAccessChain();\r
- builder.setAccessChainRValue(length);\r
-\r
- return false;\r
- }\r
- case glslang::EOpEmitVertex:\r
- case glslang::EOpEndPrimitive:\r
- case glslang::EOpBarrier:\r
- case glslang::EOpMemoryBarrier:\r
- case glslang::EOpMemoryBarrierAtomicCounter:\r
- case glslang::EOpMemoryBarrierBuffer:\r
- case glslang::EOpMemoryBarrierImage:\r
- case glslang::EOpMemoryBarrierShared:\r
- case glslang::EOpGroupMemoryBarrier:\r
- noReturnValue = true;\r
- // These all have 0 operands and will naturally finish up in the code below for 0 operands\r
- break;\r
-\r
- default:\r
- break;\r
- }\r
-\r
- //\r
- // See if it maps to a regular operation.\r
- //\r
-\r
- if (binOp != glslang::EOpNull) {\r
- glslang::TIntermTyped* left = node->getSequence()[0]->getAsTyped();\r
- glslang::TIntermTyped* right = node->getSequence()[1]->getAsTyped();\r
- assert(left && right);\r
-\r
- builder.clearAccessChain();\r
- left->traverse(this);\r
- spv::Id leftId = builder.accessChainLoad(TranslatePrecisionDecoration(left->getType()));\r
-\r
- builder.clearAccessChain();\r
- right->traverse(this);\r
- spv::Id rightId = builder.accessChainLoad(TranslatePrecisionDecoration(right->getType()));\r
-\r
- result = createBinaryOperation(binOp, precision, \r
- convertGlslangToSpvType(node->getType()), leftId, rightId, \r
- left->getType().getBasicType(), reduceComparison);\r
-\r
- // code above should only make binOp that exists in createBinaryOperation\r
- if (result == 0)\r
- spv::MissingFunctionality("createBinaryOperation for aggregate");\r
-\r
- builder.clearAccessChain();\r
- builder.setAccessChainRValue(result);\r
-\r
- return false;\r
- }\r
-\r
- glslang::TIntermSequence& glslangOperands = node->getSequence();\r
- std::vector<spv::Id> operands;\r
- for (int arg = 0; arg < (int)glslangOperands.size(); ++arg) {\r
- builder.clearAccessChain();\r
- glslangOperands[arg]->traverse(this);\r
-\r
- // special case l-value operands; there are just a few\r
- bool lvalue = false;\r
- switch (node->getOp()) {\r
- //case glslang::EOpFrexp:\r
- case glslang::EOpModf:\r
- if (arg == 1)\r
- lvalue = true;\r
- break;\r
- //case glslang::EOpUAddCarry:\r
- //case glslang::EOpUSubBorrow:\r
- //case glslang::EOpUMulExtended:\r
- default:\r
- break;\r
- }\r
- if (lvalue)\r
- operands.push_back(builder.accessChainGetLValue());\r
- else\r
- operands.push_back(builder.accessChainLoad(TranslatePrecisionDecoration(glslangOperands[arg]->getAsTyped()->getType())));\r
- }\r
- switch (glslangOperands.size()) {\r
- case 0:\r
- result = createNoArgOperation(node->getOp());\r
- break;\r
- case 1:\r
- result = createUnaryOperation(node->getOp(), precision, convertGlslangToSpvType(node->getType()), operands.front(), node->getType().getBasicType() == glslang::EbtFloat || node->getType().getBasicType() == glslang::EbtDouble);\r
- break;\r
- default:\r
- result = createMiscOperation(node->getOp(), precision, convertGlslangToSpvType(node->getType()), operands);\r
- break;\r
- }\r
-\r
- if (noReturnValue)\r
- return false;\r
-\r
- if (! result) {\r
- spv::MissingFunctionality("glslang aggregate");\r
- return true;\r
- } else {\r
- builder.clearAccessChain();\r
- builder.setAccessChainRValue(result);\r
- return false;\r
- }\r
-}\r
-\r
-bool TGlslangToSpvTraverser::visitSelection(glslang::TVisit /* visit */, glslang::TIntermSelection* node)\r
-{\r
- // This path handles both if-then-else and ?:\r
- // The if-then-else has a node type of void, while\r
- // ?: has a non-void node type\r
- spv::Id result = 0;\r
- if (node->getBasicType() != glslang::EbtVoid) {\r
- // don't handle this as just on-the-fly temporaries, because there will be two names\r
- // and better to leave SSA to later passes\r
- result = builder.createVariable(spv::StorageClassFunction, convertGlslangToSpvType(node->getType()));\r
- }\r
-\r
- // emit the condition before doing anything with selection\r
- node->getCondition()->traverse(this);\r
-\r
- // make an "if" based on the value created by the condition\r
- spv::Builder::If ifBuilder(builder.accessChainLoad(spv::NoPrecision), builder);\r
-\r
- if (node->getTrueBlock()) {\r
- // emit the "then" statement\r
- node->getTrueBlock()->traverse(this);\r
- if (result)\r
- builder.createStore(builder.accessChainLoad(TranslatePrecisionDecoration(node->getTrueBlock()->getAsTyped()->getType())), result);\r
- }\r
-\r
- if (node->getFalseBlock()) {\r
- ifBuilder.makeBeginElse();\r
- // emit the "else" statement\r
- node->getFalseBlock()->traverse(this);\r
- if (result)\r
- builder.createStore(builder.accessChainLoad(TranslatePrecisionDecoration(node->getFalseBlock()->getAsTyped()->getType())), result);\r
- }\r
-\r
- ifBuilder.makeEndIf();\r
-\r
- if (result) {\r
- // GLSL only has r-values as the result of a :?, but\r
- // if we have an l-value, that can be more efficient if it will\r
- // become the base of a complex r-value expression, because the\r
- // next layer copies r-values into memory to use the access-chain mechanism\r
- builder.clearAccessChain();\r
- builder.setAccessChainLValue(result);\r
- }\r
-\r
- return false;\r
-}\r
-\r
-bool TGlslangToSpvTraverser::visitSwitch(glslang::TVisit /* visit */, glslang::TIntermSwitch* node)\r
-{\r
- // emit and get the condition before doing anything with switch\r
- node->getCondition()->traverse(this);\r
- spv::Id selector = builder.accessChainLoad(TranslatePrecisionDecoration(node->getCondition()->getAsTyped()->getType()));\r
-\r
- // browse the children to sort out code segments\r
- int defaultSegment = -1;\r
- std::vector<TIntermNode*> codeSegments;\r
- glslang::TIntermSequence& sequence = node->getBody()->getSequence();\r
- std::vector<int> caseValues;\r
- std::vector<int> valueIndexToSegment(sequence.size()); // note: probably not all are used, it is an overestimate\r
- for (glslang::TIntermSequence::iterator c = sequence.begin(); c != sequence.end(); ++c) {\r
- TIntermNode* child = *c;\r
- if (child->getAsBranchNode() && child->getAsBranchNode()->getFlowOp() == glslang::EOpDefault)\r
- defaultSegment = codeSegments.size();\r
- else if (child->getAsBranchNode() && child->getAsBranchNode()->getFlowOp() == glslang::EOpCase) {\r
- valueIndexToSegment[caseValues.size()] = codeSegments.size();\r
- caseValues.push_back(child->getAsBranchNode()->getExpression()->getAsConstantUnion()->getConstArray()[0].getIConst());\r
- } else\r
- codeSegments.push_back(child);\r
- }\r
-\r
- // handle the case where the last code segment is missing, due to no code \r
- // statements between the last case and the end of the switch statement\r
- if ((caseValues.size() && (int)codeSegments.size() == valueIndexToSegment[caseValues.size() - 1]) ||\r
- (int)codeSegments.size() == defaultSegment)\r
- codeSegments.push_back(nullptr);\r
-\r
- // make the switch statement\r
- std::vector<spv::Block*> segmentBlocks; // returned, as the blocks allocated in the call\r
- builder.makeSwitch(selector, codeSegments.size(), caseValues, valueIndexToSegment, defaultSegment, segmentBlocks);\r
-\r
- // emit all the code in the segments\r
- breakForLoop.push(false);\r
- for (unsigned int s = 0; s < codeSegments.size(); ++s) {\r
- builder.nextSwitchSegment(segmentBlocks, s);\r
- if (codeSegments[s])\r
- codeSegments[s]->traverse(this);\r
- else\r
- builder.addSwitchBreak();\r
- }\r
- breakForLoop.pop();\r
-\r
- builder.endSwitch(segmentBlocks);\r
-\r
- return false;\r
-}\r
-\r
-void TGlslangToSpvTraverser::visitConstantUnion(glslang::TIntermConstantUnion* node)\r
-{\r
- int nextConst = 0;\r
- spv::Id constant = createSpvConstant(node->getType(), node->getConstArray(), nextConst);\r
-\r
- builder.clearAccessChain();\r
- builder.setAccessChainRValue(constant);\r
-}\r
-\r
-bool TGlslangToSpvTraverser::visitLoop(glslang::TVisit /* visit */, glslang::TIntermLoop* node)\r
-{\r
- // body emission needs to know what the for-loop terminal is when it sees a "continue"\r
- loopTerminal.push(node->getTerminal());\r
-\r
- builder.makeNewLoop();\r
-\r
- bool bodyOut = false;\r
- if (! node->testFirst()) {\r
- builder.endLoopHeaderWithoutTest();\r
- if (node->getBody()) {\r
- breakForLoop.push(true);\r
- node->getBody()->traverse(this);\r
- breakForLoop.pop();\r
- }\r
- bodyOut = true;\r
- builder.createBranchToLoopTest();\r
- }\r
-\r
- if (node->getTest()) {\r
- node->getTest()->traverse(this);\r
- // the AST only contained the test computation, not the branch, we have to add it\r
- spv::Id condition = builder.accessChainLoad(TranslatePrecisionDecoration(node->getTest()->getType()));\r
- builder.createLoopTestBranch(condition);\r
- }\r
-\r
- if (! bodyOut && node->getBody()) {\r
- breakForLoop.push(true);\r
- node->getBody()->traverse(this);\r
- breakForLoop.pop();\r
- }\r
-\r
- if (loopTerminal.top())\r
- loopTerminal.top()->traverse(this);\r
-\r
- builder.closeLoop();\r
-\r
- loopTerminal.pop();\r
-\r
- return false;\r
-}\r
-\r
-bool TGlslangToSpvTraverser::visitBranch(glslang::TVisit /* visit */, glslang::TIntermBranch* node)\r
-{\r
- if (node->getExpression())\r
- node->getExpression()->traverse(this);\r
-\r
- switch (node->getFlowOp()) {\r
- case glslang::EOpKill:\r
- builder.makeDiscard();\r
- break;\r
- case glslang::EOpBreak:\r
- if (breakForLoop.top())\r
- builder.createLoopExit();\r
- else\r
- builder.addSwitchBreak();\r
- break;\r
- case glslang::EOpContinue:\r
- if (loopTerminal.top())\r
- loopTerminal.top()->traverse(this);\r
- builder.createLoopContinue();\r
- break;\r
- case glslang::EOpReturn:\r
- if (inMain)\r
- builder.makeMainReturn();\r
- else if (node->getExpression())\r
- builder.makeReturn(false, builder.accessChainLoad(TranslatePrecisionDecoration(node->getExpression()->getType())));\r
- else\r
- builder.makeReturn();\r
-\r
- builder.clearAccessChain();\r
- break;\r
-\r
- default:\r
- spv::MissingFunctionality("branch type");\r
- break;\r
- }\r
-\r
- return false;\r
-}\r
-\r
-spv::Id TGlslangToSpvTraverser::createSpvVariable(const glslang::TIntermSymbol* node)\r
-{\r
- // First, steer off constants, which are not SPIR-V variables, but \r
- // can still have a mapping to a SPIR-V Id.\r
- if (node->getQualifier().storage == glslang::EvqConst) {\r
- int nextConst = 0;\r
- return createSpvConstant(node->getType(), node->getConstArray(), nextConst);\r
- }\r
-\r
- // Now, handle actual variables\r
- spv::StorageClass storageClass = TranslateStorageClass(node->getType());\r
- spv::Id spvType = convertGlslangToSpvType(node->getType());\r
-\r
- const char* name = node->getName().c_str();\r
- if (glslang::IsAnonymous(name))\r
- name = "";\r
-\r
- return builder.createVariable(storageClass, spvType, name);\r
-}\r
-\r
-// Return type Id of the sampled type.\r
-spv::Id TGlslangToSpvTraverser::getSampledType(const glslang::TSampler& sampler)\r
-{\r
- switch (sampler.type) {\r
- case glslang::EbtFloat: return builder.makeFloatType(32);\r
- case glslang::EbtInt: return builder.makeIntType(32);\r
- case glslang::EbtUint: return builder.makeUintType(32);\r
- default:\r
- spv::MissingFunctionality("sampled type");\r
- return builder.makeFloatType(32);\r
- }\r
-}\r
-\r
-// Do full recursive conversion of an arbitrary glslang type to a SPIR-V Id.\r
-spv::Id TGlslangToSpvTraverser::convertGlslangToSpvType(const glslang::TType& type)\r
-{\r
- spv::Id spvType = 0;\r
-\r
- switch (type.getBasicType()) {\r
- case glslang::EbtVoid:\r
- spvType = builder.makeVoidType();\r
- if (type.isArray())\r
- spv::MissingFunctionality("array of void");\r
- break;\r
- case glslang::EbtFloat:\r
- spvType = builder.makeFloatType(32);\r
- break;\r
- case glslang::EbtDouble:\r
- spvType = builder.makeFloatType(64);\r
- break;\r
- case glslang::EbtBool:\r
- spvType = builder.makeBoolType();\r
- break;\r
- case glslang::EbtInt:\r
- spvType = builder.makeIntType(32);\r
- break;\r
- case glslang::EbtUint:\r
- spvType = builder.makeUintType(32);\r
- break;\r
- case glslang::EbtSampler:\r
- {\r
- const glslang::TSampler& sampler = type.getSampler();\r
- spvType = builder.makeSampler(getSampledType(sampler), TranslateDimensionality(sampler), \r
- sampler.image ? spv::Builder::samplerContentImage : spv::Builder::samplerContentTextureFilter,\r
- sampler.arrayed, sampler.shadow, sampler.ms);\r
- }\r
- break;\r
- case glslang::EbtStruct:\r
- case glslang::EbtBlock:\r
- {\r
- // If we've seen this struct type, return it\r
- const glslang::TTypeList* glslangStruct = type.getStruct();\r
- std::vector<spv::Id> structFields;\r
- spvType = structMap[glslangStruct];\r
- if (spvType)\r
- break;\r
-\r
- // else, we haven't seen it...\r
-\r
- // Create a vector of struct types for SPIR-V to consume\r
- int memberDelta = 0; // how much the member's index changes from glslang to SPIR-V, normally 0, except sometimes for blocks\r
- if (type.getBasicType() == glslang::EbtBlock)\r
- memberRemapper[glslangStruct].resize(glslangStruct->size());\r
- for (int i = 0; i < (int)glslangStruct->size(); i++) {\r
- glslang::TType& glslangType = *(*glslangStruct)[i].type;\r
- if (glslangType.hiddenMember()) {\r
- ++memberDelta;\r
- if (type.getBasicType() == glslang::EbtBlock)\r
- memberRemapper[glslangStruct][i] = -1;\r
- } else {\r
- if (type.getBasicType() == glslang::EbtBlock)\r
- memberRemapper[glslangStruct][i] = i - memberDelta;\r
- structFields.push_back(convertGlslangToSpvType(glslangType));\r
- }\r
- }\r
-\r
- // Make the SPIR-V type\r
- spvType = builder.makeStructType(structFields, type.getTypeName().c_str());\r
- structMap[glslangStruct] = spvType;\r
-\r
- // Name and decorate the non-hidden members\r
- for (int i = 0; i < (int)glslangStruct->size(); i++) {\r
- glslang::TType& glslangType = *(*glslangStruct)[i].type;\r
- int member = i;\r
- if (type.getBasicType() == glslang::EbtBlock)\r
- member = memberRemapper[glslangStruct][i];\r
- // using -1 above to indicate a hidden member\r
- if (member >= 0) {\r
- builder.addMemberName(spvType, member, glslangType.getFieldName().c_str());\r
- addMemberDecoration(spvType, member, TranslateLayoutDecoration(glslangType));\r
- addMemberDecoration(spvType, member, TranslatePrecisionDecoration(glslangType));\r
- addMemberDecoration(spvType, member, TranslateInterpolationDecoration(glslangType));\r
- addMemberDecoration(spvType, member, TranslateInvariantDecoration(glslangType));\r
- if (glslangType.getQualifier().hasLocation())\r
- builder.addMemberDecoration(spvType, member, spv::DecorationLocation, glslangType.getQualifier().layoutLocation);\r
- if (glslangType.getQualifier().hasComponent())\r
- builder.addMemberDecoration(spvType, member, spv::DecorationComponent, glslangType.getQualifier().layoutComponent);\r
- if (glslangType.getQualifier().hasXfbOffset())\r
- builder.addMemberDecoration(spvType, member, spv::DecorationOffset, glslangType.getQualifier().layoutXfbOffset);\r
-\r
- // built-in variable decorations\r
- int builtIn = TranslateBuiltInDecoration(glslangType.getQualifier().builtIn);\r
- if (builtIn != spv::BadValue)\r
- builder.addMemberDecoration(spvType, member, spv::DecorationBuiltIn, builtIn);\r
- }\r
- }\r
-\r
- // Decorate the structure\r
- addDecoration(spvType, TranslateLayoutDecoration(type));\r
- addDecoration(spvType, TranslateBlockDecoration(type));\r
- if (type.getQualifier().hasStream())\r
- builder.addDecoration(spvType, spv::DecorationStream, type.getQualifier().layoutStream);\r
- if (glslangIntermediate->getXfbMode()) {\r
- if (type.getQualifier().hasXfbStride())\r
- builder.addDecoration(spvType, spv::DecorationStride, type.getQualifier().layoutXfbStride);\r
- if (type.getQualifier().hasXfbBuffer())\r
- builder.addDecoration(spvType, spv::DecorationXfbBuffer, type.getQualifier().layoutXfbBuffer);\r
- }\r
- }\r
- break;\r
- default:\r
- spv::MissingFunctionality("basic type");\r
- break;\r
- }\r
-\r
- if (type.isMatrix())\r
- spvType = builder.makeMatrixType(spvType, type.getMatrixCols(), type.getMatrixRows());\r
- else {\r
- // If this variable has a vector element count greater than 1, create a SPIR-V vector\r
- if (type.getVectorSize() > 1)\r
- spvType = builder.makeVectorType(spvType, type.getVectorSize());\r
- }\r
-\r
- if (type.isArray()) {\r
- unsigned arraySize;\r
- if (! type.isExplicitlySizedArray()) {\r
- spv::MissingFunctionality("Unsized array");\r
- arraySize = 8;\r
- } else\r
- arraySize = type.getArraySize();\r
- spvType = builder.makeArrayType(spvType, arraySize);\r
- }\r
-\r
- return spvType;\r
-}\r
-\r
-bool TGlslangToSpvTraverser::isShaderEntrypoint(const glslang::TIntermAggregate* node)\r
-{\r
- return node->getName() == "main(";\r
-}\r
-\r
-// Make all the functions, skeletally, without actually visiting their bodies.\r
-void TGlslangToSpvTraverser::makeFunctions(const glslang::TIntermSequence& glslFunctions)\r
-{\r
- for (int f = 0; f < (int)glslFunctions.size(); ++f) {\r
- glslang::TIntermAggregate* glslFunction = glslFunctions[f]->getAsAggregate();\r
- if (! glslFunction || glslFunction->getOp() != glslang::EOpFunction || isShaderEntrypoint(glslFunction))\r
- continue;\r
-\r
- // We're on a user function. Set up the basic interface for the function now,\r
- // so that it's available to call.\r
- // Translating the body will happen later.\r
- //\r
- // Typically (except for a "const in" parameter), an address will be passed to the \r
- // function. What it is an address of varies:\r
- //\r
- // - "in" parameters not marked as "const" can be written to without modifying the argument,\r
- // so that write needs to be to a copy, hence the address of a copy works.\r
- //\r
- // - "const in" parameters can just be the r-value, as no writes need occur.\r
- //\r
- // - "out" and "inout" arguments can't be done as direct pointers, because GLSL has\r
- // copy-in/copy-out semantics. They can be handled though with a pointer to a copy.\r
-\r
- std::vector<spv::Id> paramTypes;\r
- glslang::TIntermSequence& parameters = glslFunction->getSequence()[0]->getAsAggregate()->getSequence();\r
-\r
- for (int p = 0; p < (int)parameters.size(); ++p) {\r
- const glslang::TType& paramType = parameters[p]->getAsTyped()->getType();\r
- spv::Id typeId = convertGlslangToSpvType(paramType);\r
- if (paramType.getQualifier().storage != glslang::EvqConstReadOnly)\r
- typeId = builder.makePointer(spv::StorageClassFunction, typeId);\r
- else\r
- constReadOnlyParameters.insert(parameters[p]->getAsSymbolNode()->getId());\r
- paramTypes.push_back(typeId);\r
- }\r
-\r
- spv::Block* functionBlock;\r
- spv::Function *function = builder.makeFunctionEntry(convertGlslangToSpvType(glslFunction->getType()), glslFunction->getName().c_str(),\r
- paramTypes, &functionBlock);\r
-\r
- // Track function to emit/call later\r
- functionMap[glslFunction->getName().c_str()] = function;\r
-\r
- // Set the parameter id's\r
- for (int p = 0; p < (int)parameters.size(); ++p) {\r
- symbolValues[parameters[p]->getAsSymbolNode()->getId()] = function->getParamId(p);\r
- // give a name too\r
- builder.addName(function->getParamId(p), parameters[p]->getAsSymbolNode()->getName().c_str());\r
- }\r
- }\r
-}\r
-\r
-// Process all the initializers, while skipping the functions and link objects\r
-void TGlslangToSpvTraverser::makeGlobalInitializers(const glslang::TIntermSequence& initializers)\r
-{\r
- builder.setBuildPoint(shaderEntry->getLastBlock());\r
- for (int i = 0; i < (int)initializers.size(); ++i) {\r
- glslang::TIntermAggregate* initializer = initializers[i]->getAsAggregate();\r
- if (initializer && initializer->getOp() != glslang::EOpFunction && initializer->getOp() != glslang::EOpLinkerObjects) {\r
-\r
- // We're on a top-level node that's not a function. Treat as an initializer, whose\r
- // code goes into the beginning of main.\r
- initializer->traverse(this);\r
- }\r
- }\r
-}\r
-\r
-// Process all the functions, while skipping initializers.\r
-void TGlslangToSpvTraverser::visitFunctions(const glslang::TIntermSequence& glslFunctions)\r
-{\r
- for (int f = 0; f < (int)glslFunctions.size(); ++f) {\r
- glslang::TIntermAggregate* node = glslFunctions[f]->getAsAggregate();\r
- if (node && (node->getOp() == glslang::EOpFunction || node->getOp() == glslang ::EOpLinkerObjects))\r
- node->traverse(this);\r
- }\r
-}\r
-\r
-void TGlslangToSpvTraverser::handleFunctionEntry(const glslang::TIntermAggregate* node)\r
-{\r
- // SPIR-V functions should already be in the functionMap from the prepass \r
- // that called makeFunctions().\r
- spv::Function* function = functionMap[node->getName().c_str()];\r
- spv::Block* functionBlock = function->getEntryBlock();\r
- builder.setBuildPoint(functionBlock);\r
-}\r
-\r
-void TGlslangToSpvTraverser::translateArguments(const glslang::TIntermSequence& glslangArguments, std::vector<spv::Id>& arguments)\r
-{\r
- for (int i = 0; i < (int)glslangArguments.size(); ++i) {\r
- builder.clearAccessChain();\r
- glslangArguments[i]->traverse(this);\r
- arguments.push_back(builder.accessChainLoad(TranslatePrecisionDecoration(glslangArguments[i]->getAsTyped()->getType())));\r
- }\r
-}\r
-\r
-spv::Id TGlslangToSpvTraverser::handleBuiltInFunctionCall(const glslang::TIntermAggregate* node)\r
-{\r
- std::vector<spv::Id> arguments;\r
- translateArguments(node->getSequence(), arguments);\r
-\r
- std::vector<spv::Id> argTypes;\r
- for (int a = 0; a < (int)arguments.size(); ++a)\r
- argTypes.push_back(builder.getTypeId(arguments[a]));\r
-\r
- spv::Decoration precision = TranslatePrecisionDecoration(node->getType());\r
-\r
- if (node->getName() == "ftransform(") {\r
- spv::MissingFunctionality("ftransform()");\r
- //spv::Id vertex = builder.createVariable(spv::StorageShaderGlobal, spv::VectorType::get(spv::makeFloatType(), 4),\r
- // "gl_Vertex_sim");\r
- //spv::Id matrix = builder.createVariable(spv::StorageShaderGlobal, spv::VectorType::get(spv::makeFloatType(), 4),\r
- // "gl_ModelViewProjectionMatrix_sim");\r
- return 0;\r
- }\r
-\r
- if (node->getName().substr(0, 7) == "texture" || node->getName().substr(0, 5) == "texel" || node->getName().substr(0, 6) == "shadow") {\r
- const glslang::TSampler sampler = node->getSequence()[0]->getAsTyped()->getType().getSampler();\r
- spv::Builder::TextureParameters params = { };\r
- params.sampler = arguments[0];\r
-\r
- // special case size query\r
- if (node->getName().find("textureSize", 0) != std::string::npos) {\r
- if (arguments.size() > 1) {\r
- params.lod = arguments[1];\r
- return builder.createTextureQueryCall(spv::OpTextureQuerySizeLod, params);\r
- } else\r
- return builder.createTextureQueryCall(spv::OpTextureQuerySize, params);\r
- }\r
-\r
- // special case the number of samples query\r
- if (node->getName().find("textureSamples", 0) != std::string::npos)\r
- return builder.createTextureQueryCall(spv::OpTextureQuerySamples, params);\r
-\r
- // special case the other queries\r
- if (node->getName().find("Query", 0) != std::string::npos) {\r
- if (node->getName().find("Levels", 0) != std::string::npos)\r
- return builder.createTextureQueryCall(spv::OpTextureQueryLevels, params);\r
- else if (node->getName().find("Lod", 0) != std::string::npos) {\r
- params.coords = arguments[1];\r
- return builder.createTextureQueryCall(spv::OpTextureQueryLod, params);\r
- } else\r
- spv::MissingFunctionality("glslang texture query");\r
- }\r
-\r
- // This is no longer a query....\r
-\r
- bool lod = node->getName().find("Lod", 0) != std::string::npos;\r
- bool proj = node->getName().find("Proj", 0) != std::string::npos;\r
- bool offsets = node->getName().find("Offsets", 0) != std::string::npos;\r
- bool offset = ! offsets && node->getName().find("Offset", 0) != std::string::npos;\r
- bool fetch = node->getName().find("Fetch", 0) != std::string::npos;\r
- bool gather = node->getName().find("Gather", 0) != std::string::npos;\r
- bool grad = node->getName().find("Grad", 0) != std::string::npos;\r
-\r
- if (fetch)\r
- spv::MissingFunctionality("texel fetch");\r
- if (gather)\r
- spv::MissingFunctionality("texture gather");\r
-\r
- // check for bias argument\r
- bool bias = false;\r
- if (! lod && ! gather && ! grad && ! fetch) {\r
- int nonBiasArgCount = 2;\r
- if (offset)\r
- ++nonBiasArgCount;\r
- if (grad)\r
- nonBiasArgCount += 2;\r
-\r
- if ((int)arguments.size() > nonBiasArgCount)\r
- bias = true;\r
- }\r
-\r
- bool cubeCompare = sampler.dim == glslang::EsdCube && sampler.arrayed && sampler.shadow;\r
-\r
- // set the rest of the arguments\r
- params.coords = arguments[1];\r
- int extraArgs = 0;\r
- if (cubeCompare)\r
- params.Dref = arguments[2];\r
- if (lod) {\r
- params.lod = arguments[2];\r
- ++extraArgs;\r
- }\r
- if (grad) {\r
- params.gradX = arguments[2 + extraArgs];\r
- params.gradY = arguments[3 + extraArgs];\r
- extraArgs += 2;\r
- }\r
- //if (gather && compare) {\r
- // params.compare = arguments[2 + extraArgs];\r
- // ++extraArgs;\r
- //}\r
- if (offset | offsets) {\r
- params.offset = arguments[2 + extraArgs];\r
- ++extraArgs;\r
- }\r
- if (bias) {\r
- params.bias = arguments[2 + extraArgs];\r
- ++extraArgs;\r
- }\r
-\r
- return builder.createTextureCall(precision, convertGlslangToSpvType(node->getType()), proj, params);\r
- }\r
-\r
- spv::MissingFunctionality("built-in function call");\r
-\r
- return 0;\r
-}\r
-\r
-spv::Id TGlslangToSpvTraverser::handleUserFunctionCall(const glslang::TIntermAggregate* node)\r
-{\r
- // Grab the function's pointer from the previously created function\r
- spv::Function* function = functionMap[node->getName().c_str()];\r
- if (! function)\r
- return 0;\r
-\r
- const glslang::TIntermSequence& glslangArgs = node->getSequence();\r
- const glslang::TQualifierList& qualifiers = node->getQualifierList();\r
-\r
- // See comments in makeFunctions() for details about the semantics for parameter passing.\r
- //\r
- // These imply we need a four step process:\r
- // 1. Evaluate the arguments\r
- // 2. Allocate and make copies of in, out, and inout arguments\r
- // 3. Make the call\r
- // 4. Copy back the results\r
-\r
- // 1. Evaluate the arguments\r
- std::vector<spv::Builder::AccessChain> lValues;\r
- std::vector<spv::Id> rValues;\r
- for (int a = 0; a < (int)glslangArgs.size(); ++a) {\r
- // build l-value\r
- builder.clearAccessChain();\r
- glslangArgs[a]->traverse(this);\r
- // keep outputs as l-values, evaluate input-only as r-values\r
- if (qualifiers[a] != glslang::EvqConstReadOnly) {\r
- // save l-value\r
- lValues.push_back(builder.getAccessChain());\r
- } else {\r
- // process r-value\r
- rValues.push_back(builder.accessChainLoad(TranslatePrecisionDecoration(glslangArgs[a]->getAsTyped()->getType())));\r
- }\r
- }\r
-\r
- // 2. Allocate space for anything needing a copy, and if it's "in" or "inout"\r
- // copy the original into that space.\r
- //\r
- // Also, build up the list of actual arguments to pass in for the call\r
- int lValueCount = 0;\r
- int rValueCount = 0;\r
- std::vector<spv::Id> spvArgs;\r
- for (int a = 0; a < (int)glslangArgs.size(); ++a) {\r
- spv::Id arg;\r
- if (qualifiers[a] != glslang::EvqConstReadOnly) {\r
- // need space to hold the copy\r
- const glslang::TType& paramType = glslangArgs[a]->getAsTyped()->getType();\r
- arg = builder.createVariable(spv::StorageClassFunction, convertGlslangToSpvType(paramType), "param");\r
- if (qualifiers[a] == glslang::EvqIn || qualifiers[a] == glslang::EvqInOut) {\r
- // need to copy the input into output space\r
- builder.setAccessChain(lValues[lValueCount]);\r
- spv::Id copy = builder.accessChainLoad(spv::NoPrecision); // TODO: get precision\r
- builder.createStore(copy, arg);\r
- }\r
- ++lValueCount;\r
- } else {\r
- arg = rValues[rValueCount];\r
- ++rValueCount;\r
- }\r
- spvArgs.push_back(arg);\r
- }\r
-\r
- // 3. Make the call.\r
- spv::Id result = builder.createFunctionCall(function, spvArgs);\r
-\r
- // 4. Copy back out an "out" arguments.\r
- lValueCount = 0;\r
- for (int a = 0; a < (int)glslangArgs.size(); ++a) {\r
- if (qualifiers[a] != glslang::EvqConstReadOnly) {\r
- if (qualifiers[a] == glslang::EvqOut || qualifiers[a] == glslang::EvqInOut) {\r
- spv::Id copy = builder.createLoad(spvArgs[a]);\r
- builder.setAccessChain(lValues[lValueCount]);\r
- builder.accessChainStore(copy);\r
- }\r
- ++lValueCount;\r
- }\r
- }\r
-\r
- return result;\r
-}\r
-\r
-// Translate AST operation to SPV operation, already having SPV-based operands/types.\r
-spv::Id TGlslangToSpvTraverser::createBinaryOperation(glslang::TOperator op, spv::Decoration precision, \r
- spv::Id typeId, spv::Id left, spv::Id right,\r
- glslang::TBasicType typeProxy, bool reduceComparison)\r
-{\r
- bool isUnsigned = typeProxy == glslang::EbtUint;\r
- bool isFloat = typeProxy == glslang::EbtFloat || typeProxy == glslang::EbtDouble;\r
-\r
- spv::Op binOp = spv::OpNop;\r
- bool needsPromotion = true;\r
- bool comparison = false;\r
-\r
- switch (op) {\r
- case glslang::EOpAdd:\r
- case glslang::EOpAddAssign:\r
- if (isFloat)\r
- binOp = spv::OpFAdd;\r
- else\r
- binOp = spv::OpIAdd;\r
- break;\r
- case glslang::EOpSub:\r
- case glslang::EOpSubAssign:\r
- if (isFloat)\r
- binOp = spv::OpFSub;\r
- else\r
- binOp = spv::OpISub;\r
- break;\r
- case glslang::EOpMul:\r
- case glslang::EOpMulAssign:\r
- if (isFloat)\r
- binOp = spv::OpFMul;\r
- else\r
- binOp = spv::OpIMul;\r
- break;\r
- case glslang::EOpVectorTimesScalar:\r
- case glslang::EOpVectorTimesScalarAssign:\r
- if (builder.isVector(right))\r
- std::swap(left, right);\r
- assert(builder.isScalar(right));\r
- binOp = spv::OpVectorTimesScalar;\r
- needsPromotion = false;\r
- break;\r
- case glslang::EOpVectorTimesMatrix:\r
- case glslang::EOpVectorTimesMatrixAssign:\r
- assert(builder.isVector(left));\r
- assert(builder.isMatrix(right));\r
- binOp = spv::OpVectorTimesMatrix;\r
- break;\r
- case glslang::EOpMatrixTimesVector:\r
- assert(builder.isMatrix(left));\r
- assert(builder.isVector(right));\r
- binOp = spv::OpMatrixTimesVector;\r
- break;\r
- case glslang::EOpMatrixTimesScalar:\r
- case glslang::EOpMatrixTimesScalarAssign:\r
- if (builder.isMatrix(right))\r
- std::swap(left, right);\r
- assert(builder.isScalar(right));\r
- binOp = spv::OpMatrixTimesScalar;\r
- break;\r
- case glslang::EOpMatrixTimesMatrix:\r
- case glslang::EOpMatrixTimesMatrixAssign:\r
- assert(builder.isMatrix(left));\r
- assert(builder.isMatrix(right));\r
- binOp = spv::OpMatrixTimesMatrix;\r
- break;\r
- case glslang::EOpOuterProduct:\r
- binOp = spv::OpOuterProduct;\r
- needsPromotion = false;\r
- break;\r
-\r
- case glslang::EOpDiv:\r
- case glslang::EOpDivAssign:\r
- if (isFloat)\r
- binOp = spv::OpFDiv;\r
- else if (isUnsigned)\r
- binOp = spv::OpUDiv;\r
- else\r
- binOp = spv::OpSDiv;\r
- break;\r
- case glslang::EOpMod:\r
- case glslang::EOpModAssign:\r
- if (isFloat)\r
- binOp = spv::OpFMod;\r
- else if (isUnsigned)\r
- binOp = spv::OpUMod;\r
- else\r
- binOp = spv::OpSMod;\r
- break;\r
- case glslang::EOpRightShift:\r
- case glslang::EOpRightShiftAssign:\r
- if (isUnsigned)\r
- binOp = spv::OpShiftRightLogical;\r
- else\r
- binOp = spv::OpShiftRightArithmetic;\r
- break;\r
- case glslang::EOpLeftShift:\r
- case glslang::EOpLeftShiftAssign:\r
- binOp = spv::OpShiftLeftLogical;\r
- break;\r
- case glslang::EOpAnd:\r
- case glslang::EOpAndAssign:\r
- binOp = spv::OpBitwiseAnd;\r
- break;\r
- case glslang::EOpLogicalAnd:\r
- needsPromotion = false;\r
- binOp = spv::OpLogicalAnd;\r
- break;\r
- case glslang::EOpInclusiveOr:\r
- case glslang::EOpInclusiveOrAssign:\r
- binOp = spv::OpBitwiseOr;\r
- break;\r
- case glslang::EOpLogicalOr:\r
- needsPromotion = false;\r
- binOp = spv::OpLogicalOr;\r
- break;\r
- case glslang::EOpExclusiveOr:\r
- case glslang::EOpExclusiveOrAssign:\r
- binOp = spv::OpBitwiseXor;\r
- break;\r
- case glslang::EOpLogicalXor:\r
- needsPromotion = false;\r
- binOp = spv::OpLogicalXor;\r
- break;\r
-\r
- case glslang::EOpLessThan:\r
- case glslang::EOpGreaterThan:\r
- case glslang::EOpLessThanEqual:\r
- case glslang::EOpGreaterThanEqual:\r
- case glslang::EOpEqual:\r
- case glslang::EOpNotEqual:\r
- case glslang::EOpVectorEqual:\r
- case glslang::EOpVectorNotEqual:\r
- comparison = true;\r
- break;\r
- default:\r
- break;\r
- }\r
-\r
- if (binOp != spv::OpNop) {\r
- if (builder.isMatrix(left) || builder.isMatrix(right)) {\r
- switch (binOp) {\r
- case spv::OpMatrixTimesScalar:\r
- case spv::OpVectorTimesMatrix:\r
- case spv::OpMatrixTimesVector:\r
- case spv::OpMatrixTimesMatrix:\r
- break;\r
- case spv::OpFDiv:\r
- // turn it into a multiply...\r
- assert(builder.isMatrix(left) && builder.isScalar(right));\r
- right = builder.createBinOp(spv::OpFDiv, builder.getTypeId(right), builder.makeFloatConstant(1.0F), right);\r
- binOp = spv::OpFMul;\r
- break;\r
- default:\r
- spv::MissingFunctionality("binary operation on matrix");\r
- break;\r
- }\r
-\r
- spv::Id id = builder.createBinOp(binOp, typeId, left, right);\r
- builder.setPrecision(id, precision);\r
-\r
- return id;\r
- }\r
-\r
- // No matrix involved; make both operands be the same number of components, if needed\r
- if (needsPromotion)\r
- builder.promoteScalar(precision, left, right);\r
-\r
- spv::Id id = builder.createBinOp(binOp, typeId, left, right);\r
- builder.setPrecision(id, precision);\r
-\r
- return id;\r
- }\r
-\r
- if (! comparison)\r
- return 0;\r
-\r
- // Comparison instructions\r
-\r
- if (reduceComparison && (builder.isVector(left) || builder.isMatrix(left) || builder.isAggregate(left))) {\r
- assert(op == glslang::EOpEqual || op == glslang::EOpNotEqual);\r
-\r
- return builder.createCompare(precision, left, right, op == glslang::EOpEqual);\r
- }\r
-\r
- switch (op) {\r
- case glslang::EOpLessThan:\r
- if (isFloat)\r
- binOp = spv::OpFOrdLessThan;\r
- else if (isUnsigned)\r
- binOp = spv::OpULessThan;\r
- else\r
- binOp = spv::OpSLessThan;\r
- break;\r
- case glslang::EOpGreaterThan:\r
- if (isFloat)\r
- binOp = spv::OpFOrdGreaterThan;\r
- else if (isUnsigned)\r
- binOp = spv::OpUGreaterThan;\r
- else\r
- binOp = spv::OpSGreaterThan;\r
- break;\r
- case glslang::EOpLessThanEqual:\r
- if (isFloat)\r
- binOp = spv::OpFOrdLessThanEqual;\r
- else if (isUnsigned)\r
- binOp = spv::OpULessThanEqual;\r
- else\r
- binOp = spv::OpSLessThanEqual;\r
- break;\r
- case glslang::EOpGreaterThanEqual:\r
- if (isFloat)\r
- binOp = spv::OpFOrdGreaterThanEqual;\r
- else if (isUnsigned)\r
- binOp = spv::OpUGreaterThanEqual;\r
- else\r
- binOp = spv::OpSGreaterThanEqual;\r
- break;\r
- case glslang::EOpEqual:\r
- case glslang::EOpVectorEqual:\r
- if (isFloat)\r
- binOp = spv::OpFOrdEqual;\r
- else\r
- binOp = spv::OpIEqual;\r
- break;\r
- case glslang::EOpNotEqual:\r
- case glslang::EOpVectorNotEqual:\r
- if (isFloat)\r
- binOp = spv::OpFOrdNotEqual;\r
- else\r
- binOp = spv::OpINotEqual;\r
- break;\r
- default:\r
- break;\r
- }\r
-\r
- if (binOp != spv::OpNop) {\r
- spv::Id id = builder.createBinOp(binOp, typeId, left, right);\r
- builder.setPrecision(id, precision);\r
-\r
- return id;\r
- }\r
-\r
- return 0;\r
-}\r
-\r
-spv::Id TGlslangToSpvTraverser::createUnaryOperation(glslang::TOperator op, spv::Decoration precision, spv::Id typeId, spv::Id operand, bool isFloat)\r
-{\r
- spv::Op unaryOp = spv::OpNop;\r
- int libCall = -1;\r
-\r
- switch (op) {\r
- case glslang::EOpNegative:\r
- if (isFloat)\r
- unaryOp = spv::OpFNegate;\r
- else\r
- unaryOp = spv::OpSNegate;\r
- break;\r
-\r
- case glslang::EOpLogicalNot:\r
- case glslang::EOpVectorLogicalNot:\r
- case glslang::EOpBitwiseNot:\r
- unaryOp = spv::OpNot;\r
- break;\r
- \r
- case glslang::EOpDeterminant:\r
- libCall = GLSL_STD_450::Determinant;\r
- break;\r
- case glslang::EOpMatrixInverse:\r
- libCall = GLSL_STD_450::MatrixInverse;\r
- break;\r
- case glslang::EOpTranspose:\r
- unaryOp = spv::OpTranspose;\r
- break;\r
-\r
- case glslang::EOpRadians:\r
- libCall = GLSL_STD_450::Radians;\r
- break;\r
- case glslang::EOpDegrees:\r
- libCall = GLSL_STD_450::Degrees;\r
- break;\r
- case glslang::EOpSin:\r
- libCall = GLSL_STD_450::Sin;\r
- break;\r
- case glslang::EOpCos:\r
- libCall = GLSL_STD_450::Cos;\r
- break;\r
- case glslang::EOpTan:\r
- libCall = GLSL_STD_450::Tan;\r
- break;\r
- case glslang::EOpAcos:\r
- libCall = GLSL_STD_450::Acos;\r
- break;\r
- case glslang::EOpAsin:\r
- libCall = GLSL_STD_450::Asin;\r
- break;\r
- case glslang::EOpAtan:\r
- libCall = GLSL_STD_450::Atan;\r
- break;\r
-\r
- case glslang::EOpAcosh:\r
- libCall = GLSL_STD_450::Acosh;\r
- break;\r
- case glslang::EOpAsinh:\r
- libCall = GLSL_STD_450::Asinh;\r
- break;\r
- case glslang::EOpAtanh:\r
- libCall = GLSL_STD_450::Atanh;\r
- break;\r
- case glslang::EOpTanh:\r
- libCall = GLSL_STD_450::Tanh;\r
- break;\r
- case glslang::EOpCosh:\r
- libCall = GLSL_STD_450::Cosh;\r
- break;\r
- case glslang::EOpSinh:\r
- libCall = GLSL_STD_450::Sinh;\r
- break;\r
-\r
- case glslang::EOpLength:\r
- libCall = GLSL_STD_450::Length;\r
- break;\r
- case glslang::EOpNormalize:\r
- libCall = GLSL_STD_450::Normalize;\r
- break;\r
-\r
- case glslang::EOpExp:\r
- libCall = GLSL_STD_450::Exp;\r
- break;\r
- case glslang::EOpLog:\r
- libCall = GLSL_STD_450::Log;\r
- break;\r
- case glslang::EOpExp2:\r
- libCall = GLSL_STD_450::Exp2;\r
- break;\r
- case glslang::EOpLog2:\r
- libCall = GLSL_STD_450::Log2;\r
- break;\r
- case glslang::EOpSqrt:\r
- libCall = GLSL_STD_450::Sqrt;\r
- break;\r
- case glslang::EOpInverseSqrt:\r
- libCall = GLSL_STD_450::InverseSqrt;\r
- break;\r
-\r
- case glslang::EOpFloor:\r
- libCall = GLSL_STD_450::Floor;\r
- break;\r
- case glslang::EOpTrunc:\r
- libCall = GLSL_STD_450::Trunc;\r
- break;\r
- case glslang::EOpRound:\r
- libCall = GLSL_STD_450::Round;\r
- break;\r
- case glslang::EOpRoundEven:\r
- libCall = GLSL_STD_450::RoundEven;\r
- break;\r
- case glslang::EOpCeil:\r
- libCall = GLSL_STD_450::Ceil;\r
- break;\r
- case glslang::EOpFract:\r
- libCall = GLSL_STD_450::Fract;\r
- break;\r
-\r
- case glslang::EOpIsNan:\r
- unaryOp = spv::OpIsNan;\r
- break;\r
- case glslang::EOpIsInf:\r
- unaryOp = spv::OpIsInf;\r
- break;\r
-\r
- case glslang::EOpFloatBitsToInt:\r
- libCall = GLSL_STD_450::FloatBitsToInt;\r
- break;\r
- case glslang::EOpFloatBitsToUint:\r
- libCall = GLSL_STD_450::FloatBitsToUint;\r
- break;\r
- case glslang::EOpIntBitsToFloat:\r
- libCall = GLSL_STD_450::IntBitsToFloat;\r
- break;\r
- case glslang::EOpUintBitsToFloat:\r
- libCall = GLSL_STD_450::UintBitsToFloat;\r
- break;\r
- case glslang::EOpPackSnorm2x16:\r
- libCall = GLSL_STD_450::PackSnorm2x16;\r
- break;\r
- case glslang::EOpUnpackSnorm2x16:\r
- libCall = GLSL_STD_450::UnpackSnorm2x16;\r
- break;\r
- case glslang::EOpPackUnorm2x16:\r
- libCall = GLSL_STD_450::PackUnorm2x16;\r
- break;\r
- case glslang::EOpUnpackUnorm2x16:\r
- libCall = GLSL_STD_450::UnpackUnorm2x16;\r
- break;\r
- case glslang::EOpPackHalf2x16:\r
- libCall = GLSL_STD_450::PackHalf2x16;\r
- break;\r
- case glslang::EOpUnpackHalf2x16:\r
- libCall = GLSL_STD_450::UnpackHalf2x16;\r
- break;\r
-\r
- case glslang::EOpDPdx:\r
- unaryOp = spv::OpDPdx;\r
- break;\r
- case glslang::EOpDPdy:\r
- unaryOp = spv::OpDPdy;\r
- break;\r
- case glslang::EOpFwidth:\r
- unaryOp = spv::OpFwidth;\r
- break;\r
- case glslang::EOpDPdxFine:\r
- unaryOp = spv::OpDPdxFine;\r
- break;\r
- case glslang::EOpDPdyFine:\r
- unaryOp = spv::OpDPdyFine;\r
- break;\r
- case glslang::EOpFwidthFine:\r
- unaryOp = spv::OpFwidthFine;\r
- break;\r
- case glslang::EOpDPdxCoarse:\r
- unaryOp = spv::OpDPdxCoarse;\r
- break;\r
- case glslang::EOpDPdyCoarse:\r
- unaryOp = spv::OpDPdyCoarse;\r
- break;\r
- case glslang::EOpFwidthCoarse:\r
- unaryOp = spv::OpFwidthCoarse;\r
- break;\r
-\r
- case glslang::EOpAny:\r
- unaryOp = spv::OpAny;\r
- break;\r
- case glslang::EOpAll:\r
- unaryOp = spv::OpAll;\r
- break;\r
-\r
- case glslang::EOpAbs:\r
- libCall = GLSL_STD_450::Abs;\r
- break;\r
- case glslang::EOpSign:\r
- libCall = GLSL_STD_450::Sign;\r
- break;\r
-\r
- default:\r
- return 0;\r
- }\r
-\r
- spv::Id id;\r
- if (libCall >= 0) {\r
- std::vector<spv::Id> args;\r
- args.push_back(operand);\r
- id = builder.createBuiltinCall(precision, typeId, stdBuiltins, libCall, args);\r
- } else\r
- id = builder.createUnaryOp(unaryOp, typeId, operand);\r
-\r
- builder.setPrecision(id, precision);\r
-\r
- return id;\r
-}\r
-\r
-spv::Id TGlslangToSpvTraverser::createConversion(glslang::TOperator op, spv::Decoration precision, spv::Id destType, spv::Id operand)\r
-{\r
- spv::Op convOp = spv::OpNop;\r
- spv::Id zero = 0;\r
- spv::Id one = 0;\r
-\r
- int vectorSize = builder.isVectorType(destType) ? builder.getNumTypeComponents(destType) : 0;\r
-\r
- switch (op) {\r
- case glslang::EOpConvIntToBool:\r
- case glslang::EOpConvUintToBool:\r
- zero = builder.makeUintConstant(0);\r
- zero = makeSmearedConstant(zero, vectorSize);\r
- return builder.createBinOp(spv::OpINotEqual, destType, operand, zero);\r
-\r
- case glslang::EOpConvFloatToBool:\r
- zero = builder.makeFloatConstant(0.0F);\r
- zero = makeSmearedConstant(zero, vectorSize);\r
- return builder.createBinOp(spv::OpFOrdNotEqual, destType, operand, zero);\r
-\r
- case glslang::EOpConvDoubleToBool:\r
- zero = builder.makeDoubleConstant(0.0);\r
- zero = makeSmearedConstant(zero, vectorSize);\r
- return builder.createBinOp(spv::OpFOrdNotEqual, destType, operand, zero);\r
-\r
- case glslang::EOpConvBoolToFloat:\r
- convOp = spv::OpSelect;\r
- zero = builder.makeFloatConstant(0.0);\r
- one = builder.makeFloatConstant(1.0);\r
- break;\r
- case glslang::EOpConvBoolToDouble:\r
- convOp = spv::OpSelect;\r
- zero = builder.makeDoubleConstant(0.0);\r
- one = builder.makeDoubleConstant(1.0);\r
- break;\r
- case glslang::EOpConvBoolToInt:\r
- zero = builder.makeIntConstant(0);\r
- one = builder.makeIntConstant(1);\r
- convOp = spv::OpSelect;\r
- break;\r
- case glslang::EOpConvBoolToUint:\r
- zero = builder.makeUintConstant(0);\r
- one = builder.makeUintConstant(1);\r
- convOp = spv::OpSelect;\r
- break;\r
-\r
- case glslang::EOpConvIntToFloat:\r
- case glslang::EOpConvIntToDouble:\r
- convOp = spv::OpConvertSToF;\r
- break;\r
-\r
- case glslang::EOpConvUintToFloat:\r
- case glslang::EOpConvUintToDouble:\r
- convOp = spv::OpConvertUToF;\r
- break;\r
-\r
- case glslang::EOpConvDoubleToFloat:\r
- case glslang::EOpConvFloatToDouble:\r
- convOp = spv::OpFConvert;\r
- break;\r
-\r
- case glslang::EOpConvFloatToInt:\r
- case glslang::EOpConvDoubleToInt:\r
- convOp = spv::OpConvertFToS;\r
- break;\r
-\r
- case glslang::EOpConvUintToInt:\r
- case glslang::EOpConvIntToUint:\r
- convOp = spv::OpBitcast;\r
- break;\r
-\r
- case glslang::EOpConvFloatToUint:\r
- case glslang::EOpConvDoubleToUint:\r
- convOp = spv::OpConvertFToU;\r
- break;\r
- default:\r
- break;\r
- }\r
-\r
- spv::Id result = 0;\r
- if (convOp == spv::OpNop)\r
- return result;\r
-\r
- if (convOp == spv::OpSelect) {\r
- zero = makeSmearedConstant(zero, vectorSize);\r
- one = makeSmearedConstant(one, vectorSize);\r
- result = builder.createTriOp(convOp, destType, operand, one, zero);\r
- } else\r
- result = builder.createUnaryOp(convOp, destType, operand);\r
-\r
- builder.setPrecision(result, precision);\r
-\r
- return result;\r
-}\r
-\r
-spv::Id TGlslangToSpvTraverser::makeSmearedConstant(spv::Id constant, int vectorSize)\r
-{\r
- if (vectorSize == 0)\r
- return constant;\r
-\r
- spv::Id vectorTypeId = builder.makeVectorType(builder.getTypeId(constant), vectorSize);\r
- std::vector<spv::Id> components;\r
- for (int c = 0; c < vectorSize; ++c)\r
- components.push_back(constant);\r
- return builder.makeCompositeConstant(vectorTypeId, components);\r
-}\r
-\r
-spv::Id TGlslangToSpvTraverser::createMiscOperation(glslang::TOperator op, spv::Decoration precision, spv::Id typeId, std::vector<spv::Id>& operands)\r
-{\r
- spv::Op opCode = spv::OpNop;\r
- int libCall = -1;\r
-\r
- switch (op) {\r
- case glslang::EOpMin:\r
- libCall = GLSL_STD_450::Min;\r
- break;\r
- case glslang::EOpModf:\r
- libCall = GLSL_STD_450::Modf;\r
- break;\r
- case glslang::EOpMax:\r
- libCall = GLSL_STD_450::Max;\r
- break;\r
- case glslang::EOpPow:\r
- libCall = GLSL_STD_450::Pow;\r
- break;\r
- case glslang::EOpDot:\r
- opCode = spv::OpDot;\r
- break;\r
- case glslang::EOpAtan:\r
- libCall = GLSL_STD_450::Atan2;\r
- break;\r
-\r
- case glslang::EOpClamp:\r
- libCall = GLSL_STD_450::Clamp;\r
- break;\r
- case glslang::EOpMix:\r
- libCall = GLSL_STD_450::Mix;\r
- break;\r
- case glslang::EOpStep:\r
- libCall = GLSL_STD_450::Step;\r
- break;\r
- case glslang::EOpSmoothStep:\r
- libCall = GLSL_STD_450::SmoothStep;\r
- break;\r
-\r
- case glslang::EOpDistance:\r
- libCall = GLSL_STD_450::Distance;\r
- break;\r
- case glslang::EOpCross:\r
- libCall = GLSL_STD_450::Cross;\r
- break;\r
- case glslang::EOpFaceForward:\r
- libCall = GLSL_STD_450::FaceForward;\r
- break;\r
- case glslang::EOpReflect:\r
- libCall = GLSL_STD_450::Reflect;\r
- break;\r
- case glslang::EOpRefract:\r
- libCall = GLSL_STD_450::Refract;\r
- break;\r
- default:\r
- return 0;\r
- }\r
-\r
- spv::Id id = 0;\r
- if (libCall >= 0)\r
- id = builder.createBuiltinCall(precision, typeId, stdBuiltins, libCall, operands);\r
- else {\r
- switch (operands.size()) {\r
- case 0:\r
- // should all be handled by visitAggregate and createNoArgOperation\r
- assert(0);\r
- return 0;\r
- case 1:\r
- // should all be handled by createUnaryOperation\r
- assert(0);\r
- return 0;\r
- case 2:\r
- id = builder.createBinOp(opCode, typeId, operands[0], operands[1]);\r
- break;\r
- case 3:\r
- id = builder.createTernaryOp(opCode, typeId, operands[0], operands[1], operands[2]);\r
- break;\r
- default:\r
- // These do not exist yet\r
- assert(0 && "operation with more than 3 operands");\r
- break;\r
- }\r
- }\r
-\r
- builder.setPrecision(id, precision);\r
-\r
- return id;\r
-}\r
-\r
-// Intrinsics with no arguments, no return value, and no precision.\r
-spv::Id TGlslangToSpvTraverser::createNoArgOperation(glslang::TOperator op)\r
-{\r
- // TODO: get the barrier operands correct\r
-\r
- switch (op) {\r
- case glslang::EOpEmitVertex:\r
- builder.createNoResultOp(spv::OpEmitVertex);\r
- return 0;\r
- case glslang::EOpEndPrimitive:\r
- builder.createNoResultOp(spv::OpEndPrimitive);\r
- return 0;\r
- case glslang::EOpBarrier:\r
- builder.createMemoryBarrier(spv::ExecutionScopeDevice, spv::MemorySemanticsAllMemory);\r
- builder.createControlBarrier(spv::ExecutionScopeDevice);\r
- return 0;\r
- case glslang::EOpMemoryBarrier:\r
- builder.createMemoryBarrier(spv::ExecutionScopeDevice, spv::MemorySemanticsAllMemory);\r
- return 0;\r
- case glslang::EOpMemoryBarrierAtomicCounter:\r
- builder.createMemoryBarrier(spv::ExecutionScopeDevice, spv::MemorySemanticsAtomicCounterMemoryMask);\r
- return 0;\r
- case glslang::EOpMemoryBarrierBuffer:\r
- builder.createMemoryBarrier(spv::ExecutionScopeDevice, spv::MemorySemanticsUniformMemoryMask);\r
- return 0;\r
- case glslang::EOpMemoryBarrierImage:\r
- builder.createMemoryBarrier(spv::ExecutionScopeDevice, spv::MemorySemanticsImageMemoryMask);\r
- return 0;\r
- case glslang::EOpMemoryBarrierShared:\r
- builder.createMemoryBarrier(spv::ExecutionScopeDevice, spv::MemorySemanticsWorkgroupLocalMemoryMask);\r
- return 0;\r
- case glslang::EOpGroupMemoryBarrier:\r
- builder.createMemoryBarrier(spv::ExecutionScopeDevice, spv::MemorySemanticsWorkgroupGlobalMemoryMask);\r
- return 0;\r
- default:\r
- spv::MissingFunctionality("operation with no arguments");\r
- return 0;\r
- }\r
-}\r
-\r
-spv::Id TGlslangToSpvTraverser::getSymbolId(const glslang::TIntermSymbol* symbol)\r
-{\r
- std::map<int, spv::Id>::iterator iter;\r
- iter = symbolValues.find(symbol->getId());\r
- spv::Id id;\r
- if (symbolValues.end() != iter) {\r
- id = iter->second;\r
- return id;\r
- }\r
-\r
- // it was not found, create it\r
- id = createSpvVariable(symbol);\r
- symbolValues[symbol->getId()] = id;\r
-\r
- if (! symbol->getType().isStruct()) {\r
- addDecoration(id, TranslatePrecisionDecoration(symbol->getType()));\r
- addDecoration(id, TranslateInterpolationDecoration(symbol->getType()));\r
- if (symbol->getQualifier().hasLocation())\r
- builder.addDecoration(id, spv::DecorationLocation, symbol->getQualifier().layoutLocation);\r
- if (symbol->getQualifier().hasIndex())\r
- builder.addDecoration(id, spv::DecorationIndex, symbol->getQualifier().layoutIndex);\r
- if (symbol->getQualifier().hasComponent())\r
- builder.addDecoration(id, spv::DecorationComponent, symbol->getQualifier().layoutComponent);\r
- if (glslangIntermediate->getXfbMode()) {\r
- if (symbol->getQualifier().hasXfbStride())\r
- builder.addDecoration(id, spv::DecorationStride, symbol->getQualifier().layoutXfbStride);\r
- if (symbol->getQualifier().hasXfbBuffer())\r
- builder.addDecoration(id, spv::DecorationXfbBuffer, symbol->getQualifier().layoutXfbBuffer);\r
- if (symbol->getQualifier().hasXfbOffset())\r
- builder.addDecoration(id, spv::DecorationOffset, symbol->getQualifier().layoutXfbOffset);\r
- }\r
- }\r
-\r
- addDecoration(id, TranslateInvariantDecoration(symbol->getType()));\r
- if (symbol->getQualifier().hasStream())\r
- builder.addDecoration(id, spv::DecorationStream, symbol->getQualifier().layoutStream);\r
- if (symbol->getQualifier().hasSet())\r
- builder.addDecoration(id, spv::DecorationDescriptorSet, symbol->getQualifier().layoutSet);\r
- if (symbol->getQualifier().hasBinding())\r
- builder.addDecoration(id, spv::DecorationBinding, symbol->getQualifier().layoutBinding);\r
- if (glslangIntermediate->getXfbMode()) {\r
- if (symbol->getQualifier().hasXfbStride())\r
- builder.addDecoration(id, spv::DecorationStride, symbol->getQualifier().layoutXfbStride);\r
- if (symbol->getQualifier().hasXfbBuffer())\r
- builder.addDecoration(id, spv::DecorationXfbBuffer, symbol->getQualifier().layoutXfbBuffer);\r
- }\r
-\r
- // built-in variable decorations\r
- int builtIn = TranslateBuiltInDecoration(symbol->getQualifier().builtIn);\r
- if (builtIn != spv::BadValue)\r
- builder.addDecoration(id, spv::DecorationBuiltIn, builtIn);\r
-\r
- if (linkageOnly)\r
- builder.addDecoration(id, spv::DecorationNoStaticUse);\r
-\r
- return id;\r
-}\r
-\r
-void TGlslangToSpvTraverser::addDecoration(spv::Id id, spv::Decoration dec)\r
-{\r
- if (dec != spv::BadValue)\r
- builder.addDecoration(id, dec);\r
-}\r
-\r
-void TGlslangToSpvTraverser::addMemberDecoration(spv::Id id, int member, spv::Decoration dec)\r
-{\r
- if (dec != spv::BadValue)\r
- builder.addMemberDecoration(id, (unsigned)member, dec);\r
-}\r
-\r
-// Use 'consts' as the flattened glslang source of scalar constants to recursively\r
-// build the aggregate SPIR-V constant.\r
-//\r
-// If there are not enough elements present in 'consts', 0 will be substituted;\r
-// an empty 'consts' can be used to create a fully zeroed SPIR-V constant.\r
-//\r
-spv::Id TGlslangToSpvTraverser::createSpvConstant(const glslang::TType& glslangType, const glslang::TConstUnionArray& consts, int& nextConst)\r
-{\r
- // vector of constants for SPIR-V\r
- std::vector<spv::Id> spvConsts;\r
-\r
- // Type is used for struct and array constants\r
- spv::Id typeId = convertGlslangToSpvType(glslangType);\r
-\r
- if (glslangType.isArray()) {\r
- glslang::TType elementType;\r
- elementType.shallowCopy(glslangType); // TODO: desktop arrays of arrays functionality will need a deeper copy to avoid modifying the original\r
- elementType.dereference();\r
- for (int i = 0; i < glslangType.getArraySize(); ++i)\r
- spvConsts.push_back(createSpvConstant(elementType, consts, nextConst));\r
- } else if (glslangType.isMatrix()) {\r
- glslang::TType vectorType;\r
- vectorType.shallowCopy(glslangType);\r
- vectorType.dereference();\r
- for (int col = 0; col < glslangType.getMatrixCols(); ++col)\r
- spvConsts.push_back(createSpvConstant(vectorType, consts, nextConst));\r
- } else if (glslangType.getStruct()) {\r
- glslang::TVector<glslang::TTypeLoc>::const_iterator iter;\r
- for (iter = glslangType.getStruct()->begin(); iter != glslangType.getStruct()->end(); ++iter)\r
- spvConsts.push_back(createSpvConstant(*iter->type, consts, nextConst));\r
- } else if (glslangType.isVector()) {\r
- for (unsigned int i = 0; i < (unsigned int)glslangType.getVectorSize(); ++i) {\r
- bool zero = nextConst >= consts.size();\r
- switch (glslangType.getBasicType()) {\r
- case glslang::EbtInt:\r
- spvConsts.push_back(builder.makeIntConstant(zero ? 0 : consts[nextConst].getIConst()));\r
- break;\r
- case glslang::EbtUint:\r
- spvConsts.push_back(builder.makeUintConstant(zero ? 0 : consts[nextConst].getUConst()));\r
- break;\r
- case glslang::EbtFloat:\r
- spvConsts.push_back(builder.makeFloatConstant(zero ? 0.0F : (float)consts[nextConst].getDConst()));\r
- break;\r
- case glslang::EbtDouble:\r
- spvConsts.push_back(builder.makeDoubleConstant(zero ? 0.0 : consts[nextConst].getDConst()));\r
- break;\r
- case glslang::EbtBool:\r
- spvConsts.push_back(builder.makeBoolConstant(zero ? false : consts[nextConst].getBConst()));\r
- break;\r
- default:\r
- spv::MissingFunctionality("constant vector type");\r
- break;\r
- }\r
- ++nextConst;\r
- }\r
- } else {\r
- // we have a non-aggregate (scalar) constant\r
- bool zero = nextConst >= consts.size();\r
- spv::Id scalar = 0;\r
- switch (glslangType.getBasicType()) {\r
- case glslang::EbtInt:\r
- scalar = builder.makeIntConstant(zero ? 0 : consts[nextConst].getIConst());\r
- break;\r
- case glslang::EbtUint:\r
- scalar = builder.makeUintConstant(zero ? 0 : consts[nextConst].getUConst());\r
- break;\r
- case glslang::EbtFloat:\r
- scalar = builder.makeFloatConstant(zero ? 0.0F : (float)consts[nextConst].getDConst());\r
- break;\r
- case glslang::EbtDouble:\r
- scalar = builder.makeDoubleConstant(zero ? 0.0 : consts[nextConst].getDConst());\r
- break;\r
- case glslang::EbtBool:\r
- scalar = builder.makeBoolConstant(zero ? false : consts[nextConst].getBConst());\r
- break;\r
- default:\r
- spv::MissingFunctionality("constant scalar type");\r
- break;\r
- }\r
- ++nextConst;\r
- return scalar;\r
- }\r
-\r
- return builder.makeCompositeConstant(typeId, spvConsts);\r
-}\r
-\r
-}; // end anonymous namespace\r
-\r
-namespace glslang {\r
-\r
-// Write SPIR-V out to a binary file\r
-void OutputSpv(const std::vector<unsigned int>& spirv, const char* baseName)\r
-{\r
- std::ofstream out;\r
- std::string fileName(baseName);\r
- fileName.append(".spv");\r
- out.open(fileName.c_str(), std::ios::binary | std::ios::out);\r
- for (int i = 0; i < (int)spirv.size(); ++i) {\r
- unsigned int word = spirv[i];\r
- out.write((const char*)&word, 4);\r
- }\r
- out.close();\r
-}\r
-\r
-//\r
-// Set up the glslang traversal\r
-//\r
-void GlslangToSpv(const glslang::TIntermediate& intermediate, std::vector<unsigned int>& spirv)\r
-{\r
- TIntermNode* root = intermediate.getTreeRoot();\r
-\r
- if (root == 0)\r
- return;\r
-\r
- glslang::GetThreadPoolAllocator().push();\r
-\r
- TGlslangToSpvTraverser it(&intermediate);\r
-\r
- root->traverse(&it);\r
-\r
- it.dumpSpv(spirv);\r
-\r
- glslang::GetThreadPoolAllocator().pop();\r
-}\r
-\r
-}; // end namespace glslang\r
+//
+//Copyright (C) 2014 LunarG, Inc.
+//
+//All rights reserved.
+//
+//Redistribution and use in source and binary forms, with or without
+//modification, are permitted provided that the following conditions
+//are met:
+//
+// Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//
+// Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following
+// disclaimer in the documentation and/or other materials provided
+// with the distribution.
+//
+// Neither the name of 3Dlabs Inc. Ltd. nor the names of its
+// contributors may be used to endorse or promote products derived
+// from this software without specific prior written permission.
+//
+//THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+//"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+//LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+//FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+//COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+//INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+//BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+//LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+//CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+//LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+//ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+//POSSIBILITY OF SUCH DAMAGE.
+
+//
+// Author: John Kessenich, LunarG
+//
+// Visit the nodes in the glslang intermediate tree representation to
+// translate them to SPIR-V.
+//
+
+#include "spirv.h"
+#include "GlslangToSpv.h"
+#include "SpvBuilder.h"
+#include "GLSL450Lib.h"
+
+// Glslang includes
+#include "glslang/MachineIndependent/localintermediate.h"
+#include "glslang/MachineIndependent/SymbolTable.h"
+
+#include <string>
+#include <map>
+#include <list>
+#include <vector>
+#include <stack>
+#include <fstream>
+
+namespace {
+
+const int GlslangMagic = 0x51a;
+
+//
+// The main holder of information for translating glslang to SPIR-V.
+//
+// Derives from the AST walking base class.
+//
+class TGlslangToSpvTraverser : public glslang::TIntermTraverser {
+public:
+ TGlslangToSpvTraverser(const glslang::TIntermediate*);
+ virtual ~TGlslangToSpvTraverser();
+
+ bool visitAggregate(glslang::TVisit, glslang::TIntermAggregate*);
+ bool visitBinary(glslang::TVisit, glslang::TIntermBinary*);
+ void visitConstantUnion(glslang::TIntermConstantUnion*);
+ bool visitSelection(glslang::TVisit, glslang::TIntermSelection*);
+ bool visitSwitch(glslang::TVisit, glslang::TIntermSwitch*);
+ void visitSymbol(glslang::TIntermSymbol* symbol);
+ bool visitUnary(glslang::TVisit, glslang::TIntermUnary*);
+ bool visitLoop(glslang::TVisit, glslang::TIntermLoop*);
+ bool visitBranch(glslang::TVisit visit, glslang::TIntermBranch*);
+
+ void dumpSpv(std::vector<unsigned int>& out) { builder.dump(out); }
+
+protected:
+ spv::Id createSpvVariable(const glslang::TIntermSymbol*);
+ spv::Id getSampledType(const glslang::TSampler&);
+ spv::Id convertGlslangToSpvType(const glslang::TType& type);
+
+ bool isShaderEntrypoint(const glslang::TIntermAggregate* node);
+ void makeFunctions(const glslang::TIntermSequence&);
+ void makeGlobalInitializers(const glslang::TIntermSequence&);
+ void visitFunctions(const glslang::TIntermSequence&);
+ void handleFunctionEntry(const glslang::TIntermAggregate* node);
+ void translateArguments(const glslang::TIntermSequence& glslangArguments, std::vector<spv::Id>& arguments);
+ spv::Id handleBuiltInFunctionCall(const glslang::TIntermAggregate*);
+ spv::Id handleUserFunctionCall(const glslang::TIntermAggregate*);
+
+ spv::Id createBinaryOperation(glslang::TOperator op, spv::Decoration precision, spv::Id typeId, spv::Id left, spv::Id right, glslang::TBasicType typeProxy, bool reduceComparison = true);
+ spv::Id createUnaryOperation(glslang::TOperator op, spv::Decoration precision, spv::Id typeId, spv::Id operand, bool isFloat);
+ spv::Id createConversion(glslang::TOperator op, spv::Decoration precision, spv::Id destTypeId, spv::Id operand);
+ spv::Id makeSmearedConstant(spv::Id constant, int vectorSize);
+ spv::Id createMiscOperation(glslang::TOperator op, spv::Decoration precision, spv::Id typeId, std::vector<spv::Id>& operands);
+ spv::Id createNoArgOperation(glslang::TOperator op);
+ spv::Id getSymbolId(const glslang::TIntermSymbol* node);
+ void addDecoration(spv::Id id, spv::Decoration dec);
+ void addMemberDecoration(spv::Id id, int member, spv::Decoration dec);
+ spv::Id createSpvConstant(const glslang::TType& type, const glslang::TConstUnionArray&, int& nextConst);
+
+ spv::Function* shaderEntry;
+ int sequenceDepth;
+
+ // There is a 1:1 mapping between a spv builder and a module; this is thread safe
+ spv::Builder builder;
+ bool inMain;
+ bool mainTerminated;
+ bool linkageOnly;
+ const glslang::TIntermediate* glslangIntermediate;
+ spv::Id stdBuiltins;
+
+ std::map<int, spv::Id> symbolValues;
+ std::set<int> constReadOnlyParameters; // set of formal function parameters that have glslang qualifier constReadOnly, so we know they are not local function "const" that are write-once
+ std::map<std::string, spv::Function*> functionMap;
+ std::map<const glslang::TTypeList*, spv::Id> structMap;
+ std::map<const glslang::TTypeList*, std::vector<int> > memberRemapper; // for mapping glslang block indices to spv indices (e.g., due to hidden members)
+ std::stack<bool> breakForLoop; // false means break for switch
+ std::stack<glslang::TIntermTyped*> loopTerminal; // code from the last part of a for loop: for(...; ...; terminal), needed for e.g., continue };
+};
+
+//
+// Helper functions for translating glslang representations to SPIR-V enumerants.
+//
+
+// Translate glslang profile to SPIR-V source language.
+spv::SourceLanguage TranslateSourceLanguage(EProfile profile)
+{
+ switch (profile) {
+ case ENoProfile:
+ case ECoreProfile:
+ case ECompatibilityProfile:
+ return spv::SourceLanguageGLSL;
+ case EEsProfile:
+ return spv::SourceLanguageESSL;
+ default:
+ return spv::SourceLanguageUnknown;
+ }
+}
+
+// Translate glslang language (stage) to SPIR-V execution model.
+spv::ExecutionModel TranslateExecutionModel(EShLanguage stage)
+{
+ switch (stage) {
+ case EShLangVertex: return spv::ExecutionModelVertex;
+ case EShLangTessControl: return spv::ExecutionModelTessellationControl;
+ case EShLangTessEvaluation: return spv::ExecutionModelTessellationEvaluation;
+ case EShLangGeometry: return spv::ExecutionModelGeometry;
+ case EShLangFragment: return spv::ExecutionModelFragment;
+ case EShLangCompute: return spv::ExecutionModelGLCompute;
+ default:
+ spv::MissingFunctionality("GLSL stage");
+ return spv::ExecutionModelFragment;
+ }
+}
+
+// Translate glslang type to SPIR-V storage class.
+spv::StorageClass TranslateStorageClass(const glslang::TType& type)
+{
+ if (type.getQualifier().isPipeInput())
+ return spv::StorageClassInput;
+ else if (type.getQualifier().isPipeOutput())
+ return spv::StorageClassOutput;
+ else if (type.getQualifier().isUniformOrBuffer()) {
+ if (type.getBasicType() == glslang::EbtBlock)
+ return spv::StorageClassUniform;
+ else
+ return spv::StorageClassUniformConstant;
+ // TODO: how are we distuingishing between default and non-default non-writable uniforms? Do default uniforms even exist?
+ } else {
+ switch (type.getQualifier().storage) {
+ case glslang::EvqShared: return spv::StorageClassWorkgroupLocal; break;
+ case glslang::EvqGlobal: return spv::StorageClassPrivateGlobal;
+ case glslang::EvqConstReadOnly: return spv::StorageClassFunction;
+ case glslang::EvqTemporary: return spv::StorageClassFunction;
+ default:
+ spv::MissingFunctionality("unknown glslang storage class");
+ return spv::StorageClassFunction;
+ }
+ }
+}
+
+// Translate glslang sampler type to SPIR-V dimensionality.
+spv::Dim TranslateDimensionality(const glslang::TSampler& sampler)
+{
+ switch (sampler.dim) {
+ case glslang::Esd1D: return spv::Dim1D;
+ case glslang::Esd2D: return spv::Dim2D;
+ case glslang::Esd3D: return spv::Dim3D;
+ case glslang::EsdCube: return spv::DimCube;
+ case glslang::EsdRect: return spv::DimRect;
+ case glslang::EsdBuffer: return spv::DimBuffer;
+ default:
+ spv::MissingFunctionality("unknown sampler dimension");
+ return spv::Dim2D;
+ }
+}
+
+// Translate glslang type to SPIR-V precision decorations.
+spv::Decoration TranslatePrecisionDecoration(const glslang::TType& type)
+{
+ switch (type.getQualifier().precision) {
+ case glslang::EpqLow: return spv::DecorationPrecisionLow;
+ case glslang::EpqMedium: return spv::DecorationPrecisionMedium;
+ case glslang::EpqHigh: return spv::DecorationPrecisionHigh;
+ default:
+ return spv::NoPrecision;
+ }
+}
+
+// Translate glslang type to SPIR-V block decorations.
+spv::Decoration TranslateBlockDecoration(const glslang::TType& type)
+{
+ if (type.getBasicType() == glslang::EbtBlock) {
+ switch (type.getQualifier().storage) {
+ case glslang::EvqUniform: return spv::DecorationBlock;
+ case glslang::EvqBuffer: return spv::DecorationBufferBlock;
+ case glslang::EvqVaryingIn: return spv::DecorationBlock;
+ case glslang::EvqVaryingOut: return spv::DecorationBlock;
+ default:
+ spv::MissingFunctionality("kind of block");
+ break;
+ }
+ }
+
+ return (spv::Decoration)spv::BadValue;
+}
+
+// Translate glslang type to SPIR-V layout decorations.
+spv::Decoration TranslateLayoutDecoration(const glslang::TType& type)
+{
+ if (type.isMatrix()) {
+ switch (type.getQualifier().layoutMatrix) {
+ case glslang::ElmRowMajor:
+ return spv::DecorationRowMajor;
+ default:
+ return spv::DecorationColMajor;
+ }
+ } else {
+ switch (type.getBasicType()) {
+ default:
+ return (spv::Decoration)spv::BadValue;
+ break;
+ case glslang::EbtBlock:
+ switch (type.getQualifier().storage) {
+ case glslang::EvqUniform:
+ case glslang::EvqBuffer:
+ switch (type.getQualifier().layoutPacking) {
+ case glslang::ElpShared: return spv::DecorationGLSLShared;
+ case glslang::ElpStd140: return spv::DecorationGLSLStd140;
+ case glslang::ElpStd430: return spv::DecorationGLSLStd430;
+ case glslang::ElpPacked: return spv::DecorationGLSLPacked;
+ default:
+ spv::MissingFunctionality("uniform block layout");
+ return spv::DecorationGLSLShared;
+ }
+ case glslang::EvqVaryingIn:
+ case glslang::EvqVaryingOut:
+ if (type.getQualifier().layoutPacking != glslang::ElpNone)
+ spv::MissingFunctionality("in/out block layout");
+ return (spv::Decoration)spv::BadValue;
+ default:
+ spv::MissingFunctionality("block storage qualification");
+ return (spv::Decoration)spv::BadValue;
+ }
+ }
+ }
+}
+
+// Translate glslang type to SPIR-V interpolation decorations.
+spv::Decoration TranslateInterpolationDecoration(const glslang::TType& type)
+{
+ if (type.getQualifier().smooth)
+ return spv::DecorationSmooth;
+ if (type.getQualifier().nopersp)
+ return spv::DecorationNoperspective;
+ else if (type.getQualifier().patch)
+ return spv::DecorationPatch;
+ else if (type.getQualifier().flat)
+ return spv::DecorationFlat;
+ else if (type.getQualifier().centroid)
+ return spv::DecorationCentroid;
+ else if (type.getQualifier().sample)
+ return spv::DecorationSample;
+ else
+ return (spv::Decoration)spv::BadValue;
+}
+
+// If glslang type is invaraiant, return SPIR-V invariant decoration.
+spv::Decoration TranslateInvariantDecoration(const glslang::TType& type)
+{
+ if (type.getQualifier().invariant)
+ return spv::DecorationInvariant;
+ else
+ return (spv::Decoration)spv::BadValue;
+}
+
+// Translate glslang built-in variable to SPIR-V built in decoration.
+spv::BuiltIn TranslateBuiltInDecoration(glslang::TBuiltInVariable builtIn)
+{
+ switch (builtIn) {
+ case glslang::EbvPosition: return spv::BuiltInPosition;
+ case glslang::EbvPointSize: return spv::BuiltInPointSize;
+ case glslang::EbvClipVertex: return spv::BuiltInClipVertex;
+ case glslang::EbvClipDistance: return spv::BuiltInClipDistance;
+ case glslang::EbvCullDistance: return spv::BuiltInCullDistance;
+ case glslang::EbvVertexId: return spv::BuiltInVertexId;
+ case glslang::EbvInstanceId: return spv::BuiltInInstanceId;
+ case glslang::EbvPrimitiveId: return spv::BuiltInPrimitiveId;
+ case glslang::EbvInvocationId: return spv::BuiltInInvocationId;
+ case glslang::EbvLayer: return spv::BuiltInLayer;
+ case glslang::EbvViewportIndex: return spv::BuiltInViewportIndex;
+ case glslang::EbvTessLevelInner: return spv::BuiltInTessLevelInner;
+ case glslang::EbvTessLevelOuter: return spv::BuiltInTessLevelOuter;
+ case glslang::EbvTessCoord: return spv::BuiltInTessCoord;
+ case glslang::EbvPatchVertices: return spv::BuiltInPatchVertices;
+ case glslang::EbvFragCoord: return spv::BuiltInFragCoord;
+ case glslang::EbvPointCoord: return spv::BuiltInPointCoord;
+ case glslang::EbvFace: return spv::BuiltInFrontFacing;
+ case glslang::EbvSampleId: return spv::BuiltInSampleId;
+ case glslang::EbvSamplePosition: return spv::BuiltInSamplePosition;
+ case glslang::EbvSampleMask: return spv::BuiltInSampleMask;
+ case glslang::EbvFragColor: return spv::BuiltInFragColor;
+ case glslang::EbvFragData: return spv::BuiltInFragColor;
+ case glslang::EbvFragDepth: return spv::BuiltInFragDepth;
+ case glslang::EbvHelperInvocation: return spv::BuiltInHelperInvocation;
+ case glslang::EbvNumWorkGroups: return spv::BuiltInNumWorkgroups;
+ case glslang::EbvWorkGroupSize: return spv::BuiltInWorkgroupSize;
+ case glslang::EbvWorkGroupId: return spv::BuiltInWorkgroupId;
+ case glslang::EbvLocalInvocationId: return spv::BuiltInLocalInvocationId;
+ case glslang::EbvLocalInvocationIndex: return spv::BuiltInLocalInvocationIndex;
+ case glslang::EbvGlobalInvocationId: return spv::BuiltInGlobalInvocationId;
+ default: return (spv::BuiltIn)spv::BadValue;
+ }
+}
+
+//
+// Implement the TGlslangToSpvTraverser class.
+//
+
+TGlslangToSpvTraverser::TGlslangToSpvTraverser(const glslang::TIntermediate* glslangIntermediate)
+ : TIntermTraverser(true, false, true), shaderEntry(0), sequenceDepth(0),
+ builder(GlslangMagic),
+ inMain(false), mainTerminated(false), linkageOnly(false),
+ glslangIntermediate(glslangIntermediate)
+{
+ spv::ExecutionModel executionModel = TranslateExecutionModel(glslangIntermediate->getStage());
+
+ builder.clearAccessChain();
+ builder.setSource(TranslateSourceLanguage(glslangIntermediate->getProfile()), glslangIntermediate->getVersion());
+ stdBuiltins = builder.import("GLSL.std.450");
+ builder.setMemoryModel(spv::AddressingModelLogical, spv::MemoryModelGLSL450);
+ shaderEntry = builder.makeMain();
+ builder.addEntryPoint(executionModel, shaderEntry);
+
+ // Add the source extensions
+ const std::set<std::string>& sourceExtensions = glslangIntermediate->getRequestedExtensions();
+ for (std::set<std::string>::const_iterator it = sourceExtensions.begin(); it != sourceExtensions.end(); ++it)
+ builder.addSourceExtension(it->c_str());
+
+ // Add the top-level modes for this shader.
+
+ if (glslangIntermediate->getXfbMode())
+ builder.addExecutionMode(shaderEntry, spv::ExecutionModeXfb);
+
+ unsigned int mode;
+ switch (glslangIntermediate->getStage()) {
+ case EShLangVertex:
+ break;
+
+ case EShLangTessControl:
+ builder.addExecutionMode(shaderEntry, spv::ExecutionModeOutputVertices, glslangIntermediate->getVertices());
+ break;
+
+ case EShLangTessEvaluation:
+ switch (glslangIntermediate->getInputPrimitive()) {
+ case glslang::ElgTriangles: mode = spv::ExecutionModeInputTriangles; break;
+ case glslang::ElgQuads: mode = spv::ExecutionModeInputQuads; break;
+ case glslang::ElgIsolines: mode = spv::ExecutionModeInputIsolines; break;
+ default: mode = spv::BadValue; break;
+ }
+ if (mode != spv::BadValue)
+ builder.addExecutionMode(shaderEntry, (spv::ExecutionMode)mode);
+
+ // TODO
+ //builder.addExecutionMode(spv::VertexSpacingMdName, glslangIntermediate->getVertexSpacing());
+ //builder.addExecutionMode(spv::VertexOrderMdName, glslangIntermediate->getVertexOrder());
+ //builder.addExecutionMode(spv::PointModeMdName, glslangIntermediate->getPointMode());
+ break;
+
+ case EShLangGeometry:
+ switch (glslangIntermediate->getInputPrimitive()) {
+ case glslang::ElgPoints: mode = spv::ExecutionModeInputPoints; break;
+ case glslang::ElgLines: mode = spv::ExecutionModeInputLines; break;
+ case glslang::ElgLinesAdjacency: mode = spv::ExecutionModeInputLinesAdjacency; break;
+ case glslang::ElgTriangles: mode = spv::ExecutionModeInputTriangles; break;
+ case glslang::ElgTrianglesAdjacency: mode = spv::ExecutionModeInputTrianglesAdjacency; break;
+ default: mode = spv::BadValue; break;
+ }
+ if (mode != spv::BadValue)
+ builder.addExecutionMode(shaderEntry, (spv::ExecutionMode)mode);
+ builder.addExecutionMode(shaderEntry, spv::ExecutionModeInvocations, glslangIntermediate->getInvocations());
+
+ switch (glslangIntermediate->getOutputPrimitive()) {
+ case glslang::ElgPoints: mode = spv::ExecutionModeOutputPoints; break;
+ case glslang::ElgLineStrip: mode = spv::ExecutionModeOutputLineStrip; break;
+ case glslang::ElgTriangleStrip: mode = spv::ExecutionModeOutputTriangleStrip; break;
+ default: mode = spv::BadValue; break;
+ }
+ if (mode != spv::BadValue)
+ builder.addExecutionMode(shaderEntry, (spv::ExecutionMode)mode);
+ builder.addExecutionMode(shaderEntry, spv::ExecutionModeOutputVertices, glslangIntermediate->getVertices());
+ break;
+
+ case EShLangFragment:
+ if (glslangIntermediate->getPixelCenterInteger())
+ builder.addExecutionMode(shaderEntry, spv::ExecutionModePixelCenterInteger);
+ if (glslangIntermediate->getOriginUpperLeft())
+ builder.addExecutionMode(shaderEntry, spv::ExecutionModeOriginUpperLeft);
+ break;
+
+ case EShLangCompute:
+ break;
+
+ default:
+ break;
+ }
+
+}
+
+TGlslangToSpvTraverser::~TGlslangToSpvTraverser()
+{
+ if (! mainTerminated) {
+ spv::Block* lastMainBlock = shaderEntry->getLastBlock();
+ builder.setBuildPoint(lastMainBlock);
+ builder.leaveFunction(true);
+ }
+}
+
+//
+// Implement the traversal functions.
+//
+// Return true from interior nodes to have the external traversal
+// continue on to children. Return false if children were
+// already processed.
+//
+
+//
+// Symbols can turn into
+// - uniform/input reads
+// - output writes
+// - complex lvalue base setups: foo.bar[3].... , where we see foo and start up an access chain
+// - something simple that degenerates into the last bullet
+//
+void TGlslangToSpvTraverser::visitSymbol(glslang::TIntermSymbol* symbol)
+{
+ // getSymbolId() will set up all the IO decorations on the first call.
+ // Formal function parameters were mapped during makeFunctions().
+ spv::Id id = getSymbolId(symbol);
+
+ if (! linkageOnly) {
+ // Prepare to generate code for the access
+
+ // L-value chains will be computed left to right. We're on the symbol now,
+ // which is the left-most part of the access chain, so now is "clear" time,
+ // followed by setting the base.
+ builder.clearAccessChain();
+
+ // For now, we consider all user variables as being in memory, so they are pointers,
+ // except for "const in" arguments to a function, which are an intermediate object.
+ // See comments in handleUserFunctionCall().
+ glslang::TStorageQualifier qualifier = symbol->getQualifier().storage;
+ if (qualifier == glslang::EvqConstReadOnly && constReadOnlyParameters.find(symbol->getId()) != constReadOnlyParameters.end())
+ builder.setAccessChainRValue(id);
+ else
+ builder.setAccessChainLValue(id);
+ }
+}
+
+bool TGlslangToSpvTraverser::visitBinary(glslang::TVisit /* visit */, glslang::TIntermBinary* node)
+{
+ // First, handle special cases
+ switch (node->getOp()) {
+ case glslang::EOpAssign:
+ case glslang::EOpAddAssign:
+ case glslang::EOpSubAssign:
+ case glslang::EOpMulAssign:
+ case glslang::EOpVectorTimesMatrixAssign:
+ case glslang::EOpVectorTimesScalarAssign:
+ case glslang::EOpMatrixTimesScalarAssign:
+ case glslang::EOpMatrixTimesMatrixAssign:
+ case glslang::EOpDivAssign:
+ case glslang::EOpModAssign:
+ case glslang::EOpAndAssign:
+ case glslang::EOpInclusiveOrAssign:
+ case glslang::EOpExclusiveOrAssign:
+ case glslang::EOpLeftShiftAssign:
+ case glslang::EOpRightShiftAssign:
+ // A bin-op assign "a += b" means the same thing as "a = a + b"
+ // where a is evaluated before b. For a simple assignment, GLSL
+ // says to evaluate the left before the right. So, always, left
+ // node then right node.
+ {
+ // get the left l-value, save it away
+ builder.clearAccessChain();
+ node->getLeft()->traverse(this);
+ spv::Builder::AccessChain lValue = builder.getAccessChain();
+
+ // evaluate the right
+ builder.clearAccessChain();
+ node->getRight()->traverse(this);
+ spv::Id rValue = builder.accessChainLoad(TranslatePrecisionDecoration(node->getRight()->getType()));
+
+ if (node->getOp() != glslang::EOpAssign) {
+ // the left is also an r-value
+ builder.setAccessChain(lValue);
+ spv::Id leftRValue = builder.accessChainLoad(TranslatePrecisionDecoration(node->getLeft()->getType()));
+
+ // do the operation
+ rValue = createBinaryOperation(node->getOp(), TranslatePrecisionDecoration(node->getType()),
+ convertGlslangToSpvType(node->getType()), leftRValue, rValue,
+ node->getType().getBasicType());
+
+ // these all need their counterparts in createBinaryOperation()
+ if (rValue == 0)
+ spv::MissingFunctionality("createBinaryOperation");
+ }
+
+ // store the result
+ builder.setAccessChain(lValue);
+ builder.accessChainStore(rValue);
+
+ // assignments are expressions having an rValue after they are evaluated...
+ builder.clearAccessChain();
+ builder.setAccessChainRValue(rValue);
+ }
+ return false;
+ case glslang::EOpIndexDirect:
+ case glslang::EOpIndexDirectStruct:
+ {
+ // Get the left part of the access chain.
+ node->getLeft()->traverse(this);
+
+ // Add the next element in the chain
+
+ int index = 0;
+ if (node->getRight()->getAsConstantUnion() == 0)
+ spv::MissingFunctionality("direct index without a constant node");
+ else
+ index = node->getRight()->getAsConstantUnion()->getConstArray()[0].getIConst();
+
+ if (node->getLeft()->getBasicType() == glslang::EbtBlock && node->getOp() == glslang::EOpIndexDirectStruct) {
+ // This may be, e.g., an anonymous block-member selection, which generally need
+ // index remapping due to hidden members in anonymous blocks.
+ std::vector<int>& remapper = memberRemapper[node->getLeft()->getType().getStruct()];
+ if (remapper.size() == 0)
+ spv::MissingFunctionality("block without member remapping");
+ else
+ index = remapper[index];
+ }
+
+ if (! node->getLeft()->getType().isArray() &&
+ node->getLeft()->getType().isVector() &&
+ node->getOp() == glslang::EOpIndexDirect) {
+ // This is essentially a hard-coded vector swizzle of size 1,
+ // so short circuit the access-chain stuff with a swizzle.
+ std::vector<unsigned> swizzle;
+ swizzle.push_back(node->getRight()->getAsConstantUnion()->getConstArray()[0].getIConst());
+ builder.accessChainPushSwizzle(swizzle);
+ } else {
+ // normal case for indexing array or structure or block
+ builder.accessChainPush(builder.makeIntConstant(index), convertGlslangToSpvType(node->getType()));
+ }
+ }
+ return false;
+ case glslang::EOpIndexIndirect:
+ {
+ // Structure or array or vector indirection.
+ // Will use native SPIR-V access-chain for struct and array indirection;
+ // matrices are arrays of vectors, so will also work for a matrix.
+ // Will use the access chain's 'component' for variable index into a vector.
+
+ // This adapter is building access chains left to right.
+ // Set up the access chain to the left.
+ node->getLeft()->traverse(this);
+
+ // save it so that computing the right side doesn't trash it
+ spv::Builder::AccessChain partial = builder.getAccessChain();
+
+ // compute the next index in the chain
+ builder.clearAccessChain();
+ node->getRight()->traverse(this);
+ spv::Id index = builder.accessChainLoad(TranslatePrecisionDecoration(node->getRight()->getType()));
+
+ // restore the saved access chain
+ builder.setAccessChain(partial);
+
+ if (! node->getLeft()->getType().isArray() && node->getLeft()->getType().isVector())
+ builder.accessChainPushComponent(index);
+ else
+ builder.accessChainPush(index, convertGlslangToSpvType(node->getType()));
+ }
+ return false;
+ case glslang::EOpVectorSwizzle:
+ {
+ node->getLeft()->traverse(this);
+ glslang::TIntermSequence& swizzleSequence = node->getRight()->getAsAggregate()->getSequence();
+ std::vector<unsigned> swizzle;
+ for (int i = 0; i < (int)swizzleSequence.size(); ++i)
+ swizzle.push_back(swizzleSequence[i]->getAsConstantUnion()->getConstArray()[0].getIConst());
+ builder.accessChainPushSwizzle(swizzle);
+ }
+ return false;
+ default:
+ break;
+ }
+
+ // Assume generic binary op...
+
+ // Get the operands
+ builder.clearAccessChain();
+ node->getLeft()->traverse(this);
+ spv::Id left = builder.accessChainLoad(TranslatePrecisionDecoration(node->getLeft()->getType()));
+
+ builder.clearAccessChain();
+ node->getRight()->traverse(this);
+ spv::Id right = builder.accessChainLoad(TranslatePrecisionDecoration(node->getRight()->getType()));
+
+ spv::Id result;
+ spv::Decoration precision = TranslatePrecisionDecoration(node->getType());
+
+ result = createBinaryOperation(node->getOp(), precision,
+ convertGlslangToSpvType(node->getType()), left, right,
+ node->getLeft()->getType().getBasicType());
+
+ if (! result) {
+ spv::MissingFunctionality("glslang binary operation");
+ } else {
+ builder.clearAccessChain();
+ builder.setAccessChainRValue(result);
+
+ return false;
+ }
+
+ return true;
+}
+
+bool TGlslangToSpvTraverser::visitUnary(glslang::TVisit /* visit */, glslang::TIntermUnary* node)
+{
+ builder.clearAccessChain();
+ node->getOperand()->traverse(this);
+ spv::Id operand = builder.accessChainLoad(TranslatePrecisionDecoration(node->getOperand()->getType()));
+
+ spv::Decoration precision = TranslatePrecisionDecoration(node->getType());
+
+ // it could be a conversion
+ spv::Id result = createConversion(node->getOp(), precision, convertGlslangToSpvType(node->getType()), operand);
+
+ // if not, then possibly an operation
+ if (! result)
+ result = createUnaryOperation(node->getOp(), precision, convertGlslangToSpvType(node->getType()), operand, node->getBasicType() == glslang::EbtFloat || node->getBasicType() == glslang::EbtDouble);
+
+ if (result) {
+ builder.clearAccessChain();
+ builder.setAccessChainRValue(result);
+
+ return false; // done with this node
+ }
+
+ // it must be a special case, check...
+ switch (node->getOp()) {
+ case glslang::EOpPostIncrement:
+ case glslang::EOpPostDecrement:
+ case glslang::EOpPreIncrement:
+ case glslang::EOpPreDecrement:
+ {
+ // we need the integer value "1" or the floating point "1.0" to add/subtract
+ spv::Id one = node->getBasicType() == glslang::EbtFloat ?
+ builder.makeFloatConstant(1.0F) :
+ builder.makeIntConstant(1);
+ glslang::TOperator op;
+ if (node->getOp() == glslang::EOpPreIncrement ||
+ node->getOp() == glslang::EOpPostIncrement)
+ op = glslang::EOpAdd;
+ else
+ op = glslang::EOpSub;
+
+ spv::Id result = createBinaryOperation(op, TranslatePrecisionDecoration(node->getType()),
+ convertGlslangToSpvType(node->getType()), operand, one,
+ node->getType().getBasicType());
+ if (result == 0)
+ spv::MissingFunctionality("createBinaryOperation for unary");
+
+ // The result of operation is always stored, but conditionally the
+ // consumed result. The consumed result is always an r-value.
+ builder.accessChainStore(result);
+ builder.clearAccessChain();
+ if (node->getOp() == glslang::EOpPreIncrement ||
+ node->getOp() == glslang::EOpPreDecrement)
+ builder.setAccessChainRValue(result);
+ else
+ builder.setAccessChainRValue(operand);
+ }
+
+ return false;
+
+ case glslang::EOpEmitStreamVertex:
+ builder.createNoResultOp(spv::OpEmitStreamVertex, operand);
+ return false;
+ case glslang::EOpEndStreamPrimitive:
+ builder.createNoResultOp(spv::OpEndStreamPrimitive, operand);
+ return false;
+
+ default:
+ spv::MissingFunctionality("glslang unary");
+ break;
+ }
+
+ return true;
+}
+
+bool TGlslangToSpvTraverser::visitAggregate(glslang::TVisit visit, glslang::TIntermAggregate* node)
+{
+ spv::Id result;
+ glslang::TOperator binOp = glslang::EOpNull;
+ bool reduceComparison = true;
+ bool isMatrix = false;
+ bool noReturnValue = false;
+
+ assert(node->getOp());
+
+ spv::Decoration precision = TranslatePrecisionDecoration(node->getType());
+
+ switch (node->getOp()) {
+ case glslang::EOpSequence:
+ {
+ if (preVisit)
+ ++sequenceDepth;
+ else
+ --sequenceDepth;
+
+ if (sequenceDepth == 1) {
+ // If this is the parent node of all the functions, we want to see them
+ // early, so all call points have actual SPIR-V functions to reference.
+ // In all cases, still let the traverser visit the children for us.
+ makeFunctions(node->getAsAggregate()->getSequence());
+
+ // Also, we want all globals initializers to go into the entry of main(), before
+ // anything else gets there, so visit out of order, doing them all now.
+ makeGlobalInitializers(node->getAsAggregate()->getSequence());
+
+ // Initializers are done, don't want to visit again, but functions link objects need to be processed,
+ // so do them manually.
+ visitFunctions(node->getAsAggregate()->getSequence());
+
+ return false;
+ }
+
+ return true;
+ }
+ case glslang::EOpLinkerObjects:
+ {
+ if (visit == glslang::EvPreVisit)
+ linkageOnly = true;
+ else
+ linkageOnly = false;
+
+ return true;
+ }
+ case glslang::EOpComma:
+ {
+ // processing from left to right naturally leaves the right-most
+ // lying around in the access chain
+ glslang::TIntermSequence& glslangOperands = node->getSequence();
+ for (int i = 0; i < (int)glslangOperands.size(); ++i)
+ glslangOperands[i]->traverse(this);
+
+ return false;
+ }
+ case glslang::EOpFunction:
+ if (visit == glslang::EvPreVisit) {
+ if (isShaderEntrypoint(node)) {
+ inMain = true;
+ builder.setBuildPoint(shaderEntry->getLastBlock());
+ } else {
+ handleFunctionEntry(node);
+ }
+ } else {
+ if (inMain)
+ mainTerminated = true;
+ builder.leaveFunction(inMain);
+ inMain = false;
+ }
+
+ return true;
+ case glslang::EOpParameters:
+ // Parameters will have been consumed by EOpFunction processing, but not
+ // the body, so we still visited the function node's children, making this
+ // child redundant.
+ return false;
+ case glslang::EOpFunctionCall:
+ {
+ if (node->isUserDefined())
+ result = handleUserFunctionCall(node);
+ else
+ result = handleBuiltInFunctionCall(node);
+
+ if (! result) {
+ spv::MissingFunctionality("glslang function call");
+ glslang::TConstUnionArray emptyConsts;
+ int nextConst = 0;
+ result = createSpvConstant(node->getType(), emptyConsts, nextConst);
+ }
+ builder.clearAccessChain();
+ builder.setAccessChainRValue(result);
+
+ return false;
+ }
+ case glslang::EOpConstructMat2x2:
+ case glslang::EOpConstructMat2x3:
+ case glslang::EOpConstructMat2x4:
+ case glslang::EOpConstructMat3x2:
+ case glslang::EOpConstructMat3x3:
+ case glslang::EOpConstructMat3x4:
+ case glslang::EOpConstructMat4x2:
+ case glslang::EOpConstructMat4x3:
+ case glslang::EOpConstructMat4x4:
+ case glslang::EOpConstructDMat2x2:
+ case glslang::EOpConstructDMat2x3:
+ case glslang::EOpConstructDMat2x4:
+ case glslang::EOpConstructDMat3x2:
+ case glslang::EOpConstructDMat3x3:
+ case glslang::EOpConstructDMat3x4:
+ case glslang::EOpConstructDMat4x2:
+ case glslang::EOpConstructDMat4x3:
+ case glslang::EOpConstructDMat4x4:
+ isMatrix = true;
+ // fall through
+ case glslang::EOpConstructFloat:
+ case glslang::EOpConstructVec2:
+ case glslang::EOpConstructVec3:
+ case glslang::EOpConstructVec4:
+ case glslang::EOpConstructDouble:
+ case glslang::EOpConstructDVec2:
+ case glslang::EOpConstructDVec3:
+ case glslang::EOpConstructDVec4:
+ case glslang::EOpConstructBool:
+ case glslang::EOpConstructBVec2:
+ case glslang::EOpConstructBVec3:
+ case glslang::EOpConstructBVec4:
+ case glslang::EOpConstructInt:
+ case glslang::EOpConstructIVec2:
+ case glslang::EOpConstructIVec3:
+ case glslang::EOpConstructIVec4:
+ case glslang::EOpConstructUint:
+ case glslang::EOpConstructUVec2:
+ case glslang::EOpConstructUVec3:
+ case glslang::EOpConstructUVec4:
+ case glslang::EOpConstructStruct:
+ {
+ std::vector<spv::Id> arguments;
+ translateArguments(node->getSequence(), arguments);
+ spv::Id resultTypeId = convertGlslangToSpvType(node->getType());
+ spv::Id constructed;
+ if (node->getOp() == glslang::EOpConstructStruct || node->getType().isArray()) {
+ std::vector<spv::Id> constituents;
+ for (int c = 0; c < (int)arguments.size(); ++c)
+ constituents.push_back(arguments[c]);
+ constructed = builder.createCompositeConstruct(resultTypeId, constituents);
+ } else {
+ if (isMatrix)
+ constructed = builder.createMatrixConstructor(precision, arguments, resultTypeId);
+ else
+ constructed = builder.createConstructor(precision, arguments, resultTypeId);
+ }
+
+ builder.clearAccessChain();
+ builder.setAccessChainRValue(constructed);
+
+ return false;
+ }
+
+ // These six are component-wise compares with component-wise results.
+ // Forward on to createBinaryOperation(), requesting a vector result.
+ case glslang::EOpLessThan:
+ case glslang::EOpGreaterThan:
+ case glslang::EOpLessThanEqual:
+ case glslang::EOpGreaterThanEqual:
+ case glslang::EOpVectorEqual:
+ case glslang::EOpVectorNotEqual:
+ {
+ // Map the operation to a binary
+ binOp = node->getOp();
+ reduceComparison = false;
+ switch (node->getOp()) {
+ case glslang::EOpVectorEqual: binOp = glslang::EOpVectorEqual; break;
+ case glslang::EOpVectorNotEqual: binOp = glslang::EOpVectorNotEqual; break;
+ default: binOp = node->getOp(); break;
+ }
+
+ break;
+ }
+ case glslang::EOpMul:
+ // compontent-wise matrix multiply
+ binOp = glslang::EOpMul;
+ break;
+ case glslang::EOpOuterProduct:
+ // two vectors multiplied to make a matrix
+ binOp = glslang::EOpOuterProduct;
+ break;
+ case glslang::EOpDot:
+ {
+ // for scalar dot product, use multiply
+ glslang::TIntermSequence& glslangOperands = node->getSequence();
+ if (! glslangOperands[0]->getAsTyped()->isVector())
+ binOp = glslang::EOpMul;
+ break;
+ }
+ case glslang::EOpMod:
+ // when an aggregate, this is the floating-point mod built-in function,
+ // which can be emitted by the one in createBinaryOperation()
+ binOp = glslang::EOpMod;
+ break;
+ case glslang::EOpArrayLength:
+ {
+ glslang::TIntermTyped* typedNode = node->getSequence()[0]->getAsTyped();
+ assert(typedNode);
+ spv::Id length = builder.makeIntConstant(typedNode->getType().getArraySize());
+
+ builder.clearAccessChain();
+ builder.setAccessChainRValue(length);
+
+ return false;
+ }
+ case glslang::EOpEmitVertex:
+ case glslang::EOpEndPrimitive:
+ case glslang::EOpBarrier:
+ case glslang::EOpMemoryBarrier:
+ case glslang::EOpMemoryBarrierAtomicCounter:
+ case glslang::EOpMemoryBarrierBuffer:
+ case glslang::EOpMemoryBarrierImage:
+ case glslang::EOpMemoryBarrierShared:
+ case glslang::EOpGroupMemoryBarrier:
+ noReturnValue = true;
+ // These all have 0 operands and will naturally finish up in the code below for 0 operands
+ break;
+
+ default:
+ break;
+ }
+
+ //
+ // See if it maps to a regular operation.
+ //
+
+ if (binOp != glslang::EOpNull) {
+ glslang::TIntermTyped* left = node->getSequence()[0]->getAsTyped();
+ glslang::TIntermTyped* right = node->getSequence()[1]->getAsTyped();
+ assert(left && right);
+
+ builder.clearAccessChain();
+ left->traverse(this);
+ spv::Id leftId = builder.accessChainLoad(TranslatePrecisionDecoration(left->getType()));
+
+ builder.clearAccessChain();
+ right->traverse(this);
+ spv::Id rightId = builder.accessChainLoad(TranslatePrecisionDecoration(right->getType()));
+
+ result = createBinaryOperation(binOp, precision,
+ convertGlslangToSpvType(node->getType()), leftId, rightId,
+ left->getType().getBasicType(), reduceComparison);
+
+ // code above should only make binOp that exists in createBinaryOperation
+ if (result == 0)
+ spv::MissingFunctionality("createBinaryOperation for aggregate");
+
+ builder.clearAccessChain();
+ builder.setAccessChainRValue(result);
+
+ return false;
+ }
+
+ glslang::TIntermSequence& glslangOperands = node->getSequence();
+ std::vector<spv::Id> operands;
+ for (int arg = 0; arg < (int)glslangOperands.size(); ++arg) {
+ builder.clearAccessChain();
+ glslangOperands[arg]->traverse(this);
+
+ // special case l-value operands; there are just a few
+ bool lvalue = false;
+ switch (node->getOp()) {
+ //case glslang::EOpFrexp:
+ case glslang::EOpModf:
+ if (arg == 1)
+ lvalue = true;
+ break;
+ //case glslang::EOpUAddCarry:
+ //case glslang::EOpUSubBorrow:
+ //case glslang::EOpUMulExtended:
+ default:
+ break;
+ }
+ if (lvalue)
+ operands.push_back(builder.accessChainGetLValue());
+ else
+ operands.push_back(builder.accessChainLoad(TranslatePrecisionDecoration(glslangOperands[arg]->getAsTyped()->getType())));
+ }
+ switch (glslangOperands.size()) {
+ case 0:
+ result = createNoArgOperation(node->getOp());
+ break;
+ case 1:
+ result = createUnaryOperation(node->getOp(), precision, convertGlslangToSpvType(node->getType()), operands.front(), node->getType().getBasicType() == glslang::EbtFloat || node->getType().getBasicType() == glslang::EbtDouble);
+ break;
+ default:
+ result = createMiscOperation(node->getOp(), precision, convertGlslangToSpvType(node->getType()), operands);
+ break;
+ }
+
+ if (noReturnValue)
+ return false;
+
+ if (! result) {
+ spv::MissingFunctionality("glslang aggregate");
+ return true;
+ } else {
+ builder.clearAccessChain();
+ builder.setAccessChainRValue(result);
+ return false;
+ }
+}
+
+bool TGlslangToSpvTraverser::visitSelection(glslang::TVisit /* visit */, glslang::TIntermSelection* node)
+{
+ // This path handles both if-then-else and ?:
+ // The if-then-else has a node type of void, while
+ // ?: has a non-void node type
+ spv::Id result = 0;
+ if (node->getBasicType() != glslang::EbtVoid) {
+ // don't handle this as just on-the-fly temporaries, because there will be two names
+ // and better to leave SSA to later passes
+ result = builder.createVariable(spv::StorageClassFunction, convertGlslangToSpvType(node->getType()));
+ }
+
+ // emit the condition before doing anything with selection
+ node->getCondition()->traverse(this);
+
+ // make an "if" based on the value created by the condition
+ spv::Builder::If ifBuilder(builder.accessChainLoad(spv::NoPrecision), builder);
+
+ if (node->getTrueBlock()) {
+ // emit the "then" statement
+ node->getTrueBlock()->traverse(this);
+ if (result)
+ builder.createStore(builder.accessChainLoad(TranslatePrecisionDecoration(node->getTrueBlock()->getAsTyped()->getType())), result);
+ }
+
+ if (node->getFalseBlock()) {
+ ifBuilder.makeBeginElse();
+ // emit the "else" statement
+ node->getFalseBlock()->traverse(this);
+ if (result)
+ builder.createStore(builder.accessChainLoad(TranslatePrecisionDecoration(node->getFalseBlock()->getAsTyped()->getType())), result);
+ }
+
+ ifBuilder.makeEndIf();
+
+ if (result) {
+ // GLSL only has r-values as the result of a :?, but
+ // if we have an l-value, that can be more efficient if it will
+ // become the base of a complex r-value expression, because the
+ // next layer copies r-values into memory to use the access-chain mechanism
+ builder.clearAccessChain();
+ builder.setAccessChainLValue(result);
+ }
+
+ return false;
+}
+
+bool TGlslangToSpvTraverser::visitSwitch(glslang::TVisit /* visit */, glslang::TIntermSwitch* node)
+{
+ // emit and get the condition before doing anything with switch
+ node->getCondition()->traverse(this);
+ spv::Id selector = builder.accessChainLoad(TranslatePrecisionDecoration(node->getCondition()->getAsTyped()->getType()));
+
+ // browse the children to sort out code segments
+ int defaultSegment = -1;
+ std::vector<TIntermNode*> codeSegments;
+ glslang::TIntermSequence& sequence = node->getBody()->getSequence();
+ std::vector<int> caseValues;
+ std::vector<int> valueIndexToSegment(sequence.size()); // note: probably not all are used, it is an overestimate
+ for (glslang::TIntermSequence::iterator c = sequence.begin(); c != sequence.end(); ++c) {
+ TIntermNode* child = *c;
+ if (child->getAsBranchNode() && child->getAsBranchNode()->getFlowOp() == glslang::EOpDefault)
+ defaultSegment = codeSegments.size();
+ else if (child->getAsBranchNode() && child->getAsBranchNode()->getFlowOp() == glslang::EOpCase) {
+ valueIndexToSegment[caseValues.size()] = codeSegments.size();
+ caseValues.push_back(child->getAsBranchNode()->getExpression()->getAsConstantUnion()->getConstArray()[0].getIConst());
+ } else
+ codeSegments.push_back(child);
+ }
+
+ // handle the case where the last code segment is missing, due to no code
+ // statements between the last case and the end of the switch statement
+ if ((caseValues.size() && (int)codeSegments.size() == valueIndexToSegment[caseValues.size() - 1]) ||
+ (int)codeSegments.size() == defaultSegment)
+ codeSegments.push_back(nullptr);
+
+ // make the switch statement
+ std::vector<spv::Block*> segmentBlocks; // returned, as the blocks allocated in the call
+ builder.makeSwitch(selector, codeSegments.size(), caseValues, valueIndexToSegment, defaultSegment, segmentBlocks);
+
+ // emit all the code in the segments
+ breakForLoop.push(false);
+ for (unsigned int s = 0; s < codeSegments.size(); ++s) {
+ builder.nextSwitchSegment(segmentBlocks, s);
+ if (codeSegments[s])
+ codeSegments[s]->traverse(this);
+ else
+ builder.addSwitchBreak();
+ }
+ breakForLoop.pop();
+
+ builder.endSwitch(segmentBlocks);
+
+ return false;
+}
+
+void TGlslangToSpvTraverser::visitConstantUnion(glslang::TIntermConstantUnion* node)
+{
+ int nextConst = 0;
+ spv::Id constant = createSpvConstant(node->getType(), node->getConstArray(), nextConst);
+
+ builder.clearAccessChain();
+ builder.setAccessChainRValue(constant);
+}
+
+bool TGlslangToSpvTraverser::visitLoop(glslang::TVisit /* visit */, glslang::TIntermLoop* node)
+{
+ // body emission needs to know what the for-loop terminal is when it sees a "continue"
+ loopTerminal.push(node->getTerminal());
+
+ builder.makeNewLoop();
+
+ bool bodyOut = false;
+ if (! node->testFirst()) {
+ builder.endLoopHeaderWithoutTest();
+ if (node->getBody()) {
+ breakForLoop.push(true);
+ node->getBody()->traverse(this);
+ breakForLoop.pop();
+ }
+ bodyOut = true;
+ builder.createBranchToLoopTest();
+ }
+
+ if (node->getTest()) {
+ node->getTest()->traverse(this);
+ // the AST only contained the test computation, not the branch, we have to add it
+ spv::Id condition = builder.accessChainLoad(TranslatePrecisionDecoration(node->getTest()->getType()));
+ builder.createLoopTestBranch(condition);
+ }
+
+ if (! bodyOut && node->getBody()) {
+ breakForLoop.push(true);
+ node->getBody()->traverse(this);
+ breakForLoop.pop();
+ }
+
+ if (loopTerminal.top())
+ loopTerminal.top()->traverse(this);
+
+ builder.closeLoop();
+
+ loopTerminal.pop();
+
+ return false;
+}
+
+bool TGlslangToSpvTraverser::visitBranch(glslang::TVisit /* visit */, glslang::TIntermBranch* node)
+{
+ if (node->getExpression())
+ node->getExpression()->traverse(this);
+
+ switch (node->getFlowOp()) {
+ case glslang::EOpKill:
+ builder.makeDiscard();
+ break;
+ case glslang::EOpBreak:
+ if (breakForLoop.top())
+ builder.createLoopExit();
+ else
+ builder.addSwitchBreak();
+ break;
+ case glslang::EOpContinue:
+ if (loopTerminal.top())
+ loopTerminal.top()->traverse(this);
+ builder.createLoopContinue();
+ break;
+ case glslang::EOpReturn:
+ if (inMain)
+ builder.makeMainReturn();
+ else if (node->getExpression())
+ builder.makeReturn(false, builder.accessChainLoad(TranslatePrecisionDecoration(node->getExpression()->getType())));
+ else
+ builder.makeReturn();
+
+ builder.clearAccessChain();
+ break;
+
+ default:
+ spv::MissingFunctionality("branch type");
+ break;
+ }
+
+ return false;
+}
+
+spv::Id TGlslangToSpvTraverser::createSpvVariable(const glslang::TIntermSymbol* node)
+{
+ // First, steer off constants, which are not SPIR-V variables, but
+ // can still have a mapping to a SPIR-V Id.
+ if (node->getQualifier().storage == glslang::EvqConst) {
+ int nextConst = 0;
+ return createSpvConstant(node->getType(), node->getConstArray(), nextConst);
+ }
+
+ // Now, handle actual variables
+ spv::StorageClass storageClass = TranslateStorageClass(node->getType());
+ spv::Id spvType = convertGlslangToSpvType(node->getType());
+
+ const char* name = node->getName().c_str();
+ if (glslang::IsAnonymous(name))
+ name = "";
+
+ return builder.createVariable(storageClass, spvType, name);
+}
+
+// Return type Id of the sampled type.
+spv::Id TGlslangToSpvTraverser::getSampledType(const glslang::TSampler& sampler)
+{
+ switch (sampler.type) {
+ case glslang::EbtFloat: return builder.makeFloatType(32);
+ case glslang::EbtInt: return builder.makeIntType(32);
+ case glslang::EbtUint: return builder.makeUintType(32);
+ default:
+ spv::MissingFunctionality("sampled type");
+ return builder.makeFloatType(32);
+ }
+}
+
+// Do full recursive conversion of an arbitrary glslang type to a SPIR-V Id.
+spv::Id TGlslangToSpvTraverser::convertGlslangToSpvType(const glslang::TType& type)
+{
+ spv::Id spvType = 0;
+
+ switch (type.getBasicType()) {
+ case glslang::EbtVoid:
+ spvType = builder.makeVoidType();
+ if (type.isArray())
+ spv::MissingFunctionality("array of void");
+ break;
+ case glslang::EbtFloat:
+ spvType = builder.makeFloatType(32);
+ break;
+ case glslang::EbtDouble:
+ spvType = builder.makeFloatType(64);
+ break;
+ case glslang::EbtBool:
+ spvType = builder.makeBoolType();
+ break;
+ case glslang::EbtInt:
+ spvType = builder.makeIntType(32);
+ break;
+ case glslang::EbtUint:
+ spvType = builder.makeUintType(32);
+ break;
+ case glslang::EbtSampler:
+ {
+ const glslang::TSampler& sampler = type.getSampler();
+ spvType = builder.makeSampler(getSampledType(sampler), TranslateDimensionality(sampler),
+ sampler.image ? spv::Builder::samplerContentImage : spv::Builder::samplerContentTextureFilter,
+ sampler.arrayed, sampler.shadow, sampler.ms);
+ }
+ break;
+ case glslang::EbtStruct:
+ case glslang::EbtBlock:
+ {
+ // If we've seen this struct type, return it
+ const glslang::TTypeList* glslangStruct = type.getStruct();
+ std::vector<spv::Id> structFields;
+ spvType = structMap[glslangStruct];
+ if (spvType)
+ break;
+
+ // else, we haven't seen it...
+
+ // Create a vector of struct types for SPIR-V to consume
+ int memberDelta = 0; // how much the member's index changes from glslang to SPIR-V, normally 0, except sometimes for blocks
+ if (type.getBasicType() == glslang::EbtBlock)
+ memberRemapper[glslangStruct].resize(glslangStruct->size());
+ for (int i = 0; i < (int)glslangStruct->size(); i++) {
+ glslang::TType& glslangType = *(*glslangStruct)[i].type;
+ if (glslangType.hiddenMember()) {
+ ++memberDelta;
+ if (type.getBasicType() == glslang::EbtBlock)
+ memberRemapper[glslangStruct][i] = -1;
+ } else {
+ if (type.getBasicType() == glslang::EbtBlock)
+ memberRemapper[glslangStruct][i] = i - memberDelta;
+ structFields.push_back(convertGlslangToSpvType(glslangType));
+ }
+ }
+
+ // Make the SPIR-V type
+ spvType = builder.makeStructType(structFields, type.getTypeName().c_str());
+ structMap[glslangStruct] = spvType;
+
+ // Name and decorate the non-hidden members
+ for (int i = 0; i < (int)glslangStruct->size(); i++) {
+ glslang::TType& glslangType = *(*glslangStruct)[i].type;
+ int member = i;
+ if (type.getBasicType() == glslang::EbtBlock)
+ member = memberRemapper[glslangStruct][i];
+ // using -1 above to indicate a hidden member
+ if (member >= 0) {
+ builder.addMemberName(spvType, member, glslangType.getFieldName().c_str());
+ addMemberDecoration(spvType, member, TranslateLayoutDecoration(glslangType));
+ addMemberDecoration(spvType, member, TranslatePrecisionDecoration(glslangType));
+ addMemberDecoration(spvType, member, TranslateInterpolationDecoration(glslangType));
+ addMemberDecoration(spvType, member, TranslateInvariantDecoration(glslangType));
+ if (glslangType.getQualifier().hasLocation())
+ builder.addMemberDecoration(spvType, member, spv::DecorationLocation, glslangType.getQualifier().layoutLocation);
+ if (glslangType.getQualifier().hasComponent())
+ builder.addMemberDecoration(spvType, member, spv::DecorationComponent, glslangType.getQualifier().layoutComponent);
+ if (glslangType.getQualifier().hasXfbOffset())
+ builder.addMemberDecoration(spvType, member, spv::DecorationOffset, glslangType.getQualifier().layoutXfbOffset);
+
+ // built-in variable decorations
+ int builtIn = TranslateBuiltInDecoration(glslangType.getQualifier().builtIn);
+ if (builtIn != spv::BadValue)
+ builder.addMemberDecoration(spvType, member, spv::DecorationBuiltIn, builtIn);
+ }
+ }
+
+ // Decorate the structure
+ addDecoration(spvType, TranslateLayoutDecoration(type));
+ addDecoration(spvType, TranslateBlockDecoration(type));
+ if (type.getQualifier().hasStream())
+ builder.addDecoration(spvType, spv::DecorationStream, type.getQualifier().layoutStream);
+ if (glslangIntermediate->getXfbMode()) {
+ if (type.getQualifier().hasXfbStride())
+ builder.addDecoration(spvType, spv::DecorationStride, type.getQualifier().layoutXfbStride);
+ if (type.getQualifier().hasXfbBuffer())
+ builder.addDecoration(spvType, spv::DecorationXfbBuffer, type.getQualifier().layoutXfbBuffer);
+ }
+ }
+ break;
+ default:
+ spv::MissingFunctionality("basic type");
+ break;
+ }
+
+ if (type.isMatrix())
+ spvType = builder.makeMatrixType(spvType, type.getMatrixCols(), type.getMatrixRows());
+ else {
+ // If this variable has a vector element count greater than 1, create a SPIR-V vector
+ if (type.getVectorSize() > 1)
+ spvType = builder.makeVectorType(spvType, type.getVectorSize());
+ }
+
+ if (type.isArray()) {
+ unsigned arraySize;
+ if (! type.isExplicitlySizedArray()) {
+ spv::MissingFunctionality("Unsized array");
+ arraySize = 8;
+ } else
+ arraySize = type.getArraySize();
+ spvType = builder.makeArrayType(spvType, arraySize);
+ }
+
+ return spvType;
+}
+
+bool TGlslangToSpvTraverser::isShaderEntrypoint(const glslang::TIntermAggregate* node)
+{
+ return node->getName() == "main(";
+}
+
+// Make all the functions, skeletally, without actually visiting their bodies.
+void TGlslangToSpvTraverser::makeFunctions(const glslang::TIntermSequence& glslFunctions)
+{
+ for (int f = 0; f < (int)glslFunctions.size(); ++f) {
+ glslang::TIntermAggregate* glslFunction = glslFunctions[f]->getAsAggregate();
+ if (! glslFunction || glslFunction->getOp() != glslang::EOpFunction || isShaderEntrypoint(glslFunction))
+ continue;
+
+ // We're on a user function. Set up the basic interface for the function now,
+ // so that it's available to call.
+ // Translating the body will happen later.
+ //
+ // Typically (except for a "const in" parameter), an address will be passed to the
+ // function. What it is an address of varies:
+ //
+ // - "in" parameters not marked as "const" can be written to without modifying the argument,
+ // so that write needs to be to a copy, hence the address of a copy works.
+ //
+ // - "const in" parameters can just be the r-value, as no writes need occur.
+ //
+ // - "out" and "inout" arguments can't be done as direct pointers, because GLSL has
+ // copy-in/copy-out semantics. They can be handled though with a pointer to a copy.
+
+ std::vector<spv::Id> paramTypes;
+ glslang::TIntermSequence& parameters = glslFunction->getSequence()[0]->getAsAggregate()->getSequence();
+
+ for (int p = 0; p < (int)parameters.size(); ++p) {
+ const glslang::TType& paramType = parameters[p]->getAsTyped()->getType();
+ spv::Id typeId = convertGlslangToSpvType(paramType);
+ if (paramType.getQualifier().storage != glslang::EvqConstReadOnly)
+ typeId = builder.makePointer(spv::StorageClassFunction, typeId);
+ else
+ constReadOnlyParameters.insert(parameters[p]->getAsSymbolNode()->getId());
+ paramTypes.push_back(typeId);
+ }
+
+ spv::Block* functionBlock;
+ spv::Function *function = builder.makeFunctionEntry(convertGlslangToSpvType(glslFunction->getType()), glslFunction->getName().c_str(),
+ paramTypes, &functionBlock);
+
+ // Track function to emit/call later
+ functionMap[glslFunction->getName().c_str()] = function;
+
+ // Set the parameter id's
+ for (int p = 0; p < (int)parameters.size(); ++p) {
+ symbolValues[parameters[p]->getAsSymbolNode()->getId()] = function->getParamId(p);
+ // give a name too
+ builder.addName(function->getParamId(p), parameters[p]->getAsSymbolNode()->getName().c_str());
+ }
+ }
+}
+
+// Process all the initializers, while skipping the functions and link objects
+void TGlslangToSpvTraverser::makeGlobalInitializers(const glslang::TIntermSequence& initializers)
+{
+ builder.setBuildPoint(shaderEntry->getLastBlock());
+ for (int i = 0; i < (int)initializers.size(); ++i) {
+ glslang::TIntermAggregate* initializer = initializers[i]->getAsAggregate();
+ if (initializer && initializer->getOp() != glslang::EOpFunction && initializer->getOp() != glslang::EOpLinkerObjects) {
+
+ // We're on a top-level node that's not a function. Treat as an initializer, whose
+ // code goes into the beginning of main.
+ initializer->traverse(this);
+ }
+ }
+}
+
+// Process all the functions, while skipping initializers.
+void TGlslangToSpvTraverser::visitFunctions(const glslang::TIntermSequence& glslFunctions)
+{
+ for (int f = 0; f < (int)glslFunctions.size(); ++f) {
+ glslang::TIntermAggregate* node = glslFunctions[f]->getAsAggregate();
+ if (node && (node->getOp() == glslang::EOpFunction || node->getOp() == glslang ::EOpLinkerObjects))
+ node->traverse(this);
+ }
+}
+
+void TGlslangToSpvTraverser::handleFunctionEntry(const glslang::TIntermAggregate* node)
+{
+ // SPIR-V functions should already be in the functionMap from the prepass
+ // that called makeFunctions().
+ spv::Function* function = functionMap[node->getName().c_str()];
+ spv::Block* functionBlock = function->getEntryBlock();
+ builder.setBuildPoint(functionBlock);
+}
+
+void TGlslangToSpvTraverser::translateArguments(const glslang::TIntermSequence& glslangArguments, std::vector<spv::Id>& arguments)
+{
+ for (int i = 0; i < (int)glslangArguments.size(); ++i) {
+ builder.clearAccessChain();
+ glslangArguments[i]->traverse(this);
+ arguments.push_back(builder.accessChainLoad(TranslatePrecisionDecoration(glslangArguments[i]->getAsTyped()->getType())));
+ }
+}
+
+spv::Id TGlslangToSpvTraverser::handleBuiltInFunctionCall(const glslang::TIntermAggregate* node)
+{
+ std::vector<spv::Id> arguments;
+ translateArguments(node->getSequence(), arguments);
+
+ std::vector<spv::Id> argTypes;
+ for (int a = 0; a < (int)arguments.size(); ++a)
+ argTypes.push_back(builder.getTypeId(arguments[a]));
+
+ spv::Decoration precision = TranslatePrecisionDecoration(node->getType());
+
+ if (node->getName() == "ftransform(") {
+ spv::MissingFunctionality("ftransform()");
+ //spv::Id vertex = builder.createVariable(spv::StorageShaderGlobal, spv::VectorType::get(spv::makeFloatType(), 4),
+ // "gl_Vertex_sim");
+ //spv::Id matrix = builder.createVariable(spv::StorageShaderGlobal, spv::VectorType::get(spv::makeFloatType(), 4),
+ // "gl_ModelViewProjectionMatrix_sim");
+ return 0;
+ }
+
+ if (node->getName().substr(0, 7) == "texture" || node->getName().substr(0, 5) == "texel" || node->getName().substr(0, 6) == "shadow") {
+ const glslang::TSampler sampler = node->getSequence()[0]->getAsTyped()->getType().getSampler();
+ spv::Builder::TextureParameters params = { };
+ params.sampler = arguments[0];
+
+ // special case size query
+ if (node->getName().find("textureSize", 0) != std::string::npos) {
+ if (arguments.size() > 1) {
+ params.lod = arguments[1];
+ return builder.createTextureQueryCall(spv::OpTextureQuerySizeLod, params);
+ } else
+ return builder.createTextureQueryCall(spv::OpTextureQuerySize, params);
+ }
+
+ // special case the number of samples query
+ if (node->getName().find("textureSamples", 0) != std::string::npos)
+ return builder.createTextureQueryCall(spv::OpTextureQuerySamples, params);
+
+ // special case the other queries
+ if (node->getName().find("Query", 0) != std::string::npos) {
+ if (node->getName().find("Levels", 0) != std::string::npos)
+ return builder.createTextureQueryCall(spv::OpTextureQueryLevels, params);
+ else if (node->getName().find("Lod", 0) != std::string::npos) {
+ params.coords = arguments[1];
+ return builder.createTextureQueryCall(spv::OpTextureQueryLod, params);
+ } else
+ spv::MissingFunctionality("glslang texture query");
+ }
+
+ // This is no longer a query....
+
+ bool lod = node->getName().find("Lod", 0) != std::string::npos;
+ bool proj = node->getName().find("Proj", 0) != std::string::npos;
+ bool offsets = node->getName().find("Offsets", 0) != std::string::npos;
+ bool offset = ! offsets && node->getName().find("Offset", 0) != std::string::npos;
+ bool fetch = node->getName().find("Fetch", 0) != std::string::npos;
+ bool gather = node->getName().find("Gather", 0) != std::string::npos;
+ bool grad = node->getName().find("Grad", 0) != std::string::npos;
+
+ if (fetch)
+ spv::MissingFunctionality("texel fetch");
+ if (gather)
+ spv::MissingFunctionality("texture gather");
+
+ // check for bias argument
+ bool bias = false;
+ if (! lod && ! gather && ! grad && ! fetch) {
+ int nonBiasArgCount = 2;
+ if (offset)
+ ++nonBiasArgCount;
+ if (grad)
+ nonBiasArgCount += 2;
+
+ if ((int)arguments.size() > nonBiasArgCount)
+ bias = true;
+ }
+
+ bool cubeCompare = sampler.dim == glslang::EsdCube && sampler.arrayed && sampler.shadow;
+
+ // set the rest of the arguments
+ params.coords = arguments[1];
+ int extraArgs = 0;
+ if (cubeCompare)
+ params.Dref = arguments[2];
+ if (lod) {
+ params.lod = arguments[2];
+ ++extraArgs;
+ }
+ if (grad) {
+ params.gradX = arguments[2 + extraArgs];
+ params.gradY = arguments[3 + extraArgs];
+ extraArgs += 2;
+ }
+ //if (gather && compare) {
+ // params.compare = arguments[2 + extraArgs];
+ // ++extraArgs;
+ //}
+ if (offset | offsets) {
+ params.offset = arguments[2 + extraArgs];
+ ++extraArgs;
+ }
+ if (bias) {
+ params.bias = arguments[2 + extraArgs];
+ ++extraArgs;
+ }
+
+ return builder.createTextureCall(precision, convertGlslangToSpvType(node->getType()), proj, params);
+ }
+
+ spv::MissingFunctionality("built-in function call");
+
+ return 0;
+}
+
+spv::Id TGlslangToSpvTraverser::handleUserFunctionCall(const glslang::TIntermAggregate* node)
+{
+ // Grab the function's pointer from the previously created function
+ spv::Function* function = functionMap[node->getName().c_str()];
+ if (! function)
+ return 0;
+
+ const glslang::TIntermSequence& glslangArgs = node->getSequence();
+ const glslang::TQualifierList& qualifiers = node->getQualifierList();
+
+ // See comments in makeFunctions() for details about the semantics for parameter passing.
+ //
+ // These imply we need a four step process:
+ // 1. Evaluate the arguments
+ // 2. Allocate and make copies of in, out, and inout arguments
+ // 3. Make the call
+ // 4. Copy back the results
+
+ // 1. Evaluate the arguments
+ std::vector<spv::Builder::AccessChain> lValues;
+ std::vector<spv::Id> rValues;
+ for (int a = 0; a < (int)glslangArgs.size(); ++a) {
+ // build l-value
+ builder.clearAccessChain();
+ glslangArgs[a]->traverse(this);
+ // keep outputs as l-values, evaluate input-only as r-values
+ if (qualifiers[a] != glslang::EvqConstReadOnly) {
+ // save l-value
+ lValues.push_back(builder.getAccessChain());
+ } else {
+ // process r-value
+ rValues.push_back(builder.accessChainLoad(TranslatePrecisionDecoration(glslangArgs[a]->getAsTyped()->getType())));
+ }
+ }
+
+ // 2. Allocate space for anything needing a copy, and if it's "in" or "inout"
+ // copy the original into that space.
+ //
+ // Also, build up the list of actual arguments to pass in for the call
+ int lValueCount = 0;
+ int rValueCount = 0;
+ std::vector<spv::Id> spvArgs;
+ for (int a = 0; a < (int)glslangArgs.size(); ++a) {
+ spv::Id arg;
+ if (qualifiers[a] != glslang::EvqConstReadOnly) {
+ // need space to hold the copy
+ const glslang::TType& paramType = glslangArgs[a]->getAsTyped()->getType();
+ arg = builder.createVariable(spv::StorageClassFunction, convertGlslangToSpvType(paramType), "param");
+ if (qualifiers[a] == glslang::EvqIn || qualifiers[a] == glslang::EvqInOut) {
+ // need to copy the input into output space
+ builder.setAccessChain(lValues[lValueCount]);
+ spv::Id copy = builder.accessChainLoad(spv::NoPrecision); // TODO: get precision
+ builder.createStore(copy, arg);
+ }
+ ++lValueCount;
+ } else {
+ arg = rValues[rValueCount];
+ ++rValueCount;
+ }
+ spvArgs.push_back(arg);
+ }
+
+ // 3. Make the call.
+ spv::Id result = builder.createFunctionCall(function, spvArgs);
+
+ // 4. Copy back out an "out" arguments.
+ lValueCount = 0;
+ for (int a = 0; a < (int)glslangArgs.size(); ++a) {
+ if (qualifiers[a] != glslang::EvqConstReadOnly) {
+ if (qualifiers[a] == glslang::EvqOut || qualifiers[a] == glslang::EvqInOut) {
+ spv::Id copy = builder.createLoad(spvArgs[a]);
+ builder.setAccessChain(lValues[lValueCount]);
+ builder.accessChainStore(copy);
+ }
+ ++lValueCount;
+ }
+ }
+
+ return result;
+}
+
+// Translate AST operation to SPV operation, already having SPV-based operands/types.
+spv::Id TGlslangToSpvTraverser::createBinaryOperation(glslang::TOperator op, spv::Decoration precision,
+ spv::Id typeId, spv::Id left, spv::Id right,
+ glslang::TBasicType typeProxy, bool reduceComparison)
+{
+ bool isUnsigned = typeProxy == glslang::EbtUint;
+ bool isFloat = typeProxy == glslang::EbtFloat || typeProxy == glslang::EbtDouble;
+
+ spv::Op binOp = spv::OpNop;
+ bool needsPromotion = true;
+ bool comparison = false;
+
+ switch (op) {
+ case glslang::EOpAdd:
+ case glslang::EOpAddAssign:
+ if (isFloat)
+ binOp = spv::OpFAdd;
+ else
+ binOp = spv::OpIAdd;
+ break;
+ case glslang::EOpSub:
+ case glslang::EOpSubAssign:
+ if (isFloat)
+ binOp = spv::OpFSub;
+ else
+ binOp = spv::OpISub;
+ break;
+ case glslang::EOpMul:
+ case glslang::EOpMulAssign:
+ if (isFloat)
+ binOp = spv::OpFMul;
+ else
+ binOp = spv::OpIMul;
+ break;
+ case glslang::EOpVectorTimesScalar:
+ case glslang::EOpVectorTimesScalarAssign:
+ if (builder.isVector(right))
+ std::swap(left, right);
+ assert(builder.isScalar(right));
+ binOp = spv::OpVectorTimesScalar;
+ needsPromotion = false;
+ break;
+ case glslang::EOpVectorTimesMatrix:
+ case glslang::EOpVectorTimesMatrixAssign:
+ assert(builder.isVector(left));
+ assert(builder.isMatrix(right));
+ binOp = spv::OpVectorTimesMatrix;
+ break;
+ case glslang::EOpMatrixTimesVector:
+ assert(builder.isMatrix(left));
+ assert(builder.isVector(right));
+ binOp = spv::OpMatrixTimesVector;
+ break;
+ case glslang::EOpMatrixTimesScalar:
+ case glslang::EOpMatrixTimesScalarAssign:
+ if (builder.isMatrix(right))
+ std::swap(left, right);
+ assert(builder.isScalar(right));
+ binOp = spv::OpMatrixTimesScalar;
+ break;
+ case glslang::EOpMatrixTimesMatrix:
+ case glslang::EOpMatrixTimesMatrixAssign:
+ assert(builder.isMatrix(left));
+ assert(builder.isMatrix(right));
+ binOp = spv::OpMatrixTimesMatrix;
+ break;
+ case glslang::EOpOuterProduct:
+ binOp = spv::OpOuterProduct;
+ needsPromotion = false;
+ break;
+
+ case glslang::EOpDiv:
+ case glslang::EOpDivAssign:
+ if (isFloat)
+ binOp = spv::OpFDiv;
+ else if (isUnsigned)
+ binOp = spv::OpUDiv;
+ else
+ binOp = spv::OpSDiv;
+ break;
+ case glslang::EOpMod:
+ case glslang::EOpModAssign:
+ if (isFloat)
+ binOp = spv::OpFMod;
+ else if (isUnsigned)
+ binOp = spv::OpUMod;
+ else
+ binOp = spv::OpSMod;
+ break;
+ case glslang::EOpRightShift:
+ case glslang::EOpRightShiftAssign:
+ if (isUnsigned)
+ binOp = spv::OpShiftRightLogical;
+ else
+ binOp = spv::OpShiftRightArithmetic;
+ break;
+ case glslang::EOpLeftShift:
+ case glslang::EOpLeftShiftAssign:
+ binOp = spv::OpShiftLeftLogical;
+ break;
+ case glslang::EOpAnd:
+ case glslang::EOpAndAssign:
+ binOp = spv::OpBitwiseAnd;
+ break;
+ case glslang::EOpLogicalAnd:
+ needsPromotion = false;
+ binOp = spv::OpLogicalAnd;
+ break;
+ case glslang::EOpInclusiveOr:
+ case glslang::EOpInclusiveOrAssign:
+ binOp = spv::OpBitwiseOr;
+ break;
+ case glslang::EOpLogicalOr:
+ needsPromotion = false;
+ binOp = spv::OpLogicalOr;
+ break;
+ case glslang::EOpExclusiveOr:
+ case glslang::EOpExclusiveOrAssign:
+ binOp = spv::OpBitwiseXor;
+ break;
+ case glslang::EOpLogicalXor:
+ needsPromotion = false;
+ binOp = spv::OpLogicalXor;
+ break;
+
+ case glslang::EOpLessThan:
+ case glslang::EOpGreaterThan:
+ case glslang::EOpLessThanEqual:
+ case glslang::EOpGreaterThanEqual:
+ case glslang::EOpEqual:
+ case glslang::EOpNotEqual:
+ case glslang::EOpVectorEqual:
+ case glslang::EOpVectorNotEqual:
+ comparison = true;
+ break;
+ default:
+ break;
+ }
+
+ if (binOp != spv::OpNop) {
+ if (builder.isMatrix(left) || builder.isMatrix(right)) {
+ switch (binOp) {
+ case spv::OpMatrixTimesScalar:
+ case spv::OpVectorTimesMatrix:
+ case spv::OpMatrixTimesVector:
+ case spv::OpMatrixTimesMatrix:
+ break;
+ case spv::OpFDiv:
+ // turn it into a multiply...
+ assert(builder.isMatrix(left) && builder.isScalar(right));
+ right = builder.createBinOp(spv::OpFDiv, builder.getTypeId(right), builder.makeFloatConstant(1.0F), right);
+ binOp = spv::OpFMul;
+ break;
+ default:
+ spv::MissingFunctionality("binary operation on matrix");
+ break;
+ }
+
+ spv::Id id = builder.createBinOp(binOp, typeId, left, right);
+ builder.setPrecision(id, precision);
+
+ return id;
+ }
+
+ // No matrix involved; make both operands be the same number of components, if needed
+ if (needsPromotion)
+ builder.promoteScalar(precision, left, right);
+
+ spv::Id id = builder.createBinOp(binOp, typeId, left, right);
+ builder.setPrecision(id, precision);
+
+ return id;
+ }
+
+ if (! comparison)
+ return 0;
+
+ // Comparison instructions
+
+ if (reduceComparison && (builder.isVector(left) || builder.isMatrix(left) || builder.isAggregate(left))) {
+ assert(op == glslang::EOpEqual || op == glslang::EOpNotEqual);
+
+ return builder.createCompare(precision, left, right, op == glslang::EOpEqual);
+ }
+
+ switch (op) {
+ case glslang::EOpLessThan:
+ if (isFloat)
+ binOp = spv::OpFOrdLessThan;
+ else if (isUnsigned)
+ binOp = spv::OpULessThan;
+ else
+ binOp = spv::OpSLessThan;
+ break;
+ case glslang::EOpGreaterThan:
+ if (isFloat)
+ binOp = spv::OpFOrdGreaterThan;
+ else if (isUnsigned)
+ binOp = spv::OpUGreaterThan;
+ else
+ binOp = spv::OpSGreaterThan;
+ break;
+ case glslang::EOpLessThanEqual:
+ if (isFloat)
+ binOp = spv::OpFOrdLessThanEqual;
+ else if (isUnsigned)
+ binOp = spv::OpULessThanEqual;
+ else
+ binOp = spv::OpSLessThanEqual;
+ break;
+ case glslang::EOpGreaterThanEqual:
+ if (isFloat)
+ binOp = spv::OpFOrdGreaterThanEqual;
+ else if (isUnsigned)
+ binOp = spv::OpUGreaterThanEqual;
+ else
+ binOp = spv::OpSGreaterThanEqual;
+ break;
+ case glslang::EOpEqual:
+ case glslang::EOpVectorEqual:
+ if (isFloat)
+ binOp = spv::OpFOrdEqual;
+ else
+ binOp = spv::OpIEqual;
+ break;
+ case glslang::EOpNotEqual:
+ case glslang::EOpVectorNotEqual:
+ if (isFloat)
+ binOp = spv::OpFOrdNotEqual;
+ else
+ binOp = spv::OpINotEqual;
+ break;
+ default:
+ break;
+ }
+
+ if (binOp != spv::OpNop) {
+ spv::Id id = builder.createBinOp(binOp, typeId, left, right);
+ builder.setPrecision(id, precision);
+
+ return id;
+ }
+
+ return 0;
+}
+
+spv::Id TGlslangToSpvTraverser::createUnaryOperation(glslang::TOperator op, spv::Decoration precision, spv::Id typeId, spv::Id operand, bool isFloat)
+{
+ spv::Op unaryOp = spv::OpNop;
+ int libCall = -1;
+
+ switch (op) {
+ case glslang::EOpNegative:
+ if (isFloat)
+ unaryOp = spv::OpFNegate;
+ else
+ unaryOp = spv::OpSNegate;
+ break;
+
+ case glslang::EOpLogicalNot:
+ case glslang::EOpVectorLogicalNot:
+ case glslang::EOpBitwiseNot:
+ unaryOp = spv::OpNot;
+ break;
+
+ case glslang::EOpDeterminant:
+ libCall = GLSL_STD_450::Determinant;
+ break;
+ case glslang::EOpMatrixInverse:
+ libCall = GLSL_STD_450::MatrixInverse;
+ break;
+ case glslang::EOpTranspose:
+ unaryOp = spv::OpTranspose;
+ break;
+
+ case glslang::EOpRadians:
+ libCall = GLSL_STD_450::Radians;
+ break;
+ case glslang::EOpDegrees:
+ libCall = GLSL_STD_450::Degrees;
+ break;
+ case glslang::EOpSin:
+ libCall = GLSL_STD_450::Sin;
+ break;
+ case glslang::EOpCos:
+ libCall = GLSL_STD_450::Cos;
+ break;
+ case glslang::EOpTan:
+ libCall = GLSL_STD_450::Tan;
+ break;
+ case glslang::EOpAcos:
+ libCall = GLSL_STD_450::Acos;
+ break;
+ case glslang::EOpAsin:
+ libCall = GLSL_STD_450::Asin;
+ break;
+ case glslang::EOpAtan:
+ libCall = GLSL_STD_450::Atan;
+ break;
+
+ case glslang::EOpAcosh:
+ libCall = GLSL_STD_450::Acosh;
+ break;
+ case glslang::EOpAsinh:
+ libCall = GLSL_STD_450::Asinh;
+ break;
+ case glslang::EOpAtanh:
+ libCall = GLSL_STD_450::Atanh;
+ break;
+ case glslang::EOpTanh:
+ libCall = GLSL_STD_450::Tanh;
+ break;
+ case glslang::EOpCosh:
+ libCall = GLSL_STD_450::Cosh;
+ break;
+ case glslang::EOpSinh:
+ libCall = GLSL_STD_450::Sinh;
+ break;
+
+ case glslang::EOpLength:
+ libCall = GLSL_STD_450::Length;
+ break;
+ case glslang::EOpNormalize:
+ libCall = GLSL_STD_450::Normalize;
+ break;
+
+ case glslang::EOpExp:
+ libCall = GLSL_STD_450::Exp;
+ break;
+ case glslang::EOpLog:
+ libCall = GLSL_STD_450::Log;
+ break;
+ case glslang::EOpExp2:
+ libCall = GLSL_STD_450::Exp2;
+ break;
+ case glslang::EOpLog2:
+ libCall = GLSL_STD_450::Log2;
+ break;
+ case glslang::EOpSqrt:
+ libCall = GLSL_STD_450::Sqrt;
+ break;
+ case glslang::EOpInverseSqrt:
+ libCall = GLSL_STD_450::InverseSqrt;
+ break;
+
+ case glslang::EOpFloor:
+ libCall = GLSL_STD_450::Floor;
+ break;
+ case glslang::EOpTrunc:
+ libCall = GLSL_STD_450::Trunc;
+ break;
+ case glslang::EOpRound:
+ libCall = GLSL_STD_450::Round;
+ break;
+ case glslang::EOpRoundEven:
+ libCall = GLSL_STD_450::RoundEven;
+ break;
+ case glslang::EOpCeil:
+ libCall = GLSL_STD_450::Ceil;
+ break;
+ case glslang::EOpFract:
+ libCall = GLSL_STD_450::Fract;
+ break;
+
+ case glslang::EOpIsNan:
+ unaryOp = spv::OpIsNan;
+ break;
+ case glslang::EOpIsInf:
+ unaryOp = spv::OpIsInf;
+ break;
+
+ case glslang::EOpFloatBitsToInt:
+ libCall = GLSL_STD_450::FloatBitsToInt;
+ break;
+ case glslang::EOpFloatBitsToUint:
+ libCall = GLSL_STD_450::FloatBitsToUint;
+ break;
+ case glslang::EOpIntBitsToFloat:
+ libCall = GLSL_STD_450::IntBitsToFloat;
+ break;
+ case glslang::EOpUintBitsToFloat:
+ libCall = GLSL_STD_450::UintBitsToFloat;
+ break;
+ case glslang::EOpPackSnorm2x16:
+ libCall = GLSL_STD_450::PackSnorm2x16;
+ break;
+ case glslang::EOpUnpackSnorm2x16:
+ libCall = GLSL_STD_450::UnpackSnorm2x16;
+ break;
+ case glslang::EOpPackUnorm2x16:
+ libCall = GLSL_STD_450::PackUnorm2x16;
+ break;
+ case glslang::EOpUnpackUnorm2x16:
+ libCall = GLSL_STD_450::UnpackUnorm2x16;
+ break;
+ case glslang::EOpPackHalf2x16:
+ libCall = GLSL_STD_450::PackHalf2x16;
+ break;
+ case glslang::EOpUnpackHalf2x16:
+ libCall = GLSL_STD_450::UnpackHalf2x16;
+ break;
+
+ case glslang::EOpDPdx:
+ unaryOp = spv::OpDPdx;
+ break;
+ case glslang::EOpDPdy:
+ unaryOp = spv::OpDPdy;
+ break;
+ case glslang::EOpFwidth:
+ unaryOp = spv::OpFwidth;
+ break;
+ case glslang::EOpDPdxFine:
+ unaryOp = spv::OpDPdxFine;
+ break;
+ case glslang::EOpDPdyFine:
+ unaryOp = spv::OpDPdyFine;
+ break;
+ case glslang::EOpFwidthFine:
+ unaryOp = spv::OpFwidthFine;
+ break;
+ case glslang::EOpDPdxCoarse:
+ unaryOp = spv::OpDPdxCoarse;
+ break;
+ case glslang::EOpDPdyCoarse:
+ unaryOp = spv::OpDPdyCoarse;
+ break;
+ case glslang::EOpFwidthCoarse:
+ unaryOp = spv::OpFwidthCoarse;
+ break;
+
+ case glslang::EOpAny:
+ unaryOp = spv::OpAny;
+ break;
+ case glslang::EOpAll:
+ unaryOp = spv::OpAll;
+ break;
+
+ case glslang::EOpAbs:
+ libCall = GLSL_STD_450::Abs;
+ break;
+ case glslang::EOpSign:
+ libCall = GLSL_STD_450::Sign;
+ break;
+
+ default:
+ return 0;
+ }
+
+ spv::Id id;
+ if (libCall >= 0) {
+ std::vector<spv::Id> args;
+ args.push_back(operand);
+ id = builder.createBuiltinCall(precision, typeId, stdBuiltins, libCall, args);
+ } else
+ id = builder.createUnaryOp(unaryOp, typeId, operand);
+
+ builder.setPrecision(id, precision);
+
+ return id;
+}
+
+spv::Id TGlslangToSpvTraverser::createConversion(glslang::TOperator op, spv::Decoration precision, spv::Id destType, spv::Id operand)
+{
+ spv::Op convOp = spv::OpNop;
+ spv::Id zero = 0;
+ spv::Id one = 0;
+
+ int vectorSize = builder.isVectorType(destType) ? builder.getNumTypeComponents(destType) : 0;
+
+ switch (op) {
+ case glslang::EOpConvIntToBool:
+ case glslang::EOpConvUintToBool:
+ zero = builder.makeUintConstant(0);
+ zero = makeSmearedConstant(zero, vectorSize);
+ return builder.createBinOp(spv::OpINotEqual, destType, operand, zero);
+
+ case glslang::EOpConvFloatToBool:
+ zero = builder.makeFloatConstant(0.0F);
+ zero = makeSmearedConstant(zero, vectorSize);
+ return builder.createBinOp(spv::OpFOrdNotEqual, destType, operand, zero);
+
+ case glslang::EOpConvDoubleToBool:
+ zero = builder.makeDoubleConstant(0.0);
+ zero = makeSmearedConstant(zero, vectorSize);
+ return builder.createBinOp(spv::OpFOrdNotEqual, destType, operand, zero);
+
+ case glslang::EOpConvBoolToFloat:
+ convOp = spv::OpSelect;
+ zero = builder.makeFloatConstant(0.0);
+ one = builder.makeFloatConstant(1.0);
+ break;
+ case glslang::EOpConvBoolToDouble:
+ convOp = spv::OpSelect;
+ zero = builder.makeDoubleConstant(0.0);
+ one = builder.makeDoubleConstant(1.0);
+ break;
+ case glslang::EOpConvBoolToInt:
+ zero = builder.makeIntConstant(0);
+ one = builder.makeIntConstant(1);
+ convOp = spv::OpSelect;
+ break;
+ case glslang::EOpConvBoolToUint:
+ zero = builder.makeUintConstant(0);
+ one = builder.makeUintConstant(1);
+ convOp = spv::OpSelect;
+ break;
+
+ case glslang::EOpConvIntToFloat:
+ case glslang::EOpConvIntToDouble:
+ convOp = spv::OpConvertSToF;
+ break;
+
+ case glslang::EOpConvUintToFloat:
+ case glslang::EOpConvUintToDouble:
+ convOp = spv::OpConvertUToF;
+ break;
+
+ case glslang::EOpConvDoubleToFloat:
+ case glslang::EOpConvFloatToDouble:
+ convOp = spv::OpFConvert;
+ break;
+
+ case glslang::EOpConvFloatToInt:
+ case glslang::EOpConvDoubleToInt:
+ convOp = spv::OpConvertFToS;
+ break;
+
+ case glslang::EOpConvUintToInt:
+ case glslang::EOpConvIntToUint:
+ convOp = spv::OpBitcast;
+ break;
+
+ case glslang::EOpConvFloatToUint:
+ case glslang::EOpConvDoubleToUint:
+ convOp = spv::OpConvertFToU;
+ break;
+ default:
+ break;
+ }
+
+ spv::Id result = 0;
+ if (convOp == spv::OpNop)
+ return result;
+
+ if (convOp == spv::OpSelect) {
+ zero = makeSmearedConstant(zero, vectorSize);
+ one = makeSmearedConstant(one, vectorSize);
+ result = builder.createTriOp(convOp, destType, operand, one, zero);
+ } else
+ result = builder.createUnaryOp(convOp, destType, operand);
+
+ builder.setPrecision(result, precision);
+
+ return result;
+}
+
+spv::Id TGlslangToSpvTraverser::makeSmearedConstant(spv::Id constant, int vectorSize)
+{
+ if (vectorSize == 0)
+ return constant;
+
+ spv::Id vectorTypeId = builder.makeVectorType(builder.getTypeId(constant), vectorSize);
+ std::vector<spv::Id> components;
+ for (int c = 0; c < vectorSize; ++c)
+ components.push_back(constant);
+ return builder.makeCompositeConstant(vectorTypeId, components);
+}
+
+spv::Id TGlslangToSpvTraverser::createMiscOperation(glslang::TOperator op, spv::Decoration precision, spv::Id typeId, std::vector<spv::Id>& operands)
+{
+ spv::Op opCode = spv::OpNop;
+ int libCall = -1;
+
+ switch (op) {
+ case glslang::EOpMin:
+ libCall = GLSL_STD_450::Min;
+ break;
+ case glslang::EOpModf:
+ libCall = GLSL_STD_450::Modf;
+ break;
+ case glslang::EOpMax:
+ libCall = GLSL_STD_450::Max;
+ break;
+ case glslang::EOpPow:
+ libCall = GLSL_STD_450::Pow;
+ break;
+ case glslang::EOpDot:
+ opCode = spv::OpDot;
+ break;
+ case glslang::EOpAtan:
+ libCall = GLSL_STD_450::Atan2;
+ break;
+
+ case glslang::EOpClamp:
+ libCall = GLSL_STD_450::Clamp;
+ break;
+ case glslang::EOpMix:
+ libCall = GLSL_STD_450::Mix;
+ break;
+ case glslang::EOpStep:
+ libCall = GLSL_STD_450::Step;
+ break;
+ case glslang::EOpSmoothStep:
+ libCall = GLSL_STD_450::SmoothStep;
+ break;
+
+ case glslang::EOpDistance:
+ libCall = GLSL_STD_450::Distance;
+ break;
+ case glslang::EOpCross:
+ libCall = GLSL_STD_450::Cross;
+ break;
+ case glslang::EOpFaceForward:
+ libCall = GLSL_STD_450::FaceForward;
+ break;
+ case glslang::EOpReflect:
+ libCall = GLSL_STD_450::Reflect;
+ break;
+ case glslang::EOpRefract:
+ libCall = GLSL_STD_450::Refract;
+ break;
+ default:
+ return 0;
+ }
+
+ spv::Id id = 0;
+ if (libCall >= 0)
+ id = builder.createBuiltinCall(precision, typeId, stdBuiltins, libCall, operands);
+ else {
+ switch (operands.size()) {
+ case 0:
+ // should all be handled by visitAggregate and createNoArgOperation
+ assert(0);
+ return 0;
+ case 1:
+ // should all be handled by createUnaryOperation
+ assert(0);
+ return 0;
+ case 2:
+ id = builder.createBinOp(opCode, typeId, operands[0], operands[1]);
+ break;
+ case 3:
+ id = builder.createTernaryOp(opCode, typeId, operands[0], operands[1], operands[2]);
+ break;
+ default:
+ // These do not exist yet
+ assert(0 && "operation with more than 3 operands");
+ break;
+ }
+ }
+
+ builder.setPrecision(id, precision);
+
+ return id;
+}
+
+// Intrinsics with no arguments, no return value, and no precision.
+spv::Id TGlslangToSpvTraverser::createNoArgOperation(glslang::TOperator op)
+{
+ // TODO: get the barrier operands correct
+
+ switch (op) {
+ case glslang::EOpEmitVertex:
+ builder.createNoResultOp(spv::OpEmitVertex);
+ return 0;
+ case glslang::EOpEndPrimitive:
+ builder.createNoResultOp(spv::OpEndPrimitive);
+ return 0;
+ case glslang::EOpBarrier:
+ builder.createMemoryBarrier(spv::ExecutionScopeDevice, spv::MemorySemanticsAllMemory);
+ builder.createControlBarrier(spv::ExecutionScopeDevice);
+ return 0;
+ case glslang::EOpMemoryBarrier:
+ builder.createMemoryBarrier(spv::ExecutionScopeDevice, spv::MemorySemanticsAllMemory);
+ return 0;
+ case glslang::EOpMemoryBarrierAtomicCounter:
+ builder.createMemoryBarrier(spv::ExecutionScopeDevice, spv::MemorySemanticsAtomicCounterMemoryMask);
+ return 0;
+ case glslang::EOpMemoryBarrierBuffer:
+ builder.createMemoryBarrier(spv::ExecutionScopeDevice, spv::MemorySemanticsUniformMemoryMask);
+ return 0;
+ case glslang::EOpMemoryBarrierImage:
+ builder.createMemoryBarrier(spv::ExecutionScopeDevice, spv::MemorySemanticsImageMemoryMask);
+ return 0;
+ case glslang::EOpMemoryBarrierShared:
+ builder.createMemoryBarrier(spv::ExecutionScopeDevice, spv::MemorySemanticsWorkgroupLocalMemoryMask);
+ return 0;
+ case glslang::EOpGroupMemoryBarrier:
+ builder.createMemoryBarrier(spv::ExecutionScopeDevice, spv::MemorySemanticsWorkgroupGlobalMemoryMask);
+ return 0;
+ default:
+ spv::MissingFunctionality("operation with no arguments");
+ return 0;
+ }
+}
+
+spv::Id TGlslangToSpvTraverser::getSymbolId(const glslang::TIntermSymbol* symbol)
+{
+ std::map<int, spv::Id>::iterator iter;
+ iter = symbolValues.find(symbol->getId());
+ spv::Id id;
+ if (symbolValues.end() != iter) {
+ id = iter->second;
+ return id;
+ }
+
+ // it was not found, create it
+ id = createSpvVariable(symbol);
+ symbolValues[symbol->getId()] = id;
+
+ if (! symbol->getType().isStruct()) {
+ addDecoration(id, TranslatePrecisionDecoration(symbol->getType()));
+ addDecoration(id, TranslateInterpolationDecoration(symbol->getType()));
+ if (symbol->getQualifier().hasLocation())
+ builder.addDecoration(id, spv::DecorationLocation, symbol->getQualifier().layoutLocation);
+ if (symbol->getQualifier().hasIndex())
+ builder.addDecoration(id, spv::DecorationIndex, symbol->getQualifier().layoutIndex);
+ if (symbol->getQualifier().hasComponent())
+ builder.addDecoration(id, spv::DecorationComponent, symbol->getQualifier().layoutComponent);
+ if (glslangIntermediate->getXfbMode()) {
+ if (symbol->getQualifier().hasXfbStride())
+ builder.addDecoration(id, spv::DecorationStride, symbol->getQualifier().layoutXfbStride);
+ if (symbol->getQualifier().hasXfbBuffer())
+ builder.addDecoration(id, spv::DecorationXfbBuffer, symbol->getQualifier().layoutXfbBuffer);
+ if (symbol->getQualifier().hasXfbOffset())
+ builder.addDecoration(id, spv::DecorationOffset, symbol->getQualifier().layoutXfbOffset);
+ }
+ }
+
+ addDecoration(id, TranslateInvariantDecoration(symbol->getType()));
+ if (symbol->getQualifier().hasStream())
+ builder.addDecoration(id, spv::DecorationStream, symbol->getQualifier().layoutStream);
+ if (symbol->getQualifier().hasSet())
+ builder.addDecoration(id, spv::DecorationDescriptorSet, symbol->getQualifier().layoutSet);
+ if (symbol->getQualifier().hasBinding())
+ builder.addDecoration(id, spv::DecorationBinding, symbol->getQualifier().layoutBinding);
+ if (glslangIntermediate->getXfbMode()) {
+ if (symbol->getQualifier().hasXfbStride())
+ builder.addDecoration(id, spv::DecorationStride, symbol->getQualifier().layoutXfbStride);
+ if (symbol->getQualifier().hasXfbBuffer())
+ builder.addDecoration(id, spv::DecorationXfbBuffer, symbol->getQualifier().layoutXfbBuffer);
+ }
+
+ // built-in variable decorations
+ int builtIn = TranslateBuiltInDecoration(symbol->getQualifier().builtIn);
+ if (builtIn != spv::BadValue)
+ builder.addDecoration(id, spv::DecorationBuiltIn, builtIn);
+
+ if (linkageOnly)
+ builder.addDecoration(id, spv::DecorationNoStaticUse);
+
+ return id;
+}
+
+void TGlslangToSpvTraverser::addDecoration(spv::Id id, spv::Decoration dec)
+{
+ if (dec != spv::BadValue)
+ builder.addDecoration(id, dec);
+}
+
+void TGlslangToSpvTraverser::addMemberDecoration(spv::Id id, int member, spv::Decoration dec)
+{
+ if (dec != spv::BadValue)
+ builder.addMemberDecoration(id, (unsigned)member, dec);
+}
+
+// Use 'consts' as the flattened glslang source of scalar constants to recursively
+// build the aggregate SPIR-V constant.
+//
+// If there are not enough elements present in 'consts', 0 will be substituted;
+// an empty 'consts' can be used to create a fully zeroed SPIR-V constant.
+//
+spv::Id TGlslangToSpvTraverser::createSpvConstant(const glslang::TType& glslangType, const glslang::TConstUnionArray& consts, int& nextConst)
+{
+ // vector of constants for SPIR-V
+ std::vector<spv::Id> spvConsts;
+
+ // Type is used for struct and array constants
+ spv::Id typeId = convertGlslangToSpvType(glslangType);
+
+ if (glslangType.isArray()) {
+ glslang::TType elementType;
+ elementType.shallowCopy(glslangType); // TODO: desktop arrays of arrays functionality will need a deeper copy to avoid modifying the original
+ elementType.dereference();
+ for (int i = 0; i < glslangType.getArraySize(); ++i)
+ spvConsts.push_back(createSpvConstant(elementType, consts, nextConst));
+ } else if (glslangType.isMatrix()) {
+ glslang::TType vectorType;
+ vectorType.shallowCopy(glslangType);
+ vectorType.dereference();
+ for (int col = 0; col < glslangType.getMatrixCols(); ++col)
+ spvConsts.push_back(createSpvConstant(vectorType, consts, nextConst));
+ } else if (glslangType.getStruct()) {
+ glslang::TVector<glslang::TTypeLoc>::const_iterator iter;
+ for (iter = glslangType.getStruct()->begin(); iter != glslangType.getStruct()->end(); ++iter)
+ spvConsts.push_back(createSpvConstant(*iter->type, consts, nextConst));
+ } else if (glslangType.isVector()) {
+ for (unsigned int i = 0; i < (unsigned int)glslangType.getVectorSize(); ++i) {
+ bool zero = nextConst >= consts.size();
+ switch (glslangType.getBasicType()) {
+ case glslang::EbtInt:
+ spvConsts.push_back(builder.makeIntConstant(zero ? 0 : consts[nextConst].getIConst()));
+ break;
+ case glslang::EbtUint:
+ spvConsts.push_back(builder.makeUintConstant(zero ? 0 : consts[nextConst].getUConst()));
+ break;
+ case glslang::EbtFloat:
+ spvConsts.push_back(builder.makeFloatConstant(zero ? 0.0F : (float)consts[nextConst].getDConst()));
+ break;
+ case glslang::EbtDouble:
+ spvConsts.push_back(builder.makeDoubleConstant(zero ? 0.0 : consts[nextConst].getDConst()));
+ break;
+ case glslang::EbtBool:
+ spvConsts.push_back(builder.makeBoolConstant(zero ? false : consts[nextConst].getBConst()));
+ break;
+ default:
+ spv::MissingFunctionality("constant vector type");
+ break;
+ }
+ ++nextConst;
+ }
+ } else {
+ // we have a non-aggregate (scalar) constant
+ bool zero = nextConst >= consts.size();
+ spv::Id scalar = 0;
+ switch (glslangType.getBasicType()) {
+ case glslang::EbtInt:
+ scalar = builder.makeIntConstant(zero ? 0 : consts[nextConst].getIConst());
+ break;
+ case glslang::EbtUint:
+ scalar = builder.makeUintConstant(zero ? 0 : consts[nextConst].getUConst());
+ break;
+ case glslang::EbtFloat:
+ scalar = builder.makeFloatConstant(zero ? 0.0F : (float)consts[nextConst].getDConst());
+ break;
+ case glslang::EbtDouble:
+ scalar = builder.makeDoubleConstant(zero ? 0.0 : consts[nextConst].getDConst());
+ break;
+ case glslang::EbtBool:
+ scalar = builder.makeBoolConstant(zero ? false : consts[nextConst].getBConst());
+ break;
+ default:
+ spv::MissingFunctionality("constant scalar type");
+ break;
+ }
+ ++nextConst;
+ return scalar;
+ }
+
+ return builder.makeCompositeConstant(typeId, spvConsts);
+}
+
+}; // end anonymous namespace
+
+namespace glslang {
+
+// Write SPIR-V out to a binary file
+void OutputSpv(const std::vector<unsigned int>& spirv, const char* baseName)
+{
+ std::ofstream out;
+ std::string fileName(baseName);
+ fileName.append(".spv");
+ out.open(fileName.c_str(), std::ios::binary | std::ios::out);
+ for (int i = 0; i < (int)spirv.size(); ++i) {
+ unsigned int word = spirv[i];
+ out.write((const char*)&word, 4);
+ }
+ out.close();
+}
+
+//
+// Set up the glslang traversal
+//
+void GlslangToSpv(const glslang::TIntermediate& intermediate, std::vector<unsigned int>& spirv)
+{
+ TIntermNode* root = intermediate.getTreeRoot();
+
+ if (root == 0)
+ return;
+
+ glslang::GetThreadPoolAllocator().push();
+
+ TGlslangToSpvTraverser it(&intermediate);
+
+ root->traverse(&it);
+
+ it.dumpSpv(spirv);
+
+ glslang::GetThreadPoolAllocator().pop();
+}
+
+}; // end namespace glslang
-//\r
-//Copyright (C) 2014 LunarG, Inc.\r
-//\r
-//All rights reserved.\r
-//\r
-//Redistribution and use in source and binary forms, with or without\r
-//modification, are permitted provided that the following conditions\r
-//are met:\r
-//\r
-// Redistributions of source code must retain the above copyright\r
-// notice, this list of conditions and the following disclaimer.\r
-//\r
-// Redistributions in binary form must reproduce the above\r
-// copyright notice, this list of conditions and the following\r
-// disclaimer in the documentation and/or other materials provided\r
-// with the distribution.\r
-//\r
-// Neither the name of 3Dlabs Inc. Ltd. nor the names of its\r
-// contributors may be used to endorse or promote products derived\r
-// from this software without specific prior written permission.\r
-//\r
-//THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\r
-//"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\r
-//LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS\r
-//FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE\r
-//COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,\r
-//INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,\r
-//BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\r
-//LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER\r
-//CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\r
-//LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN\r
-//ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE\r
-//POSSIBILITY OF SUCH DAMAGE.\r
-\r
-#include "../glslang/Include/intermediate.h"\r
-\r
-namespace glslang {\r
-\r
-void GlslangToSpv(const glslang::TIntermediate& intermediate, std::vector<unsigned int>& spirv);\r
-void OutputSpv(const std::vector<unsigned int>& spirv, const char* baseName);\r
-\r
-};\r
+//
+//Copyright (C) 2014 LunarG, Inc.
+//
+//All rights reserved.
+//
+//Redistribution and use in source and binary forms, with or without
+//modification, are permitted provided that the following conditions
+//are met:
+//
+// Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//
+// Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following
+// disclaimer in the documentation and/or other materials provided
+// with the distribution.
+//
+// Neither the name of 3Dlabs Inc. Ltd. nor the names of its
+// contributors may be used to endorse or promote products derived
+// from this software without specific prior written permission.
+//
+//THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+//"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+//LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+//FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+//COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+//INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+//BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+//LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+//CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+//LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+//ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+//POSSIBILITY OF SUCH DAMAGE.
+
+#include "../glslang/Include/intermediate.h"
+
+namespace glslang {
+
+void GlslangToSpv(const glslang::TIntermediate& intermediate, std::vector<unsigned int>& spirv);
+void OutputSpv(const std::vector<unsigned int>& spirv, const char* baseName);
+
+};
-//\r
-//Copyright (C) 2015 LunarG, Inc.\r
-//\r
-//All rights reserved.\r
-//\r
-//Redistribution and use in source and binary forms, with or without\r
-//modification, are permitted provided that the following conditions\r
-//are met:\r
-//\r
-// Redistributions of source code must retain the above copyright\r
-// notice, this list of conditions and the following disclaimer.\r
-//\r
-// Redistributions in binary form must reproduce the above\r
-// copyright notice, this list of conditions and the following\r
-// disclaimer in the documentation and/or other materials provided\r
-// with the distribution.\r
-//\r
-// Neither the name of 3Dlabs Inc. Ltd. nor the names of its\r
-// contributors may be used to endorse or promote products derived\r
-// from this software without specific prior written permission.\r
-//\r
-//THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\r
-//"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\r
-//LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS\r
-//FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE\r
-//COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,\r
-//INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,\r
-//BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\r
-//LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER\r
-//CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\r
-//LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN\r
-//ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE\r
-//POSSIBILITY OF SUCH DAMAGE.\r
-//\r
-\r
-#include "SPVRemapper.h"\r
-#include "doc.h"\r
-\r
-#if !defined (use_cpp11)\r
-// ... not supported before C++11\r
-#else // defined (use_cpp11)\r
-\r
-#include <algorithm>\r
-#include <cassert>\r
-\r
-namespace spv {\r
-\r
- // By default, just abort on error. Can be overridden via RegisterErrorHandler\r
- spirvbin_t::errorfn_t spirvbin_t::errorHandler = [](const std::string&) { exit(5); };\r
- // By default, eat log messages. Can be overridden via RegisterLogHandler\r
- spirvbin_t::logfn_t spirvbin_t::logHandler = [](const std::string&) { };\r
-\r
- // This can be overridden to provide other message behavior if needed\r
- void spirvbin_t::msg(int minVerbosity, int indent, const std::string& txt) const\r
- {\r
- if (verbose >= minVerbosity)\r
- logHandler(std::string(indent, ' ') + txt);\r
- }\r
-\r
- // hash opcode, with special handling for OpExtInst\r
- std::uint32_t spirvbin_t::asOpCodeHash(unsigned word)\r
- {\r
- const spv::Op opCode = asOpCode(word);\r
-\r
- std::uint32_t offset = 0;\r
-\r
- switch (opCode) {\r
- case spv::OpExtInst:\r
- offset += asId(word + 4); break;\r
- default:\r
- break;\r
- }\r
-\r
- return opCode * 19 + offset; // 19 = small prime\r
- }\r
-\r
- spirvbin_t::range_t spirvbin_t::literalRange(spv::Op opCode) const\r
- {\r
- static const int maxCount = 1<<30;\r
-\r
- switch (opCode) {\r
- case spv::OpTypeFloat: // fall through...\r
- case spv::OpTypePointer: return range_t(2, 3);\r
- case spv::OpTypeInt: return range_t(2, 4);\r
- case spv::OpTypeSampler: return range_t(3, 8);\r
- case spv::OpTypeVector: // fall through\r
- case spv::OpTypeMatrix: // ...\r
- case spv::OpTypePipe: return range_t(3, 4);\r
- case spv::OpConstant: return range_t(3, maxCount);\r
- default: return range_t(0, 0);\r
- }\r
- }\r
-\r
- spirvbin_t::range_t spirvbin_t::typeRange(spv::Op opCode) const\r
- {\r
- static const int maxCount = 1<<30;\r
-\r
- if (isConstOp(opCode))\r
- return range_t(1, 2);\r
-\r
- switch (opCode) {\r
- case spv::OpTypeVector: // fall through\r
- case spv::OpTypeMatrix: // ... \r
- case spv::OpTypeSampler: // ... \r
- case spv::OpTypeArray: // ... \r
- case spv::OpTypeRuntimeArray: // ... \r
- case spv::OpTypePipe: return range_t(2, 3);\r
- case spv::OpTypeStruct: // fall through\r
- case spv::OpTypeFunction: return range_t(2, maxCount);\r
- case spv::OpTypePointer: return range_t(3, 4);\r
- default: return range_t(0, 0);\r
- }\r
- }\r
-\r
- spirvbin_t::range_t spirvbin_t::constRange(spv::Op opCode) const\r
- {\r
- static const int maxCount = 1<<30;\r
-\r
- switch (opCode) {\r
- case spv::OpTypeArray: // fall through...\r
- case spv::OpTypeRuntimeArray: return range_t(3, 4);\r
- case spv::OpConstantComposite: return range_t(3, maxCount);\r
- default: return range_t(0, 0);\r
- }\r
- }\r
-\r
- // Is this an opcode we should remove when using --strip?\r
- bool spirvbin_t::isStripOp(spv::Op opCode) const\r
- {\r
- switch (opCode) {\r
- case spv::OpSource:\r
- case spv::OpSourceExtension:\r
- case spv::OpName:\r
- case spv::OpMemberName:\r
- case spv::OpLine: return true;\r
- default: return false;\r
- }\r
- }\r
-\r
- bool spirvbin_t::isFlowCtrlOpen(spv::Op opCode) const\r
- {\r
- switch (opCode) {\r
- case spv::OpBranchConditional:\r
- case spv::OpSwitch: return true;\r
- default: return false;\r
- }\r
- }\r
-\r
- bool spirvbin_t::isFlowCtrlClose(spv::Op opCode) const\r
- {\r
- switch (opCode) {\r
- case spv::OpLoopMerge:\r
- case spv::OpSelectionMerge: return true;\r
- default: return false;\r
- }\r
- }\r
-\r
- bool spirvbin_t::isTypeOp(spv::Op opCode) const\r
- {\r
- switch (opCode) {\r
- case spv::OpTypeVoid:\r
- case spv::OpTypeBool:\r
- case spv::OpTypeInt:\r
- case spv::OpTypeFloat:\r
- case spv::OpTypeVector:\r
- case spv::OpTypeMatrix:\r
- case spv::OpTypeSampler:\r
- case spv::OpTypeFilter:\r
- case spv::OpTypeArray:\r
- case spv::OpTypeRuntimeArray:\r
- case spv::OpTypeStruct:\r
- case spv::OpTypeOpaque:\r
- case spv::OpTypePointer:\r
- case spv::OpTypeFunction:\r
- case spv::OpTypeEvent:\r
- case spv::OpTypeDeviceEvent:\r
- case spv::OpTypeReserveId:\r
- case spv::OpTypeQueue:\r
- case spv::OpTypePipe: return true;\r
- default: return false;\r
- }\r
- }\r
-\r
- bool spirvbin_t::isConstOp(spv::Op opCode) const\r
- {\r
- switch (opCode) {\r
- case spv::OpConstantNullObject: error("unimplemented constant type");\r
- case spv::OpConstantSampler: error("unimplemented constant type");\r
-\r
- case spv::OpConstantTrue:\r
- case spv::OpConstantFalse:\r
- case spv::OpConstantNullPointer:\r
- case spv::OpConstantComposite:\r
- case spv::OpConstant: return true;\r
- default: return false;\r
- }\r
- }\r
-\r
- const auto inst_fn_nop = [](spv::Op, unsigned) { return false; };\r
- const auto op_fn_nop = [](spv::Id&) { };\r
-\r
- // g++ doesn't like these defined in the class proper in an anonymous namespace.\r
- // Dunno why. Also MSVC doesn't like the constexpr keyword. Also dunno why.\r
- // Defining them externally seems to please both compilers, so, here they are.\r
- const spv::Id spirvbin_t::unmapped = spv::Id(-10000);\r
- const spv::Id spirvbin_t::unused = spv::Id(-10001);\r
- const int spirvbin_t::header_size = 5;\r
-\r
- spv::Id spirvbin_t::nextUnusedId(spv::Id id)\r
- {\r
- while (isNewIdMapped(id)) // search for an unused ID\r
- ++id;\r
-\r
- return id;\r
- }\r
-\r
- spv::Id spirvbin_t::localId(spv::Id id, spv::Id newId)\r
- {\r
- assert(id != spv::NoResult && newId != spv::NoResult);\r
-\r
- if (id >= idMapL.size())\r
- idMapL.resize(id+1, unused);\r
-\r
- if (newId != unmapped && newId != unused) {\r
- if (isOldIdUnused(id))\r
- error(std::string("ID unused in module: ") + std::to_string(id));\r
-\r
- if (!isOldIdUnmapped(id))\r
- error(std::string("ID already mapped: ") + std::to_string(id) + " -> "\r
- + std::to_string(localId(id)));\r
-\r
- if (isNewIdMapped(newId))\r
- error(std::string("ID already used in module: ") + std::to_string(newId));\r
-\r
- msg(4, 4, std::string("map: ") + std::to_string(id) + " -> " + std::to_string(newId));\r
- setMapped(newId);\r
- largestNewId = std::max(largestNewId, newId);\r
- }\r
-\r
- return idMapL[id] = newId;\r
- }\r
-\r
- // Parse a literal string from the SPIR binary and return it as an std::string\r
- // Due to C++11 RValue references, this doesn't copy the result string.\r
- std::string spirvbin_t::literalString(unsigned word) const\r
- {\r
- std::string literal;\r
-\r
- literal.reserve(16);\r
-\r
- const char* bytes = reinterpret_cast<const char*>(spv.data() + word);\r
-\r
- while (bytes && *bytes)\r
- literal += *bytes++;\r
-\r
- return literal;\r
- }\r
-\r
-\r
- void spirvbin_t::applyMap()\r
- {\r
- msg(3, 2, std::string("Applying map: "));\r
-\r
- // Map local IDs through the ID map\r
- process(inst_fn_nop, // ignore instructions\r
- [this](spv::Id& id) {\r
- id = localId(id);\r
- assert(id != unused && id != unmapped);\r
- }\r
- );\r
- }\r
-\r
-\r
- // Find free IDs for anything we haven't mapped\r
- void spirvbin_t::mapRemainder()\r
- {\r
- msg(3, 2, std::string("Remapping remainder: "));\r
-\r
- spv::Id unusedId = 1; // can't use 0: that's NoResult\r
- spirword_t maxBound = 0;\r
-\r
- for (spv::Id id = 0; id < idMapL.size(); ++id) {\r
- if (isOldIdUnused(id))\r
- continue;\r
-\r
- // Find a new mapping for any used but unmapped IDs\r
- if (isOldIdUnmapped(id))\r
- localId(id, unusedId = nextUnusedId(unusedId));\r
-\r
- if (isOldIdUnmapped(id))\r
- error(std::string("old ID not mapped: ") + std::to_string(id));\r
-\r
- // Track max bound\r
- maxBound = std::max(maxBound, localId(id) + 1);\r
- }\r
-\r
- bound(maxBound); // reset header ID bound to as big as it now needs to be\r
- }\r
-\r
- void spirvbin_t::stripDebug()\r
- {\r
- if ((options & STRIP) == 0)\r
- return;\r
-\r
- // build local Id and name maps\r
- process(\r
- [&](spv::Op opCode, unsigned start) {\r
- // remember opcodes we want to strip later\r
- if (isStripOp(opCode))\r
- stripInst(start);\r
- return true;\r
- },\r
- op_fn_nop);\r
- }\r
-\r
- void spirvbin_t::buildLocalMaps()\r
- {\r
- msg(2, 2, std::string("build local maps: "));\r
-\r
- mapped.clear();\r
- idMapL.clear();\r
-// preserve nameMap, so we don't clear that.\r
- fnPos.clear();\r
- fnPosDCE.clear();\r
- fnCalls.clear();\r
- typeConstPos.clear();\r
- typeConstPosR.clear();\r
- entryPoint = spv::NoResult;\r
- largestNewId = 0;\r
-\r
- idMapL.resize(bound(), unused);\r
-\r
- int fnStart = 0;\r
- spv::Id fnRes = spv::NoResult;\r
-\r
- // build local Id and name maps\r
- process(\r
- [&](spv::Op opCode, unsigned start) {\r
- // remember opcodes we want to strip later\r
- if ((options & STRIP) && isStripOp(opCode))\r
- stripInst(start);\r
-\r
- if (opCode == spv::Op::OpName) {\r
- const spv::Id target = asId(start+1);\r
- const std::string name = literalString(start+2);\r
- nameMap[name] = target;\r
-\r
- } else if (opCode == spv::Op::OpFunctionCall) {\r
- ++fnCalls[asId(start + 3)];\r
- } else if (opCode == spv::Op::OpEntryPoint) {\r
- entryPoint = asId(start + 2);\r
- } else if (opCode == spv::Op::OpFunction) {\r
- if (fnStart != 0)\r
- error("nested function found");\r
- fnStart = start;\r
- fnRes = asId(start + 2);\r
- } else if (opCode == spv::Op::OpFunctionEnd) {\r
- assert(fnRes != spv::NoResult);\r
- if (fnStart == 0)\r
- error("function end without function start");\r
- fnPos[fnRes] = range_t(fnStart, start + asWordCount(start));\r
- fnStart = 0;\r
- } else if (isConstOp(opCode)) {\r
- assert(asId(start + 2) != spv::NoResult);\r
- typeConstPos.insert(start);\r
- typeConstPosR[asId(start + 2)] = start;\r
- } else if (isTypeOp(opCode)) {\r
- assert(asId(start + 1) != spv::NoResult);\r
- typeConstPos.insert(start);\r
- typeConstPosR[asId(start + 1)] = start;\r
- }\r
-\r
- return false;\r
- },\r
-\r
- [this](spv::Id& id) { localId(id, unmapped); }\r
- );\r
- }\r
-\r
- // Validate the SPIR header\r
- void spirvbin_t::validate() const\r
- {\r
- msg(2, 2, std::string("validating: "));\r
-\r
- if (spv.size() < header_size)\r
- error("file too short: ");\r
-\r
- if (magic() != spv::MagicNumber)\r
- error("bad magic number");\r
-\r
- // field 1 = version\r
- // field 2 = generator magic\r
- // field 3 = result <id> bound\r
-\r
- if (schemaNum() != 0)\r
- error("bad schema, must be 0");\r
- }\r
-\r
-\r
- int spirvbin_t::processInstruction(unsigned word, instfn_t instFn, idfn_t idFn)\r
- {\r
- const auto instructionStart = word;\r
- const unsigned wordCount = asWordCount(instructionStart);\r
- const spv::Op opCode = asOpCode(instructionStart);\r
- const int nextInst = word++ + wordCount;\r
-\r
- if (nextInst > int(spv.size()))\r
- error("spir instruction terminated too early");\r
-\r
- // Base for computing number of operands; will be updated as more is learned\r
- unsigned numOperands = wordCount - 1;\r
-\r
- if (instFn(opCode, instructionStart))\r
- return nextInst;\r
-\r
- // Read type and result ID from instruction desc table\r
- if (spv::InstructionDesc[opCode].hasType()) {\r
- idFn(asId(word++));\r
- --numOperands;\r
- }\r
-\r
- if (spv::InstructionDesc[opCode].hasResult()) {\r
- idFn(asId(word++));\r
- --numOperands;\r
- }\r
-\r
- // Extended instructions: currently, assume everything is an ID.\r
- // TODO: add whatever data we need for exceptions to that\r
- if (opCode == spv::OpExtInst) {\r
- word += 2; // instruction set, and instruction from set\r
- numOperands -= 2;\r
-\r
- for (unsigned op=0; op < numOperands; ++op)\r
- idFn(asId(word++)); // ID\r
-\r
- return nextInst;\r
- }\r
-\r
- // Store IDs from instruction in our map\r
- for (int op = 0; op < spv::InstructionDesc[opCode].operands.getNum(); ++op, --numOperands) {\r
- switch (spv::InstructionDesc[opCode].operands.getClass(op)) {\r
- case spv::OperandId:\r
- idFn(asId(word++));\r
- break;\r
-\r
- case spv::OperandOptionalId:\r
- case spv::OperandVariableIds:\r
- for (unsigned i = 0; i < numOperands; ++i)\r
- idFn(asId(word++));\r
- return nextInst;\r
-\r
- case spv::OperandVariableLiterals:\r
- if (opCode == spv::OpDecorate && asDecoration(word - 1) == spv::DecorationBuiltIn) {\r
- ++word;\r
- --numOperands;\r
- }\r
- word += numOperands;\r
- return nextInst;\r
-\r
- case spv::OperandVariableLiteralId:\r
- while (numOperands > 0) {\r
- ++word; // immediate\r
- idFn(asId(word++)); // ID\r
- numOperands -= 2;\r
- }\r
- return nextInst;\r
-\r
- case spv::OperandLiteralString:\r
- word += literalStringWords(literalString(word));\r
- return nextInst;\r
-\r
- // Single word operands we simply ignore, as they hold no IDs\r
- case spv::OperandLiteralNumber:\r
- case spv::OperandSource:\r
- case spv::OperandExecutionModel:\r
- case spv::OperandAddressing:\r
- case spv::OperandMemory:\r
- case spv::OperandExecutionMode:\r
- case spv::OperandStorage:\r
- case spv::OperandDimensionality:\r
- case spv::OperandDecoration:\r
- case spv::OperandBuiltIn:\r
- case spv::OperandSelect:\r
- case spv::OperandLoop:\r
- case spv::OperandFunction:\r
- case spv::OperandMemorySemantics:\r
- case spv::OperandMemoryAccess:\r
- case spv::OperandExecutionScope:\r
- case spv::OperandGroupOperation:\r
- case spv::OperandKernelEnqueueFlags:\r
- case spv::OperandKernelProfilingInfo:\r
- ++word;\r
- break;\r
-\r
- default:\r
- break;\r
- }\r
- }\r
-\r
- return nextInst;\r
- }\r
-\r
- // Make a pass over all the instructions and process them given appropriate functions\r
- spirvbin_t& spirvbin_t::process(instfn_t instFn, idfn_t idFn, unsigned begin, unsigned end)\r
- {\r
- // For efficiency, reserve name map space. It can grow if needed.\r
- nameMap.reserve(32);\r
-\r
- // If begin or end == 0, use defaults\r
- begin = (begin == 0 ? header_size : begin);\r
- end = (end == 0 ? unsigned(spv.size()) : end);\r
-\r
- // basic parsing and InstructionDesc table borrowed from SpvDisassemble.cpp...\r
- unsigned nextInst = unsigned(spv.size());\r
-\r
- for (unsigned word = begin; word < end; word = nextInst)\r
- nextInst = processInstruction(word, instFn, idFn);\r
-\r
- return *this;\r
- }\r
-\r
- // Apply global name mapping to a single module\r
- void spirvbin_t::mapNames()\r
- {\r
- static const std::uint32_t softTypeIdLimit = 3011; // small prime. TODO: get from options\r
- static const std::uint32_t firstMappedID = 3019; // offset into ID space\r
-\r
- for (const auto& name : nameMap) {\r
- std::uint32_t hashval = 1911;\r
- for (const char c : name.first)\r
- hashval = hashval * 1009 + c;\r
-\r
- if (isOldIdUnmapped(name.second))\r
- localId(name.second, nextUnusedId(hashval % softTypeIdLimit + firstMappedID));\r
- }\r
- }\r
-\r
- // Map fn contents to IDs of similar functions in other modules\r
- void spirvbin_t::mapFnBodies()\r
- {\r
- static const std::uint32_t softTypeIdLimit = 19071; // small prime. TODO: get from options\r
- static const std::uint32_t firstMappedID = 6203; // offset into ID space\r
-\r
- // Initial approach: go through some high priority opcodes first and assign them\r
- // hash values.\r
-\r
- spv::Id fnId = spv::NoResult;\r
- std::vector<unsigned> instPos;\r
- instPos.reserve(unsigned(spv.size()) / 16); // initial estimate; can grow if needed.\r
-\r
- // Build local table of instruction start positions\r
- process(\r
- [&](spv::Op, unsigned start) { instPos.push_back(start); return true; },\r
- op_fn_nop);\r
-\r
- // Window size for context-sensitive canonicalization values\r
- // Emperical best size from a single data set. TODO: Would be a good tunable.\r
- // We essentially performa a little convolution around each instruction,\r
- // to capture the flavor of nearby code, to hopefully match to similar\r
- // code in other modules.\r
- static const unsigned windowSize = 2;\r
-\r
- for (unsigned entry = 0; entry < unsigned(instPos.size()); ++entry) {\r
- const unsigned start = instPos[entry];\r
- const spv::Op opCode = asOpCode(start);\r
-\r
- if (opCode == spv::OpFunction)\r
- fnId = asId(start + 2);\r
-\r
- if (opCode == spv::OpFunctionEnd)\r
- fnId = spv::NoResult;\r
-\r
- if (fnId != spv::NoResult) { // if inside a function\r
- if (spv::InstructionDesc[opCode].hasResult()) {\r
- const unsigned word = start + (spv::InstructionDesc[opCode].hasType() ? 2 : 1);\r
- const spv::Id resId = asId(word);\r
- std::uint32_t hashval = fnId * 17; // small prime\r
-\r
- for (unsigned i = entry-1; i >= entry-windowSize; --i) {\r
- if (asOpCode(instPos[i]) == spv::OpFunction)\r
- break;\r
- hashval = hashval * 30103 + asOpCodeHash(instPos[i]); // 30103 = semiarbitrary prime\r
- }\r
-\r
- for (unsigned i = entry; i <= entry + windowSize; ++i) {\r
- if (asOpCode(instPos[i]) == spv::OpFunctionEnd)\r
- break;\r
- hashval = hashval * 30103 + asOpCodeHash(instPos[i]); // 30103 = semiarbitrary prime\r
- }\r
-\r
- if (isOldIdUnmapped(resId))\r
- localId(resId, nextUnusedId(hashval % softTypeIdLimit + firstMappedID));\r
- }\r
- }\r
- }\r
-\r
- spv::Op thisOpCode(spv::OpNop);\r
- std::unordered_map<int, int> opCounter;\r
- int idCounter(0);\r
- fnId = spv::NoResult;\r
-\r
- process(\r
- [&](spv::Op opCode, unsigned start) {\r
- switch (opCode) {\r
- case spv::OpFunction:\r
- // Reset counters at each function\r
- idCounter = 0;\r
- opCounter.clear();\r
- fnId = asId(start + 2);\r
- break;\r
-\r
- case spv::OpTextureSample:\r
- case spv::OpTextureSampleDref:\r
- case spv::OpTextureSampleLod:\r
- case spv::OpTextureSampleProj:\r
- case spv::OpTextureSampleGrad:\r
- case spv::OpTextureSampleOffset:\r
- case spv::OpTextureSampleProjLod:\r
- case spv::OpTextureSampleProjGrad:\r
- case spv::OpTextureSampleLodOffset:\r
- case spv::OpTextureSampleProjOffset:\r
- case spv::OpTextureSampleGradOffset: \r
- case spv::OpTextureSampleProjLodOffset:\r
- case spv::OpTextureSampleProjGradOffset:\r
- case spv::OpDot:\r
- case spv::OpCompositeExtract:\r
- case spv::OpCompositeInsert:\r
- case spv::OpVectorShuffle:\r
- case spv::OpLabel:\r
- case spv::OpVariable:\r
-\r
- case spv::OpAccessChain:\r
- case spv::OpLoad:\r
- case spv::OpStore:\r
- case spv::OpCompositeConstruct:\r
- case spv::OpFunctionCall:\r
- ++opCounter[opCode];\r
- idCounter = 0;\r
- thisOpCode = opCode;\r
- break;\r
- default:\r
- thisOpCode = spv::OpNop;\r
- }\r
-\r
- return false;\r
- },\r
-\r
- [&](spv::Id& id) {\r
- if (thisOpCode != spv::OpNop) {\r
- ++idCounter;\r
- const std::uint32_t hashval = opCounter[thisOpCode] * thisOpCode * 50047 + idCounter + fnId * 117;\r
-\r
- if (isOldIdUnmapped(id))\r
- localId(id, nextUnusedId(hashval % softTypeIdLimit + firstMappedID));\r
- }\r
- });\r
- }\r
-\r
- // EXPERIMENTAL: forward IO and uniform load/stores into operands\r
- // This produces invalid Schema-0 SPIRV\r
- void spirvbin_t::forwardLoadStores()\r
- {\r
- idset_t fnLocalVars; // set of function local vars\r
- idmap_t idMap; // Map of load result IDs to what they load\r
-\r
- // EXPERIMENTAL: Forward input and access chain loads into consumptions\r
- process(\r
- [&](spv::Op opCode, unsigned start) {\r
- // Add inputs and uniforms to the map\r
- if (((opCode == spv::OpVariable && asWordCount(start) == 4) || (opCode == spv::OpVariableArray)) &&\r
- (spv[start+3] == spv::StorageClassUniform ||\r
- spv[start+3] == spv::StorageClassUniformConstant ||\r
- spv[start+3] == spv::StorageClassInput))\r
- fnLocalVars.insert(asId(start+2));\r
-\r
- if (opCode == spv::OpAccessChain && fnLocalVars.count(asId(start+3)) > 0)\r
- fnLocalVars.insert(asId(start+2));\r
-\r
- if (opCode == spv::OpLoad && fnLocalVars.count(asId(start+3)) > 0) {\r
- idMap[asId(start+2)] = asId(start+3);\r
- stripInst(start);\r
- }\r
-\r
- return false;\r
- },\r
-\r
- [&](spv::Id& id) { if (idMap.find(id) != idMap.end()) id = idMap[id]; }\r
- );\r
-\r
- // EXPERIMENTAL: Implicit output stores\r
- fnLocalVars.clear();\r
- idMap.clear();\r
-\r
- process(\r
- [&](spv::Op opCode, unsigned start) {\r
- // Add inputs and uniforms to the map\r
- if (((opCode == spv::OpVariable && asWordCount(start) == 4) || (opCode == spv::OpVariableArray)) &&\r
- (spv[start+3] == spv::StorageClassOutput))\r
- fnLocalVars.insert(asId(start+2));\r
-\r
- if (opCode == spv::OpStore && fnLocalVars.count(asId(start+1)) > 0) {\r
- idMap[asId(start+2)] = asId(start+1);\r
- stripInst(start);\r
- }\r
-\r
- return false;\r
- },\r
- op_fn_nop);\r
-\r
- process(\r
- inst_fn_nop,\r
- [&](spv::Id& id) { if (idMap.find(id) != idMap.end()) id = idMap[id]; }\r
- );\r
-\r
- strip(); // strip out data we decided to eliminate\r
- }\r
-\r
- // remove bodies of uncalled functions\r
- void spirvbin_t::optLoadStore()\r
- {\r
- idset_t fnLocalVars;\r
- // Map of load result IDs to what they load\r
- idmap_t idMap;\r
-\r
- // Find all the function local pointers stored at most once, and not via access chains\r
- process(\r
- [&](spv::Op opCode, unsigned start) {\r
- const int wordCount = asWordCount(start);\r
-\r
- // Add local variables to the map\r
- if ((opCode == spv::OpVariable && spv[start+3] == spv::StorageClassFunction && asWordCount(start) == 4) ||\r
- (opCode == spv::OpVariableArray && spv[start+3] == spv::StorageClassFunction))\r
- fnLocalVars.insert(asId(start+2));\r
-\r
- // Ignore process vars referenced via access chain\r
- if ((opCode == spv::OpAccessChain || opCode == spv::OpInBoundsAccessChain) && fnLocalVars.count(asId(start+3)) > 0) {\r
- fnLocalVars.erase(asId(start+3));\r
- idMap.erase(asId(start+3));\r
- }\r
-\r
- if (opCode == spv::OpLoad && fnLocalVars.count(asId(start+3)) > 0) {\r
- // Avoid loads before stores (TODO: why? Crashes driver, but seems like it shouldn't).\r
- if (idMap.find(asId(start+3)) == idMap.end()) {\r
- fnLocalVars.erase(asId(start+3));\r
- idMap.erase(asId(start+3));\r
- }\r
-\r
- // don't do for volatile references\r
- if (wordCount > 4 && (spv[start+4] & spv::MemoryAccessVolatileMask)) {\r
- fnLocalVars.erase(asId(start+3));\r
- idMap.erase(asId(start+3));\r
- }\r
- }\r
-\r
- if (opCode == spv::OpStore && fnLocalVars.count(asId(start+1)) > 0) {\r
- if (idMap.find(asId(start+1)) == idMap.end()) {\r
- idMap[asId(start+1)] = asId(start+2);\r
- } else {\r
- // Remove if it has more than one store to the same pointer\r
- fnLocalVars.erase(asId(start+1));\r
- idMap.erase(asId(start+1));\r
- }\r
-\r
- // don't do for volatile references\r
- if (wordCount > 3 && (spv[start+3] & spv::MemoryAccessVolatileMask)) {\r
- fnLocalVars.erase(asId(start+3));\r
- idMap.erase(asId(start+3));\r
- }\r
- }\r
-\r
- return true;\r
- },\r
- op_fn_nop);\r
-\r
- process(\r
- [&](spv::Op opCode, unsigned start) {\r
- if (opCode == spv::OpLoad && fnLocalVars.count(asId(start+3)) > 0)\r
- idMap[asId(start+2)] = idMap[asId(start+3)];\r
- return false;\r
- },\r
- op_fn_nop);\r
-\r
- // Remove the load/store/variables for the ones we've discovered\r
- process(\r
- [&](spv::Op opCode, unsigned start) {\r
- if ((opCode == spv::OpLoad && fnLocalVars.count(asId(start+3)) > 0) ||\r
- (opCode == spv::OpStore && fnLocalVars.count(asId(start+1)) > 0) ||\r
- (opCode == spv::OpVariable && fnLocalVars.count(asId(start+2)) > 0)) {\r
- stripInst(start);\r
- return true;\r
- }\r
-\r
- return false;\r
- },\r
-\r
- [&](spv::Id& id) { if (idMap.find(id) != idMap.end()) id = idMap[id]; }\r
- );\r
-\r
- strip(); // strip out data we decided to eliminate\r
- }\r
-\r
- // remove bodies of uncalled functions\r
- void spirvbin_t::dceFuncs()\r
- {\r
- msg(3, 2, std::string("Removing Dead Functions: "));\r
-\r
- // TODO: There are more efficient ways to do this.\r
- bool changed = true;\r
-\r
- while (changed) {\r
- changed = false;\r
-\r
- for (auto fn = fnPos.begin(); fn != fnPos.end(); ) {\r
- if (fn->first == entryPoint) { // don't DCE away the entry point!\r
- ++fn;\r
- continue;\r
- }\r
-\r
- const auto call_it = fnCalls.find(fn->first);\r
-\r
- if (call_it == fnCalls.end() || call_it->second == 0) {\r
- changed = true;\r
- stripRange.push_back(fn->second);\r
- fnPosDCE.insert(*fn);\r
-\r
- // decrease counts of called functions\r
- process(\r
- [&](spv::Op opCode, unsigned start) {\r
- if (opCode == spv::Op::OpFunctionCall) {\r
- const auto call_it = fnCalls.find(asId(start + 3));\r
- if (call_it != fnCalls.end()) {\r
- if (--call_it->second <= 0)\r
- fnCalls.erase(call_it);\r
- }\r
- }\r
-\r
- return true;\r
- },\r
- op_fn_nop,\r
- fn->second.first,\r
- fn->second.second);\r
-\r
- fn = fnPos.erase(fn);\r
- } else ++fn;\r
- }\r
- }\r
- }\r
-\r
- // remove unused function variables + decorations\r
- void spirvbin_t::dceVars()\r
- {\r
- msg(3, 2, std::string("DCE Vars: "));\r
-\r
- std::unordered_map<spv::Id, int> varUseCount;\r
-\r
- // Count function variable use\r
- process(\r
- [&](spv::Op opCode, unsigned start) {\r
- if (opCode == spv::OpVariable) { ++varUseCount[asId(start+2)]; return true; }\r
- return false;\r
- },\r
-\r
- [&](spv::Id& id) { if (varUseCount[id]) ++varUseCount[id]; }\r
- );\r
-\r
- // Remove single-use function variables + associated decorations and names\r
- process(\r
- [&](spv::Op opCode, unsigned start) {\r
- if ((opCode == spv::OpVariable && varUseCount[asId(start+2)] == 1) ||\r
- (opCode == spv::OpDecorate && varUseCount[asId(start+1)] == 1) ||\r
- (opCode == spv::OpName && varUseCount[asId(start+1)] == 1)) {\r
- stripInst(start);\r
- }\r
- return true;\r
- },\r
- op_fn_nop);\r
- }\r
-\r
- // remove unused types\r
- void spirvbin_t::dceTypes()\r
- {\r
- std::vector<bool> isType(bound(), false);\r
-\r
- // for speed, make O(1) way to get to type query (map is log(n))\r
- for (const auto typeStart : typeConstPos)\r
- isType[asTypeConstId(typeStart)] = true;\r
-\r
- std::unordered_map<spv::Id, int> typeUseCount;\r
-\r
- // Count total type usage\r
- process(inst_fn_nop,\r
- [&](spv::Id& id) { if (isType[id]) ++typeUseCount[id]; }\r
- );\r
-\r
- // Remove types from deleted code\r
- for (const auto& fn : fnPosDCE)\r
- process(inst_fn_nop,\r
- [&](spv::Id& id) { if (isType[id]) --typeUseCount[id]; },\r
- fn.second.first, fn.second.second);\r
-\r
- // Remove single reference types\r
- for (const auto typeStart : typeConstPos) {\r
- const spv::Id typeId = asTypeConstId(typeStart);\r
- if (typeUseCount[typeId] == 1) {\r
- --typeUseCount[typeId];\r
- stripInst(typeStart);\r
- }\r
- }\r
- }\r
-\r
-\r
-#ifdef NOTDEF\r
- bool spirvbin_t::matchType(const spirvbin_t::globaltypes_t& globalTypes, spv::Id lt, spv::Id gt) const\r
- {\r
- // Find the local type id "lt" and global type id "gt"\r
- const auto lt_it = typeConstPosR.find(lt);\r
- if (lt_it == typeConstPosR.end())\r
- return false;\r
-\r
- const auto typeStart = lt_it->second;\r
-\r
- // Search for entry in global table\r
- const auto gtype = globalTypes.find(gt);\r
- if (gtype == globalTypes.end())\r
- return false;\r
-\r
- const auto& gdata = gtype->second;\r
-\r
- // local wordcount and opcode\r
- const int wordCount = asWordCount(typeStart);\r
- const spv::Op opCode = asOpCode(typeStart);\r
-\r
- // no type match if opcodes don't match, or operand count doesn't match\r
- if (opCode != opOpCode(gdata[0]) || wordCount != opWordCount(gdata[0]))\r
- return false;\r
-\r
- const unsigned numOperands = wordCount - 2; // all types have a result\r
-\r
- const auto cmpIdRange = [&](range_t range) {\r
- for (int x=range.first; x<std::min(range.second, wordCount); ++x)\r
- if (!matchType(globalTypes, asId(typeStart+x), gdata[x]))\r
- return false;\r
- return true;\r
- };\r
-\r
- const auto cmpConst = [&]() { return cmpIdRange(constRange(opCode)); };\r
- const auto cmpSubType = [&]() { return cmpIdRange(typeRange(opCode)); };\r
-\r
- // Compare literals in range [start,end)\r
- const auto cmpLiteral = [&]() {\r
- const auto range = literalRange(opCode);\r
- return std::equal(spir.begin() + typeStart + range.first,\r
- spir.begin() + typeStart + std::min(range.second, wordCount),\r
- gdata.begin() + range.first);\r
- };\r
-\r
- assert(isTypeOp(opCode) || isConstOp(opCode));\r
-\r
- switch (opCode) {\r
- case spv::OpTypeOpaque: // TODO: disable until we compare the literal strings.\r
- case spv::OpTypeQueue: return false;\r
- case spv::OpTypeEvent: // fall through...\r
- case spv::OpTypeDeviceEvent: // ...\r
- case spv::OpTypeReserveId: return false;\r
- // for samplers, we don't handle the optional parameters yet\r
- case spv::OpTypeSampler: return cmpLiteral() && cmpConst() && cmpSubType() && wordCount == 8;\r
- default: return cmpLiteral() && cmpConst() && cmpSubType();\r
- }\r
- }\r
-\r
-\r
- // Look for an equivalent type in the globalTypes map\r
- spv::Id spirvbin_t::findType(const spirvbin_t::globaltypes_t& globalTypes, spv::Id lt) const\r
- {\r
- // Try a recursive type match on each in turn, and return a match if we find one\r
- for (const auto& gt : globalTypes)\r
- if (matchType(globalTypes, lt, gt.first))\r
- return gt.first;\r
-\r
- return spv::NoType;\r
- }\r
-#endif // NOTDEF\r
-\r
- // Return start position in SPV of given type. error if not found.\r
- unsigned spirvbin_t::typePos(spv::Id id) const\r
- {\r
- const auto tid_it = typeConstPosR.find(id);\r
- if (tid_it == typeConstPosR.end())\r
- error("type ID not found");\r
-\r
- return tid_it->second;\r
- }\r
-\r
- // Hash types to canonical values. This can return ID collisions (it's a bit\r
- // inevitable): it's up to the caller to handle that gracefully.\r
- std::uint32_t spirvbin_t::hashType(unsigned typeStart) const\r
- {\r
- const unsigned wordCount = asWordCount(typeStart);\r
- const spv::Op opCode = asOpCode(typeStart);\r
-\r
- switch (opCode) {\r
- case spv::OpTypeVoid: return 0;\r
- case spv::OpTypeBool: return 1;\r
- case spv::OpTypeInt: return 3 + (spv[typeStart+3]);\r
- case spv::OpTypeFloat: return 5;\r
- case spv::OpTypeVector:\r
- return 6 + hashType(typePos(spv[typeStart+2])) * (spv[typeStart+3] - 1);\r
- case spv::OpTypeMatrix:\r
- return 30 + hashType(typePos(spv[typeStart+2])) * (spv[typeStart+3] - 1);\r
- case spv::OpTypeSampler:\r
- return 120 + hashType(typePos(spv[typeStart+2])) +\r
- spv[typeStart+3] + // dimensionality\r
- spv[typeStart+4] * 8 * 16 + // content\r
- spv[typeStart+5] * 4 * 16 + // arrayed\r
- spv[typeStart+6] * 2 * 16 + // compare\r
- spv[typeStart+7] * 1 * 16; // multisampled\r
- case spv::OpTypeFilter:\r
- return 500;\r
- case spv::OpTypeArray:\r
- return 501 + hashType(typePos(spv[typeStart+2])) * spv[typeStart+3];\r
- case spv::OpTypeRuntimeArray:\r
- return 5000 + hashType(typePos(spv[typeStart+2]));\r
- case spv::OpTypeStruct:\r
- {\r
- std::uint32_t hash = 10000;\r
- for (unsigned w=2; w < wordCount; ++w)\r
- hash += w * hashType(typePos(spv[typeStart+w]));\r
- return hash;\r
- }\r
-\r
- case spv::OpTypeOpaque: return 6000 + spv[typeStart+2];\r
- case spv::OpTypePointer: return 100000 + hashType(typePos(spv[typeStart+3]));\r
- case spv::OpTypeFunction:\r
- {\r
- std::uint32_t hash = 200000;\r
- for (unsigned w=2; w < wordCount; ++w)\r
- hash += w * hashType(typePos(spv[typeStart+w]));\r
- return hash;\r
- }\r
-\r
- case spv::OpTypeEvent: return 300000;\r
- case spv::OpTypeDeviceEvent: return 300001;\r
- case spv::OpTypeReserveId: return 300002;\r
- case spv::OpTypeQueue: return 300003;\r
- case spv::OpTypePipe: return 300004;\r
-\r
- case spv::OpConstantNullObject: return 300005;\r
- case spv::OpConstantSampler: return 300006;\r
-\r
- case spv::OpConstantTrue: return 300007;\r
- case spv::OpConstantFalse: return 300008;\r
- case spv::OpConstantNullPointer: return 300009;\r
- case spv::OpConstantComposite:\r
- {\r
- std::uint32_t hash = 300011 + hashType(typePos(spv[typeStart+1]));\r
- for (unsigned w=3; w < wordCount; ++w)\r
- hash += w * hashType(typePos(spv[typeStart+w]));\r
- return hash;\r
- }\r
- case spv::OpConstant:\r
- {\r
- std::uint32_t hash = 400011 + hashType(typePos(spv[typeStart+1]));\r
- for (unsigned w=3; w < wordCount; ++w)\r
- hash += w * spv[typeStart+w];\r
- return hash;\r
- }\r
-\r
- default:\r
- error("unknown type opcode");\r
- return 0;\r
- }\r
- }\r
-\r
- void spirvbin_t::mapTypeConst()\r
- {\r
- globaltypes_t globalTypeMap;\r
-\r
- msg(3, 2, std::string("Remapping Consts & Types: "));\r
-\r
- static const std::uint32_t softTypeIdLimit = 3011; // small prime. TODO: get from options\r
- static const std::uint32_t firstMappedID = 8; // offset into ID space\r
-\r
- for (auto& typeStart : typeConstPos) {\r
- const spv::Id resId = asTypeConstId(typeStart);\r
- const std::uint32_t hashval = hashType(typeStart);\r
-\r
- if (isOldIdUnmapped(resId))\r
- localId(resId, nextUnusedId(hashval % softTypeIdLimit + firstMappedID));\r
- }\r
- }\r
-\r
-\r
- // Strip a single binary by removing ranges given in stripRange\r
- void spirvbin_t::strip()\r
- {\r
- if (stripRange.empty()) // nothing to do\r
- return;\r
-\r
- // Sort strip ranges in order of traversal\r
- std::sort(stripRange.begin(), stripRange.end());\r
-\r
- // Allocate a new binary big enough to hold old binary\r
- // We'll step this iterator through the strip ranges as we go through the binary\r
- auto strip_it = stripRange.begin();\r
-\r
- int strippedPos = 0;\r
- for (unsigned word = 0; word < unsigned(spv.size()); ++word) {\r
- if (strip_it != stripRange.end() && word >= strip_it->second)\r
- ++strip_it;\r
-\r
- if (strip_it == stripRange.end() || word < strip_it->first || word >= strip_it->second)\r
- spv[strippedPos++] = spv[word];\r
- }\r
-\r
- spv.resize(strippedPos);\r
- stripRange.clear();\r
-\r
- buildLocalMaps();\r
- }\r
-\r
- // Strip a single binary by removing ranges given in stripRange\r
- void spirvbin_t::remap(std::uint32_t opts)\r
- {\r
- options = opts;\r
-\r
- // Set up opcode tables from SpvDoc\r
- spv::Parameterize();\r
-\r
- validate(); // validate header\r
- buildLocalMaps();\r
-\r
- msg(3, 4, std::string("ID bound: ") + std::to_string(bound()));\r
-\r
- strip(); // strip out data we decided to eliminate\r
-\r
- if (options & OPT_LOADSTORE) optLoadStore();\r
- if (options & OPT_FWD_LS) forwardLoadStores();\r
- if (options & DCE_FUNCS) dceFuncs();\r
- if (options & DCE_VARS) dceVars();\r
- if (options & DCE_TYPES) dceTypes();\r
- if (options & MAP_TYPES) mapTypeConst();\r
- if (options & MAP_NAMES) mapNames();\r
- if (options & MAP_FUNCS) mapFnBodies();\r
-\r
- mapRemainder(); // map any unmapped IDs\r
- applyMap(); // Now remap each shader to the new IDs we've come up with\r
- strip(); // strip out data we decided to eliminate\r
- }\r
-\r
- // remap from a memory image\r
- void spirvbin_t::remap(std::vector<std::uint32_t>& in_spv, std::uint32_t opts)\r
- {\r
- spv.swap(in_spv);\r
- remap(opts);\r
- spv.swap(in_spv);\r
- }\r
-\r
-} // namespace SPV\r
-\r
-#endif // defined (use_cpp11)\r
-\r
+//
+//Copyright (C) 2015 LunarG, Inc.
+//
+//All rights reserved.
+//
+//Redistribution and use in source and binary forms, with or without
+//modification, are permitted provided that the following conditions
+//are met:
+//
+// Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//
+// Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following
+// disclaimer in the documentation and/or other materials provided
+// with the distribution.
+//
+// Neither the name of 3Dlabs Inc. Ltd. nor the names of its
+// contributors may be used to endorse or promote products derived
+// from this software without specific prior written permission.
+//
+//THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+//"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+//LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+//FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+//COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+//INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+//BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+//LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+//CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+//LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+//ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+//POSSIBILITY OF SUCH DAMAGE.
+//
+
+#include "SPVRemapper.h"
+#include "doc.h"
+
+#if !defined (use_cpp11)
+// ... not supported before C++11
+#else // defined (use_cpp11)
+
+#include <algorithm>
+#include <cassert>
+
+namespace spv {
+
+ // By default, just abort on error. Can be overridden via RegisterErrorHandler
+ spirvbin_t::errorfn_t spirvbin_t::errorHandler = [](const std::string&) { exit(5); };
+ // By default, eat log messages. Can be overridden via RegisterLogHandler
+ spirvbin_t::logfn_t spirvbin_t::logHandler = [](const std::string&) { };
+
+ // This can be overridden to provide other message behavior if needed
+ void spirvbin_t::msg(int minVerbosity, int indent, const std::string& txt) const
+ {
+ if (verbose >= minVerbosity)
+ logHandler(std::string(indent, ' ') + txt);
+ }
+
+ // hash opcode, with special handling for OpExtInst
+ std::uint32_t spirvbin_t::asOpCodeHash(unsigned word)
+ {
+ const spv::Op opCode = asOpCode(word);
+
+ std::uint32_t offset = 0;
+
+ switch (opCode) {
+ case spv::OpExtInst:
+ offset += asId(word + 4); break;
+ default:
+ break;
+ }
+
+ return opCode * 19 + offset; // 19 = small prime
+ }
+
+ spirvbin_t::range_t spirvbin_t::literalRange(spv::Op opCode) const
+ {
+ static const int maxCount = 1<<30;
+
+ switch (opCode) {
+ case spv::OpTypeFloat: // fall through...
+ case spv::OpTypePointer: return range_t(2, 3);
+ case spv::OpTypeInt: return range_t(2, 4);
+ case spv::OpTypeSampler: return range_t(3, 8);
+ case spv::OpTypeVector: // fall through
+ case spv::OpTypeMatrix: // ...
+ case spv::OpTypePipe: return range_t(3, 4);
+ case spv::OpConstant: return range_t(3, maxCount);
+ default: return range_t(0, 0);
+ }
+ }
+
+ spirvbin_t::range_t spirvbin_t::typeRange(spv::Op opCode) const
+ {
+ static const int maxCount = 1<<30;
+
+ if (isConstOp(opCode))
+ return range_t(1, 2);
+
+ switch (opCode) {
+ case spv::OpTypeVector: // fall through
+ case spv::OpTypeMatrix: // ...
+ case spv::OpTypeSampler: // ...
+ case spv::OpTypeArray: // ...
+ case spv::OpTypeRuntimeArray: // ...
+ case spv::OpTypePipe: return range_t(2, 3);
+ case spv::OpTypeStruct: // fall through
+ case spv::OpTypeFunction: return range_t(2, maxCount);
+ case spv::OpTypePointer: return range_t(3, 4);
+ default: return range_t(0, 0);
+ }
+ }
+
+ spirvbin_t::range_t spirvbin_t::constRange(spv::Op opCode) const
+ {
+ static const int maxCount = 1<<30;
+
+ switch (opCode) {
+ case spv::OpTypeArray: // fall through...
+ case spv::OpTypeRuntimeArray: return range_t(3, 4);
+ case spv::OpConstantComposite: return range_t(3, maxCount);
+ default: return range_t(0, 0);
+ }
+ }
+
+ // Is this an opcode we should remove when using --strip?
+ bool spirvbin_t::isStripOp(spv::Op opCode) const
+ {
+ switch (opCode) {
+ case spv::OpSource:
+ case spv::OpSourceExtension:
+ case spv::OpName:
+ case spv::OpMemberName:
+ case spv::OpLine: return true;
+ default: return false;
+ }
+ }
+
+ bool spirvbin_t::isFlowCtrlOpen(spv::Op opCode) const
+ {
+ switch (opCode) {
+ case spv::OpBranchConditional:
+ case spv::OpSwitch: return true;
+ default: return false;
+ }
+ }
+
+ bool spirvbin_t::isFlowCtrlClose(spv::Op opCode) const
+ {
+ switch (opCode) {
+ case spv::OpLoopMerge:
+ case spv::OpSelectionMerge: return true;
+ default: return false;
+ }
+ }
+
+ bool spirvbin_t::isTypeOp(spv::Op opCode) const
+ {
+ switch (opCode) {
+ case spv::OpTypeVoid:
+ case spv::OpTypeBool:
+ case spv::OpTypeInt:
+ case spv::OpTypeFloat:
+ case spv::OpTypeVector:
+ case spv::OpTypeMatrix:
+ case spv::OpTypeSampler:
+ case spv::OpTypeFilter:
+ case spv::OpTypeArray:
+ case spv::OpTypeRuntimeArray:
+ case spv::OpTypeStruct:
+ case spv::OpTypeOpaque:
+ case spv::OpTypePointer:
+ case spv::OpTypeFunction:
+ case spv::OpTypeEvent:
+ case spv::OpTypeDeviceEvent:
+ case spv::OpTypeReserveId:
+ case spv::OpTypeQueue:
+ case spv::OpTypePipe: return true;
+ default: return false;
+ }
+ }
+
+ bool spirvbin_t::isConstOp(spv::Op opCode) const
+ {
+ switch (opCode) {
+ case spv::OpConstantNullObject: error("unimplemented constant type");
+ case spv::OpConstantSampler: error("unimplemented constant type");
+
+ case spv::OpConstantTrue:
+ case spv::OpConstantFalse:
+ case spv::OpConstantNullPointer:
+ case spv::OpConstantComposite:
+ case spv::OpConstant: return true;
+ default: return false;
+ }
+ }
+
+ const auto inst_fn_nop = [](spv::Op, unsigned) { return false; };
+ const auto op_fn_nop = [](spv::Id&) { };
+
+ // g++ doesn't like these defined in the class proper in an anonymous namespace.
+ // Dunno why. Also MSVC doesn't like the constexpr keyword. Also dunno why.
+ // Defining them externally seems to please both compilers, so, here they are.
+ const spv::Id spirvbin_t::unmapped = spv::Id(-10000);
+ const spv::Id spirvbin_t::unused = spv::Id(-10001);
+ const int spirvbin_t::header_size = 5;
+
+ spv::Id spirvbin_t::nextUnusedId(spv::Id id)
+ {
+ while (isNewIdMapped(id)) // search for an unused ID
+ ++id;
+
+ return id;
+ }
+
+ spv::Id spirvbin_t::localId(spv::Id id, spv::Id newId)
+ {
+ assert(id != spv::NoResult && newId != spv::NoResult);
+
+ if (id >= idMapL.size())
+ idMapL.resize(id+1, unused);
+
+ if (newId != unmapped && newId != unused) {
+ if (isOldIdUnused(id))
+ error(std::string("ID unused in module: ") + std::to_string(id));
+
+ if (!isOldIdUnmapped(id))
+ error(std::string("ID already mapped: ") + std::to_string(id) + " -> "
+ + std::to_string(localId(id)));
+
+ if (isNewIdMapped(newId))
+ error(std::string("ID already used in module: ") + std::to_string(newId));
+
+ msg(4, 4, std::string("map: ") + std::to_string(id) + " -> " + std::to_string(newId));
+ setMapped(newId);
+ largestNewId = std::max(largestNewId, newId);
+ }
+
+ return idMapL[id] = newId;
+ }
+
+ // Parse a literal string from the SPIR binary and return it as an std::string
+ // Due to C++11 RValue references, this doesn't copy the result string.
+ std::string spirvbin_t::literalString(unsigned word) const
+ {
+ std::string literal;
+
+ literal.reserve(16);
+
+ const char* bytes = reinterpret_cast<const char*>(spv.data() + word);
+
+ while (bytes && *bytes)
+ literal += *bytes++;
+
+ return literal;
+ }
+
+
+ void spirvbin_t::applyMap()
+ {
+ msg(3, 2, std::string("Applying map: "));
+
+ // Map local IDs through the ID map
+ process(inst_fn_nop, // ignore instructions
+ [this](spv::Id& id) {
+ id = localId(id);
+ assert(id != unused && id != unmapped);
+ }
+ );
+ }
+
+
+ // Find free IDs for anything we haven't mapped
+ void spirvbin_t::mapRemainder()
+ {
+ msg(3, 2, std::string("Remapping remainder: "));
+
+ spv::Id unusedId = 1; // can't use 0: that's NoResult
+ spirword_t maxBound = 0;
+
+ for (spv::Id id = 0; id < idMapL.size(); ++id) {
+ if (isOldIdUnused(id))
+ continue;
+
+ // Find a new mapping for any used but unmapped IDs
+ if (isOldIdUnmapped(id))
+ localId(id, unusedId = nextUnusedId(unusedId));
+
+ if (isOldIdUnmapped(id))
+ error(std::string("old ID not mapped: ") + std::to_string(id));
+
+ // Track max bound
+ maxBound = std::max(maxBound, localId(id) + 1);
+ }
+
+ bound(maxBound); // reset header ID bound to as big as it now needs to be
+ }
+
+ void spirvbin_t::stripDebug()
+ {
+ if ((options & STRIP) == 0)
+ return;
+
+ // build local Id and name maps
+ process(
+ [&](spv::Op opCode, unsigned start) {
+ // remember opcodes we want to strip later
+ if (isStripOp(opCode))
+ stripInst(start);
+ return true;
+ },
+ op_fn_nop);
+ }
+
+ void spirvbin_t::buildLocalMaps()
+ {
+ msg(2, 2, std::string("build local maps: "));
+
+ mapped.clear();
+ idMapL.clear();
+// preserve nameMap, so we don't clear that.
+ fnPos.clear();
+ fnPosDCE.clear();
+ fnCalls.clear();
+ typeConstPos.clear();
+ typeConstPosR.clear();
+ entryPoint = spv::NoResult;
+ largestNewId = 0;
+
+ idMapL.resize(bound(), unused);
+
+ int fnStart = 0;
+ spv::Id fnRes = spv::NoResult;
+
+ // build local Id and name maps
+ process(
+ [&](spv::Op opCode, unsigned start) {
+ // remember opcodes we want to strip later
+ if ((options & STRIP) && isStripOp(opCode))
+ stripInst(start);
+
+ if (opCode == spv::Op::OpName) {
+ const spv::Id target = asId(start+1);
+ const std::string name = literalString(start+2);
+ nameMap[name] = target;
+
+ } else if (opCode == spv::Op::OpFunctionCall) {
+ ++fnCalls[asId(start + 3)];
+ } else if (opCode == spv::Op::OpEntryPoint) {
+ entryPoint = asId(start + 2);
+ } else if (opCode == spv::Op::OpFunction) {
+ if (fnStart != 0)
+ error("nested function found");
+ fnStart = start;
+ fnRes = asId(start + 2);
+ } else if (opCode == spv::Op::OpFunctionEnd) {
+ assert(fnRes != spv::NoResult);
+ if (fnStart == 0)
+ error("function end without function start");
+ fnPos[fnRes] = range_t(fnStart, start + asWordCount(start));
+ fnStart = 0;
+ } else if (isConstOp(opCode)) {
+ assert(asId(start + 2) != spv::NoResult);
+ typeConstPos.insert(start);
+ typeConstPosR[asId(start + 2)] = start;
+ } else if (isTypeOp(opCode)) {
+ assert(asId(start + 1) != spv::NoResult);
+ typeConstPos.insert(start);
+ typeConstPosR[asId(start + 1)] = start;
+ }
+
+ return false;
+ },
+
+ [this](spv::Id& id) { localId(id, unmapped); }
+ );
+ }
+
+ // Validate the SPIR header
+ void spirvbin_t::validate() const
+ {
+ msg(2, 2, std::string("validating: "));
+
+ if (spv.size() < header_size)
+ error("file too short: ");
+
+ if (magic() != spv::MagicNumber)
+ error("bad magic number");
+
+ // field 1 = version
+ // field 2 = generator magic
+ // field 3 = result <id> bound
+
+ if (schemaNum() != 0)
+ error("bad schema, must be 0");
+ }
+
+
+ int spirvbin_t::processInstruction(unsigned word, instfn_t instFn, idfn_t idFn)
+ {
+ const auto instructionStart = word;
+ const unsigned wordCount = asWordCount(instructionStart);
+ const spv::Op opCode = asOpCode(instructionStart);
+ const int nextInst = word++ + wordCount;
+
+ if (nextInst > int(spv.size()))
+ error("spir instruction terminated too early");
+
+ // Base for computing number of operands; will be updated as more is learned
+ unsigned numOperands = wordCount - 1;
+
+ if (instFn(opCode, instructionStart))
+ return nextInst;
+
+ // Read type and result ID from instruction desc table
+ if (spv::InstructionDesc[opCode].hasType()) {
+ idFn(asId(word++));
+ --numOperands;
+ }
+
+ if (spv::InstructionDesc[opCode].hasResult()) {
+ idFn(asId(word++));
+ --numOperands;
+ }
+
+ // Extended instructions: currently, assume everything is an ID.
+ // TODO: add whatever data we need for exceptions to that
+ if (opCode == spv::OpExtInst) {
+ word += 2; // instruction set, and instruction from set
+ numOperands -= 2;
+
+ for (unsigned op=0; op < numOperands; ++op)
+ idFn(asId(word++)); // ID
+
+ return nextInst;
+ }
+
+ // Store IDs from instruction in our map
+ for (int op = 0; op < spv::InstructionDesc[opCode].operands.getNum(); ++op, --numOperands) {
+ switch (spv::InstructionDesc[opCode].operands.getClass(op)) {
+ case spv::OperandId:
+ idFn(asId(word++));
+ break;
+
+ case spv::OperandOptionalId:
+ case spv::OperandVariableIds:
+ for (unsigned i = 0; i < numOperands; ++i)
+ idFn(asId(word++));
+ return nextInst;
+
+ case spv::OperandVariableLiterals:
+ if (opCode == spv::OpDecorate && asDecoration(word - 1) == spv::DecorationBuiltIn) {
+ ++word;
+ --numOperands;
+ }
+ word += numOperands;
+ return nextInst;
+
+ case spv::OperandVariableLiteralId:
+ while (numOperands > 0) {
+ ++word; // immediate
+ idFn(asId(word++)); // ID
+ numOperands -= 2;
+ }
+ return nextInst;
+
+ case spv::OperandLiteralString:
+ word += literalStringWords(literalString(word));
+ return nextInst;
+
+ // Single word operands we simply ignore, as they hold no IDs
+ case spv::OperandLiteralNumber:
+ case spv::OperandSource:
+ case spv::OperandExecutionModel:
+ case spv::OperandAddressing:
+ case spv::OperandMemory:
+ case spv::OperandExecutionMode:
+ case spv::OperandStorage:
+ case spv::OperandDimensionality:
+ case spv::OperandDecoration:
+ case spv::OperandBuiltIn:
+ case spv::OperandSelect:
+ case spv::OperandLoop:
+ case spv::OperandFunction:
+ case spv::OperandMemorySemantics:
+ case spv::OperandMemoryAccess:
+ case spv::OperandExecutionScope:
+ case spv::OperandGroupOperation:
+ case spv::OperandKernelEnqueueFlags:
+ case spv::OperandKernelProfilingInfo:
+ ++word;
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ return nextInst;
+ }
+
+ // Make a pass over all the instructions and process them given appropriate functions
+ spirvbin_t& spirvbin_t::process(instfn_t instFn, idfn_t idFn, unsigned begin, unsigned end)
+ {
+ // For efficiency, reserve name map space. It can grow if needed.
+ nameMap.reserve(32);
+
+ // If begin or end == 0, use defaults
+ begin = (begin == 0 ? header_size : begin);
+ end = (end == 0 ? unsigned(spv.size()) : end);
+
+ // basic parsing and InstructionDesc table borrowed from SpvDisassemble.cpp...
+ unsigned nextInst = unsigned(spv.size());
+
+ for (unsigned word = begin; word < end; word = nextInst)
+ nextInst = processInstruction(word, instFn, idFn);
+
+ return *this;
+ }
+
+ // Apply global name mapping to a single module
+ void spirvbin_t::mapNames()
+ {
+ static const std::uint32_t softTypeIdLimit = 3011; // small prime. TODO: get from options
+ static const std::uint32_t firstMappedID = 3019; // offset into ID space
+
+ for (const auto& name : nameMap) {
+ std::uint32_t hashval = 1911;
+ for (const char c : name.first)
+ hashval = hashval * 1009 + c;
+
+ if (isOldIdUnmapped(name.second))
+ localId(name.second, nextUnusedId(hashval % softTypeIdLimit + firstMappedID));
+ }
+ }
+
+ // Map fn contents to IDs of similar functions in other modules
+ void spirvbin_t::mapFnBodies()
+ {
+ static const std::uint32_t softTypeIdLimit = 19071; // small prime. TODO: get from options
+ static const std::uint32_t firstMappedID = 6203; // offset into ID space
+
+ // Initial approach: go through some high priority opcodes first and assign them
+ // hash values.
+
+ spv::Id fnId = spv::NoResult;
+ std::vector<unsigned> instPos;
+ instPos.reserve(unsigned(spv.size()) / 16); // initial estimate; can grow if needed.
+
+ // Build local table of instruction start positions
+ process(
+ [&](spv::Op, unsigned start) { instPos.push_back(start); return true; },
+ op_fn_nop);
+
+ // Window size for context-sensitive canonicalization values
+ // Emperical best size from a single data set. TODO: Would be a good tunable.
+ // We essentially performa a little convolution around each instruction,
+ // to capture the flavor of nearby code, to hopefully match to similar
+ // code in other modules.
+ static const unsigned windowSize = 2;
+
+ for (unsigned entry = 0; entry < unsigned(instPos.size()); ++entry) {
+ const unsigned start = instPos[entry];
+ const spv::Op opCode = asOpCode(start);
+
+ if (opCode == spv::OpFunction)
+ fnId = asId(start + 2);
+
+ if (opCode == spv::OpFunctionEnd)
+ fnId = spv::NoResult;
+
+ if (fnId != spv::NoResult) { // if inside a function
+ if (spv::InstructionDesc[opCode].hasResult()) {
+ const unsigned word = start + (spv::InstructionDesc[opCode].hasType() ? 2 : 1);
+ const spv::Id resId = asId(word);
+ std::uint32_t hashval = fnId * 17; // small prime
+
+ for (unsigned i = entry-1; i >= entry-windowSize; --i) {
+ if (asOpCode(instPos[i]) == spv::OpFunction)
+ break;
+ hashval = hashval * 30103 + asOpCodeHash(instPos[i]); // 30103 = semiarbitrary prime
+ }
+
+ for (unsigned i = entry; i <= entry + windowSize; ++i) {
+ if (asOpCode(instPos[i]) == spv::OpFunctionEnd)
+ break;
+ hashval = hashval * 30103 + asOpCodeHash(instPos[i]); // 30103 = semiarbitrary prime
+ }
+
+ if (isOldIdUnmapped(resId))
+ localId(resId, nextUnusedId(hashval % softTypeIdLimit + firstMappedID));
+ }
+ }
+ }
+
+ spv::Op thisOpCode(spv::OpNop);
+ std::unordered_map<int, int> opCounter;
+ int idCounter(0);
+ fnId = spv::NoResult;
+
+ process(
+ [&](spv::Op opCode, unsigned start) {
+ switch (opCode) {
+ case spv::OpFunction:
+ // Reset counters at each function
+ idCounter = 0;
+ opCounter.clear();
+ fnId = asId(start + 2);
+ break;
+
+ case spv::OpTextureSample:
+ case spv::OpTextureSampleDref:
+ case spv::OpTextureSampleLod:
+ case spv::OpTextureSampleProj:
+ case spv::OpTextureSampleGrad:
+ case spv::OpTextureSampleOffset:
+ case spv::OpTextureSampleProjLod:
+ case spv::OpTextureSampleProjGrad:
+ case spv::OpTextureSampleLodOffset:
+ case spv::OpTextureSampleProjOffset:
+ case spv::OpTextureSampleGradOffset:
+ case spv::OpTextureSampleProjLodOffset:
+ case spv::OpTextureSampleProjGradOffset:
+ case spv::OpDot:
+ case spv::OpCompositeExtract:
+ case spv::OpCompositeInsert:
+ case spv::OpVectorShuffle:
+ case spv::OpLabel:
+ case spv::OpVariable:
+
+ case spv::OpAccessChain:
+ case spv::OpLoad:
+ case spv::OpStore:
+ case spv::OpCompositeConstruct:
+ case spv::OpFunctionCall:
+ ++opCounter[opCode];
+ idCounter = 0;
+ thisOpCode = opCode;
+ break;
+ default:
+ thisOpCode = spv::OpNop;
+ }
+
+ return false;
+ },
+
+ [&](spv::Id& id) {
+ if (thisOpCode != spv::OpNop) {
+ ++idCounter;
+ const std::uint32_t hashval = opCounter[thisOpCode] * thisOpCode * 50047 + idCounter + fnId * 117;
+
+ if (isOldIdUnmapped(id))
+ localId(id, nextUnusedId(hashval % softTypeIdLimit + firstMappedID));
+ }
+ });
+ }
+
+ // EXPERIMENTAL: forward IO and uniform load/stores into operands
+ // This produces invalid Schema-0 SPIRV
+ void spirvbin_t::forwardLoadStores()
+ {
+ idset_t fnLocalVars; // set of function local vars
+ idmap_t idMap; // Map of load result IDs to what they load
+
+ // EXPERIMENTAL: Forward input and access chain loads into consumptions
+ process(
+ [&](spv::Op opCode, unsigned start) {
+ // Add inputs and uniforms to the map
+ if (((opCode == spv::OpVariable && asWordCount(start) == 4) || (opCode == spv::OpVariableArray)) &&
+ (spv[start+3] == spv::StorageClassUniform ||
+ spv[start+3] == spv::StorageClassUniformConstant ||
+ spv[start+3] == spv::StorageClassInput))
+ fnLocalVars.insert(asId(start+2));
+
+ if (opCode == spv::OpAccessChain && fnLocalVars.count(asId(start+3)) > 0)
+ fnLocalVars.insert(asId(start+2));
+
+ if (opCode == spv::OpLoad && fnLocalVars.count(asId(start+3)) > 0) {
+ idMap[asId(start+2)] = asId(start+3);
+ stripInst(start);
+ }
+
+ return false;
+ },
+
+ [&](spv::Id& id) { if (idMap.find(id) != idMap.end()) id = idMap[id]; }
+ );
+
+ // EXPERIMENTAL: Implicit output stores
+ fnLocalVars.clear();
+ idMap.clear();
+
+ process(
+ [&](spv::Op opCode, unsigned start) {
+ // Add inputs and uniforms to the map
+ if (((opCode == spv::OpVariable && asWordCount(start) == 4) || (opCode == spv::OpVariableArray)) &&
+ (spv[start+3] == spv::StorageClassOutput))
+ fnLocalVars.insert(asId(start+2));
+
+ if (opCode == spv::OpStore && fnLocalVars.count(asId(start+1)) > 0) {
+ idMap[asId(start+2)] = asId(start+1);
+ stripInst(start);
+ }
+
+ return false;
+ },
+ op_fn_nop);
+
+ process(
+ inst_fn_nop,
+ [&](spv::Id& id) { if (idMap.find(id) != idMap.end()) id = idMap[id]; }
+ );
+
+ strip(); // strip out data we decided to eliminate
+ }
+
+ // remove bodies of uncalled functions
+ void spirvbin_t::optLoadStore()
+ {
+ idset_t fnLocalVars;
+ // Map of load result IDs to what they load
+ idmap_t idMap;
+
+ // Find all the function local pointers stored at most once, and not via access chains
+ process(
+ [&](spv::Op opCode, unsigned start) {
+ const int wordCount = asWordCount(start);
+
+ // Add local variables to the map
+ if ((opCode == spv::OpVariable && spv[start+3] == spv::StorageClassFunction && asWordCount(start) == 4) ||
+ (opCode == spv::OpVariableArray && spv[start+3] == spv::StorageClassFunction))
+ fnLocalVars.insert(asId(start+2));
+
+ // Ignore process vars referenced via access chain
+ if ((opCode == spv::OpAccessChain || opCode == spv::OpInBoundsAccessChain) && fnLocalVars.count(asId(start+3)) > 0) {
+ fnLocalVars.erase(asId(start+3));
+ idMap.erase(asId(start+3));
+ }
+
+ if (opCode == spv::OpLoad && fnLocalVars.count(asId(start+3)) > 0) {
+ // Avoid loads before stores (TODO: why? Crashes driver, but seems like it shouldn't).
+ if (idMap.find(asId(start+3)) == idMap.end()) {
+ fnLocalVars.erase(asId(start+3));
+ idMap.erase(asId(start+3));
+ }
+
+ // don't do for volatile references
+ if (wordCount > 4 && (spv[start+4] & spv::MemoryAccessVolatileMask)) {
+ fnLocalVars.erase(asId(start+3));
+ idMap.erase(asId(start+3));
+ }
+ }
+
+ if (opCode == spv::OpStore && fnLocalVars.count(asId(start+1)) > 0) {
+ if (idMap.find(asId(start+1)) == idMap.end()) {
+ idMap[asId(start+1)] = asId(start+2);
+ } else {
+ // Remove if it has more than one store to the same pointer
+ fnLocalVars.erase(asId(start+1));
+ idMap.erase(asId(start+1));
+ }
+
+ // don't do for volatile references
+ if (wordCount > 3 && (spv[start+3] & spv::MemoryAccessVolatileMask)) {
+ fnLocalVars.erase(asId(start+3));
+ idMap.erase(asId(start+3));
+ }
+ }
+
+ return true;
+ },
+ op_fn_nop);
+
+ process(
+ [&](spv::Op opCode, unsigned start) {
+ if (opCode == spv::OpLoad && fnLocalVars.count(asId(start+3)) > 0)
+ idMap[asId(start+2)] = idMap[asId(start+3)];
+ return false;
+ },
+ op_fn_nop);
+
+ // Remove the load/store/variables for the ones we've discovered
+ process(
+ [&](spv::Op opCode, unsigned start) {
+ if ((opCode == spv::OpLoad && fnLocalVars.count(asId(start+3)) > 0) ||
+ (opCode == spv::OpStore && fnLocalVars.count(asId(start+1)) > 0) ||
+ (opCode == spv::OpVariable && fnLocalVars.count(asId(start+2)) > 0)) {
+ stripInst(start);
+ return true;
+ }
+
+ return false;
+ },
+
+ [&](spv::Id& id) { if (idMap.find(id) != idMap.end()) id = idMap[id]; }
+ );
+
+ strip(); // strip out data we decided to eliminate
+ }
+
+ // remove bodies of uncalled functions
+ void spirvbin_t::dceFuncs()
+ {
+ msg(3, 2, std::string("Removing Dead Functions: "));
+
+ // TODO: There are more efficient ways to do this.
+ bool changed = true;
+
+ while (changed) {
+ changed = false;
+
+ for (auto fn = fnPos.begin(); fn != fnPos.end(); ) {
+ if (fn->first == entryPoint) { // don't DCE away the entry point!
+ ++fn;
+ continue;
+ }
+
+ const auto call_it = fnCalls.find(fn->first);
+
+ if (call_it == fnCalls.end() || call_it->second == 0) {
+ changed = true;
+ stripRange.push_back(fn->second);
+ fnPosDCE.insert(*fn);
+
+ // decrease counts of called functions
+ process(
+ [&](spv::Op opCode, unsigned start) {
+ if (opCode == spv::Op::OpFunctionCall) {
+ const auto call_it = fnCalls.find(asId(start + 3));
+ if (call_it != fnCalls.end()) {
+ if (--call_it->second <= 0)
+ fnCalls.erase(call_it);
+ }
+ }
+
+ return true;
+ },
+ op_fn_nop,
+ fn->second.first,
+ fn->second.second);
+
+ fn = fnPos.erase(fn);
+ } else ++fn;
+ }
+ }
+ }
+
+ // remove unused function variables + decorations
+ void spirvbin_t::dceVars()
+ {
+ msg(3, 2, std::string("DCE Vars: "));
+
+ std::unordered_map<spv::Id, int> varUseCount;
+
+ // Count function variable use
+ process(
+ [&](spv::Op opCode, unsigned start) {
+ if (opCode == spv::OpVariable) { ++varUseCount[asId(start+2)]; return true; }
+ return false;
+ },
+
+ [&](spv::Id& id) { if (varUseCount[id]) ++varUseCount[id]; }
+ );
+
+ // Remove single-use function variables + associated decorations and names
+ process(
+ [&](spv::Op opCode, unsigned start) {
+ if ((opCode == spv::OpVariable && varUseCount[asId(start+2)] == 1) ||
+ (opCode == spv::OpDecorate && varUseCount[asId(start+1)] == 1) ||
+ (opCode == spv::OpName && varUseCount[asId(start+1)] == 1)) {
+ stripInst(start);
+ }
+ return true;
+ },
+ op_fn_nop);
+ }
+
+ // remove unused types
+ void spirvbin_t::dceTypes()
+ {
+ std::vector<bool> isType(bound(), false);
+
+ // for speed, make O(1) way to get to type query (map is log(n))
+ for (const auto typeStart : typeConstPos)
+ isType[asTypeConstId(typeStart)] = true;
+
+ std::unordered_map<spv::Id, int> typeUseCount;
+
+ // Count total type usage
+ process(inst_fn_nop,
+ [&](spv::Id& id) { if (isType[id]) ++typeUseCount[id]; }
+ );
+
+ // Remove types from deleted code
+ for (const auto& fn : fnPosDCE)
+ process(inst_fn_nop,
+ [&](spv::Id& id) { if (isType[id]) --typeUseCount[id]; },
+ fn.second.first, fn.second.second);
+
+ // Remove single reference types
+ for (const auto typeStart : typeConstPos) {
+ const spv::Id typeId = asTypeConstId(typeStart);
+ if (typeUseCount[typeId] == 1) {
+ --typeUseCount[typeId];
+ stripInst(typeStart);
+ }
+ }
+ }
+
+
+#ifdef NOTDEF
+ bool spirvbin_t::matchType(const spirvbin_t::globaltypes_t& globalTypes, spv::Id lt, spv::Id gt) const
+ {
+ // Find the local type id "lt" and global type id "gt"
+ const auto lt_it = typeConstPosR.find(lt);
+ if (lt_it == typeConstPosR.end())
+ return false;
+
+ const auto typeStart = lt_it->second;
+
+ // Search for entry in global table
+ const auto gtype = globalTypes.find(gt);
+ if (gtype == globalTypes.end())
+ return false;
+
+ const auto& gdata = gtype->second;
+
+ // local wordcount and opcode
+ const int wordCount = asWordCount(typeStart);
+ const spv::Op opCode = asOpCode(typeStart);
+
+ // no type match if opcodes don't match, or operand count doesn't match
+ if (opCode != opOpCode(gdata[0]) || wordCount != opWordCount(gdata[0]))
+ return false;
+
+ const unsigned numOperands = wordCount - 2; // all types have a result
+
+ const auto cmpIdRange = [&](range_t range) {
+ for (int x=range.first; x<std::min(range.second, wordCount); ++x)
+ if (!matchType(globalTypes, asId(typeStart+x), gdata[x]))
+ return false;
+ return true;
+ };
+
+ const auto cmpConst = [&]() { return cmpIdRange(constRange(opCode)); };
+ const auto cmpSubType = [&]() { return cmpIdRange(typeRange(opCode)); };
+
+ // Compare literals in range [start,end)
+ const auto cmpLiteral = [&]() {
+ const auto range = literalRange(opCode);
+ return std::equal(spir.begin() + typeStart + range.first,
+ spir.begin() + typeStart + std::min(range.second, wordCount),
+ gdata.begin() + range.first);
+ };
+
+ assert(isTypeOp(opCode) || isConstOp(opCode));
+
+ switch (opCode) {
+ case spv::OpTypeOpaque: // TODO: disable until we compare the literal strings.
+ case spv::OpTypeQueue: return false;
+ case spv::OpTypeEvent: // fall through...
+ case spv::OpTypeDeviceEvent: // ...
+ case spv::OpTypeReserveId: return false;
+ // for samplers, we don't handle the optional parameters yet
+ case spv::OpTypeSampler: return cmpLiteral() && cmpConst() && cmpSubType() && wordCount == 8;
+ default: return cmpLiteral() && cmpConst() && cmpSubType();
+ }
+ }
+
+
+ // Look for an equivalent type in the globalTypes map
+ spv::Id spirvbin_t::findType(const spirvbin_t::globaltypes_t& globalTypes, spv::Id lt) const
+ {
+ // Try a recursive type match on each in turn, and return a match if we find one
+ for (const auto& gt : globalTypes)
+ if (matchType(globalTypes, lt, gt.first))
+ return gt.first;
+
+ return spv::NoType;
+ }
+#endif // NOTDEF
+
+ // Return start position in SPV of given type. error if not found.
+ unsigned spirvbin_t::typePos(spv::Id id) const
+ {
+ const auto tid_it = typeConstPosR.find(id);
+ if (tid_it == typeConstPosR.end())
+ error("type ID not found");
+
+ return tid_it->second;
+ }
+
+ // Hash types to canonical values. This can return ID collisions (it's a bit
+ // inevitable): it's up to the caller to handle that gracefully.
+ std::uint32_t spirvbin_t::hashType(unsigned typeStart) const
+ {
+ const unsigned wordCount = asWordCount(typeStart);
+ const spv::Op opCode = asOpCode(typeStart);
+
+ switch (opCode) {
+ case spv::OpTypeVoid: return 0;
+ case spv::OpTypeBool: return 1;
+ case spv::OpTypeInt: return 3 + (spv[typeStart+3]);
+ case spv::OpTypeFloat: return 5;
+ case spv::OpTypeVector:
+ return 6 + hashType(typePos(spv[typeStart+2])) * (spv[typeStart+3] - 1);
+ case spv::OpTypeMatrix:
+ return 30 + hashType(typePos(spv[typeStart+2])) * (spv[typeStart+3] - 1);
+ case spv::OpTypeSampler:
+ return 120 + hashType(typePos(spv[typeStart+2])) +
+ spv[typeStart+3] + // dimensionality
+ spv[typeStart+4] * 8 * 16 + // content
+ spv[typeStart+5] * 4 * 16 + // arrayed
+ spv[typeStart+6] * 2 * 16 + // compare
+ spv[typeStart+7] * 1 * 16; // multisampled
+ case spv::OpTypeFilter:
+ return 500;
+ case spv::OpTypeArray:
+ return 501 + hashType(typePos(spv[typeStart+2])) * spv[typeStart+3];
+ case spv::OpTypeRuntimeArray:
+ return 5000 + hashType(typePos(spv[typeStart+2]));
+ case spv::OpTypeStruct:
+ {
+ std::uint32_t hash = 10000;
+ for (unsigned w=2; w < wordCount; ++w)
+ hash += w * hashType(typePos(spv[typeStart+w]));
+ return hash;
+ }
+
+ case spv::OpTypeOpaque: return 6000 + spv[typeStart+2];
+ case spv::OpTypePointer: return 100000 + hashType(typePos(spv[typeStart+3]));
+ case spv::OpTypeFunction:
+ {
+ std::uint32_t hash = 200000;
+ for (unsigned w=2; w < wordCount; ++w)
+ hash += w * hashType(typePos(spv[typeStart+w]));
+ return hash;
+ }
+
+ case spv::OpTypeEvent: return 300000;
+ case spv::OpTypeDeviceEvent: return 300001;
+ case spv::OpTypeReserveId: return 300002;
+ case spv::OpTypeQueue: return 300003;
+ case spv::OpTypePipe: return 300004;
+
+ case spv::OpConstantNullObject: return 300005;
+ case spv::OpConstantSampler: return 300006;
+
+ case spv::OpConstantTrue: return 300007;
+ case spv::OpConstantFalse: return 300008;
+ case spv::OpConstantNullPointer: return 300009;
+ case spv::OpConstantComposite:
+ {
+ std::uint32_t hash = 300011 + hashType(typePos(spv[typeStart+1]));
+ for (unsigned w=3; w < wordCount; ++w)
+ hash += w * hashType(typePos(spv[typeStart+w]));
+ return hash;
+ }
+ case spv::OpConstant:
+ {
+ std::uint32_t hash = 400011 + hashType(typePos(spv[typeStart+1]));
+ for (unsigned w=3; w < wordCount; ++w)
+ hash += w * spv[typeStart+w];
+ return hash;
+ }
+
+ default:
+ error("unknown type opcode");
+ return 0;
+ }
+ }
+
+ void spirvbin_t::mapTypeConst()
+ {
+ globaltypes_t globalTypeMap;
+
+ msg(3, 2, std::string("Remapping Consts & Types: "));
+
+ static const std::uint32_t softTypeIdLimit = 3011; // small prime. TODO: get from options
+ static const std::uint32_t firstMappedID = 8; // offset into ID space
+
+ for (auto& typeStart : typeConstPos) {
+ const spv::Id resId = asTypeConstId(typeStart);
+ const std::uint32_t hashval = hashType(typeStart);
+
+ if (isOldIdUnmapped(resId))
+ localId(resId, nextUnusedId(hashval % softTypeIdLimit + firstMappedID));
+ }
+ }
+
+
+ // Strip a single binary by removing ranges given in stripRange
+ void spirvbin_t::strip()
+ {
+ if (stripRange.empty()) // nothing to do
+ return;
+
+ // Sort strip ranges in order of traversal
+ std::sort(stripRange.begin(), stripRange.end());
+
+ // Allocate a new binary big enough to hold old binary
+ // We'll step this iterator through the strip ranges as we go through the binary
+ auto strip_it = stripRange.begin();
+
+ int strippedPos = 0;
+ for (unsigned word = 0; word < unsigned(spv.size()); ++word) {
+ if (strip_it != stripRange.end() && word >= strip_it->second)
+ ++strip_it;
+
+ if (strip_it == stripRange.end() || word < strip_it->first || word >= strip_it->second)
+ spv[strippedPos++] = spv[word];
+ }
+
+ spv.resize(strippedPos);
+ stripRange.clear();
+
+ buildLocalMaps();
+ }
+
+ // Strip a single binary by removing ranges given in stripRange
+ void spirvbin_t::remap(std::uint32_t opts)
+ {
+ options = opts;
+
+ // Set up opcode tables from SpvDoc
+ spv::Parameterize();
+
+ validate(); // validate header
+ buildLocalMaps();
+
+ msg(3, 4, std::string("ID bound: ") + std::to_string(bound()));
+
+ strip(); // strip out data we decided to eliminate
+
+ if (options & OPT_LOADSTORE) optLoadStore();
+ if (options & OPT_FWD_LS) forwardLoadStores();
+ if (options & DCE_FUNCS) dceFuncs();
+ if (options & DCE_VARS) dceVars();
+ if (options & DCE_TYPES) dceTypes();
+ if (options & MAP_TYPES) mapTypeConst();
+ if (options & MAP_NAMES) mapNames();
+ if (options & MAP_FUNCS) mapFnBodies();
+
+ mapRemainder(); // map any unmapped IDs
+ applyMap(); // Now remap each shader to the new IDs we've come up with
+ strip(); // strip out data we decided to eliminate
+ }
+
+ // remap from a memory image
+ void spirvbin_t::remap(std::vector<std::uint32_t>& in_spv, std::uint32_t opts)
+ {
+ spv.swap(in_spv);
+ remap(opts);
+ spv.swap(in_spv);
+ }
+
+} // namespace SPV
+
+#endif // defined (use_cpp11)
+
-//\r
-//Copyright (C) 2015 LunarG, Inc.\r
-//\r
-//All rights reserved.\r
-//\r
-//Redistribution and use in source and binary forms, with or without\r
-//modification, are permitted provided that the following conditions\r
-//are met:\r
-//\r
-// Redistributions of source code must retain the above copyright\r
-// notice, this list of conditions and the following disclaimer.\r
-//\r
-// Redistributions in binary form must reproduce the above\r
-// copyright notice, this list of conditions and the following\r
-// disclaimer in the documentation and/or other materials provided\r
-// with the distribution.\r
-//\r
-// Neither the name of 3Dlabs Inc. Ltd. nor the names of its\r
-// contributors may be used to endorse or promote products derived\r
-// from this software without specific prior written permission.\r
-//\r
-//THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\r
-//"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\r
-//LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS\r
-//FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE\r
-//COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,\r
-//INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,\r
-//BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\r
-//LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER\r
-//CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\r
-//LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN\r
-//ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE\r
-//POSSIBILITY OF SUCH DAMAGE.\r
-//\r
-\r
-#ifndef SPIRVREMAPPER_H\r
-#define SPIRVREMAPPER_H\r
-\r
-#include <string>\r
-#include <vector>\r
-#include <stdlib.h>\r
-\r
-namespace spv {\r
-\r
-// MSVC defines __cplusplus as an older value, even when it supports almost all of 11.\r
-// We handle that here by making our own symbol.\r
-#if __cplusplus >= 201103L || _MSC_VER >= 1700\r
-# define use_cpp11 1\r
-#endif\r
-\r
-class spirvbin_base_t\r
-{\r
-public:\r
- enum Options {\r
- NONE = 0,\r
- STRIP = (1<<0),\r
- MAP_TYPES = (1<<1),\r
- MAP_NAMES = (1<<2),\r
- MAP_FUNCS = (1<<3),\r
- DCE_FUNCS = (1<<4),\r
- DCE_VARS = (1<<5),\r
- DCE_TYPES = (1<<6),\r
- OPT_LOADSTORE = (1<<7),\r
- OPT_FWD_LS = (1<<8), // EXPERIMENTAL: PRODUCES INVALID SCHEMA-0 SPIRV\r
- MAP_ALL = (MAP_TYPES | MAP_NAMES | MAP_FUNCS),\r
- DCE_ALL = (DCE_FUNCS | DCE_VARS | DCE_TYPES),\r
- OPT_ALL = (OPT_LOADSTORE),\r
-\r
- ALL_BUT_STRIP = (MAP_ALL | DCE_ALL | OPT_ALL),\r
- DO_EVERYTHING = (STRIP | ALL_BUT_STRIP)\r
- };\r
-};\r
-\r
-} // namespace SPV\r
-\r
-#if !defined (use_cpp11)\r
-#include <stdio.h>\r
-\r
-namespace spv {\r
-class spirvbin_t : public spirvbin_base_t\r
-{\r
-public:\r
- spirvbin_t(int /*verbose = 0*/) { }\r
-\r
- void remap(std::vector<unsigned int>& /*spv*/, unsigned int /*opts = 0*/)\r
- {\r
- printf("Tool not compiled for C++11, which is required for SPIR-V remapping.\n");\r
- exit(5);\r
- }\r
-};\r
-\r
-} // namespace SPV\r
-\r
-#else // defined (use_cpp11)\r
-\r
-#include <functional>\r
-#include <cstdint>\r
-#include <unordered_map>\r
-#include <unordered_set>\r
-#include <map>\r
-#include <set>\r
-#include <cassert>\r
-\r
-#include "../../glslang/SPIRV/spirv.h"\r
-#include "../../glslang/SPIRV/spvIR.h"\r
-\r
-namespace spv {\r
-\r
-// class to hold SPIR-V binary data for remapping, DCE, and debug stripping\r
-class spirvbin_t : public spirvbin_base_t\r
-{\r
-public:\r
- spirvbin_t(int verbose = 0) : entryPoint(spv::NoResult), largestNewId(0), verbose(verbose) { }\r
- \r
- // remap on an existing binary in memory\r
- void remap(std::vector<std::uint32_t>& spv, std::uint32_t opts = DO_EVERYTHING);\r
-\r
- // Type for error/log handler functions\r
- typedef std::function<void(const std::string&)> errorfn_t;\r
- typedef std::function<void(const std::string&)> logfn_t;\r
-\r
- // Register error/log handling functions (can be lambda fn / functor / etc)\r
- static void registerErrorHandler(errorfn_t handler) { errorHandler = handler; }\r
- static void registerLogHandler(logfn_t handler) { logHandler = handler; }\r
-\r
-protected:\r
- // This can be overridden to provide other message behavior if needed\r
- virtual void msg(int minVerbosity, int indent, const std::string& txt) const;\r
-\r
-private:\r
- // Local to global, or global to local ID map\r
- typedef std::unordered_map<spv::Id, spv::Id> idmap_t;\r
- typedef std::unordered_set<spv::Id> idset_t;\r
-\r
- void remap(std::uint32_t opts = DO_EVERYTHING);\r
-\r
- // Map of names to IDs\r
- typedef std::unordered_map<std::string, spv::Id> namemap_t;\r
-\r
- typedef std::uint32_t spirword_t;\r
-\r
- typedef std::pair<unsigned, unsigned> range_t;\r
- typedef std::function<void(spv::Id&)> idfn_t;\r
- typedef std::function<bool(spv::Op, unsigned start)> instfn_t;\r
-\r
- // Special Values for ID map:\r
- static const spv::Id unmapped; // unchanged from default value\r
- static const spv::Id unused; // unused ID\r
- static const int header_size; // SPIR header = 5 words\r
-\r
- class id_iterator_t;\r
-\r
- // For mapping type entries between different shaders\r
- typedef std::vector<spirword_t> typeentry_t;\r
- typedef std::map<spv::Id, typeentry_t> globaltypes_t;\r
-\r
- // A set that preserves position order, and a reverse map\r
- typedef std::set<int> posmap_t;\r
- typedef std::unordered_map<spv::Id, int> posmap_rev_t;\r
-\r
- // handle error\r
- void error(const std::string& txt) const { errorHandler(txt); }\r
-\r
- bool isConstOp(spv::Op opCode) const;\r
- bool isTypeOp(spv::Op opCode) const;\r
- bool isStripOp(spv::Op opCode) const;\r
- bool isFlowCtrlOpen(spv::Op opCode) const;\r
- bool isFlowCtrlClose(spv::Op opCode) const;\r
- range_t literalRange(spv::Op opCode) const;\r
- range_t typeRange(spv::Op opCode) const;\r
- range_t constRange(spv::Op opCode) const;\r
- \r
- spv::Id& asId(unsigned word) { return spv[word]; }\r
- const spv::Id& asId(unsigned word) const { return spv[word]; }\r
- spv::Op asOpCode(unsigned word) const { return opOpCode(spv[word]); }\r
- std::uint32_t asOpCodeHash(unsigned word);\r
- spv::Decoration asDecoration(unsigned word) const { return spv::Decoration(spv[word]); }\r
- unsigned asWordCount(unsigned word) const { return opWordCount(spv[word]); }\r
- spv::Id asTypeConstId(unsigned word) const { return asId(word + (isTypeOp(asOpCode(word)) ? 1 : 2)); }\r
- unsigned typePos(spv::Id id) const;\r
-\r
- static unsigned opWordCount(spirword_t data) { return data >> spv::WordCountShift; }\r
- static spv::Op opOpCode(spirword_t data) { return spv::Op(data & spv::OpCodeMask); }\r
-\r
- // Header access & set methods\r
- spirword_t magic() const { return spv[0]; } // return magic number\r
- spirword_t bound() const { return spv[3]; } // return Id bound from header\r
- spirword_t bound(spirword_t b) { return spv[3] = b; };\r
- spirword_t genmagic() const { return spv[2]; } // generator magic\r
- spirword_t genmagic(spirword_t m) { return spv[2] = m; }\r
- spirword_t schemaNum() const { return spv[4]; } // schema number from header\r
-\r
- // Mapping fns: get\r
- spv::Id localId(spv::Id id) const { return idMapL[id]; }\r
-\r
- // Mapping fns: set\r
- inline spv::Id localId(spv::Id id, spv::Id newId);\r
- void countIds(spv::Id id);\r
-\r
- // Return next unused new local ID.\r
- // NOTE: boost::dynamic_bitset would be more efficient due to find_next(),\r
- // which std::vector<bool> doens't have.\r
- inline spv::Id nextUnusedId(spv::Id id);\r
-\r
- void buildLocalMaps();\r
- std::string literalString(unsigned word) const; // Return literal as a std::string\r
- int literalStringWords(const std::string& str) const { return (int(str.size())+4)/4; }\r
-\r
- bool isNewIdMapped(spv::Id newId) const { return isMapped(newId); }\r
- bool isOldIdUnmapped(spv::Id oldId) const { return localId(oldId) == unmapped; }\r
- bool isOldIdUnused(spv::Id oldId) const { return localId(oldId) == unused; }\r
- bool isOldIdMapped(spv::Id oldId) const { return !isOldIdUnused(oldId) && !isOldIdUnmapped(oldId); }\r
- bool isFunction(spv::Id oldId) const { return fnPos.find(oldId) != fnPos.end(); }\r
-\r
- // bool matchType(const globaltypes_t& globalTypes, spv::Id lt, spv::Id gt) const;\r
- // spv::Id findType(const globaltypes_t& globalTypes, spv::Id lt) const;\r
- std::uint32_t hashType(unsigned typeStart) const;\r
-\r
- spirvbin_t& process(instfn_t, idfn_t, unsigned begin = 0, unsigned end = 0);\r
- int processInstruction(unsigned word, instfn_t, idfn_t);\r
-\r
- void validate() const;\r
- void mapTypeConst();\r
- void mapFnBodies();\r
- void optLoadStore();\r
- void dceFuncs();\r
- void dceVars();\r
- void dceTypes();\r
- void mapNames();\r
- void foldIds(); // fold IDs to smallest space\r
- void forwardLoadStores(); // load store forwarding (EXPERIMENTAL)\r
- void offsetIds(); // create relative offset IDs\r
-\r
- void applyMap(); // remap per local name map\r
- void mapRemainder(); // map any IDs we haven't touched yet\r
- void stripDebug(); // strip debug info\r
- void strip(); // remove debug symbols\r
- \r
- std::vector<spirword_t> spv; // SPIR words\r
-\r
- namemap_t nameMap; // ID names from OpName\r
-\r
- // Since we want to also do binary ops, we can't use std::vector<bool>. we could use\r
- // boost::dynamic_bitset, but we're trying to avoid a boost dependency.\r
- typedef std::uint64_t bits_t;\r
- std::vector<bits_t> mapped; // which new IDs have been mapped\r
- static const int mBits = sizeof(bits_t) * 4;\r
-\r
- bool isMapped(spv::Id id) const { return id < maxMappedId() && ((mapped[id/mBits] & (1LL<<(id%mBits))) != 0); }\r
- void setMapped(spv::Id id) { resizeMapped(id); mapped[id/mBits] |= (1LL<<(id%mBits)); }\r
- void resizeMapped(spv::Id id) { if (id >= maxMappedId()) mapped.resize(id/mBits+1, 0); }\r
- size_t maxMappedId() const { return mapped.size() * mBits; }\r
-\r
- // Add a strip range for a given instruction starting at 'start'\r
- // Note: avoiding brace initializers to please older versions os MSVC.\r
- void stripInst(unsigned start) { stripRange.push_back(range_t(start, start + asWordCount(start))); }\r
-\r
- // Function start and end. use unordered_map because we'll have\r
- // many fewer functions than IDs.\r
- std::unordered_map<spv::Id, range_t> fnPos;\r
- std::unordered_map<spv::Id, range_t> fnPosDCE; // deleted functions\r
-\r
- // Which functions are called, anywhere in the module, with a call count\r
- std::unordered_map<spv::Id, int> fnCalls;\r
- \r
- posmap_t typeConstPos; // word positions that define types & consts (ordered)\r
- posmap_rev_t typeConstPosR; // reverse map from IDs to positions\r
- \r
- std::vector<spv::Id> idMapL; // ID {M}ap from {L}ocal to {G}lobal IDs\r
-\r
- spv::Id entryPoint; // module entry point\r
- spv::Id largestNewId; // biggest new ID we have mapped anything to\r
-\r
- // Sections of the binary to strip, given as [begin,end)\r
- std::vector<range_t> stripRange;\r
-\r
- // processing options:\r
- std::uint32_t options;\r
- int verbose; // verbosity level\r
-\r
- static errorfn_t errorHandler;\r
- static logfn_t logHandler;\r
-};\r
-\r
-} // namespace SPV\r
-\r
-#endif // defined (use_cpp11)\r
-#endif // SPIRVREMAPPER_H\r
+//
+//Copyright (C) 2015 LunarG, Inc.
+//
+//All rights reserved.
+//
+//Redistribution and use in source and binary forms, with or without
+//modification, are permitted provided that the following conditions
+//are met:
+//
+// Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//
+// Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following
+// disclaimer in the documentation and/or other materials provided
+// with the distribution.
+//
+// Neither the name of 3Dlabs Inc. Ltd. nor the names of its
+// contributors may be used to endorse or promote products derived
+// from this software without specific prior written permission.
+//
+//THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+//"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+//LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+//FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+//COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+//INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+//BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+//LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+//CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+//LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+//ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+//POSSIBILITY OF SUCH DAMAGE.
+//
+
+#ifndef SPIRVREMAPPER_H
+#define SPIRVREMAPPER_H
+
+#include <string>
+#include <vector>
+#include <stdlib.h>
+
+namespace spv {
+
+// MSVC defines __cplusplus as an older value, even when it supports almost all of 11.
+// We handle that here by making our own symbol.
+#if __cplusplus >= 201103L || _MSC_VER >= 1700
+# define use_cpp11 1
+#endif
+
+class spirvbin_base_t
+{
+public:
+ enum Options {
+ NONE = 0,
+ STRIP = (1<<0),
+ MAP_TYPES = (1<<1),
+ MAP_NAMES = (1<<2),
+ MAP_FUNCS = (1<<3),
+ DCE_FUNCS = (1<<4),
+ DCE_VARS = (1<<5),
+ DCE_TYPES = (1<<6),
+ OPT_LOADSTORE = (1<<7),
+ OPT_FWD_LS = (1<<8), // EXPERIMENTAL: PRODUCES INVALID SCHEMA-0 SPIRV
+ MAP_ALL = (MAP_TYPES | MAP_NAMES | MAP_FUNCS),
+ DCE_ALL = (DCE_FUNCS | DCE_VARS | DCE_TYPES),
+ OPT_ALL = (OPT_LOADSTORE),
+
+ ALL_BUT_STRIP = (MAP_ALL | DCE_ALL | OPT_ALL),
+ DO_EVERYTHING = (STRIP | ALL_BUT_STRIP)
+ };
+};
+
+} // namespace SPV
+
+#if !defined (use_cpp11)
+#include <stdio.h>
+
+namespace spv {
+class spirvbin_t : public spirvbin_base_t
+{
+public:
+ spirvbin_t(int /*verbose = 0*/) { }
+
+ void remap(std::vector<unsigned int>& /*spv*/, unsigned int /*opts = 0*/)
+ {
+ printf("Tool not compiled for C++11, which is required for SPIR-V remapping.\n");
+ exit(5);
+ }
+};
+
+} // namespace SPV
+
+#else // defined (use_cpp11)
+
+#include <functional>
+#include <cstdint>
+#include <unordered_map>
+#include <unordered_set>
+#include <map>
+#include <set>
+#include <cassert>
+
+#include "../../glslang/SPIRV/spirv.h"
+#include "../../glslang/SPIRV/spvIR.h"
+
+namespace spv {
+
+// class to hold SPIR-V binary data for remapping, DCE, and debug stripping
+class spirvbin_t : public spirvbin_base_t
+{
+public:
+ spirvbin_t(int verbose = 0) : entryPoint(spv::NoResult), largestNewId(0), verbose(verbose) { }
+
+ // remap on an existing binary in memory
+ void remap(std::vector<std::uint32_t>& spv, std::uint32_t opts = DO_EVERYTHING);
+
+ // Type for error/log handler functions
+ typedef std::function<void(const std::string&)> errorfn_t;
+ typedef std::function<void(const std::string&)> logfn_t;
+
+ // Register error/log handling functions (can be lambda fn / functor / etc)
+ static void registerErrorHandler(errorfn_t handler) { errorHandler = handler; }
+ static void registerLogHandler(logfn_t handler) { logHandler = handler; }
+
+protected:
+ // This can be overridden to provide other message behavior if needed
+ virtual void msg(int minVerbosity, int indent, const std::string& txt) const;
+
+private:
+ // Local to global, or global to local ID map
+ typedef std::unordered_map<spv::Id, spv::Id> idmap_t;
+ typedef std::unordered_set<spv::Id> idset_t;
+
+ void remap(std::uint32_t opts = DO_EVERYTHING);
+
+ // Map of names to IDs
+ typedef std::unordered_map<std::string, spv::Id> namemap_t;
+
+ typedef std::uint32_t spirword_t;
+
+ typedef std::pair<unsigned, unsigned> range_t;
+ typedef std::function<void(spv::Id&)> idfn_t;
+ typedef std::function<bool(spv::Op, unsigned start)> instfn_t;
+
+ // Special Values for ID map:
+ static const spv::Id unmapped; // unchanged from default value
+ static const spv::Id unused; // unused ID
+ static const int header_size; // SPIR header = 5 words
+
+ class id_iterator_t;
+
+ // For mapping type entries between different shaders
+ typedef std::vector<spirword_t> typeentry_t;
+ typedef std::map<spv::Id, typeentry_t> globaltypes_t;
+
+ // A set that preserves position order, and a reverse map
+ typedef std::set<int> posmap_t;
+ typedef std::unordered_map<spv::Id, int> posmap_rev_t;
+
+ // handle error
+ void error(const std::string& txt) const { errorHandler(txt); }
+
+ bool isConstOp(spv::Op opCode) const;
+ bool isTypeOp(spv::Op opCode) const;
+ bool isStripOp(spv::Op opCode) const;
+ bool isFlowCtrlOpen(spv::Op opCode) const;
+ bool isFlowCtrlClose(spv::Op opCode) const;
+ range_t literalRange(spv::Op opCode) const;
+ range_t typeRange(spv::Op opCode) const;
+ range_t constRange(spv::Op opCode) const;
+
+ spv::Id& asId(unsigned word) { return spv[word]; }
+ const spv::Id& asId(unsigned word) const { return spv[word]; }
+ spv::Op asOpCode(unsigned word) const { return opOpCode(spv[word]); }
+ std::uint32_t asOpCodeHash(unsigned word);
+ spv::Decoration asDecoration(unsigned word) const { return spv::Decoration(spv[word]); }
+ unsigned asWordCount(unsigned word) const { return opWordCount(spv[word]); }
+ spv::Id asTypeConstId(unsigned word) const { return asId(word + (isTypeOp(asOpCode(word)) ? 1 : 2)); }
+ unsigned typePos(spv::Id id) const;
+
+ static unsigned opWordCount(spirword_t data) { return data >> spv::WordCountShift; }
+ static spv::Op opOpCode(spirword_t data) { return spv::Op(data & spv::OpCodeMask); }
+
+ // Header access & set methods
+ spirword_t magic() const { return spv[0]; } // return magic number
+ spirword_t bound() const { return spv[3]; } // return Id bound from header
+ spirword_t bound(spirword_t b) { return spv[3] = b; };
+ spirword_t genmagic() const { return spv[2]; } // generator magic
+ spirword_t genmagic(spirword_t m) { return spv[2] = m; }
+ spirword_t schemaNum() const { return spv[4]; } // schema number from header
+
+ // Mapping fns: get
+ spv::Id localId(spv::Id id) const { return idMapL[id]; }
+
+ // Mapping fns: set
+ inline spv::Id localId(spv::Id id, spv::Id newId);
+ void countIds(spv::Id id);
+
+ // Return next unused new local ID.
+ // NOTE: boost::dynamic_bitset would be more efficient due to find_next(),
+ // which std::vector<bool> doens't have.
+ inline spv::Id nextUnusedId(spv::Id id);
+
+ void buildLocalMaps();
+ std::string literalString(unsigned word) const; // Return literal as a std::string
+ int literalStringWords(const std::string& str) const { return (int(str.size())+4)/4; }
+
+ bool isNewIdMapped(spv::Id newId) const { return isMapped(newId); }
+ bool isOldIdUnmapped(spv::Id oldId) const { return localId(oldId) == unmapped; }
+ bool isOldIdUnused(spv::Id oldId) const { return localId(oldId) == unused; }
+ bool isOldIdMapped(spv::Id oldId) const { return !isOldIdUnused(oldId) && !isOldIdUnmapped(oldId); }
+ bool isFunction(spv::Id oldId) const { return fnPos.find(oldId) != fnPos.end(); }
+
+ // bool matchType(const globaltypes_t& globalTypes, spv::Id lt, spv::Id gt) const;
+ // spv::Id findType(const globaltypes_t& globalTypes, spv::Id lt) const;
+ std::uint32_t hashType(unsigned typeStart) const;
+
+ spirvbin_t& process(instfn_t, idfn_t, unsigned begin = 0, unsigned end = 0);
+ int processInstruction(unsigned word, instfn_t, idfn_t);
+
+ void validate() const;
+ void mapTypeConst();
+ void mapFnBodies();
+ void optLoadStore();
+ void dceFuncs();
+ void dceVars();
+ void dceTypes();
+ void mapNames();
+ void foldIds(); // fold IDs to smallest space
+ void forwardLoadStores(); // load store forwarding (EXPERIMENTAL)
+ void offsetIds(); // create relative offset IDs
+
+ void applyMap(); // remap per local name map
+ void mapRemainder(); // map any IDs we haven't touched yet
+ void stripDebug(); // strip debug info
+ void strip(); // remove debug symbols
+
+ std::vector<spirword_t> spv; // SPIR words
+
+ namemap_t nameMap; // ID names from OpName
+
+ // Since we want to also do binary ops, we can't use std::vector<bool>. we could use
+ // boost::dynamic_bitset, but we're trying to avoid a boost dependency.
+ typedef std::uint64_t bits_t;
+ std::vector<bits_t> mapped; // which new IDs have been mapped
+ static const int mBits = sizeof(bits_t) * 4;
+
+ bool isMapped(spv::Id id) const { return id < maxMappedId() && ((mapped[id/mBits] & (1LL<<(id%mBits))) != 0); }
+ void setMapped(spv::Id id) { resizeMapped(id); mapped[id/mBits] |= (1LL<<(id%mBits)); }
+ void resizeMapped(spv::Id id) { if (id >= maxMappedId()) mapped.resize(id/mBits+1, 0); }
+ size_t maxMappedId() const { return mapped.size() * mBits; }
+
+ // Add a strip range for a given instruction starting at 'start'
+ // Note: avoiding brace initializers to please older versions os MSVC.
+ void stripInst(unsigned start) { stripRange.push_back(range_t(start, start + asWordCount(start))); }
+
+ // Function start and end. use unordered_map because we'll have
+ // many fewer functions than IDs.
+ std::unordered_map<spv::Id, range_t> fnPos;
+ std::unordered_map<spv::Id, range_t> fnPosDCE; // deleted functions
+
+ // Which functions are called, anywhere in the module, with a call count
+ std::unordered_map<spv::Id, int> fnCalls;
+
+ posmap_t typeConstPos; // word positions that define types & consts (ordered)
+ posmap_rev_t typeConstPosR; // reverse map from IDs to positions
+
+ std::vector<spv::Id> idMapL; // ID {M}ap from {L}ocal to {G}lobal IDs
+
+ spv::Id entryPoint; // module entry point
+ spv::Id largestNewId; // biggest new ID we have mapped anything to
+
+ // Sections of the binary to strip, given as [begin,end)
+ std::vector<range_t> stripRange;
+
+ // processing options:
+ std::uint32_t options;
+ int verbose; // verbosity level
+
+ static errorfn_t errorHandler;
+ static logfn_t logHandler;
+};
+
+} // namespace SPV
+
+#endif // defined (use_cpp11)
+#endif // SPIRVREMAPPER_H
-//\r
-//Copyright (C) 2014 LunarG, Inc.\r
-//\r
-//All rights reserved.\r
-//\r
-//Redistribution and use in source and binary forms, with or without\r
-//modification, are permitted provided that the following conditions\r
-//are met:\r
-//\r
-// Redistributions of source code must retain the above copyright\r
-// notice, this list of conditions and the following disclaimer.\r
-//\r
-// Redistributions in binary form must reproduce the above\r
-// copyright notice, this list of conditions and the following\r
-// disclaimer in the documentation and/or other materials provided\r
-// with the distribution.\r
-//\r
-// Neither the name of 3Dlabs Inc. Ltd. nor the names of its\r
-// contributors may be used to endorse or promote products derived\r
-// from this software without specific prior written permission.\r
-//\r
-//THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\r
-//"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\r
-//LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS\r
-//FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE\r
-//COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,\r
-//INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,\r
-//BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\r
-//LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER\r
-//CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\r
-//LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN\r
-//ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE\r
-//POSSIBILITY OF SUCH DAMAGE.\r
-\r
-//\r
-// Author: John Kessenich, LunarG\r
-//\r
-\r
-//\r
-// Helper for making SPIR-V IR. Generally, this is documented in the header\r
-// SpvBuilder.h.\r
-//\r
-\r
-#include <assert.h>\r
-#include <stdio.h>\r
-#include <stdlib.h>\r
-\r
-#include "SpvBuilder.h"\r
-\r
-#ifndef _WIN32\r
- #include <cstdio>\r
-#endif\r
-\r
-namespace spv {\r
-\r
-const int SpvBuilderMagic = 0xBB;\r
-\r
-Builder::Builder(unsigned int userNumber) :\r
- source(SourceLanguageUnknown),\r
- sourceVersion(0),\r
- addressModel(AddressingModelLogical),\r
- memoryModel(MemoryModelGLSL450),\r
- builderNumber(userNumber << 16 | SpvBuilderMagic),\r
- buildPoint(0),\r
- uniqueId(0),\r
- mainFunction(0),\r
- stageExit(0)\r
-{\r
- clearAccessChain();\r
-}\r
-\r
-Builder::~Builder()\r
-{\r
-}\r
-\r
-Id Builder::import(const char* name)\r
-{\r
- Instruction* import = new Instruction(getUniqueId(), NoType, OpExtInstImport);\r
- import->addStringOperand(name);\r
- \r
- imports.push_back(import);\r
- return import->getResultId();\r
-}\r
-\r
-// For creating new groupedTypes (will return old type if the requested one was already made).\r
-Id Builder::makeVoidType()\r
-{\r
- Instruction* type;\r
- if (groupedTypes[OpTypeVoid].size() == 0) {\r
- type = new Instruction(getUniqueId(), NoType, OpTypeVoid);\r
- groupedTypes[OpTypeVoid].push_back(type);\r
- constantsTypesGlobals.push_back(type);\r
- module.mapInstruction(type);\r
- } else\r
- type = groupedTypes[OpTypeVoid].back();\r
-\r
- return type->getResultId();\r
-}\r
-\r
-Id Builder::makeBoolType()\r
-{\r
- Instruction* type;\r
- if (groupedTypes[OpTypeBool].size() == 0) {\r
- type = new Instruction(getUniqueId(), NoType, OpTypeBool);\r
- groupedTypes[OpTypeBool].push_back(type);\r
- constantsTypesGlobals.push_back(type);\r
- module.mapInstruction(type);\r
- } else\r
- type = groupedTypes[OpTypeBool].back();\r
-\r
- return type->getResultId();\r
-}\r
-\r
-Id Builder::makePointer(StorageClass storageClass, Id pointee)\r
-{\r
- // try to find it\r
- Instruction* type;\r
- for (int t = 0; t < (int)groupedTypes[OpTypePointer].size(); ++t) {\r
- type = groupedTypes[OpTypePointer][t];\r
- if (type->getImmediateOperand(0) == (unsigned)storageClass &&\r
- type->getIdOperand(1) == pointee)\r
- return type->getResultId();\r
- }\r
-\r
- // not found, make it\r
- type = new Instruction(getUniqueId(), NoType, OpTypePointer);\r
- type->addImmediateOperand(storageClass);\r
- type->addIdOperand(pointee);\r
- groupedTypes[OpTypePointer].push_back(type);\r
- constantsTypesGlobals.push_back(type);\r
- module.mapInstruction(type);\r
-\r
- return type->getResultId();\r
-}\r
-\r
-Id Builder::makeIntegerType(int width, bool hasSign)\r
-{\r
- // try to find it\r
- Instruction* type;\r
- for (int t = 0; t < (int)groupedTypes[OpTypeInt].size(); ++t) {\r
- type = groupedTypes[OpTypeInt][t];\r
- if (type->getImmediateOperand(0) == (unsigned)width &&\r
- type->getImmediateOperand(1) == (hasSign ? 1u : 0u))\r
- return type->getResultId();\r
- }\r
-\r
- // not found, make it\r
- type = new Instruction(getUniqueId(), NoType, OpTypeInt);\r
- type->addImmediateOperand(width);\r
- type->addImmediateOperand(hasSign ? 1 : 0);\r
- groupedTypes[OpTypeInt].push_back(type);\r
- constantsTypesGlobals.push_back(type);\r
- module.mapInstruction(type);\r
-\r
- return type->getResultId();\r
-}\r
-\r
-Id Builder::makeFloatType(int width)\r
-{\r
- // try to find it\r
- Instruction* type;\r
- for (int t = 0; t < (int)groupedTypes[OpTypeFloat].size(); ++t) {\r
- type = groupedTypes[OpTypeFloat][t];\r
- if (type->getImmediateOperand(0) == (unsigned)width)\r
- return type->getResultId();\r
- }\r
-\r
- // not found, make it\r
- type = new Instruction(getUniqueId(), NoType, OpTypeFloat);\r
- type->addImmediateOperand(width);\r
- groupedTypes[OpTypeFloat].push_back(type);\r
- constantsTypesGlobals.push_back(type);\r
- module.mapInstruction(type);\r
-\r
- return type->getResultId();\r
-}\r
-\r
-Id Builder::makeStructType(std::vector<Id>& members, const char* name)\r
-{\r
- // not found, make it\r
- Instruction* type = new Instruction(getUniqueId(), NoType, OpTypeStruct);\r
- for (int op = 0; op < (int)members.size(); ++op)\r
- type->addIdOperand(members[op]);\r
- groupedTypes[OpTypeStruct].push_back(type);\r
- constantsTypesGlobals.push_back(type);\r
- module.mapInstruction(type);\r
- addName(type->getResultId(), name);\r
-\r
- return type->getResultId();\r
-}\r
-\r
-Id Builder::makeVectorType(Id component, int size)\r
-{\r
- // try to find it\r
- Instruction* type;\r
- for (int t = 0; t < (int)groupedTypes[OpTypeVector].size(); ++t) {\r
- type = groupedTypes[OpTypeVector][t];\r
- if (type->getIdOperand(0) == component &&\r
- type->getImmediateOperand(1) == (unsigned)size)\r
- return type->getResultId();\r
- }\r
-\r
- // not found, make it\r
- type = new Instruction(getUniqueId(), NoType, OpTypeVector);\r
- type->addIdOperand(component);\r
- type->addImmediateOperand(size);\r
- groupedTypes[OpTypeVector].push_back(type);\r
- constantsTypesGlobals.push_back(type);\r
- module.mapInstruction(type);\r
-\r
- return type->getResultId();\r
-}\r
-\r
-Id Builder::makeMatrixType(Id component, int cols, int rows)\r
-{\r
- assert(cols <= maxMatrixSize && rows <= maxMatrixSize);\r
-\r
- Id column = makeVectorType(component, rows);\r
-\r
- // try to find it\r
- Instruction* type;\r
- for (int t = 0; t < (int)groupedTypes[OpTypeMatrix].size(); ++t) {\r
- type = groupedTypes[OpTypeMatrix][t];\r
- if (type->getIdOperand(0) == column &&\r
- type->getImmediateOperand(1) == (unsigned)cols)\r
- return type->getResultId();\r
- }\r
-\r
- // not found, make it\r
- type = new Instruction(getUniqueId(), NoType, OpTypeMatrix);\r
- type->addIdOperand(column);\r
- type->addImmediateOperand(cols);\r
- groupedTypes[OpTypeMatrix].push_back(type);\r
- constantsTypesGlobals.push_back(type);\r
- module.mapInstruction(type);\r
-\r
- return type->getResultId();\r
-}\r
-\r
-Id Builder::makeArrayType(Id element, unsigned size)\r
-{\r
- // First, we need a constant instruction for the size\r
- Id sizeId = makeUintConstant(size);\r
-\r
- // try to find existing type\r
- Instruction* type;\r
- for (int t = 0; t < (int)groupedTypes[OpTypeArray].size(); ++t) {\r
- type = groupedTypes[OpTypeArray][t];\r
- if (type->getIdOperand(0) == element &&\r
- type->getIdOperand(1) == sizeId)\r
- return type->getResultId();\r
- }\r
-\r
- // not found, make it\r
- type = new Instruction(getUniqueId(), NoType, OpTypeArray);\r
- type->addIdOperand(element);\r
- type->addIdOperand(sizeId);\r
- groupedTypes[OpTypeArray].push_back(type);\r
- constantsTypesGlobals.push_back(type);\r
- module.mapInstruction(type);\r
-\r
- return type->getResultId();\r
-}\r
-\r
-Id Builder::makeFunctionType(Id returnType, std::vector<Id>& paramTypes)\r
-{\r
- // try to find it\r
- Instruction* type;\r
- for (int t = 0; t < (int)groupedTypes[OpTypeFunction].size(); ++t) {\r
- type = groupedTypes[OpTypeFunction][t];\r
- if (type->getIdOperand(0) != returnType || (int)paramTypes.size() != type->getNumOperands() - 1)\r
- continue;\r
- bool mismatch = false;\r
- for (int p = 0; p < (int)paramTypes.size(); ++p) {\r
- if (paramTypes[p] != type->getIdOperand(p + 1)) {\r
- mismatch = true;\r
- break;\r
- }\r
- }\r
- if (! mismatch)\r
- return type->getResultId(); \r
- }\r
-\r
- // not found, make it\r
- type = new Instruction(getUniqueId(), NoType, OpTypeFunction);\r
- type->addIdOperand(returnType);\r
- for (int p = 0; p < (int)paramTypes.size(); ++p)\r
- type->addIdOperand(paramTypes[p]);\r
- groupedTypes[OpTypeFunction].push_back(type);\r
- constantsTypesGlobals.push_back(type);\r
- module.mapInstruction(type);\r
-\r
- return type->getResultId();\r
-}\r
-\r
-Id Builder::makeSampler(Id sampledType, Dim dim, samplerContent content, bool arrayed, bool shadow, bool ms)\r
-{\r
- // try to find it\r
- Instruction* type;\r
- for (int t = 0; t < (int)groupedTypes[OpTypeSampler].size(); ++t) {\r
- type = groupedTypes[OpTypeSampler][t];\r
- if (type->getIdOperand(0) == sampledType &&\r
- type->getImmediateOperand(1) == (unsigned int)dim &&\r
- type->getImmediateOperand(2) == (unsigned int)content &&\r
- type->getImmediateOperand(3) == (arrayed ? 1u : 0u) &&\r
- type->getImmediateOperand(4) == ( shadow ? 1u : 0u) &&\r
- type->getImmediateOperand(5) == ( ms ? 1u : 0u))\r
- return type->getResultId();\r
- }\r
-\r
- // not found, make it\r
- type = new Instruction(getUniqueId(), NoType, OpTypeSampler);\r
- type->addIdOperand(sampledType);\r
- type->addImmediateOperand( dim);\r
- type->addImmediateOperand(content);\r
- type->addImmediateOperand(arrayed ? 1 : 0);\r
- type->addImmediateOperand( shadow ? 1 : 0);\r
- type->addImmediateOperand( ms ? 1 : 0);\r
-\r
- groupedTypes[OpTypeSampler].push_back(type);\r
- constantsTypesGlobals.push_back(type);\r
- module.mapInstruction(type);\r
-\r
- return type->getResultId();\r
-}\r
-\r
-Id Builder::getDerefTypeId(Id resultId) const\r
-{\r
- Id typeId = getTypeId(resultId);\r
- assert(isPointerType(typeId));\r
-\r
- return module.getInstruction(typeId)->getImmediateOperand(1);\r
-}\r
-\r
-Op Builder::getMostBasicTypeClass(Id typeId) const\r
-{\r
- Instruction* instr = module.getInstruction(typeId);\r
-\r
- Op typeClass = instr->getOpCode();\r
- switch (typeClass)\r
- {\r
- case OpTypeVoid:\r
- case OpTypeBool:\r
- case OpTypeInt:\r
- case OpTypeFloat:\r
- case OpTypeStruct:\r
- return typeClass;\r
- case OpTypeVector:\r
- case OpTypeMatrix:\r
- case OpTypeArray:\r
- case OpTypeRuntimeArray:\r
- return getMostBasicTypeClass(instr->getIdOperand(0));\r
- case OpTypePointer:\r
- return getMostBasicTypeClass(instr->getIdOperand(1));\r
- default:\r
- MissingFunctionality("getMostBasicTypeClass");\r
- return OpTypeFloat;\r
- }\r
-}\r
-\r
-int Builder::getNumTypeComponents(Id typeId) const\r
-{\r
- Instruction* instr = module.getInstruction(typeId);\r
-\r
- switch (instr->getOpCode())\r
- {\r
- case OpTypeBool:\r
- case OpTypeInt:\r
- case OpTypeFloat:\r
- return 1;\r
- case OpTypeVector:\r
- case OpTypeMatrix:\r
- return instr->getImmediateOperand(1);\r
- default:\r
- MissingFunctionality("getNumTypeComponents on non bool/int/float/vector/matrix");\r
- return 1;\r
- }\r
-}\r
-\r
-// Return the lowest-level type of scalar that an homogeneous composite is made out of.\r
-// Typically, this is just to find out if something is made out of ints or floats.\r
-// However, it includes returning a structure, if say, it is an array of structure.\r
-Id Builder::getScalarTypeId(Id typeId) const\r
-{\r
- Instruction* instr = module.getInstruction(typeId);\r
-\r
- Op typeClass = instr->getOpCode();\r
- switch (typeClass)\r
- {\r
- case OpTypeVoid:\r
- case OpTypeBool:\r
- case OpTypeInt:\r
- case OpTypeFloat:\r
- case OpTypeStruct:\r
- return instr->getResultId();\r
- case OpTypeVector:\r
- case OpTypeMatrix:\r
- case OpTypeArray:\r
- case OpTypeRuntimeArray:\r
- case OpTypePointer:\r
- return getScalarTypeId(getContainedTypeId(typeId));\r
- default:\r
- MissingFunctionality("getScalarTypeId");\r
- return NoResult;\r
- }\r
-}\r
-\r
-// Return the type of 'member' of a composite.\r
-Id Builder::getContainedTypeId(Id typeId, int member) const\r
-{\r
- Instruction* instr = module.getInstruction(typeId);\r
-\r
- Op typeClass = instr->getOpCode();\r
- switch (typeClass)\r
- {\r
- case OpTypeVector:\r
- case OpTypeMatrix:\r
- case OpTypeArray:\r
- case OpTypeRuntimeArray:\r
- return instr->getIdOperand(0);\r
- case OpTypePointer:\r
- return instr->getIdOperand(1);\r
- case OpTypeStruct:\r
- return instr->getIdOperand(member);\r
- default:\r
- MissingFunctionality("getContainedTypeId");\r
- return NoResult;\r
- }\r
-}\r
-\r
-// Return the immediately contained type of a given composite type.\r
-Id Builder::getContainedTypeId(Id typeId) const\r
-{\r
- return getContainedTypeId(typeId, 0);\r
-}\r
-\r
-// See if a scalar constant of this type has already been created, so it\r
-// can be reused rather than duplicated. (Required by the specification).\r
-Id Builder::findScalarConstant(Op typeClass, Id typeId, unsigned value) const\r
-{\r
- Instruction* constant;\r
- for (int i = 0; i < (int)groupedConstants[typeClass].size(); ++i) {\r
- constant = groupedConstants[typeClass][i];\r
- if (constant->getNumOperands() == 1 &&\r
- constant->getTypeId() == typeId &&\r
- constant->getImmediateOperand(0) == value)\r
- return constant->getResultId();\r
- }\r
-\r
- return 0;\r
-}\r
-\r
-// Version of findScalarConstant (see above) for scalars that take two operands (e.g. a 'double').\r
-Id Builder::findScalarConstant(Op typeClass, Id typeId, unsigned v1, unsigned v2) const\r
-{\r
- Instruction* constant;\r
- for (int i = 0; i < (int)groupedConstants[typeClass].size(); ++i) {\r
- constant = groupedConstants[typeClass][i];\r
- if (constant->getNumOperands() == 2 &&\r
- constant->getTypeId() == typeId &&\r
- constant->getImmediateOperand(0) == v1 &&\r
- constant->getImmediateOperand(1) == v2)\r
- return constant->getResultId();\r
- }\r
-\r
- return 0;\r
-}\r
-\r
-Id Builder::makeBoolConstant(bool b)\r
-{\r
- Id typeId = makeBoolType();\r
- Instruction* constant;\r
-\r
- // See if we already made it\r
- Id existing = 0;\r
- for (int i = 0; i < (int)groupedConstants[OpTypeBool].size(); ++i) {\r
- constant = groupedConstants[OpTypeBool][i];\r
- if (constant->getTypeId() == typeId &&\r
- (b ? (constant->getOpCode() == OpConstantTrue) : \r
- (constant->getOpCode() == OpConstantFalse)))\r
- existing = constant->getResultId();\r
- }\r
-\r
- if (existing)\r
- return existing;\r
-\r
- // Make it\r
- Instruction* c = new Instruction(getUniqueId(), typeId, b ? OpConstantTrue : OpConstantFalse);\r
- constantsTypesGlobals.push_back(c);\r
- groupedConstants[OpTypeBool].push_back(c);\r
- module.mapInstruction(c);\r
-\r
- return c->getResultId();\r
-}\r
-\r
-Id Builder::makeIntConstant(Id typeId, unsigned value)\r
-{\r
- Id existing = findScalarConstant(OpTypeInt, typeId, value);\r
- if (existing)\r
- return existing;\r
-\r
- Instruction* c = new Instruction(getUniqueId(), typeId, OpConstant);\r
- c->addImmediateOperand(value);\r
- constantsTypesGlobals.push_back(c);\r
- groupedConstants[OpTypeInt].push_back(c);\r
- module.mapInstruction(c);\r
-\r
- return c->getResultId();\r
-}\r
-\r
-Id Builder::makeFloatConstant(float f)\r
-{\r
- Id typeId = makeFloatType(32);\r
- unsigned value = *(unsigned int*)&f;\r
- Id existing = findScalarConstant(OpTypeFloat, typeId, value);\r
- if (existing)\r
- return existing;\r
-\r
- Instruction* c = new Instruction(getUniqueId(), typeId, OpConstant);\r
- c->addImmediateOperand(value);\r
- constantsTypesGlobals.push_back(c);\r
- groupedConstants[OpTypeFloat].push_back(c);\r
- module.mapInstruction(c);\r
-\r
- return c->getResultId();\r
-}\r
-\r
-Id Builder::makeDoubleConstant(double d)\r
-{\r
- Id typeId = makeFloatType(64);\r
- unsigned long long value = *(unsigned long long*)&d;\r
- unsigned op1 = value & 0xFFFFFFFF;\r
- unsigned op2 = value >> 32;\r
- Id existing = findScalarConstant(OpTypeFloat, typeId, op1, op2);\r
- if (existing)\r
- return existing;\r
-\r
- Instruction* c = new Instruction(getUniqueId(), typeId, OpConstant);\r
- c->addImmediateOperand(op1);\r
- c->addImmediateOperand(op2);\r
- constantsTypesGlobals.push_back(c);\r
- groupedConstants[OpTypeFloat].push_back(c);\r
- module.mapInstruction(c);\r
-\r
- return c->getResultId();\r
-}\r
-\r
-Id Builder::findCompositeConstant(Op typeClass, std::vector<Id>& comps) const\r
-{\r
- Instruction* constant = 0;\r
- bool found = false;\r
- for (int i = 0; i < (int)groupedConstants[typeClass].size(); ++i) {\r
- constant = groupedConstants[typeClass][i];\r
-\r
- // same shape?\r
- if (constant->getNumOperands() != (int)comps.size())\r
- continue;\r
-\r
- // same contents?\r
- bool mismatch = false;\r
- for (int op = 0; op < constant->getNumOperands(); ++op) {\r
- if (constant->getIdOperand(op) != comps[op]) {\r
- mismatch = true;\r
- break;\r
- }\r
- }\r
- if (! mismatch) {\r
- found = true;\r
- break;\r
- }\r
- }\r
-\r
- return found ? constant->getResultId() : NoResult;\r
-}\r
-\r
-// Comments in header\r
-Id Builder::makeCompositeConstant(Id typeId, std::vector<Id>& members)\r
-{\r
- assert(typeId);\r
- Op typeClass = getTypeClass(typeId);\r
-\r
- switch (typeClass) {\r
- case OpTypeVector:\r
- case OpTypeArray:\r
- case OpTypeStruct:\r
- case OpTypeMatrix:\r
- break;\r
- default:\r
- MissingFunctionality("Constant composite type in Builder");\r
- return makeFloatConstant(0.0);\r
- }\r
-\r
- Id existing = findCompositeConstant(typeClass, members);\r
- if (existing)\r
- return existing;\r
-\r
- Instruction* c = new Instruction(getUniqueId(), typeId, OpConstantComposite);\r
- for (int op = 0; op < (int)members.size(); ++op)\r
- c->addIdOperand(members[op]);\r
- constantsTypesGlobals.push_back(c);\r
- groupedConstants[typeClass].push_back(c);\r
- module.mapInstruction(c);\r
-\r
- return c->getResultId();\r
-}\r
-\r
-void Builder::addEntryPoint(ExecutionModel model, Function* function)\r
-{\r
- Instruction* entryPoint = new Instruction(OpEntryPoint);\r
- entryPoint->addImmediateOperand(model);\r
- entryPoint->addIdOperand(function->getId());\r
-\r
- entryPoints.push_back(entryPoint);\r
-}\r
-\r
-void Builder::addExecutionMode(Function* entryPoint, ExecutionMode mode, int value)\r
-{\r
- // TODO: handle multiple optional arguments\r
- Instruction* instr = new Instruction(OpExecutionMode);\r
- instr->addIdOperand(entryPoint->getId());\r
- instr->addImmediateOperand(mode);\r
- if (value >= 0)\r
- instr->addImmediateOperand(value);\r
-\r
- executionModes.push_back(instr);\r
-}\r
-\r
-void Builder::addName(Id id, const char* string)\r
-{\r
- Instruction* name = new Instruction(OpName);\r
- name->addIdOperand(id);\r
- name->addStringOperand(string);\r
-\r
- names.push_back(name);\r
-}\r
-\r
-void Builder::addMemberName(Id id, int memberNumber, const char* string)\r
-{\r
- Instruction* name = new Instruction(OpMemberName);\r
- name->addIdOperand(id);\r
- name->addImmediateOperand(memberNumber);\r
- name->addStringOperand(string);\r
-\r
- names.push_back(name);\r
-}\r
-\r
-void Builder::addLine(Id target, Id fileName, int lineNum, int column)\r
-{\r
- Instruction* line = new Instruction(OpLine);\r
- line->addIdOperand(target);\r
- line->addIdOperand(fileName);\r
- line->addImmediateOperand(lineNum);\r
- line->addImmediateOperand(column);\r
-\r
- lines.push_back(line);\r
-}\r
-\r
-void Builder::addDecoration(Id id, Decoration decoration, int num)\r
-{\r
- Instruction* dec = new Instruction(OpDecorate);\r
- dec->addIdOperand(id);\r
- dec->addImmediateOperand(decoration);\r
- if (num >= 0)\r
- dec->addImmediateOperand(num);\r
-\r
- decorations.push_back(dec);\r
-}\r
-\r
-void Builder::addMemberDecoration(Id id, unsigned int member, Decoration decoration, int num)\r
-{\r
- Instruction* dec = new Instruction(OpMemberDecorate);\r
- dec->addIdOperand(id);\r
- dec->addImmediateOperand(member);\r
- dec->addImmediateOperand(decoration);\r
- if (num >= 0)\r
- dec->addImmediateOperand(num);\r
-\r
- decorations.push_back(dec);\r
-}\r
-\r
-// Comments in header\r
-Function* Builder::makeMain()\r
-{\r
- assert(! mainFunction);\r
-\r
- Block* entry;\r
- std::vector<Id> params;\r
-\r
- mainFunction = makeFunctionEntry(makeVoidType(), "main", params, &entry);\r
- stageExit = new Block(getUniqueId(), *mainFunction);\r
-\r
- return mainFunction;\r
-}\r
-\r
-// Comments in header\r
-void Builder::closeMain()\r
-{\r
- setBuildPoint(stageExit);\r
- stageExit->addInstruction(new Instruction(NoResult, NoType, OpReturn));\r
- mainFunction->addBlock(stageExit);\r
-}\r
-\r
-// Comments in header\r
-Function* Builder::makeFunctionEntry(Id returnType, const char* name, std::vector<Id>& paramTypes, Block **entry)\r
-{\r
- Id typeId = makeFunctionType(returnType, paramTypes);\r
- Id firstParamId = paramTypes.size() == 0 ? 0 : getUniqueIds(paramTypes.size());\r
- Function* function = new Function(getUniqueId(), returnType, typeId, firstParamId, module);\r
-\r
- if (entry) {\r
- *entry = new Block(getUniqueId(), *function);\r
- function->addBlock(*entry);\r
- setBuildPoint(*entry);\r
- }\r
-\r
- if (name)\r
- addName(function->getId(), name);\r
-\r
- return function;\r
-}\r
-\r
-// Comments in header\r
-void Builder::makeReturn(bool implicit, Id retVal, bool isMain)\r
-{\r
- if (isMain && retVal)\r
- MissingFunctionality("return value from main()");\r
-\r
- if (isMain)\r
- createBranch(stageExit);\r
- else if (retVal) {\r
- Instruction* inst = new Instruction(NoResult, NoType, OpReturnValue);\r
- inst->addIdOperand(retVal);\r
- buildPoint->addInstruction(inst);\r
- } else\r
- buildPoint->addInstruction(new Instruction(NoResult, NoType, OpReturn));\r
-\r
- if (! implicit)\r
- createAndSetNoPredecessorBlock("post-return");\r
-}\r
-\r
-// Comments in header\r
-void Builder::leaveFunction(bool main)\r
-{\r
- Block* block = buildPoint;\r
- Function& function = buildPoint->getParent();\r
- assert(block);\r
-\r
- // If our function did not contain a return, add a return void now.\r
- if (! block->isTerminated()) {\r
-\r
- // Whether we're in an unreachable (non-entry) block.\r
- bool unreachable = function.getEntryBlock() != block && block->getNumPredecessors() == 0;\r
-\r
- if (unreachable) {\r
- // Given that this block is at the end of a function, it must be right after an\r
- // explicit return, just remove it.\r
- function.popBlock(block);\r
- } else if (main)\r
- makeMainReturn(true);\r
- else {\r
- // We're get a return instruction at the end of the current block,\r
- // which for a non-void function is really error recovery (?), as the source\r
- // being translated should have had an explicit return, which would have been\r
- // followed by an unreachable block, which was handled above.\r
- if (function.getReturnType() == makeVoidType())\r
- makeReturn(true);\r
- else {\r
- Id retStorage = createVariable(StorageClassFunction, function.getReturnType(), "dummyReturn");\r
- Id retValue = createLoad(retStorage);\r
- makeReturn(true, retValue);\r
- }\r
- }\r
- }\r
-\r
- if (main)\r
- closeMain();\r
-}\r
-\r
-// Comments in header\r
-void Builder::makeDiscard()\r
-{\r
- buildPoint->addInstruction(new Instruction(OpKill));\r
- createAndSetNoPredecessorBlock("post-discard");\r
-}\r
-\r
-// Comments in header\r
-Id Builder::createVariable(StorageClass storageClass, Id type, const char* name)\r
-{\r
- Id pointerType = makePointer(storageClass, type);\r
- Instruction* inst = new Instruction(getUniqueId(), pointerType, OpVariable);\r
- inst->addImmediateOperand(storageClass);\r
-\r
- switch (storageClass) {\r
- case StorageClassUniformConstant:\r
- case StorageClassUniform:\r
- case StorageClassInput:\r
- case StorageClassOutput:\r
- case StorageClassWorkgroupLocal:\r
- case StorageClassPrivateGlobal:\r
- case StorageClassWorkgroupGlobal:\r
- constantsTypesGlobals.push_back(inst);\r
- module.mapInstruction(inst);\r
- break;\r
-\r
- case StorageClassFunction:\r
- // Validation rules require the declaration in the entry block\r
- buildPoint->getParent().addLocalVariable(inst);\r
- break;\r
-\r
- default:\r
- MissingFunctionality("storage class in createVariable");\r
- break;\r
- }\r
-\r
- if (name)\r
- addName(inst->getResultId(), name);\r
-\r
- return inst->getResultId();\r
-}\r
-\r
-// Comments in header\r
-void Builder::createStore(Id rValue, Id lValue)\r
-{\r
- Instruction* store = new Instruction(OpStore);\r
- store->addIdOperand(lValue);\r
- store->addIdOperand(rValue);\r
- buildPoint->addInstruction(store);\r
-}\r
-\r
-// Comments in header\r
-Id Builder::createLoad(Id lValue)\r
-{\r
- Instruction* load = new Instruction(getUniqueId(), getDerefTypeId(lValue), OpLoad);\r
- load->addIdOperand(lValue);\r
- buildPoint->addInstruction(load);\r
-\r
- return load->getResultId();\r
-}\r
-\r
-// Comments in header\r
-Id Builder::createAccessChain(StorageClass storageClass, Id base, std::vector<Id>& offsets)\r
-{\r
- // Figure out the final resulting type.\r
- spv::Id typeId = getTypeId(base);\r
- assert(isPointerType(typeId) && offsets.size() > 0);\r
- typeId = getContainedTypeId(typeId);\r
- for (int i = 0; i < (int)offsets.size(); ++i) {\r
- if (isStructType(typeId)) {\r
- assert(isConstantScalar(offsets[i]));\r
- typeId = getContainedTypeId(typeId, getConstantScalar(offsets[i]));\r
- } else\r
- typeId = getContainedTypeId(typeId, offsets[i]);\r
- }\r
- typeId = makePointer(storageClass, typeId);\r
-\r
- // Make the instruction\r
- Instruction* chain = new Instruction(getUniqueId(), typeId, OpAccessChain);\r
- chain->addIdOperand(base);\r
- for (int i = 0; i < (int)offsets.size(); ++i)\r
- chain->addIdOperand(offsets[i]);\r
- buildPoint->addInstruction(chain);\r
-\r
- return chain->getResultId();\r
-}\r
-\r
-Id Builder::createCompositeExtract(Id composite, Id typeId, unsigned index)\r
-{\r
- Instruction* extract = new Instruction(getUniqueId(), typeId, OpCompositeExtract);\r
- extract->addIdOperand(composite);\r
- extract->addImmediateOperand(index);\r
- buildPoint->addInstruction(extract);\r
-\r
- return extract->getResultId();\r
-}\r
-\r
-Id Builder::createCompositeExtract(Id composite, Id typeId, std::vector<unsigned>& indexes)\r
-{\r
- Instruction* extract = new Instruction(getUniqueId(), typeId, OpCompositeExtract);\r
- extract->addIdOperand(composite);\r
- for (int i = 0; i < (int)indexes.size(); ++i)\r
- extract->addImmediateOperand(indexes[i]);\r
- buildPoint->addInstruction(extract);\r
-\r
- return extract->getResultId();\r
-}\r
-\r
-Id Builder::createCompositeInsert(Id object, Id composite, Id typeId, unsigned index)\r
-{\r
- Instruction* insert = new Instruction(getUniqueId(), typeId, OpCompositeInsert);\r
- insert->addIdOperand(object);\r
- insert->addIdOperand(composite);\r
- insert->addImmediateOperand(index);\r
- buildPoint->addInstruction(insert);\r
-\r
- return insert->getResultId();\r
-}\r
-\r
-Id Builder::createCompositeInsert(Id object, Id composite, Id typeId, std::vector<unsigned>& indexes)\r
-{\r
- Instruction* insert = new Instruction(getUniqueId(), typeId, OpCompositeInsert);\r
- insert->addIdOperand(object);\r
- insert->addIdOperand(composite);\r
- for (int i = 0; i < (int)indexes.size(); ++i)\r
- insert->addImmediateOperand(indexes[i]);\r
- buildPoint->addInstruction(insert);\r
-\r
- return insert->getResultId();\r
-}\r
-\r
-Id Builder::createVectorExtractDynamic(Id vector, Id typeId, Id componentIndex)\r
-{\r
- Instruction* extract = new Instruction(getUniqueId(), typeId, OpVectorExtractDynamic);\r
- extract->addIdOperand(vector);\r
- extract->addIdOperand(componentIndex);\r
- buildPoint->addInstruction(extract);\r
-\r
- return extract->getResultId();\r
-}\r
-\r
-Id Builder::createVectorInsertDynamic(Id vector, Id typeId, Id component, Id componentIndex)\r
-{\r
- Instruction* insert = new Instruction(getUniqueId(), typeId, OpVectorInsertDynamic);\r
- insert->addIdOperand(vector);\r
- insert->addIdOperand(component);\r
- insert->addIdOperand(componentIndex);\r
- buildPoint->addInstruction(insert);\r
-\r
- return insert->getResultId();\r
-}\r
-\r
-// An opcode that has no operands, no result id, and no type\r
-void Builder::createNoResultOp(Op opCode)\r
-{\r
- Instruction* op = new Instruction(opCode);\r
- buildPoint->addInstruction(op);\r
-}\r
-\r
-// An opcode that has one operand, no result id, and no type\r
-void Builder::createNoResultOp(Op opCode, Id operand)\r
-{\r
- Instruction* op = new Instruction(opCode);\r
- op->addIdOperand(operand);\r
- buildPoint->addInstruction(op);\r
-}\r
-\r
-void Builder::createControlBarrier(unsigned executionScope)\r
-{\r
- Instruction* op = new Instruction(OpControlBarrier);\r
- op->addImmediateOperand(executionScope);\r
- buildPoint->addInstruction(op);\r
-}\r
-\r
-void Builder::createMemoryBarrier(unsigned executionScope, unsigned memorySemantics)\r
-{\r
- Instruction* op = new Instruction(OpMemoryBarrier);\r
- op->addImmediateOperand(executionScope);\r
- op->addImmediateOperand(memorySemantics);\r
- buildPoint->addInstruction(op);\r
-}\r
-\r
-// An opcode that has one operands, a result id, and a type\r
-Id Builder::createUnaryOp(Op opCode, Id typeId, Id operand)\r
-{\r
- Instruction* op = new Instruction(getUniqueId(), typeId, opCode);\r
- op->addIdOperand(operand);\r
- buildPoint->addInstruction(op);\r
-\r
- return op->getResultId();\r
-}\r
-\r
-Id Builder::createBinOp(Op opCode, Id typeId, Id left, Id right)\r
-{\r
- Instruction* op = new Instruction(getUniqueId(), typeId, opCode);\r
- op->addIdOperand(left);\r
- op->addIdOperand(right);\r
- buildPoint->addInstruction(op);\r
-\r
- return op->getResultId();\r
-}\r
-\r
-Id Builder::createTriOp(Op opCode, Id typeId, Id op1, Id op2, Id op3)\r
-{\r
- Instruction* op = new Instruction(getUniqueId(), typeId, opCode);\r
- op->addIdOperand(op1);\r
- op->addIdOperand(op2);\r
- op->addIdOperand(op3);\r
- buildPoint->addInstruction(op);\r
-\r
- return op->getResultId();\r
-}\r
-\r
-Id Builder::createTernaryOp(Op opCode, Id typeId, Id op1, Id op2, Id op3)\r
-{\r
- Instruction* op = new Instruction(getUniqueId(), typeId, opCode);\r
- op->addIdOperand(op1);\r
- op->addIdOperand(op2);\r
- op->addIdOperand(op3);\r
- buildPoint->addInstruction(op);\r
-\r
- return op->getResultId();\r
-}\r
-\r
-Id Builder::createFunctionCall(spv::Function* function, std::vector<spv::Id>& args)\r
-{\r
- Instruction* op = new Instruction(getUniqueId(), function->getReturnType(), OpFunctionCall);\r
- op->addIdOperand(function->getId());\r
- for (int a = 0; a < (int)args.size(); ++a)\r
- op->addIdOperand(args[a]);\r
- buildPoint->addInstruction(op);\r
-\r
- return op->getResultId();\r
-}\r
-\r
-// Comments in header\r
-Id Builder::createRvalueSwizzle(Id typeId, Id source, std::vector<unsigned>& channels)\r
-{\r
- if (channels.size() == 1)\r
- return createCompositeExtract(source, typeId, channels.front());\r
-\r
- Instruction* swizzle = new Instruction(getUniqueId(), typeId, OpVectorShuffle);\r
- assert(isVector(source));\r
- swizzle->addIdOperand(source);\r
- swizzle->addIdOperand(source);\r
- for (int i = 0; i < (int)channels.size(); ++i)\r
- swizzle->addImmediateOperand(channels[i]);\r
- buildPoint->addInstruction(swizzle);\r
-\r
- return swizzle->getResultId();\r
-}\r
-\r
-// Comments in header\r
-Id Builder::createLvalueSwizzle(Id typeId, Id target, Id source, std::vector<unsigned>& channels)\r
-{\r
- assert(getNumComponents(source) == channels.size());\r
- if (channels.size() == 1 && getNumComponents(source) == 1)\r
- return createCompositeInsert(source, target, typeId, channels.front());\r
-\r
- Instruction* swizzle = new Instruction(getUniqueId(), typeId, OpVectorShuffle);\r
- assert(isVector(source));\r
- assert(isVector(target));\r
- swizzle->addIdOperand(target);\r
- swizzle->addIdOperand(source);\r
-\r
- // Set up an identity shuffle from the base value to the result value\r
- unsigned int components[4];\r
- int numTargetComponents = getNumComponents(target);\r
- for (int i = 0; i < numTargetComponents; ++i)\r
- components[i] = i;\r
-\r
- // Punch in the l-value swizzle\r
- for (int i = 0; i < (int)channels.size(); ++i)\r
- components[channels[i]] = numTargetComponents + i;\r
-\r
- // finish the instruction with these components selectors\r
- for (int i = 0; i < numTargetComponents; ++i)\r
- swizzle->addImmediateOperand(components[i]);\r
- buildPoint->addInstruction(swizzle);\r
-\r
- return swizzle->getResultId();\r
-}\r
-\r
-// Comments in header\r
-void Builder::promoteScalar(Decoration precision, Id& left, Id& right)\r
-{\r
- int direction = getNumComponents(right) - getNumComponents(left);\r
-\r
- if (direction > 0)\r
- left = smearScalar(precision, left, getTypeId(right));\r
- else if (direction < 0)\r
- right = smearScalar(precision, right, getTypeId(left));\r
-\r
- return;\r
-}\r
-\r
-// Comments in header\r
-Id Builder::smearScalar(Decoration /*precision*/, Id scalar, Id vectorType)\r
-{\r
- assert(getNumComponents(scalar) == 1);\r
-\r
- int numComponents = getNumTypeComponents(vectorType);\r
- if (numComponents == 1)\r
- return scalar;\r
-\r
- Instruction* smear = new Instruction(getUniqueId(), vectorType, OpCompositeConstruct);\r
- for (int c = 0; c < numComponents; ++c)\r
- smear->addIdOperand(scalar);\r
- buildPoint->addInstruction(smear);\r
-\r
- return smear->getResultId();\r
-}\r
-\r
-// Comments in header\r
-Id Builder::createBuiltinCall(Decoration /*precision*/, Id resultType, Id builtins, int entryPoint, std::vector<Id>& args)\r
-{\r
- Instruction* inst = new Instruction(getUniqueId(), resultType, OpExtInst);\r
- inst->addIdOperand(builtins);\r
- inst->addImmediateOperand(entryPoint);\r
- for (int arg = 0; arg < (int)args.size(); ++arg)\r
- inst->addIdOperand(args[arg]);\r
-\r
- buildPoint->addInstruction(inst);\r
- return inst->getResultId();\r
-}\r
-\r
-// Accept all parameters needed to create a texture instruction.\r
-// Create the correct instruction based on the inputs, and make the call.\r
-Id Builder::createTextureCall(Decoration precision, Id resultType, bool proj, const TextureParameters& parameters)\r
-{\r
- static const int maxTextureArgs = 5;\r
- Id texArgs[maxTextureArgs] = {};\r
-\r
- //\r
- // Set up the arguments\r
- //\r
-\r
- int numArgs = 0;\r
- texArgs[numArgs++] = parameters.sampler;\r
- texArgs[numArgs++] = parameters.coords;\r
-\r
- if (parameters.gradX) {\r
- texArgs[numArgs++] = parameters.gradX;\r
- texArgs[numArgs++] = parameters.gradY;\r
- }\r
- if (parameters.lod)\r
- texArgs[numArgs++] = parameters.lod;\r
- if (parameters.offset)\r
- texArgs[numArgs++] = parameters.offset;\r
- if (parameters.bias)\r
- texArgs[numArgs++] = parameters.bias;\r
- if (parameters.Dref)\r
- texArgs[numArgs++] = parameters.Dref;\r
-\r
- //\r
- // Set up the instruction\r
- //\r
-\r
- Op opCode;\r
- if (proj && parameters.gradX && parameters.offset)\r
- opCode = OpTextureSampleProjGradOffset;\r
- else if (proj && parameters.lod && parameters.offset)\r
- opCode = OpTextureSampleProjLodOffset;\r
- else if (parameters.gradX && parameters.offset)\r
- opCode = OpTextureSampleGradOffset;\r
- else if (proj && parameters.offset)\r
- opCode = OpTextureSampleProjOffset;\r
- else if (parameters.lod && parameters.offset)\r
- opCode = OpTextureSampleLodOffset;\r
- else if (proj && parameters.gradX)\r
- opCode = OpTextureSampleProjGrad;\r
- else if (proj && parameters.lod)\r
- opCode = OpTextureSampleProjLod;\r
- else if (parameters.offset)\r
- opCode = OpTextureSampleOffset;\r
- else if (parameters.gradX)\r
- opCode = OpTextureSampleGrad;\r
- else if (proj)\r
- opCode = OpTextureSampleProj;\r
- else if (parameters.lod)\r
- opCode = OpTextureSampleLod;\r
- else if (parameters.Dref)\r
- opCode = OpTextureSampleDref;\r
- else\r
- opCode = OpTextureSample;\r
-\r
- Instruction* textureInst = new Instruction(getUniqueId(), resultType, opCode);\r
- for (int op = 0; op < numArgs; ++op)\r
- textureInst->addIdOperand(texArgs[op]);\r
- setPrecision(textureInst->getResultId(), precision);\r
- buildPoint->addInstruction(textureInst);\r
-\r
- return textureInst->getResultId();\r
-}\r
-\r
-// Comments in header\r
-Id Builder::createTextureQueryCall(Op opCode, const TextureParameters& parameters)\r
-{\r
- // Figure out the result type\r
- Id resultType;\r
- switch (opCode) {\r
- case OpTextureQuerySize:\r
- case OpTextureQuerySizeLod:\r
- {\r
- int numComponents;\r
- switch (getDimensionality(parameters.sampler)) {\r
- case Dim1D:\r
- case DimBuffer:\r
- numComponents = 1;\r
- break;\r
- case Dim2D:\r
- case DimCube:\r
- case DimRect:\r
- numComponents = 2;\r
- break;\r
- case Dim3D:\r
- numComponents = 3;\r
- break;\r
- default:\r
- MissingFunctionality("texture query dimensionality");\r
- break;\r
- }\r
- if (isArrayedSampler(parameters.sampler))\r
- ++numComponents;\r
- if (numComponents == 1)\r
- resultType = makeIntType(32);\r
- else\r
- resultType = makeVectorType(makeIntType(32), numComponents);\r
-\r
- break;\r
- }\r
- case OpTextureQueryLod:\r
- resultType = makeVectorType(makeFloatType(32), 2);\r
- break;\r
- case OpTextureQueryLevels:\r
- case OpTextureQuerySamples:\r
- resultType = makeIntType(32);\r
- break;\r
- default:\r
- MissingFunctionality("Texture query op code");\r
- }\r
-\r
- Instruction* query = new Instruction(getUniqueId(), resultType, opCode);\r
- query->addIdOperand(parameters.sampler);\r
- if (parameters.coords)\r
- query->addIdOperand(parameters.coords);\r
- if (parameters.lod)\r
- query->addIdOperand(parameters.lod);\r
- buildPoint->addInstruction(query);\r
-\r
- return query->getResultId();\r
-}\r
-\r
-// Comments in header\r
-//Id Builder::createSamplePositionCall(Decoration precision, Id returnType, Id sampleIdx)\r
-//{\r
-// // Return type is only flexible type\r
-// Function* opCode = (fSamplePosition, returnType);\r
-//\r
-// Instruction* instr = (opCode, sampleIdx);\r
-// setPrecision(instr, precision);\r
-//\r
-// return instr;\r
-//}\r
-\r
-// Comments in header\r
-//Id Builder::createBitFieldExtractCall(Decoration precision, Id id, Id offset, Id bits, bool isSigned)\r
-//{\r
-// Op opCode = isSigned ? sBitFieldExtract\r
-// : uBitFieldExtract;\r
-//\r
-// if (isScalar(offset) == false || isScalar(bits) == false)\r
-// MissingFunctionality("bitFieldExtract operand types");\r
-//\r
-// // Dest and value are matching flexible types\r
-// Function* opCode = (opCode, id->getType(), id->getType());\r
-//\r
-// assert(opCode);\r
-//\r
-// Instruction* instr = (opCode, id, offset, bits);\r
-// setPrecision(instr, precision);\r
-//\r
-// return instr;\r
-//}\r
-\r
-// Comments in header\r
-//Id Builder::createBitFieldInsertCall(Decoration precision, Id base, Id insert, Id offset, Id bits)\r
-//{\r
-// Op opCode = bitFieldInsert;\r
-//\r
-// if (isScalar(offset) == false || isScalar(bits) == false)\r
-// MissingFunctionality("bitFieldInsert operand types");\r
-//\r
-// // Dest, base, and insert are matching flexible types\r
-// Function* opCode = (opCode, base->getType(), base->getType(), base->getType());\r
-//\r
-// assert(opCode);\r
-//\r
-// Instruction* instr = (opCode, base, insert, offset, bits);\r
-// setPrecision(instr, precision);\r
-//\r
-// return instr;\r
-//}\r
-\r
-// Comments in header\r
-Id Builder::createCompare(Decoration precision, Id value1, Id value2, bool equal)\r
-{\r
- Id boolType = makeBoolType();\r
- Id valueType = getTypeId(value1);\r
-\r
- assert(valueType == getTypeId(value2));\r
- assert(! isScalar(value1));\r
-\r
- // Vectors\r
-\r
- if (isVectorType(valueType)) {\r
- Id boolVectorType = makeVectorType(boolType, getNumTypeComponents(valueType));\r
- Id boolVector;\r
- Op op;\r
- if (getMostBasicTypeClass(valueType) == OpTypeFloat)\r
- op = equal ? OpFOrdEqual : OpFOrdNotEqual;\r
- else\r
- op = equal ? OpIEqual : OpINotEqual;\r
-\r
- boolVector = createBinOp(op, boolVectorType, value1, value2);\r
- setPrecision(boolVector, precision);\r
-\r
- // Reduce vector compares with any() and all().\r
-\r
- op = equal ? OpAll : OpAny;\r
-\r
- return createUnaryOp(op, boolType, boolVector);\r
- }\r
-\r
- spv::MissingFunctionality("Composite comparison of non-vectors");\r
-\r
- return NoResult;\r
-\r
- // Recursively handle aggregates, which include matrices, arrays, and structures\r
- // and accumulate the results.\r
-\r
- // Matrices\r
-\r
- // Arrays\r
-\r
- //int numElements;\r
- //const llvm::ArrayType* arrayType = llvm::dyn_cast<llvm::ArrayType>(value1->getType());\r
- //if (arrayType)\r
- // numElements = (int)arrayType->getNumElements();\r
- //else {\r
- // // better be structure\r
- // const llvm::StructType* structType = llvm::dyn_cast<llvm::StructType>(value1->getType());\r
- // assert(structType);\r
- // numElements = structType->getNumElements();\r
- //}\r
-\r
- //assert(numElements > 0);\r
-\r
- //for (int element = 0; element < numElements; ++element) {\r
- // // Get intermediate comparison values\r
- // llvm::Value* element1 = builder.CreateExtractValue(value1, element, "element1");\r
- // setInstructionPrecision(element1, precision);\r
- // llvm::Value* element2 = builder.CreateExtractValue(value2, element, "element2");\r
- // setInstructionPrecision(element2, precision);\r
-\r
- // llvm::Value* subResult = createCompare(precision, element1, element2, equal, "comp");\r
-\r
- // // Accumulate intermediate comparison\r
- // if (element == 0)\r
- // result = subResult;\r
- // else {\r
- // if (equal)\r
- // result = builder.CreateAnd(result, subResult);\r
- // else\r
- // result = builder.CreateOr(result, subResult);\r
- // setInstructionPrecision(result, precision);\r
- // }\r
- //}\r
-\r
- //return result;\r
-}\r
-\r
-// Comments in header\r
-//Id Builder::createOperation(Decoration precision, Op opCode, Id operand)\r
-//{\r
-// Op* opCode = 0;\r
-//\r
-// // Handle special return types here. Things that don't have same result type as parameter\r
-// switch (opCode) {\r
-// case fIsNan:\r
-// case fIsInf:\r
-// break;\r
-// case fFloatBitsToInt:\r
-// break;\r
-// case fIntBitsTofloat:\r
-// break;\r
-// case fPackSnorm2x16:\r
-// case fPackUnorm2x16:\r
-// case fPackHalf2x16:\r
-// break;\r
-// case fUnpackUnorm2x16:\r
-// case fUnpackSnorm2x16:\r
-// case fUnpackHalf2x16:\r
-// break;\r
-//\r
-// case fFrexp:\r
-// case fLdexp:\r
-// case fPackUnorm4x8:\r
-// case fPackSnorm4x8:\r
-// case fUnpackUnorm4x8:\r
-// case fUnpackSnorm4x8:\r
-// case fPackDouble2x32:\r
-// case fUnpackDouble2x32:\r
-// break;\r
-// case fLength:\r
-// // scalar result type\r
-// break;\r
-// case any:\r
-// case all:\r
-// // fixed result type\r
-// break;\r
-// case fModF:\r
-// // modf() will return a struct that the caller must decode\r
-// break;\r
-// default:\r
-// // Unary operations that have operand and dest with same flexible type\r
-// break;\r
-// }\r
-//\r
-// assert(opCode);\r
-//\r
-// Instruction* instr = (opCode, operand);\r
-// setPrecision(instr, precision);\r
-//\r
-// return instr;\r
-//}\r
-//\r
-//// Comments in header\r
-//Id Builder::createOperation(Decoration precision, Op opCode, Id operand0, Id operand1)\r
-//{\r
-// Function* opCode = 0;\r
-//\r
-// // Handle special return types here. Things that don't have same result type as parameter\r
-// switch (opCode) {\r
-// case fDistance:\r
-// case fDot2:\r
-// case fDot3:\r
-// case fDot4:\r
-// // scalar result type\r
-// break;\r
-// case fStep:\r
-// // first argument can be scalar, return and second argument match\r
-// break;\r
-// case fSmoothStep:\r
-// // first argument can be scalar, return and second argument match\r
-// break;\r
-// default:\r
-// // Binary operations that have operand and dest with same flexible type\r
-// break;\r
-// }\r
-//\r
-// assert(opCode);\r
-//\r
-// Instruction* instr = (opCode, operand0, operand1);\r
-// setPrecision(instr, precision);\r
-//\r
-// return instr;\r
-//}\r
-//\r
-//Id Builder::createOperation(Decoration precision, Op opCode, Id operand0, Id operand1, Id operand2)\r
-//{\r
-// Function* opCode;\r
-//\r
-// // Handle special return types here. Things that don't have same result type as parameter\r
-// switch (opCode) {\r
-// case fSmoothStep:\r
-// // first argument can be scalar, return and second argument match\r
-// break;\r
-// default:\r
-// // Use operand0 type as result type\r
-// break;\r
-// }\r
-//\r
-// assert(opCode);\r
-//\r
-// Instruction* instr = (opCode, operand0, operand1, operand2);\r
-// setPrecision(instr, precision);\r
-//\r
-// return instr;\r
-//}\r
-\r
-// OpCompositeConstruct\r
-Id Builder::createCompositeConstruct(Id typeId, std::vector<Id>& constituents)\r
-{\r
- assert(isAggregateType(typeId) || getNumTypeComponents(typeId) > 1 && getNumTypeComponents(typeId) == constituents.size());\r
-\r
- Instruction* op = new Instruction(getUniqueId(), typeId, OpCompositeConstruct);\r
- for (int c = 0; c < (int)constituents.size(); ++c)\r
- op->addIdOperand(constituents[c]);\r
- buildPoint->addInstruction(op);\r
-\r
- return op->getResultId();\r
-}\r
-\r
-// Vector or scalar constructor\r
-Id Builder::createConstructor(Decoration precision, const std::vector<Id>& sources, Id resultTypeId)\r
-{\r
- Id result = 0;\r
- unsigned int numTargetComponents = getNumTypeComponents(resultTypeId);\r
- unsigned int targetComponent = 0;\r
-\r
- // Special case: when calling a vector constructor with a single scalar\r
- // argument, smear the scalar\r
- if (sources.size() == 1 && isScalar(sources[0]) && numTargetComponents > 1)\r
- return smearScalar(precision, sources[0], resultTypeId);\r
-\r
- Id scalarTypeId = getScalarTypeId(resultTypeId);\r
- std::vector<Id> constituents; // accumulate the arguments for OpCompositeConstruct\r
- for (unsigned int i = 0; i < sources.size(); ++i) {\r
- if (isAggregate(sources[i]))\r
- MissingFunctionality("aggregate in vector constructor");\r
-\r
- unsigned int sourceSize = getNumComponents(sources[i]);\r
-\r
- unsigned int sourcesToUse = sourceSize;\r
- if (sourcesToUse + targetComponent > numTargetComponents)\r
- sourcesToUse = numTargetComponents - targetComponent;\r
-\r
- for (unsigned int s = 0; s < sourcesToUse; ++s) {\r
- Id arg = sources[i];\r
- if (sourceSize > 1) {\r
- std::vector<unsigned> swiz;\r
- swiz.push_back(s);\r
- arg = createRvalueSwizzle(scalarTypeId, arg, swiz);\r
- }\r
-\r
- if (numTargetComponents > 1)\r
- constituents.push_back(arg);\r
- else\r
- result = arg;\r
- ++targetComponent;\r
- }\r
-\r
- if (targetComponent >= numTargetComponents)\r
- break;\r
- }\r
-\r
- if (constituents.size() > 0)\r
- result = createCompositeConstruct(resultTypeId, constituents);\r
-\r
- setPrecision(result, precision);\r
-\r
- return result;\r
-}\r
-\r
-// Comments in header\r
-Id Builder::createMatrixConstructor(Decoration precision, const std::vector<Id>& sources, Id resultTypeId)\r
-{\r
- Id componentTypeId = getScalarTypeId(resultTypeId);\r
- int numCols = getTypeNumColumns(resultTypeId);\r
- int numRows = getTypeNumRows(resultTypeId);\r
-\r
- // Will use a two step process\r
- // 1. make a compile-time 2D array of values\r
- // 2. construct a matrix from that array\r
-\r
- // Step 1.\r
-\r
- // initialize the array to the identity matrix\r
- Id ids[maxMatrixSize][maxMatrixSize];\r
- Id one = makeFloatConstant(1.0);\r
- Id zero = makeFloatConstant(0.0);\r
- for (int col = 0; col < 4; ++col) {\r
- for (int row = 0; row < 4; ++row) {\r
- if (col == row)\r
- ids[col][row] = one;\r
- else\r
- ids[col][row] = zero;\r
- }\r
- }\r
-\r
- // modify components as dictated by the arguments\r
- if (sources.size() == 1 && isScalar(sources[0])) {\r
- // a single scalar; resets the diagonals\r
- for (int col = 0; col < 4; ++col)\r
- ids[col][col] = sources[0];\r
- } else if (isMatrix(sources[0])) {\r
- // constructing from another matrix; copy over the parts that exist in both the argument and constructee\r
- Id matrix = sources[0];\r
- int minCols = std::min(numCols, getNumColumns(matrix));\r
- int minRows = std::min(numRows, getNumRows(matrix));\r
- for (int col = 0; col < minCols; ++col) {\r
- std::vector<unsigned> indexes;\r
- indexes.push_back(col);\r
- for (int row = 0; row < minRows; ++row) {\r
- indexes.push_back(row);\r
- ids[col][row] = createCompositeExtract(matrix, componentTypeId, indexes);\r
- indexes.pop_back();\r
- setPrecision(ids[col][row], precision);\r
- }\r
- }\r
- } else {\r
- // fill in the matrix in column-major order with whatever argument components are available\r
- int row = 0;\r
- int col = 0;\r
-\r
- for (int arg = 0; arg < (int)sources.size(); ++arg) {\r
- Id argComp = sources[arg];\r
- for (int comp = 0; comp < getNumComponents(sources[arg]); ++comp) {\r
- if (getNumComponents(sources[arg]) > 1) {\r
- argComp = createCompositeExtract(sources[arg], componentTypeId, comp);\r
- setPrecision(argComp, precision);\r
- }\r
- ids[col][row++] = argComp;\r
- if (row == numRows) {\r
- row = 0;\r
- col++;\r
- }\r
- }\r
- }\r
- }\r
-\r
-\r
- // Step 2: Construct a matrix from that array.\r
- // First make the column vectors, then make the matrix.\r
-\r
- // make the column vectors\r
- Id columnTypeId = getContainedTypeId(resultTypeId);\r
- std::vector<Id> matrixColumns;\r
- for (int col = 0; col < numCols; ++col) {\r
- std::vector<Id> vectorComponents;\r
- for (int row = 0; row < numRows; ++row)\r
- vectorComponents.push_back(ids[col][row]);\r
- matrixColumns.push_back(createCompositeConstruct(columnTypeId, vectorComponents));\r
- }\r
-\r
- // make the matrix\r
- return createCompositeConstruct(resultTypeId, matrixColumns);\r
-}\r
-\r
-// Comments in header\r
-Builder::If::If(Id cond, Builder& gb) :\r
- builder(gb),\r
- condition(cond),\r
- elseBlock(0)\r
-{\r
- function = &builder.getBuildPoint()->getParent();\r
-\r
- // make the blocks, but only put the then-block into the function,\r
- // the else-block and merge-block will be added later, in order, after\r
- // earlier code is emitted\r
- thenBlock = new Block(builder.getUniqueId(), *function);\r
- mergeBlock = new Block(builder.getUniqueId(), *function);\r
-\r
- // Save the current block, so that we can add in the flow control split when\r
- // makeEndIf is called.\r
- headerBlock = builder.getBuildPoint();\r
-\r
- function->addBlock(thenBlock);\r
- builder.setBuildPoint(thenBlock);\r
-}\r
-\r
-// Comments in header\r
-void Builder::If::makeBeginElse()\r
-{\r
- // Close out the "then" by having it jump to the mergeBlock\r
- builder.createBranch(mergeBlock);\r
-\r
- // Make the first else block and add it to the function\r
- elseBlock = new Block(builder.getUniqueId(), *function);\r
- function->addBlock(elseBlock);\r
-\r
- // Start building the else block\r
- builder.setBuildPoint(elseBlock);\r
-}\r
-\r
-// Comments in header\r
-void Builder::If::makeEndIf()\r
-{\r
- // jump to the merge block\r
- builder.createBranch(mergeBlock);\r
-\r
- // Go back to the headerBlock and make the flow control split\r
- builder.setBuildPoint(headerBlock);\r
- builder.createMerge(OpSelectionMerge, mergeBlock, SelectionControlMaskNone);\r
- if (elseBlock)\r
- builder.createConditionalBranch(condition, thenBlock, elseBlock);\r
- else\r
- builder.createConditionalBranch(condition, thenBlock, mergeBlock);\r
-\r
- // add the merge block to the function\r
- function->addBlock(mergeBlock);\r
- builder.setBuildPoint(mergeBlock);\r
-}\r
-\r
-// Comments in header\r
-void Builder::makeSwitch(Id selector, int numSegments, std::vector<int>& caseValues, std::vector<int>& valueIndexToSegment, int defaultSegment,\r
- std::vector<Block*>& segmentBlocks)\r
-{\r
- Function& function = buildPoint->getParent();\r
-\r
- // make all the blocks\r
- for (int s = 0; s < numSegments; ++s)\r
- segmentBlocks.push_back(new Block(getUniqueId(), function));\r
-\r
- Block* mergeBlock = new Block(getUniqueId(), function);\r
-\r
- // make and insert the switch's selection-merge instruction\r
- createMerge(OpSelectionMerge, mergeBlock, SelectionControlMaskNone);\r
-\r
- // make the switch instruction\r
- Instruction* switchInst = new Instruction(NoResult, NoType, OpSwitch);\r
- switchInst->addIdOperand(selector);\r
- switchInst->addIdOperand(defaultSegment >= 0 ? segmentBlocks[defaultSegment]->getId() : mergeBlock->getId());\r
- for (int i = 0; i < (int)caseValues.size(); ++i) {\r
- switchInst->addImmediateOperand(caseValues[i]);\r
- switchInst->addIdOperand(segmentBlocks[valueIndexToSegment[i]]->getId());\r
- }\r
- buildPoint->addInstruction(switchInst);\r
-\r
- // push the merge block\r
- switchMerges.push(mergeBlock);\r
-}\r
-\r
-// Comments in header\r
-void Builder::addSwitchBreak()\r
-{\r
- // branch to the top of the merge block stack\r
- createBranch(switchMerges.top());\r
- createAndSetNoPredecessorBlock("post-switch-break");\r
-}\r
-\r
-// Comments in header\r
-void Builder::nextSwitchSegment(std::vector<Block*>& segmentBlock, int nextSegment)\r
-{\r
- int lastSegment = nextSegment - 1;\r
- if (lastSegment >= 0) {\r
- // Close out previous segment by jumping, if necessary, to next segment\r
- if (! buildPoint->isTerminated())\r
- createBranch(segmentBlock[nextSegment]);\r
- }\r
- Block* block = segmentBlock[nextSegment];\r
- block->getParent().addBlock(block);\r
- setBuildPoint(block);\r
-}\r
-\r
-// Comments in header\r
-void Builder::endSwitch(std::vector<Block*>& /*segmentBlock*/)\r
-{\r
- // Close out previous segment by jumping, if necessary, to next segment\r
- if (! buildPoint->isTerminated())\r
- addSwitchBreak();\r
-\r
- switchMerges.top()->getParent().addBlock(switchMerges.top());\r
- setBuildPoint(switchMerges.top());\r
-\r
- switchMerges.pop();\r
-}\r
-\r
-// Comments in header\r
-void Builder::makeNewLoop()\r
-{\r
- Loop loop = { };\r
-\r
- loop.function = &getBuildPoint()->getParent();\r
- loop.header = new Block(getUniqueId(), *loop.function);\r
- loop.merge = new Block(getUniqueId(), *loop.function);\r
- loop.test = NULL;\r
-\r
- loops.push(loop);\r
-\r
- // Branch into the loop\r
- createBranch(loop.header);\r
-\r
- // Set ourselves inside the loop\r
- loop.function->addBlock(loop.header);\r
- setBuildPoint(loop.header);\r
-}\r
-\r
-void Builder::createLoopTestBranch(Id condition)\r
-{\r
- Loop& loop = loops.top();\r
-\r
- // If loop.test exists, then we've already generated the LoopMerge\r
- // for this loop.\r
- if (!loop.test)\r
- createMerge(OpLoopMerge, loop.merge, LoopControlMaskNone);\r
-\r
- // Branching to the "body" block will keep control inside\r
- // the loop.\r
- Block* body = new Block(getUniqueId(), *loop.function);\r
- createConditionalBranch(condition, body, loop.merge);\r
- loop.function->addBlock(body);\r
- setBuildPoint(body);\r
-}\r
-\r
-void Builder::endLoopHeaderWithoutTest()\r
-{\r
- Loop& loop = loops.top();\r
-\r
- createMerge(OpLoopMerge, loop.merge, LoopControlMaskNone);\r
- Block* body = new Block(getUniqueId(), *loop.function);\r
- createBranch(body);\r
- loop.function->addBlock(body);\r
- setBuildPoint(body);\r
-\r
- assert(!loop.test);\r
- loop.test = new Block(getUniqueId(), *loop.function);\r
-}\r
-\r
-void Builder::createBranchToLoopTest()\r
-{\r
- Loop& loop = loops.top();\r
- Block* testBlock = loop.test;\r
- assert(testBlock);\r
- createBranch(testBlock);\r
- loop.function->addBlock(testBlock);\r
- setBuildPoint(testBlock);\r
-}\r
-\r
-void Builder::createLoopContinue()\r
-{\r
- Loop& loop = loops.top();\r
- if (loop.test)\r
- createBranch(loop.test);\r
- else\r
- createBranch(loop.header);\r
- // Set up a block for dead code.\r
- createAndSetNoPredecessorBlock("post-loop-continue");\r
-}\r
-\r
-// Add an exit (e.g. "break") for the innermost loop that you're in\r
-void Builder::createLoopExit()\r
-{\r
- createBranch(loops.top().merge);\r
- // Set up a block for dead code.\r
- createAndSetNoPredecessorBlock("post-loop-break");\r
-}\r
-\r
-// Close the innermost loop\r
-void Builder::closeLoop()\r
-{\r
- Loop& loop = loops.top();\r
-\r
- // Branch back to the top\r
- createBranch(loop.header);\r
-\r
- // Add the merge block and set the build point to it\r
- loop.function->addBlock(loop.merge);\r
- setBuildPoint(loop.merge);\r
-\r
- loops.pop();\r
-}\r
-\r
-void Builder::clearAccessChain()\r
-{\r
- accessChain.base = 0;\r
- accessChain.indexChain.clear();\r
- accessChain.instr = 0;\r
- accessChain.swizzle.clear();\r
- accessChain.component = 0;\r
- accessChain.resultType = NoType;\r
- accessChain.isRValue = false;\r
-}\r
-\r
-// Comments in header\r
-void Builder::accessChainPushSwizzle(std::vector<unsigned>& swizzle)\r
-{\r
- // if needed, propagate the swizzle for the current access chain\r
- if (accessChain.swizzle.size()) {\r
- std::vector<unsigned> oldSwizzle = accessChain.swizzle;\r
- accessChain.swizzle.resize(0);\r
- for (unsigned int i = 0; i < swizzle.size(); ++i) {\r
- accessChain.swizzle.push_back(oldSwizzle[swizzle[i]]);\r
- }\r
- } else\r
- accessChain.swizzle = swizzle;\r
-\r
- // determine if we need to track this swizzle anymore\r
- simplifyAccessChainSwizzle();\r
-}\r
-\r
-// Comments in header\r
-void Builder::accessChainStore(Id rvalue)\r
-{\r
- assert(accessChain.isRValue == false);\r
-\r
- Id base = collapseAccessChain();\r
-\r
- if (accessChain.swizzle.size() && accessChain.component)\r
- MissingFunctionality("simultaneous l-value swizzle and dynamic component selection");\r
-\r
- // If swizzle exists, it is out-of-order or not full, we must load the target vector,\r
- // extract and insert elements to perform writeMask and/or swizzle.\r
- Id source = NoResult;\r
- if (accessChain.swizzle.size()) {\r
- Id tempBaseId = createLoad(base);\r
- source = createLvalueSwizzle(getTypeId(tempBaseId), tempBaseId, rvalue, accessChain.swizzle);\r
- }\r
-\r
- // dynamic component selection\r
- if (accessChain.component) {\r
- Id tempBaseId = (source == NoResult) ? createLoad(base) : source;\r
- source = createVectorInsertDynamic(tempBaseId, getTypeId(tempBaseId), rvalue, accessChain.component);\r
- }\r
-\r
- if (source == NoResult)\r
- source = rvalue;\r
-\r
- createStore(source, base);\r
-}\r
-\r
-// Comments in header\r
-Id Builder::accessChainLoad(Decoration /*precision*/)\r
-{\r
- Id id;\r
-\r
- if (accessChain.isRValue) {\r
- if (accessChain.indexChain.size() > 0) {\r
- mergeAccessChainSwizzle(); // TODO: optimization: look at applying this optimization more widely\r
- // if all the accesses are constants, we can use OpCompositeExtract\r
- std::vector<unsigned> indexes;\r
- bool constant = true;\r
- for (int i = 0; i < (int)accessChain.indexChain.size(); ++i) {\r
- if (isConstantScalar(accessChain.indexChain[i]))\r
- indexes.push_back(getConstantScalar(accessChain.indexChain[i]));\r
- else {\r
- constant = false;\r
- break;\r
- }\r
- }\r
-\r
- if (constant)\r
- id = createCompositeExtract(accessChain.base, accessChain.resultType, indexes);\r
- else {\r
- // make a new function variable for this r-value\r
- Id lValue = createVariable(StorageClassFunction, getTypeId(accessChain.base), "indexable");\r
-\r
- // store into it\r
- createStore(accessChain.base, lValue);\r
-\r
- // move base to the new variable\r
- accessChain.base = lValue;\r
- accessChain.isRValue = false;\r
-\r
- // load through the access chain\r
- id = createLoad(collapseAccessChain());\r
- }\r
- } else\r
- id = accessChain.base;\r
- } else {\r
- // load through the access chain\r
- id = createLoad(collapseAccessChain());\r
- }\r
-\r
- // Done, unless there are swizzles to do\r
- if (accessChain.swizzle.size() == 0 && accessChain.component == 0)\r
- return id;\r
-\r
- Id componentType = getScalarTypeId(accessChain.resultType);\r
-\r
- // Do remaining swizzling\r
- // First, static swizzling\r
- if (accessChain.swizzle.size()) {\r
- // static swizzle\r
- Id resultType = componentType;\r
- if (accessChain.swizzle.size() > 1)\r
- resultType = makeVectorType(componentType, accessChain.swizzle.size());\r
- id = createRvalueSwizzle(resultType, id, accessChain.swizzle);\r
- }\r
-\r
- // dynamic single-component selection\r
- if (accessChain.component)\r
- id = createVectorExtractDynamic(id, componentType, accessChain.component);\r
-\r
- return id;\r
-}\r
-\r
-Id Builder::accessChainGetLValue()\r
-{\r
- assert(accessChain.isRValue == false);\r
-\r
- Id lvalue = collapseAccessChain();\r
-\r
- // If swizzle exists, it is out-of-order or not full, we must load the target vector,\r
- // extract and insert elements to perform writeMask and/or swizzle. This does not\r
- // go with getting a direct l-value pointer.\r
- assert(accessChain.swizzle.size() == 0);\r
- assert(accessChain.component == spv::NoResult);\r
-\r
- return lvalue;\r
-}\r
-\r
-void Builder::dump(std::vector<unsigned int>& out) const\r
-{\r
- // Header, before first instructions:\r
- out.push_back(MagicNumber);\r
- out.push_back(Version);\r
- out.push_back(builderNumber);\r
- out.push_back(uniqueId + 1);\r
- out.push_back(0);\r
-\r
- // First instructions, some created on the spot here:\r
- if (source != SourceLanguageUnknown) {\r
- Instruction sourceInst(0, 0, OpSource);\r
- sourceInst.addImmediateOperand(source);\r
- sourceInst.addImmediateOperand(sourceVersion);\r
- sourceInst.dump(out);\r
- }\r
- for (int e = 0; e < (int)extensions.size(); ++e) {\r
- Instruction extInst(0, 0, OpSourceExtension);\r
- extInst.addStringOperand(extensions[e]);\r
- extInst.dump(out);\r
- }\r
- // TBD: OpExtension ...\r
- dumpInstructions(out, imports);\r
- Instruction memInst(0, 0, OpMemoryModel);\r
- memInst.addImmediateOperand(addressModel);\r
- memInst.addImmediateOperand(memoryModel);\r
- memInst.dump(out);\r
-\r
- // Instructions saved up while building:\r
- dumpInstructions(out, entryPoints);\r
- dumpInstructions(out, executionModes);\r
- dumpInstructions(out, names);\r
- dumpInstructions(out, lines);\r
- dumpInstructions(out, decorations);\r
- dumpInstructions(out, constantsTypesGlobals);\r
- dumpInstructions(out, externals);\r
-\r
- // The functions\r
- module.dump(out);\r
-}\r
-\r
-//\r
-// Protected methods.\r
-//\r
-\r
-Id Builder::collapseAccessChain()\r
-{\r
- // TODO: bring in an individual component swizzle here, so that a pointer \r
- // all the way to the component level can be created.\r
- assert(accessChain.isRValue == false);\r
-\r
- if (accessChain.indexChain.size() > 0) {\r
- if (accessChain.instr == 0) {\r
- StorageClass storageClass = (StorageClass)module.getStorageClass(getTypeId(accessChain.base));\r
- accessChain.instr = createAccessChain(storageClass, accessChain.base, accessChain.indexChain);\r
- }\r
-\r
- return accessChain.instr;\r
- } else\r
- return accessChain.base;\r
-}\r
-\r
-// clear out swizzle if it is redundant\r
-void Builder::simplifyAccessChainSwizzle()\r
-{\r
- // If the swizzle has fewer components than the vector, it is subsetting, and must stay\r
- // to preserve that fact.\r
- if (getNumTypeComponents(accessChain.resultType) > (int)accessChain.swizzle.size())\r
- return;\r
-\r
- // if components are out of order, it is a swizzle\r
- for (unsigned int i = 0; i < accessChain.swizzle.size(); ++i) {\r
- if (i != accessChain.swizzle[i])\r
- return;\r
- }\r
-\r
- // otherwise, there is no need to track this swizzle\r
- accessChain.swizzle.clear();\r
-}\r
-\r
-// clear out swizzle if it can become part of the indexes\r
-void Builder::mergeAccessChainSwizzle()\r
-{\r
- // is there even a chance of doing something? Need a single-component swizzle\r
- if ((accessChain.swizzle.size() > 1) ||\r
- (accessChain.swizzle.size() == 0 && accessChain.component == 0))\r
- return;\r
-\r
- // TODO: optimization: remove this, but for now confine this to non-dynamic accesses\r
- // (the above test is correct when this is removed.)\r
- if (accessChain.component)\r
- return;\r
-\r
- // move the swizzle over to the indexes\r
- if (accessChain.swizzle.size() == 1)\r
- accessChain.indexChain.push_back(makeUintConstant(accessChain.swizzle.front()));\r
- else\r
- accessChain.indexChain.push_back(accessChain.component);\r
- accessChain.resultType = getScalarTypeId(accessChain.resultType);\r
-\r
- // now there is no need to track this swizzle\r
- accessChain.component = NoResult;\r
- accessChain.swizzle.clear();\r
-}\r
-\r
-// Utility method for creating a new block and setting the insert point to\r
-// be in it. This is useful for flow-control operations that need a "dummy"\r
-// block proceeding them (e.g. instructions after a discard, etc).\r
-void Builder::createAndSetNoPredecessorBlock(const char* /*name*/)\r
-{\r
- Block* block = new Block(getUniqueId(), buildPoint->getParent());\r
- block->setUnreachable();\r
- buildPoint->getParent().addBlock(block);\r
- setBuildPoint(block);\r
-\r
- //if (name)\r
- // addName(block->getId(), name);\r
-}\r
-\r
-// Comments in header\r
-void Builder::createBranch(Block* block)\r
-{\r
- Instruction* branch = new Instruction(OpBranch);\r
- branch->addIdOperand(block->getId());\r
- buildPoint->addInstruction(branch);\r
- block->addPredecessor(buildPoint);\r
-}\r
-\r
-void Builder::createMerge(Op mergeCode, Block* mergeBlock, unsigned int control)\r
-{\r
- Instruction* merge = new Instruction(mergeCode);\r
- merge->addIdOperand(mergeBlock->getId());\r
- merge->addImmediateOperand(control);\r
- buildPoint->addInstruction(merge);\r
-}\r
-\r
-void Builder::createConditionalBranch(Id condition, Block* thenBlock, Block* elseBlock)\r
-{\r
- Instruction* branch = new Instruction(OpBranchConditional);\r
- branch->addIdOperand(condition);\r
- branch->addIdOperand(thenBlock->getId());\r
- branch->addIdOperand(elseBlock->getId());\r
- buildPoint->addInstruction(branch);\r
- thenBlock->addPredecessor(buildPoint);\r
- elseBlock->addPredecessor(buildPoint);\r
-}\r
-\r
-void Builder::dumpInstructions(std::vector<unsigned int>& out, const std::vector<Instruction*>& instructions) const\r
-{\r
- for (int i = 0; i < (int)instructions.size(); ++i) {\r
- instructions[i]->dump(out);\r
- }\r
-}\r
-\r
-void MissingFunctionality(const char* fun)\r
-{\r
- printf("Missing functionality: %s\n", fun);\r
- exit(1);\r
-}\r
-\r
-void ValidationError(const char* error)\r
-{\r
- printf("Validation Error: %s\n", error);\r
-}\r
-\r
-}; // end spv namespace\r
+//
+//Copyright (C) 2014 LunarG, Inc.
+//
+//All rights reserved.
+//
+//Redistribution and use in source and binary forms, with or without
+//modification, are permitted provided that the following conditions
+//are met:
+//
+// Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//
+// Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following
+// disclaimer in the documentation and/or other materials provided
+// with the distribution.
+//
+// Neither the name of 3Dlabs Inc. Ltd. nor the names of its
+// contributors may be used to endorse or promote products derived
+// from this software without specific prior written permission.
+//
+//THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+//"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+//LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+//FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+//COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+//INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+//BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+//LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+//CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+//LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+//ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+//POSSIBILITY OF SUCH DAMAGE.
+
+//
+// Author: John Kessenich, LunarG
+//
+
+//
+// Helper for making SPIR-V IR. Generally, this is documented in the header
+// SpvBuilder.h.
+//
+
+#include <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "SpvBuilder.h"
+
+#ifndef _WIN32
+ #include <cstdio>
+#endif
+
+namespace spv {
+
+const int SpvBuilderMagic = 0xBB;
+
+Builder::Builder(unsigned int userNumber) :
+ source(SourceLanguageUnknown),
+ sourceVersion(0),
+ addressModel(AddressingModelLogical),
+ memoryModel(MemoryModelGLSL450),
+ builderNumber(userNumber << 16 | SpvBuilderMagic),
+ buildPoint(0),
+ uniqueId(0),
+ mainFunction(0),
+ stageExit(0)
+{
+ clearAccessChain();
+}
+
+Builder::~Builder()
+{
+}
+
+Id Builder::import(const char* name)
+{
+ Instruction* import = new Instruction(getUniqueId(), NoType, OpExtInstImport);
+ import->addStringOperand(name);
+
+ imports.push_back(import);
+ return import->getResultId();
+}
+
+// For creating new groupedTypes (will return old type if the requested one was already made).
+Id Builder::makeVoidType()
+{
+ Instruction* type;
+ if (groupedTypes[OpTypeVoid].size() == 0) {
+ type = new Instruction(getUniqueId(), NoType, OpTypeVoid);
+ groupedTypes[OpTypeVoid].push_back(type);
+ constantsTypesGlobals.push_back(type);
+ module.mapInstruction(type);
+ } else
+ type = groupedTypes[OpTypeVoid].back();
+
+ return type->getResultId();
+}
+
+Id Builder::makeBoolType()
+{
+ Instruction* type;
+ if (groupedTypes[OpTypeBool].size() == 0) {
+ type = new Instruction(getUniqueId(), NoType, OpTypeBool);
+ groupedTypes[OpTypeBool].push_back(type);
+ constantsTypesGlobals.push_back(type);
+ module.mapInstruction(type);
+ } else
+ type = groupedTypes[OpTypeBool].back();
+
+ return type->getResultId();
+}
+
+Id Builder::makePointer(StorageClass storageClass, Id pointee)
+{
+ // try to find it
+ Instruction* type;
+ for (int t = 0; t < (int)groupedTypes[OpTypePointer].size(); ++t) {
+ type = groupedTypes[OpTypePointer][t];
+ if (type->getImmediateOperand(0) == (unsigned)storageClass &&
+ type->getIdOperand(1) == pointee)
+ return type->getResultId();
+ }
+
+ // not found, make it
+ type = new Instruction(getUniqueId(), NoType, OpTypePointer);
+ type->addImmediateOperand(storageClass);
+ type->addIdOperand(pointee);
+ groupedTypes[OpTypePointer].push_back(type);
+ constantsTypesGlobals.push_back(type);
+ module.mapInstruction(type);
+
+ return type->getResultId();
+}
+
+Id Builder::makeIntegerType(int width, bool hasSign)
+{
+ // try to find it
+ Instruction* type;
+ for (int t = 0; t < (int)groupedTypes[OpTypeInt].size(); ++t) {
+ type = groupedTypes[OpTypeInt][t];
+ if (type->getImmediateOperand(0) == (unsigned)width &&
+ type->getImmediateOperand(1) == (hasSign ? 1u : 0u))
+ return type->getResultId();
+ }
+
+ // not found, make it
+ type = new Instruction(getUniqueId(), NoType, OpTypeInt);
+ type->addImmediateOperand(width);
+ type->addImmediateOperand(hasSign ? 1 : 0);
+ groupedTypes[OpTypeInt].push_back(type);
+ constantsTypesGlobals.push_back(type);
+ module.mapInstruction(type);
+
+ return type->getResultId();
+}
+
+Id Builder::makeFloatType(int width)
+{
+ // try to find it
+ Instruction* type;
+ for (int t = 0; t < (int)groupedTypes[OpTypeFloat].size(); ++t) {
+ type = groupedTypes[OpTypeFloat][t];
+ if (type->getImmediateOperand(0) == (unsigned)width)
+ return type->getResultId();
+ }
+
+ // not found, make it
+ type = new Instruction(getUniqueId(), NoType, OpTypeFloat);
+ type->addImmediateOperand(width);
+ groupedTypes[OpTypeFloat].push_back(type);
+ constantsTypesGlobals.push_back(type);
+ module.mapInstruction(type);
+
+ return type->getResultId();
+}
+
+Id Builder::makeStructType(std::vector<Id>& members, const char* name)
+{
+ // not found, make it
+ Instruction* type = new Instruction(getUniqueId(), NoType, OpTypeStruct);
+ for (int op = 0; op < (int)members.size(); ++op)
+ type->addIdOperand(members[op]);
+ groupedTypes[OpTypeStruct].push_back(type);
+ constantsTypesGlobals.push_back(type);
+ module.mapInstruction(type);
+ addName(type->getResultId(), name);
+
+ return type->getResultId();
+}
+
+Id Builder::makeVectorType(Id component, int size)
+{
+ // try to find it
+ Instruction* type;
+ for (int t = 0; t < (int)groupedTypes[OpTypeVector].size(); ++t) {
+ type = groupedTypes[OpTypeVector][t];
+ if (type->getIdOperand(0) == component &&
+ type->getImmediateOperand(1) == (unsigned)size)
+ return type->getResultId();
+ }
+
+ // not found, make it
+ type = new Instruction(getUniqueId(), NoType, OpTypeVector);
+ type->addIdOperand(component);
+ type->addImmediateOperand(size);
+ groupedTypes[OpTypeVector].push_back(type);
+ constantsTypesGlobals.push_back(type);
+ module.mapInstruction(type);
+
+ return type->getResultId();
+}
+
+Id Builder::makeMatrixType(Id component, int cols, int rows)
+{
+ assert(cols <= maxMatrixSize && rows <= maxMatrixSize);
+
+ Id column = makeVectorType(component, rows);
+
+ // try to find it
+ Instruction* type;
+ for (int t = 0; t < (int)groupedTypes[OpTypeMatrix].size(); ++t) {
+ type = groupedTypes[OpTypeMatrix][t];
+ if (type->getIdOperand(0) == column &&
+ type->getImmediateOperand(1) == (unsigned)cols)
+ return type->getResultId();
+ }
+
+ // not found, make it
+ type = new Instruction(getUniqueId(), NoType, OpTypeMatrix);
+ type->addIdOperand(column);
+ type->addImmediateOperand(cols);
+ groupedTypes[OpTypeMatrix].push_back(type);
+ constantsTypesGlobals.push_back(type);
+ module.mapInstruction(type);
+
+ return type->getResultId();
+}
+
+Id Builder::makeArrayType(Id element, unsigned size)
+{
+ // First, we need a constant instruction for the size
+ Id sizeId = makeUintConstant(size);
+
+ // try to find existing type
+ Instruction* type;
+ for (int t = 0; t < (int)groupedTypes[OpTypeArray].size(); ++t) {
+ type = groupedTypes[OpTypeArray][t];
+ if (type->getIdOperand(0) == element &&
+ type->getIdOperand(1) == sizeId)
+ return type->getResultId();
+ }
+
+ // not found, make it
+ type = new Instruction(getUniqueId(), NoType, OpTypeArray);
+ type->addIdOperand(element);
+ type->addIdOperand(sizeId);
+ groupedTypes[OpTypeArray].push_back(type);
+ constantsTypesGlobals.push_back(type);
+ module.mapInstruction(type);
+
+ return type->getResultId();
+}
+
+Id Builder::makeFunctionType(Id returnType, std::vector<Id>& paramTypes)
+{
+ // try to find it
+ Instruction* type;
+ for (int t = 0; t < (int)groupedTypes[OpTypeFunction].size(); ++t) {
+ type = groupedTypes[OpTypeFunction][t];
+ if (type->getIdOperand(0) != returnType || (int)paramTypes.size() != type->getNumOperands() - 1)
+ continue;
+ bool mismatch = false;
+ for (int p = 0; p < (int)paramTypes.size(); ++p) {
+ if (paramTypes[p] != type->getIdOperand(p + 1)) {
+ mismatch = true;
+ break;
+ }
+ }
+ if (! mismatch)
+ return type->getResultId();
+ }
+
+ // not found, make it
+ type = new Instruction(getUniqueId(), NoType, OpTypeFunction);
+ type->addIdOperand(returnType);
+ for (int p = 0; p < (int)paramTypes.size(); ++p)
+ type->addIdOperand(paramTypes[p]);
+ groupedTypes[OpTypeFunction].push_back(type);
+ constantsTypesGlobals.push_back(type);
+ module.mapInstruction(type);
+
+ return type->getResultId();
+}
+
+Id Builder::makeSampler(Id sampledType, Dim dim, samplerContent content, bool arrayed, bool shadow, bool ms)
+{
+ // try to find it
+ Instruction* type;
+ for (int t = 0; t < (int)groupedTypes[OpTypeSampler].size(); ++t) {
+ type = groupedTypes[OpTypeSampler][t];
+ if (type->getIdOperand(0) == sampledType &&
+ type->getImmediateOperand(1) == (unsigned int)dim &&
+ type->getImmediateOperand(2) == (unsigned int)content &&
+ type->getImmediateOperand(3) == (arrayed ? 1u : 0u) &&
+ type->getImmediateOperand(4) == ( shadow ? 1u : 0u) &&
+ type->getImmediateOperand(5) == ( ms ? 1u : 0u))
+ return type->getResultId();
+ }
+
+ // not found, make it
+ type = new Instruction(getUniqueId(), NoType, OpTypeSampler);
+ type->addIdOperand(sampledType);
+ type->addImmediateOperand( dim);
+ type->addImmediateOperand(content);
+ type->addImmediateOperand(arrayed ? 1 : 0);
+ type->addImmediateOperand( shadow ? 1 : 0);
+ type->addImmediateOperand( ms ? 1 : 0);
+
+ groupedTypes[OpTypeSampler].push_back(type);
+ constantsTypesGlobals.push_back(type);
+ module.mapInstruction(type);
+
+ return type->getResultId();
+}
+
+Id Builder::getDerefTypeId(Id resultId) const
+{
+ Id typeId = getTypeId(resultId);
+ assert(isPointerType(typeId));
+
+ return module.getInstruction(typeId)->getImmediateOperand(1);
+}
+
+Op Builder::getMostBasicTypeClass(Id typeId) const
+{
+ Instruction* instr = module.getInstruction(typeId);
+
+ Op typeClass = instr->getOpCode();
+ switch (typeClass)
+ {
+ case OpTypeVoid:
+ case OpTypeBool:
+ case OpTypeInt:
+ case OpTypeFloat:
+ case OpTypeStruct:
+ return typeClass;
+ case OpTypeVector:
+ case OpTypeMatrix:
+ case OpTypeArray:
+ case OpTypeRuntimeArray:
+ return getMostBasicTypeClass(instr->getIdOperand(0));
+ case OpTypePointer:
+ return getMostBasicTypeClass(instr->getIdOperand(1));
+ default:
+ MissingFunctionality("getMostBasicTypeClass");
+ return OpTypeFloat;
+ }
+}
+
+int Builder::getNumTypeComponents(Id typeId) const
+{
+ Instruction* instr = module.getInstruction(typeId);
+
+ switch (instr->getOpCode())
+ {
+ case OpTypeBool:
+ case OpTypeInt:
+ case OpTypeFloat:
+ return 1;
+ case OpTypeVector:
+ case OpTypeMatrix:
+ return instr->getImmediateOperand(1);
+ default:
+ MissingFunctionality("getNumTypeComponents on non bool/int/float/vector/matrix");
+ return 1;
+ }
+}
+
+// Return the lowest-level type of scalar that an homogeneous composite is made out of.
+// Typically, this is just to find out if something is made out of ints or floats.
+// However, it includes returning a structure, if say, it is an array of structure.
+Id Builder::getScalarTypeId(Id typeId) const
+{
+ Instruction* instr = module.getInstruction(typeId);
+
+ Op typeClass = instr->getOpCode();
+ switch (typeClass)
+ {
+ case OpTypeVoid:
+ case OpTypeBool:
+ case OpTypeInt:
+ case OpTypeFloat:
+ case OpTypeStruct:
+ return instr->getResultId();
+ case OpTypeVector:
+ case OpTypeMatrix:
+ case OpTypeArray:
+ case OpTypeRuntimeArray:
+ case OpTypePointer:
+ return getScalarTypeId(getContainedTypeId(typeId));
+ default:
+ MissingFunctionality("getScalarTypeId");
+ return NoResult;
+ }
+}
+
+// Return the type of 'member' of a composite.
+Id Builder::getContainedTypeId(Id typeId, int member) const
+{
+ Instruction* instr = module.getInstruction(typeId);
+
+ Op typeClass = instr->getOpCode();
+ switch (typeClass)
+ {
+ case OpTypeVector:
+ case OpTypeMatrix:
+ case OpTypeArray:
+ case OpTypeRuntimeArray:
+ return instr->getIdOperand(0);
+ case OpTypePointer:
+ return instr->getIdOperand(1);
+ case OpTypeStruct:
+ return instr->getIdOperand(member);
+ default:
+ MissingFunctionality("getContainedTypeId");
+ return NoResult;
+ }
+}
+
+// Return the immediately contained type of a given composite type.
+Id Builder::getContainedTypeId(Id typeId) const
+{
+ return getContainedTypeId(typeId, 0);
+}
+
+// See if a scalar constant of this type has already been created, so it
+// can be reused rather than duplicated. (Required by the specification).
+Id Builder::findScalarConstant(Op typeClass, Id typeId, unsigned value) const
+{
+ Instruction* constant;
+ for (int i = 0; i < (int)groupedConstants[typeClass].size(); ++i) {
+ constant = groupedConstants[typeClass][i];
+ if (constant->getNumOperands() == 1 &&
+ constant->getTypeId() == typeId &&
+ constant->getImmediateOperand(0) == value)
+ return constant->getResultId();
+ }
+
+ return 0;
+}
+
+// Version of findScalarConstant (see above) for scalars that take two operands (e.g. a 'double').
+Id Builder::findScalarConstant(Op typeClass, Id typeId, unsigned v1, unsigned v2) const
+{
+ Instruction* constant;
+ for (int i = 0; i < (int)groupedConstants[typeClass].size(); ++i) {
+ constant = groupedConstants[typeClass][i];
+ if (constant->getNumOperands() == 2 &&
+ constant->getTypeId() == typeId &&
+ constant->getImmediateOperand(0) == v1 &&
+ constant->getImmediateOperand(1) == v2)
+ return constant->getResultId();
+ }
+
+ return 0;
+}
+
+Id Builder::makeBoolConstant(bool b)
+{
+ Id typeId = makeBoolType();
+ Instruction* constant;
+
+ // See if we already made it
+ Id existing = 0;
+ for (int i = 0; i < (int)groupedConstants[OpTypeBool].size(); ++i) {
+ constant = groupedConstants[OpTypeBool][i];
+ if (constant->getTypeId() == typeId &&
+ (b ? (constant->getOpCode() == OpConstantTrue) :
+ (constant->getOpCode() == OpConstantFalse)))
+ existing = constant->getResultId();
+ }
+
+ if (existing)
+ return existing;
+
+ // Make it
+ Instruction* c = new Instruction(getUniqueId(), typeId, b ? OpConstantTrue : OpConstantFalse);
+ constantsTypesGlobals.push_back(c);
+ groupedConstants[OpTypeBool].push_back(c);
+ module.mapInstruction(c);
+
+ return c->getResultId();
+}
+
+Id Builder::makeIntConstant(Id typeId, unsigned value)
+{
+ Id existing = findScalarConstant(OpTypeInt, typeId, value);
+ if (existing)
+ return existing;
+
+ Instruction* c = new Instruction(getUniqueId(), typeId, OpConstant);
+ c->addImmediateOperand(value);
+ constantsTypesGlobals.push_back(c);
+ groupedConstants[OpTypeInt].push_back(c);
+ module.mapInstruction(c);
+
+ return c->getResultId();
+}
+
+Id Builder::makeFloatConstant(float f)
+{
+ Id typeId = makeFloatType(32);
+ unsigned value = *(unsigned int*)&f;
+ Id existing = findScalarConstant(OpTypeFloat, typeId, value);
+ if (existing)
+ return existing;
+
+ Instruction* c = new Instruction(getUniqueId(), typeId, OpConstant);
+ c->addImmediateOperand(value);
+ constantsTypesGlobals.push_back(c);
+ groupedConstants[OpTypeFloat].push_back(c);
+ module.mapInstruction(c);
+
+ return c->getResultId();
+}
+
+Id Builder::makeDoubleConstant(double d)
+{
+ Id typeId = makeFloatType(64);
+ unsigned long long value = *(unsigned long long*)&d;
+ unsigned op1 = value & 0xFFFFFFFF;
+ unsigned op2 = value >> 32;
+ Id existing = findScalarConstant(OpTypeFloat, typeId, op1, op2);
+ if (existing)
+ return existing;
+
+ Instruction* c = new Instruction(getUniqueId(), typeId, OpConstant);
+ c->addImmediateOperand(op1);
+ c->addImmediateOperand(op2);
+ constantsTypesGlobals.push_back(c);
+ groupedConstants[OpTypeFloat].push_back(c);
+ module.mapInstruction(c);
+
+ return c->getResultId();
+}
+
+Id Builder::findCompositeConstant(Op typeClass, std::vector<Id>& comps) const
+{
+ Instruction* constant = 0;
+ bool found = false;
+ for (int i = 0; i < (int)groupedConstants[typeClass].size(); ++i) {
+ constant = groupedConstants[typeClass][i];
+
+ // same shape?
+ if (constant->getNumOperands() != (int)comps.size())
+ continue;
+
+ // same contents?
+ bool mismatch = false;
+ for (int op = 0; op < constant->getNumOperands(); ++op) {
+ if (constant->getIdOperand(op) != comps[op]) {
+ mismatch = true;
+ break;
+ }
+ }
+ if (! mismatch) {
+ found = true;
+ break;
+ }
+ }
+
+ return found ? constant->getResultId() : NoResult;
+}
+
+// Comments in header
+Id Builder::makeCompositeConstant(Id typeId, std::vector<Id>& members)
+{
+ assert(typeId);
+ Op typeClass = getTypeClass(typeId);
+
+ switch (typeClass) {
+ case OpTypeVector:
+ case OpTypeArray:
+ case OpTypeStruct:
+ case OpTypeMatrix:
+ break;
+ default:
+ MissingFunctionality("Constant composite type in Builder");
+ return makeFloatConstant(0.0);
+ }
+
+ Id existing = findCompositeConstant(typeClass, members);
+ if (existing)
+ return existing;
+
+ Instruction* c = new Instruction(getUniqueId(), typeId, OpConstantComposite);
+ for (int op = 0; op < (int)members.size(); ++op)
+ c->addIdOperand(members[op]);
+ constantsTypesGlobals.push_back(c);
+ groupedConstants[typeClass].push_back(c);
+ module.mapInstruction(c);
+
+ return c->getResultId();
+}
+
+void Builder::addEntryPoint(ExecutionModel model, Function* function)
+{
+ Instruction* entryPoint = new Instruction(OpEntryPoint);
+ entryPoint->addImmediateOperand(model);
+ entryPoint->addIdOperand(function->getId());
+
+ entryPoints.push_back(entryPoint);
+}
+
+void Builder::addExecutionMode(Function* entryPoint, ExecutionMode mode, int value)
+{
+ // TODO: handle multiple optional arguments
+ Instruction* instr = new Instruction(OpExecutionMode);
+ instr->addIdOperand(entryPoint->getId());
+ instr->addImmediateOperand(mode);
+ if (value >= 0)
+ instr->addImmediateOperand(value);
+
+ executionModes.push_back(instr);
+}
+
+void Builder::addName(Id id, const char* string)
+{
+ Instruction* name = new Instruction(OpName);
+ name->addIdOperand(id);
+ name->addStringOperand(string);
+
+ names.push_back(name);
+}
+
+void Builder::addMemberName(Id id, int memberNumber, const char* string)
+{
+ Instruction* name = new Instruction(OpMemberName);
+ name->addIdOperand(id);
+ name->addImmediateOperand(memberNumber);
+ name->addStringOperand(string);
+
+ names.push_back(name);
+}
+
+void Builder::addLine(Id target, Id fileName, int lineNum, int column)
+{
+ Instruction* line = new Instruction(OpLine);
+ line->addIdOperand(target);
+ line->addIdOperand(fileName);
+ line->addImmediateOperand(lineNum);
+ line->addImmediateOperand(column);
+
+ lines.push_back(line);
+}
+
+void Builder::addDecoration(Id id, Decoration decoration, int num)
+{
+ Instruction* dec = new Instruction(OpDecorate);
+ dec->addIdOperand(id);
+ dec->addImmediateOperand(decoration);
+ if (num >= 0)
+ dec->addImmediateOperand(num);
+
+ decorations.push_back(dec);
+}
+
+void Builder::addMemberDecoration(Id id, unsigned int member, Decoration decoration, int num)
+{
+ Instruction* dec = new Instruction(OpMemberDecorate);
+ dec->addIdOperand(id);
+ dec->addImmediateOperand(member);
+ dec->addImmediateOperand(decoration);
+ if (num >= 0)
+ dec->addImmediateOperand(num);
+
+ decorations.push_back(dec);
+}
+
+// Comments in header
+Function* Builder::makeMain()
+{
+ assert(! mainFunction);
+
+ Block* entry;
+ std::vector<Id> params;
+
+ mainFunction = makeFunctionEntry(makeVoidType(), "main", params, &entry);
+ stageExit = new Block(getUniqueId(), *mainFunction);
+
+ return mainFunction;
+}
+
+// Comments in header
+void Builder::closeMain()
+{
+ setBuildPoint(stageExit);
+ stageExit->addInstruction(new Instruction(NoResult, NoType, OpReturn));
+ mainFunction->addBlock(stageExit);
+}
+
+// Comments in header
+Function* Builder::makeFunctionEntry(Id returnType, const char* name, std::vector<Id>& paramTypes, Block **entry)
+{
+ Id typeId = makeFunctionType(returnType, paramTypes);
+ Id firstParamId = paramTypes.size() == 0 ? 0 : getUniqueIds(paramTypes.size());
+ Function* function = new Function(getUniqueId(), returnType, typeId, firstParamId, module);
+
+ if (entry) {
+ *entry = new Block(getUniqueId(), *function);
+ function->addBlock(*entry);
+ setBuildPoint(*entry);
+ }
+
+ if (name)
+ addName(function->getId(), name);
+
+ return function;
+}
+
+// Comments in header
+void Builder::makeReturn(bool implicit, Id retVal, bool isMain)
+{
+ if (isMain && retVal)
+ MissingFunctionality("return value from main()");
+
+ if (isMain)
+ createBranch(stageExit);
+ else if (retVal) {
+ Instruction* inst = new Instruction(NoResult, NoType, OpReturnValue);
+ inst->addIdOperand(retVal);
+ buildPoint->addInstruction(inst);
+ } else
+ buildPoint->addInstruction(new Instruction(NoResult, NoType, OpReturn));
+
+ if (! implicit)
+ createAndSetNoPredecessorBlock("post-return");
+}
+
+// Comments in header
+void Builder::leaveFunction(bool main)
+{
+ Block* block = buildPoint;
+ Function& function = buildPoint->getParent();
+ assert(block);
+
+ // If our function did not contain a return, add a return void now.
+ if (! block->isTerminated()) {
+
+ // Whether we're in an unreachable (non-entry) block.
+ bool unreachable = function.getEntryBlock() != block && block->getNumPredecessors() == 0;
+
+ if (unreachable) {
+ // Given that this block is at the end of a function, it must be right after an
+ // explicit return, just remove it.
+ function.popBlock(block);
+ } else if (main)
+ makeMainReturn(true);
+ else {
+ // We're get a return instruction at the end of the current block,
+ // which for a non-void function is really error recovery (?), as the source
+ // being translated should have had an explicit return, which would have been
+ // followed by an unreachable block, which was handled above.
+ if (function.getReturnType() == makeVoidType())
+ makeReturn(true);
+ else {
+ Id retStorage = createVariable(StorageClassFunction, function.getReturnType(), "dummyReturn");
+ Id retValue = createLoad(retStorage);
+ makeReturn(true, retValue);
+ }
+ }
+ }
+
+ if (main)
+ closeMain();
+}
+
+// Comments in header
+void Builder::makeDiscard()
+{
+ buildPoint->addInstruction(new Instruction(OpKill));
+ createAndSetNoPredecessorBlock("post-discard");
+}
+
+// Comments in header
+Id Builder::createVariable(StorageClass storageClass, Id type, const char* name)
+{
+ Id pointerType = makePointer(storageClass, type);
+ Instruction* inst = new Instruction(getUniqueId(), pointerType, OpVariable);
+ inst->addImmediateOperand(storageClass);
+
+ switch (storageClass) {
+ case StorageClassUniformConstant:
+ case StorageClassUniform:
+ case StorageClassInput:
+ case StorageClassOutput:
+ case StorageClassWorkgroupLocal:
+ case StorageClassPrivateGlobal:
+ case StorageClassWorkgroupGlobal:
+ constantsTypesGlobals.push_back(inst);
+ module.mapInstruction(inst);
+ break;
+
+ case StorageClassFunction:
+ // Validation rules require the declaration in the entry block
+ buildPoint->getParent().addLocalVariable(inst);
+ break;
+
+ default:
+ MissingFunctionality("storage class in createVariable");
+ break;
+ }
+
+ if (name)
+ addName(inst->getResultId(), name);
+
+ return inst->getResultId();
+}
+
+// Comments in header
+void Builder::createStore(Id rValue, Id lValue)
+{
+ Instruction* store = new Instruction(OpStore);
+ store->addIdOperand(lValue);
+ store->addIdOperand(rValue);
+ buildPoint->addInstruction(store);
+}
+
+// Comments in header
+Id Builder::createLoad(Id lValue)
+{
+ Instruction* load = new Instruction(getUniqueId(), getDerefTypeId(lValue), OpLoad);
+ load->addIdOperand(lValue);
+ buildPoint->addInstruction(load);
+
+ return load->getResultId();
+}
+
+// Comments in header
+Id Builder::createAccessChain(StorageClass storageClass, Id base, std::vector<Id>& offsets)
+{
+ // Figure out the final resulting type.
+ spv::Id typeId = getTypeId(base);
+ assert(isPointerType(typeId) && offsets.size() > 0);
+ typeId = getContainedTypeId(typeId);
+ for (int i = 0; i < (int)offsets.size(); ++i) {
+ if (isStructType(typeId)) {
+ assert(isConstantScalar(offsets[i]));
+ typeId = getContainedTypeId(typeId, getConstantScalar(offsets[i]));
+ } else
+ typeId = getContainedTypeId(typeId, offsets[i]);
+ }
+ typeId = makePointer(storageClass, typeId);
+
+ // Make the instruction
+ Instruction* chain = new Instruction(getUniqueId(), typeId, OpAccessChain);
+ chain->addIdOperand(base);
+ for (int i = 0; i < (int)offsets.size(); ++i)
+ chain->addIdOperand(offsets[i]);
+ buildPoint->addInstruction(chain);
+
+ return chain->getResultId();
+}
+
+Id Builder::createCompositeExtract(Id composite, Id typeId, unsigned index)
+{
+ Instruction* extract = new Instruction(getUniqueId(), typeId, OpCompositeExtract);
+ extract->addIdOperand(composite);
+ extract->addImmediateOperand(index);
+ buildPoint->addInstruction(extract);
+
+ return extract->getResultId();
+}
+
+Id Builder::createCompositeExtract(Id composite, Id typeId, std::vector<unsigned>& indexes)
+{
+ Instruction* extract = new Instruction(getUniqueId(), typeId, OpCompositeExtract);
+ extract->addIdOperand(composite);
+ for (int i = 0; i < (int)indexes.size(); ++i)
+ extract->addImmediateOperand(indexes[i]);
+ buildPoint->addInstruction(extract);
+
+ return extract->getResultId();
+}
+
+Id Builder::createCompositeInsert(Id object, Id composite, Id typeId, unsigned index)
+{
+ Instruction* insert = new Instruction(getUniqueId(), typeId, OpCompositeInsert);
+ insert->addIdOperand(object);
+ insert->addIdOperand(composite);
+ insert->addImmediateOperand(index);
+ buildPoint->addInstruction(insert);
+
+ return insert->getResultId();
+}
+
+Id Builder::createCompositeInsert(Id object, Id composite, Id typeId, std::vector<unsigned>& indexes)
+{
+ Instruction* insert = new Instruction(getUniqueId(), typeId, OpCompositeInsert);
+ insert->addIdOperand(object);
+ insert->addIdOperand(composite);
+ for (int i = 0; i < (int)indexes.size(); ++i)
+ insert->addImmediateOperand(indexes[i]);
+ buildPoint->addInstruction(insert);
+
+ return insert->getResultId();
+}
+
+Id Builder::createVectorExtractDynamic(Id vector, Id typeId, Id componentIndex)
+{
+ Instruction* extract = new Instruction(getUniqueId(), typeId, OpVectorExtractDynamic);
+ extract->addIdOperand(vector);
+ extract->addIdOperand(componentIndex);
+ buildPoint->addInstruction(extract);
+
+ return extract->getResultId();
+}
+
+Id Builder::createVectorInsertDynamic(Id vector, Id typeId, Id component, Id componentIndex)
+{
+ Instruction* insert = new Instruction(getUniqueId(), typeId, OpVectorInsertDynamic);
+ insert->addIdOperand(vector);
+ insert->addIdOperand(component);
+ insert->addIdOperand(componentIndex);
+ buildPoint->addInstruction(insert);
+
+ return insert->getResultId();
+}
+
+// An opcode that has no operands, no result id, and no type
+void Builder::createNoResultOp(Op opCode)
+{
+ Instruction* op = new Instruction(opCode);
+ buildPoint->addInstruction(op);
+}
+
+// An opcode that has one operand, no result id, and no type
+void Builder::createNoResultOp(Op opCode, Id operand)
+{
+ Instruction* op = new Instruction(opCode);
+ op->addIdOperand(operand);
+ buildPoint->addInstruction(op);
+}
+
+void Builder::createControlBarrier(unsigned executionScope)
+{
+ Instruction* op = new Instruction(OpControlBarrier);
+ op->addImmediateOperand(executionScope);
+ buildPoint->addInstruction(op);
+}
+
+void Builder::createMemoryBarrier(unsigned executionScope, unsigned memorySemantics)
+{
+ Instruction* op = new Instruction(OpMemoryBarrier);
+ op->addImmediateOperand(executionScope);
+ op->addImmediateOperand(memorySemantics);
+ buildPoint->addInstruction(op);
+}
+
+// An opcode that has one operands, a result id, and a type
+Id Builder::createUnaryOp(Op opCode, Id typeId, Id operand)
+{
+ Instruction* op = new Instruction(getUniqueId(), typeId, opCode);
+ op->addIdOperand(operand);
+ buildPoint->addInstruction(op);
+
+ return op->getResultId();
+}
+
+Id Builder::createBinOp(Op opCode, Id typeId, Id left, Id right)
+{
+ Instruction* op = new Instruction(getUniqueId(), typeId, opCode);
+ op->addIdOperand(left);
+ op->addIdOperand(right);
+ buildPoint->addInstruction(op);
+
+ return op->getResultId();
+}
+
+Id Builder::createTriOp(Op opCode, Id typeId, Id op1, Id op2, Id op3)
+{
+ Instruction* op = new Instruction(getUniqueId(), typeId, opCode);
+ op->addIdOperand(op1);
+ op->addIdOperand(op2);
+ op->addIdOperand(op3);
+ buildPoint->addInstruction(op);
+
+ return op->getResultId();
+}
+
+Id Builder::createTernaryOp(Op opCode, Id typeId, Id op1, Id op2, Id op3)
+{
+ Instruction* op = new Instruction(getUniqueId(), typeId, opCode);
+ op->addIdOperand(op1);
+ op->addIdOperand(op2);
+ op->addIdOperand(op3);
+ buildPoint->addInstruction(op);
+
+ return op->getResultId();
+}
+
+Id Builder::createFunctionCall(spv::Function* function, std::vector<spv::Id>& args)
+{
+ Instruction* op = new Instruction(getUniqueId(), function->getReturnType(), OpFunctionCall);
+ op->addIdOperand(function->getId());
+ for (int a = 0; a < (int)args.size(); ++a)
+ op->addIdOperand(args[a]);
+ buildPoint->addInstruction(op);
+
+ return op->getResultId();
+}
+
+// Comments in header
+Id Builder::createRvalueSwizzle(Id typeId, Id source, std::vector<unsigned>& channels)
+{
+ if (channels.size() == 1)
+ return createCompositeExtract(source, typeId, channels.front());
+
+ Instruction* swizzle = new Instruction(getUniqueId(), typeId, OpVectorShuffle);
+ assert(isVector(source));
+ swizzle->addIdOperand(source);
+ swizzle->addIdOperand(source);
+ for (int i = 0; i < (int)channels.size(); ++i)
+ swizzle->addImmediateOperand(channels[i]);
+ buildPoint->addInstruction(swizzle);
+
+ return swizzle->getResultId();
+}
+
+// Comments in header
+Id Builder::createLvalueSwizzle(Id typeId, Id target, Id source, std::vector<unsigned>& channels)
+{
+ assert(getNumComponents(source) == channels.size());
+ if (channels.size() == 1 && getNumComponents(source) == 1)
+ return createCompositeInsert(source, target, typeId, channels.front());
+
+ Instruction* swizzle = new Instruction(getUniqueId(), typeId, OpVectorShuffle);
+ assert(isVector(source));
+ assert(isVector(target));
+ swizzle->addIdOperand(target);
+ swizzle->addIdOperand(source);
+
+ // Set up an identity shuffle from the base value to the result value
+ unsigned int components[4];
+ int numTargetComponents = getNumComponents(target);
+ for (int i = 0; i < numTargetComponents; ++i)
+ components[i] = i;
+
+ // Punch in the l-value swizzle
+ for (int i = 0; i < (int)channels.size(); ++i)
+ components[channels[i]] = numTargetComponents + i;
+
+ // finish the instruction with these components selectors
+ for (int i = 0; i < numTargetComponents; ++i)
+ swizzle->addImmediateOperand(components[i]);
+ buildPoint->addInstruction(swizzle);
+
+ return swizzle->getResultId();
+}
+
+// Comments in header
+void Builder::promoteScalar(Decoration precision, Id& left, Id& right)
+{
+ int direction = getNumComponents(right) - getNumComponents(left);
+
+ if (direction > 0)
+ left = smearScalar(precision, left, getTypeId(right));
+ else if (direction < 0)
+ right = smearScalar(precision, right, getTypeId(left));
+
+ return;
+}
+
+// Comments in header
+Id Builder::smearScalar(Decoration /*precision*/, Id scalar, Id vectorType)
+{
+ assert(getNumComponents(scalar) == 1);
+
+ int numComponents = getNumTypeComponents(vectorType);
+ if (numComponents == 1)
+ return scalar;
+
+ Instruction* smear = new Instruction(getUniqueId(), vectorType, OpCompositeConstruct);
+ for (int c = 0; c < numComponents; ++c)
+ smear->addIdOperand(scalar);
+ buildPoint->addInstruction(smear);
+
+ return smear->getResultId();
+}
+
+// Comments in header
+Id Builder::createBuiltinCall(Decoration /*precision*/, Id resultType, Id builtins, int entryPoint, std::vector<Id>& args)
+{
+ Instruction* inst = new Instruction(getUniqueId(), resultType, OpExtInst);
+ inst->addIdOperand(builtins);
+ inst->addImmediateOperand(entryPoint);
+ for (int arg = 0; arg < (int)args.size(); ++arg)
+ inst->addIdOperand(args[arg]);
+
+ buildPoint->addInstruction(inst);
+ return inst->getResultId();
+}
+
+// Accept all parameters needed to create a texture instruction.
+// Create the correct instruction based on the inputs, and make the call.
+Id Builder::createTextureCall(Decoration precision, Id resultType, bool proj, const TextureParameters& parameters)
+{
+ static const int maxTextureArgs = 5;
+ Id texArgs[maxTextureArgs] = {};
+
+ //
+ // Set up the arguments
+ //
+
+ int numArgs = 0;
+ texArgs[numArgs++] = parameters.sampler;
+ texArgs[numArgs++] = parameters.coords;
+
+ if (parameters.gradX) {
+ texArgs[numArgs++] = parameters.gradX;
+ texArgs[numArgs++] = parameters.gradY;
+ }
+ if (parameters.lod)
+ texArgs[numArgs++] = parameters.lod;
+ if (parameters.offset)
+ texArgs[numArgs++] = parameters.offset;
+ if (parameters.bias)
+ texArgs[numArgs++] = parameters.bias;
+ if (parameters.Dref)
+ texArgs[numArgs++] = parameters.Dref;
+
+ //
+ // Set up the instruction
+ //
+
+ Op opCode;
+ if (proj && parameters.gradX && parameters.offset)
+ opCode = OpTextureSampleProjGradOffset;
+ else if (proj && parameters.lod && parameters.offset)
+ opCode = OpTextureSampleProjLodOffset;
+ else if (parameters.gradX && parameters.offset)
+ opCode = OpTextureSampleGradOffset;
+ else if (proj && parameters.offset)
+ opCode = OpTextureSampleProjOffset;
+ else if (parameters.lod && parameters.offset)
+ opCode = OpTextureSampleLodOffset;
+ else if (proj && parameters.gradX)
+ opCode = OpTextureSampleProjGrad;
+ else if (proj && parameters.lod)
+ opCode = OpTextureSampleProjLod;
+ else if (parameters.offset)
+ opCode = OpTextureSampleOffset;
+ else if (parameters.gradX)
+ opCode = OpTextureSampleGrad;
+ else if (proj)
+ opCode = OpTextureSampleProj;
+ else if (parameters.lod)
+ opCode = OpTextureSampleLod;
+ else if (parameters.Dref)
+ opCode = OpTextureSampleDref;
+ else
+ opCode = OpTextureSample;
+
+ Instruction* textureInst = new Instruction(getUniqueId(), resultType, opCode);
+ for (int op = 0; op < numArgs; ++op)
+ textureInst->addIdOperand(texArgs[op]);
+ setPrecision(textureInst->getResultId(), precision);
+ buildPoint->addInstruction(textureInst);
+
+ return textureInst->getResultId();
+}
+
+// Comments in header
+Id Builder::createTextureQueryCall(Op opCode, const TextureParameters& parameters)
+{
+ // Figure out the result type
+ Id resultType;
+ switch (opCode) {
+ case OpTextureQuerySize:
+ case OpTextureQuerySizeLod:
+ {
+ int numComponents;
+ switch (getDimensionality(parameters.sampler)) {
+ case Dim1D:
+ case DimBuffer:
+ numComponents = 1;
+ break;
+ case Dim2D:
+ case DimCube:
+ case DimRect:
+ numComponents = 2;
+ break;
+ case Dim3D:
+ numComponents = 3;
+ break;
+ default:
+ MissingFunctionality("texture query dimensionality");
+ break;
+ }
+ if (isArrayedSampler(parameters.sampler))
+ ++numComponents;
+ if (numComponents == 1)
+ resultType = makeIntType(32);
+ else
+ resultType = makeVectorType(makeIntType(32), numComponents);
+
+ break;
+ }
+ case OpTextureQueryLod:
+ resultType = makeVectorType(makeFloatType(32), 2);
+ break;
+ case OpTextureQueryLevels:
+ case OpTextureQuerySamples:
+ resultType = makeIntType(32);
+ break;
+ default:
+ MissingFunctionality("Texture query op code");
+ }
+
+ Instruction* query = new Instruction(getUniqueId(), resultType, opCode);
+ query->addIdOperand(parameters.sampler);
+ if (parameters.coords)
+ query->addIdOperand(parameters.coords);
+ if (parameters.lod)
+ query->addIdOperand(parameters.lod);
+ buildPoint->addInstruction(query);
+
+ return query->getResultId();
+}
+
+// Comments in header
+//Id Builder::createSamplePositionCall(Decoration precision, Id returnType, Id sampleIdx)
+//{
+// // Return type is only flexible type
+// Function* opCode = (fSamplePosition, returnType);
+//
+// Instruction* instr = (opCode, sampleIdx);
+// setPrecision(instr, precision);
+//
+// return instr;
+//}
+
+// Comments in header
+//Id Builder::createBitFieldExtractCall(Decoration precision, Id id, Id offset, Id bits, bool isSigned)
+//{
+// Op opCode = isSigned ? sBitFieldExtract
+// : uBitFieldExtract;
+//
+// if (isScalar(offset) == false || isScalar(bits) == false)
+// MissingFunctionality("bitFieldExtract operand types");
+//
+// // Dest and value are matching flexible types
+// Function* opCode = (opCode, id->getType(), id->getType());
+//
+// assert(opCode);
+//
+// Instruction* instr = (opCode, id, offset, bits);
+// setPrecision(instr, precision);
+//
+// return instr;
+//}
+
+// Comments in header
+//Id Builder::createBitFieldInsertCall(Decoration precision, Id base, Id insert, Id offset, Id bits)
+//{
+// Op opCode = bitFieldInsert;
+//
+// if (isScalar(offset) == false || isScalar(bits) == false)
+// MissingFunctionality("bitFieldInsert operand types");
+//
+// // Dest, base, and insert are matching flexible types
+// Function* opCode = (opCode, base->getType(), base->getType(), base->getType());
+//
+// assert(opCode);
+//
+// Instruction* instr = (opCode, base, insert, offset, bits);
+// setPrecision(instr, precision);
+//
+// return instr;
+//}
+
+// Comments in header
+Id Builder::createCompare(Decoration precision, Id value1, Id value2, bool equal)
+{
+ Id boolType = makeBoolType();
+ Id valueType = getTypeId(value1);
+
+ assert(valueType == getTypeId(value2));
+ assert(! isScalar(value1));
+
+ // Vectors
+
+ if (isVectorType(valueType)) {
+ Id boolVectorType = makeVectorType(boolType, getNumTypeComponents(valueType));
+ Id boolVector;
+ Op op;
+ if (getMostBasicTypeClass(valueType) == OpTypeFloat)
+ op = equal ? OpFOrdEqual : OpFOrdNotEqual;
+ else
+ op = equal ? OpIEqual : OpINotEqual;
+
+ boolVector = createBinOp(op, boolVectorType, value1, value2);
+ setPrecision(boolVector, precision);
+
+ // Reduce vector compares with any() and all().
+
+ op = equal ? OpAll : OpAny;
+
+ return createUnaryOp(op, boolType, boolVector);
+ }
+
+ spv::MissingFunctionality("Composite comparison of non-vectors");
+
+ return NoResult;
+
+ // Recursively handle aggregates, which include matrices, arrays, and structures
+ // and accumulate the results.
+
+ // Matrices
+
+ // Arrays
+
+ //int numElements;
+ //const llvm::ArrayType* arrayType = llvm::dyn_cast<llvm::ArrayType>(value1->getType());
+ //if (arrayType)
+ // numElements = (int)arrayType->getNumElements();
+ //else {
+ // // better be structure
+ // const llvm::StructType* structType = llvm::dyn_cast<llvm::StructType>(value1->getType());
+ // assert(structType);
+ // numElements = structType->getNumElements();
+ //}
+
+ //assert(numElements > 0);
+
+ //for (int element = 0; element < numElements; ++element) {
+ // // Get intermediate comparison values
+ // llvm::Value* element1 = builder.CreateExtractValue(value1, element, "element1");
+ // setInstructionPrecision(element1, precision);
+ // llvm::Value* element2 = builder.CreateExtractValue(value2, element, "element2");
+ // setInstructionPrecision(element2, precision);
+
+ // llvm::Value* subResult = createCompare(precision, element1, element2, equal, "comp");
+
+ // // Accumulate intermediate comparison
+ // if (element == 0)
+ // result = subResult;
+ // else {
+ // if (equal)
+ // result = builder.CreateAnd(result, subResult);
+ // else
+ // result = builder.CreateOr(result, subResult);
+ // setInstructionPrecision(result, precision);
+ // }
+ //}
+
+ //return result;
+}
+
+// Comments in header
+//Id Builder::createOperation(Decoration precision, Op opCode, Id operand)
+//{
+// Op* opCode = 0;
+//
+// // Handle special return types here. Things that don't have same result type as parameter
+// switch (opCode) {
+// case fIsNan:
+// case fIsInf:
+// break;
+// case fFloatBitsToInt:
+// break;
+// case fIntBitsTofloat:
+// break;
+// case fPackSnorm2x16:
+// case fPackUnorm2x16:
+// case fPackHalf2x16:
+// break;
+// case fUnpackUnorm2x16:
+// case fUnpackSnorm2x16:
+// case fUnpackHalf2x16:
+// break;
+//
+// case fFrexp:
+// case fLdexp:
+// case fPackUnorm4x8:
+// case fPackSnorm4x8:
+// case fUnpackUnorm4x8:
+// case fUnpackSnorm4x8:
+// case fPackDouble2x32:
+// case fUnpackDouble2x32:
+// break;
+// case fLength:
+// // scalar result type
+// break;
+// case any:
+// case all:
+// // fixed result type
+// break;
+// case fModF:
+// // modf() will return a struct that the caller must decode
+// break;
+// default:
+// // Unary operations that have operand and dest with same flexible type
+// break;
+// }
+//
+// assert(opCode);
+//
+// Instruction* instr = (opCode, operand);
+// setPrecision(instr, precision);
+//
+// return instr;
+//}
+//
+//// Comments in header
+//Id Builder::createOperation(Decoration precision, Op opCode, Id operand0, Id operand1)
+//{
+// Function* opCode = 0;
+//
+// // Handle special return types here. Things that don't have same result type as parameter
+// switch (opCode) {
+// case fDistance:
+// case fDot2:
+// case fDot3:
+// case fDot4:
+// // scalar result type
+// break;
+// case fStep:
+// // first argument can be scalar, return and second argument match
+// break;
+// case fSmoothStep:
+// // first argument can be scalar, return and second argument match
+// break;
+// default:
+// // Binary operations that have operand and dest with same flexible type
+// break;
+// }
+//
+// assert(opCode);
+//
+// Instruction* instr = (opCode, operand0, operand1);
+// setPrecision(instr, precision);
+//
+// return instr;
+//}
+//
+//Id Builder::createOperation(Decoration precision, Op opCode, Id operand0, Id operand1, Id operand2)
+//{
+// Function* opCode;
+//
+// // Handle special return types here. Things that don't have same result type as parameter
+// switch (opCode) {
+// case fSmoothStep:
+// // first argument can be scalar, return and second argument match
+// break;
+// default:
+// // Use operand0 type as result type
+// break;
+// }
+//
+// assert(opCode);
+//
+// Instruction* instr = (opCode, operand0, operand1, operand2);
+// setPrecision(instr, precision);
+//
+// return instr;
+//}
+
+// OpCompositeConstruct
+Id Builder::createCompositeConstruct(Id typeId, std::vector<Id>& constituents)
+{
+ assert(isAggregateType(typeId) || getNumTypeComponents(typeId) > 1 && getNumTypeComponents(typeId) == constituents.size());
+
+ Instruction* op = new Instruction(getUniqueId(), typeId, OpCompositeConstruct);
+ for (int c = 0; c < (int)constituents.size(); ++c)
+ op->addIdOperand(constituents[c]);
+ buildPoint->addInstruction(op);
+
+ return op->getResultId();
+}
+
+// Vector or scalar constructor
+Id Builder::createConstructor(Decoration precision, const std::vector<Id>& sources, Id resultTypeId)
+{
+ Id result = 0;
+ unsigned int numTargetComponents = getNumTypeComponents(resultTypeId);
+ unsigned int targetComponent = 0;
+
+ // Special case: when calling a vector constructor with a single scalar
+ // argument, smear the scalar
+ if (sources.size() == 1 && isScalar(sources[0]) && numTargetComponents > 1)
+ return smearScalar(precision, sources[0], resultTypeId);
+
+ Id scalarTypeId = getScalarTypeId(resultTypeId);
+ std::vector<Id> constituents; // accumulate the arguments for OpCompositeConstruct
+ for (unsigned int i = 0; i < sources.size(); ++i) {
+ if (isAggregate(sources[i]))
+ MissingFunctionality("aggregate in vector constructor");
+
+ unsigned int sourceSize = getNumComponents(sources[i]);
+
+ unsigned int sourcesToUse = sourceSize;
+ if (sourcesToUse + targetComponent > numTargetComponents)
+ sourcesToUse = numTargetComponents - targetComponent;
+
+ for (unsigned int s = 0; s < sourcesToUse; ++s) {
+ Id arg = sources[i];
+ if (sourceSize > 1) {
+ std::vector<unsigned> swiz;
+ swiz.push_back(s);
+ arg = createRvalueSwizzle(scalarTypeId, arg, swiz);
+ }
+
+ if (numTargetComponents > 1)
+ constituents.push_back(arg);
+ else
+ result = arg;
+ ++targetComponent;
+ }
+
+ if (targetComponent >= numTargetComponents)
+ break;
+ }
+
+ if (constituents.size() > 0)
+ result = createCompositeConstruct(resultTypeId, constituents);
+
+ setPrecision(result, precision);
+
+ return result;
+}
+
+// Comments in header
+Id Builder::createMatrixConstructor(Decoration precision, const std::vector<Id>& sources, Id resultTypeId)
+{
+ Id componentTypeId = getScalarTypeId(resultTypeId);
+ int numCols = getTypeNumColumns(resultTypeId);
+ int numRows = getTypeNumRows(resultTypeId);
+
+ // Will use a two step process
+ // 1. make a compile-time 2D array of values
+ // 2. construct a matrix from that array
+
+ // Step 1.
+
+ // initialize the array to the identity matrix
+ Id ids[maxMatrixSize][maxMatrixSize];
+ Id one = makeFloatConstant(1.0);
+ Id zero = makeFloatConstant(0.0);
+ for (int col = 0; col < 4; ++col) {
+ for (int row = 0; row < 4; ++row) {
+ if (col == row)
+ ids[col][row] = one;
+ else
+ ids[col][row] = zero;
+ }
+ }
+
+ // modify components as dictated by the arguments
+ if (sources.size() == 1 && isScalar(sources[0])) {
+ // a single scalar; resets the diagonals
+ for (int col = 0; col < 4; ++col)
+ ids[col][col] = sources[0];
+ } else if (isMatrix(sources[0])) {
+ // constructing from another matrix; copy over the parts that exist in both the argument and constructee
+ Id matrix = sources[0];
+ int minCols = std::min(numCols, getNumColumns(matrix));
+ int minRows = std::min(numRows, getNumRows(matrix));
+ for (int col = 0; col < minCols; ++col) {
+ std::vector<unsigned> indexes;
+ indexes.push_back(col);
+ for (int row = 0; row < minRows; ++row) {
+ indexes.push_back(row);
+ ids[col][row] = createCompositeExtract(matrix, componentTypeId, indexes);
+ indexes.pop_back();
+ setPrecision(ids[col][row], precision);
+ }
+ }
+ } else {
+ // fill in the matrix in column-major order with whatever argument components are available
+ int row = 0;
+ int col = 0;
+
+ for (int arg = 0; arg < (int)sources.size(); ++arg) {
+ Id argComp = sources[arg];
+ for (int comp = 0; comp < getNumComponents(sources[arg]); ++comp) {
+ if (getNumComponents(sources[arg]) > 1) {
+ argComp = createCompositeExtract(sources[arg], componentTypeId, comp);
+ setPrecision(argComp, precision);
+ }
+ ids[col][row++] = argComp;
+ if (row == numRows) {
+ row = 0;
+ col++;
+ }
+ }
+ }
+ }
+
+
+ // Step 2: Construct a matrix from that array.
+ // First make the column vectors, then make the matrix.
+
+ // make the column vectors
+ Id columnTypeId = getContainedTypeId(resultTypeId);
+ std::vector<Id> matrixColumns;
+ for (int col = 0; col < numCols; ++col) {
+ std::vector<Id> vectorComponents;
+ for (int row = 0; row < numRows; ++row)
+ vectorComponents.push_back(ids[col][row]);
+ matrixColumns.push_back(createCompositeConstruct(columnTypeId, vectorComponents));
+ }
+
+ // make the matrix
+ return createCompositeConstruct(resultTypeId, matrixColumns);
+}
+
+// Comments in header
+Builder::If::If(Id cond, Builder& gb) :
+ builder(gb),
+ condition(cond),
+ elseBlock(0)
+{
+ function = &builder.getBuildPoint()->getParent();
+
+ // make the blocks, but only put the then-block into the function,
+ // the else-block and merge-block will be added later, in order, after
+ // earlier code is emitted
+ thenBlock = new Block(builder.getUniqueId(), *function);
+ mergeBlock = new Block(builder.getUniqueId(), *function);
+
+ // Save the current block, so that we can add in the flow control split when
+ // makeEndIf is called.
+ headerBlock = builder.getBuildPoint();
+
+ function->addBlock(thenBlock);
+ builder.setBuildPoint(thenBlock);
+}
+
+// Comments in header
+void Builder::If::makeBeginElse()
+{
+ // Close out the "then" by having it jump to the mergeBlock
+ builder.createBranch(mergeBlock);
+
+ // Make the first else block and add it to the function
+ elseBlock = new Block(builder.getUniqueId(), *function);
+ function->addBlock(elseBlock);
+
+ // Start building the else block
+ builder.setBuildPoint(elseBlock);
+}
+
+// Comments in header
+void Builder::If::makeEndIf()
+{
+ // jump to the merge block
+ builder.createBranch(mergeBlock);
+
+ // Go back to the headerBlock and make the flow control split
+ builder.setBuildPoint(headerBlock);
+ builder.createMerge(OpSelectionMerge, mergeBlock, SelectionControlMaskNone);
+ if (elseBlock)
+ builder.createConditionalBranch(condition, thenBlock, elseBlock);
+ else
+ builder.createConditionalBranch(condition, thenBlock, mergeBlock);
+
+ // add the merge block to the function
+ function->addBlock(mergeBlock);
+ builder.setBuildPoint(mergeBlock);
+}
+
+// Comments in header
+void Builder::makeSwitch(Id selector, int numSegments, std::vector<int>& caseValues, std::vector<int>& valueIndexToSegment, int defaultSegment,
+ std::vector<Block*>& segmentBlocks)
+{
+ Function& function = buildPoint->getParent();
+
+ // make all the blocks
+ for (int s = 0; s < numSegments; ++s)
+ segmentBlocks.push_back(new Block(getUniqueId(), function));
+
+ Block* mergeBlock = new Block(getUniqueId(), function);
+
+ // make and insert the switch's selection-merge instruction
+ createMerge(OpSelectionMerge, mergeBlock, SelectionControlMaskNone);
+
+ // make the switch instruction
+ Instruction* switchInst = new Instruction(NoResult, NoType, OpSwitch);
+ switchInst->addIdOperand(selector);
+ switchInst->addIdOperand(defaultSegment >= 0 ? segmentBlocks[defaultSegment]->getId() : mergeBlock->getId());
+ for (int i = 0; i < (int)caseValues.size(); ++i) {
+ switchInst->addImmediateOperand(caseValues[i]);
+ switchInst->addIdOperand(segmentBlocks[valueIndexToSegment[i]]->getId());
+ }
+ buildPoint->addInstruction(switchInst);
+
+ // push the merge block
+ switchMerges.push(mergeBlock);
+}
+
+// Comments in header
+void Builder::addSwitchBreak()
+{
+ // branch to the top of the merge block stack
+ createBranch(switchMerges.top());
+ createAndSetNoPredecessorBlock("post-switch-break");
+}
+
+// Comments in header
+void Builder::nextSwitchSegment(std::vector<Block*>& segmentBlock, int nextSegment)
+{
+ int lastSegment = nextSegment - 1;
+ if (lastSegment >= 0) {
+ // Close out previous segment by jumping, if necessary, to next segment
+ if (! buildPoint->isTerminated())
+ createBranch(segmentBlock[nextSegment]);
+ }
+ Block* block = segmentBlock[nextSegment];
+ block->getParent().addBlock(block);
+ setBuildPoint(block);
+}
+
+// Comments in header
+void Builder::endSwitch(std::vector<Block*>& /*segmentBlock*/)
+{
+ // Close out previous segment by jumping, if necessary, to next segment
+ if (! buildPoint->isTerminated())
+ addSwitchBreak();
+
+ switchMerges.top()->getParent().addBlock(switchMerges.top());
+ setBuildPoint(switchMerges.top());
+
+ switchMerges.pop();
+}
+
+// Comments in header
+void Builder::makeNewLoop()
+{
+ Loop loop = { };
+
+ loop.function = &getBuildPoint()->getParent();
+ loop.header = new Block(getUniqueId(), *loop.function);
+ loop.merge = new Block(getUniqueId(), *loop.function);
+ loop.test = NULL;
+
+ loops.push(loop);
+
+ // Branch into the loop
+ createBranch(loop.header);
+
+ // Set ourselves inside the loop
+ loop.function->addBlock(loop.header);
+ setBuildPoint(loop.header);
+}
+
+void Builder::createLoopTestBranch(Id condition)
+{
+ Loop& loop = loops.top();
+
+ // If loop.test exists, then we've already generated the LoopMerge
+ // for this loop.
+ if (!loop.test)
+ createMerge(OpLoopMerge, loop.merge, LoopControlMaskNone);
+
+ // Branching to the "body" block will keep control inside
+ // the loop.
+ Block* body = new Block(getUniqueId(), *loop.function);
+ createConditionalBranch(condition, body, loop.merge);
+ loop.function->addBlock(body);
+ setBuildPoint(body);
+}
+
+void Builder::endLoopHeaderWithoutTest()
+{
+ Loop& loop = loops.top();
+
+ createMerge(OpLoopMerge, loop.merge, LoopControlMaskNone);
+ Block* body = new Block(getUniqueId(), *loop.function);
+ createBranch(body);
+ loop.function->addBlock(body);
+ setBuildPoint(body);
+
+ assert(!loop.test);
+ loop.test = new Block(getUniqueId(), *loop.function);
+}
+
+void Builder::createBranchToLoopTest()
+{
+ Loop& loop = loops.top();
+ Block* testBlock = loop.test;
+ assert(testBlock);
+ createBranch(testBlock);
+ loop.function->addBlock(testBlock);
+ setBuildPoint(testBlock);
+}
+
+void Builder::createLoopContinue()
+{
+ Loop& loop = loops.top();
+ if (loop.test)
+ createBranch(loop.test);
+ else
+ createBranch(loop.header);
+ // Set up a block for dead code.
+ createAndSetNoPredecessorBlock("post-loop-continue");
+}
+
+// Add an exit (e.g. "break") for the innermost loop that you're in
+void Builder::createLoopExit()
+{
+ createBranch(loops.top().merge);
+ // Set up a block for dead code.
+ createAndSetNoPredecessorBlock("post-loop-break");
+}
+
+// Close the innermost loop
+void Builder::closeLoop()
+{
+ Loop& loop = loops.top();
+
+ // Branch back to the top
+ createBranch(loop.header);
+
+ // Add the merge block and set the build point to it
+ loop.function->addBlock(loop.merge);
+ setBuildPoint(loop.merge);
+
+ loops.pop();
+}
+
+void Builder::clearAccessChain()
+{
+ accessChain.base = 0;
+ accessChain.indexChain.clear();
+ accessChain.instr = 0;
+ accessChain.swizzle.clear();
+ accessChain.component = 0;
+ accessChain.resultType = NoType;
+ accessChain.isRValue = false;
+}
+
+// Comments in header
+void Builder::accessChainPushSwizzle(std::vector<unsigned>& swizzle)
+{
+ // if needed, propagate the swizzle for the current access chain
+ if (accessChain.swizzle.size()) {
+ std::vector<unsigned> oldSwizzle = accessChain.swizzle;
+ accessChain.swizzle.resize(0);
+ for (unsigned int i = 0; i < swizzle.size(); ++i) {
+ accessChain.swizzle.push_back(oldSwizzle[swizzle[i]]);
+ }
+ } else
+ accessChain.swizzle = swizzle;
+
+ // determine if we need to track this swizzle anymore
+ simplifyAccessChainSwizzle();
+}
+
+// Comments in header
+void Builder::accessChainStore(Id rvalue)
+{
+ assert(accessChain.isRValue == false);
+
+ Id base = collapseAccessChain();
+
+ if (accessChain.swizzle.size() && accessChain.component)
+ MissingFunctionality("simultaneous l-value swizzle and dynamic component selection");
+
+ // If swizzle exists, it is out-of-order or not full, we must load the target vector,
+ // extract and insert elements to perform writeMask and/or swizzle.
+ Id source = NoResult;
+ if (accessChain.swizzle.size()) {
+ Id tempBaseId = createLoad(base);
+ source = createLvalueSwizzle(getTypeId(tempBaseId), tempBaseId, rvalue, accessChain.swizzle);
+ }
+
+ // dynamic component selection
+ if (accessChain.component) {
+ Id tempBaseId = (source == NoResult) ? createLoad(base) : source;
+ source = createVectorInsertDynamic(tempBaseId, getTypeId(tempBaseId), rvalue, accessChain.component);
+ }
+
+ if (source == NoResult)
+ source = rvalue;
+
+ createStore(source, base);
+}
+
+// Comments in header
+Id Builder::accessChainLoad(Decoration /*precision*/)
+{
+ Id id;
+
+ if (accessChain.isRValue) {
+ if (accessChain.indexChain.size() > 0) {
+ mergeAccessChainSwizzle(); // TODO: optimization: look at applying this optimization more widely
+ // if all the accesses are constants, we can use OpCompositeExtract
+ std::vector<unsigned> indexes;
+ bool constant = true;
+ for (int i = 0; i < (int)accessChain.indexChain.size(); ++i) {
+ if (isConstantScalar(accessChain.indexChain[i]))
+ indexes.push_back(getConstantScalar(accessChain.indexChain[i]));
+ else {
+ constant = false;
+ break;
+ }
+ }
+
+ if (constant)
+ id = createCompositeExtract(accessChain.base, accessChain.resultType, indexes);
+ else {
+ // make a new function variable for this r-value
+ Id lValue = createVariable(StorageClassFunction, getTypeId(accessChain.base), "indexable");
+
+ // store into it
+ createStore(accessChain.base, lValue);
+
+ // move base to the new variable
+ accessChain.base = lValue;
+ accessChain.isRValue = false;
+
+ // load through the access chain
+ id = createLoad(collapseAccessChain());
+ }
+ } else
+ id = accessChain.base;
+ } else {
+ // load through the access chain
+ id = createLoad(collapseAccessChain());
+ }
+
+ // Done, unless there are swizzles to do
+ if (accessChain.swizzle.size() == 0 && accessChain.component == 0)
+ return id;
+
+ Id componentType = getScalarTypeId(accessChain.resultType);
+
+ // Do remaining swizzling
+ // First, static swizzling
+ if (accessChain.swizzle.size()) {
+ // static swizzle
+ Id resultType = componentType;
+ if (accessChain.swizzle.size() > 1)
+ resultType = makeVectorType(componentType, accessChain.swizzle.size());
+ id = createRvalueSwizzle(resultType, id, accessChain.swizzle);
+ }
+
+ // dynamic single-component selection
+ if (accessChain.component)
+ id = createVectorExtractDynamic(id, componentType, accessChain.component);
+
+ return id;
+}
+
+Id Builder::accessChainGetLValue()
+{
+ assert(accessChain.isRValue == false);
+
+ Id lvalue = collapseAccessChain();
+
+ // If swizzle exists, it is out-of-order or not full, we must load the target vector,
+ // extract and insert elements to perform writeMask and/or swizzle. This does not
+ // go with getting a direct l-value pointer.
+ assert(accessChain.swizzle.size() == 0);
+ assert(accessChain.component == spv::NoResult);
+
+ return lvalue;
+}
+
+void Builder::dump(std::vector<unsigned int>& out) const
+{
+ // Header, before first instructions:
+ out.push_back(MagicNumber);
+ out.push_back(Version);
+ out.push_back(builderNumber);
+ out.push_back(uniqueId + 1);
+ out.push_back(0);
+
+ // First instructions, some created on the spot here:
+ if (source != SourceLanguageUnknown) {
+ Instruction sourceInst(0, 0, OpSource);
+ sourceInst.addImmediateOperand(source);
+ sourceInst.addImmediateOperand(sourceVersion);
+ sourceInst.dump(out);
+ }
+ for (int e = 0; e < (int)extensions.size(); ++e) {
+ Instruction extInst(0, 0, OpSourceExtension);
+ extInst.addStringOperand(extensions[e]);
+ extInst.dump(out);
+ }
+ // TBD: OpExtension ...
+ dumpInstructions(out, imports);
+ Instruction memInst(0, 0, OpMemoryModel);
+ memInst.addImmediateOperand(addressModel);
+ memInst.addImmediateOperand(memoryModel);
+ memInst.dump(out);
+
+ // Instructions saved up while building:
+ dumpInstructions(out, entryPoints);
+ dumpInstructions(out, executionModes);
+ dumpInstructions(out, names);
+ dumpInstructions(out, lines);
+ dumpInstructions(out, decorations);
+ dumpInstructions(out, constantsTypesGlobals);
+ dumpInstructions(out, externals);
+
+ // The functions
+ module.dump(out);
+}
+
+//
+// Protected methods.
+//
+
+Id Builder::collapseAccessChain()
+{
+ // TODO: bring in an individual component swizzle here, so that a pointer
+ // all the way to the component level can be created.
+ assert(accessChain.isRValue == false);
+
+ if (accessChain.indexChain.size() > 0) {
+ if (accessChain.instr == 0) {
+ StorageClass storageClass = (StorageClass)module.getStorageClass(getTypeId(accessChain.base));
+ accessChain.instr = createAccessChain(storageClass, accessChain.base, accessChain.indexChain);
+ }
+
+ return accessChain.instr;
+ } else
+ return accessChain.base;
+}
+
+// clear out swizzle if it is redundant
+void Builder::simplifyAccessChainSwizzle()
+{
+ // If the swizzle has fewer components than the vector, it is subsetting, and must stay
+ // to preserve that fact.
+ if (getNumTypeComponents(accessChain.resultType) > (int)accessChain.swizzle.size())
+ return;
+
+ // if components are out of order, it is a swizzle
+ for (unsigned int i = 0; i < accessChain.swizzle.size(); ++i) {
+ if (i != accessChain.swizzle[i])
+ return;
+ }
+
+ // otherwise, there is no need to track this swizzle
+ accessChain.swizzle.clear();
+}
+
+// clear out swizzle if it can become part of the indexes
+void Builder::mergeAccessChainSwizzle()
+{
+ // is there even a chance of doing something? Need a single-component swizzle
+ if ((accessChain.swizzle.size() > 1) ||
+ (accessChain.swizzle.size() == 0 && accessChain.component == 0))
+ return;
+
+ // TODO: optimization: remove this, but for now confine this to non-dynamic accesses
+ // (the above test is correct when this is removed.)
+ if (accessChain.component)
+ return;
+
+ // move the swizzle over to the indexes
+ if (accessChain.swizzle.size() == 1)
+ accessChain.indexChain.push_back(makeUintConstant(accessChain.swizzle.front()));
+ else
+ accessChain.indexChain.push_back(accessChain.component);
+ accessChain.resultType = getScalarTypeId(accessChain.resultType);
+
+ // now there is no need to track this swizzle
+ accessChain.component = NoResult;
+ accessChain.swizzle.clear();
+}
+
+// Utility method for creating a new block and setting the insert point to
+// be in it. This is useful for flow-control operations that need a "dummy"
+// block proceeding them (e.g. instructions after a discard, etc).
+void Builder::createAndSetNoPredecessorBlock(const char* /*name*/)
+{
+ Block* block = new Block(getUniqueId(), buildPoint->getParent());
+ block->setUnreachable();
+ buildPoint->getParent().addBlock(block);
+ setBuildPoint(block);
+
+ //if (name)
+ // addName(block->getId(), name);
+}
+
+// Comments in header
+void Builder::createBranch(Block* block)
+{
+ Instruction* branch = new Instruction(OpBranch);
+ branch->addIdOperand(block->getId());
+ buildPoint->addInstruction(branch);
+ block->addPredecessor(buildPoint);
+}
+
+void Builder::createMerge(Op mergeCode, Block* mergeBlock, unsigned int control)
+{
+ Instruction* merge = new Instruction(mergeCode);
+ merge->addIdOperand(mergeBlock->getId());
+ merge->addImmediateOperand(control);
+ buildPoint->addInstruction(merge);
+}
+
+void Builder::createConditionalBranch(Id condition, Block* thenBlock, Block* elseBlock)
+{
+ Instruction* branch = new Instruction(OpBranchConditional);
+ branch->addIdOperand(condition);
+ branch->addIdOperand(thenBlock->getId());
+ branch->addIdOperand(elseBlock->getId());
+ buildPoint->addInstruction(branch);
+ thenBlock->addPredecessor(buildPoint);
+ elseBlock->addPredecessor(buildPoint);
+}
+
+void Builder::dumpInstructions(std::vector<unsigned int>& out, const std::vector<Instruction*>& instructions) const
+{
+ for (int i = 0; i < (int)instructions.size(); ++i) {
+ instructions[i]->dump(out);
+ }
+}
+
+void MissingFunctionality(const char* fun)
+{
+ printf("Missing functionality: %s\n", fun);
+ exit(1);
+}
+
+void ValidationError(const char* error)
+{
+ printf("Validation Error: %s\n", error);
+}
+
+}; // end spv namespace
-//\r
-//Copyright (C) 2014 LunarG, Inc.\r
-//\r
-//All rights reserved.\r
-//\r
-//Redistribution and use in source and binary forms, with or without\r
-//modification, are permitted provided that the following conditions\r
-//are met:\r
-//\r
-// Redistributions of source code must retain the above copyright\r
-// notice, this list of conditions and the following disclaimer.\r
-//\r
-// Redistributions in binary form must reproduce the above\r
-// copyright notice, this list of conditions and the following\r
-// disclaimer in the documentation and/or other materials provided\r
-// with the distribution.\r
-//\r
-// Neither the name of 3Dlabs Inc. Ltd. nor the names of its\r
-// contributors may be used to endorse or promote products derived\r
-// from this software without specific prior written permission.\r
-//\r
-//THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\r
-//"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\r
-//LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS\r
-//FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE\r
-//COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,\r
-//INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,\r
-//BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\r
-//LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER\r
-//CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\r
-//LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN\r
-//ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE\r
-//POSSIBILITY OF SUCH DAMAGE.\r
-\r
-//\r
-// Author: John Kessenich, LunarG\r
-//\r
-\r
-//\r
-// "Builder" is an interface to fully build SPIR-V IR. Allocate one of\r
-// these to build (a thread safe) internal SPIR-V representation (IR),\r
-// and then dump it as a binary stream according to the SPIR-V specification.\r
-//\r
-// A Builder has a 1:1 relationship with a SPIR-V module.\r
-//\r
-\r
-#pragma once\r
-#ifndef SpvBuilder_H\r
-#define SpvBuilder_H\r
-\r
-#include "spirv.h"\r
-#include "spvIR.h"\r
-\r
-#include <algorithm>\r
-#include <stack>\r
-#include <map>\r
-\r
-namespace spv {\r
-\r
-class Builder {\r
-public:\r
- Builder(unsigned int userNumber);\r
- virtual ~Builder();\r
-\r
- static const int maxMatrixSize = 4;\r
-\r
- void setSource(spv::SourceLanguage lang, int version)\r
- {\r
- source = lang;\r
- sourceVersion = version;\r
- }\r
- void addSourceExtension(const char* ext) { extensions.push_back(ext); }\r
- Id import(const char*);\r
- void setMemoryModel(spv::AddressingModel addr, spv::MemoryModel mem)\r
- {\r
- addressModel = addr;\r
- memoryModel = mem;\r
- }\r
-\r
- // To get a new <id> for anything needing a new one.\r
- Id getUniqueId() { return ++uniqueId; }\r
-\r
- // To get a set of new <id>s, e.g., for a set of function parameters\r
- Id getUniqueIds(int numIds)\r
- {\r
- Id id = uniqueId + 1;\r
- uniqueId += numIds;\r
- return id;\r
- }\r
-\r
- // For creating new types (will return old type if the requested one was already made).\r
- Id makeVoidType();\r
- Id makeBoolType();\r
- Id makePointer(StorageClass, Id type);\r
- Id makeIntegerType(int width, bool hasSign); // generic\r
- Id makeIntType(int width) { return makeIntegerType(width, true); }\r
- Id makeUintType(int width) { return makeIntegerType(width, false); }\r
- Id makeFloatType(int width);\r
- Id makeStructType(std::vector<Id>& members, const char*);\r
- Id makeVectorType(Id component, int size);\r
- Id makeMatrixType(Id component, int cols, int rows);\r
- Id makeArrayType(Id element, unsigned size);\r
- Id makeFunctionType(Id returnType, std::vector<Id>& paramTypes);\r
- enum samplerContent {\r
- samplerContentTexture,\r
- samplerContentImage,\r
- samplerContentTextureFilter\r
- };\r
- Id makeSampler(Id sampledType, Dim, samplerContent, bool arrayed, bool shadow, bool ms);\r
-\r
- // For querying about types.\r
- Id getTypeId(Id resultId) const { return module.getTypeId(resultId); }\r
- Id getDerefTypeId(Id resultId) const;\r
- Op getOpCode(Id id) const { return module.getInstruction(id)->getOpCode(); }\r
- Op getTypeClass(Id typeId) const { return getOpCode(typeId); }\r
- Op getMostBasicTypeClass(Id typeId) const;\r
- int getNumComponents(Id resultId) const { return getNumTypeComponents(getTypeId(resultId)); }\r
- int getNumTypeComponents(Id typeId) const;\r
- Id getScalarTypeId(Id typeId) const;\r
- Id getContainedTypeId(Id typeId) const;\r
- Id getContainedTypeId(Id typeId, int) const;\r
-\r
- bool isPointer(Id resultId) const { return isPointerType(getTypeId(resultId)); }\r
- bool isScalar(Id resultId) const { return isScalarType(getTypeId(resultId)); }\r
- bool isVector(Id resultId) const { return isVectorType(getTypeId(resultId)); }\r
- bool isMatrix(Id resultId) const { return isMatrixType(getTypeId(resultId)); }\r
- bool isAggregate(Id resultId) const { return isAggregateType(getTypeId(resultId)); }\r
-\r
- bool isPointerType(Id typeId) const { return getTypeClass(typeId) == OpTypePointer; }\r
- bool isScalarType(Id typeId) const { return getTypeClass(typeId) == OpTypeFloat || getTypeClass(typeId) == OpTypeInt || getTypeClass(typeId) == OpTypeBool; }\r
- bool isVectorType(Id typeId) const { return getTypeClass(typeId) == OpTypeVector; }\r
- bool isMatrixType(Id typeId) const { return getTypeClass(typeId) == OpTypeMatrix; }\r
- bool isStructType(Id typeId) const { return getTypeClass(typeId) == OpTypeStruct; }\r
- bool isArrayType(Id typeId) const { return getTypeClass(typeId) == OpTypeArray; }\r
- bool isAggregateType(Id typeId) const { return isArrayType(typeId) || isStructType(typeId); }\r
- bool isSamplerType(Id typeId) const { return getTypeClass(typeId) == OpTypeSampler; }\r
-\r
- bool isConstantScalar(Id resultId) const { return getOpCode(resultId) == OpConstant; }\r
- unsigned int getConstantScalar(Id resultId) const { return module.getInstruction(resultId)->getImmediateOperand(0); }\r
-\r
- int getTypeNumColumns(Id typeId) const\r
- {\r
- assert(isMatrixType(typeId));\r
- return getNumTypeComponents(typeId);\r
- }\r
- int getNumColumns(Id resultId) const { return getTypeNumColumns(getTypeId(resultId)); }\r
- int getTypeNumRows(Id typeId) const\r
- {\r
- assert(isMatrixType(typeId));\r
- return getNumTypeComponents(getContainedTypeId(typeId));\r
- }\r
- int getNumRows(Id resultId) const { return getTypeNumRows(getTypeId(resultId)); }\r
-\r
- Dim getDimensionality(Id resultId) const\r
- {\r
- assert(isSamplerType(getTypeId(resultId)));\r
- return (Dim)module.getInstruction(getTypeId(resultId))->getImmediateOperand(1);\r
- }\r
- bool isArrayedSampler(Id resultId) const\r
- {\r
- assert(isSamplerType(getTypeId(resultId)));\r
- return module.getInstruction(getTypeId(resultId))->getImmediateOperand(3) != 0;\r
- }\r
-\r
- // For making new constants (will return old constant if the requested one was already made).\r
- Id makeBoolConstant(bool b);\r
- Id makeIntConstant(Id typeId, unsigned value);\r
- Id makeIntConstant(int i) { return makeIntConstant(makeIntType(32), (unsigned)i); }\r
- Id makeUintConstant(unsigned u) { return makeIntConstant(makeUintType(32), u); }\r
- Id makeFloatConstant(float f);\r
- Id makeDoubleConstant(double d);\r
-\r
- // Turn the array of constants into a proper spv constant of the requested type.\r
- Id makeCompositeConstant(Id type, std::vector<Id>& comps);\r
-\r
- // Methods for adding information outside the CFG.\r
- void addEntryPoint(ExecutionModel, Function*);\r
- void addExecutionMode(Function*, ExecutionMode mode, int value = -1);\r
- void addName(Id, const char* name);\r
- void addMemberName(Id, int member, const char* name);\r
- void addLine(Id target, Id fileName, int line, int column);\r
- void addDecoration(Id, Decoration, int num = -1);\r
- void addMemberDecoration(Id, unsigned int member, Decoration, int num = -1);\r
-\r
- // At the end of what block do the next create*() instructions go?\r
- void setBuildPoint(Block* bp) { buildPoint = bp; }\r
- Block* getBuildPoint() const { return buildPoint; }\r
-\r
- // Make the main function.\r
- Function* makeMain();\r
-\r
- // Return from main. Implicit denotes a return at the very end of main.\r
- void makeMainReturn(bool implicit = false) { makeReturn(implicit, 0, true); }\r
-\r
- // Close the main function.\r
- void closeMain();\r
-\r
- // Make a shader-style function, and create its entry block if entry is non-zero.\r
- // Return the function, pass back the entry.\r
- Function* makeFunctionEntry(Id returnType, const char* name, std::vector<Id>& paramTypes, Block **entry = 0);\r
-\r
- // Create a return. Pass whether it is a return form main, and the return\r
- // value (if applicable). In the case of an implicit return, no post-return\r
- // block is inserted.\r
- void makeReturn(bool implicit = false, Id retVal = 0, bool isMain = false);\r
-\r
- // Generate all the code needed to finish up a function.\r
- void leaveFunction(bool main);\r
-\r
- // Create a discard.\r
- void makeDiscard();\r
-\r
- // Create a global or function local or IO variable.\r
- Id createVariable(StorageClass, Id type, const char* name = 0);\r
-\r
- // Store into an Id and return the l-value\r
- void createStore(Id rValue, Id lValue);\r
-\r
- // Load from an Id and return it\r
- Id createLoad(Id lValue);\r
-\r
- // Create an OpAccessChain instruction\r
- Id createAccessChain(StorageClass, Id base, std::vector<Id>& offsets);\r
-\r
- // Create an OpCompositeExtract instruction\r
- Id createCompositeExtract(Id composite, Id typeId, unsigned index);\r
- Id createCompositeExtract(Id composite, Id typeId, std::vector<unsigned>& indexes);\r
- Id createCompositeInsert(Id object, Id composite, Id typeId, unsigned index);\r
- Id createCompositeInsert(Id object, Id composite, Id typeId, std::vector<unsigned>& indexes);\r
-\r
- Id createVectorExtractDynamic(Id vector, Id typeId, Id componentIndex);\r
- Id createVectorInsertDynamic(Id vector, Id typeId, Id component, Id componentIndex);\r
-\r
- void createNoResultOp(Op);\r
- void createNoResultOp(Op, Id operand);\r
- void createControlBarrier(unsigned executionScope);\r
- void createMemoryBarrier(unsigned executionScope, unsigned memorySemantics);\r
- Id createUnaryOp(Op, Id typeId, Id operand);\r
- Id createBinOp(Op, Id typeId, Id operand1, Id operand2);\r
- Id createTriOp(Op, Id typeId, Id operand1, Id operand2, Id operand3);\r
- Id createTernaryOp(Op, Id typeId, Id operand1, Id operand2, Id operand3);\r
- Id createFunctionCall(spv::Function*, std::vector<spv::Id>&);\r
-\r
- // Take an rvalue (source) and a set of channels to extract from it to\r
- // make a new rvalue, which is returned.\r
- Id createRvalueSwizzle(Id typeId, Id source, std::vector<unsigned>& channels);\r
-\r
- // Take a copy of an lvalue (target) and a source of components, and set the\r
- // source components into the lvalue where the 'channels' say to put them.\r
- // An updated version of the target is returned.\r
- // (No true lvalue or stores are used.)\r
- Id createLvalueSwizzle(Id typeId, Id target, Id source, std::vector<unsigned>& channels);\r
-\r
- // If the value passed in is an instruction and the precision is not EMpNone,\r
- // it gets tagged with the requested precision.\r
- void setPrecision(Id /* value */, Decoration /* precision */)\r
- {\r
- // TODO\r
- }\r
-\r
- // Can smear a scalar to a vector for the following forms:\r
- // - promoteScalar(scalar, vector) // smear scalar to width of vector\r
- // - promoteScalar(vector, scalar) // smear scalar to width of vector\r
- // - promoteScalar(pointer, scalar) // smear scalar to width of what pointer points to\r
- // - promoteScalar(scalar, scalar) // do nothing\r
- // Other forms are not allowed.\r
- //\r
- // Note: One of the arguments will change, with the result coming back that way rather than \r
- // through the return value.\r
- void promoteScalar(Decoration precision, Id& left, Id& right);\r
-\r
- // make a value by smearing the scalar to fill the type\r
- Id smearScalar(Decoration precision, Id scalarVal, Id);\r
-\r
- // Create a call to a built-in function.\r
- Id createBuiltinCall(Decoration precision, Id resultType, Id builtins, int entryPoint, std::vector<Id>& args);\r
-\r
- // List of parameters used to create a texture operation\r
- struct TextureParameters {\r
- Id sampler;\r
- Id coords;\r
- Id bias;\r
- Id lod;\r
- Id Dref;\r
- Id offset;\r
- Id gradX;\r
- Id gradY;\r
- };\r
-\r
- // Select the correct texture operation based on all inputs, and emit the correct instruction\r
- Id createTextureCall(Decoration precision, Id resultType, bool proj, const TextureParameters&);\r
-\r
- // Emit the OpTextureQuery* instruction that was passed in.\r
- // Figure out the right return value and type, and return it.\r
- Id createTextureQueryCall(Op, const TextureParameters&);\r
-\r
- Id createSamplePositionCall(Decoration precision, Id, Id);\r
-\r
- Id createBitFieldExtractCall(Decoration precision, Id, Id, Id, bool isSigned);\r
- Id createBitFieldInsertCall(Decoration precision, Id, Id, Id, Id);\r
-\r
- // Reduction comparision for composites: For equal and not-equal resulting in a scalar.\r
- Id createCompare(Decoration precision, Id, Id, bool /* true if for equal, fales if for not-equal */);\r
-\r
- // OpCompositeConstruct\r
- Id createCompositeConstruct(Id typeId, std::vector<Id>& constituents);\r
-\r
- // vector or scalar constructor\r
- Id createConstructor(Decoration precision, const std::vector<Id>& sources, Id resultTypeId);\r
-\r
- // matrix constructor\r
- Id createMatrixConstructor(Decoration precision, const std::vector<Id>& sources, Id constructee);\r
-\r
- // Helper to use for building nested control flow with if-then-else.\r
- class If {\r
- public:\r
- If(Id condition, Builder& builder);\r
- ~If() {}\r
-\r
- void makeBeginElse();\r
- void makeEndIf();\r
-\r
- private:\r
- If(const If&);\r
- If& operator=(If&);\r
-\r
- Builder& builder;\r
- Id condition;\r
- Function* function;\r
- Block* headerBlock;\r
- Block* thenBlock;\r
- Block* elseBlock;\r
- Block* mergeBlock;\r
- };\r
-\r
- // Make a switch statement. A switch has 'numSegments' of pieces of code, not containing\r
- // any case/default labels, all separated by one or more case/default labels. Each possible\r
- // case value v is a jump to the caseValues[v] segment. The defaultSegment is also in this\r
- // number space. How to compute the value is given by 'condition', as in switch(condition).\r
- //\r
- // The SPIR-V Builder will maintain the stack of post-switch merge blocks for nested switches.\r
- //\r
- // Use a defaultSegment < 0 if there is no default segment (to branch to post switch).\r
- //\r
- // Returns the right set of basic blocks to start each code segment with, so that the caller's\r
- // recursion stack can hold the memory for it.\r
- //\r
- void makeSwitch(Id condition, int numSegments, std::vector<int>& caseValues, std::vector<int>& valueToSegment, int defaultSegment,\r
- std::vector<Block*>& segmentBB); // return argument\r
-\r
- // Add a branch to the innermost switch's merge block.\r
- void addSwitchBreak();\r
-\r
- // Move to the next code segment, passing in the return argument in makeSwitch()\r
- void nextSwitchSegment(std::vector<Block*>& segmentBB, int segment);\r
-\r
- // Finish off the innermost switch.\r
- void endSwitch(std::vector<Block*>& segmentBB);\r
-\r
- // Start the beginning of a new loop.\r
- void makeNewLoop();\r
-\r
- // Add the branch for the loop test, based on the given condition.\r
- // The true branch goes to the block that remains inside the loop, and\r
- // the false branch goes to the loop's merge block. The builder insertion\r
- // point will be placed at the start of the inside-the-loop block.\r
- void createLoopTestBranch(Id condition);\r
-\r
- // Finish generating the loop header block in the case where the loop test\r
- // is at the bottom of the loop. It will include the LoopMerge instruction\r
- // and a branch to the rest of the body. The loop header block must be\r
- // separate from the rest of the body to make room for the the two kinds\r
- // of *Merge instructions that might have to occur just before a branch:\r
- // the loop header must have a LoopMerge as its second-last instruction,\r
- // and the body might begin with a conditional branch, which must have its\r
- // own SelectionMerge instruction.\r
- // Also create the basic block that will contain the loop test, but don't\r
- // insert it into the function yet. Any "continue" constructs in this loop\r
- // will branch to the loop test block. The builder insertion point will be\r
- // placed at the start of the body block.\r
- void endLoopHeaderWithoutTest();\r
-\r
- // Generate a branch to the loop test block. This can only be called if\r
- // the loop test is at the bottom of the loop. The builder insertion point\r
- // is left at the start of the test block.\r
- void createBranchToLoopTest();\r
-\r
- // Add a branch to the test of the current (innermost) loop.\r
- void createLoopContinue();\r
-\r
- // Add an exit (e.g. "break") for the innermost loop that you're in\r
- void createLoopExit();\r
-\r
- // Close the innermost loop that you're in\r
- void closeLoop();\r
-\r
- //\r
- // Access chain design for an R-Value vs. L-Value:\r
- //\r
- // There is a single access chain the builder is building at\r
- // any particular time. Such a chain can be used to either to a load or\r
- // a store, when desired.\r
- //\r
- // Expressions can be r-values, l-values, or both, or only r-values:\r
- // a[b.c].d = .... // l-value\r
- // ... = a[b.c].d; // r-value, that also looks like an l-value\r
- // ++a[b.c].d; // r-value and l-value\r
- // (x + y)[2]; // r-value only, can't possibly be l-value\r
- //\r
- // Computing an r-value means generating code. Hence,\r
- // r-values should only be computed when they are needed, not speculatively.\r
- //\r
- // Computing an l-value means saving away information for later use in the compiler,\r
- // no code is generated until the l-value is later dereferenced. It is okay\r
- // to speculatively generate an l-value, just not okay to speculatively dereference it.\r
- //\r
- // The base of the access chain (the left-most variable or expression\r
- // from which everything is based) can be set either as an l-value\r
- // or as an r-value. Most efficient would be to set an l-value if one\r
- // is available. If an expression was evaluated, the resulting r-value\r
- // can be set as the chain base.\r
- //\r
- // The users of this single access chain can save and restore if they\r
- // want to nest or manage multiple chains.\r
- //\r
-\r
- struct AccessChain {\r
- Id base; // for l-values, pointer to the base object, for r-values, the base object\r
- std::vector<Id> indexChain;\r
- Id instr; // the instruction that generates this access chain\r
- std::vector<unsigned> swizzle;\r
- Id component; // a dynamic component index, can coexist with a swizzle, done after the swizzle\r
- Id resultType; // dereferenced type, to be exclusive of swizzles\r
- bool isRValue;\r
- };\r
-\r
- //\r
- // the SPIR-V builder maintains a single active chain that\r
- // the following methods operated on\r
- //\r
-\r
- // for external save and restore\r
- AccessChain getAccessChain() { return accessChain; }\r
- void setAccessChain(AccessChain newChain) { accessChain = newChain; }\r
-\r
- // clear accessChain\r
- void clearAccessChain();\r
-\r
- // set new base as an l-value base\r
- void setAccessChainLValue(Id lValue)\r
- {\r
- assert(isPointer(lValue));\r
- accessChain.base = lValue;\r
- accessChain.resultType = getContainedTypeId(getTypeId(lValue));\r
- }\r
-\r
- // set new base value as an r-value\r
- void setAccessChainRValue(Id rValue)\r
- {\r
- accessChain.isRValue = true;\r
- accessChain.base = rValue;\r
- accessChain.resultType = getTypeId(rValue);\r
- }\r
-\r
- // push offset onto the end of the chain\r
- void accessChainPush(Id offset, Id newType)\r
- {\r
- accessChain.indexChain.push_back(offset);\r
- accessChain.resultType = newType;\r
- }\r
-\r
- // push new swizzle onto the end of any existing swizzle, merging into a single swizzle\r
- void accessChainPushSwizzle(std::vector<unsigned>& swizzle);\r
-\r
- // push a variable component selection onto the access chain; supporting only one, so unsided\r
- void accessChainPushComponent(Id component) { accessChain.component = component; }\r
-\r
- // use accessChain and swizzle to store value\r
- void accessChainStore(Id rvalue);\r
-\r
- // use accessChain and swizzle to load an r-value\r
- Id accessChainLoad(Decoration precision);\r
-\r
- // get the direct pointer for an l-value\r
- Id accessChainGetLValue();\r
-\r
- void dump(std::vector<unsigned int>&) const;\r
-\r
-protected:\r
- Id findScalarConstant(Op typeClass, Id typeId, unsigned value) const;\r
- Id findScalarConstant(Op typeClass, Id typeId, unsigned v1, unsigned v2) const;\r
- Id findCompositeConstant(Op typeClass, std::vector<Id>& comps) const;\r
- Id collapseAccessChain();\r
- void simplifyAccessChainSwizzle();\r
- void mergeAccessChainSwizzle();\r
- void createAndSetNoPredecessorBlock(const char*);\r
- void createBranch(Block* block);\r
- void createMerge(Op, Block*, unsigned int control);\r
- void createConditionalBranch(Id condition, Block* thenBlock, Block* elseBlock);\r
- void dumpInstructions(std::vector<unsigned int>&, const std::vector<Instruction*>&) const;\r
-\r
- SourceLanguage source;\r
- int sourceVersion;\r
- std::vector<const char*> extensions;\r
- AddressingModel addressModel;\r
- MemoryModel memoryModel;\r
- int builderNumber;\r
- Module module;\r
- Block* buildPoint;\r
- Id uniqueId;\r
- Function* mainFunction;\r
- Block* stageExit;\r
- AccessChain accessChain;\r
-\r
- // special blocks of instructions for output\r
- std::vector<Instruction*> imports;\r
- std::vector<Instruction*> entryPoints;\r
- std::vector<Instruction*> executionModes;\r
- std::vector<Instruction*> names;\r
- std::vector<Instruction*> lines;\r
- std::vector<Instruction*> decorations;\r
- std::vector<Instruction*> constantsTypesGlobals;\r
- std::vector<Instruction*> externals;\r
-\r
- // not output, internally used for quick & dirty canonical (unique) creation\r
- std::vector<Instruction*> groupedConstants[OpConstant]; // all types appear before OpConstant\r
- std::vector<Instruction*> groupedTypes[OpConstant];\r
-\r
- // stack of switches\r
- std::stack<Block*> switchMerges;\r
-\r
- // Data that needs to be kept in order to properly handle loops.\r
- struct Loop {\r
- // The header is the first block generated for the loop.\r
- // It dominates all the blocks in the loop, i.e. it is always\r
- // executed before any others.\r
- // If the loop test is executed before the body (as in "while" and\r
- // "for" loops), then the header begins with the test code.\r
- // Otherwise, the loop is a "do-while" loop and the header contains the\r
- // start of the body of the loop (if the body exists).\r
- Block* header;\r
- // The merge block marks the end of the loop. Control is transferred\r
- // to the merge block when either the loop test fails, or when a\r
- // nested "break" is encountered.\r
- Block* merge;\r
- // If not NULL, the test block is the basic block containing the loop\r
- // test and the conditional branch back to the header or the merge\r
- // block. This is created for "do-while" loops, and is the target of\r
- // any "continue" constructs that might exist.\r
- Block* test;\r
- Function* function;\r
- };\r
-\r
- // Our loop stack.\r
- std::stack<Loop> loops;\r
-}; // end Builder class\r
-\r
-void MissingFunctionality(const char*);\r
-void ValidationError(const char* error);\r
-\r
-}; // end spv namespace\r
-\r
-#endif // SpvBuilder_H\r
+//
+//Copyright (C) 2014 LunarG, Inc.
+//
+//All rights reserved.
+//
+//Redistribution and use in source and binary forms, with or without
+//modification, are permitted provided that the following conditions
+//are met:
+//
+// Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//
+// Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following
+// disclaimer in the documentation and/or other materials provided
+// with the distribution.
+//
+// Neither the name of 3Dlabs Inc. Ltd. nor the names of its
+// contributors may be used to endorse or promote products derived
+// from this software without specific prior written permission.
+//
+//THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+//"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+//LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+//FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+//COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+//INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+//BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+//LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+//CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+//LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+//ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+//POSSIBILITY OF SUCH DAMAGE.
+
+//
+// Author: John Kessenich, LunarG
+//
+
+//
+// "Builder" is an interface to fully build SPIR-V IR. Allocate one of
+// these to build (a thread safe) internal SPIR-V representation (IR),
+// and then dump it as a binary stream according to the SPIR-V specification.
+//
+// A Builder has a 1:1 relationship with a SPIR-V module.
+//
+
+#pragma once
+#ifndef SpvBuilder_H
+#define SpvBuilder_H
+
+#include "spirv.h"
+#include "spvIR.h"
+
+#include <algorithm>
+#include <stack>
+#include <map>
+
+namespace spv {
+
+class Builder {
+public:
+ Builder(unsigned int userNumber);
+ virtual ~Builder();
+
+ static const int maxMatrixSize = 4;
+
+ void setSource(spv::SourceLanguage lang, int version)
+ {
+ source = lang;
+ sourceVersion = version;
+ }
+ void addSourceExtension(const char* ext) { extensions.push_back(ext); }
+ Id import(const char*);
+ void setMemoryModel(spv::AddressingModel addr, spv::MemoryModel mem)
+ {
+ addressModel = addr;
+ memoryModel = mem;
+ }
+
+ // To get a new <id> for anything needing a new one.
+ Id getUniqueId() { return ++uniqueId; }
+
+ // To get a set of new <id>s, e.g., for a set of function parameters
+ Id getUniqueIds(int numIds)
+ {
+ Id id = uniqueId + 1;
+ uniqueId += numIds;
+ return id;
+ }
+
+ // For creating new types (will return old type if the requested one was already made).
+ Id makeVoidType();
+ Id makeBoolType();
+ Id makePointer(StorageClass, Id type);
+ Id makeIntegerType(int width, bool hasSign); // generic
+ Id makeIntType(int width) { return makeIntegerType(width, true); }
+ Id makeUintType(int width) { return makeIntegerType(width, false); }
+ Id makeFloatType(int width);
+ Id makeStructType(std::vector<Id>& members, const char*);
+ Id makeVectorType(Id component, int size);
+ Id makeMatrixType(Id component, int cols, int rows);
+ Id makeArrayType(Id element, unsigned size);
+ Id makeFunctionType(Id returnType, std::vector<Id>& paramTypes);
+ enum samplerContent {
+ samplerContentTexture,
+ samplerContentImage,
+ samplerContentTextureFilter
+ };
+ Id makeSampler(Id sampledType, Dim, samplerContent, bool arrayed, bool shadow, bool ms);
+
+ // For querying about types.
+ Id getTypeId(Id resultId) const { return module.getTypeId(resultId); }
+ Id getDerefTypeId(Id resultId) const;
+ Op getOpCode(Id id) const { return module.getInstruction(id)->getOpCode(); }
+ Op getTypeClass(Id typeId) const { return getOpCode(typeId); }
+ Op getMostBasicTypeClass(Id typeId) const;
+ int getNumComponents(Id resultId) const { return getNumTypeComponents(getTypeId(resultId)); }
+ int getNumTypeComponents(Id typeId) const;
+ Id getScalarTypeId(Id typeId) const;
+ Id getContainedTypeId(Id typeId) const;
+ Id getContainedTypeId(Id typeId, int) const;
+
+ bool isPointer(Id resultId) const { return isPointerType(getTypeId(resultId)); }
+ bool isScalar(Id resultId) const { return isScalarType(getTypeId(resultId)); }
+ bool isVector(Id resultId) const { return isVectorType(getTypeId(resultId)); }
+ bool isMatrix(Id resultId) const { return isMatrixType(getTypeId(resultId)); }
+ bool isAggregate(Id resultId) const { return isAggregateType(getTypeId(resultId)); }
+
+ bool isPointerType(Id typeId) const { return getTypeClass(typeId) == OpTypePointer; }
+ bool isScalarType(Id typeId) const { return getTypeClass(typeId) == OpTypeFloat || getTypeClass(typeId) == OpTypeInt || getTypeClass(typeId) == OpTypeBool; }
+ bool isVectorType(Id typeId) const { return getTypeClass(typeId) == OpTypeVector; }
+ bool isMatrixType(Id typeId) const { return getTypeClass(typeId) == OpTypeMatrix; }
+ bool isStructType(Id typeId) const { return getTypeClass(typeId) == OpTypeStruct; }
+ bool isArrayType(Id typeId) const { return getTypeClass(typeId) == OpTypeArray; }
+ bool isAggregateType(Id typeId) const { return isArrayType(typeId) || isStructType(typeId); }
+ bool isSamplerType(Id typeId) const { return getTypeClass(typeId) == OpTypeSampler; }
+
+ bool isConstantScalar(Id resultId) const { return getOpCode(resultId) == OpConstant; }
+ unsigned int getConstantScalar(Id resultId) const { return module.getInstruction(resultId)->getImmediateOperand(0); }
+
+ int getTypeNumColumns(Id typeId) const
+ {
+ assert(isMatrixType(typeId));
+ return getNumTypeComponents(typeId);
+ }
+ int getNumColumns(Id resultId) const { return getTypeNumColumns(getTypeId(resultId)); }
+ int getTypeNumRows(Id typeId) const
+ {
+ assert(isMatrixType(typeId));
+ return getNumTypeComponents(getContainedTypeId(typeId));
+ }
+ int getNumRows(Id resultId) const { return getTypeNumRows(getTypeId(resultId)); }
+
+ Dim getDimensionality(Id resultId) const
+ {
+ assert(isSamplerType(getTypeId(resultId)));
+ return (Dim)module.getInstruction(getTypeId(resultId))->getImmediateOperand(1);
+ }
+ bool isArrayedSampler(Id resultId) const
+ {
+ assert(isSamplerType(getTypeId(resultId)));
+ return module.getInstruction(getTypeId(resultId))->getImmediateOperand(3) != 0;
+ }
+
+ // For making new constants (will return old constant if the requested one was already made).
+ Id makeBoolConstant(bool b);
+ Id makeIntConstant(Id typeId, unsigned value);
+ Id makeIntConstant(int i) { return makeIntConstant(makeIntType(32), (unsigned)i); }
+ Id makeUintConstant(unsigned u) { return makeIntConstant(makeUintType(32), u); }
+ Id makeFloatConstant(float f);
+ Id makeDoubleConstant(double d);
+
+ // Turn the array of constants into a proper spv constant of the requested type.
+ Id makeCompositeConstant(Id type, std::vector<Id>& comps);
+
+ // Methods for adding information outside the CFG.
+ void addEntryPoint(ExecutionModel, Function*);
+ void addExecutionMode(Function*, ExecutionMode mode, int value = -1);
+ void addName(Id, const char* name);
+ void addMemberName(Id, int member, const char* name);
+ void addLine(Id target, Id fileName, int line, int column);
+ void addDecoration(Id, Decoration, int num = -1);
+ void addMemberDecoration(Id, unsigned int member, Decoration, int num = -1);
+
+ // At the end of what block do the next create*() instructions go?
+ void setBuildPoint(Block* bp) { buildPoint = bp; }
+ Block* getBuildPoint() const { return buildPoint; }
+
+ // Make the main function.
+ Function* makeMain();
+
+ // Return from main. Implicit denotes a return at the very end of main.
+ void makeMainReturn(bool implicit = false) { makeReturn(implicit, 0, true); }
+
+ // Close the main function.
+ void closeMain();
+
+ // Make a shader-style function, and create its entry block if entry is non-zero.
+ // Return the function, pass back the entry.
+ Function* makeFunctionEntry(Id returnType, const char* name, std::vector<Id>& paramTypes, Block **entry = 0);
+
+ // Create a return. Pass whether it is a return form main, and the return
+ // value (if applicable). In the case of an implicit return, no post-return
+ // block is inserted.
+ void makeReturn(bool implicit = false, Id retVal = 0, bool isMain = false);
+
+ // Generate all the code needed to finish up a function.
+ void leaveFunction(bool main);
+
+ // Create a discard.
+ void makeDiscard();
+
+ // Create a global or function local or IO variable.
+ Id createVariable(StorageClass, Id type, const char* name = 0);
+
+ // Store into an Id and return the l-value
+ void createStore(Id rValue, Id lValue);
+
+ // Load from an Id and return it
+ Id createLoad(Id lValue);
+
+ // Create an OpAccessChain instruction
+ Id createAccessChain(StorageClass, Id base, std::vector<Id>& offsets);
+
+ // Create an OpCompositeExtract instruction
+ Id createCompositeExtract(Id composite, Id typeId, unsigned index);
+ Id createCompositeExtract(Id composite, Id typeId, std::vector<unsigned>& indexes);
+ Id createCompositeInsert(Id object, Id composite, Id typeId, unsigned index);
+ Id createCompositeInsert(Id object, Id composite, Id typeId, std::vector<unsigned>& indexes);
+
+ Id createVectorExtractDynamic(Id vector, Id typeId, Id componentIndex);
+ Id createVectorInsertDynamic(Id vector, Id typeId, Id component, Id componentIndex);
+
+ void createNoResultOp(Op);
+ void createNoResultOp(Op, Id operand);
+ void createControlBarrier(unsigned executionScope);
+ void createMemoryBarrier(unsigned executionScope, unsigned memorySemantics);
+ Id createUnaryOp(Op, Id typeId, Id operand);
+ Id createBinOp(Op, Id typeId, Id operand1, Id operand2);
+ Id createTriOp(Op, Id typeId, Id operand1, Id operand2, Id operand3);
+ Id createTernaryOp(Op, Id typeId, Id operand1, Id operand2, Id operand3);
+ Id createFunctionCall(spv::Function*, std::vector<spv::Id>&);
+
+ // Take an rvalue (source) and a set of channels to extract from it to
+ // make a new rvalue, which is returned.
+ Id createRvalueSwizzle(Id typeId, Id source, std::vector<unsigned>& channels);
+
+ // Take a copy of an lvalue (target) and a source of components, and set the
+ // source components into the lvalue where the 'channels' say to put them.
+ // An updated version of the target is returned.
+ // (No true lvalue or stores are used.)
+ Id createLvalueSwizzle(Id typeId, Id target, Id source, std::vector<unsigned>& channels);
+
+ // If the value passed in is an instruction and the precision is not EMpNone,
+ // it gets tagged with the requested precision.
+ void setPrecision(Id /* value */, Decoration /* precision */)
+ {
+ // TODO
+ }
+
+ // Can smear a scalar to a vector for the following forms:
+ // - promoteScalar(scalar, vector) // smear scalar to width of vector
+ // - promoteScalar(vector, scalar) // smear scalar to width of vector
+ // - promoteScalar(pointer, scalar) // smear scalar to width of what pointer points to
+ // - promoteScalar(scalar, scalar) // do nothing
+ // Other forms are not allowed.
+ //
+ // Note: One of the arguments will change, with the result coming back that way rather than
+ // through the return value.
+ void promoteScalar(Decoration precision, Id& left, Id& right);
+
+ // make a value by smearing the scalar to fill the type
+ Id smearScalar(Decoration precision, Id scalarVal, Id);
+
+ // Create a call to a built-in function.
+ Id createBuiltinCall(Decoration precision, Id resultType, Id builtins, int entryPoint, std::vector<Id>& args);
+
+ // List of parameters used to create a texture operation
+ struct TextureParameters {
+ Id sampler;
+ Id coords;
+ Id bias;
+ Id lod;
+ Id Dref;
+ Id offset;
+ Id gradX;
+ Id gradY;
+ };
+
+ // Select the correct texture operation based on all inputs, and emit the correct instruction
+ Id createTextureCall(Decoration precision, Id resultType, bool proj, const TextureParameters&);
+
+ // Emit the OpTextureQuery* instruction that was passed in.
+ // Figure out the right return value and type, and return it.
+ Id createTextureQueryCall(Op, const TextureParameters&);
+
+ Id createSamplePositionCall(Decoration precision, Id, Id);
+
+ Id createBitFieldExtractCall(Decoration precision, Id, Id, Id, bool isSigned);
+ Id createBitFieldInsertCall(Decoration precision, Id, Id, Id, Id);
+
+ // Reduction comparision for composites: For equal and not-equal resulting in a scalar.
+ Id createCompare(Decoration precision, Id, Id, bool /* true if for equal, fales if for not-equal */);
+
+ // OpCompositeConstruct
+ Id createCompositeConstruct(Id typeId, std::vector<Id>& constituents);
+
+ // vector or scalar constructor
+ Id createConstructor(Decoration precision, const std::vector<Id>& sources, Id resultTypeId);
+
+ // matrix constructor
+ Id createMatrixConstructor(Decoration precision, const std::vector<Id>& sources, Id constructee);
+
+ // Helper to use for building nested control flow with if-then-else.
+ class If {
+ public:
+ If(Id condition, Builder& builder);
+ ~If() {}
+
+ void makeBeginElse();
+ void makeEndIf();
+
+ private:
+ If(const If&);
+ If& operator=(If&);
+
+ Builder& builder;
+ Id condition;
+ Function* function;
+ Block* headerBlock;
+ Block* thenBlock;
+ Block* elseBlock;
+ Block* mergeBlock;
+ };
+
+ // Make a switch statement. A switch has 'numSegments' of pieces of code, not containing
+ // any case/default labels, all separated by one or more case/default labels. Each possible
+ // case value v is a jump to the caseValues[v] segment. The defaultSegment is also in this
+ // number space. How to compute the value is given by 'condition', as in switch(condition).
+ //
+ // The SPIR-V Builder will maintain the stack of post-switch merge blocks for nested switches.
+ //
+ // Use a defaultSegment < 0 if there is no default segment (to branch to post switch).
+ //
+ // Returns the right set of basic blocks to start each code segment with, so that the caller's
+ // recursion stack can hold the memory for it.
+ //
+ void makeSwitch(Id condition, int numSegments, std::vector<int>& caseValues, std::vector<int>& valueToSegment, int defaultSegment,
+ std::vector<Block*>& segmentBB); // return argument
+
+ // Add a branch to the innermost switch's merge block.
+ void addSwitchBreak();
+
+ // Move to the next code segment, passing in the return argument in makeSwitch()
+ void nextSwitchSegment(std::vector<Block*>& segmentBB, int segment);
+
+ // Finish off the innermost switch.
+ void endSwitch(std::vector<Block*>& segmentBB);
+
+ // Start the beginning of a new loop.
+ void makeNewLoop();
+
+ // Add the branch for the loop test, based on the given condition.
+ // The true branch goes to the block that remains inside the loop, and
+ // the false branch goes to the loop's merge block. The builder insertion
+ // point will be placed at the start of the inside-the-loop block.
+ void createLoopTestBranch(Id condition);
+
+ // Finish generating the loop header block in the case where the loop test
+ // is at the bottom of the loop. It will include the LoopMerge instruction
+ // and a branch to the rest of the body. The loop header block must be
+ // separate from the rest of the body to make room for the the two kinds
+ // of *Merge instructions that might have to occur just before a branch:
+ // the loop header must have a LoopMerge as its second-last instruction,
+ // and the body might begin with a conditional branch, which must have its
+ // own SelectionMerge instruction.
+ // Also create the basic block that will contain the loop test, but don't
+ // insert it into the function yet. Any "continue" constructs in this loop
+ // will branch to the loop test block. The builder insertion point will be
+ // placed at the start of the body block.
+ void endLoopHeaderWithoutTest();
+
+ // Generate a branch to the loop test block. This can only be called if
+ // the loop test is at the bottom of the loop. The builder insertion point
+ // is left at the start of the test block.
+ void createBranchToLoopTest();
+
+ // Add a branch to the test of the current (innermost) loop.
+ void createLoopContinue();
+
+ // Add an exit (e.g. "break") for the innermost loop that you're in
+ void createLoopExit();
+
+ // Close the innermost loop that you're in
+ void closeLoop();
+
+ //
+ // Access chain design for an R-Value vs. L-Value:
+ //
+ // There is a single access chain the builder is building at
+ // any particular time. Such a chain can be used to either to a load or
+ // a store, when desired.
+ //
+ // Expressions can be r-values, l-values, or both, or only r-values:
+ // a[b.c].d = .... // l-value
+ // ... = a[b.c].d; // r-value, that also looks like an l-value
+ // ++a[b.c].d; // r-value and l-value
+ // (x + y)[2]; // r-value only, can't possibly be l-value
+ //
+ // Computing an r-value means generating code. Hence,
+ // r-values should only be computed when they are needed, not speculatively.
+ //
+ // Computing an l-value means saving away information for later use in the compiler,
+ // no code is generated until the l-value is later dereferenced. It is okay
+ // to speculatively generate an l-value, just not okay to speculatively dereference it.
+ //
+ // The base of the access chain (the left-most variable or expression
+ // from which everything is based) can be set either as an l-value
+ // or as an r-value. Most efficient would be to set an l-value if one
+ // is available. If an expression was evaluated, the resulting r-value
+ // can be set as the chain base.
+ //
+ // The users of this single access chain can save and restore if they
+ // want to nest or manage multiple chains.
+ //
+
+ struct AccessChain {
+ Id base; // for l-values, pointer to the base object, for r-values, the base object
+ std::vector<Id> indexChain;
+ Id instr; // the instruction that generates this access chain
+ std::vector<unsigned> swizzle;
+ Id component; // a dynamic component index, can coexist with a swizzle, done after the swizzle
+ Id resultType; // dereferenced type, to be exclusive of swizzles
+ bool isRValue;
+ };
+
+ //
+ // the SPIR-V builder maintains a single active chain that
+ // the following methods operated on
+ //
+
+ // for external save and restore
+ AccessChain getAccessChain() { return accessChain; }
+ void setAccessChain(AccessChain newChain) { accessChain = newChain; }
+
+ // clear accessChain
+ void clearAccessChain();
+
+ // set new base as an l-value base
+ void setAccessChainLValue(Id lValue)
+ {
+ assert(isPointer(lValue));
+ accessChain.base = lValue;
+ accessChain.resultType = getContainedTypeId(getTypeId(lValue));
+ }
+
+ // set new base value as an r-value
+ void setAccessChainRValue(Id rValue)
+ {
+ accessChain.isRValue = true;
+ accessChain.base = rValue;
+ accessChain.resultType = getTypeId(rValue);
+ }
+
+ // push offset onto the end of the chain
+ void accessChainPush(Id offset, Id newType)
+ {
+ accessChain.indexChain.push_back(offset);
+ accessChain.resultType = newType;
+ }
+
+ // push new swizzle onto the end of any existing swizzle, merging into a single swizzle
+ void accessChainPushSwizzle(std::vector<unsigned>& swizzle);
+
+ // push a variable component selection onto the access chain; supporting only one, so unsided
+ void accessChainPushComponent(Id component) { accessChain.component = component; }
+
+ // use accessChain and swizzle to store value
+ void accessChainStore(Id rvalue);
+
+ // use accessChain and swizzle to load an r-value
+ Id accessChainLoad(Decoration precision);
+
+ // get the direct pointer for an l-value
+ Id accessChainGetLValue();
+
+ void dump(std::vector<unsigned int>&) const;
+
+protected:
+ Id findScalarConstant(Op typeClass, Id typeId, unsigned value) const;
+ Id findScalarConstant(Op typeClass, Id typeId, unsigned v1, unsigned v2) const;
+ Id findCompositeConstant(Op typeClass, std::vector<Id>& comps) const;
+ Id collapseAccessChain();
+ void simplifyAccessChainSwizzle();
+ void mergeAccessChainSwizzle();
+ void createAndSetNoPredecessorBlock(const char*);
+ void createBranch(Block* block);
+ void createMerge(Op, Block*, unsigned int control);
+ void createConditionalBranch(Id condition, Block* thenBlock, Block* elseBlock);
+ void dumpInstructions(std::vector<unsigned int>&, const std::vector<Instruction*>&) const;
+
+ SourceLanguage source;
+ int sourceVersion;
+ std::vector<const char*> extensions;
+ AddressingModel addressModel;
+ MemoryModel memoryModel;
+ int builderNumber;
+ Module module;
+ Block* buildPoint;
+ Id uniqueId;
+ Function* mainFunction;
+ Block* stageExit;
+ AccessChain accessChain;
+
+ // special blocks of instructions for output
+ std::vector<Instruction*> imports;
+ std::vector<Instruction*> entryPoints;
+ std::vector<Instruction*> executionModes;
+ std::vector<Instruction*> names;
+ std::vector<Instruction*> lines;
+ std::vector<Instruction*> decorations;
+ std::vector<Instruction*> constantsTypesGlobals;
+ std::vector<Instruction*> externals;
+
+ // not output, internally used for quick & dirty canonical (unique) creation
+ std::vector<Instruction*> groupedConstants[OpConstant]; // all types appear before OpConstant
+ std::vector<Instruction*> groupedTypes[OpConstant];
+
+ // stack of switches
+ std::stack<Block*> switchMerges;
+
+ // Data that needs to be kept in order to properly handle loops.
+ struct Loop {
+ // The header is the first block generated for the loop.
+ // It dominates all the blocks in the loop, i.e. it is always
+ // executed before any others.
+ // If the loop test is executed before the body (as in "while" and
+ // "for" loops), then the header begins with the test code.
+ // Otherwise, the loop is a "do-while" loop and the header contains the
+ // start of the body of the loop (if the body exists).
+ Block* header;
+ // The merge block marks the end of the loop. Control is transferred
+ // to the merge block when either the loop test fails, or when a
+ // nested "break" is encountered.
+ Block* merge;
+ // If not NULL, the test block is the basic block containing the loop
+ // test and the conditional branch back to the header or the merge
+ // block. This is created for "do-while" loops, and is the target of
+ // any "continue" constructs that might exist.
+ Block* test;
+ Function* function;
+ };
+
+ // Our loop stack.
+ std::stack<Loop> loops;
+}; // end Builder class
+
+void MissingFunctionality(const char*);
+void ValidationError(const char* error);
+
+}; // end spv namespace
+
+#endif // SpvBuilder_H
-//\r
-//Copyright (C) 2014 LunarG, Inc.\r
-//\r
-//All rights reserved.\r
-//\r
-//Redistribution and use in source and binary forms, with or without\r
-//modification, are permitted provided that the following conditions\r
-//are met:\r
-//\r
-// Redistributions of source code must retain the above copyright\r
-// notice, this list of conditions and the following disclaimer.\r
-//\r
-// Redistributions in binary form must reproduce the above\r
-// copyright notice, this list of conditions and the following\r
-// disclaimer in the documentation and/or other materials provided\r
-// with the distribution.\r
-//\r
-// Neither the name of 3Dlabs Inc. Ltd. nor the names of its\r
-// contributors may be used to endorse or promote products derived\r
-// from this software without specific prior written permission.\r
-//\r
-//THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\r
-//"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\r
-//LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTAstreamITY AND FITNESS\r
-//FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE\r
-//COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,\r
-//INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,\r
-//BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\r
-//LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER\r
-//CAUSED AND ON ANY THEORY OF LIAstreamITY, WHETHER IN CONTRACT, STRICT\r
-//LIAstreamITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN\r
-//ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE\r
-//POSSIstreamITY OF SUCH DAMAGE.\r
-\r
-//\r
-// Author: John Kessenich, LunarG\r
-//\r
-\r
-//\r
-// Disassembler for SPIR-V.\r
-//\r
-\r
-#include <stdlib.h>\r
-#include <assert.h>\r
-#include <iomanip>\r
-#include <stack>\r
-#include <sstream>\r
-\r
-#include "GLSL450Lib.h"\r
-extern const char* GlslStd450DebugNames[GLSL_STD_450::Count];\r
-\r
-#include "disassemble.h"\r
-#include "doc.h"\r
-\r
-namespace spv {\r
-\r
-void Kill(std::ostream& out, const char* message)\r
-{\r
- out << std::endl << "Disassembly failed: " << message << std::endl;\r
- exit(1);\r
-}\r
-\r
-// Container class for a single instance of a SPIR-V stream, with methods for disassembly.\r
-class SpirvStream {\r
-public:\r
- SpirvStream(std::ostream& out, const std::vector<unsigned int>& stream) : out(out), stream(stream), word(0), nextNestedControl(0) { }\r
- virtual ~SpirvStream() { }\r
-\r
- void validate();\r
- void processInstructions();\r
-\r
-protected:\r
- SpirvStream(SpirvStream&);\r
- SpirvStream& operator=(SpirvStream&);\r
-\r
- Op getOpCode(int id) const { return idInstruction[id] ? (Op)(stream[idInstruction[id]] & OpCodeMask) : OpNop; }\r
-\r
- // Output methods\r
- void outputIndent();\r
- void formatId(Id id, std::stringstream&);\r
- void outputResultId(Id id);\r
- void outputTypeId(Id id);\r
- void outputId(Id id);\r
- void disassembleImmediates(int numOperands);\r
- void disassembleIds(int numOperands);\r
- void disassembleString();\r
- void disassembleInstruction(Id resultId, Id typeId, Op opCode, int numOperands);\r
-\r
- // Data\r
- std::ostream& out; // where to write the disassembly\r
- const std::vector<unsigned int>& stream; // the actual word stream\r
- int size; // the size of the word stream\r
- int word; // the next word of the stream to read\r
-\r
- // map each <id> to the instruction that created it\r
- Id bound;\r
- std::vector<unsigned int> idInstruction; // the word offset into the stream where the instruction for result [id] starts; 0 if not yet seen (forward reference or function parameter)\r
-\r
- std::vector<std::string> idDescriptor; // the best text string known for explaining the <id>\r
-\r
- // schema\r
- unsigned int schema;\r
-\r
- // stack of structured-merge points\r
- std::stack<Id> nestedControl;\r
- Id nextNestedControl; // need a slight delay for when we are nested\r
-};\r
-\r
-void SpirvStream::validate()\r
-{\r
- size = (int)stream.size();\r
- if (size < 4)\r
- Kill(out, "stream is too short");\r
-\r
- // Magic number\r
- if (stream[word++] != MagicNumber) {\r
- out << "Bad magic number";\r
- return;\r
- }\r
-\r
- // Version\r
- out << "// Module Version " << stream[word++] << std::endl;\r
-\r
- // Generator's magic number\r
- out << "// Generated by (magic number): " << std::setbase(16) << stream[word++] << std::setbase(10) << std::endl;\r
-\r
- // Result <id> bound\r
- bound = stream[word++];\r
- idInstruction.resize(bound);\r
- idDescriptor.resize(bound);\r
- out << "// Id's are bound by " << bound << std::endl;\r
- out << std::endl;\r
-\r
- // Reserved schema, must be 0 for now\r
- schema = stream[word++];\r
- if (schema != 0)\r
- Kill(out, "bad schema, must be 0");\r
-}\r
-\r
-// Loop over all the instructions, in order, processing each.\r
-// Boiler plate for each is handled here directly, the rest is dispatched.\r
-void SpirvStream::processInstructions()\r
-{\r
- // Instructions\r
- while (word < size) {\r
- int instructionStart = word;\r
-\r
- // Instruction wordCount and opcode\r
- unsigned int firstWord = stream[word];\r
- unsigned wordCount = firstWord >> WordCountShift;\r
- Op opCode = (Op)(firstWord & OpCodeMask);\r
- int nextInst = word + wordCount;\r
- ++word;\r
-\r
- // Presence of full instruction\r
- if (nextInst > size)\r
- Kill(out, "stream instruction terminated too early");\r
-\r
- // Base for computing number of operands; will be updated as more is learned\r
- unsigned numOperands = wordCount - 1;\r
-\r
- // Type <id>\r
- Id typeId = 0;\r
- if (InstructionDesc[opCode].hasType()) {\r
- typeId = stream[word++];\r
- --numOperands;\r
- }\r
-\r
- // Result <id>\r
- Id resultId = 0;\r
- if (InstructionDesc[opCode].hasResult()) {\r
- resultId = stream[word++];\r
- --numOperands;\r
-\r
- // save instruction for future reference\r
- idInstruction[resultId] = instructionStart;\r
- }\r
-\r
- outputResultId(resultId);\r
- outputTypeId(typeId);\r
- outputIndent();\r
-\r
- // Hand off the Op and all its operands\r
- disassembleInstruction(resultId, typeId, opCode, numOperands);\r
- if (word != nextInst) {\r
- out << " ERROR, incorrect number of operands consumed. At " << word << " instead of " << nextInst << " instruction start was " << instructionStart;\r
- word = nextInst;\r
- }\r
- out << std::endl;\r
- }\r
-}\r
-\r
-void SpirvStream::outputIndent()\r
-{\r
- for (int i = 0; i < (int)nestedControl.size(); ++i)\r
- out << " ";\r
-}\r
-\r
-void SpirvStream::formatId(Id id, std::stringstream& idStream)\r
-{\r
- if (id >= bound)\r
- Kill(out, "Bad <id>");\r
-\r
- if (id != 0) {\r
- idStream << id;\r
- if (idDescriptor[id].size() > 0)\r
- idStream << "(" << idDescriptor[id] << ")";\r
- }\r
-}\r
-\r
-void SpirvStream::outputResultId(Id id)\r
-{\r
- const int width = 16;\r
- std::stringstream idStream;\r
- formatId(id, idStream);\r
- out << std::setw(width) << std::right << idStream.str();\r
- if (id != 0)\r
- out << ":";\r
- else\r
- out << " ";\r
-\r
- if (nestedControl.size() && id == nestedControl.top())\r
- nestedControl.pop();\r
-}\r
-\r
-void SpirvStream::outputTypeId(Id id)\r
-{\r
- const int width = 12;\r
- std::stringstream idStream;\r
- formatId(id, idStream);\r
- out << std::setw(width) << std::right << idStream.str() << " ";\r
-}\r
-\r
-void SpirvStream::outputId(Id id)\r
-{\r
- if (id >= bound)\r
- Kill(out, "Bad <id>");\r
-\r
- out << id;\r
- if (idDescriptor[id].size() > 0)\r
- out << "(" << idDescriptor[id] << ")";\r
-}\r
-\r
-void SpirvStream::disassembleImmediates(int numOperands)\r
-{\r
- for (int i = 0; i < numOperands; ++i) {\r
- out << stream[word++];\r
- if (i < numOperands - 1)\r
- out << " ";\r
- }\r
-}\r
-\r
-void SpirvStream::disassembleIds(int numOperands)\r
-{\r
- for (int i = 0; i < numOperands; ++i) {\r
- outputId(stream[word++]);\r
- if (i < numOperands - 1)\r
- out << " ";\r
- }\r
-}\r
-\r
-void SpirvStream::disassembleString()\r
-{\r
- out << " \"";\r
-\r
- char* wordString;\r
- bool done = false;\r
- do {\r
- unsigned int content = stream[word];\r
- wordString = (char*)&content;\r
- for (int charCount = 0; charCount < 4; ++charCount) {\r
- if (*wordString == 0) {\r
- done = true;\r
- break;\r
- }\r
- out << *(wordString++);\r
- }\r
- ++word;\r
- } while (! done);\r
-\r
- out << "\"";\r
-}\r
-\r
-void SpirvStream::disassembleInstruction(Id resultId, Id /*typeId*/, Op opCode, int numOperands)\r
-{\r
- // Process the opcode\r
-\r
- out << (OpcodeString(opCode) + 2); // leave out the "Op"\r
-\r
- if (opCode == OpLoopMerge || opCode == OpSelectionMerge)\r
- nextNestedControl = stream[word];\r
- else if (opCode == OpBranchConditional || opCode == OpSwitch) {\r
- if (nextNestedControl) {\r
- nestedControl.push(nextNestedControl);\r
- nextNestedControl = 0;\r
- }\r
- } else if (opCode == OpExtInstImport)\r
- idDescriptor[resultId] = (char*)(&stream[word]);\r
- else {\r
- if (idDescriptor[resultId].size() == 0) {\r
- switch (opCode) {\r
- case OpTypeInt:\r
- idDescriptor[resultId] = "int";\r
- break;\r
- case OpTypeFloat:\r
- idDescriptor[resultId] = "float";\r
- break;\r
- case OpTypeBool:\r
- idDescriptor[resultId] = "bool";\r
- break;\r
- case OpTypeStruct:\r
- idDescriptor[resultId] = "struct";\r
- break;\r
- case OpTypePointer:\r
- idDescriptor[resultId] = "ptr";\r
- break;\r
- case OpTypeVector:\r
- if (idDescriptor[stream[word]].size() > 0)\r
- idDescriptor[resultId].append(idDescriptor[stream[word]].begin(), idDescriptor[stream[word]].begin() + 1);\r
- idDescriptor[resultId].append("vec");\r
- switch (stream[word + 1]) {\r
- case 2: idDescriptor[resultId].append("2"); break;\r
- case 3: idDescriptor[resultId].append("3"); break;\r
- case 4: idDescriptor[resultId].append("4"); break;\r
- case 8: idDescriptor[resultId].append("8"); break;\r
- case 16: idDescriptor[resultId].append("16"); break;\r
- case 32: idDescriptor[resultId].append("32"); break;\r
- default: break;\r
- }\r
- break;\r
- default:\r
- break;\r
- }\r
- }\r
- }\r
-\r
- // Process the operands. Note, a new context-dependent set could be\r
- // swapped in mid-traversal.\r
-\r
- // Handle textures specially, so can put out helpful strings.\r
- if (opCode == OpTypeSampler) {\r
- disassembleIds(1);\r
- out << " " << DimensionString((Dim)stream[word++]);\r
- switch (stream[word++]) {\r
- case 0: out << " texture"; break;\r
- case 1: out << " image"; break;\r
- case 2: out << " filter+texture"; break;\r
- }\r
- out << (stream[word++] != 0 ? " array" : "");\r
- out << (stream[word++] != 0 ? " depth" : "");\r
- out << (stream[word++] != 0 ? " multi-sampled" : "");\r
- return;\r
- }\r
-\r
- // Handle all the parameterized operands\r
- for (int op = 0; op < InstructionDesc[opCode].operands.getNum(); ++op) {\r
- out << " ";\r
- OperandClass operandClass = InstructionDesc[opCode].operands.getClass(op);\r
- switch (operandClass) {\r
- case OperandId:\r
- disassembleIds(1);\r
- // Get names for printing "(XXX)" for readability, *after* this id\r
- if (opCode == OpName)\r
- idDescriptor[stream[word - 1]] = (char*)(&stream[word]);\r
- break;\r
- case OperandOptionalId:\r
- case OperandVariableIds:\r
- disassembleIds(numOperands);\r
- return;\r
- case OperandVariableLiterals:\r
- if ((opCode == OpDecorate && stream[word - 1] == DecorationBuiltIn) ||\r
- (opCode == OpMemberDecorate && stream[word - 1] == DecorationBuiltIn)) {\r
- out << BuiltInString(stream[word++]);\r
- --numOperands;\r
- ++op;\r
- }\r
- disassembleImmediates(numOperands);\r
- return;\r
- case OperandVariableLiteralId:\r
- while (numOperands > 0) {\r
- out << std::endl;\r
- outputResultId(0);\r
- outputTypeId(0);\r
- outputIndent();\r
- out << " case ";\r
- disassembleImmediates(1);\r
- out << ": ";\r
- disassembleIds(1);\r
- numOperands -= 2;\r
- }\r
- return;\r
- case OperandLiteralNumber:\r
- disassembleImmediates(1);\r
- if (opCode == OpExtInst) {\r
- unsigned entrypoint = stream[word - 1];\r
- if (entrypoint < GLSL_STD_450::Count)\r
- out << "(" << GlslStd450DebugNames[entrypoint] << ")";\r
- }\r
- break;\r
- case OperandLiteralString:\r
- disassembleString();\r
- return;\r
- default:\r
- assert(operandClass >= OperandSource && operandClass < OperandOpcode);\r
-\r
- if (OperandClassParams[operandClass].bitmask) {\r
- unsigned int mask = stream[word++];\r
- if (mask == 0)\r
- out << "None";\r
- else {\r
- for (int m = 0; m < OperandClassParams[operandClass].ceiling; ++m) {\r
- if (mask & (1 << m))\r
- out << OperandClassParams[operandClass].getName(m) << " ";\r
- }\r
- }\r
- break;\r
- } else\r
- out << OperandClassParams[operandClass].getName(stream[word++]);\r
-\r
- break;\r
- }\r
- --numOperands;\r
- }\r
-\r
- return;\r
-}\r
-\r
-void Disassemble(std::ostream& out, const std::vector<unsigned int>& stream)\r
-{\r
- SpirvStream SpirvStream(out, stream);\r
- SpirvStream.validate();\r
- SpirvStream.processInstructions();\r
-}\r
-\r
-}; // end namespace spv\r
+//
+//Copyright (C) 2014 LunarG, Inc.
+//
+//All rights reserved.
+//
+//Redistribution and use in source and binary forms, with or without
+//modification, are permitted provided that the following conditions
+//are met:
+//
+// Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//
+// Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following
+// disclaimer in the documentation and/or other materials provided
+// with the distribution.
+//
+// Neither the name of 3Dlabs Inc. Ltd. nor the names of its
+// contributors may be used to endorse or promote products derived
+// from this software without specific prior written permission.
+//
+//THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+//"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+//LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTAstreamITY AND FITNESS
+//FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+//COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+//INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+//BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+//LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+//CAUSED AND ON ANY THEORY OF LIAstreamITY, WHETHER IN CONTRACT, STRICT
+//LIAstreamITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+//ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+//POSSIstreamITY OF SUCH DAMAGE.
+
+//
+// Author: John Kessenich, LunarG
+//
+
+//
+// Disassembler for SPIR-V.
+//
+
+#include <stdlib.h>
+#include <assert.h>
+#include <iomanip>
+#include <stack>
+#include <sstream>
+
+#include "GLSL450Lib.h"
+extern const char* GlslStd450DebugNames[GLSL_STD_450::Count];
+
+#include "disassemble.h"
+#include "doc.h"
+
+namespace spv {
+
+void Kill(std::ostream& out, const char* message)
+{
+ out << std::endl << "Disassembly failed: " << message << std::endl;
+ exit(1);
+}
+
+// Container class for a single instance of a SPIR-V stream, with methods for disassembly.
+class SpirvStream {
+public:
+ SpirvStream(std::ostream& out, const std::vector<unsigned int>& stream) : out(out), stream(stream), word(0), nextNestedControl(0) { }
+ virtual ~SpirvStream() { }
+
+ void validate();
+ void processInstructions();
+
+protected:
+ SpirvStream(SpirvStream&);
+ SpirvStream& operator=(SpirvStream&);
+
+ Op getOpCode(int id) const { return idInstruction[id] ? (Op)(stream[idInstruction[id]] & OpCodeMask) : OpNop; }
+
+ // Output methods
+ void outputIndent();
+ void formatId(Id id, std::stringstream&);
+ void outputResultId(Id id);
+ void outputTypeId(Id id);
+ void outputId(Id id);
+ void disassembleImmediates(int numOperands);
+ void disassembleIds(int numOperands);
+ void disassembleString();
+ void disassembleInstruction(Id resultId, Id typeId, Op opCode, int numOperands);
+
+ // Data
+ std::ostream& out; // where to write the disassembly
+ const std::vector<unsigned int>& stream; // the actual word stream
+ int size; // the size of the word stream
+ int word; // the next word of the stream to read
+
+ // map each <id> to the instruction that created it
+ Id bound;
+ std::vector<unsigned int> idInstruction; // the word offset into the stream where the instruction for result [id] starts; 0 if not yet seen (forward reference or function parameter)
+
+ std::vector<std::string> idDescriptor; // the best text string known for explaining the <id>
+
+ // schema
+ unsigned int schema;
+
+ // stack of structured-merge points
+ std::stack<Id> nestedControl;
+ Id nextNestedControl; // need a slight delay for when we are nested
+};
+
+void SpirvStream::validate()
+{
+ size = (int)stream.size();
+ if (size < 4)
+ Kill(out, "stream is too short");
+
+ // Magic number
+ if (stream[word++] != MagicNumber) {
+ out << "Bad magic number";
+ return;
+ }
+
+ // Version
+ out << "// Module Version " << stream[word++] << std::endl;
+
+ // Generator's magic number
+ out << "// Generated by (magic number): " << std::setbase(16) << stream[word++] << std::setbase(10) << std::endl;
+
+ // Result <id> bound
+ bound = stream[word++];
+ idInstruction.resize(bound);
+ idDescriptor.resize(bound);
+ out << "// Id's are bound by " << bound << std::endl;
+ out << std::endl;
+
+ // Reserved schema, must be 0 for now
+ schema = stream[word++];
+ if (schema != 0)
+ Kill(out, "bad schema, must be 0");
+}
+
+// Loop over all the instructions, in order, processing each.
+// Boiler plate for each is handled here directly, the rest is dispatched.
+void SpirvStream::processInstructions()
+{
+ // Instructions
+ while (word < size) {
+ int instructionStart = word;
+
+ // Instruction wordCount and opcode
+ unsigned int firstWord = stream[word];
+ unsigned wordCount = firstWord >> WordCountShift;
+ Op opCode = (Op)(firstWord & OpCodeMask);
+ int nextInst = word + wordCount;
+ ++word;
+
+ // Presence of full instruction
+ if (nextInst > size)
+ Kill(out, "stream instruction terminated too early");
+
+ // Base for computing number of operands; will be updated as more is learned
+ unsigned numOperands = wordCount - 1;
+
+ // Type <id>
+ Id typeId = 0;
+ if (InstructionDesc[opCode].hasType()) {
+ typeId = stream[word++];
+ --numOperands;
+ }
+
+ // Result <id>
+ Id resultId = 0;
+ if (InstructionDesc[opCode].hasResult()) {
+ resultId = stream[word++];
+ --numOperands;
+
+ // save instruction for future reference
+ idInstruction[resultId] = instructionStart;
+ }
+
+ outputResultId(resultId);
+ outputTypeId(typeId);
+ outputIndent();
+
+ // Hand off the Op and all its operands
+ disassembleInstruction(resultId, typeId, opCode, numOperands);
+ if (word != nextInst) {
+ out << " ERROR, incorrect number of operands consumed. At " << word << " instead of " << nextInst << " instruction start was " << instructionStart;
+ word = nextInst;
+ }
+ out << std::endl;
+ }
+}
+
+void SpirvStream::outputIndent()
+{
+ for (int i = 0; i < (int)nestedControl.size(); ++i)
+ out << " ";
+}
+
+void SpirvStream::formatId(Id id, std::stringstream& idStream)
+{
+ if (id >= bound)
+ Kill(out, "Bad <id>");
+
+ if (id != 0) {
+ idStream << id;
+ if (idDescriptor[id].size() > 0)
+ idStream << "(" << idDescriptor[id] << ")";
+ }
+}
+
+void SpirvStream::outputResultId(Id id)
+{
+ const int width = 16;
+ std::stringstream idStream;
+ formatId(id, idStream);
+ out << std::setw(width) << std::right << idStream.str();
+ if (id != 0)
+ out << ":";
+ else
+ out << " ";
+
+ if (nestedControl.size() && id == nestedControl.top())
+ nestedControl.pop();
+}
+
+void SpirvStream::outputTypeId(Id id)
+{
+ const int width = 12;
+ std::stringstream idStream;
+ formatId(id, idStream);
+ out << std::setw(width) << std::right << idStream.str() << " ";
+}
+
+void SpirvStream::outputId(Id id)
+{
+ if (id >= bound)
+ Kill(out, "Bad <id>");
+
+ out << id;
+ if (idDescriptor[id].size() > 0)
+ out << "(" << idDescriptor[id] << ")";
+}
+
+void SpirvStream::disassembleImmediates(int numOperands)
+{
+ for (int i = 0; i < numOperands; ++i) {
+ out << stream[word++];
+ if (i < numOperands - 1)
+ out << " ";
+ }
+}
+
+void SpirvStream::disassembleIds(int numOperands)
+{
+ for (int i = 0; i < numOperands; ++i) {
+ outputId(stream[word++]);
+ if (i < numOperands - 1)
+ out << " ";
+ }
+}
+
+void SpirvStream::disassembleString()
+{
+ out << " \"";
+
+ char* wordString;
+ bool done = false;
+ do {
+ unsigned int content = stream[word];
+ wordString = (char*)&content;
+ for (int charCount = 0; charCount < 4; ++charCount) {
+ if (*wordString == 0) {
+ done = true;
+ break;
+ }
+ out << *(wordString++);
+ }
+ ++word;
+ } while (! done);
+
+ out << "\"";
+}
+
+void SpirvStream::disassembleInstruction(Id resultId, Id /*typeId*/, Op opCode, int numOperands)
+{
+ // Process the opcode
+
+ out << (OpcodeString(opCode) + 2); // leave out the "Op"
+
+ if (opCode == OpLoopMerge || opCode == OpSelectionMerge)
+ nextNestedControl = stream[word];
+ else if (opCode == OpBranchConditional || opCode == OpSwitch) {
+ if (nextNestedControl) {
+ nestedControl.push(nextNestedControl);
+ nextNestedControl = 0;
+ }
+ } else if (opCode == OpExtInstImport)
+ idDescriptor[resultId] = (char*)(&stream[word]);
+ else {
+ if (idDescriptor[resultId].size() == 0) {
+ switch (opCode) {
+ case OpTypeInt:
+ idDescriptor[resultId] = "int";
+ break;
+ case OpTypeFloat:
+ idDescriptor[resultId] = "float";
+ break;
+ case OpTypeBool:
+ idDescriptor[resultId] = "bool";
+ break;
+ case OpTypeStruct:
+ idDescriptor[resultId] = "struct";
+ break;
+ case OpTypePointer:
+ idDescriptor[resultId] = "ptr";
+ break;
+ case OpTypeVector:
+ if (idDescriptor[stream[word]].size() > 0)
+ idDescriptor[resultId].append(idDescriptor[stream[word]].begin(), idDescriptor[stream[word]].begin() + 1);
+ idDescriptor[resultId].append("vec");
+ switch (stream[word + 1]) {
+ case 2: idDescriptor[resultId].append("2"); break;
+ case 3: idDescriptor[resultId].append("3"); break;
+ case 4: idDescriptor[resultId].append("4"); break;
+ case 8: idDescriptor[resultId].append("8"); break;
+ case 16: idDescriptor[resultId].append("16"); break;
+ case 32: idDescriptor[resultId].append("32"); break;
+ default: break;
+ }
+ break;
+ default:
+ break;
+ }
+ }
+ }
+
+ // Process the operands. Note, a new context-dependent set could be
+ // swapped in mid-traversal.
+
+ // Handle textures specially, so can put out helpful strings.
+ if (opCode == OpTypeSampler) {
+ disassembleIds(1);
+ out << " " << DimensionString((Dim)stream[word++]);
+ switch (stream[word++]) {
+ case 0: out << " texture"; break;
+ case 1: out << " image"; break;
+ case 2: out << " filter+texture"; break;
+ }
+ out << (stream[word++] != 0 ? " array" : "");
+ out << (stream[word++] != 0 ? " depth" : "");
+ out << (stream[word++] != 0 ? " multi-sampled" : "");
+ return;
+ }
+
+ // Handle all the parameterized operands
+ for (int op = 0; op < InstructionDesc[opCode].operands.getNum(); ++op) {
+ out << " ";
+ OperandClass operandClass = InstructionDesc[opCode].operands.getClass(op);
+ switch (operandClass) {
+ case OperandId:
+ disassembleIds(1);
+ // Get names for printing "(XXX)" for readability, *after* this id
+ if (opCode == OpName)
+ idDescriptor[stream[word - 1]] = (char*)(&stream[word]);
+ break;
+ case OperandOptionalId:
+ case OperandVariableIds:
+ disassembleIds(numOperands);
+ return;
+ case OperandVariableLiterals:
+ if ((opCode == OpDecorate && stream[word - 1] == DecorationBuiltIn) ||
+ (opCode == OpMemberDecorate && stream[word - 1] == DecorationBuiltIn)) {
+ out << BuiltInString(stream[word++]);
+ --numOperands;
+ ++op;
+ }
+ disassembleImmediates(numOperands);
+ return;
+ case OperandVariableLiteralId:
+ while (numOperands > 0) {
+ out << std::endl;
+ outputResultId(0);
+ outputTypeId(0);
+ outputIndent();
+ out << " case ";
+ disassembleImmediates(1);
+ out << ": ";
+ disassembleIds(1);
+ numOperands -= 2;
+ }
+ return;
+ case OperandLiteralNumber:
+ disassembleImmediates(1);
+ if (opCode == OpExtInst) {
+ unsigned entrypoint = stream[word - 1];
+ if (entrypoint < GLSL_STD_450::Count)
+ out << "(" << GlslStd450DebugNames[entrypoint] << ")";
+ }
+ break;
+ case OperandLiteralString:
+ disassembleString();
+ return;
+ default:
+ assert(operandClass >= OperandSource && operandClass < OperandOpcode);
+
+ if (OperandClassParams[operandClass].bitmask) {
+ unsigned int mask = stream[word++];
+ if (mask == 0)
+ out << "None";
+ else {
+ for (int m = 0; m < OperandClassParams[operandClass].ceiling; ++m) {
+ if (mask & (1 << m))
+ out << OperandClassParams[operandClass].getName(m) << " ";
+ }
+ }
+ break;
+ } else
+ out << OperandClassParams[operandClass].getName(stream[word++]);
+
+ break;
+ }
+ --numOperands;
+ }
+
+ return;
+}
+
+void Disassemble(std::ostream& out, const std::vector<unsigned int>& stream)
+{
+ SpirvStream SpirvStream(out, stream);
+ SpirvStream.validate();
+ SpirvStream.processInstructions();
+}
+
+}; // end namespace spv
-//\r
-//Copyright (C) 2014 LunarG, Inc.\r
-//\r
-//All rights reserved.\r
-//\r
-//Redistribution and use in source and binary forms, with or without\r
-//modification, are permitted provided that the following conditions\r
-//are met:\r
-//\r
-// Redistributions of source code must retain the above copyright\r
-// notice, this list of conditions and the following disclaimer.\r
-//\r
-// Redistributions in binary form must reproduce the above\r
-// copyright notice, this list of conditions and the following\r
-// disclaimer in the documentation and/or other materials provided\r
-// with the distribution.\r
-//\r
-// Neither the name of 3Dlabs Inc. Ltd. nor the names of its\r
-// contributors may be used to endorse or promote products derived\r
-// from this software without specific prior written permission.\r
-//\r
-//THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\r
-//"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\r
-//LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS\r
-//FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE\r
-//COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,\r
-//INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,\r
-//BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\r
-//LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER\r
-//CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\r
-//LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN\r
-//ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE\r
-//POSSIBILITY OF SUCH DAMAGE.\r
-\r
-//\r
-// Author: John Kessenich, LunarG\r
-//\r
-\r
-//\r
-// Disassembler for SPIR-V.\r
-//\r
-\r
-#pragma once\r
-#ifndef disassembler_H\r
-#define disassembler_H\r
-\r
-#include <iostream>\r
-#include <vector>\r
-\r
-namespace spv {\r
-\r
- void Disassemble(std::ostream& out, const std::vector<unsigned int>&);\r
-\r
-}; // end namespace spv\r
-\r
-#endif // disassembler_H\r
+//
+//Copyright (C) 2014 LunarG, Inc.
+//
+//All rights reserved.
+//
+//Redistribution and use in source and binary forms, with or without
+//modification, are permitted provided that the following conditions
+//are met:
+//
+// Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//
+// Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following
+// disclaimer in the documentation and/or other materials provided
+// with the distribution.
+//
+// Neither the name of 3Dlabs Inc. Ltd. nor the names of its
+// contributors may be used to endorse or promote products derived
+// from this software without specific prior written permission.
+//
+//THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+//"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+//LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+//FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+//COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+//INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+//BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+//LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+//CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+//LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+//ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+//POSSIBILITY OF SUCH DAMAGE.
+
+//
+// Author: John Kessenich, LunarG
+//
+
+//
+// Disassembler for SPIR-V.
+//
+
+#pragma once
+#ifndef disassembler_H
+#define disassembler_H
+
+#include <iostream>
+#include <vector>
+
+namespace spv {
+
+ void Disassemble(std::ostream& out, const std::vector<unsigned int>&);
+
+}; // end namespace spv
+
+#endif // disassembler_H
-//\r
-//Copyright (C) 2014 LunarG, Inc.\r
-//\r
-//All rights reserved.\r
-//\r
-//Redistribution and use in source and binary forms, with or without\r
-//modification, are permitted provided that the following conditions\r
-//are met:\r
-//\r
-// Redistributions of source code must retain the above copyright\r
-// notice, this list of conditions and the following disclaimer.\r
-//\r
-// Redistributions in binary form must reproduce the above\r
-// copyright notice, this list of conditions and the following\r
-// disclaimer in the documentation and/or other materials provided\r
-// with the distribution.\r
-//\r
-// Neither the name of 3Dlabs Inc. Ltd. nor the names of its\r
-// contributors may be used to endorse or promote products derived\r
-// from this software without specific prior written permission.\r
-//\r
-//THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\r
-//"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\r
-//LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS\r
-//FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE\r
-//COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,\r
-//INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,\r
-//BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\r
-//LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER\r
-//CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\r
-//LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN\r
-//ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE\r
-//POSSIBILITY OF SUCH DAMAGE.\r
-\r
-//\r
-// Author: John Kessenich, LunarG\r
-//\r
-\r
-//\r
-// 1) Programatically fill in instruction/operand information.\r
-// This can be used for disassembly, printing documentation, etc.\r
-//\r
-// 2) Print documentation from this parameterization.\r
-//\r
-\r
-#include "doc.h"\r
-\r
-#include <stdio.h>\r
-#include <string.h>\r
-#include <algorithm>\r
-\r
-namespace spv {\r
-\r
-//\r
-// Whole set of functions that translate enumerants to their text strings for\r
-// the specification (or their sanitized versions for auto-generating the\r
-// spirv.h header.\r
-//\r
-// Also, the ceilings are declared next to these, to help keep them in sync.\r
-// Ceilings should be\r
-// - one more than the maximum value an enumerant takes on, for non-mask enumerants\r
-// (for non-sparse enums, this is the number of enumurants)\r
-// - the number of bits consumed by the set of masks\r
-// (for non-sparse mask enums, this is the number of enumurants)\r
-//\r
-\r
-const int SourceLanguageCeiling = 4;\r
-\r
-const char* SourceString(int source)\r
-{\r
- switch (source) {\r
- case 0: return "Unknown";\r
- case 1: return "ESSL";\r
- case 2: return "GLSL";\r
- case 3: return "OpenCL";\r
-\r
- case SourceLanguageCeiling:\r
- default: return "Bad";\r
- }\r
-}\r
-\r
-const int ExecutionModelCeiling = 7;\r
-\r
-const char* ExecutionModelString(int model)\r
-{\r
- switch (model) {\r
- case 0: return "Vertex";\r
- case 1: return "TessellationControl";\r
- case 2: return "TessellationEvaluation";\r
- case 3: return "Geometry";\r
- case 4: return "Fragment";\r
- case 5: return "GLCompute";\r
- case 6: return "Kernel";\r
-\r
- case ExecutionModelCeiling:\r
- default: return "Bad";\r
- }\r
-}\r
-\r
-const int AddressingModelCeiling = 3;\r
-\r
-const char* AddressingString(int addr)\r
-{\r
- switch (addr) {\r
- case 0: return "Logical";\r
- case 1: return "Physical32";\r
- case 2: return "Physical64";\r
-\r
- case AddressingModelCeiling:\r
- default: return "Bad";\r
- }\r
-}\r
-\r
-const int MemoryModelCeiling = 5;\r
-\r
-const char* MemoryString(int mem)\r
-{\r
- switch (mem) {\r
- case 0: return "Simple";\r
- case 1: return "GLSL450";\r
- case 2: return "OpenCL1.2";\r
- case 3: return "OpenCL2.0";\r
- case 4: return "OpenCL2.1";\r
-\r
- case MemoryModelCeiling:\r
- default: return "Bad";\r
- }\r
-}\r
-\r
-const int ExecutionModeCeiling = 31;\r
-\r
-const char* ExecutionModeString(int mode)\r
-{\r
- switch (mode) {\r
- case 0: return "Invocations";\r
- case 1: return "SpacingEqual";\r
- case 2: return "SpacingFractionalEven";\r
- case 3: return "SpacingFractionalOdd";\r
- case 4: return "VertexOrderCw";\r
- case 5: return "VertexOrderCcw";\r
- case 6: return "PixelCenterInteger";\r
- case 7: return "OriginUpperLeft";\r
- case 8: return "EarlyFragmentTests";\r
- case 9: return "PointMode";\r
- case 10: return "Xfb";\r
- case 11: return "DepthReplacing";\r
- case 12: return "DepthAny";\r
- case 13: return "DepthGreater";\r
- case 14: return "DepthLess";\r
- case 15: return "DepthUnchanged";\r
- case 16: return "LocalSize";\r
- case 17: return "LocalSizeHint";\r
- case 18: return "InputPoints";\r
- case 19: return "InputLines";\r
- case 20: return "InputLinesAdjacency";\r
- case 21: return "InputTriangles";\r
- case 22: return "InputTrianglesAdjacency";\r
- case 23: return "InputQuads";\r
- case 24: return "InputIsolines";\r
- case 25: return "OutputVertices";\r
- case 26: return "OutputPoints";\r
- case 27: return "OutputLineStrip";\r
- case 28: return "OutputTriangleStrip";\r
- case 29: return "VecTypeHint";\r
- case 30: return "ContractionOff";\r
-\r
- case ExecutionModeCeiling:\r
- default: return "Bad";\r
- }\r
-}\r
-\r
-const int StorageClassCeiling = 11;\r
-\r
-const char* StorageClassString(int StorageClass)\r
-{\r
- switch (StorageClass) {\r
- case 0: return "UniformConstant";\r
- case 1: return "Input";\r
- case 2: return "Uniform";\r
- case 3: return "Output";\r
- case 4: return "WorkgroupLocal";\r
- case 5: return "WorkgroupGlobal";\r
- case 6: return "PrivateGlobal";\r
- case 7: return "Function";\r
- case 8: return "Generic";\r
- case 9: return "Private";\r
- case 10: return "AtomicCounter";\r
-\r
- case StorageClassCeiling:\r
- default: return "Bad";\r
- }\r
-}\r
-\r
-const int DecorationCeiling = 45;\r
-\r
-const char* DecorationString(int decoration)\r
-{\r
- switch (decoration) {\r
- case 0: return "PrecisionLow";\r
- case 1: return "PrecisionMedium";\r
- case 2: return "PrecisionHigh";\r
- case 3: return "Block";\r
- case 4: return "BufferBlock";\r
- case 5: return "RowMajor";\r
- case 6: return "ColMajor";\r
- case 7: return "GLSLShared";\r
- case 8: return "GLSLStd140";\r
- case 9: return "GLSLStd430";\r
- case 10: return "GLSLPacked";\r
- case 11: return "Smooth";\r
- case 12: return "Noperspective";\r
- case 13: return "Flat";\r
- case 14: return "Patch";\r
- case 15: return "Centroid";\r
- case 16: return "Sample";\r
- case 17: return "Invariant";\r
- case 18: return "Restrict";\r
- case 19: return "Aliased";\r
- case 20: return "Volatile";\r
- case 21: return "Constant";\r
- case 22: return "Coherent";\r
- case 23: return "Nonwritable";\r
- case 24: return "Nonreadable";\r
- case 25: return "Uniform";\r
- case 26: return "NoStaticUse";\r
- case 27: return "CPacked";\r
- case 28: return "SaturatedConversion";\r
- case 29: return "Stream";\r
- case 30: return "Location";\r
- case 31: return "Component";\r
- case 32: return "Index";\r
- case 33: return "Binding";\r
- case 34: return "DescriptorSet";\r
- case 35: return "Offset";\r
- case 36: return "Alignment";\r
- case 37: return "XfbBuffer";\r
- case 38: return "Stride";\r
- case 39: return "BuiltIn";\r
- case 40: return "FuncParamAttr";\r
- case 41: return "FP Rounding Mode";\r
- case 42: return "FP Fast Math Mode";\r
- case 43: return "Linkage Attributes";\r
- case 44: return "SpecId";\r
-\r
- case DecorationCeiling:\r
- default: return "Bad";\r
- }\r
-}\r
-\r
-const int BuiltInCeiling = 42;\r
-\r
-const char* BuiltInString(int builtIn)\r
-{\r
- switch (builtIn) {\r
- case 0: return "Position";\r
- case 1: return "PointSize";\r
- case 2: return "ClipVertex";\r
- case 3: return "ClipDistance";\r
- case 4: return "CullDistance";\r
- case 5: return "VertexId";\r
- case 6: return "InstanceId";\r
- case 7: return "PrimitiveId";\r
- case 8: return "InvocationId";\r
- case 9: return "Layer";\r
- case 10: return "ViewportIndex";\r
- case 11: return "TessLevelOuter";\r
- case 12: return "TessLevelInner";\r
- case 13: return "TessCoord";\r
- case 14: return "PatchVertices";\r
- case 15: return "FragCoord";\r
- case 16: return "PointCoord";\r
- case 17: return "FrontFacing";\r
- case 18: return "SampleId";\r
- case 19: return "SamplePosition";\r
- case 20: return "SampleMask";\r
- case 21: return "FragColor";\r
- case 22: return "FragDepth";\r
- case 23: return "HelperInvocation";\r
- case 24: return "NumWorkgroups";\r
- case 25: return "WorkgroupSize";\r
- case 26: return "WorkgroupId";\r
- case 27: return "LocalInvocationId";\r
- case 28: return "GlobalInvocationId";\r
- case 29: return "LocalInvocationIndex";\r
- case 30: return "WorkDim";\r
- case 31: return "GlobalSize";\r
- case 32: return "EnqueuedWorkgroupSize";\r
- case 33: return "GlobalOffset";\r
- case 34: return "GlobalLinearId";\r
- case 35: return "WorkgroupLinearId";\r
- case 36: return "SubgroupSize";\r
- case 37: return "SubgroupMaxSize";\r
- case 38: return "NumSubgroups";\r
- case 39: return "NumEnqueuedSubgroups";\r
- case 40: return "SubgroupId";\r
- case 41: return "SubgroupLocalInvocationId";\r
-\r
- case BuiltInCeiling:\r
- default: return "Bad";\r
- }\r
-}\r
-\r
-const int DimensionCeiling = 6;\r
-\r
-const char* DimensionString(int dim)\r
-{\r
- switch (dim) {\r
- case 0: return "1D";\r
- case 1: return "2D";\r
- case 2: return "3D";\r
- case 3: return "Cube";\r
- case 4: return "Rect";\r
- case 5: return "Buffer";\r
-\r
- case DimensionCeiling:\r
- default: return "Bad";\r
- }\r
-}\r
-\r
-const int SamplerAddressingModeCeiling = 5;\r
-\r
-const char* SamplerAddressingModeString(int mode)\r
-{\r
- switch (mode) {\r
- case 0: return "None";\r
- case 1: return "ClampToEdge";\r
- case 2: return "Clamp";\r
- case 3: return "Repeat";\r
- case 4: return "RepeatMirrored";\r
-\r
- case SamplerAddressingModeCeiling:\r
- default: return "Bad";\r
- }\r
-}\r
-\r
-const int SamplerFilterModeCeiling = 2;\r
-\r
-const char* SamplerFilterModeString(int mode)\r
-{\r
- switch (mode) {\r
- case 0: return "Nearest";\r
- case 1: return "Linear";\r
-\r
- case SamplerFilterModeCeiling:\r
- default: return "Bad";\r
- }\r
-}\r
-\r
-const int FPFastMathCeiling = 5;\r
-\r
-const char* FPFastMathString(int mode)\r
-{\r
- switch (mode) {\r
- case 0: return "NotNaN";\r
- case 1: return "NotInf";\r
- case 2: return "NSZ";\r
- case 3: return "AllowRecip";\r
- case 4: return "Fast";\r
-\r
- case FPFastMathCeiling:\r
- default: return "Bad";\r
- }\r
-}\r
-\r
-const int FPRoundingModeCeiling = 4;\r
-\r
-const char* FPRoundingModeString(int mode)\r
-{\r
- switch (mode) {\r
- case 0: return "RTE";\r
- case 1: return "RTZ";\r
- case 2: return "RTP";\r
- case 3: return "RTN";\r
-\r
- case FPRoundingModeCeiling:\r
- default: return "Bad";\r
- }\r
-}\r
-\r
-const int LinkageTypeCeiling = 2;\r
-\r
-const char* LinkageTypeString(int type)\r
-{\r
- switch (type) {\r
- case 0: return "Export";\r
- case 1: return "Import";\r
-\r
- case LinkageTypeCeiling:\r
- default: return "Bad";\r
- }\r
-}\r
-\r
-const int FuncParamAttrCeiling = 9;\r
-\r
-const char* FuncParamAttrString(int attr)\r
-{\r
- switch (attr) {\r
- case 0: return "Zext";\r
- case 1: return "Sext";\r
- case 2: return "ByVal";\r
- case 3: return "Sret";\r
- case 4: return "NoAlias";\r
- case 5: return "NoCapture";\r
- case 6: return "SVM";\r
- case 7: return "NoWrite";\r
- case 8: return "NoReadWrite";\r
-\r
- case FuncParamAttrCeiling:\r
- default: return "Bad";\r
- }\r
-}\r
-\r
-const int AccessQualifierCeiling = 3;\r
-\r
-const char* AccessQualifierString(int attr)\r
-{\r
- switch (attr) {\r
- case 0: return "ReadOnly";\r
- case 1: return "WriteOnly";\r
- case 2: return "ReadWrite";\r
-\r
- case AccessQualifierCeiling:\r
- default: return "Bad";\r
- }\r
-}\r
-\r
-const int SelectControlCeiling = 2;\r
-\r
-const char* SelectControlString(int cont)\r
-{\r
- switch (cont) {\r
- case 0: return "Flatten";\r
- case 1: return "DontFlatten";\r
-\r
- case SelectControlCeiling:\r
- default: return "Bad";\r
- }\r
-}\r
-\r
-const int LoopControlCeiling = 2;\r
-\r
-const char* LoopControlString(int cont)\r
-{\r
- switch (cont) {\r
- case 0: return "Unroll";\r
- case 1: return "DontUnroll";\r
-\r
- case LoopControlCeiling:\r
- default: return "Bad";\r
- }\r
-}\r
-\r
-const int FunctionControlCeiling = 4;\r
-\r
-const char* FunctionControlString(int cont)\r
-{\r
- switch (cont) {\r
- case 0: return "Inline";\r
- case 1: return "DontInline";\r
- case 2: return "Pure";\r
- case 3: return "Const";\r
-\r
- case FunctionControlCeiling:\r
- default: return "Bad";\r
- }\r
-}\r
-\r
-const int MemorySemanticsCeiling = 10;\r
-\r
-const char* MemorySemanticsString(int mem)\r
-{\r
- switch (mem) {\r
- case 0: return "Relaxed";\r
- case 1: return "SequentiallyConsistent";\r
- case 2: return "Acquire";\r
- case 3: return "Release";\r
-\r
- case 4: return "UniformMemory";\r
- case 5: return "SubgroupMemory";\r
- case 6: return "WorkgroupLocalMemory";\r
- case 7: return "WorkgroupGlobalMemory";\r
- case 8: return "AtomicCounterMemory";\r
- case 9: return "ImageMemory";\r
-\r
- case MemorySemanticsCeiling:\r
- default: return "Bad";\r
- }\r
-}\r
-\r
-const int MemoryAccessCeiling = 2;\r
-\r
-const char* MemoryAccessString(int mem)\r
-{\r
- switch (mem) {\r
- case 0: return "Volatile";\r
- case 1: return "Aligned";\r
-\r
- case MemoryAccessCeiling:\r
- default: return "Bad";\r
- }\r
-}\r
-\r
-const int ExecutionScopeCeiling = 4;\r
-\r
-const char* ExecutionScopeString(int mem)\r
-{\r
- switch (mem) {\r
- case 0: return "CrossDevice";\r
- case 1: return "Device";\r
- case 2: return "Workgroup";\r
- case 3: return "Subgroup";\r
-\r
- case ExecutionScopeCeiling:\r
- default: return "Bad";\r
- }\r
-}\r
-\r
-const int GroupOperationCeiling = 3;\r
-\r
-const char* GroupOperationString(int gop)\r
-{\r
-\r
- switch (gop)\r
- {\r
- case 0: return "Reduce";\r
- case 1: return "InclusiveScan";\r
- case 2: return "ExclusiveScan";\r
-\r
- case GroupOperationCeiling:\r
- default: return "Bad";\r
- }\r
-}\r
-\r
-const int KernelEnqueueFlagsCeiling = 3;\r
-\r
-const char* KernelEnqueueFlagsString(int flag)\r
-{\r
- switch (flag)\r
- {\r
- case 0: return "NoWait";\r
- case 1: return "WaitKernel";\r
- case 2: return "WaitWorkGroup";\r
-\r
- case KernelEnqueueFlagsCeiling:\r
- default: return "Bad";\r
- }\r
-}\r
-\r
-const int KernelProfilingInfoCeiling = 1;\r
-\r
-const char* KernelProfilingInfoString(int info)\r
-{\r
- switch (info)\r
- {\r
- case 0: return "CmdExecTime";\r
-\r
- case KernelProfilingInfoCeiling:\r
- default: return "Bad";\r
- }\r
-}\r
-\r
-const char* OpcodeString(int op)\r
-{\r
- switch (op) {\r
- case 0: return "OpNop";\r
- case 1: return "OpSource";\r
- case 2: return "OpSourceExtension";\r
- case 3: return "OpExtension";\r
- case 4: return "OpExtInstImport";\r
- case 5: return "OpMemoryModel";\r
- case 6: return "OpEntryPoint";\r
- case 7: return "OpExecutionMode";\r
- case 8: return "OpTypeVoid";\r
- case 9: return "OpTypeBool";\r
- case 10: return "OpTypeInt";\r
- case 11: return "OpTypeFloat";\r
- case 12: return "OpTypeVector";\r
- case 13: return "OpTypeMatrix";\r
- case 14: return "OpTypeSampler";\r
- case 15: return "OpTypeFilter";\r
- case 16: return "OpTypeArray";\r
- case 17: return "OpTypeRuntimeArray";\r
- case 18: return "OpTypeStruct";\r
- case 19: return "OpTypeOpaque";\r
- case 20: return "OpTypePointer";\r
- case 21: return "OpTypeFunction";\r
- case 22: return "OpTypeEvent";\r
- case 23: return "OpTypeDeviceEvent";\r
- case 24: return "OpTypeReserveId";\r
- case 25: return "OpTypeQueue";\r
- case 26: return "OpTypePipe";\r
- case 27: return "OpConstantTrue";\r
- case 28: return "OpConstantFalse";\r
- case 29: return "OpConstant";\r
- case 30: return "OpConstantComposite";\r
- case 31: return "OpConstantSampler";\r
- case 32: return "OpConstantNullPointer";\r
- case 33: return "OpConstantNullObject";\r
- case 34: return "OpSpecConstantTrue";\r
- case 35: return "OpSpecConstantFalse";\r
- case 36: return "OpSpecConstant";\r
- case 37: return "OpSpecConstantComposite";\r
- case 38: return "OpVariable";\r
- case 39: return "OpVariableArray";\r
- case 40: return "OpFunction";\r
- case 41: return "OpFunctionParameter";\r
- case 42: return "OpFunctionEnd";\r
- case 43: return "OpFunctionCall";\r
- case 44: return "OpExtInst";\r
- case 45: return "OpUndef";\r
- case 46: return "OpLoad";\r
- case 47: return "OpStore";\r
- case 48: return "OpPhi";\r
- case 49: return "OpDecorationGroup";\r
- case 50: return "OpDecorate";\r
- case 51: return "OpMemberDecorate";\r
- case 52: return "OpGroupDecorate";\r
- case 53: return "OpGroupMemberDecorate";\r
- case 54: return "OpName";\r
- case 55: return "OpMemberName";\r
- case 56: return "OpString";\r
- case 57: return "OpLine";\r
- case 58: return "OpVectorExtractDynamic";\r
- case 59: return "OpVectorInsertDynamic";\r
- case 60: return "OpVectorShuffle";\r
- case 61: return "OpCompositeConstruct";\r
- case 62: return "OpCompositeExtract";\r
- case 63: return "OpCompositeInsert";\r
- case 64: return "OpCopyObject";\r
- case 65: return "OpCopyMemory";\r
- case 66: return "OpCopyMemorySized";\r
- case 67: return "OpSampler";\r
- case 68: return "OpTextureSample";\r
- case 69: return "OpTextureSampleDref";\r
- case 70: return "OpTextureSampleLod";\r
- case 71: return "OpTextureSampleProj";\r
- case 72: return "OpTextureSampleGrad";\r
- case 73: return "OpTextureSampleOffset";\r
- case 74: return "OpTextureSampleProjLod";\r
- case 75: return "OpTextureSampleProjGrad";\r
- case 76: return "OpTextureSampleLodOffset";\r
- case 77: return "OpTextureSampleProjOffset";\r
- case 78: return "OpTextureSampleGradOffset";\r
- case 79: return "OpTextureSampleProjLodOffset";\r
- case 80: return "OpTextureSampleProjGradOffset";\r
- case 81: return "OpTextureFetchTexelLod";\r
- case 82: return "OpTextureFetchTexelOffset";\r
- case 83: return "OpTextureFetchSample";\r
- case 84: return "OpTextureFetchTexel";\r
- case 85: return "OpTextureGather";\r
- case 86: return "OpTextureGatherOffset";\r
- case 87: return "OpTextureGatherOffsets";\r
- case 88: return "OpTextureQuerySizeLod";\r
- case 89: return "OpTextureQuerySize";\r
- case 90: return "OpTextureQueryLod";\r
- case 91: return "OpTextureQueryLevels";\r
- case 92: return "OpTextureQuerySamples";\r
- case 93: return "OpAccessChain";\r
- case 94: return "OpInBoundsAccessChain";\r
- case 95: return "OpSNegate";\r
- case 96: return "OpFNegate";\r
- case 97: return "OpNot";\r
- case 98: return "OpAny";\r
- case 99: return "OpAll";\r
- case 100: return "OpConvertFToU";\r
- case 101: return "OpConvertFToS";\r
- case 102: return "OpConvertSToF";\r
- case 103: return "OpConvertUToF";\r
- case 104: return "OpUConvert";\r
- case 105: return "OpSConvert";\r
- case 106: return "OpFConvert";\r
- case 107: return "OpConvertPtrToU";\r
- case 108: return "OpConvertUToPtr";\r
- case 109: return "OpPtrCastToGeneric";\r
- case 110: return "OpGenericCastToPtr";\r
- case 111: return "OpBitcast";\r
- case 112: return "OpTranspose";\r
- case 113: return "OpIsNan";\r
- case 114: return "OpIsInf";\r
- case 115: return "OpIsFinite";\r
- case 116: return "OpIsNormal";\r
- case 117: return "OpSignBitSet";\r
- case 118: return "OpLessOrGreater";\r
- case 119: return "OpOrdered";\r
- case 120: return "OpUnordered";\r
- case 121: return "OpArrayLength";\r
- case 122: return "OpIAdd";\r
- case 123: return "OpFAdd";\r
- case 124: return "OpISub";\r
- case 125: return "OpFSub";\r
- case 126: return "OpIMul";\r
- case 127: return "OpFMul";\r
- case 128: return "OpUDiv";\r
- case 129: return "OpSDiv";\r
- case 130: return "OpFDiv";\r
- case 131: return "OpUMod";\r
- case 132: return "OpSRem";\r
- case 133: return "OpSMod";\r
- case 134: return "OpFRem";\r
- case 135: return "OpFMod";\r
- case 136: return "OpVectorTimesScalar";\r
- case 137: return "OpMatrixTimesScalar";\r
- case 138: return "OpVectorTimesMatrix";\r
- case 139: return "OpMatrixTimesVector";\r
- case 140: return "OpMatrixTimesMatrix";\r
- case 141: return "OpOuterProduct";\r
- case 142: return "OpDot";\r
- case 143: return "OpShiftRightLogical";\r
- case 144: return "OpShiftRightArithmetic";\r
- case 145: return "OpShiftLeftLogical";\r
- case 146: return "OpLogicalOr";\r
- case 147: return "OpLogicalXor";\r
- case 148: return "OpLogicalAnd";\r
- case 149: return "OpBitwiseOr";\r
- case 150: return "OpBitwiseXor";\r
- case 151: return "OpBitwiseAnd";\r
- case 152: return "OpSelect";\r
- case 153: return "OpIEqual";\r
- case 154: return "OpFOrdEqual";\r
- case 155: return "OpFUnordEqual";\r
- case 156: return "OpINotEqual";\r
- case 157: return "OpFOrdNotEqual";\r
- case 158: return "OpFUnordNotEqual";\r
- case 159: return "OpULessThan";\r
- case 160: return "OpSLessThan";\r
- case 161: return "OpFOrdLessThan";\r
- case 162: return "OpFUnordLessThan";\r
- case 163: return "OpUGreaterThan";\r
- case 164: return "OpSGreaterThan";\r
- case 165: return "OpFOrdGreaterThan";\r
- case 166: return "OpFUnordGreaterThan";\r
- case 167: return "OpULessThanEqual";\r
- case 168: return "OpSLessThanEqual";\r
- case 169: return "OpFOrdLessThanEqual";\r
- case 170: return "OpFUnordLessThanEqual";\r
- case 171: return "OpUGreaterThanEqual";\r
- case 172: return "OpSGreaterThanEqual";\r
- case 173: return "OpFOrdGreaterThanEqual";\r
- case 174: return "OpFUnordGreaterThanEqual";\r
- case 175: return "OpDPdx";\r
- case 176: return "OpDPdy";\r
- case 177: return "OpFwidth";\r
- case 178: return "OpDPdxFine";\r
- case 179: return "OpDPdyFine";\r
- case 180: return "OpFwidthFine";\r
- case 181: return "OpDPdxCoarse";\r
- case 182: return "OpDPdyCoarse";\r
- case 183: return "OpFwidthCoarse";\r
- case 184: return "OpEmitVertex";\r
- case 185: return "OpEndPrimitive";\r
- case 186: return "OpEmitStreamVertex";\r
- case 187: return "OpEndStreamPrimitive";\r
- case 188: return "OpControlBarrier";\r
- case 189: return "OpMemoryBarrier";\r
- case 190: return "OpImagePointer";\r
- case 191: return "OpAtomicInit";\r
- case 192: return "OpAtomicLoad";\r
- case 193: return "OpAtomicStore";\r
- case 194: return "OpAtomicExchange";\r
- case 195: return "OpAtomicCompareExchange";\r
- case 196: return "OpAtomicCompareExchangeWeak";\r
- case 197: return "OpAtomicIIncrement";\r
- case 198: return "OpAtomicIDecrement";\r
- case 199: return "OpAtomicIAdd";\r
- case 200: return "OpAtomicISub";\r
- case 201: return "OpAtomicUMin";\r
- case 202: return "OpAtomicUMax";\r
- case 203: return "OpAtomicAnd";\r
- case 204: return "OpAtomicOr";\r
- case 205: return "OpAtomicXor";\r
- case 206: return "OpLoopMerge";\r
- case 207: return "OpSelectionMerge";\r
- case 208: return "OpLabel";\r
- case 209: return "OpBranch";\r
- case 210: return "OpBranchConditional";\r
- case 211: return "OpSwitch";\r
- case 212: return "OpKill";\r
- case 213: return "OpReturn";\r
- case 214: return "OpReturnValue";\r
- case 215: return "OpUnreachable";\r
- case 216: return "OpLifetimeStart";\r
- case 217: return "OpLifetimeStop";\r
- case 218: return "OpCompileFlag";\r
- case 219: return "OpAsyncGroupCopy";\r
- case 220: return "OpWaitGroupEvents";\r
- case 221: return "OpGroupAll";\r
- case 222: return "OpGroupAny";\r
- case 223: return "OpGroupBroadcast";\r
- case 224: return "OpGroupIAdd";\r
- case 225: return "OpGroupFAdd";\r
- case 226: return "OpGroupFMin";\r
- case 227: return "OpGroupUMin";\r
- case 228: return "OpGroupSMin";\r
- case 229: return "OpGroupFMax";\r
- case 230: return "OpGroupUMax";\r
- case 231: return "OpGroupSMax";\r
- case 232: return "OpGenericCastToPtrExplicit";\r
- case 233: return "OpGenericPtrMemSemantics";\r
- case 234: return "OpReadPipe";\r
- case 235: return "OpWritePipe";\r
- case 236: return "OpReservedReadPipe";\r
- case 237: return "OpReservedWritePipe";\r
- case 238: return "OpReserveReadPipePackets";\r
- case 239: return "OpReserveWritePipePackets";\r
- case 240: return "OpCommitReadPipe";\r
- case 241: return "OpCommitWritePipe";\r
- case 242: return "OpIsValidReserveId";\r
- case 243: return "OpGetNumPipePackets";\r
- case 244: return "OpGetMaxPipePackets";\r
- case 245: return "OpGroupReserveReadPipePackets";\r
- case 246: return "OpGroupReserveWritePipePackets";\r
- case 247: return "OpGroupCommitReadPipe";\r
- case 248: return "OpGroupCommitWritePipe";\r
- case 249: return "OpEnqueueMarker";\r
- case 250: return "OpEnqueueKernel";\r
- case 251: return "OpGetKernelNDrangeSubGroupCount";\r
- case 252: return "OpGetKernelNDrangeMaxSubGroupSize";\r
- case 253: return "OpGetKernelWorkGroupSize";\r
- case 254: return "OpGetKernelPreferredWorkGroupSizeMultiple";\r
- case 255: return "OpRetainEvent";\r
- case 256: return "OpReleaseEvent";\r
- case 257: return "OpCreateUserEvent";\r
- case 258: return "OpIsValidEvent";\r
- case 259: return "OpSetUserEventStatus";\r
- case 260: return "OpCaptureEventProfilingInfo";\r
- case 261: return "OpGetDefaultQueue";\r
- case 262: return "OpBuildNDRange";\r
- case 263: return "OpSatConvertSToU";\r
- case 264: return "OpSatConvertUToS";\r
- case 265: return "OpAtomicIMin";\r
- case 266: return "OpAtomicIMax";\r
-\r
- case OpcodeCeiling:\r
- default:\r
- return "Bad";\r
- }\r
-}\r
-\r
-// The set of objects that hold all the instruction/operand\r
-// parameterization information.\r
-InstructionParameters InstructionDesc[OpcodeCeiling];\r
-OperandParameters ExecutionModeOperands[ExecutionModeCeiling];\r
-OperandParameters DecorationOperands[DecorationCeiling];\r
-\r
-EnumDefinition OperandClassParams[OperandCount];\r
-EnumParameters ExecutionModelParams[ExecutionModelCeiling];\r
-EnumParameters AddressingParams[AddressingModelCeiling];\r
-EnumParameters MemoryParams[MemoryModelCeiling];\r
-EnumParameters ExecutionModeParams[ExecutionModeCeiling];\r
-EnumParameters StorageParams[StorageClassCeiling];\r
-EnumParameters SamplerAddressingModeParams[SamplerAddressingModeCeiling];\r
-EnumParameters SamplerFilterModeParams[SamplerFilterModeCeiling];\r
-EnumParameters FPFastMathParams[FPFastMathCeiling];\r
-EnumParameters FPRoundingModeParams[FPRoundingModeCeiling];\r
-EnumParameters LinkageTypeParams[LinkageTypeCeiling];\r
-EnumParameters DecorationParams[DecorationCeiling];\r
-EnumParameters BuiltInParams[BuiltInCeiling];\r
-EnumParameters DimensionalityParams[DimensionCeiling];\r
-EnumParameters FuncParamAttrParams[FuncParamAttrCeiling];\r
-EnumParameters AccessQualifierParams[AccessQualifierCeiling];\r
-EnumParameters GroupOperationParams[GroupOperationCeiling];\r
-EnumParameters LoopControlParams[FunctionControlCeiling];\r
-EnumParameters SelectionControlParams[SelectControlCeiling];\r
-EnumParameters FunctionControlParams[FunctionControlCeiling];\r
-EnumParameters MemorySemanticsParams[MemorySemanticsCeiling];\r
-EnumParameters MemoryAccessParams[MemoryAccessCeiling];\r
-EnumParameters ExecutionScopeParams[ExecutionScopeCeiling];\r
-EnumParameters KernelEnqueueFlagsParams[KernelEnqueueFlagsCeiling];\r
-EnumParameters KernelProfilingInfoParams[KernelProfilingInfoCeiling];\r
-\r
-// Set up all the parameterizing descriptions of the opcodes, operands, etc.\r
-void Parameterize()\r
-{\r
- static bool initialized = false;\r
-\r
- // only do this once.\r
- if (initialized)\r
- return;\r
-\r
- initialized = true;\r
-\r
- // Exceptions to having a result <id> and a resulting type <id>.\r
- // (Everything is initialized to have both).\r
-\r
- InstructionDesc[OpNop].setResultAndType(false, false);\r
- InstructionDesc[OpSource].setResultAndType(false, false);\r
- InstructionDesc[OpSourceExtension].setResultAndType(false, false);\r
- InstructionDesc[OpExtension].setResultAndType(false, false);\r
- InstructionDesc[OpExtInstImport].setResultAndType(true, false);\r
- InstructionDesc[OpMemoryModel].setResultAndType(false, false);\r
- InstructionDesc[OpEntryPoint].setResultAndType(false, false);\r
- InstructionDesc[OpExecutionMode].setResultAndType(false, false);\r
- InstructionDesc[OpTypeVoid].setResultAndType(true, false);\r
- InstructionDesc[OpTypeBool].setResultAndType(true, false);\r
- InstructionDesc[OpTypeInt].setResultAndType(true, false);\r
- InstructionDesc[OpTypeFloat].setResultAndType(true, false);\r
- InstructionDesc[OpTypeVector].setResultAndType(true, false);\r
- InstructionDesc[OpTypeMatrix].setResultAndType(true, false);\r
- InstructionDesc[OpTypeSampler].setResultAndType(true, false);\r
- InstructionDesc[OpTypeFilter].setResultAndType(true, false);\r
- InstructionDesc[OpTypeArray].setResultAndType(true, false);\r
- InstructionDesc[OpTypeRuntimeArray].setResultAndType(true, false);\r
- InstructionDesc[OpTypeStruct].setResultAndType(true, false);\r
- InstructionDesc[OpTypeOpaque].setResultAndType(true, false);\r
- InstructionDesc[OpTypePointer].setResultAndType(true, false);\r
- InstructionDesc[OpTypeFunction].setResultAndType(true, false);\r
- InstructionDesc[OpTypeEvent].setResultAndType(true, false);\r
- InstructionDesc[OpTypeDeviceEvent].setResultAndType(true, false);\r
- InstructionDesc[OpTypeReserveId].setResultAndType(true, false);\r
- InstructionDesc[OpTypeQueue].setResultAndType(true, false);\r
- InstructionDesc[OpTypePipe].setResultAndType(true, false);\r
- InstructionDesc[OpFunctionEnd].setResultAndType(false, false);\r
- InstructionDesc[OpStore].setResultAndType(false, false);\r
- InstructionDesc[OpDecorationGroup].setResultAndType(true, false);\r
- InstructionDesc[OpDecorate].setResultAndType(false, false);\r
- InstructionDesc[OpMemberDecorate].setResultAndType(false, false);\r
- InstructionDesc[OpGroupDecorate].setResultAndType(false, false);\r
- InstructionDesc[OpGroupMemberDecorate].setResultAndType(false, false);\r
- InstructionDesc[OpName].setResultAndType(false, false);\r
- InstructionDesc[OpMemberName].setResultAndType(false, false);\r
- InstructionDesc[OpString].setResultAndType(true, false);\r
- InstructionDesc[OpLine].setResultAndType(false, false);\r
- InstructionDesc[OpCopyMemory].setResultAndType(false, false);\r
- InstructionDesc[OpCopyMemorySized].setResultAndType(false, false);\r
- InstructionDesc[OpEmitVertex].setResultAndType(false, false);\r
- InstructionDesc[OpEndPrimitive].setResultAndType(false, false);\r
- InstructionDesc[OpEmitStreamVertex].setResultAndType(false, false);\r
- InstructionDesc[OpEndStreamPrimitive].setResultAndType(false, false);\r
- InstructionDesc[OpControlBarrier].setResultAndType(false, false);\r
- InstructionDesc[OpMemoryBarrier].setResultAndType(false, false);\r
- InstructionDesc[OpAtomicInit].setResultAndType(false, false);\r
- InstructionDesc[OpAtomicStore].setResultAndType(false, false);\r
- InstructionDesc[OpLoopMerge].setResultAndType(false, false);\r
- InstructionDesc[OpSelectionMerge].setResultAndType(false, false);\r
- InstructionDesc[OpLabel].setResultAndType(true, false);\r
- InstructionDesc[OpBranch].setResultAndType(false, false);\r
- InstructionDesc[OpBranchConditional].setResultAndType(false, false);\r
- InstructionDesc[OpSwitch].setResultAndType(false, false);\r
- InstructionDesc[OpKill].setResultAndType(false, false);\r
- InstructionDesc[OpReturn].setResultAndType(false, false);\r
- InstructionDesc[OpReturnValue].setResultAndType(false, false);\r
- InstructionDesc[OpUnreachable].setResultAndType(false, false);\r
- InstructionDesc[OpLifetimeStart].setResultAndType(false, false);\r
- InstructionDesc[OpLifetimeStop].setResultAndType(false, false);\r
- InstructionDesc[OpCompileFlag].setResultAndType(false, false);\r
- InstructionDesc[OpCommitReadPipe].setResultAndType(false, false);\r
- InstructionDesc[OpCommitWritePipe].setResultAndType(false, false);\r
- InstructionDesc[OpGroupCommitWritePipe].setResultAndType(false, false);\r
- InstructionDesc[OpGroupCommitReadPipe].setResultAndType(false, false);\r
- InstructionDesc[OpCaptureEventProfilingInfo].setResultAndType(false, false);\r
- InstructionDesc[OpSetUserEventStatus].setResultAndType(false, false);\r
- InstructionDesc[OpRetainEvent].setResultAndType(false, false);\r
- InstructionDesc[OpReleaseEvent].setResultAndType(false, false);\r
-\r
- // Specific additional context-dependent operands\r
-\r
- ExecutionModeOperands[ExecutionModeInvocations].push(OperandLiteralNumber, "Number of invocations");\r
-\r
- ExecutionModeOperands[ExecutionModeLocalSize].push(OperandLiteralNumber, "'x size'");\r
- ExecutionModeOperands[ExecutionModeLocalSize].push(OperandLiteralNumber, "'y size'");\r
- ExecutionModeOperands[ExecutionModeLocalSize].push(OperandLiteralNumber, "'z size'");\r
-\r
- ExecutionModeOperands[ExecutionModeLocalSizeHint].push(OperandLiteralNumber, "'x size'");\r
- ExecutionModeOperands[ExecutionModeLocalSizeHint].push(OperandLiteralNumber, "'y size'");\r
- ExecutionModeOperands[ExecutionModeLocalSizeHint].push(OperandLiteralNumber, "'z size'");\r
-\r
- ExecutionModeOperands[ExecutionModeOutputVertices].push(OperandLiteralNumber, "Vertex count");\r
- ExecutionModeOperands[ExecutionModeVecTypeHint].push(OperandId, "Vector type");\r
-\r
- DecorationOperands[DecorationStream].push(OperandLiteralNumber, "Stream number");\r
- DecorationOperands[DecorationLocation].push(OperandLiteralNumber, "Location");\r
- DecorationOperands[DecorationComponent].push(OperandLiteralNumber, "Component within a vector");\r
- DecorationOperands[DecorationIndex].push(OperandLiteralNumber, "Index");\r
- DecorationOperands[DecorationBinding].push(OperandLiteralNumber, "Binding point");\r
- DecorationOperands[DecorationDescriptorSet].push(OperandLiteralNumber, "Descriptor set");\r
- DecorationOperands[DecorationOffset].push(OperandLiteralNumber, "Byte offset");\r
- DecorationOperands[DecorationAlignment].push(OperandLiteralNumber, "Declared alignment");\r
- DecorationOperands[DecorationXfbBuffer].push(OperandLiteralNumber, "XFB Buffer number");\r
- DecorationOperands[DecorationStride].push(OperandLiteralNumber, "Stride");\r
- DecorationOperands[DecorationBuiltIn].push(OperandLiteralNumber, "See <<BuiltIn,*BuiltIn*>>");\r
- DecorationOperands[DecorationFPRoundingMode].push(OperandFPRoundingMode, "floating-point rounding mode");\r
- DecorationOperands[DecorationFPFastMathMode].push(OperandFPFastMath, "fast-math mode");\r
- DecorationOperands[DecorationLinkageAttributes].push(OperandLiteralString, "name");\r
- DecorationOperands[DecorationLinkageAttributes].push(OperandLinkageType, "linkage type");\r
- DecorationOperands[DecorationFuncParamAttr].push(OperandFuncParamAttr, "function parameter attribute");\r
- DecorationOperands[DecorationSpecId].push(OperandLiteralNumber, "Specialization Constant ID");\r
-\r
- OperandClassParams[OperandSource].set(SourceLanguageCeiling, SourceString, 0);\r
- OperandClassParams[OperandExecutionModel].set(ExecutionModelCeiling, ExecutionModelString, ExecutionModelParams);\r
- OperandClassParams[OperandAddressing].set(AddressingModelCeiling, AddressingString, AddressingParams);\r
- OperandClassParams[OperandMemory].set(MemoryModelCeiling, MemoryString, MemoryParams);\r
- OperandClassParams[OperandExecutionMode].set(ExecutionModeCeiling, ExecutionModeString, ExecutionModeParams);\r
- OperandClassParams[OperandExecutionMode].setOperands(ExecutionModeOperands);\r
- OperandClassParams[OperandStorage].set(StorageClassCeiling, StorageClassString, StorageParams);\r
- OperandClassParams[OperandDimensionality].set(DimensionCeiling, DimensionString, DimensionalityParams);\r
- OperandClassParams[OperandSamplerAddressingMode].set(SamplerAddressingModeCeiling, SamplerAddressingModeString, SamplerAddressingModeParams);\r
- OperandClassParams[OperandSamplerFilterMode].set(SamplerFilterModeCeiling, SamplerFilterModeString, SamplerFilterModeParams);\r
- OperandClassParams[OperandFPFastMath].set(FPFastMathCeiling, FPFastMathString, FPFastMathParams, true);\r
- OperandClassParams[OperandFPRoundingMode].set(FPRoundingModeCeiling, FPRoundingModeString, FPRoundingModeParams);\r
- OperandClassParams[OperandLinkageType].set(LinkageTypeCeiling, LinkageTypeString, LinkageTypeParams);\r
- OperandClassParams[OperandFuncParamAttr].set(FuncParamAttrCeiling, FuncParamAttrString, FuncParamAttrParams);\r
- OperandClassParams[OperandAccessQualifier].set(AccessQualifierCeiling, AccessQualifierString, AccessQualifierParams);\r
- OperandClassParams[OperandDecoration].set(DecorationCeiling, DecorationString, DecorationParams);\r
- OperandClassParams[OperandDecoration].setOperands(DecorationOperands);\r
- OperandClassParams[OperandBuiltIn].set(BuiltInCeiling, BuiltInString, BuiltInParams);\r
- OperandClassParams[OperandSelect].set(SelectControlCeiling, SelectControlString, SelectionControlParams, true);\r
- OperandClassParams[OperandLoop].set(LoopControlCeiling, LoopControlString, LoopControlParams, true);\r
- OperandClassParams[OperandFunction].set(FunctionControlCeiling, FunctionControlString, FunctionControlParams, true);\r
- OperandClassParams[OperandMemorySemantics].set(MemorySemanticsCeiling, MemorySemanticsString, MemorySemanticsParams, true);\r
- OperandClassParams[OperandMemoryAccess].set(MemoryAccessCeiling, MemoryAccessString, MemoryAccessParams, true);\r
- OperandClassParams[OperandExecutionScope].set(ExecutionScopeCeiling, ExecutionScopeString, ExecutionScopeParams);\r
- OperandClassParams[OperandGroupOperation].set(GroupOperationCeiling, GroupOperationString, GroupOperationParams);\r
- OperandClassParams[OperandKernelEnqueueFlags].set(KernelEnqueueFlagsCeiling, KernelEnqueueFlagsString, KernelEnqueueFlagsParams);\r
- OperandClassParams[OperandKernelProfilingInfo].set(KernelProfilingInfoCeiling, KernelProfilingInfoString, KernelProfilingInfoParams, true);\r
- OperandClassParams[OperandOpcode].set(OpcodeCeiling, OpcodeString, 0);\r
-\r
- AddressingParams[AddressingModelPhysical32].caps.push_back(CapAddr);\r
- AddressingParams[AddressingModelPhysical64].caps.push_back(CapAddr);\r
-\r
- MemoryParams[MemoryModelSimple].caps.push_back(CapShader);\r
- MemoryParams[MemoryModelGLSL450].caps.push_back(CapShader);\r
- MemoryParams[MemoryModelOpenCL12].caps.push_back(CapKernel);\r
- MemoryParams[MemoryModelOpenCL20].caps.push_back(CapKernel);\r
- MemoryParams[MemoryModelOpenCL21].caps.push_back(CapKernel);\r
-\r
- ExecutionModelParams[ExecutionModelVertex].caps.push_back(CapShader);\r
- ExecutionModelParams[ExecutionModelTessellationControl].caps.push_back(CapTess);\r
- ExecutionModelParams[ExecutionModelTessellationEvaluation].caps.push_back(CapTess);\r
- ExecutionModelParams[ExecutionModelGeometry].caps.push_back(CapGeom);\r
- ExecutionModelParams[ExecutionModelFragment].caps.push_back(CapShader);\r
- ExecutionModelParams[ExecutionModelGLCompute].caps.push_back(CapShader);\r
- ExecutionModelParams[ExecutionModelKernel].caps.push_back(CapKernel);\r
-\r
- // Storage capabilites\r
- StorageParams[StorageClassInput].caps.push_back(CapShader);\r
- StorageParams[StorageClassUniform].caps.push_back(CapShader);\r
- StorageParams[StorageClassOutput].caps.push_back(CapShader);\r
- StorageParams[StorageClassPrivateGlobal].caps.push_back(CapShader);\r
- StorageParams[StorageClassFunction].caps.push_back(CapShader);\r
- StorageParams[StorageClassGeneric].caps.push_back(CapKernel);\r
- StorageParams[StorageClassPrivate].caps.push_back(CapKernel);\r
- StorageParams[StorageClassAtomicCounter].caps.push_back(CapShader);\r
-\r
- // Sampler Filter & Addressing mode capabilities\r
- SamplerAddressingModeParams[SamplerAddressingModeNone].caps.push_back(CapKernel);\r
- SamplerAddressingModeParams[SamplerAddressingModeClampToEdge].caps.push_back(CapKernel);\r
- SamplerAddressingModeParams[SamplerAddressingModeClamp].caps.push_back(CapKernel);\r
- SamplerAddressingModeParams[SamplerAddressingModeRepeat].caps.push_back(CapKernel);\r
- SamplerAddressingModeParams[SamplerAddressingModeRepeatMirrored].caps.push_back(CapKernel);\r
-\r
- SamplerFilterModeParams[SamplerFilterModeNearest].caps.push_back(CapKernel);\r
- SamplerFilterModeParams[SamplerFilterModeLinear].caps.push_back(CapKernel);\r
-\r
- // fast math flags capabilities\r
- for (int i = 0; i < FPFastMathCeiling; ++i) {\r
- FPFastMathParams[i].caps.push_back(CapKernel);\r
- }\r
-\r
- // fp rounding mode capabilities\r
- for (int i = 0; i < FPRoundingModeCeiling; ++i) {\r
- FPRoundingModeParams[i].caps.push_back(CapKernel);\r
- }\r
-\r
- // linkage types\r
- for (int i = 0; i < LinkageTypeCeiling; ++i) {\r
- LinkageTypeParams[i].caps.push_back(CapLink);\r
- }\r
-\r
- // function argument types\r
- for (int i = 0; i < FuncParamAttrCeiling; ++i) {\r
- FuncParamAttrParams[i].caps.push_back(CapKernel);\r
- }\r
-\r
- // function argument types\r
- for (int i = 0; i < AccessQualifierCeiling; ++i) {\r
- AccessQualifierParams[i].caps.push_back(CapKernel);\r
- }\r
-\r
- ExecutionModeParams[ExecutionModeInvocations].caps.push_back(CapGeom);\r
- ExecutionModeParams[ExecutionModeSpacingEqual].caps.push_back(CapTess);\r
- ExecutionModeParams[ExecutionModeSpacingFractionalEven].caps.push_back(CapTess);\r
- ExecutionModeParams[ExecutionModeSpacingFractionalOdd].caps.push_back(CapTess);\r
- ExecutionModeParams[ExecutionModeVertexOrderCw].caps.push_back(CapTess);\r
- ExecutionModeParams[ExecutionModeVertexOrderCcw].caps.push_back(CapTess);\r
- ExecutionModeParams[ExecutionModePixelCenterInteger].caps.push_back(CapShader);\r
- ExecutionModeParams[ExecutionModeOriginUpperLeft].caps.push_back(CapShader);\r
- ExecutionModeParams[ExecutionModeEarlyFragmentTests].caps.push_back(CapShader);\r
- ExecutionModeParams[ExecutionModePointMode].caps.push_back(CapTess);\r
- ExecutionModeParams[ExecutionModeXfb].caps.push_back(CapShader);\r
- ExecutionModeParams[ExecutionModeDepthReplacing].caps.push_back(CapShader);\r
- ExecutionModeParams[ExecutionModeDepthAny].caps.push_back(CapShader);\r
- ExecutionModeParams[ExecutionModeDepthGreater].caps.push_back(CapShader);\r
- ExecutionModeParams[ExecutionModeDepthLess].caps.push_back(CapShader);\r
- ExecutionModeParams[ExecutionModeDepthUnchanged].caps.push_back(CapShader);\r
- ExecutionModeParams[ExecutionModeLocalSizeHint].caps.push_back(CapKernel);\r
- ExecutionModeParams[ExecutionModeInputPoints].caps.push_back(CapGeom);\r
- ExecutionModeParams[ExecutionModeInputLines].caps.push_back(CapGeom);\r
- ExecutionModeParams[ExecutionModeInputLinesAdjacency].caps.push_back(CapGeom);\r
- ExecutionModeParams[ExecutionModeInputTriangles].caps.push_back(CapGeom);\r
- ExecutionModeParams[ExecutionModeInputTriangles].caps.push_back(CapTess);\r
- ExecutionModeParams[ExecutionModeInputTrianglesAdjacency].caps.push_back(CapGeom);\r
- ExecutionModeParams[ExecutionModeInputQuads].caps.push_back(CapTess);\r
- ExecutionModeParams[ExecutionModeInputIsolines].caps.push_back(CapTess);\r
- ExecutionModeParams[ExecutionModeOutputVertices].caps.push_back(CapGeom);\r
- ExecutionModeParams[ExecutionModeOutputVertices].caps.push_back(CapTess);\r
- ExecutionModeParams[ExecutionModeOutputPoints].caps.push_back(CapGeom);\r
- ExecutionModeParams[ExecutionModeOutputLineStrip].caps.push_back(CapGeom);\r
- ExecutionModeParams[ExecutionModeOutputTriangleStrip].caps.push_back(CapGeom);\r
- ExecutionModeParams[ExecutionModeVecTypeHint].caps.push_back(CapKernel);\r
- ExecutionModeParams[ExecutionModeContractionOff].caps.push_back(CapKernel);\r
-\r
- DecorationParams[DecorationPrecisionLow].caps.push_back(CapShader);\r
- DecorationParams[DecorationPrecisionMedium].caps.push_back(CapShader);\r
- DecorationParams[DecorationPrecisionHigh].caps.push_back(CapShader);\r
- DecorationParams[DecorationBlock].caps.push_back(CapShader);\r
- DecorationParams[DecorationBufferBlock].caps.push_back(CapShader);\r
- DecorationParams[DecorationRowMajor].caps.push_back(CapMatrix);\r
- DecorationParams[DecorationColMajor].caps.push_back(CapMatrix);\r
- DecorationParams[DecorationGLSLShared].caps.push_back(CapShader);\r
- DecorationParams[DecorationGLSLStd140].caps.push_back(CapShader);\r
- DecorationParams[DecorationGLSLStd430].caps.push_back(CapShader);\r
- DecorationParams[DecorationGLSLPacked].caps.push_back(CapShader);\r
- DecorationParams[DecorationSmooth].caps.push_back(CapShader);\r
- DecorationParams[DecorationNoperspective].caps.push_back(CapShader);\r
- DecorationParams[DecorationFlat].caps.push_back(CapShader);\r
- DecorationParams[DecorationPatch].caps.push_back(CapTess);\r
- DecorationParams[DecorationCentroid].caps.push_back(CapShader);\r
- DecorationParams[DecorationSample].caps.push_back(CapShader);\r
- DecorationParams[DecorationInvariant].caps.push_back(CapShader);\r
- DecorationParams[DecorationConstant].caps.push_back(CapKernel);\r
- DecorationParams[DecorationUniform].caps.push_back(CapShader);\r
- DecorationParams[DecorationCPacked].caps.push_back(CapKernel);\r
- DecorationParams[DecorationSaturatedConversion].caps.push_back(CapKernel);\r
- DecorationParams[DecorationStream].caps.push_back(CapGeom);\r
- DecorationParams[DecorationLocation].caps.push_back(CapShader);\r
- DecorationParams[DecorationComponent].caps.push_back(CapShader);\r
- DecorationParams[DecorationIndex].caps.push_back(CapShader);\r
- DecorationParams[DecorationBinding].caps.push_back(CapShader);\r
- DecorationParams[DecorationDescriptorSet].caps.push_back(CapShader);\r
- DecorationParams[DecorationXfbBuffer].caps.push_back(CapShader);\r
- DecorationParams[DecorationStride].caps.push_back(CapShader);\r
- DecorationParams[DecorationBuiltIn].caps.push_back(CapShader);\r
- DecorationParams[DecorationFuncParamAttr].caps.push_back(CapKernel);\r
- DecorationParams[DecorationFPRoundingMode].caps.push_back(CapKernel);\r
- DecorationParams[DecorationFPFastMathMode].caps.push_back(CapKernel);\r
- DecorationParams[DecorationLinkageAttributes].caps.push_back(CapLink);\r
- DecorationParams[DecorationSpecId].caps.push_back(CapShader);\r
-\r
- BuiltInParams[BuiltInPosition].caps.push_back(CapShader);\r
- BuiltInParams[BuiltInPointSize].caps.push_back(CapShader);\r
- BuiltInParams[BuiltInClipVertex].caps.push_back(CapShader);\r
- BuiltInParams[BuiltInClipDistance].caps.push_back(CapShader);\r
- BuiltInParams[BuiltInCullDistance].caps.push_back(CapShader);\r
- BuiltInParams[BuiltInVertexId].caps.push_back(CapShader);\r
- BuiltInParams[BuiltInInstanceId].caps.push_back(CapShader);\r
- BuiltInParams[BuiltInPrimitiveId].caps.push_back(CapGeom);\r
- BuiltInParams[BuiltInPrimitiveId].caps.push_back(CapTess);\r
- BuiltInParams[BuiltInInvocationId].caps.push_back(CapGeom);\r
- BuiltInParams[BuiltInInvocationId].caps.push_back(CapTess);\r
- BuiltInParams[BuiltInLayer].caps.push_back(CapGeom);\r
- BuiltInParams[BuiltInViewportIndex].caps.push_back(CapGeom);\r
- BuiltInParams[BuiltInTessLevelOuter].caps.push_back(CapTess);\r
- BuiltInParams[BuiltInTessLevelInner].caps.push_back(CapTess);\r
- BuiltInParams[BuiltInTessCoord].caps.push_back(CapTess);\r
- BuiltInParams[BuiltInPatchVertices].caps.push_back(CapTess);\r
- BuiltInParams[BuiltInFragCoord].caps.push_back(CapShader);\r
- BuiltInParams[BuiltInPointCoord].caps.push_back(CapShader);\r
- BuiltInParams[BuiltInFrontFacing].caps.push_back(CapShader);\r
- BuiltInParams[BuiltInSampleId].caps.push_back(CapShader);\r
- BuiltInParams[BuiltInSamplePosition].caps.push_back(CapShader);\r
- BuiltInParams[BuiltInSampleMask].caps.push_back(CapShader);\r
- BuiltInParams[BuiltInFragColor].caps.push_back(CapShader);\r
- BuiltInParams[BuiltInFragDepth].caps.push_back(CapShader);\r
- BuiltInParams[BuiltInHelperInvocation].caps.push_back(CapShader);\r
- BuiltInParams[BuiltInLocalInvocationIndex].caps.push_back(CapShader);\r
- BuiltInParams[BuiltInWorkDim].caps.push_back(CapKernel);\r
- BuiltInParams[BuiltInGlobalSize].caps.push_back(CapKernel);\r
- BuiltInParams[BuiltInEnqueuedWorkgroupSize].caps.push_back(CapKernel);\r
- BuiltInParams[BuiltInGlobalOffset].caps.push_back(CapKernel);\r
- BuiltInParams[BuiltInGlobalLinearId].caps.push_back(CapKernel);\r
- BuiltInParams[BuiltInWorkgroupLinearId].caps.push_back(CapKernel);\r
-\r
- BuiltInParams[BuiltInSubgroupSize].caps.push_back(CapKernel);\r
- BuiltInParams[BuiltInSubgroupMaxSize].caps.push_back(CapKernel);\r
- BuiltInParams[BuiltInNumSubgroups].caps.push_back(CapKernel);\r
- BuiltInParams[BuiltInNumEnqueuedSubgroups].caps.push_back(CapKernel);\r
- BuiltInParams[BuiltInSubgroupId].caps.push_back(CapKernel);\r
- BuiltInParams[BuiltInSubgroupLocalInvocationId].caps.push_back(CapKernel);\r
-\r
- DimensionalityParams[DimCube].caps.push_back(CapShader);\r
- DimensionalityParams[DimRect].caps.push_back(CapShader);\r
-\r
- // Group Operations\r
- for (int i = 0; i < GroupOperationCeiling; ++i) {\r
- GroupOperationParams[i].caps.push_back(CapKernel);\r
- }\r
-\r
- // Enqueue flags\r
- for (int i = 0; i < KernelEnqueueFlagsCeiling; ++i) {\r
- KernelEnqueueFlagsParams[i].caps.push_back(CapKernel);\r
- }\r
-\r
- // Profiling info\r
- KernelProfilingInfoParams[0].caps.push_back(CapKernel);\r
-\r
- // set name of operator, an initial set of <id> style operands, and the description\r
-\r
- InstructionDesc[OpSource].operands.push(OperandSource, "");\r
- InstructionDesc[OpSource].operands.push(OperandLiteralNumber, "'Version'");\r
-\r
- InstructionDesc[OpSourceExtension].operands.push(OperandLiteralString, "'Extension'");\r
-\r
- InstructionDesc[OpName].operands.push(OperandId, "'Target'");\r
- InstructionDesc[OpName].operands.push(OperandLiteralString, "'Name'");\r
-\r
- InstructionDesc[OpMemberName].operands.push(OperandId, "'Type'");\r
- InstructionDesc[OpMemberName].operands.push(OperandLiteralNumber, "'Member'");\r
- InstructionDesc[OpMemberName].operands.push(OperandLiteralString, "'Name'");\r
-\r
- InstructionDesc[OpString].operands.push(OperandLiteralString, "'String'");\r
-\r
- InstructionDesc[OpLine].operands.push(OperandId, "'Target'");\r
- InstructionDesc[OpLine].operands.push(OperandId, "'File'");\r
- InstructionDesc[OpLine].operands.push(OperandLiteralNumber, "'Line'");\r
- InstructionDesc[OpLine].operands.push(OperandLiteralNumber, "'Column'");\r
-\r
- InstructionDesc[OpExtension].operands.push(OperandLiteralString, "'Name'");\r
-\r
- InstructionDesc[OpExtInstImport].operands.push(OperandLiteralString, "'Name'");\r
-\r
- InstructionDesc[OpMemoryModel].operands.push(OperandAddressing, "");\r
- InstructionDesc[OpMemoryModel].operands.push(OperandMemory, "");\r
-\r
- InstructionDesc[OpEntryPoint].operands.push(OperandExecutionModel, "");\r
- InstructionDesc[OpEntryPoint].operands.push(OperandId, "'Entry Point'");\r
-\r
- InstructionDesc[OpExecutionMode].operands.push(OperandId, "'Entry Point'");\r
- InstructionDesc[OpExecutionMode].operands.push(OperandExecutionMode, "'Mode'");\r
- InstructionDesc[OpExecutionMode].operands.push(OperandVariableLiterals, "See <<Execution Mode,Execution Mode>>");\r
-\r
- InstructionDesc[OpTypeInt].operands.push(OperandLiteralNumber, "'Width'");\r
- InstructionDesc[OpTypeInt].operands.push(OperandLiteralNumber, "'Signedness'");\r
-\r
- InstructionDesc[OpTypeFloat].operands.push(OperandLiteralNumber, "'Width'");\r
-\r
- InstructionDesc[OpTypeVector].operands.push(OperandId, "'Component type'");\r
- InstructionDesc[OpTypeVector].operands.push(OperandLiteralNumber, "'Component count'");\r
-\r
- InstructionDesc[OpTypeMatrix].capabilities.push_back(CapMatrix);\r
- InstructionDesc[OpTypeMatrix].operands.push(OperandId, "'Column type'");\r
- InstructionDesc[OpTypeMatrix].operands.push(OperandLiteralNumber, "'Column count'");\r
-\r
- InstructionDesc[OpTypeSampler].operands.push(OperandId, "'Sampled Type'");\r
- InstructionDesc[OpTypeSampler].operands.push(OperandDimensionality, "");\r
- InstructionDesc[OpTypeSampler].operands.push(OperandLiteralNumber, "'Content'");\r
- InstructionDesc[OpTypeSampler].operands.push(OperandLiteralNumber, "'Arrayed'");\r
- InstructionDesc[OpTypeSampler].operands.push(OperandLiteralNumber, "'Compare'");\r
- InstructionDesc[OpTypeSampler].operands.push(OperandLiteralNumber, "'MS'");\r
- InstructionDesc[OpTypeSampler].operands.push(OperandOptionalId, "'Qualifier'");\r
-\r
- InstructionDesc[OpTypeArray].operands.push(OperandId, "'Element type'");\r
- InstructionDesc[OpTypeArray].operands.push(OperandId, "'Length'");\r
-\r
- InstructionDesc[OpTypeRuntimeArray].capabilities.push_back(CapShader);\r
- InstructionDesc[OpTypeRuntimeArray].operands.push(OperandId, "'Element type'");\r
-\r
- InstructionDesc[OpTypeStruct].operands.push(OperandVariableIds, "'Member 0 type', +\n'member 1 type', +\n...");\r
-\r
- InstructionDesc[OpTypeOpaque].capabilities.push_back(CapKernel);\r
- InstructionDesc[OpTypeOpaque].operands.push(OperandLiteralString, "The name of the opaque type.");\r
-\r
- InstructionDesc[OpTypePointer].operands.push(OperandStorage, "");\r
- InstructionDesc[OpTypePointer].operands.push(OperandId, "'Type'");\r
-\r
- InstructionDesc[OpTypeEvent].capabilities.push_back(CapKernel);\r
-\r
- InstructionDesc[OpTypeDeviceEvent].capabilities.push_back(CapKernel);\r
-\r
- InstructionDesc[OpTypeReserveId].capabilities.push_back(CapKernel);\r
-\r
- InstructionDesc[OpTypeQueue].capabilities.push_back(CapKernel);\r
-\r
- InstructionDesc[OpTypePipe].operands.push(OperandId, "'Type'");\r
- InstructionDesc[OpTypePipe].operands.push(OperandAccessQualifier, "'Qualifier'");\r
- InstructionDesc[OpTypePipe].capabilities.push_back(CapKernel);\r
-\r
- InstructionDesc[OpTypeFunction].operands.push(OperandId, "'Return Type'");\r
- InstructionDesc[OpTypeFunction].operands.push(OperandVariableIds, "'Parameter 0 Type', +\n'Parameter 1 Type', +\n...");\r
-\r
- InstructionDesc[OpConstant].operands.push(OperandVariableLiterals, "'Value'");\r
-\r
- InstructionDesc[OpConstantComposite].operands.push(OperandVariableIds, "'Constituents'");\r
-\r
- InstructionDesc[OpConstantNullPointer].capabilities.push_back(CapAddr);\r
-\r
- InstructionDesc[OpConstantNullObject].capabilities.push_back(CapKernel);\r
-\r
- InstructionDesc[OpConstantSampler].capabilities.push_back(CapKernel);\r
- InstructionDesc[OpConstantSampler].operands.push(OperandLiteralNumber, "'Mode'");\r
- InstructionDesc[OpConstantSampler].operands.push(OperandLiteralNumber, "'Param'");\r
- InstructionDesc[OpConstantSampler].operands.push(OperandLiteralNumber, "'Filter'");\r
-\r
- InstructionDesc[OpSpecConstantTrue].capabilities.push_back(CapShader);\r
-\r
- InstructionDesc[OpSpecConstantFalse].capabilities.push_back(CapShader);\r
-\r
- InstructionDesc[OpSpecConstant].operands.push(OperandVariableLiterals, "'Value'");\r
- InstructionDesc[OpSpecConstant].capabilities.push_back(CapShader);\r
-\r
- InstructionDesc[OpSpecConstantComposite].operands.push(OperandVariableIds, "'Constituents'");\r
- InstructionDesc[OpSpecConstantComposite].capabilities.push_back(CapShader);\r
-\r
- InstructionDesc[OpVariable].operands.push(OperandStorage, "");\r
- InstructionDesc[OpVariable].operands.push(OperandOptionalId, "'Initializer'");\r
-\r
- InstructionDesc[OpVariableArray].operands.push(OperandStorage, "");\r
- InstructionDesc[OpVariableArray].operands.push(OperandId, "'N'");\r
- InstructionDesc[OpVariableArray].capabilities.push_back(CapAddr);\r
-\r
- InstructionDesc[OpFunction].operands.push(OperandFunction, "");\r
- InstructionDesc[OpFunction].operands.push(OperandId, "'Function Type'");\r
-\r
- InstructionDesc[OpFunctionCall].operands.push(OperandId, "'Function'");\r
- InstructionDesc[OpFunctionCall].operands.push(OperandVariableIds, "'Argument 0', +\n'Argument 1', +\n...");\r
-\r
- InstructionDesc[OpExtInst].operands.push(OperandId, "'Set'");\r
- InstructionDesc[OpExtInst].operands.push(OperandLiteralNumber, "'Instruction'");\r
- InstructionDesc[OpExtInst].operands.push(OperandVariableIds, "'Operand 1', +\n'Operand 2', +\n...");\r
-\r
- InstructionDesc[OpLoad].operands.push(OperandId, "'Pointer'");\r
- InstructionDesc[OpLoad].operands.push(OperandVariableLiterals, "'Memory Access'");\r
-\r
- InstructionDesc[OpStore].operands.push(OperandId, "'Pointer'");\r
- InstructionDesc[OpStore].operands.push(OperandId, "'Object'");\r
- InstructionDesc[OpStore].operands.push(OperandVariableLiterals, "'Memory Access'");\r
-\r
- InstructionDesc[OpPhi].operands.push(OperandVariableIds, "");\r
-\r
- InstructionDesc[OpDecorate].operands.push(OperandId, "'Target'");\r
- InstructionDesc[OpDecorate].operands.push(OperandDecoration, "");\r
- InstructionDesc[OpDecorate].operands.push(OperandVariableLiterals, "See <<Decoration,'Decoration'>>.");\r
-\r
- InstructionDesc[OpMemberDecorate].operands.push(OperandId, "'Structure type'");\r
- InstructionDesc[OpMemberDecorate].operands.push(OperandLiteralNumber, "'Member'");\r
- InstructionDesc[OpMemberDecorate].operands.push(OperandDecoration, "");\r
- InstructionDesc[OpMemberDecorate].operands.push(OperandVariableLiterals, "See <<Decoration,'Decoration'>>.");\r
-\r
- InstructionDesc[OpGroupDecorate].operands.push(OperandId, "'Decoration group'");\r
- InstructionDesc[OpGroupDecorate].operands.push(OperandVariableIds, "'Target', 'Target', ...");\r
-\r
- InstructionDesc[OpGroupMemberDecorate].operands.push(OperandId, "'Decoration group'");\r
- InstructionDesc[OpGroupMemberDecorate].operands.push(OperandVariableIds, "'Target', 'Target', ...");\r
-\r
- InstructionDesc[OpVectorExtractDynamic].operands.push(OperandId, "'Vector'");\r
- InstructionDesc[OpVectorExtractDynamic].operands.push(OperandId, "'Index'");\r
-\r
- InstructionDesc[OpVectorInsertDynamic].operands.push(OperandId, "'Vector'");\r
- InstructionDesc[OpVectorInsertDynamic].operands.push(OperandId, "'Component'");\r
- InstructionDesc[OpVectorInsertDynamic].operands.push(OperandId, "'Index'");\r
-\r
- InstructionDesc[OpVectorShuffle].operands.push(OperandId, "'Vector 1'");\r
- InstructionDesc[OpVectorShuffle].operands.push(OperandId, "'Vector 2'");\r
- InstructionDesc[OpVectorShuffle].operands.push(OperandVariableLiterals, "'Components'");\r
-\r
- InstructionDesc[OpCompositeConstruct].operands.push(OperandVariableIds, "'Constituents'");\r
-\r
- InstructionDesc[OpCompositeExtract].operands.push(OperandId, "'Composite'");\r
- InstructionDesc[OpCompositeExtract].operands.push(OperandVariableLiterals, "'Indexes'");\r
-\r
- InstructionDesc[OpCompositeInsert].operands.push(OperandId, "'Object'");\r
- InstructionDesc[OpCompositeInsert].operands.push(OperandId, "'Composite'");\r
- InstructionDesc[OpCompositeInsert].operands.push(OperandVariableLiterals, "'Indexes'");\r
-\r
- InstructionDesc[OpCopyObject].operands.push(OperandId, "'Operand'");\r
-\r
- InstructionDesc[OpCopyMemory].operands.push(OperandId, "'Target'");\r
- InstructionDesc[OpCopyMemory].operands.push(OperandId, "'Source'");\r
- InstructionDesc[OpCopyMemory].operands.push(OperandVariableLiterals, "'Memory Access'");\r
-\r
- InstructionDesc[OpCopyMemorySized].operands.push(OperandId, "'Target'");\r
- InstructionDesc[OpCopyMemorySized].operands.push(OperandId, "'Source'");\r
- InstructionDesc[OpCopyMemorySized].operands.push(OperandId, "'Size'");\r
- InstructionDesc[OpCopyMemorySized].operands.push(OperandVariableLiterals, "'Memory Access'");\r
-\r
- InstructionDesc[OpCopyMemorySized].capabilities.push_back(CapAddr);\r
-\r
- InstructionDesc[OpSampler].operands.push(OperandId, "'Sampler'");\r
- InstructionDesc[OpSampler].operands.push(OperandId, "'Filter'");\r
-\r
- InstructionDesc[OpTextureSample].operands.push(OperandId, "'Sampler'");\r
- InstructionDesc[OpTextureSample].operands.push(OperandId, "'Coordinate'");\r
- InstructionDesc[OpTextureSample].operands.push(OperandOptionalId, "['Bias']");\r
- InstructionDesc[OpTextureSample].capabilities.push_back(CapShader);\r
-\r
- InstructionDesc[OpTextureSampleDref].operands.push(OperandId, "'Sampler'");\r
- InstructionDesc[OpTextureSampleDref].operands.push(OperandId, "'Coordinate'");\r
- InstructionDesc[OpTextureSampleDref].operands.push(OperandId, "'D~ref~'");\r
- InstructionDesc[OpTextureSampleDref].capabilities.push_back(CapShader);\r
-\r
- InstructionDesc[OpTextureSampleLod].operands.push(OperandId, "'Sampler'");\r
- InstructionDesc[OpTextureSampleLod].operands.push(OperandId, "'Coordinate'");\r
- InstructionDesc[OpTextureSampleLod].operands.push(OperandId, "'Level of Detail'");\r
- InstructionDesc[OpTextureSampleLod].capabilities.push_back(CapShader);\r
-\r
- InstructionDesc[OpTextureSampleProj].operands.push(OperandId, "'Sampler'");\r
- InstructionDesc[OpTextureSampleProj].operands.push(OperandId, "'Coordinate'");\r
- InstructionDesc[OpTextureSampleProj].operands.push(OperandOptionalId, "['Bias']");\r
- InstructionDesc[OpTextureSampleProj].capabilities.push_back(CapShader);\r
-\r
- InstructionDesc[OpTextureSampleGrad].operands.push(OperandId, "'Sampler'");\r
- InstructionDesc[OpTextureSampleGrad].operands.push(OperandId, "'Coordinate'");\r
- InstructionDesc[OpTextureSampleGrad].operands.push(OperandId, "'dx'");\r
- InstructionDesc[OpTextureSampleGrad].operands.push(OperandId, "'dy'");\r
- InstructionDesc[OpTextureSampleGrad].capabilities.push_back(CapShader);\r
-\r
- InstructionDesc[OpTextureSampleOffset].operands.push(OperandId, "'Sampler'");\r
- InstructionDesc[OpTextureSampleOffset].operands.push(OperandId, "'Coordinate'");\r
- InstructionDesc[OpTextureSampleOffset].operands.push(OperandId, "'Offset'");\r
- InstructionDesc[OpTextureSampleOffset].operands.push(OperandOptionalId, "['Bias']");\r
- InstructionDesc[OpTextureSampleOffset].capabilities.push_back(CapShader);\r
-\r
- InstructionDesc[OpTextureSampleProjLod].operands.push(OperandId, "'Sampler'");\r
- InstructionDesc[OpTextureSampleProjLod].operands.push(OperandId, "'Coordinate'");\r
- InstructionDesc[OpTextureSampleProjLod].operands.push(OperandId, "'Level of Detail'");\r
- InstructionDesc[OpTextureSampleProjLod].capabilities.push_back(CapShader);\r
-\r
- InstructionDesc[OpTextureSampleProjGrad].operands.push(OperandId, "'Sampler'");\r
- InstructionDesc[OpTextureSampleProjGrad].operands.push(OperandId, "'Coordinate'");\r
- InstructionDesc[OpTextureSampleProjGrad].operands.push(OperandId, "'dx'");\r
- InstructionDesc[OpTextureSampleProjGrad].operands.push(OperandId, "'dy'");\r
- InstructionDesc[OpTextureSampleProjGrad].capabilities.push_back(CapShader);\r
-\r
- InstructionDesc[OpTextureSampleLodOffset].operands.push(OperandId, "'Sampler'");\r
- InstructionDesc[OpTextureSampleLodOffset].operands.push(OperandId, "'Coordinate'");\r
- InstructionDesc[OpTextureSampleLodOffset].operands.push(OperandId, "'Level of Detail'");\r
- InstructionDesc[OpTextureSampleLodOffset].operands.push(OperandId, "'Offset'");\r
- InstructionDesc[OpTextureSampleLodOffset].capabilities.push_back(CapShader);\r
-\r
- InstructionDesc[OpTextureSampleProjOffset].operands.push(OperandId, "'Sampler'");\r
- InstructionDesc[OpTextureSampleProjOffset].operands.push(OperandId, "'Coordinate'");\r
- InstructionDesc[OpTextureSampleProjOffset].operands.push(OperandId, "'Offset'");\r
- InstructionDesc[OpTextureSampleProjOffset].operands.push(OperandOptionalId, "['Bias']");\r
- InstructionDesc[OpTextureSampleProjOffset].capabilities.push_back(CapShader);\r
-\r
- InstructionDesc[OpTextureSampleGradOffset].operands.push(OperandId, "'Sampler'");\r
- InstructionDesc[OpTextureSampleGradOffset].operands.push(OperandId, "'Coordinate'");\r
- InstructionDesc[OpTextureSampleGradOffset].operands.push(OperandId, "'dx'");\r
- InstructionDesc[OpTextureSampleGradOffset].operands.push(OperandId, "'dy'");\r
- InstructionDesc[OpTextureSampleGradOffset].operands.push(OperandId, "'Offset'");\r
- InstructionDesc[OpTextureSampleGradOffset].capabilities.push_back(CapShader);\r
-\r
- InstructionDesc[OpTextureSampleProjLodOffset].operands.push(OperandId, "'Sampler'");\r
- InstructionDesc[OpTextureSampleProjLodOffset].operands.push(OperandId, "'Coordinate'");\r
- InstructionDesc[OpTextureSampleProjLodOffset].operands.push(OperandId, "'Level of Detail'");\r
- InstructionDesc[OpTextureSampleProjLodOffset].operands.push(OperandId, "'Offset'");\r
- InstructionDesc[OpTextureSampleProjLodOffset].capabilities.push_back(CapShader);\r
-\r
- InstructionDesc[OpTextureSampleProjGradOffset].operands.push(OperandId, "'Sampler'");\r
- InstructionDesc[OpTextureSampleProjGradOffset].operands.push(OperandId, "'Coordinate'");\r
- InstructionDesc[OpTextureSampleProjGradOffset].operands.push(OperandId, "'dx'");\r
- InstructionDesc[OpTextureSampleProjGradOffset].operands.push(OperandId, "'dy'");\r
- InstructionDesc[OpTextureSampleProjGradOffset].operands.push(OperandId, "'Offset'");\r
- InstructionDesc[OpTextureSampleProjGradOffset].capabilities.push_back(CapShader);\r
-\r
- InstructionDesc[OpTextureFetchTexelLod].operands.push(OperandId, "'Sampler'");\r
- InstructionDesc[OpTextureFetchTexelLod].operands.push(OperandId, "'Coordinate'");\r
- InstructionDesc[OpTextureFetchTexelLod].operands.push(OperandId, "'Level of Detail'");\r
- InstructionDesc[OpTextureFetchTexelLod].capabilities.push_back(CapShader);\r
-\r
- InstructionDesc[OpTextureFetchTexelOffset].operands.push(OperandId, "'Sampler'");\r
- InstructionDesc[OpTextureFetchTexelOffset].operands.push(OperandId, "'Coordinate'");\r
- InstructionDesc[OpTextureFetchTexelOffset].operands.push(OperandId, "'Offset'");\r
- InstructionDesc[OpTextureFetchTexelOffset].capabilities.push_back(CapShader);\r
-\r
- InstructionDesc[OpTextureFetchSample].operands.push(OperandId, "'Sampler'");\r
- InstructionDesc[OpTextureFetchSample].operands.push(OperandId, "'Coordinate'");\r
- InstructionDesc[OpTextureFetchSample].operands.push(OperandId, "'Sample'");\r
- InstructionDesc[OpTextureFetchSample].capabilities.push_back(CapShader);\r
-\r
- InstructionDesc[OpTextureFetchTexel].operands.push(OperandId, "'Sampler'");\r
- InstructionDesc[OpTextureFetchTexel].operands.push(OperandId, "'Element'");\r
- InstructionDesc[OpTextureFetchTexel].capabilities.push_back(CapShader);\r
-\r
- InstructionDesc[OpTextureGather].operands.push(OperandId, "'Sampler'");\r
- InstructionDesc[OpTextureGather].operands.push(OperandId, "'Coordinate'");\r
- InstructionDesc[OpTextureGather].operands.push(OperandId, "'Component'");\r
- InstructionDesc[OpTextureGather].capabilities.push_back(CapShader);\r
-\r
- InstructionDesc[OpTextureGatherOffset].operands.push(OperandId, "'Sampler'");\r
- InstructionDesc[OpTextureGatherOffset].operands.push(OperandId, "'Coordinate'");\r
- InstructionDesc[OpTextureGatherOffset].operands.push(OperandId, "'Component'");\r
- InstructionDesc[OpTextureGatherOffset].operands.push(OperandId, "'Offset'");\r
- InstructionDesc[OpTextureGatherOffset].capabilities.push_back(CapShader);\r
-\r
- InstructionDesc[OpTextureGatherOffsets].operands.push(OperandId, "'Sampler'");\r
- InstructionDesc[OpTextureGatherOffsets].operands.push(OperandId, "'Coordinate'");\r
- InstructionDesc[OpTextureGatherOffsets].operands.push(OperandId, "'Component'");\r
- InstructionDesc[OpTextureGatherOffsets].operands.push(OperandId, "'Offsets'");\r
- InstructionDesc[OpTextureGatherOffsets].capabilities.push_back(CapShader);\r
-\r
- InstructionDesc[OpTextureQuerySizeLod].operands.push(OperandId, "'Sampler'");\r
- InstructionDesc[OpTextureQuerySizeLod].operands.push(OperandId, "'Level of Detail'");\r
- InstructionDesc[OpTextureQuerySizeLod].capabilities.push_back(CapShader);\r
-\r
- InstructionDesc[OpTextureQuerySize].operands.push(OperandId, "'Sampler'");\r
- InstructionDesc[OpTextureQuerySize].capabilities.push_back(CapShader);\r
-\r
- InstructionDesc[OpTextureQueryLod].operands.push(OperandId, "'Sampler'");\r
- InstructionDesc[OpTextureQueryLod].operands.push(OperandId, "'Coordinate'");\r
- InstructionDesc[OpTextureQueryLod].capabilities.push_back(CapShader);\r
-\r
- InstructionDesc[OpTextureQueryLevels].operands.push(OperandId, "'Sampler'");\r
- InstructionDesc[OpTextureQueryLevels].capabilities.push_back(CapShader);\r
-\r
- InstructionDesc[OpTextureQuerySamples].operands.push(OperandId, "'Sampler'");\r
- InstructionDesc[OpTextureQuerySamples].capabilities.push_back(CapShader);\r
-\r
- InstructionDesc[OpAccessChain].operands.push(OperandId, "'Base'");\r
- InstructionDesc[OpAccessChain].operands.push(OperandVariableIds, "'Indexes'");\r
-\r
- InstructionDesc[OpInBoundsAccessChain].operands.push(OperandId, "'Base'");\r
- InstructionDesc[OpInBoundsAccessChain].operands.push(OperandVariableIds, "'Indexes'");\r
-\r
- InstructionDesc[OpSNegate].operands.push(OperandId, "'Operand'");\r
-\r
- InstructionDesc[OpFNegate].operands.push(OperandId, "'Operand'");\r
-\r
- InstructionDesc[OpNot].operands.push(OperandId, "'Operand'");\r
-\r
- InstructionDesc[OpAny].operands.push(OperandId, "'Vector'");\r
-\r
- InstructionDesc[OpAll].operands.push(OperandId, "'Vector'");\r
-\r
- InstructionDesc[OpConvertFToU].operands.push(OperandId, "'Float Value'");\r
-\r
- InstructionDesc[OpConvertFToS].operands.push(OperandId, "'Float Value'");\r
-\r
- InstructionDesc[OpConvertSToF].operands.push(OperandId, "'Signed Value'");\r
-\r
- InstructionDesc[OpConvertUToF].operands.push(OperandId, "'Unsigned value'");\r
-\r
- InstructionDesc[OpUConvert].operands.push(OperandId, "'Unsigned value'");\r
-\r
- InstructionDesc[OpSConvert].operands.push(OperandId, "'Signed Value'");\r
-\r
- InstructionDesc[OpFConvert].operands.push(OperandId, "'Float Value'");\r
-\r
- InstructionDesc[OpSatConvertSToU].operands.push(OperandId, "'Signed Value'");\r
- InstructionDesc[OpSatConvertSToU].capabilities.push_back(CapKernel);\r
-\r
- InstructionDesc[OpSatConvertUToS].operands.push(OperandId, "'Unsigned Value'");\r
- InstructionDesc[OpSatConvertUToS].capabilities.push_back(CapKernel);\r
-\r
- InstructionDesc[OpConvertPtrToU].operands.push(OperandId, "'Pointer'");\r
- InstructionDesc[OpConvertPtrToU].capabilities.push_back(CapAddr);\r
-\r
- InstructionDesc[OpConvertUToPtr].operands.push(OperandId, "'Integer value'");\r
- InstructionDesc[OpConvertUToPtr].capabilities.push_back(CapAddr);\r
-\r
- InstructionDesc[OpPtrCastToGeneric].operands.push(OperandId, "'Source pointer'");\r
- InstructionDesc[OpPtrCastToGeneric].capabilities.push_back(CapKernel);\r
-\r
-\r
- InstructionDesc[OpGenericCastToPtr].operands.push(OperandId, "'Source pointer'");\r
- InstructionDesc[OpGenericCastToPtr].capabilities.push_back(CapKernel);\r
-\r
- InstructionDesc[OpGenericCastToPtrExplicit].operands.push(OperandId, "'Source pointer'");\r
- InstructionDesc[OpGenericCastToPtrExplicit].operands.push(OperandStorage, "'storage'");\r
- InstructionDesc[OpGenericCastToPtrExplicit].capabilities.push_back(CapKernel);\r
-\r
- InstructionDesc[OpGenericPtrMemSemantics].operands.push(OperandId, "'ptr'");\r
- InstructionDesc[OpGenericPtrMemSemantics].capabilities.push_back(CapKernel);\r
-\r
- InstructionDesc[OpBitcast].operands.push(OperandId, "'Operand'");\r
-\r
- InstructionDesc[OpTranspose].capabilities.push_back(CapMatrix);\r
- InstructionDesc[OpTranspose].operands.push(OperandId, "'Matrix'");\r
-\r
- InstructionDesc[OpIsNan].operands.push(OperandId, "'x'");\r
-\r
- InstructionDesc[OpIsInf].operands.push(OperandId, "'x'");\r
-\r
- InstructionDesc[OpIsFinite].capabilities.push_back(CapKernel);\r
- InstructionDesc[OpIsFinite].operands.push(OperandId, "'x'");\r
-\r
- InstructionDesc[OpIsNormal].capabilities.push_back(CapKernel);\r
- InstructionDesc[OpIsNormal].operands.push(OperandId, "'x'");\r
-\r
- InstructionDesc[OpSignBitSet].capabilities.push_back(CapKernel);\r
- InstructionDesc[OpSignBitSet].operands.push(OperandId, "'x'");\r
-\r
- InstructionDesc[OpLessOrGreater].capabilities.push_back(CapKernel);\r
- InstructionDesc[OpLessOrGreater].operands.push(OperandId, "'x'");\r
- InstructionDesc[OpLessOrGreater].operands.push(OperandId, "'y'");\r
-\r
- InstructionDesc[OpOrdered].capabilities.push_back(CapKernel);\r
- InstructionDesc[OpOrdered].operands.push(OperandId, "'x'");\r
- InstructionDesc[OpOrdered].operands.push(OperandId, "'y'");\r
-\r
- InstructionDesc[OpUnordered].capabilities.push_back(CapKernel);\r
- InstructionDesc[OpUnordered].operands.push(OperandId, "'x'");\r
- InstructionDesc[OpUnordered].operands.push(OperandId, "'y'");\r
-\r
- InstructionDesc[OpArrayLength].operands.push(OperandId, "'Structure'");\r
- InstructionDesc[OpArrayLength].operands.push(OperandLiteralNumber, "'Array member'");\r
- InstructionDesc[OpArrayLength].capabilities.push_back(CapShader);\r
-\r
- InstructionDesc[OpIAdd].operands.push(OperandId, "'Operand 1'");\r
- InstructionDesc[OpIAdd].operands.push(OperandId, "'Operand 2'");\r
-\r
- InstructionDesc[OpFAdd].operands.push(OperandId, "'Operand 1'");\r
- InstructionDesc[OpFAdd].operands.push(OperandId, "'Operand 2'");\r
-\r
- InstructionDesc[OpISub].operands.push(OperandId, "'Operand 1'");\r
- InstructionDesc[OpISub].operands.push(OperandId, "'Operand 2'");\r
-\r
- InstructionDesc[OpFSub].operands.push(OperandId, "'Operand 1'");\r
- InstructionDesc[OpFSub].operands.push(OperandId, "'Operand 2'");\r
-\r
- InstructionDesc[OpIMul].operands.push(OperandId, "'Operand 1'");\r
- InstructionDesc[OpIMul].operands.push(OperandId, "'Operand 2'");\r
-\r
- InstructionDesc[OpFMul].operands.push(OperandId, "'Operand 1'");\r
- InstructionDesc[OpFMul].operands.push(OperandId, "'Operand 2'");\r
-\r
- InstructionDesc[OpUDiv].operands.push(OperandId, "'Operand 1'");\r
- InstructionDesc[OpUDiv].operands.push(OperandId, "'Operand 2'");\r
-\r
- InstructionDesc[OpSDiv].operands.push(OperandId, "'Operand 1'");\r
- InstructionDesc[OpSDiv].operands.push(OperandId, "'Operand 2'");\r
-\r
- InstructionDesc[OpFDiv].operands.push(OperandId, "'Operand 1'");\r
- InstructionDesc[OpFDiv].operands.push(OperandId, "'Operand 2'");\r
-\r
- InstructionDesc[OpUMod].operands.push(OperandId, "'Operand 1'");\r
- InstructionDesc[OpUMod].operands.push(OperandId, "'Operand 2'");\r
-\r
- InstructionDesc[OpSRem].operands.push(OperandId, "'Operand 1'");\r
- InstructionDesc[OpSRem].operands.push(OperandId, "'Operand 2'");\r
-\r
- InstructionDesc[OpSMod].operands.push(OperandId, "'Operand 1'");\r
- InstructionDesc[OpSMod].operands.push(OperandId, "'Operand 2'");\r
-\r
- InstructionDesc[OpFRem].operands.push(OperandId, "'Operand 1'");\r
- InstructionDesc[OpFRem].operands.push(OperandId, "'Operand 2'");\r
-\r
- InstructionDesc[OpFMod].operands.push(OperandId, "'Operand 1'");\r
- InstructionDesc[OpFMod].operands.push(OperandId, "'Operand 2'");\r
-\r
- InstructionDesc[OpVectorTimesScalar].operands.push(OperandId, "'Vector'");\r
- InstructionDesc[OpVectorTimesScalar].operands.push(OperandId, "'Scalar'");\r
-\r
- InstructionDesc[OpMatrixTimesScalar].capabilities.push_back(CapMatrix);\r
- InstructionDesc[OpMatrixTimesScalar].operands.push(OperandId, "'Matrix'");\r
- InstructionDesc[OpMatrixTimesScalar].operands.push(OperandId, "'Scalar'");\r
-\r
- InstructionDesc[OpVectorTimesMatrix].capabilities.push_back(CapMatrix);\r
- InstructionDesc[OpVectorTimesMatrix].operands.push(OperandId, "'Vector'");\r
- InstructionDesc[OpVectorTimesMatrix].operands.push(OperandId, "'Matrix'");\r
-\r
- InstructionDesc[OpMatrixTimesVector].capabilities.push_back(CapMatrix);\r
- InstructionDesc[OpMatrixTimesVector].operands.push(OperandId, "'Matrix'");\r
- InstructionDesc[OpMatrixTimesVector].operands.push(OperandId, "'Vector'");\r
-\r
- InstructionDesc[OpMatrixTimesMatrix].capabilities.push_back(CapMatrix);\r
- InstructionDesc[OpMatrixTimesMatrix].operands.push(OperandId, "'LeftMatrix'");\r
- InstructionDesc[OpMatrixTimesMatrix].operands.push(OperandId, "'RightMatrix'");\r
-\r
- InstructionDesc[OpOuterProduct].capabilities.push_back(CapMatrix);\r
- InstructionDesc[OpOuterProduct].operands.push(OperandId, "'Vector 1'");\r
- InstructionDesc[OpOuterProduct].operands.push(OperandId, "'Vector 2'");\r
-\r
- InstructionDesc[OpDot].operands.push(OperandId, "'Vector 1'");\r
- InstructionDesc[OpDot].operands.push(OperandId, "'Vector 2'");\r
-\r
- InstructionDesc[OpShiftRightLogical].operands.push(OperandId, "'Operand 1'");\r
- InstructionDesc[OpShiftRightLogical].operands.push(OperandId, "'Operand 2'");\r
-\r
- InstructionDesc[OpShiftRightArithmetic].operands.push(OperandId, "'Operand 1'");\r
- InstructionDesc[OpShiftRightArithmetic].operands.push(OperandId, "'Operand 2'");\r
-\r
- InstructionDesc[OpShiftLeftLogical].operands.push(OperandId, "'Operand 1'");\r
- InstructionDesc[OpShiftLeftLogical].operands.push(OperandId, "'Operand 2'");\r
-\r
- InstructionDesc[OpLogicalOr].operands.push(OperandId, "'Operand 1'");\r
- InstructionDesc[OpLogicalOr].operands.push(OperandId, "'Operand 2'");\r
-\r
- InstructionDesc[OpLogicalXor].operands.push(OperandId, "'Operand 1'");\r
- InstructionDesc[OpLogicalXor].operands.push(OperandId, "'Operand 2'");\r
-\r
- InstructionDesc[OpLogicalAnd].operands.push(OperandId, "'Operand 1'");\r
- InstructionDesc[OpLogicalAnd].operands.push(OperandId, "'Operand 2'");\r
-\r
- InstructionDesc[OpBitwiseOr].operands.push(OperandId, "'Operand 1'");\r
- InstructionDesc[OpBitwiseOr].operands.push(OperandId, "'Operand 2'");\r
-\r
- InstructionDesc[OpBitwiseXor].operands.push(OperandId, "'Operand 1'");\r
- InstructionDesc[OpBitwiseXor].operands.push(OperandId, "'Operand 2'");\r
-\r
- InstructionDesc[OpBitwiseAnd].operands.push(OperandId, "'Operand 1'");\r
- InstructionDesc[OpBitwiseAnd].operands.push(OperandId, "'Operand 2'");\r
-\r
- InstructionDesc[OpSelect].operands.push(OperandId, "'Condition'");\r
- InstructionDesc[OpSelect].operands.push(OperandId, "'Object 1'");\r
- InstructionDesc[OpSelect].operands.push(OperandId, "'Object 2'");\r
-\r
- InstructionDesc[OpIEqual].operands.push(OperandId, "'Operand 1'");\r
- InstructionDesc[OpIEqual].operands.push(OperandId, "'Operand 2'");\r
-\r
- InstructionDesc[OpFOrdEqual].operands.push(OperandId, "'Operand 1'");\r
- InstructionDesc[OpFOrdEqual].operands.push(OperandId, "'Operand 2'");\r
-\r
- InstructionDesc[OpFUnordEqual].operands.push(OperandId, "'Operand 1'");\r
- InstructionDesc[OpFUnordEqual].operands.push(OperandId, "'Operand 2'");\r
-\r
- InstructionDesc[OpINotEqual].operands.push(OperandId, "'Operand 1'");\r
- InstructionDesc[OpINotEqual].operands.push(OperandId, "'Operand 2'");\r
-\r
- InstructionDesc[OpFOrdNotEqual].operands.push(OperandId, "'Operand 1'");\r
- InstructionDesc[OpFOrdNotEqual].operands.push(OperandId, "'Operand 2'");\r
-\r
- InstructionDesc[OpFUnordNotEqual].operands.push(OperandId, "'Operand 1'");\r
- InstructionDesc[OpFUnordNotEqual].operands.push(OperandId, "'Operand 2'");\r
-\r
- InstructionDesc[OpULessThan].operands.push(OperandId, "'Operand 1'");\r
- InstructionDesc[OpULessThan].operands.push(OperandId, "'Operand 2'");\r
-\r
- InstructionDesc[OpSLessThan].operands.push(OperandId, "'Operand 1'");\r
- InstructionDesc[OpSLessThan].operands.push(OperandId, "'Operand 2'");\r
-\r
- InstructionDesc[OpFOrdLessThan].operands.push(OperandId, "'Operand 1'");\r
- InstructionDesc[OpFOrdLessThan].operands.push(OperandId, "'Operand 2'");\r
-\r
- InstructionDesc[OpFUnordLessThan].operands.push(OperandId, "'Operand 1'");\r
- InstructionDesc[OpFUnordLessThan].operands.push(OperandId, "'Operand 2'");\r
-\r
- InstructionDesc[OpUGreaterThan].operands.push(OperandId, "'Operand 1'");\r
- InstructionDesc[OpUGreaterThan].operands.push(OperandId, "'Operand 2'");\r
-\r
- InstructionDesc[OpSGreaterThan].operands.push(OperandId, "'Operand 1'");\r
- InstructionDesc[OpSGreaterThan].operands.push(OperandId, "'Operand 2'");\r
-\r
- InstructionDesc[OpFOrdGreaterThan].operands.push(OperandId, "'Operand 1'");\r
- InstructionDesc[OpFOrdGreaterThan].operands.push(OperandId, "'Operand 2'");\r
-\r
- InstructionDesc[OpFUnordGreaterThan].operands.push(OperandId, "'Operand 1'");\r
- InstructionDesc[OpFUnordGreaterThan].operands.push(OperandId, "'Operand 2'");\r
-\r
- InstructionDesc[OpULessThanEqual].operands.push(OperandId, "'Operand 1'");\r
- InstructionDesc[OpULessThanEqual].operands.push(OperandId, "'Operand 2'");\r
-\r
- InstructionDesc[OpSLessThanEqual].operands.push(OperandId, "'Operand 1'");\r
- InstructionDesc[OpSLessThanEqual].operands.push(OperandId, "'Operand 2'");\r
-\r
- InstructionDesc[OpFOrdLessThanEqual].operands.push(OperandId, "'Operand 1'");\r
- InstructionDesc[OpFOrdLessThanEqual].operands.push(OperandId, "'Operand 2'");\r
-\r
- InstructionDesc[OpFUnordLessThanEqual].operands.push(OperandId, "'Operand 1'");\r
- InstructionDesc[OpFUnordLessThanEqual].operands.push(OperandId, "'Operand 2'");\r
-\r
- InstructionDesc[OpUGreaterThanEqual].operands.push(OperandId, "'Operand 1'");\r
- InstructionDesc[OpUGreaterThanEqual].operands.push(OperandId, "'Operand 2'");\r
-\r
- InstructionDesc[OpSGreaterThanEqual].operands.push(OperandId, "'Operand 1'");\r
- InstructionDesc[OpSGreaterThanEqual].operands.push(OperandId, "'Operand 2'");\r
-\r
- InstructionDesc[OpFOrdGreaterThanEqual].operands.push(OperandId, "'Operand 1'");\r
- InstructionDesc[OpFOrdGreaterThanEqual].operands.push(OperandId, "'Operand 2'");\r
-\r
- InstructionDesc[OpFUnordGreaterThanEqual].operands.push(OperandId, "'Operand 1'");\r
- InstructionDesc[OpFUnordGreaterThanEqual].operands.push(OperandId, "'Operand 2'");\r
-\r
- InstructionDesc[OpDPdx].capabilities.push_back(CapShader);\r
- InstructionDesc[OpDPdx].operands.push(OperandId, "'P'");\r
-\r
- InstructionDesc[OpDPdy].capabilities.push_back(CapShader);\r
- InstructionDesc[OpDPdy].operands.push(OperandId, "'P'");\r
-\r
- InstructionDesc[OpFwidth].capabilities.push_back(CapShader);\r
- InstructionDesc[OpFwidth].operands.push(OperandId, "'P'");\r
-\r
- InstructionDesc[OpDPdxFine].capabilities.push_back(CapShader);\r
- InstructionDesc[OpDPdxFine].operands.push(OperandId, "'P'");\r
-\r
- InstructionDesc[OpDPdyFine].capabilities.push_back(CapShader);\r
- InstructionDesc[OpDPdyFine].operands.push(OperandId, "'P'");\r
-\r
- InstructionDesc[OpFwidthFine].capabilities.push_back(CapShader);\r
- InstructionDesc[OpFwidthFine].operands.push(OperandId, "'P'");\r
-\r
- InstructionDesc[OpDPdxCoarse].capabilities.push_back(CapShader);\r
- InstructionDesc[OpDPdxCoarse].operands.push(OperandId, "'P'");\r
-\r
- InstructionDesc[OpDPdyCoarse].capabilities.push_back(CapShader);\r
- InstructionDesc[OpDPdyCoarse].operands.push(OperandId, "'P'");\r
-\r
- InstructionDesc[OpFwidthCoarse].capabilities.push_back(CapShader);\r
- InstructionDesc[OpFwidthCoarse].operands.push(OperandId, "'P'");\r
-\r
- InstructionDesc[OpEmitVertex].capabilities.push_back(CapGeom);\r
-\r
- InstructionDesc[OpEndPrimitive].capabilities.push_back(CapGeom);\r
-\r
- InstructionDesc[OpEmitStreamVertex].operands.push(OperandId, "'Stream'");\r
- InstructionDesc[OpEmitStreamVertex].capabilities.push_back(CapGeom);\r
-\r
- InstructionDesc[OpEndStreamPrimitive].operands.push(OperandId, "'Stream'");\r
- InstructionDesc[OpEndStreamPrimitive].capabilities.push_back(CapGeom);\r
-\r
- InstructionDesc[OpControlBarrier].operands.push(OperandExecutionScope, "'Scope'");\r
-\r
- InstructionDesc[OpMemoryBarrier].operands.push(OperandExecutionScope, "'Scope'");\r
- InstructionDesc[OpMemoryBarrier].operands.push(OperandMemorySemantics, "'Semantics'");\r
-\r
- InstructionDesc[OpImagePointer].operands.push(OperandId, "'Image'");\r
- InstructionDesc[OpImagePointer].operands.push(OperandId, "'Coordinate'");\r
- InstructionDesc[OpImagePointer].operands.push(OperandId, "'Sample'");\r
-\r
- InstructionDesc[OpAtomicInit].operands.push(OperandId, "'Pointer'");\r
- InstructionDesc[OpAtomicInit].operands.push(OperandId, "'Value'");\r
-\r
- InstructionDesc[OpAtomicLoad].operands.push(OperandId, "'Pointer'");\r
- InstructionDesc[OpAtomicLoad].operands.push(OperandExecutionScope, "'Scope'");\r
- InstructionDesc[OpAtomicLoad].operands.push(OperandMemorySemantics, "'Semantics'");\r
-\r
- InstructionDesc[OpAtomicStore].operands.push(OperandId, "'Pointer'");\r
- InstructionDesc[OpAtomicStore].operands.push(OperandExecutionScope, "'Scope'");\r
- InstructionDesc[OpAtomicStore].operands.push(OperandMemorySemantics, "'Semantics'");\r
- InstructionDesc[OpAtomicStore].operands.push(OperandId, "'Value'");\r
-\r
- InstructionDesc[OpAtomicExchange].operands.push(OperandId, "'Pointer'");\r
- InstructionDesc[OpAtomicExchange].operands.push(OperandExecutionScope, "'Scope'");\r
- InstructionDesc[OpAtomicExchange].operands.push(OperandMemorySemantics, "'Semantics'");\r
- InstructionDesc[OpAtomicExchange].operands.push(OperandId, "'Value'");\r
-\r
- InstructionDesc[OpAtomicCompareExchange].operands.push(OperandId, "'Pointer'");\r
- InstructionDesc[OpAtomicCompareExchange].operands.push(OperandExecutionScope, "'Scope'");\r
- InstructionDesc[OpAtomicCompareExchange].operands.push(OperandMemorySemantics, "'Semantics'");\r
- InstructionDesc[OpAtomicCompareExchange].operands.push(OperandId, "'Value'");\r
- InstructionDesc[OpAtomicCompareExchange].operands.push(OperandId, "'Comparator'");\r
-\r
- InstructionDesc[OpAtomicCompareExchangeWeak].operands.push(OperandId, "'Pointer'");\r
- InstructionDesc[OpAtomicCompareExchangeWeak].operands.push(OperandExecutionScope, "'Scope'");\r
- InstructionDesc[OpAtomicCompareExchangeWeak].operands.push(OperandMemorySemantics, "'Semantics'");\r
- InstructionDesc[OpAtomicCompareExchangeWeak].operands.push(OperandId, "'Value'");\r
- InstructionDesc[OpAtomicCompareExchangeWeak].operands.push(OperandId, "'Comparator'");\r
-\r
- InstructionDesc[OpAtomicIIncrement].operands.push(OperandId, "'Pointer'");\r
- InstructionDesc[OpAtomicIIncrement].operands.push(OperandExecutionScope, "'Scope'");\r
- InstructionDesc[OpAtomicIIncrement].operands.push(OperandMemorySemantics, "'Semantics'");\r
-\r
- InstructionDesc[OpAtomicIDecrement].operands.push(OperandId, "'Pointer'");\r
- InstructionDesc[OpAtomicIDecrement].operands.push(OperandExecutionScope, "'Scope'");\r
- InstructionDesc[OpAtomicIDecrement].operands.push(OperandMemorySemantics, "'Semantics'");\r
-\r
- InstructionDesc[OpAtomicIAdd].operands.push(OperandId, "'Pointer'");\r
- InstructionDesc[OpAtomicIAdd].operands.push(OperandExecutionScope, "'Scope'");\r
- InstructionDesc[OpAtomicIAdd].operands.push(OperandMemorySemantics, "'Semantics'");\r
- InstructionDesc[OpAtomicIAdd].operands.push(OperandId, "'Value'");\r
-\r
- InstructionDesc[OpAtomicISub].operands.push(OperandId, "'Pointer'");\r
- InstructionDesc[OpAtomicISub].operands.push(OperandExecutionScope, "'Scope'");\r
- InstructionDesc[OpAtomicISub].operands.push(OperandMemorySemantics, "'Semantics'");\r
- InstructionDesc[OpAtomicISub].operands.push(OperandId, "'Value'");\r
-\r
- InstructionDesc[OpAtomicUMin].operands.push(OperandId, "'Pointer'");\r
- InstructionDesc[OpAtomicUMin].operands.push(OperandExecutionScope, "'Scope'");\r
- InstructionDesc[OpAtomicUMin].operands.push(OperandMemorySemantics, "'Semantics'");\r
- InstructionDesc[OpAtomicUMin].operands.push(OperandId, "'Value'");\r
-\r
- InstructionDesc[OpAtomicUMax].operands.push(OperandId, "'Pointer'");\r
- InstructionDesc[OpAtomicUMax].operands.push(OperandExecutionScope, "'Scope'");\r
- InstructionDesc[OpAtomicUMax].operands.push(OperandMemorySemantics, "'Semantics'");\r
- InstructionDesc[OpAtomicUMax].operands.push(OperandId, "'Value'");\r
-\r
- InstructionDesc[OpAtomicIMin].operands.push(OperandId, "'Pointer'");\r
- InstructionDesc[OpAtomicIMin].operands.push(OperandExecutionScope, "'Scope'");\r
- InstructionDesc[OpAtomicIMin].operands.push(OperandMemorySemantics, "'Semantics'");\r
- InstructionDesc[OpAtomicIMin].operands.push(OperandId, "'Value'");\r
-\r
- InstructionDesc[OpAtomicIMax].operands.push(OperandId, "'Pointer'");\r
- InstructionDesc[OpAtomicIMax].operands.push(OperandExecutionScope, "'Scope'");\r
- InstructionDesc[OpAtomicIMax].operands.push(OperandMemorySemantics, "'Semantics'");\r
- InstructionDesc[OpAtomicIMax].operands.push(OperandId, "'Value'");\r
-\r
- InstructionDesc[OpAtomicAnd].operands.push(OperandId, "'Pointer'");\r
- InstructionDesc[OpAtomicAnd].operands.push(OperandExecutionScope, "'Scope'");\r
- InstructionDesc[OpAtomicAnd].operands.push(OperandMemorySemantics, "'Semantics'");\r
- InstructionDesc[OpAtomicAnd].operands.push(OperandId, "'Value'");\r
-\r
- InstructionDesc[OpAtomicOr].operands.push(OperandId, "'Pointer'");\r
- InstructionDesc[OpAtomicOr].operands.push(OperandExecutionScope, "'Scope'");\r
- InstructionDesc[OpAtomicOr].operands.push(OperandMemorySemantics, "'Semantics'");\r
- InstructionDesc[OpAtomicOr].operands.push(OperandId, "'Value'");\r
-\r
- InstructionDesc[OpAtomicXor].operands.push(OperandId, "'Pointer'");\r
- InstructionDesc[OpAtomicXor].operands.push(OperandExecutionScope, "'Scope'");\r
- InstructionDesc[OpAtomicXor].operands.push(OperandMemorySemantics, "'Semantics'");\r
- InstructionDesc[OpAtomicXor].operands.push(OperandId, "'Value'");\r
-\r
- InstructionDesc[OpLoopMerge].operands.push(OperandId, "'Label'");\r
- InstructionDesc[OpLoopMerge].operands.push(OperandLoop, "");\r
-\r
- InstructionDesc[OpSelectionMerge].operands.push(OperandId, "'Label'");\r
- InstructionDesc[OpSelectionMerge].operands.push(OperandSelect, "");\r
-\r
- InstructionDesc[OpBranch].operands.push(OperandId, "'Target Label'");\r
-\r
- InstructionDesc[OpBranchConditional].operands.push(OperandId, "'Condition'");\r
- InstructionDesc[OpBranchConditional].operands.push(OperandId, "'True Label'");\r
- InstructionDesc[OpBranchConditional].operands.push(OperandId, "'False Label'");\r
- InstructionDesc[OpBranchConditional].operands.push(OperandVariableLiterals, "'Branch weights'");\r
-\r
- InstructionDesc[OpSwitch].operands.push(OperandId, "'Selector'");\r
- InstructionDesc[OpSwitch].operands.push(OperandId, "'Default'");\r
- InstructionDesc[OpSwitch].operands.push(OperandVariableLiteralId, "'Target'");\r
-\r
- InstructionDesc[OpKill].capabilities.push_back(CapShader);\r
-\r
- InstructionDesc[OpReturnValue].operands.push(OperandId, "'Value'");\r
-\r
- InstructionDesc[OpUnreachable].capabilities.push_back(CapKernel);\r
-\r
- InstructionDesc[OpLifetimeStart].operands.push(OperandId, "");\r
- InstructionDesc[OpLifetimeStart].operands.push(OperandLiteralNumber, "");\r
-\r
- InstructionDesc[OpLifetimeStop].operands.push(OperandId, "");\r
- InstructionDesc[OpLifetimeStop].operands.push(OperandLiteralNumber, "");\r
-\r
- InstructionDesc[OpCompileFlag].capabilities.push_back(CapKernel);\r
- InstructionDesc[OpCompileFlag].operands.push(OperandLiteralString, "'Flag'");\r
-\r
- InstructionDesc[OpAsyncGroupCopy].capabilities.push_back(CapKernel);\r
- InstructionDesc[OpAsyncGroupCopy].operands.push(OperandExecutionScope, "'Scope'");\r
- InstructionDesc[OpAsyncGroupCopy].operands.push(OperandId, "'Destination'");\r
- InstructionDesc[OpAsyncGroupCopy].operands.push(OperandId, "'Source'");\r
- InstructionDesc[OpAsyncGroupCopy].operands.push(OperandId, "'Num Elements'");\r
- InstructionDesc[OpAsyncGroupCopy].operands.push(OperandId, "'Stride'");\r
- InstructionDesc[OpAsyncGroupCopy].operands.push(OperandId, "'Event'");\r
-\r
- InstructionDesc[OpWaitGroupEvents].capabilities.push_back(CapKernel);\r
- InstructionDesc[OpWaitGroupEvents].operands.push(OperandExecutionScope, "'Scope'");\r
- InstructionDesc[OpWaitGroupEvents].operands.push(OperandId, "'Num Events'");\r
- InstructionDesc[OpWaitGroupEvents].operands.push(OperandId, "'Events List'");\r
-\r
- InstructionDesc[OpGroupAll].capabilities.push_back(CapKernel);\r
- InstructionDesc[OpGroupAll].operands.push(OperandExecutionScope, "'Scope'");\r
- InstructionDesc[OpGroupAll].operands.push(OperandId, "'Predicate'");\r
-\r
- InstructionDesc[OpGroupAny].capabilities.push_back(CapKernel);\r
- InstructionDesc[OpGroupAny].operands.push(OperandExecutionScope, "'Scope'");\r
- InstructionDesc[OpGroupAny].operands.push(OperandId, "'Predicate'");\r
-\r
- InstructionDesc[OpGroupBroadcast].capabilities.push_back(CapKernel);\r
- InstructionDesc[OpGroupBroadcast].operands.push(OperandExecutionScope, "'Scope'");\r
- InstructionDesc[OpGroupBroadcast].operands.push(OperandId, "'Value'");\r
- InstructionDesc[OpGroupBroadcast].operands.push(OperandId, "'LocalId'");\r
-\r
- InstructionDesc[OpGroupIAdd].capabilities.push_back(CapKernel);\r
- InstructionDesc[OpGroupIAdd].operands.push(OperandExecutionScope, "'Scope'");\r
- InstructionDesc[OpGroupIAdd].operands.push(OperandGroupOperation, "'Operation'");\r
- InstructionDesc[OpGroupIAdd].operands.push(OperandId, "'X'");\r
-\r
- InstructionDesc[OpGroupFAdd].capabilities.push_back(CapKernel);\r
- InstructionDesc[OpGroupFAdd].operands.push(OperandExecutionScope, "'Scope'");\r
- InstructionDesc[OpGroupFAdd].operands.push(OperandGroupOperation, "'Operation'");\r
- InstructionDesc[OpGroupFAdd].operands.push(OperandId, "'X'");\r
-\r
- InstructionDesc[OpGroupUMin].capabilities.push_back(CapKernel);\r
- InstructionDesc[OpGroupUMin].operands.push(OperandExecutionScope, "'Scope'");\r
- InstructionDesc[OpGroupUMin].operands.push(OperandGroupOperation, "'Operation'");\r
- InstructionDesc[OpGroupUMin].operands.push(OperandId, "'X'");\r
-\r
- InstructionDesc[OpGroupSMin].capabilities.push_back(CapKernel);\r
- InstructionDesc[OpGroupSMin].operands.push(OperandExecutionScope, "'Scope'");\r
- InstructionDesc[OpGroupSMin].operands.push(OperandGroupOperation, "'Operation'");\r
- InstructionDesc[OpGroupSMin].operands.push(OperandId, "X");\r
-\r
- InstructionDesc[OpGroupFMin].capabilities.push_back(CapKernel);\r
- InstructionDesc[OpGroupFMin].operands.push(OperandExecutionScope, "'Scope'");\r
- InstructionDesc[OpGroupFMin].operands.push(OperandGroupOperation, "'Operation'");\r
- InstructionDesc[OpGroupFMin].operands.push(OperandId, "X");\r
-\r
- InstructionDesc[OpGroupUMax].capabilities.push_back(CapKernel);\r
- InstructionDesc[OpGroupUMax].operands.push(OperandExecutionScope, "'Scope'");\r
- InstructionDesc[OpGroupUMax].operands.push(OperandGroupOperation, "'Operation'");\r
- InstructionDesc[OpGroupUMax].operands.push(OperandId, "X");\r
-\r
- InstructionDesc[OpGroupSMax].capabilities.push_back(CapKernel);\r
- InstructionDesc[OpGroupSMax].operands.push(OperandExecutionScope, "'Scope'");\r
- InstructionDesc[OpGroupSMax].operands.push(OperandGroupOperation, "'Operation'");\r
- InstructionDesc[OpGroupSMax].operands.push(OperandId, "X");\r
-\r
- InstructionDesc[OpGroupFMax].capabilities.push_back(CapKernel);\r
- InstructionDesc[OpGroupFMax].operands.push(OperandExecutionScope, "'Scope'");\r
- InstructionDesc[OpGroupFMax].operands.push(OperandGroupOperation, "'Operation'");\r
- InstructionDesc[OpGroupFMax].operands.push(OperandId, "X");\r
-\r
- InstructionDesc[OpReadPipe].capabilities.push_back(CapKernel);\r
- InstructionDesc[OpReadPipe].operands.push(OperandId, "'p'");\r
- InstructionDesc[OpReadPipe].operands.push(OperandId, "'ptr'");\r
-\r
- InstructionDesc[OpWritePipe].capabilities.push_back(CapKernel);\r
- InstructionDesc[OpWritePipe].operands.push(OperandId, "'p'");\r
- InstructionDesc[OpWritePipe].operands.push(OperandId, "'ptr'");\r
-\r
- InstructionDesc[OpReservedReadPipe].capabilities.push_back(CapKernel);\r
- InstructionDesc[OpReservedReadPipe].operands.push(OperandId, "'p'");\r
- InstructionDesc[OpReservedReadPipe].operands.push(OperandId, "'reserve_id'");\r
- InstructionDesc[OpReservedReadPipe].operands.push(OperandId, "'index'");\r
- InstructionDesc[OpReservedReadPipe].operands.push(OperandId, "'ptr'");\r
-\r
- InstructionDesc[OpReservedWritePipe].capabilities.push_back(CapKernel);\r
- InstructionDesc[OpReservedWritePipe].operands.push(OperandId, "'p'");\r
- InstructionDesc[OpReservedWritePipe].operands.push(OperandId, "'reserve_id'");\r
- InstructionDesc[OpReservedWritePipe].operands.push(OperandId, "'index'");\r
- InstructionDesc[OpReservedWritePipe].operands.push(OperandId, "'ptr'");\r
-\r
- InstructionDesc[OpReserveReadPipePackets].capabilities.push_back(CapKernel);\r
- InstructionDesc[OpReserveReadPipePackets].operands.push(OperandId, "'p'");\r
- InstructionDesc[OpReserveReadPipePackets].operands.push(OperandId, "'num_packets'");\r
-\r
- InstructionDesc[OpReserveWritePipePackets].capabilities.push_back(CapKernel);\r
- InstructionDesc[OpReserveWritePipePackets].operands.push(OperandId, "'p'");\r
- InstructionDesc[OpReserveWritePipePackets].operands.push(OperandId, "'num_packets'");\r
-\r
- InstructionDesc[OpCommitReadPipe].capabilities.push_back(CapKernel);\r
- InstructionDesc[OpCommitReadPipe].operands.push(OperandId, "'p'");\r
- InstructionDesc[OpCommitReadPipe].operands.push(OperandId, "'reserve_id'");\r
-\r
- InstructionDesc[OpCommitWritePipe].capabilities.push_back(CapKernel);\r
- InstructionDesc[OpCommitWritePipe].operands.push(OperandId, "'p'");\r
- InstructionDesc[OpCommitWritePipe].operands.push(OperandId, "'reserve_id'");\r
-\r
- InstructionDesc[OpIsValidReserveId].capabilities.push_back(CapKernel);\r
- InstructionDesc[OpIsValidReserveId].operands.push(OperandId, "'reserve_id'");\r
-\r
- InstructionDesc[OpGetNumPipePackets].capabilities.push_back(CapKernel);\r
- InstructionDesc[OpGetNumPipePackets].operands.push(OperandId, "'p'");\r
-\r
- InstructionDesc[OpGetMaxPipePackets].capabilities.push_back(CapKernel);\r
- InstructionDesc[OpGetMaxPipePackets].operands.push(OperandId, "'p'");\r
-\r
- InstructionDesc[OpGroupReserveReadPipePackets].capabilities.push_back(CapKernel);\r
- InstructionDesc[OpGroupReserveReadPipePackets].operands.push(OperandExecutionScope, "'Scope'");\r
- InstructionDesc[OpGroupReserveReadPipePackets].operands.push(OperandId, "'p'");\r
- InstructionDesc[OpGroupReserveReadPipePackets].operands.push(OperandId, "'num_packets'");\r
-\r
- InstructionDesc[OpGroupReserveWritePipePackets].capabilities.push_back(CapKernel);\r
- InstructionDesc[OpGroupReserveWritePipePackets].operands.push(OperandExecutionScope, "'Scope'");\r
- InstructionDesc[OpGroupReserveWritePipePackets].operands.push(OperandId, "'p'");\r
- InstructionDesc[OpGroupReserveWritePipePackets].operands.push(OperandId, "'num_packets'");\r
-\r
- InstructionDesc[OpGroupCommitReadPipe].capabilities.push_back(CapKernel);\r
- InstructionDesc[OpGroupCommitReadPipe].operands.push(OperandExecutionScope, "'Scope'");\r
- InstructionDesc[OpGroupCommitReadPipe].operands.push(OperandId, "'p'");\r
- InstructionDesc[OpGroupCommitReadPipe].operands.push(OperandId, "'reserve_id'");\r
-\r
- InstructionDesc[OpGroupCommitWritePipe].capabilities.push_back(CapKernel);\r
- InstructionDesc[OpGroupCommitWritePipe].operands.push(OperandExecutionScope, "'Scope'");\r
- InstructionDesc[OpGroupCommitWritePipe].operands.push(OperandId, "'p'");\r
- InstructionDesc[OpGroupCommitWritePipe].operands.push(OperandId, "'reserve_id'");\r
-\r
- InstructionDesc[OpBuildNDRange].capabilities.push_back(CapKernel);\r
- InstructionDesc[OpBuildNDRange].operands.push(OperandId, "'GlobalWorkSize'");\r
- InstructionDesc[OpBuildNDRange].operands.push(OperandId, "'LocalWorkSize'");\r
- InstructionDesc[OpBuildNDRange].operands.push(OperandId, "'GlobalWorkOffset'");\r
-\r
- InstructionDesc[OpGetDefaultQueue].capabilities.push_back(CapKernel);\r
-\r
- InstructionDesc[OpCaptureEventProfilingInfo].capabilities.push_back(CapKernel);\r
-\r
- InstructionDesc[OpCaptureEventProfilingInfo].operands.push(OperandId, "'event'");\r
- InstructionDesc[OpCaptureEventProfilingInfo].operands.push(OperandKernelProfilingInfo, "'info'");\r
- InstructionDesc[OpCaptureEventProfilingInfo].operands.push(OperandId, "'value'");\r
-\r
- InstructionDesc[OpSetUserEventStatus].capabilities.push_back(CapKernel);\r
-\r
- InstructionDesc[OpSetUserEventStatus].operands.push(OperandId, "'event'");\r
- InstructionDesc[OpSetUserEventStatus].operands.push(OperandId, "'status'");\r
-\r
- InstructionDesc[OpIsValidEvent].capabilities.push_back(CapKernel);\r
- InstructionDesc[OpIsValidEvent].operands.push(OperandId, "'event'");\r
-\r
- InstructionDesc[OpCreateUserEvent].capabilities.push_back(CapKernel);\r
-\r
- InstructionDesc[OpRetainEvent].capabilities.push_back(CapKernel);\r
- InstructionDesc[OpRetainEvent].operands.push(OperandId, "'event'");\r
-\r
- InstructionDesc[OpReleaseEvent].capabilities.push_back(CapKernel);\r
- InstructionDesc[OpReleaseEvent].operands.push(OperandId, "'event'");\r
-\r
- InstructionDesc[OpGetKernelWorkGroupSize].capabilities.push_back(CapKernel);\r
- InstructionDesc[OpGetKernelWorkGroupSize].operands.push(OperandId, "'Invoke'");\r
-\r
- InstructionDesc[OpGetKernelPreferredWorkGroupSizeMultiple].capabilities.push_back(CapKernel);\r
- InstructionDesc[OpGetKernelPreferredWorkGroupSizeMultiple].operands.push(OperandId, "'Invoke'");\r
-\r
- InstructionDesc[OpGetKernelNDrangeSubGroupCount].capabilities.push_back(CapKernel);\r
- InstructionDesc[OpGetKernelNDrangeSubGroupCount].operands.push(OperandId, "'ND Range'");\r
- InstructionDesc[OpGetKernelNDrangeSubGroupCount].operands.push(OperandId, "'Invoke'");\r
-\r
- InstructionDesc[OpGetKernelNDrangeMaxSubGroupSize].capabilities.push_back(CapKernel);\r
- InstructionDesc[OpGetKernelNDrangeMaxSubGroupSize].operands.push(OperandId, "'ND Range'");\r
- InstructionDesc[OpGetKernelNDrangeMaxSubGroupSize].operands.push(OperandId, "'Invoke'");\r
-\r
- InstructionDesc[OpEnqueueKernel].capabilities.push_back(CapKernel);\r
- InstructionDesc[OpEnqueueKernel].operands.push(OperandId, "'q'");\r
- InstructionDesc[OpEnqueueKernel].operands.push(OperandKernelEnqueueFlags, "'flags'");\r
- InstructionDesc[OpEnqueueKernel].operands.push(OperandId, "'ND Range'");\r
- InstructionDesc[OpEnqueueKernel].operands.push(OperandId, "'Num Events'");\r
- InstructionDesc[OpEnqueueKernel].operands.push(OperandId, "'Wait Events'");\r
- InstructionDesc[OpEnqueueKernel].operands.push(OperandId, "'Ret Event'");\r
- InstructionDesc[OpEnqueueKernel].operands.push(OperandId, "'Invoke'");\r
- InstructionDesc[OpEnqueueKernel].operands.push(OperandId, "'Param'");\r
- InstructionDesc[OpEnqueueKernel].operands.push(OperandId, "'Param Size'");\r
- InstructionDesc[OpEnqueueKernel].operands.push(OperandId, "'Param Align'");\r
- InstructionDesc[OpEnqueueKernel].operands.push(OperandVariableIds, "'Local Size'");\r
-\r
- InstructionDesc[OpEnqueueMarker].capabilities.push_back(CapKernel);\r
- InstructionDesc[OpEnqueueMarker].operands.push(OperandId, "'q'");\r
- InstructionDesc[OpEnqueueMarker].operands.push(OperandId, "'Num Events'");\r
- InstructionDesc[OpEnqueueMarker].operands.push(OperandId, "'Wait Events'");\r
- InstructionDesc[OpEnqueueMarker].operands.push(OperandId, "'Ret Event'");\r
-}\r
-\r
-}; // end spv namespace\r
+//
+//Copyright (C) 2014 LunarG, Inc.
+//
+//All rights reserved.
+//
+//Redistribution and use in source and binary forms, with or without
+//modification, are permitted provided that the following conditions
+//are met:
+//
+// Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//
+// Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following
+// disclaimer in the documentation and/or other materials provided
+// with the distribution.
+//
+// Neither the name of 3Dlabs Inc. Ltd. nor the names of its
+// contributors may be used to endorse or promote products derived
+// from this software without specific prior written permission.
+//
+//THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+//"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+//LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+//FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+//COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+//INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+//BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+//LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+//CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+//LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+//ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+//POSSIBILITY OF SUCH DAMAGE.
+
+//
+// Author: John Kessenich, LunarG
+//
+
+//
+// 1) Programatically fill in instruction/operand information.
+// This can be used for disassembly, printing documentation, etc.
+//
+// 2) Print documentation from this parameterization.
+//
+
+#include "doc.h"
+
+#include <stdio.h>
+#include <string.h>
+#include <algorithm>
+
+namespace spv {
+
+//
+// Whole set of functions that translate enumerants to their text strings for
+// the specification (or their sanitized versions for auto-generating the
+// spirv.h header.
+//
+// Also, the ceilings are declared next to these, to help keep them in sync.
+// Ceilings should be
+// - one more than the maximum value an enumerant takes on, for non-mask enumerants
+// (for non-sparse enums, this is the number of enumurants)
+// - the number of bits consumed by the set of masks
+// (for non-sparse mask enums, this is the number of enumurants)
+//
+
+const int SourceLanguageCeiling = 4;
+
+const char* SourceString(int source)
+{
+ switch (source) {
+ case 0: return "Unknown";
+ case 1: return "ESSL";
+ case 2: return "GLSL";
+ case 3: return "OpenCL";
+
+ case SourceLanguageCeiling:
+ default: return "Bad";
+ }
+}
+
+const int ExecutionModelCeiling = 7;
+
+const char* ExecutionModelString(int model)
+{
+ switch (model) {
+ case 0: return "Vertex";
+ case 1: return "TessellationControl";
+ case 2: return "TessellationEvaluation";
+ case 3: return "Geometry";
+ case 4: return "Fragment";
+ case 5: return "GLCompute";
+ case 6: return "Kernel";
+
+ case ExecutionModelCeiling:
+ default: return "Bad";
+ }
+}
+
+const int AddressingModelCeiling = 3;
+
+const char* AddressingString(int addr)
+{
+ switch (addr) {
+ case 0: return "Logical";
+ case 1: return "Physical32";
+ case 2: return "Physical64";
+
+ case AddressingModelCeiling:
+ default: return "Bad";
+ }
+}
+
+const int MemoryModelCeiling = 5;
+
+const char* MemoryString(int mem)
+{
+ switch (mem) {
+ case 0: return "Simple";
+ case 1: return "GLSL450";
+ case 2: return "OpenCL1.2";
+ case 3: return "OpenCL2.0";
+ case 4: return "OpenCL2.1";
+
+ case MemoryModelCeiling:
+ default: return "Bad";
+ }
+}
+
+const int ExecutionModeCeiling = 31;
+
+const char* ExecutionModeString(int mode)
+{
+ switch (mode) {
+ case 0: return "Invocations";
+ case 1: return "SpacingEqual";
+ case 2: return "SpacingFractionalEven";
+ case 3: return "SpacingFractionalOdd";
+ case 4: return "VertexOrderCw";
+ case 5: return "VertexOrderCcw";
+ case 6: return "PixelCenterInteger";
+ case 7: return "OriginUpperLeft";
+ case 8: return "EarlyFragmentTests";
+ case 9: return "PointMode";
+ case 10: return "Xfb";
+ case 11: return "DepthReplacing";
+ case 12: return "DepthAny";
+ case 13: return "DepthGreater";
+ case 14: return "DepthLess";
+ case 15: return "DepthUnchanged";
+ case 16: return "LocalSize";
+ case 17: return "LocalSizeHint";
+ case 18: return "InputPoints";
+ case 19: return "InputLines";
+ case 20: return "InputLinesAdjacency";
+ case 21: return "InputTriangles";
+ case 22: return "InputTrianglesAdjacency";
+ case 23: return "InputQuads";
+ case 24: return "InputIsolines";
+ case 25: return "OutputVertices";
+ case 26: return "OutputPoints";
+ case 27: return "OutputLineStrip";
+ case 28: return "OutputTriangleStrip";
+ case 29: return "VecTypeHint";
+ case 30: return "ContractionOff";
+
+ case ExecutionModeCeiling:
+ default: return "Bad";
+ }
+}
+
+const int StorageClassCeiling = 11;
+
+const char* StorageClassString(int StorageClass)
+{
+ switch (StorageClass) {
+ case 0: return "UniformConstant";
+ case 1: return "Input";
+ case 2: return "Uniform";
+ case 3: return "Output";
+ case 4: return "WorkgroupLocal";
+ case 5: return "WorkgroupGlobal";
+ case 6: return "PrivateGlobal";
+ case 7: return "Function";
+ case 8: return "Generic";
+ case 9: return "Private";
+ case 10: return "AtomicCounter";
+
+ case StorageClassCeiling:
+ default: return "Bad";
+ }
+}
+
+const int DecorationCeiling = 45;
+
+const char* DecorationString(int decoration)
+{
+ switch (decoration) {
+ case 0: return "PrecisionLow";
+ case 1: return "PrecisionMedium";
+ case 2: return "PrecisionHigh";
+ case 3: return "Block";
+ case 4: return "BufferBlock";
+ case 5: return "RowMajor";
+ case 6: return "ColMajor";
+ case 7: return "GLSLShared";
+ case 8: return "GLSLStd140";
+ case 9: return "GLSLStd430";
+ case 10: return "GLSLPacked";
+ case 11: return "Smooth";
+ case 12: return "Noperspective";
+ case 13: return "Flat";
+ case 14: return "Patch";
+ case 15: return "Centroid";
+ case 16: return "Sample";
+ case 17: return "Invariant";
+ case 18: return "Restrict";
+ case 19: return "Aliased";
+ case 20: return "Volatile";
+ case 21: return "Constant";
+ case 22: return "Coherent";
+ case 23: return "Nonwritable";
+ case 24: return "Nonreadable";
+ case 25: return "Uniform";
+ case 26: return "NoStaticUse";
+ case 27: return "CPacked";
+ case 28: return "SaturatedConversion";
+ case 29: return "Stream";
+ case 30: return "Location";
+ case 31: return "Component";
+ case 32: return "Index";
+ case 33: return "Binding";
+ case 34: return "DescriptorSet";
+ case 35: return "Offset";
+ case 36: return "Alignment";
+ case 37: return "XfbBuffer";
+ case 38: return "Stride";
+ case 39: return "BuiltIn";
+ case 40: return "FuncParamAttr";
+ case 41: return "FP Rounding Mode";
+ case 42: return "FP Fast Math Mode";
+ case 43: return "Linkage Attributes";
+ case 44: return "SpecId";
+
+ case DecorationCeiling:
+ default: return "Bad";
+ }
+}
+
+const int BuiltInCeiling = 42;
+
+const char* BuiltInString(int builtIn)
+{
+ switch (builtIn) {
+ case 0: return "Position";
+ case 1: return "PointSize";
+ case 2: return "ClipVertex";
+ case 3: return "ClipDistance";
+ case 4: return "CullDistance";
+ case 5: return "VertexId";
+ case 6: return "InstanceId";
+ case 7: return "PrimitiveId";
+ case 8: return "InvocationId";
+ case 9: return "Layer";
+ case 10: return "ViewportIndex";
+ case 11: return "TessLevelOuter";
+ case 12: return "TessLevelInner";
+ case 13: return "TessCoord";
+ case 14: return "PatchVertices";
+ case 15: return "FragCoord";
+ case 16: return "PointCoord";
+ case 17: return "FrontFacing";
+ case 18: return "SampleId";
+ case 19: return "SamplePosition";
+ case 20: return "SampleMask";
+ case 21: return "FragColor";
+ case 22: return "FragDepth";
+ case 23: return "HelperInvocation";
+ case 24: return "NumWorkgroups";
+ case 25: return "WorkgroupSize";
+ case 26: return "WorkgroupId";
+ case 27: return "LocalInvocationId";
+ case 28: return "GlobalInvocationId";
+ case 29: return "LocalInvocationIndex";
+ case 30: return "WorkDim";
+ case 31: return "GlobalSize";
+ case 32: return "EnqueuedWorkgroupSize";
+ case 33: return "GlobalOffset";
+ case 34: return "GlobalLinearId";
+ case 35: return "WorkgroupLinearId";
+ case 36: return "SubgroupSize";
+ case 37: return "SubgroupMaxSize";
+ case 38: return "NumSubgroups";
+ case 39: return "NumEnqueuedSubgroups";
+ case 40: return "SubgroupId";
+ case 41: return "SubgroupLocalInvocationId";
+
+ case BuiltInCeiling:
+ default: return "Bad";
+ }
+}
+
+const int DimensionCeiling = 6;
+
+const char* DimensionString(int dim)
+{
+ switch (dim) {
+ case 0: return "1D";
+ case 1: return "2D";
+ case 2: return "3D";
+ case 3: return "Cube";
+ case 4: return "Rect";
+ case 5: return "Buffer";
+
+ case DimensionCeiling:
+ default: return "Bad";
+ }
+}
+
+const int SamplerAddressingModeCeiling = 5;
+
+const char* SamplerAddressingModeString(int mode)
+{
+ switch (mode) {
+ case 0: return "None";
+ case 1: return "ClampToEdge";
+ case 2: return "Clamp";
+ case 3: return "Repeat";
+ case 4: return "RepeatMirrored";
+
+ case SamplerAddressingModeCeiling:
+ default: return "Bad";
+ }
+}
+
+const int SamplerFilterModeCeiling = 2;
+
+const char* SamplerFilterModeString(int mode)
+{
+ switch (mode) {
+ case 0: return "Nearest";
+ case 1: return "Linear";
+
+ case SamplerFilterModeCeiling:
+ default: return "Bad";
+ }
+}
+
+const int FPFastMathCeiling = 5;
+
+const char* FPFastMathString(int mode)
+{
+ switch (mode) {
+ case 0: return "NotNaN";
+ case 1: return "NotInf";
+ case 2: return "NSZ";
+ case 3: return "AllowRecip";
+ case 4: return "Fast";
+
+ case FPFastMathCeiling:
+ default: return "Bad";
+ }
+}
+
+const int FPRoundingModeCeiling = 4;
+
+const char* FPRoundingModeString(int mode)
+{
+ switch (mode) {
+ case 0: return "RTE";
+ case 1: return "RTZ";
+ case 2: return "RTP";
+ case 3: return "RTN";
+
+ case FPRoundingModeCeiling:
+ default: return "Bad";
+ }
+}
+
+const int LinkageTypeCeiling = 2;
+
+const char* LinkageTypeString(int type)
+{
+ switch (type) {
+ case 0: return "Export";
+ case 1: return "Import";
+
+ case LinkageTypeCeiling:
+ default: return "Bad";
+ }
+}
+
+const int FuncParamAttrCeiling = 9;
+
+const char* FuncParamAttrString(int attr)
+{
+ switch (attr) {
+ case 0: return "Zext";
+ case 1: return "Sext";
+ case 2: return "ByVal";
+ case 3: return "Sret";
+ case 4: return "NoAlias";
+ case 5: return "NoCapture";
+ case 6: return "SVM";
+ case 7: return "NoWrite";
+ case 8: return "NoReadWrite";
+
+ case FuncParamAttrCeiling:
+ default: return "Bad";
+ }
+}
+
+const int AccessQualifierCeiling = 3;
+
+const char* AccessQualifierString(int attr)
+{
+ switch (attr) {
+ case 0: return "ReadOnly";
+ case 1: return "WriteOnly";
+ case 2: return "ReadWrite";
+
+ case AccessQualifierCeiling:
+ default: return "Bad";
+ }
+}
+
+const int SelectControlCeiling = 2;
+
+const char* SelectControlString(int cont)
+{
+ switch (cont) {
+ case 0: return "Flatten";
+ case 1: return "DontFlatten";
+
+ case SelectControlCeiling:
+ default: return "Bad";
+ }
+}
+
+const int LoopControlCeiling = 2;
+
+const char* LoopControlString(int cont)
+{
+ switch (cont) {
+ case 0: return "Unroll";
+ case 1: return "DontUnroll";
+
+ case LoopControlCeiling:
+ default: return "Bad";
+ }
+}
+
+const int FunctionControlCeiling = 4;
+
+const char* FunctionControlString(int cont)
+{
+ switch (cont) {
+ case 0: return "Inline";
+ case 1: return "DontInline";
+ case 2: return "Pure";
+ case 3: return "Const";
+
+ case FunctionControlCeiling:
+ default: return "Bad";
+ }
+}
+
+const int MemorySemanticsCeiling = 10;
+
+const char* MemorySemanticsString(int mem)
+{
+ switch (mem) {
+ case 0: return "Relaxed";
+ case 1: return "SequentiallyConsistent";
+ case 2: return "Acquire";
+ case 3: return "Release";
+
+ case 4: return "UniformMemory";
+ case 5: return "SubgroupMemory";
+ case 6: return "WorkgroupLocalMemory";
+ case 7: return "WorkgroupGlobalMemory";
+ case 8: return "AtomicCounterMemory";
+ case 9: return "ImageMemory";
+
+ case MemorySemanticsCeiling:
+ default: return "Bad";
+ }
+}
+
+const int MemoryAccessCeiling = 2;
+
+const char* MemoryAccessString(int mem)
+{
+ switch (mem) {
+ case 0: return "Volatile";
+ case 1: return "Aligned";
+
+ case MemoryAccessCeiling:
+ default: return "Bad";
+ }
+}
+
+const int ExecutionScopeCeiling = 4;
+
+const char* ExecutionScopeString(int mem)
+{
+ switch (mem) {
+ case 0: return "CrossDevice";
+ case 1: return "Device";
+ case 2: return "Workgroup";
+ case 3: return "Subgroup";
+
+ case ExecutionScopeCeiling:
+ default: return "Bad";
+ }
+}
+
+const int GroupOperationCeiling = 3;
+
+const char* GroupOperationString(int gop)
+{
+
+ switch (gop)
+ {
+ case 0: return "Reduce";
+ case 1: return "InclusiveScan";
+ case 2: return "ExclusiveScan";
+
+ case GroupOperationCeiling:
+ default: return "Bad";
+ }
+}
+
+const int KernelEnqueueFlagsCeiling = 3;
+
+const char* KernelEnqueueFlagsString(int flag)
+{
+ switch (flag)
+ {
+ case 0: return "NoWait";
+ case 1: return "WaitKernel";
+ case 2: return "WaitWorkGroup";
+
+ case KernelEnqueueFlagsCeiling:
+ default: return "Bad";
+ }
+}
+
+const int KernelProfilingInfoCeiling = 1;
+
+const char* KernelProfilingInfoString(int info)
+{
+ switch (info)
+ {
+ case 0: return "CmdExecTime";
+
+ case KernelProfilingInfoCeiling:
+ default: return "Bad";
+ }
+}
+
+const char* OpcodeString(int op)
+{
+ switch (op) {
+ case 0: return "OpNop";
+ case 1: return "OpSource";
+ case 2: return "OpSourceExtension";
+ case 3: return "OpExtension";
+ case 4: return "OpExtInstImport";
+ case 5: return "OpMemoryModel";
+ case 6: return "OpEntryPoint";
+ case 7: return "OpExecutionMode";
+ case 8: return "OpTypeVoid";
+ case 9: return "OpTypeBool";
+ case 10: return "OpTypeInt";
+ case 11: return "OpTypeFloat";
+ case 12: return "OpTypeVector";
+ case 13: return "OpTypeMatrix";
+ case 14: return "OpTypeSampler";
+ case 15: return "OpTypeFilter";
+ case 16: return "OpTypeArray";
+ case 17: return "OpTypeRuntimeArray";
+ case 18: return "OpTypeStruct";
+ case 19: return "OpTypeOpaque";
+ case 20: return "OpTypePointer";
+ case 21: return "OpTypeFunction";
+ case 22: return "OpTypeEvent";
+ case 23: return "OpTypeDeviceEvent";
+ case 24: return "OpTypeReserveId";
+ case 25: return "OpTypeQueue";
+ case 26: return "OpTypePipe";
+ case 27: return "OpConstantTrue";
+ case 28: return "OpConstantFalse";
+ case 29: return "OpConstant";
+ case 30: return "OpConstantComposite";
+ case 31: return "OpConstantSampler";
+ case 32: return "OpConstantNullPointer";
+ case 33: return "OpConstantNullObject";
+ case 34: return "OpSpecConstantTrue";
+ case 35: return "OpSpecConstantFalse";
+ case 36: return "OpSpecConstant";
+ case 37: return "OpSpecConstantComposite";
+ case 38: return "OpVariable";
+ case 39: return "OpVariableArray";
+ case 40: return "OpFunction";
+ case 41: return "OpFunctionParameter";
+ case 42: return "OpFunctionEnd";
+ case 43: return "OpFunctionCall";
+ case 44: return "OpExtInst";
+ case 45: return "OpUndef";
+ case 46: return "OpLoad";
+ case 47: return "OpStore";
+ case 48: return "OpPhi";
+ case 49: return "OpDecorationGroup";
+ case 50: return "OpDecorate";
+ case 51: return "OpMemberDecorate";
+ case 52: return "OpGroupDecorate";
+ case 53: return "OpGroupMemberDecorate";
+ case 54: return "OpName";
+ case 55: return "OpMemberName";
+ case 56: return "OpString";
+ case 57: return "OpLine";
+ case 58: return "OpVectorExtractDynamic";
+ case 59: return "OpVectorInsertDynamic";
+ case 60: return "OpVectorShuffle";
+ case 61: return "OpCompositeConstruct";
+ case 62: return "OpCompositeExtract";
+ case 63: return "OpCompositeInsert";
+ case 64: return "OpCopyObject";
+ case 65: return "OpCopyMemory";
+ case 66: return "OpCopyMemorySized";
+ case 67: return "OpSampler";
+ case 68: return "OpTextureSample";
+ case 69: return "OpTextureSampleDref";
+ case 70: return "OpTextureSampleLod";
+ case 71: return "OpTextureSampleProj";
+ case 72: return "OpTextureSampleGrad";
+ case 73: return "OpTextureSampleOffset";
+ case 74: return "OpTextureSampleProjLod";
+ case 75: return "OpTextureSampleProjGrad";
+ case 76: return "OpTextureSampleLodOffset";
+ case 77: return "OpTextureSampleProjOffset";
+ case 78: return "OpTextureSampleGradOffset";
+ case 79: return "OpTextureSampleProjLodOffset";
+ case 80: return "OpTextureSampleProjGradOffset";
+ case 81: return "OpTextureFetchTexelLod";
+ case 82: return "OpTextureFetchTexelOffset";
+ case 83: return "OpTextureFetchSample";
+ case 84: return "OpTextureFetchTexel";
+ case 85: return "OpTextureGather";
+ case 86: return "OpTextureGatherOffset";
+ case 87: return "OpTextureGatherOffsets";
+ case 88: return "OpTextureQuerySizeLod";
+ case 89: return "OpTextureQuerySize";
+ case 90: return "OpTextureQueryLod";
+ case 91: return "OpTextureQueryLevels";
+ case 92: return "OpTextureQuerySamples";
+ case 93: return "OpAccessChain";
+ case 94: return "OpInBoundsAccessChain";
+ case 95: return "OpSNegate";
+ case 96: return "OpFNegate";
+ case 97: return "OpNot";
+ case 98: return "OpAny";
+ case 99: return "OpAll";
+ case 100: return "OpConvertFToU";
+ case 101: return "OpConvertFToS";
+ case 102: return "OpConvertSToF";
+ case 103: return "OpConvertUToF";
+ case 104: return "OpUConvert";
+ case 105: return "OpSConvert";
+ case 106: return "OpFConvert";
+ case 107: return "OpConvertPtrToU";
+ case 108: return "OpConvertUToPtr";
+ case 109: return "OpPtrCastToGeneric";
+ case 110: return "OpGenericCastToPtr";
+ case 111: return "OpBitcast";
+ case 112: return "OpTranspose";
+ case 113: return "OpIsNan";
+ case 114: return "OpIsInf";
+ case 115: return "OpIsFinite";
+ case 116: return "OpIsNormal";
+ case 117: return "OpSignBitSet";
+ case 118: return "OpLessOrGreater";
+ case 119: return "OpOrdered";
+ case 120: return "OpUnordered";
+ case 121: return "OpArrayLength";
+ case 122: return "OpIAdd";
+ case 123: return "OpFAdd";
+ case 124: return "OpISub";
+ case 125: return "OpFSub";
+ case 126: return "OpIMul";
+ case 127: return "OpFMul";
+ case 128: return "OpUDiv";
+ case 129: return "OpSDiv";
+ case 130: return "OpFDiv";
+ case 131: return "OpUMod";
+ case 132: return "OpSRem";
+ case 133: return "OpSMod";
+ case 134: return "OpFRem";
+ case 135: return "OpFMod";
+ case 136: return "OpVectorTimesScalar";
+ case 137: return "OpMatrixTimesScalar";
+ case 138: return "OpVectorTimesMatrix";
+ case 139: return "OpMatrixTimesVector";
+ case 140: return "OpMatrixTimesMatrix";
+ case 141: return "OpOuterProduct";
+ case 142: return "OpDot";
+ case 143: return "OpShiftRightLogical";
+ case 144: return "OpShiftRightArithmetic";
+ case 145: return "OpShiftLeftLogical";
+ case 146: return "OpLogicalOr";
+ case 147: return "OpLogicalXor";
+ case 148: return "OpLogicalAnd";
+ case 149: return "OpBitwiseOr";
+ case 150: return "OpBitwiseXor";
+ case 151: return "OpBitwiseAnd";
+ case 152: return "OpSelect";
+ case 153: return "OpIEqual";
+ case 154: return "OpFOrdEqual";
+ case 155: return "OpFUnordEqual";
+ case 156: return "OpINotEqual";
+ case 157: return "OpFOrdNotEqual";
+ case 158: return "OpFUnordNotEqual";
+ case 159: return "OpULessThan";
+ case 160: return "OpSLessThan";
+ case 161: return "OpFOrdLessThan";
+ case 162: return "OpFUnordLessThan";
+ case 163: return "OpUGreaterThan";
+ case 164: return "OpSGreaterThan";
+ case 165: return "OpFOrdGreaterThan";
+ case 166: return "OpFUnordGreaterThan";
+ case 167: return "OpULessThanEqual";
+ case 168: return "OpSLessThanEqual";
+ case 169: return "OpFOrdLessThanEqual";
+ case 170: return "OpFUnordLessThanEqual";
+ case 171: return "OpUGreaterThanEqual";
+ case 172: return "OpSGreaterThanEqual";
+ case 173: return "OpFOrdGreaterThanEqual";
+ case 174: return "OpFUnordGreaterThanEqual";
+ case 175: return "OpDPdx";
+ case 176: return "OpDPdy";
+ case 177: return "OpFwidth";
+ case 178: return "OpDPdxFine";
+ case 179: return "OpDPdyFine";
+ case 180: return "OpFwidthFine";
+ case 181: return "OpDPdxCoarse";
+ case 182: return "OpDPdyCoarse";
+ case 183: return "OpFwidthCoarse";
+ case 184: return "OpEmitVertex";
+ case 185: return "OpEndPrimitive";
+ case 186: return "OpEmitStreamVertex";
+ case 187: return "OpEndStreamPrimitive";
+ case 188: return "OpControlBarrier";
+ case 189: return "OpMemoryBarrier";
+ case 190: return "OpImagePointer";
+ case 191: return "OpAtomicInit";
+ case 192: return "OpAtomicLoad";
+ case 193: return "OpAtomicStore";
+ case 194: return "OpAtomicExchange";
+ case 195: return "OpAtomicCompareExchange";
+ case 196: return "OpAtomicCompareExchangeWeak";
+ case 197: return "OpAtomicIIncrement";
+ case 198: return "OpAtomicIDecrement";
+ case 199: return "OpAtomicIAdd";
+ case 200: return "OpAtomicISub";
+ case 201: return "OpAtomicUMin";
+ case 202: return "OpAtomicUMax";
+ case 203: return "OpAtomicAnd";
+ case 204: return "OpAtomicOr";
+ case 205: return "OpAtomicXor";
+ case 206: return "OpLoopMerge";
+ case 207: return "OpSelectionMerge";
+ case 208: return "OpLabel";
+ case 209: return "OpBranch";
+ case 210: return "OpBranchConditional";
+ case 211: return "OpSwitch";
+ case 212: return "OpKill";
+ case 213: return "OpReturn";
+ case 214: return "OpReturnValue";
+ case 215: return "OpUnreachable";
+ case 216: return "OpLifetimeStart";
+ case 217: return "OpLifetimeStop";
+ case 218: return "OpCompileFlag";
+ case 219: return "OpAsyncGroupCopy";
+ case 220: return "OpWaitGroupEvents";
+ case 221: return "OpGroupAll";
+ case 222: return "OpGroupAny";
+ case 223: return "OpGroupBroadcast";
+ case 224: return "OpGroupIAdd";
+ case 225: return "OpGroupFAdd";
+ case 226: return "OpGroupFMin";
+ case 227: return "OpGroupUMin";
+ case 228: return "OpGroupSMin";
+ case 229: return "OpGroupFMax";
+ case 230: return "OpGroupUMax";
+ case 231: return "OpGroupSMax";
+ case 232: return "OpGenericCastToPtrExplicit";
+ case 233: return "OpGenericPtrMemSemantics";
+ case 234: return "OpReadPipe";
+ case 235: return "OpWritePipe";
+ case 236: return "OpReservedReadPipe";
+ case 237: return "OpReservedWritePipe";
+ case 238: return "OpReserveReadPipePackets";
+ case 239: return "OpReserveWritePipePackets";
+ case 240: return "OpCommitReadPipe";
+ case 241: return "OpCommitWritePipe";
+ case 242: return "OpIsValidReserveId";
+ case 243: return "OpGetNumPipePackets";
+ case 244: return "OpGetMaxPipePackets";
+ case 245: return "OpGroupReserveReadPipePackets";
+ case 246: return "OpGroupReserveWritePipePackets";
+ case 247: return "OpGroupCommitReadPipe";
+ case 248: return "OpGroupCommitWritePipe";
+ case 249: return "OpEnqueueMarker";
+ case 250: return "OpEnqueueKernel";
+ case 251: return "OpGetKernelNDrangeSubGroupCount";
+ case 252: return "OpGetKernelNDrangeMaxSubGroupSize";
+ case 253: return "OpGetKernelWorkGroupSize";
+ case 254: return "OpGetKernelPreferredWorkGroupSizeMultiple";
+ case 255: return "OpRetainEvent";
+ case 256: return "OpReleaseEvent";
+ case 257: return "OpCreateUserEvent";
+ case 258: return "OpIsValidEvent";
+ case 259: return "OpSetUserEventStatus";
+ case 260: return "OpCaptureEventProfilingInfo";
+ case 261: return "OpGetDefaultQueue";
+ case 262: return "OpBuildNDRange";
+ case 263: return "OpSatConvertSToU";
+ case 264: return "OpSatConvertUToS";
+ case 265: return "OpAtomicIMin";
+ case 266: return "OpAtomicIMax";
+
+ case OpcodeCeiling:
+ default:
+ return "Bad";
+ }
+}
+
+// The set of objects that hold all the instruction/operand
+// parameterization information.
+InstructionParameters InstructionDesc[OpcodeCeiling];
+OperandParameters ExecutionModeOperands[ExecutionModeCeiling];
+OperandParameters DecorationOperands[DecorationCeiling];
+
+EnumDefinition OperandClassParams[OperandCount];
+EnumParameters ExecutionModelParams[ExecutionModelCeiling];
+EnumParameters AddressingParams[AddressingModelCeiling];
+EnumParameters MemoryParams[MemoryModelCeiling];
+EnumParameters ExecutionModeParams[ExecutionModeCeiling];
+EnumParameters StorageParams[StorageClassCeiling];
+EnumParameters SamplerAddressingModeParams[SamplerAddressingModeCeiling];
+EnumParameters SamplerFilterModeParams[SamplerFilterModeCeiling];
+EnumParameters FPFastMathParams[FPFastMathCeiling];
+EnumParameters FPRoundingModeParams[FPRoundingModeCeiling];
+EnumParameters LinkageTypeParams[LinkageTypeCeiling];
+EnumParameters DecorationParams[DecorationCeiling];
+EnumParameters BuiltInParams[BuiltInCeiling];
+EnumParameters DimensionalityParams[DimensionCeiling];
+EnumParameters FuncParamAttrParams[FuncParamAttrCeiling];
+EnumParameters AccessQualifierParams[AccessQualifierCeiling];
+EnumParameters GroupOperationParams[GroupOperationCeiling];
+EnumParameters LoopControlParams[FunctionControlCeiling];
+EnumParameters SelectionControlParams[SelectControlCeiling];
+EnumParameters FunctionControlParams[FunctionControlCeiling];
+EnumParameters MemorySemanticsParams[MemorySemanticsCeiling];
+EnumParameters MemoryAccessParams[MemoryAccessCeiling];
+EnumParameters ExecutionScopeParams[ExecutionScopeCeiling];
+EnumParameters KernelEnqueueFlagsParams[KernelEnqueueFlagsCeiling];
+EnumParameters KernelProfilingInfoParams[KernelProfilingInfoCeiling];
+
+// Set up all the parameterizing descriptions of the opcodes, operands, etc.
+void Parameterize()
+{
+ static bool initialized = false;
+
+ // only do this once.
+ if (initialized)
+ return;
+
+ initialized = true;
+
+ // Exceptions to having a result <id> and a resulting type <id>.
+ // (Everything is initialized to have both).
+
+ InstructionDesc[OpNop].setResultAndType(false, false);
+ InstructionDesc[OpSource].setResultAndType(false, false);
+ InstructionDesc[OpSourceExtension].setResultAndType(false, false);
+ InstructionDesc[OpExtension].setResultAndType(false, false);
+ InstructionDesc[OpExtInstImport].setResultAndType(true, false);
+ InstructionDesc[OpMemoryModel].setResultAndType(false, false);
+ InstructionDesc[OpEntryPoint].setResultAndType(false, false);
+ InstructionDesc[OpExecutionMode].setResultAndType(false, false);
+ InstructionDesc[OpTypeVoid].setResultAndType(true, false);
+ InstructionDesc[OpTypeBool].setResultAndType(true, false);
+ InstructionDesc[OpTypeInt].setResultAndType(true, false);
+ InstructionDesc[OpTypeFloat].setResultAndType(true, false);
+ InstructionDesc[OpTypeVector].setResultAndType(true, false);
+ InstructionDesc[OpTypeMatrix].setResultAndType(true, false);
+ InstructionDesc[OpTypeSampler].setResultAndType(true, false);
+ InstructionDesc[OpTypeFilter].setResultAndType(true, false);
+ InstructionDesc[OpTypeArray].setResultAndType(true, false);
+ InstructionDesc[OpTypeRuntimeArray].setResultAndType(true, false);
+ InstructionDesc[OpTypeStruct].setResultAndType(true, false);
+ InstructionDesc[OpTypeOpaque].setResultAndType(true, false);
+ InstructionDesc[OpTypePointer].setResultAndType(true, false);
+ InstructionDesc[OpTypeFunction].setResultAndType(true, false);
+ InstructionDesc[OpTypeEvent].setResultAndType(true, false);
+ InstructionDesc[OpTypeDeviceEvent].setResultAndType(true, false);
+ InstructionDesc[OpTypeReserveId].setResultAndType(true, false);
+ InstructionDesc[OpTypeQueue].setResultAndType(true, false);
+ InstructionDesc[OpTypePipe].setResultAndType(true, false);
+ InstructionDesc[OpFunctionEnd].setResultAndType(false, false);
+ InstructionDesc[OpStore].setResultAndType(false, false);
+ InstructionDesc[OpDecorationGroup].setResultAndType(true, false);
+ InstructionDesc[OpDecorate].setResultAndType(false, false);
+ InstructionDesc[OpMemberDecorate].setResultAndType(false, false);
+ InstructionDesc[OpGroupDecorate].setResultAndType(false, false);
+ InstructionDesc[OpGroupMemberDecorate].setResultAndType(false, false);
+ InstructionDesc[OpName].setResultAndType(false, false);
+ InstructionDesc[OpMemberName].setResultAndType(false, false);
+ InstructionDesc[OpString].setResultAndType(true, false);
+ InstructionDesc[OpLine].setResultAndType(false, false);
+ InstructionDesc[OpCopyMemory].setResultAndType(false, false);
+ InstructionDesc[OpCopyMemorySized].setResultAndType(false, false);
+ InstructionDesc[OpEmitVertex].setResultAndType(false, false);
+ InstructionDesc[OpEndPrimitive].setResultAndType(false, false);
+ InstructionDesc[OpEmitStreamVertex].setResultAndType(false, false);
+ InstructionDesc[OpEndStreamPrimitive].setResultAndType(false, false);
+ InstructionDesc[OpControlBarrier].setResultAndType(false, false);
+ InstructionDesc[OpMemoryBarrier].setResultAndType(false, false);
+ InstructionDesc[OpAtomicInit].setResultAndType(false, false);
+ InstructionDesc[OpAtomicStore].setResultAndType(false, false);
+ InstructionDesc[OpLoopMerge].setResultAndType(false, false);
+ InstructionDesc[OpSelectionMerge].setResultAndType(false, false);
+ InstructionDesc[OpLabel].setResultAndType(true, false);
+ InstructionDesc[OpBranch].setResultAndType(false, false);
+ InstructionDesc[OpBranchConditional].setResultAndType(false, false);
+ InstructionDesc[OpSwitch].setResultAndType(false, false);
+ InstructionDesc[OpKill].setResultAndType(false, false);
+ InstructionDesc[OpReturn].setResultAndType(false, false);
+ InstructionDesc[OpReturnValue].setResultAndType(false, false);
+ InstructionDesc[OpUnreachable].setResultAndType(false, false);
+ InstructionDesc[OpLifetimeStart].setResultAndType(false, false);
+ InstructionDesc[OpLifetimeStop].setResultAndType(false, false);
+ InstructionDesc[OpCompileFlag].setResultAndType(false, false);
+ InstructionDesc[OpCommitReadPipe].setResultAndType(false, false);
+ InstructionDesc[OpCommitWritePipe].setResultAndType(false, false);
+ InstructionDesc[OpGroupCommitWritePipe].setResultAndType(false, false);
+ InstructionDesc[OpGroupCommitReadPipe].setResultAndType(false, false);
+ InstructionDesc[OpCaptureEventProfilingInfo].setResultAndType(false, false);
+ InstructionDesc[OpSetUserEventStatus].setResultAndType(false, false);
+ InstructionDesc[OpRetainEvent].setResultAndType(false, false);
+ InstructionDesc[OpReleaseEvent].setResultAndType(false, false);
+
+ // Specific additional context-dependent operands
+
+ ExecutionModeOperands[ExecutionModeInvocations].push(OperandLiteralNumber, "Number of invocations");
+
+ ExecutionModeOperands[ExecutionModeLocalSize].push(OperandLiteralNumber, "'x size'");
+ ExecutionModeOperands[ExecutionModeLocalSize].push(OperandLiteralNumber, "'y size'");
+ ExecutionModeOperands[ExecutionModeLocalSize].push(OperandLiteralNumber, "'z size'");
+
+ ExecutionModeOperands[ExecutionModeLocalSizeHint].push(OperandLiteralNumber, "'x size'");
+ ExecutionModeOperands[ExecutionModeLocalSizeHint].push(OperandLiteralNumber, "'y size'");
+ ExecutionModeOperands[ExecutionModeLocalSizeHint].push(OperandLiteralNumber, "'z size'");
+
+ ExecutionModeOperands[ExecutionModeOutputVertices].push(OperandLiteralNumber, "Vertex count");
+ ExecutionModeOperands[ExecutionModeVecTypeHint].push(OperandId, "Vector type");
+
+ DecorationOperands[DecorationStream].push(OperandLiteralNumber, "Stream number");
+ DecorationOperands[DecorationLocation].push(OperandLiteralNumber, "Location");
+ DecorationOperands[DecorationComponent].push(OperandLiteralNumber, "Component within a vector");
+ DecorationOperands[DecorationIndex].push(OperandLiteralNumber, "Index");
+ DecorationOperands[DecorationBinding].push(OperandLiteralNumber, "Binding point");
+ DecorationOperands[DecorationDescriptorSet].push(OperandLiteralNumber, "Descriptor set");
+ DecorationOperands[DecorationOffset].push(OperandLiteralNumber, "Byte offset");
+ DecorationOperands[DecorationAlignment].push(OperandLiteralNumber, "Declared alignment");
+ DecorationOperands[DecorationXfbBuffer].push(OperandLiteralNumber, "XFB Buffer number");
+ DecorationOperands[DecorationStride].push(OperandLiteralNumber, "Stride");
+ DecorationOperands[DecorationBuiltIn].push(OperandLiteralNumber, "See <<BuiltIn,*BuiltIn*>>");
+ DecorationOperands[DecorationFPRoundingMode].push(OperandFPRoundingMode, "floating-point rounding mode");
+ DecorationOperands[DecorationFPFastMathMode].push(OperandFPFastMath, "fast-math mode");
+ DecorationOperands[DecorationLinkageAttributes].push(OperandLiteralString, "name");
+ DecorationOperands[DecorationLinkageAttributes].push(OperandLinkageType, "linkage type");
+ DecorationOperands[DecorationFuncParamAttr].push(OperandFuncParamAttr, "function parameter attribute");
+ DecorationOperands[DecorationSpecId].push(OperandLiteralNumber, "Specialization Constant ID");
+
+ OperandClassParams[OperandSource].set(SourceLanguageCeiling, SourceString, 0);
+ OperandClassParams[OperandExecutionModel].set(ExecutionModelCeiling, ExecutionModelString, ExecutionModelParams);
+ OperandClassParams[OperandAddressing].set(AddressingModelCeiling, AddressingString, AddressingParams);
+ OperandClassParams[OperandMemory].set(MemoryModelCeiling, MemoryString, MemoryParams);
+ OperandClassParams[OperandExecutionMode].set(ExecutionModeCeiling, ExecutionModeString, ExecutionModeParams);
+ OperandClassParams[OperandExecutionMode].setOperands(ExecutionModeOperands);
+ OperandClassParams[OperandStorage].set(StorageClassCeiling, StorageClassString, StorageParams);
+ OperandClassParams[OperandDimensionality].set(DimensionCeiling, DimensionString, DimensionalityParams);
+ OperandClassParams[OperandSamplerAddressingMode].set(SamplerAddressingModeCeiling, SamplerAddressingModeString, SamplerAddressingModeParams);
+ OperandClassParams[OperandSamplerFilterMode].set(SamplerFilterModeCeiling, SamplerFilterModeString, SamplerFilterModeParams);
+ OperandClassParams[OperandFPFastMath].set(FPFastMathCeiling, FPFastMathString, FPFastMathParams, true);
+ OperandClassParams[OperandFPRoundingMode].set(FPRoundingModeCeiling, FPRoundingModeString, FPRoundingModeParams);
+ OperandClassParams[OperandLinkageType].set(LinkageTypeCeiling, LinkageTypeString, LinkageTypeParams);
+ OperandClassParams[OperandFuncParamAttr].set(FuncParamAttrCeiling, FuncParamAttrString, FuncParamAttrParams);
+ OperandClassParams[OperandAccessQualifier].set(AccessQualifierCeiling, AccessQualifierString, AccessQualifierParams);
+ OperandClassParams[OperandDecoration].set(DecorationCeiling, DecorationString, DecorationParams);
+ OperandClassParams[OperandDecoration].setOperands(DecorationOperands);
+ OperandClassParams[OperandBuiltIn].set(BuiltInCeiling, BuiltInString, BuiltInParams);
+ OperandClassParams[OperandSelect].set(SelectControlCeiling, SelectControlString, SelectionControlParams, true);
+ OperandClassParams[OperandLoop].set(LoopControlCeiling, LoopControlString, LoopControlParams, true);
+ OperandClassParams[OperandFunction].set(FunctionControlCeiling, FunctionControlString, FunctionControlParams, true);
+ OperandClassParams[OperandMemorySemantics].set(MemorySemanticsCeiling, MemorySemanticsString, MemorySemanticsParams, true);
+ OperandClassParams[OperandMemoryAccess].set(MemoryAccessCeiling, MemoryAccessString, MemoryAccessParams, true);
+ OperandClassParams[OperandExecutionScope].set(ExecutionScopeCeiling, ExecutionScopeString, ExecutionScopeParams);
+ OperandClassParams[OperandGroupOperation].set(GroupOperationCeiling, GroupOperationString, GroupOperationParams);
+ OperandClassParams[OperandKernelEnqueueFlags].set(KernelEnqueueFlagsCeiling, KernelEnqueueFlagsString, KernelEnqueueFlagsParams);
+ OperandClassParams[OperandKernelProfilingInfo].set(KernelProfilingInfoCeiling, KernelProfilingInfoString, KernelProfilingInfoParams, true);
+ OperandClassParams[OperandOpcode].set(OpcodeCeiling, OpcodeString, 0);
+
+ AddressingParams[AddressingModelPhysical32].caps.push_back(CapAddr);
+ AddressingParams[AddressingModelPhysical64].caps.push_back(CapAddr);
+
+ MemoryParams[MemoryModelSimple].caps.push_back(CapShader);
+ MemoryParams[MemoryModelGLSL450].caps.push_back(CapShader);
+ MemoryParams[MemoryModelOpenCL12].caps.push_back(CapKernel);
+ MemoryParams[MemoryModelOpenCL20].caps.push_back(CapKernel);
+ MemoryParams[MemoryModelOpenCL21].caps.push_back(CapKernel);
+
+ ExecutionModelParams[ExecutionModelVertex].caps.push_back(CapShader);
+ ExecutionModelParams[ExecutionModelTessellationControl].caps.push_back(CapTess);
+ ExecutionModelParams[ExecutionModelTessellationEvaluation].caps.push_back(CapTess);
+ ExecutionModelParams[ExecutionModelGeometry].caps.push_back(CapGeom);
+ ExecutionModelParams[ExecutionModelFragment].caps.push_back(CapShader);
+ ExecutionModelParams[ExecutionModelGLCompute].caps.push_back(CapShader);
+ ExecutionModelParams[ExecutionModelKernel].caps.push_back(CapKernel);
+
+ // Storage capabilites
+ StorageParams[StorageClassInput].caps.push_back(CapShader);
+ StorageParams[StorageClassUniform].caps.push_back(CapShader);
+ StorageParams[StorageClassOutput].caps.push_back(CapShader);
+ StorageParams[StorageClassPrivateGlobal].caps.push_back(CapShader);
+ StorageParams[StorageClassFunction].caps.push_back(CapShader);
+ StorageParams[StorageClassGeneric].caps.push_back(CapKernel);
+ StorageParams[StorageClassPrivate].caps.push_back(CapKernel);
+ StorageParams[StorageClassAtomicCounter].caps.push_back(CapShader);
+
+ // Sampler Filter & Addressing mode capabilities
+ SamplerAddressingModeParams[SamplerAddressingModeNone].caps.push_back(CapKernel);
+ SamplerAddressingModeParams[SamplerAddressingModeClampToEdge].caps.push_back(CapKernel);
+ SamplerAddressingModeParams[SamplerAddressingModeClamp].caps.push_back(CapKernel);
+ SamplerAddressingModeParams[SamplerAddressingModeRepeat].caps.push_back(CapKernel);
+ SamplerAddressingModeParams[SamplerAddressingModeRepeatMirrored].caps.push_back(CapKernel);
+
+ SamplerFilterModeParams[SamplerFilterModeNearest].caps.push_back(CapKernel);
+ SamplerFilterModeParams[SamplerFilterModeLinear].caps.push_back(CapKernel);
+
+ // fast math flags capabilities
+ for (int i = 0; i < FPFastMathCeiling; ++i) {
+ FPFastMathParams[i].caps.push_back(CapKernel);
+ }
+
+ // fp rounding mode capabilities
+ for (int i = 0; i < FPRoundingModeCeiling; ++i) {
+ FPRoundingModeParams[i].caps.push_back(CapKernel);
+ }
+
+ // linkage types
+ for (int i = 0; i < LinkageTypeCeiling; ++i) {
+ LinkageTypeParams[i].caps.push_back(CapLink);
+ }
+
+ // function argument types
+ for (int i = 0; i < FuncParamAttrCeiling; ++i) {
+ FuncParamAttrParams[i].caps.push_back(CapKernel);
+ }
+
+ // function argument types
+ for (int i = 0; i < AccessQualifierCeiling; ++i) {
+ AccessQualifierParams[i].caps.push_back(CapKernel);
+ }
+
+ ExecutionModeParams[ExecutionModeInvocations].caps.push_back(CapGeom);
+ ExecutionModeParams[ExecutionModeSpacingEqual].caps.push_back(CapTess);
+ ExecutionModeParams[ExecutionModeSpacingFractionalEven].caps.push_back(CapTess);
+ ExecutionModeParams[ExecutionModeSpacingFractionalOdd].caps.push_back(CapTess);
+ ExecutionModeParams[ExecutionModeVertexOrderCw].caps.push_back(CapTess);
+ ExecutionModeParams[ExecutionModeVertexOrderCcw].caps.push_back(CapTess);
+ ExecutionModeParams[ExecutionModePixelCenterInteger].caps.push_back(CapShader);
+ ExecutionModeParams[ExecutionModeOriginUpperLeft].caps.push_back(CapShader);
+ ExecutionModeParams[ExecutionModeEarlyFragmentTests].caps.push_back(CapShader);
+ ExecutionModeParams[ExecutionModePointMode].caps.push_back(CapTess);
+ ExecutionModeParams[ExecutionModeXfb].caps.push_back(CapShader);
+ ExecutionModeParams[ExecutionModeDepthReplacing].caps.push_back(CapShader);
+ ExecutionModeParams[ExecutionModeDepthAny].caps.push_back(CapShader);
+ ExecutionModeParams[ExecutionModeDepthGreater].caps.push_back(CapShader);
+ ExecutionModeParams[ExecutionModeDepthLess].caps.push_back(CapShader);
+ ExecutionModeParams[ExecutionModeDepthUnchanged].caps.push_back(CapShader);
+ ExecutionModeParams[ExecutionModeLocalSizeHint].caps.push_back(CapKernel);
+ ExecutionModeParams[ExecutionModeInputPoints].caps.push_back(CapGeom);
+ ExecutionModeParams[ExecutionModeInputLines].caps.push_back(CapGeom);
+ ExecutionModeParams[ExecutionModeInputLinesAdjacency].caps.push_back(CapGeom);
+ ExecutionModeParams[ExecutionModeInputTriangles].caps.push_back(CapGeom);
+ ExecutionModeParams[ExecutionModeInputTriangles].caps.push_back(CapTess);
+ ExecutionModeParams[ExecutionModeInputTrianglesAdjacency].caps.push_back(CapGeom);
+ ExecutionModeParams[ExecutionModeInputQuads].caps.push_back(CapTess);
+ ExecutionModeParams[ExecutionModeInputIsolines].caps.push_back(CapTess);
+ ExecutionModeParams[ExecutionModeOutputVertices].caps.push_back(CapGeom);
+ ExecutionModeParams[ExecutionModeOutputVertices].caps.push_back(CapTess);
+ ExecutionModeParams[ExecutionModeOutputPoints].caps.push_back(CapGeom);
+ ExecutionModeParams[ExecutionModeOutputLineStrip].caps.push_back(CapGeom);
+ ExecutionModeParams[ExecutionModeOutputTriangleStrip].caps.push_back(CapGeom);
+ ExecutionModeParams[ExecutionModeVecTypeHint].caps.push_back(CapKernel);
+ ExecutionModeParams[ExecutionModeContractionOff].caps.push_back(CapKernel);
+
+ DecorationParams[DecorationPrecisionLow].caps.push_back(CapShader);
+ DecorationParams[DecorationPrecisionMedium].caps.push_back(CapShader);
+ DecorationParams[DecorationPrecisionHigh].caps.push_back(CapShader);
+ DecorationParams[DecorationBlock].caps.push_back(CapShader);
+ DecorationParams[DecorationBufferBlock].caps.push_back(CapShader);
+ DecorationParams[DecorationRowMajor].caps.push_back(CapMatrix);
+ DecorationParams[DecorationColMajor].caps.push_back(CapMatrix);
+ DecorationParams[DecorationGLSLShared].caps.push_back(CapShader);
+ DecorationParams[DecorationGLSLStd140].caps.push_back(CapShader);
+ DecorationParams[DecorationGLSLStd430].caps.push_back(CapShader);
+ DecorationParams[DecorationGLSLPacked].caps.push_back(CapShader);
+ DecorationParams[DecorationSmooth].caps.push_back(CapShader);
+ DecorationParams[DecorationNoperspective].caps.push_back(CapShader);
+ DecorationParams[DecorationFlat].caps.push_back(CapShader);
+ DecorationParams[DecorationPatch].caps.push_back(CapTess);
+ DecorationParams[DecorationCentroid].caps.push_back(CapShader);
+ DecorationParams[DecorationSample].caps.push_back(CapShader);
+ DecorationParams[DecorationInvariant].caps.push_back(CapShader);
+ DecorationParams[DecorationConstant].caps.push_back(CapKernel);
+ DecorationParams[DecorationUniform].caps.push_back(CapShader);
+ DecorationParams[DecorationCPacked].caps.push_back(CapKernel);
+ DecorationParams[DecorationSaturatedConversion].caps.push_back(CapKernel);
+ DecorationParams[DecorationStream].caps.push_back(CapGeom);
+ DecorationParams[DecorationLocation].caps.push_back(CapShader);
+ DecorationParams[DecorationComponent].caps.push_back(CapShader);
+ DecorationParams[DecorationIndex].caps.push_back(CapShader);
+ DecorationParams[DecorationBinding].caps.push_back(CapShader);
+ DecorationParams[DecorationDescriptorSet].caps.push_back(CapShader);
+ DecorationParams[DecorationXfbBuffer].caps.push_back(CapShader);
+ DecorationParams[DecorationStride].caps.push_back(CapShader);
+ DecorationParams[DecorationBuiltIn].caps.push_back(CapShader);
+ DecorationParams[DecorationFuncParamAttr].caps.push_back(CapKernel);
+ DecorationParams[DecorationFPRoundingMode].caps.push_back(CapKernel);
+ DecorationParams[DecorationFPFastMathMode].caps.push_back(CapKernel);
+ DecorationParams[DecorationLinkageAttributes].caps.push_back(CapLink);
+ DecorationParams[DecorationSpecId].caps.push_back(CapShader);
+
+ BuiltInParams[BuiltInPosition].caps.push_back(CapShader);
+ BuiltInParams[BuiltInPointSize].caps.push_back(CapShader);
+ BuiltInParams[BuiltInClipVertex].caps.push_back(CapShader);
+ BuiltInParams[BuiltInClipDistance].caps.push_back(CapShader);
+ BuiltInParams[BuiltInCullDistance].caps.push_back(CapShader);
+ BuiltInParams[BuiltInVertexId].caps.push_back(CapShader);
+ BuiltInParams[BuiltInInstanceId].caps.push_back(CapShader);
+ BuiltInParams[BuiltInPrimitiveId].caps.push_back(CapGeom);
+ BuiltInParams[BuiltInPrimitiveId].caps.push_back(CapTess);
+ BuiltInParams[BuiltInInvocationId].caps.push_back(CapGeom);
+ BuiltInParams[BuiltInInvocationId].caps.push_back(CapTess);
+ BuiltInParams[BuiltInLayer].caps.push_back(CapGeom);
+ BuiltInParams[BuiltInViewportIndex].caps.push_back(CapGeom);
+ BuiltInParams[BuiltInTessLevelOuter].caps.push_back(CapTess);
+ BuiltInParams[BuiltInTessLevelInner].caps.push_back(CapTess);
+ BuiltInParams[BuiltInTessCoord].caps.push_back(CapTess);
+ BuiltInParams[BuiltInPatchVertices].caps.push_back(CapTess);
+ BuiltInParams[BuiltInFragCoord].caps.push_back(CapShader);
+ BuiltInParams[BuiltInPointCoord].caps.push_back(CapShader);
+ BuiltInParams[BuiltInFrontFacing].caps.push_back(CapShader);
+ BuiltInParams[BuiltInSampleId].caps.push_back(CapShader);
+ BuiltInParams[BuiltInSamplePosition].caps.push_back(CapShader);
+ BuiltInParams[BuiltInSampleMask].caps.push_back(CapShader);
+ BuiltInParams[BuiltInFragColor].caps.push_back(CapShader);
+ BuiltInParams[BuiltInFragDepth].caps.push_back(CapShader);
+ BuiltInParams[BuiltInHelperInvocation].caps.push_back(CapShader);
+ BuiltInParams[BuiltInLocalInvocationIndex].caps.push_back(CapShader);
+ BuiltInParams[BuiltInWorkDim].caps.push_back(CapKernel);
+ BuiltInParams[BuiltInGlobalSize].caps.push_back(CapKernel);
+ BuiltInParams[BuiltInEnqueuedWorkgroupSize].caps.push_back(CapKernel);
+ BuiltInParams[BuiltInGlobalOffset].caps.push_back(CapKernel);
+ BuiltInParams[BuiltInGlobalLinearId].caps.push_back(CapKernel);
+ BuiltInParams[BuiltInWorkgroupLinearId].caps.push_back(CapKernel);
+
+ BuiltInParams[BuiltInSubgroupSize].caps.push_back(CapKernel);
+ BuiltInParams[BuiltInSubgroupMaxSize].caps.push_back(CapKernel);
+ BuiltInParams[BuiltInNumSubgroups].caps.push_back(CapKernel);
+ BuiltInParams[BuiltInNumEnqueuedSubgroups].caps.push_back(CapKernel);
+ BuiltInParams[BuiltInSubgroupId].caps.push_back(CapKernel);
+ BuiltInParams[BuiltInSubgroupLocalInvocationId].caps.push_back(CapKernel);
+
+ DimensionalityParams[DimCube].caps.push_back(CapShader);
+ DimensionalityParams[DimRect].caps.push_back(CapShader);
+
+ // Group Operations
+ for (int i = 0; i < GroupOperationCeiling; ++i) {
+ GroupOperationParams[i].caps.push_back(CapKernel);
+ }
+
+ // Enqueue flags
+ for (int i = 0; i < KernelEnqueueFlagsCeiling; ++i) {
+ KernelEnqueueFlagsParams[i].caps.push_back(CapKernel);
+ }
+
+ // Profiling info
+ KernelProfilingInfoParams[0].caps.push_back(CapKernel);
+
+ // set name of operator, an initial set of <id> style operands, and the description
+
+ InstructionDesc[OpSource].operands.push(OperandSource, "");
+ InstructionDesc[OpSource].operands.push(OperandLiteralNumber, "'Version'");
+
+ InstructionDesc[OpSourceExtension].operands.push(OperandLiteralString, "'Extension'");
+
+ InstructionDesc[OpName].operands.push(OperandId, "'Target'");
+ InstructionDesc[OpName].operands.push(OperandLiteralString, "'Name'");
+
+ InstructionDesc[OpMemberName].operands.push(OperandId, "'Type'");
+ InstructionDesc[OpMemberName].operands.push(OperandLiteralNumber, "'Member'");
+ InstructionDesc[OpMemberName].operands.push(OperandLiteralString, "'Name'");
+
+ InstructionDesc[OpString].operands.push(OperandLiteralString, "'String'");
+
+ InstructionDesc[OpLine].operands.push(OperandId, "'Target'");
+ InstructionDesc[OpLine].operands.push(OperandId, "'File'");
+ InstructionDesc[OpLine].operands.push(OperandLiteralNumber, "'Line'");
+ InstructionDesc[OpLine].operands.push(OperandLiteralNumber, "'Column'");
+
+ InstructionDesc[OpExtension].operands.push(OperandLiteralString, "'Name'");
+
+ InstructionDesc[OpExtInstImport].operands.push(OperandLiteralString, "'Name'");
+
+ InstructionDesc[OpMemoryModel].operands.push(OperandAddressing, "");
+ InstructionDesc[OpMemoryModel].operands.push(OperandMemory, "");
+
+ InstructionDesc[OpEntryPoint].operands.push(OperandExecutionModel, "");
+ InstructionDesc[OpEntryPoint].operands.push(OperandId, "'Entry Point'");
+
+ InstructionDesc[OpExecutionMode].operands.push(OperandId, "'Entry Point'");
+ InstructionDesc[OpExecutionMode].operands.push(OperandExecutionMode, "'Mode'");
+ InstructionDesc[OpExecutionMode].operands.push(OperandVariableLiterals, "See <<Execution Mode,Execution Mode>>");
+
+ InstructionDesc[OpTypeInt].operands.push(OperandLiteralNumber, "'Width'");
+ InstructionDesc[OpTypeInt].operands.push(OperandLiteralNumber, "'Signedness'");
+
+ InstructionDesc[OpTypeFloat].operands.push(OperandLiteralNumber, "'Width'");
+
+ InstructionDesc[OpTypeVector].operands.push(OperandId, "'Component type'");
+ InstructionDesc[OpTypeVector].operands.push(OperandLiteralNumber, "'Component count'");
+
+ InstructionDesc[OpTypeMatrix].capabilities.push_back(CapMatrix);
+ InstructionDesc[OpTypeMatrix].operands.push(OperandId, "'Column type'");
+ InstructionDesc[OpTypeMatrix].operands.push(OperandLiteralNumber, "'Column count'");
+
+ InstructionDesc[OpTypeSampler].operands.push(OperandId, "'Sampled Type'");
+ InstructionDesc[OpTypeSampler].operands.push(OperandDimensionality, "");
+ InstructionDesc[OpTypeSampler].operands.push(OperandLiteralNumber, "'Content'");
+ InstructionDesc[OpTypeSampler].operands.push(OperandLiteralNumber, "'Arrayed'");
+ InstructionDesc[OpTypeSampler].operands.push(OperandLiteralNumber, "'Compare'");
+ InstructionDesc[OpTypeSampler].operands.push(OperandLiteralNumber, "'MS'");
+ InstructionDesc[OpTypeSampler].operands.push(OperandOptionalId, "'Qualifier'");
+
+ InstructionDesc[OpTypeArray].operands.push(OperandId, "'Element type'");
+ InstructionDesc[OpTypeArray].operands.push(OperandId, "'Length'");
+
+ InstructionDesc[OpTypeRuntimeArray].capabilities.push_back(CapShader);
+ InstructionDesc[OpTypeRuntimeArray].operands.push(OperandId, "'Element type'");
+
+ InstructionDesc[OpTypeStruct].operands.push(OperandVariableIds, "'Member 0 type', +\n'member 1 type', +\n...");
+
+ InstructionDesc[OpTypeOpaque].capabilities.push_back(CapKernel);
+ InstructionDesc[OpTypeOpaque].operands.push(OperandLiteralString, "The name of the opaque type.");
+
+ InstructionDesc[OpTypePointer].operands.push(OperandStorage, "");
+ InstructionDesc[OpTypePointer].operands.push(OperandId, "'Type'");
+
+ InstructionDesc[OpTypeEvent].capabilities.push_back(CapKernel);
+
+ InstructionDesc[OpTypeDeviceEvent].capabilities.push_back(CapKernel);
+
+ InstructionDesc[OpTypeReserveId].capabilities.push_back(CapKernel);
+
+ InstructionDesc[OpTypeQueue].capabilities.push_back(CapKernel);
+
+ InstructionDesc[OpTypePipe].operands.push(OperandId, "'Type'");
+ InstructionDesc[OpTypePipe].operands.push(OperandAccessQualifier, "'Qualifier'");
+ InstructionDesc[OpTypePipe].capabilities.push_back(CapKernel);
+
+ InstructionDesc[OpTypeFunction].operands.push(OperandId, "'Return Type'");
+ InstructionDesc[OpTypeFunction].operands.push(OperandVariableIds, "'Parameter 0 Type', +\n'Parameter 1 Type', +\n...");
+
+ InstructionDesc[OpConstant].operands.push(OperandVariableLiterals, "'Value'");
+
+ InstructionDesc[OpConstantComposite].operands.push(OperandVariableIds, "'Constituents'");
+
+ InstructionDesc[OpConstantNullPointer].capabilities.push_back(CapAddr);
+
+ InstructionDesc[OpConstantNullObject].capabilities.push_back(CapKernel);
+
+ InstructionDesc[OpConstantSampler].capabilities.push_back(CapKernel);
+ InstructionDesc[OpConstantSampler].operands.push(OperandLiteralNumber, "'Mode'");
+ InstructionDesc[OpConstantSampler].operands.push(OperandLiteralNumber, "'Param'");
+ InstructionDesc[OpConstantSampler].operands.push(OperandLiteralNumber, "'Filter'");
+
+ InstructionDesc[OpSpecConstantTrue].capabilities.push_back(CapShader);
+
+ InstructionDesc[OpSpecConstantFalse].capabilities.push_back(CapShader);
+
+ InstructionDesc[OpSpecConstant].operands.push(OperandVariableLiterals, "'Value'");
+ InstructionDesc[OpSpecConstant].capabilities.push_back(CapShader);
+
+ InstructionDesc[OpSpecConstantComposite].operands.push(OperandVariableIds, "'Constituents'");
+ InstructionDesc[OpSpecConstantComposite].capabilities.push_back(CapShader);
+
+ InstructionDesc[OpVariable].operands.push(OperandStorage, "");
+ InstructionDesc[OpVariable].operands.push(OperandOptionalId, "'Initializer'");
+
+ InstructionDesc[OpVariableArray].operands.push(OperandStorage, "");
+ InstructionDesc[OpVariableArray].operands.push(OperandId, "'N'");
+ InstructionDesc[OpVariableArray].capabilities.push_back(CapAddr);
+
+ InstructionDesc[OpFunction].operands.push(OperandFunction, "");
+ InstructionDesc[OpFunction].operands.push(OperandId, "'Function Type'");
+
+ InstructionDesc[OpFunctionCall].operands.push(OperandId, "'Function'");
+ InstructionDesc[OpFunctionCall].operands.push(OperandVariableIds, "'Argument 0', +\n'Argument 1', +\n...");
+
+ InstructionDesc[OpExtInst].operands.push(OperandId, "'Set'");
+ InstructionDesc[OpExtInst].operands.push(OperandLiteralNumber, "'Instruction'");
+ InstructionDesc[OpExtInst].operands.push(OperandVariableIds, "'Operand 1', +\n'Operand 2', +\n...");
+
+ InstructionDesc[OpLoad].operands.push(OperandId, "'Pointer'");
+ InstructionDesc[OpLoad].operands.push(OperandVariableLiterals, "'Memory Access'");
+
+ InstructionDesc[OpStore].operands.push(OperandId, "'Pointer'");
+ InstructionDesc[OpStore].operands.push(OperandId, "'Object'");
+ InstructionDesc[OpStore].operands.push(OperandVariableLiterals, "'Memory Access'");
+
+ InstructionDesc[OpPhi].operands.push(OperandVariableIds, "");
+
+ InstructionDesc[OpDecorate].operands.push(OperandId, "'Target'");
+ InstructionDesc[OpDecorate].operands.push(OperandDecoration, "");
+ InstructionDesc[OpDecorate].operands.push(OperandVariableLiterals, "See <<Decoration,'Decoration'>>.");
+
+ InstructionDesc[OpMemberDecorate].operands.push(OperandId, "'Structure type'");
+ InstructionDesc[OpMemberDecorate].operands.push(OperandLiteralNumber, "'Member'");
+ InstructionDesc[OpMemberDecorate].operands.push(OperandDecoration, "");
+ InstructionDesc[OpMemberDecorate].operands.push(OperandVariableLiterals, "See <<Decoration,'Decoration'>>.");
+
+ InstructionDesc[OpGroupDecorate].operands.push(OperandId, "'Decoration group'");
+ InstructionDesc[OpGroupDecorate].operands.push(OperandVariableIds, "'Target', 'Target', ...");
+
+ InstructionDesc[OpGroupMemberDecorate].operands.push(OperandId, "'Decoration group'");
+ InstructionDesc[OpGroupMemberDecorate].operands.push(OperandVariableIds, "'Target', 'Target', ...");
+
+ InstructionDesc[OpVectorExtractDynamic].operands.push(OperandId, "'Vector'");
+ InstructionDesc[OpVectorExtractDynamic].operands.push(OperandId, "'Index'");
+
+ InstructionDesc[OpVectorInsertDynamic].operands.push(OperandId, "'Vector'");
+ InstructionDesc[OpVectorInsertDynamic].operands.push(OperandId, "'Component'");
+ InstructionDesc[OpVectorInsertDynamic].operands.push(OperandId, "'Index'");
+
+ InstructionDesc[OpVectorShuffle].operands.push(OperandId, "'Vector 1'");
+ InstructionDesc[OpVectorShuffle].operands.push(OperandId, "'Vector 2'");
+ InstructionDesc[OpVectorShuffle].operands.push(OperandVariableLiterals, "'Components'");
+
+ InstructionDesc[OpCompositeConstruct].operands.push(OperandVariableIds, "'Constituents'");
+
+ InstructionDesc[OpCompositeExtract].operands.push(OperandId, "'Composite'");
+ InstructionDesc[OpCompositeExtract].operands.push(OperandVariableLiterals, "'Indexes'");
+
+ InstructionDesc[OpCompositeInsert].operands.push(OperandId, "'Object'");
+ InstructionDesc[OpCompositeInsert].operands.push(OperandId, "'Composite'");
+ InstructionDesc[OpCompositeInsert].operands.push(OperandVariableLiterals, "'Indexes'");
+
+ InstructionDesc[OpCopyObject].operands.push(OperandId, "'Operand'");
+
+ InstructionDesc[OpCopyMemory].operands.push(OperandId, "'Target'");
+ InstructionDesc[OpCopyMemory].operands.push(OperandId, "'Source'");
+ InstructionDesc[OpCopyMemory].operands.push(OperandVariableLiterals, "'Memory Access'");
+
+ InstructionDesc[OpCopyMemorySized].operands.push(OperandId, "'Target'");
+ InstructionDesc[OpCopyMemorySized].operands.push(OperandId, "'Source'");
+ InstructionDesc[OpCopyMemorySized].operands.push(OperandId, "'Size'");
+ InstructionDesc[OpCopyMemorySized].operands.push(OperandVariableLiterals, "'Memory Access'");
+
+ InstructionDesc[OpCopyMemorySized].capabilities.push_back(CapAddr);
+
+ InstructionDesc[OpSampler].operands.push(OperandId, "'Sampler'");
+ InstructionDesc[OpSampler].operands.push(OperandId, "'Filter'");
+
+ InstructionDesc[OpTextureSample].operands.push(OperandId, "'Sampler'");
+ InstructionDesc[OpTextureSample].operands.push(OperandId, "'Coordinate'");
+ InstructionDesc[OpTextureSample].operands.push(OperandOptionalId, "['Bias']");
+ InstructionDesc[OpTextureSample].capabilities.push_back(CapShader);
+
+ InstructionDesc[OpTextureSampleDref].operands.push(OperandId, "'Sampler'");
+ InstructionDesc[OpTextureSampleDref].operands.push(OperandId, "'Coordinate'");
+ InstructionDesc[OpTextureSampleDref].operands.push(OperandId, "'D~ref~'");
+ InstructionDesc[OpTextureSampleDref].capabilities.push_back(CapShader);
+
+ InstructionDesc[OpTextureSampleLod].operands.push(OperandId, "'Sampler'");
+ InstructionDesc[OpTextureSampleLod].operands.push(OperandId, "'Coordinate'");
+ InstructionDesc[OpTextureSampleLod].operands.push(OperandId, "'Level of Detail'");
+ InstructionDesc[OpTextureSampleLod].capabilities.push_back(CapShader);
+
+ InstructionDesc[OpTextureSampleProj].operands.push(OperandId, "'Sampler'");
+ InstructionDesc[OpTextureSampleProj].operands.push(OperandId, "'Coordinate'");
+ InstructionDesc[OpTextureSampleProj].operands.push(OperandOptionalId, "['Bias']");
+ InstructionDesc[OpTextureSampleProj].capabilities.push_back(CapShader);
+
+ InstructionDesc[OpTextureSampleGrad].operands.push(OperandId, "'Sampler'");
+ InstructionDesc[OpTextureSampleGrad].operands.push(OperandId, "'Coordinate'");
+ InstructionDesc[OpTextureSampleGrad].operands.push(OperandId, "'dx'");
+ InstructionDesc[OpTextureSampleGrad].operands.push(OperandId, "'dy'");
+ InstructionDesc[OpTextureSampleGrad].capabilities.push_back(CapShader);
+
+ InstructionDesc[OpTextureSampleOffset].operands.push(OperandId, "'Sampler'");
+ InstructionDesc[OpTextureSampleOffset].operands.push(OperandId, "'Coordinate'");
+ InstructionDesc[OpTextureSampleOffset].operands.push(OperandId, "'Offset'");
+ InstructionDesc[OpTextureSampleOffset].operands.push(OperandOptionalId, "['Bias']");
+ InstructionDesc[OpTextureSampleOffset].capabilities.push_back(CapShader);
+
+ InstructionDesc[OpTextureSampleProjLod].operands.push(OperandId, "'Sampler'");
+ InstructionDesc[OpTextureSampleProjLod].operands.push(OperandId, "'Coordinate'");
+ InstructionDesc[OpTextureSampleProjLod].operands.push(OperandId, "'Level of Detail'");
+ InstructionDesc[OpTextureSampleProjLod].capabilities.push_back(CapShader);
+
+ InstructionDesc[OpTextureSampleProjGrad].operands.push(OperandId, "'Sampler'");
+ InstructionDesc[OpTextureSampleProjGrad].operands.push(OperandId, "'Coordinate'");
+ InstructionDesc[OpTextureSampleProjGrad].operands.push(OperandId, "'dx'");
+ InstructionDesc[OpTextureSampleProjGrad].operands.push(OperandId, "'dy'");
+ InstructionDesc[OpTextureSampleProjGrad].capabilities.push_back(CapShader);
+
+ InstructionDesc[OpTextureSampleLodOffset].operands.push(OperandId, "'Sampler'");
+ InstructionDesc[OpTextureSampleLodOffset].operands.push(OperandId, "'Coordinate'");
+ InstructionDesc[OpTextureSampleLodOffset].operands.push(OperandId, "'Level of Detail'");
+ InstructionDesc[OpTextureSampleLodOffset].operands.push(OperandId, "'Offset'");
+ InstructionDesc[OpTextureSampleLodOffset].capabilities.push_back(CapShader);
+
+ InstructionDesc[OpTextureSampleProjOffset].operands.push(OperandId, "'Sampler'");
+ InstructionDesc[OpTextureSampleProjOffset].operands.push(OperandId, "'Coordinate'");
+ InstructionDesc[OpTextureSampleProjOffset].operands.push(OperandId, "'Offset'");
+ InstructionDesc[OpTextureSampleProjOffset].operands.push(OperandOptionalId, "['Bias']");
+ InstructionDesc[OpTextureSampleProjOffset].capabilities.push_back(CapShader);
+
+ InstructionDesc[OpTextureSampleGradOffset].operands.push(OperandId, "'Sampler'");
+ InstructionDesc[OpTextureSampleGradOffset].operands.push(OperandId, "'Coordinate'");
+ InstructionDesc[OpTextureSampleGradOffset].operands.push(OperandId, "'dx'");
+ InstructionDesc[OpTextureSampleGradOffset].operands.push(OperandId, "'dy'");
+ InstructionDesc[OpTextureSampleGradOffset].operands.push(OperandId, "'Offset'");
+ InstructionDesc[OpTextureSampleGradOffset].capabilities.push_back(CapShader);
+
+ InstructionDesc[OpTextureSampleProjLodOffset].operands.push(OperandId, "'Sampler'");
+ InstructionDesc[OpTextureSampleProjLodOffset].operands.push(OperandId, "'Coordinate'");
+ InstructionDesc[OpTextureSampleProjLodOffset].operands.push(OperandId, "'Level of Detail'");
+ InstructionDesc[OpTextureSampleProjLodOffset].operands.push(OperandId, "'Offset'");
+ InstructionDesc[OpTextureSampleProjLodOffset].capabilities.push_back(CapShader);
+
+ InstructionDesc[OpTextureSampleProjGradOffset].operands.push(OperandId, "'Sampler'");
+ InstructionDesc[OpTextureSampleProjGradOffset].operands.push(OperandId, "'Coordinate'");
+ InstructionDesc[OpTextureSampleProjGradOffset].operands.push(OperandId, "'dx'");
+ InstructionDesc[OpTextureSampleProjGradOffset].operands.push(OperandId, "'dy'");
+ InstructionDesc[OpTextureSampleProjGradOffset].operands.push(OperandId, "'Offset'");
+ InstructionDesc[OpTextureSampleProjGradOffset].capabilities.push_back(CapShader);
+
+ InstructionDesc[OpTextureFetchTexelLod].operands.push(OperandId, "'Sampler'");
+ InstructionDesc[OpTextureFetchTexelLod].operands.push(OperandId, "'Coordinate'");
+ InstructionDesc[OpTextureFetchTexelLod].operands.push(OperandId, "'Level of Detail'");
+ InstructionDesc[OpTextureFetchTexelLod].capabilities.push_back(CapShader);
+
+ InstructionDesc[OpTextureFetchTexelOffset].operands.push(OperandId, "'Sampler'");
+ InstructionDesc[OpTextureFetchTexelOffset].operands.push(OperandId, "'Coordinate'");
+ InstructionDesc[OpTextureFetchTexelOffset].operands.push(OperandId, "'Offset'");
+ InstructionDesc[OpTextureFetchTexelOffset].capabilities.push_back(CapShader);
+
+ InstructionDesc[OpTextureFetchSample].operands.push(OperandId, "'Sampler'");
+ InstructionDesc[OpTextureFetchSample].operands.push(OperandId, "'Coordinate'");
+ InstructionDesc[OpTextureFetchSample].operands.push(OperandId, "'Sample'");
+ InstructionDesc[OpTextureFetchSample].capabilities.push_back(CapShader);
+
+ InstructionDesc[OpTextureFetchTexel].operands.push(OperandId, "'Sampler'");
+ InstructionDesc[OpTextureFetchTexel].operands.push(OperandId, "'Element'");
+ InstructionDesc[OpTextureFetchTexel].capabilities.push_back(CapShader);
+
+ InstructionDesc[OpTextureGather].operands.push(OperandId, "'Sampler'");
+ InstructionDesc[OpTextureGather].operands.push(OperandId, "'Coordinate'");
+ InstructionDesc[OpTextureGather].operands.push(OperandId, "'Component'");
+ InstructionDesc[OpTextureGather].capabilities.push_back(CapShader);
+
+ InstructionDesc[OpTextureGatherOffset].operands.push(OperandId, "'Sampler'");
+ InstructionDesc[OpTextureGatherOffset].operands.push(OperandId, "'Coordinate'");
+ InstructionDesc[OpTextureGatherOffset].operands.push(OperandId, "'Component'");
+ InstructionDesc[OpTextureGatherOffset].operands.push(OperandId, "'Offset'");
+ InstructionDesc[OpTextureGatherOffset].capabilities.push_back(CapShader);
+
+ InstructionDesc[OpTextureGatherOffsets].operands.push(OperandId, "'Sampler'");
+ InstructionDesc[OpTextureGatherOffsets].operands.push(OperandId, "'Coordinate'");
+ InstructionDesc[OpTextureGatherOffsets].operands.push(OperandId, "'Component'");
+ InstructionDesc[OpTextureGatherOffsets].operands.push(OperandId, "'Offsets'");
+ InstructionDesc[OpTextureGatherOffsets].capabilities.push_back(CapShader);
+
+ InstructionDesc[OpTextureQuerySizeLod].operands.push(OperandId, "'Sampler'");
+ InstructionDesc[OpTextureQuerySizeLod].operands.push(OperandId, "'Level of Detail'");
+ InstructionDesc[OpTextureQuerySizeLod].capabilities.push_back(CapShader);
+
+ InstructionDesc[OpTextureQuerySize].operands.push(OperandId, "'Sampler'");
+ InstructionDesc[OpTextureQuerySize].capabilities.push_back(CapShader);
+
+ InstructionDesc[OpTextureQueryLod].operands.push(OperandId, "'Sampler'");
+ InstructionDesc[OpTextureQueryLod].operands.push(OperandId, "'Coordinate'");
+ InstructionDesc[OpTextureQueryLod].capabilities.push_back(CapShader);
+
+ InstructionDesc[OpTextureQueryLevels].operands.push(OperandId, "'Sampler'");
+ InstructionDesc[OpTextureQueryLevels].capabilities.push_back(CapShader);
+
+ InstructionDesc[OpTextureQuerySamples].operands.push(OperandId, "'Sampler'");
+ InstructionDesc[OpTextureQuerySamples].capabilities.push_back(CapShader);
+
+ InstructionDesc[OpAccessChain].operands.push(OperandId, "'Base'");
+ InstructionDesc[OpAccessChain].operands.push(OperandVariableIds, "'Indexes'");
+
+ InstructionDesc[OpInBoundsAccessChain].operands.push(OperandId, "'Base'");
+ InstructionDesc[OpInBoundsAccessChain].operands.push(OperandVariableIds, "'Indexes'");
+
+ InstructionDesc[OpSNegate].operands.push(OperandId, "'Operand'");
+
+ InstructionDesc[OpFNegate].operands.push(OperandId, "'Operand'");
+
+ InstructionDesc[OpNot].operands.push(OperandId, "'Operand'");
+
+ InstructionDesc[OpAny].operands.push(OperandId, "'Vector'");
+
+ InstructionDesc[OpAll].operands.push(OperandId, "'Vector'");
+
+ InstructionDesc[OpConvertFToU].operands.push(OperandId, "'Float Value'");
+
+ InstructionDesc[OpConvertFToS].operands.push(OperandId, "'Float Value'");
+
+ InstructionDesc[OpConvertSToF].operands.push(OperandId, "'Signed Value'");
+
+ InstructionDesc[OpConvertUToF].operands.push(OperandId, "'Unsigned value'");
+
+ InstructionDesc[OpUConvert].operands.push(OperandId, "'Unsigned value'");
+
+ InstructionDesc[OpSConvert].operands.push(OperandId, "'Signed Value'");
+
+ InstructionDesc[OpFConvert].operands.push(OperandId, "'Float Value'");
+
+ InstructionDesc[OpSatConvertSToU].operands.push(OperandId, "'Signed Value'");
+ InstructionDesc[OpSatConvertSToU].capabilities.push_back(CapKernel);
+
+ InstructionDesc[OpSatConvertUToS].operands.push(OperandId, "'Unsigned Value'");
+ InstructionDesc[OpSatConvertUToS].capabilities.push_back(CapKernel);
+
+ InstructionDesc[OpConvertPtrToU].operands.push(OperandId, "'Pointer'");
+ InstructionDesc[OpConvertPtrToU].capabilities.push_back(CapAddr);
+
+ InstructionDesc[OpConvertUToPtr].operands.push(OperandId, "'Integer value'");
+ InstructionDesc[OpConvertUToPtr].capabilities.push_back(CapAddr);
+
+ InstructionDesc[OpPtrCastToGeneric].operands.push(OperandId, "'Source pointer'");
+ InstructionDesc[OpPtrCastToGeneric].capabilities.push_back(CapKernel);
+
+
+ InstructionDesc[OpGenericCastToPtr].operands.push(OperandId, "'Source pointer'");
+ InstructionDesc[OpGenericCastToPtr].capabilities.push_back(CapKernel);
+
+ InstructionDesc[OpGenericCastToPtrExplicit].operands.push(OperandId, "'Source pointer'");
+ InstructionDesc[OpGenericCastToPtrExplicit].operands.push(OperandStorage, "'storage'");
+ InstructionDesc[OpGenericCastToPtrExplicit].capabilities.push_back(CapKernel);
+
+ InstructionDesc[OpGenericPtrMemSemantics].operands.push(OperandId, "'ptr'");
+ InstructionDesc[OpGenericPtrMemSemantics].capabilities.push_back(CapKernel);
+
+ InstructionDesc[OpBitcast].operands.push(OperandId, "'Operand'");
+
+ InstructionDesc[OpTranspose].capabilities.push_back(CapMatrix);
+ InstructionDesc[OpTranspose].operands.push(OperandId, "'Matrix'");
+
+ InstructionDesc[OpIsNan].operands.push(OperandId, "'x'");
+
+ InstructionDesc[OpIsInf].operands.push(OperandId, "'x'");
+
+ InstructionDesc[OpIsFinite].capabilities.push_back(CapKernel);
+ InstructionDesc[OpIsFinite].operands.push(OperandId, "'x'");
+
+ InstructionDesc[OpIsNormal].capabilities.push_back(CapKernel);
+ InstructionDesc[OpIsNormal].operands.push(OperandId, "'x'");
+
+ InstructionDesc[OpSignBitSet].capabilities.push_back(CapKernel);
+ InstructionDesc[OpSignBitSet].operands.push(OperandId, "'x'");
+
+ InstructionDesc[OpLessOrGreater].capabilities.push_back(CapKernel);
+ InstructionDesc[OpLessOrGreater].operands.push(OperandId, "'x'");
+ InstructionDesc[OpLessOrGreater].operands.push(OperandId, "'y'");
+
+ InstructionDesc[OpOrdered].capabilities.push_back(CapKernel);
+ InstructionDesc[OpOrdered].operands.push(OperandId, "'x'");
+ InstructionDesc[OpOrdered].operands.push(OperandId, "'y'");
+
+ InstructionDesc[OpUnordered].capabilities.push_back(CapKernel);
+ InstructionDesc[OpUnordered].operands.push(OperandId, "'x'");
+ InstructionDesc[OpUnordered].operands.push(OperandId, "'y'");
+
+ InstructionDesc[OpArrayLength].operands.push(OperandId, "'Structure'");
+ InstructionDesc[OpArrayLength].operands.push(OperandLiteralNumber, "'Array member'");
+ InstructionDesc[OpArrayLength].capabilities.push_back(CapShader);
+
+ InstructionDesc[OpIAdd].operands.push(OperandId, "'Operand 1'");
+ InstructionDesc[OpIAdd].operands.push(OperandId, "'Operand 2'");
+
+ InstructionDesc[OpFAdd].operands.push(OperandId, "'Operand 1'");
+ InstructionDesc[OpFAdd].operands.push(OperandId, "'Operand 2'");
+
+ InstructionDesc[OpISub].operands.push(OperandId, "'Operand 1'");
+ InstructionDesc[OpISub].operands.push(OperandId, "'Operand 2'");
+
+ InstructionDesc[OpFSub].operands.push(OperandId, "'Operand 1'");
+ InstructionDesc[OpFSub].operands.push(OperandId, "'Operand 2'");
+
+ InstructionDesc[OpIMul].operands.push(OperandId, "'Operand 1'");
+ InstructionDesc[OpIMul].operands.push(OperandId, "'Operand 2'");
+
+ InstructionDesc[OpFMul].operands.push(OperandId, "'Operand 1'");
+ InstructionDesc[OpFMul].operands.push(OperandId, "'Operand 2'");
+
+ InstructionDesc[OpUDiv].operands.push(OperandId, "'Operand 1'");
+ InstructionDesc[OpUDiv].operands.push(OperandId, "'Operand 2'");
+
+ InstructionDesc[OpSDiv].operands.push(OperandId, "'Operand 1'");
+ InstructionDesc[OpSDiv].operands.push(OperandId, "'Operand 2'");
+
+ InstructionDesc[OpFDiv].operands.push(OperandId, "'Operand 1'");
+ InstructionDesc[OpFDiv].operands.push(OperandId, "'Operand 2'");
+
+ InstructionDesc[OpUMod].operands.push(OperandId, "'Operand 1'");
+ InstructionDesc[OpUMod].operands.push(OperandId, "'Operand 2'");
+
+ InstructionDesc[OpSRem].operands.push(OperandId, "'Operand 1'");
+ InstructionDesc[OpSRem].operands.push(OperandId, "'Operand 2'");
+
+ InstructionDesc[OpSMod].operands.push(OperandId, "'Operand 1'");
+ InstructionDesc[OpSMod].operands.push(OperandId, "'Operand 2'");
+
+ InstructionDesc[OpFRem].operands.push(OperandId, "'Operand 1'");
+ InstructionDesc[OpFRem].operands.push(OperandId, "'Operand 2'");
+
+ InstructionDesc[OpFMod].operands.push(OperandId, "'Operand 1'");
+ InstructionDesc[OpFMod].operands.push(OperandId, "'Operand 2'");
+
+ InstructionDesc[OpVectorTimesScalar].operands.push(OperandId, "'Vector'");
+ InstructionDesc[OpVectorTimesScalar].operands.push(OperandId, "'Scalar'");
+
+ InstructionDesc[OpMatrixTimesScalar].capabilities.push_back(CapMatrix);
+ InstructionDesc[OpMatrixTimesScalar].operands.push(OperandId, "'Matrix'");
+ InstructionDesc[OpMatrixTimesScalar].operands.push(OperandId, "'Scalar'");
+
+ InstructionDesc[OpVectorTimesMatrix].capabilities.push_back(CapMatrix);
+ InstructionDesc[OpVectorTimesMatrix].operands.push(OperandId, "'Vector'");
+ InstructionDesc[OpVectorTimesMatrix].operands.push(OperandId, "'Matrix'");
+
+ InstructionDesc[OpMatrixTimesVector].capabilities.push_back(CapMatrix);
+ InstructionDesc[OpMatrixTimesVector].operands.push(OperandId, "'Matrix'");
+ InstructionDesc[OpMatrixTimesVector].operands.push(OperandId, "'Vector'");
+
+ InstructionDesc[OpMatrixTimesMatrix].capabilities.push_back(CapMatrix);
+ InstructionDesc[OpMatrixTimesMatrix].operands.push(OperandId, "'LeftMatrix'");
+ InstructionDesc[OpMatrixTimesMatrix].operands.push(OperandId, "'RightMatrix'");
+
+ InstructionDesc[OpOuterProduct].capabilities.push_back(CapMatrix);
+ InstructionDesc[OpOuterProduct].operands.push(OperandId, "'Vector 1'");
+ InstructionDesc[OpOuterProduct].operands.push(OperandId, "'Vector 2'");
+
+ InstructionDesc[OpDot].operands.push(OperandId, "'Vector 1'");
+ InstructionDesc[OpDot].operands.push(OperandId, "'Vector 2'");
+
+ InstructionDesc[OpShiftRightLogical].operands.push(OperandId, "'Operand 1'");
+ InstructionDesc[OpShiftRightLogical].operands.push(OperandId, "'Operand 2'");
+
+ InstructionDesc[OpShiftRightArithmetic].operands.push(OperandId, "'Operand 1'");
+ InstructionDesc[OpShiftRightArithmetic].operands.push(OperandId, "'Operand 2'");
+
+ InstructionDesc[OpShiftLeftLogical].operands.push(OperandId, "'Operand 1'");
+ InstructionDesc[OpShiftLeftLogical].operands.push(OperandId, "'Operand 2'");
+
+ InstructionDesc[OpLogicalOr].operands.push(OperandId, "'Operand 1'");
+ InstructionDesc[OpLogicalOr].operands.push(OperandId, "'Operand 2'");
+
+ InstructionDesc[OpLogicalXor].operands.push(OperandId, "'Operand 1'");
+ InstructionDesc[OpLogicalXor].operands.push(OperandId, "'Operand 2'");
+
+ InstructionDesc[OpLogicalAnd].operands.push(OperandId, "'Operand 1'");
+ InstructionDesc[OpLogicalAnd].operands.push(OperandId, "'Operand 2'");
+
+ InstructionDesc[OpBitwiseOr].operands.push(OperandId, "'Operand 1'");
+ InstructionDesc[OpBitwiseOr].operands.push(OperandId, "'Operand 2'");
+
+ InstructionDesc[OpBitwiseXor].operands.push(OperandId, "'Operand 1'");
+ InstructionDesc[OpBitwiseXor].operands.push(OperandId, "'Operand 2'");
+
+ InstructionDesc[OpBitwiseAnd].operands.push(OperandId, "'Operand 1'");
+ InstructionDesc[OpBitwiseAnd].operands.push(OperandId, "'Operand 2'");
+
+ InstructionDesc[OpSelect].operands.push(OperandId, "'Condition'");
+ InstructionDesc[OpSelect].operands.push(OperandId, "'Object 1'");
+ InstructionDesc[OpSelect].operands.push(OperandId, "'Object 2'");
+
+ InstructionDesc[OpIEqual].operands.push(OperandId, "'Operand 1'");
+ InstructionDesc[OpIEqual].operands.push(OperandId, "'Operand 2'");
+
+ InstructionDesc[OpFOrdEqual].operands.push(OperandId, "'Operand 1'");
+ InstructionDesc[OpFOrdEqual].operands.push(OperandId, "'Operand 2'");
+
+ InstructionDesc[OpFUnordEqual].operands.push(OperandId, "'Operand 1'");
+ InstructionDesc[OpFUnordEqual].operands.push(OperandId, "'Operand 2'");
+
+ InstructionDesc[OpINotEqual].operands.push(OperandId, "'Operand 1'");
+ InstructionDesc[OpINotEqual].operands.push(OperandId, "'Operand 2'");
+
+ InstructionDesc[OpFOrdNotEqual].operands.push(OperandId, "'Operand 1'");
+ InstructionDesc[OpFOrdNotEqual].operands.push(OperandId, "'Operand 2'");
+
+ InstructionDesc[OpFUnordNotEqual].operands.push(OperandId, "'Operand 1'");
+ InstructionDesc[OpFUnordNotEqual].operands.push(OperandId, "'Operand 2'");
+
+ InstructionDesc[OpULessThan].operands.push(OperandId, "'Operand 1'");
+ InstructionDesc[OpULessThan].operands.push(OperandId, "'Operand 2'");
+
+ InstructionDesc[OpSLessThan].operands.push(OperandId, "'Operand 1'");
+ InstructionDesc[OpSLessThan].operands.push(OperandId, "'Operand 2'");
+
+ InstructionDesc[OpFOrdLessThan].operands.push(OperandId, "'Operand 1'");
+ InstructionDesc[OpFOrdLessThan].operands.push(OperandId, "'Operand 2'");
+
+ InstructionDesc[OpFUnordLessThan].operands.push(OperandId, "'Operand 1'");
+ InstructionDesc[OpFUnordLessThan].operands.push(OperandId, "'Operand 2'");
+
+ InstructionDesc[OpUGreaterThan].operands.push(OperandId, "'Operand 1'");
+ InstructionDesc[OpUGreaterThan].operands.push(OperandId, "'Operand 2'");
+
+ InstructionDesc[OpSGreaterThan].operands.push(OperandId, "'Operand 1'");
+ InstructionDesc[OpSGreaterThan].operands.push(OperandId, "'Operand 2'");
+
+ InstructionDesc[OpFOrdGreaterThan].operands.push(OperandId, "'Operand 1'");
+ InstructionDesc[OpFOrdGreaterThan].operands.push(OperandId, "'Operand 2'");
+
+ InstructionDesc[OpFUnordGreaterThan].operands.push(OperandId, "'Operand 1'");
+ InstructionDesc[OpFUnordGreaterThan].operands.push(OperandId, "'Operand 2'");
+
+ InstructionDesc[OpULessThanEqual].operands.push(OperandId, "'Operand 1'");
+ InstructionDesc[OpULessThanEqual].operands.push(OperandId, "'Operand 2'");
+
+ InstructionDesc[OpSLessThanEqual].operands.push(OperandId, "'Operand 1'");
+ InstructionDesc[OpSLessThanEqual].operands.push(OperandId, "'Operand 2'");
+
+ InstructionDesc[OpFOrdLessThanEqual].operands.push(OperandId, "'Operand 1'");
+ InstructionDesc[OpFOrdLessThanEqual].operands.push(OperandId, "'Operand 2'");
+
+ InstructionDesc[OpFUnordLessThanEqual].operands.push(OperandId, "'Operand 1'");
+ InstructionDesc[OpFUnordLessThanEqual].operands.push(OperandId, "'Operand 2'");
+
+ InstructionDesc[OpUGreaterThanEqual].operands.push(OperandId, "'Operand 1'");
+ InstructionDesc[OpUGreaterThanEqual].operands.push(OperandId, "'Operand 2'");
+
+ InstructionDesc[OpSGreaterThanEqual].operands.push(OperandId, "'Operand 1'");
+ InstructionDesc[OpSGreaterThanEqual].operands.push(OperandId, "'Operand 2'");
+
+ InstructionDesc[OpFOrdGreaterThanEqual].operands.push(OperandId, "'Operand 1'");
+ InstructionDesc[OpFOrdGreaterThanEqual].operands.push(OperandId, "'Operand 2'");
+
+ InstructionDesc[OpFUnordGreaterThanEqual].operands.push(OperandId, "'Operand 1'");
+ InstructionDesc[OpFUnordGreaterThanEqual].operands.push(OperandId, "'Operand 2'");
+
+ InstructionDesc[OpDPdx].capabilities.push_back(CapShader);
+ InstructionDesc[OpDPdx].operands.push(OperandId, "'P'");
+
+ InstructionDesc[OpDPdy].capabilities.push_back(CapShader);
+ InstructionDesc[OpDPdy].operands.push(OperandId, "'P'");
+
+ InstructionDesc[OpFwidth].capabilities.push_back(CapShader);
+ InstructionDesc[OpFwidth].operands.push(OperandId, "'P'");
+
+ InstructionDesc[OpDPdxFine].capabilities.push_back(CapShader);
+ InstructionDesc[OpDPdxFine].operands.push(OperandId, "'P'");
+
+ InstructionDesc[OpDPdyFine].capabilities.push_back(CapShader);
+ InstructionDesc[OpDPdyFine].operands.push(OperandId, "'P'");
+
+ InstructionDesc[OpFwidthFine].capabilities.push_back(CapShader);
+ InstructionDesc[OpFwidthFine].operands.push(OperandId, "'P'");
+
+ InstructionDesc[OpDPdxCoarse].capabilities.push_back(CapShader);
+ InstructionDesc[OpDPdxCoarse].operands.push(OperandId, "'P'");
+
+ InstructionDesc[OpDPdyCoarse].capabilities.push_back(CapShader);
+ InstructionDesc[OpDPdyCoarse].operands.push(OperandId, "'P'");
+
+ InstructionDesc[OpFwidthCoarse].capabilities.push_back(CapShader);
+ InstructionDesc[OpFwidthCoarse].operands.push(OperandId, "'P'");
+
+ InstructionDesc[OpEmitVertex].capabilities.push_back(CapGeom);
+
+ InstructionDesc[OpEndPrimitive].capabilities.push_back(CapGeom);
+
+ InstructionDesc[OpEmitStreamVertex].operands.push(OperandId, "'Stream'");
+ InstructionDesc[OpEmitStreamVertex].capabilities.push_back(CapGeom);
+
+ InstructionDesc[OpEndStreamPrimitive].operands.push(OperandId, "'Stream'");
+ InstructionDesc[OpEndStreamPrimitive].capabilities.push_back(CapGeom);
+
+ InstructionDesc[OpControlBarrier].operands.push(OperandExecutionScope, "'Scope'");
+
+ InstructionDesc[OpMemoryBarrier].operands.push(OperandExecutionScope, "'Scope'");
+ InstructionDesc[OpMemoryBarrier].operands.push(OperandMemorySemantics, "'Semantics'");
+
+ InstructionDesc[OpImagePointer].operands.push(OperandId, "'Image'");
+ InstructionDesc[OpImagePointer].operands.push(OperandId, "'Coordinate'");
+ InstructionDesc[OpImagePointer].operands.push(OperandId, "'Sample'");
+
+ InstructionDesc[OpAtomicInit].operands.push(OperandId, "'Pointer'");
+ InstructionDesc[OpAtomicInit].operands.push(OperandId, "'Value'");
+
+ InstructionDesc[OpAtomicLoad].operands.push(OperandId, "'Pointer'");
+ InstructionDesc[OpAtomicLoad].operands.push(OperandExecutionScope, "'Scope'");
+ InstructionDesc[OpAtomicLoad].operands.push(OperandMemorySemantics, "'Semantics'");
+
+ InstructionDesc[OpAtomicStore].operands.push(OperandId, "'Pointer'");
+ InstructionDesc[OpAtomicStore].operands.push(OperandExecutionScope, "'Scope'");
+ InstructionDesc[OpAtomicStore].operands.push(OperandMemorySemantics, "'Semantics'");
+ InstructionDesc[OpAtomicStore].operands.push(OperandId, "'Value'");
+
+ InstructionDesc[OpAtomicExchange].operands.push(OperandId, "'Pointer'");
+ InstructionDesc[OpAtomicExchange].operands.push(OperandExecutionScope, "'Scope'");
+ InstructionDesc[OpAtomicExchange].operands.push(OperandMemorySemantics, "'Semantics'");
+ InstructionDesc[OpAtomicExchange].operands.push(OperandId, "'Value'");
+
+ InstructionDesc[OpAtomicCompareExchange].operands.push(OperandId, "'Pointer'");
+ InstructionDesc[OpAtomicCompareExchange].operands.push(OperandExecutionScope, "'Scope'");
+ InstructionDesc[OpAtomicCompareExchange].operands.push(OperandMemorySemantics, "'Semantics'");
+ InstructionDesc[OpAtomicCompareExchange].operands.push(OperandId, "'Value'");
+ InstructionDesc[OpAtomicCompareExchange].operands.push(OperandId, "'Comparator'");
+
+ InstructionDesc[OpAtomicCompareExchangeWeak].operands.push(OperandId, "'Pointer'");
+ InstructionDesc[OpAtomicCompareExchangeWeak].operands.push(OperandExecutionScope, "'Scope'");
+ InstructionDesc[OpAtomicCompareExchangeWeak].operands.push(OperandMemorySemantics, "'Semantics'");
+ InstructionDesc[OpAtomicCompareExchangeWeak].operands.push(OperandId, "'Value'");
+ InstructionDesc[OpAtomicCompareExchangeWeak].operands.push(OperandId, "'Comparator'");
+
+ InstructionDesc[OpAtomicIIncrement].operands.push(OperandId, "'Pointer'");
+ InstructionDesc[OpAtomicIIncrement].operands.push(OperandExecutionScope, "'Scope'");
+ InstructionDesc[OpAtomicIIncrement].operands.push(OperandMemorySemantics, "'Semantics'");
+
+ InstructionDesc[OpAtomicIDecrement].operands.push(OperandId, "'Pointer'");
+ InstructionDesc[OpAtomicIDecrement].operands.push(OperandExecutionScope, "'Scope'");
+ InstructionDesc[OpAtomicIDecrement].operands.push(OperandMemorySemantics, "'Semantics'");
+
+ InstructionDesc[OpAtomicIAdd].operands.push(OperandId, "'Pointer'");
+ InstructionDesc[OpAtomicIAdd].operands.push(OperandExecutionScope, "'Scope'");
+ InstructionDesc[OpAtomicIAdd].operands.push(OperandMemorySemantics, "'Semantics'");
+ InstructionDesc[OpAtomicIAdd].operands.push(OperandId, "'Value'");
+
+ InstructionDesc[OpAtomicISub].operands.push(OperandId, "'Pointer'");
+ InstructionDesc[OpAtomicISub].operands.push(OperandExecutionScope, "'Scope'");
+ InstructionDesc[OpAtomicISub].operands.push(OperandMemorySemantics, "'Semantics'");
+ InstructionDesc[OpAtomicISub].operands.push(OperandId, "'Value'");
+
+ InstructionDesc[OpAtomicUMin].operands.push(OperandId, "'Pointer'");
+ InstructionDesc[OpAtomicUMin].operands.push(OperandExecutionScope, "'Scope'");
+ InstructionDesc[OpAtomicUMin].operands.push(OperandMemorySemantics, "'Semantics'");
+ InstructionDesc[OpAtomicUMin].operands.push(OperandId, "'Value'");
+
+ InstructionDesc[OpAtomicUMax].operands.push(OperandId, "'Pointer'");
+ InstructionDesc[OpAtomicUMax].operands.push(OperandExecutionScope, "'Scope'");
+ InstructionDesc[OpAtomicUMax].operands.push(OperandMemorySemantics, "'Semantics'");
+ InstructionDesc[OpAtomicUMax].operands.push(OperandId, "'Value'");
+
+ InstructionDesc[OpAtomicIMin].operands.push(OperandId, "'Pointer'");
+ InstructionDesc[OpAtomicIMin].operands.push(OperandExecutionScope, "'Scope'");
+ InstructionDesc[OpAtomicIMin].operands.push(OperandMemorySemantics, "'Semantics'");
+ InstructionDesc[OpAtomicIMin].operands.push(OperandId, "'Value'");
+
+ InstructionDesc[OpAtomicIMax].operands.push(OperandId, "'Pointer'");
+ InstructionDesc[OpAtomicIMax].operands.push(OperandExecutionScope, "'Scope'");
+ InstructionDesc[OpAtomicIMax].operands.push(OperandMemorySemantics, "'Semantics'");
+ InstructionDesc[OpAtomicIMax].operands.push(OperandId, "'Value'");
+
+ InstructionDesc[OpAtomicAnd].operands.push(OperandId, "'Pointer'");
+ InstructionDesc[OpAtomicAnd].operands.push(OperandExecutionScope, "'Scope'");
+ InstructionDesc[OpAtomicAnd].operands.push(OperandMemorySemantics, "'Semantics'");
+ InstructionDesc[OpAtomicAnd].operands.push(OperandId, "'Value'");
+
+ InstructionDesc[OpAtomicOr].operands.push(OperandId, "'Pointer'");
+ InstructionDesc[OpAtomicOr].operands.push(OperandExecutionScope, "'Scope'");
+ InstructionDesc[OpAtomicOr].operands.push(OperandMemorySemantics, "'Semantics'");
+ InstructionDesc[OpAtomicOr].operands.push(OperandId, "'Value'");
+
+ InstructionDesc[OpAtomicXor].operands.push(OperandId, "'Pointer'");
+ InstructionDesc[OpAtomicXor].operands.push(OperandExecutionScope, "'Scope'");
+ InstructionDesc[OpAtomicXor].operands.push(OperandMemorySemantics, "'Semantics'");
+ InstructionDesc[OpAtomicXor].operands.push(OperandId, "'Value'");
+
+ InstructionDesc[OpLoopMerge].operands.push(OperandId, "'Label'");
+ InstructionDesc[OpLoopMerge].operands.push(OperandLoop, "");
+
+ InstructionDesc[OpSelectionMerge].operands.push(OperandId, "'Label'");
+ InstructionDesc[OpSelectionMerge].operands.push(OperandSelect, "");
+
+ InstructionDesc[OpBranch].operands.push(OperandId, "'Target Label'");
+
+ InstructionDesc[OpBranchConditional].operands.push(OperandId, "'Condition'");
+ InstructionDesc[OpBranchConditional].operands.push(OperandId, "'True Label'");
+ InstructionDesc[OpBranchConditional].operands.push(OperandId, "'False Label'");
+ InstructionDesc[OpBranchConditional].operands.push(OperandVariableLiterals, "'Branch weights'");
+
+ InstructionDesc[OpSwitch].operands.push(OperandId, "'Selector'");
+ InstructionDesc[OpSwitch].operands.push(OperandId, "'Default'");
+ InstructionDesc[OpSwitch].operands.push(OperandVariableLiteralId, "'Target'");
+
+ InstructionDesc[OpKill].capabilities.push_back(CapShader);
+
+ InstructionDesc[OpReturnValue].operands.push(OperandId, "'Value'");
+
+ InstructionDesc[OpUnreachable].capabilities.push_back(CapKernel);
+
+ InstructionDesc[OpLifetimeStart].operands.push(OperandId, "");
+ InstructionDesc[OpLifetimeStart].operands.push(OperandLiteralNumber, "");
+
+ InstructionDesc[OpLifetimeStop].operands.push(OperandId, "");
+ InstructionDesc[OpLifetimeStop].operands.push(OperandLiteralNumber, "");
+
+ InstructionDesc[OpCompileFlag].capabilities.push_back(CapKernel);
+ InstructionDesc[OpCompileFlag].operands.push(OperandLiteralString, "'Flag'");
+
+ InstructionDesc[OpAsyncGroupCopy].capabilities.push_back(CapKernel);
+ InstructionDesc[OpAsyncGroupCopy].operands.push(OperandExecutionScope, "'Scope'");
+ InstructionDesc[OpAsyncGroupCopy].operands.push(OperandId, "'Destination'");
+ InstructionDesc[OpAsyncGroupCopy].operands.push(OperandId, "'Source'");
+ InstructionDesc[OpAsyncGroupCopy].operands.push(OperandId, "'Num Elements'");
+ InstructionDesc[OpAsyncGroupCopy].operands.push(OperandId, "'Stride'");
+ InstructionDesc[OpAsyncGroupCopy].operands.push(OperandId, "'Event'");
+
+ InstructionDesc[OpWaitGroupEvents].capabilities.push_back(CapKernel);
+ InstructionDesc[OpWaitGroupEvents].operands.push(OperandExecutionScope, "'Scope'");
+ InstructionDesc[OpWaitGroupEvents].operands.push(OperandId, "'Num Events'");
+ InstructionDesc[OpWaitGroupEvents].operands.push(OperandId, "'Events List'");
+
+ InstructionDesc[OpGroupAll].capabilities.push_back(CapKernel);
+ InstructionDesc[OpGroupAll].operands.push(OperandExecutionScope, "'Scope'");
+ InstructionDesc[OpGroupAll].operands.push(OperandId, "'Predicate'");
+
+ InstructionDesc[OpGroupAny].capabilities.push_back(CapKernel);
+ InstructionDesc[OpGroupAny].operands.push(OperandExecutionScope, "'Scope'");
+ InstructionDesc[OpGroupAny].operands.push(OperandId, "'Predicate'");
+
+ InstructionDesc[OpGroupBroadcast].capabilities.push_back(CapKernel);
+ InstructionDesc[OpGroupBroadcast].operands.push(OperandExecutionScope, "'Scope'");
+ InstructionDesc[OpGroupBroadcast].operands.push(OperandId, "'Value'");
+ InstructionDesc[OpGroupBroadcast].operands.push(OperandId, "'LocalId'");
+
+ InstructionDesc[OpGroupIAdd].capabilities.push_back(CapKernel);
+ InstructionDesc[OpGroupIAdd].operands.push(OperandExecutionScope, "'Scope'");
+ InstructionDesc[OpGroupIAdd].operands.push(OperandGroupOperation, "'Operation'");
+ InstructionDesc[OpGroupIAdd].operands.push(OperandId, "'X'");
+
+ InstructionDesc[OpGroupFAdd].capabilities.push_back(CapKernel);
+ InstructionDesc[OpGroupFAdd].operands.push(OperandExecutionScope, "'Scope'");
+ InstructionDesc[OpGroupFAdd].operands.push(OperandGroupOperation, "'Operation'");
+ InstructionDesc[OpGroupFAdd].operands.push(OperandId, "'X'");
+
+ InstructionDesc[OpGroupUMin].capabilities.push_back(CapKernel);
+ InstructionDesc[OpGroupUMin].operands.push(OperandExecutionScope, "'Scope'");
+ InstructionDesc[OpGroupUMin].operands.push(OperandGroupOperation, "'Operation'");
+ InstructionDesc[OpGroupUMin].operands.push(OperandId, "'X'");
+
+ InstructionDesc[OpGroupSMin].capabilities.push_back(CapKernel);
+ InstructionDesc[OpGroupSMin].operands.push(OperandExecutionScope, "'Scope'");
+ InstructionDesc[OpGroupSMin].operands.push(OperandGroupOperation, "'Operation'");
+ InstructionDesc[OpGroupSMin].operands.push(OperandId, "X");
+
+ InstructionDesc[OpGroupFMin].capabilities.push_back(CapKernel);
+ InstructionDesc[OpGroupFMin].operands.push(OperandExecutionScope, "'Scope'");
+ InstructionDesc[OpGroupFMin].operands.push(OperandGroupOperation, "'Operation'");
+ InstructionDesc[OpGroupFMin].operands.push(OperandId, "X");
+
+ InstructionDesc[OpGroupUMax].capabilities.push_back(CapKernel);
+ InstructionDesc[OpGroupUMax].operands.push(OperandExecutionScope, "'Scope'");
+ InstructionDesc[OpGroupUMax].operands.push(OperandGroupOperation, "'Operation'");
+ InstructionDesc[OpGroupUMax].operands.push(OperandId, "X");
+
+ InstructionDesc[OpGroupSMax].capabilities.push_back(CapKernel);
+ InstructionDesc[OpGroupSMax].operands.push(OperandExecutionScope, "'Scope'");
+ InstructionDesc[OpGroupSMax].operands.push(OperandGroupOperation, "'Operation'");
+ InstructionDesc[OpGroupSMax].operands.push(OperandId, "X");
+
+ InstructionDesc[OpGroupFMax].capabilities.push_back(CapKernel);
+ InstructionDesc[OpGroupFMax].operands.push(OperandExecutionScope, "'Scope'");
+ InstructionDesc[OpGroupFMax].operands.push(OperandGroupOperation, "'Operation'");
+ InstructionDesc[OpGroupFMax].operands.push(OperandId, "X");
+
+ InstructionDesc[OpReadPipe].capabilities.push_back(CapKernel);
+ InstructionDesc[OpReadPipe].operands.push(OperandId, "'p'");
+ InstructionDesc[OpReadPipe].operands.push(OperandId, "'ptr'");
+
+ InstructionDesc[OpWritePipe].capabilities.push_back(CapKernel);
+ InstructionDesc[OpWritePipe].operands.push(OperandId, "'p'");
+ InstructionDesc[OpWritePipe].operands.push(OperandId, "'ptr'");
+
+ InstructionDesc[OpReservedReadPipe].capabilities.push_back(CapKernel);
+ InstructionDesc[OpReservedReadPipe].operands.push(OperandId, "'p'");
+ InstructionDesc[OpReservedReadPipe].operands.push(OperandId, "'reserve_id'");
+ InstructionDesc[OpReservedReadPipe].operands.push(OperandId, "'index'");
+ InstructionDesc[OpReservedReadPipe].operands.push(OperandId, "'ptr'");
+
+ InstructionDesc[OpReservedWritePipe].capabilities.push_back(CapKernel);
+ InstructionDesc[OpReservedWritePipe].operands.push(OperandId, "'p'");
+ InstructionDesc[OpReservedWritePipe].operands.push(OperandId, "'reserve_id'");
+ InstructionDesc[OpReservedWritePipe].operands.push(OperandId, "'index'");
+ InstructionDesc[OpReservedWritePipe].operands.push(OperandId, "'ptr'");
+
+ InstructionDesc[OpReserveReadPipePackets].capabilities.push_back(CapKernel);
+ InstructionDesc[OpReserveReadPipePackets].operands.push(OperandId, "'p'");
+ InstructionDesc[OpReserveReadPipePackets].operands.push(OperandId, "'num_packets'");
+
+ InstructionDesc[OpReserveWritePipePackets].capabilities.push_back(CapKernel);
+ InstructionDesc[OpReserveWritePipePackets].operands.push(OperandId, "'p'");
+ InstructionDesc[OpReserveWritePipePackets].operands.push(OperandId, "'num_packets'");
+
+ InstructionDesc[OpCommitReadPipe].capabilities.push_back(CapKernel);
+ InstructionDesc[OpCommitReadPipe].operands.push(OperandId, "'p'");
+ InstructionDesc[OpCommitReadPipe].operands.push(OperandId, "'reserve_id'");
+
+ InstructionDesc[OpCommitWritePipe].capabilities.push_back(CapKernel);
+ InstructionDesc[OpCommitWritePipe].operands.push(OperandId, "'p'");
+ InstructionDesc[OpCommitWritePipe].operands.push(OperandId, "'reserve_id'");
+
+ InstructionDesc[OpIsValidReserveId].capabilities.push_back(CapKernel);
+ InstructionDesc[OpIsValidReserveId].operands.push(OperandId, "'reserve_id'");
+
+ InstructionDesc[OpGetNumPipePackets].capabilities.push_back(CapKernel);
+ InstructionDesc[OpGetNumPipePackets].operands.push(OperandId, "'p'");
+
+ InstructionDesc[OpGetMaxPipePackets].capabilities.push_back(CapKernel);
+ InstructionDesc[OpGetMaxPipePackets].operands.push(OperandId, "'p'");
+
+ InstructionDesc[OpGroupReserveReadPipePackets].capabilities.push_back(CapKernel);
+ InstructionDesc[OpGroupReserveReadPipePackets].operands.push(OperandExecutionScope, "'Scope'");
+ InstructionDesc[OpGroupReserveReadPipePackets].operands.push(OperandId, "'p'");
+ InstructionDesc[OpGroupReserveReadPipePackets].operands.push(OperandId, "'num_packets'");
+
+ InstructionDesc[OpGroupReserveWritePipePackets].capabilities.push_back(CapKernel);
+ InstructionDesc[OpGroupReserveWritePipePackets].operands.push(OperandExecutionScope, "'Scope'");
+ InstructionDesc[OpGroupReserveWritePipePackets].operands.push(OperandId, "'p'");
+ InstructionDesc[OpGroupReserveWritePipePackets].operands.push(OperandId, "'num_packets'");
+
+ InstructionDesc[OpGroupCommitReadPipe].capabilities.push_back(CapKernel);
+ InstructionDesc[OpGroupCommitReadPipe].operands.push(OperandExecutionScope, "'Scope'");
+ InstructionDesc[OpGroupCommitReadPipe].operands.push(OperandId, "'p'");
+ InstructionDesc[OpGroupCommitReadPipe].operands.push(OperandId, "'reserve_id'");
+
+ InstructionDesc[OpGroupCommitWritePipe].capabilities.push_back(CapKernel);
+ InstructionDesc[OpGroupCommitWritePipe].operands.push(OperandExecutionScope, "'Scope'");
+ InstructionDesc[OpGroupCommitWritePipe].operands.push(OperandId, "'p'");
+ InstructionDesc[OpGroupCommitWritePipe].operands.push(OperandId, "'reserve_id'");
+
+ InstructionDesc[OpBuildNDRange].capabilities.push_back(CapKernel);
+ InstructionDesc[OpBuildNDRange].operands.push(OperandId, "'GlobalWorkSize'");
+ InstructionDesc[OpBuildNDRange].operands.push(OperandId, "'LocalWorkSize'");
+ InstructionDesc[OpBuildNDRange].operands.push(OperandId, "'GlobalWorkOffset'");
+
+ InstructionDesc[OpGetDefaultQueue].capabilities.push_back(CapKernel);
+
+ InstructionDesc[OpCaptureEventProfilingInfo].capabilities.push_back(CapKernel);
+
+ InstructionDesc[OpCaptureEventProfilingInfo].operands.push(OperandId, "'event'");
+ InstructionDesc[OpCaptureEventProfilingInfo].operands.push(OperandKernelProfilingInfo, "'info'");
+ InstructionDesc[OpCaptureEventProfilingInfo].operands.push(OperandId, "'value'");
+
+ InstructionDesc[OpSetUserEventStatus].capabilities.push_back(CapKernel);
+
+ InstructionDesc[OpSetUserEventStatus].operands.push(OperandId, "'event'");
+ InstructionDesc[OpSetUserEventStatus].operands.push(OperandId, "'status'");
+
+ InstructionDesc[OpIsValidEvent].capabilities.push_back(CapKernel);
+ InstructionDesc[OpIsValidEvent].operands.push(OperandId, "'event'");
+
+ InstructionDesc[OpCreateUserEvent].capabilities.push_back(CapKernel);
+
+ InstructionDesc[OpRetainEvent].capabilities.push_back(CapKernel);
+ InstructionDesc[OpRetainEvent].operands.push(OperandId, "'event'");
+
+ InstructionDesc[OpReleaseEvent].capabilities.push_back(CapKernel);
+ InstructionDesc[OpReleaseEvent].operands.push(OperandId, "'event'");
+
+ InstructionDesc[OpGetKernelWorkGroupSize].capabilities.push_back(CapKernel);
+ InstructionDesc[OpGetKernelWorkGroupSize].operands.push(OperandId, "'Invoke'");
+
+ InstructionDesc[OpGetKernelPreferredWorkGroupSizeMultiple].capabilities.push_back(CapKernel);
+ InstructionDesc[OpGetKernelPreferredWorkGroupSizeMultiple].operands.push(OperandId, "'Invoke'");
+
+ InstructionDesc[OpGetKernelNDrangeSubGroupCount].capabilities.push_back(CapKernel);
+ InstructionDesc[OpGetKernelNDrangeSubGroupCount].operands.push(OperandId, "'ND Range'");
+ InstructionDesc[OpGetKernelNDrangeSubGroupCount].operands.push(OperandId, "'Invoke'");
+
+ InstructionDesc[OpGetKernelNDrangeMaxSubGroupSize].capabilities.push_back(CapKernel);
+ InstructionDesc[OpGetKernelNDrangeMaxSubGroupSize].operands.push(OperandId, "'ND Range'");
+ InstructionDesc[OpGetKernelNDrangeMaxSubGroupSize].operands.push(OperandId, "'Invoke'");
+
+ InstructionDesc[OpEnqueueKernel].capabilities.push_back(CapKernel);
+ InstructionDesc[OpEnqueueKernel].operands.push(OperandId, "'q'");
+ InstructionDesc[OpEnqueueKernel].operands.push(OperandKernelEnqueueFlags, "'flags'");
+ InstructionDesc[OpEnqueueKernel].operands.push(OperandId, "'ND Range'");
+ InstructionDesc[OpEnqueueKernel].operands.push(OperandId, "'Num Events'");
+ InstructionDesc[OpEnqueueKernel].operands.push(OperandId, "'Wait Events'");
+ InstructionDesc[OpEnqueueKernel].operands.push(OperandId, "'Ret Event'");
+ InstructionDesc[OpEnqueueKernel].operands.push(OperandId, "'Invoke'");
+ InstructionDesc[OpEnqueueKernel].operands.push(OperandId, "'Param'");
+ InstructionDesc[OpEnqueueKernel].operands.push(OperandId, "'Param Size'");
+ InstructionDesc[OpEnqueueKernel].operands.push(OperandId, "'Param Align'");
+ InstructionDesc[OpEnqueueKernel].operands.push(OperandVariableIds, "'Local Size'");
+
+ InstructionDesc[OpEnqueueMarker].capabilities.push_back(CapKernel);
+ InstructionDesc[OpEnqueueMarker].operands.push(OperandId, "'q'");
+ InstructionDesc[OpEnqueueMarker].operands.push(OperandId, "'Num Events'");
+ InstructionDesc[OpEnqueueMarker].operands.push(OperandId, "'Wait Events'");
+ InstructionDesc[OpEnqueueMarker].operands.push(OperandId, "'Ret Event'");
+}
+
+}; // end spv namespace
-//\r
-//Copyright (C) 2014 LunarG, Inc.\r
-//\r
-//All rights reserved.\r
-//\r
-//Redistribution and use in source and binary forms, with or without\r
-//modification, are permitted provided that the following conditions\r
-//are met:\r
-//\r
-// Redistributions of source code must retain the above copyright\r
-// notice, this list of conditions and the following disclaimer.\r
-//\r
-// Redistributions in binary form must reproduce the above\r
-// copyright notice, this list of conditions and the following\r
-// disclaimer in the documentation and/or other materials provided\r
-// with the distribution.\r
-//\r
-// Neither the name of 3Dlabs Inc. Ltd. nor the names of its\r
-// contributors may be used to endorse or promote products derived\r
-// from this software without specific prior written permission.\r
-//\r
-//THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\r
-//"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\r
-//LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS\r
-//FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE\r
-//COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,\r
-//INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,\r
-//BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\r
-//LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER\r
-//CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\r
-//LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN\r
-//ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE\r
-//POSSIBILITY OF SUCH DAMAGE.\r
-\r
-//\r
-// Author: John Kessenich, LunarG\r
-//\r
-\r
-//\r
-// Parameterize the SPIR-V enumerants.\r
-//\r
-\r
-#include "spirv.h"\r
-\r
-#include <vector>\r
-\r
-namespace spv {\r
-\r
-// Fill in all the parameters\r
-void Parameterize();\r
-\r
-// Return the English names of all the enums.\r
-const char* SourceString(int);\r
-const char* AddressingString(int);\r
-const char* MemoryString(int);\r
-const char* ExecutionModelString(int);\r
-const char* ExecutionModeString(int);\r
-const char* StorageClassString(int);\r
-const char* DecorationString(int);\r
-const char* BuiltInString(int);\r
-const char* DimensionString(int);\r
-const char* SelectControlString(int);\r
-const char* LoopControlString(int);\r
-const char* FunctionControlString(int);\r
-const char* SamplerAddressingModeString(int);\r
-const char* SamplerFilterModeString(int);\r
-const char* FPFastMathString(int);\r
-const char* FPRoundingModeString(int);\r
-const char* LinkageTypeString(int);\r
-const char* FuncParamAttrString(int);\r
-const char* AccessQualifierString(int);\r
-const char* MemorySemanticsString(int);\r
-const char* MemoryAccessString(int);\r
-const char* ExecutionScopeString(int);\r
-const char* GroupOperationString(int);\r
-const char* KernelEnqueueFlagsString(int);\r
-const char* KernelProfilingInfoString(int);\r
-const char* OpcodeString(int);\r
-\r
-// For grouping opcodes into subsections\r
-enum OpcodeClass {\r
- OpClassMisc, // default, until opcode is classified\r
- OpClassDebug,\r
- OpClassAnnotate,\r
- OpClassExtension,\r
- OpClassMode,\r
- OpClassType,\r
- OpClassConstant,\r
- OpClassMemory,\r
- OpClassFunction,\r
- OpClassTexture,\r
- OpClassConvert,\r
- OpClassComposite,\r
- OpClassArithmetic,\r
- OpClassRelationalLogical,\r
- OpClassDerivative,\r
- OpClassFlowControl,\r
- OpClassAtomic,\r
- OpClassPrimitive,\r
- OpClassBarrier,\r
- OpClassGroup,\r
- OpClassDeviceSideEnqueue,\r
- OpClassPipe,\r
-\r
- OpClassCount\r
-};\r
-\r
-// For parameterizing operands.\r
-enum OperandClass {\r
- OperandNone,\r
- OperandId,\r
- OperandOptionalId,\r
- OperandVariableIds,\r
- OperandVariableLiterals,\r
- OperandVariableLiteralId,\r
- OperandLiteralNumber,\r
- OperandLiteralString,\r
- OperandSource,\r
- OperandExecutionModel,\r
- OperandAddressing,\r
- OperandMemory,\r
- OperandExecutionMode,\r
- OperandStorage,\r
- OperandDimensionality,\r
- OperandSamplerAddressingMode,\r
- OperandSamplerFilterMode,\r
- OperandFPFastMath,\r
- OperandFPRoundingMode,\r
- OperandLinkageType,\r
- OperandAccessQualifier,\r
- OperandFuncParamAttr,\r
- OperandDecoration,\r
- OperandBuiltIn,\r
- OperandSelect,\r
- OperandLoop,\r
- OperandFunction,\r
- OperandMemorySemantics,\r
- OperandMemoryAccess,\r
- OperandExecutionScope,\r
- OperandGroupOperation,\r
- OperandKernelEnqueueFlags,\r
- OperandKernelProfilingInfo,\r
-\r
- OperandOpcode,\r
-\r
- OperandCount\r
-};\r
-\r
-// Set of capabilities. Generally, something is assumed to be in core,\r
-// if nothing else is said. So, these are used to identify when something\r
-// requires a specific capability to be declared.\r
-enum Capability {\r
- CapMatrix,\r
- CapShader,\r
- CapGeom,\r
- CapTess,\r
- CapAddr,\r
- CapLink,\r
- CapKernel\r
-};\r
-\r
-// Any specific enum can have a set of capabilities that allow it:\r
-typedef std::vector<Capability> EnumCaps;\r
-\r
-// Parameterize a set of operands with their OperandClass(es) and descriptions.\r
-class OperandParameters {\r
-public:\r
- OperandParameters() { }\r
- void push(OperandClass oc, const char* d)\r
- {\r
- opClass.push_back(oc);\r
- desc.push_back(d);\r
- }\r
- OperandClass getClass(int op) const { return opClass[op]; }\r
- const char* getDesc(int op) const { return desc[op]; }\r
- int getNum() const { return (int)opClass.size(); }\r
-\r
-protected:\r
- std::vector<OperandClass> opClass;\r
- std::vector<const char*> desc;\r
-};\r
-\r
-// Parameterize an enumerant\r
-class EnumParameters {\r
-public:\r
- EnumParameters() : desc(0) { }\r
- EnumCaps caps;\r
- const char* desc;\r
-};\r
-\r
-// Parameterize a set of enumerants that form an enum\r
-class EnumDefinition : public EnumParameters {\r
-public:\r
- EnumDefinition() : \r
- ceiling(0), bitmask(false), getName(0), enumParams(0), operandParams(0) { }\r
- void set(int ceil, const char* (*name)(int), EnumParameters* ep, bool mask = false)\r
- {\r
- ceiling = ceil;\r
- getName = name;\r
- bitmask = mask;\r
- enumParams = ep;\r
- }\r
- void setOperands(OperandParameters* op) { operandParams = op; }\r
- int ceiling; // ceiling of enumerants\r
- bool bitmask; // true if these enumerants combine into a bitmask\r
- const char* (*getName)(int); // a function that returns the name for each enumerant value (or shift)\r
- EnumParameters* enumParams; // parameters for each individual enumerant\r
- OperandParameters* operandParams; // sets of operands\r
-};\r
-\r
-// Parameterize an instruction's logical format, including its known set of operands,\r
-// per OperandParameters above.\r
-class InstructionParameters {\r
-public:\r
- InstructionParameters() :\r
- typePresent(true), // most normal, only exceptions have to be spelled out\r
- resultPresent(true), // most normal, only exceptions have to be spelled out\r
- opDesc(0),\r
- opClass(OpClassMisc)\r
- { }\r
-\r
- void setResultAndType(bool r, bool t)\r
- {\r
- resultPresent = r;\r
- typePresent = t;\r
- }\r
-\r
- bool hasResult() const { return resultPresent != 0; }\r
- bool hasType() const { return typePresent != 0; }\r
-\r
- const char* opDesc;\r
- EnumCaps capabilities;\r
- OpcodeClass opClass;\r
- OperandParameters operands;\r
-\r
-protected:\r
- int typePresent : 1;\r
- int resultPresent : 1;\r
-};\r
-\r
-const int OpcodeCeiling = 267;\r
-\r
-// The set of objects that hold all the instruction/operand\r
-// parameterization information.\r
-extern InstructionParameters InstructionDesc[];\r
-\r
-// These hold definitions of the enumerants used for operands\r
-extern EnumDefinition OperandClassParams[];\r
-\r
-const char* GetOperandDesc(OperandClass operand);\r
-void PrintImmediateRow(int imm, const char* name, const EnumParameters* enumParams, bool caps, bool hex = false);\r
-const char* AccessQualifierString(int attr);\r
-\r
-void PrintOperands(const OperandParameters& operands, int reservedOperands);\r
-\r
-}; // end namespace spv\r
+//
+//Copyright (C) 2014 LunarG, Inc.
+//
+//All rights reserved.
+//
+//Redistribution and use in source and binary forms, with or without
+//modification, are permitted provided that the following conditions
+//are met:
+//
+// Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//
+// Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following
+// disclaimer in the documentation and/or other materials provided
+// with the distribution.
+//
+// Neither the name of 3Dlabs Inc. Ltd. nor the names of its
+// contributors may be used to endorse or promote products derived
+// from this software without specific prior written permission.
+//
+//THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+//"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+//LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+//FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+//COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+//INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+//BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+//LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+//CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+//LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+//ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+//POSSIBILITY OF SUCH DAMAGE.
+
+//
+// Author: John Kessenich, LunarG
+//
+
+//
+// Parameterize the SPIR-V enumerants.
+//
+
+#include "spirv.h"
+
+#include <vector>
+
+namespace spv {
+
+// Fill in all the parameters
+void Parameterize();
+
+// Return the English names of all the enums.
+const char* SourceString(int);
+const char* AddressingString(int);
+const char* MemoryString(int);
+const char* ExecutionModelString(int);
+const char* ExecutionModeString(int);
+const char* StorageClassString(int);
+const char* DecorationString(int);
+const char* BuiltInString(int);
+const char* DimensionString(int);
+const char* SelectControlString(int);
+const char* LoopControlString(int);
+const char* FunctionControlString(int);
+const char* SamplerAddressingModeString(int);
+const char* SamplerFilterModeString(int);
+const char* FPFastMathString(int);
+const char* FPRoundingModeString(int);
+const char* LinkageTypeString(int);
+const char* FuncParamAttrString(int);
+const char* AccessQualifierString(int);
+const char* MemorySemanticsString(int);
+const char* MemoryAccessString(int);
+const char* ExecutionScopeString(int);
+const char* GroupOperationString(int);
+const char* KernelEnqueueFlagsString(int);
+const char* KernelProfilingInfoString(int);
+const char* OpcodeString(int);
+
+// For grouping opcodes into subsections
+enum OpcodeClass {
+ OpClassMisc, // default, until opcode is classified
+ OpClassDebug,
+ OpClassAnnotate,
+ OpClassExtension,
+ OpClassMode,
+ OpClassType,
+ OpClassConstant,
+ OpClassMemory,
+ OpClassFunction,
+ OpClassTexture,
+ OpClassConvert,
+ OpClassComposite,
+ OpClassArithmetic,
+ OpClassRelationalLogical,
+ OpClassDerivative,
+ OpClassFlowControl,
+ OpClassAtomic,
+ OpClassPrimitive,
+ OpClassBarrier,
+ OpClassGroup,
+ OpClassDeviceSideEnqueue,
+ OpClassPipe,
+
+ OpClassCount
+};
+
+// For parameterizing operands.
+enum OperandClass {
+ OperandNone,
+ OperandId,
+ OperandOptionalId,
+ OperandVariableIds,
+ OperandVariableLiterals,
+ OperandVariableLiteralId,
+ OperandLiteralNumber,
+ OperandLiteralString,
+ OperandSource,
+ OperandExecutionModel,
+ OperandAddressing,
+ OperandMemory,
+ OperandExecutionMode,
+ OperandStorage,
+ OperandDimensionality,
+ OperandSamplerAddressingMode,
+ OperandSamplerFilterMode,
+ OperandFPFastMath,
+ OperandFPRoundingMode,
+ OperandLinkageType,
+ OperandAccessQualifier,
+ OperandFuncParamAttr,
+ OperandDecoration,
+ OperandBuiltIn,
+ OperandSelect,
+ OperandLoop,
+ OperandFunction,
+ OperandMemorySemantics,
+ OperandMemoryAccess,
+ OperandExecutionScope,
+ OperandGroupOperation,
+ OperandKernelEnqueueFlags,
+ OperandKernelProfilingInfo,
+
+ OperandOpcode,
+
+ OperandCount
+};
+
+// Set of capabilities. Generally, something is assumed to be in core,
+// if nothing else is said. So, these are used to identify when something
+// requires a specific capability to be declared.
+enum Capability {
+ CapMatrix,
+ CapShader,
+ CapGeom,
+ CapTess,
+ CapAddr,
+ CapLink,
+ CapKernel
+};
+
+// Any specific enum can have a set of capabilities that allow it:
+typedef std::vector<Capability> EnumCaps;
+
+// Parameterize a set of operands with their OperandClass(es) and descriptions.
+class OperandParameters {
+public:
+ OperandParameters() { }
+ void push(OperandClass oc, const char* d)
+ {
+ opClass.push_back(oc);
+ desc.push_back(d);
+ }
+ OperandClass getClass(int op) const { return opClass[op]; }
+ const char* getDesc(int op) const { return desc[op]; }
+ int getNum() const { return (int)opClass.size(); }
+
+protected:
+ std::vector<OperandClass> opClass;
+ std::vector<const char*> desc;
+};
+
+// Parameterize an enumerant
+class EnumParameters {
+public:
+ EnumParameters() : desc(0) { }
+ EnumCaps caps;
+ const char* desc;
+};
+
+// Parameterize a set of enumerants that form an enum
+class EnumDefinition : public EnumParameters {
+public:
+ EnumDefinition() :
+ ceiling(0), bitmask(false), getName(0), enumParams(0), operandParams(0) { }
+ void set(int ceil, const char* (*name)(int), EnumParameters* ep, bool mask = false)
+ {
+ ceiling = ceil;
+ getName = name;
+ bitmask = mask;
+ enumParams = ep;
+ }
+ void setOperands(OperandParameters* op) { operandParams = op; }
+ int ceiling; // ceiling of enumerants
+ bool bitmask; // true if these enumerants combine into a bitmask
+ const char* (*getName)(int); // a function that returns the name for each enumerant value (or shift)
+ EnumParameters* enumParams; // parameters for each individual enumerant
+ OperandParameters* operandParams; // sets of operands
+};
+
+// Parameterize an instruction's logical format, including its known set of operands,
+// per OperandParameters above.
+class InstructionParameters {
+public:
+ InstructionParameters() :
+ typePresent(true), // most normal, only exceptions have to be spelled out
+ resultPresent(true), // most normal, only exceptions have to be spelled out
+ opDesc(0),
+ opClass(OpClassMisc)
+ { }
+
+ void setResultAndType(bool r, bool t)
+ {
+ resultPresent = r;
+ typePresent = t;
+ }
+
+ bool hasResult() const { return resultPresent != 0; }
+ bool hasType() const { return typePresent != 0; }
+
+ const char* opDesc;
+ EnumCaps capabilities;
+ OpcodeClass opClass;
+ OperandParameters operands;
+
+protected:
+ int typePresent : 1;
+ int resultPresent : 1;
+};
+
+const int OpcodeCeiling = 267;
+
+// The set of objects that hold all the instruction/operand
+// parameterization information.
+extern InstructionParameters InstructionDesc[];
+
+// These hold definitions of the enumerants used for operands
+extern EnumDefinition OperandClassParams[];
+
+const char* GetOperandDesc(OperandClass operand);
+void PrintImmediateRow(int imm, const char* name, const EnumParameters* enumParams, bool caps, bool hex = false);
+const char* AccessQualifierString(int attr);
+
+void PrintOperands(const OperandParameters& operands, int reservedOperands);
+
+}; // end namespace spv
-/*\r
-** Copyright (c) 2015 The Khronos Group Inc.\r
-**\r
-** Permission is hereby granted, free of charge, to any person obtaining a copy\r
-** of this software and/or associated documentation files (the "Materials"),\r
-** to deal in the Materials without restriction, including without limitation\r
-** the rights to use, copy, modify, merge, publish, distribute, sublicense,\r
-** and/or sell copies of the Materials, and to permit persons to whom the\r
-** Materials are furnished to do so, subject to the following conditions:\r
-**\r
-** The above copyright notice and this permission notice shall be included in\r
-** all copies or substantial portions of the Materials.\r
-**\r
-** MODIFICATIONS TO THIS FILE MAY MEAN IT NO LONGER ACCURATELY REFLECTS KHRONOS\r
-** STANDARDS. THE UNMODIFIED, NORMATIVE VERSIONS OF KHRONOS SPECIFICATIONS AND\r
-** HEADER INFORMATION ARE LOCATED AT https://www.khronos.org/registry/ \r
-**\r
-** THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS\r
-** OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\r
-** FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL\r
-** THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\r
-** LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\r
-** FROM,OUT OF OR IN CONNECTION WITH THE MATERIALS OR THE USE OR OTHER DEALINGS\r
-** IN THE MATERIALS.\r
-*/\r
-\r
-/*\r
-** This header is automatically generated by the same tool that creates\r
-** the Binary Section of the SPIR-V specification.\r
-*/\r
-\r
-/*\r
-** Specification revision 30.\r
-** Enumeration tokens for SPIR-V, in three styles: C, C++, generic.\r
-** - C++ will have the tokens in the "spv" name space, with no prefix.\r
-** - C will have tokens with as "Spv" prefix.\r
-**\r
-** Some tokens act like mask values, which can be OR'd together,\r
-** while others are mutually exclusive. The mask-like ones have\r
-** "Mask" in their name, and a parallel enum that has the shift\r
-** amount (1 << x) for each corresponding enumerant.\r
-*/\r
-\r
-#ifndef spirv_H\r
-#define spirv_H\r
-\r
-#ifdef __cplusplus\r
-\r
-namespace spv {\r
-\r
-const int MagicNumber = 0x07230203;\r
-const int Version = 99;\r
-\r
-typedef unsigned int Id;\r
-\r
-const unsigned int OpCodeMask = 0xFFFF;\r
-const unsigned int WordCountShift = 16;\r
-\r
-enum SourceLanguage {\r
- SourceLanguageUnknown = 0,\r
- SourceLanguageESSL = 1,\r
- SourceLanguageGLSL = 2,\r
- SourceLanguageOpenCL = 3,\r
-};\r
-\r
-enum ExecutionModel {\r
- ExecutionModelVertex = 0,\r
- ExecutionModelTessellationControl = 1,\r
- ExecutionModelTessellationEvaluation = 2,\r
- ExecutionModelGeometry = 3,\r
- ExecutionModelFragment = 4,\r
- ExecutionModelGLCompute = 5,\r
- ExecutionModelKernel = 6,\r
-};\r
-\r
-enum AddressingModel {\r
- AddressingModelLogical = 0,\r
- AddressingModelPhysical32 = 1,\r
- AddressingModelPhysical64 = 2,\r
-};\r
-\r
-enum MemoryModel {\r
- MemoryModelSimple = 0,\r
- MemoryModelGLSL450 = 1,\r
- MemoryModelOpenCL12 = 2,\r
- MemoryModelOpenCL20 = 3,\r
- MemoryModelOpenCL21 = 4,\r
-};\r
-\r
-enum ExecutionMode {\r
- ExecutionModeInvocations = 0,\r
- ExecutionModeSpacingEqual = 1,\r
- ExecutionModeSpacingFractionalEven = 2,\r
- ExecutionModeSpacingFractionalOdd = 3,\r
- ExecutionModeVertexOrderCw = 4,\r
- ExecutionModeVertexOrderCcw = 5,\r
- ExecutionModePixelCenterInteger = 6,\r
- ExecutionModeOriginUpperLeft = 7,\r
- ExecutionModeEarlyFragmentTests = 8,\r
- ExecutionModePointMode = 9,\r
- ExecutionModeXfb = 10,\r
- ExecutionModeDepthReplacing = 11,\r
- ExecutionModeDepthAny = 12,\r
- ExecutionModeDepthGreater = 13,\r
- ExecutionModeDepthLess = 14,\r
- ExecutionModeDepthUnchanged = 15,\r
- ExecutionModeLocalSize = 16,\r
- ExecutionModeLocalSizeHint = 17,\r
- ExecutionModeInputPoints = 18,\r
- ExecutionModeInputLines = 19,\r
- ExecutionModeInputLinesAdjacency = 20,\r
- ExecutionModeInputTriangles = 21,\r
- ExecutionModeInputTrianglesAdjacency = 22,\r
- ExecutionModeInputQuads = 23,\r
- ExecutionModeInputIsolines = 24,\r
- ExecutionModeOutputVertices = 25,\r
- ExecutionModeOutputPoints = 26,\r
- ExecutionModeOutputLineStrip = 27,\r
- ExecutionModeOutputTriangleStrip = 28,\r
- ExecutionModeVecTypeHint = 29,\r
- ExecutionModeContractionOff = 30,\r
-};\r
-\r
-enum StorageClass {\r
- StorageClassUniformConstant = 0,\r
- StorageClassInput = 1,\r
- StorageClassUniform = 2,\r
- StorageClassOutput = 3,\r
- StorageClassWorkgroupLocal = 4,\r
- StorageClassWorkgroupGlobal = 5,\r
- StorageClassPrivateGlobal = 6,\r
- StorageClassFunction = 7,\r
- StorageClassGeneric = 8,\r
- StorageClassPrivate = 9,\r
- StorageClassAtomicCounter = 10,\r
-};\r
-\r
-enum Dim {\r
- Dim1D = 0,\r
- Dim2D = 1,\r
- Dim3D = 2,\r
- DimCube = 3,\r
- DimRect = 4,\r
- DimBuffer = 5,\r
-};\r
-\r
-enum SamplerAddressingMode {\r
- SamplerAddressingModeNone = 0,\r
- SamplerAddressingModeClampToEdge = 1,\r
- SamplerAddressingModeClamp = 2,\r
- SamplerAddressingModeRepeat = 3,\r
- SamplerAddressingModeRepeatMirrored = 4,\r
-};\r
-\r
-enum SamplerFilterMode {\r
- SamplerFilterModeNearest = 0,\r
- SamplerFilterModeLinear = 1,\r
-};\r
-\r
-enum FPFastMathModeShift {\r
- FPFastMathModeNotNaNShift = 0,\r
- FPFastMathModeNotInfShift = 1,\r
- FPFastMathModeNSZShift = 2,\r
- FPFastMathModeAllowRecipShift = 3,\r
- FPFastMathModeFastShift = 4,\r
-};\r
-\r
-enum FPFastMathModeMask {\r
- FPFastMathModeMaskNone = 0,\r
- FPFastMathModeNotNaNMask = 0x00000001,\r
- FPFastMathModeNotInfMask = 0x00000002,\r
- FPFastMathModeNSZMask = 0x00000004,\r
- FPFastMathModeAllowRecipMask = 0x00000008,\r
- FPFastMathModeFastMask = 0x00000010,\r
-};\r
-\r
-enum FPRoundingMode {\r
- FPRoundingModeRTE = 0,\r
- FPRoundingModeRTZ = 1,\r
- FPRoundingModeRTP = 2,\r
- FPRoundingModeRTN = 3,\r
-};\r
-\r
-enum LinkageType {\r
- LinkageTypeExport = 0,\r
- LinkageTypeImport = 1,\r
-};\r
-\r
-enum AccessQualifier {\r
- AccessQualifierReadOnly = 0,\r
- AccessQualifierWriteOnly = 1,\r
- AccessQualifierReadWrite = 2,\r
-};\r
-\r
-enum FunctionParameterAttribute {\r
- FunctionParameterAttributeZext = 0,\r
- FunctionParameterAttributeSext = 1,\r
- FunctionParameterAttributeByVal = 2,\r
- FunctionParameterAttributeSret = 3,\r
- FunctionParameterAttributeNoAlias = 4,\r
- FunctionParameterAttributeNoCapture = 5,\r
- FunctionParameterAttributeSVM = 6,\r
- FunctionParameterAttributeNoWrite = 7,\r
- FunctionParameterAttributeNoReadWrite = 8,\r
-};\r
-\r
-enum Decoration {\r
- DecorationPrecisionLow = 0,\r
- DecorationPrecisionMedium = 1,\r
- DecorationPrecisionHigh = 2,\r
- DecorationBlock = 3,\r
- DecorationBufferBlock = 4,\r
- DecorationRowMajor = 5,\r
- DecorationColMajor = 6,\r
- DecorationGLSLShared = 7,\r
- DecorationGLSLStd140 = 8,\r
- DecorationGLSLStd430 = 9,\r
- DecorationGLSLPacked = 10,\r
- DecorationSmooth = 11,\r
- DecorationNoperspective = 12,\r
- DecorationFlat = 13,\r
- DecorationPatch = 14,\r
- DecorationCentroid = 15,\r
- DecorationSample = 16,\r
- DecorationInvariant = 17,\r
- DecorationRestrict = 18,\r
- DecorationAliased = 19,\r
- DecorationVolatile = 20,\r
- DecorationConstant = 21,\r
- DecorationCoherent = 22,\r
- DecorationNonwritable = 23,\r
- DecorationNonreadable = 24,\r
- DecorationUniform = 25,\r
- DecorationNoStaticUse = 26,\r
- DecorationCPacked = 27,\r
- DecorationSaturatedConversion = 28,\r
- DecorationStream = 29,\r
- DecorationLocation = 30,\r
- DecorationComponent = 31,\r
- DecorationIndex = 32,\r
- DecorationBinding = 33,\r
- DecorationDescriptorSet = 34,\r
- DecorationOffset = 35,\r
- DecorationAlignment = 36,\r
- DecorationXfbBuffer = 37,\r
- DecorationStride = 38,\r
- DecorationBuiltIn = 39,\r
- DecorationFuncParamAttr = 40,\r
- DecorationFPRoundingMode = 41,\r
- DecorationFPFastMathMode = 42,\r
- DecorationLinkageAttributes = 43,\r
- DecorationSpecId = 44,\r
-};\r
-\r
-enum BuiltIn {\r
- BuiltInPosition = 0,\r
- BuiltInPointSize = 1,\r
- BuiltInClipVertex = 2,\r
- BuiltInClipDistance = 3,\r
- BuiltInCullDistance = 4,\r
- BuiltInVertexId = 5,\r
- BuiltInInstanceId = 6,\r
- BuiltInPrimitiveId = 7,\r
- BuiltInInvocationId = 8,\r
- BuiltInLayer = 9,\r
- BuiltInViewportIndex = 10,\r
- BuiltInTessLevelOuter = 11,\r
- BuiltInTessLevelInner = 12,\r
- BuiltInTessCoord = 13,\r
- BuiltInPatchVertices = 14,\r
- BuiltInFragCoord = 15,\r
- BuiltInPointCoord = 16,\r
- BuiltInFrontFacing = 17,\r
- BuiltInSampleId = 18,\r
- BuiltInSamplePosition = 19,\r
- BuiltInSampleMask = 20,\r
- BuiltInFragColor = 21,\r
- BuiltInFragDepth = 22,\r
- BuiltInHelperInvocation = 23,\r
- BuiltInNumWorkgroups = 24,\r
- BuiltInWorkgroupSize = 25,\r
- BuiltInWorkgroupId = 26,\r
- BuiltInLocalInvocationId = 27,\r
- BuiltInGlobalInvocationId = 28,\r
- BuiltInLocalInvocationIndex = 29,\r
- BuiltInWorkDim = 30,\r
- BuiltInGlobalSize = 31,\r
- BuiltInEnqueuedWorkgroupSize = 32,\r
- BuiltInGlobalOffset = 33,\r
- BuiltInGlobalLinearId = 34,\r
- BuiltInWorkgroupLinearId = 35,\r
- BuiltInSubgroupSize = 36,\r
- BuiltInSubgroupMaxSize = 37,\r
- BuiltInNumSubgroups = 38,\r
- BuiltInNumEnqueuedSubgroups = 39,\r
- BuiltInSubgroupId = 40,\r
- BuiltInSubgroupLocalInvocationId = 41,\r
-};\r
-\r
-enum SelectionControlShift {\r
- SelectionControlFlattenShift = 0,\r
- SelectionControlDontFlattenShift = 1,\r
-};\r
-\r
-enum SelectionControlMask {\r
- SelectionControlMaskNone = 0,\r
- SelectionControlFlattenMask = 0x00000001,\r
- SelectionControlDontFlattenMask = 0x00000002,\r
-};\r
-\r
-enum LoopControlShift {\r
- LoopControlUnrollShift = 0,\r
- LoopControlDontUnrollShift = 1,\r
-};\r
-\r
-enum LoopControlMask {\r
- LoopControlMaskNone = 0,\r
- LoopControlUnrollMask = 0x00000001,\r
- LoopControlDontUnrollMask = 0x00000002,\r
-};\r
-\r
-enum FunctionControlShift {\r
- FunctionControlInlineShift = 0,\r
- FunctionControlDontInlineShift = 1,\r
- FunctionControlPureShift = 2,\r
- FunctionControlConstShift = 3,\r
-};\r
-\r
-enum FunctionControlMask {\r
- FunctionControlMaskNone = 0,\r
- FunctionControlInlineMask = 0x00000001,\r
- FunctionControlDontInlineMask = 0x00000002,\r
- FunctionControlPureMask = 0x00000004,\r
- FunctionControlConstMask = 0x00000008,\r
-};\r
-\r
-enum MemorySemanticsShift {\r
- MemorySemanticsRelaxedShift = 0,\r
- MemorySemanticsSequentiallyConsistentShift = 1,\r
- MemorySemanticsAcquireShift = 2,\r
- MemorySemanticsReleaseShift = 3,\r
- MemorySemanticsUniformMemoryShift = 4,\r
- MemorySemanticsSubgroupMemoryShift = 5,\r
- MemorySemanticsWorkgroupLocalMemoryShift = 6,\r
- MemorySemanticsWorkgroupGlobalMemoryShift = 7,\r
- MemorySemanticsAtomicCounterMemoryShift = 8,\r
- MemorySemanticsImageMemoryShift = 9,\r
-};\r
-\r
-enum MemorySemanticsMask {\r
- MemorySemanticsMaskNone = 0,\r
- MemorySemanticsRelaxedMask = 0x00000001,\r
- MemorySemanticsSequentiallyConsistentMask = 0x00000002,\r
- MemorySemanticsAcquireMask = 0x00000004,\r
- MemorySemanticsReleaseMask = 0x00000008,\r
- MemorySemanticsUniformMemoryMask = 0x00000010,\r
- MemorySemanticsSubgroupMemoryMask = 0x00000020,\r
- MemorySemanticsWorkgroupLocalMemoryMask = 0x00000040,\r
- MemorySemanticsWorkgroupGlobalMemoryMask = 0x00000080,\r
- MemorySemanticsAtomicCounterMemoryMask = 0x00000100,\r
- MemorySemanticsImageMemoryMask = 0x00000200,\r
-};\r
-\r
-enum MemoryAccessShift {\r
- MemoryAccessVolatileShift = 0,\r
- MemoryAccessAlignedShift = 1,\r
-};\r
-\r
-enum MemoryAccessMask {\r
- MemoryAccessMaskNone = 0,\r
- MemoryAccessVolatileMask = 0x00000001,\r
- MemoryAccessAlignedMask = 0x00000002,\r
-};\r
-\r
-enum ExecutionScope {\r
- ExecutionScopeCrossDevice = 0,\r
- ExecutionScopeDevice = 1,\r
- ExecutionScopeWorkgroup = 2,\r
- ExecutionScopeSubgroup = 3,\r
-};\r
-\r
-enum GroupOperation {\r
- GroupOperationReduce = 0,\r
- GroupOperationInclusiveScan = 1,\r
- GroupOperationExclusiveScan = 2,\r
-};\r
-\r
-enum KernelEnqueueFlags {\r
- KernelEnqueueFlagsNoWait = 0,\r
- KernelEnqueueFlagsWaitKernel = 1,\r
- KernelEnqueueFlagsWaitWorkGroup = 2,\r
-};\r
-\r
-enum KernelProfilingInfoShift {\r
- KernelProfilingInfoCmdExecTimeShift = 0,\r
-};\r
-\r
-enum KernelProfilingInfoMask {\r
- KernelProfilingInfoMaskNone = 0,\r
- KernelProfilingInfoCmdExecTimeMask = 0x00000001,\r
-};\r
-\r
-enum Op {\r
- OpNop = 0,\r
- OpSource = 1,\r
- OpSourceExtension = 2,\r
- OpExtension = 3,\r
- OpExtInstImport = 4,\r
- OpMemoryModel = 5,\r
- OpEntryPoint = 6,\r
- OpExecutionMode = 7,\r
- OpTypeVoid = 8,\r
- OpTypeBool = 9,\r
- OpTypeInt = 10,\r
- OpTypeFloat = 11,\r
- OpTypeVector = 12,\r
- OpTypeMatrix = 13,\r
- OpTypeSampler = 14,\r
- OpTypeFilter = 15,\r
- OpTypeArray = 16,\r
- OpTypeRuntimeArray = 17,\r
- OpTypeStruct = 18,\r
- OpTypeOpaque = 19,\r
- OpTypePointer = 20,\r
- OpTypeFunction = 21,\r
- OpTypeEvent = 22,\r
- OpTypeDeviceEvent = 23,\r
- OpTypeReserveId = 24,\r
- OpTypeQueue = 25,\r
- OpTypePipe = 26,\r
- OpConstantTrue = 27,\r
- OpConstantFalse = 28,\r
- OpConstant = 29,\r
- OpConstantComposite = 30,\r
- OpConstantSampler = 31,\r
- OpConstantNullPointer = 32,\r
- OpConstantNullObject = 33,\r
- OpSpecConstantTrue = 34,\r
- OpSpecConstantFalse = 35,\r
- OpSpecConstant = 36,\r
- OpSpecConstantComposite = 37,\r
- OpVariable = 38,\r
- OpVariableArray = 39,\r
- OpFunction = 40,\r
- OpFunctionParameter = 41,\r
- OpFunctionEnd = 42,\r
- OpFunctionCall = 43,\r
- OpExtInst = 44,\r
- OpUndef = 45,\r
- OpLoad = 46,\r
- OpStore = 47,\r
- OpPhi = 48,\r
- OpDecorationGroup = 49,\r
- OpDecorate = 50,\r
- OpMemberDecorate = 51,\r
- OpGroupDecorate = 52,\r
- OpGroupMemberDecorate = 53,\r
- OpName = 54,\r
- OpMemberName = 55,\r
- OpString = 56,\r
- OpLine = 57,\r
- OpVectorExtractDynamic = 58,\r
- OpVectorInsertDynamic = 59,\r
- OpVectorShuffle = 60,\r
- OpCompositeConstruct = 61,\r
- OpCompositeExtract = 62,\r
- OpCompositeInsert = 63,\r
- OpCopyObject = 64,\r
- OpCopyMemory = 65,\r
- OpCopyMemorySized = 66,\r
- OpSampler = 67,\r
- OpTextureSample = 68,\r
- OpTextureSampleDref = 69,\r
- OpTextureSampleLod = 70,\r
- OpTextureSampleProj = 71,\r
- OpTextureSampleGrad = 72,\r
- OpTextureSampleOffset = 73,\r
- OpTextureSampleProjLod = 74,\r
- OpTextureSampleProjGrad = 75,\r
- OpTextureSampleLodOffset = 76,\r
- OpTextureSampleProjOffset = 77,\r
- OpTextureSampleGradOffset = 78,\r
- OpTextureSampleProjLodOffset = 79,\r
- OpTextureSampleProjGradOffset = 80,\r
- OpTextureFetchTexelLod = 81,\r
- OpTextureFetchTexelOffset = 82,\r
- OpTextureFetchSample = 83,\r
- OpTextureFetchTexel = 84,\r
- OpTextureGather = 85,\r
- OpTextureGatherOffset = 86,\r
- OpTextureGatherOffsets = 87,\r
- OpTextureQuerySizeLod = 88,\r
- OpTextureQuerySize = 89,\r
- OpTextureQueryLod = 90,\r
- OpTextureQueryLevels = 91,\r
- OpTextureQuerySamples = 92,\r
- OpAccessChain = 93,\r
- OpInBoundsAccessChain = 94,\r
- OpSNegate = 95,\r
- OpFNegate = 96,\r
- OpNot = 97,\r
- OpAny = 98,\r
- OpAll = 99,\r
- OpConvertFToU = 100,\r
- OpConvertFToS = 101,\r
- OpConvertSToF = 102,\r
- OpConvertUToF = 103,\r
- OpUConvert = 104,\r
- OpSConvert = 105,\r
- OpFConvert = 106,\r
- OpConvertPtrToU = 107,\r
- OpConvertUToPtr = 108,\r
- OpPtrCastToGeneric = 109,\r
- OpGenericCastToPtr = 110,\r
- OpBitcast = 111,\r
- OpTranspose = 112,\r
- OpIsNan = 113,\r
- OpIsInf = 114,\r
- OpIsFinite = 115,\r
- OpIsNormal = 116,\r
- OpSignBitSet = 117,\r
- OpLessOrGreater = 118,\r
- OpOrdered = 119,\r
- OpUnordered = 120,\r
- OpArrayLength = 121,\r
- OpIAdd = 122,\r
- OpFAdd = 123,\r
- OpISub = 124,\r
- OpFSub = 125,\r
- OpIMul = 126,\r
- OpFMul = 127,\r
- OpUDiv = 128,\r
- OpSDiv = 129,\r
- OpFDiv = 130,\r
- OpUMod = 131,\r
- OpSRem = 132,\r
- OpSMod = 133,\r
- OpFRem = 134,\r
- OpFMod = 135,\r
- OpVectorTimesScalar = 136,\r
- OpMatrixTimesScalar = 137,\r
- OpVectorTimesMatrix = 138,\r
- OpMatrixTimesVector = 139,\r
- OpMatrixTimesMatrix = 140,\r
- OpOuterProduct = 141,\r
- OpDot = 142,\r
- OpShiftRightLogical = 143,\r
- OpShiftRightArithmetic = 144,\r
- OpShiftLeftLogical = 145,\r
- OpLogicalOr = 146,\r
- OpLogicalXor = 147,\r
- OpLogicalAnd = 148,\r
- OpBitwiseOr = 149,\r
- OpBitwiseXor = 150,\r
- OpBitwiseAnd = 151,\r
- OpSelect = 152,\r
- OpIEqual = 153,\r
- OpFOrdEqual = 154,\r
- OpFUnordEqual = 155,\r
- OpINotEqual = 156,\r
- OpFOrdNotEqual = 157,\r
- OpFUnordNotEqual = 158,\r
- OpULessThan = 159,\r
- OpSLessThan = 160,\r
- OpFOrdLessThan = 161,\r
- OpFUnordLessThan = 162,\r
- OpUGreaterThan = 163,\r
- OpSGreaterThan = 164,\r
- OpFOrdGreaterThan = 165,\r
- OpFUnordGreaterThan = 166,\r
- OpULessThanEqual = 167,\r
- OpSLessThanEqual = 168,\r
- OpFOrdLessThanEqual = 169,\r
- OpFUnordLessThanEqual = 170,\r
- OpUGreaterThanEqual = 171,\r
- OpSGreaterThanEqual = 172,\r
- OpFOrdGreaterThanEqual = 173,\r
- OpFUnordGreaterThanEqual = 174,\r
- OpDPdx = 175,\r
- OpDPdy = 176,\r
- OpFwidth = 177,\r
- OpDPdxFine = 178,\r
- OpDPdyFine = 179,\r
- OpFwidthFine = 180,\r
- OpDPdxCoarse = 181,\r
- OpDPdyCoarse = 182,\r
- OpFwidthCoarse = 183,\r
- OpEmitVertex = 184,\r
- OpEndPrimitive = 185,\r
- OpEmitStreamVertex = 186,\r
- OpEndStreamPrimitive = 187,\r
- OpControlBarrier = 188,\r
- OpMemoryBarrier = 189,\r
- OpImagePointer = 190,\r
- OpAtomicInit = 191,\r
- OpAtomicLoad = 192,\r
- OpAtomicStore = 193,\r
- OpAtomicExchange = 194,\r
- OpAtomicCompareExchange = 195,\r
- OpAtomicCompareExchangeWeak = 196,\r
- OpAtomicIIncrement = 197,\r
- OpAtomicIDecrement = 198,\r
- OpAtomicIAdd = 199,\r
- OpAtomicISub = 200,\r
- OpAtomicUMin = 201,\r
- OpAtomicUMax = 202,\r
- OpAtomicAnd = 203,\r
- OpAtomicOr = 204,\r
- OpAtomicXor = 205,\r
- OpLoopMerge = 206,\r
- OpSelectionMerge = 207,\r
- OpLabel = 208,\r
- OpBranch = 209,\r
- OpBranchConditional = 210,\r
- OpSwitch = 211,\r
- OpKill = 212,\r
- OpReturn = 213,\r
- OpReturnValue = 214,\r
- OpUnreachable = 215,\r
- OpLifetimeStart = 216,\r
- OpLifetimeStop = 217,\r
- OpCompileFlag = 218,\r
- OpAsyncGroupCopy = 219,\r
- OpWaitGroupEvents = 220,\r
- OpGroupAll = 221,\r
- OpGroupAny = 222,\r
- OpGroupBroadcast = 223,\r
- OpGroupIAdd = 224,\r
- OpGroupFAdd = 225,\r
- OpGroupFMin = 226,\r
- OpGroupUMin = 227,\r
- OpGroupSMin = 228,\r
- OpGroupFMax = 229,\r
- OpGroupUMax = 230,\r
- OpGroupSMax = 231,\r
- OpGenericCastToPtrExplicit = 232,\r
- OpGenericPtrMemSemantics = 233,\r
- OpReadPipe = 234,\r
- OpWritePipe = 235,\r
- OpReservedReadPipe = 236,\r
- OpReservedWritePipe = 237,\r
- OpReserveReadPipePackets = 238,\r
- OpReserveWritePipePackets = 239,\r
- OpCommitReadPipe = 240,\r
- OpCommitWritePipe = 241,\r
- OpIsValidReserveId = 242,\r
- OpGetNumPipePackets = 243,\r
- OpGetMaxPipePackets = 244,\r
- OpGroupReserveReadPipePackets = 245,\r
- OpGroupReserveWritePipePackets = 246,\r
- OpGroupCommitReadPipe = 247,\r
- OpGroupCommitWritePipe = 248,\r
- OpEnqueueMarker = 249,\r
- OpEnqueueKernel = 250,\r
- OpGetKernelNDrangeSubGroupCount = 251,\r
- OpGetKernelNDrangeMaxSubGroupSize = 252,\r
- OpGetKernelWorkGroupSize = 253,\r
- OpGetKernelPreferredWorkGroupSizeMultiple = 254,\r
- OpRetainEvent = 255,\r
- OpReleaseEvent = 256,\r
- OpCreateUserEvent = 257,\r
- OpIsValidEvent = 258,\r
- OpSetUserEventStatus = 259,\r
- OpCaptureEventProfilingInfo = 260,\r
- OpGetDefaultQueue = 261,\r
- OpBuildNDRange = 262,\r
- OpSatConvertSToU = 263,\r
- OpSatConvertUToS = 264,\r
- OpAtomicIMin = 265,\r
- OpAtomicIMax = 266,\r
-};\r
-\r
-}; // end namespace spv\r
-\r
-#endif // #ifdef __cplusplus\r
-\r
-\r
-#ifndef __cplusplus\r
-\r
-const int SpvMagicNumber = 0x07230203;\r
-const int SpvVersion = 99;\r
-\r
-typedef unsigned int SpvId;\r
-\r
-const unsigned int SpvOpCodeMask = 0xFFFF;\r
-const unsigned int SpvWordCountShift = 16;\r
-\r
-typedef enum SpvSourceLanguage_ {\r
- SpvSourceLanguageUnknown = 0,\r
- SpvSourceLanguageESSL = 1,\r
- SpvSourceLanguageGLSL = 2,\r
- SpvSourceLanguageOpenCL = 3,\r
-} SpvSourceLanguage;\r
-\r
-typedef enum SpvExecutionModel_ {\r
- SpvExecutionModelVertex = 0,\r
- SpvExecutionModelTessellationControl = 1,\r
- SpvExecutionModelTessellationEvaluation = 2,\r
- SpvExecutionModelGeometry = 3,\r
- SpvExecutionModelFragment = 4,\r
- SpvExecutionModelGLCompute = 5,\r
- SpvExecutionModelKernel = 6,\r
-} SpvExecutionModel;\r
-\r
-typedef enum SpvAddressingModel_ {\r
- SpvAddressingModelLogical = 0,\r
- SpvAddressingModelPhysical32 = 1,\r
- SpvAddressingModelPhysical64 = 2,\r
-} SpvAddressingModel;\r
-\r
-typedef enum SpvMemoryModel_ {\r
- SpvMemoryModelSimple = 0,\r
- SpvMemoryModelGLSL450 = 1,\r
- SpvMemoryModelOpenCL12 = 2,\r
- SpvMemoryModelOpenCL20 = 3,\r
- SpvMemoryModelOpenCL21 = 4,\r
-} SpvMemoryModel;\r
-\r
-typedef enum SpvExecutionMode_ {\r
- SpvExecutionModeInvocations = 0,\r
- SpvExecutionModeSpacingEqual = 1,\r
- SpvExecutionModeSpacingFractionalEven = 2,\r
- SpvExecutionModeSpacingFractionalOdd = 3,\r
- SpvExecutionModeVertexOrderCw = 4,\r
- SpvExecutionModeVertexOrderCcw = 5,\r
- SpvExecutionModePixelCenterInteger = 6,\r
- SpvExecutionModeOriginUpperLeft = 7,\r
- SpvExecutionModeEarlyFragmentTests = 8,\r
- SpvExecutionModePointMode = 9,\r
- SpvExecutionModeXfb = 10,\r
- SpvExecutionModeDepthReplacing = 11,\r
- SpvExecutionModeDepthAny = 12,\r
- SpvExecutionModeDepthGreater = 13,\r
- SpvExecutionModeDepthLess = 14,\r
- SpvExecutionModeDepthUnchanged = 15,\r
- SpvExecutionModeLocalSize = 16,\r
- SpvExecutionModeLocalSizeHint = 17,\r
- SpvExecutionModeInputPoints = 18,\r
- SpvExecutionModeInputLines = 19,\r
- SpvExecutionModeInputLinesAdjacency = 20,\r
- SpvExecutionModeInputTriangles = 21,\r
- SpvExecutionModeInputTrianglesAdjacency = 22,\r
- SpvExecutionModeInputQuads = 23,\r
- SpvExecutionModeInputIsolines = 24,\r
- SpvExecutionModeOutputVertices = 25,\r
- SpvExecutionModeOutputPoints = 26,\r
- SpvExecutionModeOutputLineStrip = 27,\r
- SpvExecutionModeOutputTriangleStrip = 28,\r
- SpvExecutionModeVecTypeHint = 29,\r
- SpvExecutionModeContractionOff = 30,\r
-} SpvExecutionMode;\r
-\r
-typedef enum SpvStorageClass_ {\r
- SpvStorageClassUniformConstant = 0,\r
- SpvStorageClassInput = 1,\r
- SpvStorageClassUniform = 2,\r
- SpvStorageClassOutput = 3,\r
- SpvStorageClassWorkgroupLocal = 4,\r
- SpvStorageClassWorkgroupGlobal = 5,\r
- SpvStorageClassPrivateGlobal = 6,\r
- SpvStorageClassFunction = 7,\r
- SpvStorageClassGeneric = 8,\r
- SpvStorageClassPrivate = 9,\r
- SpvStorageClassAtomicCounter = 10,\r
-} SpvStorageClass;\r
-\r
-typedef enum SpvDim_ {\r
- SpvDim1D = 0,\r
- SpvDim2D = 1,\r
- SpvDim3D = 2,\r
- SpvDimCube = 3,\r
- SpvDimRect = 4,\r
- SpvDimBuffer = 5,\r
-} SpvDim;\r
-\r
-typedef enum SpvSamplerAddressingMode_ {\r
- SpvSamplerAddressingModeNone = 0,\r
- SpvSamplerAddressingModeClampToEdge = 1,\r
- SpvSamplerAddressingModeClamp = 2,\r
- SpvSamplerAddressingModeRepeat = 3,\r
- SpvSamplerAddressingModeRepeatMirrored = 4,\r
-} SpvSamplerAddressingMode;\r
-\r
-typedef enum SpvSamplerFilterMode_ {\r
- SpvSamplerFilterModeNearest = 0,\r
- SpvSamplerFilterModeLinear = 1,\r
-} SpvSamplerFilterMode;\r
-\r
-typedef enum SpvFPFastMathModeShift_ {\r
- SpvFPFastMathModeNotNaNShift = 0,\r
- SpvFPFastMathModeNotInfShift = 1,\r
- SpvFPFastMathModeNSZShift = 2,\r
- SpvFPFastMathModeAllowRecipShift = 3,\r
- SpvFPFastMathModeFastShift = 4,\r
-} SpvFPFastMathModeShift;\r
-\r
-typedef enum SpvFPFastMathModeMask_ {\r
- SpvFPFastMathModeMaskNone = 0,\r
- SpvFPFastMathModeNotNaNMask = 0x00000001,\r
- SpvFPFastMathModeNotInfMask = 0x00000002,\r
- SpvFPFastMathModeNSZMask = 0x00000004,\r
- SpvFPFastMathModeAllowRecipMask = 0x00000008,\r
- SpvFPFastMathModeFastMask = 0x00000010,\r
-} SpvFPFastMathModeMask;\r
-\r
-typedef enum SpvFPRoundingMode_ {\r
- SpvFPRoundingModeRTE = 0,\r
- SpvFPRoundingModeRTZ = 1,\r
- SpvFPRoundingModeRTP = 2,\r
- SpvFPRoundingModeRTN = 3,\r
-} SpvFPRoundingMode;\r
-\r
-typedef enum SpvLinkageType_ {\r
- SpvLinkageTypeExport = 0,\r
- SpvLinkageTypeImport = 1,\r
-} SpvLinkageType;\r
-\r
-typedef enum SpvAccessQualifier_ {\r
- SpvAccessQualifierReadOnly = 0,\r
- SpvAccessQualifierWriteOnly = 1,\r
- SpvAccessQualifierReadWrite = 2,\r
-} SpvAccessQualifier;\r
-\r
-typedef enum SpvFunctionParameterAttribute_ {\r
- SpvFunctionParameterAttributeZext = 0,\r
- SpvFunctionParameterAttributeSext = 1,\r
- SpvFunctionParameterAttributeByVal = 2,\r
- SpvFunctionParameterAttributeSret = 3,\r
- SpvFunctionParameterAttributeNoAlias = 4,\r
- SpvFunctionParameterAttributeNoCapture = 5,\r
- SpvFunctionParameterAttributeSVM = 6,\r
- SpvFunctionParameterAttributeNoWrite = 7,\r
- SpvFunctionParameterAttributeNoReadWrite = 8,\r
-} SpvFunctionParameterAttribute;\r
-\r
-typedef enum SpvDecoration_ {\r
- SpvDecorationPrecisionLow = 0,\r
- SpvDecorationPrecisionMedium = 1,\r
- SpvDecorationPrecisionHigh = 2,\r
- SpvDecorationBlock = 3,\r
- SpvDecorationBufferBlock = 4,\r
- SpvDecorationRowMajor = 5,\r
- SpvDecorationColMajor = 6,\r
- SpvDecorationGLSLShared = 7,\r
- SpvDecorationGLSLStd140 = 8,\r
- SpvDecorationGLSLStd430 = 9,\r
- SpvDecorationGLSLPacked = 10,\r
- SpvDecorationSmooth = 11,\r
- SpvDecorationNoperspective = 12,\r
- SpvDecorationFlat = 13,\r
- SpvDecorationPatch = 14,\r
- SpvDecorationCentroid = 15,\r
- SpvDecorationSample = 16,\r
- SpvDecorationInvariant = 17,\r
- SpvDecorationRestrict = 18,\r
- SpvDecorationAliased = 19,\r
- SpvDecorationVolatile = 20,\r
- SpvDecorationConstant = 21,\r
- SpvDecorationCoherent = 22,\r
- SpvDecorationNonwritable = 23,\r
- SpvDecorationNonreadable = 24,\r
- SpvDecorationUniform = 25,\r
- SpvDecorationNoStaticUse = 26,\r
- SpvDecorationCPacked = 27,\r
- SpvDecorationSaturatedConversion = 28,\r
- SpvDecorationStream = 29,\r
- SpvDecorationLocation = 30,\r
- SpvDecorationComponent = 31,\r
- SpvDecorationIndex = 32,\r
- SpvDecorationBinding = 33,\r
- SpvDecorationDescriptorSet = 34,\r
- SpvDecorationOffset = 35,\r
- SpvDecorationAlignment = 36,\r
- SpvDecorationXfbBuffer = 37,\r
- SpvDecorationStride = 38,\r
- SpvDecorationBuiltIn = 39,\r
- SpvDecorationFuncParamAttr = 40,\r
- SpvDecorationFPRoundingMode = 41,\r
- SpvDecorationFPFastMathMode = 42,\r
- SpvDecorationLinkageAttributes = 43,\r
- SpvDecorationSpecId = 44,\r
-} SpvDecoration;\r
-\r
-typedef enum SpvBuiltIn_ {\r
- SpvBuiltInPosition = 0,\r
- SpvBuiltInPointSize = 1,\r
- SpvBuiltInClipVertex = 2,\r
- SpvBuiltInClipDistance = 3,\r
- SpvBuiltInCullDistance = 4,\r
- SpvBuiltInVertexId = 5,\r
- SpvBuiltInInstanceId = 6,\r
- SpvBuiltInPrimitiveId = 7,\r
- SpvBuiltInInvocationId = 8,\r
- SpvBuiltInLayer = 9,\r
- SpvBuiltInViewportIndex = 10,\r
- SpvBuiltInTessLevelOuter = 11,\r
- SpvBuiltInTessLevelInner = 12,\r
- SpvBuiltInTessCoord = 13,\r
- SpvBuiltInPatchVertices = 14,\r
- SpvBuiltInFragCoord = 15,\r
- SpvBuiltInPointCoord = 16,\r
- SpvBuiltInFrontFacing = 17,\r
- SpvBuiltInSampleId = 18,\r
- SpvBuiltInSamplePosition = 19,\r
- SpvBuiltInSampleMask = 20,\r
- SpvBuiltInFragColor = 21,\r
- SpvBuiltInFragDepth = 22,\r
- SpvBuiltInHelperInvocation = 23,\r
- SpvBuiltInNumWorkgroups = 24,\r
- SpvBuiltInWorkgroupSize = 25,\r
- SpvBuiltInWorkgroupId = 26,\r
- SpvBuiltInLocalInvocationId = 27,\r
- SpvBuiltInGlobalInvocationId = 28,\r
- SpvBuiltInLocalInvocationIndex = 29,\r
- SpvBuiltInWorkDim = 30,\r
- SpvBuiltInGlobalSize = 31,\r
- SpvBuiltInEnqueuedWorkgroupSize = 32,\r
- SpvBuiltInGlobalOffset = 33,\r
- SpvBuiltInGlobalLinearId = 34,\r
- SpvBuiltInWorkgroupLinearId = 35,\r
- SpvBuiltInSubgroupSize = 36,\r
- SpvBuiltInSubgroupMaxSize = 37,\r
- SpvBuiltInNumSubgroups = 38,\r
- SpvBuiltInNumEnqueuedSubgroups = 39,\r
- SpvBuiltInSubgroupId = 40,\r
- SpvBuiltInSubgroupLocalInvocationId = 41,\r
-} SpvBuiltIn;\r
-\r
-typedef enum SpvSelectionControlShift_ {\r
- SpvSelectionControlFlattenShift = 0,\r
- SpvSelectionControlDontFlattenShift = 1,\r
-} SpvSelectionControlShift;\r
-\r
-typedef enum SpvSelectionControlMask_ {\r
- SpvSelectionControlMaskNone = 0,\r
- SpvSelectionControlFlattenMask = 0x00000001,\r
- SpvSelectionControlDontFlattenMask = 0x00000002,\r
-} SpvSelectionControlMask;\r
-\r
-typedef enum SpvLoopControlShift_ {\r
- SpvLoopControlUnrollShift = 0,\r
- SpvLoopControlDontUnrollShift = 1,\r
-} SpvLoopControlShift;\r
-\r
-typedef enum SpvLoopControlMask_ {\r
- SpvLoopControlMaskNone = 0,\r
- SpvLoopControlUnrollMask = 0x00000001,\r
- SpvLoopControlDontUnrollMask = 0x00000002,\r
-} SpvLoopControlMask;\r
-\r
-typedef enum SpvFunctionControlShift_ {\r
- SpvFunctionControlInlineShift = 0,\r
- SpvFunctionControlDontInlineShift = 1,\r
- SpvFunctionControlPureShift = 2,\r
- SpvFunctionControlConstShift = 3,\r
-} SpvFunctionControlShift;\r
-\r
-typedef enum SpvFunctionControlMask_ {\r
- SpvFunctionControlMaskNone = 0,\r
- SpvFunctionControlInlineMask = 0x00000001,\r
- SpvFunctionControlDontInlineMask = 0x00000002,\r
- SpvFunctionControlPureMask = 0x00000004,\r
- SpvFunctionControlConstMask = 0x00000008,\r
-} SpvFunctionControlMask;\r
-\r
-typedef enum SpvMemorySemanticsShift_ {\r
- SpvMemorySemanticsRelaxedShift = 0,\r
- SpvMemorySemanticsSequentiallyConsistentShift = 1,\r
- SpvMemorySemanticsAcquireShift = 2,\r
- SpvMemorySemanticsReleaseShift = 3,\r
- SpvMemorySemanticsUniformMemoryShift = 4,\r
- SpvMemorySemanticsSubgroupMemoryShift = 5,\r
- SpvMemorySemanticsWorkgroupLocalMemoryShift = 6,\r
- SpvMemorySemanticsWorkgroupGlobalMemoryShift = 7,\r
- SpvMemorySemanticsAtomicCounterMemoryShift = 8,\r
- SpvMemorySemanticsImageMemoryShift = 9,\r
-} SpvMemorySemanticsShift;\r
-\r
-typedef enum SpvMemorySemanticsMask_ {\r
- SpvMemorySemanticsMaskNone = 0,\r
- SpvMemorySemanticsRelaxedMask = 0x00000001,\r
- SpvMemorySemanticsSequentiallyConsistentMask = 0x00000002,\r
- SpvMemorySemanticsAcquireMask = 0x00000004,\r
- SpvMemorySemanticsReleaseMask = 0x00000008,\r
- SpvMemorySemanticsUniformMemoryMask = 0x00000010,\r
- SpvMemorySemanticsSubgroupMemoryMask = 0x00000020,\r
- SpvMemorySemanticsWorkgroupLocalMemoryMask = 0x00000040,\r
- SpvMemorySemanticsWorkgroupGlobalMemoryMask = 0x00000080,\r
- SpvMemorySemanticsAtomicCounterMemoryMask = 0x00000100,\r
- SpvMemorySemanticsImageMemoryMask = 0x00000200,\r
-} SpvMemorySemanticsMask;\r
-\r
-typedef enum SpvMemoryAccessShift_ {\r
- SpvMemoryAccessVolatileShift = 0,\r
- SpvMemoryAccessAlignedShift = 1,\r
-} SpvMemoryAccessShift;\r
-\r
-typedef enum SpvMemoryAccessMask_ {\r
- SpvMemoryAccessMaskNone = 0,\r
- SpvMemoryAccessVolatileMask = 0x00000001,\r
- SpvMemoryAccessAlignedMask = 0x00000002,\r
-} SpvMemoryAccessMask;\r
-\r
-typedef enum SpvExecutionScope_ {\r
- SpvExecutionScopeCrossDevice = 0,\r
- SpvExecutionScopeDevice = 1,\r
- SpvExecutionScopeWorkgroup = 2,\r
- SpvExecutionScopeSubgroup = 3,\r
-} SpvExecutionScope;\r
-\r
-typedef enum SpvGroupOperation_ {\r
- SpvGroupOperationReduce = 0,\r
- SpvGroupOperationInclusiveScan = 1,\r
- SpvGroupOperationExclusiveScan = 2,\r
-} SpvGroupOperation;\r
-\r
-typedef enum SpvKernelEnqueueFlags_ {\r
- SpvKernelEnqueueFlagsNoWait = 0,\r
- SpvKernelEnqueueFlagsWaitKernel = 1,\r
- SpvKernelEnqueueFlagsWaitWorkGroup = 2,\r
-} SpvKernelEnqueueFlags;\r
-\r
-typedef enum SpvKernelProfilingInfoShift_ {\r
- SpvKernelProfilingInfoCmdExecTimeShift = 0,\r
-} SpvKernelProfilingInfoShift;\r
-\r
-typedef enum SpvKernelProfilingInfoMask_ {\r
- SpvKernelProfilingInfoMaskNone = 0,\r
- SpvKernelProfilingInfoCmdExecTimeMask = 0x00000001,\r
-} SpvKernelProfilingInfoMask;\r
-\r
-typedef enum SpvOp_ {\r
- SpvOpNop = 0,\r
- SpvOpSource = 1,\r
- SpvOpSourceExtension = 2,\r
- SpvOpExtension = 3,\r
- SpvOpExtInstImport = 4,\r
- SpvOpMemoryModel = 5,\r
- SpvOpEntryPoint = 6,\r
- SpvOpExecutionMode = 7,\r
- SpvOpTypeVoid = 8,\r
- SpvOpTypeBool = 9,\r
- SpvOpTypeInt = 10,\r
- SpvOpTypeFloat = 11,\r
- SpvOpTypeVector = 12,\r
- SpvOpTypeMatrix = 13,\r
- SpvOpTypeSampler = 14,\r
- SpvOpTypeFilter = 15,\r
- SpvOpTypeArray = 16,\r
- SpvOpTypeRuntimeArray = 17,\r
- SpvOpTypeStruct = 18,\r
- SpvOpTypeOpaque = 19,\r
- SpvOpTypePointer = 20,\r
- SpvOpTypeFunction = 21,\r
- SpvOpTypeEvent = 22,\r
- SpvOpTypeDeviceEvent = 23,\r
- SpvOpTypeReserveId = 24,\r
- SpvOpTypeQueue = 25,\r
- SpvOpTypePipe = 26,\r
- SpvOpConstantTrue = 27,\r
- SpvOpConstantFalse = 28,\r
- SpvOpConstant = 29,\r
- SpvOpConstantComposite = 30,\r
- SpvOpConstantSampler = 31,\r
- SpvOpConstantNullPointer = 32,\r
- SpvOpConstantNullObject = 33,\r
- SpvOpSpecConstantTrue = 34,\r
- SpvOpSpecConstantFalse = 35,\r
- SpvOpSpecConstant = 36,\r
- SpvOpSpecConstantComposite = 37,\r
- SpvOpVariable = 38,\r
- SpvOpVariableArray = 39,\r
- SpvOpFunction = 40,\r
- SpvOpFunctionParameter = 41,\r
- SpvOpFunctionEnd = 42,\r
- SpvOpFunctionCall = 43,\r
- SpvOpExtInst = 44,\r
- SpvOpUndef = 45,\r
- SpvOpLoad = 46,\r
- SpvOpStore = 47,\r
- SpvOpPhi = 48,\r
- SpvOpDecorationGroup = 49,\r
- SpvOpDecorate = 50,\r
- SpvOpMemberDecorate = 51,\r
- SpvOpGroupDecorate = 52,\r
- SpvOpGroupMemberDecorate = 53,\r
- SpvOpName = 54,\r
- SpvOpMemberName = 55,\r
- SpvOpString = 56,\r
- SpvOpLine = 57,\r
- SpvOpVectorExtractDynamic = 58,\r
- SpvOpVectorInsertDynamic = 59,\r
- SpvOpVectorShuffle = 60,\r
- SpvOpCompositeConstruct = 61,\r
- SpvOpCompositeExtract = 62,\r
- SpvOpCompositeInsert = 63,\r
- SpvOpCopyObject = 64,\r
- SpvOpCopyMemory = 65,\r
- SpvOpCopyMemorySized = 66,\r
- SpvOpSampler = 67,\r
- SpvOpTextureSample = 68,\r
- SpvOpTextureSampleDref = 69,\r
- SpvOpTextureSampleLod = 70,\r
- SpvOpTextureSampleProj = 71,\r
- SpvOpTextureSampleGrad = 72,\r
- SpvOpTextureSampleOffset = 73,\r
- SpvOpTextureSampleProjLod = 74,\r
- SpvOpTextureSampleProjGrad = 75,\r
- SpvOpTextureSampleLodOffset = 76,\r
- SpvOpTextureSampleProjOffset = 77,\r
- SpvOpTextureSampleGradOffset = 78,\r
- SpvOpTextureSampleProjLodOffset = 79,\r
- SpvOpTextureSampleProjGradOffset = 80,\r
- SpvOpTextureFetchTexelLod = 81,\r
- SpvOpTextureFetchTexelOffset = 82,\r
- SpvOpTextureFetchSample = 83,\r
- SpvOpTextureFetchTexel = 84,\r
- SpvOpTextureGather = 85,\r
- SpvOpTextureGatherOffset = 86,\r
- SpvOpTextureGatherOffsets = 87,\r
- SpvOpTextureQuerySizeLod = 88,\r
- SpvOpTextureQuerySize = 89,\r
- SpvOpTextureQueryLod = 90,\r
- SpvOpTextureQueryLevels = 91,\r
- SpvOpTextureQuerySamples = 92,\r
- SpvOpAccessChain = 93,\r
- SpvOpInBoundsAccessChain = 94,\r
- SpvOpSNegate = 95,\r
- SpvOpFNegate = 96,\r
- SpvOpNot = 97,\r
- SpvOpAny = 98,\r
- SpvOpAll = 99,\r
- SpvOpConvertFToU = 100,\r
- SpvOpConvertFToS = 101,\r
- SpvOpConvertSToF = 102,\r
- SpvOpConvertUToF = 103,\r
- SpvOpUConvert = 104,\r
- SpvOpSConvert = 105,\r
- SpvOpFConvert = 106,\r
- SpvOpConvertPtrToU = 107,\r
- SpvOpConvertUToPtr = 108,\r
- SpvOpPtrCastToGeneric = 109,\r
- SpvOpGenericCastToPtr = 110,\r
- SpvOpBitcast = 111,\r
- SpvOpTranspose = 112,\r
- SpvOpIsNan = 113,\r
- SpvOpIsInf = 114,\r
- SpvOpIsFinite = 115,\r
- SpvOpIsNormal = 116,\r
- SpvOpSignBitSet = 117,\r
- SpvOpLessOrGreater = 118,\r
- SpvOpOrdered = 119,\r
- SpvOpUnordered = 120,\r
- SpvOpArrayLength = 121,\r
- SpvOpIAdd = 122,\r
- SpvOpFAdd = 123,\r
- SpvOpISub = 124,\r
- SpvOpFSub = 125,\r
- SpvOpIMul = 126,\r
- SpvOpFMul = 127,\r
- SpvOpUDiv = 128,\r
- SpvOpSDiv = 129,\r
- SpvOpFDiv = 130,\r
- SpvOpUMod = 131,\r
- SpvOpSRem = 132,\r
- SpvOpSMod = 133,\r
- SpvOpFRem = 134,\r
- SpvOpFMod = 135,\r
- SpvOpVectorTimesScalar = 136,\r
- SpvOpMatrixTimesScalar = 137,\r
- SpvOpVectorTimesMatrix = 138,\r
- SpvOpMatrixTimesVector = 139,\r
- SpvOpMatrixTimesMatrix = 140,\r
- SpvOpOuterProduct = 141,\r
- SpvOpDot = 142,\r
- SpvOpShiftRightLogical = 143,\r
- SpvOpShiftRightArithmetic = 144,\r
- SpvOpShiftLeftLogical = 145,\r
- SpvOpLogicalOr = 146,\r
- SpvOpLogicalXor = 147,\r
- SpvOpLogicalAnd = 148,\r
- SpvOpBitwiseOr = 149,\r
- SpvOpBitwiseXor = 150,\r
- SpvOpBitwiseAnd = 151,\r
- SpvOpSelect = 152,\r
- SpvOpIEqual = 153,\r
- SpvOpFOrdEqual = 154,\r
- SpvOpFUnordEqual = 155,\r
- SpvOpINotEqual = 156,\r
- SpvOpFOrdNotEqual = 157,\r
- SpvOpFUnordNotEqual = 158,\r
- SpvOpULessThan = 159,\r
- SpvOpSLessThan = 160,\r
- SpvOpFOrdLessThan = 161,\r
- SpvOpFUnordLessThan = 162,\r
- SpvOpUGreaterThan = 163,\r
- SpvOpSGreaterThan = 164,\r
- SpvOpFOrdGreaterThan = 165,\r
- SpvOpFUnordGreaterThan = 166,\r
- SpvOpULessThanEqual = 167,\r
- SpvOpSLessThanEqual = 168,\r
- SpvOpFOrdLessThanEqual = 169,\r
- SpvOpFUnordLessThanEqual = 170,\r
- SpvOpUGreaterThanEqual = 171,\r
- SpvOpSGreaterThanEqual = 172,\r
- SpvOpFOrdGreaterThanEqual = 173,\r
- SpvOpFUnordGreaterThanEqual = 174,\r
- SpvOpDPdx = 175,\r
- SpvOpDPdy = 176,\r
- SpvOpFwidth = 177,\r
- SpvOpDPdxFine = 178,\r
- SpvOpDPdyFine = 179,\r
- SpvOpFwidthFine = 180,\r
- SpvOpDPdxCoarse = 181,\r
- SpvOpDPdyCoarse = 182,\r
- SpvOpFwidthCoarse = 183,\r
- SpvOpEmitVertex = 184,\r
- SpvOpEndPrimitive = 185,\r
- SpvOpEmitStreamVertex = 186,\r
- SpvOpEndStreamPrimitive = 187,\r
- SpvOpControlBarrier = 188,\r
- SpvOpMemoryBarrier = 189,\r
- SpvOpImagePointer = 190,\r
- SpvOpAtomicInit = 191,\r
- SpvOpAtomicLoad = 192,\r
- SpvOpAtomicStore = 193,\r
- SpvOpAtomicExchange = 194,\r
- SpvOpAtomicCompareExchange = 195,\r
- SpvOpAtomicCompareExchangeWeak = 196,\r
- SpvOpAtomicIIncrement = 197,\r
- SpvOpAtomicIDecrement = 198,\r
- SpvOpAtomicIAdd = 199,\r
- SpvOpAtomicISub = 200,\r
- SpvOpAtomicUMin = 201,\r
- SpvOpAtomicUMax = 202,\r
- SpvOpAtomicAnd = 203,\r
- SpvOpAtomicOr = 204,\r
- SpvOpAtomicXor = 205,\r
- SpvOpLoopMerge = 206,\r
- SpvOpSelectionMerge = 207,\r
- SpvOpLabel = 208,\r
- SpvOpBranch = 209,\r
- SpvOpBranchConditional = 210,\r
- SpvOpSwitch = 211,\r
- SpvOpKill = 212,\r
- SpvOpReturn = 213,\r
- SpvOpReturnValue = 214,\r
- SpvOpUnreachable = 215,\r
- SpvOpLifetimeStart = 216,\r
- SpvOpLifetimeStop = 217,\r
- SpvOpCompileFlag = 218,\r
- SpvOpAsyncGroupCopy = 219,\r
- SpvOpWaitGroupEvents = 220,\r
- SpvOpGroupAll = 221,\r
- SpvOpGroupAny = 222,\r
- SpvOpGroupBroadcast = 223,\r
- SpvOpGroupIAdd = 224,\r
- SpvOpGroupFAdd = 225,\r
- SpvOpGroupFMin = 226,\r
- SpvOpGroupUMin = 227,\r
- SpvOpGroupSMin = 228,\r
- SpvOpGroupFMax = 229,\r
- SpvOpGroupUMax = 230,\r
- SpvOpGroupSMax = 231,\r
- SpvOpGenericCastToPtrExplicit = 232,\r
- SpvOpGenericPtrMemSemantics = 233,\r
- SpvOpReadPipe = 234,\r
- SpvOpWritePipe = 235,\r
- SpvOpReservedReadPipe = 236,\r
- SpvOpReservedWritePipe = 237,\r
- SpvOpReserveReadPipePackets = 238,\r
- SpvOpReserveWritePipePackets = 239,\r
- SpvOpCommitReadPipe = 240,\r
- SpvOpCommitWritePipe = 241,\r
- SpvOpIsValidReserveId = 242,\r
- SpvOpGetNumPipePackets = 243,\r
- SpvOpGetMaxPipePackets = 244,\r
- SpvOpGroupReserveReadPipePackets = 245,\r
- SpvOpGroupReserveWritePipePackets = 246,\r
- SpvOpGroupCommitReadPipe = 247,\r
- SpvOpGroupCommitWritePipe = 248,\r
- SpvOpEnqueueMarker = 249,\r
- SpvOpEnqueueKernel = 250,\r
- SpvOpGetKernelNDrangeSubGroupCount = 251,\r
- SpvOpGetKernelNDrangeMaxSubGroupSize = 252,\r
- SpvOpGetKernelWorkGroupSize = 253,\r
- SpvOpGetKernelPreferredWorkGroupSizeMultiple = 254,\r
- SpvOpRetainEvent = 255,\r
- SpvOpReleaseEvent = 256,\r
- SpvOpCreateUserEvent = 257,\r
- SpvOpIsValidEvent = 258,\r
- SpvOpSetUserEventStatus = 259,\r
- SpvOpCaptureEventProfilingInfo = 260,\r
- SpvOpGetDefaultQueue = 261,\r
- SpvOpBuildNDRange = 262,\r
- SpvOpSatConvertSToU = 263,\r
- SpvOpSatConvertUToS = 264,\r
- SpvOpAtomicIMin = 265,\r
- SpvOpAtomicIMax = 266,\r
-} SpvOp;\r
-\r
-#endif // #ifndef __cplusplus\r
-\r
-#endif // #ifndef spirv_H\r
+/*
+** Copyright (c) 2015 The Khronos Group Inc.
+**
+** Permission is hereby granted, free of charge, to any person obtaining a copy
+** of this software and/or associated documentation files (the "Materials"),
+** to deal in the Materials without restriction, including without limitation
+** the rights to use, copy, modify, merge, publish, distribute, sublicense,
+** and/or sell copies of the Materials, and to permit persons to whom the
+** Materials are furnished to do so, subject to the following conditions:
+**
+** The above copyright notice and this permission notice shall be included in
+** all copies or substantial portions of the Materials.
+**
+** MODIFICATIONS TO THIS FILE MAY MEAN IT NO LONGER ACCURATELY REFLECTS KHRONOS
+** STANDARDS. THE UNMODIFIED, NORMATIVE VERSIONS OF KHRONOS SPECIFICATIONS AND
+** HEADER INFORMATION ARE LOCATED AT https://www.khronos.org/registry/
+**
+** THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+** OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+** FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+** THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+** LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+** FROM,OUT OF OR IN CONNECTION WITH THE MATERIALS OR THE USE OR OTHER DEALINGS
+** IN THE MATERIALS.
+*/
+
+/*
+** This header is automatically generated by the same tool that creates
+** the Binary Section of the SPIR-V specification.
+*/
+
+/*
+** Specification revision 30.
+** Enumeration tokens for SPIR-V, in three styles: C, C++, generic.
+** - C++ will have the tokens in the "spv" name space, with no prefix.
+** - C will have tokens with as "Spv" prefix.
+**
+** Some tokens act like mask values, which can be OR'd together,
+** while others are mutually exclusive. The mask-like ones have
+** "Mask" in their name, and a parallel enum that has the shift
+** amount (1 << x) for each corresponding enumerant.
+*/
+
+#ifndef spirv_H
+#define spirv_H
+
+#ifdef __cplusplus
+
+namespace spv {
+
+const int MagicNumber = 0x07230203;
+const int Version = 99;
+
+typedef unsigned int Id;
+
+const unsigned int OpCodeMask = 0xFFFF;
+const unsigned int WordCountShift = 16;
+
+enum SourceLanguage {
+ SourceLanguageUnknown = 0,
+ SourceLanguageESSL = 1,
+ SourceLanguageGLSL = 2,
+ SourceLanguageOpenCL = 3,
+};
+
+enum ExecutionModel {
+ ExecutionModelVertex = 0,
+ ExecutionModelTessellationControl = 1,
+ ExecutionModelTessellationEvaluation = 2,
+ ExecutionModelGeometry = 3,
+ ExecutionModelFragment = 4,
+ ExecutionModelGLCompute = 5,
+ ExecutionModelKernel = 6,
+};
+
+enum AddressingModel {
+ AddressingModelLogical = 0,
+ AddressingModelPhysical32 = 1,
+ AddressingModelPhysical64 = 2,
+};
+
+enum MemoryModel {
+ MemoryModelSimple = 0,
+ MemoryModelGLSL450 = 1,
+ MemoryModelOpenCL12 = 2,
+ MemoryModelOpenCL20 = 3,
+ MemoryModelOpenCL21 = 4,
+};
+
+enum ExecutionMode {
+ ExecutionModeInvocations = 0,
+ ExecutionModeSpacingEqual = 1,
+ ExecutionModeSpacingFractionalEven = 2,
+ ExecutionModeSpacingFractionalOdd = 3,
+ ExecutionModeVertexOrderCw = 4,
+ ExecutionModeVertexOrderCcw = 5,
+ ExecutionModePixelCenterInteger = 6,
+ ExecutionModeOriginUpperLeft = 7,
+ ExecutionModeEarlyFragmentTests = 8,
+ ExecutionModePointMode = 9,
+ ExecutionModeXfb = 10,
+ ExecutionModeDepthReplacing = 11,
+ ExecutionModeDepthAny = 12,
+ ExecutionModeDepthGreater = 13,
+ ExecutionModeDepthLess = 14,
+ ExecutionModeDepthUnchanged = 15,
+ ExecutionModeLocalSize = 16,
+ ExecutionModeLocalSizeHint = 17,
+ ExecutionModeInputPoints = 18,
+ ExecutionModeInputLines = 19,
+ ExecutionModeInputLinesAdjacency = 20,
+ ExecutionModeInputTriangles = 21,
+ ExecutionModeInputTrianglesAdjacency = 22,
+ ExecutionModeInputQuads = 23,
+ ExecutionModeInputIsolines = 24,
+ ExecutionModeOutputVertices = 25,
+ ExecutionModeOutputPoints = 26,
+ ExecutionModeOutputLineStrip = 27,
+ ExecutionModeOutputTriangleStrip = 28,
+ ExecutionModeVecTypeHint = 29,
+ ExecutionModeContractionOff = 30,
+};
+
+enum StorageClass {
+ StorageClassUniformConstant = 0,
+ StorageClassInput = 1,
+ StorageClassUniform = 2,
+ StorageClassOutput = 3,
+ StorageClassWorkgroupLocal = 4,
+ StorageClassWorkgroupGlobal = 5,
+ StorageClassPrivateGlobal = 6,
+ StorageClassFunction = 7,
+ StorageClassGeneric = 8,
+ StorageClassPrivate = 9,
+ StorageClassAtomicCounter = 10,
+};
+
+enum Dim {
+ Dim1D = 0,
+ Dim2D = 1,
+ Dim3D = 2,
+ DimCube = 3,
+ DimRect = 4,
+ DimBuffer = 5,
+};
+
+enum SamplerAddressingMode {
+ SamplerAddressingModeNone = 0,
+ SamplerAddressingModeClampToEdge = 1,
+ SamplerAddressingModeClamp = 2,
+ SamplerAddressingModeRepeat = 3,
+ SamplerAddressingModeRepeatMirrored = 4,
+};
+
+enum SamplerFilterMode {
+ SamplerFilterModeNearest = 0,
+ SamplerFilterModeLinear = 1,
+};
+
+enum FPFastMathModeShift {
+ FPFastMathModeNotNaNShift = 0,
+ FPFastMathModeNotInfShift = 1,
+ FPFastMathModeNSZShift = 2,
+ FPFastMathModeAllowRecipShift = 3,
+ FPFastMathModeFastShift = 4,
+};
+
+enum FPFastMathModeMask {
+ FPFastMathModeMaskNone = 0,
+ FPFastMathModeNotNaNMask = 0x00000001,
+ FPFastMathModeNotInfMask = 0x00000002,
+ FPFastMathModeNSZMask = 0x00000004,
+ FPFastMathModeAllowRecipMask = 0x00000008,
+ FPFastMathModeFastMask = 0x00000010,
+};
+
+enum FPRoundingMode {
+ FPRoundingModeRTE = 0,
+ FPRoundingModeRTZ = 1,
+ FPRoundingModeRTP = 2,
+ FPRoundingModeRTN = 3,
+};
+
+enum LinkageType {
+ LinkageTypeExport = 0,
+ LinkageTypeImport = 1,
+};
+
+enum AccessQualifier {
+ AccessQualifierReadOnly = 0,
+ AccessQualifierWriteOnly = 1,
+ AccessQualifierReadWrite = 2,
+};
+
+enum FunctionParameterAttribute {
+ FunctionParameterAttributeZext = 0,
+ FunctionParameterAttributeSext = 1,
+ FunctionParameterAttributeByVal = 2,
+ FunctionParameterAttributeSret = 3,
+ FunctionParameterAttributeNoAlias = 4,
+ FunctionParameterAttributeNoCapture = 5,
+ FunctionParameterAttributeSVM = 6,
+ FunctionParameterAttributeNoWrite = 7,
+ FunctionParameterAttributeNoReadWrite = 8,
+};
+
+enum Decoration {
+ DecorationPrecisionLow = 0,
+ DecorationPrecisionMedium = 1,
+ DecorationPrecisionHigh = 2,
+ DecorationBlock = 3,
+ DecorationBufferBlock = 4,
+ DecorationRowMajor = 5,
+ DecorationColMajor = 6,
+ DecorationGLSLShared = 7,
+ DecorationGLSLStd140 = 8,
+ DecorationGLSLStd430 = 9,
+ DecorationGLSLPacked = 10,
+ DecorationSmooth = 11,
+ DecorationNoperspective = 12,
+ DecorationFlat = 13,
+ DecorationPatch = 14,
+ DecorationCentroid = 15,
+ DecorationSample = 16,
+ DecorationInvariant = 17,
+ DecorationRestrict = 18,
+ DecorationAliased = 19,
+ DecorationVolatile = 20,
+ DecorationConstant = 21,
+ DecorationCoherent = 22,
+ DecorationNonwritable = 23,
+ DecorationNonreadable = 24,
+ DecorationUniform = 25,
+ DecorationNoStaticUse = 26,
+ DecorationCPacked = 27,
+ DecorationSaturatedConversion = 28,
+ DecorationStream = 29,
+ DecorationLocation = 30,
+ DecorationComponent = 31,
+ DecorationIndex = 32,
+ DecorationBinding = 33,
+ DecorationDescriptorSet = 34,
+ DecorationOffset = 35,
+ DecorationAlignment = 36,
+ DecorationXfbBuffer = 37,
+ DecorationStride = 38,
+ DecorationBuiltIn = 39,
+ DecorationFuncParamAttr = 40,
+ DecorationFPRoundingMode = 41,
+ DecorationFPFastMathMode = 42,
+ DecorationLinkageAttributes = 43,
+ DecorationSpecId = 44,
+};
+
+enum BuiltIn {
+ BuiltInPosition = 0,
+ BuiltInPointSize = 1,
+ BuiltInClipVertex = 2,
+ BuiltInClipDistance = 3,
+ BuiltInCullDistance = 4,
+ BuiltInVertexId = 5,
+ BuiltInInstanceId = 6,
+ BuiltInPrimitiveId = 7,
+ BuiltInInvocationId = 8,
+ BuiltInLayer = 9,
+ BuiltInViewportIndex = 10,
+ BuiltInTessLevelOuter = 11,
+ BuiltInTessLevelInner = 12,
+ BuiltInTessCoord = 13,
+ BuiltInPatchVertices = 14,
+ BuiltInFragCoord = 15,
+ BuiltInPointCoord = 16,
+ BuiltInFrontFacing = 17,
+ BuiltInSampleId = 18,
+ BuiltInSamplePosition = 19,
+ BuiltInSampleMask = 20,
+ BuiltInFragColor = 21,
+ BuiltInFragDepth = 22,
+ BuiltInHelperInvocation = 23,
+ BuiltInNumWorkgroups = 24,
+ BuiltInWorkgroupSize = 25,
+ BuiltInWorkgroupId = 26,
+ BuiltInLocalInvocationId = 27,
+ BuiltInGlobalInvocationId = 28,
+ BuiltInLocalInvocationIndex = 29,
+ BuiltInWorkDim = 30,
+ BuiltInGlobalSize = 31,
+ BuiltInEnqueuedWorkgroupSize = 32,
+ BuiltInGlobalOffset = 33,
+ BuiltInGlobalLinearId = 34,
+ BuiltInWorkgroupLinearId = 35,
+ BuiltInSubgroupSize = 36,
+ BuiltInSubgroupMaxSize = 37,
+ BuiltInNumSubgroups = 38,
+ BuiltInNumEnqueuedSubgroups = 39,
+ BuiltInSubgroupId = 40,
+ BuiltInSubgroupLocalInvocationId = 41,
+};
+
+enum SelectionControlShift {
+ SelectionControlFlattenShift = 0,
+ SelectionControlDontFlattenShift = 1,
+};
+
+enum SelectionControlMask {
+ SelectionControlMaskNone = 0,
+ SelectionControlFlattenMask = 0x00000001,
+ SelectionControlDontFlattenMask = 0x00000002,
+};
+
+enum LoopControlShift {
+ LoopControlUnrollShift = 0,
+ LoopControlDontUnrollShift = 1,
+};
+
+enum LoopControlMask {
+ LoopControlMaskNone = 0,
+ LoopControlUnrollMask = 0x00000001,
+ LoopControlDontUnrollMask = 0x00000002,
+};
+
+enum FunctionControlShift {
+ FunctionControlInlineShift = 0,
+ FunctionControlDontInlineShift = 1,
+ FunctionControlPureShift = 2,
+ FunctionControlConstShift = 3,
+};
+
+enum FunctionControlMask {
+ FunctionControlMaskNone = 0,
+ FunctionControlInlineMask = 0x00000001,
+ FunctionControlDontInlineMask = 0x00000002,
+ FunctionControlPureMask = 0x00000004,
+ FunctionControlConstMask = 0x00000008,
+};
+
+enum MemorySemanticsShift {
+ MemorySemanticsRelaxedShift = 0,
+ MemorySemanticsSequentiallyConsistentShift = 1,
+ MemorySemanticsAcquireShift = 2,
+ MemorySemanticsReleaseShift = 3,
+ MemorySemanticsUniformMemoryShift = 4,
+ MemorySemanticsSubgroupMemoryShift = 5,
+ MemorySemanticsWorkgroupLocalMemoryShift = 6,
+ MemorySemanticsWorkgroupGlobalMemoryShift = 7,
+ MemorySemanticsAtomicCounterMemoryShift = 8,
+ MemorySemanticsImageMemoryShift = 9,
+};
+
+enum MemorySemanticsMask {
+ MemorySemanticsMaskNone = 0,
+ MemorySemanticsRelaxedMask = 0x00000001,
+ MemorySemanticsSequentiallyConsistentMask = 0x00000002,
+ MemorySemanticsAcquireMask = 0x00000004,
+ MemorySemanticsReleaseMask = 0x00000008,
+ MemorySemanticsUniformMemoryMask = 0x00000010,
+ MemorySemanticsSubgroupMemoryMask = 0x00000020,
+ MemorySemanticsWorkgroupLocalMemoryMask = 0x00000040,
+ MemorySemanticsWorkgroupGlobalMemoryMask = 0x00000080,
+ MemorySemanticsAtomicCounterMemoryMask = 0x00000100,
+ MemorySemanticsImageMemoryMask = 0x00000200,
+};
+
+enum MemoryAccessShift {
+ MemoryAccessVolatileShift = 0,
+ MemoryAccessAlignedShift = 1,
+};
+
+enum MemoryAccessMask {
+ MemoryAccessMaskNone = 0,
+ MemoryAccessVolatileMask = 0x00000001,
+ MemoryAccessAlignedMask = 0x00000002,
+};
+
+enum ExecutionScope {
+ ExecutionScopeCrossDevice = 0,
+ ExecutionScopeDevice = 1,
+ ExecutionScopeWorkgroup = 2,
+ ExecutionScopeSubgroup = 3,
+};
+
+enum GroupOperation {
+ GroupOperationReduce = 0,
+ GroupOperationInclusiveScan = 1,
+ GroupOperationExclusiveScan = 2,
+};
+
+enum KernelEnqueueFlags {
+ KernelEnqueueFlagsNoWait = 0,
+ KernelEnqueueFlagsWaitKernel = 1,
+ KernelEnqueueFlagsWaitWorkGroup = 2,
+};
+
+enum KernelProfilingInfoShift {
+ KernelProfilingInfoCmdExecTimeShift = 0,
+};
+
+enum KernelProfilingInfoMask {
+ KernelProfilingInfoMaskNone = 0,
+ KernelProfilingInfoCmdExecTimeMask = 0x00000001,
+};
+
+enum Op {
+ OpNop = 0,
+ OpSource = 1,
+ OpSourceExtension = 2,
+ OpExtension = 3,
+ OpExtInstImport = 4,
+ OpMemoryModel = 5,
+ OpEntryPoint = 6,
+ OpExecutionMode = 7,
+ OpTypeVoid = 8,
+ OpTypeBool = 9,
+ OpTypeInt = 10,
+ OpTypeFloat = 11,
+ OpTypeVector = 12,
+ OpTypeMatrix = 13,
+ OpTypeSampler = 14,
+ OpTypeFilter = 15,
+ OpTypeArray = 16,
+ OpTypeRuntimeArray = 17,
+ OpTypeStruct = 18,
+ OpTypeOpaque = 19,
+ OpTypePointer = 20,
+ OpTypeFunction = 21,
+ OpTypeEvent = 22,
+ OpTypeDeviceEvent = 23,
+ OpTypeReserveId = 24,
+ OpTypeQueue = 25,
+ OpTypePipe = 26,
+ OpConstantTrue = 27,
+ OpConstantFalse = 28,
+ OpConstant = 29,
+ OpConstantComposite = 30,
+ OpConstantSampler = 31,
+ OpConstantNullPointer = 32,
+ OpConstantNullObject = 33,
+ OpSpecConstantTrue = 34,
+ OpSpecConstantFalse = 35,
+ OpSpecConstant = 36,
+ OpSpecConstantComposite = 37,
+ OpVariable = 38,
+ OpVariableArray = 39,
+ OpFunction = 40,
+ OpFunctionParameter = 41,
+ OpFunctionEnd = 42,
+ OpFunctionCall = 43,
+ OpExtInst = 44,
+ OpUndef = 45,
+ OpLoad = 46,
+ OpStore = 47,
+ OpPhi = 48,
+ OpDecorationGroup = 49,
+ OpDecorate = 50,
+ OpMemberDecorate = 51,
+ OpGroupDecorate = 52,
+ OpGroupMemberDecorate = 53,
+ OpName = 54,
+ OpMemberName = 55,
+ OpString = 56,
+ OpLine = 57,
+ OpVectorExtractDynamic = 58,
+ OpVectorInsertDynamic = 59,
+ OpVectorShuffle = 60,
+ OpCompositeConstruct = 61,
+ OpCompositeExtract = 62,
+ OpCompositeInsert = 63,
+ OpCopyObject = 64,
+ OpCopyMemory = 65,
+ OpCopyMemorySized = 66,
+ OpSampler = 67,
+ OpTextureSample = 68,
+ OpTextureSampleDref = 69,
+ OpTextureSampleLod = 70,
+ OpTextureSampleProj = 71,
+ OpTextureSampleGrad = 72,
+ OpTextureSampleOffset = 73,
+ OpTextureSampleProjLod = 74,
+ OpTextureSampleProjGrad = 75,
+ OpTextureSampleLodOffset = 76,
+ OpTextureSampleProjOffset = 77,
+ OpTextureSampleGradOffset = 78,
+ OpTextureSampleProjLodOffset = 79,
+ OpTextureSampleProjGradOffset = 80,
+ OpTextureFetchTexelLod = 81,
+ OpTextureFetchTexelOffset = 82,
+ OpTextureFetchSample = 83,
+ OpTextureFetchTexel = 84,
+ OpTextureGather = 85,
+ OpTextureGatherOffset = 86,
+ OpTextureGatherOffsets = 87,
+ OpTextureQuerySizeLod = 88,
+ OpTextureQuerySize = 89,
+ OpTextureQueryLod = 90,
+ OpTextureQueryLevels = 91,
+ OpTextureQuerySamples = 92,
+ OpAccessChain = 93,
+ OpInBoundsAccessChain = 94,
+ OpSNegate = 95,
+ OpFNegate = 96,
+ OpNot = 97,
+ OpAny = 98,
+ OpAll = 99,
+ OpConvertFToU = 100,
+ OpConvertFToS = 101,
+ OpConvertSToF = 102,
+ OpConvertUToF = 103,
+ OpUConvert = 104,
+ OpSConvert = 105,
+ OpFConvert = 106,
+ OpConvertPtrToU = 107,
+ OpConvertUToPtr = 108,
+ OpPtrCastToGeneric = 109,
+ OpGenericCastToPtr = 110,
+ OpBitcast = 111,
+ OpTranspose = 112,
+ OpIsNan = 113,
+ OpIsInf = 114,
+ OpIsFinite = 115,
+ OpIsNormal = 116,
+ OpSignBitSet = 117,
+ OpLessOrGreater = 118,
+ OpOrdered = 119,
+ OpUnordered = 120,
+ OpArrayLength = 121,
+ OpIAdd = 122,
+ OpFAdd = 123,
+ OpISub = 124,
+ OpFSub = 125,
+ OpIMul = 126,
+ OpFMul = 127,
+ OpUDiv = 128,
+ OpSDiv = 129,
+ OpFDiv = 130,
+ OpUMod = 131,
+ OpSRem = 132,
+ OpSMod = 133,
+ OpFRem = 134,
+ OpFMod = 135,
+ OpVectorTimesScalar = 136,
+ OpMatrixTimesScalar = 137,
+ OpVectorTimesMatrix = 138,
+ OpMatrixTimesVector = 139,
+ OpMatrixTimesMatrix = 140,
+ OpOuterProduct = 141,
+ OpDot = 142,
+ OpShiftRightLogical = 143,
+ OpShiftRightArithmetic = 144,
+ OpShiftLeftLogical = 145,
+ OpLogicalOr = 146,
+ OpLogicalXor = 147,
+ OpLogicalAnd = 148,
+ OpBitwiseOr = 149,
+ OpBitwiseXor = 150,
+ OpBitwiseAnd = 151,
+ OpSelect = 152,
+ OpIEqual = 153,
+ OpFOrdEqual = 154,
+ OpFUnordEqual = 155,
+ OpINotEqual = 156,
+ OpFOrdNotEqual = 157,
+ OpFUnordNotEqual = 158,
+ OpULessThan = 159,
+ OpSLessThan = 160,
+ OpFOrdLessThan = 161,
+ OpFUnordLessThan = 162,
+ OpUGreaterThan = 163,
+ OpSGreaterThan = 164,
+ OpFOrdGreaterThan = 165,
+ OpFUnordGreaterThan = 166,
+ OpULessThanEqual = 167,
+ OpSLessThanEqual = 168,
+ OpFOrdLessThanEqual = 169,
+ OpFUnordLessThanEqual = 170,
+ OpUGreaterThanEqual = 171,
+ OpSGreaterThanEqual = 172,
+ OpFOrdGreaterThanEqual = 173,
+ OpFUnordGreaterThanEqual = 174,
+ OpDPdx = 175,
+ OpDPdy = 176,
+ OpFwidth = 177,
+ OpDPdxFine = 178,
+ OpDPdyFine = 179,
+ OpFwidthFine = 180,
+ OpDPdxCoarse = 181,
+ OpDPdyCoarse = 182,
+ OpFwidthCoarse = 183,
+ OpEmitVertex = 184,
+ OpEndPrimitive = 185,
+ OpEmitStreamVertex = 186,
+ OpEndStreamPrimitive = 187,
+ OpControlBarrier = 188,
+ OpMemoryBarrier = 189,
+ OpImagePointer = 190,
+ OpAtomicInit = 191,
+ OpAtomicLoad = 192,
+ OpAtomicStore = 193,
+ OpAtomicExchange = 194,
+ OpAtomicCompareExchange = 195,
+ OpAtomicCompareExchangeWeak = 196,
+ OpAtomicIIncrement = 197,
+ OpAtomicIDecrement = 198,
+ OpAtomicIAdd = 199,
+ OpAtomicISub = 200,
+ OpAtomicUMin = 201,
+ OpAtomicUMax = 202,
+ OpAtomicAnd = 203,
+ OpAtomicOr = 204,
+ OpAtomicXor = 205,
+ OpLoopMerge = 206,
+ OpSelectionMerge = 207,
+ OpLabel = 208,
+ OpBranch = 209,
+ OpBranchConditional = 210,
+ OpSwitch = 211,
+ OpKill = 212,
+ OpReturn = 213,
+ OpReturnValue = 214,
+ OpUnreachable = 215,
+ OpLifetimeStart = 216,
+ OpLifetimeStop = 217,
+ OpCompileFlag = 218,
+ OpAsyncGroupCopy = 219,
+ OpWaitGroupEvents = 220,
+ OpGroupAll = 221,
+ OpGroupAny = 222,
+ OpGroupBroadcast = 223,
+ OpGroupIAdd = 224,
+ OpGroupFAdd = 225,
+ OpGroupFMin = 226,
+ OpGroupUMin = 227,
+ OpGroupSMin = 228,
+ OpGroupFMax = 229,
+ OpGroupUMax = 230,
+ OpGroupSMax = 231,
+ OpGenericCastToPtrExplicit = 232,
+ OpGenericPtrMemSemantics = 233,
+ OpReadPipe = 234,
+ OpWritePipe = 235,
+ OpReservedReadPipe = 236,
+ OpReservedWritePipe = 237,
+ OpReserveReadPipePackets = 238,
+ OpReserveWritePipePackets = 239,
+ OpCommitReadPipe = 240,
+ OpCommitWritePipe = 241,
+ OpIsValidReserveId = 242,
+ OpGetNumPipePackets = 243,
+ OpGetMaxPipePackets = 244,
+ OpGroupReserveReadPipePackets = 245,
+ OpGroupReserveWritePipePackets = 246,
+ OpGroupCommitReadPipe = 247,
+ OpGroupCommitWritePipe = 248,
+ OpEnqueueMarker = 249,
+ OpEnqueueKernel = 250,
+ OpGetKernelNDrangeSubGroupCount = 251,
+ OpGetKernelNDrangeMaxSubGroupSize = 252,
+ OpGetKernelWorkGroupSize = 253,
+ OpGetKernelPreferredWorkGroupSizeMultiple = 254,
+ OpRetainEvent = 255,
+ OpReleaseEvent = 256,
+ OpCreateUserEvent = 257,
+ OpIsValidEvent = 258,
+ OpSetUserEventStatus = 259,
+ OpCaptureEventProfilingInfo = 260,
+ OpGetDefaultQueue = 261,
+ OpBuildNDRange = 262,
+ OpSatConvertSToU = 263,
+ OpSatConvertUToS = 264,
+ OpAtomicIMin = 265,
+ OpAtomicIMax = 266,
+};
+
+}; // end namespace spv
+
+#endif // #ifdef __cplusplus
+
+
+#ifndef __cplusplus
+
+const int SpvMagicNumber = 0x07230203;
+const int SpvVersion = 99;
+
+typedef unsigned int SpvId;
+
+const unsigned int SpvOpCodeMask = 0xFFFF;
+const unsigned int SpvWordCountShift = 16;
+
+typedef enum SpvSourceLanguage_ {
+ SpvSourceLanguageUnknown = 0,
+ SpvSourceLanguageESSL = 1,
+ SpvSourceLanguageGLSL = 2,
+ SpvSourceLanguageOpenCL = 3,
+} SpvSourceLanguage;
+
+typedef enum SpvExecutionModel_ {
+ SpvExecutionModelVertex = 0,
+ SpvExecutionModelTessellationControl = 1,
+ SpvExecutionModelTessellationEvaluation = 2,
+ SpvExecutionModelGeometry = 3,
+ SpvExecutionModelFragment = 4,
+ SpvExecutionModelGLCompute = 5,
+ SpvExecutionModelKernel = 6,
+} SpvExecutionModel;
+
+typedef enum SpvAddressingModel_ {
+ SpvAddressingModelLogical = 0,
+ SpvAddressingModelPhysical32 = 1,
+ SpvAddressingModelPhysical64 = 2,
+} SpvAddressingModel;
+
+typedef enum SpvMemoryModel_ {
+ SpvMemoryModelSimple = 0,
+ SpvMemoryModelGLSL450 = 1,
+ SpvMemoryModelOpenCL12 = 2,
+ SpvMemoryModelOpenCL20 = 3,
+ SpvMemoryModelOpenCL21 = 4,
+} SpvMemoryModel;
+
+typedef enum SpvExecutionMode_ {
+ SpvExecutionModeInvocations = 0,
+ SpvExecutionModeSpacingEqual = 1,
+ SpvExecutionModeSpacingFractionalEven = 2,
+ SpvExecutionModeSpacingFractionalOdd = 3,
+ SpvExecutionModeVertexOrderCw = 4,
+ SpvExecutionModeVertexOrderCcw = 5,
+ SpvExecutionModePixelCenterInteger = 6,
+ SpvExecutionModeOriginUpperLeft = 7,
+ SpvExecutionModeEarlyFragmentTests = 8,
+ SpvExecutionModePointMode = 9,
+ SpvExecutionModeXfb = 10,
+ SpvExecutionModeDepthReplacing = 11,
+ SpvExecutionModeDepthAny = 12,
+ SpvExecutionModeDepthGreater = 13,
+ SpvExecutionModeDepthLess = 14,
+ SpvExecutionModeDepthUnchanged = 15,
+ SpvExecutionModeLocalSize = 16,
+ SpvExecutionModeLocalSizeHint = 17,
+ SpvExecutionModeInputPoints = 18,
+ SpvExecutionModeInputLines = 19,
+ SpvExecutionModeInputLinesAdjacency = 20,
+ SpvExecutionModeInputTriangles = 21,
+ SpvExecutionModeInputTrianglesAdjacency = 22,
+ SpvExecutionModeInputQuads = 23,
+ SpvExecutionModeInputIsolines = 24,
+ SpvExecutionModeOutputVertices = 25,
+ SpvExecutionModeOutputPoints = 26,
+ SpvExecutionModeOutputLineStrip = 27,
+ SpvExecutionModeOutputTriangleStrip = 28,
+ SpvExecutionModeVecTypeHint = 29,
+ SpvExecutionModeContractionOff = 30,
+} SpvExecutionMode;
+
+typedef enum SpvStorageClass_ {
+ SpvStorageClassUniformConstant = 0,
+ SpvStorageClassInput = 1,
+ SpvStorageClassUniform = 2,
+ SpvStorageClassOutput = 3,
+ SpvStorageClassWorkgroupLocal = 4,
+ SpvStorageClassWorkgroupGlobal = 5,
+ SpvStorageClassPrivateGlobal = 6,
+ SpvStorageClassFunction = 7,
+ SpvStorageClassGeneric = 8,
+ SpvStorageClassPrivate = 9,
+ SpvStorageClassAtomicCounter = 10,
+} SpvStorageClass;
+
+typedef enum SpvDim_ {
+ SpvDim1D = 0,
+ SpvDim2D = 1,
+ SpvDim3D = 2,
+ SpvDimCube = 3,
+ SpvDimRect = 4,
+ SpvDimBuffer = 5,
+} SpvDim;
+
+typedef enum SpvSamplerAddressingMode_ {
+ SpvSamplerAddressingModeNone = 0,
+ SpvSamplerAddressingModeClampToEdge = 1,
+ SpvSamplerAddressingModeClamp = 2,
+ SpvSamplerAddressingModeRepeat = 3,
+ SpvSamplerAddressingModeRepeatMirrored = 4,
+} SpvSamplerAddressingMode;
+
+typedef enum SpvSamplerFilterMode_ {
+ SpvSamplerFilterModeNearest = 0,
+ SpvSamplerFilterModeLinear = 1,
+} SpvSamplerFilterMode;
+
+typedef enum SpvFPFastMathModeShift_ {
+ SpvFPFastMathModeNotNaNShift = 0,
+ SpvFPFastMathModeNotInfShift = 1,
+ SpvFPFastMathModeNSZShift = 2,
+ SpvFPFastMathModeAllowRecipShift = 3,
+ SpvFPFastMathModeFastShift = 4,
+} SpvFPFastMathModeShift;
+
+typedef enum SpvFPFastMathModeMask_ {
+ SpvFPFastMathModeMaskNone = 0,
+ SpvFPFastMathModeNotNaNMask = 0x00000001,
+ SpvFPFastMathModeNotInfMask = 0x00000002,
+ SpvFPFastMathModeNSZMask = 0x00000004,
+ SpvFPFastMathModeAllowRecipMask = 0x00000008,
+ SpvFPFastMathModeFastMask = 0x00000010,
+} SpvFPFastMathModeMask;
+
+typedef enum SpvFPRoundingMode_ {
+ SpvFPRoundingModeRTE = 0,
+ SpvFPRoundingModeRTZ = 1,
+ SpvFPRoundingModeRTP = 2,
+ SpvFPRoundingModeRTN = 3,
+} SpvFPRoundingMode;
+
+typedef enum SpvLinkageType_ {
+ SpvLinkageTypeExport = 0,
+ SpvLinkageTypeImport = 1,
+} SpvLinkageType;
+
+typedef enum SpvAccessQualifier_ {
+ SpvAccessQualifierReadOnly = 0,
+ SpvAccessQualifierWriteOnly = 1,
+ SpvAccessQualifierReadWrite = 2,
+} SpvAccessQualifier;
+
+typedef enum SpvFunctionParameterAttribute_ {
+ SpvFunctionParameterAttributeZext = 0,
+ SpvFunctionParameterAttributeSext = 1,
+ SpvFunctionParameterAttributeByVal = 2,
+ SpvFunctionParameterAttributeSret = 3,
+ SpvFunctionParameterAttributeNoAlias = 4,
+ SpvFunctionParameterAttributeNoCapture = 5,
+ SpvFunctionParameterAttributeSVM = 6,
+ SpvFunctionParameterAttributeNoWrite = 7,
+ SpvFunctionParameterAttributeNoReadWrite = 8,
+} SpvFunctionParameterAttribute;
+
+typedef enum SpvDecoration_ {
+ SpvDecorationPrecisionLow = 0,
+ SpvDecorationPrecisionMedium = 1,
+ SpvDecorationPrecisionHigh = 2,
+ SpvDecorationBlock = 3,
+ SpvDecorationBufferBlock = 4,
+ SpvDecorationRowMajor = 5,
+ SpvDecorationColMajor = 6,
+ SpvDecorationGLSLShared = 7,
+ SpvDecorationGLSLStd140 = 8,
+ SpvDecorationGLSLStd430 = 9,
+ SpvDecorationGLSLPacked = 10,
+ SpvDecorationSmooth = 11,
+ SpvDecorationNoperspective = 12,
+ SpvDecorationFlat = 13,
+ SpvDecorationPatch = 14,
+ SpvDecorationCentroid = 15,
+ SpvDecorationSample = 16,
+ SpvDecorationInvariant = 17,
+ SpvDecorationRestrict = 18,
+ SpvDecorationAliased = 19,
+ SpvDecorationVolatile = 20,
+ SpvDecorationConstant = 21,
+ SpvDecorationCoherent = 22,
+ SpvDecorationNonwritable = 23,
+ SpvDecorationNonreadable = 24,
+ SpvDecorationUniform = 25,
+ SpvDecorationNoStaticUse = 26,
+ SpvDecorationCPacked = 27,
+ SpvDecorationSaturatedConversion = 28,
+ SpvDecorationStream = 29,
+ SpvDecorationLocation = 30,
+ SpvDecorationComponent = 31,
+ SpvDecorationIndex = 32,
+ SpvDecorationBinding = 33,
+ SpvDecorationDescriptorSet = 34,
+ SpvDecorationOffset = 35,
+ SpvDecorationAlignment = 36,
+ SpvDecorationXfbBuffer = 37,
+ SpvDecorationStride = 38,
+ SpvDecorationBuiltIn = 39,
+ SpvDecorationFuncParamAttr = 40,
+ SpvDecorationFPRoundingMode = 41,
+ SpvDecorationFPFastMathMode = 42,
+ SpvDecorationLinkageAttributes = 43,
+ SpvDecorationSpecId = 44,
+} SpvDecoration;
+
+typedef enum SpvBuiltIn_ {
+ SpvBuiltInPosition = 0,
+ SpvBuiltInPointSize = 1,
+ SpvBuiltInClipVertex = 2,
+ SpvBuiltInClipDistance = 3,
+ SpvBuiltInCullDistance = 4,
+ SpvBuiltInVertexId = 5,
+ SpvBuiltInInstanceId = 6,
+ SpvBuiltInPrimitiveId = 7,
+ SpvBuiltInInvocationId = 8,
+ SpvBuiltInLayer = 9,
+ SpvBuiltInViewportIndex = 10,
+ SpvBuiltInTessLevelOuter = 11,
+ SpvBuiltInTessLevelInner = 12,
+ SpvBuiltInTessCoord = 13,
+ SpvBuiltInPatchVertices = 14,
+ SpvBuiltInFragCoord = 15,
+ SpvBuiltInPointCoord = 16,
+ SpvBuiltInFrontFacing = 17,
+ SpvBuiltInSampleId = 18,
+ SpvBuiltInSamplePosition = 19,
+ SpvBuiltInSampleMask = 20,
+ SpvBuiltInFragColor = 21,
+ SpvBuiltInFragDepth = 22,
+ SpvBuiltInHelperInvocation = 23,
+ SpvBuiltInNumWorkgroups = 24,
+ SpvBuiltInWorkgroupSize = 25,
+ SpvBuiltInWorkgroupId = 26,
+ SpvBuiltInLocalInvocationId = 27,
+ SpvBuiltInGlobalInvocationId = 28,
+ SpvBuiltInLocalInvocationIndex = 29,
+ SpvBuiltInWorkDim = 30,
+ SpvBuiltInGlobalSize = 31,
+ SpvBuiltInEnqueuedWorkgroupSize = 32,
+ SpvBuiltInGlobalOffset = 33,
+ SpvBuiltInGlobalLinearId = 34,
+ SpvBuiltInWorkgroupLinearId = 35,
+ SpvBuiltInSubgroupSize = 36,
+ SpvBuiltInSubgroupMaxSize = 37,
+ SpvBuiltInNumSubgroups = 38,
+ SpvBuiltInNumEnqueuedSubgroups = 39,
+ SpvBuiltInSubgroupId = 40,
+ SpvBuiltInSubgroupLocalInvocationId = 41,
+} SpvBuiltIn;
+
+typedef enum SpvSelectionControlShift_ {
+ SpvSelectionControlFlattenShift = 0,
+ SpvSelectionControlDontFlattenShift = 1,
+} SpvSelectionControlShift;
+
+typedef enum SpvSelectionControlMask_ {
+ SpvSelectionControlMaskNone = 0,
+ SpvSelectionControlFlattenMask = 0x00000001,
+ SpvSelectionControlDontFlattenMask = 0x00000002,
+} SpvSelectionControlMask;
+
+typedef enum SpvLoopControlShift_ {
+ SpvLoopControlUnrollShift = 0,
+ SpvLoopControlDontUnrollShift = 1,
+} SpvLoopControlShift;
+
+typedef enum SpvLoopControlMask_ {
+ SpvLoopControlMaskNone = 0,
+ SpvLoopControlUnrollMask = 0x00000001,
+ SpvLoopControlDontUnrollMask = 0x00000002,
+} SpvLoopControlMask;
+
+typedef enum SpvFunctionControlShift_ {
+ SpvFunctionControlInlineShift = 0,
+ SpvFunctionControlDontInlineShift = 1,
+ SpvFunctionControlPureShift = 2,
+ SpvFunctionControlConstShift = 3,
+} SpvFunctionControlShift;
+
+typedef enum SpvFunctionControlMask_ {
+ SpvFunctionControlMaskNone = 0,
+ SpvFunctionControlInlineMask = 0x00000001,
+ SpvFunctionControlDontInlineMask = 0x00000002,
+ SpvFunctionControlPureMask = 0x00000004,
+ SpvFunctionControlConstMask = 0x00000008,
+} SpvFunctionControlMask;
+
+typedef enum SpvMemorySemanticsShift_ {
+ SpvMemorySemanticsRelaxedShift = 0,
+ SpvMemorySemanticsSequentiallyConsistentShift = 1,
+ SpvMemorySemanticsAcquireShift = 2,
+ SpvMemorySemanticsReleaseShift = 3,
+ SpvMemorySemanticsUniformMemoryShift = 4,
+ SpvMemorySemanticsSubgroupMemoryShift = 5,
+ SpvMemorySemanticsWorkgroupLocalMemoryShift = 6,
+ SpvMemorySemanticsWorkgroupGlobalMemoryShift = 7,
+ SpvMemorySemanticsAtomicCounterMemoryShift = 8,
+ SpvMemorySemanticsImageMemoryShift = 9,
+} SpvMemorySemanticsShift;
+
+typedef enum SpvMemorySemanticsMask_ {
+ SpvMemorySemanticsMaskNone = 0,
+ SpvMemorySemanticsRelaxedMask = 0x00000001,
+ SpvMemorySemanticsSequentiallyConsistentMask = 0x00000002,
+ SpvMemorySemanticsAcquireMask = 0x00000004,
+ SpvMemorySemanticsReleaseMask = 0x00000008,
+ SpvMemorySemanticsUniformMemoryMask = 0x00000010,
+ SpvMemorySemanticsSubgroupMemoryMask = 0x00000020,
+ SpvMemorySemanticsWorkgroupLocalMemoryMask = 0x00000040,
+ SpvMemorySemanticsWorkgroupGlobalMemoryMask = 0x00000080,
+ SpvMemorySemanticsAtomicCounterMemoryMask = 0x00000100,
+ SpvMemorySemanticsImageMemoryMask = 0x00000200,
+} SpvMemorySemanticsMask;
+
+typedef enum SpvMemoryAccessShift_ {
+ SpvMemoryAccessVolatileShift = 0,
+ SpvMemoryAccessAlignedShift = 1,
+} SpvMemoryAccessShift;
+
+typedef enum SpvMemoryAccessMask_ {
+ SpvMemoryAccessMaskNone = 0,
+ SpvMemoryAccessVolatileMask = 0x00000001,
+ SpvMemoryAccessAlignedMask = 0x00000002,
+} SpvMemoryAccessMask;
+
+typedef enum SpvExecutionScope_ {
+ SpvExecutionScopeCrossDevice = 0,
+ SpvExecutionScopeDevice = 1,
+ SpvExecutionScopeWorkgroup = 2,
+ SpvExecutionScopeSubgroup = 3,
+} SpvExecutionScope;
+
+typedef enum SpvGroupOperation_ {
+ SpvGroupOperationReduce = 0,
+ SpvGroupOperationInclusiveScan = 1,
+ SpvGroupOperationExclusiveScan = 2,
+} SpvGroupOperation;
+
+typedef enum SpvKernelEnqueueFlags_ {
+ SpvKernelEnqueueFlagsNoWait = 0,
+ SpvKernelEnqueueFlagsWaitKernel = 1,
+ SpvKernelEnqueueFlagsWaitWorkGroup = 2,
+} SpvKernelEnqueueFlags;
+
+typedef enum SpvKernelProfilingInfoShift_ {
+ SpvKernelProfilingInfoCmdExecTimeShift = 0,
+} SpvKernelProfilingInfoShift;
+
+typedef enum SpvKernelProfilingInfoMask_ {
+ SpvKernelProfilingInfoMaskNone = 0,
+ SpvKernelProfilingInfoCmdExecTimeMask = 0x00000001,
+} SpvKernelProfilingInfoMask;
+
+typedef enum SpvOp_ {
+ SpvOpNop = 0,
+ SpvOpSource = 1,
+ SpvOpSourceExtension = 2,
+ SpvOpExtension = 3,
+ SpvOpExtInstImport = 4,
+ SpvOpMemoryModel = 5,
+ SpvOpEntryPoint = 6,
+ SpvOpExecutionMode = 7,
+ SpvOpTypeVoid = 8,
+ SpvOpTypeBool = 9,
+ SpvOpTypeInt = 10,
+ SpvOpTypeFloat = 11,
+ SpvOpTypeVector = 12,
+ SpvOpTypeMatrix = 13,
+ SpvOpTypeSampler = 14,
+ SpvOpTypeFilter = 15,
+ SpvOpTypeArray = 16,
+ SpvOpTypeRuntimeArray = 17,
+ SpvOpTypeStruct = 18,
+ SpvOpTypeOpaque = 19,
+ SpvOpTypePointer = 20,
+ SpvOpTypeFunction = 21,
+ SpvOpTypeEvent = 22,
+ SpvOpTypeDeviceEvent = 23,
+ SpvOpTypeReserveId = 24,
+ SpvOpTypeQueue = 25,
+ SpvOpTypePipe = 26,
+ SpvOpConstantTrue = 27,
+ SpvOpConstantFalse = 28,
+ SpvOpConstant = 29,
+ SpvOpConstantComposite = 30,
+ SpvOpConstantSampler = 31,
+ SpvOpConstantNullPointer = 32,
+ SpvOpConstantNullObject = 33,
+ SpvOpSpecConstantTrue = 34,
+ SpvOpSpecConstantFalse = 35,
+ SpvOpSpecConstant = 36,
+ SpvOpSpecConstantComposite = 37,
+ SpvOpVariable = 38,
+ SpvOpVariableArray = 39,
+ SpvOpFunction = 40,
+ SpvOpFunctionParameter = 41,
+ SpvOpFunctionEnd = 42,
+ SpvOpFunctionCall = 43,
+ SpvOpExtInst = 44,
+ SpvOpUndef = 45,
+ SpvOpLoad = 46,
+ SpvOpStore = 47,
+ SpvOpPhi = 48,
+ SpvOpDecorationGroup = 49,
+ SpvOpDecorate = 50,
+ SpvOpMemberDecorate = 51,
+ SpvOpGroupDecorate = 52,
+ SpvOpGroupMemberDecorate = 53,
+ SpvOpName = 54,
+ SpvOpMemberName = 55,
+ SpvOpString = 56,
+ SpvOpLine = 57,
+ SpvOpVectorExtractDynamic = 58,
+ SpvOpVectorInsertDynamic = 59,
+ SpvOpVectorShuffle = 60,
+ SpvOpCompositeConstruct = 61,
+ SpvOpCompositeExtract = 62,
+ SpvOpCompositeInsert = 63,
+ SpvOpCopyObject = 64,
+ SpvOpCopyMemory = 65,
+ SpvOpCopyMemorySized = 66,
+ SpvOpSampler = 67,
+ SpvOpTextureSample = 68,
+ SpvOpTextureSampleDref = 69,
+ SpvOpTextureSampleLod = 70,
+ SpvOpTextureSampleProj = 71,
+ SpvOpTextureSampleGrad = 72,
+ SpvOpTextureSampleOffset = 73,
+ SpvOpTextureSampleProjLod = 74,
+ SpvOpTextureSampleProjGrad = 75,
+ SpvOpTextureSampleLodOffset = 76,
+ SpvOpTextureSampleProjOffset = 77,
+ SpvOpTextureSampleGradOffset = 78,
+ SpvOpTextureSampleProjLodOffset = 79,
+ SpvOpTextureSampleProjGradOffset = 80,
+ SpvOpTextureFetchTexelLod = 81,
+ SpvOpTextureFetchTexelOffset = 82,
+ SpvOpTextureFetchSample = 83,
+ SpvOpTextureFetchTexel = 84,
+ SpvOpTextureGather = 85,
+ SpvOpTextureGatherOffset = 86,
+ SpvOpTextureGatherOffsets = 87,
+ SpvOpTextureQuerySizeLod = 88,
+ SpvOpTextureQuerySize = 89,
+ SpvOpTextureQueryLod = 90,
+ SpvOpTextureQueryLevels = 91,
+ SpvOpTextureQuerySamples = 92,
+ SpvOpAccessChain = 93,
+ SpvOpInBoundsAccessChain = 94,
+ SpvOpSNegate = 95,
+ SpvOpFNegate = 96,
+ SpvOpNot = 97,
+ SpvOpAny = 98,
+ SpvOpAll = 99,
+ SpvOpConvertFToU = 100,
+ SpvOpConvertFToS = 101,
+ SpvOpConvertSToF = 102,
+ SpvOpConvertUToF = 103,
+ SpvOpUConvert = 104,
+ SpvOpSConvert = 105,
+ SpvOpFConvert = 106,
+ SpvOpConvertPtrToU = 107,
+ SpvOpConvertUToPtr = 108,
+ SpvOpPtrCastToGeneric = 109,
+ SpvOpGenericCastToPtr = 110,
+ SpvOpBitcast = 111,
+ SpvOpTranspose = 112,
+ SpvOpIsNan = 113,
+ SpvOpIsInf = 114,
+ SpvOpIsFinite = 115,
+ SpvOpIsNormal = 116,
+ SpvOpSignBitSet = 117,
+ SpvOpLessOrGreater = 118,
+ SpvOpOrdered = 119,
+ SpvOpUnordered = 120,
+ SpvOpArrayLength = 121,
+ SpvOpIAdd = 122,
+ SpvOpFAdd = 123,
+ SpvOpISub = 124,
+ SpvOpFSub = 125,
+ SpvOpIMul = 126,
+ SpvOpFMul = 127,
+ SpvOpUDiv = 128,
+ SpvOpSDiv = 129,
+ SpvOpFDiv = 130,
+ SpvOpUMod = 131,
+ SpvOpSRem = 132,
+ SpvOpSMod = 133,
+ SpvOpFRem = 134,
+ SpvOpFMod = 135,
+ SpvOpVectorTimesScalar = 136,
+ SpvOpMatrixTimesScalar = 137,
+ SpvOpVectorTimesMatrix = 138,
+ SpvOpMatrixTimesVector = 139,
+ SpvOpMatrixTimesMatrix = 140,
+ SpvOpOuterProduct = 141,
+ SpvOpDot = 142,
+ SpvOpShiftRightLogical = 143,
+ SpvOpShiftRightArithmetic = 144,
+ SpvOpShiftLeftLogical = 145,
+ SpvOpLogicalOr = 146,
+ SpvOpLogicalXor = 147,
+ SpvOpLogicalAnd = 148,
+ SpvOpBitwiseOr = 149,
+ SpvOpBitwiseXor = 150,
+ SpvOpBitwiseAnd = 151,
+ SpvOpSelect = 152,
+ SpvOpIEqual = 153,
+ SpvOpFOrdEqual = 154,
+ SpvOpFUnordEqual = 155,
+ SpvOpINotEqual = 156,
+ SpvOpFOrdNotEqual = 157,
+ SpvOpFUnordNotEqual = 158,
+ SpvOpULessThan = 159,
+ SpvOpSLessThan = 160,
+ SpvOpFOrdLessThan = 161,
+ SpvOpFUnordLessThan = 162,
+ SpvOpUGreaterThan = 163,
+ SpvOpSGreaterThan = 164,
+ SpvOpFOrdGreaterThan = 165,
+ SpvOpFUnordGreaterThan = 166,
+ SpvOpULessThanEqual = 167,
+ SpvOpSLessThanEqual = 168,
+ SpvOpFOrdLessThanEqual = 169,
+ SpvOpFUnordLessThanEqual = 170,
+ SpvOpUGreaterThanEqual = 171,
+ SpvOpSGreaterThanEqual = 172,
+ SpvOpFOrdGreaterThanEqual = 173,
+ SpvOpFUnordGreaterThanEqual = 174,
+ SpvOpDPdx = 175,
+ SpvOpDPdy = 176,
+ SpvOpFwidth = 177,
+ SpvOpDPdxFine = 178,
+ SpvOpDPdyFine = 179,
+ SpvOpFwidthFine = 180,
+ SpvOpDPdxCoarse = 181,
+ SpvOpDPdyCoarse = 182,
+ SpvOpFwidthCoarse = 183,
+ SpvOpEmitVertex = 184,
+ SpvOpEndPrimitive = 185,
+ SpvOpEmitStreamVertex = 186,
+ SpvOpEndStreamPrimitive = 187,
+ SpvOpControlBarrier = 188,
+ SpvOpMemoryBarrier = 189,
+ SpvOpImagePointer = 190,
+ SpvOpAtomicInit = 191,
+ SpvOpAtomicLoad = 192,
+ SpvOpAtomicStore = 193,
+ SpvOpAtomicExchange = 194,
+ SpvOpAtomicCompareExchange = 195,
+ SpvOpAtomicCompareExchangeWeak = 196,
+ SpvOpAtomicIIncrement = 197,
+ SpvOpAtomicIDecrement = 198,
+ SpvOpAtomicIAdd = 199,
+ SpvOpAtomicISub = 200,
+ SpvOpAtomicUMin = 201,
+ SpvOpAtomicUMax = 202,
+ SpvOpAtomicAnd = 203,
+ SpvOpAtomicOr = 204,
+ SpvOpAtomicXor = 205,
+ SpvOpLoopMerge = 206,
+ SpvOpSelectionMerge = 207,
+ SpvOpLabel = 208,
+ SpvOpBranch = 209,
+ SpvOpBranchConditional = 210,
+ SpvOpSwitch = 211,
+ SpvOpKill = 212,
+ SpvOpReturn = 213,
+ SpvOpReturnValue = 214,
+ SpvOpUnreachable = 215,
+ SpvOpLifetimeStart = 216,
+ SpvOpLifetimeStop = 217,
+ SpvOpCompileFlag = 218,
+ SpvOpAsyncGroupCopy = 219,
+ SpvOpWaitGroupEvents = 220,
+ SpvOpGroupAll = 221,
+ SpvOpGroupAny = 222,
+ SpvOpGroupBroadcast = 223,
+ SpvOpGroupIAdd = 224,
+ SpvOpGroupFAdd = 225,
+ SpvOpGroupFMin = 226,
+ SpvOpGroupUMin = 227,
+ SpvOpGroupSMin = 228,
+ SpvOpGroupFMax = 229,
+ SpvOpGroupUMax = 230,
+ SpvOpGroupSMax = 231,
+ SpvOpGenericCastToPtrExplicit = 232,
+ SpvOpGenericPtrMemSemantics = 233,
+ SpvOpReadPipe = 234,
+ SpvOpWritePipe = 235,
+ SpvOpReservedReadPipe = 236,
+ SpvOpReservedWritePipe = 237,
+ SpvOpReserveReadPipePackets = 238,
+ SpvOpReserveWritePipePackets = 239,
+ SpvOpCommitReadPipe = 240,
+ SpvOpCommitWritePipe = 241,
+ SpvOpIsValidReserveId = 242,
+ SpvOpGetNumPipePackets = 243,
+ SpvOpGetMaxPipePackets = 244,
+ SpvOpGroupReserveReadPipePackets = 245,
+ SpvOpGroupReserveWritePipePackets = 246,
+ SpvOpGroupCommitReadPipe = 247,
+ SpvOpGroupCommitWritePipe = 248,
+ SpvOpEnqueueMarker = 249,
+ SpvOpEnqueueKernel = 250,
+ SpvOpGetKernelNDrangeSubGroupCount = 251,
+ SpvOpGetKernelNDrangeMaxSubGroupSize = 252,
+ SpvOpGetKernelWorkGroupSize = 253,
+ SpvOpGetKernelPreferredWorkGroupSizeMultiple = 254,
+ SpvOpRetainEvent = 255,
+ SpvOpReleaseEvent = 256,
+ SpvOpCreateUserEvent = 257,
+ SpvOpIsValidEvent = 258,
+ SpvOpSetUserEventStatus = 259,
+ SpvOpCaptureEventProfilingInfo = 260,
+ SpvOpGetDefaultQueue = 261,
+ SpvOpBuildNDRange = 262,
+ SpvOpSatConvertSToU = 263,
+ SpvOpSatConvertUToS = 264,
+ SpvOpAtomicIMin = 265,
+ SpvOpAtomicIMax = 266,
+} SpvOp;
+
+#endif // #ifndef __cplusplus
+
+#endif // #ifndef spirv_H
-//\r
-//Copyright (C) 2014 LunarG, Inc.\r
-//\r
-//All rights reserved.\r
-//\r
-//Redistribution and use in source and binary forms, with or without\r
-//modification, are permitted provided that the following conditions\r
-//are met:\r
-//\r
-// Redistributions of source code must retain the above copyright\r
-// notice, this list of conditions and the following disclaimer.\r
-//\r
-// Redistributions in binary form must reproduce the above\r
-// copyright notice, this list of conditions and the following\r
-// disclaimer in the documentation and/or other materials provided\r
-// with the distribution.\r
-//\r
-// Neither the name of 3Dlabs Inc. Ltd. nor the names of its\r
-// contributors may be used to endorse or promote products derived\r
-// from this software without specific prior written permission.\r
-//\r
-//THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\r
-//"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\r
-//LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS\r
-//FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE\r
-//COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,\r
-//INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,\r
-//BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\r
-//LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER\r
-//CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\r
-//LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN\r
-//ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE\r
-//POSSIBILITY OF SUCH DAMAGE.\r
-\r
-//\r
-// Author: John Kessenich, LunarG\r
-//\r
-\r
-// SPIRV-IR\r
-//\r
-// Simple in-memory representation (IR) of SPIRV. Just for holding\r
-// Each function's CFG of blocks. Has this hierarchy:\r
-// - Module, which is a list of \r
-// - Function, which is a list of \r
-// - Block, which is a list of \r
-// - Instruction\r
-//\r
-\r
-#pragma once\r
-#ifndef spvIR_H\r
-#define spvIR_H\r
-\r
-#include "spirv.h"\r
-\r
-#include <vector>\r
-#include <iostream>\r
-#include <assert.h>\r
-\r
-namespace spv {\r
-\r
-class Function;\r
-class Module;\r
-\r
-const Id NoResult = 0;\r
-const Id NoType = 0;\r
-\r
-const unsigned int BadValue = 0xFFFFFFFF;\r
-const Decoration NoPrecision = (Decoration)BadValue;\r
-const MemorySemanticsMask MemorySemanticsAllMemory = (MemorySemanticsMask)0x3FF;\r
-\r
-//\r
-// SPIR-V IR instruction.\r
-//\r
-\r
-class Instruction {\r
-public:\r
- Instruction(Id resultId, Id typeId, Op opCode) : resultId(resultId), typeId(typeId), opCode(opCode), string(0) { }\r
- explicit Instruction(Op opCode) : resultId(NoResult), typeId(NoType), opCode(opCode), string(0) { }\r
- virtual ~Instruction()\r
- {\r
- delete string;\r
- }\r
- void addIdOperand(Id id) { operands.push_back(id); }\r
- void addImmediateOperand(unsigned int immediate) { operands.push_back(immediate); }\r
- void addStringOperand(const char* str)\r
- {\r
- originalString = str;\r
- string = new std::vector<unsigned int>;\r
- unsigned int word;\r
- char* wordString = (char*)&word;\r
- char* wordPtr = wordString;\r
- int charCount = 0;\r
- char c;\r
- do {\r
- c = *(str++);\r
- *(wordPtr++) = c;\r
- ++charCount;\r
- if (charCount == 4) {\r
- string->push_back(word);\r
- wordPtr = wordString;\r
- charCount = 0;\r
- }\r
- } while (c != 0);\r
-\r
- // deal with partial last word\r
- if (charCount > 0) {\r
- // pad with 0s\r
- for (; charCount < 4; ++charCount)\r
- *(wordPtr++) = 0;\r
- string->push_back(word);\r
- }\r
- }\r
- Op getOpCode() const { return opCode; }\r
- int getNumOperands() const { return (int)operands.size(); }\r
- Id getResultId() const { return resultId; }\r
- Id getTypeId() const { return typeId; }\r
- Id getIdOperand(int op) const { return operands[op]; }\r
- unsigned int getImmediateOperand(int op) const { return operands[op]; }\r
- const char* getStringOperand() const { return originalString.c_str(); }\r
-\r
- // Write out the binary form.\r
- void dump(std::vector<unsigned int>& out) const\r
- {\r
- // Compute the wordCount\r
- unsigned int wordCount = 1;\r
- if (typeId)\r
- ++wordCount;\r
- if (resultId)\r
- ++wordCount;\r
- wordCount += (unsigned int)operands.size();\r
- if (string)\r
- wordCount += (unsigned int)string->size();\r
-\r
- // Write out the beginning of the instruction\r
- out.push_back(((wordCount) << WordCountShift) | opCode);\r
- if (typeId)\r
- out.push_back(typeId);\r
- if (resultId)\r
- out.push_back(resultId);\r
-\r
- // Write out the operands\r
- for (int op = 0; op < (int)operands.size(); ++op)\r
- out.push_back(operands[op]);\r
- if (string)\r
- for (int op = 0; op < (int)string->size(); ++op)\r
- out.push_back((*string)[op]);\r
- }\r
-\r
-protected:\r
- Instruction(const Instruction&);\r
- Id resultId;\r
- Id typeId;\r
- Op opCode;\r
- std::vector<Id> operands;\r
- std::vector<unsigned int>* string; // usually non-existent\r
- std::string originalString; // could be optimized away; convenience for getting string operand\r
-};\r
-\r
-//\r
-// SPIR-V IR block.\r
-//\r
-\r
-class Block {\r
-public:\r
- Block(Id id, Function& parent);\r
- virtual ~Block()\r
- {\r
- // TODO: free instructions\r
- }\r
- \r
- Id getId() { return instructions.front()->getResultId(); }\r
-\r
- Function& getParent() const { return parent; }\r
- void addInstruction(Instruction* inst);\r
- void addPredecessor(Block* pred) { predecessors.push_back(pred); }\r
- void addLocalVariable(Instruction* inst) { localVariables.push_back(inst); }\r
- int getNumPredecessors() const { return (int)predecessors.size(); }\r
- void setUnreachable() { unreachable = true; }\r
- bool isUnreachable() const { return unreachable; }\r
-\r
- bool isTerminated() const\r
- {\r
- switch (instructions.back()->getOpCode()) {\r
- case OpBranch:\r
- case OpBranchConditional:\r
- case OpSwitch:\r
- case OpKill:\r
- case OpReturn:\r
- case OpReturnValue:\r
- return true;\r
- default:\r
- return false;\r
- }\r
- }\r
-\r
- void dump(std::vector<unsigned int>& out) const\r
- {\r
- // skip the degenerate unreachable blocks\r
- // TODO: code gen: skip all unreachable blocks (transitive closure)\r
- // (but, until that's done safer to keep non-degenerate unreachable blocks, in case others depend on something)\r
- if (unreachable && instructions.size() <= 2)\r
- return;\r
-\r
- instructions[0]->dump(out);\r
- for (int i = 0; i < (int)localVariables.size(); ++i)\r
- localVariables[i]->dump(out);\r
- for (int i = 1; i < (int)instructions.size(); ++i)\r
- instructions[i]->dump(out);\r
- }\r
-\r
-protected:\r
- Block(const Block&);\r
- Block& operator=(Block&);\r
-\r
- // To enforce keeping parent and ownership in sync:\r
- friend Function;\r
-\r
- std::vector<Instruction*> instructions;\r
- std::vector<Block*> predecessors;\r
- std::vector<Instruction*> localVariables;\r
- Function& parent;\r
-\r
- // track whether this block is known to be uncreachable (not necessarily \r
- // true for all unreachable blocks, but should be set at least\r
- // for the extraneous ones introduced by the builder).\r
- bool unreachable;\r
-};\r
-\r
-//\r
-// SPIR-V IR Function.\r
-//\r
-\r
-class Function {\r
-public:\r
- Function(Id id, Id resultType, Id functionType, Id firstParam, Module& parent);\r
- virtual ~Function()\r
- {\r
- for (int i = 0; i < (int)parameterInstructions.size(); ++i)\r
- delete parameterInstructions[i];\r
-\r
- for (int i = 0; i < (int)blocks.size(); ++i)\r
- delete blocks[i];\r
- }\r
- Id getId() const { return functionInstruction.getResultId(); }\r
- Id getParamId(int p) { return parameterInstructions[p]->getResultId(); }\r
-\r
- void addBlock(Block* block) { blocks.push_back(block); }\r
- void popBlock(Block*) { blocks.pop_back(); }\r
-\r
- Module& getParent() const { return parent; }\r
- Block* getEntryBlock() const { return blocks.front(); }\r
- Block* getLastBlock() const { return blocks.back(); }\r
- void addLocalVariable(Instruction* inst);\r
- Id getReturnType() const { return functionInstruction.getTypeId(); }\r
- void dump(std::vector<unsigned int>& out) const\r
- {\r
- // OpFunction\r
- functionInstruction.dump(out);\r
-\r
- // OpFunctionParameter\r
- for (int p = 0; p < (int)parameterInstructions.size(); ++p)\r
- parameterInstructions[p]->dump(out);\r
-\r
- // Blocks\r
- for (int b = 0; b < (int)blocks.size(); ++b)\r
- blocks[b]->dump(out);\r
- Instruction end(0, 0, OpFunctionEnd);\r
- end.dump(out);\r
- }\r
-\r
-protected:\r
- Function(const Function&);\r
- Function& operator=(Function&);\r
-\r
- Module& parent;\r
- Instruction functionInstruction;\r
- std::vector<Instruction*> parameterInstructions;\r
- std::vector<Block*> blocks;\r
-};\r
-\r
-//\r
-// SPIR-V IR Module.\r
-//\r
-\r
-class Module {\r
-public:\r
- Module() {}\r
- virtual ~Module()\r
- {\r
- // TODO delete things\r
- }\r
-\r
- void addFunction(Function *fun) { functions.push_back(fun); }\r
-\r
- void mapInstruction(Instruction *instruction)\r
- {\r
- spv::Id resultId = instruction->getResultId();\r
- // map the instruction's result id\r
- if (resultId >= idToInstruction.size())\r
- idToInstruction.resize(resultId + 16);\r
- idToInstruction[resultId] = instruction;\r
- }\r
-\r
- Instruction* getInstruction(Id id) const { return idToInstruction[id]; }\r
- spv::Id getTypeId(Id resultId) const { return idToInstruction[resultId]->getTypeId(); }\r
- StorageClass getStorageClass(Id typeId) const { return (StorageClass)idToInstruction[typeId]->getImmediateOperand(0); }\r
- void dump(std::vector<unsigned int>& out) const\r
- {\r
- for (int f = 0; f < (int)functions.size(); ++f)\r
- functions[f]->dump(out);\r
- }\r
-\r
-protected:\r
- Module(const Module&);\r
- std::vector<Function*> functions;\r
-\r
- // map from result id to instruction having that result id\r
- std::vector<Instruction*> idToInstruction;\r
-\r
- // map from a result id to its type id\r
-};\r
-\r
-//\r
-// Implementation (it's here due to circular type definitions).\r
-//\r
-\r
-// Add both\r
-// - the OpFunction instruction\r
-// - all the OpFunctionParameter instructions\r
-__inline Function::Function(Id id, Id resultType, Id functionType, Id firstParamId, Module& parent)\r
- : parent(parent), functionInstruction(id, resultType, OpFunction)\r
-{\r
- // OpFunction\r
- functionInstruction.addImmediateOperand(FunctionControlMaskNone);\r
- functionInstruction.addIdOperand(functionType);\r
- parent.mapInstruction(&functionInstruction);\r
- parent.addFunction(this);\r
-\r
- // OpFunctionParameter\r
- Instruction* typeInst = parent.getInstruction(functionType);\r
- int numParams = typeInst->getNumOperands() - 1;\r
- for (int p = 0; p < numParams; ++p) {\r
- Instruction* param = new Instruction(firstParamId + p, typeInst->getIdOperand(p + 1), OpFunctionParameter);\r
- parent.mapInstruction(param);\r
- parameterInstructions.push_back(param);\r
- }\r
-}\r
-\r
-__inline void Function::addLocalVariable(Instruction* inst)\r
-{\r
- blocks[0]->addLocalVariable(inst);\r
- parent.mapInstruction(inst);\r
-}\r
-\r
-__inline Block::Block(Id id, Function& parent) : parent(parent), unreachable(false)\r
-{\r
- instructions.push_back(new Instruction(id, NoType, OpLabel));\r
-}\r
-\r
-__inline void Block::addInstruction(Instruction* inst)\r
-{\r
- instructions.push_back(inst);\r
- if (inst->getResultId())\r
- parent.getParent().mapInstruction(inst);\r
-}\r
-\r
-}; // end spv namespace\r
-\r
-#endif // spvIR_H\r
+//
+//Copyright (C) 2014 LunarG, Inc.
+//
+//All rights reserved.
+//
+//Redistribution and use in source and binary forms, with or without
+//modification, are permitted provided that the following conditions
+//are met:
+//
+// Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//
+// Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following
+// disclaimer in the documentation and/or other materials provided
+// with the distribution.
+//
+// Neither the name of 3Dlabs Inc. Ltd. nor the names of its
+// contributors may be used to endorse or promote products derived
+// from this software without specific prior written permission.
+//
+//THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+//"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+//LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+//FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+//COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+//INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+//BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+//LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+//CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+//LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+//ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+//POSSIBILITY OF SUCH DAMAGE.
+
+//
+// Author: John Kessenich, LunarG
+//
+
+// SPIRV-IR
+//
+// Simple in-memory representation (IR) of SPIRV. Just for holding
+// Each function's CFG of blocks. Has this hierarchy:
+// - Module, which is a list of
+// - Function, which is a list of
+// - Block, which is a list of
+// - Instruction
+//
+
+#pragma once
+#ifndef spvIR_H
+#define spvIR_H
+
+#include "spirv.h"
+
+#include <vector>
+#include <iostream>
+#include <assert.h>
+
+namespace spv {
+
+class Function;
+class Module;
+
+const Id NoResult = 0;
+const Id NoType = 0;
+
+const unsigned int BadValue = 0xFFFFFFFF;
+const Decoration NoPrecision = (Decoration)BadValue;
+const MemorySemanticsMask MemorySemanticsAllMemory = (MemorySemanticsMask)0x3FF;
+
+//
+// SPIR-V IR instruction.
+//
+
+class Instruction {
+public:
+ Instruction(Id resultId, Id typeId, Op opCode) : resultId(resultId), typeId(typeId), opCode(opCode), string(0) { }
+ explicit Instruction(Op opCode) : resultId(NoResult), typeId(NoType), opCode(opCode), string(0) { }
+ virtual ~Instruction()
+ {
+ delete string;
+ }
+ void addIdOperand(Id id) { operands.push_back(id); }
+ void addImmediateOperand(unsigned int immediate) { operands.push_back(immediate); }
+ void addStringOperand(const char* str)
+ {
+ originalString = str;
+ string = new std::vector<unsigned int>;
+ unsigned int word;
+ char* wordString = (char*)&word;
+ char* wordPtr = wordString;
+ int charCount = 0;
+ char c;
+ do {
+ c = *(str++);
+ *(wordPtr++) = c;
+ ++charCount;
+ if (charCount == 4) {
+ string->push_back(word);
+ wordPtr = wordString;
+ charCount = 0;
+ }
+ } while (c != 0);
+
+ // deal with partial last word
+ if (charCount > 0) {
+ // pad with 0s
+ for (; charCount < 4; ++charCount)
+ *(wordPtr++) = 0;
+ string->push_back(word);
+ }
+ }
+ Op getOpCode() const { return opCode; }
+ int getNumOperands() const { return (int)operands.size(); }
+ Id getResultId() const { return resultId; }
+ Id getTypeId() const { return typeId; }
+ Id getIdOperand(int op) const { return operands[op]; }
+ unsigned int getImmediateOperand(int op) const { return operands[op]; }
+ const char* getStringOperand() const { return originalString.c_str(); }
+
+ // Write out the binary form.
+ void dump(std::vector<unsigned int>& out) const
+ {
+ // Compute the wordCount
+ unsigned int wordCount = 1;
+ if (typeId)
+ ++wordCount;
+ if (resultId)
+ ++wordCount;
+ wordCount += (unsigned int)operands.size();
+ if (string)
+ wordCount += (unsigned int)string->size();
+
+ // Write out the beginning of the instruction
+ out.push_back(((wordCount) << WordCountShift) | opCode);
+ if (typeId)
+ out.push_back(typeId);
+ if (resultId)
+ out.push_back(resultId);
+
+ // Write out the operands
+ for (int op = 0; op < (int)operands.size(); ++op)
+ out.push_back(operands[op]);
+ if (string)
+ for (int op = 0; op < (int)string->size(); ++op)
+ out.push_back((*string)[op]);
+ }
+
+protected:
+ Instruction(const Instruction&);
+ Id resultId;
+ Id typeId;
+ Op opCode;
+ std::vector<Id> operands;
+ std::vector<unsigned int>* string; // usually non-existent
+ std::string originalString; // could be optimized away; convenience for getting string operand
+};
+
+//
+// SPIR-V IR block.
+//
+
+class Block {
+public:
+ Block(Id id, Function& parent);
+ virtual ~Block()
+ {
+ // TODO: free instructions
+ }
+
+ Id getId() { return instructions.front()->getResultId(); }
+
+ Function& getParent() const { return parent; }
+ void addInstruction(Instruction* inst);
+ void addPredecessor(Block* pred) { predecessors.push_back(pred); }
+ void addLocalVariable(Instruction* inst) { localVariables.push_back(inst); }
+ int getNumPredecessors() const { return (int)predecessors.size(); }
+ void setUnreachable() { unreachable = true; }
+ bool isUnreachable() const { return unreachable; }
+
+ bool isTerminated() const
+ {
+ switch (instructions.back()->getOpCode()) {
+ case OpBranch:
+ case OpBranchConditional:
+ case OpSwitch:
+ case OpKill:
+ case OpReturn:
+ case OpReturnValue:
+ return true;
+ default:
+ return false;
+ }
+ }
+
+ void dump(std::vector<unsigned int>& out) const
+ {
+ // skip the degenerate unreachable blocks
+ // TODO: code gen: skip all unreachable blocks (transitive closure)
+ // (but, until that's done safer to keep non-degenerate unreachable blocks, in case others depend on something)
+ if (unreachable && instructions.size() <= 2)
+ return;
+
+ instructions[0]->dump(out);
+ for (int i = 0; i < (int)localVariables.size(); ++i)
+ localVariables[i]->dump(out);
+ for (int i = 1; i < (int)instructions.size(); ++i)
+ instructions[i]->dump(out);
+ }
+
+protected:
+ Block(const Block&);
+ Block& operator=(Block&);
+
+ // To enforce keeping parent and ownership in sync:
+ friend Function;
+
+ std::vector<Instruction*> instructions;
+ std::vector<Block*> predecessors;
+ std::vector<Instruction*> localVariables;
+ Function& parent;
+
+ // track whether this block is known to be uncreachable (not necessarily
+ // true for all unreachable blocks, but should be set at least
+ // for the extraneous ones introduced by the builder).
+ bool unreachable;
+};
+
+//
+// SPIR-V IR Function.
+//
+
+class Function {
+public:
+ Function(Id id, Id resultType, Id functionType, Id firstParam, Module& parent);
+ virtual ~Function()
+ {
+ for (int i = 0; i < (int)parameterInstructions.size(); ++i)
+ delete parameterInstructions[i];
+
+ for (int i = 0; i < (int)blocks.size(); ++i)
+ delete blocks[i];
+ }
+ Id getId() const { return functionInstruction.getResultId(); }
+ Id getParamId(int p) { return parameterInstructions[p]->getResultId(); }
+
+ void addBlock(Block* block) { blocks.push_back(block); }
+ void popBlock(Block*) { blocks.pop_back(); }
+
+ Module& getParent() const { return parent; }
+ Block* getEntryBlock() const { return blocks.front(); }
+ Block* getLastBlock() const { return blocks.back(); }
+ void addLocalVariable(Instruction* inst);
+ Id getReturnType() const { return functionInstruction.getTypeId(); }
+ void dump(std::vector<unsigned int>& out) const
+ {
+ // OpFunction
+ functionInstruction.dump(out);
+
+ // OpFunctionParameter
+ for (int p = 0; p < (int)parameterInstructions.size(); ++p)
+ parameterInstructions[p]->dump(out);
+
+ // Blocks
+ for (int b = 0; b < (int)blocks.size(); ++b)
+ blocks[b]->dump(out);
+ Instruction end(0, 0, OpFunctionEnd);
+ end.dump(out);
+ }
+
+protected:
+ Function(const Function&);
+ Function& operator=(Function&);
+
+ Module& parent;
+ Instruction functionInstruction;
+ std::vector<Instruction*> parameterInstructions;
+ std::vector<Block*> blocks;
+};
+
+//
+// SPIR-V IR Module.
+//
+
+class Module {
+public:
+ Module() {}
+ virtual ~Module()
+ {
+ // TODO delete things
+ }
+
+ void addFunction(Function *fun) { functions.push_back(fun); }
+
+ void mapInstruction(Instruction *instruction)
+ {
+ spv::Id resultId = instruction->getResultId();
+ // map the instruction's result id
+ if (resultId >= idToInstruction.size())
+ idToInstruction.resize(resultId + 16);
+ idToInstruction[resultId] = instruction;
+ }
+
+ Instruction* getInstruction(Id id) const { return idToInstruction[id]; }
+ spv::Id getTypeId(Id resultId) const { return idToInstruction[resultId]->getTypeId(); }
+ StorageClass getStorageClass(Id typeId) const { return (StorageClass)idToInstruction[typeId]->getImmediateOperand(0); }
+ void dump(std::vector<unsigned int>& out) const
+ {
+ for (int f = 0; f < (int)functions.size(); ++f)
+ functions[f]->dump(out);
+ }
+
+protected:
+ Module(const Module&);
+ std::vector<Function*> functions;
+
+ // map from result id to instruction having that result id
+ std::vector<Instruction*> idToInstruction;
+
+ // map from a result id to its type id
+};
+
+//
+// Implementation (it's here due to circular type definitions).
+//
+
+// Add both
+// - the OpFunction instruction
+// - all the OpFunctionParameter instructions
+__inline Function::Function(Id id, Id resultType, Id functionType, Id firstParamId, Module& parent)
+ : parent(parent), functionInstruction(id, resultType, OpFunction)
+{
+ // OpFunction
+ functionInstruction.addImmediateOperand(FunctionControlMaskNone);
+ functionInstruction.addIdOperand(functionType);
+ parent.mapInstruction(&functionInstruction);
+ parent.addFunction(this);
+
+ // OpFunctionParameter
+ Instruction* typeInst = parent.getInstruction(functionType);
+ int numParams = typeInst->getNumOperands() - 1;
+ for (int p = 0; p < numParams; ++p) {
+ Instruction* param = new Instruction(firstParamId + p, typeInst->getIdOperand(p + 1), OpFunctionParameter);
+ parent.mapInstruction(param);
+ parameterInstructions.push_back(param);
+ }
+}
+
+__inline void Function::addLocalVariable(Instruction* inst)
+{
+ blocks[0]->addLocalVariable(inst);
+ parent.mapInstruction(inst);
+}
+
+__inline Block::Block(Id id, Function& parent) : parent(parent), unreachable(false)
+{
+ instructions.push_back(new Instruction(id, NoType, OpLabel));
+}
+
+__inline void Block::addInstruction(Instruction* inst)
+{
+ instructions.push_back(inst);
+ if (inst->getResultId())
+ parent.getParent().mapInstruction(inst);
+}
+
+}; // end spv namespace
+
+#endif // spvIR_H
-cmake_minimum_required(VERSION 2.8)\r
-\r
-include_directories(.)\r
-if(WIN32)\r
- include_directories(../glslang/OSDependent/Windows)\r
-elseif(UNIX)\r
- include_directories(../glslang/OSDependent/Linux)\r
-else(WIN32)\r
- message("unkown platform")\r
-endif(WIN32)\r
-\r
-set(SOURCES StandAlone.cpp)\r
-set(REMAPPER_SOURCES spirv-remap.cpp)\r
-\r
-add_executable(glslangValidator ${SOURCES})\r
-add_executable(spirv-remap ${REMAPPER_SOURCES})\r
-\r
-set(LIBRARIES\r
- glslang\r
- OGLCompiler\r
- OSDependent\r
- SPIRV)\r
-\r
-if(WIN32)\r
- set(LIBRARIES ${LIBRARIES} psapi)\r
-elseif(UNIX)\r
- set(LIBRARIES ${LIBRARIES} pthread)\r
-endif(WIN32)\r
-\r
-target_link_libraries(glslangValidator ${LIBRARIES})\r
-target_link_libraries(spirv-remap ${LIBRARIES})\r
-\r
-if(WIN32)\r
- source_group("Source" FILES ${SOURCES})\r
-endif(WIN32)\r
-\r
-install(TARGETS glslangValidator\r
- RUNTIME DESTINATION bin)\r
-\r
-install(TARGETS spirv-remap\r
- RUNTIME DESTINATION bin)\r
+cmake_minimum_required(VERSION 2.8)
+
+include_directories(.)
+if(WIN32)
+ include_directories(../glslang/OSDependent/Windows)
+elseif(UNIX)
+ include_directories(../glslang/OSDependent/Linux)
+else(WIN32)
+ message("unkown platform")
+endif(WIN32)
+
+set(SOURCES StandAlone.cpp)
+set(REMAPPER_SOURCES spirv-remap.cpp)
+
+add_executable(glslangValidator ${SOURCES})
+add_executable(spirv-remap ${REMAPPER_SOURCES})
+
+set(LIBRARIES
+ glslang
+ OGLCompiler
+ OSDependent
+ SPIRV)
+
+if(WIN32)
+ set(LIBRARIES ${LIBRARIES} psapi)
+elseif(UNIX)
+ set(LIBRARIES ${LIBRARIES} pthread)
+endif(WIN32)
+
+target_link_libraries(glslangValidator ${LIBRARIES})
+target_link_libraries(spirv-remap ${LIBRARIES})
+
+if(WIN32)
+ source_group("Source" FILES ${SOURCES})
+endif(WIN32)
+
+install(TARGETS glslangValidator
+ RUNTIME DESTINATION bin)
+
+install(TARGETS spirv-remap
+ RUNTIME DESTINATION bin)
-//\r
-//Copyright (C) 2015 LunarG, Inc.\r
-//\r
-//All rights reserved.\r
-//\r
-//Redistribution and use in source and binary forms, with or without\r
-//modification, are permitted provided that the following conditions\r
-//are met:\r
-//\r
-// Redistributions of source code must retain the above copyright\r
-// notice, this list of conditions and the following disclaimer.\r
-//\r
-// Redistributions in binary form must reproduce the above\r
-// copyright notice, this list of conditions and the following\r
-// disclaimer in the documentation and/or other materials provided\r
-// with the distribution.\r
-//\r
-// Neither the name of 3Dlabs Inc. Ltd. nor the names of its\r
-// contributors may be used to endorse or promote products derived\r
-// from this software without specific prior written permission.\r
-//\r
-//THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\r
-//"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\r
-//LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS\r
-//FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE\r
-//COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,\r
-//INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,\r
-//BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\r
-//LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER\r
-//CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\r
-//LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN\r
-//ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE\r
-//POSSIBILITY OF SUCH DAMAGE.\r
-//\r
-\r
-#include <iostream>\r
-#include <fstream>\r
-#include <cstring>\r
-#include <stdexcept>\r
-\r
-#include "../SPIRV/SPVRemapper.h"\r
-\r
-namespace {\r
-\r
- typedef unsigned int SpvWord;\r
-\r
- // Poor man's basename: given a complete path, return file portion.\r
- // E.g:\r
- // Linux: /foo/bar/test -> test\r
- // Win: c:\foo\bar\test -> test\r
- // It's not very efficient, but that doesn't matter for our minimal-duty use.\r
- // Using boost::filesystem would be better in many ways, but want to avoid that dependency.\r
-\r
- // OS dependent path separator (avoiding boost::filesystem dependency)\r
-#if defined(_WIN32)\r
- char path_sep_char() { return '\\'; }\r
-#else\r
- char path_sep_char() { return '/'; }\r
-#endif\r
-\r
- std::string basename(const std::string filename)\r
- {\r
- const size_t sepLoc = filename.find_last_of(path_sep_char());\r
-\r
- return (sepLoc == filename.npos) ? filename : filename.substr(sepLoc+1);\r
- }\r
-\r
- void errHandler(const std::string& str) {\r
- std::cout << str << std::endl;\r
- exit(5);\r
- }\r
-\r
- void logHandler(const std::string& str) {\r
- std::cout << str << std::endl;\r
- }\r
-\r
- // Read word stream from disk\r
- void read(std::vector<SpvWord>& spv, const std::string& inFilename, int verbosity)\r
- {\r
- std::ifstream fp;\r
-\r
- if (verbosity > 0)\r
- logHandler(std::string(" reading: ") + inFilename);\r
-\r
- spv.clear();\r
- fp.open(inFilename, std::fstream::in | std::fstream::binary);\r
-\r
- if (fp.fail())\r
- errHandler("error opening file for read: ");\r
-\r
- // Reserve space (for efficiency, not for correctness)\r
- fp.seekg(0, fp.end);\r
- spv.reserve(size_t(fp.tellg()) / sizeof(SpvWord));\r
- fp.seekg(0, fp.beg);\r
-\r
- while (!fp.eof()) {\r
- SpvWord inWord;\r
- fp.read((char *)&inWord, sizeof(inWord));\r
-\r
- if (!fp.eof()) {\r
- spv.push_back(inWord);\r
- if (fp.fail())\r
- errHandler(std::string("error reading file: ") + inFilename);\r
- }\r
- }\r
- }\r
-\r
- void write(std::vector<SpvWord>& spv, const std::string& outFile, int verbosity)\r
- {\r
- if (outFile.empty())\r
- errHandler("missing output filename.");\r
-\r
- std::ofstream fp;\r
-\r
- if (verbosity > 0)\r
- logHandler(std::string(" writing: ") + outFile);\r
-\r
- fp.open(outFile, std::fstream::out | std::fstream::binary);\r
-\r
- if (fp.fail())\r
- errHandler(std::string("error opening file for write: ") + outFile);\r
-\r
- for (auto word : spv) {\r
- fp.write((char *)&word, sizeof(word));\r
- if (fp.fail())\r
- errHandler(std::string("error writing file: ") + outFile);\r
- }\r
-\r
- // file is closed by destructor\r
- }\r
-\r
- // Print helpful usage message to stdout, and exit\r
- void usage(const char* const name, const char* const msg = 0)\r
- {\r
- if (msg)\r
- std::cout << msg << std::endl << std::endl;\r
-\r
- std::cout << "Usage: " << std::endl;\r
-\r
- std::cout << " " << basename(name)\r
- << " [-v[v[...]] | --verbose [int]]"\r
- << " [--map (all|types|names|funcs)]"\r
- << " [--dce (all|types|funcs)]"\r
- << " [--opt (all|loadstore)]"\r
- << " [--strip-all | --strip all | -s]" \r
- << " [--do-everything]" \r
- << " --input | -i file1 [file2...] --output|-o DESTDIR"\r
- << std::endl;\r
-\r
- std::cout << " " << basename(name) << " [--version | -V]" << std::endl;\r
- std::cout << " " << basename(name) << " [--help | -?]" << std::endl;\r
-\r
- exit(5);\r
- }\r
-\r
- // grind through each SPIR in turn\r
- void execute(const std::vector<std::string>& inputFile, const std::string& outputDir,\r
- int opts, int verbosity)\r
- {\r
- for (const auto& filename : inputFile) {\r
- std::vector<SpvWord> spv;\r
- read(spv, filename, verbosity);\r
- spv::spirvbin_t(verbosity).remap(spv, opts);\r
-\r
- const std::string outfile = outputDir + path_sep_char() + basename(filename);\r
-\r
- write(spv, outfile, verbosity);\r
- }\r
-\r
- if (verbosity > 0)\r
- std::cout << "Done: " << inputFile.size() << " file(s) processed" << std::endl;\r
- }\r
-\r
- // Parse command line options\r
- void parseCmdLine(int argc, char** argv, std::vector<std::string>& inputFile,\r
- std::string& outputDir,\r
- int& options,\r
- int& verbosity)\r
- {\r
- if (argc < 2)\r
- usage(argv[0]);\r
-\r
- verbosity = 0;\r
- options = spv::spirvbin_t::NONE;\r
-\r
- // Parse command line.\r
- // boost::program_options would be quite a bit nicer, but we don't want to\r
- // introduce a dependency on boost.\r
- for (int a=1; a<argc; ) {\r
- const std::string arg = argv[a];\r
-\r
- if (arg == "--output" || arg == "-o") {\r
- // Output directory\r
- if (++a >= argc)\r
- usage(argv[0], "--output requires an argument");\r
- if (!outputDir.empty())\r
- usage(argv[0], "--output can be provided only once");\r
-\r
- outputDir = argv[a++];\r
-\r
- // Remove trailing directory separator characters\r
- while (!outputDir.empty() && outputDir.back() == path_sep_char())\r
- outputDir.pop_back();\r
-\r
- }\r
- else if (arg == "-vv") { verbosity = 2; ++a; } // verbosity shortcuts\r
- else if (arg == "-vvv") { verbosity = 3; ++a; } // ...\r
- else if (arg == "-vvvv") { verbosity = 4; ++a; } // ...\r
- else if (arg == "-vvvvv") { verbosity = 5; ++a; } // ...\r
-\r
- else if (arg == "--verbose" || arg == "-v") {\r
- ++a;\r
- verbosity = 1;\r
-\r
- if (a < argc) {\r
- try {\r
- verbosity = std::stoi(argv[a]);\r
- ++a;\r
- } catch (const std::invalid_argument&) { } // ok to have no numeric value\r
- }\r
- }\r
- else if (arg == "--version" || arg == "-V") {\r
- std::cout << basename(argv[0]) << " version 0.97 " << __DATE__ << " " << __TIME__ << std::endl;\r
- exit(0);\r
- } else if (arg == "--input" || arg == "-i") {\r
- // Collect input files\r
- for (++a; a < argc && argv[a][0] != '-'; ++a)\r
- inputFile.push_back(argv[a]);\r
- } else if (arg == "--do-everything") {\r
- ++a;\r
- options = options | spv::spirvbin_t::DO_EVERYTHING;\r
- } else if (arg == "--strip-all" || arg == "-s") {\r
- ++a;\r
- options = options | spv::spirvbin_t::STRIP;\r
- } else if (arg == "--strip") {\r
- ++a;\r
- if (strncmp(argv[a], "all", 3) == 0) {\r
- options = options | spv::spirvbin_t::STRIP;\r
- ++a;\r
- }\r
- } else if (arg == "--dce") {\r
- // Parse comma (or colon, etc) separated list of things to dce\r
- ++a;\r
- for (const char* c = argv[a]; *c; ++c) {\r
- if (strncmp(c, "all", 3) == 0) {\r
- options = (options | spv::spirvbin_t::DCE_ALL);\r
- c += 3;\r
- } else if (strncmp(c, "*", 1) == 0) {\r
- options = (options | spv::spirvbin_t::DCE_ALL);\r
- c += 1;\r
- } else if (strncmp(c, "funcs", 5) == 0) {\r
- options = (options | spv::spirvbin_t::DCE_FUNCS);\r
- c += 5;\r
- } else if (strncmp(c, "types", 5) == 0) {\r
- options = (options | spv::spirvbin_t::DCE_TYPES);\r
- c += 5;\r
- }\r
- }\r
- ++a;\r
- } else if (arg == "--map") {\r
- // Parse comma (or colon, etc) separated list of things to map\r
- ++a;\r
- for (const char* c = argv[a]; *c; ++c) {\r
- if (strncmp(c, "all", 3) == 0) {\r
- options = (options | spv::spirvbin_t::MAP_ALL);\r
- c += 3;\r
- } else if (strncmp(c, "*", 1) == 0) {\r
- options = (options | spv::spirvbin_t::MAP_ALL);\r
- c += 1;\r
- } else if (strncmp(c, "types", 5) == 0) {\r
- options = (options | spv::spirvbin_t::MAP_TYPES);\r
- c += 5;\r
- } else if (strncmp(c, "names", 5) == 0) {\r
- options = (options | spv::spirvbin_t::MAP_NAMES);\r
- c += 5;\r
- } else if (strncmp(c, "funcs", 5) == 0) {\r
- options = (options | spv::spirvbin_t::MAP_FUNCS);\r
- c += 5;\r
- }\r
- }\r
- ++a;\r
- } else if (arg == "--opt") {\r
- ++a;\r
- for (const char* c = argv[a]; *c; ++c) {\r
- if (strncmp(c, "all", 3) == 0) {\r
- options = (options | spv::spirvbin_t::OPT_ALL);\r
- c += 3;\r
- } else if (strncmp(c, "*", 1) == 0) {\r
- options = (options | spv::spirvbin_t::OPT_ALL);\r
- c += 1;\r
- } else if (strncmp(c, "loadstore", 9) == 0) {\r
- options = (options | spv::spirvbin_t::OPT_LOADSTORE);\r
- c += 9;\r
- }\r
- }\r
- ++a;\r
- } else if (arg == "--help" || arg == "-?") {\r
- usage(argv[0]);\r
- } else {\r
- usage(argv[0], "Unknown command line option");\r
- }\r
- }\r
- }\r
-\r
-} // namespace\r
-\r
-\r
-int main(int argc, char** argv)\r
-{\r
- std::vector<std::string> inputFile;\r
- std::string outputDir;\r
- int opts;\r
- int verbosity;\r
-\r
-#ifdef use_cpp11\r
- // handle errors by exiting\r
- spv::spirvbin_t::registerErrorHandler(errHandler);\r
-\r
- // Log messages to std::cout\r
- spv::spirvbin_t::registerLogHandler(logHandler);\r
-#endif\r
-\r
- if (argc < 2)\r
- usage(argv[0]);\r
-\r
- parseCmdLine(argc, argv, inputFile, outputDir, opts, verbosity);\r
-\r
- if (outputDir.empty())\r
- usage(argv[0], "Output directory required");\r
-\r
- std::string errmsg;\r
-\r
- // Main operations: read, remap, and write.\r
- execute(inputFile, outputDir, opts, verbosity);\r
-\r
- // If we get here, everything went OK! Nothing more to be done.\r
-}\r
+//
+//Copyright (C) 2015 LunarG, Inc.
+//
+//All rights reserved.
+//
+//Redistribution and use in source and binary forms, with or without
+//modification, are permitted provided that the following conditions
+//are met:
+//
+// Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//
+// Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following
+// disclaimer in the documentation and/or other materials provided
+// with the distribution.
+//
+// Neither the name of 3Dlabs Inc. Ltd. nor the names of its
+// contributors may be used to endorse or promote products derived
+// from this software without specific prior written permission.
+//
+//THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+//"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+//LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+//FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+//COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+//INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+//BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+//LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+//CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+//LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+//ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+//POSSIBILITY OF SUCH DAMAGE.
+//
+
+#include <iostream>
+#include <fstream>
+#include <cstring>
+#include <stdexcept>
+
+#include "../SPIRV/SPVRemapper.h"
+
+namespace {
+
+ typedef unsigned int SpvWord;
+
+ // Poor man's basename: given a complete path, return file portion.
+ // E.g:
+ // Linux: /foo/bar/test -> test
+ // Win: c:\foo\bar\test -> test
+ // It's not very efficient, but that doesn't matter for our minimal-duty use.
+ // Using boost::filesystem would be better in many ways, but want to avoid that dependency.
+
+ // OS dependent path separator (avoiding boost::filesystem dependency)
+#if defined(_WIN32)
+ char path_sep_char() { return '\\'; }
+#else
+ char path_sep_char() { return '/'; }
+#endif
+
+ std::string basename(const std::string filename)
+ {
+ const size_t sepLoc = filename.find_last_of(path_sep_char());
+
+ return (sepLoc == filename.npos) ? filename : filename.substr(sepLoc+1);
+ }
+
+ void errHandler(const std::string& str) {
+ std::cout << str << std::endl;
+ exit(5);
+ }
+
+ void logHandler(const std::string& str) {
+ std::cout << str << std::endl;
+ }
+
+ // Read word stream from disk
+ void read(std::vector<SpvWord>& spv, const std::string& inFilename, int verbosity)
+ {
+ std::ifstream fp;
+
+ if (verbosity > 0)
+ logHandler(std::string(" reading: ") + inFilename);
+
+ spv.clear();
+ fp.open(inFilename, std::fstream::in | std::fstream::binary);
+
+ if (fp.fail())
+ errHandler("error opening file for read: ");
+
+ // Reserve space (for efficiency, not for correctness)
+ fp.seekg(0, fp.end);
+ spv.reserve(size_t(fp.tellg()) / sizeof(SpvWord));
+ fp.seekg(0, fp.beg);
+
+ while (!fp.eof()) {
+ SpvWord inWord;
+ fp.read((char *)&inWord, sizeof(inWord));
+
+ if (!fp.eof()) {
+ spv.push_back(inWord);
+ if (fp.fail())
+ errHandler(std::string("error reading file: ") + inFilename);
+ }
+ }
+ }
+
+ void write(std::vector<SpvWord>& spv, const std::string& outFile, int verbosity)
+ {
+ if (outFile.empty())
+ errHandler("missing output filename.");
+
+ std::ofstream fp;
+
+ if (verbosity > 0)
+ logHandler(std::string(" writing: ") + outFile);
+
+ fp.open(outFile, std::fstream::out | std::fstream::binary);
+
+ if (fp.fail())
+ errHandler(std::string("error opening file for write: ") + outFile);
+
+ for (auto word : spv) {
+ fp.write((char *)&word, sizeof(word));
+ if (fp.fail())
+ errHandler(std::string("error writing file: ") + outFile);
+ }
+
+ // file is closed by destructor
+ }
+
+ // Print helpful usage message to stdout, and exit
+ void usage(const char* const name, const char* const msg = 0)
+ {
+ if (msg)
+ std::cout << msg << std::endl << std::endl;
+
+ std::cout << "Usage: " << std::endl;
+
+ std::cout << " " << basename(name)
+ << " [-v[v[...]] | --verbose [int]]"
+ << " [--map (all|types|names|funcs)]"
+ << " [--dce (all|types|funcs)]"
+ << " [--opt (all|loadstore)]"
+ << " [--strip-all | --strip all | -s]"
+ << " [--do-everything]"
+ << " --input | -i file1 [file2...] --output|-o DESTDIR"
+ << std::endl;
+
+ std::cout << " " << basename(name) << " [--version | -V]" << std::endl;
+ std::cout << " " << basename(name) << " [--help | -?]" << std::endl;
+
+ exit(5);
+ }
+
+ // grind through each SPIR in turn
+ void execute(const std::vector<std::string>& inputFile, const std::string& outputDir,
+ int opts, int verbosity)
+ {
+ for (const auto& filename : inputFile) {
+ std::vector<SpvWord> spv;
+ read(spv, filename, verbosity);
+ spv::spirvbin_t(verbosity).remap(spv, opts);
+
+ const std::string outfile = outputDir + path_sep_char() + basename(filename);
+
+ write(spv, outfile, verbosity);
+ }
+
+ if (verbosity > 0)
+ std::cout << "Done: " << inputFile.size() << " file(s) processed" << std::endl;
+ }
+
+ // Parse command line options
+ void parseCmdLine(int argc, char** argv, std::vector<std::string>& inputFile,
+ std::string& outputDir,
+ int& options,
+ int& verbosity)
+ {
+ if (argc < 2)
+ usage(argv[0]);
+
+ verbosity = 0;
+ options = spv::spirvbin_t::NONE;
+
+ // Parse command line.
+ // boost::program_options would be quite a bit nicer, but we don't want to
+ // introduce a dependency on boost.
+ for (int a=1; a<argc; ) {
+ const std::string arg = argv[a];
+
+ if (arg == "--output" || arg == "-o") {
+ // Output directory
+ if (++a >= argc)
+ usage(argv[0], "--output requires an argument");
+ if (!outputDir.empty())
+ usage(argv[0], "--output can be provided only once");
+
+ outputDir = argv[a++];
+
+ // Remove trailing directory separator characters
+ while (!outputDir.empty() && outputDir.back() == path_sep_char())
+ outputDir.pop_back();
+
+ }
+ else if (arg == "-vv") { verbosity = 2; ++a; } // verbosity shortcuts
+ else if (arg == "-vvv") { verbosity = 3; ++a; } // ...
+ else if (arg == "-vvvv") { verbosity = 4; ++a; } // ...
+ else if (arg == "-vvvvv") { verbosity = 5; ++a; } // ...
+
+ else if (arg == "--verbose" || arg == "-v") {
+ ++a;
+ verbosity = 1;
+
+ if (a < argc) {
+ try {
+ verbosity = std::stoi(argv[a]);
+ ++a;
+ } catch (const std::invalid_argument&) { } // ok to have no numeric value
+ }
+ }
+ else if (arg == "--version" || arg == "-V") {
+ std::cout << basename(argv[0]) << " version 0.97 " << __DATE__ << " " << __TIME__ << std::endl;
+ exit(0);
+ } else if (arg == "--input" || arg == "-i") {
+ // Collect input files
+ for (++a; a < argc && argv[a][0] != '-'; ++a)
+ inputFile.push_back(argv[a]);
+ } else if (arg == "--do-everything") {
+ ++a;
+ options = options | spv::spirvbin_t::DO_EVERYTHING;
+ } else if (arg == "--strip-all" || arg == "-s") {
+ ++a;
+ options = options | spv::spirvbin_t::STRIP;
+ } else if (arg == "--strip") {
+ ++a;
+ if (strncmp(argv[a], "all", 3) == 0) {
+ options = options | spv::spirvbin_t::STRIP;
+ ++a;
+ }
+ } else if (arg == "--dce") {
+ // Parse comma (or colon, etc) separated list of things to dce
+ ++a;
+ for (const char* c = argv[a]; *c; ++c) {
+ if (strncmp(c, "all", 3) == 0) {
+ options = (options | spv::spirvbin_t::DCE_ALL);
+ c += 3;
+ } else if (strncmp(c, "*", 1) == 0) {
+ options = (options | spv::spirvbin_t::DCE_ALL);
+ c += 1;
+ } else if (strncmp(c, "funcs", 5) == 0) {
+ options = (options | spv::spirvbin_t::DCE_FUNCS);
+ c += 5;
+ } else if (strncmp(c, "types", 5) == 0) {
+ options = (options | spv::spirvbin_t::DCE_TYPES);
+ c += 5;
+ }
+ }
+ ++a;
+ } else if (arg == "--map") {
+ // Parse comma (or colon, etc) separated list of things to map
+ ++a;
+ for (const char* c = argv[a]; *c; ++c) {
+ if (strncmp(c, "all", 3) == 0) {
+ options = (options | spv::spirvbin_t::MAP_ALL);
+ c += 3;
+ } else if (strncmp(c, "*", 1) == 0) {
+ options = (options | spv::spirvbin_t::MAP_ALL);
+ c += 1;
+ } else if (strncmp(c, "types", 5) == 0) {
+ options = (options | spv::spirvbin_t::MAP_TYPES);
+ c += 5;
+ } else if (strncmp(c, "names", 5) == 0) {
+ options = (options | spv::spirvbin_t::MAP_NAMES);
+ c += 5;
+ } else if (strncmp(c, "funcs", 5) == 0) {
+ options = (options | spv::spirvbin_t::MAP_FUNCS);
+ c += 5;
+ }
+ }
+ ++a;
+ } else if (arg == "--opt") {
+ ++a;
+ for (const char* c = argv[a]; *c; ++c) {
+ if (strncmp(c, "all", 3) == 0) {
+ options = (options | spv::spirvbin_t::OPT_ALL);
+ c += 3;
+ } else if (strncmp(c, "*", 1) == 0) {
+ options = (options | spv::spirvbin_t::OPT_ALL);
+ c += 1;
+ } else if (strncmp(c, "loadstore", 9) == 0) {
+ options = (options | spv::spirvbin_t::OPT_LOADSTORE);
+ c += 9;
+ }
+ }
+ ++a;
+ } else if (arg == "--help" || arg == "-?") {
+ usage(argv[0]);
+ } else {
+ usage(argv[0], "Unknown command line option");
+ }
+ }
+ }
+
+} // namespace
+
+
+int main(int argc, char** argv)
+{
+ std::vector<std::string> inputFile;
+ std::string outputDir;
+ int opts;
+ int verbosity;
+
+#ifdef use_cpp11
+ // handle errors by exiting
+ spv::spirvbin_t::registerErrorHandler(errHandler);
+
+ // Log messages to std::cout
+ spv::spirvbin_t::registerLogHandler(logHandler);
+#endif
+
+ if (argc < 2)
+ usage(argv[0]);
+
+ parseCmdLine(argc, argv, inputFile, outputDir, opts, verbosity);
+
+ if (outputDir.empty())
+ usage(argv[0], "Output directory required");
+
+ std::string errmsg;
+
+ // Main operations: read, remap, and write.
+ execute(inputFile, outputDir, opts, verbosity);
+
+ // If we get here, everything went OK! Nothing more to be done.
+}