From 140f3df1349bf8bdb29207f4a526c998e2a7f738 Mon Sep 17 00:00:00 2001 From: John Kessenich Date: Fri, 26 Jun 2015 16:58:36 -0600 Subject: [PATCH] Final round for line endings. --- Install/Linux/README.txt | 12 +- Install/Windows/README.txt | 12 +- OGLCompilersDLL/CMakeLists.txt | 42 +- SPIRV/CMakeLists.txt | 56 +- SPIRV/GLSL450Lib.h | 420 +-- SPIRV/GlslangToSpv.cpp | 5156 ++++++++++++++++---------------- SPIRV/GlslangToSpv.h | 84 +- SPIRV/SPVRemapper.cpp | 2322 +++++++------- SPIRV/SPVRemapper.h | 576 ++-- SPIRV/SpvBuilder.cpp | 4274 +++++++++++++------------- SPIRV/SpvBuilder.h | 1126 +++---- SPIRV/disassemble.cpp | 870 +++--- SPIRV/disassemble.h | 112 +- SPIRV/doc.cpp | 4254 +++++++++++++------------- SPIRV/doc.h | 512 ++-- SPIRV/spirv.h | 2608 ++++++++-------- SPIRV/spvIR.h | 738 ++--- StandAlone/CMakeLists.txt | 82 +- StandAlone/spirv-remap.cpp | 674 ++--- 19 files changed, 11965 insertions(+), 11965 deletions(-) diff --git a/Install/Linux/README.txt b/Install/Linux/README.txt index 9bd06640..aefc9fd8 100644 --- a/Install/Linux/README.txt +++ b/Install/Linux/README.txt @@ -1,6 +1,6 @@ -This directory contains a Linux binary for the glslang validator. - -Installation: The executable in this directory is self sufficient, and can be -placed where desired; in a test directory, or in a system path, etc. - -Usage: Execute glslangValidator with no arguments to get a usage statement. +This directory contains a Linux binary for the glslang validator. + +Installation: The executable in this directory is self sufficient, and can be +placed where desired; in a test directory, or in a system path, etc. + +Usage: Execute glslangValidator with no arguments to get a usage statement. diff --git a/Install/Windows/README.txt b/Install/Windows/README.txt index ee673f34..bde97b9d 100644 --- a/Install/Windows/README.txt +++ b/Install/Windows/README.txt @@ -1,6 +1,6 @@ -This directory contains a Windows binary for the glslang validator. - -Installation: The executable in this directory is self sufficient, and can be -placed where desired; in a test directory, or in a system path, etc. - -Usage: Execute glslangValidator with no arguments to get a usage statement. +This directory contains a Windows binary for the glslang validator. + +Installation: The executable in this directory is self sufficient, and can be +placed where desired; in a test directory, or in a system path, etc. + +Usage: Execute glslangValidator with no arguments to get a usage statement. diff --git a/OGLCompilersDLL/CMakeLists.txt b/OGLCompilersDLL/CMakeLists.txt index 6ade8cab..afabe75b 100644 --- a/OGLCompilersDLL/CMakeLists.txt +++ b/OGLCompilersDLL/CMakeLists.txt @@ -1,21 +1,21 @@ -cmake_minimum_required(VERSION 2.8) - -include_directories(. ../glslang) -if(WIN32) - include_directories(${include_directories} ../glslang/OSDependent/Windows) -elseif(UNIX) - include_directories(${include_directories} ../glslang/OSDependent/Linux) -else(WIN32) - message("unknown platform") -endif(WIN32) - -set(SOURCES InitializeDll.cpp InitializeDll.h) - -add_library(OGLCompiler STATIC ${SOURCES}) - -if(WIN32) - source_group("Source" FILES ${SOURCES}) -endif(WIN32) - -install(TARGETS OGLCompiler - ARCHIVE DESTINATION lib) +cmake_minimum_required(VERSION 2.8) + +include_directories(. ../glslang) +if(WIN32) + include_directories(${include_directories} ../glslang/OSDependent/Windows) +elseif(UNIX) + include_directories(${include_directories} ../glslang/OSDependent/Linux) +else(WIN32) + message("unknown platform") +endif(WIN32) + +set(SOURCES InitializeDll.cpp InitializeDll.h) + +add_library(OGLCompiler STATIC ${SOURCES}) + +if(WIN32) + source_group("Source" FILES ${SOURCES}) +endif(WIN32) + +install(TARGETS OGLCompiler + ARCHIVE DESTINATION lib) diff --git a/SPIRV/CMakeLists.txt b/SPIRV/CMakeLists.txt index 3bc149fe..6bb140be 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 7565d8a4..32f45638 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 969c091b..8cdc0329 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 -#include -#include -#include -#include -#include - -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& 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& 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& 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 symbolValues; - std::set 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 functionMap; - std::map structMap; - std::map > memberRemapper; // for mapping glslang block indices to spv indices (e.g., due to hidden members) - std::stack breakForLoop; // false means break for switch - std::stack 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& sourceExtensions = glslangIntermediate->getRequestedExtensions(); - for (std::set::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& 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 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 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 arguments; - translateArguments(node->getSequence(), arguments); - spv::Id resultTypeId = convertGlslangToSpvType(node->getType()); - spv::Id constructed; - if (node->getOp() == glslang::EOpConstructStruct || node->getType().isArray()) { - std::vector 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 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 codeSegments; - glslang::TIntermSequence& sequence = node->getBody()->getSequence(); - std::vector caseValues; - std::vector 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 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 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 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& 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 arguments; - translateArguments(node->getSequence(), arguments); - - std::vector 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 lValues; - std::vector 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 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 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 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& 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::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 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::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& 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& 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 +#include +#include +#include +#include +#include + +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& 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& 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& 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 symbolValues; + std::set 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 functionMap; + std::map structMap; + std::map > memberRemapper; // for mapping glslang block indices to spv indices (e.g., due to hidden members) + std::stack breakForLoop; // false means break for switch + std::stack 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& sourceExtensions = glslangIntermediate->getRequestedExtensions(); + for (std::set::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& 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 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 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 arguments; + translateArguments(node->getSequence(), arguments); + spv::Id resultTypeId = convertGlslangToSpvType(node->getType()); + spv::Id constructed; + if (node->getOp() == glslang::EOpConstructStruct || node->getType().isArray()) { + std::vector 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 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 codeSegments; + glslang::TIntermSequence& sequence = node->getBody()->getSequence(); + std::vector caseValues; + std::vector 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 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 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 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& 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 arguments; + translateArguments(node->getSequence(), arguments); + + std::vector 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 lValues; + std::vector 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 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 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 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& 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::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 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::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& 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& 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 1a14fe55..75375d81 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& spirv); -void OutputSpv(const std::vector& 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& spirv); +void OutputSpv(const std::vector& spirv, const char* baseName); + +}; diff --git a/SPIRV/SPVRemapper.cpp b/SPIRV/SPVRemapper.cpp index a8b71f95..76d47729 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 -#include - -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(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 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 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 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 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 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 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; xsecond; - } - - // 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& 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 +#include + +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(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 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 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 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 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 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 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; xsecond; + } + + // 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& 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 71ca7191..1b148b35 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 -#include -#include - -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 - -namespace spv { -class spirvbin_t : public spirvbin_base_t -{ -public: - spirvbin_t(int /*verbose = 0*/) { } - - void remap(std::vector& /*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 -#include -#include -#include -#include -#include -#include - -#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& spv, std::uint32_t opts = DO_EVERYTHING); - - // Type for error/log handler functions - typedef std::function errorfn_t; - typedef std::function 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 idmap_t; - typedef std::unordered_set idset_t; - - void remap(std::uint32_t opts = DO_EVERYTHING); - - // Map of names to IDs - typedef std::unordered_map namemap_t; - - typedef std::uint32_t spirword_t; - - typedef std::pair range_t; - typedef std::function idfn_t; - typedef std::function 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 typeentry_t; - typedef std::map globaltypes_t; - - // A set that preserves position order, and a reverse map - typedef std::set posmap_t; - typedef std::unordered_map 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 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 spv; // SPIR words - - namemap_t nameMap; // ID names from OpName - - // Since we want to also do binary ops, we can't use std::vector. we could use - // boost::dynamic_bitset, but we're trying to avoid a boost dependency. - typedef std::uint64_t bits_t; - std::vector 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 fnPos; - std::unordered_map fnPosDCE; // deleted functions - - // Which functions are called, anywhere in the module, with a call count - std::unordered_map fnCalls; - - posmap_t typeConstPos; // word positions that define types & consts (ordered) - posmap_rev_t typeConstPosR; // reverse map from IDs to positions - - std::vector 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 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 +#include +#include + +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 + +namespace spv { +class spirvbin_t : public spirvbin_base_t +{ +public: + spirvbin_t(int /*verbose = 0*/) { } + + void remap(std::vector& /*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 +#include +#include +#include +#include +#include +#include + +#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& spv, std::uint32_t opts = DO_EVERYTHING); + + // Type for error/log handler functions + typedef std::function errorfn_t; + typedef std::function 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 idmap_t; + typedef std::unordered_set idset_t; + + void remap(std::uint32_t opts = DO_EVERYTHING); + + // Map of names to IDs + typedef std::unordered_map namemap_t; + + typedef std::uint32_t spirword_t; + + typedef std::pair range_t; + typedef std::function idfn_t; + typedef std::function 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 typeentry_t; + typedef std::map globaltypes_t; + + // A set that preserves position order, and a reverse map + typedef std::set posmap_t; + typedef std::unordered_map 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 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 spv; // SPIR words + + namemap_t nameMap; // ID names from OpName + + // Since we want to also do binary ops, we can't use std::vector. we could use + // boost::dynamic_bitset, but we're trying to avoid a boost dependency. + typedef std::uint64_t bits_t; + std::vector 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 fnPos; + std::unordered_map fnPosDCE; // deleted functions + + // Which functions are called, anywhere in the module, with a call count + std::unordered_map fnCalls; + + posmap_t typeConstPos; // word positions that define types & consts (ordered) + posmap_rev_t typeConstPosR; // reverse map from IDs to positions + + std::vector 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 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 35270b08..f90dd709 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 -#include -#include - -#include "SpvBuilder.h" - -#ifndef _WIN32 - #include -#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& 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& 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& 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& 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 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& 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& 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& 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& 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& 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& 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& 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& 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(value1->getType()); - //if (arrayType) - // numElements = (int)arrayType->getNumElements(); - //else { - // // better be structure - // const llvm::StructType* structType = llvm::dyn_cast(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& 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& 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 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 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& 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 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 matrixColumns; - for (int col = 0; col < numCols; ++col) { - std::vector 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& caseValues, std::vector& valueIndexToSegment, int defaultSegment, - std::vector& 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& 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& /*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& swizzle) -{ - // if needed, propagate the swizzle for the current access chain - if (accessChain.swizzle.size()) { - std::vector 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 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& 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& out, const std::vector& 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 +#include +#include + +#include "SpvBuilder.h" + +#ifndef _WIN32 + #include +#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& 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& 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& 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& 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 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& 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& 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& 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& 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& 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& 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& 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& 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(value1->getType()); + //if (arrayType) + // numElements = (int)arrayType->getNumElements(); + //else { + // // better be structure + // const llvm::StructType* structType = llvm::dyn_cast(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& 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& 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 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 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& 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 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 matrixColumns; + for (int col = 0; col < numCols; ++col) { + std::vector 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& caseValues, std::vector& valueIndexToSegment, int defaultSegment, + std::vector& 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& 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& /*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& swizzle) +{ + // if needed, propagate the swizzle for the current access chain + if (accessChain.swizzle.size()) { + std::vector 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 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& 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& out, const std::vector& 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..4eef5a4c 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 -#include -#include - -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 for anything needing a new one. - Id getUniqueId() { return ++uniqueId; } - - // To get a set of new 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& 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& 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& 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& 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& offsets); - - // Create an OpCompositeExtract instruction - Id createCompositeExtract(Id composite, Id typeId, unsigned index); - Id createCompositeExtract(Id composite, Id typeId, std::vector& indexes); - Id createCompositeInsert(Id object, Id composite, Id typeId, unsigned index); - Id createCompositeInsert(Id object, Id composite, Id typeId, std::vector& 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&); - - // 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& 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& 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& 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& constituents); - - // vector or scalar constructor - Id createConstructor(Decoration precision, const std::vector& sources, Id resultTypeId); - - // matrix constructor - Id createMatrixConstructor(Decoration precision, const std::vector& 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& caseValues, std::vector& valueToSegment, int defaultSegment, - std::vector& 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& segmentBB, int segment); - - // Finish off the innermost switch. - void endSwitch(std::vector& 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 indexChain; - Id instr; // the instruction that generates this access chain - std::vector 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& 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&) 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& 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&, const std::vector&) const; - - SourceLanguage source; - int sourceVersion; - std::vector 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 imports; - std::vector entryPoints; - std::vector executionModes; - std::vector names; - std::vector lines; - std::vector decorations; - std::vector constantsTypesGlobals; - std::vector externals; - - // not output, internally used for quick & dirty canonical (unique) creation - std::vector groupedConstants[OpConstant]; // all types appear before OpConstant - std::vector groupedTypes[OpConstant]; - - // stack of switches - std::stack 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 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 +#include +#include + +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 for anything needing a new one. + Id getUniqueId() { return ++uniqueId; } + + // To get a set of new 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& 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& 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& 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& 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& offsets); + + // Create an OpCompositeExtract instruction + Id createCompositeExtract(Id composite, Id typeId, unsigned index); + Id createCompositeExtract(Id composite, Id typeId, std::vector& indexes); + Id createCompositeInsert(Id object, Id composite, Id typeId, unsigned index); + Id createCompositeInsert(Id object, Id composite, Id typeId, std::vector& 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&); + + // 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& 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& 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& 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& constituents); + + // vector or scalar constructor + Id createConstructor(Decoration precision, const std::vector& sources, Id resultTypeId); + + // matrix constructor + Id createMatrixConstructor(Decoration precision, const std::vector& 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& caseValues, std::vector& valueToSegment, int defaultSegment, + std::vector& 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& segmentBB, int segment); + + // Finish off the innermost switch. + void endSwitch(std::vector& 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 indexChain; + Id instr; // the instruction that generates this access chain + std::vector 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& 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&) 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& 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&, const std::vector&) const; + + SourceLanguage source; + int sourceVersion; + std::vector 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 imports; + std::vector entryPoints; + std::vector executionModes; + std::vector names; + std::vector lines; + std::vector decorations; + std::vector constantsTypesGlobals; + std::vector externals; + + // not output, internally used for quick & dirty canonical (unique) creation + std::vector groupedConstants[OpConstant]; // all types appear before OpConstant + std::vector groupedTypes[OpConstant]; + + // stack of switches + std::stack 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 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 bc8ca880..adbe1acf 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 -#include -#include -#include -#include - -#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& 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& 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 to the instruction that created it - Id bound; - std::vector 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 idDescriptor; // the best text string known for explaining the - - // schema - unsigned int schema; - - // stack of structured-merge points - std::stack 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 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 typeId = 0; - if (InstructionDesc[opCode].hasType()) { - typeId = stream[word++]; - --numOperands; - } - - // Result - 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 "); - - 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 "); - - 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& 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 +#include +#include +#include +#include + +#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& 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& 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 to the instruction that created it + Id bound; + std::vector 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 idDescriptor; // the best text string known for explaining the + + // schema + unsigned int schema; + + // stack of structured-merge points + std::stack 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 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 typeId = 0; + if (InstructionDesc[opCode].hasType()) { + typeId = stream[word++]; + --numOperands; + } + + // Result + 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 "); + + 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 "); + + 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& stream) +{ + SpirvStream SpirvStream(out, stream); + SpirvStream.validate(); + SpirvStream.processInstructions(); +} + +}; // end namespace spv diff --git a/SPIRV/disassemble.h b/SPIRV/disassemble.h index ca8bbb9c..bcb05ef2 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 -#include - -namespace spv { - - void Disassemble(std::ostream& out, const std::vector&); - -}; // 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 +#include + +namespace spv { + + void Disassemble(std::ostream& out, const std::vector&); + +}; // end namespace spv + +#endif // disassembler_H diff --git a/SPIRV/doc.cpp b/SPIRV/doc.cpp index 29658b69..a98ab4d5 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 -#include -#include - -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 and a resulting type . - // (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 <>"); - 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 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 <>"); - - 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 <>."); - - InstructionDesc[OpMemberDecorate].operands.push(OperandId, "'Structure type'"); - InstructionDesc[OpMemberDecorate].operands.push(OperandLiteralNumber, "'Member'"); - InstructionDesc[OpMemberDecorate].operands.push(OperandDecoration, ""); - InstructionDesc[OpMemberDecorate].operands.push(OperandVariableLiterals, "See <>."); - - 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 +#include +#include + +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 and a resulting type . + // (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 <>"); + 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 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 <>"); + + 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 <>."); + + InstructionDesc[OpMemberDecorate].operands.push(OperandId, "'Structure type'"); + InstructionDesc[OpMemberDecorate].operands.push(OperandLiteralNumber, "'Member'"); + InstructionDesc[OpMemberDecorate].operands.push(OperandDecoration, ""); + InstructionDesc[OpMemberDecorate].operands.push(OperandVariableLiterals, "See <>."); + + 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 9059f0e5..ce4d9729 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 - -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 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 opClass; - std::vector 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 + +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 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 opClass; + std::vector 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 f3d18a3f..dc1e579b 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 ec758243..028671d7 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 -#include -#include - -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 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& 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 operands; - std::vector* 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& 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 instructions; - std::vector predecessors; - std::vector 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& 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 parameterInstructions; - std::vector 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& out) const - { - for (int f = 0; f < (int)functions.size(); ++f) - functions[f]->dump(out); - } - -protected: - Module(const Module&); - std::vector functions; - - // map from result id to instruction having that result id - std::vector 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 +#include +#include + +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 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& 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 operands; + std::vector* 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& 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 instructions; + std::vector predecessors; + std::vector 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& 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 parameterInstructions; + std::vector 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& out) const + { + for (int f = 0; f < (int)functions.size(); ++f) + functions[f]->dump(out); + } + +protected: + Module(const Module&); + std::vector functions; + + // map from result id to instruction having that result id + std::vector 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 diff --git a/StandAlone/CMakeLists.txt b/StandAlone/CMakeLists.txt index a5592c82..f5ebab9b 100644 --- a/StandAlone/CMakeLists.txt +++ b/StandAlone/CMakeLists.txt @@ -1,41 +1,41 @@ -cmake_minimum_required(VERSION 2.8) - -include_directories(.) -if(WIN32) - include_directories(../glslang/OSDependent/Windows) -elseif(UNIX) - include_directories(../glslang/OSDependent/Linux) -else(WIN32) - message("unkown platform") -endif(WIN32) - -set(SOURCES StandAlone.cpp) -set(REMAPPER_SOURCES spirv-remap.cpp) - -add_executable(glslangValidator ${SOURCES}) -add_executable(spirv-remap ${REMAPPER_SOURCES}) - -set(LIBRARIES - glslang - OGLCompiler - OSDependent - SPIRV) - -if(WIN32) - set(LIBRARIES ${LIBRARIES} psapi) -elseif(UNIX) - set(LIBRARIES ${LIBRARIES} pthread) -endif(WIN32) - -target_link_libraries(glslangValidator ${LIBRARIES}) -target_link_libraries(spirv-remap ${LIBRARIES}) - -if(WIN32) - source_group("Source" FILES ${SOURCES}) -endif(WIN32) - -install(TARGETS glslangValidator - RUNTIME DESTINATION bin) - -install(TARGETS spirv-remap - RUNTIME DESTINATION bin) +cmake_minimum_required(VERSION 2.8) + +include_directories(.) +if(WIN32) + include_directories(../glslang/OSDependent/Windows) +elseif(UNIX) + include_directories(../glslang/OSDependent/Linux) +else(WIN32) + message("unkown platform") +endif(WIN32) + +set(SOURCES StandAlone.cpp) +set(REMAPPER_SOURCES spirv-remap.cpp) + +add_executable(glslangValidator ${SOURCES}) +add_executable(spirv-remap ${REMAPPER_SOURCES}) + +set(LIBRARIES + glslang + OGLCompiler + OSDependent + SPIRV) + +if(WIN32) + set(LIBRARIES ${LIBRARIES} psapi) +elseif(UNIX) + set(LIBRARIES ${LIBRARIES} pthread) +endif(WIN32) + +target_link_libraries(glslangValidator ${LIBRARIES}) +target_link_libraries(spirv-remap ${LIBRARIES}) + +if(WIN32) + source_group("Source" FILES ${SOURCES}) +endif(WIN32) + +install(TARGETS glslangValidator + RUNTIME DESTINATION bin) + +install(TARGETS spirv-remap + RUNTIME DESTINATION bin) diff --git a/StandAlone/spirv-remap.cpp b/StandAlone/spirv-remap.cpp index b3359a62..301256fc 100644 --- a/StandAlone/spirv-remap.cpp +++ b/StandAlone/spirv-remap.cpp @@ -1,337 +1,337 @@ -// -//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 -#include -#include -#include - -#include "../SPIRV/SPVRemapper.h" - -namespace { - - typedef unsigned int SpvWord; - - // Poor man's basename: given a complete path, return file portion. - // E.g: - // Linux: /foo/bar/test -> test - // Win: c:\foo\bar\test -> test - // It's not very efficient, but that doesn't matter for our minimal-duty use. - // Using boost::filesystem would be better in many ways, but want to avoid that dependency. - - // OS dependent path separator (avoiding boost::filesystem dependency) -#if defined(_WIN32) - char path_sep_char() { return '\\'; } -#else - char path_sep_char() { return '/'; } -#endif - - std::string basename(const std::string filename) - { - const size_t sepLoc = filename.find_last_of(path_sep_char()); - - return (sepLoc == filename.npos) ? filename : filename.substr(sepLoc+1); - } - - void errHandler(const std::string& str) { - std::cout << str << std::endl; - exit(5); - } - - void logHandler(const std::string& str) { - std::cout << str << std::endl; - } - - // Read word stream from disk - void read(std::vector& spv, const std::string& inFilename, int verbosity) - { - std::ifstream fp; - - if (verbosity > 0) - logHandler(std::string(" reading: ") + inFilename); - - spv.clear(); - fp.open(inFilename, std::fstream::in | std::fstream::binary); - - if (fp.fail()) - errHandler("error opening file for read: "); - - // Reserve space (for efficiency, not for correctness) - fp.seekg(0, fp.end); - spv.reserve(size_t(fp.tellg()) / sizeof(SpvWord)); - fp.seekg(0, fp.beg); - - while (!fp.eof()) { - SpvWord inWord; - fp.read((char *)&inWord, sizeof(inWord)); - - if (!fp.eof()) { - spv.push_back(inWord); - if (fp.fail()) - errHandler(std::string("error reading file: ") + inFilename); - } - } - } - - void write(std::vector& spv, const std::string& outFile, int verbosity) - { - if (outFile.empty()) - errHandler("missing output filename."); - - std::ofstream fp; - - if (verbosity > 0) - logHandler(std::string(" writing: ") + outFile); - - fp.open(outFile, std::fstream::out | std::fstream::binary); - - if (fp.fail()) - errHandler(std::string("error opening file for write: ") + outFile); - - for (auto word : spv) { - fp.write((char *)&word, sizeof(word)); - if (fp.fail()) - errHandler(std::string("error writing file: ") + outFile); - } - - // file is closed by destructor - } - - // Print helpful usage message to stdout, and exit - void usage(const char* const name, const char* const msg = 0) - { - if (msg) - std::cout << msg << std::endl << std::endl; - - std::cout << "Usage: " << std::endl; - - std::cout << " " << basename(name) - << " [-v[v[...]] | --verbose [int]]" - << " [--map (all|types|names|funcs)]" - << " [--dce (all|types|funcs)]" - << " [--opt (all|loadstore)]" - << " [--strip-all | --strip all | -s]" - << " [--do-everything]" - << " --input | -i file1 [file2...] --output|-o DESTDIR" - << std::endl; - - std::cout << " " << basename(name) << " [--version | -V]" << std::endl; - std::cout << " " << basename(name) << " [--help | -?]" << std::endl; - - exit(5); - } - - // grind through each SPIR in turn - void execute(const std::vector& inputFile, const std::string& outputDir, - int opts, int verbosity) - { - for (const auto& filename : inputFile) { - std::vector spv; - read(spv, filename, verbosity); - spv::spirvbin_t(verbosity).remap(spv, opts); - - const std::string outfile = outputDir + path_sep_char() + basename(filename); - - write(spv, outfile, verbosity); - } - - if (verbosity > 0) - std::cout << "Done: " << inputFile.size() << " file(s) processed" << std::endl; - } - - // Parse command line options - void parseCmdLine(int argc, char** argv, std::vector& inputFile, - std::string& outputDir, - int& options, - int& verbosity) - { - if (argc < 2) - usage(argv[0]); - - verbosity = 0; - options = spv::spirvbin_t::NONE; - - // Parse command line. - // boost::program_options would be quite a bit nicer, but we don't want to - // introduce a dependency on boost. - for (int a=1; a= argc) - usage(argv[0], "--output requires an argument"); - if (!outputDir.empty()) - usage(argv[0], "--output can be provided only once"); - - outputDir = argv[a++]; - - // Remove trailing directory separator characters - while (!outputDir.empty() && outputDir.back() == path_sep_char()) - outputDir.pop_back(); - - } - else if (arg == "-vv") { verbosity = 2; ++a; } // verbosity shortcuts - else if (arg == "-vvv") { verbosity = 3; ++a; } // ... - else if (arg == "-vvvv") { verbosity = 4; ++a; } // ... - else if (arg == "-vvvvv") { verbosity = 5; ++a; } // ... - - else if (arg == "--verbose" || arg == "-v") { - ++a; - verbosity = 1; - - if (a < argc) { - try { - verbosity = std::stoi(argv[a]); - ++a; - } catch (const std::invalid_argument&) { } // ok to have no numeric value - } - } - else if (arg == "--version" || arg == "-V") { - std::cout << basename(argv[0]) << " version 0.97 " << __DATE__ << " " << __TIME__ << std::endl; - exit(0); - } else if (arg == "--input" || arg == "-i") { - // Collect input files - for (++a; a < argc && argv[a][0] != '-'; ++a) - inputFile.push_back(argv[a]); - } else if (arg == "--do-everything") { - ++a; - options = options | spv::spirvbin_t::DO_EVERYTHING; - } else if (arg == "--strip-all" || arg == "-s") { - ++a; - options = options | spv::spirvbin_t::STRIP; - } else if (arg == "--strip") { - ++a; - if (strncmp(argv[a], "all", 3) == 0) { - options = options | spv::spirvbin_t::STRIP; - ++a; - } - } else if (arg == "--dce") { - // Parse comma (or colon, etc) separated list of things to dce - ++a; - for (const char* c = argv[a]; *c; ++c) { - if (strncmp(c, "all", 3) == 0) { - options = (options | spv::spirvbin_t::DCE_ALL); - c += 3; - } else if (strncmp(c, "*", 1) == 0) { - options = (options | spv::spirvbin_t::DCE_ALL); - c += 1; - } else if (strncmp(c, "funcs", 5) == 0) { - options = (options | spv::spirvbin_t::DCE_FUNCS); - c += 5; - } else if (strncmp(c, "types", 5) == 0) { - options = (options | spv::spirvbin_t::DCE_TYPES); - c += 5; - } - } - ++a; - } else if (arg == "--map") { - // Parse comma (or colon, etc) separated list of things to map - ++a; - for (const char* c = argv[a]; *c; ++c) { - if (strncmp(c, "all", 3) == 0) { - options = (options | spv::spirvbin_t::MAP_ALL); - c += 3; - } else if (strncmp(c, "*", 1) == 0) { - options = (options | spv::spirvbin_t::MAP_ALL); - c += 1; - } else if (strncmp(c, "types", 5) == 0) { - options = (options | spv::spirvbin_t::MAP_TYPES); - c += 5; - } else if (strncmp(c, "names", 5) == 0) { - options = (options | spv::spirvbin_t::MAP_NAMES); - c += 5; - } else if (strncmp(c, "funcs", 5) == 0) { - options = (options | spv::spirvbin_t::MAP_FUNCS); - c += 5; - } - } - ++a; - } else if (arg == "--opt") { - ++a; - for (const char* c = argv[a]; *c; ++c) { - if (strncmp(c, "all", 3) == 0) { - options = (options | spv::spirvbin_t::OPT_ALL); - c += 3; - } else if (strncmp(c, "*", 1) == 0) { - options = (options | spv::spirvbin_t::OPT_ALL); - c += 1; - } else if (strncmp(c, "loadstore", 9) == 0) { - options = (options | spv::spirvbin_t::OPT_LOADSTORE); - c += 9; - } - } - ++a; - } else if (arg == "--help" || arg == "-?") { - usage(argv[0]); - } else { - usage(argv[0], "Unknown command line option"); - } - } - } - -} // namespace - - -int main(int argc, char** argv) -{ - std::vector inputFile; - std::string outputDir; - int opts; - int verbosity; - -#ifdef use_cpp11 - // handle errors by exiting - spv::spirvbin_t::registerErrorHandler(errHandler); - - // Log messages to std::cout - spv::spirvbin_t::registerLogHandler(logHandler); -#endif - - if (argc < 2) - usage(argv[0]); - - parseCmdLine(argc, argv, inputFile, outputDir, opts, verbosity); - - if (outputDir.empty()) - usage(argv[0], "Output directory required"); - - std::string errmsg; - - // Main operations: read, remap, and write. - execute(inputFile, outputDir, opts, verbosity); - - // If we get here, everything went OK! Nothing more to be done. -} +// +//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 +#include +#include +#include + +#include "../SPIRV/SPVRemapper.h" + +namespace { + + typedef unsigned int SpvWord; + + // Poor man's basename: given a complete path, return file portion. + // E.g: + // Linux: /foo/bar/test -> test + // Win: c:\foo\bar\test -> test + // It's not very efficient, but that doesn't matter for our minimal-duty use. + // Using boost::filesystem would be better in many ways, but want to avoid that dependency. + + // OS dependent path separator (avoiding boost::filesystem dependency) +#if defined(_WIN32) + char path_sep_char() { return '\\'; } +#else + char path_sep_char() { return '/'; } +#endif + + std::string basename(const std::string filename) + { + const size_t sepLoc = filename.find_last_of(path_sep_char()); + + return (sepLoc == filename.npos) ? filename : filename.substr(sepLoc+1); + } + + void errHandler(const std::string& str) { + std::cout << str << std::endl; + exit(5); + } + + void logHandler(const std::string& str) { + std::cout << str << std::endl; + } + + // Read word stream from disk + void read(std::vector& spv, const std::string& inFilename, int verbosity) + { + std::ifstream fp; + + if (verbosity > 0) + logHandler(std::string(" reading: ") + inFilename); + + spv.clear(); + fp.open(inFilename, std::fstream::in | std::fstream::binary); + + if (fp.fail()) + errHandler("error opening file for read: "); + + // Reserve space (for efficiency, not for correctness) + fp.seekg(0, fp.end); + spv.reserve(size_t(fp.tellg()) / sizeof(SpvWord)); + fp.seekg(0, fp.beg); + + while (!fp.eof()) { + SpvWord inWord; + fp.read((char *)&inWord, sizeof(inWord)); + + if (!fp.eof()) { + spv.push_back(inWord); + if (fp.fail()) + errHandler(std::string("error reading file: ") + inFilename); + } + } + } + + void write(std::vector& spv, const std::string& outFile, int verbosity) + { + if (outFile.empty()) + errHandler("missing output filename."); + + std::ofstream fp; + + if (verbosity > 0) + logHandler(std::string(" writing: ") + outFile); + + fp.open(outFile, std::fstream::out | std::fstream::binary); + + if (fp.fail()) + errHandler(std::string("error opening file for write: ") + outFile); + + for (auto word : spv) { + fp.write((char *)&word, sizeof(word)); + if (fp.fail()) + errHandler(std::string("error writing file: ") + outFile); + } + + // file is closed by destructor + } + + // Print helpful usage message to stdout, and exit + void usage(const char* const name, const char* const msg = 0) + { + if (msg) + std::cout << msg << std::endl << std::endl; + + std::cout << "Usage: " << std::endl; + + std::cout << " " << basename(name) + << " [-v[v[...]] | --verbose [int]]" + << " [--map (all|types|names|funcs)]" + << " [--dce (all|types|funcs)]" + << " [--opt (all|loadstore)]" + << " [--strip-all | --strip all | -s]" + << " [--do-everything]" + << " --input | -i file1 [file2...] --output|-o DESTDIR" + << std::endl; + + std::cout << " " << basename(name) << " [--version | -V]" << std::endl; + std::cout << " " << basename(name) << " [--help | -?]" << std::endl; + + exit(5); + } + + // grind through each SPIR in turn + void execute(const std::vector& inputFile, const std::string& outputDir, + int opts, int verbosity) + { + for (const auto& filename : inputFile) { + std::vector spv; + read(spv, filename, verbosity); + spv::spirvbin_t(verbosity).remap(spv, opts); + + const std::string outfile = outputDir + path_sep_char() + basename(filename); + + write(spv, outfile, verbosity); + } + + if (verbosity > 0) + std::cout << "Done: " << inputFile.size() << " file(s) processed" << std::endl; + } + + // Parse command line options + void parseCmdLine(int argc, char** argv, std::vector& inputFile, + std::string& outputDir, + int& options, + int& verbosity) + { + if (argc < 2) + usage(argv[0]); + + verbosity = 0; + options = spv::spirvbin_t::NONE; + + // Parse command line. + // boost::program_options would be quite a bit nicer, but we don't want to + // introduce a dependency on boost. + for (int a=1; a= argc) + usage(argv[0], "--output requires an argument"); + if (!outputDir.empty()) + usage(argv[0], "--output can be provided only once"); + + outputDir = argv[a++]; + + // Remove trailing directory separator characters + while (!outputDir.empty() && outputDir.back() == path_sep_char()) + outputDir.pop_back(); + + } + else if (arg == "-vv") { verbosity = 2; ++a; } // verbosity shortcuts + else if (arg == "-vvv") { verbosity = 3; ++a; } // ... + else if (arg == "-vvvv") { verbosity = 4; ++a; } // ... + else if (arg == "-vvvvv") { verbosity = 5; ++a; } // ... + + else if (arg == "--verbose" || arg == "-v") { + ++a; + verbosity = 1; + + if (a < argc) { + try { + verbosity = std::stoi(argv[a]); + ++a; + } catch (const std::invalid_argument&) { } // ok to have no numeric value + } + } + else if (arg == "--version" || arg == "-V") { + std::cout << basename(argv[0]) << " version 0.97 " << __DATE__ << " " << __TIME__ << std::endl; + exit(0); + } else if (arg == "--input" || arg == "-i") { + // Collect input files + for (++a; a < argc && argv[a][0] != '-'; ++a) + inputFile.push_back(argv[a]); + } else if (arg == "--do-everything") { + ++a; + options = options | spv::spirvbin_t::DO_EVERYTHING; + } else if (arg == "--strip-all" || arg == "-s") { + ++a; + options = options | spv::spirvbin_t::STRIP; + } else if (arg == "--strip") { + ++a; + if (strncmp(argv[a], "all", 3) == 0) { + options = options | spv::spirvbin_t::STRIP; + ++a; + } + } else if (arg == "--dce") { + // Parse comma (or colon, etc) separated list of things to dce + ++a; + for (const char* c = argv[a]; *c; ++c) { + if (strncmp(c, "all", 3) == 0) { + options = (options | spv::spirvbin_t::DCE_ALL); + c += 3; + } else if (strncmp(c, "*", 1) == 0) { + options = (options | spv::spirvbin_t::DCE_ALL); + c += 1; + } else if (strncmp(c, "funcs", 5) == 0) { + options = (options | spv::spirvbin_t::DCE_FUNCS); + c += 5; + } else if (strncmp(c, "types", 5) == 0) { + options = (options | spv::spirvbin_t::DCE_TYPES); + c += 5; + } + } + ++a; + } else if (arg == "--map") { + // Parse comma (or colon, etc) separated list of things to map + ++a; + for (const char* c = argv[a]; *c; ++c) { + if (strncmp(c, "all", 3) == 0) { + options = (options | spv::spirvbin_t::MAP_ALL); + c += 3; + } else if (strncmp(c, "*", 1) == 0) { + options = (options | spv::spirvbin_t::MAP_ALL); + c += 1; + } else if (strncmp(c, "types", 5) == 0) { + options = (options | spv::spirvbin_t::MAP_TYPES); + c += 5; + } else if (strncmp(c, "names", 5) == 0) { + options = (options | spv::spirvbin_t::MAP_NAMES); + c += 5; + } else if (strncmp(c, "funcs", 5) == 0) { + options = (options | spv::spirvbin_t::MAP_FUNCS); + c += 5; + } + } + ++a; + } else if (arg == "--opt") { + ++a; + for (const char* c = argv[a]; *c; ++c) { + if (strncmp(c, "all", 3) == 0) { + options = (options | spv::spirvbin_t::OPT_ALL); + c += 3; + } else if (strncmp(c, "*", 1) == 0) { + options = (options | spv::spirvbin_t::OPT_ALL); + c += 1; + } else if (strncmp(c, "loadstore", 9) == 0) { + options = (options | spv::spirvbin_t::OPT_LOADSTORE); + c += 9; + } + } + ++a; + } else if (arg == "--help" || arg == "-?") { + usage(argv[0]); + } else { + usage(argv[0], "Unknown command line option"); + } + } + } + +} // namespace + + +int main(int argc, char** argv) +{ + std::vector inputFile; + std::string outputDir; + int opts; + int verbosity; + +#ifdef use_cpp11 + // handle errors by exiting + spv::spirvbin_t::registerErrorHandler(errHandler); + + // Log messages to std::cout + spv::spirvbin_t::registerLogHandler(logHandler); +#endif + + if (argc < 2) + usage(argv[0]); + + parseCmdLine(argc, argv, inputFile, outputDir, opts, verbosity); + + if (outputDir.empty()) + usage(argv[0], "Output directory required"); + + std::string errmsg; + + // Main operations: read, remap, and write. + execute(inputFile, outputDir, opts, verbosity); + + // If we get here, everything went OK! Nothing more to be done. +}