Final round for line endings.
diff --git a/Install/Linux/README.txt b/Install/Linux/README.txt
index 9bd0664..aefc9fd 100644
--- a/Install/Linux/README.txt
+++ b/Install/Linux/README.txt
@@ -1,6 +1,6 @@
-This directory contains a Linux binary for the glslang validator.

-

-Installation: The executable in this directory is self sufficient, and can be 

-placed where desired; in a test directory, or in a system path, etc.

-

-Usage:  Execute glslangValidator with no arguments to get a usage statement.

+This directory contains a Linux binary for the glslang validator.
+
+Installation: The executable in this directory is self sufficient, and can be 
+placed where desired; in a test directory, or in a system path, etc.
+
+Usage:  Execute glslangValidator with no arguments to get a usage statement.
diff --git a/Install/Windows/README.txt b/Install/Windows/README.txt
index ee673f3..bde97b9 100644
--- a/Install/Windows/README.txt
+++ b/Install/Windows/README.txt
@@ -1,6 +1,6 @@
-This directory contains a Windows binary for the glslang validator.

-

-Installation: The executable in this directory is self sufficient, and can be 

-placed where desired; in a test directory, or in a system path, etc.

-

-Usage:  Execute glslangValidator with no arguments to get a usage statement.

+This directory contains a Windows binary for the glslang validator.
+
+Installation: The executable in this directory is self sufficient, and can be 
+placed where desired; in a test directory, or in a system path, etc.
+
+Usage:  Execute glslangValidator with no arguments to get a usage statement.
diff --git a/OGLCompilersDLL/CMakeLists.txt b/OGLCompilersDLL/CMakeLists.txt
index 6ade8ca..afabe75 100644
--- a/OGLCompilersDLL/CMakeLists.txt
+++ b/OGLCompilersDLL/CMakeLists.txt
@@ -1,21 +1,21 @@
-cmake_minimum_required(VERSION 2.8)

-

-include_directories(. ../glslang)

-if(WIN32)

-    include_directories(${include_directories} ../glslang/OSDependent/Windows)

-elseif(UNIX)

-    include_directories(${include_directories} ../glslang/OSDependent/Linux)

-else(WIN32)

-    message("unknown platform")

-endif(WIN32)

-

-set(SOURCES InitializeDll.cpp InitializeDll.h)

-

-add_library(OGLCompiler STATIC ${SOURCES})

-

-if(WIN32)

-    source_group("Source" FILES ${SOURCES})

-endif(WIN32)

-

-install(TARGETS OGLCompiler 

-        ARCHIVE DESTINATION lib)

+cmake_minimum_required(VERSION 2.8)
+
+include_directories(. ../glslang)
+if(WIN32)
+    include_directories(${include_directories} ../glslang/OSDependent/Windows)
+elseif(UNIX)
+    include_directories(${include_directories} ../glslang/OSDependent/Linux)
+else(WIN32)
+    message("unknown platform")
+endif(WIN32)
+
+set(SOURCES InitializeDll.cpp InitializeDll.h)
+
+add_library(OGLCompiler STATIC ${SOURCES})
+
+if(WIN32)
+    source_group("Source" FILES ${SOURCES})
+endif(WIN32)
+
+install(TARGETS OGLCompiler 
+        ARCHIVE DESTINATION lib)
diff --git a/SPIRV/CMakeLists.txt b/SPIRV/CMakeLists.txt
index 3bc149f..6bb140b 100644
--- a/SPIRV/CMakeLists.txt
+++ b/SPIRV/CMakeLists.txt
@@ -1,28 +1,28 @@
-cmake_minimum_required(VERSION 2.8)

-

-include_directories(.. ${CMAKE_CURRENT_BINARY_DIR})

-

-set(SOURCES

-    GlslangToSpv.cpp

-    SpvBuilder.cpp

-    SPVRemapper.cpp

-    doc.cpp

-    disassemble.cpp)

-

-set(HEADERS

-    spirv.h

-    GlslangToSpv.h

-    SpvBuilder.h

-    SPVRemapper.h

-    spvIR.h

-    doc.h

-    disassemble.h)

-

-add_library(SPIRV STATIC ${SOURCES} ${HEADERS})

-

-if(WIN32)

-    source_group("Source" FILES ${SOURCES} ${HEADERS})

-endif(WIN32)

-

-install(TARGETS SPIRV

-        ARCHIVE DESTINATION lib)

+cmake_minimum_required(VERSION 2.8)
+
+include_directories(.. ${CMAKE_CURRENT_BINARY_DIR})
+
+set(SOURCES
+    GlslangToSpv.cpp
+    SpvBuilder.cpp
+    SPVRemapper.cpp
+    doc.cpp
+    disassemble.cpp)
+
+set(HEADERS
+    spirv.h
+    GlslangToSpv.h
+    SpvBuilder.h
+    SPVRemapper.h
+    spvIR.h
+    doc.h
+    disassemble.h)
+
+add_library(SPIRV STATIC ${SOURCES} ${HEADERS})
+
+if(WIN32)
+    source_group("Source" FILES ${SOURCES} ${HEADERS})
+endif(WIN32)
+
+install(TARGETS SPIRV
+        ARCHIVE DESTINATION lib)
diff --git a/SPIRV/GLSL450Lib.h b/SPIRV/GLSL450Lib.h
index 7565d8a..32f4563 100644
--- a/SPIRV/GLSL450Lib.h
+++ b/SPIRV/GLSL450Lib.h
@@ -1,210 +1,210 @@
-/*

-** Copyright (c) 2014-2015 The Khronos Group Inc.

-**

-** Permission is hereby granted, free of charge, to any person obtaining a

-** copy of this software and/or associated documentation files (the

-** "Materials"), to deal in the Materials without restriction, including

-** without limitation the rights to use, copy, modify, merge, publish,

-** distribute, sublicense, and/or sell copies of the Materials, and to

-** permit persons to whom the Materials are furnished to do so, subject to

-** the following conditions:

-**

-** The above copyright notice and this permission notice shall be included

-** in all copies or substantial portions of the Materials.

-**

-** THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,

-** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF

-** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.

-** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY

-** CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,

-** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE

-** MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.

-*/

-

-//

-// Author: John Kessenich, LunarG

-//

-

-namespace GLSL_STD_450 {

-

-enum Entrypoints {

-    Round = 0,

-    RoundEven = 1,

-    Trunc = 2,

-    Abs = 3,

-    Sign = 4,

-    Floor = 5,

-    Ceil = 6,

-    Fract = 7,

-

-    Radians = 8,

-    Degrees = 9,

-    Sin = 10,

-    Cos = 11,

-    Tan = 12,

-    Asin = 13,

-    Acos = 14,

-    Atan = 15,

-    Sinh = 16,

-    Cosh = 17,

-    Tanh = 18,

-    Asinh = 19,

-    Acosh = 20,

-    Atanh = 21,

-    Atan2 = 22,

-

-    Pow = 23,

-    Exp = 24,

-    Log = 25,

-    Exp2 = 26,

-    Log2 = 27,

-    Sqrt = 28,

-    InverseSqrt = 29,

-

-    Determinant = 30,

-    MatrixInverse = 31,

-

-    Modf = 32,            // second argument needs the OpVariable = , not an OpLoad

-    Min = 33,

-    Max = 34,

-    Clamp = 35,

-    Mix = 36,

-    Step = 37,

-    SmoothStep = 38,

-

-    FloatBitsToInt = 39,

-    FloatBitsToUint = 40,

-    IntBitsToFloat = 41,

-    UintBitsToFloat = 42,

-

-    Fma = 43,

-    Frexp = 44,

-    Ldexp = 45,

-

-    PackSnorm4x8 = 46,

-    PackUnorm4x8 = 47,

-    PackSnorm2x16 = 48,

-    PackUnorm2x16 = 49,

-    PackHalf2x16 = 50,

-    PackDouble2x32 = 51,

-    UnpackSnorm2x16 = 52,

-    UnpackUnorm2x16 = 53,

-    UnpackHalf2x16 = 54,

-    UnpackSnorm4x8 = 55,

-    UnpackUnorm4x8 = 56,

-    UnpackDouble2x32 = 57,

-

-    Length = 58,

-    Distance = 59,

-    Cross = 60,

-    Normalize = 61,

-    Ftransform = 62,

-    FaceForward = 63,

-    Reflect = 64,

-    Refract = 65,

-

-    UaddCarry = 66,

-    UsubBorrow = 67,

-    UmulExtended = 68,

-    ImulExtended = 69,

-    BitfieldExtract = 70,

-    BitfieldInsert = 71,

-    BitfieldReverse = 72,

-    BitCount = 73,

-    FindLSB = 74,

-    FindMSB = 75,

-

-    InterpolateAtCentroid = 76,

-    InterpolateAtSample = 77,

-    InterpolateAtOffset = 78,

-

-    Count

-};

-

-inline void GetDebugNames(const char** names)

-{

-    for (int i = 0; i < Count; ++i)

-        names[i] = "Unknown";

-

-    names[Round]                   = "round";

-    names[RoundEven]               = "roundEven";

-    names[Trunc]                   = "trunc";

-    names[Abs]                     = "abs";

-    names[Sign]                    = "sign";

-    names[Floor]                   = "floor";

-    names[Ceil]                    = "ceil";

-    names[Fract]                   = "fract";

-    names[Radians]                 = "radians";

-    names[Degrees]                 = "degrees";

-    names[Sin]                     = "sin";

-    names[Cos]                     = "cos";

-    names[Tan]                     = "tan";

-    names[Asin]                    = "asin";

-    names[Acos]                    = "acos";

-    names[Atan]                    = "atan";

-    names[Sinh]                    = "sinh";

-    names[Cosh]                    = "cosh";

-    names[Tanh]                    = "tanh";

-    names[Asinh]                   = "asinh";

-    names[Acosh]                   = "acosh";

-    names[Atanh]                   = "atanh";

-    names[Atan2]                   = "atan2";

-    names[Pow]                     = "pow";

-    names[Exp]                     = "exp";

-    names[Log]                     = "log";

-    names[Exp2]                    = "exp2";

-    names[Log2]                    = "log2";

-    names[Sqrt]                    = "sqrt";

-    names[InverseSqrt]             = "inverseSqrt";

-    names[Determinant]             = "determinant";

-    names[MatrixInverse]           = "matrixInverse";

-    names[Modf]                    = "modf";

-    names[Min]                     = "min";

-    names[Max]                     = "max";

-    names[Clamp]                   = "clamp";

-    names[Mix]                     = "mix";

-    names[Step]                    = "step";

-    names[SmoothStep]              = "smoothStep";

-    names[FloatBitsToInt]          = "floatBitsToInt";

-    names[FloatBitsToUint]         = "floatBitsToUint";

-    names[IntBitsToFloat]          = "intBitsToFloat";

-    names[UintBitsToFloat]         = "uintBitsToFloat";

-    names[Fma]                     = "fma";

-    names[Frexp]                   = "frexp";

-    names[Ldexp]                   = "ldexp";

-    names[PackSnorm4x8]            = "packSnorm4x8";

-    names[PackUnorm4x8]            = "packUnorm4x8";

-    names[PackSnorm2x16]           = "packSnorm2x16";

-    names[PackUnorm2x16]           = "packUnorm2x16";

-    names[PackHalf2x16]            = "packHalf2x16";

-    names[PackDouble2x32]          = "packDouble2x32";

-    names[UnpackSnorm2x16]         = "unpackSnorm2x16";

-    names[UnpackUnorm2x16]         = "unpackUnorm2x16";

-    names[UnpackHalf2x16]          = "unpackHalf2x16";

-    names[UnpackSnorm4x8]          = "unpackSnorm4x8";

-    names[UnpackUnorm4x8]          = "unpackUnorm4x8";

-    names[UnpackDouble2x32]        = "unpackDouble2x32";

-    names[Length]                  = "length";

-    names[Distance]                = "distance";

-    names[Cross]                   = "cross";

-    names[Normalize]               = "normalize";

-    names[Ftransform]              = "ftransform";

-    names[FaceForward]             = "faceForward";

-    names[Reflect]                 = "reflect";

-    names[Refract]                 = "refract";

-    names[UaddCarry]               = "uaddCarry";

-    names[UsubBorrow]              = "usubBorrow";

-    names[UmulExtended]            = "umulExtended";

-    names[ImulExtended]            = "imulExtended";

-    names[BitfieldExtract]         = "bitfieldExtract";

-    names[BitfieldInsert]          = "bitfieldInsert";

-    names[BitfieldReverse]         = "bitfieldReverse";

-    names[BitCount]                = "bitCount";

-    names[FindLSB]                 = "findLSB";

-    names[FindMSB]                 = "findMSB";

-    names[InterpolateAtCentroid]   = "interpolateAtCentroid";

-    names[InterpolateAtSample]     = "interpolateAtSample";

-    names[InterpolateAtOffset]     = "interpolateAtOffset";

-}

-

-}; // end namespace GLSL_STD_450

+/*
+** Copyright (c) 2014-2015 The Khronos Group Inc.
+**
+** Permission is hereby granted, free of charge, to any person obtaining a
+** copy of this software and/or associated documentation files (the
+** "Materials"), to deal in the Materials without restriction, including
+** without limitation the rights to use, copy, modify, merge, publish,
+** distribute, sublicense, and/or sell copies of the Materials, and to
+** permit persons to whom the Materials are furnished to do so, subject to
+** the following conditions:
+**
+** The above copyright notice and this permission notice shall be included
+** in all copies or substantial portions of the Materials.
+**
+** THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+** CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+** MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
+*/
+
+//
+// Author: John Kessenich, LunarG
+//
+
+namespace GLSL_STD_450 {
+
+enum Entrypoints {
+    Round = 0,
+    RoundEven = 1,
+    Trunc = 2,
+    Abs = 3,
+    Sign = 4,
+    Floor = 5,
+    Ceil = 6,
+    Fract = 7,
+
+    Radians = 8,
+    Degrees = 9,
+    Sin = 10,
+    Cos = 11,
+    Tan = 12,
+    Asin = 13,
+    Acos = 14,
+    Atan = 15,
+    Sinh = 16,
+    Cosh = 17,
+    Tanh = 18,
+    Asinh = 19,
+    Acosh = 20,
+    Atanh = 21,
+    Atan2 = 22,
+
+    Pow = 23,
+    Exp = 24,
+    Log = 25,
+    Exp2 = 26,
+    Log2 = 27,
+    Sqrt = 28,
+    InverseSqrt = 29,
+
+    Determinant = 30,
+    MatrixInverse = 31,
+
+    Modf = 32,            // second argument needs the OpVariable = , not an OpLoad
+    Min = 33,
+    Max = 34,
+    Clamp = 35,
+    Mix = 36,
+    Step = 37,
+    SmoothStep = 38,
+
+    FloatBitsToInt = 39,
+    FloatBitsToUint = 40,
+    IntBitsToFloat = 41,
+    UintBitsToFloat = 42,
+
+    Fma = 43,
+    Frexp = 44,
+    Ldexp = 45,
+
+    PackSnorm4x8 = 46,
+    PackUnorm4x8 = 47,
+    PackSnorm2x16 = 48,
+    PackUnorm2x16 = 49,
+    PackHalf2x16 = 50,
+    PackDouble2x32 = 51,
+    UnpackSnorm2x16 = 52,
+    UnpackUnorm2x16 = 53,
+    UnpackHalf2x16 = 54,
+    UnpackSnorm4x8 = 55,
+    UnpackUnorm4x8 = 56,
+    UnpackDouble2x32 = 57,
+
+    Length = 58,
+    Distance = 59,
+    Cross = 60,
+    Normalize = 61,
+    Ftransform = 62,
+    FaceForward = 63,
+    Reflect = 64,
+    Refract = 65,
+
+    UaddCarry = 66,
+    UsubBorrow = 67,
+    UmulExtended = 68,
+    ImulExtended = 69,
+    BitfieldExtract = 70,
+    BitfieldInsert = 71,
+    BitfieldReverse = 72,
+    BitCount = 73,
+    FindLSB = 74,
+    FindMSB = 75,
+
+    InterpolateAtCentroid = 76,
+    InterpolateAtSample = 77,
+    InterpolateAtOffset = 78,
+
+    Count
+};
+
+inline void GetDebugNames(const char** names)
+{
+    for (int i = 0; i < Count; ++i)
+        names[i] = "Unknown";
+
+    names[Round]                   = "round";
+    names[RoundEven]               = "roundEven";
+    names[Trunc]                   = "trunc";
+    names[Abs]                     = "abs";
+    names[Sign]                    = "sign";
+    names[Floor]                   = "floor";
+    names[Ceil]                    = "ceil";
+    names[Fract]                   = "fract";
+    names[Radians]                 = "radians";
+    names[Degrees]                 = "degrees";
+    names[Sin]                     = "sin";
+    names[Cos]                     = "cos";
+    names[Tan]                     = "tan";
+    names[Asin]                    = "asin";
+    names[Acos]                    = "acos";
+    names[Atan]                    = "atan";
+    names[Sinh]                    = "sinh";
+    names[Cosh]                    = "cosh";
+    names[Tanh]                    = "tanh";
+    names[Asinh]                   = "asinh";
+    names[Acosh]                   = "acosh";
+    names[Atanh]                   = "atanh";
+    names[Atan2]                   = "atan2";
+    names[Pow]                     = "pow";
+    names[Exp]                     = "exp";
+    names[Log]                     = "log";
+    names[Exp2]                    = "exp2";
+    names[Log2]                    = "log2";
+    names[Sqrt]                    = "sqrt";
+    names[InverseSqrt]             = "inverseSqrt";
+    names[Determinant]             = "determinant";
+    names[MatrixInverse]           = "matrixInverse";
+    names[Modf]                    = "modf";
+    names[Min]                     = "min";
+    names[Max]                     = "max";
+    names[Clamp]                   = "clamp";
+    names[Mix]                     = "mix";
+    names[Step]                    = "step";
+    names[SmoothStep]              = "smoothStep";
+    names[FloatBitsToInt]          = "floatBitsToInt";
+    names[FloatBitsToUint]         = "floatBitsToUint";
+    names[IntBitsToFloat]          = "intBitsToFloat";
+    names[UintBitsToFloat]         = "uintBitsToFloat";
+    names[Fma]                     = "fma";
+    names[Frexp]                   = "frexp";
+    names[Ldexp]                   = "ldexp";
+    names[PackSnorm4x8]            = "packSnorm4x8";
+    names[PackUnorm4x8]            = "packUnorm4x8";
+    names[PackSnorm2x16]           = "packSnorm2x16";
+    names[PackUnorm2x16]           = "packUnorm2x16";
+    names[PackHalf2x16]            = "packHalf2x16";
+    names[PackDouble2x32]          = "packDouble2x32";
+    names[UnpackSnorm2x16]         = "unpackSnorm2x16";
+    names[UnpackUnorm2x16]         = "unpackUnorm2x16";
+    names[UnpackHalf2x16]          = "unpackHalf2x16";
+    names[UnpackSnorm4x8]          = "unpackSnorm4x8";
+    names[UnpackUnorm4x8]          = "unpackUnorm4x8";
+    names[UnpackDouble2x32]        = "unpackDouble2x32";
+    names[Length]                  = "length";
+    names[Distance]                = "distance";
+    names[Cross]                   = "cross";
+    names[Normalize]               = "normalize";
+    names[Ftransform]              = "ftransform";
+    names[FaceForward]             = "faceForward";
+    names[Reflect]                 = "reflect";
+    names[Refract]                 = "refract";
+    names[UaddCarry]               = "uaddCarry";
+    names[UsubBorrow]              = "usubBorrow";
+    names[UmulExtended]            = "umulExtended";
+    names[ImulExtended]            = "imulExtended";
+    names[BitfieldExtract]         = "bitfieldExtract";
+    names[BitfieldInsert]          = "bitfieldInsert";
+    names[BitfieldReverse]         = "bitfieldReverse";
+    names[BitCount]                = "bitCount";
+    names[FindLSB]                 = "findLSB";
+    names[FindMSB]                 = "findMSB";
+    names[InterpolateAtCentroid]   = "interpolateAtCentroid";
+    names[InterpolateAtSample]     = "interpolateAtSample";
+    names[InterpolateAtOffset]     = "interpolateAtOffset";
+}
+
+}; // end namespace GLSL_STD_450
diff --git a/SPIRV/GlslangToSpv.cpp b/SPIRV/GlslangToSpv.cpp
index 969c091..8cdc032 100644
--- a/SPIRV/GlslangToSpv.cpp
+++ b/SPIRV/GlslangToSpv.cpp
@@ -1,2578 +1,2578 @@
-//

-//Copyright (C) 2014 LunarG, Inc.

-//

-//All rights reserved.

-//

-//Redistribution and use in source and binary forms, with or without

-//modification, are permitted provided that the following conditions

-//are met:

-//

-//    Redistributions of source code must retain the above copyright

-//    notice, this list of conditions and the following disclaimer.

-//

-//    Redistributions in binary form must reproduce the above

-//    copyright notice, this list of conditions and the following

-//    disclaimer in the documentation and/or other materials provided

-//    with the distribution.

-//

-//    Neither the name of 3Dlabs Inc. Ltd. nor the names of its

-//    contributors may be used to endorse or promote products derived

-//    from this software without specific prior written permission.

-//

-//THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS

-//"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT

-//LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS

-//FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE

-//COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,

-//INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,

-//BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;

-//LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER

-//CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT

-//LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN

-//ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE

-//POSSIBILITY OF SUCH DAMAGE.

-

-//

-// Author: John Kessenich, LunarG

-//

-// Visit the nodes in the glslang intermediate tree representation to

-// translate them to SPIR-V.

-//

-

-#include "spirv.h"

-#include "GlslangToSpv.h"

-#include "SpvBuilder.h"

-#include "GLSL450Lib.h"

-

-// Glslang includes

-#include "glslang/MachineIndependent/localintermediate.h"

-#include "glslang/MachineIndependent/SymbolTable.h"

-

-#include <string>

-#include <map>

-#include <list>

-#include <vector>

-#include <stack>

-#include <fstream>

-

-namespace {

-

-const int GlslangMagic = 0x51a;

-

-//

-// The main holder of information for translating glslang to SPIR-V.

-//

-// Derives from the AST walking base class.

-//

-class TGlslangToSpvTraverser : public glslang::TIntermTraverser {

-public:

-    TGlslangToSpvTraverser(const glslang::TIntermediate*);

-    virtual ~TGlslangToSpvTraverser();

-

-    bool visitAggregate(glslang::TVisit, glslang::TIntermAggregate*);

-    bool visitBinary(glslang::TVisit, glslang::TIntermBinary*);

-    void visitConstantUnion(glslang::TIntermConstantUnion*);

-    bool visitSelection(glslang::TVisit, glslang::TIntermSelection*);

-    bool visitSwitch(glslang::TVisit, glslang::TIntermSwitch*);

-    void visitSymbol(glslang::TIntermSymbol* symbol);

-    bool visitUnary(glslang::TVisit, glslang::TIntermUnary*);

-    bool visitLoop(glslang::TVisit, glslang::TIntermLoop*);

-    bool visitBranch(glslang::TVisit visit, glslang::TIntermBranch*);

-

-    void dumpSpv(std::vector<unsigned int>& out) { builder.dump(out); }

-

-protected:

-    spv::Id createSpvVariable(const glslang::TIntermSymbol*);

-    spv::Id getSampledType(const glslang::TSampler&);

-    spv::Id convertGlslangToSpvType(const glslang::TType& type);

-

-    bool isShaderEntrypoint(const glslang::TIntermAggregate* node);

-    void makeFunctions(const glslang::TIntermSequence&);

-    void makeGlobalInitializers(const glslang::TIntermSequence&);

-    void visitFunctions(const glslang::TIntermSequence&);

-    void handleFunctionEntry(const glslang::TIntermAggregate* node);

-    void translateArguments(const glslang::TIntermSequence& glslangArguments, std::vector<spv::Id>& arguments);

-    spv::Id handleBuiltInFunctionCall(const glslang::TIntermAggregate*);

-    spv::Id handleUserFunctionCall(const glslang::TIntermAggregate*);

-

-    spv::Id createBinaryOperation(glslang::TOperator op, spv::Decoration precision, spv::Id typeId, spv::Id left, spv::Id right, glslang::TBasicType typeProxy, bool reduceComparison = true);

-    spv::Id createUnaryOperation(glslang::TOperator op, spv::Decoration precision, spv::Id typeId, spv::Id operand, bool isFloat);

-    spv::Id createConversion(glslang::TOperator op, spv::Decoration precision, spv::Id destTypeId, spv::Id operand);

-    spv::Id makeSmearedConstant(spv::Id constant, int vectorSize);

-    spv::Id createMiscOperation(glslang::TOperator op, spv::Decoration precision, spv::Id typeId, std::vector<spv::Id>& operands);

-    spv::Id createNoArgOperation(glslang::TOperator op);

-    spv::Id getSymbolId(const glslang::TIntermSymbol* node);

-    void addDecoration(spv::Id id, spv::Decoration dec);

-    void addMemberDecoration(spv::Id id, int member, spv::Decoration dec);

-    spv::Id createSpvConstant(const glslang::TType& type, const glslang::TConstUnionArray&, int& nextConst);

-

-    spv::Function* shaderEntry;

-    int sequenceDepth;

-

-    // There is a 1:1 mapping between a spv builder and a module; this is thread safe

-    spv::Builder builder;

-    bool inMain;

-    bool mainTerminated;

-    bool linkageOnly;

-    const glslang::TIntermediate* glslangIntermediate;

-    spv::Id stdBuiltins;

-

-    std::map<int, spv::Id> symbolValues;

-    std::set<int> constReadOnlyParameters;  // set of formal function parameters that have glslang qualifier constReadOnly, so we know they are not local function "const" that are write-once

-    std::map<std::string, spv::Function*> functionMap;

-    std::map<const glslang::TTypeList*, spv::Id> structMap;

-    std::map<const glslang::TTypeList*, std::vector<int> > memberRemapper;  // for mapping glslang block indices to spv indices (e.g., due to hidden members)

-    std::stack<bool> breakForLoop;  // false means break for switch

-    std::stack<glslang::TIntermTyped*> loopTerminal;  // code from the last part of a for loop: for(...; ...; terminal), needed for e.g., continue };

-};

-

-//

-// Helper functions for translating glslang representations to SPIR-V enumerants.

-//

-

-// Translate glslang profile to SPIR-V source language.

-spv::SourceLanguage TranslateSourceLanguage(EProfile profile)

-{

-    switch (profile) {

-    case ENoProfile:

-    case ECoreProfile:

-    case ECompatibilityProfile:

-        return spv::SourceLanguageGLSL;

-    case EEsProfile:

-        return spv::SourceLanguageESSL;

-    default:

-        return spv::SourceLanguageUnknown;

-    }

-}

-

-// Translate glslang language (stage) to SPIR-V execution model.

-spv::ExecutionModel TranslateExecutionModel(EShLanguage stage)

-{

-    switch (stage) {

-    case EShLangVertex:           return spv::ExecutionModelVertex;

-    case EShLangTessControl:      return spv::ExecutionModelTessellationControl;

-    case EShLangTessEvaluation:   return spv::ExecutionModelTessellationEvaluation;

-    case EShLangGeometry:         return spv::ExecutionModelGeometry;

-    case EShLangFragment:         return spv::ExecutionModelFragment;

-    case EShLangCompute:          return spv::ExecutionModelGLCompute;

-    default:

-        spv::MissingFunctionality("GLSL stage");

-        return spv::ExecutionModelFragment;

-    }

-}

-

-// Translate glslang type to SPIR-V storage class.

-spv::StorageClass TranslateStorageClass(const glslang::TType& type)

-{

-    if (type.getQualifier().isPipeInput())

-        return spv::StorageClassInput;

-    else if (type.getQualifier().isPipeOutput())

-        return spv::StorageClassOutput;

-    else if (type.getQualifier().isUniformOrBuffer()) {

-        if (type.getBasicType() == glslang::EbtBlock)

-            return spv::StorageClassUniform;

-        else

-            return spv::StorageClassUniformConstant;

-        // TODO: how are we distuingishing between default and non-default non-writable uniforms?  Do default uniforms even exist?

-    } else {

-        switch (type.getQualifier().storage) {

-        case glslang::EvqShared:        return spv::StorageClassWorkgroupLocal;  break;

-        case glslang::EvqGlobal:        return spv::StorageClassPrivateGlobal;

-        case glslang::EvqConstReadOnly: return spv::StorageClassFunction;

-        case glslang::EvqTemporary:     return spv::StorageClassFunction;

-        default: 

-            spv::MissingFunctionality("unknown glslang storage class");

-            return spv::StorageClassFunction;

-        }

-    }

-}

-

-// Translate glslang sampler type to SPIR-V dimensionality.

-spv::Dim TranslateDimensionality(const glslang::TSampler& sampler)

-{

-    switch (sampler.dim) {

-    case glslang::Esd1D:     return spv::Dim1D;

-    case glslang::Esd2D:     return spv::Dim2D;

-    case glslang::Esd3D:     return spv::Dim3D;

-    case glslang::EsdCube:   return spv::DimCube;

-    case glslang::EsdRect:   return spv::DimRect;

-    case glslang::EsdBuffer: return spv::DimBuffer;

-    default:

-        spv::MissingFunctionality("unknown sampler dimension");

-        return spv::Dim2D;

-    }

-}

-

-// Translate glslang type to SPIR-V precision decorations.

-spv::Decoration TranslatePrecisionDecoration(const glslang::TType& type)

-{

-    switch (type.getQualifier().precision) {

-    case glslang::EpqLow:    return spv::DecorationPrecisionLow;

-    case glslang::EpqMedium: return spv::DecorationPrecisionMedium;

-    case glslang::EpqHigh:   return spv::DecorationPrecisionHigh;

-    default:

-        return spv::NoPrecision;

-    }

-}

-

-// Translate glslang type to SPIR-V block decorations.

-spv::Decoration TranslateBlockDecoration(const glslang::TType& type)

-{

-    if (type.getBasicType() == glslang::EbtBlock) {

-        switch (type.getQualifier().storage) {

-        case glslang::EvqUniform:      return spv::DecorationBlock;

-        case glslang::EvqBuffer:       return spv::DecorationBufferBlock;

-        case glslang::EvqVaryingIn:    return spv::DecorationBlock;

-        case glslang::EvqVaryingOut:   return spv::DecorationBlock;

-        default:

-            spv::MissingFunctionality("kind of block");

-            break;

-        }

-    }

-

-    return (spv::Decoration)spv::BadValue;

-}

-

-// Translate glslang type to SPIR-V layout decorations.

-spv::Decoration TranslateLayoutDecoration(const glslang::TType& type)

-{

-    if (type.isMatrix()) {

-        switch (type.getQualifier().layoutMatrix) {

-        case glslang::ElmRowMajor:

-            return spv::DecorationRowMajor;

-        default:

-            return spv::DecorationColMajor;

-        }

-    } else {

-        switch (type.getBasicType()) {

-        default:

-            return (spv::Decoration)spv::BadValue;

-            break;

-        case glslang::EbtBlock:

-            switch (type.getQualifier().storage) {

-            case glslang::EvqUniform:

-            case glslang::EvqBuffer:

-                switch (type.getQualifier().layoutPacking) {

-                case glslang::ElpShared:  return spv::DecorationGLSLShared;

-                case glslang::ElpStd140:  return spv::DecorationGLSLStd140;

-                case glslang::ElpStd430:  return spv::DecorationGLSLStd430;

-                case glslang::ElpPacked:  return spv::DecorationGLSLPacked;

-                default:

-                    spv::MissingFunctionality("uniform block layout");

-                    return spv::DecorationGLSLShared;

-                }

-            case glslang::EvqVaryingIn:

-            case glslang::EvqVaryingOut:

-                if (type.getQualifier().layoutPacking != glslang::ElpNone)

-                    spv::MissingFunctionality("in/out block layout");

-                return (spv::Decoration)spv::BadValue;

-            default:

-                spv::MissingFunctionality("block storage qualification");

-                return (spv::Decoration)spv::BadValue;

-            }

-        }

-    }

-}

-

-// Translate glslang type to SPIR-V interpolation decorations.

-spv::Decoration TranslateInterpolationDecoration(const glslang::TType& type)

-{

-    if (type.getQualifier().smooth)

-        return spv::DecorationSmooth;

-    if (type.getQualifier().nopersp)

-        return spv::DecorationNoperspective;

-    else if (type.getQualifier().patch)

-        return spv::DecorationPatch;

-    else if (type.getQualifier().flat)

-        return spv::DecorationFlat;

-    else if (type.getQualifier().centroid)

-        return spv::DecorationCentroid;

-    else if (type.getQualifier().sample)

-        return spv::DecorationSample;

-    else

-        return (spv::Decoration)spv::BadValue;

-}

-

-// If glslang type is invaraiant, return SPIR-V invariant decoration.

-spv::Decoration TranslateInvariantDecoration(const glslang::TType& type)

-{

-    if (type.getQualifier().invariant)

-        return spv::DecorationInvariant;

-    else

-        return (spv::Decoration)spv::BadValue;

-}

-

-// Translate glslang built-in variable to SPIR-V built in decoration.

-spv::BuiltIn TranslateBuiltInDecoration(glslang::TBuiltInVariable builtIn)

-{

-    switch (builtIn) {

-    case glslang::EbvPosition:             return spv::BuiltInPosition;

-    case glslang::EbvPointSize:            return spv::BuiltInPointSize;

-    case glslang::EbvClipVertex:           return spv::BuiltInClipVertex;

-    case glslang::EbvClipDistance:         return spv::BuiltInClipDistance;

-    case glslang::EbvCullDistance:         return spv::BuiltInCullDistance;

-    case glslang::EbvVertexId:             return spv::BuiltInVertexId;

-    case glslang::EbvInstanceId:           return spv::BuiltInInstanceId;

-    case glslang::EbvPrimitiveId:          return spv::BuiltInPrimitiveId;

-    case glslang::EbvInvocationId:         return spv::BuiltInInvocationId;

-    case glslang::EbvLayer:                return spv::BuiltInLayer;

-    case glslang::EbvViewportIndex:        return spv::BuiltInViewportIndex;

-    case glslang::EbvTessLevelInner:       return spv::BuiltInTessLevelInner;

-    case glslang::EbvTessLevelOuter:       return spv::BuiltInTessLevelOuter;

-    case glslang::EbvTessCoord:            return spv::BuiltInTessCoord;

-    case glslang::EbvPatchVertices:        return spv::BuiltInPatchVertices;

-    case glslang::EbvFragCoord:            return spv::BuiltInFragCoord;

-    case glslang::EbvPointCoord:           return spv::BuiltInPointCoord;

-    case glslang::EbvFace:                 return spv::BuiltInFrontFacing;

-    case glslang::EbvSampleId:             return spv::BuiltInSampleId;

-    case glslang::EbvSamplePosition:       return spv::BuiltInSamplePosition;

-    case glslang::EbvSampleMask:           return spv::BuiltInSampleMask;

-    case glslang::EbvFragColor:            return spv::BuiltInFragColor;

-    case glslang::EbvFragData:             return spv::BuiltInFragColor;

-    case glslang::EbvFragDepth:            return spv::BuiltInFragDepth;

-    case glslang::EbvHelperInvocation:     return spv::BuiltInHelperInvocation;

-    case glslang::EbvNumWorkGroups:        return spv::BuiltInNumWorkgroups;

-    case glslang::EbvWorkGroupSize:        return spv::BuiltInWorkgroupSize;

-    case glslang::EbvWorkGroupId:          return spv::BuiltInWorkgroupId;

-    case glslang::EbvLocalInvocationId:    return spv::BuiltInLocalInvocationId;

-    case glslang::EbvLocalInvocationIndex: return spv::BuiltInLocalInvocationIndex;

-    case glslang::EbvGlobalInvocationId:   return spv::BuiltInGlobalInvocationId;

-    default:                               return (spv::BuiltIn)spv::BadValue;

-    }

-}

-

-//

-// Implement the TGlslangToSpvTraverser class.

-//

-

-TGlslangToSpvTraverser::TGlslangToSpvTraverser(const glslang::TIntermediate* glslangIntermediate)

-    : TIntermTraverser(true, false, true), shaderEntry(0), sequenceDepth(0),

-      builder(GlslangMagic),

-      inMain(false), mainTerminated(false), linkageOnly(false),

-      glslangIntermediate(glslangIntermediate)

-{

-    spv::ExecutionModel executionModel = TranslateExecutionModel(glslangIntermediate->getStage());

-

-    builder.clearAccessChain();

-    builder.setSource(TranslateSourceLanguage(glslangIntermediate->getProfile()), glslangIntermediate->getVersion());

-    stdBuiltins = builder.import("GLSL.std.450");

-    builder.setMemoryModel(spv::AddressingModelLogical, spv::MemoryModelGLSL450);

-    shaderEntry = builder.makeMain();

-    builder.addEntryPoint(executionModel, shaderEntry);

-

-    // Add the source extensions

-    const std::set<std::string>& sourceExtensions = glslangIntermediate->getRequestedExtensions();

-    for (std::set<std::string>::const_iterator it = sourceExtensions.begin(); it != sourceExtensions.end(); ++it)

-        builder.addSourceExtension(it->c_str());

-

-    // Add the top-level modes for this shader.

-

-    if (glslangIntermediate->getXfbMode())

-        builder.addExecutionMode(shaderEntry, spv::ExecutionModeXfb);

-

-    unsigned int mode;

-    switch (glslangIntermediate->getStage()) {

-    case EShLangVertex:

-        break;

-

-    case EShLangTessControl:

-        builder.addExecutionMode(shaderEntry, spv::ExecutionModeOutputVertices, glslangIntermediate->getVertices());

-        break;

-

-    case EShLangTessEvaluation:

-        switch (glslangIntermediate->getInputPrimitive()) {

-        case glslang::ElgTriangles:           mode = spv::ExecutionModeInputTriangles;     break;

-        case glslang::ElgQuads:               mode = spv::ExecutionModeInputQuads;         break;

-        case glslang::ElgIsolines:            mode = spv::ExecutionModeInputIsolines;      break;

-        default:                              mode = spv::BadValue;    break;

-        }

-        if (mode != spv::BadValue)

-            builder.addExecutionMode(shaderEntry, (spv::ExecutionMode)mode);

-

-        // TODO

-        //builder.addExecutionMode(spv::VertexSpacingMdName, glslangIntermediate->getVertexSpacing());

-        //builder.addExecutionMode(spv::VertexOrderMdName, glslangIntermediate->getVertexOrder());

-        //builder.addExecutionMode(spv::PointModeMdName, glslangIntermediate->getPointMode());

-        break;

-

-    case EShLangGeometry:

-        switch (glslangIntermediate->getInputPrimitive()) {

-        case glslang::ElgPoints:             mode = spv::ExecutionModeInputPoints;             break;

-        case glslang::ElgLines:              mode = spv::ExecutionModeInputLines;              break;

-        case glslang::ElgLinesAdjacency:     mode = spv::ExecutionModeInputLinesAdjacency;     break;

-        case glslang::ElgTriangles:          mode = spv::ExecutionModeInputTriangles;          break;

-        case glslang::ElgTrianglesAdjacency: mode = spv::ExecutionModeInputTrianglesAdjacency; break;

-        default:                             mode = spv::BadValue;         break;

-        }

-        if (mode != spv::BadValue)

-            builder.addExecutionMode(shaderEntry, (spv::ExecutionMode)mode);

-        builder.addExecutionMode(shaderEntry, spv::ExecutionModeInvocations, glslangIntermediate->getInvocations());

-

-        switch (glslangIntermediate->getOutputPrimitive()) {

-        case glslang::ElgPoints:        mode = spv::ExecutionModeOutputPoints;                 break;

-        case glslang::ElgLineStrip:     mode = spv::ExecutionModeOutputLineStrip;              break;

-        case glslang::ElgTriangleStrip: mode = spv::ExecutionModeOutputTriangleStrip;          break;

-        default:                        mode = spv::BadValue;              break;

-        }

-        if (mode != spv::BadValue)

-            builder.addExecutionMode(shaderEntry, (spv::ExecutionMode)mode);

-        builder.addExecutionMode(shaderEntry, spv::ExecutionModeOutputVertices, glslangIntermediate->getVertices());

-        break;

-

-    case EShLangFragment:

-        if (glslangIntermediate->getPixelCenterInteger())

-            builder.addExecutionMode(shaderEntry, spv::ExecutionModePixelCenterInteger);

-        if (glslangIntermediate->getOriginUpperLeft())

-            builder.addExecutionMode(shaderEntry, spv::ExecutionModeOriginUpperLeft);

-        break;

-

-    case EShLangCompute:

-        break;

-

-    default:

-        break;

-    }

-

-}

-

-TGlslangToSpvTraverser::~TGlslangToSpvTraverser()

-{

-    if (! mainTerminated) {

-        spv::Block* lastMainBlock = shaderEntry->getLastBlock();

-        builder.setBuildPoint(lastMainBlock);

-        builder.leaveFunction(true);

-    }

-}

-

-//

-// Implement the traversal functions.

-//

-// Return true from interior nodes to have the external traversal

-// continue on to children.  Return false if children were

-// already processed.

-//

-

-//

-// Symbols can turn into 

-//  - uniform/input reads

-//  - output writes

-//  - complex lvalue base setups:  foo.bar[3]....  , where we see foo and start up an access chain

-//  - something simple that degenerates into the last bullet

-//

-void TGlslangToSpvTraverser::visitSymbol(glslang::TIntermSymbol* symbol)

-{

-    // getSymbolId() will set up all the IO decorations on the first call.

-    // Formal function parameters were mapped during makeFunctions().

-    spv::Id id = getSymbolId(symbol);

-    

-    if (! linkageOnly) {

-        // Prepare to generate code for the access

-

-        // L-value chains will be computed left to right.  We're on the symbol now,

-        // which is the left-most part of the access chain, so now is "clear" time,

-        // followed by setting the base.

-        builder.clearAccessChain();

-

-        // For now, we consider all user variables as being in memory, so they are pointers,

-        // except for "const in" arguments to a function, which are an intermediate object.

-        // See comments in handleUserFunctionCall().

-        glslang::TStorageQualifier qualifier = symbol->getQualifier().storage;

-        if (qualifier == glslang::EvqConstReadOnly && constReadOnlyParameters.find(symbol->getId()) != constReadOnlyParameters.end())

-            builder.setAccessChainRValue(id);

-        else

-            builder.setAccessChainLValue(id);

-    }

-}

-

-bool TGlslangToSpvTraverser::visitBinary(glslang::TVisit /* visit */, glslang::TIntermBinary* node)

-{

-    // First, handle special cases

-    switch (node->getOp()) {

-    case glslang::EOpAssign:

-    case glslang::EOpAddAssign:

-    case glslang::EOpSubAssign:

-    case glslang::EOpMulAssign:

-    case glslang::EOpVectorTimesMatrixAssign:

-    case glslang::EOpVectorTimesScalarAssign:

-    case glslang::EOpMatrixTimesScalarAssign:

-    case glslang::EOpMatrixTimesMatrixAssign:

-    case glslang::EOpDivAssign:

-    case glslang::EOpModAssign:

-    case glslang::EOpAndAssign:

-    case glslang::EOpInclusiveOrAssign:

-    case glslang::EOpExclusiveOrAssign:

-    case glslang::EOpLeftShiftAssign:

-    case glslang::EOpRightShiftAssign:

-        // A bin-op assign "a += b" means the same thing as "a = a + b"

-        // where a is evaluated before b. For a simple assignment, GLSL

-        // says to evaluate the left before the right.  So, always, left

-        // node then right node.

-        {

-            // get the left l-value, save it away

-            builder.clearAccessChain();

-            node->getLeft()->traverse(this);

-            spv::Builder::AccessChain lValue = builder.getAccessChain();

-

-            // evaluate the right

-            builder.clearAccessChain();

-            node->getRight()->traverse(this);

-            spv::Id rValue = builder.accessChainLoad(TranslatePrecisionDecoration(node->getRight()->getType()));

-

-            if (node->getOp() != glslang::EOpAssign) {

-                // the left is also an r-value

-                builder.setAccessChain(lValue);

-                spv::Id leftRValue = builder.accessChainLoad(TranslatePrecisionDecoration(node->getLeft()->getType()));

-

-                // do the operation

-                rValue = createBinaryOperation(node->getOp(), TranslatePrecisionDecoration(node->getType()), 

-                                               convertGlslangToSpvType(node->getType()), leftRValue, rValue,

-                                               node->getType().getBasicType());

-

-                // these all need their counterparts in createBinaryOperation()

-                if (rValue == 0)

-                    spv::MissingFunctionality("createBinaryOperation");

-            }

-

-            // store the result

-            builder.setAccessChain(lValue);

-            builder.accessChainStore(rValue);

-

-            // assignments are expressions having an rValue after they are evaluated...

-            builder.clearAccessChain();

-            builder.setAccessChainRValue(rValue);

-        }

-        return false;

-    case glslang::EOpIndexDirect:

-    case glslang::EOpIndexDirectStruct:

-        {

-            // Get the left part of the access chain.

-            node->getLeft()->traverse(this);

-

-            // Add the next element in the chain

-

-            int index = 0;

-            if (node->getRight()->getAsConstantUnion() == 0)

-                spv::MissingFunctionality("direct index without a constant node");

-            else 

-                index = node->getRight()->getAsConstantUnion()->getConstArray()[0].getIConst();

-

-            if (node->getLeft()->getBasicType() == glslang::EbtBlock && node->getOp() == glslang::EOpIndexDirectStruct) {

-                // This may be, e.g., an anonymous block-member selection, which generally need

-                // index remapping due to hidden members in anonymous blocks.

-                std::vector<int>& remapper = memberRemapper[node->getLeft()->getType().getStruct()];

-                if (remapper.size() == 0)

-                    spv::MissingFunctionality("block without member remapping");

-                else

-                    index = remapper[index];

-            }

-

-            if (! node->getLeft()->getType().isArray() &&

-                node->getLeft()->getType().isVector() &&

-                node->getOp() == glslang::EOpIndexDirect) {

-                // This is essentially a hard-coded vector swizzle of size 1,

-                // so short circuit the access-chain stuff with a swizzle.

-                std::vector<unsigned> swizzle;

-                swizzle.push_back(node->getRight()->getAsConstantUnion()->getConstArray()[0].getIConst());

-                builder.accessChainPushSwizzle(swizzle);

-            } else {

-                // normal case for indexing array or structure or block

-                builder.accessChainPush(builder.makeIntConstant(index), convertGlslangToSpvType(node->getType()));

-            }

-        }

-        return false;

-    case glslang::EOpIndexIndirect:

-        {

-            // Structure or array or vector indirection.

-            // Will use native SPIR-V access-chain for struct and array indirection;

-            // matrices are arrays of vectors, so will also work for a matrix.

-            // Will use the access chain's 'component' for variable index into a vector.

-

-            // This adapter is building access chains left to right.

-            // Set up the access chain to the left.

-            node->getLeft()->traverse(this);

-

-            // save it so that computing the right side doesn't trash it

-            spv::Builder::AccessChain partial = builder.getAccessChain();

-

-            // compute the next index in the chain

-            builder.clearAccessChain();

-            node->getRight()->traverse(this);

-            spv::Id index = builder.accessChainLoad(TranslatePrecisionDecoration(node->getRight()->getType()));

-

-            // restore the saved access chain

-            builder.setAccessChain(partial);

-

-            if (! node->getLeft()->getType().isArray() && node->getLeft()->getType().isVector())

-                builder.accessChainPushComponent(index);

-            else

-                builder.accessChainPush(index, convertGlslangToSpvType(node->getType()));

-        }

-        return false;

-    case glslang::EOpVectorSwizzle:

-        {

-            node->getLeft()->traverse(this);

-            glslang::TIntermSequence& swizzleSequence = node->getRight()->getAsAggregate()->getSequence();

-            std::vector<unsigned> swizzle;

-            for (int i = 0; i < (int)swizzleSequence.size(); ++i)

-                swizzle.push_back(swizzleSequence[i]->getAsConstantUnion()->getConstArray()[0].getIConst());

-            builder.accessChainPushSwizzle(swizzle);

-        }

-        return false;

-    default:

-        break;

-    }

-

-    // Assume generic binary op...

-

-    // Get the operands

-    builder.clearAccessChain();

-    node->getLeft()->traverse(this);

-    spv::Id left = builder.accessChainLoad(TranslatePrecisionDecoration(node->getLeft()->getType()));

-

-    builder.clearAccessChain();

-    node->getRight()->traverse(this);

-    spv::Id right = builder.accessChainLoad(TranslatePrecisionDecoration(node->getRight()->getType()));

-

-    spv::Id result;

-    spv::Decoration precision = TranslatePrecisionDecoration(node->getType());

-

-    result = createBinaryOperation(node->getOp(), precision, 

-                                   convertGlslangToSpvType(node->getType()), left, right,

-                                   node->getLeft()->getType().getBasicType());

-

-    if (! result) {

-        spv::MissingFunctionality("glslang binary operation");

-    } else {

-        builder.clearAccessChain();

-        builder.setAccessChainRValue(result);

-

-        return false;

-    }

-

-    return true;

-}

-

-bool TGlslangToSpvTraverser::visitUnary(glslang::TVisit /* visit */, glslang::TIntermUnary* node)

-{

-    builder.clearAccessChain();

-    node->getOperand()->traverse(this);

-    spv::Id operand = builder.accessChainLoad(TranslatePrecisionDecoration(node->getOperand()->getType()));

-

-    spv::Decoration precision = TranslatePrecisionDecoration(node->getType());

-

-    // it could be a conversion

-    spv::Id result = createConversion(node->getOp(), precision, convertGlslangToSpvType(node->getType()), operand);

-

-    // if not, then possibly an operation

-    if (! result)

-        result = createUnaryOperation(node->getOp(), precision, convertGlslangToSpvType(node->getType()), operand, node->getBasicType() == glslang::EbtFloat || node->getBasicType() == glslang::EbtDouble);

-

-    if (result) {

-        builder.clearAccessChain();

-        builder.setAccessChainRValue(result);

-

-        return false; // done with this node

-    }

-

-    // it must be a special case, check...

-    switch (node->getOp()) {

-    case glslang::EOpPostIncrement:

-    case glslang::EOpPostDecrement:

-    case glslang::EOpPreIncrement:

-    case glslang::EOpPreDecrement:

-        {

-            // we need the integer value "1" or the floating point "1.0" to add/subtract

-            spv::Id one = node->getBasicType() == glslang::EbtFloat ?

-                                     builder.makeFloatConstant(1.0F) :

-                                     builder.makeIntConstant(1);

-            glslang::TOperator op;

-            if (node->getOp() == glslang::EOpPreIncrement ||

-                node->getOp() == glslang::EOpPostIncrement)

-                op = glslang::EOpAdd;

-            else

-                op = glslang::EOpSub;

-

-            spv::Id result = createBinaryOperation(op, TranslatePrecisionDecoration(node->getType()), 

-                                                     convertGlslangToSpvType(node->getType()), operand, one, 

-                                                     node->getType().getBasicType());

-            if (result == 0)

-                spv::MissingFunctionality("createBinaryOperation for unary");

-

-            // The result of operation is always stored, but conditionally the

-            // consumed result.  The consumed result is always an r-value.

-            builder.accessChainStore(result);

-            builder.clearAccessChain();

-            if (node->getOp() == glslang::EOpPreIncrement ||

-                node->getOp() == glslang::EOpPreDecrement)

-                builder.setAccessChainRValue(result);

-            else

-                builder.setAccessChainRValue(operand);

-        }

-

-        return false;

-

-    case glslang::EOpEmitStreamVertex:

-        builder.createNoResultOp(spv::OpEmitStreamVertex, operand);

-        return false;

-    case glslang::EOpEndStreamPrimitive:

-        builder.createNoResultOp(spv::OpEndStreamPrimitive, operand);

-        return false;

-

-    default:

-        spv::MissingFunctionality("glslang unary");

-        break;

-    }

-

-    return true;

-}

-

-bool TGlslangToSpvTraverser::visitAggregate(glslang::TVisit visit, glslang::TIntermAggregate* node)

-{

-    spv::Id result;

-    glslang::TOperator binOp = glslang::EOpNull;

-    bool reduceComparison = true;

-    bool isMatrix = false;

-    bool noReturnValue = false;

-

-    assert(node->getOp());

-

-    spv::Decoration precision = TranslatePrecisionDecoration(node->getType());

-

-    switch (node->getOp()) {

-    case glslang::EOpSequence:

-    {

-        if (preVisit)

-            ++sequenceDepth;

-        else

-            --sequenceDepth;

-

-        if (sequenceDepth == 1) {

-            // If this is the parent node of all the functions, we want to see them

-            // early, so all call points have actual SPIR-V functions to reference.

-            // In all cases, still let the traverser visit the children for us.

-            makeFunctions(node->getAsAggregate()->getSequence());

-

-            // Also, we want all globals initializers to go into the entry of main(), before

-            // anything else gets there, so visit out of order, doing them all now.

-            makeGlobalInitializers(node->getAsAggregate()->getSequence());

-

-            // Initializers are done, don't want to visit again, but functions link objects need to be processed,

-            // so do them manually.

-            visitFunctions(node->getAsAggregate()->getSequence());

-

-            return false;

-        }

-

-        return true;

-    }

-    case glslang::EOpLinkerObjects:

-    {

-        if (visit == glslang::EvPreVisit)

-            linkageOnly = true;

-        else

-            linkageOnly = false;

-

-        return true;

-    }

-    case glslang::EOpComma:

-    {

-        // processing from left to right naturally leaves the right-most

-        // lying around in the access chain

-        glslang::TIntermSequence& glslangOperands = node->getSequence();

-        for (int i = 0; i < (int)glslangOperands.size(); ++i)

-            glslangOperands[i]->traverse(this);

-

-        return false;

-    }

-    case glslang::EOpFunction:

-        if (visit == glslang::EvPreVisit) {

-            if (isShaderEntrypoint(node)) {

-                inMain = true;

-                builder.setBuildPoint(shaderEntry->getLastBlock());

-            } else {

-                handleFunctionEntry(node);

-            }

-        } else {

-            if (inMain)

-                mainTerminated = true;

-            builder.leaveFunction(inMain);

-            inMain = false;

-        }

-

-        return true;

-    case glslang::EOpParameters:

-        // Parameters will have been consumed by EOpFunction processing, but not

-        // the body, so we still visited the function node's children, making this

-        // child redundant.

-        return false;

-    case glslang::EOpFunctionCall:

-    {

-        if (node->isUserDefined())

-            result = handleUserFunctionCall(node);

-        else

-            result = handleBuiltInFunctionCall(node);

-

-        if (! result) {

-            spv::MissingFunctionality("glslang function call");

-            glslang::TConstUnionArray emptyConsts;

-            int nextConst = 0;

-            result = createSpvConstant(node->getType(), emptyConsts, nextConst);

-        }

-        builder.clearAccessChain();

-        builder.setAccessChainRValue(result);

-

-        return false;

-    }

-    case glslang::EOpConstructMat2x2:

-    case glslang::EOpConstructMat2x3:

-    case glslang::EOpConstructMat2x4:

-    case glslang::EOpConstructMat3x2:

-    case glslang::EOpConstructMat3x3:

-    case glslang::EOpConstructMat3x4:

-    case glslang::EOpConstructMat4x2:

-    case glslang::EOpConstructMat4x3:

-    case glslang::EOpConstructMat4x4:

-    case glslang::EOpConstructDMat2x2:

-    case glslang::EOpConstructDMat2x3:

-    case glslang::EOpConstructDMat2x4:

-    case glslang::EOpConstructDMat3x2:

-    case glslang::EOpConstructDMat3x3:

-    case glslang::EOpConstructDMat3x4:

-    case glslang::EOpConstructDMat4x2:

-    case glslang::EOpConstructDMat4x3:

-    case glslang::EOpConstructDMat4x4:

-        isMatrix = true;

-        // fall through

-    case glslang::EOpConstructFloat:

-    case glslang::EOpConstructVec2:

-    case glslang::EOpConstructVec3:

-    case glslang::EOpConstructVec4:

-    case glslang::EOpConstructDouble:

-    case glslang::EOpConstructDVec2:

-    case glslang::EOpConstructDVec3:

-    case glslang::EOpConstructDVec4:

-    case glslang::EOpConstructBool:

-    case glslang::EOpConstructBVec2:

-    case glslang::EOpConstructBVec3:

-    case glslang::EOpConstructBVec4:

-    case glslang::EOpConstructInt:

-    case glslang::EOpConstructIVec2:

-    case glslang::EOpConstructIVec3:

-    case glslang::EOpConstructIVec4:

-    case glslang::EOpConstructUint:

-    case glslang::EOpConstructUVec2:

-    case glslang::EOpConstructUVec3:

-    case glslang::EOpConstructUVec4:

-    case glslang::EOpConstructStruct:

-    {

-        std::vector<spv::Id> arguments;

-        translateArguments(node->getSequence(), arguments);

-        spv::Id resultTypeId = convertGlslangToSpvType(node->getType());

-        spv::Id constructed;

-        if (node->getOp() == glslang::EOpConstructStruct || node->getType().isArray()) {

-            std::vector<spv::Id> constituents;

-            for (int c = 0; c < (int)arguments.size(); ++c)

-                constituents.push_back(arguments[c]);

-            constructed = builder.createCompositeConstruct(resultTypeId, constituents);

-        } else {

-            if (isMatrix)

-                constructed = builder.createMatrixConstructor(precision, arguments, resultTypeId);

-            else

-                constructed = builder.createConstructor(precision, arguments, resultTypeId);

-        }

-

-        builder.clearAccessChain();

-        builder.setAccessChainRValue(constructed);

-

-        return false;

-    }

-

-    // These six are component-wise compares with component-wise results.

-    // Forward on to createBinaryOperation(), requesting a vector result.

-    case glslang::EOpLessThan:

-    case glslang::EOpGreaterThan:

-    case glslang::EOpLessThanEqual:

-    case glslang::EOpGreaterThanEqual:

-    case glslang::EOpVectorEqual:

-    case glslang::EOpVectorNotEqual:

-    {

-        // Map the operation to a binary

-        binOp = node->getOp();

-        reduceComparison = false;

-        switch (node->getOp()) {

-        case glslang::EOpVectorEqual:     binOp = glslang::EOpVectorEqual;      break;

-        case glslang::EOpVectorNotEqual:  binOp = glslang::EOpVectorNotEqual;   break;

-        default:                          binOp = node->getOp();                break;

-        }

-

-        break;

-    }

-    case glslang::EOpMul:

-        // compontent-wise matrix multiply      

-        binOp = glslang::EOpMul;

-        break;

-    case glslang::EOpOuterProduct:

-        // two vectors multiplied to make a matrix

-        binOp = glslang::EOpOuterProduct;

-        break;

-    case glslang::EOpDot:

-    {

-        // for scalar dot product, use multiply        

-        glslang::TIntermSequence& glslangOperands = node->getSequence();

-        if (! glslangOperands[0]->getAsTyped()->isVector())

-            binOp = glslang::EOpMul;

-        break;

-    }

-    case glslang::EOpMod:

-        // when an aggregate, this is the floating-point mod built-in function,

-        // which can be emitted by the one in createBinaryOperation()

-        binOp = glslang::EOpMod;

-        break;

-    case glslang::EOpArrayLength:

-    {

-        glslang::TIntermTyped* typedNode = node->getSequence()[0]->getAsTyped();

-        assert(typedNode);

-        spv::Id length = builder.makeIntConstant(typedNode->getType().getArraySize());

-

-        builder.clearAccessChain();

-        builder.setAccessChainRValue(length);

-

-        return false;

-    }

-    case glslang::EOpEmitVertex:

-    case glslang::EOpEndPrimitive:

-    case glslang::EOpBarrier:

-    case glslang::EOpMemoryBarrier:

-    case glslang::EOpMemoryBarrierAtomicCounter:

-    case glslang::EOpMemoryBarrierBuffer:

-    case glslang::EOpMemoryBarrierImage:

-    case glslang::EOpMemoryBarrierShared:

-    case glslang::EOpGroupMemoryBarrier:

-        noReturnValue = true;

-        // These all have 0 operands and will naturally finish up in the code below for 0 operands

-        break;

-

-    default:

-        break;

-    }

-

-    //

-    // See if it maps to a regular operation.

-    //

-

-    if (binOp != glslang::EOpNull) {

-        glslang::TIntermTyped* left = node->getSequence()[0]->getAsTyped();

-        glslang::TIntermTyped* right = node->getSequence()[1]->getAsTyped();

-        assert(left && right);

-

-        builder.clearAccessChain();

-        left->traverse(this);

-        spv::Id leftId = builder.accessChainLoad(TranslatePrecisionDecoration(left->getType()));

-

-        builder.clearAccessChain();

-        right->traverse(this);

-        spv::Id rightId = builder.accessChainLoad(TranslatePrecisionDecoration(right->getType()));

-

-        result = createBinaryOperation(binOp, precision, 

-                                       convertGlslangToSpvType(node->getType()), leftId, rightId, 

-                                       left->getType().getBasicType(), reduceComparison);

-

-        // code above should only make binOp that exists in createBinaryOperation

-        if (result == 0)

-            spv::MissingFunctionality("createBinaryOperation for aggregate");

-

-        builder.clearAccessChain();

-        builder.setAccessChainRValue(result);

-

-        return false;

-    }

-

-    glslang::TIntermSequence& glslangOperands = node->getSequence();

-    std::vector<spv::Id> operands;

-    for (int arg = 0; arg < (int)glslangOperands.size(); ++arg) {

-        builder.clearAccessChain();

-        glslangOperands[arg]->traverse(this);

-

-        // special case l-value operands; there are just a few

-        bool lvalue = false;

-        switch (node->getOp()) {

-        //case glslang::EOpFrexp:

-        case glslang::EOpModf:

-            if (arg == 1)

-                lvalue = true;

-            break;

-        //case glslang::EOpUAddCarry:

-        //case glslang::EOpUSubBorrow:

-        //case glslang::EOpUMulExtended:

-        default:

-            break;

-        }

-        if (lvalue)

-            operands.push_back(builder.accessChainGetLValue());

-        else

-            operands.push_back(builder.accessChainLoad(TranslatePrecisionDecoration(glslangOperands[arg]->getAsTyped()->getType())));

-    }

-    switch (glslangOperands.size()) {

-    case 0:

-        result = createNoArgOperation(node->getOp());

-        break;

-    case 1:

-        result = createUnaryOperation(node->getOp(), precision, convertGlslangToSpvType(node->getType()), operands.front(), node->getType().getBasicType() == glslang::EbtFloat || node->getType().getBasicType() == glslang::EbtDouble);

-        break;

-    default:

-        result = createMiscOperation(node->getOp(), precision, convertGlslangToSpvType(node->getType()), operands);

-        break;

-    }

-

-    if (noReturnValue)

-        return false;

-

-    if (! result) {

-        spv::MissingFunctionality("glslang aggregate");

-        return true;

-    } else {

-        builder.clearAccessChain();

-        builder.setAccessChainRValue(result);

-        return false;

-    }

-}

-

-bool TGlslangToSpvTraverser::visitSelection(glslang::TVisit /* visit */, glslang::TIntermSelection* node)

-{

-    // This path handles both if-then-else and ?:

-    // The if-then-else has a node type of void, while

-    // ?: has a non-void node type

-    spv::Id result = 0;

-    if (node->getBasicType() != glslang::EbtVoid) {

-        // don't handle this as just on-the-fly temporaries, because there will be two names

-        // and better to leave SSA to later passes

-        result = builder.createVariable(spv::StorageClassFunction, convertGlslangToSpvType(node->getType()));

-    }

-

-    // emit the condition before doing anything with selection

-    node->getCondition()->traverse(this);

-

-    // make an "if" based on the value created by the condition

-    spv::Builder::If ifBuilder(builder.accessChainLoad(spv::NoPrecision), builder);

-

-    if (node->getTrueBlock()) {

-        // emit the "then" statement

-        node->getTrueBlock()->traverse(this);

-        if (result)

-            builder.createStore(builder.accessChainLoad(TranslatePrecisionDecoration(node->getTrueBlock()->getAsTyped()->getType())), result);

-    }

-

-    if (node->getFalseBlock()) {

-        ifBuilder.makeBeginElse();

-        // emit the "else" statement

-        node->getFalseBlock()->traverse(this);

-        if (result)

-            builder.createStore(builder.accessChainLoad(TranslatePrecisionDecoration(node->getFalseBlock()->getAsTyped()->getType())), result);

-    }

-

-    ifBuilder.makeEndIf();

-

-    if (result) {

-        // GLSL only has r-values as the result of a :?, but

-        // if we have an l-value, that can be more efficient if it will

-        // become the base of a complex r-value expression, because the

-        // next layer copies r-values into memory to use the access-chain mechanism

-        builder.clearAccessChain();

-        builder.setAccessChainLValue(result);

-    }

-

-    return false;

-}

-

-bool TGlslangToSpvTraverser::visitSwitch(glslang::TVisit /* visit */, glslang::TIntermSwitch* node)

-{

-    // emit and get the condition before doing anything with switch

-    node->getCondition()->traverse(this);

-    spv::Id selector = builder.accessChainLoad(TranslatePrecisionDecoration(node->getCondition()->getAsTyped()->getType()));

-

-    // browse the children to sort out code segments

-    int defaultSegment = -1;

-    std::vector<TIntermNode*> codeSegments;

-    glslang::TIntermSequence& sequence = node->getBody()->getSequence();

-    std::vector<int> caseValues;

-    std::vector<int> valueIndexToSegment(sequence.size());  // note: probably not all are used, it is an overestimate

-    for (glslang::TIntermSequence::iterator c = sequence.begin(); c != sequence.end(); ++c) {

-        TIntermNode* child = *c;

-        if (child->getAsBranchNode() && child->getAsBranchNode()->getFlowOp() == glslang::EOpDefault)

-            defaultSegment = codeSegments.size();

-        else if (child->getAsBranchNode() && child->getAsBranchNode()->getFlowOp() == glslang::EOpCase) {

-            valueIndexToSegment[caseValues.size()] = codeSegments.size();

-            caseValues.push_back(child->getAsBranchNode()->getExpression()->getAsConstantUnion()->getConstArray()[0].getIConst());

-        } else

-            codeSegments.push_back(child);

-    }

-

-    // handle the case where the last code segment is missing, due to no code 

-    // statements between the last case and the end of the switch statement

-    if ((caseValues.size() && (int)codeSegments.size() == valueIndexToSegment[caseValues.size() - 1]) ||

-        (int)codeSegments.size() == defaultSegment)

-        codeSegments.push_back(nullptr);

-

-    // make the switch statement

-    std::vector<spv::Block*> segmentBlocks; // returned, as the blocks allocated in the call

-    builder.makeSwitch(selector, codeSegments.size(), caseValues, valueIndexToSegment, defaultSegment, segmentBlocks);

-

-    // emit all the code in the segments

-    breakForLoop.push(false);

-    for (unsigned int s = 0; s < codeSegments.size(); ++s) {

-        builder.nextSwitchSegment(segmentBlocks, s);

-        if (codeSegments[s])

-            codeSegments[s]->traverse(this);

-        else

-            builder.addSwitchBreak();

-    }

-    breakForLoop.pop();

-

-    builder.endSwitch(segmentBlocks);

-

-    return false;

-}

-

-void TGlslangToSpvTraverser::visitConstantUnion(glslang::TIntermConstantUnion* node)

-{

-    int nextConst = 0;

-    spv::Id constant = createSpvConstant(node->getType(), node->getConstArray(), nextConst);

-

-    builder.clearAccessChain();

-    builder.setAccessChainRValue(constant);

-}

-

-bool TGlslangToSpvTraverser::visitLoop(glslang::TVisit /* visit */, glslang::TIntermLoop* node)

-{

-    // body emission needs to know what the for-loop terminal is when it sees a "continue"

-    loopTerminal.push(node->getTerminal());

-

-    builder.makeNewLoop();

-

-    bool bodyOut = false;

-    if (! node->testFirst()) {

-        builder.endLoopHeaderWithoutTest();

-        if (node->getBody()) {

-            breakForLoop.push(true);

-            node->getBody()->traverse(this);

-            breakForLoop.pop();

-        }

-        bodyOut = true;

-        builder.createBranchToLoopTest();

-    }

-

-    if (node->getTest()) {

-        node->getTest()->traverse(this);

-        // the AST only contained the test computation, not the branch, we have to add it

-        spv::Id condition = builder.accessChainLoad(TranslatePrecisionDecoration(node->getTest()->getType()));

-        builder.createLoopTestBranch(condition);

-    }

-

-    if (! bodyOut && node->getBody()) {

-        breakForLoop.push(true);

-        node->getBody()->traverse(this);

-        breakForLoop.pop();

-    }

-

-    if (loopTerminal.top())

-        loopTerminal.top()->traverse(this);

-

-    builder.closeLoop();

-

-    loopTerminal.pop();

-

-    return false;

-}

-

-bool TGlslangToSpvTraverser::visitBranch(glslang::TVisit /* visit */, glslang::TIntermBranch* node)

-{

-    if (node->getExpression())

-        node->getExpression()->traverse(this);

-

-    switch (node->getFlowOp()) {

-    case glslang::EOpKill:

-        builder.makeDiscard();

-        break;

-    case glslang::EOpBreak:

-        if (breakForLoop.top())

-            builder.createLoopExit();

-        else

-            builder.addSwitchBreak();

-        break;

-    case glslang::EOpContinue:

-        if (loopTerminal.top())

-            loopTerminal.top()->traverse(this);

-        builder.createLoopContinue();

-        break;

-    case glslang::EOpReturn:

-        if (inMain)

-            builder.makeMainReturn();

-        else if (node->getExpression())

-            builder.makeReturn(false, builder.accessChainLoad(TranslatePrecisionDecoration(node->getExpression()->getType())));

-        else

-            builder.makeReturn();

-

-        builder.clearAccessChain();

-        break;

-

-    default:

-        spv::MissingFunctionality("branch type");

-        break;

-    }

-

-    return false;

-}

-

-spv::Id TGlslangToSpvTraverser::createSpvVariable(const glslang::TIntermSymbol* node)

-{

-    // First, steer off constants, which are not SPIR-V variables, but 

-    // can still have a mapping to a SPIR-V Id.

-    if (node->getQualifier().storage == glslang::EvqConst) {

-        int nextConst = 0;

-        return createSpvConstant(node->getType(), node->getConstArray(), nextConst);

-    }

-

-    // Now, handle actual variables

-    spv::StorageClass storageClass = TranslateStorageClass(node->getType());

-    spv::Id spvType = convertGlslangToSpvType(node->getType());

-

-    const char* name = node->getName().c_str();

-    if (glslang::IsAnonymous(name))

-        name = "";

-

-    return builder.createVariable(storageClass, spvType, name);

-}

-

-// Return type Id of the sampled type.

-spv::Id TGlslangToSpvTraverser::getSampledType(const glslang::TSampler& sampler)

-{

-    switch (sampler.type) {

-        case glslang::EbtFloat:    return builder.makeFloatType(32);

-        case glslang::EbtInt:      return builder.makeIntType(32);

-        case glslang::EbtUint:     return builder.makeUintType(32);

-        default:

-            spv::MissingFunctionality("sampled type");

-            return builder.makeFloatType(32);

-    }

-}

-

-// Do full recursive conversion of an arbitrary glslang type to a SPIR-V Id.

-spv::Id TGlslangToSpvTraverser::convertGlslangToSpvType(const glslang::TType& type)

-{

-    spv::Id spvType = 0;

-

-    switch (type.getBasicType()) {

-    case glslang::EbtVoid:

-        spvType = builder.makeVoidType();

-        if (type.isArray())

-            spv::MissingFunctionality("array of void");

-        break;

-    case glslang::EbtFloat:

-        spvType = builder.makeFloatType(32);

-        break;

-    case glslang::EbtDouble:

-        spvType = builder.makeFloatType(64);

-        break;

-    case glslang::EbtBool:

-        spvType = builder.makeBoolType();

-        break;

-    case glslang::EbtInt:

-        spvType = builder.makeIntType(32);

-        break;

-    case glslang::EbtUint:

-        spvType = builder.makeUintType(32);

-        break;

-    case glslang::EbtSampler:

-        {

-            const glslang::TSampler& sampler = type.getSampler();

-            spvType = builder.makeSampler(getSampledType(sampler), TranslateDimensionality(sampler), 

-                                          sampler.image ? spv::Builder::samplerContentImage : spv::Builder::samplerContentTextureFilter,

-                                          sampler.arrayed, sampler.shadow, sampler.ms);

-        }

-        break;

-    case glslang::EbtStruct:

-    case glslang::EbtBlock:

-        {

-            // If we've seen this struct type, return it

-            const glslang::TTypeList* glslangStruct = type.getStruct();

-            std::vector<spv::Id> structFields;

-            spvType = structMap[glslangStruct];

-            if (spvType)

-                break;

-

-            // else, we haven't seen it...

-

-            // Create a vector of struct types for SPIR-V to consume

-            int memberDelta = 0;  // how much the member's index changes from glslang to SPIR-V, normally 0, except sometimes for blocks

-            if (type.getBasicType() == glslang::EbtBlock)

-                memberRemapper[glslangStruct].resize(glslangStruct->size());

-            for (int i = 0; i < (int)glslangStruct->size(); i++) {

-                glslang::TType& glslangType = *(*glslangStruct)[i].type;

-                if (glslangType.hiddenMember()) {

-                    ++memberDelta;

-                    if (type.getBasicType() == glslang::EbtBlock)

-                        memberRemapper[glslangStruct][i] = -1;

-                } else {

-                    if (type.getBasicType() == glslang::EbtBlock)

-                        memberRemapper[glslangStruct][i] = i - memberDelta;

-                    structFields.push_back(convertGlslangToSpvType(glslangType));

-                }

-            }

-

-            // Make the SPIR-V type

-            spvType = builder.makeStructType(structFields, type.getTypeName().c_str());

-            structMap[glslangStruct] = spvType;

-

-            // Name and decorate the non-hidden members

-            for (int i = 0; i < (int)glslangStruct->size(); i++) {

-                glslang::TType& glslangType = *(*glslangStruct)[i].type;

-                int member = i;

-                if (type.getBasicType() == glslang::EbtBlock)

-                    member = memberRemapper[glslangStruct][i];

-                // using -1 above to indicate a hidden member

-                if (member >= 0) {

-                    builder.addMemberName(spvType, member, glslangType.getFieldName().c_str());

-                    addMemberDecoration(spvType, member, TranslateLayoutDecoration(glslangType));

-                    addMemberDecoration(spvType, member, TranslatePrecisionDecoration(glslangType));

-                    addMemberDecoration(spvType, member, TranslateInterpolationDecoration(glslangType));

-                    addMemberDecoration(spvType, member, TranslateInvariantDecoration(glslangType));

-                    if (glslangType.getQualifier().hasLocation())

-                        builder.addMemberDecoration(spvType, member, spv::DecorationLocation, glslangType.getQualifier().layoutLocation);

-                    if (glslangType.getQualifier().hasComponent())

-                        builder.addMemberDecoration(spvType, member, spv::DecorationComponent, glslangType.getQualifier().layoutComponent);

-                    if (glslangType.getQualifier().hasXfbOffset())

-                        builder.addMemberDecoration(spvType, member, spv::DecorationOffset, glslangType.getQualifier().layoutXfbOffset);

-

-                    // built-in variable decorations

-                    int builtIn = TranslateBuiltInDecoration(glslangType.getQualifier().builtIn);

-                    if (builtIn != spv::BadValue)

-                        builder.addMemberDecoration(spvType, member, spv::DecorationBuiltIn, builtIn);

-                }

-            }

-

-            // Decorate the structure

-            addDecoration(spvType, TranslateLayoutDecoration(type));

-            addDecoration(spvType, TranslateBlockDecoration(type));

-            if (type.getQualifier().hasStream())

-                builder.addDecoration(spvType, spv::DecorationStream, type.getQualifier().layoutStream);

-            if (glslangIntermediate->getXfbMode()) {

-                if (type.getQualifier().hasXfbStride())

-                    builder.addDecoration(spvType, spv::DecorationStride, type.getQualifier().layoutXfbStride);

-                if (type.getQualifier().hasXfbBuffer())

-                    builder.addDecoration(spvType, spv::DecorationXfbBuffer, type.getQualifier().layoutXfbBuffer);

-            }

-        }

-        break;

-    default:

-        spv::MissingFunctionality("basic type");

-        break;

-    }

-

-    if (type.isMatrix())

-        spvType = builder.makeMatrixType(spvType, type.getMatrixCols(), type.getMatrixRows());

-    else {

-        // If this variable has a vector element count greater than 1, create a SPIR-V vector

-        if (type.getVectorSize() > 1)

-            spvType = builder.makeVectorType(spvType, type.getVectorSize());

-    }

-

-    if (type.isArray()) {

-        unsigned arraySize;

-        if (! type.isExplicitlySizedArray()) {

-            spv::MissingFunctionality("Unsized array");

-            arraySize = 8;

-        } else

-            arraySize = type.getArraySize();

-        spvType = builder.makeArrayType(spvType, arraySize);

-    }

-

-    return spvType;

-}

-

-bool TGlslangToSpvTraverser::isShaderEntrypoint(const glslang::TIntermAggregate* node)

-{

-    return node->getName() == "main(";

-}

-

-// Make all the functions, skeletally, without actually visiting their bodies.

-void TGlslangToSpvTraverser::makeFunctions(const glslang::TIntermSequence& glslFunctions)

-{

-    for (int f = 0; f < (int)glslFunctions.size(); ++f) {

-        glslang::TIntermAggregate* glslFunction = glslFunctions[f]->getAsAggregate();

-        if (! glslFunction || glslFunction->getOp() != glslang::EOpFunction || isShaderEntrypoint(glslFunction))

-            continue;

-

-        // We're on a user function.  Set up the basic interface for the function now,

-        // so that it's available to call.

-        // Translating the body will happen later.

-        //

-        // Typically (except for a "const in" parameter), an address will be passed to the 

-        // function.  What it is an address of varies:

-        //

-        // - "in" parameters not marked as "const" can be written to without modifying the argument,

-        //  so that write needs to be to a copy, hence the address of a copy works.

-        //

-        // - "const in" parameters can just be the r-value, as no writes need occur.

-        //

-        // - "out" and "inout" arguments can't be done as direct pointers, because GLSL has

-        // copy-in/copy-out semantics.  They can be handled though with a pointer to a copy.

-

-        std::vector<spv::Id> paramTypes;

-        glslang::TIntermSequence& parameters = glslFunction->getSequence()[0]->getAsAggregate()->getSequence();

-

-        for (int p = 0; p < (int)parameters.size(); ++p) {

-            const glslang::TType& paramType = parameters[p]->getAsTyped()->getType();

-            spv::Id typeId = convertGlslangToSpvType(paramType);

-            if (paramType.getQualifier().storage != glslang::EvqConstReadOnly)

-                typeId = builder.makePointer(spv::StorageClassFunction, typeId);

-            else

-                constReadOnlyParameters.insert(parameters[p]->getAsSymbolNode()->getId());

-            paramTypes.push_back(typeId);

-        }

-

-        spv::Block* functionBlock;

-        spv::Function *function = builder.makeFunctionEntry(convertGlslangToSpvType(glslFunction->getType()), glslFunction->getName().c_str(),

-                                                              paramTypes, &functionBlock);

-

-        // Track function to emit/call later

-        functionMap[glslFunction->getName().c_str()] = function;

-

-        // Set the parameter id's

-        for (int p = 0; p < (int)parameters.size(); ++p) {

-            symbolValues[parameters[p]->getAsSymbolNode()->getId()] = function->getParamId(p);

-            // give a name too

-            builder.addName(function->getParamId(p), parameters[p]->getAsSymbolNode()->getName().c_str());

-        }

-    }

-}

-

-// Process all the initializers, while skipping the functions and link objects

-void TGlslangToSpvTraverser::makeGlobalInitializers(const glslang::TIntermSequence& initializers)

-{

-    builder.setBuildPoint(shaderEntry->getLastBlock());

-    for (int i = 0; i < (int)initializers.size(); ++i) {

-        glslang::TIntermAggregate* initializer = initializers[i]->getAsAggregate();

-        if (initializer && initializer->getOp() != glslang::EOpFunction && initializer->getOp() != glslang::EOpLinkerObjects) {

-

-            // We're on a top-level node that's not a function.  Treat as an initializer, whose

-            // code goes into the beginning of main.

-            initializer->traverse(this);

-        }

-    }

-}

-

-// Process all the functions, while skipping initializers.

-void TGlslangToSpvTraverser::visitFunctions(const glslang::TIntermSequence& glslFunctions)

-{

-    for (int f = 0; f < (int)glslFunctions.size(); ++f) {

-        glslang::TIntermAggregate* node = glslFunctions[f]->getAsAggregate();

-        if (node && (node->getOp() == glslang::EOpFunction || node->getOp() == glslang ::EOpLinkerObjects))

-            node->traverse(this);

-    }

-}

-

-void TGlslangToSpvTraverser::handleFunctionEntry(const glslang::TIntermAggregate* node)

-{

-    // SPIR-V functions should already be in the functionMap from the prepass 

-    // that called makeFunctions().

-    spv::Function* function = functionMap[node->getName().c_str()];

-    spv::Block* functionBlock = function->getEntryBlock();

-    builder.setBuildPoint(functionBlock);

-}

-

-void TGlslangToSpvTraverser::translateArguments(const glslang::TIntermSequence& glslangArguments, std::vector<spv::Id>& arguments)

-{

-    for (int i = 0; i < (int)glslangArguments.size(); ++i) {

-        builder.clearAccessChain();

-        glslangArguments[i]->traverse(this);

-        arguments.push_back(builder.accessChainLoad(TranslatePrecisionDecoration(glslangArguments[i]->getAsTyped()->getType())));

-    }

-}

-

-spv::Id TGlslangToSpvTraverser::handleBuiltInFunctionCall(const glslang::TIntermAggregate* node)

-{

-    std::vector<spv::Id> arguments;

-    translateArguments(node->getSequence(), arguments);

-

-    std::vector<spv::Id> argTypes;

-    for (int a = 0; a < (int)arguments.size(); ++a)

-        argTypes.push_back(builder.getTypeId(arguments[a]));

-

-    spv::Decoration precision = TranslatePrecisionDecoration(node->getType());

-

-    if (node->getName() == "ftransform(") {

-        spv::MissingFunctionality("ftransform()");

-        //spv::Id vertex = builder.createVariable(spv::StorageShaderGlobal, spv::VectorType::get(spv::makeFloatType(), 4),

-        //                                                             "gl_Vertex_sim");

-        //spv::Id matrix = builder.createVariable(spv::StorageShaderGlobal, spv::VectorType::get(spv::makeFloatType(), 4),

-        //                                                             "gl_ModelViewProjectionMatrix_sim");

-        return 0;

-    }

-

-    if (node->getName().substr(0, 7) == "texture" || node->getName().substr(0, 5) == "texel" || node->getName().substr(0, 6) == "shadow") {

-        const glslang::TSampler sampler = node->getSequence()[0]->getAsTyped()->getType().getSampler();

-        spv::Builder::TextureParameters params = { };

-        params.sampler = arguments[0];

-

-        // special case size query

-        if (node->getName().find("textureSize", 0) != std::string::npos) {

-            if (arguments.size() > 1) {

-                params.lod = arguments[1];

-                return builder.createTextureQueryCall(spv::OpTextureQuerySizeLod, params);

-            } else

-                return builder.createTextureQueryCall(spv::OpTextureQuerySize, params);

-        }

-

-        // special case the number of samples query

-        if (node->getName().find("textureSamples", 0) != std::string::npos)

-            return builder.createTextureQueryCall(spv::OpTextureQuerySamples, params);

-

-        // special case the other queries

-        if (node->getName().find("Query", 0) != std::string::npos) {

-            if (node->getName().find("Levels", 0) != std::string::npos)

-                return builder.createTextureQueryCall(spv::OpTextureQueryLevels, params);

-            else if (node->getName().find("Lod", 0) != std::string::npos) {

-                params.coords = arguments[1];

-                return builder.createTextureQueryCall(spv::OpTextureQueryLod, params);

-            } else

-                spv::MissingFunctionality("glslang texture query");

-        }

-

-        // This is no longer a query....

-

-        bool lod = node->getName().find("Lod", 0) != std::string::npos;

-        bool proj = node->getName().find("Proj", 0) != std::string::npos;

-        bool offsets = node->getName().find("Offsets", 0) != std::string::npos;

-        bool offset = ! offsets && node->getName().find("Offset", 0) != std::string::npos;

-        bool fetch = node->getName().find("Fetch", 0) != std::string::npos;

-        bool gather = node->getName().find("Gather", 0) != std::string::npos;

-        bool grad = node->getName().find("Grad", 0) != std::string::npos;

-

-        if (fetch)

-            spv::MissingFunctionality("texel fetch");

-        if (gather)

-            spv::MissingFunctionality("texture gather");

-

-        // check for bias argument

-        bool bias = false;

-        if (! lod && ! gather && ! grad && ! fetch) {

-            int nonBiasArgCount = 2;

-            if (offset)

-                ++nonBiasArgCount;

-            if (grad)

-                nonBiasArgCount += 2;

-

-            if ((int)arguments.size() > nonBiasArgCount)

-                bias = true;

-        }

-

-        bool cubeCompare = sampler.dim == glslang::EsdCube && sampler.arrayed && sampler.shadow;

-

-        // set the rest of the arguments

-        params.coords = arguments[1];

-        int extraArgs = 0;

-        if (cubeCompare)

-            params.Dref = arguments[2];

-        if (lod) {

-            params.lod = arguments[2];

-            ++extraArgs;

-        }

-        if (grad) {

-            params.gradX = arguments[2 + extraArgs];

-            params.gradY = arguments[3 + extraArgs];

-            extraArgs += 2;

-        }

-        //if (gather && compare) {

-        //    params.compare = arguments[2 + extraArgs];

-        //    ++extraArgs;

-        //}

-        if (offset | offsets) {

-            params.offset = arguments[2 + extraArgs];

-            ++extraArgs;

-        }

-        if (bias) {

-            params.bias = arguments[2 + extraArgs];

-            ++extraArgs;

-        }

-

-        return builder.createTextureCall(precision, convertGlslangToSpvType(node->getType()), proj, params);

-    }

-

-    spv::MissingFunctionality("built-in function call");

-

-    return 0;

-}

-

-spv::Id TGlslangToSpvTraverser::handleUserFunctionCall(const glslang::TIntermAggregate* node)

-{

-    // Grab the function's pointer from the previously created function

-    spv::Function* function = functionMap[node->getName().c_str()];

-    if (! function)

-        return 0;

-

-    const glslang::TIntermSequence& glslangArgs = node->getSequence();

-    const glslang::TQualifierList& qualifiers = node->getQualifierList();

-

-    //  See comments in makeFunctions() for details about the semantics for parameter passing.

-    //

-    // These imply we need a four step process:

-    // 1. Evaluate the arguments

-    // 2. Allocate and make copies of in, out, and inout arguments

-    // 3. Make the call

-    // 4. Copy back the results

-

-    // 1. Evaluate the arguments

-    std::vector<spv::Builder::AccessChain> lValues;

-    std::vector<spv::Id> rValues;

-    for (int a = 0; a < (int)glslangArgs.size(); ++a) {

-        // build l-value

-        builder.clearAccessChain();

-        glslangArgs[a]->traverse(this);

-        // keep outputs as l-values, evaluate input-only as r-values

-        if (qualifiers[a] != glslang::EvqConstReadOnly) {

-            // save l-value

-            lValues.push_back(builder.getAccessChain());

-        } else {

-            // process r-value

-            rValues.push_back(builder.accessChainLoad(TranslatePrecisionDecoration(glslangArgs[a]->getAsTyped()->getType())));

-        }

-    }

-

-    // 2. Allocate space for anything needing a copy, and if it's "in" or "inout"

-    // copy the original into that space.

-    //

-    // Also, build up the list of actual arguments to pass in for the call

-    int lValueCount = 0;

-    int rValueCount = 0;

-    std::vector<spv::Id> spvArgs;

-    for (int a = 0; a < (int)glslangArgs.size(); ++a) {

-        spv::Id arg;

-        if (qualifiers[a] != glslang::EvqConstReadOnly) {

-            // need space to hold the copy

-            const glslang::TType& paramType = glslangArgs[a]->getAsTyped()->getType();

-            arg = builder.createVariable(spv::StorageClassFunction, convertGlslangToSpvType(paramType), "param");

-            if (qualifiers[a] == glslang::EvqIn || qualifiers[a] == glslang::EvqInOut) {

-                // need to copy the input into output space

-                builder.setAccessChain(lValues[lValueCount]);

-                spv::Id copy = builder.accessChainLoad(spv::NoPrecision);  // TODO: get precision

-                builder.createStore(copy, arg);

-            }

-            ++lValueCount;

-        } else {

-            arg = rValues[rValueCount];

-            ++rValueCount;

-        }

-        spvArgs.push_back(arg);

-    }

-

-    // 3. Make the call.

-    spv::Id result = builder.createFunctionCall(function, spvArgs);

-

-    // 4. Copy back out an "out" arguments.

-    lValueCount = 0;

-    for (int a = 0; a < (int)glslangArgs.size(); ++a) {

-        if (qualifiers[a] != glslang::EvqConstReadOnly) {

-            if (qualifiers[a] == glslang::EvqOut || qualifiers[a] == glslang::EvqInOut) {

-                spv::Id copy = builder.createLoad(spvArgs[a]);

-                builder.setAccessChain(lValues[lValueCount]);

-                builder.accessChainStore(copy);

-            }

-            ++lValueCount;

-        }

-    }

-

-    return result;

-}

-

-// Translate AST operation to SPV operation, already having SPV-based operands/types.

-spv::Id TGlslangToSpvTraverser::createBinaryOperation(glslang::TOperator op, spv::Decoration precision, 

-                                                      spv::Id typeId, spv::Id left, spv::Id right,

-                                                      glslang::TBasicType typeProxy, bool reduceComparison)

-{

-    bool isUnsigned = typeProxy == glslang::EbtUint;

-    bool isFloat = typeProxy == glslang::EbtFloat || typeProxy == glslang::EbtDouble;

-

-    spv::Op binOp = spv::OpNop;

-    bool needsPromotion = true;

-    bool comparison = false;

-

-    switch (op) {

-    case glslang::EOpAdd:

-    case glslang::EOpAddAssign:

-        if (isFloat)

-            binOp = spv::OpFAdd;

-        else

-            binOp = spv::OpIAdd;

-        break;

-    case glslang::EOpSub:

-    case glslang::EOpSubAssign:

-        if (isFloat)

-            binOp = spv::OpFSub;

-        else

-            binOp = spv::OpISub;

-        break;

-    case glslang::EOpMul:

-    case glslang::EOpMulAssign:

-        if (isFloat)

-            binOp = spv::OpFMul;

-        else

-            binOp = spv::OpIMul;

-        break;

-    case glslang::EOpVectorTimesScalar:

-    case glslang::EOpVectorTimesScalarAssign:

-        if (builder.isVector(right))

-            std::swap(left, right);

-        assert(builder.isScalar(right));

-        binOp = spv::OpVectorTimesScalar;

-        needsPromotion = false;

-        break;

-    case glslang::EOpVectorTimesMatrix:

-    case glslang::EOpVectorTimesMatrixAssign:

-        assert(builder.isVector(left));

-        assert(builder.isMatrix(right));

-        binOp = spv::OpVectorTimesMatrix;

-        break;

-    case glslang::EOpMatrixTimesVector:

-        assert(builder.isMatrix(left));

-        assert(builder.isVector(right));

-        binOp = spv::OpMatrixTimesVector;

-        break;

-    case glslang::EOpMatrixTimesScalar:

-    case glslang::EOpMatrixTimesScalarAssign:

-        if (builder.isMatrix(right))

-            std::swap(left, right);

-        assert(builder.isScalar(right));

-        binOp = spv::OpMatrixTimesScalar;

-        break;

-    case glslang::EOpMatrixTimesMatrix:

-    case glslang::EOpMatrixTimesMatrixAssign:

-        assert(builder.isMatrix(left));

-        assert(builder.isMatrix(right));

-        binOp = spv::OpMatrixTimesMatrix;

-        break;

-    case glslang::EOpOuterProduct:

-        binOp = spv::OpOuterProduct;

-        needsPromotion = false;

-        break;

-

-    case glslang::EOpDiv:

-    case glslang::EOpDivAssign:

-        if (isFloat)

-            binOp = spv::OpFDiv;

-        else if (isUnsigned)

-            binOp = spv::OpUDiv;

-        else

-            binOp = spv::OpSDiv;

-        break;

-    case glslang::EOpMod:

-    case glslang::EOpModAssign:

-        if (isFloat)

-            binOp = spv::OpFMod;

-        else if (isUnsigned)

-            binOp = spv::OpUMod;

-        else

-            binOp = spv::OpSMod;

-        break;

-    case glslang::EOpRightShift:

-    case glslang::EOpRightShiftAssign:

-        if (isUnsigned)

-            binOp = spv::OpShiftRightLogical;

-        else

-            binOp = spv::OpShiftRightArithmetic;

-        break;

-    case glslang::EOpLeftShift:

-    case glslang::EOpLeftShiftAssign:

-        binOp = spv::OpShiftLeftLogical;

-        break;

-    case glslang::EOpAnd:

-    case glslang::EOpAndAssign:

-        binOp = spv::OpBitwiseAnd;

-        break;

-    case glslang::EOpLogicalAnd:

-        needsPromotion = false;

-        binOp = spv::OpLogicalAnd;

-        break;

-    case glslang::EOpInclusiveOr:

-    case glslang::EOpInclusiveOrAssign:

-        binOp = spv::OpBitwiseOr;

-        break;

-    case glslang::EOpLogicalOr:

-        needsPromotion = false;

-        binOp = spv::OpLogicalOr;

-        break;

-    case glslang::EOpExclusiveOr:

-    case glslang::EOpExclusiveOrAssign:

-        binOp = spv::OpBitwiseXor;

-        break;

-    case glslang::EOpLogicalXor:

-        needsPromotion = false;

-        binOp = spv::OpLogicalXor;

-        break;

-

-    case glslang::EOpLessThan:

-    case glslang::EOpGreaterThan:

-    case glslang::EOpLessThanEqual:

-    case glslang::EOpGreaterThanEqual:

-    case glslang::EOpEqual:

-    case glslang::EOpNotEqual:

-    case glslang::EOpVectorEqual:

-    case glslang::EOpVectorNotEqual:

-        comparison = true;

-        break;

-    default:

-        break;

-    }

-

-    if (binOp != spv::OpNop) {

-        if (builder.isMatrix(left) || builder.isMatrix(right)) {

-            switch (binOp) {

-            case spv::OpMatrixTimesScalar:

-            case spv::OpVectorTimesMatrix:

-            case spv::OpMatrixTimesVector:

-            case spv::OpMatrixTimesMatrix:

-                break;

-            case spv::OpFDiv:

-                // turn it into a multiply...

-                assert(builder.isMatrix(left) && builder.isScalar(right));

-                right = builder.createBinOp(spv::OpFDiv, builder.getTypeId(right), builder.makeFloatConstant(1.0F), right);

-                binOp = spv::OpFMul;

-                break;

-            default:

-                spv::MissingFunctionality("binary operation on matrix");

-                break;

-            }

-

-            spv::Id id = builder.createBinOp(binOp, typeId, left, right);

-            builder.setPrecision(id, precision);

-

-            return id;

-        }

-

-        // No matrix involved; make both operands be the same number of components, if needed

-        if (needsPromotion)

-            builder.promoteScalar(precision, left, right);

-

-        spv::Id id = builder.createBinOp(binOp, typeId, left, right);

-        builder.setPrecision(id, precision);

-

-        return id;

-    }

-

-    if (! comparison)

-        return 0;

-

-    // Comparison instructions

-

-    if (reduceComparison && (builder.isVector(left) || builder.isMatrix(left) || builder.isAggregate(left))) {

-        assert(op == glslang::EOpEqual || op == glslang::EOpNotEqual);

-

-        return builder.createCompare(precision, left, right, op == glslang::EOpEqual);

-    }

-

-    switch (op) {

-    case glslang::EOpLessThan:

-        if (isFloat)

-            binOp = spv::OpFOrdLessThan;

-        else if (isUnsigned)

-            binOp = spv::OpULessThan;

-        else

-            binOp = spv::OpSLessThan;

-        break;

-    case glslang::EOpGreaterThan:

-        if (isFloat)

-            binOp = spv::OpFOrdGreaterThan;

-        else if (isUnsigned)

-            binOp = spv::OpUGreaterThan;

-        else

-            binOp = spv::OpSGreaterThan;

-        break;

-    case glslang::EOpLessThanEqual:

-        if (isFloat)

-            binOp = spv::OpFOrdLessThanEqual;

-        else if (isUnsigned)

-            binOp = spv::OpULessThanEqual;

-        else

-            binOp = spv::OpSLessThanEqual;

-        break;

-    case glslang::EOpGreaterThanEqual:

-        if (isFloat)

-            binOp = spv::OpFOrdGreaterThanEqual;

-        else if (isUnsigned)

-            binOp = spv::OpUGreaterThanEqual;

-        else

-            binOp = spv::OpSGreaterThanEqual;

-        break;

-    case glslang::EOpEqual:

-    case glslang::EOpVectorEqual:

-        if (isFloat)

-            binOp = spv::OpFOrdEqual;

-        else

-            binOp = spv::OpIEqual;

-        break;

-    case glslang::EOpNotEqual:

-    case glslang::EOpVectorNotEqual:

-        if (isFloat)

-            binOp = spv::OpFOrdNotEqual;

-        else

-            binOp = spv::OpINotEqual;

-        break;

-    default:

-        break;

-    }

-

-    if (binOp != spv::OpNop) {

-        spv::Id id = builder.createBinOp(binOp, typeId, left, right);

-        builder.setPrecision(id, precision);

-

-        return id;

-    }

-

-    return 0;

-}

-

-spv::Id TGlslangToSpvTraverser::createUnaryOperation(glslang::TOperator op, spv::Decoration precision, spv::Id typeId, spv::Id operand, bool isFloat)

-{

-    spv::Op unaryOp = spv::OpNop;

-    int libCall = -1;

-

-    switch (op) {

-    case glslang::EOpNegative:

-        if (isFloat)

-            unaryOp = spv::OpFNegate;

-        else

-            unaryOp = spv::OpSNegate;

-        break;

-

-    case glslang::EOpLogicalNot:

-    case glslang::EOpVectorLogicalNot:

-    case glslang::EOpBitwiseNot:

-        unaryOp = spv::OpNot;

-        break;

-    

-    case glslang::EOpDeterminant:

-        libCall = GLSL_STD_450::Determinant;

-        break;

-    case glslang::EOpMatrixInverse:

-        libCall = GLSL_STD_450::MatrixInverse;

-        break;

-    case glslang::EOpTranspose:

-        unaryOp = spv::OpTranspose;

-        break;

-

-    case glslang::EOpRadians:

-        libCall = GLSL_STD_450::Radians;

-        break;

-    case glslang::EOpDegrees:

-        libCall = GLSL_STD_450::Degrees;

-        break;

-    case glslang::EOpSin:

-        libCall = GLSL_STD_450::Sin;

-        break;

-    case glslang::EOpCos:

-        libCall = GLSL_STD_450::Cos;

-        break;

-    case glslang::EOpTan:

-        libCall = GLSL_STD_450::Tan;

-        break;

-    case glslang::EOpAcos:

-        libCall = GLSL_STD_450::Acos;

-        break;

-    case glslang::EOpAsin:

-        libCall = GLSL_STD_450::Asin;

-        break;

-    case glslang::EOpAtan:

-        libCall = GLSL_STD_450::Atan;

-        break;

-

-    case glslang::EOpAcosh:

-        libCall = GLSL_STD_450::Acosh;

-        break;

-    case glslang::EOpAsinh:

-        libCall = GLSL_STD_450::Asinh;

-        break;

-    case glslang::EOpAtanh:

-        libCall = GLSL_STD_450::Atanh;

-        break;

-    case glslang::EOpTanh:

-        libCall = GLSL_STD_450::Tanh;

-        break;

-    case glslang::EOpCosh:

-        libCall = GLSL_STD_450::Cosh;

-        break;

-    case glslang::EOpSinh:

-        libCall = GLSL_STD_450::Sinh;

-        break;

-

-    case glslang::EOpLength:

-        libCall = GLSL_STD_450::Length;

-        break;

-    case glslang::EOpNormalize:

-        libCall = GLSL_STD_450::Normalize;

-        break;

-

-    case glslang::EOpExp:

-        libCall = GLSL_STD_450::Exp;

-        break;

-    case glslang::EOpLog:

-        libCall = GLSL_STD_450::Log;

-        break;

-    case glslang::EOpExp2:

-        libCall = GLSL_STD_450::Exp2;

-        break;

-    case glslang::EOpLog2:

-        libCall = GLSL_STD_450::Log2;

-        break;

-    case glslang::EOpSqrt:

-        libCall = GLSL_STD_450::Sqrt;

-        break;

-    case glslang::EOpInverseSqrt:

-        libCall = GLSL_STD_450::InverseSqrt;

-        break;

-

-    case glslang::EOpFloor:

-        libCall = GLSL_STD_450::Floor;

-        break;

-    case glslang::EOpTrunc:

-        libCall = GLSL_STD_450::Trunc;

-        break;

-    case glslang::EOpRound:

-        libCall = GLSL_STD_450::Round;

-        break;

-    case glslang::EOpRoundEven:

-        libCall = GLSL_STD_450::RoundEven;

-        break;

-    case glslang::EOpCeil:

-        libCall = GLSL_STD_450::Ceil;

-        break;

-    case glslang::EOpFract:

-        libCall = GLSL_STD_450::Fract;

-        break;

-

-    case glslang::EOpIsNan:

-        unaryOp = spv::OpIsNan;

-        break;

-    case glslang::EOpIsInf:

-        unaryOp = spv::OpIsInf;

-        break;

-

-    case glslang::EOpFloatBitsToInt:

-        libCall = GLSL_STD_450::FloatBitsToInt;

-        break;

-    case glslang::EOpFloatBitsToUint:

-        libCall = GLSL_STD_450::FloatBitsToUint;

-        break;

-    case glslang::EOpIntBitsToFloat:

-        libCall = GLSL_STD_450::IntBitsToFloat;

-        break;

-    case glslang::EOpUintBitsToFloat:

-        libCall = GLSL_STD_450::UintBitsToFloat;

-        break;

-    case glslang::EOpPackSnorm2x16:

-        libCall = GLSL_STD_450::PackSnorm2x16;

-        break;

-    case glslang::EOpUnpackSnorm2x16:

-        libCall = GLSL_STD_450::UnpackSnorm2x16;

-        break;

-    case glslang::EOpPackUnorm2x16:

-        libCall = GLSL_STD_450::PackUnorm2x16;

-        break;

-    case glslang::EOpUnpackUnorm2x16:

-        libCall = GLSL_STD_450::UnpackUnorm2x16;

-        break;

-    case glslang::EOpPackHalf2x16:

-        libCall = GLSL_STD_450::PackHalf2x16;

-        break;

-    case glslang::EOpUnpackHalf2x16:

-        libCall = GLSL_STD_450::UnpackHalf2x16;

-        break;

-

-    case glslang::EOpDPdx:

-        unaryOp = spv::OpDPdx;

-        break;

-    case glslang::EOpDPdy:

-        unaryOp = spv::OpDPdy;

-        break;

-    case glslang::EOpFwidth:

-        unaryOp = spv::OpFwidth;

-        break;

-    case glslang::EOpDPdxFine:

-        unaryOp = spv::OpDPdxFine;

-        break;

-    case glslang::EOpDPdyFine:

-        unaryOp = spv::OpDPdyFine;

-        break;

-    case glslang::EOpFwidthFine:

-        unaryOp = spv::OpFwidthFine;

-        break;

-    case glslang::EOpDPdxCoarse:

-        unaryOp = spv::OpDPdxCoarse;

-        break;

-    case glslang::EOpDPdyCoarse:

-        unaryOp = spv::OpDPdyCoarse;

-        break;

-    case glslang::EOpFwidthCoarse:

-        unaryOp = spv::OpFwidthCoarse;

-        break;

-

-    case glslang::EOpAny:

-        unaryOp = spv::OpAny;

-        break;

-    case glslang::EOpAll:

-        unaryOp = spv::OpAll;

-        break;

-

-    case glslang::EOpAbs:

-        libCall = GLSL_STD_450::Abs;

-        break;

-    case glslang::EOpSign:

-        libCall = GLSL_STD_450::Sign;

-        break;

-

-    default:

-        return 0;

-    }

-

-    spv::Id id;

-    if (libCall >= 0) {

-        std::vector<spv::Id> args;

-        args.push_back(operand);

-        id = builder.createBuiltinCall(precision, typeId, stdBuiltins, libCall, args);

-    } else

-        id = builder.createUnaryOp(unaryOp, typeId, operand);

-

-    builder.setPrecision(id, precision);

-

-    return id;

-}

-

-spv::Id TGlslangToSpvTraverser::createConversion(glslang::TOperator op, spv::Decoration precision, spv::Id destType, spv::Id operand)

-{

-    spv::Op convOp = spv::OpNop;

-    spv::Id zero = 0;

-    spv::Id one = 0;

-

-    int vectorSize = builder.isVectorType(destType) ? builder.getNumTypeComponents(destType) : 0;

-

-    switch (op) {

-    case glslang::EOpConvIntToBool:

-    case glslang::EOpConvUintToBool:

-        zero = builder.makeUintConstant(0);

-        zero = makeSmearedConstant(zero, vectorSize);

-        return builder.createBinOp(spv::OpINotEqual, destType, operand, zero);

-

-    case glslang::EOpConvFloatToBool:

-        zero = builder.makeFloatConstant(0.0F);

-        zero = makeSmearedConstant(zero, vectorSize);

-        return builder.createBinOp(spv::OpFOrdNotEqual, destType, operand, zero);

-

-    case glslang::EOpConvDoubleToBool:

-        zero = builder.makeDoubleConstant(0.0);

-        zero = makeSmearedConstant(zero, vectorSize);

-        return builder.createBinOp(spv::OpFOrdNotEqual, destType, operand, zero);

-

-    case glslang::EOpConvBoolToFloat:

-        convOp = spv::OpSelect;

-        zero = builder.makeFloatConstant(0.0);

-        one  = builder.makeFloatConstant(1.0);

-        break;

-    case glslang::EOpConvBoolToDouble:

-        convOp = spv::OpSelect;

-        zero = builder.makeDoubleConstant(0.0);

-        one  = builder.makeDoubleConstant(1.0);

-        break;

-    case glslang::EOpConvBoolToInt:

-        zero = builder.makeIntConstant(0);

-        one  = builder.makeIntConstant(1);

-        convOp = spv::OpSelect;

-        break;

-    case glslang::EOpConvBoolToUint:

-        zero = builder.makeUintConstant(0);

-        one  = builder.makeUintConstant(1);

-        convOp = spv::OpSelect;

-        break;

-

-    case glslang::EOpConvIntToFloat:

-    case glslang::EOpConvIntToDouble:

-        convOp = spv::OpConvertSToF;

-        break;

-

-    case glslang::EOpConvUintToFloat:

-    case glslang::EOpConvUintToDouble:

-        convOp = spv::OpConvertUToF;

-        break;

-

-    case glslang::EOpConvDoubleToFloat:

-    case glslang::EOpConvFloatToDouble:

-        convOp = spv::OpFConvert;

-        break;

-

-    case glslang::EOpConvFloatToInt:

-    case glslang::EOpConvDoubleToInt:

-        convOp = spv::OpConvertFToS;

-        break;

-

-    case glslang::EOpConvUintToInt:

-    case glslang::EOpConvIntToUint:

-        convOp = spv::OpBitcast;

-        break;

-

-    case glslang::EOpConvFloatToUint:

-    case glslang::EOpConvDoubleToUint:

-        convOp = spv::OpConvertFToU;

-        break;

-    default:

-        break;

-    }

-

-    spv::Id result = 0;

-    if (convOp == spv::OpNop)

-        return result;

-

-    if (convOp == spv::OpSelect) {

-        zero = makeSmearedConstant(zero, vectorSize);

-        one  = makeSmearedConstant(one, vectorSize);

-        result = builder.createTriOp(convOp, destType, operand, one, zero);

-    } else

-        result = builder.createUnaryOp(convOp, destType, operand);

-

-    builder.setPrecision(result, precision);

-

-    return result;

-}

-

-spv::Id TGlslangToSpvTraverser::makeSmearedConstant(spv::Id constant, int vectorSize)

-{

-    if (vectorSize == 0)

-        return constant;

-

-    spv::Id vectorTypeId = builder.makeVectorType(builder.getTypeId(constant), vectorSize);

-    std::vector<spv::Id> components;

-    for (int c = 0; c < vectorSize; ++c)

-        components.push_back(constant);

-    return builder.makeCompositeConstant(vectorTypeId, components);

-}

-

-spv::Id TGlslangToSpvTraverser::createMiscOperation(glslang::TOperator op, spv::Decoration precision, spv::Id typeId, std::vector<spv::Id>& operands)

-{

-    spv::Op opCode = spv::OpNop;

-    int libCall = -1;

-

-    switch (op) {

-    case glslang::EOpMin:

-        libCall = GLSL_STD_450::Min;

-        break;

-    case glslang::EOpModf:

-        libCall = GLSL_STD_450::Modf;

-        break;

-    case glslang::EOpMax:

-        libCall = GLSL_STD_450::Max;

-        break;

-    case glslang::EOpPow:

-        libCall = GLSL_STD_450::Pow;

-        break;

-    case glslang::EOpDot:

-        opCode = spv::OpDot;

-        break;

-    case glslang::EOpAtan:

-        libCall = GLSL_STD_450::Atan2;

-        break;

-

-    case glslang::EOpClamp:

-        libCall = GLSL_STD_450::Clamp;

-        break;

-    case glslang::EOpMix:

-        libCall = GLSL_STD_450::Mix;

-        break;

-    case glslang::EOpStep:

-        libCall = GLSL_STD_450::Step;

-        break;

-    case glslang::EOpSmoothStep:

-        libCall = GLSL_STD_450::SmoothStep;

-        break;

-

-    case glslang::EOpDistance:

-        libCall = GLSL_STD_450::Distance;

-        break;

-    case glslang::EOpCross:

-        libCall = GLSL_STD_450::Cross;

-        break;

-    case glslang::EOpFaceForward:

-        libCall = GLSL_STD_450::FaceForward;

-        break;

-    case glslang::EOpReflect:

-        libCall = GLSL_STD_450::Reflect;

-        break;

-    case glslang::EOpRefract:

-        libCall = GLSL_STD_450::Refract;

-        break;

-    default:

-        return 0;

-    }

-

-    spv::Id id = 0;

-    if (libCall >= 0)

-        id = builder.createBuiltinCall(precision, typeId, stdBuiltins, libCall, operands);

-    else {

-        switch (operands.size()) {

-        case 0:

-            // should all be handled by visitAggregate and createNoArgOperation

-            assert(0);

-            return 0;

-        case 1:

-            // should all be handled by createUnaryOperation

-            assert(0);

-            return 0;

-        case 2:

-            id = builder.createBinOp(opCode, typeId, operands[0], operands[1]);

-            break;

-        case 3:

-            id = builder.createTernaryOp(opCode, typeId, operands[0], operands[1], operands[2]);

-            break;

-        default:

-            // These do not exist yet

-            assert(0 && "operation with more than 3 operands");

-            break;

-        }

-    }

-

-    builder.setPrecision(id, precision);

-

-    return id;

-}

-

-// Intrinsics with no arguments, no return value, and no precision.

-spv::Id TGlslangToSpvTraverser::createNoArgOperation(glslang::TOperator op)

-{

-    // TODO: get the barrier operands correct

-

-    switch (op) {

-    case glslang::EOpEmitVertex:

-        builder.createNoResultOp(spv::OpEmitVertex);

-        return 0;

-    case glslang::EOpEndPrimitive:

-        builder.createNoResultOp(spv::OpEndPrimitive);

-        return 0;

-    case glslang::EOpBarrier:

-        builder.createMemoryBarrier(spv::ExecutionScopeDevice, spv::MemorySemanticsAllMemory);

-        builder.createControlBarrier(spv::ExecutionScopeDevice);

-        return 0;

-    case glslang::EOpMemoryBarrier:

-        builder.createMemoryBarrier(spv::ExecutionScopeDevice, spv::MemorySemanticsAllMemory);

-        return 0;

-    case glslang::EOpMemoryBarrierAtomicCounter:

-        builder.createMemoryBarrier(spv::ExecutionScopeDevice, spv::MemorySemanticsAtomicCounterMemoryMask);

-        return 0;

-    case glslang::EOpMemoryBarrierBuffer:

-        builder.createMemoryBarrier(spv::ExecutionScopeDevice, spv::MemorySemanticsUniformMemoryMask);

-        return 0;

-    case glslang::EOpMemoryBarrierImage:

-        builder.createMemoryBarrier(spv::ExecutionScopeDevice, spv::MemorySemanticsImageMemoryMask);

-        return 0;

-    case glslang::EOpMemoryBarrierShared:

-        builder.createMemoryBarrier(spv::ExecutionScopeDevice, spv::MemorySemanticsWorkgroupLocalMemoryMask);

-        return 0;

-    case glslang::EOpGroupMemoryBarrier:

-        builder.createMemoryBarrier(spv::ExecutionScopeDevice, spv::MemorySemanticsWorkgroupGlobalMemoryMask);

-        return 0;

-    default:

-        spv::MissingFunctionality("operation with no arguments");

-        return 0;

-    }

-}

-

-spv::Id TGlslangToSpvTraverser::getSymbolId(const glslang::TIntermSymbol* symbol)

-{

-    std::map<int, spv::Id>::iterator iter;

-    iter = symbolValues.find(symbol->getId());

-    spv::Id id;

-    if (symbolValues.end() != iter) {

-        id = iter->second;

-        return id;

-    }

-

-    // it was not found, create it

-    id = createSpvVariable(symbol);

-    symbolValues[symbol->getId()] = id;

-

-    if (! symbol->getType().isStruct()) {

-        addDecoration(id, TranslatePrecisionDecoration(symbol->getType()));

-        addDecoration(id, TranslateInterpolationDecoration(symbol->getType()));

-        if (symbol->getQualifier().hasLocation())

-            builder.addDecoration(id, spv::DecorationLocation, symbol->getQualifier().layoutLocation);

-        if (symbol->getQualifier().hasIndex())

-            builder.addDecoration(id, spv::DecorationIndex, symbol->getQualifier().layoutIndex);

-        if (symbol->getQualifier().hasComponent())

-            builder.addDecoration(id, spv::DecorationComponent, symbol->getQualifier().layoutComponent);

-        if (glslangIntermediate->getXfbMode()) {

-            if (symbol->getQualifier().hasXfbStride())

-                builder.addDecoration(id, spv::DecorationStride, symbol->getQualifier().layoutXfbStride);

-            if (symbol->getQualifier().hasXfbBuffer())

-                builder.addDecoration(id, spv::DecorationXfbBuffer, symbol->getQualifier().layoutXfbBuffer);

-            if (symbol->getQualifier().hasXfbOffset())

-                builder.addDecoration(id, spv::DecorationOffset, symbol->getQualifier().layoutXfbOffset);

-        }

-    }

-

-    addDecoration(id, TranslateInvariantDecoration(symbol->getType()));

-    if (symbol->getQualifier().hasStream())

-        builder.addDecoration(id, spv::DecorationStream, symbol->getQualifier().layoutStream);

-    if (symbol->getQualifier().hasSet())

-        builder.addDecoration(id, spv::DecorationDescriptorSet, symbol->getQualifier().layoutSet);

-    if (symbol->getQualifier().hasBinding())

-        builder.addDecoration(id, spv::DecorationBinding, symbol->getQualifier().layoutBinding);

-    if (glslangIntermediate->getXfbMode()) {

-        if (symbol->getQualifier().hasXfbStride())

-            builder.addDecoration(id, spv::DecorationStride, symbol->getQualifier().layoutXfbStride);

-        if (symbol->getQualifier().hasXfbBuffer())

-            builder.addDecoration(id, spv::DecorationXfbBuffer, symbol->getQualifier().layoutXfbBuffer);

-    }

-

-    // built-in variable decorations

-    int builtIn = TranslateBuiltInDecoration(symbol->getQualifier().builtIn);

-    if (builtIn != spv::BadValue)

-        builder.addDecoration(id, spv::DecorationBuiltIn, builtIn);

-

-    if (linkageOnly)

-        builder.addDecoration(id, spv::DecorationNoStaticUse);

-

-    return id;

-}

-

-void TGlslangToSpvTraverser::addDecoration(spv::Id id, spv::Decoration dec)

-{

-    if (dec != spv::BadValue)

-        builder.addDecoration(id, dec);

-}

-

-void TGlslangToSpvTraverser::addMemberDecoration(spv::Id id, int member, spv::Decoration dec)

-{

-    if (dec != spv::BadValue)

-        builder.addMemberDecoration(id, (unsigned)member, dec);

-}

-

-// Use 'consts' as the flattened glslang source of scalar constants to recursively

-// build the aggregate SPIR-V constant.

-//

-// If there are not enough elements present in 'consts', 0 will be substituted;

-// an empty 'consts' can be used to create a fully zeroed SPIR-V constant.

-//

-spv::Id TGlslangToSpvTraverser::createSpvConstant(const glslang::TType& glslangType, const glslang::TConstUnionArray& consts, int& nextConst)

-{

-    // vector of constants for SPIR-V

-    std::vector<spv::Id> spvConsts;

-

-    // Type is used for struct and array constants

-    spv::Id typeId = convertGlslangToSpvType(glslangType);

-

-    if (glslangType.isArray()) {

-        glslang::TType elementType;

-        elementType.shallowCopy(glslangType);   // TODO: desktop arrays of arrays functionality will need a deeper copy to avoid modifying the original

-        elementType.dereference();

-        for (int i = 0; i < glslangType.getArraySize(); ++i)

-            spvConsts.push_back(createSpvConstant(elementType, consts, nextConst));

-    } else if (glslangType.isMatrix()) {

-        glslang::TType vectorType;

-        vectorType.shallowCopy(glslangType);

-        vectorType.dereference();

-        for (int col = 0; col < glslangType.getMatrixCols(); ++col)

-            spvConsts.push_back(createSpvConstant(vectorType, consts, nextConst));

-    } else if (glslangType.getStruct()) {

-        glslang::TVector<glslang::TTypeLoc>::const_iterator iter;

-        for (iter = glslangType.getStruct()->begin(); iter != glslangType.getStruct()->end(); ++iter)

-            spvConsts.push_back(createSpvConstant(*iter->type, consts, nextConst));

-    } else if (glslangType.isVector()) {

-        for (unsigned int i = 0; i < (unsigned int)glslangType.getVectorSize(); ++i) {

-            bool zero = nextConst >= consts.size();

-            switch (glslangType.getBasicType()) {

-            case glslang::EbtInt:

-                spvConsts.push_back(builder.makeIntConstant(zero ? 0 : consts[nextConst].getIConst()));

-                break;

-            case glslang::EbtUint:

-                spvConsts.push_back(builder.makeUintConstant(zero ? 0 : consts[nextConst].getUConst()));

-                break;

-            case glslang::EbtFloat:

-                spvConsts.push_back(builder.makeFloatConstant(zero ? 0.0F : (float)consts[nextConst].getDConst()));

-                break;

-            case glslang::EbtDouble:

-                spvConsts.push_back(builder.makeDoubleConstant(zero ? 0.0 : consts[nextConst].getDConst()));

-                break;

-            case glslang::EbtBool:

-                spvConsts.push_back(builder.makeBoolConstant(zero ? false : consts[nextConst].getBConst()));

-                break;

-            default:

-                spv::MissingFunctionality("constant vector type");

-                break;

-            }

-            ++nextConst;

-        }

-    } else {

-        // we have a non-aggregate (scalar) constant

-        bool zero = nextConst >= consts.size();

-        spv::Id scalar = 0;

-        switch (glslangType.getBasicType()) {

-        case glslang::EbtInt:

-            scalar = builder.makeIntConstant(zero ? 0 : consts[nextConst].getIConst());

-            break;

-        case glslang::EbtUint:

-            scalar = builder.makeUintConstant(zero ? 0 : consts[nextConst].getUConst());

-            break;

-        case glslang::EbtFloat:

-            scalar = builder.makeFloatConstant(zero ? 0.0F : (float)consts[nextConst].getDConst());

-            break;

-        case glslang::EbtDouble:

-            scalar = builder.makeDoubleConstant(zero ? 0.0 : consts[nextConst].getDConst());

-            break;

-        case glslang::EbtBool:

-            scalar = builder.makeBoolConstant(zero ? false : consts[nextConst].getBConst());

-            break;

-        default:

-            spv::MissingFunctionality("constant scalar type");

-            break;

-        }

-        ++nextConst;

-        return scalar;

-    }

-

-    return builder.makeCompositeConstant(typeId, spvConsts);

-}

-

-};  // end anonymous namespace

-

-namespace glslang {

-

-// Write SPIR-V out to a binary file

-void OutputSpv(const std::vector<unsigned int>& spirv, const char* baseName)

-{

-    std::ofstream out;

-    std::string fileName(baseName);

-    fileName.append(".spv");

-    out.open(fileName.c_str(), std::ios::binary | std::ios::out);

-    for (int i = 0; i < (int)spirv.size(); ++i) {

-        unsigned int word = spirv[i];

-        out.write((const char*)&word, 4);

-    }

-    out.close();

-}

-

-//

-// Set up the glslang traversal

-//

-void GlslangToSpv(const glslang::TIntermediate& intermediate, std::vector<unsigned int>& spirv)

-{

-    TIntermNode* root = intermediate.getTreeRoot();

-

-    if (root == 0)

-        return;

-

-    glslang::GetThreadPoolAllocator().push();

-

-    TGlslangToSpvTraverser it(&intermediate);

-

-    root->traverse(&it);

-

-    it.dumpSpv(spirv);

-

-    glslang::GetThreadPoolAllocator().pop();

-}

-

-}; // end namespace glslang

+//
+//Copyright (C) 2014 LunarG, Inc.
+//
+//All rights reserved.
+//
+//Redistribution and use in source and binary forms, with or without
+//modification, are permitted provided that the following conditions
+//are met:
+//
+//    Redistributions of source code must retain the above copyright
+//    notice, this list of conditions and the following disclaimer.
+//
+//    Redistributions in binary form must reproduce the above
+//    copyright notice, this list of conditions and the following
+//    disclaimer in the documentation and/or other materials provided
+//    with the distribution.
+//
+//    Neither the name of 3Dlabs Inc. Ltd. nor the names of its
+//    contributors may be used to endorse or promote products derived
+//    from this software without specific prior written permission.
+//
+//THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+//"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+//LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+//FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+//COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+//INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+//BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+//LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+//CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+//LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+//ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+//POSSIBILITY OF SUCH DAMAGE.
+
+//
+// Author: John Kessenich, LunarG
+//
+// Visit the nodes in the glslang intermediate tree representation to
+// translate them to SPIR-V.
+//
+
+#include "spirv.h"
+#include "GlslangToSpv.h"
+#include "SpvBuilder.h"
+#include "GLSL450Lib.h"
+
+// Glslang includes
+#include "glslang/MachineIndependent/localintermediate.h"
+#include "glslang/MachineIndependent/SymbolTable.h"
+
+#include <string>
+#include <map>
+#include <list>
+#include <vector>
+#include <stack>
+#include <fstream>
+
+namespace {
+
+const int GlslangMagic = 0x51a;
+
+//
+// The main holder of information for translating glslang to SPIR-V.
+//
+// Derives from the AST walking base class.
+//
+class TGlslangToSpvTraverser : public glslang::TIntermTraverser {
+public:
+    TGlslangToSpvTraverser(const glslang::TIntermediate*);
+    virtual ~TGlslangToSpvTraverser();
+
+    bool visitAggregate(glslang::TVisit, glslang::TIntermAggregate*);
+    bool visitBinary(glslang::TVisit, glslang::TIntermBinary*);
+    void visitConstantUnion(glslang::TIntermConstantUnion*);
+    bool visitSelection(glslang::TVisit, glslang::TIntermSelection*);
+    bool visitSwitch(glslang::TVisit, glslang::TIntermSwitch*);
+    void visitSymbol(glslang::TIntermSymbol* symbol);
+    bool visitUnary(glslang::TVisit, glslang::TIntermUnary*);
+    bool visitLoop(glslang::TVisit, glslang::TIntermLoop*);
+    bool visitBranch(glslang::TVisit visit, glslang::TIntermBranch*);
+
+    void dumpSpv(std::vector<unsigned int>& out) { builder.dump(out); }
+
+protected:
+    spv::Id createSpvVariable(const glslang::TIntermSymbol*);
+    spv::Id getSampledType(const glslang::TSampler&);
+    spv::Id convertGlslangToSpvType(const glslang::TType& type);
+
+    bool isShaderEntrypoint(const glslang::TIntermAggregate* node);
+    void makeFunctions(const glslang::TIntermSequence&);
+    void makeGlobalInitializers(const glslang::TIntermSequence&);
+    void visitFunctions(const glslang::TIntermSequence&);
+    void handleFunctionEntry(const glslang::TIntermAggregate* node);
+    void translateArguments(const glslang::TIntermSequence& glslangArguments, std::vector<spv::Id>& arguments);
+    spv::Id handleBuiltInFunctionCall(const glslang::TIntermAggregate*);
+    spv::Id handleUserFunctionCall(const glslang::TIntermAggregate*);
+
+    spv::Id createBinaryOperation(glslang::TOperator op, spv::Decoration precision, spv::Id typeId, spv::Id left, spv::Id right, glslang::TBasicType typeProxy, bool reduceComparison = true);
+    spv::Id createUnaryOperation(glslang::TOperator op, spv::Decoration precision, spv::Id typeId, spv::Id operand, bool isFloat);
+    spv::Id createConversion(glslang::TOperator op, spv::Decoration precision, spv::Id destTypeId, spv::Id operand);
+    spv::Id makeSmearedConstant(spv::Id constant, int vectorSize);
+    spv::Id createMiscOperation(glslang::TOperator op, spv::Decoration precision, spv::Id typeId, std::vector<spv::Id>& operands);
+    spv::Id createNoArgOperation(glslang::TOperator op);
+    spv::Id getSymbolId(const glslang::TIntermSymbol* node);
+    void addDecoration(spv::Id id, spv::Decoration dec);
+    void addMemberDecoration(spv::Id id, int member, spv::Decoration dec);
+    spv::Id createSpvConstant(const glslang::TType& type, const glslang::TConstUnionArray&, int& nextConst);
+
+    spv::Function* shaderEntry;
+    int sequenceDepth;
+
+    // There is a 1:1 mapping between a spv builder and a module; this is thread safe
+    spv::Builder builder;
+    bool inMain;
+    bool mainTerminated;
+    bool linkageOnly;
+    const glslang::TIntermediate* glslangIntermediate;
+    spv::Id stdBuiltins;
+
+    std::map<int, spv::Id> symbolValues;
+    std::set<int> constReadOnlyParameters;  // set of formal function parameters that have glslang qualifier constReadOnly, so we know they are not local function "const" that are write-once
+    std::map<std::string, spv::Function*> functionMap;
+    std::map<const glslang::TTypeList*, spv::Id> structMap;
+    std::map<const glslang::TTypeList*, std::vector<int> > memberRemapper;  // for mapping glslang block indices to spv indices (e.g., due to hidden members)
+    std::stack<bool> breakForLoop;  // false means break for switch
+    std::stack<glslang::TIntermTyped*> loopTerminal;  // code from the last part of a for loop: for(...; ...; terminal), needed for e.g., continue };
+};
+
+//
+// Helper functions for translating glslang representations to SPIR-V enumerants.
+//
+
+// Translate glslang profile to SPIR-V source language.
+spv::SourceLanguage TranslateSourceLanguage(EProfile profile)
+{
+    switch (profile) {
+    case ENoProfile:
+    case ECoreProfile:
+    case ECompatibilityProfile:
+        return spv::SourceLanguageGLSL;
+    case EEsProfile:
+        return spv::SourceLanguageESSL;
+    default:
+        return spv::SourceLanguageUnknown;
+    }
+}
+
+// Translate glslang language (stage) to SPIR-V execution model.
+spv::ExecutionModel TranslateExecutionModel(EShLanguage stage)
+{
+    switch (stage) {
+    case EShLangVertex:           return spv::ExecutionModelVertex;
+    case EShLangTessControl:      return spv::ExecutionModelTessellationControl;
+    case EShLangTessEvaluation:   return spv::ExecutionModelTessellationEvaluation;
+    case EShLangGeometry:         return spv::ExecutionModelGeometry;
+    case EShLangFragment:         return spv::ExecutionModelFragment;
+    case EShLangCompute:          return spv::ExecutionModelGLCompute;
+    default:
+        spv::MissingFunctionality("GLSL stage");
+        return spv::ExecutionModelFragment;
+    }
+}
+
+// Translate glslang type to SPIR-V storage class.
+spv::StorageClass TranslateStorageClass(const glslang::TType& type)
+{
+    if (type.getQualifier().isPipeInput())
+        return spv::StorageClassInput;
+    else if (type.getQualifier().isPipeOutput())
+        return spv::StorageClassOutput;
+    else if (type.getQualifier().isUniformOrBuffer()) {
+        if (type.getBasicType() == glslang::EbtBlock)
+            return spv::StorageClassUniform;
+        else
+            return spv::StorageClassUniformConstant;
+        // TODO: how are we distuingishing between default and non-default non-writable uniforms?  Do default uniforms even exist?
+    } else {
+        switch (type.getQualifier().storage) {
+        case glslang::EvqShared:        return spv::StorageClassWorkgroupLocal;  break;
+        case glslang::EvqGlobal:        return spv::StorageClassPrivateGlobal;
+        case glslang::EvqConstReadOnly: return spv::StorageClassFunction;
+        case glslang::EvqTemporary:     return spv::StorageClassFunction;
+        default: 
+            spv::MissingFunctionality("unknown glslang storage class");
+            return spv::StorageClassFunction;
+        }
+    }
+}
+
+// Translate glslang sampler type to SPIR-V dimensionality.
+spv::Dim TranslateDimensionality(const glslang::TSampler& sampler)
+{
+    switch (sampler.dim) {
+    case glslang::Esd1D:     return spv::Dim1D;
+    case glslang::Esd2D:     return spv::Dim2D;
+    case glslang::Esd3D:     return spv::Dim3D;
+    case glslang::EsdCube:   return spv::DimCube;
+    case glslang::EsdRect:   return spv::DimRect;
+    case glslang::EsdBuffer: return spv::DimBuffer;
+    default:
+        spv::MissingFunctionality("unknown sampler dimension");
+        return spv::Dim2D;
+    }
+}
+
+// Translate glslang type to SPIR-V precision decorations.
+spv::Decoration TranslatePrecisionDecoration(const glslang::TType& type)
+{
+    switch (type.getQualifier().precision) {
+    case glslang::EpqLow:    return spv::DecorationPrecisionLow;
+    case glslang::EpqMedium: return spv::DecorationPrecisionMedium;
+    case glslang::EpqHigh:   return spv::DecorationPrecisionHigh;
+    default:
+        return spv::NoPrecision;
+    }
+}
+
+// Translate glslang type to SPIR-V block decorations.
+spv::Decoration TranslateBlockDecoration(const glslang::TType& type)
+{
+    if (type.getBasicType() == glslang::EbtBlock) {
+        switch (type.getQualifier().storage) {
+        case glslang::EvqUniform:      return spv::DecorationBlock;
+        case glslang::EvqBuffer:       return spv::DecorationBufferBlock;
+        case glslang::EvqVaryingIn:    return spv::DecorationBlock;
+        case glslang::EvqVaryingOut:   return spv::DecorationBlock;
+        default:
+            spv::MissingFunctionality("kind of block");
+            break;
+        }
+    }
+
+    return (spv::Decoration)spv::BadValue;
+}
+
+// Translate glslang type to SPIR-V layout decorations.
+spv::Decoration TranslateLayoutDecoration(const glslang::TType& type)
+{
+    if (type.isMatrix()) {
+        switch (type.getQualifier().layoutMatrix) {
+        case glslang::ElmRowMajor:
+            return spv::DecorationRowMajor;
+        default:
+            return spv::DecorationColMajor;
+        }
+    } else {
+        switch (type.getBasicType()) {
+        default:
+            return (spv::Decoration)spv::BadValue;
+            break;
+        case glslang::EbtBlock:
+            switch (type.getQualifier().storage) {
+            case glslang::EvqUniform:
+            case glslang::EvqBuffer:
+                switch (type.getQualifier().layoutPacking) {
+                case glslang::ElpShared:  return spv::DecorationGLSLShared;
+                case glslang::ElpStd140:  return spv::DecorationGLSLStd140;
+                case glslang::ElpStd430:  return spv::DecorationGLSLStd430;
+                case glslang::ElpPacked:  return spv::DecorationGLSLPacked;
+                default:
+                    spv::MissingFunctionality("uniform block layout");
+                    return spv::DecorationGLSLShared;
+                }
+            case glslang::EvqVaryingIn:
+            case glslang::EvqVaryingOut:
+                if (type.getQualifier().layoutPacking != glslang::ElpNone)
+                    spv::MissingFunctionality("in/out block layout");
+                return (spv::Decoration)spv::BadValue;
+            default:
+                spv::MissingFunctionality("block storage qualification");
+                return (spv::Decoration)spv::BadValue;
+            }
+        }
+    }
+}
+
+// Translate glslang type to SPIR-V interpolation decorations.
+spv::Decoration TranslateInterpolationDecoration(const glslang::TType& type)
+{
+    if (type.getQualifier().smooth)
+        return spv::DecorationSmooth;
+    if (type.getQualifier().nopersp)
+        return spv::DecorationNoperspective;
+    else if (type.getQualifier().patch)
+        return spv::DecorationPatch;
+    else if (type.getQualifier().flat)
+        return spv::DecorationFlat;
+    else if (type.getQualifier().centroid)
+        return spv::DecorationCentroid;
+    else if (type.getQualifier().sample)
+        return spv::DecorationSample;
+    else
+        return (spv::Decoration)spv::BadValue;
+}
+
+// If glslang type is invaraiant, return SPIR-V invariant decoration.
+spv::Decoration TranslateInvariantDecoration(const glslang::TType& type)
+{
+    if (type.getQualifier().invariant)
+        return spv::DecorationInvariant;
+    else
+        return (spv::Decoration)spv::BadValue;
+}
+
+// Translate glslang built-in variable to SPIR-V built in decoration.
+spv::BuiltIn TranslateBuiltInDecoration(glslang::TBuiltInVariable builtIn)
+{
+    switch (builtIn) {
+    case glslang::EbvPosition:             return spv::BuiltInPosition;
+    case glslang::EbvPointSize:            return spv::BuiltInPointSize;
+    case glslang::EbvClipVertex:           return spv::BuiltInClipVertex;
+    case glslang::EbvClipDistance:         return spv::BuiltInClipDistance;
+    case glslang::EbvCullDistance:         return spv::BuiltInCullDistance;
+    case glslang::EbvVertexId:             return spv::BuiltInVertexId;
+    case glslang::EbvInstanceId:           return spv::BuiltInInstanceId;
+    case glslang::EbvPrimitiveId:          return spv::BuiltInPrimitiveId;
+    case glslang::EbvInvocationId:         return spv::BuiltInInvocationId;
+    case glslang::EbvLayer:                return spv::BuiltInLayer;
+    case glslang::EbvViewportIndex:        return spv::BuiltInViewportIndex;
+    case glslang::EbvTessLevelInner:       return spv::BuiltInTessLevelInner;
+    case glslang::EbvTessLevelOuter:       return spv::BuiltInTessLevelOuter;
+    case glslang::EbvTessCoord:            return spv::BuiltInTessCoord;
+    case glslang::EbvPatchVertices:        return spv::BuiltInPatchVertices;
+    case glslang::EbvFragCoord:            return spv::BuiltInFragCoord;
+    case glslang::EbvPointCoord:           return spv::BuiltInPointCoord;
+    case glslang::EbvFace:                 return spv::BuiltInFrontFacing;
+    case glslang::EbvSampleId:             return spv::BuiltInSampleId;
+    case glslang::EbvSamplePosition:       return spv::BuiltInSamplePosition;
+    case glslang::EbvSampleMask:           return spv::BuiltInSampleMask;
+    case glslang::EbvFragColor:            return spv::BuiltInFragColor;
+    case glslang::EbvFragData:             return spv::BuiltInFragColor;
+    case glslang::EbvFragDepth:            return spv::BuiltInFragDepth;
+    case glslang::EbvHelperInvocation:     return spv::BuiltInHelperInvocation;
+    case glslang::EbvNumWorkGroups:        return spv::BuiltInNumWorkgroups;
+    case glslang::EbvWorkGroupSize:        return spv::BuiltInWorkgroupSize;
+    case glslang::EbvWorkGroupId:          return spv::BuiltInWorkgroupId;
+    case glslang::EbvLocalInvocationId:    return spv::BuiltInLocalInvocationId;
+    case glslang::EbvLocalInvocationIndex: return spv::BuiltInLocalInvocationIndex;
+    case glslang::EbvGlobalInvocationId:   return spv::BuiltInGlobalInvocationId;
+    default:                               return (spv::BuiltIn)spv::BadValue;
+    }
+}
+
+//
+// Implement the TGlslangToSpvTraverser class.
+//
+
+TGlslangToSpvTraverser::TGlslangToSpvTraverser(const glslang::TIntermediate* glslangIntermediate)
+    : TIntermTraverser(true, false, true), shaderEntry(0), sequenceDepth(0),
+      builder(GlslangMagic),
+      inMain(false), mainTerminated(false), linkageOnly(false),
+      glslangIntermediate(glslangIntermediate)
+{
+    spv::ExecutionModel executionModel = TranslateExecutionModel(glslangIntermediate->getStage());
+
+    builder.clearAccessChain();
+    builder.setSource(TranslateSourceLanguage(glslangIntermediate->getProfile()), glslangIntermediate->getVersion());
+    stdBuiltins = builder.import("GLSL.std.450");
+    builder.setMemoryModel(spv::AddressingModelLogical, spv::MemoryModelGLSL450);
+    shaderEntry = builder.makeMain();
+    builder.addEntryPoint(executionModel, shaderEntry);
+
+    // Add the source extensions
+    const std::set<std::string>& sourceExtensions = glslangIntermediate->getRequestedExtensions();
+    for (std::set<std::string>::const_iterator it = sourceExtensions.begin(); it != sourceExtensions.end(); ++it)
+        builder.addSourceExtension(it->c_str());
+
+    // Add the top-level modes for this shader.
+
+    if (glslangIntermediate->getXfbMode())
+        builder.addExecutionMode(shaderEntry, spv::ExecutionModeXfb);
+
+    unsigned int mode;
+    switch (glslangIntermediate->getStage()) {
+    case EShLangVertex:
+        break;
+
+    case EShLangTessControl:
+        builder.addExecutionMode(shaderEntry, spv::ExecutionModeOutputVertices, glslangIntermediate->getVertices());
+        break;
+
+    case EShLangTessEvaluation:
+        switch (glslangIntermediate->getInputPrimitive()) {
+        case glslang::ElgTriangles:           mode = spv::ExecutionModeInputTriangles;     break;
+        case glslang::ElgQuads:               mode = spv::ExecutionModeInputQuads;         break;
+        case glslang::ElgIsolines:            mode = spv::ExecutionModeInputIsolines;      break;
+        default:                              mode = spv::BadValue;    break;
+        }
+        if (mode != spv::BadValue)
+            builder.addExecutionMode(shaderEntry, (spv::ExecutionMode)mode);
+
+        // TODO
+        //builder.addExecutionMode(spv::VertexSpacingMdName, glslangIntermediate->getVertexSpacing());
+        //builder.addExecutionMode(spv::VertexOrderMdName, glslangIntermediate->getVertexOrder());
+        //builder.addExecutionMode(spv::PointModeMdName, glslangIntermediate->getPointMode());
+        break;
+
+    case EShLangGeometry:
+        switch (glslangIntermediate->getInputPrimitive()) {
+        case glslang::ElgPoints:             mode = spv::ExecutionModeInputPoints;             break;
+        case glslang::ElgLines:              mode = spv::ExecutionModeInputLines;              break;
+        case glslang::ElgLinesAdjacency:     mode = spv::ExecutionModeInputLinesAdjacency;     break;
+        case glslang::ElgTriangles:          mode = spv::ExecutionModeInputTriangles;          break;
+        case glslang::ElgTrianglesAdjacency: mode = spv::ExecutionModeInputTrianglesAdjacency; break;
+        default:                             mode = spv::BadValue;         break;
+        }
+        if (mode != spv::BadValue)
+            builder.addExecutionMode(shaderEntry, (spv::ExecutionMode)mode);
+        builder.addExecutionMode(shaderEntry, spv::ExecutionModeInvocations, glslangIntermediate->getInvocations());
+
+        switch (glslangIntermediate->getOutputPrimitive()) {
+        case glslang::ElgPoints:        mode = spv::ExecutionModeOutputPoints;                 break;
+        case glslang::ElgLineStrip:     mode = spv::ExecutionModeOutputLineStrip;              break;
+        case glslang::ElgTriangleStrip: mode = spv::ExecutionModeOutputTriangleStrip;          break;
+        default:                        mode = spv::BadValue;              break;
+        }
+        if (mode != spv::BadValue)
+            builder.addExecutionMode(shaderEntry, (spv::ExecutionMode)mode);
+        builder.addExecutionMode(shaderEntry, spv::ExecutionModeOutputVertices, glslangIntermediate->getVertices());
+        break;
+
+    case EShLangFragment:
+        if (glslangIntermediate->getPixelCenterInteger())
+            builder.addExecutionMode(shaderEntry, spv::ExecutionModePixelCenterInteger);
+        if (glslangIntermediate->getOriginUpperLeft())
+            builder.addExecutionMode(shaderEntry, spv::ExecutionModeOriginUpperLeft);
+        break;
+
+    case EShLangCompute:
+        break;
+
+    default:
+        break;
+    }
+
+}
+
+TGlslangToSpvTraverser::~TGlslangToSpvTraverser()
+{
+    if (! mainTerminated) {
+        spv::Block* lastMainBlock = shaderEntry->getLastBlock();
+        builder.setBuildPoint(lastMainBlock);
+        builder.leaveFunction(true);
+    }
+}
+
+//
+// Implement the traversal functions.
+//
+// Return true from interior nodes to have the external traversal
+// continue on to children.  Return false if children were
+// already processed.
+//
+
+//
+// Symbols can turn into 
+//  - uniform/input reads
+//  - output writes
+//  - complex lvalue base setups:  foo.bar[3]....  , where we see foo and start up an access chain
+//  - something simple that degenerates into the last bullet
+//
+void TGlslangToSpvTraverser::visitSymbol(glslang::TIntermSymbol* symbol)
+{
+    // getSymbolId() will set up all the IO decorations on the first call.
+    // Formal function parameters were mapped during makeFunctions().
+    spv::Id id = getSymbolId(symbol);
+    
+    if (! linkageOnly) {
+        // Prepare to generate code for the access
+
+        // L-value chains will be computed left to right.  We're on the symbol now,
+        // which is the left-most part of the access chain, so now is "clear" time,
+        // followed by setting the base.
+        builder.clearAccessChain();
+
+        // For now, we consider all user variables as being in memory, so they are pointers,
+        // except for "const in" arguments to a function, which are an intermediate object.
+        // See comments in handleUserFunctionCall().
+        glslang::TStorageQualifier qualifier = symbol->getQualifier().storage;
+        if (qualifier == glslang::EvqConstReadOnly && constReadOnlyParameters.find(symbol->getId()) != constReadOnlyParameters.end())
+            builder.setAccessChainRValue(id);
+        else
+            builder.setAccessChainLValue(id);
+    }
+}
+
+bool TGlslangToSpvTraverser::visitBinary(glslang::TVisit /* visit */, glslang::TIntermBinary* node)
+{
+    // First, handle special cases
+    switch (node->getOp()) {
+    case glslang::EOpAssign:
+    case glslang::EOpAddAssign:
+    case glslang::EOpSubAssign:
+    case glslang::EOpMulAssign:
+    case glslang::EOpVectorTimesMatrixAssign:
+    case glslang::EOpVectorTimesScalarAssign:
+    case glslang::EOpMatrixTimesScalarAssign:
+    case glslang::EOpMatrixTimesMatrixAssign:
+    case glslang::EOpDivAssign:
+    case glslang::EOpModAssign:
+    case glslang::EOpAndAssign:
+    case glslang::EOpInclusiveOrAssign:
+    case glslang::EOpExclusiveOrAssign:
+    case glslang::EOpLeftShiftAssign:
+    case glslang::EOpRightShiftAssign:
+        // A bin-op assign "a += b" means the same thing as "a = a + b"
+        // where a is evaluated before b. For a simple assignment, GLSL
+        // says to evaluate the left before the right.  So, always, left
+        // node then right node.
+        {
+            // get the left l-value, save it away
+            builder.clearAccessChain();
+            node->getLeft()->traverse(this);
+            spv::Builder::AccessChain lValue = builder.getAccessChain();
+
+            // evaluate the right
+            builder.clearAccessChain();
+            node->getRight()->traverse(this);
+            spv::Id rValue = builder.accessChainLoad(TranslatePrecisionDecoration(node->getRight()->getType()));
+
+            if (node->getOp() != glslang::EOpAssign) {
+                // the left is also an r-value
+                builder.setAccessChain(lValue);
+                spv::Id leftRValue = builder.accessChainLoad(TranslatePrecisionDecoration(node->getLeft()->getType()));
+
+                // do the operation
+                rValue = createBinaryOperation(node->getOp(), TranslatePrecisionDecoration(node->getType()), 
+                                               convertGlslangToSpvType(node->getType()), leftRValue, rValue,
+                                               node->getType().getBasicType());
+
+                // these all need their counterparts in createBinaryOperation()
+                if (rValue == 0)
+                    spv::MissingFunctionality("createBinaryOperation");
+            }
+
+            // store the result
+            builder.setAccessChain(lValue);
+            builder.accessChainStore(rValue);
+
+            // assignments are expressions having an rValue after they are evaluated...
+            builder.clearAccessChain();
+            builder.setAccessChainRValue(rValue);
+        }
+        return false;
+    case glslang::EOpIndexDirect:
+    case glslang::EOpIndexDirectStruct:
+        {
+            // Get the left part of the access chain.
+            node->getLeft()->traverse(this);
+
+            // Add the next element in the chain
+
+            int index = 0;
+            if (node->getRight()->getAsConstantUnion() == 0)
+                spv::MissingFunctionality("direct index without a constant node");
+            else 
+                index = node->getRight()->getAsConstantUnion()->getConstArray()[0].getIConst();
+
+            if (node->getLeft()->getBasicType() == glslang::EbtBlock && node->getOp() == glslang::EOpIndexDirectStruct) {
+                // This may be, e.g., an anonymous block-member selection, which generally need
+                // index remapping due to hidden members in anonymous blocks.
+                std::vector<int>& remapper = memberRemapper[node->getLeft()->getType().getStruct()];
+                if (remapper.size() == 0)
+                    spv::MissingFunctionality("block without member remapping");
+                else
+                    index = remapper[index];
+            }
+
+            if (! node->getLeft()->getType().isArray() &&
+                node->getLeft()->getType().isVector() &&
+                node->getOp() == glslang::EOpIndexDirect) {
+                // This is essentially a hard-coded vector swizzle of size 1,
+                // so short circuit the access-chain stuff with a swizzle.
+                std::vector<unsigned> swizzle;
+                swizzle.push_back(node->getRight()->getAsConstantUnion()->getConstArray()[0].getIConst());
+                builder.accessChainPushSwizzle(swizzle);
+            } else {
+                // normal case for indexing array or structure or block
+                builder.accessChainPush(builder.makeIntConstant(index), convertGlslangToSpvType(node->getType()));
+            }
+        }
+        return false;
+    case glslang::EOpIndexIndirect:
+        {
+            // Structure or array or vector indirection.
+            // Will use native SPIR-V access-chain for struct and array indirection;
+            // matrices are arrays of vectors, so will also work for a matrix.
+            // Will use the access chain's 'component' for variable index into a vector.
+
+            // This adapter is building access chains left to right.
+            // Set up the access chain to the left.
+            node->getLeft()->traverse(this);
+
+            // save it so that computing the right side doesn't trash it
+            spv::Builder::AccessChain partial = builder.getAccessChain();
+
+            // compute the next index in the chain
+            builder.clearAccessChain();
+            node->getRight()->traverse(this);
+            spv::Id index = builder.accessChainLoad(TranslatePrecisionDecoration(node->getRight()->getType()));
+
+            // restore the saved access chain
+            builder.setAccessChain(partial);
+
+            if (! node->getLeft()->getType().isArray() && node->getLeft()->getType().isVector())
+                builder.accessChainPushComponent(index);
+            else
+                builder.accessChainPush(index, convertGlslangToSpvType(node->getType()));
+        }
+        return false;
+    case glslang::EOpVectorSwizzle:
+        {
+            node->getLeft()->traverse(this);
+            glslang::TIntermSequence& swizzleSequence = node->getRight()->getAsAggregate()->getSequence();
+            std::vector<unsigned> swizzle;
+            for (int i = 0; i < (int)swizzleSequence.size(); ++i)
+                swizzle.push_back(swizzleSequence[i]->getAsConstantUnion()->getConstArray()[0].getIConst());
+            builder.accessChainPushSwizzle(swizzle);
+        }
+        return false;
+    default:
+        break;
+    }
+
+    // Assume generic binary op...
+
+    // Get the operands
+    builder.clearAccessChain();
+    node->getLeft()->traverse(this);
+    spv::Id left = builder.accessChainLoad(TranslatePrecisionDecoration(node->getLeft()->getType()));
+
+    builder.clearAccessChain();
+    node->getRight()->traverse(this);
+    spv::Id right = builder.accessChainLoad(TranslatePrecisionDecoration(node->getRight()->getType()));
+
+    spv::Id result;
+    spv::Decoration precision = TranslatePrecisionDecoration(node->getType());
+
+    result = createBinaryOperation(node->getOp(), precision, 
+                                   convertGlslangToSpvType(node->getType()), left, right,
+                                   node->getLeft()->getType().getBasicType());
+
+    if (! result) {
+        spv::MissingFunctionality("glslang binary operation");
+    } else {
+        builder.clearAccessChain();
+        builder.setAccessChainRValue(result);
+
+        return false;
+    }
+
+    return true;
+}
+
+bool TGlslangToSpvTraverser::visitUnary(glslang::TVisit /* visit */, glslang::TIntermUnary* node)
+{
+    builder.clearAccessChain();
+    node->getOperand()->traverse(this);
+    spv::Id operand = builder.accessChainLoad(TranslatePrecisionDecoration(node->getOperand()->getType()));
+
+    spv::Decoration precision = TranslatePrecisionDecoration(node->getType());
+
+    // it could be a conversion
+    spv::Id result = createConversion(node->getOp(), precision, convertGlslangToSpvType(node->getType()), operand);
+
+    // if not, then possibly an operation
+    if (! result)
+        result = createUnaryOperation(node->getOp(), precision, convertGlslangToSpvType(node->getType()), operand, node->getBasicType() == glslang::EbtFloat || node->getBasicType() == glslang::EbtDouble);
+
+    if (result) {
+        builder.clearAccessChain();
+        builder.setAccessChainRValue(result);
+
+        return false; // done with this node
+    }
+
+    // it must be a special case, check...
+    switch (node->getOp()) {
+    case glslang::EOpPostIncrement:
+    case glslang::EOpPostDecrement:
+    case glslang::EOpPreIncrement:
+    case glslang::EOpPreDecrement:
+        {
+            // we need the integer value "1" or the floating point "1.0" to add/subtract
+            spv::Id one = node->getBasicType() == glslang::EbtFloat ?
+                                     builder.makeFloatConstant(1.0F) :
+                                     builder.makeIntConstant(1);
+            glslang::TOperator op;
+            if (node->getOp() == glslang::EOpPreIncrement ||
+                node->getOp() == glslang::EOpPostIncrement)
+                op = glslang::EOpAdd;
+            else
+                op = glslang::EOpSub;
+
+            spv::Id result = createBinaryOperation(op, TranslatePrecisionDecoration(node->getType()), 
+                                                     convertGlslangToSpvType(node->getType()), operand, one, 
+                                                     node->getType().getBasicType());
+            if (result == 0)
+                spv::MissingFunctionality("createBinaryOperation for unary");
+
+            // The result of operation is always stored, but conditionally the
+            // consumed result.  The consumed result is always an r-value.
+            builder.accessChainStore(result);
+            builder.clearAccessChain();
+            if (node->getOp() == glslang::EOpPreIncrement ||
+                node->getOp() == glslang::EOpPreDecrement)
+                builder.setAccessChainRValue(result);
+            else
+                builder.setAccessChainRValue(operand);
+        }
+
+        return false;
+
+    case glslang::EOpEmitStreamVertex:
+        builder.createNoResultOp(spv::OpEmitStreamVertex, operand);
+        return false;
+    case glslang::EOpEndStreamPrimitive:
+        builder.createNoResultOp(spv::OpEndStreamPrimitive, operand);
+        return false;
+
+    default:
+        spv::MissingFunctionality("glslang unary");
+        break;
+    }
+
+    return true;
+}
+
+bool TGlslangToSpvTraverser::visitAggregate(glslang::TVisit visit, glslang::TIntermAggregate* node)
+{
+    spv::Id result;
+    glslang::TOperator binOp = glslang::EOpNull;
+    bool reduceComparison = true;
+    bool isMatrix = false;
+    bool noReturnValue = false;
+
+    assert(node->getOp());
+
+    spv::Decoration precision = TranslatePrecisionDecoration(node->getType());
+
+    switch (node->getOp()) {
+    case glslang::EOpSequence:
+    {
+        if (preVisit)
+            ++sequenceDepth;
+        else
+            --sequenceDepth;
+
+        if (sequenceDepth == 1) {
+            // If this is the parent node of all the functions, we want to see them
+            // early, so all call points have actual SPIR-V functions to reference.
+            // In all cases, still let the traverser visit the children for us.
+            makeFunctions(node->getAsAggregate()->getSequence());
+
+            // Also, we want all globals initializers to go into the entry of main(), before
+            // anything else gets there, so visit out of order, doing them all now.
+            makeGlobalInitializers(node->getAsAggregate()->getSequence());
+
+            // Initializers are done, don't want to visit again, but functions link objects need to be processed,
+            // so do them manually.
+            visitFunctions(node->getAsAggregate()->getSequence());
+
+            return false;
+        }
+
+        return true;
+    }
+    case glslang::EOpLinkerObjects:
+    {
+        if (visit == glslang::EvPreVisit)
+            linkageOnly = true;
+        else
+            linkageOnly = false;
+
+        return true;
+    }
+    case glslang::EOpComma:
+    {
+        // processing from left to right naturally leaves the right-most
+        // lying around in the access chain
+        glslang::TIntermSequence& glslangOperands = node->getSequence();
+        for (int i = 0; i < (int)glslangOperands.size(); ++i)
+            glslangOperands[i]->traverse(this);
+
+        return false;
+    }
+    case glslang::EOpFunction:
+        if (visit == glslang::EvPreVisit) {
+            if (isShaderEntrypoint(node)) {
+                inMain = true;
+                builder.setBuildPoint(shaderEntry->getLastBlock());
+            } else {
+                handleFunctionEntry(node);
+            }
+        } else {
+            if (inMain)
+                mainTerminated = true;
+            builder.leaveFunction(inMain);
+            inMain = false;
+        }
+
+        return true;
+    case glslang::EOpParameters:
+        // Parameters will have been consumed by EOpFunction processing, but not
+        // the body, so we still visited the function node's children, making this
+        // child redundant.
+        return false;
+    case glslang::EOpFunctionCall:
+    {
+        if (node->isUserDefined())
+            result = handleUserFunctionCall(node);
+        else
+            result = handleBuiltInFunctionCall(node);
+
+        if (! result) {
+            spv::MissingFunctionality("glslang function call");
+            glslang::TConstUnionArray emptyConsts;
+            int nextConst = 0;
+            result = createSpvConstant(node->getType(), emptyConsts, nextConst);
+        }
+        builder.clearAccessChain();
+        builder.setAccessChainRValue(result);
+
+        return false;
+    }
+    case glslang::EOpConstructMat2x2:
+    case glslang::EOpConstructMat2x3:
+    case glslang::EOpConstructMat2x4:
+    case glslang::EOpConstructMat3x2:
+    case glslang::EOpConstructMat3x3:
+    case glslang::EOpConstructMat3x4:
+    case glslang::EOpConstructMat4x2:
+    case glslang::EOpConstructMat4x3:
+    case glslang::EOpConstructMat4x4:
+    case glslang::EOpConstructDMat2x2:
+    case glslang::EOpConstructDMat2x3:
+    case glslang::EOpConstructDMat2x4:
+    case glslang::EOpConstructDMat3x2:
+    case glslang::EOpConstructDMat3x3:
+    case glslang::EOpConstructDMat3x4:
+    case glslang::EOpConstructDMat4x2:
+    case glslang::EOpConstructDMat4x3:
+    case glslang::EOpConstructDMat4x4:
+        isMatrix = true;
+        // fall through
+    case glslang::EOpConstructFloat:
+    case glslang::EOpConstructVec2:
+    case glslang::EOpConstructVec3:
+    case glslang::EOpConstructVec4:
+    case glslang::EOpConstructDouble:
+    case glslang::EOpConstructDVec2:
+    case glslang::EOpConstructDVec3:
+    case glslang::EOpConstructDVec4:
+    case glslang::EOpConstructBool:
+    case glslang::EOpConstructBVec2:
+    case glslang::EOpConstructBVec3:
+    case glslang::EOpConstructBVec4:
+    case glslang::EOpConstructInt:
+    case glslang::EOpConstructIVec2:
+    case glslang::EOpConstructIVec3:
+    case glslang::EOpConstructIVec4:
+    case glslang::EOpConstructUint:
+    case glslang::EOpConstructUVec2:
+    case glslang::EOpConstructUVec3:
+    case glslang::EOpConstructUVec4:
+    case glslang::EOpConstructStruct:
+    {
+        std::vector<spv::Id> arguments;
+        translateArguments(node->getSequence(), arguments);
+        spv::Id resultTypeId = convertGlslangToSpvType(node->getType());
+        spv::Id constructed;
+        if (node->getOp() == glslang::EOpConstructStruct || node->getType().isArray()) {
+            std::vector<spv::Id> constituents;
+            for (int c = 0; c < (int)arguments.size(); ++c)
+                constituents.push_back(arguments[c]);
+            constructed = builder.createCompositeConstruct(resultTypeId, constituents);
+        } else {
+            if (isMatrix)
+                constructed = builder.createMatrixConstructor(precision, arguments, resultTypeId);
+            else
+                constructed = builder.createConstructor(precision, arguments, resultTypeId);
+        }
+
+        builder.clearAccessChain();
+        builder.setAccessChainRValue(constructed);
+
+        return false;
+    }
+
+    // These six are component-wise compares with component-wise results.
+    // Forward on to createBinaryOperation(), requesting a vector result.
+    case glslang::EOpLessThan:
+    case glslang::EOpGreaterThan:
+    case glslang::EOpLessThanEqual:
+    case glslang::EOpGreaterThanEqual:
+    case glslang::EOpVectorEqual:
+    case glslang::EOpVectorNotEqual:
+    {
+        // Map the operation to a binary
+        binOp = node->getOp();
+        reduceComparison = false;
+        switch (node->getOp()) {
+        case glslang::EOpVectorEqual:     binOp = glslang::EOpVectorEqual;      break;
+        case glslang::EOpVectorNotEqual:  binOp = glslang::EOpVectorNotEqual;   break;
+        default:                          binOp = node->getOp();                break;
+        }
+
+        break;
+    }
+    case glslang::EOpMul:
+        // compontent-wise matrix multiply      
+        binOp = glslang::EOpMul;
+        break;
+    case glslang::EOpOuterProduct:
+        // two vectors multiplied to make a matrix
+        binOp = glslang::EOpOuterProduct;
+        break;
+    case glslang::EOpDot:
+    {
+        // for scalar dot product, use multiply        
+        glslang::TIntermSequence& glslangOperands = node->getSequence();
+        if (! glslangOperands[0]->getAsTyped()->isVector())
+            binOp = glslang::EOpMul;
+        break;
+    }
+    case glslang::EOpMod:
+        // when an aggregate, this is the floating-point mod built-in function,
+        // which can be emitted by the one in createBinaryOperation()
+        binOp = glslang::EOpMod;
+        break;
+    case glslang::EOpArrayLength:
+    {
+        glslang::TIntermTyped* typedNode = node->getSequence()[0]->getAsTyped();
+        assert(typedNode);
+        spv::Id length = builder.makeIntConstant(typedNode->getType().getArraySize());
+
+        builder.clearAccessChain();
+        builder.setAccessChainRValue(length);
+
+        return false;
+    }
+    case glslang::EOpEmitVertex:
+    case glslang::EOpEndPrimitive:
+    case glslang::EOpBarrier:
+    case glslang::EOpMemoryBarrier:
+    case glslang::EOpMemoryBarrierAtomicCounter:
+    case glslang::EOpMemoryBarrierBuffer:
+    case glslang::EOpMemoryBarrierImage:
+    case glslang::EOpMemoryBarrierShared:
+    case glslang::EOpGroupMemoryBarrier:
+        noReturnValue = true;
+        // These all have 0 operands and will naturally finish up in the code below for 0 operands
+        break;
+
+    default:
+        break;
+    }
+
+    //
+    // See if it maps to a regular operation.
+    //
+
+    if (binOp != glslang::EOpNull) {
+        glslang::TIntermTyped* left = node->getSequence()[0]->getAsTyped();
+        glslang::TIntermTyped* right = node->getSequence()[1]->getAsTyped();
+        assert(left && right);
+
+        builder.clearAccessChain();
+        left->traverse(this);
+        spv::Id leftId = builder.accessChainLoad(TranslatePrecisionDecoration(left->getType()));
+
+        builder.clearAccessChain();
+        right->traverse(this);
+        spv::Id rightId = builder.accessChainLoad(TranslatePrecisionDecoration(right->getType()));
+
+        result = createBinaryOperation(binOp, precision, 
+                                       convertGlslangToSpvType(node->getType()), leftId, rightId, 
+                                       left->getType().getBasicType(), reduceComparison);
+
+        // code above should only make binOp that exists in createBinaryOperation
+        if (result == 0)
+            spv::MissingFunctionality("createBinaryOperation for aggregate");
+
+        builder.clearAccessChain();
+        builder.setAccessChainRValue(result);
+
+        return false;
+    }
+
+    glslang::TIntermSequence& glslangOperands = node->getSequence();
+    std::vector<spv::Id> operands;
+    for (int arg = 0; arg < (int)glslangOperands.size(); ++arg) {
+        builder.clearAccessChain();
+        glslangOperands[arg]->traverse(this);
+
+        // special case l-value operands; there are just a few
+        bool lvalue = false;
+        switch (node->getOp()) {
+        //case glslang::EOpFrexp:
+        case glslang::EOpModf:
+            if (arg == 1)
+                lvalue = true;
+            break;
+        //case glslang::EOpUAddCarry:
+        //case glslang::EOpUSubBorrow:
+        //case glslang::EOpUMulExtended:
+        default:
+            break;
+        }
+        if (lvalue)
+            operands.push_back(builder.accessChainGetLValue());
+        else
+            operands.push_back(builder.accessChainLoad(TranslatePrecisionDecoration(glslangOperands[arg]->getAsTyped()->getType())));
+    }
+    switch (glslangOperands.size()) {
+    case 0:
+        result = createNoArgOperation(node->getOp());
+        break;
+    case 1:
+        result = createUnaryOperation(node->getOp(), precision, convertGlslangToSpvType(node->getType()), operands.front(), node->getType().getBasicType() == glslang::EbtFloat || node->getType().getBasicType() == glslang::EbtDouble);
+        break;
+    default:
+        result = createMiscOperation(node->getOp(), precision, convertGlslangToSpvType(node->getType()), operands);
+        break;
+    }
+
+    if (noReturnValue)
+        return false;
+
+    if (! result) {
+        spv::MissingFunctionality("glslang aggregate");
+        return true;
+    } else {
+        builder.clearAccessChain();
+        builder.setAccessChainRValue(result);
+        return false;
+    }
+}
+
+bool TGlslangToSpvTraverser::visitSelection(glslang::TVisit /* visit */, glslang::TIntermSelection* node)
+{
+    // This path handles both if-then-else and ?:
+    // The if-then-else has a node type of void, while
+    // ?: has a non-void node type
+    spv::Id result = 0;
+    if (node->getBasicType() != glslang::EbtVoid) {
+        // don't handle this as just on-the-fly temporaries, because there will be two names
+        // and better to leave SSA to later passes
+        result = builder.createVariable(spv::StorageClassFunction, convertGlslangToSpvType(node->getType()));
+    }
+
+    // emit the condition before doing anything with selection
+    node->getCondition()->traverse(this);
+
+    // make an "if" based on the value created by the condition
+    spv::Builder::If ifBuilder(builder.accessChainLoad(spv::NoPrecision), builder);
+
+    if (node->getTrueBlock()) {
+        // emit the "then" statement
+        node->getTrueBlock()->traverse(this);
+        if (result)
+            builder.createStore(builder.accessChainLoad(TranslatePrecisionDecoration(node->getTrueBlock()->getAsTyped()->getType())), result);
+    }
+
+    if (node->getFalseBlock()) {
+        ifBuilder.makeBeginElse();
+        // emit the "else" statement
+        node->getFalseBlock()->traverse(this);
+        if (result)
+            builder.createStore(builder.accessChainLoad(TranslatePrecisionDecoration(node->getFalseBlock()->getAsTyped()->getType())), result);
+    }
+
+    ifBuilder.makeEndIf();
+
+    if (result) {
+        // GLSL only has r-values as the result of a :?, but
+        // if we have an l-value, that can be more efficient if it will
+        // become the base of a complex r-value expression, because the
+        // next layer copies r-values into memory to use the access-chain mechanism
+        builder.clearAccessChain();
+        builder.setAccessChainLValue(result);
+    }
+
+    return false;
+}
+
+bool TGlslangToSpvTraverser::visitSwitch(glslang::TVisit /* visit */, glslang::TIntermSwitch* node)
+{
+    // emit and get the condition before doing anything with switch
+    node->getCondition()->traverse(this);
+    spv::Id selector = builder.accessChainLoad(TranslatePrecisionDecoration(node->getCondition()->getAsTyped()->getType()));
+
+    // browse the children to sort out code segments
+    int defaultSegment = -1;
+    std::vector<TIntermNode*> codeSegments;
+    glslang::TIntermSequence& sequence = node->getBody()->getSequence();
+    std::vector<int> caseValues;
+    std::vector<int> valueIndexToSegment(sequence.size());  // note: probably not all are used, it is an overestimate
+    for (glslang::TIntermSequence::iterator c = sequence.begin(); c != sequence.end(); ++c) {
+        TIntermNode* child = *c;
+        if (child->getAsBranchNode() && child->getAsBranchNode()->getFlowOp() == glslang::EOpDefault)
+            defaultSegment = codeSegments.size();
+        else if (child->getAsBranchNode() && child->getAsBranchNode()->getFlowOp() == glslang::EOpCase) {
+            valueIndexToSegment[caseValues.size()] = codeSegments.size();
+            caseValues.push_back(child->getAsBranchNode()->getExpression()->getAsConstantUnion()->getConstArray()[0].getIConst());
+        } else
+            codeSegments.push_back(child);
+    }
+
+    // handle the case where the last code segment is missing, due to no code 
+    // statements between the last case and the end of the switch statement
+    if ((caseValues.size() && (int)codeSegments.size() == valueIndexToSegment[caseValues.size() - 1]) ||
+        (int)codeSegments.size() == defaultSegment)
+        codeSegments.push_back(nullptr);
+
+    // make the switch statement
+    std::vector<spv::Block*> segmentBlocks; // returned, as the blocks allocated in the call
+    builder.makeSwitch(selector, codeSegments.size(), caseValues, valueIndexToSegment, defaultSegment, segmentBlocks);
+
+    // emit all the code in the segments
+    breakForLoop.push(false);
+    for (unsigned int s = 0; s < codeSegments.size(); ++s) {
+        builder.nextSwitchSegment(segmentBlocks, s);
+        if (codeSegments[s])
+            codeSegments[s]->traverse(this);
+        else
+            builder.addSwitchBreak();
+    }
+    breakForLoop.pop();
+
+    builder.endSwitch(segmentBlocks);
+
+    return false;
+}
+
+void TGlslangToSpvTraverser::visitConstantUnion(glslang::TIntermConstantUnion* node)
+{
+    int nextConst = 0;
+    spv::Id constant = createSpvConstant(node->getType(), node->getConstArray(), nextConst);
+
+    builder.clearAccessChain();
+    builder.setAccessChainRValue(constant);
+}
+
+bool TGlslangToSpvTraverser::visitLoop(glslang::TVisit /* visit */, glslang::TIntermLoop* node)
+{
+    // body emission needs to know what the for-loop terminal is when it sees a "continue"
+    loopTerminal.push(node->getTerminal());
+
+    builder.makeNewLoop();
+
+    bool bodyOut = false;
+    if (! node->testFirst()) {
+        builder.endLoopHeaderWithoutTest();
+        if (node->getBody()) {
+            breakForLoop.push(true);
+            node->getBody()->traverse(this);
+            breakForLoop.pop();
+        }
+        bodyOut = true;
+        builder.createBranchToLoopTest();
+    }
+
+    if (node->getTest()) {
+        node->getTest()->traverse(this);
+        // the AST only contained the test computation, not the branch, we have to add it
+        spv::Id condition = builder.accessChainLoad(TranslatePrecisionDecoration(node->getTest()->getType()));
+        builder.createLoopTestBranch(condition);
+    }
+
+    if (! bodyOut && node->getBody()) {
+        breakForLoop.push(true);
+        node->getBody()->traverse(this);
+        breakForLoop.pop();
+    }
+
+    if (loopTerminal.top())
+        loopTerminal.top()->traverse(this);
+
+    builder.closeLoop();
+
+    loopTerminal.pop();
+
+    return false;
+}
+
+bool TGlslangToSpvTraverser::visitBranch(glslang::TVisit /* visit */, glslang::TIntermBranch* node)
+{
+    if (node->getExpression())
+        node->getExpression()->traverse(this);
+
+    switch (node->getFlowOp()) {
+    case glslang::EOpKill:
+        builder.makeDiscard();
+        break;
+    case glslang::EOpBreak:
+        if (breakForLoop.top())
+            builder.createLoopExit();
+        else
+            builder.addSwitchBreak();
+        break;
+    case glslang::EOpContinue:
+        if (loopTerminal.top())
+            loopTerminal.top()->traverse(this);
+        builder.createLoopContinue();
+        break;
+    case glslang::EOpReturn:
+        if (inMain)
+            builder.makeMainReturn();
+        else if (node->getExpression())
+            builder.makeReturn(false, builder.accessChainLoad(TranslatePrecisionDecoration(node->getExpression()->getType())));
+        else
+            builder.makeReturn();
+
+        builder.clearAccessChain();
+        break;
+
+    default:
+        spv::MissingFunctionality("branch type");
+        break;
+    }
+
+    return false;
+}
+
+spv::Id TGlslangToSpvTraverser::createSpvVariable(const glslang::TIntermSymbol* node)
+{
+    // First, steer off constants, which are not SPIR-V variables, but 
+    // can still have a mapping to a SPIR-V Id.
+    if (node->getQualifier().storage == glslang::EvqConst) {
+        int nextConst = 0;
+        return createSpvConstant(node->getType(), node->getConstArray(), nextConst);
+    }
+
+    // Now, handle actual variables
+    spv::StorageClass storageClass = TranslateStorageClass(node->getType());
+    spv::Id spvType = convertGlslangToSpvType(node->getType());
+
+    const char* name = node->getName().c_str();
+    if (glslang::IsAnonymous(name))
+        name = "";
+
+    return builder.createVariable(storageClass, spvType, name);
+}
+
+// Return type Id of the sampled type.
+spv::Id TGlslangToSpvTraverser::getSampledType(const glslang::TSampler& sampler)
+{
+    switch (sampler.type) {
+        case glslang::EbtFloat:    return builder.makeFloatType(32);
+        case glslang::EbtInt:      return builder.makeIntType(32);
+        case glslang::EbtUint:     return builder.makeUintType(32);
+        default:
+            spv::MissingFunctionality("sampled type");
+            return builder.makeFloatType(32);
+    }
+}
+
+// Do full recursive conversion of an arbitrary glslang type to a SPIR-V Id.
+spv::Id TGlslangToSpvTraverser::convertGlslangToSpvType(const glslang::TType& type)
+{
+    spv::Id spvType = 0;
+
+    switch (type.getBasicType()) {
+    case glslang::EbtVoid:
+        spvType = builder.makeVoidType();
+        if (type.isArray())
+            spv::MissingFunctionality("array of void");
+        break;
+    case glslang::EbtFloat:
+        spvType = builder.makeFloatType(32);
+        break;
+    case glslang::EbtDouble:
+        spvType = builder.makeFloatType(64);
+        break;
+    case glslang::EbtBool:
+        spvType = builder.makeBoolType();
+        break;
+    case glslang::EbtInt:
+        spvType = builder.makeIntType(32);
+        break;
+    case glslang::EbtUint:
+        spvType = builder.makeUintType(32);
+        break;
+    case glslang::EbtSampler:
+        {
+            const glslang::TSampler& sampler = type.getSampler();
+            spvType = builder.makeSampler(getSampledType(sampler), TranslateDimensionality(sampler), 
+                                          sampler.image ? spv::Builder::samplerContentImage : spv::Builder::samplerContentTextureFilter,
+                                          sampler.arrayed, sampler.shadow, sampler.ms);
+        }
+        break;
+    case glslang::EbtStruct:
+    case glslang::EbtBlock:
+        {
+            // If we've seen this struct type, return it
+            const glslang::TTypeList* glslangStruct = type.getStruct();
+            std::vector<spv::Id> structFields;
+            spvType = structMap[glslangStruct];
+            if (spvType)
+                break;
+
+            // else, we haven't seen it...
+
+            // Create a vector of struct types for SPIR-V to consume
+            int memberDelta = 0;  // how much the member's index changes from glslang to SPIR-V, normally 0, except sometimes for blocks
+            if (type.getBasicType() == glslang::EbtBlock)
+                memberRemapper[glslangStruct].resize(glslangStruct->size());
+            for (int i = 0; i < (int)glslangStruct->size(); i++) {
+                glslang::TType& glslangType = *(*glslangStruct)[i].type;
+                if (glslangType.hiddenMember()) {
+                    ++memberDelta;
+                    if (type.getBasicType() == glslang::EbtBlock)
+                        memberRemapper[glslangStruct][i] = -1;
+                } else {
+                    if (type.getBasicType() == glslang::EbtBlock)
+                        memberRemapper[glslangStruct][i] = i - memberDelta;
+                    structFields.push_back(convertGlslangToSpvType(glslangType));
+                }
+            }
+
+            // Make the SPIR-V type
+            spvType = builder.makeStructType(structFields, type.getTypeName().c_str());
+            structMap[glslangStruct] = spvType;
+
+            // Name and decorate the non-hidden members
+            for (int i = 0; i < (int)glslangStruct->size(); i++) {
+                glslang::TType& glslangType = *(*glslangStruct)[i].type;
+                int member = i;
+                if (type.getBasicType() == glslang::EbtBlock)
+                    member = memberRemapper[glslangStruct][i];
+                // using -1 above to indicate a hidden member
+                if (member >= 0) {
+                    builder.addMemberName(spvType, member, glslangType.getFieldName().c_str());
+                    addMemberDecoration(spvType, member, TranslateLayoutDecoration(glslangType));
+                    addMemberDecoration(spvType, member, TranslatePrecisionDecoration(glslangType));
+                    addMemberDecoration(spvType, member, TranslateInterpolationDecoration(glslangType));
+                    addMemberDecoration(spvType, member, TranslateInvariantDecoration(glslangType));
+                    if (glslangType.getQualifier().hasLocation())
+                        builder.addMemberDecoration(spvType, member, spv::DecorationLocation, glslangType.getQualifier().layoutLocation);
+                    if (glslangType.getQualifier().hasComponent())
+                        builder.addMemberDecoration(spvType, member, spv::DecorationComponent, glslangType.getQualifier().layoutComponent);
+                    if (glslangType.getQualifier().hasXfbOffset())
+                        builder.addMemberDecoration(spvType, member, spv::DecorationOffset, glslangType.getQualifier().layoutXfbOffset);
+
+                    // built-in variable decorations
+                    int builtIn = TranslateBuiltInDecoration(glslangType.getQualifier().builtIn);
+                    if (builtIn != spv::BadValue)
+                        builder.addMemberDecoration(spvType, member, spv::DecorationBuiltIn, builtIn);
+                }
+            }
+
+            // Decorate the structure
+            addDecoration(spvType, TranslateLayoutDecoration(type));
+            addDecoration(spvType, TranslateBlockDecoration(type));
+            if (type.getQualifier().hasStream())
+                builder.addDecoration(spvType, spv::DecorationStream, type.getQualifier().layoutStream);
+            if (glslangIntermediate->getXfbMode()) {
+                if (type.getQualifier().hasXfbStride())
+                    builder.addDecoration(spvType, spv::DecorationStride, type.getQualifier().layoutXfbStride);
+                if (type.getQualifier().hasXfbBuffer())
+                    builder.addDecoration(spvType, spv::DecorationXfbBuffer, type.getQualifier().layoutXfbBuffer);
+            }
+        }
+        break;
+    default:
+        spv::MissingFunctionality("basic type");
+        break;
+    }
+
+    if (type.isMatrix())
+        spvType = builder.makeMatrixType(spvType, type.getMatrixCols(), type.getMatrixRows());
+    else {
+        // If this variable has a vector element count greater than 1, create a SPIR-V vector
+        if (type.getVectorSize() > 1)
+            spvType = builder.makeVectorType(spvType, type.getVectorSize());
+    }
+
+    if (type.isArray()) {
+        unsigned arraySize;
+        if (! type.isExplicitlySizedArray()) {
+            spv::MissingFunctionality("Unsized array");
+            arraySize = 8;
+        } else
+            arraySize = type.getArraySize();
+        spvType = builder.makeArrayType(spvType, arraySize);
+    }
+
+    return spvType;
+}
+
+bool TGlslangToSpvTraverser::isShaderEntrypoint(const glslang::TIntermAggregate* node)
+{
+    return node->getName() == "main(";
+}
+
+// Make all the functions, skeletally, without actually visiting their bodies.
+void TGlslangToSpvTraverser::makeFunctions(const glslang::TIntermSequence& glslFunctions)
+{
+    for (int f = 0; f < (int)glslFunctions.size(); ++f) {
+        glslang::TIntermAggregate* glslFunction = glslFunctions[f]->getAsAggregate();
+        if (! glslFunction || glslFunction->getOp() != glslang::EOpFunction || isShaderEntrypoint(glslFunction))
+            continue;
+
+        // We're on a user function.  Set up the basic interface for the function now,
+        // so that it's available to call.
+        // Translating the body will happen later.
+        //
+        // Typically (except for a "const in" parameter), an address will be passed to the 
+        // function.  What it is an address of varies:
+        //
+        // - "in" parameters not marked as "const" can be written to without modifying the argument,
+        //  so that write needs to be to a copy, hence the address of a copy works.
+        //
+        // - "const in" parameters can just be the r-value, as no writes need occur.
+        //
+        // - "out" and "inout" arguments can't be done as direct pointers, because GLSL has
+        // copy-in/copy-out semantics.  They can be handled though with a pointer to a copy.
+
+        std::vector<spv::Id> paramTypes;
+        glslang::TIntermSequence& parameters = glslFunction->getSequence()[0]->getAsAggregate()->getSequence();
+
+        for (int p = 0; p < (int)parameters.size(); ++p) {
+            const glslang::TType& paramType = parameters[p]->getAsTyped()->getType();
+            spv::Id typeId = convertGlslangToSpvType(paramType);
+            if (paramType.getQualifier().storage != glslang::EvqConstReadOnly)
+                typeId = builder.makePointer(spv::StorageClassFunction, typeId);
+            else
+                constReadOnlyParameters.insert(parameters[p]->getAsSymbolNode()->getId());
+            paramTypes.push_back(typeId);
+        }
+
+        spv::Block* functionBlock;
+        spv::Function *function = builder.makeFunctionEntry(convertGlslangToSpvType(glslFunction->getType()), glslFunction->getName().c_str(),
+                                                              paramTypes, &functionBlock);
+
+        // Track function to emit/call later
+        functionMap[glslFunction->getName().c_str()] = function;
+
+        // Set the parameter id's
+        for (int p = 0; p < (int)parameters.size(); ++p) {
+            symbolValues[parameters[p]->getAsSymbolNode()->getId()] = function->getParamId(p);
+            // give a name too
+            builder.addName(function->getParamId(p), parameters[p]->getAsSymbolNode()->getName().c_str());
+        }
+    }
+}
+
+// Process all the initializers, while skipping the functions and link objects
+void TGlslangToSpvTraverser::makeGlobalInitializers(const glslang::TIntermSequence& initializers)
+{
+    builder.setBuildPoint(shaderEntry->getLastBlock());
+    for (int i = 0; i < (int)initializers.size(); ++i) {
+        glslang::TIntermAggregate* initializer = initializers[i]->getAsAggregate();
+        if (initializer && initializer->getOp() != glslang::EOpFunction && initializer->getOp() != glslang::EOpLinkerObjects) {
+
+            // We're on a top-level node that's not a function.  Treat as an initializer, whose
+            // code goes into the beginning of main.
+            initializer->traverse(this);
+        }
+    }
+}
+
+// Process all the functions, while skipping initializers.
+void TGlslangToSpvTraverser::visitFunctions(const glslang::TIntermSequence& glslFunctions)
+{
+    for (int f = 0; f < (int)glslFunctions.size(); ++f) {
+        glslang::TIntermAggregate* node = glslFunctions[f]->getAsAggregate();
+        if (node && (node->getOp() == glslang::EOpFunction || node->getOp() == glslang ::EOpLinkerObjects))
+            node->traverse(this);
+    }
+}
+
+void TGlslangToSpvTraverser::handleFunctionEntry(const glslang::TIntermAggregate* node)
+{
+    // SPIR-V functions should already be in the functionMap from the prepass 
+    // that called makeFunctions().
+    spv::Function* function = functionMap[node->getName().c_str()];
+    spv::Block* functionBlock = function->getEntryBlock();
+    builder.setBuildPoint(functionBlock);
+}
+
+void TGlslangToSpvTraverser::translateArguments(const glslang::TIntermSequence& glslangArguments, std::vector<spv::Id>& arguments)
+{
+    for (int i = 0; i < (int)glslangArguments.size(); ++i) {
+        builder.clearAccessChain();
+        glslangArguments[i]->traverse(this);
+        arguments.push_back(builder.accessChainLoad(TranslatePrecisionDecoration(glslangArguments[i]->getAsTyped()->getType())));
+    }
+}
+
+spv::Id TGlslangToSpvTraverser::handleBuiltInFunctionCall(const glslang::TIntermAggregate* node)
+{
+    std::vector<spv::Id> arguments;
+    translateArguments(node->getSequence(), arguments);
+
+    std::vector<spv::Id> argTypes;
+    for (int a = 0; a < (int)arguments.size(); ++a)
+        argTypes.push_back(builder.getTypeId(arguments[a]));
+
+    spv::Decoration precision = TranslatePrecisionDecoration(node->getType());
+
+    if (node->getName() == "ftransform(") {
+        spv::MissingFunctionality("ftransform()");
+        //spv::Id vertex = builder.createVariable(spv::StorageShaderGlobal, spv::VectorType::get(spv::makeFloatType(), 4),
+        //                                                             "gl_Vertex_sim");
+        //spv::Id matrix = builder.createVariable(spv::StorageShaderGlobal, spv::VectorType::get(spv::makeFloatType(), 4),
+        //                                                             "gl_ModelViewProjectionMatrix_sim");
+        return 0;
+    }
+
+    if (node->getName().substr(0, 7) == "texture" || node->getName().substr(0, 5) == "texel" || node->getName().substr(0, 6) == "shadow") {
+        const glslang::TSampler sampler = node->getSequence()[0]->getAsTyped()->getType().getSampler();
+        spv::Builder::TextureParameters params = { };
+        params.sampler = arguments[0];
+
+        // special case size query
+        if (node->getName().find("textureSize", 0) != std::string::npos) {
+            if (arguments.size() > 1) {
+                params.lod = arguments[1];
+                return builder.createTextureQueryCall(spv::OpTextureQuerySizeLod, params);
+            } else
+                return builder.createTextureQueryCall(spv::OpTextureQuerySize, params);
+        }
+
+        // special case the number of samples query
+        if (node->getName().find("textureSamples", 0) != std::string::npos)
+            return builder.createTextureQueryCall(spv::OpTextureQuerySamples, params);
+
+        // special case the other queries
+        if (node->getName().find("Query", 0) != std::string::npos) {
+            if (node->getName().find("Levels", 0) != std::string::npos)
+                return builder.createTextureQueryCall(spv::OpTextureQueryLevels, params);
+            else if (node->getName().find("Lod", 0) != std::string::npos) {
+                params.coords = arguments[1];
+                return builder.createTextureQueryCall(spv::OpTextureQueryLod, params);
+            } else
+                spv::MissingFunctionality("glslang texture query");
+        }
+
+        // This is no longer a query....
+
+        bool lod = node->getName().find("Lod", 0) != std::string::npos;
+        bool proj = node->getName().find("Proj", 0) != std::string::npos;
+        bool offsets = node->getName().find("Offsets", 0) != std::string::npos;
+        bool offset = ! offsets && node->getName().find("Offset", 0) != std::string::npos;
+        bool fetch = node->getName().find("Fetch", 0) != std::string::npos;
+        bool gather = node->getName().find("Gather", 0) != std::string::npos;
+        bool grad = node->getName().find("Grad", 0) != std::string::npos;
+
+        if (fetch)
+            spv::MissingFunctionality("texel fetch");
+        if (gather)
+            spv::MissingFunctionality("texture gather");
+
+        // check for bias argument
+        bool bias = false;
+        if (! lod && ! gather && ! grad && ! fetch) {
+            int nonBiasArgCount = 2;
+            if (offset)
+                ++nonBiasArgCount;
+            if (grad)
+                nonBiasArgCount += 2;
+
+            if ((int)arguments.size() > nonBiasArgCount)
+                bias = true;
+        }
+
+        bool cubeCompare = sampler.dim == glslang::EsdCube && sampler.arrayed && sampler.shadow;
+
+        // set the rest of the arguments
+        params.coords = arguments[1];
+        int extraArgs = 0;
+        if (cubeCompare)
+            params.Dref = arguments[2];
+        if (lod) {
+            params.lod = arguments[2];
+            ++extraArgs;
+        }
+        if (grad) {
+            params.gradX = arguments[2 + extraArgs];
+            params.gradY = arguments[3 + extraArgs];
+            extraArgs += 2;
+        }
+        //if (gather && compare) {
+        //    params.compare = arguments[2 + extraArgs];
+        //    ++extraArgs;
+        //}
+        if (offset | offsets) {
+            params.offset = arguments[2 + extraArgs];
+            ++extraArgs;
+        }
+        if (bias) {
+            params.bias = arguments[2 + extraArgs];
+            ++extraArgs;
+        }
+
+        return builder.createTextureCall(precision, convertGlslangToSpvType(node->getType()), proj, params);
+    }
+
+    spv::MissingFunctionality("built-in function call");
+
+    return 0;
+}
+
+spv::Id TGlslangToSpvTraverser::handleUserFunctionCall(const glslang::TIntermAggregate* node)
+{
+    // Grab the function's pointer from the previously created function
+    spv::Function* function = functionMap[node->getName().c_str()];
+    if (! function)
+        return 0;
+
+    const glslang::TIntermSequence& glslangArgs = node->getSequence();
+    const glslang::TQualifierList& qualifiers = node->getQualifierList();
+
+    //  See comments in makeFunctions() for details about the semantics for parameter passing.
+    //
+    // These imply we need a four step process:
+    // 1. Evaluate the arguments
+    // 2. Allocate and make copies of in, out, and inout arguments
+    // 3. Make the call
+    // 4. Copy back the results
+
+    // 1. Evaluate the arguments
+    std::vector<spv::Builder::AccessChain> lValues;
+    std::vector<spv::Id> rValues;
+    for (int a = 0; a < (int)glslangArgs.size(); ++a) {
+        // build l-value
+        builder.clearAccessChain();
+        glslangArgs[a]->traverse(this);
+        // keep outputs as l-values, evaluate input-only as r-values
+        if (qualifiers[a] != glslang::EvqConstReadOnly) {
+            // save l-value
+            lValues.push_back(builder.getAccessChain());
+        } else {
+            // process r-value
+            rValues.push_back(builder.accessChainLoad(TranslatePrecisionDecoration(glslangArgs[a]->getAsTyped()->getType())));
+        }
+    }
+
+    // 2. Allocate space for anything needing a copy, and if it's "in" or "inout"
+    // copy the original into that space.
+    //
+    // Also, build up the list of actual arguments to pass in for the call
+    int lValueCount = 0;
+    int rValueCount = 0;
+    std::vector<spv::Id> spvArgs;
+    for (int a = 0; a < (int)glslangArgs.size(); ++a) {
+        spv::Id arg;
+        if (qualifiers[a] != glslang::EvqConstReadOnly) {
+            // need space to hold the copy
+            const glslang::TType& paramType = glslangArgs[a]->getAsTyped()->getType();
+            arg = builder.createVariable(spv::StorageClassFunction, convertGlslangToSpvType(paramType), "param");
+            if (qualifiers[a] == glslang::EvqIn || qualifiers[a] == glslang::EvqInOut) {
+                // need to copy the input into output space
+                builder.setAccessChain(lValues[lValueCount]);
+                spv::Id copy = builder.accessChainLoad(spv::NoPrecision);  // TODO: get precision
+                builder.createStore(copy, arg);
+            }
+            ++lValueCount;
+        } else {
+            arg = rValues[rValueCount];
+            ++rValueCount;
+        }
+        spvArgs.push_back(arg);
+    }
+
+    // 3. Make the call.
+    spv::Id result = builder.createFunctionCall(function, spvArgs);
+
+    // 4. Copy back out an "out" arguments.
+    lValueCount = 0;
+    for (int a = 0; a < (int)glslangArgs.size(); ++a) {
+        if (qualifiers[a] != glslang::EvqConstReadOnly) {
+            if (qualifiers[a] == glslang::EvqOut || qualifiers[a] == glslang::EvqInOut) {
+                spv::Id copy = builder.createLoad(spvArgs[a]);
+                builder.setAccessChain(lValues[lValueCount]);
+                builder.accessChainStore(copy);
+            }
+            ++lValueCount;
+        }
+    }
+
+    return result;
+}
+
+// Translate AST operation to SPV operation, already having SPV-based operands/types.
+spv::Id TGlslangToSpvTraverser::createBinaryOperation(glslang::TOperator op, spv::Decoration precision, 
+                                                      spv::Id typeId, spv::Id left, spv::Id right,
+                                                      glslang::TBasicType typeProxy, bool reduceComparison)
+{
+    bool isUnsigned = typeProxy == glslang::EbtUint;
+    bool isFloat = typeProxy == glslang::EbtFloat || typeProxy == glslang::EbtDouble;
+
+    spv::Op binOp = spv::OpNop;
+    bool needsPromotion = true;
+    bool comparison = false;
+
+    switch (op) {
+    case glslang::EOpAdd:
+    case glslang::EOpAddAssign:
+        if (isFloat)
+            binOp = spv::OpFAdd;
+        else
+            binOp = spv::OpIAdd;
+        break;
+    case glslang::EOpSub:
+    case glslang::EOpSubAssign:
+        if (isFloat)
+            binOp = spv::OpFSub;
+        else
+            binOp = spv::OpISub;
+        break;
+    case glslang::EOpMul:
+    case glslang::EOpMulAssign:
+        if (isFloat)
+            binOp = spv::OpFMul;
+        else
+            binOp = spv::OpIMul;
+        break;
+    case glslang::EOpVectorTimesScalar:
+    case glslang::EOpVectorTimesScalarAssign:
+        if (builder.isVector(right))
+            std::swap(left, right);
+        assert(builder.isScalar(right));
+        binOp = spv::OpVectorTimesScalar;
+        needsPromotion = false;
+        break;
+    case glslang::EOpVectorTimesMatrix:
+    case glslang::EOpVectorTimesMatrixAssign:
+        assert(builder.isVector(left));
+        assert(builder.isMatrix(right));
+        binOp = spv::OpVectorTimesMatrix;
+        break;
+    case glslang::EOpMatrixTimesVector:
+        assert(builder.isMatrix(left));
+        assert(builder.isVector(right));
+        binOp = spv::OpMatrixTimesVector;
+        break;
+    case glslang::EOpMatrixTimesScalar:
+    case glslang::EOpMatrixTimesScalarAssign:
+        if (builder.isMatrix(right))
+            std::swap(left, right);
+        assert(builder.isScalar(right));
+        binOp = spv::OpMatrixTimesScalar;
+        break;
+    case glslang::EOpMatrixTimesMatrix:
+    case glslang::EOpMatrixTimesMatrixAssign:
+        assert(builder.isMatrix(left));
+        assert(builder.isMatrix(right));
+        binOp = spv::OpMatrixTimesMatrix;
+        break;
+    case glslang::EOpOuterProduct:
+        binOp = spv::OpOuterProduct;
+        needsPromotion = false;
+        break;
+
+    case glslang::EOpDiv:
+    case glslang::EOpDivAssign:
+        if (isFloat)
+            binOp = spv::OpFDiv;
+        else if (isUnsigned)
+            binOp = spv::OpUDiv;
+        else
+            binOp = spv::OpSDiv;
+        break;
+    case glslang::EOpMod:
+    case glslang::EOpModAssign:
+        if (isFloat)
+            binOp = spv::OpFMod;
+        else if (isUnsigned)
+            binOp = spv::OpUMod;
+        else
+            binOp = spv::OpSMod;
+        break;
+    case glslang::EOpRightShift:
+    case glslang::EOpRightShiftAssign:
+        if (isUnsigned)
+            binOp = spv::OpShiftRightLogical;
+        else
+            binOp = spv::OpShiftRightArithmetic;
+        break;
+    case glslang::EOpLeftShift:
+    case glslang::EOpLeftShiftAssign:
+        binOp = spv::OpShiftLeftLogical;
+        break;
+    case glslang::EOpAnd:
+    case glslang::EOpAndAssign:
+        binOp = spv::OpBitwiseAnd;
+        break;
+    case glslang::EOpLogicalAnd:
+        needsPromotion = false;
+        binOp = spv::OpLogicalAnd;
+        break;
+    case glslang::EOpInclusiveOr:
+    case glslang::EOpInclusiveOrAssign:
+        binOp = spv::OpBitwiseOr;
+        break;
+    case glslang::EOpLogicalOr:
+        needsPromotion = false;
+        binOp = spv::OpLogicalOr;
+        break;
+    case glslang::EOpExclusiveOr:
+    case glslang::EOpExclusiveOrAssign:
+        binOp = spv::OpBitwiseXor;
+        break;
+    case glslang::EOpLogicalXor:
+        needsPromotion = false;
+        binOp = spv::OpLogicalXor;
+        break;
+
+    case glslang::EOpLessThan:
+    case glslang::EOpGreaterThan:
+    case glslang::EOpLessThanEqual:
+    case glslang::EOpGreaterThanEqual:
+    case glslang::EOpEqual:
+    case glslang::EOpNotEqual:
+    case glslang::EOpVectorEqual:
+    case glslang::EOpVectorNotEqual:
+        comparison = true;
+        break;
+    default:
+        break;
+    }
+
+    if (binOp != spv::OpNop) {
+        if (builder.isMatrix(left) || builder.isMatrix(right)) {
+            switch (binOp) {
+            case spv::OpMatrixTimesScalar:
+            case spv::OpVectorTimesMatrix:
+            case spv::OpMatrixTimesVector:
+            case spv::OpMatrixTimesMatrix:
+                break;
+            case spv::OpFDiv:
+                // turn it into a multiply...
+                assert(builder.isMatrix(left) && builder.isScalar(right));
+                right = builder.createBinOp(spv::OpFDiv, builder.getTypeId(right), builder.makeFloatConstant(1.0F), right);
+                binOp = spv::OpFMul;
+                break;
+            default:
+                spv::MissingFunctionality("binary operation on matrix");
+                break;
+            }
+
+            spv::Id id = builder.createBinOp(binOp, typeId, left, right);
+            builder.setPrecision(id, precision);
+
+            return id;
+        }
+
+        // No matrix involved; make both operands be the same number of components, if needed
+        if (needsPromotion)
+            builder.promoteScalar(precision, left, right);
+
+        spv::Id id = builder.createBinOp(binOp, typeId, left, right);
+        builder.setPrecision(id, precision);
+
+        return id;
+    }
+
+    if (! comparison)
+        return 0;
+
+    // Comparison instructions
+
+    if (reduceComparison && (builder.isVector(left) || builder.isMatrix(left) || builder.isAggregate(left))) {
+        assert(op == glslang::EOpEqual || op == glslang::EOpNotEqual);
+
+        return builder.createCompare(precision, left, right, op == glslang::EOpEqual);
+    }
+
+    switch (op) {
+    case glslang::EOpLessThan:
+        if (isFloat)
+            binOp = spv::OpFOrdLessThan;
+        else if (isUnsigned)
+            binOp = spv::OpULessThan;
+        else
+            binOp = spv::OpSLessThan;
+        break;
+    case glslang::EOpGreaterThan:
+        if (isFloat)
+            binOp = spv::OpFOrdGreaterThan;
+        else if (isUnsigned)
+            binOp = spv::OpUGreaterThan;
+        else
+            binOp = spv::OpSGreaterThan;
+        break;
+    case glslang::EOpLessThanEqual:
+        if (isFloat)
+            binOp = spv::OpFOrdLessThanEqual;
+        else if (isUnsigned)
+            binOp = spv::OpULessThanEqual;
+        else
+            binOp = spv::OpSLessThanEqual;
+        break;
+    case glslang::EOpGreaterThanEqual:
+        if (isFloat)
+            binOp = spv::OpFOrdGreaterThanEqual;
+        else if (isUnsigned)
+            binOp = spv::OpUGreaterThanEqual;
+        else
+            binOp = spv::OpSGreaterThanEqual;
+        break;
+    case glslang::EOpEqual:
+    case glslang::EOpVectorEqual:
+        if (isFloat)
+            binOp = spv::OpFOrdEqual;
+        else
+            binOp = spv::OpIEqual;
+        break;
+    case glslang::EOpNotEqual:
+    case glslang::EOpVectorNotEqual:
+        if (isFloat)
+            binOp = spv::OpFOrdNotEqual;
+        else
+            binOp = spv::OpINotEqual;
+        break;
+    default:
+        break;
+    }
+
+    if (binOp != spv::OpNop) {
+        spv::Id id = builder.createBinOp(binOp, typeId, left, right);
+        builder.setPrecision(id, precision);
+
+        return id;
+    }
+
+    return 0;
+}
+
+spv::Id TGlslangToSpvTraverser::createUnaryOperation(glslang::TOperator op, spv::Decoration precision, spv::Id typeId, spv::Id operand, bool isFloat)
+{
+    spv::Op unaryOp = spv::OpNop;
+    int libCall = -1;
+
+    switch (op) {
+    case glslang::EOpNegative:
+        if (isFloat)
+            unaryOp = spv::OpFNegate;
+        else
+            unaryOp = spv::OpSNegate;
+        break;
+
+    case glslang::EOpLogicalNot:
+    case glslang::EOpVectorLogicalNot:
+    case glslang::EOpBitwiseNot:
+        unaryOp = spv::OpNot;
+        break;
+    
+    case glslang::EOpDeterminant:
+        libCall = GLSL_STD_450::Determinant;
+        break;
+    case glslang::EOpMatrixInverse:
+        libCall = GLSL_STD_450::MatrixInverse;
+        break;
+    case glslang::EOpTranspose:
+        unaryOp = spv::OpTranspose;
+        break;
+
+    case glslang::EOpRadians:
+        libCall = GLSL_STD_450::Radians;
+        break;
+    case glslang::EOpDegrees:
+        libCall = GLSL_STD_450::Degrees;
+        break;
+    case glslang::EOpSin:
+        libCall = GLSL_STD_450::Sin;
+        break;
+    case glslang::EOpCos:
+        libCall = GLSL_STD_450::Cos;
+        break;
+    case glslang::EOpTan:
+        libCall = GLSL_STD_450::Tan;
+        break;
+    case glslang::EOpAcos:
+        libCall = GLSL_STD_450::Acos;
+        break;
+    case glslang::EOpAsin:
+        libCall = GLSL_STD_450::Asin;
+        break;
+    case glslang::EOpAtan:
+        libCall = GLSL_STD_450::Atan;
+        break;
+
+    case glslang::EOpAcosh:
+        libCall = GLSL_STD_450::Acosh;
+        break;
+    case glslang::EOpAsinh:
+        libCall = GLSL_STD_450::Asinh;
+        break;
+    case glslang::EOpAtanh:
+        libCall = GLSL_STD_450::Atanh;
+        break;
+    case glslang::EOpTanh:
+        libCall = GLSL_STD_450::Tanh;
+        break;
+    case glslang::EOpCosh:
+        libCall = GLSL_STD_450::Cosh;
+        break;
+    case glslang::EOpSinh:
+        libCall = GLSL_STD_450::Sinh;
+        break;
+
+    case glslang::EOpLength:
+        libCall = GLSL_STD_450::Length;
+        break;
+    case glslang::EOpNormalize:
+        libCall = GLSL_STD_450::Normalize;
+        break;
+
+    case glslang::EOpExp:
+        libCall = GLSL_STD_450::Exp;
+        break;
+    case glslang::EOpLog:
+        libCall = GLSL_STD_450::Log;
+        break;
+    case glslang::EOpExp2:
+        libCall = GLSL_STD_450::Exp2;
+        break;
+    case glslang::EOpLog2:
+        libCall = GLSL_STD_450::Log2;
+        break;
+    case glslang::EOpSqrt:
+        libCall = GLSL_STD_450::Sqrt;
+        break;
+    case glslang::EOpInverseSqrt:
+        libCall = GLSL_STD_450::InverseSqrt;
+        break;
+
+    case glslang::EOpFloor:
+        libCall = GLSL_STD_450::Floor;
+        break;
+    case glslang::EOpTrunc:
+        libCall = GLSL_STD_450::Trunc;
+        break;
+    case glslang::EOpRound:
+        libCall = GLSL_STD_450::Round;
+        break;
+    case glslang::EOpRoundEven:
+        libCall = GLSL_STD_450::RoundEven;
+        break;
+    case glslang::EOpCeil:
+        libCall = GLSL_STD_450::Ceil;
+        break;
+    case glslang::EOpFract:
+        libCall = GLSL_STD_450::Fract;
+        break;
+
+    case glslang::EOpIsNan:
+        unaryOp = spv::OpIsNan;
+        break;
+    case glslang::EOpIsInf:
+        unaryOp = spv::OpIsInf;
+        break;
+
+    case glslang::EOpFloatBitsToInt:
+        libCall = GLSL_STD_450::FloatBitsToInt;
+        break;
+    case glslang::EOpFloatBitsToUint:
+        libCall = GLSL_STD_450::FloatBitsToUint;
+        break;
+    case glslang::EOpIntBitsToFloat:
+        libCall = GLSL_STD_450::IntBitsToFloat;
+        break;
+    case glslang::EOpUintBitsToFloat:
+        libCall = GLSL_STD_450::UintBitsToFloat;
+        break;
+    case glslang::EOpPackSnorm2x16:
+        libCall = GLSL_STD_450::PackSnorm2x16;
+        break;
+    case glslang::EOpUnpackSnorm2x16:
+        libCall = GLSL_STD_450::UnpackSnorm2x16;
+        break;
+    case glslang::EOpPackUnorm2x16:
+        libCall = GLSL_STD_450::PackUnorm2x16;
+        break;
+    case glslang::EOpUnpackUnorm2x16:
+        libCall = GLSL_STD_450::UnpackUnorm2x16;
+        break;
+    case glslang::EOpPackHalf2x16:
+        libCall = GLSL_STD_450::PackHalf2x16;
+        break;
+    case glslang::EOpUnpackHalf2x16:
+        libCall = GLSL_STD_450::UnpackHalf2x16;
+        break;
+
+    case glslang::EOpDPdx:
+        unaryOp = spv::OpDPdx;
+        break;
+    case glslang::EOpDPdy:
+        unaryOp = spv::OpDPdy;
+        break;
+    case glslang::EOpFwidth:
+        unaryOp = spv::OpFwidth;
+        break;
+    case glslang::EOpDPdxFine:
+        unaryOp = spv::OpDPdxFine;
+        break;
+    case glslang::EOpDPdyFine:
+        unaryOp = spv::OpDPdyFine;
+        break;
+    case glslang::EOpFwidthFine:
+        unaryOp = spv::OpFwidthFine;
+        break;
+    case glslang::EOpDPdxCoarse:
+        unaryOp = spv::OpDPdxCoarse;
+        break;
+    case glslang::EOpDPdyCoarse:
+        unaryOp = spv::OpDPdyCoarse;
+        break;
+    case glslang::EOpFwidthCoarse:
+        unaryOp = spv::OpFwidthCoarse;
+        break;
+
+    case glslang::EOpAny:
+        unaryOp = spv::OpAny;
+        break;
+    case glslang::EOpAll:
+        unaryOp = spv::OpAll;
+        break;
+
+    case glslang::EOpAbs:
+        libCall = GLSL_STD_450::Abs;
+        break;
+    case glslang::EOpSign:
+        libCall = GLSL_STD_450::Sign;
+        break;
+
+    default:
+        return 0;
+    }
+
+    spv::Id id;
+    if (libCall >= 0) {
+        std::vector<spv::Id> args;
+        args.push_back(operand);
+        id = builder.createBuiltinCall(precision, typeId, stdBuiltins, libCall, args);
+    } else
+        id = builder.createUnaryOp(unaryOp, typeId, operand);
+
+    builder.setPrecision(id, precision);
+
+    return id;
+}
+
+spv::Id TGlslangToSpvTraverser::createConversion(glslang::TOperator op, spv::Decoration precision, spv::Id destType, spv::Id operand)
+{
+    spv::Op convOp = spv::OpNop;
+    spv::Id zero = 0;
+    spv::Id one = 0;
+
+    int vectorSize = builder.isVectorType(destType) ? builder.getNumTypeComponents(destType) : 0;
+
+    switch (op) {
+    case glslang::EOpConvIntToBool:
+    case glslang::EOpConvUintToBool:
+        zero = builder.makeUintConstant(0);
+        zero = makeSmearedConstant(zero, vectorSize);
+        return builder.createBinOp(spv::OpINotEqual, destType, operand, zero);
+
+    case glslang::EOpConvFloatToBool:
+        zero = builder.makeFloatConstant(0.0F);
+        zero = makeSmearedConstant(zero, vectorSize);
+        return builder.createBinOp(spv::OpFOrdNotEqual, destType, operand, zero);
+
+    case glslang::EOpConvDoubleToBool:
+        zero = builder.makeDoubleConstant(0.0);
+        zero = makeSmearedConstant(zero, vectorSize);
+        return builder.createBinOp(spv::OpFOrdNotEqual, destType, operand, zero);
+
+    case glslang::EOpConvBoolToFloat:
+        convOp = spv::OpSelect;
+        zero = builder.makeFloatConstant(0.0);
+        one  = builder.makeFloatConstant(1.0);
+        break;
+    case glslang::EOpConvBoolToDouble:
+        convOp = spv::OpSelect;
+        zero = builder.makeDoubleConstant(0.0);
+        one  = builder.makeDoubleConstant(1.0);
+        break;
+    case glslang::EOpConvBoolToInt:
+        zero = builder.makeIntConstant(0);
+        one  = builder.makeIntConstant(1);
+        convOp = spv::OpSelect;
+        break;
+    case glslang::EOpConvBoolToUint:
+        zero = builder.makeUintConstant(0);
+        one  = builder.makeUintConstant(1);
+        convOp = spv::OpSelect;
+        break;
+
+    case glslang::EOpConvIntToFloat:
+    case glslang::EOpConvIntToDouble:
+        convOp = spv::OpConvertSToF;
+        break;
+
+    case glslang::EOpConvUintToFloat:
+    case glslang::EOpConvUintToDouble:
+        convOp = spv::OpConvertUToF;
+        break;
+
+    case glslang::EOpConvDoubleToFloat:
+    case glslang::EOpConvFloatToDouble:
+        convOp = spv::OpFConvert;
+        break;
+
+    case glslang::EOpConvFloatToInt:
+    case glslang::EOpConvDoubleToInt:
+        convOp = spv::OpConvertFToS;
+        break;
+
+    case glslang::EOpConvUintToInt:
+    case glslang::EOpConvIntToUint:
+        convOp = spv::OpBitcast;
+        break;
+
+    case glslang::EOpConvFloatToUint:
+    case glslang::EOpConvDoubleToUint:
+        convOp = spv::OpConvertFToU;
+        break;
+    default:
+        break;
+    }
+
+    spv::Id result = 0;
+    if (convOp == spv::OpNop)
+        return result;
+
+    if (convOp == spv::OpSelect) {
+        zero = makeSmearedConstant(zero, vectorSize);
+        one  = makeSmearedConstant(one, vectorSize);
+        result = builder.createTriOp(convOp, destType, operand, one, zero);
+    } else
+        result = builder.createUnaryOp(convOp, destType, operand);
+
+    builder.setPrecision(result, precision);
+
+    return result;
+}
+
+spv::Id TGlslangToSpvTraverser::makeSmearedConstant(spv::Id constant, int vectorSize)
+{
+    if (vectorSize == 0)
+        return constant;
+
+    spv::Id vectorTypeId = builder.makeVectorType(builder.getTypeId(constant), vectorSize);
+    std::vector<spv::Id> components;
+    for (int c = 0; c < vectorSize; ++c)
+        components.push_back(constant);
+    return builder.makeCompositeConstant(vectorTypeId, components);
+}
+
+spv::Id TGlslangToSpvTraverser::createMiscOperation(glslang::TOperator op, spv::Decoration precision, spv::Id typeId, std::vector<spv::Id>& operands)
+{
+    spv::Op opCode = spv::OpNop;
+    int libCall = -1;
+
+    switch (op) {
+    case glslang::EOpMin:
+        libCall = GLSL_STD_450::Min;
+        break;
+    case glslang::EOpModf:
+        libCall = GLSL_STD_450::Modf;
+        break;
+    case glslang::EOpMax:
+        libCall = GLSL_STD_450::Max;
+        break;
+    case glslang::EOpPow:
+        libCall = GLSL_STD_450::Pow;
+        break;
+    case glslang::EOpDot:
+        opCode = spv::OpDot;
+        break;
+    case glslang::EOpAtan:
+        libCall = GLSL_STD_450::Atan2;
+        break;
+
+    case glslang::EOpClamp:
+        libCall = GLSL_STD_450::Clamp;
+        break;
+    case glslang::EOpMix:
+        libCall = GLSL_STD_450::Mix;
+        break;
+    case glslang::EOpStep:
+        libCall = GLSL_STD_450::Step;
+        break;
+    case glslang::EOpSmoothStep:
+        libCall = GLSL_STD_450::SmoothStep;
+        break;
+
+    case glslang::EOpDistance:
+        libCall = GLSL_STD_450::Distance;
+        break;
+    case glslang::EOpCross:
+        libCall = GLSL_STD_450::Cross;
+        break;
+    case glslang::EOpFaceForward:
+        libCall = GLSL_STD_450::FaceForward;
+        break;
+    case glslang::EOpReflect:
+        libCall = GLSL_STD_450::Reflect;
+        break;
+    case glslang::EOpRefract:
+        libCall = GLSL_STD_450::Refract;
+        break;
+    default:
+        return 0;
+    }
+
+    spv::Id id = 0;
+    if (libCall >= 0)
+        id = builder.createBuiltinCall(precision, typeId, stdBuiltins, libCall, operands);
+    else {
+        switch (operands.size()) {
+        case 0:
+            // should all be handled by visitAggregate and createNoArgOperation
+            assert(0);
+            return 0;
+        case 1:
+            // should all be handled by createUnaryOperation
+            assert(0);
+            return 0;
+        case 2:
+            id = builder.createBinOp(opCode, typeId, operands[0], operands[1]);
+            break;
+        case 3:
+            id = builder.createTernaryOp(opCode, typeId, operands[0], operands[1], operands[2]);
+            break;
+        default:
+            // These do not exist yet
+            assert(0 && "operation with more than 3 operands");
+            break;
+        }
+    }
+
+    builder.setPrecision(id, precision);
+
+    return id;
+}
+
+// Intrinsics with no arguments, no return value, and no precision.
+spv::Id TGlslangToSpvTraverser::createNoArgOperation(glslang::TOperator op)
+{
+    // TODO: get the barrier operands correct
+
+    switch (op) {
+    case glslang::EOpEmitVertex:
+        builder.createNoResultOp(spv::OpEmitVertex);
+        return 0;
+    case glslang::EOpEndPrimitive:
+        builder.createNoResultOp(spv::OpEndPrimitive);
+        return 0;
+    case glslang::EOpBarrier:
+        builder.createMemoryBarrier(spv::ExecutionScopeDevice, spv::MemorySemanticsAllMemory);
+        builder.createControlBarrier(spv::ExecutionScopeDevice);
+        return 0;
+    case glslang::EOpMemoryBarrier:
+        builder.createMemoryBarrier(spv::ExecutionScopeDevice, spv::MemorySemanticsAllMemory);
+        return 0;
+    case glslang::EOpMemoryBarrierAtomicCounter:
+        builder.createMemoryBarrier(spv::ExecutionScopeDevice, spv::MemorySemanticsAtomicCounterMemoryMask);
+        return 0;
+    case glslang::EOpMemoryBarrierBuffer:
+        builder.createMemoryBarrier(spv::ExecutionScopeDevice, spv::MemorySemanticsUniformMemoryMask);
+        return 0;
+    case glslang::EOpMemoryBarrierImage:
+        builder.createMemoryBarrier(spv::ExecutionScopeDevice, spv::MemorySemanticsImageMemoryMask);
+        return 0;
+    case glslang::EOpMemoryBarrierShared:
+        builder.createMemoryBarrier(spv::ExecutionScopeDevice, spv::MemorySemanticsWorkgroupLocalMemoryMask);
+        return 0;
+    case glslang::EOpGroupMemoryBarrier:
+        builder.createMemoryBarrier(spv::ExecutionScopeDevice, spv::MemorySemanticsWorkgroupGlobalMemoryMask);
+        return 0;
+    default:
+        spv::MissingFunctionality("operation with no arguments");
+        return 0;
+    }
+}
+
+spv::Id TGlslangToSpvTraverser::getSymbolId(const glslang::TIntermSymbol* symbol)
+{
+    std::map<int, spv::Id>::iterator iter;
+    iter = symbolValues.find(symbol->getId());
+    spv::Id id;
+    if (symbolValues.end() != iter) {
+        id = iter->second;
+        return id;
+    }
+
+    // it was not found, create it
+    id = createSpvVariable(symbol);
+    symbolValues[symbol->getId()] = id;
+
+    if (! symbol->getType().isStruct()) {
+        addDecoration(id, TranslatePrecisionDecoration(symbol->getType()));
+        addDecoration(id, TranslateInterpolationDecoration(symbol->getType()));
+        if (symbol->getQualifier().hasLocation())
+            builder.addDecoration(id, spv::DecorationLocation, symbol->getQualifier().layoutLocation);
+        if (symbol->getQualifier().hasIndex())
+            builder.addDecoration(id, spv::DecorationIndex, symbol->getQualifier().layoutIndex);
+        if (symbol->getQualifier().hasComponent())
+            builder.addDecoration(id, spv::DecorationComponent, symbol->getQualifier().layoutComponent);
+        if (glslangIntermediate->getXfbMode()) {
+            if (symbol->getQualifier().hasXfbStride())
+                builder.addDecoration(id, spv::DecorationStride, symbol->getQualifier().layoutXfbStride);
+            if (symbol->getQualifier().hasXfbBuffer())
+                builder.addDecoration(id, spv::DecorationXfbBuffer, symbol->getQualifier().layoutXfbBuffer);
+            if (symbol->getQualifier().hasXfbOffset())
+                builder.addDecoration(id, spv::DecorationOffset, symbol->getQualifier().layoutXfbOffset);
+        }
+    }
+
+    addDecoration(id, TranslateInvariantDecoration(symbol->getType()));
+    if (symbol->getQualifier().hasStream())
+        builder.addDecoration(id, spv::DecorationStream, symbol->getQualifier().layoutStream);
+    if (symbol->getQualifier().hasSet())
+        builder.addDecoration(id, spv::DecorationDescriptorSet, symbol->getQualifier().layoutSet);
+    if (symbol->getQualifier().hasBinding())
+        builder.addDecoration(id, spv::DecorationBinding, symbol->getQualifier().layoutBinding);
+    if (glslangIntermediate->getXfbMode()) {
+        if (symbol->getQualifier().hasXfbStride())
+            builder.addDecoration(id, spv::DecorationStride, symbol->getQualifier().layoutXfbStride);
+        if (symbol->getQualifier().hasXfbBuffer())
+            builder.addDecoration(id, spv::DecorationXfbBuffer, symbol->getQualifier().layoutXfbBuffer);
+    }
+
+    // built-in variable decorations
+    int builtIn = TranslateBuiltInDecoration(symbol->getQualifier().builtIn);
+    if (builtIn != spv::BadValue)
+        builder.addDecoration(id, spv::DecorationBuiltIn, builtIn);
+
+    if (linkageOnly)
+        builder.addDecoration(id, spv::DecorationNoStaticUse);
+
+    return id;
+}
+
+void TGlslangToSpvTraverser::addDecoration(spv::Id id, spv::Decoration dec)
+{
+    if (dec != spv::BadValue)
+        builder.addDecoration(id, dec);
+}
+
+void TGlslangToSpvTraverser::addMemberDecoration(spv::Id id, int member, spv::Decoration dec)
+{
+    if (dec != spv::BadValue)
+        builder.addMemberDecoration(id, (unsigned)member, dec);
+}
+
+// Use 'consts' as the flattened glslang source of scalar constants to recursively
+// build the aggregate SPIR-V constant.
+//
+// If there are not enough elements present in 'consts', 0 will be substituted;
+// an empty 'consts' can be used to create a fully zeroed SPIR-V constant.
+//
+spv::Id TGlslangToSpvTraverser::createSpvConstant(const glslang::TType& glslangType, const glslang::TConstUnionArray& consts, int& nextConst)
+{
+    // vector of constants for SPIR-V
+    std::vector<spv::Id> spvConsts;
+
+    // Type is used for struct and array constants
+    spv::Id typeId = convertGlslangToSpvType(glslangType);
+
+    if (glslangType.isArray()) {
+        glslang::TType elementType;
+        elementType.shallowCopy(glslangType);   // TODO: desktop arrays of arrays functionality will need a deeper copy to avoid modifying the original
+        elementType.dereference();
+        for (int i = 0; i < glslangType.getArraySize(); ++i)
+            spvConsts.push_back(createSpvConstant(elementType, consts, nextConst));
+    } else if (glslangType.isMatrix()) {
+        glslang::TType vectorType;
+        vectorType.shallowCopy(glslangType);
+        vectorType.dereference();
+        for (int col = 0; col < glslangType.getMatrixCols(); ++col)
+            spvConsts.push_back(createSpvConstant(vectorType, consts, nextConst));
+    } else if (glslangType.getStruct()) {
+        glslang::TVector<glslang::TTypeLoc>::const_iterator iter;
+        for (iter = glslangType.getStruct()->begin(); iter != glslangType.getStruct()->end(); ++iter)
+            spvConsts.push_back(createSpvConstant(*iter->type, consts, nextConst));
+    } else if (glslangType.isVector()) {
+        for (unsigned int i = 0; i < (unsigned int)glslangType.getVectorSize(); ++i) {
+            bool zero = nextConst >= consts.size();
+            switch (glslangType.getBasicType()) {
+            case glslang::EbtInt:
+                spvConsts.push_back(builder.makeIntConstant(zero ? 0 : consts[nextConst].getIConst()));
+                break;
+            case glslang::EbtUint:
+                spvConsts.push_back(builder.makeUintConstant(zero ? 0 : consts[nextConst].getUConst()));
+                break;
+            case glslang::EbtFloat:
+                spvConsts.push_back(builder.makeFloatConstant(zero ? 0.0F : (float)consts[nextConst].getDConst()));
+                break;
+            case glslang::EbtDouble:
+                spvConsts.push_back(builder.makeDoubleConstant(zero ? 0.0 : consts[nextConst].getDConst()));
+                break;
+            case glslang::EbtBool:
+                spvConsts.push_back(builder.makeBoolConstant(zero ? false : consts[nextConst].getBConst()));
+                break;
+            default:
+                spv::MissingFunctionality("constant vector type");
+                break;
+            }
+            ++nextConst;
+        }
+    } else {
+        // we have a non-aggregate (scalar) constant
+        bool zero = nextConst >= consts.size();
+        spv::Id scalar = 0;
+        switch (glslangType.getBasicType()) {
+        case glslang::EbtInt:
+            scalar = builder.makeIntConstant(zero ? 0 : consts[nextConst].getIConst());
+            break;
+        case glslang::EbtUint:
+            scalar = builder.makeUintConstant(zero ? 0 : consts[nextConst].getUConst());
+            break;
+        case glslang::EbtFloat:
+            scalar = builder.makeFloatConstant(zero ? 0.0F : (float)consts[nextConst].getDConst());
+            break;
+        case glslang::EbtDouble:
+            scalar = builder.makeDoubleConstant(zero ? 0.0 : consts[nextConst].getDConst());
+            break;
+        case glslang::EbtBool:
+            scalar = builder.makeBoolConstant(zero ? false : consts[nextConst].getBConst());
+            break;
+        default:
+            spv::MissingFunctionality("constant scalar type");
+            break;
+        }
+        ++nextConst;
+        return scalar;
+    }
+
+    return builder.makeCompositeConstant(typeId, spvConsts);
+}
+
+};  // end anonymous namespace
+
+namespace glslang {
+
+// Write SPIR-V out to a binary file
+void OutputSpv(const std::vector<unsigned int>& spirv, const char* baseName)
+{
+    std::ofstream out;
+    std::string fileName(baseName);
+    fileName.append(".spv");
+    out.open(fileName.c_str(), std::ios::binary | std::ios::out);
+    for (int i = 0; i < (int)spirv.size(); ++i) {
+        unsigned int word = spirv[i];
+        out.write((const char*)&word, 4);
+    }
+    out.close();
+}
+
+//
+// Set up the glslang traversal
+//
+void GlslangToSpv(const glslang::TIntermediate& intermediate, std::vector<unsigned int>& spirv)
+{
+    TIntermNode* root = intermediate.getTreeRoot();
+
+    if (root == 0)
+        return;
+
+    glslang::GetThreadPoolAllocator().push();
+
+    TGlslangToSpvTraverser it(&intermediate);
+
+    root->traverse(&it);
+
+    it.dumpSpv(spirv);
+
+    glslang::GetThreadPoolAllocator().pop();
+}
+
+}; // end namespace glslang
diff --git a/SPIRV/GlslangToSpv.h b/SPIRV/GlslangToSpv.h
index 1a14fe5..75375d8 100644
--- a/SPIRV/GlslangToSpv.h
+++ b/SPIRV/GlslangToSpv.h
@@ -1,42 +1,42 @@
-//

-//Copyright (C) 2014 LunarG, Inc.

-//

-//All rights reserved.

-//

-//Redistribution and use in source and binary forms, with or without

-//modification, are permitted provided that the following conditions

-//are met:

-//

-//    Redistributions of source code must retain the above copyright

-//    notice, this list of conditions and the following disclaimer.

-//

-//    Redistributions in binary form must reproduce the above

-//    copyright notice, this list of conditions and the following

-//    disclaimer in the documentation and/or other materials provided

-//    with the distribution.

-//

-//    Neither the name of 3Dlabs Inc. Ltd. nor the names of its

-//    contributors may be used to endorse or promote products derived

-//    from this software without specific prior written permission.

-//

-//THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS

-//"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT

-//LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS

-//FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE

-//COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,

-//INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,

-//BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;

-//LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER

-//CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT

-//LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN

-//ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE

-//POSSIBILITY OF SUCH DAMAGE.

-

-#include "../glslang/Include/intermediate.h"

-

-namespace glslang {

-

-void GlslangToSpv(const glslang::TIntermediate& intermediate, std::vector<unsigned int>& spirv);

-void OutputSpv(const std::vector<unsigned int>& spirv, const char* baseName);

-

-};

+//
+//Copyright (C) 2014 LunarG, Inc.
+//
+//All rights reserved.
+//
+//Redistribution and use in source and binary forms, with or without
+//modification, are permitted provided that the following conditions
+//are met:
+//
+//    Redistributions of source code must retain the above copyright
+//    notice, this list of conditions and the following disclaimer.
+//
+//    Redistributions in binary form must reproduce the above
+//    copyright notice, this list of conditions and the following
+//    disclaimer in the documentation and/or other materials provided
+//    with the distribution.
+//
+//    Neither the name of 3Dlabs Inc. Ltd. nor the names of its
+//    contributors may be used to endorse or promote products derived
+//    from this software without specific prior written permission.
+//
+//THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+//"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+//LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+//FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+//COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+//INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+//BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+//LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+//CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+//LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+//ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+//POSSIBILITY OF SUCH DAMAGE.
+
+#include "../glslang/Include/intermediate.h"
+
+namespace glslang {
+
+void GlslangToSpv(const glslang::TIntermediate& intermediate, std::vector<unsigned int>& spirv);
+void OutputSpv(const std::vector<unsigned int>& spirv, const char* baseName);
+
+};
diff --git a/SPIRV/SPVRemapper.cpp b/SPIRV/SPVRemapper.cpp
index a8b71f9..76d4772 100644
--- a/SPIRV/SPVRemapper.cpp
+++ b/SPIRV/SPVRemapper.cpp
@@ -1,1161 +1,1161 @@
-//

-//Copyright (C) 2015 LunarG, Inc.

-//

-//All rights reserved.

-//

-//Redistribution and use in source and binary forms, with or without

-//modification, are permitted provided that the following conditions

-//are met:

-//

-//    Redistributions of source code must retain the above copyright

-//    notice, this list of conditions and the following disclaimer.

-//

-//    Redistributions in binary form must reproduce the above

-//    copyright notice, this list of conditions and the following

-//    disclaimer in the documentation and/or other materials provided

-//    with the distribution.

-//

-//    Neither the name of 3Dlabs Inc. Ltd. nor the names of its

-//    contributors may be used to endorse or promote products derived

-//    from this software without specific prior written permission.

-//

-//THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS

-//"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT

-//LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS

-//FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE

-//COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,

-//INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,

-//BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;

-//LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER

-//CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT

-//LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN

-//ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE

-//POSSIBILITY OF SUCH DAMAGE.

-//

-

-#include "SPVRemapper.h"

-#include "doc.h"

-

-#if !defined (use_cpp11)

-// ... not supported before C++11

-#else // defined (use_cpp11)

-

-#include <algorithm>

-#include <cassert>

-

-namespace spv {

-

-    // By default, just abort on error.  Can be overridden via RegisterErrorHandler

-    spirvbin_t::errorfn_t spirvbin_t::errorHandler = [](const std::string&) { exit(5); };

-    // By default, eat log messages.  Can be overridden via RegisterLogHandler

-    spirvbin_t::logfn_t   spirvbin_t::logHandler   = [](const std::string&) { };

-

-    // This can be overridden to provide other message behavior if needed

-    void spirvbin_t::msg(int minVerbosity, int indent, const std::string& txt) const

-    {

-        if (verbose >= minVerbosity)

-            logHandler(std::string(indent, ' ') + txt);

-    }

-

-    // hash opcode, with special handling for OpExtInst

-    std::uint32_t spirvbin_t::asOpCodeHash(unsigned word)

-    {

-        const spv::Op opCode = asOpCode(word);

-

-        std::uint32_t offset = 0;

-

-        switch (opCode) {

-        case spv::OpExtInst:

-            offset += asId(word + 4); break;

-        default:

-            break;

-        }

-

-        return opCode * 19 + offset; // 19 = small prime

-    }

-

-    spirvbin_t::range_t spirvbin_t::literalRange(spv::Op opCode) const

-    {

-        static const int maxCount = 1<<30;

-

-        switch (opCode) {

-        case spv::OpTypeFloat:        // fall through...

-        case spv::OpTypePointer:      return range_t(2, 3);

-        case spv::OpTypeInt:          return range_t(2, 4);

-        case spv::OpTypeSampler:      return range_t(3, 8);

-        case spv::OpTypeVector:       // fall through

-        case spv::OpTypeMatrix:       // ...

-        case spv::OpTypePipe:         return range_t(3, 4);

-        case spv::OpConstant:         return range_t(3, maxCount);

-        default:                      return range_t(0, 0);

-        }

-    }

-

-    spirvbin_t::range_t spirvbin_t::typeRange(spv::Op opCode) const

-    {

-        static const int maxCount = 1<<30;

-

-        if (isConstOp(opCode))

-            return range_t(1, 2);

-

-        switch (opCode) {

-        case spv::OpTypeVector:       // fall through

-        case spv::OpTypeMatrix:       // ... 

-        case spv::OpTypeSampler:      // ... 

-        case spv::OpTypeArray:        // ... 

-        case spv::OpTypeRuntimeArray: // ... 

-        case spv::OpTypePipe:         return range_t(2, 3);

-        case spv::OpTypeStruct:       // fall through

-        case spv::OpTypeFunction:     return range_t(2, maxCount);

-        case spv::OpTypePointer:      return range_t(3, 4);

-        default:                      return range_t(0, 0);

-        }

-    }

-

-    spirvbin_t::range_t spirvbin_t::constRange(spv::Op opCode) const

-    {

-        static const int maxCount = 1<<30;

-

-        switch (opCode) {

-        case spv::OpTypeArray:         // fall through...

-        case spv::OpTypeRuntimeArray:  return range_t(3, 4);

-        case spv::OpConstantComposite: return range_t(3, maxCount);

-        default:                       return range_t(0, 0);

-        }

-    }

-

-    // Is this an opcode we should remove when using --strip?

-    bool spirvbin_t::isStripOp(spv::Op opCode) const

-    {

-        switch (opCode) {

-        case spv::OpSource:

-        case spv::OpSourceExtension:

-        case spv::OpName:

-        case spv::OpMemberName:

-        case spv::OpLine:           return true;

-        default:                    return false;

-        }

-    }

-

-    bool spirvbin_t::isFlowCtrlOpen(spv::Op opCode) const

-    {

-        switch (opCode) {

-        case spv::OpBranchConditional:

-        case spv::OpSwitch:         return true;

-        default:                    return false;

-        }

-    }

-

-    bool spirvbin_t::isFlowCtrlClose(spv::Op opCode) const

-    {

-        switch (opCode) {

-        case spv::OpLoopMerge:

-        case spv::OpSelectionMerge: return true;

-        default:                    return false;

-        }

-    }

-

-    bool spirvbin_t::isTypeOp(spv::Op opCode) const

-    {

-        switch (opCode) {

-        case spv::OpTypeVoid:

-        case spv::OpTypeBool:

-        case spv::OpTypeInt:

-        case spv::OpTypeFloat:

-        case spv::OpTypeVector:

-        case spv::OpTypeMatrix:

-        case spv::OpTypeSampler:

-        case spv::OpTypeFilter:

-        case spv::OpTypeArray:

-        case spv::OpTypeRuntimeArray:

-        case spv::OpTypeStruct:

-        case spv::OpTypeOpaque:

-        case spv::OpTypePointer:

-        case spv::OpTypeFunction:

-        case spv::OpTypeEvent:

-        case spv::OpTypeDeviceEvent:

-        case spv::OpTypeReserveId:

-        case spv::OpTypeQueue:

-        case spv::OpTypePipe:         return true;

-        default:                      return false;

-        }

-    }

-

-    bool spirvbin_t::isConstOp(spv::Op opCode) const

-    {

-        switch (opCode) {

-        case spv::OpConstantNullObject: error("unimplemented constant type");

-        case spv::OpConstantSampler:    error("unimplemented constant type");

-

-        case spv::OpConstantTrue:

-        case spv::OpConstantFalse:

-        case spv::OpConstantNullPointer:

-        case spv::OpConstantComposite:

-        case spv::OpConstant:         return true;

-        default:                      return false;

-        }

-    }

-

-    const auto inst_fn_nop = [](spv::Op, unsigned) { return false; };

-    const auto op_fn_nop   = [](spv::Id&)          { };

-

-    // g++ doesn't like these defined in the class proper in an anonymous namespace.

-    // Dunno why.  Also MSVC doesn't like the constexpr keyword.  Also dunno why.

-    // Defining them externally seems to please both compilers, so, here they are.

-    const spv::Id spirvbin_t::unmapped    = spv::Id(-10000);

-    const spv::Id spirvbin_t::unused      = spv::Id(-10001);

-    const int     spirvbin_t::header_size = 5;

-

-    spv::Id spirvbin_t::nextUnusedId(spv::Id id)

-    {

-        while (isNewIdMapped(id))  // search for an unused ID

-            ++id;

-

-        return id;

-    }

-

-    spv::Id spirvbin_t::localId(spv::Id id, spv::Id newId)

-    {

-        assert(id != spv::NoResult && newId != spv::NoResult);

-

-        if (id >= idMapL.size())

-            idMapL.resize(id+1, unused);

-

-        if (newId != unmapped && newId != unused) {

-            if (isOldIdUnused(id))

-                error(std::string("ID unused in module: ") + std::to_string(id));

-

-            if (!isOldIdUnmapped(id))

-                error(std::string("ID already mapped: ") + std::to_string(id) + " -> "

-                + std::to_string(localId(id)));

-

-            if (isNewIdMapped(newId))

-                error(std::string("ID already used in module: ") + std::to_string(newId));

-

-            msg(4, 4, std::string("map: ") + std::to_string(id) + " -> " + std::to_string(newId));

-            setMapped(newId);

-            largestNewId = std::max(largestNewId, newId);

-        }

-

-        return idMapL[id] = newId;

-    }

-

-    // Parse a literal string from the SPIR binary and return it as an std::string

-    // Due to C++11 RValue references, this doesn't copy the result string.

-    std::string spirvbin_t::literalString(unsigned word) const

-    {

-        std::string literal;

-

-        literal.reserve(16);

-

-        const char* bytes = reinterpret_cast<const char*>(spv.data() + word);

-

-        while (bytes && *bytes)

-            literal += *bytes++;

-

-        return literal;

-    }

-

-

-    void spirvbin_t::applyMap()

-    {

-        msg(3, 2, std::string("Applying map: "));

-

-        // Map local IDs through the ID map

-        process(inst_fn_nop, // ignore instructions

-            [this](spv::Id& id) {

-                id = localId(id);

-                assert(id != unused && id != unmapped);

-            }

-        );

-    }

-

-

-    // Find free IDs for anything we haven't mapped

-    void spirvbin_t::mapRemainder()

-    {

-        msg(3, 2, std::string("Remapping remainder: "));

-

-        spv::Id     unusedId  = 1;  // can't use 0: that's NoResult

-        spirword_t  maxBound  = 0;

-

-        for (spv::Id id = 0; id < idMapL.size(); ++id) {

-            if (isOldIdUnused(id))

-                continue;

-

-            // Find a new mapping for any used but unmapped IDs

-            if (isOldIdUnmapped(id))

-                localId(id, unusedId = nextUnusedId(unusedId));

-

-            if (isOldIdUnmapped(id))

-                error(std::string("old ID not mapped: ") + std::to_string(id));

-

-            // Track max bound

-            maxBound = std::max(maxBound, localId(id) + 1);

-        }

-

-        bound(maxBound); // reset header ID bound to as big as it now needs to be

-    }

-

-    void spirvbin_t::stripDebug()

-    {

-        if ((options & STRIP) == 0)

-            return;

-

-        // build local Id and name maps

-        process(

-            [&](spv::Op opCode, unsigned start) {

-                // remember opcodes we want to strip later

-                if (isStripOp(opCode))

-                    stripInst(start);

-                return true;

-            },

-            op_fn_nop);

-    }

-

-    void spirvbin_t::buildLocalMaps()

-    {

-        msg(2, 2, std::string("build local maps: "));

-

-        mapped.clear();

-        idMapL.clear();

-//      preserve nameMap, so we don't clear that.

-        fnPos.clear();

-        fnPosDCE.clear();

-        fnCalls.clear();

-        typeConstPos.clear();

-        typeConstPosR.clear();

-        entryPoint = spv::NoResult;

-        largestNewId = 0;

-

-        idMapL.resize(bound(), unused);

-

-        int         fnStart = 0;

-        spv::Id     fnRes   = spv::NoResult;

-

-        // build local Id and name maps

-        process(

-            [&](spv::Op opCode, unsigned start) {

-                // remember opcodes we want to strip later

-                if ((options & STRIP) && isStripOp(opCode))

-                    stripInst(start);

-

-                if (opCode == spv::Op::OpName) {

-                    const spv::Id    target = asId(start+1);

-                    const std::string  name = literalString(start+2);

-                    nameMap[name] = target;

-

-                } else if (opCode == spv::Op::OpFunctionCall) {

-                    ++fnCalls[asId(start + 3)];

-                } else if (opCode == spv::Op::OpEntryPoint) {

-                    entryPoint = asId(start + 2);

-                } else if (opCode == spv::Op::OpFunction) {

-                    if (fnStart != 0)

-                        error("nested function found");

-                    fnStart = start;

-                    fnRes   = asId(start + 2);

-                } else if (opCode == spv::Op::OpFunctionEnd) {

-                    assert(fnRes != spv::NoResult);

-                    if (fnStart == 0)

-                        error("function end without function start");

-                    fnPos[fnRes] = range_t(fnStart, start + asWordCount(start));

-                    fnStart = 0;

-                } else if (isConstOp(opCode)) {

-                    assert(asId(start + 2) != spv::NoResult);

-                    typeConstPos.insert(start);

-                    typeConstPosR[asId(start + 2)] = start;

-                } else if (isTypeOp(opCode)) {

-                    assert(asId(start + 1) != spv::NoResult);

-                    typeConstPos.insert(start);

-                    typeConstPosR[asId(start + 1)] = start;

-                }

-

-                return false;

-            },

-

-            [this](spv::Id& id) { localId(id, unmapped); }

-        );

-    }

-

-    // Validate the SPIR header

-    void spirvbin_t::validate() const

-    {

-        msg(2, 2, std::string("validating: "));

-

-        if (spv.size() < header_size)

-            error("file too short: ");

-

-        if (magic() != spv::MagicNumber)

-            error("bad magic number");

-

-        // field 1 = version

-        // field 2 = generator magic

-        // field 3 = result <id> bound

-

-        if (schemaNum() != 0)

-            error("bad schema, must be 0");

-    }

-

-

-    int spirvbin_t::processInstruction(unsigned word, instfn_t instFn, idfn_t idFn)

-    {

-        const auto     instructionStart = word;

-        const unsigned wordCount = asWordCount(instructionStart);

-        const spv::Op  opCode    = asOpCode(instructionStart);

-        const int      nextInst  = word++ + wordCount;

-

-        if (nextInst > int(spv.size()))

-            error("spir instruction terminated too early");

-

-        // Base for computing number of operands; will be updated as more is learned

-        unsigned numOperands = wordCount - 1;

-

-        if (instFn(opCode, instructionStart))

-            return nextInst;

-

-        // Read type and result ID from instruction desc table

-        if (spv::InstructionDesc[opCode].hasType()) {

-            idFn(asId(word++));

-            --numOperands;

-        }

-

-        if (spv::InstructionDesc[opCode].hasResult()) {

-            idFn(asId(word++));

-            --numOperands;

-        }

-

-        // Extended instructions: currently, assume everything is an ID.

-        // TODO: add whatever data we need for exceptions to that

-        if (opCode == spv::OpExtInst) {

-            word        += 2; // instruction set, and instruction from set

-            numOperands -= 2;

-

-            for (unsigned op=0; op < numOperands; ++op)

-                idFn(asId(word++)); // ID

-

-            return nextInst;

-        }

-

-        // Store IDs from instruction in our map

-        for (int op = 0; op < spv::InstructionDesc[opCode].operands.getNum(); ++op, --numOperands) {

-            switch (spv::InstructionDesc[opCode].operands.getClass(op)) {

-            case spv::OperandId:

-                idFn(asId(word++));

-                break;

-

-            case spv::OperandOptionalId:

-            case spv::OperandVariableIds:

-                for (unsigned i = 0; i < numOperands; ++i)

-                    idFn(asId(word++));

-                return nextInst;

-

-            case spv::OperandVariableLiterals:

-                if (opCode == spv::OpDecorate && asDecoration(word - 1) == spv::DecorationBuiltIn) {

-                    ++word;

-                    --numOperands;

-                }

-                word += numOperands;

-                return nextInst;

-

-            case spv::OperandVariableLiteralId:

-                while (numOperands > 0) {

-                    ++word;             // immediate

-                    idFn(asId(word++)); // ID

-                    numOperands -= 2;

-                }

-                return nextInst;

-

-            case spv::OperandLiteralString:

-                word += literalStringWords(literalString(word));

-                return nextInst;

-

-                // Single word operands we simply ignore, as they hold no IDs

-            case spv::OperandLiteralNumber:

-            case spv::OperandSource:

-            case spv::OperandExecutionModel:

-            case spv::OperandAddressing:

-            case spv::OperandMemory:

-            case spv::OperandExecutionMode:

-            case spv::OperandStorage:

-            case spv::OperandDimensionality:

-            case spv::OperandDecoration:

-            case spv::OperandBuiltIn:

-            case spv::OperandSelect:

-            case spv::OperandLoop:

-            case spv::OperandFunction:

-            case spv::OperandMemorySemantics:

-            case spv::OperandMemoryAccess:

-            case spv::OperandExecutionScope:

-            case spv::OperandGroupOperation:

-            case spv::OperandKernelEnqueueFlags:

-            case spv::OperandKernelProfilingInfo:

-                ++word;

-                break;

-

-            default:

-                break;

-            }

-        }

-

-        return nextInst;

-    }

-

-    // Make a pass over all the instructions and process them given appropriate functions

-    spirvbin_t& spirvbin_t::process(instfn_t instFn, idfn_t idFn, unsigned begin, unsigned end)

-    {

-        // For efficiency, reserve name map space.  It can grow if needed.

-        nameMap.reserve(32);

-

-        // If begin or end == 0, use defaults

-        begin = (begin == 0 ? header_size          : begin);

-        end   = (end   == 0 ? unsigned(spv.size()) : end);

-

-        // basic parsing and InstructionDesc table borrowed from SpvDisassemble.cpp...

-        unsigned nextInst = unsigned(spv.size());

-

-        for (unsigned word = begin; word < end; word = nextInst)

-            nextInst = processInstruction(word, instFn, idFn);

-

-        return *this;

-    }

-

-    // Apply global name mapping to a single module

-    void spirvbin_t::mapNames()

-    {

-        static const std::uint32_t softTypeIdLimit = 3011;  // small prime.  TODO: get from options

-        static const std::uint32_t firstMappedID   = 3019;  // offset into ID space

-

-        for (const auto& name : nameMap) {

-            std::uint32_t hashval = 1911;

-            for (const char c : name.first)

-                hashval = hashval * 1009 + c;

-

-            if (isOldIdUnmapped(name.second))

-                localId(name.second, nextUnusedId(hashval % softTypeIdLimit + firstMappedID));

-        }

-    }

-

-    // Map fn contents to IDs of similar functions in other modules

-    void spirvbin_t::mapFnBodies()

-    {

-        static const std::uint32_t softTypeIdLimit = 19071;  // small prime.  TODO: get from options

-        static const std::uint32_t firstMappedID   =  6203;  // offset into ID space

-

-        // Initial approach: go through some high priority opcodes first and assign them

-        // hash values.

-

-        spv::Id               fnId       = spv::NoResult;

-        std::vector<unsigned> instPos;

-        instPos.reserve(unsigned(spv.size()) / 16); // initial estimate; can grow if needed.

-

-        // Build local table of instruction start positions

-        process(

-            [&](spv::Op, unsigned start) { instPos.push_back(start); return true; },

-            op_fn_nop);

-

-        // Window size for context-sensitive canonicalization values

-        // Emperical best size from a single data set.  TODO: Would be a good tunable.

-        // We essentially performa a little convolution around each instruction,

-        // to capture the flavor of nearby code, to hopefully match to similar

-        // code in other modules.

-        static const unsigned windowSize = 2;

-

-        for (unsigned entry = 0; entry < unsigned(instPos.size()); ++entry) {

-            const unsigned start  = instPos[entry];

-            const spv::Op  opCode = asOpCode(start);

-

-            if (opCode == spv::OpFunction)

-                fnId   = asId(start + 2);

-

-            if (opCode == spv::OpFunctionEnd)

-                fnId = spv::NoResult;

-

-            if (fnId != spv::NoResult) { // if inside a function

-                if (spv::InstructionDesc[opCode].hasResult()) {

-                    const unsigned word    = start + (spv::InstructionDesc[opCode].hasType() ? 2 : 1);

-                    const spv::Id  resId   = asId(word);

-                    std::uint32_t  hashval = fnId * 17; // small prime

-

-                    for (unsigned i = entry-1; i >= entry-windowSize; --i) {

-                        if (asOpCode(instPos[i]) == spv::OpFunction)

-                            break;

-                        hashval = hashval * 30103 + asOpCodeHash(instPos[i]); // 30103 = semiarbitrary prime

-                    }

-

-                    for (unsigned i = entry; i <= entry + windowSize; ++i) {

-                        if (asOpCode(instPos[i]) == spv::OpFunctionEnd)

-                            break;

-                        hashval = hashval * 30103 + asOpCodeHash(instPos[i]); // 30103 = semiarbitrary prime

-                    }

-

-                    if (isOldIdUnmapped(resId))

-                        localId(resId, nextUnusedId(hashval % softTypeIdLimit + firstMappedID));

-                }

-            }

-        }

-

-        spv::Op          thisOpCode(spv::OpNop);

-        std::unordered_map<int, int> opCounter;

-        int              idCounter(0);

-        fnId = spv::NoResult;

-

-        process(

-            [&](spv::Op opCode, unsigned start) {

-                switch (opCode) {

-                case spv::OpFunction:

-                    // Reset counters at each function

-                    idCounter = 0;

-                    opCounter.clear();

-                    fnId = asId(start + 2);

-                    break;

-

-                case spv::OpTextureSample:

-                case spv::OpTextureSampleDref:

-                case spv::OpTextureSampleLod:

-                case spv::OpTextureSampleProj:

-                case spv::OpTextureSampleGrad:

-                case spv::OpTextureSampleOffset:

-                case spv::OpTextureSampleProjLod:

-                case spv::OpTextureSampleProjGrad:

-                case spv::OpTextureSampleLodOffset:

-                case spv::OpTextureSampleProjOffset:

-                case spv::OpTextureSampleGradOffset:                     

-                case spv::OpTextureSampleProjLodOffset:

-                case spv::OpTextureSampleProjGradOffset:

-                case spv::OpDot:

-                case spv::OpCompositeExtract:

-                case spv::OpCompositeInsert:

-                case spv::OpVectorShuffle:

-                case spv::OpLabel:

-                case spv::OpVariable:

-

-                case spv::OpAccessChain:

-                case spv::OpLoad:

-                case spv::OpStore:

-                case spv::OpCompositeConstruct:

-                case spv::OpFunctionCall:

-                    ++opCounter[opCode];

-                    idCounter = 0;

-                    thisOpCode = opCode;

-                    break;

-                default:

-                    thisOpCode = spv::OpNop;

-                }

-

-                return false;

-            },

-

-            [&](spv::Id& id) {

-                if (thisOpCode != spv::OpNop) {

-                    ++idCounter;

-                    const std::uint32_t hashval = opCounter[thisOpCode] * thisOpCode * 50047 + idCounter + fnId * 117;

-

-                    if (isOldIdUnmapped(id))

-                        localId(id, nextUnusedId(hashval % softTypeIdLimit + firstMappedID));

-                }

-            });

-    }

-

-    // EXPERIMENTAL: forward IO and uniform load/stores into operands

-    // This produces invalid Schema-0 SPIRV

-    void spirvbin_t::forwardLoadStores()

-    {

-        idset_t fnLocalVars; // set of function local vars

-        idmap_t idMap;       // Map of load result IDs to what they load

-

-        // EXPERIMENTAL: Forward input and access chain loads into consumptions

-        process(

-            [&](spv::Op opCode, unsigned start) {

-                // Add inputs and uniforms to the map

-                if (((opCode == spv::OpVariable && asWordCount(start) == 4) || (opCode == spv::OpVariableArray)) &&

-                    (spv[start+3] == spv::StorageClassUniform ||

-                    spv[start+3] == spv::StorageClassUniformConstant ||

-                    spv[start+3] == spv::StorageClassInput))

-                    fnLocalVars.insert(asId(start+2));

-

-                if (opCode == spv::OpAccessChain && fnLocalVars.count(asId(start+3)) > 0)

-                    fnLocalVars.insert(asId(start+2));

-

-                if (opCode == spv::OpLoad && fnLocalVars.count(asId(start+3)) > 0) {

-                    idMap[asId(start+2)] = asId(start+3);

-                    stripInst(start);

-                }

-

-                return false;

-            },

-

-            [&](spv::Id& id) { if (idMap.find(id) != idMap.end()) id = idMap[id]; }

-        );

-

-        // EXPERIMENTAL: Implicit output stores

-        fnLocalVars.clear();

-        idMap.clear();

-

-        process(

-            [&](spv::Op opCode, unsigned start) {

-                // Add inputs and uniforms to the map

-                if (((opCode == spv::OpVariable && asWordCount(start) == 4) || (opCode == spv::OpVariableArray)) &&

-                    (spv[start+3] == spv::StorageClassOutput))

-                    fnLocalVars.insert(asId(start+2));

-

-                if (opCode == spv::OpStore && fnLocalVars.count(asId(start+1)) > 0) {

-                    idMap[asId(start+2)] = asId(start+1);

-                    stripInst(start);

-                }

-

-                return false;

-            },

-            op_fn_nop);

-

-        process(

-            inst_fn_nop,

-            [&](spv::Id& id) { if (idMap.find(id) != idMap.end()) id = idMap[id]; }

-        );

-

-        strip();          // strip out data we decided to eliminate

-    }

-

-    // remove bodies of uncalled functions

-    void spirvbin_t::optLoadStore()

-    {

-        idset_t fnLocalVars;

-        // Map of load result IDs to what they load

-        idmap_t idMap;

-

-        // Find all the function local pointers stored at most once, and not via access chains

-        process(

-            [&](spv::Op opCode, unsigned start) {

-                const int wordCount = asWordCount(start);

-

-                // Add local variables to the map

-                if ((opCode == spv::OpVariable && spv[start+3] == spv::StorageClassFunction && asWordCount(start) == 4) ||

-                    (opCode == spv::OpVariableArray && spv[start+3] == spv::StorageClassFunction))

-                    fnLocalVars.insert(asId(start+2));

-

-                // Ignore process vars referenced via access chain

-                if ((opCode == spv::OpAccessChain || opCode == spv::OpInBoundsAccessChain) && fnLocalVars.count(asId(start+3)) > 0) {

-                    fnLocalVars.erase(asId(start+3));

-                    idMap.erase(asId(start+3));

-                }

-

-                if (opCode == spv::OpLoad && fnLocalVars.count(asId(start+3)) > 0) {

-                    // Avoid loads before stores (TODO: why?  Crashes driver, but seems like it shouldn't).

-                    if (idMap.find(asId(start+3)) == idMap.end()) {

-                        fnLocalVars.erase(asId(start+3));

-                        idMap.erase(asId(start+3));

-                    }

-

-                    // don't do for volatile references

-                    if (wordCount > 4 && (spv[start+4] & spv::MemoryAccessVolatileMask)) {

-                        fnLocalVars.erase(asId(start+3));

-                        idMap.erase(asId(start+3));

-                    }

-                }

-

-                if (opCode == spv::OpStore && fnLocalVars.count(asId(start+1)) > 0) {

-                    if (idMap.find(asId(start+1)) == idMap.end()) {

-                        idMap[asId(start+1)] = asId(start+2);

-                    } else {

-                        // Remove if it has more than one store to the same pointer

-                        fnLocalVars.erase(asId(start+1));

-                        idMap.erase(asId(start+1));

-                    }

-

-                    // don't do for volatile references

-                    if (wordCount > 3 && (spv[start+3] & spv::MemoryAccessVolatileMask)) {

-                        fnLocalVars.erase(asId(start+3));

-                        idMap.erase(asId(start+3));

-                    }

-                }

-

-                return true;

-            },

-            op_fn_nop);

-

-        process(

-            [&](spv::Op opCode, unsigned start) {

-                if (opCode == spv::OpLoad && fnLocalVars.count(asId(start+3)) > 0)

-                    idMap[asId(start+2)] = idMap[asId(start+3)];

-                return false;

-            },

-            op_fn_nop);

-

-        // Remove the load/store/variables for the ones we've discovered

-        process(

-            [&](spv::Op opCode, unsigned start) {

-                if ((opCode == spv::OpLoad  && fnLocalVars.count(asId(start+3)) > 0) ||

-                    (opCode == spv::OpStore && fnLocalVars.count(asId(start+1)) > 0) ||

-                    (opCode == spv::OpVariable && fnLocalVars.count(asId(start+2)) > 0)) {

-                    stripInst(start);

-                    return true;

-                }

-

-                return false;

-            },

-

-            [&](spv::Id& id) { if (idMap.find(id) != idMap.end()) id = idMap[id]; }

-        );

-

-        strip();          // strip out data we decided to eliminate

-    }

-

-    // remove bodies of uncalled functions

-    void spirvbin_t::dceFuncs()

-    {

-        msg(3, 2, std::string("Removing Dead Functions: "));

-

-        // TODO: There are more efficient ways to do this.

-        bool changed = true;

-

-        while (changed) {

-            changed = false;

-

-            for (auto fn = fnPos.begin(); fn != fnPos.end(); ) {

-                if (fn->first == entryPoint) { // don't DCE away the entry point!

-                    ++fn;

-                    continue;

-                }

-

-                const auto call_it = fnCalls.find(fn->first);

-

-                if (call_it == fnCalls.end() || call_it->second == 0) {

-                    changed = true;

-                    stripRange.push_back(fn->second);

-                    fnPosDCE.insert(*fn);

-

-                    // decrease counts of called functions

-                    process(

-                        [&](spv::Op opCode, unsigned start) {

-                            if (opCode == spv::Op::OpFunctionCall) {

-                                const auto call_it = fnCalls.find(asId(start + 3));

-                                if (call_it != fnCalls.end()) {

-                                    if (--call_it->second <= 0)

-                                        fnCalls.erase(call_it);

-                                }

-                            }

-

-                            return true;

-                        },

-                        op_fn_nop,

-                        fn->second.first,

-                        fn->second.second);

-

-                    fn = fnPos.erase(fn);

-                } else ++fn;

-            }

-        }

-    }

-

-    // remove unused function variables + decorations

-    void spirvbin_t::dceVars()

-    {

-        msg(3, 2, std::string("DCE Vars: "));

-

-        std::unordered_map<spv::Id, int> varUseCount;

-

-        // Count function variable use

-        process(

-            [&](spv::Op opCode, unsigned start) {

-                if (opCode == spv::OpVariable) { ++varUseCount[asId(start+2)]; return true; }

-                return false;

-            },

-

-            [&](spv::Id& id) { if (varUseCount[id]) ++varUseCount[id]; }

-        );

-

-        // Remove single-use function variables + associated decorations and names

-        process(

-            [&](spv::Op opCode, unsigned start) {

-                if ((opCode == spv::OpVariable && varUseCount[asId(start+2)] == 1)  ||

-                    (opCode == spv::OpDecorate && varUseCount[asId(start+1)] == 1)  ||

-                    (opCode == spv::OpName     && varUseCount[asId(start+1)] == 1)) {

-                        stripInst(start);

-                }

-                return true;

-            },

-            op_fn_nop);

-    }

-

-    // remove unused types

-    void spirvbin_t::dceTypes()

-    {

-        std::vector<bool> isType(bound(), false);

-

-        // for speed, make O(1) way to get to type query (map is log(n))

-        for (const auto typeStart : typeConstPos)

-            isType[asTypeConstId(typeStart)] = true;

-

-        std::unordered_map<spv::Id, int> typeUseCount;

-

-        // Count total type usage

-        process(inst_fn_nop,

-            [&](spv::Id& id) { if (isType[id]) ++typeUseCount[id]; }

-        );

-

-        // Remove types from deleted code

-        for (const auto& fn : fnPosDCE)

-            process(inst_fn_nop,

-            [&](spv::Id& id) { if (isType[id]) --typeUseCount[id]; },

-            fn.second.first, fn.second.second);

-

-        // Remove single reference types

-        for (const auto typeStart : typeConstPos) {

-            const spv::Id typeId = asTypeConstId(typeStart);

-            if (typeUseCount[typeId] == 1) {

-                --typeUseCount[typeId];

-                stripInst(typeStart);

-            }

-        }

-    }

-

-

-#ifdef NOTDEF

-    bool spirvbin_t::matchType(const spirvbin_t::globaltypes_t& globalTypes, spv::Id lt, spv::Id gt) const

-    {

-        // Find the local type id "lt" and global type id "gt"

-        const auto lt_it = typeConstPosR.find(lt);

-        if (lt_it == typeConstPosR.end())

-            return false;

-

-        const auto typeStart = lt_it->second;

-

-        // Search for entry in global table

-        const auto gtype = globalTypes.find(gt);

-        if (gtype == globalTypes.end())

-            return false;

-

-        const auto& gdata = gtype->second;

-

-        // local wordcount and opcode

-        const int     wordCount   = asWordCount(typeStart);

-        const spv::Op opCode      = asOpCode(typeStart);

-

-        // no type match if opcodes don't match, or operand count doesn't match

-        if (opCode != opOpCode(gdata[0]) || wordCount != opWordCount(gdata[0]))

-            return false;

-

-        const unsigned numOperands = wordCount - 2; // all types have a result

-

-        const auto cmpIdRange = [&](range_t range) {

-            for (int x=range.first; x<std::min(range.second, wordCount); ++x)

-                if (!matchType(globalTypes, asId(typeStart+x), gdata[x]))

-                    return false;

-            return true;

-        };

-

-        const auto cmpConst   = [&]() { return cmpIdRange(constRange(opCode)); };

-        const auto cmpSubType = [&]() { return cmpIdRange(typeRange(opCode));  };

-

-        // Compare literals in range [start,end)

-        const auto cmpLiteral = [&]() {

-            const auto range = literalRange(opCode);

-            return std::equal(spir.begin() + typeStart + range.first,

-                spir.begin() + typeStart + std::min(range.second, wordCount),

-                gdata.begin() + range.first);

-        };

-

-        assert(isTypeOp(opCode) || isConstOp(opCode));

-

-        switch (opCode) {

-        case spv::OpTypeOpaque:       // TODO: disable until we compare the literal strings.

-        case spv::OpTypeQueue:        return false;

-        case spv::OpTypeEvent:        // fall through...

-        case spv::OpTypeDeviceEvent:  // ...

-        case spv::OpTypeReserveId:    return false;

-            // for samplers, we don't handle the optional parameters yet

-        case spv::OpTypeSampler:      return cmpLiteral() && cmpConst() && cmpSubType() && wordCount == 8;

-        default:                      return cmpLiteral() && cmpConst() && cmpSubType();

-        }

-    }

-

-

-    // Look for an equivalent type in the globalTypes map

-    spv::Id spirvbin_t::findType(const spirvbin_t::globaltypes_t& globalTypes, spv::Id lt) const

-    {

-        // Try a recursive type match on each in turn, and return a match if we find one

-        for (const auto& gt : globalTypes)

-            if (matchType(globalTypes, lt, gt.first))

-                return gt.first;

-

-        return spv::NoType;

-    }

-#endif // NOTDEF

-

-    // Return start position in SPV of given type.  error if not found.

-    unsigned spirvbin_t::typePos(spv::Id id) const

-    {

-        const auto tid_it = typeConstPosR.find(id);

-        if (tid_it == typeConstPosR.end())

-            error("type ID not found");

-

-        return tid_it->second;

-    }

-

-    // Hash types to canonical values.  This can return ID collisions (it's a bit

-    // inevitable): it's up to the caller to handle that gracefully.

-    std::uint32_t spirvbin_t::hashType(unsigned typeStart) const

-    {

-        const unsigned wordCount   = asWordCount(typeStart);

-        const spv::Op  opCode      = asOpCode(typeStart);

-

-        switch (opCode) {

-        case spv::OpTypeVoid:         return 0;

-        case spv::OpTypeBool:         return 1;

-        case spv::OpTypeInt:          return 3 + (spv[typeStart+3]);

-        case spv::OpTypeFloat:        return 5;

-        case spv::OpTypeVector:

-            return 6 + hashType(typePos(spv[typeStart+2])) * (spv[typeStart+3] - 1);

-        case spv::OpTypeMatrix:

-            return 30 + hashType(typePos(spv[typeStart+2])) * (spv[typeStart+3] - 1);

-        case spv::OpTypeSampler:

-            return 120 + hashType(typePos(spv[typeStart+2])) +

-                spv[typeStart+3] +            // dimensionality

-                spv[typeStart+4] * 8 * 16 +   // content

-                spv[typeStart+5] * 4 * 16 +   // arrayed

-                spv[typeStart+6] * 2 * 16 +   // compare

-                spv[typeStart+7] * 1 * 16;    // multisampled

-        case spv::OpTypeFilter:

-            return 500;

-        case spv::OpTypeArray:

-            return 501 + hashType(typePos(spv[typeStart+2])) * spv[typeStart+3];

-        case spv::OpTypeRuntimeArray:

-            return 5000  + hashType(typePos(spv[typeStart+2]));

-        case spv::OpTypeStruct:

-            {

-                std::uint32_t hash = 10000;

-                for (unsigned w=2; w < wordCount; ++w)

-                    hash += w * hashType(typePos(spv[typeStart+w]));

-                return hash;

-            }

-

-        case spv::OpTypeOpaque:         return 6000 + spv[typeStart+2];

-        case spv::OpTypePointer:        return 100000  + hashType(typePos(spv[typeStart+3]));

-        case spv::OpTypeFunction:

-            {

-                std::uint32_t hash = 200000;

-                for (unsigned w=2; w < wordCount; ++w)

-                    hash += w * hashType(typePos(spv[typeStart+w]));

-                return hash;

-            }

-

-        case spv::OpTypeEvent:           return 300000;

-        case spv::OpTypeDeviceEvent:     return 300001;

-        case spv::OpTypeReserveId:       return 300002;

-        case spv::OpTypeQueue:           return 300003;

-        case spv::OpTypePipe:            return 300004;

-

-        case spv::OpConstantNullObject:  return 300005;

-        case spv::OpConstantSampler:     return 300006;

-

-        case spv::OpConstantTrue:        return 300007;

-        case spv::OpConstantFalse:       return 300008;

-        case spv::OpConstantNullPointer: return 300009;

-        case spv::OpConstantComposite:

-            {

-                std::uint32_t hash = 300011 + hashType(typePos(spv[typeStart+1]));

-                for (unsigned w=3; w < wordCount; ++w)

-                    hash += w * hashType(typePos(spv[typeStart+w]));

-                return hash;

-            }

-        case spv::OpConstant:

-            {

-                std::uint32_t hash = 400011 + hashType(typePos(spv[typeStart+1]));

-                for (unsigned w=3; w < wordCount; ++w)

-                    hash += w * spv[typeStart+w];

-                return hash;

-            }

-

-        default:

-            error("unknown type opcode");

-            return 0;

-        }

-    }

-

-    void spirvbin_t::mapTypeConst()

-    {

-        globaltypes_t globalTypeMap;

-

-        msg(3, 2, std::string("Remapping Consts & Types: "));

-

-        static const std::uint32_t softTypeIdLimit = 3011; // small prime.  TODO: get from options

-        static const std::uint32_t firstMappedID   = 8;    // offset into ID space

-

-        for (auto& typeStart : typeConstPos) {

-            const spv::Id       resId     = asTypeConstId(typeStart);

-            const std::uint32_t hashval   = hashType(typeStart);

-

-            if (isOldIdUnmapped(resId))

-                localId(resId, nextUnusedId(hashval % softTypeIdLimit + firstMappedID));

-        }

-    }

-

-

-    // Strip a single binary by removing ranges given in stripRange

-    void spirvbin_t::strip()

-    {

-        if (stripRange.empty()) // nothing to do

-            return;

-

-        // Sort strip ranges in order of traversal

-        std::sort(stripRange.begin(), stripRange.end());

-

-        // Allocate a new binary big enough to hold old binary

-        // We'll step this iterator through the strip ranges as we go through the binary

-        auto strip_it = stripRange.begin();

-

-        int strippedPos = 0;

-        for (unsigned word = 0; word < unsigned(spv.size()); ++word) {

-            if (strip_it != stripRange.end() && word >= strip_it->second)

-                ++strip_it;

-

-            if (strip_it == stripRange.end() || word < strip_it->first || word >= strip_it->second)

-                spv[strippedPos++] = spv[word];

-        }

-

-        spv.resize(strippedPos);

-        stripRange.clear();

-

-        buildLocalMaps();

-    }

-

-    // Strip a single binary by removing ranges given in stripRange

-    void spirvbin_t::remap(std::uint32_t opts)

-    {

-        options = opts;

-

-        // Set up opcode tables from SpvDoc

-        spv::Parameterize();

-

-        validate();  // validate header

-        buildLocalMaps();

-

-        msg(3, 4, std::string("ID bound: ") + std::to_string(bound()));

-

-        strip();        // strip out data we decided to eliminate

-

-        if (options & OPT_LOADSTORE) optLoadStore();

-        if (options & OPT_FWD_LS)    forwardLoadStores();

-        if (options & DCE_FUNCS)     dceFuncs();

-        if (options & DCE_VARS)      dceVars();

-        if (options & DCE_TYPES)     dceTypes();

-        if (options & MAP_TYPES)     mapTypeConst();

-        if (options & MAP_NAMES)     mapNames();

-        if (options & MAP_FUNCS)     mapFnBodies();

-

-        mapRemainder(); // map any unmapped IDs

-        applyMap();     // Now remap each shader to the new IDs we've come up with

-        strip();        // strip out data we decided to eliminate

-    }

-

-    // remap from a memory image

-    void spirvbin_t::remap(std::vector<std::uint32_t>& in_spv, std::uint32_t opts)

-    {

-        spv.swap(in_spv);

-        remap(opts);

-        spv.swap(in_spv);

-    }

-

-} // namespace SPV

-

-#endif // defined (use_cpp11)

-

+//
+//Copyright (C) 2015 LunarG, Inc.
+//
+//All rights reserved.
+//
+//Redistribution and use in source and binary forms, with or without
+//modification, are permitted provided that the following conditions
+//are met:
+//
+//    Redistributions of source code must retain the above copyright
+//    notice, this list of conditions and the following disclaimer.
+//
+//    Redistributions in binary form must reproduce the above
+//    copyright notice, this list of conditions and the following
+//    disclaimer in the documentation and/or other materials provided
+//    with the distribution.
+//
+//    Neither the name of 3Dlabs Inc. Ltd. nor the names of its
+//    contributors may be used to endorse or promote products derived
+//    from this software without specific prior written permission.
+//
+//THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+//"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+//LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+//FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+//COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+//INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+//BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+//LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+//CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+//LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+//ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+//POSSIBILITY OF SUCH DAMAGE.
+//
+
+#include "SPVRemapper.h"
+#include "doc.h"
+
+#if !defined (use_cpp11)
+// ... not supported before C++11
+#else // defined (use_cpp11)
+
+#include <algorithm>
+#include <cassert>
+
+namespace spv {
+
+    // By default, just abort on error.  Can be overridden via RegisterErrorHandler
+    spirvbin_t::errorfn_t spirvbin_t::errorHandler = [](const std::string&) { exit(5); };
+    // By default, eat log messages.  Can be overridden via RegisterLogHandler
+    spirvbin_t::logfn_t   spirvbin_t::logHandler   = [](const std::string&) { };
+
+    // This can be overridden to provide other message behavior if needed
+    void spirvbin_t::msg(int minVerbosity, int indent, const std::string& txt) const
+    {
+        if (verbose >= minVerbosity)
+            logHandler(std::string(indent, ' ') + txt);
+    }
+
+    // hash opcode, with special handling for OpExtInst
+    std::uint32_t spirvbin_t::asOpCodeHash(unsigned word)
+    {
+        const spv::Op opCode = asOpCode(word);
+
+        std::uint32_t offset = 0;
+
+        switch (opCode) {
+        case spv::OpExtInst:
+            offset += asId(word + 4); break;
+        default:
+            break;
+        }
+
+        return opCode * 19 + offset; // 19 = small prime
+    }
+
+    spirvbin_t::range_t spirvbin_t::literalRange(spv::Op opCode) const
+    {
+        static const int maxCount = 1<<30;
+
+        switch (opCode) {
+        case spv::OpTypeFloat:        // fall through...
+        case spv::OpTypePointer:      return range_t(2, 3);
+        case spv::OpTypeInt:          return range_t(2, 4);
+        case spv::OpTypeSampler:      return range_t(3, 8);
+        case spv::OpTypeVector:       // fall through
+        case spv::OpTypeMatrix:       // ...
+        case spv::OpTypePipe:         return range_t(3, 4);
+        case spv::OpConstant:         return range_t(3, maxCount);
+        default:                      return range_t(0, 0);
+        }
+    }
+
+    spirvbin_t::range_t spirvbin_t::typeRange(spv::Op opCode) const
+    {
+        static const int maxCount = 1<<30;
+
+        if (isConstOp(opCode))
+            return range_t(1, 2);
+
+        switch (opCode) {
+        case spv::OpTypeVector:       // fall through
+        case spv::OpTypeMatrix:       // ... 
+        case spv::OpTypeSampler:      // ... 
+        case spv::OpTypeArray:        // ... 
+        case spv::OpTypeRuntimeArray: // ... 
+        case spv::OpTypePipe:         return range_t(2, 3);
+        case spv::OpTypeStruct:       // fall through
+        case spv::OpTypeFunction:     return range_t(2, maxCount);
+        case spv::OpTypePointer:      return range_t(3, 4);
+        default:                      return range_t(0, 0);
+        }
+    }
+
+    spirvbin_t::range_t spirvbin_t::constRange(spv::Op opCode) const
+    {
+        static const int maxCount = 1<<30;
+
+        switch (opCode) {
+        case spv::OpTypeArray:         // fall through...
+        case spv::OpTypeRuntimeArray:  return range_t(3, 4);
+        case spv::OpConstantComposite: return range_t(3, maxCount);
+        default:                       return range_t(0, 0);
+        }
+    }
+
+    // Is this an opcode we should remove when using --strip?
+    bool spirvbin_t::isStripOp(spv::Op opCode) const
+    {
+        switch (opCode) {
+        case spv::OpSource:
+        case spv::OpSourceExtension:
+        case spv::OpName:
+        case spv::OpMemberName:
+        case spv::OpLine:           return true;
+        default:                    return false;
+        }
+    }
+
+    bool spirvbin_t::isFlowCtrlOpen(spv::Op opCode) const
+    {
+        switch (opCode) {
+        case spv::OpBranchConditional:
+        case spv::OpSwitch:         return true;
+        default:                    return false;
+        }
+    }
+
+    bool spirvbin_t::isFlowCtrlClose(spv::Op opCode) const
+    {
+        switch (opCode) {
+        case spv::OpLoopMerge:
+        case spv::OpSelectionMerge: return true;
+        default:                    return false;
+        }
+    }
+
+    bool spirvbin_t::isTypeOp(spv::Op opCode) const
+    {
+        switch (opCode) {
+        case spv::OpTypeVoid:
+        case spv::OpTypeBool:
+        case spv::OpTypeInt:
+        case spv::OpTypeFloat:
+        case spv::OpTypeVector:
+        case spv::OpTypeMatrix:
+        case spv::OpTypeSampler:
+        case spv::OpTypeFilter:
+        case spv::OpTypeArray:
+        case spv::OpTypeRuntimeArray:
+        case spv::OpTypeStruct:
+        case spv::OpTypeOpaque:
+        case spv::OpTypePointer:
+        case spv::OpTypeFunction:
+        case spv::OpTypeEvent:
+        case spv::OpTypeDeviceEvent:
+        case spv::OpTypeReserveId:
+        case spv::OpTypeQueue:
+        case spv::OpTypePipe:         return true;
+        default:                      return false;
+        }
+    }
+
+    bool spirvbin_t::isConstOp(spv::Op opCode) const
+    {
+        switch (opCode) {
+        case spv::OpConstantNullObject: error("unimplemented constant type");
+        case spv::OpConstantSampler:    error("unimplemented constant type");
+
+        case spv::OpConstantTrue:
+        case spv::OpConstantFalse:
+        case spv::OpConstantNullPointer:
+        case spv::OpConstantComposite:
+        case spv::OpConstant:         return true;
+        default:                      return false;
+        }
+    }
+
+    const auto inst_fn_nop = [](spv::Op, unsigned) { return false; };
+    const auto op_fn_nop   = [](spv::Id&)          { };
+
+    // g++ doesn't like these defined in the class proper in an anonymous namespace.
+    // Dunno why.  Also MSVC doesn't like the constexpr keyword.  Also dunno why.
+    // Defining them externally seems to please both compilers, so, here they are.
+    const spv::Id spirvbin_t::unmapped    = spv::Id(-10000);
+    const spv::Id spirvbin_t::unused      = spv::Id(-10001);
+    const int     spirvbin_t::header_size = 5;
+
+    spv::Id spirvbin_t::nextUnusedId(spv::Id id)
+    {
+        while (isNewIdMapped(id))  // search for an unused ID
+            ++id;
+
+        return id;
+    }
+
+    spv::Id spirvbin_t::localId(spv::Id id, spv::Id newId)
+    {
+        assert(id != spv::NoResult && newId != spv::NoResult);
+
+        if (id >= idMapL.size())
+            idMapL.resize(id+1, unused);
+
+        if (newId != unmapped && newId != unused) {
+            if (isOldIdUnused(id))
+                error(std::string("ID unused in module: ") + std::to_string(id));
+
+            if (!isOldIdUnmapped(id))
+                error(std::string("ID already mapped: ") + std::to_string(id) + " -> "
+                + std::to_string(localId(id)));
+
+            if (isNewIdMapped(newId))
+                error(std::string("ID already used in module: ") + std::to_string(newId));
+
+            msg(4, 4, std::string("map: ") + std::to_string(id) + " -> " + std::to_string(newId));
+            setMapped(newId);
+            largestNewId = std::max(largestNewId, newId);
+        }
+
+        return idMapL[id] = newId;
+    }
+
+    // Parse a literal string from the SPIR binary and return it as an std::string
+    // Due to C++11 RValue references, this doesn't copy the result string.
+    std::string spirvbin_t::literalString(unsigned word) const
+    {
+        std::string literal;
+
+        literal.reserve(16);
+
+        const char* bytes = reinterpret_cast<const char*>(spv.data() + word);
+
+        while (bytes && *bytes)
+            literal += *bytes++;
+
+        return literal;
+    }
+
+
+    void spirvbin_t::applyMap()
+    {
+        msg(3, 2, std::string("Applying map: "));
+
+        // Map local IDs through the ID map
+        process(inst_fn_nop, // ignore instructions
+            [this](spv::Id& id) {
+                id = localId(id);
+                assert(id != unused && id != unmapped);
+            }
+        );
+    }
+
+
+    // Find free IDs for anything we haven't mapped
+    void spirvbin_t::mapRemainder()
+    {
+        msg(3, 2, std::string("Remapping remainder: "));
+
+        spv::Id     unusedId  = 1;  // can't use 0: that's NoResult
+        spirword_t  maxBound  = 0;
+
+        for (spv::Id id = 0; id < idMapL.size(); ++id) {
+            if (isOldIdUnused(id))
+                continue;
+
+            // Find a new mapping for any used but unmapped IDs
+            if (isOldIdUnmapped(id))
+                localId(id, unusedId = nextUnusedId(unusedId));
+
+            if (isOldIdUnmapped(id))
+                error(std::string("old ID not mapped: ") + std::to_string(id));
+
+            // Track max bound
+            maxBound = std::max(maxBound, localId(id) + 1);
+        }
+
+        bound(maxBound); // reset header ID bound to as big as it now needs to be
+    }
+
+    void spirvbin_t::stripDebug()
+    {
+        if ((options & STRIP) == 0)
+            return;
+
+        // build local Id and name maps
+        process(
+            [&](spv::Op opCode, unsigned start) {
+                // remember opcodes we want to strip later
+                if (isStripOp(opCode))
+                    stripInst(start);
+                return true;
+            },
+            op_fn_nop);
+    }
+
+    void spirvbin_t::buildLocalMaps()
+    {
+        msg(2, 2, std::string("build local maps: "));
+
+        mapped.clear();
+        idMapL.clear();
+//      preserve nameMap, so we don't clear that.
+        fnPos.clear();
+        fnPosDCE.clear();
+        fnCalls.clear();
+        typeConstPos.clear();
+        typeConstPosR.clear();
+        entryPoint = spv::NoResult;
+        largestNewId = 0;
+
+        idMapL.resize(bound(), unused);
+
+        int         fnStart = 0;
+        spv::Id     fnRes   = spv::NoResult;
+
+        // build local Id and name maps
+        process(
+            [&](spv::Op opCode, unsigned start) {
+                // remember opcodes we want to strip later
+                if ((options & STRIP) && isStripOp(opCode))
+                    stripInst(start);
+
+                if (opCode == spv::Op::OpName) {
+                    const spv::Id    target = asId(start+1);
+                    const std::string  name = literalString(start+2);
+                    nameMap[name] = target;
+
+                } else if (opCode == spv::Op::OpFunctionCall) {
+                    ++fnCalls[asId(start + 3)];
+                } else if (opCode == spv::Op::OpEntryPoint) {
+                    entryPoint = asId(start + 2);
+                } else if (opCode == spv::Op::OpFunction) {
+                    if (fnStart != 0)
+                        error("nested function found");
+                    fnStart = start;
+                    fnRes   = asId(start + 2);
+                } else if (opCode == spv::Op::OpFunctionEnd) {
+                    assert(fnRes != spv::NoResult);
+                    if (fnStart == 0)
+                        error("function end without function start");
+                    fnPos[fnRes] = range_t(fnStart, start + asWordCount(start));
+                    fnStart = 0;
+                } else if (isConstOp(opCode)) {
+                    assert(asId(start + 2) != spv::NoResult);
+                    typeConstPos.insert(start);
+                    typeConstPosR[asId(start + 2)] = start;
+                } else if (isTypeOp(opCode)) {
+                    assert(asId(start + 1) != spv::NoResult);
+                    typeConstPos.insert(start);
+                    typeConstPosR[asId(start + 1)] = start;
+                }
+
+                return false;
+            },
+
+            [this](spv::Id& id) { localId(id, unmapped); }
+        );
+    }
+
+    // Validate the SPIR header
+    void spirvbin_t::validate() const
+    {
+        msg(2, 2, std::string("validating: "));
+
+        if (spv.size() < header_size)
+            error("file too short: ");
+
+        if (magic() != spv::MagicNumber)
+            error("bad magic number");
+
+        // field 1 = version
+        // field 2 = generator magic
+        // field 3 = result <id> bound
+
+        if (schemaNum() != 0)
+            error("bad schema, must be 0");
+    }
+
+
+    int spirvbin_t::processInstruction(unsigned word, instfn_t instFn, idfn_t idFn)
+    {
+        const auto     instructionStart = word;
+        const unsigned wordCount = asWordCount(instructionStart);
+        const spv::Op  opCode    = asOpCode(instructionStart);
+        const int      nextInst  = word++ + wordCount;
+
+        if (nextInst > int(spv.size()))
+            error("spir instruction terminated too early");
+
+        // Base for computing number of operands; will be updated as more is learned
+        unsigned numOperands = wordCount - 1;
+
+        if (instFn(opCode, instructionStart))
+            return nextInst;
+
+        // Read type and result ID from instruction desc table
+        if (spv::InstructionDesc[opCode].hasType()) {
+            idFn(asId(word++));
+            --numOperands;
+        }
+
+        if (spv::InstructionDesc[opCode].hasResult()) {
+            idFn(asId(word++));
+            --numOperands;
+        }
+
+        // Extended instructions: currently, assume everything is an ID.
+        // TODO: add whatever data we need for exceptions to that
+        if (opCode == spv::OpExtInst) {
+            word        += 2; // instruction set, and instruction from set
+            numOperands -= 2;
+
+            for (unsigned op=0; op < numOperands; ++op)
+                idFn(asId(word++)); // ID
+
+            return nextInst;
+        }
+
+        // Store IDs from instruction in our map
+        for (int op = 0; op < spv::InstructionDesc[opCode].operands.getNum(); ++op, --numOperands) {
+            switch (spv::InstructionDesc[opCode].operands.getClass(op)) {
+            case spv::OperandId:
+                idFn(asId(word++));
+                break;
+
+            case spv::OperandOptionalId:
+            case spv::OperandVariableIds:
+                for (unsigned i = 0; i < numOperands; ++i)
+                    idFn(asId(word++));
+                return nextInst;
+
+            case spv::OperandVariableLiterals:
+                if (opCode == spv::OpDecorate && asDecoration(word - 1) == spv::DecorationBuiltIn) {
+                    ++word;
+                    --numOperands;
+                }
+                word += numOperands;
+                return nextInst;
+
+            case spv::OperandVariableLiteralId:
+                while (numOperands > 0) {
+                    ++word;             // immediate
+                    idFn(asId(word++)); // ID
+                    numOperands -= 2;
+                }
+                return nextInst;
+
+            case spv::OperandLiteralString:
+                word += literalStringWords(literalString(word));
+                return nextInst;
+
+                // Single word operands we simply ignore, as they hold no IDs
+            case spv::OperandLiteralNumber:
+            case spv::OperandSource:
+            case spv::OperandExecutionModel:
+            case spv::OperandAddressing:
+            case spv::OperandMemory:
+            case spv::OperandExecutionMode:
+            case spv::OperandStorage:
+            case spv::OperandDimensionality:
+            case spv::OperandDecoration:
+            case spv::OperandBuiltIn:
+            case spv::OperandSelect:
+            case spv::OperandLoop:
+            case spv::OperandFunction:
+            case spv::OperandMemorySemantics:
+            case spv::OperandMemoryAccess:
+            case spv::OperandExecutionScope:
+            case spv::OperandGroupOperation:
+            case spv::OperandKernelEnqueueFlags:
+            case spv::OperandKernelProfilingInfo:
+                ++word;
+                break;
+
+            default:
+                break;
+            }
+        }
+
+        return nextInst;
+    }
+
+    // Make a pass over all the instructions and process them given appropriate functions
+    spirvbin_t& spirvbin_t::process(instfn_t instFn, idfn_t idFn, unsigned begin, unsigned end)
+    {
+        // For efficiency, reserve name map space.  It can grow if needed.
+        nameMap.reserve(32);
+
+        // If begin or end == 0, use defaults
+        begin = (begin == 0 ? header_size          : begin);
+        end   = (end   == 0 ? unsigned(spv.size()) : end);
+
+        // basic parsing and InstructionDesc table borrowed from SpvDisassemble.cpp...
+        unsigned nextInst = unsigned(spv.size());
+
+        for (unsigned word = begin; word < end; word = nextInst)
+            nextInst = processInstruction(word, instFn, idFn);
+
+        return *this;
+    }
+
+    // Apply global name mapping to a single module
+    void spirvbin_t::mapNames()
+    {
+        static const std::uint32_t softTypeIdLimit = 3011;  // small prime.  TODO: get from options
+        static const std::uint32_t firstMappedID   = 3019;  // offset into ID space
+
+        for (const auto& name : nameMap) {
+            std::uint32_t hashval = 1911;
+            for (const char c : name.first)
+                hashval = hashval * 1009 + c;
+
+            if (isOldIdUnmapped(name.second))
+                localId(name.second, nextUnusedId(hashval % softTypeIdLimit + firstMappedID));
+        }
+    }
+
+    // Map fn contents to IDs of similar functions in other modules
+    void spirvbin_t::mapFnBodies()
+    {
+        static const std::uint32_t softTypeIdLimit = 19071;  // small prime.  TODO: get from options
+        static const std::uint32_t firstMappedID   =  6203;  // offset into ID space
+
+        // Initial approach: go through some high priority opcodes first and assign them
+        // hash values.
+
+        spv::Id               fnId       = spv::NoResult;
+        std::vector<unsigned> instPos;
+        instPos.reserve(unsigned(spv.size()) / 16); // initial estimate; can grow if needed.
+
+        // Build local table of instruction start positions
+        process(
+            [&](spv::Op, unsigned start) { instPos.push_back(start); return true; },
+            op_fn_nop);
+
+        // Window size for context-sensitive canonicalization values
+        // Emperical best size from a single data set.  TODO: Would be a good tunable.
+        // We essentially performa a little convolution around each instruction,
+        // to capture the flavor of nearby code, to hopefully match to similar
+        // code in other modules.
+        static const unsigned windowSize = 2;
+
+        for (unsigned entry = 0; entry < unsigned(instPos.size()); ++entry) {
+            const unsigned start  = instPos[entry];
+            const spv::Op  opCode = asOpCode(start);
+
+            if (opCode == spv::OpFunction)
+                fnId   = asId(start + 2);
+
+            if (opCode == spv::OpFunctionEnd)
+                fnId = spv::NoResult;
+
+            if (fnId != spv::NoResult) { // if inside a function
+                if (spv::InstructionDesc[opCode].hasResult()) {
+                    const unsigned word    = start + (spv::InstructionDesc[opCode].hasType() ? 2 : 1);
+                    const spv::Id  resId   = asId(word);
+                    std::uint32_t  hashval = fnId * 17; // small prime
+
+                    for (unsigned i = entry-1; i >= entry-windowSize; --i) {
+                        if (asOpCode(instPos[i]) == spv::OpFunction)
+                            break;
+                        hashval = hashval * 30103 + asOpCodeHash(instPos[i]); // 30103 = semiarbitrary prime
+                    }
+
+                    for (unsigned i = entry; i <= entry + windowSize; ++i) {
+                        if (asOpCode(instPos[i]) == spv::OpFunctionEnd)
+                            break;
+                        hashval = hashval * 30103 + asOpCodeHash(instPos[i]); // 30103 = semiarbitrary prime
+                    }
+
+                    if (isOldIdUnmapped(resId))
+                        localId(resId, nextUnusedId(hashval % softTypeIdLimit + firstMappedID));
+                }
+            }
+        }
+
+        spv::Op          thisOpCode(spv::OpNop);
+        std::unordered_map<int, int> opCounter;
+        int              idCounter(0);
+        fnId = spv::NoResult;
+
+        process(
+            [&](spv::Op opCode, unsigned start) {
+                switch (opCode) {
+                case spv::OpFunction:
+                    // Reset counters at each function
+                    idCounter = 0;
+                    opCounter.clear();
+                    fnId = asId(start + 2);
+                    break;
+
+                case spv::OpTextureSample:
+                case spv::OpTextureSampleDref:
+                case spv::OpTextureSampleLod:
+                case spv::OpTextureSampleProj:
+                case spv::OpTextureSampleGrad:
+                case spv::OpTextureSampleOffset:
+                case spv::OpTextureSampleProjLod:
+                case spv::OpTextureSampleProjGrad:
+                case spv::OpTextureSampleLodOffset:
+                case spv::OpTextureSampleProjOffset:
+                case spv::OpTextureSampleGradOffset:                     
+                case spv::OpTextureSampleProjLodOffset:
+                case spv::OpTextureSampleProjGradOffset:
+                case spv::OpDot:
+                case spv::OpCompositeExtract:
+                case spv::OpCompositeInsert:
+                case spv::OpVectorShuffle:
+                case spv::OpLabel:
+                case spv::OpVariable:
+
+                case spv::OpAccessChain:
+                case spv::OpLoad:
+                case spv::OpStore:
+                case spv::OpCompositeConstruct:
+                case spv::OpFunctionCall:
+                    ++opCounter[opCode];
+                    idCounter = 0;
+                    thisOpCode = opCode;
+                    break;
+                default:
+                    thisOpCode = spv::OpNop;
+                }
+
+                return false;
+            },
+
+            [&](spv::Id& id) {
+                if (thisOpCode != spv::OpNop) {
+                    ++idCounter;
+                    const std::uint32_t hashval = opCounter[thisOpCode] * thisOpCode * 50047 + idCounter + fnId * 117;
+
+                    if (isOldIdUnmapped(id))
+                        localId(id, nextUnusedId(hashval % softTypeIdLimit + firstMappedID));
+                }
+            });
+    }
+
+    // EXPERIMENTAL: forward IO and uniform load/stores into operands
+    // This produces invalid Schema-0 SPIRV
+    void spirvbin_t::forwardLoadStores()
+    {
+        idset_t fnLocalVars; // set of function local vars
+        idmap_t idMap;       // Map of load result IDs to what they load
+
+        // EXPERIMENTAL: Forward input and access chain loads into consumptions
+        process(
+            [&](spv::Op opCode, unsigned start) {
+                // Add inputs and uniforms to the map
+                if (((opCode == spv::OpVariable && asWordCount(start) == 4) || (opCode == spv::OpVariableArray)) &&
+                    (spv[start+3] == spv::StorageClassUniform ||
+                    spv[start+3] == spv::StorageClassUniformConstant ||
+                    spv[start+3] == spv::StorageClassInput))
+                    fnLocalVars.insert(asId(start+2));
+
+                if (opCode == spv::OpAccessChain && fnLocalVars.count(asId(start+3)) > 0)
+                    fnLocalVars.insert(asId(start+2));
+
+                if (opCode == spv::OpLoad && fnLocalVars.count(asId(start+3)) > 0) {
+                    idMap[asId(start+2)] = asId(start+3);
+                    stripInst(start);
+                }
+
+                return false;
+            },
+
+            [&](spv::Id& id) { if (idMap.find(id) != idMap.end()) id = idMap[id]; }
+        );
+
+        // EXPERIMENTAL: Implicit output stores
+        fnLocalVars.clear();
+        idMap.clear();
+
+        process(
+            [&](spv::Op opCode, unsigned start) {
+                // Add inputs and uniforms to the map
+                if (((opCode == spv::OpVariable && asWordCount(start) == 4) || (opCode == spv::OpVariableArray)) &&
+                    (spv[start+3] == spv::StorageClassOutput))
+                    fnLocalVars.insert(asId(start+2));
+
+                if (opCode == spv::OpStore && fnLocalVars.count(asId(start+1)) > 0) {
+                    idMap[asId(start+2)] = asId(start+1);
+                    stripInst(start);
+                }
+
+                return false;
+            },
+            op_fn_nop);
+
+        process(
+            inst_fn_nop,
+            [&](spv::Id& id) { if (idMap.find(id) != idMap.end()) id = idMap[id]; }
+        );
+
+        strip();          // strip out data we decided to eliminate
+    }
+
+    // remove bodies of uncalled functions
+    void spirvbin_t::optLoadStore()
+    {
+        idset_t fnLocalVars;
+        // Map of load result IDs to what they load
+        idmap_t idMap;
+
+        // Find all the function local pointers stored at most once, and not via access chains
+        process(
+            [&](spv::Op opCode, unsigned start) {
+                const int wordCount = asWordCount(start);
+
+                // Add local variables to the map
+                if ((opCode == spv::OpVariable && spv[start+3] == spv::StorageClassFunction && asWordCount(start) == 4) ||
+                    (opCode == spv::OpVariableArray && spv[start+3] == spv::StorageClassFunction))
+                    fnLocalVars.insert(asId(start+2));
+
+                // Ignore process vars referenced via access chain
+                if ((opCode == spv::OpAccessChain || opCode == spv::OpInBoundsAccessChain) && fnLocalVars.count(asId(start+3)) > 0) {
+                    fnLocalVars.erase(asId(start+3));
+                    idMap.erase(asId(start+3));
+                }
+
+                if (opCode == spv::OpLoad && fnLocalVars.count(asId(start+3)) > 0) {
+                    // Avoid loads before stores (TODO: why?  Crashes driver, but seems like it shouldn't).
+                    if (idMap.find(asId(start+3)) == idMap.end()) {
+                        fnLocalVars.erase(asId(start+3));
+                        idMap.erase(asId(start+3));
+                    }
+
+                    // don't do for volatile references
+                    if (wordCount > 4 && (spv[start+4] & spv::MemoryAccessVolatileMask)) {
+                        fnLocalVars.erase(asId(start+3));
+                        idMap.erase(asId(start+3));
+                    }
+                }
+
+                if (opCode == spv::OpStore && fnLocalVars.count(asId(start+1)) > 0) {
+                    if (idMap.find(asId(start+1)) == idMap.end()) {
+                        idMap[asId(start+1)] = asId(start+2);
+                    } else {
+                        // Remove if it has more than one store to the same pointer
+                        fnLocalVars.erase(asId(start+1));
+                        idMap.erase(asId(start+1));
+                    }
+
+                    // don't do for volatile references
+                    if (wordCount > 3 && (spv[start+3] & spv::MemoryAccessVolatileMask)) {
+                        fnLocalVars.erase(asId(start+3));
+                        idMap.erase(asId(start+3));
+                    }
+                }
+
+                return true;
+            },
+            op_fn_nop);
+
+        process(
+            [&](spv::Op opCode, unsigned start) {
+                if (opCode == spv::OpLoad && fnLocalVars.count(asId(start+3)) > 0)
+                    idMap[asId(start+2)] = idMap[asId(start+3)];
+                return false;
+            },
+            op_fn_nop);
+
+        // Remove the load/store/variables for the ones we've discovered
+        process(
+            [&](spv::Op opCode, unsigned start) {
+                if ((opCode == spv::OpLoad  && fnLocalVars.count(asId(start+3)) > 0) ||
+                    (opCode == spv::OpStore && fnLocalVars.count(asId(start+1)) > 0) ||
+                    (opCode == spv::OpVariable && fnLocalVars.count(asId(start+2)) > 0)) {
+                    stripInst(start);
+                    return true;
+                }
+
+                return false;
+            },
+
+            [&](spv::Id& id) { if (idMap.find(id) != idMap.end()) id = idMap[id]; }
+        );
+
+        strip();          // strip out data we decided to eliminate
+    }
+
+    // remove bodies of uncalled functions
+    void spirvbin_t::dceFuncs()
+    {
+        msg(3, 2, std::string("Removing Dead Functions: "));
+
+        // TODO: There are more efficient ways to do this.
+        bool changed = true;
+
+        while (changed) {
+            changed = false;
+
+            for (auto fn = fnPos.begin(); fn != fnPos.end(); ) {
+                if (fn->first == entryPoint) { // don't DCE away the entry point!
+                    ++fn;
+                    continue;
+                }
+
+                const auto call_it = fnCalls.find(fn->first);
+
+                if (call_it == fnCalls.end() || call_it->second == 0) {
+                    changed = true;
+                    stripRange.push_back(fn->second);
+                    fnPosDCE.insert(*fn);
+
+                    // decrease counts of called functions
+                    process(
+                        [&](spv::Op opCode, unsigned start) {
+                            if (opCode == spv::Op::OpFunctionCall) {
+                                const auto call_it = fnCalls.find(asId(start + 3));
+                                if (call_it != fnCalls.end()) {
+                                    if (--call_it->second <= 0)
+                                        fnCalls.erase(call_it);
+                                }
+                            }
+
+                            return true;
+                        },
+                        op_fn_nop,
+                        fn->second.first,
+                        fn->second.second);
+
+                    fn = fnPos.erase(fn);
+                } else ++fn;
+            }
+        }
+    }
+
+    // remove unused function variables + decorations
+    void spirvbin_t::dceVars()
+    {
+        msg(3, 2, std::string("DCE Vars: "));
+
+        std::unordered_map<spv::Id, int> varUseCount;
+
+        // Count function variable use
+        process(
+            [&](spv::Op opCode, unsigned start) {
+                if (opCode == spv::OpVariable) { ++varUseCount[asId(start+2)]; return true; }
+                return false;
+            },
+
+            [&](spv::Id& id) { if (varUseCount[id]) ++varUseCount[id]; }
+        );
+
+        // Remove single-use function variables + associated decorations and names
+        process(
+            [&](spv::Op opCode, unsigned start) {
+                if ((opCode == spv::OpVariable && varUseCount[asId(start+2)] == 1)  ||
+                    (opCode == spv::OpDecorate && varUseCount[asId(start+1)] == 1)  ||
+                    (opCode == spv::OpName     && varUseCount[asId(start+1)] == 1)) {
+                        stripInst(start);
+                }
+                return true;
+            },
+            op_fn_nop);
+    }
+
+    // remove unused types
+    void spirvbin_t::dceTypes()
+    {
+        std::vector<bool> isType(bound(), false);
+
+        // for speed, make O(1) way to get to type query (map is log(n))
+        for (const auto typeStart : typeConstPos)
+            isType[asTypeConstId(typeStart)] = true;
+
+        std::unordered_map<spv::Id, int> typeUseCount;
+
+        // Count total type usage
+        process(inst_fn_nop,
+            [&](spv::Id& id) { if (isType[id]) ++typeUseCount[id]; }
+        );
+
+        // Remove types from deleted code
+        for (const auto& fn : fnPosDCE)
+            process(inst_fn_nop,
+            [&](spv::Id& id) { if (isType[id]) --typeUseCount[id]; },
+            fn.second.first, fn.second.second);
+
+        // Remove single reference types
+        for (const auto typeStart : typeConstPos) {
+            const spv::Id typeId = asTypeConstId(typeStart);
+            if (typeUseCount[typeId] == 1) {
+                --typeUseCount[typeId];
+                stripInst(typeStart);
+            }
+        }
+    }
+
+
+#ifdef NOTDEF
+    bool spirvbin_t::matchType(const spirvbin_t::globaltypes_t& globalTypes, spv::Id lt, spv::Id gt) const
+    {
+        // Find the local type id "lt" and global type id "gt"
+        const auto lt_it = typeConstPosR.find(lt);
+        if (lt_it == typeConstPosR.end())
+            return false;
+
+        const auto typeStart = lt_it->second;
+
+        // Search for entry in global table
+        const auto gtype = globalTypes.find(gt);
+        if (gtype == globalTypes.end())
+            return false;
+
+        const auto& gdata = gtype->second;
+
+        // local wordcount and opcode
+        const int     wordCount   = asWordCount(typeStart);
+        const spv::Op opCode      = asOpCode(typeStart);
+
+        // no type match if opcodes don't match, or operand count doesn't match
+        if (opCode != opOpCode(gdata[0]) || wordCount != opWordCount(gdata[0]))
+            return false;
+
+        const unsigned numOperands = wordCount - 2; // all types have a result
+
+        const auto cmpIdRange = [&](range_t range) {
+            for (int x=range.first; x<std::min(range.second, wordCount); ++x)
+                if (!matchType(globalTypes, asId(typeStart+x), gdata[x]))
+                    return false;
+            return true;
+        };
+
+        const auto cmpConst   = [&]() { return cmpIdRange(constRange(opCode)); };
+        const auto cmpSubType = [&]() { return cmpIdRange(typeRange(opCode));  };
+
+        // Compare literals in range [start,end)
+        const auto cmpLiteral = [&]() {
+            const auto range = literalRange(opCode);
+            return std::equal(spir.begin() + typeStart + range.first,
+                spir.begin() + typeStart + std::min(range.second, wordCount),
+                gdata.begin() + range.first);
+        };
+
+        assert(isTypeOp(opCode) || isConstOp(opCode));
+
+        switch (opCode) {
+        case spv::OpTypeOpaque:       // TODO: disable until we compare the literal strings.
+        case spv::OpTypeQueue:        return false;
+        case spv::OpTypeEvent:        // fall through...
+        case spv::OpTypeDeviceEvent:  // ...
+        case spv::OpTypeReserveId:    return false;
+            // for samplers, we don't handle the optional parameters yet
+        case spv::OpTypeSampler:      return cmpLiteral() && cmpConst() && cmpSubType() && wordCount == 8;
+        default:                      return cmpLiteral() && cmpConst() && cmpSubType();
+        }
+    }
+
+
+    // Look for an equivalent type in the globalTypes map
+    spv::Id spirvbin_t::findType(const spirvbin_t::globaltypes_t& globalTypes, spv::Id lt) const
+    {
+        // Try a recursive type match on each in turn, and return a match if we find one
+        for (const auto& gt : globalTypes)
+            if (matchType(globalTypes, lt, gt.first))
+                return gt.first;
+
+        return spv::NoType;
+    }
+#endif // NOTDEF
+
+    // Return start position in SPV of given type.  error if not found.
+    unsigned spirvbin_t::typePos(spv::Id id) const
+    {
+        const auto tid_it = typeConstPosR.find(id);
+        if (tid_it == typeConstPosR.end())
+            error("type ID not found");
+
+        return tid_it->second;
+    }
+
+    // Hash types to canonical values.  This can return ID collisions (it's a bit
+    // inevitable): it's up to the caller to handle that gracefully.
+    std::uint32_t spirvbin_t::hashType(unsigned typeStart) const
+    {
+        const unsigned wordCount   = asWordCount(typeStart);
+        const spv::Op  opCode      = asOpCode(typeStart);
+
+        switch (opCode) {
+        case spv::OpTypeVoid:         return 0;
+        case spv::OpTypeBool:         return 1;
+        case spv::OpTypeInt:          return 3 + (spv[typeStart+3]);
+        case spv::OpTypeFloat:        return 5;
+        case spv::OpTypeVector:
+            return 6 + hashType(typePos(spv[typeStart+2])) * (spv[typeStart+3] - 1);
+        case spv::OpTypeMatrix:
+            return 30 + hashType(typePos(spv[typeStart+2])) * (spv[typeStart+3] - 1);
+        case spv::OpTypeSampler:
+            return 120 + hashType(typePos(spv[typeStart+2])) +
+                spv[typeStart+3] +            // dimensionality
+                spv[typeStart+4] * 8 * 16 +   // content
+                spv[typeStart+5] * 4 * 16 +   // arrayed
+                spv[typeStart+6] * 2 * 16 +   // compare
+                spv[typeStart+7] * 1 * 16;    // multisampled
+        case spv::OpTypeFilter:
+            return 500;
+        case spv::OpTypeArray:
+            return 501 + hashType(typePos(spv[typeStart+2])) * spv[typeStart+3];
+        case spv::OpTypeRuntimeArray:
+            return 5000  + hashType(typePos(spv[typeStart+2]));
+        case spv::OpTypeStruct:
+            {
+                std::uint32_t hash = 10000;
+                for (unsigned w=2; w < wordCount; ++w)
+                    hash += w * hashType(typePos(spv[typeStart+w]));
+                return hash;
+            }
+
+        case spv::OpTypeOpaque:         return 6000 + spv[typeStart+2];
+        case spv::OpTypePointer:        return 100000  + hashType(typePos(spv[typeStart+3]));
+        case spv::OpTypeFunction:
+            {
+                std::uint32_t hash = 200000;
+                for (unsigned w=2; w < wordCount; ++w)
+                    hash += w * hashType(typePos(spv[typeStart+w]));
+                return hash;
+            }
+
+        case spv::OpTypeEvent:           return 300000;
+        case spv::OpTypeDeviceEvent:     return 300001;
+        case spv::OpTypeReserveId:       return 300002;
+        case spv::OpTypeQueue:           return 300003;
+        case spv::OpTypePipe:            return 300004;
+
+        case spv::OpConstantNullObject:  return 300005;
+        case spv::OpConstantSampler:     return 300006;
+
+        case spv::OpConstantTrue:        return 300007;
+        case spv::OpConstantFalse:       return 300008;
+        case spv::OpConstantNullPointer: return 300009;
+        case spv::OpConstantComposite:
+            {
+                std::uint32_t hash = 300011 + hashType(typePos(spv[typeStart+1]));
+                for (unsigned w=3; w < wordCount; ++w)
+                    hash += w * hashType(typePos(spv[typeStart+w]));
+                return hash;
+            }
+        case spv::OpConstant:
+            {
+                std::uint32_t hash = 400011 + hashType(typePos(spv[typeStart+1]));
+                for (unsigned w=3; w < wordCount; ++w)
+                    hash += w * spv[typeStart+w];
+                return hash;
+            }
+
+        default:
+            error("unknown type opcode");
+            return 0;
+        }
+    }
+
+    void spirvbin_t::mapTypeConst()
+    {
+        globaltypes_t globalTypeMap;
+
+        msg(3, 2, std::string("Remapping Consts & Types: "));
+
+        static const std::uint32_t softTypeIdLimit = 3011; // small prime.  TODO: get from options
+        static const std::uint32_t firstMappedID   = 8;    // offset into ID space
+
+        for (auto& typeStart : typeConstPos) {
+            const spv::Id       resId     = asTypeConstId(typeStart);
+            const std::uint32_t hashval   = hashType(typeStart);
+
+            if (isOldIdUnmapped(resId))
+                localId(resId, nextUnusedId(hashval % softTypeIdLimit + firstMappedID));
+        }
+    }
+
+
+    // Strip a single binary by removing ranges given in stripRange
+    void spirvbin_t::strip()
+    {
+        if (stripRange.empty()) // nothing to do
+            return;
+
+        // Sort strip ranges in order of traversal
+        std::sort(stripRange.begin(), stripRange.end());
+
+        // Allocate a new binary big enough to hold old binary
+        // We'll step this iterator through the strip ranges as we go through the binary
+        auto strip_it = stripRange.begin();
+
+        int strippedPos = 0;
+        for (unsigned word = 0; word < unsigned(spv.size()); ++word) {
+            if (strip_it != stripRange.end() && word >= strip_it->second)
+                ++strip_it;
+
+            if (strip_it == stripRange.end() || word < strip_it->first || word >= strip_it->second)
+                spv[strippedPos++] = spv[word];
+        }
+
+        spv.resize(strippedPos);
+        stripRange.clear();
+
+        buildLocalMaps();
+    }
+
+    // Strip a single binary by removing ranges given in stripRange
+    void spirvbin_t::remap(std::uint32_t opts)
+    {
+        options = opts;
+
+        // Set up opcode tables from SpvDoc
+        spv::Parameterize();
+
+        validate();  // validate header
+        buildLocalMaps();
+
+        msg(3, 4, std::string("ID bound: ") + std::to_string(bound()));
+
+        strip();        // strip out data we decided to eliminate
+
+        if (options & OPT_LOADSTORE) optLoadStore();
+        if (options & OPT_FWD_LS)    forwardLoadStores();
+        if (options & DCE_FUNCS)     dceFuncs();
+        if (options & DCE_VARS)      dceVars();
+        if (options & DCE_TYPES)     dceTypes();
+        if (options & MAP_TYPES)     mapTypeConst();
+        if (options & MAP_NAMES)     mapNames();
+        if (options & MAP_FUNCS)     mapFnBodies();
+
+        mapRemainder(); // map any unmapped IDs
+        applyMap();     // Now remap each shader to the new IDs we've come up with
+        strip();        // strip out data we decided to eliminate
+    }
+
+    // remap from a memory image
+    void spirvbin_t::remap(std::vector<std::uint32_t>& in_spv, std::uint32_t opts)
+    {
+        spv.swap(in_spv);
+        remap(opts);
+        spv.swap(in_spv);
+    }
+
+} // namespace SPV
+
+#endif // defined (use_cpp11)
+
diff --git a/SPIRV/SPVRemapper.h b/SPIRV/SPVRemapper.h
index 71ca719..1b148b3 100644
--- a/SPIRV/SPVRemapper.h
+++ b/SPIRV/SPVRemapper.h
@@ -1,288 +1,288 @@
-//

-//Copyright (C) 2015 LunarG, Inc.

-//

-//All rights reserved.

-//

-//Redistribution and use in source and binary forms, with or without

-//modification, are permitted provided that the following conditions

-//are met:

-//

-//    Redistributions of source code must retain the above copyright

-//    notice, this list of conditions and the following disclaimer.

-//

-//    Redistributions in binary form must reproduce the above

-//    copyright notice, this list of conditions and the following

-//    disclaimer in the documentation and/or other materials provided

-//    with the distribution.

-//

-//    Neither the name of 3Dlabs Inc. Ltd. nor the names of its

-//    contributors may be used to endorse or promote products derived

-//    from this software without specific prior written permission.

-//

-//THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS

-//"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT

-//LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS

-//FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE

-//COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,

-//INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,

-//BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;

-//LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER

-//CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT

-//LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN

-//ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE

-//POSSIBILITY OF SUCH DAMAGE.

-//

-

-#ifndef SPIRVREMAPPER_H

-#define SPIRVREMAPPER_H

-

-#include <string>

-#include <vector>

-#include <stdlib.h>

-

-namespace spv {

-

-// MSVC defines __cplusplus as an older value, even when it supports almost all of 11.

-// We handle that here by making our own symbol.

-#if __cplusplus >= 201103L || _MSC_VER >= 1700

-#   define use_cpp11 1

-#endif

-

-class spirvbin_base_t

-{

-public:

-   enum Options {

-      NONE          = 0,

-      STRIP         = (1<<0),

-      MAP_TYPES     = (1<<1),

-      MAP_NAMES     = (1<<2),

-      MAP_FUNCS     = (1<<3),

-      DCE_FUNCS     = (1<<4),

-      DCE_VARS      = (1<<5),

-      DCE_TYPES     = (1<<6),

-      OPT_LOADSTORE = (1<<7),

-      OPT_FWD_LS    = (1<<8), // EXPERIMENTAL: PRODUCES INVALID SCHEMA-0 SPIRV

-      MAP_ALL       = (MAP_TYPES | MAP_NAMES | MAP_FUNCS),

-      DCE_ALL       = (DCE_FUNCS | DCE_VARS | DCE_TYPES),

-      OPT_ALL       = (OPT_LOADSTORE),

-

-      ALL_BUT_STRIP = (MAP_ALL | DCE_ALL | OPT_ALL),

-      DO_EVERYTHING = (STRIP | ALL_BUT_STRIP)

-   };

-};

-

-} // namespace SPV

-

-#if !defined (use_cpp11)

-#include <stdio.h>

-

-namespace spv {

-class spirvbin_t : public spirvbin_base_t

-{

-public:

-    spirvbin_t(int /*verbose = 0*/) { }

-

-    void remap(std::vector<unsigned int>& /*spv*/, unsigned int /*opts = 0*/)

-    {

-        printf("Tool not compiled for C++11, which is required for SPIR-V remapping.\n");

-        exit(5);

-    }

-};

-

-} // namespace SPV

-

-#else // defined (use_cpp11)

-

-#include <functional>

-#include <cstdint>

-#include <unordered_map>

-#include <unordered_set>

-#include <map>

-#include <set>

-#include <cassert>

-

-#include "../../glslang/SPIRV/spirv.h"

-#include "../../glslang/SPIRV/spvIR.h"

-

-namespace spv {

-

-// class to hold SPIR-V binary data for remapping, DCE, and debug stripping

-class spirvbin_t : public spirvbin_base_t

-{

-public:

-   spirvbin_t(int verbose = 0) : entryPoint(spv::NoResult), largestNewId(0), verbose(verbose) { }

-   

-   // remap on an existing binary in memory

-   void remap(std::vector<std::uint32_t>& spv, std::uint32_t opts = DO_EVERYTHING);

-

-   // Type for error/log handler functions

-   typedef std::function<void(const std::string&)> errorfn_t;

-   typedef std::function<void(const std::string&)> logfn_t;

-

-   // Register error/log handling functions (can be lambda fn / functor / etc)

-   static void registerErrorHandler(errorfn_t handler) { errorHandler = handler; }

-   static void registerLogHandler(logfn_t handler)     { logHandler   = handler; }

-

-protected:

-   // This can be overridden to provide other message behavior if needed

-   virtual void msg(int minVerbosity, int indent, const std::string& txt) const;

-

-private:

-   // Local to global, or global to local ID map

-   typedef std::unordered_map<spv::Id, spv::Id> idmap_t;

-   typedef std::unordered_set<spv::Id>          idset_t;

-

-   void remap(std::uint32_t opts = DO_EVERYTHING);

-

-   // Map of names to IDs

-   typedef std::unordered_map<std::string, spv::Id> namemap_t;

-

-   typedef std::uint32_t spirword_t;

-

-   typedef std::pair<unsigned, unsigned> range_t;

-   typedef std::function<void(spv::Id&)>                idfn_t;

-   typedef std::function<bool(spv::Op, unsigned start)> instfn_t;

-

-   // Special Values for ID map:

-   static const spv::Id unmapped;     // unchanged from default value

-   static const spv::Id unused;       // unused ID

-   static const int     header_size;  // SPIR header = 5 words

-

-   class id_iterator_t;

-

-   // For mapping type entries between different shaders

-   typedef std::vector<spirword_t>        typeentry_t;

-   typedef std::map<spv::Id, typeentry_t> globaltypes_t;

-

-   // A set that preserves position order, and a reverse map

-   typedef std::set<int>                    posmap_t;

-   typedef std::unordered_map<spv::Id, int> posmap_rev_t;

-

-   // handle error

-   void error(const std::string& txt) const { errorHandler(txt); }

-

-   bool    isConstOp(spv::Op opCode)       const;

-   bool    isTypeOp(spv::Op opCode)        const;

-   bool    isStripOp(spv::Op opCode)       const;

-   bool    isFlowCtrlOpen(spv::Op opCode)  const;

-   bool    isFlowCtrlClose(spv::Op opCode) const;

-   range_t literalRange(spv::Op opCode)    const;

-   range_t typeRange(spv::Op opCode)       const;

-   range_t constRange(spv::Op opCode)      const;

-   

-   spv::Id&        asId(unsigned word)                { return spv[word]; }

-   const spv::Id&  asId(unsigned word)          const { return spv[word]; }

-   spv::Op         asOpCode(unsigned word)      const { return opOpCode(spv[word]); }

-   std::uint32_t   asOpCodeHash(unsigned word);

-   spv::Decoration asDecoration(unsigned word)  const { return spv::Decoration(spv[word]); }

-   unsigned        asWordCount(unsigned word)   const { return opWordCount(spv[word]); }

-   spv::Id         asTypeConstId(unsigned word) const { return asId(word + (isTypeOp(asOpCode(word)) ? 1 : 2)); }

-   unsigned        typePos(spv::Id id)          const;

-

-   static unsigned    opWordCount(spirword_t data) { return data >> spv::WordCountShift; }

-   static spv::Op     opOpCode(spirword_t data)    { return spv::Op(data & spv::OpCodeMask); }

-

-   // Header access & set methods

-   spirword_t  magic()    const       { return spv[0]; } // return magic number

-   spirword_t  bound()    const       { return spv[3]; } // return Id bound from header

-   spirword_t  bound(spirword_t b)    { return spv[3] = b; };

-   spirword_t  genmagic() const       { return spv[2]; } // generator magic

-   spirword_t  genmagic(spirword_t m) { return spv[2] = m; }

-   spirword_t  schemaNum() const      { return spv[4]; } // schema number from header

-

-   // Mapping fns: get

-   spv::Id     localId(spv::Id id) const { return idMapL[id]; }

-

-   // Mapping fns: set

-   inline spv::Id   localId(spv::Id id, spv::Id newId);

-   void             countIds(spv::Id id);

-

-   // Return next unused new local ID.

-   // NOTE: boost::dynamic_bitset would be more efficient due to find_next(),

-   // which std::vector<bool> doens't have.

-   inline spv::Id   nextUnusedId(spv::Id id);

-

-   void buildLocalMaps();

-   std::string literalString(unsigned word) const; // Return literal as a std::string

-   int literalStringWords(const std::string& str) const { return (int(str.size())+4)/4; }

-

-   bool isNewIdMapped(spv::Id newId)   const { return isMapped(newId);            }

-   bool isOldIdUnmapped(spv::Id oldId) const { return localId(oldId) == unmapped; }

-   bool isOldIdUnused(spv::Id oldId)   const { return localId(oldId) == unused;   }

-   bool isOldIdMapped(spv::Id oldId)   const { return !isOldIdUnused(oldId) && !isOldIdUnmapped(oldId); }

-   bool isFunction(spv::Id oldId)      const { return fnPos.find(oldId) != fnPos.end(); }

-

-   // bool    matchType(const globaltypes_t& globalTypes, spv::Id lt, spv::Id gt) const;

-   // spv::Id findType(const globaltypes_t& globalTypes, spv::Id lt) const;

-   std::uint32_t hashType(unsigned typeStart) const;

-

-   spirvbin_t& process(instfn_t, idfn_t, unsigned begin = 0, unsigned end = 0);

-   int         processInstruction(unsigned word, instfn_t, idfn_t);

-

-   void        validate() const;

-   void        mapTypeConst();

-   void        mapFnBodies();

-   void        optLoadStore();

-   void        dceFuncs();

-   void        dceVars();

-   void        dceTypes();

-   void        mapNames();

-   void        foldIds();  // fold IDs to smallest space

-   void        forwardLoadStores(); // load store forwarding (EXPERIMENTAL)

-   void        offsetIds(); // create relative offset IDs

-

-   void        applyMap();            // remap per local name map

-   void        mapRemainder();        // map any IDs we haven't touched yet

-   void        stripDebug();          // strip debug info

-   void        strip();               // remove debug symbols

-   

-   std::vector<spirword_t> spv;      // SPIR words

-

-   namemap_t               nameMap;  // ID names from OpName

-

-   // Since we want to also do binary ops, we can't use std::vector<bool>.  we could use

-   // boost::dynamic_bitset, but we're trying to avoid a boost dependency.

-   typedef std::uint64_t bits_t;

-   std::vector<bits_t> mapped; // which new IDs have been mapped

-   static const int mBits = sizeof(bits_t) * 4;

-

-   bool isMapped(spv::Id id) const  { return id < maxMappedId() && ((mapped[id/mBits] & (1LL<<(id%mBits))) != 0); }

-   void setMapped(spv::Id id) { resizeMapped(id); mapped[id/mBits] |= (1LL<<(id%mBits)); }

-   void resizeMapped(spv::Id id) { if (id >= maxMappedId()) mapped.resize(id/mBits+1, 0); }

-   size_t maxMappedId() const { return mapped.size() * mBits; }

-

-   // Add a strip range for a given instruction starting at 'start'

-   // Note: avoiding brace initializers to please older versions os MSVC.

-   void stripInst(unsigned start) { stripRange.push_back(range_t(start, start + asWordCount(start))); }

-

-   // Function start and end.  use unordered_map because we'll have

-   // many fewer functions than IDs.

-   std::unordered_map<spv::Id, range_t> fnPos;

-   std::unordered_map<spv::Id, range_t> fnPosDCE; // deleted functions

-

-   // Which functions are called, anywhere in the module, with a call count

-   std::unordered_map<spv::Id, int> fnCalls;

-   

-   posmap_t     typeConstPos;   // word positions that define types & consts (ordered)

-   posmap_rev_t typeConstPosR;  // reverse map from IDs to positions

-   

-   std::vector<spv::Id>  idMapL;   // ID {M}ap from {L}ocal to {G}lobal IDs

-

-   spv::Id entryPoint;      // module entry point

-   spv::Id largestNewId;    // biggest new ID we have mapped anything to

-

-   // Sections of the binary to strip, given as [begin,end)

-   std::vector<range_t> stripRange;

-

-   // processing options:

-   std::uint32_t options;

-   int           verbose;     // verbosity level

-

-   static errorfn_t errorHandler;

-   static logfn_t   logHandler;

-};

-

-} // namespace SPV

-

-#endif // defined (use_cpp11)

-#endif // SPIRVREMAPPER_H

+//
+//Copyright (C) 2015 LunarG, Inc.
+//
+//All rights reserved.
+//
+//Redistribution and use in source and binary forms, with or without
+//modification, are permitted provided that the following conditions
+//are met:
+//
+//    Redistributions of source code must retain the above copyright
+//    notice, this list of conditions and the following disclaimer.
+//
+//    Redistributions in binary form must reproduce the above
+//    copyright notice, this list of conditions and the following
+//    disclaimer in the documentation and/or other materials provided
+//    with the distribution.
+//
+//    Neither the name of 3Dlabs Inc. Ltd. nor the names of its
+//    contributors may be used to endorse or promote products derived
+//    from this software without specific prior written permission.
+//
+//THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+//"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+//LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+//FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+//COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+//INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+//BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+//LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+//CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+//LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+//ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+//POSSIBILITY OF SUCH DAMAGE.
+//
+
+#ifndef SPIRVREMAPPER_H
+#define SPIRVREMAPPER_H
+
+#include <string>
+#include <vector>
+#include <stdlib.h>
+
+namespace spv {
+
+// MSVC defines __cplusplus as an older value, even when it supports almost all of 11.
+// We handle that here by making our own symbol.
+#if __cplusplus >= 201103L || _MSC_VER >= 1700
+#   define use_cpp11 1
+#endif
+
+class spirvbin_base_t
+{
+public:
+   enum Options {
+      NONE          = 0,
+      STRIP         = (1<<0),
+      MAP_TYPES     = (1<<1),
+      MAP_NAMES     = (1<<2),
+      MAP_FUNCS     = (1<<3),
+      DCE_FUNCS     = (1<<4),
+      DCE_VARS      = (1<<5),
+      DCE_TYPES     = (1<<6),
+      OPT_LOADSTORE = (1<<7),
+      OPT_FWD_LS    = (1<<8), // EXPERIMENTAL: PRODUCES INVALID SCHEMA-0 SPIRV
+      MAP_ALL       = (MAP_TYPES | MAP_NAMES | MAP_FUNCS),
+      DCE_ALL       = (DCE_FUNCS | DCE_VARS | DCE_TYPES),
+      OPT_ALL       = (OPT_LOADSTORE),
+
+      ALL_BUT_STRIP = (MAP_ALL | DCE_ALL | OPT_ALL),
+      DO_EVERYTHING = (STRIP | ALL_BUT_STRIP)
+   };
+};
+
+} // namespace SPV
+
+#if !defined (use_cpp11)
+#include <stdio.h>
+
+namespace spv {
+class spirvbin_t : public spirvbin_base_t
+{
+public:
+    spirvbin_t(int /*verbose = 0*/) { }
+
+    void remap(std::vector<unsigned int>& /*spv*/, unsigned int /*opts = 0*/)
+    {
+        printf("Tool not compiled for C++11, which is required for SPIR-V remapping.\n");
+        exit(5);
+    }
+};
+
+} // namespace SPV
+
+#else // defined (use_cpp11)
+
+#include <functional>
+#include <cstdint>
+#include <unordered_map>
+#include <unordered_set>
+#include <map>
+#include <set>
+#include <cassert>
+
+#include "../../glslang/SPIRV/spirv.h"
+#include "../../glslang/SPIRV/spvIR.h"
+
+namespace spv {
+
+// class to hold SPIR-V binary data for remapping, DCE, and debug stripping
+class spirvbin_t : public spirvbin_base_t
+{
+public:
+   spirvbin_t(int verbose = 0) : entryPoint(spv::NoResult), largestNewId(0), verbose(verbose) { }
+   
+   // remap on an existing binary in memory
+   void remap(std::vector<std::uint32_t>& spv, std::uint32_t opts = DO_EVERYTHING);
+
+   // Type for error/log handler functions
+   typedef std::function<void(const std::string&)> errorfn_t;
+   typedef std::function<void(const std::string&)> logfn_t;
+
+   // Register error/log handling functions (can be lambda fn / functor / etc)
+   static void registerErrorHandler(errorfn_t handler) { errorHandler = handler; }
+   static void registerLogHandler(logfn_t handler)     { logHandler   = handler; }
+
+protected:
+   // This can be overridden to provide other message behavior if needed
+   virtual void msg(int minVerbosity, int indent, const std::string& txt) const;
+
+private:
+   // Local to global, or global to local ID map
+   typedef std::unordered_map<spv::Id, spv::Id> idmap_t;
+   typedef std::unordered_set<spv::Id>          idset_t;
+
+   void remap(std::uint32_t opts = DO_EVERYTHING);
+
+   // Map of names to IDs
+   typedef std::unordered_map<std::string, spv::Id> namemap_t;
+
+   typedef std::uint32_t spirword_t;
+
+   typedef std::pair<unsigned, unsigned> range_t;
+   typedef std::function<void(spv::Id&)>                idfn_t;
+   typedef std::function<bool(spv::Op, unsigned start)> instfn_t;
+
+   // Special Values for ID map:
+   static const spv::Id unmapped;     // unchanged from default value
+   static const spv::Id unused;       // unused ID
+   static const int     header_size;  // SPIR header = 5 words
+
+   class id_iterator_t;
+
+   // For mapping type entries between different shaders
+   typedef std::vector<spirword_t>        typeentry_t;
+   typedef std::map<spv::Id, typeentry_t> globaltypes_t;
+
+   // A set that preserves position order, and a reverse map
+   typedef std::set<int>                    posmap_t;
+   typedef std::unordered_map<spv::Id, int> posmap_rev_t;
+
+   // handle error
+   void error(const std::string& txt) const { errorHandler(txt); }
+
+   bool    isConstOp(spv::Op opCode)       const;
+   bool    isTypeOp(spv::Op opCode)        const;
+   bool    isStripOp(spv::Op opCode)       const;
+   bool    isFlowCtrlOpen(spv::Op opCode)  const;
+   bool    isFlowCtrlClose(spv::Op opCode) const;
+   range_t literalRange(spv::Op opCode)    const;
+   range_t typeRange(spv::Op opCode)       const;
+   range_t constRange(spv::Op opCode)      const;
+   
+   spv::Id&        asId(unsigned word)                { return spv[word]; }
+   const spv::Id&  asId(unsigned word)          const { return spv[word]; }
+   spv::Op         asOpCode(unsigned word)      const { return opOpCode(spv[word]); }
+   std::uint32_t   asOpCodeHash(unsigned word);
+   spv::Decoration asDecoration(unsigned word)  const { return spv::Decoration(spv[word]); }
+   unsigned        asWordCount(unsigned word)   const { return opWordCount(spv[word]); }
+   spv::Id         asTypeConstId(unsigned word) const { return asId(word + (isTypeOp(asOpCode(word)) ? 1 : 2)); }
+   unsigned        typePos(spv::Id id)          const;
+
+   static unsigned    opWordCount(spirword_t data) { return data >> spv::WordCountShift; }
+   static spv::Op     opOpCode(spirword_t data)    { return spv::Op(data & spv::OpCodeMask); }
+
+   // Header access & set methods
+   spirword_t  magic()    const       { return spv[0]; } // return magic number
+   spirword_t  bound()    const       { return spv[3]; } // return Id bound from header
+   spirword_t  bound(spirword_t b)    { return spv[3] = b; };
+   spirword_t  genmagic() const       { return spv[2]; } // generator magic
+   spirword_t  genmagic(spirword_t m) { return spv[2] = m; }
+   spirword_t  schemaNum() const      { return spv[4]; } // schema number from header
+
+   // Mapping fns: get
+   spv::Id     localId(spv::Id id) const { return idMapL[id]; }
+
+   // Mapping fns: set
+   inline spv::Id   localId(spv::Id id, spv::Id newId);
+   void             countIds(spv::Id id);
+
+   // Return next unused new local ID.
+   // NOTE: boost::dynamic_bitset would be more efficient due to find_next(),
+   // which std::vector<bool> doens't have.
+   inline spv::Id   nextUnusedId(spv::Id id);
+
+   void buildLocalMaps();
+   std::string literalString(unsigned word) const; // Return literal as a std::string
+   int literalStringWords(const std::string& str) const { return (int(str.size())+4)/4; }
+
+   bool isNewIdMapped(spv::Id newId)   const { return isMapped(newId);            }
+   bool isOldIdUnmapped(spv::Id oldId) const { return localId(oldId) == unmapped; }
+   bool isOldIdUnused(spv::Id oldId)   const { return localId(oldId) == unused;   }
+   bool isOldIdMapped(spv::Id oldId)   const { return !isOldIdUnused(oldId) && !isOldIdUnmapped(oldId); }
+   bool isFunction(spv::Id oldId)      const { return fnPos.find(oldId) != fnPos.end(); }
+
+   // bool    matchType(const globaltypes_t& globalTypes, spv::Id lt, spv::Id gt) const;
+   // spv::Id findType(const globaltypes_t& globalTypes, spv::Id lt) const;
+   std::uint32_t hashType(unsigned typeStart) const;
+
+   spirvbin_t& process(instfn_t, idfn_t, unsigned begin = 0, unsigned end = 0);
+   int         processInstruction(unsigned word, instfn_t, idfn_t);
+
+   void        validate() const;
+   void        mapTypeConst();
+   void        mapFnBodies();
+   void        optLoadStore();
+   void        dceFuncs();
+   void        dceVars();
+   void        dceTypes();
+   void        mapNames();
+   void        foldIds();  // fold IDs to smallest space
+   void        forwardLoadStores(); // load store forwarding (EXPERIMENTAL)
+   void        offsetIds(); // create relative offset IDs
+
+   void        applyMap();            // remap per local name map
+   void        mapRemainder();        // map any IDs we haven't touched yet
+   void        stripDebug();          // strip debug info
+   void        strip();               // remove debug symbols
+   
+   std::vector<spirword_t> spv;      // SPIR words
+
+   namemap_t               nameMap;  // ID names from OpName
+
+   // Since we want to also do binary ops, we can't use std::vector<bool>.  we could use
+   // boost::dynamic_bitset, but we're trying to avoid a boost dependency.
+   typedef std::uint64_t bits_t;
+   std::vector<bits_t> mapped; // which new IDs have been mapped
+   static const int mBits = sizeof(bits_t) * 4;
+
+   bool isMapped(spv::Id id) const  { return id < maxMappedId() && ((mapped[id/mBits] & (1LL<<(id%mBits))) != 0); }
+   void setMapped(spv::Id id) { resizeMapped(id); mapped[id/mBits] |= (1LL<<(id%mBits)); }
+   void resizeMapped(spv::Id id) { if (id >= maxMappedId()) mapped.resize(id/mBits+1, 0); }
+   size_t maxMappedId() const { return mapped.size() * mBits; }
+
+   // Add a strip range for a given instruction starting at 'start'
+   // Note: avoiding brace initializers to please older versions os MSVC.
+   void stripInst(unsigned start) { stripRange.push_back(range_t(start, start + asWordCount(start))); }
+
+   // Function start and end.  use unordered_map because we'll have
+   // many fewer functions than IDs.
+   std::unordered_map<spv::Id, range_t> fnPos;
+   std::unordered_map<spv::Id, range_t> fnPosDCE; // deleted functions
+
+   // Which functions are called, anywhere in the module, with a call count
+   std::unordered_map<spv::Id, int> fnCalls;
+   
+   posmap_t     typeConstPos;   // word positions that define types & consts (ordered)
+   posmap_rev_t typeConstPosR;  // reverse map from IDs to positions
+   
+   std::vector<spv::Id>  idMapL;   // ID {M}ap from {L}ocal to {G}lobal IDs
+
+   spv::Id entryPoint;      // module entry point
+   spv::Id largestNewId;    // biggest new ID we have mapped anything to
+
+   // Sections of the binary to strip, given as [begin,end)
+   std::vector<range_t> stripRange;
+
+   // processing options:
+   std::uint32_t options;
+   int           verbose;     // verbosity level
+
+   static errorfn_t errorHandler;
+   static logfn_t   logHandler;
+};
+
+} // namespace SPV
+
+#endif // defined (use_cpp11)
+#endif // SPIRVREMAPPER_H
diff --git a/SPIRV/SpvBuilder.cpp b/SPIRV/SpvBuilder.cpp
index 35270b0..f90dd70 100644
--- a/SPIRV/SpvBuilder.cpp
+++ b/SPIRV/SpvBuilder.cpp
@@ -1,2137 +1,2137 @@
-//

-//Copyright (C) 2014 LunarG, Inc.

-//

-//All rights reserved.

-//

-//Redistribution and use in source and binary forms, with or without

-//modification, are permitted provided that the following conditions

-//are met:

-//

-//    Redistributions of source code must retain the above copyright

-//    notice, this list of conditions and the following disclaimer.

-//

-//    Redistributions in binary form must reproduce the above

-//    copyright notice, this list of conditions and the following

-//    disclaimer in the documentation and/or other materials provided

-//    with the distribution.

-//

-//    Neither the name of 3Dlabs Inc. Ltd. nor the names of its

-//    contributors may be used to endorse or promote products derived

-//    from this software without specific prior written permission.

-//

-//THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS

-//"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT

-//LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS

-//FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE

-//COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,

-//INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,

-//BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;

-//LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER

-//CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT

-//LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN

-//ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE

-//POSSIBILITY OF SUCH DAMAGE.

-

-//

-// Author: John Kessenich, LunarG

-//

-

-//

-// Helper for making SPIR-V IR.  Generally, this is documented in the header

-// SpvBuilder.h.

-//

-

-#include <assert.h>

-#include <stdio.h>

-#include <stdlib.h>

-

-#include "SpvBuilder.h"

-

-#ifndef _WIN32

-    #include <cstdio>

-#endif

-

-namespace spv {

-

-const int SpvBuilderMagic = 0xBB;

-

-Builder::Builder(unsigned int userNumber) :

-    source(SourceLanguageUnknown),

-    sourceVersion(0),

-    addressModel(AddressingModelLogical),

-    memoryModel(MemoryModelGLSL450),

-    builderNumber(userNumber << 16 | SpvBuilderMagic),

-    buildPoint(0),

-    uniqueId(0),

-    mainFunction(0),

-    stageExit(0)

-{

-    clearAccessChain();

-}

-

-Builder::~Builder()

-{

-}

-

-Id Builder::import(const char* name)

-{

-    Instruction* import = new Instruction(getUniqueId(), NoType, OpExtInstImport);

-    import->addStringOperand(name);

-    

-    imports.push_back(import);

-    return import->getResultId();

-}

-

-// For creating new groupedTypes (will return old type if the requested one was already made).

-Id Builder::makeVoidType()

-{

-    Instruction* type;

-    if (groupedTypes[OpTypeVoid].size() == 0) {

-        type = new Instruction(getUniqueId(), NoType, OpTypeVoid);

-        groupedTypes[OpTypeVoid].push_back(type);

-        constantsTypesGlobals.push_back(type);

-        module.mapInstruction(type);

-    } else

-        type = groupedTypes[OpTypeVoid].back();

-

-    return type->getResultId();

-}

-

-Id Builder::makeBoolType()

-{

-    Instruction* type;

-    if (groupedTypes[OpTypeBool].size() == 0) {

-        type = new Instruction(getUniqueId(), NoType, OpTypeBool);

-        groupedTypes[OpTypeBool].push_back(type);

-        constantsTypesGlobals.push_back(type);

-        module.mapInstruction(type);

-    } else

-        type = groupedTypes[OpTypeBool].back();

-

-    return type->getResultId();

-}

-

-Id Builder::makePointer(StorageClass storageClass, Id pointee)

-{

-    // try to find it

-    Instruction* type;

-    for (int t = 0; t < (int)groupedTypes[OpTypePointer].size(); ++t) {

-        type = groupedTypes[OpTypePointer][t];

-        if (type->getImmediateOperand(0) == (unsigned)storageClass &&

-            type->getIdOperand(1) == pointee)

-            return type->getResultId();

-    }

-

-    // not found, make it

-    type = new Instruction(getUniqueId(), NoType, OpTypePointer);

-    type->addImmediateOperand(storageClass);

-    type->addIdOperand(pointee);

-    groupedTypes[OpTypePointer].push_back(type);

-    constantsTypesGlobals.push_back(type);

-    module.mapInstruction(type);

-

-    return type->getResultId();

-}

-

-Id Builder::makeIntegerType(int width, bool hasSign)

-{

-    // try to find it

-    Instruction* type;

-    for (int t = 0; t < (int)groupedTypes[OpTypeInt].size(); ++t) {

-        type = groupedTypes[OpTypeInt][t];

-        if (type->getImmediateOperand(0) == (unsigned)width &&

-            type->getImmediateOperand(1) == (hasSign ? 1u : 0u))

-            return type->getResultId();

-    }

-

-    // not found, make it

-    type = new Instruction(getUniqueId(), NoType, OpTypeInt);

-    type->addImmediateOperand(width);

-    type->addImmediateOperand(hasSign ? 1 : 0);

-    groupedTypes[OpTypeInt].push_back(type);

-    constantsTypesGlobals.push_back(type);

-    module.mapInstruction(type);

-

-    return type->getResultId();

-}

-

-Id Builder::makeFloatType(int width)

-{

-    // try to find it

-    Instruction* type;

-    for (int t = 0; t < (int)groupedTypes[OpTypeFloat].size(); ++t) {

-        type = groupedTypes[OpTypeFloat][t];

-        if (type->getImmediateOperand(0) == (unsigned)width)

-            return type->getResultId();

-    }

-

-    // not found, make it

-    type = new Instruction(getUniqueId(), NoType, OpTypeFloat);

-    type->addImmediateOperand(width);

-    groupedTypes[OpTypeFloat].push_back(type);

-    constantsTypesGlobals.push_back(type);

-    module.mapInstruction(type);

-

-    return type->getResultId();

-}

-

-Id Builder::makeStructType(std::vector<Id>& members, const char* name)

-{

-    // not found, make it

-    Instruction* type = new Instruction(getUniqueId(), NoType, OpTypeStruct);

-    for (int op = 0; op < (int)members.size(); ++op)

-        type->addIdOperand(members[op]);

-    groupedTypes[OpTypeStruct].push_back(type);

-    constantsTypesGlobals.push_back(type);

-    module.mapInstruction(type);

-    addName(type->getResultId(), name);

-

-    return type->getResultId();

-}

-

-Id Builder::makeVectorType(Id component, int size)

-{

-    // try to find it

-    Instruction* type;

-    for (int t = 0; t < (int)groupedTypes[OpTypeVector].size(); ++t) {

-        type = groupedTypes[OpTypeVector][t];

-        if (type->getIdOperand(0) == component &&

-            type->getImmediateOperand(1) == (unsigned)size)

-            return type->getResultId();

-    }

-

-    // not found, make it

-    type = new Instruction(getUniqueId(), NoType, OpTypeVector);

-    type->addIdOperand(component);

-    type->addImmediateOperand(size);

-    groupedTypes[OpTypeVector].push_back(type);

-    constantsTypesGlobals.push_back(type);

-    module.mapInstruction(type);

-

-    return type->getResultId();

-}

-

-Id Builder::makeMatrixType(Id component, int cols, int rows)

-{

-    assert(cols <= maxMatrixSize && rows <= maxMatrixSize);

-

-    Id column = makeVectorType(component, rows);

-

-    // try to find it

-    Instruction* type;

-    for (int t = 0; t < (int)groupedTypes[OpTypeMatrix].size(); ++t) {

-        type = groupedTypes[OpTypeMatrix][t];

-        if (type->getIdOperand(0) == column &&

-            type->getImmediateOperand(1) == (unsigned)cols)

-            return type->getResultId();

-    }

-

-    // not found, make it

-    type = new Instruction(getUniqueId(), NoType, OpTypeMatrix);

-    type->addIdOperand(column);

-    type->addImmediateOperand(cols);

-    groupedTypes[OpTypeMatrix].push_back(type);

-    constantsTypesGlobals.push_back(type);

-    module.mapInstruction(type);

-

-    return type->getResultId();

-}

-

-Id Builder::makeArrayType(Id element, unsigned size)

-{

-    // First, we need a constant instruction for the size

-    Id sizeId = makeUintConstant(size);

-

-    // try to find existing type

-    Instruction* type;

-    for (int t = 0; t < (int)groupedTypes[OpTypeArray].size(); ++t) {

-        type = groupedTypes[OpTypeArray][t];

-        if (type->getIdOperand(0) == element &&

-            type->getIdOperand(1) == sizeId)

-            return type->getResultId();

-    }

-

-    // not found, make it

-    type = new Instruction(getUniqueId(), NoType, OpTypeArray);

-    type->addIdOperand(element);

-    type->addIdOperand(sizeId);

-    groupedTypes[OpTypeArray].push_back(type);

-    constantsTypesGlobals.push_back(type);

-    module.mapInstruction(type);

-

-    return type->getResultId();

-}

-

-Id Builder::makeFunctionType(Id returnType, std::vector<Id>& paramTypes)

-{

-    // try to find it

-    Instruction* type;

-    for (int t = 0; t < (int)groupedTypes[OpTypeFunction].size(); ++t) {

-        type = groupedTypes[OpTypeFunction][t];

-        if (type->getIdOperand(0) != returnType || (int)paramTypes.size() != type->getNumOperands() - 1)

-            continue;

-        bool mismatch = false;

-        for (int p = 0; p < (int)paramTypes.size(); ++p) {

-            if (paramTypes[p] != type->getIdOperand(p + 1)) {

-                mismatch = true;

-                break;

-            }

-        }

-        if (! mismatch)

-            return type->getResultId();            

-    }

-

-    // not found, make it

-    type = new Instruction(getUniqueId(), NoType, OpTypeFunction);

-    type->addIdOperand(returnType);

-    for (int p = 0; p < (int)paramTypes.size(); ++p)

-        type->addIdOperand(paramTypes[p]);

-    groupedTypes[OpTypeFunction].push_back(type);

-    constantsTypesGlobals.push_back(type);

-    module.mapInstruction(type);

-

-    return type->getResultId();

-}

-

-Id Builder::makeSampler(Id sampledType, Dim dim, samplerContent content, bool arrayed, bool shadow, bool ms)

-{

-    // try to find it

-    Instruction* type;

-    for (int t = 0; t < (int)groupedTypes[OpTypeSampler].size(); ++t) {

-        type = groupedTypes[OpTypeSampler][t];

-        if (type->getIdOperand(0) == sampledType &&

-            type->getImmediateOperand(1) == (unsigned int)dim &&

-            type->getImmediateOperand(2) == (unsigned int)content &&

-            type->getImmediateOperand(3) == (arrayed ? 1u : 0u) &&

-            type->getImmediateOperand(4) == ( shadow ? 1u : 0u) &&

-            type->getImmediateOperand(5) == (     ms ? 1u : 0u))

-            return type->getResultId();

-    }

-

-    // not found, make it

-    type = new Instruction(getUniqueId(), NoType, OpTypeSampler);

-    type->addIdOperand(sampledType);

-    type->addImmediateOperand(   dim);

-    type->addImmediateOperand(content);

-    type->addImmediateOperand(arrayed ? 1 : 0);

-    type->addImmediateOperand( shadow ? 1 : 0);

-    type->addImmediateOperand(     ms ? 1 : 0);

-

-    groupedTypes[OpTypeSampler].push_back(type);

-    constantsTypesGlobals.push_back(type);

-    module.mapInstruction(type);

-

-    return type->getResultId();

-}

-

-Id Builder::getDerefTypeId(Id resultId) const

-{

-    Id typeId = getTypeId(resultId);

-    assert(isPointerType(typeId));

-

-    return module.getInstruction(typeId)->getImmediateOperand(1);

-}

-

-Op Builder::getMostBasicTypeClass(Id typeId) const

-{

-    Instruction* instr = module.getInstruction(typeId);

-

-    Op typeClass = instr->getOpCode();

-    switch (typeClass)

-    {

-    case OpTypeVoid:

-    case OpTypeBool:

-    case OpTypeInt:

-    case OpTypeFloat:

-    case OpTypeStruct:

-        return typeClass;

-    case OpTypeVector:

-    case OpTypeMatrix:

-    case OpTypeArray:

-    case OpTypeRuntimeArray:

-        return getMostBasicTypeClass(instr->getIdOperand(0));

-    case OpTypePointer:

-        return getMostBasicTypeClass(instr->getIdOperand(1));

-    default:

-        MissingFunctionality("getMostBasicTypeClass");

-        return OpTypeFloat;

-    }

-}

-

-int Builder::getNumTypeComponents(Id typeId) const

-{

-    Instruction* instr = module.getInstruction(typeId);

-

-    switch (instr->getOpCode())

-    {

-    case OpTypeBool:

-    case OpTypeInt:

-    case OpTypeFloat:

-        return 1;

-    case OpTypeVector:

-    case OpTypeMatrix:

-        return instr->getImmediateOperand(1);

-    default:

-        MissingFunctionality("getNumTypeComponents on non bool/int/float/vector/matrix");

-        return 1;

-    }

-}

-

-// Return the lowest-level type of scalar that an homogeneous composite is made out of.

-// Typically, this is just to find out if something is made out of ints or floats.

-// However, it includes returning a structure, if say, it is an array of structure.

-Id Builder::getScalarTypeId(Id typeId) const

-{

-    Instruction* instr = module.getInstruction(typeId);

-

-    Op typeClass = instr->getOpCode();

-    switch (typeClass)

-    {

-    case OpTypeVoid:

-    case OpTypeBool:

-    case OpTypeInt:

-    case OpTypeFloat:

-    case OpTypeStruct:

-        return instr->getResultId();

-    case OpTypeVector:

-    case OpTypeMatrix:

-    case OpTypeArray:

-    case OpTypeRuntimeArray:

-    case OpTypePointer:

-        return getScalarTypeId(getContainedTypeId(typeId));

-    default:

-        MissingFunctionality("getScalarTypeId");

-        return NoResult;

-    }

-}

-

-// Return the type of 'member' of a composite.

-Id Builder::getContainedTypeId(Id typeId, int member) const

-{

-    Instruction* instr = module.getInstruction(typeId);

-

-    Op typeClass = instr->getOpCode();

-    switch (typeClass)

-    {

-    case OpTypeVector:

-    case OpTypeMatrix:

-    case OpTypeArray:

-    case OpTypeRuntimeArray:

-        return instr->getIdOperand(0);

-    case OpTypePointer:

-        return instr->getIdOperand(1);

-    case OpTypeStruct:

-        return instr->getIdOperand(member);

-    default:

-        MissingFunctionality("getContainedTypeId");

-        return NoResult;

-    }

-}

-

-// Return the immediately contained type of a given composite type.

-Id Builder::getContainedTypeId(Id typeId) const

-{

-    return getContainedTypeId(typeId, 0);

-}

-

-// See if a scalar constant of this type has already been created, so it

-// can be reused rather than duplicated.  (Required by the specification).

-Id Builder::findScalarConstant(Op typeClass, Id typeId, unsigned value) const

-{

-    Instruction* constant;

-    for (int i = 0; i < (int)groupedConstants[typeClass].size(); ++i) {

-        constant = groupedConstants[typeClass][i];

-        if (constant->getNumOperands() == 1 &&

-            constant->getTypeId() == typeId &&

-            constant->getImmediateOperand(0) == value)

-            return constant->getResultId();

-    }

-

-    return 0;

-}

-

-// Version of findScalarConstant (see above) for scalars that take two operands (e.g. a 'double').

-Id Builder::findScalarConstant(Op typeClass, Id typeId, unsigned v1, unsigned v2) const

-{

-    Instruction* constant;

-    for (int i = 0; i < (int)groupedConstants[typeClass].size(); ++i) {

-        constant = groupedConstants[typeClass][i];

-        if (constant->getNumOperands() == 2 &&

-            constant->getTypeId() == typeId &&

-            constant->getImmediateOperand(0) == v1 &&

-            constant->getImmediateOperand(1) == v2)

-            return constant->getResultId();

-    }

-

-    return 0;

-}

-

-Id Builder::makeBoolConstant(bool b)

-{

-    Id typeId = makeBoolType();

-    Instruction* constant;

-

-    // See if we already made it

-    Id existing = 0;

-    for (int i = 0; i < (int)groupedConstants[OpTypeBool].size(); ++i) {

-        constant = groupedConstants[OpTypeBool][i];

-        if (constant->getTypeId() == typeId &&

-            (b ? (constant->getOpCode() == OpConstantTrue) : 

-                 (constant->getOpCode() == OpConstantFalse)))

-            existing = constant->getResultId();

-    }

-

-    if (existing)

-        return existing;

-

-    // Make it

-    Instruction* c = new Instruction(getUniqueId(), typeId, b ? OpConstantTrue : OpConstantFalse);

-    constantsTypesGlobals.push_back(c);

-    groupedConstants[OpTypeBool].push_back(c);

-    module.mapInstruction(c);

-

-    return c->getResultId();

-}

-

-Id Builder::makeIntConstant(Id typeId, unsigned value)

-{

-    Id existing = findScalarConstant(OpTypeInt, typeId, value);

-    if (existing)

-        return existing;

-

-    Instruction* c = new Instruction(getUniqueId(), typeId, OpConstant);

-    c->addImmediateOperand(value);

-    constantsTypesGlobals.push_back(c);

-    groupedConstants[OpTypeInt].push_back(c);

-    module.mapInstruction(c);

-

-    return c->getResultId();

-}

-

-Id Builder::makeFloatConstant(float f)

-{

-    Id typeId = makeFloatType(32);

-    unsigned value = *(unsigned int*)&f;

-    Id existing = findScalarConstant(OpTypeFloat, typeId, value);

-    if (existing)

-        return existing;

-

-    Instruction* c = new Instruction(getUniqueId(), typeId, OpConstant);

-    c->addImmediateOperand(value);

-    constantsTypesGlobals.push_back(c);

-    groupedConstants[OpTypeFloat].push_back(c);

-    module.mapInstruction(c);

-

-    return c->getResultId();

-}

-

-Id Builder::makeDoubleConstant(double d)

-{

-    Id typeId = makeFloatType(64);

-    unsigned long long value = *(unsigned long long*)&d;

-    unsigned op1 = value & 0xFFFFFFFF;

-    unsigned op2 = value >> 32;

-    Id existing = findScalarConstant(OpTypeFloat, typeId, op1, op2);

-    if (existing)

-        return existing;

-

-    Instruction* c = new Instruction(getUniqueId(), typeId, OpConstant);

-    c->addImmediateOperand(op1);

-    c->addImmediateOperand(op2);

-    constantsTypesGlobals.push_back(c);

-    groupedConstants[OpTypeFloat].push_back(c);

-    module.mapInstruction(c);

-

-    return c->getResultId();

-}

-

-Id Builder::findCompositeConstant(Op typeClass, std::vector<Id>& comps) const

-{

-    Instruction* constant = 0;

-    bool found = false;

-    for (int i = 0; i < (int)groupedConstants[typeClass].size(); ++i) {

-        constant = groupedConstants[typeClass][i];

-

-        // same shape?

-        if (constant->getNumOperands() != (int)comps.size())

-            continue;

-

-        // same contents?

-        bool mismatch = false;

-        for (int op = 0; op < constant->getNumOperands(); ++op) {

-            if (constant->getIdOperand(op) != comps[op]) {

-                mismatch = true;

-                break;

-            }

-        }

-        if (! mismatch) {

-            found = true;

-            break;

-        }

-    }

-

-    return found ? constant->getResultId() : NoResult;

-}

-

-// Comments in header

-Id Builder::makeCompositeConstant(Id typeId, std::vector<Id>& members)

-{

-    assert(typeId);

-    Op typeClass = getTypeClass(typeId);

-

-    switch (typeClass) {

-    case OpTypeVector:

-    case OpTypeArray:

-    case OpTypeStruct:

-    case OpTypeMatrix:

-        break;

-    default:

-        MissingFunctionality("Constant composite type in Builder");

-        return makeFloatConstant(0.0);

-    }

-

-    Id existing = findCompositeConstant(typeClass, members);

-    if (existing)

-        return existing;

-

-    Instruction* c = new Instruction(getUniqueId(), typeId, OpConstantComposite);

-    for (int op = 0; op < (int)members.size(); ++op)

-        c->addIdOperand(members[op]);

-    constantsTypesGlobals.push_back(c);

-    groupedConstants[typeClass].push_back(c);

-    module.mapInstruction(c);

-

-    return c->getResultId();

-}

-

-void Builder::addEntryPoint(ExecutionModel model, Function* function)

-{

-    Instruction* entryPoint = new Instruction(OpEntryPoint);

-    entryPoint->addImmediateOperand(model);

-    entryPoint->addIdOperand(function->getId());

-

-    entryPoints.push_back(entryPoint);

-}

-

-void Builder::addExecutionMode(Function* entryPoint, ExecutionMode mode, int value)

-{

-    // TODO: handle multiple optional arguments

-    Instruction* instr = new Instruction(OpExecutionMode);

-    instr->addIdOperand(entryPoint->getId());

-    instr->addImmediateOperand(mode);

-    if (value >= 0)

-        instr->addImmediateOperand(value);

-

-    executionModes.push_back(instr);

-}

-

-void Builder::addName(Id id, const char* string)

-{

-    Instruction* name = new Instruction(OpName);

-    name->addIdOperand(id);

-    name->addStringOperand(string);

-

-    names.push_back(name);

-}

-

-void Builder::addMemberName(Id id, int memberNumber, const char* string)

-{

-    Instruction* name = new Instruction(OpMemberName);

-    name->addIdOperand(id);

-    name->addImmediateOperand(memberNumber);

-    name->addStringOperand(string);

-

-    names.push_back(name);

-}

-

-void Builder::addLine(Id target, Id fileName, int lineNum, int column)

-{

-    Instruction* line = new Instruction(OpLine);

-    line->addIdOperand(target);

-    line->addIdOperand(fileName);

-    line->addImmediateOperand(lineNum);

-    line->addImmediateOperand(column);

-

-    lines.push_back(line);

-}

-

-void Builder::addDecoration(Id id, Decoration decoration, int num)

-{

-    Instruction* dec = new Instruction(OpDecorate);

-    dec->addIdOperand(id);

-    dec->addImmediateOperand(decoration);

-    if (num >= 0)

-        dec->addImmediateOperand(num);

-

-    decorations.push_back(dec);

-}

-

-void Builder::addMemberDecoration(Id id, unsigned int member, Decoration decoration, int num)

-{

-    Instruction* dec = new Instruction(OpMemberDecorate);

-    dec->addIdOperand(id);

-    dec->addImmediateOperand(member);

-    dec->addImmediateOperand(decoration);

-    if (num >= 0)

-        dec->addImmediateOperand(num);

-

-    decorations.push_back(dec);

-}

-

-// Comments in header

-Function* Builder::makeMain()

-{

-    assert(! mainFunction);

-

-    Block* entry;

-    std::vector<Id> params;

-

-    mainFunction = makeFunctionEntry(makeVoidType(), "main", params, &entry);

-    stageExit = new Block(getUniqueId(), *mainFunction);

-

-    return mainFunction;

-}

-

-// Comments in header

-void Builder::closeMain()

-{

-    setBuildPoint(stageExit);

-    stageExit->addInstruction(new Instruction(NoResult, NoType, OpReturn));

-    mainFunction->addBlock(stageExit);

-}

-

-// Comments in header

-Function* Builder::makeFunctionEntry(Id returnType, const char* name, std::vector<Id>& paramTypes, Block **entry)

-{

-    Id typeId = makeFunctionType(returnType, paramTypes);

-    Id firstParamId = paramTypes.size() == 0 ? 0 : getUniqueIds(paramTypes.size());

-    Function* function = new Function(getUniqueId(), returnType, typeId, firstParamId, module);

-

-    if (entry) {

-        *entry = new Block(getUniqueId(), *function);

-        function->addBlock(*entry);

-        setBuildPoint(*entry);

-    }

-

-    if (name)

-        addName(function->getId(), name);

-

-    return function;

-}

-

-// Comments in header

-void Builder::makeReturn(bool implicit, Id retVal, bool isMain)

-{

-    if (isMain && retVal)

-        MissingFunctionality("return value from main()");

-

-    if (isMain)

-        createBranch(stageExit);

-    else if (retVal) {

-        Instruction* inst = new Instruction(NoResult, NoType, OpReturnValue);

-        inst->addIdOperand(retVal);

-        buildPoint->addInstruction(inst);

-    } else

-        buildPoint->addInstruction(new Instruction(NoResult, NoType, OpReturn));

-

-    if (! implicit)

-        createAndSetNoPredecessorBlock("post-return");

-}

-

-// Comments in header

-void Builder::leaveFunction(bool main)

-{

-    Block* block = buildPoint;

-    Function& function = buildPoint->getParent();

-    assert(block);

-

-    // If our function did not contain a return, add a return void now.

-    if (! block->isTerminated()) {

-

-        // Whether we're in an unreachable (non-entry) block.

-        bool unreachable = function.getEntryBlock() != block && block->getNumPredecessors() == 0;

-

-        if (unreachable) {

-            // Given that this block is at the end of a function, it must be right after an

-            // explicit return, just remove it.

-            function.popBlock(block);

-        } else if (main)

-            makeMainReturn(true);

-        else {

-            // We're get a return instruction at the end of the current block,

-            // which for a non-void function is really error recovery (?), as the source

-            // being translated should have had an explicit return, which would have been

-            // followed by an unreachable block, which was handled above.

-            if (function.getReturnType() == makeVoidType())

-                makeReturn(true);

-            else {

-                Id retStorage = createVariable(StorageClassFunction, function.getReturnType(), "dummyReturn");

-                Id retValue = createLoad(retStorage);

-                makeReturn(true, retValue);

-            }

-        }

-    }

-

-    if (main)

-        closeMain();

-}

-

-// Comments in header

-void Builder::makeDiscard()

-{

-    buildPoint->addInstruction(new Instruction(OpKill));

-    createAndSetNoPredecessorBlock("post-discard");

-}

-

-// Comments in header

-Id Builder::createVariable(StorageClass storageClass, Id type, const char* name)

-{

-    Id pointerType = makePointer(storageClass, type);

-    Instruction* inst = new Instruction(getUniqueId(), pointerType, OpVariable);

-    inst->addImmediateOperand(storageClass);

-

-    switch (storageClass) {

-    case StorageClassUniformConstant:

-    case StorageClassUniform:

-    case StorageClassInput:

-    case StorageClassOutput:

-    case StorageClassWorkgroupLocal:

-    case StorageClassPrivateGlobal:

-    case StorageClassWorkgroupGlobal:

-        constantsTypesGlobals.push_back(inst);

-        module.mapInstruction(inst);

-        break;

-

-    case StorageClassFunction:

-        // Validation rules require the declaration in the entry block

-        buildPoint->getParent().addLocalVariable(inst);

-        break;

-

-    default:

-        MissingFunctionality("storage class in createVariable");

-        break;

-    }

-

-    if (name)

-        addName(inst->getResultId(), name);

-

-    return inst->getResultId();

-}

-

-// Comments in header

-void Builder::createStore(Id rValue, Id lValue)

-{

-    Instruction* store = new Instruction(OpStore);

-    store->addIdOperand(lValue);

-    store->addIdOperand(rValue);

-    buildPoint->addInstruction(store);

-}

-

-// Comments in header

-Id Builder::createLoad(Id lValue)

-{

-    Instruction* load = new Instruction(getUniqueId(), getDerefTypeId(lValue), OpLoad);

-    load->addIdOperand(lValue);

-    buildPoint->addInstruction(load);

-

-    return load->getResultId();

-}

-

-// Comments in header

-Id Builder::createAccessChain(StorageClass storageClass, Id base, std::vector<Id>& offsets)

-{

-    // Figure out the final resulting type.

-    spv::Id typeId = getTypeId(base);

-    assert(isPointerType(typeId) && offsets.size() > 0);

-    typeId = getContainedTypeId(typeId);

-    for (int i = 0; i < (int)offsets.size(); ++i) {

-        if (isStructType(typeId)) {

-            assert(isConstantScalar(offsets[i]));

-            typeId = getContainedTypeId(typeId, getConstantScalar(offsets[i]));

-        } else

-            typeId = getContainedTypeId(typeId, offsets[i]);

-    }

-    typeId = makePointer(storageClass, typeId);

-

-    // Make the instruction

-    Instruction* chain = new Instruction(getUniqueId(), typeId, OpAccessChain);

-    chain->addIdOperand(base);

-    for (int i = 0; i < (int)offsets.size(); ++i)

-        chain->addIdOperand(offsets[i]);

-    buildPoint->addInstruction(chain);

-

-    return chain->getResultId();

-}

-

-Id Builder::createCompositeExtract(Id composite, Id typeId, unsigned index)

-{

-    Instruction* extract = new Instruction(getUniqueId(), typeId, OpCompositeExtract);

-    extract->addIdOperand(composite);

-    extract->addImmediateOperand(index);

-    buildPoint->addInstruction(extract);

-

-    return extract->getResultId();

-}

-

-Id Builder::createCompositeExtract(Id composite, Id typeId, std::vector<unsigned>& indexes)

-{

-    Instruction* extract = new Instruction(getUniqueId(), typeId, OpCompositeExtract);

-    extract->addIdOperand(composite);

-    for (int i = 0; i < (int)indexes.size(); ++i)

-        extract->addImmediateOperand(indexes[i]);

-    buildPoint->addInstruction(extract);

-

-    return extract->getResultId();

-}

-

-Id Builder::createCompositeInsert(Id object, Id composite, Id typeId, unsigned index)

-{

-    Instruction* insert = new Instruction(getUniqueId(), typeId, OpCompositeInsert);

-    insert->addIdOperand(object);

-    insert->addIdOperand(composite);

-    insert->addImmediateOperand(index);

-    buildPoint->addInstruction(insert);

-

-    return insert->getResultId();

-}

-

-Id Builder::createCompositeInsert(Id object, Id composite, Id typeId, std::vector<unsigned>& indexes)

-{

-    Instruction* insert = new Instruction(getUniqueId(), typeId, OpCompositeInsert);

-    insert->addIdOperand(object);

-    insert->addIdOperand(composite);

-    for (int i = 0; i < (int)indexes.size(); ++i)

-        insert->addImmediateOperand(indexes[i]);

-    buildPoint->addInstruction(insert);

-

-    return insert->getResultId();

-}

-

-Id Builder::createVectorExtractDynamic(Id vector, Id typeId, Id componentIndex)

-{

-    Instruction* extract = new Instruction(getUniqueId(), typeId, OpVectorExtractDynamic);

-    extract->addIdOperand(vector);

-    extract->addIdOperand(componentIndex);

-    buildPoint->addInstruction(extract);

-

-    return extract->getResultId();

-}

-

-Id Builder::createVectorInsertDynamic(Id vector, Id typeId, Id component, Id componentIndex)

-{

-    Instruction* insert = new Instruction(getUniqueId(), typeId, OpVectorInsertDynamic);

-    insert->addIdOperand(vector);

-    insert->addIdOperand(component);

-    insert->addIdOperand(componentIndex);

-    buildPoint->addInstruction(insert);

-

-    return insert->getResultId();

-}

-

-// An opcode that has no operands, no result id, and no type

-void Builder::createNoResultOp(Op opCode)

-{

-    Instruction* op = new Instruction(opCode);

-    buildPoint->addInstruction(op);

-}

-

-// An opcode that has one operand, no result id, and no type

-void Builder::createNoResultOp(Op opCode, Id operand)

-{

-    Instruction* op = new Instruction(opCode);

-    op->addIdOperand(operand);

-    buildPoint->addInstruction(op);

-}

-

-void Builder::createControlBarrier(unsigned executionScope)

-{

-    Instruction* op = new Instruction(OpControlBarrier);

-    op->addImmediateOperand(executionScope);

-    buildPoint->addInstruction(op);

-}

-

-void Builder::createMemoryBarrier(unsigned executionScope, unsigned memorySemantics)

-{

-    Instruction* op = new Instruction(OpMemoryBarrier);

-    op->addImmediateOperand(executionScope);

-    op->addImmediateOperand(memorySemantics);

-    buildPoint->addInstruction(op);

-}

-

-// An opcode that has one operands, a result id, and a type

-Id Builder::createUnaryOp(Op opCode, Id typeId, Id operand)

-{

-    Instruction* op = new Instruction(getUniqueId(), typeId, opCode);

-    op->addIdOperand(operand);

-    buildPoint->addInstruction(op);

-

-    return op->getResultId();

-}

-

-Id Builder::createBinOp(Op opCode, Id typeId, Id left, Id right)

-{

-    Instruction* op = new Instruction(getUniqueId(), typeId, opCode);

-    op->addIdOperand(left);

-    op->addIdOperand(right);

-    buildPoint->addInstruction(op);

-

-    return op->getResultId();

-}

-

-Id Builder::createTriOp(Op opCode, Id typeId, Id op1, Id op2, Id op3)

-{

-    Instruction* op = new Instruction(getUniqueId(), typeId, opCode);

-    op->addIdOperand(op1);

-    op->addIdOperand(op2);

-    op->addIdOperand(op3);

-    buildPoint->addInstruction(op);

-

-    return op->getResultId();

-}

-

-Id Builder::createTernaryOp(Op opCode, Id typeId, Id op1, Id op2, Id op3)

-{

-    Instruction* op = new Instruction(getUniqueId(), typeId, opCode);

-    op->addIdOperand(op1);

-    op->addIdOperand(op2);

-    op->addIdOperand(op3);

-    buildPoint->addInstruction(op);

-

-    return op->getResultId();

-}

-

-Id Builder::createFunctionCall(spv::Function* function, std::vector<spv::Id>& args)

-{

-    Instruction* op = new Instruction(getUniqueId(), function->getReturnType(), OpFunctionCall);

-    op->addIdOperand(function->getId());

-    for (int a = 0; a < (int)args.size(); ++a)

-        op->addIdOperand(args[a]);

-    buildPoint->addInstruction(op);

-

-    return op->getResultId();

-}

-

-// Comments in header

-Id Builder::createRvalueSwizzle(Id typeId, Id source, std::vector<unsigned>& channels)

-{

-    if (channels.size() == 1)

-        return createCompositeExtract(source, typeId, channels.front());

-

-    Instruction* swizzle = new Instruction(getUniqueId(), typeId, OpVectorShuffle);

-    assert(isVector(source));

-    swizzle->addIdOperand(source);

-    swizzle->addIdOperand(source);

-    for (int i = 0; i < (int)channels.size(); ++i)

-        swizzle->addImmediateOperand(channels[i]);

-    buildPoint->addInstruction(swizzle);

-

-    return swizzle->getResultId();

-}

-

-// Comments in header

-Id Builder::createLvalueSwizzle(Id typeId, Id target, Id source, std::vector<unsigned>& channels)

-{

-    assert(getNumComponents(source) == channels.size());

-    if (channels.size() == 1 && getNumComponents(source) == 1)

-        return createCompositeInsert(source, target, typeId, channels.front());

-

-    Instruction* swizzle = new Instruction(getUniqueId(), typeId, OpVectorShuffle);

-    assert(isVector(source));

-    assert(isVector(target));

-    swizzle->addIdOperand(target);

-    swizzle->addIdOperand(source);

-

-    // Set up an identity shuffle from the base value to the result value

-    unsigned int components[4];

-    int numTargetComponents = getNumComponents(target);

-    for (int i = 0; i < numTargetComponents; ++i)

-        components[i] = i;

-

-    // Punch in the l-value swizzle

-    for (int i = 0; i < (int)channels.size(); ++i)

-        components[channels[i]] = numTargetComponents + i;

-

-    // finish the instruction with these components selectors

-    for (int i = 0; i < numTargetComponents; ++i)

-        swizzle->addImmediateOperand(components[i]);

-    buildPoint->addInstruction(swizzle);

-

-    return swizzle->getResultId();

-}

-

-// Comments in header

-void Builder::promoteScalar(Decoration precision, Id& left, Id& right)

-{

-    int direction = getNumComponents(right) - getNumComponents(left);

-

-    if (direction > 0)

-        left = smearScalar(precision, left, getTypeId(right));

-    else if (direction < 0)

-        right = smearScalar(precision, right, getTypeId(left));

-

-    return;

-}

-

-// Comments in header

-Id Builder::smearScalar(Decoration /*precision*/, Id scalar, Id vectorType)

-{

-    assert(getNumComponents(scalar) == 1);

-

-    int numComponents = getNumTypeComponents(vectorType);

-    if (numComponents == 1)

-        return scalar;

-

-    Instruction* smear = new Instruction(getUniqueId(), vectorType, OpCompositeConstruct);

-    for (int c = 0; c < numComponents; ++c)

-        smear->addIdOperand(scalar);

-    buildPoint->addInstruction(smear);

-

-    return smear->getResultId();

-}

-

-// Comments in header

-Id Builder::createBuiltinCall(Decoration /*precision*/, Id resultType, Id builtins, int entryPoint, std::vector<Id>& args)

-{

-    Instruction* inst = new Instruction(getUniqueId(), resultType, OpExtInst);

-    inst->addIdOperand(builtins);

-    inst->addImmediateOperand(entryPoint);

-    for (int arg = 0; arg < (int)args.size(); ++arg)

-        inst->addIdOperand(args[arg]);

-

-    buildPoint->addInstruction(inst);

-    return inst->getResultId();

-}

-

-// Accept all parameters needed to create a texture instruction.

-// Create the correct instruction based on the inputs, and make the call.

-Id Builder::createTextureCall(Decoration precision, Id resultType, bool proj, const TextureParameters& parameters)

-{

-    static const int maxTextureArgs = 5;

-    Id texArgs[maxTextureArgs] = {};

-

-    //

-    // Set up the arguments

-    //

-

-    int numArgs = 0;

-    texArgs[numArgs++] = parameters.sampler;

-    texArgs[numArgs++] = parameters.coords;

-

-    if (parameters.gradX) {

-        texArgs[numArgs++] = parameters.gradX;

-        texArgs[numArgs++] = parameters.gradY;

-    }

-    if (parameters.lod)

-        texArgs[numArgs++] = parameters.lod;

-    if (parameters.offset)

-        texArgs[numArgs++] = parameters.offset;

-    if (parameters.bias)

-        texArgs[numArgs++] = parameters.bias;

-    if (parameters.Dref)

-        texArgs[numArgs++] = parameters.Dref;

-

-    //

-    // Set up the instruction

-    //

-

-    Op opCode;

-    if (proj && parameters.gradX && parameters.offset)

-        opCode = OpTextureSampleProjGradOffset;

-    else if (proj && parameters.lod && parameters.offset)

-        opCode = OpTextureSampleProjLodOffset;

-    else if (parameters.gradX && parameters.offset)

-        opCode = OpTextureSampleGradOffset;

-    else if (proj && parameters.offset)

-        opCode = OpTextureSampleProjOffset;

-    else if (parameters.lod && parameters.offset)

-        opCode = OpTextureSampleLodOffset;

-    else if (proj && parameters.gradX)

-        opCode = OpTextureSampleProjGrad;

-    else if (proj && parameters.lod)

-        opCode = OpTextureSampleProjLod;

-    else if (parameters.offset)

-        opCode = OpTextureSampleOffset;

-    else if (parameters.gradX)

-        opCode = OpTextureSampleGrad;

-    else if (proj)

-        opCode = OpTextureSampleProj;

-    else if (parameters.lod)

-        opCode = OpTextureSampleLod;

-    else if (parameters.Dref)

-        opCode = OpTextureSampleDref;

-    else

-        opCode = OpTextureSample;

-

-    Instruction* textureInst = new Instruction(getUniqueId(), resultType, opCode);

-    for (int op = 0; op < numArgs; ++op)

-        textureInst->addIdOperand(texArgs[op]);

-    setPrecision(textureInst->getResultId(), precision);

-    buildPoint->addInstruction(textureInst);

-

-    return textureInst->getResultId();

-}

-

-// Comments in header

-Id Builder::createTextureQueryCall(Op opCode, const TextureParameters& parameters)

-{

-    // Figure out the result type

-    Id resultType;

-    switch (opCode) {

-    case OpTextureQuerySize:

-    case OpTextureQuerySizeLod:

-    {

-        int numComponents;

-        switch (getDimensionality(parameters.sampler)) {

-        case Dim1D:

-        case DimBuffer:

-            numComponents = 1;

-            break;

-        case Dim2D:

-        case DimCube:

-        case DimRect:

-            numComponents = 2;

-            break;

-        case Dim3D:

-            numComponents = 3;

-            break;

-        default:

-            MissingFunctionality("texture query dimensionality");

-            break;

-        }

-        if (isArrayedSampler(parameters.sampler))

-            ++numComponents;

-        if (numComponents == 1)

-            resultType = makeIntType(32);

-        else

-            resultType = makeVectorType(makeIntType(32), numComponents);

-

-        break;

-    }

-    case OpTextureQueryLod:

-        resultType = makeVectorType(makeFloatType(32), 2);

-        break;

-    case OpTextureQueryLevels:

-    case OpTextureQuerySamples:

-        resultType = makeIntType(32);

-        break;

-    default:

-        MissingFunctionality("Texture query op code");

-    }

-

-    Instruction* query = new Instruction(getUniqueId(), resultType, opCode);

-    query->addIdOperand(parameters.sampler);

-    if (parameters.coords)

-        query->addIdOperand(parameters.coords);

-    if (parameters.lod)

-        query->addIdOperand(parameters.lod);

-    buildPoint->addInstruction(query);

-

-    return query->getResultId();

-}

-

-// Comments in header

-//Id Builder::createSamplePositionCall(Decoration precision, Id returnType, Id sampleIdx)

-//{

-//    // Return type is only flexible type

-//    Function* opCode = (fSamplePosition, returnType);

-//

-//    Instruction* instr = (opCode, sampleIdx);

-//    setPrecision(instr, precision);

-//

-//    return instr;

-//}

-

-// Comments in header

-//Id Builder::createBitFieldExtractCall(Decoration precision, Id id, Id offset, Id bits, bool isSigned)

-//{

-//    Op opCode = isSigned ? sBitFieldExtract

-//                                               : uBitFieldExtract;

-//

-//    if (isScalar(offset) == false || isScalar(bits) == false)

-//        MissingFunctionality("bitFieldExtract operand types");

-//

-//    // Dest and value are matching flexible types

-//    Function* opCode = (opCode, id->getType(), id->getType());

-//

-//    assert(opCode);

-//

-//    Instruction* instr = (opCode, id, offset, bits);

-//    setPrecision(instr, precision);

-//

-//    return instr;

-//}

-

-// Comments in header

-//Id Builder::createBitFieldInsertCall(Decoration precision, Id base, Id insert, Id offset, Id bits)

-//{

-//    Op opCode = bitFieldInsert;

-//

-//    if (isScalar(offset) == false || isScalar(bits) == false)

-//        MissingFunctionality("bitFieldInsert operand types");

-//

-//    // Dest, base, and insert are matching flexible types

-//    Function* opCode = (opCode, base->getType(), base->getType(), base->getType());

-//

-//    assert(opCode);

-//

-//    Instruction* instr = (opCode, base, insert, offset, bits);

-//    setPrecision(instr, precision);

-//

-//    return instr;

-//}

-

-// Comments in header

-Id Builder::createCompare(Decoration precision, Id value1, Id value2, bool equal)

-{

-    Id boolType = makeBoolType();

-    Id valueType = getTypeId(value1);

-

-    assert(valueType == getTypeId(value2));

-    assert(! isScalar(value1));

-

-    // Vectors

-

-    if (isVectorType(valueType)) {

-        Id boolVectorType = makeVectorType(boolType, getNumTypeComponents(valueType));

-        Id boolVector;

-        Op op;

-        if (getMostBasicTypeClass(valueType) == OpTypeFloat)

-            op = equal ? OpFOrdEqual : OpFOrdNotEqual;

-        else

-            op = equal ? OpIEqual : OpINotEqual;

-

-        boolVector = createBinOp(op, boolVectorType, value1, value2);

-        setPrecision(boolVector, precision);

-

-        // Reduce vector compares with any() and all().

-

-        op = equal ? OpAll : OpAny;

-

-        return createUnaryOp(op, boolType, boolVector);

-    }

-

-    spv::MissingFunctionality("Composite comparison of non-vectors");

-

-    return NoResult;

-

-    // Recursively handle aggregates, which include matrices, arrays, and structures

-    // and accumulate the results.

-

-    // Matrices

-

-    // Arrays

-

-    //int numElements;

-    //const llvm::ArrayType* arrayType = llvm::dyn_cast<llvm::ArrayType>(value1->getType());

-    //if (arrayType)

-    //    numElements = (int)arrayType->getNumElements();

-    //else {

-    //    // better be structure

-    //    const llvm::StructType* structType = llvm::dyn_cast<llvm::StructType>(value1->getType());

-    //    assert(structType);

-    //    numElements = structType->getNumElements();

-    //}

-

-    //assert(numElements > 0);

-

-    //for (int element = 0; element < numElements; ++element) {

-    //    // Get intermediate comparison values

-    //    llvm::Value* element1 = builder.CreateExtractValue(value1, element, "element1");

-    //    setInstructionPrecision(element1, precision);

-    //    llvm::Value* element2 = builder.CreateExtractValue(value2, element, "element2");

-    //    setInstructionPrecision(element2, precision);

-

-    //    llvm::Value* subResult = createCompare(precision, element1, element2, equal, "comp");

-

-    //    // Accumulate intermediate comparison

-    //    if (element == 0)

-    //        result = subResult;

-    //    else {

-    //        if (equal)

-    //            result = builder.CreateAnd(result, subResult);

-    //        else

-    //            result = builder.CreateOr(result, subResult);

-    //        setInstructionPrecision(result, precision);

-    //    }

-    //}

-

-    //return result;

-}

-

-// Comments in header

-//Id Builder::createOperation(Decoration precision, Op opCode, Id operand)

-//{

-//    Op* opCode = 0;

-//

-//    // Handle special return types here.  Things that don't have same result type as parameter

-//    switch (opCode) {

-//    case fIsNan:

-//    case fIsInf:

-//        break;

-//    case fFloatBitsToInt:

-//        break;

-//    case fIntBitsTofloat:

-//        break;

-//    case fPackSnorm2x16:

-//    case fPackUnorm2x16:

-//    case fPackHalf2x16:

-//        break;

-//    case fUnpackUnorm2x16:

-//    case fUnpackSnorm2x16:

-//    case fUnpackHalf2x16:

-//        break;

-//

-//    case fFrexp:

-//    case fLdexp:

-//    case fPackUnorm4x8:

-//    case fPackSnorm4x8:

-//    case fUnpackUnorm4x8:

-//    case fUnpackSnorm4x8:

-//    case fPackDouble2x32:

-//    case fUnpackDouble2x32:

-//        break;

-//    case fLength:

-//       // scalar result type

-//       break;

-//    case any:

-//    case all:

-//        // fixed result type

-//        break;

-//    case fModF:

-//        // modf() will return a struct that the caller must decode

-//        break;

-//    default:

-//        // Unary operations that have operand and dest with same flexible type

-//        break;

-//    }

-//

-//    assert(opCode);

-//

-//    Instruction* instr = (opCode, operand);

-//    setPrecision(instr, precision);

-//

-//    return instr;

-//}

-//

-//// Comments in header

-//Id Builder::createOperation(Decoration precision, Op opCode, Id operand0, Id operand1)

-//{

-//    Function* opCode = 0;

-//

-//    // Handle special return types here.  Things that don't have same result type as parameter

-//    switch (opCode) {

-//    case fDistance:

-//    case fDot2:

-//    case fDot3:

-//    case fDot4:

-//        // scalar result type

-//        break;

-//    case fStep:

-//        // first argument can be scalar, return and second argument match

-//        break;

-//    case fSmoothStep:

-//        // first argument can be scalar, return and second argument match

-//        break;

-//    default:

-//        // Binary operations that have operand and dest with same flexible type

-//        break;

-//    }

-//

-//    assert(opCode);

-//

-//    Instruction* instr = (opCode, operand0, operand1);

-//    setPrecision(instr, precision);

-//

-//    return instr;

-//}

-//

-//Id Builder::createOperation(Decoration precision, Op opCode, Id operand0, Id operand1, Id operand2)

-//{

-//    Function* opCode;

-//

-//    // Handle special return types here.  Things that don't have same result type as parameter

-//    switch (opCode) {

-//    case fSmoothStep:

-//        // first argument can be scalar, return and second argument match

-//        break;

-//    default:

-//        // Use operand0 type as result type

-//        break;

-//    }

-//

-//    assert(opCode);

-//

-//    Instruction* instr = (opCode, operand0, operand1, operand2);

-//    setPrecision(instr, precision);

-//

-//    return instr;

-//}

-

-// OpCompositeConstruct

-Id Builder::createCompositeConstruct(Id typeId, std::vector<Id>& constituents)

-{

-    assert(isAggregateType(typeId) || getNumTypeComponents(typeId) > 1 && getNumTypeComponents(typeId) == constituents.size());

-

-    Instruction* op = new Instruction(getUniqueId(), typeId, OpCompositeConstruct);

-    for (int c = 0; c < (int)constituents.size(); ++c)

-        op->addIdOperand(constituents[c]);

-    buildPoint->addInstruction(op);

-

-    return op->getResultId();

-}

-

-// Vector or scalar constructor

-Id Builder::createConstructor(Decoration precision, const std::vector<Id>& sources, Id resultTypeId)

-{

-    Id result = 0;

-    unsigned int numTargetComponents = getNumTypeComponents(resultTypeId);

-    unsigned int targetComponent = 0;

-

-    // Special case: when calling a vector constructor with a single scalar

-    // argument, smear the scalar

-    if (sources.size() == 1 && isScalar(sources[0]) && numTargetComponents > 1)

-        return smearScalar(precision, sources[0], resultTypeId);

-

-    Id scalarTypeId = getScalarTypeId(resultTypeId);

-    std::vector<Id> constituents;  // accumulate the arguments for OpCompositeConstruct

-    for (unsigned int i = 0; i < sources.size(); ++i) {

-        if (isAggregate(sources[i]))

-            MissingFunctionality("aggregate in vector constructor");

-

-        unsigned int sourceSize = getNumComponents(sources[i]);

-

-        unsigned int sourcesToUse = sourceSize;

-        if (sourcesToUse + targetComponent > numTargetComponents)

-            sourcesToUse = numTargetComponents - targetComponent;

-

-        for (unsigned int s = 0; s < sourcesToUse; ++s) {

-            Id arg = sources[i];

-            if (sourceSize > 1) {

-                std::vector<unsigned> swiz;

-                swiz.push_back(s);

-                arg = createRvalueSwizzle(scalarTypeId, arg, swiz);

-            }

-

-            if (numTargetComponents > 1)

-                constituents.push_back(arg);

-            else

-                result = arg;

-            ++targetComponent;

-        }

-

-        if (targetComponent >= numTargetComponents)

-            break;

-    }

-

-    if (constituents.size() > 0)

-        result = createCompositeConstruct(resultTypeId, constituents);

-

-    setPrecision(result, precision);

-

-    return result;

-}

-

-// Comments in header

-Id Builder::createMatrixConstructor(Decoration precision, const std::vector<Id>& sources, Id resultTypeId)

-{

-    Id componentTypeId = getScalarTypeId(resultTypeId);

-    int numCols = getTypeNumColumns(resultTypeId);

-    int numRows = getTypeNumRows(resultTypeId);

-

-    // Will use a two step process

-    // 1. make a compile-time 2D array of values

-    // 2. construct a matrix from that array

-

-    // Step 1.

-

-    // initialize the array to the identity matrix

-    Id ids[maxMatrixSize][maxMatrixSize];

-    Id  one = makeFloatConstant(1.0);

-    Id zero = makeFloatConstant(0.0);

-    for (int col = 0; col < 4; ++col) {

-        for (int row = 0; row < 4; ++row) {

-            if (col == row)

-                ids[col][row] = one;

-            else

-                ids[col][row] = zero;

-        }

-    }

-

-    // modify components as dictated by the arguments

-    if (sources.size() == 1 && isScalar(sources[0])) {

-        // a single scalar; resets the diagonals

-        for (int col = 0; col < 4; ++col)

-            ids[col][col] = sources[0];

-    } else if (isMatrix(sources[0])) {

-        // constructing from another matrix; copy over the parts that exist in both the argument and constructee

-        Id matrix = sources[0];

-        int minCols = std::min(numCols, getNumColumns(matrix));

-        int minRows = std::min(numRows, getNumRows(matrix));

-        for (int col = 0; col < minCols; ++col) {

-            std::vector<unsigned> indexes;

-            indexes.push_back(col);

-            for (int row = 0; row < minRows; ++row) {

-                indexes.push_back(row);

-                ids[col][row] = createCompositeExtract(matrix, componentTypeId, indexes);

-                indexes.pop_back();

-                setPrecision(ids[col][row], precision);

-            }

-        }

-    } else {

-        // fill in the matrix in column-major order with whatever argument components are available

-        int row = 0;

-        int col = 0;

-

-        for (int arg = 0; arg < (int)sources.size(); ++arg) {

-            Id argComp = sources[arg];

-            for (int comp = 0; comp < getNumComponents(sources[arg]); ++comp) {

-                if (getNumComponents(sources[arg]) > 1) {

-                    argComp = createCompositeExtract(sources[arg], componentTypeId, comp);

-                    setPrecision(argComp, precision);

-                }

-                ids[col][row++] = argComp;

-                if (row == numRows) {

-                    row = 0;

-                    col++;

-                }

-            }

-        }

-    }

-

-

-    // Step 2:  Construct a matrix from that array.

-    // First make the column vectors, then make the matrix.

-

-    // make the column vectors

-    Id columnTypeId = getContainedTypeId(resultTypeId);

-    std::vector<Id> matrixColumns;

-    for (int col = 0; col < numCols; ++col) {

-        std::vector<Id> vectorComponents;

-        for (int row = 0; row < numRows; ++row)

-            vectorComponents.push_back(ids[col][row]);

-        matrixColumns.push_back(createCompositeConstruct(columnTypeId, vectorComponents));

-    }

-

-    // make the matrix

-    return createCompositeConstruct(resultTypeId, matrixColumns);

-}

-

-// Comments in header

-Builder::If::If(Id cond, Builder& gb) :

-    builder(gb),

-    condition(cond),

-    elseBlock(0)

-{

-    function = &builder.getBuildPoint()->getParent();

-

-    // make the blocks, but only put the then-block into the function,

-    // the else-block and merge-block will be added later, in order, after

-    // earlier code is emitted

-    thenBlock = new Block(builder.getUniqueId(), *function);

-    mergeBlock = new Block(builder.getUniqueId(), *function);

-

-    // Save the current block, so that we can add in the flow control split when

-    // makeEndIf is called.

-    headerBlock = builder.getBuildPoint();

-

-    function->addBlock(thenBlock);

-    builder.setBuildPoint(thenBlock);

-}

-

-// Comments in header

-void Builder::If::makeBeginElse()

-{

-    // Close out the "then" by having it jump to the mergeBlock

-    builder.createBranch(mergeBlock);

-

-    // Make the first else block and add it to the function

-    elseBlock = new Block(builder.getUniqueId(), *function);

-    function->addBlock(elseBlock);

-

-    // Start building the else block

-    builder.setBuildPoint(elseBlock);

-}

-

-// Comments in header

-void Builder::If::makeEndIf()

-{

-    // jump to the merge block

-    builder.createBranch(mergeBlock);

-

-    // Go back to the headerBlock and make the flow control split

-    builder.setBuildPoint(headerBlock);

-    builder.createMerge(OpSelectionMerge, mergeBlock, SelectionControlMaskNone);

-    if (elseBlock)

-        builder.createConditionalBranch(condition, thenBlock, elseBlock);

-    else

-        builder.createConditionalBranch(condition, thenBlock, mergeBlock);

-

-    // add the merge block to the function

-    function->addBlock(mergeBlock);

-    builder.setBuildPoint(mergeBlock);

-}

-

-// Comments in header

-void Builder::makeSwitch(Id selector, int numSegments, std::vector<int>& caseValues, std::vector<int>& valueIndexToSegment, int defaultSegment,

-                         std::vector<Block*>& segmentBlocks)

-{

-    Function& function = buildPoint->getParent();

-

-    // make all the blocks

-    for (int s = 0; s < numSegments; ++s)

-        segmentBlocks.push_back(new Block(getUniqueId(), function));

-

-    Block* mergeBlock = new Block(getUniqueId(), function);

-

-    // make and insert the switch's selection-merge instruction

-    createMerge(OpSelectionMerge, mergeBlock, SelectionControlMaskNone);

-

-    // make the switch instruction

-    Instruction* switchInst = new Instruction(NoResult, NoType, OpSwitch);

-    switchInst->addIdOperand(selector);

-    switchInst->addIdOperand(defaultSegment >= 0 ? segmentBlocks[defaultSegment]->getId() : mergeBlock->getId());

-    for (int i = 0; i < (int)caseValues.size(); ++i) {

-        switchInst->addImmediateOperand(caseValues[i]);

-        switchInst->addIdOperand(segmentBlocks[valueIndexToSegment[i]]->getId());

-    }

-    buildPoint->addInstruction(switchInst);

-

-    // push the merge block

-    switchMerges.push(mergeBlock);

-}

-

-// Comments in header

-void Builder::addSwitchBreak()

-{

-    // branch to the top of the merge block stack

-    createBranch(switchMerges.top());

-    createAndSetNoPredecessorBlock("post-switch-break");

-}

-

-// Comments in header

-void Builder::nextSwitchSegment(std::vector<Block*>& segmentBlock, int nextSegment)

-{

-    int lastSegment = nextSegment - 1;

-    if (lastSegment >= 0) {

-        // Close out previous segment by jumping, if necessary, to next segment

-        if (! buildPoint->isTerminated())

-            createBranch(segmentBlock[nextSegment]);

-    }

-    Block* block = segmentBlock[nextSegment];

-    block->getParent().addBlock(block);

-    setBuildPoint(block);

-}

-

-// Comments in header

-void Builder::endSwitch(std::vector<Block*>& /*segmentBlock*/)

-{

-    // Close out previous segment by jumping, if necessary, to next segment

-    if (! buildPoint->isTerminated())

-        addSwitchBreak();

-

-    switchMerges.top()->getParent().addBlock(switchMerges.top());

-    setBuildPoint(switchMerges.top());

-

-    switchMerges.pop();

-}

-

-// Comments in header

-void Builder::makeNewLoop()

-{

-    Loop loop = { };

-

-    loop.function = &getBuildPoint()->getParent();

-    loop.header = new Block(getUniqueId(), *loop.function);

-    loop.merge  = new Block(getUniqueId(), *loop.function);

-    loop.test   = NULL;

-

-    loops.push(loop);

-

-    // Branch into the loop

-    createBranch(loop.header);

-

-    // Set ourselves inside the loop

-    loop.function->addBlock(loop.header);

-    setBuildPoint(loop.header);

-}

-

-void Builder::createLoopTestBranch(Id condition)

-{

-    Loop& loop = loops.top();

-

-    // If loop.test exists, then we've already generated the LoopMerge

-    // for this loop.

-    if (!loop.test)

-      createMerge(OpLoopMerge, loop.merge, LoopControlMaskNone);

-

-    // Branching to the "body" block will keep control inside

-    // the loop.

-    Block* body = new Block(getUniqueId(), *loop.function);

-    createConditionalBranch(condition, body, loop.merge);

-    loop.function->addBlock(body);

-    setBuildPoint(body);

-}

-

-void Builder::endLoopHeaderWithoutTest()

-{

-    Loop& loop = loops.top();

-

-    createMerge(OpLoopMerge, loop.merge, LoopControlMaskNone);

-    Block* body = new Block(getUniqueId(), *loop.function);

-    createBranch(body);

-    loop.function->addBlock(body);

-    setBuildPoint(body);

-

-    assert(!loop.test);

-    loop.test = new Block(getUniqueId(), *loop.function);

-}

-

-void Builder::createBranchToLoopTest()

-{

-    Loop& loop = loops.top();

-    Block* testBlock = loop.test;

-    assert(testBlock);

-    createBranch(testBlock);

-    loop.function->addBlock(testBlock);

-    setBuildPoint(testBlock);

-}

-

-void Builder::createLoopContinue()

-{

-    Loop& loop = loops.top();

-    if (loop.test)

-      createBranch(loop.test);

-    else

-      createBranch(loop.header);

-    // Set up a block for dead code.

-    createAndSetNoPredecessorBlock("post-loop-continue");

-}

-

-// Add an exit (e.g. "break") for the innermost loop that you're in

-void Builder::createLoopExit()

-{

-    createBranch(loops.top().merge);

-    // Set up a block for dead code.

-    createAndSetNoPredecessorBlock("post-loop-break");

-}

-

-// Close the innermost loop

-void Builder::closeLoop()

-{

-    Loop& loop = loops.top();

-

-    // Branch back to the top

-    createBranch(loop.header);

-

-    // Add the merge block and set the build point to it

-    loop.function->addBlock(loop.merge);

-    setBuildPoint(loop.merge);

-

-    loops.pop();

-}

-

-void Builder::clearAccessChain()

-{

-    accessChain.base = 0;

-    accessChain.indexChain.clear();

-    accessChain.instr = 0;

-    accessChain.swizzle.clear();

-    accessChain.component = 0;

-    accessChain.resultType = NoType;

-    accessChain.isRValue = false;

-}

-

-// Comments in header

-void Builder::accessChainPushSwizzle(std::vector<unsigned>& swizzle)

-{

-    // if needed, propagate the swizzle for the current access chain

-    if (accessChain.swizzle.size()) {

-        std::vector<unsigned> oldSwizzle = accessChain.swizzle;

-        accessChain.swizzle.resize(0);

-        for (unsigned int i = 0; i < swizzle.size(); ++i) {

-            accessChain.swizzle.push_back(oldSwizzle[swizzle[i]]);

-        }

-    } else

-        accessChain.swizzle = swizzle;

-

-    // determine if we need to track this swizzle anymore

-    simplifyAccessChainSwizzle();

-}

-

-// Comments in header

-void Builder::accessChainStore(Id rvalue)

-{

-    assert(accessChain.isRValue == false);

-

-    Id base = collapseAccessChain();

-

-    if (accessChain.swizzle.size() && accessChain.component)

-        MissingFunctionality("simultaneous l-value swizzle and dynamic component selection");

-

-    // If swizzle exists, it is out-of-order or not full, we must load the target vector,

-    // extract and insert elements to perform writeMask and/or swizzle.

-    Id source = NoResult;

-    if (accessChain.swizzle.size()) {

-        Id tempBaseId = createLoad(base);

-        source = createLvalueSwizzle(getTypeId(tempBaseId), tempBaseId, rvalue, accessChain.swizzle);

-    }

-

-    // dynamic component selection

-    if (accessChain.component) {

-        Id tempBaseId = (source == NoResult) ? createLoad(base) : source;

-        source = createVectorInsertDynamic(tempBaseId, getTypeId(tempBaseId), rvalue, accessChain.component);

-    }

-

-    if (source == NoResult)

-        source = rvalue;

-

-    createStore(source, base);

-}

-

-// Comments in header

-Id Builder::accessChainLoad(Decoration /*precision*/)

-{

-    Id id;

-

-    if (accessChain.isRValue) {

-        if (accessChain.indexChain.size() > 0) {

-            mergeAccessChainSwizzle();  // TODO: optimization: look at applying this optimization more widely

-            // if all the accesses are constants, we can use OpCompositeExtract

-            std::vector<unsigned> indexes;

-            bool constant = true;

-            for (int i = 0; i < (int)accessChain.indexChain.size(); ++i) {

-                if (isConstantScalar(accessChain.indexChain[i]))

-                    indexes.push_back(getConstantScalar(accessChain.indexChain[i]));

-                else {

-                    constant = false;

-                    break;

-                }

-            }

-

-            if (constant)

-                id = createCompositeExtract(accessChain.base, accessChain.resultType, indexes);

-            else {

-                // make a new function variable for this r-value

-                Id lValue = createVariable(StorageClassFunction, getTypeId(accessChain.base), "indexable");

-

-                // store into it

-                createStore(accessChain.base, lValue);

-

-                // move base to the new variable

-                accessChain.base = lValue;

-                accessChain.isRValue = false;

-

-                // load through the access chain

-                id = createLoad(collapseAccessChain());

-            }

-        } else

-            id = accessChain.base;

-    } else {

-        // load through the access chain

-        id = createLoad(collapseAccessChain());

-    }

-

-    // Done, unless there are swizzles to do

-    if (accessChain.swizzle.size() == 0 && accessChain.component == 0)

-        return id;

-

-    Id componentType = getScalarTypeId(accessChain.resultType);

-

-    // Do remaining swizzling

-    // First, static swizzling

-    if (accessChain.swizzle.size()) {

-        // static swizzle

-        Id resultType = componentType;

-        if (accessChain.swizzle.size() > 1)

-            resultType = makeVectorType(componentType, accessChain.swizzle.size());

-        id = createRvalueSwizzle(resultType, id, accessChain.swizzle);

-    }

-

-    // dynamic single-component selection

-    if (accessChain.component)

-        id = createVectorExtractDynamic(id, componentType, accessChain.component);

-

-    return id;

-}

-

-Id Builder::accessChainGetLValue()

-{

-    assert(accessChain.isRValue == false);

-

-    Id lvalue = collapseAccessChain();

-

-    // If swizzle exists, it is out-of-order or not full, we must load the target vector,

-    // extract and insert elements to perform writeMask and/or swizzle.  This does not

-    // go with getting a direct l-value pointer.

-    assert(accessChain.swizzle.size() == 0);

-    assert(accessChain.component == spv::NoResult);

-

-    return lvalue;

-}

-

-void Builder::dump(std::vector<unsigned int>& out) const

-{

-    // Header, before first instructions:

-    out.push_back(MagicNumber);

-    out.push_back(Version);

-    out.push_back(builderNumber);

-    out.push_back(uniqueId + 1);

-    out.push_back(0);

-

-    // First instructions, some created on the spot here:

-    if (source != SourceLanguageUnknown) {

-        Instruction sourceInst(0, 0, OpSource);

-        sourceInst.addImmediateOperand(source);

-        sourceInst.addImmediateOperand(sourceVersion);

-        sourceInst.dump(out);

-    }

-    for (int e = 0; e < (int)extensions.size(); ++e) {

-        Instruction extInst(0, 0, OpSourceExtension);

-        extInst.addStringOperand(extensions[e]);

-        extInst.dump(out);

-    }

-    // TBD: OpExtension ...

-    dumpInstructions(out, imports);

-    Instruction memInst(0, 0, OpMemoryModel);

-    memInst.addImmediateOperand(addressModel);

-    memInst.addImmediateOperand(memoryModel);

-    memInst.dump(out);

-

-    // Instructions saved up while building:

-    dumpInstructions(out, entryPoints);

-    dumpInstructions(out, executionModes);

-    dumpInstructions(out, names);

-    dumpInstructions(out, lines);

-    dumpInstructions(out, decorations);

-    dumpInstructions(out, constantsTypesGlobals);

-    dumpInstructions(out, externals);

-

-    // The functions

-    module.dump(out);

-}

-

-//

-// Protected methods.

-//

-

-Id Builder::collapseAccessChain()

-{

-    // TODO: bring in an individual component swizzle here, so that a pointer 

-    // all the way to the component level can be created.

-    assert(accessChain.isRValue == false);

-

-    if (accessChain.indexChain.size() > 0) {

-        if (accessChain.instr == 0) {

-            StorageClass storageClass = (StorageClass)module.getStorageClass(getTypeId(accessChain.base));

-            accessChain.instr = createAccessChain(storageClass, accessChain.base, accessChain.indexChain);

-        }

-

-        return accessChain.instr;

-    } else

-        return accessChain.base;

-}

-

-// clear out swizzle if it is redundant

-void Builder::simplifyAccessChainSwizzle()

-{

-    // If the swizzle has fewer components than the vector, it is subsetting, and must stay

-    // to preserve that fact.

-    if (getNumTypeComponents(accessChain.resultType) > (int)accessChain.swizzle.size())

-        return;

-

-    // if components are out of order, it is a swizzle

-    for (unsigned int i = 0; i < accessChain.swizzle.size(); ++i) {

-        if (i != accessChain.swizzle[i])

-            return;

-    }

-

-    // otherwise, there is no need to track this swizzle

-    accessChain.swizzle.clear();

-}

-

-// clear out swizzle if it can become part of the indexes

-void Builder::mergeAccessChainSwizzle()

-{

-    // is there even a chance of doing something?  Need a single-component swizzle

-    if ((accessChain.swizzle.size() > 1) ||

-        (accessChain.swizzle.size() == 0 && accessChain.component == 0))

-        return;

-

-    // TODO: optimization: remove this, but for now confine this to non-dynamic accesses

-    // (the above test is correct when this is removed.)

-    if (accessChain.component)

-        return;

-

-    // move the swizzle over to the indexes

-    if (accessChain.swizzle.size() == 1)

-        accessChain.indexChain.push_back(makeUintConstant(accessChain.swizzle.front()));

-    else

-        accessChain.indexChain.push_back(accessChain.component);

-    accessChain.resultType = getScalarTypeId(accessChain.resultType);

-

-    // now there is no need to track this swizzle

-    accessChain.component = NoResult;

-    accessChain.swizzle.clear();

-}

-

-// Utility method for creating a new block and setting the insert point to

-// be in it. This is useful for flow-control operations that need a "dummy"

-// block proceeding them (e.g. instructions after a discard, etc).

-void Builder::createAndSetNoPredecessorBlock(const char* /*name*/)

-{

-    Block* block = new Block(getUniqueId(), buildPoint->getParent());

-    block->setUnreachable();

-    buildPoint->getParent().addBlock(block);

-    setBuildPoint(block);

-

-    //if (name)

-    //    addName(block->getId(), name);

-}

-

-// Comments in header

-void Builder::createBranch(Block* block)

-{

-    Instruction* branch = new Instruction(OpBranch);

-    branch->addIdOperand(block->getId());

-    buildPoint->addInstruction(branch);

-    block->addPredecessor(buildPoint);

-}

-

-void Builder::createMerge(Op mergeCode, Block* mergeBlock, unsigned int control)

-{

-    Instruction* merge = new Instruction(mergeCode);

-    merge->addIdOperand(mergeBlock->getId());

-    merge->addImmediateOperand(control);

-    buildPoint->addInstruction(merge);

-}

-

-void Builder::createConditionalBranch(Id condition, Block* thenBlock, Block* elseBlock)

-{

-    Instruction* branch = new Instruction(OpBranchConditional);

-    branch->addIdOperand(condition);

-    branch->addIdOperand(thenBlock->getId());

-    branch->addIdOperand(elseBlock->getId());

-    buildPoint->addInstruction(branch);

-    thenBlock->addPredecessor(buildPoint);

-    elseBlock->addPredecessor(buildPoint);

-}

-

-void Builder::dumpInstructions(std::vector<unsigned int>& out, const std::vector<Instruction*>& instructions) const

-{

-    for (int i = 0; i < (int)instructions.size(); ++i) {

-        instructions[i]->dump(out);

-    }

-}

-

-void MissingFunctionality(const char* fun)

-{

-    printf("Missing functionality: %s\n", fun);

-    exit(1);

-}

-

-void ValidationError(const char* error)

-{

-    printf("Validation Error: %s\n", error);

-}

-

-}; // end spv namespace

+//
+//Copyright (C) 2014 LunarG, Inc.
+//
+//All rights reserved.
+//
+//Redistribution and use in source and binary forms, with or without
+//modification, are permitted provided that the following conditions
+//are met:
+//
+//    Redistributions of source code must retain the above copyright
+//    notice, this list of conditions and the following disclaimer.
+//
+//    Redistributions in binary form must reproduce the above
+//    copyright notice, this list of conditions and the following
+//    disclaimer in the documentation and/or other materials provided
+//    with the distribution.
+//
+//    Neither the name of 3Dlabs Inc. Ltd. nor the names of its
+//    contributors may be used to endorse or promote products derived
+//    from this software without specific prior written permission.
+//
+//THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+//"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+//LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+//FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+//COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+//INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+//BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+//LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+//CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+//LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+//ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+//POSSIBILITY OF SUCH DAMAGE.
+
+//
+// Author: John Kessenich, LunarG
+//
+
+//
+// Helper for making SPIR-V IR.  Generally, this is documented in the header
+// SpvBuilder.h.
+//
+
+#include <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "SpvBuilder.h"
+
+#ifndef _WIN32
+    #include <cstdio>
+#endif
+
+namespace spv {
+
+const int SpvBuilderMagic = 0xBB;
+
+Builder::Builder(unsigned int userNumber) :
+    source(SourceLanguageUnknown),
+    sourceVersion(0),
+    addressModel(AddressingModelLogical),
+    memoryModel(MemoryModelGLSL450),
+    builderNumber(userNumber << 16 | SpvBuilderMagic),
+    buildPoint(0),
+    uniqueId(0),
+    mainFunction(0),
+    stageExit(0)
+{
+    clearAccessChain();
+}
+
+Builder::~Builder()
+{
+}
+
+Id Builder::import(const char* name)
+{
+    Instruction* import = new Instruction(getUniqueId(), NoType, OpExtInstImport);
+    import->addStringOperand(name);
+    
+    imports.push_back(import);
+    return import->getResultId();
+}
+
+// For creating new groupedTypes (will return old type if the requested one was already made).
+Id Builder::makeVoidType()
+{
+    Instruction* type;
+    if (groupedTypes[OpTypeVoid].size() == 0) {
+        type = new Instruction(getUniqueId(), NoType, OpTypeVoid);
+        groupedTypes[OpTypeVoid].push_back(type);
+        constantsTypesGlobals.push_back(type);
+        module.mapInstruction(type);
+    } else
+        type = groupedTypes[OpTypeVoid].back();
+
+    return type->getResultId();
+}
+
+Id Builder::makeBoolType()
+{
+    Instruction* type;
+    if (groupedTypes[OpTypeBool].size() == 0) {
+        type = new Instruction(getUniqueId(), NoType, OpTypeBool);
+        groupedTypes[OpTypeBool].push_back(type);
+        constantsTypesGlobals.push_back(type);
+        module.mapInstruction(type);
+    } else
+        type = groupedTypes[OpTypeBool].back();
+
+    return type->getResultId();
+}
+
+Id Builder::makePointer(StorageClass storageClass, Id pointee)
+{
+    // try to find it
+    Instruction* type;
+    for (int t = 0; t < (int)groupedTypes[OpTypePointer].size(); ++t) {
+        type = groupedTypes[OpTypePointer][t];
+        if (type->getImmediateOperand(0) == (unsigned)storageClass &&
+            type->getIdOperand(1) == pointee)
+            return type->getResultId();
+    }
+
+    // not found, make it
+    type = new Instruction(getUniqueId(), NoType, OpTypePointer);
+    type->addImmediateOperand(storageClass);
+    type->addIdOperand(pointee);
+    groupedTypes[OpTypePointer].push_back(type);
+    constantsTypesGlobals.push_back(type);
+    module.mapInstruction(type);
+
+    return type->getResultId();
+}
+
+Id Builder::makeIntegerType(int width, bool hasSign)
+{
+    // try to find it
+    Instruction* type;
+    for (int t = 0; t < (int)groupedTypes[OpTypeInt].size(); ++t) {
+        type = groupedTypes[OpTypeInt][t];
+        if (type->getImmediateOperand(0) == (unsigned)width &&
+            type->getImmediateOperand(1) == (hasSign ? 1u : 0u))
+            return type->getResultId();
+    }
+
+    // not found, make it
+    type = new Instruction(getUniqueId(), NoType, OpTypeInt);
+    type->addImmediateOperand(width);
+    type->addImmediateOperand(hasSign ? 1 : 0);
+    groupedTypes[OpTypeInt].push_back(type);
+    constantsTypesGlobals.push_back(type);
+    module.mapInstruction(type);
+
+    return type->getResultId();
+}
+
+Id Builder::makeFloatType(int width)
+{
+    // try to find it
+    Instruction* type;
+    for (int t = 0; t < (int)groupedTypes[OpTypeFloat].size(); ++t) {
+        type = groupedTypes[OpTypeFloat][t];
+        if (type->getImmediateOperand(0) == (unsigned)width)
+            return type->getResultId();
+    }
+
+    // not found, make it
+    type = new Instruction(getUniqueId(), NoType, OpTypeFloat);
+    type->addImmediateOperand(width);
+    groupedTypes[OpTypeFloat].push_back(type);
+    constantsTypesGlobals.push_back(type);
+    module.mapInstruction(type);
+
+    return type->getResultId();
+}
+
+Id Builder::makeStructType(std::vector<Id>& members, const char* name)
+{
+    // not found, make it
+    Instruction* type = new Instruction(getUniqueId(), NoType, OpTypeStruct);
+    for (int op = 0; op < (int)members.size(); ++op)
+        type->addIdOperand(members[op]);
+    groupedTypes[OpTypeStruct].push_back(type);
+    constantsTypesGlobals.push_back(type);
+    module.mapInstruction(type);
+    addName(type->getResultId(), name);
+
+    return type->getResultId();
+}
+
+Id Builder::makeVectorType(Id component, int size)
+{
+    // try to find it
+    Instruction* type;
+    for (int t = 0; t < (int)groupedTypes[OpTypeVector].size(); ++t) {
+        type = groupedTypes[OpTypeVector][t];
+        if (type->getIdOperand(0) == component &&
+            type->getImmediateOperand(1) == (unsigned)size)
+            return type->getResultId();
+    }
+
+    // not found, make it
+    type = new Instruction(getUniqueId(), NoType, OpTypeVector);
+    type->addIdOperand(component);
+    type->addImmediateOperand(size);
+    groupedTypes[OpTypeVector].push_back(type);
+    constantsTypesGlobals.push_back(type);
+    module.mapInstruction(type);
+
+    return type->getResultId();
+}
+
+Id Builder::makeMatrixType(Id component, int cols, int rows)
+{
+    assert(cols <= maxMatrixSize && rows <= maxMatrixSize);
+
+    Id column = makeVectorType(component, rows);
+
+    // try to find it
+    Instruction* type;
+    for (int t = 0; t < (int)groupedTypes[OpTypeMatrix].size(); ++t) {
+        type = groupedTypes[OpTypeMatrix][t];
+        if (type->getIdOperand(0) == column &&
+            type->getImmediateOperand(1) == (unsigned)cols)
+            return type->getResultId();
+    }
+
+    // not found, make it
+    type = new Instruction(getUniqueId(), NoType, OpTypeMatrix);
+    type->addIdOperand(column);
+    type->addImmediateOperand(cols);
+    groupedTypes[OpTypeMatrix].push_back(type);
+    constantsTypesGlobals.push_back(type);
+    module.mapInstruction(type);
+
+    return type->getResultId();
+}
+
+Id Builder::makeArrayType(Id element, unsigned size)
+{
+    // First, we need a constant instruction for the size
+    Id sizeId = makeUintConstant(size);
+
+    // try to find existing type
+    Instruction* type;
+    for (int t = 0; t < (int)groupedTypes[OpTypeArray].size(); ++t) {
+        type = groupedTypes[OpTypeArray][t];
+        if (type->getIdOperand(0) == element &&
+            type->getIdOperand(1) == sizeId)
+            return type->getResultId();
+    }
+
+    // not found, make it
+    type = new Instruction(getUniqueId(), NoType, OpTypeArray);
+    type->addIdOperand(element);
+    type->addIdOperand(sizeId);
+    groupedTypes[OpTypeArray].push_back(type);
+    constantsTypesGlobals.push_back(type);
+    module.mapInstruction(type);
+
+    return type->getResultId();
+}
+
+Id Builder::makeFunctionType(Id returnType, std::vector<Id>& paramTypes)
+{
+    // try to find it
+    Instruction* type;
+    for (int t = 0; t < (int)groupedTypes[OpTypeFunction].size(); ++t) {
+        type = groupedTypes[OpTypeFunction][t];
+        if (type->getIdOperand(0) != returnType || (int)paramTypes.size() != type->getNumOperands() - 1)
+            continue;
+        bool mismatch = false;
+        for (int p = 0; p < (int)paramTypes.size(); ++p) {
+            if (paramTypes[p] != type->getIdOperand(p + 1)) {
+                mismatch = true;
+                break;
+            }
+        }
+        if (! mismatch)
+            return type->getResultId();            
+    }
+
+    // not found, make it
+    type = new Instruction(getUniqueId(), NoType, OpTypeFunction);
+    type->addIdOperand(returnType);
+    for (int p = 0; p < (int)paramTypes.size(); ++p)
+        type->addIdOperand(paramTypes[p]);
+    groupedTypes[OpTypeFunction].push_back(type);
+    constantsTypesGlobals.push_back(type);
+    module.mapInstruction(type);
+
+    return type->getResultId();
+}
+
+Id Builder::makeSampler(Id sampledType, Dim dim, samplerContent content, bool arrayed, bool shadow, bool ms)
+{
+    // try to find it
+    Instruction* type;
+    for (int t = 0; t < (int)groupedTypes[OpTypeSampler].size(); ++t) {
+        type = groupedTypes[OpTypeSampler][t];
+        if (type->getIdOperand(0) == sampledType &&
+            type->getImmediateOperand(1) == (unsigned int)dim &&
+            type->getImmediateOperand(2) == (unsigned int)content &&
+            type->getImmediateOperand(3) == (arrayed ? 1u : 0u) &&
+            type->getImmediateOperand(4) == ( shadow ? 1u : 0u) &&
+            type->getImmediateOperand(5) == (     ms ? 1u : 0u))
+            return type->getResultId();
+    }
+
+    // not found, make it
+    type = new Instruction(getUniqueId(), NoType, OpTypeSampler);
+    type->addIdOperand(sampledType);
+    type->addImmediateOperand(   dim);
+    type->addImmediateOperand(content);
+    type->addImmediateOperand(arrayed ? 1 : 0);
+    type->addImmediateOperand( shadow ? 1 : 0);
+    type->addImmediateOperand(     ms ? 1 : 0);
+
+    groupedTypes[OpTypeSampler].push_back(type);
+    constantsTypesGlobals.push_back(type);
+    module.mapInstruction(type);
+
+    return type->getResultId();
+}
+
+Id Builder::getDerefTypeId(Id resultId) const
+{
+    Id typeId = getTypeId(resultId);
+    assert(isPointerType(typeId));
+
+    return module.getInstruction(typeId)->getImmediateOperand(1);
+}
+
+Op Builder::getMostBasicTypeClass(Id typeId) const
+{
+    Instruction* instr = module.getInstruction(typeId);
+
+    Op typeClass = instr->getOpCode();
+    switch (typeClass)
+    {
+    case OpTypeVoid:
+    case OpTypeBool:
+    case OpTypeInt:
+    case OpTypeFloat:
+    case OpTypeStruct:
+        return typeClass;
+    case OpTypeVector:
+    case OpTypeMatrix:
+    case OpTypeArray:
+    case OpTypeRuntimeArray:
+        return getMostBasicTypeClass(instr->getIdOperand(0));
+    case OpTypePointer:
+        return getMostBasicTypeClass(instr->getIdOperand(1));
+    default:
+        MissingFunctionality("getMostBasicTypeClass");
+        return OpTypeFloat;
+    }
+}
+
+int Builder::getNumTypeComponents(Id typeId) const
+{
+    Instruction* instr = module.getInstruction(typeId);
+
+    switch (instr->getOpCode())
+    {
+    case OpTypeBool:
+    case OpTypeInt:
+    case OpTypeFloat:
+        return 1;
+    case OpTypeVector:
+    case OpTypeMatrix:
+        return instr->getImmediateOperand(1);
+    default:
+        MissingFunctionality("getNumTypeComponents on non bool/int/float/vector/matrix");
+        return 1;
+    }
+}
+
+// Return the lowest-level type of scalar that an homogeneous composite is made out of.
+// Typically, this is just to find out if something is made out of ints or floats.
+// However, it includes returning a structure, if say, it is an array of structure.
+Id Builder::getScalarTypeId(Id typeId) const
+{
+    Instruction* instr = module.getInstruction(typeId);
+
+    Op typeClass = instr->getOpCode();
+    switch (typeClass)
+    {
+    case OpTypeVoid:
+    case OpTypeBool:
+    case OpTypeInt:
+    case OpTypeFloat:
+    case OpTypeStruct:
+        return instr->getResultId();
+    case OpTypeVector:
+    case OpTypeMatrix:
+    case OpTypeArray:
+    case OpTypeRuntimeArray:
+    case OpTypePointer:
+        return getScalarTypeId(getContainedTypeId(typeId));
+    default:
+        MissingFunctionality("getScalarTypeId");
+        return NoResult;
+    }
+}
+
+// Return the type of 'member' of a composite.
+Id Builder::getContainedTypeId(Id typeId, int member) const
+{
+    Instruction* instr = module.getInstruction(typeId);
+
+    Op typeClass = instr->getOpCode();
+    switch (typeClass)
+    {
+    case OpTypeVector:
+    case OpTypeMatrix:
+    case OpTypeArray:
+    case OpTypeRuntimeArray:
+        return instr->getIdOperand(0);
+    case OpTypePointer:
+        return instr->getIdOperand(1);
+    case OpTypeStruct:
+        return instr->getIdOperand(member);
+    default:
+        MissingFunctionality("getContainedTypeId");
+        return NoResult;
+    }
+}
+
+// Return the immediately contained type of a given composite type.
+Id Builder::getContainedTypeId(Id typeId) const
+{
+    return getContainedTypeId(typeId, 0);
+}
+
+// See if a scalar constant of this type has already been created, so it
+// can be reused rather than duplicated.  (Required by the specification).
+Id Builder::findScalarConstant(Op typeClass, Id typeId, unsigned value) const
+{
+    Instruction* constant;
+    for (int i = 0; i < (int)groupedConstants[typeClass].size(); ++i) {
+        constant = groupedConstants[typeClass][i];
+        if (constant->getNumOperands() == 1 &&
+            constant->getTypeId() == typeId &&
+            constant->getImmediateOperand(0) == value)
+            return constant->getResultId();
+    }
+
+    return 0;
+}
+
+// Version of findScalarConstant (see above) for scalars that take two operands (e.g. a 'double').
+Id Builder::findScalarConstant(Op typeClass, Id typeId, unsigned v1, unsigned v2) const
+{
+    Instruction* constant;
+    for (int i = 0; i < (int)groupedConstants[typeClass].size(); ++i) {
+        constant = groupedConstants[typeClass][i];
+        if (constant->getNumOperands() == 2 &&
+            constant->getTypeId() == typeId &&
+            constant->getImmediateOperand(0) == v1 &&
+            constant->getImmediateOperand(1) == v2)
+            return constant->getResultId();
+    }
+
+    return 0;
+}
+
+Id Builder::makeBoolConstant(bool b)
+{
+    Id typeId = makeBoolType();
+    Instruction* constant;
+
+    // See if we already made it
+    Id existing = 0;
+    for (int i = 0; i < (int)groupedConstants[OpTypeBool].size(); ++i) {
+        constant = groupedConstants[OpTypeBool][i];
+        if (constant->getTypeId() == typeId &&
+            (b ? (constant->getOpCode() == OpConstantTrue) : 
+                 (constant->getOpCode() == OpConstantFalse)))
+            existing = constant->getResultId();
+    }
+
+    if (existing)
+        return existing;
+
+    // Make it
+    Instruction* c = new Instruction(getUniqueId(), typeId, b ? OpConstantTrue : OpConstantFalse);
+    constantsTypesGlobals.push_back(c);
+    groupedConstants[OpTypeBool].push_back(c);
+    module.mapInstruction(c);
+
+    return c->getResultId();
+}
+
+Id Builder::makeIntConstant(Id typeId, unsigned value)
+{
+    Id existing = findScalarConstant(OpTypeInt, typeId, value);
+    if (existing)
+        return existing;
+
+    Instruction* c = new Instruction(getUniqueId(), typeId, OpConstant);
+    c->addImmediateOperand(value);
+    constantsTypesGlobals.push_back(c);
+    groupedConstants[OpTypeInt].push_back(c);
+    module.mapInstruction(c);
+
+    return c->getResultId();
+}
+
+Id Builder::makeFloatConstant(float f)
+{
+    Id typeId = makeFloatType(32);
+    unsigned value = *(unsigned int*)&f;
+    Id existing = findScalarConstant(OpTypeFloat, typeId, value);
+    if (existing)
+        return existing;
+
+    Instruction* c = new Instruction(getUniqueId(), typeId, OpConstant);
+    c->addImmediateOperand(value);
+    constantsTypesGlobals.push_back(c);
+    groupedConstants[OpTypeFloat].push_back(c);
+    module.mapInstruction(c);
+
+    return c->getResultId();
+}
+
+Id Builder::makeDoubleConstant(double d)
+{
+    Id typeId = makeFloatType(64);
+    unsigned long long value = *(unsigned long long*)&d;
+    unsigned op1 = value & 0xFFFFFFFF;
+    unsigned op2 = value >> 32;
+    Id existing = findScalarConstant(OpTypeFloat, typeId, op1, op2);
+    if (existing)
+        return existing;
+
+    Instruction* c = new Instruction(getUniqueId(), typeId, OpConstant);
+    c->addImmediateOperand(op1);
+    c->addImmediateOperand(op2);
+    constantsTypesGlobals.push_back(c);
+    groupedConstants[OpTypeFloat].push_back(c);
+    module.mapInstruction(c);
+
+    return c->getResultId();
+}
+
+Id Builder::findCompositeConstant(Op typeClass, std::vector<Id>& comps) const
+{
+    Instruction* constant = 0;
+    bool found = false;
+    for (int i = 0; i < (int)groupedConstants[typeClass].size(); ++i) {
+        constant = groupedConstants[typeClass][i];
+
+        // same shape?
+        if (constant->getNumOperands() != (int)comps.size())
+            continue;
+
+        // same contents?
+        bool mismatch = false;
+        for (int op = 0; op < constant->getNumOperands(); ++op) {
+            if (constant->getIdOperand(op) != comps[op]) {
+                mismatch = true;
+                break;
+            }
+        }
+        if (! mismatch) {
+            found = true;
+            break;
+        }
+    }
+
+    return found ? constant->getResultId() : NoResult;
+}
+
+// Comments in header
+Id Builder::makeCompositeConstant(Id typeId, std::vector<Id>& members)
+{
+    assert(typeId);
+    Op typeClass = getTypeClass(typeId);
+
+    switch (typeClass) {
+    case OpTypeVector:
+    case OpTypeArray:
+    case OpTypeStruct:
+    case OpTypeMatrix:
+        break;
+    default:
+        MissingFunctionality("Constant composite type in Builder");
+        return makeFloatConstant(0.0);
+    }
+
+    Id existing = findCompositeConstant(typeClass, members);
+    if (existing)
+        return existing;
+
+    Instruction* c = new Instruction(getUniqueId(), typeId, OpConstantComposite);
+    for (int op = 0; op < (int)members.size(); ++op)
+        c->addIdOperand(members[op]);
+    constantsTypesGlobals.push_back(c);
+    groupedConstants[typeClass].push_back(c);
+    module.mapInstruction(c);
+
+    return c->getResultId();
+}
+
+void Builder::addEntryPoint(ExecutionModel model, Function* function)
+{
+    Instruction* entryPoint = new Instruction(OpEntryPoint);
+    entryPoint->addImmediateOperand(model);
+    entryPoint->addIdOperand(function->getId());
+
+    entryPoints.push_back(entryPoint);
+}
+
+void Builder::addExecutionMode(Function* entryPoint, ExecutionMode mode, int value)
+{
+    // TODO: handle multiple optional arguments
+    Instruction* instr = new Instruction(OpExecutionMode);
+    instr->addIdOperand(entryPoint->getId());
+    instr->addImmediateOperand(mode);
+    if (value >= 0)
+        instr->addImmediateOperand(value);
+
+    executionModes.push_back(instr);
+}
+
+void Builder::addName(Id id, const char* string)
+{
+    Instruction* name = new Instruction(OpName);
+    name->addIdOperand(id);
+    name->addStringOperand(string);
+
+    names.push_back(name);
+}
+
+void Builder::addMemberName(Id id, int memberNumber, const char* string)
+{
+    Instruction* name = new Instruction(OpMemberName);
+    name->addIdOperand(id);
+    name->addImmediateOperand(memberNumber);
+    name->addStringOperand(string);
+
+    names.push_back(name);
+}
+
+void Builder::addLine(Id target, Id fileName, int lineNum, int column)
+{
+    Instruction* line = new Instruction(OpLine);
+    line->addIdOperand(target);
+    line->addIdOperand(fileName);
+    line->addImmediateOperand(lineNum);
+    line->addImmediateOperand(column);
+
+    lines.push_back(line);
+}
+
+void Builder::addDecoration(Id id, Decoration decoration, int num)
+{
+    Instruction* dec = new Instruction(OpDecorate);
+    dec->addIdOperand(id);
+    dec->addImmediateOperand(decoration);
+    if (num >= 0)
+        dec->addImmediateOperand(num);
+
+    decorations.push_back(dec);
+}
+
+void Builder::addMemberDecoration(Id id, unsigned int member, Decoration decoration, int num)
+{
+    Instruction* dec = new Instruction(OpMemberDecorate);
+    dec->addIdOperand(id);
+    dec->addImmediateOperand(member);
+    dec->addImmediateOperand(decoration);
+    if (num >= 0)
+        dec->addImmediateOperand(num);
+
+    decorations.push_back(dec);
+}
+
+// Comments in header
+Function* Builder::makeMain()
+{
+    assert(! mainFunction);
+
+    Block* entry;
+    std::vector<Id> params;
+
+    mainFunction = makeFunctionEntry(makeVoidType(), "main", params, &entry);
+    stageExit = new Block(getUniqueId(), *mainFunction);
+
+    return mainFunction;
+}
+
+// Comments in header
+void Builder::closeMain()
+{
+    setBuildPoint(stageExit);
+    stageExit->addInstruction(new Instruction(NoResult, NoType, OpReturn));
+    mainFunction->addBlock(stageExit);
+}
+
+// Comments in header
+Function* Builder::makeFunctionEntry(Id returnType, const char* name, std::vector<Id>& paramTypes, Block **entry)
+{
+    Id typeId = makeFunctionType(returnType, paramTypes);
+    Id firstParamId = paramTypes.size() == 0 ? 0 : getUniqueIds(paramTypes.size());
+    Function* function = new Function(getUniqueId(), returnType, typeId, firstParamId, module);
+
+    if (entry) {
+        *entry = new Block(getUniqueId(), *function);
+        function->addBlock(*entry);
+        setBuildPoint(*entry);
+    }
+
+    if (name)
+        addName(function->getId(), name);
+
+    return function;
+}
+
+// Comments in header
+void Builder::makeReturn(bool implicit, Id retVal, bool isMain)
+{
+    if (isMain && retVal)
+        MissingFunctionality("return value from main()");
+
+    if (isMain)
+        createBranch(stageExit);
+    else if (retVal) {
+        Instruction* inst = new Instruction(NoResult, NoType, OpReturnValue);
+        inst->addIdOperand(retVal);
+        buildPoint->addInstruction(inst);
+    } else
+        buildPoint->addInstruction(new Instruction(NoResult, NoType, OpReturn));
+
+    if (! implicit)
+        createAndSetNoPredecessorBlock("post-return");
+}
+
+// Comments in header
+void Builder::leaveFunction(bool main)
+{
+    Block* block = buildPoint;
+    Function& function = buildPoint->getParent();
+    assert(block);
+
+    // If our function did not contain a return, add a return void now.
+    if (! block->isTerminated()) {
+
+        // Whether we're in an unreachable (non-entry) block.
+        bool unreachable = function.getEntryBlock() != block && block->getNumPredecessors() == 0;
+
+        if (unreachable) {
+            // Given that this block is at the end of a function, it must be right after an
+            // explicit return, just remove it.
+            function.popBlock(block);
+        } else if (main)
+            makeMainReturn(true);
+        else {
+            // We're get a return instruction at the end of the current block,
+            // which for a non-void function is really error recovery (?), as the source
+            // being translated should have had an explicit return, which would have been
+            // followed by an unreachable block, which was handled above.
+            if (function.getReturnType() == makeVoidType())
+                makeReturn(true);
+            else {
+                Id retStorage = createVariable(StorageClassFunction, function.getReturnType(), "dummyReturn");
+                Id retValue = createLoad(retStorage);
+                makeReturn(true, retValue);
+            }
+        }
+    }
+
+    if (main)
+        closeMain();
+}
+
+// Comments in header
+void Builder::makeDiscard()
+{
+    buildPoint->addInstruction(new Instruction(OpKill));
+    createAndSetNoPredecessorBlock("post-discard");
+}
+
+// Comments in header
+Id Builder::createVariable(StorageClass storageClass, Id type, const char* name)
+{
+    Id pointerType = makePointer(storageClass, type);
+    Instruction* inst = new Instruction(getUniqueId(), pointerType, OpVariable);
+    inst->addImmediateOperand(storageClass);
+
+    switch (storageClass) {
+    case StorageClassUniformConstant:
+    case StorageClassUniform:
+    case StorageClassInput:
+    case StorageClassOutput:
+    case StorageClassWorkgroupLocal:
+    case StorageClassPrivateGlobal:
+    case StorageClassWorkgroupGlobal:
+        constantsTypesGlobals.push_back(inst);
+        module.mapInstruction(inst);
+        break;
+
+    case StorageClassFunction:
+        // Validation rules require the declaration in the entry block
+        buildPoint->getParent().addLocalVariable(inst);
+        break;
+
+    default:
+        MissingFunctionality("storage class in createVariable");
+        break;
+    }
+
+    if (name)
+        addName(inst->getResultId(), name);
+
+    return inst->getResultId();
+}
+
+// Comments in header
+void Builder::createStore(Id rValue, Id lValue)
+{
+    Instruction* store = new Instruction(OpStore);
+    store->addIdOperand(lValue);
+    store->addIdOperand(rValue);
+    buildPoint->addInstruction(store);
+}
+
+// Comments in header
+Id Builder::createLoad(Id lValue)
+{
+    Instruction* load = new Instruction(getUniqueId(), getDerefTypeId(lValue), OpLoad);
+    load->addIdOperand(lValue);
+    buildPoint->addInstruction(load);
+
+    return load->getResultId();
+}
+
+// Comments in header
+Id Builder::createAccessChain(StorageClass storageClass, Id base, std::vector<Id>& offsets)
+{
+    // Figure out the final resulting type.
+    spv::Id typeId = getTypeId(base);
+    assert(isPointerType(typeId) && offsets.size() > 0);
+    typeId = getContainedTypeId(typeId);
+    for (int i = 0; i < (int)offsets.size(); ++i) {
+        if (isStructType(typeId)) {
+            assert(isConstantScalar(offsets[i]));
+            typeId = getContainedTypeId(typeId, getConstantScalar(offsets[i]));
+        } else
+            typeId = getContainedTypeId(typeId, offsets[i]);
+    }
+    typeId = makePointer(storageClass, typeId);
+
+    // Make the instruction
+    Instruction* chain = new Instruction(getUniqueId(), typeId, OpAccessChain);
+    chain->addIdOperand(base);
+    for (int i = 0; i < (int)offsets.size(); ++i)
+        chain->addIdOperand(offsets[i]);
+    buildPoint->addInstruction(chain);
+
+    return chain->getResultId();
+}
+
+Id Builder::createCompositeExtract(Id composite, Id typeId, unsigned index)
+{
+    Instruction* extract = new Instruction(getUniqueId(), typeId, OpCompositeExtract);
+    extract->addIdOperand(composite);
+    extract->addImmediateOperand(index);
+    buildPoint->addInstruction(extract);
+
+    return extract->getResultId();
+}
+
+Id Builder::createCompositeExtract(Id composite, Id typeId, std::vector<unsigned>& indexes)
+{
+    Instruction* extract = new Instruction(getUniqueId(), typeId, OpCompositeExtract);
+    extract->addIdOperand(composite);
+    for (int i = 0; i < (int)indexes.size(); ++i)
+        extract->addImmediateOperand(indexes[i]);
+    buildPoint->addInstruction(extract);
+
+    return extract->getResultId();
+}
+
+Id Builder::createCompositeInsert(Id object, Id composite, Id typeId, unsigned index)
+{
+    Instruction* insert = new Instruction(getUniqueId(), typeId, OpCompositeInsert);
+    insert->addIdOperand(object);
+    insert->addIdOperand(composite);
+    insert->addImmediateOperand(index);
+    buildPoint->addInstruction(insert);
+
+    return insert->getResultId();
+}
+
+Id Builder::createCompositeInsert(Id object, Id composite, Id typeId, std::vector<unsigned>& indexes)
+{
+    Instruction* insert = new Instruction(getUniqueId(), typeId, OpCompositeInsert);
+    insert->addIdOperand(object);
+    insert->addIdOperand(composite);
+    for (int i = 0; i < (int)indexes.size(); ++i)
+        insert->addImmediateOperand(indexes[i]);
+    buildPoint->addInstruction(insert);
+
+    return insert->getResultId();
+}
+
+Id Builder::createVectorExtractDynamic(Id vector, Id typeId, Id componentIndex)
+{
+    Instruction* extract = new Instruction(getUniqueId(), typeId, OpVectorExtractDynamic);
+    extract->addIdOperand(vector);
+    extract->addIdOperand(componentIndex);
+    buildPoint->addInstruction(extract);
+
+    return extract->getResultId();
+}
+
+Id Builder::createVectorInsertDynamic(Id vector, Id typeId, Id component, Id componentIndex)
+{
+    Instruction* insert = new Instruction(getUniqueId(), typeId, OpVectorInsertDynamic);
+    insert->addIdOperand(vector);
+    insert->addIdOperand(component);
+    insert->addIdOperand(componentIndex);
+    buildPoint->addInstruction(insert);
+
+    return insert->getResultId();
+}
+
+// An opcode that has no operands, no result id, and no type
+void Builder::createNoResultOp(Op opCode)
+{
+    Instruction* op = new Instruction(opCode);
+    buildPoint->addInstruction(op);
+}
+
+// An opcode that has one operand, no result id, and no type
+void Builder::createNoResultOp(Op opCode, Id operand)
+{
+    Instruction* op = new Instruction(opCode);
+    op->addIdOperand(operand);
+    buildPoint->addInstruction(op);
+}
+
+void Builder::createControlBarrier(unsigned executionScope)
+{
+    Instruction* op = new Instruction(OpControlBarrier);
+    op->addImmediateOperand(executionScope);
+    buildPoint->addInstruction(op);
+}
+
+void Builder::createMemoryBarrier(unsigned executionScope, unsigned memorySemantics)
+{
+    Instruction* op = new Instruction(OpMemoryBarrier);
+    op->addImmediateOperand(executionScope);
+    op->addImmediateOperand(memorySemantics);
+    buildPoint->addInstruction(op);
+}
+
+// An opcode that has one operands, a result id, and a type
+Id Builder::createUnaryOp(Op opCode, Id typeId, Id operand)
+{
+    Instruction* op = new Instruction(getUniqueId(), typeId, opCode);
+    op->addIdOperand(operand);
+    buildPoint->addInstruction(op);
+
+    return op->getResultId();
+}
+
+Id Builder::createBinOp(Op opCode, Id typeId, Id left, Id right)
+{
+    Instruction* op = new Instruction(getUniqueId(), typeId, opCode);
+    op->addIdOperand(left);
+    op->addIdOperand(right);
+    buildPoint->addInstruction(op);
+
+    return op->getResultId();
+}
+
+Id Builder::createTriOp(Op opCode, Id typeId, Id op1, Id op2, Id op3)
+{
+    Instruction* op = new Instruction(getUniqueId(), typeId, opCode);
+    op->addIdOperand(op1);
+    op->addIdOperand(op2);
+    op->addIdOperand(op3);
+    buildPoint->addInstruction(op);
+
+    return op->getResultId();
+}
+
+Id Builder::createTernaryOp(Op opCode, Id typeId, Id op1, Id op2, Id op3)
+{
+    Instruction* op = new Instruction(getUniqueId(), typeId, opCode);
+    op->addIdOperand(op1);
+    op->addIdOperand(op2);
+    op->addIdOperand(op3);
+    buildPoint->addInstruction(op);
+
+    return op->getResultId();
+}
+
+Id Builder::createFunctionCall(spv::Function* function, std::vector<spv::Id>& args)
+{
+    Instruction* op = new Instruction(getUniqueId(), function->getReturnType(), OpFunctionCall);
+    op->addIdOperand(function->getId());
+    for (int a = 0; a < (int)args.size(); ++a)
+        op->addIdOperand(args[a]);
+    buildPoint->addInstruction(op);
+
+    return op->getResultId();
+}
+
+// Comments in header
+Id Builder::createRvalueSwizzle(Id typeId, Id source, std::vector<unsigned>& channels)
+{
+    if (channels.size() == 1)
+        return createCompositeExtract(source, typeId, channels.front());
+
+    Instruction* swizzle = new Instruction(getUniqueId(), typeId, OpVectorShuffle);
+    assert(isVector(source));
+    swizzle->addIdOperand(source);
+    swizzle->addIdOperand(source);
+    for (int i = 0; i < (int)channels.size(); ++i)
+        swizzle->addImmediateOperand(channels[i]);
+    buildPoint->addInstruction(swizzle);
+
+    return swizzle->getResultId();
+}
+
+// Comments in header
+Id Builder::createLvalueSwizzle(Id typeId, Id target, Id source, std::vector<unsigned>& channels)
+{
+    assert(getNumComponents(source) == channels.size());
+    if (channels.size() == 1 && getNumComponents(source) == 1)
+        return createCompositeInsert(source, target, typeId, channels.front());
+
+    Instruction* swizzle = new Instruction(getUniqueId(), typeId, OpVectorShuffle);
+    assert(isVector(source));
+    assert(isVector(target));
+    swizzle->addIdOperand(target);
+    swizzle->addIdOperand(source);
+
+    // Set up an identity shuffle from the base value to the result value
+    unsigned int components[4];
+    int numTargetComponents = getNumComponents(target);
+    for (int i = 0; i < numTargetComponents; ++i)
+        components[i] = i;
+
+    // Punch in the l-value swizzle
+    for (int i = 0; i < (int)channels.size(); ++i)
+        components[channels[i]] = numTargetComponents + i;
+
+    // finish the instruction with these components selectors
+    for (int i = 0; i < numTargetComponents; ++i)
+        swizzle->addImmediateOperand(components[i]);
+    buildPoint->addInstruction(swizzle);
+
+    return swizzle->getResultId();
+}
+
+// Comments in header
+void Builder::promoteScalar(Decoration precision, Id& left, Id& right)
+{
+    int direction = getNumComponents(right) - getNumComponents(left);
+
+    if (direction > 0)
+        left = smearScalar(precision, left, getTypeId(right));
+    else if (direction < 0)
+        right = smearScalar(precision, right, getTypeId(left));
+
+    return;
+}
+
+// Comments in header
+Id Builder::smearScalar(Decoration /*precision*/, Id scalar, Id vectorType)
+{
+    assert(getNumComponents(scalar) == 1);
+
+    int numComponents = getNumTypeComponents(vectorType);
+    if (numComponents == 1)
+        return scalar;
+
+    Instruction* smear = new Instruction(getUniqueId(), vectorType, OpCompositeConstruct);
+    for (int c = 0; c < numComponents; ++c)
+        smear->addIdOperand(scalar);
+    buildPoint->addInstruction(smear);
+
+    return smear->getResultId();
+}
+
+// Comments in header
+Id Builder::createBuiltinCall(Decoration /*precision*/, Id resultType, Id builtins, int entryPoint, std::vector<Id>& args)
+{
+    Instruction* inst = new Instruction(getUniqueId(), resultType, OpExtInst);
+    inst->addIdOperand(builtins);
+    inst->addImmediateOperand(entryPoint);
+    for (int arg = 0; arg < (int)args.size(); ++arg)
+        inst->addIdOperand(args[arg]);
+
+    buildPoint->addInstruction(inst);
+    return inst->getResultId();
+}
+
+// Accept all parameters needed to create a texture instruction.
+// Create the correct instruction based on the inputs, and make the call.
+Id Builder::createTextureCall(Decoration precision, Id resultType, bool proj, const TextureParameters& parameters)
+{
+    static const int maxTextureArgs = 5;
+    Id texArgs[maxTextureArgs] = {};
+
+    //
+    // Set up the arguments
+    //
+
+    int numArgs = 0;
+    texArgs[numArgs++] = parameters.sampler;
+    texArgs[numArgs++] = parameters.coords;
+
+    if (parameters.gradX) {
+        texArgs[numArgs++] = parameters.gradX;
+        texArgs[numArgs++] = parameters.gradY;
+    }
+    if (parameters.lod)
+        texArgs[numArgs++] = parameters.lod;
+    if (parameters.offset)
+        texArgs[numArgs++] = parameters.offset;
+    if (parameters.bias)
+        texArgs[numArgs++] = parameters.bias;
+    if (parameters.Dref)
+        texArgs[numArgs++] = parameters.Dref;
+
+    //
+    // Set up the instruction
+    //
+
+    Op opCode;
+    if (proj && parameters.gradX && parameters.offset)
+        opCode = OpTextureSampleProjGradOffset;
+    else if (proj && parameters.lod && parameters.offset)
+        opCode = OpTextureSampleProjLodOffset;
+    else if (parameters.gradX && parameters.offset)
+        opCode = OpTextureSampleGradOffset;
+    else if (proj && parameters.offset)
+        opCode = OpTextureSampleProjOffset;
+    else if (parameters.lod && parameters.offset)
+        opCode = OpTextureSampleLodOffset;
+    else if (proj && parameters.gradX)
+        opCode = OpTextureSampleProjGrad;
+    else if (proj && parameters.lod)
+        opCode = OpTextureSampleProjLod;
+    else if (parameters.offset)
+        opCode = OpTextureSampleOffset;
+    else if (parameters.gradX)
+        opCode = OpTextureSampleGrad;
+    else if (proj)
+        opCode = OpTextureSampleProj;
+    else if (parameters.lod)
+        opCode = OpTextureSampleLod;
+    else if (parameters.Dref)
+        opCode = OpTextureSampleDref;
+    else
+        opCode = OpTextureSample;
+
+    Instruction* textureInst = new Instruction(getUniqueId(), resultType, opCode);
+    for (int op = 0; op < numArgs; ++op)
+        textureInst->addIdOperand(texArgs[op]);
+    setPrecision(textureInst->getResultId(), precision);
+    buildPoint->addInstruction(textureInst);
+
+    return textureInst->getResultId();
+}
+
+// Comments in header
+Id Builder::createTextureQueryCall(Op opCode, const TextureParameters& parameters)
+{
+    // Figure out the result type
+    Id resultType;
+    switch (opCode) {
+    case OpTextureQuerySize:
+    case OpTextureQuerySizeLod:
+    {
+        int numComponents;
+        switch (getDimensionality(parameters.sampler)) {
+        case Dim1D:
+        case DimBuffer:
+            numComponents = 1;
+            break;
+        case Dim2D:
+        case DimCube:
+        case DimRect:
+            numComponents = 2;
+            break;
+        case Dim3D:
+            numComponents = 3;
+            break;
+        default:
+            MissingFunctionality("texture query dimensionality");
+            break;
+        }
+        if (isArrayedSampler(parameters.sampler))
+            ++numComponents;
+        if (numComponents == 1)
+            resultType = makeIntType(32);
+        else
+            resultType = makeVectorType(makeIntType(32), numComponents);
+
+        break;
+    }
+    case OpTextureQueryLod:
+        resultType = makeVectorType(makeFloatType(32), 2);
+        break;
+    case OpTextureQueryLevels:
+    case OpTextureQuerySamples:
+        resultType = makeIntType(32);
+        break;
+    default:
+        MissingFunctionality("Texture query op code");
+    }
+
+    Instruction* query = new Instruction(getUniqueId(), resultType, opCode);
+    query->addIdOperand(parameters.sampler);
+    if (parameters.coords)
+        query->addIdOperand(parameters.coords);
+    if (parameters.lod)
+        query->addIdOperand(parameters.lod);
+    buildPoint->addInstruction(query);
+
+    return query->getResultId();
+}
+
+// Comments in header
+//Id Builder::createSamplePositionCall(Decoration precision, Id returnType, Id sampleIdx)
+//{
+//    // Return type is only flexible type
+//    Function* opCode = (fSamplePosition, returnType);
+//
+//    Instruction* instr = (opCode, sampleIdx);
+//    setPrecision(instr, precision);
+//
+//    return instr;
+//}
+
+// Comments in header
+//Id Builder::createBitFieldExtractCall(Decoration precision, Id id, Id offset, Id bits, bool isSigned)
+//{
+//    Op opCode = isSigned ? sBitFieldExtract
+//                                               : uBitFieldExtract;
+//
+//    if (isScalar(offset) == false || isScalar(bits) == false)
+//        MissingFunctionality("bitFieldExtract operand types");
+//
+//    // Dest and value are matching flexible types
+//    Function* opCode = (opCode, id->getType(), id->getType());
+//
+//    assert(opCode);
+//
+//    Instruction* instr = (opCode, id, offset, bits);
+//    setPrecision(instr, precision);
+//
+//    return instr;
+//}
+
+// Comments in header
+//Id Builder::createBitFieldInsertCall(Decoration precision, Id base, Id insert, Id offset, Id bits)
+//{
+//    Op opCode = bitFieldInsert;
+//
+//    if (isScalar(offset) == false || isScalar(bits) == false)
+//        MissingFunctionality("bitFieldInsert operand types");
+//
+//    // Dest, base, and insert are matching flexible types
+//    Function* opCode = (opCode, base->getType(), base->getType(), base->getType());
+//
+//    assert(opCode);
+//
+//    Instruction* instr = (opCode, base, insert, offset, bits);
+//    setPrecision(instr, precision);
+//
+//    return instr;
+//}
+
+// Comments in header
+Id Builder::createCompare(Decoration precision, Id value1, Id value2, bool equal)
+{
+    Id boolType = makeBoolType();
+    Id valueType = getTypeId(value1);
+
+    assert(valueType == getTypeId(value2));
+    assert(! isScalar(value1));
+
+    // Vectors
+
+    if (isVectorType(valueType)) {
+        Id boolVectorType = makeVectorType(boolType, getNumTypeComponents(valueType));
+        Id boolVector;
+        Op op;
+        if (getMostBasicTypeClass(valueType) == OpTypeFloat)
+            op = equal ? OpFOrdEqual : OpFOrdNotEqual;
+        else
+            op = equal ? OpIEqual : OpINotEqual;
+
+        boolVector = createBinOp(op, boolVectorType, value1, value2);
+        setPrecision(boolVector, precision);
+
+        // Reduce vector compares with any() and all().
+
+        op = equal ? OpAll : OpAny;
+
+        return createUnaryOp(op, boolType, boolVector);
+    }
+
+    spv::MissingFunctionality("Composite comparison of non-vectors");
+
+    return NoResult;
+
+    // Recursively handle aggregates, which include matrices, arrays, and structures
+    // and accumulate the results.
+
+    // Matrices
+
+    // Arrays
+
+    //int numElements;
+    //const llvm::ArrayType* arrayType = llvm::dyn_cast<llvm::ArrayType>(value1->getType());
+    //if (arrayType)
+    //    numElements = (int)arrayType->getNumElements();
+    //else {
+    //    // better be structure
+    //    const llvm::StructType* structType = llvm::dyn_cast<llvm::StructType>(value1->getType());
+    //    assert(structType);
+    //    numElements = structType->getNumElements();
+    //}
+
+    //assert(numElements > 0);
+
+    //for (int element = 0; element < numElements; ++element) {
+    //    // Get intermediate comparison values
+    //    llvm::Value* element1 = builder.CreateExtractValue(value1, element, "element1");
+    //    setInstructionPrecision(element1, precision);
+    //    llvm::Value* element2 = builder.CreateExtractValue(value2, element, "element2");
+    //    setInstructionPrecision(element2, precision);
+
+    //    llvm::Value* subResult = createCompare(precision, element1, element2, equal, "comp");
+
+    //    // Accumulate intermediate comparison
+    //    if (element == 0)
+    //        result = subResult;
+    //    else {
+    //        if (equal)
+    //            result = builder.CreateAnd(result, subResult);
+    //        else
+    //            result = builder.CreateOr(result, subResult);
+    //        setInstructionPrecision(result, precision);
+    //    }
+    //}
+
+    //return result;
+}
+
+// Comments in header
+//Id Builder::createOperation(Decoration precision, Op opCode, Id operand)
+//{
+//    Op* opCode = 0;
+//
+//    // Handle special return types here.  Things that don't have same result type as parameter
+//    switch (opCode) {
+//    case fIsNan:
+//    case fIsInf:
+//        break;
+//    case fFloatBitsToInt:
+//        break;
+//    case fIntBitsTofloat:
+//        break;
+//    case fPackSnorm2x16:
+//    case fPackUnorm2x16:
+//    case fPackHalf2x16:
+//        break;
+//    case fUnpackUnorm2x16:
+//    case fUnpackSnorm2x16:
+//    case fUnpackHalf2x16:
+//        break;
+//
+//    case fFrexp:
+//    case fLdexp:
+//    case fPackUnorm4x8:
+//    case fPackSnorm4x8:
+//    case fUnpackUnorm4x8:
+//    case fUnpackSnorm4x8:
+//    case fPackDouble2x32:
+//    case fUnpackDouble2x32:
+//        break;
+//    case fLength:
+//       // scalar result type
+//       break;
+//    case any:
+//    case all:
+//        // fixed result type
+//        break;
+//    case fModF:
+//        // modf() will return a struct that the caller must decode
+//        break;
+//    default:
+//        // Unary operations that have operand and dest with same flexible type
+//        break;
+//    }
+//
+//    assert(opCode);
+//
+//    Instruction* instr = (opCode, operand);
+//    setPrecision(instr, precision);
+//
+//    return instr;
+//}
+//
+//// Comments in header
+//Id Builder::createOperation(Decoration precision, Op opCode, Id operand0, Id operand1)
+//{
+//    Function* opCode = 0;
+//
+//    // Handle special return types here.  Things that don't have same result type as parameter
+//    switch (opCode) {
+//    case fDistance:
+//    case fDot2:
+//    case fDot3:
+//    case fDot4:
+//        // scalar result type
+//        break;
+//    case fStep:
+//        // first argument can be scalar, return and second argument match
+//        break;
+//    case fSmoothStep:
+//        // first argument can be scalar, return and second argument match
+//        break;
+//    default:
+//        // Binary operations that have operand and dest with same flexible type
+//        break;
+//    }
+//
+//    assert(opCode);
+//
+//    Instruction* instr = (opCode, operand0, operand1);
+//    setPrecision(instr, precision);
+//
+//    return instr;
+//}
+//
+//Id Builder::createOperation(Decoration precision, Op opCode, Id operand0, Id operand1, Id operand2)
+//{
+//    Function* opCode;
+//
+//    // Handle special return types here.  Things that don't have same result type as parameter
+//    switch (opCode) {
+//    case fSmoothStep:
+//        // first argument can be scalar, return and second argument match
+//        break;
+//    default:
+//        // Use operand0 type as result type
+//        break;
+//    }
+//
+//    assert(opCode);
+//
+//    Instruction* instr = (opCode, operand0, operand1, operand2);
+//    setPrecision(instr, precision);
+//
+//    return instr;
+//}
+
+// OpCompositeConstruct
+Id Builder::createCompositeConstruct(Id typeId, std::vector<Id>& constituents)
+{
+    assert(isAggregateType(typeId) || getNumTypeComponents(typeId) > 1 && getNumTypeComponents(typeId) == constituents.size());
+
+    Instruction* op = new Instruction(getUniqueId(), typeId, OpCompositeConstruct);
+    for (int c = 0; c < (int)constituents.size(); ++c)
+        op->addIdOperand(constituents[c]);
+    buildPoint->addInstruction(op);
+
+    return op->getResultId();
+}
+
+// Vector or scalar constructor
+Id Builder::createConstructor(Decoration precision, const std::vector<Id>& sources, Id resultTypeId)
+{
+    Id result = 0;
+    unsigned int numTargetComponents = getNumTypeComponents(resultTypeId);
+    unsigned int targetComponent = 0;
+
+    // Special case: when calling a vector constructor with a single scalar
+    // argument, smear the scalar
+    if (sources.size() == 1 && isScalar(sources[0]) && numTargetComponents > 1)
+        return smearScalar(precision, sources[0], resultTypeId);
+
+    Id scalarTypeId = getScalarTypeId(resultTypeId);
+    std::vector<Id> constituents;  // accumulate the arguments for OpCompositeConstruct
+    for (unsigned int i = 0; i < sources.size(); ++i) {
+        if (isAggregate(sources[i]))
+            MissingFunctionality("aggregate in vector constructor");
+
+        unsigned int sourceSize = getNumComponents(sources[i]);
+
+        unsigned int sourcesToUse = sourceSize;
+        if (sourcesToUse + targetComponent > numTargetComponents)
+            sourcesToUse = numTargetComponents - targetComponent;
+
+        for (unsigned int s = 0; s < sourcesToUse; ++s) {
+            Id arg = sources[i];
+            if (sourceSize > 1) {
+                std::vector<unsigned> swiz;
+                swiz.push_back(s);
+                arg = createRvalueSwizzle(scalarTypeId, arg, swiz);
+            }
+
+            if (numTargetComponents > 1)
+                constituents.push_back(arg);
+            else
+                result = arg;
+            ++targetComponent;
+        }
+
+        if (targetComponent >= numTargetComponents)
+            break;
+    }
+
+    if (constituents.size() > 0)
+        result = createCompositeConstruct(resultTypeId, constituents);
+
+    setPrecision(result, precision);
+
+    return result;
+}
+
+// Comments in header
+Id Builder::createMatrixConstructor(Decoration precision, const std::vector<Id>& sources, Id resultTypeId)
+{
+    Id componentTypeId = getScalarTypeId(resultTypeId);
+    int numCols = getTypeNumColumns(resultTypeId);
+    int numRows = getTypeNumRows(resultTypeId);
+
+    // Will use a two step process
+    // 1. make a compile-time 2D array of values
+    // 2. construct a matrix from that array
+
+    // Step 1.
+
+    // initialize the array to the identity matrix
+    Id ids[maxMatrixSize][maxMatrixSize];
+    Id  one = makeFloatConstant(1.0);
+    Id zero = makeFloatConstant(0.0);
+    for (int col = 0; col < 4; ++col) {
+        for (int row = 0; row < 4; ++row) {
+            if (col == row)
+                ids[col][row] = one;
+            else
+                ids[col][row] = zero;
+        }
+    }
+
+    // modify components as dictated by the arguments
+    if (sources.size() == 1 && isScalar(sources[0])) {
+        // a single scalar; resets the diagonals
+        for (int col = 0; col < 4; ++col)
+            ids[col][col] = sources[0];
+    } else if (isMatrix(sources[0])) {
+        // constructing from another matrix; copy over the parts that exist in both the argument and constructee
+        Id matrix = sources[0];
+        int minCols = std::min(numCols, getNumColumns(matrix));
+        int minRows = std::min(numRows, getNumRows(matrix));
+        for (int col = 0; col < minCols; ++col) {
+            std::vector<unsigned> indexes;
+            indexes.push_back(col);
+            for (int row = 0; row < minRows; ++row) {
+                indexes.push_back(row);
+                ids[col][row] = createCompositeExtract(matrix, componentTypeId, indexes);
+                indexes.pop_back();
+                setPrecision(ids[col][row], precision);
+            }
+        }
+    } else {
+        // fill in the matrix in column-major order with whatever argument components are available
+        int row = 0;
+        int col = 0;
+
+        for (int arg = 0; arg < (int)sources.size(); ++arg) {
+            Id argComp = sources[arg];
+            for (int comp = 0; comp < getNumComponents(sources[arg]); ++comp) {
+                if (getNumComponents(sources[arg]) > 1) {
+                    argComp = createCompositeExtract(sources[arg], componentTypeId, comp);
+                    setPrecision(argComp, precision);
+                }
+                ids[col][row++] = argComp;
+                if (row == numRows) {
+                    row = 0;
+                    col++;
+                }
+            }
+        }
+    }
+
+
+    // Step 2:  Construct a matrix from that array.
+    // First make the column vectors, then make the matrix.
+
+    // make the column vectors
+    Id columnTypeId = getContainedTypeId(resultTypeId);
+    std::vector<Id> matrixColumns;
+    for (int col = 0; col < numCols; ++col) {
+        std::vector<Id> vectorComponents;
+        for (int row = 0; row < numRows; ++row)
+            vectorComponents.push_back(ids[col][row]);
+        matrixColumns.push_back(createCompositeConstruct(columnTypeId, vectorComponents));
+    }
+
+    // make the matrix
+    return createCompositeConstruct(resultTypeId, matrixColumns);
+}
+
+// Comments in header
+Builder::If::If(Id cond, Builder& gb) :
+    builder(gb),
+    condition(cond),
+    elseBlock(0)
+{
+    function = &builder.getBuildPoint()->getParent();
+
+    // make the blocks, but only put the then-block into the function,
+    // the else-block and merge-block will be added later, in order, after
+    // earlier code is emitted
+    thenBlock = new Block(builder.getUniqueId(), *function);
+    mergeBlock = new Block(builder.getUniqueId(), *function);
+
+    // Save the current block, so that we can add in the flow control split when
+    // makeEndIf is called.
+    headerBlock = builder.getBuildPoint();
+
+    function->addBlock(thenBlock);
+    builder.setBuildPoint(thenBlock);
+}
+
+// Comments in header
+void Builder::If::makeBeginElse()
+{
+    // Close out the "then" by having it jump to the mergeBlock
+    builder.createBranch(mergeBlock);
+
+    // Make the first else block and add it to the function
+    elseBlock = new Block(builder.getUniqueId(), *function);
+    function->addBlock(elseBlock);
+
+    // Start building the else block
+    builder.setBuildPoint(elseBlock);
+}
+
+// Comments in header
+void Builder::If::makeEndIf()
+{
+    // jump to the merge block
+    builder.createBranch(mergeBlock);
+
+    // Go back to the headerBlock and make the flow control split
+    builder.setBuildPoint(headerBlock);
+    builder.createMerge(OpSelectionMerge, mergeBlock, SelectionControlMaskNone);
+    if (elseBlock)
+        builder.createConditionalBranch(condition, thenBlock, elseBlock);
+    else
+        builder.createConditionalBranch(condition, thenBlock, mergeBlock);
+
+    // add the merge block to the function
+    function->addBlock(mergeBlock);
+    builder.setBuildPoint(mergeBlock);
+}
+
+// Comments in header
+void Builder::makeSwitch(Id selector, int numSegments, std::vector<int>& caseValues, std::vector<int>& valueIndexToSegment, int defaultSegment,
+                         std::vector<Block*>& segmentBlocks)
+{
+    Function& function = buildPoint->getParent();
+
+    // make all the blocks
+    for (int s = 0; s < numSegments; ++s)
+        segmentBlocks.push_back(new Block(getUniqueId(), function));
+
+    Block* mergeBlock = new Block(getUniqueId(), function);
+
+    // make and insert the switch's selection-merge instruction
+    createMerge(OpSelectionMerge, mergeBlock, SelectionControlMaskNone);
+
+    // make the switch instruction
+    Instruction* switchInst = new Instruction(NoResult, NoType, OpSwitch);
+    switchInst->addIdOperand(selector);
+    switchInst->addIdOperand(defaultSegment >= 0 ? segmentBlocks[defaultSegment]->getId() : mergeBlock->getId());
+    for (int i = 0; i < (int)caseValues.size(); ++i) {
+        switchInst->addImmediateOperand(caseValues[i]);
+        switchInst->addIdOperand(segmentBlocks[valueIndexToSegment[i]]->getId());
+    }
+    buildPoint->addInstruction(switchInst);
+
+    // push the merge block
+    switchMerges.push(mergeBlock);
+}
+
+// Comments in header
+void Builder::addSwitchBreak()
+{
+    // branch to the top of the merge block stack
+    createBranch(switchMerges.top());
+    createAndSetNoPredecessorBlock("post-switch-break");
+}
+
+// Comments in header
+void Builder::nextSwitchSegment(std::vector<Block*>& segmentBlock, int nextSegment)
+{
+    int lastSegment = nextSegment - 1;
+    if (lastSegment >= 0) {
+        // Close out previous segment by jumping, if necessary, to next segment
+        if (! buildPoint->isTerminated())
+            createBranch(segmentBlock[nextSegment]);
+    }
+    Block* block = segmentBlock[nextSegment];
+    block->getParent().addBlock(block);
+    setBuildPoint(block);
+}
+
+// Comments in header
+void Builder::endSwitch(std::vector<Block*>& /*segmentBlock*/)
+{
+    // Close out previous segment by jumping, if necessary, to next segment
+    if (! buildPoint->isTerminated())
+        addSwitchBreak();
+
+    switchMerges.top()->getParent().addBlock(switchMerges.top());
+    setBuildPoint(switchMerges.top());
+
+    switchMerges.pop();
+}
+
+// Comments in header
+void Builder::makeNewLoop()
+{
+    Loop loop = { };
+
+    loop.function = &getBuildPoint()->getParent();
+    loop.header = new Block(getUniqueId(), *loop.function);
+    loop.merge  = new Block(getUniqueId(), *loop.function);
+    loop.test   = NULL;
+
+    loops.push(loop);
+
+    // Branch into the loop
+    createBranch(loop.header);
+
+    // Set ourselves inside the loop
+    loop.function->addBlock(loop.header);
+    setBuildPoint(loop.header);
+}
+
+void Builder::createLoopTestBranch(Id condition)
+{
+    Loop& loop = loops.top();
+
+    // If loop.test exists, then we've already generated the LoopMerge
+    // for this loop.
+    if (!loop.test)
+      createMerge(OpLoopMerge, loop.merge, LoopControlMaskNone);
+
+    // Branching to the "body" block will keep control inside
+    // the loop.
+    Block* body = new Block(getUniqueId(), *loop.function);
+    createConditionalBranch(condition, body, loop.merge);
+    loop.function->addBlock(body);
+    setBuildPoint(body);
+}
+
+void Builder::endLoopHeaderWithoutTest()
+{
+    Loop& loop = loops.top();
+
+    createMerge(OpLoopMerge, loop.merge, LoopControlMaskNone);
+    Block* body = new Block(getUniqueId(), *loop.function);
+    createBranch(body);
+    loop.function->addBlock(body);
+    setBuildPoint(body);
+
+    assert(!loop.test);
+    loop.test = new Block(getUniqueId(), *loop.function);
+}
+
+void Builder::createBranchToLoopTest()
+{
+    Loop& loop = loops.top();
+    Block* testBlock = loop.test;
+    assert(testBlock);
+    createBranch(testBlock);
+    loop.function->addBlock(testBlock);
+    setBuildPoint(testBlock);
+}
+
+void Builder::createLoopContinue()
+{
+    Loop& loop = loops.top();
+    if (loop.test)
+      createBranch(loop.test);
+    else
+      createBranch(loop.header);
+    // Set up a block for dead code.
+    createAndSetNoPredecessorBlock("post-loop-continue");
+}
+
+// Add an exit (e.g. "break") for the innermost loop that you're in
+void Builder::createLoopExit()
+{
+    createBranch(loops.top().merge);
+    // Set up a block for dead code.
+    createAndSetNoPredecessorBlock("post-loop-break");
+}
+
+// Close the innermost loop
+void Builder::closeLoop()
+{
+    Loop& loop = loops.top();
+
+    // Branch back to the top
+    createBranch(loop.header);
+
+    // Add the merge block and set the build point to it
+    loop.function->addBlock(loop.merge);
+    setBuildPoint(loop.merge);
+
+    loops.pop();
+}
+
+void Builder::clearAccessChain()
+{
+    accessChain.base = 0;
+    accessChain.indexChain.clear();
+    accessChain.instr = 0;
+    accessChain.swizzle.clear();
+    accessChain.component = 0;
+    accessChain.resultType = NoType;
+    accessChain.isRValue = false;
+}
+
+// Comments in header
+void Builder::accessChainPushSwizzle(std::vector<unsigned>& swizzle)
+{
+    // if needed, propagate the swizzle for the current access chain
+    if (accessChain.swizzle.size()) {
+        std::vector<unsigned> oldSwizzle = accessChain.swizzle;
+        accessChain.swizzle.resize(0);
+        for (unsigned int i = 0; i < swizzle.size(); ++i) {
+            accessChain.swizzle.push_back(oldSwizzle[swizzle[i]]);
+        }
+    } else
+        accessChain.swizzle = swizzle;
+
+    // determine if we need to track this swizzle anymore
+    simplifyAccessChainSwizzle();
+}
+
+// Comments in header
+void Builder::accessChainStore(Id rvalue)
+{
+    assert(accessChain.isRValue == false);
+
+    Id base = collapseAccessChain();
+
+    if (accessChain.swizzle.size() && accessChain.component)
+        MissingFunctionality("simultaneous l-value swizzle and dynamic component selection");
+
+    // If swizzle exists, it is out-of-order or not full, we must load the target vector,
+    // extract and insert elements to perform writeMask and/or swizzle.
+    Id source = NoResult;
+    if (accessChain.swizzle.size()) {
+        Id tempBaseId = createLoad(base);
+        source = createLvalueSwizzle(getTypeId(tempBaseId), tempBaseId, rvalue, accessChain.swizzle);
+    }
+
+    // dynamic component selection
+    if (accessChain.component) {
+        Id tempBaseId = (source == NoResult) ? createLoad(base) : source;
+        source = createVectorInsertDynamic(tempBaseId, getTypeId(tempBaseId), rvalue, accessChain.component);
+    }
+
+    if (source == NoResult)
+        source = rvalue;
+
+    createStore(source, base);
+}
+
+// Comments in header
+Id Builder::accessChainLoad(Decoration /*precision*/)
+{
+    Id id;
+
+    if (accessChain.isRValue) {
+        if (accessChain.indexChain.size() > 0) {
+            mergeAccessChainSwizzle();  // TODO: optimization: look at applying this optimization more widely
+            // if all the accesses are constants, we can use OpCompositeExtract
+            std::vector<unsigned> indexes;
+            bool constant = true;
+            for (int i = 0; i < (int)accessChain.indexChain.size(); ++i) {
+                if (isConstantScalar(accessChain.indexChain[i]))
+                    indexes.push_back(getConstantScalar(accessChain.indexChain[i]));
+                else {
+                    constant = false;
+                    break;
+                }
+            }
+
+            if (constant)
+                id = createCompositeExtract(accessChain.base, accessChain.resultType, indexes);
+            else {
+                // make a new function variable for this r-value
+                Id lValue = createVariable(StorageClassFunction, getTypeId(accessChain.base), "indexable");
+
+                // store into it
+                createStore(accessChain.base, lValue);
+
+                // move base to the new variable
+                accessChain.base = lValue;
+                accessChain.isRValue = false;
+
+                // load through the access chain
+                id = createLoad(collapseAccessChain());
+            }
+        } else
+            id = accessChain.base;
+    } else {
+        // load through the access chain
+        id = createLoad(collapseAccessChain());
+    }
+
+    // Done, unless there are swizzles to do
+    if (accessChain.swizzle.size() == 0 && accessChain.component == 0)
+        return id;
+
+    Id componentType = getScalarTypeId(accessChain.resultType);
+
+    // Do remaining swizzling
+    // First, static swizzling
+    if (accessChain.swizzle.size()) {
+        // static swizzle
+        Id resultType = componentType;
+        if (accessChain.swizzle.size() > 1)
+            resultType = makeVectorType(componentType, accessChain.swizzle.size());
+        id = createRvalueSwizzle(resultType, id, accessChain.swizzle);
+    }
+
+    // dynamic single-component selection
+    if (accessChain.component)
+        id = createVectorExtractDynamic(id, componentType, accessChain.component);
+
+    return id;
+}
+
+Id Builder::accessChainGetLValue()
+{
+    assert(accessChain.isRValue == false);
+
+    Id lvalue = collapseAccessChain();
+
+    // If swizzle exists, it is out-of-order or not full, we must load the target vector,
+    // extract and insert elements to perform writeMask and/or swizzle.  This does not
+    // go with getting a direct l-value pointer.
+    assert(accessChain.swizzle.size() == 0);
+    assert(accessChain.component == spv::NoResult);
+
+    return lvalue;
+}
+
+void Builder::dump(std::vector<unsigned int>& out) const
+{
+    // Header, before first instructions:
+    out.push_back(MagicNumber);
+    out.push_back(Version);
+    out.push_back(builderNumber);
+    out.push_back(uniqueId + 1);
+    out.push_back(0);
+
+    // First instructions, some created on the spot here:
+    if (source != SourceLanguageUnknown) {
+        Instruction sourceInst(0, 0, OpSource);
+        sourceInst.addImmediateOperand(source);
+        sourceInst.addImmediateOperand(sourceVersion);
+        sourceInst.dump(out);
+    }
+    for (int e = 0; e < (int)extensions.size(); ++e) {
+        Instruction extInst(0, 0, OpSourceExtension);
+        extInst.addStringOperand(extensions[e]);
+        extInst.dump(out);
+    }
+    // TBD: OpExtension ...
+    dumpInstructions(out, imports);
+    Instruction memInst(0, 0, OpMemoryModel);
+    memInst.addImmediateOperand(addressModel);
+    memInst.addImmediateOperand(memoryModel);
+    memInst.dump(out);
+
+    // Instructions saved up while building:
+    dumpInstructions(out, entryPoints);
+    dumpInstructions(out, executionModes);
+    dumpInstructions(out, names);
+    dumpInstructions(out, lines);
+    dumpInstructions(out, decorations);
+    dumpInstructions(out, constantsTypesGlobals);
+    dumpInstructions(out, externals);
+
+    // The functions
+    module.dump(out);
+}
+
+//
+// Protected methods.
+//
+
+Id Builder::collapseAccessChain()
+{
+    // TODO: bring in an individual component swizzle here, so that a pointer 
+    // all the way to the component level can be created.
+    assert(accessChain.isRValue == false);
+
+    if (accessChain.indexChain.size() > 0) {
+        if (accessChain.instr == 0) {
+            StorageClass storageClass = (StorageClass)module.getStorageClass(getTypeId(accessChain.base));
+            accessChain.instr = createAccessChain(storageClass, accessChain.base, accessChain.indexChain);
+        }
+
+        return accessChain.instr;
+    } else
+        return accessChain.base;
+}
+
+// clear out swizzle if it is redundant
+void Builder::simplifyAccessChainSwizzle()
+{
+    // If the swizzle has fewer components than the vector, it is subsetting, and must stay
+    // to preserve that fact.
+    if (getNumTypeComponents(accessChain.resultType) > (int)accessChain.swizzle.size())
+        return;
+
+    // if components are out of order, it is a swizzle
+    for (unsigned int i = 0; i < accessChain.swizzle.size(); ++i) {
+        if (i != accessChain.swizzle[i])
+            return;
+    }
+
+    // otherwise, there is no need to track this swizzle
+    accessChain.swizzle.clear();
+}
+
+// clear out swizzle if it can become part of the indexes
+void Builder::mergeAccessChainSwizzle()
+{
+    // is there even a chance of doing something?  Need a single-component swizzle
+    if ((accessChain.swizzle.size() > 1) ||
+        (accessChain.swizzle.size() == 0 && accessChain.component == 0))
+        return;
+
+    // TODO: optimization: remove this, but for now confine this to non-dynamic accesses
+    // (the above test is correct when this is removed.)
+    if (accessChain.component)
+        return;
+
+    // move the swizzle over to the indexes
+    if (accessChain.swizzle.size() == 1)
+        accessChain.indexChain.push_back(makeUintConstant(accessChain.swizzle.front()));
+    else
+        accessChain.indexChain.push_back(accessChain.component);
+    accessChain.resultType = getScalarTypeId(accessChain.resultType);
+
+    // now there is no need to track this swizzle
+    accessChain.component = NoResult;
+    accessChain.swizzle.clear();
+}
+
+// Utility method for creating a new block and setting the insert point to
+// be in it. This is useful for flow-control operations that need a "dummy"
+// block proceeding them (e.g. instructions after a discard, etc).
+void Builder::createAndSetNoPredecessorBlock(const char* /*name*/)
+{
+    Block* block = new Block(getUniqueId(), buildPoint->getParent());
+    block->setUnreachable();
+    buildPoint->getParent().addBlock(block);
+    setBuildPoint(block);
+
+    //if (name)
+    //    addName(block->getId(), name);
+}
+
+// Comments in header
+void Builder::createBranch(Block* block)
+{
+    Instruction* branch = new Instruction(OpBranch);
+    branch->addIdOperand(block->getId());
+    buildPoint->addInstruction(branch);
+    block->addPredecessor(buildPoint);
+}
+
+void Builder::createMerge(Op mergeCode, Block* mergeBlock, unsigned int control)
+{
+    Instruction* merge = new Instruction(mergeCode);
+    merge->addIdOperand(mergeBlock->getId());
+    merge->addImmediateOperand(control);
+    buildPoint->addInstruction(merge);
+}
+
+void Builder::createConditionalBranch(Id condition, Block* thenBlock, Block* elseBlock)
+{
+    Instruction* branch = new Instruction(OpBranchConditional);
+    branch->addIdOperand(condition);
+    branch->addIdOperand(thenBlock->getId());
+    branch->addIdOperand(elseBlock->getId());
+    buildPoint->addInstruction(branch);
+    thenBlock->addPredecessor(buildPoint);
+    elseBlock->addPredecessor(buildPoint);
+}
+
+void Builder::dumpInstructions(std::vector<unsigned int>& out, const std::vector<Instruction*>& instructions) const
+{
+    for (int i = 0; i < (int)instructions.size(); ++i) {
+        instructions[i]->dump(out);
+    }
+}
+
+void MissingFunctionality(const char* fun)
+{
+    printf("Missing functionality: %s\n", fun);
+    exit(1);
+}
+
+void ValidationError(const char* error)
+{
+    printf("Validation Error: %s\n", error);
+}
+
+}; // end spv namespace
diff --git a/SPIRV/SpvBuilder.h b/SPIRV/SpvBuilder.h
index b500c1fe..4eef5a4 100644
--- a/SPIRV/SpvBuilder.h
+++ b/SPIRV/SpvBuilder.h
@@ -1,563 +1,563 @@
-//

-//Copyright (C) 2014 LunarG, Inc.

-//

-//All rights reserved.

-//

-//Redistribution and use in source and binary forms, with or without

-//modification, are permitted provided that the following conditions

-//are met:

-//

-//    Redistributions of source code must retain the above copyright

-//    notice, this list of conditions and the following disclaimer.

-//

-//    Redistributions in binary form must reproduce the above

-//    copyright notice, this list of conditions and the following

-//    disclaimer in the documentation and/or other materials provided

-//    with the distribution.

-//

-//    Neither the name of 3Dlabs Inc. Ltd. nor the names of its

-//    contributors may be used to endorse or promote products derived

-//    from this software without specific prior written permission.

-//

-//THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS

-//"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT

-//LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS

-//FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE

-//COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,

-//INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,

-//BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;

-//LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER

-//CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT

-//LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN

-//ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE

-//POSSIBILITY OF SUCH DAMAGE.

-

-//

-// Author: John Kessenich, LunarG

-//

-

-//

-// "Builder" is an interface to fully build SPIR-V IR.   Allocate one of

-// these to build (a thread safe) internal SPIR-V representation (IR),

-// and then dump it as a binary stream according to the SPIR-V specification.

-//

-// A Builder has a 1:1 relationship with a SPIR-V module.

-//

-

-#pragma once

-#ifndef SpvBuilder_H

-#define SpvBuilder_H

-

-#include "spirv.h"

-#include "spvIR.h"

-

-#include <algorithm>

-#include <stack>

-#include <map>

-

-namespace spv {

-

-class Builder {

-public:

-    Builder(unsigned int userNumber);

-    virtual ~Builder();

-

-    static const int maxMatrixSize = 4;

-

-    void setSource(spv::SourceLanguage lang, int version)

-    {

-        source = lang;

-        sourceVersion = version;

-    }

-    void addSourceExtension(const char* ext) { extensions.push_back(ext); }

-    Id import(const char*);

-    void setMemoryModel(spv::AddressingModel addr, spv::MemoryModel mem)

-    {

-        addressModel = addr;

-        memoryModel = mem;

-    }

-

-    // To get a new <id> for anything needing a new one.

-    Id getUniqueId() { return ++uniqueId; }

-

-    // To get a set of new <id>s, e.g., for a set of function parameters

-    Id getUniqueIds(int numIds)

-    {

-        Id id = uniqueId + 1;

-        uniqueId += numIds;

-        return id;

-    }

-

-    // For creating new types (will return old type if the requested one was already made).

-    Id makeVoidType();

-    Id makeBoolType();

-    Id makePointer(StorageClass, Id type);

-    Id makeIntegerType(int width, bool hasSign);   // generic

-    Id makeIntType(int width) { return makeIntegerType(width, true); }

-    Id makeUintType(int width) { return makeIntegerType(width, false); }

-    Id makeFloatType(int width);

-    Id makeStructType(std::vector<Id>& members, const char*);

-    Id makeVectorType(Id component, int size);

-    Id makeMatrixType(Id component, int cols, int rows);

-    Id makeArrayType(Id element, unsigned size);

-    Id makeFunctionType(Id returnType, std::vector<Id>& paramTypes);

-    enum samplerContent {

-        samplerContentTexture,

-        samplerContentImage,

-        samplerContentTextureFilter

-    };

-    Id makeSampler(Id sampledType, Dim, samplerContent, bool arrayed, bool shadow, bool ms);

-

-    // For querying about types.

-    Id getTypeId(Id resultId) const { return module.getTypeId(resultId); }

-    Id getDerefTypeId(Id resultId) const;

-    Op getOpCode(Id id) const { return module.getInstruction(id)->getOpCode(); }

-    Op getTypeClass(Id typeId) const { return getOpCode(typeId); }

-    Op getMostBasicTypeClass(Id typeId) const;

-    int getNumComponents(Id resultId) const { return getNumTypeComponents(getTypeId(resultId)); }

-    int getNumTypeComponents(Id typeId) const;

-    Id getScalarTypeId(Id typeId) const;

-    Id getContainedTypeId(Id typeId) const;

-    Id getContainedTypeId(Id typeId, int) const;

-

-    bool isPointer(Id resultId)     const { return isPointerType(getTypeId(resultId)); }

-    bool isScalar(Id resultId)      const { return isScalarType(getTypeId(resultId)); }

-    bool isVector(Id resultId)      const { return isVectorType(getTypeId(resultId)); }

-    bool isMatrix(Id resultId)      const { return isMatrixType(getTypeId(resultId)); }

-    bool isAggregate(Id resultId)   const { return isAggregateType(getTypeId(resultId)); }

-

-    bool isPointerType(Id typeId)   const { return getTypeClass(typeId) == OpTypePointer; }

-    bool isScalarType(Id typeId)    const { return getTypeClass(typeId) == OpTypeFloat  || getTypeClass(typeId) == OpTypeInt || getTypeClass(typeId) == OpTypeBool; }

-    bool isVectorType(Id typeId)    const { return getTypeClass(typeId) == OpTypeVector; }

-    bool isMatrixType(Id typeId)    const { return getTypeClass(typeId) == OpTypeMatrix; }

-    bool isStructType(Id typeId)    const { return getTypeClass(typeId) == OpTypeStruct; }

-    bool isArrayType(Id typeId)     const { return getTypeClass(typeId) == OpTypeArray; }

-    bool isAggregateType(Id typeId) const { return isArrayType(typeId) || isStructType(typeId); }

-    bool isSamplerType(Id typeId)   const { return getTypeClass(typeId) == OpTypeSampler; }

-

-    bool isConstantScalar(Id resultId) const { return getOpCode(resultId) == OpConstant; }

-    unsigned int getConstantScalar(Id resultId) const { return module.getInstruction(resultId)->getImmediateOperand(0); }

-

-    int getTypeNumColumns(Id typeId) const

-    {

-        assert(isMatrixType(typeId));

-        return getNumTypeComponents(typeId);

-    }

-    int getNumColumns(Id resultId) const { return getTypeNumColumns(getTypeId(resultId)); }

-    int getTypeNumRows(Id typeId) const

-    {

-        assert(isMatrixType(typeId));

-        return getNumTypeComponents(getContainedTypeId(typeId));

-    }

-    int getNumRows(Id resultId) const { return getTypeNumRows(getTypeId(resultId)); }

-

-    Dim getDimensionality(Id resultId) const

-    {

-        assert(isSamplerType(getTypeId(resultId)));

-        return (Dim)module.getInstruction(getTypeId(resultId))->getImmediateOperand(1);

-    }

-    bool isArrayedSampler(Id resultId) const

-    {

-        assert(isSamplerType(getTypeId(resultId)));

-        return module.getInstruction(getTypeId(resultId))->getImmediateOperand(3) != 0;

-    }

-

-    // For making new constants (will return old constant if the requested one was already made).

-    Id makeBoolConstant(bool b);

-    Id makeIntConstant(Id typeId, unsigned value);

-    Id makeIntConstant(int i)         { return makeIntConstant(makeIntType(32),  (unsigned)i); }

-    Id makeUintConstant(unsigned u)   { return makeIntConstant(makeUintType(32),           u); }

-    Id makeFloatConstant(float f);

-    Id makeDoubleConstant(double d);

-

-    // Turn the array of constants into a proper spv constant of the requested type.

-    Id makeCompositeConstant(Id type, std::vector<Id>& comps);

-

-    // Methods for adding information outside the CFG.

-    void addEntryPoint(ExecutionModel, Function*);

-    void addExecutionMode(Function*, ExecutionMode mode, int value = -1);

-    void addName(Id, const char* name);

-    void addMemberName(Id, int member, const char* name);

-    void addLine(Id target, Id fileName, int line, int column);

-    void addDecoration(Id, Decoration, int num = -1);

-    void addMemberDecoration(Id, unsigned int member, Decoration, int num = -1);

-

-    // At the end of what block do the next create*() instructions go?

-    void setBuildPoint(Block* bp) { buildPoint = bp; }

-    Block* getBuildPoint() const { return buildPoint; }

-

-    // Make the main function.

-    Function* makeMain();

-

-    // Return from main. Implicit denotes a return at the very end of main.

-    void makeMainReturn(bool implicit = false) { makeReturn(implicit, 0, true); }

-

-    // Close the main function.

-    void closeMain();

-

-    // Make a shader-style function, and create its entry block if entry is non-zero.

-    // Return the function, pass back the entry.

-    Function* makeFunctionEntry(Id returnType, const char* name, std::vector<Id>& paramTypes, Block **entry = 0);

-

-    // Create a return. Pass whether it is a return form main, and the return

-    // value (if applicable). In the case of an implicit return, no post-return

-    // block is inserted.

-    void makeReturn(bool implicit = false, Id retVal = 0, bool isMain = false);

-

-    // Generate all the code needed to finish up a function.

-    void leaveFunction(bool main);

-

-    // Create a discard.

-    void makeDiscard();

-

-    // Create a global or function local or IO variable.

-    Id createVariable(StorageClass, Id type, const char* name = 0);

-

-    // Store into an Id and return the l-value

-    void createStore(Id rValue, Id lValue);

-

-    // Load from an Id and return it

-    Id createLoad(Id lValue);

-

-    // Create an OpAccessChain instruction

-    Id createAccessChain(StorageClass, Id base, std::vector<Id>& offsets);

-

-    // Create an OpCompositeExtract instruction

-    Id createCompositeExtract(Id composite, Id typeId, unsigned index);

-    Id createCompositeExtract(Id composite, Id typeId, std::vector<unsigned>& indexes);

-    Id createCompositeInsert(Id object, Id composite, Id typeId, unsigned index);

-    Id createCompositeInsert(Id object, Id composite, Id typeId, std::vector<unsigned>& indexes);

-

-    Id createVectorExtractDynamic(Id vector, Id typeId, Id componentIndex);

-    Id createVectorInsertDynamic(Id vector, Id typeId, Id component, Id componentIndex);

-

-    void createNoResultOp(Op);

-    void createNoResultOp(Op, Id operand);

-    void createControlBarrier(unsigned executionScope);

-    void createMemoryBarrier(unsigned executionScope, unsigned memorySemantics);

-    Id createUnaryOp(Op, Id typeId, Id operand);

-    Id createBinOp(Op, Id typeId, Id operand1, Id operand2);

-    Id createTriOp(Op, Id typeId, Id operand1, Id operand2, Id operand3);

-    Id createTernaryOp(Op, Id typeId, Id operand1, Id operand2, Id operand3);

-    Id createFunctionCall(spv::Function*, std::vector<spv::Id>&);

-

-    // Take an rvalue (source) and a set of channels to extract from it to

-    // make a new rvalue, which is returned.

-    Id createRvalueSwizzle(Id typeId, Id source, std::vector<unsigned>& channels);

-

-    // Take a copy of an lvalue (target) and a source of components, and set the

-    // source components into the lvalue where the 'channels' say to put them.

-    // An updated version of the target is returned.

-    // (No true lvalue or stores are used.)

-    Id createLvalueSwizzle(Id typeId, Id target, Id source, std::vector<unsigned>& channels);

-

-    // If the value passed in is an instruction and the precision is not EMpNone,

-    // it gets tagged with the requested precision.

-    void setPrecision(Id /* value */, Decoration /* precision */)

-    {

-        // TODO

-    }

-

-    // Can smear a scalar to a vector for the following forms:

-    //   - promoteScalar(scalar, vector)  // smear scalar to width of vector

-    //   - promoteScalar(vector, scalar)  // smear scalar to width of vector

-    //   - promoteScalar(pointer, scalar) // smear scalar to width of what pointer points to

-    //   - promoteScalar(scalar, scalar)  // do nothing

-    // Other forms are not allowed.

-    //

-    // Note: One of the arguments will change, with the result coming back that way rather than 

-    // through the return value.

-    void promoteScalar(Decoration precision, Id& left, Id& right);

-

-    // make a value by smearing the scalar to fill the type

-    Id smearScalar(Decoration precision, Id scalarVal, Id);

-

-    // Create a call to a built-in function.

-    Id createBuiltinCall(Decoration precision, Id resultType, Id builtins, int entryPoint, std::vector<Id>& args);

-

-    // List of parameters used to create a texture operation

-    struct TextureParameters {

-        Id sampler;

-        Id coords;

-        Id bias;

-        Id lod;

-        Id Dref;

-        Id offset;

-        Id gradX;

-        Id gradY;

-    };

-

-    // Select the correct texture operation based on all inputs, and emit the correct instruction

-    Id createTextureCall(Decoration precision, Id resultType, bool proj, const TextureParameters&);

-

-    // Emit the OpTextureQuery* instruction that was passed in.

-    // Figure out the right return value and type, and return it.

-    Id createTextureQueryCall(Op, const TextureParameters&);

-

-    Id createSamplePositionCall(Decoration precision, Id, Id);

-

-    Id createBitFieldExtractCall(Decoration precision, Id, Id, Id, bool isSigned);

-    Id createBitFieldInsertCall(Decoration precision, Id, Id, Id, Id);

-

-    // Reduction comparision for composites:  For equal and not-equal resulting in a scalar.

-    Id createCompare(Decoration precision, Id, Id, bool /* true if for equal, fales if for not-equal */);

-

-    // OpCompositeConstruct

-    Id createCompositeConstruct(Id typeId, std::vector<Id>& constituents);

-

-    // vector or scalar constructor

-    Id createConstructor(Decoration precision, const std::vector<Id>& sources, Id resultTypeId);

-

-    // matrix constructor

-    Id createMatrixConstructor(Decoration precision, const std::vector<Id>& sources, Id constructee);

-

-    // Helper to use for building nested control flow with if-then-else.

-    class If {

-    public:

-        If(Id condition, Builder& builder);

-        ~If() {}

-

-        void makeBeginElse();

-        void makeEndIf();

-

-    private:

-        If(const If&);

-        If& operator=(If&);

-

-        Builder& builder;

-        Id condition;

-        Function* function;

-        Block* headerBlock;

-        Block* thenBlock;

-        Block* elseBlock;

-        Block* mergeBlock;

-    };

-

-    // Make a switch statement.  A switch has 'numSegments' of pieces of code, not containing

-    // any case/default labels, all separated by one or more case/default labels.  Each possible

-    // case value v is a jump to the caseValues[v] segment.  The defaultSegment is also in this

-    // number space.  How to compute the value is given by 'condition', as in switch(condition).

-    //

-    // The SPIR-V Builder will maintain the stack of post-switch merge blocks for nested switches.

-    //

-    // Use a defaultSegment < 0 if there is no default segment (to branch to post switch).

-    //

-    // Returns the right set of basic blocks to start each code segment with, so that the caller's

-    // recursion stack can hold the memory for it.

-    //

-    void makeSwitch(Id condition, int numSegments, std::vector<int>& caseValues, std::vector<int>& valueToSegment, int defaultSegment,

-                    std::vector<Block*>& segmentBB);  // return argument

-

-    // Add a branch to the innermost switch's merge block.

-    void addSwitchBreak();

-

-    // Move to the next code segment, passing in the return argument in makeSwitch()

-    void nextSwitchSegment(std::vector<Block*>& segmentBB, int segment);

-

-    // Finish off the innermost switch.

-    void endSwitch(std::vector<Block*>& segmentBB);

-

-    // Start the beginning of a new loop.

-    void makeNewLoop();

-

-    // Add the branch for the loop test, based on the given condition.

-    // The true branch goes to the block that remains inside the loop, and

-    // the false branch goes to the loop's merge block.  The  builder insertion

-    // point will be placed at the start of the inside-the-loop block.

-    void createLoopTestBranch(Id condition);

-

-    // Finish generating the loop header block in the case where the loop test

-    // is at the bottom of the loop.  It will include the LoopMerge instruction

-    // and a branch to the rest of the body.  The loop header block must be

-    // separate from the rest of the body to make room for the the two kinds

-    // of *Merge instructions that might have to occur just before a branch:

-    // the loop header must have a LoopMerge as its second-last instruction,

-    // and the body might begin with a conditional branch, which must have its

-    // own SelectionMerge instruction.

-    // Also create the basic block that will contain the loop test, but don't

-    // insert it into the function yet.  Any "continue" constructs in this loop

-    // will branch to the loop test block. The builder insertion point will be

-    // placed at the start of the body block.

-    void endLoopHeaderWithoutTest();

-

-    // Generate a branch to the loop test block.  This can only be called if

-    // the loop test is at the bottom of the loop. The builder insertion point

-    // is left at the start of the test block.

-    void createBranchToLoopTest();

-

-    // Add a branch to the test of the current (innermost) loop.

-    void createLoopContinue();

-

-    // Add an exit (e.g. "break") for the innermost loop that you're in

-    void createLoopExit();

-

-    // Close the innermost loop that you're in

-    void closeLoop();

-

-    //

-    // Access chain design for an R-Value vs. L-Value:

-    //

-    // There is a single access chain the builder is building at

-    // any particular time.  Such a chain can be used to either to a load or

-    // a store, when desired.

-    //

-    // Expressions can be r-values, l-values, or both, or only r-values:

-    //    a[b.c].d = ....  // l-value

-    //    ... = a[b.c].d;  // r-value, that also looks like an l-value

-    //    ++a[b.c].d;      // r-value and l-value

-    //    (x + y)[2];      // r-value only, can't possibly be l-value

-    //

-    // Computing an r-value means generating code.  Hence,

-    // r-values should only be computed when they are needed, not speculatively.

-    //

-    // Computing an l-value means saving away information for later use in the compiler,

-    // no code is generated until the l-value is later dereferenced.  It is okay

-    // to speculatively generate an l-value, just not okay to speculatively dereference it.

-    //

-    // The base of the access chain (the left-most variable or expression

-    // from which everything is based) can be set either as an l-value

-    // or as an r-value.  Most efficient would be to set an l-value if one

-    // is available.  If an expression was evaluated, the resulting r-value

-    // can be set as the chain base.

-    //

-    // The users of this single access chain can save and restore if they

-    // want to nest or manage multiple chains.

-    //

-

-    struct AccessChain {

-        Id base;                     // for l-values, pointer to the base object, for r-values, the base object

-        std::vector<Id> indexChain;

-        Id instr;                    // the instruction that generates this access chain

-        std::vector<unsigned> swizzle;

-        Id component;                // a dynamic component index, can coexist with a swizzle, done after the swizzle

-        Id resultType;               // dereferenced type, to be exclusive of swizzles

-        bool isRValue;

-    };

-

-    //

-    // the SPIR-V builder maintains a single active chain that

-    // the following methods operated on

-    //

-

-    // for external save and restore

-    AccessChain getAccessChain() { return accessChain; }

-    void setAccessChain(AccessChain newChain) { accessChain = newChain; }

-

-    // clear accessChain

-    void clearAccessChain();

-

-    // set new base as an l-value base

-    void setAccessChainLValue(Id lValue)

-    {

-        assert(isPointer(lValue));

-        accessChain.base = lValue;

-        accessChain.resultType = getContainedTypeId(getTypeId(lValue));

-    }

-

-    // set new base value as an r-value

-    void setAccessChainRValue(Id rValue)

-    {

-        accessChain.isRValue = true;

-        accessChain.base = rValue;

-        accessChain.resultType = getTypeId(rValue);

-    }

-

-    // push offset onto the end of the chain

-    void accessChainPush(Id offset, Id newType)

-    {

-        accessChain.indexChain.push_back(offset);

-        accessChain.resultType = newType;

-    }

-

-    // push new swizzle onto the end of any existing swizzle, merging into a single swizzle

-    void accessChainPushSwizzle(std::vector<unsigned>& swizzle);

-

-    // push a variable component selection onto the access chain; supporting only one, so unsided

-    void accessChainPushComponent(Id component) { accessChain.component = component; }

-

-    // use accessChain and swizzle to store value

-    void accessChainStore(Id rvalue);

-

-    // use accessChain and swizzle to load an r-value

-    Id accessChainLoad(Decoration precision);

-

-    // get the direct pointer for an l-value

-    Id accessChainGetLValue();

-

-    void dump(std::vector<unsigned int>&) const;

-

-protected:

-    Id findScalarConstant(Op typeClass, Id typeId, unsigned value) const;

-    Id findScalarConstant(Op typeClass, Id typeId, unsigned v1, unsigned v2) const;

-    Id findCompositeConstant(Op typeClass, std::vector<Id>& comps) const;

-    Id collapseAccessChain();

-    void simplifyAccessChainSwizzle();

-    void mergeAccessChainSwizzle();

-    void createAndSetNoPredecessorBlock(const char*);

-    void createBranch(Block* block);

-    void createMerge(Op, Block*, unsigned int control);

-    void createConditionalBranch(Id condition, Block* thenBlock, Block* elseBlock);

-    void dumpInstructions(std::vector<unsigned int>&, const std::vector<Instruction*>&) const;

-

-    SourceLanguage source;

-    int sourceVersion;

-    std::vector<const char*> extensions;

-    AddressingModel addressModel;

-    MemoryModel memoryModel;

-    int builderNumber;

-    Module module;

-    Block* buildPoint;

-    Id uniqueId;

-    Function* mainFunction;

-    Block* stageExit;

-    AccessChain accessChain;

-

-    // special blocks of instructions for output

-    std::vector<Instruction*> imports;

-    std::vector<Instruction*> entryPoints;

-    std::vector<Instruction*> executionModes;

-    std::vector<Instruction*> names;

-    std::vector<Instruction*> lines;

-    std::vector<Instruction*> decorations;

-    std::vector<Instruction*> constantsTypesGlobals;

-    std::vector<Instruction*> externals;

-

-     // not output, internally used for quick & dirty canonical (unique) creation

-    std::vector<Instruction*> groupedConstants[OpConstant];  // all types appear before OpConstant

-    std::vector<Instruction*> groupedTypes[OpConstant];

-

-    // stack of switches

-    std::stack<Block*> switchMerges;

-

-    // Data that needs to be kept in order to properly handle loops.

-    struct Loop {

-        // The header is the first block generated for the loop.

-        // It dominates all the blocks in the loop, i.e. it is always

-        // executed before any others.

-        // If the loop test is executed before the body (as in "while" and

-        // "for" loops), then the header begins with the test code.

-        // Otherwise, the loop is a "do-while" loop and the header contains the

-        // start of the body of the loop (if the body exists).

-        Block* header;

-        // The merge block marks the end of the loop.  Control is transferred

-        // to the merge block when either the loop test fails, or when a

-        // nested "break" is encountered.

-        Block* merge;

-        // If not NULL, the test block is the basic block containing the loop

-        // test and the conditional branch back to the header or the merge

-        // block.  This is created for "do-while" loops, and is the target of

-        // any "continue" constructs that might exist.

-        Block* test;

-        Function* function;

-    };

-

-    // Our loop stack.

-    std::stack<Loop> loops;

-};  // end Builder class

-

-void MissingFunctionality(const char*);

-void ValidationError(const char* error);

-

-};  // end spv namespace

-

-#endif // SpvBuilder_H

+//
+//Copyright (C) 2014 LunarG, Inc.
+//
+//All rights reserved.
+//
+//Redistribution and use in source and binary forms, with or without
+//modification, are permitted provided that the following conditions
+//are met:
+//
+//    Redistributions of source code must retain the above copyright
+//    notice, this list of conditions and the following disclaimer.
+//
+//    Redistributions in binary form must reproduce the above
+//    copyright notice, this list of conditions and the following
+//    disclaimer in the documentation and/or other materials provided
+//    with the distribution.
+//
+//    Neither the name of 3Dlabs Inc. Ltd. nor the names of its
+//    contributors may be used to endorse or promote products derived
+//    from this software without specific prior written permission.
+//
+//THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+//"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+//LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+//FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+//COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+//INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+//BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+//LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+//CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+//LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+//ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+//POSSIBILITY OF SUCH DAMAGE.
+
+//
+// Author: John Kessenich, LunarG
+//
+
+//
+// "Builder" is an interface to fully build SPIR-V IR.   Allocate one of
+// these to build (a thread safe) internal SPIR-V representation (IR),
+// and then dump it as a binary stream according to the SPIR-V specification.
+//
+// A Builder has a 1:1 relationship with a SPIR-V module.
+//
+
+#pragma once
+#ifndef SpvBuilder_H
+#define SpvBuilder_H
+
+#include "spirv.h"
+#include "spvIR.h"
+
+#include <algorithm>
+#include <stack>
+#include <map>
+
+namespace spv {
+
+class Builder {
+public:
+    Builder(unsigned int userNumber);
+    virtual ~Builder();
+
+    static const int maxMatrixSize = 4;
+
+    void setSource(spv::SourceLanguage lang, int version)
+    {
+        source = lang;
+        sourceVersion = version;
+    }
+    void addSourceExtension(const char* ext) { extensions.push_back(ext); }
+    Id import(const char*);
+    void setMemoryModel(spv::AddressingModel addr, spv::MemoryModel mem)
+    {
+        addressModel = addr;
+        memoryModel = mem;
+    }
+
+    // To get a new <id> for anything needing a new one.
+    Id getUniqueId() { return ++uniqueId; }
+
+    // To get a set of new <id>s, e.g., for a set of function parameters
+    Id getUniqueIds(int numIds)
+    {
+        Id id = uniqueId + 1;
+        uniqueId += numIds;
+        return id;
+    }
+
+    // For creating new types (will return old type if the requested one was already made).
+    Id makeVoidType();
+    Id makeBoolType();
+    Id makePointer(StorageClass, Id type);
+    Id makeIntegerType(int width, bool hasSign);   // generic
+    Id makeIntType(int width) { return makeIntegerType(width, true); }
+    Id makeUintType(int width) { return makeIntegerType(width, false); }
+    Id makeFloatType(int width);
+    Id makeStructType(std::vector<Id>& members, const char*);
+    Id makeVectorType(Id component, int size);
+    Id makeMatrixType(Id component, int cols, int rows);
+    Id makeArrayType(Id element, unsigned size);
+    Id makeFunctionType(Id returnType, std::vector<Id>& paramTypes);
+    enum samplerContent {
+        samplerContentTexture,
+        samplerContentImage,
+        samplerContentTextureFilter
+    };
+    Id makeSampler(Id sampledType, Dim, samplerContent, bool arrayed, bool shadow, bool ms);
+
+    // For querying about types.
+    Id getTypeId(Id resultId) const { return module.getTypeId(resultId); }
+    Id getDerefTypeId(Id resultId) const;
+    Op getOpCode(Id id) const { return module.getInstruction(id)->getOpCode(); }
+    Op getTypeClass(Id typeId) const { return getOpCode(typeId); }
+    Op getMostBasicTypeClass(Id typeId) const;
+    int getNumComponents(Id resultId) const { return getNumTypeComponents(getTypeId(resultId)); }
+    int getNumTypeComponents(Id typeId) const;
+    Id getScalarTypeId(Id typeId) const;
+    Id getContainedTypeId(Id typeId) const;
+    Id getContainedTypeId(Id typeId, int) const;
+
+    bool isPointer(Id resultId)     const { return isPointerType(getTypeId(resultId)); }
+    bool isScalar(Id resultId)      const { return isScalarType(getTypeId(resultId)); }
+    bool isVector(Id resultId)      const { return isVectorType(getTypeId(resultId)); }
+    bool isMatrix(Id resultId)      const { return isMatrixType(getTypeId(resultId)); }
+    bool isAggregate(Id resultId)   const { return isAggregateType(getTypeId(resultId)); }
+
+    bool isPointerType(Id typeId)   const { return getTypeClass(typeId) == OpTypePointer; }
+    bool isScalarType(Id typeId)    const { return getTypeClass(typeId) == OpTypeFloat  || getTypeClass(typeId) == OpTypeInt || getTypeClass(typeId) == OpTypeBool; }
+    bool isVectorType(Id typeId)    const { return getTypeClass(typeId) == OpTypeVector; }
+    bool isMatrixType(Id typeId)    const { return getTypeClass(typeId) == OpTypeMatrix; }
+    bool isStructType(Id typeId)    const { return getTypeClass(typeId) == OpTypeStruct; }
+    bool isArrayType(Id typeId)     const { return getTypeClass(typeId) == OpTypeArray; }
+    bool isAggregateType(Id typeId) const { return isArrayType(typeId) || isStructType(typeId); }
+    bool isSamplerType(Id typeId)   const { return getTypeClass(typeId) == OpTypeSampler; }
+
+    bool isConstantScalar(Id resultId) const { return getOpCode(resultId) == OpConstant; }
+    unsigned int getConstantScalar(Id resultId) const { return module.getInstruction(resultId)->getImmediateOperand(0); }
+
+    int getTypeNumColumns(Id typeId) const
+    {
+        assert(isMatrixType(typeId));
+        return getNumTypeComponents(typeId);
+    }
+    int getNumColumns(Id resultId) const { return getTypeNumColumns(getTypeId(resultId)); }
+    int getTypeNumRows(Id typeId) const
+    {
+        assert(isMatrixType(typeId));
+        return getNumTypeComponents(getContainedTypeId(typeId));
+    }
+    int getNumRows(Id resultId) const { return getTypeNumRows(getTypeId(resultId)); }
+
+    Dim getDimensionality(Id resultId) const
+    {
+        assert(isSamplerType(getTypeId(resultId)));
+        return (Dim)module.getInstruction(getTypeId(resultId))->getImmediateOperand(1);
+    }
+    bool isArrayedSampler(Id resultId) const
+    {
+        assert(isSamplerType(getTypeId(resultId)));
+        return module.getInstruction(getTypeId(resultId))->getImmediateOperand(3) != 0;
+    }
+
+    // For making new constants (will return old constant if the requested one was already made).
+    Id makeBoolConstant(bool b);
+    Id makeIntConstant(Id typeId, unsigned value);
+    Id makeIntConstant(int i)         { return makeIntConstant(makeIntType(32),  (unsigned)i); }
+    Id makeUintConstant(unsigned u)   { return makeIntConstant(makeUintType(32),           u); }
+    Id makeFloatConstant(float f);
+    Id makeDoubleConstant(double d);
+
+    // Turn the array of constants into a proper spv constant of the requested type.
+    Id makeCompositeConstant(Id type, std::vector<Id>& comps);
+
+    // Methods for adding information outside the CFG.
+    void addEntryPoint(ExecutionModel, Function*);
+    void addExecutionMode(Function*, ExecutionMode mode, int value = -1);
+    void addName(Id, const char* name);
+    void addMemberName(Id, int member, const char* name);
+    void addLine(Id target, Id fileName, int line, int column);
+    void addDecoration(Id, Decoration, int num = -1);
+    void addMemberDecoration(Id, unsigned int member, Decoration, int num = -1);
+
+    // At the end of what block do the next create*() instructions go?
+    void setBuildPoint(Block* bp) { buildPoint = bp; }
+    Block* getBuildPoint() const { return buildPoint; }
+
+    // Make the main function.
+    Function* makeMain();
+
+    // Return from main. Implicit denotes a return at the very end of main.
+    void makeMainReturn(bool implicit = false) { makeReturn(implicit, 0, true); }
+
+    // Close the main function.
+    void closeMain();
+
+    // Make a shader-style function, and create its entry block if entry is non-zero.
+    // Return the function, pass back the entry.
+    Function* makeFunctionEntry(Id returnType, const char* name, std::vector<Id>& paramTypes, Block **entry = 0);
+
+    // Create a return. Pass whether it is a return form main, and the return
+    // value (if applicable). In the case of an implicit return, no post-return
+    // block is inserted.
+    void makeReturn(bool implicit = false, Id retVal = 0, bool isMain = false);
+
+    // Generate all the code needed to finish up a function.
+    void leaveFunction(bool main);
+
+    // Create a discard.
+    void makeDiscard();
+
+    // Create a global or function local or IO variable.
+    Id createVariable(StorageClass, Id type, const char* name = 0);
+
+    // Store into an Id and return the l-value
+    void createStore(Id rValue, Id lValue);
+
+    // Load from an Id and return it
+    Id createLoad(Id lValue);
+
+    // Create an OpAccessChain instruction
+    Id createAccessChain(StorageClass, Id base, std::vector<Id>& offsets);
+
+    // Create an OpCompositeExtract instruction
+    Id createCompositeExtract(Id composite, Id typeId, unsigned index);
+    Id createCompositeExtract(Id composite, Id typeId, std::vector<unsigned>& indexes);
+    Id createCompositeInsert(Id object, Id composite, Id typeId, unsigned index);
+    Id createCompositeInsert(Id object, Id composite, Id typeId, std::vector<unsigned>& indexes);
+
+    Id createVectorExtractDynamic(Id vector, Id typeId, Id componentIndex);
+    Id createVectorInsertDynamic(Id vector, Id typeId, Id component, Id componentIndex);
+
+    void createNoResultOp(Op);
+    void createNoResultOp(Op, Id operand);
+    void createControlBarrier(unsigned executionScope);
+    void createMemoryBarrier(unsigned executionScope, unsigned memorySemantics);
+    Id createUnaryOp(Op, Id typeId, Id operand);
+    Id createBinOp(Op, Id typeId, Id operand1, Id operand2);
+    Id createTriOp(Op, Id typeId, Id operand1, Id operand2, Id operand3);
+    Id createTernaryOp(Op, Id typeId, Id operand1, Id operand2, Id operand3);
+    Id createFunctionCall(spv::Function*, std::vector<spv::Id>&);
+
+    // Take an rvalue (source) and a set of channels to extract from it to
+    // make a new rvalue, which is returned.
+    Id createRvalueSwizzle(Id typeId, Id source, std::vector<unsigned>& channels);
+
+    // Take a copy of an lvalue (target) and a source of components, and set the
+    // source components into the lvalue where the 'channels' say to put them.
+    // An updated version of the target is returned.
+    // (No true lvalue or stores are used.)
+    Id createLvalueSwizzle(Id typeId, Id target, Id source, std::vector<unsigned>& channels);
+
+    // If the value passed in is an instruction and the precision is not EMpNone,
+    // it gets tagged with the requested precision.
+    void setPrecision(Id /* value */, Decoration /* precision */)
+    {
+        // TODO
+    }
+
+    // Can smear a scalar to a vector for the following forms:
+    //   - promoteScalar(scalar, vector)  // smear scalar to width of vector
+    //   - promoteScalar(vector, scalar)  // smear scalar to width of vector
+    //   - promoteScalar(pointer, scalar) // smear scalar to width of what pointer points to
+    //   - promoteScalar(scalar, scalar)  // do nothing
+    // Other forms are not allowed.
+    //
+    // Note: One of the arguments will change, with the result coming back that way rather than 
+    // through the return value.
+    void promoteScalar(Decoration precision, Id& left, Id& right);
+
+    // make a value by smearing the scalar to fill the type
+    Id smearScalar(Decoration precision, Id scalarVal, Id);
+
+    // Create a call to a built-in function.
+    Id createBuiltinCall(Decoration precision, Id resultType, Id builtins, int entryPoint, std::vector<Id>& args);
+
+    // List of parameters used to create a texture operation
+    struct TextureParameters {
+        Id sampler;
+        Id coords;
+        Id bias;
+        Id lod;
+        Id Dref;
+        Id offset;
+        Id gradX;
+        Id gradY;
+    };
+
+    // Select the correct texture operation based on all inputs, and emit the correct instruction
+    Id createTextureCall(Decoration precision, Id resultType, bool proj, const TextureParameters&);
+
+    // Emit the OpTextureQuery* instruction that was passed in.
+    // Figure out the right return value and type, and return it.
+    Id createTextureQueryCall(Op, const TextureParameters&);
+
+    Id createSamplePositionCall(Decoration precision, Id, Id);
+
+    Id createBitFieldExtractCall(Decoration precision, Id, Id, Id, bool isSigned);
+    Id createBitFieldInsertCall(Decoration precision, Id, Id, Id, Id);
+
+    // Reduction comparision for composites:  For equal and not-equal resulting in a scalar.
+    Id createCompare(Decoration precision, Id, Id, bool /* true if for equal, fales if for not-equal */);
+
+    // OpCompositeConstruct
+    Id createCompositeConstruct(Id typeId, std::vector<Id>& constituents);
+
+    // vector or scalar constructor
+    Id createConstructor(Decoration precision, const std::vector<Id>& sources, Id resultTypeId);
+
+    // matrix constructor
+    Id createMatrixConstructor(Decoration precision, const std::vector<Id>& sources, Id constructee);
+
+    // Helper to use for building nested control flow with if-then-else.
+    class If {
+    public:
+        If(Id condition, Builder& builder);
+        ~If() {}
+
+        void makeBeginElse();
+        void makeEndIf();
+
+    private:
+        If(const If&);
+        If& operator=(If&);
+
+        Builder& builder;
+        Id condition;
+        Function* function;
+        Block* headerBlock;
+        Block* thenBlock;
+        Block* elseBlock;
+        Block* mergeBlock;
+    };
+
+    // Make a switch statement.  A switch has 'numSegments' of pieces of code, not containing
+    // any case/default labels, all separated by one or more case/default labels.  Each possible
+    // case value v is a jump to the caseValues[v] segment.  The defaultSegment is also in this
+    // number space.  How to compute the value is given by 'condition', as in switch(condition).
+    //
+    // The SPIR-V Builder will maintain the stack of post-switch merge blocks for nested switches.
+    //
+    // Use a defaultSegment < 0 if there is no default segment (to branch to post switch).
+    //
+    // Returns the right set of basic blocks to start each code segment with, so that the caller's
+    // recursion stack can hold the memory for it.
+    //
+    void makeSwitch(Id condition, int numSegments, std::vector<int>& caseValues, std::vector<int>& valueToSegment, int defaultSegment,
+                    std::vector<Block*>& segmentBB);  // return argument
+
+    // Add a branch to the innermost switch's merge block.
+    void addSwitchBreak();
+
+    // Move to the next code segment, passing in the return argument in makeSwitch()
+    void nextSwitchSegment(std::vector<Block*>& segmentBB, int segment);
+
+    // Finish off the innermost switch.
+    void endSwitch(std::vector<Block*>& segmentBB);
+
+    // Start the beginning of a new loop.
+    void makeNewLoop();
+
+    // Add the branch for the loop test, based on the given condition.
+    // The true branch goes to the block that remains inside the loop, and
+    // the false branch goes to the loop's merge block.  The  builder insertion
+    // point will be placed at the start of the inside-the-loop block.
+    void createLoopTestBranch(Id condition);
+
+    // Finish generating the loop header block in the case where the loop test
+    // is at the bottom of the loop.  It will include the LoopMerge instruction
+    // and a branch to the rest of the body.  The loop header block must be
+    // separate from the rest of the body to make room for the the two kinds
+    // of *Merge instructions that might have to occur just before a branch:
+    // the loop header must have a LoopMerge as its second-last instruction,
+    // and the body might begin with a conditional branch, which must have its
+    // own SelectionMerge instruction.
+    // Also create the basic block that will contain the loop test, but don't
+    // insert it into the function yet.  Any "continue" constructs in this loop
+    // will branch to the loop test block. The builder insertion point will be
+    // placed at the start of the body block.
+    void endLoopHeaderWithoutTest();
+
+    // Generate a branch to the loop test block.  This can only be called if
+    // the loop test is at the bottom of the loop. The builder insertion point
+    // is left at the start of the test block.
+    void createBranchToLoopTest();
+
+    // Add a branch to the test of the current (innermost) loop.
+    void createLoopContinue();
+
+    // Add an exit (e.g. "break") for the innermost loop that you're in
+    void createLoopExit();
+
+    // Close the innermost loop that you're in
+    void closeLoop();
+
+    //
+    // Access chain design for an R-Value vs. L-Value:
+    //
+    // There is a single access chain the builder is building at
+    // any particular time.  Such a chain can be used to either to a load or
+    // a store, when desired.
+    //
+    // Expressions can be r-values, l-values, or both, or only r-values:
+    //    a[b.c].d = ....  // l-value
+    //    ... = a[b.c].d;  // r-value, that also looks like an l-value
+    //    ++a[b.c].d;      // r-value and l-value
+    //    (x + y)[2];      // r-value only, can't possibly be l-value
+    //
+    // Computing an r-value means generating code.  Hence,
+    // r-values should only be computed when they are needed, not speculatively.
+    //
+    // Computing an l-value means saving away information for later use in the compiler,
+    // no code is generated until the l-value is later dereferenced.  It is okay
+    // to speculatively generate an l-value, just not okay to speculatively dereference it.
+    //
+    // The base of the access chain (the left-most variable or expression
+    // from which everything is based) can be set either as an l-value
+    // or as an r-value.  Most efficient would be to set an l-value if one
+    // is available.  If an expression was evaluated, the resulting r-value
+    // can be set as the chain base.
+    //
+    // The users of this single access chain can save and restore if they
+    // want to nest or manage multiple chains.
+    //
+
+    struct AccessChain {
+        Id base;                     // for l-values, pointer to the base object, for r-values, the base object
+        std::vector<Id> indexChain;
+        Id instr;                    // the instruction that generates this access chain
+        std::vector<unsigned> swizzle;
+        Id component;                // a dynamic component index, can coexist with a swizzle, done after the swizzle
+        Id resultType;               // dereferenced type, to be exclusive of swizzles
+        bool isRValue;
+    };
+
+    //
+    // the SPIR-V builder maintains a single active chain that
+    // the following methods operated on
+    //
+
+    // for external save and restore
+    AccessChain getAccessChain() { return accessChain; }
+    void setAccessChain(AccessChain newChain) { accessChain = newChain; }
+
+    // clear accessChain
+    void clearAccessChain();
+
+    // set new base as an l-value base
+    void setAccessChainLValue(Id lValue)
+    {
+        assert(isPointer(lValue));
+        accessChain.base = lValue;
+        accessChain.resultType = getContainedTypeId(getTypeId(lValue));
+    }
+
+    // set new base value as an r-value
+    void setAccessChainRValue(Id rValue)
+    {
+        accessChain.isRValue = true;
+        accessChain.base = rValue;
+        accessChain.resultType = getTypeId(rValue);
+    }
+
+    // push offset onto the end of the chain
+    void accessChainPush(Id offset, Id newType)
+    {
+        accessChain.indexChain.push_back(offset);
+        accessChain.resultType = newType;
+    }
+
+    // push new swizzle onto the end of any existing swizzle, merging into a single swizzle
+    void accessChainPushSwizzle(std::vector<unsigned>& swizzle);
+
+    // push a variable component selection onto the access chain; supporting only one, so unsided
+    void accessChainPushComponent(Id component) { accessChain.component = component; }
+
+    // use accessChain and swizzle to store value
+    void accessChainStore(Id rvalue);
+
+    // use accessChain and swizzle to load an r-value
+    Id accessChainLoad(Decoration precision);
+
+    // get the direct pointer for an l-value
+    Id accessChainGetLValue();
+
+    void dump(std::vector<unsigned int>&) const;
+
+protected:
+    Id findScalarConstant(Op typeClass, Id typeId, unsigned value) const;
+    Id findScalarConstant(Op typeClass, Id typeId, unsigned v1, unsigned v2) const;
+    Id findCompositeConstant(Op typeClass, std::vector<Id>& comps) const;
+    Id collapseAccessChain();
+    void simplifyAccessChainSwizzle();
+    void mergeAccessChainSwizzle();
+    void createAndSetNoPredecessorBlock(const char*);
+    void createBranch(Block* block);
+    void createMerge(Op, Block*, unsigned int control);
+    void createConditionalBranch(Id condition, Block* thenBlock, Block* elseBlock);
+    void dumpInstructions(std::vector<unsigned int>&, const std::vector<Instruction*>&) const;
+
+    SourceLanguage source;
+    int sourceVersion;
+    std::vector<const char*> extensions;
+    AddressingModel addressModel;
+    MemoryModel memoryModel;
+    int builderNumber;
+    Module module;
+    Block* buildPoint;
+    Id uniqueId;
+    Function* mainFunction;
+    Block* stageExit;
+    AccessChain accessChain;
+
+    // special blocks of instructions for output
+    std::vector<Instruction*> imports;
+    std::vector<Instruction*> entryPoints;
+    std::vector<Instruction*> executionModes;
+    std::vector<Instruction*> names;
+    std::vector<Instruction*> lines;
+    std::vector<Instruction*> decorations;
+    std::vector<Instruction*> constantsTypesGlobals;
+    std::vector<Instruction*> externals;
+
+     // not output, internally used for quick & dirty canonical (unique) creation
+    std::vector<Instruction*> groupedConstants[OpConstant];  // all types appear before OpConstant
+    std::vector<Instruction*> groupedTypes[OpConstant];
+
+    // stack of switches
+    std::stack<Block*> switchMerges;
+
+    // Data that needs to be kept in order to properly handle loops.
+    struct Loop {
+        // The header is the first block generated for the loop.
+        // It dominates all the blocks in the loop, i.e. it is always
+        // executed before any others.
+        // If the loop test is executed before the body (as in "while" and
+        // "for" loops), then the header begins with the test code.
+        // Otherwise, the loop is a "do-while" loop and the header contains the
+        // start of the body of the loop (if the body exists).
+        Block* header;
+        // The merge block marks the end of the loop.  Control is transferred
+        // to the merge block when either the loop test fails, or when a
+        // nested "break" is encountered.
+        Block* merge;
+        // If not NULL, the test block is the basic block containing the loop
+        // test and the conditional branch back to the header or the merge
+        // block.  This is created for "do-while" loops, and is the target of
+        // any "continue" constructs that might exist.
+        Block* test;
+        Function* function;
+    };
+
+    // Our loop stack.
+    std::stack<Loop> loops;
+};  // end Builder class
+
+void MissingFunctionality(const char*);
+void ValidationError(const char* error);
+
+};  // end spv namespace
+
+#endif // SpvBuilder_H
diff --git a/SPIRV/disassemble.cpp b/SPIRV/disassemble.cpp
index bc8ca88..adbe1ac 100644
--- a/SPIRV/disassemble.cpp
+++ b/SPIRV/disassemble.cpp
@@ -1,435 +1,435 @@
-//

-//Copyright (C) 2014 LunarG, Inc.

-//

-//All rights reserved.

-//

-//Redistribution and use in source and binary forms, with or without

-//modification, are permitted provided that the following conditions

-//are met:

-//

-//    Redistributions of source code must retain the above copyright

-//    notice, this list of conditions and the following disclaimer.

-//

-//    Redistributions in binary form must reproduce the above

-//    copyright notice, this list of conditions and the following

-//    disclaimer in the documentation and/or other materials provided

-//    with the distribution.

-//

-//    Neither the name of 3Dlabs Inc. Ltd. nor the names of its

-//    contributors may be used to endorse or promote products derived

-//    from this software without specific prior written permission.

-//

-//THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS

-//"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT

-//LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTAstreamITY AND FITNESS

-//FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE

-//COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,

-//INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,

-//BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;

-//LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER

-//CAUSED AND ON ANY THEORY OF LIAstreamITY, WHETHER IN CONTRACT, STRICT

-//LIAstreamITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN

-//ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE

-//POSSIstreamITY OF SUCH DAMAGE.

-

-//

-// Author: John Kessenich, LunarG

-//

-

-//

-// Disassembler for SPIR-V.

-//

-

-#include <stdlib.h>

-#include <assert.h>

-#include <iomanip>

-#include <stack>

-#include <sstream>

-

-#include "GLSL450Lib.h"

-extern const char* GlslStd450DebugNames[GLSL_STD_450::Count];

-

-#include "disassemble.h"

-#include "doc.h"

-

-namespace spv {

-

-void Kill(std::ostream& out, const char* message)

-{

-    out << std::endl << "Disassembly failed: " << message << std::endl;

-    exit(1);

-}

-

-// Container class for a single instance of a SPIR-V stream, with methods for disassembly.

-class SpirvStream {

-public:

-    SpirvStream(std::ostream& out, const std::vector<unsigned int>& stream) : out(out), stream(stream), word(0), nextNestedControl(0) { }

-    virtual ~SpirvStream() { }

-

-    void validate();

-    void processInstructions();

-

-protected:

-    SpirvStream(SpirvStream&);

-    SpirvStream& operator=(SpirvStream&);

-

-    Op getOpCode(int id) const { return idInstruction[id] ? (Op)(stream[idInstruction[id]] & OpCodeMask) : OpNop; }

-

-    // Output methods

-    void outputIndent();

-    void formatId(Id id, std::stringstream&);

-    void outputResultId(Id id);

-    void outputTypeId(Id id);

-    void outputId(Id id);

-    void disassembleImmediates(int numOperands);

-    void disassembleIds(int numOperands);

-    void disassembleString();

-    void disassembleInstruction(Id resultId, Id typeId, Op opCode, int numOperands);

-

-    // Data

-    std::ostream& out;                       // where to write the disassembly

-    const std::vector<unsigned int>& stream; // the actual word stream

-    int size;                                // the size of the word stream

-    int word;                                // the next word of the stream to read

-

-    // map each <id> to the instruction that created it

-    Id bound;

-    std::vector<unsigned int> idInstruction;  // the word offset into the stream where the instruction for result [id] starts; 0 if not yet seen (forward reference or function parameter)

-

-    std::vector<std::string> idDescriptor;    // the best text string known for explaining the <id>

-

-    // schema

-    unsigned int schema;

-

-    // stack of structured-merge points

-    std::stack<Id> nestedControl;

-    Id nextNestedControl;         // need a slight delay for when we are nested

-};

-

-void SpirvStream::validate()

-{

-    size = (int)stream.size();

-    if (size < 4)

-        Kill(out, "stream is too short");

-

-    // Magic number

-    if (stream[word++] != MagicNumber) {

-        out << "Bad magic number";

-        return;

-    }

-

-    // Version

-    out << "// Module Version " << stream[word++] << std::endl;

-

-    // Generator's magic number

-    out << "// Generated by (magic number): " << std::setbase(16) << stream[word++] << std::setbase(10) << std::endl;

-

-    // Result <id> bound

-    bound = stream[word++];

-    idInstruction.resize(bound);

-    idDescriptor.resize(bound);

-    out << "// Id's are bound by " << bound << std::endl;

-    out << std::endl;

-

-    // Reserved schema, must be 0 for now

-    schema = stream[word++];

-    if (schema != 0)

-        Kill(out, "bad schema, must be 0");

-}

-

-// Loop over all the instructions, in order, processing each.

-// Boiler plate for each is handled here directly, the rest is dispatched.

-void SpirvStream::processInstructions()

-{

-    // Instructions

-    while (word < size) {

-        int instructionStart = word;

-

-        // Instruction wordCount and opcode

-        unsigned int firstWord = stream[word];

-        unsigned wordCount = firstWord >> WordCountShift;

-        Op opCode = (Op)(firstWord & OpCodeMask);

-        int nextInst = word + wordCount;

-        ++word;

-

-        // Presence of full instruction

-        if (nextInst > size)

-            Kill(out, "stream instruction terminated too early");

-

-        // Base for computing number of operands; will be updated as more is learned

-        unsigned numOperands = wordCount - 1;

-

-        // Type <id>

-        Id typeId = 0;

-        if (InstructionDesc[opCode].hasType()) {

-            typeId = stream[word++];

-            --numOperands;

-        }

-

-        // Result <id>

-        Id resultId = 0;

-        if (InstructionDesc[opCode].hasResult()) {

-            resultId = stream[word++];

-            --numOperands;

-

-            // save instruction for future reference

-            idInstruction[resultId] = instructionStart;

-        }

-

-        outputResultId(resultId);

-        outputTypeId(typeId);

-        outputIndent();

-

-        // Hand off the Op and all its operands

-        disassembleInstruction(resultId, typeId, opCode, numOperands);

-        if (word != nextInst) {

-            out << " ERROR, incorrect number of operands consumed.  At " << word << " instead of " << nextInst << " instruction start was " << instructionStart;

-            word = nextInst;

-        }

-        out << std::endl;

-    }

-}

-

-void SpirvStream::outputIndent()

-{

-    for (int i = 0; i < (int)nestedControl.size(); ++i)

-        out << "  ";

-}

-

-void SpirvStream::formatId(Id id, std::stringstream& idStream)

-{

-    if (id >= bound)

-        Kill(out, "Bad <id>");

-

-    if (id != 0) {

-        idStream << id;

-        if (idDescriptor[id].size() > 0)

-            idStream << "(" << idDescriptor[id] << ")";

-    }

-}

-

-void SpirvStream::outputResultId(Id id)

-{

-    const int width = 16;

-    std::stringstream idStream;

-    formatId(id, idStream);

-    out << std::setw(width) << std::right << idStream.str();

-    if (id != 0)

-        out << ":";

-    else

-        out << " ";

-

-    if (nestedControl.size() && id == nestedControl.top())

-        nestedControl.pop();

-}

-

-void SpirvStream::outputTypeId(Id id)

-{

-    const int width = 12;

-    std::stringstream idStream;

-    formatId(id, idStream);

-    out << std::setw(width) << std::right << idStream.str() << " ";

-}

-

-void SpirvStream::outputId(Id id)

-{

-    if (id >= bound)

-        Kill(out, "Bad <id>");

-

-    out << id;

-    if (idDescriptor[id].size() > 0)

-        out << "(" << idDescriptor[id] << ")";

-}

-

-void SpirvStream::disassembleImmediates(int numOperands)

-{

-    for (int i = 0; i < numOperands; ++i) {

-        out << stream[word++];

-        if (i < numOperands - 1)

-            out << " ";

-    }

-}

-

-void SpirvStream::disassembleIds(int numOperands)

-{

-    for (int i = 0; i < numOperands; ++i) {

-        outputId(stream[word++]);

-        if (i < numOperands - 1)

-            out << " ";

-    }

-}

-

-void SpirvStream::disassembleString()

-{

-    out << " \"";

-

-    char* wordString;

-    bool done = false;

-    do {

-        unsigned int content = stream[word];

-        wordString = (char*)&content;

-        for (int charCount = 0; charCount < 4; ++charCount) {

-            if (*wordString == 0) {

-                done = true;

-                break;

-            }

-            out << *(wordString++);

-        }

-        ++word;

-    } while (! done);

-

-    out << "\"";

-}

-

-void SpirvStream::disassembleInstruction(Id resultId, Id /*typeId*/, Op opCode, int numOperands)

-{

-    // Process the opcode

-

-    out << (OpcodeString(opCode) + 2);  // leave out the "Op"

-

-    if (opCode == OpLoopMerge || opCode == OpSelectionMerge)

-        nextNestedControl = stream[word];

-    else if (opCode == OpBranchConditional || opCode == OpSwitch) {

-        if (nextNestedControl) {

-            nestedControl.push(nextNestedControl);

-            nextNestedControl = 0;

-        }

-    } else if (opCode == OpExtInstImport)

-        idDescriptor[resultId] = (char*)(&stream[word]);

-    else {

-        if (idDescriptor[resultId].size() == 0) {

-            switch (opCode) {

-            case OpTypeInt:

-                idDescriptor[resultId] = "int";

-                break;

-            case OpTypeFloat:

-                idDescriptor[resultId] = "float";

-                break;

-            case OpTypeBool:

-                idDescriptor[resultId] = "bool";

-                break;

-            case OpTypeStruct:

-                idDescriptor[resultId] = "struct";

-                break;

-            case OpTypePointer:

-                idDescriptor[resultId] = "ptr";

-                break;

-            case OpTypeVector:

-                if (idDescriptor[stream[word]].size() > 0)

-                    idDescriptor[resultId].append(idDescriptor[stream[word]].begin(), idDescriptor[stream[word]].begin() + 1);

-                idDescriptor[resultId].append("vec");

-                switch (stream[word + 1]) {

-                case 2:   idDescriptor[resultId].append("2");   break;

-                case 3:   idDescriptor[resultId].append("3");   break;

-                case 4:   idDescriptor[resultId].append("4");   break;

-                case 8:   idDescriptor[resultId].append("8");   break;

-                case 16:  idDescriptor[resultId].append("16");  break;

-                case 32:  idDescriptor[resultId].append("32");  break;

-                default: break;

-                }

-                break;

-            default:

-                break;

-            }

-        }

-    }

-

-    // Process the operands.  Note, a new context-dependent set could be

-    // swapped in mid-traversal.

-

-    // Handle textures specially, so can put out helpful strings.

-    if (opCode == OpTypeSampler) {

-        disassembleIds(1);

-        out << " " << DimensionString((Dim)stream[word++]);

-        switch (stream[word++]) {

-        case 0: out << " texture";        break;

-        case 1: out << " image";          break;

-        case 2: out << " filter+texture"; break;

-        }

-        out << (stream[word++] != 0 ? " array" : "");

-        out << (stream[word++] != 0 ? " depth" : "");

-        out << (stream[word++] != 0 ? " multi-sampled" : "");

-        return;

-    }

-

-    // Handle all the parameterized operands

-    for (int op = 0; op < InstructionDesc[opCode].operands.getNum(); ++op) {

-        out << " ";

-        OperandClass operandClass = InstructionDesc[opCode].operands.getClass(op);

-        switch (operandClass) {

-        case OperandId:

-            disassembleIds(1);

-            // Get names for printing "(XXX)" for readability, *after* this id

-            if (opCode == OpName)

-                idDescriptor[stream[word - 1]] = (char*)(&stream[word]);

-            break;

-        case OperandOptionalId:

-        case OperandVariableIds:

-            disassembleIds(numOperands);

-            return;

-        case OperandVariableLiterals:

-            if ((opCode == OpDecorate && stream[word - 1] == DecorationBuiltIn) ||

-                (opCode == OpMemberDecorate && stream[word - 1] == DecorationBuiltIn)) {

-                out << BuiltInString(stream[word++]);

-                --numOperands;

-                ++op;

-            }

-            disassembleImmediates(numOperands);

-            return;

-        case OperandVariableLiteralId:

-            while (numOperands > 0) {

-                out << std::endl;

-                outputResultId(0);

-                outputTypeId(0);

-                outputIndent();

-                out << "     case ";

-                disassembleImmediates(1);

-                out << ": ";

-                disassembleIds(1);

-                numOperands -= 2;

-            }

-            return;

-        case OperandLiteralNumber:

-            disassembleImmediates(1);

-            if (opCode == OpExtInst) {

-                unsigned entrypoint = stream[word - 1];

-                if (entrypoint < GLSL_STD_450::Count)

-                    out << "(" << GlslStd450DebugNames[entrypoint] << ")";

-            }

-            break;

-        case OperandLiteralString:

-            disassembleString();

-            return;

-        default:

-            assert(operandClass >= OperandSource && operandClass < OperandOpcode);

-

-            if (OperandClassParams[operandClass].bitmask) {

-                unsigned int mask = stream[word++];

-                if (mask == 0)

-                    out << "None";

-                else {

-                    for (int m = 0; m < OperandClassParams[operandClass].ceiling; ++m) {

-                        if (mask & (1 << m))

-                            out << OperandClassParams[operandClass].getName(m) << " ";

-                    }

-                }

-                break;

-            } else

-                out << OperandClassParams[operandClass].getName(stream[word++]);

-

-            break;

-        }

-        --numOperands;

-    }

-

-    return;

-}

-

-void Disassemble(std::ostream& out, const std::vector<unsigned int>& stream)

-{

-    SpirvStream SpirvStream(out, stream);

-    SpirvStream.validate();

-    SpirvStream.processInstructions();

-}

-

-}; // end namespace spv

+//
+//Copyright (C) 2014 LunarG, Inc.
+//
+//All rights reserved.
+//
+//Redistribution and use in source and binary forms, with or without
+//modification, are permitted provided that the following conditions
+//are met:
+//
+//    Redistributions of source code must retain the above copyright
+//    notice, this list of conditions and the following disclaimer.
+//
+//    Redistributions in binary form must reproduce the above
+//    copyright notice, this list of conditions and the following
+//    disclaimer in the documentation and/or other materials provided
+//    with the distribution.
+//
+//    Neither the name of 3Dlabs Inc. Ltd. nor the names of its
+//    contributors may be used to endorse or promote products derived
+//    from this software without specific prior written permission.
+//
+//THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+//"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+//LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTAstreamITY AND FITNESS
+//FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+//COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+//INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+//BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+//LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+//CAUSED AND ON ANY THEORY OF LIAstreamITY, WHETHER IN CONTRACT, STRICT
+//LIAstreamITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+//ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+//POSSIstreamITY OF SUCH DAMAGE.
+
+//
+// Author: John Kessenich, LunarG
+//
+
+//
+// Disassembler for SPIR-V.
+//
+
+#include <stdlib.h>
+#include <assert.h>
+#include <iomanip>
+#include <stack>
+#include <sstream>
+
+#include "GLSL450Lib.h"
+extern const char* GlslStd450DebugNames[GLSL_STD_450::Count];
+
+#include "disassemble.h"
+#include "doc.h"
+
+namespace spv {
+
+void Kill(std::ostream& out, const char* message)
+{
+    out << std::endl << "Disassembly failed: " << message << std::endl;
+    exit(1);
+}
+
+// Container class for a single instance of a SPIR-V stream, with methods for disassembly.
+class SpirvStream {
+public:
+    SpirvStream(std::ostream& out, const std::vector<unsigned int>& stream) : out(out), stream(stream), word(0), nextNestedControl(0) { }
+    virtual ~SpirvStream() { }
+
+    void validate();
+    void processInstructions();
+
+protected:
+    SpirvStream(SpirvStream&);
+    SpirvStream& operator=(SpirvStream&);
+
+    Op getOpCode(int id) const { return idInstruction[id] ? (Op)(stream[idInstruction[id]] & OpCodeMask) : OpNop; }
+
+    // Output methods
+    void outputIndent();
+    void formatId(Id id, std::stringstream&);
+    void outputResultId(Id id);
+    void outputTypeId(Id id);
+    void outputId(Id id);
+    void disassembleImmediates(int numOperands);
+    void disassembleIds(int numOperands);
+    void disassembleString();
+    void disassembleInstruction(Id resultId, Id typeId, Op opCode, int numOperands);
+
+    // Data
+    std::ostream& out;                       // where to write the disassembly
+    const std::vector<unsigned int>& stream; // the actual word stream
+    int size;                                // the size of the word stream
+    int word;                                // the next word of the stream to read
+
+    // map each <id> to the instruction that created it
+    Id bound;
+    std::vector<unsigned int> idInstruction;  // the word offset into the stream where the instruction for result [id] starts; 0 if not yet seen (forward reference or function parameter)
+
+    std::vector<std::string> idDescriptor;    // the best text string known for explaining the <id>
+
+    // schema
+    unsigned int schema;
+
+    // stack of structured-merge points
+    std::stack<Id> nestedControl;
+    Id nextNestedControl;         // need a slight delay for when we are nested
+};
+
+void SpirvStream::validate()
+{
+    size = (int)stream.size();
+    if (size < 4)
+        Kill(out, "stream is too short");
+
+    // Magic number
+    if (stream[word++] != MagicNumber) {
+        out << "Bad magic number";
+        return;
+    }
+
+    // Version
+    out << "// Module Version " << stream[word++] << std::endl;
+
+    // Generator's magic number
+    out << "// Generated by (magic number): " << std::setbase(16) << stream[word++] << std::setbase(10) << std::endl;
+
+    // Result <id> bound
+    bound = stream[word++];
+    idInstruction.resize(bound);
+    idDescriptor.resize(bound);
+    out << "// Id's are bound by " << bound << std::endl;
+    out << std::endl;
+
+    // Reserved schema, must be 0 for now
+    schema = stream[word++];
+    if (schema != 0)
+        Kill(out, "bad schema, must be 0");
+}
+
+// Loop over all the instructions, in order, processing each.
+// Boiler plate for each is handled here directly, the rest is dispatched.
+void SpirvStream::processInstructions()
+{
+    // Instructions
+    while (word < size) {
+        int instructionStart = word;
+
+        // Instruction wordCount and opcode
+        unsigned int firstWord = stream[word];
+        unsigned wordCount = firstWord >> WordCountShift;
+        Op opCode = (Op)(firstWord & OpCodeMask);
+        int nextInst = word + wordCount;
+        ++word;
+
+        // Presence of full instruction
+        if (nextInst > size)
+            Kill(out, "stream instruction terminated too early");
+
+        // Base for computing number of operands; will be updated as more is learned
+        unsigned numOperands = wordCount - 1;
+
+        // Type <id>
+        Id typeId = 0;
+        if (InstructionDesc[opCode].hasType()) {
+            typeId = stream[word++];
+            --numOperands;
+        }
+
+        // Result <id>
+        Id resultId = 0;
+        if (InstructionDesc[opCode].hasResult()) {
+            resultId = stream[word++];
+            --numOperands;
+
+            // save instruction for future reference
+            idInstruction[resultId] = instructionStart;
+        }
+
+        outputResultId(resultId);
+        outputTypeId(typeId);
+        outputIndent();
+
+        // Hand off the Op and all its operands
+        disassembleInstruction(resultId, typeId, opCode, numOperands);
+        if (word != nextInst) {
+            out << " ERROR, incorrect number of operands consumed.  At " << word << " instead of " << nextInst << " instruction start was " << instructionStart;
+            word = nextInst;
+        }
+        out << std::endl;
+    }
+}
+
+void SpirvStream::outputIndent()
+{
+    for (int i = 0; i < (int)nestedControl.size(); ++i)
+        out << "  ";
+}
+
+void SpirvStream::formatId(Id id, std::stringstream& idStream)
+{
+    if (id >= bound)
+        Kill(out, "Bad <id>");
+
+    if (id != 0) {
+        idStream << id;
+        if (idDescriptor[id].size() > 0)
+            idStream << "(" << idDescriptor[id] << ")";
+    }
+}
+
+void SpirvStream::outputResultId(Id id)
+{
+    const int width = 16;
+    std::stringstream idStream;
+    formatId(id, idStream);
+    out << std::setw(width) << std::right << idStream.str();
+    if (id != 0)
+        out << ":";
+    else
+        out << " ";
+
+    if (nestedControl.size() && id == nestedControl.top())
+        nestedControl.pop();
+}
+
+void SpirvStream::outputTypeId(Id id)
+{
+    const int width = 12;
+    std::stringstream idStream;
+    formatId(id, idStream);
+    out << std::setw(width) << std::right << idStream.str() << " ";
+}
+
+void SpirvStream::outputId(Id id)
+{
+    if (id >= bound)
+        Kill(out, "Bad <id>");
+
+    out << id;
+    if (idDescriptor[id].size() > 0)
+        out << "(" << idDescriptor[id] << ")";
+}
+
+void SpirvStream::disassembleImmediates(int numOperands)
+{
+    for (int i = 0; i < numOperands; ++i) {
+        out << stream[word++];
+        if (i < numOperands - 1)
+            out << " ";
+    }
+}
+
+void SpirvStream::disassembleIds(int numOperands)
+{
+    for (int i = 0; i < numOperands; ++i) {
+        outputId(stream[word++]);
+        if (i < numOperands - 1)
+            out << " ";
+    }
+}
+
+void SpirvStream::disassembleString()
+{
+    out << " \"";
+
+    char* wordString;
+    bool done = false;
+    do {
+        unsigned int content = stream[word];
+        wordString = (char*)&content;
+        for (int charCount = 0; charCount < 4; ++charCount) {
+            if (*wordString == 0) {
+                done = true;
+                break;
+            }
+            out << *(wordString++);
+        }
+        ++word;
+    } while (! done);
+
+    out << "\"";
+}
+
+void SpirvStream::disassembleInstruction(Id resultId, Id /*typeId*/, Op opCode, int numOperands)
+{
+    // Process the opcode
+
+    out << (OpcodeString(opCode) + 2);  // leave out the "Op"
+
+    if (opCode == OpLoopMerge || opCode == OpSelectionMerge)
+        nextNestedControl = stream[word];
+    else if (opCode == OpBranchConditional || opCode == OpSwitch) {
+        if (nextNestedControl) {
+            nestedControl.push(nextNestedControl);
+            nextNestedControl = 0;
+        }
+    } else if (opCode == OpExtInstImport)
+        idDescriptor[resultId] = (char*)(&stream[word]);
+    else {
+        if (idDescriptor[resultId].size() == 0) {
+            switch (opCode) {
+            case OpTypeInt:
+                idDescriptor[resultId] = "int";
+                break;
+            case OpTypeFloat:
+                idDescriptor[resultId] = "float";
+                break;
+            case OpTypeBool:
+                idDescriptor[resultId] = "bool";
+                break;
+            case OpTypeStruct:
+                idDescriptor[resultId] = "struct";
+                break;
+            case OpTypePointer:
+                idDescriptor[resultId] = "ptr";
+                break;
+            case OpTypeVector:
+                if (idDescriptor[stream[word]].size() > 0)
+                    idDescriptor[resultId].append(idDescriptor[stream[word]].begin(), idDescriptor[stream[word]].begin() + 1);
+                idDescriptor[resultId].append("vec");
+                switch (stream[word + 1]) {
+                case 2:   idDescriptor[resultId].append("2");   break;
+                case 3:   idDescriptor[resultId].append("3");   break;
+                case 4:   idDescriptor[resultId].append("4");   break;
+                case 8:   idDescriptor[resultId].append("8");   break;
+                case 16:  idDescriptor[resultId].append("16");  break;
+                case 32:  idDescriptor[resultId].append("32");  break;
+                default: break;
+                }
+                break;
+            default:
+                break;
+            }
+        }
+    }
+
+    // Process the operands.  Note, a new context-dependent set could be
+    // swapped in mid-traversal.
+
+    // Handle textures specially, so can put out helpful strings.
+    if (opCode == OpTypeSampler) {
+        disassembleIds(1);
+        out << " " << DimensionString((Dim)stream[word++]);
+        switch (stream[word++]) {
+        case 0: out << " texture";        break;
+        case 1: out << " image";          break;
+        case 2: out << " filter+texture"; break;
+        }
+        out << (stream[word++] != 0 ? " array" : "");
+        out << (stream[word++] != 0 ? " depth" : "");
+        out << (stream[word++] != 0 ? " multi-sampled" : "");
+        return;
+    }
+
+    // Handle all the parameterized operands
+    for (int op = 0; op < InstructionDesc[opCode].operands.getNum(); ++op) {
+        out << " ";
+        OperandClass operandClass = InstructionDesc[opCode].operands.getClass(op);
+        switch (operandClass) {
+        case OperandId:
+            disassembleIds(1);
+            // Get names for printing "(XXX)" for readability, *after* this id
+            if (opCode == OpName)
+                idDescriptor[stream[word - 1]] = (char*)(&stream[word]);
+            break;
+        case OperandOptionalId:
+        case OperandVariableIds:
+            disassembleIds(numOperands);
+            return;
+        case OperandVariableLiterals:
+            if ((opCode == OpDecorate && stream[word - 1] == DecorationBuiltIn) ||
+                (opCode == OpMemberDecorate && stream[word - 1] == DecorationBuiltIn)) {
+                out << BuiltInString(stream[word++]);
+                --numOperands;
+                ++op;
+            }
+            disassembleImmediates(numOperands);
+            return;
+        case OperandVariableLiteralId:
+            while (numOperands > 0) {
+                out << std::endl;
+                outputResultId(0);
+                outputTypeId(0);
+                outputIndent();
+                out << "     case ";
+                disassembleImmediates(1);
+                out << ": ";
+                disassembleIds(1);
+                numOperands -= 2;
+            }
+            return;
+        case OperandLiteralNumber:
+            disassembleImmediates(1);
+            if (opCode == OpExtInst) {
+                unsigned entrypoint = stream[word - 1];
+                if (entrypoint < GLSL_STD_450::Count)
+                    out << "(" << GlslStd450DebugNames[entrypoint] << ")";
+            }
+            break;
+        case OperandLiteralString:
+            disassembleString();
+            return;
+        default:
+            assert(operandClass >= OperandSource && operandClass < OperandOpcode);
+
+            if (OperandClassParams[operandClass].bitmask) {
+                unsigned int mask = stream[word++];
+                if (mask == 0)
+                    out << "None";
+                else {
+                    for (int m = 0; m < OperandClassParams[operandClass].ceiling; ++m) {
+                        if (mask & (1 << m))
+                            out << OperandClassParams[operandClass].getName(m) << " ";
+                    }
+                }
+                break;
+            } else
+                out << OperandClassParams[operandClass].getName(stream[word++]);
+
+            break;
+        }
+        --numOperands;
+    }
+
+    return;
+}
+
+void Disassemble(std::ostream& out, const std::vector<unsigned int>& stream)
+{
+    SpirvStream SpirvStream(out, stream);
+    SpirvStream.validate();
+    SpirvStream.processInstructions();
+}
+
+}; // end namespace spv
diff --git a/SPIRV/disassemble.h b/SPIRV/disassemble.h
index ca8bbb9..bcb05ef 100644
--- a/SPIRV/disassemble.h
+++ b/SPIRV/disassemble.h
@@ -1,56 +1,56 @@
-//

-//Copyright (C) 2014 LunarG, Inc.

-//

-//All rights reserved.

-//

-//Redistribution and use in source and binary forms, with or without

-//modification, are permitted provided that the following conditions

-//are met:

-//

-//    Redistributions of source code must retain the above copyright

-//    notice, this list of conditions and the following disclaimer.

-//

-//    Redistributions in binary form must reproduce the above

-//    copyright notice, this list of conditions and the following

-//    disclaimer in the documentation and/or other materials provided

-//    with the distribution.

-//

-//    Neither the name of 3Dlabs Inc. Ltd. nor the names of its

-//    contributors may be used to endorse or promote products derived

-//    from this software without specific prior written permission.

-//

-//THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS

-//"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT

-//LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS

-//FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE

-//COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,

-//INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,

-//BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;

-//LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER

-//CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT

-//LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN

-//ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE

-//POSSIBILITY OF SUCH DAMAGE.

-

-//

-// Author: John Kessenich, LunarG

-//

-

-//

-// Disassembler for SPIR-V.

-//

-

-#pragma once

-#ifndef disassembler_H

-#define disassembler_H

-

-#include <iostream>

-#include <vector>

-

-namespace spv {

-

-    void Disassemble(std::ostream& out, const std::vector<unsigned int>&);

-

-};  // end namespace spv

-

-#endif // disassembler_H

+//
+//Copyright (C) 2014 LunarG, Inc.
+//
+//All rights reserved.
+//
+//Redistribution and use in source and binary forms, with or without
+//modification, are permitted provided that the following conditions
+//are met:
+//
+//    Redistributions of source code must retain the above copyright
+//    notice, this list of conditions and the following disclaimer.
+//
+//    Redistributions in binary form must reproduce the above
+//    copyright notice, this list of conditions and the following
+//    disclaimer in the documentation and/or other materials provided
+//    with the distribution.
+//
+//    Neither the name of 3Dlabs Inc. Ltd. nor the names of its
+//    contributors may be used to endorse or promote products derived
+//    from this software without specific prior written permission.
+//
+//THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+//"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+//LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+//FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+//COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+//INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+//BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+//LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+//CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+//LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+//ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+//POSSIBILITY OF SUCH DAMAGE.
+
+//
+// Author: John Kessenich, LunarG
+//
+
+//
+// Disassembler for SPIR-V.
+//
+
+#pragma once
+#ifndef disassembler_H
+#define disassembler_H
+
+#include <iostream>
+#include <vector>
+
+namespace spv {
+
+    void Disassemble(std::ostream& out, const std::vector<unsigned int>&);
+
+};  // end namespace spv
+
+#endif // disassembler_H
diff --git a/SPIRV/doc.cpp b/SPIRV/doc.cpp
index 29658b6..a98ab4d 100644
--- a/SPIRV/doc.cpp
+++ b/SPIRV/doc.cpp
@@ -1,2127 +1,2127 @@
-//

-//Copyright (C) 2014 LunarG, Inc.

-//

-//All rights reserved.

-//

-//Redistribution and use in source and binary forms, with or without

-//modification, are permitted provided that the following conditions

-//are met:

-//

-//    Redistributions of source code must retain the above copyright

-//    notice, this list of conditions and the following disclaimer.

-//

-//    Redistributions in binary form must reproduce the above

-//    copyright notice, this list of conditions and the following

-//    disclaimer in the documentation and/or other materials provided

-//    with the distribution.

-//

-//    Neither the name of 3Dlabs Inc. Ltd. nor the names of its

-//    contributors may be used to endorse or promote products derived

-//    from this software without specific prior written permission.

-//

-//THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS

-//"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT

-//LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS

-//FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE

-//COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,

-//INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,

-//BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;

-//LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER

-//CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT

-//LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN

-//ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE

-//POSSIBILITY OF SUCH DAMAGE.

-

-//

-// Author: John Kessenich, LunarG

-//

-

-//

-// 1) Programatically fill in instruction/operand information.

-//    This can be used for disassembly, printing documentation, etc.

-//

-// 2) Print documentation from this parameterization.

-//

-

-#include "doc.h"

-

-#include <stdio.h>

-#include <string.h>

-#include <algorithm>

-

-namespace spv {

-

-//

-// Whole set of functions that translate enumerants to their text strings for

-// the specification (or their sanitized versions for auto-generating the

-// spirv.h header.

-//

-// Also, the ceilings are declared next to these, to help keep them in sync.

-// Ceilings should be

-//  - one more than the maximum value an enumerant takes on, for non-mask enumerants

-//    (for non-sparse enums, this is the number of enumurants)

-//  - the number of bits consumed by the set of masks

-//    (for non-sparse mask enums, this is the number of enumurants)

-//

-

-const int SourceLanguageCeiling = 4;

-

-const char* SourceString(int source)

-{

-    switch (source) {

-    case 0:  return "Unknown";

-    case 1:  return "ESSL";

-    case 2:  return "GLSL";

-    case 3:  return "OpenCL";

-

-    case SourceLanguageCeiling:

-    default: return "Bad";

-    }

-}

-

-const int ExecutionModelCeiling = 7;

-

-const char* ExecutionModelString(int model)

-{

-    switch (model) {

-    case 0:  return "Vertex";

-    case 1:  return "TessellationControl";

-    case 2:  return "TessellationEvaluation";

-    case 3:  return "Geometry";

-    case 4:  return "Fragment";

-    case 5:  return "GLCompute";

-    case 6:  return "Kernel";

-

-    case ExecutionModelCeiling:

-    default: return "Bad";

-    }

-}

-

-const int AddressingModelCeiling = 3;

-

-const char* AddressingString(int addr)

-{

-    switch (addr) {

-    case 0:  return "Logical";

-    case 1:  return "Physical32";

-    case 2:  return "Physical64";

-

-    case AddressingModelCeiling:

-    default: return "Bad";

-    }

-}

-

-const int MemoryModelCeiling = 5;

-

-const char* MemoryString(int mem)

-{

-    switch (mem) {

-    case 0:  return "Simple";

-    case 1:  return "GLSL450";

-    case 2:  return "OpenCL1.2";

-    case 3:  return "OpenCL2.0";

-    case 4:  return "OpenCL2.1";

-

-    case MemoryModelCeiling:

-    default: return "Bad";

-    }

-}

-

-const int ExecutionModeCeiling = 31;

-

-const char* ExecutionModeString(int mode)

-{

-    switch (mode) {

-    case 0:  return "Invocations";

-    case 1:  return "SpacingEqual";

-    case 2:  return "SpacingFractionalEven";

-    case 3:  return "SpacingFractionalOdd";

-    case 4:  return "VertexOrderCw";

-    case 5:  return "VertexOrderCcw";

-    case 6:  return "PixelCenterInteger";

-    case 7:  return "OriginUpperLeft";

-    case 8:  return "EarlyFragmentTests";

-    case 9:  return "PointMode";

-    case 10: return "Xfb";

-    case 11: return "DepthReplacing";

-    case 12: return "DepthAny";

-    case 13: return "DepthGreater";

-    case 14: return "DepthLess";

-    case 15: return "DepthUnchanged";

-    case 16: return "LocalSize";

-    case 17: return "LocalSizeHint";

-    case 18: return "InputPoints";

-    case 19: return "InputLines";

-    case 20: return "InputLinesAdjacency";

-    case 21: return "InputTriangles";

-    case 22: return "InputTrianglesAdjacency";

-    case 23: return "InputQuads";

-    case 24: return "InputIsolines";

-    case 25: return "OutputVertices";

-    case 26: return "OutputPoints";

-    case 27: return "OutputLineStrip";

-    case 28: return "OutputTriangleStrip";

-    case 29: return "VecTypeHint";

-    case 30: return "ContractionOff";

-

-    case ExecutionModeCeiling:

-    default: return "Bad";

-    }

-}

-

-const int StorageClassCeiling = 11;

-

-const char* StorageClassString(int StorageClass)

-{

-    switch (StorageClass) {

-    case 0:  return "UniformConstant";

-    case 1:  return "Input";

-    case 2:  return "Uniform";

-    case 3:  return "Output";

-    case 4:  return "WorkgroupLocal";

-    case 5:  return "WorkgroupGlobal";

-    case 6:  return "PrivateGlobal";

-    case 7:  return "Function";

-    case 8:  return "Generic";

-    case 9:  return "Private";

-    case 10: return "AtomicCounter";

-

-    case StorageClassCeiling:

-    default: return "Bad";

-    }

-}

-

-const int DecorationCeiling = 45;

-

-const char* DecorationString(int decoration)

-{

-    switch (decoration) {

-    case 0:  return "PrecisionLow";

-    case 1:  return "PrecisionMedium";

-    case 2:  return "PrecisionHigh";

-    case 3:  return "Block";

-    case 4:  return "BufferBlock";

-    case 5:  return "RowMajor";

-    case 6:  return "ColMajor";

-    case 7:  return "GLSLShared";

-    case 8:  return "GLSLStd140";

-    case 9:  return "GLSLStd430";

-    case 10: return "GLSLPacked";

-    case 11: return "Smooth";

-    case 12: return "Noperspective";

-    case 13: return "Flat";

-    case 14: return "Patch";

-    case 15: return "Centroid";

-    case 16: return "Sample";

-    case 17: return "Invariant";

-    case 18: return "Restrict";

-    case 19: return "Aliased";

-    case 20: return "Volatile";

-    case 21: return "Constant";

-    case 22: return "Coherent";

-    case 23: return "Nonwritable";

-    case 24: return "Nonreadable";

-    case 25: return "Uniform";

-    case 26: return "NoStaticUse";

-    case 27: return "CPacked";

-    case 28: return "SaturatedConversion";

-    case 29: return "Stream";

-    case 30: return "Location";

-    case 31: return "Component";

-    case 32: return "Index";

-    case 33: return "Binding";

-    case 34: return "DescriptorSet";

-    case 35: return "Offset";

-    case 36: return "Alignment";

-    case 37: return "XfbBuffer";

-    case 38: return "Stride";

-    case 39: return "BuiltIn";

-    case 40: return "FuncParamAttr";

-    case 41: return "FP Rounding Mode";

-    case 42: return "FP Fast Math Mode";

-    case 43: return "Linkage Attributes";

-    case 44: return "SpecId";

-

-    case DecorationCeiling:

-    default:  return "Bad";

-    }

-}

-

-const int BuiltInCeiling = 42;

-

-const char* BuiltInString(int builtIn)

-{

-    switch (builtIn) {

-    case 0:  return "Position";

-    case 1:  return "PointSize";

-    case 2:  return "ClipVertex";

-    case 3:  return "ClipDistance";

-    case 4:  return "CullDistance";

-    case 5:  return "VertexId";

-    case 6:  return "InstanceId";

-    case 7:  return "PrimitiveId";

-    case 8:  return "InvocationId";

-    case 9:  return "Layer";

-    case 10: return "ViewportIndex";

-    case 11: return "TessLevelOuter";

-    case 12: return "TessLevelInner";

-    case 13: return "TessCoord";

-    case 14: return "PatchVertices";

-    case 15: return "FragCoord";

-    case 16: return "PointCoord";

-    case 17: return "FrontFacing";

-    case 18: return "SampleId";

-    case 19: return "SamplePosition";

-    case 20: return "SampleMask";

-    case 21: return "FragColor";

-    case 22: return "FragDepth";

-    case 23: return "HelperInvocation";

-    case 24: return "NumWorkgroups";

-    case 25: return "WorkgroupSize";

-    case 26: return "WorkgroupId";

-    case 27: return "LocalInvocationId";

-    case 28: return "GlobalInvocationId";

-    case 29: return "LocalInvocationIndex";

-    case 30: return "WorkDim";

-    case 31: return "GlobalSize";

-    case 32: return "EnqueuedWorkgroupSize";

-    case 33: return "GlobalOffset";

-    case 34: return "GlobalLinearId";

-    case 35: return "WorkgroupLinearId";

-    case 36: return "SubgroupSize";

-    case 37: return "SubgroupMaxSize";

-    case 38: return "NumSubgroups";

-    case 39: return "NumEnqueuedSubgroups";

-    case 40: return "SubgroupId";

-    case 41: return "SubgroupLocalInvocationId";

-

-    case BuiltInCeiling:

-    default: return "Bad";

-    }

-}

-

-const int DimensionCeiling = 6;

-

-const char* DimensionString(int dim)

-{

-    switch (dim) {

-    case 0:  return "1D";

-    case 1:  return "2D";

-    case 2:  return "3D";

-    case 3:  return "Cube";

-    case 4:  return "Rect";

-    case 5:  return "Buffer";

-

-    case DimensionCeiling:

-    default: return "Bad";

-    }

-}

-

-const int SamplerAddressingModeCeiling = 5;

-

-const char* SamplerAddressingModeString(int mode)

-{

-    switch (mode) {

-    case 0:  return "None";

-    case 1:  return "ClampToEdge";

-    case 2:  return "Clamp";

-    case 3:  return "Repeat";

-    case 4:  return "RepeatMirrored";

-

-    case SamplerAddressingModeCeiling:

-    default: return "Bad";

-    }

-}

-

-const int SamplerFilterModeCeiling = 2;

-

-const char* SamplerFilterModeString(int mode)

-{

-    switch (mode) {

-    case 0: return "Nearest";

-    case 1: return "Linear";

-

-    case SamplerFilterModeCeiling:

-    default: return "Bad";

-    }

-}

-

-const int FPFastMathCeiling = 5;

-

-const char* FPFastMathString(int mode)

-{

-    switch (mode) {

-    case 0: return "NotNaN";

-    case 1: return "NotInf";

-    case 2: return "NSZ";

-    case 3: return "AllowRecip";

-    case 4: return "Fast";

-

-    case FPFastMathCeiling:

-    default:     return "Bad";

-    }

-}

-

-const int FPRoundingModeCeiling = 4;

-

-const char* FPRoundingModeString(int mode)

-{

-    switch (mode) {

-    case 0:  return "RTE";

-    case 1:  return "RTZ";

-    case 2:  return "RTP";

-    case 3:  return "RTN";

-

-    case FPRoundingModeCeiling:

-    default: return "Bad";

-    }

-}

-

-const int LinkageTypeCeiling = 2;

-

-const char* LinkageTypeString(int type)

-{

-    switch (type) {

-    case 0:  return "Export";

-    case 1:  return "Import";

-

-    case LinkageTypeCeiling:

-    default: return "Bad";

-    }

-}

-

-const int FuncParamAttrCeiling = 9;

-

-const char* FuncParamAttrString(int attr)

-{

-    switch (attr) {

-    case 0:  return "Zext";

-    case 1:  return "Sext";

-    case 2:  return "ByVal";

-    case 3:  return "Sret";

-    case 4:  return "NoAlias";

-    case 5:  return "NoCapture";

-    case 6:  return "SVM";

-    case 7:  return "NoWrite";

-    case 8:  return "NoReadWrite";

-

-    case FuncParamAttrCeiling:

-    default: return "Bad";

-    }

-}

-

-const int AccessQualifierCeiling = 3;

-

-const char* AccessQualifierString(int attr)

-{

-    switch (attr) {

-    case 0:  return "ReadOnly";

-    case 1:  return "WriteOnly";

-    case 2:  return "ReadWrite";

-

-    case AccessQualifierCeiling:

-    default: return "Bad";

-    }

-}

-

-const int SelectControlCeiling = 2;

-

-const char* SelectControlString(int cont)

-{

-    switch (cont) {

-    case 0:  return "Flatten";

-    case 1:  return "DontFlatten";

-

-    case SelectControlCeiling:

-    default:                       return "Bad";

-    }

-}

-

-const int LoopControlCeiling = 2;

-

-const char* LoopControlString(int cont)

-{

-    switch (cont) {

-    case 0: return "Unroll";

-    case 1: return "DontUnroll";

-

-    case LoopControlCeiling:

-    default:     return "Bad";

-    }

-}

-

-const int FunctionControlCeiling = 4;

-

-const char* FunctionControlString(int cont)

-{

-    switch (cont) {

-    case 0:  return "Inline";

-    case 1:  return "DontInline";

-    case 2:  return "Pure";

-    case 3:  return "Const";

-

-    case FunctionControlCeiling:

-    default: return "Bad";

-    }

-}

-

-const int MemorySemanticsCeiling = 10;

-

-const char* MemorySemanticsString(int mem)

-{

-    switch (mem) {

-    case 0: return "Relaxed";

-    case 1: return "SequentiallyConsistent";

-    case 2: return "Acquire";

-    case 3: return "Release";

-

-    case 4: return "UniformMemory";

-    case 5: return "SubgroupMemory";

-    case 6: return "WorkgroupLocalMemory";

-    case 7: return "WorkgroupGlobalMemory";

-    case 8: return "AtomicCounterMemory";

-    case 9: return "ImageMemory";

-

-    case MemorySemanticsCeiling:

-    default:     return "Bad";

-    }

-}

-

-const int MemoryAccessCeiling = 2;

-

-const char* MemoryAccessString(int mem)

-{

-    switch (mem) {

-    case 0:  return "Volatile";

-    case 1:  return "Aligned";

-

-    case MemoryAccessCeiling:

-    default: return "Bad";

-    }

-}

-

-const int ExecutionScopeCeiling = 4;

-

-const char* ExecutionScopeString(int mem)

-{

-    switch (mem) {

-    case 0:  return "CrossDevice";

-    case 1:  return "Device";

-    case 2:  return "Workgroup";

-    case 3:  return "Subgroup";

-

-    case ExecutionScopeCeiling:

-    default: return "Bad";

-    }

-}

-

-const int GroupOperationCeiling = 3;

-

-const char* GroupOperationString(int gop)

-{

-

-    switch (gop)

-    {

-    case 0:  return "Reduce";

-    case 1:  return "InclusiveScan";

-    case 2:  return "ExclusiveScan";

-

-    case GroupOperationCeiling:

-    default: return "Bad";

-    }

-}

-

-const int KernelEnqueueFlagsCeiling = 3;

-

-const char* KernelEnqueueFlagsString(int flag)

-{

-    switch (flag)

-    {

-    case 0:  return "NoWait";

-    case 1:  return "WaitKernel";

-    case 2:  return "WaitWorkGroup";

-

-    case KernelEnqueueFlagsCeiling:

-    default: return "Bad";

-    }

-}

-

-const int KernelProfilingInfoCeiling = 1;

-

-const char* KernelProfilingInfoString(int info)

-{

-    switch (info)

-    {

-    case 0:  return "CmdExecTime";

-

-    case KernelProfilingInfoCeiling:

-    default: return "Bad";

-    }

-}

-

-const char* OpcodeString(int op)

-{

-    switch (op) {

-    case 0:   return "OpNop";

-    case 1:   return "OpSource";

-    case 2:   return "OpSourceExtension";

-    case 3:   return "OpExtension";

-    case 4:   return "OpExtInstImport";

-    case 5:   return "OpMemoryModel";

-    case 6:   return "OpEntryPoint";

-    case 7:   return "OpExecutionMode";

-    case 8:   return "OpTypeVoid";

-    case 9:   return "OpTypeBool";

-    case 10:  return "OpTypeInt";

-    case 11:  return "OpTypeFloat";

-    case 12:  return "OpTypeVector";

-    case 13:  return "OpTypeMatrix";

-    case 14:  return "OpTypeSampler";

-    case 15:  return "OpTypeFilter";

-    case 16:  return "OpTypeArray";

-    case 17:  return "OpTypeRuntimeArray";

-    case 18:  return "OpTypeStruct";

-    case 19:  return "OpTypeOpaque";

-    case 20:  return "OpTypePointer";

-    case 21:  return "OpTypeFunction";

-    case 22:  return "OpTypeEvent";

-    case 23:  return "OpTypeDeviceEvent";

-    case 24:  return "OpTypeReserveId";

-    case 25:  return "OpTypeQueue";

-    case 26:  return "OpTypePipe";

-    case 27:  return "OpConstantTrue";

-    case 28:  return "OpConstantFalse";

-    case 29:  return "OpConstant";

-    case 30:  return "OpConstantComposite";

-    case 31:  return "OpConstantSampler";

-    case 32:  return "OpConstantNullPointer";

-    case 33:  return "OpConstantNullObject";

-    case 34:  return "OpSpecConstantTrue";

-    case 35:  return "OpSpecConstantFalse";

-    case 36:  return "OpSpecConstant";

-    case 37:  return "OpSpecConstantComposite";

-    case 38:  return "OpVariable";

-    case 39:  return "OpVariableArray";

-    case 40:  return "OpFunction";

-    case 41:  return "OpFunctionParameter";

-    case 42:  return "OpFunctionEnd";

-    case 43:  return "OpFunctionCall";

-    case 44:  return "OpExtInst";

-    case 45:  return "OpUndef";

-    case 46:  return "OpLoad";

-    case 47:  return "OpStore";

-    case 48:  return "OpPhi";

-    case 49:  return "OpDecorationGroup";

-    case 50:  return "OpDecorate";

-    case 51:  return "OpMemberDecorate";

-    case 52:  return "OpGroupDecorate";

-    case 53:  return "OpGroupMemberDecorate";

-    case 54:  return "OpName";

-    case 55:  return "OpMemberName";

-    case 56:  return "OpString";

-    case 57:  return "OpLine";

-    case 58:  return "OpVectorExtractDynamic";

-    case 59:  return "OpVectorInsertDynamic";

-    case 60:  return "OpVectorShuffle";

-    case 61:  return "OpCompositeConstruct";

-    case 62:  return "OpCompositeExtract";

-    case 63:  return "OpCompositeInsert";

-    case 64:  return "OpCopyObject";

-    case 65:  return "OpCopyMemory";

-    case 66:  return "OpCopyMemorySized";

-    case 67:  return "OpSampler";

-    case 68:  return "OpTextureSample";

-    case 69:  return "OpTextureSampleDref";

-    case 70:  return "OpTextureSampleLod";

-    case 71:  return "OpTextureSampleProj";

-    case 72:  return "OpTextureSampleGrad";

-    case 73:  return "OpTextureSampleOffset";

-    case 74:  return "OpTextureSampleProjLod";

-    case 75:  return "OpTextureSampleProjGrad";

-    case 76:  return "OpTextureSampleLodOffset";

-    case 77:  return "OpTextureSampleProjOffset";

-    case 78:  return "OpTextureSampleGradOffset";

-    case 79:  return "OpTextureSampleProjLodOffset";

-    case 80:  return "OpTextureSampleProjGradOffset";

-    case 81:  return "OpTextureFetchTexelLod";

-    case 82:  return "OpTextureFetchTexelOffset";

-    case 83:  return "OpTextureFetchSample";

-    case 84:  return "OpTextureFetchTexel";

-    case 85:  return "OpTextureGather";

-    case 86:  return "OpTextureGatherOffset";

-    case 87:  return "OpTextureGatherOffsets";

-    case 88:  return "OpTextureQuerySizeLod";

-    case 89:  return "OpTextureQuerySize";

-    case 90:  return "OpTextureQueryLod";

-    case 91:  return "OpTextureQueryLevels";

-    case 92:  return "OpTextureQuerySamples";

-    case 93:  return "OpAccessChain";

-    case 94:  return "OpInBoundsAccessChain";

-    case 95:  return "OpSNegate";

-    case 96:  return "OpFNegate";

-    case 97:  return "OpNot";

-    case 98:  return "OpAny";

-    case 99:  return "OpAll";

-    case 100: return "OpConvertFToU";

-    case 101: return "OpConvertFToS";

-    case 102: return "OpConvertSToF";

-    case 103: return "OpConvertUToF";

-    case 104: return "OpUConvert";

-    case 105: return "OpSConvert";

-    case 106: return "OpFConvert";

-    case 107: return "OpConvertPtrToU";

-    case 108: return "OpConvertUToPtr";

-    case 109: return "OpPtrCastToGeneric";

-    case 110: return "OpGenericCastToPtr";

-    case 111: return "OpBitcast";

-    case 112: return "OpTranspose";

-    case 113: return "OpIsNan";

-    case 114: return "OpIsInf";

-    case 115: return "OpIsFinite";

-    case 116: return "OpIsNormal";

-    case 117: return "OpSignBitSet";

-    case 118: return "OpLessOrGreater";

-    case 119: return "OpOrdered";

-    case 120: return "OpUnordered";

-    case 121: return "OpArrayLength";

-    case 122: return "OpIAdd";

-    case 123: return "OpFAdd";

-    case 124: return "OpISub";

-    case 125: return "OpFSub";

-    case 126: return "OpIMul";

-    case 127: return "OpFMul";

-    case 128: return "OpUDiv";

-    case 129: return "OpSDiv";

-    case 130: return "OpFDiv";

-    case 131: return "OpUMod";

-    case 132: return "OpSRem";

-    case 133: return "OpSMod";

-    case 134: return "OpFRem";

-    case 135: return "OpFMod";

-    case 136: return "OpVectorTimesScalar";

-    case 137: return "OpMatrixTimesScalar";

-    case 138: return "OpVectorTimesMatrix";

-    case 139: return "OpMatrixTimesVector";

-    case 140: return "OpMatrixTimesMatrix";

-    case 141: return "OpOuterProduct";

-    case 142: return "OpDot";

-    case 143: return "OpShiftRightLogical";

-    case 144: return "OpShiftRightArithmetic";

-    case 145: return "OpShiftLeftLogical";

-    case 146: return "OpLogicalOr";

-    case 147: return "OpLogicalXor";

-    case 148: return "OpLogicalAnd";

-    case 149: return "OpBitwiseOr";

-    case 150: return "OpBitwiseXor";

-    case 151: return "OpBitwiseAnd";

-    case 152: return "OpSelect";

-    case 153: return "OpIEqual";

-    case 154: return "OpFOrdEqual";

-    case 155: return "OpFUnordEqual";

-    case 156: return "OpINotEqual";

-    case 157: return "OpFOrdNotEqual";

-    case 158: return "OpFUnordNotEqual";

-    case 159: return "OpULessThan";

-    case 160: return "OpSLessThan";

-    case 161: return "OpFOrdLessThan";

-    case 162: return "OpFUnordLessThan";

-    case 163: return "OpUGreaterThan";

-    case 164: return "OpSGreaterThan";

-    case 165: return "OpFOrdGreaterThan";

-    case 166: return "OpFUnordGreaterThan";

-    case 167: return "OpULessThanEqual";

-    case 168: return "OpSLessThanEqual";

-    case 169: return "OpFOrdLessThanEqual";

-    case 170: return "OpFUnordLessThanEqual";

-    case 171: return "OpUGreaterThanEqual";

-    case 172: return "OpSGreaterThanEqual";

-    case 173: return "OpFOrdGreaterThanEqual";

-    case 174: return "OpFUnordGreaterThanEqual";

-    case 175: return "OpDPdx";

-    case 176: return "OpDPdy";

-    case 177: return "OpFwidth";

-    case 178: return "OpDPdxFine";

-    case 179: return "OpDPdyFine";

-    case 180: return "OpFwidthFine";

-    case 181: return "OpDPdxCoarse";

-    case 182: return "OpDPdyCoarse";

-    case 183: return "OpFwidthCoarse";

-    case 184: return "OpEmitVertex";

-    case 185: return "OpEndPrimitive";

-    case 186: return "OpEmitStreamVertex";

-    case 187: return "OpEndStreamPrimitive";

-    case 188: return "OpControlBarrier";

-    case 189: return "OpMemoryBarrier";

-    case 190: return "OpImagePointer";

-    case 191: return "OpAtomicInit";

-    case 192: return "OpAtomicLoad";

-    case 193: return "OpAtomicStore";

-    case 194: return "OpAtomicExchange";

-    case 195: return "OpAtomicCompareExchange";

-    case 196: return "OpAtomicCompareExchangeWeak";

-    case 197: return "OpAtomicIIncrement";

-    case 198: return "OpAtomicIDecrement";

-    case 199: return "OpAtomicIAdd";

-    case 200: return "OpAtomicISub";

-    case 201: return "OpAtomicUMin";

-    case 202: return "OpAtomicUMax";

-    case 203: return "OpAtomicAnd";

-    case 204: return "OpAtomicOr";

-    case 205: return "OpAtomicXor";

-    case 206: return "OpLoopMerge";

-    case 207: return "OpSelectionMerge";

-    case 208: return "OpLabel";

-    case 209: return "OpBranch";

-    case 210: return "OpBranchConditional";

-    case 211: return "OpSwitch";

-    case 212: return "OpKill";

-    case 213: return "OpReturn";

-    case 214: return "OpReturnValue";

-    case 215: return "OpUnreachable";

-    case 216: return "OpLifetimeStart";

-    case 217: return "OpLifetimeStop";

-    case 218: return "OpCompileFlag";

-    case 219: return "OpAsyncGroupCopy";

-    case 220: return "OpWaitGroupEvents";

-    case 221: return "OpGroupAll";

-    case 222: return "OpGroupAny";

-    case 223: return "OpGroupBroadcast";

-    case 224: return "OpGroupIAdd";

-    case 225: return "OpGroupFAdd";

-    case 226: return "OpGroupFMin";

-    case 227: return "OpGroupUMin";

-    case 228: return "OpGroupSMin";

-    case 229: return "OpGroupFMax";

-    case 230: return "OpGroupUMax";

-    case 231: return "OpGroupSMax";

-    case 232: return "OpGenericCastToPtrExplicit";

-    case 233: return "OpGenericPtrMemSemantics";

-    case 234: return "OpReadPipe";

-    case 235: return "OpWritePipe";

-    case 236: return "OpReservedReadPipe";

-    case 237: return "OpReservedWritePipe";

-    case 238: return "OpReserveReadPipePackets";

-    case 239: return "OpReserveWritePipePackets";

-    case 240: return "OpCommitReadPipe";

-    case 241: return "OpCommitWritePipe";

-    case 242: return "OpIsValidReserveId";

-    case 243: return "OpGetNumPipePackets";

-    case 244: return "OpGetMaxPipePackets";

-    case 245: return "OpGroupReserveReadPipePackets";

-    case 246: return "OpGroupReserveWritePipePackets";

-    case 247: return "OpGroupCommitReadPipe";

-    case 248: return "OpGroupCommitWritePipe";

-    case 249: return "OpEnqueueMarker";

-    case 250: return "OpEnqueueKernel";

-    case 251: return "OpGetKernelNDrangeSubGroupCount";

-    case 252: return "OpGetKernelNDrangeMaxSubGroupSize";

-    case 253: return "OpGetKernelWorkGroupSize";

-    case 254: return "OpGetKernelPreferredWorkGroupSizeMultiple";

-    case 255: return "OpRetainEvent";

-    case 256: return "OpReleaseEvent";

-    case 257: return "OpCreateUserEvent";

-    case 258: return "OpIsValidEvent";

-    case 259: return "OpSetUserEventStatus";

-    case 260: return "OpCaptureEventProfilingInfo";

-    case 261: return "OpGetDefaultQueue";

-    case 262: return "OpBuildNDRange";

-    case 263: return "OpSatConvertSToU";

-    case 264: return "OpSatConvertUToS";

-    case 265: return "OpAtomicIMin";

-    case 266: return "OpAtomicIMax";

-

-    case OpcodeCeiling:

-    default:

-        return "Bad";

-    }

-}

-

-// The set of objects that hold all the instruction/operand

-// parameterization information.

-InstructionParameters InstructionDesc[OpcodeCeiling];

-OperandParameters ExecutionModeOperands[ExecutionModeCeiling];

-OperandParameters DecorationOperands[DecorationCeiling];

-

-EnumDefinition OperandClassParams[OperandCount];

-EnumParameters ExecutionModelParams[ExecutionModelCeiling];

-EnumParameters AddressingParams[AddressingModelCeiling];

-EnumParameters MemoryParams[MemoryModelCeiling];

-EnumParameters ExecutionModeParams[ExecutionModeCeiling];

-EnumParameters StorageParams[StorageClassCeiling];

-EnumParameters SamplerAddressingModeParams[SamplerAddressingModeCeiling];

-EnumParameters SamplerFilterModeParams[SamplerFilterModeCeiling];

-EnumParameters FPFastMathParams[FPFastMathCeiling];

-EnumParameters FPRoundingModeParams[FPRoundingModeCeiling];

-EnumParameters LinkageTypeParams[LinkageTypeCeiling];

-EnumParameters DecorationParams[DecorationCeiling];

-EnumParameters BuiltInParams[BuiltInCeiling];

-EnumParameters DimensionalityParams[DimensionCeiling];

-EnumParameters FuncParamAttrParams[FuncParamAttrCeiling];

-EnumParameters AccessQualifierParams[AccessQualifierCeiling];

-EnumParameters GroupOperationParams[GroupOperationCeiling];

-EnumParameters LoopControlParams[FunctionControlCeiling];

-EnumParameters SelectionControlParams[SelectControlCeiling];

-EnumParameters FunctionControlParams[FunctionControlCeiling];

-EnumParameters MemorySemanticsParams[MemorySemanticsCeiling];

-EnumParameters MemoryAccessParams[MemoryAccessCeiling];

-EnumParameters ExecutionScopeParams[ExecutionScopeCeiling];

-EnumParameters KernelEnqueueFlagsParams[KernelEnqueueFlagsCeiling];

-EnumParameters KernelProfilingInfoParams[KernelProfilingInfoCeiling];

-

-// Set up all the parameterizing descriptions of the opcodes, operands, etc.

-void Parameterize()

-{

-    static bool initialized = false;

-

-    // only do this once.

-    if (initialized)

-        return;

-

-    initialized = true;

-

-    // Exceptions to having a result <id> and a resulting type <id>.

-    // (Everything is initialized to have both).

-

-    InstructionDesc[OpNop].setResultAndType(false, false);

-    InstructionDesc[OpSource].setResultAndType(false, false);

-    InstructionDesc[OpSourceExtension].setResultAndType(false, false);

-    InstructionDesc[OpExtension].setResultAndType(false, false);

-    InstructionDesc[OpExtInstImport].setResultAndType(true, false);

-    InstructionDesc[OpMemoryModel].setResultAndType(false, false);

-    InstructionDesc[OpEntryPoint].setResultAndType(false, false);

-    InstructionDesc[OpExecutionMode].setResultAndType(false, false);

-    InstructionDesc[OpTypeVoid].setResultAndType(true, false);

-    InstructionDesc[OpTypeBool].setResultAndType(true, false);

-    InstructionDesc[OpTypeInt].setResultAndType(true, false);

-    InstructionDesc[OpTypeFloat].setResultAndType(true, false);

-    InstructionDesc[OpTypeVector].setResultAndType(true, false);

-    InstructionDesc[OpTypeMatrix].setResultAndType(true, false);

-    InstructionDesc[OpTypeSampler].setResultAndType(true, false);

-    InstructionDesc[OpTypeFilter].setResultAndType(true, false);

-    InstructionDesc[OpTypeArray].setResultAndType(true, false);

-    InstructionDesc[OpTypeRuntimeArray].setResultAndType(true, false);

-    InstructionDesc[OpTypeStruct].setResultAndType(true, false);

-    InstructionDesc[OpTypeOpaque].setResultAndType(true, false);

-    InstructionDesc[OpTypePointer].setResultAndType(true, false);

-    InstructionDesc[OpTypeFunction].setResultAndType(true, false);

-    InstructionDesc[OpTypeEvent].setResultAndType(true, false);

-    InstructionDesc[OpTypeDeviceEvent].setResultAndType(true, false);

-    InstructionDesc[OpTypeReserveId].setResultAndType(true, false);

-    InstructionDesc[OpTypeQueue].setResultAndType(true, false);

-    InstructionDesc[OpTypePipe].setResultAndType(true, false);

-    InstructionDesc[OpFunctionEnd].setResultAndType(false, false);

-    InstructionDesc[OpStore].setResultAndType(false, false);

-    InstructionDesc[OpDecorationGroup].setResultAndType(true, false);

-    InstructionDesc[OpDecorate].setResultAndType(false, false);

-    InstructionDesc[OpMemberDecorate].setResultAndType(false, false);

-    InstructionDesc[OpGroupDecorate].setResultAndType(false, false);

-    InstructionDesc[OpGroupMemberDecorate].setResultAndType(false, false);

-    InstructionDesc[OpName].setResultAndType(false, false);

-    InstructionDesc[OpMemberName].setResultAndType(false, false);

-    InstructionDesc[OpString].setResultAndType(true, false);

-    InstructionDesc[OpLine].setResultAndType(false, false);

-    InstructionDesc[OpCopyMemory].setResultAndType(false, false);

-    InstructionDesc[OpCopyMemorySized].setResultAndType(false, false);

-    InstructionDesc[OpEmitVertex].setResultAndType(false, false);

-    InstructionDesc[OpEndPrimitive].setResultAndType(false, false);

-    InstructionDesc[OpEmitStreamVertex].setResultAndType(false, false);

-    InstructionDesc[OpEndStreamPrimitive].setResultAndType(false, false);

-    InstructionDesc[OpControlBarrier].setResultAndType(false, false);

-    InstructionDesc[OpMemoryBarrier].setResultAndType(false, false);

-    InstructionDesc[OpAtomicInit].setResultAndType(false, false);

-    InstructionDesc[OpAtomicStore].setResultAndType(false, false);

-    InstructionDesc[OpLoopMerge].setResultAndType(false, false);

-    InstructionDesc[OpSelectionMerge].setResultAndType(false, false);

-    InstructionDesc[OpLabel].setResultAndType(true, false);

-    InstructionDesc[OpBranch].setResultAndType(false, false);

-    InstructionDesc[OpBranchConditional].setResultAndType(false, false);

-    InstructionDesc[OpSwitch].setResultAndType(false, false);

-    InstructionDesc[OpKill].setResultAndType(false, false);

-    InstructionDesc[OpReturn].setResultAndType(false, false);

-    InstructionDesc[OpReturnValue].setResultAndType(false, false);

-    InstructionDesc[OpUnreachable].setResultAndType(false, false);

-    InstructionDesc[OpLifetimeStart].setResultAndType(false, false);

-    InstructionDesc[OpLifetimeStop].setResultAndType(false, false);

-    InstructionDesc[OpCompileFlag].setResultAndType(false, false);

-    InstructionDesc[OpCommitReadPipe].setResultAndType(false, false);

-    InstructionDesc[OpCommitWritePipe].setResultAndType(false, false);

-    InstructionDesc[OpGroupCommitWritePipe].setResultAndType(false, false);

-    InstructionDesc[OpGroupCommitReadPipe].setResultAndType(false, false);

-    InstructionDesc[OpCaptureEventProfilingInfo].setResultAndType(false, false);

-    InstructionDesc[OpSetUserEventStatus].setResultAndType(false, false);

-    InstructionDesc[OpRetainEvent].setResultAndType(false, false);

-    InstructionDesc[OpReleaseEvent].setResultAndType(false, false);

-

-    // Specific additional context-dependent operands

-

-    ExecutionModeOperands[ExecutionModeInvocations].push(OperandLiteralNumber, "Number of invocations");

-

-    ExecutionModeOperands[ExecutionModeLocalSize].push(OperandLiteralNumber, "'x size'");

-    ExecutionModeOperands[ExecutionModeLocalSize].push(OperandLiteralNumber, "'y size'");

-    ExecutionModeOperands[ExecutionModeLocalSize].push(OperandLiteralNumber, "'z size'");

-

-    ExecutionModeOperands[ExecutionModeLocalSizeHint].push(OperandLiteralNumber, "'x size'");

-    ExecutionModeOperands[ExecutionModeLocalSizeHint].push(OperandLiteralNumber, "'y size'");

-    ExecutionModeOperands[ExecutionModeLocalSizeHint].push(OperandLiteralNumber, "'z size'");

-

-    ExecutionModeOperands[ExecutionModeOutputVertices].push(OperandLiteralNumber, "Vertex count");

-    ExecutionModeOperands[ExecutionModeVecTypeHint].push(OperandId, "Vector type");

-

-    DecorationOperands[DecorationStream].push(OperandLiteralNumber, "Stream number");

-    DecorationOperands[DecorationLocation].push(OperandLiteralNumber, "Location");

-    DecorationOperands[DecorationComponent].push(OperandLiteralNumber, "Component within a vector");

-    DecorationOperands[DecorationIndex].push(OperandLiteralNumber, "Index");

-    DecorationOperands[DecorationBinding].push(OperandLiteralNumber, "Binding point");

-    DecorationOperands[DecorationDescriptorSet].push(OperandLiteralNumber, "Descriptor set");

-    DecorationOperands[DecorationOffset].push(OperandLiteralNumber, "Byte offset");

-    DecorationOperands[DecorationAlignment].push(OperandLiteralNumber, "Declared alignment");

-    DecorationOperands[DecorationXfbBuffer].push(OperandLiteralNumber, "XFB Buffer number");

-    DecorationOperands[DecorationStride].push(OperandLiteralNumber, "Stride");

-    DecorationOperands[DecorationBuiltIn].push(OperandLiteralNumber, "See <<BuiltIn,*BuiltIn*>>");

-    DecorationOperands[DecorationFPRoundingMode].push(OperandFPRoundingMode, "floating-point rounding mode");

-    DecorationOperands[DecorationFPFastMathMode].push(OperandFPFastMath, "fast-math mode");

-    DecorationOperands[DecorationLinkageAttributes].push(OperandLiteralString, "name");

-    DecorationOperands[DecorationLinkageAttributes].push(OperandLinkageType, "linkage type");

-    DecorationOperands[DecorationFuncParamAttr].push(OperandFuncParamAttr, "function parameter attribute");

-    DecorationOperands[DecorationSpecId].push(OperandLiteralNumber, "Specialization Constant ID");

-

-    OperandClassParams[OperandSource].set(SourceLanguageCeiling, SourceString, 0);

-    OperandClassParams[OperandExecutionModel].set(ExecutionModelCeiling, ExecutionModelString, ExecutionModelParams);

-    OperandClassParams[OperandAddressing].set(AddressingModelCeiling, AddressingString, AddressingParams);

-    OperandClassParams[OperandMemory].set(MemoryModelCeiling, MemoryString, MemoryParams);

-    OperandClassParams[OperandExecutionMode].set(ExecutionModeCeiling, ExecutionModeString, ExecutionModeParams);

-    OperandClassParams[OperandExecutionMode].setOperands(ExecutionModeOperands);

-    OperandClassParams[OperandStorage].set(StorageClassCeiling, StorageClassString, StorageParams);

-    OperandClassParams[OperandDimensionality].set(DimensionCeiling, DimensionString, DimensionalityParams);

-    OperandClassParams[OperandSamplerAddressingMode].set(SamplerAddressingModeCeiling, SamplerAddressingModeString, SamplerAddressingModeParams);

-    OperandClassParams[OperandSamplerFilterMode].set(SamplerFilterModeCeiling, SamplerFilterModeString, SamplerFilterModeParams);

-    OperandClassParams[OperandFPFastMath].set(FPFastMathCeiling, FPFastMathString, FPFastMathParams, true);

-    OperandClassParams[OperandFPRoundingMode].set(FPRoundingModeCeiling, FPRoundingModeString, FPRoundingModeParams);

-    OperandClassParams[OperandLinkageType].set(LinkageTypeCeiling, LinkageTypeString, LinkageTypeParams);

-    OperandClassParams[OperandFuncParamAttr].set(FuncParamAttrCeiling, FuncParamAttrString, FuncParamAttrParams);

-    OperandClassParams[OperandAccessQualifier].set(AccessQualifierCeiling, AccessQualifierString, AccessQualifierParams);

-    OperandClassParams[OperandDecoration].set(DecorationCeiling, DecorationString, DecorationParams);

-    OperandClassParams[OperandDecoration].setOperands(DecorationOperands);

-    OperandClassParams[OperandBuiltIn].set(BuiltInCeiling, BuiltInString, BuiltInParams);

-    OperandClassParams[OperandSelect].set(SelectControlCeiling, SelectControlString, SelectionControlParams, true);

-    OperandClassParams[OperandLoop].set(LoopControlCeiling, LoopControlString, LoopControlParams, true);

-    OperandClassParams[OperandFunction].set(FunctionControlCeiling, FunctionControlString, FunctionControlParams, true);

-    OperandClassParams[OperandMemorySemantics].set(MemorySemanticsCeiling, MemorySemanticsString, MemorySemanticsParams, true);

-    OperandClassParams[OperandMemoryAccess].set(MemoryAccessCeiling, MemoryAccessString, MemoryAccessParams, true);

-    OperandClassParams[OperandExecutionScope].set(ExecutionScopeCeiling, ExecutionScopeString, ExecutionScopeParams);

-    OperandClassParams[OperandGroupOperation].set(GroupOperationCeiling, GroupOperationString, GroupOperationParams);

-    OperandClassParams[OperandKernelEnqueueFlags].set(KernelEnqueueFlagsCeiling, KernelEnqueueFlagsString, KernelEnqueueFlagsParams);

-    OperandClassParams[OperandKernelProfilingInfo].set(KernelProfilingInfoCeiling, KernelProfilingInfoString, KernelProfilingInfoParams, true);

-    OperandClassParams[OperandOpcode].set(OpcodeCeiling, OpcodeString, 0);

-

-    AddressingParams[AddressingModelPhysical32].caps.push_back(CapAddr);

-    AddressingParams[AddressingModelPhysical64].caps.push_back(CapAddr);

-

-    MemoryParams[MemoryModelSimple].caps.push_back(CapShader);

-    MemoryParams[MemoryModelGLSL450].caps.push_back(CapShader);

-    MemoryParams[MemoryModelOpenCL12].caps.push_back(CapKernel);

-    MemoryParams[MemoryModelOpenCL20].caps.push_back(CapKernel);

-    MemoryParams[MemoryModelOpenCL21].caps.push_back(CapKernel);

-

-    ExecutionModelParams[ExecutionModelVertex].caps.push_back(CapShader);

-    ExecutionModelParams[ExecutionModelTessellationControl].caps.push_back(CapTess);

-    ExecutionModelParams[ExecutionModelTessellationEvaluation].caps.push_back(CapTess);

-    ExecutionModelParams[ExecutionModelGeometry].caps.push_back(CapGeom);

-    ExecutionModelParams[ExecutionModelFragment].caps.push_back(CapShader);

-    ExecutionModelParams[ExecutionModelGLCompute].caps.push_back(CapShader);

-    ExecutionModelParams[ExecutionModelKernel].caps.push_back(CapKernel);

-

-    // Storage capabilites

-    StorageParams[StorageClassInput].caps.push_back(CapShader);

-    StorageParams[StorageClassUniform].caps.push_back(CapShader);

-    StorageParams[StorageClassOutput].caps.push_back(CapShader);

-    StorageParams[StorageClassPrivateGlobal].caps.push_back(CapShader);

-    StorageParams[StorageClassFunction].caps.push_back(CapShader);

-    StorageParams[StorageClassGeneric].caps.push_back(CapKernel);

-    StorageParams[StorageClassPrivate].caps.push_back(CapKernel);

-    StorageParams[StorageClassAtomicCounter].caps.push_back(CapShader);

-

-    // Sampler Filter & Addressing mode capabilities

-    SamplerAddressingModeParams[SamplerAddressingModeNone].caps.push_back(CapKernel);

-    SamplerAddressingModeParams[SamplerAddressingModeClampToEdge].caps.push_back(CapKernel);

-    SamplerAddressingModeParams[SamplerAddressingModeClamp].caps.push_back(CapKernel);

-    SamplerAddressingModeParams[SamplerAddressingModeRepeat].caps.push_back(CapKernel);

-    SamplerAddressingModeParams[SamplerAddressingModeRepeatMirrored].caps.push_back(CapKernel);

-

-    SamplerFilterModeParams[SamplerFilterModeNearest].caps.push_back(CapKernel);

-    SamplerFilterModeParams[SamplerFilterModeLinear].caps.push_back(CapKernel);

-

-    // fast math flags capabilities

-    for (int i = 0; i < FPFastMathCeiling; ++i) {

-        FPFastMathParams[i].caps.push_back(CapKernel);

-    }

-

-    // fp rounding mode capabilities

-    for (int i = 0; i < FPRoundingModeCeiling; ++i) {

-        FPRoundingModeParams[i].caps.push_back(CapKernel);

-    }

-

-    // linkage types

-    for (int i = 0; i < LinkageTypeCeiling; ++i) {

-        LinkageTypeParams[i].caps.push_back(CapLink);

-    }

-

-    // function argument types

-    for (int i = 0; i < FuncParamAttrCeiling; ++i) {

-        FuncParamAttrParams[i].caps.push_back(CapKernel);

-    }

-

-    // function argument types

-    for (int i = 0; i < AccessQualifierCeiling; ++i) {

-        AccessQualifierParams[i].caps.push_back(CapKernel);

-    }

-

-    ExecutionModeParams[ExecutionModeInvocations].caps.push_back(CapGeom);

-    ExecutionModeParams[ExecutionModeSpacingEqual].caps.push_back(CapTess);

-    ExecutionModeParams[ExecutionModeSpacingFractionalEven].caps.push_back(CapTess);

-    ExecutionModeParams[ExecutionModeSpacingFractionalOdd].caps.push_back(CapTess);

-    ExecutionModeParams[ExecutionModeVertexOrderCw].caps.push_back(CapTess);

-    ExecutionModeParams[ExecutionModeVertexOrderCcw].caps.push_back(CapTess);

-    ExecutionModeParams[ExecutionModePixelCenterInteger].caps.push_back(CapShader);

-    ExecutionModeParams[ExecutionModeOriginUpperLeft].caps.push_back(CapShader);

-    ExecutionModeParams[ExecutionModeEarlyFragmentTests].caps.push_back(CapShader);

-    ExecutionModeParams[ExecutionModePointMode].caps.push_back(CapTess);

-    ExecutionModeParams[ExecutionModeXfb].caps.push_back(CapShader);

-    ExecutionModeParams[ExecutionModeDepthReplacing].caps.push_back(CapShader);

-    ExecutionModeParams[ExecutionModeDepthAny].caps.push_back(CapShader);

-    ExecutionModeParams[ExecutionModeDepthGreater].caps.push_back(CapShader);

-    ExecutionModeParams[ExecutionModeDepthLess].caps.push_back(CapShader);

-    ExecutionModeParams[ExecutionModeDepthUnchanged].caps.push_back(CapShader);

-    ExecutionModeParams[ExecutionModeLocalSizeHint].caps.push_back(CapKernel);

-    ExecutionModeParams[ExecutionModeInputPoints].caps.push_back(CapGeom);

-    ExecutionModeParams[ExecutionModeInputLines].caps.push_back(CapGeom);

-    ExecutionModeParams[ExecutionModeInputLinesAdjacency].caps.push_back(CapGeom);

-    ExecutionModeParams[ExecutionModeInputTriangles].caps.push_back(CapGeom);

-    ExecutionModeParams[ExecutionModeInputTriangles].caps.push_back(CapTess);

-    ExecutionModeParams[ExecutionModeInputTrianglesAdjacency].caps.push_back(CapGeom);

-    ExecutionModeParams[ExecutionModeInputQuads].caps.push_back(CapTess);

-    ExecutionModeParams[ExecutionModeInputIsolines].caps.push_back(CapTess);

-    ExecutionModeParams[ExecutionModeOutputVertices].caps.push_back(CapGeom);

-    ExecutionModeParams[ExecutionModeOutputVertices].caps.push_back(CapTess);

-    ExecutionModeParams[ExecutionModeOutputPoints].caps.push_back(CapGeom);

-    ExecutionModeParams[ExecutionModeOutputLineStrip].caps.push_back(CapGeom);

-    ExecutionModeParams[ExecutionModeOutputTriangleStrip].caps.push_back(CapGeom);

-    ExecutionModeParams[ExecutionModeVecTypeHint].caps.push_back(CapKernel);

-    ExecutionModeParams[ExecutionModeContractionOff].caps.push_back(CapKernel);

-

-    DecorationParams[DecorationPrecisionLow].caps.push_back(CapShader);

-    DecorationParams[DecorationPrecisionMedium].caps.push_back(CapShader);

-    DecorationParams[DecorationPrecisionHigh].caps.push_back(CapShader);

-    DecorationParams[DecorationBlock].caps.push_back(CapShader);

-    DecorationParams[DecorationBufferBlock].caps.push_back(CapShader);

-    DecorationParams[DecorationRowMajor].caps.push_back(CapMatrix);

-    DecorationParams[DecorationColMajor].caps.push_back(CapMatrix);

-    DecorationParams[DecorationGLSLShared].caps.push_back(CapShader);

-    DecorationParams[DecorationGLSLStd140].caps.push_back(CapShader);

-    DecorationParams[DecorationGLSLStd430].caps.push_back(CapShader);

-    DecorationParams[DecorationGLSLPacked].caps.push_back(CapShader);

-    DecorationParams[DecorationSmooth].caps.push_back(CapShader);

-    DecorationParams[DecorationNoperspective].caps.push_back(CapShader);

-    DecorationParams[DecorationFlat].caps.push_back(CapShader);

-    DecorationParams[DecorationPatch].caps.push_back(CapTess);

-    DecorationParams[DecorationCentroid].caps.push_back(CapShader);

-    DecorationParams[DecorationSample].caps.push_back(CapShader);

-    DecorationParams[DecorationInvariant].caps.push_back(CapShader);

-    DecorationParams[DecorationConstant].caps.push_back(CapKernel);

-    DecorationParams[DecorationUniform].caps.push_back(CapShader);

-    DecorationParams[DecorationCPacked].caps.push_back(CapKernel);

-    DecorationParams[DecorationSaturatedConversion].caps.push_back(CapKernel);

-    DecorationParams[DecorationStream].caps.push_back(CapGeom);

-    DecorationParams[DecorationLocation].caps.push_back(CapShader);

-    DecorationParams[DecorationComponent].caps.push_back(CapShader);

-    DecorationParams[DecorationIndex].caps.push_back(CapShader);

-    DecorationParams[DecorationBinding].caps.push_back(CapShader);

-    DecorationParams[DecorationDescriptorSet].caps.push_back(CapShader);

-    DecorationParams[DecorationXfbBuffer].caps.push_back(CapShader);

-    DecorationParams[DecorationStride].caps.push_back(CapShader);

-    DecorationParams[DecorationBuiltIn].caps.push_back(CapShader);

-    DecorationParams[DecorationFuncParamAttr].caps.push_back(CapKernel);

-    DecorationParams[DecorationFPRoundingMode].caps.push_back(CapKernel);

-    DecorationParams[DecorationFPFastMathMode].caps.push_back(CapKernel);

-    DecorationParams[DecorationLinkageAttributes].caps.push_back(CapLink);

-    DecorationParams[DecorationSpecId].caps.push_back(CapShader);

-

-    BuiltInParams[BuiltInPosition].caps.push_back(CapShader);

-    BuiltInParams[BuiltInPointSize].caps.push_back(CapShader);

-    BuiltInParams[BuiltInClipVertex].caps.push_back(CapShader);

-    BuiltInParams[BuiltInClipDistance].caps.push_back(CapShader);

-    BuiltInParams[BuiltInCullDistance].caps.push_back(CapShader);

-    BuiltInParams[BuiltInVertexId].caps.push_back(CapShader);

-    BuiltInParams[BuiltInInstanceId].caps.push_back(CapShader);

-    BuiltInParams[BuiltInPrimitiveId].caps.push_back(CapGeom);

-    BuiltInParams[BuiltInPrimitiveId].caps.push_back(CapTess);

-    BuiltInParams[BuiltInInvocationId].caps.push_back(CapGeom);

-    BuiltInParams[BuiltInInvocationId].caps.push_back(CapTess);

-    BuiltInParams[BuiltInLayer].caps.push_back(CapGeom);

-    BuiltInParams[BuiltInViewportIndex].caps.push_back(CapGeom);

-    BuiltInParams[BuiltInTessLevelOuter].caps.push_back(CapTess);

-    BuiltInParams[BuiltInTessLevelInner].caps.push_back(CapTess);

-    BuiltInParams[BuiltInTessCoord].caps.push_back(CapTess);

-    BuiltInParams[BuiltInPatchVertices].caps.push_back(CapTess);

-    BuiltInParams[BuiltInFragCoord].caps.push_back(CapShader);

-    BuiltInParams[BuiltInPointCoord].caps.push_back(CapShader);

-    BuiltInParams[BuiltInFrontFacing].caps.push_back(CapShader);

-    BuiltInParams[BuiltInSampleId].caps.push_back(CapShader);

-    BuiltInParams[BuiltInSamplePosition].caps.push_back(CapShader);

-    BuiltInParams[BuiltInSampleMask].caps.push_back(CapShader);

-    BuiltInParams[BuiltInFragColor].caps.push_back(CapShader);

-    BuiltInParams[BuiltInFragDepth].caps.push_back(CapShader);

-    BuiltInParams[BuiltInHelperInvocation].caps.push_back(CapShader);

-    BuiltInParams[BuiltInLocalInvocationIndex].caps.push_back(CapShader);

-    BuiltInParams[BuiltInWorkDim].caps.push_back(CapKernel);

-    BuiltInParams[BuiltInGlobalSize].caps.push_back(CapKernel);

-    BuiltInParams[BuiltInEnqueuedWorkgroupSize].caps.push_back(CapKernel);

-    BuiltInParams[BuiltInGlobalOffset].caps.push_back(CapKernel);

-    BuiltInParams[BuiltInGlobalLinearId].caps.push_back(CapKernel);

-    BuiltInParams[BuiltInWorkgroupLinearId].caps.push_back(CapKernel);

-

-    BuiltInParams[BuiltInSubgroupSize].caps.push_back(CapKernel);

-    BuiltInParams[BuiltInSubgroupMaxSize].caps.push_back(CapKernel);

-    BuiltInParams[BuiltInNumSubgroups].caps.push_back(CapKernel);

-    BuiltInParams[BuiltInNumEnqueuedSubgroups].caps.push_back(CapKernel);

-    BuiltInParams[BuiltInSubgroupId].caps.push_back(CapKernel);

-    BuiltInParams[BuiltInSubgroupLocalInvocationId].caps.push_back(CapKernel);

-

-    DimensionalityParams[DimCube].caps.push_back(CapShader);

-    DimensionalityParams[DimRect].caps.push_back(CapShader);

-

-    // Group Operations

-    for (int i = 0; i < GroupOperationCeiling; ++i) {

-        GroupOperationParams[i].caps.push_back(CapKernel);

-    }

-

-    // Enqueue flags

-    for (int i = 0; i < KernelEnqueueFlagsCeiling; ++i) {

-        KernelEnqueueFlagsParams[i].caps.push_back(CapKernel);

-    }

-

-    // Profiling info

-    KernelProfilingInfoParams[0].caps.push_back(CapKernel);

-

-    // set name of operator, an initial set of <id> style operands, and the description

-

-    InstructionDesc[OpSource].operands.push(OperandSource, "");

-    InstructionDesc[OpSource].operands.push(OperandLiteralNumber, "'Version'");

-

-    InstructionDesc[OpSourceExtension].operands.push(OperandLiteralString, "'Extension'");

-

-    InstructionDesc[OpName].operands.push(OperandId, "'Target'");

-    InstructionDesc[OpName].operands.push(OperandLiteralString, "'Name'");

-

-    InstructionDesc[OpMemberName].operands.push(OperandId, "'Type'");

-    InstructionDesc[OpMemberName].operands.push(OperandLiteralNumber, "'Member'");

-    InstructionDesc[OpMemberName].operands.push(OperandLiteralString, "'Name'");

-

-    InstructionDesc[OpString].operands.push(OperandLiteralString, "'String'");

-

-    InstructionDesc[OpLine].operands.push(OperandId, "'Target'");

-    InstructionDesc[OpLine].operands.push(OperandId, "'File'");

-    InstructionDesc[OpLine].operands.push(OperandLiteralNumber, "'Line'");

-    InstructionDesc[OpLine].operands.push(OperandLiteralNumber, "'Column'");

-

-    InstructionDesc[OpExtension].operands.push(OperandLiteralString, "'Name'");

-

-    InstructionDesc[OpExtInstImport].operands.push(OperandLiteralString, "'Name'");

-

-    InstructionDesc[OpMemoryModel].operands.push(OperandAddressing, "");

-    InstructionDesc[OpMemoryModel].operands.push(OperandMemory, "");

-

-    InstructionDesc[OpEntryPoint].operands.push(OperandExecutionModel, "");

-    InstructionDesc[OpEntryPoint].operands.push(OperandId, "'Entry Point'");

-

-    InstructionDesc[OpExecutionMode].operands.push(OperandId, "'Entry Point'");

-    InstructionDesc[OpExecutionMode].operands.push(OperandExecutionMode, "'Mode'");

-    InstructionDesc[OpExecutionMode].operands.push(OperandVariableLiterals, "See <<Execution Mode,Execution Mode>>");

-

-    InstructionDesc[OpTypeInt].operands.push(OperandLiteralNumber, "'Width'");

-    InstructionDesc[OpTypeInt].operands.push(OperandLiteralNumber, "'Signedness'");

-

-    InstructionDesc[OpTypeFloat].operands.push(OperandLiteralNumber, "'Width'");

-

-    InstructionDesc[OpTypeVector].operands.push(OperandId, "'Component type'");

-    InstructionDesc[OpTypeVector].operands.push(OperandLiteralNumber, "'Component count'");

-

-    InstructionDesc[OpTypeMatrix].capabilities.push_back(CapMatrix);

-    InstructionDesc[OpTypeMatrix].operands.push(OperandId, "'Column type'");

-    InstructionDesc[OpTypeMatrix].operands.push(OperandLiteralNumber, "'Column count'");

-

-    InstructionDesc[OpTypeSampler].operands.push(OperandId, "'Sampled Type'");

-    InstructionDesc[OpTypeSampler].operands.push(OperandDimensionality, "");

-    InstructionDesc[OpTypeSampler].operands.push(OperandLiteralNumber, "'Content'");

-    InstructionDesc[OpTypeSampler].operands.push(OperandLiteralNumber, "'Arrayed'");

-    InstructionDesc[OpTypeSampler].operands.push(OperandLiteralNumber, "'Compare'");

-    InstructionDesc[OpTypeSampler].operands.push(OperandLiteralNumber, "'MS'");

-    InstructionDesc[OpTypeSampler].operands.push(OperandOptionalId, "'Qualifier'");

-

-    InstructionDesc[OpTypeArray].operands.push(OperandId, "'Element type'");

-    InstructionDesc[OpTypeArray].operands.push(OperandId, "'Length'");

-

-    InstructionDesc[OpTypeRuntimeArray].capabilities.push_back(CapShader);

-    InstructionDesc[OpTypeRuntimeArray].operands.push(OperandId, "'Element type'");

-

-    InstructionDesc[OpTypeStruct].operands.push(OperandVariableIds, "'Member 0 type', +\n'member 1 type', +\n...");

-

-    InstructionDesc[OpTypeOpaque].capabilities.push_back(CapKernel);

-    InstructionDesc[OpTypeOpaque].operands.push(OperandLiteralString, "The name of the opaque type.");

-

-    InstructionDesc[OpTypePointer].operands.push(OperandStorage, "");

-    InstructionDesc[OpTypePointer].operands.push(OperandId, "'Type'");

-

-    InstructionDesc[OpTypeEvent].capabilities.push_back(CapKernel);

-

-    InstructionDesc[OpTypeDeviceEvent].capabilities.push_back(CapKernel);

-

-    InstructionDesc[OpTypeReserveId].capabilities.push_back(CapKernel);

-

-    InstructionDesc[OpTypeQueue].capabilities.push_back(CapKernel);

-

-    InstructionDesc[OpTypePipe].operands.push(OperandId, "'Type'");

-    InstructionDesc[OpTypePipe].operands.push(OperandAccessQualifier, "'Qualifier'");

-    InstructionDesc[OpTypePipe].capabilities.push_back(CapKernel);

-

-    InstructionDesc[OpTypeFunction].operands.push(OperandId, "'Return Type'");

-    InstructionDesc[OpTypeFunction].operands.push(OperandVariableIds, "'Parameter 0 Type', +\n'Parameter 1 Type', +\n...");

-

-    InstructionDesc[OpConstant].operands.push(OperandVariableLiterals, "'Value'");

-

-    InstructionDesc[OpConstantComposite].operands.push(OperandVariableIds, "'Constituents'");

-

-    InstructionDesc[OpConstantNullPointer].capabilities.push_back(CapAddr);

-

-    InstructionDesc[OpConstantNullObject].capabilities.push_back(CapKernel);

-

-    InstructionDesc[OpConstantSampler].capabilities.push_back(CapKernel);

-    InstructionDesc[OpConstantSampler].operands.push(OperandLiteralNumber, "'Mode'");

-    InstructionDesc[OpConstantSampler].operands.push(OperandLiteralNumber, "'Param'");

-    InstructionDesc[OpConstantSampler].operands.push(OperandLiteralNumber, "'Filter'");

-

-    InstructionDesc[OpSpecConstantTrue].capabilities.push_back(CapShader);

-

-    InstructionDesc[OpSpecConstantFalse].capabilities.push_back(CapShader);

-

-    InstructionDesc[OpSpecConstant].operands.push(OperandVariableLiterals, "'Value'");

-    InstructionDesc[OpSpecConstant].capabilities.push_back(CapShader);

-

-    InstructionDesc[OpSpecConstantComposite].operands.push(OperandVariableIds, "'Constituents'");

-    InstructionDesc[OpSpecConstantComposite].capabilities.push_back(CapShader);

-

-    InstructionDesc[OpVariable].operands.push(OperandStorage, "");

-    InstructionDesc[OpVariable].operands.push(OperandOptionalId, "'Initializer'");

-

-    InstructionDesc[OpVariableArray].operands.push(OperandStorage, "");

-    InstructionDesc[OpVariableArray].operands.push(OperandId, "'N'");

-    InstructionDesc[OpVariableArray].capabilities.push_back(CapAddr);

-

-    InstructionDesc[OpFunction].operands.push(OperandFunction, "");

-    InstructionDesc[OpFunction].operands.push(OperandId, "'Function Type'");

-

-    InstructionDesc[OpFunctionCall].operands.push(OperandId, "'Function'");

-    InstructionDesc[OpFunctionCall].operands.push(OperandVariableIds, "'Argument 0', +\n'Argument 1', +\n...");

-

-    InstructionDesc[OpExtInst].operands.push(OperandId, "'Set'");

-    InstructionDesc[OpExtInst].operands.push(OperandLiteralNumber, "'Instruction'");

-    InstructionDesc[OpExtInst].operands.push(OperandVariableIds, "'Operand 1', +\n'Operand 2', +\n...");

-

-    InstructionDesc[OpLoad].operands.push(OperandId, "'Pointer'");

-    InstructionDesc[OpLoad].operands.push(OperandVariableLiterals, "'Memory Access'");

-

-    InstructionDesc[OpStore].operands.push(OperandId, "'Pointer'");

-    InstructionDesc[OpStore].operands.push(OperandId, "'Object'");

-    InstructionDesc[OpStore].operands.push(OperandVariableLiterals, "'Memory Access'");

-

-    InstructionDesc[OpPhi].operands.push(OperandVariableIds, "");

-

-    InstructionDesc[OpDecorate].operands.push(OperandId, "'Target'");

-    InstructionDesc[OpDecorate].operands.push(OperandDecoration, "");

-    InstructionDesc[OpDecorate].operands.push(OperandVariableLiterals, "See <<Decoration,'Decoration'>>.");

-

-    InstructionDesc[OpMemberDecorate].operands.push(OperandId, "'Structure type'");

-    InstructionDesc[OpMemberDecorate].operands.push(OperandLiteralNumber, "'Member'");

-    InstructionDesc[OpMemberDecorate].operands.push(OperandDecoration, "");

-    InstructionDesc[OpMemberDecorate].operands.push(OperandVariableLiterals, "See <<Decoration,'Decoration'>>.");

-

-    InstructionDesc[OpGroupDecorate].operands.push(OperandId, "'Decoration group'");

-    InstructionDesc[OpGroupDecorate].operands.push(OperandVariableIds, "'Target', 'Target', ...");

-

-    InstructionDesc[OpGroupMemberDecorate].operands.push(OperandId, "'Decoration group'");

-    InstructionDesc[OpGroupMemberDecorate].operands.push(OperandVariableIds, "'Target', 'Target', ...");

-

-    InstructionDesc[OpVectorExtractDynamic].operands.push(OperandId, "'Vector'");

-    InstructionDesc[OpVectorExtractDynamic].operands.push(OperandId, "'Index'");

-

-    InstructionDesc[OpVectorInsertDynamic].operands.push(OperandId, "'Vector'");

-    InstructionDesc[OpVectorInsertDynamic].operands.push(OperandId, "'Component'");

-    InstructionDesc[OpVectorInsertDynamic].operands.push(OperandId, "'Index'");

-

-    InstructionDesc[OpVectorShuffle].operands.push(OperandId, "'Vector 1'");

-    InstructionDesc[OpVectorShuffle].operands.push(OperandId, "'Vector 2'");

-    InstructionDesc[OpVectorShuffle].operands.push(OperandVariableLiterals, "'Components'");

-

-    InstructionDesc[OpCompositeConstruct].operands.push(OperandVariableIds, "'Constituents'");

-

-    InstructionDesc[OpCompositeExtract].operands.push(OperandId, "'Composite'");

-    InstructionDesc[OpCompositeExtract].operands.push(OperandVariableLiterals, "'Indexes'");

-

-    InstructionDesc[OpCompositeInsert].operands.push(OperandId, "'Object'");

-    InstructionDesc[OpCompositeInsert].operands.push(OperandId, "'Composite'");

-    InstructionDesc[OpCompositeInsert].operands.push(OperandVariableLiterals, "'Indexes'");

-

-    InstructionDesc[OpCopyObject].operands.push(OperandId, "'Operand'");

-

-    InstructionDesc[OpCopyMemory].operands.push(OperandId, "'Target'");

-    InstructionDesc[OpCopyMemory].operands.push(OperandId, "'Source'");

-    InstructionDesc[OpCopyMemory].operands.push(OperandVariableLiterals, "'Memory Access'");

-

-    InstructionDesc[OpCopyMemorySized].operands.push(OperandId, "'Target'");

-    InstructionDesc[OpCopyMemorySized].operands.push(OperandId, "'Source'");

-    InstructionDesc[OpCopyMemorySized].operands.push(OperandId, "'Size'");

-    InstructionDesc[OpCopyMemorySized].operands.push(OperandVariableLiterals, "'Memory Access'");

-

-    InstructionDesc[OpCopyMemorySized].capabilities.push_back(CapAddr);

-

-    InstructionDesc[OpSampler].operands.push(OperandId, "'Sampler'");

-    InstructionDesc[OpSampler].operands.push(OperandId, "'Filter'");

-

-    InstructionDesc[OpTextureSample].operands.push(OperandId, "'Sampler'");

-    InstructionDesc[OpTextureSample].operands.push(OperandId, "'Coordinate'");

-    InstructionDesc[OpTextureSample].operands.push(OperandOptionalId, "['Bias']");

-    InstructionDesc[OpTextureSample].capabilities.push_back(CapShader);

-

-    InstructionDesc[OpTextureSampleDref].operands.push(OperandId, "'Sampler'");

-    InstructionDesc[OpTextureSampleDref].operands.push(OperandId, "'Coordinate'");

-    InstructionDesc[OpTextureSampleDref].operands.push(OperandId, "'D~ref~'");

-    InstructionDesc[OpTextureSampleDref].capabilities.push_back(CapShader);

-

-    InstructionDesc[OpTextureSampleLod].operands.push(OperandId, "'Sampler'");

-    InstructionDesc[OpTextureSampleLod].operands.push(OperandId, "'Coordinate'");

-    InstructionDesc[OpTextureSampleLod].operands.push(OperandId, "'Level of Detail'");

-    InstructionDesc[OpTextureSampleLod].capabilities.push_back(CapShader);

-

-    InstructionDesc[OpTextureSampleProj].operands.push(OperandId, "'Sampler'");

-    InstructionDesc[OpTextureSampleProj].operands.push(OperandId, "'Coordinate'");

-    InstructionDesc[OpTextureSampleProj].operands.push(OperandOptionalId, "['Bias']");

-    InstructionDesc[OpTextureSampleProj].capabilities.push_back(CapShader);

-

-    InstructionDesc[OpTextureSampleGrad].operands.push(OperandId, "'Sampler'");

-    InstructionDesc[OpTextureSampleGrad].operands.push(OperandId, "'Coordinate'");

-    InstructionDesc[OpTextureSampleGrad].operands.push(OperandId, "'dx'");

-    InstructionDesc[OpTextureSampleGrad].operands.push(OperandId, "'dy'");

-    InstructionDesc[OpTextureSampleGrad].capabilities.push_back(CapShader);

-

-    InstructionDesc[OpTextureSampleOffset].operands.push(OperandId, "'Sampler'");

-    InstructionDesc[OpTextureSampleOffset].operands.push(OperandId, "'Coordinate'");

-    InstructionDesc[OpTextureSampleOffset].operands.push(OperandId, "'Offset'");

-    InstructionDesc[OpTextureSampleOffset].operands.push(OperandOptionalId, "['Bias']");

-    InstructionDesc[OpTextureSampleOffset].capabilities.push_back(CapShader);

-

-    InstructionDesc[OpTextureSampleProjLod].operands.push(OperandId, "'Sampler'");

-    InstructionDesc[OpTextureSampleProjLod].operands.push(OperandId, "'Coordinate'");

-    InstructionDesc[OpTextureSampleProjLod].operands.push(OperandId, "'Level of Detail'");

-    InstructionDesc[OpTextureSampleProjLod].capabilities.push_back(CapShader);

-

-    InstructionDesc[OpTextureSampleProjGrad].operands.push(OperandId, "'Sampler'");

-    InstructionDesc[OpTextureSampleProjGrad].operands.push(OperandId, "'Coordinate'");

-    InstructionDesc[OpTextureSampleProjGrad].operands.push(OperandId, "'dx'");

-    InstructionDesc[OpTextureSampleProjGrad].operands.push(OperandId, "'dy'");

-    InstructionDesc[OpTextureSampleProjGrad].capabilities.push_back(CapShader);

-

-    InstructionDesc[OpTextureSampleLodOffset].operands.push(OperandId, "'Sampler'");

-    InstructionDesc[OpTextureSampleLodOffset].operands.push(OperandId, "'Coordinate'");

-    InstructionDesc[OpTextureSampleLodOffset].operands.push(OperandId, "'Level of Detail'");

-    InstructionDesc[OpTextureSampleLodOffset].operands.push(OperandId, "'Offset'");

-    InstructionDesc[OpTextureSampleLodOffset].capabilities.push_back(CapShader);

-

-    InstructionDesc[OpTextureSampleProjOffset].operands.push(OperandId, "'Sampler'");

-    InstructionDesc[OpTextureSampleProjOffset].operands.push(OperandId, "'Coordinate'");

-    InstructionDesc[OpTextureSampleProjOffset].operands.push(OperandId, "'Offset'");

-    InstructionDesc[OpTextureSampleProjOffset].operands.push(OperandOptionalId, "['Bias']");

-    InstructionDesc[OpTextureSampleProjOffset].capabilities.push_back(CapShader);

-

-    InstructionDesc[OpTextureSampleGradOffset].operands.push(OperandId, "'Sampler'");

-    InstructionDesc[OpTextureSampleGradOffset].operands.push(OperandId, "'Coordinate'");

-    InstructionDesc[OpTextureSampleGradOffset].operands.push(OperandId, "'dx'");

-    InstructionDesc[OpTextureSampleGradOffset].operands.push(OperandId, "'dy'");

-    InstructionDesc[OpTextureSampleGradOffset].operands.push(OperandId, "'Offset'");

-    InstructionDesc[OpTextureSampleGradOffset].capabilities.push_back(CapShader);

-

-    InstructionDesc[OpTextureSampleProjLodOffset].operands.push(OperandId, "'Sampler'");

-    InstructionDesc[OpTextureSampleProjLodOffset].operands.push(OperandId, "'Coordinate'");

-    InstructionDesc[OpTextureSampleProjLodOffset].operands.push(OperandId, "'Level of Detail'");

-    InstructionDesc[OpTextureSampleProjLodOffset].operands.push(OperandId, "'Offset'");

-    InstructionDesc[OpTextureSampleProjLodOffset].capabilities.push_back(CapShader);

-

-    InstructionDesc[OpTextureSampleProjGradOffset].operands.push(OperandId, "'Sampler'");

-    InstructionDesc[OpTextureSampleProjGradOffset].operands.push(OperandId, "'Coordinate'");

-    InstructionDesc[OpTextureSampleProjGradOffset].operands.push(OperandId, "'dx'");

-    InstructionDesc[OpTextureSampleProjGradOffset].operands.push(OperandId, "'dy'");

-    InstructionDesc[OpTextureSampleProjGradOffset].operands.push(OperandId, "'Offset'");

-    InstructionDesc[OpTextureSampleProjGradOffset].capabilities.push_back(CapShader);

-

-    InstructionDesc[OpTextureFetchTexelLod].operands.push(OperandId, "'Sampler'");

-    InstructionDesc[OpTextureFetchTexelLod].operands.push(OperandId, "'Coordinate'");

-    InstructionDesc[OpTextureFetchTexelLod].operands.push(OperandId, "'Level of Detail'");

-    InstructionDesc[OpTextureFetchTexelLod].capabilities.push_back(CapShader);

-

-    InstructionDesc[OpTextureFetchTexelOffset].operands.push(OperandId, "'Sampler'");

-    InstructionDesc[OpTextureFetchTexelOffset].operands.push(OperandId, "'Coordinate'");

-    InstructionDesc[OpTextureFetchTexelOffset].operands.push(OperandId, "'Offset'");

-    InstructionDesc[OpTextureFetchTexelOffset].capabilities.push_back(CapShader);

-

-    InstructionDesc[OpTextureFetchSample].operands.push(OperandId, "'Sampler'");

-    InstructionDesc[OpTextureFetchSample].operands.push(OperandId, "'Coordinate'");

-    InstructionDesc[OpTextureFetchSample].operands.push(OperandId, "'Sample'");

-    InstructionDesc[OpTextureFetchSample].capabilities.push_back(CapShader);

-

-    InstructionDesc[OpTextureFetchTexel].operands.push(OperandId, "'Sampler'");

-    InstructionDesc[OpTextureFetchTexel].operands.push(OperandId, "'Element'");

-    InstructionDesc[OpTextureFetchTexel].capabilities.push_back(CapShader);

-

-    InstructionDesc[OpTextureGather].operands.push(OperandId, "'Sampler'");

-    InstructionDesc[OpTextureGather].operands.push(OperandId, "'Coordinate'");

-    InstructionDesc[OpTextureGather].operands.push(OperandId, "'Component'");

-    InstructionDesc[OpTextureGather].capabilities.push_back(CapShader);

-

-    InstructionDesc[OpTextureGatherOffset].operands.push(OperandId, "'Sampler'");

-    InstructionDesc[OpTextureGatherOffset].operands.push(OperandId, "'Coordinate'");

-    InstructionDesc[OpTextureGatherOffset].operands.push(OperandId, "'Component'");

-    InstructionDesc[OpTextureGatherOffset].operands.push(OperandId, "'Offset'");

-    InstructionDesc[OpTextureGatherOffset].capabilities.push_back(CapShader);

-

-    InstructionDesc[OpTextureGatherOffsets].operands.push(OperandId, "'Sampler'");

-    InstructionDesc[OpTextureGatherOffsets].operands.push(OperandId, "'Coordinate'");

-    InstructionDesc[OpTextureGatherOffsets].operands.push(OperandId, "'Component'");

-    InstructionDesc[OpTextureGatherOffsets].operands.push(OperandId, "'Offsets'");

-    InstructionDesc[OpTextureGatherOffsets].capabilities.push_back(CapShader);

-

-    InstructionDesc[OpTextureQuerySizeLod].operands.push(OperandId, "'Sampler'");

-    InstructionDesc[OpTextureQuerySizeLod].operands.push(OperandId, "'Level of Detail'");

-    InstructionDesc[OpTextureQuerySizeLod].capabilities.push_back(CapShader);

-

-    InstructionDesc[OpTextureQuerySize].operands.push(OperandId, "'Sampler'");

-    InstructionDesc[OpTextureQuerySize].capabilities.push_back(CapShader);

-

-    InstructionDesc[OpTextureQueryLod].operands.push(OperandId, "'Sampler'");

-    InstructionDesc[OpTextureQueryLod].operands.push(OperandId, "'Coordinate'");

-    InstructionDesc[OpTextureQueryLod].capabilities.push_back(CapShader);

-

-    InstructionDesc[OpTextureQueryLevels].operands.push(OperandId, "'Sampler'");

-    InstructionDesc[OpTextureQueryLevels].capabilities.push_back(CapShader);

-

-    InstructionDesc[OpTextureQuerySamples].operands.push(OperandId, "'Sampler'");

-    InstructionDesc[OpTextureQuerySamples].capabilities.push_back(CapShader);

-

-    InstructionDesc[OpAccessChain].operands.push(OperandId, "'Base'");

-    InstructionDesc[OpAccessChain].operands.push(OperandVariableIds, "'Indexes'");

-

-    InstructionDesc[OpInBoundsAccessChain].operands.push(OperandId, "'Base'");

-    InstructionDesc[OpInBoundsAccessChain].operands.push(OperandVariableIds, "'Indexes'");

-

-    InstructionDesc[OpSNegate].operands.push(OperandId, "'Operand'");

-

-    InstructionDesc[OpFNegate].operands.push(OperandId, "'Operand'");

-

-    InstructionDesc[OpNot].operands.push(OperandId, "'Operand'");

-

-    InstructionDesc[OpAny].operands.push(OperandId, "'Vector'");

-

-    InstructionDesc[OpAll].operands.push(OperandId, "'Vector'");

-

-    InstructionDesc[OpConvertFToU].operands.push(OperandId, "'Float Value'");

-

-    InstructionDesc[OpConvertFToS].operands.push(OperandId, "'Float Value'");

-

-    InstructionDesc[OpConvertSToF].operands.push(OperandId, "'Signed Value'");

-

-    InstructionDesc[OpConvertUToF].operands.push(OperandId, "'Unsigned value'");

-

-    InstructionDesc[OpUConvert].operands.push(OperandId, "'Unsigned value'");

-

-    InstructionDesc[OpSConvert].operands.push(OperandId, "'Signed Value'");

-

-    InstructionDesc[OpFConvert].operands.push(OperandId, "'Float Value'");

-

-    InstructionDesc[OpSatConvertSToU].operands.push(OperandId, "'Signed Value'");

-    InstructionDesc[OpSatConvertSToU].capabilities.push_back(CapKernel);

-

-    InstructionDesc[OpSatConvertUToS].operands.push(OperandId, "'Unsigned Value'");

-    InstructionDesc[OpSatConvertUToS].capabilities.push_back(CapKernel);

-

-    InstructionDesc[OpConvertPtrToU].operands.push(OperandId, "'Pointer'");

-    InstructionDesc[OpConvertPtrToU].capabilities.push_back(CapAddr);

-

-    InstructionDesc[OpConvertUToPtr].operands.push(OperandId, "'Integer value'");

-    InstructionDesc[OpConvertUToPtr].capabilities.push_back(CapAddr);

-

-    InstructionDesc[OpPtrCastToGeneric].operands.push(OperandId, "'Source pointer'");

-    InstructionDesc[OpPtrCastToGeneric].capabilities.push_back(CapKernel);

-

-

-    InstructionDesc[OpGenericCastToPtr].operands.push(OperandId, "'Source pointer'");

-    InstructionDesc[OpGenericCastToPtr].capabilities.push_back(CapKernel);

-

-    InstructionDesc[OpGenericCastToPtrExplicit].operands.push(OperandId, "'Source pointer'");

-    InstructionDesc[OpGenericCastToPtrExplicit].operands.push(OperandStorage, "'storage'");

-    InstructionDesc[OpGenericCastToPtrExplicit].capabilities.push_back(CapKernel);

-

-    InstructionDesc[OpGenericPtrMemSemantics].operands.push(OperandId, "'ptr'");

-    InstructionDesc[OpGenericPtrMemSemantics].capabilities.push_back(CapKernel);

-

-    InstructionDesc[OpBitcast].operands.push(OperandId, "'Operand'");

-

-    InstructionDesc[OpTranspose].capabilities.push_back(CapMatrix);

-    InstructionDesc[OpTranspose].operands.push(OperandId, "'Matrix'");

-

-    InstructionDesc[OpIsNan].operands.push(OperandId, "'x'");

-

-    InstructionDesc[OpIsInf].operands.push(OperandId, "'x'");

-

-    InstructionDesc[OpIsFinite].capabilities.push_back(CapKernel);

-    InstructionDesc[OpIsFinite].operands.push(OperandId, "'x'");

-

-    InstructionDesc[OpIsNormal].capabilities.push_back(CapKernel);

-    InstructionDesc[OpIsNormal].operands.push(OperandId, "'x'");

-

-    InstructionDesc[OpSignBitSet].capabilities.push_back(CapKernel);

-    InstructionDesc[OpSignBitSet].operands.push(OperandId, "'x'");

-

-    InstructionDesc[OpLessOrGreater].capabilities.push_back(CapKernel);

-    InstructionDesc[OpLessOrGreater].operands.push(OperandId, "'x'");

-    InstructionDesc[OpLessOrGreater].operands.push(OperandId, "'y'");

-

-    InstructionDesc[OpOrdered].capabilities.push_back(CapKernel);

-    InstructionDesc[OpOrdered].operands.push(OperandId, "'x'");

-    InstructionDesc[OpOrdered].operands.push(OperandId, "'y'");

-

-    InstructionDesc[OpUnordered].capabilities.push_back(CapKernel);

-    InstructionDesc[OpUnordered].operands.push(OperandId, "'x'");

-    InstructionDesc[OpUnordered].operands.push(OperandId, "'y'");

-

-    InstructionDesc[OpArrayLength].operands.push(OperandId, "'Structure'");

-    InstructionDesc[OpArrayLength].operands.push(OperandLiteralNumber, "'Array member'");

-    InstructionDesc[OpArrayLength].capabilities.push_back(CapShader);

-

-    InstructionDesc[OpIAdd].operands.push(OperandId, "'Operand 1'");

-    InstructionDesc[OpIAdd].operands.push(OperandId, "'Operand 2'");

-

-    InstructionDesc[OpFAdd].operands.push(OperandId, "'Operand 1'");

-    InstructionDesc[OpFAdd].operands.push(OperandId, "'Operand 2'");

-

-    InstructionDesc[OpISub].operands.push(OperandId, "'Operand 1'");

-    InstructionDesc[OpISub].operands.push(OperandId, "'Operand 2'");

-

-    InstructionDesc[OpFSub].operands.push(OperandId, "'Operand 1'");

-    InstructionDesc[OpFSub].operands.push(OperandId, "'Operand 2'");

-

-    InstructionDesc[OpIMul].operands.push(OperandId, "'Operand 1'");

-    InstructionDesc[OpIMul].operands.push(OperandId, "'Operand 2'");

-

-    InstructionDesc[OpFMul].operands.push(OperandId, "'Operand 1'");

-    InstructionDesc[OpFMul].operands.push(OperandId, "'Operand 2'");

-

-    InstructionDesc[OpUDiv].operands.push(OperandId, "'Operand 1'");

-    InstructionDesc[OpUDiv].operands.push(OperandId, "'Operand 2'");

-

-    InstructionDesc[OpSDiv].operands.push(OperandId, "'Operand 1'");

-    InstructionDesc[OpSDiv].operands.push(OperandId, "'Operand 2'");

-

-    InstructionDesc[OpFDiv].operands.push(OperandId, "'Operand 1'");

-    InstructionDesc[OpFDiv].operands.push(OperandId, "'Operand 2'");

-

-    InstructionDesc[OpUMod].operands.push(OperandId, "'Operand 1'");

-    InstructionDesc[OpUMod].operands.push(OperandId, "'Operand 2'");

-

-    InstructionDesc[OpSRem].operands.push(OperandId, "'Operand 1'");

-    InstructionDesc[OpSRem].operands.push(OperandId, "'Operand 2'");

-

-    InstructionDesc[OpSMod].operands.push(OperandId, "'Operand 1'");

-    InstructionDesc[OpSMod].operands.push(OperandId, "'Operand 2'");

-

-    InstructionDesc[OpFRem].operands.push(OperandId, "'Operand 1'");

-    InstructionDesc[OpFRem].operands.push(OperandId, "'Operand 2'");

-

-    InstructionDesc[OpFMod].operands.push(OperandId, "'Operand 1'");

-    InstructionDesc[OpFMod].operands.push(OperandId, "'Operand 2'");

-

-    InstructionDesc[OpVectorTimesScalar].operands.push(OperandId, "'Vector'");

-    InstructionDesc[OpVectorTimesScalar].operands.push(OperandId, "'Scalar'");

-

-    InstructionDesc[OpMatrixTimesScalar].capabilities.push_back(CapMatrix);

-    InstructionDesc[OpMatrixTimesScalar].operands.push(OperandId, "'Matrix'");

-    InstructionDesc[OpMatrixTimesScalar].operands.push(OperandId, "'Scalar'");

-

-    InstructionDesc[OpVectorTimesMatrix].capabilities.push_back(CapMatrix);

-    InstructionDesc[OpVectorTimesMatrix].operands.push(OperandId, "'Vector'");

-    InstructionDesc[OpVectorTimesMatrix].operands.push(OperandId, "'Matrix'");

-

-    InstructionDesc[OpMatrixTimesVector].capabilities.push_back(CapMatrix);

-    InstructionDesc[OpMatrixTimesVector].operands.push(OperandId, "'Matrix'");

-    InstructionDesc[OpMatrixTimesVector].operands.push(OperandId, "'Vector'");

-

-    InstructionDesc[OpMatrixTimesMatrix].capabilities.push_back(CapMatrix);

-    InstructionDesc[OpMatrixTimesMatrix].operands.push(OperandId, "'LeftMatrix'");

-    InstructionDesc[OpMatrixTimesMatrix].operands.push(OperandId, "'RightMatrix'");

-

-    InstructionDesc[OpOuterProduct].capabilities.push_back(CapMatrix);

-    InstructionDesc[OpOuterProduct].operands.push(OperandId, "'Vector 1'");

-    InstructionDesc[OpOuterProduct].operands.push(OperandId, "'Vector 2'");

-

-    InstructionDesc[OpDot].operands.push(OperandId, "'Vector 1'");

-    InstructionDesc[OpDot].operands.push(OperandId, "'Vector 2'");

-

-    InstructionDesc[OpShiftRightLogical].operands.push(OperandId, "'Operand 1'");

-    InstructionDesc[OpShiftRightLogical].operands.push(OperandId, "'Operand 2'");

-

-    InstructionDesc[OpShiftRightArithmetic].operands.push(OperandId, "'Operand 1'");

-    InstructionDesc[OpShiftRightArithmetic].operands.push(OperandId, "'Operand 2'");

-

-    InstructionDesc[OpShiftLeftLogical].operands.push(OperandId, "'Operand 1'");

-    InstructionDesc[OpShiftLeftLogical].operands.push(OperandId, "'Operand 2'");

-

-    InstructionDesc[OpLogicalOr].operands.push(OperandId, "'Operand 1'");

-    InstructionDesc[OpLogicalOr].operands.push(OperandId, "'Operand 2'");

-

-    InstructionDesc[OpLogicalXor].operands.push(OperandId, "'Operand 1'");

-    InstructionDesc[OpLogicalXor].operands.push(OperandId, "'Operand 2'");

-

-    InstructionDesc[OpLogicalAnd].operands.push(OperandId, "'Operand 1'");

-    InstructionDesc[OpLogicalAnd].operands.push(OperandId, "'Operand 2'");

-

-    InstructionDesc[OpBitwiseOr].operands.push(OperandId, "'Operand 1'");

-    InstructionDesc[OpBitwiseOr].operands.push(OperandId, "'Operand 2'");

-

-    InstructionDesc[OpBitwiseXor].operands.push(OperandId, "'Operand 1'");

-    InstructionDesc[OpBitwiseXor].operands.push(OperandId, "'Operand 2'");

-

-    InstructionDesc[OpBitwiseAnd].operands.push(OperandId, "'Operand 1'");

-    InstructionDesc[OpBitwiseAnd].operands.push(OperandId, "'Operand 2'");

-

-    InstructionDesc[OpSelect].operands.push(OperandId, "'Condition'");

-    InstructionDesc[OpSelect].operands.push(OperandId, "'Object 1'");

-    InstructionDesc[OpSelect].operands.push(OperandId, "'Object 2'");

-

-    InstructionDesc[OpIEqual].operands.push(OperandId, "'Operand 1'");

-    InstructionDesc[OpIEqual].operands.push(OperandId, "'Operand 2'");

-

-    InstructionDesc[OpFOrdEqual].operands.push(OperandId, "'Operand 1'");

-    InstructionDesc[OpFOrdEqual].operands.push(OperandId, "'Operand 2'");

-

-    InstructionDesc[OpFUnordEqual].operands.push(OperandId, "'Operand 1'");

-    InstructionDesc[OpFUnordEqual].operands.push(OperandId, "'Operand 2'");

-

-    InstructionDesc[OpINotEqual].operands.push(OperandId, "'Operand 1'");

-    InstructionDesc[OpINotEqual].operands.push(OperandId, "'Operand 2'");

-

-    InstructionDesc[OpFOrdNotEqual].operands.push(OperandId, "'Operand 1'");

-    InstructionDesc[OpFOrdNotEqual].operands.push(OperandId, "'Operand 2'");

-

-    InstructionDesc[OpFUnordNotEqual].operands.push(OperandId, "'Operand 1'");

-    InstructionDesc[OpFUnordNotEqual].operands.push(OperandId, "'Operand 2'");

-

-    InstructionDesc[OpULessThan].operands.push(OperandId, "'Operand 1'");

-    InstructionDesc[OpULessThan].operands.push(OperandId, "'Operand 2'");

-

-    InstructionDesc[OpSLessThan].operands.push(OperandId, "'Operand 1'");

-    InstructionDesc[OpSLessThan].operands.push(OperandId, "'Operand 2'");

-

-    InstructionDesc[OpFOrdLessThan].operands.push(OperandId, "'Operand 1'");

-    InstructionDesc[OpFOrdLessThan].operands.push(OperandId, "'Operand 2'");

-

-    InstructionDesc[OpFUnordLessThan].operands.push(OperandId, "'Operand 1'");

-    InstructionDesc[OpFUnordLessThan].operands.push(OperandId, "'Operand 2'");

-

-    InstructionDesc[OpUGreaterThan].operands.push(OperandId, "'Operand 1'");

-    InstructionDesc[OpUGreaterThan].operands.push(OperandId, "'Operand 2'");

-

-    InstructionDesc[OpSGreaterThan].operands.push(OperandId, "'Operand 1'");

-    InstructionDesc[OpSGreaterThan].operands.push(OperandId, "'Operand 2'");

-

-    InstructionDesc[OpFOrdGreaterThan].operands.push(OperandId, "'Operand 1'");

-    InstructionDesc[OpFOrdGreaterThan].operands.push(OperandId, "'Operand 2'");

-

-    InstructionDesc[OpFUnordGreaterThan].operands.push(OperandId, "'Operand 1'");

-    InstructionDesc[OpFUnordGreaterThan].operands.push(OperandId, "'Operand 2'");

-

-    InstructionDesc[OpULessThanEqual].operands.push(OperandId, "'Operand 1'");

-    InstructionDesc[OpULessThanEqual].operands.push(OperandId, "'Operand 2'");

-

-    InstructionDesc[OpSLessThanEqual].operands.push(OperandId, "'Operand 1'");

-    InstructionDesc[OpSLessThanEqual].operands.push(OperandId, "'Operand 2'");

-

-    InstructionDesc[OpFOrdLessThanEqual].operands.push(OperandId, "'Operand 1'");

-    InstructionDesc[OpFOrdLessThanEqual].operands.push(OperandId, "'Operand 2'");

-

-    InstructionDesc[OpFUnordLessThanEqual].operands.push(OperandId, "'Operand 1'");

-    InstructionDesc[OpFUnordLessThanEqual].operands.push(OperandId, "'Operand 2'");

-

-    InstructionDesc[OpUGreaterThanEqual].operands.push(OperandId, "'Operand 1'");

-    InstructionDesc[OpUGreaterThanEqual].operands.push(OperandId, "'Operand 2'");

-

-    InstructionDesc[OpSGreaterThanEqual].operands.push(OperandId, "'Operand 1'");

-    InstructionDesc[OpSGreaterThanEqual].operands.push(OperandId, "'Operand 2'");

-

-    InstructionDesc[OpFOrdGreaterThanEqual].operands.push(OperandId, "'Operand 1'");

-    InstructionDesc[OpFOrdGreaterThanEqual].operands.push(OperandId, "'Operand 2'");

-

-    InstructionDesc[OpFUnordGreaterThanEqual].operands.push(OperandId, "'Operand 1'");

-    InstructionDesc[OpFUnordGreaterThanEqual].operands.push(OperandId, "'Operand 2'");

-

-    InstructionDesc[OpDPdx].capabilities.push_back(CapShader);

-    InstructionDesc[OpDPdx].operands.push(OperandId, "'P'");

-

-    InstructionDesc[OpDPdy].capabilities.push_back(CapShader);

-    InstructionDesc[OpDPdy].operands.push(OperandId, "'P'");

-

-    InstructionDesc[OpFwidth].capabilities.push_back(CapShader);

-    InstructionDesc[OpFwidth].operands.push(OperandId, "'P'");

-

-    InstructionDesc[OpDPdxFine].capabilities.push_back(CapShader);

-    InstructionDesc[OpDPdxFine].operands.push(OperandId, "'P'");

-

-    InstructionDesc[OpDPdyFine].capabilities.push_back(CapShader);

-    InstructionDesc[OpDPdyFine].operands.push(OperandId, "'P'");

-

-    InstructionDesc[OpFwidthFine].capabilities.push_back(CapShader);

-    InstructionDesc[OpFwidthFine].operands.push(OperandId, "'P'");

-

-    InstructionDesc[OpDPdxCoarse].capabilities.push_back(CapShader);

-    InstructionDesc[OpDPdxCoarse].operands.push(OperandId, "'P'");

-

-    InstructionDesc[OpDPdyCoarse].capabilities.push_back(CapShader);

-    InstructionDesc[OpDPdyCoarse].operands.push(OperandId, "'P'");

-

-    InstructionDesc[OpFwidthCoarse].capabilities.push_back(CapShader);

-    InstructionDesc[OpFwidthCoarse].operands.push(OperandId, "'P'");

-

-    InstructionDesc[OpEmitVertex].capabilities.push_back(CapGeom);

-

-    InstructionDesc[OpEndPrimitive].capabilities.push_back(CapGeom);

-

-    InstructionDesc[OpEmitStreamVertex].operands.push(OperandId, "'Stream'");

-    InstructionDesc[OpEmitStreamVertex].capabilities.push_back(CapGeom);

-

-    InstructionDesc[OpEndStreamPrimitive].operands.push(OperandId, "'Stream'");

-    InstructionDesc[OpEndStreamPrimitive].capabilities.push_back(CapGeom);

-

-    InstructionDesc[OpControlBarrier].operands.push(OperandExecutionScope, "'Scope'");

-

-    InstructionDesc[OpMemoryBarrier].operands.push(OperandExecutionScope, "'Scope'");

-    InstructionDesc[OpMemoryBarrier].operands.push(OperandMemorySemantics, "'Semantics'");

-

-    InstructionDesc[OpImagePointer].operands.push(OperandId, "'Image'");

-    InstructionDesc[OpImagePointer].operands.push(OperandId, "'Coordinate'");

-    InstructionDesc[OpImagePointer].operands.push(OperandId, "'Sample'");

-

-    InstructionDesc[OpAtomicInit].operands.push(OperandId, "'Pointer'");

-    InstructionDesc[OpAtomicInit].operands.push(OperandId, "'Value'");

-

-    InstructionDesc[OpAtomicLoad].operands.push(OperandId, "'Pointer'");

-    InstructionDesc[OpAtomicLoad].operands.push(OperandExecutionScope, "'Scope'");

-    InstructionDesc[OpAtomicLoad].operands.push(OperandMemorySemantics, "'Semantics'");

-

-    InstructionDesc[OpAtomicStore].operands.push(OperandId, "'Pointer'");

-    InstructionDesc[OpAtomicStore].operands.push(OperandExecutionScope, "'Scope'");

-    InstructionDesc[OpAtomicStore].operands.push(OperandMemorySemantics, "'Semantics'");

-    InstructionDesc[OpAtomicStore].operands.push(OperandId, "'Value'");

-

-    InstructionDesc[OpAtomicExchange].operands.push(OperandId, "'Pointer'");

-    InstructionDesc[OpAtomicExchange].operands.push(OperandExecutionScope, "'Scope'");

-    InstructionDesc[OpAtomicExchange].operands.push(OperandMemorySemantics, "'Semantics'");

-    InstructionDesc[OpAtomicExchange].operands.push(OperandId, "'Value'");

-

-    InstructionDesc[OpAtomicCompareExchange].operands.push(OperandId, "'Pointer'");

-    InstructionDesc[OpAtomicCompareExchange].operands.push(OperandExecutionScope, "'Scope'");

-    InstructionDesc[OpAtomicCompareExchange].operands.push(OperandMemorySemantics, "'Semantics'");

-    InstructionDesc[OpAtomicCompareExchange].operands.push(OperandId, "'Value'");

-    InstructionDesc[OpAtomicCompareExchange].operands.push(OperandId, "'Comparator'");

-

-    InstructionDesc[OpAtomicCompareExchangeWeak].operands.push(OperandId, "'Pointer'");

-    InstructionDesc[OpAtomicCompareExchangeWeak].operands.push(OperandExecutionScope, "'Scope'");

-    InstructionDesc[OpAtomicCompareExchangeWeak].operands.push(OperandMemorySemantics, "'Semantics'");

-    InstructionDesc[OpAtomicCompareExchangeWeak].operands.push(OperandId, "'Value'");

-    InstructionDesc[OpAtomicCompareExchangeWeak].operands.push(OperandId, "'Comparator'");

-

-    InstructionDesc[OpAtomicIIncrement].operands.push(OperandId, "'Pointer'");

-    InstructionDesc[OpAtomicIIncrement].operands.push(OperandExecutionScope, "'Scope'");

-    InstructionDesc[OpAtomicIIncrement].operands.push(OperandMemorySemantics, "'Semantics'");

-

-    InstructionDesc[OpAtomicIDecrement].operands.push(OperandId, "'Pointer'");

-    InstructionDesc[OpAtomicIDecrement].operands.push(OperandExecutionScope, "'Scope'");

-    InstructionDesc[OpAtomicIDecrement].operands.push(OperandMemorySemantics, "'Semantics'");

-

-    InstructionDesc[OpAtomicIAdd].operands.push(OperandId, "'Pointer'");

-    InstructionDesc[OpAtomicIAdd].operands.push(OperandExecutionScope, "'Scope'");

-    InstructionDesc[OpAtomicIAdd].operands.push(OperandMemorySemantics, "'Semantics'");

-    InstructionDesc[OpAtomicIAdd].operands.push(OperandId, "'Value'");

-

-    InstructionDesc[OpAtomicISub].operands.push(OperandId, "'Pointer'");

-    InstructionDesc[OpAtomicISub].operands.push(OperandExecutionScope, "'Scope'");

-    InstructionDesc[OpAtomicISub].operands.push(OperandMemorySemantics, "'Semantics'");

-    InstructionDesc[OpAtomicISub].operands.push(OperandId, "'Value'");

-

-    InstructionDesc[OpAtomicUMin].operands.push(OperandId, "'Pointer'");

-    InstructionDesc[OpAtomicUMin].operands.push(OperandExecutionScope, "'Scope'");

-    InstructionDesc[OpAtomicUMin].operands.push(OperandMemorySemantics, "'Semantics'");

-    InstructionDesc[OpAtomicUMin].operands.push(OperandId, "'Value'");

-

-    InstructionDesc[OpAtomicUMax].operands.push(OperandId, "'Pointer'");

-    InstructionDesc[OpAtomicUMax].operands.push(OperandExecutionScope, "'Scope'");

-    InstructionDesc[OpAtomicUMax].operands.push(OperandMemorySemantics, "'Semantics'");

-    InstructionDesc[OpAtomicUMax].operands.push(OperandId, "'Value'");

-

-    InstructionDesc[OpAtomicIMin].operands.push(OperandId, "'Pointer'");

-    InstructionDesc[OpAtomicIMin].operands.push(OperandExecutionScope, "'Scope'");

-    InstructionDesc[OpAtomicIMin].operands.push(OperandMemorySemantics, "'Semantics'");

-    InstructionDesc[OpAtomicIMin].operands.push(OperandId, "'Value'");

-

-    InstructionDesc[OpAtomicIMax].operands.push(OperandId, "'Pointer'");

-    InstructionDesc[OpAtomicIMax].operands.push(OperandExecutionScope, "'Scope'");

-    InstructionDesc[OpAtomicIMax].operands.push(OperandMemorySemantics, "'Semantics'");

-    InstructionDesc[OpAtomicIMax].operands.push(OperandId, "'Value'");

-

-    InstructionDesc[OpAtomicAnd].operands.push(OperandId, "'Pointer'");

-    InstructionDesc[OpAtomicAnd].operands.push(OperandExecutionScope, "'Scope'");

-    InstructionDesc[OpAtomicAnd].operands.push(OperandMemorySemantics, "'Semantics'");

-    InstructionDesc[OpAtomicAnd].operands.push(OperandId, "'Value'");

-

-    InstructionDesc[OpAtomicOr].operands.push(OperandId, "'Pointer'");

-    InstructionDesc[OpAtomicOr].operands.push(OperandExecutionScope, "'Scope'");

-    InstructionDesc[OpAtomicOr].operands.push(OperandMemorySemantics, "'Semantics'");

-    InstructionDesc[OpAtomicOr].operands.push(OperandId, "'Value'");

-

-    InstructionDesc[OpAtomicXor].operands.push(OperandId, "'Pointer'");

-    InstructionDesc[OpAtomicXor].operands.push(OperandExecutionScope, "'Scope'");

-    InstructionDesc[OpAtomicXor].operands.push(OperandMemorySemantics, "'Semantics'");

-    InstructionDesc[OpAtomicXor].operands.push(OperandId, "'Value'");

-

-    InstructionDesc[OpLoopMerge].operands.push(OperandId, "'Label'");

-    InstructionDesc[OpLoopMerge].operands.push(OperandLoop, "");

-

-    InstructionDesc[OpSelectionMerge].operands.push(OperandId, "'Label'");

-    InstructionDesc[OpSelectionMerge].operands.push(OperandSelect, "");

-

-    InstructionDesc[OpBranch].operands.push(OperandId, "'Target Label'");

-

-    InstructionDesc[OpBranchConditional].operands.push(OperandId, "'Condition'");

-    InstructionDesc[OpBranchConditional].operands.push(OperandId, "'True Label'");

-    InstructionDesc[OpBranchConditional].operands.push(OperandId, "'False Label'");

-    InstructionDesc[OpBranchConditional].operands.push(OperandVariableLiterals, "'Branch weights'");

-

-    InstructionDesc[OpSwitch].operands.push(OperandId, "'Selector'");

-    InstructionDesc[OpSwitch].operands.push(OperandId, "'Default'");

-    InstructionDesc[OpSwitch].operands.push(OperandVariableLiteralId, "'Target'");

-

-    InstructionDesc[OpKill].capabilities.push_back(CapShader);

-

-    InstructionDesc[OpReturnValue].operands.push(OperandId, "'Value'");

-

-    InstructionDesc[OpUnreachable].capabilities.push_back(CapKernel);

-

-    InstructionDesc[OpLifetimeStart].operands.push(OperandId, "");

-    InstructionDesc[OpLifetimeStart].operands.push(OperandLiteralNumber, "");

-

-    InstructionDesc[OpLifetimeStop].operands.push(OperandId, "");

-    InstructionDesc[OpLifetimeStop].operands.push(OperandLiteralNumber, "");

-

-    InstructionDesc[OpCompileFlag].capabilities.push_back(CapKernel);

-    InstructionDesc[OpCompileFlag].operands.push(OperandLiteralString, "'Flag'");

-

-    InstructionDesc[OpAsyncGroupCopy].capabilities.push_back(CapKernel);

-    InstructionDesc[OpAsyncGroupCopy].operands.push(OperandExecutionScope, "'Scope'");

-    InstructionDesc[OpAsyncGroupCopy].operands.push(OperandId, "'Destination'");

-    InstructionDesc[OpAsyncGroupCopy].operands.push(OperandId, "'Source'");

-    InstructionDesc[OpAsyncGroupCopy].operands.push(OperandId, "'Num Elements'");

-    InstructionDesc[OpAsyncGroupCopy].operands.push(OperandId, "'Stride'");

-    InstructionDesc[OpAsyncGroupCopy].operands.push(OperandId, "'Event'");

-

-    InstructionDesc[OpWaitGroupEvents].capabilities.push_back(CapKernel);

-    InstructionDesc[OpWaitGroupEvents].operands.push(OperandExecutionScope, "'Scope'");

-    InstructionDesc[OpWaitGroupEvents].operands.push(OperandId, "'Num Events'");

-    InstructionDesc[OpWaitGroupEvents].operands.push(OperandId, "'Events List'");

-

-    InstructionDesc[OpGroupAll].capabilities.push_back(CapKernel);

-    InstructionDesc[OpGroupAll].operands.push(OperandExecutionScope, "'Scope'");

-    InstructionDesc[OpGroupAll].operands.push(OperandId, "'Predicate'");

-

-    InstructionDesc[OpGroupAny].capabilities.push_back(CapKernel);

-    InstructionDesc[OpGroupAny].operands.push(OperandExecutionScope, "'Scope'");

-    InstructionDesc[OpGroupAny].operands.push(OperandId, "'Predicate'");

-

-    InstructionDesc[OpGroupBroadcast].capabilities.push_back(CapKernel);

-    InstructionDesc[OpGroupBroadcast].operands.push(OperandExecutionScope, "'Scope'");

-    InstructionDesc[OpGroupBroadcast].operands.push(OperandId, "'Value'");

-    InstructionDesc[OpGroupBroadcast].operands.push(OperandId, "'LocalId'");

-

-    InstructionDesc[OpGroupIAdd].capabilities.push_back(CapKernel);

-    InstructionDesc[OpGroupIAdd].operands.push(OperandExecutionScope, "'Scope'");

-    InstructionDesc[OpGroupIAdd].operands.push(OperandGroupOperation, "'Operation'");

-    InstructionDesc[OpGroupIAdd].operands.push(OperandId, "'X'");

-

-    InstructionDesc[OpGroupFAdd].capabilities.push_back(CapKernel);

-    InstructionDesc[OpGroupFAdd].operands.push(OperandExecutionScope, "'Scope'");

-    InstructionDesc[OpGroupFAdd].operands.push(OperandGroupOperation, "'Operation'");

-    InstructionDesc[OpGroupFAdd].operands.push(OperandId, "'X'");

-

-    InstructionDesc[OpGroupUMin].capabilities.push_back(CapKernel);

-    InstructionDesc[OpGroupUMin].operands.push(OperandExecutionScope, "'Scope'");

-    InstructionDesc[OpGroupUMin].operands.push(OperandGroupOperation, "'Operation'");

-    InstructionDesc[OpGroupUMin].operands.push(OperandId, "'X'");

-

-    InstructionDesc[OpGroupSMin].capabilities.push_back(CapKernel);

-    InstructionDesc[OpGroupSMin].operands.push(OperandExecutionScope, "'Scope'");

-    InstructionDesc[OpGroupSMin].operands.push(OperandGroupOperation, "'Operation'");

-    InstructionDesc[OpGroupSMin].operands.push(OperandId, "X");

-

-    InstructionDesc[OpGroupFMin].capabilities.push_back(CapKernel);

-    InstructionDesc[OpGroupFMin].operands.push(OperandExecutionScope, "'Scope'");

-    InstructionDesc[OpGroupFMin].operands.push(OperandGroupOperation, "'Operation'");

-    InstructionDesc[OpGroupFMin].operands.push(OperandId, "X");

-

-    InstructionDesc[OpGroupUMax].capabilities.push_back(CapKernel);

-    InstructionDesc[OpGroupUMax].operands.push(OperandExecutionScope, "'Scope'");

-    InstructionDesc[OpGroupUMax].operands.push(OperandGroupOperation, "'Operation'");

-    InstructionDesc[OpGroupUMax].operands.push(OperandId, "X");

-

-    InstructionDesc[OpGroupSMax].capabilities.push_back(CapKernel);

-    InstructionDesc[OpGroupSMax].operands.push(OperandExecutionScope, "'Scope'");

-    InstructionDesc[OpGroupSMax].operands.push(OperandGroupOperation, "'Operation'");

-    InstructionDesc[OpGroupSMax].operands.push(OperandId, "X");

-

-    InstructionDesc[OpGroupFMax].capabilities.push_back(CapKernel);

-    InstructionDesc[OpGroupFMax].operands.push(OperandExecutionScope, "'Scope'");

-    InstructionDesc[OpGroupFMax].operands.push(OperandGroupOperation, "'Operation'");

-    InstructionDesc[OpGroupFMax].operands.push(OperandId, "X");

-

-    InstructionDesc[OpReadPipe].capabilities.push_back(CapKernel);

-    InstructionDesc[OpReadPipe].operands.push(OperandId, "'p'");

-    InstructionDesc[OpReadPipe].operands.push(OperandId, "'ptr'");

-

-    InstructionDesc[OpWritePipe].capabilities.push_back(CapKernel);

-    InstructionDesc[OpWritePipe].operands.push(OperandId, "'p'");

-    InstructionDesc[OpWritePipe].operands.push(OperandId, "'ptr'");

-

-    InstructionDesc[OpReservedReadPipe].capabilities.push_back(CapKernel);

-    InstructionDesc[OpReservedReadPipe].operands.push(OperandId, "'p'");

-    InstructionDesc[OpReservedReadPipe].operands.push(OperandId, "'reserve_id'");

-    InstructionDesc[OpReservedReadPipe].operands.push(OperandId, "'index'");

-    InstructionDesc[OpReservedReadPipe].operands.push(OperandId, "'ptr'");

-

-    InstructionDesc[OpReservedWritePipe].capabilities.push_back(CapKernel);

-    InstructionDesc[OpReservedWritePipe].operands.push(OperandId, "'p'");

-    InstructionDesc[OpReservedWritePipe].operands.push(OperandId, "'reserve_id'");

-    InstructionDesc[OpReservedWritePipe].operands.push(OperandId, "'index'");

-    InstructionDesc[OpReservedWritePipe].operands.push(OperandId, "'ptr'");

-

-    InstructionDesc[OpReserveReadPipePackets].capabilities.push_back(CapKernel);

-    InstructionDesc[OpReserveReadPipePackets].operands.push(OperandId, "'p'");

-    InstructionDesc[OpReserveReadPipePackets].operands.push(OperandId, "'num_packets'");

-

-    InstructionDesc[OpReserveWritePipePackets].capabilities.push_back(CapKernel);

-    InstructionDesc[OpReserveWritePipePackets].operands.push(OperandId, "'p'");

-    InstructionDesc[OpReserveWritePipePackets].operands.push(OperandId, "'num_packets'");

-

-    InstructionDesc[OpCommitReadPipe].capabilities.push_back(CapKernel);

-    InstructionDesc[OpCommitReadPipe].operands.push(OperandId, "'p'");

-    InstructionDesc[OpCommitReadPipe].operands.push(OperandId, "'reserve_id'");

-

-    InstructionDesc[OpCommitWritePipe].capabilities.push_back(CapKernel);

-    InstructionDesc[OpCommitWritePipe].operands.push(OperandId, "'p'");

-    InstructionDesc[OpCommitWritePipe].operands.push(OperandId, "'reserve_id'");

-

-    InstructionDesc[OpIsValidReserveId].capabilities.push_back(CapKernel);

-    InstructionDesc[OpIsValidReserveId].operands.push(OperandId, "'reserve_id'");

-

-    InstructionDesc[OpGetNumPipePackets].capabilities.push_back(CapKernel);

-    InstructionDesc[OpGetNumPipePackets].operands.push(OperandId, "'p'");

-

-    InstructionDesc[OpGetMaxPipePackets].capabilities.push_back(CapKernel);

-    InstructionDesc[OpGetMaxPipePackets].operands.push(OperandId, "'p'");

-

-    InstructionDesc[OpGroupReserveReadPipePackets].capabilities.push_back(CapKernel);

-    InstructionDesc[OpGroupReserveReadPipePackets].operands.push(OperandExecutionScope, "'Scope'");

-    InstructionDesc[OpGroupReserveReadPipePackets].operands.push(OperandId, "'p'");

-    InstructionDesc[OpGroupReserveReadPipePackets].operands.push(OperandId, "'num_packets'");

-

-    InstructionDesc[OpGroupReserveWritePipePackets].capabilities.push_back(CapKernel);

-    InstructionDesc[OpGroupReserveWritePipePackets].operands.push(OperandExecutionScope, "'Scope'");

-    InstructionDesc[OpGroupReserveWritePipePackets].operands.push(OperandId, "'p'");

-    InstructionDesc[OpGroupReserveWritePipePackets].operands.push(OperandId, "'num_packets'");

-

-    InstructionDesc[OpGroupCommitReadPipe].capabilities.push_back(CapKernel);

-    InstructionDesc[OpGroupCommitReadPipe].operands.push(OperandExecutionScope, "'Scope'");

-    InstructionDesc[OpGroupCommitReadPipe].operands.push(OperandId, "'p'");

-    InstructionDesc[OpGroupCommitReadPipe].operands.push(OperandId, "'reserve_id'");

-

-    InstructionDesc[OpGroupCommitWritePipe].capabilities.push_back(CapKernel);

-    InstructionDesc[OpGroupCommitWritePipe].operands.push(OperandExecutionScope, "'Scope'");

-    InstructionDesc[OpGroupCommitWritePipe].operands.push(OperandId, "'p'");

-    InstructionDesc[OpGroupCommitWritePipe].operands.push(OperandId, "'reserve_id'");

-

-    InstructionDesc[OpBuildNDRange].capabilities.push_back(CapKernel);

-    InstructionDesc[OpBuildNDRange].operands.push(OperandId, "'GlobalWorkSize'");

-    InstructionDesc[OpBuildNDRange].operands.push(OperandId, "'LocalWorkSize'");

-    InstructionDesc[OpBuildNDRange].operands.push(OperandId, "'GlobalWorkOffset'");

-

-    InstructionDesc[OpGetDefaultQueue].capabilities.push_back(CapKernel);

-

-    InstructionDesc[OpCaptureEventProfilingInfo].capabilities.push_back(CapKernel);

-

-    InstructionDesc[OpCaptureEventProfilingInfo].operands.push(OperandId, "'event'");

-    InstructionDesc[OpCaptureEventProfilingInfo].operands.push(OperandKernelProfilingInfo, "'info'");

-    InstructionDesc[OpCaptureEventProfilingInfo].operands.push(OperandId, "'value'");

-

-    InstructionDesc[OpSetUserEventStatus].capabilities.push_back(CapKernel);

-

-    InstructionDesc[OpSetUserEventStatus].operands.push(OperandId, "'event'");

-    InstructionDesc[OpSetUserEventStatus].operands.push(OperandId, "'status'");

-

-    InstructionDesc[OpIsValidEvent].capabilities.push_back(CapKernel);

-    InstructionDesc[OpIsValidEvent].operands.push(OperandId, "'event'");

-

-    InstructionDesc[OpCreateUserEvent].capabilities.push_back(CapKernel);

-

-    InstructionDesc[OpRetainEvent].capabilities.push_back(CapKernel);

-    InstructionDesc[OpRetainEvent].operands.push(OperandId, "'event'");

-

-    InstructionDesc[OpReleaseEvent].capabilities.push_back(CapKernel);

-    InstructionDesc[OpReleaseEvent].operands.push(OperandId, "'event'");

-

-    InstructionDesc[OpGetKernelWorkGroupSize].capabilities.push_back(CapKernel);

-    InstructionDesc[OpGetKernelWorkGroupSize].operands.push(OperandId, "'Invoke'");

-

-    InstructionDesc[OpGetKernelPreferredWorkGroupSizeMultiple].capabilities.push_back(CapKernel);

-    InstructionDesc[OpGetKernelPreferredWorkGroupSizeMultiple].operands.push(OperandId, "'Invoke'");

-

-    InstructionDesc[OpGetKernelNDrangeSubGroupCount].capabilities.push_back(CapKernel);

-    InstructionDesc[OpGetKernelNDrangeSubGroupCount].operands.push(OperandId, "'ND Range'");

-    InstructionDesc[OpGetKernelNDrangeSubGroupCount].operands.push(OperandId, "'Invoke'");

-

-    InstructionDesc[OpGetKernelNDrangeMaxSubGroupSize].capabilities.push_back(CapKernel);

-    InstructionDesc[OpGetKernelNDrangeMaxSubGroupSize].operands.push(OperandId, "'ND Range'");

-    InstructionDesc[OpGetKernelNDrangeMaxSubGroupSize].operands.push(OperandId, "'Invoke'");

-

-    InstructionDesc[OpEnqueueKernel].capabilities.push_back(CapKernel);

-    InstructionDesc[OpEnqueueKernel].operands.push(OperandId, "'q'");

-    InstructionDesc[OpEnqueueKernel].operands.push(OperandKernelEnqueueFlags, "'flags'");

-    InstructionDesc[OpEnqueueKernel].operands.push(OperandId, "'ND Range'");

-    InstructionDesc[OpEnqueueKernel].operands.push(OperandId, "'Num Events'");

-    InstructionDesc[OpEnqueueKernel].operands.push(OperandId, "'Wait Events'");

-    InstructionDesc[OpEnqueueKernel].operands.push(OperandId, "'Ret Event'");

-    InstructionDesc[OpEnqueueKernel].operands.push(OperandId, "'Invoke'");

-    InstructionDesc[OpEnqueueKernel].operands.push(OperandId, "'Param'");

-    InstructionDesc[OpEnqueueKernel].operands.push(OperandId, "'Param Size'");

-    InstructionDesc[OpEnqueueKernel].operands.push(OperandId, "'Param Align'");

-    InstructionDesc[OpEnqueueKernel].operands.push(OperandVariableIds, "'Local Size'");

-

-    InstructionDesc[OpEnqueueMarker].capabilities.push_back(CapKernel);

-    InstructionDesc[OpEnqueueMarker].operands.push(OperandId, "'q'");

-    InstructionDesc[OpEnqueueMarker].operands.push(OperandId, "'Num Events'");

-    InstructionDesc[OpEnqueueMarker].operands.push(OperandId, "'Wait Events'");

-    InstructionDesc[OpEnqueueMarker].operands.push(OperandId, "'Ret Event'");

-}

-

-}; // end spv namespace

+//
+//Copyright (C) 2014 LunarG, Inc.
+//
+//All rights reserved.
+//
+//Redistribution and use in source and binary forms, with or without
+//modification, are permitted provided that the following conditions
+//are met:
+//
+//    Redistributions of source code must retain the above copyright
+//    notice, this list of conditions and the following disclaimer.
+//
+//    Redistributions in binary form must reproduce the above
+//    copyright notice, this list of conditions and the following
+//    disclaimer in the documentation and/or other materials provided
+//    with the distribution.
+//
+//    Neither the name of 3Dlabs Inc. Ltd. nor the names of its
+//    contributors may be used to endorse or promote products derived
+//    from this software without specific prior written permission.
+//
+//THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+//"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+//LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+//FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+//COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+//INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+//BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+//LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+//CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+//LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+//ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+//POSSIBILITY OF SUCH DAMAGE.
+
+//
+// Author: John Kessenich, LunarG
+//
+
+//
+// 1) Programatically fill in instruction/operand information.
+//    This can be used for disassembly, printing documentation, etc.
+//
+// 2) Print documentation from this parameterization.
+//
+
+#include "doc.h"
+
+#include <stdio.h>
+#include <string.h>
+#include <algorithm>
+
+namespace spv {
+
+//
+// Whole set of functions that translate enumerants to their text strings for
+// the specification (or their sanitized versions for auto-generating the
+// spirv.h header.
+//
+// Also, the ceilings are declared next to these, to help keep them in sync.
+// Ceilings should be
+//  - one more than the maximum value an enumerant takes on, for non-mask enumerants
+//    (for non-sparse enums, this is the number of enumurants)
+//  - the number of bits consumed by the set of masks
+//    (for non-sparse mask enums, this is the number of enumurants)
+//
+
+const int SourceLanguageCeiling = 4;
+
+const char* SourceString(int source)
+{
+    switch (source) {
+    case 0:  return "Unknown";
+    case 1:  return "ESSL";
+    case 2:  return "GLSL";
+    case 3:  return "OpenCL";
+
+    case SourceLanguageCeiling:
+    default: return "Bad";
+    }
+}
+
+const int ExecutionModelCeiling = 7;
+
+const char* ExecutionModelString(int model)
+{
+    switch (model) {
+    case 0:  return "Vertex";
+    case 1:  return "TessellationControl";
+    case 2:  return "TessellationEvaluation";
+    case 3:  return "Geometry";
+    case 4:  return "Fragment";
+    case 5:  return "GLCompute";
+    case 6:  return "Kernel";
+
+    case ExecutionModelCeiling:
+    default: return "Bad";
+    }
+}
+
+const int AddressingModelCeiling = 3;
+
+const char* AddressingString(int addr)
+{
+    switch (addr) {
+    case 0:  return "Logical";
+    case 1:  return "Physical32";
+    case 2:  return "Physical64";
+
+    case AddressingModelCeiling:
+    default: return "Bad";
+    }
+}
+
+const int MemoryModelCeiling = 5;
+
+const char* MemoryString(int mem)
+{
+    switch (mem) {
+    case 0:  return "Simple";
+    case 1:  return "GLSL450";
+    case 2:  return "OpenCL1.2";
+    case 3:  return "OpenCL2.0";
+    case 4:  return "OpenCL2.1";
+
+    case MemoryModelCeiling:
+    default: return "Bad";
+    }
+}
+
+const int ExecutionModeCeiling = 31;
+
+const char* ExecutionModeString(int mode)
+{
+    switch (mode) {
+    case 0:  return "Invocations";
+    case 1:  return "SpacingEqual";
+    case 2:  return "SpacingFractionalEven";
+    case 3:  return "SpacingFractionalOdd";
+    case 4:  return "VertexOrderCw";
+    case 5:  return "VertexOrderCcw";
+    case 6:  return "PixelCenterInteger";
+    case 7:  return "OriginUpperLeft";
+    case 8:  return "EarlyFragmentTests";
+    case 9:  return "PointMode";
+    case 10: return "Xfb";
+    case 11: return "DepthReplacing";
+    case 12: return "DepthAny";
+    case 13: return "DepthGreater";
+    case 14: return "DepthLess";
+    case 15: return "DepthUnchanged";
+    case 16: return "LocalSize";
+    case 17: return "LocalSizeHint";
+    case 18: return "InputPoints";
+    case 19: return "InputLines";
+    case 20: return "InputLinesAdjacency";
+    case 21: return "InputTriangles";
+    case 22: return "InputTrianglesAdjacency";
+    case 23: return "InputQuads";
+    case 24: return "InputIsolines";
+    case 25: return "OutputVertices";
+    case 26: return "OutputPoints";
+    case 27: return "OutputLineStrip";
+    case 28: return "OutputTriangleStrip";
+    case 29: return "VecTypeHint";
+    case 30: return "ContractionOff";
+
+    case ExecutionModeCeiling:
+    default: return "Bad";
+    }
+}
+
+const int StorageClassCeiling = 11;
+
+const char* StorageClassString(int StorageClass)
+{
+    switch (StorageClass) {
+    case 0:  return "UniformConstant";
+    case 1:  return "Input";
+    case 2:  return "Uniform";
+    case 3:  return "Output";
+    case 4:  return "WorkgroupLocal";
+    case 5:  return "WorkgroupGlobal";
+    case 6:  return "PrivateGlobal";
+    case 7:  return "Function";
+    case 8:  return "Generic";
+    case 9:  return "Private";
+    case 10: return "AtomicCounter";
+
+    case StorageClassCeiling:
+    default: return "Bad";
+    }
+}
+
+const int DecorationCeiling = 45;
+
+const char* DecorationString(int decoration)
+{
+    switch (decoration) {
+    case 0:  return "PrecisionLow";
+    case 1:  return "PrecisionMedium";
+    case 2:  return "PrecisionHigh";
+    case 3:  return "Block";
+    case 4:  return "BufferBlock";
+    case 5:  return "RowMajor";
+    case 6:  return "ColMajor";
+    case 7:  return "GLSLShared";
+    case 8:  return "GLSLStd140";
+    case 9:  return "GLSLStd430";
+    case 10: return "GLSLPacked";
+    case 11: return "Smooth";
+    case 12: return "Noperspective";
+    case 13: return "Flat";
+    case 14: return "Patch";
+    case 15: return "Centroid";
+    case 16: return "Sample";
+    case 17: return "Invariant";
+    case 18: return "Restrict";
+    case 19: return "Aliased";
+    case 20: return "Volatile";
+    case 21: return "Constant";
+    case 22: return "Coherent";
+    case 23: return "Nonwritable";
+    case 24: return "Nonreadable";
+    case 25: return "Uniform";
+    case 26: return "NoStaticUse";
+    case 27: return "CPacked";
+    case 28: return "SaturatedConversion";
+    case 29: return "Stream";
+    case 30: return "Location";
+    case 31: return "Component";
+    case 32: return "Index";
+    case 33: return "Binding";
+    case 34: return "DescriptorSet";
+    case 35: return "Offset";
+    case 36: return "Alignment";
+    case 37: return "XfbBuffer";
+    case 38: return "Stride";
+    case 39: return "BuiltIn";
+    case 40: return "FuncParamAttr";
+    case 41: return "FP Rounding Mode";
+    case 42: return "FP Fast Math Mode";
+    case 43: return "Linkage Attributes";
+    case 44: return "SpecId";
+
+    case DecorationCeiling:
+    default:  return "Bad";
+    }
+}
+
+const int BuiltInCeiling = 42;
+
+const char* BuiltInString(int builtIn)
+{
+    switch (builtIn) {
+    case 0:  return "Position";
+    case 1:  return "PointSize";
+    case 2:  return "ClipVertex";
+    case 3:  return "ClipDistance";
+    case 4:  return "CullDistance";
+    case 5:  return "VertexId";
+    case 6:  return "InstanceId";
+    case 7:  return "PrimitiveId";
+    case 8:  return "InvocationId";
+    case 9:  return "Layer";
+    case 10: return "ViewportIndex";
+    case 11: return "TessLevelOuter";
+    case 12: return "TessLevelInner";
+    case 13: return "TessCoord";
+    case 14: return "PatchVertices";
+    case 15: return "FragCoord";
+    case 16: return "PointCoord";
+    case 17: return "FrontFacing";
+    case 18: return "SampleId";
+    case 19: return "SamplePosition";
+    case 20: return "SampleMask";
+    case 21: return "FragColor";
+    case 22: return "FragDepth";
+    case 23: return "HelperInvocation";
+    case 24: return "NumWorkgroups";
+    case 25: return "WorkgroupSize";
+    case 26: return "WorkgroupId";
+    case 27: return "LocalInvocationId";
+    case 28: return "GlobalInvocationId";
+    case 29: return "LocalInvocationIndex";
+    case 30: return "WorkDim";
+    case 31: return "GlobalSize";
+    case 32: return "EnqueuedWorkgroupSize";
+    case 33: return "GlobalOffset";
+    case 34: return "GlobalLinearId";
+    case 35: return "WorkgroupLinearId";
+    case 36: return "SubgroupSize";
+    case 37: return "SubgroupMaxSize";
+    case 38: return "NumSubgroups";
+    case 39: return "NumEnqueuedSubgroups";
+    case 40: return "SubgroupId";
+    case 41: return "SubgroupLocalInvocationId";
+
+    case BuiltInCeiling:
+    default: return "Bad";
+    }
+}
+
+const int DimensionCeiling = 6;
+
+const char* DimensionString(int dim)
+{
+    switch (dim) {
+    case 0:  return "1D";
+    case 1:  return "2D";
+    case 2:  return "3D";
+    case 3:  return "Cube";
+    case 4:  return "Rect";
+    case 5:  return "Buffer";
+
+    case DimensionCeiling:
+    default: return "Bad";
+    }
+}
+
+const int SamplerAddressingModeCeiling = 5;
+
+const char* SamplerAddressingModeString(int mode)
+{
+    switch (mode) {
+    case 0:  return "None";
+    case 1:  return "ClampToEdge";
+    case 2:  return "Clamp";
+    case 3:  return "Repeat";
+    case 4:  return "RepeatMirrored";
+
+    case SamplerAddressingModeCeiling:
+    default: return "Bad";
+    }
+}
+
+const int SamplerFilterModeCeiling = 2;
+
+const char* SamplerFilterModeString(int mode)
+{
+    switch (mode) {
+    case 0: return "Nearest";
+    case 1: return "Linear";
+
+    case SamplerFilterModeCeiling:
+    default: return "Bad";
+    }
+}
+
+const int FPFastMathCeiling = 5;
+
+const char* FPFastMathString(int mode)
+{
+    switch (mode) {
+    case 0: return "NotNaN";
+    case 1: return "NotInf";
+    case 2: return "NSZ";
+    case 3: return "AllowRecip";
+    case 4: return "Fast";
+
+    case FPFastMathCeiling:
+    default:     return "Bad";
+    }
+}
+
+const int FPRoundingModeCeiling = 4;
+
+const char* FPRoundingModeString(int mode)
+{
+    switch (mode) {
+    case 0:  return "RTE";
+    case 1:  return "RTZ";
+    case 2:  return "RTP";
+    case 3:  return "RTN";
+
+    case FPRoundingModeCeiling:
+    default: return "Bad";
+    }
+}
+
+const int LinkageTypeCeiling = 2;
+
+const char* LinkageTypeString(int type)
+{
+    switch (type) {
+    case 0:  return "Export";
+    case 1:  return "Import";
+
+    case LinkageTypeCeiling:
+    default: return "Bad";
+    }
+}
+
+const int FuncParamAttrCeiling = 9;
+
+const char* FuncParamAttrString(int attr)
+{
+    switch (attr) {
+    case 0:  return "Zext";
+    case 1:  return "Sext";
+    case 2:  return "ByVal";
+    case 3:  return "Sret";
+    case 4:  return "NoAlias";
+    case 5:  return "NoCapture";
+    case 6:  return "SVM";
+    case 7:  return "NoWrite";
+    case 8:  return "NoReadWrite";
+
+    case FuncParamAttrCeiling:
+    default: return "Bad";
+    }
+}
+
+const int AccessQualifierCeiling = 3;
+
+const char* AccessQualifierString(int attr)
+{
+    switch (attr) {
+    case 0:  return "ReadOnly";
+    case 1:  return "WriteOnly";
+    case 2:  return "ReadWrite";
+
+    case AccessQualifierCeiling:
+    default: return "Bad";
+    }
+}
+
+const int SelectControlCeiling = 2;
+
+const char* SelectControlString(int cont)
+{
+    switch (cont) {
+    case 0:  return "Flatten";
+    case 1:  return "DontFlatten";
+
+    case SelectControlCeiling:
+    default:                       return "Bad";
+    }
+}
+
+const int LoopControlCeiling = 2;
+
+const char* LoopControlString(int cont)
+{
+    switch (cont) {
+    case 0: return "Unroll";
+    case 1: return "DontUnroll";
+
+    case LoopControlCeiling:
+    default:     return "Bad";
+    }
+}
+
+const int FunctionControlCeiling = 4;
+
+const char* FunctionControlString(int cont)
+{
+    switch (cont) {
+    case 0:  return "Inline";
+    case 1:  return "DontInline";
+    case 2:  return "Pure";
+    case 3:  return "Const";
+
+    case FunctionControlCeiling:
+    default: return "Bad";
+    }
+}
+
+const int MemorySemanticsCeiling = 10;
+
+const char* MemorySemanticsString(int mem)
+{
+    switch (mem) {
+    case 0: return "Relaxed";
+    case 1: return "SequentiallyConsistent";
+    case 2: return "Acquire";
+    case 3: return "Release";
+
+    case 4: return "UniformMemory";
+    case 5: return "SubgroupMemory";
+    case 6: return "WorkgroupLocalMemory";
+    case 7: return "WorkgroupGlobalMemory";
+    case 8: return "AtomicCounterMemory";
+    case 9: return "ImageMemory";
+
+    case MemorySemanticsCeiling:
+    default:     return "Bad";
+    }
+}
+
+const int MemoryAccessCeiling = 2;
+
+const char* MemoryAccessString(int mem)
+{
+    switch (mem) {
+    case 0:  return "Volatile";
+    case 1:  return "Aligned";
+
+    case MemoryAccessCeiling:
+    default: return "Bad";
+    }
+}
+
+const int ExecutionScopeCeiling = 4;
+
+const char* ExecutionScopeString(int mem)
+{
+    switch (mem) {
+    case 0:  return "CrossDevice";
+    case 1:  return "Device";
+    case 2:  return "Workgroup";
+    case 3:  return "Subgroup";
+
+    case ExecutionScopeCeiling:
+    default: return "Bad";
+    }
+}
+
+const int GroupOperationCeiling = 3;
+
+const char* GroupOperationString(int gop)
+{
+
+    switch (gop)
+    {
+    case 0:  return "Reduce";
+    case 1:  return "InclusiveScan";
+    case 2:  return "ExclusiveScan";
+
+    case GroupOperationCeiling:
+    default: return "Bad";
+    }
+}
+
+const int KernelEnqueueFlagsCeiling = 3;
+
+const char* KernelEnqueueFlagsString(int flag)
+{
+    switch (flag)
+    {
+    case 0:  return "NoWait";
+    case 1:  return "WaitKernel";
+    case 2:  return "WaitWorkGroup";
+
+    case KernelEnqueueFlagsCeiling:
+    default: return "Bad";
+    }
+}
+
+const int KernelProfilingInfoCeiling = 1;
+
+const char* KernelProfilingInfoString(int info)
+{
+    switch (info)
+    {
+    case 0:  return "CmdExecTime";
+
+    case KernelProfilingInfoCeiling:
+    default: return "Bad";
+    }
+}
+
+const char* OpcodeString(int op)
+{
+    switch (op) {
+    case 0:   return "OpNop";
+    case 1:   return "OpSource";
+    case 2:   return "OpSourceExtension";
+    case 3:   return "OpExtension";
+    case 4:   return "OpExtInstImport";
+    case 5:   return "OpMemoryModel";
+    case 6:   return "OpEntryPoint";
+    case 7:   return "OpExecutionMode";
+    case 8:   return "OpTypeVoid";
+    case 9:   return "OpTypeBool";
+    case 10:  return "OpTypeInt";
+    case 11:  return "OpTypeFloat";
+    case 12:  return "OpTypeVector";
+    case 13:  return "OpTypeMatrix";
+    case 14:  return "OpTypeSampler";
+    case 15:  return "OpTypeFilter";
+    case 16:  return "OpTypeArray";
+    case 17:  return "OpTypeRuntimeArray";
+    case 18:  return "OpTypeStruct";
+    case 19:  return "OpTypeOpaque";
+    case 20:  return "OpTypePointer";
+    case 21:  return "OpTypeFunction";
+    case 22:  return "OpTypeEvent";
+    case 23:  return "OpTypeDeviceEvent";
+    case 24:  return "OpTypeReserveId";
+    case 25:  return "OpTypeQueue";
+    case 26:  return "OpTypePipe";
+    case 27:  return "OpConstantTrue";
+    case 28:  return "OpConstantFalse";
+    case 29:  return "OpConstant";
+    case 30:  return "OpConstantComposite";
+    case 31:  return "OpConstantSampler";
+    case 32:  return "OpConstantNullPointer";
+    case 33:  return "OpConstantNullObject";
+    case 34:  return "OpSpecConstantTrue";
+    case 35:  return "OpSpecConstantFalse";
+    case 36:  return "OpSpecConstant";
+    case 37:  return "OpSpecConstantComposite";
+    case 38:  return "OpVariable";
+    case 39:  return "OpVariableArray";
+    case 40:  return "OpFunction";
+    case 41:  return "OpFunctionParameter";
+    case 42:  return "OpFunctionEnd";
+    case 43:  return "OpFunctionCall";
+    case 44:  return "OpExtInst";
+    case 45:  return "OpUndef";
+    case 46:  return "OpLoad";
+    case 47:  return "OpStore";
+    case 48:  return "OpPhi";
+    case 49:  return "OpDecorationGroup";
+    case 50:  return "OpDecorate";
+    case 51:  return "OpMemberDecorate";
+    case 52:  return "OpGroupDecorate";
+    case 53:  return "OpGroupMemberDecorate";
+    case 54:  return "OpName";
+    case 55:  return "OpMemberName";
+    case 56:  return "OpString";
+    case 57:  return "OpLine";
+    case 58:  return "OpVectorExtractDynamic";
+    case 59:  return "OpVectorInsertDynamic";
+    case 60:  return "OpVectorShuffle";
+    case 61:  return "OpCompositeConstruct";
+    case 62:  return "OpCompositeExtract";
+    case 63:  return "OpCompositeInsert";
+    case 64:  return "OpCopyObject";
+    case 65:  return "OpCopyMemory";
+    case 66:  return "OpCopyMemorySized";
+    case 67:  return "OpSampler";
+    case 68:  return "OpTextureSample";
+    case 69:  return "OpTextureSampleDref";
+    case 70:  return "OpTextureSampleLod";
+    case 71:  return "OpTextureSampleProj";
+    case 72:  return "OpTextureSampleGrad";
+    case 73:  return "OpTextureSampleOffset";
+    case 74:  return "OpTextureSampleProjLod";
+    case 75:  return "OpTextureSampleProjGrad";
+    case 76:  return "OpTextureSampleLodOffset";
+    case 77:  return "OpTextureSampleProjOffset";
+    case 78:  return "OpTextureSampleGradOffset";
+    case 79:  return "OpTextureSampleProjLodOffset";
+    case 80:  return "OpTextureSampleProjGradOffset";
+    case 81:  return "OpTextureFetchTexelLod";
+    case 82:  return "OpTextureFetchTexelOffset";
+    case 83:  return "OpTextureFetchSample";
+    case 84:  return "OpTextureFetchTexel";
+    case 85:  return "OpTextureGather";
+    case 86:  return "OpTextureGatherOffset";
+    case 87:  return "OpTextureGatherOffsets";
+    case 88:  return "OpTextureQuerySizeLod";
+    case 89:  return "OpTextureQuerySize";
+    case 90:  return "OpTextureQueryLod";
+    case 91:  return "OpTextureQueryLevels";
+    case 92:  return "OpTextureQuerySamples";
+    case 93:  return "OpAccessChain";
+    case 94:  return "OpInBoundsAccessChain";
+    case 95:  return "OpSNegate";
+    case 96:  return "OpFNegate";
+    case 97:  return "OpNot";
+    case 98:  return "OpAny";
+    case 99:  return "OpAll";
+    case 100: return "OpConvertFToU";
+    case 101: return "OpConvertFToS";
+    case 102: return "OpConvertSToF";
+    case 103: return "OpConvertUToF";
+    case 104: return "OpUConvert";
+    case 105: return "OpSConvert";
+    case 106: return "OpFConvert";
+    case 107: return "OpConvertPtrToU";
+    case 108: return "OpConvertUToPtr";
+    case 109: return "OpPtrCastToGeneric";
+    case 110: return "OpGenericCastToPtr";
+    case 111: return "OpBitcast";
+    case 112: return "OpTranspose";
+    case 113: return "OpIsNan";
+    case 114: return "OpIsInf";
+    case 115: return "OpIsFinite";
+    case 116: return "OpIsNormal";
+    case 117: return "OpSignBitSet";
+    case 118: return "OpLessOrGreater";
+    case 119: return "OpOrdered";
+    case 120: return "OpUnordered";
+    case 121: return "OpArrayLength";
+    case 122: return "OpIAdd";
+    case 123: return "OpFAdd";
+    case 124: return "OpISub";
+    case 125: return "OpFSub";
+    case 126: return "OpIMul";
+    case 127: return "OpFMul";
+    case 128: return "OpUDiv";
+    case 129: return "OpSDiv";
+    case 130: return "OpFDiv";
+    case 131: return "OpUMod";
+    case 132: return "OpSRem";
+    case 133: return "OpSMod";
+    case 134: return "OpFRem";
+    case 135: return "OpFMod";
+    case 136: return "OpVectorTimesScalar";
+    case 137: return "OpMatrixTimesScalar";
+    case 138: return "OpVectorTimesMatrix";
+    case 139: return "OpMatrixTimesVector";
+    case 140: return "OpMatrixTimesMatrix";
+    case 141: return "OpOuterProduct";
+    case 142: return "OpDot";
+    case 143: return "OpShiftRightLogical";
+    case 144: return "OpShiftRightArithmetic";
+    case 145: return "OpShiftLeftLogical";
+    case 146: return "OpLogicalOr";
+    case 147: return "OpLogicalXor";
+    case 148: return "OpLogicalAnd";
+    case 149: return "OpBitwiseOr";
+    case 150: return "OpBitwiseXor";
+    case 151: return "OpBitwiseAnd";
+    case 152: return "OpSelect";
+    case 153: return "OpIEqual";
+    case 154: return "OpFOrdEqual";
+    case 155: return "OpFUnordEqual";
+    case 156: return "OpINotEqual";
+    case 157: return "OpFOrdNotEqual";
+    case 158: return "OpFUnordNotEqual";
+    case 159: return "OpULessThan";
+    case 160: return "OpSLessThan";
+    case 161: return "OpFOrdLessThan";
+    case 162: return "OpFUnordLessThan";
+    case 163: return "OpUGreaterThan";
+    case 164: return "OpSGreaterThan";
+    case 165: return "OpFOrdGreaterThan";
+    case 166: return "OpFUnordGreaterThan";
+    case 167: return "OpULessThanEqual";
+    case 168: return "OpSLessThanEqual";
+    case 169: return "OpFOrdLessThanEqual";
+    case 170: return "OpFUnordLessThanEqual";
+    case 171: return "OpUGreaterThanEqual";
+    case 172: return "OpSGreaterThanEqual";
+    case 173: return "OpFOrdGreaterThanEqual";
+    case 174: return "OpFUnordGreaterThanEqual";
+    case 175: return "OpDPdx";
+    case 176: return "OpDPdy";
+    case 177: return "OpFwidth";
+    case 178: return "OpDPdxFine";
+    case 179: return "OpDPdyFine";
+    case 180: return "OpFwidthFine";
+    case 181: return "OpDPdxCoarse";
+    case 182: return "OpDPdyCoarse";
+    case 183: return "OpFwidthCoarse";
+    case 184: return "OpEmitVertex";
+    case 185: return "OpEndPrimitive";
+    case 186: return "OpEmitStreamVertex";
+    case 187: return "OpEndStreamPrimitive";
+    case 188: return "OpControlBarrier";
+    case 189: return "OpMemoryBarrier";
+    case 190: return "OpImagePointer";
+    case 191: return "OpAtomicInit";
+    case 192: return "OpAtomicLoad";
+    case 193: return "OpAtomicStore";
+    case 194: return "OpAtomicExchange";
+    case 195: return "OpAtomicCompareExchange";
+    case 196: return "OpAtomicCompareExchangeWeak";
+    case 197: return "OpAtomicIIncrement";
+    case 198: return "OpAtomicIDecrement";
+    case 199: return "OpAtomicIAdd";
+    case 200: return "OpAtomicISub";
+    case 201: return "OpAtomicUMin";
+    case 202: return "OpAtomicUMax";
+    case 203: return "OpAtomicAnd";
+    case 204: return "OpAtomicOr";
+    case 205: return "OpAtomicXor";
+    case 206: return "OpLoopMerge";
+    case 207: return "OpSelectionMerge";
+    case 208: return "OpLabel";
+    case 209: return "OpBranch";
+    case 210: return "OpBranchConditional";
+    case 211: return "OpSwitch";
+    case 212: return "OpKill";
+    case 213: return "OpReturn";
+    case 214: return "OpReturnValue";
+    case 215: return "OpUnreachable";
+    case 216: return "OpLifetimeStart";
+    case 217: return "OpLifetimeStop";
+    case 218: return "OpCompileFlag";
+    case 219: return "OpAsyncGroupCopy";
+    case 220: return "OpWaitGroupEvents";
+    case 221: return "OpGroupAll";
+    case 222: return "OpGroupAny";
+    case 223: return "OpGroupBroadcast";
+    case 224: return "OpGroupIAdd";
+    case 225: return "OpGroupFAdd";
+    case 226: return "OpGroupFMin";
+    case 227: return "OpGroupUMin";
+    case 228: return "OpGroupSMin";
+    case 229: return "OpGroupFMax";
+    case 230: return "OpGroupUMax";
+    case 231: return "OpGroupSMax";
+    case 232: return "OpGenericCastToPtrExplicit";
+    case 233: return "OpGenericPtrMemSemantics";
+    case 234: return "OpReadPipe";
+    case 235: return "OpWritePipe";
+    case 236: return "OpReservedReadPipe";
+    case 237: return "OpReservedWritePipe";
+    case 238: return "OpReserveReadPipePackets";
+    case 239: return "OpReserveWritePipePackets";
+    case 240: return "OpCommitReadPipe";
+    case 241: return "OpCommitWritePipe";
+    case 242: return "OpIsValidReserveId";
+    case 243: return "OpGetNumPipePackets";
+    case 244: return "OpGetMaxPipePackets";
+    case 245: return "OpGroupReserveReadPipePackets";
+    case 246: return "OpGroupReserveWritePipePackets";
+    case 247: return "OpGroupCommitReadPipe";
+    case 248: return "OpGroupCommitWritePipe";
+    case 249: return "OpEnqueueMarker";
+    case 250: return "OpEnqueueKernel";
+    case 251: return "OpGetKernelNDrangeSubGroupCount";
+    case 252: return "OpGetKernelNDrangeMaxSubGroupSize";
+    case 253: return "OpGetKernelWorkGroupSize";
+    case 254: return "OpGetKernelPreferredWorkGroupSizeMultiple";
+    case 255: return "OpRetainEvent";
+    case 256: return "OpReleaseEvent";
+    case 257: return "OpCreateUserEvent";
+    case 258: return "OpIsValidEvent";
+    case 259: return "OpSetUserEventStatus";
+    case 260: return "OpCaptureEventProfilingInfo";
+    case 261: return "OpGetDefaultQueue";
+    case 262: return "OpBuildNDRange";
+    case 263: return "OpSatConvertSToU";
+    case 264: return "OpSatConvertUToS";
+    case 265: return "OpAtomicIMin";
+    case 266: return "OpAtomicIMax";
+
+    case OpcodeCeiling:
+    default:
+        return "Bad";
+    }
+}
+
+// The set of objects that hold all the instruction/operand
+// parameterization information.
+InstructionParameters InstructionDesc[OpcodeCeiling];
+OperandParameters ExecutionModeOperands[ExecutionModeCeiling];
+OperandParameters DecorationOperands[DecorationCeiling];
+
+EnumDefinition OperandClassParams[OperandCount];
+EnumParameters ExecutionModelParams[ExecutionModelCeiling];
+EnumParameters AddressingParams[AddressingModelCeiling];
+EnumParameters MemoryParams[MemoryModelCeiling];
+EnumParameters ExecutionModeParams[ExecutionModeCeiling];
+EnumParameters StorageParams[StorageClassCeiling];
+EnumParameters SamplerAddressingModeParams[SamplerAddressingModeCeiling];
+EnumParameters SamplerFilterModeParams[SamplerFilterModeCeiling];
+EnumParameters FPFastMathParams[FPFastMathCeiling];
+EnumParameters FPRoundingModeParams[FPRoundingModeCeiling];
+EnumParameters LinkageTypeParams[LinkageTypeCeiling];
+EnumParameters DecorationParams[DecorationCeiling];
+EnumParameters BuiltInParams[BuiltInCeiling];
+EnumParameters DimensionalityParams[DimensionCeiling];
+EnumParameters FuncParamAttrParams[FuncParamAttrCeiling];
+EnumParameters AccessQualifierParams[AccessQualifierCeiling];
+EnumParameters GroupOperationParams[GroupOperationCeiling];
+EnumParameters LoopControlParams[FunctionControlCeiling];
+EnumParameters SelectionControlParams[SelectControlCeiling];
+EnumParameters FunctionControlParams[FunctionControlCeiling];
+EnumParameters MemorySemanticsParams[MemorySemanticsCeiling];
+EnumParameters MemoryAccessParams[MemoryAccessCeiling];
+EnumParameters ExecutionScopeParams[ExecutionScopeCeiling];
+EnumParameters KernelEnqueueFlagsParams[KernelEnqueueFlagsCeiling];
+EnumParameters KernelProfilingInfoParams[KernelProfilingInfoCeiling];
+
+// Set up all the parameterizing descriptions of the opcodes, operands, etc.
+void Parameterize()
+{
+    static bool initialized = false;
+
+    // only do this once.
+    if (initialized)
+        return;
+
+    initialized = true;
+
+    // Exceptions to having a result <id> and a resulting type <id>.
+    // (Everything is initialized to have both).
+
+    InstructionDesc[OpNop].setResultAndType(false, false);
+    InstructionDesc[OpSource].setResultAndType(false, false);
+    InstructionDesc[OpSourceExtension].setResultAndType(false, false);
+    InstructionDesc[OpExtension].setResultAndType(false, false);
+    InstructionDesc[OpExtInstImport].setResultAndType(true, false);
+    InstructionDesc[OpMemoryModel].setResultAndType(false, false);
+    InstructionDesc[OpEntryPoint].setResultAndType(false, false);
+    InstructionDesc[OpExecutionMode].setResultAndType(false, false);
+    InstructionDesc[OpTypeVoid].setResultAndType(true, false);
+    InstructionDesc[OpTypeBool].setResultAndType(true, false);
+    InstructionDesc[OpTypeInt].setResultAndType(true, false);
+    InstructionDesc[OpTypeFloat].setResultAndType(true, false);
+    InstructionDesc[OpTypeVector].setResultAndType(true, false);
+    InstructionDesc[OpTypeMatrix].setResultAndType(true, false);
+    InstructionDesc[OpTypeSampler].setResultAndType(true, false);
+    InstructionDesc[OpTypeFilter].setResultAndType(true, false);
+    InstructionDesc[OpTypeArray].setResultAndType(true, false);
+    InstructionDesc[OpTypeRuntimeArray].setResultAndType(true, false);
+    InstructionDesc[OpTypeStruct].setResultAndType(true, false);
+    InstructionDesc[OpTypeOpaque].setResultAndType(true, false);
+    InstructionDesc[OpTypePointer].setResultAndType(true, false);
+    InstructionDesc[OpTypeFunction].setResultAndType(true, false);
+    InstructionDesc[OpTypeEvent].setResultAndType(true, false);
+    InstructionDesc[OpTypeDeviceEvent].setResultAndType(true, false);
+    InstructionDesc[OpTypeReserveId].setResultAndType(true, false);
+    InstructionDesc[OpTypeQueue].setResultAndType(true, false);
+    InstructionDesc[OpTypePipe].setResultAndType(true, false);
+    InstructionDesc[OpFunctionEnd].setResultAndType(false, false);
+    InstructionDesc[OpStore].setResultAndType(false, false);
+    InstructionDesc[OpDecorationGroup].setResultAndType(true, false);
+    InstructionDesc[OpDecorate].setResultAndType(false, false);
+    InstructionDesc[OpMemberDecorate].setResultAndType(false, false);
+    InstructionDesc[OpGroupDecorate].setResultAndType(false, false);
+    InstructionDesc[OpGroupMemberDecorate].setResultAndType(false, false);
+    InstructionDesc[OpName].setResultAndType(false, false);
+    InstructionDesc[OpMemberName].setResultAndType(false, false);
+    InstructionDesc[OpString].setResultAndType(true, false);
+    InstructionDesc[OpLine].setResultAndType(false, false);
+    InstructionDesc[OpCopyMemory].setResultAndType(false, false);
+    InstructionDesc[OpCopyMemorySized].setResultAndType(false, false);
+    InstructionDesc[OpEmitVertex].setResultAndType(false, false);
+    InstructionDesc[OpEndPrimitive].setResultAndType(false, false);
+    InstructionDesc[OpEmitStreamVertex].setResultAndType(false, false);
+    InstructionDesc[OpEndStreamPrimitive].setResultAndType(false, false);
+    InstructionDesc[OpControlBarrier].setResultAndType(false, false);
+    InstructionDesc[OpMemoryBarrier].setResultAndType(false, false);
+    InstructionDesc[OpAtomicInit].setResultAndType(false, false);
+    InstructionDesc[OpAtomicStore].setResultAndType(false, false);
+    InstructionDesc[OpLoopMerge].setResultAndType(false, false);
+    InstructionDesc[OpSelectionMerge].setResultAndType(false, false);
+    InstructionDesc[OpLabel].setResultAndType(true, false);
+    InstructionDesc[OpBranch].setResultAndType(false, false);
+    InstructionDesc[OpBranchConditional].setResultAndType(false, false);
+    InstructionDesc[OpSwitch].setResultAndType(false, false);
+    InstructionDesc[OpKill].setResultAndType(false, false);
+    InstructionDesc[OpReturn].setResultAndType(false, false);
+    InstructionDesc[OpReturnValue].setResultAndType(false, false);
+    InstructionDesc[OpUnreachable].setResultAndType(false, false);
+    InstructionDesc[OpLifetimeStart].setResultAndType(false, false);
+    InstructionDesc[OpLifetimeStop].setResultAndType(false, false);
+    InstructionDesc[OpCompileFlag].setResultAndType(false, false);
+    InstructionDesc[OpCommitReadPipe].setResultAndType(false, false);
+    InstructionDesc[OpCommitWritePipe].setResultAndType(false, false);
+    InstructionDesc[OpGroupCommitWritePipe].setResultAndType(false, false);
+    InstructionDesc[OpGroupCommitReadPipe].setResultAndType(false, false);
+    InstructionDesc[OpCaptureEventProfilingInfo].setResultAndType(false, false);
+    InstructionDesc[OpSetUserEventStatus].setResultAndType(false, false);
+    InstructionDesc[OpRetainEvent].setResultAndType(false, false);
+    InstructionDesc[OpReleaseEvent].setResultAndType(false, false);
+
+    // Specific additional context-dependent operands
+
+    ExecutionModeOperands[ExecutionModeInvocations].push(OperandLiteralNumber, "Number of invocations");
+
+    ExecutionModeOperands[ExecutionModeLocalSize].push(OperandLiteralNumber, "'x size'");
+    ExecutionModeOperands[ExecutionModeLocalSize].push(OperandLiteralNumber, "'y size'");
+    ExecutionModeOperands[ExecutionModeLocalSize].push(OperandLiteralNumber, "'z size'");
+
+    ExecutionModeOperands[ExecutionModeLocalSizeHint].push(OperandLiteralNumber, "'x size'");
+    ExecutionModeOperands[ExecutionModeLocalSizeHint].push(OperandLiteralNumber, "'y size'");
+    ExecutionModeOperands[ExecutionModeLocalSizeHint].push(OperandLiteralNumber, "'z size'");
+
+    ExecutionModeOperands[ExecutionModeOutputVertices].push(OperandLiteralNumber, "Vertex count");
+    ExecutionModeOperands[ExecutionModeVecTypeHint].push(OperandId, "Vector type");
+
+    DecorationOperands[DecorationStream].push(OperandLiteralNumber, "Stream number");
+    DecorationOperands[DecorationLocation].push(OperandLiteralNumber, "Location");
+    DecorationOperands[DecorationComponent].push(OperandLiteralNumber, "Component within a vector");
+    DecorationOperands[DecorationIndex].push(OperandLiteralNumber, "Index");
+    DecorationOperands[DecorationBinding].push(OperandLiteralNumber, "Binding point");
+    DecorationOperands[DecorationDescriptorSet].push(OperandLiteralNumber, "Descriptor set");
+    DecorationOperands[DecorationOffset].push(OperandLiteralNumber, "Byte offset");
+    DecorationOperands[DecorationAlignment].push(OperandLiteralNumber, "Declared alignment");
+    DecorationOperands[DecorationXfbBuffer].push(OperandLiteralNumber, "XFB Buffer number");
+    DecorationOperands[DecorationStride].push(OperandLiteralNumber, "Stride");
+    DecorationOperands[DecorationBuiltIn].push(OperandLiteralNumber, "See <<BuiltIn,*BuiltIn*>>");
+    DecorationOperands[DecorationFPRoundingMode].push(OperandFPRoundingMode, "floating-point rounding mode");
+    DecorationOperands[DecorationFPFastMathMode].push(OperandFPFastMath, "fast-math mode");
+    DecorationOperands[DecorationLinkageAttributes].push(OperandLiteralString, "name");
+    DecorationOperands[DecorationLinkageAttributes].push(OperandLinkageType, "linkage type");
+    DecorationOperands[DecorationFuncParamAttr].push(OperandFuncParamAttr, "function parameter attribute");
+    DecorationOperands[DecorationSpecId].push(OperandLiteralNumber, "Specialization Constant ID");
+
+    OperandClassParams[OperandSource].set(SourceLanguageCeiling, SourceString, 0);
+    OperandClassParams[OperandExecutionModel].set(ExecutionModelCeiling, ExecutionModelString, ExecutionModelParams);
+    OperandClassParams[OperandAddressing].set(AddressingModelCeiling, AddressingString, AddressingParams);
+    OperandClassParams[OperandMemory].set(MemoryModelCeiling, MemoryString, MemoryParams);
+    OperandClassParams[OperandExecutionMode].set(ExecutionModeCeiling, ExecutionModeString, ExecutionModeParams);
+    OperandClassParams[OperandExecutionMode].setOperands(ExecutionModeOperands);
+    OperandClassParams[OperandStorage].set(StorageClassCeiling, StorageClassString, StorageParams);
+    OperandClassParams[OperandDimensionality].set(DimensionCeiling, DimensionString, DimensionalityParams);
+    OperandClassParams[OperandSamplerAddressingMode].set(SamplerAddressingModeCeiling, SamplerAddressingModeString, SamplerAddressingModeParams);
+    OperandClassParams[OperandSamplerFilterMode].set(SamplerFilterModeCeiling, SamplerFilterModeString, SamplerFilterModeParams);
+    OperandClassParams[OperandFPFastMath].set(FPFastMathCeiling, FPFastMathString, FPFastMathParams, true);
+    OperandClassParams[OperandFPRoundingMode].set(FPRoundingModeCeiling, FPRoundingModeString, FPRoundingModeParams);
+    OperandClassParams[OperandLinkageType].set(LinkageTypeCeiling, LinkageTypeString, LinkageTypeParams);
+    OperandClassParams[OperandFuncParamAttr].set(FuncParamAttrCeiling, FuncParamAttrString, FuncParamAttrParams);
+    OperandClassParams[OperandAccessQualifier].set(AccessQualifierCeiling, AccessQualifierString, AccessQualifierParams);
+    OperandClassParams[OperandDecoration].set(DecorationCeiling, DecorationString, DecorationParams);
+    OperandClassParams[OperandDecoration].setOperands(DecorationOperands);
+    OperandClassParams[OperandBuiltIn].set(BuiltInCeiling, BuiltInString, BuiltInParams);
+    OperandClassParams[OperandSelect].set(SelectControlCeiling, SelectControlString, SelectionControlParams, true);
+    OperandClassParams[OperandLoop].set(LoopControlCeiling, LoopControlString, LoopControlParams, true);
+    OperandClassParams[OperandFunction].set(FunctionControlCeiling, FunctionControlString, FunctionControlParams, true);
+    OperandClassParams[OperandMemorySemantics].set(MemorySemanticsCeiling, MemorySemanticsString, MemorySemanticsParams, true);
+    OperandClassParams[OperandMemoryAccess].set(MemoryAccessCeiling, MemoryAccessString, MemoryAccessParams, true);
+    OperandClassParams[OperandExecutionScope].set(ExecutionScopeCeiling, ExecutionScopeString, ExecutionScopeParams);
+    OperandClassParams[OperandGroupOperation].set(GroupOperationCeiling, GroupOperationString, GroupOperationParams);
+    OperandClassParams[OperandKernelEnqueueFlags].set(KernelEnqueueFlagsCeiling, KernelEnqueueFlagsString, KernelEnqueueFlagsParams);
+    OperandClassParams[OperandKernelProfilingInfo].set(KernelProfilingInfoCeiling, KernelProfilingInfoString, KernelProfilingInfoParams, true);
+    OperandClassParams[OperandOpcode].set(OpcodeCeiling, OpcodeString, 0);
+
+    AddressingParams[AddressingModelPhysical32].caps.push_back(CapAddr);
+    AddressingParams[AddressingModelPhysical64].caps.push_back(CapAddr);
+
+    MemoryParams[MemoryModelSimple].caps.push_back(CapShader);
+    MemoryParams[MemoryModelGLSL450].caps.push_back(CapShader);
+    MemoryParams[MemoryModelOpenCL12].caps.push_back(CapKernel);
+    MemoryParams[MemoryModelOpenCL20].caps.push_back(CapKernel);
+    MemoryParams[MemoryModelOpenCL21].caps.push_back(CapKernel);
+
+    ExecutionModelParams[ExecutionModelVertex].caps.push_back(CapShader);
+    ExecutionModelParams[ExecutionModelTessellationControl].caps.push_back(CapTess);
+    ExecutionModelParams[ExecutionModelTessellationEvaluation].caps.push_back(CapTess);
+    ExecutionModelParams[ExecutionModelGeometry].caps.push_back(CapGeom);
+    ExecutionModelParams[ExecutionModelFragment].caps.push_back(CapShader);
+    ExecutionModelParams[ExecutionModelGLCompute].caps.push_back(CapShader);
+    ExecutionModelParams[ExecutionModelKernel].caps.push_back(CapKernel);
+
+    // Storage capabilites
+    StorageParams[StorageClassInput].caps.push_back(CapShader);
+    StorageParams[StorageClassUniform].caps.push_back(CapShader);
+    StorageParams[StorageClassOutput].caps.push_back(CapShader);
+    StorageParams[StorageClassPrivateGlobal].caps.push_back(CapShader);
+    StorageParams[StorageClassFunction].caps.push_back(CapShader);
+    StorageParams[StorageClassGeneric].caps.push_back(CapKernel);
+    StorageParams[StorageClassPrivate].caps.push_back(CapKernel);
+    StorageParams[StorageClassAtomicCounter].caps.push_back(CapShader);
+
+    // Sampler Filter & Addressing mode capabilities
+    SamplerAddressingModeParams[SamplerAddressingModeNone].caps.push_back(CapKernel);
+    SamplerAddressingModeParams[SamplerAddressingModeClampToEdge].caps.push_back(CapKernel);
+    SamplerAddressingModeParams[SamplerAddressingModeClamp].caps.push_back(CapKernel);
+    SamplerAddressingModeParams[SamplerAddressingModeRepeat].caps.push_back(CapKernel);
+    SamplerAddressingModeParams[SamplerAddressingModeRepeatMirrored].caps.push_back(CapKernel);
+
+    SamplerFilterModeParams[SamplerFilterModeNearest].caps.push_back(CapKernel);
+    SamplerFilterModeParams[SamplerFilterModeLinear].caps.push_back(CapKernel);
+
+    // fast math flags capabilities
+    for (int i = 0; i < FPFastMathCeiling; ++i) {
+        FPFastMathParams[i].caps.push_back(CapKernel);
+    }
+
+    // fp rounding mode capabilities
+    for (int i = 0; i < FPRoundingModeCeiling; ++i) {
+        FPRoundingModeParams[i].caps.push_back(CapKernel);
+    }
+
+    // linkage types
+    for (int i = 0; i < LinkageTypeCeiling; ++i) {
+        LinkageTypeParams[i].caps.push_back(CapLink);
+    }
+
+    // function argument types
+    for (int i = 0; i < FuncParamAttrCeiling; ++i) {
+        FuncParamAttrParams[i].caps.push_back(CapKernel);
+    }
+
+    // function argument types
+    for (int i = 0; i < AccessQualifierCeiling; ++i) {
+        AccessQualifierParams[i].caps.push_back(CapKernel);
+    }
+
+    ExecutionModeParams[ExecutionModeInvocations].caps.push_back(CapGeom);
+    ExecutionModeParams[ExecutionModeSpacingEqual].caps.push_back(CapTess);
+    ExecutionModeParams[ExecutionModeSpacingFractionalEven].caps.push_back(CapTess);
+    ExecutionModeParams[ExecutionModeSpacingFractionalOdd].caps.push_back(CapTess);
+    ExecutionModeParams[ExecutionModeVertexOrderCw].caps.push_back(CapTess);
+    ExecutionModeParams[ExecutionModeVertexOrderCcw].caps.push_back(CapTess);
+    ExecutionModeParams[ExecutionModePixelCenterInteger].caps.push_back(CapShader);
+    ExecutionModeParams[ExecutionModeOriginUpperLeft].caps.push_back(CapShader);
+    ExecutionModeParams[ExecutionModeEarlyFragmentTests].caps.push_back(CapShader);
+    ExecutionModeParams[ExecutionModePointMode].caps.push_back(CapTess);
+    ExecutionModeParams[ExecutionModeXfb].caps.push_back(CapShader);
+    ExecutionModeParams[ExecutionModeDepthReplacing].caps.push_back(CapShader);
+    ExecutionModeParams[ExecutionModeDepthAny].caps.push_back(CapShader);
+    ExecutionModeParams[ExecutionModeDepthGreater].caps.push_back(CapShader);
+    ExecutionModeParams[ExecutionModeDepthLess].caps.push_back(CapShader);
+    ExecutionModeParams[ExecutionModeDepthUnchanged].caps.push_back(CapShader);
+    ExecutionModeParams[ExecutionModeLocalSizeHint].caps.push_back(CapKernel);
+    ExecutionModeParams[ExecutionModeInputPoints].caps.push_back(CapGeom);
+    ExecutionModeParams[ExecutionModeInputLines].caps.push_back(CapGeom);
+    ExecutionModeParams[ExecutionModeInputLinesAdjacency].caps.push_back(CapGeom);
+    ExecutionModeParams[ExecutionModeInputTriangles].caps.push_back(CapGeom);
+    ExecutionModeParams[ExecutionModeInputTriangles].caps.push_back(CapTess);
+    ExecutionModeParams[ExecutionModeInputTrianglesAdjacency].caps.push_back(CapGeom);
+    ExecutionModeParams[ExecutionModeInputQuads].caps.push_back(CapTess);
+    ExecutionModeParams[ExecutionModeInputIsolines].caps.push_back(CapTess);
+    ExecutionModeParams[ExecutionModeOutputVertices].caps.push_back(CapGeom);
+    ExecutionModeParams[ExecutionModeOutputVertices].caps.push_back(CapTess);
+    ExecutionModeParams[ExecutionModeOutputPoints].caps.push_back(CapGeom);
+    ExecutionModeParams[ExecutionModeOutputLineStrip].caps.push_back(CapGeom);
+    ExecutionModeParams[ExecutionModeOutputTriangleStrip].caps.push_back(CapGeom);
+    ExecutionModeParams[ExecutionModeVecTypeHint].caps.push_back(CapKernel);
+    ExecutionModeParams[ExecutionModeContractionOff].caps.push_back(CapKernel);
+
+    DecorationParams[DecorationPrecisionLow].caps.push_back(CapShader);
+    DecorationParams[DecorationPrecisionMedium].caps.push_back(CapShader);
+    DecorationParams[DecorationPrecisionHigh].caps.push_back(CapShader);
+    DecorationParams[DecorationBlock].caps.push_back(CapShader);
+    DecorationParams[DecorationBufferBlock].caps.push_back(CapShader);
+    DecorationParams[DecorationRowMajor].caps.push_back(CapMatrix);
+    DecorationParams[DecorationColMajor].caps.push_back(CapMatrix);
+    DecorationParams[DecorationGLSLShared].caps.push_back(CapShader);
+    DecorationParams[DecorationGLSLStd140].caps.push_back(CapShader);
+    DecorationParams[DecorationGLSLStd430].caps.push_back(CapShader);
+    DecorationParams[DecorationGLSLPacked].caps.push_back(CapShader);
+    DecorationParams[DecorationSmooth].caps.push_back(CapShader);
+    DecorationParams[DecorationNoperspective].caps.push_back(CapShader);
+    DecorationParams[DecorationFlat].caps.push_back(CapShader);
+    DecorationParams[DecorationPatch].caps.push_back(CapTess);
+    DecorationParams[DecorationCentroid].caps.push_back(CapShader);
+    DecorationParams[DecorationSample].caps.push_back(CapShader);
+    DecorationParams[DecorationInvariant].caps.push_back(CapShader);
+    DecorationParams[DecorationConstant].caps.push_back(CapKernel);
+    DecorationParams[DecorationUniform].caps.push_back(CapShader);
+    DecorationParams[DecorationCPacked].caps.push_back(CapKernel);
+    DecorationParams[DecorationSaturatedConversion].caps.push_back(CapKernel);
+    DecorationParams[DecorationStream].caps.push_back(CapGeom);
+    DecorationParams[DecorationLocation].caps.push_back(CapShader);
+    DecorationParams[DecorationComponent].caps.push_back(CapShader);
+    DecorationParams[DecorationIndex].caps.push_back(CapShader);
+    DecorationParams[DecorationBinding].caps.push_back(CapShader);
+    DecorationParams[DecorationDescriptorSet].caps.push_back(CapShader);
+    DecorationParams[DecorationXfbBuffer].caps.push_back(CapShader);
+    DecorationParams[DecorationStride].caps.push_back(CapShader);
+    DecorationParams[DecorationBuiltIn].caps.push_back(CapShader);
+    DecorationParams[DecorationFuncParamAttr].caps.push_back(CapKernel);
+    DecorationParams[DecorationFPRoundingMode].caps.push_back(CapKernel);
+    DecorationParams[DecorationFPFastMathMode].caps.push_back(CapKernel);
+    DecorationParams[DecorationLinkageAttributes].caps.push_back(CapLink);
+    DecorationParams[DecorationSpecId].caps.push_back(CapShader);
+
+    BuiltInParams[BuiltInPosition].caps.push_back(CapShader);
+    BuiltInParams[BuiltInPointSize].caps.push_back(CapShader);
+    BuiltInParams[BuiltInClipVertex].caps.push_back(CapShader);
+    BuiltInParams[BuiltInClipDistance].caps.push_back(CapShader);
+    BuiltInParams[BuiltInCullDistance].caps.push_back(CapShader);
+    BuiltInParams[BuiltInVertexId].caps.push_back(CapShader);
+    BuiltInParams[BuiltInInstanceId].caps.push_back(CapShader);
+    BuiltInParams[BuiltInPrimitiveId].caps.push_back(CapGeom);
+    BuiltInParams[BuiltInPrimitiveId].caps.push_back(CapTess);
+    BuiltInParams[BuiltInInvocationId].caps.push_back(CapGeom);
+    BuiltInParams[BuiltInInvocationId].caps.push_back(CapTess);
+    BuiltInParams[BuiltInLayer].caps.push_back(CapGeom);
+    BuiltInParams[BuiltInViewportIndex].caps.push_back(CapGeom);
+    BuiltInParams[BuiltInTessLevelOuter].caps.push_back(CapTess);
+    BuiltInParams[BuiltInTessLevelInner].caps.push_back(CapTess);
+    BuiltInParams[BuiltInTessCoord].caps.push_back(CapTess);
+    BuiltInParams[BuiltInPatchVertices].caps.push_back(CapTess);
+    BuiltInParams[BuiltInFragCoord].caps.push_back(CapShader);
+    BuiltInParams[BuiltInPointCoord].caps.push_back(CapShader);
+    BuiltInParams[BuiltInFrontFacing].caps.push_back(CapShader);
+    BuiltInParams[BuiltInSampleId].caps.push_back(CapShader);
+    BuiltInParams[BuiltInSamplePosition].caps.push_back(CapShader);
+    BuiltInParams[BuiltInSampleMask].caps.push_back(CapShader);
+    BuiltInParams[BuiltInFragColor].caps.push_back(CapShader);
+    BuiltInParams[BuiltInFragDepth].caps.push_back(CapShader);
+    BuiltInParams[BuiltInHelperInvocation].caps.push_back(CapShader);
+    BuiltInParams[BuiltInLocalInvocationIndex].caps.push_back(CapShader);
+    BuiltInParams[BuiltInWorkDim].caps.push_back(CapKernel);
+    BuiltInParams[BuiltInGlobalSize].caps.push_back(CapKernel);
+    BuiltInParams[BuiltInEnqueuedWorkgroupSize].caps.push_back(CapKernel);
+    BuiltInParams[BuiltInGlobalOffset].caps.push_back(CapKernel);
+    BuiltInParams[BuiltInGlobalLinearId].caps.push_back(CapKernel);
+    BuiltInParams[BuiltInWorkgroupLinearId].caps.push_back(CapKernel);
+
+    BuiltInParams[BuiltInSubgroupSize].caps.push_back(CapKernel);
+    BuiltInParams[BuiltInSubgroupMaxSize].caps.push_back(CapKernel);
+    BuiltInParams[BuiltInNumSubgroups].caps.push_back(CapKernel);
+    BuiltInParams[BuiltInNumEnqueuedSubgroups].caps.push_back(CapKernel);
+    BuiltInParams[BuiltInSubgroupId].caps.push_back(CapKernel);
+    BuiltInParams[BuiltInSubgroupLocalInvocationId].caps.push_back(CapKernel);
+
+    DimensionalityParams[DimCube].caps.push_back(CapShader);
+    DimensionalityParams[DimRect].caps.push_back(CapShader);
+
+    // Group Operations
+    for (int i = 0; i < GroupOperationCeiling; ++i) {
+        GroupOperationParams[i].caps.push_back(CapKernel);
+    }
+
+    // Enqueue flags
+    for (int i = 0; i < KernelEnqueueFlagsCeiling; ++i) {
+        KernelEnqueueFlagsParams[i].caps.push_back(CapKernel);
+    }
+
+    // Profiling info
+    KernelProfilingInfoParams[0].caps.push_back(CapKernel);
+
+    // set name of operator, an initial set of <id> style operands, and the description
+
+    InstructionDesc[OpSource].operands.push(OperandSource, "");
+    InstructionDesc[OpSource].operands.push(OperandLiteralNumber, "'Version'");
+
+    InstructionDesc[OpSourceExtension].operands.push(OperandLiteralString, "'Extension'");
+
+    InstructionDesc[OpName].operands.push(OperandId, "'Target'");
+    InstructionDesc[OpName].operands.push(OperandLiteralString, "'Name'");
+
+    InstructionDesc[OpMemberName].operands.push(OperandId, "'Type'");
+    InstructionDesc[OpMemberName].operands.push(OperandLiteralNumber, "'Member'");
+    InstructionDesc[OpMemberName].operands.push(OperandLiteralString, "'Name'");
+
+    InstructionDesc[OpString].operands.push(OperandLiteralString, "'String'");
+
+    InstructionDesc[OpLine].operands.push(OperandId, "'Target'");
+    InstructionDesc[OpLine].operands.push(OperandId, "'File'");
+    InstructionDesc[OpLine].operands.push(OperandLiteralNumber, "'Line'");
+    InstructionDesc[OpLine].operands.push(OperandLiteralNumber, "'Column'");
+
+    InstructionDesc[OpExtension].operands.push(OperandLiteralString, "'Name'");
+
+    InstructionDesc[OpExtInstImport].operands.push(OperandLiteralString, "'Name'");
+
+    InstructionDesc[OpMemoryModel].operands.push(OperandAddressing, "");
+    InstructionDesc[OpMemoryModel].operands.push(OperandMemory, "");
+
+    InstructionDesc[OpEntryPoint].operands.push(OperandExecutionModel, "");
+    InstructionDesc[OpEntryPoint].operands.push(OperandId, "'Entry Point'");
+
+    InstructionDesc[OpExecutionMode].operands.push(OperandId, "'Entry Point'");
+    InstructionDesc[OpExecutionMode].operands.push(OperandExecutionMode, "'Mode'");
+    InstructionDesc[OpExecutionMode].operands.push(OperandVariableLiterals, "See <<Execution Mode,Execution Mode>>");
+
+    InstructionDesc[OpTypeInt].operands.push(OperandLiteralNumber, "'Width'");
+    InstructionDesc[OpTypeInt].operands.push(OperandLiteralNumber, "'Signedness'");
+
+    InstructionDesc[OpTypeFloat].operands.push(OperandLiteralNumber, "'Width'");
+
+    InstructionDesc[OpTypeVector].operands.push(OperandId, "'Component type'");
+    InstructionDesc[OpTypeVector].operands.push(OperandLiteralNumber, "'Component count'");
+
+    InstructionDesc[OpTypeMatrix].capabilities.push_back(CapMatrix);
+    InstructionDesc[OpTypeMatrix].operands.push(OperandId, "'Column type'");
+    InstructionDesc[OpTypeMatrix].operands.push(OperandLiteralNumber, "'Column count'");
+
+    InstructionDesc[OpTypeSampler].operands.push(OperandId, "'Sampled Type'");
+    InstructionDesc[OpTypeSampler].operands.push(OperandDimensionality, "");
+    InstructionDesc[OpTypeSampler].operands.push(OperandLiteralNumber, "'Content'");
+    InstructionDesc[OpTypeSampler].operands.push(OperandLiteralNumber, "'Arrayed'");
+    InstructionDesc[OpTypeSampler].operands.push(OperandLiteralNumber, "'Compare'");
+    InstructionDesc[OpTypeSampler].operands.push(OperandLiteralNumber, "'MS'");
+    InstructionDesc[OpTypeSampler].operands.push(OperandOptionalId, "'Qualifier'");
+
+    InstructionDesc[OpTypeArray].operands.push(OperandId, "'Element type'");
+    InstructionDesc[OpTypeArray].operands.push(OperandId, "'Length'");
+
+    InstructionDesc[OpTypeRuntimeArray].capabilities.push_back(CapShader);
+    InstructionDesc[OpTypeRuntimeArray].operands.push(OperandId, "'Element type'");
+
+    InstructionDesc[OpTypeStruct].operands.push(OperandVariableIds, "'Member 0 type', +\n'member 1 type', +\n...");
+
+    InstructionDesc[OpTypeOpaque].capabilities.push_back(CapKernel);
+    InstructionDesc[OpTypeOpaque].operands.push(OperandLiteralString, "The name of the opaque type.");
+
+    InstructionDesc[OpTypePointer].operands.push(OperandStorage, "");
+    InstructionDesc[OpTypePointer].operands.push(OperandId, "'Type'");
+
+    InstructionDesc[OpTypeEvent].capabilities.push_back(CapKernel);
+
+    InstructionDesc[OpTypeDeviceEvent].capabilities.push_back(CapKernel);
+
+    InstructionDesc[OpTypeReserveId].capabilities.push_back(CapKernel);
+
+    InstructionDesc[OpTypeQueue].capabilities.push_back(CapKernel);
+
+    InstructionDesc[OpTypePipe].operands.push(OperandId, "'Type'");
+    InstructionDesc[OpTypePipe].operands.push(OperandAccessQualifier, "'Qualifier'");
+    InstructionDesc[OpTypePipe].capabilities.push_back(CapKernel);
+
+    InstructionDesc[OpTypeFunction].operands.push(OperandId, "'Return Type'");
+    InstructionDesc[OpTypeFunction].operands.push(OperandVariableIds, "'Parameter 0 Type', +\n'Parameter 1 Type', +\n...");
+
+    InstructionDesc[OpConstant].operands.push(OperandVariableLiterals, "'Value'");
+
+    InstructionDesc[OpConstantComposite].operands.push(OperandVariableIds, "'Constituents'");
+
+    InstructionDesc[OpConstantNullPointer].capabilities.push_back(CapAddr);
+
+    InstructionDesc[OpConstantNullObject].capabilities.push_back(CapKernel);
+
+    InstructionDesc[OpConstantSampler].capabilities.push_back(CapKernel);
+    InstructionDesc[OpConstantSampler].operands.push(OperandLiteralNumber, "'Mode'");
+    InstructionDesc[OpConstantSampler].operands.push(OperandLiteralNumber, "'Param'");
+    InstructionDesc[OpConstantSampler].operands.push(OperandLiteralNumber, "'Filter'");
+
+    InstructionDesc[OpSpecConstantTrue].capabilities.push_back(CapShader);
+
+    InstructionDesc[OpSpecConstantFalse].capabilities.push_back(CapShader);
+
+    InstructionDesc[OpSpecConstant].operands.push(OperandVariableLiterals, "'Value'");
+    InstructionDesc[OpSpecConstant].capabilities.push_back(CapShader);
+
+    InstructionDesc[OpSpecConstantComposite].operands.push(OperandVariableIds, "'Constituents'");
+    InstructionDesc[OpSpecConstantComposite].capabilities.push_back(CapShader);
+
+    InstructionDesc[OpVariable].operands.push(OperandStorage, "");
+    InstructionDesc[OpVariable].operands.push(OperandOptionalId, "'Initializer'");
+
+    InstructionDesc[OpVariableArray].operands.push(OperandStorage, "");
+    InstructionDesc[OpVariableArray].operands.push(OperandId, "'N'");
+    InstructionDesc[OpVariableArray].capabilities.push_back(CapAddr);
+
+    InstructionDesc[OpFunction].operands.push(OperandFunction, "");
+    InstructionDesc[OpFunction].operands.push(OperandId, "'Function Type'");
+
+    InstructionDesc[OpFunctionCall].operands.push(OperandId, "'Function'");
+    InstructionDesc[OpFunctionCall].operands.push(OperandVariableIds, "'Argument 0', +\n'Argument 1', +\n...");
+
+    InstructionDesc[OpExtInst].operands.push(OperandId, "'Set'");
+    InstructionDesc[OpExtInst].operands.push(OperandLiteralNumber, "'Instruction'");
+    InstructionDesc[OpExtInst].operands.push(OperandVariableIds, "'Operand 1', +\n'Operand 2', +\n...");
+
+    InstructionDesc[OpLoad].operands.push(OperandId, "'Pointer'");
+    InstructionDesc[OpLoad].operands.push(OperandVariableLiterals, "'Memory Access'");
+
+    InstructionDesc[OpStore].operands.push(OperandId, "'Pointer'");
+    InstructionDesc[OpStore].operands.push(OperandId, "'Object'");
+    InstructionDesc[OpStore].operands.push(OperandVariableLiterals, "'Memory Access'");
+
+    InstructionDesc[OpPhi].operands.push(OperandVariableIds, "");
+
+    InstructionDesc[OpDecorate].operands.push(OperandId, "'Target'");
+    InstructionDesc[OpDecorate].operands.push(OperandDecoration, "");
+    InstructionDesc[OpDecorate].operands.push(OperandVariableLiterals, "See <<Decoration,'Decoration'>>.");
+
+    InstructionDesc[OpMemberDecorate].operands.push(OperandId, "'Structure type'");
+    InstructionDesc[OpMemberDecorate].operands.push(OperandLiteralNumber, "'Member'");
+    InstructionDesc[OpMemberDecorate].operands.push(OperandDecoration, "");
+    InstructionDesc[OpMemberDecorate].operands.push(OperandVariableLiterals, "See <<Decoration,'Decoration'>>.");
+
+    InstructionDesc[OpGroupDecorate].operands.push(OperandId, "'Decoration group'");
+    InstructionDesc[OpGroupDecorate].operands.push(OperandVariableIds, "'Target', 'Target', ...");
+
+    InstructionDesc[OpGroupMemberDecorate].operands.push(OperandId, "'Decoration group'");
+    InstructionDesc[OpGroupMemberDecorate].operands.push(OperandVariableIds, "'Target', 'Target', ...");
+
+    InstructionDesc[OpVectorExtractDynamic].operands.push(OperandId, "'Vector'");
+    InstructionDesc[OpVectorExtractDynamic].operands.push(OperandId, "'Index'");
+
+    InstructionDesc[OpVectorInsertDynamic].operands.push(OperandId, "'Vector'");
+    InstructionDesc[OpVectorInsertDynamic].operands.push(OperandId, "'Component'");
+    InstructionDesc[OpVectorInsertDynamic].operands.push(OperandId, "'Index'");
+
+    InstructionDesc[OpVectorShuffle].operands.push(OperandId, "'Vector 1'");
+    InstructionDesc[OpVectorShuffle].operands.push(OperandId, "'Vector 2'");
+    InstructionDesc[OpVectorShuffle].operands.push(OperandVariableLiterals, "'Components'");
+
+    InstructionDesc[OpCompositeConstruct].operands.push(OperandVariableIds, "'Constituents'");
+
+    InstructionDesc[OpCompositeExtract].operands.push(OperandId, "'Composite'");
+    InstructionDesc[OpCompositeExtract].operands.push(OperandVariableLiterals, "'Indexes'");
+
+    InstructionDesc[OpCompositeInsert].operands.push(OperandId, "'Object'");
+    InstructionDesc[OpCompositeInsert].operands.push(OperandId, "'Composite'");
+    InstructionDesc[OpCompositeInsert].operands.push(OperandVariableLiterals, "'Indexes'");
+
+    InstructionDesc[OpCopyObject].operands.push(OperandId, "'Operand'");
+
+    InstructionDesc[OpCopyMemory].operands.push(OperandId, "'Target'");
+    InstructionDesc[OpCopyMemory].operands.push(OperandId, "'Source'");
+    InstructionDesc[OpCopyMemory].operands.push(OperandVariableLiterals, "'Memory Access'");
+
+    InstructionDesc[OpCopyMemorySized].operands.push(OperandId, "'Target'");
+    InstructionDesc[OpCopyMemorySized].operands.push(OperandId, "'Source'");
+    InstructionDesc[OpCopyMemorySized].operands.push(OperandId, "'Size'");
+    InstructionDesc[OpCopyMemorySized].operands.push(OperandVariableLiterals, "'Memory Access'");
+
+    InstructionDesc[OpCopyMemorySized].capabilities.push_back(CapAddr);
+
+    InstructionDesc[OpSampler].operands.push(OperandId, "'Sampler'");
+    InstructionDesc[OpSampler].operands.push(OperandId, "'Filter'");
+
+    InstructionDesc[OpTextureSample].operands.push(OperandId, "'Sampler'");
+    InstructionDesc[OpTextureSample].operands.push(OperandId, "'Coordinate'");
+    InstructionDesc[OpTextureSample].operands.push(OperandOptionalId, "['Bias']");
+    InstructionDesc[OpTextureSample].capabilities.push_back(CapShader);
+
+    InstructionDesc[OpTextureSampleDref].operands.push(OperandId, "'Sampler'");
+    InstructionDesc[OpTextureSampleDref].operands.push(OperandId, "'Coordinate'");
+    InstructionDesc[OpTextureSampleDref].operands.push(OperandId, "'D~ref~'");
+    InstructionDesc[OpTextureSampleDref].capabilities.push_back(CapShader);
+
+    InstructionDesc[OpTextureSampleLod].operands.push(OperandId, "'Sampler'");
+    InstructionDesc[OpTextureSampleLod].operands.push(OperandId, "'Coordinate'");
+    InstructionDesc[OpTextureSampleLod].operands.push(OperandId, "'Level of Detail'");
+    InstructionDesc[OpTextureSampleLod].capabilities.push_back(CapShader);
+
+    InstructionDesc[OpTextureSampleProj].operands.push(OperandId, "'Sampler'");
+    InstructionDesc[OpTextureSampleProj].operands.push(OperandId, "'Coordinate'");
+    InstructionDesc[OpTextureSampleProj].operands.push(OperandOptionalId, "['Bias']");
+    InstructionDesc[OpTextureSampleProj].capabilities.push_back(CapShader);
+
+    InstructionDesc[OpTextureSampleGrad].operands.push(OperandId, "'Sampler'");
+    InstructionDesc[OpTextureSampleGrad].operands.push(OperandId, "'Coordinate'");
+    InstructionDesc[OpTextureSampleGrad].operands.push(OperandId, "'dx'");
+    InstructionDesc[OpTextureSampleGrad].operands.push(OperandId, "'dy'");
+    InstructionDesc[OpTextureSampleGrad].capabilities.push_back(CapShader);
+
+    InstructionDesc[OpTextureSampleOffset].operands.push(OperandId, "'Sampler'");
+    InstructionDesc[OpTextureSampleOffset].operands.push(OperandId, "'Coordinate'");
+    InstructionDesc[OpTextureSampleOffset].operands.push(OperandId, "'Offset'");
+    InstructionDesc[OpTextureSampleOffset].operands.push(OperandOptionalId, "['Bias']");
+    InstructionDesc[OpTextureSampleOffset].capabilities.push_back(CapShader);
+
+    InstructionDesc[OpTextureSampleProjLod].operands.push(OperandId, "'Sampler'");
+    InstructionDesc[OpTextureSampleProjLod].operands.push(OperandId, "'Coordinate'");
+    InstructionDesc[OpTextureSampleProjLod].operands.push(OperandId, "'Level of Detail'");
+    InstructionDesc[OpTextureSampleProjLod].capabilities.push_back(CapShader);
+
+    InstructionDesc[OpTextureSampleProjGrad].operands.push(OperandId, "'Sampler'");
+    InstructionDesc[OpTextureSampleProjGrad].operands.push(OperandId, "'Coordinate'");
+    InstructionDesc[OpTextureSampleProjGrad].operands.push(OperandId, "'dx'");
+    InstructionDesc[OpTextureSampleProjGrad].operands.push(OperandId, "'dy'");
+    InstructionDesc[OpTextureSampleProjGrad].capabilities.push_back(CapShader);
+
+    InstructionDesc[OpTextureSampleLodOffset].operands.push(OperandId, "'Sampler'");
+    InstructionDesc[OpTextureSampleLodOffset].operands.push(OperandId, "'Coordinate'");
+    InstructionDesc[OpTextureSampleLodOffset].operands.push(OperandId, "'Level of Detail'");
+    InstructionDesc[OpTextureSampleLodOffset].operands.push(OperandId, "'Offset'");
+    InstructionDesc[OpTextureSampleLodOffset].capabilities.push_back(CapShader);
+
+    InstructionDesc[OpTextureSampleProjOffset].operands.push(OperandId, "'Sampler'");
+    InstructionDesc[OpTextureSampleProjOffset].operands.push(OperandId, "'Coordinate'");
+    InstructionDesc[OpTextureSampleProjOffset].operands.push(OperandId, "'Offset'");
+    InstructionDesc[OpTextureSampleProjOffset].operands.push(OperandOptionalId, "['Bias']");
+    InstructionDesc[OpTextureSampleProjOffset].capabilities.push_back(CapShader);
+
+    InstructionDesc[OpTextureSampleGradOffset].operands.push(OperandId, "'Sampler'");
+    InstructionDesc[OpTextureSampleGradOffset].operands.push(OperandId, "'Coordinate'");
+    InstructionDesc[OpTextureSampleGradOffset].operands.push(OperandId, "'dx'");
+    InstructionDesc[OpTextureSampleGradOffset].operands.push(OperandId, "'dy'");
+    InstructionDesc[OpTextureSampleGradOffset].operands.push(OperandId, "'Offset'");
+    InstructionDesc[OpTextureSampleGradOffset].capabilities.push_back(CapShader);
+
+    InstructionDesc[OpTextureSampleProjLodOffset].operands.push(OperandId, "'Sampler'");
+    InstructionDesc[OpTextureSampleProjLodOffset].operands.push(OperandId, "'Coordinate'");
+    InstructionDesc[OpTextureSampleProjLodOffset].operands.push(OperandId, "'Level of Detail'");
+    InstructionDesc[OpTextureSampleProjLodOffset].operands.push(OperandId, "'Offset'");
+    InstructionDesc[OpTextureSampleProjLodOffset].capabilities.push_back(CapShader);
+
+    InstructionDesc[OpTextureSampleProjGradOffset].operands.push(OperandId, "'Sampler'");
+    InstructionDesc[OpTextureSampleProjGradOffset].operands.push(OperandId, "'Coordinate'");
+    InstructionDesc[OpTextureSampleProjGradOffset].operands.push(OperandId, "'dx'");
+    InstructionDesc[OpTextureSampleProjGradOffset].operands.push(OperandId, "'dy'");
+    InstructionDesc[OpTextureSampleProjGradOffset].operands.push(OperandId, "'Offset'");
+    InstructionDesc[OpTextureSampleProjGradOffset].capabilities.push_back(CapShader);
+
+    InstructionDesc[OpTextureFetchTexelLod].operands.push(OperandId, "'Sampler'");
+    InstructionDesc[OpTextureFetchTexelLod].operands.push(OperandId, "'Coordinate'");
+    InstructionDesc[OpTextureFetchTexelLod].operands.push(OperandId, "'Level of Detail'");
+    InstructionDesc[OpTextureFetchTexelLod].capabilities.push_back(CapShader);
+
+    InstructionDesc[OpTextureFetchTexelOffset].operands.push(OperandId, "'Sampler'");
+    InstructionDesc[OpTextureFetchTexelOffset].operands.push(OperandId, "'Coordinate'");
+    InstructionDesc[OpTextureFetchTexelOffset].operands.push(OperandId, "'Offset'");
+    InstructionDesc[OpTextureFetchTexelOffset].capabilities.push_back(CapShader);
+
+    InstructionDesc[OpTextureFetchSample].operands.push(OperandId, "'Sampler'");
+    InstructionDesc[OpTextureFetchSample].operands.push(OperandId, "'Coordinate'");
+    InstructionDesc[OpTextureFetchSample].operands.push(OperandId, "'Sample'");
+    InstructionDesc[OpTextureFetchSample].capabilities.push_back(CapShader);
+
+    InstructionDesc[OpTextureFetchTexel].operands.push(OperandId, "'Sampler'");
+    InstructionDesc[OpTextureFetchTexel].operands.push(OperandId, "'Element'");
+    InstructionDesc[OpTextureFetchTexel].capabilities.push_back(CapShader);
+
+    InstructionDesc[OpTextureGather].operands.push(OperandId, "'Sampler'");
+    InstructionDesc[OpTextureGather].operands.push(OperandId, "'Coordinate'");
+    InstructionDesc[OpTextureGather].operands.push(OperandId, "'Component'");
+    InstructionDesc[OpTextureGather].capabilities.push_back(CapShader);
+
+    InstructionDesc[OpTextureGatherOffset].operands.push(OperandId, "'Sampler'");
+    InstructionDesc[OpTextureGatherOffset].operands.push(OperandId, "'Coordinate'");
+    InstructionDesc[OpTextureGatherOffset].operands.push(OperandId, "'Component'");
+    InstructionDesc[OpTextureGatherOffset].operands.push(OperandId, "'Offset'");
+    InstructionDesc[OpTextureGatherOffset].capabilities.push_back(CapShader);
+
+    InstructionDesc[OpTextureGatherOffsets].operands.push(OperandId, "'Sampler'");
+    InstructionDesc[OpTextureGatherOffsets].operands.push(OperandId, "'Coordinate'");
+    InstructionDesc[OpTextureGatherOffsets].operands.push(OperandId, "'Component'");
+    InstructionDesc[OpTextureGatherOffsets].operands.push(OperandId, "'Offsets'");
+    InstructionDesc[OpTextureGatherOffsets].capabilities.push_back(CapShader);
+
+    InstructionDesc[OpTextureQuerySizeLod].operands.push(OperandId, "'Sampler'");
+    InstructionDesc[OpTextureQuerySizeLod].operands.push(OperandId, "'Level of Detail'");
+    InstructionDesc[OpTextureQuerySizeLod].capabilities.push_back(CapShader);
+
+    InstructionDesc[OpTextureQuerySize].operands.push(OperandId, "'Sampler'");
+    InstructionDesc[OpTextureQuerySize].capabilities.push_back(CapShader);
+
+    InstructionDesc[OpTextureQueryLod].operands.push(OperandId, "'Sampler'");
+    InstructionDesc[OpTextureQueryLod].operands.push(OperandId, "'Coordinate'");
+    InstructionDesc[OpTextureQueryLod].capabilities.push_back(CapShader);
+
+    InstructionDesc[OpTextureQueryLevels].operands.push(OperandId, "'Sampler'");
+    InstructionDesc[OpTextureQueryLevels].capabilities.push_back(CapShader);
+
+    InstructionDesc[OpTextureQuerySamples].operands.push(OperandId, "'Sampler'");
+    InstructionDesc[OpTextureQuerySamples].capabilities.push_back(CapShader);
+
+    InstructionDesc[OpAccessChain].operands.push(OperandId, "'Base'");
+    InstructionDesc[OpAccessChain].operands.push(OperandVariableIds, "'Indexes'");
+
+    InstructionDesc[OpInBoundsAccessChain].operands.push(OperandId, "'Base'");
+    InstructionDesc[OpInBoundsAccessChain].operands.push(OperandVariableIds, "'Indexes'");
+
+    InstructionDesc[OpSNegate].operands.push(OperandId, "'Operand'");
+
+    InstructionDesc[OpFNegate].operands.push(OperandId, "'Operand'");
+
+    InstructionDesc[OpNot].operands.push(OperandId, "'Operand'");
+
+    InstructionDesc[OpAny].operands.push(OperandId, "'Vector'");
+
+    InstructionDesc[OpAll].operands.push(OperandId, "'Vector'");
+
+    InstructionDesc[OpConvertFToU].operands.push(OperandId, "'Float Value'");
+
+    InstructionDesc[OpConvertFToS].operands.push(OperandId, "'Float Value'");
+
+    InstructionDesc[OpConvertSToF].operands.push(OperandId, "'Signed Value'");
+
+    InstructionDesc[OpConvertUToF].operands.push(OperandId, "'Unsigned value'");
+
+    InstructionDesc[OpUConvert].operands.push(OperandId, "'Unsigned value'");
+
+    InstructionDesc[OpSConvert].operands.push(OperandId, "'Signed Value'");
+
+    InstructionDesc[OpFConvert].operands.push(OperandId, "'Float Value'");
+
+    InstructionDesc[OpSatConvertSToU].operands.push(OperandId, "'Signed Value'");
+    InstructionDesc[OpSatConvertSToU].capabilities.push_back(CapKernel);
+
+    InstructionDesc[OpSatConvertUToS].operands.push(OperandId, "'Unsigned Value'");
+    InstructionDesc[OpSatConvertUToS].capabilities.push_back(CapKernel);
+
+    InstructionDesc[OpConvertPtrToU].operands.push(OperandId, "'Pointer'");
+    InstructionDesc[OpConvertPtrToU].capabilities.push_back(CapAddr);
+
+    InstructionDesc[OpConvertUToPtr].operands.push(OperandId, "'Integer value'");
+    InstructionDesc[OpConvertUToPtr].capabilities.push_back(CapAddr);
+
+    InstructionDesc[OpPtrCastToGeneric].operands.push(OperandId, "'Source pointer'");
+    InstructionDesc[OpPtrCastToGeneric].capabilities.push_back(CapKernel);
+
+
+    InstructionDesc[OpGenericCastToPtr].operands.push(OperandId, "'Source pointer'");
+    InstructionDesc[OpGenericCastToPtr].capabilities.push_back(CapKernel);
+
+    InstructionDesc[OpGenericCastToPtrExplicit].operands.push(OperandId, "'Source pointer'");
+    InstructionDesc[OpGenericCastToPtrExplicit].operands.push(OperandStorage, "'storage'");
+    InstructionDesc[OpGenericCastToPtrExplicit].capabilities.push_back(CapKernel);
+
+    InstructionDesc[OpGenericPtrMemSemantics].operands.push(OperandId, "'ptr'");
+    InstructionDesc[OpGenericPtrMemSemantics].capabilities.push_back(CapKernel);
+
+    InstructionDesc[OpBitcast].operands.push(OperandId, "'Operand'");
+
+    InstructionDesc[OpTranspose].capabilities.push_back(CapMatrix);
+    InstructionDesc[OpTranspose].operands.push(OperandId, "'Matrix'");
+
+    InstructionDesc[OpIsNan].operands.push(OperandId, "'x'");
+
+    InstructionDesc[OpIsInf].operands.push(OperandId, "'x'");
+
+    InstructionDesc[OpIsFinite].capabilities.push_back(CapKernel);
+    InstructionDesc[OpIsFinite].operands.push(OperandId, "'x'");
+
+    InstructionDesc[OpIsNormal].capabilities.push_back(CapKernel);
+    InstructionDesc[OpIsNormal].operands.push(OperandId, "'x'");
+
+    InstructionDesc[OpSignBitSet].capabilities.push_back(CapKernel);
+    InstructionDesc[OpSignBitSet].operands.push(OperandId, "'x'");
+
+    InstructionDesc[OpLessOrGreater].capabilities.push_back(CapKernel);
+    InstructionDesc[OpLessOrGreater].operands.push(OperandId, "'x'");
+    InstructionDesc[OpLessOrGreater].operands.push(OperandId, "'y'");
+
+    InstructionDesc[OpOrdered].capabilities.push_back(CapKernel);
+    InstructionDesc[OpOrdered].operands.push(OperandId, "'x'");
+    InstructionDesc[OpOrdered].operands.push(OperandId, "'y'");
+
+    InstructionDesc[OpUnordered].capabilities.push_back(CapKernel);
+    InstructionDesc[OpUnordered].operands.push(OperandId, "'x'");
+    InstructionDesc[OpUnordered].operands.push(OperandId, "'y'");
+
+    InstructionDesc[OpArrayLength].operands.push(OperandId, "'Structure'");
+    InstructionDesc[OpArrayLength].operands.push(OperandLiteralNumber, "'Array member'");
+    InstructionDesc[OpArrayLength].capabilities.push_back(CapShader);
+
+    InstructionDesc[OpIAdd].operands.push(OperandId, "'Operand 1'");
+    InstructionDesc[OpIAdd].operands.push(OperandId, "'Operand 2'");
+
+    InstructionDesc[OpFAdd].operands.push(OperandId, "'Operand 1'");
+    InstructionDesc[OpFAdd].operands.push(OperandId, "'Operand 2'");
+
+    InstructionDesc[OpISub].operands.push(OperandId, "'Operand 1'");
+    InstructionDesc[OpISub].operands.push(OperandId, "'Operand 2'");
+
+    InstructionDesc[OpFSub].operands.push(OperandId, "'Operand 1'");
+    InstructionDesc[OpFSub].operands.push(OperandId, "'Operand 2'");
+
+    InstructionDesc[OpIMul].operands.push(OperandId, "'Operand 1'");
+    InstructionDesc[OpIMul].operands.push(OperandId, "'Operand 2'");
+
+    InstructionDesc[OpFMul].operands.push(OperandId, "'Operand 1'");
+    InstructionDesc[OpFMul].operands.push(OperandId, "'Operand 2'");
+
+    InstructionDesc[OpUDiv].operands.push(OperandId, "'Operand 1'");
+    InstructionDesc[OpUDiv].operands.push(OperandId, "'Operand 2'");
+
+    InstructionDesc[OpSDiv].operands.push(OperandId, "'Operand 1'");
+    InstructionDesc[OpSDiv].operands.push(OperandId, "'Operand 2'");
+
+    InstructionDesc[OpFDiv].operands.push(OperandId, "'Operand 1'");
+    InstructionDesc[OpFDiv].operands.push(OperandId, "'Operand 2'");
+
+    InstructionDesc[OpUMod].operands.push(OperandId, "'Operand 1'");
+    InstructionDesc[OpUMod].operands.push(OperandId, "'Operand 2'");
+
+    InstructionDesc[OpSRem].operands.push(OperandId, "'Operand 1'");
+    InstructionDesc[OpSRem].operands.push(OperandId, "'Operand 2'");
+
+    InstructionDesc[OpSMod].operands.push(OperandId, "'Operand 1'");
+    InstructionDesc[OpSMod].operands.push(OperandId, "'Operand 2'");
+
+    InstructionDesc[OpFRem].operands.push(OperandId, "'Operand 1'");
+    InstructionDesc[OpFRem].operands.push(OperandId, "'Operand 2'");
+
+    InstructionDesc[OpFMod].operands.push(OperandId, "'Operand 1'");
+    InstructionDesc[OpFMod].operands.push(OperandId, "'Operand 2'");
+
+    InstructionDesc[OpVectorTimesScalar].operands.push(OperandId, "'Vector'");
+    InstructionDesc[OpVectorTimesScalar].operands.push(OperandId, "'Scalar'");
+
+    InstructionDesc[OpMatrixTimesScalar].capabilities.push_back(CapMatrix);
+    InstructionDesc[OpMatrixTimesScalar].operands.push(OperandId, "'Matrix'");
+    InstructionDesc[OpMatrixTimesScalar].operands.push(OperandId, "'Scalar'");
+
+    InstructionDesc[OpVectorTimesMatrix].capabilities.push_back(CapMatrix);
+    InstructionDesc[OpVectorTimesMatrix].operands.push(OperandId, "'Vector'");
+    InstructionDesc[OpVectorTimesMatrix].operands.push(OperandId, "'Matrix'");
+
+    InstructionDesc[OpMatrixTimesVector].capabilities.push_back(CapMatrix);
+    InstructionDesc[OpMatrixTimesVector].operands.push(OperandId, "'Matrix'");
+    InstructionDesc[OpMatrixTimesVector].operands.push(OperandId, "'Vector'");
+
+    InstructionDesc[OpMatrixTimesMatrix].capabilities.push_back(CapMatrix);
+    InstructionDesc[OpMatrixTimesMatrix].operands.push(OperandId, "'LeftMatrix'");
+    InstructionDesc[OpMatrixTimesMatrix].operands.push(OperandId, "'RightMatrix'");
+
+    InstructionDesc[OpOuterProduct].capabilities.push_back(CapMatrix);
+    InstructionDesc[OpOuterProduct].operands.push(OperandId, "'Vector 1'");
+    InstructionDesc[OpOuterProduct].operands.push(OperandId, "'Vector 2'");
+
+    InstructionDesc[OpDot].operands.push(OperandId, "'Vector 1'");
+    InstructionDesc[OpDot].operands.push(OperandId, "'Vector 2'");
+
+    InstructionDesc[OpShiftRightLogical].operands.push(OperandId, "'Operand 1'");
+    InstructionDesc[OpShiftRightLogical].operands.push(OperandId, "'Operand 2'");
+
+    InstructionDesc[OpShiftRightArithmetic].operands.push(OperandId, "'Operand 1'");
+    InstructionDesc[OpShiftRightArithmetic].operands.push(OperandId, "'Operand 2'");
+
+    InstructionDesc[OpShiftLeftLogical].operands.push(OperandId, "'Operand 1'");
+    InstructionDesc[OpShiftLeftLogical].operands.push(OperandId, "'Operand 2'");
+
+    InstructionDesc[OpLogicalOr].operands.push(OperandId, "'Operand 1'");
+    InstructionDesc[OpLogicalOr].operands.push(OperandId, "'Operand 2'");
+
+    InstructionDesc[OpLogicalXor].operands.push(OperandId, "'Operand 1'");
+    InstructionDesc[OpLogicalXor].operands.push(OperandId, "'Operand 2'");
+
+    InstructionDesc[OpLogicalAnd].operands.push(OperandId, "'Operand 1'");
+    InstructionDesc[OpLogicalAnd].operands.push(OperandId, "'Operand 2'");
+
+    InstructionDesc[OpBitwiseOr].operands.push(OperandId, "'Operand 1'");
+    InstructionDesc[OpBitwiseOr].operands.push(OperandId, "'Operand 2'");
+
+    InstructionDesc[OpBitwiseXor].operands.push(OperandId, "'Operand 1'");
+    InstructionDesc[OpBitwiseXor].operands.push(OperandId, "'Operand 2'");
+
+    InstructionDesc[OpBitwiseAnd].operands.push(OperandId, "'Operand 1'");
+    InstructionDesc[OpBitwiseAnd].operands.push(OperandId, "'Operand 2'");
+
+    InstructionDesc[OpSelect].operands.push(OperandId, "'Condition'");
+    InstructionDesc[OpSelect].operands.push(OperandId, "'Object 1'");
+    InstructionDesc[OpSelect].operands.push(OperandId, "'Object 2'");
+
+    InstructionDesc[OpIEqual].operands.push(OperandId, "'Operand 1'");
+    InstructionDesc[OpIEqual].operands.push(OperandId, "'Operand 2'");
+
+    InstructionDesc[OpFOrdEqual].operands.push(OperandId, "'Operand 1'");
+    InstructionDesc[OpFOrdEqual].operands.push(OperandId, "'Operand 2'");
+
+    InstructionDesc[OpFUnordEqual].operands.push(OperandId, "'Operand 1'");
+    InstructionDesc[OpFUnordEqual].operands.push(OperandId, "'Operand 2'");
+
+    InstructionDesc[OpINotEqual].operands.push(OperandId, "'Operand 1'");
+    InstructionDesc[OpINotEqual].operands.push(OperandId, "'Operand 2'");
+
+    InstructionDesc[OpFOrdNotEqual].operands.push(OperandId, "'Operand 1'");
+    InstructionDesc[OpFOrdNotEqual].operands.push(OperandId, "'Operand 2'");
+
+    InstructionDesc[OpFUnordNotEqual].operands.push(OperandId, "'Operand 1'");
+    InstructionDesc[OpFUnordNotEqual].operands.push(OperandId, "'Operand 2'");
+
+    InstructionDesc[OpULessThan].operands.push(OperandId, "'Operand 1'");
+    InstructionDesc[OpULessThan].operands.push(OperandId, "'Operand 2'");
+
+    InstructionDesc[OpSLessThan].operands.push(OperandId, "'Operand 1'");
+    InstructionDesc[OpSLessThan].operands.push(OperandId, "'Operand 2'");
+
+    InstructionDesc[OpFOrdLessThan].operands.push(OperandId, "'Operand 1'");
+    InstructionDesc[OpFOrdLessThan].operands.push(OperandId, "'Operand 2'");
+
+    InstructionDesc[OpFUnordLessThan].operands.push(OperandId, "'Operand 1'");
+    InstructionDesc[OpFUnordLessThan].operands.push(OperandId, "'Operand 2'");
+
+    InstructionDesc[OpUGreaterThan].operands.push(OperandId, "'Operand 1'");
+    InstructionDesc[OpUGreaterThan].operands.push(OperandId, "'Operand 2'");
+
+    InstructionDesc[OpSGreaterThan].operands.push(OperandId, "'Operand 1'");
+    InstructionDesc[OpSGreaterThan].operands.push(OperandId, "'Operand 2'");
+
+    InstructionDesc[OpFOrdGreaterThan].operands.push(OperandId, "'Operand 1'");
+    InstructionDesc[OpFOrdGreaterThan].operands.push(OperandId, "'Operand 2'");
+
+    InstructionDesc[OpFUnordGreaterThan].operands.push(OperandId, "'Operand 1'");
+    InstructionDesc[OpFUnordGreaterThan].operands.push(OperandId, "'Operand 2'");
+
+    InstructionDesc[OpULessThanEqual].operands.push(OperandId, "'Operand 1'");
+    InstructionDesc[OpULessThanEqual].operands.push(OperandId, "'Operand 2'");
+
+    InstructionDesc[OpSLessThanEqual].operands.push(OperandId, "'Operand 1'");
+    InstructionDesc[OpSLessThanEqual].operands.push(OperandId, "'Operand 2'");
+
+    InstructionDesc[OpFOrdLessThanEqual].operands.push(OperandId, "'Operand 1'");
+    InstructionDesc[OpFOrdLessThanEqual].operands.push(OperandId, "'Operand 2'");
+
+    InstructionDesc[OpFUnordLessThanEqual].operands.push(OperandId, "'Operand 1'");
+    InstructionDesc[OpFUnordLessThanEqual].operands.push(OperandId, "'Operand 2'");
+
+    InstructionDesc[OpUGreaterThanEqual].operands.push(OperandId, "'Operand 1'");
+    InstructionDesc[OpUGreaterThanEqual].operands.push(OperandId, "'Operand 2'");
+
+    InstructionDesc[OpSGreaterThanEqual].operands.push(OperandId, "'Operand 1'");
+    InstructionDesc[OpSGreaterThanEqual].operands.push(OperandId, "'Operand 2'");
+
+    InstructionDesc[OpFOrdGreaterThanEqual].operands.push(OperandId, "'Operand 1'");
+    InstructionDesc[OpFOrdGreaterThanEqual].operands.push(OperandId, "'Operand 2'");
+
+    InstructionDesc[OpFUnordGreaterThanEqual].operands.push(OperandId, "'Operand 1'");
+    InstructionDesc[OpFUnordGreaterThanEqual].operands.push(OperandId, "'Operand 2'");
+
+    InstructionDesc[OpDPdx].capabilities.push_back(CapShader);
+    InstructionDesc[OpDPdx].operands.push(OperandId, "'P'");
+
+    InstructionDesc[OpDPdy].capabilities.push_back(CapShader);
+    InstructionDesc[OpDPdy].operands.push(OperandId, "'P'");
+
+    InstructionDesc[OpFwidth].capabilities.push_back(CapShader);
+    InstructionDesc[OpFwidth].operands.push(OperandId, "'P'");
+
+    InstructionDesc[OpDPdxFine].capabilities.push_back(CapShader);
+    InstructionDesc[OpDPdxFine].operands.push(OperandId, "'P'");
+
+    InstructionDesc[OpDPdyFine].capabilities.push_back(CapShader);
+    InstructionDesc[OpDPdyFine].operands.push(OperandId, "'P'");
+
+    InstructionDesc[OpFwidthFine].capabilities.push_back(CapShader);
+    InstructionDesc[OpFwidthFine].operands.push(OperandId, "'P'");
+
+    InstructionDesc[OpDPdxCoarse].capabilities.push_back(CapShader);
+    InstructionDesc[OpDPdxCoarse].operands.push(OperandId, "'P'");
+
+    InstructionDesc[OpDPdyCoarse].capabilities.push_back(CapShader);
+    InstructionDesc[OpDPdyCoarse].operands.push(OperandId, "'P'");
+
+    InstructionDesc[OpFwidthCoarse].capabilities.push_back(CapShader);
+    InstructionDesc[OpFwidthCoarse].operands.push(OperandId, "'P'");
+
+    InstructionDesc[OpEmitVertex].capabilities.push_back(CapGeom);
+
+    InstructionDesc[OpEndPrimitive].capabilities.push_back(CapGeom);
+
+    InstructionDesc[OpEmitStreamVertex].operands.push(OperandId, "'Stream'");
+    InstructionDesc[OpEmitStreamVertex].capabilities.push_back(CapGeom);
+
+    InstructionDesc[OpEndStreamPrimitive].operands.push(OperandId, "'Stream'");
+    InstructionDesc[OpEndStreamPrimitive].capabilities.push_back(CapGeom);
+
+    InstructionDesc[OpControlBarrier].operands.push(OperandExecutionScope, "'Scope'");
+
+    InstructionDesc[OpMemoryBarrier].operands.push(OperandExecutionScope, "'Scope'");
+    InstructionDesc[OpMemoryBarrier].operands.push(OperandMemorySemantics, "'Semantics'");
+
+    InstructionDesc[OpImagePointer].operands.push(OperandId, "'Image'");
+    InstructionDesc[OpImagePointer].operands.push(OperandId, "'Coordinate'");
+    InstructionDesc[OpImagePointer].operands.push(OperandId, "'Sample'");
+
+    InstructionDesc[OpAtomicInit].operands.push(OperandId, "'Pointer'");
+    InstructionDesc[OpAtomicInit].operands.push(OperandId, "'Value'");
+
+    InstructionDesc[OpAtomicLoad].operands.push(OperandId, "'Pointer'");
+    InstructionDesc[OpAtomicLoad].operands.push(OperandExecutionScope, "'Scope'");
+    InstructionDesc[OpAtomicLoad].operands.push(OperandMemorySemantics, "'Semantics'");
+
+    InstructionDesc[OpAtomicStore].operands.push(OperandId, "'Pointer'");
+    InstructionDesc[OpAtomicStore].operands.push(OperandExecutionScope, "'Scope'");
+    InstructionDesc[OpAtomicStore].operands.push(OperandMemorySemantics, "'Semantics'");
+    InstructionDesc[OpAtomicStore].operands.push(OperandId, "'Value'");
+
+    InstructionDesc[OpAtomicExchange].operands.push(OperandId, "'Pointer'");
+    InstructionDesc[OpAtomicExchange].operands.push(OperandExecutionScope, "'Scope'");
+    InstructionDesc[OpAtomicExchange].operands.push(OperandMemorySemantics, "'Semantics'");
+    InstructionDesc[OpAtomicExchange].operands.push(OperandId, "'Value'");
+
+    InstructionDesc[OpAtomicCompareExchange].operands.push(OperandId, "'Pointer'");
+    InstructionDesc[OpAtomicCompareExchange].operands.push(OperandExecutionScope, "'Scope'");
+    InstructionDesc[OpAtomicCompareExchange].operands.push(OperandMemorySemantics, "'Semantics'");
+    InstructionDesc[OpAtomicCompareExchange].operands.push(OperandId, "'Value'");
+    InstructionDesc[OpAtomicCompareExchange].operands.push(OperandId, "'Comparator'");
+
+    InstructionDesc[OpAtomicCompareExchangeWeak].operands.push(OperandId, "'Pointer'");
+    InstructionDesc[OpAtomicCompareExchangeWeak].operands.push(OperandExecutionScope, "'Scope'");
+    InstructionDesc[OpAtomicCompareExchangeWeak].operands.push(OperandMemorySemantics, "'Semantics'");
+    InstructionDesc[OpAtomicCompareExchangeWeak].operands.push(OperandId, "'Value'");
+    InstructionDesc[OpAtomicCompareExchangeWeak].operands.push(OperandId, "'Comparator'");
+
+    InstructionDesc[OpAtomicIIncrement].operands.push(OperandId, "'Pointer'");
+    InstructionDesc[OpAtomicIIncrement].operands.push(OperandExecutionScope, "'Scope'");
+    InstructionDesc[OpAtomicIIncrement].operands.push(OperandMemorySemantics, "'Semantics'");
+
+    InstructionDesc[OpAtomicIDecrement].operands.push(OperandId, "'Pointer'");
+    InstructionDesc[OpAtomicIDecrement].operands.push(OperandExecutionScope, "'Scope'");
+    InstructionDesc[OpAtomicIDecrement].operands.push(OperandMemorySemantics, "'Semantics'");
+
+    InstructionDesc[OpAtomicIAdd].operands.push(OperandId, "'Pointer'");
+    InstructionDesc[OpAtomicIAdd].operands.push(OperandExecutionScope, "'Scope'");
+    InstructionDesc[OpAtomicIAdd].operands.push(OperandMemorySemantics, "'Semantics'");
+    InstructionDesc[OpAtomicIAdd].operands.push(OperandId, "'Value'");
+
+    InstructionDesc[OpAtomicISub].operands.push(OperandId, "'Pointer'");
+    InstructionDesc[OpAtomicISub].operands.push(OperandExecutionScope, "'Scope'");
+    InstructionDesc[OpAtomicISub].operands.push(OperandMemorySemantics, "'Semantics'");
+    InstructionDesc[OpAtomicISub].operands.push(OperandId, "'Value'");
+
+    InstructionDesc[OpAtomicUMin].operands.push(OperandId, "'Pointer'");
+    InstructionDesc[OpAtomicUMin].operands.push(OperandExecutionScope, "'Scope'");
+    InstructionDesc[OpAtomicUMin].operands.push(OperandMemorySemantics, "'Semantics'");
+    InstructionDesc[OpAtomicUMin].operands.push(OperandId, "'Value'");
+
+    InstructionDesc[OpAtomicUMax].operands.push(OperandId, "'Pointer'");
+    InstructionDesc[OpAtomicUMax].operands.push(OperandExecutionScope, "'Scope'");
+    InstructionDesc[OpAtomicUMax].operands.push(OperandMemorySemantics, "'Semantics'");
+    InstructionDesc[OpAtomicUMax].operands.push(OperandId, "'Value'");
+
+    InstructionDesc[OpAtomicIMin].operands.push(OperandId, "'Pointer'");
+    InstructionDesc[OpAtomicIMin].operands.push(OperandExecutionScope, "'Scope'");
+    InstructionDesc[OpAtomicIMin].operands.push(OperandMemorySemantics, "'Semantics'");
+    InstructionDesc[OpAtomicIMin].operands.push(OperandId, "'Value'");
+
+    InstructionDesc[OpAtomicIMax].operands.push(OperandId, "'Pointer'");
+    InstructionDesc[OpAtomicIMax].operands.push(OperandExecutionScope, "'Scope'");
+    InstructionDesc[OpAtomicIMax].operands.push(OperandMemorySemantics, "'Semantics'");
+    InstructionDesc[OpAtomicIMax].operands.push(OperandId, "'Value'");
+
+    InstructionDesc[OpAtomicAnd].operands.push(OperandId, "'Pointer'");
+    InstructionDesc[OpAtomicAnd].operands.push(OperandExecutionScope, "'Scope'");
+    InstructionDesc[OpAtomicAnd].operands.push(OperandMemorySemantics, "'Semantics'");
+    InstructionDesc[OpAtomicAnd].operands.push(OperandId, "'Value'");
+
+    InstructionDesc[OpAtomicOr].operands.push(OperandId, "'Pointer'");
+    InstructionDesc[OpAtomicOr].operands.push(OperandExecutionScope, "'Scope'");
+    InstructionDesc[OpAtomicOr].operands.push(OperandMemorySemantics, "'Semantics'");
+    InstructionDesc[OpAtomicOr].operands.push(OperandId, "'Value'");
+
+    InstructionDesc[OpAtomicXor].operands.push(OperandId, "'Pointer'");
+    InstructionDesc[OpAtomicXor].operands.push(OperandExecutionScope, "'Scope'");
+    InstructionDesc[OpAtomicXor].operands.push(OperandMemorySemantics, "'Semantics'");
+    InstructionDesc[OpAtomicXor].operands.push(OperandId, "'Value'");
+
+    InstructionDesc[OpLoopMerge].operands.push(OperandId, "'Label'");
+    InstructionDesc[OpLoopMerge].operands.push(OperandLoop, "");
+
+    InstructionDesc[OpSelectionMerge].operands.push(OperandId, "'Label'");
+    InstructionDesc[OpSelectionMerge].operands.push(OperandSelect, "");
+
+    InstructionDesc[OpBranch].operands.push(OperandId, "'Target Label'");
+
+    InstructionDesc[OpBranchConditional].operands.push(OperandId, "'Condition'");
+    InstructionDesc[OpBranchConditional].operands.push(OperandId, "'True Label'");
+    InstructionDesc[OpBranchConditional].operands.push(OperandId, "'False Label'");
+    InstructionDesc[OpBranchConditional].operands.push(OperandVariableLiterals, "'Branch weights'");
+
+    InstructionDesc[OpSwitch].operands.push(OperandId, "'Selector'");
+    InstructionDesc[OpSwitch].operands.push(OperandId, "'Default'");
+    InstructionDesc[OpSwitch].operands.push(OperandVariableLiteralId, "'Target'");
+
+    InstructionDesc[OpKill].capabilities.push_back(CapShader);
+
+    InstructionDesc[OpReturnValue].operands.push(OperandId, "'Value'");
+
+    InstructionDesc[OpUnreachable].capabilities.push_back(CapKernel);
+
+    InstructionDesc[OpLifetimeStart].operands.push(OperandId, "");
+    InstructionDesc[OpLifetimeStart].operands.push(OperandLiteralNumber, "");
+
+    InstructionDesc[OpLifetimeStop].operands.push(OperandId, "");
+    InstructionDesc[OpLifetimeStop].operands.push(OperandLiteralNumber, "");
+
+    InstructionDesc[OpCompileFlag].capabilities.push_back(CapKernel);
+    InstructionDesc[OpCompileFlag].operands.push(OperandLiteralString, "'Flag'");
+
+    InstructionDesc[OpAsyncGroupCopy].capabilities.push_back(CapKernel);
+    InstructionDesc[OpAsyncGroupCopy].operands.push(OperandExecutionScope, "'Scope'");
+    InstructionDesc[OpAsyncGroupCopy].operands.push(OperandId, "'Destination'");
+    InstructionDesc[OpAsyncGroupCopy].operands.push(OperandId, "'Source'");
+    InstructionDesc[OpAsyncGroupCopy].operands.push(OperandId, "'Num Elements'");
+    InstructionDesc[OpAsyncGroupCopy].operands.push(OperandId, "'Stride'");
+    InstructionDesc[OpAsyncGroupCopy].operands.push(OperandId, "'Event'");
+
+    InstructionDesc[OpWaitGroupEvents].capabilities.push_back(CapKernel);
+    InstructionDesc[OpWaitGroupEvents].operands.push(OperandExecutionScope, "'Scope'");
+    InstructionDesc[OpWaitGroupEvents].operands.push(OperandId, "'Num Events'");
+    InstructionDesc[OpWaitGroupEvents].operands.push(OperandId, "'Events List'");
+
+    InstructionDesc[OpGroupAll].capabilities.push_back(CapKernel);
+    InstructionDesc[OpGroupAll].operands.push(OperandExecutionScope, "'Scope'");
+    InstructionDesc[OpGroupAll].operands.push(OperandId, "'Predicate'");
+
+    InstructionDesc[OpGroupAny].capabilities.push_back(CapKernel);
+    InstructionDesc[OpGroupAny].operands.push(OperandExecutionScope, "'Scope'");
+    InstructionDesc[OpGroupAny].operands.push(OperandId, "'Predicate'");
+
+    InstructionDesc[OpGroupBroadcast].capabilities.push_back(CapKernel);
+    InstructionDesc[OpGroupBroadcast].operands.push(OperandExecutionScope, "'Scope'");
+    InstructionDesc[OpGroupBroadcast].operands.push(OperandId, "'Value'");
+    InstructionDesc[OpGroupBroadcast].operands.push(OperandId, "'LocalId'");
+
+    InstructionDesc[OpGroupIAdd].capabilities.push_back(CapKernel);
+    InstructionDesc[OpGroupIAdd].operands.push(OperandExecutionScope, "'Scope'");
+    InstructionDesc[OpGroupIAdd].operands.push(OperandGroupOperation, "'Operation'");
+    InstructionDesc[OpGroupIAdd].operands.push(OperandId, "'X'");
+
+    InstructionDesc[OpGroupFAdd].capabilities.push_back(CapKernel);
+    InstructionDesc[OpGroupFAdd].operands.push(OperandExecutionScope, "'Scope'");
+    InstructionDesc[OpGroupFAdd].operands.push(OperandGroupOperation, "'Operation'");
+    InstructionDesc[OpGroupFAdd].operands.push(OperandId, "'X'");
+
+    InstructionDesc[OpGroupUMin].capabilities.push_back(CapKernel);
+    InstructionDesc[OpGroupUMin].operands.push(OperandExecutionScope, "'Scope'");
+    InstructionDesc[OpGroupUMin].operands.push(OperandGroupOperation, "'Operation'");
+    InstructionDesc[OpGroupUMin].operands.push(OperandId, "'X'");
+
+    InstructionDesc[OpGroupSMin].capabilities.push_back(CapKernel);
+    InstructionDesc[OpGroupSMin].operands.push(OperandExecutionScope, "'Scope'");
+    InstructionDesc[OpGroupSMin].operands.push(OperandGroupOperation, "'Operation'");
+    InstructionDesc[OpGroupSMin].operands.push(OperandId, "X");
+
+    InstructionDesc[OpGroupFMin].capabilities.push_back(CapKernel);
+    InstructionDesc[OpGroupFMin].operands.push(OperandExecutionScope, "'Scope'");
+    InstructionDesc[OpGroupFMin].operands.push(OperandGroupOperation, "'Operation'");
+    InstructionDesc[OpGroupFMin].operands.push(OperandId, "X");
+
+    InstructionDesc[OpGroupUMax].capabilities.push_back(CapKernel);
+    InstructionDesc[OpGroupUMax].operands.push(OperandExecutionScope, "'Scope'");
+    InstructionDesc[OpGroupUMax].operands.push(OperandGroupOperation, "'Operation'");
+    InstructionDesc[OpGroupUMax].operands.push(OperandId, "X");
+
+    InstructionDesc[OpGroupSMax].capabilities.push_back(CapKernel);
+    InstructionDesc[OpGroupSMax].operands.push(OperandExecutionScope, "'Scope'");
+    InstructionDesc[OpGroupSMax].operands.push(OperandGroupOperation, "'Operation'");
+    InstructionDesc[OpGroupSMax].operands.push(OperandId, "X");
+
+    InstructionDesc[OpGroupFMax].capabilities.push_back(CapKernel);
+    InstructionDesc[OpGroupFMax].operands.push(OperandExecutionScope, "'Scope'");
+    InstructionDesc[OpGroupFMax].operands.push(OperandGroupOperation, "'Operation'");
+    InstructionDesc[OpGroupFMax].operands.push(OperandId, "X");
+
+    InstructionDesc[OpReadPipe].capabilities.push_back(CapKernel);
+    InstructionDesc[OpReadPipe].operands.push(OperandId, "'p'");
+    InstructionDesc[OpReadPipe].operands.push(OperandId, "'ptr'");
+
+    InstructionDesc[OpWritePipe].capabilities.push_back(CapKernel);
+    InstructionDesc[OpWritePipe].operands.push(OperandId, "'p'");
+    InstructionDesc[OpWritePipe].operands.push(OperandId, "'ptr'");
+
+    InstructionDesc[OpReservedReadPipe].capabilities.push_back(CapKernel);
+    InstructionDesc[OpReservedReadPipe].operands.push(OperandId, "'p'");
+    InstructionDesc[OpReservedReadPipe].operands.push(OperandId, "'reserve_id'");
+    InstructionDesc[OpReservedReadPipe].operands.push(OperandId, "'index'");
+    InstructionDesc[OpReservedReadPipe].operands.push(OperandId, "'ptr'");
+
+    InstructionDesc[OpReservedWritePipe].capabilities.push_back(CapKernel);
+    InstructionDesc[OpReservedWritePipe].operands.push(OperandId, "'p'");
+    InstructionDesc[OpReservedWritePipe].operands.push(OperandId, "'reserve_id'");
+    InstructionDesc[OpReservedWritePipe].operands.push(OperandId, "'index'");
+    InstructionDesc[OpReservedWritePipe].operands.push(OperandId, "'ptr'");
+
+    InstructionDesc[OpReserveReadPipePackets].capabilities.push_back(CapKernel);
+    InstructionDesc[OpReserveReadPipePackets].operands.push(OperandId, "'p'");
+    InstructionDesc[OpReserveReadPipePackets].operands.push(OperandId, "'num_packets'");
+
+    InstructionDesc[OpReserveWritePipePackets].capabilities.push_back(CapKernel);
+    InstructionDesc[OpReserveWritePipePackets].operands.push(OperandId, "'p'");
+    InstructionDesc[OpReserveWritePipePackets].operands.push(OperandId, "'num_packets'");
+
+    InstructionDesc[OpCommitReadPipe].capabilities.push_back(CapKernel);
+    InstructionDesc[OpCommitReadPipe].operands.push(OperandId, "'p'");
+    InstructionDesc[OpCommitReadPipe].operands.push(OperandId, "'reserve_id'");
+
+    InstructionDesc[OpCommitWritePipe].capabilities.push_back(CapKernel);
+    InstructionDesc[OpCommitWritePipe].operands.push(OperandId, "'p'");
+    InstructionDesc[OpCommitWritePipe].operands.push(OperandId, "'reserve_id'");
+
+    InstructionDesc[OpIsValidReserveId].capabilities.push_back(CapKernel);
+    InstructionDesc[OpIsValidReserveId].operands.push(OperandId, "'reserve_id'");
+
+    InstructionDesc[OpGetNumPipePackets].capabilities.push_back(CapKernel);
+    InstructionDesc[OpGetNumPipePackets].operands.push(OperandId, "'p'");
+
+    InstructionDesc[OpGetMaxPipePackets].capabilities.push_back(CapKernel);
+    InstructionDesc[OpGetMaxPipePackets].operands.push(OperandId, "'p'");
+
+    InstructionDesc[OpGroupReserveReadPipePackets].capabilities.push_back(CapKernel);
+    InstructionDesc[OpGroupReserveReadPipePackets].operands.push(OperandExecutionScope, "'Scope'");
+    InstructionDesc[OpGroupReserveReadPipePackets].operands.push(OperandId, "'p'");
+    InstructionDesc[OpGroupReserveReadPipePackets].operands.push(OperandId, "'num_packets'");
+
+    InstructionDesc[OpGroupReserveWritePipePackets].capabilities.push_back(CapKernel);
+    InstructionDesc[OpGroupReserveWritePipePackets].operands.push(OperandExecutionScope, "'Scope'");
+    InstructionDesc[OpGroupReserveWritePipePackets].operands.push(OperandId, "'p'");
+    InstructionDesc[OpGroupReserveWritePipePackets].operands.push(OperandId, "'num_packets'");
+
+    InstructionDesc[OpGroupCommitReadPipe].capabilities.push_back(CapKernel);
+    InstructionDesc[OpGroupCommitReadPipe].operands.push(OperandExecutionScope, "'Scope'");
+    InstructionDesc[OpGroupCommitReadPipe].operands.push(OperandId, "'p'");
+    InstructionDesc[OpGroupCommitReadPipe].operands.push(OperandId, "'reserve_id'");
+
+    InstructionDesc[OpGroupCommitWritePipe].capabilities.push_back(CapKernel);
+    InstructionDesc[OpGroupCommitWritePipe].operands.push(OperandExecutionScope, "'Scope'");
+    InstructionDesc[OpGroupCommitWritePipe].operands.push(OperandId, "'p'");
+    InstructionDesc[OpGroupCommitWritePipe].operands.push(OperandId, "'reserve_id'");
+
+    InstructionDesc[OpBuildNDRange].capabilities.push_back(CapKernel);
+    InstructionDesc[OpBuildNDRange].operands.push(OperandId, "'GlobalWorkSize'");
+    InstructionDesc[OpBuildNDRange].operands.push(OperandId, "'LocalWorkSize'");
+    InstructionDesc[OpBuildNDRange].operands.push(OperandId, "'GlobalWorkOffset'");
+
+    InstructionDesc[OpGetDefaultQueue].capabilities.push_back(CapKernel);
+
+    InstructionDesc[OpCaptureEventProfilingInfo].capabilities.push_back(CapKernel);
+
+    InstructionDesc[OpCaptureEventProfilingInfo].operands.push(OperandId, "'event'");
+    InstructionDesc[OpCaptureEventProfilingInfo].operands.push(OperandKernelProfilingInfo, "'info'");
+    InstructionDesc[OpCaptureEventProfilingInfo].operands.push(OperandId, "'value'");
+
+    InstructionDesc[OpSetUserEventStatus].capabilities.push_back(CapKernel);
+
+    InstructionDesc[OpSetUserEventStatus].operands.push(OperandId, "'event'");
+    InstructionDesc[OpSetUserEventStatus].operands.push(OperandId, "'status'");
+
+    InstructionDesc[OpIsValidEvent].capabilities.push_back(CapKernel);
+    InstructionDesc[OpIsValidEvent].operands.push(OperandId, "'event'");
+
+    InstructionDesc[OpCreateUserEvent].capabilities.push_back(CapKernel);
+
+    InstructionDesc[OpRetainEvent].capabilities.push_back(CapKernel);
+    InstructionDesc[OpRetainEvent].operands.push(OperandId, "'event'");
+
+    InstructionDesc[OpReleaseEvent].capabilities.push_back(CapKernel);
+    InstructionDesc[OpReleaseEvent].operands.push(OperandId, "'event'");
+
+    InstructionDesc[OpGetKernelWorkGroupSize].capabilities.push_back(CapKernel);
+    InstructionDesc[OpGetKernelWorkGroupSize].operands.push(OperandId, "'Invoke'");
+
+    InstructionDesc[OpGetKernelPreferredWorkGroupSizeMultiple].capabilities.push_back(CapKernel);
+    InstructionDesc[OpGetKernelPreferredWorkGroupSizeMultiple].operands.push(OperandId, "'Invoke'");
+
+    InstructionDesc[OpGetKernelNDrangeSubGroupCount].capabilities.push_back(CapKernel);
+    InstructionDesc[OpGetKernelNDrangeSubGroupCount].operands.push(OperandId, "'ND Range'");
+    InstructionDesc[OpGetKernelNDrangeSubGroupCount].operands.push(OperandId, "'Invoke'");
+
+    InstructionDesc[OpGetKernelNDrangeMaxSubGroupSize].capabilities.push_back(CapKernel);
+    InstructionDesc[OpGetKernelNDrangeMaxSubGroupSize].operands.push(OperandId, "'ND Range'");
+    InstructionDesc[OpGetKernelNDrangeMaxSubGroupSize].operands.push(OperandId, "'Invoke'");
+
+    InstructionDesc[OpEnqueueKernel].capabilities.push_back(CapKernel);
+    InstructionDesc[OpEnqueueKernel].operands.push(OperandId, "'q'");
+    InstructionDesc[OpEnqueueKernel].operands.push(OperandKernelEnqueueFlags, "'flags'");
+    InstructionDesc[OpEnqueueKernel].operands.push(OperandId, "'ND Range'");
+    InstructionDesc[OpEnqueueKernel].operands.push(OperandId, "'Num Events'");
+    InstructionDesc[OpEnqueueKernel].operands.push(OperandId, "'Wait Events'");
+    InstructionDesc[OpEnqueueKernel].operands.push(OperandId, "'Ret Event'");
+    InstructionDesc[OpEnqueueKernel].operands.push(OperandId, "'Invoke'");
+    InstructionDesc[OpEnqueueKernel].operands.push(OperandId, "'Param'");
+    InstructionDesc[OpEnqueueKernel].operands.push(OperandId, "'Param Size'");
+    InstructionDesc[OpEnqueueKernel].operands.push(OperandId, "'Param Align'");
+    InstructionDesc[OpEnqueueKernel].operands.push(OperandVariableIds, "'Local Size'");
+
+    InstructionDesc[OpEnqueueMarker].capabilities.push_back(CapKernel);
+    InstructionDesc[OpEnqueueMarker].operands.push(OperandId, "'q'");
+    InstructionDesc[OpEnqueueMarker].operands.push(OperandId, "'Num Events'");
+    InstructionDesc[OpEnqueueMarker].operands.push(OperandId, "'Wait Events'");
+    InstructionDesc[OpEnqueueMarker].operands.push(OperandId, "'Ret Event'");
+}
+
+}; // end spv namespace
diff --git a/SPIRV/doc.h b/SPIRV/doc.h
index 9059f0e..ce4d972 100644
--- a/SPIRV/doc.h
+++ b/SPIRV/doc.h
@@ -1,256 +1,256 @@
-//

-//Copyright (C) 2014 LunarG, Inc.

-//

-//All rights reserved.

-//

-//Redistribution and use in source and binary forms, with or without

-//modification, are permitted provided that the following conditions

-//are met:

-//

-//    Redistributions of source code must retain the above copyright

-//    notice, this list of conditions and the following disclaimer.

-//

-//    Redistributions in binary form must reproduce the above

-//    copyright notice, this list of conditions and the following

-//    disclaimer in the documentation and/or other materials provided

-//    with the distribution.

-//

-//    Neither the name of 3Dlabs Inc. Ltd. nor the names of its

-//    contributors may be used to endorse or promote products derived

-//    from this software without specific prior written permission.

-//

-//THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS

-//"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT

-//LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS

-//FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE

-//COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,

-//INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,

-//BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;

-//LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER

-//CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT

-//LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN

-//ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE

-//POSSIBILITY OF SUCH DAMAGE.

-

-//

-// Author: John Kessenich, LunarG

-//

-

-//

-// Parameterize the SPIR-V enumerants.

-//

-

-#include "spirv.h"

-

-#include <vector>

-

-namespace spv {

-

-// Fill in all the parameters

-void Parameterize();

-

-// Return the English names of all the enums.

-const char* SourceString(int);

-const char* AddressingString(int);

-const char* MemoryString(int);

-const char* ExecutionModelString(int);

-const char* ExecutionModeString(int);

-const char* StorageClassString(int);

-const char* DecorationString(int);

-const char* BuiltInString(int);

-const char* DimensionString(int);

-const char* SelectControlString(int);

-const char* LoopControlString(int);

-const char* FunctionControlString(int);

-const char* SamplerAddressingModeString(int);

-const char* SamplerFilterModeString(int);

-const char* FPFastMathString(int);

-const char* FPRoundingModeString(int);

-const char* LinkageTypeString(int);

-const char* FuncParamAttrString(int);

-const char* AccessQualifierString(int);

-const char* MemorySemanticsString(int);

-const char* MemoryAccessString(int);

-const char* ExecutionScopeString(int);

-const char* GroupOperationString(int);

-const char* KernelEnqueueFlagsString(int);

-const char* KernelProfilingInfoString(int);

-const char* OpcodeString(int);

-

-// For grouping opcodes into subsections

-enum OpcodeClass {

-    OpClassMisc,            // default, until opcode is classified

-    OpClassDebug,

-    OpClassAnnotate,

-    OpClassExtension,

-    OpClassMode,

-    OpClassType,

-    OpClassConstant,

-    OpClassMemory,

-    OpClassFunction,

-    OpClassTexture,

-    OpClassConvert,

-    OpClassComposite,

-    OpClassArithmetic,

-    OpClassRelationalLogical,

-    OpClassDerivative,

-    OpClassFlowControl,

-    OpClassAtomic,

-    OpClassPrimitive,

-    OpClassBarrier,

-    OpClassGroup,

-    OpClassDeviceSideEnqueue,

-    OpClassPipe,

-

-    OpClassCount

-};

-

-// For parameterizing operands.

-enum OperandClass {

-    OperandNone,

-    OperandId,

-    OperandOptionalId,

-    OperandVariableIds,

-    OperandVariableLiterals,

-    OperandVariableLiteralId,

-    OperandLiteralNumber,

-    OperandLiteralString,

-    OperandSource,

-    OperandExecutionModel,

-    OperandAddressing,

-    OperandMemory,

-    OperandExecutionMode,

-    OperandStorage,

-    OperandDimensionality,

-    OperandSamplerAddressingMode,

-    OperandSamplerFilterMode,

-    OperandFPFastMath,

-    OperandFPRoundingMode,

-    OperandLinkageType,

-    OperandAccessQualifier,

-    OperandFuncParamAttr,

-    OperandDecoration,

-    OperandBuiltIn,

-    OperandSelect,

-    OperandLoop,

-    OperandFunction,

-    OperandMemorySemantics,

-    OperandMemoryAccess,

-    OperandExecutionScope,

-	OperandGroupOperation,

-    OperandKernelEnqueueFlags,

-    OperandKernelProfilingInfo,

-

-    OperandOpcode,

-

-    OperandCount

-};

-

-// Set of capabilities.  Generally, something is assumed to be in core,

-// if nothing else is said.  So, these are used to identify when something

-// requires a specific capability to be declared.

-enum Capability {

-    CapMatrix,

-    CapShader,

-    CapGeom,

-    CapTess,

-    CapAddr,

-    CapLink,

-    CapKernel

-};

-

-// Any specific enum can have a set of capabilities that allow it:

-typedef std::vector<Capability> EnumCaps;

-

-// Parameterize a set of operands with their OperandClass(es) and descriptions.

-class OperandParameters {

-public:

-    OperandParameters() { }

-    void push(OperandClass oc, const char* d)

-    {

-        opClass.push_back(oc);

-        desc.push_back(d);

-    }

-    OperandClass getClass(int op) const { return opClass[op]; }

-    const char* getDesc(int op) const { return desc[op]; }

-    int getNum() const { return (int)opClass.size(); }

-

-protected:

-    std::vector<OperandClass> opClass;

-    std::vector<const char*> desc;

-};

-

-// Parameterize an enumerant

-class EnumParameters {

-public:

-    EnumParameters() : desc(0) { }

-    EnumCaps caps;

-    const char* desc;

-};

-

-// Parameterize a set of enumerants that form an enum

-class EnumDefinition : public EnumParameters {

-public:

-    EnumDefinition() : 

-        ceiling(0), bitmask(false), getName(0), enumParams(0), operandParams(0) { }

-    void set(int ceil, const char* (*name)(int), EnumParameters* ep, bool mask = false)

-    {

-        ceiling = ceil;

-        getName = name;

-        bitmask = mask;

-        enumParams = ep;

-    }

-    void setOperands(OperandParameters* op) { operandParams = op; }

-    int ceiling;   // ceiling of enumerants

-    bool bitmask;  // true if these enumerants combine into a bitmask

-    const char* (*getName)(int);      // a function that returns the name for each enumerant value (or shift)

-    EnumParameters* enumParams;       // parameters for each individual enumerant

-    OperandParameters* operandParams; // sets of operands

-};

-

-// Parameterize an instruction's logical format, including its known set of operands,

-// per OperandParameters above.

-class InstructionParameters {

-public:

-    InstructionParameters() :

-        typePresent(true),         // most normal, only exceptions have to be spelled out

-        resultPresent(true),       // most normal, only exceptions have to be spelled out

-        opDesc(0),

-        opClass(OpClassMisc)

-    { }

-

-    void setResultAndType(bool r, bool t)

-    {

-        resultPresent = r;

-        typePresent = t;

-    }

-

-    bool hasResult() const { return resultPresent != 0; }

-    bool hasType()   const { return typePresent != 0; }

-

-    const char* opDesc;

-    EnumCaps capabilities;

-    OpcodeClass opClass;

-    OperandParameters operands;

-

-protected:

-    int typePresent   : 1;

-    int resultPresent : 1;

-};

-

-const int OpcodeCeiling = 267;

-

-// The set of objects that hold all the instruction/operand

-// parameterization information.

-extern InstructionParameters InstructionDesc[];

-

-// These hold definitions of the enumerants used for operands

-extern EnumDefinition OperandClassParams[];

-

-const char* GetOperandDesc(OperandClass operand);

-void PrintImmediateRow(int imm, const char* name, const EnumParameters* enumParams, bool caps, bool hex = false);

-const char* AccessQualifierString(int attr);

-

-void PrintOperands(const OperandParameters& operands, int reservedOperands);

-

-};  // end namespace spv

+//
+//Copyright (C) 2014 LunarG, Inc.
+//
+//All rights reserved.
+//
+//Redistribution and use in source and binary forms, with or without
+//modification, are permitted provided that the following conditions
+//are met:
+//
+//    Redistributions of source code must retain the above copyright
+//    notice, this list of conditions and the following disclaimer.
+//
+//    Redistributions in binary form must reproduce the above
+//    copyright notice, this list of conditions and the following
+//    disclaimer in the documentation and/or other materials provided
+//    with the distribution.
+//
+//    Neither the name of 3Dlabs Inc. Ltd. nor the names of its
+//    contributors may be used to endorse or promote products derived
+//    from this software without specific prior written permission.
+//
+//THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+//"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+//LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+//FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+//COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+//INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+//BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+//LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+//CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+//LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+//ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+//POSSIBILITY OF SUCH DAMAGE.
+
+//
+// Author: John Kessenich, LunarG
+//
+
+//
+// Parameterize the SPIR-V enumerants.
+//
+
+#include "spirv.h"
+
+#include <vector>
+
+namespace spv {
+
+// Fill in all the parameters
+void Parameterize();
+
+// Return the English names of all the enums.
+const char* SourceString(int);
+const char* AddressingString(int);
+const char* MemoryString(int);
+const char* ExecutionModelString(int);
+const char* ExecutionModeString(int);
+const char* StorageClassString(int);
+const char* DecorationString(int);
+const char* BuiltInString(int);
+const char* DimensionString(int);
+const char* SelectControlString(int);
+const char* LoopControlString(int);
+const char* FunctionControlString(int);
+const char* SamplerAddressingModeString(int);
+const char* SamplerFilterModeString(int);
+const char* FPFastMathString(int);
+const char* FPRoundingModeString(int);
+const char* LinkageTypeString(int);
+const char* FuncParamAttrString(int);
+const char* AccessQualifierString(int);
+const char* MemorySemanticsString(int);
+const char* MemoryAccessString(int);
+const char* ExecutionScopeString(int);
+const char* GroupOperationString(int);
+const char* KernelEnqueueFlagsString(int);
+const char* KernelProfilingInfoString(int);
+const char* OpcodeString(int);
+
+// For grouping opcodes into subsections
+enum OpcodeClass {
+    OpClassMisc,            // default, until opcode is classified
+    OpClassDebug,
+    OpClassAnnotate,
+    OpClassExtension,
+    OpClassMode,
+    OpClassType,
+    OpClassConstant,
+    OpClassMemory,
+    OpClassFunction,
+    OpClassTexture,
+    OpClassConvert,
+    OpClassComposite,
+    OpClassArithmetic,
+    OpClassRelationalLogical,
+    OpClassDerivative,
+    OpClassFlowControl,
+    OpClassAtomic,
+    OpClassPrimitive,
+    OpClassBarrier,
+    OpClassGroup,
+    OpClassDeviceSideEnqueue,
+    OpClassPipe,
+
+    OpClassCount
+};
+
+// For parameterizing operands.
+enum OperandClass {
+    OperandNone,
+    OperandId,
+    OperandOptionalId,
+    OperandVariableIds,
+    OperandVariableLiterals,
+    OperandVariableLiteralId,
+    OperandLiteralNumber,
+    OperandLiteralString,
+    OperandSource,
+    OperandExecutionModel,
+    OperandAddressing,
+    OperandMemory,
+    OperandExecutionMode,
+    OperandStorage,
+    OperandDimensionality,
+    OperandSamplerAddressingMode,
+    OperandSamplerFilterMode,
+    OperandFPFastMath,
+    OperandFPRoundingMode,
+    OperandLinkageType,
+    OperandAccessQualifier,
+    OperandFuncParamAttr,
+    OperandDecoration,
+    OperandBuiltIn,
+    OperandSelect,
+    OperandLoop,
+    OperandFunction,
+    OperandMemorySemantics,
+    OperandMemoryAccess,
+    OperandExecutionScope,
+	OperandGroupOperation,
+    OperandKernelEnqueueFlags,
+    OperandKernelProfilingInfo,
+
+    OperandOpcode,
+
+    OperandCount
+};
+
+// Set of capabilities.  Generally, something is assumed to be in core,
+// if nothing else is said.  So, these are used to identify when something
+// requires a specific capability to be declared.
+enum Capability {
+    CapMatrix,
+    CapShader,
+    CapGeom,
+    CapTess,
+    CapAddr,
+    CapLink,
+    CapKernel
+};
+
+// Any specific enum can have a set of capabilities that allow it:
+typedef std::vector<Capability> EnumCaps;
+
+// Parameterize a set of operands with their OperandClass(es) and descriptions.
+class OperandParameters {
+public:
+    OperandParameters() { }
+    void push(OperandClass oc, const char* d)
+    {
+        opClass.push_back(oc);
+        desc.push_back(d);
+    }
+    OperandClass getClass(int op) const { return opClass[op]; }
+    const char* getDesc(int op) const { return desc[op]; }
+    int getNum() const { return (int)opClass.size(); }
+
+protected:
+    std::vector<OperandClass> opClass;
+    std::vector<const char*> desc;
+};
+
+// Parameterize an enumerant
+class EnumParameters {
+public:
+    EnumParameters() : desc(0) { }
+    EnumCaps caps;
+    const char* desc;
+};
+
+// Parameterize a set of enumerants that form an enum
+class EnumDefinition : public EnumParameters {
+public:
+    EnumDefinition() : 
+        ceiling(0), bitmask(false), getName(0), enumParams(0), operandParams(0) { }
+    void set(int ceil, const char* (*name)(int), EnumParameters* ep, bool mask = false)
+    {
+        ceiling = ceil;
+        getName = name;
+        bitmask = mask;
+        enumParams = ep;
+    }
+    void setOperands(OperandParameters* op) { operandParams = op; }
+    int ceiling;   // ceiling of enumerants
+    bool bitmask;  // true if these enumerants combine into a bitmask
+    const char* (*getName)(int);      // a function that returns the name for each enumerant value (or shift)
+    EnumParameters* enumParams;       // parameters for each individual enumerant
+    OperandParameters* operandParams; // sets of operands
+};
+
+// Parameterize an instruction's logical format, including its known set of operands,
+// per OperandParameters above.
+class InstructionParameters {
+public:
+    InstructionParameters() :
+        typePresent(true),         // most normal, only exceptions have to be spelled out
+        resultPresent(true),       // most normal, only exceptions have to be spelled out
+        opDesc(0),
+        opClass(OpClassMisc)
+    { }
+
+    void setResultAndType(bool r, bool t)
+    {
+        resultPresent = r;
+        typePresent = t;
+    }
+
+    bool hasResult() const { return resultPresent != 0; }
+    bool hasType()   const { return typePresent != 0; }
+
+    const char* opDesc;
+    EnumCaps capabilities;
+    OpcodeClass opClass;
+    OperandParameters operands;
+
+protected:
+    int typePresent   : 1;
+    int resultPresent : 1;
+};
+
+const int OpcodeCeiling = 267;
+
+// The set of objects that hold all the instruction/operand
+// parameterization information.
+extern InstructionParameters InstructionDesc[];
+
+// These hold definitions of the enumerants used for operands
+extern EnumDefinition OperandClassParams[];
+
+const char* GetOperandDesc(OperandClass operand);
+void PrintImmediateRow(int imm, const char* name, const EnumParameters* enumParams, bool caps, bool hex = false);
+const char* AccessQualifierString(int attr);
+
+void PrintOperands(const OperandParameters& operands, int reservedOperands);
+
+};  // end namespace spv
diff --git a/SPIRV/spirv.h b/SPIRV/spirv.h
index f3d18a3..dc1e579 100644
--- a/SPIRV/spirv.h
+++ b/SPIRV/spirv.h
@@ -1,1304 +1,1304 @@
-/*

-** Copyright (c) 2015 The Khronos Group Inc.

-**

-** Permission is hereby granted, free of charge, to any person obtaining a copy

-** of this software and/or associated documentation files (the "Materials"),

-** to deal in the Materials without restriction, including without limitation

-** the rights to use, copy, modify, merge, publish, distribute, sublicense,

-** and/or sell copies of the Materials, and to permit persons to whom the

-** Materials are furnished to do so, subject to the following conditions:

-**

-** The above copyright notice and this permission notice shall be included in

-** all copies or substantial portions of the Materials.

-**

-** MODIFICATIONS TO THIS FILE MAY MEAN IT NO LONGER ACCURATELY REFLECTS KHRONOS

-** STANDARDS. THE UNMODIFIED, NORMATIVE VERSIONS OF KHRONOS SPECIFICATIONS AND

-** HEADER INFORMATION ARE LOCATED AT https://www.khronos.org/registry/ 

-**

-** THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS

-** OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,

-** FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL

-** THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER

-** LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING

-** FROM,OUT OF OR IN CONNECTION WITH THE MATERIALS OR THE USE OR OTHER DEALINGS

-** IN THE MATERIALS.

-*/

-

-/*

-** This header is automatically generated by the same tool that creates

-** the Binary Section of the SPIR-V specification.

-*/

-

-/*

-** Specification revision 30.

-** Enumeration tokens for SPIR-V, in three styles: C, C++, generic.

-** - C++ will have the tokens in the "spv" name space, with no prefix.

-** - C will have tokens with as "Spv" prefix.

-**

-** Some tokens act like mask values, which can be OR'd together,

-** while others are mutually exclusive.  The mask-like ones have

-** "Mask" in their name, and a parallel enum that has the shift

-** amount (1 << x) for each corresponding enumerant.

-*/

-

-#ifndef spirv_H

-#define spirv_H

-

-#ifdef __cplusplus

-

-namespace spv {

-

-const int MagicNumber = 0x07230203;

-const int Version = 99;

-

-typedef unsigned int Id;

-

-const unsigned int OpCodeMask = 0xFFFF;

-const unsigned int WordCountShift = 16;

-

-enum SourceLanguage {

-    SourceLanguageUnknown = 0,

-    SourceLanguageESSL = 1,

-    SourceLanguageGLSL = 2,

-    SourceLanguageOpenCL = 3,

-};

-

-enum ExecutionModel {

-    ExecutionModelVertex = 0,

-    ExecutionModelTessellationControl = 1,

-    ExecutionModelTessellationEvaluation = 2,

-    ExecutionModelGeometry = 3,

-    ExecutionModelFragment = 4,

-    ExecutionModelGLCompute = 5,

-    ExecutionModelKernel = 6,

-};

-

-enum AddressingModel {

-    AddressingModelLogical = 0,

-    AddressingModelPhysical32 = 1,

-    AddressingModelPhysical64 = 2,

-};

-

-enum MemoryModel {

-    MemoryModelSimple = 0,

-    MemoryModelGLSL450 = 1,

-    MemoryModelOpenCL12 = 2,

-    MemoryModelOpenCL20 = 3,

-    MemoryModelOpenCL21 = 4,

-};

-

-enum ExecutionMode {

-    ExecutionModeInvocations = 0,

-    ExecutionModeSpacingEqual = 1,

-    ExecutionModeSpacingFractionalEven = 2,

-    ExecutionModeSpacingFractionalOdd = 3,

-    ExecutionModeVertexOrderCw = 4,

-    ExecutionModeVertexOrderCcw = 5,

-    ExecutionModePixelCenterInteger = 6,

-    ExecutionModeOriginUpperLeft = 7,

-    ExecutionModeEarlyFragmentTests = 8,

-    ExecutionModePointMode = 9,

-    ExecutionModeXfb = 10,

-    ExecutionModeDepthReplacing = 11,

-    ExecutionModeDepthAny = 12,

-    ExecutionModeDepthGreater = 13,

-    ExecutionModeDepthLess = 14,

-    ExecutionModeDepthUnchanged = 15,

-    ExecutionModeLocalSize = 16,

-    ExecutionModeLocalSizeHint = 17,

-    ExecutionModeInputPoints = 18,

-    ExecutionModeInputLines = 19,

-    ExecutionModeInputLinesAdjacency = 20,

-    ExecutionModeInputTriangles = 21,

-    ExecutionModeInputTrianglesAdjacency = 22,

-    ExecutionModeInputQuads = 23,

-    ExecutionModeInputIsolines = 24,

-    ExecutionModeOutputVertices = 25,

-    ExecutionModeOutputPoints = 26,

-    ExecutionModeOutputLineStrip = 27,

-    ExecutionModeOutputTriangleStrip = 28,

-    ExecutionModeVecTypeHint = 29,

-    ExecutionModeContractionOff = 30,

-};

-

-enum StorageClass {

-    StorageClassUniformConstant = 0,

-    StorageClassInput = 1,

-    StorageClassUniform = 2,

-    StorageClassOutput = 3,

-    StorageClassWorkgroupLocal = 4,

-    StorageClassWorkgroupGlobal = 5,

-    StorageClassPrivateGlobal = 6,

-    StorageClassFunction = 7,

-    StorageClassGeneric = 8,

-    StorageClassPrivate = 9,

-    StorageClassAtomicCounter = 10,

-};

-

-enum Dim {

-    Dim1D = 0,

-    Dim2D = 1,

-    Dim3D = 2,

-    DimCube = 3,

-    DimRect = 4,

-    DimBuffer = 5,

-};

-

-enum SamplerAddressingMode {

-    SamplerAddressingModeNone = 0,

-    SamplerAddressingModeClampToEdge = 1,

-    SamplerAddressingModeClamp = 2,

-    SamplerAddressingModeRepeat = 3,

-    SamplerAddressingModeRepeatMirrored = 4,

-};

-

-enum SamplerFilterMode {

-    SamplerFilterModeNearest = 0,

-    SamplerFilterModeLinear = 1,

-};

-

-enum FPFastMathModeShift {

-    FPFastMathModeNotNaNShift = 0,

-    FPFastMathModeNotInfShift = 1,

-    FPFastMathModeNSZShift = 2,

-    FPFastMathModeAllowRecipShift = 3,

-    FPFastMathModeFastShift = 4,

-};

-

-enum FPFastMathModeMask {

-    FPFastMathModeMaskNone = 0,

-    FPFastMathModeNotNaNMask = 0x00000001,

-    FPFastMathModeNotInfMask = 0x00000002,

-    FPFastMathModeNSZMask = 0x00000004,

-    FPFastMathModeAllowRecipMask = 0x00000008,

-    FPFastMathModeFastMask = 0x00000010,

-};

-

-enum FPRoundingMode {

-    FPRoundingModeRTE = 0,

-    FPRoundingModeRTZ = 1,

-    FPRoundingModeRTP = 2,

-    FPRoundingModeRTN = 3,

-};

-

-enum LinkageType {

-    LinkageTypeExport = 0,

-    LinkageTypeImport = 1,

-};

-

-enum AccessQualifier {

-    AccessQualifierReadOnly = 0,

-    AccessQualifierWriteOnly = 1,

-    AccessQualifierReadWrite = 2,

-};

-

-enum FunctionParameterAttribute {

-    FunctionParameterAttributeZext = 0,

-    FunctionParameterAttributeSext = 1,

-    FunctionParameterAttributeByVal = 2,

-    FunctionParameterAttributeSret = 3,

-    FunctionParameterAttributeNoAlias = 4,

-    FunctionParameterAttributeNoCapture = 5,

-    FunctionParameterAttributeSVM = 6,

-    FunctionParameterAttributeNoWrite = 7,

-    FunctionParameterAttributeNoReadWrite = 8,

-};

-

-enum Decoration {

-    DecorationPrecisionLow = 0,

-    DecorationPrecisionMedium = 1,

-    DecorationPrecisionHigh = 2,

-    DecorationBlock = 3,

-    DecorationBufferBlock = 4,

-    DecorationRowMajor = 5,

-    DecorationColMajor = 6,

-    DecorationGLSLShared = 7,

-    DecorationGLSLStd140 = 8,

-    DecorationGLSLStd430 = 9,

-    DecorationGLSLPacked = 10,

-    DecorationSmooth = 11,

-    DecorationNoperspective = 12,

-    DecorationFlat = 13,

-    DecorationPatch = 14,

-    DecorationCentroid = 15,

-    DecorationSample = 16,

-    DecorationInvariant = 17,

-    DecorationRestrict = 18,

-    DecorationAliased = 19,

-    DecorationVolatile = 20,

-    DecorationConstant = 21,

-    DecorationCoherent = 22,

-    DecorationNonwritable = 23,

-    DecorationNonreadable = 24,

-    DecorationUniform = 25,

-    DecorationNoStaticUse = 26,

-    DecorationCPacked = 27,

-    DecorationSaturatedConversion = 28,

-    DecorationStream = 29,

-    DecorationLocation = 30,

-    DecorationComponent = 31,

-    DecorationIndex = 32,

-    DecorationBinding = 33,

-    DecorationDescriptorSet = 34,

-    DecorationOffset = 35,

-    DecorationAlignment = 36,

-    DecorationXfbBuffer = 37,

-    DecorationStride = 38,

-    DecorationBuiltIn = 39,

-    DecorationFuncParamAttr = 40,

-    DecorationFPRoundingMode = 41,

-    DecorationFPFastMathMode = 42,

-    DecorationLinkageAttributes = 43,

-    DecorationSpecId = 44,

-};

-

-enum BuiltIn {

-    BuiltInPosition = 0,

-    BuiltInPointSize = 1,

-    BuiltInClipVertex = 2,

-    BuiltInClipDistance = 3,

-    BuiltInCullDistance = 4,

-    BuiltInVertexId = 5,

-    BuiltInInstanceId = 6,

-    BuiltInPrimitiveId = 7,

-    BuiltInInvocationId = 8,

-    BuiltInLayer = 9,

-    BuiltInViewportIndex = 10,

-    BuiltInTessLevelOuter = 11,

-    BuiltInTessLevelInner = 12,

-    BuiltInTessCoord = 13,

-    BuiltInPatchVertices = 14,

-    BuiltInFragCoord = 15,

-    BuiltInPointCoord = 16,

-    BuiltInFrontFacing = 17,

-    BuiltInSampleId = 18,

-    BuiltInSamplePosition = 19,

-    BuiltInSampleMask = 20,

-    BuiltInFragColor = 21,

-    BuiltInFragDepth = 22,

-    BuiltInHelperInvocation = 23,

-    BuiltInNumWorkgroups = 24,

-    BuiltInWorkgroupSize = 25,

-    BuiltInWorkgroupId = 26,

-    BuiltInLocalInvocationId = 27,

-    BuiltInGlobalInvocationId = 28,

-    BuiltInLocalInvocationIndex = 29,

-    BuiltInWorkDim = 30,

-    BuiltInGlobalSize = 31,

-    BuiltInEnqueuedWorkgroupSize = 32,

-    BuiltInGlobalOffset = 33,

-    BuiltInGlobalLinearId = 34,

-    BuiltInWorkgroupLinearId = 35,

-    BuiltInSubgroupSize = 36,

-    BuiltInSubgroupMaxSize = 37,

-    BuiltInNumSubgroups = 38,

-    BuiltInNumEnqueuedSubgroups = 39,

-    BuiltInSubgroupId = 40,

-    BuiltInSubgroupLocalInvocationId = 41,

-};

-

-enum SelectionControlShift {

-    SelectionControlFlattenShift = 0,

-    SelectionControlDontFlattenShift = 1,

-};

-

-enum SelectionControlMask {

-    SelectionControlMaskNone = 0,

-    SelectionControlFlattenMask = 0x00000001,

-    SelectionControlDontFlattenMask = 0x00000002,

-};

-

-enum LoopControlShift {

-    LoopControlUnrollShift = 0,

-    LoopControlDontUnrollShift = 1,

-};

-

-enum LoopControlMask {

-    LoopControlMaskNone = 0,

-    LoopControlUnrollMask = 0x00000001,

-    LoopControlDontUnrollMask = 0x00000002,

-};

-

-enum FunctionControlShift {

-    FunctionControlInlineShift = 0,

-    FunctionControlDontInlineShift = 1,

-    FunctionControlPureShift = 2,

-    FunctionControlConstShift = 3,

-};

-

-enum FunctionControlMask {

-    FunctionControlMaskNone = 0,

-    FunctionControlInlineMask = 0x00000001,

-    FunctionControlDontInlineMask = 0x00000002,

-    FunctionControlPureMask = 0x00000004,

-    FunctionControlConstMask = 0x00000008,

-};

-

-enum MemorySemanticsShift {

-    MemorySemanticsRelaxedShift = 0,

-    MemorySemanticsSequentiallyConsistentShift = 1,

-    MemorySemanticsAcquireShift = 2,

-    MemorySemanticsReleaseShift = 3,

-    MemorySemanticsUniformMemoryShift = 4,

-    MemorySemanticsSubgroupMemoryShift = 5,

-    MemorySemanticsWorkgroupLocalMemoryShift = 6,

-    MemorySemanticsWorkgroupGlobalMemoryShift = 7,

-    MemorySemanticsAtomicCounterMemoryShift = 8,

-    MemorySemanticsImageMemoryShift = 9,

-};

-

-enum MemorySemanticsMask {

-    MemorySemanticsMaskNone = 0,

-    MemorySemanticsRelaxedMask = 0x00000001,

-    MemorySemanticsSequentiallyConsistentMask = 0x00000002,

-    MemorySemanticsAcquireMask = 0x00000004,

-    MemorySemanticsReleaseMask = 0x00000008,

-    MemorySemanticsUniformMemoryMask = 0x00000010,

-    MemorySemanticsSubgroupMemoryMask = 0x00000020,

-    MemorySemanticsWorkgroupLocalMemoryMask = 0x00000040,

-    MemorySemanticsWorkgroupGlobalMemoryMask = 0x00000080,

-    MemorySemanticsAtomicCounterMemoryMask = 0x00000100,

-    MemorySemanticsImageMemoryMask = 0x00000200,

-};

-

-enum MemoryAccessShift {

-    MemoryAccessVolatileShift = 0,

-    MemoryAccessAlignedShift = 1,

-};

-

-enum MemoryAccessMask {

-    MemoryAccessMaskNone = 0,

-    MemoryAccessVolatileMask = 0x00000001,

-    MemoryAccessAlignedMask = 0x00000002,

-};

-

-enum ExecutionScope {

-    ExecutionScopeCrossDevice = 0,

-    ExecutionScopeDevice = 1,

-    ExecutionScopeWorkgroup = 2,

-    ExecutionScopeSubgroup = 3,

-};

-

-enum GroupOperation {

-    GroupOperationReduce = 0,

-    GroupOperationInclusiveScan = 1,

-    GroupOperationExclusiveScan = 2,

-};

-

-enum KernelEnqueueFlags {

-    KernelEnqueueFlagsNoWait = 0,

-    KernelEnqueueFlagsWaitKernel = 1,

-    KernelEnqueueFlagsWaitWorkGroup = 2,

-};

-

-enum KernelProfilingInfoShift {

-    KernelProfilingInfoCmdExecTimeShift = 0,

-};

-

-enum KernelProfilingInfoMask {

-    KernelProfilingInfoMaskNone = 0,

-    KernelProfilingInfoCmdExecTimeMask = 0x00000001,

-};

-

-enum Op {

-    OpNop = 0,

-    OpSource = 1,

-    OpSourceExtension = 2,

-    OpExtension = 3,

-    OpExtInstImport = 4,

-    OpMemoryModel = 5,

-    OpEntryPoint = 6,

-    OpExecutionMode = 7,

-    OpTypeVoid = 8,

-    OpTypeBool = 9,

-    OpTypeInt = 10,

-    OpTypeFloat = 11,

-    OpTypeVector = 12,

-    OpTypeMatrix = 13,

-    OpTypeSampler = 14,

-    OpTypeFilter = 15,

-    OpTypeArray = 16,

-    OpTypeRuntimeArray = 17,

-    OpTypeStruct = 18,

-    OpTypeOpaque = 19,

-    OpTypePointer = 20,

-    OpTypeFunction = 21,

-    OpTypeEvent = 22,

-    OpTypeDeviceEvent = 23,

-    OpTypeReserveId = 24,

-    OpTypeQueue = 25,

-    OpTypePipe = 26,

-    OpConstantTrue = 27,

-    OpConstantFalse = 28,

-    OpConstant = 29,

-    OpConstantComposite = 30,

-    OpConstantSampler = 31,

-    OpConstantNullPointer = 32,

-    OpConstantNullObject = 33,

-    OpSpecConstantTrue = 34,

-    OpSpecConstantFalse = 35,

-    OpSpecConstant = 36,

-    OpSpecConstantComposite = 37,

-    OpVariable = 38,

-    OpVariableArray = 39,

-    OpFunction = 40,

-    OpFunctionParameter = 41,

-    OpFunctionEnd = 42,

-    OpFunctionCall = 43,

-    OpExtInst = 44,

-    OpUndef = 45,

-    OpLoad = 46,

-    OpStore = 47,

-    OpPhi = 48,

-    OpDecorationGroup = 49,

-    OpDecorate = 50,

-    OpMemberDecorate = 51,

-    OpGroupDecorate = 52,

-    OpGroupMemberDecorate = 53,

-    OpName = 54,

-    OpMemberName = 55,

-    OpString = 56,

-    OpLine = 57,

-    OpVectorExtractDynamic = 58,

-    OpVectorInsertDynamic = 59,

-    OpVectorShuffle = 60,

-    OpCompositeConstruct = 61,

-    OpCompositeExtract = 62,

-    OpCompositeInsert = 63,

-    OpCopyObject = 64,

-    OpCopyMemory = 65,

-    OpCopyMemorySized = 66,

-    OpSampler = 67,

-    OpTextureSample = 68,

-    OpTextureSampleDref = 69,

-    OpTextureSampleLod = 70,

-    OpTextureSampleProj = 71,

-    OpTextureSampleGrad = 72,

-    OpTextureSampleOffset = 73,

-    OpTextureSampleProjLod = 74,

-    OpTextureSampleProjGrad = 75,

-    OpTextureSampleLodOffset = 76,

-    OpTextureSampleProjOffset = 77,

-    OpTextureSampleGradOffset = 78,

-    OpTextureSampleProjLodOffset = 79,

-    OpTextureSampleProjGradOffset = 80,

-    OpTextureFetchTexelLod = 81,

-    OpTextureFetchTexelOffset = 82,

-    OpTextureFetchSample = 83,

-    OpTextureFetchTexel = 84,

-    OpTextureGather = 85,

-    OpTextureGatherOffset = 86,

-    OpTextureGatherOffsets = 87,

-    OpTextureQuerySizeLod = 88,

-    OpTextureQuerySize = 89,

-    OpTextureQueryLod = 90,

-    OpTextureQueryLevels = 91,

-    OpTextureQuerySamples = 92,

-    OpAccessChain = 93,

-    OpInBoundsAccessChain = 94,

-    OpSNegate = 95,

-    OpFNegate = 96,

-    OpNot = 97,

-    OpAny = 98,

-    OpAll = 99,

-    OpConvertFToU = 100,

-    OpConvertFToS = 101,

-    OpConvertSToF = 102,

-    OpConvertUToF = 103,

-    OpUConvert = 104,

-    OpSConvert = 105,

-    OpFConvert = 106,

-    OpConvertPtrToU = 107,

-    OpConvertUToPtr = 108,

-    OpPtrCastToGeneric = 109,

-    OpGenericCastToPtr = 110,

-    OpBitcast = 111,

-    OpTranspose = 112,

-    OpIsNan = 113,

-    OpIsInf = 114,

-    OpIsFinite = 115,

-    OpIsNormal = 116,

-    OpSignBitSet = 117,

-    OpLessOrGreater = 118,

-    OpOrdered = 119,

-    OpUnordered = 120,

-    OpArrayLength = 121,

-    OpIAdd = 122,

-    OpFAdd = 123,

-    OpISub = 124,

-    OpFSub = 125,

-    OpIMul = 126,

-    OpFMul = 127,

-    OpUDiv = 128,

-    OpSDiv = 129,

-    OpFDiv = 130,

-    OpUMod = 131,

-    OpSRem = 132,

-    OpSMod = 133,

-    OpFRem = 134,

-    OpFMod = 135,

-    OpVectorTimesScalar = 136,

-    OpMatrixTimesScalar = 137,

-    OpVectorTimesMatrix = 138,

-    OpMatrixTimesVector = 139,

-    OpMatrixTimesMatrix = 140,

-    OpOuterProduct = 141,

-    OpDot = 142,

-    OpShiftRightLogical = 143,

-    OpShiftRightArithmetic = 144,

-    OpShiftLeftLogical = 145,

-    OpLogicalOr = 146,

-    OpLogicalXor = 147,

-    OpLogicalAnd = 148,

-    OpBitwiseOr = 149,

-    OpBitwiseXor = 150,

-    OpBitwiseAnd = 151,

-    OpSelect = 152,

-    OpIEqual = 153,

-    OpFOrdEqual = 154,

-    OpFUnordEqual = 155,

-    OpINotEqual = 156,

-    OpFOrdNotEqual = 157,

-    OpFUnordNotEqual = 158,

-    OpULessThan = 159,

-    OpSLessThan = 160,

-    OpFOrdLessThan = 161,

-    OpFUnordLessThan = 162,

-    OpUGreaterThan = 163,

-    OpSGreaterThan = 164,

-    OpFOrdGreaterThan = 165,

-    OpFUnordGreaterThan = 166,

-    OpULessThanEqual = 167,

-    OpSLessThanEqual = 168,

-    OpFOrdLessThanEqual = 169,

-    OpFUnordLessThanEqual = 170,

-    OpUGreaterThanEqual = 171,

-    OpSGreaterThanEqual = 172,

-    OpFOrdGreaterThanEqual = 173,

-    OpFUnordGreaterThanEqual = 174,

-    OpDPdx = 175,

-    OpDPdy = 176,

-    OpFwidth = 177,

-    OpDPdxFine = 178,

-    OpDPdyFine = 179,

-    OpFwidthFine = 180,

-    OpDPdxCoarse = 181,

-    OpDPdyCoarse = 182,

-    OpFwidthCoarse = 183,

-    OpEmitVertex = 184,

-    OpEndPrimitive = 185,

-    OpEmitStreamVertex = 186,

-    OpEndStreamPrimitive = 187,

-    OpControlBarrier = 188,

-    OpMemoryBarrier = 189,

-    OpImagePointer = 190,

-    OpAtomicInit = 191,

-    OpAtomicLoad = 192,

-    OpAtomicStore = 193,

-    OpAtomicExchange = 194,

-    OpAtomicCompareExchange = 195,

-    OpAtomicCompareExchangeWeak = 196,

-    OpAtomicIIncrement = 197,

-    OpAtomicIDecrement = 198,

-    OpAtomicIAdd = 199,

-    OpAtomicISub = 200,

-    OpAtomicUMin = 201,

-    OpAtomicUMax = 202,

-    OpAtomicAnd = 203,

-    OpAtomicOr = 204,

-    OpAtomicXor = 205,

-    OpLoopMerge = 206,

-    OpSelectionMerge = 207,

-    OpLabel = 208,

-    OpBranch = 209,

-    OpBranchConditional = 210,

-    OpSwitch = 211,

-    OpKill = 212,

-    OpReturn = 213,

-    OpReturnValue = 214,

-    OpUnreachable = 215,

-    OpLifetimeStart = 216,

-    OpLifetimeStop = 217,

-    OpCompileFlag = 218,

-    OpAsyncGroupCopy = 219,

-    OpWaitGroupEvents = 220,

-    OpGroupAll = 221,

-    OpGroupAny = 222,

-    OpGroupBroadcast = 223,

-    OpGroupIAdd = 224,

-    OpGroupFAdd = 225,

-    OpGroupFMin = 226,

-    OpGroupUMin = 227,

-    OpGroupSMin = 228,

-    OpGroupFMax = 229,

-    OpGroupUMax = 230,

-    OpGroupSMax = 231,

-    OpGenericCastToPtrExplicit = 232,

-    OpGenericPtrMemSemantics = 233,

-    OpReadPipe = 234,

-    OpWritePipe = 235,

-    OpReservedReadPipe = 236,

-    OpReservedWritePipe = 237,

-    OpReserveReadPipePackets = 238,

-    OpReserveWritePipePackets = 239,

-    OpCommitReadPipe = 240,

-    OpCommitWritePipe = 241,

-    OpIsValidReserveId = 242,

-    OpGetNumPipePackets = 243,

-    OpGetMaxPipePackets = 244,

-    OpGroupReserveReadPipePackets = 245,

-    OpGroupReserveWritePipePackets = 246,

-    OpGroupCommitReadPipe = 247,

-    OpGroupCommitWritePipe = 248,

-    OpEnqueueMarker = 249,

-    OpEnqueueKernel = 250,

-    OpGetKernelNDrangeSubGroupCount = 251,

-    OpGetKernelNDrangeMaxSubGroupSize = 252,

-    OpGetKernelWorkGroupSize = 253,

-    OpGetKernelPreferredWorkGroupSizeMultiple = 254,

-    OpRetainEvent = 255,

-    OpReleaseEvent = 256,

-    OpCreateUserEvent = 257,

-    OpIsValidEvent = 258,

-    OpSetUserEventStatus = 259,

-    OpCaptureEventProfilingInfo = 260,

-    OpGetDefaultQueue = 261,

-    OpBuildNDRange = 262,

-    OpSatConvertSToU = 263,

-    OpSatConvertUToS = 264,

-    OpAtomicIMin = 265,

-    OpAtomicIMax = 266,

-};

-

-};  // end namespace spv

-

-#endif  // #ifdef __cplusplus

-

-

-#ifndef __cplusplus

-

-const int SpvMagicNumber = 0x07230203;

-const int SpvVersion = 99;

-

-typedef unsigned int SpvId;

-

-const unsigned int SpvOpCodeMask = 0xFFFF;

-const unsigned int SpvWordCountShift = 16;

-

-typedef enum SpvSourceLanguage_ {

-    SpvSourceLanguageUnknown = 0,

-    SpvSourceLanguageESSL = 1,

-    SpvSourceLanguageGLSL = 2,

-    SpvSourceLanguageOpenCL = 3,

-} SpvSourceLanguage;

-

-typedef enum SpvExecutionModel_ {

-    SpvExecutionModelVertex = 0,

-    SpvExecutionModelTessellationControl = 1,

-    SpvExecutionModelTessellationEvaluation = 2,

-    SpvExecutionModelGeometry = 3,

-    SpvExecutionModelFragment = 4,

-    SpvExecutionModelGLCompute = 5,

-    SpvExecutionModelKernel = 6,

-} SpvExecutionModel;

-

-typedef enum SpvAddressingModel_ {

-    SpvAddressingModelLogical = 0,

-    SpvAddressingModelPhysical32 = 1,

-    SpvAddressingModelPhysical64 = 2,

-} SpvAddressingModel;

-

-typedef enum SpvMemoryModel_ {

-    SpvMemoryModelSimple = 0,

-    SpvMemoryModelGLSL450 = 1,

-    SpvMemoryModelOpenCL12 = 2,

-    SpvMemoryModelOpenCL20 = 3,

-    SpvMemoryModelOpenCL21 = 4,

-} SpvMemoryModel;

-

-typedef enum SpvExecutionMode_ {

-    SpvExecutionModeInvocations = 0,

-    SpvExecutionModeSpacingEqual = 1,

-    SpvExecutionModeSpacingFractionalEven = 2,

-    SpvExecutionModeSpacingFractionalOdd = 3,

-    SpvExecutionModeVertexOrderCw = 4,

-    SpvExecutionModeVertexOrderCcw = 5,

-    SpvExecutionModePixelCenterInteger = 6,

-    SpvExecutionModeOriginUpperLeft = 7,

-    SpvExecutionModeEarlyFragmentTests = 8,

-    SpvExecutionModePointMode = 9,

-    SpvExecutionModeXfb = 10,

-    SpvExecutionModeDepthReplacing = 11,

-    SpvExecutionModeDepthAny = 12,

-    SpvExecutionModeDepthGreater = 13,

-    SpvExecutionModeDepthLess = 14,

-    SpvExecutionModeDepthUnchanged = 15,

-    SpvExecutionModeLocalSize = 16,

-    SpvExecutionModeLocalSizeHint = 17,

-    SpvExecutionModeInputPoints = 18,

-    SpvExecutionModeInputLines = 19,

-    SpvExecutionModeInputLinesAdjacency = 20,

-    SpvExecutionModeInputTriangles = 21,

-    SpvExecutionModeInputTrianglesAdjacency = 22,

-    SpvExecutionModeInputQuads = 23,

-    SpvExecutionModeInputIsolines = 24,

-    SpvExecutionModeOutputVertices = 25,

-    SpvExecutionModeOutputPoints = 26,

-    SpvExecutionModeOutputLineStrip = 27,

-    SpvExecutionModeOutputTriangleStrip = 28,

-    SpvExecutionModeVecTypeHint = 29,

-    SpvExecutionModeContractionOff = 30,

-} SpvExecutionMode;

-

-typedef enum SpvStorageClass_ {

-    SpvStorageClassUniformConstant = 0,

-    SpvStorageClassInput = 1,

-    SpvStorageClassUniform = 2,

-    SpvStorageClassOutput = 3,

-    SpvStorageClassWorkgroupLocal = 4,

-    SpvStorageClassWorkgroupGlobal = 5,

-    SpvStorageClassPrivateGlobal = 6,

-    SpvStorageClassFunction = 7,

-    SpvStorageClassGeneric = 8,

-    SpvStorageClassPrivate = 9,

-    SpvStorageClassAtomicCounter = 10,

-} SpvStorageClass;

-

-typedef enum SpvDim_ {

-    SpvDim1D = 0,

-    SpvDim2D = 1,

-    SpvDim3D = 2,

-    SpvDimCube = 3,

-    SpvDimRect = 4,

-    SpvDimBuffer = 5,

-} SpvDim;

-

-typedef enum SpvSamplerAddressingMode_ {

-    SpvSamplerAddressingModeNone = 0,

-    SpvSamplerAddressingModeClampToEdge = 1,

-    SpvSamplerAddressingModeClamp = 2,

-    SpvSamplerAddressingModeRepeat = 3,

-    SpvSamplerAddressingModeRepeatMirrored = 4,

-} SpvSamplerAddressingMode;

-

-typedef enum SpvSamplerFilterMode_ {

-    SpvSamplerFilterModeNearest = 0,

-    SpvSamplerFilterModeLinear = 1,

-} SpvSamplerFilterMode;

-

-typedef enum SpvFPFastMathModeShift_ {

-    SpvFPFastMathModeNotNaNShift = 0,

-    SpvFPFastMathModeNotInfShift = 1,

-    SpvFPFastMathModeNSZShift = 2,

-    SpvFPFastMathModeAllowRecipShift = 3,

-    SpvFPFastMathModeFastShift = 4,

-} SpvFPFastMathModeShift;

-

-typedef enum SpvFPFastMathModeMask_ {

-    SpvFPFastMathModeMaskNone = 0,

-    SpvFPFastMathModeNotNaNMask = 0x00000001,

-    SpvFPFastMathModeNotInfMask = 0x00000002,

-    SpvFPFastMathModeNSZMask = 0x00000004,

-    SpvFPFastMathModeAllowRecipMask = 0x00000008,

-    SpvFPFastMathModeFastMask = 0x00000010,

-} SpvFPFastMathModeMask;

-

-typedef enum SpvFPRoundingMode_ {

-    SpvFPRoundingModeRTE = 0,

-    SpvFPRoundingModeRTZ = 1,

-    SpvFPRoundingModeRTP = 2,

-    SpvFPRoundingModeRTN = 3,

-} SpvFPRoundingMode;

-

-typedef enum SpvLinkageType_ {

-    SpvLinkageTypeExport = 0,

-    SpvLinkageTypeImport = 1,

-} SpvLinkageType;

-

-typedef enum SpvAccessQualifier_ {

-    SpvAccessQualifierReadOnly = 0,

-    SpvAccessQualifierWriteOnly = 1,

-    SpvAccessQualifierReadWrite = 2,

-} SpvAccessQualifier;

-

-typedef enum SpvFunctionParameterAttribute_ {

-    SpvFunctionParameterAttributeZext = 0,

-    SpvFunctionParameterAttributeSext = 1,

-    SpvFunctionParameterAttributeByVal = 2,

-    SpvFunctionParameterAttributeSret = 3,

-    SpvFunctionParameterAttributeNoAlias = 4,

-    SpvFunctionParameterAttributeNoCapture = 5,

-    SpvFunctionParameterAttributeSVM = 6,

-    SpvFunctionParameterAttributeNoWrite = 7,

-    SpvFunctionParameterAttributeNoReadWrite = 8,

-} SpvFunctionParameterAttribute;

-

-typedef enum SpvDecoration_ {

-    SpvDecorationPrecisionLow = 0,

-    SpvDecorationPrecisionMedium = 1,

-    SpvDecorationPrecisionHigh = 2,

-    SpvDecorationBlock = 3,

-    SpvDecorationBufferBlock = 4,

-    SpvDecorationRowMajor = 5,

-    SpvDecorationColMajor = 6,

-    SpvDecorationGLSLShared = 7,

-    SpvDecorationGLSLStd140 = 8,

-    SpvDecorationGLSLStd430 = 9,

-    SpvDecorationGLSLPacked = 10,

-    SpvDecorationSmooth = 11,

-    SpvDecorationNoperspective = 12,

-    SpvDecorationFlat = 13,

-    SpvDecorationPatch = 14,

-    SpvDecorationCentroid = 15,

-    SpvDecorationSample = 16,

-    SpvDecorationInvariant = 17,

-    SpvDecorationRestrict = 18,

-    SpvDecorationAliased = 19,

-    SpvDecorationVolatile = 20,

-    SpvDecorationConstant = 21,

-    SpvDecorationCoherent = 22,

-    SpvDecorationNonwritable = 23,

-    SpvDecorationNonreadable = 24,

-    SpvDecorationUniform = 25,

-    SpvDecorationNoStaticUse = 26,

-    SpvDecorationCPacked = 27,

-    SpvDecorationSaturatedConversion = 28,

-    SpvDecorationStream = 29,

-    SpvDecorationLocation = 30,

-    SpvDecorationComponent = 31,

-    SpvDecorationIndex = 32,

-    SpvDecorationBinding = 33,

-    SpvDecorationDescriptorSet = 34,

-    SpvDecorationOffset = 35,

-    SpvDecorationAlignment = 36,

-    SpvDecorationXfbBuffer = 37,

-    SpvDecorationStride = 38,

-    SpvDecorationBuiltIn = 39,

-    SpvDecorationFuncParamAttr = 40,

-    SpvDecorationFPRoundingMode = 41,

-    SpvDecorationFPFastMathMode = 42,

-    SpvDecorationLinkageAttributes = 43,

-    SpvDecorationSpecId = 44,

-} SpvDecoration;

-

-typedef enum SpvBuiltIn_ {

-    SpvBuiltInPosition = 0,

-    SpvBuiltInPointSize = 1,

-    SpvBuiltInClipVertex = 2,

-    SpvBuiltInClipDistance = 3,

-    SpvBuiltInCullDistance = 4,

-    SpvBuiltInVertexId = 5,

-    SpvBuiltInInstanceId = 6,

-    SpvBuiltInPrimitiveId = 7,

-    SpvBuiltInInvocationId = 8,

-    SpvBuiltInLayer = 9,

-    SpvBuiltInViewportIndex = 10,

-    SpvBuiltInTessLevelOuter = 11,

-    SpvBuiltInTessLevelInner = 12,

-    SpvBuiltInTessCoord = 13,

-    SpvBuiltInPatchVertices = 14,

-    SpvBuiltInFragCoord = 15,

-    SpvBuiltInPointCoord = 16,

-    SpvBuiltInFrontFacing = 17,

-    SpvBuiltInSampleId = 18,

-    SpvBuiltInSamplePosition = 19,

-    SpvBuiltInSampleMask = 20,

-    SpvBuiltInFragColor = 21,

-    SpvBuiltInFragDepth = 22,

-    SpvBuiltInHelperInvocation = 23,

-    SpvBuiltInNumWorkgroups = 24,

-    SpvBuiltInWorkgroupSize = 25,

-    SpvBuiltInWorkgroupId = 26,

-    SpvBuiltInLocalInvocationId = 27,

-    SpvBuiltInGlobalInvocationId = 28,

-    SpvBuiltInLocalInvocationIndex = 29,

-    SpvBuiltInWorkDim = 30,

-    SpvBuiltInGlobalSize = 31,

-    SpvBuiltInEnqueuedWorkgroupSize = 32,

-    SpvBuiltInGlobalOffset = 33,

-    SpvBuiltInGlobalLinearId = 34,

-    SpvBuiltInWorkgroupLinearId = 35,

-    SpvBuiltInSubgroupSize = 36,

-    SpvBuiltInSubgroupMaxSize = 37,

-    SpvBuiltInNumSubgroups = 38,

-    SpvBuiltInNumEnqueuedSubgroups = 39,

-    SpvBuiltInSubgroupId = 40,

-    SpvBuiltInSubgroupLocalInvocationId = 41,

-} SpvBuiltIn;

-

-typedef enum SpvSelectionControlShift_ {

-    SpvSelectionControlFlattenShift = 0,

-    SpvSelectionControlDontFlattenShift = 1,

-} SpvSelectionControlShift;

-

-typedef enum SpvSelectionControlMask_ {

-    SpvSelectionControlMaskNone = 0,

-    SpvSelectionControlFlattenMask = 0x00000001,

-    SpvSelectionControlDontFlattenMask = 0x00000002,

-} SpvSelectionControlMask;

-

-typedef enum SpvLoopControlShift_ {

-    SpvLoopControlUnrollShift = 0,

-    SpvLoopControlDontUnrollShift = 1,

-} SpvLoopControlShift;

-

-typedef enum SpvLoopControlMask_ {

-    SpvLoopControlMaskNone = 0,

-    SpvLoopControlUnrollMask = 0x00000001,

-    SpvLoopControlDontUnrollMask = 0x00000002,

-} SpvLoopControlMask;

-

-typedef enum SpvFunctionControlShift_ {

-    SpvFunctionControlInlineShift = 0,

-    SpvFunctionControlDontInlineShift = 1,

-    SpvFunctionControlPureShift = 2,

-    SpvFunctionControlConstShift = 3,

-} SpvFunctionControlShift;

-

-typedef enum SpvFunctionControlMask_ {

-    SpvFunctionControlMaskNone = 0,

-    SpvFunctionControlInlineMask = 0x00000001,

-    SpvFunctionControlDontInlineMask = 0x00000002,

-    SpvFunctionControlPureMask = 0x00000004,

-    SpvFunctionControlConstMask = 0x00000008,

-} SpvFunctionControlMask;

-

-typedef enum SpvMemorySemanticsShift_ {

-    SpvMemorySemanticsRelaxedShift = 0,

-    SpvMemorySemanticsSequentiallyConsistentShift = 1,

-    SpvMemorySemanticsAcquireShift = 2,

-    SpvMemorySemanticsReleaseShift = 3,

-    SpvMemorySemanticsUniformMemoryShift = 4,

-    SpvMemorySemanticsSubgroupMemoryShift = 5,

-    SpvMemorySemanticsWorkgroupLocalMemoryShift = 6,

-    SpvMemorySemanticsWorkgroupGlobalMemoryShift = 7,

-    SpvMemorySemanticsAtomicCounterMemoryShift = 8,

-    SpvMemorySemanticsImageMemoryShift = 9,

-} SpvMemorySemanticsShift;

-

-typedef enum SpvMemorySemanticsMask_ {

-    SpvMemorySemanticsMaskNone = 0,

-    SpvMemorySemanticsRelaxedMask = 0x00000001,

-    SpvMemorySemanticsSequentiallyConsistentMask = 0x00000002,

-    SpvMemorySemanticsAcquireMask = 0x00000004,

-    SpvMemorySemanticsReleaseMask = 0x00000008,

-    SpvMemorySemanticsUniformMemoryMask = 0x00000010,

-    SpvMemorySemanticsSubgroupMemoryMask = 0x00000020,

-    SpvMemorySemanticsWorkgroupLocalMemoryMask = 0x00000040,

-    SpvMemorySemanticsWorkgroupGlobalMemoryMask = 0x00000080,

-    SpvMemorySemanticsAtomicCounterMemoryMask = 0x00000100,

-    SpvMemorySemanticsImageMemoryMask = 0x00000200,

-} SpvMemorySemanticsMask;

-

-typedef enum SpvMemoryAccessShift_ {

-    SpvMemoryAccessVolatileShift = 0,

-    SpvMemoryAccessAlignedShift = 1,

-} SpvMemoryAccessShift;

-

-typedef enum SpvMemoryAccessMask_ {

-    SpvMemoryAccessMaskNone = 0,

-    SpvMemoryAccessVolatileMask = 0x00000001,

-    SpvMemoryAccessAlignedMask = 0x00000002,

-} SpvMemoryAccessMask;

-

-typedef enum SpvExecutionScope_ {

-    SpvExecutionScopeCrossDevice = 0,

-    SpvExecutionScopeDevice = 1,

-    SpvExecutionScopeWorkgroup = 2,

-    SpvExecutionScopeSubgroup = 3,

-} SpvExecutionScope;

-

-typedef enum SpvGroupOperation_ {

-    SpvGroupOperationReduce = 0,

-    SpvGroupOperationInclusiveScan = 1,

-    SpvGroupOperationExclusiveScan = 2,

-} SpvGroupOperation;

-

-typedef enum SpvKernelEnqueueFlags_ {

-    SpvKernelEnqueueFlagsNoWait = 0,

-    SpvKernelEnqueueFlagsWaitKernel = 1,

-    SpvKernelEnqueueFlagsWaitWorkGroup = 2,

-} SpvKernelEnqueueFlags;

-

-typedef enum SpvKernelProfilingInfoShift_ {

-    SpvKernelProfilingInfoCmdExecTimeShift = 0,

-} SpvKernelProfilingInfoShift;

-

-typedef enum SpvKernelProfilingInfoMask_ {

-    SpvKernelProfilingInfoMaskNone = 0,

-    SpvKernelProfilingInfoCmdExecTimeMask = 0x00000001,

-} SpvKernelProfilingInfoMask;

-

-typedef enum SpvOp_ {

-    SpvOpNop = 0,

-    SpvOpSource = 1,

-    SpvOpSourceExtension = 2,

-    SpvOpExtension = 3,

-    SpvOpExtInstImport = 4,

-    SpvOpMemoryModel = 5,

-    SpvOpEntryPoint = 6,

-    SpvOpExecutionMode = 7,

-    SpvOpTypeVoid = 8,

-    SpvOpTypeBool = 9,

-    SpvOpTypeInt = 10,

-    SpvOpTypeFloat = 11,

-    SpvOpTypeVector = 12,

-    SpvOpTypeMatrix = 13,

-    SpvOpTypeSampler = 14,

-    SpvOpTypeFilter = 15,

-    SpvOpTypeArray = 16,

-    SpvOpTypeRuntimeArray = 17,

-    SpvOpTypeStruct = 18,

-    SpvOpTypeOpaque = 19,

-    SpvOpTypePointer = 20,

-    SpvOpTypeFunction = 21,

-    SpvOpTypeEvent = 22,

-    SpvOpTypeDeviceEvent = 23,

-    SpvOpTypeReserveId = 24,

-    SpvOpTypeQueue = 25,

-    SpvOpTypePipe = 26,

-    SpvOpConstantTrue = 27,

-    SpvOpConstantFalse = 28,

-    SpvOpConstant = 29,

-    SpvOpConstantComposite = 30,

-    SpvOpConstantSampler = 31,

-    SpvOpConstantNullPointer = 32,

-    SpvOpConstantNullObject = 33,

-    SpvOpSpecConstantTrue = 34,

-    SpvOpSpecConstantFalse = 35,

-    SpvOpSpecConstant = 36,

-    SpvOpSpecConstantComposite = 37,

-    SpvOpVariable = 38,

-    SpvOpVariableArray = 39,

-    SpvOpFunction = 40,

-    SpvOpFunctionParameter = 41,

-    SpvOpFunctionEnd = 42,

-    SpvOpFunctionCall = 43,

-    SpvOpExtInst = 44,

-    SpvOpUndef = 45,

-    SpvOpLoad = 46,

-    SpvOpStore = 47,

-    SpvOpPhi = 48,

-    SpvOpDecorationGroup = 49,

-    SpvOpDecorate = 50,

-    SpvOpMemberDecorate = 51,

-    SpvOpGroupDecorate = 52,

-    SpvOpGroupMemberDecorate = 53,

-    SpvOpName = 54,

-    SpvOpMemberName = 55,

-    SpvOpString = 56,

-    SpvOpLine = 57,

-    SpvOpVectorExtractDynamic = 58,

-    SpvOpVectorInsertDynamic = 59,

-    SpvOpVectorShuffle = 60,

-    SpvOpCompositeConstruct = 61,

-    SpvOpCompositeExtract = 62,

-    SpvOpCompositeInsert = 63,

-    SpvOpCopyObject = 64,

-    SpvOpCopyMemory = 65,

-    SpvOpCopyMemorySized = 66,

-    SpvOpSampler = 67,

-    SpvOpTextureSample = 68,

-    SpvOpTextureSampleDref = 69,

-    SpvOpTextureSampleLod = 70,

-    SpvOpTextureSampleProj = 71,

-    SpvOpTextureSampleGrad = 72,

-    SpvOpTextureSampleOffset = 73,

-    SpvOpTextureSampleProjLod = 74,

-    SpvOpTextureSampleProjGrad = 75,

-    SpvOpTextureSampleLodOffset = 76,

-    SpvOpTextureSampleProjOffset = 77,

-    SpvOpTextureSampleGradOffset = 78,

-    SpvOpTextureSampleProjLodOffset = 79,

-    SpvOpTextureSampleProjGradOffset = 80,

-    SpvOpTextureFetchTexelLod = 81,

-    SpvOpTextureFetchTexelOffset = 82,

-    SpvOpTextureFetchSample = 83,

-    SpvOpTextureFetchTexel = 84,

-    SpvOpTextureGather = 85,

-    SpvOpTextureGatherOffset = 86,

-    SpvOpTextureGatherOffsets = 87,

-    SpvOpTextureQuerySizeLod = 88,

-    SpvOpTextureQuerySize = 89,

-    SpvOpTextureQueryLod = 90,

-    SpvOpTextureQueryLevels = 91,

-    SpvOpTextureQuerySamples = 92,

-    SpvOpAccessChain = 93,

-    SpvOpInBoundsAccessChain = 94,

-    SpvOpSNegate = 95,

-    SpvOpFNegate = 96,

-    SpvOpNot = 97,

-    SpvOpAny = 98,

-    SpvOpAll = 99,

-    SpvOpConvertFToU = 100,

-    SpvOpConvertFToS = 101,

-    SpvOpConvertSToF = 102,

-    SpvOpConvertUToF = 103,

-    SpvOpUConvert = 104,

-    SpvOpSConvert = 105,

-    SpvOpFConvert = 106,

-    SpvOpConvertPtrToU = 107,

-    SpvOpConvertUToPtr = 108,

-    SpvOpPtrCastToGeneric = 109,

-    SpvOpGenericCastToPtr = 110,

-    SpvOpBitcast = 111,

-    SpvOpTranspose = 112,

-    SpvOpIsNan = 113,

-    SpvOpIsInf = 114,

-    SpvOpIsFinite = 115,

-    SpvOpIsNormal = 116,

-    SpvOpSignBitSet = 117,

-    SpvOpLessOrGreater = 118,

-    SpvOpOrdered = 119,

-    SpvOpUnordered = 120,

-    SpvOpArrayLength = 121,

-    SpvOpIAdd = 122,

-    SpvOpFAdd = 123,

-    SpvOpISub = 124,

-    SpvOpFSub = 125,

-    SpvOpIMul = 126,

-    SpvOpFMul = 127,

-    SpvOpUDiv = 128,

-    SpvOpSDiv = 129,

-    SpvOpFDiv = 130,

-    SpvOpUMod = 131,

-    SpvOpSRem = 132,

-    SpvOpSMod = 133,

-    SpvOpFRem = 134,

-    SpvOpFMod = 135,

-    SpvOpVectorTimesScalar = 136,

-    SpvOpMatrixTimesScalar = 137,

-    SpvOpVectorTimesMatrix = 138,

-    SpvOpMatrixTimesVector = 139,

-    SpvOpMatrixTimesMatrix = 140,

-    SpvOpOuterProduct = 141,

-    SpvOpDot = 142,

-    SpvOpShiftRightLogical = 143,

-    SpvOpShiftRightArithmetic = 144,

-    SpvOpShiftLeftLogical = 145,

-    SpvOpLogicalOr = 146,

-    SpvOpLogicalXor = 147,

-    SpvOpLogicalAnd = 148,

-    SpvOpBitwiseOr = 149,

-    SpvOpBitwiseXor = 150,

-    SpvOpBitwiseAnd = 151,

-    SpvOpSelect = 152,

-    SpvOpIEqual = 153,

-    SpvOpFOrdEqual = 154,

-    SpvOpFUnordEqual = 155,

-    SpvOpINotEqual = 156,

-    SpvOpFOrdNotEqual = 157,

-    SpvOpFUnordNotEqual = 158,

-    SpvOpULessThan = 159,

-    SpvOpSLessThan = 160,

-    SpvOpFOrdLessThan = 161,

-    SpvOpFUnordLessThan = 162,

-    SpvOpUGreaterThan = 163,

-    SpvOpSGreaterThan = 164,

-    SpvOpFOrdGreaterThan = 165,

-    SpvOpFUnordGreaterThan = 166,

-    SpvOpULessThanEqual = 167,

-    SpvOpSLessThanEqual = 168,

-    SpvOpFOrdLessThanEqual = 169,

-    SpvOpFUnordLessThanEqual = 170,

-    SpvOpUGreaterThanEqual = 171,

-    SpvOpSGreaterThanEqual = 172,

-    SpvOpFOrdGreaterThanEqual = 173,

-    SpvOpFUnordGreaterThanEqual = 174,

-    SpvOpDPdx = 175,

-    SpvOpDPdy = 176,

-    SpvOpFwidth = 177,

-    SpvOpDPdxFine = 178,

-    SpvOpDPdyFine = 179,

-    SpvOpFwidthFine = 180,

-    SpvOpDPdxCoarse = 181,

-    SpvOpDPdyCoarse = 182,

-    SpvOpFwidthCoarse = 183,

-    SpvOpEmitVertex = 184,

-    SpvOpEndPrimitive = 185,

-    SpvOpEmitStreamVertex = 186,

-    SpvOpEndStreamPrimitive = 187,

-    SpvOpControlBarrier = 188,

-    SpvOpMemoryBarrier = 189,

-    SpvOpImagePointer = 190,

-    SpvOpAtomicInit = 191,

-    SpvOpAtomicLoad = 192,

-    SpvOpAtomicStore = 193,

-    SpvOpAtomicExchange = 194,

-    SpvOpAtomicCompareExchange = 195,

-    SpvOpAtomicCompareExchangeWeak = 196,

-    SpvOpAtomicIIncrement = 197,

-    SpvOpAtomicIDecrement = 198,

-    SpvOpAtomicIAdd = 199,

-    SpvOpAtomicISub = 200,

-    SpvOpAtomicUMin = 201,

-    SpvOpAtomicUMax = 202,

-    SpvOpAtomicAnd = 203,

-    SpvOpAtomicOr = 204,

-    SpvOpAtomicXor = 205,

-    SpvOpLoopMerge = 206,

-    SpvOpSelectionMerge = 207,

-    SpvOpLabel = 208,

-    SpvOpBranch = 209,

-    SpvOpBranchConditional = 210,

-    SpvOpSwitch = 211,

-    SpvOpKill = 212,

-    SpvOpReturn = 213,

-    SpvOpReturnValue = 214,

-    SpvOpUnreachable = 215,

-    SpvOpLifetimeStart = 216,

-    SpvOpLifetimeStop = 217,

-    SpvOpCompileFlag = 218,

-    SpvOpAsyncGroupCopy = 219,

-    SpvOpWaitGroupEvents = 220,

-    SpvOpGroupAll = 221,

-    SpvOpGroupAny = 222,

-    SpvOpGroupBroadcast = 223,

-    SpvOpGroupIAdd = 224,

-    SpvOpGroupFAdd = 225,

-    SpvOpGroupFMin = 226,

-    SpvOpGroupUMin = 227,

-    SpvOpGroupSMin = 228,

-    SpvOpGroupFMax = 229,

-    SpvOpGroupUMax = 230,

-    SpvOpGroupSMax = 231,

-    SpvOpGenericCastToPtrExplicit = 232,

-    SpvOpGenericPtrMemSemantics = 233,

-    SpvOpReadPipe = 234,

-    SpvOpWritePipe = 235,

-    SpvOpReservedReadPipe = 236,

-    SpvOpReservedWritePipe = 237,

-    SpvOpReserveReadPipePackets = 238,

-    SpvOpReserveWritePipePackets = 239,

-    SpvOpCommitReadPipe = 240,

-    SpvOpCommitWritePipe = 241,

-    SpvOpIsValidReserveId = 242,

-    SpvOpGetNumPipePackets = 243,

-    SpvOpGetMaxPipePackets = 244,

-    SpvOpGroupReserveReadPipePackets = 245,

-    SpvOpGroupReserveWritePipePackets = 246,

-    SpvOpGroupCommitReadPipe = 247,

-    SpvOpGroupCommitWritePipe = 248,

-    SpvOpEnqueueMarker = 249,

-    SpvOpEnqueueKernel = 250,

-    SpvOpGetKernelNDrangeSubGroupCount = 251,

-    SpvOpGetKernelNDrangeMaxSubGroupSize = 252,

-    SpvOpGetKernelWorkGroupSize = 253,

-    SpvOpGetKernelPreferredWorkGroupSizeMultiple = 254,

-    SpvOpRetainEvent = 255,

-    SpvOpReleaseEvent = 256,

-    SpvOpCreateUserEvent = 257,

-    SpvOpIsValidEvent = 258,

-    SpvOpSetUserEventStatus = 259,

-    SpvOpCaptureEventProfilingInfo = 260,

-    SpvOpGetDefaultQueue = 261,

-    SpvOpBuildNDRange = 262,

-    SpvOpSatConvertSToU = 263,

-    SpvOpSatConvertUToS = 264,

-    SpvOpAtomicIMin = 265,

-    SpvOpAtomicIMax = 266,

-} SpvOp;

-

-#endif  // #ifndef __cplusplus

-

-#endif  // #ifndef spirv_H

+/*
+** Copyright (c) 2015 The Khronos Group Inc.
+**
+** Permission is hereby granted, free of charge, to any person obtaining a copy
+** of this software and/or associated documentation files (the "Materials"),
+** to deal in the Materials without restriction, including without limitation
+** the rights to use, copy, modify, merge, publish, distribute, sublicense,
+** and/or sell copies of the Materials, and to permit persons to whom the
+** Materials are furnished to do so, subject to the following conditions:
+**
+** The above copyright notice and this permission notice shall be included in
+** all copies or substantial portions of the Materials.
+**
+** MODIFICATIONS TO THIS FILE MAY MEAN IT NO LONGER ACCURATELY REFLECTS KHRONOS
+** STANDARDS. THE UNMODIFIED, NORMATIVE VERSIONS OF KHRONOS SPECIFICATIONS AND
+** HEADER INFORMATION ARE LOCATED AT https://www.khronos.org/registry/ 
+**
+** THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+** OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+** FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+** THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+** LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+** FROM,OUT OF OR IN CONNECTION WITH THE MATERIALS OR THE USE OR OTHER DEALINGS
+** IN THE MATERIALS.
+*/
+
+/*
+** This header is automatically generated by the same tool that creates
+** the Binary Section of the SPIR-V specification.
+*/
+
+/*
+** Specification revision 30.
+** Enumeration tokens for SPIR-V, in three styles: C, C++, generic.
+** - C++ will have the tokens in the "spv" name space, with no prefix.
+** - C will have tokens with as "Spv" prefix.
+**
+** Some tokens act like mask values, which can be OR'd together,
+** while others are mutually exclusive.  The mask-like ones have
+** "Mask" in their name, and a parallel enum that has the shift
+** amount (1 << x) for each corresponding enumerant.
+*/
+
+#ifndef spirv_H
+#define spirv_H
+
+#ifdef __cplusplus
+
+namespace spv {
+
+const int MagicNumber = 0x07230203;
+const int Version = 99;
+
+typedef unsigned int Id;
+
+const unsigned int OpCodeMask = 0xFFFF;
+const unsigned int WordCountShift = 16;
+
+enum SourceLanguage {
+    SourceLanguageUnknown = 0,
+    SourceLanguageESSL = 1,
+    SourceLanguageGLSL = 2,
+    SourceLanguageOpenCL = 3,
+};
+
+enum ExecutionModel {
+    ExecutionModelVertex = 0,
+    ExecutionModelTessellationControl = 1,
+    ExecutionModelTessellationEvaluation = 2,
+    ExecutionModelGeometry = 3,
+    ExecutionModelFragment = 4,
+    ExecutionModelGLCompute = 5,
+    ExecutionModelKernel = 6,
+};
+
+enum AddressingModel {
+    AddressingModelLogical = 0,
+    AddressingModelPhysical32 = 1,
+    AddressingModelPhysical64 = 2,
+};
+
+enum MemoryModel {
+    MemoryModelSimple = 0,
+    MemoryModelGLSL450 = 1,
+    MemoryModelOpenCL12 = 2,
+    MemoryModelOpenCL20 = 3,
+    MemoryModelOpenCL21 = 4,
+};
+
+enum ExecutionMode {
+    ExecutionModeInvocations = 0,
+    ExecutionModeSpacingEqual = 1,
+    ExecutionModeSpacingFractionalEven = 2,
+    ExecutionModeSpacingFractionalOdd = 3,
+    ExecutionModeVertexOrderCw = 4,
+    ExecutionModeVertexOrderCcw = 5,
+    ExecutionModePixelCenterInteger = 6,
+    ExecutionModeOriginUpperLeft = 7,
+    ExecutionModeEarlyFragmentTests = 8,
+    ExecutionModePointMode = 9,
+    ExecutionModeXfb = 10,
+    ExecutionModeDepthReplacing = 11,
+    ExecutionModeDepthAny = 12,
+    ExecutionModeDepthGreater = 13,
+    ExecutionModeDepthLess = 14,
+    ExecutionModeDepthUnchanged = 15,
+    ExecutionModeLocalSize = 16,
+    ExecutionModeLocalSizeHint = 17,
+    ExecutionModeInputPoints = 18,
+    ExecutionModeInputLines = 19,
+    ExecutionModeInputLinesAdjacency = 20,
+    ExecutionModeInputTriangles = 21,
+    ExecutionModeInputTrianglesAdjacency = 22,
+    ExecutionModeInputQuads = 23,
+    ExecutionModeInputIsolines = 24,
+    ExecutionModeOutputVertices = 25,
+    ExecutionModeOutputPoints = 26,
+    ExecutionModeOutputLineStrip = 27,
+    ExecutionModeOutputTriangleStrip = 28,
+    ExecutionModeVecTypeHint = 29,
+    ExecutionModeContractionOff = 30,
+};
+
+enum StorageClass {
+    StorageClassUniformConstant = 0,
+    StorageClassInput = 1,
+    StorageClassUniform = 2,
+    StorageClassOutput = 3,
+    StorageClassWorkgroupLocal = 4,
+    StorageClassWorkgroupGlobal = 5,
+    StorageClassPrivateGlobal = 6,
+    StorageClassFunction = 7,
+    StorageClassGeneric = 8,
+    StorageClassPrivate = 9,
+    StorageClassAtomicCounter = 10,
+};
+
+enum Dim {
+    Dim1D = 0,
+    Dim2D = 1,
+    Dim3D = 2,
+    DimCube = 3,
+    DimRect = 4,
+    DimBuffer = 5,
+};
+
+enum SamplerAddressingMode {
+    SamplerAddressingModeNone = 0,
+    SamplerAddressingModeClampToEdge = 1,
+    SamplerAddressingModeClamp = 2,
+    SamplerAddressingModeRepeat = 3,
+    SamplerAddressingModeRepeatMirrored = 4,
+};
+
+enum SamplerFilterMode {
+    SamplerFilterModeNearest = 0,
+    SamplerFilterModeLinear = 1,
+};
+
+enum FPFastMathModeShift {
+    FPFastMathModeNotNaNShift = 0,
+    FPFastMathModeNotInfShift = 1,
+    FPFastMathModeNSZShift = 2,
+    FPFastMathModeAllowRecipShift = 3,
+    FPFastMathModeFastShift = 4,
+};
+
+enum FPFastMathModeMask {
+    FPFastMathModeMaskNone = 0,
+    FPFastMathModeNotNaNMask = 0x00000001,
+    FPFastMathModeNotInfMask = 0x00000002,
+    FPFastMathModeNSZMask = 0x00000004,
+    FPFastMathModeAllowRecipMask = 0x00000008,
+    FPFastMathModeFastMask = 0x00000010,
+};
+
+enum FPRoundingMode {
+    FPRoundingModeRTE = 0,
+    FPRoundingModeRTZ = 1,
+    FPRoundingModeRTP = 2,
+    FPRoundingModeRTN = 3,
+};
+
+enum LinkageType {
+    LinkageTypeExport = 0,
+    LinkageTypeImport = 1,
+};
+
+enum AccessQualifier {
+    AccessQualifierReadOnly = 0,
+    AccessQualifierWriteOnly = 1,
+    AccessQualifierReadWrite = 2,
+};
+
+enum FunctionParameterAttribute {
+    FunctionParameterAttributeZext = 0,
+    FunctionParameterAttributeSext = 1,
+    FunctionParameterAttributeByVal = 2,
+    FunctionParameterAttributeSret = 3,
+    FunctionParameterAttributeNoAlias = 4,
+    FunctionParameterAttributeNoCapture = 5,
+    FunctionParameterAttributeSVM = 6,
+    FunctionParameterAttributeNoWrite = 7,
+    FunctionParameterAttributeNoReadWrite = 8,
+};
+
+enum Decoration {
+    DecorationPrecisionLow = 0,
+    DecorationPrecisionMedium = 1,
+    DecorationPrecisionHigh = 2,
+    DecorationBlock = 3,
+    DecorationBufferBlock = 4,
+    DecorationRowMajor = 5,
+    DecorationColMajor = 6,
+    DecorationGLSLShared = 7,
+    DecorationGLSLStd140 = 8,
+    DecorationGLSLStd430 = 9,
+    DecorationGLSLPacked = 10,
+    DecorationSmooth = 11,
+    DecorationNoperspective = 12,
+    DecorationFlat = 13,
+    DecorationPatch = 14,
+    DecorationCentroid = 15,
+    DecorationSample = 16,
+    DecorationInvariant = 17,
+    DecorationRestrict = 18,
+    DecorationAliased = 19,
+    DecorationVolatile = 20,
+    DecorationConstant = 21,
+    DecorationCoherent = 22,
+    DecorationNonwritable = 23,
+    DecorationNonreadable = 24,
+    DecorationUniform = 25,
+    DecorationNoStaticUse = 26,
+    DecorationCPacked = 27,
+    DecorationSaturatedConversion = 28,
+    DecorationStream = 29,
+    DecorationLocation = 30,
+    DecorationComponent = 31,
+    DecorationIndex = 32,
+    DecorationBinding = 33,
+    DecorationDescriptorSet = 34,
+    DecorationOffset = 35,
+    DecorationAlignment = 36,
+    DecorationXfbBuffer = 37,
+    DecorationStride = 38,
+    DecorationBuiltIn = 39,
+    DecorationFuncParamAttr = 40,
+    DecorationFPRoundingMode = 41,
+    DecorationFPFastMathMode = 42,
+    DecorationLinkageAttributes = 43,
+    DecorationSpecId = 44,
+};
+
+enum BuiltIn {
+    BuiltInPosition = 0,
+    BuiltInPointSize = 1,
+    BuiltInClipVertex = 2,
+    BuiltInClipDistance = 3,
+    BuiltInCullDistance = 4,
+    BuiltInVertexId = 5,
+    BuiltInInstanceId = 6,
+    BuiltInPrimitiveId = 7,
+    BuiltInInvocationId = 8,
+    BuiltInLayer = 9,
+    BuiltInViewportIndex = 10,
+    BuiltInTessLevelOuter = 11,
+    BuiltInTessLevelInner = 12,
+    BuiltInTessCoord = 13,
+    BuiltInPatchVertices = 14,
+    BuiltInFragCoord = 15,
+    BuiltInPointCoord = 16,
+    BuiltInFrontFacing = 17,
+    BuiltInSampleId = 18,
+    BuiltInSamplePosition = 19,
+    BuiltInSampleMask = 20,
+    BuiltInFragColor = 21,
+    BuiltInFragDepth = 22,
+    BuiltInHelperInvocation = 23,
+    BuiltInNumWorkgroups = 24,
+    BuiltInWorkgroupSize = 25,
+    BuiltInWorkgroupId = 26,
+    BuiltInLocalInvocationId = 27,
+    BuiltInGlobalInvocationId = 28,
+    BuiltInLocalInvocationIndex = 29,
+    BuiltInWorkDim = 30,
+    BuiltInGlobalSize = 31,
+    BuiltInEnqueuedWorkgroupSize = 32,
+    BuiltInGlobalOffset = 33,
+    BuiltInGlobalLinearId = 34,
+    BuiltInWorkgroupLinearId = 35,
+    BuiltInSubgroupSize = 36,
+    BuiltInSubgroupMaxSize = 37,
+    BuiltInNumSubgroups = 38,
+    BuiltInNumEnqueuedSubgroups = 39,
+    BuiltInSubgroupId = 40,
+    BuiltInSubgroupLocalInvocationId = 41,
+};
+
+enum SelectionControlShift {
+    SelectionControlFlattenShift = 0,
+    SelectionControlDontFlattenShift = 1,
+};
+
+enum SelectionControlMask {
+    SelectionControlMaskNone = 0,
+    SelectionControlFlattenMask = 0x00000001,
+    SelectionControlDontFlattenMask = 0x00000002,
+};
+
+enum LoopControlShift {
+    LoopControlUnrollShift = 0,
+    LoopControlDontUnrollShift = 1,
+};
+
+enum LoopControlMask {
+    LoopControlMaskNone = 0,
+    LoopControlUnrollMask = 0x00000001,
+    LoopControlDontUnrollMask = 0x00000002,
+};
+
+enum FunctionControlShift {
+    FunctionControlInlineShift = 0,
+    FunctionControlDontInlineShift = 1,
+    FunctionControlPureShift = 2,
+    FunctionControlConstShift = 3,
+};
+
+enum FunctionControlMask {
+    FunctionControlMaskNone = 0,
+    FunctionControlInlineMask = 0x00000001,
+    FunctionControlDontInlineMask = 0x00000002,
+    FunctionControlPureMask = 0x00000004,
+    FunctionControlConstMask = 0x00000008,
+};
+
+enum MemorySemanticsShift {
+    MemorySemanticsRelaxedShift = 0,
+    MemorySemanticsSequentiallyConsistentShift = 1,
+    MemorySemanticsAcquireShift = 2,
+    MemorySemanticsReleaseShift = 3,
+    MemorySemanticsUniformMemoryShift = 4,
+    MemorySemanticsSubgroupMemoryShift = 5,
+    MemorySemanticsWorkgroupLocalMemoryShift = 6,
+    MemorySemanticsWorkgroupGlobalMemoryShift = 7,
+    MemorySemanticsAtomicCounterMemoryShift = 8,
+    MemorySemanticsImageMemoryShift = 9,
+};
+
+enum MemorySemanticsMask {
+    MemorySemanticsMaskNone = 0,
+    MemorySemanticsRelaxedMask = 0x00000001,
+    MemorySemanticsSequentiallyConsistentMask = 0x00000002,
+    MemorySemanticsAcquireMask = 0x00000004,
+    MemorySemanticsReleaseMask = 0x00000008,
+    MemorySemanticsUniformMemoryMask = 0x00000010,
+    MemorySemanticsSubgroupMemoryMask = 0x00000020,
+    MemorySemanticsWorkgroupLocalMemoryMask = 0x00000040,
+    MemorySemanticsWorkgroupGlobalMemoryMask = 0x00000080,
+    MemorySemanticsAtomicCounterMemoryMask = 0x00000100,
+    MemorySemanticsImageMemoryMask = 0x00000200,
+};
+
+enum MemoryAccessShift {
+    MemoryAccessVolatileShift = 0,
+    MemoryAccessAlignedShift = 1,
+};
+
+enum MemoryAccessMask {
+    MemoryAccessMaskNone = 0,
+    MemoryAccessVolatileMask = 0x00000001,
+    MemoryAccessAlignedMask = 0x00000002,
+};
+
+enum ExecutionScope {
+    ExecutionScopeCrossDevice = 0,
+    ExecutionScopeDevice = 1,
+    ExecutionScopeWorkgroup = 2,
+    ExecutionScopeSubgroup = 3,
+};
+
+enum GroupOperation {
+    GroupOperationReduce = 0,
+    GroupOperationInclusiveScan = 1,
+    GroupOperationExclusiveScan = 2,
+};
+
+enum KernelEnqueueFlags {
+    KernelEnqueueFlagsNoWait = 0,
+    KernelEnqueueFlagsWaitKernel = 1,
+    KernelEnqueueFlagsWaitWorkGroup = 2,
+};
+
+enum KernelProfilingInfoShift {
+    KernelProfilingInfoCmdExecTimeShift = 0,
+};
+
+enum KernelProfilingInfoMask {
+    KernelProfilingInfoMaskNone = 0,
+    KernelProfilingInfoCmdExecTimeMask = 0x00000001,
+};
+
+enum Op {
+    OpNop = 0,
+    OpSource = 1,
+    OpSourceExtension = 2,
+    OpExtension = 3,
+    OpExtInstImport = 4,
+    OpMemoryModel = 5,
+    OpEntryPoint = 6,
+    OpExecutionMode = 7,
+    OpTypeVoid = 8,
+    OpTypeBool = 9,
+    OpTypeInt = 10,
+    OpTypeFloat = 11,
+    OpTypeVector = 12,
+    OpTypeMatrix = 13,
+    OpTypeSampler = 14,
+    OpTypeFilter = 15,
+    OpTypeArray = 16,
+    OpTypeRuntimeArray = 17,
+    OpTypeStruct = 18,
+    OpTypeOpaque = 19,
+    OpTypePointer = 20,
+    OpTypeFunction = 21,
+    OpTypeEvent = 22,
+    OpTypeDeviceEvent = 23,
+    OpTypeReserveId = 24,
+    OpTypeQueue = 25,
+    OpTypePipe = 26,
+    OpConstantTrue = 27,
+    OpConstantFalse = 28,
+    OpConstant = 29,
+    OpConstantComposite = 30,
+    OpConstantSampler = 31,
+    OpConstantNullPointer = 32,
+    OpConstantNullObject = 33,
+    OpSpecConstantTrue = 34,
+    OpSpecConstantFalse = 35,
+    OpSpecConstant = 36,
+    OpSpecConstantComposite = 37,
+    OpVariable = 38,
+    OpVariableArray = 39,
+    OpFunction = 40,
+    OpFunctionParameter = 41,
+    OpFunctionEnd = 42,
+    OpFunctionCall = 43,
+    OpExtInst = 44,
+    OpUndef = 45,
+    OpLoad = 46,
+    OpStore = 47,
+    OpPhi = 48,
+    OpDecorationGroup = 49,
+    OpDecorate = 50,
+    OpMemberDecorate = 51,
+    OpGroupDecorate = 52,
+    OpGroupMemberDecorate = 53,
+    OpName = 54,
+    OpMemberName = 55,
+    OpString = 56,
+    OpLine = 57,
+    OpVectorExtractDynamic = 58,
+    OpVectorInsertDynamic = 59,
+    OpVectorShuffle = 60,
+    OpCompositeConstruct = 61,
+    OpCompositeExtract = 62,
+    OpCompositeInsert = 63,
+    OpCopyObject = 64,
+    OpCopyMemory = 65,
+    OpCopyMemorySized = 66,
+    OpSampler = 67,
+    OpTextureSample = 68,
+    OpTextureSampleDref = 69,
+    OpTextureSampleLod = 70,
+    OpTextureSampleProj = 71,
+    OpTextureSampleGrad = 72,
+    OpTextureSampleOffset = 73,
+    OpTextureSampleProjLod = 74,
+    OpTextureSampleProjGrad = 75,
+    OpTextureSampleLodOffset = 76,
+    OpTextureSampleProjOffset = 77,
+    OpTextureSampleGradOffset = 78,
+    OpTextureSampleProjLodOffset = 79,
+    OpTextureSampleProjGradOffset = 80,
+    OpTextureFetchTexelLod = 81,
+    OpTextureFetchTexelOffset = 82,
+    OpTextureFetchSample = 83,
+    OpTextureFetchTexel = 84,
+    OpTextureGather = 85,
+    OpTextureGatherOffset = 86,
+    OpTextureGatherOffsets = 87,
+    OpTextureQuerySizeLod = 88,
+    OpTextureQuerySize = 89,
+    OpTextureQueryLod = 90,
+    OpTextureQueryLevels = 91,
+    OpTextureQuerySamples = 92,
+    OpAccessChain = 93,
+    OpInBoundsAccessChain = 94,
+    OpSNegate = 95,
+    OpFNegate = 96,
+    OpNot = 97,
+    OpAny = 98,
+    OpAll = 99,
+    OpConvertFToU = 100,
+    OpConvertFToS = 101,
+    OpConvertSToF = 102,
+    OpConvertUToF = 103,
+    OpUConvert = 104,
+    OpSConvert = 105,
+    OpFConvert = 106,
+    OpConvertPtrToU = 107,
+    OpConvertUToPtr = 108,
+    OpPtrCastToGeneric = 109,
+    OpGenericCastToPtr = 110,
+    OpBitcast = 111,
+    OpTranspose = 112,
+    OpIsNan = 113,
+    OpIsInf = 114,
+    OpIsFinite = 115,
+    OpIsNormal = 116,
+    OpSignBitSet = 117,
+    OpLessOrGreater = 118,
+    OpOrdered = 119,
+    OpUnordered = 120,
+    OpArrayLength = 121,
+    OpIAdd = 122,
+    OpFAdd = 123,
+    OpISub = 124,
+    OpFSub = 125,
+    OpIMul = 126,
+    OpFMul = 127,
+    OpUDiv = 128,
+    OpSDiv = 129,
+    OpFDiv = 130,
+    OpUMod = 131,
+    OpSRem = 132,
+    OpSMod = 133,
+    OpFRem = 134,
+    OpFMod = 135,
+    OpVectorTimesScalar = 136,
+    OpMatrixTimesScalar = 137,
+    OpVectorTimesMatrix = 138,
+    OpMatrixTimesVector = 139,
+    OpMatrixTimesMatrix = 140,
+    OpOuterProduct = 141,
+    OpDot = 142,
+    OpShiftRightLogical = 143,
+    OpShiftRightArithmetic = 144,
+    OpShiftLeftLogical = 145,
+    OpLogicalOr = 146,
+    OpLogicalXor = 147,
+    OpLogicalAnd = 148,
+    OpBitwiseOr = 149,
+    OpBitwiseXor = 150,
+    OpBitwiseAnd = 151,
+    OpSelect = 152,
+    OpIEqual = 153,
+    OpFOrdEqual = 154,
+    OpFUnordEqual = 155,
+    OpINotEqual = 156,
+    OpFOrdNotEqual = 157,
+    OpFUnordNotEqual = 158,
+    OpULessThan = 159,
+    OpSLessThan = 160,
+    OpFOrdLessThan = 161,
+    OpFUnordLessThan = 162,
+    OpUGreaterThan = 163,
+    OpSGreaterThan = 164,
+    OpFOrdGreaterThan = 165,
+    OpFUnordGreaterThan = 166,
+    OpULessThanEqual = 167,
+    OpSLessThanEqual = 168,
+    OpFOrdLessThanEqual = 169,
+    OpFUnordLessThanEqual = 170,
+    OpUGreaterThanEqual = 171,
+    OpSGreaterThanEqual = 172,
+    OpFOrdGreaterThanEqual = 173,
+    OpFUnordGreaterThanEqual = 174,
+    OpDPdx = 175,
+    OpDPdy = 176,
+    OpFwidth = 177,
+    OpDPdxFine = 178,
+    OpDPdyFine = 179,
+    OpFwidthFine = 180,
+    OpDPdxCoarse = 181,
+    OpDPdyCoarse = 182,
+    OpFwidthCoarse = 183,
+    OpEmitVertex = 184,
+    OpEndPrimitive = 185,
+    OpEmitStreamVertex = 186,
+    OpEndStreamPrimitive = 187,
+    OpControlBarrier = 188,
+    OpMemoryBarrier = 189,
+    OpImagePointer = 190,
+    OpAtomicInit = 191,
+    OpAtomicLoad = 192,
+    OpAtomicStore = 193,
+    OpAtomicExchange = 194,
+    OpAtomicCompareExchange = 195,
+    OpAtomicCompareExchangeWeak = 196,
+    OpAtomicIIncrement = 197,
+    OpAtomicIDecrement = 198,
+    OpAtomicIAdd = 199,
+    OpAtomicISub = 200,
+    OpAtomicUMin = 201,
+    OpAtomicUMax = 202,
+    OpAtomicAnd = 203,
+    OpAtomicOr = 204,
+    OpAtomicXor = 205,
+    OpLoopMerge = 206,
+    OpSelectionMerge = 207,
+    OpLabel = 208,
+    OpBranch = 209,
+    OpBranchConditional = 210,
+    OpSwitch = 211,
+    OpKill = 212,
+    OpReturn = 213,
+    OpReturnValue = 214,
+    OpUnreachable = 215,
+    OpLifetimeStart = 216,
+    OpLifetimeStop = 217,
+    OpCompileFlag = 218,
+    OpAsyncGroupCopy = 219,
+    OpWaitGroupEvents = 220,
+    OpGroupAll = 221,
+    OpGroupAny = 222,
+    OpGroupBroadcast = 223,
+    OpGroupIAdd = 224,
+    OpGroupFAdd = 225,
+    OpGroupFMin = 226,
+    OpGroupUMin = 227,
+    OpGroupSMin = 228,
+    OpGroupFMax = 229,
+    OpGroupUMax = 230,
+    OpGroupSMax = 231,
+    OpGenericCastToPtrExplicit = 232,
+    OpGenericPtrMemSemantics = 233,
+    OpReadPipe = 234,
+    OpWritePipe = 235,
+    OpReservedReadPipe = 236,
+    OpReservedWritePipe = 237,
+    OpReserveReadPipePackets = 238,
+    OpReserveWritePipePackets = 239,
+    OpCommitReadPipe = 240,
+    OpCommitWritePipe = 241,
+    OpIsValidReserveId = 242,
+    OpGetNumPipePackets = 243,
+    OpGetMaxPipePackets = 244,
+    OpGroupReserveReadPipePackets = 245,
+    OpGroupReserveWritePipePackets = 246,
+    OpGroupCommitReadPipe = 247,
+    OpGroupCommitWritePipe = 248,
+    OpEnqueueMarker = 249,
+    OpEnqueueKernel = 250,
+    OpGetKernelNDrangeSubGroupCount = 251,
+    OpGetKernelNDrangeMaxSubGroupSize = 252,
+    OpGetKernelWorkGroupSize = 253,
+    OpGetKernelPreferredWorkGroupSizeMultiple = 254,
+    OpRetainEvent = 255,
+    OpReleaseEvent = 256,
+    OpCreateUserEvent = 257,
+    OpIsValidEvent = 258,
+    OpSetUserEventStatus = 259,
+    OpCaptureEventProfilingInfo = 260,
+    OpGetDefaultQueue = 261,
+    OpBuildNDRange = 262,
+    OpSatConvertSToU = 263,
+    OpSatConvertUToS = 264,
+    OpAtomicIMin = 265,
+    OpAtomicIMax = 266,
+};
+
+};  // end namespace spv
+
+#endif  // #ifdef __cplusplus
+
+
+#ifndef __cplusplus
+
+const int SpvMagicNumber = 0x07230203;
+const int SpvVersion = 99;
+
+typedef unsigned int SpvId;
+
+const unsigned int SpvOpCodeMask = 0xFFFF;
+const unsigned int SpvWordCountShift = 16;
+
+typedef enum SpvSourceLanguage_ {
+    SpvSourceLanguageUnknown = 0,
+    SpvSourceLanguageESSL = 1,
+    SpvSourceLanguageGLSL = 2,
+    SpvSourceLanguageOpenCL = 3,
+} SpvSourceLanguage;
+
+typedef enum SpvExecutionModel_ {
+    SpvExecutionModelVertex = 0,
+    SpvExecutionModelTessellationControl = 1,
+    SpvExecutionModelTessellationEvaluation = 2,
+    SpvExecutionModelGeometry = 3,
+    SpvExecutionModelFragment = 4,
+    SpvExecutionModelGLCompute = 5,
+    SpvExecutionModelKernel = 6,
+} SpvExecutionModel;
+
+typedef enum SpvAddressingModel_ {
+    SpvAddressingModelLogical = 0,
+    SpvAddressingModelPhysical32 = 1,
+    SpvAddressingModelPhysical64 = 2,
+} SpvAddressingModel;
+
+typedef enum SpvMemoryModel_ {
+    SpvMemoryModelSimple = 0,
+    SpvMemoryModelGLSL450 = 1,
+    SpvMemoryModelOpenCL12 = 2,
+    SpvMemoryModelOpenCL20 = 3,
+    SpvMemoryModelOpenCL21 = 4,
+} SpvMemoryModel;
+
+typedef enum SpvExecutionMode_ {
+    SpvExecutionModeInvocations = 0,
+    SpvExecutionModeSpacingEqual = 1,
+    SpvExecutionModeSpacingFractionalEven = 2,
+    SpvExecutionModeSpacingFractionalOdd = 3,
+    SpvExecutionModeVertexOrderCw = 4,
+    SpvExecutionModeVertexOrderCcw = 5,
+    SpvExecutionModePixelCenterInteger = 6,
+    SpvExecutionModeOriginUpperLeft = 7,
+    SpvExecutionModeEarlyFragmentTests = 8,
+    SpvExecutionModePointMode = 9,
+    SpvExecutionModeXfb = 10,
+    SpvExecutionModeDepthReplacing = 11,
+    SpvExecutionModeDepthAny = 12,
+    SpvExecutionModeDepthGreater = 13,
+    SpvExecutionModeDepthLess = 14,
+    SpvExecutionModeDepthUnchanged = 15,
+    SpvExecutionModeLocalSize = 16,
+    SpvExecutionModeLocalSizeHint = 17,
+    SpvExecutionModeInputPoints = 18,
+    SpvExecutionModeInputLines = 19,
+    SpvExecutionModeInputLinesAdjacency = 20,
+    SpvExecutionModeInputTriangles = 21,
+    SpvExecutionModeInputTrianglesAdjacency = 22,
+    SpvExecutionModeInputQuads = 23,
+    SpvExecutionModeInputIsolines = 24,
+    SpvExecutionModeOutputVertices = 25,
+    SpvExecutionModeOutputPoints = 26,
+    SpvExecutionModeOutputLineStrip = 27,
+    SpvExecutionModeOutputTriangleStrip = 28,
+    SpvExecutionModeVecTypeHint = 29,
+    SpvExecutionModeContractionOff = 30,
+} SpvExecutionMode;
+
+typedef enum SpvStorageClass_ {
+    SpvStorageClassUniformConstant = 0,
+    SpvStorageClassInput = 1,
+    SpvStorageClassUniform = 2,
+    SpvStorageClassOutput = 3,
+    SpvStorageClassWorkgroupLocal = 4,
+    SpvStorageClassWorkgroupGlobal = 5,
+    SpvStorageClassPrivateGlobal = 6,
+    SpvStorageClassFunction = 7,
+    SpvStorageClassGeneric = 8,
+    SpvStorageClassPrivate = 9,
+    SpvStorageClassAtomicCounter = 10,
+} SpvStorageClass;
+
+typedef enum SpvDim_ {
+    SpvDim1D = 0,
+    SpvDim2D = 1,
+    SpvDim3D = 2,
+    SpvDimCube = 3,
+    SpvDimRect = 4,
+    SpvDimBuffer = 5,
+} SpvDim;
+
+typedef enum SpvSamplerAddressingMode_ {
+    SpvSamplerAddressingModeNone = 0,
+    SpvSamplerAddressingModeClampToEdge = 1,
+    SpvSamplerAddressingModeClamp = 2,
+    SpvSamplerAddressingModeRepeat = 3,
+    SpvSamplerAddressingModeRepeatMirrored = 4,
+} SpvSamplerAddressingMode;
+
+typedef enum SpvSamplerFilterMode_ {
+    SpvSamplerFilterModeNearest = 0,
+    SpvSamplerFilterModeLinear = 1,
+} SpvSamplerFilterMode;
+
+typedef enum SpvFPFastMathModeShift_ {
+    SpvFPFastMathModeNotNaNShift = 0,
+    SpvFPFastMathModeNotInfShift = 1,
+    SpvFPFastMathModeNSZShift = 2,
+    SpvFPFastMathModeAllowRecipShift = 3,
+    SpvFPFastMathModeFastShift = 4,
+} SpvFPFastMathModeShift;
+
+typedef enum SpvFPFastMathModeMask_ {
+    SpvFPFastMathModeMaskNone = 0,
+    SpvFPFastMathModeNotNaNMask = 0x00000001,
+    SpvFPFastMathModeNotInfMask = 0x00000002,
+    SpvFPFastMathModeNSZMask = 0x00000004,
+    SpvFPFastMathModeAllowRecipMask = 0x00000008,
+    SpvFPFastMathModeFastMask = 0x00000010,
+} SpvFPFastMathModeMask;
+
+typedef enum SpvFPRoundingMode_ {
+    SpvFPRoundingModeRTE = 0,
+    SpvFPRoundingModeRTZ = 1,
+    SpvFPRoundingModeRTP = 2,
+    SpvFPRoundingModeRTN = 3,
+} SpvFPRoundingMode;
+
+typedef enum SpvLinkageType_ {
+    SpvLinkageTypeExport = 0,
+    SpvLinkageTypeImport = 1,
+} SpvLinkageType;
+
+typedef enum SpvAccessQualifier_ {
+    SpvAccessQualifierReadOnly = 0,
+    SpvAccessQualifierWriteOnly = 1,
+    SpvAccessQualifierReadWrite = 2,
+} SpvAccessQualifier;
+
+typedef enum SpvFunctionParameterAttribute_ {
+    SpvFunctionParameterAttributeZext = 0,
+    SpvFunctionParameterAttributeSext = 1,
+    SpvFunctionParameterAttributeByVal = 2,
+    SpvFunctionParameterAttributeSret = 3,
+    SpvFunctionParameterAttributeNoAlias = 4,
+    SpvFunctionParameterAttributeNoCapture = 5,
+    SpvFunctionParameterAttributeSVM = 6,
+    SpvFunctionParameterAttributeNoWrite = 7,
+    SpvFunctionParameterAttributeNoReadWrite = 8,
+} SpvFunctionParameterAttribute;
+
+typedef enum SpvDecoration_ {
+    SpvDecorationPrecisionLow = 0,
+    SpvDecorationPrecisionMedium = 1,
+    SpvDecorationPrecisionHigh = 2,
+    SpvDecorationBlock = 3,
+    SpvDecorationBufferBlock = 4,
+    SpvDecorationRowMajor = 5,
+    SpvDecorationColMajor = 6,
+    SpvDecorationGLSLShared = 7,
+    SpvDecorationGLSLStd140 = 8,
+    SpvDecorationGLSLStd430 = 9,
+    SpvDecorationGLSLPacked = 10,
+    SpvDecorationSmooth = 11,
+    SpvDecorationNoperspective = 12,
+    SpvDecorationFlat = 13,
+    SpvDecorationPatch = 14,
+    SpvDecorationCentroid = 15,
+    SpvDecorationSample = 16,
+    SpvDecorationInvariant = 17,
+    SpvDecorationRestrict = 18,
+    SpvDecorationAliased = 19,
+    SpvDecorationVolatile = 20,
+    SpvDecorationConstant = 21,
+    SpvDecorationCoherent = 22,
+    SpvDecorationNonwritable = 23,
+    SpvDecorationNonreadable = 24,
+    SpvDecorationUniform = 25,
+    SpvDecorationNoStaticUse = 26,
+    SpvDecorationCPacked = 27,
+    SpvDecorationSaturatedConversion = 28,
+    SpvDecorationStream = 29,
+    SpvDecorationLocation = 30,
+    SpvDecorationComponent = 31,
+    SpvDecorationIndex = 32,
+    SpvDecorationBinding = 33,
+    SpvDecorationDescriptorSet = 34,
+    SpvDecorationOffset = 35,
+    SpvDecorationAlignment = 36,
+    SpvDecorationXfbBuffer = 37,
+    SpvDecorationStride = 38,
+    SpvDecorationBuiltIn = 39,
+    SpvDecorationFuncParamAttr = 40,
+    SpvDecorationFPRoundingMode = 41,
+    SpvDecorationFPFastMathMode = 42,
+    SpvDecorationLinkageAttributes = 43,
+    SpvDecorationSpecId = 44,
+} SpvDecoration;
+
+typedef enum SpvBuiltIn_ {
+    SpvBuiltInPosition = 0,
+    SpvBuiltInPointSize = 1,
+    SpvBuiltInClipVertex = 2,
+    SpvBuiltInClipDistance = 3,
+    SpvBuiltInCullDistance = 4,
+    SpvBuiltInVertexId = 5,
+    SpvBuiltInInstanceId = 6,
+    SpvBuiltInPrimitiveId = 7,
+    SpvBuiltInInvocationId = 8,
+    SpvBuiltInLayer = 9,
+    SpvBuiltInViewportIndex = 10,
+    SpvBuiltInTessLevelOuter = 11,
+    SpvBuiltInTessLevelInner = 12,
+    SpvBuiltInTessCoord = 13,
+    SpvBuiltInPatchVertices = 14,
+    SpvBuiltInFragCoord = 15,
+    SpvBuiltInPointCoord = 16,
+    SpvBuiltInFrontFacing = 17,
+    SpvBuiltInSampleId = 18,
+    SpvBuiltInSamplePosition = 19,
+    SpvBuiltInSampleMask = 20,
+    SpvBuiltInFragColor = 21,
+    SpvBuiltInFragDepth = 22,
+    SpvBuiltInHelperInvocation = 23,
+    SpvBuiltInNumWorkgroups = 24,
+    SpvBuiltInWorkgroupSize = 25,
+    SpvBuiltInWorkgroupId = 26,
+    SpvBuiltInLocalInvocationId = 27,
+    SpvBuiltInGlobalInvocationId = 28,
+    SpvBuiltInLocalInvocationIndex = 29,
+    SpvBuiltInWorkDim = 30,
+    SpvBuiltInGlobalSize = 31,
+    SpvBuiltInEnqueuedWorkgroupSize = 32,
+    SpvBuiltInGlobalOffset = 33,
+    SpvBuiltInGlobalLinearId = 34,
+    SpvBuiltInWorkgroupLinearId = 35,
+    SpvBuiltInSubgroupSize = 36,
+    SpvBuiltInSubgroupMaxSize = 37,
+    SpvBuiltInNumSubgroups = 38,
+    SpvBuiltInNumEnqueuedSubgroups = 39,
+    SpvBuiltInSubgroupId = 40,
+    SpvBuiltInSubgroupLocalInvocationId = 41,
+} SpvBuiltIn;
+
+typedef enum SpvSelectionControlShift_ {
+    SpvSelectionControlFlattenShift = 0,
+    SpvSelectionControlDontFlattenShift = 1,
+} SpvSelectionControlShift;
+
+typedef enum SpvSelectionControlMask_ {
+    SpvSelectionControlMaskNone = 0,
+    SpvSelectionControlFlattenMask = 0x00000001,
+    SpvSelectionControlDontFlattenMask = 0x00000002,
+} SpvSelectionControlMask;
+
+typedef enum SpvLoopControlShift_ {
+    SpvLoopControlUnrollShift = 0,
+    SpvLoopControlDontUnrollShift = 1,
+} SpvLoopControlShift;
+
+typedef enum SpvLoopControlMask_ {
+    SpvLoopControlMaskNone = 0,
+    SpvLoopControlUnrollMask = 0x00000001,
+    SpvLoopControlDontUnrollMask = 0x00000002,
+} SpvLoopControlMask;
+
+typedef enum SpvFunctionControlShift_ {
+    SpvFunctionControlInlineShift = 0,
+    SpvFunctionControlDontInlineShift = 1,
+    SpvFunctionControlPureShift = 2,
+    SpvFunctionControlConstShift = 3,
+} SpvFunctionControlShift;
+
+typedef enum SpvFunctionControlMask_ {
+    SpvFunctionControlMaskNone = 0,
+    SpvFunctionControlInlineMask = 0x00000001,
+    SpvFunctionControlDontInlineMask = 0x00000002,
+    SpvFunctionControlPureMask = 0x00000004,
+    SpvFunctionControlConstMask = 0x00000008,
+} SpvFunctionControlMask;
+
+typedef enum SpvMemorySemanticsShift_ {
+    SpvMemorySemanticsRelaxedShift = 0,
+    SpvMemorySemanticsSequentiallyConsistentShift = 1,
+    SpvMemorySemanticsAcquireShift = 2,
+    SpvMemorySemanticsReleaseShift = 3,
+    SpvMemorySemanticsUniformMemoryShift = 4,
+    SpvMemorySemanticsSubgroupMemoryShift = 5,
+    SpvMemorySemanticsWorkgroupLocalMemoryShift = 6,
+    SpvMemorySemanticsWorkgroupGlobalMemoryShift = 7,
+    SpvMemorySemanticsAtomicCounterMemoryShift = 8,
+    SpvMemorySemanticsImageMemoryShift = 9,
+} SpvMemorySemanticsShift;
+
+typedef enum SpvMemorySemanticsMask_ {
+    SpvMemorySemanticsMaskNone = 0,
+    SpvMemorySemanticsRelaxedMask = 0x00000001,
+    SpvMemorySemanticsSequentiallyConsistentMask = 0x00000002,
+    SpvMemorySemanticsAcquireMask = 0x00000004,
+    SpvMemorySemanticsReleaseMask = 0x00000008,
+    SpvMemorySemanticsUniformMemoryMask = 0x00000010,
+    SpvMemorySemanticsSubgroupMemoryMask = 0x00000020,
+    SpvMemorySemanticsWorkgroupLocalMemoryMask = 0x00000040,
+    SpvMemorySemanticsWorkgroupGlobalMemoryMask = 0x00000080,
+    SpvMemorySemanticsAtomicCounterMemoryMask = 0x00000100,
+    SpvMemorySemanticsImageMemoryMask = 0x00000200,
+} SpvMemorySemanticsMask;
+
+typedef enum SpvMemoryAccessShift_ {
+    SpvMemoryAccessVolatileShift = 0,
+    SpvMemoryAccessAlignedShift = 1,
+} SpvMemoryAccessShift;
+
+typedef enum SpvMemoryAccessMask_ {
+    SpvMemoryAccessMaskNone = 0,
+    SpvMemoryAccessVolatileMask = 0x00000001,
+    SpvMemoryAccessAlignedMask = 0x00000002,
+} SpvMemoryAccessMask;
+
+typedef enum SpvExecutionScope_ {
+    SpvExecutionScopeCrossDevice = 0,
+    SpvExecutionScopeDevice = 1,
+    SpvExecutionScopeWorkgroup = 2,
+    SpvExecutionScopeSubgroup = 3,
+} SpvExecutionScope;
+
+typedef enum SpvGroupOperation_ {
+    SpvGroupOperationReduce = 0,
+    SpvGroupOperationInclusiveScan = 1,
+    SpvGroupOperationExclusiveScan = 2,
+} SpvGroupOperation;
+
+typedef enum SpvKernelEnqueueFlags_ {
+    SpvKernelEnqueueFlagsNoWait = 0,
+    SpvKernelEnqueueFlagsWaitKernel = 1,
+    SpvKernelEnqueueFlagsWaitWorkGroup = 2,
+} SpvKernelEnqueueFlags;
+
+typedef enum SpvKernelProfilingInfoShift_ {
+    SpvKernelProfilingInfoCmdExecTimeShift = 0,
+} SpvKernelProfilingInfoShift;
+
+typedef enum SpvKernelProfilingInfoMask_ {
+    SpvKernelProfilingInfoMaskNone = 0,
+    SpvKernelProfilingInfoCmdExecTimeMask = 0x00000001,
+} SpvKernelProfilingInfoMask;
+
+typedef enum SpvOp_ {
+    SpvOpNop = 0,
+    SpvOpSource = 1,
+    SpvOpSourceExtension = 2,
+    SpvOpExtension = 3,
+    SpvOpExtInstImport = 4,
+    SpvOpMemoryModel = 5,
+    SpvOpEntryPoint = 6,
+    SpvOpExecutionMode = 7,
+    SpvOpTypeVoid = 8,
+    SpvOpTypeBool = 9,
+    SpvOpTypeInt = 10,
+    SpvOpTypeFloat = 11,
+    SpvOpTypeVector = 12,
+    SpvOpTypeMatrix = 13,
+    SpvOpTypeSampler = 14,
+    SpvOpTypeFilter = 15,
+    SpvOpTypeArray = 16,
+    SpvOpTypeRuntimeArray = 17,
+    SpvOpTypeStruct = 18,
+    SpvOpTypeOpaque = 19,
+    SpvOpTypePointer = 20,
+    SpvOpTypeFunction = 21,
+    SpvOpTypeEvent = 22,
+    SpvOpTypeDeviceEvent = 23,
+    SpvOpTypeReserveId = 24,
+    SpvOpTypeQueue = 25,
+    SpvOpTypePipe = 26,
+    SpvOpConstantTrue = 27,
+    SpvOpConstantFalse = 28,
+    SpvOpConstant = 29,
+    SpvOpConstantComposite = 30,
+    SpvOpConstantSampler = 31,
+    SpvOpConstantNullPointer = 32,
+    SpvOpConstantNullObject = 33,
+    SpvOpSpecConstantTrue = 34,
+    SpvOpSpecConstantFalse = 35,
+    SpvOpSpecConstant = 36,
+    SpvOpSpecConstantComposite = 37,
+    SpvOpVariable = 38,
+    SpvOpVariableArray = 39,
+    SpvOpFunction = 40,
+    SpvOpFunctionParameter = 41,
+    SpvOpFunctionEnd = 42,
+    SpvOpFunctionCall = 43,
+    SpvOpExtInst = 44,
+    SpvOpUndef = 45,
+    SpvOpLoad = 46,
+    SpvOpStore = 47,
+    SpvOpPhi = 48,
+    SpvOpDecorationGroup = 49,
+    SpvOpDecorate = 50,
+    SpvOpMemberDecorate = 51,
+    SpvOpGroupDecorate = 52,
+    SpvOpGroupMemberDecorate = 53,
+    SpvOpName = 54,
+    SpvOpMemberName = 55,
+    SpvOpString = 56,
+    SpvOpLine = 57,
+    SpvOpVectorExtractDynamic = 58,
+    SpvOpVectorInsertDynamic = 59,
+    SpvOpVectorShuffle = 60,
+    SpvOpCompositeConstruct = 61,
+    SpvOpCompositeExtract = 62,
+    SpvOpCompositeInsert = 63,
+    SpvOpCopyObject = 64,
+    SpvOpCopyMemory = 65,
+    SpvOpCopyMemorySized = 66,
+    SpvOpSampler = 67,
+    SpvOpTextureSample = 68,
+    SpvOpTextureSampleDref = 69,
+    SpvOpTextureSampleLod = 70,
+    SpvOpTextureSampleProj = 71,
+    SpvOpTextureSampleGrad = 72,
+    SpvOpTextureSampleOffset = 73,
+    SpvOpTextureSampleProjLod = 74,
+    SpvOpTextureSampleProjGrad = 75,
+    SpvOpTextureSampleLodOffset = 76,
+    SpvOpTextureSampleProjOffset = 77,
+    SpvOpTextureSampleGradOffset = 78,
+    SpvOpTextureSampleProjLodOffset = 79,
+    SpvOpTextureSampleProjGradOffset = 80,
+    SpvOpTextureFetchTexelLod = 81,
+    SpvOpTextureFetchTexelOffset = 82,
+    SpvOpTextureFetchSample = 83,
+    SpvOpTextureFetchTexel = 84,
+    SpvOpTextureGather = 85,
+    SpvOpTextureGatherOffset = 86,
+    SpvOpTextureGatherOffsets = 87,
+    SpvOpTextureQuerySizeLod = 88,
+    SpvOpTextureQuerySize = 89,
+    SpvOpTextureQueryLod = 90,
+    SpvOpTextureQueryLevels = 91,
+    SpvOpTextureQuerySamples = 92,
+    SpvOpAccessChain = 93,
+    SpvOpInBoundsAccessChain = 94,
+    SpvOpSNegate = 95,
+    SpvOpFNegate = 96,
+    SpvOpNot = 97,
+    SpvOpAny = 98,
+    SpvOpAll = 99,
+    SpvOpConvertFToU = 100,
+    SpvOpConvertFToS = 101,
+    SpvOpConvertSToF = 102,
+    SpvOpConvertUToF = 103,
+    SpvOpUConvert = 104,
+    SpvOpSConvert = 105,
+    SpvOpFConvert = 106,
+    SpvOpConvertPtrToU = 107,
+    SpvOpConvertUToPtr = 108,
+    SpvOpPtrCastToGeneric = 109,
+    SpvOpGenericCastToPtr = 110,
+    SpvOpBitcast = 111,
+    SpvOpTranspose = 112,
+    SpvOpIsNan = 113,
+    SpvOpIsInf = 114,
+    SpvOpIsFinite = 115,
+    SpvOpIsNormal = 116,
+    SpvOpSignBitSet = 117,
+    SpvOpLessOrGreater = 118,
+    SpvOpOrdered = 119,
+    SpvOpUnordered = 120,
+    SpvOpArrayLength = 121,
+    SpvOpIAdd = 122,
+    SpvOpFAdd = 123,
+    SpvOpISub = 124,
+    SpvOpFSub = 125,
+    SpvOpIMul = 126,
+    SpvOpFMul = 127,
+    SpvOpUDiv = 128,
+    SpvOpSDiv = 129,
+    SpvOpFDiv = 130,
+    SpvOpUMod = 131,
+    SpvOpSRem = 132,
+    SpvOpSMod = 133,
+    SpvOpFRem = 134,
+    SpvOpFMod = 135,
+    SpvOpVectorTimesScalar = 136,
+    SpvOpMatrixTimesScalar = 137,
+    SpvOpVectorTimesMatrix = 138,
+    SpvOpMatrixTimesVector = 139,
+    SpvOpMatrixTimesMatrix = 140,
+    SpvOpOuterProduct = 141,
+    SpvOpDot = 142,
+    SpvOpShiftRightLogical = 143,
+    SpvOpShiftRightArithmetic = 144,
+    SpvOpShiftLeftLogical = 145,
+    SpvOpLogicalOr = 146,
+    SpvOpLogicalXor = 147,
+    SpvOpLogicalAnd = 148,
+    SpvOpBitwiseOr = 149,
+    SpvOpBitwiseXor = 150,
+    SpvOpBitwiseAnd = 151,
+    SpvOpSelect = 152,
+    SpvOpIEqual = 153,
+    SpvOpFOrdEqual = 154,
+    SpvOpFUnordEqual = 155,
+    SpvOpINotEqual = 156,
+    SpvOpFOrdNotEqual = 157,
+    SpvOpFUnordNotEqual = 158,
+    SpvOpULessThan = 159,
+    SpvOpSLessThan = 160,
+    SpvOpFOrdLessThan = 161,
+    SpvOpFUnordLessThan = 162,
+    SpvOpUGreaterThan = 163,
+    SpvOpSGreaterThan = 164,
+    SpvOpFOrdGreaterThan = 165,
+    SpvOpFUnordGreaterThan = 166,
+    SpvOpULessThanEqual = 167,
+    SpvOpSLessThanEqual = 168,
+    SpvOpFOrdLessThanEqual = 169,
+    SpvOpFUnordLessThanEqual = 170,
+    SpvOpUGreaterThanEqual = 171,
+    SpvOpSGreaterThanEqual = 172,
+    SpvOpFOrdGreaterThanEqual = 173,
+    SpvOpFUnordGreaterThanEqual = 174,
+    SpvOpDPdx = 175,
+    SpvOpDPdy = 176,
+    SpvOpFwidth = 177,
+    SpvOpDPdxFine = 178,
+    SpvOpDPdyFine = 179,
+    SpvOpFwidthFine = 180,
+    SpvOpDPdxCoarse = 181,
+    SpvOpDPdyCoarse = 182,
+    SpvOpFwidthCoarse = 183,
+    SpvOpEmitVertex = 184,
+    SpvOpEndPrimitive = 185,
+    SpvOpEmitStreamVertex = 186,
+    SpvOpEndStreamPrimitive = 187,
+    SpvOpControlBarrier = 188,
+    SpvOpMemoryBarrier = 189,
+    SpvOpImagePointer = 190,
+    SpvOpAtomicInit = 191,
+    SpvOpAtomicLoad = 192,
+    SpvOpAtomicStore = 193,
+    SpvOpAtomicExchange = 194,
+    SpvOpAtomicCompareExchange = 195,
+    SpvOpAtomicCompareExchangeWeak = 196,
+    SpvOpAtomicIIncrement = 197,
+    SpvOpAtomicIDecrement = 198,
+    SpvOpAtomicIAdd = 199,
+    SpvOpAtomicISub = 200,
+    SpvOpAtomicUMin = 201,
+    SpvOpAtomicUMax = 202,
+    SpvOpAtomicAnd = 203,
+    SpvOpAtomicOr = 204,
+    SpvOpAtomicXor = 205,
+    SpvOpLoopMerge = 206,
+    SpvOpSelectionMerge = 207,
+    SpvOpLabel = 208,
+    SpvOpBranch = 209,
+    SpvOpBranchConditional = 210,
+    SpvOpSwitch = 211,
+    SpvOpKill = 212,
+    SpvOpReturn = 213,
+    SpvOpReturnValue = 214,
+    SpvOpUnreachable = 215,
+    SpvOpLifetimeStart = 216,
+    SpvOpLifetimeStop = 217,
+    SpvOpCompileFlag = 218,
+    SpvOpAsyncGroupCopy = 219,
+    SpvOpWaitGroupEvents = 220,
+    SpvOpGroupAll = 221,
+    SpvOpGroupAny = 222,
+    SpvOpGroupBroadcast = 223,
+    SpvOpGroupIAdd = 224,
+    SpvOpGroupFAdd = 225,
+    SpvOpGroupFMin = 226,
+    SpvOpGroupUMin = 227,
+    SpvOpGroupSMin = 228,
+    SpvOpGroupFMax = 229,
+    SpvOpGroupUMax = 230,
+    SpvOpGroupSMax = 231,
+    SpvOpGenericCastToPtrExplicit = 232,
+    SpvOpGenericPtrMemSemantics = 233,
+    SpvOpReadPipe = 234,
+    SpvOpWritePipe = 235,
+    SpvOpReservedReadPipe = 236,
+    SpvOpReservedWritePipe = 237,
+    SpvOpReserveReadPipePackets = 238,
+    SpvOpReserveWritePipePackets = 239,
+    SpvOpCommitReadPipe = 240,
+    SpvOpCommitWritePipe = 241,
+    SpvOpIsValidReserveId = 242,
+    SpvOpGetNumPipePackets = 243,
+    SpvOpGetMaxPipePackets = 244,
+    SpvOpGroupReserveReadPipePackets = 245,
+    SpvOpGroupReserveWritePipePackets = 246,
+    SpvOpGroupCommitReadPipe = 247,
+    SpvOpGroupCommitWritePipe = 248,
+    SpvOpEnqueueMarker = 249,
+    SpvOpEnqueueKernel = 250,
+    SpvOpGetKernelNDrangeSubGroupCount = 251,
+    SpvOpGetKernelNDrangeMaxSubGroupSize = 252,
+    SpvOpGetKernelWorkGroupSize = 253,
+    SpvOpGetKernelPreferredWorkGroupSizeMultiple = 254,
+    SpvOpRetainEvent = 255,
+    SpvOpReleaseEvent = 256,
+    SpvOpCreateUserEvent = 257,
+    SpvOpIsValidEvent = 258,
+    SpvOpSetUserEventStatus = 259,
+    SpvOpCaptureEventProfilingInfo = 260,
+    SpvOpGetDefaultQueue = 261,
+    SpvOpBuildNDRange = 262,
+    SpvOpSatConvertSToU = 263,
+    SpvOpSatConvertUToS = 264,
+    SpvOpAtomicIMin = 265,
+    SpvOpAtomicIMax = 266,
+} SpvOp;
+
+#endif  // #ifndef __cplusplus
+
+#endif  // #ifndef spirv_H
diff --git a/SPIRV/spvIR.h b/SPIRV/spvIR.h
index ec75824..028671d 100644
--- a/SPIRV/spvIR.h
+++ b/SPIRV/spvIR.h
@@ -1,369 +1,369 @@
-//

-//Copyright (C) 2014 LunarG, Inc.

-//

-//All rights reserved.

-//

-//Redistribution and use in source and binary forms, with or without

-//modification, are permitted provided that the following conditions

-//are met:

-//

-//    Redistributions of source code must retain the above copyright

-//    notice, this list of conditions and the following disclaimer.

-//

-//    Redistributions in binary form must reproduce the above

-//    copyright notice, this list of conditions and the following

-//    disclaimer in the documentation and/or other materials provided

-//    with the distribution.

-//

-//    Neither the name of 3Dlabs Inc. Ltd. nor the names of its

-//    contributors may be used to endorse or promote products derived

-//    from this software without specific prior written permission.

-//

-//THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS

-//"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT

-//LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS

-//FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE

-//COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,

-//INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,

-//BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;

-//LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER

-//CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT

-//LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN

-//ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE

-//POSSIBILITY OF SUCH DAMAGE.

-

-//

-// Author: John Kessenich, LunarG

-//

-

-// SPIRV-IR

-//

-// Simple in-memory representation (IR) of SPIRV.  Just for holding

-// Each function's CFG of blocks.  Has this hierarchy:

-//  - Module, which is a list of 

-//    - Function, which is a list of 

-//      - Block, which is a list of 

-//        - Instruction

-//

-

-#pragma once

-#ifndef spvIR_H

-#define spvIR_H

-

-#include "spirv.h"

-

-#include <vector>

-#include <iostream>

-#include <assert.h>

-

-namespace spv {

-

-class Function;

-class Module;

-

-const Id NoResult = 0;

-const Id NoType = 0;

-

-const unsigned int BadValue = 0xFFFFFFFF;

-const Decoration NoPrecision = (Decoration)BadValue;

-const MemorySemanticsMask MemorySemanticsAllMemory = (MemorySemanticsMask)0x3FF;

-

-//

-// SPIR-V IR instruction.

-//

-

-class Instruction {

-public:

-    Instruction(Id resultId, Id typeId, Op opCode) : resultId(resultId), typeId(typeId), opCode(opCode), string(0) { }

-    explicit Instruction(Op opCode) : resultId(NoResult), typeId(NoType), opCode(opCode), string(0) { }

-    virtual ~Instruction()

-    {

-        delete string;

-    }

-    void addIdOperand(Id id) { operands.push_back(id); }

-    void addImmediateOperand(unsigned int immediate) { operands.push_back(immediate); }

-    void addStringOperand(const char* str)

-    {

-        originalString = str;

-        string = new std::vector<unsigned int>;

-        unsigned int word;

-        char* wordString = (char*)&word;

-        char* wordPtr = wordString;

-        int charCount = 0;

-        char c;

-        do {

-            c = *(str++);

-            *(wordPtr++) = c;

-            ++charCount;

-            if (charCount == 4) {

-                string->push_back(word);

-                wordPtr = wordString;

-                charCount = 0;

-            }

-        } while (c != 0);

-

-        // deal with partial last word

-        if (charCount > 0) {

-            // pad with 0s

-            for (; charCount < 4; ++charCount)

-                *(wordPtr++) = 0;

-            string->push_back(word);

-        }

-    }

-    Op getOpCode() const { return opCode; }

-    int getNumOperands() const { return (int)operands.size(); }

-    Id getResultId() const { return resultId; }

-    Id getTypeId() const { return typeId; }

-    Id getIdOperand(int op) const { return operands[op]; }

-    unsigned int getImmediateOperand(int op) const { return operands[op]; }

-    const char* getStringOperand() const { return originalString.c_str(); }

-

-    // Write out the binary form.

-    void dump(std::vector<unsigned int>& out) const

-    {

-        // Compute the wordCount

-        unsigned int wordCount = 1;

-        if (typeId)

-            ++wordCount;

-        if (resultId)

-            ++wordCount;

-        wordCount += (unsigned int)operands.size();

-        if (string)

-            wordCount += (unsigned int)string->size();

-

-        // Write out the beginning of the instruction

-        out.push_back(((wordCount) << WordCountShift) | opCode);

-        if (typeId)

-            out.push_back(typeId);

-        if (resultId)

-            out.push_back(resultId);

-

-        // Write out the operands

-        for (int op = 0; op < (int)operands.size(); ++op)

-            out.push_back(operands[op]);

-        if (string)

-            for (int op = 0; op < (int)string->size(); ++op)

-                out.push_back((*string)[op]);

-    }

-

-protected:

-    Instruction(const Instruction&);

-    Id resultId;

-    Id typeId;

-    Op opCode;

-    std::vector<Id> operands;

-    std::vector<unsigned int>* string; // usually non-existent

-    std::string originalString;        // could be optimized away; convenience for getting string operand

-};

-

-//

-// SPIR-V IR block.

-//

-

-class Block {

-public:

-    Block(Id id, Function& parent);

-    virtual ~Block()

-    {

-        // TODO: free instructions

-    }

-    

-    Id getId() { return instructions.front()->getResultId(); }

-

-    Function& getParent() const { return parent; }

-    void addInstruction(Instruction* inst);

-    void addPredecessor(Block* pred) { predecessors.push_back(pred); }

-    void addLocalVariable(Instruction* inst) { localVariables.push_back(inst); }

-    int getNumPredecessors() const { return (int)predecessors.size(); }

-    void setUnreachable() { unreachable = true; }

-    bool isUnreachable() const { return unreachable; }

-

-    bool isTerminated() const

-    {

-        switch (instructions.back()->getOpCode()) {

-        case OpBranch:

-        case OpBranchConditional:

-        case OpSwitch:

-        case OpKill:

-        case OpReturn:

-        case OpReturnValue:

-            return true;

-        default:

-            return false;

-        }

-    }

-

-    void dump(std::vector<unsigned int>& out) const

-    {

-        // skip the degenerate unreachable blocks

-        // TODO: code gen: skip all unreachable blocks (transitive closure)

-        //                 (but, until that's done safer to keep non-degenerate unreachable blocks, in case others depend on something)

-        if (unreachable && instructions.size() <= 2)

-            return;

-

-        instructions[0]->dump(out);

-        for (int i = 0; i < (int)localVariables.size(); ++i)

-            localVariables[i]->dump(out);

-        for (int i = 1; i < (int)instructions.size(); ++i)

-            instructions[i]->dump(out);

-    }

-

-protected:

-    Block(const Block&);

-    Block& operator=(Block&);

-

-    // To enforce keeping parent and ownership in sync:

-    friend Function;

-

-    std::vector<Instruction*> instructions;

-    std::vector<Block*> predecessors;

-    std::vector<Instruction*> localVariables;

-    Function& parent;

-

-    // track whether this block is known to be uncreachable (not necessarily 

-    // true for all unreachable blocks, but should be set at least

-    // for the extraneous ones introduced by the builder).

-    bool unreachable;

-};

-

-//

-// SPIR-V IR Function.

-//

-

-class Function {

-public:

-    Function(Id id, Id resultType, Id functionType, Id firstParam, Module& parent);

-    virtual ~Function()

-    {

-        for (int i = 0; i < (int)parameterInstructions.size(); ++i)

-            delete parameterInstructions[i];

-

-        for (int i = 0; i < (int)blocks.size(); ++i)

-            delete blocks[i];

-    }

-    Id getId() const { return functionInstruction.getResultId(); }

-    Id getParamId(int p) { return parameterInstructions[p]->getResultId(); }

-

-    void addBlock(Block* block) { blocks.push_back(block); }

-    void popBlock(Block*) { blocks.pop_back(); }

-

-    Module& getParent() const { return parent; }

-    Block* getEntryBlock() const { return blocks.front(); }

-    Block* getLastBlock() const { return blocks.back(); }

-    void addLocalVariable(Instruction* inst);

-    Id getReturnType() const { return functionInstruction.getTypeId(); }

-    void dump(std::vector<unsigned int>& out) const

-    {

-        // OpFunction

-        functionInstruction.dump(out);

-

-        // OpFunctionParameter

-        for (int p = 0; p < (int)parameterInstructions.size(); ++p)

-            parameterInstructions[p]->dump(out);

-

-        // Blocks

-        for (int b = 0; b < (int)blocks.size(); ++b)

-            blocks[b]->dump(out);

-        Instruction end(0, 0, OpFunctionEnd);

-        end.dump(out);

-    }

-

-protected:

-    Function(const Function&);

-    Function& operator=(Function&);

-

-    Module& parent;

-    Instruction functionInstruction;

-    std::vector<Instruction*> parameterInstructions;

-    std::vector<Block*> blocks;

-};

-

-//

-// SPIR-V IR Module.

-//

-

-class Module {

-public:

-    Module() {}

-    virtual ~Module()

-    {

-        // TODO delete things

-    }

-

-    void addFunction(Function *fun) { functions.push_back(fun); }

-

-    void mapInstruction(Instruction *instruction)

-    {

-        spv::Id resultId = instruction->getResultId();

-        // map the instruction's result id

-        if (resultId >= idToInstruction.size())

-            idToInstruction.resize(resultId + 16);

-        idToInstruction[resultId] = instruction;

-    }

-

-    Instruction* getInstruction(Id id) const { return idToInstruction[id]; }

-    spv::Id getTypeId(Id resultId) const { return idToInstruction[resultId]->getTypeId(); }

-    StorageClass getStorageClass(Id typeId) const { return (StorageClass)idToInstruction[typeId]->getImmediateOperand(0); }

-    void dump(std::vector<unsigned int>& out) const

-    {

-        for (int f = 0; f < (int)functions.size(); ++f)

-            functions[f]->dump(out);

-    }

-

-protected:

-    Module(const Module&);

-    std::vector<Function*> functions;

-

-    // map from result id to instruction having that result id

-    std::vector<Instruction*> idToInstruction;

-

-    // map from a result id to its type id

-};

-

-//

-// Implementation (it's here due to circular type definitions).

-//

-

-// Add both

-// - the OpFunction instruction

-// - all the OpFunctionParameter instructions

-__inline Function::Function(Id id, Id resultType, Id functionType, Id firstParamId, Module& parent)

-    : parent(parent), functionInstruction(id, resultType, OpFunction)

-{

-    // OpFunction

-    functionInstruction.addImmediateOperand(FunctionControlMaskNone);

-    functionInstruction.addIdOperand(functionType);

-    parent.mapInstruction(&functionInstruction);

-    parent.addFunction(this);

-

-    // OpFunctionParameter

-    Instruction* typeInst = parent.getInstruction(functionType);

-    int numParams = typeInst->getNumOperands() - 1;

-    for (int p = 0; p < numParams; ++p) {

-        Instruction* param = new Instruction(firstParamId + p, typeInst->getIdOperand(p + 1), OpFunctionParameter);

-        parent.mapInstruction(param);

-        parameterInstructions.push_back(param);

-    }

-}

-

-__inline void Function::addLocalVariable(Instruction* inst)

-{

-    blocks[0]->addLocalVariable(inst);

-    parent.mapInstruction(inst);

-}

-

-__inline Block::Block(Id id, Function& parent) : parent(parent), unreachable(false)

-{

-    instructions.push_back(new Instruction(id, NoType, OpLabel));

-}

-

-__inline void Block::addInstruction(Instruction* inst)

-{

-    instructions.push_back(inst);

-    if (inst->getResultId())

-        parent.getParent().mapInstruction(inst);

-}

-

-};  // end spv namespace

-

-#endif // spvIR_H

+//
+//Copyright (C) 2014 LunarG, Inc.
+//
+//All rights reserved.
+//
+//Redistribution and use in source and binary forms, with or without
+//modification, are permitted provided that the following conditions
+//are met:
+//
+//    Redistributions of source code must retain the above copyright
+//    notice, this list of conditions and the following disclaimer.
+//
+//    Redistributions in binary form must reproduce the above
+//    copyright notice, this list of conditions and the following
+//    disclaimer in the documentation and/or other materials provided
+//    with the distribution.
+//
+//    Neither the name of 3Dlabs Inc. Ltd. nor the names of its
+//    contributors may be used to endorse or promote products derived
+//    from this software without specific prior written permission.
+//
+//THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+//"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+//LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+//FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+//COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+//INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+//BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+//LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+//CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+//LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+//ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+//POSSIBILITY OF SUCH DAMAGE.
+
+//
+// Author: John Kessenich, LunarG
+//
+
+// SPIRV-IR
+//
+// Simple in-memory representation (IR) of SPIRV.  Just for holding
+// Each function's CFG of blocks.  Has this hierarchy:
+//  - Module, which is a list of 
+//    - Function, which is a list of 
+//      - Block, which is a list of 
+//        - Instruction
+//
+
+#pragma once
+#ifndef spvIR_H
+#define spvIR_H
+
+#include "spirv.h"
+
+#include <vector>
+#include <iostream>
+#include <assert.h>
+
+namespace spv {
+
+class Function;
+class Module;
+
+const Id NoResult = 0;
+const Id NoType = 0;
+
+const unsigned int BadValue = 0xFFFFFFFF;
+const Decoration NoPrecision = (Decoration)BadValue;
+const MemorySemanticsMask MemorySemanticsAllMemory = (MemorySemanticsMask)0x3FF;
+
+//
+// SPIR-V IR instruction.
+//
+
+class Instruction {
+public:
+    Instruction(Id resultId, Id typeId, Op opCode) : resultId(resultId), typeId(typeId), opCode(opCode), string(0) { }
+    explicit Instruction(Op opCode) : resultId(NoResult), typeId(NoType), opCode(opCode), string(0) { }
+    virtual ~Instruction()
+    {
+        delete string;
+    }
+    void addIdOperand(Id id) { operands.push_back(id); }
+    void addImmediateOperand(unsigned int immediate) { operands.push_back(immediate); }
+    void addStringOperand(const char* str)
+    {
+        originalString = str;
+        string = new std::vector<unsigned int>;
+        unsigned int word;
+        char* wordString = (char*)&word;
+        char* wordPtr = wordString;
+        int charCount = 0;
+        char c;
+        do {
+            c = *(str++);
+            *(wordPtr++) = c;
+            ++charCount;
+            if (charCount == 4) {
+                string->push_back(word);
+                wordPtr = wordString;
+                charCount = 0;
+            }
+        } while (c != 0);
+
+        // deal with partial last word
+        if (charCount > 0) {
+            // pad with 0s
+            for (; charCount < 4; ++charCount)
+                *(wordPtr++) = 0;
+            string->push_back(word);
+        }
+    }
+    Op getOpCode() const { return opCode; }
+    int getNumOperands() const { return (int)operands.size(); }
+    Id getResultId() const { return resultId; }
+    Id getTypeId() const { return typeId; }
+    Id getIdOperand(int op) const { return operands[op]; }
+    unsigned int getImmediateOperand(int op) const { return operands[op]; }
+    const char* getStringOperand() const { return originalString.c_str(); }
+
+    // Write out the binary form.
+    void dump(std::vector<unsigned int>& out) const
+    {
+        // Compute the wordCount
+        unsigned int wordCount = 1;
+        if (typeId)
+            ++wordCount;
+        if (resultId)
+            ++wordCount;
+        wordCount += (unsigned int)operands.size();
+        if (string)
+            wordCount += (unsigned int)string->size();
+
+        // Write out the beginning of the instruction
+        out.push_back(((wordCount) << WordCountShift) | opCode);
+        if (typeId)
+            out.push_back(typeId);
+        if (resultId)
+            out.push_back(resultId);
+
+        // Write out the operands
+        for (int op = 0; op < (int)operands.size(); ++op)
+            out.push_back(operands[op]);
+        if (string)
+            for (int op = 0; op < (int)string->size(); ++op)
+                out.push_back((*string)[op]);
+    }
+
+protected:
+    Instruction(const Instruction&);
+    Id resultId;
+    Id typeId;
+    Op opCode;
+    std::vector<Id> operands;
+    std::vector<unsigned int>* string; // usually non-existent
+    std::string originalString;        // could be optimized away; convenience for getting string operand
+};
+
+//
+// SPIR-V IR block.
+//
+
+class Block {
+public:
+    Block(Id id, Function& parent);
+    virtual ~Block()
+    {
+        // TODO: free instructions
+    }
+    
+    Id getId() { return instructions.front()->getResultId(); }
+
+    Function& getParent() const { return parent; }
+    void addInstruction(Instruction* inst);
+    void addPredecessor(Block* pred) { predecessors.push_back(pred); }
+    void addLocalVariable(Instruction* inst) { localVariables.push_back(inst); }
+    int getNumPredecessors() const { return (int)predecessors.size(); }
+    void setUnreachable() { unreachable = true; }
+    bool isUnreachable() const { return unreachable; }
+
+    bool isTerminated() const
+    {
+        switch (instructions.back()->getOpCode()) {
+        case OpBranch:
+        case OpBranchConditional:
+        case OpSwitch:
+        case OpKill:
+        case OpReturn:
+        case OpReturnValue:
+            return true;
+        default:
+            return false;
+        }
+    }
+
+    void dump(std::vector<unsigned int>& out) const
+    {
+        // skip the degenerate unreachable blocks
+        // TODO: code gen: skip all unreachable blocks (transitive closure)
+        //                 (but, until that's done safer to keep non-degenerate unreachable blocks, in case others depend on something)
+        if (unreachable && instructions.size() <= 2)
+            return;
+
+        instructions[0]->dump(out);
+        for (int i = 0; i < (int)localVariables.size(); ++i)
+            localVariables[i]->dump(out);
+        for (int i = 1; i < (int)instructions.size(); ++i)
+            instructions[i]->dump(out);
+    }
+
+protected:
+    Block(const Block&);
+    Block& operator=(Block&);
+
+    // To enforce keeping parent and ownership in sync:
+    friend Function;
+
+    std::vector<Instruction*> instructions;
+    std::vector<Block*> predecessors;
+    std::vector<Instruction*> localVariables;
+    Function& parent;
+
+    // track whether this block is known to be uncreachable (not necessarily 
+    // true for all unreachable blocks, but should be set at least
+    // for the extraneous ones introduced by the builder).
+    bool unreachable;
+};
+
+//
+// SPIR-V IR Function.
+//
+
+class Function {
+public:
+    Function(Id id, Id resultType, Id functionType, Id firstParam, Module& parent);
+    virtual ~Function()
+    {
+        for (int i = 0; i < (int)parameterInstructions.size(); ++i)
+            delete parameterInstructions[i];
+
+        for (int i = 0; i < (int)blocks.size(); ++i)
+            delete blocks[i];
+    }
+    Id getId() const { return functionInstruction.getResultId(); }
+    Id getParamId(int p) { return parameterInstructions[p]->getResultId(); }
+
+    void addBlock(Block* block) { blocks.push_back(block); }
+    void popBlock(Block*) { blocks.pop_back(); }
+
+    Module& getParent() const { return parent; }
+    Block* getEntryBlock() const { return blocks.front(); }
+    Block* getLastBlock() const { return blocks.back(); }
+    void addLocalVariable(Instruction* inst);
+    Id getReturnType() const { return functionInstruction.getTypeId(); }
+    void dump(std::vector<unsigned int>& out) const
+    {
+        // OpFunction
+        functionInstruction.dump(out);
+
+        // OpFunctionParameter
+        for (int p = 0; p < (int)parameterInstructions.size(); ++p)
+            parameterInstructions[p]->dump(out);
+
+        // Blocks
+        for (int b = 0; b < (int)blocks.size(); ++b)
+            blocks[b]->dump(out);
+        Instruction end(0, 0, OpFunctionEnd);
+        end.dump(out);
+    }
+
+protected:
+    Function(const Function&);
+    Function& operator=(Function&);
+
+    Module& parent;
+    Instruction functionInstruction;
+    std::vector<Instruction*> parameterInstructions;
+    std::vector<Block*> blocks;
+};
+
+//
+// SPIR-V IR Module.
+//
+
+class Module {
+public:
+    Module() {}
+    virtual ~Module()
+    {
+        // TODO delete things
+    }
+
+    void addFunction(Function *fun) { functions.push_back(fun); }
+
+    void mapInstruction(Instruction *instruction)
+    {
+        spv::Id resultId = instruction->getResultId();
+        // map the instruction's result id
+        if (resultId >= idToInstruction.size())
+            idToInstruction.resize(resultId + 16);
+        idToInstruction[resultId] = instruction;
+    }
+
+    Instruction* getInstruction(Id id) const { return idToInstruction[id]; }
+    spv::Id getTypeId(Id resultId) const { return idToInstruction[resultId]->getTypeId(); }
+    StorageClass getStorageClass(Id typeId) const { return (StorageClass)idToInstruction[typeId]->getImmediateOperand(0); }
+    void dump(std::vector<unsigned int>& out) const
+    {
+        for (int f = 0; f < (int)functions.size(); ++f)
+            functions[f]->dump(out);
+    }
+
+protected:
+    Module(const Module&);
+    std::vector<Function*> functions;
+
+    // map from result id to instruction having that result id
+    std::vector<Instruction*> idToInstruction;
+
+    // map from a result id to its type id
+};
+
+//
+// Implementation (it's here due to circular type definitions).
+//
+
+// Add both
+// - the OpFunction instruction
+// - all the OpFunctionParameter instructions
+__inline Function::Function(Id id, Id resultType, Id functionType, Id firstParamId, Module& parent)
+    : parent(parent), functionInstruction(id, resultType, OpFunction)
+{
+    // OpFunction
+    functionInstruction.addImmediateOperand(FunctionControlMaskNone);
+    functionInstruction.addIdOperand(functionType);
+    parent.mapInstruction(&functionInstruction);
+    parent.addFunction(this);
+
+    // OpFunctionParameter
+    Instruction* typeInst = parent.getInstruction(functionType);
+    int numParams = typeInst->getNumOperands() - 1;
+    for (int p = 0; p < numParams; ++p) {
+        Instruction* param = new Instruction(firstParamId + p, typeInst->getIdOperand(p + 1), OpFunctionParameter);
+        parent.mapInstruction(param);
+        parameterInstructions.push_back(param);
+    }
+}
+
+__inline void Function::addLocalVariable(Instruction* inst)
+{
+    blocks[0]->addLocalVariable(inst);
+    parent.mapInstruction(inst);
+}
+
+__inline Block::Block(Id id, Function& parent) : parent(parent), unreachable(false)
+{
+    instructions.push_back(new Instruction(id, NoType, OpLabel));
+}
+
+__inline void Block::addInstruction(Instruction* inst)
+{
+    instructions.push_back(inst);
+    if (inst->getResultId())
+        parent.getParent().mapInstruction(inst);
+}
+
+};  // end spv namespace
+
+#endif // spvIR_H
diff --git a/StandAlone/CMakeLists.txt b/StandAlone/CMakeLists.txt
index a5592c8..f5ebab9 100644
--- a/StandAlone/CMakeLists.txt
+++ b/StandAlone/CMakeLists.txt
@@ -1,41 +1,41 @@
-cmake_minimum_required(VERSION 2.8)

-

-include_directories(.)

-if(WIN32)

-    include_directories(../glslang/OSDependent/Windows)

-elseif(UNIX)

-    include_directories(../glslang/OSDependent/Linux)

-else(WIN32)

-    message("unkown platform")

-endif(WIN32)

-

-set(SOURCES StandAlone.cpp)

-set(REMAPPER_SOURCES spirv-remap.cpp)

-

-add_executable(glslangValidator ${SOURCES})

-add_executable(spirv-remap ${REMAPPER_SOURCES})

-

-set(LIBRARIES

-    glslang

-    OGLCompiler

-    OSDependent

-    SPIRV)

-

-if(WIN32)

-    set(LIBRARIES ${LIBRARIES} psapi)

-elseif(UNIX)

-    set(LIBRARIES ${LIBRARIES} pthread)

-endif(WIN32)

-

-target_link_libraries(glslangValidator ${LIBRARIES})

-target_link_libraries(spirv-remap ${LIBRARIES})

-

-if(WIN32)

-    source_group("Source" FILES ${SOURCES})

-endif(WIN32)

-

-install(TARGETS glslangValidator

-        RUNTIME DESTINATION bin)

-

-install(TARGETS spirv-remap

-        RUNTIME DESTINATION bin)

+cmake_minimum_required(VERSION 2.8)
+
+include_directories(.)
+if(WIN32)
+    include_directories(../glslang/OSDependent/Windows)
+elseif(UNIX)
+    include_directories(../glslang/OSDependent/Linux)
+else(WIN32)
+    message("unkown platform")
+endif(WIN32)
+
+set(SOURCES StandAlone.cpp)
+set(REMAPPER_SOURCES spirv-remap.cpp)
+
+add_executable(glslangValidator ${SOURCES})
+add_executable(spirv-remap ${REMAPPER_SOURCES})
+
+set(LIBRARIES
+    glslang
+    OGLCompiler
+    OSDependent
+    SPIRV)
+
+if(WIN32)
+    set(LIBRARIES ${LIBRARIES} psapi)
+elseif(UNIX)
+    set(LIBRARIES ${LIBRARIES} pthread)
+endif(WIN32)
+
+target_link_libraries(glslangValidator ${LIBRARIES})
+target_link_libraries(spirv-remap ${LIBRARIES})
+
+if(WIN32)
+    source_group("Source" FILES ${SOURCES})
+endif(WIN32)
+
+install(TARGETS glslangValidator
+        RUNTIME DESTINATION bin)
+
+install(TARGETS spirv-remap
+        RUNTIME DESTINATION bin)
diff --git a/StandAlone/spirv-remap.cpp b/StandAlone/spirv-remap.cpp
index b3359a6..301256f 100644
--- a/StandAlone/spirv-remap.cpp
+++ b/StandAlone/spirv-remap.cpp
@@ -1,337 +1,337 @@
-//

-//Copyright (C) 2015 LunarG, Inc.

-//

-//All rights reserved.

-//

-//Redistribution and use in source and binary forms, with or without

-//modification, are permitted provided that the following conditions

-//are met:

-//

-//    Redistributions of source code must retain the above copyright

-//    notice, this list of conditions and the following disclaimer.

-//

-//    Redistributions in binary form must reproduce the above

-//    copyright notice, this list of conditions and the following

-//    disclaimer in the documentation and/or other materials provided

-//    with the distribution.

-//

-//    Neither the name of 3Dlabs Inc. Ltd. nor the names of its

-//    contributors may be used to endorse or promote products derived

-//    from this software without specific prior written permission.

-//

-//THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS

-//"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT

-//LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS

-//FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE

-//COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,

-//INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,

-//BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;

-//LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER

-//CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT

-//LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN

-//ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE

-//POSSIBILITY OF SUCH DAMAGE.

-//

-

-#include <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.

-}

+//
+//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.
+}