Home | History | Annotate | Download | only in SPIRV
      1 //
      2 //Copyright (C) 2014-2016 LunarG, Inc.
      3 //Copyright (C) 2015-2016 Google, Inc.
      4 //
      5 //All rights reserved.
      6 //
      7 //Redistribution and use in source and binary forms, with or without
      8 //modification, are permitted provided that the following conditions
      9 //are met:
     10 //
     11 //    Redistributions of source code must retain the above copyright
     12 //    notice, this list of conditions and the following disclaimer.
     13 //
     14 //    Redistributions in binary form must reproduce the above
     15 //    copyright notice, this list of conditions and the following
     16 //    disclaimer in the documentation and/or other materials provided
     17 //    with the distribution.
     18 //
     19 //    Neither the name of 3Dlabs Inc. Ltd. nor the names of its
     20 //    contributors may be used to endorse or promote products derived
     21 //    from this software without specific prior written permission.
     22 //
     23 //THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     24 //"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     25 //LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
     26 //FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
     27 //COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
     28 //INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
     29 //BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
     30 //LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
     31 //CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     32 //LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
     33 //ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     34 //POSSIBILITY OF SUCH DAMAGE.
     35 
     36 //
     37 // Visit the nodes in the glslang intermediate tree representation to
     38 // translate them to SPIR-V.
     39 //
     40 
     41 #include "spirv.hpp"
     42 #include "GlslangToSpv.h"
     43 #include "SpvBuilder.h"
     44 namespace spv {
     45    #include "GLSL.std.450.h"
     46 }
     47 
     48 // Glslang includes
     49 #include "../glslang/MachineIndependent/localintermediate.h"
     50 #include "../glslang/MachineIndependent/SymbolTable.h"
     51 #include "../glslang/Include/Common.h"
     52 #include "../glslang/Include/revision.h"
     53 
     54 #include <fstream>
     55 #include <iomanip>
     56 #include <list>
     57 #include <map>
     58 #include <stack>
     59 #include <string>
     60 #include <vector>
     61 
     62 namespace {
     63 
     64 // For low-order part of the generator's magic number. Bump up
     65 // when there is a change in the style (e.g., if SSA form changes,
     66 // or a different instruction sequence to do something gets used).
     67 const int GeneratorVersion = 1;
     68 
     69 namespace {
     70 class SpecConstantOpModeGuard {
     71 public:
     72     SpecConstantOpModeGuard(spv::Builder* builder)
     73         : builder_(builder) {
     74         previous_flag_ = builder->isInSpecConstCodeGenMode();
     75     }
     76     ~SpecConstantOpModeGuard() {
     77         previous_flag_ ? builder_->setToSpecConstCodeGenMode()
     78                        : builder_->setToNormalCodeGenMode();
     79     }
     80     void turnOnSpecConstantOpMode() {
     81         builder_->setToSpecConstCodeGenMode();
     82     }
     83 
     84 private:
     85     spv::Builder* builder_;
     86     bool previous_flag_;
     87 };
     88 }
     89 
     90 //
     91 // The main holder of information for translating glslang to SPIR-V.
     92 //
     93 // Derives from the AST walking base class.
     94 //
     95 class TGlslangToSpvTraverser : public glslang::TIntermTraverser {
     96 public:
     97     TGlslangToSpvTraverser(const glslang::TIntermediate*, spv::SpvBuildLogger* logger);
     98     virtual ~TGlslangToSpvTraverser();
     99 
    100     bool visitAggregate(glslang::TVisit, glslang::TIntermAggregate*);
    101     bool visitBinary(glslang::TVisit, glslang::TIntermBinary*);
    102     void visitConstantUnion(glslang::TIntermConstantUnion*);
    103     bool visitSelection(glslang::TVisit, glslang::TIntermSelection*);
    104     bool visitSwitch(glslang::TVisit, glslang::TIntermSwitch*);
    105     void visitSymbol(glslang::TIntermSymbol* symbol);
    106     bool visitUnary(glslang::TVisit, glslang::TIntermUnary*);
    107     bool visitLoop(glslang::TVisit, glslang::TIntermLoop*);
    108     bool visitBranch(glslang::TVisit visit, glslang::TIntermBranch*);
    109 
    110     void dumpSpv(std::vector<unsigned int>& out);
    111 
    112 protected:
    113     spv::Decoration TranslateAuxiliaryStorageDecoration(const glslang::TQualifier& qualifier);
    114     spv::BuiltIn TranslateBuiltInDecoration(glslang::TBuiltInVariable, bool memberDeclaration);
    115     spv::ImageFormat TranslateImageFormat(const glslang::TType& type);
    116     spv::Id createSpvVariable(const glslang::TIntermSymbol*);
    117     spv::Id getSampledType(const glslang::TSampler&);
    118     spv::Id convertGlslangToSpvType(const glslang::TType& type);
    119     spv::Id convertGlslangToSpvType(const glslang::TType& type, glslang::TLayoutPacking, const glslang::TQualifier&);
    120     spv::Id convertGlslangStructToSpvType(const glslang::TType&, const glslang::TTypeList* glslangStruct,
    121                                           glslang::TLayoutPacking, const glslang::TQualifier&);
    122     void decorateStructType(const glslang::TType&, const glslang::TTypeList* glslangStruct, glslang::TLayoutPacking,
    123                             const glslang::TQualifier&, spv::Id);
    124     spv::Id makeArraySizeId(const glslang::TArraySizes&, int dim);
    125     spv::Id accessChainLoad(const glslang::TType& type);
    126     void    accessChainStore(const glslang::TType& type, spv::Id rvalue);
    127     glslang::TLayoutPacking getExplicitLayout(const glslang::TType& type) const;
    128     int getArrayStride(const glslang::TType& arrayType, glslang::TLayoutPacking, glslang::TLayoutMatrix);
    129     int getMatrixStride(const glslang::TType& matrixType, glslang::TLayoutPacking, glslang::TLayoutMatrix);
    130     void updateMemberOffset(const glslang::TType& structType, const glslang::TType& memberType, int& currentOffset, int& nextOffset, glslang::TLayoutPacking, glslang::TLayoutMatrix);
    131     void declareUseOfStructMember(const glslang::TTypeList& members, int glslangMember);
    132 
    133     bool isShaderEntrypoint(const glslang::TIntermAggregate* node);
    134     void makeFunctions(const glslang::TIntermSequence&);
    135     void makeGlobalInitializers(const glslang::TIntermSequence&);
    136     void visitFunctions(const glslang::TIntermSequence&);
    137     void handleFunctionEntry(const glslang::TIntermAggregate* node);
    138     void translateArguments(const glslang::TIntermAggregate& node, std::vector<spv::Id>& arguments);
    139     void translateArguments(glslang::TIntermUnary& node, std::vector<spv::Id>& arguments);
    140     spv::Id createImageTextureFunctionCall(glslang::TIntermOperator* node);
    141     spv::Id handleUserFunctionCall(const glslang::TIntermAggregate*);
    142 
    143     spv::Id createBinaryOperation(glslang::TOperator op, spv::Decoration precision, spv::Decoration noContraction, spv::Id typeId, spv::Id left, spv::Id right, glslang::TBasicType typeProxy, bool reduceComparison = true);
    144     spv::Id createBinaryMatrixOperation(spv::Op, spv::Decoration precision, spv::Decoration noContraction, spv::Id typeId, spv::Id left, spv::Id right);
    145     spv::Id createUnaryOperation(glslang::TOperator op, spv::Decoration precision, spv::Decoration noContraction, spv::Id typeId, spv::Id operand,glslang::TBasicType typeProxy);
    146     spv::Id createUnaryMatrixOperation(spv::Op, spv::Decoration precision, spv::Decoration noContraction, spv::Id typeId, spv::Id operand,glslang::TBasicType typeProxy);
    147     spv::Id createConversion(glslang::TOperator op, spv::Decoration precision, spv::Decoration noContraction, spv::Id destTypeId, spv::Id operand, glslang::TBasicType typeProxy);
    148     spv::Id makeSmearedConstant(spv::Id constant, int vectorSize);
    149     spv::Id createAtomicOperation(glslang::TOperator op, spv::Decoration precision, spv::Id typeId, std::vector<spv::Id>& operands, glslang::TBasicType typeProxy);
    150     spv::Id createInvocationsOperation(glslang::TOperator, spv::Id typeId, spv::Id operand);
    151     spv::Id createMiscOperation(glslang::TOperator op, spv::Decoration precision, spv::Id typeId, std::vector<spv::Id>& operands, glslang::TBasicType typeProxy);
    152     spv::Id createNoArgOperation(glslang::TOperator op);
    153     spv::Id getSymbolId(const glslang::TIntermSymbol* node);
    154     void addDecoration(spv::Id id, spv::Decoration dec);
    155     void addDecoration(spv::Id id, spv::Decoration dec, unsigned value);
    156     void addMemberDecoration(spv::Id id, int member, spv::Decoration dec);
    157     void addMemberDecoration(spv::Id id, int member, spv::Decoration dec, unsigned value);
    158     spv::Id createSpvConstant(const glslang::TIntermTyped&);
    159     spv::Id createSpvConstantFromConstUnionArray(const glslang::TType& type, const glslang::TConstUnionArray&, int& nextConst, bool specConstant);
    160     bool isTrivialLeaf(const glslang::TIntermTyped* node);
    161     bool isTrivial(const glslang::TIntermTyped* node);
    162     spv::Id createShortCircuit(glslang::TOperator, glslang::TIntermTyped& left, glslang::TIntermTyped& right);
    163 
    164     spv::Function* shaderEntry;
    165     spv::Instruction* entryPoint;
    166     int sequenceDepth;
    167 
    168     spv::SpvBuildLogger* logger;
    169 
    170     // There is a 1:1 mapping between a spv builder and a module; this is thread safe
    171     spv::Builder builder;
    172     bool inMain;
    173     bool mainTerminated;
    174     bool linkageOnly;                  // true when visiting the set of objects in the AST present only for establishing interface, whether or not they were statically used
    175     std::set<spv::Id> iOSet;           // all input/output variables from either static use or declaration of interface
    176     const glslang::TIntermediate* glslangIntermediate;
    177     spv::Id stdBuiltins;
    178 
    179     std::unordered_map<int, spv::Id> symbolValues;
    180     std::unordered_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
    181     std::unordered_map<std::string, spv::Function*> functionMap;
    182     std::unordered_map<const glslang::TTypeList*, spv::Id> structMap[glslang::ElpCount][glslang::ElmCount];
    183     std::unordered_map<const glslang::TTypeList*, std::vector<int> > memberRemapper;  // for mapping glslang block indices to spv indices (e.g., due to hidden members)
    184     std::stack<bool> breakForLoop;  // false means break for switch
    185 };
    186 
    187 //
    188 // Helper functions for translating glslang representations to SPIR-V enumerants.
    189 //
    190 
    191 // Translate glslang profile to SPIR-V source language.
    192 spv::SourceLanguage TranslateSourceLanguage(glslang::EShSource source, EProfile profile)
    193 {
    194     switch (source) {
    195     case glslang::EShSourceGlsl:
    196         switch (profile) {
    197         case ENoProfile:
    198         case ECoreProfile:
    199         case ECompatibilityProfile:
    200             return spv::SourceLanguageGLSL;
    201         case EEsProfile:
    202             return spv::SourceLanguageESSL;
    203         default:
    204             return spv::SourceLanguageUnknown;
    205         }
    206     case glslang::EShSourceHlsl:
    207         return spv::SourceLanguageHLSL;
    208     default:
    209         return spv::SourceLanguageUnknown;
    210     }
    211 }
    212 
    213 // Translate glslang language (stage) to SPIR-V execution model.
    214 spv::ExecutionModel TranslateExecutionModel(EShLanguage stage)
    215 {
    216     switch (stage) {
    217     case EShLangVertex:           return spv::ExecutionModelVertex;
    218     case EShLangTessControl:      return spv::ExecutionModelTessellationControl;
    219     case EShLangTessEvaluation:   return spv::ExecutionModelTessellationEvaluation;
    220     case EShLangGeometry:         return spv::ExecutionModelGeometry;
    221     case EShLangFragment:         return spv::ExecutionModelFragment;
    222     case EShLangCompute:          return spv::ExecutionModelGLCompute;
    223     default:
    224         assert(0);
    225         return spv::ExecutionModelFragment;
    226     }
    227 }
    228 
    229 // Translate glslang type to SPIR-V storage class.
    230 spv::StorageClass TranslateStorageClass(const glslang::TType& type)
    231 {
    232     if (type.getQualifier().isPipeInput())
    233         return spv::StorageClassInput;
    234     else if (type.getQualifier().isPipeOutput())
    235         return spv::StorageClassOutput;
    236     else if (type.getBasicType() == glslang::EbtSampler)
    237         return spv::StorageClassUniformConstant;
    238     else if (type.getBasicType() == glslang::EbtAtomicUint)
    239         return spv::StorageClassAtomicCounter;
    240     else if (type.getQualifier().isUniformOrBuffer()) {
    241         if (type.getQualifier().layoutPushConstant)
    242             return spv::StorageClassPushConstant;
    243         if (type.getBasicType() == glslang::EbtBlock)
    244             return spv::StorageClassUniform;
    245         else
    246             return spv::StorageClassUniformConstant;
    247         // TODO: how are we distinguishing between default and non-default non-writable uniforms?  Do default uniforms even exist?
    248     } else {
    249         switch (type.getQualifier().storage) {
    250         case glslang::EvqShared:        return spv::StorageClassWorkgroup;  break;
    251         case glslang::EvqGlobal:        return spv::StorageClassPrivate;
    252         case glslang::EvqConstReadOnly: return spv::StorageClassFunction;
    253         case glslang::EvqTemporary:     return spv::StorageClassFunction;
    254         default:
    255             assert(0);
    256             return spv::StorageClassFunction;
    257         }
    258     }
    259 }
    260 
    261 // Translate glslang sampler type to SPIR-V dimensionality.
    262 spv::Dim TranslateDimensionality(const glslang::TSampler& sampler)
    263 {
    264     switch (sampler.dim) {
    265     case glslang::Esd1D:      return spv::Dim1D;
    266     case glslang::Esd2D:      return spv::Dim2D;
    267     case glslang::Esd3D:      return spv::Dim3D;
    268     case glslang::EsdCube:    return spv::DimCube;
    269     case glslang::EsdRect:    return spv::DimRect;
    270     case glslang::EsdBuffer:  return spv::DimBuffer;
    271     case glslang::EsdSubpass: return spv::DimSubpassData;
    272     default:
    273         assert(0);
    274         return spv::Dim2D;
    275     }
    276 }
    277 
    278 // Translate glslang type to SPIR-V precision decorations.
    279 spv::Decoration TranslatePrecisionDecoration(const glslang::TType& type)
    280 {
    281     switch (type.getQualifier().precision) {
    282     case glslang::EpqLow:    return spv::DecorationRelaxedPrecision;
    283     case glslang::EpqMedium: return spv::DecorationRelaxedPrecision;
    284     default:
    285         return spv::NoPrecision;
    286     }
    287 }
    288 
    289 // Translate glslang type to SPIR-V block decorations.
    290 spv::Decoration TranslateBlockDecoration(const glslang::TType& type)
    291 {
    292     if (type.getBasicType() == glslang::EbtBlock) {
    293         switch (type.getQualifier().storage) {
    294         case glslang::EvqUniform:      return spv::DecorationBlock;
    295         case glslang::EvqBuffer:       return spv::DecorationBufferBlock;
    296         case glslang::EvqVaryingIn:    return spv::DecorationBlock;
    297         case glslang::EvqVaryingOut:   return spv::DecorationBlock;
    298         default:
    299             assert(0);
    300             break;
    301         }
    302     }
    303 
    304     return spv::DecorationMax;
    305 }
    306 
    307 // Translate glslang type to SPIR-V memory decorations.
    308 void TranslateMemoryDecoration(const glslang::TQualifier& qualifier, std::vector<spv::Decoration>& memory)
    309 {
    310     if (qualifier.coherent)
    311         memory.push_back(spv::DecorationCoherent);
    312     if (qualifier.volatil)
    313         memory.push_back(spv::DecorationVolatile);
    314     if (qualifier.restrict)
    315         memory.push_back(spv::DecorationRestrict);
    316     if (qualifier.readonly)
    317         memory.push_back(spv::DecorationNonWritable);
    318     if (qualifier.writeonly)
    319        memory.push_back(spv::DecorationNonReadable);
    320 }
    321 
    322 // Translate glslang type to SPIR-V layout decorations.
    323 spv::Decoration TranslateLayoutDecoration(const glslang::TType& type, glslang::TLayoutMatrix matrixLayout)
    324 {
    325     if (type.isMatrix()) {
    326         switch (matrixLayout) {
    327         case glslang::ElmRowMajor:
    328             return spv::DecorationRowMajor;
    329         case glslang::ElmColumnMajor:
    330             return spv::DecorationColMajor;
    331         default:
    332             // opaque layouts don't need a majorness
    333             return spv::DecorationMax;
    334         }
    335     } else {
    336         switch (type.getBasicType()) {
    337         default:
    338             return spv::DecorationMax;
    339             break;
    340         case glslang::EbtBlock:
    341             switch (type.getQualifier().storage) {
    342             case glslang::EvqUniform:
    343             case glslang::EvqBuffer:
    344                 switch (type.getQualifier().layoutPacking) {
    345                 case glslang::ElpShared:  return spv::DecorationGLSLShared;
    346                 case glslang::ElpPacked:  return spv::DecorationGLSLPacked;
    347                 default:
    348                     return spv::DecorationMax;
    349                 }
    350             case glslang::EvqVaryingIn:
    351             case glslang::EvqVaryingOut:
    352                 assert(type.getQualifier().layoutPacking == glslang::ElpNone);
    353                 return spv::DecorationMax;
    354             default:
    355                 assert(0);
    356                 return spv::DecorationMax;
    357             }
    358         }
    359     }
    360 }
    361 
    362 // Translate glslang type to SPIR-V interpolation decorations.
    363 // Returns spv::DecorationMax when no decoration
    364 // should be applied.
    365 spv::Decoration TranslateInterpolationDecoration(const glslang::TQualifier& qualifier)
    366 {
    367     if (qualifier.smooth)
    368         // Smooth decoration doesn't exist in SPIR-V 1.0
    369         return spv::DecorationMax;
    370     else if (qualifier.nopersp)
    371         return spv::DecorationNoPerspective;
    372     else if (qualifier.flat)
    373         return spv::DecorationFlat;
    374     else
    375         return spv::DecorationMax;
    376 }
    377 
    378 // Translate glslang type to SPIR-V auxiliary storage decorations.
    379 // Returns spv::DecorationMax when no decoration
    380 // should be applied.
    381 spv::Decoration TGlslangToSpvTraverser::TranslateAuxiliaryStorageDecoration(const glslang::TQualifier& qualifier)
    382 {
    383     if (qualifier.patch)
    384         return spv::DecorationPatch;
    385     else if (qualifier.centroid)
    386         return spv::DecorationCentroid;
    387     else if (qualifier.sample) {
    388         builder.addCapability(spv::CapabilitySampleRateShading);
    389         return spv::DecorationSample;
    390     } else
    391         return spv::DecorationMax;
    392 }
    393 
    394 // If glslang type is invariant, return SPIR-V invariant decoration.
    395 spv::Decoration TranslateInvariantDecoration(const glslang::TQualifier& qualifier)
    396 {
    397     if (qualifier.invariant)
    398         return spv::DecorationInvariant;
    399     else
    400         return spv::DecorationMax;
    401 }
    402 
    403 // If glslang type is noContraction, return SPIR-V NoContraction decoration.
    404 spv::Decoration TranslateNoContractionDecoration(const glslang::TQualifier& qualifier)
    405 {
    406     if (qualifier.noContraction)
    407         return spv::DecorationNoContraction;
    408     else
    409         return spv::DecorationMax;
    410 }
    411 
    412 // Translate a glslang built-in variable to a SPIR-V built in decoration.  Also generate
    413 // associated capabilities when required.  For some built-in variables, a capability
    414 // is generated only when using the variable in an executable instruction, but not when
    415 // just declaring a struct member variable with it.  This is true for PointSize,
    416 // ClipDistance, and CullDistance.
    417 spv::BuiltIn TGlslangToSpvTraverser::TranslateBuiltInDecoration(glslang::TBuiltInVariable builtIn, bool memberDeclaration)
    418 {
    419     switch (builtIn) {
    420     case glslang::EbvPointSize:
    421         // Defer adding the capability until the built-in is actually used.
    422         if (! memberDeclaration) {
    423             switch (glslangIntermediate->getStage()) {
    424             case EShLangGeometry:
    425                 builder.addCapability(spv::CapabilityGeometryPointSize);
    426                 break;
    427             case EShLangTessControl:
    428             case EShLangTessEvaluation:
    429                 builder.addCapability(spv::CapabilityTessellationPointSize);
    430                 break;
    431             default:
    432                 break;
    433             }
    434         }
    435         return spv::BuiltInPointSize;
    436 
    437     // These *Distance capabilities logically belong here, but if the member is declared and
    438     // then never used, consumers of SPIR-V prefer the capability not be declared.
    439     // They are now generated when used, rather than here when declared.
    440     // Potentially, the specification should be more clear what the minimum
    441     // use needed is to trigger the capability.
    442     //
    443     case glslang::EbvClipDistance:
    444         if (!memberDeclaration)
    445         builder.addCapability(spv::CapabilityClipDistance);
    446         return spv::BuiltInClipDistance;
    447 
    448     case glslang::EbvCullDistance:
    449         if (!memberDeclaration)
    450         builder.addCapability(spv::CapabilityCullDistance);
    451         return spv::BuiltInCullDistance;
    452 
    453     case glslang::EbvViewportIndex:
    454         builder.addCapability(spv::CapabilityMultiViewport);
    455         return spv::BuiltInViewportIndex;
    456 
    457     case glslang::EbvSampleId:
    458         builder.addCapability(spv::CapabilitySampleRateShading);
    459         return spv::BuiltInSampleId;
    460 
    461     case glslang::EbvSamplePosition:
    462         builder.addCapability(spv::CapabilitySampleRateShading);
    463         return spv::BuiltInSamplePosition;
    464 
    465     case glslang::EbvSampleMask:
    466         builder.addCapability(spv::CapabilitySampleRateShading);
    467         return spv::BuiltInSampleMask;
    468 
    469     case glslang::EbvLayer:
    470         builder.addCapability(spv::CapabilityGeometry);
    471         return spv::BuiltInLayer;
    472 
    473     case glslang::EbvPosition:             return spv::BuiltInPosition;
    474     case glslang::EbvVertexId:             return spv::BuiltInVertexId;
    475     case glslang::EbvInstanceId:           return spv::BuiltInInstanceId;
    476     case glslang::EbvVertexIndex:          return spv::BuiltInVertexIndex;
    477     case glslang::EbvInstanceIndex:        return spv::BuiltInInstanceIndex;
    478     case glslang::EbvBaseVertex:
    479     case glslang::EbvBaseInstance:
    480     case glslang::EbvDrawId:
    481         // TODO: Add SPIR-V builtin ID.
    482         logger->missingFunctionality("shader draw parameters");
    483         return spv::BuiltInMax;
    484     case glslang::EbvPrimitiveId:          return spv::BuiltInPrimitiveId;
    485     case glslang::EbvInvocationId:         return spv::BuiltInInvocationId;
    486     case glslang::EbvTessLevelInner:       return spv::BuiltInTessLevelInner;
    487     case glslang::EbvTessLevelOuter:       return spv::BuiltInTessLevelOuter;
    488     case glslang::EbvTessCoord:            return spv::BuiltInTessCoord;
    489     case glslang::EbvPatchVertices:        return spv::BuiltInPatchVertices;
    490     case glslang::EbvFragCoord:            return spv::BuiltInFragCoord;
    491     case glslang::EbvPointCoord:           return spv::BuiltInPointCoord;
    492     case glslang::EbvFace:                 return spv::BuiltInFrontFacing;
    493     case glslang::EbvFragDepth:            return spv::BuiltInFragDepth;
    494     case glslang::EbvHelperInvocation:     return spv::BuiltInHelperInvocation;
    495     case glslang::EbvNumWorkGroups:        return spv::BuiltInNumWorkgroups;
    496     case glslang::EbvWorkGroupSize:        return spv::BuiltInWorkgroupSize;
    497     case glslang::EbvWorkGroupId:          return spv::BuiltInWorkgroupId;
    498     case glslang::EbvLocalInvocationId:    return spv::BuiltInLocalInvocationId;
    499     case glslang::EbvLocalInvocationIndex: return spv::BuiltInLocalInvocationIndex;
    500     case glslang::EbvGlobalInvocationId:   return spv::BuiltInGlobalInvocationId;
    501     case glslang::EbvSubGroupSize:
    502     case glslang::EbvSubGroupInvocation:
    503     case glslang::EbvSubGroupEqMask:
    504     case glslang::EbvSubGroupGeMask:
    505     case glslang::EbvSubGroupGtMask:
    506     case glslang::EbvSubGroupLeMask:
    507     case glslang::EbvSubGroupLtMask:
    508         // TODO: Add SPIR-V builtin ID.
    509         logger->missingFunctionality("shader ballot");
    510         return spv::BuiltInMax;
    511     default:                               return spv::BuiltInMax;
    512     }
    513 }
    514 
    515 // Translate glslang image layout format to SPIR-V image format.
    516 spv::ImageFormat TGlslangToSpvTraverser::TranslateImageFormat(const glslang::TType& type)
    517 {
    518     assert(type.getBasicType() == glslang::EbtSampler);
    519 
    520     // Check for capabilities
    521     switch (type.getQualifier().layoutFormat) {
    522     case glslang::ElfRg32f:
    523     case glslang::ElfRg16f:
    524     case glslang::ElfR11fG11fB10f:
    525     case glslang::ElfR16f:
    526     case glslang::ElfRgba16:
    527     case glslang::ElfRgb10A2:
    528     case glslang::ElfRg16:
    529     case glslang::ElfRg8:
    530     case glslang::ElfR16:
    531     case glslang::ElfR8:
    532     case glslang::ElfRgba16Snorm:
    533     case glslang::ElfRg16Snorm:
    534     case glslang::ElfRg8Snorm:
    535     case glslang::ElfR16Snorm:
    536     case glslang::ElfR8Snorm:
    537 
    538     case glslang::ElfRg32i:
    539     case glslang::ElfRg16i:
    540     case glslang::ElfRg8i:
    541     case glslang::ElfR16i:
    542     case glslang::ElfR8i:
    543 
    544     case glslang::ElfRgb10a2ui:
    545     case glslang::ElfRg32ui:
    546     case glslang::ElfRg16ui:
    547     case glslang::ElfRg8ui:
    548     case glslang::ElfR16ui:
    549     case glslang::ElfR8ui:
    550         builder.addCapability(spv::CapabilityStorageImageExtendedFormats);
    551         break;
    552 
    553     default:
    554         break;
    555     }
    556 
    557     // do the translation
    558     switch (type.getQualifier().layoutFormat) {
    559     case glslang::ElfNone:          return spv::ImageFormatUnknown;
    560     case glslang::ElfRgba32f:       return spv::ImageFormatRgba32f;
    561     case glslang::ElfRgba16f:       return spv::ImageFormatRgba16f;
    562     case glslang::ElfR32f:          return spv::ImageFormatR32f;
    563     case glslang::ElfRgba8:         return spv::ImageFormatRgba8;
    564     case glslang::ElfRgba8Snorm:    return spv::ImageFormatRgba8Snorm;
    565     case glslang::ElfRg32f:         return spv::ImageFormatRg32f;
    566     case glslang::ElfRg16f:         return spv::ImageFormatRg16f;
    567     case glslang::ElfR11fG11fB10f:  return spv::ImageFormatR11fG11fB10f;
    568     case glslang::ElfR16f:          return spv::ImageFormatR16f;
    569     case glslang::ElfRgba16:        return spv::ImageFormatRgba16;
    570     case glslang::ElfRgb10A2:       return spv::ImageFormatRgb10A2;
    571     case glslang::ElfRg16:          return spv::ImageFormatRg16;
    572     case glslang::ElfRg8:           return spv::ImageFormatRg8;
    573     case glslang::ElfR16:           return spv::ImageFormatR16;
    574     case glslang::ElfR8:            return spv::ImageFormatR8;
    575     case glslang::ElfRgba16Snorm:   return spv::ImageFormatRgba16Snorm;
    576     case glslang::ElfRg16Snorm:     return spv::ImageFormatRg16Snorm;
    577     case glslang::ElfRg8Snorm:      return spv::ImageFormatRg8Snorm;
    578     case glslang::ElfR16Snorm:      return spv::ImageFormatR16Snorm;
    579     case glslang::ElfR8Snorm:       return spv::ImageFormatR8Snorm;
    580     case glslang::ElfRgba32i:       return spv::ImageFormatRgba32i;
    581     case glslang::ElfRgba16i:       return spv::ImageFormatRgba16i;
    582     case glslang::ElfRgba8i:        return spv::ImageFormatRgba8i;
    583     case glslang::ElfR32i:          return spv::ImageFormatR32i;
    584     case glslang::ElfRg32i:         return spv::ImageFormatRg32i;
    585     case glslang::ElfRg16i:         return spv::ImageFormatRg16i;
    586     case glslang::ElfRg8i:          return spv::ImageFormatRg8i;
    587     case glslang::ElfR16i:          return spv::ImageFormatR16i;
    588     case glslang::ElfR8i:           return spv::ImageFormatR8i;
    589     case glslang::ElfRgba32ui:      return spv::ImageFormatRgba32ui;
    590     case glslang::ElfRgba16ui:      return spv::ImageFormatRgba16ui;
    591     case glslang::ElfRgba8ui:       return spv::ImageFormatRgba8ui;
    592     case glslang::ElfR32ui:         return spv::ImageFormatR32ui;
    593     case glslang::ElfRg32ui:        return spv::ImageFormatRg32ui;
    594     case glslang::ElfRg16ui:        return spv::ImageFormatRg16ui;
    595     case glslang::ElfRgb10a2ui:     return spv::ImageFormatRgb10a2ui;
    596     case glslang::ElfRg8ui:         return spv::ImageFormatRg8ui;
    597     case glslang::ElfR16ui:         return spv::ImageFormatR16ui;
    598     case glslang::ElfR8ui:          return spv::ImageFormatR8ui;
    599     default:                        return spv::ImageFormatMax;
    600     }
    601 }
    602 
    603 // Return whether or not the given type is something that should be tied to a
    604 // descriptor set.
    605 bool IsDescriptorResource(const glslang::TType& type)
    606 {
    607     // uniform and buffer blocks are included, unless it is a push_constant
    608     if (type.getBasicType() == glslang::EbtBlock)
    609         return type.getQualifier().isUniformOrBuffer() && ! type.getQualifier().layoutPushConstant;
    610 
    611     // non block...
    612     // basically samplerXXX/subpass/sampler/texture are all included
    613     // if they are the global-scope-class, not the function parameter
    614     // (or local, if they ever exist) class.
    615     if (type.getBasicType() == glslang::EbtSampler)
    616         return type.getQualifier().isUniformOrBuffer();
    617 
    618     // None of the above.
    619     return false;
    620 }
    621 
    622 void InheritQualifiers(glslang::TQualifier& child, const glslang::TQualifier& parent)
    623 {
    624     if (child.layoutMatrix == glslang::ElmNone)
    625         child.layoutMatrix = parent.layoutMatrix;
    626 
    627     if (parent.invariant)
    628         child.invariant = true;
    629     if (parent.nopersp)
    630         child.nopersp = true;
    631     if (parent.flat)
    632         child.flat = true;
    633     if (parent.centroid)
    634         child.centroid = true;
    635     if (parent.patch)
    636         child.patch = true;
    637     if (parent.sample)
    638         child.sample = true;
    639     if (parent.coherent)
    640         child.coherent = true;
    641     if (parent.volatil)
    642         child.volatil = true;
    643     if (parent.restrict)
    644         child.restrict = true;
    645     if (parent.readonly)
    646         child.readonly = true;
    647     if (parent.writeonly)
    648         child.writeonly = true;
    649 }
    650 
    651 bool HasNonLayoutQualifiers(const glslang::TQualifier& qualifier)
    652 {
    653     // This should list qualifiers that simultaneous satisfy:
    654     // - struct members can inherit from a struct declaration
    655     // - affect decorations on the struct members (note smooth does not, and expecting something like volatile to effect the whole object)
    656     // - are not part of the offset/st430/etc or row/column-major layout
    657     return qualifier.invariant || qualifier.hasLocation();
    658 }
    659 
    660 //
    661 // Implement the TGlslangToSpvTraverser class.
    662 //
    663 
    664 TGlslangToSpvTraverser::TGlslangToSpvTraverser(const glslang::TIntermediate* glslangIntermediate, spv::SpvBuildLogger* buildLogger)
    665     : TIntermTraverser(true, false, true), shaderEntry(0), sequenceDepth(0), logger(buildLogger),
    666       builder((glslang::GetKhronosToolId() << 16) | GeneratorVersion, logger),
    667       inMain(false), mainTerminated(false), linkageOnly(false),
    668       glslangIntermediate(glslangIntermediate)
    669 {
    670     spv::ExecutionModel executionModel = TranslateExecutionModel(glslangIntermediate->getStage());
    671 
    672     builder.clearAccessChain();
    673     builder.setSource(TranslateSourceLanguage(glslangIntermediate->getSource(), glslangIntermediate->getProfile()), glslangIntermediate->getVersion());
    674     stdBuiltins = builder.import("GLSL.std.450");
    675     builder.setMemoryModel(spv::AddressingModelLogical, spv::MemoryModelGLSL450);
    676     shaderEntry = builder.makeEntrypoint(glslangIntermediate->getEntryPoint().c_str());
    677     entryPoint = builder.addEntryPoint(executionModel, shaderEntry, glslangIntermediate->getEntryPoint().c_str());
    678 
    679     // Add the source extensions
    680     const auto& sourceExtensions = glslangIntermediate->getRequestedExtensions();
    681     for (auto it = sourceExtensions.begin(); it != sourceExtensions.end(); ++it)
    682         builder.addSourceExtension(it->c_str());
    683 
    684     // Add the top-level modes for this shader.
    685 
    686     if (glslangIntermediate->getXfbMode()) {
    687         builder.addCapability(spv::CapabilityTransformFeedback);
    688         builder.addExecutionMode(shaderEntry, spv::ExecutionModeXfb);
    689     }
    690 
    691     unsigned int mode;
    692     switch (glslangIntermediate->getStage()) {
    693     case EShLangVertex:
    694         builder.addCapability(spv::CapabilityShader);
    695         break;
    696 
    697     case EShLangTessControl:
    698         builder.addCapability(spv::CapabilityTessellation);
    699         builder.addExecutionMode(shaderEntry, spv::ExecutionModeOutputVertices, glslangIntermediate->getVertices());
    700         break;
    701 
    702     case EShLangTessEvaluation:
    703         builder.addCapability(spv::CapabilityTessellation);
    704         switch (glslangIntermediate->getInputPrimitive()) {
    705         case glslang::ElgTriangles:           mode = spv::ExecutionModeTriangles;     break;
    706         case glslang::ElgQuads:               mode = spv::ExecutionModeQuads;         break;
    707         case glslang::ElgIsolines:            mode = spv::ExecutionModeIsolines;      break;
    708         default:                              mode = spv::ExecutionModeMax;           break;
    709         }
    710         if (mode != spv::ExecutionModeMax)
    711             builder.addExecutionMode(shaderEntry, (spv::ExecutionMode)mode);
    712 
    713         switch (glslangIntermediate->getVertexSpacing()) {
    714         case glslang::EvsEqual:            mode = spv::ExecutionModeSpacingEqual;          break;
    715         case glslang::EvsFractionalEven:   mode = spv::ExecutionModeSpacingFractionalEven; break;
    716         case glslang::EvsFractionalOdd:    mode = spv::ExecutionModeSpacingFractionalOdd;  break;
    717         default:                           mode = spv::ExecutionModeMax;                   break;
    718         }
    719         if (mode != spv::ExecutionModeMax)
    720             builder.addExecutionMode(shaderEntry, (spv::ExecutionMode)mode);
    721 
    722         switch (glslangIntermediate->getVertexOrder()) {
    723         case glslang::EvoCw:     mode = spv::ExecutionModeVertexOrderCw;  break;
    724         case glslang::EvoCcw:    mode = spv::ExecutionModeVertexOrderCcw; break;
    725         default:                 mode = spv::ExecutionModeMax;            break;
    726         }
    727         if (mode != spv::ExecutionModeMax)
    728             builder.addExecutionMode(shaderEntry, (spv::ExecutionMode)mode);
    729 
    730         if (glslangIntermediate->getPointMode())
    731             builder.addExecutionMode(shaderEntry, spv::ExecutionModePointMode);
    732         break;
    733 
    734     case EShLangGeometry:
    735         builder.addCapability(spv::CapabilityGeometry);
    736         switch (glslangIntermediate->getInputPrimitive()) {
    737         case glslang::ElgPoints:             mode = spv::ExecutionModeInputPoints;             break;
    738         case glslang::ElgLines:              mode = spv::ExecutionModeInputLines;              break;
    739         case glslang::ElgLinesAdjacency:     mode = spv::ExecutionModeInputLinesAdjacency;     break;
    740         case glslang::ElgTriangles:          mode = spv::ExecutionModeTriangles;               break;
    741         case glslang::ElgTrianglesAdjacency: mode = spv::ExecutionModeInputTrianglesAdjacency; break;
    742         default:                             mode = spv::ExecutionModeMax;                     break;
    743         }
    744         if (mode != spv::ExecutionModeMax)
    745             builder.addExecutionMode(shaderEntry, (spv::ExecutionMode)mode);
    746 
    747         builder.addExecutionMode(shaderEntry, spv::ExecutionModeInvocations, glslangIntermediate->getInvocations());
    748 
    749         switch (glslangIntermediate->getOutputPrimitive()) {
    750         case glslang::ElgPoints:        mode = spv::ExecutionModeOutputPoints;                 break;
    751         case glslang::ElgLineStrip:     mode = spv::ExecutionModeOutputLineStrip;              break;
    752         case glslang::ElgTriangleStrip: mode = spv::ExecutionModeOutputTriangleStrip;          break;
    753         default:                        mode = spv::ExecutionModeMax;                          break;
    754         }
    755         if (mode != spv::ExecutionModeMax)
    756             builder.addExecutionMode(shaderEntry, (spv::ExecutionMode)mode);
    757         builder.addExecutionMode(shaderEntry, spv::ExecutionModeOutputVertices, glslangIntermediate->getVertices());
    758         break;
    759 
    760     case EShLangFragment:
    761         builder.addCapability(spv::CapabilityShader);
    762         if (glslangIntermediate->getPixelCenterInteger())
    763             builder.addExecutionMode(shaderEntry, spv::ExecutionModePixelCenterInteger);
    764 
    765         if (glslangIntermediate->getOriginUpperLeft())
    766             builder.addExecutionMode(shaderEntry, spv::ExecutionModeOriginUpperLeft);
    767         else
    768             builder.addExecutionMode(shaderEntry, spv::ExecutionModeOriginLowerLeft);
    769 
    770         if (glslangIntermediate->getEarlyFragmentTests())
    771             builder.addExecutionMode(shaderEntry, spv::ExecutionModeEarlyFragmentTests);
    772 
    773         switch(glslangIntermediate->getDepth()) {
    774         case glslang::EldGreater:  mode = spv::ExecutionModeDepthGreater; break;
    775         case glslang::EldLess:     mode = spv::ExecutionModeDepthLess;    break;
    776         default:                   mode = spv::ExecutionModeMax;          break;
    777         }
    778         if (mode != spv::ExecutionModeMax)
    779             builder.addExecutionMode(shaderEntry, (spv::ExecutionMode)mode);
    780 
    781         if (glslangIntermediate->getDepth() != glslang::EldUnchanged && glslangIntermediate->isDepthReplacing())
    782             builder.addExecutionMode(shaderEntry, spv::ExecutionModeDepthReplacing);
    783         break;
    784 
    785     case EShLangCompute:
    786         builder.addCapability(spv::CapabilityShader);
    787         builder.addExecutionMode(shaderEntry, spv::ExecutionModeLocalSize, glslangIntermediate->getLocalSize(0),
    788                                                                            glslangIntermediate->getLocalSize(1),
    789                                                                            glslangIntermediate->getLocalSize(2));
    790         break;
    791 
    792     default:
    793         break;
    794     }
    795 
    796 }
    797 
    798 // Finish everything and dump
    799 void TGlslangToSpvTraverser::dumpSpv(std::vector<unsigned int>& out)
    800 {
    801     // finish off the entry-point SPV instruction by adding the Input/Output <id>
    802     for (auto it = iOSet.cbegin(); it != iOSet.cend(); ++it)
    803         entryPoint->addIdOperand(*it);
    804 
    805     builder.eliminateDeadDecorations();
    806     builder.dump(out);
    807 }
    808 
    809 TGlslangToSpvTraverser::~TGlslangToSpvTraverser()
    810 {
    811     if (! mainTerminated) {
    812         spv::Block* lastMainBlock = shaderEntry->getLastBlock();
    813         builder.setBuildPoint(lastMainBlock);
    814         builder.leaveFunction();
    815     }
    816 }
    817 
    818 //
    819 // Implement the traversal functions.
    820 //
    821 // Return true from interior nodes to have the external traversal
    822 // continue on to children.  Return false if children were
    823 // already processed.
    824 //
    825 
    826 //
    827 // Symbols can turn into
    828 //  - uniform/input reads
    829 //  - output writes
    830 //  - complex lvalue base setups:  foo.bar[3]....  , where we see foo and start up an access chain
    831 //  - something simple that degenerates into the last bullet
    832 //
    833 void TGlslangToSpvTraverser::visitSymbol(glslang::TIntermSymbol* symbol)
    834 {
    835     SpecConstantOpModeGuard spec_constant_op_mode_setter(&builder);
    836     if (symbol->getType().getQualifier().isSpecConstant())
    837         spec_constant_op_mode_setter.turnOnSpecConstantOpMode();
    838 
    839     // getSymbolId() will set up all the IO decorations on the first call.
    840     // Formal function parameters were mapped during makeFunctions().
    841     spv::Id id = getSymbolId(symbol);
    842 
    843     // Include all "static use" and "linkage only" interface variables on the OpEntryPoint instruction
    844     if (builder.isPointer(id)) {
    845         spv::StorageClass sc = builder.getStorageClass(id);
    846         if (sc == spv::StorageClassInput || sc == spv::StorageClassOutput)
    847             iOSet.insert(id);
    848     }
    849 
    850     // Only process non-linkage-only nodes for generating actual static uses
    851     if (! linkageOnly || symbol->getQualifier().isSpecConstant()) {
    852         // Prepare to generate code for the access
    853 
    854         // L-value chains will be computed left to right.  We're on the symbol now,
    855         // which is the left-most part of the access chain, so now is "clear" time,
    856         // followed by setting the base.
    857         builder.clearAccessChain();
    858 
    859         // For now, we consider all user variables as being in memory, so they are pointers,
    860         // except for
    861         // A) "const in" arguments to a function, which are an intermediate object.
    862         //    See comments in handleUserFunctionCall().
    863         // B) Specialization constants (normal constant don't even come in as a variable),
    864         //    These are also pure R-values.
    865         glslang::TQualifier qualifier = symbol->getQualifier();
    866         if ((qualifier.storage == glslang::EvqConstReadOnly && constReadOnlyParameters.find(symbol->getId()) != constReadOnlyParameters.end()) ||
    867              qualifier.isSpecConstant())
    868             builder.setAccessChainRValue(id);
    869         else
    870             builder.setAccessChainLValue(id);
    871     }
    872 }
    873 
    874 bool TGlslangToSpvTraverser::visitBinary(glslang::TVisit /* visit */, glslang::TIntermBinary* node)
    875 {
    876     SpecConstantOpModeGuard spec_constant_op_mode_setter(&builder);
    877     if (node->getType().getQualifier().isSpecConstant())
    878         spec_constant_op_mode_setter.turnOnSpecConstantOpMode();
    879 
    880     // First, handle special cases
    881     switch (node->getOp()) {
    882     case glslang::EOpAssign:
    883     case glslang::EOpAddAssign:
    884     case glslang::EOpSubAssign:
    885     case glslang::EOpMulAssign:
    886     case glslang::EOpVectorTimesMatrixAssign:
    887     case glslang::EOpVectorTimesScalarAssign:
    888     case glslang::EOpMatrixTimesScalarAssign:
    889     case glslang::EOpMatrixTimesMatrixAssign:
    890     case glslang::EOpDivAssign:
    891     case glslang::EOpModAssign:
    892     case glslang::EOpAndAssign:
    893     case glslang::EOpInclusiveOrAssign:
    894     case glslang::EOpExclusiveOrAssign:
    895     case glslang::EOpLeftShiftAssign:
    896     case glslang::EOpRightShiftAssign:
    897         // A bin-op assign "a += b" means the same thing as "a = a + b"
    898         // where a is evaluated before b. For a simple assignment, GLSL
    899         // says to evaluate the left before the right.  So, always, left
    900         // node then right node.
    901         {
    902             // get the left l-value, save it away
    903             builder.clearAccessChain();
    904             node->getLeft()->traverse(this);
    905             spv::Builder::AccessChain lValue = builder.getAccessChain();
    906 
    907             // evaluate the right
    908             builder.clearAccessChain();
    909             node->getRight()->traverse(this);
    910             spv::Id rValue = accessChainLoad(node->getRight()->getType());
    911 
    912             if (node->getOp() != glslang::EOpAssign) {
    913                 // the left is also an r-value
    914                 builder.setAccessChain(lValue);
    915                 spv::Id leftRValue = accessChainLoad(node->getLeft()->getType());
    916 
    917                 // do the operation
    918                 rValue = createBinaryOperation(node->getOp(), TranslatePrecisionDecoration(node->getType()),
    919                                                TranslateNoContractionDecoration(node->getType().getQualifier()),
    920                                                convertGlslangToSpvType(node->getType()), leftRValue, rValue,
    921                                                node->getType().getBasicType());
    922 
    923                 // these all need their counterparts in createBinaryOperation()
    924                 assert(rValue != spv::NoResult);
    925             }
    926 
    927             // store the result
    928             builder.setAccessChain(lValue);
    929             accessChainStore(node->getType(), rValue);
    930 
    931             // assignments are expressions having an rValue after they are evaluated...
    932             builder.clearAccessChain();
    933             builder.setAccessChainRValue(rValue);
    934         }
    935         return false;
    936     case glslang::EOpIndexDirect:
    937     case glslang::EOpIndexDirectStruct:
    938         {
    939             // Get the left part of the access chain.
    940             node->getLeft()->traverse(this);
    941 
    942             // Add the next element in the chain
    943 
    944             const int glslangIndex = node->getRight()->getAsConstantUnion()->getConstArray()[0].getIConst();
    945             if (! node->getLeft()->getType().isArray() &&
    946                 node->getLeft()->getType().isVector() &&
    947                 node->getOp() == glslang::EOpIndexDirect) {
    948                 // This is essentially a hard-coded vector swizzle of size 1,
    949                 // so short circuit the access-chain stuff with a swizzle.
    950                 std::vector<unsigned> swizzle;
    951                 swizzle.push_back(glslangIndex);
    952                 builder.accessChainPushSwizzle(swizzle, convertGlslangToSpvType(node->getLeft()->getType()));
    953             } else {
    954                 int spvIndex = glslangIndex;
    955                 if (node->getLeft()->getBasicType() == glslang::EbtBlock &&
    956                     node->getOp() == glslang::EOpIndexDirectStruct)
    957                 {
    958                     // This may be, e.g., an anonymous block-member selection, which generally need
    959                     // index remapping due to hidden members in anonymous blocks.
    960                     std::vector<int>& remapper = memberRemapper[node->getLeft()->getType().getStruct()];
    961                     assert(remapper.size() > 0);
    962                     spvIndex = remapper[glslangIndex];
    963                 }
    964 
    965                 // normal case for indexing array or structure or block
    966                 builder.accessChainPush(builder.makeIntConstant(spvIndex));
    967 
    968                 // Add capabilities here for accessing PointSize and clip/cull distance.
    969                 // We have deferred generation of associated capabilities until now.
    970                 if (node->getLeft()->getType().isStruct() && ! node->getLeft()->getType().isArray())
    971                     declareUseOfStructMember(*(node->getLeft()->getType().getStruct()), glslangIndex);
    972             }
    973         }
    974         return false;
    975     case glslang::EOpIndexIndirect:
    976         {
    977             // Structure or array or vector indirection.
    978             // Will use native SPIR-V access-chain for struct and array indirection;
    979             // matrices are arrays of vectors, so will also work for a matrix.
    980             // Will use the access chain's 'component' for variable index into a vector.
    981 
    982             // This adapter is building access chains left to right.
    983             // Set up the access chain to the left.
    984             node->getLeft()->traverse(this);
    985 
    986             // save it so that computing the right side doesn't trash it
    987             spv::Builder::AccessChain partial = builder.getAccessChain();
    988 
    989             // compute the next index in the chain
    990             builder.clearAccessChain();
    991             node->getRight()->traverse(this);
    992             spv::Id index = accessChainLoad(node->getRight()->getType());
    993 
    994             // restore the saved access chain
    995             builder.setAccessChain(partial);
    996 
    997             if (! node->getLeft()->getType().isArray() && node->getLeft()->getType().isVector())
    998                 builder.accessChainPushComponent(index, convertGlslangToSpvType(node->getLeft()->getType()));
    999             else
   1000                 builder.accessChainPush(index);
   1001         }
   1002         return false;
   1003     case glslang::EOpVectorSwizzle:
   1004         {
   1005             node->getLeft()->traverse(this);
   1006             glslang::TIntermSequence& swizzleSequence = node->getRight()->getAsAggregate()->getSequence();
   1007             std::vector<unsigned> swizzle;
   1008             for (int i = 0; i < (int)swizzleSequence.size(); ++i)
   1009                 swizzle.push_back(swizzleSequence[i]->getAsConstantUnion()->getConstArray()[0].getIConst());
   1010             builder.accessChainPushSwizzle(swizzle, convertGlslangToSpvType(node->getLeft()->getType()));
   1011         }
   1012         return false;
   1013     case glslang::EOpLogicalOr:
   1014     case glslang::EOpLogicalAnd:
   1015         {
   1016 
   1017             // These may require short circuiting, but can sometimes be done as straight
   1018             // binary operations.  The right operand must be short circuited if it has
   1019             // side effects, and should probably be if it is complex.
   1020             if (isTrivial(node->getRight()->getAsTyped()))
   1021                 break; // handle below as a normal binary operation
   1022             // otherwise, we need to do dynamic short circuiting on the right operand
   1023             spv::Id result = createShortCircuit(node->getOp(), *node->getLeft()->getAsTyped(), *node->getRight()->getAsTyped());
   1024             builder.clearAccessChain();
   1025             builder.setAccessChainRValue(result);
   1026         }
   1027         return false;
   1028     default:
   1029         break;
   1030     }
   1031 
   1032     // Assume generic binary op...
   1033 
   1034     // get right operand
   1035     builder.clearAccessChain();
   1036     node->getLeft()->traverse(this);
   1037     spv::Id left = accessChainLoad(node->getLeft()->getType());
   1038 
   1039     // get left operand
   1040     builder.clearAccessChain();
   1041     node->getRight()->traverse(this);
   1042     spv::Id right = accessChainLoad(node->getRight()->getType());
   1043 
   1044     // get result
   1045     spv::Id result = createBinaryOperation(node->getOp(), TranslatePrecisionDecoration(node->getType()),
   1046                                            TranslateNoContractionDecoration(node->getType().getQualifier()),
   1047                                            convertGlslangToSpvType(node->getType()), left, right,
   1048                                            node->getLeft()->getType().getBasicType());
   1049 
   1050     builder.clearAccessChain();
   1051     if (! result) {
   1052         logger->missingFunctionality("unknown glslang binary operation");
   1053         return true;  // pick up a child as the place-holder result
   1054     } else {
   1055         builder.setAccessChainRValue(result);
   1056         return false;
   1057     }
   1058 }
   1059 
   1060 bool TGlslangToSpvTraverser::visitUnary(glslang::TVisit /* visit */, glslang::TIntermUnary* node)
   1061 {
   1062     SpecConstantOpModeGuard spec_constant_op_mode_setter(&builder);
   1063     if (node->getType().getQualifier().isSpecConstant())
   1064         spec_constant_op_mode_setter.turnOnSpecConstantOpMode();
   1065 
   1066     spv::Id result = spv::NoResult;
   1067 
   1068     // try texturing first
   1069     result = createImageTextureFunctionCall(node);
   1070     if (result != spv::NoResult) {
   1071         builder.clearAccessChain();
   1072         builder.setAccessChainRValue(result);
   1073 
   1074         return false; // done with this node
   1075     }
   1076 
   1077     // Non-texturing.
   1078 
   1079     if (node->getOp() == glslang::EOpArrayLength) {
   1080         // Quite special; won't want to evaluate the operand.
   1081 
   1082         // Normal .length() would have been constant folded by the front-end.
   1083         // So, this has to be block.lastMember.length().
   1084         // SPV wants "block" and member number as the operands, go get them.
   1085         assert(node->getOperand()->getType().isRuntimeSizedArray());
   1086         glslang::TIntermTyped* block = node->getOperand()->getAsBinaryNode()->getLeft();
   1087         block->traverse(this);
   1088         unsigned int member = node->getOperand()->getAsBinaryNode()->getRight()->getAsConstantUnion()->getConstArray()[0].getUConst();
   1089         spv::Id length = builder.createArrayLength(builder.accessChainGetLValue(), member);
   1090 
   1091         builder.clearAccessChain();
   1092         builder.setAccessChainRValue(length);
   1093 
   1094         return false;
   1095     }
   1096 
   1097     // Start by evaluating the operand
   1098 
   1099     builder.clearAccessChain();
   1100     node->getOperand()->traverse(this);
   1101 
   1102     spv::Id operand = spv::NoResult;
   1103 
   1104     if (node->getOp() == glslang::EOpAtomicCounterIncrement ||
   1105         node->getOp() == glslang::EOpAtomicCounterDecrement ||
   1106         node->getOp() == glslang::EOpAtomicCounter          ||
   1107         node->getOp() == glslang::EOpInterpolateAtCentroid)
   1108         operand = builder.accessChainGetLValue(); // Special case l-value operands
   1109     else
   1110         operand = accessChainLoad(node->getOperand()->getType());
   1111 
   1112     spv::Decoration precision = TranslatePrecisionDecoration(node->getType());
   1113     spv::Decoration noContraction = TranslateNoContractionDecoration(node->getType().getQualifier());
   1114 
   1115     // it could be a conversion
   1116     if (! result)
   1117         result = createConversion(node->getOp(), precision, noContraction, convertGlslangToSpvType(node->getType()), operand, node->getOperand()->getBasicType());
   1118 
   1119     // if not, then possibly an operation
   1120     if (! result)
   1121         result = createUnaryOperation(node->getOp(), precision, noContraction, convertGlslangToSpvType(node->getType()), operand, node->getOperand()->getBasicType());
   1122 
   1123     if (result) {
   1124         builder.clearAccessChain();
   1125         builder.setAccessChainRValue(result);
   1126 
   1127         return false; // done with this node
   1128     }
   1129 
   1130     // it must be a special case, check...
   1131     switch (node->getOp()) {
   1132     case glslang::EOpPostIncrement:
   1133     case glslang::EOpPostDecrement:
   1134     case glslang::EOpPreIncrement:
   1135     case glslang::EOpPreDecrement:
   1136         {
   1137             // we need the integer value "1" or the floating point "1.0" to add/subtract
   1138             spv::Id one = 0;
   1139             if (node->getBasicType() == glslang::EbtFloat)
   1140                 one = builder.makeFloatConstant(1.0F);
   1141             else if (node->getBasicType() == glslang::EbtInt64 || node->getBasicType() == glslang::EbtUint64)
   1142                 one = builder.makeInt64Constant(1);
   1143             else
   1144                 one = builder.makeIntConstant(1);
   1145             glslang::TOperator op;
   1146             if (node->getOp() == glslang::EOpPreIncrement ||
   1147                 node->getOp() == glslang::EOpPostIncrement)
   1148                 op = glslang::EOpAdd;
   1149             else
   1150                 op = glslang::EOpSub;
   1151 
   1152             spv::Id result = createBinaryOperation(op, TranslatePrecisionDecoration(node->getType()),
   1153                                                    TranslateNoContractionDecoration(node->getType().getQualifier()),
   1154                                                    convertGlslangToSpvType(node->getType()), operand, one,
   1155                                                    node->getType().getBasicType());
   1156             assert(result != spv::NoResult);
   1157 
   1158             // The result of operation is always stored, but conditionally the
   1159             // consumed result.  The consumed result is always an r-value.
   1160             builder.accessChainStore(result);
   1161             builder.clearAccessChain();
   1162             if (node->getOp() == glslang::EOpPreIncrement ||
   1163                 node->getOp() == glslang::EOpPreDecrement)
   1164                 builder.setAccessChainRValue(result);
   1165             else
   1166                 builder.setAccessChainRValue(operand);
   1167         }
   1168 
   1169         return false;
   1170 
   1171     case glslang::EOpEmitStreamVertex:
   1172         builder.createNoResultOp(spv::OpEmitStreamVertex, operand);
   1173         return false;
   1174     case glslang::EOpEndStreamPrimitive:
   1175         builder.createNoResultOp(spv::OpEndStreamPrimitive, operand);
   1176         return false;
   1177 
   1178     default:
   1179         logger->missingFunctionality("unknown glslang unary");
   1180         return true;  // pick up operand as placeholder result
   1181     }
   1182 }
   1183 
   1184 bool TGlslangToSpvTraverser::visitAggregate(glslang::TVisit visit, glslang::TIntermAggregate* node)
   1185 {
   1186     SpecConstantOpModeGuard spec_constant_op_mode_setter(&builder);
   1187     if (node->getType().getQualifier().isSpecConstant())
   1188         spec_constant_op_mode_setter.turnOnSpecConstantOpMode();
   1189 
   1190     spv::Id result = spv::NoResult;
   1191 
   1192     // try texturing
   1193     result = createImageTextureFunctionCall(node);
   1194     if (result != spv::NoResult) {
   1195         builder.clearAccessChain();
   1196         builder.setAccessChainRValue(result);
   1197 
   1198         return false;
   1199     } else if (node->getOp() == glslang::EOpImageStore) {
   1200         // "imageStore" is a special case, which has no result
   1201         return false;
   1202     }
   1203 
   1204     glslang::TOperator binOp = glslang::EOpNull;
   1205     bool reduceComparison = true;
   1206     bool isMatrix = false;
   1207     bool noReturnValue = false;
   1208     bool atomic = false;
   1209 
   1210     assert(node->getOp());
   1211 
   1212     spv::Decoration precision = TranslatePrecisionDecoration(node->getType());
   1213 
   1214     switch (node->getOp()) {
   1215     case glslang::EOpSequence:
   1216     {
   1217         if (preVisit)
   1218             ++sequenceDepth;
   1219         else
   1220             --sequenceDepth;
   1221 
   1222         if (sequenceDepth == 1) {
   1223             // If this is the parent node of all the functions, we want to see them
   1224             // early, so all call points have actual SPIR-V functions to reference.
   1225             // In all cases, still let the traverser visit the children for us.
   1226             makeFunctions(node->getAsAggregate()->getSequence());
   1227 
   1228             // Also, we want all globals initializers to go into the entry of main(), before
   1229             // anything else gets there, so visit out of order, doing them all now.
   1230             makeGlobalInitializers(node->getAsAggregate()->getSequence());
   1231 
   1232             // Initializers are done, don't want to visit again, but functions link objects need to be processed,
   1233             // so do them manually.
   1234             visitFunctions(node->getAsAggregate()->getSequence());
   1235 
   1236             return false;
   1237         }
   1238 
   1239         return true;
   1240     }
   1241     case glslang::EOpLinkerObjects:
   1242     {
   1243         if (visit == glslang::EvPreVisit)
   1244             linkageOnly = true;
   1245         else
   1246             linkageOnly = false;
   1247 
   1248         return true;
   1249     }
   1250     case glslang::EOpComma:
   1251     {
   1252         // processing from left to right naturally leaves the right-most
   1253         // lying around in the access chain
   1254         glslang::TIntermSequence& glslangOperands = node->getSequence();
   1255         for (int i = 0; i < (int)glslangOperands.size(); ++i)
   1256             glslangOperands[i]->traverse(this);
   1257 
   1258         return false;
   1259     }
   1260     case glslang::EOpFunction:
   1261         if (visit == glslang::EvPreVisit) {
   1262             if (isShaderEntrypoint(node)) {
   1263                 inMain = true;
   1264                 builder.setBuildPoint(shaderEntry->getLastBlock());
   1265             } else {
   1266                 handleFunctionEntry(node);
   1267             }
   1268         } else {
   1269             if (inMain)
   1270                 mainTerminated = true;
   1271             builder.leaveFunction();
   1272             inMain = false;
   1273         }
   1274 
   1275         return true;
   1276     case glslang::EOpParameters:
   1277         // Parameters will have been consumed by EOpFunction processing, but not
   1278         // the body, so we still visited the function node's children, making this
   1279         // child redundant.
   1280         return false;
   1281     case glslang::EOpFunctionCall:
   1282     {
   1283         if (node->isUserDefined())
   1284             result = handleUserFunctionCall(node);
   1285         //assert(result);  // this can happen for bad shaders because the call graph completeness checking is not yet done
   1286         if (result) {
   1287             builder.clearAccessChain();
   1288             builder.setAccessChainRValue(result);
   1289         } else
   1290             logger->missingFunctionality("missing user function; linker needs to catch that");
   1291 
   1292         return false;
   1293     }
   1294     case glslang::EOpConstructMat2x2:
   1295     case glslang::EOpConstructMat2x3:
   1296     case glslang::EOpConstructMat2x4:
   1297     case glslang::EOpConstructMat3x2:
   1298     case glslang::EOpConstructMat3x3:
   1299     case glslang::EOpConstructMat3x4:
   1300     case glslang::EOpConstructMat4x2:
   1301     case glslang::EOpConstructMat4x3:
   1302     case glslang::EOpConstructMat4x4:
   1303     case glslang::EOpConstructDMat2x2:
   1304     case glslang::EOpConstructDMat2x3:
   1305     case glslang::EOpConstructDMat2x4:
   1306     case glslang::EOpConstructDMat3x2:
   1307     case glslang::EOpConstructDMat3x3:
   1308     case glslang::EOpConstructDMat3x4:
   1309     case glslang::EOpConstructDMat4x2:
   1310     case glslang::EOpConstructDMat4x3:
   1311     case glslang::EOpConstructDMat4x4:
   1312         isMatrix = true;
   1313         // fall through
   1314     case glslang::EOpConstructFloat:
   1315     case glslang::EOpConstructVec2:
   1316     case glslang::EOpConstructVec3:
   1317     case glslang::EOpConstructVec4:
   1318     case glslang::EOpConstructDouble:
   1319     case glslang::EOpConstructDVec2:
   1320     case glslang::EOpConstructDVec3:
   1321     case glslang::EOpConstructDVec4:
   1322     case glslang::EOpConstructBool:
   1323     case glslang::EOpConstructBVec2:
   1324     case glslang::EOpConstructBVec3:
   1325     case glslang::EOpConstructBVec4:
   1326     case glslang::EOpConstructInt:
   1327     case glslang::EOpConstructIVec2:
   1328     case glslang::EOpConstructIVec3:
   1329     case glslang::EOpConstructIVec4:
   1330     case glslang::EOpConstructUint:
   1331     case glslang::EOpConstructUVec2:
   1332     case glslang::EOpConstructUVec3:
   1333     case glslang::EOpConstructUVec4:
   1334     case glslang::EOpConstructInt64:
   1335     case glslang::EOpConstructI64Vec2:
   1336     case glslang::EOpConstructI64Vec3:
   1337     case glslang::EOpConstructI64Vec4:
   1338     case glslang::EOpConstructUint64:
   1339     case glslang::EOpConstructU64Vec2:
   1340     case glslang::EOpConstructU64Vec3:
   1341     case glslang::EOpConstructU64Vec4:
   1342     case glslang::EOpConstructStruct:
   1343     case glslang::EOpConstructTextureSampler:
   1344     {
   1345         std::vector<spv::Id> arguments;
   1346         translateArguments(*node, arguments);
   1347         spv::Id resultTypeId = convertGlslangToSpvType(node->getType());
   1348         spv::Id constructed;
   1349         if (node->getOp() == glslang::EOpConstructTextureSampler)
   1350             constructed = builder.createOp(spv::OpSampledImage, resultTypeId, arguments);
   1351         else if (node->getOp() == glslang::EOpConstructStruct || node->getType().isArray()) {
   1352             std::vector<spv::Id> constituents;
   1353             for (int c = 0; c < (int)arguments.size(); ++c)
   1354                 constituents.push_back(arguments[c]);
   1355             constructed = builder.createCompositeConstruct(resultTypeId, constituents);
   1356         } else if (isMatrix)
   1357             constructed = builder.createMatrixConstructor(precision, arguments, resultTypeId);
   1358         else
   1359             constructed = builder.createConstructor(precision, arguments, resultTypeId);
   1360 
   1361         builder.clearAccessChain();
   1362         builder.setAccessChainRValue(constructed);
   1363 
   1364         return false;
   1365     }
   1366 
   1367     // These six are component-wise compares with component-wise results.
   1368     // Forward on to createBinaryOperation(), requesting a vector result.
   1369     case glslang::EOpLessThan:
   1370     case glslang::EOpGreaterThan:
   1371     case glslang::EOpLessThanEqual:
   1372     case glslang::EOpGreaterThanEqual:
   1373     case glslang::EOpVectorEqual:
   1374     case glslang::EOpVectorNotEqual:
   1375     {
   1376         // Map the operation to a binary
   1377         binOp = node->getOp();
   1378         reduceComparison = false;
   1379         switch (node->getOp()) {
   1380         case glslang::EOpVectorEqual:     binOp = glslang::EOpVectorEqual;      break;
   1381         case glslang::EOpVectorNotEqual:  binOp = glslang::EOpVectorNotEqual;   break;
   1382         default:                          binOp = node->getOp();                break;
   1383         }
   1384 
   1385         break;
   1386     }
   1387     case glslang::EOpMul:
   1388         // compontent-wise matrix multiply
   1389         binOp = glslang::EOpMul;
   1390         break;
   1391     case glslang::EOpOuterProduct:
   1392         // two vectors multiplied to make a matrix
   1393         binOp = glslang::EOpOuterProduct;
   1394         break;
   1395     case glslang::EOpDot:
   1396     {
   1397         // for scalar dot product, use multiply
   1398         glslang::TIntermSequence& glslangOperands = node->getSequence();
   1399         if (glslangOperands[0]->getAsTyped()->getVectorSize() == 1)
   1400             binOp = glslang::EOpMul;
   1401         break;
   1402     }
   1403     case glslang::EOpMod:
   1404         // when an aggregate, this is the floating-point mod built-in function,
   1405         // which can be emitted by the one in createBinaryOperation()
   1406         binOp = glslang::EOpMod;
   1407         break;
   1408     case glslang::EOpEmitVertex:
   1409     case glslang::EOpEndPrimitive:
   1410     case glslang::EOpBarrier:
   1411     case glslang::EOpMemoryBarrier:
   1412     case glslang::EOpMemoryBarrierAtomicCounter:
   1413     case glslang::EOpMemoryBarrierBuffer:
   1414     case glslang::EOpMemoryBarrierImage:
   1415     case glslang::EOpMemoryBarrierShared:
   1416     case glslang::EOpGroupMemoryBarrier:
   1417     case glslang::EOpAllMemoryBarrierWithGroupSync:
   1418     case glslang::EOpGroupMemoryBarrierWithGroupSync:
   1419     case glslang::EOpWorkgroupMemoryBarrier:
   1420     case glslang::EOpWorkgroupMemoryBarrierWithGroupSync:
   1421         noReturnValue = true;
   1422         // These all have 0 operands and will naturally finish up in the code below for 0 operands
   1423         break;
   1424 
   1425     case glslang::EOpAtomicAdd:
   1426     case glslang::EOpAtomicMin:
   1427     case glslang::EOpAtomicMax:
   1428     case glslang::EOpAtomicAnd:
   1429     case glslang::EOpAtomicOr:
   1430     case glslang::EOpAtomicXor:
   1431     case glslang::EOpAtomicExchange:
   1432     case glslang::EOpAtomicCompSwap:
   1433         atomic = true;
   1434         break;
   1435 
   1436     default:
   1437         break;
   1438     }
   1439 
   1440     //
   1441     // See if it maps to a regular operation.
   1442     //
   1443     if (binOp != glslang::EOpNull) {
   1444         glslang::TIntermTyped* left = node->getSequence()[0]->getAsTyped();
   1445         glslang::TIntermTyped* right = node->getSequence()[1]->getAsTyped();
   1446         assert(left && right);
   1447 
   1448         builder.clearAccessChain();
   1449         left->traverse(this);
   1450         spv::Id leftId = accessChainLoad(left->getType());
   1451 
   1452         builder.clearAccessChain();
   1453         right->traverse(this);
   1454         spv::Id rightId = accessChainLoad(right->getType());
   1455 
   1456         result = createBinaryOperation(binOp, precision, TranslateNoContractionDecoration(node->getType().getQualifier()),
   1457                                        convertGlslangToSpvType(node->getType()), leftId, rightId,
   1458                                        left->getType().getBasicType(), reduceComparison);
   1459 
   1460         // code above should only make binOp that exists in createBinaryOperation
   1461         assert(result != spv::NoResult);
   1462         builder.clearAccessChain();
   1463         builder.setAccessChainRValue(result);
   1464 
   1465         return false;
   1466     }
   1467 
   1468     //
   1469     // Create the list of operands.
   1470     //
   1471     glslang::TIntermSequence& glslangOperands = node->getSequence();
   1472     std::vector<spv::Id> operands;
   1473     for (int arg = 0; arg < (int)glslangOperands.size(); ++arg) {
   1474         builder.clearAccessChain();
   1475         glslangOperands[arg]->traverse(this);
   1476 
   1477         // special case l-value operands; there are just a few
   1478         bool lvalue = false;
   1479         switch (node->getOp()) {
   1480         case glslang::EOpFrexp:
   1481         case glslang::EOpModf:
   1482             if (arg == 1)
   1483                 lvalue = true;
   1484             break;
   1485         case glslang::EOpInterpolateAtSample:
   1486         case glslang::EOpInterpolateAtOffset:
   1487             if (arg == 0)
   1488                 lvalue = true;
   1489             break;
   1490         case glslang::EOpAtomicAdd:
   1491         case glslang::EOpAtomicMin:
   1492         case glslang::EOpAtomicMax:
   1493         case glslang::EOpAtomicAnd:
   1494         case glslang::EOpAtomicOr:
   1495         case glslang::EOpAtomicXor:
   1496         case glslang::EOpAtomicExchange:
   1497         case glslang::EOpAtomicCompSwap:
   1498             if (arg == 0)
   1499                 lvalue = true;
   1500             break;
   1501         case glslang::EOpAddCarry:
   1502         case glslang::EOpSubBorrow:
   1503             if (arg == 2)
   1504                 lvalue = true;
   1505             break;
   1506         case glslang::EOpUMulExtended:
   1507         case glslang::EOpIMulExtended:
   1508             if (arg >= 2)
   1509                 lvalue = true;
   1510             break;
   1511         default:
   1512             break;
   1513         }
   1514         if (lvalue)
   1515             operands.push_back(builder.accessChainGetLValue());
   1516         else
   1517             operands.push_back(accessChainLoad(glslangOperands[arg]->getAsTyped()->getType()));
   1518     }
   1519 
   1520     if (atomic) {
   1521         // Handle all atomics
   1522         result = createAtomicOperation(node->getOp(), precision, convertGlslangToSpvType(node->getType()), operands, node->getBasicType());
   1523     } else {
   1524         // Pass through to generic operations.
   1525         switch (glslangOperands.size()) {
   1526         case 0:
   1527             result = createNoArgOperation(node->getOp());
   1528             break;
   1529         case 1:
   1530             result = createUnaryOperation(
   1531                 node->getOp(), precision,
   1532                 TranslateNoContractionDecoration(node->getType().getQualifier()),
   1533                 convertGlslangToSpvType(node->getType()), operands.front(),
   1534                 glslangOperands[0]->getAsTyped()->getBasicType());
   1535             break;
   1536         default:
   1537             result = createMiscOperation(node->getOp(), precision, convertGlslangToSpvType(node->getType()), operands, node->getBasicType());
   1538             break;
   1539         }
   1540     }
   1541 
   1542     if (noReturnValue)
   1543         return false;
   1544 
   1545     if (! result) {
   1546         logger->missingFunctionality("unknown glslang aggregate");
   1547         return true;  // pick up a child as a placeholder operand
   1548     } else {
   1549         builder.clearAccessChain();
   1550         builder.setAccessChainRValue(result);
   1551         return false;
   1552     }
   1553 }
   1554 
   1555 bool TGlslangToSpvTraverser::visitSelection(glslang::TVisit /* visit */, glslang::TIntermSelection* node)
   1556 {
   1557     // This path handles both if-then-else and ?:
   1558     // The if-then-else has a node type of void, while
   1559     // ?: has a non-void node type
   1560     spv::Id result = 0;
   1561     if (node->getBasicType() != glslang::EbtVoid) {
   1562         // don't handle this as just on-the-fly temporaries, because there will be two names
   1563         // and better to leave SSA to later passes
   1564         result = builder.createVariable(spv::StorageClassFunction, convertGlslangToSpvType(node->getType()));
   1565     }
   1566 
   1567     // emit the condition before doing anything with selection
   1568     node->getCondition()->traverse(this);
   1569 
   1570     // make an "if" based on the value created by the condition
   1571     spv::Builder::If ifBuilder(accessChainLoad(node->getCondition()->getType()), builder);
   1572 
   1573     if (node->getTrueBlock()) {
   1574         // emit the "then" statement
   1575         node->getTrueBlock()->traverse(this);
   1576         if (result)
   1577             builder.createStore(accessChainLoad(node->getTrueBlock()->getAsTyped()->getType()), result);
   1578     }
   1579 
   1580     if (node->getFalseBlock()) {
   1581         ifBuilder.makeBeginElse();
   1582         // emit the "else" statement
   1583         node->getFalseBlock()->traverse(this);
   1584         if (result)
   1585             builder.createStore(accessChainLoad(node->getFalseBlock()->getAsTyped()->getType()), result);
   1586     }
   1587 
   1588     ifBuilder.makeEndIf();
   1589 
   1590     if (result) {
   1591         // GLSL only has r-values as the result of a :?, but
   1592         // if we have an l-value, that can be more efficient if it will
   1593         // become the base of a complex r-value expression, because the
   1594         // next layer copies r-values into memory to use the access-chain mechanism
   1595         builder.clearAccessChain();
   1596         builder.setAccessChainLValue(result);
   1597     }
   1598 
   1599     return false;
   1600 }
   1601 
   1602 bool TGlslangToSpvTraverser::visitSwitch(glslang::TVisit /* visit */, glslang::TIntermSwitch* node)
   1603 {
   1604     // emit and get the condition before doing anything with switch
   1605     node->getCondition()->traverse(this);
   1606     spv::Id selector = accessChainLoad(node->getCondition()->getAsTyped()->getType());
   1607 
   1608     // browse the children to sort out code segments
   1609     int defaultSegment = -1;
   1610     std::vector<TIntermNode*> codeSegments;
   1611     glslang::TIntermSequence& sequence = node->getBody()->getSequence();
   1612     std::vector<int> caseValues;
   1613     std::vector<int> valueIndexToSegment(sequence.size());  // note: probably not all are used, it is an overestimate
   1614     for (glslang::TIntermSequence::iterator c = sequence.begin(); c != sequence.end(); ++c) {
   1615         TIntermNode* child = *c;
   1616         if (child->getAsBranchNode() && child->getAsBranchNode()->getFlowOp() == glslang::EOpDefault)
   1617             defaultSegment = (int)codeSegments.size();
   1618         else if (child->getAsBranchNode() && child->getAsBranchNode()->getFlowOp() == glslang::EOpCase) {
   1619             valueIndexToSegment[caseValues.size()] = (int)codeSegments.size();
   1620             caseValues.push_back(child->getAsBranchNode()->getExpression()->getAsConstantUnion()->getConstArray()[0].getIConst());
   1621         } else
   1622             codeSegments.push_back(child);
   1623     }
   1624 
   1625     // handle the case where the last code segment is missing, due to no code
   1626     // statements between the last case and the end of the switch statement
   1627     if ((caseValues.size() && (int)codeSegments.size() == valueIndexToSegment[caseValues.size() - 1]) ||
   1628         (int)codeSegments.size() == defaultSegment)
   1629         codeSegments.push_back(nullptr);
   1630 
   1631     // make the switch statement
   1632     std::vector<spv::Block*> segmentBlocks; // returned, as the blocks allocated in the call
   1633     builder.makeSwitch(selector, (int)codeSegments.size(), caseValues, valueIndexToSegment, defaultSegment, segmentBlocks);
   1634 
   1635     // emit all the code in the segments
   1636     breakForLoop.push(false);
   1637     for (unsigned int s = 0; s < codeSegments.size(); ++s) {
   1638         builder.nextSwitchSegment(segmentBlocks, s);
   1639         if (codeSegments[s])
   1640             codeSegments[s]->traverse(this);
   1641         else
   1642             builder.addSwitchBreak();
   1643     }
   1644     breakForLoop.pop();
   1645 
   1646     builder.endSwitch(segmentBlocks);
   1647 
   1648     return false;
   1649 }
   1650 
   1651 void TGlslangToSpvTraverser::visitConstantUnion(glslang::TIntermConstantUnion* node)
   1652 {
   1653     int nextConst = 0;
   1654     spv::Id constant = createSpvConstantFromConstUnionArray(node->getType(), node->getConstArray(), nextConst, false);
   1655 
   1656     builder.clearAccessChain();
   1657     builder.setAccessChainRValue(constant);
   1658 }
   1659 
   1660 bool TGlslangToSpvTraverser::visitLoop(glslang::TVisit /* visit */, glslang::TIntermLoop* node)
   1661 {
   1662     auto blocks = builder.makeNewLoop();
   1663     builder.createBranch(&blocks.head);
   1664     // Spec requires back edges to target header blocks, and every header block
   1665     // must dominate its merge block.  Make a header block first to ensure these
   1666     // conditions are met.  By definition, it will contain OpLoopMerge, followed
   1667     // by a block-ending branch.  But we don't want to put any other body/test
   1668     // instructions in it, since the body/test may have arbitrary instructions,
   1669     // including merges of its own.
   1670     builder.setBuildPoint(&blocks.head);
   1671     builder.createLoopMerge(&blocks.merge, &blocks.continue_target, spv::LoopControlMaskNone);
   1672     if (node->testFirst() && node->getTest()) {
   1673         spv::Block& test = builder.makeNewBlock();
   1674         builder.createBranch(&test);
   1675 
   1676         builder.setBuildPoint(&test);
   1677         node->getTest()->traverse(this);
   1678         spv::Id condition =
   1679             accessChainLoad(node->getTest()->getType());
   1680         builder.createConditionalBranch(condition, &blocks.body, &blocks.merge);
   1681 
   1682         builder.setBuildPoint(&blocks.body);
   1683         breakForLoop.push(true);
   1684         if (node->getBody())
   1685             node->getBody()->traverse(this);
   1686         builder.createBranch(&blocks.continue_target);
   1687         breakForLoop.pop();
   1688 
   1689         builder.setBuildPoint(&blocks.continue_target);
   1690         if (node->getTerminal())
   1691             node->getTerminal()->traverse(this);
   1692         builder.createBranch(&blocks.head);
   1693     } else {
   1694         builder.createBranch(&blocks.body);
   1695 
   1696         breakForLoop.push(true);
   1697         builder.setBuildPoint(&blocks.body);
   1698         if (node->getBody())
   1699             node->getBody()->traverse(this);
   1700         builder.createBranch(&blocks.continue_target);
   1701         breakForLoop.pop();
   1702 
   1703         builder.setBuildPoint(&blocks.continue_target);
   1704         if (node->getTerminal())
   1705             node->getTerminal()->traverse(this);
   1706         if (node->getTest()) {
   1707             node->getTest()->traverse(this);
   1708             spv::Id condition =
   1709                 accessChainLoad(node->getTest()->getType());
   1710             builder.createConditionalBranch(condition, &blocks.head, &blocks.merge);
   1711         } else {
   1712             // TODO: unless there was a break/return/discard instruction
   1713             // somewhere in the body, this is an infinite loop, so we should
   1714             // issue a warning.
   1715             builder.createBranch(&blocks.head);
   1716         }
   1717     }
   1718     builder.setBuildPoint(&blocks.merge);
   1719     builder.closeLoop();
   1720     return false;
   1721 }
   1722 
   1723 bool TGlslangToSpvTraverser::visitBranch(glslang::TVisit /* visit */, glslang::TIntermBranch* node)
   1724 {
   1725     if (node->getExpression())
   1726         node->getExpression()->traverse(this);
   1727 
   1728     switch (node->getFlowOp()) {
   1729     case glslang::EOpKill:
   1730         builder.makeDiscard();
   1731         break;
   1732     case glslang::EOpBreak:
   1733         if (breakForLoop.top())
   1734             builder.createLoopExit();
   1735         else
   1736             builder.addSwitchBreak();
   1737         break;
   1738     case glslang::EOpContinue:
   1739         builder.createLoopContinue();
   1740         break;
   1741     case glslang::EOpReturn:
   1742         if (node->getExpression())
   1743             builder.makeReturn(false, accessChainLoad(node->getExpression()->getType()));
   1744         else
   1745             builder.makeReturn(false);
   1746 
   1747         builder.clearAccessChain();
   1748         break;
   1749 
   1750     default:
   1751         assert(0);
   1752         break;
   1753     }
   1754 
   1755     return false;
   1756 }
   1757 
   1758 spv::Id TGlslangToSpvTraverser::createSpvVariable(const glslang::TIntermSymbol* node)
   1759 {
   1760     // First, steer off constants, which are not SPIR-V variables, but
   1761     // can still have a mapping to a SPIR-V Id.
   1762     // This includes specialization constants.
   1763     if (node->getQualifier().isConstant()) {
   1764         return createSpvConstant(*node);
   1765     }
   1766 
   1767     // Now, handle actual variables
   1768     spv::StorageClass storageClass = TranslateStorageClass(node->getType());
   1769     spv::Id spvType = convertGlslangToSpvType(node->getType());
   1770 
   1771     const char* name = node->getName().c_str();
   1772     if (glslang::IsAnonymous(name))
   1773         name = "";
   1774 
   1775     return builder.createVariable(storageClass, spvType, name);
   1776 }
   1777 
   1778 // Return type Id of the sampled type.
   1779 spv::Id TGlslangToSpvTraverser::getSampledType(const glslang::TSampler& sampler)
   1780 {
   1781     switch (sampler.type) {
   1782         case glslang::EbtFloat:    return builder.makeFloatType(32);
   1783         case glslang::EbtInt:      return builder.makeIntType(32);
   1784         case glslang::EbtUint:     return builder.makeUintType(32);
   1785         default:
   1786             assert(0);
   1787             return builder.makeFloatType(32);
   1788     }
   1789 }
   1790 
   1791 // Convert from a glslang type to an SPV type, by calling into a
   1792 // recursive version of this function. This establishes the inherited
   1793 // layout state rooted from the top-level type.
   1794 spv::Id TGlslangToSpvTraverser::convertGlslangToSpvType(const glslang::TType& type)
   1795 {
   1796     return convertGlslangToSpvType(type, getExplicitLayout(type), type.getQualifier());
   1797 }
   1798 
   1799 // Do full recursive conversion of an arbitrary glslang type to a SPIR-V Id.
   1800 // explicitLayout can be kept the same throughout the hierarchical recursive walk.
   1801 // Mutually recursive with convertGlslangStructToSpvType().
   1802 spv::Id TGlslangToSpvTraverser::convertGlslangToSpvType(const glslang::TType& type, glslang::TLayoutPacking explicitLayout, const glslang::TQualifier& qualifier)
   1803 {
   1804     spv::Id spvType = spv::NoResult;
   1805 
   1806     switch (type.getBasicType()) {
   1807     case glslang::EbtVoid:
   1808         spvType = builder.makeVoidType();
   1809         assert (! type.isArray());
   1810         break;
   1811     case glslang::EbtFloat:
   1812         spvType = builder.makeFloatType(32);
   1813         break;
   1814     case glslang::EbtDouble:
   1815         spvType = builder.makeFloatType(64);
   1816         break;
   1817     case glslang::EbtBool:
   1818         // "transparent" bool doesn't exist in SPIR-V.  The GLSL convention is
   1819         // a 32-bit int where non-0 means true.
   1820         if (explicitLayout != glslang::ElpNone)
   1821             spvType = builder.makeUintType(32);
   1822         else
   1823             spvType = builder.makeBoolType();
   1824         break;
   1825     case glslang::EbtInt:
   1826         spvType = builder.makeIntType(32);
   1827         break;
   1828     case glslang::EbtUint:
   1829         spvType = builder.makeUintType(32);
   1830         break;
   1831     case glslang::EbtInt64:
   1832         builder.addCapability(spv::CapabilityInt64);
   1833         spvType = builder.makeIntType(64);
   1834         break;
   1835     case glslang::EbtUint64:
   1836         builder.addCapability(spv::CapabilityInt64);
   1837         spvType = builder.makeUintType(64);
   1838         break;
   1839     case glslang::EbtAtomicUint:
   1840         builder.addCapability(spv::CapabilityAtomicStorage);
   1841         spvType = builder.makeUintType(32);
   1842         break;
   1843     case glslang::EbtSampler:
   1844         {
   1845             const glslang::TSampler& sampler = type.getSampler();
   1846             if (sampler.sampler) {
   1847                 // pure sampler
   1848                 spvType = builder.makeSamplerType();
   1849             } else {
   1850                 // an image is present, make its type
   1851                 spvType = builder.makeImageType(getSampledType(sampler), TranslateDimensionality(sampler), sampler.shadow, sampler.arrayed, sampler.ms,
   1852                                                 sampler.image ? 2 : 1, TranslateImageFormat(type));
   1853                 if (sampler.combined) {
   1854                     // already has both image and sampler, make the combined type
   1855                     spvType = builder.makeSampledImageType(spvType);
   1856                 }
   1857             }
   1858         }
   1859         break;
   1860     case glslang::EbtStruct:
   1861     case glslang::EbtBlock:
   1862         {
   1863             // If we've seen this struct type, return it
   1864             const glslang::TTypeList* glslangMembers = type.getStruct();
   1865 
   1866             // Try to share structs for different layouts, but not yet for other
   1867             // kinds of qualification (primarily not yet including interpolant qualification).
   1868             if (! HasNonLayoutQualifiers(qualifier))
   1869                 spvType = structMap[explicitLayout][qualifier.layoutMatrix][glslangMembers];
   1870             if (spvType != spv::NoResult)
   1871                 break;
   1872 
   1873             // else, we haven't seen it...
   1874             if (type.getBasicType() == glslang::EbtBlock)
   1875                 memberRemapper[glslangMembers].resize(glslangMembers->size());
   1876             spvType = convertGlslangStructToSpvType(type, glslangMembers, explicitLayout, qualifier);
   1877         }
   1878         break;
   1879     default:
   1880         assert(0);
   1881         break;
   1882     }
   1883 
   1884     if (type.isMatrix())
   1885         spvType = builder.makeMatrixType(spvType, type.getMatrixCols(), type.getMatrixRows());
   1886     else {
   1887         // If this variable has a vector element count greater than 1, create a SPIR-V vector
   1888         if (type.getVectorSize() > 1)
   1889             spvType = builder.makeVectorType(spvType, type.getVectorSize());
   1890     }
   1891 
   1892     if (type.isArray()) {
   1893         int stride = 0;  // keep this 0 unless doing an explicit layout; 0 will mean no decoration, no stride
   1894 
   1895         // Do all but the outer dimension
   1896         if (type.getArraySizes()->getNumDims() > 1) {
   1897             // We need to decorate array strides for types needing explicit layout, except blocks.
   1898             if (explicitLayout != glslang::ElpNone && type.getBasicType() != glslang::EbtBlock) {
   1899                 // Use a dummy glslang type for querying internal strides of
   1900                 // arrays of arrays, but using just a one-dimensional array.
   1901                 glslang::TType simpleArrayType(type, 0); // deference type of the array
   1902                 while (simpleArrayType.getArraySizes().getNumDims() > 1)
   1903                     simpleArrayType.getArraySizes().dereference();
   1904 
   1905                 // Will compute the higher-order strides here, rather than making a whole
   1906                 // pile of types and doing repetitive recursion on their contents.
   1907                 stride = getArrayStride(simpleArrayType, explicitLayout, qualifier.layoutMatrix);
   1908             }
   1909 
   1910             // make the arrays
   1911             for (int dim = type.getArraySizes()->getNumDims() - 1; dim > 0; --dim) {
   1912                 spvType = builder.makeArrayType(spvType, makeArraySizeId(*type.getArraySizes(), dim), stride);
   1913                 if (stride > 0)
   1914                     builder.addDecoration(spvType, spv::DecorationArrayStride, stride);
   1915                 stride *= type.getArraySizes()->getDimSize(dim);
   1916             }
   1917         } else {
   1918             // single-dimensional array, and don't yet have stride
   1919 
   1920             // We need to decorate array strides for types needing explicit layout, except blocks.
   1921             if (explicitLayout != glslang::ElpNone && type.getBasicType() != glslang::EbtBlock)
   1922                 stride = getArrayStride(type, explicitLayout, qualifier.layoutMatrix);
   1923         }
   1924 
   1925         // Do the outer dimension, which might not be known for a runtime-sized array
   1926         if (type.isRuntimeSizedArray()) {
   1927             spvType = builder.makeRuntimeArray(spvType);
   1928         } else {
   1929             assert(type.getOuterArraySize() > 0);
   1930             spvType = builder.makeArrayType(spvType, makeArraySizeId(*type.getArraySizes(), 0), stride);
   1931         }
   1932         if (stride > 0)
   1933             builder.addDecoration(spvType, spv::DecorationArrayStride, stride);
   1934     }
   1935 
   1936     return spvType;
   1937 }
   1938 
   1939 
   1940 // Do full recursive conversion of a glslang structure (or block) type to a SPIR-V Id.
   1941 // explicitLayout can be kept the same throughout the hierarchical recursive walk.
   1942 // Mutually recursive with convertGlslangToSpvType().
   1943 spv::Id TGlslangToSpvTraverser::convertGlslangStructToSpvType(const glslang::TType& type,
   1944                                                               const glslang::TTypeList* glslangMembers,
   1945                                                               glslang::TLayoutPacking explicitLayout,
   1946                                                               const glslang::TQualifier& qualifier)
   1947 {
   1948     // Create a vector of struct types for SPIR-V to consume
   1949     std::vector<spv::Id> spvMembers;
   1950     int memberDelta = 0;  // how much the member's index changes from glslang to SPIR-V, normally 0, except sometimes for blocks
   1951     int locationOffset = 0;  // for use across struct members, when they are called recursively
   1952     for (int i = 0; i < (int)glslangMembers->size(); i++) {
   1953         glslang::TType& glslangMember = *(*glslangMembers)[i].type;
   1954         if (glslangMember.hiddenMember()) {
   1955             ++memberDelta;
   1956             if (type.getBasicType() == glslang::EbtBlock)
   1957                 memberRemapper[glslangMembers][i] = -1;
   1958         } else {
   1959             if (type.getBasicType() == glslang::EbtBlock)
   1960                 memberRemapper[glslangMembers][i] = i - memberDelta;
   1961             // modify just this child's view of the qualifier
   1962             glslang::TQualifier memberQualifier = glslangMember.getQualifier();
   1963             InheritQualifiers(memberQualifier, qualifier);
   1964 
   1965             // manually inherit location; it's more complex
   1966             if (! memberQualifier.hasLocation() && qualifier.hasLocation())
   1967                 memberQualifier.layoutLocation = qualifier.layoutLocation + locationOffset;
   1968             if (qualifier.hasLocation())
   1969                 locationOffset += glslangIntermediate->computeTypeLocationSize(glslangMember);
   1970 
   1971             // recurse
   1972             spvMembers.push_back(convertGlslangToSpvType(glslangMember, explicitLayout, memberQualifier));
   1973         }
   1974     }
   1975 
   1976     // Make the SPIR-V type
   1977     spv::Id spvType = builder.makeStructType(spvMembers, type.getTypeName().c_str());
   1978     if (! HasNonLayoutQualifiers(qualifier))
   1979         structMap[explicitLayout][qualifier.layoutMatrix][glslangMembers] = spvType;
   1980 
   1981     // Decorate it
   1982     decorateStructType(type, glslangMembers, explicitLayout, qualifier, spvType);
   1983 
   1984     return spvType;
   1985 }
   1986 
   1987 void TGlslangToSpvTraverser::decorateStructType(const glslang::TType& type,
   1988                                                 const glslang::TTypeList* glslangMembers,
   1989                                                 glslang::TLayoutPacking explicitLayout,
   1990                                                 const glslang::TQualifier& qualifier,
   1991                                                 spv::Id spvType)
   1992 {
   1993     // Name and decorate the non-hidden members
   1994     int offset = -1;
   1995     int locationOffset = 0;  // for use within the members of this struct
   1996     for (int i = 0; i < (int)glslangMembers->size(); i++) {
   1997         glslang::TType& glslangMember = *(*glslangMembers)[i].type;
   1998         int member = i;
   1999         if (type.getBasicType() == glslang::EbtBlock)
   2000             member = memberRemapper[glslangMembers][i];
   2001 
   2002         // modify just this child's view of the qualifier
   2003         glslang::TQualifier memberQualifier = glslangMember.getQualifier();
   2004         InheritQualifiers(memberQualifier, qualifier);
   2005 
   2006         // using -1 above to indicate a hidden member
   2007         if (member >= 0) {
   2008             builder.addMemberName(spvType, member, glslangMember.getFieldName().c_str());
   2009             addMemberDecoration(spvType, member, TranslateLayoutDecoration(glslangMember, memberQualifier.layoutMatrix));
   2010             addMemberDecoration(spvType, member, TranslatePrecisionDecoration(glslangMember));
   2011             // Add interpolation and auxiliary storage decorations only to top-level members of Input and Output storage classes
   2012             if (type.getQualifier().storage == glslang::EvqVaryingIn || type.getQualifier().storage == glslang::EvqVaryingOut) {
   2013                 if (type.getBasicType() == glslang::EbtBlock) {
   2014                     addMemberDecoration(spvType, member, TranslateInterpolationDecoration(memberQualifier));
   2015                     addMemberDecoration(spvType, member, TranslateAuxiliaryStorageDecoration(memberQualifier));
   2016                 }
   2017             }
   2018             addMemberDecoration(spvType, member, TranslateInvariantDecoration(memberQualifier));
   2019 
   2020             if (qualifier.storage == glslang::EvqBuffer) {
   2021                 std::vector<spv::Decoration> memory;
   2022                 TranslateMemoryDecoration(memberQualifier, memory);
   2023                 for (unsigned int i = 0; i < memory.size(); ++i)
   2024                     addMemberDecoration(spvType, member, memory[i]);
   2025             }
   2026 
   2027             // Compute location decoration; tricky based on whether inheritance is at play and
   2028             // what kind of container we have, etc.
   2029             // TODO: This algorithm (and it's cousin above doing almost the same thing) should
   2030             //       probably move to the linker stage of the front end proper, and just have the
   2031             //       answer sitting already distributed throughout the individual member locations.
   2032             int location = -1;                // will only decorate if present or inherited
   2033             // Ignore member locations if the container is an array, as that's
   2034             // ill-specified and decisions have been made to not allow this anyway.
   2035             // The object itself must have a location, and that comes out from decorating the object,
   2036             // not the type (this code decorates types).
   2037             if (! type.isArray()) {
   2038                 if (memberQualifier.hasLocation()) { // no inheritance, or override of inheritance
   2039                     // struct members should not have explicit locations
   2040                     assert(type.getBasicType() != glslang::EbtStruct);
   2041                     location = memberQualifier.layoutLocation;
   2042                 } else if (type.getBasicType() != glslang::EbtBlock) {
   2043                     // If it is a not a Block, (...) Its members are assigned consecutive locations (...)
   2044                     // The members, and their nested types, must not themselves have Location decorations.
   2045                 } else if (qualifier.hasLocation()) // inheritance
   2046                     location = qualifier.layoutLocation + locationOffset;
   2047             }
   2048             if (location >= 0)
   2049                 builder.addMemberDecoration(spvType, member, spv::DecorationLocation, location);
   2050 
   2051             if (qualifier.hasLocation())      // track for upcoming inheritance
   2052                 locationOffset += glslangIntermediate->computeTypeLocationSize(glslangMember);
   2053 
   2054             // component, XFB, others
   2055             if (glslangMember.getQualifier().hasComponent())
   2056                 builder.addMemberDecoration(spvType, member, spv::DecorationComponent, glslangMember.getQualifier().layoutComponent);
   2057             if (glslangMember.getQualifier().hasXfbOffset())
   2058                 builder.addMemberDecoration(spvType, member, spv::DecorationOffset, glslangMember.getQualifier().layoutXfbOffset);
   2059             else if (explicitLayout != glslang::ElpNone) {
   2060                 // figure out what to do with offset, which is accumulating
   2061                 int nextOffset;
   2062                 updateMemberOffset(type, glslangMember, offset, nextOffset, explicitLayout, memberQualifier.layoutMatrix);
   2063                 if (offset >= 0)
   2064                     builder.addMemberDecoration(spvType, member, spv::DecorationOffset, offset);
   2065                 offset = nextOffset;
   2066             }
   2067 
   2068             if (glslangMember.isMatrix() && explicitLayout != glslang::ElpNone)
   2069                 builder.addMemberDecoration(spvType, member, spv::DecorationMatrixStride, getMatrixStride(glslangMember, explicitLayout, memberQualifier.layoutMatrix));
   2070 
   2071             // built-in variable decorations
   2072             spv::BuiltIn builtIn = TranslateBuiltInDecoration(glslangMember.getQualifier().builtIn, true);
   2073             if (builtIn != spv::BuiltInMax)
   2074                 addMemberDecoration(spvType, member, spv::DecorationBuiltIn, (int)builtIn);
   2075         }
   2076     }
   2077 
   2078     // Decorate the structure
   2079     addDecoration(spvType, TranslateLayoutDecoration(type, qualifier.layoutMatrix));
   2080     addDecoration(spvType, TranslateBlockDecoration(type));
   2081     if (type.getQualifier().hasStream() && glslangIntermediate->isMultiStream()) {
   2082         builder.addCapability(spv::CapabilityGeometryStreams);
   2083         builder.addDecoration(spvType, spv::DecorationStream, type.getQualifier().layoutStream);
   2084     }
   2085     if (glslangIntermediate->getXfbMode()) {
   2086         builder.addCapability(spv::CapabilityTransformFeedback);
   2087         if (type.getQualifier().hasXfbStride())
   2088             builder.addDecoration(spvType, spv::DecorationXfbStride, type.getQualifier().layoutXfbStride);
   2089         if (type.getQualifier().hasXfbBuffer())
   2090             builder.addDecoration(spvType, spv::DecorationXfbBuffer, type.getQualifier().layoutXfbBuffer);
   2091     }
   2092 }
   2093 
   2094 // Turn the expression forming the array size into an id.
   2095 // This is not quite trivial, because of specialization constants.
   2096 // Sometimes, a raw constant is turned into an Id, and sometimes
   2097 // a specialization constant expression is.
   2098 spv::Id TGlslangToSpvTraverser::makeArraySizeId(const glslang::TArraySizes& arraySizes, int dim)
   2099 {
   2100     // First, see if this is sized with a node, meaning a specialization constant:
   2101     glslang::TIntermTyped* specNode = arraySizes.getDimNode(dim);
   2102     if (specNode != nullptr) {
   2103         builder.clearAccessChain();
   2104         specNode->traverse(this);
   2105         return accessChainLoad(specNode->getAsTyped()->getType());
   2106     }
   2107 
   2108     // Otherwise, need a compile-time (front end) size, get it:
   2109     int size = arraySizes.getDimSize(dim);
   2110     assert(size > 0);
   2111     return builder.makeUintConstant(size);
   2112 }
   2113 
   2114 // Wrap the builder's accessChainLoad to:
   2115 //  - localize handling of RelaxedPrecision
   2116 //  - use the SPIR-V inferred type instead of another conversion of the glslang type
   2117 //    (avoids unnecessary work and possible type punning for structures)
   2118 //  - do conversion of concrete to abstract type
   2119 spv::Id TGlslangToSpvTraverser::accessChainLoad(const glslang::TType& type)
   2120 {
   2121     spv::Id nominalTypeId = builder.accessChainGetInferredType();
   2122     spv::Id loadedId = builder.accessChainLoad(TranslatePrecisionDecoration(type), nominalTypeId);
   2123 
   2124     // Need to convert to abstract types when necessary
   2125     if (type.getBasicType() == glslang::EbtBool) {
   2126         if (builder.isScalarType(nominalTypeId)) {
   2127             // Conversion for bool
   2128             spv::Id boolType = builder.makeBoolType();
   2129             if (nominalTypeId != boolType)
   2130                 loadedId = builder.createBinOp(spv::OpINotEqual, boolType, loadedId, builder.makeUintConstant(0));
   2131         } else if (builder.isVectorType(nominalTypeId)) {
   2132             // Conversion for bvec
   2133             int vecSize = builder.getNumTypeComponents(nominalTypeId);
   2134             spv::Id bvecType = builder.makeVectorType(builder.makeBoolType(), vecSize);
   2135             if (nominalTypeId != bvecType)
   2136                 loadedId = builder.createBinOp(spv::OpINotEqual, bvecType, loadedId, makeSmearedConstant(builder.makeUintConstant(0), vecSize));
   2137         }
   2138     }
   2139 
   2140     return loadedId;
   2141 }
   2142 
   2143 // Wrap the builder's accessChainStore to:
   2144 //  - do conversion of concrete to abstract type
   2145 void TGlslangToSpvTraverser::accessChainStore(const glslang::TType& type, spv::Id rvalue)
   2146 {
   2147     // Need to convert to abstract types when necessary
   2148     if (type.getBasicType() == glslang::EbtBool) {
   2149         spv::Id nominalTypeId = builder.accessChainGetInferredType();
   2150 
   2151         if (builder.isScalarType(nominalTypeId)) {
   2152             // Conversion for bool
   2153             spv::Id boolType = builder.makeBoolType();
   2154             if (nominalTypeId != boolType) {
   2155                 spv::Id zero = builder.makeUintConstant(0);
   2156                 spv::Id one  = builder.makeUintConstant(1);
   2157                 rvalue = builder.createTriOp(spv::OpSelect, nominalTypeId, rvalue, one, zero);
   2158             }
   2159         } else if (builder.isVectorType(nominalTypeId)) {
   2160             // Conversion for bvec
   2161             int vecSize = builder.getNumTypeComponents(nominalTypeId);
   2162             spv::Id bvecType = builder.makeVectorType(builder.makeBoolType(), vecSize);
   2163             if (nominalTypeId != bvecType) {
   2164                 spv::Id zero = makeSmearedConstant(builder.makeUintConstant(0), vecSize);
   2165                 spv::Id one  = makeSmearedConstant(builder.makeUintConstant(1), vecSize);
   2166                 rvalue = builder.createTriOp(spv::OpSelect, nominalTypeId, rvalue, one, zero);
   2167             }
   2168         }
   2169     }
   2170 
   2171     builder.accessChainStore(rvalue);
   2172 }
   2173 
   2174 // Decide whether or not this type should be
   2175 // decorated with offsets and strides, and if so
   2176 // whether std140 or std430 rules should be applied.
   2177 glslang::TLayoutPacking TGlslangToSpvTraverser::getExplicitLayout(const glslang::TType& type) const
   2178 {
   2179     // has to be a block
   2180     if (type.getBasicType() != glslang::EbtBlock)
   2181         return glslang::ElpNone;
   2182 
   2183     // has to be a uniform or buffer block
   2184     if (type.getQualifier().storage != glslang::EvqUniform &&
   2185         type.getQualifier().storage != glslang::EvqBuffer)
   2186         return glslang::ElpNone;
   2187 
   2188     // return the layout to use
   2189     switch (type.getQualifier().layoutPacking) {
   2190     case glslang::ElpStd140:
   2191     case glslang::ElpStd430:
   2192         return type.getQualifier().layoutPacking;
   2193     default:
   2194         return glslang::ElpNone;
   2195     }
   2196 }
   2197 
   2198 // Given an array type, returns the integer stride required for that array
   2199 int TGlslangToSpvTraverser::getArrayStride(const glslang::TType& arrayType, glslang::TLayoutPacking explicitLayout, glslang::TLayoutMatrix matrixLayout)
   2200 {
   2201     int size;
   2202     int stride;
   2203     glslangIntermediate->getBaseAlignment(arrayType, size, stride, explicitLayout == glslang::ElpStd140, matrixLayout == glslang::ElmRowMajor);
   2204 
   2205     return stride;
   2206 }
   2207 
   2208 // Given a matrix type, or array (of array) of matrixes type, returns the integer stride required for that matrix
   2209 // when used as a member of an interface block
   2210 int TGlslangToSpvTraverser::getMatrixStride(const glslang::TType& matrixType, glslang::TLayoutPacking explicitLayout, glslang::TLayoutMatrix matrixLayout)
   2211 {
   2212     glslang::TType elementType;
   2213     elementType.shallowCopy(matrixType);
   2214     elementType.clearArraySizes();
   2215 
   2216     int size;
   2217     int stride;
   2218     glslangIntermediate->getBaseAlignment(elementType, size, stride, explicitLayout == glslang::ElpStd140, matrixLayout == glslang::ElmRowMajor);
   2219 
   2220     return stride;
   2221 }
   2222 
   2223 // Given a member type of a struct, realign the current offset for it, and compute
   2224 // the next (not yet aligned) offset for the next member, which will get aligned
   2225 // on the next call.
   2226 // 'currentOffset' should be passed in already initialized, ready to modify, and reflecting
   2227 // the migration of data from nextOffset -> currentOffset.  It should be -1 on the first call.
   2228 // -1 means a non-forced member offset (no decoration needed).
   2229 void TGlslangToSpvTraverser::updateMemberOffset(const glslang::TType& /*structType*/, const glslang::TType& memberType, int& currentOffset, int& nextOffset,
   2230                                                 glslang::TLayoutPacking explicitLayout, glslang::TLayoutMatrix matrixLayout)
   2231 {
   2232     // this will get a positive value when deemed necessary
   2233     nextOffset = -1;
   2234 
   2235     // override anything in currentOffset with user-set offset
   2236     if (memberType.getQualifier().hasOffset())
   2237         currentOffset = memberType.getQualifier().layoutOffset;
   2238 
   2239     // It could be that current linker usage in glslang updated all the layoutOffset,
   2240     // in which case the following code does not matter.  But, that's not quite right
   2241     // once cross-compilation unit GLSL validation is done, as the original user
   2242     // settings are needed in layoutOffset, and then the following will come into play.
   2243 
   2244     if (explicitLayout == glslang::ElpNone) {
   2245         if (! memberType.getQualifier().hasOffset())
   2246             currentOffset = -1;
   2247 
   2248         return;
   2249     }
   2250 
   2251     // Getting this far means we need explicit offsets
   2252     if (currentOffset < 0)
   2253         currentOffset = 0;
   2254 
   2255     // Now, currentOffset is valid (either 0, or from a previous nextOffset),
   2256     // but possibly not yet correctly aligned.
   2257 
   2258     int memberSize;
   2259     int dummyStride;
   2260     int memberAlignment = glslangIntermediate->getBaseAlignment(memberType, memberSize, dummyStride, explicitLayout == glslang::ElpStd140, matrixLayout == glslang::ElmRowMajor);
   2261     glslang::RoundToPow2(currentOffset, memberAlignment);
   2262     nextOffset = currentOffset + memberSize;
   2263 }
   2264 
   2265 void TGlslangToSpvTraverser::declareUseOfStructMember(const glslang::TTypeList& members, int glslangMember)
   2266 {
   2267     const glslang::TBuiltInVariable glslangBuiltIn = members[glslangMember].type->getQualifier().builtIn;
   2268     switch (glslangBuiltIn)
   2269     {
   2270     case glslang::EbvClipDistance:
   2271     case glslang::EbvCullDistance:
   2272     case glslang::EbvPointSize:
   2273         // Generate the associated capability.  Delegate to TranslateBuiltInDecoration.
   2274         // Alternately, we could just call this for any glslang built-in, since the
   2275         // capability already guards against duplicates.
   2276         TranslateBuiltInDecoration(glslangBuiltIn, false);
   2277         break;
   2278     default:
   2279         // Capabilities were already generated when the struct was declared.
   2280         break;
   2281     }
   2282 }
   2283 
   2284 bool TGlslangToSpvTraverser::isShaderEntrypoint(const glslang::TIntermAggregate* node)
   2285 {
   2286     // have to ignore mangling and just look at the base name
   2287     size_t firstOpen = node->getName().find('(');
   2288     return node->getName().compare(0, firstOpen, glslangIntermediate->getEntryPoint().c_str()) == 0;
   2289 }
   2290 
   2291 // Make all the functions, skeletally, without actually visiting their bodies.
   2292 void TGlslangToSpvTraverser::makeFunctions(const glslang::TIntermSequence& glslFunctions)
   2293 {
   2294     for (int f = 0; f < (int)glslFunctions.size(); ++f) {
   2295         glslang::TIntermAggregate* glslFunction = glslFunctions[f]->getAsAggregate();
   2296         if (! glslFunction || glslFunction->getOp() != glslang::EOpFunction || isShaderEntrypoint(glslFunction))
   2297             continue;
   2298 
   2299         // We're on a user function.  Set up the basic interface for the function now,
   2300         // so that it's available to call.
   2301         // Translating the body will happen later.
   2302         //
   2303         // Typically (except for a "const in" parameter), an address will be passed to the
   2304         // function.  What it is an address of varies:
   2305         //
   2306         // - "in" parameters not marked as "const" can be written to without modifying the argument,
   2307         //  so that write needs to be to a copy, hence the address of a copy works.
   2308         //
   2309         // - "const in" parameters can just be the r-value, as no writes need occur.
   2310         //
   2311         // - "out" and "inout" arguments can't be done as direct pointers, because GLSL has
   2312         // copy-in/copy-out semantics.  They can be handled though with a pointer to a copy.
   2313 
   2314         std::vector<spv::Id> paramTypes;
   2315         std::vector<spv::Decoration> paramPrecisions;
   2316         glslang::TIntermSequence& parameters = glslFunction->getSequence()[0]->getAsAggregate()->getSequence();
   2317 
   2318         for (int p = 0; p < (int)parameters.size(); ++p) {
   2319             const glslang::TType& paramType = parameters[p]->getAsTyped()->getType();
   2320             spv::Id typeId = convertGlslangToSpvType(paramType);
   2321             if (paramType.isOpaque())
   2322                 typeId = builder.makePointer(TranslateStorageClass(paramType), typeId);
   2323             else if (paramType.getQualifier().storage != glslang::EvqConstReadOnly)
   2324                 typeId = builder.makePointer(spv::StorageClassFunction, typeId);
   2325             else
   2326                 constReadOnlyParameters.insert(parameters[p]->getAsSymbolNode()->getId());
   2327             paramPrecisions.push_back(TranslatePrecisionDecoration(paramType));
   2328             paramTypes.push_back(typeId);
   2329         }
   2330 
   2331         spv::Block* functionBlock;
   2332         spv::Function *function = builder.makeFunctionEntry(TranslatePrecisionDecoration(glslFunction->getType()),
   2333                                                             convertGlslangToSpvType(glslFunction->getType()),
   2334                                                             glslFunction->getName().c_str(), paramTypes, paramPrecisions, &functionBlock);
   2335 
   2336         // Track function to emit/call later
   2337         functionMap[glslFunction->getName().c_str()] = function;
   2338 
   2339         // Set the parameter id's
   2340         for (int p = 0; p < (int)parameters.size(); ++p) {
   2341             symbolValues[parameters[p]->getAsSymbolNode()->getId()] = function->getParamId(p);
   2342             // give a name too
   2343             builder.addName(function->getParamId(p), parameters[p]->getAsSymbolNode()->getName().c_str());
   2344         }
   2345     }
   2346 }
   2347 
   2348 // Process all the initializers, while skipping the functions and link objects
   2349 void TGlslangToSpvTraverser::makeGlobalInitializers(const glslang::TIntermSequence& initializers)
   2350 {
   2351     builder.setBuildPoint(shaderEntry->getLastBlock());
   2352     for (int i = 0; i < (int)initializers.size(); ++i) {
   2353         glslang::TIntermAggregate* initializer = initializers[i]->getAsAggregate();
   2354         if (initializer && initializer->getOp() != glslang::EOpFunction && initializer->getOp() != glslang::EOpLinkerObjects) {
   2355 
   2356             // We're on a top-level node that's not a function.  Treat as an initializer, whose
   2357             // code goes into the beginning of main.
   2358             initializer->traverse(this);
   2359         }
   2360     }
   2361 }
   2362 
   2363 // Process all the functions, while skipping initializers.
   2364 void TGlslangToSpvTraverser::visitFunctions(const glslang::TIntermSequence& glslFunctions)
   2365 {
   2366     for (int f = 0; f < (int)glslFunctions.size(); ++f) {
   2367         glslang::TIntermAggregate* node = glslFunctions[f]->getAsAggregate();
   2368         if (node && (node->getOp() == glslang::EOpFunction || node->getOp() == glslang ::EOpLinkerObjects))
   2369             node->traverse(this);
   2370     }
   2371 }
   2372 
   2373 void TGlslangToSpvTraverser::handleFunctionEntry(const glslang::TIntermAggregate* node)
   2374 {
   2375     // SPIR-V functions should already be in the functionMap from the prepass
   2376     // that called makeFunctions().
   2377     spv::Function* function = functionMap[node->getName().c_str()];
   2378     spv::Block* functionBlock = function->getEntryBlock();
   2379     builder.setBuildPoint(functionBlock);
   2380 }
   2381 
   2382 void TGlslangToSpvTraverser::translateArguments(const glslang::TIntermAggregate& node, std::vector<spv::Id>& arguments)
   2383 {
   2384     const glslang::TIntermSequence& glslangArguments = node.getSequence();
   2385 
   2386     glslang::TSampler sampler = {};
   2387     bool cubeCompare = false;
   2388     if (node.isTexture() || node.isImage()) {
   2389         sampler = glslangArguments[0]->getAsTyped()->getType().getSampler();
   2390         cubeCompare = sampler.dim == glslang::EsdCube && sampler.arrayed && sampler.shadow;
   2391     }
   2392 
   2393     for (int i = 0; i < (int)glslangArguments.size(); ++i) {
   2394         builder.clearAccessChain();
   2395         glslangArguments[i]->traverse(this);
   2396 
   2397         // Special case l-value operands
   2398         bool lvalue = false;
   2399         switch (node.getOp()) {
   2400         case glslang::EOpImageAtomicAdd:
   2401         case glslang::EOpImageAtomicMin:
   2402         case glslang::EOpImageAtomicMax:
   2403         case glslang::EOpImageAtomicAnd:
   2404         case glslang::EOpImageAtomicOr:
   2405         case glslang::EOpImageAtomicXor:
   2406         case glslang::EOpImageAtomicExchange:
   2407         case glslang::EOpImageAtomicCompSwap:
   2408             if (i == 0)
   2409                 lvalue = true;
   2410             break;
   2411         case glslang::EOpSparseImageLoad:
   2412             if ((sampler.ms && i == 3) || (! sampler.ms && i == 2))
   2413                 lvalue = true;
   2414             break;
   2415         case glslang::EOpSparseTexture:
   2416             if ((cubeCompare && i == 3) || (! cubeCompare && i == 2))
   2417                 lvalue = true;
   2418             break;
   2419         case glslang::EOpSparseTextureClamp:
   2420             if ((cubeCompare && i == 4) || (! cubeCompare && i == 3))
   2421                 lvalue = true;
   2422             break;
   2423         case glslang::EOpSparseTextureLod:
   2424         case glslang::EOpSparseTextureOffset:
   2425             if (i == 3)
   2426                 lvalue = true;
   2427             break;
   2428         case glslang::EOpSparseTextureFetch:
   2429             if ((sampler.dim != glslang::EsdRect && i == 3) || (sampler.dim == glslang::EsdRect && i == 2))
   2430                 lvalue = true;
   2431             break;
   2432         case glslang::EOpSparseTextureFetchOffset:
   2433             if ((sampler.dim != glslang::EsdRect && i == 4) || (sampler.dim == glslang::EsdRect && i == 3))
   2434                 lvalue = true;
   2435             break;
   2436         case glslang::EOpSparseTextureLodOffset:
   2437         case glslang::EOpSparseTextureGrad:
   2438         case glslang::EOpSparseTextureOffsetClamp:
   2439             if (i == 4)
   2440                 lvalue = true;
   2441             break;
   2442         case glslang::EOpSparseTextureGradOffset:
   2443         case glslang::EOpSparseTextureGradClamp:
   2444             if (i == 5)
   2445                 lvalue = true;
   2446             break;
   2447         case glslang::EOpSparseTextureGradOffsetClamp:
   2448             if (i == 6)
   2449                 lvalue = true;
   2450             break;
   2451          case glslang::EOpSparseTextureGather:
   2452             if ((sampler.shadow && i == 3) || (! sampler.shadow && i == 2))
   2453                 lvalue = true;
   2454             break;
   2455         case glslang::EOpSparseTextureGatherOffset:
   2456         case glslang::EOpSparseTextureGatherOffsets:
   2457             if ((sampler.shadow && i == 4) || (! sampler.shadow && i == 3))
   2458                 lvalue = true;
   2459             break;
   2460         default:
   2461             break;
   2462         }
   2463 
   2464         if (lvalue)
   2465             arguments.push_back(builder.accessChainGetLValue());
   2466         else
   2467             arguments.push_back(accessChainLoad(glslangArguments[i]->getAsTyped()->getType()));
   2468     }
   2469 }
   2470 
   2471 void TGlslangToSpvTraverser::translateArguments(glslang::TIntermUnary& node, std::vector<spv::Id>& arguments)
   2472 {
   2473     builder.clearAccessChain();
   2474     node.getOperand()->traverse(this);
   2475     arguments.push_back(accessChainLoad(node.getOperand()->getType()));
   2476 }
   2477 
   2478 spv::Id TGlslangToSpvTraverser::createImageTextureFunctionCall(glslang::TIntermOperator* node)
   2479 {
   2480     if (! node->isImage() && ! node->isTexture()) {
   2481         return spv::NoResult;
   2482     }
   2483 
   2484     // Process a GLSL texturing op (will be SPV image)
   2485     const glslang::TSampler sampler = node->getAsAggregate() ? node->getAsAggregate()->getSequence()[0]->getAsTyped()->getType().getSampler()
   2486                                                              : node->getAsUnaryNode()->getOperand()->getAsTyped()->getType().getSampler();
   2487     std::vector<spv::Id> arguments;
   2488     if (node->getAsAggregate())
   2489         translateArguments(*node->getAsAggregate(), arguments);
   2490     else
   2491         translateArguments(*node->getAsUnaryNode(), arguments);
   2492     spv::Decoration precision = TranslatePrecisionDecoration(node->getType());
   2493 
   2494     spv::Builder::TextureParameters params = { };
   2495     params.sampler = arguments[0];
   2496 
   2497     glslang::TCrackedTextureOp cracked;
   2498     node->crackTexture(sampler, cracked);
   2499 
   2500     // Check for queries
   2501     if (cracked.query) {
   2502         // a sampled image needs to have the image extracted first
   2503         if (builder.isSampledImage(params.sampler))
   2504             params.sampler = builder.createUnaryOp(spv::OpImage, builder.getImageType(params.sampler), params.sampler);
   2505         switch (node->getOp()) {
   2506         case glslang::EOpImageQuerySize:
   2507         case glslang::EOpTextureQuerySize:
   2508             if (arguments.size() > 1) {
   2509                 params.lod = arguments[1];
   2510                 return builder.createTextureQueryCall(spv::OpImageQuerySizeLod, params);
   2511             } else
   2512                 return builder.createTextureQueryCall(spv::OpImageQuerySize, params);
   2513         case glslang::EOpImageQuerySamples:
   2514         case glslang::EOpTextureQuerySamples:
   2515             return builder.createTextureQueryCall(spv::OpImageQuerySamples, params);
   2516         case glslang::EOpTextureQueryLod:
   2517             params.coords = arguments[1];
   2518             return builder.createTextureQueryCall(spv::OpImageQueryLod, params);
   2519         case glslang::EOpTextureQueryLevels:
   2520             return builder.createTextureQueryCall(spv::OpImageQueryLevels, params);
   2521         case glslang::EOpSparseTexelsResident:
   2522             return builder.createUnaryOp(spv::OpImageSparseTexelsResident, builder.makeBoolType(), arguments[0]);
   2523         default:
   2524             assert(0);
   2525             break;
   2526         }
   2527     }
   2528 
   2529     // Check for image functions other than queries
   2530     if (node->isImage()) {
   2531         std::vector<spv::Id> operands;
   2532         auto opIt = arguments.begin();
   2533         operands.push_back(*(opIt++));
   2534 
   2535         // Handle subpass operations
   2536         // TODO: GLSL should change to have the "MS" only on the type rather than the
   2537         // built-in function.
   2538         if (cracked.subpass) {
   2539             // add on the (0,0) coordinate
   2540             spv::Id zero = builder.makeIntConstant(0);
   2541             std::vector<spv::Id> comps;
   2542             comps.push_back(zero);
   2543             comps.push_back(zero);
   2544             operands.push_back(builder.makeCompositeConstant(builder.makeVectorType(builder.makeIntType(32), 2), comps));
   2545             if (sampler.ms) {
   2546                 operands.push_back(spv::ImageOperandsSampleMask);
   2547                 operands.push_back(*(opIt++));
   2548             }
   2549             return builder.createOp(spv::OpImageRead, convertGlslangToSpvType(node->getType()), operands);
   2550         }
   2551 
   2552         operands.push_back(*(opIt++));
   2553         if (node->getOp() == glslang::EOpImageLoad) {
   2554             if (sampler.ms) {
   2555                 operands.push_back(spv::ImageOperandsSampleMask);
   2556                 operands.push_back(*opIt);
   2557             }
   2558             if (builder.getImageTypeFormat(builder.getImageType(operands.front())) == spv::ImageFormatUnknown)
   2559                 builder.addCapability(spv::CapabilityStorageImageReadWithoutFormat);
   2560             return builder.createOp(spv::OpImageRead, convertGlslangToSpvType(node->getType()), operands);
   2561         } else if (node->getOp() == glslang::EOpImageStore) {
   2562             if (sampler.ms) {
   2563                 operands.push_back(*(opIt + 1));
   2564                 operands.push_back(spv::ImageOperandsSampleMask);
   2565                 operands.push_back(*opIt);
   2566             } else
   2567                 operands.push_back(*opIt);
   2568             builder.createNoResultOp(spv::OpImageWrite, operands);
   2569             if (builder.getImageTypeFormat(builder.getImageType(operands.front())) == spv::ImageFormatUnknown)
   2570                 builder.addCapability(spv::CapabilityStorageImageWriteWithoutFormat);
   2571             return spv::NoResult;
   2572         } else if (node->getOp() == glslang::EOpSparseImageLoad) {
   2573             builder.addCapability(spv::CapabilitySparseResidency);
   2574             if (builder.getImageTypeFormat(builder.getImageType(operands.front())) == spv::ImageFormatUnknown)
   2575                 builder.addCapability(spv::CapabilityStorageImageReadWithoutFormat);
   2576 
   2577             if (sampler.ms) {
   2578                 operands.push_back(spv::ImageOperandsSampleMask);
   2579                 operands.push_back(*opIt++);
   2580             }
   2581 
   2582             // Create the return type that was a special structure
   2583             spv::Id texelOut = *opIt;
   2584             spv::Id typeId0 = convertGlslangToSpvType(node->getType());
   2585             spv::Id typeId1 = builder.getDerefTypeId(texelOut);
   2586             spv::Id resultTypeId = builder.makeStructResultType(typeId0, typeId1);
   2587 
   2588             spv::Id resultId = builder.createOp(spv::OpImageSparseRead, resultTypeId, operands);
   2589 
   2590             // Decode the return type
   2591             builder.createStore(builder.createCompositeExtract(resultId, typeId1, 1), texelOut);
   2592             return builder.createCompositeExtract(resultId, typeId0, 0);
   2593         } else {
   2594             // Process image atomic operations
   2595 
   2596             // GLSL "IMAGE_PARAMS" will involve in constructing an image texel pointer and this pointer,
   2597             // as the first source operand, is required by SPIR-V atomic operations.
   2598             operands.push_back(sampler.ms ? *(opIt++) : builder.makeUintConstant(0)); // For non-MS, the value should be 0
   2599 
   2600             spv::Id resultTypeId = builder.makePointer(spv::StorageClassImage, convertGlslangToSpvType(node->getType()));
   2601             spv::Id pointer = builder.createOp(spv::OpImageTexelPointer, resultTypeId, operands);
   2602 
   2603             std::vector<spv::Id> operands;
   2604             operands.push_back(pointer);
   2605             for (; opIt != arguments.end(); ++opIt)
   2606                 operands.push_back(*opIt);
   2607 
   2608             return createAtomicOperation(node->getOp(), precision, convertGlslangToSpvType(node->getType()), operands, node->getBasicType());
   2609         }
   2610     }
   2611 
   2612     // Check for texture functions other than queries
   2613     bool sparse = node->isSparseTexture();
   2614     bool cubeCompare = sampler.dim == glslang::EsdCube && sampler.arrayed && sampler.shadow;
   2615 
   2616     // check for bias argument
   2617     bool bias = false;
   2618     if (! cracked.lod && ! cracked.gather && ! cracked.grad && ! cracked.fetch && ! cubeCompare) {
   2619         int nonBiasArgCount = 2;
   2620         if (cracked.offset)
   2621             ++nonBiasArgCount;
   2622         if (cracked.grad)
   2623             nonBiasArgCount += 2;
   2624         if (cracked.lodClamp)
   2625             ++nonBiasArgCount;
   2626         if (sparse)
   2627             ++nonBiasArgCount;
   2628 
   2629         if ((int)arguments.size() > nonBiasArgCount)
   2630             bias = true;
   2631     }
   2632 
   2633     // See if the sampler param should really be just the SPV image part
   2634     if (cracked.fetch) {
   2635         // a fetch needs to have the image extracted first
   2636         if (builder.isSampledImage(params.sampler))
   2637             params.sampler = builder.createUnaryOp(spv::OpImage, builder.getImageType(params.sampler), params.sampler);
   2638     }
   2639 
   2640     // set the rest of the arguments
   2641 
   2642     params.coords = arguments[1];
   2643     int extraArgs = 0;
   2644     bool noImplicitLod = false;
   2645 
   2646     // sort out where Dref is coming from
   2647     if (cubeCompare) {
   2648         params.Dref = arguments[2];
   2649         ++extraArgs;
   2650     } else if (sampler.shadow && cracked.gather) {
   2651         params.Dref = arguments[2];
   2652         ++extraArgs;
   2653     } else if (sampler.shadow) {
   2654         std::vector<spv::Id> indexes;
   2655         int dRefComp;
   2656         if (cracked.proj)
   2657             dRefComp = 2;  // "The resulting 3rd component of P in the shadow forms is used as Dref"
   2658         else
   2659             dRefComp = builder.getNumComponents(params.coords) - 1;
   2660         indexes.push_back(dRefComp);
   2661         params.Dref = builder.createCompositeExtract(params.coords, builder.getScalarTypeId(builder.getTypeId(params.coords)), indexes);
   2662     }
   2663 
   2664     // lod
   2665     if (cracked.lod) {
   2666         params.lod = arguments[2];
   2667         ++extraArgs;
   2668     } else if (glslangIntermediate->getStage() != EShLangFragment) {
   2669         // we need to invent the default lod for an explicit lod instruction for a non-fragment stage
   2670         noImplicitLod = true;
   2671     }
   2672 
   2673     // multisample
   2674     if (sampler.ms) {
   2675         params.sample = arguments[2]; // For MS, "sample" should be specified
   2676         ++extraArgs;
   2677     }
   2678 
   2679     // gradient
   2680     if (cracked.grad) {
   2681         params.gradX = arguments[2 + extraArgs];
   2682         params.gradY = arguments[3 + extraArgs];
   2683         extraArgs += 2;
   2684     }
   2685 
   2686     // offset and offsets
   2687     if (cracked.offset) {
   2688         params.offset = arguments[2 + extraArgs];
   2689         ++extraArgs;
   2690     } else if (cracked.offsets) {
   2691         params.offsets = arguments[2 + extraArgs];
   2692         ++extraArgs;
   2693     }
   2694 
   2695     // lod clamp
   2696     if (cracked.lodClamp) {
   2697         params.lodClamp = arguments[2 + extraArgs];
   2698         ++extraArgs;
   2699     }
   2700 
   2701     // sparse
   2702     if (sparse) {
   2703         params.texelOut = arguments[2 + extraArgs];
   2704         ++extraArgs;
   2705     }
   2706 
   2707     // bias
   2708     if (bias) {
   2709         params.bias = arguments[2 + extraArgs];
   2710         ++extraArgs;
   2711     }
   2712 
   2713     // gather component
   2714     if (cracked.gather && ! sampler.shadow) {
   2715         // default component is 0, if missing, otherwise an argument
   2716         if (2 + extraArgs < (int)arguments.size()) {
   2717             params.component = arguments[2 + extraArgs];
   2718             ++extraArgs;
   2719         } else {
   2720             params.component = builder.makeIntConstant(0);
   2721         }
   2722     }
   2723 
   2724     // projective component (might not to move)
   2725     // GLSL: "The texture coordinates consumed from P, not including the last component of P,
   2726     //       are divided by the last component of P."
   2727     // SPIR-V:  "... (u [, v] [, w], q)... It may be a vector larger than needed, but all
   2728     //          unused components will appear after all used components."
   2729     if (cracked.proj) {
   2730         int projSourceComp = builder.getNumComponents(params.coords) - 1;
   2731         int projTargetComp;
   2732         switch (sampler.dim) {
   2733         case glslang::Esd1D:   projTargetComp = 1;              break;
   2734         case glslang::Esd2D:   projTargetComp = 2;              break;
   2735         case glslang::EsdRect: projTargetComp = 2;              break;
   2736         default:               projTargetComp = projSourceComp; break;
   2737         }
   2738         // copy the projective coordinate if we have to
   2739         if (projTargetComp != projSourceComp) {
   2740             spv::Id projComp = builder.createCompositeExtract(params.coords,
   2741                                                               builder.getScalarTypeId(builder.getTypeId(params.coords)),
   2742                                                               projSourceComp);
   2743             params.coords = builder.createCompositeInsert(projComp, params.coords,
   2744                                                           builder.getTypeId(params.coords), projTargetComp);
   2745         }
   2746     }
   2747 
   2748     return builder.createTextureCall(precision, convertGlslangToSpvType(node->getType()), sparse, cracked.fetch, cracked.proj, cracked.gather, noImplicitLod, params);
   2749 }
   2750 
   2751 spv::Id TGlslangToSpvTraverser::handleUserFunctionCall(const glslang::TIntermAggregate* node)
   2752 {
   2753     // Grab the function's pointer from the previously created function
   2754     spv::Function* function = functionMap[node->getName().c_str()];
   2755     if (! function)
   2756         return 0;
   2757 
   2758     const glslang::TIntermSequence& glslangArgs = node->getSequence();
   2759     const glslang::TQualifierList& qualifiers = node->getQualifierList();
   2760 
   2761     //  See comments in makeFunctions() for details about the semantics for parameter passing.
   2762     //
   2763     // These imply we need a four step process:
   2764     // 1. Evaluate the arguments
   2765     // 2. Allocate and make copies of in, out, and inout arguments
   2766     // 3. Make the call
   2767     // 4. Copy back the results
   2768 
   2769     // 1. Evaluate the arguments
   2770     std::vector<spv::Builder::AccessChain> lValues;
   2771     std::vector<spv::Id> rValues;
   2772     std::vector<const glslang::TType*> argTypes;
   2773     for (int a = 0; a < (int)glslangArgs.size(); ++a) {
   2774         const glslang::TType& paramType = glslangArgs[a]->getAsTyped()->getType();
   2775         // build l-value
   2776         builder.clearAccessChain();
   2777         glslangArgs[a]->traverse(this);
   2778         argTypes.push_back(&paramType);
   2779         // keep outputs as and opaque objects l-values, evaluate input-only as r-values
   2780         if (qualifiers[a] != glslang::EvqConstReadOnly || paramType.isOpaque()) {
   2781             // save l-value
   2782             lValues.push_back(builder.getAccessChain());
   2783         } else {
   2784             // process r-value
   2785             rValues.push_back(accessChainLoad(*argTypes.back()));
   2786         }
   2787     }
   2788 
   2789     // 2. Allocate space for anything needing a copy, and if it's "in" or "inout"
   2790     // copy the original into that space.
   2791     //
   2792     // Also, build up the list of actual arguments to pass in for the call
   2793     int lValueCount = 0;
   2794     int rValueCount = 0;
   2795     std::vector<spv::Id> spvArgs;
   2796     for (int a = 0; a < (int)glslangArgs.size(); ++a) {
   2797         const glslang::TType& paramType = glslangArgs[a]->getAsTyped()->getType();
   2798         spv::Id arg;
   2799         if (paramType.isOpaque()) {
   2800             builder.setAccessChain(lValues[lValueCount]);
   2801             arg = builder.accessChainGetLValue();
   2802             ++lValueCount;
   2803         } else if (qualifiers[a] != glslang::EvqConstReadOnly) {
   2804             // need space to hold the copy
   2805             arg = builder.createVariable(spv::StorageClassFunction, convertGlslangToSpvType(paramType), "param");
   2806             if (qualifiers[a] == glslang::EvqIn || qualifiers[a] == glslang::EvqInOut) {
   2807                 // need to copy the input into output space
   2808                 builder.setAccessChain(lValues[lValueCount]);
   2809                 spv::Id copy = accessChainLoad(*argTypes[a]);
   2810                 builder.createStore(copy, arg);
   2811             }
   2812             ++lValueCount;
   2813         } else {
   2814             arg = rValues[rValueCount];
   2815             ++rValueCount;
   2816         }
   2817         spvArgs.push_back(arg);
   2818     }
   2819 
   2820     // 3. Make the call.
   2821     spv::Id result = builder.createFunctionCall(function, spvArgs);
   2822     builder.setPrecision(result, TranslatePrecisionDecoration(node->getType()));
   2823 
   2824     // 4. Copy back out an "out" arguments.
   2825     lValueCount = 0;
   2826     for (int a = 0; a < (int)glslangArgs.size(); ++a) {
   2827         if (qualifiers[a] != glslang::EvqConstReadOnly) {
   2828             if (qualifiers[a] == glslang::EvqOut || qualifiers[a] == glslang::EvqInOut) {
   2829                 spv::Id copy = builder.createLoad(spvArgs[a]);
   2830                 builder.setAccessChain(lValues[lValueCount]);
   2831                 accessChainStore(glslangArgs[a]->getAsTyped()->getType(), copy);
   2832             }
   2833             ++lValueCount;
   2834         }
   2835     }
   2836 
   2837     return result;
   2838 }
   2839 
   2840 // Translate AST operation to SPV operation, already having SPV-based operands/types.
   2841 spv::Id TGlslangToSpvTraverser::createBinaryOperation(glslang::TOperator op, spv::Decoration precision,
   2842                                                       spv::Decoration noContraction,
   2843                                                       spv::Id typeId, spv::Id left, spv::Id right,
   2844                                                       glslang::TBasicType typeProxy, bool reduceComparison)
   2845 {
   2846     bool isUnsigned = typeProxy == glslang::EbtUint || typeProxy == glslang::EbtUint64;
   2847     bool isFloat = typeProxy == glslang::EbtFloat || typeProxy == glslang::EbtDouble;
   2848     bool isBool = typeProxy == glslang::EbtBool;
   2849 
   2850     spv::Op binOp = spv::OpNop;
   2851     bool needMatchingVectors = true;  // for non-matrix ops, would a scalar need to smear to match a vector?
   2852     bool comparison = false;
   2853 
   2854     switch (op) {
   2855     case glslang::EOpAdd:
   2856     case glslang::EOpAddAssign:
   2857         if (isFloat)
   2858             binOp = spv::OpFAdd;
   2859         else
   2860             binOp = spv::OpIAdd;
   2861         break;
   2862     case glslang::EOpSub:
   2863     case glslang::EOpSubAssign:
   2864         if (isFloat)
   2865             binOp = spv::OpFSub;
   2866         else
   2867             binOp = spv::OpISub;
   2868         break;
   2869     case glslang::EOpMul:
   2870     case glslang::EOpMulAssign:
   2871         if (isFloat)
   2872             binOp = spv::OpFMul;
   2873         else
   2874             binOp = spv::OpIMul;
   2875         break;
   2876     case glslang::EOpVectorTimesScalar:
   2877     case glslang::EOpVectorTimesScalarAssign:
   2878         if (isFloat && (builder.isVector(left) || builder.isVector(right))) {
   2879             if (builder.isVector(right))
   2880                 std::swap(left, right);
   2881             assert(builder.isScalar(right));
   2882             needMatchingVectors = false;
   2883             binOp = spv::OpVectorTimesScalar;
   2884         } else
   2885             binOp = spv::OpIMul;
   2886         break;
   2887     case glslang::EOpVectorTimesMatrix:
   2888     case glslang::EOpVectorTimesMatrixAssign:
   2889         binOp = spv::OpVectorTimesMatrix;
   2890         break;
   2891     case glslang::EOpMatrixTimesVector:
   2892         binOp = spv::OpMatrixTimesVector;
   2893         break;
   2894     case glslang::EOpMatrixTimesScalar:
   2895     case glslang::EOpMatrixTimesScalarAssign:
   2896         binOp = spv::OpMatrixTimesScalar;
   2897         break;
   2898     case glslang::EOpMatrixTimesMatrix:
   2899     case glslang::EOpMatrixTimesMatrixAssign:
   2900         binOp = spv::OpMatrixTimesMatrix;
   2901         break;
   2902     case glslang::EOpOuterProduct:
   2903         binOp = spv::OpOuterProduct;
   2904         needMatchingVectors = false;
   2905         break;
   2906 
   2907     case glslang::EOpDiv:
   2908     case glslang::EOpDivAssign:
   2909         if (isFloat)
   2910             binOp = spv::OpFDiv;
   2911         else if (isUnsigned)
   2912             binOp = spv::OpUDiv;
   2913         else
   2914             binOp = spv::OpSDiv;
   2915         break;
   2916     case glslang::EOpMod:
   2917     case glslang::EOpModAssign:
   2918         if (isFloat)
   2919             binOp = spv::OpFMod;
   2920         else if (isUnsigned)
   2921             binOp = spv::OpUMod;
   2922         else
   2923             binOp = spv::OpSMod;
   2924         break;
   2925     case glslang::EOpRightShift:
   2926     case glslang::EOpRightShiftAssign:
   2927         if (isUnsigned)
   2928             binOp = spv::OpShiftRightLogical;
   2929         else
   2930             binOp = spv::OpShiftRightArithmetic;
   2931         break;
   2932     case glslang::EOpLeftShift:
   2933     case glslang::EOpLeftShiftAssign:
   2934         binOp = spv::OpShiftLeftLogical;
   2935         break;
   2936     case glslang::EOpAnd:
   2937     case glslang::EOpAndAssign:
   2938         binOp = spv::OpBitwiseAnd;
   2939         break;
   2940     case glslang::EOpLogicalAnd:
   2941         needMatchingVectors = false;
   2942         binOp = spv::OpLogicalAnd;
   2943         break;
   2944     case glslang::EOpInclusiveOr:
   2945     case glslang::EOpInclusiveOrAssign:
   2946         binOp = spv::OpBitwiseOr;
   2947         break;
   2948     case glslang::EOpLogicalOr:
   2949         needMatchingVectors = false;
   2950         binOp = spv::OpLogicalOr;
   2951         break;
   2952     case glslang::EOpExclusiveOr:
   2953     case glslang::EOpExclusiveOrAssign:
   2954         binOp = spv::OpBitwiseXor;
   2955         break;
   2956     case glslang::EOpLogicalXor:
   2957         needMatchingVectors = false;
   2958         binOp = spv::OpLogicalNotEqual;
   2959         break;
   2960 
   2961     case glslang::EOpLessThan:
   2962     case glslang::EOpGreaterThan:
   2963     case glslang::EOpLessThanEqual:
   2964     case glslang::EOpGreaterThanEqual:
   2965     case glslang::EOpEqual:
   2966     case glslang::EOpNotEqual:
   2967     case glslang::EOpVectorEqual:
   2968     case glslang::EOpVectorNotEqual:
   2969         comparison = true;
   2970         break;
   2971     default:
   2972         break;
   2973     }
   2974 
   2975     // handle mapped binary operations (should be non-comparison)
   2976     if (binOp != spv::OpNop) {
   2977         assert(comparison == false);
   2978         if (builder.isMatrix(left) || builder.isMatrix(right))
   2979             return createBinaryMatrixOperation(binOp, precision, noContraction, typeId, left, right);
   2980 
   2981         // No matrix involved; make both operands be the same number of components, if needed
   2982         if (needMatchingVectors)
   2983             builder.promoteScalar(precision, left, right);
   2984 
   2985         spv::Id result = builder.createBinOp(binOp, typeId, left, right);
   2986         addDecoration(result, noContraction);
   2987         return builder.setPrecision(result, precision);
   2988     }
   2989 
   2990     if (! comparison)
   2991         return 0;
   2992 
   2993     // Handle comparison instructions
   2994 
   2995     if (reduceComparison && (builder.isVector(left) || builder.isMatrix(left) || builder.isAggregate(left))) {
   2996         assert(op == glslang::EOpEqual || op == glslang::EOpNotEqual);
   2997 
   2998         return builder.createCompositeCompare(precision, left, right, op == glslang::EOpEqual);
   2999     }
   3000 
   3001     switch (op) {
   3002     case glslang::EOpLessThan:
   3003         if (isFloat)
   3004             binOp = spv::OpFOrdLessThan;
   3005         else if (isUnsigned)
   3006             binOp = spv::OpULessThan;
   3007         else
   3008             binOp = spv::OpSLessThan;
   3009         break;
   3010     case glslang::EOpGreaterThan:
   3011         if (isFloat)
   3012             binOp = spv::OpFOrdGreaterThan;
   3013         else if (isUnsigned)
   3014             binOp = spv::OpUGreaterThan;
   3015         else
   3016             binOp = spv::OpSGreaterThan;
   3017         break;
   3018     case glslang::EOpLessThanEqual:
   3019         if (isFloat)
   3020             binOp = spv::OpFOrdLessThanEqual;
   3021         else if (isUnsigned)
   3022             binOp = spv::OpULessThanEqual;
   3023         else
   3024             binOp = spv::OpSLessThanEqual;
   3025         break;
   3026     case glslang::EOpGreaterThanEqual:
   3027         if (isFloat)
   3028             binOp = spv::OpFOrdGreaterThanEqual;
   3029         else if (isUnsigned)
   3030             binOp = spv::OpUGreaterThanEqual;
   3031         else
   3032             binOp = spv::OpSGreaterThanEqual;
   3033         break;
   3034     case glslang::EOpEqual:
   3035     case glslang::EOpVectorEqual:
   3036         if (isFloat)
   3037             binOp = spv::OpFOrdEqual;
   3038         else if (isBool)
   3039             binOp = spv::OpLogicalEqual;
   3040         else
   3041             binOp = spv::OpIEqual;
   3042         break;
   3043     case glslang::EOpNotEqual:
   3044     case glslang::EOpVectorNotEqual:
   3045         if (isFloat)
   3046             binOp = spv::OpFOrdNotEqual;
   3047         else if (isBool)
   3048             binOp = spv::OpLogicalNotEqual;
   3049         else
   3050             binOp = spv::OpINotEqual;
   3051         break;
   3052     default:
   3053         break;
   3054     }
   3055 
   3056     if (binOp != spv::OpNop) {
   3057         spv::Id result = builder.createBinOp(binOp, typeId, left, right);
   3058         addDecoration(result, noContraction);
   3059         return builder.setPrecision(result, precision);
   3060     }
   3061 
   3062     return 0;
   3063 }
   3064 
   3065 //
   3066 // Translate AST matrix operation to SPV operation, already having SPV-based operands/types.
   3067 // These can be any of:
   3068 //
   3069 //   matrix * scalar
   3070 //   scalar * matrix
   3071 //   matrix * matrix     linear algebraic
   3072 //   matrix * vector
   3073 //   vector * matrix
   3074 //   matrix * matrix     componentwise
   3075 //   matrix op matrix    op in {+, -, /}
   3076 //   matrix op scalar    op in {+, -, /}
   3077 //   scalar op matrix    op in {+, -, /}
   3078 //
   3079 spv::Id TGlslangToSpvTraverser::createBinaryMatrixOperation(spv::Op op, spv::Decoration precision, spv::Decoration noContraction, spv::Id typeId, spv::Id left, spv::Id right)
   3080 {
   3081     bool firstClass = true;
   3082 
   3083     // First, handle first-class matrix operations (* and matrix/scalar)
   3084     switch (op) {
   3085     case spv::OpFDiv:
   3086         if (builder.isMatrix(left) && builder.isScalar(right)) {
   3087             // turn matrix / scalar into a multiply...
   3088             right = builder.createBinOp(spv::OpFDiv, builder.getTypeId(right), builder.makeFloatConstant(1.0F), right);
   3089             op = spv::OpMatrixTimesScalar;
   3090         } else
   3091             firstClass = false;
   3092         break;
   3093     case spv::OpMatrixTimesScalar:
   3094         if (builder.isMatrix(right))
   3095             std::swap(left, right);
   3096         assert(builder.isScalar(right));
   3097         break;
   3098     case spv::OpVectorTimesMatrix:
   3099         assert(builder.isVector(left));
   3100         assert(builder.isMatrix(right));
   3101         break;
   3102     case spv::OpMatrixTimesVector:
   3103         assert(builder.isMatrix(left));
   3104         assert(builder.isVector(right));
   3105         break;
   3106     case spv::OpMatrixTimesMatrix:
   3107         assert(builder.isMatrix(left));
   3108         assert(builder.isMatrix(right));
   3109         break;
   3110     default:
   3111         firstClass = false;
   3112         break;
   3113     }
   3114 
   3115     if (firstClass) {
   3116         spv::Id result = builder.createBinOp(op, typeId, left, right);
   3117         addDecoration(result, noContraction);
   3118         return builder.setPrecision(result, precision);
   3119     }
   3120 
   3121     // Handle component-wise +, -, *, %, and / for all combinations of type.
   3122     // The result type of all of them is the same type as the (a) matrix operand.
   3123     // The algorithm is to:
   3124     //   - break the matrix(es) into vectors
   3125     //   - smear any scalar to a vector
   3126     //   - do vector operations
   3127     //   - make a matrix out the vector results
   3128     switch (op) {
   3129     case spv::OpFAdd:
   3130     case spv::OpFSub:
   3131     case spv::OpFDiv:
   3132     case spv::OpFMod:
   3133     case spv::OpFMul:
   3134     {
   3135         // one time set up...
   3136         bool  leftMat = builder.isMatrix(left);
   3137         bool rightMat = builder.isMatrix(right);
   3138         unsigned int numCols = leftMat ? builder.getNumColumns(left) : builder.getNumColumns(right);
   3139         int numRows = leftMat ? builder.getNumRows(left) : builder.getNumRows(right);
   3140         spv::Id scalarType = builder.getScalarTypeId(typeId);
   3141         spv::Id vecType = builder.makeVectorType(scalarType, numRows);
   3142         std::vector<spv::Id> results;
   3143         spv::Id smearVec = spv::NoResult;
   3144         if (builder.isScalar(left))
   3145             smearVec = builder.smearScalar(precision, left, vecType);
   3146         else if (builder.isScalar(right))
   3147             smearVec = builder.smearScalar(precision, right, vecType);
   3148 
   3149         // do each vector op
   3150         for (unsigned int c = 0; c < numCols; ++c) {
   3151             std::vector<unsigned int> indexes;
   3152             indexes.push_back(c);
   3153             spv::Id  leftVec =  leftMat ? builder.createCompositeExtract( left, vecType, indexes) : smearVec;
   3154             spv::Id rightVec = rightMat ? builder.createCompositeExtract(right, vecType, indexes) : smearVec;
   3155             spv::Id result = builder.createBinOp(op, vecType, leftVec, rightVec);
   3156             addDecoration(result, noContraction);
   3157             results.push_back(builder.setPrecision(result, precision));
   3158         }
   3159 
   3160         // put the pieces together
   3161         return  builder.setPrecision(builder.createCompositeConstruct(typeId, results), precision);
   3162     }
   3163     default:
   3164         assert(0);
   3165         return spv::NoResult;
   3166     }
   3167 }
   3168 
   3169 spv::Id TGlslangToSpvTraverser::createUnaryOperation(glslang::TOperator op, spv::Decoration precision, spv::Decoration noContraction, spv::Id typeId, spv::Id operand, glslang::TBasicType typeProxy)
   3170 {
   3171     spv::Op unaryOp = spv::OpNop;
   3172     int libCall = -1;
   3173     bool isUnsigned = typeProxy == glslang::EbtUint || typeProxy == glslang::EbtUint64;
   3174     bool isFloat = typeProxy == glslang::EbtFloat || typeProxy == glslang::EbtDouble;
   3175 
   3176     switch (op) {
   3177     case glslang::EOpNegative:
   3178         if (isFloat) {
   3179             unaryOp = spv::OpFNegate;
   3180             if (builder.isMatrixType(typeId))
   3181                 return createUnaryMatrixOperation(unaryOp, precision, noContraction, typeId, operand, typeProxy);
   3182         } else
   3183             unaryOp = spv::OpSNegate;
   3184         break;
   3185 
   3186     case glslang::EOpLogicalNot:
   3187     case glslang::EOpVectorLogicalNot:
   3188         unaryOp = spv::OpLogicalNot;
   3189         break;
   3190     case glslang::EOpBitwiseNot:
   3191         unaryOp = spv::OpNot;
   3192         break;
   3193 
   3194     case glslang::EOpDeterminant:
   3195         libCall = spv::GLSLstd450Determinant;
   3196         break;
   3197     case glslang::EOpMatrixInverse:
   3198         libCall = spv::GLSLstd450MatrixInverse;
   3199         break;
   3200     case glslang::EOpTranspose:
   3201         unaryOp = spv::OpTranspose;
   3202         break;
   3203 
   3204     case glslang::EOpRadians:
   3205         libCall = spv::GLSLstd450Radians;
   3206         break;
   3207     case glslang::EOpDegrees:
   3208         libCall = spv::GLSLstd450Degrees;
   3209         break;
   3210     case glslang::EOpSin:
   3211         libCall = spv::GLSLstd450Sin;
   3212         break;
   3213     case glslang::EOpCos:
   3214         libCall = spv::GLSLstd450Cos;
   3215         break;
   3216     case glslang::EOpTan:
   3217         libCall = spv::GLSLstd450Tan;
   3218         break;
   3219     case glslang::EOpAcos:
   3220         libCall = spv::GLSLstd450Acos;
   3221         break;
   3222     case glslang::EOpAsin:
   3223         libCall = spv::GLSLstd450Asin;
   3224         break;
   3225     case glslang::EOpAtan:
   3226         libCall = spv::GLSLstd450Atan;
   3227         break;
   3228 
   3229     case glslang::EOpAcosh:
   3230         libCall = spv::GLSLstd450Acosh;
   3231         break;
   3232     case glslang::EOpAsinh:
   3233         libCall = spv::GLSLstd450Asinh;
   3234         break;
   3235     case glslang::EOpAtanh:
   3236         libCall = spv::GLSLstd450Atanh;
   3237         break;
   3238     case glslang::EOpTanh:
   3239         libCall = spv::GLSLstd450Tanh;
   3240         break;
   3241     case glslang::EOpCosh:
   3242         libCall = spv::GLSLstd450Cosh;
   3243         break;
   3244     case glslang::EOpSinh:
   3245         libCall = spv::GLSLstd450Sinh;
   3246         break;
   3247 
   3248     case glslang::EOpLength:
   3249         libCall = spv::GLSLstd450Length;
   3250         break;
   3251     case glslang::EOpNormalize:
   3252         libCall = spv::GLSLstd450Normalize;
   3253         break;
   3254 
   3255     case glslang::EOpExp:
   3256         libCall = spv::GLSLstd450Exp;
   3257         break;
   3258     case glslang::EOpLog:
   3259         libCall = spv::GLSLstd450Log;
   3260         break;
   3261     case glslang::EOpExp2:
   3262         libCall = spv::GLSLstd450Exp2;
   3263         break;
   3264     case glslang::EOpLog2:
   3265         libCall = spv::GLSLstd450Log2;
   3266         break;
   3267     case glslang::EOpSqrt:
   3268         libCall = spv::GLSLstd450Sqrt;
   3269         break;
   3270     case glslang::EOpInverseSqrt:
   3271         libCall = spv::GLSLstd450InverseSqrt;
   3272         break;
   3273 
   3274     case glslang::EOpFloor:
   3275         libCall = spv::GLSLstd450Floor;
   3276         break;
   3277     case glslang::EOpTrunc:
   3278         libCall = spv::GLSLstd450Trunc;
   3279         break;
   3280     case glslang::EOpRound:
   3281         libCall = spv::GLSLstd450Round;
   3282         break;
   3283     case glslang::EOpRoundEven:
   3284         libCall = spv::GLSLstd450RoundEven;
   3285         break;
   3286     case glslang::EOpCeil:
   3287         libCall = spv::GLSLstd450Ceil;
   3288         break;
   3289     case glslang::EOpFract:
   3290         libCall = spv::GLSLstd450Fract;
   3291         break;
   3292 
   3293     case glslang::EOpIsNan:
   3294         unaryOp = spv::OpIsNan;
   3295         break;
   3296     case glslang::EOpIsInf:
   3297         unaryOp = spv::OpIsInf;
   3298         break;
   3299     case glslang::EOpIsFinite:
   3300         unaryOp = spv::OpIsFinite;
   3301         break;
   3302 
   3303     case glslang::EOpFloatBitsToInt:
   3304     case glslang::EOpFloatBitsToUint:
   3305     case glslang::EOpIntBitsToFloat:
   3306     case glslang::EOpUintBitsToFloat:
   3307     case glslang::EOpDoubleBitsToInt64:
   3308     case glslang::EOpDoubleBitsToUint64:
   3309     case glslang::EOpInt64BitsToDouble:
   3310     case glslang::EOpUint64BitsToDouble:
   3311         unaryOp = spv::OpBitcast;
   3312         break;
   3313 
   3314     case glslang::EOpPackSnorm2x16:
   3315         libCall = spv::GLSLstd450PackSnorm2x16;
   3316         break;
   3317     case glslang::EOpUnpackSnorm2x16:
   3318         libCall = spv::GLSLstd450UnpackSnorm2x16;
   3319         break;
   3320     case glslang::EOpPackUnorm2x16:
   3321         libCall = spv::GLSLstd450PackUnorm2x16;
   3322         break;
   3323     case glslang::EOpUnpackUnorm2x16:
   3324         libCall = spv::GLSLstd450UnpackUnorm2x16;
   3325         break;
   3326     case glslang::EOpPackHalf2x16:
   3327         libCall = spv::GLSLstd450PackHalf2x16;
   3328         break;
   3329     case glslang::EOpUnpackHalf2x16:
   3330         libCall = spv::GLSLstd450UnpackHalf2x16;
   3331         break;
   3332     case glslang::EOpPackSnorm4x8:
   3333         libCall = spv::GLSLstd450PackSnorm4x8;
   3334         break;
   3335     case glslang::EOpUnpackSnorm4x8:
   3336         libCall = spv::GLSLstd450UnpackSnorm4x8;
   3337         break;
   3338     case glslang::EOpPackUnorm4x8:
   3339         libCall = spv::GLSLstd450PackUnorm4x8;
   3340         break;
   3341     case glslang::EOpUnpackUnorm4x8:
   3342         libCall = spv::GLSLstd450UnpackUnorm4x8;
   3343         break;
   3344     case glslang::EOpPackDouble2x32:
   3345         libCall = spv::GLSLstd450PackDouble2x32;
   3346         break;
   3347     case glslang::EOpUnpackDouble2x32:
   3348         libCall = spv::GLSLstd450UnpackDouble2x32;
   3349         break;
   3350 
   3351     case glslang::EOpPackInt2x32:
   3352     case glslang::EOpUnpackInt2x32:
   3353     case glslang::EOpPackUint2x32:
   3354     case glslang::EOpUnpackUint2x32:
   3355         logger->missingFunctionality("shader int64");
   3356         libCall = spv::GLSLstd450Bad; // TODO: This is a placeholder.
   3357         break;
   3358 
   3359     case glslang::EOpDPdx:
   3360         unaryOp = spv::OpDPdx;
   3361         break;
   3362     case glslang::EOpDPdy:
   3363         unaryOp = spv::OpDPdy;
   3364         break;
   3365     case glslang::EOpFwidth:
   3366         unaryOp = spv::OpFwidth;
   3367         break;
   3368     case glslang::EOpDPdxFine:
   3369         builder.addCapability(spv::CapabilityDerivativeControl);
   3370         unaryOp = spv::OpDPdxFine;
   3371         break;
   3372     case glslang::EOpDPdyFine:
   3373         builder.addCapability(spv::CapabilityDerivativeControl);
   3374         unaryOp = spv::OpDPdyFine;
   3375         break;
   3376     case glslang::EOpFwidthFine:
   3377         builder.addCapability(spv::CapabilityDerivativeControl);
   3378         unaryOp = spv::OpFwidthFine;
   3379         break;
   3380     case glslang::EOpDPdxCoarse:
   3381         builder.addCapability(spv::CapabilityDerivativeControl);
   3382         unaryOp = spv::OpDPdxCoarse;
   3383         break;
   3384     case glslang::EOpDPdyCoarse:
   3385         builder.addCapability(spv::CapabilityDerivativeControl);
   3386         unaryOp = spv::OpDPdyCoarse;
   3387         break;
   3388     case glslang::EOpFwidthCoarse:
   3389         builder.addCapability(spv::CapabilityDerivativeControl);
   3390         unaryOp = spv::OpFwidthCoarse;
   3391         break;
   3392     case glslang::EOpInterpolateAtCentroid:
   3393         builder.addCapability(spv::CapabilityInterpolationFunction);
   3394         libCall = spv::GLSLstd450InterpolateAtCentroid;
   3395         break;
   3396     case glslang::EOpAny:
   3397         unaryOp = spv::OpAny;
   3398         break;
   3399     case glslang::EOpAll:
   3400         unaryOp = spv::OpAll;
   3401         break;
   3402 
   3403     case glslang::EOpAbs:
   3404         if (isFloat)
   3405             libCall = spv::GLSLstd450FAbs;
   3406         else
   3407             libCall = spv::GLSLstd450SAbs;
   3408         break;
   3409     case glslang::EOpSign:
   3410         if (isFloat)
   3411             libCall = spv::GLSLstd450FSign;
   3412         else
   3413             libCall = spv::GLSLstd450SSign;
   3414         break;
   3415 
   3416     case glslang::EOpAtomicCounterIncrement:
   3417     case glslang::EOpAtomicCounterDecrement:
   3418     case glslang::EOpAtomicCounter:
   3419     {
   3420         // Handle all of the atomics in one place, in createAtomicOperation()
   3421         std::vector<spv::Id> operands;
   3422         operands.push_back(operand);
   3423         return createAtomicOperation(op, precision, typeId, operands, typeProxy);
   3424     }
   3425 
   3426     case glslang::EOpBitFieldReverse:
   3427         unaryOp = spv::OpBitReverse;
   3428         break;
   3429     case glslang::EOpBitCount:
   3430         unaryOp = spv::OpBitCount;
   3431         break;
   3432     case glslang::EOpFindLSB:
   3433         libCall = spv::GLSLstd450FindILsb;
   3434         break;
   3435     case glslang::EOpFindMSB:
   3436         if (isUnsigned)
   3437             libCall = spv::GLSLstd450FindUMsb;
   3438         else
   3439             libCall = spv::GLSLstd450FindSMsb;
   3440         break;
   3441 
   3442     case glslang::EOpBallot:
   3443     case glslang::EOpReadFirstInvocation:
   3444         logger->missingFunctionality("shader ballot");
   3445         libCall = spv::GLSLstd450Bad;
   3446         break;
   3447 
   3448     case glslang::EOpAnyInvocation:
   3449     case glslang::EOpAllInvocations:
   3450     case glslang::EOpAllInvocationsEqual:
   3451         return createInvocationsOperation(op, typeId, operand);
   3452 
   3453     default:
   3454         return 0;
   3455     }
   3456 
   3457     spv::Id id;
   3458     if (libCall >= 0) {
   3459         std::vector<spv::Id> args;
   3460         args.push_back(operand);
   3461         id = builder.createBuiltinCall(typeId, stdBuiltins, libCall, args);
   3462     } else {
   3463         id = builder.createUnaryOp(unaryOp, typeId, operand);
   3464     }
   3465 
   3466     addDecoration(id, noContraction);
   3467     return builder.setPrecision(id, precision);
   3468 }
   3469 
   3470 // Create a unary operation on a matrix
   3471 spv::Id TGlslangToSpvTraverser::createUnaryMatrixOperation(spv::Op op, spv::Decoration precision, spv::Decoration noContraction, spv::Id typeId, spv::Id operand, glslang::TBasicType /* typeProxy */)
   3472 {
   3473     // Handle unary operations vector by vector.
   3474     // The result type is the same type as the original type.
   3475     // The algorithm is to:
   3476     //   - break the matrix into vectors
   3477     //   - apply the operation to each vector
   3478     //   - make a matrix out the vector results
   3479 
   3480     // get the types sorted out
   3481     int numCols = builder.getNumColumns(operand);
   3482     int numRows = builder.getNumRows(operand);
   3483     spv::Id srcVecType  = builder.makeVectorType(builder.getScalarTypeId(builder.getTypeId(operand)), numRows);
   3484     spv::Id destVecType = builder.makeVectorType(builder.getScalarTypeId(typeId), numRows);
   3485     std::vector<spv::Id> results;
   3486 
   3487     // do each vector op
   3488     for (int c = 0; c < numCols; ++c) {
   3489         std::vector<unsigned int> indexes;
   3490         indexes.push_back(c);
   3491         spv::Id srcVec  = builder.createCompositeExtract(operand, srcVecType, indexes);
   3492         spv::Id destVec = builder.createUnaryOp(op, destVecType, srcVec);
   3493         addDecoration(destVec, noContraction);
   3494         results.push_back(builder.setPrecision(destVec, precision));
   3495     }
   3496 
   3497     // put the pieces together
   3498     return builder.setPrecision(builder.createCompositeConstruct(typeId, results), precision);
   3499 }
   3500 
   3501 spv::Id TGlslangToSpvTraverser::createConversion(glslang::TOperator op, spv::Decoration precision, spv::Decoration noContraction, spv::Id destType, spv::Id operand, glslang::TBasicType typeProxy)
   3502 {
   3503     spv::Op convOp = spv::OpNop;
   3504     spv::Id zero = 0;
   3505     spv::Id one = 0;
   3506     spv::Id type = 0;
   3507 
   3508     int vectorSize = builder.isVectorType(destType) ? builder.getNumTypeComponents(destType) : 0;
   3509 
   3510     switch (op) {
   3511     case glslang::EOpConvIntToBool:
   3512     case glslang::EOpConvUintToBool:
   3513     case glslang::EOpConvInt64ToBool:
   3514     case glslang::EOpConvUint64ToBool:
   3515         zero = (op == glslang::EOpConvInt64ToBool ||
   3516                 op == glslang::EOpConvUint64ToBool) ? builder.makeUint64Constant(0) : builder.makeUintConstant(0);
   3517         zero = makeSmearedConstant(zero, vectorSize);
   3518         return builder.createBinOp(spv::OpINotEqual, destType, operand, zero);
   3519 
   3520     case glslang::EOpConvFloatToBool:
   3521         zero = builder.makeFloatConstant(0.0F);
   3522         zero = makeSmearedConstant(zero, vectorSize);
   3523         return builder.createBinOp(spv::OpFOrdNotEqual, destType, operand, zero);
   3524 
   3525     case glslang::EOpConvDoubleToBool:
   3526         zero = builder.makeDoubleConstant(0.0);
   3527         zero = makeSmearedConstant(zero, vectorSize);
   3528         return builder.createBinOp(spv::OpFOrdNotEqual, destType, operand, zero);
   3529 
   3530     case glslang::EOpConvBoolToFloat:
   3531         convOp = spv::OpSelect;
   3532         zero = builder.makeFloatConstant(0.0);
   3533         one  = builder.makeFloatConstant(1.0);
   3534         break;
   3535     case glslang::EOpConvBoolToDouble:
   3536         convOp = spv::OpSelect;
   3537         zero = builder.makeDoubleConstant(0.0);
   3538         one  = builder.makeDoubleConstant(1.0);
   3539         break;
   3540     case glslang::EOpConvBoolToInt:
   3541     case glslang::EOpConvBoolToInt64:
   3542         zero = (op == glslang::EOpConvBoolToInt64) ? builder.makeInt64Constant(0) : builder.makeIntConstant(0);
   3543         one  = (op == glslang::EOpConvBoolToInt64) ? builder.makeInt64Constant(1) : builder.makeIntConstant(1);
   3544         convOp = spv::OpSelect;
   3545         break;
   3546     case glslang::EOpConvBoolToUint:
   3547     case glslang::EOpConvBoolToUint64:
   3548         zero = (op == glslang::EOpConvBoolToUint64) ? builder.makeUint64Constant(0) : builder.makeUintConstant(0);
   3549         one  = (op == glslang::EOpConvBoolToUint64) ? builder.makeUint64Constant(1) : builder.makeUintConstant(1);
   3550         convOp = spv::OpSelect;
   3551         break;
   3552 
   3553     case glslang::EOpConvIntToFloat:
   3554     case glslang::EOpConvIntToDouble:
   3555     case glslang::EOpConvInt64ToFloat:
   3556     case glslang::EOpConvInt64ToDouble:
   3557         convOp = spv::OpConvertSToF;
   3558         break;
   3559 
   3560     case glslang::EOpConvUintToFloat:
   3561     case glslang::EOpConvUintToDouble:
   3562     case glslang::EOpConvUint64ToFloat:
   3563     case glslang::EOpConvUint64ToDouble:
   3564         convOp = spv::OpConvertUToF;
   3565         break;
   3566 
   3567     case glslang::EOpConvDoubleToFloat:
   3568     case glslang::EOpConvFloatToDouble:
   3569         convOp = spv::OpFConvert;
   3570         if (builder.isMatrixType(destType))
   3571             return createUnaryMatrixOperation(convOp, precision, noContraction, destType, operand, typeProxy);
   3572         break;
   3573 
   3574     case glslang::EOpConvFloatToInt:
   3575     case glslang::EOpConvDoubleToInt:
   3576     case glslang::EOpConvFloatToInt64:
   3577     case glslang::EOpConvDoubleToInt64:
   3578         convOp = spv::OpConvertFToS;
   3579         break;
   3580 
   3581     case glslang::EOpConvUintToInt:
   3582     case glslang::EOpConvIntToUint:
   3583     case glslang::EOpConvUint64ToInt64:
   3584     case glslang::EOpConvInt64ToUint64:
   3585         if (builder.isInSpecConstCodeGenMode()) {
   3586             // Build zero scalar or vector for OpIAdd.
   3587             zero = (op == glslang::EOpConvUintToInt64 ||
   3588                     op == glslang::EOpConvIntToUint64) ? builder.makeUint64Constant(0) : builder.makeUintConstant(0);
   3589             zero = makeSmearedConstant(zero, vectorSize);
   3590             // Use OpIAdd, instead of OpBitcast to do the conversion when
   3591             // generating for OpSpecConstantOp instruction.
   3592             return builder.createBinOp(spv::OpIAdd, destType, operand, zero);
   3593         }
   3594         // For normal run-time conversion instruction, use OpBitcast.
   3595         convOp = spv::OpBitcast;
   3596         break;
   3597 
   3598     case glslang::EOpConvFloatToUint:
   3599     case glslang::EOpConvDoubleToUint:
   3600     case glslang::EOpConvFloatToUint64:
   3601     case glslang::EOpConvDoubleToUint64:
   3602         convOp = spv::OpConvertFToU;
   3603         break;
   3604 
   3605     case glslang::EOpConvIntToInt64:
   3606     case glslang::EOpConvInt64ToInt:
   3607         convOp = spv::OpSConvert;
   3608         break;
   3609 
   3610     case glslang::EOpConvUintToUint64:
   3611     case glslang::EOpConvUint64ToUint:
   3612         convOp = spv::OpUConvert;
   3613         break;
   3614 
   3615     case glslang::EOpConvIntToUint64:
   3616     case glslang::EOpConvInt64ToUint:
   3617     case glslang::EOpConvUint64ToInt:
   3618     case glslang::EOpConvUintToInt64:
   3619         // OpSConvert/OpUConvert + OpBitCast
   3620         switch (op) {
   3621         case glslang::EOpConvIntToUint64:
   3622             convOp = spv::OpSConvert;
   3623             type   = builder.makeIntType(64);
   3624             break;
   3625         case glslang::EOpConvInt64ToUint:
   3626             convOp = spv::OpSConvert;
   3627             type   = builder.makeIntType(32);
   3628             break;
   3629         case glslang::EOpConvUint64ToInt:
   3630             convOp = spv::OpUConvert;
   3631             type   = builder.makeUintType(32);
   3632             break;
   3633         case glslang::EOpConvUintToInt64:
   3634             convOp = spv::OpUConvert;
   3635             type   = builder.makeUintType(64);
   3636             break;
   3637         default:
   3638             assert(0);
   3639             break;
   3640         }
   3641 
   3642         if (vectorSize > 0)
   3643             type = builder.makeVectorType(type, vectorSize);
   3644 
   3645         operand = builder.createUnaryOp(convOp, type, operand);
   3646 
   3647         if (builder.isInSpecConstCodeGenMode()) {
   3648             // Build zero scalar or vector for OpIAdd.
   3649             zero = (op == glslang::EOpConvIntToUint64 ||
   3650                     op == glslang::EOpConvUintToInt64) ? builder.makeUint64Constant(0) : builder.makeUintConstant(0);
   3651             zero = makeSmearedConstant(zero, vectorSize);
   3652             // Use OpIAdd, instead of OpBitcast to do the conversion when
   3653             // generating for OpSpecConstantOp instruction.
   3654             return builder.createBinOp(spv::OpIAdd, destType, operand, zero);
   3655         }
   3656         // For normal run-time conversion instruction, use OpBitcast.
   3657         convOp = spv::OpBitcast;
   3658         break;
   3659     default:
   3660         break;
   3661     }
   3662 
   3663     spv::Id result = 0;
   3664     if (convOp == spv::OpNop)
   3665         return result;
   3666 
   3667     if (convOp == spv::OpSelect) {
   3668         zero = makeSmearedConstant(zero, vectorSize);
   3669         one  = makeSmearedConstant(one, vectorSize);
   3670         result = builder.createTriOp(convOp, destType, operand, one, zero);
   3671     } else
   3672         result = builder.createUnaryOp(convOp, destType, operand);
   3673 
   3674     return builder.setPrecision(result, precision);
   3675 }
   3676 
   3677 spv::Id TGlslangToSpvTraverser::makeSmearedConstant(spv::Id constant, int vectorSize)
   3678 {
   3679     if (vectorSize == 0)
   3680         return constant;
   3681 
   3682     spv::Id vectorTypeId = builder.makeVectorType(builder.getTypeId(constant), vectorSize);
   3683     std::vector<spv::Id> components;
   3684     for (int c = 0; c < vectorSize; ++c)
   3685         components.push_back(constant);
   3686     return builder.makeCompositeConstant(vectorTypeId, components);
   3687 }
   3688 
   3689 // For glslang ops that map to SPV atomic opCodes
   3690 spv::Id TGlslangToSpvTraverser::createAtomicOperation(glslang::TOperator op, spv::Decoration /*precision*/, spv::Id typeId, std::vector<spv::Id>& operands, glslang::TBasicType typeProxy)
   3691 {
   3692     spv::Op opCode = spv::OpNop;
   3693 
   3694     switch (op) {
   3695     case glslang::EOpAtomicAdd:
   3696     case glslang::EOpImageAtomicAdd:
   3697         opCode = spv::OpAtomicIAdd;
   3698         break;
   3699     case glslang::EOpAtomicMin:
   3700     case glslang::EOpImageAtomicMin:
   3701         opCode = typeProxy == glslang::EbtUint ? spv::OpAtomicUMin : spv::OpAtomicSMin;
   3702         break;
   3703     case glslang::EOpAtomicMax:
   3704     case glslang::EOpImageAtomicMax:
   3705         opCode = typeProxy == glslang::EbtUint ? spv::OpAtomicUMax : spv::OpAtomicSMax;
   3706         break;
   3707     case glslang::EOpAtomicAnd:
   3708     case glslang::EOpImageAtomicAnd:
   3709         opCode = spv::OpAtomicAnd;
   3710         break;
   3711     case glslang::EOpAtomicOr:
   3712     case glslang::EOpImageAtomicOr:
   3713         opCode = spv::OpAtomicOr;
   3714         break;
   3715     case glslang::EOpAtomicXor:
   3716     case glslang::EOpImageAtomicXor:
   3717         opCode = spv::OpAtomicXor;
   3718         break;
   3719     case glslang::EOpAtomicExchange:
   3720     case glslang::EOpImageAtomicExchange:
   3721         opCode = spv::OpAtomicExchange;
   3722         break;
   3723     case glslang::EOpAtomicCompSwap:
   3724     case glslang::EOpImageAtomicCompSwap:
   3725         opCode = spv::OpAtomicCompareExchange;
   3726         break;
   3727     case glslang::EOpAtomicCounterIncrement:
   3728         opCode = spv::OpAtomicIIncrement;
   3729         break;
   3730     case glslang::EOpAtomicCounterDecrement:
   3731         opCode = spv::OpAtomicIDecrement;
   3732         break;
   3733     case glslang::EOpAtomicCounter:
   3734         opCode = spv::OpAtomicLoad;
   3735         break;
   3736     default:
   3737         assert(0);
   3738         break;
   3739     }
   3740 
   3741     // Sort out the operands
   3742     //  - mapping from glslang -> SPV
   3743     //  - there are extra SPV operands with no glslang source
   3744     //  - compare-exchange swaps the value and comparator
   3745     //  - compare-exchange has an extra memory semantics
   3746     std::vector<spv::Id> spvAtomicOperands;  // hold the spv operands
   3747     auto opIt = operands.begin();            // walk the glslang operands
   3748     spvAtomicOperands.push_back(*(opIt++));
   3749     spvAtomicOperands.push_back(builder.makeUintConstant(spv::ScopeDevice));     // TBD: what is the correct scope?
   3750     spvAtomicOperands.push_back(builder.makeUintConstant(spv::MemorySemanticsMaskNone)); // TBD: what are the correct memory semantics?
   3751     if (opCode == spv::OpAtomicCompareExchange) {
   3752         // There are 2 memory semantics for compare-exchange. And the operand order of "comparator" and "new value" in GLSL
   3753         // differs from that in SPIR-V. Hence, special processing is required.
   3754         spvAtomicOperands.push_back(builder.makeUintConstant(spv::MemorySemanticsMaskNone));
   3755         spvAtomicOperands.push_back(*(opIt + 1));
   3756         spvAtomicOperands.push_back(*opIt);
   3757         opIt += 2;
   3758     }
   3759 
   3760     // Add the rest of the operands, skipping any that were dealt with above.
   3761     for (; opIt != operands.end(); ++opIt)
   3762         spvAtomicOperands.push_back(*opIt);
   3763 
   3764     return builder.createOp(opCode, typeId, spvAtomicOperands);
   3765 }
   3766 
   3767 // Create group invocation operations.
   3768 spv::Id TGlslangToSpvTraverser::createInvocationsOperation(glslang::TOperator op, spv::Id typeId, spv::Id operand)
   3769 {
   3770     builder.addCapability(spv::CapabilityGroups);
   3771 
   3772     std::vector<spv::Id> operands;
   3773     operands.push_back(builder.makeUintConstant(spv::ScopeSubgroup));
   3774     operands.push_back(operand);
   3775 
   3776     switch (op) {
   3777     case glslang::EOpAnyInvocation:
   3778     case glslang::EOpAllInvocations:
   3779         return builder.createOp(op == glslang::EOpAnyInvocation ? spv::OpGroupAny : spv::OpGroupAll, typeId, operands);
   3780 
   3781     case glslang::EOpAllInvocationsEqual:
   3782     {
   3783         spv::Id groupAll = builder.createOp(spv::OpGroupAll, typeId, operands);
   3784         spv::Id groupAny = builder.createOp(spv::OpGroupAny, typeId, operands);
   3785 
   3786         return builder.createBinOp(spv::OpLogicalOr, typeId, groupAll,
   3787                                    builder.createUnaryOp(spv::OpLogicalNot, typeId, groupAny));
   3788     }
   3789     default:
   3790         logger->missingFunctionality("invocation operation");
   3791         return spv::NoResult;
   3792     }
   3793 }
   3794 
   3795 spv::Id TGlslangToSpvTraverser::createMiscOperation(glslang::TOperator op, spv::Decoration precision, spv::Id typeId, std::vector<spv::Id>& operands, glslang::TBasicType typeProxy)
   3796 {
   3797     bool isUnsigned = typeProxy == glslang::EbtUint || typeProxy == glslang::EbtUint64;
   3798     bool isFloat = typeProxy == glslang::EbtFloat || typeProxy == glslang::EbtDouble;
   3799 
   3800     spv::Op opCode = spv::OpNop;
   3801     int libCall = -1;
   3802     size_t consumedOperands = operands.size();
   3803     spv::Id typeId0 = 0;
   3804     if (consumedOperands > 0)
   3805         typeId0 = builder.getTypeId(operands[0]);
   3806     spv::Id frexpIntType = 0;
   3807 
   3808     switch (op) {
   3809     case glslang::EOpMin:
   3810         if (isFloat)
   3811             libCall = spv::GLSLstd450FMin;
   3812         else if (isUnsigned)
   3813             libCall = spv::GLSLstd450UMin;
   3814         else
   3815             libCall = spv::GLSLstd450SMin;
   3816         builder.promoteScalar(precision, operands.front(), operands.back());
   3817         break;
   3818     case glslang::EOpModf:
   3819         libCall = spv::GLSLstd450Modf;
   3820         break;
   3821     case glslang::EOpMax:
   3822         if (isFloat)
   3823             libCall = spv::GLSLstd450FMax;
   3824         else if (isUnsigned)
   3825             libCall = spv::GLSLstd450UMax;
   3826         else
   3827             libCall = spv::GLSLstd450SMax;
   3828         builder.promoteScalar(precision, operands.front(), operands.back());
   3829         break;
   3830     case glslang::EOpPow:
   3831         libCall = spv::GLSLstd450Pow;
   3832         break;
   3833     case glslang::EOpDot:
   3834         opCode = spv::OpDot;
   3835         break;
   3836     case glslang::EOpAtan:
   3837         libCall = spv::GLSLstd450Atan2;
   3838         break;
   3839 
   3840     case glslang::EOpClamp:
   3841         if (isFloat)
   3842             libCall = spv::GLSLstd450FClamp;
   3843         else if (isUnsigned)
   3844             libCall = spv::GLSLstd450UClamp;
   3845         else
   3846             libCall = spv::GLSLstd450SClamp;
   3847         builder.promoteScalar(precision, operands.front(), operands[1]);
   3848         builder.promoteScalar(precision, operands.front(), operands[2]);
   3849         break;
   3850     case glslang::EOpMix:
   3851         if (! builder.isBoolType(builder.getScalarTypeId(builder.getTypeId(operands.back())))) {
   3852             assert(isFloat);
   3853             libCall = spv::GLSLstd450FMix;
   3854         } else {
   3855             opCode = spv::OpSelect;
   3856             std::swap(operands.front(), operands.back());
   3857         }
   3858         builder.promoteScalar(precision, operands.front(), operands.back());
   3859         break;
   3860     case glslang::EOpStep:
   3861         libCall = spv::GLSLstd450Step;
   3862         builder.promoteScalar(precision, operands.front(), operands.back());
   3863         break;
   3864     case glslang::EOpSmoothStep:
   3865         libCall = spv::GLSLstd450SmoothStep;
   3866         builder.promoteScalar(precision, operands[0], operands[2]);
   3867         builder.promoteScalar(precision, operands[1], operands[2]);
   3868         break;
   3869 
   3870     case glslang::EOpDistance:
   3871         libCall = spv::GLSLstd450Distance;
   3872         break;
   3873     case glslang::EOpCross:
   3874         libCall = spv::GLSLstd450Cross;
   3875         break;
   3876     case glslang::EOpFaceForward:
   3877         libCall = spv::GLSLstd450FaceForward;
   3878         break;
   3879     case glslang::EOpReflect:
   3880         libCall = spv::GLSLstd450Reflect;
   3881         break;
   3882     case glslang::EOpRefract:
   3883         libCall = spv::GLSLstd450Refract;
   3884         break;
   3885     case glslang::EOpInterpolateAtSample:
   3886         builder.addCapability(spv::CapabilityInterpolationFunction);
   3887         libCall = spv::GLSLstd450InterpolateAtSample;
   3888         break;
   3889     case glslang::EOpInterpolateAtOffset:
   3890         builder.addCapability(spv::CapabilityInterpolationFunction);
   3891         libCall = spv::GLSLstd450InterpolateAtOffset;
   3892         break;
   3893     case glslang::EOpAddCarry:
   3894         opCode = spv::OpIAddCarry;
   3895         typeId = builder.makeStructResultType(typeId0, typeId0);
   3896         consumedOperands = 2;
   3897         break;
   3898     case glslang::EOpSubBorrow:
   3899         opCode = spv::OpISubBorrow;
   3900         typeId = builder.makeStructResultType(typeId0, typeId0);
   3901         consumedOperands = 2;
   3902         break;
   3903     case glslang::EOpUMulExtended:
   3904         opCode = spv::OpUMulExtended;
   3905         typeId = builder.makeStructResultType(typeId0, typeId0);
   3906         consumedOperands = 2;
   3907         break;
   3908     case glslang::EOpIMulExtended:
   3909         opCode = spv::OpSMulExtended;
   3910         typeId = builder.makeStructResultType(typeId0, typeId0);
   3911         consumedOperands = 2;
   3912         break;
   3913     case glslang::EOpBitfieldExtract:
   3914         if (isUnsigned)
   3915             opCode = spv::OpBitFieldUExtract;
   3916         else
   3917             opCode = spv::OpBitFieldSExtract;
   3918         break;
   3919     case glslang::EOpBitfieldInsert:
   3920         opCode = spv::OpBitFieldInsert;
   3921         break;
   3922 
   3923     case glslang::EOpFma:
   3924         libCall = spv::GLSLstd450Fma;
   3925         break;
   3926     case glslang::EOpFrexp:
   3927         libCall = spv::GLSLstd450FrexpStruct;
   3928         if (builder.getNumComponents(operands[0]) == 1)
   3929             frexpIntType = builder.makeIntegerType(32, true);
   3930         else
   3931             frexpIntType = builder.makeVectorType(builder.makeIntegerType(32, true), builder.getNumComponents(operands[0]));
   3932         typeId = builder.makeStructResultType(typeId0, frexpIntType);
   3933         consumedOperands = 1;
   3934         break;
   3935     case glslang::EOpLdexp:
   3936         libCall = spv::GLSLstd450Ldexp;
   3937         break;
   3938 
   3939     case glslang::EOpReadInvocation:
   3940         logger->missingFunctionality("shader ballot");
   3941         libCall = spv::GLSLstd450Bad;
   3942         break;
   3943 
   3944     default:
   3945         return 0;
   3946     }
   3947 
   3948     spv::Id id = 0;
   3949     if (libCall >= 0) {
   3950         // Use an extended instruction from the standard library.
   3951         // Construct the call arguments, without modifying the original operands vector.
   3952         // We might need the remaining arguments, e.g. in the EOpFrexp case.
   3953         std::vector<spv::Id> callArguments(operands.begin(), operands.begin() + consumedOperands);
   3954         id = builder.createBuiltinCall(typeId, stdBuiltins, libCall, callArguments);
   3955     } else {
   3956         switch (consumedOperands) {
   3957         case 0:
   3958             // should all be handled by visitAggregate and createNoArgOperation
   3959             assert(0);
   3960             return 0;
   3961         case 1:
   3962             // should all be handled by createUnaryOperation
   3963             assert(0);
   3964             return 0;
   3965         case 2:
   3966             id = builder.createBinOp(opCode, typeId, operands[0], operands[1]);
   3967             break;
   3968         default:
   3969             // anything 3 or over doesn't have l-value operands, so all should be consumed
   3970             assert(consumedOperands == operands.size());
   3971             id = builder.createOp(opCode, typeId, operands);
   3972             break;
   3973         }
   3974     }
   3975 
   3976     // Decode the return types that were structures
   3977     switch (op) {
   3978     case glslang::EOpAddCarry:
   3979     case glslang::EOpSubBorrow:
   3980         builder.createStore(builder.createCompositeExtract(id, typeId0, 1), operands[2]);
   3981         id = builder.createCompositeExtract(id, typeId0, 0);
   3982         break;
   3983     case glslang::EOpUMulExtended:
   3984     case glslang::EOpIMulExtended:
   3985         builder.createStore(builder.createCompositeExtract(id, typeId0, 0), operands[3]);
   3986         builder.createStore(builder.createCompositeExtract(id, typeId0, 1), operands[2]);
   3987         break;
   3988     case glslang::EOpFrexp:
   3989         assert(operands.size() == 2);
   3990         builder.createStore(builder.createCompositeExtract(id, frexpIntType, 1), operands[1]);
   3991         id = builder.createCompositeExtract(id, typeId0, 0);
   3992         break;
   3993     default:
   3994         break;
   3995     }
   3996 
   3997     return builder.setPrecision(id, precision);
   3998 }
   3999 
   4000 // Intrinsics with no arguments, no return value, and no precision.
   4001 spv::Id TGlslangToSpvTraverser::createNoArgOperation(glslang::TOperator op)
   4002 {
   4003     // TODO: get the barrier operands correct
   4004 
   4005     switch (op) {
   4006     case glslang::EOpEmitVertex:
   4007         builder.createNoResultOp(spv::OpEmitVertex);
   4008         return 0;
   4009     case glslang::EOpEndPrimitive:
   4010         builder.createNoResultOp(spv::OpEndPrimitive);
   4011         return 0;
   4012     case glslang::EOpBarrier:
   4013         builder.createControlBarrier(spv::ScopeDevice, spv::ScopeDevice, spv::MemorySemanticsMaskNone);
   4014         return 0;
   4015     case glslang::EOpMemoryBarrier:
   4016         builder.createMemoryBarrier(spv::ScopeDevice, spv::MemorySemanticsAllMemory);
   4017         return 0;
   4018     case glslang::EOpMemoryBarrierAtomicCounter:
   4019         builder.createMemoryBarrier(spv::ScopeDevice, spv::MemorySemanticsAtomicCounterMemoryMask);
   4020         return 0;
   4021     case glslang::EOpMemoryBarrierBuffer:
   4022         builder.createMemoryBarrier(spv::ScopeDevice, spv::MemorySemanticsUniformMemoryMask);
   4023         return 0;
   4024     case glslang::EOpMemoryBarrierImage:
   4025         builder.createMemoryBarrier(spv::ScopeDevice, spv::MemorySemanticsImageMemoryMask);
   4026         return 0;
   4027     case glslang::EOpMemoryBarrierShared:
   4028         builder.createMemoryBarrier(spv::ScopeDevice, spv::MemorySemanticsWorkgroupMemoryMask);
   4029         return 0;
   4030     case glslang::EOpGroupMemoryBarrier:
   4031         builder.createMemoryBarrier(spv::ScopeDevice, spv::MemorySemanticsCrossWorkgroupMemoryMask);
   4032         return 0;
   4033     case glslang::EOpAllMemoryBarrierWithGroupSync:
   4034         // Control barrier with non-"None" semantic is also a memory barrier.
   4035         builder.createControlBarrier(spv::ScopeDevice, spv::ScopeDevice, spv::MemorySemanticsAllMemory);
   4036         return 0;
   4037     case glslang::EOpGroupMemoryBarrierWithGroupSync:
   4038         // Control barrier with non-"None" semantic is also a memory barrier.
   4039         builder.createControlBarrier(spv::ScopeDevice, spv::ScopeDevice, spv::MemorySemanticsCrossWorkgroupMemoryMask);
   4040         return 0;
   4041     case glslang::EOpWorkgroupMemoryBarrier:
   4042         builder.createMemoryBarrier(spv::ScopeWorkgroup, spv::MemorySemanticsWorkgroupMemoryMask);
   4043         return 0;
   4044     case glslang::EOpWorkgroupMemoryBarrierWithGroupSync:
   4045         // Control barrier with non-"None" semantic is also a memory barrier.
   4046         builder.createControlBarrier(spv::ScopeWorkgroup, spv::ScopeWorkgroup, spv::MemorySemanticsWorkgroupMemoryMask);
   4047         return 0;
   4048     default:
   4049         logger->missingFunctionality("unknown operation with no arguments");
   4050         return 0;
   4051     }
   4052 }
   4053 
   4054 spv::Id TGlslangToSpvTraverser::getSymbolId(const glslang::TIntermSymbol* symbol)
   4055 {
   4056     auto iter = symbolValues.find(symbol->getId());
   4057     spv::Id id;
   4058     if (symbolValues.end() != iter) {
   4059         id = iter->second;
   4060         return id;
   4061     }
   4062 
   4063     // it was not found, create it
   4064     id = createSpvVariable(symbol);
   4065     symbolValues[symbol->getId()] = id;
   4066 
   4067     if (symbol->getBasicType() != glslang::EbtBlock) {
   4068         addDecoration(id, TranslatePrecisionDecoration(symbol->getType()));
   4069         addDecoration(id, TranslateInterpolationDecoration(symbol->getType().getQualifier()));
   4070         addDecoration(id, TranslateAuxiliaryStorageDecoration(symbol->getType().getQualifier()));
   4071         if (symbol->getType().getQualifier().hasSpecConstantId())
   4072             addDecoration(id, spv::DecorationSpecId, symbol->getType().getQualifier().layoutSpecConstantId);
   4073         if (symbol->getQualifier().hasIndex())
   4074             builder.addDecoration(id, spv::DecorationIndex, symbol->getQualifier().layoutIndex);
   4075         if (symbol->getQualifier().hasComponent())
   4076             builder.addDecoration(id, spv::DecorationComponent, symbol->getQualifier().layoutComponent);
   4077         if (glslangIntermediate->getXfbMode()) {
   4078             builder.addCapability(spv::CapabilityTransformFeedback);
   4079             if (symbol->getQualifier().hasXfbStride())
   4080                 builder.addDecoration(id, spv::DecorationXfbStride, symbol->getQualifier().layoutXfbStride);
   4081             if (symbol->getQualifier().hasXfbBuffer())
   4082                 builder.addDecoration(id, spv::DecorationXfbBuffer, symbol->getQualifier().layoutXfbBuffer);
   4083             if (symbol->getQualifier().hasXfbOffset())
   4084                 builder.addDecoration(id, spv::DecorationOffset, symbol->getQualifier().layoutXfbOffset);
   4085         }
   4086         // atomic counters use this:
   4087         if (symbol->getQualifier().hasOffset())
   4088             builder.addDecoration(id, spv::DecorationOffset, symbol->getQualifier().layoutOffset);
   4089     }
   4090 
   4091     if (symbol->getQualifier().hasLocation())
   4092         builder.addDecoration(id, spv::DecorationLocation, symbol->getQualifier().layoutLocation);
   4093     addDecoration(id, TranslateInvariantDecoration(symbol->getType().getQualifier()));
   4094     if (symbol->getQualifier().hasStream() && glslangIntermediate->isMultiStream()) {
   4095         builder.addCapability(spv::CapabilityGeometryStreams);
   4096         builder.addDecoration(id, spv::DecorationStream, symbol->getQualifier().layoutStream);
   4097     }
   4098     if (symbol->getQualifier().hasSet())
   4099         builder.addDecoration(id, spv::DecorationDescriptorSet, symbol->getQualifier().layoutSet);
   4100     else if (IsDescriptorResource(symbol->getType())) {
   4101         // default to 0
   4102         builder.addDecoration(id, spv::DecorationDescriptorSet, 0);
   4103     }
   4104     if (symbol->getQualifier().hasBinding())
   4105         builder.addDecoration(id, spv::DecorationBinding, symbol->getQualifier().layoutBinding);
   4106     if (symbol->getQualifier().hasAttachment())
   4107         builder.addDecoration(id, spv::DecorationInputAttachmentIndex, symbol->getQualifier().layoutAttachment);
   4108     if (glslangIntermediate->getXfbMode()) {
   4109         builder.addCapability(spv::CapabilityTransformFeedback);
   4110         if (symbol->getQualifier().hasXfbStride())
   4111             builder.addDecoration(id, spv::DecorationXfbStride, symbol->getQualifier().layoutXfbStride);
   4112         if (symbol->getQualifier().hasXfbBuffer())
   4113             builder.addDecoration(id, spv::DecorationXfbBuffer, symbol->getQualifier().layoutXfbBuffer);
   4114     }
   4115 
   4116     if (symbol->getType().isImage()) {
   4117         std::vector<spv::Decoration> memory;
   4118         TranslateMemoryDecoration(symbol->getType().getQualifier(), memory);
   4119         for (unsigned int i = 0; i < memory.size(); ++i)
   4120             addDecoration(id, memory[i]);
   4121     }
   4122 
   4123     // built-in variable decorations
   4124     spv::BuiltIn builtIn = TranslateBuiltInDecoration(symbol->getQualifier().builtIn, false);
   4125     if (builtIn != spv::BuiltInMax)
   4126         addDecoration(id, spv::DecorationBuiltIn, (int)builtIn);
   4127 
   4128     return id;
   4129 }
   4130 
   4131 // If 'dec' is valid, add no-operand decoration to an object
   4132 void TGlslangToSpvTraverser::addDecoration(spv::Id id, spv::Decoration dec)
   4133 {
   4134     if (dec != spv::DecorationMax)
   4135         builder.addDecoration(id, dec);
   4136 }
   4137 
   4138 // If 'dec' is valid, add a one-operand decoration to an object
   4139 void TGlslangToSpvTraverser::addDecoration(spv::Id id, spv::Decoration dec, unsigned value)
   4140 {
   4141     if (dec != spv::DecorationMax)
   4142         builder.addDecoration(id, dec, value);
   4143 }
   4144 
   4145 // If 'dec' is valid, add a no-operand decoration to a struct member
   4146 void TGlslangToSpvTraverser::addMemberDecoration(spv::Id id, int member, spv::Decoration dec)
   4147 {
   4148     if (dec != spv::DecorationMax)
   4149         builder.addMemberDecoration(id, (unsigned)member, dec);
   4150 }
   4151 
   4152 // If 'dec' is valid, add a one-operand decoration to a struct member
   4153 void TGlslangToSpvTraverser::addMemberDecoration(spv::Id id, int member, spv::Decoration dec, unsigned value)
   4154 {
   4155     if (dec != spv::DecorationMax)
   4156         builder.addMemberDecoration(id, (unsigned)member, dec, value);
   4157 }
   4158 
   4159 // Make a full tree of instructions to build a SPIR-V specialization constant,
   4160 // or regular constant if possible.
   4161 //
   4162 // TBD: this is not yet done, nor verified to be the best design, it does do the leaf symbols though
   4163 //
   4164 // Recursively walk the nodes.  The nodes form a tree whose leaves are
   4165 // regular constants, which themselves are trees that createSpvConstant()
   4166 // recursively walks.  So, this function walks the "top" of the tree:
   4167 //  - emit specialization constant-building instructions for specConstant
   4168 //  - when running into a non-spec-constant, switch to createSpvConstant()
   4169 spv::Id TGlslangToSpvTraverser::createSpvConstant(const glslang::TIntermTyped& node)
   4170 {
   4171     assert(node.getQualifier().isConstant());
   4172 
   4173     // Handle front-end constants first (non-specialization constants).
   4174     if (! node.getQualifier().specConstant) {
   4175         // hand off to the non-spec-constant path
   4176         assert(node.getAsConstantUnion() != nullptr || node.getAsSymbolNode() != nullptr);
   4177         int nextConst = 0;
   4178         return createSpvConstantFromConstUnionArray(node.getType(), node.getAsConstantUnion() ? node.getAsConstantUnion()->getConstArray() : node.getAsSymbolNode()->getConstArray(),
   4179                                  nextConst, false);
   4180     }
   4181 
   4182     // We now know we have a specialization constant to build
   4183 
   4184     // gl_WorkGroupSize is a special case until the front-end handles hierarchical specialization constants,
   4185     // even then, it's specialization ids are handled by special case syntax in GLSL: layout(local_size_x = ...
   4186     if (node.getType().getQualifier().builtIn == glslang::EbvWorkGroupSize) {
   4187         std::vector<spv::Id> dimConstId;
   4188         for (int dim = 0; dim < 3; ++dim) {
   4189             bool specConst = (glslangIntermediate->getLocalSizeSpecId(dim) != glslang::TQualifier::layoutNotSet);
   4190             dimConstId.push_back(builder.makeUintConstant(glslangIntermediate->getLocalSize(dim), specConst));
   4191             if (specConst)
   4192                 addDecoration(dimConstId.back(), spv::DecorationSpecId, glslangIntermediate->getLocalSizeSpecId(dim));
   4193         }
   4194         return builder.makeCompositeConstant(builder.makeVectorType(builder.makeUintType(32), 3), dimConstId, true);
   4195     }
   4196 
   4197     // An AST node labelled as specialization constant should be a symbol node.
   4198     // Its initializer should either be a sub tree with constant nodes, or a constant union array.
   4199     if (auto* sn = node.getAsSymbolNode()) {
   4200         if (auto* sub_tree = sn->getConstSubtree()) {
   4201             // Traverse the constant constructor sub tree like generating normal run-time instructions.
   4202             // During the AST traversal, if the node is marked as 'specConstant', SpecConstantOpModeGuard
   4203             // will set the builder into spec constant op instruction generating mode.
   4204             sub_tree->traverse(this);
   4205             return accessChainLoad(sub_tree->getType());
   4206         } else if (auto* const_union_array = &sn->getConstArray()){
   4207             int nextConst = 0;
   4208             return createSpvConstantFromConstUnionArray(sn->getType(), *const_union_array, nextConst, true);
   4209         }
   4210     }
   4211 
   4212     // Neither a front-end constant node, nor a specialization constant node with constant union array or
   4213     // constant sub tree as initializer.
   4214     logger->missingFunctionality("Neither a front-end constant nor a spec constant.");
   4215     exit(1);
   4216     return spv::NoResult;
   4217 }
   4218 
   4219 // Use 'consts' as the flattened glslang source of scalar constants to recursively
   4220 // build the aggregate SPIR-V constant.
   4221 //
   4222 // If there are not enough elements present in 'consts', 0 will be substituted;
   4223 // an empty 'consts' can be used to create a fully zeroed SPIR-V constant.
   4224 //
   4225 spv::Id TGlslangToSpvTraverser::createSpvConstantFromConstUnionArray(const glslang::TType& glslangType, const glslang::TConstUnionArray& consts, int& nextConst, bool specConstant)
   4226 {
   4227     // vector of constants for SPIR-V
   4228     std::vector<spv::Id> spvConsts;
   4229 
   4230     // Type is used for struct and array constants
   4231     spv::Id typeId = convertGlslangToSpvType(glslangType);
   4232 
   4233     if (glslangType.isArray()) {
   4234         glslang::TType elementType(glslangType, 0);
   4235         for (int i = 0; i < glslangType.getOuterArraySize(); ++i)
   4236             spvConsts.push_back(createSpvConstantFromConstUnionArray(elementType, consts, nextConst, false));
   4237     } else if (glslangType.isMatrix()) {
   4238         glslang::TType vectorType(glslangType, 0);
   4239         for (int col = 0; col < glslangType.getMatrixCols(); ++col)
   4240             spvConsts.push_back(createSpvConstantFromConstUnionArray(vectorType, consts, nextConst, false));
   4241     } else if (glslangType.getStruct()) {
   4242         glslang::TVector<glslang::TTypeLoc>::const_iterator iter;
   4243         for (iter = glslangType.getStruct()->begin(); iter != glslangType.getStruct()->end(); ++iter)
   4244             spvConsts.push_back(createSpvConstantFromConstUnionArray(*iter->type, consts, nextConst, false));
   4245     } else if (glslangType.getVectorSize() > 1) {
   4246         for (unsigned int i = 0; i < (unsigned int)glslangType.getVectorSize(); ++i) {
   4247             bool zero = nextConst >= consts.size();
   4248             switch (glslangType.getBasicType()) {
   4249             case glslang::EbtInt:
   4250                 spvConsts.push_back(builder.makeIntConstant(zero ? 0 : consts[nextConst].getIConst()));
   4251                 break;
   4252             case glslang::EbtUint:
   4253                 spvConsts.push_back(builder.makeUintConstant(zero ? 0 : consts[nextConst].getUConst()));
   4254                 break;
   4255             case glslang::EbtInt64:
   4256                 spvConsts.push_back(builder.makeInt64Constant(zero ? 0 : consts[nextConst].getI64Const()));
   4257                 break;
   4258             case glslang::EbtUint64:
   4259                 spvConsts.push_back(builder.makeUint64Constant(zero ? 0 : consts[nextConst].getU64Const()));
   4260                 break;
   4261             case glslang::EbtFloat:
   4262                 spvConsts.push_back(builder.makeFloatConstant(zero ? 0.0F : (float)consts[nextConst].getDConst()));
   4263                 break;
   4264             case glslang::EbtDouble:
   4265                 spvConsts.push_back(builder.makeDoubleConstant(zero ? 0.0 : consts[nextConst].getDConst()));
   4266                 break;
   4267             case glslang::EbtBool:
   4268                 spvConsts.push_back(builder.makeBoolConstant(zero ? false : consts[nextConst].getBConst()));
   4269                 break;
   4270             default:
   4271                 assert(0);
   4272                 break;
   4273             }
   4274             ++nextConst;
   4275         }
   4276     } else {
   4277         // we have a non-aggregate (scalar) constant
   4278         bool zero = nextConst >= consts.size();
   4279         spv::Id scalar = 0;
   4280         switch (glslangType.getBasicType()) {
   4281         case glslang::EbtInt:
   4282             scalar = builder.makeIntConstant(zero ? 0 : consts[nextConst].getIConst(), specConstant);
   4283             break;
   4284         case glslang::EbtUint:
   4285             scalar = builder.makeUintConstant(zero ? 0 : consts[nextConst].getUConst(), specConstant);
   4286             break;
   4287         case glslang::EbtInt64:
   4288             scalar = builder.makeInt64Constant(zero ? 0 : consts[nextConst].getI64Const(), specConstant);
   4289             break;
   4290         case glslang::EbtUint64:
   4291             scalar = builder.makeUint64Constant(zero ? 0 : consts[nextConst].getU64Const(), specConstant);
   4292             break;
   4293         case glslang::EbtFloat:
   4294             scalar = builder.makeFloatConstant(zero ? 0.0F : (float)consts[nextConst].getDConst(), specConstant);
   4295             break;
   4296         case glslang::EbtDouble:
   4297             scalar = builder.makeDoubleConstant(zero ? 0.0 : consts[nextConst].getDConst(), specConstant);
   4298             break;
   4299         case glslang::EbtBool:
   4300             scalar = builder.makeBoolConstant(zero ? false : consts[nextConst].getBConst(), specConstant);
   4301             break;
   4302         default:
   4303             assert(0);
   4304             break;
   4305         }
   4306         ++nextConst;
   4307         return scalar;
   4308     }
   4309 
   4310     return builder.makeCompositeConstant(typeId, spvConsts);
   4311 }
   4312 
   4313 // Return true if the node is a constant or symbol whose reading has no
   4314 // non-trivial observable cost or effect.
   4315 bool TGlslangToSpvTraverser::isTrivialLeaf(const glslang::TIntermTyped* node)
   4316 {
   4317     // don't know what this is
   4318     if (node == nullptr)
   4319         return false;
   4320 
   4321     // a constant is safe
   4322     if (node->getAsConstantUnion() != nullptr)
   4323         return true;
   4324 
   4325     // not a symbol means non-trivial
   4326     if (node->getAsSymbolNode() == nullptr)
   4327         return false;
   4328 
   4329     // a symbol, depends on what's being read
   4330     switch (node->getType().getQualifier().storage) {
   4331     case glslang::EvqTemporary:
   4332     case glslang::EvqGlobal:
   4333     case glslang::EvqIn:
   4334     case glslang::EvqInOut:
   4335     case glslang::EvqConst:
   4336     case glslang::EvqConstReadOnly:
   4337     case glslang::EvqUniform:
   4338         return true;
   4339     default:
   4340         return false;
   4341     }
   4342 }
   4343 
   4344 // A node is trivial if it is a single operation with no side effects.
   4345 // Error on the side of saying non-trivial.
   4346 // Return true if trivial.
   4347 bool TGlslangToSpvTraverser::isTrivial(const glslang::TIntermTyped* node)
   4348 {
   4349     if (node == nullptr)
   4350         return false;
   4351 
   4352     // symbols and constants are trivial
   4353     if (isTrivialLeaf(node))
   4354         return true;
   4355 
   4356     // otherwise, it needs to be a simple operation or one or two leaf nodes
   4357 
   4358     // not a simple operation
   4359     const glslang::TIntermBinary* binaryNode = node->getAsBinaryNode();
   4360     const glslang::TIntermUnary* unaryNode = node->getAsUnaryNode();
   4361     if (binaryNode == nullptr && unaryNode == nullptr)
   4362         return false;
   4363 
   4364     // not on leaf nodes
   4365     if (binaryNode && (! isTrivialLeaf(binaryNode->getLeft()) || ! isTrivialLeaf(binaryNode->getRight())))
   4366         return false;
   4367 
   4368     if (unaryNode && ! isTrivialLeaf(unaryNode->getOperand())) {
   4369         return false;
   4370     }
   4371 
   4372     switch (node->getAsOperator()->getOp()) {
   4373     case glslang::EOpLogicalNot:
   4374     case glslang::EOpConvIntToBool:
   4375     case glslang::EOpConvUintToBool:
   4376     case glslang::EOpConvFloatToBool:
   4377     case glslang::EOpConvDoubleToBool:
   4378     case glslang::EOpEqual:
   4379     case glslang::EOpNotEqual:
   4380     case glslang::EOpLessThan:
   4381     case glslang::EOpGreaterThan:
   4382     case glslang::EOpLessThanEqual:
   4383     case glslang::EOpGreaterThanEqual:
   4384     case glslang::EOpIndexDirect:
   4385     case glslang::EOpIndexDirectStruct:
   4386     case glslang::EOpLogicalXor:
   4387     case glslang::EOpAny:
   4388     case glslang::EOpAll:
   4389         return true;
   4390     default:
   4391         return false;
   4392     }
   4393 }
   4394 
   4395 // Emit short-circuiting code, where 'right' is never evaluated unless
   4396 // the left side is true (for &&) or false (for ||).
   4397 spv::Id TGlslangToSpvTraverser::createShortCircuit(glslang::TOperator op, glslang::TIntermTyped& left, glslang::TIntermTyped& right)
   4398 {
   4399     spv::Id boolTypeId = builder.makeBoolType();
   4400 
   4401     // emit left operand
   4402     builder.clearAccessChain();
   4403     left.traverse(this);
   4404     spv::Id leftId = accessChainLoad(left.getType());
   4405 
   4406     // Operands to accumulate OpPhi operands
   4407     std::vector<spv::Id> phiOperands;
   4408     // accumulate left operand's phi information
   4409     phiOperands.push_back(leftId);
   4410     phiOperands.push_back(builder.getBuildPoint()->getId());
   4411 
   4412     // Make the two kinds of operation symmetric with a "!"
   4413     //   || => emit "if (! left) result = right"
   4414     //   && => emit "if (  left) result = right"
   4415     //
   4416     // TODO: this runtime "not" for || could be avoided by adding functionality
   4417     // to 'builder' to have an "else" without an "then"
   4418     if (op == glslang::EOpLogicalOr)
   4419         leftId = builder.createUnaryOp(spv::OpLogicalNot, boolTypeId, leftId);
   4420 
   4421     // make an "if" based on the left value
   4422     spv::Builder::If ifBuilder(leftId, builder);
   4423 
   4424     // emit right operand as the "then" part of the "if"
   4425     builder.clearAccessChain();
   4426     right.traverse(this);
   4427     spv::Id rightId = accessChainLoad(right.getType());
   4428 
   4429     // accumulate left operand's phi information
   4430     phiOperands.push_back(rightId);
   4431     phiOperands.push_back(builder.getBuildPoint()->getId());
   4432 
   4433     // finish the "if"
   4434     ifBuilder.makeEndIf();
   4435 
   4436     // phi together the two results
   4437     return builder.createOp(spv::OpPhi, boolTypeId, phiOperands);
   4438 }
   4439 
   4440 };  // end anonymous namespace
   4441 
   4442 namespace glslang {
   4443 
   4444 void GetSpirvVersion(std::string& version)
   4445 {
   4446     const int bufSize = 100;
   4447     char buf[bufSize];
   4448     snprintf(buf, bufSize, "0x%08x, Revision %d", spv::Version, spv::Revision);
   4449     version = buf;
   4450 }
   4451 
   4452 // Write SPIR-V out to a binary file
   4453 void OutputSpvBin(const std::vector<unsigned int>& spirv, const char* baseName)
   4454 {
   4455     std::ofstream out;
   4456     out.open(baseName, std::ios::binary | std::ios::out);
   4457     for (int i = 0; i < (int)spirv.size(); ++i) {
   4458         unsigned int word = spirv[i];
   4459         out.write((const char*)&word, 4);
   4460     }
   4461     out.close();
   4462 }
   4463 
   4464 // Write SPIR-V out to a text file with 32-bit hexadecimal words
   4465 void OutputSpvHex(const std::vector<unsigned int>& spirv, const char* baseName)
   4466 {
   4467     std::ofstream out;
   4468     out.open(baseName, std::ios::binary | std::ios::out);
   4469     out << "\t// " GLSLANG_REVISION " " GLSLANG_DATE << std::endl;
   4470     const int WORDS_PER_LINE = 8;
   4471     for (int i = 0; i < (int)spirv.size(); i += WORDS_PER_LINE) {
   4472         out << "\t";
   4473         for (int j = 0; j < WORDS_PER_LINE && i + j < (int)spirv.size(); ++j) {
   4474             const unsigned int word = spirv[i + j];
   4475             out << "0x" << std::hex << std::setw(8) << std::setfill('0') << word;
   4476             if (i + j + 1 < (int)spirv.size()) {
   4477                 out << ",";
   4478             }
   4479         }
   4480         out << std::endl;
   4481     }
   4482     out.close();
   4483 }
   4484 
   4485 //
   4486 // Set up the glslang traversal
   4487 //
   4488 void GlslangToSpv(const glslang::TIntermediate& intermediate, std::vector<unsigned int>& spirv)
   4489 {
   4490     spv::SpvBuildLogger logger;
   4491     GlslangToSpv(intermediate, spirv, &logger);
   4492 }
   4493 
   4494 void GlslangToSpv(const glslang::TIntermediate& intermediate, std::vector<unsigned int>& spirv, spv::SpvBuildLogger* logger)
   4495 {
   4496     TIntermNode* root = intermediate.getTreeRoot();
   4497 
   4498     if (root == 0)
   4499         return;
   4500 
   4501     glslang::GetThreadPoolAllocator().push();
   4502 
   4503     TGlslangToSpvTraverser it(&intermediate, logger);
   4504 
   4505     root->traverse(&it);
   4506 
   4507     it.dumpSpv(spirv);
   4508 
   4509     glslang::GetThreadPoolAllocator().pop();
   4510 }
   4511 
   4512 }; // end namespace glslang
   4513