Final round for line endings.
authorJohn Kessenich <cepheus@frii.com>
Fri, 26 Jun 2015 22:58:36 +0000 (16:58 -0600)
committerJohn Kessenich <cepheus@frii.com>
Fri, 26 Jun 2015 22:58:36 +0000 (16:58 -0600)
19 files changed:
Install/Linux/README.txt
Install/Windows/README.txt
OGLCompilersDLL/CMakeLists.txt
SPIRV/CMakeLists.txt
SPIRV/GLSL450Lib.h
SPIRV/GlslangToSpv.cpp
SPIRV/GlslangToSpv.h
SPIRV/SPVRemapper.cpp
SPIRV/SPVRemapper.h
SPIRV/SpvBuilder.cpp
SPIRV/SpvBuilder.h
SPIRV/disassemble.cpp
SPIRV/disassemble.h
SPIRV/doc.cpp
SPIRV/doc.h
SPIRV/spirv.h
SPIRV/spvIR.h
StandAlone/CMakeLists.txt
StandAlone/spirv-remap.cpp

index 9bd0664..aefc9fd 100644 (file)
@@ -1,6 +1,6 @@
-This directory contains a Linux binary for the glslang validator.\r
-\r
-Installation: The executable in this directory is self sufficient, and can be \r
-placed where desired; in a test directory, or in a system path, etc.\r
-\r
-Usage:  Execute glslangValidator with no arguments to get a usage statement.\r
+This directory contains a Linux binary for the glslang validator.
+
+Installation: The executable in this directory is self sufficient, and can be 
+placed where desired; in a test directory, or in a system path, etc.
+
+Usage:  Execute glslangValidator with no arguments to get a usage statement.
index ee673f3..bde97b9 100644 (file)
@@ -1,6 +1,6 @@
-This directory contains a Windows binary for the glslang validator.\r
-\r
-Installation: The executable in this directory is self sufficient, and can be \r
-placed where desired; in a test directory, or in a system path, etc.\r
-\r
-Usage:  Execute glslangValidator with no arguments to get a usage statement.\r
+This directory contains a Windows binary for the glslang validator.
+
+Installation: The executable in this directory is self sufficient, and can be 
+placed where desired; in a test directory, or in a system path, etc.
+
+Usage:  Execute glslangValidator with no arguments to get a usage statement.
index 6ade8ca..afabe75 100644 (file)
@@ -1,21 +1,21 @@
-cmake_minimum_required(VERSION 2.8)\r
-\r
-include_directories(. ../glslang)\r
-if(WIN32)\r
-    include_directories(${include_directories} ../glslang/OSDependent/Windows)\r
-elseif(UNIX)\r
-    include_directories(${include_directories} ../glslang/OSDependent/Linux)\r
-else(WIN32)\r
-    message("unknown platform")\r
-endif(WIN32)\r
-\r
-set(SOURCES InitializeDll.cpp InitializeDll.h)\r
-\r
-add_library(OGLCompiler STATIC ${SOURCES})\r
-\r
-if(WIN32)\r
-    source_group("Source" FILES ${SOURCES})\r
-endif(WIN32)\r
-\r
-install(TARGETS OGLCompiler \r
-        ARCHIVE DESTINATION lib)\r
+cmake_minimum_required(VERSION 2.8)
+
+include_directories(. ../glslang)
+if(WIN32)
+    include_directories(${include_directories} ../glslang/OSDependent/Windows)
+elseif(UNIX)
+    include_directories(${include_directories} ../glslang/OSDependent/Linux)
+else(WIN32)
+    message("unknown platform")
+endif(WIN32)
+
+set(SOURCES InitializeDll.cpp InitializeDll.h)
+
+add_library(OGLCompiler STATIC ${SOURCES})
+
+if(WIN32)
+    source_group("Source" FILES ${SOURCES})
+endif(WIN32)
+
+install(TARGETS OGLCompiler 
+        ARCHIVE DESTINATION lib)
index 3bc149f..6bb140b 100644 (file)
@@ -1,28 +1,28 @@
-cmake_minimum_required(VERSION 2.8)\r
-\r
-include_directories(.. ${CMAKE_CURRENT_BINARY_DIR})\r
-\r
-set(SOURCES\r
-    GlslangToSpv.cpp\r
-    SpvBuilder.cpp\r
-    SPVRemapper.cpp\r
-    doc.cpp\r
-    disassemble.cpp)\r
-\r
-set(HEADERS\r
-    spirv.h\r
-    GlslangToSpv.h\r
-    SpvBuilder.h\r
-    SPVRemapper.h\r
-    spvIR.h\r
-    doc.h\r
-    disassemble.h)\r
-\r
-add_library(SPIRV STATIC ${SOURCES} ${HEADERS})\r
-\r
-if(WIN32)\r
-    source_group("Source" FILES ${SOURCES} ${HEADERS})\r
-endif(WIN32)\r
-\r
-install(TARGETS SPIRV\r
-        ARCHIVE DESTINATION lib)\r
+cmake_minimum_required(VERSION 2.8)
+
+include_directories(.. ${CMAKE_CURRENT_BINARY_DIR})
+
+set(SOURCES
+    GlslangToSpv.cpp
+    SpvBuilder.cpp
+    SPVRemapper.cpp
+    doc.cpp
+    disassemble.cpp)
+
+set(HEADERS
+    spirv.h
+    GlslangToSpv.h
+    SpvBuilder.h
+    SPVRemapper.h
+    spvIR.h
+    doc.h
+    disassemble.h)
+
+add_library(SPIRV STATIC ${SOURCES} ${HEADERS})
+
+if(WIN32)
+    source_group("Source" FILES ${SOURCES} ${HEADERS})
+endif(WIN32)
+
+install(TARGETS SPIRV
+        ARCHIVE DESTINATION lib)
index 7565d8a..32f4563 100644 (file)
-/*\r
-** Copyright (c) 2014-2015 The Khronos Group Inc.\r
-**\r
-** Permission is hereby granted, free of charge, to any person obtaining a\r
-** copy of this software and/or associated documentation files (the\r
-** "Materials"), to deal in the Materials without restriction, including\r
-** without limitation the rights to use, copy, modify, merge, publish,\r
-** distribute, sublicense, and/or sell copies of the Materials, and to\r
-** permit persons to whom the Materials are furnished to do so, subject to\r
-** the following conditions:\r
-**\r
-** The above copyright notice and this permission notice shall be included\r
-** in all copies or substantial portions of the Materials.\r
-**\r
-** THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
-** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
-** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\r
-** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY\r
-** CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,\r
-** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE\r
-** MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.\r
-*/\r
-\r
-//\r
-// Author: John Kessenich, LunarG\r
-//\r
-\r
-namespace GLSL_STD_450 {\r
-\r
-enum Entrypoints {\r
-    Round = 0,\r
-    RoundEven = 1,\r
-    Trunc = 2,\r
-    Abs = 3,\r
-    Sign = 4,\r
-    Floor = 5,\r
-    Ceil = 6,\r
-    Fract = 7,\r
-\r
-    Radians = 8,\r
-    Degrees = 9,\r
-    Sin = 10,\r
-    Cos = 11,\r
-    Tan = 12,\r
-    Asin = 13,\r
-    Acos = 14,\r
-    Atan = 15,\r
-    Sinh = 16,\r
-    Cosh = 17,\r
-    Tanh = 18,\r
-    Asinh = 19,\r
-    Acosh = 20,\r
-    Atanh = 21,\r
-    Atan2 = 22,\r
-\r
-    Pow = 23,\r
-    Exp = 24,\r
-    Log = 25,\r
-    Exp2 = 26,\r
-    Log2 = 27,\r
-    Sqrt = 28,\r
-    InverseSqrt = 29,\r
-\r
-    Determinant = 30,\r
-    MatrixInverse = 31,\r
-\r
-    Modf = 32,            // second argument needs the OpVariable = , not an OpLoad\r
-    Min = 33,\r
-    Max = 34,\r
-    Clamp = 35,\r
-    Mix = 36,\r
-    Step = 37,\r
-    SmoothStep = 38,\r
-\r
-    FloatBitsToInt = 39,\r
-    FloatBitsToUint = 40,\r
-    IntBitsToFloat = 41,\r
-    UintBitsToFloat = 42,\r
-\r
-    Fma = 43,\r
-    Frexp = 44,\r
-    Ldexp = 45,\r
-\r
-    PackSnorm4x8 = 46,\r
-    PackUnorm4x8 = 47,\r
-    PackSnorm2x16 = 48,\r
-    PackUnorm2x16 = 49,\r
-    PackHalf2x16 = 50,\r
-    PackDouble2x32 = 51,\r
-    UnpackSnorm2x16 = 52,\r
-    UnpackUnorm2x16 = 53,\r
-    UnpackHalf2x16 = 54,\r
-    UnpackSnorm4x8 = 55,\r
-    UnpackUnorm4x8 = 56,\r
-    UnpackDouble2x32 = 57,\r
-\r
-    Length = 58,\r
-    Distance = 59,\r
-    Cross = 60,\r
-    Normalize = 61,\r
-    Ftransform = 62,\r
-    FaceForward = 63,\r
-    Reflect = 64,\r
-    Refract = 65,\r
-\r
-    UaddCarry = 66,\r
-    UsubBorrow = 67,\r
-    UmulExtended = 68,\r
-    ImulExtended = 69,\r
-    BitfieldExtract = 70,\r
-    BitfieldInsert = 71,\r
-    BitfieldReverse = 72,\r
-    BitCount = 73,\r
-    FindLSB = 74,\r
-    FindMSB = 75,\r
-\r
-    InterpolateAtCentroid = 76,\r
-    InterpolateAtSample = 77,\r
-    InterpolateAtOffset = 78,\r
-\r
-    Count\r
-};\r
-\r
-inline void GetDebugNames(const char** names)\r
-{\r
-    for (int i = 0; i < Count; ++i)\r
-        names[i] = "Unknown";\r
-\r
-    names[Round]                   = "round";\r
-    names[RoundEven]               = "roundEven";\r
-    names[Trunc]                   = "trunc";\r
-    names[Abs]                     = "abs";\r
-    names[Sign]                    = "sign";\r
-    names[Floor]                   = "floor";\r
-    names[Ceil]                    = "ceil";\r
-    names[Fract]                   = "fract";\r
-    names[Radians]                 = "radians";\r
-    names[Degrees]                 = "degrees";\r
-    names[Sin]                     = "sin";\r
-    names[Cos]                     = "cos";\r
-    names[Tan]                     = "tan";\r
-    names[Asin]                    = "asin";\r
-    names[Acos]                    = "acos";\r
-    names[Atan]                    = "atan";\r
-    names[Sinh]                    = "sinh";\r
-    names[Cosh]                    = "cosh";\r
-    names[Tanh]                    = "tanh";\r
-    names[Asinh]                   = "asinh";\r
-    names[Acosh]                   = "acosh";\r
-    names[Atanh]                   = "atanh";\r
-    names[Atan2]                   = "atan2";\r
-    names[Pow]                     = "pow";\r
-    names[Exp]                     = "exp";\r
-    names[Log]                     = "log";\r
-    names[Exp2]                    = "exp2";\r
-    names[Log2]                    = "log2";\r
-    names[Sqrt]                    = "sqrt";\r
-    names[InverseSqrt]             = "inverseSqrt";\r
-    names[Determinant]             = "determinant";\r
-    names[MatrixInverse]           = "matrixInverse";\r
-    names[Modf]                    = "modf";\r
-    names[Min]                     = "min";\r
-    names[Max]                     = "max";\r
-    names[Clamp]                   = "clamp";\r
-    names[Mix]                     = "mix";\r
-    names[Step]                    = "step";\r
-    names[SmoothStep]              = "smoothStep";\r
-    names[FloatBitsToInt]          = "floatBitsToInt";\r
-    names[FloatBitsToUint]         = "floatBitsToUint";\r
-    names[IntBitsToFloat]          = "intBitsToFloat";\r
-    names[UintBitsToFloat]         = "uintBitsToFloat";\r
-    names[Fma]                     = "fma";\r
-    names[Frexp]                   = "frexp";\r
-    names[Ldexp]                   = "ldexp";\r
-    names[PackSnorm4x8]            = "packSnorm4x8";\r
-    names[PackUnorm4x8]            = "packUnorm4x8";\r
-    names[PackSnorm2x16]           = "packSnorm2x16";\r
-    names[PackUnorm2x16]           = "packUnorm2x16";\r
-    names[PackHalf2x16]            = "packHalf2x16";\r
-    names[PackDouble2x32]          = "packDouble2x32";\r
-    names[UnpackSnorm2x16]         = "unpackSnorm2x16";\r
-    names[UnpackUnorm2x16]         = "unpackUnorm2x16";\r
-    names[UnpackHalf2x16]          = "unpackHalf2x16";\r
-    names[UnpackSnorm4x8]          = "unpackSnorm4x8";\r
-    names[UnpackUnorm4x8]          = "unpackUnorm4x8";\r
-    names[UnpackDouble2x32]        = "unpackDouble2x32";\r
-    names[Length]                  = "length";\r
-    names[Distance]                = "distance";\r
-    names[Cross]                   = "cross";\r
-    names[Normalize]               = "normalize";\r
-    names[Ftransform]              = "ftransform";\r
-    names[FaceForward]             = "faceForward";\r
-    names[Reflect]                 = "reflect";\r
-    names[Refract]                 = "refract";\r
-    names[UaddCarry]               = "uaddCarry";\r
-    names[UsubBorrow]              = "usubBorrow";\r
-    names[UmulExtended]            = "umulExtended";\r
-    names[ImulExtended]            = "imulExtended";\r
-    names[BitfieldExtract]         = "bitfieldExtract";\r
-    names[BitfieldInsert]          = "bitfieldInsert";\r
-    names[BitfieldReverse]         = "bitfieldReverse";\r
-    names[BitCount]                = "bitCount";\r
-    names[FindLSB]                 = "findLSB";\r
-    names[FindMSB]                 = "findMSB";\r
-    names[InterpolateAtCentroid]   = "interpolateAtCentroid";\r
-    names[InterpolateAtSample]     = "interpolateAtSample";\r
-    names[InterpolateAtOffset]     = "interpolateAtOffset";\r
-}\r
-\r
-}; // end namespace GLSL_STD_450\r
+/*
+** Copyright (c) 2014-2015 The Khronos Group Inc.
+**
+** Permission is hereby granted, free of charge, to any person obtaining a
+** copy of this software and/or associated documentation files (the
+** "Materials"), to deal in the Materials without restriction, including
+** without limitation the rights to use, copy, modify, merge, publish,
+** distribute, sublicense, and/or sell copies of the Materials, and to
+** permit persons to whom the Materials are furnished to do so, subject to
+** the following conditions:
+**
+** The above copyright notice and this permission notice shall be included
+** in all copies or substantial portions of the Materials.
+**
+** THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+** CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+** MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
+*/
+
+//
+// Author: John Kessenich, LunarG
+//
+
+namespace GLSL_STD_450 {
+
+enum Entrypoints {
+    Round = 0,
+    RoundEven = 1,
+    Trunc = 2,
+    Abs = 3,
+    Sign = 4,
+    Floor = 5,
+    Ceil = 6,
+    Fract = 7,
+
+    Radians = 8,
+    Degrees = 9,
+    Sin = 10,
+    Cos = 11,
+    Tan = 12,
+    Asin = 13,
+    Acos = 14,
+    Atan = 15,
+    Sinh = 16,
+    Cosh = 17,
+    Tanh = 18,
+    Asinh = 19,
+    Acosh = 20,
+    Atanh = 21,
+    Atan2 = 22,
+
+    Pow = 23,
+    Exp = 24,
+    Log = 25,
+    Exp2 = 26,
+    Log2 = 27,
+    Sqrt = 28,
+    InverseSqrt = 29,
+
+    Determinant = 30,
+    MatrixInverse = 31,
+
+    Modf = 32,            // second argument needs the OpVariable = , not an OpLoad
+    Min = 33,
+    Max = 34,
+    Clamp = 35,
+    Mix = 36,
+    Step = 37,
+    SmoothStep = 38,
+
+    FloatBitsToInt = 39,
+    FloatBitsToUint = 40,
+    IntBitsToFloat = 41,
+    UintBitsToFloat = 42,
+
+    Fma = 43,
+    Frexp = 44,
+    Ldexp = 45,
+
+    PackSnorm4x8 = 46,
+    PackUnorm4x8 = 47,
+    PackSnorm2x16 = 48,
+    PackUnorm2x16 = 49,
+    PackHalf2x16 = 50,
+    PackDouble2x32 = 51,
+    UnpackSnorm2x16 = 52,
+    UnpackUnorm2x16 = 53,
+    UnpackHalf2x16 = 54,
+    UnpackSnorm4x8 = 55,
+    UnpackUnorm4x8 = 56,
+    UnpackDouble2x32 = 57,
+
+    Length = 58,
+    Distance = 59,
+    Cross = 60,
+    Normalize = 61,
+    Ftransform = 62,
+    FaceForward = 63,
+    Reflect = 64,
+    Refract = 65,
+
+    UaddCarry = 66,
+    UsubBorrow = 67,
+    UmulExtended = 68,
+    ImulExtended = 69,
+    BitfieldExtract = 70,
+    BitfieldInsert = 71,
+    BitfieldReverse = 72,
+    BitCount = 73,
+    FindLSB = 74,
+    FindMSB = 75,
+
+    InterpolateAtCentroid = 76,
+    InterpolateAtSample = 77,
+    InterpolateAtOffset = 78,
+
+    Count
+};
+
+inline void GetDebugNames(const char** names)
+{
+    for (int i = 0; i < Count; ++i)
+        names[i] = "Unknown";
+
+    names[Round]                   = "round";
+    names[RoundEven]               = "roundEven";
+    names[Trunc]                   = "trunc";
+    names[Abs]                     = "abs";
+    names[Sign]                    = "sign";
+    names[Floor]                   = "floor";
+    names[Ceil]                    = "ceil";
+    names[Fract]                   = "fract";
+    names[Radians]                 = "radians";
+    names[Degrees]                 = "degrees";
+    names[Sin]                     = "sin";
+    names[Cos]                     = "cos";
+    names[Tan]                     = "tan";
+    names[Asin]                    = "asin";
+    names[Acos]                    = "acos";
+    names[Atan]                    = "atan";
+    names[Sinh]                    = "sinh";
+    names[Cosh]                    = "cosh";
+    names[Tanh]                    = "tanh";
+    names[Asinh]                   = "asinh";
+    names[Acosh]                   = "acosh";
+    names[Atanh]                   = "atanh";
+    names[Atan2]                   = "atan2";
+    names[Pow]                     = "pow";
+    names[Exp]                     = "exp";
+    names[Log]                     = "log";
+    names[Exp2]                    = "exp2";
+    names[Log2]                    = "log2";
+    names[Sqrt]                    = "sqrt";
+    names[InverseSqrt]             = "inverseSqrt";
+    names[Determinant]             = "determinant";
+    names[MatrixInverse]           = "matrixInverse";
+    names[Modf]                    = "modf";
+    names[Min]                     = "min";
+    names[Max]                     = "max";
+    names[Clamp]                   = "clamp";
+    names[Mix]                     = "mix";
+    names[Step]                    = "step";
+    names[SmoothStep]              = "smoothStep";
+    names[FloatBitsToInt]          = "floatBitsToInt";
+    names[FloatBitsToUint]         = "floatBitsToUint";
+    names[IntBitsToFloat]          = "intBitsToFloat";
+    names[UintBitsToFloat]         = "uintBitsToFloat";
+    names[Fma]                     = "fma";
+    names[Frexp]                   = "frexp";
+    names[Ldexp]                   = "ldexp";
+    names[PackSnorm4x8]            = "packSnorm4x8";
+    names[PackUnorm4x8]            = "packUnorm4x8";
+    names[PackSnorm2x16]           = "packSnorm2x16";
+    names[PackUnorm2x16]           = "packUnorm2x16";
+    names[PackHalf2x16]            = "packHalf2x16";
+    names[PackDouble2x32]          = "packDouble2x32";
+    names[UnpackSnorm2x16]         = "unpackSnorm2x16";
+    names[UnpackUnorm2x16]         = "unpackUnorm2x16";
+    names[UnpackHalf2x16]          = "unpackHalf2x16";
+    names[UnpackSnorm4x8]          = "unpackSnorm4x8";
+    names[UnpackUnorm4x8]          = "unpackUnorm4x8";
+    names[UnpackDouble2x32]        = "unpackDouble2x32";
+    names[Length]                  = "length";
+    names[Distance]                = "distance";
+    names[Cross]                   = "cross";
+    names[Normalize]               = "normalize";
+    names[Ftransform]              = "ftransform";
+    names[FaceForward]             = "faceForward";
+    names[Reflect]                 = "reflect";
+    names[Refract]                 = "refract";
+    names[UaddCarry]               = "uaddCarry";
+    names[UsubBorrow]              = "usubBorrow";
+    names[UmulExtended]            = "umulExtended";
+    names[ImulExtended]            = "imulExtended";
+    names[BitfieldExtract]         = "bitfieldExtract";
+    names[BitfieldInsert]          = "bitfieldInsert";
+    names[BitfieldReverse]         = "bitfieldReverse";
+    names[BitCount]                = "bitCount";
+    names[FindLSB]                 = "findLSB";
+    names[FindMSB]                 = "findMSB";
+    names[InterpolateAtCentroid]   = "interpolateAtCentroid";
+    names[InterpolateAtSample]     = "interpolateAtSample";
+    names[InterpolateAtOffset]     = "interpolateAtOffset";
+}
+
+}; // end namespace GLSL_STD_450
index 969c091..8cdc032 100644 (file)
-//\r
-//Copyright (C) 2014 LunarG, Inc.\r
-//\r
-//All rights reserved.\r
-//\r
-//Redistribution and use in source and binary forms, with or without\r
-//modification, are permitted provided that the following conditions\r
-//are met:\r
-//\r
-//    Redistributions of source code must retain the above copyright\r
-//    notice, this list of conditions and the following disclaimer.\r
-//\r
-//    Redistributions in binary form must reproduce the above\r
-//    copyright notice, this list of conditions and the following\r
-//    disclaimer in the documentation and/or other materials provided\r
-//    with the distribution.\r
-//\r
-//    Neither the name of 3Dlabs Inc. Ltd. nor the names of its\r
-//    contributors may be used to endorse or promote products derived\r
-//    from this software without specific prior written permission.\r
-//\r
-//THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\r
-//"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\r
-//LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS\r
-//FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE\r
-//COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,\r
-//INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,\r
-//BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\r
-//LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER\r
-//CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\r
-//LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN\r
-//ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE\r
-//POSSIBILITY OF SUCH DAMAGE.\r
-\r
-//\r
-// Author: John Kessenich, LunarG\r
-//\r
-// Visit the nodes in the glslang intermediate tree representation to\r
-// translate them to SPIR-V.\r
-//\r
-\r
-#include "spirv.h"\r
-#include "GlslangToSpv.h"\r
-#include "SpvBuilder.h"\r
-#include "GLSL450Lib.h"\r
-\r
-// Glslang includes\r
-#include "glslang/MachineIndependent/localintermediate.h"\r
-#include "glslang/MachineIndependent/SymbolTable.h"\r
-\r
-#include <string>\r
-#include <map>\r
-#include <list>\r
-#include <vector>\r
-#include <stack>\r
-#include <fstream>\r
-\r
-namespace {\r
-\r
-const int GlslangMagic = 0x51a;\r
-\r
-//\r
-// The main holder of information for translating glslang to SPIR-V.\r
-//\r
-// Derives from the AST walking base class.\r
-//\r
-class TGlslangToSpvTraverser : public glslang::TIntermTraverser {\r
-public:\r
-    TGlslangToSpvTraverser(const glslang::TIntermediate*);\r
-    virtual ~TGlslangToSpvTraverser();\r
-\r
-    bool visitAggregate(glslang::TVisit, glslang::TIntermAggregate*);\r
-    bool visitBinary(glslang::TVisit, glslang::TIntermBinary*);\r
-    void visitConstantUnion(glslang::TIntermConstantUnion*);\r
-    bool visitSelection(glslang::TVisit, glslang::TIntermSelection*);\r
-    bool visitSwitch(glslang::TVisit, glslang::TIntermSwitch*);\r
-    void visitSymbol(glslang::TIntermSymbol* symbol);\r
-    bool visitUnary(glslang::TVisit, glslang::TIntermUnary*);\r
-    bool visitLoop(glslang::TVisit, glslang::TIntermLoop*);\r
-    bool visitBranch(glslang::TVisit visit, glslang::TIntermBranch*);\r
-\r
-    void dumpSpv(std::vector<unsigned int>& out) { builder.dump(out); }\r
-\r
-protected:\r
-    spv::Id createSpvVariable(const glslang::TIntermSymbol*);\r
-    spv::Id getSampledType(const glslang::TSampler&);\r
-    spv::Id convertGlslangToSpvType(const glslang::TType& type);\r
-\r
-    bool isShaderEntrypoint(const glslang::TIntermAggregate* node);\r
-    void makeFunctions(const glslang::TIntermSequence&);\r
-    void makeGlobalInitializers(const glslang::TIntermSequence&);\r
-    void visitFunctions(const glslang::TIntermSequence&);\r
-    void handleFunctionEntry(const glslang::TIntermAggregate* node);\r
-    void translateArguments(const glslang::TIntermSequence& glslangArguments, std::vector<spv::Id>& arguments);\r
-    spv::Id handleBuiltInFunctionCall(const glslang::TIntermAggregate*);\r
-    spv::Id handleUserFunctionCall(const glslang::TIntermAggregate*);\r
-\r
-    spv::Id createBinaryOperation(glslang::TOperator op, spv::Decoration precision, spv::Id typeId, spv::Id left, spv::Id right, glslang::TBasicType typeProxy, bool reduceComparison = true);\r
-    spv::Id createUnaryOperation(glslang::TOperator op, spv::Decoration precision, spv::Id typeId, spv::Id operand, bool isFloat);\r
-    spv::Id createConversion(glslang::TOperator op, spv::Decoration precision, spv::Id destTypeId, spv::Id operand);\r
-    spv::Id makeSmearedConstant(spv::Id constant, int vectorSize);\r
-    spv::Id createMiscOperation(glslang::TOperator op, spv::Decoration precision, spv::Id typeId, std::vector<spv::Id>& operands);\r
-    spv::Id createNoArgOperation(glslang::TOperator op);\r
-    spv::Id getSymbolId(const glslang::TIntermSymbol* node);\r
-    void addDecoration(spv::Id id, spv::Decoration dec);\r
-    void addMemberDecoration(spv::Id id, int member, spv::Decoration dec);\r
-    spv::Id createSpvConstant(const glslang::TType& type, const glslang::TConstUnionArray&, int& nextConst);\r
-\r
-    spv::Function* shaderEntry;\r
-    int sequenceDepth;\r
-\r
-    // There is a 1:1 mapping between a spv builder and a module; this is thread safe\r
-    spv::Builder builder;\r
-    bool inMain;\r
-    bool mainTerminated;\r
-    bool linkageOnly;\r
-    const glslang::TIntermediate* glslangIntermediate;\r
-    spv::Id stdBuiltins;\r
-\r
-    std::map<int, spv::Id> symbolValues;\r
-    std::set<int> constReadOnlyParameters;  // set of formal function parameters that have glslang qualifier constReadOnly, so we know they are not local function "const" that are write-once\r
-    std::map<std::string, spv::Function*> functionMap;\r
-    std::map<const glslang::TTypeList*, spv::Id> structMap;\r
-    std::map<const glslang::TTypeList*, std::vector<int> > memberRemapper;  // for mapping glslang block indices to spv indices (e.g., due to hidden members)\r
-    std::stack<bool> breakForLoop;  // false means break for switch\r
-    std::stack<glslang::TIntermTyped*> loopTerminal;  // code from the last part of a for loop: for(...; ...; terminal), needed for e.g., continue };\r
-};\r
-\r
-//\r
-// Helper functions for translating glslang representations to SPIR-V enumerants.\r
-//\r
-\r
-// Translate glslang profile to SPIR-V source language.\r
-spv::SourceLanguage TranslateSourceLanguage(EProfile profile)\r
-{\r
-    switch (profile) {\r
-    case ENoProfile:\r
-    case ECoreProfile:\r
-    case ECompatibilityProfile:\r
-        return spv::SourceLanguageGLSL;\r
-    case EEsProfile:\r
-        return spv::SourceLanguageESSL;\r
-    default:\r
-        return spv::SourceLanguageUnknown;\r
-    }\r
-}\r
-\r
-// Translate glslang language (stage) to SPIR-V execution model.\r
-spv::ExecutionModel TranslateExecutionModel(EShLanguage stage)\r
-{\r
-    switch (stage) {\r
-    case EShLangVertex:           return spv::ExecutionModelVertex;\r
-    case EShLangTessControl:      return spv::ExecutionModelTessellationControl;\r
-    case EShLangTessEvaluation:   return spv::ExecutionModelTessellationEvaluation;\r
-    case EShLangGeometry:         return spv::ExecutionModelGeometry;\r
-    case EShLangFragment:         return spv::ExecutionModelFragment;\r
-    case EShLangCompute:          return spv::ExecutionModelGLCompute;\r
-    default:\r
-        spv::MissingFunctionality("GLSL stage");\r
-        return spv::ExecutionModelFragment;\r
-    }\r
-}\r
-\r
-// Translate glslang type to SPIR-V storage class.\r
-spv::StorageClass TranslateStorageClass(const glslang::TType& type)\r
-{\r
-    if (type.getQualifier().isPipeInput())\r
-        return spv::StorageClassInput;\r
-    else if (type.getQualifier().isPipeOutput())\r
-        return spv::StorageClassOutput;\r
-    else if (type.getQualifier().isUniformOrBuffer()) {\r
-        if (type.getBasicType() == glslang::EbtBlock)\r
-            return spv::StorageClassUniform;\r
-        else\r
-            return spv::StorageClassUniformConstant;\r
-        // TODO: how are we distuingishing between default and non-default non-writable uniforms?  Do default uniforms even exist?\r
-    } else {\r
-        switch (type.getQualifier().storage) {\r
-        case glslang::EvqShared:        return spv::StorageClassWorkgroupLocal;  break;\r
-        case glslang::EvqGlobal:        return spv::StorageClassPrivateGlobal;\r
-        case glslang::EvqConstReadOnly: return spv::StorageClassFunction;\r
-        case glslang::EvqTemporary:     return spv::StorageClassFunction;\r
-        default: \r
-            spv::MissingFunctionality("unknown glslang storage class");\r
-            return spv::StorageClassFunction;\r
-        }\r
-    }\r
-}\r
-\r
-// Translate glslang sampler type to SPIR-V dimensionality.\r
-spv::Dim TranslateDimensionality(const glslang::TSampler& sampler)\r
-{\r
-    switch (sampler.dim) {\r
-    case glslang::Esd1D:     return spv::Dim1D;\r
-    case glslang::Esd2D:     return spv::Dim2D;\r
-    case glslang::Esd3D:     return spv::Dim3D;\r
-    case glslang::EsdCube:   return spv::DimCube;\r
-    case glslang::EsdRect:   return spv::DimRect;\r
-    case glslang::EsdBuffer: return spv::DimBuffer;\r
-    default:\r
-        spv::MissingFunctionality("unknown sampler dimension");\r
-        return spv::Dim2D;\r
-    }\r
-}\r
-\r
-// Translate glslang type to SPIR-V precision decorations.\r
-spv::Decoration TranslatePrecisionDecoration(const glslang::TType& type)\r
-{\r
-    switch (type.getQualifier().precision) {\r
-    case glslang::EpqLow:    return spv::DecorationPrecisionLow;\r
-    case glslang::EpqMedium: return spv::DecorationPrecisionMedium;\r
-    case glslang::EpqHigh:   return spv::DecorationPrecisionHigh;\r
-    default:\r
-        return spv::NoPrecision;\r
-    }\r
-}\r
-\r
-// Translate glslang type to SPIR-V block decorations.\r
-spv::Decoration TranslateBlockDecoration(const glslang::TType& type)\r
-{\r
-    if (type.getBasicType() == glslang::EbtBlock) {\r
-        switch (type.getQualifier().storage) {\r
-        case glslang::EvqUniform:      return spv::DecorationBlock;\r
-        case glslang::EvqBuffer:       return spv::DecorationBufferBlock;\r
-        case glslang::EvqVaryingIn:    return spv::DecorationBlock;\r
-        case glslang::EvqVaryingOut:   return spv::DecorationBlock;\r
-        default:\r
-            spv::MissingFunctionality("kind of block");\r
-            break;\r
-        }\r
-    }\r
-\r
-    return (spv::Decoration)spv::BadValue;\r
-}\r
-\r
-// Translate glslang type to SPIR-V layout decorations.\r
-spv::Decoration TranslateLayoutDecoration(const glslang::TType& type)\r
-{\r
-    if (type.isMatrix()) {\r
-        switch (type.getQualifier().layoutMatrix) {\r
-        case glslang::ElmRowMajor:\r
-            return spv::DecorationRowMajor;\r
-        default:\r
-            return spv::DecorationColMajor;\r
-        }\r
-    } else {\r
-        switch (type.getBasicType()) {\r
-        default:\r
-            return (spv::Decoration)spv::BadValue;\r
-            break;\r
-        case glslang::EbtBlock:\r
-            switch (type.getQualifier().storage) {\r
-            case glslang::EvqUniform:\r
-            case glslang::EvqBuffer:\r
-                switch (type.getQualifier().layoutPacking) {\r
-                case glslang::ElpShared:  return spv::DecorationGLSLShared;\r
-                case glslang::ElpStd140:  return spv::DecorationGLSLStd140;\r
-                case glslang::ElpStd430:  return spv::DecorationGLSLStd430;\r
-                case glslang::ElpPacked:  return spv::DecorationGLSLPacked;\r
-                default:\r
-                    spv::MissingFunctionality("uniform block layout");\r
-                    return spv::DecorationGLSLShared;\r
-                }\r
-            case glslang::EvqVaryingIn:\r
-            case glslang::EvqVaryingOut:\r
-                if (type.getQualifier().layoutPacking != glslang::ElpNone)\r
-                    spv::MissingFunctionality("in/out block layout");\r
-                return (spv::Decoration)spv::BadValue;\r
-            default:\r
-                spv::MissingFunctionality("block storage qualification");\r
-                return (spv::Decoration)spv::BadValue;\r
-            }\r
-        }\r
-    }\r
-}\r
-\r
-// Translate glslang type to SPIR-V interpolation decorations.\r
-spv::Decoration TranslateInterpolationDecoration(const glslang::TType& type)\r
-{\r
-    if (type.getQualifier().smooth)\r
-        return spv::DecorationSmooth;\r
-    if (type.getQualifier().nopersp)\r
-        return spv::DecorationNoperspective;\r
-    else if (type.getQualifier().patch)\r
-        return spv::DecorationPatch;\r
-    else if (type.getQualifier().flat)\r
-        return spv::DecorationFlat;\r
-    else if (type.getQualifier().centroid)\r
-        return spv::DecorationCentroid;\r
-    else if (type.getQualifier().sample)\r
-        return spv::DecorationSample;\r
-    else\r
-        return (spv::Decoration)spv::BadValue;\r
-}\r
-\r
-// If glslang type is invaraiant, return SPIR-V invariant decoration.\r
-spv::Decoration TranslateInvariantDecoration(const glslang::TType& type)\r
-{\r
-    if (type.getQualifier().invariant)\r
-        return spv::DecorationInvariant;\r
-    else\r
-        return (spv::Decoration)spv::BadValue;\r
-}\r
-\r
-// Translate glslang built-in variable to SPIR-V built in decoration.\r
-spv::BuiltIn TranslateBuiltInDecoration(glslang::TBuiltInVariable builtIn)\r
-{\r
-    switch (builtIn) {\r
-    case glslang::EbvPosition:             return spv::BuiltInPosition;\r
-    case glslang::EbvPointSize:            return spv::BuiltInPointSize;\r
-    case glslang::EbvClipVertex:           return spv::BuiltInClipVertex;\r
-    case glslang::EbvClipDistance:         return spv::BuiltInClipDistance;\r
-    case glslang::EbvCullDistance:         return spv::BuiltInCullDistance;\r
-    case glslang::EbvVertexId:             return spv::BuiltInVertexId;\r
-    case glslang::EbvInstanceId:           return spv::BuiltInInstanceId;\r
-    case glslang::EbvPrimitiveId:          return spv::BuiltInPrimitiveId;\r
-    case glslang::EbvInvocationId:         return spv::BuiltInInvocationId;\r
-    case glslang::EbvLayer:                return spv::BuiltInLayer;\r
-    case glslang::EbvViewportIndex:        return spv::BuiltInViewportIndex;\r
-    case glslang::EbvTessLevelInner:       return spv::BuiltInTessLevelInner;\r
-    case glslang::EbvTessLevelOuter:       return spv::BuiltInTessLevelOuter;\r
-    case glslang::EbvTessCoord:            return spv::BuiltInTessCoord;\r
-    case glslang::EbvPatchVertices:        return spv::BuiltInPatchVertices;\r
-    case glslang::EbvFragCoord:            return spv::BuiltInFragCoord;\r
-    case glslang::EbvPointCoord:           return spv::BuiltInPointCoord;\r
-    case glslang::EbvFace:                 return spv::BuiltInFrontFacing;\r
-    case glslang::EbvSampleId:             return spv::BuiltInSampleId;\r
-    case glslang::EbvSamplePosition:       return spv::BuiltInSamplePosition;\r
-    case glslang::EbvSampleMask:           return spv::BuiltInSampleMask;\r
-    case glslang::EbvFragColor:            return spv::BuiltInFragColor;\r
-    case glslang::EbvFragData:             return spv::BuiltInFragColor;\r
-    case glslang::EbvFragDepth:            return spv::BuiltInFragDepth;\r
-    case glslang::EbvHelperInvocation:     return spv::BuiltInHelperInvocation;\r
-    case glslang::EbvNumWorkGroups:        return spv::BuiltInNumWorkgroups;\r
-    case glslang::EbvWorkGroupSize:        return spv::BuiltInWorkgroupSize;\r
-    case glslang::EbvWorkGroupId:          return spv::BuiltInWorkgroupId;\r
-    case glslang::EbvLocalInvocationId:    return spv::BuiltInLocalInvocationId;\r
-    case glslang::EbvLocalInvocationIndex: return spv::BuiltInLocalInvocationIndex;\r
-    case glslang::EbvGlobalInvocationId:   return spv::BuiltInGlobalInvocationId;\r
-    default:                               return (spv::BuiltIn)spv::BadValue;\r
-    }\r
-}\r
-\r
-//\r
-// Implement the TGlslangToSpvTraverser class.\r
-//\r
-\r
-TGlslangToSpvTraverser::TGlslangToSpvTraverser(const glslang::TIntermediate* glslangIntermediate)\r
-    : TIntermTraverser(true, false, true), shaderEntry(0), sequenceDepth(0),\r
-      builder(GlslangMagic),\r
-      inMain(false), mainTerminated(false), linkageOnly(false),\r
-      glslangIntermediate(glslangIntermediate)\r
-{\r
-    spv::ExecutionModel executionModel = TranslateExecutionModel(glslangIntermediate->getStage());\r
-\r
-    builder.clearAccessChain();\r
-    builder.setSource(TranslateSourceLanguage(glslangIntermediate->getProfile()), glslangIntermediate->getVersion());\r
-    stdBuiltins = builder.import("GLSL.std.450");\r
-    builder.setMemoryModel(spv::AddressingModelLogical, spv::MemoryModelGLSL450);\r
-    shaderEntry = builder.makeMain();\r
-    builder.addEntryPoint(executionModel, shaderEntry);\r
-\r
-    // Add the source extensions\r
-    const std::set<std::string>& sourceExtensions = glslangIntermediate->getRequestedExtensions();\r
-    for (std::set<std::string>::const_iterator it = sourceExtensions.begin(); it != sourceExtensions.end(); ++it)\r
-        builder.addSourceExtension(it->c_str());\r
-\r
-    // Add the top-level modes for this shader.\r
-\r
-    if (glslangIntermediate->getXfbMode())\r
-        builder.addExecutionMode(shaderEntry, spv::ExecutionModeXfb);\r
-\r
-    unsigned int mode;\r
-    switch (glslangIntermediate->getStage()) {\r
-    case EShLangVertex:\r
-        break;\r
-\r
-    case EShLangTessControl:\r
-        builder.addExecutionMode(shaderEntry, spv::ExecutionModeOutputVertices, glslangIntermediate->getVertices());\r
-        break;\r
-\r
-    case EShLangTessEvaluation:\r
-        switch (glslangIntermediate->getInputPrimitive()) {\r
-        case glslang::ElgTriangles:           mode = spv::ExecutionModeInputTriangles;     break;\r
-        case glslang::ElgQuads:               mode = spv::ExecutionModeInputQuads;         break;\r
-        case glslang::ElgIsolines:            mode = spv::ExecutionModeInputIsolines;      break;\r
-        default:                              mode = spv::BadValue;    break;\r
-        }\r
-        if (mode != spv::BadValue)\r
-            builder.addExecutionMode(shaderEntry, (spv::ExecutionMode)mode);\r
-\r
-        // TODO\r
-        //builder.addExecutionMode(spv::VertexSpacingMdName, glslangIntermediate->getVertexSpacing());\r
-        //builder.addExecutionMode(spv::VertexOrderMdName, glslangIntermediate->getVertexOrder());\r
-        //builder.addExecutionMode(spv::PointModeMdName, glslangIntermediate->getPointMode());\r
-        break;\r
-\r
-    case EShLangGeometry:\r
-        switch (glslangIntermediate->getInputPrimitive()) {\r
-        case glslang::ElgPoints:             mode = spv::ExecutionModeInputPoints;             break;\r
-        case glslang::ElgLines:              mode = spv::ExecutionModeInputLines;              break;\r
-        case glslang::ElgLinesAdjacency:     mode = spv::ExecutionModeInputLinesAdjacency;     break;\r
-        case glslang::ElgTriangles:          mode = spv::ExecutionModeInputTriangles;          break;\r
-        case glslang::ElgTrianglesAdjacency: mode = spv::ExecutionModeInputTrianglesAdjacency; break;\r
-        default:                             mode = spv::BadValue;         break;\r
-        }\r
-        if (mode != spv::BadValue)\r
-            builder.addExecutionMode(shaderEntry, (spv::ExecutionMode)mode);\r
-        builder.addExecutionMode(shaderEntry, spv::ExecutionModeInvocations, glslangIntermediate->getInvocations());\r
-\r
-        switch (glslangIntermediate->getOutputPrimitive()) {\r
-        case glslang::ElgPoints:        mode = spv::ExecutionModeOutputPoints;                 break;\r
-        case glslang::ElgLineStrip:     mode = spv::ExecutionModeOutputLineStrip;              break;\r
-        case glslang::ElgTriangleStrip: mode = spv::ExecutionModeOutputTriangleStrip;          break;\r
-        default:                        mode = spv::BadValue;              break;\r
-        }\r
-        if (mode != spv::BadValue)\r
-            builder.addExecutionMode(shaderEntry, (spv::ExecutionMode)mode);\r
-        builder.addExecutionMode(shaderEntry, spv::ExecutionModeOutputVertices, glslangIntermediate->getVertices());\r
-        break;\r
-\r
-    case EShLangFragment:\r
-        if (glslangIntermediate->getPixelCenterInteger())\r
-            builder.addExecutionMode(shaderEntry, spv::ExecutionModePixelCenterInteger);\r
-        if (glslangIntermediate->getOriginUpperLeft())\r
-            builder.addExecutionMode(shaderEntry, spv::ExecutionModeOriginUpperLeft);\r
-        break;\r
-\r
-    case EShLangCompute:\r
-        break;\r
-\r
-    default:\r
-        break;\r
-    }\r
-\r
-}\r
-\r
-TGlslangToSpvTraverser::~TGlslangToSpvTraverser()\r
-{\r
-    if (! mainTerminated) {\r
-        spv::Block* lastMainBlock = shaderEntry->getLastBlock();\r
-        builder.setBuildPoint(lastMainBlock);\r
-        builder.leaveFunction(true);\r
-    }\r
-}\r
-\r
-//\r
-// Implement the traversal functions.\r
-//\r
-// Return true from interior nodes to have the external traversal\r
-// continue on to children.  Return false if children were\r
-// already processed.\r
-//\r
-\r
-//\r
-// Symbols can turn into \r
-//  - uniform/input reads\r
-//  - output writes\r
-//  - complex lvalue base setups:  foo.bar[3]....  , where we see foo and start up an access chain\r
-//  - something simple that degenerates into the last bullet\r
-//\r
-void TGlslangToSpvTraverser::visitSymbol(glslang::TIntermSymbol* symbol)\r
-{\r
-    // getSymbolId() will set up all the IO decorations on the first call.\r
-    // Formal function parameters were mapped during makeFunctions().\r
-    spv::Id id = getSymbolId(symbol);\r
-    \r
-    if (! linkageOnly) {\r
-        // Prepare to generate code for the access\r
-\r
-        // L-value chains will be computed left to right.  We're on the symbol now,\r
-        // which is the left-most part of the access chain, so now is "clear" time,\r
-        // followed by setting the base.\r
-        builder.clearAccessChain();\r
-\r
-        // For now, we consider all user variables as being in memory, so they are pointers,\r
-        // except for "const in" arguments to a function, which are an intermediate object.\r
-        // See comments in handleUserFunctionCall().\r
-        glslang::TStorageQualifier qualifier = symbol->getQualifier().storage;\r
-        if (qualifier == glslang::EvqConstReadOnly && constReadOnlyParameters.find(symbol->getId()) != constReadOnlyParameters.end())\r
-            builder.setAccessChainRValue(id);\r
-        else\r
-            builder.setAccessChainLValue(id);\r
-    }\r
-}\r
-\r
-bool TGlslangToSpvTraverser::visitBinary(glslang::TVisit /* visit */, glslang::TIntermBinary* node)\r
-{\r
-    // First, handle special cases\r
-    switch (node->getOp()) {\r
-    case glslang::EOpAssign:\r
-    case glslang::EOpAddAssign:\r
-    case glslang::EOpSubAssign:\r
-    case glslang::EOpMulAssign:\r
-    case glslang::EOpVectorTimesMatrixAssign:\r
-    case glslang::EOpVectorTimesScalarAssign:\r
-    case glslang::EOpMatrixTimesScalarAssign:\r
-    case glslang::EOpMatrixTimesMatrixAssign:\r
-    case glslang::EOpDivAssign:\r
-    case glslang::EOpModAssign:\r
-    case glslang::EOpAndAssign:\r
-    case glslang::EOpInclusiveOrAssign:\r
-    case glslang::EOpExclusiveOrAssign:\r
-    case glslang::EOpLeftShiftAssign:\r
-    case glslang::EOpRightShiftAssign:\r
-        // A bin-op assign "a += b" means the same thing as "a = a + b"\r
-        // where a is evaluated before b. For a simple assignment, GLSL\r
-        // says to evaluate the left before the right.  So, always, left\r
-        // node then right node.\r
-        {\r
-            // get the left l-value, save it away\r
-            builder.clearAccessChain();\r
-            node->getLeft()->traverse(this);\r
-            spv::Builder::AccessChain lValue = builder.getAccessChain();\r
-\r
-            // evaluate the right\r
-            builder.clearAccessChain();\r
-            node->getRight()->traverse(this);\r
-            spv::Id rValue = builder.accessChainLoad(TranslatePrecisionDecoration(node->getRight()->getType()));\r
-\r
-            if (node->getOp() != glslang::EOpAssign) {\r
-                // the left is also an r-value\r
-                builder.setAccessChain(lValue);\r
-                spv::Id leftRValue = builder.accessChainLoad(TranslatePrecisionDecoration(node->getLeft()->getType()));\r
-\r
-                // do the operation\r
-                rValue = createBinaryOperation(node->getOp(), TranslatePrecisionDecoration(node->getType()), \r
-                                               convertGlslangToSpvType(node->getType()), leftRValue, rValue,\r
-                                               node->getType().getBasicType());\r
-\r
-                // these all need their counterparts in createBinaryOperation()\r
-                if (rValue == 0)\r
-                    spv::MissingFunctionality("createBinaryOperation");\r
-            }\r
-\r
-            // store the result\r
-            builder.setAccessChain(lValue);\r
-            builder.accessChainStore(rValue);\r
-\r
-            // assignments are expressions having an rValue after they are evaluated...\r
-            builder.clearAccessChain();\r
-            builder.setAccessChainRValue(rValue);\r
-        }\r
-        return false;\r
-    case glslang::EOpIndexDirect:\r
-    case glslang::EOpIndexDirectStruct:\r
-        {\r
-            // Get the left part of the access chain.\r
-            node->getLeft()->traverse(this);\r
-\r
-            // Add the next element in the chain\r
-\r
-            int index = 0;\r
-            if (node->getRight()->getAsConstantUnion() == 0)\r
-                spv::MissingFunctionality("direct index without a constant node");\r
-            else \r
-                index = node->getRight()->getAsConstantUnion()->getConstArray()[0].getIConst();\r
-\r
-            if (node->getLeft()->getBasicType() == glslang::EbtBlock && node->getOp() == glslang::EOpIndexDirectStruct) {\r
-                // This may be, e.g., an anonymous block-member selection, which generally need\r
-                // index remapping due to hidden members in anonymous blocks.\r
-                std::vector<int>& remapper = memberRemapper[node->getLeft()->getType().getStruct()];\r
-                if (remapper.size() == 0)\r
-                    spv::MissingFunctionality("block without member remapping");\r
-                else\r
-                    index = remapper[index];\r
-            }\r
-\r
-            if (! node->getLeft()->getType().isArray() &&\r
-                node->getLeft()->getType().isVector() &&\r
-                node->getOp() == glslang::EOpIndexDirect) {\r
-                // This is essentially a hard-coded vector swizzle of size 1,\r
-                // so short circuit the access-chain stuff with a swizzle.\r
-                std::vector<unsigned> swizzle;\r
-                swizzle.push_back(node->getRight()->getAsConstantUnion()->getConstArray()[0].getIConst());\r
-                builder.accessChainPushSwizzle(swizzle);\r
-            } else {\r
-                // normal case for indexing array or structure or block\r
-                builder.accessChainPush(builder.makeIntConstant(index), convertGlslangToSpvType(node->getType()));\r
-            }\r
-        }\r
-        return false;\r
-    case glslang::EOpIndexIndirect:\r
-        {\r
-            // Structure or array or vector indirection.\r
-            // Will use native SPIR-V access-chain for struct and array indirection;\r
-            // matrices are arrays of vectors, so will also work for a matrix.\r
-            // Will use the access chain's 'component' for variable index into a vector.\r
-\r
-            // This adapter is building access chains left to right.\r
-            // Set up the access chain to the left.\r
-            node->getLeft()->traverse(this);\r
-\r
-            // save it so that computing the right side doesn't trash it\r
-            spv::Builder::AccessChain partial = builder.getAccessChain();\r
-\r
-            // compute the next index in the chain\r
-            builder.clearAccessChain();\r
-            node->getRight()->traverse(this);\r
-            spv::Id index = builder.accessChainLoad(TranslatePrecisionDecoration(node->getRight()->getType()));\r
-\r
-            // restore the saved access chain\r
-            builder.setAccessChain(partial);\r
-\r
-            if (! node->getLeft()->getType().isArray() && node->getLeft()->getType().isVector())\r
-                builder.accessChainPushComponent(index);\r
-            else\r
-                builder.accessChainPush(index, convertGlslangToSpvType(node->getType()));\r
-        }\r
-        return false;\r
-    case glslang::EOpVectorSwizzle:\r
-        {\r
-            node->getLeft()->traverse(this);\r
-            glslang::TIntermSequence& swizzleSequence = node->getRight()->getAsAggregate()->getSequence();\r
-            std::vector<unsigned> swizzle;\r
-            for (int i = 0; i < (int)swizzleSequence.size(); ++i)\r
-                swizzle.push_back(swizzleSequence[i]->getAsConstantUnion()->getConstArray()[0].getIConst());\r
-            builder.accessChainPushSwizzle(swizzle);\r
-        }\r
-        return false;\r
-    default:\r
-        break;\r
-    }\r
-\r
-    // Assume generic binary op...\r
-\r
-    // Get the operands\r
-    builder.clearAccessChain();\r
-    node->getLeft()->traverse(this);\r
-    spv::Id left = builder.accessChainLoad(TranslatePrecisionDecoration(node->getLeft()->getType()));\r
-\r
-    builder.clearAccessChain();\r
-    node->getRight()->traverse(this);\r
-    spv::Id right = builder.accessChainLoad(TranslatePrecisionDecoration(node->getRight()->getType()));\r
-\r
-    spv::Id result;\r
-    spv::Decoration precision = TranslatePrecisionDecoration(node->getType());\r
-\r
-    result = createBinaryOperation(node->getOp(), precision, \r
-                                   convertGlslangToSpvType(node->getType()), left, right,\r
-                                   node->getLeft()->getType().getBasicType());\r
-\r
-    if (! result) {\r
-        spv::MissingFunctionality("glslang binary operation");\r
-    } else {\r
-        builder.clearAccessChain();\r
-        builder.setAccessChainRValue(result);\r
-\r
-        return false;\r
-    }\r
-\r
-    return true;\r
-}\r
-\r
-bool TGlslangToSpvTraverser::visitUnary(glslang::TVisit /* visit */, glslang::TIntermUnary* node)\r
-{\r
-    builder.clearAccessChain();\r
-    node->getOperand()->traverse(this);\r
-    spv::Id operand = builder.accessChainLoad(TranslatePrecisionDecoration(node->getOperand()->getType()));\r
-\r
-    spv::Decoration precision = TranslatePrecisionDecoration(node->getType());\r
-\r
-    // it could be a conversion\r
-    spv::Id result = createConversion(node->getOp(), precision, convertGlslangToSpvType(node->getType()), operand);\r
-\r
-    // if not, then possibly an operation\r
-    if (! result)\r
-        result = createUnaryOperation(node->getOp(), precision, convertGlslangToSpvType(node->getType()), operand, node->getBasicType() == glslang::EbtFloat || node->getBasicType() == glslang::EbtDouble);\r
-\r
-    if (result) {\r
-        builder.clearAccessChain();\r
-        builder.setAccessChainRValue(result);\r
-\r
-        return false; // done with this node\r
-    }\r
-\r
-    // it must be a special case, check...\r
-    switch (node->getOp()) {\r
-    case glslang::EOpPostIncrement:\r
-    case glslang::EOpPostDecrement:\r
-    case glslang::EOpPreIncrement:\r
-    case glslang::EOpPreDecrement:\r
-        {\r
-            // we need the integer value "1" or the floating point "1.0" to add/subtract\r
-            spv::Id one = node->getBasicType() == glslang::EbtFloat ?\r
-                                     builder.makeFloatConstant(1.0F) :\r
-                                     builder.makeIntConstant(1);\r
-            glslang::TOperator op;\r
-            if (node->getOp() == glslang::EOpPreIncrement ||\r
-                node->getOp() == glslang::EOpPostIncrement)\r
-                op = glslang::EOpAdd;\r
-            else\r
-                op = glslang::EOpSub;\r
-\r
-            spv::Id result = createBinaryOperation(op, TranslatePrecisionDecoration(node->getType()), \r
-                                                     convertGlslangToSpvType(node->getType()), operand, one, \r
-                                                     node->getType().getBasicType());\r
-            if (result == 0)\r
-                spv::MissingFunctionality("createBinaryOperation for unary");\r
-\r
-            // The result of operation is always stored, but conditionally the\r
-            // consumed result.  The consumed result is always an r-value.\r
-            builder.accessChainStore(result);\r
-            builder.clearAccessChain();\r
-            if (node->getOp() == glslang::EOpPreIncrement ||\r
-                node->getOp() == glslang::EOpPreDecrement)\r
-                builder.setAccessChainRValue(result);\r
-            else\r
-                builder.setAccessChainRValue(operand);\r
-        }\r
-\r
-        return false;\r
-\r
-    case glslang::EOpEmitStreamVertex:\r
-        builder.createNoResultOp(spv::OpEmitStreamVertex, operand);\r
-        return false;\r
-    case glslang::EOpEndStreamPrimitive:\r
-        builder.createNoResultOp(spv::OpEndStreamPrimitive, operand);\r
-        return false;\r
-\r
-    default:\r
-        spv::MissingFunctionality("glslang unary");\r
-        break;\r
-    }\r
-\r
-    return true;\r
-}\r
-\r
-bool TGlslangToSpvTraverser::visitAggregate(glslang::TVisit visit, glslang::TIntermAggregate* node)\r
-{\r
-    spv::Id result;\r
-    glslang::TOperator binOp = glslang::EOpNull;\r
-    bool reduceComparison = true;\r
-    bool isMatrix = false;\r
-    bool noReturnValue = false;\r
-\r
-    assert(node->getOp());\r
-\r
-    spv::Decoration precision = TranslatePrecisionDecoration(node->getType());\r
-\r
-    switch (node->getOp()) {\r
-    case glslang::EOpSequence:\r
-    {\r
-        if (preVisit)\r
-            ++sequenceDepth;\r
-        else\r
-            --sequenceDepth;\r
-\r
-        if (sequenceDepth == 1) {\r
-            // If this is the parent node of all the functions, we want to see them\r
-            // early, so all call points have actual SPIR-V functions to reference.\r
-            // In all cases, still let the traverser visit the children for us.\r
-            makeFunctions(node->getAsAggregate()->getSequence());\r
-\r
-            // Also, we want all globals initializers to go into the entry of main(), before\r
-            // anything else gets there, so visit out of order, doing them all now.\r
-            makeGlobalInitializers(node->getAsAggregate()->getSequence());\r
-\r
-            // Initializers are done, don't want to visit again, but functions link objects need to be processed,\r
-            // so do them manually.\r
-            visitFunctions(node->getAsAggregate()->getSequence());\r
-\r
-            return false;\r
-        }\r
-\r
-        return true;\r
-    }\r
-    case glslang::EOpLinkerObjects:\r
-    {\r
-        if (visit == glslang::EvPreVisit)\r
-            linkageOnly = true;\r
-        else\r
-            linkageOnly = false;\r
-\r
-        return true;\r
-    }\r
-    case glslang::EOpComma:\r
-    {\r
-        // processing from left to right naturally leaves the right-most\r
-        // lying around in the access chain\r
-        glslang::TIntermSequence& glslangOperands = node->getSequence();\r
-        for (int i = 0; i < (int)glslangOperands.size(); ++i)\r
-            glslangOperands[i]->traverse(this);\r
-\r
-        return false;\r
-    }\r
-    case glslang::EOpFunction:\r
-        if (visit == glslang::EvPreVisit) {\r
-            if (isShaderEntrypoint(node)) {\r
-                inMain = true;\r
-                builder.setBuildPoint(shaderEntry->getLastBlock());\r
-            } else {\r
-                handleFunctionEntry(node);\r
-            }\r
-        } else {\r
-            if (inMain)\r
-                mainTerminated = true;\r
-            builder.leaveFunction(inMain);\r
-            inMain = false;\r
-        }\r
-\r
-        return true;\r
-    case glslang::EOpParameters:\r
-        // Parameters will have been consumed by EOpFunction processing, but not\r
-        // the body, so we still visited the function node's children, making this\r
-        // child redundant.\r
-        return false;\r
-    case glslang::EOpFunctionCall:\r
-    {\r
-        if (node->isUserDefined())\r
-            result = handleUserFunctionCall(node);\r
-        else\r
-            result = handleBuiltInFunctionCall(node);\r
-\r
-        if (! result) {\r
-            spv::MissingFunctionality("glslang function call");\r
-            glslang::TConstUnionArray emptyConsts;\r
-            int nextConst = 0;\r
-            result = createSpvConstant(node->getType(), emptyConsts, nextConst);\r
-        }\r
-        builder.clearAccessChain();\r
-        builder.setAccessChainRValue(result);\r
-\r
-        return false;\r
-    }\r
-    case glslang::EOpConstructMat2x2:\r
-    case glslang::EOpConstructMat2x3:\r
-    case glslang::EOpConstructMat2x4:\r
-    case glslang::EOpConstructMat3x2:\r
-    case glslang::EOpConstructMat3x3:\r
-    case glslang::EOpConstructMat3x4:\r
-    case glslang::EOpConstructMat4x2:\r
-    case glslang::EOpConstructMat4x3:\r
-    case glslang::EOpConstructMat4x4:\r
-    case glslang::EOpConstructDMat2x2:\r
-    case glslang::EOpConstructDMat2x3:\r
-    case glslang::EOpConstructDMat2x4:\r
-    case glslang::EOpConstructDMat3x2:\r
-    case glslang::EOpConstructDMat3x3:\r
-    case glslang::EOpConstructDMat3x4:\r
-    case glslang::EOpConstructDMat4x2:\r
-    case glslang::EOpConstructDMat4x3:\r
-    case glslang::EOpConstructDMat4x4:\r
-        isMatrix = true;\r
-        // fall through\r
-    case glslang::EOpConstructFloat:\r
-    case glslang::EOpConstructVec2:\r
-    case glslang::EOpConstructVec3:\r
-    case glslang::EOpConstructVec4:\r
-    case glslang::EOpConstructDouble:\r
-    case glslang::EOpConstructDVec2:\r
-    case glslang::EOpConstructDVec3:\r
-    case glslang::EOpConstructDVec4:\r
-    case glslang::EOpConstructBool:\r
-    case glslang::EOpConstructBVec2:\r
-    case glslang::EOpConstructBVec3:\r
-    case glslang::EOpConstructBVec4:\r
-    case glslang::EOpConstructInt:\r
-    case glslang::EOpConstructIVec2:\r
-    case glslang::EOpConstructIVec3:\r
-    case glslang::EOpConstructIVec4:\r
-    case glslang::EOpConstructUint:\r
-    case glslang::EOpConstructUVec2:\r
-    case glslang::EOpConstructUVec3:\r
-    case glslang::EOpConstructUVec4:\r
-    case glslang::EOpConstructStruct:\r
-    {\r
-        std::vector<spv::Id> arguments;\r
-        translateArguments(node->getSequence(), arguments);\r
-        spv::Id resultTypeId = convertGlslangToSpvType(node->getType());\r
-        spv::Id constructed;\r
-        if (node->getOp() == glslang::EOpConstructStruct || node->getType().isArray()) {\r
-            std::vector<spv::Id> constituents;\r
-            for (int c = 0; c < (int)arguments.size(); ++c)\r
-                constituents.push_back(arguments[c]);\r
-            constructed = builder.createCompositeConstruct(resultTypeId, constituents);\r
-        } else {\r
-            if (isMatrix)\r
-                constructed = builder.createMatrixConstructor(precision, arguments, resultTypeId);\r
-            else\r
-                constructed = builder.createConstructor(precision, arguments, resultTypeId);\r
-        }\r
-\r
-        builder.clearAccessChain();\r
-        builder.setAccessChainRValue(constructed);\r
-\r
-        return false;\r
-    }\r
-\r
-    // These six are component-wise compares with component-wise results.\r
-    // Forward on to createBinaryOperation(), requesting a vector result.\r
-    case glslang::EOpLessThan:\r
-    case glslang::EOpGreaterThan:\r
-    case glslang::EOpLessThanEqual:\r
-    case glslang::EOpGreaterThanEqual:\r
-    case glslang::EOpVectorEqual:\r
-    case glslang::EOpVectorNotEqual:\r
-    {\r
-        // Map the operation to a binary\r
-        binOp = node->getOp();\r
-        reduceComparison = false;\r
-        switch (node->getOp()) {\r
-        case glslang::EOpVectorEqual:     binOp = glslang::EOpVectorEqual;      break;\r
-        case glslang::EOpVectorNotEqual:  binOp = glslang::EOpVectorNotEqual;   break;\r
-        default:                          binOp = node->getOp();                break;\r
-        }\r
-\r
-        break;\r
-    }\r
-    case glslang::EOpMul:\r
-        // compontent-wise matrix multiply      \r
-        binOp = glslang::EOpMul;\r
-        break;\r
-    case glslang::EOpOuterProduct:\r
-        // two vectors multiplied to make a matrix\r
-        binOp = glslang::EOpOuterProduct;\r
-        break;\r
-    case glslang::EOpDot:\r
-    {\r
-        // for scalar dot product, use multiply        \r
-        glslang::TIntermSequence& glslangOperands = node->getSequence();\r
-        if (! glslangOperands[0]->getAsTyped()->isVector())\r
-            binOp = glslang::EOpMul;\r
-        break;\r
-    }\r
-    case glslang::EOpMod:\r
-        // when an aggregate, this is the floating-point mod built-in function,\r
-        // which can be emitted by the one in createBinaryOperation()\r
-        binOp = glslang::EOpMod;\r
-        break;\r
-    case glslang::EOpArrayLength:\r
-    {\r
-        glslang::TIntermTyped* typedNode = node->getSequence()[0]->getAsTyped();\r
-        assert(typedNode);\r
-        spv::Id length = builder.makeIntConstant(typedNode->getType().getArraySize());\r
-\r
-        builder.clearAccessChain();\r
-        builder.setAccessChainRValue(length);\r
-\r
-        return false;\r
-    }\r
-    case glslang::EOpEmitVertex:\r
-    case glslang::EOpEndPrimitive:\r
-    case glslang::EOpBarrier:\r
-    case glslang::EOpMemoryBarrier:\r
-    case glslang::EOpMemoryBarrierAtomicCounter:\r
-    case glslang::EOpMemoryBarrierBuffer:\r
-    case glslang::EOpMemoryBarrierImage:\r
-    case glslang::EOpMemoryBarrierShared:\r
-    case glslang::EOpGroupMemoryBarrier:\r
-        noReturnValue = true;\r
-        // These all have 0 operands and will naturally finish up in the code below for 0 operands\r
-        break;\r
-\r
-    default:\r
-        break;\r
-    }\r
-\r
-    //\r
-    // See if it maps to a regular operation.\r
-    //\r
-\r
-    if (binOp != glslang::EOpNull) {\r
-        glslang::TIntermTyped* left = node->getSequence()[0]->getAsTyped();\r
-        glslang::TIntermTyped* right = node->getSequence()[1]->getAsTyped();\r
-        assert(left && right);\r
-\r
-        builder.clearAccessChain();\r
-        left->traverse(this);\r
-        spv::Id leftId = builder.accessChainLoad(TranslatePrecisionDecoration(left->getType()));\r
-\r
-        builder.clearAccessChain();\r
-        right->traverse(this);\r
-        spv::Id rightId = builder.accessChainLoad(TranslatePrecisionDecoration(right->getType()));\r
-\r
-        result = createBinaryOperation(binOp, precision, \r
-                                       convertGlslangToSpvType(node->getType()), leftId, rightId, \r
-                                       left->getType().getBasicType(), reduceComparison);\r
-\r
-        // code above should only make binOp that exists in createBinaryOperation\r
-        if (result == 0)\r
-            spv::MissingFunctionality("createBinaryOperation for aggregate");\r
-\r
-        builder.clearAccessChain();\r
-        builder.setAccessChainRValue(result);\r
-\r
-        return false;\r
-    }\r
-\r
-    glslang::TIntermSequence& glslangOperands = node->getSequence();\r
-    std::vector<spv::Id> operands;\r
-    for (int arg = 0; arg < (int)glslangOperands.size(); ++arg) {\r
-        builder.clearAccessChain();\r
-        glslangOperands[arg]->traverse(this);\r
-\r
-        // special case l-value operands; there are just a few\r
-        bool lvalue = false;\r
-        switch (node->getOp()) {\r
-        //case glslang::EOpFrexp:\r
-        case glslang::EOpModf:\r
-            if (arg == 1)\r
-                lvalue = true;\r
-            break;\r
-        //case glslang::EOpUAddCarry:\r
-        //case glslang::EOpUSubBorrow:\r
-        //case glslang::EOpUMulExtended:\r
-        default:\r
-            break;\r
-        }\r
-        if (lvalue)\r
-            operands.push_back(builder.accessChainGetLValue());\r
-        else\r
-            operands.push_back(builder.accessChainLoad(TranslatePrecisionDecoration(glslangOperands[arg]->getAsTyped()->getType())));\r
-    }\r
-    switch (glslangOperands.size()) {\r
-    case 0:\r
-        result = createNoArgOperation(node->getOp());\r
-        break;\r
-    case 1:\r
-        result = createUnaryOperation(node->getOp(), precision, convertGlslangToSpvType(node->getType()), operands.front(), node->getType().getBasicType() == glslang::EbtFloat || node->getType().getBasicType() == glslang::EbtDouble);\r
-        break;\r
-    default:\r
-        result = createMiscOperation(node->getOp(), precision, convertGlslangToSpvType(node->getType()), operands);\r
-        break;\r
-    }\r
-\r
-    if (noReturnValue)\r
-        return false;\r
-\r
-    if (! result) {\r
-        spv::MissingFunctionality("glslang aggregate");\r
-        return true;\r
-    } else {\r
-        builder.clearAccessChain();\r
-        builder.setAccessChainRValue(result);\r
-        return false;\r
-    }\r
-}\r
-\r
-bool TGlslangToSpvTraverser::visitSelection(glslang::TVisit /* visit */, glslang::TIntermSelection* node)\r
-{\r
-    // This path handles both if-then-else and ?:\r
-    // The if-then-else has a node type of void, while\r
-    // ?: has a non-void node type\r
-    spv::Id result = 0;\r
-    if (node->getBasicType() != glslang::EbtVoid) {\r
-        // don't handle this as just on-the-fly temporaries, because there will be two names\r
-        // and better to leave SSA to later passes\r
-        result = builder.createVariable(spv::StorageClassFunction, convertGlslangToSpvType(node->getType()));\r
-    }\r
-\r
-    // emit the condition before doing anything with selection\r
-    node->getCondition()->traverse(this);\r
-\r
-    // make an "if" based on the value created by the condition\r
-    spv::Builder::If ifBuilder(builder.accessChainLoad(spv::NoPrecision), builder);\r
-\r
-    if (node->getTrueBlock()) {\r
-        // emit the "then" statement\r
-        node->getTrueBlock()->traverse(this);\r
-        if (result)\r
-            builder.createStore(builder.accessChainLoad(TranslatePrecisionDecoration(node->getTrueBlock()->getAsTyped()->getType())), result);\r
-    }\r
-\r
-    if (node->getFalseBlock()) {\r
-        ifBuilder.makeBeginElse();\r
-        // emit the "else" statement\r
-        node->getFalseBlock()->traverse(this);\r
-        if (result)\r
-            builder.createStore(builder.accessChainLoad(TranslatePrecisionDecoration(node->getFalseBlock()->getAsTyped()->getType())), result);\r
-    }\r
-\r
-    ifBuilder.makeEndIf();\r
-\r
-    if (result) {\r
-        // GLSL only has r-values as the result of a :?, but\r
-        // if we have an l-value, that can be more efficient if it will\r
-        // become the base of a complex r-value expression, because the\r
-        // next layer copies r-values into memory to use the access-chain mechanism\r
-        builder.clearAccessChain();\r
-        builder.setAccessChainLValue(result);\r
-    }\r
-\r
-    return false;\r
-}\r
-\r
-bool TGlslangToSpvTraverser::visitSwitch(glslang::TVisit /* visit */, glslang::TIntermSwitch* node)\r
-{\r
-    // emit and get the condition before doing anything with switch\r
-    node->getCondition()->traverse(this);\r
-    spv::Id selector = builder.accessChainLoad(TranslatePrecisionDecoration(node->getCondition()->getAsTyped()->getType()));\r
-\r
-    // browse the children to sort out code segments\r
-    int defaultSegment = -1;\r
-    std::vector<TIntermNode*> codeSegments;\r
-    glslang::TIntermSequence& sequence = node->getBody()->getSequence();\r
-    std::vector<int> caseValues;\r
-    std::vector<int> valueIndexToSegment(sequence.size());  // note: probably not all are used, it is an overestimate\r
-    for (glslang::TIntermSequence::iterator c = sequence.begin(); c != sequence.end(); ++c) {\r
-        TIntermNode* child = *c;\r
-        if (child->getAsBranchNode() && child->getAsBranchNode()->getFlowOp() == glslang::EOpDefault)\r
-            defaultSegment = codeSegments.size();\r
-        else if (child->getAsBranchNode() && child->getAsBranchNode()->getFlowOp() == glslang::EOpCase) {\r
-            valueIndexToSegment[caseValues.size()] = codeSegments.size();\r
-            caseValues.push_back(child->getAsBranchNode()->getExpression()->getAsConstantUnion()->getConstArray()[0].getIConst());\r
-        } else\r
-            codeSegments.push_back(child);\r
-    }\r
-\r
-    // handle the case where the last code segment is missing, due to no code \r
-    // statements between the last case and the end of the switch statement\r
-    if ((caseValues.size() && (int)codeSegments.size() == valueIndexToSegment[caseValues.size() - 1]) ||\r
-        (int)codeSegments.size() == defaultSegment)\r
-        codeSegments.push_back(nullptr);\r
-\r
-    // make the switch statement\r
-    std::vector<spv::Block*> segmentBlocks; // returned, as the blocks allocated in the call\r
-    builder.makeSwitch(selector, codeSegments.size(), caseValues, valueIndexToSegment, defaultSegment, segmentBlocks);\r
-\r
-    // emit all the code in the segments\r
-    breakForLoop.push(false);\r
-    for (unsigned int s = 0; s < codeSegments.size(); ++s) {\r
-        builder.nextSwitchSegment(segmentBlocks, s);\r
-        if (codeSegments[s])\r
-            codeSegments[s]->traverse(this);\r
-        else\r
-            builder.addSwitchBreak();\r
-    }\r
-    breakForLoop.pop();\r
-\r
-    builder.endSwitch(segmentBlocks);\r
-\r
-    return false;\r
-}\r
-\r
-void TGlslangToSpvTraverser::visitConstantUnion(glslang::TIntermConstantUnion* node)\r
-{\r
-    int nextConst = 0;\r
-    spv::Id constant = createSpvConstant(node->getType(), node->getConstArray(), nextConst);\r
-\r
-    builder.clearAccessChain();\r
-    builder.setAccessChainRValue(constant);\r
-}\r
-\r
-bool TGlslangToSpvTraverser::visitLoop(glslang::TVisit /* visit */, glslang::TIntermLoop* node)\r
-{\r
-    // body emission needs to know what the for-loop terminal is when it sees a "continue"\r
-    loopTerminal.push(node->getTerminal());\r
-\r
-    builder.makeNewLoop();\r
-\r
-    bool bodyOut = false;\r
-    if (! node->testFirst()) {\r
-        builder.endLoopHeaderWithoutTest();\r
-        if (node->getBody()) {\r
-            breakForLoop.push(true);\r
-            node->getBody()->traverse(this);\r
-            breakForLoop.pop();\r
-        }\r
-        bodyOut = true;\r
-        builder.createBranchToLoopTest();\r
-    }\r
-\r
-    if (node->getTest()) {\r
-        node->getTest()->traverse(this);\r
-        // the AST only contained the test computation, not the branch, we have to add it\r
-        spv::Id condition = builder.accessChainLoad(TranslatePrecisionDecoration(node->getTest()->getType()));\r
-        builder.createLoopTestBranch(condition);\r
-    }\r
-\r
-    if (! bodyOut && node->getBody()) {\r
-        breakForLoop.push(true);\r
-        node->getBody()->traverse(this);\r
-        breakForLoop.pop();\r
-    }\r
-\r
-    if (loopTerminal.top())\r
-        loopTerminal.top()->traverse(this);\r
-\r
-    builder.closeLoop();\r
-\r
-    loopTerminal.pop();\r
-\r
-    return false;\r
-}\r
-\r
-bool TGlslangToSpvTraverser::visitBranch(glslang::TVisit /* visit */, glslang::TIntermBranch* node)\r
-{\r
-    if (node->getExpression())\r
-        node->getExpression()->traverse(this);\r
-\r
-    switch (node->getFlowOp()) {\r
-    case glslang::EOpKill:\r
-        builder.makeDiscard();\r
-        break;\r
-    case glslang::EOpBreak:\r
-        if (breakForLoop.top())\r
-            builder.createLoopExit();\r
-        else\r
-            builder.addSwitchBreak();\r
-        break;\r
-    case glslang::EOpContinue:\r
-        if (loopTerminal.top())\r
-            loopTerminal.top()->traverse(this);\r
-        builder.createLoopContinue();\r
-        break;\r
-    case glslang::EOpReturn:\r
-        if (inMain)\r
-            builder.makeMainReturn();\r
-        else if (node->getExpression())\r
-            builder.makeReturn(false, builder.accessChainLoad(TranslatePrecisionDecoration(node->getExpression()->getType())));\r
-        else\r
-            builder.makeReturn();\r
-\r
-        builder.clearAccessChain();\r
-        break;\r
-\r
-    default:\r
-        spv::MissingFunctionality("branch type");\r
-        break;\r
-    }\r
-\r
-    return false;\r
-}\r
-\r
-spv::Id TGlslangToSpvTraverser::createSpvVariable(const glslang::TIntermSymbol* node)\r
-{\r
-    // First, steer off constants, which are not SPIR-V variables, but \r
-    // can still have a mapping to a SPIR-V Id.\r
-    if (node->getQualifier().storage == glslang::EvqConst) {\r
-        int nextConst = 0;\r
-        return createSpvConstant(node->getType(), node->getConstArray(), nextConst);\r
-    }\r
-\r
-    // Now, handle actual variables\r
-    spv::StorageClass storageClass = TranslateStorageClass(node->getType());\r
-    spv::Id spvType = convertGlslangToSpvType(node->getType());\r
-\r
-    const char* name = node->getName().c_str();\r
-    if (glslang::IsAnonymous(name))\r
-        name = "";\r
-\r
-    return builder.createVariable(storageClass, spvType, name);\r
-}\r
-\r
-// Return type Id of the sampled type.\r
-spv::Id TGlslangToSpvTraverser::getSampledType(const glslang::TSampler& sampler)\r
-{\r
-    switch (sampler.type) {\r
-        case glslang::EbtFloat:    return builder.makeFloatType(32);\r
-        case glslang::EbtInt:      return builder.makeIntType(32);\r
-        case glslang::EbtUint:     return builder.makeUintType(32);\r
-        default:\r
-            spv::MissingFunctionality("sampled type");\r
-            return builder.makeFloatType(32);\r
-    }\r
-}\r
-\r
-// Do full recursive conversion of an arbitrary glslang type to a SPIR-V Id.\r
-spv::Id TGlslangToSpvTraverser::convertGlslangToSpvType(const glslang::TType& type)\r
-{\r
-    spv::Id spvType = 0;\r
-\r
-    switch (type.getBasicType()) {\r
-    case glslang::EbtVoid:\r
-        spvType = builder.makeVoidType();\r
-        if (type.isArray())\r
-            spv::MissingFunctionality("array of void");\r
-        break;\r
-    case glslang::EbtFloat:\r
-        spvType = builder.makeFloatType(32);\r
-        break;\r
-    case glslang::EbtDouble:\r
-        spvType = builder.makeFloatType(64);\r
-        break;\r
-    case glslang::EbtBool:\r
-        spvType = builder.makeBoolType();\r
-        break;\r
-    case glslang::EbtInt:\r
-        spvType = builder.makeIntType(32);\r
-        break;\r
-    case glslang::EbtUint:\r
-        spvType = builder.makeUintType(32);\r
-        break;\r
-    case glslang::EbtSampler:\r
-        {\r
-            const glslang::TSampler& sampler = type.getSampler();\r
-            spvType = builder.makeSampler(getSampledType(sampler), TranslateDimensionality(sampler), \r
-                                          sampler.image ? spv::Builder::samplerContentImage : spv::Builder::samplerContentTextureFilter,\r
-                                          sampler.arrayed, sampler.shadow, sampler.ms);\r
-        }\r
-        break;\r
-    case glslang::EbtStruct:\r
-    case glslang::EbtBlock:\r
-        {\r
-            // If we've seen this struct type, return it\r
-            const glslang::TTypeList* glslangStruct = type.getStruct();\r
-            std::vector<spv::Id> structFields;\r
-            spvType = structMap[glslangStruct];\r
-            if (spvType)\r
-                break;\r
-\r
-            // else, we haven't seen it...\r
-\r
-            // Create a vector of struct types for SPIR-V to consume\r
-            int memberDelta = 0;  // how much the member's index changes from glslang to SPIR-V, normally 0, except sometimes for blocks\r
-            if (type.getBasicType() == glslang::EbtBlock)\r
-                memberRemapper[glslangStruct].resize(glslangStruct->size());\r
-            for (int i = 0; i < (int)glslangStruct->size(); i++) {\r
-                glslang::TType& glslangType = *(*glslangStruct)[i].type;\r
-                if (glslangType.hiddenMember()) {\r
-                    ++memberDelta;\r
-                    if (type.getBasicType() == glslang::EbtBlock)\r
-                        memberRemapper[glslangStruct][i] = -1;\r
-                } else {\r
-                    if (type.getBasicType() == glslang::EbtBlock)\r
-                        memberRemapper[glslangStruct][i] = i - memberDelta;\r
-                    structFields.push_back(convertGlslangToSpvType(glslangType));\r
-                }\r
-            }\r
-\r
-            // Make the SPIR-V type\r
-            spvType = builder.makeStructType(structFields, type.getTypeName().c_str());\r
-            structMap[glslangStruct] = spvType;\r
-\r
-            // Name and decorate the non-hidden members\r
-            for (int i = 0; i < (int)glslangStruct->size(); i++) {\r
-                glslang::TType& glslangType = *(*glslangStruct)[i].type;\r
-                int member = i;\r
-                if (type.getBasicType() == glslang::EbtBlock)\r
-                    member = memberRemapper[glslangStruct][i];\r
-                // using -1 above to indicate a hidden member\r
-                if (member >= 0) {\r
-                    builder.addMemberName(spvType, member, glslangType.getFieldName().c_str());\r
-                    addMemberDecoration(spvType, member, TranslateLayoutDecoration(glslangType));\r
-                    addMemberDecoration(spvType, member, TranslatePrecisionDecoration(glslangType));\r
-                    addMemberDecoration(spvType, member, TranslateInterpolationDecoration(glslangType));\r
-                    addMemberDecoration(spvType, member, TranslateInvariantDecoration(glslangType));\r
-                    if (glslangType.getQualifier().hasLocation())\r
-                        builder.addMemberDecoration(spvType, member, spv::DecorationLocation, glslangType.getQualifier().layoutLocation);\r
-                    if (glslangType.getQualifier().hasComponent())\r
-                        builder.addMemberDecoration(spvType, member, spv::DecorationComponent, glslangType.getQualifier().layoutComponent);\r
-                    if (glslangType.getQualifier().hasXfbOffset())\r
-                        builder.addMemberDecoration(spvType, member, spv::DecorationOffset, glslangType.getQualifier().layoutXfbOffset);\r
-\r
-                    // built-in variable decorations\r
-                    int builtIn = TranslateBuiltInDecoration(glslangType.getQualifier().builtIn);\r
-                    if (builtIn != spv::BadValue)\r
-                        builder.addMemberDecoration(spvType, member, spv::DecorationBuiltIn, builtIn);\r
-                }\r
-            }\r
-\r
-            // Decorate the structure\r
-            addDecoration(spvType, TranslateLayoutDecoration(type));\r
-            addDecoration(spvType, TranslateBlockDecoration(type));\r
-            if (type.getQualifier().hasStream())\r
-                builder.addDecoration(spvType, spv::DecorationStream, type.getQualifier().layoutStream);\r
-            if (glslangIntermediate->getXfbMode()) {\r
-                if (type.getQualifier().hasXfbStride())\r
-                    builder.addDecoration(spvType, spv::DecorationStride, type.getQualifier().layoutXfbStride);\r
-                if (type.getQualifier().hasXfbBuffer())\r
-                    builder.addDecoration(spvType, spv::DecorationXfbBuffer, type.getQualifier().layoutXfbBuffer);\r
-            }\r
-        }\r
-        break;\r
-    default:\r
-        spv::MissingFunctionality("basic type");\r
-        break;\r
-    }\r
-\r
-    if (type.isMatrix())\r
-        spvType = builder.makeMatrixType(spvType, type.getMatrixCols(), type.getMatrixRows());\r
-    else {\r
-        // If this variable has a vector element count greater than 1, create a SPIR-V vector\r
-        if (type.getVectorSize() > 1)\r
-            spvType = builder.makeVectorType(spvType, type.getVectorSize());\r
-    }\r
-\r
-    if (type.isArray()) {\r
-        unsigned arraySize;\r
-        if (! type.isExplicitlySizedArray()) {\r
-            spv::MissingFunctionality("Unsized array");\r
-            arraySize = 8;\r
-        } else\r
-            arraySize = type.getArraySize();\r
-        spvType = builder.makeArrayType(spvType, arraySize);\r
-    }\r
-\r
-    return spvType;\r
-}\r
-\r
-bool TGlslangToSpvTraverser::isShaderEntrypoint(const glslang::TIntermAggregate* node)\r
-{\r
-    return node->getName() == "main(";\r
-}\r
-\r
-// Make all the functions, skeletally, without actually visiting their bodies.\r
-void TGlslangToSpvTraverser::makeFunctions(const glslang::TIntermSequence& glslFunctions)\r
-{\r
-    for (int f = 0; f < (int)glslFunctions.size(); ++f) {\r
-        glslang::TIntermAggregate* glslFunction = glslFunctions[f]->getAsAggregate();\r
-        if (! glslFunction || glslFunction->getOp() != glslang::EOpFunction || isShaderEntrypoint(glslFunction))\r
-            continue;\r
-\r
-        // We're on a user function.  Set up the basic interface for the function now,\r
-        // so that it's available to call.\r
-        // Translating the body will happen later.\r
-        //\r
-        // Typically (except for a "const in" parameter), an address will be passed to the \r
-        // function.  What it is an address of varies:\r
-        //\r
-        // - "in" parameters not marked as "const" can be written to without modifying the argument,\r
-        //  so that write needs to be to a copy, hence the address of a copy works.\r
-        //\r
-        // - "const in" parameters can just be the r-value, as no writes need occur.\r
-        //\r
-        // - "out" and "inout" arguments can't be done as direct pointers, because GLSL has\r
-        // copy-in/copy-out semantics.  They can be handled though with a pointer to a copy.\r
-\r
-        std::vector<spv::Id> paramTypes;\r
-        glslang::TIntermSequence& parameters = glslFunction->getSequence()[0]->getAsAggregate()->getSequence();\r
-\r
-        for (int p = 0; p < (int)parameters.size(); ++p) {\r
-            const glslang::TType& paramType = parameters[p]->getAsTyped()->getType();\r
-            spv::Id typeId = convertGlslangToSpvType(paramType);\r
-            if (paramType.getQualifier().storage != glslang::EvqConstReadOnly)\r
-                typeId = builder.makePointer(spv::StorageClassFunction, typeId);\r
-            else\r
-                constReadOnlyParameters.insert(parameters[p]->getAsSymbolNode()->getId());\r
-            paramTypes.push_back(typeId);\r
-        }\r
-\r
-        spv::Block* functionBlock;\r
-        spv::Function *function = builder.makeFunctionEntry(convertGlslangToSpvType(glslFunction->getType()), glslFunction->getName().c_str(),\r
-                                                              paramTypes, &functionBlock);\r
-\r
-        // Track function to emit/call later\r
-        functionMap[glslFunction->getName().c_str()] = function;\r
-\r
-        // Set the parameter id's\r
-        for (int p = 0; p < (int)parameters.size(); ++p) {\r
-            symbolValues[parameters[p]->getAsSymbolNode()->getId()] = function->getParamId(p);\r
-            // give a name too\r
-            builder.addName(function->getParamId(p), parameters[p]->getAsSymbolNode()->getName().c_str());\r
-        }\r
-    }\r
-}\r
-\r
-// Process all the initializers, while skipping the functions and link objects\r
-void TGlslangToSpvTraverser::makeGlobalInitializers(const glslang::TIntermSequence& initializers)\r
-{\r
-    builder.setBuildPoint(shaderEntry->getLastBlock());\r
-    for (int i = 0; i < (int)initializers.size(); ++i) {\r
-        glslang::TIntermAggregate* initializer = initializers[i]->getAsAggregate();\r
-        if (initializer && initializer->getOp() != glslang::EOpFunction && initializer->getOp() != glslang::EOpLinkerObjects) {\r
-\r
-            // We're on a top-level node that's not a function.  Treat as an initializer, whose\r
-            // code goes into the beginning of main.\r
-            initializer->traverse(this);\r
-        }\r
-    }\r
-}\r
-\r
-// Process all the functions, while skipping initializers.\r
-void TGlslangToSpvTraverser::visitFunctions(const glslang::TIntermSequence& glslFunctions)\r
-{\r
-    for (int f = 0; f < (int)glslFunctions.size(); ++f) {\r
-        glslang::TIntermAggregate* node = glslFunctions[f]->getAsAggregate();\r
-        if (node && (node->getOp() == glslang::EOpFunction || node->getOp() == glslang ::EOpLinkerObjects))\r
-            node->traverse(this);\r
-    }\r
-}\r
-\r
-void TGlslangToSpvTraverser::handleFunctionEntry(const glslang::TIntermAggregate* node)\r
-{\r
-    // SPIR-V functions should already be in the functionMap from the prepass \r
-    // that called makeFunctions().\r
-    spv::Function* function = functionMap[node->getName().c_str()];\r
-    spv::Block* functionBlock = function->getEntryBlock();\r
-    builder.setBuildPoint(functionBlock);\r
-}\r
-\r
-void TGlslangToSpvTraverser::translateArguments(const glslang::TIntermSequence& glslangArguments, std::vector<spv::Id>& arguments)\r
-{\r
-    for (int i = 0; i < (int)glslangArguments.size(); ++i) {\r
-        builder.clearAccessChain();\r
-        glslangArguments[i]->traverse(this);\r
-        arguments.push_back(builder.accessChainLoad(TranslatePrecisionDecoration(glslangArguments[i]->getAsTyped()->getType())));\r
-    }\r
-}\r
-\r
-spv::Id TGlslangToSpvTraverser::handleBuiltInFunctionCall(const glslang::TIntermAggregate* node)\r
-{\r
-    std::vector<spv::Id> arguments;\r
-    translateArguments(node->getSequence(), arguments);\r
-\r
-    std::vector<spv::Id> argTypes;\r
-    for (int a = 0; a < (int)arguments.size(); ++a)\r
-        argTypes.push_back(builder.getTypeId(arguments[a]));\r
-\r
-    spv::Decoration precision = TranslatePrecisionDecoration(node->getType());\r
-\r
-    if (node->getName() == "ftransform(") {\r
-        spv::MissingFunctionality("ftransform()");\r
-        //spv::Id vertex = builder.createVariable(spv::StorageShaderGlobal, spv::VectorType::get(spv::makeFloatType(), 4),\r
-        //                                                             "gl_Vertex_sim");\r
-        //spv::Id matrix = builder.createVariable(spv::StorageShaderGlobal, spv::VectorType::get(spv::makeFloatType(), 4),\r
-        //                                                             "gl_ModelViewProjectionMatrix_sim");\r
-        return 0;\r
-    }\r
-\r
-    if (node->getName().substr(0, 7) == "texture" || node->getName().substr(0, 5) == "texel" || node->getName().substr(0, 6) == "shadow") {\r
-        const glslang::TSampler sampler = node->getSequence()[0]->getAsTyped()->getType().getSampler();\r
-        spv::Builder::TextureParameters params = { };\r
-        params.sampler = arguments[0];\r
-\r
-        // special case size query\r
-        if (node->getName().find("textureSize", 0) != std::string::npos) {\r
-            if (arguments.size() > 1) {\r
-                params.lod = arguments[1];\r
-                return builder.createTextureQueryCall(spv::OpTextureQuerySizeLod, params);\r
-            } else\r
-                return builder.createTextureQueryCall(spv::OpTextureQuerySize, params);\r
-        }\r
-\r
-        // special case the number of samples query\r
-        if (node->getName().find("textureSamples", 0) != std::string::npos)\r
-            return builder.createTextureQueryCall(spv::OpTextureQuerySamples, params);\r
-\r
-        // special case the other queries\r
-        if (node->getName().find("Query", 0) != std::string::npos) {\r
-            if (node->getName().find("Levels", 0) != std::string::npos)\r
-                return builder.createTextureQueryCall(spv::OpTextureQueryLevels, params);\r
-            else if (node->getName().find("Lod", 0) != std::string::npos) {\r
-                params.coords = arguments[1];\r
-                return builder.createTextureQueryCall(spv::OpTextureQueryLod, params);\r
-            } else\r
-                spv::MissingFunctionality("glslang texture query");\r
-        }\r
-\r
-        // This is no longer a query....\r
-\r
-        bool lod = node->getName().find("Lod", 0) != std::string::npos;\r
-        bool proj = node->getName().find("Proj", 0) != std::string::npos;\r
-        bool offsets = node->getName().find("Offsets", 0) != std::string::npos;\r
-        bool offset = ! offsets && node->getName().find("Offset", 0) != std::string::npos;\r
-        bool fetch = node->getName().find("Fetch", 0) != std::string::npos;\r
-        bool gather = node->getName().find("Gather", 0) != std::string::npos;\r
-        bool grad = node->getName().find("Grad", 0) != std::string::npos;\r
-\r
-        if (fetch)\r
-            spv::MissingFunctionality("texel fetch");\r
-        if (gather)\r
-            spv::MissingFunctionality("texture gather");\r
-\r
-        // check for bias argument\r
-        bool bias = false;\r
-        if (! lod && ! gather && ! grad && ! fetch) {\r
-            int nonBiasArgCount = 2;\r
-            if (offset)\r
-                ++nonBiasArgCount;\r
-            if (grad)\r
-                nonBiasArgCount += 2;\r
-\r
-            if ((int)arguments.size() > nonBiasArgCount)\r
-                bias = true;\r
-        }\r
-\r
-        bool cubeCompare = sampler.dim == glslang::EsdCube && sampler.arrayed && sampler.shadow;\r
-\r
-        // set the rest of the arguments\r
-        params.coords = arguments[1];\r
-        int extraArgs = 0;\r
-        if (cubeCompare)\r
-            params.Dref = arguments[2];\r
-        if (lod) {\r
-            params.lod = arguments[2];\r
-            ++extraArgs;\r
-        }\r
-        if (grad) {\r
-            params.gradX = arguments[2 + extraArgs];\r
-            params.gradY = arguments[3 + extraArgs];\r
-            extraArgs += 2;\r
-        }\r
-        //if (gather && compare) {\r
-        //    params.compare = arguments[2 + extraArgs];\r
-        //    ++extraArgs;\r
-        //}\r
-        if (offset | offsets) {\r
-            params.offset = arguments[2 + extraArgs];\r
-            ++extraArgs;\r
-        }\r
-        if (bias) {\r
-            params.bias = arguments[2 + extraArgs];\r
-            ++extraArgs;\r
-        }\r
-\r
-        return builder.createTextureCall(precision, convertGlslangToSpvType(node->getType()), proj, params);\r
-    }\r
-\r
-    spv::MissingFunctionality("built-in function call");\r
-\r
-    return 0;\r
-}\r
-\r
-spv::Id TGlslangToSpvTraverser::handleUserFunctionCall(const glslang::TIntermAggregate* node)\r
-{\r
-    // Grab the function's pointer from the previously created function\r
-    spv::Function* function = functionMap[node->getName().c_str()];\r
-    if (! function)\r
-        return 0;\r
-\r
-    const glslang::TIntermSequence& glslangArgs = node->getSequence();\r
-    const glslang::TQualifierList& qualifiers = node->getQualifierList();\r
-\r
-    //  See comments in makeFunctions() for details about the semantics for parameter passing.\r
-    //\r
-    // These imply we need a four step process:\r
-    // 1. Evaluate the arguments\r
-    // 2. Allocate and make copies of in, out, and inout arguments\r
-    // 3. Make the call\r
-    // 4. Copy back the results\r
-\r
-    // 1. Evaluate the arguments\r
-    std::vector<spv::Builder::AccessChain> lValues;\r
-    std::vector<spv::Id> rValues;\r
-    for (int a = 0; a < (int)glslangArgs.size(); ++a) {\r
-        // build l-value\r
-        builder.clearAccessChain();\r
-        glslangArgs[a]->traverse(this);\r
-        // keep outputs as l-values, evaluate input-only as r-values\r
-        if (qualifiers[a] != glslang::EvqConstReadOnly) {\r
-            // save l-value\r
-            lValues.push_back(builder.getAccessChain());\r
-        } else {\r
-            // process r-value\r
-            rValues.push_back(builder.accessChainLoad(TranslatePrecisionDecoration(glslangArgs[a]->getAsTyped()->getType())));\r
-        }\r
-    }\r
-\r
-    // 2. Allocate space for anything needing a copy, and if it's "in" or "inout"\r
-    // copy the original into that space.\r
-    //\r
-    // Also, build up the list of actual arguments to pass in for the call\r
-    int lValueCount = 0;\r
-    int rValueCount = 0;\r
-    std::vector<spv::Id> spvArgs;\r
-    for (int a = 0; a < (int)glslangArgs.size(); ++a) {\r
-        spv::Id arg;\r
-        if (qualifiers[a] != glslang::EvqConstReadOnly) {\r
-            // need space to hold the copy\r
-            const glslang::TType& paramType = glslangArgs[a]->getAsTyped()->getType();\r
-            arg = builder.createVariable(spv::StorageClassFunction, convertGlslangToSpvType(paramType), "param");\r
-            if (qualifiers[a] == glslang::EvqIn || qualifiers[a] == glslang::EvqInOut) {\r
-                // need to copy the input into output space\r
-                builder.setAccessChain(lValues[lValueCount]);\r
-                spv::Id copy = builder.accessChainLoad(spv::NoPrecision);  // TODO: get precision\r
-                builder.createStore(copy, arg);\r
-            }\r
-            ++lValueCount;\r
-        } else {\r
-            arg = rValues[rValueCount];\r
-            ++rValueCount;\r
-        }\r
-        spvArgs.push_back(arg);\r
-    }\r
-\r
-    // 3. Make the call.\r
-    spv::Id result = builder.createFunctionCall(function, spvArgs);\r
-\r
-    // 4. Copy back out an "out" arguments.\r
-    lValueCount = 0;\r
-    for (int a = 0; a < (int)glslangArgs.size(); ++a) {\r
-        if (qualifiers[a] != glslang::EvqConstReadOnly) {\r
-            if (qualifiers[a] == glslang::EvqOut || qualifiers[a] == glslang::EvqInOut) {\r
-                spv::Id copy = builder.createLoad(spvArgs[a]);\r
-                builder.setAccessChain(lValues[lValueCount]);\r
-                builder.accessChainStore(copy);\r
-            }\r
-            ++lValueCount;\r
-        }\r
-    }\r
-\r
-    return result;\r
-}\r
-\r
-// Translate AST operation to SPV operation, already having SPV-based operands/types.\r
-spv::Id TGlslangToSpvTraverser::createBinaryOperation(glslang::TOperator op, spv::Decoration precision, \r
-                                                      spv::Id typeId, spv::Id left, spv::Id right,\r
-                                                      glslang::TBasicType typeProxy, bool reduceComparison)\r
-{\r
-    bool isUnsigned = typeProxy == glslang::EbtUint;\r
-    bool isFloat = typeProxy == glslang::EbtFloat || typeProxy == glslang::EbtDouble;\r
-\r
-    spv::Op binOp = spv::OpNop;\r
-    bool needsPromotion = true;\r
-    bool comparison = false;\r
-\r
-    switch (op) {\r
-    case glslang::EOpAdd:\r
-    case glslang::EOpAddAssign:\r
-        if (isFloat)\r
-            binOp = spv::OpFAdd;\r
-        else\r
-            binOp = spv::OpIAdd;\r
-        break;\r
-    case glslang::EOpSub:\r
-    case glslang::EOpSubAssign:\r
-        if (isFloat)\r
-            binOp = spv::OpFSub;\r
-        else\r
-            binOp = spv::OpISub;\r
-        break;\r
-    case glslang::EOpMul:\r
-    case glslang::EOpMulAssign:\r
-        if (isFloat)\r
-            binOp = spv::OpFMul;\r
-        else\r
-            binOp = spv::OpIMul;\r
-        break;\r
-    case glslang::EOpVectorTimesScalar:\r
-    case glslang::EOpVectorTimesScalarAssign:\r
-        if (builder.isVector(right))\r
-            std::swap(left, right);\r
-        assert(builder.isScalar(right));\r
-        binOp = spv::OpVectorTimesScalar;\r
-        needsPromotion = false;\r
-        break;\r
-    case glslang::EOpVectorTimesMatrix:\r
-    case glslang::EOpVectorTimesMatrixAssign:\r
-        assert(builder.isVector(left));\r
-        assert(builder.isMatrix(right));\r
-        binOp = spv::OpVectorTimesMatrix;\r
-        break;\r
-    case glslang::EOpMatrixTimesVector:\r
-        assert(builder.isMatrix(left));\r
-        assert(builder.isVector(right));\r
-        binOp = spv::OpMatrixTimesVector;\r
-        break;\r
-    case glslang::EOpMatrixTimesScalar:\r
-    case glslang::EOpMatrixTimesScalarAssign:\r
-        if (builder.isMatrix(right))\r
-            std::swap(left, right);\r
-        assert(builder.isScalar(right));\r
-        binOp = spv::OpMatrixTimesScalar;\r
-        break;\r
-    case glslang::EOpMatrixTimesMatrix:\r
-    case glslang::EOpMatrixTimesMatrixAssign:\r
-        assert(builder.isMatrix(left));\r
-        assert(builder.isMatrix(right));\r
-        binOp = spv::OpMatrixTimesMatrix;\r
-        break;\r
-    case glslang::EOpOuterProduct:\r
-        binOp = spv::OpOuterProduct;\r
-        needsPromotion = false;\r
-        break;\r
-\r
-    case glslang::EOpDiv:\r
-    case glslang::EOpDivAssign:\r
-        if (isFloat)\r
-            binOp = spv::OpFDiv;\r
-        else if (isUnsigned)\r
-            binOp = spv::OpUDiv;\r
-        else\r
-            binOp = spv::OpSDiv;\r
-        break;\r
-    case glslang::EOpMod:\r
-    case glslang::EOpModAssign:\r
-        if (isFloat)\r
-            binOp = spv::OpFMod;\r
-        else if (isUnsigned)\r
-            binOp = spv::OpUMod;\r
-        else\r
-            binOp = spv::OpSMod;\r
-        break;\r
-    case glslang::EOpRightShift:\r
-    case glslang::EOpRightShiftAssign:\r
-        if (isUnsigned)\r
-            binOp = spv::OpShiftRightLogical;\r
-        else\r
-            binOp = spv::OpShiftRightArithmetic;\r
-        break;\r
-    case glslang::EOpLeftShift:\r
-    case glslang::EOpLeftShiftAssign:\r
-        binOp = spv::OpShiftLeftLogical;\r
-        break;\r
-    case glslang::EOpAnd:\r
-    case glslang::EOpAndAssign:\r
-        binOp = spv::OpBitwiseAnd;\r
-        break;\r
-    case glslang::EOpLogicalAnd:\r
-        needsPromotion = false;\r
-        binOp = spv::OpLogicalAnd;\r
-        break;\r
-    case glslang::EOpInclusiveOr:\r
-    case glslang::EOpInclusiveOrAssign:\r
-        binOp = spv::OpBitwiseOr;\r
-        break;\r
-    case glslang::EOpLogicalOr:\r
-        needsPromotion = false;\r
-        binOp = spv::OpLogicalOr;\r
-        break;\r
-    case glslang::EOpExclusiveOr:\r
-    case glslang::EOpExclusiveOrAssign:\r
-        binOp = spv::OpBitwiseXor;\r
-        break;\r
-    case glslang::EOpLogicalXor:\r
-        needsPromotion = false;\r
-        binOp = spv::OpLogicalXor;\r
-        break;\r
-\r
-    case glslang::EOpLessThan:\r
-    case glslang::EOpGreaterThan:\r
-    case glslang::EOpLessThanEqual:\r
-    case glslang::EOpGreaterThanEqual:\r
-    case glslang::EOpEqual:\r
-    case glslang::EOpNotEqual:\r
-    case glslang::EOpVectorEqual:\r
-    case glslang::EOpVectorNotEqual:\r
-        comparison = true;\r
-        break;\r
-    default:\r
-        break;\r
-    }\r
-\r
-    if (binOp != spv::OpNop) {\r
-        if (builder.isMatrix(left) || builder.isMatrix(right)) {\r
-            switch (binOp) {\r
-            case spv::OpMatrixTimesScalar:\r
-            case spv::OpVectorTimesMatrix:\r
-            case spv::OpMatrixTimesVector:\r
-            case spv::OpMatrixTimesMatrix:\r
-                break;\r
-            case spv::OpFDiv:\r
-                // turn it into a multiply...\r
-                assert(builder.isMatrix(left) && builder.isScalar(right));\r
-                right = builder.createBinOp(spv::OpFDiv, builder.getTypeId(right), builder.makeFloatConstant(1.0F), right);\r
-                binOp = spv::OpFMul;\r
-                break;\r
-            default:\r
-                spv::MissingFunctionality("binary operation on matrix");\r
-                break;\r
-            }\r
-\r
-            spv::Id id = builder.createBinOp(binOp, typeId, left, right);\r
-            builder.setPrecision(id, precision);\r
-\r
-            return id;\r
-        }\r
-\r
-        // No matrix involved; make both operands be the same number of components, if needed\r
-        if (needsPromotion)\r
-            builder.promoteScalar(precision, left, right);\r
-\r
-        spv::Id id = builder.createBinOp(binOp, typeId, left, right);\r
-        builder.setPrecision(id, precision);\r
-\r
-        return id;\r
-    }\r
-\r
-    if (! comparison)\r
-        return 0;\r
-\r
-    // Comparison instructions\r
-\r
-    if (reduceComparison && (builder.isVector(left) || builder.isMatrix(left) || builder.isAggregate(left))) {\r
-        assert(op == glslang::EOpEqual || op == glslang::EOpNotEqual);\r
-\r
-        return builder.createCompare(precision, left, right, op == glslang::EOpEqual);\r
-    }\r
-\r
-    switch (op) {\r
-    case glslang::EOpLessThan:\r
-        if (isFloat)\r
-            binOp = spv::OpFOrdLessThan;\r
-        else if (isUnsigned)\r
-            binOp = spv::OpULessThan;\r
-        else\r
-            binOp = spv::OpSLessThan;\r
-        break;\r
-    case glslang::EOpGreaterThan:\r
-        if (isFloat)\r
-            binOp = spv::OpFOrdGreaterThan;\r
-        else if (isUnsigned)\r
-            binOp = spv::OpUGreaterThan;\r
-        else\r
-            binOp = spv::OpSGreaterThan;\r
-        break;\r
-    case glslang::EOpLessThanEqual:\r
-        if (isFloat)\r
-            binOp = spv::OpFOrdLessThanEqual;\r
-        else if (isUnsigned)\r
-            binOp = spv::OpULessThanEqual;\r
-        else\r
-            binOp = spv::OpSLessThanEqual;\r
-        break;\r
-    case glslang::EOpGreaterThanEqual:\r
-        if (isFloat)\r
-            binOp = spv::OpFOrdGreaterThanEqual;\r
-        else if (isUnsigned)\r
-            binOp = spv::OpUGreaterThanEqual;\r
-        else\r
-            binOp = spv::OpSGreaterThanEqual;\r
-        break;\r
-    case glslang::EOpEqual:\r
-    case glslang::EOpVectorEqual:\r
-        if (isFloat)\r
-            binOp = spv::OpFOrdEqual;\r
-        else\r
-            binOp = spv::OpIEqual;\r
-        break;\r
-    case glslang::EOpNotEqual:\r
-    case glslang::EOpVectorNotEqual:\r
-        if (isFloat)\r
-            binOp = spv::OpFOrdNotEqual;\r
-        else\r
-            binOp = spv::OpINotEqual;\r
-        break;\r
-    default:\r
-        break;\r
-    }\r
-\r
-    if (binOp != spv::OpNop) {\r
-        spv::Id id = builder.createBinOp(binOp, typeId, left, right);\r
-        builder.setPrecision(id, precision);\r
-\r
-        return id;\r
-    }\r
-\r
-    return 0;\r
-}\r
-\r
-spv::Id TGlslangToSpvTraverser::createUnaryOperation(glslang::TOperator op, spv::Decoration precision, spv::Id typeId, spv::Id operand, bool isFloat)\r
-{\r
-    spv::Op unaryOp = spv::OpNop;\r
-    int libCall = -1;\r
-\r
-    switch (op) {\r
-    case glslang::EOpNegative:\r
-        if (isFloat)\r
-            unaryOp = spv::OpFNegate;\r
-        else\r
-            unaryOp = spv::OpSNegate;\r
-        break;\r
-\r
-    case glslang::EOpLogicalNot:\r
-    case glslang::EOpVectorLogicalNot:\r
-    case glslang::EOpBitwiseNot:\r
-        unaryOp = spv::OpNot;\r
-        break;\r
-    \r
-    case glslang::EOpDeterminant:\r
-        libCall = GLSL_STD_450::Determinant;\r
-        break;\r
-    case glslang::EOpMatrixInverse:\r
-        libCall = GLSL_STD_450::MatrixInverse;\r
-        break;\r
-    case glslang::EOpTranspose:\r
-        unaryOp = spv::OpTranspose;\r
-        break;\r
-\r
-    case glslang::EOpRadians:\r
-        libCall = GLSL_STD_450::Radians;\r
-        break;\r
-    case glslang::EOpDegrees:\r
-        libCall = GLSL_STD_450::Degrees;\r
-        break;\r
-    case glslang::EOpSin:\r
-        libCall = GLSL_STD_450::Sin;\r
-        break;\r
-    case glslang::EOpCos:\r
-        libCall = GLSL_STD_450::Cos;\r
-        break;\r
-    case glslang::EOpTan:\r
-        libCall = GLSL_STD_450::Tan;\r
-        break;\r
-    case glslang::EOpAcos:\r
-        libCall = GLSL_STD_450::Acos;\r
-        break;\r
-    case glslang::EOpAsin:\r
-        libCall = GLSL_STD_450::Asin;\r
-        break;\r
-    case glslang::EOpAtan:\r
-        libCall = GLSL_STD_450::Atan;\r
-        break;\r
-\r
-    case glslang::EOpAcosh:\r
-        libCall = GLSL_STD_450::Acosh;\r
-        break;\r
-    case glslang::EOpAsinh:\r
-        libCall = GLSL_STD_450::Asinh;\r
-        break;\r
-    case glslang::EOpAtanh:\r
-        libCall = GLSL_STD_450::Atanh;\r
-        break;\r
-    case glslang::EOpTanh:\r
-        libCall = GLSL_STD_450::Tanh;\r
-        break;\r
-    case glslang::EOpCosh:\r
-        libCall = GLSL_STD_450::Cosh;\r
-        break;\r
-    case glslang::EOpSinh:\r
-        libCall = GLSL_STD_450::Sinh;\r
-        break;\r
-\r
-    case glslang::EOpLength:\r
-        libCall = GLSL_STD_450::Length;\r
-        break;\r
-    case glslang::EOpNormalize:\r
-        libCall = GLSL_STD_450::Normalize;\r
-        break;\r
-\r
-    case glslang::EOpExp:\r
-        libCall = GLSL_STD_450::Exp;\r
-        break;\r
-    case glslang::EOpLog:\r
-        libCall = GLSL_STD_450::Log;\r
-        break;\r
-    case glslang::EOpExp2:\r
-        libCall = GLSL_STD_450::Exp2;\r
-        break;\r
-    case glslang::EOpLog2:\r
-        libCall = GLSL_STD_450::Log2;\r
-        break;\r
-    case glslang::EOpSqrt:\r
-        libCall = GLSL_STD_450::Sqrt;\r
-        break;\r
-    case glslang::EOpInverseSqrt:\r
-        libCall = GLSL_STD_450::InverseSqrt;\r
-        break;\r
-\r
-    case glslang::EOpFloor:\r
-        libCall = GLSL_STD_450::Floor;\r
-        break;\r
-    case glslang::EOpTrunc:\r
-        libCall = GLSL_STD_450::Trunc;\r
-        break;\r
-    case glslang::EOpRound:\r
-        libCall = GLSL_STD_450::Round;\r
-        break;\r
-    case glslang::EOpRoundEven:\r
-        libCall = GLSL_STD_450::RoundEven;\r
-        break;\r
-    case glslang::EOpCeil:\r
-        libCall = GLSL_STD_450::Ceil;\r
-        break;\r
-    case glslang::EOpFract:\r
-        libCall = GLSL_STD_450::Fract;\r
-        break;\r
-\r
-    case glslang::EOpIsNan:\r
-        unaryOp = spv::OpIsNan;\r
-        break;\r
-    case glslang::EOpIsInf:\r
-        unaryOp = spv::OpIsInf;\r
-        break;\r
-\r
-    case glslang::EOpFloatBitsToInt:\r
-        libCall = GLSL_STD_450::FloatBitsToInt;\r
-        break;\r
-    case glslang::EOpFloatBitsToUint:\r
-        libCall = GLSL_STD_450::FloatBitsToUint;\r
-        break;\r
-    case glslang::EOpIntBitsToFloat:\r
-        libCall = GLSL_STD_450::IntBitsToFloat;\r
-        break;\r
-    case glslang::EOpUintBitsToFloat:\r
-        libCall = GLSL_STD_450::UintBitsToFloat;\r
-        break;\r
-    case glslang::EOpPackSnorm2x16:\r
-        libCall = GLSL_STD_450::PackSnorm2x16;\r
-        break;\r
-    case glslang::EOpUnpackSnorm2x16:\r
-        libCall = GLSL_STD_450::UnpackSnorm2x16;\r
-        break;\r
-    case glslang::EOpPackUnorm2x16:\r
-        libCall = GLSL_STD_450::PackUnorm2x16;\r
-        break;\r
-    case glslang::EOpUnpackUnorm2x16:\r
-        libCall = GLSL_STD_450::UnpackUnorm2x16;\r
-        break;\r
-    case glslang::EOpPackHalf2x16:\r
-        libCall = GLSL_STD_450::PackHalf2x16;\r
-        break;\r
-    case glslang::EOpUnpackHalf2x16:\r
-        libCall = GLSL_STD_450::UnpackHalf2x16;\r
-        break;\r
-\r
-    case glslang::EOpDPdx:\r
-        unaryOp = spv::OpDPdx;\r
-        break;\r
-    case glslang::EOpDPdy:\r
-        unaryOp = spv::OpDPdy;\r
-        break;\r
-    case glslang::EOpFwidth:\r
-        unaryOp = spv::OpFwidth;\r
-        break;\r
-    case glslang::EOpDPdxFine:\r
-        unaryOp = spv::OpDPdxFine;\r
-        break;\r
-    case glslang::EOpDPdyFine:\r
-        unaryOp = spv::OpDPdyFine;\r
-        break;\r
-    case glslang::EOpFwidthFine:\r
-        unaryOp = spv::OpFwidthFine;\r
-        break;\r
-    case glslang::EOpDPdxCoarse:\r
-        unaryOp = spv::OpDPdxCoarse;\r
-        break;\r
-    case glslang::EOpDPdyCoarse:\r
-        unaryOp = spv::OpDPdyCoarse;\r
-        break;\r
-    case glslang::EOpFwidthCoarse:\r
-        unaryOp = spv::OpFwidthCoarse;\r
-        break;\r
-\r
-    case glslang::EOpAny:\r
-        unaryOp = spv::OpAny;\r
-        break;\r
-    case glslang::EOpAll:\r
-        unaryOp = spv::OpAll;\r
-        break;\r
-\r
-    case glslang::EOpAbs:\r
-        libCall = GLSL_STD_450::Abs;\r
-        break;\r
-    case glslang::EOpSign:\r
-        libCall = GLSL_STD_450::Sign;\r
-        break;\r
-\r
-    default:\r
-        return 0;\r
-    }\r
-\r
-    spv::Id id;\r
-    if (libCall >= 0) {\r
-        std::vector<spv::Id> args;\r
-        args.push_back(operand);\r
-        id = builder.createBuiltinCall(precision, typeId, stdBuiltins, libCall, args);\r
-    } else\r
-        id = builder.createUnaryOp(unaryOp, typeId, operand);\r
-\r
-    builder.setPrecision(id, precision);\r
-\r
-    return id;\r
-}\r
-\r
-spv::Id TGlslangToSpvTraverser::createConversion(glslang::TOperator op, spv::Decoration precision, spv::Id destType, spv::Id operand)\r
-{\r
-    spv::Op convOp = spv::OpNop;\r
-    spv::Id zero = 0;\r
-    spv::Id one = 0;\r
-\r
-    int vectorSize = builder.isVectorType(destType) ? builder.getNumTypeComponents(destType) : 0;\r
-\r
-    switch (op) {\r
-    case glslang::EOpConvIntToBool:\r
-    case glslang::EOpConvUintToBool:\r
-        zero = builder.makeUintConstant(0);\r
-        zero = makeSmearedConstant(zero, vectorSize);\r
-        return builder.createBinOp(spv::OpINotEqual, destType, operand, zero);\r
-\r
-    case glslang::EOpConvFloatToBool:\r
-        zero = builder.makeFloatConstant(0.0F);\r
-        zero = makeSmearedConstant(zero, vectorSize);\r
-        return builder.createBinOp(spv::OpFOrdNotEqual, destType, operand, zero);\r
-\r
-    case glslang::EOpConvDoubleToBool:\r
-        zero = builder.makeDoubleConstant(0.0);\r
-        zero = makeSmearedConstant(zero, vectorSize);\r
-        return builder.createBinOp(spv::OpFOrdNotEqual, destType, operand, zero);\r
-\r
-    case glslang::EOpConvBoolToFloat:\r
-        convOp = spv::OpSelect;\r
-        zero = builder.makeFloatConstant(0.0);\r
-        one  = builder.makeFloatConstant(1.0);\r
-        break;\r
-    case glslang::EOpConvBoolToDouble:\r
-        convOp = spv::OpSelect;\r
-        zero = builder.makeDoubleConstant(0.0);\r
-        one  = builder.makeDoubleConstant(1.0);\r
-        break;\r
-    case glslang::EOpConvBoolToInt:\r
-        zero = builder.makeIntConstant(0);\r
-        one  = builder.makeIntConstant(1);\r
-        convOp = spv::OpSelect;\r
-        break;\r
-    case glslang::EOpConvBoolToUint:\r
-        zero = builder.makeUintConstant(0);\r
-        one  = builder.makeUintConstant(1);\r
-        convOp = spv::OpSelect;\r
-        break;\r
-\r
-    case glslang::EOpConvIntToFloat:\r
-    case glslang::EOpConvIntToDouble:\r
-        convOp = spv::OpConvertSToF;\r
-        break;\r
-\r
-    case glslang::EOpConvUintToFloat:\r
-    case glslang::EOpConvUintToDouble:\r
-        convOp = spv::OpConvertUToF;\r
-        break;\r
-\r
-    case glslang::EOpConvDoubleToFloat:\r
-    case glslang::EOpConvFloatToDouble:\r
-        convOp = spv::OpFConvert;\r
-        break;\r
-\r
-    case glslang::EOpConvFloatToInt:\r
-    case glslang::EOpConvDoubleToInt:\r
-        convOp = spv::OpConvertFToS;\r
-        break;\r
-\r
-    case glslang::EOpConvUintToInt:\r
-    case glslang::EOpConvIntToUint:\r
-        convOp = spv::OpBitcast;\r
-        break;\r
-\r
-    case glslang::EOpConvFloatToUint:\r
-    case glslang::EOpConvDoubleToUint:\r
-        convOp = spv::OpConvertFToU;\r
-        break;\r
-    default:\r
-        break;\r
-    }\r
-\r
-    spv::Id result = 0;\r
-    if (convOp == spv::OpNop)\r
-        return result;\r
-\r
-    if (convOp == spv::OpSelect) {\r
-        zero = makeSmearedConstant(zero, vectorSize);\r
-        one  = makeSmearedConstant(one, vectorSize);\r
-        result = builder.createTriOp(convOp, destType, operand, one, zero);\r
-    } else\r
-        result = builder.createUnaryOp(convOp, destType, operand);\r
-\r
-    builder.setPrecision(result, precision);\r
-\r
-    return result;\r
-}\r
-\r
-spv::Id TGlslangToSpvTraverser::makeSmearedConstant(spv::Id constant, int vectorSize)\r
-{\r
-    if (vectorSize == 0)\r
-        return constant;\r
-\r
-    spv::Id vectorTypeId = builder.makeVectorType(builder.getTypeId(constant), vectorSize);\r
-    std::vector<spv::Id> components;\r
-    for (int c = 0; c < vectorSize; ++c)\r
-        components.push_back(constant);\r
-    return builder.makeCompositeConstant(vectorTypeId, components);\r
-}\r
-\r
-spv::Id TGlslangToSpvTraverser::createMiscOperation(glslang::TOperator op, spv::Decoration precision, spv::Id typeId, std::vector<spv::Id>& operands)\r
-{\r
-    spv::Op opCode = spv::OpNop;\r
-    int libCall = -1;\r
-\r
-    switch (op) {\r
-    case glslang::EOpMin:\r
-        libCall = GLSL_STD_450::Min;\r
-        break;\r
-    case glslang::EOpModf:\r
-        libCall = GLSL_STD_450::Modf;\r
-        break;\r
-    case glslang::EOpMax:\r
-        libCall = GLSL_STD_450::Max;\r
-        break;\r
-    case glslang::EOpPow:\r
-        libCall = GLSL_STD_450::Pow;\r
-        break;\r
-    case glslang::EOpDot:\r
-        opCode = spv::OpDot;\r
-        break;\r
-    case glslang::EOpAtan:\r
-        libCall = GLSL_STD_450::Atan2;\r
-        break;\r
-\r
-    case glslang::EOpClamp:\r
-        libCall = GLSL_STD_450::Clamp;\r
-        break;\r
-    case glslang::EOpMix:\r
-        libCall = GLSL_STD_450::Mix;\r
-        break;\r
-    case glslang::EOpStep:\r
-        libCall = GLSL_STD_450::Step;\r
-        break;\r
-    case glslang::EOpSmoothStep:\r
-        libCall = GLSL_STD_450::SmoothStep;\r
-        break;\r
-\r
-    case glslang::EOpDistance:\r
-        libCall = GLSL_STD_450::Distance;\r
-        break;\r
-    case glslang::EOpCross:\r
-        libCall = GLSL_STD_450::Cross;\r
-        break;\r
-    case glslang::EOpFaceForward:\r
-        libCall = GLSL_STD_450::FaceForward;\r
-        break;\r
-    case glslang::EOpReflect:\r
-        libCall = GLSL_STD_450::Reflect;\r
-        break;\r
-    case glslang::EOpRefract:\r
-        libCall = GLSL_STD_450::Refract;\r
-        break;\r
-    default:\r
-        return 0;\r
-    }\r
-\r
-    spv::Id id = 0;\r
-    if (libCall >= 0)\r
-        id = builder.createBuiltinCall(precision, typeId, stdBuiltins, libCall, operands);\r
-    else {\r
-        switch (operands.size()) {\r
-        case 0:\r
-            // should all be handled by visitAggregate and createNoArgOperation\r
-            assert(0);\r
-            return 0;\r
-        case 1:\r
-            // should all be handled by createUnaryOperation\r
-            assert(0);\r
-            return 0;\r
-        case 2:\r
-            id = builder.createBinOp(opCode, typeId, operands[0], operands[1]);\r
-            break;\r
-        case 3:\r
-            id = builder.createTernaryOp(opCode, typeId, operands[0], operands[1], operands[2]);\r
-            break;\r
-        default:\r
-            // These do not exist yet\r
-            assert(0 && "operation with more than 3 operands");\r
-            break;\r
-        }\r
-    }\r
-\r
-    builder.setPrecision(id, precision);\r
-\r
-    return id;\r
-}\r
-\r
-// Intrinsics with no arguments, no return value, and no precision.\r
-spv::Id TGlslangToSpvTraverser::createNoArgOperation(glslang::TOperator op)\r
-{\r
-    // TODO: get the barrier operands correct\r
-\r
-    switch (op) {\r
-    case glslang::EOpEmitVertex:\r
-        builder.createNoResultOp(spv::OpEmitVertex);\r
-        return 0;\r
-    case glslang::EOpEndPrimitive:\r
-        builder.createNoResultOp(spv::OpEndPrimitive);\r
-        return 0;\r
-    case glslang::EOpBarrier:\r
-        builder.createMemoryBarrier(spv::ExecutionScopeDevice, spv::MemorySemanticsAllMemory);\r
-        builder.createControlBarrier(spv::ExecutionScopeDevice);\r
-        return 0;\r
-    case glslang::EOpMemoryBarrier:\r
-        builder.createMemoryBarrier(spv::ExecutionScopeDevice, spv::MemorySemanticsAllMemory);\r
-        return 0;\r
-    case glslang::EOpMemoryBarrierAtomicCounter:\r
-        builder.createMemoryBarrier(spv::ExecutionScopeDevice, spv::MemorySemanticsAtomicCounterMemoryMask);\r
-        return 0;\r
-    case glslang::EOpMemoryBarrierBuffer:\r
-        builder.createMemoryBarrier(spv::ExecutionScopeDevice, spv::MemorySemanticsUniformMemoryMask);\r
-        return 0;\r
-    case glslang::EOpMemoryBarrierImage:\r
-        builder.createMemoryBarrier(spv::ExecutionScopeDevice, spv::MemorySemanticsImageMemoryMask);\r
-        return 0;\r
-    case glslang::EOpMemoryBarrierShared:\r
-        builder.createMemoryBarrier(spv::ExecutionScopeDevice, spv::MemorySemanticsWorkgroupLocalMemoryMask);\r
-        return 0;\r
-    case glslang::EOpGroupMemoryBarrier:\r
-        builder.createMemoryBarrier(spv::ExecutionScopeDevice, spv::MemorySemanticsWorkgroupGlobalMemoryMask);\r
-        return 0;\r
-    default:\r
-        spv::MissingFunctionality("operation with no arguments");\r
-        return 0;\r
-    }\r
-}\r
-\r
-spv::Id TGlslangToSpvTraverser::getSymbolId(const glslang::TIntermSymbol* symbol)\r
-{\r
-    std::map<int, spv::Id>::iterator iter;\r
-    iter = symbolValues.find(symbol->getId());\r
-    spv::Id id;\r
-    if (symbolValues.end() != iter) {\r
-        id = iter->second;\r
-        return id;\r
-    }\r
-\r
-    // it was not found, create it\r
-    id = createSpvVariable(symbol);\r
-    symbolValues[symbol->getId()] = id;\r
-\r
-    if (! symbol->getType().isStruct()) {\r
-        addDecoration(id, TranslatePrecisionDecoration(symbol->getType()));\r
-        addDecoration(id, TranslateInterpolationDecoration(symbol->getType()));\r
-        if (symbol->getQualifier().hasLocation())\r
-            builder.addDecoration(id, spv::DecorationLocation, symbol->getQualifier().layoutLocation);\r
-        if (symbol->getQualifier().hasIndex())\r
-            builder.addDecoration(id, spv::DecorationIndex, symbol->getQualifier().layoutIndex);\r
-        if (symbol->getQualifier().hasComponent())\r
-            builder.addDecoration(id, spv::DecorationComponent, symbol->getQualifier().layoutComponent);\r
-        if (glslangIntermediate->getXfbMode()) {\r
-            if (symbol->getQualifier().hasXfbStride())\r
-                builder.addDecoration(id, spv::DecorationStride, symbol->getQualifier().layoutXfbStride);\r
-            if (symbol->getQualifier().hasXfbBuffer())\r
-                builder.addDecoration(id, spv::DecorationXfbBuffer, symbol->getQualifier().layoutXfbBuffer);\r
-            if (symbol->getQualifier().hasXfbOffset())\r
-                builder.addDecoration(id, spv::DecorationOffset, symbol->getQualifier().layoutXfbOffset);\r
-        }\r
-    }\r
-\r
-    addDecoration(id, TranslateInvariantDecoration(symbol->getType()));\r
-    if (symbol->getQualifier().hasStream())\r
-        builder.addDecoration(id, spv::DecorationStream, symbol->getQualifier().layoutStream);\r
-    if (symbol->getQualifier().hasSet())\r
-        builder.addDecoration(id, spv::DecorationDescriptorSet, symbol->getQualifier().layoutSet);\r
-    if (symbol->getQualifier().hasBinding())\r
-        builder.addDecoration(id, spv::DecorationBinding, symbol->getQualifier().layoutBinding);\r
-    if (glslangIntermediate->getXfbMode()) {\r
-        if (symbol->getQualifier().hasXfbStride())\r
-            builder.addDecoration(id, spv::DecorationStride, symbol->getQualifier().layoutXfbStride);\r
-        if (symbol->getQualifier().hasXfbBuffer())\r
-            builder.addDecoration(id, spv::DecorationXfbBuffer, symbol->getQualifier().layoutXfbBuffer);\r
-    }\r
-\r
-    // built-in variable decorations\r
-    int builtIn = TranslateBuiltInDecoration(symbol->getQualifier().builtIn);\r
-    if (builtIn != spv::BadValue)\r
-        builder.addDecoration(id, spv::DecorationBuiltIn, builtIn);\r
-\r
-    if (linkageOnly)\r
-        builder.addDecoration(id, spv::DecorationNoStaticUse);\r
-\r
-    return id;\r
-}\r
-\r
-void TGlslangToSpvTraverser::addDecoration(spv::Id id, spv::Decoration dec)\r
-{\r
-    if (dec != spv::BadValue)\r
-        builder.addDecoration(id, dec);\r
-}\r
-\r
-void TGlslangToSpvTraverser::addMemberDecoration(spv::Id id, int member, spv::Decoration dec)\r
-{\r
-    if (dec != spv::BadValue)\r
-        builder.addMemberDecoration(id, (unsigned)member, dec);\r
-}\r
-\r
-// Use 'consts' as the flattened glslang source of scalar constants to recursively\r
-// build the aggregate SPIR-V constant.\r
-//\r
-// If there are not enough elements present in 'consts', 0 will be substituted;\r
-// an empty 'consts' can be used to create a fully zeroed SPIR-V constant.\r
-//\r
-spv::Id TGlslangToSpvTraverser::createSpvConstant(const glslang::TType& glslangType, const glslang::TConstUnionArray& consts, int& nextConst)\r
-{\r
-    // vector of constants for SPIR-V\r
-    std::vector<spv::Id> spvConsts;\r
-\r
-    // Type is used for struct and array constants\r
-    spv::Id typeId = convertGlslangToSpvType(glslangType);\r
-\r
-    if (glslangType.isArray()) {\r
-        glslang::TType elementType;\r
-        elementType.shallowCopy(glslangType);   // TODO: desktop arrays of arrays functionality will need a deeper copy to avoid modifying the original\r
-        elementType.dereference();\r
-        for (int i = 0; i < glslangType.getArraySize(); ++i)\r
-            spvConsts.push_back(createSpvConstant(elementType, consts, nextConst));\r
-    } else if (glslangType.isMatrix()) {\r
-        glslang::TType vectorType;\r
-        vectorType.shallowCopy(glslangType);\r
-        vectorType.dereference();\r
-        for (int col = 0; col < glslangType.getMatrixCols(); ++col)\r
-            spvConsts.push_back(createSpvConstant(vectorType, consts, nextConst));\r
-    } else if (glslangType.getStruct()) {\r
-        glslang::TVector<glslang::TTypeLoc>::const_iterator iter;\r
-        for (iter = glslangType.getStruct()->begin(); iter != glslangType.getStruct()->end(); ++iter)\r
-            spvConsts.push_back(createSpvConstant(*iter->type, consts, nextConst));\r
-    } else if (glslangType.isVector()) {\r
-        for (unsigned int i = 0; i < (unsigned int)glslangType.getVectorSize(); ++i) {\r
-            bool zero = nextConst >= consts.size();\r
-            switch (glslangType.getBasicType()) {\r
-            case glslang::EbtInt:\r
-                spvConsts.push_back(builder.makeIntConstant(zero ? 0 : consts[nextConst].getIConst()));\r
-                break;\r
-            case glslang::EbtUint:\r
-                spvConsts.push_back(builder.makeUintConstant(zero ? 0 : consts[nextConst].getUConst()));\r
-                break;\r
-            case glslang::EbtFloat:\r
-                spvConsts.push_back(builder.makeFloatConstant(zero ? 0.0F : (float)consts[nextConst].getDConst()));\r
-                break;\r
-            case glslang::EbtDouble:\r
-                spvConsts.push_back(builder.makeDoubleConstant(zero ? 0.0 : consts[nextConst].getDConst()));\r
-                break;\r
-            case glslang::EbtBool:\r
-                spvConsts.push_back(builder.makeBoolConstant(zero ? false : consts[nextConst].getBConst()));\r
-                break;\r
-            default:\r
-                spv::MissingFunctionality("constant vector type");\r
-                break;\r
-            }\r
-            ++nextConst;\r
-        }\r
-    } else {\r
-        // we have a non-aggregate (scalar) constant\r
-        bool zero = nextConst >= consts.size();\r
-        spv::Id scalar = 0;\r
-        switch (glslangType.getBasicType()) {\r
-        case glslang::EbtInt:\r
-            scalar = builder.makeIntConstant(zero ? 0 : consts[nextConst].getIConst());\r
-            break;\r
-        case glslang::EbtUint:\r
-            scalar = builder.makeUintConstant(zero ? 0 : consts[nextConst].getUConst());\r
-            break;\r
-        case glslang::EbtFloat:\r
-            scalar = builder.makeFloatConstant(zero ? 0.0F : (float)consts[nextConst].getDConst());\r
-            break;\r
-        case glslang::EbtDouble:\r
-            scalar = builder.makeDoubleConstant(zero ? 0.0 : consts[nextConst].getDConst());\r
-            break;\r
-        case glslang::EbtBool:\r
-            scalar = builder.makeBoolConstant(zero ? false : consts[nextConst].getBConst());\r
-            break;\r
-        default:\r
-            spv::MissingFunctionality("constant scalar type");\r
-            break;\r
-        }\r
-        ++nextConst;\r
-        return scalar;\r
-    }\r
-\r
-    return builder.makeCompositeConstant(typeId, spvConsts);\r
-}\r
-\r
-};  // end anonymous namespace\r
-\r
-namespace glslang {\r
-\r
-// Write SPIR-V out to a binary file\r
-void OutputSpv(const std::vector<unsigned int>& spirv, const char* baseName)\r
-{\r
-    std::ofstream out;\r
-    std::string fileName(baseName);\r
-    fileName.append(".spv");\r
-    out.open(fileName.c_str(), std::ios::binary | std::ios::out);\r
-    for (int i = 0; i < (int)spirv.size(); ++i) {\r
-        unsigned int word = spirv[i];\r
-        out.write((const char*)&word, 4);\r
-    }\r
-    out.close();\r
-}\r
-\r
-//\r
-// Set up the glslang traversal\r
-//\r
-void GlslangToSpv(const glslang::TIntermediate& intermediate, std::vector<unsigned int>& spirv)\r
-{\r
-    TIntermNode* root = intermediate.getTreeRoot();\r
-\r
-    if (root == 0)\r
-        return;\r
-\r
-    glslang::GetThreadPoolAllocator().push();\r
-\r
-    TGlslangToSpvTraverser it(&intermediate);\r
-\r
-    root->traverse(&it);\r
-\r
-    it.dumpSpv(spirv);\r
-\r
-    glslang::GetThreadPoolAllocator().pop();\r
-}\r
-\r
-}; // end namespace glslang\r
+//
+//Copyright (C) 2014 LunarG, Inc.
+//
+//All rights reserved.
+//
+//Redistribution and use in source and binary forms, with or without
+//modification, are permitted provided that the following conditions
+//are met:
+//
+//    Redistributions of source code must retain the above copyright
+//    notice, this list of conditions and the following disclaimer.
+//
+//    Redistributions in binary form must reproduce the above
+//    copyright notice, this list of conditions and the following
+//    disclaimer in the documentation and/or other materials provided
+//    with the distribution.
+//
+//    Neither the name of 3Dlabs Inc. Ltd. nor the names of its
+//    contributors may be used to endorse or promote products derived
+//    from this software without specific prior written permission.
+//
+//THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+//"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+//LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+//FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+//COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+//INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+//BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+//LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+//CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+//LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+//ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+//POSSIBILITY OF SUCH DAMAGE.
+
+//
+// Author: John Kessenich, LunarG
+//
+// Visit the nodes in the glslang intermediate tree representation to
+// translate them to SPIR-V.
+//
+
+#include "spirv.h"
+#include "GlslangToSpv.h"
+#include "SpvBuilder.h"
+#include "GLSL450Lib.h"
+
+// Glslang includes
+#include "glslang/MachineIndependent/localintermediate.h"
+#include "glslang/MachineIndependent/SymbolTable.h"
+
+#include <string>
+#include <map>
+#include <list>
+#include <vector>
+#include <stack>
+#include <fstream>
+
+namespace {
+
+const int GlslangMagic = 0x51a;
+
+//
+// The main holder of information for translating glslang to SPIR-V.
+//
+// Derives from the AST walking base class.
+//
+class TGlslangToSpvTraverser : public glslang::TIntermTraverser {
+public:
+    TGlslangToSpvTraverser(const glslang::TIntermediate*);
+    virtual ~TGlslangToSpvTraverser();
+
+    bool visitAggregate(glslang::TVisit, glslang::TIntermAggregate*);
+    bool visitBinary(glslang::TVisit, glslang::TIntermBinary*);
+    void visitConstantUnion(glslang::TIntermConstantUnion*);
+    bool visitSelection(glslang::TVisit, glslang::TIntermSelection*);
+    bool visitSwitch(glslang::TVisit, glslang::TIntermSwitch*);
+    void visitSymbol(glslang::TIntermSymbol* symbol);
+    bool visitUnary(glslang::TVisit, glslang::TIntermUnary*);
+    bool visitLoop(glslang::TVisit, glslang::TIntermLoop*);
+    bool visitBranch(glslang::TVisit visit, glslang::TIntermBranch*);
+
+    void dumpSpv(std::vector<unsigned int>& out) { builder.dump(out); }
+
+protected:
+    spv::Id createSpvVariable(const glslang::TIntermSymbol*);
+    spv::Id getSampledType(const glslang::TSampler&);
+    spv::Id convertGlslangToSpvType(const glslang::TType& type);
+
+    bool isShaderEntrypoint(const glslang::TIntermAggregate* node);
+    void makeFunctions(const glslang::TIntermSequence&);
+    void makeGlobalInitializers(const glslang::TIntermSequence&);
+    void visitFunctions(const glslang::TIntermSequence&);
+    void handleFunctionEntry(const glslang::TIntermAggregate* node);
+    void translateArguments(const glslang::TIntermSequence& glslangArguments, std::vector<spv::Id>& arguments);
+    spv::Id handleBuiltInFunctionCall(const glslang::TIntermAggregate*);
+    spv::Id handleUserFunctionCall(const glslang::TIntermAggregate*);
+
+    spv::Id createBinaryOperation(glslang::TOperator op, spv::Decoration precision, spv::Id typeId, spv::Id left, spv::Id right, glslang::TBasicType typeProxy, bool reduceComparison = true);
+    spv::Id createUnaryOperation(glslang::TOperator op, spv::Decoration precision, spv::Id typeId, spv::Id operand, bool isFloat);
+    spv::Id createConversion(glslang::TOperator op, spv::Decoration precision, spv::Id destTypeId, spv::Id operand);
+    spv::Id makeSmearedConstant(spv::Id constant, int vectorSize);
+    spv::Id createMiscOperation(glslang::TOperator op, spv::Decoration precision, spv::Id typeId, std::vector<spv::Id>& operands);
+    spv::Id createNoArgOperation(glslang::TOperator op);
+    spv::Id getSymbolId(const glslang::TIntermSymbol* node);
+    void addDecoration(spv::Id id, spv::Decoration dec);
+    void addMemberDecoration(spv::Id id, int member, spv::Decoration dec);
+    spv::Id createSpvConstant(const glslang::TType& type, const glslang::TConstUnionArray&, int& nextConst);
+
+    spv::Function* shaderEntry;
+    int sequenceDepth;
+
+    // There is a 1:1 mapping between a spv builder and a module; this is thread safe
+    spv::Builder builder;
+    bool inMain;
+    bool mainTerminated;
+    bool linkageOnly;
+    const glslang::TIntermediate* glslangIntermediate;
+    spv::Id stdBuiltins;
+
+    std::map<int, spv::Id> symbolValues;
+    std::set<int> constReadOnlyParameters;  // set of formal function parameters that have glslang qualifier constReadOnly, so we know they are not local function "const" that are write-once
+    std::map<std::string, spv::Function*> functionMap;
+    std::map<const glslang::TTypeList*, spv::Id> structMap;
+    std::map<const glslang::TTypeList*, std::vector<int> > memberRemapper;  // for mapping glslang block indices to spv indices (e.g., due to hidden members)
+    std::stack<bool> breakForLoop;  // false means break for switch
+    std::stack<glslang::TIntermTyped*> loopTerminal;  // code from the last part of a for loop: for(...; ...; terminal), needed for e.g., continue };
+};
+
+//
+// Helper functions for translating glslang representations to SPIR-V enumerants.
+//
+
+// Translate glslang profile to SPIR-V source language.
+spv::SourceLanguage TranslateSourceLanguage(EProfile profile)
+{
+    switch (profile) {
+    case ENoProfile:
+    case ECoreProfile:
+    case ECompatibilityProfile:
+        return spv::SourceLanguageGLSL;
+    case EEsProfile:
+        return spv::SourceLanguageESSL;
+    default:
+        return spv::SourceLanguageUnknown;
+    }
+}
+
+// Translate glslang language (stage) to SPIR-V execution model.
+spv::ExecutionModel TranslateExecutionModel(EShLanguage stage)
+{
+    switch (stage) {
+    case EShLangVertex:           return spv::ExecutionModelVertex;
+    case EShLangTessControl:      return spv::ExecutionModelTessellationControl;
+    case EShLangTessEvaluation:   return spv::ExecutionModelTessellationEvaluation;
+    case EShLangGeometry:         return spv::ExecutionModelGeometry;
+    case EShLangFragment:         return spv::ExecutionModelFragment;
+    case EShLangCompute:          return spv::ExecutionModelGLCompute;
+    default:
+        spv::MissingFunctionality("GLSL stage");
+        return spv::ExecutionModelFragment;
+    }
+}
+
+// Translate glslang type to SPIR-V storage class.
+spv::StorageClass TranslateStorageClass(const glslang::TType& type)
+{
+    if (type.getQualifier().isPipeInput())
+        return spv::StorageClassInput;
+    else if (type.getQualifier().isPipeOutput())
+        return spv::StorageClassOutput;
+    else if (type.getQualifier().isUniformOrBuffer()) {
+        if (type.getBasicType() == glslang::EbtBlock)
+            return spv::StorageClassUniform;
+        else
+            return spv::StorageClassUniformConstant;
+        // TODO: how are we distuingishing between default and non-default non-writable uniforms?  Do default uniforms even exist?
+    } else {
+        switch (type.getQualifier().storage) {
+        case glslang::EvqShared:        return spv::StorageClassWorkgroupLocal;  break;
+        case glslang::EvqGlobal:        return spv::StorageClassPrivateGlobal;
+        case glslang::EvqConstReadOnly: return spv::StorageClassFunction;
+        case glslang::EvqTemporary:     return spv::StorageClassFunction;
+        default: 
+            spv::MissingFunctionality("unknown glslang storage class");
+            return spv::StorageClassFunction;
+        }
+    }
+}
+
+// Translate glslang sampler type to SPIR-V dimensionality.
+spv::Dim TranslateDimensionality(const glslang::TSampler& sampler)
+{
+    switch (sampler.dim) {
+    case glslang::Esd1D:     return spv::Dim1D;
+    case glslang::Esd2D:     return spv::Dim2D;
+    case glslang::Esd3D:     return spv::Dim3D;
+    case glslang::EsdCube:   return spv::DimCube;
+    case glslang::EsdRect:   return spv::DimRect;
+    case glslang::EsdBuffer: return spv::DimBuffer;
+    default:
+        spv::MissingFunctionality("unknown sampler dimension");
+        return spv::Dim2D;
+    }
+}
+
+// Translate glslang type to SPIR-V precision decorations.
+spv::Decoration TranslatePrecisionDecoration(const glslang::TType& type)
+{
+    switch (type.getQualifier().precision) {
+    case glslang::EpqLow:    return spv::DecorationPrecisionLow;
+    case glslang::EpqMedium: return spv::DecorationPrecisionMedium;
+    case glslang::EpqHigh:   return spv::DecorationPrecisionHigh;
+    default:
+        return spv::NoPrecision;
+    }
+}
+
+// Translate glslang type to SPIR-V block decorations.
+spv::Decoration TranslateBlockDecoration(const glslang::TType& type)
+{
+    if (type.getBasicType() == glslang::EbtBlock) {
+        switch (type.getQualifier().storage) {
+        case glslang::EvqUniform:      return spv::DecorationBlock;
+        case glslang::EvqBuffer:       return spv::DecorationBufferBlock;
+        case glslang::EvqVaryingIn:    return spv::DecorationBlock;
+        case glslang::EvqVaryingOut:   return spv::DecorationBlock;
+        default:
+            spv::MissingFunctionality("kind of block");
+            break;
+        }
+    }
+
+    return (spv::Decoration)spv::BadValue;
+}
+
+// Translate glslang type to SPIR-V layout decorations.
+spv::Decoration TranslateLayoutDecoration(const glslang::TType& type)
+{
+    if (type.isMatrix()) {
+        switch (type.getQualifier().layoutMatrix) {
+        case glslang::ElmRowMajor:
+            return spv::DecorationRowMajor;
+        default:
+            return spv::DecorationColMajor;
+        }
+    } else {
+        switch (type.getBasicType()) {
+        default:
+            return (spv::Decoration)spv::BadValue;
+            break;
+        case glslang::EbtBlock:
+            switch (type.getQualifier().storage) {
+            case glslang::EvqUniform:
+            case glslang::EvqBuffer:
+                switch (type.getQualifier().layoutPacking) {
+                case glslang::ElpShared:  return spv::DecorationGLSLShared;
+                case glslang::ElpStd140:  return spv::DecorationGLSLStd140;
+                case glslang::ElpStd430:  return spv::DecorationGLSLStd430;
+                case glslang::ElpPacked:  return spv::DecorationGLSLPacked;
+                default:
+                    spv::MissingFunctionality("uniform block layout");
+                    return spv::DecorationGLSLShared;
+                }
+            case glslang::EvqVaryingIn:
+            case glslang::EvqVaryingOut:
+                if (type.getQualifier().layoutPacking != glslang::ElpNone)
+                    spv::MissingFunctionality("in/out block layout");
+                return (spv::Decoration)spv::BadValue;
+            default:
+                spv::MissingFunctionality("block storage qualification");
+                return (spv::Decoration)spv::BadValue;
+            }
+        }
+    }
+}
+
+// Translate glslang type to SPIR-V interpolation decorations.
+spv::Decoration TranslateInterpolationDecoration(const glslang::TType& type)
+{
+    if (type.getQualifier().smooth)
+        return spv::DecorationSmooth;
+    if (type.getQualifier().nopersp)
+        return spv::DecorationNoperspective;
+    else if (type.getQualifier().patch)
+        return spv::DecorationPatch;
+    else if (type.getQualifier().flat)
+        return spv::DecorationFlat;
+    else if (type.getQualifier().centroid)
+        return spv::DecorationCentroid;
+    else if (type.getQualifier().sample)
+        return spv::DecorationSample;
+    else
+        return (spv::Decoration)spv::BadValue;
+}
+
+// If glslang type is invaraiant, return SPIR-V invariant decoration.
+spv::Decoration TranslateInvariantDecoration(const glslang::TType& type)
+{
+    if (type.getQualifier().invariant)
+        return spv::DecorationInvariant;
+    else
+        return (spv::Decoration)spv::BadValue;
+}
+
+// Translate glslang built-in variable to SPIR-V built in decoration.
+spv::BuiltIn TranslateBuiltInDecoration(glslang::TBuiltInVariable builtIn)
+{
+    switch (builtIn) {
+    case glslang::EbvPosition:             return spv::BuiltInPosition;
+    case glslang::EbvPointSize:            return spv::BuiltInPointSize;
+    case glslang::EbvClipVertex:           return spv::BuiltInClipVertex;
+    case glslang::EbvClipDistance:         return spv::BuiltInClipDistance;
+    case glslang::EbvCullDistance:         return spv::BuiltInCullDistance;
+    case glslang::EbvVertexId:             return spv::BuiltInVertexId;
+    case glslang::EbvInstanceId:           return spv::BuiltInInstanceId;
+    case glslang::EbvPrimitiveId:          return spv::BuiltInPrimitiveId;
+    case glslang::EbvInvocationId:         return spv::BuiltInInvocationId;
+    case glslang::EbvLayer:                return spv::BuiltInLayer;
+    case glslang::EbvViewportIndex:        return spv::BuiltInViewportIndex;
+    case glslang::EbvTessLevelInner:       return spv::BuiltInTessLevelInner;
+    case glslang::EbvTessLevelOuter:       return spv::BuiltInTessLevelOuter;
+    case glslang::EbvTessCoord:            return spv::BuiltInTessCoord;
+    case glslang::EbvPatchVertices:        return spv::BuiltInPatchVertices;
+    case glslang::EbvFragCoord:            return spv::BuiltInFragCoord;
+    case glslang::EbvPointCoord:           return spv::BuiltInPointCoord;
+    case glslang::EbvFace:                 return spv::BuiltInFrontFacing;
+    case glslang::EbvSampleId:             return spv::BuiltInSampleId;
+    case glslang::EbvSamplePosition:       return spv::BuiltInSamplePosition;
+    case glslang::EbvSampleMask:           return spv::BuiltInSampleMask;
+    case glslang::EbvFragColor:            return spv::BuiltInFragColor;
+    case glslang::EbvFragData:             return spv::BuiltInFragColor;
+    case glslang::EbvFragDepth:            return spv::BuiltInFragDepth;
+    case glslang::EbvHelperInvocation:     return spv::BuiltInHelperInvocation;
+    case glslang::EbvNumWorkGroups:        return spv::BuiltInNumWorkgroups;
+    case glslang::EbvWorkGroupSize:        return spv::BuiltInWorkgroupSize;
+    case glslang::EbvWorkGroupId:          return spv::BuiltInWorkgroupId;
+    case glslang::EbvLocalInvocationId:    return spv::BuiltInLocalInvocationId;
+    case glslang::EbvLocalInvocationIndex: return spv::BuiltInLocalInvocationIndex;
+    case glslang::EbvGlobalInvocationId:   return spv::BuiltInGlobalInvocationId;
+    default:                               return (spv::BuiltIn)spv::BadValue;
+    }
+}
+
+//
+// Implement the TGlslangToSpvTraverser class.
+//
+
+TGlslangToSpvTraverser::TGlslangToSpvTraverser(const glslang::TIntermediate* glslangIntermediate)
+    : TIntermTraverser(true, false, true), shaderEntry(0), sequenceDepth(0),
+      builder(GlslangMagic),
+      inMain(false), mainTerminated(false), linkageOnly(false),
+      glslangIntermediate(glslangIntermediate)
+{
+    spv::ExecutionModel executionModel = TranslateExecutionModel(glslangIntermediate->getStage());
+
+    builder.clearAccessChain();
+    builder.setSource(TranslateSourceLanguage(glslangIntermediate->getProfile()), glslangIntermediate->getVersion());
+    stdBuiltins = builder.import("GLSL.std.450");
+    builder.setMemoryModel(spv::AddressingModelLogical, spv::MemoryModelGLSL450);
+    shaderEntry = builder.makeMain();
+    builder.addEntryPoint(executionModel, shaderEntry);
+
+    // Add the source extensions
+    const std::set<std::string>& sourceExtensions = glslangIntermediate->getRequestedExtensions();
+    for (std::set<std::string>::const_iterator it = sourceExtensions.begin(); it != sourceExtensions.end(); ++it)
+        builder.addSourceExtension(it->c_str());
+
+    // Add the top-level modes for this shader.
+
+    if (glslangIntermediate->getXfbMode())
+        builder.addExecutionMode(shaderEntry, spv::ExecutionModeXfb);
+
+    unsigned int mode;
+    switch (glslangIntermediate->getStage()) {
+    case EShLangVertex:
+        break;
+
+    case EShLangTessControl:
+        builder.addExecutionMode(shaderEntry, spv::ExecutionModeOutputVertices, glslangIntermediate->getVertices());
+        break;
+
+    case EShLangTessEvaluation:
+        switch (glslangIntermediate->getInputPrimitive()) {
+        case glslang::ElgTriangles:           mode = spv::ExecutionModeInputTriangles;     break;
+        case glslang::ElgQuads:               mode = spv::ExecutionModeInputQuads;         break;
+        case glslang::ElgIsolines:            mode = spv::ExecutionModeInputIsolines;      break;
+        default:                              mode = spv::BadValue;    break;
+        }
+        if (mode != spv::BadValue)
+            builder.addExecutionMode(shaderEntry, (spv::ExecutionMode)mode);
+
+        // TODO
+        //builder.addExecutionMode(spv::VertexSpacingMdName, glslangIntermediate->getVertexSpacing());
+        //builder.addExecutionMode(spv::VertexOrderMdName, glslangIntermediate->getVertexOrder());
+        //builder.addExecutionMode(spv::PointModeMdName, glslangIntermediate->getPointMode());
+        break;
+
+    case EShLangGeometry:
+        switch (glslangIntermediate->getInputPrimitive()) {
+        case glslang::ElgPoints:             mode = spv::ExecutionModeInputPoints;             break;
+        case glslang::ElgLines:              mode = spv::ExecutionModeInputLines;              break;
+        case glslang::ElgLinesAdjacency:     mode = spv::ExecutionModeInputLinesAdjacency;     break;
+        case glslang::ElgTriangles:          mode = spv::ExecutionModeInputTriangles;          break;
+        case glslang::ElgTrianglesAdjacency: mode = spv::ExecutionModeInputTrianglesAdjacency; break;
+        default:                             mode = spv::BadValue;         break;
+        }
+        if (mode != spv::BadValue)
+            builder.addExecutionMode(shaderEntry, (spv::ExecutionMode)mode);
+        builder.addExecutionMode(shaderEntry, spv::ExecutionModeInvocations, glslangIntermediate->getInvocations());
+
+        switch (glslangIntermediate->getOutputPrimitive()) {
+        case glslang::ElgPoints:        mode = spv::ExecutionModeOutputPoints;                 break;
+        case glslang::ElgLineStrip:     mode = spv::ExecutionModeOutputLineStrip;              break;
+        case glslang::ElgTriangleStrip: mode = spv::ExecutionModeOutputTriangleStrip;          break;
+        default:                        mode = spv::BadValue;              break;
+        }
+        if (mode != spv::BadValue)
+            builder.addExecutionMode(shaderEntry, (spv::ExecutionMode)mode);
+        builder.addExecutionMode(shaderEntry, spv::ExecutionModeOutputVertices, glslangIntermediate->getVertices());
+        break;
+
+    case EShLangFragment:
+        if (glslangIntermediate->getPixelCenterInteger())
+            builder.addExecutionMode(shaderEntry, spv::ExecutionModePixelCenterInteger);
+        if (glslangIntermediate->getOriginUpperLeft())
+            builder.addExecutionMode(shaderEntry, spv::ExecutionModeOriginUpperLeft);
+        break;
+
+    case EShLangCompute:
+        break;
+
+    default:
+        break;
+    }
+
+}
+
+TGlslangToSpvTraverser::~TGlslangToSpvTraverser()
+{
+    if (! mainTerminated) {
+        spv::Block* lastMainBlock = shaderEntry->getLastBlock();
+        builder.setBuildPoint(lastMainBlock);
+        builder.leaveFunction(true);
+    }
+}
+
+//
+// Implement the traversal functions.
+//
+// Return true from interior nodes to have the external traversal
+// continue on to children.  Return false if children were
+// already processed.
+//
+
+//
+// Symbols can turn into 
+//  - uniform/input reads
+//  - output writes
+//  - complex lvalue base setups:  foo.bar[3]....  , where we see foo and start up an access chain
+//  - something simple that degenerates into the last bullet
+//
+void TGlslangToSpvTraverser::visitSymbol(glslang::TIntermSymbol* symbol)
+{
+    // getSymbolId() will set up all the IO decorations on the first call.
+    // Formal function parameters were mapped during makeFunctions().
+    spv::Id id = getSymbolId(symbol);
+    
+    if (! linkageOnly) {
+        // Prepare to generate code for the access
+
+        // L-value chains will be computed left to right.  We're on the symbol now,
+        // which is the left-most part of the access chain, so now is "clear" time,
+        // followed by setting the base.
+        builder.clearAccessChain();
+
+        // For now, we consider all user variables as being in memory, so they are pointers,
+        // except for "const in" arguments to a function, which are an intermediate object.
+        // See comments in handleUserFunctionCall().
+        glslang::TStorageQualifier qualifier = symbol->getQualifier().storage;
+        if (qualifier == glslang::EvqConstReadOnly && constReadOnlyParameters.find(symbol->getId()) != constReadOnlyParameters.end())
+            builder.setAccessChainRValue(id);
+        else
+            builder.setAccessChainLValue(id);
+    }
+}
+
+bool TGlslangToSpvTraverser::visitBinary(glslang::TVisit /* visit */, glslang::TIntermBinary* node)
+{
+    // First, handle special cases
+    switch (node->getOp()) {
+    case glslang::EOpAssign:
+    case glslang::EOpAddAssign:
+    case glslang::EOpSubAssign:
+    case glslang::EOpMulAssign:
+    case glslang::EOpVectorTimesMatrixAssign:
+    case glslang::EOpVectorTimesScalarAssign:
+    case glslang::EOpMatrixTimesScalarAssign:
+    case glslang::EOpMatrixTimesMatrixAssign:
+    case glslang::EOpDivAssign:
+    case glslang::EOpModAssign:
+    case glslang::EOpAndAssign:
+    case glslang::EOpInclusiveOrAssign:
+    case glslang::EOpExclusiveOrAssign:
+    case glslang::EOpLeftShiftAssign:
+    case glslang::EOpRightShiftAssign:
+        // A bin-op assign "a += b" means the same thing as "a = a + b"
+        // where a is evaluated before b. For a simple assignment, GLSL
+        // says to evaluate the left before the right.  So, always, left
+        // node then right node.
+        {
+            // get the left l-value, save it away
+            builder.clearAccessChain();
+            node->getLeft()->traverse(this);
+            spv::Builder::AccessChain lValue = builder.getAccessChain();
+
+            // evaluate the right
+            builder.clearAccessChain();
+            node->getRight()->traverse(this);
+            spv::Id rValue = builder.accessChainLoad(TranslatePrecisionDecoration(node->getRight()->getType()));
+
+            if (node->getOp() != glslang::EOpAssign) {
+                // the left is also an r-value
+                builder.setAccessChain(lValue);
+                spv::Id leftRValue = builder.accessChainLoad(TranslatePrecisionDecoration(node->getLeft()->getType()));
+
+                // do the operation
+                rValue = createBinaryOperation(node->getOp(), TranslatePrecisionDecoration(node->getType()), 
+                                               convertGlslangToSpvType(node->getType()), leftRValue, rValue,
+                                               node->getType().getBasicType());
+
+                // these all need their counterparts in createBinaryOperation()
+                if (rValue == 0)
+                    spv::MissingFunctionality("createBinaryOperation");
+            }
+
+            // store the result
+            builder.setAccessChain(lValue);
+            builder.accessChainStore(rValue);
+
+            // assignments are expressions having an rValue after they are evaluated...
+            builder.clearAccessChain();
+            builder.setAccessChainRValue(rValue);
+        }
+        return false;
+    case glslang::EOpIndexDirect:
+    case glslang::EOpIndexDirectStruct:
+        {
+            // Get the left part of the access chain.
+            node->getLeft()->traverse(this);
+
+            // Add the next element in the chain
+
+            int index = 0;
+            if (node->getRight()->getAsConstantUnion() == 0)
+                spv::MissingFunctionality("direct index without a constant node");
+            else 
+                index = node->getRight()->getAsConstantUnion()->getConstArray()[0].getIConst();
+
+            if (node->getLeft()->getBasicType() == glslang::EbtBlock && node->getOp() == glslang::EOpIndexDirectStruct) {
+                // This may be, e.g., an anonymous block-member selection, which generally need
+                // index remapping due to hidden members in anonymous blocks.
+                std::vector<int>& remapper = memberRemapper[node->getLeft()->getType().getStruct()];
+                if (remapper.size() == 0)
+                    spv::MissingFunctionality("block without member remapping");
+                else
+                    index = remapper[index];
+            }
+
+            if (! node->getLeft()->getType().isArray() &&
+                node->getLeft()->getType().isVector() &&
+                node->getOp() == glslang::EOpIndexDirect) {
+                // This is essentially a hard-coded vector swizzle of size 1,
+                // so short circuit the access-chain stuff with a swizzle.
+                std::vector<unsigned> swizzle;
+                swizzle.push_back(node->getRight()->getAsConstantUnion()->getConstArray()[0].getIConst());
+                builder.accessChainPushSwizzle(swizzle);
+            } else {
+                // normal case for indexing array or structure or block
+                builder.accessChainPush(builder.makeIntConstant(index), convertGlslangToSpvType(node->getType()));
+            }
+        }
+        return false;
+    case glslang::EOpIndexIndirect:
+        {
+            // Structure or array or vector indirection.
+            // Will use native SPIR-V access-chain for struct and array indirection;
+            // matrices are arrays of vectors, so will also work for a matrix.
+            // Will use the access chain's 'component' for variable index into a vector.
+
+            // This adapter is building access chains left to right.
+            // Set up the access chain to the left.
+            node->getLeft()->traverse(this);
+
+            // save it so that computing the right side doesn't trash it
+            spv::Builder::AccessChain partial = builder.getAccessChain();
+
+            // compute the next index in the chain
+            builder.clearAccessChain();
+            node->getRight()->traverse(this);
+            spv::Id index = builder.accessChainLoad(TranslatePrecisionDecoration(node->getRight()->getType()));
+
+            // restore the saved access chain
+            builder.setAccessChain(partial);
+
+            if (! node->getLeft()->getType().isArray() && node->getLeft()->getType().isVector())
+                builder.accessChainPushComponent(index);
+            else
+                builder.accessChainPush(index, convertGlslangToSpvType(node->getType()));
+        }
+        return false;
+    case glslang::EOpVectorSwizzle:
+        {
+            node->getLeft()->traverse(this);
+            glslang::TIntermSequence& swizzleSequence = node->getRight()->getAsAggregate()->getSequence();
+            std::vector<unsigned> swizzle;
+            for (int i = 0; i < (int)swizzleSequence.size(); ++i)
+                swizzle.push_back(swizzleSequence[i]->getAsConstantUnion()->getConstArray()[0].getIConst());
+            builder.accessChainPushSwizzle(swizzle);
+        }
+        return false;
+    default:
+        break;
+    }
+
+    // Assume generic binary op...
+
+    // Get the operands
+    builder.clearAccessChain();
+    node->getLeft()->traverse(this);
+    spv::Id left = builder.accessChainLoad(TranslatePrecisionDecoration(node->getLeft()->getType()));
+
+    builder.clearAccessChain();
+    node->getRight()->traverse(this);
+    spv::Id right = builder.accessChainLoad(TranslatePrecisionDecoration(node->getRight()->getType()));
+
+    spv::Id result;
+    spv::Decoration precision = TranslatePrecisionDecoration(node->getType());
+
+    result = createBinaryOperation(node->getOp(), precision, 
+                                   convertGlslangToSpvType(node->getType()), left, right,
+                                   node->getLeft()->getType().getBasicType());
+
+    if (! result) {
+        spv::MissingFunctionality("glslang binary operation");
+    } else {
+        builder.clearAccessChain();
+        builder.setAccessChainRValue(result);
+
+        return false;
+    }
+
+    return true;
+}
+
+bool TGlslangToSpvTraverser::visitUnary(glslang::TVisit /* visit */, glslang::TIntermUnary* node)
+{
+    builder.clearAccessChain();
+    node->getOperand()->traverse(this);
+    spv::Id operand = builder.accessChainLoad(TranslatePrecisionDecoration(node->getOperand()->getType()));
+
+    spv::Decoration precision = TranslatePrecisionDecoration(node->getType());
+
+    // it could be a conversion
+    spv::Id result = createConversion(node->getOp(), precision, convertGlslangToSpvType(node->getType()), operand);
+
+    // if not, then possibly an operation
+    if (! result)
+        result = createUnaryOperation(node->getOp(), precision, convertGlslangToSpvType(node->getType()), operand, node->getBasicType() == glslang::EbtFloat || node->getBasicType() == glslang::EbtDouble);
+
+    if (result) {
+        builder.clearAccessChain();
+        builder.setAccessChainRValue(result);
+
+        return false; // done with this node
+    }
+
+    // it must be a special case, check...
+    switch (node->getOp()) {
+    case glslang::EOpPostIncrement:
+    case glslang::EOpPostDecrement:
+    case glslang::EOpPreIncrement:
+    case glslang::EOpPreDecrement:
+        {
+            // we need the integer value "1" or the floating point "1.0" to add/subtract
+            spv::Id one = node->getBasicType() == glslang::EbtFloat ?
+                                     builder.makeFloatConstant(1.0F) :
+                                     builder.makeIntConstant(1);
+            glslang::TOperator op;
+            if (node->getOp() == glslang::EOpPreIncrement ||
+                node->getOp() == glslang::EOpPostIncrement)
+                op = glslang::EOpAdd;
+            else
+                op = glslang::EOpSub;
+
+            spv::Id result = createBinaryOperation(op, TranslatePrecisionDecoration(node->getType()), 
+                                                     convertGlslangToSpvType(node->getType()), operand, one, 
+                                                     node->getType().getBasicType());
+            if (result == 0)
+                spv::MissingFunctionality("createBinaryOperation for unary");
+
+            // The result of operation is always stored, but conditionally the
+            // consumed result.  The consumed result is always an r-value.
+            builder.accessChainStore(result);
+            builder.clearAccessChain();
+            if (node->getOp() == glslang::EOpPreIncrement ||
+                node->getOp() == glslang::EOpPreDecrement)
+                builder.setAccessChainRValue(result);
+            else
+                builder.setAccessChainRValue(operand);
+        }
+
+        return false;
+
+    case glslang::EOpEmitStreamVertex:
+        builder.createNoResultOp(spv::OpEmitStreamVertex, operand);
+        return false;
+    case glslang::EOpEndStreamPrimitive:
+        builder.createNoResultOp(spv::OpEndStreamPrimitive, operand);
+        return false;
+
+    default:
+        spv::MissingFunctionality("glslang unary");
+        break;
+    }
+
+    return true;
+}
+
+bool TGlslangToSpvTraverser::visitAggregate(glslang::TVisit visit, glslang::TIntermAggregate* node)
+{
+    spv::Id result;
+    glslang::TOperator binOp = glslang::EOpNull;
+    bool reduceComparison = true;
+    bool isMatrix = false;
+    bool noReturnValue = false;
+
+    assert(node->getOp());
+
+    spv::Decoration precision = TranslatePrecisionDecoration(node->getType());
+
+    switch (node->getOp()) {
+    case glslang::EOpSequence:
+    {
+        if (preVisit)
+            ++sequenceDepth;
+        else
+            --sequenceDepth;
+
+        if (sequenceDepth == 1) {
+            // If this is the parent node of all the functions, we want to see them
+            // early, so all call points have actual SPIR-V functions to reference.
+            // In all cases, still let the traverser visit the children for us.
+            makeFunctions(node->getAsAggregate()->getSequence());
+
+            // Also, we want all globals initializers to go into the entry of main(), before
+            // anything else gets there, so visit out of order, doing them all now.
+            makeGlobalInitializers(node->getAsAggregate()->getSequence());
+
+            // Initializers are done, don't want to visit again, but functions link objects need to be processed,
+            // so do them manually.
+            visitFunctions(node->getAsAggregate()->getSequence());
+
+            return false;
+        }
+
+        return true;
+    }
+    case glslang::EOpLinkerObjects:
+    {
+        if (visit == glslang::EvPreVisit)
+            linkageOnly = true;
+        else
+            linkageOnly = false;
+
+        return true;
+    }
+    case glslang::EOpComma:
+    {
+        // processing from left to right naturally leaves the right-most
+        // lying around in the access chain
+        glslang::TIntermSequence& glslangOperands = node->getSequence();
+        for (int i = 0; i < (int)glslangOperands.size(); ++i)
+            glslangOperands[i]->traverse(this);
+
+        return false;
+    }
+    case glslang::EOpFunction:
+        if (visit == glslang::EvPreVisit) {
+            if (isShaderEntrypoint(node)) {
+                inMain = true;
+                builder.setBuildPoint(shaderEntry->getLastBlock());
+            } else {
+                handleFunctionEntry(node);
+            }
+        } else {
+            if (inMain)
+                mainTerminated = true;
+            builder.leaveFunction(inMain);
+            inMain = false;
+        }
+
+        return true;
+    case glslang::EOpParameters:
+        // Parameters will have been consumed by EOpFunction processing, but not
+        // the body, so we still visited the function node's children, making this
+        // child redundant.
+        return false;
+    case glslang::EOpFunctionCall:
+    {
+        if (node->isUserDefined())
+            result = handleUserFunctionCall(node);
+        else
+            result = handleBuiltInFunctionCall(node);
+
+        if (! result) {
+            spv::MissingFunctionality("glslang function call");
+            glslang::TConstUnionArray emptyConsts;
+            int nextConst = 0;
+            result = createSpvConstant(node->getType(), emptyConsts, nextConst);
+        }
+        builder.clearAccessChain();
+        builder.setAccessChainRValue(result);
+
+        return false;
+    }
+    case glslang::EOpConstructMat2x2:
+    case glslang::EOpConstructMat2x3:
+    case glslang::EOpConstructMat2x4:
+    case glslang::EOpConstructMat3x2:
+    case glslang::EOpConstructMat3x3:
+    case glslang::EOpConstructMat3x4:
+    case glslang::EOpConstructMat4x2:
+    case glslang::EOpConstructMat4x3:
+    case glslang::EOpConstructMat4x4:
+    case glslang::EOpConstructDMat2x2:
+    case glslang::EOpConstructDMat2x3:
+    case glslang::EOpConstructDMat2x4:
+    case glslang::EOpConstructDMat3x2:
+    case glslang::EOpConstructDMat3x3:
+    case glslang::EOpConstructDMat3x4:
+    case glslang::EOpConstructDMat4x2:
+    case glslang::EOpConstructDMat4x3:
+    case glslang::EOpConstructDMat4x4:
+        isMatrix = true;
+        // fall through
+    case glslang::EOpConstructFloat:
+    case glslang::EOpConstructVec2:
+    case glslang::EOpConstructVec3:
+    case glslang::EOpConstructVec4:
+    case glslang::EOpConstructDouble:
+    case glslang::EOpConstructDVec2:
+    case glslang::EOpConstructDVec3:
+    case glslang::EOpConstructDVec4:
+    case glslang::EOpConstructBool:
+    case glslang::EOpConstructBVec2:
+    case glslang::EOpConstructBVec3:
+    case glslang::EOpConstructBVec4:
+    case glslang::EOpConstructInt:
+    case glslang::EOpConstructIVec2:
+    case glslang::EOpConstructIVec3:
+    case glslang::EOpConstructIVec4:
+    case glslang::EOpConstructUint:
+    case glslang::EOpConstructUVec2:
+    case glslang::EOpConstructUVec3:
+    case glslang::EOpConstructUVec4:
+    case glslang::EOpConstructStruct:
+    {
+        std::vector<spv::Id> arguments;
+        translateArguments(node->getSequence(), arguments);
+        spv::Id resultTypeId = convertGlslangToSpvType(node->getType());
+        spv::Id constructed;
+        if (node->getOp() == glslang::EOpConstructStruct || node->getType().isArray()) {
+            std::vector<spv::Id> constituents;
+            for (int c = 0; c < (int)arguments.size(); ++c)
+                constituents.push_back(arguments[c]);
+            constructed = builder.createCompositeConstruct(resultTypeId, constituents);
+        } else {
+            if (isMatrix)
+                constructed = builder.createMatrixConstructor(precision, arguments, resultTypeId);
+            else
+                constructed = builder.createConstructor(precision, arguments, resultTypeId);
+        }
+
+        builder.clearAccessChain();
+        builder.setAccessChainRValue(constructed);
+
+        return false;
+    }
+
+    // These six are component-wise compares with component-wise results.
+    // Forward on to createBinaryOperation(), requesting a vector result.
+    case glslang::EOpLessThan:
+    case glslang::EOpGreaterThan:
+    case glslang::EOpLessThanEqual:
+    case glslang::EOpGreaterThanEqual:
+    case glslang::EOpVectorEqual:
+    case glslang::EOpVectorNotEqual:
+    {
+        // Map the operation to a binary
+        binOp = node->getOp();
+        reduceComparison = false;
+        switch (node->getOp()) {
+        case glslang::EOpVectorEqual:     binOp = glslang::EOpVectorEqual;      break;
+        case glslang::EOpVectorNotEqual:  binOp = glslang::EOpVectorNotEqual;   break;
+        default:                          binOp = node->getOp();                break;
+        }
+
+        break;
+    }
+    case glslang::EOpMul:
+        // compontent-wise matrix multiply      
+        binOp = glslang::EOpMul;
+        break;
+    case glslang::EOpOuterProduct:
+        // two vectors multiplied to make a matrix
+        binOp = glslang::EOpOuterProduct;
+        break;
+    case glslang::EOpDot:
+    {
+        // for scalar dot product, use multiply        
+        glslang::TIntermSequence& glslangOperands = node->getSequence();
+        if (! glslangOperands[0]->getAsTyped()->isVector())
+            binOp = glslang::EOpMul;
+        break;
+    }
+    case glslang::EOpMod:
+        // when an aggregate, this is the floating-point mod built-in function,
+        // which can be emitted by the one in createBinaryOperation()
+        binOp = glslang::EOpMod;
+        break;
+    case glslang::EOpArrayLength:
+    {
+        glslang::TIntermTyped* typedNode = node->getSequence()[0]->getAsTyped();
+        assert(typedNode);
+        spv::Id length = builder.makeIntConstant(typedNode->getType().getArraySize());
+
+        builder.clearAccessChain();
+        builder.setAccessChainRValue(length);
+
+        return false;
+    }
+    case glslang::EOpEmitVertex:
+    case glslang::EOpEndPrimitive:
+    case glslang::EOpBarrier:
+    case glslang::EOpMemoryBarrier:
+    case glslang::EOpMemoryBarrierAtomicCounter:
+    case glslang::EOpMemoryBarrierBuffer:
+    case glslang::EOpMemoryBarrierImage:
+    case glslang::EOpMemoryBarrierShared:
+    case glslang::EOpGroupMemoryBarrier:
+        noReturnValue = true;
+        // These all have 0 operands and will naturally finish up in the code below for 0 operands
+        break;
+
+    default:
+        break;
+    }
+
+    //
+    // See if it maps to a regular operation.
+    //
+
+    if (binOp != glslang::EOpNull) {
+        glslang::TIntermTyped* left = node->getSequence()[0]->getAsTyped();
+        glslang::TIntermTyped* right = node->getSequence()[1]->getAsTyped();
+        assert(left && right);
+
+        builder.clearAccessChain();
+        left->traverse(this);
+        spv::Id leftId = builder.accessChainLoad(TranslatePrecisionDecoration(left->getType()));
+
+        builder.clearAccessChain();
+        right->traverse(this);
+        spv::Id rightId = builder.accessChainLoad(TranslatePrecisionDecoration(right->getType()));
+
+        result = createBinaryOperation(binOp, precision, 
+                                       convertGlslangToSpvType(node->getType()), leftId, rightId, 
+                                       left->getType().getBasicType(), reduceComparison);
+
+        // code above should only make binOp that exists in createBinaryOperation
+        if (result == 0)
+            spv::MissingFunctionality("createBinaryOperation for aggregate");
+
+        builder.clearAccessChain();
+        builder.setAccessChainRValue(result);
+
+        return false;
+    }
+
+    glslang::TIntermSequence& glslangOperands = node->getSequence();
+    std::vector<spv::Id> operands;
+    for (int arg = 0; arg < (int)glslangOperands.size(); ++arg) {
+        builder.clearAccessChain();
+        glslangOperands[arg]->traverse(this);
+
+        // special case l-value operands; there are just a few
+        bool lvalue = false;
+        switch (node->getOp()) {
+        //case glslang::EOpFrexp:
+        case glslang::EOpModf:
+            if (arg == 1)
+                lvalue = true;
+            break;
+        //case glslang::EOpUAddCarry:
+        //case glslang::EOpUSubBorrow:
+        //case glslang::EOpUMulExtended:
+        default:
+            break;
+        }
+        if (lvalue)
+            operands.push_back(builder.accessChainGetLValue());
+        else
+            operands.push_back(builder.accessChainLoad(TranslatePrecisionDecoration(glslangOperands[arg]->getAsTyped()->getType())));
+    }
+    switch (glslangOperands.size()) {
+    case 0:
+        result = createNoArgOperation(node->getOp());
+        break;
+    case 1:
+        result = createUnaryOperation(node->getOp(), precision, convertGlslangToSpvType(node->getType()), operands.front(), node->getType().getBasicType() == glslang::EbtFloat || node->getType().getBasicType() == glslang::EbtDouble);
+        break;
+    default:
+        result = createMiscOperation(node->getOp(), precision, convertGlslangToSpvType(node->getType()), operands);
+        break;
+    }
+
+    if (noReturnValue)
+        return false;
+
+    if (! result) {
+        spv::MissingFunctionality("glslang aggregate");
+        return true;
+    } else {
+        builder.clearAccessChain();
+        builder.setAccessChainRValue(result);
+        return false;
+    }
+}
+
+bool TGlslangToSpvTraverser::visitSelection(glslang::TVisit /* visit */, glslang::TIntermSelection* node)
+{
+    // This path handles both if-then-else and ?:
+    // The if-then-else has a node type of void, while
+    // ?: has a non-void node type
+    spv::Id result = 0;
+    if (node->getBasicType() != glslang::EbtVoid) {
+        // don't handle this as just on-the-fly temporaries, because there will be two names
+        // and better to leave SSA to later passes
+        result = builder.createVariable(spv::StorageClassFunction, convertGlslangToSpvType(node->getType()));
+    }
+
+    // emit the condition before doing anything with selection
+    node->getCondition()->traverse(this);
+
+    // make an "if" based on the value created by the condition
+    spv::Builder::If ifBuilder(builder.accessChainLoad(spv::NoPrecision), builder);
+
+    if (node->getTrueBlock()) {
+        // emit the "then" statement
+        node->getTrueBlock()->traverse(this);
+        if (result)
+            builder.createStore(builder.accessChainLoad(TranslatePrecisionDecoration(node->getTrueBlock()->getAsTyped()->getType())), result);
+    }
+
+    if (node->getFalseBlock()) {
+        ifBuilder.makeBeginElse();
+        // emit the "else" statement
+        node->getFalseBlock()->traverse(this);
+        if (result)
+            builder.createStore(builder.accessChainLoad(TranslatePrecisionDecoration(node->getFalseBlock()->getAsTyped()->getType())), result);
+    }
+
+    ifBuilder.makeEndIf();
+
+    if (result) {
+        // GLSL only has r-values as the result of a :?, but
+        // if we have an l-value, that can be more efficient if it will
+        // become the base of a complex r-value expression, because the
+        // next layer copies r-values into memory to use the access-chain mechanism
+        builder.clearAccessChain();
+        builder.setAccessChainLValue(result);
+    }
+
+    return false;
+}
+
+bool TGlslangToSpvTraverser::visitSwitch(glslang::TVisit /* visit */, glslang::TIntermSwitch* node)
+{
+    // emit and get the condition before doing anything with switch
+    node->getCondition()->traverse(this);
+    spv::Id selector = builder.accessChainLoad(TranslatePrecisionDecoration(node->getCondition()->getAsTyped()->getType()));
+
+    // browse the children to sort out code segments
+    int defaultSegment = -1;
+    std::vector<TIntermNode*> codeSegments;
+    glslang::TIntermSequence& sequence = node->getBody()->getSequence();
+    std::vector<int> caseValues;
+    std::vector<int> valueIndexToSegment(sequence.size());  // note: probably not all are used, it is an overestimate
+    for (glslang::TIntermSequence::iterator c = sequence.begin(); c != sequence.end(); ++c) {
+        TIntermNode* child = *c;
+        if (child->getAsBranchNode() && child->getAsBranchNode()->getFlowOp() == glslang::EOpDefault)
+            defaultSegment = codeSegments.size();
+        else if (child->getAsBranchNode() && child->getAsBranchNode()->getFlowOp() == glslang::EOpCase) {
+            valueIndexToSegment[caseValues.size()] = codeSegments.size();
+            caseValues.push_back(child->getAsBranchNode()->getExpression()->getAsConstantUnion()->getConstArray()[0].getIConst());
+        } else
+            codeSegments.push_back(child);
+    }
+
+    // handle the case where the last code segment is missing, due to no code 
+    // statements between the last case and the end of the switch statement
+    if ((caseValues.size() && (int)codeSegments.size() == valueIndexToSegment[caseValues.size() - 1]) ||
+        (int)codeSegments.size() == defaultSegment)
+        codeSegments.push_back(nullptr);
+
+    // make the switch statement
+    std::vector<spv::Block*> segmentBlocks; // returned, as the blocks allocated in the call
+    builder.makeSwitch(selector, codeSegments.size(), caseValues, valueIndexToSegment, defaultSegment, segmentBlocks);
+
+    // emit all the code in the segments
+    breakForLoop.push(false);
+    for (unsigned int s = 0; s < codeSegments.size(); ++s) {
+        builder.nextSwitchSegment(segmentBlocks, s);
+        if (codeSegments[s])
+            codeSegments[s]->traverse(this);
+        else
+            builder.addSwitchBreak();
+    }
+    breakForLoop.pop();
+
+    builder.endSwitch(segmentBlocks);
+
+    return false;
+}
+
+void TGlslangToSpvTraverser::visitConstantUnion(glslang::TIntermConstantUnion* node)
+{
+    int nextConst = 0;
+    spv::Id constant = createSpvConstant(node->getType(), node->getConstArray(), nextConst);
+
+    builder.clearAccessChain();
+    builder.setAccessChainRValue(constant);
+}
+
+bool TGlslangToSpvTraverser::visitLoop(glslang::TVisit /* visit */, glslang::TIntermLoop* node)
+{
+    // body emission needs to know what the for-loop terminal is when it sees a "continue"
+    loopTerminal.push(node->getTerminal());
+
+    builder.makeNewLoop();
+
+    bool bodyOut = false;
+    if (! node->testFirst()) {
+        builder.endLoopHeaderWithoutTest();
+        if (node->getBody()) {
+            breakForLoop.push(true);
+            node->getBody()->traverse(this);
+            breakForLoop.pop();
+        }
+        bodyOut = true;
+        builder.createBranchToLoopTest();
+    }
+
+    if (node->getTest()) {
+        node->getTest()->traverse(this);
+        // the AST only contained the test computation, not the branch, we have to add it
+        spv::Id condition = builder.accessChainLoad(TranslatePrecisionDecoration(node->getTest()->getType()));
+        builder.createLoopTestBranch(condition);
+    }
+
+    if (! bodyOut && node->getBody()) {
+        breakForLoop.push(true);
+        node->getBody()->traverse(this);
+        breakForLoop.pop();
+    }
+
+    if (loopTerminal.top())
+        loopTerminal.top()->traverse(this);
+
+    builder.closeLoop();
+
+    loopTerminal.pop();
+
+    return false;
+}
+
+bool TGlslangToSpvTraverser::visitBranch(glslang::TVisit /* visit */, glslang::TIntermBranch* node)
+{
+    if (node->getExpression())
+        node->getExpression()->traverse(this);
+
+    switch (node->getFlowOp()) {
+    case glslang::EOpKill:
+        builder.makeDiscard();
+        break;
+    case glslang::EOpBreak:
+        if (breakForLoop.top())
+            builder.createLoopExit();
+        else
+            builder.addSwitchBreak();
+        break;
+    case glslang::EOpContinue:
+        if (loopTerminal.top())
+            loopTerminal.top()->traverse(this);
+        builder.createLoopContinue();
+        break;
+    case glslang::EOpReturn:
+        if (inMain)
+            builder.makeMainReturn();
+        else if (node->getExpression())
+            builder.makeReturn(false, builder.accessChainLoad(TranslatePrecisionDecoration(node->getExpression()->getType())));
+        else
+            builder.makeReturn();
+
+        builder.clearAccessChain();
+        break;
+
+    default:
+        spv::MissingFunctionality("branch type");
+        break;
+    }
+
+    return false;
+}
+
+spv::Id TGlslangToSpvTraverser::createSpvVariable(const glslang::TIntermSymbol* node)
+{
+    // First, steer off constants, which are not SPIR-V variables, but 
+    // can still have a mapping to a SPIR-V Id.
+    if (node->getQualifier().storage == glslang::EvqConst) {
+        int nextConst = 0;
+        return createSpvConstant(node->getType(), node->getConstArray(), nextConst);
+    }
+
+    // Now, handle actual variables
+    spv::StorageClass storageClass = TranslateStorageClass(node->getType());
+    spv::Id spvType = convertGlslangToSpvType(node->getType());
+
+    const char* name = node->getName().c_str();
+    if (glslang::IsAnonymous(name))
+        name = "";
+
+    return builder.createVariable(storageClass, spvType, name);
+}
+
+// Return type Id of the sampled type.
+spv::Id TGlslangToSpvTraverser::getSampledType(const glslang::TSampler& sampler)
+{
+    switch (sampler.type) {
+        case glslang::EbtFloat:    return builder.makeFloatType(32);
+        case glslang::EbtInt:      return builder.makeIntType(32);
+        case glslang::EbtUint:     return builder.makeUintType(32);
+        default:
+            spv::MissingFunctionality("sampled type");
+            return builder.makeFloatType(32);
+    }
+}
+
+// Do full recursive conversion of an arbitrary glslang type to a SPIR-V Id.
+spv::Id TGlslangToSpvTraverser::convertGlslangToSpvType(const glslang::TType& type)
+{
+    spv::Id spvType = 0;
+
+    switch (type.getBasicType()) {
+    case glslang::EbtVoid:
+        spvType = builder.makeVoidType();
+        if (type.isArray())
+            spv::MissingFunctionality("array of void");
+        break;
+    case glslang::EbtFloat:
+        spvType = builder.makeFloatType(32);
+        break;
+    case glslang::EbtDouble:
+        spvType = builder.makeFloatType(64);
+        break;
+    case glslang::EbtBool:
+        spvType = builder.makeBoolType();
+        break;
+    case glslang::EbtInt:
+        spvType = builder.makeIntType(32);
+        break;
+    case glslang::EbtUint:
+        spvType = builder.makeUintType(32);
+        break;
+    case glslang::EbtSampler:
+        {
+            const glslang::TSampler& sampler = type.getSampler();
+            spvType = builder.makeSampler(getSampledType(sampler), TranslateDimensionality(sampler), 
+                                          sampler.image ? spv::Builder::samplerContentImage : spv::Builder::samplerContentTextureFilter,
+                                          sampler.arrayed, sampler.shadow, sampler.ms);
+        }
+        break;
+    case glslang::EbtStruct:
+    case glslang::EbtBlock:
+        {
+            // If we've seen this struct type, return it
+            const glslang::TTypeList* glslangStruct = type.getStruct();
+            std::vector<spv::Id> structFields;
+            spvType = structMap[glslangStruct];
+            if (spvType)
+                break;
+
+            // else, we haven't seen it...
+
+            // Create a vector of struct types for SPIR-V to consume
+            int memberDelta = 0;  // how much the member's index changes from glslang to SPIR-V, normally 0, except sometimes for blocks
+            if (type.getBasicType() == glslang::EbtBlock)
+                memberRemapper[glslangStruct].resize(glslangStruct->size());
+            for (int i = 0; i < (int)glslangStruct->size(); i++) {
+                glslang::TType& glslangType = *(*glslangStruct)[i].type;
+                if (glslangType.hiddenMember()) {
+                    ++memberDelta;
+                    if (type.getBasicType() == glslang::EbtBlock)
+                        memberRemapper[glslangStruct][i] = -1;
+                } else {
+                    if (type.getBasicType() == glslang::EbtBlock)
+                        memberRemapper[glslangStruct][i] = i - memberDelta;
+                    structFields.push_back(convertGlslangToSpvType(glslangType));
+                }
+            }
+
+            // Make the SPIR-V type
+            spvType = builder.makeStructType(structFields, type.getTypeName().c_str());
+            structMap[glslangStruct] = spvType;
+
+            // Name and decorate the non-hidden members
+            for (int i = 0; i < (int)glslangStruct->size(); i++) {
+                glslang::TType& glslangType = *(*glslangStruct)[i].type;
+                int member = i;
+                if (type.getBasicType() == glslang::EbtBlock)
+                    member = memberRemapper[glslangStruct][i];
+                // using -1 above to indicate a hidden member
+                if (member >= 0) {
+                    builder.addMemberName(spvType, member, glslangType.getFieldName().c_str());
+                    addMemberDecoration(spvType, member, TranslateLayoutDecoration(glslangType));
+                    addMemberDecoration(spvType, member, TranslatePrecisionDecoration(glslangType));
+                    addMemberDecoration(spvType, member, TranslateInterpolationDecoration(glslangType));
+                    addMemberDecoration(spvType, member, TranslateInvariantDecoration(glslangType));
+                    if (glslangType.getQualifier().hasLocation())
+                        builder.addMemberDecoration(spvType, member, spv::DecorationLocation, glslangType.getQualifier().layoutLocation);
+                    if (glslangType.getQualifier().hasComponent())
+                        builder.addMemberDecoration(spvType, member, spv::DecorationComponent, glslangType.getQualifier().layoutComponent);
+                    if (glslangType.getQualifier().hasXfbOffset())
+                        builder.addMemberDecoration(spvType, member, spv::DecorationOffset, glslangType.getQualifier().layoutXfbOffset);
+
+                    // built-in variable decorations
+                    int builtIn = TranslateBuiltInDecoration(glslangType.getQualifier().builtIn);
+                    if (builtIn != spv::BadValue)
+                        builder.addMemberDecoration(spvType, member, spv::DecorationBuiltIn, builtIn);
+                }
+            }
+
+            // Decorate the structure
+            addDecoration(spvType, TranslateLayoutDecoration(type));
+            addDecoration(spvType, TranslateBlockDecoration(type));
+            if (type.getQualifier().hasStream())
+                builder.addDecoration(spvType, spv::DecorationStream, type.getQualifier().layoutStream);
+            if (glslangIntermediate->getXfbMode()) {
+                if (type.getQualifier().hasXfbStride())
+                    builder.addDecoration(spvType, spv::DecorationStride, type.getQualifier().layoutXfbStride);
+                if (type.getQualifier().hasXfbBuffer())
+                    builder.addDecoration(spvType, spv::DecorationXfbBuffer, type.getQualifier().layoutXfbBuffer);
+            }
+        }
+        break;
+    default:
+        spv::MissingFunctionality("basic type");
+        break;
+    }
+
+    if (type.isMatrix())
+        spvType = builder.makeMatrixType(spvType, type.getMatrixCols(), type.getMatrixRows());
+    else {
+        // If this variable has a vector element count greater than 1, create a SPIR-V vector
+        if (type.getVectorSize() > 1)
+            spvType = builder.makeVectorType(spvType, type.getVectorSize());
+    }
+
+    if (type.isArray()) {
+        unsigned arraySize;
+        if (! type.isExplicitlySizedArray()) {
+            spv::MissingFunctionality("Unsized array");
+            arraySize = 8;
+        } else
+            arraySize = type.getArraySize();
+        spvType = builder.makeArrayType(spvType, arraySize);
+    }
+
+    return spvType;
+}
+
+bool TGlslangToSpvTraverser::isShaderEntrypoint(const glslang::TIntermAggregate* node)
+{
+    return node->getName() == "main(";
+}
+
+// Make all the functions, skeletally, without actually visiting their bodies.
+void TGlslangToSpvTraverser::makeFunctions(const glslang::TIntermSequence& glslFunctions)
+{
+    for (int f = 0; f < (int)glslFunctions.size(); ++f) {
+        glslang::TIntermAggregate* glslFunction = glslFunctions[f]->getAsAggregate();
+        if (! glslFunction || glslFunction->getOp() != glslang::EOpFunction || isShaderEntrypoint(glslFunction))
+            continue;
+
+        // We're on a user function.  Set up the basic interface for the function now,
+        // so that it's available to call.
+        // Translating the body will happen later.
+        //
+        // Typically (except for a "const in" parameter), an address will be passed to the 
+        // function.  What it is an address of varies:
+        //
+        // - "in" parameters not marked as "const" can be written to without modifying the argument,
+        //  so that write needs to be to a copy, hence the address of a copy works.
+        //
+        // - "const in" parameters can just be the r-value, as no writes need occur.
+        //
+        // - "out" and "inout" arguments can't be done as direct pointers, because GLSL has
+        // copy-in/copy-out semantics.  They can be handled though with a pointer to a copy.
+
+        std::vector<spv::Id> paramTypes;
+        glslang::TIntermSequence& parameters = glslFunction->getSequence()[0]->getAsAggregate()->getSequence();
+
+        for (int p = 0; p < (int)parameters.size(); ++p) {
+            const glslang::TType& paramType = parameters[p]->getAsTyped()->getType();
+            spv::Id typeId = convertGlslangToSpvType(paramType);
+            if (paramType.getQualifier().storage != glslang::EvqConstReadOnly)
+                typeId = builder.makePointer(spv::StorageClassFunction, typeId);
+            else
+                constReadOnlyParameters.insert(parameters[p]->getAsSymbolNode()->getId());
+            paramTypes.push_back(typeId);
+        }
+
+        spv::Block* functionBlock;
+        spv::Function *function = builder.makeFunctionEntry(convertGlslangToSpvType(glslFunction->getType()), glslFunction->getName().c_str(),
+                                                              paramTypes, &functionBlock);
+
+        // Track function to emit/call later
+        functionMap[glslFunction->getName().c_str()] = function;
+
+        // Set the parameter id's
+        for (int p = 0; p < (int)parameters.size(); ++p) {
+            symbolValues[parameters[p]->getAsSymbolNode()->getId()] = function->getParamId(p);
+            // give a name too
+            builder.addName(function->getParamId(p), parameters[p]->getAsSymbolNode()->getName().c_str());
+        }
+    }
+}
+
+// Process all the initializers, while skipping the functions and link objects
+void TGlslangToSpvTraverser::makeGlobalInitializers(const glslang::TIntermSequence& initializers)
+{
+    builder.setBuildPoint(shaderEntry->getLastBlock());
+    for (int i = 0; i < (int)initializers.size(); ++i) {
+        glslang::TIntermAggregate* initializer = initializers[i]->getAsAggregate();
+        if (initializer && initializer->getOp() != glslang::EOpFunction && initializer->getOp() != glslang::EOpLinkerObjects) {
+
+            // We're on a top-level node that's not a function.  Treat as an initializer, whose
+            // code goes into the beginning of main.
+            initializer->traverse(this);
+        }
+    }
+}
+
+// Process all the functions, while skipping initializers.
+void TGlslangToSpvTraverser::visitFunctions(const glslang::TIntermSequence& glslFunctions)
+{
+    for (int f = 0; f < (int)glslFunctions.size(); ++f) {
+        glslang::TIntermAggregate* node = glslFunctions[f]->getAsAggregate();
+        if (node && (node->getOp() == glslang::EOpFunction || node->getOp() == glslang ::EOpLinkerObjects))
+            node->traverse(this);
+    }
+}
+
+void TGlslangToSpvTraverser::handleFunctionEntry(const glslang::TIntermAggregate* node)
+{
+    // SPIR-V functions should already be in the functionMap from the prepass 
+    // that called makeFunctions().
+    spv::Function* function = functionMap[node->getName().c_str()];
+    spv::Block* functionBlock = function->getEntryBlock();
+    builder.setBuildPoint(functionBlock);
+}
+
+void TGlslangToSpvTraverser::translateArguments(const glslang::TIntermSequence& glslangArguments, std::vector<spv::Id>& arguments)
+{
+    for (int i = 0; i < (int)glslangArguments.size(); ++i) {
+        builder.clearAccessChain();
+        glslangArguments[i]->traverse(this);
+        arguments.push_back(builder.accessChainLoad(TranslatePrecisionDecoration(glslangArguments[i]->getAsTyped()->getType())));
+    }
+}
+
+spv::Id TGlslangToSpvTraverser::handleBuiltInFunctionCall(const glslang::TIntermAggregate* node)
+{
+    std::vector<spv::Id> arguments;
+    translateArguments(node->getSequence(), arguments);
+
+    std::vector<spv::Id> argTypes;
+    for (int a = 0; a < (int)arguments.size(); ++a)
+        argTypes.push_back(builder.getTypeId(arguments[a]));
+
+    spv::Decoration precision = TranslatePrecisionDecoration(node->getType());
+
+    if (node->getName() == "ftransform(") {
+        spv::MissingFunctionality("ftransform()");
+        //spv::Id vertex = builder.createVariable(spv::StorageShaderGlobal, spv::VectorType::get(spv::makeFloatType(), 4),
+        //                                                             "gl_Vertex_sim");
+        //spv::Id matrix = builder.createVariable(spv::StorageShaderGlobal, spv::VectorType::get(spv::makeFloatType(), 4),
+        //                                                             "gl_ModelViewProjectionMatrix_sim");
+        return 0;
+    }
+
+    if (node->getName().substr(0, 7) == "texture" || node->getName().substr(0, 5) == "texel" || node->getName().substr(0, 6) == "shadow") {
+        const glslang::TSampler sampler = node->getSequence()[0]->getAsTyped()->getType().getSampler();
+        spv::Builder::TextureParameters params = { };
+        params.sampler = arguments[0];
+
+        // special case size query
+        if (node->getName().find("textureSize", 0) != std::string::npos) {
+            if (arguments.size() > 1) {
+                params.lod = arguments[1];
+                return builder.createTextureQueryCall(spv::OpTextureQuerySizeLod, params);
+            } else
+                return builder.createTextureQueryCall(spv::OpTextureQuerySize, params);
+        }
+
+        // special case the number of samples query
+        if (node->getName().find("textureSamples", 0) != std::string::npos)
+            return builder.createTextureQueryCall(spv::OpTextureQuerySamples, params);
+
+        // special case the other queries
+        if (node->getName().find("Query", 0) != std::string::npos) {
+            if (node->getName().find("Levels", 0) != std::string::npos)
+                return builder.createTextureQueryCall(spv::OpTextureQueryLevels, params);
+            else if (node->getName().find("Lod", 0) != std::string::npos) {
+                params.coords = arguments[1];
+                return builder.createTextureQueryCall(spv::OpTextureQueryLod, params);
+            } else
+                spv::MissingFunctionality("glslang texture query");
+        }
+
+        // This is no longer a query....
+
+        bool lod = node->getName().find("Lod", 0) != std::string::npos;
+        bool proj = node->getName().find("Proj", 0) != std::string::npos;
+        bool offsets = node->getName().find("Offsets", 0) != std::string::npos;
+        bool offset = ! offsets && node->getName().find("Offset", 0) != std::string::npos;
+        bool fetch = node->getName().find("Fetch", 0) != std::string::npos;
+        bool gather = node->getName().find("Gather", 0) != std::string::npos;
+        bool grad = node->getName().find("Grad", 0) != std::string::npos;
+
+        if (fetch)
+            spv::MissingFunctionality("texel fetch");
+        if (gather)
+            spv::MissingFunctionality("texture gather");
+
+        // check for bias argument
+        bool bias = false;
+        if (! lod && ! gather && ! grad && ! fetch) {
+            int nonBiasArgCount = 2;
+            if (offset)
+                ++nonBiasArgCount;
+            if (grad)
+                nonBiasArgCount += 2;
+
+            if ((int)arguments.size() > nonBiasArgCount)
+                bias = true;
+        }
+
+        bool cubeCompare = sampler.dim == glslang::EsdCube && sampler.arrayed && sampler.shadow;
+
+        // set the rest of the arguments
+        params.coords = arguments[1];
+        int extraArgs = 0;
+        if (cubeCompare)
+            params.Dref = arguments[2];
+        if (lod) {
+            params.lod = arguments[2];
+            ++extraArgs;
+        }
+        if (grad) {
+            params.gradX = arguments[2 + extraArgs];
+            params.gradY = arguments[3 + extraArgs];
+            extraArgs += 2;
+        }
+        //if (gather && compare) {
+        //    params.compare = arguments[2 + extraArgs];
+        //    ++extraArgs;
+        //}
+        if (offset | offsets) {
+            params.offset = arguments[2 + extraArgs];
+            ++extraArgs;
+        }
+        if (bias) {
+            params.bias = arguments[2 + extraArgs];
+            ++extraArgs;
+        }
+
+        return builder.createTextureCall(precision, convertGlslangToSpvType(node->getType()), proj, params);
+    }
+
+    spv::MissingFunctionality("built-in function call");
+
+    return 0;
+}
+
+spv::Id TGlslangToSpvTraverser::handleUserFunctionCall(const glslang::TIntermAggregate* node)
+{
+    // Grab the function's pointer from the previously created function
+    spv::Function* function = functionMap[node->getName().c_str()];
+    if (! function)
+        return 0;
+
+    const glslang::TIntermSequence& glslangArgs = node->getSequence();
+    const glslang::TQualifierList& qualifiers = node->getQualifierList();
+
+    //  See comments in makeFunctions() for details about the semantics for parameter passing.
+    //
+    // These imply we need a four step process:
+    // 1. Evaluate the arguments
+    // 2. Allocate and make copies of in, out, and inout arguments
+    // 3. Make the call
+    // 4. Copy back the results
+
+    // 1. Evaluate the arguments
+    std::vector<spv::Builder::AccessChain> lValues;
+    std::vector<spv::Id> rValues;
+    for (int a = 0; a < (int)glslangArgs.size(); ++a) {
+        // build l-value
+        builder.clearAccessChain();
+        glslangArgs[a]->traverse(this);
+        // keep outputs as l-values, evaluate input-only as r-values
+        if (qualifiers[a] != glslang::EvqConstReadOnly) {
+            // save l-value
+            lValues.push_back(builder.getAccessChain());
+        } else {
+            // process r-value
+            rValues.push_back(builder.accessChainLoad(TranslatePrecisionDecoration(glslangArgs[a]->getAsTyped()->getType())));
+        }
+    }
+
+    // 2. Allocate space for anything needing a copy, and if it's "in" or "inout"
+    // copy the original into that space.
+    //
+    // Also, build up the list of actual arguments to pass in for the call
+    int lValueCount = 0;
+    int rValueCount = 0;
+    std::vector<spv::Id> spvArgs;
+    for (int a = 0; a < (int)glslangArgs.size(); ++a) {
+        spv::Id arg;
+        if (qualifiers[a] != glslang::EvqConstReadOnly) {
+            // need space to hold the copy
+            const glslang::TType& paramType = glslangArgs[a]->getAsTyped()->getType();
+            arg = builder.createVariable(spv::StorageClassFunction, convertGlslangToSpvType(paramType), "param");
+            if (qualifiers[a] == glslang::EvqIn || qualifiers[a] == glslang::EvqInOut) {
+                // need to copy the input into output space
+                builder.setAccessChain(lValues[lValueCount]);
+                spv::Id copy = builder.accessChainLoad(spv::NoPrecision);  // TODO: get precision
+                builder.createStore(copy, arg);
+            }
+            ++lValueCount;
+        } else {
+            arg = rValues[rValueCount];
+            ++rValueCount;
+        }
+        spvArgs.push_back(arg);
+    }
+
+    // 3. Make the call.
+    spv::Id result = builder.createFunctionCall(function, spvArgs);
+
+    // 4. Copy back out an "out" arguments.
+    lValueCount = 0;
+    for (int a = 0; a < (int)glslangArgs.size(); ++a) {
+        if (qualifiers[a] != glslang::EvqConstReadOnly) {
+            if (qualifiers[a] == glslang::EvqOut || qualifiers[a] == glslang::EvqInOut) {
+                spv::Id copy = builder.createLoad(spvArgs[a]);
+                builder.setAccessChain(lValues[lValueCount]);
+                builder.accessChainStore(copy);
+            }
+            ++lValueCount;
+        }
+    }
+
+    return result;
+}
+
+// Translate AST operation to SPV operation, already having SPV-based operands/types.
+spv::Id TGlslangToSpvTraverser::createBinaryOperation(glslang::TOperator op, spv::Decoration precision, 
+                                                      spv::Id typeId, spv::Id left, spv::Id right,
+                                                      glslang::TBasicType typeProxy, bool reduceComparison)
+{
+    bool isUnsigned = typeProxy == glslang::EbtUint;
+    bool isFloat = typeProxy == glslang::EbtFloat || typeProxy == glslang::EbtDouble;
+
+    spv::Op binOp = spv::OpNop;
+    bool needsPromotion = true;
+    bool comparison = false;
+
+    switch (op) {
+    case glslang::EOpAdd:
+    case glslang::EOpAddAssign:
+        if (isFloat)
+            binOp = spv::OpFAdd;
+        else
+            binOp = spv::OpIAdd;
+        break;
+    case glslang::EOpSub:
+    case glslang::EOpSubAssign:
+        if (isFloat)
+            binOp = spv::OpFSub;
+        else
+            binOp = spv::OpISub;
+        break;
+    case glslang::EOpMul:
+    case glslang::EOpMulAssign:
+        if (isFloat)
+            binOp = spv::OpFMul;
+        else
+            binOp = spv::OpIMul;
+        break;
+    case glslang::EOpVectorTimesScalar:
+    case glslang::EOpVectorTimesScalarAssign:
+        if (builder.isVector(right))
+            std::swap(left, right);
+        assert(builder.isScalar(right));
+        binOp = spv::OpVectorTimesScalar;
+        needsPromotion = false;
+        break;
+    case glslang::EOpVectorTimesMatrix:
+    case glslang::EOpVectorTimesMatrixAssign:
+        assert(builder.isVector(left));
+        assert(builder.isMatrix(right));
+        binOp = spv::OpVectorTimesMatrix;
+        break;
+    case glslang::EOpMatrixTimesVector:
+        assert(builder.isMatrix(left));
+        assert(builder.isVector(right));
+        binOp = spv::OpMatrixTimesVector;
+        break;
+    case glslang::EOpMatrixTimesScalar:
+    case glslang::EOpMatrixTimesScalarAssign:
+        if (builder.isMatrix(right))
+            std::swap(left, right);
+        assert(builder.isScalar(right));
+        binOp = spv::OpMatrixTimesScalar;
+        break;
+    case glslang::EOpMatrixTimesMatrix:
+    case glslang::EOpMatrixTimesMatrixAssign:
+        assert(builder.isMatrix(left));
+        assert(builder.isMatrix(right));
+        binOp = spv::OpMatrixTimesMatrix;
+        break;
+    case glslang::EOpOuterProduct:
+        binOp = spv::OpOuterProduct;
+        needsPromotion = false;
+        break;
+
+    case glslang::EOpDiv:
+    case glslang::EOpDivAssign:
+        if (isFloat)
+            binOp = spv::OpFDiv;
+        else if (isUnsigned)
+            binOp = spv::OpUDiv;
+        else
+            binOp = spv::OpSDiv;
+        break;
+    case glslang::EOpMod:
+    case glslang::EOpModAssign:
+        if (isFloat)
+            binOp = spv::OpFMod;
+        else if (isUnsigned)
+            binOp = spv::OpUMod;
+        else
+            binOp = spv::OpSMod;
+        break;
+    case glslang::EOpRightShift:
+    case glslang::EOpRightShiftAssign:
+        if (isUnsigned)
+            binOp = spv::OpShiftRightLogical;
+        else
+            binOp = spv::OpShiftRightArithmetic;
+        break;
+    case glslang::EOpLeftShift:
+    case glslang::EOpLeftShiftAssign:
+        binOp = spv::OpShiftLeftLogical;
+        break;
+    case glslang::EOpAnd:
+    case glslang::EOpAndAssign:
+        binOp = spv::OpBitwiseAnd;
+        break;
+    case glslang::EOpLogicalAnd:
+        needsPromotion = false;
+        binOp = spv::OpLogicalAnd;
+        break;
+    case glslang::EOpInclusiveOr:
+    case glslang::EOpInclusiveOrAssign:
+        binOp = spv::OpBitwiseOr;
+        break;
+    case glslang::EOpLogicalOr:
+        needsPromotion = false;
+        binOp = spv::OpLogicalOr;
+        break;
+    case glslang::EOpExclusiveOr:
+    case glslang::EOpExclusiveOrAssign:
+        binOp = spv::OpBitwiseXor;
+        break;
+    case glslang::EOpLogicalXor:
+        needsPromotion = false;
+        binOp = spv::OpLogicalXor;
+        break;
+
+    case glslang::EOpLessThan:
+    case glslang::EOpGreaterThan:
+    case glslang::EOpLessThanEqual:
+    case glslang::EOpGreaterThanEqual:
+    case glslang::EOpEqual:
+    case glslang::EOpNotEqual:
+    case glslang::EOpVectorEqual:
+    case glslang::EOpVectorNotEqual:
+        comparison = true;
+        break;
+    default:
+        break;
+    }
+
+    if (binOp != spv::OpNop) {
+        if (builder.isMatrix(left) || builder.isMatrix(right)) {
+            switch (binOp) {
+            case spv::OpMatrixTimesScalar:
+            case spv::OpVectorTimesMatrix:
+            case spv::OpMatrixTimesVector:
+            case spv::OpMatrixTimesMatrix:
+                break;
+            case spv::OpFDiv:
+                // turn it into a multiply...
+                assert(builder.isMatrix(left) && builder.isScalar(right));
+                right = builder.createBinOp(spv::OpFDiv, builder.getTypeId(right), builder.makeFloatConstant(1.0F), right);
+                binOp = spv::OpFMul;
+                break;
+            default:
+                spv::MissingFunctionality("binary operation on matrix");
+                break;
+            }
+
+            spv::Id id = builder.createBinOp(binOp, typeId, left, right);
+            builder.setPrecision(id, precision);
+
+            return id;
+        }
+
+        // No matrix involved; make both operands be the same number of components, if needed
+        if (needsPromotion)
+            builder.promoteScalar(precision, left, right);
+
+        spv::Id id = builder.createBinOp(binOp, typeId, left, right);
+        builder.setPrecision(id, precision);
+
+        return id;
+    }
+
+    if (! comparison)
+        return 0;
+
+    // Comparison instructions
+
+    if (reduceComparison && (builder.isVector(left) || builder.isMatrix(left) || builder.isAggregate(left))) {
+        assert(op == glslang::EOpEqual || op == glslang::EOpNotEqual);
+
+        return builder.createCompare(precision, left, right, op == glslang::EOpEqual);
+    }
+
+    switch (op) {
+    case glslang::EOpLessThan:
+        if (isFloat)
+            binOp = spv::OpFOrdLessThan;
+        else if (isUnsigned)
+            binOp = spv::OpULessThan;
+        else
+            binOp = spv::OpSLessThan;
+        break;
+    case glslang::EOpGreaterThan:
+        if (isFloat)
+            binOp = spv::OpFOrdGreaterThan;
+        else if (isUnsigned)
+            binOp = spv::OpUGreaterThan;
+        else
+            binOp = spv::OpSGreaterThan;
+        break;
+    case glslang::EOpLessThanEqual:
+        if (isFloat)
+            binOp = spv::OpFOrdLessThanEqual;
+        else if (isUnsigned)
+            binOp = spv::OpULessThanEqual;
+        else
+            binOp = spv::OpSLessThanEqual;
+        break;
+    case glslang::EOpGreaterThanEqual:
+        if (isFloat)
+            binOp = spv::OpFOrdGreaterThanEqual;
+        else if (isUnsigned)
+            binOp = spv::OpUGreaterThanEqual;
+        else
+            binOp = spv::OpSGreaterThanEqual;
+        break;
+    case glslang::EOpEqual:
+    case glslang::EOpVectorEqual:
+        if (isFloat)
+            binOp = spv::OpFOrdEqual;
+        else
+            binOp = spv::OpIEqual;
+        break;
+    case glslang::EOpNotEqual:
+    case glslang::EOpVectorNotEqual:
+        if (isFloat)
+            binOp = spv::OpFOrdNotEqual;
+        else
+            binOp = spv::OpINotEqual;
+        break;
+    default:
+        break;
+    }
+
+    if (binOp != spv::OpNop) {
+        spv::Id id = builder.createBinOp(binOp, typeId, left, right);
+        builder.setPrecision(id, precision);
+
+        return id;
+    }
+
+    return 0;
+}
+
+spv::Id TGlslangToSpvTraverser::createUnaryOperation(glslang::TOperator op, spv::Decoration precision, spv::Id typeId, spv::Id operand, bool isFloat)
+{
+    spv::Op unaryOp = spv::OpNop;
+    int libCall = -1;
+
+    switch (op) {
+    case glslang::EOpNegative:
+        if (isFloat)
+            unaryOp = spv::OpFNegate;
+        else
+            unaryOp = spv::OpSNegate;
+        break;
+
+    case glslang::EOpLogicalNot:
+    case glslang::EOpVectorLogicalNot:
+    case glslang::EOpBitwiseNot:
+        unaryOp = spv::OpNot;
+        break;
+    
+    case glslang::EOpDeterminant:
+        libCall = GLSL_STD_450::Determinant;
+        break;
+    case glslang::EOpMatrixInverse:
+        libCall = GLSL_STD_450::MatrixInverse;
+        break;
+    case glslang::EOpTranspose:
+        unaryOp = spv::OpTranspose;
+        break;
+
+    case glslang::EOpRadians:
+        libCall = GLSL_STD_450::Radians;
+        break;
+    case glslang::EOpDegrees:
+        libCall = GLSL_STD_450::Degrees;
+        break;
+    case glslang::EOpSin:
+        libCall = GLSL_STD_450::Sin;
+        break;
+    case glslang::EOpCos:
+        libCall = GLSL_STD_450::Cos;
+        break;
+    case glslang::EOpTan:
+        libCall = GLSL_STD_450::Tan;
+        break;
+    case glslang::EOpAcos:
+        libCall = GLSL_STD_450::Acos;
+        break;
+    case glslang::EOpAsin:
+        libCall = GLSL_STD_450::Asin;
+        break;
+    case glslang::EOpAtan:
+        libCall = GLSL_STD_450::Atan;
+        break;
+
+    case glslang::EOpAcosh:
+        libCall = GLSL_STD_450::Acosh;
+        break;
+    case glslang::EOpAsinh:
+        libCall = GLSL_STD_450::Asinh;
+        break;
+    case glslang::EOpAtanh:
+        libCall = GLSL_STD_450::Atanh;
+        break;
+    case glslang::EOpTanh:
+        libCall = GLSL_STD_450::Tanh;
+        break;
+    case glslang::EOpCosh:
+        libCall = GLSL_STD_450::Cosh;
+        break;
+    case glslang::EOpSinh:
+        libCall = GLSL_STD_450::Sinh;
+        break;
+
+    case glslang::EOpLength:
+        libCall = GLSL_STD_450::Length;
+        break;
+    case glslang::EOpNormalize:
+        libCall = GLSL_STD_450::Normalize;
+        break;
+
+    case glslang::EOpExp:
+        libCall = GLSL_STD_450::Exp;
+        break;
+    case glslang::EOpLog:
+        libCall = GLSL_STD_450::Log;
+        break;
+    case glslang::EOpExp2:
+        libCall = GLSL_STD_450::Exp2;
+        break;
+    case glslang::EOpLog2:
+        libCall = GLSL_STD_450::Log2;
+        break;
+    case glslang::EOpSqrt:
+        libCall = GLSL_STD_450::Sqrt;
+        break;
+    case glslang::EOpInverseSqrt:
+        libCall = GLSL_STD_450::InverseSqrt;
+        break;
+
+    case glslang::EOpFloor:
+        libCall = GLSL_STD_450::Floor;
+        break;
+    case glslang::EOpTrunc:
+        libCall = GLSL_STD_450::Trunc;
+        break;
+    case glslang::EOpRound:
+        libCall = GLSL_STD_450::Round;
+        break;
+    case glslang::EOpRoundEven:
+        libCall = GLSL_STD_450::RoundEven;
+        break;
+    case glslang::EOpCeil:
+        libCall = GLSL_STD_450::Ceil;
+        break;
+    case glslang::EOpFract:
+        libCall = GLSL_STD_450::Fract;
+        break;
+
+    case glslang::EOpIsNan:
+        unaryOp = spv::OpIsNan;
+        break;
+    case glslang::EOpIsInf:
+        unaryOp = spv::OpIsInf;
+        break;
+
+    case glslang::EOpFloatBitsToInt:
+        libCall = GLSL_STD_450::FloatBitsToInt;
+        break;
+    case glslang::EOpFloatBitsToUint:
+        libCall = GLSL_STD_450::FloatBitsToUint;
+        break;
+    case glslang::EOpIntBitsToFloat:
+        libCall = GLSL_STD_450::IntBitsToFloat;
+        break;
+    case glslang::EOpUintBitsToFloat:
+        libCall = GLSL_STD_450::UintBitsToFloat;
+        break;
+    case glslang::EOpPackSnorm2x16:
+        libCall = GLSL_STD_450::PackSnorm2x16;
+        break;
+    case glslang::EOpUnpackSnorm2x16:
+        libCall = GLSL_STD_450::UnpackSnorm2x16;
+        break;
+    case glslang::EOpPackUnorm2x16:
+        libCall = GLSL_STD_450::PackUnorm2x16;
+        break;
+    case glslang::EOpUnpackUnorm2x16:
+        libCall = GLSL_STD_450::UnpackUnorm2x16;
+        break;
+    case glslang::EOpPackHalf2x16:
+        libCall = GLSL_STD_450::PackHalf2x16;
+        break;
+    case glslang::EOpUnpackHalf2x16:
+        libCall = GLSL_STD_450::UnpackHalf2x16;
+        break;
+
+    case glslang::EOpDPdx:
+        unaryOp = spv::OpDPdx;
+        break;
+    case glslang::EOpDPdy:
+        unaryOp = spv::OpDPdy;
+        break;
+    case glslang::EOpFwidth:
+        unaryOp = spv::OpFwidth;
+        break;
+    case glslang::EOpDPdxFine:
+        unaryOp = spv::OpDPdxFine;
+        break;
+    case glslang::EOpDPdyFine:
+        unaryOp = spv::OpDPdyFine;
+        break;
+    case glslang::EOpFwidthFine:
+        unaryOp = spv::OpFwidthFine;
+        break;
+    case glslang::EOpDPdxCoarse:
+        unaryOp = spv::OpDPdxCoarse;
+        break;
+    case glslang::EOpDPdyCoarse:
+        unaryOp = spv::OpDPdyCoarse;
+        break;
+    case glslang::EOpFwidthCoarse:
+        unaryOp = spv::OpFwidthCoarse;
+        break;
+
+    case glslang::EOpAny:
+        unaryOp = spv::OpAny;
+        break;
+    case glslang::EOpAll:
+        unaryOp = spv::OpAll;
+        break;
+
+    case glslang::EOpAbs:
+        libCall = GLSL_STD_450::Abs;
+        break;
+    case glslang::EOpSign:
+        libCall = GLSL_STD_450::Sign;
+        break;
+
+    default:
+        return 0;
+    }
+
+    spv::Id id;
+    if (libCall >= 0) {
+        std::vector<spv::Id> args;
+        args.push_back(operand);
+        id = builder.createBuiltinCall(precision, typeId, stdBuiltins, libCall, args);
+    } else
+        id = builder.createUnaryOp(unaryOp, typeId, operand);
+
+    builder.setPrecision(id, precision);
+
+    return id;
+}
+
+spv::Id TGlslangToSpvTraverser::createConversion(glslang::TOperator op, spv::Decoration precision, spv::Id destType, spv::Id operand)
+{
+    spv::Op convOp = spv::OpNop;
+    spv::Id zero = 0;
+    spv::Id one = 0;
+
+    int vectorSize = builder.isVectorType(destType) ? builder.getNumTypeComponents(destType) : 0;
+
+    switch (op) {
+    case glslang::EOpConvIntToBool:
+    case glslang::EOpConvUintToBool:
+        zero = builder.makeUintConstant(0);
+        zero = makeSmearedConstant(zero, vectorSize);
+        return builder.createBinOp(spv::OpINotEqual, destType, operand, zero);
+
+    case glslang::EOpConvFloatToBool:
+        zero = builder.makeFloatConstant(0.0F);
+        zero = makeSmearedConstant(zero, vectorSize);
+        return builder.createBinOp(spv::OpFOrdNotEqual, destType, operand, zero);
+
+    case glslang::EOpConvDoubleToBool:
+        zero = builder.makeDoubleConstant(0.0);
+        zero = makeSmearedConstant(zero, vectorSize);
+        return builder.createBinOp(spv::OpFOrdNotEqual, destType, operand, zero);
+
+    case glslang::EOpConvBoolToFloat:
+        convOp = spv::OpSelect;
+        zero = builder.makeFloatConstant(0.0);
+        one  = builder.makeFloatConstant(1.0);
+        break;
+    case glslang::EOpConvBoolToDouble:
+        convOp = spv::OpSelect;
+        zero = builder.makeDoubleConstant(0.0);
+        one  = builder.makeDoubleConstant(1.0);
+        break;
+    case glslang::EOpConvBoolToInt:
+        zero = builder.makeIntConstant(0);
+        one  = builder.makeIntConstant(1);
+        convOp = spv::OpSelect;
+        break;
+    case glslang::EOpConvBoolToUint:
+        zero = builder.makeUintConstant(0);
+        one  = builder.makeUintConstant(1);
+        convOp = spv::OpSelect;
+        break;
+
+    case glslang::EOpConvIntToFloat:
+    case glslang::EOpConvIntToDouble:
+        convOp = spv::OpConvertSToF;
+        break;
+
+    case glslang::EOpConvUintToFloat:
+    case glslang::EOpConvUintToDouble:
+        convOp = spv::OpConvertUToF;
+        break;
+
+    case glslang::EOpConvDoubleToFloat:
+    case glslang::EOpConvFloatToDouble:
+        convOp = spv::OpFConvert;
+        break;
+
+    case glslang::EOpConvFloatToInt:
+    case glslang::EOpConvDoubleToInt:
+        convOp = spv::OpConvertFToS;
+        break;
+
+    case glslang::EOpConvUintToInt:
+    case glslang::EOpConvIntToUint:
+        convOp = spv::OpBitcast;
+        break;
+
+    case glslang::EOpConvFloatToUint:
+    case glslang::EOpConvDoubleToUint:
+        convOp = spv::OpConvertFToU;
+        break;
+    default:
+        break;
+    }
+
+    spv::Id result = 0;
+    if (convOp == spv::OpNop)
+        return result;
+
+    if (convOp == spv::OpSelect) {
+        zero = makeSmearedConstant(zero, vectorSize);
+        one  = makeSmearedConstant(one, vectorSize);
+        result = builder.createTriOp(convOp, destType, operand, one, zero);
+    } else
+        result = builder.createUnaryOp(convOp, destType, operand);
+
+    builder.setPrecision(result, precision);
+
+    return result;
+}
+
+spv::Id TGlslangToSpvTraverser::makeSmearedConstant(spv::Id constant, int vectorSize)
+{
+    if (vectorSize == 0)
+        return constant;
+
+    spv::Id vectorTypeId = builder.makeVectorType(builder.getTypeId(constant), vectorSize);
+    std::vector<spv::Id> components;
+    for (int c = 0; c < vectorSize; ++c)
+        components.push_back(constant);
+    return builder.makeCompositeConstant(vectorTypeId, components);
+}
+
+spv::Id TGlslangToSpvTraverser::createMiscOperation(glslang::TOperator op, spv::Decoration precision, spv::Id typeId, std::vector<spv::Id>& operands)
+{
+    spv::Op opCode = spv::OpNop;
+    int libCall = -1;
+
+    switch (op) {
+    case glslang::EOpMin:
+        libCall = GLSL_STD_450::Min;
+        break;
+    case glslang::EOpModf:
+        libCall = GLSL_STD_450::Modf;
+        break;
+    case glslang::EOpMax:
+        libCall = GLSL_STD_450::Max;
+        break;
+    case glslang::EOpPow:
+        libCall = GLSL_STD_450::Pow;
+        break;
+    case glslang::EOpDot:
+        opCode = spv::OpDot;
+        break;
+    case glslang::EOpAtan:
+        libCall = GLSL_STD_450::Atan2;
+        break;
+
+    case glslang::EOpClamp:
+        libCall = GLSL_STD_450::Clamp;
+        break;
+    case glslang::EOpMix:
+        libCall = GLSL_STD_450::Mix;
+        break;
+    case glslang::EOpStep:
+        libCall = GLSL_STD_450::Step;
+        break;
+    case glslang::EOpSmoothStep:
+        libCall = GLSL_STD_450::SmoothStep;
+        break;
+
+    case glslang::EOpDistance:
+        libCall = GLSL_STD_450::Distance;
+        break;
+    case glslang::EOpCross:
+        libCall = GLSL_STD_450::Cross;
+        break;
+    case glslang::EOpFaceForward:
+        libCall = GLSL_STD_450::FaceForward;
+        break;
+    case glslang::EOpReflect:
+        libCall = GLSL_STD_450::Reflect;
+        break;
+    case glslang::EOpRefract:
+        libCall = GLSL_STD_450::Refract;
+        break;
+    default:
+        return 0;
+    }
+
+    spv::Id id = 0;
+    if (libCall >= 0)
+        id = builder.createBuiltinCall(precision, typeId, stdBuiltins, libCall, operands);
+    else {
+        switch (operands.size()) {
+        case 0:
+            // should all be handled by visitAggregate and createNoArgOperation
+            assert(0);
+            return 0;
+        case 1:
+            // should all be handled by createUnaryOperation
+            assert(0);
+            return 0;
+        case 2:
+            id = builder.createBinOp(opCode, typeId, operands[0], operands[1]);
+            break;
+        case 3:
+            id = builder.createTernaryOp(opCode, typeId, operands[0], operands[1], operands[2]);
+            break;
+        default:
+            // These do not exist yet
+            assert(0 && "operation with more than 3 operands");
+            break;
+        }
+    }
+
+    builder.setPrecision(id, precision);
+
+    return id;
+}
+
+// Intrinsics with no arguments, no return value, and no precision.
+spv::Id TGlslangToSpvTraverser::createNoArgOperation(glslang::TOperator op)
+{
+    // TODO: get the barrier operands correct
+
+    switch (op) {
+    case glslang::EOpEmitVertex:
+        builder.createNoResultOp(spv::OpEmitVertex);
+        return 0;
+    case glslang::EOpEndPrimitive:
+        builder.createNoResultOp(spv::OpEndPrimitive);
+        return 0;
+    case glslang::EOpBarrier:
+        builder.createMemoryBarrier(spv::ExecutionScopeDevice, spv::MemorySemanticsAllMemory);
+        builder.createControlBarrier(spv::ExecutionScopeDevice);
+        return 0;
+    case glslang::EOpMemoryBarrier:
+        builder.createMemoryBarrier(spv::ExecutionScopeDevice, spv::MemorySemanticsAllMemory);
+        return 0;
+    case glslang::EOpMemoryBarrierAtomicCounter:
+        builder.createMemoryBarrier(spv::ExecutionScopeDevice, spv::MemorySemanticsAtomicCounterMemoryMask);
+        return 0;
+    case glslang::EOpMemoryBarrierBuffer:
+        builder.createMemoryBarrier(spv::ExecutionScopeDevice, spv::MemorySemanticsUniformMemoryMask);
+        return 0;
+    case glslang::EOpMemoryBarrierImage:
+        builder.createMemoryBarrier(spv::ExecutionScopeDevice, spv::MemorySemanticsImageMemoryMask);
+        return 0;
+    case glslang::EOpMemoryBarrierShared:
+        builder.createMemoryBarrier(spv::ExecutionScopeDevice, spv::MemorySemanticsWorkgroupLocalMemoryMask);
+        return 0;
+    case glslang::EOpGroupMemoryBarrier:
+        builder.createMemoryBarrier(spv::ExecutionScopeDevice, spv::MemorySemanticsWorkgroupGlobalMemoryMask);
+        return 0;
+    default:
+        spv::MissingFunctionality("operation with no arguments");
+        return 0;
+    }
+}
+
+spv::Id TGlslangToSpvTraverser::getSymbolId(const glslang::TIntermSymbol* symbol)
+{
+    std::map<int, spv::Id>::iterator iter;
+    iter = symbolValues.find(symbol->getId());
+    spv::Id id;
+    if (symbolValues.end() != iter) {
+        id = iter->second;
+        return id;
+    }
+
+    // it was not found, create it
+    id = createSpvVariable(symbol);
+    symbolValues[symbol->getId()] = id;
+
+    if (! symbol->getType().isStruct()) {
+        addDecoration(id, TranslatePrecisionDecoration(symbol->getType()));
+        addDecoration(id, TranslateInterpolationDecoration(symbol->getType()));
+        if (symbol->getQualifier().hasLocation())
+            builder.addDecoration(id, spv::DecorationLocation, symbol->getQualifier().layoutLocation);
+        if (symbol->getQualifier().hasIndex())
+            builder.addDecoration(id, spv::DecorationIndex, symbol->getQualifier().layoutIndex);
+        if (symbol->getQualifier().hasComponent())
+            builder.addDecoration(id, spv::DecorationComponent, symbol->getQualifier().layoutComponent);
+        if (glslangIntermediate->getXfbMode()) {
+            if (symbol->getQualifier().hasXfbStride())
+                builder.addDecoration(id, spv::DecorationStride, symbol->getQualifier().layoutXfbStride);
+            if (symbol->getQualifier().hasXfbBuffer())
+                builder.addDecoration(id, spv::DecorationXfbBuffer, symbol->getQualifier().layoutXfbBuffer);
+            if (symbol->getQualifier().hasXfbOffset())
+                builder.addDecoration(id, spv::DecorationOffset, symbol->getQualifier().layoutXfbOffset);
+        }
+    }
+
+    addDecoration(id, TranslateInvariantDecoration(symbol->getType()));
+    if (symbol->getQualifier().hasStream())
+        builder.addDecoration(id, spv::DecorationStream, symbol->getQualifier().layoutStream);
+    if (symbol->getQualifier().hasSet())
+        builder.addDecoration(id, spv::DecorationDescriptorSet, symbol->getQualifier().layoutSet);
+    if (symbol->getQualifier().hasBinding())
+        builder.addDecoration(id, spv::DecorationBinding, symbol->getQualifier().layoutBinding);
+    if (glslangIntermediate->getXfbMode()) {
+        if (symbol->getQualifier().hasXfbStride())
+            builder.addDecoration(id, spv::DecorationStride, symbol->getQualifier().layoutXfbStride);
+        if (symbol->getQualifier().hasXfbBuffer())
+            builder.addDecoration(id, spv::DecorationXfbBuffer, symbol->getQualifier().layoutXfbBuffer);
+    }
+
+    // built-in variable decorations
+    int builtIn = TranslateBuiltInDecoration(symbol->getQualifier().builtIn);
+    if (builtIn != spv::BadValue)
+        builder.addDecoration(id, spv::DecorationBuiltIn, builtIn);
+
+    if (linkageOnly)
+        builder.addDecoration(id, spv::DecorationNoStaticUse);
+
+    return id;
+}
+
+void TGlslangToSpvTraverser::addDecoration(spv::Id id, spv::Decoration dec)
+{
+    if (dec != spv::BadValue)
+        builder.addDecoration(id, dec);
+}
+
+void TGlslangToSpvTraverser::addMemberDecoration(spv::Id id, int member, spv::Decoration dec)
+{
+    if (dec != spv::BadValue)
+        builder.addMemberDecoration(id, (unsigned)member, dec);
+}
+
+// Use 'consts' as the flattened glslang source of scalar constants to recursively
+// build the aggregate SPIR-V constant.
+//
+// If there are not enough elements present in 'consts', 0 will be substituted;
+// an empty 'consts' can be used to create a fully zeroed SPIR-V constant.
+//
+spv::Id TGlslangToSpvTraverser::createSpvConstant(const glslang::TType& glslangType, const glslang::TConstUnionArray& consts, int& nextConst)
+{
+    // vector of constants for SPIR-V
+    std::vector<spv::Id> spvConsts;
+
+    // Type is used for struct and array constants
+    spv::Id typeId = convertGlslangToSpvType(glslangType);
+
+    if (glslangType.isArray()) {
+        glslang::TType elementType;
+        elementType.shallowCopy(glslangType);   // TODO: desktop arrays of arrays functionality will need a deeper copy to avoid modifying the original
+        elementType.dereference();
+        for (int i = 0; i < glslangType.getArraySize(); ++i)
+            spvConsts.push_back(createSpvConstant(elementType, consts, nextConst));
+    } else if (glslangType.isMatrix()) {
+        glslang::TType vectorType;
+        vectorType.shallowCopy(glslangType);
+        vectorType.dereference();
+        for (int col = 0; col < glslangType.getMatrixCols(); ++col)
+            spvConsts.push_back(createSpvConstant(vectorType, consts, nextConst));
+    } else if (glslangType.getStruct()) {
+        glslang::TVector<glslang::TTypeLoc>::const_iterator iter;
+        for (iter = glslangType.getStruct()->begin(); iter != glslangType.getStruct()->end(); ++iter)
+            spvConsts.push_back(createSpvConstant(*iter->type, consts, nextConst));
+    } else if (glslangType.isVector()) {
+        for (unsigned int i = 0; i < (unsigned int)glslangType.getVectorSize(); ++i) {
+            bool zero = nextConst >= consts.size();
+            switch (glslangType.getBasicType()) {
+            case glslang::EbtInt:
+                spvConsts.push_back(builder.makeIntConstant(zero ? 0 : consts[nextConst].getIConst()));
+                break;
+            case glslang::EbtUint:
+                spvConsts.push_back(builder.makeUintConstant(zero ? 0 : consts[nextConst].getUConst()));
+                break;
+            case glslang::EbtFloat:
+                spvConsts.push_back(builder.makeFloatConstant(zero ? 0.0F : (float)consts[nextConst].getDConst()));
+                break;
+            case glslang::EbtDouble:
+                spvConsts.push_back(builder.makeDoubleConstant(zero ? 0.0 : consts[nextConst].getDConst()));
+                break;
+            case glslang::EbtBool:
+                spvConsts.push_back(builder.makeBoolConstant(zero ? false : consts[nextConst].getBConst()));
+                break;
+            default:
+                spv::MissingFunctionality("constant vector type");
+                break;
+            }
+            ++nextConst;
+        }
+    } else {
+        // we have a non-aggregate (scalar) constant
+        bool zero = nextConst >= consts.size();
+        spv::Id scalar = 0;
+        switch (glslangType.getBasicType()) {
+        case glslang::EbtInt:
+            scalar = builder.makeIntConstant(zero ? 0 : consts[nextConst].getIConst());
+            break;
+        case glslang::EbtUint:
+            scalar = builder.makeUintConstant(zero ? 0 : consts[nextConst].getUConst());
+            break;
+        case glslang::EbtFloat:
+            scalar = builder.makeFloatConstant(zero ? 0.0F : (float)consts[nextConst].getDConst());
+            break;
+        case glslang::EbtDouble:
+            scalar = builder.makeDoubleConstant(zero ? 0.0 : consts[nextConst].getDConst());
+            break;
+        case glslang::EbtBool:
+            scalar = builder.makeBoolConstant(zero ? false : consts[nextConst].getBConst());
+            break;
+        default:
+            spv::MissingFunctionality("constant scalar type");
+            break;
+        }
+        ++nextConst;
+        return scalar;
+    }
+
+    return builder.makeCompositeConstant(typeId, spvConsts);
+}
+
+};  // end anonymous namespace
+
+namespace glslang {
+
+// Write SPIR-V out to a binary file
+void OutputSpv(const std::vector<unsigned int>& spirv, const char* baseName)
+{
+    std::ofstream out;
+    std::string fileName(baseName);
+    fileName.append(".spv");
+    out.open(fileName.c_str(), std::ios::binary | std::ios::out);
+    for (int i = 0; i < (int)spirv.size(); ++i) {
+        unsigned int word = spirv[i];
+        out.write((const char*)&word, 4);
+    }
+    out.close();
+}
+
+//
+// Set up the glslang traversal
+//
+void GlslangToSpv(const glslang::TIntermediate& intermediate, std::vector<unsigned int>& spirv)
+{
+    TIntermNode* root = intermediate.getTreeRoot();
+
+    if (root == 0)
+        return;
+
+    glslang::GetThreadPoolAllocator().push();
+
+    TGlslangToSpvTraverser it(&intermediate);
+
+    root->traverse(&it);
+
+    it.dumpSpv(spirv);
+
+    glslang::GetThreadPoolAllocator().pop();
+}
+
+}; // end namespace glslang
index 1a14fe5..75375d8 100644 (file)
@@ -1,42 +1,42 @@
-//\r
-//Copyright (C) 2014 LunarG, Inc.\r
-//\r
-//All rights reserved.\r
-//\r
-//Redistribution and use in source and binary forms, with or without\r
-//modification, are permitted provided that the following conditions\r
-//are met:\r
-//\r
-//    Redistributions of source code must retain the above copyright\r
-//    notice, this list of conditions and the following disclaimer.\r
-//\r
-//    Redistributions in binary form must reproduce the above\r
-//    copyright notice, this list of conditions and the following\r
-//    disclaimer in the documentation and/or other materials provided\r
-//    with the distribution.\r
-//\r
-//    Neither the name of 3Dlabs Inc. Ltd. nor the names of its\r
-//    contributors may be used to endorse or promote products derived\r
-//    from this software without specific prior written permission.\r
-//\r
-//THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\r
-//"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\r
-//LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS\r
-//FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE\r
-//COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,\r
-//INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,\r
-//BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\r
-//LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER\r
-//CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\r
-//LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN\r
-//ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE\r
-//POSSIBILITY OF SUCH DAMAGE.\r
-\r
-#include "../glslang/Include/intermediate.h"\r
-\r
-namespace glslang {\r
-\r
-void GlslangToSpv(const glslang::TIntermediate& intermediate, std::vector<unsigned int>& spirv);\r
-void OutputSpv(const std::vector<unsigned int>& spirv, const char* baseName);\r
-\r
-};\r
+//
+//Copyright (C) 2014 LunarG, Inc.
+//
+//All rights reserved.
+//
+//Redistribution and use in source and binary forms, with or without
+//modification, are permitted provided that the following conditions
+//are met:
+//
+//    Redistributions of source code must retain the above copyright
+//    notice, this list of conditions and the following disclaimer.
+//
+//    Redistributions in binary form must reproduce the above
+//    copyright notice, this list of conditions and the following
+//    disclaimer in the documentation and/or other materials provided
+//    with the distribution.
+//
+//    Neither the name of 3Dlabs Inc. Ltd. nor the names of its
+//    contributors may be used to endorse or promote products derived
+//    from this software without specific prior written permission.
+//
+//THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+//"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+//LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+//FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+//COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+//INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+//BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+//LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+//CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+//LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+//ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+//POSSIBILITY OF SUCH DAMAGE.
+
+#include "../glslang/Include/intermediate.h"
+
+namespace glslang {
+
+void GlslangToSpv(const glslang::TIntermediate& intermediate, std::vector<unsigned int>& spirv);
+void OutputSpv(const std::vector<unsigned int>& spirv, const char* baseName);
+
+};
index a8b71f9..76d4772 100644 (file)
-//\r
-//Copyright (C) 2015 LunarG, Inc.\r
-//\r
-//All rights reserved.\r
-//\r
-//Redistribution and use in source and binary forms, with or without\r
-//modification, are permitted provided that the following conditions\r
-//are met:\r
-//\r
-//    Redistributions of source code must retain the above copyright\r
-//    notice, this list of conditions and the following disclaimer.\r
-//\r
-//    Redistributions in binary form must reproduce the above\r
-//    copyright notice, this list of conditions and the following\r
-//    disclaimer in the documentation and/or other materials provided\r
-//    with the distribution.\r
-//\r
-//    Neither the name of 3Dlabs Inc. Ltd. nor the names of its\r
-//    contributors may be used to endorse or promote products derived\r
-//    from this software without specific prior written permission.\r
-//\r
-//THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\r
-//"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\r
-//LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS\r
-//FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE\r
-//COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,\r
-//INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,\r
-//BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\r
-//LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER\r
-//CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\r
-//LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN\r
-//ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE\r
-//POSSIBILITY OF SUCH DAMAGE.\r
-//\r
-\r
-#include "SPVRemapper.h"\r
-#include "doc.h"\r
-\r
-#if !defined (use_cpp11)\r
-// ... not supported before C++11\r
-#else // defined (use_cpp11)\r
-\r
-#include <algorithm>\r
-#include <cassert>\r
-\r
-namespace spv {\r
-\r
-    // By default, just abort on error.  Can be overridden via RegisterErrorHandler\r
-    spirvbin_t::errorfn_t spirvbin_t::errorHandler = [](const std::string&) { exit(5); };\r
-    // By default, eat log messages.  Can be overridden via RegisterLogHandler\r
-    spirvbin_t::logfn_t   spirvbin_t::logHandler   = [](const std::string&) { };\r
-\r
-    // This can be overridden to provide other message behavior if needed\r
-    void spirvbin_t::msg(int minVerbosity, int indent, const std::string& txt) const\r
-    {\r
-        if (verbose >= minVerbosity)\r
-            logHandler(std::string(indent, ' ') + txt);\r
-    }\r
-\r
-    // hash opcode, with special handling for OpExtInst\r
-    std::uint32_t spirvbin_t::asOpCodeHash(unsigned word)\r
-    {\r
-        const spv::Op opCode = asOpCode(word);\r
-\r
-        std::uint32_t offset = 0;\r
-\r
-        switch (opCode) {\r
-        case spv::OpExtInst:\r
-            offset += asId(word + 4); break;\r
-        default:\r
-            break;\r
-        }\r
-\r
-        return opCode * 19 + offset; // 19 = small prime\r
-    }\r
-\r
-    spirvbin_t::range_t spirvbin_t::literalRange(spv::Op opCode) const\r
-    {\r
-        static const int maxCount = 1<<30;\r
-\r
-        switch (opCode) {\r
-        case spv::OpTypeFloat:        // fall through...\r
-        case spv::OpTypePointer:      return range_t(2, 3);\r
-        case spv::OpTypeInt:          return range_t(2, 4);\r
-        case spv::OpTypeSampler:      return range_t(3, 8);\r
-        case spv::OpTypeVector:       // fall through\r
-        case spv::OpTypeMatrix:       // ...\r
-        case spv::OpTypePipe:         return range_t(3, 4);\r
-        case spv::OpConstant:         return range_t(3, maxCount);\r
-        default:                      return range_t(0, 0);\r
-        }\r
-    }\r
-\r
-    spirvbin_t::range_t spirvbin_t::typeRange(spv::Op opCode) const\r
-    {\r
-        static const int maxCount = 1<<30;\r
-\r
-        if (isConstOp(opCode))\r
-            return range_t(1, 2);\r
-\r
-        switch (opCode) {\r
-        case spv::OpTypeVector:       // fall through\r
-        case spv::OpTypeMatrix:       // ... \r
-        case spv::OpTypeSampler:      // ... \r
-        case spv::OpTypeArray:        // ... \r
-        case spv::OpTypeRuntimeArray: // ... \r
-        case spv::OpTypePipe:         return range_t(2, 3);\r
-        case spv::OpTypeStruct:       // fall through\r
-        case spv::OpTypeFunction:     return range_t(2, maxCount);\r
-        case spv::OpTypePointer:      return range_t(3, 4);\r
-        default:                      return range_t(0, 0);\r
-        }\r
-    }\r
-\r
-    spirvbin_t::range_t spirvbin_t::constRange(spv::Op opCode) const\r
-    {\r
-        static const int maxCount = 1<<30;\r
-\r
-        switch (opCode) {\r
-        case spv::OpTypeArray:         // fall through...\r
-        case spv::OpTypeRuntimeArray:  return range_t(3, 4);\r
-        case spv::OpConstantComposite: return range_t(3, maxCount);\r
-        default:                       return range_t(0, 0);\r
-        }\r
-    }\r
-\r
-    // Is this an opcode we should remove when using --strip?\r
-    bool spirvbin_t::isStripOp(spv::Op opCode) const\r
-    {\r
-        switch (opCode) {\r
-        case spv::OpSource:\r
-        case spv::OpSourceExtension:\r
-        case spv::OpName:\r
-        case spv::OpMemberName:\r
-        case spv::OpLine:           return true;\r
-        default:                    return false;\r
-        }\r
-    }\r
-\r
-    bool spirvbin_t::isFlowCtrlOpen(spv::Op opCode) const\r
-    {\r
-        switch (opCode) {\r
-        case spv::OpBranchConditional:\r
-        case spv::OpSwitch:         return true;\r
-        default:                    return false;\r
-        }\r
-    }\r
-\r
-    bool spirvbin_t::isFlowCtrlClose(spv::Op opCode) const\r
-    {\r
-        switch (opCode) {\r
-        case spv::OpLoopMerge:\r
-        case spv::OpSelectionMerge: return true;\r
-        default:                    return false;\r
-        }\r
-    }\r
-\r
-    bool spirvbin_t::isTypeOp(spv::Op opCode) const\r
-    {\r
-        switch (opCode) {\r
-        case spv::OpTypeVoid:\r
-        case spv::OpTypeBool:\r
-        case spv::OpTypeInt:\r
-        case spv::OpTypeFloat:\r
-        case spv::OpTypeVector:\r
-        case spv::OpTypeMatrix:\r
-        case spv::OpTypeSampler:\r
-        case spv::OpTypeFilter:\r
-        case spv::OpTypeArray:\r
-        case spv::OpTypeRuntimeArray:\r
-        case spv::OpTypeStruct:\r
-        case spv::OpTypeOpaque:\r
-        case spv::OpTypePointer:\r
-        case spv::OpTypeFunction:\r
-        case spv::OpTypeEvent:\r
-        case spv::OpTypeDeviceEvent:\r
-        case spv::OpTypeReserveId:\r
-        case spv::OpTypeQueue:\r
-        case spv::OpTypePipe:         return true;\r
-        default:                      return false;\r
-        }\r
-    }\r
-\r
-    bool spirvbin_t::isConstOp(spv::Op opCode) const\r
-    {\r
-        switch (opCode) {\r
-        case spv::OpConstantNullObject: error("unimplemented constant type");\r
-        case spv::OpConstantSampler:    error("unimplemented constant type");\r
-\r
-        case spv::OpConstantTrue:\r
-        case spv::OpConstantFalse:\r
-        case spv::OpConstantNullPointer:\r
-        case spv::OpConstantComposite:\r
-        case spv::OpConstant:         return true;\r
-        default:                      return false;\r
-        }\r
-    }\r
-\r
-    const auto inst_fn_nop = [](spv::Op, unsigned) { return false; };\r
-    const auto op_fn_nop   = [](spv::Id&)          { };\r
-\r
-    // g++ doesn't like these defined in the class proper in an anonymous namespace.\r
-    // Dunno why.  Also MSVC doesn't like the constexpr keyword.  Also dunno why.\r
-    // Defining them externally seems to please both compilers, so, here they are.\r
-    const spv::Id spirvbin_t::unmapped    = spv::Id(-10000);\r
-    const spv::Id spirvbin_t::unused      = spv::Id(-10001);\r
-    const int     spirvbin_t::header_size = 5;\r
-\r
-    spv::Id spirvbin_t::nextUnusedId(spv::Id id)\r
-    {\r
-        while (isNewIdMapped(id))  // search for an unused ID\r
-            ++id;\r
-\r
-        return id;\r
-    }\r
-\r
-    spv::Id spirvbin_t::localId(spv::Id id, spv::Id newId)\r
-    {\r
-        assert(id != spv::NoResult && newId != spv::NoResult);\r
-\r
-        if (id >= idMapL.size())\r
-            idMapL.resize(id+1, unused);\r
-\r
-        if (newId != unmapped && newId != unused) {\r
-            if (isOldIdUnused(id))\r
-                error(std::string("ID unused in module: ") + std::to_string(id));\r
-\r
-            if (!isOldIdUnmapped(id))\r
-                error(std::string("ID already mapped: ") + std::to_string(id) + " -> "\r
-                + std::to_string(localId(id)));\r
-\r
-            if (isNewIdMapped(newId))\r
-                error(std::string("ID already used in module: ") + std::to_string(newId));\r
-\r
-            msg(4, 4, std::string("map: ") + std::to_string(id) + " -> " + std::to_string(newId));\r
-            setMapped(newId);\r
-            largestNewId = std::max(largestNewId, newId);\r
-        }\r
-\r
-        return idMapL[id] = newId;\r
-    }\r
-\r
-    // Parse a literal string from the SPIR binary and return it as an std::string\r
-    // Due to C++11 RValue references, this doesn't copy the result string.\r
-    std::string spirvbin_t::literalString(unsigned word) const\r
-    {\r
-        std::string literal;\r
-\r
-        literal.reserve(16);\r
-\r
-        const char* bytes = reinterpret_cast<const char*>(spv.data() + word);\r
-\r
-        while (bytes && *bytes)\r
-            literal += *bytes++;\r
-\r
-        return literal;\r
-    }\r
-\r
-\r
-    void spirvbin_t::applyMap()\r
-    {\r
-        msg(3, 2, std::string("Applying map: "));\r
-\r
-        // Map local IDs through the ID map\r
-        process(inst_fn_nop, // ignore instructions\r
-            [this](spv::Id& id) {\r
-                id = localId(id);\r
-                assert(id != unused && id != unmapped);\r
-            }\r
-        );\r
-    }\r
-\r
-\r
-    // Find free IDs for anything we haven't mapped\r
-    void spirvbin_t::mapRemainder()\r
-    {\r
-        msg(3, 2, std::string("Remapping remainder: "));\r
-\r
-        spv::Id     unusedId  = 1;  // can't use 0: that's NoResult\r
-        spirword_t  maxBound  = 0;\r
-\r
-        for (spv::Id id = 0; id < idMapL.size(); ++id) {\r
-            if (isOldIdUnused(id))\r
-                continue;\r
-\r
-            // Find a new mapping for any used but unmapped IDs\r
-            if (isOldIdUnmapped(id))\r
-                localId(id, unusedId = nextUnusedId(unusedId));\r
-\r
-            if (isOldIdUnmapped(id))\r
-                error(std::string("old ID not mapped: ") + std::to_string(id));\r
-\r
-            // Track max bound\r
-            maxBound = std::max(maxBound, localId(id) + 1);\r
-        }\r
-\r
-        bound(maxBound); // reset header ID bound to as big as it now needs to be\r
-    }\r
-\r
-    void spirvbin_t::stripDebug()\r
-    {\r
-        if ((options & STRIP) == 0)\r
-            return;\r
-\r
-        // build local Id and name maps\r
-        process(\r
-            [&](spv::Op opCode, unsigned start) {\r
-                // remember opcodes we want to strip later\r
-                if (isStripOp(opCode))\r
-                    stripInst(start);\r
-                return true;\r
-            },\r
-            op_fn_nop);\r
-    }\r
-\r
-    void spirvbin_t::buildLocalMaps()\r
-    {\r
-        msg(2, 2, std::string("build local maps: "));\r
-\r
-        mapped.clear();\r
-        idMapL.clear();\r
-//      preserve nameMap, so we don't clear that.\r
-        fnPos.clear();\r
-        fnPosDCE.clear();\r
-        fnCalls.clear();\r
-        typeConstPos.clear();\r
-        typeConstPosR.clear();\r
-        entryPoint = spv::NoResult;\r
-        largestNewId = 0;\r
-\r
-        idMapL.resize(bound(), unused);\r
-\r
-        int         fnStart = 0;\r
-        spv::Id     fnRes   = spv::NoResult;\r
-\r
-        // build local Id and name maps\r
-        process(\r
-            [&](spv::Op opCode, unsigned start) {\r
-                // remember opcodes we want to strip later\r
-                if ((options & STRIP) && isStripOp(opCode))\r
-                    stripInst(start);\r
-\r
-                if (opCode == spv::Op::OpName) {\r
-                    const spv::Id    target = asId(start+1);\r
-                    const std::string  name = literalString(start+2);\r
-                    nameMap[name] = target;\r
-\r
-                } else if (opCode == spv::Op::OpFunctionCall) {\r
-                    ++fnCalls[asId(start + 3)];\r
-                } else if (opCode == spv::Op::OpEntryPoint) {\r
-                    entryPoint = asId(start + 2);\r
-                } else if (opCode == spv::Op::OpFunction) {\r
-                    if (fnStart != 0)\r
-                        error("nested function found");\r
-                    fnStart = start;\r
-                    fnRes   = asId(start + 2);\r
-                } else if (opCode == spv::Op::OpFunctionEnd) {\r
-                    assert(fnRes != spv::NoResult);\r
-                    if (fnStart == 0)\r
-                        error("function end without function start");\r
-                    fnPos[fnRes] = range_t(fnStart, start + asWordCount(start));\r
-                    fnStart = 0;\r
-                } else if (isConstOp(opCode)) {\r
-                    assert(asId(start + 2) != spv::NoResult);\r
-                    typeConstPos.insert(start);\r
-                    typeConstPosR[asId(start + 2)] = start;\r
-                } else if (isTypeOp(opCode)) {\r
-                    assert(asId(start + 1) != spv::NoResult);\r
-                    typeConstPos.insert(start);\r
-                    typeConstPosR[asId(start + 1)] = start;\r
-                }\r
-\r
-                return false;\r
-            },\r
-\r
-            [this](spv::Id& id) { localId(id, unmapped); }\r
-        );\r
-    }\r
-\r
-    // Validate the SPIR header\r
-    void spirvbin_t::validate() const\r
-    {\r
-        msg(2, 2, std::string("validating: "));\r
-\r
-        if (spv.size() < header_size)\r
-            error("file too short: ");\r
-\r
-        if (magic() != spv::MagicNumber)\r
-            error("bad magic number");\r
-\r
-        // field 1 = version\r
-        // field 2 = generator magic\r
-        // field 3 = result <id> bound\r
-\r
-        if (schemaNum() != 0)\r
-            error("bad schema, must be 0");\r
-    }\r
-\r
-\r
-    int spirvbin_t::processInstruction(unsigned word, instfn_t instFn, idfn_t idFn)\r
-    {\r
-        const auto     instructionStart = word;\r
-        const unsigned wordCount = asWordCount(instructionStart);\r
-        const spv::Op  opCode    = asOpCode(instructionStart);\r
-        const int      nextInst  = word++ + wordCount;\r
-\r
-        if (nextInst > int(spv.size()))\r
-            error("spir instruction terminated too early");\r
-\r
-        // Base for computing number of operands; will be updated as more is learned\r
-        unsigned numOperands = wordCount - 1;\r
-\r
-        if (instFn(opCode, instructionStart))\r
-            return nextInst;\r
-\r
-        // Read type and result ID from instruction desc table\r
-        if (spv::InstructionDesc[opCode].hasType()) {\r
-            idFn(asId(word++));\r
-            --numOperands;\r
-        }\r
-\r
-        if (spv::InstructionDesc[opCode].hasResult()) {\r
-            idFn(asId(word++));\r
-            --numOperands;\r
-        }\r
-\r
-        // Extended instructions: currently, assume everything is an ID.\r
-        // TODO: add whatever data we need for exceptions to that\r
-        if (opCode == spv::OpExtInst) {\r
-            word        += 2; // instruction set, and instruction from set\r
-            numOperands -= 2;\r
-\r
-            for (unsigned op=0; op < numOperands; ++op)\r
-                idFn(asId(word++)); // ID\r
-\r
-            return nextInst;\r
-        }\r
-\r
-        // Store IDs from instruction in our map\r
-        for (int op = 0; op < spv::InstructionDesc[opCode].operands.getNum(); ++op, --numOperands) {\r
-            switch (spv::InstructionDesc[opCode].operands.getClass(op)) {\r
-            case spv::OperandId:\r
-                idFn(asId(word++));\r
-                break;\r
-\r
-            case spv::OperandOptionalId:\r
-            case spv::OperandVariableIds:\r
-                for (unsigned i = 0; i < numOperands; ++i)\r
-                    idFn(asId(word++));\r
-                return nextInst;\r
-\r
-            case spv::OperandVariableLiterals:\r
-                if (opCode == spv::OpDecorate && asDecoration(word - 1) == spv::DecorationBuiltIn) {\r
-                    ++word;\r
-                    --numOperands;\r
-                }\r
-                word += numOperands;\r
-                return nextInst;\r
-\r
-            case spv::OperandVariableLiteralId:\r
-                while (numOperands > 0) {\r
-                    ++word;             // immediate\r
-                    idFn(asId(word++)); // ID\r
-                    numOperands -= 2;\r
-                }\r
-                return nextInst;\r
-\r
-            case spv::OperandLiteralString:\r
-                word += literalStringWords(literalString(word));\r
-                return nextInst;\r
-\r
-                // Single word operands we simply ignore, as they hold no IDs\r
-            case spv::OperandLiteralNumber:\r
-            case spv::OperandSource:\r
-            case spv::OperandExecutionModel:\r
-            case spv::OperandAddressing:\r
-            case spv::OperandMemory:\r
-            case spv::OperandExecutionMode:\r
-            case spv::OperandStorage:\r
-            case spv::OperandDimensionality:\r
-            case spv::OperandDecoration:\r
-            case spv::OperandBuiltIn:\r
-            case spv::OperandSelect:\r
-            case spv::OperandLoop:\r
-            case spv::OperandFunction:\r
-            case spv::OperandMemorySemantics:\r
-            case spv::OperandMemoryAccess:\r
-            case spv::OperandExecutionScope:\r
-            case spv::OperandGroupOperation:\r
-            case spv::OperandKernelEnqueueFlags:\r
-            case spv::OperandKernelProfilingInfo:\r
-                ++word;\r
-                break;\r
-\r
-            default:\r
-                break;\r
-            }\r
-        }\r
-\r
-        return nextInst;\r
-    }\r
-\r
-    // Make a pass over all the instructions and process them given appropriate functions\r
-    spirvbin_t& spirvbin_t::process(instfn_t instFn, idfn_t idFn, unsigned begin, unsigned end)\r
-    {\r
-        // For efficiency, reserve name map space.  It can grow if needed.\r
-        nameMap.reserve(32);\r
-\r
-        // If begin or end == 0, use defaults\r
-        begin = (begin == 0 ? header_size          : begin);\r
-        end   = (end   == 0 ? unsigned(spv.size()) : end);\r
-\r
-        // basic parsing and InstructionDesc table borrowed from SpvDisassemble.cpp...\r
-        unsigned nextInst = unsigned(spv.size());\r
-\r
-        for (unsigned word = begin; word < end; word = nextInst)\r
-            nextInst = processInstruction(word, instFn, idFn);\r
-\r
-        return *this;\r
-    }\r
-\r
-    // Apply global name mapping to a single module\r
-    void spirvbin_t::mapNames()\r
-    {\r
-        static const std::uint32_t softTypeIdLimit = 3011;  // small prime.  TODO: get from options\r
-        static const std::uint32_t firstMappedID   = 3019;  // offset into ID space\r
-\r
-        for (const auto& name : nameMap) {\r
-            std::uint32_t hashval = 1911;\r
-            for (const char c : name.first)\r
-                hashval = hashval * 1009 + c;\r
-\r
-            if (isOldIdUnmapped(name.second))\r
-                localId(name.second, nextUnusedId(hashval % softTypeIdLimit + firstMappedID));\r
-        }\r
-    }\r
-\r
-    // Map fn contents to IDs of similar functions in other modules\r
-    void spirvbin_t::mapFnBodies()\r
-    {\r
-        static const std::uint32_t softTypeIdLimit = 19071;  // small prime.  TODO: get from options\r
-        static const std::uint32_t firstMappedID   =  6203;  // offset into ID space\r
-\r
-        // Initial approach: go through some high priority opcodes first and assign them\r
-        // hash values.\r
-\r
-        spv::Id               fnId       = spv::NoResult;\r
-        std::vector<unsigned> instPos;\r
-        instPos.reserve(unsigned(spv.size()) / 16); // initial estimate; can grow if needed.\r
-\r
-        // Build local table of instruction start positions\r
-        process(\r
-            [&](spv::Op, unsigned start) { instPos.push_back(start); return true; },\r
-            op_fn_nop);\r
-\r
-        // Window size for context-sensitive canonicalization values\r
-        // Emperical best size from a single data set.  TODO: Would be a good tunable.\r
-        // We essentially performa a little convolution around each instruction,\r
-        // to capture the flavor of nearby code, to hopefully match to similar\r
-        // code in other modules.\r
-        static const unsigned windowSize = 2;\r
-\r
-        for (unsigned entry = 0; entry < unsigned(instPos.size()); ++entry) {\r
-            const unsigned start  = instPos[entry];\r
-            const spv::Op  opCode = asOpCode(start);\r
-\r
-            if (opCode == spv::OpFunction)\r
-                fnId   = asId(start + 2);\r
-\r
-            if (opCode == spv::OpFunctionEnd)\r
-                fnId = spv::NoResult;\r
-\r
-            if (fnId != spv::NoResult) { // if inside a function\r
-                if (spv::InstructionDesc[opCode].hasResult()) {\r
-                    const unsigned word    = start + (spv::InstructionDesc[opCode].hasType() ? 2 : 1);\r
-                    const spv::Id  resId   = asId(word);\r
-                    std::uint32_t  hashval = fnId * 17; // small prime\r
-\r
-                    for (unsigned i = entry-1; i >= entry-windowSize; --i) {\r
-                        if (asOpCode(instPos[i]) == spv::OpFunction)\r
-                            break;\r
-                        hashval = hashval * 30103 + asOpCodeHash(instPos[i]); // 30103 = semiarbitrary prime\r
-                    }\r
-\r
-                    for (unsigned i = entry; i <= entry + windowSize; ++i) {\r
-                        if (asOpCode(instPos[i]) == spv::OpFunctionEnd)\r
-                            break;\r
-                        hashval = hashval * 30103 + asOpCodeHash(instPos[i]); // 30103 = semiarbitrary prime\r
-                    }\r
-\r
-                    if (isOldIdUnmapped(resId))\r
-                        localId(resId, nextUnusedId(hashval % softTypeIdLimit + firstMappedID));\r
-                }\r
-            }\r
-        }\r
-\r
-        spv::Op          thisOpCode(spv::OpNop);\r
-        std::unordered_map<int, int> opCounter;\r
-        int              idCounter(0);\r
-        fnId = spv::NoResult;\r
-\r
-        process(\r
-            [&](spv::Op opCode, unsigned start) {\r
-                switch (opCode) {\r
-                case spv::OpFunction:\r
-                    // Reset counters at each function\r
-                    idCounter = 0;\r
-                    opCounter.clear();\r
-                    fnId = asId(start + 2);\r
-                    break;\r
-\r
-                case spv::OpTextureSample:\r
-                case spv::OpTextureSampleDref:\r
-                case spv::OpTextureSampleLod:\r
-                case spv::OpTextureSampleProj:\r
-                case spv::OpTextureSampleGrad:\r
-                case spv::OpTextureSampleOffset:\r
-                case spv::OpTextureSampleProjLod:\r
-                case spv::OpTextureSampleProjGrad:\r
-                case spv::OpTextureSampleLodOffset:\r
-                case spv::OpTextureSampleProjOffset:\r
-                case spv::OpTextureSampleGradOffset:                     \r
-                case spv::OpTextureSampleProjLodOffset:\r
-                case spv::OpTextureSampleProjGradOffset:\r
-                case spv::OpDot:\r
-                case spv::OpCompositeExtract:\r
-                case spv::OpCompositeInsert:\r
-                case spv::OpVectorShuffle:\r
-                case spv::OpLabel:\r
-                case spv::OpVariable:\r
-\r
-                case spv::OpAccessChain:\r
-                case spv::OpLoad:\r
-                case spv::OpStore:\r
-                case spv::OpCompositeConstruct:\r
-                case spv::OpFunctionCall:\r
-                    ++opCounter[opCode];\r
-                    idCounter = 0;\r
-                    thisOpCode = opCode;\r
-                    break;\r
-                default:\r
-                    thisOpCode = spv::OpNop;\r
-                }\r
-\r
-                return false;\r
-            },\r
-\r
-            [&](spv::Id& id) {\r
-                if (thisOpCode != spv::OpNop) {\r
-                    ++idCounter;\r
-                    const std::uint32_t hashval = opCounter[thisOpCode] * thisOpCode * 50047 + idCounter + fnId * 117;\r
-\r
-                    if (isOldIdUnmapped(id))\r
-                        localId(id, nextUnusedId(hashval % softTypeIdLimit + firstMappedID));\r
-                }\r
-            });\r
-    }\r
-\r
-    // EXPERIMENTAL: forward IO and uniform load/stores into operands\r
-    // This produces invalid Schema-0 SPIRV\r
-    void spirvbin_t::forwardLoadStores()\r
-    {\r
-        idset_t fnLocalVars; // set of function local vars\r
-        idmap_t idMap;       // Map of load result IDs to what they load\r
-\r
-        // EXPERIMENTAL: Forward input and access chain loads into consumptions\r
-        process(\r
-            [&](spv::Op opCode, unsigned start) {\r
-                // Add inputs and uniforms to the map\r
-                if (((opCode == spv::OpVariable && asWordCount(start) == 4) || (opCode == spv::OpVariableArray)) &&\r
-                    (spv[start+3] == spv::StorageClassUniform ||\r
-                    spv[start+3] == spv::StorageClassUniformConstant ||\r
-                    spv[start+3] == spv::StorageClassInput))\r
-                    fnLocalVars.insert(asId(start+2));\r
-\r
-                if (opCode == spv::OpAccessChain && fnLocalVars.count(asId(start+3)) > 0)\r
-                    fnLocalVars.insert(asId(start+2));\r
-\r
-                if (opCode == spv::OpLoad && fnLocalVars.count(asId(start+3)) > 0) {\r
-                    idMap[asId(start+2)] = asId(start+3);\r
-                    stripInst(start);\r
-                }\r
-\r
-                return false;\r
-            },\r
-\r
-            [&](spv::Id& id) { if (idMap.find(id) != idMap.end()) id = idMap[id]; }\r
-        );\r
-\r
-        // EXPERIMENTAL: Implicit output stores\r
-        fnLocalVars.clear();\r
-        idMap.clear();\r
-\r
-        process(\r
-            [&](spv::Op opCode, unsigned start) {\r
-                // Add inputs and uniforms to the map\r
-                if (((opCode == spv::OpVariable && asWordCount(start) == 4) || (opCode == spv::OpVariableArray)) &&\r
-                    (spv[start+3] == spv::StorageClassOutput))\r
-                    fnLocalVars.insert(asId(start+2));\r
-\r
-                if (opCode == spv::OpStore && fnLocalVars.count(asId(start+1)) > 0) {\r
-                    idMap[asId(start+2)] = asId(start+1);\r
-                    stripInst(start);\r
-                }\r
-\r
-                return false;\r
-            },\r
-            op_fn_nop);\r
-\r
-        process(\r
-            inst_fn_nop,\r
-            [&](spv::Id& id) { if (idMap.find(id) != idMap.end()) id = idMap[id]; }\r
-        );\r
-\r
-        strip();          // strip out data we decided to eliminate\r
-    }\r
-\r
-    // remove bodies of uncalled functions\r
-    void spirvbin_t::optLoadStore()\r
-    {\r
-        idset_t fnLocalVars;\r
-        // Map of load result IDs to what they load\r
-        idmap_t idMap;\r
-\r
-        // Find all the function local pointers stored at most once, and not via access chains\r
-        process(\r
-            [&](spv::Op opCode, unsigned start) {\r
-                const int wordCount = asWordCount(start);\r
-\r
-                // Add local variables to the map\r
-                if ((opCode == spv::OpVariable && spv[start+3] == spv::StorageClassFunction && asWordCount(start) == 4) ||\r
-                    (opCode == spv::OpVariableArray && spv[start+3] == spv::StorageClassFunction))\r
-                    fnLocalVars.insert(asId(start+2));\r
-\r
-                // Ignore process vars referenced via access chain\r
-                if ((opCode == spv::OpAccessChain || opCode == spv::OpInBoundsAccessChain) && fnLocalVars.count(asId(start+3)) > 0) {\r
-                    fnLocalVars.erase(asId(start+3));\r
-                    idMap.erase(asId(start+3));\r
-                }\r
-\r
-                if (opCode == spv::OpLoad && fnLocalVars.count(asId(start+3)) > 0) {\r
-                    // Avoid loads before stores (TODO: why?  Crashes driver, but seems like it shouldn't).\r
-                    if (idMap.find(asId(start+3)) == idMap.end()) {\r
-                        fnLocalVars.erase(asId(start+3));\r
-                        idMap.erase(asId(start+3));\r
-                    }\r
-\r
-                    // don't do for volatile references\r
-                    if (wordCount > 4 && (spv[start+4] & spv::MemoryAccessVolatileMask)) {\r
-                        fnLocalVars.erase(asId(start+3));\r
-                        idMap.erase(asId(start+3));\r
-                    }\r
-                }\r
-\r
-                if (opCode == spv::OpStore && fnLocalVars.count(asId(start+1)) > 0) {\r
-                    if (idMap.find(asId(start+1)) == idMap.end()) {\r
-                        idMap[asId(start+1)] = asId(start+2);\r
-                    } else {\r
-                        // Remove if it has more than one store to the same pointer\r
-                        fnLocalVars.erase(asId(start+1));\r
-                        idMap.erase(asId(start+1));\r
-                    }\r
-\r
-                    // don't do for volatile references\r
-                    if (wordCount > 3 && (spv[start+3] & spv::MemoryAccessVolatileMask)) {\r
-                        fnLocalVars.erase(asId(start+3));\r
-                        idMap.erase(asId(start+3));\r
-                    }\r
-                }\r
-\r
-                return true;\r
-            },\r
-            op_fn_nop);\r
-\r
-        process(\r
-            [&](spv::Op opCode, unsigned start) {\r
-                if (opCode == spv::OpLoad && fnLocalVars.count(asId(start+3)) > 0)\r
-                    idMap[asId(start+2)] = idMap[asId(start+3)];\r
-                return false;\r
-            },\r
-            op_fn_nop);\r
-\r
-        // Remove the load/store/variables for the ones we've discovered\r
-        process(\r
-            [&](spv::Op opCode, unsigned start) {\r
-                if ((opCode == spv::OpLoad  && fnLocalVars.count(asId(start+3)) > 0) ||\r
-                    (opCode == spv::OpStore && fnLocalVars.count(asId(start+1)) > 0) ||\r
-                    (opCode == spv::OpVariable && fnLocalVars.count(asId(start+2)) > 0)) {\r
-                    stripInst(start);\r
-                    return true;\r
-                }\r
-\r
-                return false;\r
-            },\r
-\r
-            [&](spv::Id& id) { if (idMap.find(id) != idMap.end()) id = idMap[id]; }\r
-        );\r
-\r
-        strip();          // strip out data we decided to eliminate\r
-    }\r
-\r
-    // remove bodies of uncalled functions\r
-    void spirvbin_t::dceFuncs()\r
-    {\r
-        msg(3, 2, std::string("Removing Dead Functions: "));\r
-\r
-        // TODO: There are more efficient ways to do this.\r
-        bool changed = true;\r
-\r
-        while (changed) {\r
-            changed = false;\r
-\r
-            for (auto fn = fnPos.begin(); fn != fnPos.end(); ) {\r
-                if (fn->first == entryPoint) { // don't DCE away the entry point!\r
-                    ++fn;\r
-                    continue;\r
-                }\r
-\r
-                const auto call_it = fnCalls.find(fn->first);\r
-\r
-                if (call_it == fnCalls.end() || call_it->second == 0) {\r
-                    changed = true;\r
-                    stripRange.push_back(fn->second);\r
-                    fnPosDCE.insert(*fn);\r
-\r
-                    // decrease counts of called functions\r
-                    process(\r
-                        [&](spv::Op opCode, unsigned start) {\r
-                            if (opCode == spv::Op::OpFunctionCall) {\r
-                                const auto call_it = fnCalls.find(asId(start + 3));\r
-                                if (call_it != fnCalls.end()) {\r
-                                    if (--call_it->second <= 0)\r
-                                        fnCalls.erase(call_it);\r
-                                }\r
-                            }\r
-\r
-                            return true;\r
-                        },\r
-                        op_fn_nop,\r
-                        fn->second.first,\r
-                        fn->second.second);\r
-\r
-                    fn = fnPos.erase(fn);\r
-                } else ++fn;\r
-            }\r
-        }\r
-    }\r
-\r
-    // remove unused function variables + decorations\r
-    void spirvbin_t::dceVars()\r
-    {\r
-        msg(3, 2, std::string("DCE Vars: "));\r
-\r
-        std::unordered_map<spv::Id, int> varUseCount;\r
-\r
-        // Count function variable use\r
-        process(\r
-            [&](spv::Op opCode, unsigned start) {\r
-                if (opCode == spv::OpVariable) { ++varUseCount[asId(start+2)]; return true; }\r
-                return false;\r
-            },\r
-\r
-            [&](spv::Id& id) { if (varUseCount[id]) ++varUseCount[id]; }\r
-        );\r
-\r
-        // Remove single-use function variables + associated decorations and names\r
-        process(\r
-            [&](spv::Op opCode, unsigned start) {\r
-                if ((opCode == spv::OpVariable && varUseCount[asId(start+2)] == 1)  ||\r
-                    (opCode == spv::OpDecorate && varUseCount[asId(start+1)] == 1)  ||\r
-                    (opCode == spv::OpName     && varUseCount[asId(start+1)] == 1)) {\r
-                        stripInst(start);\r
-                }\r
-                return true;\r
-            },\r
-            op_fn_nop);\r
-    }\r
-\r
-    // remove unused types\r
-    void spirvbin_t::dceTypes()\r
-    {\r
-        std::vector<bool> isType(bound(), false);\r
-\r
-        // for speed, make O(1) way to get to type query (map is log(n))\r
-        for (const auto typeStart : typeConstPos)\r
-            isType[asTypeConstId(typeStart)] = true;\r
-\r
-        std::unordered_map<spv::Id, int> typeUseCount;\r
-\r
-        // Count total type usage\r
-        process(inst_fn_nop,\r
-            [&](spv::Id& id) { if (isType[id]) ++typeUseCount[id]; }\r
-        );\r
-\r
-        // Remove types from deleted code\r
-        for (const auto& fn : fnPosDCE)\r
-            process(inst_fn_nop,\r
-            [&](spv::Id& id) { if (isType[id]) --typeUseCount[id]; },\r
-            fn.second.first, fn.second.second);\r
-\r
-        // Remove single reference types\r
-        for (const auto typeStart : typeConstPos) {\r
-            const spv::Id typeId = asTypeConstId(typeStart);\r
-            if (typeUseCount[typeId] == 1) {\r
-                --typeUseCount[typeId];\r
-                stripInst(typeStart);\r
-            }\r
-        }\r
-    }\r
-\r
-\r
-#ifdef NOTDEF\r
-    bool spirvbin_t::matchType(const spirvbin_t::globaltypes_t& globalTypes, spv::Id lt, spv::Id gt) const\r
-    {\r
-        // Find the local type id "lt" and global type id "gt"\r
-        const auto lt_it = typeConstPosR.find(lt);\r
-        if (lt_it == typeConstPosR.end())\r
-            return false;\r
-\r
-        const auto typeStart = lt_it->second;\r
-\r
-        // Search for entry in global table\r
-        const auto gtype = globalTypes.find(gt);\r
-        if (gtype == globalTypes.end())\r
-            return false;\r
-\r
-        const auto& gdata = gtype->second;\r
-\r
-        // local wordcount and opcode\r
-        const int     wordCount   = asWordCount(typeStart);\r
-        const spv::Op opCode      = asOpCode(typeStart);\r
-\r
-        // no type match if opcodes don't match, or operand count doesn't match\r
-        if (opCode != opOpCode(gdata[0]) || wordCount != opWordCount(gdata[0]))\r
-            return false;\r
-\r
-        const unsigned numOperands = wordCount - 2; // all types have a result\r
-\r
-        const auto cmpIdRange = [&](range_t range) {\r
-            for (int x=range.first; x<std::min(range.second, wordCount); ++x)\r
-                if (!matchType(globalTypes, asId(typeStart+x), gdata[x]))\r
-                    return false;\r
-            return true;\r
-        };\r
-\r
-        const auto cmpConst   = [&]() { return cmpIdRange(constRange(opCode)); };\r
-        const auto cmpSubType = [&]() { return cmpIdRange(typeRange(opCode));  };\r
-\r
-        // Compare literals in range [start,end)\r
-        const auto cmpLiteral = [&]() {\r
-            const auto range = literalRange(opCode);\r
-            return std::equal(spir.begin() + typeStart + range.first,\r
-                spir.begin() + typeStart + std::min(range.second, wordCount),\r
-                gdata.begin() + range.first);\r
-        };\r
-\r
-        assert(isTypeOp(opCode) || isConstOp(opCode));\r
-\r
-        switch (opCode) {\r
-        case spv::OpTypeOpaque:       // TODO: disable until we compare the literal strings.\r
-        case spv::OpTypeQueue:        return false;\r
-        case spv::OpTypeEvent:        // fall through...\r
-        case spv::OpTypeDeviceEvent:  // ...\r
-        case spv::OpTypeReserveId:    return false;\r
-            // for samplers, we don't handle the optional parameters yet\r
-        case spv::OpTypeSampler:      return cmpLiteral() && cmpConst() && cmpSubType() && wordCount == 8;\r
-        default:                      return cmpLiteral() && cmpConst() && cmpSubType();\r
-        }\r
-    }\r
-\r
-\r
-    // Look for an equivalent type in the globalTypes map\r
-    spv::Id spirvbin_t::findType(const spirvbin_t::globaltypes_t& globalTypes, spv::Id lt) const\r
-    {\r
-        // Try a recursive type match on each in turn, and return a match if we find one\r
-        for (const auto& gt : globalTypes)\r
-            if (matchType(globalTypes, lt, gt.first))\r
-                return gt.first;\r
-\r
-        return spv::NoType;\r
-    }\r
-#endif // NOTDEF\r
-\r
-    // Return start position in SPV of given type.  error if not found.\r
-    unsigned spirvbin_t::typePos(spv::Id id) const\r
-    {\r
-        const auto tid_it = typeConstPosR.find(id);\r
-        if (tid_it == typeConstPosR.end())\r
-            error("type ID not found");\r
-\r
-        return tid_it->second;\r
-    }\r
-\r
-    // Hash types to canonical values.  This can return ID collisions (it's a bit\r
-    // inevitable): it's up to the caller to handle that gracefully.\r
-    std::uint32_t spirvbin_t::hashType(unsigned typeStart) const\r
-    {\r
-        const unsigned wordCount   = asWordCount(typeStart);\r
-        const spv::Op  opCode      = asOpCode(typeStart);\r
-\r
-        switch (opCode) {\r
-        case spv::OpTypeVoid:         return 0;\r
-        case spv::OpTypeBool:         return 1;\r
-        case spv::OpTypeInt:          return 3 + (spv[typeStart+3]);\r
-        case spv::OpTypeFloat:        return 5;\r
-        case spv::OpTypeVector:\r
-            return 6 + hashType(typePos(spv[typeStart+2])) * (spv[typeStart+3] - 1);\r
-        case spv::OpTypeMatrix:\r
-            return 30 + hashType(typePos(spv[typeStart+2])) * (spv[typeStart+3] - 1);\r
-        case spv::OpTypeSampler:\r
-            return 120 + hashType(typePos(spv[typeStart+2])) +\r
-                spv[typeStart+3] +            // dimensionality\r
-                spv[typeStart+4] * 8 * 16 +   // content\r
-                spv[typeStart+5] * 4 * 16 +   // arrayed\r
-                spv[typeStart+6] * 2 * 16 +   // compare\r
-                spv[typeStart+7] * 1 * 16;    // multisampled\r
-        case spv::OpTypeFilter:\r
-            return 500;\r
-        case spv::OpTypeArray:\r
-            return 501 + hashType(typePos(spv[typeStart+2])) * spv[typeStart+3];\r
-        case spv::OpTypeRuntimeArray:\r
-            return 5000  + hashType(typePos(spv[typeStart+2]));\r
-        case spv::OpTypeStruct:\r
-            {\r
-                std::uint32_t hash = 10000;\r
-                for (unsigned w=2; w < wordCount; ++w)\r
-                    hash += w * hashType(typePos(spv[typeStart+w]));\r
-                return hash;\r
-            }\r
-\r
-        case spv::OpTypeOpaque:         return 6000 + spv[typeStart+2];\r
-        case spv::OpTypePointer:        return 100000  + hashType(typePos(spv[typeStart+3]));\r
-        case spv::OpTypeFunction:\r
-            {\r
-                std::uint32_t hash = 200000;\r
-                for (unsigned w=2; w < wordCount; ++w)\r
-                    hash += w * hashType(typePos(spv[typeStart+w]));\r
-                return hash;\r
-            }\r
-\r
-        case spv::OpTypeEvent:           return 300000;\r
-        case spv::OpTypeDeviceEvent:     return 300001;\r
-        case spv::OpTypeReserveId:       return 300002;\r
-        case spv::OpTypeQueue:           return 300003;\r
-        case spv::OpTypePipe:            return 300004;\r
-\r
-        case spv::OpConstantNullObject:  return 300005;\r
-        case spv::OpConstantSampler:     return 300006;\r
-\r
-        case spv::OpConstantTrue:        return 300007;\r
-        case spv::OpConstantFalse:       return 300008;\r
-        case spv::OpConstantNullPointer: return 300009;\r
-        case spv::OpConstantComposite:\r
-            {\r
-                std::uint32_t hash = 300011 + hashType(typePos(spv[typeStart+1]));\r
-                for (unsigned w=3; w < wordCount; ++w)\r
-                    hash += w * hashType(typePos(spv[typeStart+w]));\r
-                return hash;\r
-            }\r
-        case spv::OpConstant:\r
-            {\r
-                std::uint32_t hash = 400011 + hashType(typePos(spv[typeStart+1]));\r
-                for (unsigned w=3; w < wordCount; ++w)\r
-                    hash += w * spv[typeStart+w];\r
-                return hash;\r
-            }\r
-\r
-        default:\r
-            error("unknown type opcode");\r
-            return 0;\r
-        }\r
-    }\r
-\r
-    void spirvbin_t::mapTypeConst()\r
-    {\r
-        globaltypes_t globalTypeMap;\r
-\r
-        msg(3, 2, std::string("Remapping Consts & Types: "));\r
-\r
-        static const std::uint32_t softTypeIdLimit = 3011; // small prime.  TODO: get from options\r
-        static const std::uint32_t firstMappedID   = 8;    // offset into ID space\r
-\r
-        for (auto& typeStart : typeConstPos) {\r
-            const spv::Id       resId     = asTypeConstId(typeStart);\r
-            const std::uint32_t hashval   = hashType(typeStart);\r
-\r
-            if (isOldIdUnmapped(resId))\r
-                localId(resId, nextUnusedId(hashval % softTypeIdLimit + firstMappedID));\r
-        }\r
-    }\r
-\r
-\r
-    // Strip a single binary by removing ranges given in stripRange\r
-    void spirvbin_t::strip()\r
-    {\r
-        if (stripRange.empty()) // nothing to do\r
-            return;\r
-\r
-        // Sort strip ranges in order of traversal\r
-        std::sort(stripRange.begin(), stripRange.end());\r
-\r
-        // Allocate a new binary big enough to hold old binary\r
-        // We'll step this iterator through the strip ranges as we go through the binary\r
-        auto strip_it = stripRange.begin();\r
-\r
-        int strippedPos = 0;\r
-        for (unsigned word = 0; word < unsigned(spv.size()); ++word) {\r
-            if (strip_it != stripRange.end() && word >= strip_it->second)\r
-                ++strip_it;\r
-\r
-            if (strip_it == stripRange.end() || word < strip_it->first || word >= strip_it->second)\r
-                spv[strippedPos++] = spv[word];\r
-        }\r
-\r
-        spv.resize(strippedPos);\r
-        stripRange.clear();\r
-\r
-        buildLocalMaps();\r
-    }\r
-\r
-    // Strip a single binary by removing ranges given in stripRange\r
-    void spirvbin_t::remap(std::uint32_t opts)\r
-    {\r
-        options = opts;\r
-\r
-        // Set up opcode tables from SpvDoc\r
-        spv::Parameterize();\r
-\r
-        validate();  // validate header\r
-        buildLocalMaps();\r
-\r
-        msg(3, 4, std::string("ID bound: ") + std::to_string(bound()));\r
-\r
-        strip();        // strip out data we decided to eliminate\r
-\r
-        if (options & OPT_LOADSTORE) optLoadStore();\r
-        if (options & OPT_FWD_LS)    forwardLoadStores();\r
-        if (options & DCE_FUNCS)     dceFuncs();\r
-        if (options & DCE_VARS)      dceVars();\r
-        if (options & DCE_TYPES)     dceTypes();\r
-        if (options & MAP_TYPES)     mapTypeConst();\r
-        if (options & MAP_NAMES)     mapNames();\r
-        if (options & MAP_FUNCS)     mapFnBodies();\r
-\r
-        mapRemainder(); // map any unmapped IDs\r
-        applyMap();     // Now remap each shader to the new IDs we've come up with\r
-        strip();        // strip out data we decided to eliminate\r
-    }\r
-\r
-    // remap from a memory image\r
-    void spirvbin_t::remap(std::vector<std::uint32_t>& in_spv, std::uint32_t opts)\r
-    {\r
-        spv.swap(in_spv);\r
-        remap(opts);\r
-        spv.swap(in_spv);\r
-    }\r
-\r
-} // namespace SPV\r
-\r
-#endif // defined (use_cpp11)\r
-\r
+//
+//Copyright (C) 2015 LunarG, Inc.
+//
+//All rights reserved.
+//
+//Redistribution and use in source and binary forms, with or without
+//modification, are permitted provided that the following conditions
+//are met:
+//
+//    Redistributions of source code must retain the above copyright
+//    notice, this list of conditions and the following disclaimer.
+//
+//    Redistributions in binary form must reproduce the above
+//    copyright notice, this list of conditions and the following
+//    disclaimer in the documentation and/or other materials provided
+//    with the distribution.
+//
+//    Neither the name of 3Dlabs Inc. Ltd. nor the names of its
+//    contributors may be used to endorse or promote products derived
+//    from this software without specific prior written permission.
+//
+//THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+//"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+//LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+//FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+//COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+//INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+//BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+//LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+//CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+//LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+//ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+//POSSIBILITY OF SUCH DAMAGE.
+//
+
+#include "SPVRemapper.h"
+#include "doc.h"
+
+#if !defined (use_cpp11)
+// ... not supported before C++11
+#else // defined (use_cpp11)
+
+#include <algorithm>
+#include <cassert>
+
+namespace spv {
+
+    // By default, just abort on error.  Can be overridden via RegisterErrorHandler
+    spirvbin_t::errorfn_t spirvbin_t::errorHandler = [](const std::string&) { exit(5); };
+    // By default, eat log messages.  Can be overridden via RegisterLogHandler
+    spirvbin_t::logfn_t   spirvbin_t::logHandler   = [](const std::string&) { };
+
+    // This can be overridden to provide other message behavior if needed
+    void spirvbin_t::msg(int minVerbosity, int indent, const std::string& txt) const
+    {
+        if (verbose >= minVerbosity)
+            logHandler(std::string(indent, ' ') + txt);
+    }
+
+    // hash opcode, with special handling for OpExtInst
+    std::uint32_t spirvbin_t::asOpCodeHash(unsigned word)
+    {
+        const spv::Op opCode = asOpCode(word);
+
+        std::uint32_t offset = 0;
+
+        switch (opCode) {
+        case spv::OpExtInst:
+            offset += asId(word + 4); break;
+        default:
+            break;
+        }
+
+        return opCode * 19 + offset; // 19 = small prime
+    }
+
+    spirvbin_t::range_t spirvbin_t::literalRange(spv::Op opCode) const
+    {
+        static const int maxCount = 1<<30;
+
+        switch (opCode) {
+        case spv::OpTypeFloat:        // fall through...
+        case spv::OpTypePointer:      return range_t(2, 3);
+        case spv::OpTypeInt:          return range_t(2, 4);
+        case spv::OpTypeSampler:      return range_t(3, 8);
+        case spv::OpTypeVector:       // fall through
+        case spv::OpTypeMatrix:       // ...
+        case spv::OpTypePipe:         return range_t(3, 4);
+        case spv::OpConstant:         return range_t(3, maxCount);
+        default:                      return range_t(0, 0);
+        }
+    }
+
+    spirvbin_t::range_t spirvbin_t::typeRange(spv::Op opCode) const
+    {
+        static const int maxCount = 1<<30;
+
+        if (isConstOp(opCode))
+            return range_t(1, 2);
+
+        switch (opCode) {
+        case spv::OpTypeVector:       // fall through
+        case spv::OpTypeMatrix:       // ... 
+        case spv::OpTypeSampler:      // ... 
+        case spv::OpTypeArray:        // ... 
+        case spv::OpTypeRuntimeArray: // ... 
+        case spv::OpTypePipe:         return range_t(2, 3);
+        case spv::OpTypeStruct:       // fall through
+        case spv::OpTypeFunction:     return range_t(2, maxCount);
+        case spv::OpTypePointer:      return range_t(3, 4);
+        default:                      return range_t(0, 0);
+        }
+    }
+
+    spirvbin_t::range_t spirvbin_t::constRange(spv::Op opCode) const
+    {
+        static const int maxCount = 1<<30;
+
+        switch (opCode) {
+        case spv::OpTypeArray:         // fall through...
+        case spv::OpTypeRuntimeArray:  return range_t(3, 4);
+        case spv::OpConstantComposite: return range_t(3, maxCount);
+        default:                       return range_t(0, 0);
+        }
+    }
+
+    // Is this an opcode we should remove when using --strip?
+    bool spirvbin_t::isStripOp(spv::Op opCode) const
+    {
+        switch (opCode) {
+        case spv::OpSource:
+        case spv::OpSourceExtension:
+        case spv::OpName:
+        case spv::OpMemberName:
+        case spv::OpLine:           return true;
+        default:                    return false;
+        }
+    }
+
+    bool spirvbin_t::isFlowCtrlOpen(spv::Op opCode) const
+    {
+        switch (opCode) {
+        case spv::OpBranchConditional:
+        case spv::OpSwitch:         return true;
+        default:                    return false;
+        }
+    }
+
+    bool spirvbin_t::isFlowCtrlClose(spv::Op opCode) const
+    {
+        switch (opCode) {
+        case spv::OpLoopMerge:
+        case spv::OpSelectionMerge: return true;
+        default:                    return false;
+        }
+    }
+
+    bool spirvbin_t::isTypeOp(spv::Op opCode) const
+    {
+        switch (opCode) {
+        case spv::OpTypeVoid:
+        case spv::OpTypeBool:
+        case spv::OpTypeInt:
+        case spv::OpTypeFloat:
+        case spv::OpTypeVector:
+        case spv::OpTypeMatrix:
+        case spv::OpTypeSampler:
+        case spv::OpTypeFilter:
+        case spv::OpTypeArray:
+        case spv::OpTypeRuntimeArray:
+        case spv::OpTypeStruct:
+        case spv::OpTypeOpaque:
+        case spv::OpTypePointer:
+        case spv::OpTypeFunction:
+        case spv::OpTypeEvent:
+        case spv::OpTypeDeviceEvent:
+        case spv::OpTypeReserveId:
+        case spv::OpTypeQueue:
+        case spv::OpTypePipe:         return true;
+        default:                      return false;
+        }
+    }
+
+    bool spirvbin_t::isConstOp(spv::Op opCode) const
+    {
+        switch (opCode) {
+        case spv::OpConstantNullObject: error("unimplemented constant type");
+        case spv::OpConstantSampler:    error("unimplemented constant type");
+
+        case spv::OpConstantTrue:
+        case spv::OpConstantFalse:
+        case spv::OpConstantNullPointer:
+        case spv::OpConstantComposite:
+        case spv::OpConstant:         return true;
+        default:                      return false;
+        }
+    }
+
+    const auto inst_fn_nop = [](spv::Op, unsigned) { return false; };
+    const auto op_fn_nop   = [](spv::Id&)          { };
+
+    // g++ doesn't like these defined in the class proper in an anonymous namespace.
+    // Dunno why.  Also MSVC doesn't like the constexpr keyword.  Also dunno why.
+    // Defining them externally seems to please both compilers, so, here they are.
+    const spv::Id spirvbin_t::unmapped    = spv::Id(-10000);
+    const spv::Id spirvbin_t::unused      = spv::Id(-10001);
+    const int     spirvbin_t::header_size = 5;
+
+    spv::Id spirvbin_t::nextUnusedId(spv::Id id)
+    {
+        while (isNewIdMapped(id))  // search for an unused ID
+            ++id;
+
+        return id;
+    }
+
+    spv::Id spirvbin_t::localId(spv::Id id, spv::Id newId)
+    {
+        assert(id != spv::NoResult && newId != spv::NoResult);
+
+        if (id >= idMapL.size())
+            idMapL.resize(id+1, unused);
+
+        if (newId != unmapped && newId != unused) {
+            if (isOldIdUnused(id))
+                error(std::string("ID unused in module: ") + std::to_string(id));
+
+            if (!isOldIdUnmapped(id))
+                error(std::string("ID already mapped: ") + std::to_string(id) + " -> "
+                + std::to_string(localId(id)));
+
+            if (isNewIdMapped(newId))
+                error(std::string("ID already used in module: ") + std::to_string(newId));
+
+            msg(4, 4, std::string("map: ") + std::to_string(id) + " -> " + std::to_string(newId));
+            setMapped(newId);
+            largestNewId = std::max(largestNewId, newId);
+        }
+
+        return idMapL[id] = newId;
+    }
+
+    // Parse a literal string from the SPIR binary and return it as an std::string
+    // Due to C++11 RValue references, this doesn't copy the result string.
+    std::string spirvbin_t::literalString(unsigned word) const
+    {
+        std::string literal;
+
+        literal.reserve(16);
+
+        const char* bytes = reinterpret_cast<const char*>(spv.data() + word);
+
+        while (bytes && *bytes)
+            literal += *bytes++;
+
+        return literal;
+    }
+
+
+    void spirvbin_t::applyMap()
+    {
+        msg(3, 2, std::string("Applying map: "));
+
+        // Map local IDs through the ID map
+        process(inst_fn_nop, // ignore instructions
+            [this](spv::Id& id) {
+                id = localId(id);
+                assert(id != unused && id != unmapped);
+            }
+        );
+    }
+
+
+    // Find free IDs for anything we haven't mapped
+    void spirvbin_t::mapRemainder()
+    {
+        msg(3, 2, std::string("Remapping remainder: "));
+
+        spv::Id     unusedId  = 1;  // can't use 0: that's NoResult
+        spirword_t  maxBound  = 0;
+
+        for (spv::Id id = 0; id < idMapL.size(); ++id) {
+            if (isOldIdUnused(id))
+                continue;
+
+            // Find a new mapping for any used but unmapped IDs
+            if (isOldIdUnmapped(id))
+                localId(id, unusedId = nextUnusedId(unusedId));
+
+            if (isOldIdUnmapped(id))
+                error(std::string("old ID not mapped: ") + std::to_string(id));
+
+            // Track max bound
+            maxBound = std::max(maxBound, localId(id) + 1);
+        }
+
+        bound(maxBound); // reset header ID bound to as big as it now needs to be
+    }
+
+    void spirvbin_t::stripDebug()
+    {
+        if ((options & STRIP) == 0)
+            return;
+
+        // build local Id and name maps
+        process(
+            [&](spv::Op opCode, unsigned start) {
+                // remember opcodes we want to strip later
+                if (isStripOp(opCode))
+                    stripInst(start);
+                return true;
+            },
+            op_fn_nop);
+    }
+
+    void spirvbin_t::buildLocalMaps()
+    {
+        msg(2, 2, std::string("build local maps: "));
+
+        mapped.clear();
+        idMapL.clear();
+//      preserve nameMap, so we don't clear that.
+        fnPos.clear();
+        fnPosDCE.clear();
+        fnCalls.clear();
+        typeConstPos.clear();
+        typeConstPosR.clear();
+        entryPoint = spv::NoResult;
+        largestNewId = 0;
+
+        idMapL.resize(bound(), unused);
+
+        int         fnStart = 0;
+        spv::Id     fnRes   = spv::NoResult;
+
+        // build local Id and name maps
+        process(
+            [&](spv::Op opCode, unsigned start) {
+                // remember opcodes we want to strip later
+                if ((options & STRIP) && isStripOp(opCode))
+                    stripInst(start);
+
+                if (opCode == spv::Op::OpName) {
+                    const spv::Id    target = asId(start+1);
+                    const std::string  name = literalString(start+2);
+                    nameMap[name] = target;
+
+                } else if (opCode == spv::Op::OpFunctionCall) {
+                    ++fnCalls[asId(start + 3)];
+                } else if (opCode == spv::Op::OpEntryPoint) {
+                    entryPoint = asId(start + 2);
+                } else if (opCode == spv::Op::OpFunction) {
+                    if (fnStart != 0)
+                        error("nested function found");
+                    fnStart = start;
+                    fnRes   = asId(start + 2);
+                } else if (opCode == spv::Op::OpFunctionEnd) {
+                    assert(fnRes != spv::NoResult);
+                    if (fnStart == 0)
+                        error("function end without function start");
+                    fnPos[fnRes] = range_t(fnStart, start + asWordCount(start));
+                    fnStart = 0;
+                } else if (isConstOp(opCode)) {
+                    assert(asId(start + 2) != spv::NoResult);
+                    typeConstPos.insert(start);
+                    typeConstPosR[asId(start + 2)] = start;
+                } else if (isTypeOp(opCode)) {
+                    assert(asId(start + 1) != spv::NoResult);
+                    typeConstPos.insert(start);
+                    typeConstPosR[asId(start + 1)] = start;
+                }
+
+                return false;
+            },
+
+            [this](spv::Id& id) { localId(id, unmapped); }
+        );
+    }
+
+    // Validate the SPIR header
+    void spirvbin_t::validate() const
+    {
+        msg(2, 2, std::string("validating: "));
+
+        if (spv.size() < header_size)
+            error("file too short: ");
+
+        if (magic() != spv::MagicNumber)
+            error("bad magic number");
+
+        // field 1 = version
+        // field 2 = generator magic
+        // field 3 = result <id> bound
+
+        if (schemaNum() != 0)
+            error("bad schema, must be 0");
+    }
+
+
+    int spirvbin_t::processInstruction(unsigned word, instfn_t instFn, idfn_t idFn)
+    {
+        const auto     instructionStart = word;
+        const unsigned wordCount = asWordCount(instructionStart);
+        const spv::Op  opCode    = asOpCode(instructionStart);
+        const int      nextInst  = word++ + wordCount;
+
+        if (nextInst > int(spv.size()))
+            error("spir instruction terminated too early");
+
+        // Base for computing number of operands; will be updated as more is learned
+        unsigned numOperands = wordCount - 1;
+
+        if (instFn(opCode, instructionStart))
+            return nextInst;
+
+        // Read type and result ID from instruction desc table
+        if (spv::InstructionDesc[opCode].hasType()) {
+            idFn(asId(word++));
+            --numOperands;
+        }
+
+        if (spv::InstructionDesc[opCode].hasResult()) {
+            idFn(asId(word++));
+            --numOperands;
+        }
+
+        // Extended instructions: currently, assume everything is an ID.
+        // TODO: add whatever data we need for exceptions to that
+        if (opCode == spv::OpExtInst) {
+            word        += 2; // instruction set, and instruction from set
+            numOperands -= 2;
+
+            for (unsigned op=0; op < numOperands; ++op)
+                idFn(asId(word++)); // ID
+
+            return nextInst;
+        }
+
+        // Store IDs from instruction in our map
+        for (int op = 0; op < spv::InstructionDesc[opCode].operands.getNum(); ++op, --numOperands) {
+            switch (spv::InstructionDesc[opCode].operands.getClass(op)) {
+            case spv::OperandId:
+                idFn(asId(word++));
+                break;
+
+            case spv::OperandOptionalId:
+            case spv::OperandVariableIds:
+                for (unsigned i = 0; i < numOperands; ++i)
+                    idFn(asId(word++));
+                return nextInst;
+
+            case spv::OperandVariableLiterals:
+                if (opCode == spv::OpDecorate && asDecoration(word - 1) == spv::DecorationBuiltIn) {
+                    ++word;
+                    --numOperands;
+                }
+                word += numOperands;
+                return nextInst;
+
+            case spv::OperandVariableLiteralId:
+                while (numOperands > 0) {
+                    ++word;             // immediate
+                    idFn(asId(word++)); // ID
+                    numOperands -= 2;
+                }
+                return nextInst;
+
+            case spv::OperandLiteralString:
+                word += literalStringWords(literalString(word));
+                return nextInst;
+
+                // Single word operands we simply ignore, as they hold no IDs
+            case spv::OperandLiteralNumber:
+            case spv::OperandSource:
+            case spv::OperandExecutionModel:
+            case spv::OperandAddressing:
+            case spv::OperandMemory:
+            case spv::OperandExecutionMode:
+            case spv::OperandStorage:
+            case spv::OperandDimensionality:
+            case spv::OperandDecoration:
+            case spv::OperandBuiltIn:
+            case spv::OperandSelect:
+            case spv::OperandLoop:
+            case spv::OperandFunction:
+            case spv::OperandMemorySemantics:
+            case spv::OperandMemoryAccess:
+            case spv::OperandExecutionScope:
+            case spv::OperandGroupOperation:
+            case spv::OperandKernelEnqueueFlags:
+            case spv::OperandKernelProfilingInfo:
+                ++word;
+                break;
+
+            default:
+                break;
+            }
+        }
+
+        return nextInst;
+    }
+
+    // Make a pass over all the instructions and process them given appropriate functions
+    spirvbin_t& spirvbin_t::process(instfn_t instFn, idfn_t idFn, unsigned begin, unsigned end)
+    {
+        // For efficiency, reserve name map space.  It can grow if needed.
+        nameMap.reserve(32);
+
+        // If begin or end == 0, use defaults
+        begin = (begin == 0 ? header_size          : begin);
+        end   = (end   == 0 ? unsigned(spv.size()) : end);
+
+        // basic parsing and InstructionDesc table borrowed from SpvDisassemble.cpp...
+        unsigned nextInst = unsigned(spv.size());
+
+        for (unsigned word = begin; word < end; word = nextInst)
+            nextInst = processInstruction(word, instFn, idFn);
+
+        return *this;
+    }
+
+    // Apply global name mapping to a single module
+    void spirvbin_t::mapNames()
+    {
+        static const std::uint32_t softTypeIdLimit = 3011;  // small prime.  TODO: get from options
+        static const std::uint32_t firstMappedID   = 3019;  // offset into ID space
+
+        for (const auto& name : nameMap) {
+            std::uint32_t hashval = 1911;
+            for (const char c : name.first)
+                hashval = hashval * 1009 + c;
+
+            if (isOldIdUnmapped(name.second))
+                localId(name.second, nextUnusedId(hashval % softTypeIdLimit + firstMappedID));
+        }
+    }
+
+    // Map fn contents to IDs of similar functions in other modules
+    void spirvbin_t::mapFnBodies()
+    {
+        static const std::uint32_t softTypeIdLimit = 19071;  // small prime.  TODO: get from options
+        static const std::uint32_t firstMappedID   =  6203;  // offset into ID space
+
+        // Initial approach: go through some high priority opcodes first and assign them
+        // hash values.
+
+        spv::Id               fnId       = spv::NoResult;
+        std::vector<unsigned> instPos;
+        instPos.reserve(unsigned(spv.size()) / 16); // initial estimate; can grow if needed.
+
+        // Build local table of instruction start positions
+        process(
+            [&](spv::Op, unsigned start) { instPos.push_back(start); return true; },
+            op_fn_nop);
+
+        // Window size for context-sensitive canonicalization values
+        // Emperical best size from a single data set.  TODO: Would be a good tunable.
+        // We essentially performa a little convolution around each instruction,
+        // to capture the flavor of nearby code, to hopefully match to similar
+        // code in other modules.
+        static const unsigned windowSize = 2;
+
+        for (unsigned entry = 0; entry < unsigned(instPos.size()); ++entry) {
+            const unsigned start  = instPos[entry];
+            const spv::Op  opCode = asOpCode(start);
+
+            if (opCode == spv::OpFunction)
+                fnId   = asId(start + 2);
+
+            if (opCode == spv::OpFunctionEnd)
+                fnId = spv::NoResult;
+
+            if (fnId != spv::NoResult) { // if inside a function
+                if (spv::InstructionDesc[opCode].hasResult()) {
+                    const unsigned word    = start + (spv::InstructionDesc[opCode].hasType() ? 2 : 1);
+                    const spv::Id  resId   = asId(word);
+                    std::uint32_t  hashval = fnId * 17; // small prime
+
+                    for (unsigned i = entry-1; i >= entry-windowSize; --i) {
+                        if (asOpCode(instPos[i]) == spv::OpFunction)
+                            break;
+                        hashval = hashval * 30103 + asOpCodeHash(instPos[i]); // 30103 = semiarbitrary prime
+                    }
+
+                    for (unsigned i = entry; i <= entry + windowSize; ++i) {
+                        if (asOpCode(instPos[i]) == spv::OpFunctionEnd)
+                            break;
+                        hashval = hashval * 30103 + asOpCodeHash(instPos[i]); // 30103 = semiarbitrary prime
+                    }
+
+                    if (isOldIdUnmapped(resId))
+                        localId(resId, nextUnusedId(hashval % softTypeIdLimit + firstMappedID));
+                }
+            }
+        }
+
+        spv::Op          thisOpCode(spv::OpNop);
+        std::unordered_map<int, int> opCounter;
+        int              idCounter(0);
+        fnId = spv::NoResult;
+
+        process(
+            [&](spv::Op opCode, unsigned start) {
+                switch (opCode) {
+                case spv::OpFunction:
+                    // Reset counters at each function
+                    idCounter = 0;
+                    opCounter.clear();
+                    fnId = asId(start + 2);
+                    break;
+
+                case spv::OpTextureSample:
+                case spv::OpTextureSampleDref:
+                case spv::OpTextureSampleLod:
+                case spv::OpTextureSampleProj:
+                case spv::OpTextureSampleGrad:
+                case spv::OpTextureSampleOffset:
+                case spv::OpTextureSampleProjLod:
+                case spv::OpTextureSampleProjGrad:
+                case spv::OpTextureSampleLodOffset:
+                case spv::OpTextureSampleProjOffset:
+                case spv::OpTextureSampleGradOffset:                     
+                case spv::OpTextureSampleProjLodOffset:
+                case spv::OpTextureSampleProjGradOffset:
+                case spv::OpDot:
+                case spv::OpCompositeExtract:
+                case spv::OpCompositeInsert:
+                case spv::OpVectorShuffle:
+                case spv::OpLabel:
+                case spv::OpVariable:
+
+                case spv::OpAccessChain:
+                case spv::OpLoad:
+                case spv::OpStore:
+                case spv::OpCompositeConstruct:
+                case spv::OpFunctionCall:
+                    ++opCounter[opCode];
+                    idCounter = 0;
+                    thisOpCode = opCode;
+                    break;
+                default:
+                    thisOpCode = spv::OpNop;
+                }
+
+                return false;
+            },
+
+            [&](spv::Id& id) {
+                if (thisOpCode != spv::OpNop) {
+                    ++idCounter;
+                    const std::uint32_t hashval = opCounter[thisOpCode] * thisOpCode * 50047 + idCounter + fnId * 117;
+
+                    if (isOldIdUnmapped(id))
+                        localId(id, nextUnusedId(hashval % softTypeIdLimit + firstMappedID));
+                }
+            });
+    }
+
+    // EXPERIMENTAL: forward IO and uniform load/stores into operands
+    // This produces invalid Schema-0 SPIRV
+    void spirvbin_t::forwardLoadStores()
+    {
+        idset_t fnLocalVars; // set of function local vars
+        idmap_t idMap;       // Map of load result IDs to what they load
+
+        // EXPERIMENTAL: Forward input and access chain loads into consumptions
+        process(
+            [&](spv::Op opCode, unsigned start) {
+                // Add inputs and uniforms to the map
+                if (((opCode == spv::OpVariable && asWordCount(start) == 4) || (opCode == spv::OpVariableArray)) &&
+                    (spv[start+3] == spv::StorageClassUniform ||
+                    spv[start+3] == spv::StorageClassUniformConstant ||
+                    spv[start+3] == spv::StorageClassInput))
+                    fnLocalVars.insert(asId(start+2));
+
+                if (opCode == spv::OpAccessChain && fnLocalVars.count(asId(start+3)) > 0)
+                    fnLocalVars.insert(asId(start+2));
+
+                if (opCode == spv::OpLoad && fnLocalVars.count(asId(start+3)) > 0) {
+                    idMap[asId(start+2)] = asId(start+3);
+                    stripInst(start);
+                }
+
+                return false;
+            },
+
+            [&](spv::Id& id) { if (idMap.find(id) != idMap.end()) id = idMap[id]; }
+        );
+
+        // EXPERIMENTAL: Implicit output stores
+        fnLocalVars.clear();
+        idMap.clear();
+
+        process(
+            [&](spv::Op opCode, unsigned start) {
+                // Add inputs and uniforms to the map
+                if (((opCode == spv::OpVariable && asWordCount(start) == 4) || (opCode == spv::OpVariableArray)) &&
+                    (spv[start+3] == spv::StorageClassOutput))
+                    fnLocalVars.insert(asId(start+2));
+
+                if (opCode == spv::OpStore && fnLocalVars.count(asId(start+1)) > 0) {
+                    idMap[asId(start+2)] = asId(start+1);
+                    stripInst(start);
+                }
+
+                return false;
+            },
+            op_fn_nop);
+
+        process(
+            inst_fn_nop,
+            [&](spv::Id& id) { if (idMap.find(id) != idMap.end()) id = idMap[id]; }
+        );
+
+        strip();          // strip out data we decided to eliminate
+    }
+
+    // remove bodies of uncalled functions
+    void spirvbin_t::optLoadStore()
+    {
+        idset_t fnLocalVars;
+        // Map of load result IDs to what they load
+        idmap_t idMap;
+
+        // Find all the function local pointers stored at most once, and not via access chains
+        process(
+            [&](spv::Op opCode, unsigned start) {
+                const int wordCount = asWordCount(start);
+
+                // Add local variables to the map
+                if ((opCode == spv::OpVariable && spv[start+3] == spv::StorageClassFunction && asWordCount(start) == 4) ||
+                    (opCode == spv::OpVariableArray && spv[start+3] == spv::StorageClassFunction))
+                    fnLocalVars.insert(asId(start+2));
+
+                // Ignore process vars referenced via access chain
+                if ((opCode == spv::OpAccessChain || opCode == spv::OpInBoundsAccessChain) && fnLocalVars.count(asId(start+3)) > 0) {
+                    fnLocalVars.erase(asId(start+3));
+                    idMap.erase(asId(start+3));
+                }
+
+                if (opCode == spv::OpLoad && fnLocalVars.count(asId(start+3)) > 0) {
+                    // Avoid loads before stores (TODO: why?  Crashes driver, but seems like it shouldn't).
+                    if (idMap.find(asId(start+3)) == idMap.end()) {
+                        fnLocalVars.erase(asId(start+3));
+                        idMap.erase(asId(start+3));
+                    }
+
+                    // don't do for volatile references
+                    if (wordCount > 4 && (spv[start+4] & spv::MemoryAccessVolatileMask)) {
+                        fnLocalVars.erase(asId(start+3));
+                        idMap.erase(asId(start+3));
+                    }
+                }
+
+                if (opCode == spv::OpStore && fnLocalVars.count(asId(start+1)) > 0) {
+                    if (idMap.find(asId(start+1)) == idMap.end()) {
+                        idMap[asId(start+1)] = asId(start+2);
+                    } else {
+                        // Remove if it has more than one store to the same pointer
+                        fnLocalVars.erase(asId(start+1));
+                        idMap.erase(asId(start+1));
+                    }
+
+                    // don't do for volatile references
+                    if (wordCount > 3 && (spv[start+3] & spv::MemoryAccessVolatileMask)) {
+                        fnLocalVars.erase(asId(start+3));
+                        idMap.erase(asId(start+3));
+                    }
+                }
+
+                return true;
+            },
+            op_fn_nop);
+
+        process(
+            [&](spv::Op opCode, unsigned start) {
+                if (opCode == spv::OpLoad && fnLocalVars.count(asId(start+3)) > 0)
+                    idMap[asId(start+2)] = idMap[asId(start+3)];
+                return false;
+            },
+            op_fn_nop);
+
+        // Remove the load/store/variables for the ones we've discovered
+        process(
+            [&](spv::Op opCode, unsigned start) {
+                if ((opCode == spv::OpLoad  && fnLocalVars.count(asId(start+3)) > 0) ||
+                    (opCode == spv::OpStore && fnLocalVars.count(asId(start+1)) > 0) ||
+                    (opCode == spv::OpVariable && fnLocalVars.count(asId(start+2)) > 0)) {
+                    stripInst(start);
+                    return true;
+                }
+
+                return false;
+            },
+
+            [&](spv::Id& id) { if (idMap.find(id) != idMap.end()) id = idMap[id]; }
+        );
+
+        strip();          // strip out data we decided to eliminate
+    }
+
+    // remove bodies of uncalled functions
+    void spirvbin_t::dceFuncs()
+    {
+        msg(3, 2, std::string("Removing Dead Functions: "));
+
+        // TODO: There are more efficient ways to do this.
+        bool changed = true;
+
+        while (changed) {
+            changed = false;
+
+            for (auto fn = fnPos.begin(); fn != fnPos.end(); ) {
+                if (fn->first == entryPoint) { // don't DCE away the entry point!
+                    ++fn;
+                    continue;
+                }
+
+                const auto call_it = fnCalls.find(fn->first);
+
+                if (call_it == fnCalls.end() || call_it->second == 0) {
+                    changed = true;
+                    stripRange.push_back(fn->second);
+                    fnPosDCE.insert(*fn);
+
+                    // decrease counts of called functions
+                    process(
+                        [&](spv::Op opCode, unsigned start) {
+                            if (opCode == spv::Op::OpFunctionCall) {
+                                const auto call_it = fnCalls.find(asId(start + 3));
+                                if (call_it != fnCalls.end()) {
+                                    if (--call_it->second <= 0)
+                                        fnCalls.erase(call_it);
+                                }
+                            }
+
+                            return true;
+                        },
+                        op_fn_nop,
+                        fn->second.first,
+                        fn->second.second);
+
+                    fn = fnPos.erase(fn);
+                } else ++fn;
+            }
+        }
+    }
+
+    // remove unused function variables + decorations
+    void spirvbin_t::dceVars()
+    {
+        msg(3, 2, std::string("DCE Vars: "));
+
+        std::unordered_map<spv::Id, int> varUseCount;
+
+        // Count function variable use
+        process(
+            [&](spv::Op opCode, unsigned start) {
+                if (opCode == spv::OpVariable) { ++varUseCount[asId(start+2)]; return true; }
+                return false;
+            },
+
+            [&](spv::Id& id) { if (varUseCount[id]) ++varUseCount[id]; }
+        );
+
+        // Remove single-use function variables + associated decorations and names
+        process(
+            [&](spv::Op opCode, unsigned start) {
+                if ((opCode == spv::OpVariable && varUseCount[asId(start+2)] == 1)  ||
+                    (opCode == spv::OpDecorate && varUseCount[asId(start+1)] == 1)  ||
+                    (opCode == spv::OpName     && varUseCount[asId(start+1)] == 1)) {
+                        stripInst(start);
+                }
+                return true;
+            },
+            op_fn_nop);
+    }
+
+    // remove unused types
+    void spirvbin_t::dceTypes()
+    {
+        std::vector<bool> isType(bound(), false);
+
+        // for speed, make O(1) way to get to type query (map is log(n))
+        for (const auto typeStart : typeConstPos)
+            isType[asTypeConstId(typeStart)] = true;
+
+        std::unordered_map<spv::Id, int> typeUseCount;
+
+        // Count total type usage
+        process(inst_fn_nop,
+            [&](spv::Id& id) { if (isType[id]) ++typeUseCount[id]; }
+        );
+
+        // Remove types from deleted code
+        for (const auto& fn : fnPosDCE)
+            process(inst_fn_nop,
+            [&](spv::Id& id) { if (isType[id]) --typeUseCount[id]; },
+            fn.second.first, fn.second.second);
+
+        // Remove single reference types
+        for (const auto typeStart : typeConstPos) {
+            const spv::Id typeId = asTypeConstId(typeStart);
+            if (typeUseCount[typeId] == 1) {
+                --typeUseCount[typeId];
+                stripInst(typeStart);
+            }
+        }
+    }
+
+
+#ifdef NOTDEF
+    bool spirvbin_t::matchType(const spirvbin_t::globaltypes_t& globalTypes, spv::Id lt, spv::Id gt) const
+    {
+        // Find the local type id "lt" and global type id "gt"
+        const auto lt_it = typeConstPosR.find(lt);
+        if (lt_it == typeConstPosR.end())
+            return false;
+
+        const auto typeStart = lt_it->second;
+
+        // Search for entry in global table
+        const auto gtype = globalTypes.find(gt);
+        if (gtype == globalTypes.end())
+            return false;
+
+        const auto& gdata = gtype->second;
+
+        // local wordcount and opcode
+        const int     wordCount   = asWordCount(typeStart);
+        const spv::Op opCode      = asOpCode(typeStart);
+
+        // no type match if opcodes don't match, or operand count doesn't match
+        if (opCode != opOpCode(gdata[0]) || wordCount != opWordCount(gdata[0]))
+            return false;
+
+        const unsigned numOperands = wordCount - 2; // all types have a result
+
+        const auto cmpIdRange = [&](range_t range) {
+            for (int x=range.first; x<std::min(range.second, wordCount); ++x)
+                if (!matchType(globalTypes, asId(typeStart+x), gdata[x]))
+                    return false;
+            return true;
+        };
+
+        const auto cmpConst   = [&]() { return cmpIdRange(constRange(opCode)); };
+        const auto cmpSubType = [&]() { return cmpIdRange(typeRange(opCode));  };
+
+        // Compare literals in range [start,end)
+        const auto cmpLiteral = [&]() {
+            const auto range = literalRange(opCode);
+            return std::equal(spir.begin() + typeStart + range.first,
+                spir.begin() + typeStart + std::min(range.second, wordCount),
+                gdata.begin() + range.first);
+        };
+
+        assert(isTypeOp(opCode) || isConstOp(opCode));
+
+        switch (opCode) {
+        case spv::OpTypeOpaque:       // TODO: disable until we compare the literal strings.
+        case spv::OpTypeQueue:        return false;
+        case spv::OpTypeEvent:        // fall through...
+        case spv::OpTypeDeviceEvent:  // ...
+        case spv::OpTypeReserveId:    return false;
+            // for samplers, we don't handle the optional parameters yet
+        case spv::OpTypeSampler:      return cmpLiteral() && cmpConst() && cmpSubType() && wordCount == 8;
+        default:                      return cmpLiteral() && cmpConst() && cmpSubType();
+        }
+    }
+
+
+    // Look for an equivalent type in the globalTypes map
+    spv::Id spirvbin_t::findType(const spirvbin_t::globaltypes_t& globalTypes, spv::Id lt) const
+    {
+        // Try a recursive type match on each in turn, and return a match if we find one
+        for (const auto& gt : globalTypes)
+            if (matchType(globalTypes, lt, gt.first))
+                return gt.first;
+
+        return spv::NoType;
+    }
+#endif // NOTDEF
+
+    // Return start position in SPV of given type.  error if not found.
+    unsigned spirvbin_t::typePos(spv::Id id) const
+    {
+        const auto tid_it = typeConstPosR.find(id);
+        if (tid_it == typeConstPosR.end())
+            error("type ID not found");
+
+        return tid_it->second;
+    }
+
+    // Hash types to canonical values.  This can return ID collisions (it's a bit
+    // inevitable): it's up to the caller to handle that gracefully.
+    std::uint32_t spirvbin_t::hashType(unsigned typeStart) const
+    {
+        const unsigned wordCount   = asWordCount(typeStart);
+        const spv::Op  opCode      = asOpCode(typeStart);
+
+        switch (opCode) {
+        case spv::OpTypeVoid:         return 0;
+        case spv::OpTypeBool:         return 1;
+        case spv::OpTypeInt:          return 3 + (spv[typeStart+3]);
+        case spv::OpTypeFloat:        return 5;
+        case spv::OpTypeVector:
+            return 6 + hashType(typePos(spv[typeStart+2])) * (spv[typeStart+3] - 1);
+        case spv::OpTypeMatrix:
+            return 30 + hashType(typePos(spv[typeStart+2])) * (spv[typeStart+3] - 1);
+        case spv::OpTypeSampler:
+            return 120 + hashType(typePos(spv[typeStart+2])) +
+                spv[typeStart+3] +            // dimensionality
+                spv[typeStart+4] * 8 * 16 +   // content
+                spv[typeStart+5] * 4 * 16 +   // arrayed
+                spv[typeStart+6] * 2 * 16 +   // compare
+                spv[typeStart+7] * 1 * 16;    // multisampled
+        case spv::OpTypeFilter:
+            return 500;
+        case spv::OpTypeArray:
+            return 501 + hashType(typePos(spv[typeStart+2])) * spv[typeStart+3];
+        case spv::OpTypeRuntimeArray:
+            return 5000  + hashType(typePos(spv[typeStart+2]));
+        case spv::OpTypeStruct:
+            {
+                std::uint32_t hash = 10000;
+                for (unsigned w=2; w < wordCount; ++w)
+                    hash += w * hashType(typePos(spv[typeStart+w]));
+                return hash;
+            }
+
+        case spv::OpTypeOpaque:         return 6000 + spv[typeStart+2];
+        case spv::OpTypePointer:        return 100000  + hashType(typePos(spv[typeStart+3]));
+        case spv::OpTypeFunction:
+            {
+                std::uint32_t hash = 200000;
+                for (unsigned w=2; w < wordCount; ++w)
+                    hash += w * hashType(typePos(spv[typeStart+w]));
+                return hash;
+            }
+
+        case spv::OpTypeEvent:           return 300000;
+        case spv::OpTypeDeviceEvent:     return 300001;
+        case spv::OpTypeReserveId:       return 300002;
+        case spv::OpTypeQueue:           return 300003;
+        case spv::OpTypePipe:            return 300004;
+
+        case spv::OpConstantNullObject:  return 300005;
+        case spv::OpConstantSampler:     return 300006;
+
+        case spv::OpConstantTrue:        return 300007;
+        case spv::OpConstantFalse:       return 300008;
+        case spv::OpConstantNullPointer: return 300009;
+        case spv::OpConstantComposite:
+            {
+                std::uint32_t hash = 300011 + hashType(typePos(spv[typeStart+1]));
+                for (unsigned w=3; w < wordCount; ++w)
+                    hash += w * hashType(typePos(spv[typeStart+w]));
+                return hash;
+            }
+        case spv::OpConstant:
+            {
+                std::uint32_t hash = 400011 + hashType(typePos(spv[typeStart+1]));
+                for (unsigned w=3; w < wordCount; ++w)
+                    hash += w * spv[typeStart+w];
+                return hash;
+            }
+
+        default:
+            error("unknown type opcode");
+            return 0;
+        }
+    }
+
+    void spirvbin_t::mapTypeConst()
+    {
+        globaltypes_t globalTypeMap;
+
+        msg(3, 2, std::string("Remapping Consts & Types: "));
+
+        static const std::uint32_t softTypeIdLimit = 3011; // small prime.  TODO: get from options
+        static const std::uint32_t firstMappedID   = 8;    // offset into ID space
+
+        for (auto& typeStart : typeConstPos) {
+            const spv::Id       resId     = asTypeConstId(typeStart);
+            const std::uint32_t hashval   = hashType(typeStart);
+
+            if (isOldIdUnmapped(resId))
+                localId(resId, nextUnusedId(hashval % softTypeIdLimit + firstMappedID));
+        }
+    }
+
+
+    // Strip a single binary by removing ranges given in stripRange
+    void spirvbin_t::strip()
+    {
+        if (stripRange.empty()) // nothing to do
+            return;
+
+        // Sort strip ranges in order of traversal
+        std::sort(stripRange.begin(), stripRange.end());
+
+        // Allocate a new binary big enough to hold old binary
+        // We'll step this iterator through the strip ranges as we go through the binary
+        auto strip_it = stripRange.begin();
+
+        int strippedPos = 0;
+        for (unsigned word = 0; word < unsigned(spv.size()); ++word) {
+            if (strip_it != stripRange.end() && word >= strip_it->second)
+                ++strip_it;
+
+            if (strip_it == stripRange.end() || word < strip_it->first || word >= strip_it->second)
+                spv[strippedPos++] = spv[word];
+        }
+
+        spv.resize(strippedPos);
+        stripRange.clear();
+
+        buildLocalMaps();
+    }
+
+    // Strip a single binary by removing ranges given in stripRange
+    void spirvbin_t::remap(std::uint32_t opts)
+    {
+        options = opts;
+
+        // Set up opcode tables from SpvDoc
+        spv::Parameterize();
+
+        validate();  // validate header
+        buildLocalMaps();
+
+        msg(3, 4, std::string("ID bound: ") + std::to_string(bound()));
+
+        strip();        // strip out data we decided to eliminate
+
+        if (options & OPT_LOADSTORE) optLoadStore();
+        if (options & OPT_FWD_LS)    forwardLoadStores();
+        if (options & DCE_FUNCS)     dceFuncs();
+        if (options & DCE_VARS)      dceVars();
+        if (options & DCE_TYPES)     dceTypes();
+        if (options & MAP_TYPES)     mapTypeConst();
+        if (options & MAP_NAMES)     mapNames();
+        if (options & MAP_FUNCS)     mapFnBodies();
+
+        mapRemainder(); // map any unmapped IDs
+        applyMap();     // Now remap each shader to the new IDs we've come up with
+        strip();        // strip out data we decided to eliminate
+    }
+
+    // remap from a memory image
+    void spirvbin_t::remap(std::vector<std::uint32_t>& in_spv, std::uint32_t opts)
+    {
+        spv.swap(in_spv);
+        remap(opts);
+        spv.swap(in_spv);
+    }
+
+} // namespace SPV
+
+#endif // defined (use_cpp11)
+
index 71ca719..1b148b3 100644 (file)
-//\r
-//Copyright (C) 2015 LunarG, Inc.\r
-//\r
-//All rights reserved.\r
-//\r
-//Redistribution and use in source and binary forms, with or without\r
-//modification, are permitted provided that the following conditions\r
-//are met:\r
-//\r
-//    Redistributions of source code must retain the above copyright\r
-//    notice, this list of conditions and the following disclaimer.\r
-//\r
-//    Redistributions in binary form must reproduce the above\r
-//    copyright notice, this list of conditions and the following\r
-//    disclaimer in the documentation and/or other materials provided\r
-//    with the distribution.\r
-//\r
-//    Neither the name of 3Dlabs Inc. Ltd. nor the names of its\r
-//    contributors may be used to endorse or promote products derived\r
-//    from this software without specific prior written permission.\r
-//\r
-//THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\r
-//"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\r
-//LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS\r
-//FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE\r
-//COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,\r
-//INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,\r
-//BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\r
-//LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER\r
-//CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\r
-//LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN\r
-//ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE\r
-//POSSIBILITY OF SUCH DAMAGE.\r
-//\r
-\r
-#ifndef SPIRVREMAPPER_H\r
-#define SPIRVREMAPPER_H\r
-\r
-#include <string>\r
-#include <vector>\r
-#include <stdlib.h>\r
-\r
-namespace spv {\r
-\r
-// MSVC defines __cplusplus as an older value, even when it supports almost all of 11.\r
-// We handle that here by making our own symbol.\r
-#if __cplusplus >= 201103L || _MSC_VER >= 1700\r
-#   define use_cpp11 1\r
-#endif\r
-\r
-class spirvbin_base_t\r
-{\r
-public:\r
-   enum Options {\r
-      NONE          = 0,\r
-      STRIP         = (1<<0),\r
-      MAP_TYPES     = (1<<1),\r
-      MAP_NAMES     = (1<<2),\r
-      MAP_FUNCS     = (1<<3),\r
-      DCE_FUNCS     = (1<<4),\r
-      DCE_VARS      = (1<<5),\r
-      DCE_TYPES     = (1<<6),\r
-      OPT_LOADSTORE = (1<<7),\r
-      OPT_FWD_LS    = (1<<8), // EXPERIMENTAL: PRODUCES INVALID SCHEMA-0 SPIRV\r
-      MAP_ALL       = (MAP_TYPES | MAP_NAMES | MAP_FUNCS),\r
-      DCE_ALL       = (DCE_FUNCS | DCE_VARS | DCE_TYPES),\r
-      OPT_ALL       = (OPT_LOADSTORE),\r
-\r
-      ALL_BUT_STRIP = (MAP_ALL | DCE_ALL | OPT_ALL),\r
-      DO_EVERYTHING = (STRIP | ALL_BUT_STRIP)\r
-   };\r
-};\r
-\r
-} // namespace SPV\r
-\r
-#if !defined (use_cpp11)\r
-#include <stdio.h>\r
-\r
-namespace spv {\r
-class spirvbin_t : public spirvbin_base_t\r
-{\r
-public:\r
-    spirvbin_t(int /*verbose = 0*/) { }\r
-\r
-    void remap(std::vector<unsigned int>& /*spv*/, unsigned int /*opts = 0*/)\r
-    {\r
-        printf("Tool not compiled for C++11, which is required for SPIR-V remapping.\n");\r
-        exit(5);\r
-    }\r
-};\r
-\r
-} // namespace SPV\r
-\r
-#else // defined (use_cpp11)\r
-\r
-#include <functional>\r
-#include <cstdint>\r
-#include <unordered_map>\r
-#include <unordered_set>\r
-#include <map>\r
-#include <set>\r
-#include <cassert>\r
-\r
-#include "../../glslang/SPIRV/spirv.h"\r
-#include "../../glslang/SPIRV/spvIR.h"\r
-\r
-namespace spv {\r
-\r
-// class to hold SPIR-V binary data for remapping, DCE, and debug stripping\r
-class spirvbin_t : public spirvbin_base_t\r
-{\r
-public:\r
-   spirvbin_t(int verbose = 0) : entryPoint(spv::NoResult), largestNewId(0), verbose(verbose) { }\r
-   \r
-   // remap on an existing binary in memory\r
-   void remap(std::vector<std::uint32_t>& spv, std::uint32_t opts = DO_EVERYTHING);\r
-\r
-   // Type for error/log handler functions\r
-   typedef std::function<void(const std::string&)> errorfn_t;\r
-   typedef std::function<void(const std::string&)> logfn_t;\r
-\r
-   // Register error/log handling functions (can be lambda fn / functor / etc)\r
-   static void registerErrorHandler(errorfn_t handler) { errorHandler = handler; }\r
-   static void registerLogHandler(logfn_t handler)     { logHandler   = handler; }\r
-\r
-protected:\r
-   // This can be overridden to provide other message behavior if needed\r
-   virtual void msg(int minVerbosity, int indent, const std::string& txt) const;\r
-\r
-private:\r
-   // Local to global, or global to local ID map\r
-   typedef std::unordered_map<spv::Id, spv::Id> idmap_t;\r
-   typedef std::unordered_set<spv::Id>          idset_t;\r
-\r
-   void remap(std::uint32_t opts = DO_EVERYTHING);\r
-\r
-   // Map of names to IDs\r
-   typedef std::unordered_map<std::string, spv::Id> namemap_t;\r
-\r
-   typedef std::uint32_t spirword_t;\r
-\r
-   typedef std::pair<unsigned, unsigned> range_t;\r
-   typedef std::function<void(spv::Id&)>                idfn_t;\r
-   typedef std::function<bool(spv::Op, unsigned start)> instfn_t;\r
-\r
-   // Special Values for ID map:\r
-   static const spv::Id unmapped;     // unchanged from default value\r
-   static const spv::Id unused;       // unused ID\r
-   static const int     header_size;  // SPIR header = 5 words\r
-\r
-   class id_iterator_t;\r
-\r
-   // For mapping type entries between different shaders\r
-   typedef std::vector<spirword_t>        typeentry_t;\r
-   typedef std::map<spv::Id, typeentry_t> globaltypes_t;\r
-\r
-   // A set that preserves position order, and a reverse map\r
-   typedef std::set<int>                    posmap_t;\r
-   typedef std::unordered_map<spv::Id, int> posmap_rev_t;\r
-\r
-   // handle error\r
-   void error(const std::string& txt) const { errorHandler(txt); }\r
-\r
-   bool    isConstOp(spv::Op opCode)       const;\r
-   bool    isTypeOp(spv::Op opCode)        const;\r
-   bool    isStripOp(spv::Op opCode)       const;\r
-   bool    isFlowCtrlOpen(spv::Op opCode)  const;\r
-   bool    isFlowCtrlClose(spv::Op opCode) const;\r
-   range_t literalRange(spv::Op opCode)    const;\r
-   range_t typeRange(spv::Op opCode)       const;\r
-   range_t constRange(spv::Op opCode)      const;\r
-   \r
-   spv::Id&        asId(unsigned word)                { return spv[word]; }\r
-   const spv::Id&  asId(unsigned word)          const { return spv[word]; }\r
-   spv::Op         asOpCode(unsigned word)      const { return opOpCode(spv[word]); }\r
-   std::uint32_t   asOpCodeHash(unsigned word);\r
-   spv::Decoration asDecoration(unsigned word)  const { return spv::Decoration(spv[word]); }\r
-   unsigned        asWordCount(unsigned word)   const { return opWordCount(spv[word]); }\r
-   spv::Id         asTypeConstId(unsigned word) const { return asId(word + (isTypeOp(asOpCode(word)) ? 1 : 2)); }\r
-   unsigned        typePos(spv::Id id)          const;\r
-\r
-   static unsigned    opWordCount(spirword_t data) { return data >> spv::WordCountShift; }\r
-   static spv::Op     opOpCode(spirword_t data)    { return spv::Op(data & spv::OpCodeMask); }\r
-\r
-   // Header access & set methods\r
-   spirword_t  magic()    const       { return spv[0]; } // return magic number\r
-   spirword_t  bound()    const       { return spv[3]; } // return Id bound from header\r
-   spirword_t  bound(spirword_t b)    { return spv[3] = b; };\r
-   spirword_t  genmagic() const       { return spv[2]; } // generator magic\r
-   spirword_t  genmagic(spirword_t m) { return spv[2] = m; }\r
-   spirword_t  schemaNum() const      { return spv[4]; } // schema number from header\r
-\r
-   // Mapping fns: get\r
-   spv::Id     localId(spv::Id id) const { return idMapL[id]; }\r
-\r
-   // Mapping fns: set\r
-   inline spv::Id   localId(spv::Id id, spv::Id newId);\r
-   void             countIds(spv::Id id);\r
-\r
-   // Return next unused new local ID.\r
-   // NOTE: boost::dynamic_bitset would be more efficient due to find_next(),\r
-   // which std::vector<bool> doens't have.\r
-   inline spv::Id   nextUnusedId(spv::Id id);\r
-\r
-   void buildLocalMaps();\r
-   std::string literalString(unsigned word) const; // Return literal as a std::string\r
-   int literalStringWords(const std::string& str) const { return (int(str.size())+4)/4; }\r
-\r
-   bool isNewIdMapped(spv::Id newId)   const { return isMapped(newId);            }\r
-   bool isOldIdUnmapped(spv::Id oldId) const { return localId(oldId) == unmapped; }\r
-   bool isOldIdUnused(spv::Id oldId)   const { return localId(oldId) == unused;   }\r
-   bool isOldIdMapped(spv::Id oldId)   const { return !isOldIdUnused(oldId) && !isOldIdUnmapped(oldId); }\r
-   bool isFunction(spv::Id oldId)      const { return fnPos.find(oldId) != fnPos.end(); }\r
-\r
-   // bool    matchType(const globaltypes_t& globalTypes, spv::Id lt, spv::Id gt) const;\r
-   // spv::Id findType(const globaltypes_t& globalTypes, spv::Id lt) const;\r
-   std::uint32_t hashType(unsigned typeStart) const;\r
-\r
-   spirvbin_t& process(instfn_t, idfn_t, unsigned begin = 0, unsigned end = 0);\r
-   int         processInstruction(unsigned word, instfn_t, idfn_t);\r
-\r
-   void        validate() const;\r
-   void        mapTypeConst();\r
-   void        mapFnBodies();\r
-   void        optLoadStore();\r
-   void        dceFuncs();\r
-   void        dceVars();\r
-   void        dceTypes();\r
-   void        mapNames();\r
-   void        foldIds();  // fold IDs to smallest space\r
-   void        forwardLoadStores(); // load store forwarding (EXPERIMENTAL)\r
-   void        offsetIds(); // create relative offset IDs\r
-\r
-   void        applyMap();            // remap per local name map\r
-   void        mapRemainder();        // map any IDs we haven't touched yet\r
-   void        stripDebug();          // strip debug info\r
-   void        strip();               // remove debug symbols\r
-   \r
-   std::vector<spirword_t> spv;      // SPIR words\r
-\r
-   namemap_t               nameMap;  // ID names from OpName\r
-\r
-   // Since we want to also do binary ops, we can't use std::vector<bool>.  we could use\r
-   // boost::dynamic_bitset, but we're trying to avoid a boost dependency.\r
-   typedef std::uint64_t bits_t;\r
-   std::vector<bits_t> mapped; // which new IDs have been mapped\r
-   static const int mBits = sizeof(bits_t) * 4;\r
-\r
-   bool isMapped(spv::Id id) const  { return id < maxMappedId() && ((mapped[id/mBits] & (1LL<<(id%mBits))) != 0); }\r
-   void setMapped(spv::Id id) { resizeMapped(id); mapped[id/mBits] |= (1LL<<(id%mBits)); }\r
-   void resizeMapped(spv::Id id) { if (id >= maxMappedId()) mapped.resize(id/mBits+1, 0); }\r
-   size_t maxMappedId() const { return mapped.size() * mBits; }\r
-\r
-   // Add a strip range for a given instruction starting at 'start'\r
-   // Note: avoiding brace initializers to please older versions os MSVC.\r
-   void stripInst(unsigned start) { stripRange.push_back(range_t(start, start + asWordCount(start))); }\r
-\r
-   // Function start and end.  use unordered_map because we'll have\r
-   // many fewer functions than IDs.\r
-   std::unordered_map<spv::Id, range_t> fnPos;\r
-   std::unordered_map<spv::Id, range_t> fnPosDCE; // deleted functions\r
-\r
-   // Which functions are called, anywhere in the module, with a call count\r
-   std::unordered_map<spv::Id, int> fnCalls;\r
-   \r
-   posmap_t     typeConstPos;   // word positions that define types & consts (ordered)\r
-   posmap_rev_t typeConstPosR;  // reverse map from IDs to positions\r
-   \r
-   std::vector<spv::Id>  idMapL;   // ID {M}ap from {L}ocal to {G}lobal IDs\r
-\r
-   spv::Id entryPoint;      // module entry point\r
-   spv::Id largestNewId;    // biggest new ID we have mapped anything to\r
-\r
-   // Sections of the binary to strip, given as [begin,end)\r
-   std::vector<range_t> stripRange;\r
-\r
-   // processing options:\r
-   std::uint32_t options;\r
-   int           verbose;     // verbosity level\r
-\r
-   static errorfn_t errorHandler;\r
-   static logfn_t   logHandler;\r
-};\r
-\r
-} // namespace SPV\r
-\r
-#endif // defined (use_cpp11)\r
-#endif // SPIRVREMAPPER_H\r
+//
+//Copyright (C) 2015 LunarG, Inc.
+//
+//All rights reserved.
+//
+//Redistribution and use in source and binary forms, with or without
+//modification, are permitted provided that the following conditions
+//are met:
+//
+//    Redistributions of source code must retain the above copyright
+//    notice, this list of conditions and the following disclaimer.
+//
+//    Redistributions in binary form must reproduce the above
+//    copyright notice, this list of conditions and the following
+//    disclaimer in the documentation and/or other materials provided
+//    with the distribution.
+//
+//    Neither the name of 3Dlabs Inc. Ltd. nor the names of its
+//    contributors may be used to endorse or promote products derived
+//    from this software without specific prior written permission.
+//
+//THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+//"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+//LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+//FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+//COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+//INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+//BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+//LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+//CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+//LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+//ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+//POSSIBILITY OF SUCH DAMAGE.
+//
+
+#ifndef SPIRVREMAPPER_H
+#define SPIRVREMAPPER_H
+
+#include <string>
+#include <vector>
+#include <stdlib.h>
+
+namespace spv {
+
+// MSVC defines __cplusplus as an older value, even when it supports almost all of 11.
+// We handle that here by making our own symbol.
+#if __cplusplus >= 201103L || _MSC_VER >= 1700
+#   define use_cpp11 1
+#endif
+
+class spirvbin_base_t
+{
+public:
+   enum Options {
+      NONE          = 0,
+      STRIP         = (1<<0),
+      MAP_TYPES     = (1<<1),
+      MAP_NAMES     = (1<<2),
+      MAP_FUNCS     = (1<<3),
+      DCE_FUNCS     = (1<<4),
+      DCE_VARS      = (1<<5),
+      DCE_TYPES     = (1<<6),
+      OPT_LOADSTORE = (1<<7),
+      OPT_FWD_LS    = (1<<8), // EXPERIMENTAL: PRODUCES INVALID SCHEMA-0 SPIRV
+      MAP_ALL       = (MAP_TYPES | MAP_NAMES | MAP_FUNCS),
+      DCE_ALL       = (DCE_FUNCS | DCE_VARS | DCE_TYPES),
+      OPT_ALL       = (OPT_LOADSTORE),
+
+      ALL_BUT_STRIP = (MAP_ALL | DCE_ALL | OPT_ALL),
+      DO_EVERYTHING = (STRIP | ALL_BUT_STRIP)
+   };
+};
+
+} // namespace SPV
+
+#if !defined (use_cpp11)
+#include <stdio.h>
+
+namespace spv {
+class spirvbin_t : public spirvbin_base_t
+{
+public:
+    spirvbin_t(int /*verbose = 0*/) { }
+
+    void remap(std::vector<unsigned int>& /*spv*/, unsigned int /*opts = 0*/)
+    {
+        printf("Tool not compiled for C++11, which is required for SPIR-V remapping.\n");
+        exit(5);
+    }
+};
+
+} // namespace SPV
+
+#else // defined (use_cpp11)
+
+#include <functional>
+#include <cstdint>
+#include <unordered_map>
+#include <unordered_set>
+#include <map>
+#include <set>
+#include <cassert>
+
+#include "../../glslang/SPIRV/spirv.h"
+#include "../../glslang/SPIRV/spvIR.h"
+
+namespace spv {
+
+// class to hold SPIR-V binary data for remapping, DCE, and debug stripping
+class spirvbin_t : public spirvbin_base_t
+{
+public:
+   spirvbin_t(int verbose = 0) : entryPoint(spv::NoResult), largestNewId(0), verbose(verbose) { }
+   
+   // remap on an existing binary in memory
+   void remap(std::vector<std::uint32_t>& spv, std::uint32_t opts = DO_EVERYTHING);
+
+   // Type for error/log handler functions
+   typedef std::function<void(const std::string&)> errorfn_t;
+   typedef std::function<void(const std::string&)> logfn_t;
+
+   // Register error/log handling functions (can be lambda fn / functor / etc)
+   static void registerErrorHandler(errorfn_t handler) { errorHandler = handler; }
+   static void registerLogHandler(logfn_t handler)     { logHandler   = handler; }
+
+protected:
+   // This can be overridden to provide other message behavior if needed
+   virtual void msg(int minVerbosity, int indent, const std::string& txt) const;
+
+private:
+   // Local to global, or global to local ID map
+   typedef std::unordered_map<spv::Id, spv::Id> idmap_t;
+   typedef std::unordered_set<spv::Id>          idset_t;
+
+   void remap(std::uint32_t opts = DO_EVERYTHING);
+
+   // Map of names to IDs
+   typedef std::unordered_map<std::string, spv::Id> namemap_t;
+
+   typedef std::uint32_t spirword_t;
+
+   typedef std::pair<unsigned, unsigned> range_t;
+   typedef std::function<void(spv::Id&)>                idfn_t;
+   typedef std::function<bool(spv::Op, unsigned start)> instfn_t;
+
+   // Special Values for ID map:
+   static const spv::Id unmapped;     // unchanged from default value
+   static const spv::Id unused;       // unused ID
+   static const int     header_size;  // SPIR header = 5 words
+
+   class id_iterator_t;
+
+   // For mapping type entries between different shaders
+   typedef std::vector<spirword_t>        typeentry_t;
+   typedef std::map<spv::Id, typeentry_t> globaltypes_t;
+
+   // A set that preserves position order, and a reverse map
+   typedef std::set<int>                    posmap_t;
+   typedef std::unordered_map<spv::Id, int> posmap_rev_t;
+
+   // handle error
+   void error(const std::string& txt) const { errorHandler(txt); }
+
+   bool    isConstOp(spv::Op opCode)       const;
+   bool    isTypeOp(spv::Op opCode)        const;
+   bool    isStripOp(spv::Op opCode)       const;
+   bool    isFlowCtrlOpen(spv::Op opCode)  const;
+   bool    isFlowCtrlClose(spv::Op opCode) const;
+   range_t literalRange(spv::Op opCode)    const;
+   range_t typeRange(spv::Op opCode)       const;
+   range_t constRange(spv::Op opCode)      const;
+   
+   spv::Id&        asId(unsigned word)                { return spv[word]; }
+   const spv::Id&  asId(unsigned word)          const { return spv[word]; }
+   spv::Op         asOpCode(unsigned word)      const { return opOpCode(spv[word]); }
+   std::uint32_t   asOpCodeHash(unsigned word);
+   spv::Decoration asDecoration(unsigned word)  const { return spv::Decoration(spv[word]); }
+   unsigned        asWordCount(unsigned word)   const { return opWordCount(spv[word]); }
+   spv::Id         asTypeConstId(unsigned word) const { return asId(word + (isTypeOp(asOpCode(word)) ? 1 : 2)); }
+   unsigned        typePos(spv::Id id)          const;
+
+   static unsigned    opWordCount(spirword_t data) { return data >> spv::WordCountShift; }
+   static spv::Op     opOpCode(spirword_t data)    { return spv::Op(data & spv::OpCodeMask); }
+
+   // Header access & set methods
+   spirword_t  magic()    const       { return spv[0]; } // return magic number
+   spirword_t  bound()    const       { return spv[3]; } // return Id bound from header
+   spirword_t  bound(spirword_t b)    { return spv[3] = b; };
+   spirword_t  genmagic() const       { return spv[2]; } // generator magic
+   spirword_t  genmagic(spirword_t m) { return spv[2] = m; }
+   spirword_t  schemaNum() const      { return spv[4]; } // schema number from header
+
+   // Mapping fns: get
+   spv::Id     localId(spv::Id id) const { return idMapL[id]; }
+
+   // Mapping fns: set
+   inline spv::Id   localId(spv::Id id, spv::Id newId);
+   void             countIds(spv::Id id);
+
+   // Return next unused new local ID.
+   // NOTE: boost::dynamic_bitset would be more efficient due to find_next(),
+   // which std::vector<bool> doens't have.
+   inline spv::Id   nextUnusedId(spv::Id id);
+
+   void buildLocalMaps();
+   std::string literalString(unsigned word) const; // Return literal as a std::string
+   int literalStringWords(const std::string& str) const { return (int(str.size())+4)/4; }
+
+   bool isNewIdMapped(spv::Id newId)   const { return isMapped(newId);            }
+   bool isOldIdUnmapped(spv::Id oldId) const { return localId(oldId) == unmapped; }
+   bool isOldIdUnused(spv::Id oldId)   const { return localId(oldId) == unused;   }
+   bool isOldIdMapped(spv::Id oldId)   const { return !isOldIdUnused(oldId) && !isOldIdUnmapped(oldId); }
+   bool isFunction(spv::Id oldId)      const { return fnPos.find(oldId) != fnPos.end(); }
+
+   // bool    matchType(const globaltypes_t& globalTypes, spv::Id lt, spv::Id gt) const;
+   // spv::Id findType(const globaltypes_t& globalTypes, spv::Id lt) const;
+   std::uint32_t hashType(unsigned typeStart) const;
+
+   spirvbin_t& process(instfn_t, idfn_t, unsigned begin = 0, unsigned end = 0);
+   int         processInstruction(unsigned word, instfn_t, idfn_t);
+
+   void        validate() const;
+   void        mapTypeConst();
+   void        mapFnBodies();
+   void        optLoadStore();
+   void        dceFuncs();
+   void        dceVars();
+   void        dceTypes();
+   void        mapNames();
+   void        foldIds();  // fold IDs to smallest space
+   void        forwardLoadStores(); // load store forwarding (EXPERIMENTAL)
+   void        offsetIds(); // create relative offset IDs
+
+   void        applyMap();            // remap per local name map
+   void        mapRemainder();        // map any IDs we haven't touched yet
+   void        stripDebug();          // strip debug info
+   void        strip();               // remove debug symbols
+   
+   std::vector<spirword_t> spv;      // SPIR words
+
+   namemap_t               nameMap;  // ID names from OpName
+
+   // Since we want to also do binary ops, we can't use std::vector<bool>.  we could use
+   // boost::dynamic_bitset, but we're trying to avoid a boost dependency.
+   typedef std::uint64_t bits_t;
+   std::vector<bits_t> mapped; // which new IDs have been mapped
+   static const int mBits = sizeof(bits_t) * 4;
+
+   bool isMapped(spv::Id id) const  { return id < maxMappedId() && ((mapped[id/mBits] & (1LL<<(id%mBits))) != 0); }
+   void setMapped(spv::Id id) { resizeMapped(id); mapped[id/mBits] |= (1LL<<(id%mBits)); }
+   void resizeMapped(spv::Id id) { if (id >= maxMappedId()) mapped.resize(id/mBits+1, 0); }
+   size_t maxMappedId() const { return mapped.size() * mBits; }
+
+   // Add a strip range for a given instruction starting at 'start'
+   // Note: avoiding brace initializers to please older versions os MSVC.
+   void stripInst(unsigned start) { stripRange.push_back(range_t(start, start + asWordCount(start))); }
+
+   // Function start and end.  use unordered_map because we'll have
+   // many fewer functions than IDs.
+   std::unordered_map<spv::Id, range_t> fnPos;
+   std::unordered_map<spv::Id, range_t> fnPosDCE; // deleted functions
+
+   // Which functions are called, anywhere in the module, with a call count
+   std::unordered_map<spv::Id, int> fnCalls;
+   
+   posmap_t     typeConstPos;   // word positions that define types & consts (ordered)
+   posmap_rev_t typeConstPosR;  // reverse map from IDs to positions
+   
+   std::vector<spv::Id>  idMapL;   // ID {M}ap from {L}ocal to {G}lobal IDs
+
+   spv::Id entryPoint;      // module entry point
+   spv::Id largestNewId;    // biggest new ID we have mapped anything to
+
+   // Sections of the binary to strip, given as [begin,end)
+   std::vector<range_t> stripRange;
+
+   // processing options:
+   std::uint32_t options;
+   int           verbose;     // verbosity level
+
+   static errorfn_t errorHandler;
+   static logfn_t   logHandler;
+};
+
+} // namespace SPV
+
+#endif // defined (use_cpp11)
+#endif // SPIRVREMAPPER_H
index 35270b0..f90dd70 100644 (file)
-//\r
-//Copyright (C) 2014 LunarG, Inc.\r
-//\r
-//All rights reserved.\r
-//\r
-//Redistribution and use in source and binary forms, with or without\r
-//modification, are permitted provided that the following conditions\r
-//are met:\r
-//\r
-//    Redistributions of source code must retain the above copyright\r
-//    notice, this list of conditions and the following disclaimer.\r
-//\r
-//    Redistributions in binary form must reproduce the above\r
-//    copyright notice, this list of conditions and the following\r
-//    disclaimer in the documentation and/or other materials provided\r
-//    with the distribution.\r
-//\r
-//    Neither the name of 3Dlabs Inc. Ltd. nor the names of its\r
-//    contributors may be used to endorse or promote products derived\r
-//    from this software without specific prior written permission.\r
-//\r
-//THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\r
-//"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\r
-//LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS\r
-//FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE\r
-//COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,\r
-//INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,\r
-//BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\r
-//LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER\r
-//CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\r
-//LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN\r
-//ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE\r
-//POSSIBILITY OF SUCH DAMAGE.\r
-\r
-//\r
-// Author: John Kessenich, LunarG\r
-//\r
-\r
-//\r
-// Helper for making SPIR-V IR.  Generally, this is documented in the header\r
-// SpvBuilder.h.\r
-//\r
-\r
-#include <assert.h>\r
-#include <stdio.h>\r
-#include <stdlib.h>\r
-\r
-#include "SpvBuilder.h"\r
-\r
-#ifndef _WIN32\r
-    #include <cstdio>\r
-#endif\r
-\r
-namespace spv {\r
-\r
-const int SpvBuilderMagic = 0xBB;\r
-\r
-Builder::Builder(unsigned int userNumber) :\r
-    source(SourceLanguageUnknown),\r
-    sourceVersion(0),\r
-    addressModel(AddressingModelLogical),\r
-    memoryModel(MemoryModelGLSL450),\r
-    builderNumber(userNumber << 16 | SpvBuilderMagic),\r
-    buildPoint(0),\r
-    uniqueId(0),\r
-    mainFunction(0),\r
-    stageExit(0)\r
-{\r
-    clearAccessChain();\r
-}\r
-\r
-Builder::~Builder()\r
-{\r
-}\r
-\r
-Id Builder::import(const char* name)\r
-{\r
-    Instruction* import = new Instruction(getUniqueId(), NoType, OpExtInstImport);\r
-    import->addStringOperand(name);\r
-    \r
-    imports.push_back(import);\r
-    return import->getResultId();\r
-}\r
-\r
-// For creating new groupedTypes (will return old type if the requested one was already made).\r
-Id Builder::makeVoidType()\r
-{\r
-    Instruction* type;\r
-    if (groupedTypes[OpTypeVoid].size() == 0) {\r
-        type = new Instruction(getUniqueId(), NoType, OpTypeVoid);\r
-        groupedTypes[OpTypeVoid].push_back(type);\r
-        constantsTypesGlobals.push_back(type);\r
-        module.mapInstruction(type);\r
-    } else\r
-        type = groupedTypes[OpTypeVoid].back();\r
-\r
-    return type->getResultId();\r
-}\r
-\r
-Id Builder::makeBoolType()\r
-{\r
-    Instruction* type;\r
-    if (groupedTypes[OpTypeBool].size() == 0) {\r
-        type = new Instruction(getUniqueId(), NoType, OpTypeBool);\r
-        groupedTypes[OpTypeBool].push_back(type);\r
-        constantsTypesGlobals.push_back(type);\r
-        module.mapInstruction(type);\r
-    } else\r
-        type = groupedTypes[OpTypeBool].back();\r
-\r
-    return type->getResultId();\r
-}\r
-\r
-Id Builder::makePointer(StorageClass storageClass, Id pointee)\r
-{\r
-    // try to find it\r
-    Instruction* type;\r
-    for (int t = 0; t < (int)groupedTypes[OpTypePointer].size(); ++t) {\r
-        type = groupedTypes[OpTypePointer][t];\r
-        if (type->getImmediateOperand(0) == (unsigned)storageClass &&\r
-            type->getIdOperand(1) == pointee)\r
-            return type->getResultId();\r
-    }\r
-\r
-    // not found, make it\r
-    type = new Instruction(getUniqueId(), NoType, OpTypePointer);\r
-    type->addImmediateOperand(storageClass);\r
-    type->addIdOperand(pointee);\r
-    groupedTypes[OpTypePointer].push_back(type);\r
-    constantsTypesGlobals.push_back(type);\r
-    module.mapInstruction(type);\r
-\r
-    return type->getResultId();\r
-}\r
-\r
-Id Builder::makeIntegerType(int width, bool hasSign)\r
-{\r
-    // try to find it\r
-    Instruction* type;\r
-    for (int t = 0; t < (int)groupedTypes[OpTypeInt].size(); ++t) {\r
-        type = groupedTypes[OpTypeInt][t];\r
-        if (type->getImmediateOperand(0) == (unsigned)width &&\r
-            type->getImmediateOperand(1) == (hasSign ? 1u : 0u))\r
-            return type->getResultId();\r
-    }\r
-\r
-    // not found, make it\r
-    type = new Instruction(getUniqueId(), NoType, OpTypeInt);\r
-    type->addImmediateOperand(width);\r
-    type->addImmediateOperand(hasSign ? 1 : 0);\r
-    groupedTypes[OpTypeInt].push_back(type);\r
-    constantsTypesGlobals.push_back(type);\r
-    module.mapInstruction(type);\r
-\r
-    return type->getResultId();\r
-}\r
-\r
-Id Builder::makeFloatType(int width)\r
-{\r
-    // try to find it\r
-    Instruction* type;\r
-    for (int t = 0; t < (int)groupedTypes[OpTypeFloat].size(); ++t) {\r
-        type = groupedTypes[OpTypeFloat][t];\r
-        if (type->getImmediateOperand(0) == (unsigned)width)\r
-            return type->getResultId();\r
-    }\r
-\r
-    // not found, make it\r
-    type = new Instruction(getUniqueId(), NoType, OpTypeFloat);\r
-    type->addImmediateOperand(width);\r
-    groupedTypes[OpTypeFloat].push_back(type);\r
-    constantsTypesGlobals.push_back(type);\r
-    module.mapInstruction(type);\r
-\r
-    return type->getResultId();\r
-}\r
-\r
-Id Builder::makeStructType(std::vector<Id>& members, const char* name)\r
-{\r
-    // not found, make it\r
-    Instruction* type = new Instruction(getUniqueId(), NoType, OpTypeStruct);\r
-    for (int op = 0; op < (int)members.size(); ++op)\r
-        type->addIdOperand(members[op]);\r
-    groupedTypes[OpTypeStruct].push_back(type);\r
-    constantsTypesGlobals.push_back(type);\r
-    module.mapInstruction(type);\r
-    addName(type->getResultId(), name);\r
-\r
-    return type->getResultId();\r
-}\r
-\r
-Id Builder::makeVectorType(Id component, int size)\r
-{\r
-    // try to find it\r
-    Instruction* type;\r
-    for (int t = 0; t < (int)groupedTypes[OpTypeVector].size(); ++t) {\r
-        type = groupedTypes[OpTypeVector][t];\r
-        if (type->getIdOperand(0) == component &&\r
-            type->getImmediateOperand(1) == (unsigned)size)\r
-            return type->getResultId();\r
-    }\r
-\r
-    // not found, make it\r
-    type = new Instruction(getUniqueId(), NoType, OpTypeVector);\r
-    type->addIdOperand(component);\r
-    type->addImmediateOperand(size);\r
-    groupedTypes[OpTypeVector].push_back(type);\r
-    constantsTypesGlobals.push_back(type);\r
-    module.mapInstruction(type);\r
-\r
-    return type->getResultId();\r
-}\r
-\r
-Id Builder::makeMatrixType(Id component, int cols, int rows)\r
-{\r
-    assert(cols <= maxMatrixSize && rows <= maxMatrixSize);\r
-\r
-    Id column = makeVectorType(component, rows);\r
-\r
-    // try to find it\r
-    Instruction* type;\r
-    for (int t = 0; t < (int)groupedTypes[OpTypeMatrix].size(); ++t) {\r
-        type = groupedTypes[OpTypeMatrix][t];\r
-        if (type->getIdOperand(0) == column &&\r
-            type->getImmediateOperand(1) == (unsigned)cols)\r
-            return type->getResultId();\r
-    }\r
-\r
-    // not found, make it\r
-    type = new Instruction(getUniqueId(), NoType, OpTypeMatrix);\r
-    type->addIdOperand(column);\r
-    type->addImmediateOperand(cols);\r
-    groupedTypes[OpTypeMatrix].push_back(type);\r
-    constantsTypesGlobals.push_back(type);\r
-    module.mapInstruction(type);\r
-\r
-    return type->getResultId();\r
-}\r
-\r
-Id Builder::makeArrayType(Id element, unsigned size)\r
-{\r
-    // First, we need a constant instruction for the size\r
-    Id sizeId = makeUintConstant(size);\r
-\r
-    // try to find existing type\r
-    Instruction* type;\r
-    for (int t = 0; t < (int)groupedTypes[OpTypeArray].size(); ++t) {\r
-        type = groupedTypes[OpTypeArray][t];\r
-        if (type->getIdOperand(0) == element &&\r
-            type->getIdOperand(1) == sizeId)\r
-            return type->getResultId();\r
-    }\r
-\r
-    // not found, make it\r
-    type = new Instruction(getUniqueId(), NoType, OpTypeArray);\r
-    type->addIdOperand(element);\r
-    type->addIdOperand(sizeId);\r
-    groupedTypes[OpTypeArray].push_back(type);\r
-    constantsTypesGlobals.push_back(type);\r
-    module.mapInstruction(type);\r
-\r
-    return type->getResultId();\r
-}\r
-\r
-Id Builder::makeFunctionType(Id returnType, std::vector<Id>& paramTypes)\r
-{\r
-    // try to find it\r
-    Instruction* type;\r
-    for (int t = 0; t < (int)groupedTypes[OpTypeFunction].size(); ++t) {\r
-        type = groupedTypes[OpTypeFunction][t];\r
-        if (type->getIdOperand(0) != returnType || (int)paramTypes.size() != type->getNumOperands() - 1)\r
-            continue;\r
-        bool mismatch = false;\r
-        for (int p = 0; p < (int)paramTypes.size(); ++p) {\r
-            if (paramTypes[p] != type->getIdOperand(p + 1)) {\r
-                mismatch = true;\r
-                break;\r
-            }\r
-        }\r
-        if (! mismatch)\r
-            return type->getResultId();            \r
-    }\r
-\r
-    // not found, make it\r
-    type = new Instruction(getUniqueId(), NoType, OpTypeFunction);\r
-    type->addIdOperand(returnType);\r
-    for (int p = 0; p < (int)paramTypes.size(); ++p)\r
-        type->addIdOperand(paramTypes[p]);\r
-    groupedTypes[OpTypeFunction].push_back(type);\r
-    constantsTypesGlobals.push_back(type);\r
-    module.mapInstruction(type);\r
-\r
-    return type->getResultId();\r
-}\r
-\r
-Id Builder::makeSampler(Id sampledType, Dim dim, samplerContent content, bool arrayed, bool shadow, bool ms)\r
-{\r
-    // try to find it\r
-    Instruction* type;\r
-    for (int t = 0; t < (int)groupedTypes[OpTypeSampler].size(); ++t) {\r
-        type = groupedTypes[OpTypeSampler][t];\r
-        if (type->getIdOperand(0) == sampledType &&\r
-            type->getImmediateOperand(1) == (unsigned int)dim &&\r
-            type->getImmediateOperand(2) == (unsigned int)content &&\r
-            type->getImmediateOperand(3) == (arrayed ? 1u : 0u) &&\r
-            type->getImmediateOperand(4) == ( shadow ? 1u : 0u) &&\r
-            type->getImmediateOperand(5) == (     ms ? 1u : 0u))\r
-            return type->getResultId();\r
-    }\r
-\r
-    // not found, make it\r
-    type = new Instruction(getUniqueId(), NoType, OpTypeSampler);\r
-    type->addIdOperand(sampledType);\r
-    type->addImmediateOperand(   dim);\r
-    type->addImmediateOperand(content);\r
-    type->addImmediateOperand(arrayed ? 1 : 0);\r
-    type->addImmediateOperand( shadow ? 1 : 0);\r
-    type->addImmediateOperand(     ms ? 1 : 0);\r
-\r
-    groupedTypes[OpTypeSampler].push_back(type);\r
-    constantsTypesGlobals.push_back(type);\r
-    module.mapInstruction(type);\r
-\r
-    return type->getResultId();\r
-}\r
-\r
-Id Builder::getDerefTypeId(Id resultId) const\r
-{\r
-    Id typeId = getTypeId(resultId);\r
-    assert(isPointerType(typeId));\r
-\r
-    return module.getInstruction(typeId)->getImmediateOperand(1);\r
-}\r
-\r
-Op Builder::getMostBasicTypeClass(Id typeId) const\r
-{\r
-    Instruction* instr = module.getInstruction(typeId);\r
-\r
-    Op typeClass = instr->getOpCode();\r
-    switch (typeClass)\r
-    {\r
-    case OpTypeVoid:\r
-    case OpTypeBool:\r
-    case OpTypeInt:\r
-    case OpTypeFloat:\r
-    case OpTypeStruct:\r
-        return typeClass;\r
-    case OpTypeVector:\r
-    case OpTypeMatrix:\r
-    case OpTypeArray:\r
-    case OpTypeRuntimeArray:\r
-        return getMostBasicTypeClass(instr->getIdOperand(0));\r
-    case OpTypePointer:\r
-        return getMostBasicTypeClass(instr->getIdOperand(1));\r
-    default:\r
-        MissingFunctionality("getMostBasicTypeClass");\r
-        return OpTypeFloat;\r
-    }\r
-}\r
-\r
-int Builder::getNumTypeComponents(Id typeId) const\r
-{\r
-    Instruction* instr = module.getInstruction(typeId);\r
-\r
-    switch (instr->getOpCode())\r
-    {\r
-    case OpTypeBool:\r
-    case OpTypeInt:\r
-    case OpTypeFloat:\r
-        return 1;\r
-    case OpTypeVector:\r
-    case OpTypeMatrix:\r
-        return instr->getImmediateOperand(1);\r
-    default:\r
-        MissingFunctionality("getNumTypeComponents on non bool/int/float/vector/matrix");\r
-        return 1;\r
-    }\r
-}\r
-\r
-// Return the lowest-level type of scalar that an homogeneous composite is made out of.\r
-// Typically, this is just to find out if something is made out of ints or floats.\r
-// However, it includes returning a structure, if say, it is an array of structure.\r
-Id Builder::getScalarTypeId(Id typeId) const\r
-{\r
-    Instruction* instr = module.getInstruction(typeId);\r
-\r
-    Op typeClass = instr->getOpCode();\r
-    switch (typeClass)\r
-    {\r
-    case OpTypeVoid:\r
-    case OpTypeBool:\r
-    case OpTypeInt:\r
-    case OpTypeFloat:\r
-    case OpTypeStruct:\r
-        return instr->getResultId();\r
-    case OpTypeVector:\r
-    case OpTypeMatrix:\r
-    case OpTypeArray:\r
-    case OpTypeRuntimeArray:\r
-    case OpTypePointer:\r
-        return getScalarTypeId(getContainedTypeId(typeId));\r
-    default:\r
-        MissingFunctionality("getScalarTypeId");\r
-        return NoResult;\r
-    }\r
-}\r
-\r
-// Return the type of 'member' of a composite.\r
-Id Builder::getContainedTypeId(Id typeId, int member) const\r
-{\r
-    Instruction* instr = module.getInstruction(typeId);\r
-\r
-    Op typeClass = instr->getOpCode();\r
-    switch (typeClass)\r
-    {\r
-    case OpTypeVector:\r
-    case OpTypeMatrix:\r
-    case OpTypeArray:\r
-    case OpTypeRuntimeArray:\r
-        return instr->getIdOperand(0);\r
-    case OpTypePointer:\r
-        return instr->getIdOperand(1);\r
-    case OpTypeStruct:\r
-        return instr->getIdOperand(member);\r
-    default:\r
-        MissingFunctionality("getContainedTypeId");\r
-        return NoResult;\r
-    }\r
-}\r
-\r
-// Return the immediately contained type of a given composite type.\r
-Id Builder::getContainedTypeId(Id typeId) const\r
-{\r
-    return getContainedTypeId(typeId, 0);\r
-}\r
-\r
-// See if a scalar constant of this type has already been created, so it\r
-// can be reused rather than duplicated.  (Required by the specification).\r
-Id Builder::findScalarConstant(Op typeClass, Id typeId, unsigned value) const\r
-{\r
-    Instruction* constant;\r
-    for (int i = 0; i < (int)groupedConstants[typeClass].size(); ++i) {\r
-        constant = groupedConstants[typeClass][i];\r
-        if (constant->getNumOperands() == 1 &&\r
-            constant->getTypeId() == typeId &&\r
-            constant->getImmediateOperand(0) == value)\r
-            return constant->getResultId();\r
-    }\r
-\r
-    return 0;\r
-}\r
-\r
-// Version of findScalarConstant (see above) for scalars that take two operands (e.g. a 'double').\r
-Id Builder::findScalarConstant(Op typeClass, Id typeId, unsigned v1, unsigned v2) const\r
-{\r
-    Instruction* constant;\r
-    for (int i = 0; i < (int)groupedConstants[typeClass].size(); ++i) {\r
-        constant = groupedConstants[typeClass][i];\r
-        if (constant->getNumOperands() == 2 &&\r
-            constant->getTypeId() == typeId &&\r
-            constant->getImmediateOperand(0) == v1 &&\r
-            constant->getImmediateOperand(1) == v2)\r
-            return constant->getResultId();\r
-    }\r
-\r
-    return 0;\r
-}\r
-\r
-Id Builder::makeBoolConstant(bool b)\r
-{\r
-    Id typeId = makeBoolType();\r
-    Instruction* constant;\r
-\r
-    // See if we already made it\r
-    Id existing = 0;\r
-    for (int i = 0; i < (int)groupedConstants[OpTypeBool].size(); ++i) {\r
-        constant = groupedConstants[OpTypeBool][i];\r
-        if (constant->getTypeId() == typeId &&\r
-            (b ? (constant->getOpCode() == OpConstantTrue) : \r
-                 (constant->getOpCode() == OpConstantFalse)))\r
-            existing = constant->getResultId();\r
-    }\r
-\r
-    if (existing)\r
-        return existing;\r
-\r
-    // Make it\r
-    Instruction* c = new Instruction(getUniqueId(), typeId, b ? OpConstantTrue : OpConstantFalse);\r
-    constantsTypesGlobals.push_back(c);\r
-    groupedConstants[OpTypeBool].push_back(c);\r
-    module.mapInstruction(c);\r
-\r
-    return c->getResultId();\r
-}\r
-\r
-Id Builder::makeIntConstant(Id typeId, unsigned value)\r
-{\r
-    Id existing = findScalarConstant(OpTypeInt, typeId, value);\r
-    if (existing)\r
-        return existing;\r
-\r
-    Instruction* c = new Instruction(getUniqueId(), typeId, OpConstant);\r
-    c->addImmediateOperand(value);\r
-    constantsTypesGlobals.push_back(c);\r
-    groupedConstants[OpTypeInt].push_back(c);\r
-    module.mapInstruction(c);\r
-\r
-    return c->getResultId();\r
-}\r
-\r
-Id Builder::makeFloatConstant(float f)\r
-{\r
-    Id typeId = makeFloatType(32);\r
-    unsigned value = *(unsigned int*)&f;\r
-    Id existing = findScalarConstant(OpTypeFloat, typeId, value);\r
-    if (existing)\r
-        return existing;\r
-\r
-    Instruction* c = new Instruction(getUniqueId(), typeId, OpConstant);\r
-    c->addImmediateOperand(value);\r
-    constantsTypesGlobals.push_back(c);\r
-    groupedConstants[OpTypeFloat].push_back(c);\r
-    module.mapInstruction(c);\r
-\r
-    return c->getResultId();\r
-}\r
-\r
-Id Builder::makeDoubleConstant(double d)\r
-{\r
-    Id typeId = makeFloatType(64);\r
-    unsigned long long value = *(unsigned long long*)&d;\r
-    unsigned op1 = value & 0xFFFFFFFF;\r
-    unsigned op2 = value >> 32;\r
-    Id existing = findScalarConstant(OpTypeFloat, typeId, op1, op2);\r
-    if (existing)\r
-        return existing;\r
-\r
-    Instruction* c = new Instruction(getUniqueId(), typeId, OpConstant);\r
-    c->addImmediateOperand(op1);\r
-    c->addImmediateOperand(op2);\r
-    constantsTypesGlobals.push_back(c);\r
-    groupedConstants[OpTypeFloat].push_back(c);\r
-    module.mapInstruction(c);\r
-\r
-    return c->getResultId();\r
-}\r
-\r
-Id Builder::findCompositeConstant(Op typeClass, std::vector<Id>& comps) const\r
-{\r
-    Instruction* constant = 0;\r
-    bool found = false;\r
-    for (int i = 0; i < (int)groupedConstants[typeClass].size(); ++i) {\r
-        constant = groupedConstants[typeClass][i];\r
-\r
-        // same shape?\r
-        if (constant->getNumOperands() != (int)comps.size())\r
-            continue;\r
-\r
-        // same contents?\r
-        bool mismatch = false;\r
-        for (int op = 0; op < constant->getNumOperands(); ++op) {\r
-            if (constant->getIdOperand(op) != comps[op]) {\r
-                mismatch = true;\r
-                break;\r
-            }\r
-        }\r
-        if (! mismatch) {\r
-            found = true;\r
-            break;\r
-        }\r
-    }\r
-\r
-    return found ? constant->getResultId() : NoResult;\r
-}\r
-\r
-// Comments in header\r
-Id Builder::makeCompositeConstant(Id typeId, std::vector<Id>& members)\r
-{\r
-    assert(typeId);\r
-    Op typeClass = getTypeClass(typeId);\r
-\r
-    switch (typeClass) {\r
-    case OpTypeVector:\r
-    case OpTypeArray:\r
-    case OpTypeStruct:\r
-    case OpTypeMatrix:\r
-        break;\r
-    default:\r
-        MissingFunctionality("Constant composite type in Builder");\r
-        return makeFloatConstant(0.0);\r
-    }\r
-\r
-    Id existing = findCompositeConstant(typeClass, members);\r
-    if (existing)\r
-        return existing;\r
-\r
-    Instruction* c = new Instruction(getUniqueId(), typeId, OpConstantComposite);\r
-    for (int op = 0; op < (int)members.size(); ++op)\r
-        c->addIdOperand(members[op]);\r
-    constantsTypesGlobals.push_back(c);\r
-    groupedConstants[typeClass].push_back(c);\r
-    module.mapInstruction(c);\r
-\r
-    return c->getResultId();\r
-}\r
-\r
-void Builder::addEntryPoint(ExecutionModel model, Function* function)\r
-{\r
-    Instruction* entryPoint = new Instruction(OpEntryPoint);\r
-    entryPoint->addImmediateOperand(model);\r
-    entryPoint->addIdOperand(function->getId());\r
-\r
-    entryPoints.push_back(entryPoint);\r
-}\r
-\r
-void Builder::addExecutionMode(Function* entryPoint, ExecutionMode mode, int value)\r
-{\r
-    // TODO: handle multiple optional arguments\r
-    Instruction* instr = new Instruction(OpExecutionMode);\r
-    instr->addIdOperand(entryPoint->getId());\r
-    instr->addImmediateOperand(mode);\r
-    if (value >= 0)\r
-        instr->addImmediateOperand(value);\r
-\r
-    executionModes.push_back(instr);\r
-}\r
-\r
-void Builder::addName(Id id, const char* string)\r
-{\r
-    Instruction* name = new Instruction(OpName);\r
-    name->addIdOperand(id);\r
-    name->addStringOperand(string);\r
-\r
-    names.push_back(name);\r
-}\r
-\r
-void Builder::addMemberName(Id id, int memberNumber, const char* string)\r
-{\r
-    Instruction* name = new Instruction(OpMemberName);\r
-    name->addIdOperand(id);\r
-    name->addImmediateOperand(memberNumber);\r
-    name->addStringOperand(string);\r
-\r
-    names.push_back(name);\r
-}\r
-\r
-void Builder::addLine(Id target, Id fileName, int lineNum, int column)\r
-{\r
-    Instruction* line = new Instruction(OpLine);\r
-    line->addIdOperand(target);\r
-    line->addIdOperand(fileName);\r
-    line->addImmediateOperand(lineNum);\r
-    line->addImmediateOperand(column);\r
-\r
-    lines.push_back(line);\r
-}\r
-\r
-void Builder::addDecoration(Id id, Decoration decoration, int num)\r
-{\r
-    Instruction* dec = new Instruction(OpDecorate);\r
-    dec->addIdOperand(id);\r
-    dec->addImmediateOperand(decoration);\r
-    if (num >= 0)\r
-        dec->addImmediateOperand(num);\r
-\r
-    decorations.push_back(dec);\r
-}\r
-\r
-void Builder::addMemberDecoration(Id id, unsigned int member, Decoration decoration, int num)\r
-{\r
-    Instruction* dec = new Instruction(OpMemberDecorate);\r
-    dec->addIdOperand(id);\r
-    dec->addImmediateOperand(member);\r
-    dec->addImmediateOperand(decoration);\r
-    if (num >= 0)\r
-        dec->addImmediateOperand(num);\r
-\r
-    decorations.push_back(dec);\r
-}\r
-\r
-// Comments in header\r
-Function* Builder::makeMain()\r
-{\r
-    assert(! mainFunction);\r
-\r
-    Block* entry;\r
-    std::vector<Id> params;\r
-\r
-    mainFunction = makeFunctionEntry(makeVoidType(), "main", params, &entry);\r
-    stageExit = new Block(getUniqueId(), *mainFunction);\r
-\r
-    return mainFunction;\r
-}\r
-\r
-// Comments in header\r
-void Builder::closeMain()\r
-{\r
-    setBuildPoint(stageExit);\r
-    stageExit->addInstruction(new Instruction(NoResult, NoType, OpReturn));\r
-    mainFunction->addBlock(stageExit);\r
-}\r
-\r
-// Comments in header\r
-Function* Builder::makeFunctionEntry(Id returnType, const char* name, std::vector<Id>& paramTypes, Block **entry)\r
-{\r
-    Id typeId = makeFunctionType(returnType, paramTypes);\r
-    Id firstParamId = paramTypes.size() == 0 ? 0 : getUniqueIds(paramTypes.size());\r
-    Function* function = new Function(getUniqueId(), returnType, typeId, firstParamId, module);\r
-\r
-    if (entry) {\r
-        *entry = new Block(getUniqueId(), *function);\r
-        function->addBlock(*entry);\r
-        setBuildPoint(*entry);\r
-    }\r
-\r
-    if (name)\r
-        addName(function->getId(), name);\r
-\r
-    return function;\r
-}\r
-\r
-// Comments in header\r
-void Builder::makeReturn(bool implicit, Id retVal, bool isMain)\r
-{\r
-    if (isMain && retVal)\r
-        MissingFunctionality("return value from main()");\r
-\r
-    if (isMain)\r
-        createBranch(stageExit);\r
-    else if (retVal) {\r
-        Instruction* inst = new Instruction(NoResult, NoType, OpReturnValue);\r
-        inst->addIdOperand(retVal);\r
-        buildPoint->addInstruction(inst);\r
-    } else\r
-        buildPoint->addInstruction(new Instruction(NoResult, NoType, OpReturn));\r
-\r
-    if (! implicit)\r
-        createAndSetNoPredecessorBlock("post-return");\r
-}\r
-\r
-// Comments in header\r
-void Builder::leaveFunction(bool main)\r
-{\r
-    Block* block = buildPoint;\r
-    Function& function = buildPoint->getParent();\r
-    assert(block);\r
-\r
-    // If our function did not contain a return, add a return void now.\r
-    if (! block->isTerminated()) {\r
-\r
-        // Whether we're in an unreachable (non-entry) block.\r
-        bool unreachable = function.getEntryBlock() != block && block->getNumPredecessors() == 0;\r
-\r
-        if (unreachable) {\r
-            // Given that this block is at the end of a function, it must be right after an\r
-            // explicit return, just remove it.\r
-            function.popBlock(block);\r
-        } else if (main)\r
-            makeMainReturn(true);\r
-        else {\r
-            // We're get a return instruction at the end of the current block,\r
-            // which for a non-void function is really error recovery (?), as the source\r
-            // being translated should have had an explicit return, which would have been\r
-            // followed by an unreachable block, which was handled above.\r
-            if (function.getReturnType() == makeVoidType())\r
-                makeReturn(true);\r
-            else {\r
-                Id retStorage = createVariable(StorageClassFunction, function.getReturnType(), "dummyReturn");\r
-                Id retValue = createLoad(retStorage);\r
-                makeReturn(true, retValue);\r
-            }\r
-        }\r
-    }\r
-\r
-    if (main)\r
-        closeMain();\r
-}\r
-\r
-// Comments in header\r
-void Builder::makeDiscard()\r
-{\r
-    buildPoint->addInstruction(new Instruction(OpKill));\r
-    createAndSetNoPredecessorBlock("post-discard");\r
-}\r
-\r
-// Comments in header\r
-Id Builder::createVariable(StorageClass storageClass, Id type, const char* name)\r
-{\r
-    Id pointerType = makePointer(storageClass, type);\r
-    Instruction* inst = new Instruction(getUniqueId(), pointerType, OpVariable);\r
-    inst->addImmediateOperand(storageClass);\r
-\r
-    switch (storageClass) {\r
-    case StorageClassUniformConstant:\r
-    case StorageClassUniform:\r
-    case StorageClassInput:\r
-    case StorageClassOutput:\r
-    case StorageClassWorkgroupLocal:\r
-    case StorageClassPrivateGlobal:\r
-    case StorageClassWorkgroupGlobal:\r
-        constantsTypesGlobals.push_back(inst);\r
-        module.mapInstruction(inst);\r
-        break;\r
-\r
-    case StorageClassFunction:\r
-        // Validation rules require the declaration in the entry block\r
-        buildPoint->getParent().addLocalVariable(inst);\r
-        break;\r
-\r
-    default:\r
-        MissingFunctionality("storage class in createVariable");\r
-        break;\r
-    }\r
-\r
-    if (name)\r
-        addName(inst->getResultId(), name);\r
-\r
-    return inst->getResultId();\r
-}\r
-\r
-// Comments in header\r
-void Builder::createStore(Id rValue, Id lValue)\r
-{\r
-    Instruction* store = new Instruction(OpStore);\r
-    store->addIdOperand(lValue);\r
-    store->addIdOperand(rValue);\r
-    buildPoint->addInstruction(store);\r
-}\r
-\r
-// Comments in header\r
-Id Builder::createLoad(Id lValue)\r
-{\r
-    Instruction* load = new Instruction(getUniqueId(), getDerefTypeId(lValue), OpLoad);\r
-    load->addIdOperand(lValue);\r
-    buildPoint->addInstruction(load);\r
-\r
-    return load->getResultId();\r
-}\r
-\r
-// Comments in header\r
-Id Builder::createAccessChain(StorageClass storageClass, Id base, std::vector<Id>& offsets)\r
-{\r
-    // Figure out the final resulting type.\r
-    spv::Id typeId = getTypeId(base);\r
-    assert(isPointerType(typeId) && offsets.size() > 0);\r
-    typeId = getContainedTypeId(typeId);\r
-    for (int i = 0; i < (int)offsets.size(); ++i) {\r
-        if (isStructType(typeId)) {\r
-            assert(isConstantScalar(offsets[i]));\r
-            typeId = getContainedTypeId(typeId, getConstantScalar(offsets[i]));\r
-        } else\r
-            typeId = getContainedTypeId(typeId, offsets[i]);\r
-    }\r
-    typeId = makePointer(storageClass, typeId);\r
-\r
-    // Make the instruction\r
-    Instruction* chain = new Instruction(getUniqueId(), typeId, OpAccessChain);\r
-    chain->addIdOperand(base);\r
-    for (int i = 0; i < (int)offsets.size(); ++i)\r
-        chain->addIdOperand(offsets[i]);\r
-    buildPoint->addInstruction(chain);\r
-\r
-    return chain->getResultId();\r
-}\r
-\r
-Id Builder::createCompositeExtract(Id composite, Id typeId, unsigned index)\r
-{\r
-    Instruction* extract = new Instruction(getUniqueId(), typeId, OpCompositeExtract);\r
-    extract->addIdOperand(composite);\r
-    extract->addImmediateOperand(index);\r
-    buildPoint->addInstruction(extract);\r
-\r
-    return extract->getResultId();\r
-}\r
-\r
-Id Builder::createCompositeExtract(Id composite, Id typeId, std::vector<unsigned>& indexes)\r
-{\r
-    Instruction* extract = new Instruction(getUniqueId(), typeId, OpCompositeExtract);\r
-    extract->addIdOperand(composite);\r
-    for (int i = 0; i < (int)indexes.size(); ++i)\r
-        extract->addImmediateOperand(indexes[i]);\r
-    buildPoint->addInstruction(extract);\r
-\r
-    return extract->getResultId();\r
-}\r
-\r
-Id Builder::createCompositeInsert(Id object, Id composite, Id typeId, unsigned index)\r
-{\r
-    Instruction* insert = new Instruction(getUniqueId(), typeId, OpCompositeInsert);\r
-    insert->addIdOperand(object);\r
-    insert->addIdOperand(composite);\r
-    insert->addImmediateOperand(index);\r
-    buildPoint->addInstruction(insert);\r
-\r
-    return insert->getResultId();\r
-}\r
-\r
-Id Builder::createCompositeInsert(Id object, Id composite, Id typeId, std::vector<unsigned>& indexes)\r
-{\r
-    Instruction* insert = new Instruction(getUniqueId(), typeId, OpCompositeInsert);\r
-    insert->addIdOperand(object);\r
-    insert->addIdOperand(composite);\r
-    for (int i = 0; i < (int)indexes.size(); ++i)\r
-        insert->addImmediateOperand(indexes[i]);\r
-    buildPoint->addInstruction(insert);\r
-\r
-    return insert->getResultId();\r
-}\r
-\r
-Id Builder::createVectorExtractDynamic(Id vector, Id typeId, Id componentIndex)\r
-{\r
-    Instruction* extract = new Instruction(getUniqueId(), typeId, OpVectorExtractDynamic);\r
-    extract->addIdOperand(vector);\r
-    extract->addIdOperand(componentIndex);\r
-    buildPoint->addInstruction(extract);\r
-\r
-    return extract->getResultId();\r
-}\r
-\r
-Id Builder::createVectorInsertDynamic(Id vector, Id typeId, Id component, Id componentIndex)\r
-{\r
-    Instruction* insert = new Instruction(getUniqueId(), typeId, OpVectorInsertDynamic);\r
-    insert->addIdOperand(vector);\r
-    insert->addIdOperand(component);\r
-    insert->addIdOperand(componentIndex);\r
-    buildPoint->addInstruction(insert);\r
-\r
-    return insert->getResultId();\r
-}\r
-\r
-// An opcode that has no operands, no result id, and no type\r
-void Builder::createNoResultOp(Op opCode)\r
-{\r
-    Instruction* op = new Instruction(opCode);\r
-    buildPoint->addInstruction(op);\r
-}\r
-\r
-// An opcode that has one operand, no result id, and no type\r
-void Builder::createNoResultOp(Op opCode, Id operand)\r
-{\r
-    Instruction* op = new Instruction(opCode);\r
-    op->addIdOperand(operand);\r
-    buildPoint->addInstruction(op);\r
-}\r
-\r
-void Builder::createControlBarrier(unsigned executionScope)\r
-{\r
-    Instruction* op = new Instruction(OpControlBarrier);\r
-    op->addImmediateOperand(executionScope);\r
-    buildPoint->addInstruction(op);\r
-}\r
-\r
-void Builder::createMemoryBarrier(unsigned executionScope, unsigned memorySemantics)\r
-{\r
-    Instruction* op = new Instruction(OpMemoryBarrier);\r
-    op->addImmediateOperand(executionScope);\r
-    op->addImmediateOperand(memorySemantics);\r
-    buildPoint->addInstruction(op);\r
-}\r
-\r
-// An opcode that has one operands, a result id, and a type\r
-Id Builder::createUnaryOp(Op opCode, Id typeId, Id operand)\r
-{\r
-    Instruction* op = new Instruction(getUniqueId(), typeId, opCode);\r
-    op->addIdOperand(operand);\r
-    buildPoint->addInstruction(op);\r
-\r
-    return op->getResultId();\r
-}\r
-\r
-Id Builder::createBinOp(Op opCode, Id typeId, Id left, Id right)\r
-{\r
-    Instruction* op = new Instruction(getUniqueId(), typeId, opCode);\r
-    op->addIdOperand(left);\r
-    op->addIdOperand(right);\r
-    buildPoint->addInstruction(op);\r
-\r
-    return op->getResultId();\r
-}\r
-\r
-Id Builder::createTriOp(Op opCode, Id typeId, Id op1, Id op2, Id op3)\r
-{\r
-    Instruction* op = new Instruction(getUniqueId(), typeId, opCode);\r
-    op->addIdOperand(op1);\r
-    op->addIdOperand(op2);\r
-    op->addIdOperand(op3);\r
-    buildPoint->addInstruction(op);\r
-\r
-    return op->getResultId();\r
-}\r
-\r
-Id Builder::createTernaryOp(Op opCode, Id typeId, Id op1, Id op2, Id op3)\r
-{\r
-    Instruction* op = new Instruction(getUniqueId(), typeId, opCode);\r
-    op->addIdOperand(op1);\r
-    op->addIdOperand(op2);\r
-    op->addIdOperand(op3);\r
-    buildPoint->addInstruction(op);\r
-\r
-    return op->getResultId();\r
-}\r
-\r
-Id Builder::createFunctionCall(spv::Function* function, std::vector<spv::Id>& args)\r
-{\r
-    Instruction* op = new Instruction(getUniqueId(), function->getReturnType(), OpFunctionCall);\r
-    op->addIdOperand(function->getId());\r
-    for (int a = 0; a < (int)args.size(); ++a)\r
-        op->addIdOperand(args[a]);\r
-    buildPoint->addInstruction(op);\r
-\r
-    return op->getResultId();\r
-}\r
-\r
-// Comments in header\r
-Id Builder::createRvalueSwizzle(Id typeId, Id source, std::vector<unsigned>& channels)\r
-{\r
-    if (channels.size() == 1)\r
-        return createCompositeExtract(source, typeId, channels.front());\r
-\r
-    Instruction* swizzle = new Instruction(getUniqueId(), typeId, OpVectorShuffle);\r
-    assert(isVector(source));\r
-    swizzle->addIdOperand(source);\r
-    swizzle->addIdOperand(source);\r
-    for (int i = 0; i < (int)channels.size(); ++i)\r
-        swizzle->addImmediateOperand(channels[i]);\r
-    buildPoint->addInstruction(swizzle);\r
-\r
-    return swizzle->getResultId();\r
-}\r
-\r
-// Comments in header\r
-Id Builder::createLvalueSwizzle(Id typeId, Id target, Id source, std::vector<unsigned>& channels)\r
-{\r
-    assert(getNumComponents(source) == channels.size());\r
-    if (channels.size() == 1 && getNumComponents(source) == 1)\r
-        return createCompositeInsert(source, target, typeId, channels.front());\r
-\r
-    Instruction* swizzle = new Instruction(getUniqueId(), typeId, OpVectorShuffle);\r
-    assert(isVector(source));\r
-    assert(isVector(target));\r
-    swizzle->addIdOperand(target);\r
-    swizzle->addIdOperand(source);\r
-\r
-    // Set up an identity shuffle from the base value to the result value\r
-    unsigned int components[4];\r
-    int numTargetComponents = getNumComponents(target);\r
-    for (int i = 0; i < numTargetComponents; ++i)\r
-        components[i] = i;\r
-\r
-    // Punch in the l-value swizzle\r
-    for (int i = 0; i < (int)channels.size(); ++i)\r
-        components[channels[i]] = numTargetComponents + i;\r
-\r
-    // finish the instruction with these components selectors\r
-    for (int i = 0; i < numTargetComponents; ++i)\r
-        swizzle->addImmediateOperand(components[i]);\r
-    buildPoint->addInstruction(swizzle);\r
-\r
-    return swizzle->getResultId();\r
-}\r
-\r
-// Comments in header\r
-void Builder::promoteScalar(Decoration precision, Id& left, Id& right)\r
-{\r
-    int direction = getNumComponents(right) - getNumComponents(left);\r
-\r
-    if (direction > 0)\r
-        left = smearScalar(precision, left, getTypeId(right));\r
-    else if (direction < 0)\r
-        right = smearScalar(precision, right, getTypeId(left));\r
-\r
-    return;\r
-}\r
-\r
-// Comments in header\r
-Id Builder::smearScalar(Decoration /*precision*/, Id scalar, Id vectorType)\r
-{\r
-    assert(getNumComponents(scalar) == 1);\r
-\r
-    int numComponents = getNumTypeComponents(vectorType);\r
-    if (numComponents == 1)\r
-        return scalar;\r
-\r
-    Instruction* smear = new Instruction(getUniqueId(), vectorType, OpCompositeConstruct);\r
-    for (int c = 0; c < numComponents; ++c)\r
-        smear->addIdOperand(scalar);\r
-    buildPoint->addInstruction(smear);\r
-\r
-    return smear->getResultId();\r
-}\r
-\r
-// Comments in header\r
-Id Builder::createBuiltinCall(Decoration /*precision*/, Id resultType, Id builtins, int entryPoint, std::vector<Id>& args)\r
-{\r
-    Instruction* inst = new Instruction(getUniqueId(), resultType, OpExtInst);\r
-    inst->addIdOperand(builtins);\r
-    inst->addImmediateOperand(entryPoint);\r
-    for (int arg = 0; arg < (int)args.size(); ++arg)\r
-        inst->addIdOperand(args[arg]);\r
-\r
-    buildPoint->addInstruction(inst);\r
-    return inst->getResultId();\r
-}\r
-\r
-// Accept all parameters needed to create a texture instruction.\r
-// Create the correct instruction based on the inputs, and make the call.\r
-Id Builder::createTextureCall(Decoration precision, Id resultType, bool proj, const TextureParameters& parameters)\r
-{\r
-    static const int maxTextureArgs = 5;\r
-    Id texArgs[maxTextureArgs] = {};\r
-\r
-    //\r
-    // Set up the arguments\r
-    //\r
-\r
-    int numArgs = 0;\r
-    texArgs[numArgs++] = parameters.sampler;\r
-    texArgs[numArgs++] = parameters.coords;\r
-\r
-    if (parameters.gradX) {\r
-        texArgs[numArgs++] = parameters.gradX;\r
-        texArgs[numArgs++] = parameters.gradY;\r
-    }\r
-    if (parameters.lod)\r
-        texArgs[numArgs++] = parameters.lod;\r
-    if (parameters.offset)\r
-        texArgs[numArgs++] = parameters.offset;\r
-    if (parameters.bias)\r
-        texArgs[numArgs++] = parameters.bias;\r
-    if (parameters.Dref)\r
-        texArgs[numArgs++] = parameters.Dref;\r
-\r
-    //\r
-    // Set up the instruction\r
-    //\r
-\r
-    Op opCode;\r
-    if (proj && parameters.gradX && parameters.offset)\r
-        opCode = OpTextureSampleProjGradOffset;\r
-    else if (proj && parameters.lod && parameters.offset)\r
-        opCode = OpTextureSampleProjLodOffset;\r
-    else if (parameters.gradX && parameters.offset)\r
-        opCode = OpTextureSampleGradOffset;\r
-    else if (proj && parameters.offset)\r
-        opCode = OpTextureSampleProjOffset;\r
-    else if (parameters.lod && parameters.offset)\r
-        opCode = OpTextureSampleLodOffset;\r
-    else if (proj && parameters.gradX)\r
-        opCode = OpTextureSampleProjGrad;\r
-    else if (proj && parameters.lod)\r
-        opCode = OpTextureSampleProjLod;\r
-    else if (parameters.offset)\r
-        opCode = OpTextureSampleOffset;\r
-    else if (parameters.gradX)\r
-        opCode = OpTextureSampleGrad;\r
-    else if (proj)\r
-        opCode = OpTextureSampleProj;\r
-    else if (parameters.lod)\r
-        opCode = OpTextureSampleLod;\r
-    else if (parameters.Dref)\r
-        opCode = OpTextureSampleDref;\r
-    else\r
-        opCode = OpTextureSample;\r
-\r
-    Instruction* textureInst = new Instruction(getUniqueId(), resultType, opCode);\r
-    for (int op = 0; op < numArgs; ++op)\r
-        textureInst->addIdOperand(texArgs[op]);\r
-    setPrecision(textureInst->getResultId(), precision);\r
-    buildPoint->addInstruction(textureInst);\r
-\r
-    return textureInst->getResultId();\r
-}\r
-\r
-// Comments in header\r
-Id Builder::createTextureQueryCall(Op opCode, const TextureParameters& parameters)\r
-{\r
-    // Figure out the result type\r
-    Id resultType;\r
-    switch (opCode) {\r
-    case OpTextureQuerySize:\r
-    case OpTextureQuerySizeLod:\r
-    {\r
-        int numComponents;\r
-        switch (getDimensionality(parameters.sampler)) {\r
-        case Dim1D:\r
-        case DimBuffer:\r
-            numComponents = 1;\r
-            break;\r
-        case Dim2D:\r
-        case DimCube:\r
-        case DimRect:\r
-            numComponents = 2;\r
-            break;\r
-        case Dim3D:\r
-            numComponents = 3;\r
-            break;\r
-        default:\r
-            MissingFunctionality("texture query dimensionality");\r
-            break;\r
-        }\r
-        if (isArrayedSampler(parameters.sampler))\r
-            ++numComponents;\r
-        if (numComponents == 1)\r
-            resultType = makeIntType(32);\r
-        else\r
-            resultType = makeVectorType(makeIntType(32), numComponents);\r
-\r
-        break;\r
-    }\r
-    case OpTextureQueryLod:\r
-        resultType = makeVectorType(makeFloatType(32), 2);\r
-        break;\r
-    case OpTextureQueryLevels:\r
-    case OpTextureQuerySamples:\r
-        resultType = makeIntType(32);\r
-        break;\r
-    default:\r
-        MissingFunctionality("Texture query op code");\r
-    }\r
-\r
-    Instruction* query = new Instruction(getUniqueId(), resultType, opCode);\r
-    query->addIdOperand(parameters.sampler);\r
-    if (parameters.coords)\r
-        query->addIdOperand(parameters.coords);\r
-    if (parameters.lod)\r
-        query->addIdOperand(parameters.lod);\r
-    buildPoint->addInstruction(query);\r
-\r
-    return query->getResultId();\r
-}\r
-\r
-// Comments in header\r
-//Id Builder::createSamplePositionCall(Decoration precision, Id returnType, Id sampleIdx)\r
-//{\r
-//    // Return type is only flexible type\r
-//    Function* opCode = (fSamplePosition, returnType);\r
-//\r
-//    Instruction* instr = (opCode, sampleIdx);\r
-//    setPrecision(instr, precision);\r
-//\r
-//    return instr;\r
-//}\r
-\r
-// Comments in header\r
-//Id Builder::createBitFieldExtractCall(Decoration precision, Id id, Id offset, Id bits, bool isSigned)\r
-//{\r
-//    Op opCode = isSigned ? sBitFieldExtract\r
-//                                               : uBitFieldExtract;\r
-//\r
-//    if (isScalar(offset) == false || isScalar(bits) == false)\r
-//        MissingFunctionality("bitFieldExtract operand types");\r
-//\r
-//    // Dest and value are matching flexible types\r
-//    Function* opCode = (opCode, id->getType(), id->getType());\r
-//\r
-//    assert(opCode);\r
-//\r
-//    Instruction* instr = (opCode, id, offset, bits);\r
-//    setPrecision(instr, precision);\r
-//\r
-//    return instr;\r
-//}\r
-\r
-// Comments in header\r
-//Id Builder::createBitFieldInsertCall(Decoration precision, Id base, Id insert, Id offset, Id bits)\r
-//{\r
-//    Op opCode = bitFieldInsert;\r
-//\r
-//    if (isScalar(offset) == false || isScalar(bits) == false)\r
-//        MissingFunctionality("bitFieldInsert operand types");\r
-//\r
-//    // Dest, base, and insert are matching flexible types\r
-//    Function* opCode = (opCode, base->getType(), base->getType(), base->getType());\r
-//\r
-//    assert(opCode);\r
-//\r
-//    Instruction* instr = (opCode, base, insert, offset, bits);\r
-//    setPrecision(instr, precision);\r
-//\r
-//    return instr;\r
-//}\r
-\r
-// Comments in header\r
-Id Builder::createCompare(Decoration precision, Id value1, Id value2, bool equal)\r
-{\r
-    Id boolType = makeBoolType();\r
-    Id valueType = getTypeId(value1);\r
-\r
-    assert(valueType == getTypeId(value2));\r
-    assert(! isScalar(value1));\r
-\r
-    // Vectors\r
-\r
-    if (isVectorType(valueType)) {\r
-        Id boolVectorType = makeVectorType(boolType, getNumTypeComponents(valueType));\r
-        Id boolVector;\r
-        Op op;\r
-        if (getMostBasicTypeClass(valueType) == OpTypeFloat)\r
-            op = equal ? OpFOrdEqual : OpFOrdNotEqual;\r
-        else\r
-            op = equal ? OpIEqual : OpINotEqual;\r
-\r
-        boolVector = createBinOp(op, boolVectorType, value1, value2);\r
-        setPrecision(boolVector, precision);\r
-\r
-        // Reduce vector compares with any() and all().\r
-\r
-        op = equal ? OpAll : OpAny;\r
-\r
-        return createUnaryOp(op, boolType, boolVector);\r
-    }\r
-\r
-    spv::MissingFunctionality("Composite comparison of non-vectors");\r
-\r
-    return NoResult;\r
-\r
-    // Recursively handle aggregates, which include matrices, arrays, and structures\r
-    // and accumulate the results.\r
-\r
-    // Matrices\r
-\r
-    // Arrays\r
-\r
-    //int numElements;\r
-    //const llvm::ArrayType* arrayType = llvm::dyn_cast<llvm::ArrayType>(value1->getType());\r
-    //if (arrayType)\r
-    //    numElements = (int)arrayType->getNumElements();\r
-    //else {\r
-    //    // better be structure\r
-    //    const llvm::StructType* structType = llvm::dyn_cast<llvm::StructType>(value1->getType());\r
-    //    assert(structType);\r
-    //    numElements = structType->getNumElements();\r
-    //}\r
-\r
-    //assert(numElements > 0);\r
-\r
-    //for (int element = 0; element < numElements; ++element) {\r
-    //    // Get intermediate comparison values\r
-    //    llvm::Value* element1 = builder.CreateExtractValue(value1, element, "element1");\r
-    //    setInstructionPrecision(element1, precision);\r
-    //    llvm::Value* element2 = builder.CreateExtractValue(value2, element, "element2");\r
-    //    setInstructionPrecision(element2, precision);\r
-\r
-    //    llvm::Value* subResult = createCompare(precision, element1, element2, equal, "comp");\r
-\r
-    //    // Accumulate intermediate comparison\r
-    //    if (element == 0)\r
-    //        result = subResult;\r
-    //    else {\r
-    //        if (equal)\r
-    //            result = builder.CreateAnd(result, subResult);\r
-    //        else\r
-    //            result = builder.CreateOr(result, subResult);\r
-    //        setInstructionPrecision(result, precision);\r
-    //    }\r
-    //}\r
-\r
-    //return result;\r
-}\r
-\r
-// Comments in header\r
-//Id Builder::createOperation(Decoration precision, Op opCode, Id operand)\r
-//{\r
-//    Op* opCode = 0;\r
-//\r
-//    // Handle special return types here.  Things that don't have same result type as parameter\r
-//    switch (opCode) {\r
-//    case fIsNan:\r
-//    case fIsInf:\r
-//        break;\r
-//    case fFloatBitsToInt:\r
-//        break;\r
-//    case fIntBitsTofloat:\r
-//        break;\r
-//    case fPackSnorm2x16:\r
-//    case fPackUnorm2x16:\r
-//    case fPackHalf2x16:\r
-//        break;\r
-//    case fUnpackUnorm2x16:\r
-//    case fUnpackSnorm2x16:\r
-//    case fUnpackHalf2x16:\r
-//        break;\r
-//\r
-//    case fFrexp:\r
-//    case fLdexp:\r
-//    case fPackUnorm4x8:\r
-//    case fPackSnorm4x8:\r
-//    case fUnpackUnorm4x8:\r
-//    case fUnpackSnorm4x8:\r
-//    case fPackDouble2x32:\r
-//    case fUnpackDouble2x32:\r
-//        break;\r
-//    case fLength:\r
-//       // scalar result type\r
-//       break;\r
-//    case any:\r
-//    case all:\r
-//        // fixed result type\r
-//        break;\r
-//    case fModF:\r
-//        // modf() will return a struct that the caller must decode\r
-//        break;\r
-//    default:\r
-//        // Unary operations that have operand and dest with same flexible type\r
-//        break;\r
-//    }\r
-//\r
-//    assert(opCode);\r
-//\r
-//    Instruction* instr = (opCode, operand);\r
-//    setPrecision(instr, precision);\r
-//\r
-//    return instr;\r
-//}\r
-//\r
-//// Comments in header\r
-//Id Builder::createOperation(Decoration precision, Op opCode, Id operand0, Id operand1)\r
-//{\r
-//    Function* opCode = 0;\r
-//\r
-//    // Handle special return types here.  Things that don't have same result type as parameter\r
-//    switch (opCode) {\r
-//    case fDistance:\r
-//    case fDot2:\r
-//    case fDot3:\r
-//    case fDot4:\r
-//        // scalar result type\r
-//        break;\r
-//    case fStep:\r
-//        // first argument can be scalar, return and second argument match\r
-//        break;\r
-//    case fSmoothStep:\r
-//        // first argument can be scalar, return and second argument match\r
-//        break;\r
-//    default:\r
-//        // Binary operations that have operand and dest with same flexible type\r
-//        break;\r
-//    }\r
-//\r
-//    assert(opCode);\r
-//\r
-//    Instruction* instr = (opCode, operand0, operand1);\r
-//    setPrecision(instr, precision);\r
-//\r
-//    return instr;\r
-//}\r
-//\r
-//Id Builder::createOperation(Decoration precision, Op opCode, Id operand0, Id operand1, Id operand2)\r
-//{\r
-//    Function* opCode;\r
-//\r
-//    // Handle special return types here.  Things that don't have same result type as parameter\r
-//    switch (opCode) {\r
-//    case fSmoothStep:\r
-//        // first argument can be scalar, return and second argument match\r
-//        break;\r
-//    default:\r
-//        // Use operand0 type as result type\r
-//        break;\r
-//    }\r
-//\r
-//    assert(opCode);\r
-//\r
-//    Instruction* instr = (opCode, operand0, operand1, operand2);\r
-//    setPrecision(instr, precision);\r
-//\r
-//    return instr;\r
-//}\r
-\r
-// OpCompositeConstruct\r
-Id Builder::createCompositeConstruct(Id typeId, std::vector<Id>& constituents)\r
-{\r
-    assert(isAggregateType(typeId) || getNumTypeComponents(typeId) > 1 && getNumTypeComponents(typeId) == constituents.size());\r
-\r
-    Instruction* op = new Instruction(getUniqueId(), typeId, OpCompositeConstruct);\r
-    for (int c = 0; c < (int)constituents.size(); ++c)\r
-        op->addIdOperand(constituents[c]);\r
-    buildPoint->addInstruction(op);\r
-\r
-    return op->getResultId();\r
-}\r
-\r
-// Vector or scalar constructor\r
-Id Builder::createConstructor(Decoration precision, const std::vector<Id>& sources, Id resultTypeId)\r
-{\r
-    Id result = 0;\r
-    unsigned int numTargetComponents = getNumTypeComponents(resultTypeId);\r
-    unsigned int targetComponent = 0;\r
-\r
-    // Special case: when calling a vector constructor with a single scalar\r
-    // argument, smear the scalar\r
-    if (sources.size() == 1 && isScalar(sources[0]) && numTargetComponents > 1)\r
-        return smearScalar(precision, sources[0], resultTypeId);\r
-\r
-    Id scalarTypeId = getScalarTypeId(resultTypeId);\r
-    std::vector<Id> constituents;  // accumulate the arguments for OpCompositeConstruct\r
-    for (unsigned int i = 0; i < sources.size(); ++i) {\r
-        if (isAggregate(sources[i]))\r
-            MissingFunctionality("aggregate in vector constructor");\r
-\r
-        unsigned int sourceSize = getNumComponents(sources[i]);\r
-\r
-        unsigned int sourcesToUse = sourceSize;\r
-        if (sourcesToUse + targetComponent > numTargetComponents)\r
-            sourcesToUse = numTargetComponents - targetComponent;\r
-\r
-        for (unsigned int s = 0; s < sourcesToUse; ++s) {\r
-            Id arg = sources[i];\r
-            if (sourceSize > 1) {\r
-                std::vector<unsigned> swiz;\r
-                swiz.push_back(s);\r
-                arg = createRvalueSwizzle(scalarTypeId, arg, swiz);\r
-            }\r
-\r
-            if (numTargetComponents > 1)\r
-                constituents.push_back(arg);\r
-            else\r
-                result = arg;\r
-            ++targetComponent;\r
-        }\r
-\r
-        if (targetComponent >= numTargetComponents)\r
-            break;\r
-    }\r
-\r
-    if (constituents.size() > 0)\r
-        result = createCompositeConstruct(resultTypeId, constituents);\r
-\r
-    setPrecision(result, precision);\r
-\r
-    return result;\r
-}\r
-\r
-// Comments in header\r
-Id Builder::createMatrixConstructor(Decoration precision, const std::vector<Id>& sources, Id resultTypeId)\r
-{\r
-    Id componentTypeId = getScalarTypeId(resultTypeId);\r
-    int numCols = getTypeNumColumns(resultTypeId);\r
-    int numRows = getTypeNumRows(resultTypeId);\r
-\r
-    // Will use a two step process\r
-    // 1. make a compile-time 2D array of values\r
-    // 2. construct a matrix from that array\r
-\r
-    // Step 1.\r
-\r
-    // initialize the array to the identity matrix\r
-    Id ids[maxMatrixSize][maxMatrixSize];\r
-    Id  one = makeFloatConstant(1.0);\r
-    Id zero = makeFloatConstant(0.0);\r
-    for (int col = 0; col < 4; ++col) {\r
-        for (int row = 0; row < 4; ++row) {\r
-            if (col == row)\r
-                ids[col][row] = one;\r
-            else\r
-                ids[col][row] = zero;\r
-        }\r
-    }\r
-\r
-    // modify components as dictated by the arguments\r
-    if (sources.size() == 1 && isScalar(sources[0])) {\r
-        // a single scalar; resets the diagonals\r
-        for (int col = 0; col < 4; ++col)\r
-            ids[col][col] = sources[0];\r
-    } else if (isMatrix(sources[0])) {\r
-        // constructing from another matrix; copy over the parts that exist in both the argument and constructee\r
-        Id matrix = sources[0];\r
-        int minCols = std::min(numCols, getNumColumns(matrix));\r
-        int minRows = std::min(numRows, getNumRows(matrix));\r
-        for (int col = 0; col < minCols; ++col) {\r
-            std::vector<unsigned> indexes;\r
-            indexes.push_back(col);\r
-            for (int row = 0; row < minRows; ++row) {\r
-                indexes.push_back(row);\r
-                ids[col][row] = createCompositeExtract(matrix, componentTypeId, indexes);\r
-                indexes.pop_back();\r
-                setPrecision(ids[col][row], precision);\r
-            }\r
-        }\r
-    } else {\r
-        // fill in the matrix in column-major order with whatever argument components are available\r
-        int row = 0;\r
-        int col = 0;\r
-\r
-        for (int arg = 0; arg < (int)sources.size(); ++arg) {\r
-            Id argComp = sources[arg];\r
-            for (int comp = 0; comp < getNumComponents(sources[arg]); ++comp) {\r
-                if (getNumComponents(sources[arg]) > 1) {\r
-                    argComp = createCompositeExtract(sources[arg], componentTypeId, comp);\r
-                    setPrecision(argComp, precision);\r
-                }\r
-                ids[col][row++] = argComp;\r
-                if (row == numRows) {\r
-                    row = 0;\r
-                    col++;\r
-                }\r
-            }\r
-        }\r
-    }\r
-\r
-\r
-    // Step 2:  Construct a matrix from that array.\r
-    // First make the column vectors, then make the matrix.\r
-\r
-    // make the column vectors\r
-    Id columnTypeId = getContainedTypeId(resultTypeId);\r
-    std::vector<Id> matrixColumns;\r
-    for (int col = 0; col < numCols; ++col) {\r
-        std::vector<Id> vectorComponents;\r
-        for (int row = 0; row < numRows; ++row)\r
-            vectorComponents.push_back(ids[col][row]);\r
-        matrixColumns.push_back(createCompositeConstruct(columnTypeId, vectorComponents));\r
-    }\r
-\r
-    // make the matrix\r
-    return createCompositeConstruct(resultTypeId, matrixColumns);\r
-}\r
-\r
-// Comments in header\r
-Builder::If::If(Id cond, Builder& gb) :\r
-    builder(gb),\r
-    condition(cond),\r
-    elseBlock(0)\r
-{\r
-    function = &builder.getBuildPoint()->getParent();\r
-\r
-    // make the blocks, but only put the then-block into the function,\r
-    // the else-block and merge-block will be added later, in order, after\r
-    // earlier code is emitted\r
-    thenBlock = new Block(builder.getUniqueId(), *function);\r
-    mergeBlock = new Block(builder.getUniqueId(), *function);\r
-\r
-    // Save the current block, so that we can add in the flow control split when\r
-    // makeEndIf is called.\r
-    headerBlock = builder.getBuildPoint();\r
-\r
-    function->addBlock(thenBlock);\r
-    builder.setBuildPoint(thenBlock);\r
-}\r
-\r
-// Comments in header\r
-void Builder::If::makeBeginElse()\r
-{\r
-    // Close out the "then" by having it jump to the mergeBlock\r
-    builder.createBranch(mergeBlock);\r
-\r
-    // Make the first else block and add it to the function\r
-    elseBlock = new Block(builder.getUniqueId(), *function);\r
-    function->addBlock(elseBlock);\r
-\r
-    // Start building the else block\r
-    builder.setBuildPoint(elseBlock);\r
-}\r
-\r
-// Comments in header\r
-void Builder::If::makeEndIf()\r
-{\r
-    // jump to the merge block\r
-    builder.createBranch(mergeBlock);\r
-\r
-    // Go back to the headerBlock and make the flow control split\r
-    builder.setBuildPoint(headerBlock);\r
-    builder.createMerge(OpSelectionMerge, mergeBlock, SelectionControlMaskNone);\r
-    if (elseBlock)\r
-        builder.createConditionalBranch(condition, thenBlock, elseBlock);\r
-    else\r
-        builder.createConditionalBranch(condition, thenBlock, mergeBlock);\r
-\r
-    // add the merge block to the function\r
-    function->addBlock(mergeBlock);\r
-    builder.setBuildPoint(mergeBlock);\r
-}\r
-\r
-// Comments in header\r
-void Builder::makeSwitch(Id selector, int numSegments, std::vector<int>& caseValues, std::vector<int>& valueIndexToSegment, int defaultSegment,\r
-                         std::vector<Block*>& segmentBlocks)\r
-{\r
-    Function& function = buildPoint->getParent();\r
-\r
-    // make all the blocks\r
-    for (int s = 0; s < numSegments; ++s)\r
-        segmentBlocks.push_back(new Block(getUniqueId(), function));\r
-\r
-    Block* mergeBlock = new Block(getUniqueId(), function);\r
-\r
-    // make and insert the switch's selection-merge instruction\r
-    createMerge(OpSelectionMerge, mergeBlock, SelectionControlMaskNone);\r
-\r
-    // make the switch instruction\r
-    Instruction* switchInst = new Instruction(NoResult, NoType, OpSwitch);\r
-    switchInst->addIdOperand(selector);\r
-    switchInst->addIdOperand(defaultSegment >= 0 ? segmentBlocks[defaultSegment]->getId() : mergeBlock->getId());\r
-    for (int i = 0; i < (int)caseValues.size(); ++i) {\r
-        switchInst->addImmediateOperand(caseValues[i]);\r
-        switchInst->addIdOperand(segmentBlocks[valueIndexToSegment[i]]->getId());\r
-    }\r
-    buildPoint->addInstruction(switchInst);\r
-\r
-    // push the merge block\r
-    switchMerges.push(mergeBlock);\r
-}\r
-\r
-// Comments in header\r
-void Builder::addSwitchBreak()\r
-{\r
-    // branch to the top of the merge block stack\r
-    createBranch(switchMerges.top());\r
-    createAndSetNoPredecessorBlock("post-switch-break");\r
-}\r
-\r
-// Comments in header\r
-void Builder::nextSwitchSegment(std::vector<Block*>& segmentBlock, int nextSegment)\r
-{\r
-    int lastSegment = nextSegment - 1;\r
-    if (lastSegment >= 0) {\r
-        // Close out previous segment by jumping, if necessary, to next segment\r
-        if (! buildPoint->isTerminated())\r
-            createBranch(segmentBlock[nextSegment]);\r
-    }\r
-    Block* block = segmentBlock[nextSegment];\r
-    block->getParent().addBlock(block);\r
-    setBuildPoint(block);\r
-}\r
-\r
-// Comments in header\r
-void Builder::endSwitch(std::vector<Block*>& /*segmentBlock*/)\r
-{\r
-    // Close out previous segment by jumping, if necessary, to next segment\r
-    if (! buildPoint->isTerminated())\r
-        addSwitchBreak();\r
-\r
-    switchMerges.top()->getParent().addBlock(switchMerges.top());\r
-    setBuildPoint(switchMerges.top());\r
-\r
-    switchMerges.pop();\r
-}\r
-\r
-// Comments in header\r
-void Builder::makeNewLoop()\r
-{\r
-    Loop loop = { };\r
-\r
-    loop.function = &getBuildPoint()->getParent();\r
-    loop.header = new Block(getUniqueId(), *loop.function);\r
-    loop.merge  = new Block(getUniqueId(), *loop.function);\r
-    loop.test   = NULL;\r
-\r
-    loops.push(loop);\r
-\r
-    // Branch into the loop\r
-    createBranch(loop.header);\r
-\r
-    // Set ourselves inside the loop\r
-    loop.function->addBlock(loop.header);\r
-    setBuildPoint(loop.header);\r
-}\r
-\r
-void Builder::createLoopTestBranch(Id condition)\r
-{\r
-    Loop& loop = loops.top();\r
-\r
-    // If loop.test exists, then we've already generated the LoopMerge\r
-    // for this loop.\r
-    if (!loop.test)\r
-      createMerge(OpLoopMerge, loop.merge, LoopControlMaskNone);\r
-\r
-    // Branching to the "body" block will keep control inside\r
-    // the loop.\r
-    Block* body = new Block(getUniqueId(), *loop.function);\r
-    createConditionalBranch(condition, body, loop.merge);\r
-    loop.function->addBlock(body);\r
-    setBuildPoint(body);\r
-}\r
-\r
-void Builder::endLoopHeaderWithoutTest()\r
-{\r
-    Loop& loop = loops.top();\r
-\r
-    createMerge(OpLoopMerge, loop.merge, LoopControlMaskNone);\r
-    Block* body = new Block(getUniqueId(), *loop.function);\r
-    createBranch(body);\r
-    loop.function->addBlock(body);\r
-    setBuildPoint(body);\r
-\r
-    assert(!loop.test);\r
-    loop.test = new Block(getUniqueId(), *loop.function);\r
-}\r
-\r
-void Builder::createBranchToLoopTest()\r
-{\r
-    Loop& loop = loops.top();\r
-    Block* testBlock = loop.test;\r
-    assert(testBlock);\r
-    createBranch(testBlock);\r
-    loop.function->addBlock(testBlock);\r
-    setBuildPoint(testBlock);\r
-}\r
-\r
-void Builder::createLoopContinue()\r
-{\r
-    Loop& loop = loops.top();\r
-    if (loop.test)\r
-      createBranch(loop.test);\r
-    else\r
-      createBranch(loop.header);\r
-    // Set up a block for dead code.\r
-    createAndSetNoPredecessorBlock("post-loop-continue");\r
-}\r
-\r
-// Add an exit (e.g. "break") for the innermost loop that you're in\r
-void Builder::createLoopExit()\r
-{\r
-    createBranch(loops.top().merge);\r
-    // Set up a block for dead code.\r
-    createAndSetNoPredecessorBlock("post-loop-break");\r
-}\r
-\r
-// Close the innermost loop\r
-void Builder::closeLoop()\r
-{\r
-    Loop& loop = loops.top();\r
-\r
-    // Branch back to the top\r
-    createBranch(loop.header);\r
-\r
-    // Add the merge block and set the build point to it\r
-    loop.function->addBlock(loop.merge);\r
-    setBuildPoint(loop.merge);\r
-\r
-    loops.pop();\r
-}\r
-\r
-void Builder::clearAccessChain()\r
-{\r
-    accessChain.base = 0;\r
-    accessChain.indexChain.clear();\r
-    accessChain.instr = 0;\r
-    accessChain.swizzle.clear();\r
-    accessChain.component = 0;\r
-    accessChain.resultType = NoType;\r
-    accessChain.isRValue = false;\r
-}\r
-\r
-// Comments in header\r
-void Builder::accessChainPushSwizzle(std::vector<unsigned>& swizzle)\r
-{\r
-    // if needed, propagate the swizzle for the current access chain\r
-    if (accessChain.swizzle.size()) {\r
-        std::vector<unsigned> oldSwizzle = accessChain.swizzle;\r
-        accessChain.swizzle.resize(0);\r
-        for (unsigned int i = 0; i < swizzle.size(); ++i) {\r
-            accessChain.swizzle.push_back(oldSwizzle[swizzle[i]]);\r
-        }\r
-    } else\r
-        accessChain.swizzle = swizzle;\r
-\r
-    // determine if we need to track this swizzle anymore\r
-    simplifyAccessChainSwizzle();\r
-}\r
-\r
-// Comments in header\r
-void Builder::accessChainStore(Id rvalue)\r
-{\r
-    assert(accessChain.isRValue == false);\r
-\r
-    Id base = collapseAccessChain();\r
-\r
-    if (accessChain.swizzle.size() && accessChain.component)\r
-        MissingFunctionality("simultaneous l-value swizzle and dynamic component selection");\r
-\r
-    // If swizzle exists, it is out-of-order or not full, we must load the target vector,\r
-    // extract and insert elements to perform writeMask and/or swizzle.\r
-    Id source = NoResult;\r
-    if (accessChain.swizzle.size()) {\r
-        Id tempBaseId = createLoad(base);\r
-        source = createLvalueSwizzle(getTypeId(tempBaseId), tempBaseId, rvalue, accessChain.swizzle);\r
-    }\r
-\r
-    // dynamic component selection\r
-    if (accessChain.component) {\r
-        Id tempBaseId = (source == NoResult) ? createLoad(base) : source;\r
-        source = createVectorInsertDynamic(tempBaseId, getTypeId(tempBaseId), rvalue, accessChain.component);\r
-    }\r
-\r
-    if (source == NoResult)\r
-        source = rvalue;\r
-\r
-    createStore(source, base);\r
-}\r
-\r
-// Comments in header\r
-Id Builder::accessChainLoad(Decoration /*precision*/)\r
-{\r
-    Id id;\r
-\r
-    if (accessChain.isRValue) {\r
-        if (accessChain.indexChain.size() > 0) {\r
-            mergeAccessChainSwizzle();  // TODO: optimization: look at applying this optimization more widely\r
-            // if all the accesses are constants, we can use OpCompositeExtract\r
-            std::vector<unsigned> indexes;\r
-            bool constant = true;\r
-            for (int i = 0; i < (int)accessChain.indexChain.size(); ++i) {\r
-                if (isConstantScalar(accessChain.indexChain[i]))\r
-                    indexes.push_back(getConstantScalar(accessChain.indexChain[i]));\r
-                else {\r
-                    constant = false;\r
-                    break;\r
-                }\r
-            }\r
-\r
-            if (constant)\r
-                id = createCompositeExtract(accessChain.base, accessChain.resultType, indexes);\r
-            else {\r
-                // make a new function variable for this r-value\r
-                Id lValue = createVariable(StorageClassFunction, getTypeId(accessChain.base), "indexable");\r
-\r
-                // store into it\r
-                createStore(accessChain.base, lValue);\r
-\r
-                // move base to the new variable\r
-                accessChain.base = lValue;\r
-                accessChain.isRValue = false;\r
-\r
-                // load through the access chain\r
-                id = createLoad(collapseAccessChain());\r
-            }\r
-        } else\r
-            id = accessChain.base;\r
-    } else {\r
-        // load through the access chain\r
-        id = createLoad(collapseAccessChain());\r
-    }\r
-\r
-    // Done, unless there are swizzles to do\r
-    if (accessChain.swizzle.size() == 0 && accessChain.component == 0)\r
-        return id;\r
-\r
-    Id componentType = getScalarTypeId(accessChain.resultType);\r
-\r
-    // Do remaining swizzling\r
-    // First, static swizzling\r
-    if (accessChain.swizzle.size()) {\r
-        // static swizzle\r
-        Id resultType = componentType;\r
-        if (accessChain.swizzle.size() > 1)\r
-            resultType = makeVectorType(componentType, accessChain.swizzle.size());\r
-        id = createRvalueSwizzle(resultType, id, accessChain.swizzle);\r
-    }\r
-\r
-    // dynamic single-component selection\r
-    if (accessChain.component)\r
-        id = createVectorExtractDynamic(id, componentType, accessChain.component);\r
-\r
-    return id;\r
-}\r
-\r
-Id Builder::accessChainGetLValue()\r
-{\r
-    assert(accessChain.isRValue == false);\r
-\r
-    Id lvalue = collapseAccessChain();\r
-\r
-    // If swizzle exists, it is out-of-order or not full, we must load the target vector,\r
-    // extract and insert elements to perform writeMask and/or swizzle.  This does not\r
-    // go with getting a direct l-value pointer.\r
-    assert(accessChain.swizzle.size() == 0);\r
-    assert(accessChain.component == spv::NoResult);\r
-\r
-    return lvalue;\r
-}\r
-\r
-void Builder::dump(std::vector<unsigned int>& out) const\r
-{\r
-    // Header, before first instructions:\r
-    out.push_back(MagicNumber);\r
-    out.push_back(Version);\r
-    out.push_back(builderNumber);\r
-    out.push_back(uniqueId + 1);\r
-    out.push_back(0);\r
-\r
-    // First instructions, some created on the spot here:\r
-    if (source != SourceLanguageUnknown) {\r
-        Instruction sourceInst(0, 0, OpSource);\r
-        sourceInst.addImmediateOperand(source);\r
-        sourceInst.addImmediateOperand(sourceVersion);\r
-        sourceInst.dump(out);\r
-    }\r
-    for (int e = 0; e < (int)extensions.size(); ++e) {\r
-        Instruction extInst(0, 0, OpSourceExtension);\r
-        extInst.addStringOperand(extensions[e]);\r
-        extInst.dump(out);\r
-    }\r
-    // TBD: OpExtension ...\r
-    dumpInstructions(out, imports);\r
-    Instruction memInst(0, 0, OpMemoryModel);\r
-    memInst.addImmediateOperand(addressModel);\r
-    memInst.addImmediateOperand(memoryModel);\r
-    memInst.dump(out);\r
-\r
-    // Instructions saved up while building:\r
-    dumpInstructions(out, entryPoints);\r
-    dumpInstructions(out, executionModes);\r
-    dumpInstructions(out, names);\r
-    dumpInstructions(out, lines);\r
-    dumpInstructions(out, decorations);\r
-    dumpInstructions(out, constantsTypesGlobals);\r
-    dumpInstructions(out, externals);\r
-\r
-    // The functions\r
-    module.dump(out);\r
-}\r
-\r
-//\r
-// Protected methods.\r
-//\r
-\r
-Id Builder::collapseAccessChain()\r
-{\r
-    // TODO: bring in an individual component swizzle here, so that a pointer \r
-    // all the way to the component level can be created.\r
-    assert(accessChain.isRValue == false);\r
-\r
-    if (accessChain.indexChain.size() > 0) {\r
-        if (accessChain.instr == 0) {\r
-            StorageClass storageClass = (StorageClass)module.getStorageClass(getTypeId(accessChain.base));\r
-            accessChain.instr = createAccessChain(storageClass, accessChain.base, accessChain.indexChain);\r
-        }\r
-\r
-        return accessChain.instr;\r
-    } else\r
-        return accessChain.base;\r
-}\r
-\r
-// clear out swizzle if it is redundant\r
-void Builder::simplifyAccessChainSwizzle()\r
-{\r
-    // If the swizzle has fewer components than the vector, it is subsetting, and must stay\r
-    // to preserve that fact.\r
-    if (getNumTypeComponents(accessChain.resultType) > (int)accessChain.swizzle.size())\r
-        return;\r
-\r
-    // if components are out of order, it is a swizzle\r
-    for (unsigned int i = 0; i < accessChain.swizzle.size(); ++i) {\r
-        if (i != accessChain.swizzle[i])\r
-            return;\r
-    }\r
-\r
-    // otherwise, there is no need to track this swizzle\r
-    accessChain.swizzle.clear();\r
-}\r
-\r
-// clear out swizzle if it can become part of the indexes\r
-void Builder::mergeAccessChainSwizzle()\r
-{\r
-    // is there even a chance of doing something?  Need a single-component swizzle\r
-    if ((accessChain.swizzle.size() > 1) ||\r
-        (accessChain.swizzle.size() == 0 && accessChain.component == 0))\r
-        return;\r
-\r
-    // TODO: optimization: remove this, but for now confine this to non-dynamic accesses\r
-    // (the above test is correct when this is removed.)\r
-    if (accessChain.component)\r
-        return;\r
-\r
-    // move the swizzle over to the indexes\r
-    if (accessChain.swizzle.size() == 1)\r
-        accessChain.indexChain.push_back(makeUintConstant(accessChain.swizzle.front()));\r
-    else\r
-        accessChain.indexChain.push_back(accessChain.component);\r
-    accessChain.resultType = getScalarTypeId(accessChain.resultType);\r
-\r
-    // now there is no need to track this swizzle\r
-    accessChain.component = NoResult;\r
-    accessChain.swizzle.clear();\r
-}\r
-\r
-// Utility method for creating a new block and setting the insert point to\r
-// be in it. This is useful for flow-control operations that need a "dummy"\r
-// block proceeding them (e.g. instructions after a discard, etc).\r
-void Builder::createAndSetNoPredecessorBlock(const char* /*name*/)\r
-{\r
-    Block* block = new Block(getUniqueId(), buildPoint->getParent());\r
-    block->setUnreachable();\r
-    buildPoint->getParent().addBlock(block);\r
-    setBuildPoint(block);\r
-\r
-    //if (name)\r
-    //    addName(block->getId(), name);\r
-}\r
-\r
-// Comments in header\r
-void Builder::createBranch(Block* block)\r
-{\r
-    Instruction* branch = new Instruction(OpBranch);\r
-    branch->addIdOperand(block->getId());\r
-    buildPoint->addInstruction(branch);\r
-    block->addPredecessor(buildPoint);\r
-}\r
-\r
-void Builder::createMerge(Op mergeCode, Block* mergeBlock, unsigned int control)\r
-{\r
-    Instruction* merge = new Instruction(mergeCode);\r
-    merge->addIdOperand(mergeBlock->getId());\r
-    merge->addImmediateOperand(control);\r
-    buildPoint->addInstruction(merge);\r
-}\r
-\r
-void Builder::createConditionalBranch(Id condition, Block* thenBlock, Block* elseBlock)\r
-{\r
-    Instruction* branch = new Instruction(OpBranchConditional);\r
-    branch->addIdOperand(condition);\r
-    branch->addIdOperand(thenBlock->getId());\r
-    branch->addIdOperand(elseBlock->getId());\r
-    buildPoint->addInstruction(branch);\r
-    thenBlock->addPredecessor(buildPoint);\r
-    elseBlock->addPredecessor(buildPoint);\r
-}\r
-\r
-void Builder::dumpInstructions(std::vector<unsigned int>& out, const std::vector<Instruction*>& instructions) const\r
-{\r
-    for (int i = 0; i < (int)instructions.size(); ++i) {\r
-        instructions[i]->dump(out);\r
-    }\r
-}\r
-\r
-void MissingFunctionality(const char* fun)\r
-{\r
-    printf("Missing functionality: %s\n", fun);\r
-    exit(1);\r
-}\r
-\r
-void ValidationError(const char* error)\r
-{\r
-    printf("Validation Error: %s\n", error);\r
-}\r
-\r
-}; // end spv namespace\r
+//
+//Copyright (C) 2014 LunarG, Inc.
+//
+//All rights reserved.
+//
+//Redistribution and use in source and binary forms, with or without
+//modification, are permitted provided that the following conditions
+//are met:
+//
+//    Redistributions of source code must retain the above copyright
+//    notice, this list of conditions and the following disclaimer.
+//
+//    Redistributions in binary form must reproduce the above
+//    copyright notice, this list of conditions and the following
+//    disclaimer in the documentation and/or other materials provided
+//    with the distribution.
+//
+//    Neither the name of 3Dlabs Inc. Ltd. nor the names of its
+//    contributors may be used to endorse or promote products derived
+//    from this software without specific prior written permission.
+//
+//THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+//"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+//LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+//FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+//COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+//INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+//BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+//LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+//CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+//LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+//ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+//POSSIBILITY OF SUCH DAMAGE.
+
+//
+// Author: John Kessenich, LunarG
+//
+
+//
+// Helper for making SPIR-V IR.  Generally, this is documented in the header
+// SpvBuilder.h.
+//
+
+#include <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "SpvBuilder.h"
+
+#ifndef _WIN32
+    #include <cstdio>
+#endif
+
+namespace spv {
+
+const int SpvBuilderMagic = 0xBB;
+
+Builder::Builder(unsigned int userNumber) :
+    source(SourceLanguageUnknown),
+    sourceVersion(0),
+    addressModel(AddressingModelLogical),
+    memoryModel(MemoryModelGLSL450),
+    builderNumber(userNumber << 16 | SpvBuilderMagic),
+    buildPoint(0),
+    uniqueId(0),
+    mainFunction(0),
+    stageExit(0)
+{
+    clearAccessChain();
+}
+
+Builder::~Builder()
+{
+}
+
+Id Builder::import(const char* name)
+{
+    Instruction* import = new Instruction(getUniqueId(), NoType, OpExtInstImport);
+    import->addStringOperand(name);
+    
+    imports.push_back(import);
+    return import->getResultId();
+}
+
+// For creating new groupedTypes (will return old type if the requested one was already made).
+Id Builder::makeVoidType()
+{
+    Instruction* type;
+    if (groupedTypes[OpTypeVoid].size() == 0) {
+        type = new Instruction(getUniqueId(), NoType, OpTypeVoid);
+        groupedTypes[OpTypeVoid].push_back(type);
+        constantsTypesGlobals.push_back(type);
+        module.mapInstruction(type);
+    } else
+        type = groupedTypes[OpTypeVoid].back();
+
+    return type->getResultId();
+}
+
+Id Builder::makeBoolType()
+{
+    Instruction* type;
+    if (groupedTypes[OpTypeBool].size() == 0) {
+        type = new Instruction(getUniqueId(), NoType, OpTypeBool);
+        groupedTypes[OpTypeBool].push_back(type);
+        constantsTypesGlobals.push_back(type);
+        module.mapInstruction(type);
+    } else
+        type = groupedTypes[OpTypeBool].back();
+
+    return type->getResultId();
+}
+
+Id Builder::makePointer(StorageClass storageClass, Id pointee)
+{
+    // try to find it
+    Instruction* type;
+    for (int t = 0; t < (int)groupedTypes[OpTypePointer].size(); ++t) {
+        type = groupedTypes[OpTypePointer][t];
+        if (type->getImmediateOperand(0) == (unsigned)storageClass &&
+            type->getIdOperand(1) == pointee)
+            return type->getResultId();
+    }
+
+    // not found, make it
+    type = new Instruction(getUniqueId(), NoType, OpTypePointer);
+    type->addImmediateOperand(storageClass);
+    type->addIdOperand(pointee);
+    groupedTypes[OpTypePointer].push_back(type);
+    constantsTypesGlobals.push_back(type);
+    module.mapInstruction(type);
+
+    return type->getResultId();
+}
+
+Id Builder::makeIntegerType(int width, bool hasSign)
+{
+    // try to find it
+    Instruction* type;
+    for (int t = 0; t < (int)groupedTypes[OpTypeInt].size(); ++t) {
+        type = groupedTypes[OpTypeInt][t];
+        if (type->getImmediateOperand(0) == (unsigned)width &&
+            type->getImmediateOperand(1) == (hasSign ? 1u : 0u))
+            return type->getResultId();
+    }
+
+    // not found, make it
+    type = new Instruction(getUniqueId(), NoType, OpTypeInt);
+    type->addImmediateOperand(width);
+    type->addImmediateOperand(hasSign ? 1 : 0);
+    groupedTypes[OpTypeInt].push_back(type);
+    constantsTypesGlobals.push_back(type);
+    module.mapInstruction(type);
+
+    return type->getResultId();
+}
+
+Id Builder::makeFloatType(int width)
+{
+    // try to find it
+    Instruction* type;
+    for (int t = 0; t < (int)groupedTypes[OpTypeFloat].size(); ++t) {
+        type = groupedTypes[OpTypeFloat][t];
+        if (type->getImmediateOperand(0) == (unsigned)width)
+            return type->getResultId();
+    }
+
+    // not found, make it
+    type = new Instruction(getUniqueId(), NoType, OpTypeFloat);
+    type->addImmediateOperand(width);
+    groupedTypes[OpTypeFloat].push_back(type);
+    constantsTypesGlobals.push_back(type);
+    module.mapInstruction(type);
+
+    return type->getResultId();
+}
+
+Id Builder::makeStructType(std::vector<Id>& members, const char* name)
+{
+    // not found, make it
+    Instruction* type = new Instruction(getUniqueId(), NoType, OpTypeStruct);
+    for (int op = 0; op < (int)members.size(); ++op)
+        type->addIdOperand(members[op]);
+    groupedTypes[OpTypeStruct].push_back(type);
+    constantsTypesGlobals.push_back(type);
+    module.mapInstruction(type);
+    addName(type->getResultId(), name);
+
+    return type->getResultId();
+}
+
+Id Builder::makeVectorType(Id component, int size)
+{
+    // try to find it
+    Instruction* type;
+    for (int t = 0; t < (int)groupedTypes[OpTypeVector].size(); ++t) {
+        type = groupedTypes[OpTypeVector][t];
+        if (type->getIdOperand(0) == component &&
+            type->getImmediateOperand(1) == (unsigned)size)
+            return type->getResultId();
+    }
+
+    // not found, make it
+    type = new Instruction(getUniqueId(), NoType, OpTypeVector);
+    type->addIdOperand(component);
+    type->addImmediateOperand(size);
+    groupedTypes[OpTypeVector].push_back(type);
+    constantsTypesGlobals.push_back(type);
+    module.mapInstruction(type);
+
+    return type->getResultId();
+}
+
+Id Builder::makeMatrixType(Id component, int cols, int rows)
+{
+    assert(cols <= maxMatrixSize && rows <= maxMatrixSize);
+
+    Id column = makeVectorType(component, rows);
+
+    // try to find it
+    Instruction* type;
+    for (int t = 0; t < (int)groupedTypes[OpTypeMatrix].size(); ++t) {
+        type = groupedTypes[OpTypeMatrix][t];
+        if (type->getIdOperand(0) == column &&
+            type->getImmediateOperand(1) == (unsigned)cols)
+            return type->getResultId();
+    }
+
+    // not found, make it
+    type = new Instruction(getUniqueId(), NoType, OpTypeMatrix);
+    type->addIdOperand(column);
+    type->addImmediateOperand(cols);
+    groupedTypes[OpTypeMatrix].push_back(type);
+    constantsTypesGlobals.push_back(type);
+    module.mapInstruction(type);
+
+    return type->getResultId();
+}
+
+Id Builder::makeArrayType(Id element, unsigned size)
+{
+    // First, we need a constant instruction for the size
+    Id sizeId = makeUintConstant(size);
+
+    // try to find existing type
+    Instruction* type;
+    for (int t = 0; t < (int)groupedTypes[OpTypeArray].size(); ++t) {
+        type = groupedTypes[OpTypeArray][t];
+        if (type->getIdOperand(0) == element &&
+            type->getIdOperand(1) == sizeId)
+            return type->getResultId();
+    }
+
+    // not found, make it
+    type = new Instruction(getUniqueId(), NoType, OpTypeArray);
+    type->addIdOperand(element);
+    type->addIdOperand(sizeId);
+    groupedTypes[OpTypeArray].push_back(type);
+    constantsTypesGlobals.push_back(type);
+    module.mapInstruction(type);
+
+    return type->getResultId();
+}
+
+Id Builder::makeFunctionType(Id returnType, std::vector<Id>& paramTypes)
+{
+    // try to find it
+    Instruction* type;
+    for (int t = 0; t < (int)groupedTypes[OpTypeFunction].size(); ++t) {
+        type = groupedTypes[OpTypeFunction][t];
+        if (type->getIdOperand(0) != returnType || (int)paramTypes.size() != type->getNumOperands() - 1)
+            continue;
+        bool mismatch = false;
+        for (int p = 0; p < (int)paramTypes.size(); ++p) {
+            if (paramTypes[p] != type->getIdOperand(p + 1)) {
+                mismatch = true;
+                break;
+            }
+        }
+        if (! mismatch)
+            return type->getResultId();            
+    }
+
+    // not found, make it
+    type = new Instruction(getUniqueId(), NoType, OpTypeFunction);
+    type->addIdOperand(returnType);
+    for (int p = 0; p < (int)paramTypes.size(); ++p)
+        type->addIdOperand(paramTypes[p]);
+    groupedTypes[OpTypeFunction].push_back(type);
+    constantsTypesGlobals.push_back(type);
+    module.mapInstruction(type);
+
+    return type->getResultId();
+}
+
+Id Builder::makeSampler(Id sampledType, Dim dim, samplerContent content, bool arrayed, bool shadow, bool ms)
+{
+    // try to find it
+    Instruction* type;
+    for (int t = 0; t < (int)groupedTypes[OpTypeSampler].size(); ++t) {
+        type = groupedTypes[OpTypeSampler][t];
+        if (type->getIdOperand(0) == sampledType &&
+            type->getImmediateOperand(1) == (unsigned int)dim &&
+            type->getImmediateOperand(2) == (unsigned int)content &&
+            type->getImmediateOperand(3) == (arrayed ? 1u : 0u) &&
+            type->getImmediateOperand(4) == ( shadow ? 1u : 0u) &&
+            type->getImmediateOperand(5) == (     ms ? 1u : 0u))
+            return type->getResultId();
+    }
+
+    // not found, make it
+    type = new Instruction(getUniqueId(), NoType, OpTypeSampler);
+    type->addIdOperand(sampledType);
+    type->addImmediateOperand(   dim);
+    type->addImmediateOperand(content);
+    type->addImmediateOperand(arrayed ? 1 : 0);
+    type->addImmediateOperand( shadow ? 1 : 0);
+    type->addImmediateOperand(     ms ? 1 : 0);
+
+    groupedTypes[OpTypeSampler].push_back(type);
+    constantsTypesGlobals.push_back(type);
+    module.mapInstruction(type);
+
+    return type->getResultId();
+}
+
+Id Builder::getDerefTypeId(Id resultId) const
+{
+    Id typeId = getTypeId(resultId);
+    assert(isPointerType(typeId));
+
+    return module.getInstruction(typeId)->getImmediateOperand(1);
+}
+
+Op Builder::getMostBasicTypeClass(Id typeId) const
+{
+    Instruction* instr = module.getInstruction(typeId);
+
+    Op typeClass = instr->getOpCode();
+    switch (typeClass)
+    {
+    case OpTypeVoid:
+    case OpTypeBool:
+    case OpTypeInt:
+    case OpTypeFloat:
+    case OpTypeStruct:
+        return typeClass;
+    case OpTypeVector:
+    case OpTypeMatrix:
+    case OpTypeArray:
+    case OpTypeRuntimeArray:
+        return getMostBasicTypeClass(instr->getIdOperand(0));
+    case OpTypePointer:
+        return getMostBasicTypeClass(instr->getIdOperand(1));
+    default:
+        MissingFunctionality("getMostBasicTypeClass");
+        return OpTypeFloat;
+    }
+}
+
+int Builder::getNumTypeComponents(Id typeId) const
+{
+    Instruction* instr = module.getInstruction(typeId);
+
+    switch (instr->getOpCode())
+    {
+    case OpTypeBool:
+    case OpTypeInt:
+    case OpTypeFloat:
+        return 1;
+    case OpTypeVector:
+    case OpTypeMatrix:
+        return instr->getImmediateOperand(1);
+    default:
+        MissingFunctionality("getNumTypeComponents on non bool/int/float/vector/matrix");
+        return 1;
+    }
+}
+
+// Return the lowest-level type of scalar that an homogeneous composite is made out of.
+// Typically, this is just to find out if something is made out of ints or floats.
+// However, it includes returning a structure, if say, it is an array of structure.
+Id Builder::getScalarTypeId(Id typeId) const
+{
+    Instruction* instr = module.getInstruction(typeId);
+
+    Op typeClass = instr->getOpCode();
+    switch (typeClass)
+    {
+    case OpTypeVoid:
+    case OpTypeBool:
+    case OpTypeInt:
+    case OpTypeFloat:
+    case OpTypeStruct:
+        return instr->getResultId();
+    case OpTypeVector:
+    case OpTypeMatrix:
+    case OpTypeArray:
+    case OpTypeRuntimeArray:
+    case OpTypePointer:
+        return getScalarTypeId(getContainedTypeId(typeId));
+    default:
+        MissingFunctionality("getScalarTypeId");
+        return NoResult;
+    }
+}
+
+// Return the type of 'member' of a composite.
+Id Builder::getContainedTypeId(Id typeId, int member) const
+{
+    Instruction* instr = module.getInstruction(typeId);
+
+    Op typeClass = instr->getOpCode();
+    switch (typeClass)
+    {
+    case OpTypeVector:
+    case OpTypeMatrix:
+    case OpTypeArray:
+    case OpTypeRuntimeArray:
+        return instr->getIdOperand(0);
+    case OpTypePointer:
+        return instr->getIdOperand(1);
+    case OpTypeStruct:
+        return instr->getIdOperand(member);
+    default:
+        MissingFunctionality("getContainedTypeId");
+        return NoResult;
+    }
+}
+
+// Return the immediately contained type of a given composite type.
+Id Builder::getContainedTypeId(Id typeId) const
+{
+    return getContainedTypeId(typeId, 0);
+}
+
+// See if a scalar constant of this type has already been created, so it
+// can be reused rather than duplicated.  (Required by the specification).
+Id Builder::findScalarConstant(Op typeClass, Id typeId, unsigned value) const
+{
+    Instruction* constant;
+    for (int i = 0; i < (int)groupedConstants[typeClass].size(); ++i) {
+        constant = groupedConstants[typeClass][i];
+        if (constant->getNumOperands() == 1 &&
+            constant->getTypeId() == typeId &&
+            constant->getImmediateOperand(0) == value)
+            return constant->getResultId();
+    }
+
+    return 0;
+}
+
+// Version of findScalarConstant (see above) for scalars that take two operands (e.g. a 'double').
+Id Builder::findScalarConstant(Op typeClass, Id typeId, unsigned v1, unsigned v2) const
+{
+    Instruction* constant;
+    for (int i = 0; i < (int)groupedConstants[typeClass].size(); ++i) {
+        constant = groupedConstants[typeClass][i];
+        if (constant->getNumOperands() == 2 &&
+            constant->getTypeId() == typeId &&
+            constant->getImmediateOperand(0) == v1 &&
+            constant->getImmediateOperand(1) == v2)
+            return constant->getResultId();
+    }
+
+    return 0;
+}
+
+Id Builder::makeBoolConstant(bool b)
+{
+    Id typeId = makeBoolType();
+    Instruction* constant;
+
+    // See if we already made it
+    Id existing = 0;
+    for (int i = 0; i < (int)groupedConstants[OpTypeBool].size(); ++i) {
+        constant = groupedConstants[OpTypeBool][i];
+        if (constant->getTypeId() == typeId &&
+            (b ? (constant->getOpCode() == OpConstantTrue) : 
+                 (constant->getOpCode() == OpConstantFalse)))
+            existing = constant->getResultId();
+    }
+
+    if (existing)
+        return existing;
+
+    // Make it
+    Instruction* c = new Instruction(getUniqueId(), typeId, b ? OpConstantTrue : OpConstantFalse);
+    constantsTypesGlobals.push_back(c);
+    groupedConstants[OpTypeBool].push_back(c);
+    module.mapInstruction(c);
+
+    return c->getResultId();
+}
+
+Id Builder::makeIntConstant(Id typeId, unsigned value)
+{
+    Id existing = findScalarConstant(OpTypeInt, typeId, value);
+    if (existing)
+        return existing;
+
+    Instruction* c = new Instruction(getUniqueId(), typeId, OpConstant);
+    c->addImmediateOperand(value);
+    constantsTypesGlobals.push_back(c);
+    groupedConstants[OpTypeInt].push_back(c);
+    module.mapInstruction(c);
+
+    return c->getResultId();
+}
+
+Id Builder::makeFloatConstant(float f)
+{
+    Id typeId = makeFloatType(32);
+    unsigned value = *(unsigned int*)&f;
+    Id existing = findScalarConstant(OpTypeFloat, typeId, value);
+    if (existing)
+        return existing;
+
+    Instruction* c = new Instruction(getUniqueId(), typeId, OpConstant);
+    c->addImmediateOperand(value);
+    constantsTypesGlobals.push_back(c);
+    groupedConstants[OpTypeFloat].push_back(c);
+    module.mapInstruction(c);
+
+    return c->getResultId();
+}
+
+Id Builder::makeDoubleConstant(double d)
+{
+    Id typeId = makeFloatType(64);
+    unsigned long long value = *(unsigned long long*)&d;
+    unsigned op1 = value & 0xFFFFFFFF;
+    unsigned op2 = value >> 32;
+    Id existing = findScalarConstant(OpTypeFloat, typeId, op1, op2);
+    if (existing)
+        return existing;
+
+    Instruction* c = new Instruction(getUniqueId(), typeId, OpConstant);
+    c->addImmediateOperand(op1);
+    c->addImmediateOperand(op2);
+    constantsTypesGlobals.push_back(c);
+    groupedConstants[OpTypeFloat].push_back(c);
+    module.mapInstruction(c);
+
+    return c->getResultId();
+}
+
+Id Builder::findCompositeConstant(Op typeClass, std::vector<Id>& comps) const
+{
+    Instruction* constant = 0;
+    bool found = false;
+    for (int i = 0; i < (int)groupedConstants[typeClass].size(); ++i) {
+        constant = groupedConstants[typeClass][i];
+
+        // same shape?
+        if (constant->getNumOperands() != (int)comps.size())
+            continue;
+
+        // same contents?
+        bool mismatch = false;
+        for (int op = 0; op < constant->getNumOperands(); ++op) {
+            if (constant->getIdOperand(op) != comps[op]) {
+                mismatch = true;
+                break;
+            }
+        }
+        if (! mismatch) {
+            found = true;
+            break;
+        }
+    }
+
+    return found ? constant->getResultId() : NoResult;
+}
+
+// Comments in header
+Id Builder::makeCompositeConstant(Id typeId, std::vector<Id>& members)
+{
+    assert(typeId);
+    Op typeClass = getTypeClass(typeId);
+
+    switch (typeClass) {
+    case OpTypeVector:
+    case OpTypeArray:
+    case OpTypeStruct:
+    case OpTypeMatrix:
+        break;
+    default:
+        MissingFunctionality("Constant composite type in Builder");
+        return makeFloatConstant(0.0);
+    }
+
+    Id existing = findCompositeConstant(typeClass, members);
+    if (existing)
+        return existing;
+
+    Instruction* c = new Instruction(getUniqueId(), typeId, OpConstantComposite);
+    for (int op = 0; op < (int)members.size(); ++op)
+        c->addIdOperand(members[op]);
+    constantsTypesGlobals.push_back(c);
+    groupedConstants[typeClass].push_back(c);
+    module.mapInstruction(c);
+
+    return c->getResultId();
+}
+
+void Builder::addEntryPoint(ExecutionModel model, Function* function)
+{
+    Instruction* entryPoint = new Instruction(OpEntryPoint);
+    entryPoint->addImmediateOperand(model);
+    entryPoint->addIdOperand(function->getId());
+
+    entryPoints.push_back(entryPoint);
+}
+
+void Builder::addExecutionMode(Function* entryPoint, ExecutionMode mode, int value)
+{
+    // TODO: handle multiple optional arguments
+    Instruction* instr = new Instruction(OpExecutionMode);
+    instr->addIdOperand(entryPoint->getId());
+    instr->addImmediateOperand(mode);
+    if (value >= 0)
+        instr->addImmediateOperand(value);
+
+    executionModes.push_back(instr);
+}
+
+void Builder::addName(Id id, const char* string)
+{
+    Instruction* name = new Instruction(OpName);
+    name->addIdOperand(id);
+    name->addStringOperand(string);
+
+    names.push_back(name);
+}
+
+void Builder::addMemberName(Id id, int memberNumber, const char* string)
+{
+    Instruction* name = new Instruction(OpMemberName);
+    name->addIdOperand(id);
+    name->addImmediateOperand(memberNumber);
+    name->addStringOperand(string);
+
+    names.push_back(name);
+}
+
+void Builder::addLine(Id target, Id fileName, int lineNum, int column)
+{
+    Instruction* line = new Instruction(OpLine);
+    line->addIdOperand(target);
+    line->addIdOperand(fileName);
+    line->addImmediateOperand(lineNum);
+    line->addImmediateOperand(column);
+
+    lines.push_back(line);
+}
+
+void Builder::addDecoration(Id id, Decoration decoration, int num)
+{
+    Instruction* dec = new Instruction(OpDecorate);
+    dec->addIdOperand(id);
+    dec->addImmediateOperand(decoration);
+    if (num >= 0)
+        dec->addImmediateOperand(num);
+
+    decorations.push_back(dec);
+}
+
+void Builder::addMemberDecoration(Id id, unsigned int member, Decoration decoration, int num)
+{
+    Instruction* dec = new Instruction(OpMemberDecorate);
+    dec->addIdOperand(id);
+    dec->addImmediateOperand(member);
+    dec->addImmediateOperand(decoration);
+    if (num >= 0)
+        dec->addImmediateOperand(num);
+
+    decorations.push_back(dec);
+}
+
+// Comments in header
+Function* Builder::makeMain()
+{
+    assert(! mainFunction);
+
+    Block* entry;
+    std::vector<Id> params;
+
+    mainFunction = makeFunctionEntry(makeVoidType(), "main", params, &entry);
+    stageExit = new Block(getUniqueId(), *mainFunction);
+
+    return mainFunction;
+}
+
+// Comments in header
+void Builder::closeMain()
+{
+    setBuildPoint(stageExit);
+    stageExit->addInstruction(new Instruction(NoResult, NoType, OpReturn));
+    mainFunction->addBlock(stageExit);
+}
+
+// Comments in header
+Function* Builder::makeFunctionEntry(Id returnType, const char* name, std::vector<Id>& paramTypes, Block **entry)
+{
+    Id typeId = makeFunctionType(returnType, paramTypes);
+    Id firstParamId = paramTypes.size() == 0 ? 0 : getUniqueIds(paramTypes.size());
+    Function* function = new Function(getUniqueId(), returnType, typeId, firstParamId, module);
+
+    if (entry) {
+        *entry = new Block(getUniqueId(), *function);
+        function->addBlock(*entry);
+        setBuildPoint(*entry);
+    }
+
+    if (name)
+        addName(function->getId(), name);
+
+    return function;
+}
+
+// Comments in header
+void Builder::makeReturn(bool implicit, Id retVal, bool isMain)
+{
+    if (isMain && retVal)
+        MissingFunctionality("return value from main()");
+
+    if (isMain)
+        createBranch(stageExit);
+    else if (retVal) {
+        Instruction* inst = new Instruction(NoResult, NoType, OpReturnValue);
+        inst->addIdOperand(retVal);
+        buildPoint->addInstruction(inst);
+    } else
+        buildPoint->addInstruction(new Instruction(NoResult, NoType, OpReturn));
+
+    if (! implicit)
+        createAndSetNoPredecessorBlock("post-return");
+}
+
+// Comments in header
+void Builder::leaveFunction(bool main)
+{
+    Block* block = buildPoint;
+    Function& function = buildPoint->getParent();
+    assert(block);
+
+    // If our function did not contain a return, add a return void now.
+    if (! block->isTerminated()) {
+
+        // Whether we're in an unreachable (non-entry) block.
+        bool unreachable = function.getEntryBlock() != block && block->getNumPredecessors() == 0;
+
+        if (unreachable) {
+            // Given that this block is at the end of a function, it must be right after an
+            // explicit return, just remove it.
+            function.popBlock(block);
+        } else if (main)
+            makeMainReturn(true);
+        else {
+            // We're get a return instruction at the end of the current block,
+            // which for a non-void function is really error recovery (?), as the source
+            // being translated should have had an explicit return, which would have been
+            // followed by an unreachable block, which was handled above.
+            if (function.getReturnType() == makeVoidType())
+                makeReturn(true);
+            else {
+                Id retStorage = createVariable(StorageClassFunction, function.getReturnType(), "dummyReturn");
+                Id retValue = createLoad(retStorage);
+                makeReturn(true, retValue);
+            }
+        }
+    }
+
+    if (main)
+        closeMain();
+}
+
+// Comments in header
+void Builder::makeDiscard()
+{
+    buildPoint->addInstruction(new Instruction(OpKill));
+    createAndSetNoPredecessorBlock("post-discard");
+}
+
+// Comments in header
+Id Builder::createVariable(StorageClass storageClass, Id type, const char* name)
+{
+    Id pointerType = makePointer(storageClass, type);
+    Instruction* inst = new Instruction(getUniqueId(), pointerType, OpVariable);
+    inst->addImmediateOperand(storageClass);
+
+    switch (storageClass) {
+    case StorageClassUniformConstant:
+    case StorageClassUniform:
+    case StorageClassInput:
+    case StorageClassOutput:
+    case StorageClassWorkgroupLocal:
+    case StorageClassPrivateGlobal:
+    case StorageClassWorkgroupGlobal:
+        constantsTypesGlobals.push_back(inst);
+        module.mapInstruction(inst);
+        break;
+
+    case StorageClassFunction:
+        // Validation rules require the declaration in the entry block
+        buildPoint->getParent().addLocalVariable(inst);
+        break;
+
+    default:
+        MissingFunctionality("storage class in createVariable");
+        break;
+    }
+
+    if (name)
+        addName(inst->getResultId(), name);
+
+    return inst->getResultId();
+}
+
+// Comments in header
+void Builder::createStore(Id rValue, Id lValue)
+{
+    Instruction* store = new Instruction(OpStore);
+    store->addIdOperand(lValue);
+    store->addIdOperand(rValue);
+    buildPoint->addInstruction(store);
+}
+
+// Comments in header
+Id Builder::createLoad(Id lValue)
+{
+    Instruction* load = new Instruction(getUniqueId(), getDerefTypeId(lValue), OpLoad);
+    load->addIdOperand(lValue);
+    buildPoint->addInstruction(load);
+
+    return load->getResultId();
+}
+
+// Comments in header
+Id Builder::createAccessChain(StorageClass storageClass, Id base, std::vector<Id>& offsets)
+{
+    // Figure out the final resulting type.
+    spv::Id typeId = getTypeId(base);
+    assert(isPointerType(typeId) && offsets.size() > 0);
+    typeId = getContainedTypeId(typeId);
+    for (int i = 0; i < (int)offsets.size(); ++i) {
+        if (isStructType(typeId)) {
+            assert(isConstantScalar(offsets[i]));
+            typeId = getContainedTypeId(typeId, getConstantScalar(offsets[i]));
+        } else
+            typeId = getContainedTypeId(typeId, offsets[i]);
+    }
+    typeId = makePointer(storageClass, typeId);
+
+    // Make the instruction
+    Instruction* chain = new Instruction(getUniqueId(), typeId, OpAccessChain);
+    chain->addIdOperand(base);
+    for (int i = 0; i < (int)offsets.size(); ++i)
+        chain->addIdOperand(offsets[i]);
+    buildPoint->addInstruction(chain);
+
+    return chain->getResultId();
+}
+
+Id Builder::createCompositeExtract(Id composite, Id typeId, unsigned index)
+{
+    Instruction* extract = new Instruction(getUniqueId(), typeId, OpCompositeExtract);
+    extract->addIdOperand(composite);
+    extract->addImmediateOperand(index);
+    buildPoint->addInstruction(extract);
+
+    return extract->getResultId();
+}
+
+Id Builder::createCompositeExtract(Id composite, Id typeId, std::vector<unsigned>& indexes)
+{
+    Instruction* extract = new Instruction(getUniqueId(), typeId, OpCompositeExtract);
+    extract->addIdOperand(composite);
+    for (int i = 0; i < (int)indexes.size(); ++i)
+        extract->addImmediateOperand(indexes[i]);
+    buildPoint->addInstruction(extract);
+
+    return extract->getResultId();
+}
+
+Id Builder::createCompositeInsert(Id object, Id composite, Id typeId, unsigned index)
+{
+    Instruction* insert = new Instruction(getUniqueId(), typeId, OpCompositeInsert);
+    insert->addIdOperand(object);
+    insert->addIdOperand(composite);
+    insert->addImmediateOperand(index);
+    buildPoint->addInstruction(insert);
+
+    return insert->getResultId();
+}
+
+Id Builder::createCompositeInsert(Id object, Id composite, Id typeId, std::vector<unsigned>& indexes)
+{
+    Instruction* insert = new Instruction(getUniqueId(), typeId, OpCompositeInsert);
+    insert->addIdOperand(object);
+    insert->addIdOperand(composite);
+    for (int i = 0; i < (int)indexes.size(); ++i)
+        insert->addImmediateOperand(indexes[i]);
+    buildPoint->addInstruction(insert);
+
+    return insert->getResultId();
+}
+
+Id Builder::createVectorExtractDynamic(Id vector, Id typeId, Id componentIndex)
+{
+    Instruction* extract = new Instruction(getUniqueId(), typeId, OpVectorExtractDynamic);
+    extract->addIdOperand(vector);
+    extract->addIdOperand(componentIndex);
+    buildPoint->addInstruction(extract);
+
+    return extract->getResultId();
+}
+
+Id Builder::createVectorInsertDynamic(Id vector, Id typeId, Id component, Id componentIndex)
+{
+    Instruction* insert = new Instruction(getUniqueId(), typeId, OpVectorInsertDynamic);
+    insert->addIdOperand(vector);
+    insert->addIdOperand(component);
+    insert->addIdOperand(componentIndex);
+    buildPoint->addInstruction(insert);
+
+    return insert->getResultId();
+}
+
+// An opcode that has no operands, no result id, and no type
+void Builder::createNoResultOp(Op opCode)
+{
+    Instruction* op = new Instruction(opCode);
+    buildPoint->addInstruction(op);
+}
+
+// An opcode that has one operand, no result id, and no type
+void Builder::createNoResultOp(Op opCode, Id operand)
+{
+    Instruction* op = new Instruction(opCode);
+    op->addIdOperand(operand);
+    buildPoint->addInstruction(op);
+}
+
+void Builder::createControlBarrier(unsigned executionScope)
+{
+    Instruction* op = new Instruction(OpControlBarrier);
+    op->addImmediateOperand(executionScope);
+    buildPoint->addInstruction(op);
+}
+
+void Builder::createMemoryBarrier(unsigned executionScope, unsigned memorySemantics)
+{
+    Instruction* op = new Instruction(OpMemoryBarrier);
+    op->addImmediateOperand(executionScope);
+    op->addImmediateOperand(memorySemantics);
+    buildPoint->addInstruction(op);
+}
+
+// An opcode that has one operands, a result id, and a type
+Id Builder::createUnaryOp(Op opCode, Id typeId, Id operand)
+{
+    Instruction* op = new Instruction(getUniqueId(), typeId, opCode);
+    op->addIdOperand(operand);
+    buildPoint->addInstruction(op);
+
+    return op->getResultId();
+}
+
+Id Builder::createBinOp(Op opCode, Id typeId, Id left, Id right)
+{
+    Instruction* op = new Instruction(getUniqueId(), typeId, opCode);
+    op->addIdOperand(left);
+    op->addIdOperand(right);
+    buildPoint->addInstruction(op);
+
+    return op->getResultId();
+}
+
+Id Builder::createTriOp(Op opCode, Id typeId, Id op1, Id op2, Id op3)
+{
+    Instruction* op = new Instruction(getUniqueId(), typeId, opCode);
+    op->addIdOperand(op1);
+    op->addIdOperand(op2);
+    op->addIdOperand(op3);
+    buildPoint->addInstruction(op);
+
+    return op->getResultId();
+}
+
+Id Builder::createTernaryOp(Op opCode, Id typeId, Id op1, Id op2, Id op3)
+{
+    Instruction* op = new Instruction(getUniqueId(), typeId, opCode);
+    op->addIdOperand(op1);
+    op->addIdOperand(op2);
+    op->addIdOperand(op3);
+    buildPoint->addInstruction(op);
+
+    return op->getResultId();
+}
+
+Id Builder::createFunctionCall(spv::Function* function, std::vector<spv::Id>& args)
+{
+    Instruction* op = new Instruction(getUniqueId(), function->getReturnType(), OpFunctionCall);
+    op->addIdOperand(function->getId());
+    for (int a = 0; a < (int)args.size(); ++a)
+        op->addIdOperand(args[a]);
+    buildPoint->addInstruction(op);
+
+    return op->getResultId();
+}
+
+// Comments in header
+Id Builder::createRvalueSwizzle(Id typeId, Id source, std::vector<unsigned>& channels)
+{
+    if (channels.size() == 1)
+        return createCompositeExtract(source, typeId, channels.front());
+
+    Instruction* swizzle = new Instruction(getUniqueId(), typeId, OpVectorShuffle);
+    assert(isVector(source));
+    swizzle->addIdOperand(source);
+    swizzle->addIdOperand(source);
+    for (int i = 0; i < (int)channels.size(); ++i)
+        swizzle->addImmediateOperand(channels[i]);
+    buildPoint->addInstruction(swizzle);
+
+    return swizzle->getResultId();
+}
+
+// Comments in header
+Id Builder::createLvalueSwizzle(Id typeId, Id target, Id source, std::vector<unsigned>& channels)
+{
+    assert(getNumComponents(source) == channels.size());
+    if (channels.size() == 1 && getNumComponents(source) == 1)
+        return createCompositeInsert(source, target, typeId, channels.front());
+
+    Instruction* swizzle = new Instruction(getUniqueId(), typeId, OpVectorShuffle);
+    assert(isVector(source));
+    assert(isVector(target));
+    swizzle->addIdOperand(target);
+    swizzle->addIdOperand(source);
+
+    // Set up an identity shuffle from the base value to the result value
+    unsigned int components[4];
+    int numTargetComponents = getNumComponents(target);
+    for (int i = 0; i < numTargetComponents; ++i)
+        components[i] = i;
+
+    // Punch in the l-value swizzle
+    for (int i = 0; i < (int)channels.size(); ++i)
+        components[channels[i]] = numTargetComponents + i;
+
+    // finish the instruction with these components selectors
+    for (int i = 0; i < numTargetComponents; ++i)
+        swizzle->addImmediateOperand(components[i]);
+    buildPoint->addInstruction(swizzle);
+
+    return swizzle->getResultId();
+}
+
+// Comments in header
+void Builder::promoteScalar(Decoration precision, Id& left, Id& right)
+{
+    int direction = getNumComponents(right) - getNumComponents(left);
+
+    if (direction > 0)
+        left = smearScalar(precision, left, getTypeId(right));
+    else if (direction < 0)
+        right = smearScalar(precision, right, getTypeId(left));
+
+    return;
+}
+
+// Comments in header
+Id Builder::smearScalar(Decoration /*precision*/, Id scalar, Id vectorType)
+{
+    assert(getNumComponents(scalar) == 1);
+
+    int numComponents = getNumTypeComponents(vectorType);
+    if (numComponents == 1)
+        return scalar;
+
+    Instruction* smear = new Instruction(getUniqueId(), vectorType, OpCompositeConstruct);
+    for (int c = 0; c < numComponents; ++c)
+        smear->addIdOperand(scalar);
+    buildPoint->addInstruction(smear);
+
+    return smear->getResultId();
+}
+
+// Comments in header
+Id Builder::createBuiltinCall(Decoration /*precision*/, Id resultType, Id builtins, int entryPoint, std::vector<Id>& args)
+{
+    Instruction* inst = new Instruction(getUniqueId(), resultType, OpExtInst);
+    inst->addIdOperand(builtins);
+    inst->addImmediateOperand(entryPoint);
+    for (int arg = 0; arg < (int)args.size(); ++arg)
+        inst->addIdOperand(args[arg]);
+
+    buildPoint->addInstruction(inst);
+    return inst->getResultId();
+}
+
+// Accept all parameters needed to create a texture instruction.
+// Create the correct instruction based on the inputs, and make the call.
+Id Builder::createTextureCall(Decoration precision, Id resultType, bool proj, const TextureParameters& parameters)
+{
+    static const int maxTextureArgs = 5;
+    Id texArgs[maxTextureArgs] = {};
+
+    //
+    // Set up the arguments
+    //
+
+    int numArgs = 0;
+    texArgs[numArgs++] = parameters.sampler;
+    texArgs[numArgs++] = parameters.coords;
+
+    if (parameters.gradX) {
+        texArgs[numArgs++] = parameters.gradX;
+        texArgs[numArgs++] = parameters.gradY;
+    }
+    if (parameters.lod)
+        texArgs[numArgs++] = parameters.lod;
+    if (parameters.offset)
+        texArgs[numArgs++] = parameters.offset;
+    if (parameters.bias)
+        texArgs[numArgs++] = parameters.bias;
+    if (parameters.Dref)
+        texArgs[numArgs++] = parameters.Dref;
+
+    //
+    // Set up the instruction
+    //
+
+    Op opCode;
+    if (proj && parameters.gradX && parameters.offset)
+        opCode = OpTextureSampleProjGradOffset;
+    else if (proj && parameters.lod && parameters.offset)
+        opCode = OpTextureSampleProjLodOffset;
+    else if (parameters.gradX && parameters.offset)
+        opCode = OpTextureSampleGradOffset;
+    else if (proj && parameters.offset)
+        opCode = OpTextureSampleProjOffset;
+    else if (parameters.lod && parameters.offset)
+        opCode = OpTextureSampleLodOffset;
+    else if (proj && parameters.gradX)
+        opCode = OpTextureSampleProjGrad;
+    else if (proj && parameters.lod)
+        opCode = OpTextureSampleProjLod;
+    else if (parameters.offset)
+        opCode = OpTextureSampleOffset;
+    else if (parameters.gradX)
+        opCode = OpTextureSampleGrad;
+    else if (proj)
+        opCode = OpTextureSampleProj;
+    else if (parameters.lod)
+        opCode = OpTextureSampleLod;
+    else if (parameters.Dref)
+        opCode = OpTextureSampleDref;
+    else
+        opCode = OpTextureSample;
+
+    Instruction* textureInst = new Instruction(getUniqueId(), resultType, opCode);
+    for (int op = 0; op < numArgs; ++op)
+        textureInst->addIdOperand(texArgs[op]);
+    setPrecision(textureInst->getResultId(), precision);
+    buildPoint->addInstruction(textureInst);
+
+    return textureInst->getResultId();
+}
+
+// Comments in header
+Id Builder::createTextureQueryCall(Op opCode, const TextureParameters& parameters)
+{
+    // Figure out the result type
+    Id resultType;
+    switch (opCode) {
+    case OpTextureQuerySize:
+    case OpTextureQuerySizeLod:
+    {
+        int numComponents;
+        switch (getDimensionality(parameters.sampler)) {
+        case Dim1D:
+        case DimBuffer:
+            numComponents = 1;
+            break;
+        case Dim2D:
+        case DimCube:
+        case DimRect:
+            numComponents = 2;
+            break;
+        case Dim3D:
+            numComponents = 3;
+            break;
+        default:
+            MissingFunctionality("texture query dimensionality");
+            break;
+        }
+        if (isArrayedSampler(parameters.sampler))
+            ++numComponents;
+        if (numComponents == 1)
+            resultType = makeIntType(32);
+        else
+            resultType = makeVectorType(makeIntType(32), numComponents);
+
+        break;
+    }
+    case OpTextureQueryLod:
+        resultType = makeVectorType(makeFloatType(32), 2);
+        break;
+    case OpTextureQueryLevels:
+    case OpTextureQuerySamples:
+        resultType = makeIntType(32);
+        break;
+    default:
+        MissingFunctionality("Texture query op code");
+    }
+
+    Instruction* query = new Instruction(getUniqueId(), resultType, opCode);
+    query->addIdOperand(parameters.sampler);
+    if (parameters.coords)
+        query->addIdOperand(parameters.coords);
+    if (parameters.lod)
+        query->addIdOperand(parameters.lod);
+    buildPoint->addInstruction(query);
+
+    return query->getResultId();
+}
+
+// Comments in header
+//Id Builder::createSamplePositionCall(Decoration precision, Id returnType, Id sampleIdx)
+//{
+//    // Return type is only flexible type
+//    Function* opCode = (fSamplePosition, returnType);
+//
+//    Instruction* instr = (opCode, sampleIdx);
+//    setPrecision(instr, precision);
+//
+//    return instr;
+//}
+
+// Comments in header
+//Id Builder::createBitFieldExtractCall(Decoration precision, Id id, Id offset, Id bits, bool isSigned)
+//{
+//    Op opCode = isSigned ? sBitFieldExtract
+//                                               : uBitFieldExtract;
+//
+//    if (isScalar(offset) == false || isScalar(bits) == false)
+//        MissingFunctionality("bitFieldExtract operand types");
+//
+//    // Dest and value are matching flexible types
+//    Function* opCode = (opCode, id->getType(), id->getType());
+//
+//    assert(opCode);
+//
+//    Instruction* instr = (opCode, id, offset, bits);
+//    setPrecision(instr, precision);
+//
+//    return instr;
+//}
+
+// Comments in header
+//Id Builder::createBitFieldInsertCall(Decoration precision, Id base, Id insert, Id offset, Id bits)
+//{
+//    Op opCode = bitFieldInsert;
+//
+//    if (isScalar(offset) == false || isScalar(bits) == false)
+//        MissingFunctionality("bitFieldInsert operand types");
+//
+//    // Dest, base, and insert are matching flexible types
+//    Function* opCode = (opCode, base->getType(), base->getType(), base->getType());
+//
+//    assert(opCode);
+//
+//    Instruction* instr = (opCode, base, insert, offset, bits);
+//    setPrecision(instr, precision);
+//
+//    return instr;
+//}
+
+// Comments in header
+Id Builder::createCompare(Decoration precision, Id value1, Id value2, bool equal)
+{
+    Id boolType = makeBoolType();
+    Id valueType = getTypeId(value1);
+
+    assert(valueType == getTypeId(value2));
+    assert(! isScalar(value1));
+
+    // Vectors
+
+    if (isVectorType(valueType)) {
+        Id boolVectorType = makeVectorType(boolType, getNumTypeComponents(valueType));
+        Id boolVector;
+        Op op;
+        if (getMostBasicTypeClass(valueType) == OpTypeFloat)
+            op = equal ? OpFOrdEqual : OpFOrdNotEqual;
+        else
+            op = equal ? OpIEqual : OpINotEqual;
+
+        boolVector = createBinOp(op, boolVectorType, value1, value2);
+        setPrecision(boolVector, precision);
+
+        // Reduce vector compares with any() and all().
+
+        op = equal ? OpAll : OpAny;
+
+        return createUnaryOp(op, boolType, boolVector);
+    }
+
+    spv::MissingFunctionality("Composite comparison of non-vectors");
+
+    return NoResult;
+
+    // Recursively handle aggregates, which include matrices, arrays, and structures
+    // and accumulate the results.
+
+    // Matrices
+
+    // Arrays
+
+    //int numElements;
+    //const llvm::ArrayType* arrayType = llvm::dyn_cast<llvm::ArrayType>(value1->getType());
+    //if (arrayType)
+    //    numElements = (int)arrayType->getNumElements();
+    //else {
+    //    // better be structure
+    //    const llvm::StructType* structType = llvm::dyn_cast<llvm::StructType>(value1->getType());
+    //    assert(structType);
+    //    numElements = structType->getNumElements();
+    //}
+
+    //assert(numElements > 0);
+
+    //for (int element = 0; element < numElements; ++element) {
+    //    // Get intermediate comparison values
+    //    llvm::Value* element1 = builder.CreateExtractValue(value1, element, "element1");
+    //    setInstructionPrecision(element1, precision);
+    //    llvm::Value* element2 = builder.CreateExtractValue(value2, element, "element2");
+    //    setInstructionPrecision(element2, precision);
+
+    //    llvm::Value* subResult = createCompare(precision, element1, element2, equal, "comp");
+
+    //    // Accumulate intermediate comparison
+    //    if (element == 0)
+    //        result = subResult;
+    //    else {
+    //        if (equal)
+    //            result = builder.CreateAnd(result, subResult);
+    //        else
+    //            result = builder.CreateOr(result, subResult);
+    //        setInstructionPrecision(result, precision);
+    //    }
+    //}
+
+    //return result;
+}
+
+// Comments in header
+//Id Builder::createOperation(Decoration precision, Op opCode, Id operand)
+//{
+//    Op* opCode = 0;
+//
+//    // Handle special return types here.  Things that don't have same result type as parameter
+//    switch (opCode) {
+//    case fIsNan:
+//    case fIsInf:
+//        break;
+//    case fFloatBitsToInt:
+//        break;
+//    case fIntBitsTofloat:
+//        break;
+//    case fPackSnorm2x16:
+//    case fPackUnorm2x16:
+//    case fPackHalf2x16:
+//        break;
+//    case fUnpackUnorm2x16:
+//    case fUnpackSnorm2x16:
+//    case fUnpackHalf2x16:
+//        break;
+//
+//    case fFrexp:
+//    case fLdexp:
+//    case fPackUnorm4x8:
+//    case fPackSnorm4x8:
+//    case fUnpackUnorm4x8:
+//    case fUnpackSnorm4x8:
+//    case fPackDouble2x32:
+//    case fUnpackDouble2x32:
+//        break;
+//    case fLength:
+//       // scalar result type
+//       break;
+//    case any:
+//    case all:
+//        // fixed result type
+//        break;
+//    case fModF:
+//        // modf() will return a struct that the caller must decode
+//        break;
+//    default:
+//        // Unary operations that have operand and dest with same flexible type
+//        break;
+//    }
+//
+//    assert(opCode);
+//
+//    Instruction* instr = (opCode, operand);
+//    setPrecision(instr, precision);
+//
+//    return instr;
+//}
+//
+//// Comments in header
+//Id Builder::createOperation(Decoration precision, Op opCode, Id operand0, Id operand1)
+//{
+//    Function* opCode = 0;
+//
+//    // Handle special return types here.  Things that don't have same result type as parameter
+//    switch (opCode) {
+//    case fDistance:
+//    case fDot2:
+//    case fDot3:
+//    case fDot4:
+//        // scalar result type
+//        break;
+//    case fStep:
+//        // first argument can be scalar, return and second argument match
+//        break;
+//    case fSmoothStep:
+//        // first argument can be scalar, return and second argument match
+//        break;
+//    default:
+//        // Binary operations that have operand and dest with same flexible type
+//        break;
+//    }
+//
+//    assert(opCode);
+//
+//    Instruction* instr = (opCode, operand0, operand1);
+//    setPrecision(instr, precision);
+//
+//    return instr;
+//}
+//
+//Id Builder::createOperation(Decoration precision, Op opCode, Id operand0, Id operand1, Id operand2)
+//{
+//    Function* opCode;
+//
+//    // Handle special return types here.  Things that don't have same result type as parameter
+//    switch (opCode) {
+//    case fSmoothStep:
+//        // first argument can be scalar, return and second argument match
+//        break;
+//    default:
+//        // Use operand0 type as result type
+//        break;
+//    }
+//
+//    assert(opCode);
+//
+//    Instruction* instr = (opCode, operand0, operand1, operand2);
+//    setPrecision(instr, precision);
+//
+//    return instr;
+//}
+
+// OpCompositeConstruct
+Id Builder::createCompositeConstruct(Id typeId, std::vector<Id>& constituents)
+{
+    assert(isAggregateType(typeId) || getNumTypeComponents(typeId) > 1 && getNumTypeComponents(typeId) == constituents.size());
+
+    Instruction* op = new Instruction(getUniqueId(), typeId, OpCompositeConstruct);
+    for (int c = 0; c < (int)constituents.size(); ++c)
+        op->addIdOperand(constituents[c]);
+    buildPoint->addInstruction(op);
+
+    return op->getResultId();
+}
+
+// Vector or scalar constructor
+Id Builder::createConstructor(Decoration precision, const std::vector<Id>& sources, Id resultTypeId)
+{
+    Id result = 0;
+    unsigned int numTargetComponents = getNumTypeComponents(resultTypeId);
+    unsigned int targetComponent = 0;
+
+    // Special case: when calling a vector constructor with a single scalar
+    // argument, smear the scalar
+    if (sources.size() == 1 && isScalar(sources[0]) && numTargetComponents > 1)
+        return smearScalar(precision, sources[0], resultTypeId);
+
+    Id scalarTypeId = getScalarTypeId(resultTypeId);
+    std::vector<Id> constituents;  // accumulate the arguments for OpCompositeConstruct
+    for (unsigned int i = 0; i < sources.size(); ++i) {
+        if (isAggregate(sources[i]))
+            MissingFunctionality("aggregate in vector constructor");
+
+        unsigned int sourceSize = getNumComponents(sources[i]);
+
+        unsigned int sourcesToUse = sourceSize;
+        if (sourcesToUse + targetComponent > numTargetComponents)
+            sourcesToUse = numTargetComponents - targetComponent;
+
+        for (unsigned int s = 0; s < sourcesToUse; ++s) {
+            Id arg = sources[i];
+            if (sourceSize > 1) {
+                std::vector<unsigned> swiz;
+                swiz.push_back(s);
+                arg = createRvalueSwizzle(scalarTypeId, arg, swiz);
+            }
+
+            if (numTargetComponents > 1)
+                constituents.push_back(arg);
+            else
+                result = arg;
+            ++targetComponent;
+        }
+
+        if (targetComponent >= numTargetComponents)
+            break;
+    }
+
+    if (constituents.size() > 0)
+        result = createCompositeConstruct(resultTypeId, constituents);
+
+    setPrecision(result, precision);
+
+    return result;
+}
+
+// Comments in header
+Id Builder::createMatrixConstructor(Decoration precision, const std::vector<Id>& sources, Id resultTypeId)
+{
+    Id componentTypeId = getScalarTypeId(resultTypeId);
+    int numCols = getTypeNumColumns(resultTypeId);
+    int numRows = getTypeNumRows(resultTypeId);
+
+    // Will use a two step process
+    // 1. make a compile-time 2D array of values
+    // 2. construct a matrix from that array
+
+    // Step 1.
+
+    // initialize the array to the identity matrix
+    Id ids[maxMatrixSize][maxMatrixSize];
+    Id  one = makeFloatConstant(1.0);
+    Id zero = makeFloatConstant(0.0);
+    for (int col = 0; col < 4; ++col) {
+        for (int row = 0; row < 4; ++row) {
+            if (col == row)
+                ids[col][row] = one;
+            else
+                ids[col][row] = zero;
+        }
+    }
+
+    // modify components as dictated by the arguments
+    if (sources.size() == 1 && isScalar(sources[0])) {
+        // a single scalar; resets the diagonals
+        for (int col = 0; col < 4; ++col)
+            ids[col][col] = sources[0];
+    } else if (isMatrix(sources[0])) {
+        // constructing from another matrix; copy over the parts that exist in both the argument and constructee
+        Id matrix = sources[0];
+        int minCols = std::min(numCols, getNumColumns(matrix));
+        int minRows = std::min(numRows, getNumRows(matrix));
+        for (int col = 0; col < minCols; ++col) {
+            std::vector<unsigned> indexes;
+            indexes.push_back(col);
+            for (int row = 0; row < minRows; ++row) {
+                indexes.push_back(row);
+                ids[col][row] = createCompositeExtract(matrix, componentTypeId, indexes);
+                indexes.pop_back();
+                setPrecision(ids[col][row], precision);
+            }
+        }
+    } else {
+        // fill in the matrix in column-major order with whatever argument components are available
+        int row = 0;
+        int col = 0;
+
+        for (int arg = 0; arg < (int)sources.size(); ++arg) {
+            Id argComp = sources[arg];
+            for (int comp = 0; comp < getNumComponents(sources[arg]); ++comp) {
+                if (getNumComponents(sources[arg]) > 1) {
+                    argComp = createCompositeExtract(sources[arg], componentTypeId, comp);
+                    setPrecision(argComp, precision);
+                }
+                ids[col][row++] = argComp;
+                if (row == numRows) {
+                    row = 0;
+                    col++;
+                }
+            }
+        }
+    }
+
+
+    // Step 2:  Construct a matrix from that array.
+    // First make the column vectors, then make the matrix.
+
+    // make the column vectors
+    Id columnTypeId = getContainedTypeId(resultTypeId);
+    std::vector<Id> matrixColumns;
+    for (int col = 0; col < numCols; ++col) {
+        std::vector<Id> vectorComponents;
+        for (int row = 0; row < numRows; ++row)
+            vectorComponents.push_back(ids[col][row]);
+        matrixColumns.push_back(createCompositeConstruct(columnTypeId, vectorComponents));
+    }
+
+    // make the matrix
+    return createCompositeConstruct(resultTypeId, matrixColumns);
+}
+
+// Comments in header
+Builder::If::If(Id cond, Builder& gb) :
+    builder(gb),
+    condition(cond),
+    elseBlock(0)
+{
+    function = &builder.getBuildPoint()->getParent();
+
+    // make the blocks, but only put the then-block into the function,
+    // the else-block and merge-block will be added later, in order, after
+    // earlier code is emitted
+    thenBlock = new Block(builder.getUniqueId(), *function);
+    mergeBlock = new Block(builder.getUniqueId(), *function);
+
+    // Save the current block, so that we can add in the flow control split when
+    // makeEndIf is called.
+    headerBlock = builder.getBuildPoint();
+
+    function->addBlock(thenBlock);
+    builder.setBuildPoint(thenBlock);
+}
+
+// Comments in header
+void Builder::If::makeBeginElse()
+{
+    // Close out the "then" by having it jump to the mergeBlock
+    builder.createBranch(mergeBlock);
+
+    // Make the first else block and add it to the function
+    elseBlock = new Block(builder.getUniqueId(), *function);
+    function->addBlock(elseBlock);
+
+    // Start building the else block
+    builder.setBuildPoint(elseBlock);
+}
+
+// Comments in header
+void Builder::If::makeEndIf()
+{
+    // jump to the merge block
+    builder.createBranch(mergeBlock);
+
+    // Go back to the headerBlock and make the flow control split
+    builder.setBuildPoint(headerBlock);
+    builder.createMerge(OpSelectionMerge, mergeBlock, SelectionControlMaskNone);
+    if (elseBlock)
+        builder.createConditionalBranch(condition, thenBlock, elseBlock);
+    else
+        builder.createConditionalBranch(condition, thenBlock, mergeBlock);
+
+    // add the merge block to the function
+    function->addBlock(mergeBlock);
+    builder.setBuildPoint(mergeBlock);
+}
+
+// Comments in header
+void Builder::makeSwitch(Id selector, int numSegments, std::vector<int>& caseValues, std::vector<int>& valueIndexToSegment, int defaultSegment,
+                         std::vector<Block*>& segmentBlocks)
+{
+    Function& function = buildPoint->getParent();
+
+    // make all the blocks
+    for (int s = 0; s < numSegments; ++s)
+        segmentBlocks.push_back(new Block(getUniqueId(), function));
+
+    Block* mergeBlock = new Block(getUniqueId(), function);
+
+    // make and insert the switch's selection-merge instruction
+    createMerge(OpSelectionMerge, mergeBlock, SelectionControlMaskNone);
+
+    // make the switch instruction
+    Instruction* switchInst = new Instruction(NoResult, NoType, OpSwitch);
+    switchInst->addIdOperand(selector);
+    switchInst->addIdOperand(defaultSegment >= 0 ? segmentBlocks[defaultSegment]->getId() : mergeBlock->getId());
+    for (int i = 0; i < (int)caseValues.size(); ++i) {
+        switchInst->addImmediateOperand(caseValues[i]);
+        switchInst->addIdOperand(segmentBlocks[valueIndexToSegment[i]]->getId());
+    }
+    buildPoint->addInstruction(switchInst);
+
+    // push the merge block
+    switchMerges.push(mergeBlock);
+}
+
+// Comments in header
+void Builder::addSwitchBreak()
+{
+    // branch to the top of the merge block stack
+    createBranch(switchMerges.top());
+    createAndSetNoPredecessorBlock("post-switch-break");
+}
+
+// Comments in header
+void Builder::nextSwitchSegment(std::vector<Block*>& segmentBlock, int nextSegment)
+{
+    int lastSegment = nextSegment - 1;
+    if (lastSegment >= 0) {
+        // Close out previous segment by jumping, if necessary, to next segment
+        if (! buildPoint->isTerminated())
+            createBranch(segmentBlock[nextSegment]);
+    }
+    Block* block = segmentBlock[nextSegment];
+    block->getParent().addBlock(block);
+    setBuildPoint(block);
+}
+
+// Comments in header
+void Builder::endSwitch(std::vector<Block*>& /*segmentBlock*/)
+{
+    // Close out previous segment by jumping, if necessary, to next segment
+    if (! buildPoint->isTerminated())
+        addSwitchBreak();
+
+    switchMerges.top()->getParent().addBlock(switchMerges.top());
+    setBuildPoint(switchMerges.top());
+
+    switchMerges.pop();
+}
+
+// Comments in header
+void Builder::makeNewLoop()
+{
+    Loop loop = { };
+
+    loop.function = &getBuildPoint()->getParent();
+    loop.header = new Block(getUniqueId(), *loop.function);
+    loop.merge  = new Block(getUniqueId(), *loop.function);
+    loop.test   = NULL;
+
+    loops.push(loop);
+
+    // Branch into the loop
+    createBranch(loop.header);
+
+    // Set ourselves inside the loop
+    loop.function->addBlock(loop.header);
+    setBuildPoint(loop.header);
+}
+
+void Builder::createLoopTestBranch(Id condition)
+{
+    Loop& loop = loops.top();
+
+    // If loop.test exists, then we've already generated the LoopMerge
+    // for this loop.
+    if (!loop.test)
+      createMerge(OpLoopMerge, loop.merge, LoopControlMaskNone);
+
+    // Branching to the "body" block will keep control inside
+    // the loop.
+    Block* body = new Block(getUniqueId(), *loop.function);
+    createConditionalBranch(condition, body, loop.merge);
+    loop.function->addBlock(body);
+    setBuildPoint(body);
+}
+
+void Builder::endLoopHeaderWithoutTest()
+{
+    Loop& loop = loops.top();
+
+    createMerge(OpLoopMerge, loop.merge, LoopControlMaskNone);
+    Block* body = new Block(getUniqueId(), *loop.function);
+    createBranch(body);
+    loop.function->addBlock(body);
+    setBuildPoint(body);
+
+    assert(!loop.test);
+    loop.test = new Block(getUniqueId(), *loop.function);
+}
+
+void Builder::createBranchToLoopTest()
+{
+    Loop& loop = loops.top();
+    Block* testBlock = loop.test;
+    assert(testBlock);
+    createBranch(testBlock);
+    loop.function->addBlock(testBlock);
+    setBuildPoint(testBlock);
+}
+
+void Builder::createLoopContinue()
+{
+    Loop& loop = loops.top();
+    if (loop.test)
+      createBranch(loop.test);
+    else
+      createBranch(loop.header);
+    // Set up a block for dead code.
+    createAndSetNoPredecessorBlock("post-loop-continue");
+}
+
+// Add an exit (e.g. "break") for the innermost loop that you're in
+void Builder::createLoopExit()
+{
+    createBranch(loops.top().merge);
+    // Set up a block for dead code.
+    createAndSetNoPredecessorBlock("post-loop-break");
+}
+
+// Close the innermost loop
+void Builder::closeLoop()
+{
+    Loop& loop = loops.top();
+
+    // Branch back to the top
+    createBranch(loop.header);
+
+    // Add the merge block and set the build point to it
+    loop.function->addBlock(loop.merge);
+    setBuildPoint(loop.merge);
+
+    loops.pop();
+}
+
+void Builder::clearAccessChain()
+{
+    accessChain.base = 0;
+    accessChain.indexChain.clear();
+    accessChain.instr = 0;
+    accessChain.swizzle.clear();
+    accessChain.component = 0;
+    accessChain.resultType = NoType;
+    accessChain.isRValue = false;
+}
+
+// Comments in header
+void Builder::accessChainPushSwizzle(std::vector<unsigned>& swizzle)
+{
+    // if needed, propagate the swizzle for the current access chain
+    if (accessChain.swizzle.size()) {
+        std::vector<unsigned> oldSwizzle = accessChain.swizzle;
+        accessChain.swizzle.resize(0);
+        for (unsigned int i = 0; i < swizzle.size(); ++i) {
+            accessChain.swizzle.push_back(oldSwizzle[swizzle[i]]);
+        }
+    } else
+        accessChain.swizzle = swizzle;
+
+    // determine if we need to track this swizzle anymore
+    simplifyAccessChainSwizzle();
+}
+
+// Comments in header
+void Builder::accessChainStore(Id rvalue)
+{
+    assert(accessChain.isRValue == false);
+
+    Id base = collapseAccessChain();
+
+    if (accessChain.swizzle.size() && accessChain.component)
+        MissingFunctionality("simultaneous l-value swizzle and dynamic component selection");
+
+    // If swizzle exists, it is out-of-order or not full, we must load the target vector,
+    // extract and insert elements to perform writeMask and/or swizzle.
+    Id source = NoResult;
+    if (accessChain.swizzle.size()) {
+        Id tempBaseId = createLoad(base);
+        source = createLvalueSwizzle(getTypeId(tempBaseId), tempBaseId, rvalue, accessChain.swizzle);
+    }
+
+    // dynamic component selection
+    if (accessChain.component) {
+        Id tempBaseId = (source == NoResult) ? createLoad(base) : source;
+        source = createVectorInsertDynamic(tempBaseId, getTypeId(tempBaseId), rvalue, accessChain.component);
+    }
+
+    if (source == NoResult)
+        source = rvalue;
+
+    createStore(source, base);
+}
+
+// Comments in header
+Id Builder::accessChainLoad(Decoration /*precision*/)
+{
+    Id id;
+
+    if (accessChain.isRValue) {
+        if (accessChain.indexChain.size() > 0) {
+            mergeAccessChainSwizzle();  // TODO: optimization: look at applying this optimization more widely
+            // if all the accesses are constants, we can use OpCompositeExtract
+            std::vector<unsigned> indexes;
+            bool constant = true;
+            for (int i = 0; i < (int)accessChain.indexChain.size(); ++i) {
+                if (isConstantScalar(accessChain.indexChain[i]))
+                    indexes.push_back(getConstantScalar(accessChain.indexChain[i]));
+                else {
+                    constant = false;
+                    break;
+                }
+            }
+
+            if (constant)
+                id = createCompositeExtract(accessChain.base, accessChain.resultType, indexes);
+            else {
+                // make a new function variable for this r-value
+                Id lValue = createVariable(StorageClassFunction, getTypeId(accessChain.base), "indexable");
+
+                // store into it
+                createStore(accessChain.base, lValue);
+
+                // move base to the new variable
+                accessChain.base = lValue;
+                accessChain.isRValue = false;
+
+                // load through the access chain
+                id = createLoad(collapseAccessChain());
+            }
+        } else
+            id = accessChain.base;
+    } else {
+        // load through the access chain
+        id = createLoad(collapseAccessChain());
+    }
+
+    // Done, unless there are swizzles to do
+    if (accessChain.swizzle.size() == 0 && accessChain.component == 0)
+        return id;
+
+    Id componentType = getScalarTypeId(accessChain.resultType);
+
+    // Do remaining swizzling
+    // First, static swizzling
+    if (accessChain.swizzle.size()) {
+        // static swizzle
+        Id resultType = componentType;
+        if (accessChain.swizzle.size() > 1)
+            resultType = makeVectorType(componentType, accessChain.swizzle.size());
+        id = createRvalueSwizzle(resultType, id, accessChain.swizzle);
+    }
+
+    // dynamic single-component selection
+    if (accessChain.component)
+        id = createVectorExtractDynamic(id, componentType, accessChain.component);
+
+    return id;
+}
+
+Id Builder::accessChainGetLValue()
+{
+    assert(accessChain.isRValue == false);
+
+    Id lvalue = collapseAccessChain();
+
+    // If swizzle exists, it is out-of-order or not full, we must load the target vector,
+    // extract and insert elements to perform writeMask and/or swizzle.  This does not
+    // go with getting a direct l-value pointer.
+    assert(accessChain.swizzle.size() == 0);
+    assert(accessChain.component == spv::NoResult);
+
+    return lvalue;
+}
+
+void Builder::dump(std::vector<unsigned int>& out) const
+{
+    // Header, before first instructions:
+    out.push_back(MagicNumber);
+    out.push_back(Version);
+    out.push_back(builderNumber);
+    out.push_back(uniqueId + 1);
+    out.push_back(0);
+
+    // First instructions, some created on the spot here:
+    if (source != SourceLanguageUnknown) {
+        Instruction sourceInst(0, 0, OpSource);
+        sourceInst.addImmediateOperand(source);
+        sourceInst.addImmediateOperand(sourceVersion);
+        sourceInst.dump(out);
+    }
+    for (int e = 0; e < (int)extensions.size(); ++e) {
+        Instruction extInst(0, 0, OpSourceExtension);
+        extInst.addStringOperand(extensions[e]);
+        extInst.dump(out);
+    }
+    // TBD: OpExtension ...
+    dumpInstructions(out, imports);
+    Instruction memInst(0, 0, OpMemoryModel);
+    memInst.addImmediateOperand(addressModel);
+    memInst.addImmediateOperand(memoryModel);
+    memInst.dump(out);
+
+    // Instructions saved up while building:
+    dumpInstructions(out, entryPoints);
+    dumpInstructions(out, executionModes);
+    dumpInstructions(out, names);
+    dumpInstructions(out, lines);
+    dumpInstructions(out, decorations);
+    dumpInstructions(out, constantsTypesGlobals);
+    dumpInstructions(out, externals);
+
+    // The functions
+    module.dump(out);
+}
+
+//
+// Protected methods.
+//
+
+Id Builder::collapseAccessChain()
+{
+    // TODO: bring in an individual component swizzle here, so that a pointer 
+    // all the way to the component level can be created.
+    assert(accessChain.isRValue == false);
+
+    if (accessChain.indexChain.size() > 0) {
+        if (accessChain.instr == 0) {
+            StorageClass storageClass = (StorageClass)module.getStorageClass(getTypeId(accessChain.base));
+            accessChain.instr = createAccessChain(storageClass, accessChain.base, accessChain.indexChain);
+        }
+
+        return accessChain.instr;
+    } else
+        return accessChain.base;
+}
+
+// clear out swizzle if it is redundant
+void Builder::simplifyAccessChainSwizzle()
+{
+    // If the swizzle has fewer components than the vector, it is subsetting, and must stay
+    // to preserve that fact.
+    if (getNumTypeComponents(accessChain.resultType) > (int)accessChain.swizzle.size())
+        return;
+
+    // if components are out of order, it is a swizzle
+    for (unsigned int i = 0; i < accessChain.swizzle.size(); ++i) {
+        if (i != accessChain.swizzle[i])
+            return;
+    }
+
+    // otherwise, there is no need to track this swizzle
+    accessChain.swizzle.clear();
+}
+
+// clear out swizzle if it can become part of the indexes
+void Builder::mergeAccessChainSwizzle()
+{
+    // is there even a chance of doing something?  Need a single-component swizzle
+    if ((accessChain.swizzle.size() > 1) ||
+        (accessChain.swizzle.size() == 0 && accessChain.component == 0))
+        return;
+
+    // TODO: optimization: remove this, but for now confine this to non-dynamic accesses
+    // (the above test is correct when this is removed.)
+    if (accessChain.component)
+        return;
+
+    // move the swizzle over to the indexes
+    if (accessChain.swizzle.size() == 1)
+        accessChain.indexChain.push_back(makeUintConstant(accessChain.swizzle.front()));
+    else
+        accessChain.indexChain.push_back(accessChain.component);
+    accessChain.resultType = getScalarTypeId(accessChain.resultType);
+
+    // now there is no need to track this swizzle
+    accessChain.component = NoResult;
+    accessChain.swizzle.clear();
+}
+
+// Utility method for creating a new block and setting the insert point to
+// be in it. This is useful for flow-control operations that need a "dummy"
+// block proceeding them (e.g. instructions after a discard, etc).
+void Builder::createAndSetNoPredecessorBlock(const char* /*name*/)
+{
+    Block* block = new Block(getUniqueId(), buildPoint->getParent());
+    block->setUnreachable();
+    buildPoint->getParent().addBlock(block);
+    setBuildPoint(block);
+
+    //if (name)
+    //    addName(block->getId(), name);
+}
+
+// Comments in header
+void Builder::createBranch(Block* block)
+{
+    Instruction* branch = new Instruction(OpBranch);
+    branch->addIdOperand(block->getId());
+    buildPoint->addInstruction(branch);
+    block->addPredecessor(buildPoint);
+}
+
+void Builder::createMerge(Op mergeCode, Block* mergeBlock, unsigned int control)
+{
+    Instruction* merge = new Instruction(mergeCode);
+    merge->addIdOperand(mergeBlock->getId());
+    merge->addImmediateOperand(control);
+    buildPoint->addInstruction(merge);
+}
+
+void Builder::createConditionalBranch(Id condition, Block* thenBlock, Block* elseBlock)
+{
+    Instruction* branch = new Instruction(OpBranchConditional);
+    branch->addIdOperand(condition);
+    branch->addIdOperand(thenBlock->getId());
+    branch->addIdOperand(elseBlock->getId());
+    buildPoint->addInstruction(branch);
+    thenBlock->addPredecessor(buildPoint);
+    elseBlock->addPredecessor(buildPoint);
+}
+
+void Builder::dumpInstructions(std::vector<unsigned int>& out, const std::vector<Instruction*>& instructions) const
+{
+    for (int i = 0; i < (int)instructions.size(); ++i) {
+        instructions[i]->dump(out);
+    }
+}
+
+void MissingFunctionality(const char* fun)
+{
+    printf("Missing functionality: %s\n", fun);
+    exit(1);
+}
+
+void ValidationError(const char* error)
+{
+    printf("Validation Error: %s\n", error);
+}
+
+}; // end spv namespace
index b500c1f..4eef5a4 100644 (file)
-//\r
-//Copyright (C) 2014 LunarG, Inc.\r
-//\r
-//All rights reserved.\r
-//\r
-//Redistribution and use in source and binary forms, with or without\r
-//modification, are permitted provided that the following conditions\r
-//are met:\r
-//\r
-//    Redistributions of source code must retain the above copyright\r
-//    notice, this list of conditions and the following disclaimer.\r
-//\r
-//    Redistributions in binary form must reproduce the above\r
-//    copyright notice, this list of conditions and the following\r
-//    disclaimer in the documentation and/or other materials provided\r
-//    with the distribution.\r
-//\r
-//    Neither the name of 3Dlabs Inc. Ltd. nor the names of its\r
-//    contributors may be used to endorse or promote products derived\r
-//    from this software without specific prior written permission.\r
-//\r
-//THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\r
-//"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\r
-//LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS\r
-//FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE\r
-//COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,\r
-//INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,\r
-//BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\r
-//LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER\r
-//CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\r
-//LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN\r
-//ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE\r
-//POSSIBILITY OF SUCH DAMAGE.\r
-\r
-//\r
-// Author: John Kessenich, LunarG\r
-//\r
-\r
-//\r
-// "Builder" is an interface to fully build SPIR-V IR.   Allocate one of\r
-// these to build (a thread safe) internal SPIR-V representation (IR),\r
-// and then dump it as a binary stream according to the SPIR-V specification.\r
-//\r
-// A Builder has a 1:1 relationship with a SPIR-V module.\r
-//\r
-\r
-#pragma once\r
-#ifndef SpvBuilder_H\r
-#define SpvBuilder_H\r
-\r
-#include "spirv.h"\r
-#include "spvIR.h"\r
-\r
-#include <algorithm>\r
-#include <stack>\r
-#include <map>\r
-\r
-namespace spv {\r
-\r
-class Builder {\r
-public:\r
-    Builder(unsigned int userNumber);\r
-    virtual ~Builder();\r
-\r
-    static const int maxMatrixSize = 4;\r
-\r
-    void setSource(spv::SourceLanguage lang, int version)\r
-    {\r
-        source = lang;\r
-        sourceVersion = version;\r
-    }\r
-    void addSourceExtension(const char* ext) { extensions.push_back(ext); }\r
-    Id import(const char*);\r
-    void setMemoryModel(spv::AddressingModel addr, spv::MemoryModel mem)\r
-    {\r
-        addressModel = addr;\r
-        memoryModel = mem;\r
-    }\r
-\r
-    // To get a new <id> for anything needing a new one.\r
-    Id getUniqueId() { return ++uniqueId; }\r
-\r
-    // To get a set of new <id>s, e.g., for a set of function parameters\r
-    Id getUniqueIds(int numIds)\r
-    {\r
-        Id id = uniqueId + 1;\r
-        uniqueId += numIds;\r
-        return id;\r
-    }\r
-\r
-    // For creating new types (will return old type if the requested one was already made).\r
-    Id makeVoidType();\r
-    Id makeBoolType();\r
-    Id makePointer(StorageClass, Id type);\r
-    Id makeIntegerType(int width, bool hasSign);   // generic\r
-    Id makeIntType(int width) { return makeIntegerType(width, true); }\r
-    Id makeUintType(int width) { return makeIntegerType(width, false); }\r
-    Id makeFloatType(int width);\r
-    Id makeStructType(std::vector<Id>& members, const char*);\r
-    Id makeVectorType(Id component, int size);\r
-    Id makeMatrixType(Id component, int cols, int rows);\r
-    Id makeArrayType(Id element, unsigned size);\r
-    Id makeFunctionType(Id returnType, std::vector<Id>& paramTypes);\r
-    enum samplerContent {\r
-        samplerContentTexture,\r
-        samplerContentImage,\r
-        samplerContentTextureFilter\r
-    };\r
-    Id makeSampler(Id sampledType, Dim, samplerContent, bool arrayed, bool shadow, bool ms);\r
-\r
-    // For querying about types.\r
-    Id getTypeId(Id resultId) const { return module.getTypeId(resultId); }\r
-    Id getDerefTypeId(Id resultId) const;\r
-    Op getOpCode(Id id) const { return module.getInstruction(id)->getOpCode(); }\r
-    Op getTypeClass(Id typeId) const { return getOpCode(typeId); }\r
-    Op getMostBasicTypeClass(Id typeId) const;\r
-    int getNumComponents(Id resultId) const { return getNumTypeComponents(getTypeId(resultId)); }\r
-    int getNumTypeComponents(Id typeId) const;\r
-    Id getScalarTypeId(Id typeId) const;\r
-    Id getContainedTypeId(Id typeId) const;\r
-    Id getContainedTypeId(Id typeId, int) const;\r
-\r
-    bool isPointer(Id resultId)     const { return isPointerType(getTypeId(resultId)); }\r
-    bool isScalar(Id resultId)      const { return isScalarType(getTypeId(resultId)); }\r
-    bool isVector(Id resultId)      const { return isVectorType(getTypeId(resultId)); }\r
-    bool isMatrix(Id resultId)      const { return isMatrixType(getTypeId(resultId)); }\r
-    bool isAggregate(Id resultId)   const { return isAggregateType(getTypeId(resultId)); }\r
-\r
-    bool isPointerType(Id typeId)   const { return getTypeClass(typeId) == OpTypePointer; }\r
-    bool isScalarType(Id typeId)    const { return getTypeClass(typeId) == OpTypeFloat  || getTypeClass(typeId) == OpTypeInt || getTypeClass(typeId) == OpTypeBool; }\r
-    bool isVectorType(Id typeId)    const { return getTypeClass(typeId) == OpTypeVector; }\r
-    bool isMatrixType(Id typeId)    const { return getTypeClass(typeId) == OpTypeMatrix; }\r
-    bool isStructType(Id typeId)    const { return getTypeClass(typeId) == OpTypeStruct; }\r
-    bool isArrayType(Id typeId)     const { return getTypeClass(typeId) == OpTypeArray; }\r
-    bool isAggregateType(Id typeId) const { return isArrayType(typeId) || isStructType(typeId); }\r
-    bool isSamplerType(Id typeId)   const { return getTypeClass(typeId) == OpTypeSampler; }\r
-\r
-    bool isConstantScalar(Id resultId) const { return getOpCode(resultId) == OpConstant; }\r
-    unsigned int getConstantScalar(Id resultId) const { return module.getInstruction(resultId)->getImmediateOperand(0); }\r
-\r
-    int getTypeNumColumns(Id typeId) const\r
-    {\r
-        assert(isMatrixType(typeId));\r
-        return getNumTypeComponents(typeId);\r
-    }\r
-    int getNumColumns(Id resultId) const { return getTypeNumColumns(getTypeId(resultId)); }\r
-    int getTypeNumRows(Id typeId) const\r
-    {\r
-        assert(isMatrixType(typeId));\r
-        return getNumTypeComponents(getContainedTypeId(typeId));\r
-    }\r
-    int getNumRows(Id resultId) const { return getTypeNumRows(getTypeId(resultId)); }\r
-\r
-    Dim getDimensionality(Id resultId) const\r
-    {\r
-        assert(isSamplerType(getTypeId(resultId)));\r
-        return (Dim)module.getInstruction(getTypeId(resultId))->getImmediateOperand(1);\r
-    }\r
-    bool isArrayedSampler(Id resultId) const\r
-    {\r
-        assert(isSamplerType(getTypeId(resultId)));\r
-        return module.getInstruction(getTypeId(resultId))->getImmediateOperand(3) != 0;\r
-    }\r
-\r
-    // For making new constants (will return old constant if the requested one was already made).\r
-    Id makeBoolConstant(bool b);\r
-    Id makeIntConstant(Id typeId, unsigned value);\r
-    Id makeIntConstant(int i)         { return makeIntConstant(makeIntType(32),  (unsigned)i); }\r
-    Id makeUintConstant(unsigned u)   { return makeIntConstant(makeUintType(32),           u); }\r
-    Id makeFloatConstant(float f);\r
-    Id makeDoubleConstant(double d);\r
-\r
-    // Turn the array of constants into a proper spv constant of the requested type.\r
-    Id makeCompositeConstant(Id type, std::vector<Id>& comps);\r
-\r
-    // Methods for adding information outside the CFG.\r
-    void addEntryPoint(ExecutionModel, Function*);\r
-    void addExecutionMode(Function*, ExecutionMode mode, int value = -1);\r
-    void addName(Id, const char* name);\r
-    void addMemberName(Id, int member, const char* name);\r
-    void addLine(Id target, Id fileName, int line, int column);\r
-    void addDecoration(Id, Decoration, int num = -1);\r
-    void addMemberDecoration(Id, unsigned int member, Decoration, int num = -1);\r
-\r
-    // At the end of what block do the next create*() instructions go?\r
-    void setBuildPoint(Block* bp) { buildPoint = bp; }\r
-    Block* getBuildPoint() const { return buildPoint; }\r
-\r
-    // Make the main function.\r
-    Function* makeMain();\r
-\r
-    // Return from main. Implicit denotes a return at the very end of main.\r
-    void makeMainReturn(bool implicit = false) { makeReturn(implicit, 0, true); }\r
-\r
-    // Close the main function.\r
-    void closeMain();\r
-\r
-    // Make a shader-style function, and create its entry block if entry is non-zero.\r
-    // Return the function, pass back the entry.\r
-    Function* makeFunctionEntry(Id returnType, const char* name, std::vector<Id>& paramTypes, Block **entry = 0);\r
-\r
-    // Create a return. Pass whether it is a return form main, and the return\r
-    // value (if applicable). In the case of an implicit return, no post-return\r
-    // block is inserted.\r
-    void makeReturn(bool implicit = false, Id retVal = 0, bool isMain = false);\r
-\r
-    // Generate all the code needed to finish up a function.\r
-    void leaveFunction(bool main);\r
-\r
-    // Create a discard.\r
-    void makeDiscard();\r
-\r
-    // Create a global or function local or IO variable.\r
-    Id createVariable(StorageClass, Id type, const char* name = 0);\r
-\r
-    // Store into an Id and return the l-value\r
-    void createStore(Id rValue, Id lValue);\r
-\r
-    // Load from an Id and return it\r
-    Id createLoad(Id lValue);\r
-\r
-    // Create an OpAccessChain instruction\r
-    Id createAccessChain(StorageClass, Id base, std::vector<Id>& offsets);\r
-\r
-    // Create an OpCompositeExtract instruction\r
-    Id createCompositeExtract(Id composite, Id typeId, unsigned index);\r
-    Id createCompositeExtract(Id composite, Id typeId, std::vector<unsigned>& indexes);\r
-    Id createCompositeInsert(Id object, Id composite, Id typeId, unsigned index);\r
-    Id createCompositeInsert(Id object, Id composite, Id typeId, std::vector<unsigned>& indexes);\r
-\r
-    Id createVectorExtractDynamic(Id vector, Id typeId, Id componentIndex);\r
-    Id createVectorInsertDynamic(Id vector, Id typeId, Id component, Id componentIndex);\r
-\r
-    void createNoResultOp(Op);\r
-    void createNoResultOp(Op, Id operand);\r
-    void createControlBarrier(unsigned executionScope);\r
-    void createMemoryBarrier(unsigned executionScope, unsigned memorySemantics);\r
-    Id createUnaryOp(Op, Id typeId, Id operand);\r
-    Id createBinOp(Op, Id typeId, Id operand1, Id operand2);\r
-    Id createTriOp(Op, Id typeId, Id operand1, Id operand2, Id operand3);\r
-    Id createTernaryOp(Op, Id typeId, Id operand1, Id operand2, Id operand3);\r
-    Id createFunctionCall(spv::Function*, std::vector<spv::Id>&);\r
-\r
-    // Take an rvalue (source) and a set of channels to extract from it to\r
-    // make a new rvalue, which is returned.\r
-    Id createRvalueSwizzle(Id typeId, Id source, std::vector<unsigned>& channels);\r
-\r
-    // Take a copy of an lvalue (target) and a source of components, and set the\r
-    // source components into the lvalue where the 'channels' say to put them.\r
-    // An updated version of the target is returned.\r
-    // (No true lvalue or stores are used.)\r
-    Id createLvalueSwizzle(Id typeId, Id target, Id source, std::vector<unsigned>& channels);\r
-\r
-    // If the value passed in is an instruction and the precision is not EMpNone,\r
-    // it gets tagged with the requested precision.\r
-    void setPrecision(Id /* value */, Decoration /* precision */)\r
-    {\r
-        // TODO\r
-    }\r
-\r
-    // Can smear a scalar to a vector for the following forms:\r
-    //   - promoteScalar(scalar, vector)  // smear scalar to width of vector\r
-    //   - promoteScalar(vector, scalar)  // smear scalar to width of vector\r
-    //   - promoteScalar(pointer, scalar) // smear scalar to width of what pointer points to\r
-    //   - promoteScalar(scalar, scalar)  // do nothing\r
-    // Other forms are not allowed.\r
-    //\r
-    // Note: One of the arguments will change, with the result coming back that way rather than \r
-    // through the return value.\r
-    void promoteScalar(Decoration precision, Id& left, Id& right);\r
-\r
-    // make a value by smearing the scalar to fill the type\r
-    Id smearScalar(Decoration precision, Id scalarVal, Id);\r
-\r
-    // Create a call to a built-in function.\r
-    Id createBuiltinCall(Decoration precision, Id resultType, Id builtins, int entryPoint, std::vector<Id>& args);\r
-\r
-    // List of parameters used to create a texture operation\r
-    struct TextureParameters {\r
-        Id sampler;\r
-        Id coords;\r
-        Id bias;\r
-        Id lod;\r
-        Id Dref;\r
-        Id offset;\r
-        Id gradX;\r
-        Id gradY;\r
-    };\r
-\r
-    // Select the correct texture operation based on all inputs, and emit the correct instruction\r
-    Id createTextureCall(Decoration precision, Id resultType, bool proj, const TextureParameters&);\r
-\r
-    // Emit the OpTextureQuery* instruction that was passed in.\r
-    // Figure out the right return value and type, and return it.\r
-    Id createTextureQueryCall(Op, const TextureParameters&);\r
-\r
-    Id createSamplePositionCall(Decoration precision, Id, Id);\r
-\r
-    Id createBitFieldExtractCall(Decoration precision, Id, Id, Id, bool isSigned);\r
-    Id createBitFieldInsertCall(Decoration precision, Id, Id, Id, Id);\r
-\r
-    // Reduction comparision for composites:  For equal and not-equal resulting in a scalar.\r
-    Id createCompare(Decoration precision, Id, Id, bool /* true if for equal, fales if for not-equal */);\r
-\r
-    // OpCompositeConstruct\r
-    Id createCompositeConstruct(Id typeId, std::vector<Id>& constituents);\r
-\r
-    // vector or scalar constructor\r
-    Id createConstructor(Decoration precision, const std::vector<Id>& sources, Id resultTypeId);\r
-\r
-    // matrix constructor\r
-    Id createMatrixConstructor(Decoration precision, const std::vector<Id>& sources, Id constructee);\r
-\r
-    // Helper to use for building nested control flow with if-then-else.\r
-    class If {\r
-    public:\r
-        If(Id condition, Builder& builder);\r
-        ~If() {}\r
-\r
-        void makeBeginElse();\r
-        void makeEndIf();\r
-\r
-    private:\r
-        If(const If&);\r
-        If& operator=(If&);\r
-\r
-        Builder& builder;\r
-        Id condition;\r
-        Function* function;\r
-        Block* headerBlock;\r
-        Block* thenBlock;\r
-        Block* elseBlock;\r
-        Block* mergeBlock;\r
-    };\r
-\r
-    // Make a switch statement.  A switch has 'numSegments' of pieces of code, not containing\r
-    // any case/default labels, all separated by one or more case/default labels.  Each possible\r
-    // case value v is a jump to the caseValues[v] segment.  The defaultSegment is also in this\r
-    // number space.  How to compute the value is given by 'condition', as in switch(condition).\r
-    //\r
-    // The SPIR-V Builder will maintain the stack of post-switch merge blocks for nested switches.\r
-    //\r
-    // Use a defaultSegment < 0 if there is no default segment (to branch to post switch).\r
-    //\r
-    // Returns the right set of basic blocks to start each code segment with, so that the caller's\r
-    // recursion stack can hold the memory for it.\r
-    //\r
-    void makeSwitch(Id condition, int numSegments, std::vector<int>& caseValues, std::vector<int>& valueToSegment, int defaultSegment,\r
-                    std::vector<Block*>& segmentBB);  // return argument\r
-\r
-    // Add a branch to the innermost switch's merge block.\r
-    void addSwitchBreak();\r
-\r
-    // Move to the next code segment, passing in the return argument in makeSwitch()\r
-    void nextSwitchSegment(std::vector<Block*>& segmentBB, int segment);\r
-\r
-    // Finish off the innermost switch.\r
-    void endSwitch(std::vector<Block*>& segmentBB);\r
-\r
-    // Start the beginning of a new loop.\r
-    void makeNewLoop();\r
-\r
-    // Add the branch for the loop test, based on the given condition.\r
-    // The true branch goes to the block that remains inside the loop, and\r
-    // the false branch goes to the loop's merge block.  The  builder insertion\r
-    // point will be placed at the start of the inside-the-loop block.\r
-    void createLoopTestBranch(Id condition);\r
-\r
-    // Finish generating the loop header block in the case where the loop test\r
-    // is at the bottom of the loop.  It will include the LoopMerge instruction\r
-    // and a branch to the rest of the body.  The loop header block must be\r
-    // separate from the rest of the body to make room for the the two kinds\r
-    // of *Merge instructions that might have to occur just before a branch:\r
-    // the loop header must have a LoopMerge as its second-last instruction,\r
-    // and the body might begin with a conditional branch, which must have its\r
-    // own SelectionMerge instruction.\r
-    // Also create the basic block that will contain the loop test, but don't\r
-    // insert it into the function yet.  Any "continue" constructs in this loop\r
-    // will branch to the loop test block. The builder insertion point will be\r
-    // placed at the start of the body block.\r
-    void endLoopHeaderWithoutTest();\r
-\r
-    // Generate a branch to the loop test block.  This can only be called if\r
-    // the loop test is at the bottom of the loop. The builder insertion point\r
-    // is left at the start of the test block.\r
-    void createBranchToLoopTest();\r
-\r
-    // Add a branch to the test of the current (innermost) loop.\r
-    void createLoopContinue();\r
-\r
-    // Add an exit (e.g. "break") for the innermost loop that you're in\r
-    void createLoopExit();\r
-\r
-    // Close the innermost loop that you're in\r
-    void closeLoop();\r
-\r
-    //\r
-    // Access chain design for an R-Value vs. L-Value:\r
-    //\r
-    // There is a single access chain the builder is building at\r
-    // any particular time.  Such a chain can be used to either to a load or\r
-    // a store, when desired.\r
-    //\r
-    // Expressions can be r-values, l-values, or both, or only r-values:\r
-    //    a[b.c].d = ....  // l-value\r
-    //    ... = a[b.c].d;  // r-value, that also looks like an l-value\r
-    //    ++a[b.c].d;      // r-value and l-value\r
-    //    (x + y)[2];      // r-value only, can't possibly be l-value\r
-    //\r
-    // Computing an r-value means generating code.  Hence,\r
-    // r-values should only be computed when they are needed, not speculatively.\r
-    //\r
-    // Computing an l-value means saving away information for later use in the compiler,\r
-    // no code is generated until the l-value is later dereferenced.  It is okay\r
-    // to speculatively generate an l-value, just not okay to speculatively dereference it.\r
-    //\r
-    // The base of the access chain (the left-most variable or expression\r
-    // from which everything is based) can be set either as an l-value\r
-    // or as an r-value.  Most efficient would be to set an l-value if one\r
-    // is available.  If an expression was evaluated, the resulting r-value\r
-    // can be set as the chain base.\r
-    //\r
-    // The users of this single access chain can save and restore if they\r
-    // want to nest or manage multiple chains.\r
-    //\r
-\r
-    struct AccessChain {\r
-        Id base;                     // for l-values, pointer to the base object, for r-values, the base object\r
-        std::vector<Id> indexChain;\r
-        Id instr;                    // the instruction that generates this access chain\r
-        std::vector<unsigned> swizzle;\r
-        Id component;                // a dynamic component index, can coexist with a swizzle, done after the swizzle\r
-        Id resultType;               // dereferenced type, to be exclusive of swizzles\r
-        bool isRValue;\r
-    };\r
-\r
-    //\r
-    // the SPIR-V builder maintains a single active chain that\r
-    // the following methods operated on\r
-    //\r
-\r
-    // for external save and restore\r
-    AccessChain getAccessChain() { return accessChain; }\r
-    void setAccessChain(AccessChain newChain) { accessChain = newChain; }\r
-\r
-    // clear accessChain\r
-    void clearAccessChain();\r
-\r
-    // set new base as an l-value base\r
-    void setAccessChainLValue(Id lValue)\r
-    {\r
-        assert(isPointer(lValue));\r
-        accessChain.base = lValue;\r
-        accessChain.resultType = getContainedTypeId(getTypeId(lValue));\r
-    }\r
-\r
-    // set new base value as an r-value\r
-    void setAccessChainRValue(Id rValue)\r
-    {\r
-        accessChain.isRValue = true;\r
-        accessChain.base = rValue;\r
-        accessChain.resultType = getTypeId(rValue);\r
-    }\r
-\r
-    // push offset onto the end of the chain\r
-    void accessChainPush(Id offset, Id newType)\r
-    {\r
-        accessChain.indexChain.push_back(offset);\r
-        accessChain.resultType = newType;\r
-    }\r
-\r
-    // push new swizzle onto the end of any existing swizzle, merging into a single swizzle\r
-    void accessChainPushSwizzle(std::vector<unsigned>& swizzle);\r
-\r
-    // push a variable component selection onto the access chain; supporting only one, so unsided\r
-    void accessChainPushComponent(Id component) { accessChain.component = component; }\r
-\r
-    // use accessChain and swizzle to store value\r
-    void accessChainStore(Id rvalue);\r
-\r
-    // use accessChain and swizzle to load an r-value\r
-    Id accessChainLoad(Decoration precision);\r
-\r
-    // get the direct pointer for an l-value\r
-    Id accessChainGetLValue();\r
-\r
-    void dump(std::vector<unsigned int>&) const;\r
-\r
-protected:\r
-    Id findScalarConstant(Op typeClass, Id typeId, unsigned value) const;\r
-    Id findScalarConstant(Op typeClass, Id typeId, unsigned v1, unsigned v2) const;\r
-    Id findCompositeConstant(Op typeClass, std::vector<Id>& comps) const;\r
-    Id collapseAccessChain();\r
-    void simplifyAccessChainSwizzle();\r
-    void mergeAccessChainSwizzle();\r
-    void createAndSetNoPredecessorBlock(const char*);\r
-    void createBranch(Block* block);\r
-    void createMerge(Op, Block*, unsigned int control);\r
-    void createConditionalBranch(Id condition, Block* thenBlock, Block* elseBlock);\r
-    void dumpInstructions(std::vector<unsigned int>&, const std::vector<Instruction*>&) const;\r
-\r
-    SourceLanguage source;\r
-    int sourceVersion;\r
-    std::vector<const char*> extensions;\r
-    AddressingModel addressModel;\r
-    MemoryModel memoryModel;\r
-    int builderNumber;\r
-    Module module;\r
-    Block* buildPoint;\r
-    Id uniqueId;\r
-    Function* mainFunction;\r
-    Block* stageExit;\r
-    AccessChain accessChain;\r
-\r
-    // special blocks of instructions for output\r
-    std::vector<Instruction*> imports;\r
-    std::vector<Instruction*> entryPoints;\r
-    std::vector<Instruction*> executionModes;\r
-    std::vector<Instruction*> names;\r
-    std::vector<Instruction*> lines;\r
-    std::vector<Instruction*> decorations;\r
-    std::vector<Instruction*> constantsTypesGlobals;\r
-    std::vector<Instruction*> externals;\r
-\r
-     // not output, internally used for quick & dirty canonical (unique) creation\r
-    std::vector<Instruction*> groupedConstants[OpConstant];  // all types appear before OpConstant\r
-    std::vector<Instruction*> groupedTypes[OpConstant];\r
-\r
-    // stack of switches\r
-    std::stack<Block*> switchMerges;\r
-\r
-    // Data that needs to be kept in order to properly handle loops.\r
-    struct Loop {\r
-        // The header is the first block generated for the loop.\r
-        // It dominates all the blocks in the loop, i.e. it is always\r
-        // executed before any others.\r
-        // If the loop test is executed before the body (as in "while" and\r
-        // "for" loops), then the header begins with the test code.\r
-        // Otherwise, the loop is a "do-while" loop and the header contains the\r
-        // start of the body of the loop (if the body exists).\r
-        Block* header;\r
-        // The merge block marks the end of the loop.  Control is transferred\r
-        // to the merge block when either the loop test fails, or when a\r
-        // nested "break" is encountered.\r
-        Block* merge;\r
-        // If not NULL, the test block is the basic block containing the loop\r
-        // test and the conditional branch back to the header or the merge\r
-        // block.  This is created for "do-while" loops, and is the target of\r
-        // any "continue" constructs that might exist.\r
-        Block* test;\r
-        Function* function;\r
-    };\r
-\r
-    // Our loop stack.\r
-    std::stack<Loop> loops;\r
-};  // end Builder class\r
-\r
-void MissingFunctionality(const char*);\r
-void ValidationError(const char* error);\r
-\r
-};  // end spv namespace\r
-\r
-#endif // SpvBuilder_H\r
+//
+//Copyright (C) 2014 LunarG, Inc.
+//
+//All rights reserved.
+//
+//Redistribution and use in source and binary forms, with or without
+//modification, are permitted provided that the following conditions
+//are met:
+//
+//    Redistributions of source code must retain the above copyright
+//    notice, this list of conditions and the following disclaimer.
+//
+//    Redistributions in binary form must reproduce the above
+//    copyright notice, this list of conditions and the following
+//    disclaimer in the documentation and/or other materials provided
+//    with the distribution.
+//
+//    Neither the name of 3Dlabs Inc. Ltd. nor the names of its
+//    contributors may be used to endorse or promote products derived
+//    from this software without specific prior written permission.
+//
+//THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+//"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+//LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+//FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+//COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+//INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+//BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+//LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+//CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+//LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+//ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+//POSSIBILITY OF SUCH DAMAGE.
+
+//
+// Author: John Kessenich, LunarG
+//
+
+//
+// "Builder" is an interface to fully build SPIR-V IR.   Allocate one of
+// these to build (a thread safe) internal SPIR-V representation (IR),
+// and then dump it as a binary stream according to the SPIR-V specification.
+//
+// A Builder has a 1:1 relationship with a SPIR-V module.
+//
+
+#pragma once
+#ifndef SpvBuilder_H
+#define SpvBuilder_H
+
+#include "spirv.h"
+#include "spvIR.h"
+
+#include <algorithm>
+#include <stack>
+#include <map>
+
+namespace spv {
+
+class Builder {
+public:
+    Builder(unsigned int userNumber);
+    virtual ~Builder();
+
+    static const int maxMatrixSize = 4;
+
+    void setSource(spv::SourceLanguage lang, int version)
+    {
+        source = lang;
+        sourceVersion = version;
+    }
+    void addSourceExtension(const char* ext) { extensions.push_back(ext); }
+    Id import(const char*);
+    void setMemoryModel(spv::AddressingModel addr, spv::MemoryModel mem)
+    {
+        addressModel = addr;
+        memoryModel = mem;
+    }
+
+    // To get a new <id> for anything needing a new one.
+    Id getUniqueId() { return ++uniqueId; }
+
+    // To get a set of new <id>s, e.g., for a set of function parameters
+    Id getUniqueIds(int numIds)
+    {
+        Id id = uniqueId + 1;
+        uniqueId += numIds;
+        return id;
+    }
+
+    // For creating new types (will return old type if the requested one was already made).
+    Id makeVoidType();
+    Id makeBoolType();
+    Id makePointer(StorageClass, Id type);
+    Id makeIntegerType(int width, bool hasSign);   // generic
+    Id makeIntType(int width) { return makeIntegerType(width, true); }
+    Id makeUintType(int width) { return makeIntegerType(width, false); }
+    Id makeFloatType(int width);
+    Id makeStructType(std::vector<Id>& members, const char*);
+    Id makeVectorType(Id component, int size);
+    Id makeMatrixType(Id component, int cols, int rows);
+    Id makeArrayType(Id element, unsigned size);
+    Id makeFunctionType(Id returnType, std::vector<Id>& paramTypes);
+    enum samplerContent {
+        samplerContentTexture,
+        samplerContentImage,
+        samplerContentTextureFilter
+    };
+    Id makeSampler(Id sampledType, Dim, samplerContent, bool arrayed, bool shadow, bool ms);
+
+    // For querying about types.
+    Id getTypeId(Id resultId) const { return module.getTypeId(resultId); }
+    Id getDerefTypeId(Id resultId) const;
+    Op getOpCode(Id id) const { return module.getInstruction(id)->getOpCode(); }
+    Op getTypeClass(Id typeId) const { return getOpCode(typeId); }
+    Op getMostBasicTypeClass(Id typeId) const;
+    int getNumComponents(Id resultId) const { return getNumTypeComponents(getTypeId(resultId)); }
+    int getNumTypeComponents(Id typeId) const;
+    Id getScalarTypeId(Id typeId) const;
+    Id getContainedTypeId(Id typeId) const;
+    Id getContainedTypeId(Id typeId, int) const;
+
+    bool isPointer(Id resultId)     const { return isPointerType(getTypeId(resultId)); }
+    bool isScalar(Id resultId)      const { return isScalarType(getTypeId(resultId)); }
+    bool isVector(Id resultId)      const { return isVectorType(getTypeId(resultId)); }
+    bool isMatrix(Id resultId)      const { return isMatrixType(getTypeId(resultId)); }
+    bool isAggregate(Id resultId)   const { return isAggregateType(getTypeId(resultId)); }
+
+    bool isPointerType(Id typeId)   const { return getTypeClass(typeId) == OpTypePointer; }
+    bool isScalarType(Id typeId)    const { return getTypeClass(typeId) == OpTypeFloat  || getTypeClass(typeId) == OpTypeInt || getTypeClass(typeId) == OpTypeBool; }
+    bool isVectorType(Id typeId)    const { return getTypeClass(typeId) == OpTypeVector; }
+    bool isMatrixType(Id typeId)    const { return getTypeClass(typeId) == OpTypeMatrix; }
+    bool isStructType(Id typeId)    const { return getTypeClass(typeId) == OpTypeStruct; }
+    bool isArrayType(Id typeId)     const { return getTypeClass(typeId) == OpTypeArray; }
+    bool isAggregateType(Id typeId) const { return isArrayType(typeId) || isStructType(typeId); }
+    bool isSamplerType(Id typeId)   const { return getTypeClass(typeId) == OpTypeSampler; }
+
+    bool isConstantScalar(Id resultId) const { return getOpCode(resultId) == OpConstant; }
+    unsigned int getConstantScalar(Id resultId) const { return module.getInstruction(resultId)->getImmediateOperand(0); }
+
+    int getTypeNumColumns(Id typeId) const
+    {
+        assert(isMatrixType(typeId));
+        return getNumTypeComponents(typeId);
+    }
+    int getNumColumns(Id resultId) const { return getTypeNumColumns(getTypeId(resultId)); }
+    int getTypeNumRows(Id typeId) const
+    {
+        assert(isMatrixType(typeId));
+        return getNumTypeComponents(getContainedTypeId(typeId));
+    }
+    int getNumRows(Id resultId) const { return getTypeNumRows(getTypeId(resultId)); }
+
+    Dim getDimensionality(Id resultId) const
+    {
+        assert(isSamplerType(getTypeId(resultId)));
+        return (Dim)module.getInstruction(getTypeId(resultId))->getImmediateOperand(1);
+    }
+    bool isArrayedSampler(Id resultId) const
+    {
+        assert(isSamplerType(getTypeId(resultId)));
+        return module.getInstruction(getTypeId(resultId))->getImmediateOperand(3) != 0;
+    }
+
+    // For making new constants (will return old constant if the requested one was already made).
+    Id makeBoolConstant(bool b);
+    Id makeIntConstant(Id typeId, unsigned value);
+    Id makeIntConstant(int i)         { return makeIntConstant(makeIntType(32),  (unsigned)i); }
+    Id makeUintConstant(unsigned u)   { return makeIntConstant(makeUintType(32),           u); }
+    Id makeFloatConstant(float f);
+    Id makeDoubleConstant(double d);
+
+    // Turn the array of constants into a proper spv constant of the requested type.
+    Id makeCompositeConstant(Id type, std::vector<Id>& comps);
+
+    // Methods for adding information outside the CFG.
+    void addEntryPoint(ExecutionModel, Function*);
+    void addExecutionMode(Function*, ExecutionMode mode, int value = -1);
+    void addName(Id, const char* name);
+    void addMemberName(Id, int member, const char* name);
+    void addLine(Id target, Id fileName, int line, int column);
+    void addDecoration(Id, Decoration, int num = -1);
+    void addMemberDecoration(Id, unsigned int member, Decoration, int num = -1);
+
+    // At the end of what block do the next create*() instructions go?
+    void setBuildPoint(Block* bp) { buildPoint = bp; }
+    Block* getBuildPoint() const { return buildPoint; }
+
+    // Make the main function.
+    Function* makeMain();
+
+    // Return from main. Implicit denotes a return at the very end of main.
+    void makeMainReturn(bool implicit = false) { makeReturn(implicit, 0, true); }
+
+    // Close the main function.
+    void closeMain();
+
+    // Make a shader-style function, and create its entry block if entry is non-zero.
+    // Return the function, pass back the entry.
+    Function* makeFunctionEntry(Id returnType, const char* name, std::vector<Id>& paramTypes, Block **entry = 0);
+
+    // Create a return. Pass whether it is a return form main, and the return
+    // value (if applicable). In the case of an implicit return, no post-return
+    // block is inserted.
+    void makeReturn(bool implicit = false, Id retVal = 0, bool isMain = false);
+
+    // Generate all the code needed to finish up a function.
+    void leaveFunction(bool main);
+
+    // Create a discard.
+    void makeDiscard();
+
+    // Create a global or function local or IO variable.
+    Id createVariable(StorageClass, Id type, const char* name = 0);
+
+    // Store into an Id and return the l-value
+    void createStore(Id rValue, Id lValue);
+
+    // Load from an Id and return it
+    Id createLoad(Id lValue);
+
+    // Create an OpAccessChain instruction
+    Id createAccessChain(StorageClass, Id base, std::vector<Id>& offsets);
+
+    // Create an OpCompositeExtract instruction
+    Id createCompositeExtract(Id composite, Id typeId, unsigned index);
+    Id createCompositeExtract(Id composite, Id typeId, std::vector<unsigned>& indexes);
+    Id createCompositeInsert(Id object, Id composite, Id typeId, unsigned index);
+    Id createCompositeInsert(Id object, Id composite, Id typeId, std::vector<unsigned>& indexes);
+
+    Id createVectorExtractDynamic(Id vector, Id typeId, Id componentIndex);
+    Id createVectorInsertDynamic(Id vector, Id typeId, Id component, Id componentIndex);
+
+    void createNoResultOp(Op);
+    void createNoResultOp(Op, Id operand);
+    void createControlBarrier(unsigned executionScope);
+    void createMemoryBarrier(unsigned executionScope, unsigned memorySemantics);
+    Id createUnaryOp(Op, Id typeId, Id operand);
+    Id createBinOp(Op, Id typeId, Id operand1, Id operand2);
+    Id createTriOp(Op, Id typeId, Id operand1, Id operand2, Id operand3);
+    Id createTernaryOp(Op, Id typeId, Id operand1, Id operand2, Id operand3);
+    Id createFunctionCall(spv::Function*, std::vector<spv::Id>&);
+
+    // Take an rvalue (source) and a set of channels to extract from it to
+    // make a new rvalue, which is returned.
+    Id createRvalueSwizzle(Id typeId, Id source, std::vector<unsigned>& channels);
+
+    // Take a copy of an lvalue (target) and a source of components, and set the
+    // source components into the lvalue where the 'channels' say to put them.
+    // An updated version of the target is returned.
+    // (No true lvalue or stores are used.)
+    Id createLvalueSwizzle(Id typeId, Id target, Id source, std::vector<unsigned>& channels);
+
+    // If the value passed in is an instruction and the precision is not EMpNone,
+    // it gets tagged with the requested precision.
+    void setPrecision(Id /* value */, Decoration /* precision */)
+    {
+        // TODO
+    }
+
+    // Can smear a scalar to a vector for the following forms:
+    //   - promoteScalar(scalar, vector)  // smear scalar to width of vector
+    //   - promoteScalar(vector, scalar)  // smear scalar to width of vector
+    //   - promoteScalar(pointer, scalar) // smear scalar to width of what pointer points to
+    //   - promoteScalar(scalar, scalar)  // do nothing
+    // Other forms are not allowed.
+    //
+    // Note: One of the arguments will change, with the result coming back that way rather than 
+    // through the return value.
+    void promoteScalar(Decoration precision, Id& left, Id& right);
+
+    // make a value by smearing the scalar to fill the type
+    Id smearScalar(Decoration precision, Id scalarVal, Id);
+
+    // Create a call to a built-in function.
+    Id createBuiltinCall(Decoration precision, Id resultType, Id builtins, int entryPoint, std::vector<Id>& args);
+
+    // List of parameters used to create a texture operation
+    struct TextureParameters {
+        Id sampler;
+        Id coords;
+        Id bias;
+        Id lod;
+        Id Dref;
+        Id offset;
+        Id gradX;
+        Id gradY;
+    };
+
+    // Select the correct texture operation based on all inputs, and emit the correct instruction
+    Id createTextureCall(Decoration precision, Id resultType, bool proj, const TextureParameters&);
+
+    // Emit the OpTextureQuery* instruction that was passed in.
+    // Figure out the right return value and type, and return it.
+    Id createTextureQueryCall(Op, const TextureParameters&);
+
+    Id createSamplePositionCall(Decoration precision, Id, Id);
+
+    Id createBitFieldExtractCall(Decoration precision, Id, Id, Id, bool isSigned);
+    Id createBitFieldInsertCall(Decoration precision, Id, Id, Id, Id);
+
+    // Reduction comparision for composites:  For equal and not-equal resulting in a scalar.
+    Id createCompare(Decoration precision, Id, Id, bool /* true if for equal, fales if for not-equal */);
+
+    // OpCompositeConstruct
+    Id createCompositeConstruct(Id typeId, std::vector<Id>& constituents);
+
+    // vector or scalar constructor
+    Id createConstructor(Decoration precision, const std::vector<Id>& sources, Id resultTypeId);
+
+    // matrix constructor
+    Id createMatrixConstructor(Decoration precision, const std::vector<Id>& sources, Id constructee);
+
+    // Helper to use for building nested control flow with if-then-else.
+    class If {
+    public:
+        If(Id condition, Builder& builder);
+        ~If() {}
+
+        void makeBeginElse();
+        void makeEndIf();
+
+    private:
+        If(const If&);
+        If& operator=(If&);
+
+        Builder& builder;
+        Id condition;
+        Function* function;
+        Block* headerBlock;
+        Block* thenBlock;
+        Block* elseBlock;
+        Block* mergeBlock;
+    };
+
+    // Make a switch statement.  A switch has 'numSegments' of pieces of code, not containing
+    // any case/default labels, all separated by one or more case/default labels.  Each possible
+    // case value v is a jump to the caseValues[v] segment.  The defaultSegment is also in this
+    // number space.  How to compute the value is given by 'condition', as in switch(condition).
+    //
+    // The SPIR-V Builder will maintain the stack of post-switch merge blocks for nested switches.
+    //
+    // Use a defaultSegment < 0 if there is no default segment (to branch to post switch).
+    //
+    // Returns the right set of basic blocks to start each code segment with, so that the caller's
+    // recursion stack can hold the memory for it.
+    //
+    void makeSwitch(Id condition, int numSegments, std::vector<int>& caseValues, std::vector<int>& valueToSegment, int defaultSegment,
+                    std::vector<Block*>& segmentBB);  // return argument
+
+    // Add a branch to the innermost switch's merge block.
+    void addSwitchBreak();
+
+    // Move to the next code segment, passing in the return argument in makeSwitch()
+    void nextSwitchSegment(std::vector<Block*>& segmentBB, int segment);
+
+    // Finish off the innermost switch.
+    void endSwitch(std::vector<Block*>& segmentBB);
+
+    // Start the beginning of a new loop.
+    void makeNewLoop();
+
+    // Add the branch for the loop test, based on the given condition.
+    // The true branch goes to the block that remains inside the loop, and
+    // the false branch goes to the loop's merge block.  The  builder insertion
+    // point will be placed at the start of the inside-the-loop block.
+    void createLoopTestBranch(Id condition);
+
+    // Finish generating the loop header block in the case where the loop test
+    // is at the bottom of the loop.  It will include the LoopMerge instruction
+    // and a branch to the rest of the body.  The loop header block must be
+    // separate from the rest of the body to make room for the the two kinds
+    // of *Merge instructions that might have to occur just before a branch:
+    // the loop header must have a LoopMerge as its second-last instruction,
+    // and the body might begin with a conditional branch, which must have its
+    // own SelectionMerge instruction.
+    // Also create the basic block that will contain the loop test, but don't
+    // insert it into the function yet.  Any "continue" constructs in this loop
+    // will branch to the loop test block. The builder insertion point will be
+    // placed at the start of the body block.
+    void endLoopHeaderWithoutTest();
+
+    // Generate a branch to the loop test block.  This can only be called if
+    // the loop test is at the bottom of the loop. The builder insertion point
+    // is left at the start of the test block.
+    void createBranchToLoopTest();
+
+    // Add a branch to the test of the current (innermost) loop.
+    void createLoopContinue();
+
+    // Add an exit (e.g. "break") for the innermost loop that you're in
+    void createLoopExit();
+
+    // Close the innermost loop that you're in
+    void closeLoop();
+
+    //
+    // Access chain design for an R-Value vs. L-Value:
+    //
+    // There is a single access chain the builder is building at
+    // any particular time.  Such a chain can be used to either to a load or
+    // a store, when desired.
+    //
+    // Expressions can be r-values, l-values, or both, or only r-values:
+    //    a[b.c].d = ....  // l-value
+    //    ... = a[b.c].d;  // r-value, that also looks like an l-value
+    //    ++a[b.c].d;      // r-value and l-value
+    //    (x + y)[2];      // r-value only, can't possibly be l-value
+    //
+    // Computing an r-value means generating code.  Hence,
+    // r-values should only be computed when they are needed, not speculatively.
+    //
+    // Computing an l-value means saving away information for later use in the compiler,
+    // no code is generated until the l-value is later dereferenced.  It is okay
+    // to speculatively generate an l-value, just not okay to speculatively dereference it.
+    //
+    // The base of the access chain (the left-most variable or expression
+    // from which everything is based) can be set either as an l-value
+    // or as an r-value.  Most efficient would be to set an l-value if one
+    // is available.  If an expression was evaluated, the resulting r-value
+    // can be set as the chain base.
+    //
+    // The users of this single access chain can save and restore if they
+    // want to nest or manage multiple chains.
+    //
+
+    struct AccessChain {
+        Id base;                     // for l-values, pointer to the base object, for r-values, the base object
+        std::vector<Id> indexChain;
+        Id instr;                    // the instruction that generates this access chain
+        std::vector<unsigned> swizzle;
+        Id component;                // a dynamic component index, can coexist with a swizzle, done after the swizzle
+        Id resultType;               // dereferenced type, to be exclusive of swizzles
+        bool isRValue;
+    };
+
+    //
+    // the SPIR-V builder maintains a single active chain that
+    // the following methods operated on
+    //
+
+    // for external save and restore
+    AccessChain getAccessChain() { return accessChain; }
+    void setAccessChain(AccessChain newChain) { accessChain = newChain; }
+
+    // clear accessChain
+    void clearAccessChain();
+
+    // set new base as an l-value base
+    void setAccessChainLValue(Id lValue)
+    {
+        assert(isPointer(lValue));
+        accessChain.base = lValue;
+        accessChain.resultType = getContainedTypeId(getTypeId(lValue));
+    }
+
+    // set new base value as an r-value
+    void setAccessChainRValue(Id rValue)
+    {
+        accessChain.isRValue = true;
+        accessChain.base = rValue;
+        accessChain.resultType = getTypeId(rValue);
+    }
+
+    // push offset onto the end of the chain
+    void accessChainPush(Id offset, Id newType)
+    {
+        accessChain.indexChain.push_back(offset);
+        accessChain.resultType = newType;
+    }
+
+    // push new swizzle onto the end of any existing swizzle, merging into a single swizzle
+    void accessChainPushSwizzle(std::vector<unsigned>& swizzle);
+
+    // push a variable component selection onto the access chain; supporting only one, so unsided
+    void accessChainPushComponent(Id component) { accessChain.component = component; }
+
+    // use accessChain and swizzle to store value
+    void accessChainStore(Id rvalue);
+
+    // use accessChain and swizzle to load an r-value
+    Id accessChainLoad(Decoration precision);
+
+    // get the direct pointer for an l-value
+    Id accessChainGetLValue();
+
+    void dump(std::vector<unsigned int>&) const;
+
+protected:
+    Id findScalarConstant(Op typeClass, Id typeId, unsigned value) const;
+    Id findScalarConstant(Op typeClass, Id typeId, unsigned v1, unsigned v2) const;
+    Id findCompositeConstant(Op typeClass, std::vector<Id>& comps) const;
+    Id collapseAccessChain();
+    void simplifyAccessChainSwizzle();
+    void mergeAccessChainSwizzle();
+    void createAndSetNoPredecessorBlock(const char*);
+    void createBranch(Block* block);
+    void createMerge(Op, Block*, unsigned int control);
+    void createConditionalBranch(Id condition, Block* thenBlock, Block* elseBlock);
+    void dumpInstructions(std::vector<unsigned int>&, const std::vector<Instruction*>&) const;
+
+    SourceLanguage source;
+    int sourceVersion;
+    std::vector<const char*> extensions;
+    AddressingModel addressModel;
+    MemoryModel memoryModel;
+    int builderNumber;
+    Module module;
+    Block* buildPoint;
+    Id uniqueId;
+    Function* mainFunction;
+    Block* stageExit;
+    AccessChain accessChain;
+
+    // special blocks of instructions for output
+    std::vector<Instruction*> imports;
+    std::vector<Instruction*> entryPoints;
+    std::vector<Instruction*> executionModes;
+    std::vector<Instruction*> names;
+    std::vector<Instruction*> lines;
+    std::vector<Instruction*> decorations;
+    std::vector<Instruction*> constantsTypesGlobals;
+    std::vector<Instruction*> externals;
+
+     // not output, internally used for quick & dirty canonical (unique) creation
+    std::vector<Instruction*> groupedConstants[OpConstant];  // all types appear before OpConstant
+    std::vector<Instruction*> groupedTypes[OpConstant];
+
+    // stack of switches
+    std::stack<Block*> switchMerges;
+
+    // Data that needs to be kept in order to properly handle loops.
+    struct Loop {
+        // The header is the first block generated for the loop.
+        // It dominates all the blocks in the loop, i.e. it is always
+        // executed before any others.
+        // If the loop test is executed before the body (as in "while" and
+        // "for" loops), then the header begins with the test code.
+        // Otherwise, the loop is a "do-while" loop and the header contains the
+        // start of the body of the loop (if the body exists).
+        Block* header;
+        // The merge block marks the end of the loop.  Control is transferred
+        // to the merge block when either the loop test fails, or when a
+        // nested "break" is encountered.
+        Block* merge;
+        // If not NULL, the test block is the basic block containing the loop
+        // test and the conditional branch back to the header or the merge
+        // block.  This is created for "do-while" loops, and is the target of
+        // any "continue" constructs that might exist.
+        Block* test;
+        Function* function;
+    };
+
+    // Our loop stack.
+    std::stack<Loop> loops;
+};  // end Builder class
+
+void MissingFunctionality(const char*);
+void ValidationError(const char* error);
+
+};  // end spv namespace
+
+#endif // SpvBuilder_H
index bc8ca88..adbe1ac 100644 (file)
-//\r
-//Copyright (C) 2014 LunarG, Inc.\r
-//\r
-//All rights reserved.\r
-//\r
-//Redistribution and use in source and binary forms, with or without\r
-//modification, are permitted provided that the following conditions\r
-//are met:\r
-//\r
-//    Redistributions of source code must retain the above copyright\r
-//    notice, this list of conditions and the following disclaimer.\r
-//\r
-//    Redistributions in binary form must reproduce the above\r
-//    copyright notice, this list of conditions and the following\r
-//    disclaimer in the documentation and/or other materials provided\r
-//    with the distribution.\r
-//\r
-//    Neither the name of 3Dlabs Inc. Ltd. nor the names of its\r
-//    contributors may be used to endorse or promote products derived\r
-//    from this software without specific prior written permission.\r
-//\r
-//THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\r
-//"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\r
-//LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTAstreamITY AND FITNESS\r
-//FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE\r
-//COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,\r
-//INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,\r
-//BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\r
-//LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER\r
-//CAUSED AND ON ANY THEORY OF LIAstreamITY, WHETHER IN CONTRACT, STRICT\r
-//LIAstreamITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN\r
-//ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE\r
-//POSSIstreamITY OF SUCH DAMAGE.\r
-\r
-//\r
-// Author: John Kessenich, LunarG\r
-//\r
-\r
-//\r
-// Disassembler for SPIR-V.\r
-//\r
-\r
-#include <stdlib.h>\r
-#include <assert.h>\r
-#include <iomanip>\r
-#include <stack>\r
-#include <sstream>\r
-\r
-#include "GLSL450Lib.h"\r
-extern const char* GlslStd450DebugNames[GLSL_STD_450::Count];\r
-\r
-#include "disassemble.h"\r
-#include "doc.h"\r
-\r
-namespace spv {\r
-\r
-void Kill(std::ostream& out, const char* message)\r
-{\r
-    out << std::endl << "Disassembly failed: " << message << std::endl;\r
-    exit(1);\r
-}\r
-\r
-// Container class for a single instance of a SPIR-V stream, with methods for disassembly.\r
-class SpirvStream {\r
-public:\r
-    SpirvStream(std::ostream& out, const std::vector<unsigned int>& stream) : out(out), stream(stream), word(0), nextNestedControl(0) { }\r
-    virtual ~SpirvStream() { }\r
-\r
-    void validate();\r
-    void processInstructions();\r
-\r
-protected:\r
-    SpirvStream(SpirvStream&);\r
-    SpirvStream& operator=(SpirvStream&);\r
-\r
-    Op getOpCode(int id) const { return idInstruction[id] ? (Op)(stream[idInstruction[id]] & OpCodeMask) : OpNop; }\r
-\r
-    // Output methods\r
-    void outputIndent();\r
-    void formatId(Id id, std::stringstream&);\r
-    void outputResultId(Id id);\r
-    void outputTypeId(Id id);\r
-    void outputId(Id id);\r
-    void disassembleImmediates(int numOperands);\r
-    void disassembleIds(int numOperands);\r
-    void disassembleString();\r
-    void disassembleInstruction(Id resultId, Id typeId, Op opCode, int numOperands);\r
-\r
-    // Data\r
-    std::ostream& out;                       // where to write the disassembly\r
-    const std::vector<unsigned int>& stream; // the actual word stream\r
-    int size;                                // the size of the word stream\r
-    int word;                                // the next word of the stream to read\r
-\r
-    // map each <id> to the instruction that created it\r
-    Id bound;\r
-    std::vector<unsigned int> idInstruction;  // the word offset into the stream where the instruction for result [id] starts; 0 if not yet seen (forward reference or function parameter)\r
-\r
-    std::vector<std::string> idDescriptor;    // the best text string known for explaining the <id>\r
-\r
-    // schema\r
-    unsigned int schema;\r
-\r
-    // stack of structured-merge points\r
-    std::stack<Id> nestedControl;\r
-    Id nextNestedControl;         // need a slight delay for when we are nested\r
-};\r
-\r
-void SpirvStream::validate()\r
-{\r
-    size = (int)stream.size();\r
-    if (size < 4)\r
-        Kill(out, "stream is too short");\r
-\r
-    // Magic number\r
-    if (stream[word++] != MagicNumber) {\r
-        out << "Bad magic number";\r
-        return;\r
-    }\r
-\r
-    // Version\r
-    out << "// Module Version " << stream[word++] << std::endl;\r
-\r
-    // Generator's magic number\r
-    out << "// Generated by (magic number): " << std::setbase(16) << stream[word++] << std::setbase(10) << std::endl;\r
-\r
-    // Result <id> bound\r
-    bound = stream[word++];\r
-    idInstruction.resize(bound);\r
-    idDescriptor.resize(bound);\r
-    out << "// Id's are bound by " << bound << std::endl;\r
-    out << std::endl;\r
-\r
-    // Reserved schema, must be 0 for now\r
-    schema = stream[word++];\r
-    if (schema != 0)\r
-        Kill(out, "bad schema, must be 0");\r
-}\r
-\r
-// Loop over all the instructions, in order, processing each.\r
-// Boiler plate for each is handled here directly, the rest is dispatched.\r
-void SpirvStream::processInstructions()\r
-{\r
-    // Instructions\r
-    while (word < size) {\r
-        int instructionStart = word;\r
-\r
-        // Instruction wordCount and opcode\r
-        unsigned int firstWord = stream[word];\r
-        unsigned wordCount = firstWord >> WordCountShift;\r
-        Op opCode = (Op)(firstWord & OpCodeMask);\r
-        int nextInst = word + wordCount;\r
-        ++word;\r
-\r
-        // Presence of full instruction\r
-        if (nextInst > size)\r
-            Kill(out, "stream instruction terminated too early");\r
-\r
-        // Base for computing number of operands; will be updated as more is learned\r
-        unsigned numOperands = wordCount - 1;\r
-\r
-        // Type <id>\r
-        Id typeId = 0;\r
-        if (InstructionDesc[opCode].hasType()) {\r
-            typeId = stream[word++];\r
-            --numOperands;\r
-        }\r
-\r
-        // Result <id>\r
-        Id resultId = 0;\r
-        if (InstructionDesc[opCode].hasResult()) {\r
-            resultId = stream[word++];\r
-            --numOperands;\r
-\r
-            // save instruction for future reference\r
-            idInstruction[resultId] = instructionStart;\r
-        }\r
-\r
-        outputResultId(resultId);\r
-        outputTypeId(typeId);\r
-        outputIndent();\r
-\r
-        // Hand off the Op and all its operands\r
-        disassembleInstruction(resultId, typeId, opCode, numOperands);\r
-        if (word != nextInst) {\r
-            out << " ERROR, incorrect number of operands consumed.  At " << word << " instead of " << nextInst << " instruction start was " << instructionStart;\r
-            word = nextInst;\r
-        }\r
-        out << std::endl;\r
-    }\r
-}\r
-\r
-void SpirvStream::outputIndent()\r
-{\r
-    for (int i = 0; i < (int)nestedControl.size(); ++i)\r
-        out << "  ";\r
-}\r
-\r
-void SpirvStream::formatId(Id id, std::stringstream& idStream)\r
-{\r
-    if (id >= bound)\r
-        Kill(out, "Bad <id>");\r
-\r
-    if (id != 0) {\r
-        idStream << id;\r
-        if (idDescriptor[id].size() > 0)\r
-            idStream << "(" << idDescriptor[id] << ")";\r
-    }\r
-}\r
-\r
-void SpirvStream::outputResultId(Id id)\r
-{\r
-    const int width = 16;\r
-    std::stringstream idStream;\r
-    formatId(id, idStream);\r
-    out << std::setw(width) << std::right << idStream.str();\r
-    if (id != 0)\r
-        out << ":";\r
-    else\r
-        out << " ";\r
-\r
-    if (nestedControl.size() && id == nestedControl.top())\r
-        nestedControl.pop();\r
-}\r
-\r
-void SpirvStream::outputTypeId(Id id)\r
-{\r
-    const int width = 12;\r
-    std::stringstream idStream;\r
-    formatId(id, idStream);\r
-    out << std::setw(width) << std::right << idStream.str() << " ";\r
-}\r
-\r
-void SpirvStream::outputId(Id id)\r
-{\r
-    if (id >= bound)\r
-        Kill(out, "Bad <id>");\r
-\r
-    out << id;\r
-    if (idDescriptor[id].size() > 0)\r
-        out << "(" << idDescriptor[id] << ")";\r
-}\r
-\r
-void SpirvStream::disassembleImmediates(int numOperands)\r
-{\r
-    for (int i = 0; i < numOperands; ++i) {\r
-        out << stream[word++];\r
-        if (i < numOperands - 1)\r
-            out << " ";\r
-    }\r
-}\r
-\r
-void SpirvStream::disassembleIds(int numOperands)\r
-{\r
-    for (int i = 0; i < numOperands; ++i) {\r
-        outputId(stream[word++]);\r
-        if (i < numOperands - 1)\r
-            out << " ";\r
-    }\r
-}\r
-\r
-void SpirvStream::disassembleString()\r
-{\r
-    out << " \"";\r
-\r
-    char* wordString;\r
-    bool done = false;\r
-    do {\r
-        unsigned int content = stream[word];\r
-        wordString = (char*)&content;\r
-        for (int charCount = 0; charCount < 4; ++charCount) {\r
-            if (*wordString == 0) {\r
-                done = true;\r
-                break;\r
-            }\r
-            out << *(wordString++);\r
-        }\r
-        ++word;\r
-    } while (! done);\r
-\r
-    out << "\"";\r
-}\r
-\r
-void SpirvStream::disassembleInstruction(Id resultId, Id /*typeId*/, Op opCode, int numOperands)\r
-{\r
-    // Process the opcode\r
-\r
-    out << (OpcodeString(opCode) + 2);  // leave out the "Op"\r
-\r
-    if (opCode == OpLoopMerge || opCode == OpSelectionMerge)\r
-        nextNestedControl = stream[word];\r
-    else if (opCode == OpBranchConditional || opCode == OpSwitch) {\r
-        if (nextNestedControl) {\r
-            nestedControl.push(nextNestedControl);\r
-            nextNestedControl = 0;\r
-        }\r
-    } else if (opCode == OpExtInstImport)\r
-        idDescriptor[resultId] = (char*)(&stream[word]);\r
-    else {\r
-        if (idDescriptor[resultId].size() == 0) {\r
-            switch (opCode) {\r
-            case OpTypeInt:\r
-                idDescriptor[resultId] = "int";\r
-                break;\r
-            case OpTypeFloat:\r
-                idDescriptor[resultId] = "float";\r
-                break;\r
-            case OpTypeBool:\r
-                idDescriptor[resultId] = "bool";\r
-                break;\r
-            case OpTypeStruct:\r
-                idDescriptor[resultId] = "struct";\r
-                break;\r
-            case OpTypePointer:\r
-                idDescriptor[resultId] = "ptr";\r
-                break;\r
-            case OpTypeVector:\r
-                if (idDescriptor[stream[word]].size() > 0)\r
-                    idDescriptor[resultId].append(idDescriptor[stream[word]].begin(), idDescriptor[stream[word]].begin() + 1);\r
-                idDescriptor[resultId].append("vec");\r
-                switch (stream[word + 1]) {\r
-                case 2:   idDescriptor[resultId].append("2");   break;\r
-                case 3:   idDescriptor[resultId].append("3");   break;\r
-                case 4:   idDescriptor[resultId].append("4");   break;\r
-                case 8:   idDescriptor[resultId].append("8");   break;\r
-                case 16:  idDescriptor[resultId].append("16");  break;\r
-                case 32:  idDescriptor[resultId].append("32");  break;\r
-                default: break;\r
-                }\r
-                break;\r
-            default:\r
-                break;\r
-            }\r
-        }\r
-    }\r
-\r
-    // Process the operands.  Note, a new context-dependent set could be\r
-    // swapped in mid-traversal.\r
-\r
-    // Handle textures specially, so can put out helpful strings.\r
-    if (opCode == OpTypeSampler) {\r
-        disassembleIds(1);\r
-        out << " " << DimensionString((Dim)stream[word++]);\r
-        switch (stream[word++]) {\r
-        case 0: out << " texture";        break;\r
-        case 1: out << " image";          break;\r
-        case 2: out << " filter+texture"; break;\r
-        }\r
-        out << (stream[word++] != 0 ? " array" : "");\r
-        out << (stream[word++] != 0 ? " depth" : "");\r
-        out << (stream[word++] != 0 ? " multi-sampled" : "");\r
-        return;\r
-    }\r
-\r
-    // Handle all the parameterized operands\r
-    for (int op = 0; op < InstructionDesc[opCode].operands.getNum(); ++op) {\r
-        out << " ";\r
-        OperandClass operandClass = InstructionDesc[opCode].operands.getClass(op);\r
-        switch (operandClass) {\r
-        case OperandId:\r
-            disassembleIds(1);\r
-            // Get names for printing "(XXX)" for readability, *after* this id\r
-            if (opCode == OpName)\r
-                idDescriptor[stream[word - 1]] = (char*)(&stream[word]);\r
-            break;\r
-        case OperandOptionalId:\r
-        case OperandVariableIds:\r
-            disassembleIds(numOperands);\r
-            return;\r
-        case OperandVariableLiterals:\r
-            if ((opCode == OpDecorate && stream[word - 1] == DecorationBuiltIn) ||\r
-                (opCode == OpMemberDecorate && stream[word - 1] == DecorationBuiltIn)) {\r
-                out << BuiltInString(stream[word++]);\r
-                --numOperands;\r
-                ++op;\r
-            }\r
-            disassembleImmediates(numOperands);\r
-            return;\r
-        case OperandVariableLiteralId:\r
-            while (numOperands > 0) {\r
-                out << std::endl;\r
-                outputResultId(0);\r
-                outputTypeId(0);\r
-                outputIndent();\r
-                out << "     case ";\r
-                disassembleImmediates(1);\r
-                out << ": ";\r
-                disassembleIds(1);\r
-                numOperands -= 2;\r
-            }\r
-            return;\r
-        case OperandLiteralNumber:\r
-            disassembleImmediates(1);\r
-            if (opCode == OpExtInst) {\r
-                unsigned entrypoint = stream[word - 1];\r
-                if (entrypoint < GLSL_STD_450::Count)\r
-                    out << "(" << GlslStd450DebugNames[entrypoint] << ")";\r
-            }\r
-            break;\r
-        case OperandLiteralString:\r
-            disassembleString();\r
-            return;\r
-        default:\r
-            assert(operandClass >= OperandSource && operandClass < OperandOpcode);\r
-\r
-            if (OperandClassParams[operandClass].bitmask) {\r
-                unsigned int mask = stream[word++];\r
-                if (mask == 0)\r
-                    out << "None";\r
-                else {\r
-                    for (int m = 0; m < OperandClassParams[operandClass].ceiling; ++m) {\r
-                        if (mask & (1 << m))\r
-                            out << OperandClassParams[operandClass].getName(m) << " ";\r
-                    }\r
-                }\r
-                break;\r
-            } else\r
-                out << OperandClassParams[operandClass].getName(stream[word++]);\r
-\r
-            break;\r
-        }\r
-        --numOperands;\r
-    }\r
-\r
-    return;\r
-}\r
-\r
-void Disassemble(std::ostream& out, const std::vector<unsigned int>& stream)\r
-{\r
-    SpirvStream SpirvStream(out, stream);\r
-    SpirvStream.validate();\r
-    SpirvStream.processInstructions();\r
-}\r
-\r
-}; // end namespace spv\r
+//
+//Copyright (C) 2014 LunarG, Inc.
+//
+//All rights reserved.
+//
+//Redistribution and use in source and binary forms, with or without
+//modification, are permitted provided that the following conditions
+//are met:
+//
+//    Redistributions of source code must retain the above copyright
+//    notice, this list of conditions and the following disclaimer.
+//
+//    Redistributions in binary form must reproduce the above
+//    copyright notice, this list of conditions and the following
+//    disclaimer in the documentation and/or other materials provided
+//    with the distribution.
+//
+//    Neither the name of 3Dlabs Inc. Ltd. nor the names of its
+//    contributors may be used to endorse or promote products derived
+//    from this software without specific prior written permission.
+//
+//THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+//"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+//LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTAstreamITY AND FITNESS
+//FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+//COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+//INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+//BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+//LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+//CAUSED AND ON ANY THEORY OF LIAstreamITY, WHETHER IN CONTRACT, STRICT
+//LIAstreamITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+//ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+//POSSIstreamITY OF SUCH DAMAGE.
+
+//
+// Author: John Kessenich, LunarG
+//
+
+//
+// Disassembler for SPIR-V.
+//
+
+#include <stdlib.h>
+#include <assert.h>
+#include <iomanip>
+#include <stack>
+#include <sstream>
+
+#include "GLSL450Lib.h"
+extern const char* GlslStd450DebugNames[GLSL_STD_450::Count];
+
+#include "disassemble.h"
+#include "doc.h"
+
+namespace spv {
+
+void Kill(std::ostream& out, const char* message)
+{
+    out << std::endl << "Disassembly failed: " << message << std::endl;
+    exit(1);
+}
+
+// Container class for a single instance of a SPIR-V stream, with methods for disassembly.
+class SpirvStream {
+public:
+    SpirvStream(std::ostream& out, const std::vector<unsigned int>& stream) : out(out), stream(stream), word(0), nextNestedControl(0) { }
+    virtual ~SpirvStream() { }
+
+    void validate();
+    void processInstructions();
+
+protected:
+    SpirvStream(SpirvStream&);
+    SpirvStream& operator=(SpirvStream&);
+
+    Op getOpCode(int id) const { return idInstruction[id] ? (Op)(stream[idInstruction[id]] & OpCodeMask) : OpNop; }
+
+    // Output methods
+    void outputIndent();
+    void formatId(Id id, std::stringstream&);
+    void outputResultId(Id id);
+    void outputTypeId(Id id);
+    void outputId(Id id);
+    void disassembleImmediates(int numOperands);
+    void disassembleIds(int numOperands);
+    void disassembleString();
+    void disassembleInstruction(Id resultId, Id typeId, Op opCode, int numOperands);
+
+    // Data
+    std::ostream& out;                       // where to write the disassembly
+    const std::vector<unsigned int>& stream; // the actual word stream
+    int size;                                // the size of the word stream
+    int word;                                // the next word of the stream to read
+
+    // map each <id> to the instruction that created it
+    Id bound;
+    std::vector<unsigned int> idInstruction;  // the word offset into the stream where the instruction for result [id] starts; 0 if not yet seen (forward reference or function parameter)
+
+    std::vector<std::string> idDescriptor;    // the best text string known for explaining the <id>
+
+    // schema
+    unsigned int schema;
+
+    // stack of structured-merge points
+    std::stack<Id> nestedControl;
+    Id nextNestedControl;         // need a slight delay for when we are nested
+};
+
+void SpirvStream::validate()
+{
+    size = (int)stream.size();
+    if (size < 4)
+        Kill(out, "stream is too short");
+
+    // Magic number
+    if (stream[word++] != MagicNumber) {
+        out << "Bad magic number";
+        return;
+    }
+
+    // Version
+    out << "// Module Version " << stream[word++] << std::endl;
+
+    // Generator's magic number
+    out << "// Generated by (magic number): " << std::setbase(16) << stream[word++] << std::setbase(10) << std::endl;
+
+    // Result <id> bound
+    bound = stream[word++];
+    idInstruction.resize(bound);
+    idDescriptor.resize(bound);
+    out << "// Id's are bound by " << bound << std::endl;
+    out << std::endl;
+
+    // Reserved schema, must be 0 for now
+    schema = stream[word++];
+    if (schema != 0)
+        Kill(out, "bad schema, must be 0");
+}
+
+// Loop over all the instructions, in order, processing each.
+// Boiler plate for each is handled here directly, the rest is dispatched.
+void SpirvStream::processInstructions()
+{
+    // Instructions
+    while (word < size) {
+        int instructionStart = word;
+
+        // Instruction wordCount and opcode
+        unsigned int firstWord = stream[word];
+        unsigned wordCount = firstWord >> WordCountShift;
+        Op opCode = (Op)(firstWord & OpCodeMask);
+        int nextInst = word + wordCount;
+        ++word;
+
+        // Presence of full instruction
+        if (nextInst > size)
+            Kill(out, "stream instruction terminated too early");
+
+        // Base for computing number of operands; will be updated as more is learned
+        unsigned numOperands = wordCount - 1;
+
+        // Type <id>
+        Id typeId = 0;
+        if (InstructionDesc[opCode].hasType()) {
+            typeId = stream[word++];
+            --numOperands;
+        }
+
+        // Result <id>
+        Id resultId = 0;
+        if (InstructionDesc[opCode].hasResult()) {
+            resultId = stream[word++];
+            --numOperands;
+
+            // save instruction for future reference
+            idInstruction[resultId] = instructionStart;
+        }
+
+        outputResultId(resultId);
+        outputTypeId(typeId);
+        outputIndent();
+
+        // Hand off the Op and all its operands
+        disassembleInstruction(resultId, typeId, opCode, numOperands);
+        if (word != nextInst) {
+            out << " ERROR, incorrect number of operands consumed.  At " << word << " instead of " << nextInst << " instruction start was " << instructionStart;
+            word = nextInst;
+        }
+        out << std::endl;
+    }
+}
+
+void SpirvStream::outputIndent()
+{
+    for (int i = 0; i < (int)nestedControl.size(); ++i)
+        out << "  ";
+}
+
+void SpirvStream::formatId(Id id, std::stringstream& idStream)
+{
+    if (id >= bound)
+        Kill(out, "Bad <id>");
+
+    if (id != 0) {
+        idStream << id;
+        if (idDescriptor[id].size() > 0)
+            idStream << "(" << idDescriptor[id] << ")";
+    }
+}
+
+void SpirvStream::outputResultId(Id id)
+{
+    const int width = 16;
+    std::stringstream idStream;
+    formatId(id, idStream);
+    out << std::setw(width) << std::right << idStream.str();
+    if (id != 0)
+        out << ":";
+    else
+        out << " ";
+
+    if (nestedControl.size() && id == nestedControl.top())
+        nestedControl.pop();
+}
+
+void SpirvStream::outputTypeId(Id id)
+{
+    const int width = 12;
+    std::stringstream idStream;
+    formatId(id, idStream);
+    out << std::setw(width) << std::right << idStream.str() << " ";
+}
+
+void SpirvStream::outputId(Id id)
+{
+    if (id >= bound)
+        Kill(out, "Bad <id>");
+
+    out << id;
+    if (idDescriptor[id].size() > 0)
+        out << "(" << idDescriptor[id] << ")";
+}
+
+void SpirvStream::disassembleImmediates(int numOperands)
+{
+    for (int i = 0; i < numOperands; ++i) {
+        out << stream[word++];
+        if (i < numOperands - 1)
+            out << " ";
+    }
+}
+
+void SpirvStream::disassembleIds(int numOperands)
+{
+    for (int i = 0; i < numOperands; ++i) {
+        outputId(stream[word++]);
+        if (i < numOperands - 1)
+            out << " ";
+    }
+}
+
+void SpirvStream::disassembleString()
+{
+    out << " \"";
+
+    char* wordString;
+    bool done = false;
+    do {
+        unsigned int content = stream[word];
+        wordString = (char*)&content;
+        for (int charCount = 0; charCount < 4; ++charCount) {
+            if (*wordString == 0) {
+                done = true;
+                break;
+            }
+            out << *(wordString++);
+        }
+        ++word;
+    } while (! done);
+
+    out << "\"";
+}
+
+void SpirvStream::disassembleInstruction(Id resultId, Id /*typeId*/, Op opCode, int numOperands)
+{
+    // Process the opcode
+
+    out << (OpcodeString(opCode) + 2);  // leave out the "Op"
+
+    if (opCode == OpLoopMerge || opCode == OpSelectionMerge)
+        nextNestedControl = stream[word];
+    else if (opCode == OpBranchConditional || opCode == OpSwitch) {
+        if (nextNestedControl) {
+            nestedControl.push(nextNestedControl);
+            nextNestedControl = 0;
+        }
+    } else if (opCode == OpExtInstImport)
+        idDescriptor[resultId] = (char*)(&stream[word]);
+    else {
+        if (idDescriptor[resultId].size() == 0) {
+            switch (opCode) {
+            case OpTypeInt:
+                idDescriptor[resultId] = "int";
+                break;
+            case OpTypeFloat:
+                idDescriptor[resultId] = "float";
+                break;
+            case OpTypeBool:
+                idDescriptor[resultId] = "bool";
+                break;
+            case OpTypeStruct:
+                idDescriptor[resultId] = "struct";
+                break;
+            case OpTypePointer:
+                idDescriptor[resultId] = "ptr";
+                break;
+            case OpTypeVector:
+                if (idDescriptor[stream[word]].size() > 0)
+                    idDescriptor[resultId].append(idDescriptor[stream[word]].begin(), idDescriptor[stream[word]].begin() + 1);
+                idDescriptor[resultId].append("vec");
+                switch (stream[word + 1]) {
+                case 2:   idDescriptor[resultId].append("2");   break;
+                case 3:   idDescriptor[resultId].append("3");   break;
+                case 4:   idDescriptor[resultId].append("4");   break;
+                case 8:   idDescriptor[resultId].append("8");   break;
+                case 16:  idDescriptor[resultId].append("16");  break;
+                case 32:  idDescriptor[resultId].append("32");  break;
+                default: break;
+                }
+                break;
+            default:
+                break;
+            }
+        }
+    }
+
+    // Process the operands.  Note, a new context-dependent set could be
+    // swapped in mid-traversal.
+
+    // Handle textures specially, so can put out helpful strings.
+    if (opCode == OpTypeSampler) {
+        disassembleIds(1);
+        out << " " << DimensionString((Dim)stream[word++]);
+        switch (stream[word++]) {
+        case 0: out << " texture";        break;
+        case 1: out << " image";          break;
+        case 2: out << " filter+texture"; break;
+        }
+        out << (stream[word++] != 0 ? " array" : "");
+        out << (stream[word++] != 0 ? " depth" : "");
+        out << (stream[word++] != 0 ? " multi-sampled" : "");
+        return;
+    }
+
+    // Handle all the parameterized operands
+    for (int op = 0; op < InstructionDesc[opCode].operands.getNum(); ++op) {
+        out << " ";
+        OperandClass operandClass = InstructionDesc[opCode].operands.getClass(op);
+        switch (operandClass) {
+        case OperandId:
+            disassembleIds(1);
+            // Get names for printing "(XXX)" for readability, *after* this id
+            if (opCode == OpName)
+                idDescriptor[stream[word - 1]] = (char*)(&stream[word]);
+            break;
+        case OperandOptionalId:
+        case OperandVariableIds:
+            disassembleIds(numOperands);
+            return;
+        case OperandVariableLiterals:
+            if ((opCode == OpDecorate && stream[word - 1] == DecorationBuiltIn) ||
+                (opCode == OpMemberDecorate && stream[word - 1] == DecorationBuiltIn)) {
+                out << BuiltInString(stream[word++]);
+                --numOperands;
+                ++op;
+            }
+            disassembleImmediates(numOperands);
+            return;
+        case OperandVariableLiteralId:
+            while (numOperands > 0) {
+                out << std::endl;
+                outputResultId(0);
+                outputTypeId(0);
+                outputIndent();
+                out << "     case ";
+                disassembleImmediates(1);
+                out << ": ";
+                disassembleIds(1);
+                numOperands -= 2;
+            }
+            return;
+        case OperandLiteralNumber:
+            disassembleImmediates(1);
+            if (opCode == OpExtInst) {
+                unsigned entrypoint = stream[word - 1];
+                if (entrypoint < GLSL_STD_450::Count)
+                    out << "(" << GlslStd450DebugNames[entrypoint] << ")";
+            }
+            break;
+        case OperandLiteralString:
+            disassembleString();
+            return;
+        default:
+            assert(operandClass >= OperandSource && operandClass < OperandOpcode);
+
+            if (OperandClassParams[operandClass].bitmask) {
+                unsigned int mask = stream[word++];
+                if (mask == 0)
+                    out << "None";
+                else {
+                    for (int m = 0; m < OperandClassParams[operandClass].ceiling; ++m) {
+                        if (mask & (1 << m))
+                            out << OperandClassParams[operandClass].getName(m) << " ";
+                    }
+                }
+                break;
+            } else
+                out << OperandClassParams[operandClass].getName(stream[word++]);
+
+            break;
+        }
+        --numOperands;
+    }
+
+    return;
+}
+
+void Disassemble(std::ostream& out, const std::vector<unsigned int>& stream)
+{
+    SpirvStream SpirvStream(out, stream);
+    SpirvStream.validate();
+    SpirvStream.processInstructions();
+}
+
+}; // end namespace spv
index ca8bbb9..bcb05ef 100644 (file)
@@ -1,56 +1,56 @@
-//\r
-//Copyright (C) 2014 LunarG, Inc.\r
-//\r
-//All rights reserved.\r
-//\r
-//Redistribution and use in source and binary forms, with or without\r
-//modification, are permitted provided that the following conditions\r
-//are met:\r
-//\r
-//    Redistributions of source code must retain the above copyright\r
-//    notice, this list of conditions and the following disclaimer.\r
-//\r
-//    Redistributions in binary form must reproduce the above\r
-//    copyright notice, this list of conditions and the following\r
-//    disclaimer in the documentation and/or other materials provided\r
-//    with the distribution.\r
-//\r
-//    Neither the name of 3Dlabs Inc. Ltd. nor the names of its\r
-//    contributors may be used to endorse or promote products derived\r
-//    from this software without specific prior written permission.\r
-//\r
-//THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\r
-//"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\r
-//LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS\r
-//FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE\r
-//COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,\r
-//INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,\r
-//BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\r
-//LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER\r
-//CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\r
-//LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN\r
-//ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE\r
-//POSSIBILITY OF SUCH DAMAGE.\r
-\r
-//\r
-// Author: John Kessenich, LunarG\r
-//\r
-\r
-//\r
-// Disassembler for SPIR-V.\r
-//\r
-\r
-#pragma once\r
-#ifndef disassembler_H\r
-#define disassembler_H\r
-\r
-#include <iostream>\r
-#include <vector>\r
-\r
-namespace spv {\r
-\r
-    void Disassemble(std::ostream& out, const std::vector<unsigned int>&);\r
-\r
-};  // end namespace spv\r
-\r
-#endif // disassembler_H\r
+//
+//Copyright (C) 2014 LunarG, Inc.
+//
+//All rights reserved.
+//
+//Redistribution and use in source and binary forms, with or without
+//modification, are permitted provided that the following conditions
+//are met:
+//
+//    Redistributions of source code must retain the above copyright
+//    notice, this list of conditions and the following disclaimer.
+//
+//    Redistributions in binary form must reproduce the above
+//    copyright notice, this list of conditions and the following
+//    disclaimer in the documentation and/or other materials provided
+//    with the distribution.
+//
+//    Neither the name of 3Dlabs Inc. Ltd. nor the names of its
+//    contributors may be used to endorse or promote products derived
+//    from this software without specific prior written permission.
+//
+//THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+//"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+//LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+//FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+//COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+//INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+//BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+//LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+//CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+//LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+//ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+//POSSIBILITY OF SUCH DAMAGE.
+
+//
+// Author: John Kessenich, LunarG
+//
+
+//
+// Disassembler for SPIR-V.
+//
+
+#pragma once
+#ifndef disassembler_H
+#define disassembler_H
+
+#include <iostream>
+#include <vector>
+
+namespace spv {
+
+    void Disassemble(std::ostream& out, const std::vector<unsigned int>&);
+
+};  // end namespace spv
+
+#endif // disassembler_H
index 29658b6..a98ab4d 100644 (file)
-//\r
-//Copyright (C) 2014 LunarG, Inc.\r
-//\r
-//All rights reserved.\r
-//\r
-//Redistribution and use in source and binary forms, with or without\r
-//modification, are permitted provided that the following conditions\r
-//are met:\r
-//\r
-//    Redistributions of source code must retain the above copyright\r
-//    notice, this list of conditions and the following disclaimer.\r
-//\r
-//    Redistributions in binary form must reproduce the above\r
-//    copyright notice, this list of conditions and the following\r
-//    disclaimer in the documentation and/or other materials provided\r
-//    with the distribution.\r
-//\r
-//    Neither the name of 3Dlabs Inc. Ltd. nor the names of its\r
-//    contributors may be used to endorse or promote products derived\r
-//    from this software without specific prior written permission.\r
-//\r
-//THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\r
-//"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\r
-//LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS\r
-//FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE\r
-//COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,\r
-//INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,\r
-//BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\r
-//LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER\r
-//CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\r
-//LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN\r
-//ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE\r
-//POSSIBILITY OF SUCH DAMAGE.\r
-\r
-//\r
-// Author: John Kessenich, LunarG\r
-//\r
-\r
-//\r
-// 1) Programatically fill in instruction/operand information.\r
-//    This can be used for disassembly, printing documentation, etc.\r
-//\r
-// 2) Print documentation from this parameterization.\r
-//\r
-\r
-#include "doc.h"\r
-\r
-#include <stdio.h>\r
-#include <string.h>\r
-#include <algorithm>\r
-\r
-namespace spv {\r
-\r
-//\r
-// Whole set of functions that translate enumerants to their text strings for\r
-// the specification (or their sanitized versions for auto-generating the\r
-// spirv.h header.\r
-//\r
-// Also, the ceilings are declared next to these, to help keep them in sync.\r
-// Ceilings should be\r
-//  - one more than the maximum value an enumerant takes on, for non-mask enumerants\r
-//    (for non-sparse enums, this is the number of enumurants)\r
-//  - the number of bits consumed by the set of masks\r
-//    (for non-sparse mask enums, this is the number of enumurants)\r
-//\r
-\r
-const int SourceLanguageCeiling = 4;\r
-\r
-const char* SourceString(int source)\r
-{\r
-    switch (source) {\r
-    case 0:  return "Unknown";\r
-    case 1:  return "ESSL";\r
-    case 2:  return "GLSL";\r
-    case 3:  return "OpenCL";\r
-\r
-    case SourceLanguageCeiling:\r
-    default: return "Bad";\r
-    }\r
-}\r
-\r
-const int ExecutionModelCeiling = 7;\r
-\r
-const char* ExecutionModelString(int model)\r
-{\r
-    switch (model) {\r
-    case 0:  return "Vertex";\r
-    case 1:  return "TessellationControl";\r
-    case 2:  return "TessellationEvaluation";\r
-    case 3:  return "Geometry";\r
-    case 4:  return "Fragment";\r
-    case 5:  return "GLCompute";\r
-    case 6:  return "Kernel";\r
-\r
-    case ExecutionModelCeiling:\r
-    default: return "Bad";\r
-    }\r
-}\r
-\r
-const int AddressingModelCeiling = 3;\r
-\r
-const char* AddressingString(int addr)\r
-{\r
-    switch (addr) {\r
-    case 0:  return "Logical";\r
-    case 1:  return "Physical32";\r
-    case 2:  return "Physical64";\r
-\r
-    case AddressingModelCeiling:\r
-    default: return "Bad";\r
-    }\r
-}\r
-\r
-const int MemoryModelCeiling = 5;\r
-\r
-const char* MemoryString(int mem)\r
-{\r
-    switch (mem) {\r
-    case 0:  return "Simple";\r
-    case 1:  return "GLSL450";\r
-    case 2:  return "OpenCL1.2";\r
-    case 3:  return "OpenCL2.0";\r
-    case 4:  return "OpenCL2.1";\r
-\r
-    case MemoryModelCeiling:\r
-    default: return "Bad";\r
-    }\r
-}\r
-\r
-const int ExecutionModeCeiling = 31;\r
-\r
-const char* ExecutionModeString(int mode)\r
-{\r
-    switch (mode) {\r
-    case 0:  return "Invocations";\r
-    case 1:  return "SpacingEqual";\r
-    case 2:  return "SpacingFractionalEven";\r
-    case 3:  return "SpacingFractionalOdd";\r
-    case 4:  return "VertexOrderCw";\r
-    case 5:  return "VertexOrderCcw";\r
-    case 6:  return "PixelCenterInteger";\r
-    case 7:  return "OriginUpperLeft";\r
-    case 8:  return "EarlyFragmentTests";\r
-    case 9:  return "PointMode";\r
-    case 10: return "Xfb";\r
-    case 11: return "DepthReplacing";\r
-    case 12: return "DepthAny";\r
-    case 13: return "DepthGreater";\r
-    case 14: return "DepthLess";\r
-    case 15: return "DepthUnchanged";\r
-    case 16: return "LocalSize";\r
-    case 17: return "LocalSizeHint";\r
-    case 18: return "InputPoints";\r
-    case 19: return "InputLines";\r
-    case 20: return "InputLinesAdjacency";\r
-    case 21: return "InputTriangles";\r
-    case 22: return "InputTrianglesAdjacency";\r
-    case 23: return "InputQuads";\r
-    case 24: return "InputIsolines";\r
-    case 25: return "OutputVertices";\r
-    case 26: return "OutputPoints";\r
-    case 27: return "OutputLineStrip";\r
-    case 28: return "OutputTriangleStrip";\r
-    case 29: return "VecTypeHint";\r
-    case 30: return "ContractionOff";\r
-\r
-    case ExecutionModeCeiling:\r
-    default: return "Bad";\r
-    }\r
-}\r
-\r
-const int StorageClassCeiling = 11;\r
-\r
-const char* StorageClassString(int StorageClass)\r
-{\r
-    switch (StorageClass) {\r
-    case 0:  return "UniformConstant";\r
-    case 1:  return "Input";\r
-    case 2:  return "Uniform";\r
-    case 3:  return "Output";\r
-    case 4:  return "WorkgroupLocal";\r
-    case 5:  return "WorkgroupGlobal";\r
-    case 6:  return "PrivateGlobal";\r
-    case 7:  return "Function";\r
-    case 8:  return "Generic";\r
-    case 9:  return "Private";\r
-    case 10: return "AtomicCounter";\r
-\r
-    case StorageClassCeiling:\r
-    default: return "Bad";\r
-    }\r
-}\r
-\r
-const int DecorationCeiling = 45;\r
-\r
-const char* DecorationString(int decoration)\r
-{\r
-    switch (decoration) {\r
-    case 0:  return "PrecisionLow";\r
-    case 1:  return "PrecisionMedium";\r
-    case 2:  return "PrecisionHigh";\r
-    case 3:  return "Block";\r
-    case 4:  return "BufferBlock";\r
-    case 5:  return "RowMajor";\r
-    case 6:  return "ColMajor";\r
-    case 7:  return "GLSLShared";\r
-    case 8:  return "GLSLStd140";\r
-    case 9:  return "GLSLStd430";\r
-    case 10: return "GLSLPacked";\r
-    case 11: return "Smooth";\r
-    case 12: return "Noperspective";\r
-    case 13: return "Flat";\r
-    case 14: return "Patch";\r
-    case 15: return "Centroid";\r
-    case 16: return "Sample";\r
-    case 17: return "Invariant";\r
-    case 18: return "Restrict";\r
-    case 19: return "Aliased";\r
-    case 20: return "Volatile";\r
-    case 21: return "Constant";\r
-    case 22: return "Coherent";\r
-    case 23: return "Nonwritable";\r
-    case 24: return "Nonreadable";\r
-    case 25: return "Uniform";\r
-    case 26: return "NoStaticUse";\r
-    case 27: return "CPacked";\r
-    case 28: return "SaturatedConversion";\r
-    case 29: return "Stream";\r
-    case 30: return "Location";\r
-    case 31: return "Component";\r
-    case 32: return "Index";\r
-    case 33: return "Binding";\r
-    case 34: return "DescriptorSet";\r
-    case 35: return "Offset";\r
-    case 36: return "Alignment";\r
-    case 37: return "XfbBuffer";\r
-    case 38: return "Stride";\r
-    case 39: return "BuiltIn";\r
-    case 40: return "FuncParamAttr";\r
-    case 41: return "FP Rounding Mode";\r
-    case 42: return "FP Fast Math Mode";\r
-    case 43: return "Linkage Attributes";\r
-    case 44: return "SpecId";\r
-\r
-    case DecorationCeiling:\r
-    default:  return "Bad";\r
-    }\r
-}\r
-\r
-const int BuiltInCeiling = 42;\r
-\r
-const char* BuiltInString(int builtIn)\r
-{\r
-    switch (builtIn) {\r
-    case 0:  return "Position";\r
-    case 1:  return "PointSize";\r
-    case 2:  return "ClipVertex";\r
-    case 3:  return "ClipDistance";\r
-    case 4:  return "CullDistance";\r
-    case 5:  return "VertexId";\r
-    case 6:  return "InstanceId";\r
-    case 7:  return "PrimitiveId";\r
-    case 8:  return "InvocationId";\r
-    case 9:  return "Layer";\r
-    case 10: return "ViewportIndex";\r
-    case 11: return "TessLevelOuter";\r
-    case 12: return "TessLevelInner";\r
-    case 13: return "TessCoord";\r
-    case 14: return "PatchVertices";\r
-    case 15: return "FragCoord";\r
-    case 16: return "PointCoord";\r
-    case 17: return "FrontFacing";\r
-    case 18: return "SampleId";\r
-    case 19: return "SamplePosition";\r
-    case 20: return "SampleMask";\r
-    case 21: return "FragColor";\r
-    case 22: return "FragDepth";\r
-    case 23: return "HelperInvocation";\r
-    case 24: return "NumWorkgroups";\r
-    case 25: return "WorkgroupSize";\r
-    case 26: return "WorkgroupId";\r
-    case 27: return "LocalInvocationId";\r
-    case 28: return "GlobalInvocationId";\r
-    case 29: return "LocalInvocationIndex";\r
-    case 30: return "WorkDim";\r
-    case 31: return "GlobalSize";\r
-    case 32: return "EnqueuedWorkgroupSize";\r
-    case 33: return "GlobalOffset";\r
-    case 34: return "GlobalLinearId";\r
-    case 35: return "WorkgroupLinearId";\r
-    case 36: return "SubgroupSize";\r
-    case 37: return "SubgroupMaxSize";\r
-    case 38: return "NumSubgroups";\r
-    case 39: return "NumEnqueuedSubgroups";\r
-    case 40: return "SubgroupId";\r
-    case 41: return "SubgroupLocalInvocationId";\r
-\r
-    case BuiltInCeiling:\r
-    default: return "Bad";\r
-    }\r
-}\r
-\r
-const int DimensionCeiling = 6;\r
-\r
-const char* DimensionString(int dim)\r
-{\r
-    switch (dim) {\r
-    case 0:  return "1D";\r
-    case 1:  return "2D";\r
-    case 2:  return "3D";\r
-    case 3:  return "Cube";\r
-    case 4:  return "Rect";\r
-    case 5:  return "Buffer";\r
-\r
-    case DimensionCeiling:\r
-    default: return "Bad";\r
-    }\r
-}\r
-\r
-const int SamplerAddressingModeCeiling = 5;\r
-\r
-const char* SamplerAddressingModeString(int mode)\r
-{\r
-    switch (mode) {\r
-    case 0:  return "None";\r
-    case 1:  return "ClampToEdge";\r
-    case 2:  return "Clamp";\r
-    case 3:  return "Repeat";\r
-    case 4:  return "RepeatMirrored";\r
-\r
-    case SamplerAddressingModeCeiling:\r
-    default: return "Bad";\r
-    }\r
-}\r
-\r
-const int SamplerFilterModeCeiling = 2;\r
-\r
-const char* SamplerFilterModeString(int mode)\r
-{\r
-    switch (mode) {\r
-    case 0: return "Nearest";\r
-    case 1: return "Linear";\r
-\r
-    case SamplerFilterModeCeiling:\r
-    default: return "Bad";\r
-    }\r
-}\r
-\r
-const int FPFastMathCeiling = 5;\r
-\r
-const char* FPFastMathString(int mode)\r
-{\r
-    switch (mode) {\r
-    case 0: return "NotNaN";\r
-    case 1: return "NotInf";\r
-    case 2: return "NSZ";\r
-    case 3: return "AllowRecip";\r
-    case 4: return "Fast";\r
-\r
-    case FPFastMathCeiling:\r
-    default:     return "Bad";\r
-    }\r
-}\r
-\r
-const int FPRoundingModeCeiling = 4;\r
-\r
-const char* FPRoundingModeString(int mode)\r
-{\r
-    switch (mode) {\r
-    case 0:  return "RTE";\r
-    case 1:  return "RTZ";\r
-    case 2:  return "RTP";\r
-    case 3:  return "RTN";\r
-\r
-    case FPRoundingModeCeiling:\r
-    default: return "Bad";\r
-    }\r
-}\r
-\r
-const int LinkageTypeCeiling = 2;\r
-\r
-const char* LinkageTypeString(int type)\r
-{\r
-    switch (type) {\r
-    case 0:  return "Export";\r
-    case 1:  return "Import";\r
-\r
-    case LinkageTypeCeiling:\r
-    default: return "Bad";\r
-    }\r
-}\r
-\r
-const int FuncParamAttrCeiling = 9;\r
-\r
-const char* FuncParamAttrString(int attr)\r
-{\r
-    switch (attr) {\r
-    case 0:  return "Zext";\r
-    case 1:  return "Sext";\r
-    case 2:  return "ByVal";\r
-    case 3:  return "Sret";\r
-    case 4:  return "NoAlias";\r
-    case 5:  return "NoCapture";\r
-    case 6:  return "SVM";\r
-    case 7:  return "NoWrite";\r
-    case 8:  return "NoReadWrite";\r
-\r
-    case FuncParamAttrCeiling:\r
-    default: return "Bad";\r
-    }\r
-}\r
-\r
-const int AccessQualifierCeiling = 3;\r
-\r
-const char* AccessQualifierString(int attr)\r
-{\r
-    switch (attr) {\r
-    case 0:  return "ReadOnly";\r
-    case 1:  return "WriteOnly";\r
-    case 2:  return "ReadWrite";\r
-\r
-    case AccessQualifierCeiling:\r
-    default: return "Bad";\r
-    }\r
-}\r
-\r
-const int SelectControlCeiling = 2;\r
-\r
-const char* SelectControlString(int cont)\r
-{\r
-    switch (cont) {\r
-    case 0:  return "Flatten";\r
-    case 1:  return "DontFlatten";\r
-\r
-    case SelectControlCeiling:\r
-    default:                       return "Bad";\r
-    }\r
-}\r
-\r
-const int LoopControlCeiling = 2;\r
-\r
-const char* LoopControlString(int cont)\r
-{\r
-    switch (cont) {\r
-    case 0: return "Unroll";\r
-    case 1: return "DontUnroll";\r
-\r
-    case LoopControlCeiling:\r
-    default:     return "Bad";\r
-    }\r
-}\r
-\r
-const int FunctionControlCeiling = 4;\r
-\r
-const char* FunctionControlString(int cont)\r
-{\r
-    switch (cont) {\r
-    case 0:  return "Inline";\r
-    case 1:  return "DontInline";\r
-    case 2:  return "Pure";\r
-    case 3:  return "Const";\r
-\r
-    case FunctionControlCeiling:\r
-    default: return "Bad";\r
-    }\r
-}\r
-\r
-const int MemorySemanticsCeiling = 10;\r
-\r
-const char* MemorySemanticsString(int mem)\r
-{\r
-    switch (mem) {\r
-    case 0: return "Relaxed";\r
-    case 1: return "SequentiallyConsistent";\r
-    case 2: return "Acquire";\r
-    case 3: return "Release";\r
-\r
-    case 4: return "UniformMemory";\r
-    case 5: return "SubgroupMemory";\r
-    case 6: return "WorkgroupLocalMemory";\r
-    case 7: return "WorkgroupGlobalMemory";\r
-    case 8: return "AtomicCounterMemory";\r
-    case 9: return "ImageMemory";\r
-\r
-    case MemorySemanticsCeiling:\r
-    default:     return "Bad";\r
-    }\r
-}\r
-\r
-const int MemoryAccessCeiling = 2;\r
-\r
-const char* MemoryAccessString(int mem)\r
-{\r
-    switch (mem) {\r
-    case 0:  return "Volatile";\r
-    case 1:  return "Aligned";\r
-\r
-    case MemoryAccessCeiling:\r
-    default: return "Bad";\r
-    }\r
-}\r
-\r
-const int ExecutionScopeCeiling = 4;\r
-\r
-const char* ExecutionScopeString(int mem)\r
-{\r
-    switch (mem) {\r
-    case 0:  return "CrossDevice";\r
-    case 1:  return "Device";\r
-    case 2:  return "Workgroup";\r
-    case 3:  return "Subgroup";\r
-\r
-    case ExecutionScopeCeiling:\r
-    default: return "Bad";\r
-    }\r
-}\r
-\r
-const int GroupOperationCeiling = 3;\r
-\r
-const char* GroupOperationString(int gop)\r
-{\r
-\r
-    switch (gop)\r
-    {\r
-    case 0:  return "Reduce";\r
-    case 1:  return "InclusiveScan";\r
-    case 2:  return "ExclusiveScan";\r
-\r
-    case GroupOperationCeiling:\r
-    default: return "Bad";\r
-    }\r
-}\r
-\r
-const int KernelEnqueueFlagsCeiling = 3;\r
-\r
-const char* KernelEnqueueFlagsString(int flag)\r
-{\r
-    switch (flag)\r
-    {\r
-    case 0:  return "NoWait";\r
-    case 1:  return "WaitKernel";\r
-    case 2:  return "WaitWorkGroup";\r
-\r
-    case KernelEnqueueFlagsCeiling:\r
-    default: return "Bad";\r
-    }\r
-}\r
-\r
-const int KernelProfilingInfoCeiling = 1;\r
-\r
-const char* KernelProfilingInfoString(int info)\r
-{\r
-    switch (info)\r
-    {\r
-    case 0:  return "CmdExecTime";\r
-\r
-    case KernelProfilingInfoCeiling:\r
-    default: return "Bad";\r
-    }\r
-}\r
-\r
-const char* OpcodeString(int op)\r
-{\r
-    switch (op) {\r
-    case 0:   return "OpNop";\r
-    case 1:   return "OpSource";\r
-    case 2:   return "OpSourceExtension";\r
-    case 3:   return "OpExtension";\r
-    case 4:   return "OpExtInstImport";\r
-    case 5:   return "OpMemoryModel";\r
-    case 6:   return "OpEntryPoint";\r
-    case 7:   return "OpExecutionMode";\r
-    case 8:   return "OpTypeVoid";\r
-    case 9:   return "OpTypeBool";\r
-    case 10:  return "OpTypeInt";\r
-    case 11:  return "OpTypeFloat";\r
-    case 12:  return "OpTypeVector";\r
-    case 13:  return "OpTypeMatrix";\r
-    case 14:  return "OpTypeSampler";\r
-    case 15:  return "OpTypeFilter";\r
-    case 16:  return "OpTypeArray";\r
-    case 17:  return "OpTypeRuntimeArray";\r
-    case 18:  return "OpTypeStruct";\r
-    case 19:  return "OpTypeOpaque";\r
-    case 20:  return "OpTypePointer";\r
-    case 21:  return "OpTypeFunction";\r
-    case 22:  return "OpTypeEvent";\r
-    case 23:  return "OpTypeDeviceEvent";\r
-    case 24:  return "OpTypeReserveId";\r
-    case 25:  return "OpTypeQueue";\r
-    case 26:  return "OpTypePipe";\r
-    case 27:  return "OpConstantTrue";\r
-    case 28:  return "OpConstantFalse";\r
-    case 29:  return "OpConstant";\r
-    case 30:  return "OpConstantComposite";\r
-    case 31:  return "OpConstantSampler";\r
-    case 32:  return "OpConstantNullPointer";\r
-    case 33:  return "OpConstantNullObject";\r
-    case 34:  return "OpSpecConstantTrue";\r
-    case 35:  return "OpSpecConstantFalse";\r
-    case 36:  return "OpSpecConstant";\r
-    case 37:  return "OpSpecConstantComposite";\r
-    case 38:  return "OpVariable";\r
-    case 39:  return "OpVariableArray";\r
-    case 40:  return "OpFunction";\r
-    case 41:  return "OpFunctionParameter";\r
-    case 42:  return "OpFunctionEnd";\r
-    case 43:  return "OpFunctionCall";\r
-    case 44:  return "OpExtInst";\r
-    case 45:  return "OpUndef";\r
-    case 46:  return "OpLoad";\r
-    case 47:  return "OpStore";\r
-    case 48:  return "OpPhi";\r
-    case 49:  return "OpDecorationGroup";\r
-    case 50:  return "OpDecorate";\r
-    case 51:  return "OpMemberDecorate";\r
-    case 52:  return "OpGroupDecorate";\r
-    case 53:  return "OpGroupMemberDecorate";\r
-    case 54:  return "OpName";\r
-    case 55:  return "OpMemberName";\r
-    case 56:  return "OpString";\r
-    case 57:  return "OpLine";\r
-    case 58:  return "OpVectorExtractDynamic";\r
-    case 59:  return "OpVectorInsertDynamic";\r
-    case 60:  return "OpVectorShuffle";\r
-    case 61:  return "OpCompositeConstruct";\r
-    case 62:  return "OpCompositeExtract";\r
-    case 63:  return "OpCompositeInsert";\r
-    case 64:  return "OpCopyObject";\r
-    case 65:  return "OpCopyMemory";\r
-    case 66:  return "OpCopyMemorySized";\r
-    case 67:  return "OpSampler";\r
-    case 68:  return "OpTextureSample";\r
-    case 69:  return "OpTextureSampleDref";\r
-    case 70:  return "OpTextureSampleLod";\r
-    case 71:  return "OpTextureSampleProj";\r
-    case 72:  return "OpTextureSampleGrad";\r
-    case 73:  return "OpTextureSampleOffset";\r
-    case 74:  return "OpTextureSampleProjLod";\r
-    case 75:  return "OpTextureSampleProjGrad";\r
-    case 76:  return "OpTextureSampleLodOffset";\r
-    case 77:  return "OpTextureSampleProjOffset";\r
-    case 78:  return "OpTextureSampleGradOffset";\r
-    case 79:  return "OpTextureSampleProjLodOffset";\r
-    case 80:  return "OpTextureSampleProjGradOffset";\r
-    case 81:  return "OpTextureFetchTexelLod";\r
-    case 82:  return "OpTextureFetchTexelOffset";\r
-    case 83:  return "OpTextureFetchSample";\r
-    case 84:  return "OpTextureFetchTexel";\r
-    case 85:  return "OpTextureGather";\r
-    case 86:  return "OpTextureGatherOffset";\r
-    case 87:  return "OpTextureGatherOffsets";\r
-    case 88:  return "OpTextureQuerySizeLod";\r
-    case 89:  return "OpTextureQuerySize";\r
-    case 90:  return "OpTextureQueryLod";\r
-    case 91:  return "OpTextureQueryLevels";\r
-    case 92:  return "OpTextureQuerySamples";\r
-    case 93:  return "OpAccessChain";\r
-    case 94:  return "OpInBoundsAccessChain";\r
-    case 95:  return "OpSNegate";\r
-    case 96:  return "OpFNegate";\r
-    case 97:  return "OpNot";\r
-    case 98:  return "OpAny";\r
-    case 99:  return "OpAll";\r
-    case 100: return "OpConvertFToU";\r
-    case 101: return "OpConvertFToS";\r
-    case 102: return "OpConvertSToF";\r
-    case 103: return "OpConvertUToF";\r
-    case 104: return "OpUConvert";\r
-    case 105: return "OpSConvert";\r
-    case 106: return "OpFConvert";\r
-    case 107: return "OpConvertPtrToU";\r
-    case 108: return "OpConvertUToPtr";\r
-    case 109: return "OpPtrCastToGeneric";\r
-    case 110: return "OpGenericCastToPtr";\r
-    case 111: return "OpBitcast";\r
-    case 112: return "OpTranspose";\r
-    case 113: return "OpIsNan";\r
-    case 114: return "OpIsInf";\r
-    case 115: return "OpIsFinite";\r
-    case 116: return "OpIsNormal";\r
-    case 117: return "OpSignBitSet";\r
-    case 118: return "OpLessOrGreater";\r
-    case 119: return "OpOrdered";\r
-    case 120: return "OpUnordered";\r
-    case 121: return "OpArrayLength";\r
-    case 122: return "OpIAdd";\r
-    case 123: return "OpFAdd";\r
-    case 124: return "OpISub";\r
-    case 125: return "OpFSub";\r
-    case 126: return "OpIMul";\r
-    case 127: return "OpFMul";\r
-    case 128: return "OpUDiv";\r
-    case 129: return "OpSDiv";\r
-    case 130: return "OpFDiv";\r
-    case 131: return "OpUMod";\r
-    case 132: return "OpSRem";\r
-    case 133: return "OpSMod";\r
-    case 134: return "OpFRem";\r
-    case 135: return "OpFMod";\r
-    case 136: return "OpVectorTimesScalar";\r
-    case 137: return "OpMatrixTimesScalar";\r
-    case 138: return "OpVectorTimesMatrix";\r
-    case 139: return "OpMatrixTimesVector";\r
-    case 140: return "OpMatrixTimesMatrix";\r
-    case 141: return "OpOuterProduct";\r
-    case 142: return "OpDot";\r
-    case 143: return "OpShiftRightLogical";\r
-    case 144: return "OpShiftRightArithmetic";\r
-    case 145: return "OpShiftLeftLogical";\r
-    case 146: return "OpLogicalOr";\r
-    case 147: return "OpLogicalXor";\r
-    case 148: return "OpLogicalAnd";\r
-    case 149: return "OpBitwiseOr";\r
-    case 150: return "OpBitwiseXor";\r
-    case 151: return "OpBitwiseAnd";\r
-    case 152: return "OpSelect";\r
-    case 153: return "OpIEqual";\r
-    case 154: return "OpFOrdEqual";\r
-    case 155: return "OpFUnordEqual";\r
-    case 156: return "OpINotEqual";\r
-    case 157: return "OpFOrdNotEqual";\r
-    case 158: return "OpFUnordNotEqual";\r
-    case 159: return "OpULessThan";\r
-    case 160: return "OpSLessThan";\r
-    case 161: return "OpFOrdLessThan";\r
-    case 162: return "OpFUnordLessThan";\r
-    case 163: return "OpUGreaterThan";\r
-    case 164: return "OpSGreaterThan";\r
-    case 165: return "OpFOrdGreaterThan";\r
-    case 166: return "OpFUnordGreaterThan";\r
-    case 167: return "OpULessThanEqual";\r
-    case 168: return "OpSLessThanEqual";\r
-    case 169: return "OpFOrdLessThanEqual";\r
-    case 170: return "OpFUnordLessThanEqual";\r
-    case 171: return "OpUGreaterThanEqual";\r
-    case 172: return "OpSGreaterThanEqual";\r
-    case 173: return "OpFOrdGreaterThanEqual";\r
-    case 174: return "OpFUnordGreaterThanEqual";\r
-    case 175: return "OpDPdx";\r
-    case 176: return "OpDPdy";\r
-    case 177: return "OpFwidth";\r
-    case 178: return "OpDPdxFine";\r
-    case 179: return "OpDPdyFine";\r
-    case 180: return "OpFwidthFine";\r
-    case 181: return "OpDPdxCoarse";\r
-    case 182: return "OpDPdyCoarse";\r
-    case 183: return "OpFwidthCoarse";\r
-    case 184: return "OpEmitVertex";\r
-    case 185: return "OpEndPrimitive";\r
-    case 186: return "OpEmitStreamVertex";\r
-    case 187: return "OpEndStreamPrimitive";\r
-    case 188: return "OpControlBarrier";\r
-    case 189: return "OpMemoryBarrier";\r
-    case 190: return "OpImagePointer";\r
-    case 191: return "OpAtomicInit";\r
-    case 192: return "OpAtomicLoad";\r
-    case 193: return "OpAtomicStore";\r
-    case 194: return "OpAtomicExchange";\r
-    case 195: return "OpAtomicCompareExchange";\r
-    case 196: return "OpAtomicCompareExchangeWeak";\r
-    case 197: return "OpAtomicIIncrement";\r
-    case 198: return "OpAtomicIDecrement";\r
-    case 199: return "OpAtomicIAdd";\r
-    case 200: return "OpAtomicISub";\r
-    case 201: return "OpAtomicUMin";\r
-    case 202: return "OpAtomicUMax";\r
-    case 203: return "OpAtomicAnd";\r
-    case 204: return "OpAtomicOr";\r
-    case 205: return "OpAtomicXor";\r
-    case 206: return "OpLoopMerge";\r
-    case 207: return "OpSelectionMerge";\r
-    case 208: return "OpLabel";\r
-    case 209: return "OpBranch";\r
-    case 210: return "OpBranchConditional";\r
-    case 211: return "OpSwitch";\r
-    case 212: return "OpKill";\r
-    case 213: return "OpReturn";\r
-    case 214: return "OpReturnValue";\r
-    case 215: return "OpUnreachable";\r
-    case 216: return "OpLifetimeStart";\r
-    case 217: return "OpLifetimeStop";\r
-    case 218: return "OpCompileFlag";\r
-    case 219: return "OpAsyncGroupCopy";\r
-    case 220: return "OpWaitGroupEvents";\r
-    case 221: return "OpGroupAll";\r
-    case 222: return "OpGroupAny";\r
-    case 223: return "OpGroupBroadcast";\r
-    case 224: return "OpGroupIAdd";\r
-    case 225: return "OpGroupFAdd";\r
-    case 226: return "OpGroupFMin";\r
-    case 227: return "OpGroupUMin";\r
-    case 228: return "OpGroupSMin";\r
-    case 229: return "OpGroupFMax";\r
-    case 230: return "OpGroupUMax";\r
-    case 231: return "OpGroupSMax";\r
-    case 232: return "OpGenericCastToPtrExplicit";\r
-    case 233: return "OpGenericPtrMemSemantics";\r
-    case 234: return "OpReadPipe";\r
-    case 235: return "OpWritePipe";\r
-    case 236: return "OpReservedReadPipe";\r
-    case 237: return "OpReservedWritePipe";\r
-    case 238: return "OpReserveReadPipePackets";\r
-    case 239: return "OpReserveWritePipePackets";\r
-    case 240: return "OpCommitReadPipe";\r
-    case 241: return "OpCommitWritePipe";\r
-    case 242: return "OpIsValidReserveId";\r
-    case 243: return "OpGetNumPipePackets";\r
-    case 244: return "OpGetMaxPipePackets";\r
-    case 245: return "OpGroupReserveReadPipePackets";\r
-    case 246: return "OpGroupReserveWritePipePackets";\r
-    case 247: return "OpGroupCommitReadPipe";\r
-    case 248: return "OpGroupCommitWritePipe";\r
-    case 249: return "OpEnqueueMarker";\r
-    case 250: return "OpEnqueueKernel";\r
-    case 251: return "OpGetKernelNDrangeSubGroupCount";\r
-    case 252: return "OpGetKernelNDrangeMaxSubGroupSize";\r
-    case 253: return "OpGetKernelWorkGroupSize";\r
-    case 254: return "OpGetKernelPreferredWorkGroupSizeMultiple";\r
-    case 255: return "OpRetainEvent";\r
-    case 256: return "OpReleaseEvent";\r
-    case 257: return "OpCreateUserEvent";\r
-    case 258: return "OpIsValidEvent";\r
-    case 259: return "OpSetUserEventStatus";\r
-    case 260: return "OpCaptureEventProfilingInfo";\r
-    case 261: return "OpGetDefaultQueue";\r
-    case 262: return "OpBuildNDRange";\r
-    case 263: return "OpSatConvertSToU";\r
-    case 264: return "OpSatConvertUToS";\r
-    case 265: return "OpAtomicIMin";\r
-    case 266: return "OpAtomicIMax";\r
-\r
-    case OpcodeCeiling:\r
-    default:\r
-        return "Bad";\r
-    }\r
-}\r
-\r
-// The set of objects that hold all the instruction/operand\r
-// parameterization information.\r
-InstructionParameters InstructionDesc[OpcodeCeiling];\r
-OperandParameters ExecutionModeOperands[ExecutionModeCeiling];\r
-OperandParameters DecorationOperands[DecorationCeiling];\r
-\r
-EnumDefinition OperandClassParams[OperandCount];\r
-EnumParameters ExecutionModelParams[ExecutionModelCeiling];\r
-EnumParameters AddressingParams[AddressingModelCeiling];\r
-EnumParameters MemoryParams[MemoryModelCeiling];\r
-EnumParameters ExecutionModeParams[ExecutionModeCeiling];\r
-EnumParameters StorageParams[StorageClassCeiling];\r
-EnumParameters SamplerAddressingModeParams[SamplerAddressingModeCeiling];\r
-EnumParameters SamplerFilterModeParams[SamplerFilterModeCeiling];\r
-EnumParameters FPFastMathParams[FPFastMathCeiling];\r
-EnumParameters FPRoundingModeParams[FPRoundingModeCeiling];\r
-EnumParameters LinkageTypeParams[LinkageTypeCeiling];\r
-EnumParameters DecorationParams[DecorationCeiling];\r
-EnumParameters BuiltInParams[BuiltInCeiling];\r
-EnumParameters DimensionalityParams[DimensionCeiling];\r
-EnumParameters FuncParamAttrParams[FuncParamAttrCeiling];\r
-EnumParameters AccessQualifierParams[AccessQualifierCeiling];\r
-EnumParameters GroupOperationParams[GroupOperationCeiling];\r
-EnumParameters LoopControlParams[FunctionControlCeiling];\r
-EnumParameters SelectionControlParams[SelectControlCeiling];\r
-EnumParameters FunctionControlParams[FunctionControlCeiling];\r
-EnumParameters MemorySemanticsParams[MemorySemanticsCeiling];\r
-EnumParameters MemoryAccessParams[MemoryAccessCeiling];\r
-EnumParameters ExecutionScopeParams[ExecutionScopeCeiling];\r
-EnumParameters KernelEnqueueFlagsParams[KernelEnqueueFlagsCeiling];\r
-EnumParameters KernelProfilingInfoParams[KernelProfilingInfoCeiling];\r
-\r
-// Set up all the parameterizing descriptions of the opcodes, operands, etc.\r
-void Parameterize()\r
-{\r
-    static bool initialized = false;\r
-\r
-    // only do this once.\r
-    if (initialized)\r
-        return;\r
-\r
-    initialized = true;\r
-\r
-    // Exceptions to having a result <id> and a resulting type <id>.\r
-    // (Everything is initialized to have both).\r
-\r
-    InstructionDesc[OpNop].setResultAndType(false, false);\r
-    InstructionDesc[OpSource].setResultAndType(false, false);\r
-    InstructionDesc[OpSourceExtension].setResultAndType(false, false);\r
-    InstructionDesc[OpExtension].setResultAndType(false, false);\r
-    InstructionDesc[OpExtInstImport].setResultAndType(true, false);\r
-    InstructionDesc[OpMemoryModel].setResultAndType(false, false);\r
-    InstructionDesc[OpEntryPoint].setResultAndType(false, false);\r
-    InstructionDesc[OpExecutionMode].setResultAndType(false, false);\r
-    InstructionDesc[OpTypeVoid].setResultAndType(true, false);\r
-    InstructionDesc[OpTypeBool].setResultAndType(true, false);\r
-    InstructionDesc[OpTypeInt].setResultAndType(true, false);\r
-    InstructionDesc[OpTypeFloat].setResultAndType(true, false);\r
-    InstructionDesc[OpTypeVector].setResultAndType(true, false);\r
-    InstructionDesc[OpTypeMatrix].setResultAndType(true, false);\r
-    InstructionDesc[OpTypeSampler].setResultAndType(true, false);\r
-    InstructionDesc[OpTypeFilter].setResultAndType(true, false);\r
-    InstructionDesc[OpTypeArray].setResultAndType(true, false);\r
-    InstructionDesc[OpTypeRuntimeArray].setResultAndType(true, false);\r
-    InstructionDesc[OpTypeStruct].setResultAndType(true, false);\r
-    InstructionDesc[OpTypeOpaque].setResultAndType(true, false);\r
-    InstructionDesc[OpTypePointer].setResultAndType(true, false);\r
-    InstructionDesc[OpTypeFunction].setResultAndType(true, false);\r
-    InstructionDesc[OpTypeEvent].setResultAndType(true, false);\r
-    InstructionDesc[OpTypeDeviceEvent].setResultAndType(true, false);\r
-    InstructionDesc[OpTypeReserveId].setResultAndType(true, false);\r
-    InstructionDesc[OpTypeQueue].setResultAndType(true, false);\r
-    InstructionDesc[OpTypePipe].setResultAndType(true, false);\r
-    InstructionDesc[OpFunctionEnd].setResultAndType(false, false);\r
-    InstructionDesc[OpStore].setResultAndType(false, false);\r
-    InstructionDesc[OpDecorationGroup].setResultAndType(true, false);\r
-    InstructionDesc[OpDecorate].setResultAndType(false, false);\r
-    InstructionDesc[OpMemberDecorate].setResultAndType(false, false);\r
-    InstructionDesc[OpGroupDecorate].setResultAndType(false, false);\r
-    InstructionDesc[OpGroupMemberDecorate].setResultAndType(false, false);\r
-    InstructionDesc[OpName].setResultAndType(false, false);\r
-    InstructionDesc[OpMemberName].setResultAndType(false, false);\r
-    InstructionDesc[OpString].setResultAndType(true, false);\r
-    InstructionDesc[OpLine].setResultAndType(false, false);\r
-    InstructionDesc[OpCopyMemory].setResultAndType(false, false);\r
-    InstructionDesc[OpCopyMemorySized].setResultAndType(false, false);\r
-    InstructionDesc[OpEmitVertex].setResultAndType(false, false);\r
-    InstructionDesc[OpEndPrimitive].setResultAndType(false, false);\r
-    InstructionDesc[OpEmitStreamVertex].setResultAndType(false, false);\r
-    InstructionDesc[OpEndStreamPrimitive].setResultAndType(false, false);\r
-    InstructionDesc[OpControlBarrier].setResultAndType(false, false);\r
-    InstructionDesc[OpMemoryBarrier].setResultAndType(false, false);\r
-    InstructionDesc[OpAtomicInit].setResultAndType(false, false);\r
-    InstructionDesc[OpAtomicStore].setResultAndType(false, false);\r
-    InstructionDesc[OpLoopMerge].setResultAndType(false, false);\r
-    InstructionDesc[OpSelectionMerge].setResultAndType(false, false);\r
-    InstructionDesc[OpLabel].setResultAndType(true, false);\r
-    InstructionDesc[OpBranch].setResultAndType(false, false);\r
-    InstructionDesc[OpBranchConditional].setResultAndType(false, false);\r
-    InstructionDesc[OpSwitch].setResultAndType(false, false);\r
-    InstructionDesc[OpKill].setResultAndType(false, false);\r
-    InstructionDesc[OpReturn].setResultAndType(false, false);\r
-    InstructionDesc[OpReturnValue].setResultAndType(false, false);\r
-    InstructionDesc[OpUnreachable].setResultAndType(false, false);\r
-    InstructionDesc[OpLifetimeStart].setResultAndType(false, false);\r
-    InstructionDesc[OpLifetimeStop].setResultAndType(false, false);\r
-    InstructionDesc[OpCompileFlag].setResultAndType(false, false);\r
-    InstructionDesc[OpCommitReadPipe].setResultAndType(false, false);\r
-    InstructionDesc[OpCommitWritePipe].setResultAndType(false, false);\r
-    InstructionDesc[OpGroupCommitWritePipe].setResultAndType(false, false);\r
-    InstructionDesc[OpGroupCommitReadPipe].setResultAndType(false, false);\r
-    InstructionDesc[OpCaptureEventProfilingInfo].setResultAndType(false, false);\r
-    InstructionDesc[OpSetUserEventStatus].setResultAndType(false, false);\r
-    InstructionDesc[OpRetainEvent].setResultAndType(false, false);\r
-    InstructionDesc[OpReleaseEvent].setResultAndType(false, false);\r
-\r
-    // Specific additional context-dependent operands\r
-\r
-    ExecutionModeOperands[ExecutionModeInvocations].push(OperandLiteralNumber, "Number of invocations");\r
-\r
-    ExecutionModeOperands[ExecutionModeLocalSize].push(OperandLiteralNumber, "'x size'");\r
-    ExecutionModeOperands[ExecutionModeLocalSize].push(OperandLiteralNumber, "'y size'");\r
-    ExecutionModeOperands[ExecutionModeLocalSize].push(OperandLiteralNumber, "'z size'");\r
-\r
-    ExecutionModeOperands[ExecutionModeLocalSizeHint].push(OperandLiteralNumber, "'x size'");\r
-    ExecutionModeOperands[ExecutionModeLocalSizeHint].push(OperandLiteralNumber, "'y size'");\r
-    ExecutionModeOperands[ExecutionModeLocalSizeHint].push(OperandLiteralNumber, "'z size'");\r
-\r
-    ExecutionModeOperands[ExecutionModeOutputVertices].push(OperandLiteralNumber, "Vertex count");\r
-    ExecutionModeOperands[ExecutionModeVecTypeHint].push(OperandId, "Vector type");\r
-\r
-    DecorationOperands[DecorationStream].push(OperandLiteralNumber, "Stream number");\r
-    DecorationOperands[DecorationLocation].push(OperandLiteralNumber, "Location");\r
-    DecorationOperands[DecorationComponent].push(OperandLiteralNumber, "Component within a vector");\r
-    DecorationOperands[DecorationIndex].push(OperandLiteralNumber, "Index");\r
-    DecorationOperands[DecorationBinding].push(OperandLiteralNumber, "Binding point");\r
-    DecorationOperands[DecorationDescriptorSet].push(OperandLiteralNumber, "Descriptor set");\r
-    DecorationOperands[DecorationOffset].push(OperandLiteralNumber, "Byte offset");\r
-    DecorationOperands[DecorationAlignment].push(OperandLiteralNumber, "Declared alignment");\r
-    DecorationOperands[DecorationXfbBuffer].push(OperandLiteralNumber, "XFB Buffer number");\r
-    DecorationOperands[DecorationStride].push(OperandLiteralNumber, "Stride");\r
-    DecorationOperands[DecorationBuiltIn].push(OperandLiteralNumber, "See <<BuiltIn,*BuiltIn*>>");\r
-    DecorationOperands[DecorationFPRoundingMode].push(OperandFPRoundingMode, "floating-point rounding mode");\r
-    DecorationOperands[DecorationFPFastMathMode].push(OperandFPFastMath, "fast-math mode");\r
-    DecorationOperands[DecorationLinkageAttributes].push(OperandLiteralString, "name");\r
-    DecorationOperands[DecorationLinkageAttributes].push(OperandLinkageType, "linkage type");\r
-    DecorationOperands[DecorationFuncParamAttr].push(OperandFuncParamAttr, "function parameter attribute");\r
-    DecorationOperands[DecorationSpecId].push(OperandLiteralNumber, "Specialization Constant ID");\r
-\r
-    OperandClassParams[OperandSource].set(SourceLanguageCeiling, SourceString, 0);\r
-    OperandClassParams[OperandExecutionModel].set(ExecutionModelCeiling, ExecutionModelString, ExecutionModelParams);\r
-    OperandClassParams[OperandAddressing].set(AddressingModelCeiling, AddressingString, AddressingParams);\r
-    OperandClassParams[OperandMemory].set(MemoryModelCeiling, MemoryString, MemoryParams);\r
-    OperandClassParams[OperandExecutionMode].set(ExecutionModeCeiling, ExecutionModeString, ExecutionModeParams);\r
-    OperandClassParams[OperandExecutionMode].setOperands(ExecutionModeOperands);\r
-    OperandClassParams[OperandStorage].set(StorageClassCeiling, StorageClassString, StorageParams);\r
-    OperandClassParams[OperandDimensionality].set(DimensionCeiling, DimensionString, DimensionalityParams);\r
-    OperandClassParams[OperandSamplerAddressingMode].set(SamplerAddressingModeCeiling, SamplerAddressingModeString, SamplerAddressingModeParams);\r
-    OperandClassParams[OperandSamplerFilterMode].set(SamplerFilterModeCeiling, SamplerFilterModeString, SamplerFilterModeParams);\r
-    OperandClassParams[OperandFPFastMath].set(FPFastMathCeiling, FPFastMathString, FPFastMathParams, true);\r
-    OperandClassParams[OperandFPRoundingMode].set(FPRoundingModeCeiling, FPRoundingModeString, FPRoundingModeParams);\r
-    OperandClassParams[OperandLinkageType].set(LinkageTypeCeiling, LinkageTypeString, LinkageTypeParams);\r
-    OperandClassParams[OperandFuncParamAttr].set(FuncParamAttrCeiling, FuncParamAttrString, FuncParamAttrParams);\r
-    OperandClassParams[OperandAccessQualifier].set(AccessQualifierCeiling, AccessQualifierString, AccessQualifierParams);\r
-    OperandClassParams[OperandDecoration].set(DecorationCeiling, DecorationString, DecorationParams);\r
-    OperandClassParams[OperandDecoration].setOperands(DecorationOperands);\r
-    OperandClassParams[OperandBuiltIn].set(BuiltInCeiling, BuiltInString, BuiltInParams);\r
-    OperandClassParams[OperandSelect].set(SelectControlCeiling, SelectControlString, SelectionControlParams, true);\r
-    OperandClassParams[OperandLoop].set(LoopControlCeiling, LoopControlString, LoopControlParams, true);\r
-    OperandClassParams[OperandFunction].set(FunctionControlCeiling, FunctionControlString, FunctionControlParams, true);\r
-    OperandClassParams[OperandMemorySemantics].set(MemorySemanticsCeiling, MemorySemanticsString, MemorySemanticsParams, true);\r
-    OperandClassParams[OperandMemoryAccess].set(MemoryAccessCeiling, MemoryAccessString, MemoryAccessParams, true);\r
-    OperandClassParams[OperandExecutionScope].set(ExecutionScopeCeiling, ExecutionScopeString, ExecutionScopeParams);\r
-    OperandClassParams[OperandGroupOperation].set(GroupOperationCeiling, GroupOperationString, GroupOperationParams);\r
-    OperandClassParams[OperandKernelEnqueueFlags].set(KernelEnqueueFlagsCeiling, KernelEnqueueFlagsString, KernelEnqueueFlagsParams);\r
-    OperandClassParams[OperandKernelProfilingInfo].set(KernelProfilingInfoCeiling, KernelProfilingInfoString, KernelProfilingInfoParams, true);\r
-    OperandClassParams[OperandOpcode].set(OpcodeCeiling, OpcodeString, 0);\r
-\r
-    AddressingParams[AddressingModelPhysical32].caps.push_back(CapAddr);\r
-    AddressingParams[AddressingModelPhysical64].caps.push_back(CapAddr);\r
-\r
-    MemoryParams[MemoryModelSimple].caps.push_back(CapShader);\r
-    MemoryParams[MemoryModelGLSL450].caps.push_back(CapShader);\r
-    MemoryParams[MemoryModelOpenCL12].caps.push_back(CapKernel);\r
-    MemoryParams[MemoryModelOpenCL20].caps.push_back(CapKernel);\r
-    MemoryParams[MemoryModelOpenCL21].caps.push_back(CapKernel);\r
-\r
-    ExecutionModelParams[ExecutionModelVertex].caps.push_back(CapShader);\r
-    ExecutionModelParams[ExecutionModelTessellationControl].caps.push_back(CapTess);\r
-    ExecutionModelParams[ExecutionModelTessellationEvaluation].caps.push_back(CapTess);\r
-    ExecutionModelParams[ExecutionModelGeometry].caps.push_back(CapGeom);\r
-    ExecutionModelParams[ExecutionModelFragment].caps.push_back(CapShader);\r
-    ExecutionModelParams[ExecutionModelGLCompute].caps.push_back(CapShader);\r
-    ExecutionModelParams[ExecutionModelKernel].caps.push_back(CapKernel);\r
-\r
-    // Storage capabilites\r
-    StorageParams[StorageClassInput].caps.push_back(CapShader);\r
-    StorageParams[StorageClassUniform].caps.push_back(CapShader);\r
-    StorageParams[StorageClassOutput].caps.push_back(CapShader);\r
-    StorageParams[StorageClassPrivateGlobal].caps.push_back(CapShader);\r
-    StorageParams[StorageClassFunction].caps.push_back(CapShader);\r
-    StorageParams[StorageClassGeneric].caps.push_back(CapKernel);\r
-    StorageParams[StorageClassPrivate].caps.push_back(CapKernel);\r
-    StorageParams[StorageClassAtomicCounter].caps.push_back(CapShader);\r
-\r
-    // Sampler Filter & Addressing mode capabilities\r
-    SamplerAddressingModeParams[SamplerAddressingModeNone].caps.push_back(CapKernel);\r
-    SamplerAddressingModeParams[SamplerAddressingModeClampToEdge].caps.push_back(CapKernel);\r
-    SamplerAddressingModeParams[SamplerAddressingModeClamp].caps.push_back(CapKernel);\r
-    SamplerAddressingModeParams[SamplerAddressingModeRepeat].caps.push_back(CapKernel);\r
-    SamplerAddressingModeParams[SamplerAddressingModeRepeatMirrored].caps.push_back(CapKernel);\r
-\r
-    SamplerFilterModeParams[SamplerFilterModeNearest].caps.push_back(CapKernel);\r
-    SamplerFilterModeParams[SamplerFilterModeLinear].caps.push_back(CapKernel);\r
-\r
-    // fast math flags capabilities\r
-    for (int i = 0; i < FPFastMathCeiling; ++i) {\r
-        FPFastMathParams[i].caps.push_back(CapKernel);\r
-    }\r
-\r
-    // fp rounding mode capabilities\r
-    for (int i = 0; i < FPRoundingModeCeiling; ++i) {\r
-        FPRoundingModeParams[i].caps.push_back(CapKernel);\r
-    }\r
-\r
-    // linkage types\r
-    for (int i = 0; i < LinkageTypeCeiling; ++i) {\r
-        LinkageTypeParams[i].caps.push_back(CapLink);\r
-    }\r
-\r
-    // function argument types\r
-    for (int i = 0; i < FuncParamAttrCeiling; ++i) {\r
-        FuncParamAttrParams[i].caps.push_back(CapKernel);\r
-    }\r
-\r
-    // function argument types\r
-    for (int i = 0; i < AccessQualifierCeiling; ++i) {\r
-        AccessQualifierParams[i].caps.push_back(CapKernel);\r
-    }\r
-\r
-    ExecutionModeParams[ExecutionModeInvocations].caps.push_back(CapGeom);\r
-    ExecutionModeParams[ExecutionModeSpacingEqual].caps.push_back(CapTess);\r
-    ExecutionModeParams[ExecutionModeSpacingFractionalEven].caps.push_back(CapTess);\r
-    ExecutionModeParams[ExecutionModeSpacingFractionalOdd].caps.push_back(CapTess);\r
-    ExecutionModeParams[ExecutionModeVertexOrderCw].caps.push_back(CapTess);\r
-    ExecutionModeParams[ExecutionModeVertexOrderCcw].caps.push_back(CapTess);\r
-    ExecutionModeParams[ExecutionModePixelCenterInteger].caps.push_back(CapShader);\r
-    ExecutionModeParams[ExecutionModeOriginUpperLeft].caps.push_back(CapShader);\r
-    ExecutionModeParams[ExecutionModeEarlyFragmentTests].caps.push_back(CapShader);\r
-    ExecutionModeParams[ExecutionModePointMode].caps.push_back(CapTess);\r
-    ExecutionModeParams[ExecutionModeXfb].caps.push_back(CapShader);\r
-    ExecutionModeParams[ExecutionModeDepthReplacing].caps.push_back(CapShader);\r
-    ExecutionModeParams[ExecutionModeDepthAny].caps.push_back(CapShader);\r
-    ExecutionModeParams[ExecutionModeDepthGreater].caps.push_back(CapShader);\r
-    ExecutionModeParams[ExecutionModeDepthLess].caps.push_back(CapShader);\r
-    ExecutionModeParams[ExecutionModeDepthUnchanged].caps.push_back(CapShader);\r
-    ExecutionModeParams[ExecutionModeLocalSizeHint].caps.push_back(CapKernel);\r
-    ExecutionModeParams[ExecutionModeInputPoints].caps.push_back(CapGeom);\r
-    ExecutionModeParams[ExecutionModeInputLines].caps.push_back(CapGeom);\r
-    ExecutionModeParams[ExecutionModeInputLinesAdjacency].caps.push_back(CapGeom);\r
-    ExecutionModeParams[ExecutionModeInputTriangles].caps.push_back(CapGeom);\r
-    ExecutionModeParams[ExecutionModeInputTriangles].caps.push_back(CapTess);\r
-    ExecutionModeParams[ExecutionModeInputTrianglesAdjacency].caps.push_back(CapGeom);\r
-    ExecutionModeParams[ExecutionModeInputQuads].caps.push_back(CapTess);\r
-    ExecutionModeParams[ExecutionModeInputIsolines].caps.push_back(CapTess);\r
-    ExecutionModeParams[ExecutionModeOutputVertices].caps.push_back(CapGeom);\r
-    ExecutionModeParams[ExecutionModeOutputVertices].caps.push_back(CapTess);\r
-    ExecutionModeParams[ExecutionModeOutputPoints].caps.push_back(CapGeom);\r
-    ExecutionModeParams[ExecutionModeOutputLineStrip].caps.push_back(CapGeom);\r
-    ExecutionModeParams[ExecutionModeOutputTriangleStrip].caps.push_back(CapGeom);\r
-    ExecutionModeParams[ExecutionModeVecTypeHint].caps.push_back(CapKernel);\r
-    ExecutionModeParams[ExecutionModeContractionOff].caps.push_back(CapKernel);\r
-\r
-    DecorationParams[DecorationPrecisionLow].caps.push_back(CapShader);\r
-    DecorationParams[DecorationPrecisionMedium].caps.push_back(CapShader);\r
-    DecorationParams[DecorationPrecisionHigh].caps.push_back(CapShader);\r
-    DecorationParams[DecorationBlock].caps.push_back(CapShader);\r
-    DecorationParams[DecorationBufferBlock].caps.push_back(CapShader);\r
-    DecorationParams[DecorationRowMajor].caps.push_back(CapMatrix);\r
-    DecorationParams[DecorationColMajor].caps.push_back(CapMatrix);\r
-    DecorationParams[DecorationGLSLShared].caps.push_back(CapShader);\r
-    DecorationParams[DecorationGLSLStd140].caps.push_back(CapShader);\r
-    DecorationParams[DecorationGLSLStd430].caps.push_back(CapShader);\r
-    DecorationParams[DecorationGLSLPacked].caps.push_back(CapShader);\r
-    DecorationParams[DecorationSmooth].caps.push_back(CapShader);\r
-    DecorationParams[DecorationNoperspective].caps.push_back(CapShader);\r
-    DecorationParams[DecorationFlat].caps.push_back(CapShader);\r
-    DecorationParams[DecorationPatch].caps.push_back(CapTess);\r
-    DecorationParams[DecorationCentroid].caps.push_back(CapShader);\r
-    DecorationParams[DecorationSample].caps.push_back(CapShader);\r
-    DecorationParams[DecorationInvariant].caps.push_back(CapShader);\r
-    DecorationParams[DecorationConstant].caps.push_back(CapKernel);\r
-    DecorationParams[DecorationUniform].caps.push_back(CapShader);\r
-    DecorationParams[DecorationCPacked].caps.push_back(CapKernel);\r
-    DecorationParams[DecorationSaturatedConversion].caps.push_back(CapKernel);\r
-    DecorationParams[DecorationStream].caps.push_back(CapGeom);\r
-    DecorationParams[DecorationLocation].caps.push_back(CapShader);\r
-    DecorationParams[DecorationComponent].caps.push_back(CapShader);\r
-    DecorationParams[DecorationIndex].caps.push_back(CapShader);\r
-    DecorationParams[DecorationBinding].caps.push_back(CapShader);\r
-    DecorationParams[DecorationDescriptorSet].caps.push_back(CapShader);\r
-    DecorationParams[DecorationXfbBuffer].caps.push_back(CapShader);\r
-    DecorationParams[DecorationStride].caps.push_back(CapShader);\r
-    DecorationParams[DecorationBuiltIn].caps.push_back(CapShader);\r
-    DecorationParams[DecorationFuncParamAttr].caps.push_back(CapKernel);\r
-    DecorationParams[DecorationFPRoundingMode].caps.push_back(CapKernel);\r
-    DecorationParams[DecorationFPFastMathMode].caps.push_back(CapKernel);\r
-    DecorationParams[DecorationLinkageAttributes].caps.push_back(CapLink);\r
-    DecorationParams[DecorationSpecId].caps.push_back(CapShader);\r
-\r
-    BuiltInParams[BuiltInPosition].caps.push_back(CapShader);\r
-    BuiltInParams[BuiltInPointSize].caps.push_back(CapShader);\r
-    BuiltInParams[BuiltInClipVertex].caps.push_back(CapShader);\r
-    BuiltInParams[BuiltInClipDistance].caps.push_back(CapShader);\r
-    BuiltInParams[BuiltInCullDistance].caps.push_back(CapShader);\r
-    BuiltInParams[BuiltInVertexId].caps.push_back(CapShader);\r
-    BuiltInParams[BuiltInInstanceId].caps.push_back(CapShader);\r
-    BuiltInParams[BuiltInPrimitiveId].caps.push_back(CapGeom);\r
-    BuiltInParams[BuiltInPrimitiveId].caps.push_back(CapTess);\r
-    BuiltInParams[BuiltInInvocationId].caps.push_back(CapGeom);\r
-    BuiltInParams[BuiltInInvocationId].caps.push_back(CapTess);\r
-    BuiltInParams[BuiltInLayer].caps.push_back(CapGeom);\r
-    BuiltInParams[BuiltInViewportIndex].caps.push_back(CapGeom);\r
-    BuiltInParams[BuiltInTessLevelOuter].caps.push_back(CapTess);\r
-    BuiltInParams[BuiltInTessLevelInner].caps.push_back(CapTess);\r
-    BuiltInParams[BuiltInTessCoord].caps.push_back(CapTess);\r
-    BuiltInParams[BuiltInPatchVertices].caps.push_back(CapTess);\r
-    BuiltInParams[BuiltInFragCoord].caps.push_back(CapShader);\r
-    BuiltInParams[BuiltInPointCoord].caps.push_back(CapShader);\r
-    BuiltInParams[BuiltInFrontFacing].caps.push_back(CapShader);\r
-    BuiltInParams[BuiltInSampleId].caps.push_back(CapShader);\r
-    BuiltInParams[BuiltInSamplePosition].caps.push_back(CapShader);\r
-    BuiltInParams[BuiltInSampleMask].caps.push_back(CapShader);\r
-    BuiltInParams[BuiltInFragColor].caps.push_back(CapShader);\r
-    BuiltInParams[BuiltInFragDepth].caps.push_back(CapShader);\r
-    BuiltInParams[BuiltInHelperInvocation].caps.push_back(CapShader);\r
-    BuiltInParams[BuiltInLocalInvocationIndex].caps.push_back(CapShader);\r
-    BuiltInParams[BuiltInWorkDim].caps.push_back(CapKernel);\r
-    BuiltInParams[BuiltInGlobalSize].caps.push_back(CapKernel);\r
-    BuiltInParams[BuiltInEnqueuedWorkgroupSize].caps.push_back(CapKernel);\r
-    BuiltInParams[BuiltInGlobalOffset].caps.push_back(CapKernel);\r
-    BuiltInParams[BuiltInGlobalLinearId].caps.push_back(CapKernel);\r
-    BuiltInParams[BuiltInWorkgroupLinearId].caps.push_back(CapKernel);\r
-\r
-    BuiltInParams[BuiltInSubgroupSize].caps.push_back(CapKernel);\r
-    BuiltInParams[BuiltInSubgroupMaxSize].caps.push_back(CapKernel);\r
-    BuiltInParams[BuiltInNumSubgroups].caps.push_back(CapKernel);\r
-    BuiltInParams[BuiltInNumEnqueuedSubgroups].caps.push_back(CapKernel);\r
-    BuiltInParams[BuiltInSubgroupId].caps.push_back(CapKernel);\r
-    BuiltInParams[BuiltInSubgroupLocalInvocationId].caps.push_back(CapKernel);\r
-\r
-    DimensionalityParams[DimCube].caps.push_back(CapShader);\r
-    DimensionalityParams[DimRect].caps.push_back(CapShader);\r
-\r
-    // Group Operations\r
-    for (int i = 0; i < GroupOperationCeiling; ++i) {\r
-        GroupOperationParams[i].caps.push_back(CapKernel);\r
-    }\r
-\r
-    // Enqueue flags\r
-    for (int i = 0; i < KernelEnqueueFlagsCeiling; ++i) {\r
-        KernelEnqueueFlagsParams[i].caps.push_back(CapKernel);\r
-    }\r
-\r
-    // Profiling info\r
-    KernelProfilingInfoParams[0].caps.push_back(CapKernel);\r
-\r
-    // set name of operator, an initial set of <id> style operands, and the description\r
-\r
-    InstructionDesc[OpSource].operands.push(OperandSource, "");\r
-    InstructionDesc[OpSource].operands.push(OperandLiteralNumber, "'Version'");\r
-\r
-    InstructionDesc[OpSourceExtension].operands.push(OperandLiteralString, "'Extension'");\r
-\r
-    InstructionDesc[OpName].operands.push(OperandId, "'Target'");\r
-    InstructionDesc[OpName].operands.push(OperandLiteralString, "'Name'");\r
-\r
-    InstructionDesc[OpMemberName].operands.push(OperandId, "'Type'");\r
-    InstructionDesc[OpMemberName].operands.push(OperandLiteralNumber, "'Member'");\r
-    InstructionDesc[OpMemberName].operands.push(OperandLiteralString, "'Name'");\r
-\r
-    InstructionDesc[OpString].operands.push(OperandLiteralString, "'String'");\r
-\r
-    InstructionDesc[OpLine].operands.push(OperandId, "'Target'");\r
-    InstructionDesc[OpLine].operands.push(OperandId, "'File'");\r
-    InstructionDesc[OpLine].operands.push(OperandLiteralNumber, "'Line'");\r
-    InstructionDesc[OpLine].operands.push(OperandLiteralNumber, "'Column'");\r
-\r
-    InstructionDesc[OpExtension].operands.push(OperandLiteralString, "'Name'");\r
-\r
-    InstructionDesc[OpExtInstImport].operands.push(OperandLiteralString, "'Name'");\r
-\r
-    InstructionDesc[OpMemoryModel].operands.push(OperandAddressing, "");\r
-    InstructionDesc[OpMemoryModel].operands.push(OperandMemory, "");\r
-\r
-    InstructionDesc[OpEntryPoint].operands.push(OperandExecutionModel, "");\r
-    InstructionDesc[OpEntryPoint].operands.push(OperandId, "'Entry Point'");\r
-\r
-    InstructionDesc[OpExecutionMode].operands.push(OperandId, "'Entry Point'");\r
-    InstructionDesc[OpExecutionMode].operands.push(OperandExecutionMode, "'Mode'");\r
-    InstructionDesc[OpExecutionMode].operands.push(OperandVariableLiterals, "See <<Execution Mode,Execution Mode>>");\r
-\r
-    InstructionDesc[OpTypeInt].operands.push(OperandLiteralNumber, "'Width'");\r
-    InstructionDesc[OpTypeInt].operands.push(OperandLiteralNumber, "'Signedness'");\r
-\r
-    InstructionDesc[OpTypeFloat].operands.push(OperandLiteralNumber, "'Width'");\r
-\r
-    InstructionDesc[OpTypeVector].operands.push(OperandId, "'Component type'");\r
-    InstructionDesc[OpTypeVector].operands.push(OperandLiteralNumber, "'Component count'");\r
-\r
-    InstructionDesc[OpTypeMatrix].capabilities.push_back(CapMatrix);\r
-    InstructionDesc[OpTypeMatrix].operands.push(OperandId, "'Column type'");\r
-    InstructionDesc[OpTypeMatrix].operands.push(OperandLiteralNumber, "'Column count'");\r
-\r
-    InstructionDesc[OpTypeSampler].operands.push(OperandId, "'Sampled Type'");\r
-    InstructionDesc[OpTypeSampler].operands.push(OperandDimensionality, "");\r
-    InstructionDesc[OpTypeSampler].operands.push(OperandLiteralNumber, "'Content'");\r
-    InstructionDesc[OpTypeSampler].operands.push(OperandLiteralNumber, "'Arrayed'");\r
-    InstructionDesc[OpTypeSampler].operands.push(OperandLiteralNumber, "'Compare'");\r
-    InstructionDesc[OpTypeSampler].operands.push(OperandLiteralNumber, "'MS'");\r
-    InstructionDesc[OpTypeSampler].operands.push(OperandOptionalId, "'Qualifier'");\r
-\r
-    InstructionDesc[OpTypeArray].operands.push(OperandId, "'Element type'");\r
-    InstructionDesc[OpTypeArray].operands.push(OperandId, "'Length'");\r
-\r
-    InstructionDesc[OpTypeRuntimeArray].capabilities.push_back(CapShader);\r
-    InstructionDesc[OpTypeRuntimeArray].operands.push(OperandId, "'Element type'");\r
-\r
-    InstructionDesc[OpTypeStruct].operands.push(OperandVariableIds, "'Member 0 type', +\n'member 1 type', +\n...");\r
-\r
-    InstructionDesc[OpTypeOpaque].capabilities.push_back(CapKernel);\r
-    InstructionDesc[OpTypeOpaque].operands.push(OperandLiteralString, "The name of the opaque type.");\r
-\r
-    InstructionDesc[OpTypePointer].operands.push(OperandStorage, "");\r
-    InstructionDesc[OpTypePointer].operands.push(OperandId, "'Type'");\r
-\r
-    InstructionDesc[OpTypeEvent].capabilities.push_back(CapKernel);\r
-\r
-    InstructionDesc[OpTypeDeviceEvent].capabilities.push_back(CapKernel);\r
-\r
-    InstructionDesc[OpTypeReserveId].capabilities.push_back(CapKernel);\r
-\r
-    InstructionDesc[OpTypeQueue].capabilities.push_back(CapKernel);\r
-\r
-    InstructionDesc[OpTypePipe].operands.push(OperandId, "'Type'");\r
-    InstructionDesc[OpTypePipe].operands.push(OperandAccessQualifier, "'Qualifier'");\r
-    InstructionDesc[OpTypePipe].capabilities.push_back(CapKernel);\r
-\r
-    InstructionDesc[OpTypeFunction].operands.push(OperandId, "'Return Type'");\r
-    InstructionDesc[OpTypeFunction].operands.push(OperandVariableIds, "'Parameter 0 Type', +\n'Parameter 1 Type', +\n...");\r
-\r
-    InstructionDesc[OpConstant].operands.push(OperandVariableLiterals, "'Value'");\r
-\r
-    InstructionDesc[OpConstantComposite].operands.push(OperandVariableIds, "'Constituents'");\r
-\r
-    InstructionDesc[OpConstantNullPointer].capabilities.push_back(CapAddr);\r
-\r
-    InstructionDesc[OpConstantNullObject].capabilities.push_back(CapKernel);\r
-\r
-    InstructionDesc[OpConstantSampler].capabilities.push_back(CapKernel);\r
-    InstructionDesc[OpConstantSampler].operands.push(OperandLiteralNumber, "'Mode'");\r
-    InstructionDesc[OpConstantSampler].operands.push(OperandLiteralNumber, "'Param'");\r
-    InstructionDesc[OpConstantSampler].operands.push(OperandLiteralNumber, "'Filter'");\r
-\r
-    InstructionDesc[OpSpecConstantTrue].capabilities.push_back(CapShader);\r
-\r
-    InstructionDesc[OpSpecConstantFalse].capabilities.push_back(CapShader);\r
-\r
-    InstructionDesc[OpSpecConstant].operands.push(OperandVariableLiterals, "'Value'");\r
-    InstructionDesc[OpSpecConstant].capabilities.push_back(CapShader);\r
-\r
-    InstructionDesc[OpSpecConstantComposite].operands.push(OperandVariableIds, "'Constituents'");\r
-    InstructionDesc[OpSpecConstantComposite].capabilities.push_back(CapShader);\r
-\r
-    InstructionDesc[OpVariable].operands.push(OperandStorage, "");\r
-    InstructionDesc[OpVariable].operands.push(OperandOptionalId, "'Initializer'");\r
-\r
-    InstructionDesc[OpVariableArray].operands.push(OperandStorage, "");\r
-    InstructionDesc[OpVariableArray].operands.push(OperandId, "'N'");\r
-    InstructionDesc[OpVariableArray].capabilities.push_back(CapAddr);\r
-\r
-    InstructionDesc[OpFunction].operands.push(OperandFunction, "");\r
-    InstructionDesc[OpFunction].operands.push(OperandId, "'Function Type'");\r
-\r
-    InstructionDesc[OpFunctionCall].operands.push(OperandId, "'Function'");\r
-    InstructionDesc[OpFunctionCall].operands.push(OperandVariableIds, "'Argument 0', +\n'Argument 1', +\n...");\r
-\r
-    InstructionDesc[OpExtInst].operands.push(OperandId, "'Set'");\r
-    InstructionDesc[OpExtInst].operands.push(OperandLiteralNumber, "'Instruction'");\r
-    InstructionDesc[OpExtInst].operands.push(OperandVariableIds, "'Operand 1', +\n'Operand 2', +\n...");\r
-\r
-    InstructionDesc[OpLoad].operands.push(OperandId, "'Pointer'");\r
-    InstructionDesc[OpLoad].operands.push(OperandVariableLiterals, "'Memory Access'");\r
-\r
-    InstructionDesc[OpStore].operands.push(OperandId, "'Pointer'");\r
-    InstructionDesc[OpStore].operands.push(OperandId, "'Object'");\r
-    InstructionDesc[OpStore].operands.push(OperandVariableLiterals, "'Memory Access'");\r
-\r
-    InstructionDesc[OpPhi].operands.push(OperandVariableIds, "");\r
-\r
-    InstructionDesc[OpDecorate].operands.push(OperandId, "'Target'");\r
-    InstructionDesc[OpDecorate].operands.push(OperandDecoration, "");\r
-    InstructionDesc[OpDecorate].operands.push(OperandVariableLiterals, "See <<Decoration,'Decoration'>>.");\r
-\r
-    InstructionDesc[OpMemberDecorate].operands.push(OperandId, "'Structure type'");\r
-    InstructionDesc[OpMemberDecorate].operands.push(OperandLiteralNumber, "'Member'");\r
-    InstructionDesc[OpMemberDecorate].operands.push(OperandDecoration, "");\r
-    InstructionDesc[OpMemberDecorate].operands.push(OperandVariableLiterals, "See <<Decoration,'Decoration'>>.");\r
-\r
-    InstructionDesc[OpGroupDecorate].operands.push(OperandId, "'Decoration group'");\r
-    InstructionDesc[OpGroupDecorate].operands.push(OperandVariableIds, "'Target', 'Target', ...");\r
-\r
-    InstructionDesc[OpGroupMemberDecorate].operands.push(OperandId, "'Decoration group'");\r
-    InstructionDesc[OpGroupMemberDecorate].operands.push(OperandVariableIds, "'Target', 'Target', ...");\r
-\r
-    InstructionDesc[OpVectorExtractDynamic].operands.push(OperandId, "'Vector'");\r
-    InstructionDesc[OpVectorExtractDynamic].operands.push(OperandId, "'Index'");\r
-\r
-    InstructionDesc[OpVectorInsertDynamic].operands.push(OperandId, "'Vector'");\r
-    InstructionDesc[OpVectorInsertDynamic].operands.push(OperandId, "'Component'");\r
-    InstructionDesc[OpVectorInsertDynamic].operands.push(OperandId, "'Index'");\r
-\r
-    InstructionDesc[OpVectorShuffle].operands.push(OperandId, "'Vector 1'");\r
-    InstructionDesc[OpVectorShuffle].operands.push(OperandId, "'Vector 2'");\r
-    InstructionDesc[OpVectorShuffle].operands.push(OperandVariableLiterals, "'Components'");\r
-\r
-    InstructionDesc[OpCompositeConstruct].operands.push(OperandVariableIds, "'Constituents'");\r
-\r
-    InstructionDesc[OpCompositeExtract].operands.push(OperandId, "'Composite'");\r
-    InstructionDesc[OpCompositeExtract].operands.push(OperandVariableLiterals, "'Indexes'");\r
-\r
-    InstructionDesc[OpCompositeInsert].operands.push(OperandId, "'Object'");\r
-    InstructionDesc[OpCompositeInsert].operands.push(OperandId, "'Composite'");\r
-    InstructionDesc[OpCompositeInsert].operands.push(OperandVariableLiterals, "'Indexes'");\r
-\r
-    InstructionDesc[OpCopyObject].operands.push(OperandId, "'Operand'");\r
-\r
-    InstructionDesc[OpCopyMemory].operands.push(OperandId, "'Target'");\r
-    InstructionDesc[OpCopyMemory].operands.push(OperandId, "'Source'");\r
-    InstructionDesc[OpCopyMemory].operands.push(OperandVariableLiterals, "'Memory Access'");\r
-\r
-    InstructionDesc[OpCopyMemorySized].operands.push(OperandId, "'Target'");\r
-    InstructionDesc[OpCopyMemorySized].operands.push(OperandId, "'Source'");\r
-    InstructionDesc[OpCopyMemorySized].operands.push(OperandId, "'Size'");\r
-    InstructionDesc[OpCopyMemorySized].operands.push(OperandVariableLiterals, "'Memory Access'");\r
-\r
-    InstructionDesc[OpCopyMemorySized].capabilities.push_back(CapAddr);\r
-\r
-    InstructionDesc[OpSampler].operands.push(OperandId, "'Sampler'");\r
-    InstructionDesc[OpSampler].operands.push(OperandId, "'Filter'");\r
-\r
-    InstructionDesc[OpTextureSample].operands.push(OperandId, "'Sampler'");\r
-    InstructionDesc[OpTextureSample].operands.push(OperandId, "'Coordinate'");\r
-    InstructionDesc[OpTextureSample].operands.push(OperandOptionalId, "['Bias']");\r
-    InstructionDesc[OpTextureSample].capabilities.push_back(CapShader);\r
-\r
-    InstructionDesc[OpTextureSampleDref].operands.push(OperandId, "'Sampler'");\r
-    InstructionDesc[OpTextureSampleDref].operands.push(OperandId, "'Coordinate'");\r
-    InstructionDesc[OpTextureSampleDref].operands.push(OperandId, "'D~ref~'");\r
-    InstructionDesc[OpTextureSampleDref].capabilities.push_back(CapShader);\r
-\r
-    InstructionDesc[OpTextureSampleLod].operands.push(OperandId, "'Sampler'");\r
-    InstructionDesc[OpTextureSampleLod].operands.push(OperandId, "'Coordinate'");\r
-    InstructionDesc[OpTextureSampleLod].operands.push(OperandId, "'Level of Detail'");\r
-    InstructionDesc[OpTextureSampleLod].capabilities.push_back(CapShader);\r
-\r
-    InstructionDesc[OpTextureSampleProj].operands.push(OperandId, "'Sampler'");\r
-    InstructionDesc[OpTextureSampleProj].operands.push(OperandId, "'Coordinate'");\r
-    InstructionDesc[OpTextureSampleProj].operands.push(OperandOptionalId, "['Bias']");\r
-    InstructionDesc[OpTextureSampleProj].capabilities.push_back(CapShader);\r
-\r
-    InstructionDesc[OpTextureSampleGrad].operands.push(OperandId, "'Sampler'");\r
-    InstructionDesc[OpTextureSampleGrad].operands.push(OperandId, "'Coordinate'");\r
-    InstructionDesc[OpTextureSampleGrad].operands.push(OperandId, "'dx'");\r
-    InstructionDesc[OpTextureSampleGrad].operands.push(OperandId, "'dy'");\r
-    InstructionDesc[OpTextureSampleGrad].capabilities.push_back(CapShader);\r
-\r
-    InstructionDesc[OpTextureSampleOffset].operands.push(OperandId, "'Sampler'");\r
-    InstructionDesc[OpTextureSampleOffset].operands.push(OperandId, "'Coordinate'");\r
-    InstructionDesc[OpTextureSampleOffset].operands.push(OperandId, "'Offset'");\r
-    InstructionDesc[OpTextureSampleOffset].operands.push(OperandOptionalId, "['Bias']");\r
-    InstructionDesc[OpTextureSampleOffset].capabilities.push_back(CapShader);\r
-\r
-    InstructionDesc[OpTextureSampleProjLod].operands.push(OperandId, "'Sampler'");\r
-    InstructionDesc[OpTextureSampleProjLod].operands.push(OperandId, "'Coordinate'");\r
-    InstructionDesc[OpTextureSampleProjLod].operands.push(OperandId, "'Level of Detail'");\r
-    InstructionDesc[OpTextureSampleProjLod].capabilities.push_back(CapShader);\r
-\r
-    InstructionDesc[OpTextureSampleProjGrad].operands.push(OperandId, "'Sampler'");\r
-    InstructionDesc[OpTextureSampleProjGrad].operands.push(OperandId, "'Coordinate'");\r
-    InstructionDesc[OpTextureSampleProjGrad].operands.push(OperandId, "'dx'");\r
-    InstructionDesc[OpTextureSampleProjGrad].operands.push(OperandId, "'dy'");\r
-    InstructionDesc[OpTextureSampleProjGrad].capabilities.push_back(CapShader);\r
-\r
-    InstructionDesc[OpTextureSampleLodOffset].operands.push(OperandId, "'Sampler'");\r
-    InstructionDesc[OpTextureSampleLodOffset].operands.push(OperandId, "'Coordinate'");\r
-    InstructionDesc[OpTextureSampleLodOffset].operands.push(OperandId, "'Level of Detail'");\r
-    InstructionDesc[OpTextureSampleLodOffset].operands.push(OperandId, "'Offset'");\r
-    InstructionDesc[OpTextureSampleLodOffset].capabilities.push_back(CapShader);\r
-\r
-    InstructionDesc[OpTextureSampleProjOffset].operands.push(OperandId, "'Sampler'");\r
-    InstructionDesc[OpTextureSampleProjOffset].operands.push(OperandId, "'Coordinate'");\r
-    InstructionDesc[OpTextureSampleProjOffset].operands.push(OperandId, "'Offset'");\r
-    InstructionDesc[OpTextureSampleProjOffset].operands.push(OperandOptionalId, "['Bias']");\r
-    InstructionDesc[OpTextureSampleProjOffset].capabilities.push_back(CapShader);\r
-\r
-    InstructionDesc[OpTextureSampleGradOffset].operands.push(OperandId, "'Sampler'");\r
-    InstructionDesc[OpTextureSampleGradOffset].operands.push(OperandId, "'Coordinate'");\r
-    InstructionDesc[OpTextureSampleGradOffset].operands.push(OperandId, "'dx'");\r
-    InstructionDesc[OpTextureSampleGradOffset].operands.push(OperandId, "'dy'");\r
-    InstructionDesc[OpTextureSampleGradOffset].operands.push(OperandId, "'Offset'");\r
-    InstructionDesc[OpTextureSampleGradOffset].capabilities.push_back(CapShader);\r
-\r
-    InstructionDesc[OpTextureSampleProjLodOffset].operands.push(OperandId, "'Sampler'");\r
-    InstructionDesc[OpTextureSampleProjLodOffset].operands.push(OperandId, "'Coordinate'");\r
-    InstructionDesc[OpTextureSampleProjLodOffset].operands.push(OperandId, "'Level of Detail'");\r
-    InstructionDesc[OpTextureSampleProjLodOffset].operands.push(OperandId, "'Offset'");\r
-    InstructionDesc[OpTextureSampleProjLodOffset].capabilities.push_back(CapShader);\r
-\r
-    InstructionDesc[OpTextureSampleProjGradOffset].operands.push(OperandId, "'Sampler'");\r
-    InstructionDesc[OpTextureSampleProjGradOffset].operands.push(OperandId, "'Coordinate'");\r
-    InstructionDesc[OpTextureSampleProjGradOffset].operands.push(OperandId, "'dx'");\r
-    InstructionDesc[OpTextureSampleProjGradOffset].operands.push(OperandId, "'dy'");\r
-    InstructionDesc[OpTextureSampleProjGradOffset].operands.push(OperandId, "'Offset'");\r
-    InstructionDesc[OpTextureSampleProjGradOffset].capabilities.push_back(CapShader);\r
-\r
-    InstructionDesc[OpTextureFetchTexelLod].operands.push(OperandId, "'Sampler'");\r
-    InstructionDesc[OpTextureFetchTexelLod].operands.push(OperandId, "'Coordinate'");\r
-    InstructionDesc[OpTextureFetchTexelLod].operands.push(OperandId, "'Level of Detail'");\r
-    InstructionDesc[OpTextureFetchTexelLod].capabilities.push_back(CapShader);\r
-\r
-    InstructionDesc[OpTextureFetchTexelOffset].operands.push(OperandId, "'Sampler'");\r
-    InstructionDesc[OpTextureFetchTexelOffset].operands.push(OperandId, "'Coordinate'");\r
-    InstructionDesc[OpTextureFetchTexelOffset].operands.push(OperandId, "'Offset'");\r
-    InstructionDesc[OpTextureFetchTexelOffset].capabilities.push_back(CapShader);\r
-\r
-    InstructionDesc[OpTextureFetchSample].operands.push(OperandId, "'Sampler'");\r
-    InstructionDesc[OpTextureFetchSample].operands.push(OperandId, "'Coordinate'");\r
-    InstructionDesc[OpTextureFetchSample].operands.push(OperandId, "'Sample'");\r
-    InstructionDesc[OpTextureFetchSample].capabilities.push_back(CapShader);\r
-\r
-    InstructionDesc[OpTextureFetchTexel].operands.push(OperandId, "'Sampler'");\r
-    InstructionDesc[OpTextureFetchTexel].operands.push(OperandId, "'Element'");\r
-    InstructionDesc[OpTextureFetchTexel].capabilities.push_back(CapShader);\r
-\r
-    InstructionDesc[OpTextureGather].operands.push(OperandId, "'Sampler'");\r
-    InstructionDesc[OpTextureGather].operands.push(OperandId, "'Coordinate'");\r
-    InstructionDesc[OpTextureGather].operands.push(OperandId, "'Component'");\r
-    InstructionDesc[OpTextureGather].capabilities.push_back(CapShader);\r
-\r
-    InstructionDesc[OpTextureGatherOffset].operands.push(OperandId, "'Sampler'");\r
-    InstructionDesc[OpTextureGatherOffset].operands.push(OperandId, "'Coordinate'");\r
-    InstructionDesc[OpTextureGatherOffset].operands.push(OperandId, "'Component'");\r
-    InstructionDesc[OpTextureGatherOffset].operands.push(OperandId, "'Offset'");\r
-    InstructionDesc[OpTextureGatherOffset].capabilities.push_back(CapShader);\r
-\r
-    InstructionDesc[OpTextureGatherOffsets].operands.push(OperandId, "'Sampler'");\r
-    InstructionDesc[OpTextureGatherOffsets].operands.push(OperandId, "'Coordinate'");\r
-    InstructionDesc[OpTextureGatherOffsets].operands.push(OperandId, "'Component'");\r
-    InstructionDesc[OpTextureGatherOffsets].operands.push(OperandId, "'Offsets'");\r
-    InstructionDesc[OpTextureGatherOffsets].capabilities.push_back(CapShader);\r
-\r
-    InstructionDesc[OpTextureQuerySizeLod].operands.push(OperandId, "'Sampler'");\r
-    InstructionDesc[OpTextureQuerySizeLod].operands.push(OperandId, "'Level of Detail'");\r
-    InstructionDesc[OpTextureQuerySizeLod].capabilities.push_back(CapShader);\r
-\r
-    InstructionDesc[OpTextureQuerySize].operands.push(OperandId, "'Sampler'");\r
-    InstructionDesc[OpTextureQuerySize].capabilities.push_back(CapShader);\r
-\r
-    InstructionDesc[OpTextureQueryLod].operands.push(OperandId, "'Sampler'");\r
-    InstructionDesc[OpTextureQueryLod].operands.push(OperandId, "'Coordinate'");\r
-    InstructionDesc[OpTextureQueryLod].capabilities.push_back(CapShader);\r
-\r
-    InstructionDesc[OpTextureQueryLevels].operands.push(OperandId, "'Sampler'");\r
-    InstructionDesc[OpTextureQueryLevels].capabilities.push_back(CapShader);\r
-\r
-    InstructionDesc[OpTextureQuerySamples].operands.push(OperandId, "'Sampler'");\r
-    InstructionDesc[OpTextureQuerySamples].capabilities.push_back(CapShader);\r
-\r
-    InstructionDesc[OpAccessChain].operands.push(OperandId, "'Base'");\r
-    InstructionDesc[OpAccessChain].operands.push(OperandVariableIds, "'Indexes'");\r
-\r
-    InstructionDesc[OpInBoundsAccessChain].operands.push(OperandId, "'Base'");\r
-    InstructionDesc[OpInBoundsAccessChain].operands.push(OperandVariableIds, "'Indexes'");\r
-\r
-    InstructionDesc[OpSNegate].operands.push(OperandId, "'Operand'");\r
-\r
-    InstructionDesc[OpFNegate].operands.push(OperandId, "'Operand'");\r
-\r
-    InstructionDesc[OpNot].operands.push(OperandId, "'Operand'");\r
-\r
-    InstructionDesc[OpAny].operands.push(OperandId, "'Vector'");\r
-\r
-    InstructionDesc[OpAll].operands.push(OperandId, "'Vector'");\r
-\r
-    InstructionDesc[OpConvertFToU].operands.push(OperandId, "'Float Value'");\r
-\r
-    InstructionDesc[OpConvertFToS].operands.push(OperandId, "'Float Value'");\r
-\r
-    InstructionDesc[OpConvertSToF].operands.push(OperandId, "'Signed Value'");\r
-\r
-    InstructionDesc[OpConvertUToF].operands.push(OperandId, "'Unsigned value'");\r
-\r
-    InstructionDesc[OpUConvert].operands.push(OperandId, "'Unsigned value'");\r
-\r
-    InstructionDesc[OpSConvert].operands.push(OperandId, "'Signed Value'");\r
-\r
-    InstructionDesc[OpFConvert].operands.push(OperandId, "'Float Value'");\r
-\r
-    InstructionDesc[OpSatConvertSToU].operands.push(OperandId, "'Signed Value'");\r
-    InstructionDesc[OpSatConvertSToU].capabilities.push_back(CapKernel);\r
-\r
-    InstructionDesc[OpSatConvertUToS].operands.push(OperandId, "'Unsigned Value'");\r
-    InstructionDesc[OpSatConvertUToS].capabilities.push_back(CapKernel);\r
-\r
-    InstructionDesc[OpConvertPtrToU].operands.push(OperandId, "'Pointer'");\r
-    InstructionDesc[OpConvertPtrToU].capabilities.push_back(CapAddr);\r
-\r
-    InstructionDesc[OpConvertUToPtr].operands.push(OperandId, "'Integer value'");\r
-    InstructionDesc[OpConvertUToPtr].capabilities.push_back(CapAddr);\r
-\r
-    InstructionDesc[OpPtrCastToGeneric].operands.push(OperandId, "'Source pointer'");\r
-    InstructionDesc[OpPtrCastToGeneric].capabilities.push_back(CapKernel);\r
-\r
-\r
-    InstructionDesc[OpGenericCastToPtr].operands.push(OperandId, "'Source pointer'");\r
-    InstructionDesc[OpGenericCastToPtr].capabilities.push_back(CapKernel);\r
-\r
-    InstructionDesc[OpGenericCastToPtrExplicit].operands.push(OperandId, "'Source pointer'");\r
-    InstructionDesc[OpGenericCastToPtrExplicit].operands.push(OperandStorage, "'storage'");\r
-    InstructionDesc[OpGenericCastToPtrExplicit].capabilities.push_back(CapKernel);\r
-\r
-    InstructionDesc[OpGenericPtrMemSemantics].operands.push(OperandId, "'ptr'");\r
-    InstructionDesc[OpGenericPtrMemSemantics].capabilities.push_back(CapKernel);\r
-\r
-    InstructionDesc[OpBitcast].operands.push(OperandId, "'Operand'");\r
-\r
-    InstructionDesc[OpTranspose].capabilities.push_back(CapMatrix);\r
-    InstructionDesc[OpTranspose].operands.push(OperandId, "'Matrix'");\r
-\r
-    InstructionDesc[OpIsNan].operands.push(OperandId, "'x'");\r
-\r
-    InstructionDesc[OpIsInf].operands.push(OperandId, "'x'");\r
-\r
-    InstructionDesc[OpIsFinite].capabilities.push_back(CapKernel);\r
-    InstructionDesc[OpIsFinite].operands.push(OperandId, "'x'");\r
-\r
-    InstructionDesc[OpIsNormal].capabilities.push_back(CapKernel);\r
-    InstructionDesc[OpIsNormal].operands.push(OperandId, "'x'");\r
-\r
-    InstructionDesc[OpSignBitSet].capabilities.push_back(CapKernel);\r
-    InstructionDesc[OpSignBitSet].operands.push(OperandId, "'x'");\r
-\r
-    InstructionDesc[OpLessOrGreater].capabilities.push_back(CapKernel);\r
-    InstructionDesc[OpLessOrGreater].operands.push(OperandId, "'x'");\r
-    InstructionDesc[OpLessOrGreater].operands.push(OperandId, "'y'");\r
-\r
-    InstructionDesc[OpOrdered].capabilities.push_back(CapKernel);\r
-    InstructionDesc[OpOrdered].operands.push(OperandId, "'x'");\r
-    InstructionDesc[OpOrdered].operands.push(OperandId, "'y'");\r
-\r
-    InstructionDesc[OpUnordered].capabilities.push_back(CapKernel);\r
-    InstructionDesc[OpUnordered].operands.push(OperandId, "'x'");\r
-    InstructionDesc[OpUnordered].operands.push(OperandId, "'y'");\r
-\r
-    InstructionDesc[OpArrayLength].operands.push(OperandId, "'Structure'");\r
-    InstructionDesc[OpArrayLength].operands.push(OperandLiteralNumber, "'Array member'");\r
-    InstructionDesc[OpArrayLength].capabilities.push_back(CapShader);\r
-\r
-    InstructionDesc[OpIAdd].operands.push(OperandId, "'Operand 1'");\r
-    InstructionDesc[OpIAdd].operands.push(OperandId, "'Operand 2'");\r
-\r
-    InstructionDesc[OpFAdd].operands.push(OperandId, "'Operand 1'");\r
-    InstructionDesc[OpFAdd].operands.push(OperandId, "'Operand 2'");\r
-\r
-    InstructionDesc[OpISub].operands.push(OperandId, "'Operand 1'");\r
-    InstructionDesc[OpISub].operands.push(OperandId, "'Operand 2'");\r
-\r
-    InstructionDesc[OpFSub].operands.push(OperandId, "'Operand 1'");\r
-    InstructionDesc[OpFSub].operands.push(OperandId, "'Operand 2'");\r
-\r
-    InstructionDesc[OpIMul].operands.push(OperandId, "'Operand 1'");\r
-    InstructionDesc[OpIMul].operands.push(OperandId, "'Operand 2'");\r
-\r
-    InstructionDesc[OpFMul].operands.push(OperandId, "'Operand 1'");\r
-    InstructionDesc[OpFMul].operands.push(OperandId, "'Operand 2'");\r
-\r
-    InstructionDesc[OpUDiv].operands.push(OperandId, "'Operand 1'");\r
-    InstructionDesc[OpUDiv].operands.push(OperandId, "'Operand 2'");\r
-\r
-    InstructionDesc[OpSDiv].operands.push(OperandId, "'Operand 1'");\r
-    InstructionDesc[OpSDiv].operands.push(OperandId, "'Operand 2'");\r
-\r
-    InstructionDesc[OpFDiv].operands.push(OperandId, "'Operand 1'");\r
-    InstructionDesc[OpFDiv].operands.push(OperandId, "'Operand 2'");\r
-\r
-    InstructionDesc[OpUMod].operands.push(OperandId, "'Operand 1'");\r
-    InstructionDesc[OpUMod].operands.push(OperandId, "'Operand 2'");\r
-\r
-    InstructionDesc[OpSRem].operands.push(OperandId, "'Operand 1'");\r
-    InstructionDesc[OpSRem].operands.push(OperandId, "'Operand 2'");\r
-\r
-    InstructionDesc[OpSMod].operands.push(OperandId, "'Operand 1'");\r
-    InstructionDesc[OpSMod].operands.push(OperandId, "'Operand 2'");\r
-\r
-    InstructionDesc[OpFRem].operands.push(OperandId, "'Operand 1'");\r
-    InstructionDesc[OpFRem].operands.push(OperandId, "'Operand 2'");\r
-\r
-    InstructionDesc[OpFMod].operands.push(OperandId, "'Operand 1'");\r
-    InstructionDesc[OpFMod].operands.push(OperandId, "'Operand 2'");\r
-\r
-    InstructionDesc[OpVectorTimesScalar].operands.push(OperandId, "'Vector'");\r
-    InstructionDesc[OpVectorTimesScalar].operands.push(OperandId, "'Scalar'");\r
-\r
-    InstructionDesc[OpMatrixTimesScalar].capabilities.push_back(CapMatrix);\r
-    InstructionDesc[OpMatrixTimesScalar].operands.push(OperandId, "'Matrix'");\r
-    InstructionDesc[OpMatrixTimesScalar].operands.push(OperandId, "'Scalar'");\r
-\r
-    InstructionDesc[OpVectorTimesMatrix].capabilities.push_back(CapMatrix);\r
-    InstructionDesc[OpVectorTimesMatrix].operands.push(OperandId, "'Vector'");\r
-    InstructionDesc[OpVectorTimesMatrix].operands.push(OperandId, "'Matrix'");\r
-\r
-    InstructionDesc[OpMatrixTimesVector].capabilities.push_back(CapMatrix);\r
-    InstructionDesc[OpMatrixTimesVector].operands.push(OperandId, "'Matrix'");\r
-    InstructionDesc[OpMatrixTimesVector].operands.push(OperandId, "'Vector'");\r
-\r
-    InstructionDesc[OpMatrixTimesMatrix].capabilities.push_back(CapMatrix);\r
-    InstructionDesc[OpMatrixTimesMatrix].operands.push(OperandId, "'LeftMatrix'");\r
-    InstructionDesc[OpMatrixTimesMatrix].operands.push(OperandId, "'RightMatrix'");\r
-\r
-    InstructionDesc[OpOuterProduct].capabilities.push_back(CapMatrix);\r
-    InstructionDesc[OpOuterProduct].operands.push(OperandId, "'Vector 1'");\r
-    InstructionDesc[OpOuterProduct].operands.push(OperandId, "'Vector 2'");\r
-\r
-    InstructionDesc[OpDot].operands.push(OperandId, "'Vector 1'");\r
-    InstructionDesc[OpDot].operands.push(OperandId, "'Vector 2'");\r
-\r
-    InstructionDesc[OpShiftRightLogical].operands.push(OperandId, "'Operand 1'");\r
-    InstructionDesc[OpShiftRightLogical].operands.push(OperandId, "'Operand 2'");\r
-\r
-    InstructionDesc[OpShiftRightArithmetic].operands.push(OperandId, "'Operand 1'");\r
-    InstructionDesc[OpShiftRightArithmetic].operands.push(OperandId, "'Operand 2'");\r
-\r
-    InstructionDesc[OpShiftLeftLogical].operands.push(OperandId, "'Operand 1'");\r
-    InstructionDesc[OpShiftLeftLogical].operands.push(OperandId, "'Operand 2'");\r
-\r
-    InstructionDesc[OpLogicalOr].operands.push(OperandId, "'Operand 1'");\r
-    InstructionDesc[OpLogicalOr].operands.push(OperandId, "'Operand 2'");\r
-\r
-    InstructionDesc[OpLogicalXor].operands.push(OperandId, "'Operand 1'");\r
-    InstructionDesc[OpLogicalXor].operands.push(OperandId, "'Operand 2'");\r
-\r
-    InstructionDesc[OpLogicalAnd].operands.push(OperandId, "'Operand 1'");\r
-    InstructionDesc[OpLogicalAnd].operands.push(OperandId, "'Operand 2'");\r
-\r
-    InstructionDesc[OpBitwiseOr].operands.push(OperandId, "'Operand 1'");\r
-    InstructionDesc[OpBitwiseOr].operands.push(OperandId, "'Operand 2'");\r
-\r
-    InstructionDesc[OpBitwiseXor].operands.push(OperandId, "'Operand 1'");\r
-    InstructionDesc[OpBitwiseXor].operands.push(OperandId, "'Operand 2'");\r
-\r
-    InstructionDesc[OpBitwiseAnd].operands.push(OperandId, "'Operand 1'");\r
-    InstructionDesc[OpBitwiseAnd].operands.push(OperandId, "'Operand 2'");\r
-\r
-    InstructionDesc[OpSelect].operands.push(OperandId, "'Condition'");\r
-    InstructionDesc[OpSelect].operands.push(OperandId, "'Object 1'");\r
-    InstructionDesc[OpSelect].operands.push(OperandId, "'Object 2'");\r
-\r
-    InstructionDesc[OpIEqual].operands.push(OperandId, "'Operand 1'");\r
-    InstructionDesc[OpIEqual].operands.push(OperandId, "'Operand 2'");\r
-\r
-    InstructionDesc[OpFOrdEqual].operands.push(OperandId, "'Operand 1'");\r
-    InstructionDesc[OpFOrdEqual].operands.push(OperandId, "'Operand 2'");\r
-\r
-    InstructionDesc[OpFUnordEqual].operands.push(OperandId, "'Operand 1'");\r
-    InstructionDesc[OpFUnordEqual].operands.push(OperandId, "'Operand 2'");\r
-\r
-    InstructionDesc[OpINotEqual].operands.push(OperandId, "'Operand 1'");\r
-    InstructionDesc[OpINotEqual].operands.push(OperandId, "'Operand 2'");\r
-\r
-    InstructionDesc[OpFOrdNotEqual].operands.push(OperandId, "'Operand 1'");\r
-    InstructionDesc[OpFOrdNotEqual].operands.push(OperandId, "'Operand 2'");\r
-\r
-    InstructionDesc[OpFUnordNotEqual].operands.push(OperandId, "'Operand 1'");\r
-    InstructionDesc[OpFUnordNotEqual].operands.push(OperandId, "'Operand 2'");\r
-\r
-    InstructionDesc[OpULessThan].operands.push(OperandId, "'Operand 1'");\r
-    InstructionDesc[OpULessThan].operands.push(OperandId, "'Operand 2'");\r
-\r
-    InstructionDesc[OpSLessThan].operands.push(OperandId, "'Operand 1'");\r
-    InstructionDesc[OpSLessThan].operands.push(OperandId, "'Operand 2'");\r
-\r
-    InstructionDesc[OpFOrdLessThan].operands.push(OperandId, "'Operand 1'");\r
-    InstructionDesc[OpFOrdLessThan].operands.push(OperandId, "'Operand 2'");\r
-\r
-    InstructionDesc[OpFUnordLessThan].operands.push(OperandId, "'Operand 1'");\r
-    InstructionDesc[OpFUnordLessThan].operands.push(OperandId, "'Operand 2'");\r
-\r
-    InstructionDesc[OpUGreaterThan].operands.push(OperandId, "'Operand 1'");\r
-    InstructionDesc[OpUGreaterThan].operands.push(OperandId, "'Operand 2'");\r
-\r
-    InstructionDesc[OpSGreaterThan].operands.push(OperandId, "'Operand 1'");\r
-    InstructionDesc[OpSGreaterThan].operands.push(OperandId, "'Operand 2'");\r
-\r
-    InstructionDesc[OpFOrdGreaterThan].operands.push(OperandId, "'Operand 1'");\r
-    InstructionDesc[OpFOrdGreaterThan].operands.push(OperandId, "'Operand 2'");\r
-\r
-    InstructionDesc[OpFUnordGreaterThan].operands.push(OperandId, "'Operand 1'");\r
-    InstructionDesc[OpFUnordGreaterThan].operands.push(OperandId, "'Operand 2'");\r
-\r
-    InstructionDesc[OpULessThanEqual].operands.push(OperandId, "'Operand 1'");\r
-    InstructionDesc[OpULessThanEqual].operands.push(OperandId, "'Operand 2'");\r
-\r
-    InstructionDesc[OpSLessThanEqual].operands.push(OperandId, "'Operand 1'");\r
-    InstructionDesc[OpSLessThanEqual].operands.push(OperandId, "'Operand 2'");\r
-\r
-    InstructionDesc[OpFOrdLessThanEqual].operands.push(OperandId, "'Operand 1'");\r
-    InstructionDesc[OpFOrdLessThanEqual].operands.push(OperandId, "'Operand 2'");\r
-\r
-    InstructionDesc[OpFUnordLessThanEqual].operands.push(OperandId, "'Operand 1'");\r
-    InstructionDesc[OpFUnordLessThanEqual].operands.push(OperandId, "'Operand 2'");\r
-\r
-    InstructionDesc[OpUGreaterThanEqual].operands.push(OperandId, "'Operand 1'");\r
-    InstructionDesc[OpUGreaterThanEqual].operands.push(OperandId, "'Operand 2'");\r
-\r
-    InstructionDesc[OpSGreaterThanEqual].operands.push(OperandId, "'Operand 1'");\r
-    InstructionDesc[OpSGreaterThanEqual].operands.push(OperandId, "'Operand 2'");\r
-\r
-    InstructionDesc[OpFOrdGreaterThanEqual].operands.push(OperandId, "'Operand 1'");\r
-    InstructionDesc[OpFOrdGreaterThanEqual].operands.push(OperandId, "'Operand 2'");\r
-\r
-    InstructionDesc[OpFUnordGreaterThanEqual].operands.push(OperandId, "'Operand 1'");\r
-    InstructionDesc[OpFUnordGreaterThanEqual].operands.push(OperandId, "'Operand 2'");\r
-\r
-    InstructionDesc[OpDPdx].capabilities.push_back(CapShader);\r
-    InstructionDesc[OpDPdx].operands.push(OperandId, "'P'");\r
-\r
-    InstructionDesc[OpDPdy].capabilities.push_back(CapShader);\r
-    InstructionDesc[OpDPdy].operands.push(OperandId, "'P'");\r
-\r
-    InstructionDesc[OpFwidth].capabilities.push_back(CapShader);\r
-    InstructionDesc[OpFwidth].operands.push(OperandId, "'P'");\r
-\r
-    InstructionDesc[OpDPdxFine].capabilities.push_back(CapShader);\r
-    InstructionDesc[OpDPdxFine].operands.push(OperandId, "'P'");\r
-\r
-    InstructionDesc[OpDPdyFine].capabilities.push_back(CapShader);\r
-    InstructionDesc[OpDPdyFine].operands.push(OperandId, "'P'");\r
-\r
-    InstructionDesc[OpFwidthFine].capabilities.push_back(CapShader);\r
-    InstructionDesc[OpFwidthFine].operands.push(OperandId, "'P'");\r
-\r
-    InstructionDesc[OpDPdxCoarse].capabilities.push_back(CapShader);\r
-    InstructionDesc[OpDPdxCoarse].operands.push(OperandId, "'P'");\r
-\r
-    InstructionDesc[OpDPdyCoarse].capabilities.push_back(CapShader);\r
-    InstructionDesc[OpDPdyCoarse].operands.push(OperandId, "'P'");\r
-\r
-    InstructionDesc[OpFwidthCoarse].capabilities.push_back(CapShader);\r
-    InstructionDesc[OpFwidthCoarse].operands.push(OperandId, "'P'");\r
-\r
-    InstructionDesc[OpEmitVertex].capabilities.push_back(CapGeom);\r
-\r
-    InstructionDesc[OpEndPrimitive].capabilities.push_back(CapGeom);\r
-\r
-    InstructionDesc[OpEmitStreamVertex].operands.push(OperandId, "'Stream'");\r
-    InstructionDesc[OpEmitStreamVertex].capabilities.push_back(CapGeom);\r
-\r
-    InstructionDesc[OpEndStreamPrimitive].operands.push(OperandId, "'Stream'");\r
-    InstructionDesc[OpEndStreamPrimitive].capabilities.push_back(CapGeom);\r
-\r
-    InstructionDesc[OpControlBarrier].operands.push(OperandExecutionScope, "'Scope'");\r
-\r
-    InstructionDesc[OpMemoryBarrier].operands.push(OperandExecutionScope, "'Scope'");\r
-    InstructionDesc[OpMemoryBarrier].operands.push(OperandMemorySemantics, "'Semantics'");\r
-\r
-    InstructionDesc[OpImagePointer].operands.push(OperandId, "'Image'");\r
-    InstructionDesc[OpImagePointer].operands.push(OperandId, "'Coordinate'");\r
-    InstructionDesc[OpImagePointer].operands.push(OperandId, "'Sample'");\r
-\r
-    InstructionDesc[OpAtomicInit].operands.push(OperandId, "'Pointer'");\r
-    InstructionDesc[OpAtomicInit].operands.push(OperandId, "'Value'");\r
-\r
-    InstructionDesc[OpAtomicLoad].operands.push(OperandId, "'Pointer'");\r
-    InstructionDesc[OpAtomicLoad].operands.push(OperandExecutionScope, "'Scope'");\r
-    InstructionDesc[OpAtomicLoad].operands.push(OperandMemorySemantics, "'Semantics'");\r
-\r
-    InstructionDesc[OpAtomicStore].operands.push(OperandId, "'Pointer'");\r
-    InstructionDesc[OpAtomicStore].operands.push(OperandExecutionScope, "'Scope'");\r
-    InstructionDesc[OpAtomicStore].operands.push(OperandMemorySemantics, "'Semantics'");\r
-    InstructionDesc[OpAtomicStore].operands.push(OperandId, "'Value'");\r
-\r
-    InstructionDesc[OpAtomicExchange].operands.push(OperandId, "'Pointer'");\r
-    InstructionDesc[OpAtomicExchange].operands.push(OperandExecutionScope, "'Scope'");\r
-    InstructionDesc[OpAtomicExchange].operands.push(OperandMemorySemantics, "'Semantics'");\r
-    InstructionDesc[OpAtomicExchange].operands.push(OperandId, "'Value'");\r
-\r
-    InstructionDesc[OpAtomicCompareExchange].operands.push(OperandId, "'Pointer'");\r
-    InstructionDesc[OpAtomicCompareExchange].operands.push(OperandExecutionScope, "'Scope'");\r
-    InstructionDesc[OpAtomicCompareExchange].operands.push(OperandMemorySemantics, "'Semantics'");\r
-    InstructionDesc[OpAtomicCompareExchange].operands.push(OperandId, "'Value'");\r
-    InstructionDesc[OpAtomicCompareExchange].operands.push(OperandId, "'Comparator'");\r
-\r
-    InstructionDesc[OpAtomicCompareExchangeWeak].operands.push(OperandId, "'Pointer'");\r
-    InstructionDesc[OpAtomicCompareExchangeWeak].operands.push(OperandExecutionScope, "'Scope'");\r
-    InstructionDesc[OpAtomicCompareExchangeWeak].operands.push(OperandMemorySemantics, "'Semantics'");\r
-    InstructionDesc[OpAtomicCompareExchangeWeak].operands.push(OperandId, "'Value'");\r
-    InstructionDesc[OpAtomicCompareExchangeWeak].operands.push(OperandId, "'Comparator'");\r
-\r
-    InstructionDesc[OpAtomicIIncrement].operands.push(OperandId, "'Pointer'");\r
-    InstructionDesc[OpAtomicIIncrement].operands.push(OperandExecutionScope, "'Scope'");\r
-    InstructionDesc[OpAtomicIIncrement].operands.push(OperandMemorySemantics, "'Semantics'");\r
-\r
-    InstructionDesc[OpAtomicIDecrement].operands.push(OperandId, "'Pointer'");\r
-    InstructionDesc[OpAtomicIDecrement].operands.push(OperandExecutionScope, "'Scope'");\r
-    InstructionDesc[OpAtomicIDecrement].operands.push(OperandMemorySemantics, "'Semantics'");\r
-\r
-    InstructionDesc[OpAtomicIAdd].operands.push(OperandId, "'Pointer'");\r
-    InstructionDesc[OpAtomicIAdd].operands.push(OperandExecutionScope, "'Scope'");\r
-    InstructionDesc[OpAtomicIAdd].operands.push(OperandMemorySemantics, "'Semantics'");\r
-    InstructionDesc[OpAtomicIAdd].operands.push(OperandId, "'Value'");\r
-\r
-    InstructionDesc[OpAtomicISub].operands.push(OperandId, "'Pointer'");\r
-    InstructionDesc[OpAtomicISub].operands.push(OperandExecutionScope, "'Scope'");\r
-    InstructionDesc[OpAtomicISub].operands.push(OperandMemorySemantics, "'Semantics'");\r
-    InstructionDesc[OpAtomicISub].operands.push(OperandId, "'Value'");\r
-\r
-    InstructionDesc[OpAtomicUMin].operands.push(OperandId, "'Pointer'");\r
-    InstructionDesc[OpAtomicUMin].operands.push(OperandExecutionScope, "'Scope'");\r
-    InstructionDesc[OpAtomicUMin].operands.push(OperandMemorySemantics, "'Semantics'");\r
-    InstructionDesc[OpAtomicUMin].operands.push(OperandId, "'Value'");\r
-\r
-    InstructionDesc[OpAtomicUMax].operands.push(OperandId, "'Pointer'");\r
-    InstructionDesc[OpAtomicUMax].operands.push(OperandExecutionScope, "'Scope'");\r
-    InstructionDesc[OpAtomicUMax].operands.push(OperandMemorySemantics, "'Semantics'");\r
-    InstructionDesc[OpAtomicUMax].operands.push(OperandId, "'Value'");\r
-\r
-    InstructionDesc[OpAtomicIMin].operands.push(OperandId, "'Pointer'");\r
-    InstructionDesc[OpAtomicIMin].operands.push(OperandExecutionScope, "'Scope'");\r
-    InstructionDesc[OpAtomicIMin].operands.push(OperandMemorySemantics, "'Semantics'");\r
-    InstructionDesc[OpAtomicIMin].operands.push(OperandId, "'Value'");\r
-\r
-    InstructionDesc[OpAtomicIMax].operands.push(OperandId, "'Pointer'");\r
-    InstructionDesc[OpAtomicIMax].operands.push(OperandExecutionScope, "'Scope'");\r
-    InstructionDesc[OpAtomicIMax].operands.push(OperandMemorySemantics, "'Semantics'");\r
-    InstructionDesc[OpAtomicIMax].operands.push(OperandId, "'Value'");\r
-\r
-    InstructionDesc[OpAtomicAnd].operands.push(OperandId, "'Pointer'");\r
-    InstructionDesc[OpAtomicAnd].operands.push(OperandExecutionScope, "'Scope'");\r
-    InstructionDesc[OpAtomicAnd].operands.push(OperandMemorySemantics, "'Semantics'");\r
-    InstructionDesc[OpAtomicAnd].operands.push(OperandId, "'Value'");\r
-\r
-    InstructionDesc[OpAtomicOr].operands.push(OperandId, "'Pointer'");\r
-    InstructionDesc[OpAtomicOr].operands.push(OperandExecutionScope, "'Scope'");\r
-    InstructionDesc[OpAtomicOr].operands.push(OperandMemorySemantics, "'Semantics'");\r
-    InstructionDesc[OpAtomicOr].operands.push(OperandId, "'Value'");\r
-\r
-    InstructionDesc[OpAtomicXor].operands.push(OperandId, "'Pointer'");\r
-    InstructionDesc[OpAtomicXor].operands.push(OperandExecutionScope, "'Scope'");\r
-    InstructionDesc[OpAtomicXor].operands.push(OperandMemorySemantics, "'Semantics'");\r
-    InstructionDesc[OpAtomicXor].operands.push(OperandId, "'Value'");\r
-\r
-    InstructionDesc[OpLoopMerge].operands.push(OperandId, "'Label'");\r
-    InstructionDesc[OpLoopMerge].operands.push(OperandLoop, "");\r
-\r
-    InstructionDesc[OpSelectionMerge].operands.push(OperandId, "'Label'");\r
-    InstructionDesc[OpSelectionMerge].operands.push(OperandSelect, "");\r
-\r
-    InstructionDesc[OpBranch].operands.push(OperandId, "'Target Label'");\r
-\r
-    InstructionDesc[OpBranchConditional].operands.push(OperandId, "'Condition'");\r
-    InstructionDesc[OpBranchConditional].operands.push(OperandId, "'True Label'");\r
-    InstructionDesc[OpBranchConditional].operands.push(OperandId, "'False Label'");\r
-    InstructionDesc[OpBranchConditional].operands.push(OperandVariableLiterals, "'Branch weights'");\r
-\r
-    InstructionDesc[OpSwitch].operands.push(OperandId, "'Selector'");\r
-    InstructionDesc[OpSwitch].operands.push(OperandId, "'Default'");\r
-    InstructionDesc[OpSwitch].operands.push(OperandVariableLiteralId, "'Target'");\r
-\r
-    InstructionDesc[OpKill].capabilities.push_back(CapShader);\r
-\r
-    InstructionDesc[OpReturnValue].operands.push(OperandId, "'Value'");\r
-\r
-    InstructionDesc[OpUnreachable].capabilities.push_back(CapKernel);\r
-\r
-    InstructionDesc[OpLifetimeStart].operands.push(OperandId, "");\r
-    InstructionDesc[OpLifetimeStart].operands.push(OperandLiteralNumber, "");\r
-\r
-    InstructionDesc[OpLifetimeStop].operands.push(OperandId, "");\r
-    InstructionDesc[OpLifetimeStop].operands.push(OperandLiteralNumber, "");\r
-\r
-    InstructionDesc[OpCompileFlag].capabilities.push_back(CapKernel);\r
-    InstructionDesc[OpCompileFlag].operands.push(OperandLiteralString, "'Flag'");\r
-\r
-    InstructionDesc[OpAsyncGroupCopy].capabilities.push_back(CapKernel);\r
-    InstructionDesc[OpAsyncGroupCopy].operands.push(OperandExecutionScope, "'Scope'");\r
-    InstructionDesc[OpAsyncGroupCopy].operands.push(OperandId, "'Destination'");\r
-    InstructionDesc[OpAsyncGroupCopy].operands.push(OperandId, "'Source'");\r
-    InstructionDesc[OpAsyncGroupCopy].operands.push(OperandId, "'Num Elements'");\r
-    InstructionDesc[OpAsyncGroupCopy].operands.push(OperandId, "'Stride'");\r
-    InstructionDesc[OpAsyncGroupCopy].operands.push(OperandId, "'Event'");\r
-\r
-    InstructionDesc[OpWaitGroupEvents].capabilities.push_back(CapKernel);\r
-    InstructionDesc[OpWaitGroupEvents].operands.push(OperandExecutionScope, "'Scope'");\r
-    InstructionDesc[OpWaitGroupEvents].operands.push(OperandId, "'Num Events'");\r
-    InstructionDesc[OpWaitGroupEvents].operands.push(OperandId, "'Events List'");\r
-\r
-    InstructionDesc[OpGroupAll].capabilities.push_back(CapKernel);\r
-    InstructionDesc[OpGroupAll].operands.push(OperandExecutionScope, "'Scope'");\r
-    InstructionDesc[OpGroupAll].operands.push(OperandId, "'Predicate'");\r
-\r
-    InstructionDesc[OpGroupAny].capabilities.push_back(CapKernel);\r
-    InstructionDesc[OpGroupAny].operands.push(OperandExecutionScope, "'Scope'");\r
-    InstructionDesc[OpGroupAny].operands.push(OperandId, "'Predicate'");\r
-\r
-    InstructionDesc[OpGroupBroadcast].capabilities.push_back(CapKernel);\r
-    InstructionDesc[OpGroupBroadcast].operands.push(OperandExecutionScope, "'Scope'");\r
-    InstructionDesc[OpGroupBroadcast].operands.push(OperandId, "'Value'");\r
-    InstructionDesc[OpGroupBroadcast].operands.push(OperandId, "'LocalId'");\r
-\r
-    InstructionDesc[OpGroupIAdd].capabilities.push_back(CapKernel);\r
-    InstructionDesc[OpGroupIAdd].operands.push(OperandExecutionScope, "'Scope'");\r
-    InstructionDesc[OpGroupIAdd].operands.push(OperandGroupOperation, "'Operation'");\r
-    InstructionDesc[OpGroupIAdd].operands.push(OperandId, "'X'");\r
-\r
-    InstructionDesc[OpGroupFAdd].capabilities.push_back(CapKernel);\r
-    InstructionDesc[OpGroupFAdd].operands.push(OperandExecutionScope, "'Scope'");\r
-    InstructionDesc[OpGroupFAdd].operands.push(OperandGroupOperation, "'Operation'");\r
-    InstructionDesc[OpGroupFAdd].operands.push(OperandId, "'X'");\r
-\r
-    InstructionDesc[OpGroupUMin].capabilities.push_back(CapKernel);\r
-    InstructionDesc[OpGroupUMin].operands.push(OperandExecutionScope, "'Scope'");\r
-    InstructionDesc[OpGroupUMin].operands.push(OperandGroupOperation, "'Operation'");\r
-    InstructionDesc[OpGroupUMin].operands.push(OperandId, "'X'");\r
-\r
-    InstructionDesc[OpGroupSMin].capabilities.push_back(CapKernel);\r
-    InstructionDesc[OpGroupSMin].operands.push(OperandExecutionScope, "'Scope'");\r
-    InstructionDesc[OpGroupSMin].operands.push(OperandGroupOperation, "'Operation'");\r
-    InstructionDesc[OpGroupSMin].operands.push(OperandId, "X");\r
-\r
-    InstructionDesc[OpGroupFMin].capabilities.push_back(CapKernel);\r
-    InstructionDesc[OpGroupFMin].operands.push(OperandExecutionScope, "'Scope'");\r
-    InstructionDesc[OpGroupFMin].operands.push(OperandGroupOperation, "'Operation'");\r
-    InstructionDesc[OpGroupFMin].operands.push(OperandId, "X");\r
-\r
-    InstructionDesc[OpGroupUMax].capabilities.push_back(CapKernel);\r
-    InstructionDesc[OpGroupUMax].operands.push(OperandExecutionScope, "'Scope'");\r
-    InstructionDesc[OpGroupUMax].operands.push(OperandGroupOperation, "'Operation'");\r
-    InstructionDesc[OpGroupUMax].operands.push(OperandId, "X");\r
-\r
-    InstructionDesc[OpGroupSMax].capabilities.push_back(CapKernel);\r
-    InstructionDesc[OpGroupSMax].operands.push(OperandExecutionScope, "'Scope'");\r
-    InstructionDesc[OpGroupSMax].operands.push(OperandGroupOperation, "'Operation'");\r
-    InstructionDesc[OpGroupSMax].operands.push(OperandId, "X");\r
-\r
-    InstructionDesc[OpGroupFMax].capabilities.push_back(CapKernel);\r
-    InstructionDesc[OpGroupFMax].operands.push(OperandExecutionScope, "'Scope'");\r
-    InstructionDesc[OpGroupFMax].operands.push(OperandGroupOperation, "'Operation'");\r
-    InstructionDesc[OpGroupFMax].operands.push(OperandId, "X");\r
-\r
-    InstructionDesc[OpReadPipe].capabilities.push_back(CapKernel);\r
-    InstructionDesc[OpReadPipe].operands.push(OperandId, "'p'");\r
-    InstructionDesc[OpReadPipe].operands.push(OperandId, "'ptr'");\r
-\r
-    InstructionDesc[OpWritePipe].capabilities.push_back(CapKernel);\r
-    InstructionDesc[OpWritePipe].operands.push(OperandId, "'p'");\r
-    InstructionDesc[OpWritePipe].operands.push(OperandId, "'ptr'");\r
-\r
-    InstructionDesc[OpReservedReadPipe].capabilities.push_back(CapKernel);\r
-    InstructionDesc[OpReservedReadPipe].operands.push(OperandId, "'p'");\r
-    InstructionDesc[OpReservedReadPipe].operands.push(OperandId, "'reserve_id'");\r
-    InstructionDesc[OpReservedReadPipe].operands.push(OperandId, "'index'");\r
-    InstructionDesc[OpReservedReadPipe].operands.push(OperandId, "'ptr'");\r
-\r
-    InstructionDesc[OpReservedWritePipe].capabilities.push_back(CapKernel);\r
-    InstructionDesc[OpReservedWritePipe].operands.push(OperandId, "'p'");\r
-    InstructionDesc[OpReservedWritePipe].operands.push(OperandId, "'reserve_id'");\r
-    InstructionDesc[OpReservedWritePipe].operands.push(OperandId, "'index'");\r
-    InstructionDesc[OpReservedWritePipe].operands.push(OperandId, "'ptr'");\r
-\r
-    InstructionDesc[OpReserveReadPipePackets].capabilities.push_back(CapKernel);\r
-    InstructionDesc[OpReserveReadPipePackets].operands.push(OperandId, "'p'");\r
-    InstructionDesc[OpReserveReadPipePackets].operands.push(OperandId, "'num_packets'");\r
-\r
-    InstructionDesc[OpReserveWritePipePackets].capabilities.push_back(CapKernel);\r
-    InstructionDesc[OpReserveWritePipePackets].operands.push(OperandId, "'p'");\r
-    InstructionDesc[OpReserveWritePipePackets].operands.push(OperandId, "'num_packets'");\r
-\r
-    InstructionDesc[OpCommitReadPipe].capabilities.push_back(CapKernel);\r
-    InstructionDesc[OpCommitReadPipe].operands.push(OperandId, "'p'");\r
-    InstructionDesc[OpCommitReadPipe].operands.push(OperandId, "'reserve_id'");\r
-\r
-    InstructionDesc[OpCommitWritePipe].capabilities.push_back(CapKernel);\r
-    InstructionDesc[OpCommitWritePipe].operands.push(OperandId, "'p'");\r
-    InstructionDesc[OpCommitWritePipe].operands.push(OperandId, "'reserve_id'");\r
-\r
-    InstructionDesc[OpIsValidReserveId].capabilities.push_back(CapKernel);\r
-    InstructionDesc[OpIsValidReserveId].operands.push(OperandId, "'reserve_id'");\r
-\r
-    InstructionDesc[OpGetNumPipePackets].capabilities.push_back(CapKernel);\r
-    InstructionDesc[OpGetNumPipePackets].operands.push(OperandId, "'p'");\r
-\r
-    InstructionDesc[OpGetMaxPipePackets].capabilities.push_back(CapKernel);\r
-    InstructionDesc[OpGetMaxPipePackets].operands.push(OperandId, "'p'");\r
-\r
-    InstructionDesc[OpGroupReserveReadPipePackets].capabilities.push_back(CapKernel);\r
-    InstructionDesc[OpGroupReserveReadPipePackets].operands.push(OperandExecutionScope, "'Scope'");\r
-    InstructionDesc[OpGroupReserveReadPipePackets].operands.push(OperandId, "'p'");\r
-    InstructionDesc[OpGroupReserveReadPipePackets].operands.push(OperandId, "'num_packets'");\r
-\r
-    InstructionDesc[OpGroupReserveWritePipePackets].capabilities.push_back(CapKernel);\r
-    InstructionDesc[OpGroupReserveWritePipePackets].operands.push(OperandExecutionScope, "'Scope'");\r
-    InstructionDesc[OpGroupReserveWritePipePackets].operands.push(OperandId, "'p'");\r
-    InstructionDesc[OpGroupReserveWritePipePackets].operands.push(OperandId, "'num_packets'");\r
-\r
-    InstructionDesc[OpGroupCommitReadPipe].capabilities.push_back(CapKernel);\r
-    InstructionDesc[OpGroupCommitReadPipe].operands.push(OperandExecutionScope, "'Scope'");\r
-    InstructionDesc[OpGroupCommitReadPipe].operands.push(OperandId, "'p'");\r
-    InstructionDesc[OpGroupCommitReadPipe].operands.push(OperandId, "'reserve_id'");\r
-\r
-    InstructionDesc[OpGroupCommitWritePipe].capabilities.push_back(CapKernel);\r
-    InstructionDesc[OpGroupCommitWritePipe].operands.push(OperandExecutionScope, "'Scope'");\r
-    InstructionDesc[OpGroupCommitWritePipe].operands.push(OperandId, "'p'");\r
-    InstructionDesc[OpGroupCommitWritePipe].operands.push(OperandId, "'reserve_id'");\r
-\r
-    InstructionDesc[OpBuildNDRange].capabilities.push_back(CapKernel);\r
-    InstructionDesc[OpBuildNDRange].operands.push(OperandId, "'GlobalWorkSize'");\r
-    InstructionDesc[OpBuildNDRange].operands.push(OperandId, "'LocalWorkSize'");\r
-    InstructionDesc[OpBuildNDRange].operands.push(OperandId, "'GlobalWorkOffset'");\r
-\r
-    InstructionDesc[OpGetDefaultQueue].capabilities.push_back(CapKernel);\r
-\r
-    InstructionDesc[OpCaptureEventProfilingInfo].capabilities.push_back(CapKernel);\r
-\r
-    InstructionDesc[OpCaptureEventProfilingInfo].operands.push(OperandId, "'event'");\r
-    InstructionDesc[OpCaptureEventProfilingInfo].operands.push(OperandKernelProfilingInfo, "'info'");\r
-    InstructionDesc[OpCaptureEventProfilingInfo].operands.push(OperandId, "'value'");\r
-\r
-    InstructionDesc[OpSetUserEventStatus].capabilities.push_back(CapKernel);\r
-\r
-    InstructionDesc[OpSetUserEventStatus].operands.push(OperandId, "'event'");\r
-    InstructionDesc[OpSetUserEventStatus].operands.push(OperandId, "'status'");\r
-\r
-    InstructionDesc[OpIsValidEvent].capabilities.push_back(CapKernel);\r
-    InstructionDesc[OpIsValidEvent].operands.push(OperandId, "'event'");\r
-\r
-    InstructionDesc[OpCreateUserEvent].capabilities.push_back(CapKernel);\r
-\r
-    InstructionDesc[OpRetainEvent].capabilities.push_back(CapKernel);\r
-    InstructionDesc[OpRetainEvent].operands.push(OperandId, "'event'");\r
-\r
-    InstructionDesc[OpReleaseEvent].capabilities.push_back(CapKernel);\r
-    InstructionDesc[OpReleaseEvent].operands.push(OperandId, "'event'");\r
-\r
-    InstructionDesc[OpGetKernelWorkGroupSize].capabilities.push_back(CapKernel);\r
-    InstructionDesc[OpGetKernelWorkGroupSize].operands.push(OperandId, "'Invoke'");\r
-\r
-    InstructionDesc[OpGetKernelPreferredWorkGroupSizeMultiple].capabilities.push_back(CapKernel);\r
-    InstructionDesc[OpGetKernelPreferredWorkGroupSizeMultiple].operands.push(OperandId, "'Invoke'");\r
-\r
-    InstructionDesc[OpGetKernelNDrangeSubGroupCount].capabilities.push_back(CapKernel);\r
-    InstructionDesc[OpGetKernelNDrangeSubGroupCount].operands.push(OperandId, "'ND Range'");\r
-    InstructionDesc[OpGetKernelNDrangeSubGroupCount].operands.push(OperandId, "'Invoke'");\r
-\r
-    InstructionDesc[OpGetKernelNDrangeMaxSubGroupSize].capabilities.push_back(CapKernel);\r
-    InstructionDesc[OpGetKernelNDrangeMaxSubGroupSize].operands.push(OperandId, "'ND Range'");\r
-    InstructionDesc[OpGetKernelNDrangeMaxSubGroupSize].operands.push(OperandId, "'Invoke'");\r
-\r
-    InstructionDesc[OpEnqueueKernel].capabilities.push_back(CapKernel);\r
-    InstructionDesc[OpEnqueueKernel].operands.push(OperandId, "'q'");\r
-    InstructionDesc[OpEnqueueKernel].operands.push(OperandKernelEnqueueFlags, "'flags'");\r
-    InstructionDesc[OpEnqueueKernel].operands.push(OperandId, "'ND Range'");\r
-    InstructionDesc[OpEnqueueKernel].operands.push(OperandId, "'Num Events'");\r
-    InstructionDesc[OpEnqueueKernel].operands.push(OperandId, "'Wait Events'");\r
-    InstructionDesc[OpEnqueueKernel].operands.push(OperandId, "'Ret Event'");\r
-    InstructionDesc[OpEnqueueKernel].operands.push(OperandId, "'Invoke'");\r
-    InstructionDesc[OpEnqueueKernel].operands.push(OperandId, "'Param'");\r
-    InstructionDesc[OpEnqueueKernel].operands.push(OperandId, "'Param Size'");\r
-    InstructionDesc[OpEnqueueKernel].operands.push(OperandId, "'Param Align'");\r
-    InstructionDesc[OpEnqueueKernel].operands.push(OperandVariableIds, "'Local Size'");\r
-\r
-    InstructionDesc[OpEnqueueMarker].capabilities.push_back(CapKernel);\r
-    InstructionDesc[OpEnqueueMarker].operands.push(OperandId, "'q'");\r
-    InstructionDesc[OpEnqueueMarker].operands.push(OperandId, "'Num Events'");\r
-    InstructionDesc[OpEnqueueMarker].operands.push(OperandId, "'Wait Events'");\r
-    InstructionDesc[OpEnqueueMarker].operands.push(OperandId, "'Ret Event'");\r
-}\r
-\r
-}; // end spv namespace\r
+//
+//Copyright (C) 2014 LunarG, Inc.
+//
+//All rights reserved.
+//
+//Redistribution and use in source and binary forms, with or without
+//modification, are permitted provided that the following conditions
+//are met:
+//
+//    Redistributions of source code must retain the above copyright
+//    notice, this list of conditions and the following disclaimer.
+//
+//    Redistributions in binary form must reproduce the above
+//    copyright notice, this list of conditions and the following
+//    disclaimer in the documentation and/or other materials provided
+//    with the distribution.
+//
+//    Neither the name of 3Dlabs Inc. Ltd. nor the names of its
+//    contributors may be used to endorse or promote products derived
+//    from this software without specific prior written permission.
+//
+//THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+//"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+//LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+//FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+//COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+//INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+//BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+//LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+//CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+//LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+//ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+//POSSIBILITY OF SUCH DAMAGE.
+
+//
+// Author: John Kessenich, LunarG
+//
+
+//
+// 1) Programatically fill in instruction/operand information.
+//    This can be used for disassembly, printing documentation, etc.
+//
+// 2) Print documentation from this parameterization.
+//
+
+#include "doc.h"
+
+#include <stdio.h>
+#include <string.h>
+#include <algorithm>
+
+namespace spv {
+
+//
+// Whole set of functions that translate enumerants to their text strings for
+// the specification (or their sanitized versions for auto-generating the
+// spirv.h header.
+//
+// Also, the ceilings are declared next to these, to help keep them in sync.
+// Ceilings should be
+//  - one more than the maximum value an enumerant takes on, for non-mask enumerants
+//    (for non-sparse enums, this is the number of enumurants)
+//  - the number of bits consumed by the set of masks
+//    (for non-sparse mask enums, this is the number of enumurants)
+//
+
+const int SourceLanguageCeiling = 4;
+
+const char* SourceString(int source)
+{
+    switch (source) {
+    case 0:  return "Unknown";
+    case 1:  return "ESSL";
+    case 2:  return "GLSL";
+    case 3:  return "OpenCL";
+
+    case SourceLanguageCeiling:
+    default: return "Bad";
+    }
+}
+
+const int ExecutionModelCeiling = 7;
+
+const char* ExecutionModelString(int model)
+{
+    switch (model) {
+    case 0:  return "Vertex";
+    case 1:  return "TessellationControl";
+    case 2:  return "TessellationEvaluation";
+    case 3:  return "Geometry";
+    case 4:  return "Fragment";
+    case 5:  return "GLCompute";
+    case 6:  return "Kernel";
+
+    case ExecutionModelCeiling:
+    default: return "Bad";
+    }
+}
+
+const int AddressingModelCeiling = 3;
+
+const char* AddressingString(int addr)
+{
+    switch (addr) {
+    case 0:  return "Logical";
+    case 1:  return "Physical32";
+    case 2:  return "Physical64";
+
+    case AddressingModelCeiling:
+    default: return "Bad";
+    }
+}
+
+const int MemoryModelCeiling = 5;
+
+const char* MemoryString(int mem)
+{
+    switch (mem) {
+    case 0:  return "Simple";
+    case 1:  return "GLSL450";
+    case 2:  return "OpenCL1.2";
+    case 3:  return "OpenCL2.0";
+    case 4:  return "OpenCL2.1";
+
+    case MemoryModelCeiling:
+    default: return "Bad";
+    }
+}
+
+const int ExecutionModeCeiling = 31;
+
+const char* ExecutionModeString(int mode)
+{
+    switch (mode) {
+    case 0:  return "Invocations";
+    case 1:  return "SpacingEqual";
+    case 2:  return "SpacingFractionalEven";
+    case 3:  return "SpacingFractionalOdd";
+    case 4:  return "VertexOrderCw";
+    case 5:  return "VertexOrderCcw";
+    case 6:  return "PixelCenterInteger";
+    case 7:  return "OriginUpperLeft";
+    case 8:  return "EarlyFragmentTests";
+    case 9:  return "PointMode";
+    case 10: return "Xfb";
+    case 11: return "DepthReplacing";
+    case 12: return "DepthAny";
+    case 13: return "DepthGreater";
+    case 14: return "DepthLess";
+    case 15: return "DepthUnchanged";
+    case 16: return "LocalSize";
+    case 17: return "LocalSizeHint";
+    case 18: return "InputPoints";
+    case 19: return "InputLines";
+    case 20: return "InputLinesAdjacency";
+    case 21: return "InputTriangles";
+    case 22: return "InputTrianglesAdjacency";
+    case 23: return "InputQuads";
+    case 24: return "InputIsolines";
+    case 25: return "OutputVertices";
+    case 26: return "OutputPoints";
+    case 27: return "OutputLineStrip";
+    case 28: return "OutputTriangleStrip";
+    case 29: return "VecTypeHint";
+    case 30: return "ContractionOff";
+
+    case ExecutionModeCeiling:
+    default: return "Bad";
+    }
+}
+
+const int StorageClassCeiling = 11;
+
+const char* StorageClassString(int StorageClass)
+{
+    switch (StorageClass) {
+    case 0:  return "UniformConstant";
+    case 1:  return "Input";
+    case 2:  return "Uniform";
+    case 3:  return "Output";
+    case 4:  return "WorkgroupLocal";
+    case 5:  return "WorkgroupGlobal";
+    case 6:  return "PrivateGlobal";
+    case 7:  return "Function";
+    case 8:  return "Generic";
+    case 9:  return "Private";
+    case 10: return "AtomicCounter";
+
+    case StorageClassCeiling:
+    default: return "Bad";
+    }
+}
+
+const int DecorationCeiling = 45;
+
+const char* DecorationString(int decoration)
+{
+    switch (decoration) {
+    case 0:  return "PrecisionLow";
+    case 1:  return "PrecisionMedium";
+    case 2:  return "PrecisionHigh";
+    case 3:  return "Block";
+    case 4:  return "BufferBlock";
+    case 5:  return "RowMajor";
+    case 6:  return "ColMajor";
+    case 7:  return "GLSLShared";
+    case 8:  return "GLSLStd140";
+    case 9:  return "GLSLStd430";
+    case 10: return "GLSLPacked";
+    case 11: return "Smooth";
+    case 12: return "Noperspective";
+    case 13: return "Flat";
+    case 14: return "Patch";
+    case 15: return "Centroid";
+    case 16: return "Sample";
+    case 17: return "Invariant";
+    case 18: return "Restrict";
+    case 19: return "Aliased";
+    case 20: return "Volatile";
+    case 21: return "Constant";
+    case 22: return "Coherent";
+    case 23: return "Nonwritable";
+    case 24: return "Nonreadable";
+    case 25: return "Uniform";
+    case 26: return "NoStaticUse";
+    case 27: return "CPacked";
+    case 28: return "SaturatedConversion";
+    case 29: return "Stream";
+    case 30: return "Location";
+    case 31: return "Component";
+    case 32: return "Index";
+    case 33: return "Binding";
+    case 34: return "DescriptorSet";
+    case 35: return "Offset";
+    case 36: return "Alignment";
+    case 37: return "XfbBuffer";
+    case 38: return "Stride";
+    case 39: return "BuiltIn";
+    case 40: return "FuncParamAttr";
+    case 41: return "FP Rounding Mode";
+    case 42: return "FP Fast Math Mode";
+    case 43: return "Linkage Attributes";
+    case 44: return "SpecId";
+
+    case DecorationCeiling:
+    default:  return "Bad";
+    }
+}
+
+const int BuiltInCeiling = 42;
+
+const char* BuiltInString(int builtIn)
+{
+    switch (builtIn) {
+    case 0:  return "Position";
+    case 1:  return "PointSize";
+    case 2:  return "ClipVertex";
+    case 3:  return "ClipDistance";
+    case 4:  return "CullDistance";
+    case 5:  return "VertexId";
+    case 6:  return "InstanceId";
+    case 7:  return "PrimitiveId";
+    case 8:  return "InvocationId";
+    case 9:  return "Layer";
+    case 10: return "ViewportIndex";
+    case 11: return "TessLevelOuter";
+    case 12: return "TessLevelInner";
+    case 13: return "TessCoord";
+    case 14: return "PatchVertices";
+    case 15: return "FragCoord";
+    case 16: return "PointCoord";
+    case 17: return "FrontFacing";
+    case 18: return "SampleId";
+    case 19: return "SamplePosition";
+    case 20: return "SampleMask";
+    case 21: return "FragColor";
+    case 22: return "FragDepth";
+    case 23: return "HelperInvocation";
+    case 24: return "NumWorkgroups";
+    case 25: return "WorkgroupSize";
+    case 26: return "WorkgroupId";
+    case 27: return "LocalInvocationId";
+    case 28: return "GlobalInvocationId";
+    case 29: return "LocalInvocationIndex";
+    case 30: return "WorkDim";
+    case 31: return "GlobalSize";
+    case 32: return "EnqueuedWorkgroupSize";
+    case 33: return "GlobalOffset";
+    case 34: return "GlobalLinearId";
+    case 35: return "WorkgroupLinearId";
+    case 36: return "SubgroupSize";
+    case 37: return "SubgroupMaxSize";
+    case 38: return "NumSubgroups";
+    case 39: return "NumEnqueuedSubgroups";
+    case 40: return "SubgroupId";
+    case 41: return "SubgroupLocalInvocationId";
+
+    case BuiltInCeiling:
+    default: return "Bad";
+    }
+}
+
+const int DimensionCeiling = 6;
+
+const char* DimensionString(int dim)
+{
+    switch (dim) {
+    case 0:  return "1D";
+    case 1:  return "2D";
+    case 2:  return "3D";
+    case 3:  return "Cube";
+    case 4:  return "Rect";
+    case 5:  return "Buffer";
+
+    case DimensionCeiling:
+    default: return "Bad";
+    }
+}
+
+const int SamplerAddressingModeCeiling = 5;
+
+const char* SamplerAddressingModeString(int mode)
+{
+    switch (mode) {
+    case 0:  return "None";
+    case 1:  return "ClampToEdge";
+    case 2:  return "Clamp";
+    case 3:  return "Repeat";
+    case 4:  return "RepeatMirrored";
+
+    case SamplerAddressingModeCeiling:
+    default: return "Bad";
+    }
+}
+
+const int SamplerFilterModeCeiling = 2;
+
+const char* SamplerFilterModeString(int mode)
+{
+    switch (mode) {
+    case 0: return "Nearest";
+    case 1: return "Linear";
+
+    case SamplerFilterModeCeiling:
+    default: return "Bad";
+    }
+}
+
+const int FPFastMathCeiling = 5;
+
+const char* FPFastMathString(int mode)
+{
+    switch (mode) {
+    case 0: return "NotNaN";
+    case 1: return "NotInf";
+    case 2: return "NSZ";
+    case 3: return "AllowRecip";
+    case 4: return "Fast";
+
+    case FPFastMathCeiling:
+    default:     return "Bad";
+    }
+}
+
+const int FPRoundingModeCeiling = 4;
+
+const char* FPRoundingModeString(int mode)
+{
+    switch (mode) {
+    case 0:  return "RTE";
+    case 1:  return "RTZ";
+    case 2:  return "RTP";
+    case 3:  return "RTN";
+
+    case FPRoundingModeCeiling:
+    default: return "Bad";
+    }
+}
+
+const int LinkageTypeCeiling = 2;
+
+const char* LinkageTypeString(int type)
+{
+    switch (type) {
+    case 0:  return "Export";
+    case 1:  return "Import";
+
+    case LinkageTypeCeiling:
+    default: return "Bad";
+    }
+}
+
+const int FuncParamAttrCeiling = 9;
+
+const char* FuncParamAttrString(int attr)
+{
+    switch (attr) {
+    case 0:  return "Zext";
+    case 1:  return "Sext";
+    case 2:  return "ByVal";
+    case 3:  return "Sret";
+    case 4:  return "NoAlias";
+    case 5:  return "NoCapture";
+    case 6:  return "SVM";
+    case 7:  return "NoWrite";
+    case 8:  return "NoReadWrite";
+
+    case FuncParamAttrCeiling:
+    default: return "Bad";
+    }
+}
+
+const int AccessQualifierCeiling = 3;
+
+const char* AccessQualifierString(int attr)
+{
+    switch (attr) {
+    case 0:  return "ReadOnly";
+    case 1:  return "WriteOnly";
+    case 2:  return "ReadWrite";
+
+    case AccessQualifierCeiling:
+    default: return "Bad";
+    }
+}
+
+const int SelectControlCeiling = 2;
+
+const char* SelectControlString(int cont)
+{
+    switch (cont) {
+    case 0:  return "Flatten";
+    case 1:  return "DontFlatten";
+
+    case SelectControlCeiling:
+    default:                       return "Bad";
+    }
+}
+
+const int LoopControlCeiling = 2;
+
+const char* LoopControlString(int cont)
+{
+    switch (cont) {
+    case 0: return "Unroll";
+    case 1: return "DontUnroll";
+
+    case LoopControlCeiling:
+    default:     return "Bad";
+    }
+}
+
+const int FunctionControlCeiling = 4;
+
+const char* FunctionControlString(int cont)
+{
+    switch (cont) {
+    case 0:  return "Inline";
+    case 1:  return "DontInline";
+    case 2:  return "Pure";
+    case 3:  return "Const";
+
+    case FunctionControlCeiling:
+    default: return "Bad";
+    }
+}
+
+const int MemorySemanticsCeiling = 10;
+
+const char* MemorySemanticsString(int mem)
+{
+    switch (mem) {
+    case 0: return "Relaxed";
+    case 1: return "SequentiallyConsistent";
+    case 2: return "Acquire";
+    case 3: return "Release";
+
+    case 4: return "UniformMemory";
+    case 5: return "SubgroupMemory";
+    case 6: return "WorkgroupLocalMemory";
+    case 7: return "WorkgroupGlobalMemory";
+    case 8: return "AtomicCounterMemory";
+    case 9: return "ImageMemory";
+
+    case MemorySemanticsCeiling:
+    default:     return "Bad";
+    }
+}
+
+const int MemoryAccessCeiling = 2;
+
+const char* MemoryAccessString(int mem)
+{
+    switch (mem) {
+    case 0:  return "Volatile";
+    case 1:  return "Aligned";
+
+    case MemoryAccessCeiling:
+    default: return "Bad";
+    }
+}
+
+const int ExecutionScopeCeiling = 4;
+
+const char* ExecutionScopeString(int mem)
+{
+    switch (mem) {
+    case 0:  return "CrossDevice";
+    case 1:  return "Device";
+    case 2:  return "Workgroup";
+    case 3:  return "Subgroup";
+
+    case ExecutionScopeCeiling:
+    default: return "Bad";
+    }
+}
+
+const int GroupOperationCeiling = 3;
+
+const char* GroupOperationString(int gop)
+{
+
+    switch (gop)
+    {
+    case 0:  return "Reduce";
+    case 1:  return "InclusiveScan";
+    case 2:  return "ExclusiveScan";
+
+    case GroupOperationCeiling:
+    default: return "Bad";
+    }
+}
+
+const int KernelEnqueueFlagsCeiling = 3;
+
+const char* KernelEnqueueFlagsString(int flag)
+{
+    switch (flag)
+    {
+    case 0:  return "NoWait";
+    case 1:  return "WaitKernel";
+    case 2:  return "WaitWorkGroup";
+
+    case KernelEnqueueFlagsCeiling:
+    default: return "Bad";
+    }
+}
+
+const int KernelProfilingInfoCeiling = 1;
+
+const char* KernelProfilingInfoString(int info)
+{
+    switch (info)
+    {
+    case 0:  return "CmdExecTime";
+
+    case KernelProfilingInfoCeiling:
+    default: return "Bad";
+    }
+}
+
+const char* OpcodeString(int op)
+{
+    switch (op) {
+    case 0:   return "OpNop";
+    case 1:   return "OpSource";
+    case 2:   return "OpSourceExtension";
+    case 3:   return "OpExtension";
+    case 4:   return "OpExtInstImport";
+    case 5:   return "OpMemoryModel";
+    case 6:   return "OpEntryPoint";
+    case 7:   return "OpExecutionMode";
+    case 8:   return "OpTypeVoid";
+    case 9:   return "OpTypeBool";
+    case 10:  return "OpTypeInt";
+    case 11:  return "OpTypeFloat";
+    case 12:  return "OpTypeVector";
+    case 13:  return "OpTypeMatrix";
+    case 14:  return "OpTypeSampler";
+    case 15:  return "OpTypeFilter";
+    case 16:  return "OpTypeArray";
+    case 17:  return "OpTypeRuntimeArray";
+    case 18:  return "OpTypeStruct";
+    case 19:  return "OpTypeOpaque";
+    case 20:  return "OpTypePointer";
+    case 21:  return "OpTypeFunction";
+    case 22:  return "OpTypeEvent";
+    case 23:  return "OpTypeDeviceEvent";
+    case 24:  return "OpTypeReserveId";
+    case 25:  return "OpTypeQueue";
+    case 26:  return "OpTypePipe";
+    case 27:  return "OpConstantTrue";
+    case 28:  return "OpConstantFalse";
+    case 29:  return "OpConstant";
+    case 30:  return "OpConstantComposite";
+    case 31:  return "OpConstantSampler";
+    case 32:  return "OpConstantNullPointer";
+    case 33:  return "OpConstantNullObject";
+    case 34:  return "OpSpecConstantTrue";
+    case 35:  return "OpSpecConstantFalse";
+    case 36:  return "OpSpecConstant";
+    case 37:  return "OpSpecConstantComposite";
+    case 38:  return "OpVariable";
+    case 39:  return "OpVariableArray";
+    case 40:  return "OpFunction";
+    case 41:  return "OpFunctionParameter";
+    case 42:  return "OpFunctionEnd";
+    case 43:  return "OpFunctionCall";
+    case 44:  return "OpExtInst";
+    case 45:  return "OpUndef";
+    case 46:  return "OpLoad";
+    case 47:  return "OpStore";
+    case 48:  return "OpPhi";
+    case 49:  return "OpDecorationGroup";
+    case 50:  return "OpDecorate";
+    case 51:  return "OpMemberDecorate";
+    case 52:  return "OpGroupDecorate";
+    case 53:  return "OpGroupMemberDecorate";
+    case 54:  return "OpName";
+    case 55:  return "OpMemberName";
+    case 56:  return "OpString";
+    case 57:  return "OpLine";
+    case 58:  return "OpVectorExtractDynamic";
+    case 59:  return "OpVectorInsertDynamic";
+    case 60:  return "OpVectorShuffle";
+    case 61:  return "OpCompositeConstruct";
+    case 62:  return "OpCompositeExtract";
+    case 63:  return "OpCompositeInsert";
+    case 64:  return "OpCopyObject";
+    case 65:  return "OpCopyMemory";
+    case 66:  return "OpCopyMemorySized";
+    case 67:  return "OpSampler";
+    case 68:  return "OpTextureSample";
+    case 69:  return "OpTextureSampleDref";
+    case 70:  return "OpTextureSampleLod";
+    case 71:  return "OpTextureSampleProj";
+    case 72:  return "OpTextureSampleGrad";
+    case 73:  return "OpTextureSampleOffset";
+    case 74:  return "OpTextureSampleProjLod";
+    case 75:  return "OpTextureSampleProjGrad";
+    case 76:  return "OpTextureSampleLodOffset";
+    case 77:  return "OpTextureSampleProjOffset";
+    case 78:  return "OpTextureSampleGradOffset";
+    case 79:  return "OpTextureSampleProjLodOffset";
+    case 80:  return "OpTextureSampleProjGradOffset";
+    case 81:  return "OpTextureFetchTexelLod";
+    case 82:  return "OpTextureFetchTexelOffset";
+    case 83:  return "OpTextureFetchSample";
+    case 84:  return "OpTextureFetchTexel";
+    case 85:  return "OpTextureGather";
+    case 86:  return "OpTextureGatherOffset";
+    case 87:  return "OpTextureGatherOffsets";
+    case 88:  return "OpTextureQuerySizeLod";
+    case 89:  return "OpTextureQuerySize";
+    case 90:  return "OpTextureQueryLod";
+    case 91:  return "OpTextureQueryLevels";
+    case 92:  return "OpTextureQuerySamples";
+    case 93:  return "OpAccessChain";
+    case 94:  return "OpInBoundsAccessChain";
+    case 95:  return "OpSNegate";
+    case 96:  return "OpFNegate";
+    case 97:  return "OpNot";
+    case 98:  return "OpAny";
+    case 99:  return "OpAll";
+    case 100: return "OpConvertFToU";
+    case 101: return "OpConvertFToS";
+    case 102: return "OpConvertSToF";
+    case 103: return "OpConvertUToF";
+    case 104: return "OpUConvert";
+    case 105: return "OpSConvert";
+    case 106: return "OpFConvert";
+    case 107: return "OpConvertPtrToU";
+    case 108: return "OpConvertUToPtr";
+    case 109: return "OpPtrCastToGeneric";
+    case 110: return "OpGenericCastToPtr";
+    case 111: return "OpBitcast";
+    case 112: return "OpTranspose";
+    case 113: return "OpIsNan";
+    case 114: return "OpIsInf";
+    case 115: return "OpIsFinite";
+    case 116: return "OpIsNormal";
+    case 117: return "OpSignBitSet";
+    case 118: return "OpLessOrGreater";
+    case 119: return "OpOrdered";
+    case 120: return "OpUnordered";
+    case 121: return "OpArrayLength";
+    case 122: return "OpIAdd";
+    case 123: return "OpFAdd";
+    case 124: return "OpISub";
+    case 125: return "OpFSub";
+    case 126: return "OpIMul";
+    case 127: return "OpFMul";
+    case 128: return "OpUDiv";
+    case 129: return "OpSDiv";
+    case 130: return "OpFDiv";
+    case 131: return "OpUMod";
+    case 132: return "OpSRem";
+    case 133: return "OpSMod";
+    case 134: return "OpFRem";
+    case 135: return "OpFMod";
+    case 136: return "OpVectorTimesScalar";
+    case 137: return "OpMatrixTimesScalar";
+    case 138: return "OpVectorTimesMatrix";
+    case 139: return "OpMatrixTimesVector";
+    case 140: return "OpMatrixTimesMatrix";
+    case 141: return "OpOuterProduct";
+    case 142: return "OpDot";
+    case 143: return "OpShiftRightLogical";
+    case 144: return "OpShiftRightArithmetic";
+    case 145: return "OpShiftLeftLogical";
+    case 146: return "OpLogicalOr";
+    case 147: return "OpLogicalXor";
+    case 148: return "OpLogicalAnd";
+    case 149: return "OpBitwiseOr";
+    case 150: return "OpBitwiseXor";
+    case 151: return "OpBitwiseAnd";
+    case 152: return "OpSelect";
+    case 153: return "OpIEqual";
+    case 154: return "OpFOrdEqual";
+    case 155: return "OpFUnordEqual";
+    case 156: return "OpINotEqual";
+    case 157: return "OpFOrdNotEqual";
+    case 158: return "OpFUnordNotEqual";
+    case 159: return "OpULessThan";
+    case 160: return "OpSLessThan";
+    case 161: return "OpFOrdLessThan";
+    case 162: return "OpFUnordLessThan";
+    case 163: return "OpUGreaterThan";
+    case 164: return "OpSGreaterThan";
+    case 165: return "OpFOrdGreaterThan";
+    case 166: return "OpFUnordGreaterThan";
+    case 167: return "OpULessThanEqual";
+    case 168: return "OpSLessThanEqual";
+    case 169: return "OpFOrdLessThanEqual";
+    case 170: return "OpFUnordLessThanEqual";
+    case 171: return "OpUGreaterThanEqual";
+    case 172: return "OpSGreaterThanEqual";
+    case 173: return "OpFOrdGreaterThanEqual";
+    case 174: return "OpFUnordGreaterThanEqual";
+    case 175: return "OpDPdx";
+    case 176: return "OpDPdy";
+    case 177: return "OpFwidth";
+    case 178: return "OpDPdxFine";
+    case 179: return "OpDPdyFine";
+    case 180: return "OpFwidthFine";
+    case 181: return "OpDPdxCoarse";
+    case 182: return "OpDPdyCoarse";
+    case 183: return "OpFwidthCoarse";
+    case 184: return "OpEmitVertex";
+    case 185: return "OpEndPrimitive";
+    case 186: return "OpEmitStreamVertex";
+    case 187: return "OpEndStreamPrimitive";
+    case 188: return "OpControlBarrier";
+    case 189: return "OpMemoryBarrier";
+    case 190: return "OpImagePointer";
+    case 191: return "OpAtomicInit";
+    case 192: return "OpAtomicLoad";
+    case 193: return "OpAtomicStore";
+    case 194: return "OpAtomicExchange";
+    case 195: return "OpAtomicCompareExchange";
+    case 196: return "OpAtomicCompareExchangeWeak";
+    case 197: return "OpAtomicIIncrement";
+    case 198: return "OpAtomicIDecrement";
+    case 199: return "OpAtomicIAdd";
+    case 200: return "OpAtomicISub";
+    case 201: return "OpAtomicUMin";
+    case 202: return "OpAtomicUMax";
+    case 203: return "OpAtomicAnd";
+    case 204: return "OpAtomicOr";
+    case 205: return "OpAtomicXor";
+    case 206: return "OpLoopMerge";
+    case 207: return "OpSelectionMerge";
+    case 208: return "OpLabel";
+    case 209: return "OpBranch";
+    case 210: return "OpBranchConditional";
+    case 211: return "OpSwitch";
+    case 212: return "OpKill";
+    case 213: return "OpReturn";
+    case 214: return "OpReturnValue";
+    case 215: return "OpUnreachable";
+    case 216: return "OpLifetimeStart";
+    case 217: return "OpLifetimeStop";
+    case 218: return "OpCompileFlag";
+    case 219: return "OpAsyncGroupCopy";
+    case 220: return "OpWaitGroupEvents";
+    case 221: return "OpGroupAll";
+    case 222: return "OpGroupAny";
+    case 223: return "OpGroupBroadcast";
+    case 224: return "OpGroupIAdd";
+    case 225: return "OpGroupFAdd";
+    case 226: return "OpGroupFMin";
+    case 227: return "OpGroupUMin";
+    case 228: return "OpGroupSMin";
+    case 229: return "OpGroupFMax";
+    case 230: return "OpGroupUMax";
+    case 231: return "OpGroupSMax";
+    case 232: return "OpGenericCastToPtrExplicit";
+    case 233: return "OpGenericPtrMemSemantics";
+    case 234: return "OpReadPipe";
+    case 235: return "OpWritePipe";
+    case 236: return "OpReservedReadPipe";
+    case 237: return "OpReservedWritePipe";
+    case 238: return "OpReserveReadPipePackets";
+    case 239: return "OpReserveWritePipePackets";
+    case 240: return "OpCommitReadPipe";
+    case 241: return "OpCommitWritePipe";
+    case 242: return "OpIsValidReserveId";
+    case 243: return "OpGetNumPipePackets";
+    case 244: return "OpGetMaxPipePackets";
+    case 245: return "OpGroupReserveReadPipePackets";
+    case 246: return "OpGroupReserveWritePipePackets";
+    case 247: return "OpGroupCommitReadPipe";
+    case 248: return "OpGroupCommitWritePipe";
+    case 249: return "OpEnqueueMarker";
+    case 250: return "OpEnqueueKernel";
+    case 251: return "OpGetKernelNDrangeSubGroupCount";
+    case 252: return "OpGetKernelNDrangeMaxSubGroupSize";
+    case 253: return "OpGetKernelWorkGroupSize";
+    case 254: return "OpGetKernelPreferredWorkGroupSizeMultiple";
+    case 255: return "OpRetainEvent";
+    case 256: return "OpReleaseEvent";
+    case 257: return "OpCreateUserEvent";
+    case 258: return "OpIsValidEvent";
+    case 259: return "OpSetUserEventStatus";
+    case 260: return "OpCaptureEventProfilingInfo";
+    case 261: return "OpGetDefaultQueue";
+    case 262: return "OpBuildNDRange";
+    case 263: return "OpSatConvertSToU";
+    case 264: return "OpSatConvertUToS";
+    case 265: return "OpAtomicIMin";
+    case 266: return "OpAtomicIMax";
+
+    case OpcodeCeiling:
+    default:
+        return "Bad";
+    }
+}
+
+// The set of objects that hold all the instruction/operand
+// parameterization information.
+InstructionParameters InstructionDesc[OpcodeCeiling];
+OperandParameters ExecutionModeOperands[ExecutionModeCeiling];
+OperandParameters DecorationOperands[DecorationCeiling];
+
+EnumDefinition OperandClassParams[OperandCount];
+EnumParameters ExecutionModelParams[ExecutionModelCeiling];
+EnumParameters AddressingParams[AddressingModelCeiling];
+EnumParameters MemoryParams[MemoryModelCeiling];
+EnumParameters ExecutionModeParams[ExecutionModeCeiling];
+EnumParameters StorageParams[StorageClassCeiling];
+EnumParameters SamplerAddressingModeParams[SamplerAddressingModeCeiling];
+EnumParameters SamplerFilterModeParams[SamplerFilterModeCeiling];
+EnumParameters FPFastMathParams[FPFastMathCeiling];
+EnumParameters FPRoundingModeParams[FPRoundingModeCeiling];
+EnumParameters LinkageTypeParams[LinkageTypeCeiling];
+EnumParameters DecorationParams[DecorationCeiling];
+EnumParameters BuiltInParams[BuiltInCeiling];
+EnumParameters DimensionalityParams[DimensionCeiling];
+EnumParameters FuncParamAttrParams[FuncParamAttrCeiling];
+EnumParameters AccessQualifierParams[AccessQualifierCeiling];
+EnumParameters GroupOperationParams[GroupOperationCeiling];
+EnumParameters LoopControlParams[FunctionControlCeiling];
+EnumParameters SelectionControlParams[SelectControlCeiling];
+EnumParameters FunctionControlParams[FunctionControlCeiling];
+EnumParameters MemorySemanticsParams[MemorySemanticsCeiling];
+EnumParameters MemoryAccessParams[MemoryAccessCeiling];
+EnumParameters ExecutionScopeParams[ExecutionScopeCeiling];
+EnumParameters KernelEnqueueFlagsParams[KernelEnqueueFlagsCeiling];
+EnumParameters KernelProfilingInfoParams[KernelProfilingInfoCeiling];
+
+// Set up all the parameterizing descriptions of the opcodes, operands, etc.
+void Parameterize()
+{
+    static bool initialized = false;
+
+    // only do this once.
+    if (initialized)
+        return;
+
+    initialized = true;
+
+    // Exceptions to having a result <id> and a resulting type <id>.
+    // (Everything is initialized to have both).
+
+    InstructionDesc[OpNop].setResultAndType(false, false);
+    InstructionDesc[OpSource].setResultAndType(false, false);
+    InstructionDesc[OpSourceExtension].setResultAndType(false, false);
+    InstructionDesc[OpExtension].setResultAndType(false, false);
+    InstructionDesc[OpExtInstImport].setResultAndType(true, false);
+    InstructionDesc[OpMemoryModel].setResultAndType(false, false);
+    InstructionDesc[OpEntryPoint].setResultAndType(false, false);
+    InstructionDesc[OpExecutionMode].setResultAndType(false, false);
+    InstructionDesc[OpTypeVoid].setResultAndType(true, false);
+    InstructionDesc[OpTypeBool].setResultAndType(true, false);
+    InstructionDesc[OpTypeInt].setResultAndType(true, false);
+    InstructionDesc[OpTypeFloat].setResultAndType(true, false);
+    InstructionDesc[OpTypeVector].setResultAndType(true, false);
+    InstructionDesc[OpTypeMatrix].setResultAndType(true, false);
+    InstructionDesc[OpTypeSampler].setResultAndType(true, false);
+    InstructionDesc[OpTypeFilter].setResultAndType(true, false);
+    InstructionDesc[OpTypeArray].setResultAndType(true, false);
+    InstructionDesc[OpTypeRuntimeArray].setResultAndType(true, false);
+    InstructionDesc[OpTypeStruct].setResultAndType(true, false);
+    InstructionDesc[OpTypeOpaque].setResultAndType(true, false);
+    InstructionDesc[OpTypePointer].setResultAndType(true, false);
+    InstructionDesc[OpTypeFunction].setResultAndType(true, false);
+    InstructionDesc[OpTypeEvent].setResultAndType(true, false);
+    InstructionDesc[OpTypeDeviceEvent].setResultAndType(true, false);
+    InstructionDesc[OpTypeReserveId].setResultAndType(true, false);
+    InstructionDesc[OpTypeQueue].setResultAndType(true, false);
+    InstructionDesc[OpTypePipe].setResultAndType(true, false);
+    InstructionDesc[OpFunctionEnd].setResultAndType(false, false);
+    InstructionDesc[OpStore].setResultAndType(false, false);
+    InstructionDesc[OpDecorationGroup].setResultAndType(true, false);
+    InstructionDesc[OpDecorate].setResultAndType(false, false);
+    InstructionDesc[OpMemberDecorate].setResultAndType(false, false);
+    InstructionDesc[OpGroupDecorate].setResultAndType(false, false);
+    InstructionDesc[OpGroupMemberDecorate].setResultAndType(false, false);
+    InstructionDesc[OpName].setResultAndType(false, false);
+    InstructionDesc[OpMemberName].setResultAndType(false, false);
+    InstructionDesc[OpString].setResultAndType(true, false);
+    InstructionDesc[OpLine].setResultAndType(false, false);
+    InstructionDesc[OpCopyMemory].setResultAndType(false, false);
+    InstructionDesc[OpCopyMemorySized].setResultAndType(false, false);
+    InstructionDesc[OpEmitVertex].setResultAndType(false, false);
+    InstructionDesc[OpEndPrimitive].setResultAndType(false, false);
+    InstructionDesc[OpEmitStreamVertex].setResultAndType(false, false);
+    InstructionDesc[OpEndStreamPrimitive].setResultAndType(false, false);
+    InstructionDesc[OpControlBarrier].setResultAndType(false, false);
+    InstructionDesc[OpMemoryBarrier].setResultAndType(false, false);
+    InstructionDesc[OpAtomicInit].setResultAndType(false, false);
+    InstructionDesc[OpAtomicStore].setResultAndType(false, false);
+    InstructionDesc[OpLoopMerge].setResultAndType(false, false);
+    InstructionDesc[OpSelectionMerge].setResultAndType(false, false);
+    InstructionDesc[OpLabel].setResultAndType(true, false);
+    InstructionDesc[OpBranch].setResultAndType(false, false);
+    InstructionDesc[OpBranchConditional].setResultAndType(false, false);
+    InstructionDesc[OpSwitch].setResultAndType(false, false);
+    InstructionDesc[OpKill].setResultAndType(false, false);
+    InstructionDesc[OpReturn].setResultAndType(false, false);
+    InstructionDesc[OpReturnValue].setResultAndType(false, false);
+    InstructionDesc[OpUnreachable].setResultAndType(false, false);
+    InstructionDesc[OpLifetimeStart].setResultAndType(false, false);
+    InstructionDesc[OpLifetimeStop].setResultAndType(false, false);
+    InstructionDesc[OpCompileFlag].setResultAndType(false, false);
+    InstructionDesc[OpCommitReadPipe].setResultAndType(false, false);
+    InstructionDesc[OpCommitWritePipe].setResultAndType(false, false);
+    InstructionDesc[OpGroupCommitWritePipe].setResultAndType(false, false);
+    InstructionDesc[OpGroupCommitReadPipe].setResultAndType(false, false);
+    InstructionDesc[OpCaptureEventProfilingInfo].setResultAndType(false, false);
+    InstructionDesc[OpSetUserEventStatus].setResultAndType(false, false);
+    InstructionDesc[OpRetainEvent].setResultAndType(false, false);
+    InstructionDesc[OpReleaseEvent].setResultAndType(false, false);
+
+    // Specific additional context-dependent operands
+
+    ExecutionModeOperands[ExecutionModeInvocations].push(OperandLiteralNumber, "Number of invocations");
+
+    ExecutionModeOperands[ExecutionModeLocalSize].push(OperandLiteralNumber, "'x size'");
+    ExecutionModeOperands[ExecutionModeLocalSize].push(OperandLiteralNumber, "'y size'");
+    ExecutionModeOperands[ExecutionModeLocalSize].push(OperandLiteralNumber, "'z size'");
+
+    ExecutionModeOperands[ExecutionModeLocalSizeHint].push(OperandLiteralNumber, "'x size'");
+    ExecutionModeOperands[ExecutionModeLocalSizeHint].push(OperandLiteralNumber, "'y size'");
+    ExecutionModeOperands[ExecutionModeLocalSizeHint].push(OperandLiteralNumber, "'z size'");
+
+    ExecutionModeOperands[ExecutionModeOutputVertices].push(OperandLiteralNumber, "Vertex count");
+    ExecutionModeOperands[ExecutionModeVecTypeHint].push(OperandId, "Vector type");
+
+    DecorationOperands[DecorationStream].push(OperandLiteralNumber, "Stream number");
+    DecorationOperands[DecorationLocation].push(OperandLiteralNumber, "Location");
+    DecorationOperands[DecorationComponent].push(OperandLiteralNumber, "Component within a vector");
+    DecorationOperands[DecorationIndex].push(OperandLiteralNumber, "Index");
+    DecorationOperands[DecorationBinding].push(OperandLiteralNumber, "Binding point");
+    DecorationOperands[DecorationDescriptorSet].push(OperandLiteralNumber, "Descriptor set");
+    DecorationOperands[DecorationOffset].push(OperandLiteralNumber, "Byte offset");
+    DecorationOperands[DecorationAlignment].push(OperandLiteralNumber, "Declared alignment");
+    DecorationOperands[DecorationXfbBuffer].push(OperandLiteralNumber, "XFB Buffer number");
+    DecorationOperands[DecorationStride].push(OperandLiteralNumber, "Stride");
+    DecorationOperands[DecorationBuiltIn].push(OperandLiteralNumber, "See <<BuiltIn,*BuiltIn*>>");
+    DecorationOperands[DecorationFPRoundingMode].push(OperandFPRoundingMode, "floating-point rounding mode");
+    DecorationOperands[DecorationFPFastMathMode].push(OperandFPFastMath, "fast-math mode");
+    DecorationOperands[DecorationLinkageAttributes].push(OperandLiteralString, "name");
+    DecorationOperands[DecorationLinkageAttributes].push(OperandLinkageType, "linkage type");
+    DecorationOperands[DecorationFuncParamAttr].push(OperandFuncParamAttr, "function parameter attribute");
+    DecorationOperands[DecorationSpecId].push(OperandLiteralNumber, "Specialization Constant ID");
+
+    OperandClassParams[OperandSource].set(SourceLanguageCeiling, SourceString, 0);
+    OperandClassParams[OperandExecutionModel].set(ExecutionModelCeiling, ExecutionModelString, ExecutionModelParams);
+    OperandClassParams[OperandAddressing].set(AddressingModelCeiling, AddressingString, AddressingParams);
+    OperandClassParams[OperandMemory].set(MemoryModelCeiling, MemoryString, MemoryParams);
+    OperandClassParams[OperandExecutionMode].set(ExecutionModeCeiling, ExecutionModeString, ExecutionModeParams);
+    OperandClassParams[OperandExecutionMode].setOperands(ExecutionModeOperands);
+    OperandClassParams[OperandStorage].set(StorageClassCeiling, StorageClassString, StorageParams);
+    OperandClassParams[OperandDimensionality].set(DimensionCeiling, DimensionString, DimensionalityParams);
+    OperandClassParams[OperandSamplerAddressingMode].set(SamplerAddressingModeCeiling, SamplerAddressingModeString, SamplerAddressingModeParams);
+    OperandClassParams[OperandSamplerFilterMode].set(SamplerFilterModeCeiling, SamplerFilterModeString, SamplerFilterModeParams);
+    OperandClassParams[OperandFPFastMath].set(FPFastMathCeiling, FPFastMathString, FPFastMathParams, true);
+    OperandClassParams[OperandFPRoundingMode].set(FPRoundingModeCeiling, FPRoundingModeString, FPRoundingModeParams);
+    OperandClassParams[OperandLinkageType].set(LinkageTypeCeiling, LinkageTypeString, LinkageTypeParams);
+    OperandClassParams[OperandFuncParamAttr].set(FuncParamAttrCeiling, FuncParamAttrString, FuncParamAttrParams);
+    OperandClassParams[OperandAccessQualifier].set(AccessQualifierCeiling, AccessQualifierString, AccessQualifierParams);
+    OperandClassParams[OperandDecoration].set(DecorationCeiling, DecorationString, DecorationParams);
+    OperandClassParams[OperandDecoration].setOperands(DecorationOperands);
+    OperandClassParams[OperandBuiltIn].set(BuiltInCeiling, BuiltInString, BuiltInParams);
+    OperandClassParams[OperandSelect].set(SelectControlCeiling, SelectControlString, SelectionControlParams, true);
+    OperandClassParams[OperandLoop].set(LoopControlCeiling, LoopControlString, LoopControlParams, true);
+    OperandClassParams[OperandFunction].set(FunctionControlCeiling, FunctionControlString, FunctionControlParams, true);
+    OperandClassParams[OperandMemorySemantics].set(MemorySemanticsCeiling, MemorySemanticsString, MemorySemanticsParams, true);
+    OperandClassParams[OperandMemoryAccess].set(MemoryAccessCeiling, MemoryAccessString, MemoryAccessParams, true);
+    OperandClassParams[OperandExecutionScope].set(ExecutionScopeCeiling, ExecutionScopeString, ExecutionScopeParams);
+    OperandClassParams[OperandGroupOperation].set(GroupOperationCeiling, GroupOperationString, GroupOperationParams);
+    OperandClassParams[OperandKernelEnqueueFlags].set(KernelEnqueueFlagsCeiling, KernelEnqueueFlagsString, KernelEnqueueFlagsParams);
+    OperandClassParams[OperandKernelProfilingInfo].set(KernelProfilingInfoCeiling, KernelProfilingInfoString, KernelProfilingInfoParams, true);
+    OperandClassParams[OperandOpcode].set(OpcodeCeiling, OpcodeString, 0);
+
+    AddressingParams[AddressingModelPhysical32].caps.push_back(CapAddr);
+    AddressingParams[AddressingModelPhysical64].caps.push_back(CapAddr);
+
+    MemoryParams[MemoryModelSimple].caps.push_back(CapShader);
+    MemoryParams[MemoryModelGLSL450].caps.push_back(CapShader);
+    MemoryParams[MemoryModelOpenCL12].caps.push_back(CapKernel);
+    MemoryParams[MemoryModelOpenCL20].caps.push_back(CapKernel);
+    MemoryParams[MemoryModelOpenCL21].caps.push_back(CapKernel);
+
+    ExecutionModelParams[ExecutionModelVertex].caps.push_back(CapShader);
+    ExecutionModelParams[ExecutionModelTessellationControl].caps.push_back(CapTess);
+    ExecutionModelParams[ExecutionModelTessellationEvaluation].caps.push_back(CapTess);
+    ExecutionModelParams[ExecutionModelGeometry].caps.push_back(CapGeom);
+    ExecutionModelParams[ExecutionModelFragment].caps.push_back(CapShader);
+    ExecutionModelParams[ExecutionModelGLCompute].caps.push_back(CapShader);
+    ExecutionModelParams[ExecutionModelKernel].caps.push_back(CapKernel);
+
+    // Storage capabilites
+    StorageParams[StorageClassInput].caps.push_back(CapShader);
+    StorageParams[StorageClassUniform].caps.push_back(CapShader);
+    StorageParams[StorageClassOutput].caps.push_back(CapShader);
+    StorageParams[StorageClassPrivateGlobal].caps.push_back(CapShader);
+    StorageParams[StorageClassFunction].caps.push_back(CapShader);
+    StorageParams[StorageClassGeneric].caps.push_back(CapKernel);
+    StorageParams[StorageClassPrivate].caps.push_back(CapKernel);
+    StorageParams[StorageClassAtomicCounter].caps.push_back(CapShader);
+
+    // Sampler Filter & Addressing mode capabilities
+    SamplerAddressingModeParams[SamplerAddressingModeNone].caps.push_back(CapKernel);
+    SamplerAddressingModeParams[SamplerAddressingModeClampToEdge].caps.push_back(CapKernel);
+    SamplerAddressingModeParams[SamplerAddressingModeClamp].caps.push_back(CapKernel);
+    SamplerAddressingModeParams[SamplerAddressingModeRepeat].caps.push_back(CapKernel);
+    SamplerAddressingModeParams[SamplerAddressingModeRepeatMirrored].caps.push_back(CapKernel);
+
+    SamplerFilterModeParams[SamplerFilterModeNearest].caps.push_back(CapKernel);
+    SamplerFilterModeParams[SamplerFilterModeLinear].caps.push_back(CapKernel);
+
+    // fast math flags capabilities
+    for (int i = 0; i < FPFastMathCeiling; ++i) {
+        FPFastMathParams[i].caps.push_back(CapKernel);
+    }
+
+    // fp rounding mode capabilities
+    for (int i = 0; i < FPRoundingModeCeiling; ++i) {
+        FPRoundingModeParams[i].caps.push_back(CapKernel);
+    }
+
+    // linkage types
+    for (int i = 0; i < LinkageTypeCeiling; ++i) {
+        LinkageTypeParams[i].caps.push_back(CapLink);
+    }
+
+    // function argument types
+    for (int i = 0; i < FuncParamAttrCeiling; ++i) {
+        FuncParamAttrParams[i].caps.push_back(CapKernel);
+    }
+
+    // function argument types
+    for (int i = 0; i < AccessQualifierCeiling; ++i) {
+        AccessQualifierParams[i].caps.push_back(CapKernel);
+    }
+
+    ExecutionModeParams[ExecutionModeInvocations].caps.push_back(CapGeom);
+    ExecutionModeParams[ExecutionModeSpacingEqual].caps.push_back(CapTess);
+    ExecutionModeParams[ExecutionModeSpacingFractionalEven].caps.push_back(CapTess);
+    ExecutionModeParams[ExecutionModeSpacingFractionalOdd].caps.push_back(CapTess);
+    ExecutionModeParams[ExecutionModeVertexOrderCw].caps.push_back(CapTess);
+    ExecutionModeParams[ExecutionModeVertexOrderCcw].caps.push_back(CapTess);
+    ExecutionModeParams[ExecutionModePixelCenterInteger].caps.push_back(CapShader);
+    ExecutionModeParams[ExecutionModeOriginUpperLeft].caps.push_back(CapShader);
+    ExecutionModeParams[ExecutionModeEarlyFragmentTests].caps.push_back(CapShader);
+    ExecutionModeParams[ExecutionModePointMode].caps.push_back(CapTess);
+    ExecutionModeParams[ExecutionModeXfb].caps.push_back(CapShader);
+    ExecutionModeParams[ExecutionModeDepthReplacing].caps.push_back(CapShader);
+    ExecutionModeParams[ExecutionModeDepthAny].caps.push_back(CapShader);
+    ExecutionModeParams[ExecutionModeDepthGreater].caps.push_back(CapShader);
+    ExecutionModeParams[ExecutionModeDepthLess].caps.push_back(CapShader);
+    ExecutionModeParams[ExecutionModeDepthUnchanged].caps.push_back(CapShader);
+    ExecutionModeParams[ExecutionModeLocalSizeHint].caps.push_back(CapKernel);
+    ExecutionModeParams[ExecutionModeInputPoints].caps.push_back(CapGeom);
+    ExecutionModeParams[ExecutionModeInputLines].caps.push_back(CapGeom);
+    ExecutionModeParams[ExecutionModeInputLinesAdjacency].caps.push_back(CapGeom);
+    ExecutionModeParams[ExecutionModeInputTriangles].caps.push_back(CapGeom);
+    ExecutionModeParams[ExecutionModeInputTriangles].caps.push_back(CapTess);
+    ExecutionModeParams[ExecutionModeInputTrianglesAdjacency].caps.push_back(CapGeom);
+    ExecutionModeParams[ExecutionModeInputQuads].caps.push_back(CapTess);
+    ExecutionModeParams[ExecutionModeInputIsolines].caps.push_back(CapTess);
+    ExecutionModeParams[ExecutionModeOutputVertices].caps.push_back(CapGeom);
+    ExecutionModeParams[ExecutionModeOutputVertices].caps.push_back(CapTess);
+    ExecutionModeParams[ExecutionModeOutputPoints].caps.push_back(CapGeom);
+    ExecutionModeParams[ExecutionModeOutputLineStrip].caps.push_back(CapGeom);
+    ExecutionModeParams[ExecutionModeOutputTriangleStrip].caps.push_back(CapGeom);
+    ExecutionModeParams[ExecutionModeVecTypeHint].caps.push_back(CapKernel);
+    ExecutionModeParams[ExecutionModeContractionOff].caps.push_back(CapKernel);
+
+    DecorationParams[DecorationPrecisionLow].caps.push_back(CapShader);
+    DecorationParams[DecorationPrecisionMedium].caps.push_back(CapShader);
+    DecorationParams[DecorationPrecisionHigh].caps.push_back(CapShader);
+    DecorationParams[DecorationBlock].caps.push_back(CapShader);
+    DecorationParams[DecorationBufferBlock].caps.push_back(CapShader);
+    DecorationParams[DecorationRowMajor].caps.push_back(CapMatrix);
+    DecorationParams[DecorationColMajor].caps.push_back(CapMatrix);
+    DecorationParams[DecorationGLSLShared].caps.push_back(CapShader);
+    DecorationParams[DecorationGLSLStd140].caps.push_back(CapShader);
+    DecorationParams[DecorationGLSLStd430].caps.push_back(CapShader);
+    DecorationParams[DecorationGLSLPacked].caps.push_back(CapShader);
+    DecorationParams[DecorationSmooth].caps.push_back(CapShader);
+    DecorationParams[DecorationNoperspective].caps.push_back(CapShader);
+    DecorationParams[DecorationFlat].caps.push_back(CapShader);
+    DecorationParams[DecorationPatch].caps.push_back(CapTess);
+    DecorationParams[DecorationCentroid].caps.push_back(CapShader);
+    DecorationParams[DecorationSample].caps.push_back(CapShader);
+    DecorationParams[DecorationInvariant].caps.push_back(CapShader);
+    DecorationParams[DecorationConstant].caps.push_back(CapKernel);
+    DecorationParams[DecorationUniform].caps.push_back(CapShader);
+    DecorationParams[DecorationCPacked].caps.push_back(CapKernel);
+    DecorationParams[DecorationSaturatedConversion].caps.push_back(CapKernel);
+    DecorationParams[DecorationStream].caps.push_back(CapGeom);
+    DecorationParams[DecorationLocation].caps.push_back(CapShader);
+    DecorationParams[DecorationComponent].caps.push_back(CapShader);
+    DecorationParams[DecorationIndex].caps.push_back(CapShader);
+    DecorationParams[DecorationBinding].caps.push_back(CapShader);
+    DecorationParams[DecorationDescriptorSet].caps.push_back(CapShader);
+    DecorationParams[DecorationXfbBuffer].caps.push_back(CapShader);
+    DecorationParams[DecorationStride].caps.push_back(CapShader);
+    DecorationParams[DecorationBuiltIn].caps.push_back(CapShader);
+    DecorationParams[DecorationFuncParamAttr].caps.push_back(CapKernel);
+    DecorationParams[DecorationFPRoundingMode].caps.push_back(CapKernel);
+    DecorationParams[DecorationFPFastMathMode].caps.push_back(CapKernel);
+    DecorationParams[DecorationLinkageAttributes].caps.push_back(CapLink);
+    DecorationParams[DecorationSpecId].caps.push_back(CapShader);
+
+    BuiltInParams[BuiltInPosition].caps.push_back(CapShader);
+    BuiltInParams[BuiltInPointSize].caps.push_back(CapShader);
+    BuiltInParams[BuiltInClipVertex].caps.push_back(CapShader);
+    BuiltInParams[BuiltInClipDistance].caps.push_back(CapShader);
+    BuiltInParams[BuiltInCullDistance].caps.push_back(CapShader);
+    BuiltInParams[BuiltInVertexId].caps.push_back(CapShader);
+    BuiltInParams[BuiltInInstanceId].caps.push_back(CapShader);
+    BuiltInParams[BuiltInPrimitiveId].caps.push_back(CapGeom);
+    BuiltInParams[BuiltInPrimitiveId].caps.push_back(CapTess);
+    BuiltInParams[BuiltInInvocationId].caps.push_back(CapGeom);
+    BuiltInParams[BuiltInInvocationId].caps.push_back(CapTess);
+    BuiltInParams[BuiltInLayer].caps.push_back(CapGeom);
+    BuiltInParams[BuiltInViewportIndex].caps.push_back(CapGeom);
+    BuiltInParams[BuiltInTessLevelOuter].caps.push_back(CapTess);
+    BuiltInParams[BuiltInTessLevelInner].caps.push_back(CapTess);
+    BuiltInParams[BuiltInTessCoord].caps.push_back(CapTess);
+    BuiltInParams[BuiltInPatchVertices].caps.push_back(CapTess);
+    BuiltInParams[BuiltInFragCoord].caps.push_back(CapShader);
+    BuiltInParams[BuiltInPointCoord].caps.push_back(CapShader);
+    BuiltInParams[BuiltInFrontFacing].caps.push_back(CapShader);
+    BuiltInParams[BuiltInSampleId].caps.push_back(CapShader);
+    BuiltInParams[BuiltInSamplePosition].caps.push_back(CapShader);
+    BuiltInParams[BuiltInSampleMask].caps.push_back(CapShader);
+    BuiltInParams[BuiltInFragColor].caps.push_back(CapShader);
+    BuiltInParams[BuiltInFragDepth].caps.push_back(CapShader);
+    BuiltInParams[BuiltInHelperInvocation].caps.push_back(CapShader);
+    BuiltInParams[BuiltInLocalInvocationIndex].caps.push_back(CapShader);
+    BuiltInParams[BuiltInWorkDim].caps.push_back(CapKernel);
+    BuiltInParams[BuiltInGlobalSize].caps.push_back(CapKernel);
+    BuiltInParams[BuiltInEnqueuedWorkgroupSize].caps.push_back(CapKernel);
+    BuiltInParams[BuiltInGlobalOffset].caps.push_back(CapKernel);
+    BuiltInParams[BuiltInGlobalLinearId].caps.push_back(CapKernel);
+    BuiltInParams[BuiltInWorkgroupLinearId].caps.push_back(CapKernel);
+
+    BuiltInParams[BuiltInSubgroupSize].caps.push_back(CapKernel);
+    BuiltInParams[BuiltInSubgroupMaxSize].caps.push_back(CapKernel);
+    BuiltInParams[BuiltInNumSubgroups].caps.push_back(CapKernel);
+    BuiltInParams[BuiltInNumEnqueuedSubgroups].caps.push_back(CapKernel);
+    BuiltInParams[BuiltInSubgroupId].caps.push_back(CapKernel);
+    BuiltInParams[BuiltInSubgroupLocalInvocationId].caps.push_back(CapKernel);
+
+    DimensionalityParams[DimCube].caps.push_back(CapShader);
+    DimensionalityParams[DimRect].caps.push_back(CapShader);
+
+    // Group Operations
+    for (int i = 0; i < GroupOperationCeiling; ++i) {
+        GroupOperationParams[i].caps.push_back(CapKernel);
+    }
+
+    // Enqueue flags
+    for (int i = 0; i < KernelEnqueueFlagsCeiling; ++i) {
+        KernelEnqueueFlagsParams[i].caps.push_back(CapKernel);
+    }
+
+    // Profiling info
+    KernelProfilingInfoParams[0].caps.push_back(CapKernel);
+
+    // set name of operator, an initial set of <id> style operands, and the description
+
+    InstructionDesc[OpSource].operands.push(OperandSource, "");
+    InstructionDesc[OpSource].operands.push(OperandLiteralNumber, "'Version'");
+
+    InstructionDesc[OpSourceExtension].operands.push(OperandLiteralString, "'Extension'");
+
+    InstructionDesc[OpName].operands.push(OperandId, "'Target'");
+    InstructionDesc[OpName].operands.push(OperandLiteralString, "'Name'");
+
+    InstructionDesc[OpMemberName].operands.push(OperandId, "'Type'");
+    InstructionDesc[OpMemberName].operands.push(OperandLiteralNumber, "'Member'");
+    InstructionDesc[OpMemberName].operands.push(OperandLiteralString, "'Name'");
+
+    InstructionDesc[OpString].operands.push(OperandLiteralString, "'String'");
+
+    InstructionDesc[OpLine].operands.push(OperandId, "'Target'");
+    InstructionDesc[OpLine].operands.push(OperandId, "'File'");
+    InstructionDesc[OpLine].operands.push(OperandLiteralNumber, "'Line'");
+    InstructionDesc[OpLine].operands.push(OperandLiteralNumber, "'Column'");
+
+    InstructionDesc[OpExtension].operands.push(OperandLiteralString, "'Name'");
+
+    InstructionDesc[OpExtInstImport].operands.push(OperandLiteralString, "'Name'");
+
+    InstructionDesc[OpMemoryModel].operands.push(OperandAddressing, "");
+    InstructionDesc[OpMemoryModel].operands.push(OperandMemory, "");
+
+    InstructionDesc[OpEntryPoint].operands.push(OperandExecutionModel, "");
+    InstructionDesc[OpEntryPoint].operands.push(OperandId, "'Entry Point'");
+
+    InstructionDesc[OpExecutionMode].operands.push(OperandId, "'Entry Point'");
+    InstructionDesc[OpExecutionMode].operands.push(OperandExecutionMode, "'Mode'");
+    InstructionDesc[OpExecutionMode].operands.push(OperandVariableLiterals, "See <<Execution Mode,Execution Mode>>");
+
+    InstructionDesc[OpTypeInt].operands.push(OperandLiteralNumber, "'Width'");
+    InstructionDesc[OpTypeInt].operands.push(OperandLiteralNumber, "'Signedness'");
+
+    InstructionDesc[OpTypeFloat].operands.push(OperandLiteralNumber, "'Width'");
+
+    InstructionDesc[OpTypeVector].operands.push(OperandId, "'Component type'");
+    InstructionDesc[OpTypeVector].operands.push(OperandLiteralNumber, "'Component count'");
+
+    InstructionDesc[OpTypeMatrix].capabilities.push_back(CapMatrix);
+    InstructionDesc[OpTypeMatrix].operands.push(OperandId, "'Column type'");
+    InstructionDesc[OpTypeMatrix].operands.push(OperandLiteralNumber, "'Column count'");
+
+    InstructionDesc[OpTypeSampler].operands.push(OperandId, "'Sampled Type'");
+    InstructionDesc[OpTypeSampler].operands.push(OperandDimensionality, "");
+    InstructionDesc[OpTypeSampler].operands.push(OperandLiteralNumber, "'Content'");
+    InstructionDesc[OpTypeSampler].operands.push(OperandLiteralNumber, "'Arrayed'");
+    InstructionDesc[OpTypeSampler].operands.push(OperandLiteralNumber, "'Compare'");
+    InstructionDesc[OpTypeSampler].operands.push(OperandLiteralNumber, "'MS'");
+    InstructionDesc[OpTypeSampler].operands.push(OperandOptionalId, "'Qualifier'");
+
+    InstructionDesc[OpTypeArray].operands.push(OperandId, "'Element type'");
+    InstructionDesc[OpTypeArray].operands.push(OperandId, "'Length'");
+
+    InstructionDesc[OpTypeRuntimeArray].capabilities.push_back(CapShader);
+    InstructionDesc[OpTypeRuntimeArray].operands.push(OperandId, "'Element type'");
+
+    InstructionDesc[OpTypeStruct].operands.push(OperandVariableIds, "'Member 0 type', +\n'member 1 type', +\n...");
+
+    InstructionDesc[OpTypeOpaque].capabilities.push_back(CapKernel);
+    InstructionDesc[OpTypeOpaque].operands.push(OperandLiteralString, "The name of the opaque type.");
+
+    InstructionDesc[OpTypePointer].operands.push(OperandStorage, "");
+    InstructionDesc[OpTypePointer].operands.push(OperandId, "'Type'");
+
+    InstructionDesc[OpTypeEvent].capabilities.push_back(CapKernel);
+
+    InstructionDesc[OpTypeDeviceEvent].capabilities.push_back(CapKernel);
+
+    InstructionDesc[OpTypeReserveId].capabilities.push_back(CapKernel);
+
+    InstructionDesc[OpTypeQueue].capabilities.push_back(CapKernel);
+
+    InstructionDesc[OpTypePipe].operands.push(OperandId, "'Type'");
+    InstructionDesc[OpTypePipe].operands.push(OperandAccessQualifier, "'Qualifier'");
+    InstructionDesc[OpTypePipe].capabilities.push_back(CapKernel);
+
+    InstructionDesc[OpTypeFunction].operands.push(OperandId, "'Return Type'");
+    InstructionDesc[OpTypeFunction].operands.push(OperandVariableIds, "'Parameter 0 Type', +\n'Parameter 1 Type', +\n...");
+
+    InstructionDesc[OpConstant].operands.push(OperandVariableLiterals, "'Value'");
+
+    InstructionDesc[OpConstantComposite].operands.push(OperandVariableIds, "'Constituents'");
+
+    InstructionDesc[OpConstantNullPointer].capabilities.push_back(CapAddr);
+
+    InstructionDesc[OpConstantNullObject].capabilities.push_back(CapKernel);
+
+    InstructionDesc[OpConstantSampler].capabilities.push_back(CapKernel);
+    InstructionDesc[OpConstantSampler].operands.push(OperandLiteralNumber, "'Mode'");
+    InstructionDesc[OpConstantSampler].operands.push(OperandLiteralNumber, "'Param'");
+    InstructionDesc[OpConstantSampler].operands.push(OperandLiteralNumber, "'Filter'");
+
+    InstructionDesc[OpSpecConstantTrue].capabilities.push_back(CapShader);
+
+    InstructionDesc[OpSpecConstantFalse].capabilities.push_back(CapShader);
+
+    InstructionDesc[OpSpecConstant].operands.push(OperandVariableLiterals, "'Value'");
+    InstructionDesc[OpSpecConstant].capabilities.push_back(CapShader);
+
+    InstructionDesc[OpSpecConstantComposite].operands.push(OperandVariableIds, "'Constituents'");
+    InstructionDesc[OpSpecConstantComposite].capabilities.push_back(CapShader);
+
+    InstructionDesc[OpVariable].operands.push(OperandStorage, "");
+    InstructionDesc[OpVariable].operands.push(OperandOptionalId, "'Initializer'");
+
+    InstructionDesc[OpVariableArray].operands.push(OperandStorage, "");
+    InstructionDesc[OpVariableArray].operands.push(OperandId, "'N'");
+    InstructionDesc[OpVariableArray].capabilities.push_back(CapAddr);
+
+    InstructionDesc[OpFunction].operands.push(OperandFunction, "");
+    InstructionDesc[OpFunction].operands.push(OperandId, "'Function Type'");
+
+    InstructionDesc[OpFunctionCall].operands.push(OperandId, "'Function'");
+    InstructionDesc[OpFunctionCall].operands.push(OperandVariableIds, "'Argument 0', +\n'Argument 1', +\n...");
+
+    InstructionDesc[OpExtInst].operands.push(OperandId, "'Set'");
+    InstructionDesc[OpExtInst].operands.push(OperandLiteralNumber, "'Instruction'");
+    InstructionDesc[OpExtInst].operands.push(OperandVariableIds, "'Operand 1', +\n'Operand 2', +\n...");
+
+    InstructionDesc[OpLoad].operands.push(OperandId, "'Pointer'");
+    InstructionDesc[OpLoad].operands.push(OperandVariableLiterals, "'Memory Access'");
+
+    InstructionDesc[OpStore].operands.push(OperandId, "'Pointer'");
+    InstructionDesc[OpStore].operands.push(OperandId, "'Object'");
+    InstructionDesc[OpStore].operands.push(OperandVariableLiterals, "'Memory Access'");
+
+    InstructionDesc[OpPhi].operands.push(OperandVariableIds, "");
+
+    InstructionDesc[OpDecorate].operands.push(OperandId, "'Target'");
+    InstructionDesc[OpDecorate].operands.push(OperandDecoration, "");
+    InstructionDesc[OpDecorate].operands.push(OperandVariableLiterals, "See <<Decoration,'Decoration'>>.");
+
+    InstructionDesc[OpMemberDecorate].operands.push(OperandId, "'Structure type'");
+    InstructionDesc[OpMemberDecorate].operands.push(OperandLiteralNumber, "'Member'");
+    InstructionDesc[OpMemberDecorate].operands.push(OperandDecoration, "");
+    InstructionDesc[OpMemberDecorate].operands.push(OperandVariableLiterals, "See <<Decoration,'Decoration'>>.");
+
+    InstructionDesc[OpGroupDecorate].operands.push(OperandId, "'Decoration group'");
+    InstructionDesc[OpGroupDecorate].operands.push(OperandVariableIds, "'Target', 'Target', ...");
+
+    InstructionDesc[OpGroupMemberDecorate].operands.push(OperandId, "'Decoration group'");
+    InstructionDesc[OpGroupMemberDecorate].operands.push(OperandVariableIds, "'Target', 'Target', ...");
+
+    InstructionDesc[OpVectorExtractDynamic].operands.push(OperandId, "'Vector'");
+    InstructionDesc[OpVectorExtractDynamic].operands.push(OperandId, "'Index'");
+
+    InstructionDesc[OpVectorInsertDynamic].operands.push(OperandId, "'Vector'");
+    InstructionDesc[OpVectorInsertDynamic].operands.push(OperandId, "'Component'");
+    InstructionDesc[OpVectorInsertDynamic].operands.push(OperandId, "'Index'");
+
+    InstructionDesc[OpVectorShuffle].operands.push(OperandId, "'Vector 1'");
+    InstructionDesc[OpVectorShuffle].operands.push(OperandId, "'Vector 2'");
+    InstructionDesc[OpVectorShuffle].operands.push(OperandVariableLiterals, "'Components'");
+
+    InstructionDesc[OpCompositeConstruct].operands.push(OperandVariableIds, "'Constituents'");
+
+    InstructionDesc[OpCompositeExtract].operands.push(OperandId, "'Composite'");
+    InstructionDesc[OpCompositeExtract].operands.push(OperandVariableLiterals, "'Indexes'");
+
+    InstructionDesc[OpCompositeInsert].operands.push(OperandId, "'Object'");
+    InstructionDesc[OpCompositeInsert].operands.push(OperandId, "'Composite'");
+    InstructionDesc[OpCompositeInsert].operands.push(OperandVariableLiterals, "'Indexes'");
+
+    InstructionDesc[OpCopyObject].operands.push(OperandId, "'Operand'");
+
+    InstructionDesc[OpCopyMemory].operands.push(OperandId, "'Target'");
+    InstructionDesc[OpCopyMemory].operands.push(OperandId, "'Source'");
+    InstructionDesc[OpCopyMemory].operands.push(OperandVariableLiterals, "'Memory Access'");
+
+    InstructionDesc[OpCopyMemorySized].operands.push(OperandId, "'Target'");
+    InstructionDesc[OpCopyMemorySized].operands.push(OperandId, "'Source'");
+    InstructionDesc[OpCopyMemorySized].operands.push(OperandId, "'Size'");
+    InstructionDesc[OpCopyMemorySized].operands.push(OperandVariableLiterals, "'Memory Access'");
+
+    InstructionDesc[OpCopyMemorySized].capabilities.push_back(CapAddr);
+
+    InstructionDesc[OpSampler].operands.push(OperandId, "'Sampler'");
+    InstructionDesc[OpSampler].operands.push(OperandId, "'Filter'");
+
+    InstructionDesc[OpTextureSample].operands.push(OperandId, "'Sampler'");
+    InstructionDesc[OpTextureSample].operands.push(OperandId, "'Coordinate'");
+    InstructionDesc[OpTextureSample].operands.push(OperandOptionalId, "['Bias']");
+    InstructionDesc[OpTextureSample].capabilities.push_back(CapShader);
+
+    InstructionDesc[OpTextureSampleDref].operands.push(OperandId, "'Sampler'");
+    InstructionDesc[OpTextureSampleDref].operands.push(OperandId, "'Coordinate'");
+    InstructionDesc[OpTextureSampleDref].operands.push(OperandId, "'D~ref~'");
+    InstructionDesc[OpTextureSampleDref].capabilities.push_back(CapShader);
+
+    InstructionDesc[OpTextureSampleLod].operands.push(OperandId, "'Sampler'");
+    InstructionDesc[OpTextureSampleLod].operands.push(OperandId, "'Coordinate'");
+    InstructionDesc[OpTextureSampleLod].operands.push(OperandId, "'Level of Detail'");
+    InstructionDesc[OpTextureSampleLod].capabilities.push_back(CapShader);
+
+    InstructionDesc[OpTextureSampleProj].operands.push(OperandId, "'Sampler'");
+    InstructionDesc[OpTextureSampleProj].operands.push(OperandId, "'Coordinate'");
+    InstructionDesc[OpTextureSampleProj].operands.push(OperandOptionalId, "['Bias']");
+    InstructionDesc[OpTextureSampleProj].capabilities.push_back(CapShader);
+
+    InstructionDesc[OpTextureSampleGrad].operands.push(OperandId, "'Sampler'");
+    InstructionDesc[OpTextureSampleGrad].operands.push(OperandId, "'Coordinate'");
+    InstructionDesc[OpTextureSampleGrad].operands.push(OperandId, "'dx'");
+    InstructionDesc[OpTextureSampleGrad].operands.push(OperandId, "'dy'");
+    InstructionDesc[OpTextureSampleGrad].capabilities.push_back(CapShader);
+
+    InstructionDesc[OpTextureSampleOffset].operands.push(OperandId, "'Sampler'");
+    InstructionDesc[OpTextureSampleOffset].operands.push(OperandId, "'Coordinate'");
+    InstructionDesc[OpTextureSampleOffset].operands.push(OperandId, "'Offset'");
+    InstructionDesc[OpTextureSampleOffset].operands.push(OperandOptionalId, "['Bias']");
+    InstructionDesc[OpTextureSampleOffset].capabilities.push_back(CapShader);
+
+    InstructionDesc[OpTextureSampleProjLod].operands.push(OperandId, "'Sampler'");
+    InstructionDesc[OpTextureSampleProjLod].operands.push(OperandId, "'Coordinate'");
+    InstructionDesc[OpTextureSampleProjLod].operands.push(OperandId, "'Level of Detail'");
+    InstructionDesc[OpTextureSampleProjLod].capabilities.push_back(CapShader);
+
+    InstructionDesc[OpTextureSampleProjGrad].operands.push(OperandId, "'Sampler'");
+    InstructionDesc[OpTextureSampleProjGrad].operands.push(OperandId, "'Coordinate'");
+    InstructionDesc[OpTextureSampleProjGrad].operands.push(OperandId, "'dx'");
+    InstructionDesc[OpTextureSampleProjGrad].operands.push(OperandId, "'dy'");
+    InstructionDesc[OpTextureSampleProjGrad].capabilities.push_back(CapShader);
+
+    InstructionDesc[OpTextureSampleLodOffset].operands.push(OperandId, "'Sampler'");
+    InstructionDesc[OpTextureSampleLodOffset].operands.push(OperandId, "'Coordinate'");
+    InstructionDesc[OpTextureSampleLodOffset].operands.push(OperandId, "'Level of Detail'");
+    InstructionDesc[OpTextureSampleLodOffset].operands.push(OperandId, "'Offset'");
+    InstructionDesc[OpTextureSampleLodOffset].capabilities.push_back(CapShader);
+
+    InstructionDesc[OpTextureSampleProjOffset].operands.push(OperandId, "'Sampler'");
+    InstructionDesc[OpTextureSampleProjOffset].operands.push(OperandId, "'Coordinate'");
+    InstructionDesc[OpTextureSampleProjOffset].operands.push(OperandId, "'Offset'");
+    InstructionDesc[OpTextureSampleProjOffset].operands.push(OperandOptionalId, "['Bias']");
+    InstructionDesc[OpTextureSampleProjOffset].capabilities.push_back(CapShader);
+
+    InstructionDesc[OpTextureSampleGradOffset].operands.push(OperandId, "'Sampler'");
+    InstructionDesc[OpTextureSampleGradOffset].operands.push(OperandId, "'Coordinate'");
+    InstructionDesc[OpTextureSampleGradOffset].operands.push(OperandId, "'dx'");
+    InstructionDesc[OpTextureSampleGradOffset].operands.push(OperandId, "'dy'");
+    InstructionDesc[OpTextureSampleGradOffset].operands.push(OperandId, "'Offset'");
+    InstructionDesc[OpTextureSampleGradOffset].capabilities.push_back(CapShader);
+
+    InstructionDesc[OpTextureSampleProjLodOffset].operands.push(OperandId, "'Sampler'");
+    InstructionDesc[OpTextureSampleProjLodOffset].operands.push(OperandId, "'Coordinate'");
+    InstructionDesc[OpTextureSampleProjLodOffset].operands.push(OperandId, "'Level of Detail'");
+    InstructionDesc[OpTextureSampleProjLodOffset].operands.push(OperandId, "'Offset'");
+    InstructionDesc[OpTextureSampleProjLodOffset].capabilities.push_back(CapShader);
+
+    InstructionDesc[OpTextureSampleProjGradOffset].operands.push(OperandId, "'Sampler'");
+    InstructionDesc[OpTextureSampleProjGradOffset].operands.push(OperandId, "'Coordinate'");
+    InstructionDesc[OpTextureSampleProjGradOffset].operands.push(OperandId, "'dx'");
+    InstructionDesc[OpTextureSampleProjGradOffset].operands.push(OperandId, "'dy'");
+    InstructionDesc[OpTextureSampleProjGradOffset].operands.push(OperandId, "'Offset'");
+    InstructionDesc[OpTextureSampleProjGradOffset].capabilities.push_back(CapShader);
+
+    InstructionDesc[OpTextureFetchTexelLod].operands.push(OperandId, "'Sampler'");
+    InstructionDesc[OpTextureFetchTexelLod].operands.push(OperandId, "'Coordinate'");
+    InstructionDesc[OpTextureFetchTexelLod].operands.push(OperandId, "'Level of Detail'");
+    InstructionDesc[OpTextureFetchTexelLod].capabilities.push_back(CapShader);
+
+    InstructionDesc[OpTextureFetchTexelOffset].operands.push(OperandId, "'Sampler'");
+    InstructionDesc[OpTextureFetchTexelOffset].operands.push(OperandId, "'Coordinate'");
+    InstructionDesc[OpTextureFetchTexelOffset].operands.push(OperandId, "'Offset'");
+    InstructionDesc[OpTextureFetchTexelOffset].capabilities.push_back(CapShader);
+
+    InstructionDesc[OpTextureFetchSample].operands.push(OperandId, "'Sampler'");
+    InstructionDesc[OpTextureFetchSample].operands.push(OperandId, "'Coordinate'");
+    InstructionDesc[OpTextureFetchSample].operands.push(OperandId, "'Sample'");
+    InstructionDesc[OpTextureFetchSample].capabilities.push_back(CapShader);
+
+    InstructionDesc[OpTextureFetchTexel].operands.push(OperandId, "'Sampler'");
+    InstructionDesc[OpTextureFetchTexel].operands.push(OperandId, "'Element'");
+    InstructionDesc[OpTextureFetchTexel].capabilities.push_back(CapShader);
+
+    InstructionDesc[OpTextureGather].operands.push(OperandId, "'Sampler'");
+    InstructionDesc[OpTextureGather].operands.push(OperandId, "'Coordinate'");
+    InstructionDesc[OpTextureGather].operands.push(OperandId, "'Component'");
+    InstructionDesc[OpTextureGather].capabilities.push_back(CapShader);
+
+    InstructionDesc[OpTextureGatherOffset].operands.push(OperandId, "'Sampler'");
+    InstructionDesc[OpTextureGatherOffset].operands.push(OperandId, "'Coordinate'");
+    InstructionDesc[OpTextureGatherOffset].operands.push(OperandId, "'Component'");
+    InstructionDesc[OpTextureGatherOffset].operands.push(OperandId, "'Offset'");
+    InstructionDesc[OpTextureGatherOffset].capabilities.push_back(CapShader);
+
+    InstructionDesc[OpTextureGatherOffsets].operands.push(OperandId, "'Sampler'");
+    InstructionDesc[OpTextureGatherOffsets].operands.push(OperandId, "'Coordinate'");
+    InstructionDesc[OpTextureGatherOffsets].operands.push(OperandId, "'Component'");
+    InstructionDesc[OpTextureGatherOffsets].operands.push(OperandId, "'Offsets'");
+    InstructionDesc[OpTextureGatherOffsets].capabilities.push_back(CapShader);
+
+    InstructionDesc[OpTextureQuerySizeLod].operands.push(OperandId, "'Sampler'");
+    InstructionDesc[OpTextureQuerySizeLod].operands.push(OperandId, "'Level of Detail'");
+    InstructionDesc[OpTextureQuerySizeLod].capabilities.push_back(CapShader);
+
+    InstructionDesc[OpTextureQuerySize].operands.push(OperandId, "'Sampler'");
+    InstructionDesc[OpTextureQuerySize].capabilities.push_back(CapShader);
+
+    InstructionDesc[OpTextureQueryLod].operands.push(OperandId, "'Sampler'");
+    InstructionDesc[OpTextureQueryLod].operands.push(OperandId, "'Coordinate'");
+    InstructionDesc[OpTextureQueryLod].capabilities.push_back(CapShader);
+
+    InstructionDesc[OpTextureQueryLevels].operands.push(OperandId, "'Sampler'");
+    InstructionDesc[OpTextureQueryLevels].capabilities.push_back(CapShader);
+
+    InstructionDesc[OpTextureQuerySamples].operands.push(OperandId, "'Sampler'");
+    InstructionDesc[OpTextureQuerySamples].capabilities.push_back(CapShader);
+
+    InstructionDesc[OpAccessChain].operands.push(OperandId, "'Base'");
+    InstructionDesc[OpAccessChain].operands.push(OperandVariableIds, "'Indexes'");
+
+    InstructionDesc[OpInBoundsAccessChain].operands.push(OperandId, "'Base'");
+    InstructionDesc[OpInBoundsAccessChain].operands.push(OperandVariableIds, "'Indexes'");
+
+    InstructionDesc[OpSNegate].operands.push(OperandId, "'Operand'");
+
+    InstructionDesc[OpFNegate].operands.push(OperandId, "'Operand'");
+
+    InstructionDesc[OpNot].operands.push(OperandId, "'Operand'");
+
+    InstructionDesc[OpAny].operands.push(OperandId, "'Vector'");
+
+    InstructionDesc[OpAll].operands.push(OperandId, "'Vector'");
+
+    InstructionDesc[OpConvertFToU].operands.push(OperandId, "'Float Value'");
+
+    InstructionDesc[OpConvertFToS].operands.push(OperandId, "'Float Value'");
+
+    InstructionDesc[OpConvertSToF].operands.push(OperandId, "'Signed Value'");
+
+    InstructionDesc[OpConvertUToF].operands.push(OperandId, "'Unsigned value'");
+
+    InstructionDesc[OpUConvert].operands.push(OperandId, "'Unsigned value'");
+
+    InstructionDesc[OpSConvert].operands.push(OperandId, "'Signed Value'");
+
+    InstructionDesc[OpFConvert].operands.push(OperandId, "'Float Value'");
+
+    InstructionDesc[OpSatConvertSToU].operands.push(OperandId, "'Signed Value'");
+    InstructionDesc[OpSatConvertSToU].capabilities.push_back(CapKernel);
+
+    InstructionDesc[OpSatConvertUToS].operands.push(OperandId, "'Unsigned Value'");
+    InstructionDesc[OpSatConvertUToS].capabilities.push_back(CapKernel);
+
+    InstructionDesc[OpConvertPtrToU].operands.push(OperandId, "'Pointer'");
+    InstructionDesc[OpConvertPtrToU].capabilities.push_back(CapAddr);
+
+    InstructionDesc[OpConvertUToPtr].operands.push(OperandId, "'Integer value'");
+    InstructionDesc[OpConvertUToPtr].capabilities.push_back(CapAddr);
+
+    InstructionDesc[OpPtrCastToGeneric].operands.push(OperandId, "'Source pointer'");
+    InstructionDesc[OpPtrCastToGeneric].capabilities.push_back(CapKernel);
+
+
+    InstructionDesc[OpGenericCastToPtr].operands.push(OperandId, "'Source pointer'");
+    InstructionDesc[OpGenericCastToPtr].capabilities.push_back(CapKernel);
+
+    InstructionDesc[OpGenericCastToPtrExplicit].operands.push(OperandId, "'Source pointer'");
+    InstructionDesc[OpGenericCastToPtrExplicit].operands.push(OperandStorage, "'storage'");
+    InstructionDesc[OpGenericCastToPtrExplicit].capabilities.push_back(CapKernel);
+
+    InstructionDesc[OpGenericPtrMemSemantics].operands.push(OperandId, "'ptr'");
+    InstructionDesc[OpGenericPtrMemSemantics].capabilities.push_back(CapKernel);
+
+    InstructionDesc[OpBitcast].operands.push(OperandId, "'Operand'");
+
+    InstructionDesc[OpTranspose].capabilities.push_back(CapMatrix);
+    InstructionDesc[OpTranspose].operands.push(OperandId, "'Matrix'");
+
+    InstructionDesc[OpIsNan].operands.push(OperandId, "'x'");
+
+    InstructionDesc[OpIsInf].operands.push(OperandId, "'x'");
+
+    InstructionDesc[OpIsFinite].capabilities.push_back(CapKernel);
+    InstructionDesc[OpIsFinite].operands.push(OperandId, "'x'");
+
+    InstructionDesc[OpIsNormal].capabilities.push_back(CapKernel);
+    InstructionDesc[OpIsNormal].operands.push(OperandId, "'x'");
+
+    InstructionDesc[OpSignBitSet].capabilities.push_back(CapKernel);
+    InstructionDesc[OpSignBitSet].operands.push(OperandId, "'x'");
+
+    InstructionDesc[OpLessOrGreater].capabilities.push_back(CapKernel);
+    InstructionDesc[OpLessOrGreater].operands.push(OperandId, "'x'");
+    InstructionDesc[OpLessOrGreater].operands.push(OperandId, "'y'");
+
+    InstructionDesc[OpOrdered].capabilities.push_back(CapKernel);
+    InstructionDesc[OpOrdered].operands.push(OperandId, "'x'");
+    InstructionDesc[OpOrdered].operands.push(OperandId, "'y'");
+
+    InstructionDesc[OpUnordered].capabilities.push_back(CapKernel);
+    InstructionDesc[OpUnordered].operands.push(OperandId, "'x'");
+    InstructionDesc[OpUnordered].operands.push(OperandId, "'y'");
+
+    InstructionDesc[OpArrayLength].operands.push(OperandId, "'Structure'");
+    InstructionDesc[OpArrayLength].operands.push(OperandLiteralNumber, "'Array member'");
+    InstructionDesc[OpArrayLength].capabilities.push_back(CapShader);
+
+    InstructionDesc[OpIAdd].operands.push(OperandId, "'Operand 1'");
+    InstructionDesc[OpIAdd].operands.push(OperandId, "'Operand 2'");
+
+    InstructionDesc[OpFAdd].operands.push(OperandId, "'Operand 1'");
+    InstructionDesc[OpFAdd].operands.push(OperandId, "'Operand 2'");
+
+    InstructionDesc[OpISub].operands.push(OperandId, "'Operand 1'");
+    InstructionDesc[OpISub].operands.push(OperandId, "'Operand 2'");
+
+    InstructionDesc[OpFSub].operands.push(OperandId, "'Operand 1'");
+    InstructionDesc[OpFSub].operands.push(OperandId, "'Operand 2'");
+
+    InstructionDesc[OpIMul].operands.push(OperandId, "'Operand 1'");
+    InstructionDesc[OpIMul].operands.push(OperandId, "'Operand 2'");
+
+    InstructionDesc[OpFMul].operands.push(OperandId, "'Operand 1'");
+    InstructionDesc[OpFMul].operands.push(OperandId, "'Operand 2'");
+
+    InstructionDesc[OpUDiv].operands.push(OperandId, "'Operand 1'");
+    InstructionDesc[OpUDiv].operands.push(OperandId, "'Operand 2'");
+
+    InstructionDesc[OpSDiv].operands.push(OperandId, "'Operand 1'");
+    InstructionDesc[OpSDiv].operands.push(OperandId, "'Operand 2'");
+
+    InstructionDesc[OpFDiv].operands.push(OperandId, "'Operand 1'");
+    InstructionDesc[OpFDiv].operands.push(OperandId, "'Operand 2'");
+
+    InstructionDesc[OpUMod].operands.push(OperandId, "'Operand 1'");
+    InstructionDesc[OpUMod].operands.push(OperandId, "'Operand 2'");
+
+    InstructionDesc[OpSRem].operands.push(OperandId, "'Operand 1'");
+    InstructionDesc[OpSRem].operands.push(OperandId, "'Operand 2'");
+
+    InstructionDesc[OpSMod].operands.push(OperandId, "'Operand 1'");
+    InstructionDesc[OpSMod].operands.push(OperandId, "'Operand 2'");
+
+    InstructionDesc[OpFRem].operands.push(OperandId, "'Operand 1'");
+    InstructionDesc[OpFRem].operands.push(OperandId, "'Operand 2'");
+
+    InstructionDesc[OpFMod].operands.push(OperandId, "'Operand 1'");
+    InstructionDesc[OpFMod].operands.push(OperandId, "'Operand 2'");
+
+    InstructionDesc[OpVectorTimesScalar].operands.push(OperandId, "'Vector'");
+    InstructionDesc[OpVectorTimesScalar].operands.push(OperandId, "'Scalar'");
+
+    InstructionDesc[OpMatrixTimesScalar].capabilities.push_back(CapMatrix);
+    InstructionDesc[OpMatrixTimesScalar].operands.push(OperandId, "'Matrix'");
+    InstructionDesc[OpMatrixTimesScalar].operands.push(OperandId, "'Scalar'");
+
+    InstructionDesc[OpVectorTimesMatrix].capabilities.push_back(CapMatrix);
+    InstructionDesc[OpVectorTimesMatrix].operands.push(OperandId, "'Vector'");
+    InstructionDesc[OpVectorTimesMatrix].operands.push(OperandId, "'Matrix'");
+
+    InstructionDesc[OpMatrixTimesVector].capabilities.push_back(CapMatrix);
+    InstructionDesc[OpMatrixTimesVector].operands.push(OperandId, "'Matrix'");
+    InstructionDesc[OpMatrixTimesVector].operands.push(OperandId, "'Vector'");
+
+    InstructionDesc[OpMatrixTimesMatrix].capabilities.push_back(CapMatrix);
+    InstructionDesc[OpMatrixTimesMatrix].operands.push(OperandId, "'LeftMatrix'");
+    InstructionDesc[OpMatrixTimesMatrix].operands.push(OperandId, "'RightMatrix'");
+
+    InstructionDesc[OpOuterProduct].capabilities.push_back(CapMatrix);
+    InstructionDesc[OpOuterProduct].operands.push(OperandId, "'Vector 1'");
+    InstructionDesc[OpOuterProduct].operands.push(OperandId, "'Vector 2'");
+
+    InstructionDesc[OpDot].operands.push(OperandId, "'Vector 1'");
+    InstructionDesc[OpDot].operands.push(OperandId, "'Vector 2'");
+
+    InstructionDesc[OpShiftRightLogical].operands.push(OperandId, "'Operand 1'");
+    InstructionDesc[OpShiftRightLogical].operands.push(OperandId, "'Operand 2'");
+
+    InstructionDesc[OpShiftRightArithmetic].operands.push(OperandId, "'Operand 1'");
+    InstructionDesc[OpShiftRightArithmetic].operands.push(OperandId, "'Operand 2'");
+
+    InstructionDesc[OpShiftLeftLogical].operands.push(OperandId, "'Operand 1'");
+    InstructionDesc[OpShiftLeftLogical].operands.push(OperandId, "'Operand 2'");
+
+    InstructionDesc[OpLogicalOr].operands.push(OperandId, "'Operand 1'");
+    InstructionDesc[OpLogicalOr].operands.push(OperandId, "'Operand 2'");
+
+    InstructionDesc[OpLogicalXor].operands.push(OperandId, "'Operand 1'");
+    InstructionDesc[OpLogicalXor].operands.push(OperandId, "'Operand 2'");
+
+    InstructionDesc[OpLogicalAnd].operands.push(OperandId, "'Operand 1'");
+    InstructionDesc[OpLogicalAnd].operands.push(OperandId, "'Operand 2'");
+
+    InstructionDesc[OpBitwiseOr].operands.push(OperandId, "'Operand 1'");
+    InstructionDesc[OpBitwiseOr].operands.push(OperandId, "'Operand 2'");
+
+    InstructionDesc[OpBitwiseXor].operands.push(OperandId, "'Operand 1'");
+    InstructionDesc[OpBitwiseXor].operands.push(OperandId, "'Operand 2'");
+
+    InstructionDesc[OpBitwiseAnd].operands.push(OperandId, "'Operand 1'");
+    InstructionDesc[OpBitwiseAnd].operands.push(OperandId, "'Operand 2'");
+
+    InstructionDesc[OpSelect].operands.push(OperandId, "'Condition'");
+    InstructionDesc[OpSelect].operands.push(OperandId, "'Object 1'");
+    InstructionDesc[OpSelect].operands.push(OperandId, "'Object 2'");
+
+    InstructionDesc[OpIEqual].operands.push(OperandId, "'Operand 1'");
+    InstructionDesc[OpIEqual].operands.push(OperandId, "'Operand 2'");
+
+    InstructionDesc[OpFOrdEqual].operands.push(OperandId, "'Operand 1'");
+    InstructionDesc[OpFOrdEqual].operands.push(OperandId, "'Operand 2'");
+
+    InstructionDesc[OpFUnordEqual].operands.push(OperandId, "'Operand 1'");
+    InstructionDesc[OpFUnordEqual].operands.push(OperandId, "'Operand 2'");
+
+    InstructionDesc[OpINotEqual].operands.push(OperandId, "'Operand 1'");
+    InstructionDesc[OpINotEqual].operands.push(OperandId, "'Operand 2'");
+
+    InstructionDesc[OpFOrdNotEqual].operands.push(OperandId, "'Operand 1'");
+    InstructionDesc[OpFOrdNotEqual].operands.push(OperandId, "'Operand 2'");
+
+    InstructionDesc[OpFUnordNotEqual].operands.push(OperandId, "'Operand 1'");
+    InstructionDesc[OpFUnordNotEqual].operands.push(OperandId, "'Operand 2'");
+
+    InstructionDesc[OpULessThan].operands.push(OperandId, "'Operand 1'");
+    InstructionDesc[OpULessThan].operands.push(OperandId, "'Operand 2'");
+
+    InstructionDesc[OpSLessThan].operands.push(OperandId, "'Operand 1'");
+    InstructionDesc[OpSLessThan].operands.push(OperandId, "'Operand 2'");
+
+    InstructionDesc[OpFOrdLessThan].operands.push(OperandId, "'Operand 1'");
+    InstructionDesc[OpFOrdLessThan].operands.push(OperandId, "'Operand 2'");
+
+    InstructionDesc[OpFUnordLessThan].operands.push(OperandId, "'Operand 1'");
+    InstructionDesc[OpFUnordLessThan].operands.push(OperandId, "'Operand 2'");
+
+    InstructionDesc[OpUGreaterThan].operands.push(OperandId, "'Operand 1'");
+    InstructionDesc[OpUGreaterThan].operands.push(OperandId, "'Operand 2'");
+
+    InstructionDesc[OpSGreaterThan].operands.push(OperandId, "'Operand 1'");
+    InstructionDesc[OpSGreaterThan].operands.push(OperandId, "'Operand 2'");
+
+    InstructionDesc[OpFOrdGreaterThan].operands.push(OperandId, "'Operand 1'");
+    InstructionDesc[OpFOrdGreaterThan].operands.push(OperandId, "'Operand 2'");
+
+    InstructionDesc[OpFUnordGreaterThan].operands.push(OperandId, "'Operand 1'");
+    InstructionDesc[OpFUnordGreaterThan].operands.push(OperandId, "'Operand 2'");
+
+    InstructionDesc[OpULessThanEqual].operands.push(OperandId, "'Operand 1'");
+    InstructionDesc[OpULessThanEqual].operands.push(OperandId, "'Operand 2'");
+
+    InstructionDesc[OpSLessThanEqual].operands.push(OperandId, "'Operand 1'");
+    InstructionDesc[OpSLessThanEqual].operands.push(OperandId, "'Operand 2'");
+
+    InstructionDesc[OpFOrdLessThanEqual].operands.push(OperandId, "'Operand 1'");
+    InstructionDesc[OpFOrdLessThanEqual].operands.push(OperandId, "'Operand 2'");
+
+    InstructionDesc[OpFUnordLessThanEqual].operands.push(OperandId, "'Operand 1'");
+    InstructionDesc[OpFUnordLessThanEqual].operands.push(OperandId, "'Operand 2'");
+
+    InstructionDesc[OpUGreaterThanEqual].operands.push(OperandId, "'Operand 1'");
+    InstructionDesc[OpUGreaterThanEqual].operands.push(OperandId, "'Operand 2'");
+
+    InstructionDesc[OpSGreaterThanEqual].operands.push(OperandId, "'Operand 1'");
+    InstructionDesc[OpSGreaterThanEqual].operands.push(OperandId, "'Operand 2'");
+
+    InstructionDesc[OpFOrdGreaterThanEqual].operands.push(OperandId, "'Operand 1'");
+    InstructionDesc[OpFOrdGreaterThanEqual].operands.push(OperandId, "'Operand 2'");
+
+    InstructionDesc[OpFUnordGreaterThanEqual].operands.push(OperandId, "'Operand 1'");
+    InstructionDesc[OpFUnordGreaterThanEqual].operands.push(OperandId, "'Operand 2'");
+
+    InstructionDesc[OpDPdx].capabilities.push_back(CapShader);
+    InstructionDesc[OpDPdx].operands.push(OperandId, "'P'");
+
+    InstructionDesc[OpDPdy].capabilities.push_back(CapShader);
+    InstructionDesc[OpDPdy].operands.push(OperandId, "'P'");
+
+    InstructionDesc[OpFwidth].capabilities.push_back(CapShader);
+    InstructionDesc[OpFwidth].operands.push(OperandId, "'P'");
+
+    InstructionDesc[OpDPdxFine].capabilities.push_back(CapShader);
+    InstructionDesc[OpDPdxFine].operands.push(OperandId, "'P'");
+
+    InstructionDesc[OpDPdyFine].capabilities.push_back(CapShader);
+    InstructionDesc[OpDPdyFine].operands.push(OperandId, "'P'");
+
+    InstructionDesc[OpFwidthFine].capabilities.push_back(CapShader);
+    InstructionDesc[OpFwidthFine].operands.push(OperandId, "'P'");
+
+    InstructionDesc[OpDPdxCoarse].capabilities.push_back(CapShader);
+    InstructionDesc[OpDPdxCoarse].operands.push(OperandId, "'P'");
+
+    InstructionDesc[OpDPdyCoarse].capabilities.push_back(CapShader);
+    InstructionDesc[OpDPdyCoarse].operands.push(OperandId, "'P'");
+
+    InstructionDesc[OpFwidthCoarse].capabilities.push_back(CapShader);
+    InstructionDesc[OpFwidthCoarse].operands.push(OperandId, "'P'");
+
+    InstructionDesc[OpEmitVertex].capabilities.push_back(CapGeom);
+
+    InstructionDesc[OpEndPrimitive].capabilities.push_back(CapGeom);
+
+    InstructionDesc[OpEmitStreamVertex].operands.push(OperandId, "'Stream'");
+    InstructionDesc[OpEmitStreamVertex].capabilities.push_back(CapGeom);
+
+    InstructionDesc[OpEndStreamPrimitive].operands.push(OperandId, "'Stream'");
+    InstructionDesc[OpEndStreamPrimitive].capabilities.push_back(CapGeom);
+
+    InstructionDesc[OpControlBarrier].operands.push(OperandExecutionScope, "'Scope'");
+
+    InstructionDesc[OpMemoryBarrier].operands.push(OperandExecutionScope, "'Scope'");
+    InstructionDesc[OpMemoryBarrier].operands.push(OperandMemorySemantics, "'Semantics'");
+
+    InstructionDesc[OpImagePointer].operands.push(OperandId, "'Image'");
+    InstructionDesc[OpImagePointer].operands.push(OperandId, "'Coordinate'");
+    InstructionDesc[OpImagePointer].operands.push(OperandId, "'Sample'");
+
+    InstructionDesc[OpAtomicInit].operands.push(OperandId, "'Pointer'");
+    InstructionDesc[OpAtomicInit].operands.push(OperandId, "'Value'");
+
+    InstructionDesc[OpAtomicLoad].operands.push(OperandId, "'Pointer'");
+    InstructionDesc[OpAtomicLoad].operands.push(OperandExecutionScope, "'Scope'");
+    InstructionDesc[OpAtomicLoad].operands.push(OperandMemorySemantics, "'Semantics'");
+
+    InstructionDesc[OpAtomicStore].operands.push(OperandId, "'Pointer'");
+    InstructionDesc[OpAtomicStore].operands.push(OperandExecutionScope, "'Scope'");
+    InstructionDesc[OpAtomicStore].operands.push(OperandMemorySemantics, "'Semantics'");
+    InstructionDesc[OpAtomicStore].operands.push(OperandId, "'Value'");
+
+    InstructionDesc[OpAtomicExchange].operands.push(OperandId, "'Pointer'");
+    InstructionDesc[OpAtomicExchange].operands.push(OperandExecutionScope, "'Scope'");
+    InstructionDesc[OpAtomicExchange].operands.push(OperandMemorySemantics, "'Semantics'");
+    InstructionDesc[OpAtomicExchange].operands.push(OperandId, "'Value'");
+
+    InstructionDesc[OpAtomicCompareExchange].operands.push(OperandId, "'Pointer'");
+    InstructionDesc[OpAtomicCompareExchange].operands.push(OperandExecutionScope, "'Scope'");
+    InstructionDesc[OpAtomicCompareExchange].operands.push(OperandMemorySemantics, "'Semantics'");
+    InstructionDesc[OpAtomicCompareExchange].operands.push(OperandId, "'Value'");
+    InstructionDesc[OpAtomicCompareExchange].operands.push(OperandId, "'Comparator'");
+
+    InstructionDesc[OpAtomicCompareExchangeWeak].operands.push(OperandId, "'Pointer'");
+    InstructionDesc[OpAtomicCompareExchangeWeak].operands.push(OperandExecutionScope, "'Scope'");
+    InstructionDesc[OpAtomicCompareExchangeWeak].operands.push(OperandMemorySemantics, "'Semantics'");
+    InstructionDesc[OpAtomicCompareExchangeWeak].operands.push(OperandId, "'Value'");
+    InstructionDesc[OpAtomicCompareExchangeWeak].operands.push(OperandId, "'Comparator'");
+
+    InstructionDesc[OpAtomicIIncrement].operands.push(OperandId, "'Pointer'");
+    InstructionDesc[OpAtomicIIncrement].operands.push(OperandExecutionScope, "'Scope'");
+    InstructionDesc[OpAtomicIIncrement].operands.push(OperandMemorySemantics, "'Semantics'");
+
+    InstructionDesc[OpAtomicIDecrement].operands.push(OperandId, "'Pointer'");
+    InstructionDesc[OpAtomicIDecrement].operands.push(OperandExecutionScope, "'Scope'");
+    InstructionDesc[OpAtomicIDecrement].operands.push(OperandMemorySemantics, "'Semantics'");
+
+    InstructionDesc[OpAtomicIAdd].operands.push(OperandId, "'Pointer'");
+    InstructionDesc[OpAtomicIAdd].operands.push(OperandExecutionScope, "'Scope'");
+    InstructionDesc[OpAtomicIAdd].operands.push(OperandMemorySemantics, "'Semantics'");
+    InstructionDesc[OpAtomicIAdd].operands.push(OperandId, "'Value'");
+
+    InstructionDesc[OpAtomicISub].operands.push(OperandId, "'Pointer'");
+    InstructionDesc[OpAtomicISub].operands.push(OperandExecutionScope, "'Scope'");
+    InstructionDesc[OpAtomicISub].operands.push(OperandMemorySemantics, "'Semantics'");
+    InstructionDesc[OpAtomicISub].operands.push(OperandId, "'Value'");
+
+    InstructionDesc[OpAtomicUMin].operands.push(OperandId, "'Pointer'");
+    InstructionDesc[OpAtomicUMin].operands.push(OperandExecutionScope, "'Scope'");
+    InstructionDesc[OpAtomicUMin].operands.push(OperandMemorySemantics, "'Semantics'");
+    InstructionDesc[OpAtomicUMin].operands.push(OperandId, "'Value'");
+
+    InstructionDesc[OpAtomicUMax].operands.push(OperandId, "'Pointer'");
+    InstructionDesc[OpAtomicUMax].operands.push(OperandExecutionScope, "'Scope'");
+    InstructionDesc[OpAtomicUMax].operands.push(OperandMemorySemantics, "'Semantics'");
+    InstructionDesc[OpAtomicUMax].operands.push(OperandId, "'Value'");
+
+    InstructionDesc[OpAtomicIMin].operands.push(OperandId, "'Pointer'");
+    InstructionDesc[OpAtomicIMin].operands.push(OperandExecutionScope, "'Scope'");
+    InstructionDesc[OpAtomicIMin].operands.push(OperandMemorySemantics, "'Semantics'");
+    InstructionDesc[OpAtomicIMin].operands.push(OperandId, "'Value'");
+
+    InstructionDesc[OpAtomicIMax].operands.push(OperandId, "'Pointer'");
+    InstructionDesc[OpAtomicIMax].operands.push(OperandExecutionScope, "'Scope'");
+    InstructionDesc[OpAtomicIMax].operands.push(OperandMemorySemantics, "'Semantics'");
+    InstructionDesc[OpAtomicIMax].operands.push(OperandId, "'Value'");
+
+    InstructionDesc[OpAtomicAnd].operands.push(OperandId, "'Pointer'");
+    InstructionDesc[OpAtomicAnd].operands.push(OperandExecutionScope, "'Scope'");
+    InstructionDesc[OpAtomicAnd].operands.push(OperandMemorySemantics, "'Semantics'");
+    InstructionDesc[OpAtomicAnd].operands.push(OperandId, "'Value'");
+
+    InstructionDesc[OpAtomicOr].operands.push(OperandId, "'Pointer'");
+    InstructionDesc[OpAtomicOr].operands.push(OperandExecutionScope, "'Scope'");
+    InstructionDesc[OpAtomicOr].operands.push(OperandMemorySemantics, "'Semantics'");
+    InstructionDesc[OpAtomicOr].operands.push(OperandId, "'Value'");
+
+    InstructionDesc[OpAtomicXor].operands.push(OperandId, "'Pointer'");
+    InstructionDesc[OpAtomicXor].operands.push(OperandExecutionScope, "'Scope'");
+    InstructionDesc[OpAtomicXor].operands.push(OperandMemorySemantics, "'Semantics'");
+    InstructionDesc[OpAtomicXor].operands.push(OperandId, "'Value'");
+
+    InstructionDesc[OpLoopMerge].operands.push(OperandId, "'Label'");
+    InstructionDesc[OpLoopMerge].operands.push(OperandLoop, "");
+
+    InstructionDesc[OpSelectionMerge].operands.push(OperandId, "'Label'");
+    InstructionDesc[OpSelectionMerge].operands.push(OperandSelect, "");
+
+    InstructionDesc[OpBranch].operands.push(OperandId, "'Target Label'");
+
+    InstructionDesc[OpBranchConditional].operands.push(OperandId, "'Condition'");
+    InstructionDesc[OpBranchConditional].operands.push(OperandId, "'True Label'");
+    InstructionDesc[OpBranchConditional].operands.push(OperandId, "'False Label'");
+    InstructionDesc[OpBranchConditional].operands.push(OperandVariableLiterals, "'Branch weights'");
+
+    InstructionDesc[OpSwitch].operands.push(OperandId, "'Selector'");
+    InstructionDesc[OpSwitch].operands.push(OperandId, "'Default'");
+    InstructionDesc[OpSwitch].operands.push(OperandVariableLiteralId, "'Target'");
+
+    InstructionDesc[OpKill].capabilities.push_back(CapShader);
+
+    InstructionDesc[OpReturnValue].operands.push(OperandId, "'Value'");
+
+    InstructionDesc[OpUnreachable].capabilities.push_back(CapKernel);
+
+    InstructionDesc[OpLifetimeStart].operands.push(OperandId, "");
+    InstructionDesc[OpLifetimeStart].operands.push(OperandLiteralNumber, "");
+
+    InstructionDesc[OpLifetimeStop].operands.push(OperandId, "");
+    InstructionDesc[OpLifetimeStop].operands.push(OperandLiteralNumber, "");
+
+    InstructionDesc[OpCompileFlag].capabilities.push_back(CapKernel);
+    InstructionDesc[OpCompileFlag].operands.push(OperandLiteralString, "'Flag'");
+
+    InstructionDesc[OpAsyncGroupCopy].capabilities.push_back(CapKernel);
+    InstructionDesc[OpAsyncGroupCopy].operands.push(OperandExecutionScope, "'Scope'");
+    InstructionDesc[OpAsyncGroupCopy].operands.push(OperandId, "'Destination'");
+    InstructionDesc[OpAsyncGroupCopy].operands.push(OperandId, "'Source'");
+    InstructionDesc[OpAsyncGroupCopy].operands.push(OperandId, "'Num Elements'");
+    InstructionDesc[OpAsyncGroupCopy].operands.push(OperandId, "'Stride'");
+    InstructionDesc[OpAsyncGroupCopy].operands.push(OperandId, "'Event'");
+
+    InstructionDesc[OpWaitGroupEvents].capabilities.push_back(CapKernel);
+    InstructionDesc[OpWaitGroupEvents].operands.push(OperandExecutionScope, "'Scope'");
+    InstructionDesc[OpWaitGroupEvents].operands.push(OperandId, "'Num Events'");
+    InstructionDesc[OpWaitGroupEvents].operands.push(OperandId, "'Events List'");
+
+    InstructionDesc[OpGroupAll].capabilities.push_back(CapKernel);
+    InstructionDesc[OpGroupAll].operands.push(OperandExecutionScope, "'Scope'");
+    InstructionDesc[OpGroupAll].operands.push(OperandId, "'Predicate'");
+
+    InstructionDesc[OpGroupAny].capabilities.push_back(CapKernel);
+    InstructionDesc[OpGroupAny].operands.push(OperandExecutionScope, "'Scope'");
+    InstructionDesc[OpGroupAny].operands.push(OperandId, "'Predicate'");
+
+    InstructionDesc[OpGroupBroadcast].capabilities.push_back(CapKernel);
+    InstructionDesc[OpGroupBroadcast].operands.push(OperandExecutionScope, "'Scope'");
+    InstructionDesc[OpGroupBroadcast].operands.push(OperandId, "'Value'");
+    InstructionDesc[OpGroupBroadcast].operands.push(OperandId, "'LocalId'");
+
+    InstructionDesc[OpGroupIAdd].capabilities.push_back(CapKernel);
+    InstructionDesc[OpGroupIAdd].operands.push(OperandExecutionScope, "'Scope'");
+    InstructionDesc[OpGroupIAdd].operands.push(OperandGroupOperation, "'Operation'");
+    InstructionDesc[OpGroupIAdd].operands.push(OperandId, "'X'");
+
+    InstructionDesc[OpGroupFAdd].capabilities.push_back(CapKernel);
+    InstructionDesc[OpGroupFAdd].operands.push(OperandExecutionScope, "'Scope'");
+    InstructionDesc[OpGroupFAdd].operands.push(OperandGroupOperation, "'Operation'");
+    InstructionDesc[OpGroupFAdd].operands.push(OperandId, "'X'");
+
+    InstructionDesc[OpGroupUMin].capabilities.push_back(CapKernel);
+    InstructionDesc[OpGroupUMin].operands.push(OperandExecutionScope, "'Scope'");
+    InstructionDesc[OpGroupUMin].operands.push(OperandGroupOperation, "'Operation'");
+    InstructionDesc[OpGroupUMin].operands.push(OperandId, "'X'");
+
+    InstructionDesc[OpGroupSMin].capabilities.push_back(CapKernel);
+    InstructionDesc[OpGroupSMin].operands.push(OperandExecutionScope, "'Scope'");
+    InstructionDesc[OpGroupSMin].operands.push(OperandGroupOperation, "'Operation'");
+    InstructionDesc[OpGroupSMin].operands.push(OperandId, "X");
+
+    InstructionDesc[OpGroupFMin].capabilities.push_back(CapKernel);
+    InstructionDesc[OpGroupFMin].operands.push(OperandExecutionScope, "'Scope'");
+    InstructionDesc[OpGroupFMin].operands.push(OperandGroupOperation, "'Operation'");
+    InstructionDesc[OpGroupFMin].operands.push(OperandId, "X");
+
+    InstructionDesc[OpGroupUMax].capabilities.push_back(CapKernel);
+    InstructionDesc[OpGroupUMax].operands.push(OperandExecutionScope, "'Scope'");
+    InstructionDesc[OpGroupUMax].operands.push(OperandGroupOperation, "'Operation'");
+    InstructionDesc[OpGroupUMax].operands.push(OperandId, "X");
+
+    InstructionDesc[OpGroupSMax].capabilities.push_back(CapKernel);
+    InstructionDesc[OpGroupSMax].operands.push(OperandExecutionScope, "'Scope'");
+    InstructionDesc[OpGroupSMax].operands.push(OperandGroupOperation, "'Operation'");
+    InstructionDesc[OpGroupSMax].operands.push(OperandId, "X");
+
+    InstructionDesc[OpGroupFMax].capabilities.push_back(CapKernel);
+    InstructionDesc[OpGroupFMax].operands.push(OperandExecutionScope, "'Scope'");
+    InstructionDesc[OpGroupFMax].operands.push(OperandGroupOperation, "'Operation'");
+    InstructionDesc[OpGroupFMax].operands.push(OperandId, "X");
+
+    InstructionDesc[OpReadPipe].capabilities.push_back(CapKernel);
+    InstructionDesc[OpReadPipe].operands.push(OperandId, "'p'");
+    InstructionDesc[OpReadPipe].operands.push(OperandId, "'ptr'");
+
+    InstructionDesc[OpWritePipe].capabilities.push_back(CapKernel);
+    InstructionDesc[OpWritePipe].operands.push(OperandId, "'p'");
+    InstructionDesc[OpWritePipe].operands.push(OperandId, "'ptr'");
+
+    InstructionDesc[OpReservedReadPipe].capabilities.push_back(CapKernel);
+    InstructionDesc[OpReservedReadPipe].operands.push(OperandId, "'p'");
+    InstructionDesc[OpReservedReadPipe].operands.push(OperandId, "'reserve_id'");
+    InstructionDesc[OpReservedReadPipe].operands.push(OperandId, "'index'");
+    InstructionDesc[OpReservedReadPipe].operands.push(OperandId, "'ptr'");
+
+    InstructionDesc[OpReservedWritePipe].capabilities.push_back(CapKernel);
+    InstructionDesc[OpReservedWritePipe].operands.push(OperandId, "'p'");
+    InstructionDesc[OpReservedWritePipe].operands.push(OperandId, "'reserve_id'");
+    InstructionDesc[OpReservedWritePipe].operands.push(OperandId, "'index'");
+    InstructionDesc[OpReservedWritePipe].operands.push(OperandId, "'ptr'");
+
+    InstructionDesc[OpReserveReadPipePackets].capabilities.push_back(CapKernel);
+    InstructionDesc[OpReserveReadPipePackets].operands.push(OperandId, "'p'");
+    InstructionDesc[OpReserveReadPipePackets].operands.push(OperandId, "'num_packets'");
+
+    InstructionDesc[OpReserveWritePipePackets].capabilities.push_back(CapKernel);
+    InstructionDesc[OpReserveWritePipePackets].operands.push(OperandId, "'p'");
+    InstructionDesc[OpReserveWritePipePackets].operands.push(OperandId, "'num_packets'");
+
+    InstructionDesc[OpCommitReadPipe].capabilities.push_back(CapKernel);
+    InstructionDesc[OpCommitReadPipe].operands.push(OperandId, "'p'");
+    InstructionDesc[OpCommitReadPipe].operands.push(OperandId, "'reserve_id'");
+
+    InstructionDesc[OpCommitWritePipe].capabilities.push_back(CapKernel);
+    InstructionDesc[OpCommitWritePipe].operands.push(OperandId, "'p'");
+    InstructionDesc[OpCommitWritePipe].operands.push(OperandId, "'reserve_id'");
+
+    InstructionDesc[OpIsValidReserveId].capabilities.push_back(CapKernel);
+    InstructionDesc[OpIsValidReserveId].operands.push(OperandId, "'reserve_id'");
+
+    InstructionDesc[OpGetNumPipePackets].capabilities.push_back(CapKernel);
+    InstructionDesc[OpGetNumPipePackets].operands.push(OperandId, "'p'");
+
+    InstructionDesc[OpGetMaxPipePackets].capabilities.push_back(CapKernel);
+    InstructionDesc[OpGetMaxPipePackets].operands.push(OperandId, "'p'");
+
+    InstructionDesc[OpGroupReserveReadPipePackets].capabilities.push_back(CapKernel);
+    InstructionDesc[OpGroupReserveReadPipePackets].operands.push(OperandExecutionScope, "'Scope'");
+    InstructionDesc[OpGroupReserveReadPipePackets].operands.push(OperandId, "'p'");
+    InstructionDesc[OpGroupReserveReadPipePackets].operands.push(OperandId, "'num_packets'");
+
+    InstructionDesc[OpGroupReserveWritePipePackets].capabilities.push_back(CapKernel);
+    InstructionDesc[OpGroupReserveWritePipePackets].operands.push(OperandExecutionScope, "'Scope'");
+    InstructionDesc[OpGroupReserveWritePipePackets].operands.push(OperandId, "'p'");
+    InstructionDesc[OpGroupReserveWritePipePackets].operands.push(OperandId, "'num_packets'");
+
+    InstructionDesc[OpGroupCommitReadPipe].capabilities.push_back(CapKernel);
+    InstructionDesc[OpGroupCommitReadPipe].operands.push(OperandExecutionScope, "'Scope'");
+    InstructionDesc[OpGroupCommitReadPipe].operands.push(OperandId, "'p'");
+    InstructionDesc[OpGroupCommitReadPipe].operands.push(OperandId, "'reserve_id'");
+
+    InstructionDesc[OpGroupCommitWritePipe].capabilities.push_back(CapKernel);
+    InstructionDesc[OpGroupCommitWritePipe].operands.push(OperandExecutionScope, "'Scope'");
+    InstructionDesc[OpGroupCommitWritePipe].operands.push(OperandId, "'p'");
+    InstructionDesc[OpGroupCommitWritePipe].operands.push(OperandId, "'reserve_id'");
+
+    InstructionDesc[OpBuildNDRange].capabilities.push_back(CapKernel);
+    InstructionDesc[OpBuildNDRange].operands.push(OperandId, "'GlobalWorkSize'");
+    InstructionDesc[OpBuildNDRange].operands.push(OperandId, "'LocalWorkSize'");
+    InstructionDesc[OpBuildNDRange].operands.push(OperandId, "'GlobalWorkOffset'");
+
+    InstructionDesc[OpGetDefaultQueue].capabilities.push_back(CapKernel);
+
+    InstructionDesc[OpCaptureEventProfilingInfo].capabilities.push_back(CapKernel);
+
+    InstructionDesc[OpCaptureEventProfilingInfo].operands.push(OperandId, "'event'");
+    InstructionDesc[OpCaptureEventProfilingInfo].operands.push(OperandKernelProfilingInfo, "'info'");
+    InstructionDesc[OpCaptureEventProfilingInfo].operands.push(OperandId, "'value'");
+
+    InstructionDesc[OpSetUserEventStatus].capabilities.push_back(CapKernel);
+
+    InstructionDesc[OpSetUserEventStatus].operands.push(OperandId, "'event'");
+    InstructionDesc[OpSetUserEventStatus].operands.push(OperandId, "'status'");
+
+    InstructionDesc[OpIsValidEvent].capabilities.push_back(CapKernel);
+    InstructionDesc[OpIsValidEvent].operands.push(OperandId, "'event'");
+
+    InstructionDesc[OpCreateUserEvent].capabilities.push_back(CapKernel);
+
+    InstructionDesc[OpRetainEvent].capabilities.push_back(CapKernel);
+    InstructionDesc[OpRetainEvent].operands.push(OperandId, "'event'");
+
+    InstructionDesc[OpReleaseEvent].capabilities.push_back(CapKernel);
+    InstructionDesc[OpReleaseEvent].operands.push(OperandId, "'event'");
+
+    InstructionDesc[OpGetKernelWorkGroupSize].capabilities.push_back(CapKernel);
+    InstructionDesc[OpGetKernelWorkGroupSize].operands.push(OperandId, "'Invoke'");
+
+    InstructionDesc[OpGetKernelPreferredWorkGroupSizeMultiple].capabilities.push_back(CapKernel);
+    InstructionDesc[OpGetKernelPreferredWorkGroupSizeMultiple].operands.push(OperandId, "'Invoke'");
+
+    InstructionDesc[OpGetKernelNDrangeSubGroupCount].capabilities.push_back(CapKernel);
+    InstructionDesc[OpGetKernelNDrangeSubGroupCount].operands.push(OperandId, "'ND Range'");
+    InstructionDesc[OpGetKernelNDrangeSubGroupCount].operands.push(OperandId, "'Invoke'");
+
+    InstructionDesc[OpGetKernelNDrangeMaxSubGroupSize].capabilities.push_back(CapKernel);
+    InstructionDesc[OpGetKernelNDrangeMaxSubGroupSize].operands.push(OperandId, "'ND Range'");
+    InstructionDesc[OpGetKernelNDrangeMaxSubGroupSize].operands.push(OperandId, "'Invoke'");
+
+    InstructionDesc[OpEnqueueKernel].capabilities.push_back(CapKernel);
+    InstructionDesc[OpEnqueueKernel].operands.push(OperandId, "'q'");
+    InstructionDesc[OpEnqueueKernel].operands.push(OperandKernelEnqueueFlags, "'flags'");
+    InstructionDesc[OpEnqueueKernel].operands.push(OperandId, "'ND Range'");
+    InstructionDesc[OpEnqueueKernel].operands.push(OperandId, "'Num Events'");
+    InstructionDesc[OpEnqueueKernel].operands.push(OperandId, "'Wait Events'");
+    InstructionDesc[OpEnqueueKernel].operands.push(OperandId, "'Ret Event'");
+    InstructionDesc[OpEnqueueKernel].operands.push(OperandId, "'Invoke'");
+    InstructionDesc[OpEnqueueKernel].operands.push(OperandId, "'Param'");
+    InstructionDesc[OpEnqueueKernel].operands.push(OperandId, "'Param Size'");
+    InstructionDesc[OpEnqueueKernel].operands.push(OperandId, "'Param Align'");
+    InstructionDesc[OpEnqueueKernel].operands.push(OperandVariableIds, "'Local Size'");
+
+    InstructionDesc[OpEnqueueMarker].capabilities.push_back(CapKernel);
+    InstructionDesc[OpEnqueueMarker].operands.push(OperandId, "'q'");
+    InstructionDesc[OpEnqueueMarker].operands.push(OperandId, "'Num Events'");
+    InstructionDesc[OpEnqueueMarker].operands.push(OperandId, "'Wait Events'");
+    InstructionDesc[OpEnqueueMarker].operands.push(OperandId, "'Ret Event'");
+}
+
+}; // end spv namespace
index 9059f0e..ce4d972 100644 (file)
-//\r
-//Copyright (C) 2014 LunarG, Inc.\r
-//\r
-//All rights reserved.\r
-//\r
-//Redistribution and use in source and binary forms, with or without\r
-//modification, are permitted provided that the following conditions\r
-//are met:\r
-//\r
-//    Redistributions of source code must retain the above copyright\r
-//    notice, this list of conditions and the following disclaimer.\r
-//\r
-//    Redistributions in binary form must reproduce the above\r
-//    copyright notice, this list of conditions and the following\r
-//    disclaimer in the documentation and/or other materials provided\r
-//    with the distribution.\r
-//\r
-//    Neither the name of 3Dlabs Inc. Ltd. nor the names of its\r
-//    contributors may be used to endorse or promote products derived\r
-//    from this software without specific prior written permission.\r
-//\r
-//THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\r
-//"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\r
-//LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS\r
-//FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE\r
-//COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,\r
-//INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,\r
-//BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\r
-//LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER\r
-//CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\r
-//LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN\r
-//ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE\r
-//POSSIBILITY OF SUCH DAMAGE.\r
-\r
-//\r
-// Author: John Kessenich, LunarG\r
-//\r
-\r
-//\r
-// Parameterize the SPIR-V enumerants.\r
-//\r
-\r
-#include "spirv.h"\r
-\r
-#include <vector>\r
-\r
-namespace spv {\r
-\r
-// Fill in all the parameters\r
-void Parameterize();\r
-\r
-// Return the English names of all the enums.\r
-const char* SourceString(int);\r
-const char* AddressingString(int);\r
-const char* MemoryString(int);\r
-const char* ExecutionModelString(int);\r
-const char* ExecutionModeString(int);\r
-const char* StorageClassString(int);\r
-const char* DecorationString(int);\r
-const char* BuiltInString(int);\r
-const char* DimensionString(int);\r
-const char* SelectControlString(int);\r
-const char* LoopControlString(int);\r
-const char* FunctionControlString(int);\r
-const char* SamplerAddressingModeString(int);\r
-const char* SamplerFilterModeString(int);\r
-const char* FPFastMathString(int);\r
-const char* FPRoundingModeString(int);\r
-const char* LinkageTypeString(int);\r
-const char* FuncParamAttrString(int);\r
-const char* AccessQualifierString(int);\r
-const char* MemorySemanticsString(int);\r
-const char* MemoryAccessString(int);\r
-const char* ExecutionScopeString(int);\r
-const char* GroupOperationString(int);\r
-const char* KernelEnqueueFlagsString(int);\r
-const char* KernelProfilingInfoString(int);\r
-const char* OpcodeString(int);\r
-\r
-// For grouping opcodes into subsections\r
-enum OpcodeClass {\r
-    OpClassMisc,            // default, until opcode is classified\r
-    OpClassDebug,\r
-    OpClassAnnotate,\r
-    OpClassExtension,\r
-    OpClassMode,\r
-    OpClassType,\r
-    OpClassConstant,\r
-    OpClassMemory,\r
-    OpClassFunction,\r
-    OpClassTexture,\r
-    OpClassConvert,\r
-    OpClassComposite,\r
-    OpClassArithmetic,\r
-    OpClassRelationalLogical,\r
-    OpClassDerivative,\r
-    OpClassFlowControl,\r
-    OpClassAtomic,\r
-    OpClassPrimitive,\r
-    OpClassBarrier,\r
-    OpClassGroup,\r
-    OpClassDeviceSideEnqueue,\r
-    OpClassPipe,\r
-\r
-    OpClassCount\r
-};\r
-\r
-// For parameterizing operands.\r
-enum OperandClass {\r
-    OperandNone,\r
-    OperandId,\r
-    OperandOptionalId,\r
-    OperandVariableIds,\r
-    OperandVariableLiterals,\r
-    OperandVariableLiteralId,\r
-    OperandLiteralNumber,\r
-    OperandLiteralString,\r
-    OperandSource,\r
-    OperandExecutionModel,\r
-    OperandAddressing,\r
-    OperandMemory,\r
-    OperandExecutionMode,\r
-    OperandStorage,\r
-    OperandDimensionality,\r
-    OperandSamplerAddressingMode,\r
-    OperandSamplerFilterMode,\r
-    OperandFPFastMath,\r
-    OperandFPRoundingMode,\r
-    OperandLinkageType,\r
-    OperandAccessQualifier,\r
-    OperandFuncParamAttr,\r
-    OperandDecoration,\r
-    OperandBuiltIn,\r
-    OperandSelect,\r
-    OperandLoop,\r
-    OperandFunction,\r
-    OperandMemorySemantics,\r
-    OperandMemoryAccess,\r
-    OperandExecutionScope,\r
-       OperandGroupOperation,\r
-    OperandKernelEnqueueFlags,\r
-    OperandKernelProfilingInfo,\r
-\r
-    OperandOpcode,\r
-\r
-    OperandCount\r
-};\r
-\r
-// Set of capabilities.  Generally, something is assumed to be in core,\r
-// if nothing else is said.  So, these are used to identify when something\r
-// requires a specific capability to be declared.\r
-enum Capability {\r
-    CapMatrix,\r
-    CapShader,\r
-    CapGeom,\r
-    CapTess,\r
-    CapAddr,\r
-    CapLink,\r
-    CapKernel\r
-};\r
-\r
-// Any specific enum can have a set of capabilities that allow it:\r
-typedef std::vector<Capability> EnumCaps;\r
-\r
-// Parameterize a set of operands with their OperandClass(es) and descriptions.\r
-class OperandParameters {\r
-public:\r
-    OperandParameters() { }\r
-    void push(OperandClass oc, const char* d)\r
-    {\r
-        opClass.push_back(oc);\r
-        desc.push_back(d);\r
-    }\r
-    OperandClass getClass(int op) const { return opClass[op]; }\r
-    const char* getDesc(int op) const { return desc[op]; }\r
-    int getNum() const { return (int)opClass.size(); }\r
-\r
-protected:\r
-    std::vector<OperandClass> opClass;\r
-    std::vector<const char*> desc;\r
-};\r
-\r
-// Parameterize an enumerant\r
-class EnumParameters {\r
-public:\r
-    EnumParameters() : desc(0) { }\r
-    EnumCaps caps;\r
-    const char* desc;\r
-};\r
-\r
-// Parameterize a set of enumerants that form an enum\r
-class EnumDefinition : public EnumParameters {\r
-public:\r
-    EnumDefinition() : \r
-        ceiling(0), bitmask(false), getName(0), enumParams(0), operandParams(0) { }\r
-    void set(int ceil, const char* (*name)(int), EnumParameters* ep, bool mask = false)\r
-    {\r
-        ceiling = ceil;\r
-        getName = name;\r
-        bitmask = mask;\r
-        enumParams = ep;\r
-    }\r
-    void setOperands(OperandParameters* op) { operandParams = op; }\r
-    int ceiling;   // ceiling of enumerants\r
-    bool bitmask;  // true if these enumerants combine into a bitmask\r
-    const char* (*getName)(int);      // a function that returns the name for each enumerant value (or shift)\r
-    EnumParameters* enumParams;       // parameters for each individual enumerant\r
-    OperandParameters* operandParams; // sets of operands\r
-};\r
-\r
-// Parameterize an instruction's logical format, including its known set of operands,\r
-// per OperandParameters above.\r
-class InstructionParameters {\r
-public:\r
-    InstructionParameters() :\r
-        typePresent(true),         // most normal, only exceptions have to be spelled out\r
-        resultPresent(true),       // most normal, only exceptions have to be spelled out\r
-        opDesc(0),\r
-        opClass(OpClassMisc)\r
-    { }\r
-\r
-    void setResultAndType(bool r, bool t)\r
-    {\r
-        resultPresent = r;\r
-        typePresent = t;\r
-    }\r
-\r
-    bool hasResult() const { return resultPresent != 0; }\r
-    bool hasType()   const { return typePresent != 0; }\r
-\r
-    const char* opDesc;\r
-    EnumCaps capabilities;\r
-    OpcodeClass opClass;\r
-    OperandParameters operands;\r
-\r
-protected:\r
-    int typePresent   : 1;\r
-    int resultPresent : 1;\r
-};\r
-\r
-const int OpcodeCeiling = 267;\r
-\r
-// The set of objects that hold all the instruction/operand\r
-// parameterization information.\r
-extern InstructionParameters InstructionDesc[];\r
-\r
-// These hold definitions of the enumerants used for operands\r
-extern EnumDefinition OperandClassParams[];\r
-\r
-const char* GetOperandDesc(OperandClass operand);\r
-void PrintImmediateRow(int imm, const char* name, const EnumParameters* enumParams, bool caps, bool hex = false);\r
-const char* AccessQualifierString(int attr);\r
-\r
-void PrintOperands(const OperandParameters& operands, int reservedOperands);\r
-\r
-};  // end namespace spv\r
+//
+//Copyright (C) 2014 LunarG, Inc.
+//
+//All rights reserved.
+//
+//Redistribution and use in source and binary forms, with or without
+//modification, are permitted provided that the following conditions
+//are met:
+//
+//    Redistributions of source code must retain the above copyright
+//    notice, this list of conditions and the following disclaimer.
+//
+//    Redistributions in binary form must reproduce the above
+//    copyright notice, this list of conditions and the following
+//    disclaimer in the documentation and/or other materials provided
+//    with the distribution.
+//
+//    Neither the name of 3Dlabs Inc. Ltd. nor the names of its
+//    contributors may be used to endorse or promote products derived
+//    from this software without specific prior written permission.
+//
+//THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+//"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+//LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+//FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+//COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+//INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+//BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+//LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+//CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+//LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+//ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+//POSSIBILITY OF SUCH DAMAGE.
+
+//
+// Author: John Kessenich, LunarG
+//
+
+//
+// Parameterize the SPIR-V enumerants.
+//
+
+#include "spirv.h"
+
+#include <vector>
+
+namespace spv {
+
+// Fill in all the parameters
+void Parameterize();
+
+// Return the English names of all the enums.
+const char* SourceString(int);
+const char* AddressingString(int);
+const char* MemoryString(int);
+const char* ExecutionModelString(int);
+const char* ExecutionModeString(int);
+const char* StorageClassString(int);
+const char* DecorationString(int);
+const char* BuiltInString(int);
+const char* DimensionString(int);
+const char* SelectControlString(int);
+const char* LoopControlString(int);
+const char* FunctionControlString(int);
+const char* SamplerAddressingModeString(int);
+const char* SamplerFilterModeString(int);
+const char* FPFastMathString(int);
+const char* FPRoundingModeString(int);
+const char* LinkageTypeString(int);
+const char* FuncParamAttrString(int);
+const char* AccessQualifierString(int);
+const char* MemorySemanticsString(int);
+const char* MemoryAccessString(int);
+const char* ExecutionScopeString(int);
+const char* GroupOperationString(int);
+const char* KernelEnqueueFlagsString(int);
+const char* KernelProfilingInfoString(int);
+const char* OpcodeString(int);
+
+// For grouping opcodes into subsections
+enum OpcodeClass {
+    OpClassMisc,            // default, until opcode is classified
+    OpClassDebug,
+    OpClassAnnotate,
+    OpClassExtension,
+    OpClassMode,
+    OpClassType,
+    OpClassConstant,
+    OpClassMemory,
+    OpClassFunction,
+    OpClassTexture,
+    OpClassConvert,
+    OpClassComposite,
+    OpClassArithmetic,
+    OpClassRelationalLogical,
+    OpClassDerivative,
+    OpClassFlowControl,
+    OpClassAtomic,
+    OpClassPrimitive,
+    OpClassBarrier,
+    OpClassGroup,
+    OpClassDeviceSideEnqueue,
+    OpClassPipe,
+
+    OpClassCount
+};
+
+// For parameterizing operands.
+enum OperandClass {
+    OperandNone,
+    OperandId,
+    OperandOptionalId,
+    OperandVariableIds,
+    OperandVariableLiterals,
+    OperandVariableLiteralId,
+    OperandLiteralNumber,
+    OperandLiteralString,
+    OperandSource,
+    OperandExecutionModel,
+    OperandAddressing,
+    OperandMemory,
+    OperandExecutionMode,
+    OperandStorage,
+    OperandDimensionality,
+    OperandSamplerAddressingMode,
+    OperandSamplerFilterMode,
+    OperandFPFastMath,
+    OperandFPRoundingMode,
+    OperandLinkageType,
+    OperandAccessQualifier,
+    OperandFuncParamAttr,
+    OperandDecoration,
+    OperandBuiltIn,
+    OperandSelect,
+    OperandLoop,
+    OperandFunction,
+    OperandMemorySemantics,
+    OperandMemoryAccess,
+    OperandExecutionScope,
+       OperandGroupOperation,
+    OperandKernelEnqueueFlags,
+    OperandKernelProfilingInfo,
+
+    OperandOpcode,
+
+    OperandCount
+};
+
+// Set of capabilities.  Generally, something is assumed to be in core,
+// if nothing else is said.  So, these are used to identify when something
+// requires a specific capability to be declared.
+enum Capability {
+    CapMatrix,
+    CapShader,
+    CapGeom,
+    CapTess,
+    CapAddr,
+    CapLink,
+    CapKernel
+};
+
+// Any specific enum can have a set of capabilities that allow it:
+typedef std::vector<Capability> EnumCaps;
+
+// Parameterize a set of operands with their OperandClass(es) and descriptions.
+class OperandParameters {
+public:
+    OperandParameters() { }
+    void push(OperandClass oc, const char* d)
+    {
+        opClass.push_back(oc);
+        desc.push_back(d);
+    }
+    OperandClass getClass(int op) const { return opClass[op]; }
+    const char* getDesc(int op) const { return desc[op]; }
+    int getNum() const { return (int)opClass.size(); }
+
+protected:
+    std::vector<OperandClass> opClass;
+    std::vector<const char*> desc;
+};
+
+// Parameterize an enumerant
+class EnumParameters {
+public:
+    EnumParameters() : desc(0) { }
+    EnumCaps caps;
+    const char* desc;
+};
+
+// Parameterize a set of enumerants that form an enum
+class EnumDefinition : public EnumParameters {
+public:
+    EnumDefinition() : 
+        ceiling(0), bitmask(false), getName(0), enumParams(0), operandParams(0) { }
+    void set(int ceil, const char* (*name)(int), EnumParameters* ep, bool mask = false)
+    {
+        ceiling = ceil;
+        getName = name;
+        bitmask = mask;
+        enumParams = ep;
+    }
+    void setOperands(OperandParameters* op) { operandParams = op; }
+    int ceiling;   // ceiling of enumerants
+    bool bitmask;  // true if these enumerants combine into a bitmask
+    const char* (*getName)(int);      // a function that returns the name for each enumerant value (or shift)
+    EnumParameters* enumParams;       // parameters for each individual enumerant
+    OperandParameters* operandParams; // sets of operands
+};
+
+// Parameterize an instruction's logical format, including its known set of operands,
+// per OperandParameters above.
+class InstructionParameters {
+public:
+    InstructionParameters() :
+        typePresent(true),         // most normal, only exceptions have to be spelled out
+        resultPresent(true),       // most normal, only exceptions have to be spelled out
+        opDesc(0),
+        opClass(OpClassMisc)
+    { }
+
+    void setResultAndType(bool r, bool t)
+    {
+        resultPresent = r;
+        typePresent = t;
+    }
+
+    bool hasResult() const { return resultPresent != 0; }
+    bool hasType()   const { return typePresent != 0; }
+
+    const char* opDesc;
+    EnumCaps capabilities;
+    OpcodeClass opClass;
+    OperandParameters operands;
+
+protected:
+    int typePresent   : 1;
+    int resultPresent : 1;
+};
+
+const int OpcodeCeiling = 267;
+
+// The set of objects that hold all the instruction/operand
+// parameterization information.
+extern InstructionParameters InstructionDesc[];
+
+// These hold definitions of the enumerants used for operands
+extern EnumDefinition OperandClassParams[];
+
+const char* GetOperandDesc(OperandClass operand);
+void PrintImmediateRow(int imm, const char* name, const EnumParameters* enumParams, bool caps, bool hex = false);
+const char* AccessQualifierString(int attr);
+
+void PrintOperands(const OperandParameters& operands, int reservedOperands);
+
+};  // end namespace spv
index f3d18a3..dc1e579 100644 (file)
-/*\r
-** Copyright (c) 2015 The Khronos Group Inc.\r
-**\r
-** Permission is hereby granted, free of charge, to any person obtaining a copy\r
-** of this software and/or associated documentation files (the "Materials"),\r
-** to deal in the Materials without restriction, including without limitation\r
-** the rights to use, copy, modify, merge, publish, distribute, sublicense,\r
-** and/or sell copies of the Materials, and to permit persons to whom the\r
-** Materials are furnished to do so, subject to the following conditions:\r
-**\r
-** The above copyright notice and this permission notice shall be included in\r
-** all copies or substantial portions of the Materials.\r
-**\r
-** MODIFICATIONS TO THIS FILE MAY MEAN IT NO LONGER ACCURATELY REFLECTS KHRONOS\r
-** STANDARDS. THE UNMODIFIED, NORMATIVE VERSIONS OF KHRONOS SPECIFICATIONS AND\r
-** HEADER INFORMATION ARE LOCATED AT https://www.khronos.org/registry/ \r
-**\r
-** THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS\r
-** OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\r
-** FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL\r
-** THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\r
-** LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\r
-** FROM,OUT OF OR IN CONNECTION WITH THE MATERIALS OR THE USE OR OTHER DEALINGS\r
-** IN THE MATERIALS.\r
-*/\r
-\r
-/*\r
-** This header is automatically generated by the same tool that creates\r
-** the Binary Section of the SPIR-V specification.\r
-*/\r
-\r
-/*\r
-** Specification revision 30.\r
-** Enumeration tokens for SPIR-V, in three styles: C, C++, generic.\r
-** - C++ will have the tokens in the "spv" name space, with no prefix.\r
-** - C will have tokens with as "Spv" prefix.\r
-**\r
-** Some tokens act like mask values, which can be OR'd together,\r
-** while others are mutually exclusive.  The mask-like ones have\r
-** "Mask" in their name, and a parallel enum that has the shift\r
-** amount (1 << x) for each corresponding enumerant.\r
-*/\r
-\r
-#ifndef spirv_H\r
-#define spirv_H\r
-\r
-#ifdef __cplusplus\r
-\r
-namespace spv {\r
-\r
-const int MagicNumber = 0x07230203;\r
-const int Version = 99;\r
-\r
-typedef unsigned int Id;\r
-\r
-const unsigned int OpCodeMask = 0xFFFF;\r
-const unsigned int WordCountShift = 16;\r
-\r
-enum SourceLanguage {\r
-    SourceLanguageUnknown = 0,\r
-    SourceLanguageESSL = 1,\r
-    SourceLanguageGLSL = 2,\r
-    SourceLanguageOpenCL = 3,\r
-};\r
-\r
-enum ExecutionModel {\r
-    ExecutionModelVertex = 0,\r
-    ExecutionModelTessellationControl = 1,\r
-    ExecutionModelTessellationEvaluation = 2,\r
-    ExecutionModelGeometry = 3,\r
-    ExecutionModelFragment = 4,\r
-    ExecutionModelGLCompute = 5,\r
-    ExecutionModelKernel = 6,\r
-};\r
-\r
-enum AddressingModel {\r
-    AddressingModelLogical = 0,\r
-    AddressingModelPhysical32 = 1,\r
-    AddressingModelPhysical64 = 2,\r
-};\r
-\r
-enum MemoryModel {\r
-    MemoryModelSimple = 0,\r
-    MemoryModelGLSL450 = 1,\r
-    MemoryModelOpenCL12 = 2,\r
-    MemoryModelOpenCL20 = 3,\r
-    MemoryModelOpenCL21 = 4,\r
-};\r
-\r
-enum ExecutionMode {\r
-    ExecutionModeInvocations = 0,\r
-    ExecutionModeSpacingEqual = 1,\r
-    ExecutionModeSpacingFractionalEven = 2,\r
-    ExecutionModeSpacingFractionalOdd = 3,\r
-    ExecutionModeVertexOrderCw = 4,\r
-    ExecutionModeVertexOrderCcw = 5,\r
-    ExecutionModePixelCenterInteger = 6,\r
-    ExecutionModeOriginUpperLeft = 7,\r
-    ExecutionModeEarlyFragmentTests = 8,\r
-    ExecutionModePointMode = 9,\r
-    ExecutionModeXfb = 10,\r
-    ExecutionModeDepthReplacing = 11,\r
-    ExecutionModeDepthAny = 12,\r
-    ExecutionModeDepthGreater = 13,\r
-    ExecutionModeDepthLess = 14,\r
-    ExecutionModeDepthUnchanged = 15,\r
-    ExecutionModeLocalSize = 16,\r
-    ExecutionModeLocalSizeHint = 17,\r
-    ExecutionModeInputPoints = 18,\r
-    ExecutionModeInputLines = 19,\r
-    ExecutionModeInputLinesAdjacency = 20,\r
-    ExecutionModeInputTriangles = 21,\r
-    ExecutionModeInputTrianglesAdjacency = 22,\r
-    ExecutionModeInputQuads = 23,\r
-    ExecutionModeInputIsolines = 24,\r
-    ExecutionModeOutputVertices = 25,\r
-    ExecutionModeOutputPoints = 26,\r
-    ExecutionModeOutputLineStrip = 27,\r
-    ExecutionModeOutputTriangleStrip = 28,\r
-    ExecutionModeVecTypeHint = 29,\r
-    ExecutionModeContractionOff = 30,\r
-};\r
-\r
-enum StorageClass {\r
-    StorageClassUniformConstant = 0,\r
-    StorageClassInput = 1,\r
-    StorageClassUniform = 2,\r
-    StorageClassOutput = 3,\r
-    StorageClassWorkgroupLocal = 4,\r
-    StorageClassWorkgroupGlobal = 5,\r
-    StorageClassPrivateGlobal = 6,\r
-    StorageClassFunction = 7,\r
-    StorageClassGeneric = 8,\r
-    StorageClassPrivate = 9,\r
-    StorageClassAtomicCounter = 10,\r
-};\r
-\r
-enum Dim {\r
-    Dim1D = 0,\r
-    Dim2D = 1,\r
-    Dim3D = 2,\r
-    DimCube = 3,\r
-    DimRect = 4,\r
-    DimBuffer = 5,\r
-};\r
-\r
-enum SamplerAddressingMode {\r
-    SamplerAddressingModeNone = 0,\r
-    SamplerAddressingModeClampToEdge = 1,\r
-    SamplerAddressingModeClamp = 2,\r
-    SamplerAddressingModeRepeat = 3,\r
-    SamplerAddressingModeRepeatMirrored = 4,\r
-};\r
-\r
-enum SamplerFilterMode {\r
-    SamplerFilterModeNearest = 0,\r
-    SamplerFilterModeLinear = 1,\r
-};\r
-\r
-enum FPFastMathModeShift {\r
-    FPFastMathModeNotNaNShift = 0,\r
-    FPFastMathModeNotInfShift = 1,\r
-    FPFastMathModeNSZShift = 2,\r
-    FPFastMathModeAllowRecipShift = 3,\r
-    FPFastMathModeFastShift = 4,\r
-};\r
-\r
-enum FPFastMathModeMask {\r
-    FPFastMathModeMaskNone = 0,\r
-    FPFastMathModeNotNaNMask = 0x00000001,\r
-    FPFastMathModeNotInfMask = 0x00000002,\r
-    FPFastMathModeNSZMask = 0x00000004,\r
-    FPFastMathModeAllowRecipMask = 0x00000008,\r
-    FPFastMathModeFastMask = 0x00000010,\r
-};\r
-\r
-enum FPRoundingMode {\r
-    FPRoundingModeRTE = 0,\r
-    FPRoundingModeRTZ = 1,\r
-    FPRoundingModeRTP = 2,\r
-    FPRoundingModeRTN = 3,\r
-};\r
-\r
-enum LinkageType {\r
-    LinkageTypeExport = 0,\r
-    LinkageTypeImport = 1,\r
-};\r
-\r
-enum AccessQualifier {\r
-    AccessQualifierReadOnly = 0,\r
-    AccessQualifierWriteOnly = 1,\r
-    AccessQualifierReadWrite = 2,\r
-};\r
-\r
-enum FunctionParameterAttribute {\r
-    FunctionParameterAttributeZext = 0,\r
-    FunctionParameterAttributeSext = 1,\r
-    FunctionParameterAttributeByVal = 2,\r
-    FunctionParameterAttributeSret = 3,\r
-    FunctionParameterAttributeNoAlias = 4,\r
-    FunctionParameterAttributeNoCapture = 5,\r
-    FunctionParameterAttributeSVM = 6,\r
-    FunctionParameterAttributeNoWrite = 7,\r
-    FunctionParameterAttributeNoReadWrite = 8,\r
-};\r
-\r
-enum Decoration {\r
-    DecorationPrecisionLow = 0,\r
-    DecorationPrecisionMedium = 1,\r
-    DecorationPrecisionHigh = 2,\r
-    DecorationBlock = 3,\r
-    DecorationBufferBlock = 4,\r
-    DecorationRowMajor = 5,\r
-    DecorationColMajor = 6,\r
-    DecorationGLSLShared = 7,\r
-    DecorationGLSLStd140 = 8,\r
-    DecorationGLSLStd430 = 9,\r
-    DecorationGLSLPacked = 10,\r
-    DecorationSmooth = 11,\r
-    DecorationNoperspective = 12,\r
-    DecorationFlat = 13,\r
-    DecorationPatch = 14,\r
-    DecorationCentroid = 15,\r
-    DecorationSample = 16,\r
-    DecorationInvariant = 17,\r
-    DecorationRestrict = 18,\r
-    DecorationAliased = 19,\r
-    DecorationVolatile = 20,\r
-    DecorationConstant = 21,\r
-    DecorationCoherent = 22,\r
-    DecorationNonwritable = 23,\r
-    DecorationNonreadable = 24,\r
-    DecorationUniform = 25,\r
-    DecorationNoStaticUse = 26,\r
-    DecorationCPacked = 27,\r
-    DecorationSaturatedConversion = 28,\r
-    DecorationStream = 29,\r
-    DecorationLocation = 30,\r
-    DecorationComponent = 31,\r
-    DecorationIndex = 32,\r
-    DecorationBinding = 33,\r
-    DecorationDescriptorSet = 34,\r
-    DecorationOffset = 35,\r
-    DecorationAlignment = 36,\r
-    DecorationXfbBuffer = 37,\r
-    DecorationStride = 38,\r
-    DecorationBuiltIn = 39,\r
-    DecorationFuncParamAttr = 40,\r
-    DecorationFPRoundingMode = 41,\r
-    DecorationFPFastMathMode = 42,\r
-    DecorationLinkageAttributes = 43,\r
-    DecorationSpecId = 44,\r
-};\r
-\r
-enum BuiltIn {\r
-    BuiltInPosition = 0,\r
-    BuiltInPointSize = 1,\r
-    BuiltInClipVertex = 2,\r
-    BuiltInClipDistance = 3,\r
-    BuiltInCullDistance = 4,\r
-    BuiltInVertexId = 5,\r
-    BuiltInInstanceId = 6,\r
-    BuiltInPrimitiveId = 7,\r
-    BuiltInInvocationId = 8,\r
-    BuiltInLayer = 9,\r
-    BuiltInViewportIndex = 10,\r
-    BuiltInTessLevelOuter = 11,\r
-    BuiltInTessLevelInner = 12,\r
-    BuiltInTessCoord = 13,\r
-    BuiltInPatchVertices = 14,\r
-    BuiltInFragCoord = 15,\r
-    BuiltInPointCoord = 16,\r
-    BuiltInFrontFacing = 17,\r
-    BuiltInSampleId = 18,\r
-    BuiltInSamplePosition = 19,\r
-    BuiltInSampleMask = 20,\r
-    BuiltInFragColor = 21,\r
-    BuiltInFragDepth = 22,\r
-    BuiltInHelperInvocation = 23,\r
-    BuiltInNumWorkgroups = 24,\r
-    BuiltInWorkgroupSize = 25,\r
-    BuiltInWorkgroupId = 26,\r
-    BuiltInLocalInvocationId = 27,\r
-    BuiltInGlobalInvocationId = 28,\r
-    BuiltInLocalInvocationIndex = 29,\r
-    BuiltInWorkDim = 30,\r
-    BuiltInGlobalSize = 31,\r
-    BuiltInEnqueuedWorkgroupSize = 32,\r
-    BuiltInGlobalOffset = 33,\r
-    BuiltInGlobalLinearId = 34,\r
-    BuiltInWorkgroupLinearId = 35,\r
-    BuiltInSubgroupSize = 36,\r
-    BuiltInSubgroupMaxSize = 37,\r
-    BuiltInNumSubgroups = 38,\r
-    BuiltInNumEnqueuedSubgroups = 39,\r
-    BuiltInSubgroupId = 40,\r
-    BuiltInSubgroupLocalInvocationId = 41,\r
-};\r
-\r
-enum SelectionControlShift {\r
-    SelectionControlFlattenShift = 0,\r
-    SelectionControlDontFlattenShift = 1,\r
-};\r
-\r
-enum SelectionControlMask {\r
-    SelectionControlMaskNone = 0,\r
-    SelectionControlFlattenMask = 0x00000001,\r
-    SelectionControlDontFlattenMask = 0x00000002,\r
-};\r
-\r
-enum LoopControlShift {\r
-    LoopControlUnrollShift = 0,\r
-    LoopControlDontUnrollShift = 1,\r
-};\r
-\r
-enum LoopControlMask {\r
-    LoopControlMaskNone = 0,\r
-    LoopControlUnrollMask = 0x00000001,\r
-    LoopControlDontUnrollMask = 0x00000002,\r
-};\r
-\r
-enum FunctionControlShift {\r
-    FunctionControlInlineShift = 0,\r
-    FunctionControlDontInlineShift = 1,\r
-    FunctionControlPureShift = 2,\r
-    FunctionControlConstShift = 3,\r
-};\r
-\r
-enum FunctionControlMask {\r
-    FunctionControlMaskNone = 0,\r
-    FunctionControlInlineMask = 0x00000001,\r
-    FunctionControlDontInlineMask = 0x00000002,\r
-    FunctionControlPureMask = 0x00000004,\r
-    FunctionControlConstMask = 0x00000008,\r
-};\r
-\r
-enum MemorySemanticsShift {\r
-    MemorySemanticsRelaxedShift = 0,\r
-    MemorySemanticsSequentiallyConsistentShift = 1,\r
-    MemorySemanticsAcquireShift = 2,\r
-    MemorySemanticsReleaseShift = 3,\r
-    MemorySemanticsUniformMemoryShift = 4,\r
-    MemorySemanticsSubgroupMemoryShift = 5,\r
-    MemorySemanticsWorkgroupLocalMemoryShift = 6,\r
-    MemorySemanticsWorkgroupGlobalMemoryShift = 7,\r
-    MemorySemanticsAtomicCounterMemoryShift = 8,\r
-    MemorySemanticsImageMemoryShift = 9,\r
-};\r
-\r
-enum MemorySemanticsMask {\r
-    MemorySemanticsMaskNone = 0,\r
-    MemorySemanticsRelaxedMask = 0x00000001,\r
-    MemorySemanticsSequentiallyConsistentMask = 0x00000002,\r
-    MemorySemanticsAcquireMask = 0x00000004,\r
-    MemorySemanticsReleaseMask = 0x00000008,\r
-    MemorySemanticsUniformMemoryMask = 0x00000010,\r
-    MemorySemanticsSubgroupMemoryMask = 0x00000020,\r
-    MemorySemanticsWorkgroupLocalMemoryMask = 0x00000040,\r
-    MemorySemanticsWorkgroupGlobalMemoryMask = 0x00000080,\r
-    MemorySemanticsAtomicCounterMemoryMask = 0x00000100,\r
-    MemorySemanticsImageMemoryMask = 0x00000200,\r
-};\r
-\r
-enum MemoryAccessShift {\r
-    MemoryAccessVolatileShift = 0,\r
-    MemoryAccessAlignedShift = 1,\r
-};\r
-\r
-enum MemoryAccessMask {\r
-    MemoryAccessMaskNone = 0,\r
-    MemoryAccessVolatileMask = 0x00000001,\r
-    MemoryAccessAlignedMask = 0x00000002,\r
-};\r
-\r
-enum ExecutionScope {\r
-    ExecutionScopeCrossDevice = 0,\r
-    ExecutionScopeDevice = 1,\r
-    ExecutionScopeWorkgroup = 2,\r
-    ExecutionScopeSubgroup = 3,\r
-};\r
-\r
-enum GroupOperation {\r
-    GroupOperationReduce = 0,\r
-    GroupOperationInclusiveScan = 1,\r
-    GroupOperationExclusiveScan = 2,\r
-};\r
-\r
-enum KernelEnqueueFlags {\r
-    KernelEnqueueFlagsNoWait = 0,\r
-    KernelEnqueueFlagsWaitKernel = 1,\r
-    KernelEnqueueFlagsWaitWorkGroup = 2,\r
-};\r
-\r
-enum KernelProfilingInfoShift {\r
-    KernelProfilingInfoCmdExecTimeShift = 0,\r
-};\r
-\r
-enum KernelProfilingInfoMask {\r
-    KernelProfilingInfoMaskNone = 0,\r
-    KernelProfilingInfoCmdExecTimeMask = 0x00000001,\r
-};\r
-\r
-enum Op {\r
-    OpNop = 0,\r
-    OpSource = 1,\r
-    OpSourceExtension = 2,\r
-    OpExtension = 3,\r
-    OpExtInstImport = 4,\r
-    OpMemoryModel = 5,\r
-    OpEntryPoint = 6,\r
-    OpExecutionMode = 7,\r
-    OpTypeVoid = 8,\r
-    OpTypeBool = 9,\r
-    OpTypeInt = 10,\r
-    OpTypeFloat = 11,\r
-    OpTypeVector = 12,\r
-    OpTypeMatrix = 13,\r
-    OpTypeSampler = 14,\r
-    OpTypeFilter = 15,\r
-    OpTypeArray = 16,\r
-    OpTypeRuntimeArray = 17,\r
-    OpTypeStruct = 18,\r
-    OpTypeOpaque = 19,\r
-    OpTypePointer = 20,\r
-    OpTypeFunction = 21,\r
-    OpTypeEvent = 22,\r
-    OpTypeDeviceEvent = 23,\r
-    OpTypeReserveId = 24,\r
-    OpTypeQueue = 25,\r
-    OpTypePipe = 26,\r
-    OpConstantTrue = 27,\r
-    OpConstantFalse = 28,\r
-    OpConstant = 29,\r
-    OpConstantComposite = 30,\r
-    OpConstantSampler = 31,\r
-    OpConstantNullPointer = 32,\r
-    OpConstantNullObject = 33,\r
-    OpSpecConstantTrue = 34,\r
-    OpSpecConstantFalse = 35,\r
-    OpSpecConstant = 36,\r
-    OpSpecConstantComposite = 37,\r
-    OpVariable = 38,\r
-    OpVariableArray = 39,\r
-    OpFunction = 40,\r
-    OpFunctionParameter = 41,\r
-    OpFunctionEnd = 42,\r
-    OpFunctionCall = 43,\r
-    OpExtInst = 44,\r
-    OpUndef = 45,\r
-    OpLoad = 46,\r
-    OpStore = 47,\r
-    OpPhi = 48,\r
-    OpDecorationGroup = 49,\r
-    OpDecorate = 50,\r
-    OpMemberDecorate = 51,\r
-    OpGroupDecorate = 52,\r
-    OpGroupMemberDecorate = 53,\r
-    OpName = 54,\r
-    OpMemberName = 55,\r
-    OpString = 56,\r
-    OpLine = 57,\r
-    OpVectorExtractDynamic = 58,\r
-    OpVectorInsertDynamic = 59,\r
-    OpVectorShuffle = 60,\r
-    OpCompositeConstruct = 61,\r
-    OpCompositeExtract = 62,\r
-    OpCompositeInsert = 63,\r
-    OpCopyObject = 64,\r
-    OpCopyMemory = 65,\r
-    OpCopyMemorySized = 66,\r
-    OpSampler = 67,\r
-    OpTextureSample = 68,\r
-    OpTextureSampleDref = 69,\r
-    OpTextureSampleLod = 70,\r
-    OpTextureSampleProj = 71,\r
-    OpTextureSampleGrad = 72,\r
-    OpTextureSampleOffset = 73,\r
-    OpTextureSampleProjLod = 74,\r
-    OpTextureSampleProjGrad = 75,\r
-    OpTextureSampleLodOffset = 76,\r
-    OpTextureSampleProjOffset = 77,\r
-    OpTextureSampleGradOffset = 78,\r
-    OpTextureSampleProjLodOffset = 79,\r
-    OpTextureSampleProjGradOffset = 80,\r
-    OpTextureFetchTexelLod = 81,\r
-    OpTextureFetchTexelOffset = 82,\r
-    OpTextureFetchSample = 83,\r
-    OpTextureFetchTexel = 84,\r
-    OpTextureGather = 85,\r
-    OpTextureGatherOffset = 86,\r
-    OpTextureGatherOffsets = 87,\r
-    OpTextureQuerySizeLod = 88,\r
-    OpTextureQuerySize = 89,\r
-    OpTextureQueryLod = 90,\r
-    OpTextureQueryLevels = 91,\r
-    OpTextureQuerySamples = 92,\r
-    OpAccessChain = 93,\r
-    OpInBoundsAccessChain = 94,\r
-    OpSNegate = 95,\r
-    OpFNegate = 96,\r
-    OpNot = 97,\r
-    OpAny = 98,\r
-    OpAll = 99,\r
-    OpConvertFToU = 100,\r
-    OpConvertFToS = 101,\r
-    OpConvertSToF = 102,\r
-    OpConvertUToF = 103,\r
-    OpUConvert = 104,\r
-    OpSConvert = 105,\r
-    OpFConvert = 106,\r
-    OpConvertPtrToU = 107,\r
-    OpConvertUToPtr = 108,\r
-    OpPtrCastToGeneric = 109,\r
-    OpGenericCastToPtr = 110,\r
-    OpBitcast = 111,\r
-    OpTranspose = 112,\r
-    OpIsNan = 113,\r
-    OpIsInf = 114,\r
-    OpIsFinite = 115,\r
-    OpIsNormal = 116,\r
-    OpSignBitSet = 117,\r
-    OpLessOrGreater = 118,\r
-    OpOrdered = 119,\r
-    OpUnordered = 120,\r
-    OpArrayLength = 121,\r
-    OpIAdd = 122,\r
-    OpFAdd = 123,\r
-    OpISub = 124,\r
-    OpFSub = 125,\r
-    OpIMul = 126,\r
-    OpFMul = 127,\r
-    OpUDiv = 128,\r
-    OpSDiv = 129,\r
-    OpFDiv = 130,\r
-    OpUMod = 131,\r
-    OpSRem = 132,\r
-    OpSMod = 133,\r
-    OpFRem = 134,\r
-    OpFMod = 135,\r
-    OpVectorTimesScalar = 136,\r
-    OpMatrixTimesScalar = 137,\r
-    OpVectorTimesMatrix = 138,\r
-    OpMatrixTimesVector = 139,\r
-    OpMatrixTimesMatrix = 140,\r
-    OpOuterProduct = 141,\r
-    OpDot = 142,\r
-    OpShiftRightLogical = 143,\r
-    OpShiftRightArithmetic = 144,\r
-    OpShiftLeftLogical = 145,\r
-    OpLogicalOr = 146,\r
-    OpLogicalXor = 147,\r
-    OpLogicalAnd = 148,\r
-    OpBitwiseOr = 149,\r
-    OpBitwiseXor = 150,\r
-    OpBitwiseAnd = 151,\r
-    OpSelect = 152,\r
-    OpIEqual = 153,\r
-    OpFOrdEqual = 154,\r
-    OpFUnordEqual = 155,\r
-    OpINotEqual = 156,\r
-    OpFOrdNotEqual = 157,\r
-    OpFUnordNotEqual = 158,\r
-    OpULessThan = 159,\r
-    OpSLessThan = 160,\r
-    OpFOrdLessThan = 161,\r
-    OpFUnordLessThan = 162,\r
-    OpUGreaterThan = 163,\r
-    OpSGreaterThan = 164,\r
-    OpFOrdGreaterThan = 165,\r
-    OpFUnordGreaterThan = 166,\r
-    OpULessThanEqual = 167,\r
-    OpSLessThanEqual = 168,\r
-    OpFOrdLessThanEqual = 169,\r
-    OpFUnordLessThanEqual = 170,\r
-    OpUGreaterThanEqual = 171,\r
-    OpSGreaterThanEqual = 172,\r
-    OpFOrdGreaterThanEqual = 173,\r
-    OpFUnordGreaterThanEqual = 174,\r
-    OpDPdx = 175,\r
-    OpDPdy = 176,\r
-    OpFwidth = 177,\r
-    OpDPdxFine = 178,\r
-    OpDPdyFine = 179,\r
-    OpFwidthFine = 180,\r
-    OpDPdxCoarse = 181,\r
-    OpDPdyCoarse = 182,\r
-    OpFwidthCoarse = 183,\r
-    OpEmitVertex = 184,\r
-    OpEndPrimitive = 185,\r
-    OpEmitStreamVertex = 186,\r
-    OpEndStreamPrimitive = 187,\r
-    OpControlBarrier = 188,\r
-    OpMemoryBarrier = 189,\r
-    OpImagePointer = 190,\r
-    OpAtomicInit = 191,\r
-    OpAtomicLoad = 192,\r
-    OpAtomicStore = 193,\r
-    OpAtomicExchange = 194,\r
-    OpAtomicCompareExchange = 195,\r
-    OpAtomicCompareExchangeWeak = 196,\r
-    OpAtomicIIncrement = 197,\r
-    OpAtomicIDecrement = 198,\r
-    OpAtomicIAdd = 199,\r
-    OpAtomicISub = 200,\r
-    OpAtomicUMin = 201,\r
-    OpAtomicUMax = 202,\r
-    OpAtomicAnd = 203,\r
-    OpAtomicOr = 204,\r
-    OpAtomicXor = 205,\r
-    OpLoopMerge = 206,\r
-    OpSelectionMerge = 207,\r
-    OpLabel = 208,\r
-    OpBranch = 209,\r
-    OpBranchConditional = 210,\r
-    OpSwitch = 211,\r
-    OpKill = 212,\r
-    OpReturn = 213,\r
-    OpReturnValue = 214,\r
-    OpUnreachable = 215,\r
-    OpLifetimeStart = 216,\r
-    OpLifetimeStop = 217,\r
-    OpCompileFlag = 218,\r
-    OpAsyncGroupCopy = 219,\r
-    OpWaitGroupEvents = 220,\r
-    OpGroupAll = 221,\r
-    OpGroupAny = 222,\r
-    OpGroupBroadcast = 223,\r
-    OpGroupIAdd = 224,\r
-    OpGroupFAdd = 225,\r
-    OpGroupFMin = 226,\r
-    OpGroupUMin = 227,\r
-    OpGroupSMin = 228,\r
-    OpGroupFMax = 229,\r
-    OpGroupUMax = 230,\r
-    OpGroupSMax = 231,\r
-    OpGenericCastToPtrExplicit = 232,\r
-    OpGenericPtrMemSemantics = 233,\r
-    OpReadPipe = 234,\r
-    OpWritePipe = 235,\r
-    OpReservedReadPipe = 236,\r
-    OpReservedWritePipe = 237,\r
-    OpReserveReadPipePackets = 238,\r
-    OpReserveWritePipePackets = 239,\r
-    OpCommitReadPipe = 240,\r
-    OpCommitWritePipe = 241,\r
-    OpIsValidReserveId = 242,\r
-    OpGetNumPipePackets = 243,\r
-    OpGetMaxPipePackets = 244,\r
-    OpGroupReserveReadPipePackets = 245,\r
-    OpGroupReserveWritePipePackets = 246,\r
-    OpGroupCommitReadPipe = 247,\r
-    OpGroupCommitWritePipe = 248,\r
-    OpEnqueueMarker = 249,\r
-    OpEnqueueKernel = 250,\r
-    OpGetKernelNDrangeSubGroupCount = 251,\r
-    OpGetKernelNDrangeMaxSubGroupSize = 252,\r
-    OpGetKernelWorkGroupSize = 253,\r
-    OpGetKernelPreferredWorkGroupSizeMultiple = 254,\r
-    OpRetainEvent = 255,\r
-    OpReleaseEvent = 256,\r
-    OpCreateUserEvent = 257,\r
-    OpIsValidEvent = 258,\r
-    OpSetUserEventStatus = 259,\r
-    OpCaptureEventProfilingInfo = 260,\r
-    OpGetDefaultQueue = 261,\r
-    OpBuildNDRange = 262,\r
-    OpSatConvertSToU = 263,\r
-    OpSatConvertUToS = 264,\r
-    OpAtomicIMin = 265,\r
-    OpAtomicIMax = 266,\r
-};\r
-\r
-};  // end namespace spv\r
-\r
-#endif  // #ifdef __cplusplus\r
-\r
-\r
-#ifndef __cplusplus\r
-\r
-const int SpvMagicNumber = 0x07230203;\r
-const int SpvVersion = 99;\r
-\r
-typedef unsigned int SpvId;\r
-\r
-const unsigned int SpvOpCodeMask = 0xFFFF;\r
-const unsigned int SpvWordCountShift = 16;\r
-\r
-typedef enum SpvSourceLanguage_ {\r
-    SpvSourceLanguageUnknown = 0,\r
-    SpvSourceLanguageESSL = 1,\r
-    SpvSourceLanguageGLSL = 2,\r
-    SpvSourceLanguageOpenCL = 3,\r
-} SpvSourceLanguage;\r
-\r
-typedef enum SpvExecutionModel_ {\r
-    SpvExecutionModelVertex = 0,\r
-    SpvExecutionModelTessellationControl = 1,\r
-    SpvExecutionModelTessellationEvaluation = 2,\r
-    SpvExecutionModelGeometry = 3,\r
-    SpvExecutionModelFragment = 4,\r
-    SpvExecutionModelGLCompute = 5,\r
-    SpvExecutionModelKernel = 6,\r
-} SpvExecutionModel;\r
-\r
-typedef enum SpvAddressingModel_ {\r
-    SpvAddressingModelLogical = 0,\r
-    SpvAddressingModelPhysical32 = 1,\r
-    SpvAddressingModelPhysical64 = 2,\r
-} SpvAddressingModel;\r
-\r
-typedef enum SpvMemoryModel_ {\r
-    SpvMemoryModelSimple = 0,\r
-    SpvMemoryModelGLSL450 = 1,\r
-    SpvMemoryModelOpenCL12 = 2,\r
-    SpvMemoryModelOpenCL20 = 3,\r
-    SpvMemoryModelOpenCL21 = 4,\r
-} SpvMemoryModel;\r
-\r
-typedef enum SpvExecutionMode_ {\r
-    SpvExecutionModeInvocations = 0,\r
-    SpvExecutionModeSpacingEqual = 1,\r
-    SpvExecutionModeSpacingFractionalEven = 2,\r
-    SpvExecutionModeSpacingFractionalOdd = 3,\r
-    SpvExecutionModeVertexOrderCw = 4,\r
-    SpvExecutionModeVertexOrderCcw = 5,\r
-    SpvExecutionModePixelCenterInteger = 6,\r
-    SpvExecutionModeOriginUpperLeft = 7,\r
-    SpvExecutionModeEarlyFragmentTests = 8,\r
-    SpvExecutionModePointMode = 9,\r
-    SpvExecutionModeXfb = 10,\r
-    SpvExecutionModeDepthReplacing = 11,\r
-    SpvExecutionModeDepthAny = 12,\r
-    SpvExecutionModeDepthGreater = 13,\r
-    SpvExecutionModeDepthLess = 14,\r
-    SpvExecutionModeDepthUnchanged = 15,\r
-    SpvExecutionModeLocalSize = 16,\r
-    SpvExecutionModeLocalSizeHint = 17,\r
-    SpvExecutionModeInputPoints = 18,\r
-    SpvExecutionModeInputLines = 19,\r
-    SpvExecutionModeInputLinesAdjacency = 20,\r
-    SpvExecutionModeInputTriangles = 21,\r
-    SpvExecutionModeInputTrianglesAdjacency = 22,\r
-    SpvExecutionModeInputQuads = 23,\r
-    SpvExecutionModeInputIsolines = 24,\r
-    SpvExecutionModeOutputVertices = 25,\r
-    SpvExecutionModeOutputPoints = 26,\r
-    SpvExecutionModeOutputLineStrip = 27,\r
-    SpvExecutionModeOutputTriangleStrip = 28,\r
-    SpvExecutionModeVecTypeHint = 29,\r
-    SpvExecutionModeContractionOff = 30,\r
-} SpvExecutionMode;\r
-\r
-typedef enum SpvStorageClass_ {\r
-    SpvStorageClassUniformConstant = 0,\r
-    SpvStorageClassInput = 1,\r
-    SpvStorageClassUniform = 2,\r
-    SpvStorageClassOutput = 3,\r
-    SpvStorageClassWorkgroupLocal = 4,\r
-    SpvStorageClassWorkgroupGlobal = 5,\r
-    SpvStorageClassPrivateGlobal = 6,\r
-    SpvStorageClassFunction = 7,\r
-    SpvStorageClassGeneric = 8,\r
-    SpvStorageClassPrivate = 9,\r
-    SpvStorageClassAtomicCounter = 10,\r
-} SpvStorageClass;\r
-\r
-typedef enum SpvDim_ {\r
-    SpvDim1D = 0,\r
-    SpvDim2D = 1,\r
-    SpvDim3D = 2,\r
-    SpvDimCube = 3,\r
-    SpvDimRect = 4,\r
-    SpvDimBuffer = 5,\r
-} SpvDim;\r
-\r
-typedef enum SpvSamplerAddressingMode_ {\r
-    SpvSamplerAddressingModeNone = 0,\r
-    SpvSamplerAddressingModeClampToEdge = 1,\r
-    SpvSamplerAddressingModeClamp = 2,\r
-    SpvSamplerAddressingModeRepeat = 3,\r
-    SpvSamplerAddressingModeRepeatMirrored = 4,\r
-} SpvSamplerAddressingMode;\r
-\r
-typedef enum SpvSamplerFilterMode_ {\r
-    SpvSamplerFilterModeNearest = 0,\r
-    SpvSamplerFilterModeLinear = 1,\r
-} SpvSamplerFilterMode;\r
-\r
-typedef enum SpvFPFastMathModeShift_ {\r
-    SpvFPFastMathModeNotNaNShift = 0,\r
-    SpvFPFastMathModeNotInfShift = 1,\r
-    SpvFPFastMathModeNSZShift = 2,\r
-    SpvFPFastMathModeAllowRecipShift = 3,\r
-    SpvFPFastMathModeFastShift = 4,\r
-} SpvFPFastMathModeShift;\r
-\r
-typedef enum SpvFPFastMathModeMask_ {\r
-    SpvFPFastMathModeMaskNone = 0,\r
-    SpvFPFastMathModeNotNaNMask = 0x00000001,\r
-    SpvFPFastMathModeNotInfMask = 0x00000002,\r
-    SpvFPFastMathModeNSZMask = 0x00000004,\r
-    SpvFPFastMathModeAllowRecipMask = 0x00000008,\r
-    SpvFPFastMathModeFastMask = 0x00000010,\r
-} SpvFPFastMathModeMask;\r
-\r
-typedef enum SpvFPRoundingMode_ {\r
-    SpvFPRoundingModeRTE = 0,\r
-    SpvFPRoundingModeRTZ = 1,\r
-    SpvFPRoundingModeRTP = 2,\r
-    SpvFPRoundingModeRTN = 3,\r
-} SpvFPRoundingMode;\r
-\r
-typedef enum SpvLinkageType_ {\r
-    SpvLinkageTypeExport = 0,\r
-    SpvLinkageTypeImport = 1,\r
-} SpvLinkageType;\r
-\r
-typedef enum SpvAccessQualifier_ {\r
-    SpvAccessQualifierReadOnly = 0,\r
-    SpvAccessQualifierWriteOnly = 1,\r
-    SpvAccessQualifierReadWrite = 2,\r
-} SpvAccessQualifier;\r
-\r
-typedef enum SpvFunctionParameterAttribute_ {\r
-    SpvFunctionParameterAttributeZext = 0,\r
-    SpvFunctionParameterAttributeSext = 1,\r
-    SpvFunctionParameterAttributeByVal = 2,\r
-    SpvFunctionParameterAttributeSret = 3,\r
-    SpvFunctionParameterAttributeNoAlias = 4,\r
-    SpvFunctionParameterAttributeNoCapture = 5,\r
-    SpvFunctionParameterAttributeSVM = 6,\r
-    SpvFunctionParameterAttributeNoWrite = 7,\r
-    SpvFunctionParameterAttributeNoReadWrite = 8,\r
-} SpvFunctionParameterAttribute;\r
-\r
-typedef enum SpvDecoration_ {\r
-    SpvDecorationPrecisionLow = 0,\r
-    SpvDecorationPrecisionMedium = 1,\r
-    SpvDecorationPrecisionHigh = 2,\r
-    SpvDecorationBlock = 3,\r
-    SpvDecorationBufferBlock = 4,\r
-    SpvDecorationRowMajor = 5,\r
-    SpvDecorationColMajor = 6,\r
-    SpvDecorationGLSLShared = 7,\r
-    SpvDecorationGLSLStd140 = 8,\r
-    SpvDecorationGLSLStd430 = 9,\r
-    SpvDecorationGLSLPacked = 10,\r
-    SpvDecorationSmooth = 11,\r
-    SpvDecorationNoperspective = 12,\r
-    SpvDecorationFlat = 13,\r
-    SpvDecorationPatch = 14,\r
-    SpvDecorationCentroid = 15,\r
-    SpvDecorationSample = 16,\r
-    SpvDecorationInvariant = 17,\r
-    SpvDecorationRestrict = 18,\r
-    SpvDecorationAliased = 19,\r
-    SpvDecorationVolatile = 20,\r
-    SpvDecorationConstant = 21,\r
-    SpvDecorationCoherent = 22,\r
-    SpvDecorationNonwritable = 23,\r
-    SpvDecorationNonreadable = 24,\r
-    SpvDecorationUniform = 25,\r
-    SpvDecorationNoStaticUse = 26,\r
-    SpvDecorationCPacked = 27,\r
-    SpvDecorationSaturatedConversion = 28,\r
-    SpvDecorationStream = 29,\r
-    SpvDecorationLocation = 30,\r
-    SpvDecorationComponent = 31,\r
-    SpvDecorationIndex = 32,\r
-    SpvDecorationBinding = 33,\r
-    SpvDecorationDescriptorSet = 34,\r
-    SpvDecorationOffset = 35,\r
-    SpvDecorationAlignment = 36,\r
-    SpvDecorationXfbBuffer = 37,\r
-    SpvDecorationStride = 38,\r
-    SpvDecorationBuiltIn = 39,\r
-    SpvDecorationFuncParamAttr = 40,\r
-    SpvDecorationFPRoundingMode = 41,\r
-    SpvDecorationFPFastMathMode = 42,\r
-    SpvDecorationLinkageAttributes = 43,\r
-    SpvDecorationSpecId = 44,\r
-} SpvDecoration;\r
-\r
-typedef enum SpvBuiltIn_ {\r
-    SpvBuiltInPosition = 0,\r
-    SpvBuiltInPointSize = 1,\r
-    SpvBuiltInClipVertex = 2,\r
-    SpvBuiltInClipDistance = 3,\r
-    SpvBuiltInCullDistance = 4,\r
-    SpvBuiltInVertexId = 5,\r
-    SpvBuiltInInstanceId = 6,\r
-    SpvBuiltInPrimitiveId = 7,\r
-    SpvBuiltInInvocationId = 8,\r
-    SpvBuiltInLayer = 9,\r
-    SpvBuiltInViewportIndex = 10,\r
-    SpvBuiltInTessLevelOuter = 11,\r
-    SpvBuiltInTessLevelInner = 12,\r
-    SpvBuiltInTessCoord = 13,\r
-    SpvBuiltInPatchVertices = 14,\r
-    SpvBuiltInFragCoord = 15,\r
-    SpvBuiltInPointCoord = 16,\r
-    SpvBuiltInFrontFacing = 17,\r
-    SpvBuiltInSampleId = 18,\r
-    SpvBuiltInSamplePosition = 19,\r
-    SpvBuiltInSampleMask = 20,\r
-    SpvBuiltInFragColor = 21,\r
-    SpvBuiltInFragDepth = 22,\r
-    SpvBuiltInHelperInvocation = 23,\r
-    SpvBuiltInNumWorkgroups = 24,\r
-    SpvBuiltInWorkgroupSize = 25,\r
-    SpvBuiltInWorkgroupId = 26,\r
-    SpvBuiltInLocalInvocationId = 27,\r
-    SpvBuiltInGlobalInvocationId = 28,\r
-    SpvBuiltInLocalInvocationIndex = 29,\r
-    SpvBuiltInWorkDim = 30,\r
-    SpvBuiltInGlobalSize = 31,\r
-    SpvBuiltInEnqueuedWorkgroupSize = 32,\r
-    SpvBuiltInGlobalOffset = 33,\r
-    SpvBuiltInGlobalLinearId = 34,\r
-    SpvBuiltInWorkgroupLinearId = 35,\r
-    SpvBuiltInSubgroupSize = 36,\r
-    SpvBuiltInSubgroupMaxSize = 37,\r
-    SpvBuiltInNumSubgroups = 38,\r
-    SpvBuiltInNumEnqueuedSubgroups = 39,\r
-    SpvBuiltInSubgroupId = 40,\r
-    SpvBuiltInSubgroupLocalInvocationId = 41,\r
-} SpvBuiltIn;\r
-\r
-typedef enum SpvSelectionControlShift_ {\r
-    SpvSelectionControlFlattenShift = 0,\r
-    SpvSelectionControlDontFlattenShift = 1,\r
-} SpvSelectionControlShift;\r
-\r
-typedef enum SpvSelectionControlMask_ {\r
-    SpvSelectionControlMaskNone = 0,\r
-    SpvSelectionControlFlattenMask = 0x00000001,\r
-    SpvSelectionControlDontFlattenMask = 0x00000002,\r
-} SpvSelectionControlMask;\r
-\r
-typedef enum SpvLoopControlShift_ {\r
-    SpvLoopControlUnrollShift = 0,\r
-    SpvLoopControlDontUnrollShift = 1,\r
-} SpvLoopControlShift;\r
-\r
-typedef enum SpvLoopControlMask_ {\r
-    SpvLoopControlMaskNone = 0,\r
-    SpvLoopControlUnrollMask = 0x00000001,\r
-    SpvLoopControlDontUnrollMask = 0x00000002,\r
-} SpvLoopControlMask;\r
-\r
-typedef enum SpvFunctionControlShift_ {\r
-    SpvFunctionControlInlineShift = 0,\r
-    SpvFunctionControlDontInlineShift = 1,\r
-    SpvFunctionControlPureShift = 2,\r
-    SpvFunctionControlConstShift = 3,\r
-} SpvFunctionControlShift;\r
-\r
-typedef enum SpvFunctionControlMask_ {\r
-    SpvFunctionControlMaskNone = 0,\r
-    SpvFunctionControlInlineMask = 0x00000001,\r
-    SpvFunctionControlDontInlineMask = 0x00000002,\r
-    SpvFunctionControlPureMask = 0x00000004,\r
-    SpvFunctionControlConstMask = 0x00000008,\r
-} SpvFunctionControlMask;\r
-\r
-typedef enum SpvMemorySemanticsShift_ {\r
-    SpvMemorySemanticsRelaxedShift = 0,\r
-    SpvMemorySemanticsSequentiallyConsistentShift = 1,\r
-    SpvMemorySemanticsAcquireShift = 2,\r
-    SpvMemorySemanticsReleaseShift = 3,\r
-    SpvMemorySemanticsUniformMemoryShift = 4,\r
-    SpvMemorySemanticsSubgroupMemoryShift = 5,\r
-    SpvMemorySemanticsWorkgroupLocalMemoryShift = 6,\r
-    SpvMemorySemanticsWorkgroupGlobalMemoryShift = 7,\r
-    SpvMemorySemanticsAtomicCounterMemoryShift = 8,\r
-    SpvMemorySemanticsImageMemoryShift = 9,\r
-} SpvMemorySemanticsShift;\r
-\r
-typedef enum SpvMemorySemanticsMask_ {\r
-    SpvMemorySemanticsMaskNone = 0,\r
-    SpvMemorySemanticsRelaxedMask = 0x00000001,\r
-    SpvMemorySemanticsSequentiallyConsistentMask = 0x00000002,\r
-    SpvMemorySemanticsAcquireMask = 0x00000004,\r
-    SpvMemorySemanticsReleaseMask = 0x00000008,\r
-    SpvMemorySemanticsUniformMemoryMask = 0x00000010,\r
-    SpvMemorySemanticsSubgroupMemoryMask = 0x00000020,\r
-    SpvMemorySemanticsWorkgroupLocalMemoryMask = 0x00000040,\r
-    SpvMemorySemanticsWorkgroupGlobalMemoryMask = 0x00000080,\r
-    SpvMemorySemanticsAtomicCounterMemoryMask = 0x00000100,\r
-    SpvMemorySemanticsImageMemoryMask = 0x00000200,\r
-} SpvMemorySemanticsMask;\r
-\r
-typedef enum SpvMemoryAccessShift_ {\r
-    SpvMemoryAccessVolatileShift = 0,\r
-    SpvMemoryAccessAlignedShift = 1,\r
-} SpvMemoryAccessShift;\r
-\r
-typedef enum SpvMemoryAccessMask_ {\r
-    SpvMemoryAccessMaskNone = 0,\r
-    SpvMemoryAccessVolatileMask = 0x00000001,\r
-    SpvMemoryAccessAlignedMask = 0x00000002,\r
-} SpvMemoryAccessMask;\r
-\r
-typedef enum SpvExecutionScope_ {\r
-    SpvExecutionScopeCrossDevice = 0,\r
-    SpvExecutionScopeDevice = 1,\r
-    SpvExecutionScopeWorkgroup = 2,\r
-    SpvExecutionScopeSubgroup = 3,\r
-} SpvExecutionScope;\r
-\r
-typedef enum SpvGroupOperation_ {\r
-    SpvGroupOperationReduce = 0,\r
-    SpvGroupOperationInclusiveScan = 1,\r
-    SpvGroupOperationExclusiveScan = 2,\r
-} SpvGroupOperation;\r
-\r
-typedef enum SpvKernelEnqueueFlags_ {\r
-    SpvKernelEnqueueFlagsNoWait = 0,\r
-    SpvKernelEnqueueFlagsWaitKernel = 1,\r
-    SpvKernelEnqueueFlagsWaitWorkGroup = 2,\r
-} SpvKernelEnqueueFlags;\r
-\r
-typedef enum SpvKernelProfilingInfoShift_ {\r
-    SpvKernelProfilingInfoCmdExecTimeShift = 0,\r
-} SpvKernelProfilingInfoShift;\r
-\r
-typedef enum SpvKernelProfilingInfoMask_ {\r
-    SpvKernelProfilingInfoMaskNone = 0,\r
-    SpvKernelProfilingInfoCmdExecTimeMask = 0x00000001,\r
-} SpvKernelProfilingInfoMask;\r
-\r
-typedef enum SpvOp_ {\r
-    SpvOpNop = 0,\r
-    SpvOpSource = 1,\r
-    SpvOpSourceExtension = 2,\r
-    SpvOpExtension = 3,\r
-    SpvOpExtInstImport = 4,\r
-    SpvOpMemoryModel = 5,\r
-    SpvOpEntryPoint = 6,\r
-    SpvOpExecutionMode = 7,\r
-    SpvOpTypeVoid = 8,\r
-    SpvOpTypeBool = 9,\r
-    SpvOpTypeInt = 10,\r
-    SpvOpTypeFloat = 11,\r
-    SpvOpTypeVector = 12,\r
-    SpvOpTypeMatrix = 13,\r
-    SpvOpTypeSampler = 14,\r
-    SpvOpTypeFilter = 15,\r
-    SpvOpTypeArray = 16,\r
-    SpvOpTypeRuntimeArray = 17,\r
-    SpvOpTypeStruct = 18,\r
-    SpvOpTypeOpaque = 19,\r
-    SpvOpTypePointer = 20,\r
-    SpvOpTypeFunction = 21,\r
-    SpvOpTypeEvent = 22,\r
-    SpvOpTypeDeviceEvent = 23,\r
-    SpvOpTypeReserveId = 24,\r
-    SpvOpTypeQueue = 25,\r
-    SpvOpTypePipe = 26,\r
-    SpvOpConstantTrue = 27,\r
-    SpvOpConstantFalse = 28,\r
-    SpvOpConstant = 29,\r
-    SpvOpConstantComposite = 30,\r
-    SpvOpConstantSampler = 31,\r
-    SpvOpConstantNullPointer = 32,\r
-    SpvOpConstantNullObject = 33,\r
-    SpvOpSpecConstantTrue = 34,\r
-    SpvOpSpecConstantFalse = 35,\r
-    SpvOpSpecConstant = 36,\r
-    SpvOpSpecConstantComposite = 37,\r
-    SpvOpVariable = 38,\r
-    SpvOpVariableArray = 39,\r
-    SpvOpFunction = 40,\r
-    SpvOpFunctionParameter = 41,\r
-    SpvOpFunctionEnd = 42,\r
-    SpvOpFunctionCall = 43,\r
-    SpvOpExtInst = 44,\r
-    SpvOpUndef = 45,\r
-    SpvOpLoad = 46,\r
-    SpvOpStore = 47,\r
-    SpvOpPhi = 48,\r
-    SpvOpDecorationGroup = 49,\r
-    SpvOpDecorate = 50,\r
-    SpvOpMemberDecorate = 51,\r
-    SpvOpGroupDecorate = 52,\r
-    SpvOpGroupMemberDecorate = 53,\r
-    SpvOpName = 54,\r
-    SpvOpMemberName = 55,\r
-    SpvOpString = 56,\r
-    SpvOpLine = 57,\r
-    SpvOpVectorExtractDynamic = 58,\r
-    SpvOpVectorInsertDynamic = 59,\r
-    SpvOpVectorShuffle = 60,\r
-    SpvOpCompositeConstruct = 61,\r
-    SpvOpCompositeExtract = 62,\r
-    SpvOpCompositeInsert = 63,\r
-    SpvOpCopyObject = 64,\r
-    SpvOpCopyMemory = 65,\r
-    SpvOpCopyMemorySized = 66,\r
-    SpvOpSampler = 67,\r
-    SpvOpTextureSample = 68,\r
-    SpvOpTextureSampleDref = 69,\r
-    SpvOpTextureSampleLod = 70,\r
-    SpvOpTextureSampleProj = 71,\r
-    SpvOpTextureSampleGrad = 72,\r
-    SpvOpTextureSampleOffset = 73,\r
-    SpvOpTextureSampleProjLod = 74,\r
-    SpvOpTextureSampleProjGrad = 75,\r
-    SpvOpTextureSampleLodOffset = 76,\r
-    SpvOpTextureSampleProjOffset = 77,\r
-    SpvOpTextureSampleGradOffset = 78,\r
-    SpvOpTextureSampleProjLodOffset = 79,\r
-    SpvOpTextureSampleProjGradOffset = 80,\r
-    SpvOpTextureFetchTexelLod = 81,\r
-    SpvOpTextureFetchTexelOffset = 82,\r
-    SpvOpTextureFetchSample = 83,\r
-    SpvOpTextureFetchTexel = 84,\r
-    SpvOpTextureGather = 85,\r
-    SpvOpTextureGatherOffset = 86,\r
-    SpvOpTextureGatherOffsets = 87,\r
-    SpvOpTextureQuerySizeLod = 88,\r
-    SpvOpTextureQuerySize = 89,\r
-    SpvOpTextureQueryLod = 90,\r
-    SpvOpTextureQueryLevels = 91,\r
-    SpvOpTextureQuerySamples = 92,\r
-    SpvOpAccessChain = 93,\r
-    SpvOpInBoundsAccessChain = 94,\r
-    SpvOpSNegate = 95,\r
-    SpvOpFNegate = 96,\r
-    SpvOpNot = 97,\r
-    SpvOpAny = 98,\r
-    SpvOpAll = 99,\r
-    SpvOpConvertFToU = 100,\r
-    SpvOpConvertFToS = 101,\r
-    SpvOpConvertSToF = 102,\r
-    SpvOpConvertUToF = 103,\r
-    SpvOpUConvert = 104,\r
-    SpvOpSConvert = 105,\r
-    SpvOpFConvert = 106,\r
-    SpvOpConvertPtrToU = 107,\r
-    SpvOpConvertUToPtr = 108,\r
-    SpvOpPtrCastToGeneric = 109,\r
-    SpvOpGenericCastToPtr = 110,\r
-    SpvOpBitcast = 111,\r
-    SpvOpTranspose = 112,\r
-    SpvOpIsNan = 113,\r
-    SpvOpIsInf = 114,\r
-    SpvOpIsFinite = 115,\r
-    SpvOpIsNormal = 116,\r
-    SpvOpSignBitSet = 117,\r
-    SpvOpLessOrGreater = 118,\r
-    SpvOpOrdered = 119,\r
-    SpvOpUnordered = 120,\r
-    SpvOpArrayLength = 121,\r
-    SpvOpIAdd = 122,\r
-    SpvOpFAdd = 123,\r
-    SpvOpISub = 124,\r
-    SpvOpFSub = 125,\r
-    SpvOpIMul = 126,\r
-    SpvOpFMul = 127,\r
-    SpvOpUDiv = 128,\r
-    SpvOpSDiv = 129,\r
-    SpvOpFDiv = 130,\r
-    SpvOpUMod = 131,\r
-    SpvOpSRem = 132,\r
-    SpvOpSMod = 133,\r
-    SpvOpFRem = 134,\r
-    SpvOpFMod = 135,\r
-    SpvOpVectorTimesScalar = 136,\r
-    SpvOpMatrixTimesScalar = 137,\r
-    SpvOpVectorTimesMatrix = 138,\r
-    SpvOpMatrixTimesVector = 139,\r
-    SpvOpMatrixTimesMatrix = 140,\r
-    SpvOpOuterProduct = 141,\r
-    SpvOpDot = 142,\r
-    SpvOpShiftRightLogical = 143,\r
-    SpvOpShiftRightArithmetic = 144,\r
-    SpvOpShiftLeftLogical = 145,\r
-    SpvOpLogicalOr = 146,\r
-    SpvOpLogicalXor = 147,\r
-    SpvOpLogicalAnd = 148,\r
-    SpvOpBitwiseOr = 149,\r
-    SpvOpBitwiseXor = 150,\r
-    SpvOpBitwiseAnd = 151,\r
-    SpvOpSelect = 152,\r
-    SpvOpIEqual = 153,\r
-    SpvOpFOrdEqual = 154,\r
-    SpvOpFUnordEqual = 155,\r
-    SpvOpINotEqual = 156,\r
-    SpvOpFOrdNotEqual = 157,\r
-    SpvOpFUnordNotEqual = 158,\r
-    SpvOpULessThan = 159,\r
-    SpvOpSLessThan = 160,\r
-    SpvOpFOrdLessThan = 161,\r
-    SpvOpFUnordLessThan = 162,\r
-    SpvOpUGreaterThan = 163,\r
-    SpvOpSGreaterThan = 164,\r
-    SpvOpFOrdGreaterThan = 165,\r
-    SpvOpFUnordGreaterThan = 166,\r
-    SpvOpULessThanEqual = 167,\r
-    SpvOpSLessThanEqual = 168,\r
-    SpvOpFOrdLessThanEqual = 169,\r
-    SpvOpFUnordLessThanEqual = 170,\r
-    SpvOpUGreaterThanEqual = 171,\r
-    SpvOpSGreaterThanEqual = 172,\r
-    SpvOpFOrdGreaterThanEqual = 173,\r
-    SpvOpFUnordGreaterThanEqual = 174,\r
-    SpvOpDPdx = 175,\r
-    SpvOpDPdy = 176,\r
-    SpvOpFwidth = 177,\r
-    SpvOpDPdxFine = 178,\r
-    SpvOpDPdyFine = 179,\r
-    SpvOpFwidthFine = 180,\r
-    SpvOpDPdxCoarse = 181,\r
-    SpvOpDPdyCoarse = 182,\r
-    SpvOpFwidthCoarse = 183,\r
-    SpvOpEmitVertex = 184,\r
-    SpvOpEndPrimitive = 185,\r
-    SpvOpEmitStreamVertex = 186,\r
-    SpvOpEndStreamPrimitive = 187,\r
-    SpvOpControlBarrier = 188,\r
-    SpvOpMemoryBarrier = 189,\r
-    SpvOpImagePointer = 190,\r
-    SpvOpAtomicInit = 191,\r
-    SpvOpAtomicLoad = 192,\r
-    SpvOpAtomicStore = 193,\r
-    SpvOpAtomicExchange = 194,\r
-    SpvOpAtomicCompareExchange = 195,\r
-    SpvOpAtomicCompareExchangeWeak = 196,\r
-    SpvOpAtomicIIncrement = 197,\r
-    SpvOpAtomicIDecrement = 198,\r
-    SpvOpAtomicIAdd = 199,\r
-    SpvOpAtomicISub = 200,\r
-    SpvOpAtomicUMin = 201,\r
-    SpvOpAtomicUMax = 202,\r
-    SpvOpAtomicAnd = 203,\r
-    SpvOpAtomicOr = 204,\r
-    SpvOpAtomicXor = 205,\r
-    SpvOpLoopMerge = 206,\r
-    SpvOpSelectionMerge = 207,\r
-    SpvOpLabel = 208,\r
-    SpvOpBranch = 209,\r
-    SpvOpBranchConditional = 210,\r
-    SpvOpSwitch = 211,\r
-    SpvOpKill = 212,\r
-    SpvOpReturn = 213,\r
-    SpvOpReturnValue = 214,\r
-    SpvOpUnreachable = 215,\r
-    SpvOpLifetimeStart = 216,\r
-    SpvOpLifetimeStop = 217,\r
-    SpvOpCompileFlag = 218,\r
-    SpvOpAsyncGroupCopy = 219,\r
-    SpvOpWaitGroupEvents = 220,\r
-    SpvOpGroupAll = 221,\r
-    SpvOpGroupAny = 222,\r
-    SpvOpGroupBroadcast = 223,\r
-    SpvOpGroupIAdd = 224,\r
-    SpvOpGroupFAdd = 225,\r
-    SpvOpGroupFMin = 226,\r
-    SpvOpGroupUMin = 227,\r
-    SpvOpGroupSMin = 228,\r
-    SpvOpGroupFMax = 229,\r
-    SpvOpGroupUMax = 230,\r
-    SpvOpGroupSMax = 231,\r
-    SpvOpGenericCastToPtrExplicit = 232,\r
-    SpvOpGenericPtrMemSemantics = 233,\r
-    SpvOpReadPipe = 234,\r
-    SpvOpWritePipe = 235,\r
-    SpvOpReservedReadPipe = 236,\r
-    SpvOpReservedWritePipe = 237,\r
-    SpvOpReserveReadPipePackets = 238,\r
-    SpvOpReserveWritePipePackets = 239,\r
-    SpvOpCommitReadPipe = 240,\r
-    SpvOpCommitWritePipe = 241,\r
-    SpvOpIsValidReserveId = 242,\r
-    SpvOpGetNumPipePackets = 243,\r
-    SpvOpGetMaxPipePackets = 244,\r
-    SpvOpGroupReserveReadPipePackets = 245,\r
-    SpvOpGroupReserveWritePipePackets = 246,\r
-    SpvOpGroupCommitReadPipe = 247,\r
-    SpvOpGroupCommitWritePipe = 248,\r
-    SpvOpEnqueueMarker = 249,\r
-    SpvOpEnqueueKernel = 250,\r
-    SpvOpGetKernelNDrangeSubGroupCount = 251,\r
-    SpvOpGetKernelNDrangeMaxSubGroupSize = 252,\r
-    SpvOpGetKernelWorkGroupSize = 253,\r
-    SpvOpGetKernelPreferredWorkGroupSizeMultiple = 254,\r
-    SpvOpRetainEvent = 255,\r
-    SpvOpReleaseEvent = 256,\r
-    SpvOpCreateUserEvent = 257,\r
-    SpvOpIsValidEvent = 258,\r
-    SpvOpSetUserEventStatus = 259,\r
-    SpvOpCaptureEventProfilingInfo = 260,\r
-    SpvOpGetDefaultQueue = 261,\r
-    SpvOpBuildNDRange = 262,\r
-    SpvOpSatConvertSToU = 263,\r
-    SpvOpSatConvertUToS = 264,\r
-    SpvOpAtomicIMin = 265,\r
-    SpvOpAtomicIMax = 266,\r
-} SpvOp;\r
-\r
-#endif  // #ifndef __cplusplus\r
-\r
-#endif  // #ifndef spirv_H\r
+/*
+** Copyright (c) 2015 The Khronos Group Inc.
+**
+** Permission is hereby granted, free of charge, to any person obtaining a copy
+** of this software and/or associated documentation files (the "Materials"),
+** to deal in the Materials without restriction, including without limitation
+** the rights to use, copy, modify, merge, publish, distribute, sublicense,
+** and/or sell copies of the Materials, and to permit persons to whom the
+** Materials are furnished to do so, subject to the following conditions:
+**
+** The above copyright notice and this permission notice shall be included in
+** all copies or substantial portions of the Materials.
+**
+** MODIFICATIONS TO THIS FILE MAY MEAN IT NO LONGER ACCURATELY REFLECTS KHRONOS
+** STANDARDS. THE UNMODIFIED, NORMATIVE VERSIONS OF KHRONOS SPECIFICATIONS AND
+** HEADER INFORMATION ARE LOCATED AT https://www.khronos.org/registry/ 
+**
+** THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+** OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+** FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+** THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+** LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+** FROM,OUT OF OR IN CONNECTION WITH THE MATERIALS OR THE USE OR OTHER DEALINGS
+** IN THE MATERIALS.
+*/
+
+/*
+** This header is automatically generated by the same tool that creates
+** the Binary Section of the SPIR-V specification.
+*/
+
+/*
+** Specification revision 30.
+** Enumeration tokens for SPIR-V, in three styles: C, C++, generic.
+** - C++ will have the tokens in the "spv" name space, with no prefix.
+** - C will have tokens with as "Spv" prefix.
+**
+** Some tokens act like mask values, which can be OR'd together,
+** while others are mutually exclusive.  The mask-like ones have
+** "Mask" in their name, and a parallel enum that has the shift
+** amount (1 << x) for each corresponding enumerant.
+*/
+
+#ifndef spirv_H
+#define spirv_H
+
+#ifdef __cplusplus
+
+namespace spv {
+
+const int MagicNumber = 0x07230203;
+const int Version = 99;
+
+typedef unsigned int Id;
+
+const unsigned int OpCodeMask = 0xFFFF;
+const unsigned int WordCountShift = 16;
+
+enum SourceLanguage {
+    SourceLanguageUnknown = 0,
+    SourceLanguageESSL = 1,
+    SourceLanguageGLSL = 2,
+    SourceLanguageOpenCL = 3,
+};
+
+enum ExecutionModel {
+    ExecutionModelVertex = 0,
+    ExecutionModelTessellationControl = 1,
+    ExecutionModelTessellationEvaluation = 2,
+    ExecutionModelGeometry = 3,
+    ExecutionModelFragment = 4,
+    ExecutionModelGLCompute = 5,
+    ExecutionModelKernel = 6,
+};
+
+enum AddressingModel {
+    AddressingModelLogical = 0,
+    AddressingModelPhysical32 = 1,
+    AddressingModelPhysical64 = 2,
+};
+
+enum MemoryModel {
+    MemoryModelSimple = 0,
+    MemoryModelGLSL450 = 1,
+    MemoryModelOpenCL12 = 2,
+    MemoryModelOpenCL20 = 3,
+    MemoryModelOpenCL21 = 4,
+};
+
+enum ExecutionMode {
+    ExecutionModeInvocations = 0,
+    ExecutionModeSpacingEqual = 1,
+    ExecutionModeSpacingFractionalEven = 2,
+    ExecutionModeSpacingFractionalOdd = 3,
+    ExecutionModeVertexOrderCw = 4,
+    ExecutionModeVertexOrderCcw = 5,
+    ExecutionModePixelCenterInteger = 6,
+    ExecutionModeOriginUpperLeft = 7,
+    ExecutionModeEarlyFragmentTests = 8,
+    ExecutionModePointMode = 9,
+    ExecutionModeXfb = 10,
+    ExecutionModeDepthReplacing = 11,
+    ExecutionModeDepthAny = 12,
+    ExecutionModeDepthGreater = 13,
+    ExecutionModeDepthLess = 14,
+    ExecutionModeDepthUnchanged = 15,
+    ExecutionModeLocalSize = 16,
+    ExecutionModeLocalSizeHint = 17,
+    ExecutionModeInputPoints = 18,
+    ExecutionModeInputLines = 19,
+    ExecutionModeInputLinesAdjacency = 20,
+    ExecutionModeInputTriangles = 21,
+    ExecutionModeInputTrianglesAdjacency = 22,
+    ExecutionModeInputQuads = 23,
+    ExecutionModeInputIsolines = 24,
+    ExecutionModeOutputVertices = 25,
+    ExecutionModeOutputPoints = 26,
+    ExecutionModeOutputLineStrip = 27,
+    ExecutionModeOutputTriangleStrip = 28,
+    ExecutionModeVecTypeHint = 29,
+    ExecutionModeContractionOff = 30,
+};
+
+enum StorageClass {
+    StorageClassUniformConstant = 0,
+    StorageClassInput = 1,
+    StorageClassUniform = 2,
+    StorageClassOutput = 3,
+    StorageClassWorkgroupLocal = 4,
+    StorageClassWorkgroupGlobal = 5,
+    StorageClassPrivateGlobal = 6,
+    StorageClassFunction = 7,
+    StorageClassGeneric = 8,
+    StorageClassPrivate = 9,
+    StorageClassAtomicCounter = 10,
+};
+
+enum Dim {
+    Dim1D = 0,
+    Dim2D = 1,
+    Dim3D = 2,
+    DimCube = 3,
+    DimRect = 4,
+    DimBuffer = 5,
+};
+
+enum SamplerAddressingMode {
+    SamplerAddressingModeNone = 0,
+    SamplerAddressingModeClampToEdge = 1,
+    SamplerAddressingModeClamp = 2,
+    SamplerAddressingModeRepeat = 3,
+    SamplerAddressingModeRepeatMirrored = 4,
+};
+
+enum SamplerFilterMode {
+    SamplerFilterModeNearest = 0,
+    SamplerFilterModeLinear = 1,
+};
+
+enum FPFastMathModeShift {
+    FPFastMathModeNotNaNShift = 0,
+    FPFastMathModeNotInfShift = 1,
+    FPFastMathModeNSZShift = 2,
+    FPFastMathModeAllowRecipShift = 3,
+    FPFastMathModeFastShift = 4,
+};
+
+enum FPFastMathModeMask {
+    FPFastMathModeMaskNone = 0,
+    FPFastMathModeNotNaNMask = 0x00000001,
+    FPFastMathModeNotInfMask = 0x00000002,
+    FPFastMathModeNSZMask = 0x00000004,
+    FPFastMathModeAllowRecipMask = 0x00000008,
+    FPFastMathModeFastMask = 0x00000010,
+};
+
+enum FPRoundingMode {
+    FPRoundingModeRTE = 0,
+    FPRoundingModeRTZ = 1,
+    FPRoundingModeRTP = 2,
+    FPRoundingModeRTN = 3,
+};
+
+enum LinkageType {
+    LinkageTypeExport = 0,
+    LinkageTypeImport = 1,
+};
+
+enum AccessQualifier {
+    AccessQualifierReadOnly = 0,
+    AccessQualifierWriteOnly = 1,
+    AccessQualifierReadWrite = 2,
+};
+
+enum FunctionParameterAttribute {
+    FunctionParameterAttributeZext = 0,
+    FunctionParameterAttributeSext = 1,
+    FunctionParameterAttributeByVal = 2,
+    FunctionParameterAttributeSret = 3,
+    FunctionParameterAttributeNoAlias = 4,
+    FunctionParameterAttributeNoCapture = 5,
+    FunctionParameterAttributeSVM = 6,
+    FunctionParameterAttributeNoWrite = 7,
+    FunctionParameterAttributeNoReadWrite = 8,
+};
+
+enum Decoration {
+    DecorationPrecisionLow = 0,
+    DecorationPrecisionMedium = 1,
+    DecorationPrecisionHigh = 2,
+    DecorationBlock = 3,
+    DecorationBufferBlock = 4,
+    DecorationRowMajor = 5,
+    DecorationColMajor = 6,
+    DecorationGLSLShared = 7,
+    DecorationGLSLStd140 = 8,
+    DecorationGLSLStd430 = 9,
+    DecorationGLSLPacked = 10,
+    DecorationSmooth = 11,
+    DecorationNoperspective = 12,
+    DecorationFlat = 13,
+    DecorationPatch = 14,
+    DecorationCentroid = 15,
+    DecorationSample = 16,
+    DecorationInvariant = 17,
+    DecorationRestrict = 18,
+    DecorationAliased = 19,
+    DecorationVolatile = 20,
+    DecorationConstant = 21,
+    DecorationCoherent = 22,
+    DecorationNonwritable = 23,
+    DecorationNonreadable = 24,
+    DecorationUniform = 25,
+    DecorationNoStaticUse = 26,
+    DecorationCPacked = 27,
+    DecorationSaturatedConversion = 28,
+    DecorationStream = 29,
+    DecorationLocation = 30,
+    DecorationComponent = 31,
+    DecorationIndex = 32,
+    DecorationBinding = 33,
+    DecorationDescriptorSet = 34,
+    DecorationOffset = 35,
+    DecorationAlignment = 36,
+    DecorationXfbBuffer = 37,
+    DecorationStride = 38,
+    DecorationBuiltIn = 39,
+    DecorationFuncParamAttr = 40,
+    DecorationFPRoundingMode = 41,
+    DecorationFPFastMathMode = 42,
+    DecorationLinkageAttributes = 43,
+    DecorationSpecId = 44,
+};
+
+enum BuiltIn {
+    BuiltInPosition = 0,
+    BuiltInPointSize = 1,
+    BuiltInClipVertex = 2,
+    BuiltInClipDistance = 3,
+    BuiltInCullDistance = 4,
+    BuiltInVertexId = 5,
+    BuiltInInstanceId = 6,
+    BuiltInPrimitiveId = 7,
+    BuiltInInvocationId = 8,
+    BuiltInLayer = 9,
+    BuiltInViewportIndex = 10,
+    BuiltInTessLevelOuter = 11,
+    BuiltInTessLevelInner = 12,
+    BuiltInTessCoord = 13,
+    BuiltInPatchVertices = 14,
+    BuiltInFragCoord = 15,
+    BuiltInPointCoord = 16,
+    BuiltInFrontFacing = 17,
+    BuiltInSampleId = 18,
+    BuiltInSamplePosition = 19,
+    BuiltInSampleMask = 20,
+    BuiltInFragColor = 21,
+    BuiltInFragDepth = 22,
+    BuiltInHelperInvocation = 23,
+    BuiltInNumWorkgroups = 24,
+    BuiltInWorkgroupSize = 25,
+    BuiltInWorkgroupId = 26,
+    BuiltInLocalInvocationId = 27,
+    BuiltInGlobalInvocationId = 28,
+    BuiltInLocalInvocationIndex = 29,
+    BuiltInWorkDim = 30,
+    BuiltInGlobalSize = 31,
+    BuiltInEnqueuedWorkgroupSize = 32,
+    BuiltInGlobalOffset = 33,
+    BuiltInGlobalLinearId = 34,
+    BuiltInWorkgroupLinearId = 35,
+    BuiltInSubgroupSize = 36,
+    BuiltInSubgroupMaxSize = 37,
+    BuiltInNumSubgroups = 38,
+    BuiltInNumEnqueuedSubgroups = 39,
+    BuiltInSubgroupId = 40,
+    BuiltInSubgroupLocalInvocationId = 41,
+};
+
+enum SelectionControlShift {
+    SelectionControlFlattenShift = 0,
+    SelectionControlDontFlattenShift = 1,
+};
+
+enum SelectionControlMask {
+    SelectionControlMaskNone = 0,
+    SelectionControlFlattenMask = 0x00000001,
+    SelectionControlDontFlattenMask = 0x00000002,
+};
+
+enum LoopControlShift {
+    LoopControlUnrollShift = 0,
+    LoopControlDontUnrollShift = 1,
+};
+
+enum LoopControlMask {
+    LoopControlMaskNone = 0,
+    LoopControlUnrollMask = 0x00000001,
+    LoopControlDontUnrollMask = 0x00000002,
+};
+
+enum FunctionControlShift {
+    FunctionControlInlineShift = 0,
+    FunctionControlDontInlineShift = 1,
+    FunctionControlPureShift = 2,
+    FunctionControlConstShift = 3,
+};
+
+enum FunctionControlMask {
+    FunctionControlMaskNone = 0,
+    FunctionControlInlineMask = 0x00000001,
+    FunctionControlDontInlineMask = 0x00000002,
+    FunctionControlPureMask = 0x00000004,
+    FunctionControlConstMask = 0x00000008,
+};
+
+enum MemorySemanticsShift {
+    MemorySemanticsRelaxedShift = 0,
+    MemorySemanticsSequentiallyConsistentShift = 1,
+    MemorySemanticsAcquireShift = 2,
+    MemorySemanticsReleaseShift = 3,
+    MemorySemanticsUniformMemoryShift = 4,
+    MemorySemanticsSubgroupMemoryShift = 5,
+    MemorySemanticsWorkgroupLocalMemoryShift = 6,
+    MemorySemanticsWorkgroupGlobalMemoryShift = 7,
+    MemorySemanticsAtomicCounterMemoryShift = 8,
+    MemorySemanticsImageMemoryShift = 9,
+};
+
+enum MemorySemanticsMask {
+    MemorySemanticsMaskNone = 0,
+    MemorySemanticsRelaxedMask = 0x00000001,
+    MemorySemanticsSequentiallyConsistentMask = 0x00000002,
+    MemorySemanticsAcquireMask = 0x00000004,
+    MemorySemanticsReleaseMask = 0x00000008,
+    MemorySemanticsUniformMemoryMask = 0x00000010,
+    MemorySemanticsSubgroupMemoryMask = 0x00000020,
+    MemorySemanticsWorkgroupLocalMemoryMask = 0x00000040,
+    MemorySemanticsWorkgroupGlobalMemoryMask = 0x00000080,
+    MemorySemanticsAtomicCounterMemoryMask = 0x00000100,
+    MemorySemanticsImageMemoryMask = 0x00000200,
+};
+
+enum MemoryAccessShift {
+    MemoryAccessVolatileShift = 0,
+    MemoryAccessAlignedShift = 1,
+};
+
+enum MemoryAccessMask {
+    MemoryAccessMaskNone = 0,
+    MemoryAccessVolatileMask = 0x00000001,
+    MemoryAccessAlignedMask = 0x00000002,
+};
+
+enum ExecutionScope {
+    ExecutionScopeCrossDevice = 0,
+    ExecutionScopeDevice = 1,
+    ExecutionScopeWorkgroup = 2,
+    ExecutionScopeSubgroup = 3,
+};
+
+enum GroupOperation {
+    GroupOperationReduce = 0,
+    GroupOperationInclusiveScan = 1,
+    GroupOperationExclusiveScan = 2,
+};
+
+enum KernelEnqueueFlags {
+    KernelEnqueueFlagsNoWait = 0,
+    KernelEnqueueFlagsWaitKernel = 1,
+    KernelEnqueueFlagsWaitWorkGroup = 2,
+};
+
+enum KernelProfilingInfoShift {
+    KernelProfilingInfoCmdExecTimeShift = 0,
+};
+
+enum KernelProfilingInfoMask {
+    KernelProfilingInfoMaskNone = 0,
+    KernelProfilingInfoCmdExecTimeMask = 0x00000001,
+};
+
+enum Op {
+    OpNop = 0,
+    OpSource = 1,
+    OpSourceExtension = 2,
+    OpExtension = 3,
+    OpExtInstImport = 4,
+    OpMemoryModel = 5,
+    OpEntryPoint = 6,
+    OpExecutionMode = 7,
+    OpTypeVoid = 8,
+    OpTypeBool = 9,
+    OpTypeInt = 10,
+    OpTypeFloat = 11,
+    OpTypeVector = 12,
+    OpTypeMatrix = 13,
+    OpTypeSampler = 14,
+    OpTypeFilter = 15,
+    OpTypeArray = 16,
+    OpTypeRuntimeArray = 17,
+    OpTypeStruct = 18,
+    OpTypeOpaque = 19,
+    OpTypePointer = 20,
+    OpTypeFunction = 21,
+    OpTypeEvent = 22,
+    OpTypeDeviceEvent = 23,
+    OpTypeReserveId = 24,
+    OpTypeQueue = 25,
+    OpTypePipe = 26,
+    OpConstantTrue = 27,
+    OpConstantFalse = 28,
+    OpConstant = 29,
+    OpConstantComposite = 30,
+    OpConstantSampler = 31,
+    OpConstantNullPointer = 32,
+    OpConstantNullObject = 33,
+    OpSpecConstantTrue = 34,
+    OpSpecConstantFalse = 35,
+    OpSpecConstant = 36,
+    OpSpecConstantComposite = 37,
+    OpVariable = 38,
+    OpVariableArray = 39,
+    OpFunction = 40,
+    OpFunctionParameter = 41,
+    OpFunctionEnd = 42,
+    OpFunctionCall = 43,
+    OpExtInst = 44,
+    OpUndef = 45,
+    OpLoad = 46,
+    OpStore = 47,
+    OpPhi = 48,
+    OpDecorationGroup = 49,
+    OpDecorate = 50,
+    OpMemberDecorate = 51,
+    OpGroupDecorate = 52,
+    OpGroupMemberDecorate = 53,
+    OpName = 54,
+    OpMemberName = 55,
+    OpString = 56,
+    OpLine = 57,
+    OpVectorExtractDynamic = 58,
+    OpVectorInsertDynamic = 59,
+    OpVectorShuffle = 60,
+    OpCompositeConstruct = 61,
+    OpCompositeExtract = 62,
+    OpCompositeInsert = 63,
+    OpCopyObject = 64,
+    OpCopyMemory = 65,
+    OpCopyMemorySized = 66,
+    OpSampler = 67,
+    OpTextureSample = 68,
+    OpTextureSampleDref = 69,
+    OpTextureSampleLod = 70,
+    OpTextureSampleProj = 71,
+    OpTextureSampleGrad = 72,
+    OpTextureSampleOffset = 73,
+    OpTextureSampleProjLod = 74,
+    OpTextureSampleProjGrad = 75,
+    OpTextureSampleLodOffset = 76,
+    OpTextureSampleProjOffset = 77,
+    OpTextureSampleGradOffset = 78,
+    OpTextureSampleProjLodOffset = 79,
+    OpTextureSampleProjGradOffset = 80,
+    OpTextureFetchTexelLod = 81,
+    OpTextureFetchTexelOffset = 82,
+    OpTextureFetchSample = 83,
+    OpTextureFetchTexel = 84,
+    OpTextureGather = 85,
+    OpTextureGatherOffset = 86,
+    OpTextureGatherOffsets = 87,
+    OpTextureQuerySizeLod = 88,
+    OpTextureQuerySize = 89,
+    OpTextureQueryLod = 90,
+    OpTextureQueryLevels = 91,
+    OpTextureQuerySamples = 92,
+    OpAccessChain = 93,
+    OpInBoundsAccessChain = 94,
+    OpSNegate = 95,
+    OpFNegate = 96,
+    OpNot = 97,
+    OpAny = 98,
+    OpAll = 99,
+    OpConvertFToU = 100,
+    OpConvertFToS = 101,
+    OpConvertSToF = 102,
+    OpConvertUToF = 103,
+    OpUConvert = 104,
+    OpSConvert = 105,
+    OpFConvert = 106,
+    OpConvertPtrToU = 107,
+    OpConvertUToPtr = 108,
+    OpPtrCastToGeneric = 109,
+    OpGenericCastToPtr = 110,
+    OpBitcast = 111,
+    OpTranspose = 112,
+    OpIsNan = 113,
+    OpIsInf = 114,
+    OpIsFinite = 115,
+    OpIsNormal = 116,
+    OpSignBitSet = 117,
+    OpLessOrGreater = 118,
+    OpOrdered = 119,
+    OpUnordered = 120,
+    OpArrayLength = 121,
+    OpIAdd = 122,
+    OpFAdd = 123,
+    OpISub = 124,
+    OpFSub = 125,
+    OpIMul = 126,
+    OpFMul = 127,
+    OpUDiv = 128,
+    OpSDiv = 129,
+    OpFDiv = 130,
+    OpUMod = 131,
+    OpSRem = 132,
+    OpSMod = 133,
+    OpFRem = 134,
+    OpFMod = 135,
+    OpVectorTimesScalar = 136,
+    OpMatrixTimesScalar = 137,
+    OpVectorTimesMatrix = 138,
+    OpMatrixTimesVector = 139,
+    OpMatrixTimesMatrix = 140,
+    OpOuterProduct = 141,
+    OpDot = 142,
+    OpShiftRightLogical = 143,
+    OpShiftRightArithmetic = 144,
+    OpShiftLeftLogical = 145,
+    OpLogicalOr = 146,
+    OpLogicalXor = 147,
+    OpLogicalAnd = 148,
+    OpBitwiseOr = 149,
+    OpBitwiseXor = 150,
+    OpBitwiseAnd = 151,
+    OpSelect = 152,
+    OpIEqual = 153,
+    OpFOrdEqual = 154,
+    OpFUnordEqual = 155,
+    OpINotEqual = 156,
+    OpFOrdNotEqual = 157,
+    OpFUnordNotEqual = 158,
+    OpULessThan = 159,
+    OpSLessThan = 160,
+    OpFOrdLessThan = 161,
+    OpFUnordLessThan = 162,
+    OpUGreaterThan = 163,
+    OpSGreaterThan = 164,
+    OpFOrdGreaterThan = 165,
+    OpFUnordGreaterThan = 166,
+    OpULessThanEqual = 167,
+    OpSLessThanEqual = 168,
+    OpFOrdLessThanEqual = 169,
+    OpFUnordLessThanEqual = 170,
+    OpUGreaterThanEqual = 171,
+    OpSGreaterThanEqual = 172,
+    OpFOrdGreaterThanEqual = 173,
+    OpFUnordGreaterThanEqual = 174,
+    OpDPdx = 175,
+    OpDPdy = 176,
+    OpFwidth = 177,
+    OpDPdxFine = 178,
+    OpDPdyFine = 179,
+    OpFwidthFine = 180,
+    OpDPdxCoarse = 181,
+    OpDPdyCoarse = 182,
+    OpFwidthCoarse = 183,
+    OpEmitVertex = 184,
+    OpEndPrimitive = 185,
+    OpEmitStreamVertex = 186,
+    OpEndStreamPrimitive = 187,
+    OpControlBarrier = 188,
+    OpMemoryBarrier = 189,
+    OpImagePointer = 190,
+    OpAtomicInit = 191,
+    OpAtomicLoad = 192,
+    OpAtomicStore = 193,
+    OpAtomicExchange = 194,
+    OpAtomicCompareExchange = 195,
+    OpAtomicCompareExchangeWeak = 196,
+    OpAtomicIIncrement = 197,
+    OpAtomicIDecrement = 198,
+    OpAtomicIAdd = 199,
+    OpAtomicISub = 200,
+    OpAtomicUMin = 201,
+    OpAtomicUMax = 202,
+    OpAtomicAnd = 203,
+    OpAtomicOr = 204,
+    OpAtomicXor = 205,
+    OpLoopMerge = 206,
+    OpSelectionMerge = 207,
+    OpLabel = 208,
+    OpBranch = 209,
+    OpBranchConditional = 210,
+    OpSwitch = 211,
+    OpKill = 212,
+    OpReturn = 213,
+    OpReturnValue = 214,
+    OpUnreachable = 215,
+    OpLifetimeStart = 216,
+    OpLifetimeStop = 217,
+    OpCompileFlag = 218,
+    OpAsyncGroupCopy = 219,
+    OpWaitGroupEvents = 220,
+    OpGroupAll = 221,
+    OpGroupAny = 222,
+    OpGroupBroadcast = 223,
+    OpGroupIAdd = 224,
+    OpGroupFAdd = 225,
+    OpGroupFMin = 226,
+    OpGroupUMin = 227,
+    OpGroupSMin = 228,
+    OpGroupFMax = 229,
+    OpGroupUMax = 230,
+    OpGroupSMax = 231,
+    OpGenericCastToPtrExplicit = 232,
+    OpGenericPtrMemSemantics = 233,
+    OpReadPipe = 234,
+    OpWritePipe = 235,
+    OpReservedReadPipe = 236,
+    OpReservedWritePipe = 237,
+    OpReserveReadPipePackets = 238,
+    OpReserveWritePipePackets = 239,
+    OpCommitReadPipe = 240,
+    OpCommitWritePipe = 241,
+    OpIsValidReserveId = 242,
+    OpGetNumPipePackets = 243,
+    OpGetMaxPipePackets = 244,
+    OpGroupReserveReadPipePackets = 245,
+    OpGroupReserveWritePipePackets = 246,
+    OpGroupCommitReadPipe = 247,
+    OpGroupCommitWritePipe = 248,
+    OpEnqueueMarker = 249,
+    OpEnqueueKernel = 250,
+    OpGetKernelNDrangeSubGroupCount = 251,
+    OpGetKernelNDrangeMaxSubGroupSize = 252,
+    OpGetKernelWorkGroupSize = 253,
+    OpGetKernelPreferredWorkGroupSizeMultiple = 254,
+    OpRetainEvent = 255,
+    OpReleaseEvent = 256,
+    OpCreateUserEvent = 257,
+    OpIsValidEvent = 258,
+    OpSetUserEventStatus = 259,
+    OpCaptureEventProfilingInfo = 260,
+    OpGetDefaultQueue = 261,
+    OpBuildNDRange = 262,
+    OpSatConvertSToU = 263,
+    OpSatConvertUToS = 264,
+    OpAtomicIMin = 265,
+    OpAtomicIMax = 266,
+};
+
+};  // end namespace spv
+
+#endif  // #ifdef __cplusplus
+
+
+#ifndef __cplusplus
+
+const int SpvMagicNumber = 0x07230203;
+const int SpvVersion = 99;
+
+typedef unsigned int SpvId;
+
+const unsigned int SpvOpCodeMask = 0xFFFF;
+const unsigned int SpvWordCountShift = 16;
+
+typedef enum SpvSourceLanguage_ {
+    SpvSourceLanguageUnknown = 0,
+    SpvSourceLanguageESSL = 1,
+    SpvSourceLanguageGLSL = 2,
+    SpvSourceLanguageOpenCL = 3,
+} SpvSourceLanguage;
+
+typedef enum SpvExecutionModel_ {
+    SpvExecutionModelVertex = 0,
+    SpvExecutionModelTessellationControl = 1,
+    SpvExecutionModelTessellationEvaluation = 2,
+    SpvExecutionModelGeometry = 3,
+    SpvExecutionModelFragment = 4,
+    SpvExecutionModelGLCompute = 5,
+    SpvExecutionModelKernel = 6,
+} SpvExecutionModel;
+
+typedef enum SpvAddressingModel_ {
+    SpvAddressingModelLogical = 0,
+    SpvAddressingModelPhysical32 = 1,
+    SpvAddressingModelPhysical64 = 2,
+} SpvAddressingModel;
+
+typedef enum SpvMemoryModel_ {
+    SpvMemoryModelSimple = 0,
+    SpvMemoryModelGLSL450 = 1,
+    SpvMemoryModelOpenCL12 = 2,
+    SpvMemoryModelOpenCL20 = 3,
+    SpvMemoryModelOpenCL21 = 4,
+} SpvMemoryModel;
+
+typedef enum SpvExecutionMode_ {
+    SpvExecutionModeInvocations = 0,
+    SpvExecutionModeSpacingEqual = 1,
+    SpvExecutionModeSpacingFractionalEven = 2,
+    SpvExecutionModeSpacingFractionalOdd = 3,
+    SpvExecutionModeVertexOrderCw = 4,
+    SpvExecutionModeVertexOrderCcw = 5,
+    SpvExecutionModePixelCenterInteger = 6,
+    SpvExecutionModeOriginUpperLeft = 7,
+    SpvExecutionModeEarlyFragmentTests = 8,
+    SpvExecutionModePointMode = 9,
+    SpvExecutionModeXfb = 10,
+    SpvExecutionModeDepthReplacing = 11,
+    SpvExecutionModeDepthAny = 12,
+    SpvExecutionModeDepthGreater = 13,
+    SpvExecutionModeDepthLess = 14,
+    SpvExecutionModeDepthUnchanged = 15,
+    SpvExecutionModeLocalSize = 16,
+    SpvExecutionModeLocalSizeHint = 17,
+    SpvExecutionModeInputPoints = 18,
+    SpvExecutionModeInputLines = 19,
+    SpvExecutionModeInputLinesAdjacency = 20,
+    SpvExecutionModeInputTriangles = 21,
+    SpvExecutionModeInputTrianglesAdjacency = 22,
+    SpvExecutionModeInputQuads = 23,
+    SpvExecutionModeInputIsolines = 24,
+    SpvExecutionModeOutputVertices = 25,
+    SpvExecutionModeOutputPoints = 26,
+    SpvExecutionModeOutputLineStrip = 27,
+    SpvExecutionModeOutputTriangleStrip = 28,
+    SpvExecutionModeVecTypeHint = 29,
+    SpvExecutionModeContractionOff = 30,
+} SpvExecutionMode;
+
+typedef enum SpvStorageClass_ {
+    SpvStorageClassUniformConstant = 0,
+    SpvStorageClassInput = 1,
+    SpvStorageClassUniform = 2,
+    SpvStorageClassOutput = 3,
+    SpvStorageClassWorkgroupLocal = 4,
+    SpvStorageClassWorkgroupGlobal = 5,
+    SpvStorageClassPrivateGlobal = 6,
+    SpvStorageClassFunction = 7,
+    SpvStorageClassGeneric = 8,
+    SpvStorageClassPrivate = 9,
+    SpvStorageClassAtomicCounter = 10,
+} SpvStorageClass;
+
+typedef enum SpvDim_ {
+    SpvDim1D = 0,
+    SpvDim2D = 1,
+    SpvDim3D = 2,
+    SpvDimCube = 3,
+    SpvDimRect = 4,
+    SpvDimBuffer = 5,
+} SpvDim;
+
+typedef enum SpvSamplerAddressingMode_ {
+    SpvSamplerAddressingModeNone = 0,
+    SpvSamplerAddressingModeClampToEdge = 1,
+    SpvSamplerAddressingModeClamp = 2,
+    SpvSamplerAddressingModeRepeat = 3,
+    SpvSamplerAddressingModeRepeatMirrored = 4,
+} SpvSamplerAddressingMode;
+
+typedef enum SpvSamplerFilterMode_ {
+    SpvSamplerFilterModeNearest = 0,
+    SpvSamplerFilterModeLinear = 1,
+} SpvSamplerFilterMode;
+
+typedef enum SpvFPFastMathModeShift_ {
+    SpvFPFastMathModeNotNaNShift = 0,
+    SpvFPFastMathModeNotInfShift = 1,
+    SpvFPFastMathModeNSZShift = 2,
+    SpvFPFastMathModeAllowRecipShift = 3,
+    SpvFPFastMathModeFastShift = 4,
+} SpvFPFastMathModeShift;
+
+typedef enum SpvFPFastMathModeMask_ {
+    SpvFPFastMathModeMaskNone = 0,
+    SpvFPFastMathModeNotNaNMask = 0x00000001,
+    SpvFPFastMathModeNotInfMask = 0x00000002,
+    SpvFPFastMathModeNSZMask = 0x00000004,
+    SpvFPFastMathModeAllowRecipMask = 0x00000008,
+    SpvFPFastMathModeFastMask = 0x00000010,
+} SpvFPFastMathModeMask;
+
+typedef enum SpvFPRoundingMode_ {
+    SpvFPRoundingModeRTE = 0,
+    SpvFPRoundingModeRTZ = 1,
+    SpvFPRoundingModeRTP = 2,
+    SpvFPRoundingModeRTN = 3,
+} SpvFPRoundingMode;
+
+typedef enum SpvLinkageType_ {
+    SpvLinkageTypeExport = 0,
+    SpvLinkageTypeImport = 1,
+} SpvLinkageType;
+
+typedef enum SpvAccessQualifier_ {
+    SpvAccessQualifierReadOnly = 0,
+    SpvAccessQualifierWriteOnly = 1,
+    SpvAccessQualifierReadWrite = 2,
+} SpvAccessQualifier;
+
+typedef enum SpvFunctionParameterAttribute_ {
+    SpvFunctionParameterAttributeZext = 0,
+    SpvFunctionParameterAttributeSext = 1,
+    SpvFunctionParameterAttributeByVal = 2,
+    SpvFunctionParameterAttributeSret = 3,
+    SpvFunctionParameterAttributeNoAlias = 4,
+    SpvFunctionParameterAttributeNoCapture = 5,
+    SpvFunctionParameterAttributeSVM = 6,
+    SpvFunctionParameterAttributeNoWrite = 7,
+    SpvFunctionParameterAttributeNoReadWrite = 8,
+} SpvFunctionParameterAttribute;
+
+typedef enum SpvDecoration_ {
+    SpvDecorationPrecisionLow = 0,
+    SpvDecorationPrecisionMedium = 1,
+    SpvDecorationPrecisionHigh = 2,
+    SpvDecorationBlock = 3,
+    SpvDecorationBufferBlock = 4,
+    SpvDecorationRowMajor = 5,
+    SpvDecorationColMajor = 6,
+    SpvDecorationGLSLShared = 7,
+    SpvDecorationGLSLStd140 = 8,
+    SpvDecorationGLSLStd430 = 9,
+    SpvDecorationGLSLPacked = 10,
+    SpvDecorationSmooth = 11,
+    SpvDecorationNoperspective = 12,
+    SpvDecorationFlat = 13,
+    SpvDecorationPatch = 14,
+    SpvDecorationCentroid = 15,
+    SpvDecorationSample = 16,
+    SpvDecorationInvariant = 17,
+    SpvDecorationRestrict = 18,
+    SpvDecorationAliased = 19,
+    SpvDecorationVolatile = 20,
+    SpvDecorationConstant = 21,
+    SpvDecorationCoherent = 22,
+    SpvDecorationNonwritable = 23,
+    SpvDecorationNonreadable = 24,
+    SpvDecorationUniform = 25,
+    SpvDecorationNoStaticUse = 26,
+    SpvDecorationCPacked = 27,
+    SpvDecorationSaturatedConversion = 28,
+    SpvDecorationStream = 29,
+    SpvDecorationLocation = 30,
+    SpvDecorationComponent = 31,
+    SpvDecorationIndex = 32,
+    SpvDecorationBinding = 33,
+    SpvDecorationDescriptorSet = 34,
+    SpvDecorationOffset = 35,
+    SpvDecorationAlignment = 36,
+    SpvDecorationXfbBuffer = 37,
+    SpvDecorationStride = 38,
+    SpvDecorationBuiltIn = 39,
+    SpvDecorationFuncParamAttr = 40,
+    SpvDecorationFPRoundingMode = 41,
+    SpvDecorationFPFastMathMode = 42,
+    SpvDecorationLinkageAttributes = 43,
+    SpvDecorationSpecId = 44,
+} SpvDecoration;
+
+typedef enum SpvBuiltIn_ {
+    SpvBuiltInPosition = 0,
+    SpvBuiltInPointSize = 1,
+    SpvBuiltInClipVertex = 2,
+    SpvBuiltInClipDistance = 3,
+    SpvBuiltInCullDistance = 4,
+    SpvBuiltInVertexId = 5,
+    SpvBuiltInInstanceId = 6,
+    SpvBuiltInPrimitiveId = 7,
+    SpvBuiltInInvocationId = 8,
+    SpvBuiltInLayer = 9,
+    SpvBuiltInViewportIndex = 10,
+    SpvBuiltInTessLevelOuter = 11,
+    SpvBuiltInTessLevelInner = 12,
+    SpvBuiltInTessCoord = 13,
+    SpvBuiltInPatchVertices = 14,
+    SpvBuiltInFragCoord = 15,
+    SpvBuiltInPointCoord = 16,
+    SpvBuiltInFrontFacing = 17,
+    SpvBuiltInSampleId = 18,
+    SpvBuiltInSamplePosition = 19,
+    SpvBuiltInSampleMask = 20,
+    SpvBuiltInFragColor = 21,
+    SpvBuiltInFragDepth = 22,
+    SpvBuiltInHelperInvocation = 23,
+    SpvBuiltInNumWorkgroups = 24,
+    SpvBuiltInWorkgroupSize = 25,
+    SpvBuiltInWorkgroupId = 26,
+    SpvBuiltInLocalInvocationId = 27,
+    SpvBuiltInGlobalInvocationId = 28,
+    SpvBuiltInLocalInvocationIndex = 29,
+    SpvBuiltInWorkDim = 30,
+    SpvBuiltInGlobalSize = 31,
+    SpvBuiltInEnqueuedWorkgroupSize = 32,
+    SpvBuiltInGlobalOffset = 33,
+    SpvBuiltInGlobalLinearId = 34,
+    SpvBuiltInWorkgroupLinearId = 35,
+    SpvBuiltInSubgroupSize = 36,
+    SpvBuiltInSubgroupMaxSize = 37,
+    SpvBuiltInNumSubgroups = 38,
+    SpvBuiltInNumEnqueuedSubgroups = 39,
+    SpvBuiltInSubgroupId = 40,
+    SpvBuiltInSubgroupLocalInvocationId = 41,
+} SpvBuiltIn;
+
+typedef enum SpvSelectionControlShift_ {
+    SpvSelectionControlFlattenShift = 0,
+    SpvSelectionControlDontFlattenShift = 1,
+} SpvSelectionControlShift;
+
+typedef enum SpvSelectionControlMask_ {
+    SpvSelectionControlMaskNone = 0,
+    SpvSelectionControlFlattenMask = 0x00000001,
+    SpvSelectionControlDontFlattenMask = 0x00000002,
+} SpvSelectionControlMask;
+
+typedef enum SpvLoopControlShift_ {
+    SpvLoopControlUnrollShift = 0,
+    SpvLoopControlDontUnrollShift = 1,
+} SpvLoopControlShift;
+
+typedef enum SpvLoopControlMask_ {
+    SpvLoopControlMaskNone = 0,
+    SpvLoopControlUnrollMask = 0x00000001,
+    SpvLoopControlDontUnrollMask = 0x00000002,
+} SpvLoopControlMask;
+
+typedef enum SpvFunctionControlShift_ {
+    SpvFunctionControlInlineShift = 0,
+    SpvFunctionControlDontInlineShift = 1,
+    SpvFunctionControlPureShift = 2,
+    SpvFunctionControlConstShift = 3,
+} SpvFunctionControlShift;
+
+typedef enum SpvFunctionControlMask_ {
+    SpvFunctionControlMaskNone = 0,
+    SpvFunctionControlInlineMask = 0x00000001,
+    SpvFunctionControlDontInlineMask = 0x00000002,
+    SpvFunctionControlPureMask = 0x00000004,
+    SpvFunctionControlConstMask = 0x00000008,
+} SpvFunctionControlMask;
+
+typedef enum SpvMemorySemanticsShift_ {
+    SpvMemorySemanticsRelaxedShift = 0,
+    SpvMemorySemanticsSequentiallyConsistentShift = 1,
+    SpvMemorySemanticsAcquireShift = 2,
+    SpvMemorySemanticsReleaseShift = 3,
+    SpvMemorySemanticsUniformMemoryShift = 4,
+    SpvMemorySemanticsSubgroupMemoryShift = 5,
+    SpvMemorySemanticsWorkgroupLocalMemoryShift = 6,
+    SpvMemorySemanticsWorkgroupGlobalMemoryShift = 7,
+    SpvMemorySemanticsAtomicCounterMemoryShift = 8,
+    SpvMemorySemanticsImageMemoryShift = 9,
+} SpvMemorySemanticsShift;
+
+typedef enum SpvMemorySemanticsMask_ {
+    SpvMemorySemanticsMaskNone = 0,
+    SpvMemorySemanticsRelaxedMask = 0x00000001,
+    SpvMemorySemanticsSequentiallyConsistentMask = 0x00000002,
+    SpvMemorySemanticsAcquireMask = 0x00000004,
+    SpvMemorySemanticsReleaseMask = 0x00000008,
+    SpvMemorySemanticsUniformMemoryMask = 0x00000010,
+    SpvMemorySemanticsSubgroupMemoryMask = 0x00000020,
+    SpvMemorySemanticsWorkgroupLocalMemoryMask = 0x00000040,
+    SpvMemorySemanticsWorkgroupGlobalMemoryMask = 0x00000080,
+    SpvMemorySemanticsAtomicCounterMemoryMask = 0x00000100,
+    SpvMemorySemanticsImageMemoryMask = 0x00000200,
+} SpvMemorySemanticsMask;
+
+typedef enum SpvMemoryAccessShift_ {
+    SpvMemoryAccessVolatileShift = 0,
+    SpvMemoryAccessAlignedShift = 1,
+} SpvMemoryAccessShift;
+
+typedef enum SpvMemoryAccessMask_ {
+    SpvMemoryAccessMaskNone = 0,
+    SpvMemoryAccessVolatileMask = 0x00000001,
+    SpvMemoryAccessAlignedMask = 0x00000002,
+} SpvMemoryAccessMask;
+
+typedef enum SpvExecutionScope_ {
+    SpvExecutionScopeCrossDevice = 0,
+    SpvExecutionScopeDevice = 1,
+    SpvExecutionScopeWorkgroup = 2,
+    SpvExecutionScopeSubgroup = 3,
+} SpvExecutionScope;
+
+typedef enum SpvGroupOperation_ {
+    SpvGroupOperationReduce = 0,
+    SpvGroupOperationInclusiveScan = 1,
+    SpvGroupOperationExclusiveScan = 2,
+} SpvGroupOperation;
+
+typedef enum SpvKernelEnqueueFlags_ {
+    SpvKernelEnqueueFlagsNoWait = 0,
+    SpvKernelEnqueueFlagsWaitKernel = 1,
+    SpvKernelEnqueueFlagsWaitWorkGroup = 2,
+} SpvKernelEnqueueFlags;
+
+typedef enum SpvKernelProfilingInfoShift_ {
+    SpvKernelProfilingInfoCmdExecTimeShift = 0,
+} SpvKernelProfilingInfoShift;
+
+typedef enum SpvKernelProfilingInfoMask_ {
+    SpvKernelProfilingInfoMaskNone = 0,
+    SpvKernelProfilingInfoCmdExecTimeMask = 0x00000001,
+} SpvKernelProfilingInfoMask;
+
+typedef enum SpvOp_ {
+    SpvOpNop = 0,
+    SpvOpSource = 1,
+    SpvOpSourceExtension = 2,
+    SpvOpExtension = 3,
+    SpvOpExtInstImport = 4,
+    SpvOpMemoryModel = 5,
+    SpvOpEntryPoint = 6,
+    SpvOpExecutionMode = 7,
+    SpvOpTypeVoid = 8,
+    SpvOpTypeBool = 9,
+    SpvOpTypeInt = 10,
+    SpvOpTypeFloat = 11,
+    SpvOpTypeVector = 12,
+    SpvOpTypeMatrix = 13,
+    SpvOpTypeSampler = 14,
+    SpvOpTypeFilter = 15,
+    SpvOpTypeArray = 16,
+    SpvOpTypeRuntimeArray = 17,
+    SpvOpTypeStruct = 18,
+    SpvOpTypeOpaque = 19,
+    SpvOpTypePointer = 20,
+    SpvOpTypeFunction = 21,
+    SpvOpTypeEvent = 22,
+    SpvOpTypeDeviceEvent = 23,
+    SpvOpTypeReserveId = 24,
+    SpvOpTypeQueue = 25,
+    SpvOpTypePipe = 26,
+    SpvOpConstantTrue = 27,
+    SpvOpConstantFalse = 28,
+    SpvOpConstant = 29,
+    SpvOpConstantComposite = 30,
+    SpvOpConstantSampler = 31,
+    SpvOpConstantNullPointer = 32,
+    SpvOpConstantNullObject = 33,
+    SpvOpSpecConstantTrue = 34,
+    SpvOpSpecConstantFalse = 35,
+    SpvOpSpecConstant = 36,
+    SpvOpSpecConstantComposite = 37,
+    SpvOpVariable = 38,
+    SpvOpVariableArray = 39,
+    SpvOpFunction = 40,
+    SpvOpFunctionParameter = 41,
+    SpvOpFunctionEnd = 42,
+    SpvOpFunctionCall = 43,
+    SpvOpExtInst = 44,
+    SpvOpUndef = 45,
+    SpvOpLoad = 46,
+    SpvOpStore = 47,
+    SpvOpPhi = 48,
+    SpvOpDecorationGroup = 49,
+    SpvOpDecorate = 50,
+    SpvOpMemberDecorate = 51,
+    SpvOpGroupDecorate = 52,
+    SpvOpGroupMemberDecorate = 53,
+    SpvOpName = 54,
+    SpvOpMemberName = 55,
+    SpvOpString = 56,
+    SpvOpLine = 57,
+    SpvOpVectorExtractDynamic = 58,
+    SpvOpVectorInsertDynamic = 59,
+    SpvOpVectorShuffle = 60,
+    SpvOpCompositeConstruct = 61,
+    SpvOpCompositeExtract = 62,
+    SpvOpCompositeInsert = 63,
+    SpvOpCopyObject = 64,
+    SpvOpCopyMemory = 65,
+    SpvOpCopyMemorySized = 66,
+    SpvOpSampler = 67,
+    SpvOpTextureSample = 68,
+    SpvOpTextureSampleDref = 69,
+    SpvOpTextureSampleLod = 70,
+    SpvOpTextureSampleProj = 71,
+    SpvOpTextureSampleGrad = 72,
+    SpvOpTextureSampleOffset = 73,
+    SpvOpTextureSampleProjLod = 74,
+    SpvOpTextureSampleProjGrad = 75,
+    SpvOpTextureSampleLodOffset = 76,
+    SpvOpTextureSampleProjOffset = 77,
+    SpvOpTextureSampleGradOffset = 78,
+    SpvOpTextureSampleProjLodOffset = 79,
+    SpvOpTextureSampleProjGradOffset = 80,
+    SpvOpTextureFetchTexelLod = 81,
+    SpvOpTextureFetchTexelOffset = 82,
+    SpvOpTextureFetchSample = 83,
+    SpvOpTextureFetchTexel = 84,
+    SpvOpTextureGather = 85,
+    SpvOpTextureGatherOffset = 86,
+    SpvOpTextureGatherOffsets = 87,
+    SpvOpTextureQuerySizeLod = 88,
+    SpvOpTextureQuerySize = 89,
+    SpvOpTextureQueryLod = 90,
+    SpvOpTextureQueryLevels = 91,
+    SpvOpTextureQuerySamples = 92,
+    SpvOpAccessChain = 93,
+    SpvOpInBoundsAccessChain = 94,
+    SpvOpSNegate = 95,
+    SpvOpFNegate = 96,
+    SpvOpNot = 97,
+    SpvOpAny = 98,
+    SpvOpAll = 99,
+    SpvOpConvertFToU = 100,
+    SpvOpConvertFToS = 101,
+    SpvOpConvertSToF = 102,
+    SpvOpConvertUToF = 103,
+    SpvOpUConvert = 104,
+    SpvOpSConvert = 105,
+    SpvOpFConvert = 106,
+    SpvOpConvertPtrToU = 107,
+    SpvOpConvertUToPtr = 108,
+    SpvOpPtrCastToGeneric = 109,
+    SpvOpGenericCastToPtr = 110,
+    SpvOpBitcast = 111,
+    SpvOpTranspose = 112,
+    SpvOpIsNan = 113,
+    SpvOpIsInf = 114,
+    SpvOpIsFinite = 115,
+    SpvOpIsNormal = 116,
+    SpvOpSignBitSet = 117,
+    SpvOpLessOrGreater = 118,
+    SpvOpOrdered = 119,
+    SpvOpUnordered = 120,
+    SpvOpArrayLength = 121,
+    SpvOpIAdd = 122,
+    SpvOpFAdd = 123,
+    SpvOpISub = 124,
+    SpvOpFSub = 125,
+    SpvOpIMul = 126,
+    SpvOpFMul = 127,
+    SpvOpUDiv = 128,
+    SpvOpSDiv = 129,
+    SpvOpFDiv = 130,
+    SpvOpUMod = 131,
+    SpvOpSRem = 132,
+    SpvOpSMod = 133,
+    SpvOpFRem = 134,
+    SpvOpFMod = 135,
+    SpvOpVectorTimesScalar = 136,
+    SpvOpMatrixTimesScalar = 137,
+    SpvOpVectorTimesMatrix = 138,
+    SpvOpMatrixTimesVector = 139,
+    SpvOpMatrixTimesMatrix = 140,
+    SpvOpOuterProduct = 141,
+    SpvOpDot = 142,
+    SpvOpShiftRightLogical = 143,
+    SpvOpShiftRightArithmetic = 144,
+    SpvOpShiftLeftLogical = 145,
+    SpvOpLogicalOr = 146,
+    SpvOpLogicalXor = 147,
+    SpvOpLogicalAnd = 148,
+    SpvOpBitwiseOr = 149,
+    SpvOpBitwiseXor = 150,
+    SpvOpBitwiseAnd = 151,
+    SpvOpSelect = 152,
+    SpvOpIEqual = 153,
+    SpvOpFOrdEqual = 154,
+    SpvOpFUnordEqual = 155,
+    SpvOpINotEqual = 156,
+    SpvOpFOrdNotEqual = 157,
+    SpvOpFUnordNotEqual = 158,
+    SpvOpULessThan = 159,
+    SpvOpSLessThan = 160,
+    SpvOpFOrdLessThan = 161,
+    SpvOpFUnordLessThan = 162,
+    SpvOpUGreaterThan = 163,
+    SpvOpSGreaterThan = 164,
+    SpvOpFOrdGreaterThan = 165,
+    SpvOpFUnordGreaterThan = 166,
+    SpvOpULessThanEqual = 167,
+    SpvOpSLessThanEqual = 168,
+    SpvOpFOrdLessThanEqual = 169,
+    SpvOpFUnordLessThanEqual = 170,
+    SpvOpUGreaterThanEqual = 171,
+    SpvOpSGreaterThanEqual = 172,
+    SpvOpFOrdGreaterThanEqual = 173,
+    SpvOpFUnordGreaterThanEqual = 174,
+    SpvOpDPdx = 175,
+    SpvOpDPdy = 176,
+    SpvOpFwidth = 177,
+    SpvOpDPdxFine = 178,
+    SpvOpDPdyFine = 179,
+    SpvOpFwidthFine = 180,
+    SpvOpDPdxCoarse = 181,
+    SpvOpDPdyCoarse = 182,
+    SpvOpFwidthCoarse = 183,
+    SpvOpEmitVertex = 184,
+    SpvOpEndPrimitive = 185,
+    SpvOpEmitStreamVertex = 186,
+    SpvOpEndStreamPrimitive = 187,
+    SpvOpControlBarrier = 188,
+    SpvOpMemoryBarrier = 189,
+    SpvOpImagePointer = 190,
+    SpvOpAtomicInit = 191,
+    SpvOpAtomicLoad = 192,
+    SpvOpAtomicStore = 193,
+    SpvOpAtomicExchange = 194,
+    SpvOpAtomicCompareExchange = 195,
+    SpvOpAtomicCompareExchangeWeak = 196,
+    SpvOpAtomicIIncrement = 197,
+    SpvOpAtomicIDecrement = 198,
+    SpvOpAtomicIAdd = 199,
+    SpvOpAtomicISub = 200,
+    SpvOpAtomicUMin = 201,
+    SpvOpAtomicUMax = 202,
+    SpvOpAtomicAnd = 203,
+    SpvOpAtomicOr = 204,
+    SpvOpAtomicXor = 205,
+    SpvOpLoopMerge = 206,
+    SpvOpSelectionMerge = 207,
+    SpvOpLabel = 208,
+    SpvOpBranch = 209,
+    SpvOpBranchConditional = 210,
+    SpvOpSwitch = 211,
+    SpvOpKill = 212,
+    SpvOpReturn = 213,
+    SpvOpReturnValue = 214,
+    SpvOpUnreachable = 215,
+    SpvOpLifetimeStart = 216,
+    SpvOpLifetimeStop = 217,
+    SpvOpCompileFlag = 218,
+    SpvOpAsyncGroupCopy = 219,
+    SpvOpWaitGroupEvents = 220,
+    SpvOpGroupAll = 221,
+    SpvOpGroupAny = 222,
+    SpvOpGroupBroadcast = 223,
+    SpvOpGroupIAdd = 224,
+    SpvOpGroupFAdd = 225,
+    SpvOpGroupFMin = 226,
+    SpvOpGroupUMin = 227,
+    SpvOpGroupSMin = 228,
+    SpvOpGroupFMax = 229,
+    SpvOpGroupUMax = 230,
+    SpvOpGroupSMax = 231,
+    SpvOpGenericCastToPtrExplicit = 232,
+    SpvOpGenericPtrMemSemantics = 233,
+    SpvOpReadPipe = 234,
+    SpvOpWritePipe = 235,
+    SpvOpReservedReadPipe = 236,
+    SpvOpReservedWritePipe = 237,
+    SpvOpReserveReadPipePackets = 238,
+    SpvOpReserveWritePipePackets = 239,
+    SpvOpCommitReadPipe = 240,
+    SpvOpCommitWritePipe = 241,
+    SpvOpIsValidReserveId = 242,
+    SpvOpGetNumPipePackets = 243,
+    SpvOpGetMaxPipePackets = 244,
+    SpvOpGroupReserveReadPipePackets = 245,
+    SpvOpGroupReserveWritePipePackets = 246,
+    SpvOpGroupCommitReadPipe = 247,
+    SpvOpGroupCommitWritePipe = 248,
+    SpvOpEnqueueMarker = 249,
+    SpvOpEnqueueKernel = 250,
+    SpvOpGetKernelNDrangeSubGroupCount = 251,
+    SpvOpGetKernelNDrangeMaxSubGroupSize = 252,
+    SpvOpGetKernelWorkGroupSize = 253,
+    SpvOpGetKernelPreferredWorkGroupSizeMultiple = 254,
+    SpvOpRetainEvent = 255,
+    SpvOpReleaseEvent = 256,
+    SpvOpCreateUserEvent = 257,
+    SpvOpIsValidEvent = 258,
+    SpvOpSetUserEventStatus = 259,
+    SpvOpCaptureEventProfilingInfo = 260,
+    SpvOpGetDefaultQueue = 261,
+    SpvOpBuildNDRange = 262,
+    SpvOpSatConvertSToU = 263,
+    SpvOpSatConvertUToS = 264,
+    SpvOpAtomicIMin = 265,
+    SpvOpAtomicIMax = 266,
+} SpvOp;
+
+#endif  // #ifndef __cplusplus
+
+#endif  // #ifndef spirv_H
index ec75824..028671d 100644 (file)
-//\r
-//Copyright (C) 2014 LunarG, Inc.\r
-//\r
-//All rights reserved.\r
-//\r
-//Redistribution and use in source and binary forms, with or without\r
-//modification, are permitted provided that the following conditions\r
-//are met:\r
-//\r
-//    Redistributions of source code must retain the above copyright\r
-//    notice, this list of conditions and the following disclaimer.\r
-//\r
-//    Redistributions in binary form must reproduce the above\r
-//    copyright notice, this list of conditions and the following\r
-//    disclaimer in the documentation and/or other materials provided\r
-//    with the distribution.\r
-//\r
-//    Neither the name of 3Dlabs Inc. Ltd. nor the names of its\r
-//    contributors may be used to endorse or promote products derived\r
-//    from this software without specific prior written permission.\r
-//\r
-//THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\r
-//"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\r
-//LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS\r
-//FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE\r
-//COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,\r
-//INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,\r
-//BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\r
-//LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER\r
-//CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\r
-//LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN\r
-//ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE\r
-//POSSIBILITY OF SUCH DAMAGE.\r
-\r
-//\r
-// Author: John Kessenich, LunarG\r
-//\r
-\r
-// SPIRV-IR\r
-//\r
-// Simple in-memory representation (IR) of SPIRV.  Just for holding\r
-// Each function's CFG of blocks.  Has this hierarchy:\r
-//  - Module, which is a list of \r
-//    - Function, which is a list of \r
-//      - Block, which is a list of \r
-//        - Instruction\r
-//\r
-\r
-#pragma once\r
-#ifndef spvIR_H\r
-#define spvIR_H\r
-\r
-#include "spirv.h"\r
-\r
-#include <vector>\r
-#include <iostream>\r
-#include <assert.h>\r
-\r
-namespace spv {\r
-\r
-class Function;\r
-class Module;\r
-\r
-const Id NoResult = 0;\r
-const Id NoType = 0;\r
-\r
-const unsigned int BadValue = 0xFFFFFFFF;\r
-const Decoration NoPrecision = (Decoration)BadValue;\r
-const MemorySemanticsMask MemorySemanticsAllMemory = (MemorySemanticsMask)0x3FF;\r
-\r
-//\r
-// SPIR-V IR instruction.\r
-//\r
-\r
-class Instruction {\r
-public:\r
-    Instruction(Id resultId, Id typeId, Op opCode) : resultId(resultId), typeId(typeId), opCode(opCode), string(0) { }\r
-    explicit Instruction(Op opCode) : resultId(NoResult), typeId(NoType), opCode(opCode), string(0) { }\r
-    virtual ~Instruction()\r
-    {\r
-        delete string;\r
-    }\r
-    void addIdOperand(Id id) { operands.push_back(id); }\r
-    void addImmediateOperand(unsigned int immediate) { operands.push_back(immediate); }\r
-    void addStringOperand(const char* str)\r
-    {\r
-        originalString = str;\r
-        string = new std::vector<unsigned int>;\r
-        unsigned int word;\r
-        char* wordString = (char*)&word;\r
-        char* wordPtr = wordString;\r
-        int charCount = 0;\r
-        char c;\r
-        do {\r
-            c = *(str++);\r
-            *(wordPtr++) = c;\r
-            ++charCount;\r
-            if (charCount == 4) {\r
-                string->push_back(word);\r
-                wordPtr = wordString;\r
-                charCount = 0;\r
-            }\r
-        } while (c != 0);\r
-\r
-        // deal with partial last word\r
-        if (charCount > 0) {\r
-            // pad with 0s\r
-            for (; charCount < 4; ++charCount)\r
-                *(wordPtr++) = 0;\r
-            string->push_back(word);\r
-        }\r
-    }\r
-    Op getOpCode() const { return opCode; }\r
-    int getNumOperands() const { return (int)operands.size(); }\r
-    Id getResultId() const { return resultId; }\r
-    Id getTypeId() const { return typeId; }\r
-    Id getIdOperand(int op) const { return operands[op]; }\r
-    unsigned int getImmediateOperand(int op) const { return operands[op]; }\r
-    const char* getStringOperand() const { return originalString.c_str(); }\r
-\r
-    // Write out the binary form.\r
-    void dump(std::vector<unsigned int>& out) const\r
-    {\r
-        // Compute the wordCount\r
-        unsigned int wordCount = 1;\r
-        if (typeId)\r
-            ++wordCount;\r
-        if (resultId)\r
-            ++wordCount;\r
-        wordCount += (unsigned int)operands.size();\r
-        if (string)\r
-            wordCount += (unsigned int)string->size();\r
-\r
-        // Write out the beginning of the instruction\r
-        out.push_back(((wordCount) << WordCountShift) | opCode);\r
-        if (typeId)\r
-            out.push_back(typeId);\r
-        if (resultId)\r
-            out.push_back(resultId);\r
-\r
-        // Write out the operands\r
-        for (int op = 0; op < (int)operands.size(); ++op)\r
-            out.push_back(operands[op]);\r
-        if (string)\r
-            for (int op = 0; op < (int)string->size(); ++op)\r
-                out.push_back((*string)[op]);\r
-    }\r
-\r
-protected:\r
-    Instruction(const Instruction&);\r
-    Id resultId;\r
-    Id typeId;\r
-    Op opCode;\r
-    std::vector<Id> operands;\r
-    std::vector<unsigned int>* string; // usually non-existent\r
-    std::string originalString;        // could be optimized away; convenience for getting string operand\r
-};\r
-\r
-//\r
-// SPIR-V IR block.\r
-//\r
-\r
-class Block {\r
-public:\r
-    Block(Id id, Function& parent);\r
-    virtual ~Block()\r
-    {\r
-        // TODO: free instructions\r
-    }\r
-    \r
-    Id getId() { return instructions.front()->getResultId(); }\r
-\r
-    Function& getParent() const { return parent; }\r
-    void addInstruction(Instruction* inst);\r
-    void addPredecessor(Block* pred) { predecessors.push_back(pred); }\r
-    void addLocalVariable(Instruction* inst) { localVariables.push_back(inst); }\r
-    int getNumPredecessors() const { return (int)predecessors.size(); }\r
-    void setUnreachable() { unreachable = true; }\r
-    bool isUnreachable() const { return unreachable; }\r
-\r
-    bool isTerminated() const\r
-    {\r
-        switch (instructions.back()->getOpCode()) {\r
-        case OpBranch:\r
-        case OpBranchConditional:\r
-        case OpSwitch:\r
-        case OpKill:\r
-        case OpReturn:\r
-        case OpReturnValue:\r
-            return true;\r
-        default:\r
-            return false;\r
-        }\r
-    }\r
-\r
-    void dump(std::vector<unsigned int>& out) const\r
-    {\r
-        // skip the degenerate unreachable blocks\r
-        // TODO: code gen: skip all unreachable blocks (transitive closure)\r
-        //                 (but, until that's done safer to keep non-degenerate unreachable blocks, in case others depend on something)\r
-        if (unreachable && instructions.size() <= 2)\r
-            return;\r
-\r
-        instructions[0]->dump(out);\r
-        for (int i = 0; i < (int)localVariables.size(); ++i)\r
-            localVariables[i]->dump(out);\r
-        for (int i = 1; i < (int)instructions.size(); ++i)\r
-            instructions[i]->dump(out);\r
-    }\r
-\r
-protected:\r
-    Block(const Block&);\r
-    Block& operator=(Block&);\r
-\r
-    // To enforce keeping parent and ownership in sync:\r
-    friend Function;\r
-\r
-    std::vector<Instruction*> instructions;\r
-    std::vector<Block*> predecessors;\r
-    std::vector<Instruction*> localVariables;\r
-    Function& parent;\r
-\r
-    // track whether this block is known to be uncreachable (not necessarily \r
-    // true for all unreachable blocks, but should be set at least\r
-    // for the extraneous ones introduced by the builder).\r
-    bool unreachable;\r
-};\r
-\r
-//\r
-// SPIR-V IR Function.\r
-//\r
-\r
-class Function {\r
-public:\r
-    Function(Id id, Id resultType, Id functionType, Id firstParam, Module& parent);\r
-    virtual ~Function()\r
-    {\r
-        for (int i = 0; i < (int)parameterInstructions.size(); ++i)\r
-            delete parameterInstructions[i];\r
-\r
-        for (int i = 0; i < (int)blocks.size(); ++i)\r
-            delete blocks[i];\r
-    }\r
-    Id getId() const { return functionInstruction.getResultId(); }\r
-    Id getParamId(int p) { return parameterInstructions[p]->getResultId(); }\r
-\r
-    void addBlock(Block* block) { blocks.push_back(block); }\r
-    void popBlock(Block*) { blocks.pop_back(); }\r
-\r
-    Module& getParent() const { return parent; }\r
-    Block* getEntryBlock() const { return blocks.front(); }\r
-    Block* getLastBlock() const { return blocks.back(); }\r
-    void addLocalVariable(Instruction* inst);\r
-    Id getReturnType() const { return functionInstruction.getTypeId(); }\r
-    void dump(std::vector<unsigned int>& out) const\r
-    {\r
-        // OpFunction\r
-        functionInstruction.dump(out);\r
-\r
-        // OpFunctionParameter\r
-        for (int p = 0; p < (int)parameterInstructions.size(); ++p)\r
-            parameterInstructions[p]->dump(out);\r
-\r
-        // Blocks\r
-        for (int b = 0; b < (int)blocks.size(); ++b)\r
-            blocks[b]->dump(out);\r
-        Instruction end(0, 0, OpFunctionEnd);\r
-        end.dump(out);\r
-    }\r
-\r
-protected:\r
-    Function(const Function&);\r
-    Function& operator=(Function&);\r
-\r
-    Module& parent;\r
-    Instruction functionInstruction;\r
-    std::vector<Instruction*> parameterInstructions;\r
-    std::vector<Block*> blocks;\r
-};\r
-\r
-//\r
-// SPIR-V IR Module.\r
-//\r
-\r
-class Module {\r
-public:\r
-    Module() {}\r
-    virtual ~Module()\r
-    {\r
-        // TODO delete things\r
-    }\r
-\r
-    void addFunction(Function *fun) { functions.push_back(fun); }\r
-\r
-    void mapInstruction(Instruction *instruction)\r
-    {\r
-        spv::Id resultId = instruction->getResultId();\r
-        // map the instruction's result id\r
-        if (resultId >= idToInstruction.size())\r
-            idToInstruction.resize(resultId + 16);\r
-        idToInstruction[resultId] = instruction;\r
-    }\r
-\r
-    Instruction* getInstruction(Id id) const { return idToInstruction[id]; }\r
-    spv::Id getTypeId(Id resultId) const { return idToInstruction[resultId]->getTypeId(); }\r
-    StorageClass getStorageClass(Id typeId) const { return (StorageClass)idToInstruction[typeId]->getImmediateOperand(0); }\r
-    void dump(std::vector<unsigned int>& out) const\r
-    {\r
-        for (int f = 0; f < (int)functions.size(); ++f)\r
-            functions[f]->dump(out);\r
-    }\r
-\r
-protected:\r
-    Module(const Module&);\r
-    std::vector<Function*> functions;\r
-\r
-    // map from result id to instruction having that result id\r
-    std::vector<Instruction*> idToInstruction;\r
-\r
-    // map from a result id to its type id\r
-};\r
-\r
-//\r
-// Implementation (it's here due to circular type definitions).\r
-//\r
-\r
-// Add both\r
-// - the OpFunction instruction\r
-// - all the OpFunctionParameter instructions\r
-__inline Function::Function(Id id, Id resultType, Id functionType, Id firstParamId, Module& parent)\r
-    : parent(parent), functionInstruction(id, resultType, OpFunction)\r
-{\r
-    // OpFunction\r
-    functionInstruction.addImmediateOperand(FunctionControlMaskNone);\r
-    functionInstruction.addIdOperand(functionType);\r
-    parent.mapInstruction(&functionInstruction);\r
-    parent.addFunction(this);\r
-\r
-    // OpFunctionParameter\r
-    Instruction* typeInst = parent.getInstruction(functionType);\r
-    int numParams = typeInst->getNumOperands() - 1;\r
-    for (int p = 0; p < numParams; ++p) {\r
-        Instruction* param = new Instruction(firstParamId + p, typeInst->getIdOperand(p + 1), OpFunctionParameter);\r
-        parent.mapInstruction(param);\r
-        parameterInstructions.push_back(param);\r
-    }\r
-}\r
-\r
-__inline void Function::addLocalVariable(Instruction* inst)\r
-{\r
-    blocks[0]->addLocalVariable(inst);\r
-    parent.mapInstruction(inst);\r
-}\r
-\r
-__inline Block::Block(Id id, Function& parent) : parent(parent), unreachable(false)\r
-{\r
-    instructions.push_back(new Instruction(id, NoType, OpLabel));\r
-}\r
-\r
-__inline void Block::addInstruction(Instruction* inst)\r
-{\r
-    instructions.push_back(inst);\r
-    if (inst->getResultId())\r
-        parent.getParent().mapInstruction(inst);\r
-}\r
-\r
-};  // end spv namespace\r
-\r
-#endif // spvIR_H\r
+//
+//Copyright (C) 2014 LunarG, Inc.
+//
+//All rights reserved.
+//
+//Redistribution and use in source and binary forms, with or without
+//modification, are permitted provided that the following conditions
+//are met:
+//
+//    Redistributions of source code must retain the above copyright
+//    notice, this list of conditions and the following disclaimer.
+//
+//    Redistributions in binary form must reproduce the above
+//    copyright notice, this list of conditions and the following
+//    disclaimer in the documentation and/or other materials provided
+//    with the distribution.
+//
+//    Neither the name of 3Dlabs Inc. Ltd. nor the names of its
+//    contributors may be used to endorse or promote products derived
+//    from this software without specific prior written permission.
+//
+//THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+//"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+//LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+//FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+//COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+//INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+//BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+//LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+//CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+//LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+//ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+//POSSIBILITY OF SUCH DAMAGE.
+
+//
+// Author: John Kessenich, LunarG
+//
+
+// SPIRV-IR
+//
+// Simple in-memory representation (IR) of SPIRV.  Just for holding
+// Each function's CFG of blocks.  Has this hierarchy:
+//  - Module, which is a list of 
+//    - Function, which is a list of 
+//      - Block, which is a list of 
+//        - Instruction
+//
+
+#pragma once
+#ifndef spvIR_H
+#define spvIR_H
+
+#include "spirv.h"
+
+#include <vector>
+#include <iostream>
+#include <assert.h>
+
+namespace spv {
+
+class Function;
+class Module;
+
+const Id NoResult = 0;
+const Id NoType = 0;
+
+const unsigned int BadValue = 0xFFFFFFFF;
+const Decoration NoPrecision = (Decoration)BadValue;
+const MemorySemanticsMask MemorySemanticsAllMemory = (MemorySemanticsMask)0x3FF;
+
+//
+// SPIR-V IR instruction.
+//
+
+class Instruction {
+public:
+    Instruction(Id resultId, Id typeId, Op opCode) : resultId(resultId), typeId(typeId), opCode(opCode), string(0) { }
+    explicit Instruction(Op opCode) : resultId(NoResult), typeId(NoType), opCode(opCode), string(0) { }
+    virtual ~Instruction()
+    {
+        delete string;
+    }
+    void addIdOperand(Id id) { operands.push_back(id); }
+    void addImmediateOperand(unsigned int immediate) { operands.push_back(immediate); }
+    void addStringOperand(const char* str)
+    {
+        originalString = str;
+        string = new std::vector<unsigned int>;
+        unsigned int word;
+        char* wordString = (char*)&word;
+        char* wordPtr = wordString;
+        int charCount = 0;
+        char c;
+        do {
+            c = *(str++);
+            *(wordPtr++) = c;
+            ++charCount;
+            if (charCount == 4) {
+                string->push_back(word);
+                wordPtr = wordString;
+                charCount = 0;
+            }
+        } while (c != 0);
+
+        // deal with partial last word
+        if (charCount > 0) {
+            // pad with 0s
+            for (; charCount < 4; ++charCount)
+                *(wordPtr++) = 0;
+            string->push_back(word);
+        }
+    }
+    Op getOpCode() const { return opCode; }
+    int getNumOperands() const { return (int)operands.size(); }
+    Id getResultId() const { return resultId; }
+    Id getTypeId() const { return typeId; }
+    Id getIdOperand(int op) const { return operands[op]; }
+    unsigned int getImmediateOperand(int op) const { return operands[op]; }
+    const char* getStringOperand() const { return originalString.c_str(); }
+
+    // Write out the binary form.
+    void dump(std::vector<unsigned int>& out) const
+    {
+        // Compute the wordCount
+        unsigned int wordCount = 1;
+        if (typeId)
+            ++wordCount;
+        if (resultId)
+            ++wordCount;
+        wordCount += (unsigned int)operands.size();
+        if (string)
+            wordCount += (unsigned int)string->size();
+
+        // Write out the beginning of the instruction
+        out.push_back(((wordCount) << WordCountShift) | opCode);
+        if (typeId)
+            out.push_back(typeId);
+        if (resultId)
+            out.push_back(resultId);
+
+        // Write out the operands
+        for (int op = 0; op < (int)operands.size(); ++op)
+            out.push_back(operands[op]);
+        if (string)
+            for (int op = 0; op < (int)string->size(); ++op)
+                out.push_back((*string)[op]);
+    }
+
+protected:
+    Instruction(const Instruction&);
+    Id resultId;
+    Id typeId;
+    Op opCode;
+    std::vector<Id> operands;
+    std::vector<unsigned int>* string; // usually non-existent
+    std::string originalString;        // could be optimized away; convenience for getting string operand
+};
+
+//
+// SPIR-V IR block.
+//
+
+class Block {
+public:
+    Block(Id id, Function& parent);
+    virtual ~Block()
+    {
+        // TODO: free instructions
+    }
+    
+    Id getId() { return instructions.front()->getResultId(); }
+
+    Function& getParent() const { return parent; }
+    void addInstruction(Instruction* inst);
+    void addPredecessor(Block* pred) { predecessors.push_back(pred); }
+    void addLocalVariable(Instruction* inst) { localVariables.push_back(inst); }
+    int getNumPredecessors() const { return (int)predecessors.size(); }
+    void setUnreachable() { unreachable = true; }
+    bool isUnreachable() const { return unreachable; }
+
+    bool isTerminated() const
+    {
+        switch (instructions.back()->getOpCode()) {
+        case OpBranch:
+        case OpBranchConditional:
+        case OpSwitch:
+        case OpKill:
+        case OpReturn:
+        case OpReturnValue:
+            return true;
+        default:
+            return false;
+        }
+    }
+
+    void dump(std::vector<unsigned int>& out) const
+    {
+        // skip the degenerate unreachable blocks
+        // TODO: code gen: skip all unreachable blocks (transitive closure)
+        //                 (but, until that's done safer to keep non-degenerate unreachable blocks, in case others depend on something)
+        if (unreachable && instructions.size() <= 2)
+            return;
+
+        instructions[0]->dump(out);
+        for (int i = 0; i < (int)localVariables.size(); ++i)
+            localVariables[i]->dump(out);
+        for (int i = 1; i < (int)instructions.size(); ++i)
+            instructions[i]->dump(out);
+    }
+
+protected:
+    Block(const Block&);
+    Block& operator=(Block&);
+
+    // To enforce keeping parent and ownership in sync:
+    friend Function;
+
+    std::vector<Instruction*> instructions;
+    std::vector<Block*> predecessors;
+    std::vector<Instruction*> localVariables;
+    Function& parent;
+
+    // track whether this block is known to be uncreachable (not necessarily 
+    // true for all unreachable blocks, but should be set at least
+    // for the extraneous ones introduced by the builder).
+    bool unreachable;
+};
+
+//
+// SPIR-V IR Function.
+//
+
+class Function {
+public:
+    Function(Id id, Id resultType, Id functionType, Id firstParam, Module& parent);
+    virtual ~Function()
+    {
+        for (int i = 0; i < (int)parameterInstructions.size(); ++i)
+            delete parameterInstructions[i];
+
+        for (int i = 0; i < (int)blocks.size(); ++i)
+            delete blocks[i];
+    }
+    Id getId() const { return functionInstruction.getResultId(); }
+    Id getParamId(int p) { return parameterInstructions[p]->getResultId(); }
+
+    void addBlock(Block* block) { blocks.push_back(block); }
+    void popBlock(Block*) { blocks.pop_back(); }
+
+    Module& getParent() const { return parent; }
+    Block* getEntryBlock() const { return blocks.front(); }
+    Block* getLastBlock() const { return blocks.back(); }
+    void addLocalVariable(Instruction* inst);
+    Id getReturnType() const { return functionInstruction.getTypeId(); }
+    void dump(std::vector<unsigned int>& out) const
+    {
+        // OpFunction
+        functionInstruction.dump(out);
+
+        // OpFunctionParameter
+        for (int p = 0; p < (int)parameterInstructions.size(); ++p)
+            parameterInstructions[p]->dump(out);
+
+        // Blocks
+        for (int b = 0; b < (int)blocks.size(); ++b)
+            blocks[b]->dump(out);
+        Instruction end(0, 0, OpFunctionEnd);
+        end.dump(out);
+    }
+
+protected:
+    Function(const Function&);
+    Function& operator=(Function&);
+
+    Module& parent;
+    Instruction functionInstruction;
+    std::vector<Instruction*> parameterInstructions;
+    std::vector<Block*> blocks;
+};
+
+//
+// SPIR-V IR Module.
+//
+
+class Module {
+public:
+    Module() {}
+    virtual ~Module()
+    {
+        // TODO delete things
+    }
+
+    void addFunction(Function *fun) { functions.push_back(fun); }
+
+    void mapInstruction(Instruction *instruction)
+    {
+        spv::Id resultId = instruction->getResultId();
+        // map the instruction's result id
+        if (resultId >= idToInstruction.size())
+            idToInstruction.resize(resultId + 16);
+        idToInstruction[resultId] = instruction;
+    }
+
+    Instruction* getInstruction(Id id) const { return idToInstruction[id]; }
+    spv::Id getTypeId(Id resultId) const { return idToInstruction[resultId]->getTypeId(); }
+    StorageClass getStorageClass(Id typeId) const { return (StorageClass)idToInstruction[typeId]->getImmediateOperand(0); }
+    void dump(std::vector<unsigned int>& out) const
+    {
+        for (int f = 0; f < (int)functions.size(); ++f)
+            functions[f]->dump(out);
+    }
+
+protected:
+    Module(const Module&);
+    std::vector<Function*> functions;
+
+    // map from result id to instruction having that result id
+    std::vector<Instruction*> idToInstruction;
+
+    // map from a result id to its type id
+};
+
+//
+// Implementation (it's here due to circular type definitions).
+//
+
+// Add both
+// - the OpFunction instruction
+// - all the OpFunctionParameter instructions
+__inline Function::Function(Id id, Id resultType, Id functionType, Id firstParamId, Module& parent)
+    : parent(parent), functionInstruction(id, resultType, OpFunction)
+{
+    // OpFunction
+    functionInstruction.addImmediateOperand(FunctionControlMaskNone);
+    functionInstruction.addIdOperand(functionType);
+    parent.mapInstruction(&functionInstruction);
+    parent.addFunction(this);
+
+    // OpFunctionParameter
+    Instruction* typeInst = parent.getInstruction(functionType);
+    int numParams = typeInst->getNumOperands() - 1;
+    for (int p = 0; p < numParams; ++p) {
+        Instruction* param = new Instruction(firstParamId + p, typeInst->getIdOperand(p + 1), OpFunctionParameter);
+        parent.mapInstruction(param);
+        parameterInstructions.push_back(param);
+    }
+}
+
+__inline void Function::addLocalVariable(Instruction* inst)
+{
+    blocks[0]->addLocalVariable(inst);
+    parent.mapInstruction(inst);
+}
+
+__inline Block::Block(Id id, Function& parent) : parent(parent), unreachable(false)
+{
+    instructions.push_back(new Instruction(id, NoType, OpLabel));
+}
+
+__inline void Block::addInstruction(Instruction* inst)
+{
+    instructions.push_back(inst);
+    if (inst->getResultId())
+        parent.getParent().mapInstruction(inst);
+}
+
+};  // end spv namespace
+
+#endif // spvIR_H
index a5592c8..f5ebab9 100644 (file)
@@ -1,41 +1,41 @@
-cmake_minimum_required(VERSION 2.8)\r
-\r
-include_directories(.)\r
-if(WIN32)\r
-    include_directories(../glslang/OSDependent/Windows)\r
-elseif(UNIX)\r
-    include_directories(../glslang/OSDependent/Linux)\r
-else(WIN32)\r
-    message("unkown platform")\r
-endif(WIN32)\r
-\r
-set(SOURCES StandAlone.cpp)\r
-set(REMAPPER_SOURCES spirv-remap.cpp)\r
-\r
-add_executable(glslangValidator ${SOURCES})\r
-add_executable(spirv-remap ${REMAPPER_SOURCES})\r
-\r
-set(LIBRARIES\r
-    glslang\r
-    OGLCompiler\r
-    OSDependent\r
-    SPIRV)\r
-\r
-if(WIN32)\r
-    set(LIBRARIES ${LIBRARIES} psapi)\r
-elseif(UNIX)\r
-    set(LIBRARIES ${LIBRARIES} pthread)\r
-endif(WIN32)\r
-\r
-target_link_libraries(glslangValidator ${LIBRARIES})\r
-target_link_libraries(spirv-remap ${LIBRARIES})\r
-\r
-if(WIN32)\r
-    source_group("Source" FILES ${SOURCES})\r
-endif(WIN32)\r
-\r
-install(TARGETS glslangValidator\r
-        RUNTIME DESTINATION bin)\r
-\r
-install(TARGETS spirv-remap\r
-        RUNTIME DESTINATION bin)\r
+cmake_minimum_required(VERSION 2.8)
+
+include_directories(.)
+if(WIN32)
+    include_directories(../glslang/OSDependent/Windows)
+elseif(UNIX)
+    include_directories(../glslang/OSDependent/Linux)
+else(WIN32)
+    message("unkown platform")
+endif(WIN32)
+
+set(SOURCES StandAlone.cpp)
+set(REMAPPER_SOURCES spirv-remap.cpp)
+
+add_executable(glslangValidator ${SOURCES})
+add_executable(spirv-remap ${REMAPPER_SOURCES})
+
+set(LIBRARIES
+    glslang
+    OGLCompiler
+    OSDependent
+    SPIRV)
+
+if(WIN32)
+    set(LIBRARIES ${LIBRARIES} psapi)
+elseif(UNIX)
+    set(LIBRARIES ${LIBRARIES} pthread)
+endif(WIN32)
+
+target_link_libraries(glslangValidator ${LIBRARIES})
+target_link_libraries(spirv-remap ${LIBRARIES})
+
+if(WIN32)
+    source_group("Source" FILES ${SOURCES})
+endif(WIN32)
+
+install(TARGETS glslangValidator
+        RUNTIME DESTINATION bin)
+
+install(TARGETS spirv-remap
+        RUNTIME DESTINATION bin)
index b3359a6..301256f 100644 (file)
-//\r
-//Copyright (C) 2015 LunarG, Inc.\r
-//\r
-//All rights reserved.\r
-//\r
-//Redistribution and use in source and binary forms, with or without\r
-//modification, are permitted provided that the following conditions\r
-//are met:\r
-//\r
-//    Redistributions of source code must retain the above copyright\r
-//    notice, this list of conditions and the following disclaimer.\r
-//\r
-//    Redistributions in binary form must reproduce the above\r
-//    copyright notice, this list of conditions and the following\r
-//    disclaimer in the documentation and/or other materials provided\r
-//    with the distribution.\r
-//\r
-//    Neither the name of 3Dlabs Inc. Ltd. nor the names of its\r
-//    contributors may be used to endorse or promote products derived\r
-//    from this software without specific prior written permission.\r
-//\r
-//THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\r
-//"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\r
-//LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS\r
-//FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE\r
-//COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,\r
-//INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,\r
-//BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\r
-//LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER\r
-//CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\r
-//LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN\r
-//ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE\r
-//POSSIBILITY OF SUCH DAMAGE.\r
-//\r
-\r
-#include <iostream>\r
-#include <fstream>\r
-#include <cstring>\r
-#include <stdexcept>\r
-\r
-#include "../SPIRV/SPVRemapper.h"\r
-\r
-namespace {\r
-\r
-    typedef unsigned int SpvWord;\r
-\r
-    // Poor man's basename: given a complete path, return file portion.\r
-    // E.g:\r
-    //      Linux:  /foo/bar/test  -> test\r
-    //      Win:   c:\foo\bar\test -> test\r
-    // It's not very efficient, but that doesn't matter for our minimal-duty use.\r
-    // Using boost::filesystem would be better in many ways, but want to avoid that dependency.\r
-\r
-    // OS dependent path separator (avoiding boost::filesystem dependency)\r
-#if defined(_WIN32)\r
-    char path_sep_char() { return '\\'; }\r
-#else\r
-    char path_sep_char() { return '/';  }\r
-#endif\r
-\r
-    std::string basename(const std::string filename)\r
-    {\r
-        const size_t sepLoc = filename.find_last_of(path_sep_char());\r
-\r
-        return (sepLoc == filename.npos) ? filename : filename.substr(sepLoc+1);\r
-    }\r
-\r
-    void errHandler(const std::string& str) {\r
-        std::cout << str << std::endl;\r
-        exit(5);\r
-    }\r
-\r
-    void logHandler(const std::string& str) {\r
-        std::cout << str << std::endl;\r
-    }\r
-\r
-    // Read word stream from disk\r
-    void read(std::vector<SpvWord>& spv, const std::string& inFilename, int verbosity)\r
-    {\r
-        std::ifstream fp;\r
-\r
-        if (verbosity > 0)\r
-            logHandler(std::string("  reading: ") + inFilename);\r
-\r
-        spv.clear();\r
-        fp.open(inFilename, std::fstream::in | std::fstream::binary);\r
-\r
-        if (fp.fail())\r
-            errHandler("error opening file for read: ");\r
-\r
-        // Reserve space (for efficiency, not for correctness)\r
-        fp.seekg(0, fp.end);\r
-        spv.reserve(size_t(fp.tellg()) / sizeof(SpvWord));\r
-        fp.seekg(0, fp.beg);\r
-\r
-        while (!fp.eof()) {\r
-            SpvWord inWord;\r
-            fp.read((char *)&inWord, sizeof(inWord));\r
-\r
-            if (!fp.eof()) {\r
-                spv.push_back(inWord);\r
-                if (fp.fail())\r
-                    errHandler(std::string("error reading file: ") + inFilename);\r
-            }\r
-        }\r
-    }\r
-\r
-    void write(std::vector<SpvWord>& spv, const std::string& outFile, int verbosity)\r
-    {\r
-        if (outFile.empty())\r
-            errHandler("missing output filename.");\r
-\r
-        std::ofstream fp;\r
-\r
-        if (verbosity > 0)\r
-            logHandler(std::string("  writing: ") + outFile);\r
-\r
-        fp.open(outFile, std::fstream::out | std::fstream::binary);\r
-\r
-        if (fp.fail())\r
-            errHandler(std::string("error opening file for write: ") + outFile);\r
-\r
-        for (auto word : spv) {\r
-            fp.write((char *)&word, sizeof(word));\r
-            if (fp.fail())\r
-                errHandler(std::string("error writing file: ") + outFile);\r
-        }\r
-\r
-        // file is closed by destructor\r
-    }\r
-\r
-    // Print helpful usage message to stdout, and exit\r
-    void usage(const char* const name, const char* const msg = 0)\r
-    {\r
-        if (msg)\r
-            std::cout << msg << std::endl << std::endl;\r
-\r
-        std::cout << "Usage: " << std::endl;\r
-\r
-        std::cout << "  " << basename(name)\r
-            << " [-v[v[...]] | --verbose [int]]"\r
-            << " [--map (all|types|names|funcs)]"\r
-            << " [--dce (all|types|funcs)]"\r
-            << " [--opt (all|loadstore)]"\r
-            << " [--strip-all | --strip all | -s]" \r
-            << " [--do-everything]" \r
-            << " --input | -i file1 [file2...] --output|-o DESTDIR"\r
-            << std::endl;\r
-\r
-        std::cout << "  " << basename(name) << " [--version | -V]" << std::endl;\r
-        std::cout << "  " << basename(name) << " [--help | -?]" << std::endl;\r
-\r
-        exit(5);\r
-    }\r
-\r
-    // grind through each SPIR in turn\r
-    void execute(const std::vector<std::string>& inputFile, const std::string& outputDir,\r
-        int opts, int verbosity)\r
-    {\r
-        for (const auto& filename : inputFile) {\r
-            std::vector<SpvWord> spv;\r
-            read(spv, filename, verbosity);\r
-            spv::spirvbin_t(verbosity).remap(spv, opts);\r
-\r
-            const std::string outfile = outputDir + path_sep_char() + basename(filename);\r
-\r
-            write(spv, outfile, verbosity);\r
-        }\r
-\r
-        if (verbosity > 0)\r
-            std::cout << "Done: " << inputFile.size() << " file(s) processed" << std::endl;\r
-    }\r
-\r
-    // Parse command line options\r
-    void parseCmdLine(int argc, char** argv, std::vector<std::string>& inputFile,\r
-        std::string& outputDir,\r
-        int& options,\r
-        int& verbosity)\r
-    {\r
-        if (argc < 2)\r
-            usage(argv[0]);\r
-\r
-        verbosity  = 0;\r
-        options    = spv::spirvbin_t::NONE;\r
-\r
-        // Parse command line.\r
-        // boost::program_options would be quite a bit nicer, but we don't want to\r
-        // introduce a dependency on boost.\r
-        for (int a=1; a<argc; ) {\r
-            const std::string arg = argv[a];\r
-\r
-            if (arg == "--output" || arg == "-o") {\r
-                // Output directory\r
-                if (++a >= argc)\r
-                    usage(argv[0], "--output requires an argument");\r
-                if (!outputDir.empty())\r
-                    usage(argv[0], "--output can be provided only once");\r
-\r
-                outputDir = argv[a++];\r
-\r
-                // Remove trailing directory separator characters\r
-                while (!outputDir.empty() && outputDir.back() == path_sep_char())\r
-                    outputDir.pop_back();\r
-\r
-            }\r
-            else if (arg == "-vv")     { verbosity = 2; ++a; } // verbosity shortcuts\r
-            else if (arg == "-vvv")    { verbosity = 3; ++a; } // ...\r
-            else if (arg == "-vvvv")   { verbosity = 4; ++a; } // ...\r
-            else if (arg == "-vvvvv")  { verbosity = 5; ++a; } // ...\r
-\r
-            else if (arg == "--verbose" || arg == "-v") {\r
-                ++a;\r
-                verbosity = 1;\r
-\r
-                if (a < argc) {\r
-                    try {\r
-                        verbosity = std::stoi(argv[a]);\r
-                        ++a;\r
-                    } catch (const std::invalid_argument&) { } // ok to have no numeric value\r
-                }\r
-            }\r
-            else if (arg == "--version" || arg == "-V") {\r
-                std::cout << basename(argv[0]) << " version 0.97 " << __DATE__ << " " << __TIME__ << std::endl;\r
-                exit(0);\r
-            } else if (arg == "--input" || arg == "-i") {\r
-                // Collect input files\r
-                for (++a; a < argc && argv[a][0] != '-'; ++a)\r
-                    inputFile.push_back(argv[a]);\r
-            } else if (arg == "--do-everything") {\r
-                ++a;\r
-                options = options | spv::spirvbin_t::DO_EVERYTHING;\r
-            } else if (arg == "--strip-all" || arg == "-s") {\r
-                ++a;\r
-                options = options | spv::spirvbin_t::STRIP;\r
-            } else if (arg == "--strip") {\r
-                ++a;\r
-                if (strncmp(argv[a], "all", 3) == 0) {\r
-                    options = options | spv::spirvbin_t::STRIP;\r
-                    ++a;\r
-                }\r
-            } else if (arg == "--dce") {\r
-                // Parse comma (or colon, etc) separated list of things to dce\r
-                ++a;\r
-                for (const char* c = argv[a]; *c; ++c) {\r
-                    if (strncmp(c, "all", 3) == 0) {\r
-                        options = (options | spv::spirvbin_t::DCE_ALL);\r
-                        c += 3;\r
-                    } else if (strncmp(c, "*", 1) == 0) {\r
-                        options = (options | spv::spirvbin_t::DCE_ALL);\r
-                        c += 1;\r
-                    } else if (strncmp(c, "funcs", 5) == 0) {\r
-                        options = (options | spv::spirvbin_t::DCE_FUNCS);\r
-                        c += 5;\r
-                    } else if (strncmp(c, "types", 5) == 0) {\r
-                        options = (options | spv::spirvbin_t::DCE_TYPES);\r
-                        c += 5;\r
-                    }\r
-                }\r
-                ++a;\r
-            } else if (arg == "--map") {\r
-                // Parse comma (or colon, etc) separated list of things to map\r
-                ++a;\r
-                for (const char* c = argv[a]; *c; ++c) {\r
-                    if (strncmp(c, "all", 3) == 0) {\r
-                        options = (options | spv::spirvbin_t::MAP_ALL);\r
-                        c += 3;\r
-                    } else if (strncmp(c, "*", 1) == 0) {\r
-                        options = (options | spv::spirvbin_t::MAP_ALL);\r
-                        c += 1;\r
-                    } else if (strncmp(c, "types", 5) == 0) {\r
-                        options = (options | spv::spirvbin_t::MAP_TYPES);\r
-                        c += 5;\r
-                    } else if (strncmp(c, "names", 5) == 0) {\r
-                        options = (options | spv::spirvbin_t::MAP_NAMES);\r
-                        c += 5;\r
-                    } else if (strncmp(c, "funcs", 5) == 0) {\r
-                        options = (options | spv::spirvbin_t::MAP_FUNCS);\r
-                        c += 5;\r
-                    }\r
-                }\r
-                ++a;\r
-            } else if (arg == "--opt") {\r
-                ++a;\r
-                for (const char* c = argv[a]; *c; ++c) {\r
-                    if (strncmp(c, "all", 3) == 0) {\r
-                        options = (options | spv::spirvbin_t::OPT_ALL);\r
-                        c += 3;\r
-                    } else if (strncmp(c, "*", 1) == 0) {\r
-                        options = (options | spv::spirvbin_t::OPT_ALL);\r
-                        c += 1;\r
-                    } else if (strncmp(c, "loadstore", 9) == 0) {\r
-                        options = (options | spv::spirvbin_t::OPT_LOADSTORE);\r
-                        c += 9;\r
-                    }\r
-                }\r
-                ++a;\r
-            } else if (arg == "--help" || arg == "-?") {\r
-                usage(argv[0]);\r
-            } else {\r
-                usage(argv[0], "Unknown command line option");\r
-            }\r
-        }\r
-    }\r
-\r
-} // namespace\r
-\r
-\r
-int main(int argc, char** argv)\r
-{\r
-    std::vector<std::string> inputFile;\r
-    std::string              outputDir;\r
-    int                      opts;\r
-    int                      verbosity;\r
-\r
-#ifdef use_cpp11\r
-    // handle errors by exiting\r
-    spv::spirvbin_t::registerErrorHandler(errHandler);\r
-\r
-    // Log messages to std::cout\r
-    spv::spirvbin_t::registerLogHandler(logHandler);\r
-#endif\r
-\r
-    if (argc < 2)\r
-        usage(argv[0]);\r
-\r
-    parseCmdLine(argc, argv, inputFile, outputDir, opts, verbosity);\r
-\r
-    if (outputDir.empty())\r
-        usage(argv[0], "Output directory required");\r
-\r
-    std::string errmsg;\r
-\r
-    // Main operations: read, remap, and write.\r
-    execute(inputFile, outputDir, opts, verbosity);\r
-\r
-    // If we get here, everything went OK!  Nothing more to be done.\r
-}\r
+//
+//Copyright (C) 2015 LunarG, Inc.
+//
+//All rights reserved.
+//
+//Redistribution and use in source and binary forms, with or without
+//modification, are permitted provided that the following conditions
+//are met:
+//
+//    Redistributions of source code must retain the above copyright
+//    notice, this list of conditions and the following disclaimer.
+//
+//    Redistributions in binary form must reproduce the above
+//    copyright notice, this list of conditions and the following
+//    disclaimer in the documentation and/or other materials provided
+//    with the distribution.
+//
+//    Neither the name of 3Dlabs Inc. Ltd. nor the names of its
+//    contributors may be used to endorse or promote products derived
+//    from this software without specific prior written permission.
+//
+//THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+//"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+//LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+//FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+//COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+//INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+//BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+//LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+//CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+//LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+//ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+//POSSIBILITY OF SUCH DAMAGE.
+//
+
+#include <iostream>
+#include <fstream>
+#include <cstring>
+#include <stdexcept>
+
+#include "../SPIRV/SPVRemapper.h"
+
+namespace {
+
+    typedef unsigned int SpvWord;
+
+    // Poor man's basename: given a complete path, return file portion.
+    // E.g:
+    //      Linux:  /foo/bar/test  -> test
+    //      Win:   c:\foo\bar\test -> test
+    // It's not very efficient, but that doesn't matter for our minimal-duty use.
+    // Using boost::filesystem would be better in many ways, but want to avoid that dependency.
+
+    // OS dependent path separator (avoiding boost::filesystem dependency)
+#if defined(_WIN32)
+    char path_sep_char() { return '\\'; }
+#else
+    char path_sep_char() { return '/';  }
+#endif
+
+    std::string basename(const std::string filename)
+    {
+        const size_t sepLoc = filename.find_last_of(path_sep_char());
+
+        return (sepLoc == filename.npos) ? filename : filename.substr(sepLoc+1);
+    }
+
+    void errHandler(const std::string& str) {
+        std::cout << str << std::endl;
+        exit(5);
+    }
+
+    void logHandler(const std::string& str) {
+        std::cout << str << std::endl;
+    }
+
+    // Read word stream from disk
+    void read(std::vector<SpvWord>& spv, const std::string& inFilename, int verbosity)
+    {
+        std::ifstream fp;
+
+        if (verbosity > 0)
+            logHandler(std::string("  reading: ") + inFilename);
+
+        spv.clear();
+        fp.open(inFilename, std::fstream::in | std::fstream::binary);
+
+        if (fp.fail())
+            errHandler("error opening file for read: ");
+
+        // Reserve space (for efficiency, not for correctness)
+        fp.seekg(0, fp.end);
+        spv.reserve(size_t(fp.tellg()) / sizeof(SpvWord));
+        fp.seekg(0, fp.beg);
+
+        while (!fp.eof()) {
+            SpvWord inWord;
+            fp.read((char *)&inWord, sizeof(inWord));
+
+            if (!fp.eof()) {
+                spv.push_back(inWord);
+                if (fp.fail())
+                    errHandler(std::string("error reading file: ") + inFilename);
+            }
+        }
+    }
+
+    void write(std::vector<SpvWord>& spv, const std::string& outFile, int verbosity)
+    {
+        if (outFile.empty())
+            errHandler("missing output filename.");
+
+        std::ofstream fp;
+
+        if (verbosity > 0)
+            logHandler(std::string("  writing: ") + outFile);
+
+        fp.open(outFile, std::fstream::out | std::fstream::binary);
+
+        if (fp.fail())
+            errHandler(std::string("error opening file for write: ") + outFile);
+
+        for (auto word : spv) {
+            fp.write((char *)&word, sizeof(word));
+            if (fp.fail())
+                errHandler(std::string("error writing file: ") + outFile);
+        }
+
+        // file is closed by destructor
+    }
+
+    // Print helpful usage message to stdout, and exit
+    void usage(const char* const name, const char* const msg = 0)
+    {
+        if (msg)
+            std::cout << msg << std::endl << std::endl;
+
+        std::cout << "Usage: " << std::endl;
+
+        std::cout << "  " << basename(name)
+            << " [-v[v[...]] | --verbose [int]]"
+            << " [--map (all|types|names|funcs)]"
+            << " [--dce (all|types|funcs)]"
+            << " [--opt (all|loadstore)]"
+            << " [--strip-all | --strip all | -s]" 
+            << " [--do-everything]" 
+            << " --input | -i file1 [file2...] --output|-o DESTDIR"
+            << std::endl;
+
+        std::cout << "  " << basename(name) << " [--version | -V]" << std::endl;
+        std::cout << "  " << basename(name) << " [--help | -?]" << std::endl;
+
+        exit(5);
+    }
+
+    // grind through each SPIR in turn
+    void execute(const std::vector<std::string>& inputFile, const std::string& outputDir,
+        int opts, int verbosity)
+    {
+        for (const auto& filename : inputFile) {
+            std::vector<SpvWord> spv;
+            read(spv, filename, verbosity);
+            spv::spirvbin_t(verbosity).remap(spv, opts);
+
+            const std::string outfile = outputDir + path_sep_char() + basename(filename);
+
+            write(spv, outfile, verbosity);
+        }
+
+        if (verbosity > 0)
+            std::cout << "Done: " << inputFile.size() << " file(s) processed" << std::endl;
+    }
+
+    // Parse command line options
+    void parseCmdLine(int argc, char** argv, std::vector<std::string>& inputFile,
+        std::string& outputDir,
+        int& options,
+        int& verbosity)
+    {
+        if (argc < 2)
+            usage(argv[0]);
+
+        verbosity  = 0;
+        options    = spv::spirvbin_t::NONE;
+
+        // Parse command line.
+        // boost::program_options would be quite a bit nicer, but we don't want to
+        // introduce a dependency on boost.
+        for (int a=1; a<argc; ) {
+            const std::string arg = argv[a];
+
+            if (arg == "--output" || arg == "-o") {
+                // Output directory
+                if (++a >= argc)
+                    usage(argv[0], "--output requires an argument");
+                if (!outputDir.empty())
+                    usage(argv[0], "--output can be provided only once");
+
+                outputDir = argv[a++];
+
+                // Remove trailing directory separator characters
+                while (!outputDir.empty() && outputDir.back() == path_sep_char())
+                    outputDir.pop_back();
+
+            }
+            else if (arg == "-vv")     { verbosity = 2; ++a; } // verbosity shortcuts
+            else if (arg == "-vvv")    { verbosity = 3; ++a; } // ...
+            else if (arg == "-vvvv")   { verbosity = 4; ++a; } // ...
+            else if (arg == "-vvvvv")  { verbosity = 5; ++a; } // ...
+
+            else if (arg == "--verbose" || arg == "-v") {
+                ++a;
+                verbosity = 1;
+
+                if (a < argc) {
+                    try {
+                        verbosity = std::stoi(argv[a]);
+                        ++a;
+                    } catch (const std::invalid_argument&) { } // ok to have no numeric value
+                }
+            }
+            else if (arg == "--version" || arg == "-V") {
+                std::cout << basename(argv[0]) << " version 0.97 " << __DATE__ << " " << __TIME__ << std::endl;
+                exit(0);
+            } else if (arg == "--input" || arg == "-i") {
+                // Collect input files
+                for (++a; a < argc && argv[a][0] != '-'; ++a)
+                    inputFile.push_back(argv[a]);
+            } else if (arg == "--do-everything") {
+                ++a;
+                options = options | spv::spirvbin_t::DO_EVERYTHING;
+            } else if (arg == "--strip-all" || arg == "-s") {
+                ++a;
+                options = options | spv::spirvbin_t::STRIP;
+            } else if (arg == "--strip") {
+                ++a;
+                if (strncmp(argv[a], "all", 3) == 0) {
+                    options = options | spv::spirvbin_t::STRIP;
+                    ++a;
+                }
+            } else if (arg == "--dce") {
+                // Parse comma (or colon, etc) separated list of things to dce
+                ++a;
+                for (const char* c = argv[a]; *c; ++c) {
+                    if (strncmp(c, "all", 3) == 0) {
+                        options = (options | spv::spirvbin_t::DCE_ALL);
+                        c += 3;
+                    } else if (strncmp(c, "*", 1) == 0) {
+                        options = (options | spv::spirvbin_t::DCE_ALL);
+                        c += 1;
+                    } else if (strncmp(c, "funcs", 5) == 0) {
+                        options = (options | spv::spirvbin_t::DCE_FUNCS);
+                        c += 5;
+                    } else if (strncmp(c, "types", 5) == 0) {
+                        options = (options | spv::spirvbin_t::DCE_TYPES);
+                        c += 5;
+                    }
+                }
+                ++a;
+            } else if (arg == "--map") {
+                // Parse comma (or colon, etc) separated list of things to map
+                ++a;
+                for (const char* c = argv[a]; *c; ++c) {
+                    if (strncmp(c, "all", 3) == 0) {
+                        options = (options | spv::spirvbin_t::MAP_ALL);
+                        c += 3;
+                    } else if (strncmp(c, "*", 1) == 0) {
+                        options = (options | spv::spirvbin_t::MAP_ALL);
+                        c += 1;
+                    } else if (strncmp(c, "types", 5) == 0) {
+                        options = (options | spv::spirvbin_t::MAP_TYPES);
+                        c += 5;
+                    } else if (strncmp(c, "names", 5) == 0) {
+                        options = (options | spv::spirvbin_t::MAP_NAMES);
+                        c += 5;
+                    } else if (strncmp(c, "funcs", 5) == 0) {
+                        options = (options | spv::spirvbin_t::MAP_FUNCS);
+                        c += 5;
+                    }
+                }
+                ++a;
+            } else if (arg == "--opt") {
+                ++a;
+                for (const char* c = argv[a]; *c; ++c) {
+                    if (strncmp(c, "all", 3) == 0) {
+                        options = (options | spv::spirvbin_t::OPT_ALL);
+                        c += 3;
+                    } else if (strncmp(c, "*", 1) == 0) {
+                        options = (options | spv::spirvbin_t::OPT_ALL);
+                        c += 1;
+                    } else if (strncmp(c, "loadstore", 9) == 0) {
+                        options = (options | spv::spirvbin_t::OPT_LOADSTORE);
+                        c += 9;
+                    }
+                }
+                ++a;
+            } else if (arg == "--help" || arg == "-?") {
+                usage(argv[0]);
+            } else {
+                usage(argv[0], "Unknown command line option");
+            }
+        }
+    }
+
+} // namespace
+
+
+int main(int argc, char** argv)
+{
+    std::vector<std::string> inputFile;
+    std::string              outputDir;
+    int                      opts;
+    int                      verbosity;
+
+#ifdef use_cpp11
+    // handle errors by exiting
+    spv::spirvbin_t::registerErrorHandler(errHandler);
+
+    // Log messages to std::cout
+    spv::spirvbin_t::registerLogHandler(logHandler);
+#endif
+
+    if (argc < 2)
+        usage(argv[0]);
+
+    parseCmdLine(argc, argv, inputFile, outputDir, opts, verbosity);
+
+    if (outputDir.empty())
+        usage(argv[0], "Output directory required");
+
+    std::string errmsg;
+
+    // Main operations: read, remap, and write.
+    execute(inputFile, outputDir, opts, verbosity);
+
+    // If we get here, everything went OK!  Nothing more to be done.
+}