Final round for line endings.
diff --git a/SPIRV/CMakeLists.txt b/SPIRV/CMakeLists.txt
index 3bc149f..6bb140b 100644
--- a/SPIRV/CMakeLists.txt
+++ b/SPIRV/CMakeLists.txt
@@ -1,28 +1,28 @@
-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)
+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)
diff --git a/SPIRV/GLSL450Lib.h b/SPIRV/GLSL450Lib.h
index 7565d8a..32f4563 100644
--- a/SPIRV/GLSL450Lib.h
+++ b/SPIRV/GLSL450Lib.h
@@ -1,210 +1,210 @@
-/*
-** 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
+/*
+** 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
diff --git a/SPIRV/GlslangToSpv.cpp b/SPIRV/GlslangToSpv.cpp
index 969c091..8cdc032 100644
--- a/SPIRV/GlslangToSpv.cpp
+++ b/SPIRV/GlslangToSpv.cpp
@@ -1,2578 +1,2578 @@
-//
-//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
+//
+//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
diff --git a/SPIRV/GlslangToSpv.h b/SPIRV/GlslangToSpv.h
index 1a14fe5..75375d8 100644
--- a/SPIRV/GlslangToSpv.h
+++ b/SPIRV/GlslangToSpv.h
@@ -1,42 +1,42 @@
-//
-//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);
-
-};
+//
+//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);
+
+};
diff --git a/SPIRV/SPVRemapper.cpp b/SPIRV/SPVRemapper.cpp
index a8b71f9..76d4772 100644
--- a/SPIRV/SPVRemapper.cpp
+++ b/SPIRV/SPVRemapper.cpp
@@ -1,1161 +1,1161 @@
-//
-//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)
-
+//
+//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)
+
diff --git a/SPIRV/SPVRemapper.h b/SPIRV/SPVRemapper.h
index 71ca719..1b148b3 100644
--- a/SPIRV/SPVRemapper.h
+++ b/SPIRV/SPVRemapper.h
@@ -1,288 +1,288 @@
-//
-//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
+//
+//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
diff --git a/SPIRV/SpvBuilder.cpp b/SPIRV/SpvBuilder.cpp
index 35270b0..f90dd70 100644
--- a/SPIRV/SpvBuilder.cpp
+++ b/SPIRV/SpvBuilder.cpp
@@ -1,2137 +1,2137 @@
-//
-//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
+//
+//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
diff --git a/SPIRV/SpvBuilder.h b/SPIRV/SpvBuilder.h
index b500c1fe..4eef5a4 100644
--- a/SPIRV/SpvBuilder.h
+++ b/SPIRV/SpvBuilder.h
@@ -1,563 +1,563 @@
-//
-//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
+//
+//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
diff --git a/SPIRV/disassemble.cpp b/SPIRV/disassemble.cpp
index bc8ca88..adbe1ac 100644
--- a/SPIRV/disassemble.cpp
+++ b/SPIRV/disassemble.cpp
@@ -1,435 +1,435 @@
-//
-//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
+//
+//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
diff --git a/SPIRV/disassemble.h b/SPIRV/disassemble.h
index ca8bbb9..bcb05ef 100644
--- a/SPIRV/disassemble.h
+++ b/SPIRV/disassemble.h
@@ -1,56 +1,56 @@
-//
-//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
+//
+//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
diff --git a/SPIRV/doc.cpp b/SPIRV/doc.cpp
index 29658b6..a98ab4d 100644
--- a/SPIRV/doc.cpp
+++ b/SPIRV/doc.cpp
@@ -1,2127 +1,2127 @@
-//
-//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
+//
+//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
diff --git a/SPIRV/doc.h b/SPIRV/doc.h
index 9059f0e..ce4d972 100644
--- a/SPIRV/doc.h
+++ b/SPIRV/doc.h
@@ -1,256 +1,256 @@
-//
-//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
+//
+//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
diff --git a/SPIRV/spirv.h b/SPIRV/spirv.h
index f3d18a3..dc1e579 100644
--- a/SPIRV/spirv.h
+++ b/SPIRV/spirv.h
@@ -1,1304 +1,1304 @@
-/*
-** 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
+/*
+** 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
diff --git a/SPIRV/spvIR.h b/SPIRV/spvIR.h
index ec75824..028671d 100644
--- a/SPIRV/spvIR.h
+++ b/SPIRV/spvIR.h
@@ -1,369 +1,369 @@
-//
-//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
+//
+//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