Final round for line endings.
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