Path: blob/master/thirdparty/glslang/SPIRV/GlslangToSpv.cpp
9903 views
//1// Copyright (C) 2014-2016 LunarG, Inc.2// Copyright (C) 2015-2020 Google, Inc.3// Copyright (C) 2017, 2022-2024 Arm Limited.4// Modifications Copyright (C) 2020 Advanced Micro Devices, Inc. All rights reserved.5//6// All rights reserved.7//8// Redistribution and use in source and binary forms, with or without9// modification, are permitted provided that the following conditions10// are met:11//12// Redistributions of source code must retain the above copyright13// notice, this list of conditions and the following disclaimer.14//15// Redistributions in binary form must reproduce the above16// copyright notice, this list of conditions and the following17// disclaimer in the documentation and/or other materials provided18// with the distribution.19//20// Neither the name of 3Dlabs Inc. Ltd. nor the names of its21// contributors may be used to endorse or promote products derived22// from this software without specific prior written permission.23//24// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS25// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT26// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS27// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE28// COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,29// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,30// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;31// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER32// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT33// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN34// ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE35// POSSIBILITY OF SUCH DAMAGE.3637//38// Visit the nodes in the glslang intermediate tree representation to39// translate them to SPIR-V.40//4142#include "spirv.hpp"43#include "GlslangToSpv.h"44#include "SpvBuilder.h"45#include "SpvTools.h"46namespace spv {47#include "GLSL.std.450.h"48#include "GLSL.ext.KHR.h"49#include "GLSL.ext.EXT.h"50#include "GLSL.ext.AMD.h"51#include "GLSL.ext.NV.h"52#include "GLSL.ext.ARM.h"53#include "GLSL.ext.QCOM.h"54#include "NonSemanticDebugPrintf.h"55}5657// Glslang includes58#include "../glslang/MachineIndependent/localintermediate.h"59#include "../glslang/MachineIndependent/SymbolTable.h"60#include "../glslang/Include/Common.h"6162// Build-time generated includes63#include "glslang/build_info.h"6465#include <fstream>66#include <iomanip>67#include <list>68#include <map>69#include <optional>70#include <stack>71#include <string>72#include <vector>7374namespace {7576namespace {77class SpecConstantOpModeGuard {78public:79SpecConstantOpModeGuard(spv::Builder* builder)80: builder_(builder) {81previous_flag_ = builder->isInSpecConstCodeGenMode();82}83~SpecConstantOpModeGuard() {84previous_flag_ ? builder_->setToSpecConstCodeGenMode()85: builder_->setToNormalCodeGenMode();86}87void turnOnSpecConstantOpMode() {88builder_->setToSpecConstCodeGenMode();89}9091private:92spv::Builder* builder_;93bool previous_flag_;94};9596struct OpDecorations {97public:98OpDecorations(spv::Decoration precision, spv::Decoration noContraction, spv::Decoration nonUniform) :99precision(precision)100,101noContraction(noContraction),102nonUniform(nonUniform)103{ }104105spv::Decoration precision;106107void addNoContraction(spv::Builder& builder, spv::Id t) { builder.addDecoration(t, noContraction); }108void addNonUniform(spv::Builder& builder, spv::Id t) { builder.addDecoration(t, nonUniform); }109protected:110spv::Decoration noContraction;111spv::Decoration nonUniform;112};113114} // namespace115116//117// The main holder of information for translating glslang to SPIR-V.118//119// Derives from the AST walking base class.120//121class TGlslangToSpvTraverser : public glslang::TIntermTraverser {122public:123TGlslangToSpvTraverser(unsigned int spvVersion, const glslang::TIntermediate*, spv::SpvBuildLogger* logger,124glslang::SpvOptions& options);125virtual ~TGlslangToSpvTraverser() { }126127bool visitAggregate(glslang::TVisit, glslang::TIntermAggregate*);128bool visitBinary(glslang::TVisit, glslang::TIntermBinary*);129void visitConstantUnion(glslang::TIntermConstantUnion*);130bool visitSelection(glslang::TVisit, glslang::TIntermSelection*);131bool visitSwitch(glslang::TVisit, glslang::TIntermSwitch*);132void visitSymbol(glslang::TIntermSymbol* symbol);133bool visitUnary(glslang::TVisit, glslang::TIntermUnary*);134bool visitLoop(glslang::TVisit, glslang::TIntermLoop*);135bool visitBranch(glslang::TVisit visit, glslang::TIntermBranch*);136137void finishSpv(bool compileOnly);138void dumpSpv(std::vector<unsigned int>& out);139140protected:141TGlslangToSpvTraverser(TGlslangToSpvTraverser&);142TGlslangToSpvTraverser& operator=(TGlslangToSpvTraverser&);143144spv::Decoration TranslateInterpolationDecoration(const glslang::TQualifier& qualifier);145spv::Decoration TranslateAuxiliaryStorageDecoration(const glslang::TQualifier& qualifier);146spv::Decoration TranslateNonUniformDecoration(const glslang::TQualifier& qualifier);147spv::Decoration TranslateNonUniformDecoration(const spv::Builder::AccessChain::CoherentFlags& coherentFlags);148spv::Builder::AccessChain::CoherentFlags TranslateCoherent(const glslang::TType& type);149spv::MemoryAccessMask TranslateMemoryAccess(const spv::Builder::AccessChain::CoherentFlags &coherentFlags);150spv::ImageOperandsMask TranslateImageOperands(const spv::Builder::AccessChain::CoherentFlags &coherentFlags);151spv::Scope TranslateMemoryScope(const spv::Builder::AccessChain::CoherentFlags &coherentFlags);152spv::BuiltIn TranslateBuiltInDecoration(glslang::TBuiltInVariable, bool memberDeclaration);153spv::ImageFormat TranslateImageFormat(const glslang::TType& type);154spv::SelectionControlMask TranslateSelectionControl(const glslang::TIntermSelection&) const;155spv::SelectionControlMask TranslateSwitchControl(const glslang::TIntermSwitch&) const;156spv::LoopControlMask TranslateLoopControl(const glslang::TIntermLoop&, std::vector<unsigned int>& operands) const;157spv::StorageClass TranslateStorageClass(const glslang::TType&);158void TranslateLiterals(const glslang::TVector<const glslang::TIntermConstantUnion*>&, std::vector<unsigned>&) const;159void addIndirectionIndexCapabilities(const glslang::TType& baseType, const glslang::TType& indexType);160spv::Id createSpvVariable(const glslang::TIntermSymbol*, spv::Id forcedType);161spv::Id getSampledType(const glslang::TSampler&);162spv::Id getInvertedSwizzleType(const glslang::TIntermTyped&);163spv::Id createInvertedSwizzle(spv::Decoration precision, const glslang::TIntermTyped&, spv::Id parentResult);164void convertSwizzle(const glslang::TIntermAggregate&, std::vector<unsigned>& swizzle);165spv::Id convertGlslangToSpvType(const glslang::TType& type, bool forwardReferenceOnly = false);166spv::Id convertGlslangToSpvType(const glslang::TType& type, glslang::TLayoutPacking, const glslang::TQualifier&,167bool lastBufferBlockMember, bool forwardReferenceOnly = false);168void applySpirvDecorate(const glslang::TType& type, spv::Id id, std::optional<int> member);169bool filterMember(const glslang::TType& member);170spv::Id convertGlslangStructToSpvType(const glslang::TType&, const glslang::TTypeList* glslangStruct,171glslang::TLayoutPacking, const glslang::TQualifier&);172spv::LinkageType convertGlslangLinkageToSpv(glslang::TLinkType glslangLinkType);173void decorateStructType(const glslang::TType&, const glslang::TTypeList* glslangStruct, glslang::TLayoutPacking,174const glslang::TQualifier&, spv::Id, const std::vector<spv::Id>& spvMembers);175spv::Id makeArraySizeId(const glslang::TArraySizes&, int dim, bool allowZero = false);176spv::Id accessChainLoad(const glslang::TType& type);177void accessChainStore(const glslang::TType& type, spv::Id rvalue);178void multiTypeStore(const glslang::TType&, spv::Id rValue);179spv::Id convertLoadedBoolInUniformToUint(const glslang::TType& type, spv::Id nominalTypeId, spv::Id loadedId);180glslang::TLayoutPacking getExplicitLayout(const glslang::TType& type) const;181int getArrayStride(const glslang::TType& arrayType, glslang::TLayoutPacking, glslang::TLayoutMatrix);182int getMatrixStride(const glslang::TType& matrixType, glslang::TLayoutPacking, glslang::TLayoutMatrix);183void updateMemberOffset(const glslang::TType& structType, const glslang::TType& memberType, int& currentOffset,184int& nextOffset, glslang::TLayoutPacking, glslang::TLayoutMatrix);185void declareUseOfStructMember(const glslang::TTypeList& members, int glslangMember);186187bool isShaderEntryPoint(const glslang::TIntermAggregate* node);188bool writableParam(glslang::TStorageQualifier) const;189bool originalParam(glslang::TStorageQualifier, const glslang::TType&, bool implicitThisParam);190void makeFunctions(const glslang::TIntermSequence&);191void makeGlobalInitializers(const glslang::TIntermSequence&);192void collectRayTracingLinkerObjects();193void visitFunctions(const glslang::TIntermSequence&);194void handleFunctionEntry(const glslang::TIntermAggregate* node);195void translateArguments(const glslang::TIntermAggregate& node, std::vector<spv::Id>& arguments,196spv::Builder::AccessChain::CoherentFlags &lvalueCoherentFlags);197void translateArguments(glslang::TIntermUnary& node, std::vector<spv::Id>& arguments);198spv::Id createImageTextureFunctionCall(glslang::TIntermOperator* node);199spv::Id handleUserFunctionCall(const glslang::TIntermAggregate*);200201spv::Id createBinaryOperation(glslang::TOperator op, OpDecorations&, spv::Id typeId, spv::Id left, spv::Id right,202glslang::TBasicType typeProxy, bool reduceComparison = true);203spv::Id createBinaryMatrixOperation(spv::Op, OpDecorations&, spv::Id typeId, spv::Id left, spv::Id right);204spv::Id createUnaryOperation(glslang::TOperator op, OpDecorations&, spv::Id typeId, spv::Id operand,205glslang::TBasicType typeProxy,206const spv::Builder::AccessChain::CoherentFlags &lvalueCoherentFlags,207const glslang::TType &opType);208spv::Id createUnaryMatrixOperation(spv::Op op, OpDecorations&, spv::Id typeId, spv::Id operand,209glslang::TBasicType typeProxy);210spv::Id createConversion(glslang::TOperator op, OpDecorations&, spv::Id destTypeId, spv::Id operand,211glslang::TBasicType typeProxy);212spv::Id createIntWidthConversion(glslang::TOperator op, spv::Id operand, int vectorSize, spv::Id destType);213spv::Id makeSmearedConstant(spv::Id constant, int vectorSize);214spv::Id createAtomicOperation(glslang::TOperator op, spv::Decoration precision, spv::Id typeId,215std::vector<spv::Id>& operands, glslang::TBasicType typeProxy,216const spv::Builder::AccessChain::CoherentFlags &lvalueCoherentFlags,217const glslang::TType &opType);218spv::Id createInvocationsOperation(glslang::TOperator op, spv::Id typeId, std::vector<spv::Id>& operands,219glslang::TBasicType typeProxy);220spv::Id CreateInvocationsVectorOperation(spv::Op op, spv::GroupOperation groupOperation,221spv::Id typeId, std::vector<spv::Id>& operands);222spv::Id createSubgroupOperation(glslang::TOperator op, spv::Id typeId, std::vector<spv::Id>& operands,223glslang::TBasicType typeProxy);224spv::Id createMiscOperation(glslang::TOperator op, spv::Decoration precision, spv::Id typeId,225std::vector<spv::Id>& operands, glslang::TBasicType typeProxy);226spv::Id createNoArgOperation(glslang::TOperator op, spv::Decoration precision, spv::Id typeId);227spv::Id getSymbolId(const glslang::TIntermSymbol* node);228void addMeshNVDecoration(spv::Id id, int member, const glslang::TQualifier & qualifier);229bool hasQCOMImageProceessingDecoration(spv::Id id, spv::Decoration decor);230void addImageProcessingQCOMDecoration(spv::Id id, spv::Decoration decor);231void addImageProcessing2QCOMDecoration(spv::Id id, bool isForGather);232spv::Id createSpvConstant(const glslang::TIntermTyped&);233spv::Id createSpvConstantFromConstUnionArray(const glslang::TType& type, const glslang::TConstUnionArray&,234int& nextConst, bool specConstant);235bool isTrivialLeaf(const glslang::TIntermTyped* node);236bool isTrivial(const glslang::TIntermTyped* node);237spv::Id createShortCircuit(glslang::TOperator, glslang::TIntermTyped& left, glslang::TIntermTyped& right);238spv::Id getExtBuiltins(const char* name);239std::pair<spv::Id, spv::Id> getForcedType(glslang::TBuiltInVariable builtIn, const glslang::TType&);240spv::Id translateForcedType(spv::Id object);241spv::Id createCompositeConstruct(spv::Id typeId, std::vector<spv::Id> constituents);242243glslang::SpvOptions& options;244spv::Function* shaderEntry;245spv::Function* currentFunction;246spv::Instruction* entryPoint;247int sequenceDepth;248249spv::SpvBuildLogger* logger;250251// There is a 1:1 mapping between a spv builder and a module; this is thread safe252spv::Builder builder;253bool inEntryPoint;254bool entryPointTerminated;255bool linkageOnly; // true when visiting the set of objects in the AST present only for256// establishing interface, whether or not they were statically used257std::set<spv::Id> iOSet; // all input/output variables from either static use or declaration of interface258const glslang::TIntermediate* glslangIntermediate;259bool nanMinMaxClamp; // true if use NMin/NMax/NClamp instead of FMin/FMax/FClamp260spv::Id stdBuiltins;261spv::Id nonSemanticDebugPrintf;262std::unordered_map<std::string, spv::Id> extBuiltinMap;263264std::unordered_map<long long, spv::Id> symbolValues;265std::unordered_map<uint32_t, spv::Id> builtInVariableIds;266std::unordered_set<long long> rValueParameters; // set of formal function parameters passed as rValues,267// rather than a pointer268std::unordered_map<std::string, spv::Function*> functionMap;269std::unordered_map<const glslang::TTypeList*, spv::Id> structMap[glslang::ElpCount][glslang::ElmCount];270// for mapping glslang block indices to spv indices (e.g., due to hidden members):271std::unordered_map<long long, std::vector<int>> memberRemapper;272// for mapping glslang symbol struct to symbol Id273std::unordered_map<const glslang::TTypeList*, long long> glslangTypeToIdMap;274std::stack<bool> breakForLoop; // false means break for switch275std::unordered_map<std::string, const glslang::TIntermSymbol*> counterOriginator;276// Map pointee types for EbtReference to their forward pointers277std::map<const glslang::TType *, spv::Id> forwardPointers;278// Type forcing, for when SPIR-V wants a different type than the AST,279// requiring local translation to and from SPIR-V type on every access.280// Maps <builtin-variable-id -> AST-required-type-id>281std::unordered_map<spv::Id, spv::Id> forceType;282// Used by Task shader while generating opearnds for OpEmitMeshTasksEXT283spv::Id taskPayloadID;284// Used later for generating OpTraceKHR/OpExecuteCallableKHR/OpHitObjectRecordHit*/OpHitObjectGetShaderBindingTableData285std::unordered_map<unsigned int, glslang::TIntermSymbol *> locationToSymbol[4];286std::unordered_map<spv::Id, std::vector<spv::Decoration> > idToQCOMDecorations;287};288289//290// Helper functions for translating glslang representations to SPIR-V enumerants.291//292293// Translate glslang profile to SPIR-V source language.294spv::SourceLanguage TranslateSourceLanguage(glslang::EShSource source, EProfile profile)295{296switch (source) {297case glslang::EShSourceGlsl:298switch (profile) {299case ENoProfile:300case ECoreProfile:301case ECompatibilityProfile:302return spv::SourceLanguageGLSL;303case EEsProfile:304return spv::SourceLanguageESSL;305default:306return spv::SourceLanguageUnknown;307}308case glslang::EShSourceHlsl:309return spv::SourceLanguageHLSL;310default:311return spv::SourceLanguageUnknown;312}313}314315// Translate glslang language (stage) to SPIR-V execution model.316spv::ExecutionModel TranslateExecutionModel(EShLanguage stage, bool isMeshShaderEXT = false)317{318switch (stage) {319case EShLangVertex: return spv::ExecutionModelVertex;320case EShLangFragment: return spv::ExecutionModelFragment;321case EShLangCompute: return spv::ExecutionModelGLCompute;322case EShLangTessControl: return spv::ExecutionModelTessellationControl;323case EShLangTessEvaluation: return spv::ExecutionModelTessellationEvaluation;324case EShLangGeometry: return spv::ExecutionModelGeometry;325case EShLangRayGen: return spv::ExecutionModelRayGenerationKHR;326case EShLangIntersect: return spv::ExecutionModelIntersectionKHR;327case EShLangAnyHit: return spv::ExecutionModelAnyHitKHR;328case EShLangClosestHit: return spv::ExecutionModelClosestHitKHR;329case EShLangMiss: return spv::ExecutionModelMissKHR;330case EShLangCallable: return spv::ExecutionModelCallableKHR;331case EShLangTask: return (isMeshShaderEXT)? spv::ExecutionModelTaskEXT : spv::ExecutionModelTaskNV;332case EShLangMesh: return (isMeshShaderEXT)? spv::ExecutionModelMeshEXT: spv::ExecutionModelMeshNV;333default:334assert(0);335return spv::ExecutionModelFragment;336}337}338339// Translate glslang sampler type to SPIR-V dimensionality.340spv::Dim TranslateDimensionality(const glslang::TSampler& sampler)341{342switch (sampler.dim) {343case glslang::Esd1D: return spv::Dim1D;344case glslang::Esd2D: return spv::Dim2D;345case glslang::Esd3D: return spv::Dim3D;346case glslang::EsdCube: return spv::DimCube;347case glslang::EsdRect: return spv::DimRect;348case glslang::EsdBuffer: return spv::DimBuffer;349case glslang::EsdSubpass: return spv::DimSubpassData;350case glslang::EsdAttachmentEXT: return spv::DimTileImageDataEXT;351default:352assert(0);353return spv::Dim2D;354}355}356357// Translate glslang precision to SPIR-V precision decorations.358spv::Decoration TranslatePrecisionDecoration(glslang::TPrecisionQualifier glslangPrecision)359{360switch (glslangPrecision) {361case glslang::EpqLow: return spv::DecorationRelaxedPrecision;362case glslang::EpqMedium: return spv::DecorationRelaxedPrecision;363default:364return spv::NoPrecision;365}366}367368// Translate glslang type to SPIR-V precision decorations.369spv::Decoration TranslatePrecisionDecoration(const glslang::TType& type)370{371return TranslatePrecisionDecoration(type.getQualifier().precision);372}373374// Translate glslang type to SPIR-V block decorations.375spv::Decoration TranslateBlockDecoration(const glslang::TStorageQualifier storage, bool useStorageBuffer)376{377switch (storage) {378case glslang::EvqUniform: return spv::DecorationBlock;379case glslang::EvqBuffer: return useStorageBuffer ? spv::DecorationBlock : spv::DecorationBufferBlock;380case glslang::EvqVaryingIn: return spv::DecorationBlock;381case glslang::EvqVaryingOut: return spv::DecorationBlock;382case glslang::EvqShared: return spv::DecorationBlock;383case glslang::EvqPayload: return spv::DecorationBlock;384case glslang::EvqPayloadIn: return spv::DecorationBlock;385case glslang::EvqHitAttr: return spv::DecorationBlock;386case glslang::EvqCallableData: return spv::DecorationBlock;387case glslang::EvqCallableDataIn: return spv::DecorationBlock;388case glslang::EvqHitObjectAttrNV: return spv::DecorationBlock;389default:390assert(0);391break;392}393394return spv::DecorationMax;395}396397// Translate glslang type to SPIR-V memory decorations.398void TranslateMemoryDecoration(const glslang::TQualifier& qualifier, std::vector<spv::Decoration>& memory,399bool useVulkanMemoryModel)400{401if (!useVulkanMemoryModel) {402if (qualifier.isVolatile()) {403memory.push_back(spv::DecorationVolatile);404memory.push_back(spv::DecorationCoherent);405} else if (qualifier.isCoherent()) {406memory.push_back(spv::DecorationCoherent);407}408}409if (qualifier.isRestrict())410memory.push_back(spv::DecorationRestrict);411if (qualifier.isReadOnly())412memory.push_back(spv::DecorationNonWritable);413if (qualifier.isWriteOnly())414memory.push_back(spv::DecorationNonReadable);415}416417// Translate glslang type to SPIR-V layout decorations.418spv::Decoration TranslateLayoutDecoration(const glslang::TType& type, glslang::TLayoutMatrix matrixLayout)419{420if (type.isMatrix()) {421switch (matrixLayout) {422case glslang::ElmRowMajor:423return spv::DecorationRowMajor;424case glslang::ElmColumnMajor:425return spv::DecorationColMajor;426default:427// opaque layouts don't need a majorness428return spv::DecorationMax;429}430} else {431switch (type.getBasicType()) {432default:433return spv::DecorationMax;434break;435case glslang::EbtBlock:436switch (type.getQualifier().storage) {437case glslang::EvqShared:438case glslang::EvqUniform:439case glslang::EvqBuffer:440switch (type.getQualifier().layoutPacking) {441case glslang::ElpShared: return spv::DecorationGLSLShared;442case glslang::ElpPacked: return spv::DecorationGLSLPacked;443default:444return spv::DecorationMax;445}446case glslang::EvqVaryingIn:447case glslang::EvqVaryingOut:448if (type.getQualifier().isTaskMemory()) {449switch (type.getQualifier().layoutPacking) {450case glslang::ElpShared: return spv::DecorationGLSLShared;451case glslang::ElpPacked: return spv::DecorationGLSLPacked;452default: break;453}454} else {455assert(type.getQualifier().layoutPacking == glslang::ElpNone);456}457return spv::DecorationMax;458case glslang::EvqPayload:459case glslang::EvqPayloadIn:460case glslang::EvqHitAttr:461case glslang::EvqCallableData:462case glslang::EvqCallableDataIn:463case glslang::EvqHitObjectAttrNV:464return spv::DecorationMax;465default:466assert(0);467return spv::DecorationMax;468}469}470}471}472473// Translate glslang type to SPIR-V interpolation decorations.474// Returns spv::DecorationMax when no decoration475// should be applied.476spv::Decoration TGlslangToSpvTraverser::TranslateInterpolationDecoration(const glslang::TQualifier& qualifier)477{478if (qualifier.smooth)479// Smooth decoration doesn't exist in SPIR-V 1.0480return spv::DecorationMax;481else if (qualifier.isNonPerspective())482return spv::DecorationNoPerspective;483else if (qualifier.flat)484return spv::DecorationFlat;485else if (qualifier.isExplicitInterpolation()) {486builder.addExtension(spv::E_SPV_AMD_shader_explicit_vertex_parameter);487return spv::DecorationExplicitInterpAMD;488}489else490return spv::DecorationMax;491}492493// Translate glslang type to SPIR-V auxiliary storage decorations.494// Returns spv::DecorationMax when no decoration495// should be applied.496spv::Decoration TGlslangToSpvTraverser::TranslateAuxiliaryStorageDecoration(const glslang::TQualifier& qualifier)497{498if (qualifier.centroid)499return spv::DecorationCentroid;500else if (qualifier.patch)501return spv::DecorationPatch;502else if (qualifier.sample) {503builder.addCapability(spv::CapabilitySampleRateShading);504return spv::DecorationSample;505}506507return spv::DecorationMax;508}509510// If glslang type is invariant, return SPIR-V invariant decoration.511spv::Decoration TranslateInvariantDecoration(const glslang::TQualifier& qualifier)512{513if (qualifier.invariant)514return spv::DecorationInvariant;515else516return spv::DecorationMax;517}518519// If glslang type is noContraction, return SPIR-V NoContraction decoration.520spv::Decoration TranslateNoContractionDecoration(const glslang::TQualifier& qualifier)521{522if (qualifier.isNoContraction())523return spv::DecorationNoContraction;524else525return spv::DecorationMax;526}527528// If glslang type is nonUniform, return SPIR-V NonUniform decoration.529spv::Decoration TGlslangToSpvTraverser::TranslateNonUniformDecoration(const glslang::TQualifier& qualifier)530{531if (qualifier.isNonUniform()) {532builder.addIncorporatedExtension("SPV_EXT_descriptor_indexing", spv::Spv_1_5);533builder.addCapability(spv::CapabilityShaderNonUniformEXT);534return spv::DecorationNonUniformEXT;535} else536return spv::DecorationMax;537}538539// If lvalue flags contains nonUniform, return SPIR-V NonUniform decoration.540spv::Decoration TGlslangToSpvTraverser::TranslateNonUniformDecoration(541const spv::Builder::AccessChain::CoherentFlags& coherentFlags)542{543if (coherentFlags.isNonUniform()) {544builder.addIncorporatedExtension("SPV_EXT_descriptor_indexing", spv::Spv_1_5);545builder.addCapability(spv::CapabilityShaderNonUniformEXT);546return spv::DecorationNonUniformEXT;547} else548return spv::DecorationMax;549}550551spv::MemoryAccessMask TGlslangToSpvTraverser::TranslateMemoryAccess(552const spv::Builder::AccessChain::CoherentFlags &coherentFlags)553{554spv::MemoryAccessMask mask = spv::MemoryAccessMaskNone;555556if (!glslangIntermediate->usingVulkanMemoryModel() || coherentFlags.isImage)557return mask;558559if (coherentFlags.isVolatile() || coherentFlags.anyCoherent()) {560mask = mask | spv::MemoryAccessMakePointerAvailableKHRMask |561spv::MemoryAccessMakePointerVisibleKHRMask;562}563564if (coherentFlags.nonprivate) {565mask = mask | spv::MemoryAccessNonPrivatePointerKHRMask;566}567if (coherentFlags.volatil) {568mask = mask | spv::MemoryAccessVolatileMask;569}570if (mask != spv::MemoryAccessMaskNone) {571builder.addCapability(spv::CapabilityVulkanMemoryModelKHR);572}573574return mask;575}576577spv::ImageOperandsMask TGlslangToSpvTraverser::TranslateImageOperands(578const spv::Builder::AccessChain::CoherentFlags &coherentFlags)579{580spv::ImageOperandsMask mask = spv::ImageOperandsMaskNone;581582if (!glslangIntermediate->usingVulkanMemoryModel())583return mask;584585if (coherentFlags.volatil ||586coherentFlags.anyCoherent()) {587mask = mask | spv::ImageOperandsMakeTexelAvailableKHRMask |588spv::ImageOperandsMakeTexelVisibleKHRMask;589}590if (coherentFlags.nonprivate) {591mask = mask | spv::ImageOperandsNonPrivateTexelKHRMask;592}593if (coherentFlags.volatil) {594mask = mask | spv::ImageOperandsVolatileTexelKHRMask;595}596if (mask != spv::ImageOperandsMaskNone) {597builder.addCapability(spv::CapabilityVulkanMemoryModelKHR);598}599600return mask;601}602603spv::Builder::AccessChain::CoherentFlags TGlslangToSpvTraverser::TranslateCoherent(const glslang::TType& type)604{605spv::Builder::AccessChain::CoherentFlags flags = {};606flags.coherent = type.getQualifier().coherent;607flags.devicecoherent = type.getQualifier().devicecoherent;608flags.queuefamilycoherent = type.getQualifier().queuefamilycoherent;609// shared variables are implicitly workgroupcoherent in GLSL.610flags.workgroupcoherent = type.getQualifier().workgroupcoherent ||611type.getQualifier().storage == glslang::EvqShared;612flags.subgroupcoherent = type.getQualifier().subgroupcoherent;613flags.shadercallcoherent = type.getQualifier().shadercallcoherent;614flags.volatil = type.getQualifier().volatil;615// *coherent variables are implicitly nonprivate in GLSL616flags.nonprivate = type.getQualifier().nonprivate ||617flags.anyCoherent() ||618flags.volatil;619flags.isImage = type.getBasicType() == glslang::EbtSampler;620flags.nonUniform = type.getQualifier().nonUniform;621return flags;622}623624spv::Scope TGlslangToSpvTraverser::TranslateMemoryScope(625const spv::Builder::AccessChain::CoherentFlags &coherentFlags)626{627spv::Scope scope = spv::ScopeMax;628629if (coherentFlags.volatil || coherentFlags.coherent) {630// coherent defaults to Device scope in the old model, QueueFamilyKHR scope in the new model631scope = glslangIntermediate->usingVulkanMemoryModel() ? spv::ScopeQueueFamilyKHR : spv::ScopeDevice;632} else if (coherentFlags.devicecoherent) {633scope = spv::ScopeDevice;634} else if (coherentFlags.queuefamilycoherent) {635scope = spv::ScopeQueueFamilyKHR;636} else if (coherentFlags.workgroupcoherent) {637scope = spv::ScopeWorkgroup;638} else if (coherentFlags.subgroupcoherent) {639scope = spv::ScopeSubgroup;640} else if (coherentFlags.shadercallcoherent) {641scope = spv::ScopeShaderCallKHR;642}643if (glslangIntermediate->usingVulkanMemoryModel() && scope == spv::ScopeDevice) {644builder.addCapability(spv::CapabilityVulkanMemoryModelDeviceScopeKHR);645}646647return scope;648}649650// Translate a glslang built-in variable to a SPIR-V built in decoration. Also generate651// associated capabilities when required. For some built-in variables, a capability652// is generated only when using the variable in an executable instruction, but not when653// just declaring a struct member variable with it. This is true for PointSize,654// ClipDistance, and CullDistance.655spv::BuiltIn TGlslangToSpvTraverser::TranslateBuiltInDecoration(glslang::TBuiltInVariable builtIn,656bool memberDeclaration)657{658switch (builtIn) {659case glslang::EbvPointSize:660// Defer adding the capability until the built-in is actually used.661if (! memberDeclaration) {662switch (glslangIntermediate->getStage()) {663case EShLangGeometry:664builder.addCapability(spv::CapabilityGeometryPointSize);665break;666case EShLangTessControl:667case EShLangTessEvaluation:668builder.addCapability(spv::CapabilityTessellationPointSize);669break;670default:671break;672}673}674return spv::BuiltInPointSize;675676case glslang::EbvPosition: return spv::BuiltInPosition;677case glslang::EbvVertexId: return spv::BuiltInVertexId;678case glslang::EbvInstanceId: return spv::BuiltInInstanceId;679case glslang::EbvVertexIndex: return spv::BuiltInVertexIndex;680case glslang::EbvInstanceIndex: return spv::BuiltInInstanceIndex;681682case glslang::EbvFragCoord: return spv::BuiltInFragCoord;683case glslang::EbvPointCoord: return spv::BuiltInPointCoord;684case glslang::EbvFace: return spv::BuiltInFrontFacing;685case glslang::EbvFragDepth: return spv::BuiltInFragDepth;686687case glslang::EbvNumWorkGroups: return spv::BuiltInNumWorkgroups;688case glslang::EbvWorkGroupSize: return spv::BuiltInWorkgroupSize;689case glslang::EbvWorkGroupId: return spv::BuiltInWorkgroupId;690case glslang::EbvLocalInvocationId: return spv::BuiltInLocalInvocationId;691case glslang::EbvLocalInvocationIndex: return spv::BuiltInLocalInvocationIndex;692case glslang::EbvGlobalInvocationId: return spv::BuiltInGlobalInvocationId;693694// These *Distance capabilities logically belong here, but if the member is declared and695// then never used, consumers of SPIR-V prefer the capability not be declared.696// They are now generated when used, rather than here when declared.697// Potentially, the specification should be more clear what the minimum698// use needed is to trigger the capability.699//700case glslang::EbvClipDistance:701if (!memberDeclaration)702builder.addCapability(spv::CapabilityClipDistance);703return spv::BuiltInClipDistance;704705case glslang::EbvCullDistance:706if (!memberDeclaration)707builder.addCapability(spv::CapabilityCullDistance);708return spv::BuiltInCullDistance;709710case glslang::EbvViewportIndex:711if (glslangIntermediate->getStage() == EShLangGeometry ||712glslangIntermediate->getStage() == EShLangFragment) {713builder.addCapability(spv::CapabilityMultiViewport);714}715if (glslangIntermediate->getStage() == EShLangVertex ||716glslangIntermediate->getStage() == EShLangTessControl ||717glslangIntermediate->getStage() == EShLangTessEvaluation) {718719if (builder.getSpvVersion() < spv::Spv_1_5) {720builder.addIncorporatedExtension(spv::E_SPV_EXT_shader_viewport_index_layer, spv::Spv_1_5);721builder.addCapability(spv::CapabilityShaderViewportIndexLayerEXT);722}723else724builder.addCapability(spv::CapabilityShaderViewportIndex);725}726return spv::BuiltInViewportIndex;727728case glslang::EbvSampleId:729builder.addCapability(spv::CapabilitySampleRateShading);730return spv::BuiltInSampleId;731732case glslang::EbvSamplePosition:733builder.addCapability(spv::CapabilitySampleRateShading);734return spv::BuiltInSamplePosition;735736case glslang::EbvSampleMask:737return spv::BuiltInSampleMask;738739case glslang::EbvLayer:740if (glslangIntermediate->getStage() == EShLangMesh) {741return spv::BuiltInLayer;742}743if (glslangIntermediate->getStage() == EShLangGeometry ||744glslangIntermediate->getStage() == EShLangFragment) {745builder.addCapability(spv::CapabilityGeometry);746}747if (glslangIntermediate->getStage() == EShLangVertex ||748glslangIntermediate->getStage() == EShLangTessControl ||749glslangIntermediate->getStage() == EShLangTessEvaluation) {750751if (builder.getSpvVersion() < spv::Spv_1_5) {752builder.addIncorporatedExtension(spv::E_SPV_EXT_shader_viewport_index_layer, spv::Spv_1_5);753builder.addCapability(spv::CapabilityShaderViewportIndexLayerEXT);754} else755builder.addCapability(spv::CapabilityShaderLayer);756}757return spv::BuiltInLayer;758759case glslang::EbvBaseVertex:760builder.addIncorporatedExtension(spv::E_SPV_KHR_shader_draw_parameters, spv::Spv_1_3);761builder.addCapability(spv::CapabilityDrawParameters);762return spv::BuiltInBaseVertex;763764case glslang::EbvBaseInstance:765builder.addIncorporatedExtension(spv::E_SPV_KHR_shader_draw_parameters, spv::Spv_1_3);766builder.addCapability(spv::CapabilityDrawParameters);767return spv::BuiltInBaseInstance;768769case glslang::EbvDrawId:770builder.addIncorporatedExtension(spv::E_SPV_KHR_shader_draw_parameters, spv::Spv_1_3);771builder.addCapability(spv::CapabilityDrawParameters);772return spv::BuiltInDrawIndex;773774case glslang::EbvPrimitiveId:775if (glslangIntermediate->getStage() == EShLangFragment)776builder.addCapability(spv::CapabilityGeometry);777return spv::BuiltInPrimitiveId;778779case glslang::EbvFragStencilRef:780builder.addExtension(spv::E_SPV_EXT_shader_stencil_export);781builder.addCapability(spv::CapabilityStencilExportEXT);782return spv::BuiltInFragStencilRefEXT;783784case glslang::EbvShadingRateKHR:785builder.addExtension(spv::E_SPV_KHR_fragment_shading_rate);786builder.addCapability(spv::CapabilityFragmentShadingRateKHR);787return spv::BuiltInShadingRateKHR;788789case glslang::EbvPrimitiveShadingRateKHR:790builder.addExtension(spv::E_SPV_KHR_fragment_shading_rate);791builder.addCapability(spv::CapabilityFragmentShadingRateKHR);792return spv::BuiltInPrimitiveShadingRateKHR;793794case glslang::EbvInvocationId: return spv::BuiltInInvocationId;795case glslang::EbvTessLevelInner: return spv::BuiltInTessLevelInner;796case glslang::EbvTessLevelOuter: return spv::BuiltInTessLevelOuter;797case glslang::EbvTessCoord: return spv::BuiltInTessCoord;798case glslang::EbvPatchVertices: return spv::BuiltInPatchVertices;799case glslang::EbvHelperInvocation: return spv::BuiltInHelperInvocation;800801case glslang::EbvSubGroupSize:802builder.addExtension(spv::E_SPV_KHR_shader_ballot);803builder.addCapability(spv::CapabilitySubgroupBallotKHR);804return spv::BuiltInSubgroupSize;805806case glslang::EbvSubGroupInvocation:807builder.addExtension(spv::E_SPV_KHR_shader_ballot);808builder.addCapability(spv::CapabilitySubgroupBallotKHR);809return spv::BuiltInSubgroupLocalInvocationId;810811case glslang::EbvSubGroupEqMask:812builder.addExtension(spv::E_SPV_KHR_shader_ballot);813builder.addCapability(spv::CapabilitySubgroupBallotKHR);814return spv::BuiltInSubgroupEqMask;815816case glslang::EbvSubGroupGeMask:817builder.addExtension(spv::E_SPV_KHR_shader_ballot);818builder.addCapability(spv::CapabilitySubgroupBallotKHR);819return spv::BuiltInSubgroupGeMask;820821case glslang::EbvSubGroupGtMask:822builder.addExtension(spv::E_SPV_KHR_shader_ballot);823builder.addCapability(spv::CapabilitySubgroupBallotKHR);824return spv::BuiltInSubgroupGtMask;825826case glslang::EbvSubGroupLeMask:827builder.addExtension(spv::E_SPV_KHR_shader_ballot);828builder.addCapability(spv::CapabilitySubgroupBallotKHR);829return spv::BuiltInSubgroupLeMask;830831case glslang::EbvSubGroupLtMask:832builder.addExtension(spv::E_SPV_KHR_shader_ballot);833builder.addCapability(spv::CapabilitySubgroupBallotKHR);834return spv::BuiltInSubgroupLtMask;835836case glslang::EbvNumSubgroups:837builder.addCapability(spv::CapabilityGroupNonUniform);838return spv::BuiltInNumSubgroups;839840case glslang::EbvSubgroupID:841builder.addCapability(spv::CapabilityGroupNonUniform);842return spv::BuiltInSubgroupId;843844case glslang::EbvSubgroupSize2:845builder.addCapability(spv::CapabilityGroupNonUniform);846return spv::BuiltInSubgroupSize;847848case glslang::EbvSubgroupInvocation2:849builder.addCapability(spv::CapabilityGroupNonUniform);850return spv::BuiltInSubgroupLocalInvocationId;851852case glslang::EbvSubgroupEqMask2:853builder.addCapability(spv::CapabilityGroupNonUniform);854builder.addCapability(spv::CapabilityGroupNonUniformBallot);855return spv::BuiltInSubgroupEqMask;856857case glslang::EbvSubgroupGeMask2:858builder.addCapability(spv::CapabilityGroupNonUniform);859builder.addCapability(spv::CapabilityGroupNonUniformBallot);860return spv::BuiltInSubgroupGeMask;861862case glslang::EbvSubgroupGtMask2:863builder.addCapability(spv::CapabilityGroupNonUniform);864builder.addCapability(spv::CapabilityGroupNonUniformBallot);865return spv::BuiltInSubgroupGtMask;866867case glslang::EbvSubgroupLeMask2:868builder.addCapability(spv::CapabilityGroupNonUniform);869builder.addCapability(spv::CapabilityGroupNonUniformBallot);870return spv::BuiltInSubgroupLeMask;871872case glslang::EbvSubgroupLtMask2:873builder.addCapability(spv::CapabilityGroupNonUniform);874builder.addCapability(spv::CapabilityGroupNonUniformBallot);875return spv::BuiltInSubgroupLtMask;876877case glslang::EbvBaryCoordNoPersp:878builder.addExtension(spv::E_SPV_AMD_shader_explicit_vertex_parameter);879return spv::BuiltInBaryCoordNoPerspAMD;880881case glslang::EbvBaryCoordNoPerspCentroid:882builder.addExtension(spv::E_SPV_AMD_shader_explicit_vertex_parameter);883return spv::BuiltInBaryCoordNoPerspCentroidAMD;884885case glslang::EbvBaryCoordNoPerspSample:886builder.addExtension(spv::E_SPV_AMD_shader_explicit_vertex_parameter);887return spv::BuiltInBaryCoordNoPerspSampleAMD;888889case glslang::EbvBaryCoordSmooth:890builder.addExtension(spv::E_SPV_AMD_shader_explicit_vertex_parameter);891return spv::BuiltInBaryCoordSmoothAMD;892893case glslang::EbvBaryCoordSmoothCentroid:894builder.addExtension(spv::E_SPV_AMD_shader_explicit_vertex_parameter);895return spv::BuiltInBaryCoordSmoothCentroidAMD;896897case glslang::EbvBaryCoordSmoothSample:898builder.addExtension(spv::E_SPV_AMD_shader_explicit_vertex_parameter);899return spv::BuiltInBaryCoordSmoothSampleAMD;900901case glslang::EbvBaryCoordPullModel:902builder.addExtension(spv::E_SPV_AMD_shader_explicit_vertex_parameter);903return spv::BuiltInBaryCoordPullModelAMD;904905case glslang::EbvDeviceIndex:906builder.addIncorporatedExtension(spv::E_SPV_KHR_device_group, spv::Spv_1_3);907builder.addCapability(spv::CapabilityDeviceGroup);908return spv::BuiltInDeviceIndex;909910case glslang::EbvViewIndex:911builder.addIncorporatedExtension(spv::E_SPV_KHR_multiview, spv::Spv_1_3);912builder.addCapability(spv::CapabilityMultiView);913return spv::BuiltInViewIndex;914915case glslang::EbvFragSizeEXT:916builder.addExtension(spv::E_SPV_EXT_fragment_invocation_density);917builder.addCapability(spv::CapabilityFragmentDensityEXT);918return spv::BuiltInFragSizeEXT;919920case glslang::EbvFragInvocationCountEXT:921builder.addExtension(spv::E_SPV_EXT_fragment_invocation_density);922builder.addCapability(spv::CapabilityFragmentDensityEXT);923return spv::BuiltInFragInvocationCountEXT;924925case glslang::EbvViewportMaskNV:926if (!memberDeclaration) {927builder.addExtension(spv::E_SPV_NV_viewport_array2);928builder.addCapability(spv::CapabilityShaderViewportMaskNV);929}930return spv::BuiltInViewportMaskNV;931case glslang::EbvSecondaryPositionNV:932if (!memberDeclaration) {933builder.addExtension(spv::E_SPV_NV_stereo_view_rendering);934builder.addCapability(spv::CapabilityShaderStereoViewNV);935}936return spv::BuiltInSecondaryPositionNV;937case glslang::EbvSecondaryViewportMaskNV:938if (!memberDeclaration) {939builder.addExtension(spv::E_SPV_NV_stereo_view_rendering);940builder.addCapability(spv::CapabilityShaderStereoViewNV);941}942return spv::BuiltInSecondaryViewportMaskNV;943case glslang::EbvPositionPerViewNV:944if (!memberDeclaration) {945builder.addExtension(spv::E_SPV_NVX_multiview_per_view_attributes);946builder.addCapability(spv::CapabilityPerViewAttributesNV);947}948return spv::BuiltInPositionPerViewNV;949case glslang::EbvViewportMaskPerViewNV:950if (!memberDeclaration) {951builder.addExtension(spv::E_SPV_NVX_multiview_per_view_attributes);952builder.addCapability(spv::CapabilityPerViewAttributesNV);953}954return spv::BuiltInViewportMaskPerViewNV;955case glslang::EbvFragFullyCoveredNV:956builder.addExtension(spv::E_SPV_EXT_fragment_fully_covered);957builder.addCapability(spv::CapabilityFragmentFullyCoveredEXT);958return spv::BuiltInFullyCoveredEXT;959case glslang::EbvFragmentSizeNV:960builder.addExtension(spv::E_SPV_NV_shading_rate);961builder.addCapability(spv::CapabilityShadingRateNV);962return spv::BuiltInFragmentSizeNV;963case glslang::EbvInvocationsPerPixelNV:964builder.addExtension(spv::E_SPV_NV_shading_rate);965builder.addCapability(spv::CapabilityShadingRateNV);966return spv::BuiltInInvocationsPerPixelNV;967968// ray tracing969case glslang::EbvLaunchId:970return spv::BuiltInLaunchIdKHR;971case glslang::EbvLaunchSize:972return spv::BuiltInLaunchSizeKHR;973case glslang::EbvWorldRayOrigin:974return spv::BuiltInWorldRayOriginKHR;975case glslang::EbvWorldRayDirection:976return spv::BuiltInWorldRayDirectionKHR;977case glslang::EbvObjectRayOrigin:978return spv::BuiltInObjectRayOriginKHR;979case glslang::EbvObjectRayDirection:980return spv::BuiltInObjectRayDirectionKHR;981case glslang::EbvRayTmin:982return spv::BuiltInRayTminKHR;983case glslang::EbvRayTmax:984return spv::BuiltInRayTmaxKHR;985case glslang::EbvCullMask:986return spv::BuiltInCullMaskKHR;987case glslang::EbvPositionFetch:988return spv::BuiltInHitTriangleVertexPositionsKHR;989case glslang::EbvInstanceCustomIndex:990return spv::BuiltInInstanceCustomIndexKHR;991case glslang::EbvHitT:992{993// this is a GLSL alias of RayTmax994// in SPV_NV_ray_tracing it has a dedicated builtin995// but in SPV_KHR_ray_tracing it gets mapped to RayTmax996auto& extensions = glslangIntermediate->getRequestedExtensions();997if (extensions.find("GL_NV_ray_tracing") != extensions.end()) {998return spv::BuiltInHitTNV;999} else {1000return spv::BuiltInRayTmaxKHR;1001}1002}1003case glslang::EbvHitKind:1004return spv::BuiltInHitKindKHR;1005case glslang::EbvObjectToWorld:1006case glslang::EbvObjectToWorld3x4:1007return spv::BuiltInObjectToWorldKHR;1008case glslang::EbvWorldToObject:1009case glslang::EbvWorldToObject3x4:1010return spv::BuiltInWorldToObjectKHR;1011case glslang::EbvIncomingRayFlags:1012return spv::BuiltInIncomingRayFlagsKHR;1013case glslang::EbvGeometryIndex:1014return spv::BuiltInRayGeometryIndexKHR;1015case glslang::EbvCurrentRayTimeNV:1016builder.addExtension(spv::E_SPV_NV_ray_tracing_motion_blur);1017builder.addCapability(spv::CapabilityRayTracingMotionBlurNV);1018return spv::BuiltInCurrentRayTimeNV;1019case glslang::EbvMicroTrianglePositionNV:1020builder.addCapability(spv::CapabilityRayTracingDisplacementMicromapNV);1021builder.addExtension("SPV_NV_displacement_micromap");1022return spv::BuiltInHitMicroTriangleVertexPositionsNV;1023case glslang::EbvMicroTriangleBaryNV:1024builder.addCapability(spv::CapabilityRayTracingDisplacementMicromapNV);1025builder.addExtension("SPV_NV_displacement_micromap");1026return spv::BuiltInHitMicroTriangleVertexBarycentricsNV;1027case glslang::EbvHitKindFrontFacingMicroTriangleNV:1028builder.addCapability(spv::CapabilityRayTracingDisplacementMicromapNV);1029builder.addExtension("SPV_NV_displacement_micromap");1030return spv::BuiltInHitKindFrontFacingMicroTriangleNV;1031case glslang::EbvHitKindBackFacingMicroTriangleNV:1032builder.addCapability(spv::CapabilityRayTracingDisplacementMicromapNV);1033builder.addExtension("SPV_NV_displacement_micromap");1034return spv::BuiltInHitKindBackFacingMicroTriangleNV;10351036// barycentrics1037case glslang::EbvBaryCoordNV:1038builder.addExtension(spv::E_SPV_NV_fragment_shader_barycentric);1039builder.addCapability(spv::CapabilityFragmentBarycentricNV);1040return spv::BuiltInBaryCoordNV;1041case glslang::EbvBaryCoordNoPerspNV:1042builder.addExtension(spv::E_SPV_NV_fragment_shader_barycentric);1043builder.addCapability(spv::CapabilityFragmentBarycentricNV);1044return spv::BuiltInBaryCoordNoPerspNV;10451046case glslang::EbvBaryCoordEXT:1047builder.addExtension(spv::E_SPV_KHR_fragment_shader_barycentric);1048builder.addCapability(spv::CapabilityFragmentBarycentricKHR);1049return spv::BuiltInBaryCoordKHR;1050case glslang::EbvBaryCoordNoPerspEXT:1051builder.addExtension(spv::E_SPV_KHR_fragment_shader_barycentric);1052builder.addCapability(spv::CapabilityFragmentBarycentricKHR);1053return spv::BuiltInBaryCoordNoPerspKHR;10541055// mesh shaders1056case glslang::EbvTaskCountNV:1057return spv::BuiltInTaskCountNV;1058case glslang::EbvPrimitiveCountNV:1059return spv::BuiltInPrimitiveCountNV;1060case glslang::EbvPrimitiveIndicesNV:1061return spv::BuiltInPrimitiveIndicesNV;1062case glslang::EbvClipDistancePerViewNV:1063return spv::BuiltInClipDistancePerViewNV;1064case glslang::EbvCullDistancePerViewNV:1065return spv::BuiltInCullDistancePerViewNV;1066case glslang::EbvLayerPerViewNV:1067return spv::BuiltInLayerPerViewNV;1068case glslang::EbvMeshViewCountNV:1069return spv::BuiltInMeshViewCountNV;1070case glslang::EbvMeshViewIndicesNV:1071return spv::BuiltInMeshViewIndicesNV;10721073// SPV_EXT_mesh_shader1074case glslang::EbvPrimitivePointIndicesEXT:1075return spv::BuiltInPrimitivePointIndicesEXT;1076case glslang::EbvPrimitiveLineIndicesEXT:1077return spv::BuiltInPrimitiveLineIndicesEXT;1078case glslang::EbvPrimitiveTriangleIndicesEXT:1079return spv::BuiltInPrimitiveTriangleIndicesEXT;1080case glslang::EbvCullPrimitiveEXT:1081return spv::BuiltInCullPrimitiveEXT;10821083// sm builtins1084case glslang::EbvWarpsPerSM:1085builder.addExtension(spv::E_SPV_NV_shader_sm_builtins);1086builder.addCapability(spv::CapabilityShaderSMBuiltinsNV);1087return spv::BuiltInWarpsPerSMNV;1088case glslang::EbvSMCount:1089builder.addExtension(spv::E_SPV_NV_shader_sm_builtins);1090builder.addCapability(spv::CapabilityShaderSMBuiltinsNV);1091return spv::BuiltInSMCountNV;1092case glslang::EbvWarpID:1093builder.addExtension(spv::E_SPV_NV_shader_sm_builtins);1094builder.addCapability(spv::CapabilityShaderSMBuiltinsNV);1095return spv::BuiltInWarpIDNV;1096case glslang::EbvSMID:1097builder.addExtension(spv::E_SPV_NV_shader_sm_builtins);1098builder.addCapability(spv::CapabilityShaderSMBuiltinsNV);1099return spv::BuiltInSMIDNV;11001101// ARM builtins1102case glslang::EbvCoreCountARM:1103builder.addExtension(spv::E_SPV_ARM_core_builtins);1104builder.addCapability(spv::CapabilityCoreBuiltinsARM);1105return spv::BuiltInCoreCountARM;1106case glslang::EbvCoreIDARM:1107builder.addExtension(spv::E_SPV_ARM_core_builtins);1108builder.addCapability(spv::CapabilityCoreBuiltinsARM);1109return spv::BuiltInCoreIDARM;1110case glslang::EbvCoreMaxIDARM:1111builder.addExtension(spv::E_SPV_ARM_core_builtins);1112builder.addCapability(spv::CapabilityCoreBuiltinsARM);1113return spv::BuiltInCoreMaxIDARM;1114case glslang::EbvWarpIDARM:1115builder.addExtension(spv::E_SPV_ARM_core_builtins);1116builder.addCapability(spv::CapabilityCoreBuiltinsARM);1117return spv::BuiltInWarpIDARM;1118case glslang::EbvWarpMaxIDARM:1119builder.addExtension(spv::E_SPV_ARM_core_builtins);1120builder.addCapability(spv::CapabilityCoreBuiltinsARM);1121return spv::BuiltInWarpMaxIDARM;11221123default:1124return spv::BuiltInMax;1125}1126}11271128// Translate glslang image layout format to SPIR-V image format.1129spv::ImageFormat TGlslangToSpvTraverser::TranslateImageFormat(const glslang::TType& type)1130{1131assert(type.getBasicType() == glslang::EbtSampler);11321133// Check for capabilities1134switch (type.getQualifier().getFormat()) {1135case glslang::ElfRg32f:1136case glslang::ElfRg16f:1137case glslang::ElfR11fG11fB10f:1138case glslang::ElfR16f:1139case glslang::ElfRgba16:1140case glslang::ElfRgb10A2:1141case glslang::ElfRg16:1142case glslang::ElfRg8:1143case glslang::ElfR16:1144case glslang::ElfR8:1145case glslang::ElfRgba16Snorm:1146case glslang::ElfRg16Snorm:1147case glslang::ElfRg8Snorm:1148case glslang::ElfR16Snorm:1149case glslang::ElfR8Snorm:11501151case glslang::ElfRg32i:1152case glslang::ElfRg16i:1153case glslang::ElfRg8i:1154case glslang::ElfR16i:1155case glslang::ElfR8i:11561157case glslang::ElfRgb10a2ui:1158case glslang::ElfRg32ui:1159case glslang::ElfRg16ui:1160case glslang::ElfRg8ui:1161case glslang::ElfR16ui:1162case glslang::ElfR8ui:1163builder.addCapability(spv::CapabilityStorageImageExtendedFormats);1164break;11651166case glslang::ElfR64ui:1167case glslang::ElfR64i:1168builder.addExtension(spv::E_SPV_EXT_shader_image_int64);1169builder.addCapability(spv::CapabilityInt64ImageEXT);1170break;1171default:1172break;1173}11741175// do the translation1176switch (type.getQualifier().getFormat()) {1177case glslang::ElfNone: return spv::ImageFormatUnknown;1178case glslang::ElfRgba32f: return spv::ImageFormatRgba32f;1179case glslang::ElfRgba16f: return spv::ImageFormatRgba16f;1180case glslang::ElfR32f: return spv::ImageFormatR32f;1181case glslang::ElfRgba8: return spv::ImageFormatRgba8;1182case glslang::ElfRgba8Snorm: return spv::ImageFormatRgba8Snorm;1183case glslang::ElfRg32f: return spv::ImageFormatRg32f;1184case glslang::ElfRg16f: return spv::ImageFormatRg16f;1185case glslang::ElfR11fG11fB10f: return spv::ImageFormatR11fG11fB10f;1186case glslang::ElfR16f: return spv::ImageFormatR16f;1187case glslang::ElfRgba16: return spv::ImageFormatRgba16;1188case glslang::ElfRgb10A2: return spv::ImageFormatRgb10A2;1189case glslang::ElfRg16: return spv::ImageFormatRg16;1190case glslang::ElfRg8: return spv::ImageFormatRg8;1191case glslang::ElfR16: return spv::ImageFormatR16;1192case glslang::ElfR8: return spv::ImageFormatR8;1193case glslang::ElfRgba16Snorm: return spv::ImageFormatRgba16Snorm;1194case glslang::ElfRg16Snorm: return spv::ImageFormatRg16Snorm;1195case glslang::ElfRg8Snorm: return spv::ImageFormatRg8Snorm;1196case glslang::ElfR16Snorm: return spv::ImageFormatR16Snorm;1197case glslang::ElfR8Snorm: return spv::ImageFormatR8Snorm;1198case glslang::ElfRgba32i: return spv::ImageFormatRgba32i;1199case glslang::ElfRgba16i: return spv::ImageFormatRgba16i;1200case glslang::ElfRgba8i: return spv::ImageFormatRgba8i;1201case glslang::ElfR32i: return spv::ImageFormatR32i;1202case glslang::ElfRg32i: return spv::ImageFormatRg32i;1203case glslang::ElfRg16i: return spv::ImageFormatRg16i;1204case glslang::ElfRg8i: return spv::ImageFormatRg8i;1205case glslang::ElfR16i: return spv::ImageFormatR16i;1206case glslang::ElfR8i: return spv::ImageFormatR8i;1207case glslang::ElfRgba32ui: return spv::ImageFormatRgba32ui;1208case glslang::ElfRgba16ui: return spv::ImageFormatRgba16ui;1209case glslang::ElfRgba8ui: return spv::ImageFormatRgba8ui;1210case glslang::ElfR32ui: return spv::ImageFormatR32ui;1211case glslang::ElfRg32ui: return spv::ImageFormatRg32ui;1212case glslang::ElfRg16ui: return spv::ImageFormatRg16ui;1213case glslang::ElfRgb10a2ui: return spv::ImageFormatRgb10a2ui;1214case glslang::ElfRg8ui: return spv::ImageFormatRg8ui;1215case glslang::ElfR16ui: return spv::ImageFormatR16ui;1216case glslang::ElfR8ui: return spv::ImageFormatR8ui;1217case glslang::ElfR64ui: return spv::ImageFormatR64ui;1218case glslang::ElfR64i: return spv::ImageFormatR64i;1219default: return spv::ImageFormatMax;1220}1221}12221223spv::SelectionControlMask TGlslangToSpvTraverser::TranslateSelectionControl(1224const glslang::TIntermSelection& selectionNode) const1225{1226if (selectionNode.getFlatten())1227return spv::SelectionControlFlattenMask;1228if (selectionNode.getDontFlatten())1229return spv::SelectionControlDontFlattenMask;1230return spv::SelectionControlMaskNone;1231}12321233spv::SelectionControlMask TGlslangToSpvTraverser::TranslateSwitchControl(const glslang::TIntermSwitch& switchNode)1234const1235{1236if (switchNode.getFlatten())1237return spv::SelectionControlFlattenMask;1238if (switchNode.getDontFlatten())1239return spv::SelectionControlDontFlattenMask;1240return spv::SelectionControlMaskNone;1241}12421243// return a non-0 dependency if the dependency argument must be set1244spv::LoopControlMask TGlslangToSpvTraverser::TranslateLoopControl(const glslang::TIntermLoop& loopNode,1245std::vector<unsigned int>& operands) const1246{1247spv::LoopControlMask control = spv::LoopControlMaskNone;12481249if (loopNode.getDontUnroll())1250control = control | spv::LoopControlDontUnrollMask;1251if (loopNode.getUnroll())1252control = control | spv::LoopControlUnrollMask;1253if (unsigned(loopNode.getLoopDependency()) == glslang::TIntermLoop::dependencyInfinite)1254control = control | spv::LoopControlDependencyInfiniteMask;1255else if (loopNode.getLoopDependency() > 0) {1256control = control | spv::LoopControlDependencyLengthMask;1257operands.push_back((unsigned int)loopNode.getLoopDependency());1258}1259if (glslangIntermediate->getSpv().spv >= glslang::EShTargetSpv_1_4) {1260if (loopNode.getMinIterations() > 0) {1261control = control | spv::LoopControlMinIterationsMask;1262operands.push_back(loopNode.getMinIterations());1263}1264if (loopNode.getMaxIterations() < glslang::TIntermLoop::iterationsInfinite) {1265control = control | spv::LoopControlMaxIterationsMask;1266operands.push_back(loopNode.getMaxIterations());1267}1268if (loopNode.getIterationMultiple() > 1) {1269control = control | spv::LoopControlIterationMultipleMask;1270operands.push_back(loopNode.getIterationMultiple());1271}1272if (loopNode.getPeelCount() > 0) {1273control = control | spv::LoopControlPeelCountMask;1274operands.push_back(loopNode.getPeelCount());1275}1276if (loopNode.getPartialCount() > 0) {1277control = control | spv::LoopControlPartialCountMask;1278operands.push_back(loopNode.getPartialCount());1279}1280}12811282return control;1283}12841285// Translate glslang type to SPIR-V storage class.1286spv::StorageClass TGlslangToSpvTraverser::TranslateStorageClass(const glslang::TType& type)1287{1288if (type.getBasicType() == glslang::EbtRayQuery || type.getBasicType() == glslang::EbtHitObjectNV)1289return spv::StorageClassPrivate;1290if (type.getQualifier().isSpirvByReference()) {1291if (type.getQualifier().isParamInput() || type.getQualifier().isParamOutput())1292return spv::StorageClassFunction;1293}1294if (type.getQualifier().isPipeInput())1295return spv::StorageClassInput;1296if (type.getQualifier().isPipeOutput())1297return spv::StorageClassOutput;1298if (type.getQualifier().storage == glslang::EvqTileImageEXT || type.isAttachmentEXT()) {1299builder.addExtension(spv::E_SPV_EXT_shader_tile_image);1300builder.addCapability(spv::CapabilityTileImageColorReadAccessEXT);1301return spv::StorageClassTileImageEXT;1302}13031304if (glslangIntermediate->getSource() != glslang::EShSourceHlsl ||1305type.getQualifier().storage == glslang::EvqUniform) {1306if (type.isAtomic())1307return spv::StorageClassAtomicCounter;1308if (type.containsOpaque() && !glslangIntermediate->getBindlessMode())1309return spv::StorageClassUniformConstant;1310}13111312if (type.getQualifier().isUniformOrBuffer() &&1313type.getQualifier().isShaderRecord()) {1314return spv::StorageClassShaderRecordBufferKHR;1315}13161317if (glslangIntermediate->usingStorageBuffer() && type.getQualifier().storage == glslang::EvqBuffer) {1318builder.addIncorporatedExtension(spv::E_SPV_KHR_storage_buffer_storage_class, spv::Spv_1_3);1319return spv::StorageClassStorageBuffer;1320}13211322if (type.getQualifier().isUniformOrBuffer()) {1323if (type.getQualifier().isPushConstant())1324return spv::StorageClassPushConstant;1325if (type.getBasicType() == glslang::EbtBlock)1326return spv::StorageClassUniform;1327return spv::StorageClassUniformConstant;1328}13291330if (type.getQualifier().storage == glslang::EvqShared && type.getBasicType() == glslang::EbtBlock) {1331builder.addExtension(spv::E_SPV_KHR_workgroup_memory_explicit_layout);1332builder.addCapability(spv::CapabilityWorkgroupMemoryExplicitLayoutKHR);1333return spv::StorageClassWorkgroup;1334}13351336switch (type.getQualifier().storage) {1337case glslang::EvqGlobal: return spv::StorageClassPrivate;1338case glslang::EvqConstReadOnly: return spv::StorageClassFunction;1339case glslang::EvqTemporary: return spv::StorageClassFunction;1340case glslang::EvqShared: return spv::StorageClassWorkgroup;1341case glslang::EvqPayload: return spv::StorageClassRayPayloadKHR;1342case glslang::EvqPayloadIn: return spv::StorageClassIncomingRayPayloadKHR;1343case glslang::EvqHitAttr: return spv::StorageClassHitAttributeKHR;1344case glslang::EvqCallableData: return spv::StorageClassCallableDataKHR;1345case glslang::EvqCallableDataIn: return spv::StorageClassIncomingCallableDataKHR;1346case glslang::EvqtaskPayloadSharedEXT : return spv::StorageClassTaskPayloadWorkgroupEXT;1347case glslang::EvqHitObjectAttrNV: return spv::StorageClassHitObjectAttributeNV;1348case glslang::EvqSpirvStorageClass: return static_cast<spv::StorageClass>(type.getQualifier().spirvStorageClass);1349default:1350assert(0);1351break;1352}13531354return spv::StorageClassFunction;1355}13561357// Translate glslang constants to SPIR-V literals1358void TGlslangToSpvTraverser::TranslateLiterals(const glslang::TVector<const glslang::TIntermConstantUnion*>& constants,1359std::vector<unsigned>& literals) const1360{1361for (auto constant : constants) {1362if (constant->getBasicType() == glslang::EbtFloat) {1363float floatValue = static_cast<float>(constant->getConstArray()[0].getDConst());1364unsigned literal;1365static_assert(sizeof(literal) == sizeof(floatValue), "sizeof(unsigned) != sizeof(float)");1366memcpy(&literal, &floatValue, sizeof(literal));1367literals.push_back(literal);1368} else if (constant->getBasicType() == glslang::EbtInt) {1369unsigned literal = constant->getConstArray()[0].getIConst();1370literals.push_back(literal);1371} else if (constant->getBasicType() == glslang::EbtUint) {1372unsigned literal = constant->getConstArray()[0].getUConst();1373literals.push_back(literal);1374} else if (constant->getBasicType() == glslang::EbtBool) {1375unsigned literal = constant->getConstArray()[0].getBConst();1376literals.push_back(literal);1377} else if (constant->getBasicType() == glslang::EbtString) {1378auto str = constant->getConstArray()[0].getSConst()->c_str();1379unsigned literal = 0;1380char* literalPtr = reinterpret_cast<char*>(&literal);1381unsigned charCount = 0;1382char ch = 0;1383do {1384ch = *(str++);1385*(literalPtr++) = ch;1386++charCount;1387if (charCount == 4) {1388literals.push_back(literal);1389literalPtr = reinterpret_cast<char*>(&literal);1390charCount = 0;1391}1392} while (ch != 0);13931394// Partial literal is padded with 01395if (charCount > 0) {1396for (; charCount < 4; ++charCount)1397*(literalPtr++) = 0;1398literals.push_back(literal);1399}1400} else1401assert(0); // Unexpected type1402}1403}14041405// Add capabilities pertaining to how an array is indexed.1406void TGlslangToSpvTraverser::addIndirectionIndexCapabilities(const glslang::TType& baseType,1407const glslang::TType& indexType)1408{1409if (indexType.getQualifier().isNonUniform()) {1410// deal with an asserted non-uniform index1411// SPV_EXT_descriptor_indexing already added in TranslateNonUniformDecoration1412if (baseType.getBasicType() == glslang::EbtSampler) {1413if (baseType.getQualifier().hasAttachment())1414builder.addCapability(spv::CapabilityInputAttachmentArrayNonUniformIndexingEXT);1415else if (baseType.isImage() && baseType.getSampler().isBuffer())1416builder.addCapability(spv::CapabilityStorageTexelBufferArrayNonUniformIndexingEXT);1417else if (baseType.isTexture() && baseType.getSampler().isBuffer())1418builder.addCapability(spv::CapabilityUniformTexelBufferArrayNonUniformIndexingEXT);1419else if (baseType.isImage())1420builder.addCapability(spv::CapabilityStorageImageArrayNonUniformIndexingEXT);1421else if (baseType.isTexture())1422builder.addCapability(spv::CapabilitySampledImageArrayNonUniformIndexingEXT);1423} else if (baseType.getBasicType() == glslang::EbtBlock) {1424if (baseType.getQualifier().storage == glslang::EvqBuffer)1425builder.addCapability(spv::CapabilityStorageBufferArrayNonUniformIndexingEXT);1426else if (baseType.getQualifier().storage == glslang::EvqUniform)1427builder.addCapability(spv::CapabilityUniformBufferArrayNonUniformIndexingEXT);1428}1429} else {1430// assume a dynamically uniform index1431if (baseType.getBasicType() == glslang::EbtSampler) {1432if (baseType.getQualifier().hasAttachment()) {1433builder.addIncorporatedExtension("SPV_EXT_descriptor_indexing", spv::Spv_1_5);1434builder.addCapability(spv::CapabilityInputAttachmentArrayDynamicIndexingEXT);1435} else if (baseType.isImage() && baseType.getSampler().isBuffer()) {1436builder.addIncorporatedExtension("SPV_EXT_descriptor_indexing", spv::Spv_1_5);1437builder.addCapability(spv::CapabilityStorageTexelBufferArrayDynamicIndexingEXT);1438} else if (baseType.isTexture() && baseType.getSampler().isBuffer()) {1439builder.addIncorporatedExtension("SPV_EXT_descriptor_indexing", spv::Spv_1_5);1440builder.addCapability(spv::CapabilityUniformTexelBufferArrayDynamicIndexingEXT);1441}1442}1443}1444}14451446// Return whether or not the given type is something that should be tied to a1447// descriptor set.1448bool IsDescriptorResource(const glslang::TType& type)1449{1450// uniform and buffer blocks are included, unless it is a push_constant1451if (type.getBasicType() == glslang::EbtBlock)1452return type.getQualifier().isUniformOrBuffer() &&1453! type.getQualifier().isShaderRecord() &&1454! type.getQualifier().isPushConstant();14551456// non block...1457// basically samplerXXX/subpass/sampler/texture are all included1458// if they are the global-scope-class, not the function parameter1459// (or local, if they ever exist) class.1460if (type.getBasicType() == glslang::EbtSampler ||1461type.getBasicType() == glslang::EbtAccStruct)1462return type.getQualifier().isUniformOrBuffer();14631464// None of the above.1465return false;1466}14671468void InheritQualifiers(glslang::TQualifier& child, const glslang::TQualifier& parent)1469{1470if (child.layoutMatrix == glslang::ElmNone)1471child.layoutMatrix = parent.layoutMatrix;14721473if (parent.invariant)1474child.invariant = true;1475if (parent.flat)1476child.flat = true;1477if (parent.centroid)1478child.centroid = true;1479if (parent.nopersp)1480child.nopersp = true;1481if (parent.explicitInterp)1482child.explicitInterp = true;1483if (parent.perPrimitiveNV)1484child.perPrimitiveNV = true;1485if (parent.perViewNV)1486child.perViewNV = true;1487if (parent.perTaskNV)1488child.perTaskNV = true;1489if (parent.storage == glslang::EvqtaskPayloadSharedEXT)1490child.storage = glslang::EvqtaskPayloadSharedEXT;1491if (parent.patch)1492child.patch = true;1493if (parent.sample)1494child.sample = true;1495if (parent.coherent)1496child.coherent = true;1497if (parent.devicecoherent)1498child.devicecoherent = true;1499if (parent.queuefamilycoherent)1500child.queuefamilycoherent = true;1501if (parent.workgroupcoherent)1502child.workgroupcoherent = true;1503if (parent.subgroupcoherent)1504child.subgroupcoherent = true;1505if (parent.shadercallcoherent)1506child.shadercallcoherent = true;1507if (parent.nonprivate)1508child.nonprivate = true;1509if (parent.volatil)1510child.volatil = true;1511if (parent.restrict)1512child.restrict = true;1513if (parent.readonly)1514child.readonly = true;1515if (parent.writeonly)1516child.writeonly = true;1517if (parent.nonUniform)1518child.nonUniform = true;1519}15201521bool HasNonLayoutQualifiers(const glslang::TType& type, const glslang::TQualifier& qualifier)1522{1523// This should list qualifiers that simultaneous satisfy:1524// - struct members might inherit from a struct declaration1525// (note that non-block structs don't explicitly inherit,1526// only implicitly, meaning no decoration involved)1527// - affect decorations on the struct members1528// (note smooth does not, and expecting something like volatile1529// to effect the whole object)1530// - are not part of the offset/st430/etc or row/column-major layout1531return qualifier.invariant || (qualifier.hasLocation() && type.getBasicType() == glslang::EbtBlock);1532}15331534//1535// Implement the TGlslangToSpvTraverser class.1536//15371538TGlslangToSpvTraverser::TGlslangToSpvTraverser(unsigned int spvVersion,1539const glslang::TIntermediate* glslangIntermediate,1540spv::SpvBuildLogger* buildLogger, glslang::SpvOptions& options) :1541TIntermTraverser(true, false, true),1542options(options),1543shaderEntry(nullptr), currentFunction(nullptr),1544sequenceDepth(0), logger(buildLogger),1545builder(spvVersion, (glslang::GetKhronosToolId() << 16) | glslang::GetSpirvGeneratorVersion(), logger),1546inEntryPoint(false), entryPointTerminated(false), linkageOnly(false),1547glslangIntermediate(glslangIntermediate),1548nanMinMaxClamp(glslangIntermediate->getNanMinMaxClamp()),1549nonSemanticDebugPrintf(0),1550taskPayloadID(0)1551{1552bool isMeshShaderExt = (glslangIntermediate->getRequestedExtensions().find(glslang::E_GL_EXT_mesh_shader) !=1553glslangIntermediate->getRequestedExtensions().end());1554spv::ExecutionModel executionModel = TranslateExecutionModel(glslangIntermediate->getStage(), isMeshShaderExt);15551556builder.clearAccessChain();1557builder.setSource(TranslateSourceLanguage(glslangIntermediate->getSource(), glslangIntermediate->getProfile()),1558glslangIntermediate->getVersion());15591560if (options.emitNonSemanticShaderDebugSource)1561this->options.emitNonSemanticShaderDebugInfo = true;1562if (options.emitNonSemanticShaderDebugInfo)1563this->options.generateDebugInfo = true;15641565if (this->options.generateDebugInfo) {1566if (this->options.emitNonSemanticShaderDebugInfo) {1567builder.setEmitNonSemanticShaderDebugInfo(this->options.emitNonSemanticShaderDebugSource);1568}1569else {1570builder.setEmitSpirvDebugInfo();1571}1572builder.setDebugSourceFile(glslangIntermediate->getSourceFile());15731574// Set the source shader's text. If for SPV version 1.0, include1575// a preamble in comments stating the OpModuleProcessed instructions.1576// Otherwise, emit those as actual instructions.1577std::string text;1578const std::vector<std::string>& processes = glslangIntermediate->getProcesses();1579for (int p = 0; p < (int)processes.size(); ++p) {1580if (glslangIntermediate->getSpv().spv < glslang::EShTargetSpv_1_1) {1581text.append("// OpModuleProcessed ");1582text.append(processes[p]);1583text.append("\n");1584} else1585builder.addModuleProcessed(processes[p]);1586}1587if (glslangIntermediate->getSpv().spv < glslang::EShTargetSpv_1_1 && (int)processes.size() > 0)1588text.append("#line 1\n");1589text.append(glslangIntermediate->getSourceText());1590builder.setSourceText(text);1591// Pass name and text for all included files1592const std::map<std::string, std::string>& include_txt = glslangIntermediate->getIncludeText();1593for (auto iItr = include_txt.begin(); iItr != include_txt.end(); ++iItr)1594builder.addInclude(iItr->first, iItr->second);1595}15961597stdBuiltins = builder.import("GLSL.std.450");15981599spv::AddressingModel addressingModel = spv::AddressingModelLogical;1600spv::MemoryModel memoryModel = spv::MemoryModelGLSL450;16011602if (glslangIntermediate->usingPhysicalStorageBuffer()) {1603addressingModel = spv::AddressingModelPhysicalStorageBuffer64EXT;1604builder.addIncorporatedExtension(spv::E_SPV_KHR_physical_storage_buffer, spv::Spv_1_5);1605builder.addCapability(spv::CapabilityPhysicalStorageBufferAddressesEXT);1606}1607if (glslangIntermediate->usingVulkanMemoryModel()) {1608memoryModel = spv::MemoryModelVulkanKHR;1609builder.addCapability(spv::CapabilityVulkanMemoryModelKHR);1610builder.addIncorporatedExtension(spv::E_SPV_KHR_vulkan_memory_model, spv::Spv_1_5);1611}1612builder.setMemoryModel(addressingModel, memoryModel);16131614if (glslangIntermediate->usingVariablePointers()) {1615builder.addCapability(spv::CapabilityVariablePointers);1616}16171618// If not linking, there is no entry point1619if (!options.compileOnly) {1620shaderEntry = builder.makeEntryPoint(glslangIntermediate->getEntryPointName().c_str());1621entryPoint =1622builder.addEntryPoint(executionModel, shaderEntry, glslangIntermediate->getEntryPointName().c_str());1623}16241625// Add the source extensions1626const auto& sourceExtensions = glslangIntermediate->getRequestedExtensions();1627for (auto it = sourceExtensions.begin(); it != sourceExtensions.end(); ++it)1628builder.addSourceExtension(it->c_str());16291630// Add the top-level modes for this shader.16311632if (glslangIntermediate->getXfbMode()) {1633builder.addCapability(spv::CapabilityTransformFeedback);1634builder.addExecutionMode(shaderEntry, spv::ExecutionModeXfb);1635}16361637if (glslangIntermediate->getLayoutPrimitiveCulling()) {1638builder.addCapability(spv::CapabilityRayTraversalPrimitiveCullingKHR);1639}16401641if (glslangIntermediate->getSubgroupUniformControlFlow()) {1642builder.addExtension(spv::E_SPV_KHR_subgroup_uniform_control_flow);1643builder.addExecutionMode(shaderEntry, spv::ExecutionModeSubgroupUniformControlFlowKHR);1644}1645if (glslangIntermediate->getMaximallyReconverges()) {1646builder.addExtension(spv::E_SPV_KHR_maximal_reconvergence);1647builder.addExecutionMode(shaderEntry, spv::ExecutionModeMaximallyReconvergesKHR);1648}16491650if (glslangIntermediate->getQuadDerivMode())1651{1652builder.addCapability(spv::CapabilityQuadControlKHR);1653builder.addExtension(spv::E_SPV_KHR_quad_control);1654builder.addExecutionMode(shaderEntry, spv::ExecutionModeQuadDerivativesKHR);1655}16561657if (glslangIntermediate->getReqFullQuadsMode())1658{1659builder.addCapability(spv::CapabilityQuadControlKHR);1660builder.addExtension(spv::E_SPV_KHR_quad_control);1661builder.addExecutionMode(shaderEntry, spv::ExecutionModeRequireFullQuadsKHR);1662}16631664unsigned int mode;1665switch (glslangIntermediate->getStage()) {1666case EShLangVertex:1667builder.addCapability(spv::CapabilityShader);1668break;16691670case EShLangFragment:1671builder.addCapability(spv::CapabilityShader);1672if (glslangIntermediate->getPixelCenterInteger())1673builder.addExecutionMode(shaderEntry, spv::ExecutionModePixelCenterInteger);16741675if (glslangIntermediate->getOriginUpperLeft())1676builder.addExecutionMode(shaderEntry, spv::ExecutionModeOriginUpperLeft);1677else1678builder.addExecutionMode(shaderEntry, spv::ExecutionModeOriginLowerLeft);16791680if (glslangIntermediate->getEarlyFragmentTests())1681builder.addExecutionMode(shaderEntry, spv::ExecutionModeEarlyFragmentTests);16821683if (glslangIntermediate->getEarlyAndLateFragmentTestsAMD())1684{1685builder.addExecutionMode(shaderEntry, spv::ExecutionModeEarlyAndLateFragmentTestsAMD);1686builder.addExtension(spv::E_SPV_AMD_shader_early_and_late_fragment_tests);1687}16881689if (glslangIntermediate->getPostDepthCoverage()) {1690builder.addCapability(spv::CapabilitySampleMaskPostDepthCoverage);1691builder.addExecutionMode(shaderEntry, spv::ExecutionModePostDepthCoverage);1692builder.addExtension(spv::E_SPV_KHR_post_depth_coverage);1693}16941695if (glslangIntermediate->getNonCoherentColorAttachmentReadEXT()) {1696builder.addCapability(spv::CapabilityTileImageColorReadAccessEXT);1697builder.addExecutionMode(shaderEntry, spv::ExecutionModeNonCoherentColorAttachmentReadEXT);1698builder.addExtension(spv::E_SPV_EXT_shader_tile_image);1699}17001701if (glslangIntermediate->getNonCoherentDepthAttachmentReadEXT()) {1702builder.addCapability(spv::CapabilityTileImageDepthReadAccessEXT);1703builder.addExecutionMode(shaderEntry, spv::ExecutionModeNonCoherentDepthAttachmentReadEXT);1704builder.addExtension(spv::E_SPV_EXT_shader_tile_image);1705}17061707if (glslangIntermediate->getNonCoherentStencilAttachmentReadEXT()) {1708builder.addCapability(spv::CapabilityTileImageStencilReadAccessEXT);1709builder.addExecutionMode(shaderEntry, spv::ExecutionModeNonCoherentStencilAttachmentReadEXT);1710builder.addExtension(spv::E_SPV_EXT_shader_tile_image);1711}17121713if (glslangIntermediate->isDepthReplacing())1714builder.addExecutionMode(shaderEntry, spv::ExecutionModeDepthReplacing);17151716if (glslangIntermediate->isStencilReplacing())1717builder.addExecutionMode(shaderEntry, spv::ExecutionModeStencilRefReplacingEXT);17181719switch(glslangIntermediate->getDepth()) {1720case glslang::EldGreater: mode = spv::ExecutionModeDepthGreater; break;1721case glslang::EldLess: mode = spv::ExecutionModeDepthLess; break;1722case glslang::EldUnchanged: mode = spv::ExecutionModeDepthUnchanged; break;1723default: mode = spv::ExecutionModeMax; break;1724}17251726if (mode != spv::ExecutionModeMax)1727builder.addExecutionMode(shaderEntry, (spv::ExecutionMode)mode);17281729switch (glslangIntermediate->getStencil()) {1730case glslang::ElsRefUnchangedFrontAMD: mode = spv::ExecutionModeStencilRefUnchangedFrontAMD; break;1731case glslang::ElsRefGreaterFrontAMD: mode = spv::ExecutionModeStencilRefGreaterFrontAMD; break;1732case glslang::ElsRefLessFrontAMD: mode = spv::ExecutionModeStencilRefLessFrontAMD; break;1733case glslang::ElsRefUnchangedBackAMD: mode = spv::ExecutionModeStencilRefUnchangedBackAMD; break;1734case glslang::ElsRefGreaterBackAMD: mode = spv::ExecutionModeStencilRefGreaterBackAMD; break;1735case glslang::ElsRefLessBackAMD: mode = spv::ExecutionModeStencilRefLessBackAMD; break;1736default: mode = spv::ExecutionModeMax; break;1737}17381739if (mode != spv::ExecutionModeMax)1740builder.addExecutionMode(shaderEntry, (spv::ExecutionMode)mode);1741switch (glslangIntermediate->getInterlockOrdering()) {1742case glslang::EioPixelInterlockOrdered: mode = spv::ExecutionModePixelInterlockOrderedEXT;1743break;1744case glslang::EioPixelInterlockUnordered: mode = spv::ExecutionModePixelInterlockUnorderedEXT;1745break;1746case glslang::EioSampleInterlockOrdered: mode = spv::ExecutionModeSampleInterlockOrderedEXT;1747break;1748case glslang::EioSampleInterlockUnordered: mode = spv::ExecutionModeSampleInterlockUnorderedEXT;1749break;1750case glslang::EioShadingRateInterlockOrdered: mode = spv::ExecutionModeShadingRateInterlockOrderedEXT;1751break;1752case glslang::EioShadingRateInterlockUnordered: mode = spv::ExecutionModeShadingRateInterlockUnorderedEXT;1753break;1754default: mode = spv::ExecutionModeMax;1755break;1756}1757if (mode != spv::ExecutionModeMax) {1758builder.addExecutionMode(shaderEntry, (spv::ExecutionMode)mode);1759if (mode == spv::ExecutionModeShadingRateInterlockOrderedEXT ||1760mode == spv::ExecutionModeShadingRateInterlockUnorderedEXT) {1761builder.addCapability(spv::CapabilityFragmentShaderShadingRateInterlockEXT);1762} else if (mode == spv::ExecutionModePixelInterlockOrderedEXT ||1763mode == spv::ExecutionModePixelInterlockUnorderedEXT) {1764builder.addCapability(spv::CapabilityFragmentShaderPixelInterlockEXT);1765} else {1766builder.addCapability(spv::CapabilityFragmentShaderSampleInterlockEXT);1767}1768builder.addExtension(spv::E_SPV_EXT_fragment_shader_interlock);1769}1770break;17711772case EShLangCompute: {1773builder.addCapability(spv::CapabilityShader);1774bool needSizeId = false;1775for (int dim = 0; dim < 3; ++dim) {1776if ((glslangIntermediate->getLocalSizeSpecId(dim) != glslang::TQualifier::layoutNotSet)) {1777needSizeId = true;1778break;1779}1780}1781if (glslangIntermediate->getSpv().spv >= glslang::EShTargetSpv_1_6 && needSizeId) {1782std::vector<spv::Id> dimConstId;1783for (int dim = 0; dim < 3; ++dim) {1784bool specConst = (glslangIntermediate->getLocalSizeSpecId(dim) != glslang::TQualifier::layoutNotSet);1785dimConstId.push_back(builder.makeUintConstant(glslangIntermediate->getLocalSize(dim), specConst));1786if (specConst) {1787builder.addDecoration(dimConstId.back(), spv::DecorationSpecId,1788glslangIntermediate->getLocalSizeSpecId(dim));1789needSizeId = true;1790}1791}1792builder.addExecutionModeId(shaderEntry, spv::ExecutionModeLocalSizeId, dimConstId);1793} else {1794builder.addExecutionMode(shaderEntry, spv::ExecutionModeLocalSize, glslangIntermediate->getLocalSize(0),1795glslangIntermediate->getLocalSize(1),1796glslangIntermediate->getLocalSize(2));1797}1798if (glslangIntermediate->getLayoutDerivativeModeNone() == glslang::LayoutDerivativeGroupQuads) {1799builder.addCapability(spv::CapabilityComputeDerivativeGroupQuadsNV);1800builder.addExecutionMode(shaderEntry, spv::ExecutionModeDerivativeGroupQuadsNV);1801builder.addExtension(spv::E_SPV_NV_compute_shader_derivatives);1802} else if (glslangIntermediate->getLayoutDerivativeModeNone() == glslang::LayoutDerivativeGroupLinear) {1803builder.addCapability(spv::CapabilityComputeDerivativeGroupLinearNV);1804builder.addExecutionMode(shaderEntry, spv::ExecutionModeDerivativeGroupLinearNV);1805builder.addExtension(spv::E_SPV_NV_compute_shader_derivatives);1806}1807break;1808}1809case EShLangTessEvaluation:1810case EShLangTessControl:1811builder.addCapability(spv::CapabilityTessellation);18121813glslang::TLayoutGeometry primitive;18141815if (glslangIntermediate->getStage() == EShLangTessControl) {1816builder.addExecutionMode(shaderEntry, spv::ExecutionModeOutputVertices,1817glslangIntermediate->getVertices());1818primitive = glslangIntermediate->getOutputPrimitive();1819} else {1820primitive = glslangIntermediate->getInputPrimitive();1821}18221823switch (primitive) {1824case glslang::ElgTriangles: mode = spv::ExecutionModeTriangles; break;1825case glslang::ElgQuads: mode = spv::ExecutionModeQuads; break;1826case glslang::ElgIsolines: mode = spv::ExecutionModeIsolines; break;1827default: mode = spv::ExecutionModeMax; break;1828}1829if (mode != spv::ExecutionModeMax)1830builder.addExecutionMode(shaderEntry, (spv::ExecutionMode)mode);18311832switch (glslangIntermediate->getVertexSpacing()) {1833case glslang::EvsEqual: mode = spv::ExecutionModeSpacingEqual; break;1834case glslang::EvsFractionalEven: mode = spv::ExecutionModeSpacingFractionalEven; break;1835case glslang::EvsFractionalOdd: mode = spv::ExecutionModeSpacingFractionalOdd; break;1836default: mode = spv::ExecutionModeMax; break;1837}1838if (mode != spv::ExecutionModeMax)1839builder.addExecutionMode(shaderEntry, (spv::ExecutionMode)mode);18401841switch (glslangIntermediate->getVertexOrder()) {1842case glslang::EvoCw: mode = spv::ExecutionModeVertexOrderCw; break;1843case glslang::EvoCcw: mode = spv::ExecutionModeVertexOrderCcw; break;1844default: mode = spv::ExecutionModeMax; break;1845}1846if (mode != spv::ExecutionModeMax)1847builder.addExecutionMode(shaderEntry, (spv::ExecutionMode)mode);18481849if (glslangIntermediate->getPointMode())1850builder.addExecutionMode(shaderEntry, spv::ExecutionModePointMode);1851break;18521853case EShLangGeometry:1854builder.addCapability(spv::CapabilityGeometry);1855switch (glslangIntermediate->getInputPrimitive()) {1856case glslang::ElgPoints: mode = spv::ExecutionModeInputPoints; break;1857case glslang::ElgLines: mode = spv::ExecutionModeInputLines; break;1858case glslang::ElgLinesAdjacency: mode = spv::ExecutionModeInputLinesAdjacency; break;1859case glslang::ElgTriangles: mode = spv::ExecutionModeTriangles; break;1860case glslang::ElgTrianglesAdjacency: mode = spv::ExecutionModeInputTrianglesAdjacency; break;1861default: mode = spv::ExecutionModeMax; break;1862}1863if (mode != spv::ExecutionModeMax)1864builder.addExecutionMode(shaderEntry, (spv::ExecutionMode)mode);18651866builder.addExecutionMode(shaderEntry, spv::ExecutionModeInvocations, glslangIntermediate->getInvocations());18671868switch (glslangIntermediate->getOutputPrimitive()) {1869case glslang::ElgPoints: mode = spv::ExecutionModeOutputPoints; break;1870case glslang::ElgLineStrip: mode = spv::ExecutionModeOutputLineStrip; break;1871case glslang::ElgTriangleStrip: mode = spv::ExecutionModeOutputTriangleStrip; break;1872default: mode = spv::ExecutionModeMax; break;1873}1874if (mode != spv::ExecutionModeMax)1875builder.addExecutionMode(shaderEntry, (spv::ExecutionMode)mode);1876builder.addExecutionMode(shaderEntry, spv::ExecutionModeOutputVertices, glslangIntermediate->getVertices());1877break;18781879case EShLangRayGen:1880case EShLangIntersect:1881case EShLangAnyHit:1882case EShLangClosestHit:1883case EShLangMiss:1884case EShLangCallable:1885{1886auto& extensions = glslangIntermediate->getRequestedExtensions();1887if (extensions.find("GL_NV_ray_tracing") == extensions.end()) {1888builder.addCapability(spv::CapabilityRayTracingKHR);1889builder.addExtension("SPV_KHR_ray_tracing");1890}1891else {1892builder.addCapability(spv::CapabilityRayTracingNV);1893builder.addExtension("SPV_NV_ray_tracing");1894}1895if (glslangIntermediate->getStage() != EShLangRayGen && glslangIntermediate->getStage() != EShLangCallable) {1896if (extensions.find("GL_EXT_ray_cull_mask") != extensions.end()) {1897builder.addCapability(spv::CapabilityRayCullMaskKHR);1898builder.addExtension("SPV_KHR_ray_cull_mask");1899}1900if (extensions.find("GL_EXT_ray_tracing_position_fetch") != extensions.end()) {1901builder.addCapability(spv::CapabilityRayTracingPositionFetchKHR);1902builder.addExtension("SPV_KHR_ray_tracing_position_fetch");1903}1904}1905break;1906}1907case EShLangTask:1908case EShLangMesh:1909if(isMeshShaderExt) {1910builder.addCapability(spv::CapabilityMeshShadingEXT);1911builder.addExtension(spv::E_SPV_EXT_mesh_shader);1912} else {1913builder.addCapability(spv::CapabilityMeshShadingNV);1914builder.addExtension(spv::E_SPV_NV_mesh_shader);1915}1916if (glslangIntermediate->getSpv().spv >= glslang::EShTargetSpv_1_6) {1917std::vector<spv::Id> dimConstId;1918for (int dim = 0; dim < 3; ++dim) {1919bool specConst = (glslangIntermediate->getLocalSizeSpecId(dim) != glslang::TQualifier::layoutNotSet);1920dimConstId.push_back(builder.makeUintConstant(glslangIntermediate->getLocalSize(dim), specConst));1921if (specConst) {1922builder.addDecoration(dimConstId.back(), spv::DecorationSpecId,1923glslangIntermediate->getLocalSizeSpecId(dim));1924}1925}1926builder.addExecutionModeId(shaderEntry, spv::ExecutionModeLocalSizeId, dimConstId);1927} else {1928builder.addExecutionMode(shaderEntry, spv::ExecutionModeLocalSize, glslangIntermediate->getLocalSize(0),1929glslangIntermediate->getLocalSize(1),1930glslangIntermediate->getLocalSize(2));1931}1932if (glslangIntermediate->getStage() == EShLangMesh) {1933builder.addExecutionMode(shaderEntry, spv::ExecutionModeOutputVertices,1934glslangIntermediate->getVertices());1935builder.addExecutionMode(shaderEntry, spv::ExecutionModeOutputPrimitivesNV,1936glslangIntermediate->getPrimitives());19371938switch (glslangIntermediate->getOutputPrimitive()) {1939case glslang::ElgPoints: mode = spv::ExecutionModeOutputPoints; break;1940case glslang::ElgLines: mode = spv::ExecutionModeOutputLinesNV; break;1941case glslang::ElgTriangles: mode = spv::ExecutionModeOutputTrianglesNV; break;1942default: mode = spv::ExecutionModeMax; break;1943}1944if (mode != spv::ExecutionModeMax)1945builder.addExecutionMode(shaderEntry, (spv::ExecutionMode)mode);1946}1947break;19481949default:1950break;1951}19521953//1954// Add SPIR-V requirements (GL_EXT_spirv_intrinsics)1955//1956if (glslangIntermediate->hasSpirvRequirement()) {1957const glslang::TSpirvRequirement& spirvRequirement = glslangIntermediate->getSpirvRequirement();19581959// Add SPIR-V extension requirement1960for (auto& extension : spirvRequirement.extensions)1961builder.addExtension(extension.c_str());19621963// Add SPIR-V capability requirement1964for (auto capability : spirvRequirement.capabilities)1965builder.addCapability(static_cast<spv::Capability>(capability));1966}19671968//1969// Add SPIR-V execution mode qualifiers (GL_EXT_spirv_intrinsics)1970//1971if (glslangIntermediate->hasSpirvExecutionMode()) {1972const glslang::TSpirvExecutionMode spirvExecutionMode = glslangIntermediate->getSpirvExecutionMode();19731974// Add spirv_execution_mode1975for (auto& mode : spirvExecutionMode.modes) {1976if (!mode.second.empty()) {1977std::vector<unsigned> literals;1978TranslateLiterals(mode.second, literals);1979builder.addExecutionMode(shaderEntry, static_cast<spv::ExecutionMode>(mode.first), literals);1980} else1981builder.addExecutionMode(shaderEntry, static_cast<spv::ExecutionMode>(mode.first));1982}19831984// Add spirv_execution_mode_id1985for (auto& modeId : spirvExecutionMode.modeIds) {1986std::vector<spv::Id> operandIds;1987assert(!modeId.second.empty());1988for (auto extraOperand : modeId.second) {1989if (extraOperand->getType().getQualifier().isSpecConstant())1990operandIds.push_back(getSymbolId(extraOperand->getAsSymbolNode()));1991else1992operandIds.push_back(createSpvConstant(*extraOperand));1993}1994builder.addExecutionModeId(shaderEntry, static_cast<spv::ExecutionMode>(modeId.first), operandIds);1995}1996}1997}19981999// Finish creating SPV, after the traversal is complete.2000void TGlslangToSpvTraverser::finishSpv(bool compileOnly)2001{2002// If not linking, an entry point is not expected2003if (!compileOnly) {2004// Finish the entry point function2005if (!entryPointTerminated) {2006builder.setBuildPoint(shaderEntry->getLastBlock());2007builder.leaveFunction();2008}20092010// finish off the entry-point SPV instruction by adding the Input/Output <id>2011entryPoint->reserveOperands(iOSet.size());2012for (auto id : iOSet)2013entryPoint->addIdOperand(id);2014}20152016// Add capabilities, extensions, remove unneeded decorations, etc.,2017// based on the resulting SPIR-V.2018// Note: WebGPU code generation must have the opportunity to aggressively2019// prune unreachable merge blocks and continue targets.2020builder.postProcess(compileOnly);2021}20222023// Write the SPV into 'out'.2024void TGlslangToSpvTraverser::dumpSpv(std::vector<unsigned int>& out)2025{2026builder.dump(out);2027}20282029//2030// Implement the traversal functions.2031//2032// Return true from interior nodes to have the external traversal2033// continue on to children. Return false if children were2034// already processed.2035//20362037//2038// Symbols can turn into2039// - uniform/input reads2040// - output writes2041// - complex lvalue base setups: foo.bar[3].... , where we see foo and start up an access chain2042// - something simple that degenerates into the last bullet2043//2044void TGlslangToSpvTraverser::visitSymbol(glslang::TIntermSymbol* symbol)2045{2046// We update the line information even though no code might be generated here2047// This is helpful to yield correct lines for control flow instructions2048if (!linkageOnly) {2049builder.setDebugSourceLocation(symbol->getLoc().line, symbol->getLoc().getFilename());2050}20512052SpecConstantOpModeGuard spec_constant_op_mode_setter(&builder);2053if (symbol->getType().isStruct())2054glslangTypeToIdMap[symbol->getType().getStruct()] = symbol->getId();20552056if (symbol->getType().getQualifier().isSpecConstant())2057spec_constant_op_mode_setter.turnOnSpecConstantOpMode();2058#ifdef ENABLE_HLSL2059// Skip symbol handling if it is string-typed2060if (symbol->getBasicType() == glslang::EbtString)2061return;2062#endif20632064// getSymbolId() will set up all the IO decorations on the first call.2065// Formal function parameters were mapped during makeFunctions().2066spv::Id id = getSymbolId(symbol);20672068if (symbol->getType().getQualifier().isTaskPayload())2069taskPayloadID = id; // cache the taskPayloadID to be used it as operand for OpEmitMeshTasksEXT20702071if (builder.isPointer(id)) {2072if (!symbol->getType().getQualifier().isParamInput() &&2073!symbol->getType().getQualifier().isParamOutput()) {2074// Include all "static use" and "linkage only" interface variables on the OpEntryPoint instruction2075// Consider adding to the OpEntryPoint interface list.2076// Only looking at structures if they have at least one member.2077if (!symbol->getType().isStruct() || symbol->getType().getStruct()->size() > 0) {2078spv::StorageClass sc = builder.getStorageClass(id);2079// Before SPIR-V 1.4, we only want to include Input and Output.2080// Starting with SPIR-V 1.4, we want all globals.2081if ((glslangIntermediate->getSpv().spv >= glslang::EShTargetSpv_1_4 && builder.isGlobalVariable(id)) ||2082(sc == spv::StorageClassInput || sc == spv::StorageClassOutput)) {2083iOSet.insert(id);2084}2085}2086}20872088// If the SPIR-V type is required to be different than the AST type2089// (for ex SubgroupMasks or 3x4 ObjectToWorld/WorldToObject matrices),2090// translate now from the SPIR-V type to the AST type, for the consuming2091// operation.2092// Note this turns it from an l-value to an r-value.2093// Currently, all symbols needing this are inputs; avoid the map lookup when non-input.2094if (symbol->getType().getQualifier().storage == glslang::EvqVaryingIn)2095id = translateForcedType(id);2096}20972098// Only process non-linkage-only nodes for generating actual static uses2099if (! linkageOnly || symbol->getQualifier().isSpecConstant()) {2100// Prepare to generate code for the access21012102// L-value chains will be computed left to right. We're on the symbol now,2103// which is the left-most part of the access chain, so now is "clear" time,2104// followed by setting the base.2105builder.clearAccessChain();21062107// For now, we consider all user variables as being in memory, so they are pointers,2108// except for2109// A) R-Value arguments to a function, which are an intermediate object.2110// See comments in handleUserFunctionCall().2111// B) Specialization constants (normal constants don't even come in as a variable),2112// These are also pure R-values.2113// C) R-Values from type translation, see above call to translateForcedType()2114glslang::TQualifier qualifier = symbol->getQualifier();2115if (qualifier.isSpecConstant() || rValueParameters.find(symbol->getId()) != rValueParameters.end() ||2116!builder.isPointerType(builder.getTypeId(id)))2117builder.setAccessChainRValue(id);2118else2119builder.setAccessChainLValue(id);2120}21212122#ifdef ENABLE_HLSL2123// Process linkage-only nodes for any special additional interface work.2124if (linkageOnly) {2125if (glslangIntermediate->getHlslFunctionality1()) {2126// Map implicit counter buffers to their originating buffers, which should have been2127// seen by now, given earlier pruning of unused counters, and preservation of order2128// of declaration.2129if (symbol->getType().getQualifier().isUniformOrBuffer()) {2130if (!glslangIntermediate->hasCounterBufferName(symbol->getName())) {2131// Save possible originating buffers for counter buffers, keyed by2132// making the potential counter-buffer name.2133std::string keyName = symbol->getName().c_str();2134keyName = glslangIntermediate->addCounterBufferName(keyName);2135counterOriginator[keyName] = symbol;2136} else {2137// Handle a counter buffer, by finding the saved originating buffer.2138std::string keyName = symbol->getName().c_str();2139auto it = counterOriginator.find(keyName);2140if (it != counterOriginator.end()) {2141id = getSymbolId(it->second);2142if (id != spv::NoResult) {2143spv::Id counterId = getSymbolId(symbol);2144if (counterId != spv::NoResult) {2145builder.addExtension("SPV_GOOGLE_hlsl_functionality1");2146builder.addDecorationId(id, spv::DecorationHlslCounterBufferGOOGLE, counterId);2147}2148}2149}2150}2151}2152}2153}2154#endif2155}21562157bool TGlslangToSpvTraverser::visitBinary(glslang::TVisit /* visit */, glslang::TIntermBinary* node)2158{2159builder.setDebugSourceLocation(node->getLoc().line, node->getLoc().getFilename());2160if (node->getLeft()->getAsSymbolNode() != nullptr && node->getLeft()->getType().isStruct()) {2161glslangTypeToIdMap[node->getLeft()->getType().getStruct()] = node->getLeft()->getAsSymbolNode()->getId();2162}2163if (node->getRight()->getAsSymbolNode() != nullptr && node->getRight()->getType().isStruct()) {2164glslangTypeToIdMap[node->getRight()->getType().getStruct()] = node->getRight()->getAsSymbolNode()->getId();2165}21662167SpecConstantOpModeGuard spec_constant_op_mode_setter(&builder);2168if (node->getType().getQualifier().isSpecConstant())2169spec_constant_op_mode_setter.turnOnSpecConstantOpMode();21702171// First, handle special cases2172switch (node->getOp()) {2173case glslang::EOpAssign:2174case glslang::EOpAddAssign:2175case glslang::EOpSubAssign:2176case glslang::EOpMulAssign:2177case glslang::EOpVectorTimesMatrixAssign:2178case glslang::EOpVectorTimesScalarAssign:2179case glslang::EOpMatrixTimesScalarAssign:2180case glslang::EOpMatrixTimesMatrixAssign:2181case glslang::EOpDivAssign:2182case glslang::EOpModAssign:2183case glslang::EOpAndAssign:2184case glslang::EOpInclusiveOrAssign:2185case glslang::EOpExclusiveOrAssign:2186case glslang::EOpLeftShiftAssign:2187case glslang::EOpRightShiftAssign:2188// A bin-op assign "a += b" means the same thing as "a = a + b"2189// where a is evaluated before b. For a simple assignment, GLSL2190// says to evaluate the left before the right. So, always, left2191// node then right node.2192{2193// get the left l-value, save it away2194builder.clearAccessChain();2195node->getLeft()->traverse(this);2196spv::Builder::AccessChain lValue = builder.getAccessChain();21972198// evaluate the right2199builder.clearAccessChain();2200node->getRight()->traverse(this);2201spv::Id rValue = accessChainLoad(node->getRight()->getType());22022203// reset line number for assignment2204builder.setDebugSourceLocation(node->getLoc().line, node->getLoc().getFilename());22052206if (node->getOp() != glslang::EOpAssign) {2207// the left is also an r-value2208builder.setAccessChain(lValue);2209spv::Id leftRValue = accessChainLoad(node->getLeft()->getType());22102211// do the operation2212spv::Builder::AccessChain::CoherentFlags coherentFlags = TranslateCoherent(node->getLeft()->getType());2213coherentFlags |= TranslateCoherent(node->getRight()->getType());2214OpDecorations decorations = { TranslatePrecisionDecoration(node->getOperationPrecision()),2215TranslateNoContractionDecoration(node->getType().getQualifier()),2216TranslateNonUniformDecoration(coherentFlags) };2217rValue = createBinaryOperation(node->getOp(), decorations,2218convertGlslangToSpvType(node->getType()), leftRValue, rValue,2219node->getType().getBasicType());22202221// these all need their counterparts in createBinaryOperation()2222assert(rValue != spv::NoResult);2223}22242225// store the result2226builder.setAccessChain(lValue);2227multiTypeStore(node->getLeft()->getType(), rValue);22282229// assignments are expressions having an rValue after they are evaluated...2230builder.clearAccessChain();2231builder.setAccessChainRValue(rValue);2232}2233return false;2234case glslang::EOpIndexDirect:2235case glslang::EOpIndexDirectStruct:2236{2237// Structure, array, matrix, or vector indirection with statically known index.2238// Get the left part of the access chain.2239node->getLeft()->traverse(this);22402241// Add the next element in the chain22422243const int glslangIndex = node->getRight()->getAsConstantUnion()->getConstArray()[0].getIConst();2244if (! node->getLeft()->getType().isArray() &&2245node->getLeft()->getType().isVector() &&2246node->getOp() == glslang::EOpIndexDirect) {2247// Swizzle is uniform so propagate uniform into access chain2248spv::Builder::AccessChain::CoherentFlags coherentFlags = TranslateCoherent(node->getLeft()->getType());2249coherentFlags.nonUniform = 0;2250// This is essentially a hard-coded vector swizzle of size 1,2251// so short circuit the access-chain stuff with a swizzle.2252std::vector<unsigned> swizzle;2253swizzle.push_back(glslangIndex);2254int dummySize;2255builder.accessChainPushSwizzle(swizzle, convertGlslangToSpvType(node->getLeft()->getType()),2256coherentFlags,2257glslangIntermediate->getBaseAlignmentScalar(2258node->getLeft()->getType(), dummySize));2259} else {22602261// Load through a block reference is performed with a dot operator that2262// is mapped to EOpIndexDirectStruct. When we get to the actual reference,2263// do a load and reset the access chain.2264if (node->getLeft()->isReference() &&2265!node->getLeft()->getType().isArray() &&2266node->getOp() == glslang::EOpIndexDirectStruct)2267{2268spv::Id left = accessChainLoad(node->getLeft()->getType());2269builder.clearAccessChain();2270builder.setAccessChainLValue(left);2271}22722273int spvIndex = glslangIndex;2274if (node->getLeft()->getBasicType() == glslang::EbtBlock &&2275node->getOp() == glslang::EOpIndexDirectStruct)2276{2277// This may be, e.g., an anonymous block-member selection, which generally need2278// index remapping due to hidden members in anonymous blocks.2279long long glslangId = glslangTypeToIdMap[node->getLeft()->getType().getStruct()];2280if (memberRemapper.find(glslangId) != memberRemapper.end()) {2281std::vector<int>& remapper = memberRemapper[glslangId];2282assert(remapper.size() > 0);2283spvIndex = remapper[glslangIndex];2284}2285}22862287// Struct reference propagates uniform lvalue2288spv::Builder::AccessChain::CoherentFlags coherentFlags =2289TranslateCoherent(node->getLeft()->getType());2290coherentFlags.nonUniform = 0;22912292// normal case for indexing array or structure or block2293builder.accessChainPush(builder.makeIntConstant(spvIndex),2294coherentFlags,2295node->getLeft()->getType().getBufferReferenceAlignment());22962297// Add capabilities here for accessing PointSize and clip/cull distance.2298// We have deferred generation of associated capabilities until now.2299if (node->getLeft()->getType().isStruct() && ! node->getLeft()->getType().isArray())2300declareUseOfStructMember(*(node->getLeft()->getType().getStruct()), glslangIndex);2301}2302}2303return false;2304case glslang::EOpIndexIndirect:2305{2306// Array, matrix, or vector indirection with variable index.2307// Will use native SPIR-V access-chain for and array indirection;2308// matrices are arrays of vectors, so will also work for a matrix.2309// Will use the access chain's 'component' for variable index into a vector.23102311// This adapter is building access chains left to right.2312// Set up the access chain to the left.2313node->getLeft()->traverse(this);23142315// save it so that computing the right side doesn't trash it2316spv::Builder::AccessChain partial = builder.getAccessChain();23172318// compute the next index in the chain2319builder.clearAccessChain();2320node->getRight()->traverse(this);2321spv::Id index = accessChainLoad(node->getRight()->getType());23222323addIndirectionIndexCapabilities(node->getLeft()->getType(), node->getRight()->getType());23242325// restore the saved access chain2326builder.setAccessChain(partial);23272328// Only if index is nonUniform should we propagate nonUniform into access chain2329spv::Builder::AccessChain::CoherentFlags index_flags = TranslateCoherent(node->getRight()->getType());2330spv::Builder::AccessChain::CoherentFlags coherent_flags = TranslateCoherent(node->getLeft()->getType());2331coherent_flags.nonUniform = index_flags.nonUniform;23322333if (! node->getLeft()->getType().isArray() && node->getLeft()->getType().isVector()) {2334int dummySize;2335builder.accessChainPushComponent(2336index, convertGlslangToSpvType(node->getLeft()->getType()), coherent_flags,2337glslangIntermediate->getBaseAlignmentScalar(node->getLeft()->getType(),2338dummySize));2339} else2340builder.accessChainPush(index, coherent_flags,2341node->getLeft()->getType().getBufferReferenceAlignment());2342}2343return false;2344case glslang::EOpVectorSwizzle:2345{2346node->getLeft()->traverse(this);2347std::vector<unsigned> swizzle;2348convertSwizzle(*node->getRight()->getAsAggregate(), swizzle);2349int dummySize;2350builder.accessChainPushSwizzle(swizzle, convertGlslangToSpvType(node->getLeft()->getType()),2351TranslateCoherent(node->getLeft()->getType()),2352glslangIntermediate->getBaseAlignmentScalar(node->getLeft()->getType(),2353dummySize));2354}2355return false;2356case glslang::EOpMatrixSwizzle:2357logger->missingFunctionality("matrix swizzle");2358return true;2359case glslang::EOpLogicalOr:2360case glslang::EOpLogicalAnd:2361{23622363// These may require short circuiting, but can sometimes be done as straight2364// binary operations. The right operand must be short circuited if it has2365// side effects, and should probably be if it is complex.2366if (isTrivial(node->getRight()->getAsTyped()))2367break; // handle below as a normal binary operation2368// otherwise, we need to do dynamic short circuiting on the right operand2369spv::Id result = createShortCircuit(node->getOp(), *node->getLeft()->getAsTyped(),2370*node->getRight()->getAsTyped());2371builder.clearAccessChain();2372builder.setAccessChainRValue(result);2373}2374return false;2375default:2376break;2377}23782379// Assume generic binary op...23802381// get right operand2382builder.clearAccessChain();2383node->getLeft()->traverse(this);2384spv::Id left = accessChainLoad(node->getLeft()->getType());23852386// get left operand2387builder.clearAccessChain();2388node->getRight()->traverse(this);2389spv::Id right = accessChainLoad(node->getRight()->getType());23902391// get result2392OpDecorations decorations = { TranslatePrecisionDecoration(node->getOperationPrecision()),2393TranslateNoContractionDecoration(node->getType().getQualifier()),2394TranslateNonUniformDecoration(node->getType().getQualifier()) };2395spv::Id result = createBinaryOperation(node->getOp(), decorations,2396convertGlslangToSpvType(node->getType()), left, right,2397node->getLeft()->getType().getBasicType());23982399builder.clearAccessChain();2400if (! result) {2401logger->missingFunctionality("unknown glslang binary operation");2402return true; // pick up a child as the place-holder result2403} else {2404builder.setAccessChainRValue(result);2405return false;2406}2407}24082409spv::Id TGlslangToSpvTraverser::convertLoadedBoolInUniformToUint(const glslang::TType& type,2410spv::Id nominalTypeId,2411spv::Id loadedId)2412{2413if (builder.isScalarType(nominalTypeId)) {2414// Conversion for bool2415spv::Id boolType = builder.makeBoolType();2416if (nominalTypeId != boolType)2417return builder.createBinOp(spv::OpINotEqual, boolType, loadedId, builder.makeUintConstant(0));2418} else if (builder.isVectorType(nominalTypeId)) {2419// Conversion for bvec2420int vecSize = builder.getNumTypeComponents(nominalTypeId);2421spv::Id bvecType = builder.makeVectorType(builder.makeBoolType(), vecSize);2422if (nominalTypeId != bvecType)2423loadedId = builder.createBinOp(spv::OpINotEqual, bvecType, loadedId,2424makeSmearedConstant(builder.makeUintConstant(0), vecSize));2425} else if (builder.isArrayType(nominalTypeId)) {2426// Conversion for bool array2427spv::Id boolArrayTypeId = convertGlslangToSpvType(type);2428if (nominalTypeId != boolArrayTypeId)2429{2430// Use OpCopyLogical from SPIR-V 1.4 if available.2431if (glslangIntermediate->getSpv().spv >= glslang::EShTargetSpv_1_4)2432return builder.createUnaryOp(spv::OpCopyLogical, boolArrayTypeId, loadedId);24332434glslang::TType glslangElementType(type, 0);2435spv::Id elementNominalTypeId = builder.getContainedTypeId(nominalTypeId);2436std::vector<spv::Id> constituents;2437for (int index = 0; index < type.getOuterArraySize(); ++index) {2438// get the element2439spv::Id elementValue = builder.createCompositeExtract(loadedId, elementNominalTypeId, index);24402441// recursively convert it2442spv::Id elementConvertedValue = convertLoadedBoolInUniformToUint(glslangElementType, elementNominalTypeId, elementValue);2443constituents.push_back(elementConvertedValue);2444}2445return builder.createCompositeConstruct(boolArrayTypeId, constituents);2446}2447}24482449return loadedId;2450}24512452// Figure out what, if any, type changes are needed when accessing a specific built-in.2453// Returns <the type SPIR-V requires for declarion, the type to translate to on use>.2454// Also see comment for 'forceType', regarding tracking SPIR-V-required types.2455std::pair<spv::Id, spv::Id> TGlslangToSpvTraverser::getForcedType(glslang::TBuiltInVariable glslangBuiltIn,2456const glslang::TType& glslangType)2457{2458switch(glslangBuiltIn)2459{2460case glslang::EbvSubGroupEqMask:2461case glslang::EbvSubGroupGeMask:2462case glslang::EbvSubGroupGtMask:2463case glslang::EbvSubGroupLeMask:2464case glslang::EbvSubGroupLtMask: {2465// these require changing a 64-bit scaler -> a vector of 32-bit components2466if (glslangType.isVector())2467break;2468spv::Id ivec4_type = builder.makeVectorType(builder.makeUintType(32), 4);2469spv::Id uint64_type = builder.makeUintType(64);2470std::pair<spv::Id, spv::Id> ret(ivec4_type, uint64_type);2471return ret;2472}2473// There are no SPIR-V builtins defined for these and map onto original non-transposed2474// builtins. During visitBinary we insert a transpose2475case glslang::EbvWorldToObject3x4:2476case glslang::EbvObjectToWorld3x4: {2477spv::Id mat43 = builder.makeMatrixType(builder.makeFloatType(32), 4, 3);2478spv::Id mat34 = builder.makeMatrixType(builder.makeFloatType(32), 3, 4);2479std::pair<spv::Id, spv::Id> ret(mat43, mat34);2480return ret;2481}2482default:2483break;2484}24852486std::pair<spv::Id, spv::Id> ret(spv::NoType, spv::NoType);2487return ret;2488}24892490// For an object previously identified (see getForcedType() and forceType)2491// as needing type translations, do the translation needed for a load, turning2492// an L-value into in R-value.2493spv::Id TGlslangToSpvTraverser::translateForcedType(spv::Id object)2494{2495const auto forceIt = forceType.find(object);2496if (forceIt == forceType.end())2497return object;24982499spv::Id desiredTypeId = forceIt->second;2500spv::Id objectTypeId = builder.getTypeId(object);2501assert(builder.isPointerType(objectTypeId));2502objectTypeId = builder.getContainedTypeId(objectTypeId);2503if (builder.isVectorType(objectTypeId) &&2504builder.getScalarTypeWidth(builder.getContainedTypeId(objectTypeId)) == 32) {2505if (builder.getScalarTypeWidth(desiredTypeId) == 64) {2506// handle 32-bit v.xy* -> 64-bit2507builder.clearAccessChain();2508builder.setAccessChainLValue(object);2509object = builder.accessChainLoad(spv::NoPrecision, spv::DecorationMax, spv::DecorationMax, objectTypeId);2510std::vector<spv::Id> components;2511components.push_back(builder.createCompositeExtract(object, builder.getContainedTypeId(objectTypeId), 0));2512components.push_back(builder.createCompositeExtract(object, builder.getContainedTypeId(objectTypeId), 1));25132514spv::Id vecType = builder.makeVectorType(builder.getContainedTypeId(objectTypeId), 2);2515return builder.createUnaryOp(spv::OpBitcast, desiredTypeId,2516builder.createCompositeConstruct(vecType, components));2517} else {2518logger->missingFunctionality("forcing 32-bit vector type to non 64-bit scalar");2519}2520} else if (builder.isMatrixType(objectTypeId)) {2521// There are no SPIR-V builtins defined for 3x4 variants of ObjectToWorld/WorldToObject2522// and we insert a transpose after loading the original non-transposed builtins2523builder.clearAccessChain();2524builder.setAccessChainLValue(object);2525object = builder.accessChainLoad(spv::NoPrecision, spv::DecorationMax, spv::DecorationMax, objectTypeId);2526return builder.createUnaryOp(spv::OpTranspose, desiredTypeId, object);25272528} else {2529logger->missingFunctionality("forcing non 32-bit vector type");2530}25312532return object;2533}25342535bool TGlslangToSpvTraverser::visitUnary(glslang::TVisit /* visit */, glslang::TIntermUnary* node)2536{2537builder.setDebugSourceLocation(node->getLoc().line, node->getLoc().getFilename());25382539SpecConstantOpModeGuard spec_constant_op_mode_setter(&builder);2540if (node->getType().getQualifier().isSpecConstant())2541spec_constant_op_mode_setter.turnOnSpecConstantOpMode();25422543spv::Id result = spv::NoResult;25442545// try texturing first2546result = createImageTextureFunctionCall(node);2547if (result != spv::NoResult) {2548builder.clearAccessChain();2549builder.setAccessChainRValue(result);25502551return false; // done with this node2552}25532554// Non-texturing.25552556if (node->getOp() == glslang::EOpArrayLength) {2557// Quite special; won't want to evaluate the operand.25582559// Currently, the front-end does not allow .length() on an array until it is sized,2560// except for the last block membeor of an SSBO.2561// TODO: If this changes, link-time sized arrays might show up here, and need their2562// size extracted.25632564// Normal .length() would have been constant folded by the front-end.2565// So, this has to be block.lastMember.length().2566// SPV wants "block" and member number as the operands, go get them.25672568spv::Id length;2569if (node->getOperand()->getType().isCoopMat()) {2570spv::Id typeId = convertGlslangToSpvType(node->getOperand()->getType());2571assert(builder.isCooperativeMatrixType(typeId));25722573if (node->getOperand()->getType().isCoopMatKHR()) {2574length = builder.createCooperativeMatrixLengthKHR(typeId);2575} else {2576spec_constant_op_mode_setter.turnOnSpecConstantOpMode();2577length = builder.createCooperativeMatrixLengthNV(typeId);2578}2579} else {2580glslang::TIntermTyped* block = node->getOperand()->getAsBinaryNode()->getLeft();2581block->traverse(this);2582unsigned int member = node->getOperand()->getAsBinaryNode()->getRight()->getAsConstantUnion()2583->getConstArray()[0].getUConst();2584length = builder.createArrayLength(builder.accessChainGetLValue(), member);2585}25862587// GLSL semantics say the result of .length() is an int, while SPIR-V says2588// signedness must be 0. So, convert from SPIR-V unsigned back to GLSL's2589// AST expectation of a signed result.2590if (glslangIntermediate->getSource() == glslang::EShSourceGlsl) {2591if (builder.isInSpecConstCodeGenMode()) {2592length = builder.createBinOp(spv::OpIAdd, builder.makeIntType(32), length, builder.makeIntConstant(0));2593} else {2594length = builder.createUnaryOp(spv::OpBitcast, builder.makeIntType(32), length);2595}2596}25972598builder.clearAccessChain();2599builder.setAccessChainRValue(length);26002601return false;2602}26032604// Force variable declaration - Debug Mode Only2605if (node->getOp() == glslang::EOpDeclare) {2606builder.clearAccessChain();2607node->getOperand()->traverse(this);2608builder.clearAccessChain();2609return false;2610}26112612// Start by evaluating the operand26132614// Does it need a swizzle inversion? If so, evaluation is inverted;2615// operate first on the swizzle base, then apply the swizzle.2616spv::Id invertedType = spv::NoType;2617auto resultType = [&invertedType, &node, this](){ return invertedType != spv::NoType ?2618invertedType : convertGlslangToSpvType(node->getType()); };2619if (node->getOp() == glslang::EOpInterpolateAtCentroid)2620invertedType = getInvertedSwizzleType(*node->getOperand());26212622builder.clearAccessChain();2623TIntermNode *operandNode;2624if (invertedType != spv::NoType)2625operandNode = node->getOperand()->getAsBinaryNode()->getLeft();2626else2627operandNode = node->getOperand();26282629operandNode->traverse(this);26302631spv::Id operand = spv::NoResult;26322633spv::Builder::AccessChain::CoherentFlags lvalueCoherentFlags;26342635const auto hitObjectOpsWithLvalue = [](glslang::TOperator op) {2636switch(op) {2637case glslang::EOpReorderThreadNV:2638case glslang::EOpHitObjectGetCurrentTimeNV:2639case glslang::EOpHitObjectGetHitKindNV:2640case glslang::EOpHitObjectGetPrimitiveIndexNV:2641case glslang::EOpHitObjectGetGeometryIndexNV:2642case glslang::EOpHitObjectGetInstanceIdNV:2643case glslang::EOpHitObjectGetInstanceCustomIndexNV:2644case glslang::EOpHitObjectGetObjectRayDirectionNV:2645case glslang::EOpHitObjectGetObjectRayOriginNV:2646case glslang::EOpHitObjectGetWorldRayDirectionNV:2647case glslang::EOpHitObjectGetWorldRayOriginNV:2648case glslang::EOpHitObjectGetWorldToObjectNV:2649case glslang::EOpHitObjectGetObjectToWorldNV:2650case glslang::EOpHitObjectGetRayTMaxNV:2651case glslang::EOpHitObjectGetRayTMinNV:2652case glslang::EOpHitObjectIsEmptyNV:2653case glslang::EOpHitObjectIsHitNV:2654case glslang::EOpHitObjectIsMissNV:2655case glslang::EOpHitObjectRecordEmptyNV:2656case glslang::EOpHitObjectGetShaderBindingTableRecordIndexNV:2657case glslang::EOpHitObjectGetShaderRecordBufferHandleNV:2658return true;2659default:2660return false;2661}2662};26632664if (node->getOp() == glslang::EOpAtomicCounterIncrement ||2665node->getOp() == glslang::EOpAtomicCounterDecrement ||2666node->getOp() == glslang::EOpAtomicCounter ||2667(node->getOp() == glslang::EOpInterpolateAtCentroid &&2668glslangIntermediate->getSource() != glslang::EShSourceHlsl) ||2669node->getOp() == glslang::EOpRayQueryProceed ||2670node->getOp() == glslang::EOpRayQueryGetRayTMin ||2671node->getOp() == glslang::EOpRayQueryGetRayFlags ||2672node->getOp() == glslang::EOpRayQueryGetWorldRayOrigin ||2673node->getOp() == glslang::EOpRayQueryGetWorldRayDirection ||2674node->getOp() == glslang::EOpRayQueryGetIntersectionCandidateAABBOpaque ||2675node->getOp() == glslang::EOpRayQueryTerminate ||2676node->getOp() == glslang::EOpRayQueryConfirmIntersection ||2677(node->getOp() == glslang::EOpSpirvInst && operandNode->getAsTyped()->getQualifier().isSpirvByReference()) ||2678hitObjectOpsWithLvalue(node->getOp())) {2679operand = builder.accessChainGetLValue(); // Special case l-value operands2680lvalueCoherentFlags = builder.getAccessChain().coherentFlags;2681lvalueCoherentFlags |= TranslateCoherent(operandNode->getAsTyped()->getType());2682} else if (operandNode->getAsTyped()->getQualifier().isSpirvLiteral()) {2683// Will be translated to a literal value, make a placeholder here2684operand = spv::NoResult;2685} else {2686operand = accessChainLoad(node->getOperand()->getType());2687}26882689OpDecorations decorations = { TranslatePrecisionDecoration(node->getOperationPrecision()),2690TranslateNoContractionDecoration(node->getType().getQualifier()),2691TranslateNonUniformDecoration(node->getType().getQualifier()) };26922693// it could be a conversion2694if (! result)2695result = createConversion(node->getOp(), decorations, resultType(), operand,2696node->getOperand()->getBasicType());26972698// if not, then possibly an operation2699if (! result)2700result = createUnaryOperation(node->getOp(), decorations, resultType(), operand,2701node->getOperand()->getBasicType(), lvalueCoherentFlags, node->getType());27022703// it could be attached to a SPIR-V intruction2704if (!result) {2705if (node->getOp() == glslang::EOpSpirvInst) {2706const auto& spirvInst = node->getSpirvInstruction();2707if (spirvInst.set == "") {2708spv::IdImmediate idImmOp = {true, operand};2709if (operandNode->getAsTyped()->getQualifier().isSpirvLiteral()) {2710// Translate the constant to a literal value2711std::vector<unsigned> literals;2712glslang::TVector<const glslang::TIntermConstantUnion*> constants;2713constants.push_back(operandNode->getAsConstantUnion());2714TranslateLiterals(constants, literals);2715idImmOp = {false, literals[0]};2716}27172718if (node->getBasicType() == glslang::EbtVoid)2719builder.createNoResultOp(static_cast<spv::Op>(spirvInst.id), {idImmOp});2720else2721result = builder.createOp(static_cast<spv::Op>(spirvInst.id), resultType(), {idImmOp});2722} else {2723result = builder.createBuiltinCall(2724resultType(), spirvInst.set == "GLSL.std.450" ? stdBuiltins : getExtBuiltins(spirvInst.set.c_str()),2725spirvInst.id, {operand});2726}27272728if (node->getBasicType() == glslang::EbtVoid)2729return false; // done with this node2730}2731}27322733if (result) {2734if (invertedType) {2735result = createInvertedSwizzle(decorations.precision, *node->getOperand(), result);2736decorations.addNonUniform(builder, result);2737}27382739builder.clearAccessChain();2740builder.setAccessChainRValue(result);27412742return false; // done with this node2743}27442745// it must be a special case, check...2746switch (node->getOp()) {2747case glslang::EOpPostIncrement:2748case glslang::EOpPostDecrement:2749case glslang::EOpPreIncrement:2750case glslang::EOpPreDecrement:2751{2752// we need the integer value "1" or the floating point "1.0" to add/subtract2753spv::Id one = 0;2754if (node->getBasicType() == glslang::EbtFloat)2755one = builder.makeFloatConstant(1.0F);2756else if (node->getBasicType() == glslang::EbtDouble)2757one = builder.makeDoubleConstant(1.0);2758else if (node->getBasicType() == glslang::EbtFloat16)2759one = builder.makeFloat16Constant(1.0F);2760else if (node->getBasicType() == glslang::EbtInt8 || node->getBasicType() == glslang::EbtUint8)2761one = builder.makeInt8Constant(1);2762else if (node->getBasicType() == glslang::EbtInt16 || node->getBasicType() == glslang::EbtUint16)2763one = builder.makeInt16Constant(1);2764else if (node->getBasicType() == glslang::EbtInt64 || node->getBasicType() == glslang::EbtUint64)2765one = builder.makeInt64Constant(1);2766else2767one = builder.makeIntConstant(1);2768glslang::TOperator op;2769if (node->getOp() == glslang::EOpPreIncrement ||2770node->getOp() == glslang::EOpPostIncrement)2771op = glslang::EOpAdd;2772else2773op = glslang::EOpSub;27742775spv::Id result = createBinaryOperation(op, decorations,2776convertGlslangToSpvType(node->getType()), operand, one,2777node->getType().getBasicType());2778assert(result != spv::NoResult);27792780// The result of operation is always stored, but conditionally the2781// consumed result. The consumed result is always an r-value.2782builder.accessChainStore(result,2783TranslateNonUniformDecoration(builder.getAccessChain().coherentFlags));2784builder.clearAccessChain();2785if (node->getOp() == glslang::EOpPreIncrement ||2786node->getOp() == glslang::EOpPreDecrement)2787builder.setAccessChainRValue(result);2788else2789builder.setAccessChainRValue(operand);2790}27912792return false;27932794case glslang::EOpAssumeEXT:2795builder.addCapability(spv::CapabilityExpectAssumeKHR);2796builder.addExtension(spv::E_SPV_KHR_expect_assume);2797builder.createNoResultOp(spv::OpAssumeTrueKHR, operand);2798return false;2799case glslang::EOpEmitStreamVertex:2800builder.createNoResultOp(spv::OpEmitStreamVertex, operand);2801return false;2802case glslang::EOpEndStreamPrimitive:2803builder.createNoResultOp(spv::OpEndStreamPrimitive, operand);2804return false;2805case glslang::EOpRayQueryTerminate:2806builder.createNoResultOp(spv::OpRayQueryTerminateKHR, operand);2807return false;2808case glslang::EOpRayQueryConfirmIntersection:2809builder.createNoResultOp(spv::OpRayQueryConfirmIntersectionKHR, operand);2810return false;2811case glslang::EOpReorderThreadNV:2812builder.createNoResultOp(spv::OpReorderThreadWithHitObjectNV, operand);2813return false;2814case glslang::EOpHitObjectRecordEmptyNV:2815builder.createNoResultOp(spv::OpHitObjectRecordEmptyNV, operand);2816return false;28172818default:2819logger->missingFunctionality("unknown glslang unary");2820return true; // pick up operand as placeholder result2821}2822}28232824// Construct a composite object, recursively copying members if their types don't match2825spv::Id TGlslangToSpvTraverser::createCompositeConstruct(spv::Id resultTypeId, std::vector<spv::Id> constituents)2826{2827for (int c = 0; c < (int)constituents.size(); ++c) {2828spv::Id& constituent = constituents[c];2829spv::Id lType = builder.getContainedTypeId(resultTypeId, c);2830spv::Id rType = builder.getTypeId(constituent);2831if (lType != rType) {2832if (glslangIntermediate->getSpv().spv >= glslang::EShTargetSpv_1_4) {2833constituent = builder.createUnaryOp(spv::OpCopyLogical, lType, constituent);2834} else if (builder.isStructType(rType)) {2835std::vector<spv::Id> rTypeConstituents;2836int numrTypeConstituents = builder.getNumTypeConstituents(rType);2837for (int i = 0; i < numrTypeConstituents; ++i) {2838rTypeConstituents.push_back(builder.createCompositeExtract(constituent,2839builder.getContainedTypeId(rType, i), i));2840}2841constituents[c] = createCompositeConstruct(lType, rTypeConstituents);2842} else {2843assert(builder.isArrayType(rType));2844std::vector<spv::Id> rTypeConstituents;2845int numrTypeConstituents = builder.getNumTypeConstituents(rType);28462847spv::Id elementRType = builder.getContainedTypeId(rType);2848for (int i = 0; i < numrTypeConstituents; ++i) {2849rTypeConstituents.push_back(builder.createCompositeExtract(constituent, elementRType, i));2850}2851constituents[c] = createCompositeConstruct(lType, rTypeConstituents);2852}2853}2854}2855return builder.createCompositeConstruct(resultTypeId, constituents);2856}28572858bool TGlslangToSpvTraverser::visitAggregate(glslang::TVisit visit, glslang::TIntermAggregate* node)2859{2860SpecConstantOpModeGuard spec_constant_op_mode_setter(&builder);2861if (node->getType().getQualifier().isSpecConstant())2862spec_constant_op_mode_setter.turnOnSpecConstantOpMode();28632864spv::Id result = spv::NoResult;2865spv::Id invertedType = spv::NoType; // to use to override the natural type of the node2866std::vector<spv::Builder::AccessChain> complexLvalues; // for holding swizzling l-values too complex for2867// SPIR-V, for an out parameter2868std::vector<spv::Id> temporaryLvalues; // temporaries to pass, as proxies for complexLValues28692870auto resultType = [&invertedType, &node, this](){ return invertedType != spv::NoType ?2871invertedType :2872convertGlslangToSpvType(node->getType()); };28732874// try texturing2875result = createImageTextureFunctionCall(node);2876if (result != spv::NoResult) {2877builder.clearAccessChain();2878builder.setAccessChainRValue(result);28792880return false;2881} else if (node->getOp() == glslang::EOpImageStore ||2882node->getOp() == glslang::EOpImageStoreLod ||2883node->getOp() == glslang::EOpImageAtomicStore) {2884// "imageStore" is a special case, which has no result2885return false;2886}28872888glslang::TOperator binOp = glslang::EOpNull;2889bool reduceComparison = true;2890bool isMatrix = false;2891bool noReturnValue = false;2892bool atomic = false;28932894spv::Builder::AccessChain::CoherentFlags lvalueCoherentFlags;28952896assert(node->getOp());28972898spv::Decoration precision = TranslatePrecisionDecoration(node->getOperationPrecision());28992900switch (node->getOp()) {2901case glslang::EOpScope:2902case glslang::EOpSequence:2903{2904if (visit == glslang::EvPreVisit) {2905++sequenceDepth;2906if (sequenceDepth == 1) {2907// If this is the parent node of all the functions, we want to see them2908// early, so all call points have actual SPIR-V functions to reference.2909// In all cases, still let the traverser visit the children for us.2910makeFunctions(node->getAsAggregate()->getSequence());29112912// Global initializers is specific to the shader entry point, which does not exist in compile-only mode2913if (!options.compileOnly) {2914// Also, we want all globals initializers to go into the beginning of the entry point, before2915// anything else gets there, so visit out of order, doing them all now.2916makeGlobalInitializers(node->getAsAggregate()->getSequence());2917}29182919//Pre process linker objects for ray tracing stages2920if (glslangIntermediate->isRayTracingStage())2921collectRayTracingLinkerObjects();29222923// Initializers are done, don't want to visit again, but functions and link objects need to be processed,2924// so do them manually.2925visitFunctions(node->getAsAggregate()->getSequence());29262927return false;2928} else {2929if (node->getOp() == glslang::EOpScope)2930builder.enterLexicalBlock(0);2931}2932} else {2933if (sequenceDepth > 1 && node->getOp() == glslang::EOpScope)2934builder.leaveLexicalBlock();2935--sequenceDepth;2936}29372938return true;2939}2940case glslang::EOpLinkerObjects:2941{2942if (visit == glslang::EvPreVisit)2943linkageOnly = true;2944else2945linkageOnly = false;29462947return true;2948}2949case glslang::EOpComma:2950{2951// processing from left to right naturally leaves the right-most2952// lying around in the access chain2953glslang::TIntermSequence& glslangOperands = node->getSequence();2954for (int i = 0; i < (int)glslangOperands.size(); ++i)2955glslangOperands[i]->traverse(this);29562957return false;2958}2959case glslang::EOpFunction:2960if (visit == glslang::EvPreVisit) {2961if (options.generateDebugInfo) {2962builder.setDebugSourceLocation(node->getLoc().line, node->getLoc().getFilename());2963}2964if (isShaderEntryPoint(node)) {2965inEntryPoint = true;2966builder.setBuildPoint(shaderEntry->getLastBlock());2967builder.enterFunction(shaderEntry);2968currentFunction = shaderEntry;2969} else {2970handleFunctionEntry(node);2971}2972if (options.generateDebugInfo && !options.emitNonSemanticShaderDebugInfo) {2973const auto& loc = node->getLoc();2974const char* sourceFileName = loc.getFilename();2975spv::Id sourceFileId = sourceFileName ? builder.getStringId(sourceFileName) : builder.getMainFileId();2976currentFunction->setDebugLineInfo(sourceFileId, loc.line, loc.column);2977}2978} else {2979if (inEntryPoint)2980entryPointTerminated = true;2981builder.leaveFunction();2982inEntryPoint = false;2983}29842985return true;2986case glslang::EOpParameters:2987// Parameters will have been consumed by EOpFunction processing, but not2988// the body, so we still visited the function node's children, making this2989// child redundant.2990return false;2991case glslang::EOpFunctionCall:2992{2993builder.setDebugSourceLocation(node->getLoc().line, node->getLoc().getFilename());2994if (node->isUserDefined())2995result = handleUserFunctionCall(node);2996if (result) {2997builder.clearAccessChain();2998builder.setAccessChainRValue(result);2999} else3000logger->missingFunctionality("missing user function; linker needs to catch that");30013002return false;3003}3004case glslang::EOpConstructMat2x2:3005case glslang::EOpConstructMat2x3:3006case glslang::EOpConstructMat2x4:3007case glslang::EOpConstructMat3x2:3008case glslang::EOpConstructMat3x3:3009case glslang::EOpConstructMat3x4:3010case glslang::EOpConstructMat4x2:3011case glslang::EOpConstructMat4x3:3012case glslang::EOpConstructMat4x4:3013case glslang::EOpConstructDMat2x2:3014case glslang::EOpConstructDMat2x3:3015case glslang::EOpConstructDMat2x4:3016case glslang::EOpConstructDMat3x2:3017case glslang::EOpConstructDMat3x3:3018case glslang::EOpConstructDMat3x4:3019case glslang::EOpConstructDMat4x2:3020case glslang::EOpConstructDMat4x3:3021case glslang::EOpConstructDMat4x4:3022case glslang::EOpConstructIMat2x2:3023case glslang::EOpConstructIMat2x3:3024case glslang::EOpConstructIMat2x4:3025case glslang::EOpConstructIMat3x2:3026case glslang::EOpConstructIMat3x3:3027case glslang::EOpConstructIMat3x4:3028case glslang::EOpConstructIMat4x2:3029case glslang::EOpConstructIMat4x3:3030case glslang::EOpConstructIMat4x4:3031case glslang::EOpConstructUMat2x2:3032case glslang::EOpConstructUMat2x3:3033case glslang::EOpConstructUMat2x4:3034case glslang::EOpConstructUMat3x2:3035case glslang::EOpConstructUMat3x3:3036case glslang::EOpConstructUMat3x4:3037case glslang::EOpConstructUMat4x2:3038case glslang::EOpConstructUMat4x3:3039case glslang::EOpConstructUMat4x4:3040case glslang::EOpConstructBMat2x2:3041case glslang::EOpConstructBMat2x3:3042case glslang::EOpConstructBMat2x4:3043case glslang::EOpConstructBMat3x2:3044case glslang::EOpConstructBMat3x3:3045case glslang::EOpConstructBMat3x4:3046case glslang::EOpConstructBMat4x2:3047case glslang::EOpConstructBMat4x3:3048case glslang::EOpConstructBMat4x4:3049case glslang::EOpConstructF16Mat2x2:3050case glslang::EOpConstructF16Mat2x3:3051case glslang::EOpConstructF16Mat2x4:3052case glslang::EOpConstructF16Mat3x2:3053case glslang::EOpConstructF16Mat3x3:3054case glslang::EOpConstructF16Mat3x4:3055case glslang::EOpConstructF16Mat4x2:3056case glslang::EOpConstructF16Mat4x3:3057case glslang::EOpConstructF16Mat4x4:3058isMatrix = true;3059[[fallthrough]];3060case glslang::EOpConstructFloat:3061case glslang::EOpConstructVec2:3062case glslang::EOpConstructVec3:3063case glslang::EOpConstructVec4:3064case glslang::EOpConstructDouble:3065case glslang::EOpConstructDVec2:3066case glslang::EOpConstructDVec3:3067case glslang::EOpConstructDVec4:3068case glslang::EOpConstructFloat16:3069case glslang::EOpConstructF16Vec2:3070case glslang::EOpConstructF16Vec3:3071case glslang::EOpConstructF16Vec4:3072case glslang::EOpConstructBool:3073case glslang::EOpConstructBVec2:3074case glslang::EOpConstructBVec3:3075case glslang::EOpConstructBVec4:3076case glslang::EOpConstructInt8:3077case glslang::EOpConstructI8Vec2:3078case glslang::EOpConstructI8Vec3:3079case glslang::EOpConstructI8Vec4:3080case glslang::EOpConstructUint8:3081case glslang::EOpConstructU8Vec2:3082case glslang::EOpConstructU8Vec3:3083case glslang::EOpConstructU8Vec4:3084case glslang::EOpConstructInt16:3085case glslang::EOpConstructI16Vec2:3086case glslang::EOpConstructI16Vec3:3087case glslang::EOpConstructI16Vec4:3088case glslang::EOpConstructUint16:3089case glslang::EOpConstructU16Vec2:3090case glslang::EOpConstructU16Vec3:3091case glslang::EOpConstructU16Vec4:3092case glslang::EOpConstructInt:3093case glslang::EOpConstructIVec2:3094case glslang::EOpConstructIVec3:3095case glslang::EOpConstructIVec4:3096case glslang::EOpConstructUint:3097case glslang::EOpConstructUVec2:3098case glslang::EOpConstructUVec3:3099case glslang::EOpConstructUVec4:3100case glslang::EOpConstructInt64:3101case glslang::EOpConstructI64Vec2:3102case glslang::EOpConstructI64Vec3:3103case glslang::EOpConstructI64Vec4:3104case glslang::EOpConstructUint64:3105case glslang::EOpConstructU64Vec2:3106case glslang::EOpConstructU64Vec3:3107case glslang::EOpConstructU64Vec4:3108case glslang::EOpConstructStruct:3109case glslang::EOpConstructTextureSampler:3110case glslang::EOpConstructReference:3111case glslang::EOpConstructCooperativeMatrixNV:3112case glslang::EOpConstructCooperativeMatrixKHR:3113{3114builder.setDebugSourceLocation(node->getLoc().line, node->getLoc().getFilename());3115std::vector<spv::Id> arguments;3116translateArguments(*node, arguments, lvalueCoherentFlags);3117spv::Id constructed;3118if (node->getOp() == glslang::EOpConstructTextureSampler) {3119const glslang::TType& texType = node->getSequence()[0]->getAsTyped()->getType();3120if (glslangIntermediate->getSpv().spv >= glslang::EShTargetSpv_1_6 &&3121texType.getSampler().isBuffer()) {3122// SamplerBuffer is not supported in spirv1.6 so3123// `samplerBuffer(textureBuffer, sampler)` is a no-op3124// and textureBuffer is the result going forward3125constructed = arguments[0];3126} else3127constructed = builder.createOp(spv::OpSampledImage, resultType(), arguments);3128} else if (node->getOp() == glslang::EOpConstructStruct ||3129node->getOp() == glslang::EOpConstructCooperativeMatrixNV ||3130node->getOp() == glslang::EOpConstructCooperativeMatrixKHR ||3131node->getType().isArray()) {3132std::vector<spv::Id> constituents;3133for (int c = 0; c < (int)arguments.size(); ++c)3134constituents.push_back(arguments[c]);3135constructed = createCompositeConstruct(resultType(), constituents);3136} else if (isMatrix)3137constructed = builder.createMatrixConstructor(precision, arguments, resultType());3138else3139constructed = builder.createConstructor(precision, arguments, resultType());31403141if (node->getType().getQualifier().isNonUniform()) {3142builder.addDecoration(constructed, spv::DecorationNonUniformEXT);3143}31443145builder.clearAccessChain();3146builder.setAccessChainRValue(constructed);31473148return false;3149}31503151// These six are component-wise compares with component-wise results.3152// Forward on to createBinaryOperation(), requesting a vector result.3153case glslang::EOpLessThan:3154case glslang::EOpGreaterThan:3155case glslang::EOpLessThanEqual:3156case glslang::EOpGreaterThanEqual:3157case glslang::EOpVectorEqual:3158case glslang::EOpVectorNotEqual:3159{3160// Map the operation to a binary3161binOp = node->getOp();3162reduceComparison = false;3163switch (node->getOp()) {3164case glslang::EOpVectorEqual: binOp = glslang::EOpVectorEqual; break;3165case glslang::EOpVectorNotEqual: binOp = glslang::EOpVectorNotEqual; break;3166default: binOp = node->getOp(); break;3167}31683169break;3170}3171case glslang::EOpMul:3172// component-wise matrix multiply3173binOp = glslang::EOpMul;3174break;3175case glslang::EOpOuterProduct:3176// two vectors multiplied to make a matrix3177binOp = glslang::EOpOuterProduct;3178break;3179case glslang::EOpDot:3180{3181// for scalar dot product, use multiply3182glslang::TIntermSequence& glslangOperands = node->getSequence();3183if (glslangOperands[0]->getAsTyped()->getVectorSize() == 1)3184binOp = glslang::EOpMul;3185break;3186}3187case glslang::EOpMod:3188// when an aggregate, this is the floating-point mod built-in function,3189// which can be emitted by the one in createBinaryOperation()3190binOp = glslang::EOpMod;3191break;31923193case glslang::EOpEmitVertex:3194case glslang::EOpEndPrimitive:3195case glslang::EOpBarrier:3196case glslang::EOpMemoryBarrier:3197case glslang::EOpMemoryBarrierAtomicCounter:3198case glslang::EOpMemoryBarrierBuffer:3199case glslang::EOpMemoryBarrierImage:3200case glslang::EOpMemoryBarrierShared:3201case glslang::EOpGroupMemoryBarrier:3202case glslang::EOpDeviceMemoryBarrier:3203case glslang::EOpAllMemoryBarrierWithGroupSync:3204case glslang::EOpDeviceMemoryBarrierWithGroupSync:3205case glslang::EOpWorkgroupMemoryBarrier:3206case glslang::EOpWorkgroupMemoryBarrierWithGroupSync:3207case glslang::EOpSubgroupBarrier:3208case glslang::EOpSubgroupMemoryBarrier:3209case glslang::EOpSubgroupMemoryBarrierBuffer:3210case glslang::EOpSubgroupMemoryBarrierImage:3211case glslang::EOpSubgroupMemoryBarrierShared:3212noReturnValue = true;3213// These all have 0 operands and will naturally finish up in the code below for 0 operands3214break;32153216case glslang::EOpAtomicAdd:3217case glslang::EOpAtomicSubtract:3218case glslang::EOpAtomicMin:3219case glslang::EOpAtomicMax:3220case glslang::EOpAtomicAnd:3221case glslang::EOpAtomicOr:3222case glslang::EOpAtomicXor:3223case glslang::EOpAtomicExchange:3224case glslang::EOpAtomicCompSwap:3225atomic = true;3226break;32273228case glslang::EOpAtomicStore:3229noReturnValue = true;3230[[fallthrough]];3231case glslang::EOpAtomicLoad:3232atomic = true;3233break;32343235case glslang::EOpAtomicCounterAdd:3236case glslang::EOpAtomicCounterSubtract:3237case glslang::EOpAtomicCounterMin:3238case glslang::EOpAtomicCounterMax:3239case glslang::EOpAtomicCounterAnd:3240case glslang::EOpAtomicCounterOr:3241case glslang::EOpAtomicCounterXor:3242case glslang::EOpAtomicCounterExchange:3243case glslang::EOpAtomicCounterCompSwap:3244builder.addExtension("SPV_KHR_shader_atomic_counter_ops");3245builder.addCapability(spv::CapabilityAtomicStorageOps);3246atomic = true;3247break;32483249case glslang::EOpAbsDifference:3250case glslang::EOpAddSaturate:3251case glslang::EOpSubSaturate:3252case glslang::EOpAverage:3253case glslang::EOpAverageRounded:3254case glslang::EOpMul32x16:3255builder.addCapability(spv::CapabilityIntegerFunctions2INTEL);3256builder.addExtension("SPV_INTEL_shader_integer_functions2");3257binOp = node->getOp();3258break;32593260case glslang::EOpExpectEXT:3261builder.addCapability(spv::CapabilityExpectAssumeKHR);3262builder.addExtension(spv::E_SPV_KHR_expect_assume);3263binOp = node->getOp();3264break;32653266case glslang::EOpIgnoreIntersectionNV:3267case glslang::EOpTerminateRayNV:3268case glslang::EOpTraceNV:3269case glslang::EOpTraceRayMotionNV:3270case glslang::EOpTraceKHR:3271case glslang::EOpExecuteCallableNV:3272case glslang::EOpExecuteCallableKHR:3273case glslang::EOpWritePackedPrimitiveIndices4x8NV:3274case glslang::EOpEmitMeshTasksEXT:3275case glslang::EOpSetMeshOutputsEXT:3276noReturnValue = true;3277break;3278case glslang::EOpRayQueryInitialize:3279case glslang::EOpRayQueryTerminate:3280case glslang::EOpRayQueryGenerateIntersection:3281case glslang::EOpRayQueryConfirmIntersection:3282builder.addExtension("SPV_KHR_ray_query");3283builder.addCapability(spv::CapabilityRayQueryKHR);3284noReturnValue = true;3285break;3286case glslang::EOpRayQueryProceed:3287case glslang::EOpRayQueryGetIntersectionType:3288case glslang::EOpRayQueryGetRayTMin:3289case glslang::EOpRayQueryGetRayFlags:3290case glslang::EOpRayQueryGetIntersectionT:3291case glslang::EOpRayQueryGetIntersectionInstanceCustomIndex:3292case glslang::EOpRayQueryGetIntersectionInstanceId:3293case glslang::EOpRayQueryGetIntersectionInstanceShaderBindingTableRecordOffset:3294case glslang::EOpRayQueryGetIntersectionGeometryIndex:3295case glslang::EOpRayQueryGetIntersectionPrimitiveIndex:3296case glslang::EOpRayQueryGetIntersectionBarycentrics:3297case glslang::EOpRayQueryGetIntersectionFrontFace:3298case glslang::EOpRayQueryGetIntersectionCandidateAABBOpaque:3299case glslang::EOpRayQueryGetIntersectionObjectRayDirection:3300case glslang::EOpRayQueryGetIntersectionObjectRayOrigin:3301case glslang::EOpRayQueryGetWorldRayDirection:3302case glslang::EOpRayQueryGetWorldRayOrigin:3303case glslang::EOpRayQueryGetIntersectionObjectToWorld:3304case glslang::EOpRayQueryGetIntersectionWorldToObject:3305builder.addExtension("SPV_KHR_ray_query");3306builder.addCapability(spv::CapabilityRayQueryKHR);3307break;3308case glslang::EOpCooperativeMatrixLoad:3309case glslang::EOpCooperativeMatrixStore:3310case glslang::EOpCooperativeMatrixLoadNV:3311case glslang::EOpCooperativeMatrixStoreNV:3312noReturnValue = true;3313break;3314case glslang::EOpBeginInvocationInterlock:3315case glslang::EOpEndInvocationInterlock:3316builder.addExtension(spv::E_SPV_EXT_fragment_shader_interlock);3317noReturnValue = true;3318break;33193320case glslang::EOpHitObjectTraceRayNV:3321case glslang::EOpHitObjectTraceRayMotionNV:3322case glslang::EOpHitObjectGetAttributesNV:3323case glslang::EOpHitObjectExecuteShaderNV:3324case glslang::EOpHitObjectRecordEmptyNV:3325case glslang::EOpHitObjectRecordMissNV:3326case glslang::EOpHitObjectRecordMissMotionNV:3327case glslang::EOpHitObjectRecordHitNV:3328case glslang::EOpHitObjectRecordHitMotionNV:3329case glslang::EOpHitObjectRecordHitWithIndexNV:3330case glslang::EOpHitObjectRecordHitWithIndexMotionNV:3331case glslang::EOpReorderThreadNV:3332noReturnValue = true;3333[[fallthrough]];3334case glslang::EOpHitObjectIsEmptyNV:3335case glslang::EOpHitObjectIsMissNV:3336case glslang::EOpHitObjectIsHitNV:3337case glslang::EOpHitObjectGetRayTMinNV:3338case glslang::EOpHitObjectGetRayTMaxNV:3339case glslang::EOpHitObjectGetObjectRayOriginNV:3340case glslang::EOpHitObjectGetObjectRayDirectionNV:3341case glslang::EOpHitObjectGetWorldRayOriginNV:3342case glslang::EOpHitObjectGetWorldRayDirectionNV:3343case glslang::EOpHitObjectGetObjectToWorldNV:3344case glslang::EOpHitObjectGetWorldToObjectNV:3345case glslang::EOpHitObjectGetInstanceCustomIndexNV:3346case glslang::EOpHitObjectGetInstanceIdNV:3347case glslang::EOpHitObjectGetGeometryIndexNV:3348case glslang::EOpHitObjectGetPrimitiveIndexNV:3349case glslang::EOpHitObjectGetHitKindNV:3350case glslang::EOpHitObjectGetCurrentTimeNV:3351case glslang::EOpHitObjectGetShaderBindingTableRecordIndexNV:3352case glslang::EOpHitObjectGetShaderRecordBufferHandleNV:3353builder.addExtension(spv::E_SPV_NV_shader_invocation_reorder);3354builder.addCapability(spv::CapabilityShaderInvocationReorderNV);3355break;3356case glslang::EOpRayQueryGetIntersectionTriangleVertexPositionsEXT:3357builder.addExtension(spv::E_SPV_KHR_ray_tracing_position_fetch);3358builder.addCapability(spv::CapabilityRayQueryPositionFetchKHR);3359noReturnValue = true;3360break;33613362case glslang::EOpImageSampleWeightedQCOM:3363builder.addCapability(spv::CapabilityTextureSampleWeightedQCOM);3364builder.addExtension(spv::E_SPV_QCOM_image_processing);3365break;3366case glslang::EOpImageBoxFilterQCOM:3367builder.addCapability(spv::CapabilityTextureBoxFilterQCOM);3368builder.addExtension(spv::E_SPV_QCOM_image_processing);3369break;3370case glslang::EOpImageBlockMatchSADQCOM:3371case glslang::EOpImageBlockMatchSSDQCOM:3372builder.addCapability(spv::CapabilityTextureBlockMatchQCOM);3373builder.addExtension(spv::E_SPV_QCOM_image_processing);3374break;33753376case glslang::EOpImageBlockMatchWindowSSDQCOM:3377case glslang::EOpImageBlockMatchWindowSADQCOM:3378builder.addCapability(spv::CapabilityTextureBlockMatchQCOM);3379builder.addExtension(spv::E_SPV_QCOM_image_processing);3380builder.addCapability(spv::CapabilityTextureBlockMatch2QCOM);3381builder.addExtension(spv::E_SPV_QCOM_image_processing2);3382break;33833384case glslang::EOpImageBlockMatchGatherSSDQCOM:3385case glslang::EOpImageBlockMatchGatherSADQCOM:3386builder.addCapability(spv::CapabilityTextureBlockMatchQCOM);3387builder.addExtension(spv::E_SPV_QCOM_image_processing);3388builder.addCapability(spv::CapabilityTextureBlockMatch2QCOM);3389builder.addExtension(spv::E_SPV_QCOM_image_processing2);3390break;33913392case glslang::EOpFetchMicroTriangleVertexPositionNV:3393case glslang::EOpFetchMicroTriangleVertexBarycentricNV:3394builder.addExtension(spv::E_SPV_NV_displacement_micromap);3395builder.addCapability(spv::CapabilityDisplacementMicromapNV);3396break;33973398case glslang::EOpDebugPrintf:3399noReturnValue = true;3400break;34013402default:3403break;3404}34053406//3407// See if it maps to a regular operation.3408//3409if (binOp != glslang::EOpNull) {3410glslang::TIntermTyped* left = node->getSequence()[0]->getAsTyped();3411glslang::TIntermTyped* right = node->getSequence()[1]->getAsTyped();3412assert(left && right);34133414builder.clearAccessChain();3415left->traverse(this);3416spv::Id leftId = accessChainLoad(left->getType());34173418builder.clearAccessChain();3419right->traverse(this);3420spv::Id rightId = accessChainLoad(right->getType());34213422builder.setDebugSourceLocation(node->getLoc().line, node->getLoc().getFilename());3423OpDecorations decorations = { precision,3424TranslateNoContractionDecoration(node->getType().getQualifier()),3425TranslateNonUniformDecoration(node->getType().getQualifier()) };3426result = createBinaryOperation(binOp, decorations,3427resultType(), leftId, rightId,3428left->getType().getBasicType(), reduceComparison);34293430// code above should only make binOp that exists in createBinaryOperation3431assert(result != spv::NoResult);3432builder.clearAccessChain();3433builder.setAccessChainRValue(result);34343435return false;3436}34373438//3439// Create the list of operands.3440//3441glslang::TIntermSequence& glslangOperands = node->getSequence();3442std::vector<spv::Id> operands;3443std::vector<spv::IdImmediate> memoryAccessOperands;3444for (int arg = 0; arg < (int)glslangOperands.size(); ++arg) {3445// special case l-value operands; there are just a few3446bool lvalue = false;3447switch (node->getOp()) {3448case glslang::EOpModf:3449if (arg == 1)3450lvalue = true;3451break;3452345334543455case glslang::EOpHitObjectRecordHitNV:3456case glslang::EOpHitObjectRecordHitMotionNV:3457case glslang::EOpHitObjectRecordHitWithIndexNV:3458case glslang::EOpHitObjectRecordHitWithIndexMotionNV:3459case glslang::EOpHitObjectTraceRayNV:3460case glslang::EOpHitObjectTraceRayMotionNV:3461case glslang::EOpHitObjectExecuteShaderNV:3462case glslang::EOpHitObjectRecordMissNV:3463case glslang::EOpHitObjectRecordMissMotionNV:3464case glslang::EOpHitObjectGetAttributesNV:3465if (arg == 0)3466lvalue = true;3467break;34683469case glslang::EOpRayQueryInitialize:3470case glslang::EOpRayQueryTerminate:3471case glslang::EOpRayQueryConfirmIntersection:3472case glslang::EOpRayQueryProceed:3473case glslang::EOpRayQueryGenerateIntersection:3474case glslang::EOpRayQueryGetIntersectionType:3475case glslang::EOpRayQueryGetIntersectionT:3476case glslang::EOpRayQueryGetIntersectionInstanceCustomIndex:3477case glslang::EOpRayQueryGetIntersectionInstanceId:3478case glslang::EOpRayQueryGetIntersectionInstanceShaderBindingTableRecordOffset:3479case glslang::EOpRayQueryGetIntersectionGeometryIndex:3480case glslang::EOpRayQueryGetIntersectionPrimitiveIndex:3481case glslang::EOpRayQueryGetIntersectionBarycentrics:3482case glslang::EOpRayQueryGetIntersectionFrontFace:3483case glslang::EOpRayQueryGetIntersectionObjectRayDirection:3484case glslang::EOpRayQueryGetIntersectionObjectRayOrigin:3485case glslang::EOpRayQueryGetIntersectionObjectToWorld:3486case glslang::EOpRayQueryGetIntersectionWorldToObject:3487if (arg == 0)3488lvalue = true;3489break;34903491case glslang::EOpAtomicAdd:3492case glslang::EOpAtomicSubtract:3493case glslang::EOpAtomicMin:3494case glslang::EOpAtomicMax:3495case glslang::EOpAtomicAnd:3496case glslang::EOpAtomicOr:3497case glslang::EOpAtomicXor:3498case glslang::EOpAtomicExchange:3499case glslang::EOpAtomicCompSwap:3500if (arg == 0)3501lvalue = true;3502break;35033504case glslang::EOpFrexp:3505if (arg == 1)3506lvalue = true;3507break;3508case glslang::EOpInterpolateAtSample:3509case glslang::EOpInterpolateAtOffset:3510case glslang::EOpInterpolateAtVertex:3511if (arg == 0) {3512// If GLSL, use the address of the interpolant argument.3513// If HLSL, use an internal version of OpInterolates that takes3514// the rvalue of the interpolant. A fixup pass in spirv-opt3515// legalization will remove the OpLoad and convert to an lvalue.3516// Had to do this because legalization will only propagate a3517// builtin into an rvalue.3518lvalue = glslangIntermediate->getSource() != glslang::EShSourceHlsl;35193520// Does it need a swizzle inversion? If so, evaluation is inverted;3521// operate first on the swizzle base, then apply the swizzle.3522// That is, we transform3523//3524// interpolate(v.zy) -> interpolate(v).zy3525//3526if (glslangOperands[0]->getAsOperator() &&3527glslangOperands[0]->getAsOperator()->getOp() == glslang::EOpVectorSwizzle)3528invertedType = convertGlslangToSpvType(3529glslangOperands[0]->getAsBinaryNode()->getLeft()->getType());3530}3531break;3532case glslang::EOpAtomicLoad:3533case glslang::EOpAtomicStore:3534case glslang::EOpAtomicCounterAdd:3535case glslang::EOpAtomicCounterSubtract:3536case glslang::EOpAtomicCounterMin:3537case glslang::EOpAtomicCounterMax:3538case glslang::EOpAtomicCounterAnd:3539case glslang::EOpAtomicCounterOr:3540case glslang::EOpAtomicCounterXor:3541case glslang::EOpAtomicCounterExchange:3542case glslang::EOpAtomicCounterCompSwap:3543if (arg == 0)3544lvalue = true;3545break;3546case glslang::EOpAddCarry:3547case glslang::EOpSubBorrow:3548if (arg == 2)3549lvalue = true;3550break;3551case glslang::EOpUMulExtended:3552case glslang::EOpIMulExtended:3553if (arg >= 2)3554lvalue = true;3555break;3556case glslang::EOpCooperativeMatrixLoad:3557case glslang::EOpCooperativeMatrixLoadNV:3558if (arg == 0 || arg == 1)3559lvalue = true;3560break;3561case glslang::EOpCooperativeMatrixStore:3562case glslang::EOpCooperativeMatrixStoreNV:3563if (arg == 1)3564lvalue = true;3565break;3566case glslang::EOpSpirvInst:3567if (glslangOperands[arg]->getAsTyped()->getQualifier().isSpirvByReference())3568lvalue = true;3569break;3570case glslang::EOpReorderThreadNV:3571//Three variants of reorderThreadNV, two of them use hitObjectNV3572if (arg == 0 && glslangOperands.size() != 2)3573lvalue = true;3574break;3575case glslang::EOpRayQueryGetIntersectionTriangleVertexPositionsEXT:3576if (arg == 0 || arg == 2)3577lvalue = true;3578break;3579default:3580break;3581}3582builder.clearAccessChain();3583if (invertedType != spv::NoType && arg == 0)3584glslangOperands[0]->getAsBinaryNode()->getLeft()->traverse(this);3585else3586glslangOperands[arg]->traverse(this);35873588if (node->getOp() == glslang::EOpCooperativeMatrixLoad ||3589node->getOp() == glslang::EOpCooperativeMatrixStore ||3590node->getOp() == glslang::EOpCooperativeMatrixLoadNV ||3591node->getOp() == glslang::EOpCooperativeMatrixStoreNV) {35923593if (arg == 1) {3594// fold "element" parameter into the access chain3595spv::Builder::AccessChain save = builder.getAccessChain();3596builder.clearAccessChain();3597glslangOperands[2]->traverse(this);35983599spv::Id elementId = accessChainLoad(glslangOperands[2]->getAsTyped()->getType());36003601builder.setAccessChain(save);36023603// Point to the first element of the array.3604builder.accessChainPush(elementId,3605TranslateCoherent(glslangOperands[arg]->getAsTyped()->getType()),3606glslangOperands[arg]->getAsTyped()->getType().getBufferReferenceAlignment());36073608spv::Builder::AccessChain::CoherentFlags coherentFlags = builder.getAccessChain().coherentFlags;3609unsigned int alignment = builder.getAccessChain().alignment;36103611int memoryAccess = TranslateMemoryAccess(coherentFlags);3612if (node->getOp() == glslang::EOpCooperativeMatrixLoad ||3613node->getOp() == glslang::EOpCooperativeMatrixLoadNV)3614memoryAccess &= ~spv::MemoryAccessMakePointerAvailableKHRMask;3615if (node->getOp() == glslang::EOpCooperativeMatrixStore ||3616node->getOp() == glslang::EOpCooperativeMatrixStoreNV)3617memoryAccess &= ~spv::MemoryAccessMakePointerVisibleKHRMask;3618if (builder.getStorageClass(builder.getAccessChain().base) ==3619spv::StorageClassPhysicalStorageBufferEXT) {3620memoryAccess = (spv::MemoryAccessMask)(memoryAccess | spv::MemoryAccessAlignedMask);3621}36223623memoryAccessOperands.push_back(spv::IdImmediate(false, memoryAccess));36243625if (memoryAccess & spv::MemoryAccessAlignedMask) {3626memoryAccessOperands.push_back(spv::IdImmediate(false, alignment));3627}36283629if (memoryAccess &3630(spv::MemoryAccessMakePointerAvailableKHRMask | spv::MemoryAccessMakePointerVisibleKHRMask)) {3631memoryAccessOperands.push_back(spv::IdImmediate(true,3632builder.makeUintConstant(TranslateMemoryScope(coherentFlags))));3633}3634} else if (arg == 2) {3635continue;3636}3637}36383639// for l-values, pass the address, for r-values, pass the value3640if (lvalue) {3641if (invertedType == spv::NoType && !builder.isSpvLvalue()) {3642// SPIR-V cannot represent an l-value containing a swizzle that doesn't3643// reduce to a simple access chain. So, we need a temporary vector to3644// receive the result, and must later swizzle that into the original3645// l-value.3646complexLvalues.push_back(builder.getAccessChain());3647temporaryLvalues.push_back(builder.createVariable(3648spv::NoPrecision, spv::StorageClassFunction,3649builder.accessChainGetInferredType(), "swizzleTemp"));3650operands.push_back(temporaryLvalues.back());3651} else {3652operands.push_back(builder.accessChainGetLValue());3653}3654lvalueCoherentFlags = builder.getAccessChain().coherentFlags;3655lvalueCoherentFlags |= TranslateCoherent(glslangOperands[arg]->getAsTyped()->getType());3656} else {3657builder.setDebugSourceLocation(node->getLoc().line, node->getLoc().getFilename());3658glslang::TOperator glslangOp = node->getOp();3659if (arg == 1 &&3660(glslangOp == glslang::EOpRayQueryGetIntersectionType ||3661glslangOp == glslang::EOpRayQueryGetIntersectionT ||3662glslangOp == glslang::EOpRayQueryGetIntersectionInstanceCustomIndex ||3663glslangOp == glslang::EOpRayQueryGetIntersectionInstanceId ||3664glslangOp == glslang::EOpRayQueryGetIntersectionInstanceShaderBindingTableRecordOffset ||3665glslangOp == glslang::EOpRayQueryGetIntersectionGeometryIndex ||3666glslangOp == glslang::EOpRayQueryGetIntersectionPrimitiveIndex ||3667glslangOp == glslang::EOpRayQueryGetIntersectionBarycentrics ||3668glslangOp == glslang::EOpRayQueryGetIntersectionFrontFace ||3669glslangOp == glslang::EOpRayQueryGetIntersectionObjectRayDirection ||3670glslangOp == glslang::EOpRayQueryGetIntersectionObjectRayOrigin ||3671glslangOp == glslang::EOpRayQueryGetIntersectionObjectToWorld ||3672glslangOp == glslang::EOpRayQueryGetIntersectionWorldToObject ||3673glslangOp == glslang::EOpRayQueryGetIntersectionTriangleVertexPositionsEXT3674)) {3675bool cond = glslangOperands[arg]->getAsConstantUnion()->getConstArray()[0].getBConst();3676operands.push_back(builder.makeIntConstant(cond ? 1 : 0));3677} else if ((arg == 10 && glslangOp == glslang::EOpTraceKHR) ||3678(arg == 11 && glslangOp == glslang::EOpTraceRayMotionNV) ||3679(arg == 1 && glslangOp == glslang::EOpExecuteCallableKHR) ||3680(arg == 1 && glslangOp == glslang::EOpHitObjectExecuteShaderNV) ||3681(arg == 11 && glslangOp == glslang::EOpHitObjectTraceRayNV) ||3682(arg == 12 && glslangOp == glslang::EOpHitObjectTraceRayMotionNV)) {3683const int set = glslangOp == glslang::EOpExecuteCallableKHR ? 1 : 0;3684const int location = glslangOperands[arg]->getAsConstantUnion()->getConstArray()[0].getUConst();3685auto itNode = locationToSymbol[set].find(location);3686visitSymbol(itNode->second);3687spv::Id symId = getSymbolId(itNode->second);3688operands.push_back(symId);3689} else if ((arg == 12 && glslangOp == glslang::EOpHitObjectRecordHitNV) ||3690(arg == 13 && glslangOp == glslang::EOpHitObjectRecordHitMotionNV) ||3691(arg == 11 && glslangOp == glslang::EOpHitObjectRecordHitWithIndexNV) ||3692(arg == 12 && glslangOp == glslang::EOpHitObjectRecordHitWithIndexMotionNV) ||3693(arg == 1 && glslangOp == glslang::EOpHitObjectGetAttributesNV)) {3694const int location = glslangOperands[arg]->getAsConstantUnion()->getConstArray()[0].getUConst();3695const int set = 2;3696auto itNode = locationToSymbol[set].find(location);3697visitSymbol(itNode->second);3698spv::Id symId = getSymbolId(itNode->second);3699operands.push_back(symId);3700} else if (glslangOperands[arg]->getAsTyped()->getQualifier().isSpirvLiteral()) {3701// Will be translated to a literal value, make a placeholder here3702operands.push_back(spv::NoResult);3703} else {3704operands.push_back(accessChainLoad(glslangOperands[arg]->getAsTyped()->getType()));3705}3706}3707}37083709builder.setDebugSourceLocation(node->getLoc().line, node->getLoc().getFilename());3710if (node->getOp() == glslang::EOpCooperativeMatrixLoad ||3711node->getOp() == glslang::EOpCooperativeMatrixLoadNV) {3712std::vector<spv::IdImmediate> idImmOps;37133714idImmOps.push_back(spv::IdImmediate(true, operands[1])); // buf3715if (node->getOp() == glslang::EOpCooperativeMatrixLoad) {3716idImmOps.push_back(spv::IdImmediate(true, operands[3])); // matrixLayout3717idImmOps.push_back(spv::IdImmediate(true, operands[2])); // stride3718} else {3719idImmOps.push_back(spv::IdImmediate(true, operands[2])); // stride3720idImmOps.push_back(spv::IdImmediate(true, operands[3])); // colMajor3721}3722idImmOps.insert(idImmOps.end(), memoryAccessOperands.begin(), memoryAccessOperands.end());3723// get the pointee type3724spv::Id typeId = builder.getContainedTypeId(builder.getTypeId(operands[0]));3725assert(builder.isCooperativeMatrixType(typeId));3726// do the op3727spv::Id result = node->getOp() == glslang::EOpCooperativeMatrixLoad3728? builder.createOp(spv::OpCooperativeMatrixLoadKHR, typeId, idImmOps)3729: builder.createOp(spv::OpCooperativeMatrixLoadNV, typeId, idImmOps);3730// store the result to the pointer (out param 'm')3731builder.createStore(result, operands[0]);3732result = 0;3733} else if (node->getOp() == glslang::EOpCooperativeMatrixStore ||3734node->getOp() == glslang::EOpCooperativeMatrixStoreNV) {3735std::vector<spv::IdImmediate> idImmOps;37363737idImmOps.push_back(spv::IdImmediate(true, operands[1])); // buf3738idImmOps.push_back(spv::IdImmediate(true, operands[0])); // object3739if (node->getOp() == glslang::EOpCooperativeMatrixStore) {3740idImmOps.push_back(spv::IdImmediate(true, operands[3])); // matrixLayout3741idImmOps.push_back(spv::IdImmediate(true, operands[2])); // stride3742} else {3743idImmOps.push_back(spv::IdImmediate(true, operands[2])); // stride3744idImmOps.push_back(spv::IdImmediate(true, operands[3])); // colMajor3745}3746idImmOps.insert(idImmOps.end(), memoryAccessOperands.begin(), memoryAccessOperands.end());37473748if (node->getOp() == glslang::EOpCooperativeMatrixStore)3749builder.createNoResultOp(spv::OpCooperativeMatrixStoreKHR, idImmOps);3750else3751builder.createNoResultOp(spv::OpCooperativeMatrixStoreNV, idImmOps);3752result = 0;3753} else if (node->getOp() == glslang::EOpRayQueryGetIntersectionTriangleVertexPositionsEXT) {3754std::vector<spv::IdImmediate> idImmOps;37553756idImmOps.push_back(spv::IdImmediate(true, operands[0])); // q3757idImmOps.push_back(spv::IdImmediate(true, operands[1])); // committed37583759spv::Id typeId = builder.makeArrayType(builder.makeVectorType(builder.makeFloatType(32), 3),3760builder.makeUintConstant(3), 0);3761// do the op37623763spv::Op spvOp = spv::OpRayQueryGetIntersectionTriangleVertexPositionsKHR;37643765spv::Id result = builder.createOp(spvOp, typeId, idImmOps);3766// store the result to the pointer (out param 'm')3767builder.createStore(result, operands[2]);3768result = 0;3769} else if (node->getOp() == glslang::EOpCooperativeMatrixMulAdd) {3770uint32_t matrixOperands = 0;37713772// If the optional operand is present, initialize matrixOperands to that value.3773if (glslangOperands.size() == 4 && glslangOperands[3]->getAsConstantUnion()) {3774matrixOperands = glslangOperands[3]->getAsConstantUnion()->getConstArray()[0].getIConst();3775}37763777// Determine Cooperative Matrix Operands bits from the signedness of the types.3778if (isTypeSignedInt(glslangOperands[0]->getAsTyped()->getBasicType()))3779matrixOperands |= spv::CooperativeMatrixOperandsMatrixASignedComponentsKHRMask;3780if (isTypeSignedInt(glslangOperands[1]->getAsTyped()->getBasicType()))3781matrixOperands |= spv::CooperativeMatrixOperandsMatrixBSignedComponentsKHRMask;3782if (isTypeSignedInt(glslangOperands[2]->getAsTyped()->getBasicType()))3783matrixOperands |= spv::CooperativeMatrixOperandsMatrixCSignedComponentsKHRMask;3784if (isTypeSignedInt(node->getBasicType()))3785matrixOperands |= spv::CooperativeMatrixOperandsMatrixResultSignedComponentsKHRMask;37863787std::vector<spv::IdImmediate> idImmOps;3788idImmOps.push_back(spv::IdImmediate(true, operands[0]));3789idImmOps.push_back(spv::IdImmediate(true, operands[1]));3790idImmOps.push_back(spv::IdImmediate(true, operands[2]));3791if (matrixOperands != 0)3792idImmOps.push_back(spv::IdImmediate(false, matrixOperands));37933794result = builder.createOp(spv::OpCooperativeMatrixMulAddKHR, resultType(), idImmOps);3795} else if (atomic) {3796// Handle all atomics3797glslang::TBasicType typeProxy = (node->getOp() == glslang::EOpAtomicStore)3798? node->getSequence()[0]->getAsTyped()->getBasicType() : node->getBasicType();3799result = createAtomicOperation(node->getOp(), precision, resultType(), operands, typeProxy,3800lvalueCoherentFlags, node->getType());3801} else if (node->getOp() == glslang::EOpSpirvInst) {3802const auto& spirvInst = node->getSpirvInstruction();3803if (spirvInst.set == "") {3804std::vector<spv::IdImmediate> idImmOps;3805for (unsigned int i = 0; i < glslangOperands.size(); ++i) {3806if (glslangOperands[i]->getAsTyped()->getQualifier().isSpirvLiteral()) {3807// Translate the constant to a literal value3808std::vector<unsigned> literals;3809glslang::TVector<const glslang::TIntermConstantUnion*> constants;3810constants.push_back(glslangOperands[i]->getAsConstantUnion());3811TranslateLiterals(constants, literals);3812idImmOps.push_back({false, literals[0]});3813} else3814idImmOps.push_back({true, operands[i]});3815}38163817if (node->getBasicType() == glslang::EbtVoid)3818builder.createNoResultOp(static_cast<spv::Op>(spirvInst.id), idImmOps);3819else3820result = builder.createOp(static_cast<spv::Op>(spirvInst.id), resultType(), idImmOps);3821} else {3822result = builder.createBuiltinCall(3823resultType(), spirvInst.set == "GLSL.std.450" ? stdBuiltins : getExtBuiltins(spirvInst.set.c_str()),3824spirvInst.id, operands);3825}3826noReturnValue = node->getBasicType() == glslang::EbtVoid;3827} else if (node->getOp() == glslang::EOpDebugPrintf) {3828if (!nonSemanticDebugPrintf) {3829nonSemanticDebugPrintf = builder.import("NonSemantic.DebugPrintf");3830}3831result = builder.createBuiltinCall(builder.makeVoidType(), nonSemanticDebugPrintf, spv::NonSemanticDebugPrintfDebugPrintf, operands);3832builder.addExtension(spv::E_SPV_KHR_non_semantic_info);3833} else {3834// Pass through to generic operations.3835switch (glslangOperands.size()) {3836case 0:3837result = createNoArgOperation(node->getOp(), precision, resultType());3838break;3839case 1:3840{3841OpDecorations decorations = { precision,3842TranslateNoContractionDecoration(node->getType().getQualifier()),3843TranslateNonUniformDecoration(node->getType().getQualifier()) };3844result = createUnaryOperation(3845node->getOp(), decorations,3846resultType(), operands.front(),3847glslangOperands[0]->getAsTyped()->getBasicType(), lvalueCoherentFlags, node->getType());3848}3849break;3850default:3851result = createMiscOperation(node->getOp(), precision, resultType(), operands, node->getBasicType());3852break;3853}38543855if (invertedType != spv::NoResult)3856result = createInvertedSwizzle(precision, *glslangOperands[0]->getAsBinaryNode(), result);38573858for (unsigned int i = 0; i < temporaryLvalues.size(); ++i) {3859builder.setAccessChain(complexLvalues[i]);3860builder.accessChainStore(builder.createLoad(temporaryLvalues[i], spv::NoPrecision),3861TranslateNonUniformDecoration(complexLvalues[i].coherentFlags));3862}3863}38643865if (noReturnValue)3866return false;38673868if (! result) {3869logger->missingFunctionality("unknown glslang aggregate");3870return true; // pick up a child as a placeholder operand3871} else {3872builder.clearAccessChain();3873builder.setAccessChainRValue(result);3874return false;3875}3876}38773878// This path handles both if-then-else and ?:3879// The if-then-else has a node type of void, while3880// ?: has either a void or a non-void node type3881//3882// Leaving the result, when not void:3883// GLSL only has r-values as the result of a :?, but3884// if we have an l-value, that can be more efficient if it will3885// become the base of a complex r-value expression, because the3886// next layer copies r-values into memory to use the access-chain mechanism3887bool TGlslangToSpvTraverser::visitSelection(glslang::TVisit /* visit */, glslang::TIntermSelection* node)3888{3889// see if OpSelect can handle it3890const auto isOpSelectable = [&]() {3891if (node->getBasicType() == glslang::EbtVoid)3892return false;3893// OpSelect can do all other types starting with SPV 1.43894if (glslangIntermediate->getSpv().spv < glslang::EShTargetSpv_1_4) {3895// pre-1.4, only scalars and vectors can be handled3896if ((!node->getType().isScalar() && !node->getType().isVector()))3897return false;3898}3899return true;3900};39013902// See if it simple and safe, or required, to execute both sides.3903// Crucially, side effects must be either semantically required or avoided,3904// and there are performance trade-offs.3905// Return true if required or a good idea (and safe) to execute both sides,3906// false otherwise.3907const auto bothSidesPolicy = [&]() -> bool {3908// do we have both sides?3909if (node->getTrueBlock() == nullptr ||3910node->getFalseBlock() == nullptr)3911return false;39123913// required? (unless we write additional code to look for side effects3914// and make performance trade-offs if none are present)3915if (!node->getShortCircuit())3916return true;39173918// if not required to execute both, decide based on performance/practicality...39193920if (!isOpSelectable())3921return false;39223923assert(node->getType() == node->getTrueBlock() ->getAsTyped()->getType() &&3924node->getType() == node->getFalseBlock()->getAsTyped()->getType());39253926// return true if a single operand to ? : is okay for OpSelect3927const auto operandOkay = [](glslang::TIntermTyped* node) {3928return node->getAsSymbolNode() || node->getType().getQualifier().isConstant();3929};39303931return operandOkay(node->getTrueBlock() ->getAsTyped()) &&3932operandOkay(node->getFalseBlock()->getAsTyped());3933};39343935spv::Id result = spv::NoResult; // upcoming result selecting between trueValue and falseValue3936// emit the condition before doing anything with selection3937node->getCondition()->traverse(this);3938spv::Id condition = accessChainLoad(node->getCondition()->getType());39393940// Find a way of executing both sides and selecting the right result.3941const auto executeBothSides = [&]() -> void {3942// execute both sides3943spv::Id resultType = convertGlslangToSpvType(node->getType());3944node->getTrueBlock()->traverse(this);3945spv::Id trueValue = accessChainLoad(node->getTrueBlock()->getAsTyped()->getType());3946node->getFalseBlock()->traverse(this);3947spv::Id falseValue = accessChainLoad(node->getFalseBlock()->getAsTyped()->getType());39483949builder.setDebugSourceLocation(node->getLoc().line, node->getLoc().getFilename());39503951// done if void3952if (node->getBasicType() == glslang::EbtVoid)3953return;39543955// emit code to select between trueValue and falseValue3956// see if OpSelect can handle the result type, and that the SPIR-V types3957// of the inputs match the result type.3958if (isOpSelectable()) {3959// Emit OpSelect for this selection.39603961// smear condition to vector, if necessary (AST is always scalar)3962// Before 1.4, smear like for mix(), starting with 1.4, keep it scalar3963if (glslangIntermediate->getSpv().spv < glslang::EShTargetSpv_1_4 && builder.isVector(trueValue)) {3964condition = builder.smearScalar(spv::NoPrecision, condition,3965builder.makeVectorType(builder.makeBoolType(),3966builder.getNumComponents(trueValue)));3967}39683969// If the types do not match, it is because of mismatched decorations on aggregates.3970// Since isOpSelectable only lets us get here for SPIR-V >= 1.4, we can use OpCopyObject3971// to get matching types.3972if (builder.getTypeId(trueValue) != resultType) {3973trueValue = builder.createUnaryOp(spv::OpCopyLogical, resultType, trueValue);3974}3975if (builder.getTypeId(falseValue) != resultType) {3976falseValue = builder.createUnaryOp(spv::OpCopyLogical, resultType, falseValue);3977}39783979// OpSelect3980result = builder.createTriOp(spv::OpSelect, resultType, condition, trueValue, falseValue);39813982builder.clearAccessChain();3983builder.setAccessChainRValue(result);3984} else {3985// We need control flow to select the result.3986// TODO: Once SPIR-V OpSelect allows arbitrary types, eliminate this path.3987result = builder.createVariable(TranslatePrecisionDecoration(node->getType()),3988spv::StorageClassFunction, resultType);39893990// Selection control:3991const spv::SelectionControlMask control = TranslateSelectionControl(*node);39923993// make an "if" based on the value created by the condition3994spv::Builder::If ifBuilder(condition, control, builder);39953996// emit the "then" statement3997builder.clearAccessChain();3998builder.setAccessChainLValue(result);3999multiTypeStore(node->getType(), trueValue);40004001ifBuilder.makeBeginElse();4002// emit the "else" statement4003builder.clearAccessChain();4004builder.setAccessChainLValue(result);4005multiTypeStore(node->getType(), falseValue);40064007// finish off the control flow4008ifBuilder.makeEndIf();40094010builder.clearAccessChain();4011builder.setAccessChainLValue(result);4012}4013};40144015// Execute the one side needed, as per the condition4016const auto executeOneSide = [&]() {4017// Always emit control flow.4018if (node->getBasicType() != glslang::EbtVoid) {4019result = builder.createVariable(TranslatePrecisionDecoration(node->getType()), spv::StorageClassFunction,4020convertGlslangToSpvType(node->getType()));4021}40224023// Selection control:4024const spv::SelectionControlMask control = TranslateSelectionControl(*node);40254026// make an "if" based on the value created by the condition4027spv::Builder::If ifBuilder(condition, control, builder);40284029// emit the "then" statement4030if (node->getTrueBlock() != nullptr) {4031node->getTrueBlock()->traverse(this);4032if (result != spv::NoResult) {4033spv::Id load = accessChainLoad(node->getTrueBlock()->getAsTyped()->getType());40344035builder.clearAccessChain();4036builder.setAccessChainLValue(result);4037multiTypeStore(node->getType(), load);4038}4039}40404041if (node->getFalseBlock() != nullptr) {4042ifBuilder.makeBeginElse();4043// emit the "else" statement4044node->getFalseBlock()->traverse(this);4045if (result != spv::NoResult) {4046spv::Id load = accessChainLoad(node->getFalseBlock()->getAsTyped()->getType());40474048builder.clearAccessChain();4049builder.setAccessChainLValue(result);4050multiTypeStore(node->getType(), load);4051}4052}40534054// finish off the control flow4055ifBuilder.makeEndIf();40564057if (result != spv::NoResult) {4058builder.clearAccessChain();4059builder.setAccessChainLValue(result);4060}4061};40624063// Try for OpSelect (or a requirement to execute both sides)4064if (bothSidesPolicy()) {4065SpecConstantOpModeGuard spec_constant_op_mode_setter(&builder);4066if (node->getType().getQualifier().isSpecConstant())4067spec_constant_op_mode_setter.turnOnSpecConstantOpMode();4068executeBothSides();4069} else4070executeOneSide();40714072return false;4073}40744075bool TGlslangToSpvTraverser::visitSwitch(glslang::TVisit /* visit */, glslang::TIntermSwitch* node)4076{4077// emit and get the condition before doing anything with switch4078node->getCondition()->traverse(this);4079spv::Id selector = accessChainLoad(node->getCondition()->getAsTyped()->getType());40804081// Selection control:4082const spv::SelectionControlMask control = TranslateSwitchControl(*node);40834084// browse the children to sort out code segments4085int defaultSegment = -1;4086std::vector<TIntermNode*> codeSegments;4087glslang::TIntermSequence& sequence = node->getBody()->getSequence();4088std::vector<int> caseValues;4089std::vector<int> valueIndexToSegment(sequence.size()); // note: probably not all are used, it is an overestimate4090for (glslang::TIntermSequence::iterator c = sequence.begin(); c != sequence.end(); ++c) {4091TIntermNode* child = *c;4092if (child->getAsBranchNode() && child->getAsBranchNode()->getFlowOp() == glslang::EOpDefault)4093defaultSegment = (int)codeSegments.size();4094else if (child->getAsBranchNode() && child->getAsBranchNode()->getFlowOp() == glslang::EOpCase) {4095valueIndexToSegment[caseValues.size()] = (int)codeSegments.size();4096caseValues.push_back(child->getAsBranchNode()->getExpression()->getAsConstantUnion()4097->getConstArray()[0].getIConst());4098} else4099codeSegments.push_back(child);4100}41014102// handle the case where the last code segment is missing, due to no code4103// statements between the last case and the end of the switch statement4104if ((caseValues.size() && (int)codeSegments.size() == valueIndexToSegment[caseValues.size() - 1]) ||4105(int)codeSegments.size() == defaultSegment)4106codeSegments.push_back(nullptr);41074108// make the switch statement4109std::vector<spv::Block*> segmentBlocks; // returned, as the blocks allocated in the call4110builder.makeSwitch(selector, control, (int)codeSegments.size(), caseValues, valueIndexToSegment, defaultSegment,4111segmentBlocks);41124113// emit all the code in the segments4114breakForLoop.push(false);4115for (unsigned int s = 0; s < codeSegments.size(); ++s) {4116builder.nextSwitchSegment(segmentBlocks, s);4117if (codeSegments[s])4118codeSegments[s]->traverse(this);4119else4120builder.addSwitchBreak();4121}4122breakForLoop.pop();41234124builder.endSwitch(segmentBlocks);41254126return false;4127}41284129void TGlslangToSpvTraverser::visitConstantUnion(glslang::TIntermConstantUnion* node)4130{4131if (node->getQualifier().isSpirvLiteral())4132return; // Translated to a literal value, skip further processing41334134int nextConst = 0;4135spv::Id constant = createSpvConstantFromConstUnionArray(node->getType(), node->getConstArray(), nextConst, false);41364137builder.clearAccessChain();4138builder.setAccessChainRValue(constant);4139}41404141bool TGlslangToSpvTraverser::visitLoop(glslang::TVisit /* visit */, glslang::TIntermLoop* node)4142{4143auto blocks = builder.makeNewLoop();4144builder.createBranch(&blocks.head);41454146// Loop control:4147std::vector<unsigned int> operands;4148const spv::LoopControlMask control = TranslateLoopControl(*node, operands);41494150// Spec requires back edges to target header blocks, and every header block4151// must dominate its merge block. Make a header block first to ensure these4152// conditions are met. By definition, it will contain OpLoopMerge, followed4153// by a block-ending branch. But we don't want to put any other body/test4154// instructions in it, since the body/test may have arbitrary instructions,4155// including merges of its own.4156builder.setBuildPoint(&blocks.head);4157builder.setDebugSourceLocation(node->getLoc().line, node->getLoc().getFilename());4158builder.createLoopMerge(&blocks.merge, &blocks.continue_target, control, operands);4159if (node->testFirst() && node->getTest()) {4160spv::Block& test = builder.makeNewBlock();4161builder.createBranch(&test);41624163builder.setBuildPoint(&test);4164node->getTest()->traverse(this);4165spv::Id condition = accessChainLoad(node->getTest()->getType());4166builder.createConditionalBranch(condition, &blocks.body, &blocks.merge);41674168builder.setBuildPoint(&blocks.body);4169breakForLoop.push(true);4170if (node->getBody())4171node->getBody()->traverse(this);4172builder.createBranch(&blocks.continue_target);4173breakForLoop.pop();41744175builder.setBuildPoint(&blocks.continue_target);4176if (node->getTerminal())4177node->getTerminal()->traverse(this);4178builder.createBranch(&blocks.head);4179} else {4180builder.setDebugSourceLocation(node->getLoc().line, node->getLoc().getFilename());4181builder.createBranch(&blocks.body);41824183breakForLoop.push(true);4184builder.setBuildPoint(&blocks.body);4185if (node->getBody())4186node->getBody()->traverse(this);4187builder.createBranch(&blocks.continue_target);4188breakForLoop.pop();41894190builder.setBuildPoint(&blocks.continue_target);4191if (node->getTerminal())4192node->getTerminal()->traverse(this);4193if (node->getTest()) {4194node->getTest()->traverse(this);4195spv::Id condition =4196accessChainLoad(node->getTest()->getType());4197builder.createConditionalBranch(condition, &blocks.head, &blocks.merge);4198} else {4199// TODO: unless there was a break/return/discard instruction4200// somewhere in the body, this is an infinite loop, so we should4201// issue a warning.4202builder.createBranch(&blocks.head);4203}4204}4205builder.setBuildPoint(&blocks.merge);4206builder.closeLoop();4207return false;4208}42094210bool TGlslangToSpvTraverser::visitBranch(glslang::TVisit /* visit */, glslang::TIntermBranch* node)4211{4212if (node->getExpression())4213node->getExpression()->traverse(this);42144215builder.setDebugSourceLocation(node->getLoc().line, node->getLoc().getFilename());42164217switch (node->getFlowOp()) {4218case glslang::EOpKill:4219if (glslangIntermediate->getSpv().spv >= glslang::EShTargetSpv_1_6) {4220if (glslangIntermediate->getSource() == glslang::EShSourceHlsl) {4221builder.addCapability(spv::CapabilityDemoteToHelperInvocation);4222builder.createNoResultOp(spv::OpDemoteToHelperInvocationEXT);4223} else {4224builder.makeStatementTerminator(spv::OpTerminateInvocation, "post-terminate-invocation");4225}4226} else {4227builder.makeStatementTerminator(spv::OpKill, "post-discard");4228}4229break;4230case glslang::EOpTerminateInvocation:4231builder.addExtension(spv::E_SPV_KHR_terminate_invocation);4232builder.makeStatementTerminator(spv::OpTerminateInvocation, "post-terminate-invocation");4233break;4234case glslang::EOpBreak:4235if (breakForLoop.top())4236builder.createLoopExit();4237else4238builder.addSwitchBreak();4239break;4240case glslang::EOpContinue:4241builder.createLoopContinue();4242break;4243case glslang::EOpReturn:4244if (node->getExpression() != nullptr) {4245const glslang::TType& glslangReturnType = node->getExpression()->getType();4246spv::Id returnId = accessChainLoad(glslangReturnType);4247if (builder.getTypeId(returnId) != currentFunction->getReturnType() ||4248TranslatePrecisionDecoration(glslangReturnType) != currentFunction->getReturnPrecision()) {4249builder.clearAccessChain();4250spv::Id copyId = builder.createVariable(currentFunction->getReturnPrecision(),4251spv::StorageClassFunction, currentFunction->getReturnType());4252builder.setAccessChainLValue(copyId);4253multiTypeStore(glslangReturnType, returnId);4254returnId = builder.createLoad(copyId, currentFunction->getReturnPrecision());4255}4256builder.makeReturn(false, returnId);4257} else4258builder.makeReturn(false);42594260builder.clearAccessChain();4261break;42624263case glslang::EOpDemote:4264builder.createNoResultOp(spv::OpDemoteToHelperInvocationEXT);4265builder.addExtension(spv::E_SPV_EXT_demote_to_helper_invocation);4266builder.addCapability(spv::CapabilityDemoteToHelperInvocationEXT);4267break;4268case glslang::EOpTerminateRayKHR:4269builder.makeStatementTerminator(spv::OpTerminateRayKHR, "post-terminateRayKHR");4270break;4271case glslang::EOpIgnoreIntersectionKHR:4272builder.makeStatementTerminator(spv::OpIgnoreIntersectionKHR, "post-ignoreIntersectionKHR");4273break;42744275default:4276assert(0);4277break;4278}42794280return false;4281}42824283spv::Id TGlslangToSpvTraverser::createSpvVariable(const glslang::TIntermSymbol* node, spv::Id forcedType)4284{4285// First, steer off constants, which are not SPIR-V variables, but4286// can still have a mapping to a SPIR-V Id.4287// This includes specialization constants.4288if (node->getQualifier().isConstant()) {4289spv::Id result = createSpvConstant(*node);4290if (result != spv::NoResult)4291return result;4292}42934294// Now, handle actual variables4295spv::StorageClass storageClass = TranslateStorageClass(node->getType());4296spv::Id spvType = forcedType == spv::NoType ? convertGlslangToSpvType(node->getType())4297: forcedType;42984299const bool contains16BitType = node->getType().contains16BitFloat() ||4300node->getType().contains16BitInt();4301if (contains16BitType) {4302switch (storageClass) {4303case spv::StorageClassInput:4304case spv::StorageClassOutput:4305builder.addIncorporatedExtension(spv::E_SPV_KHR_16bit_storage, spv::Spv_1_3);4306builder.addCapability(spv::CapabilityStorageInputOutput16);4307break;4308case spv::StorageClassUniform:4309builder.addIncorporatedExtension(spv::E_SPV_KHR_16bit_storage, spv::Spv_1_3);4310if (node->getType().getQualifier().storage == glslang::EvqBuffer)4311builder.addCapability(spv::CapabilityStorageUniformBufferBlock16);4312else4313builder.addCapability(spv::CapabilityStorageUniform16);4314break;4315case spv::StorageClassPushConstant:4316builder.addIncorporatedExtension(spv::E_SPV_KHR_16bit_storage, spv::Spv_1_3);4317builder.addCapability(spv::CapabilityStoragePushConstant16);4318break;4319case spv::StorageClassStorageBuffer:4320case spv::StorageClassPhysicalStorageBufferEXT:4321builder.addIncorporatedExtension(spv::E_SPV_KHR_16bit_storage, spv::Spv_1_3);4322builder.addCapability(spv::CapabilityStorageUniformBufferBlock16);4323break;4324default:4325if (storageClass == spv::StorageClassWorkgroup &&4326node->getType().getBasicType() == glslang::EbtBlock) {4327builder.addCapability(spv::CapabilityWorkgroupMemoryExplicitLayout16BitAccessKHR);4328break;4329}4330if (node->getType().contains16BitFloat())4331builder.addCapability(spv::CapabilityFloat16);4332if (node->getType().contains16BitInt())4333builder.addCapability(spv::CapabilityInt16);4334break;4335}4336}43374338if (node->getType().contains8BitInt()) {4339if (storageClass == spv::StorageClassPushConstant) {4340builder.addIncorporatedExtension(spv::E_SPV_KHR_8bit_storage, spv::Spv_1_5);4341builder.addCapability(spv::CapabilityStoragePushConstant8);4342} else if (storageClass == spv::StorageClassUniform) {4343builder.addIncorporatedExtension(spv::E_SPV_KHR_8bit_storage, spv::Spv_1_5);4344builder.addCapability(spv::CapabilityUniformAndStorageBuffer8BitAccess);4345} else if (storageClass == spv::StorageClassStorageBuffer) {4346builder.addIncorporatedExtension(spv::E_SPV_KHR_8bit_storage, spv::Spv_1_5);4347builder.addCapability(spv::CapabilityStorageBuffer8BitAccess);4348} else if (storageClass == spv::StorageClassWorkgroup &&4349node->getType().getBasicType() == glslang::EbtBlock) {4350builder.addCapability(spv::CapabilityWorkgroupMemoryExplicitLayout8BitAccessKHR);4351} else {4352builder.addCapability(spv::CapabilityInt8);4353}4354}43554356const char* name = node->getName().c_str();4357if (glslang::IsAnonymous(name))4358name = "";43594360spv::Id initializer = spv::NoResult;43614362if (node->getType().getQualifier().storage == glslang::EvqUniform && !node->getConstArray().empty()) {4363int nextConst = 0;4364initializer = createSpvConstantFromConstUnionArray(node->getType(),4365node->getConstArray(),4366nextConst,4367false /* specConst */);4368} else if (node->getType().getQualifier().isNullInit()) {4369initializer = builder.makeNullConstant(spvType);4370}43714372return builder.createVariable(spv::NoPrecision, storageClass, spvType, name, initializer, false);4373}43744375// Return type Id of the sampled type.4376spv::Id TGlslangToSpvTraverser::getSampledType(const glslang::TSampler& sampler)4377{4378switch (sampler.type) {4379case glslang::EbtInt: return builder.makeIntType(32);4380case glslang::EbtUint: return builder.makeUintType(32);4381case glslang::EbtFloat: return builder.makeFloatType(32);4382case glslang::EbtFloat16:4383builder.addExtension(spv::E_SPV_AMD_gpu_shader_half_float_fetch);4384builder.addCapability(spv::CapabilityFloat16ImageAMD);4385return builder.makeFloatType(16);4386case glslang::EbtInt64:4387builder.addExtension(spv::E_SPV_EXT_shader_image_int64);4388builder.addCapability(spv::CapabilityInt64ImageEXT);4389return builder.makeIntType(64);4390case glslang::EbtUint64:4391builder.addExtension(spv::E_SPV_EXT_shader_image_int64);4392builder.addCapability(spv::CapabilityInt64ImageEXT);4393return builder.makeUintType(64);4394default:4395assert(0);4396return builder.makeFloatType(32);4397}4398}43994400// If node is a swizzle operation, return the type that should be used if4401// the swizzle base is first consumed by another operation, before the swizzle4402// is applied.4403spv::Id TGlslangToSpvTraverser::getInvertedSwizzleType(const glslang::TIntermTyped& node)4404{4405if (node.getAsOperator() &&4406node.getAsOperator()->getOp() == glslang::EOpVectorSwizzle)4407return convertGlslangToSpvType(node.getAsBinaryNode()->getLeft()->getType());4408else4409return spv::NoType;4410}44114412// When inverting a swizzle with a parent op, this function4413// will apply the swizzle operation to a completed parent operation.4414spv::Id TGlslangToSpvTraverser::createInvertedSwizzle(spv::Decoration precision, const glslang::TIntermTyped& node,4415spv::Id parentResult)4416{4417std::vector<unsigned> swizzle;4418convertSwizzle(*node.getAsBinaryNode()->getRight()->getAsAggregate(), swizzle);4419return builder.createRvalueSwizzle(precision, convertGlslangToSpvType(node.getType()), parentResult, swizzle);4420}44214422// Convert a glslang AST swizzle node to a swizzle vector for building SPIR-V.4423void TGlslangToSpvTraverser::convertSwizzle(const glslang::TIntermAggregate& node, std::vector<unsigned>& swizzle)4424{4425const glslang::TIntermSequence& swizzleSequence = node.getSequence();4426for (int i = 0; i < (int)swizzleSequence.size(); ++i)4427swizzle.push_back(swizzleSequence[i]->getAsConstantUnion()->getConstArray()[0].getIConst());4428}44294430// Convert from a glslang type to an SPV type, by calling into a4431// recursive version of this function. This establishes the inherited4432// layout state rooted from the top-level type.4433spv::Id TGlslangToSpvTraverser::convertGlslangToSpvType(const glslang::TType& type, bool forwardReferenceOnly)4434{4435return convertGlslangToSpvType(type, getExplicitLayout(type), type.getQualifier(), false, forwardReferenceOnly);4436}44374438spv::LinkageType TGlslangToSpvTraverser::convertGlslangLinkageToSpv(glslang::TLinkType linkType)4439{4440switch (linkType) {4441case glslang::ELinkExport:4442return spv::LinkageTypeExport;4443default:4444return spv::LinkageTypeMax;4445}4446}44474448// Do full recursive conversion of an arbitrary glslang type to a SPIR-V Id.4449// explicitLayout can be kept the same throughout the hierarchical recursive walk.4450// Mutually recursive with convertGlslangStructToSpvType().4451spv::Id TGlslangToSpvTraverser::convertGlslangToSpvType(const glslang::TType& type,4452glslang::TLayoutPacking explicitLayout, const glslang::TQualifier& qualifier,4453bool lastBufferBlockMember, bool forwardReferenceOnly)4454{4455spv::Id spvType = spv::NoResult;44564457switch (type.getBasicType()) {4458case glslang::EbtVoid:4459spvType = builder.makeVoidType();4460assert (! type.isArray());4461break;4462case glslang::EbtBool:4463// "transparent" bool doesn't exist in SPIR-V. The GLSL convention is4464// a 32-bit int where non-0 means true.4465if (explicitLayout != glslang::ElpNone)4466spvType = builder.makeUintType(32);4467else4468spvType = builder.makeBoolType();4469break;4470case glslang::EbtInt:4471spvType = builder.makeIntType(32);4472break;4473case glslang::EbtUint:4474spvType = builder.makeUintType(32);4475break;4476case glslang::EbtFloat:4477spvType = builder.makeFloatType(32);4478break;4479case glslang::EbtDouble:4480spvType = builder.makeFloatType(64);4481break;4482case glslang::EbtFloat16:4483spvType = builder.makeFloatType(16);4484break;4485case glslang::EbtInt8:4486spvType = builder.makeIntType(8);4487break;4488case glslang::EbtUint8:4489spvType = builder.makeUintType(8);4490break;4491case glslang::EbtInt16:4492spvType = builder.makeIntType(16);4493break;4494case glslang::EbtUint16:4495spvType = builder.makeUintType(16);4496break;4497case glslang::EbtInt64:4498spvType = builder.makeIntType(64);4499break;4500case glslang::EbtUint64:4501spvType = builder.makeUintType(64);4502break;4503case glslang::EbtAtomicUint:4504builder.addCapability(spv::CapabilityAtomicStorage);4505spvType = builder.makeUintType(32);4506break;4507case glslang::EbtAccStruct:4508switch (glslangIntermediate->getStage()) {4509case EShLangRayGen:4510case EShLangIntersect:4511case EShLangAnyHit:4512case EShLangClosestHit:4513case EShLangMiss:4514case EShLangCallable:4515// these all should have the RayTracingNV/KHR capability already4516break;4517default:4518{4519auto& extensions = glslangIntermediate->getRequestedExtensions();4520if (extensions.find("GL_EXT_ray_query") != extensions.end()) {4521builder.addExtension(spv::E_SPV_KHR_ray_query);4522builder.addCapability(spv::CapabilityRayQueryKHR);4523}4524}4525break;4526}4527spvType = builder.makeAccelerationStructureType();4528break;4529case glslang::EbtRayQuery:4530{4531auto& extensions = glslangIntermediate->getRequestedExtensions();4532if (extensions.find("GL_EXT_ray_query") != extensions.end()) {4533builder.addExtension(spv::E_SPV_KHR_ray_query);4534builder.addCapability(spv::CapabilityRayQueryKHR);4535}4536spvType = builder.makeRayQueryType();4537}4538break;4539case glslang::EbtReference:4540{4541// Make the forward pointer, then recurse to convert the structure type, then4542// patch up the forward pointer with a real pointer type.4543if (forwardPointers.find(type.getReferentType()) == forwardPointers.end()) {4544spv::Id forwardId = builder.makeForwardPointer(spv::StorageClassPhysicalStorageBufferEXT);4545forwardPointers[type.getReferentType()] = forwardId;4546}4547spvType = forwardPointers[type.getReferentType()];4548if (!forwardReferenceOnly) {4549spv::Id referentType = convertGlslangToSpvType(*type.getReferentType());4550builder.makePointerFromForwardPointer(spv::StorageClassPhysicalStorageBufferEXT,4551forwardPointers[type.getReferentType()],4552referentType);4553}4554}4555break;4556case glslang::EbtSampler:4557{4558const glslang::TSampler& sampler = type.getSampler();4559if (sampler.isPureSampler()) {4560spvType = builder.makeSamplerType();4561} else {4562// an image is present, make its type4563spvType = builder.makeImageType(getSampledType(sampler), TranslateDimensionality(sampler),4564sampler.isShadow(), sampler.isArrayed(), sampler.isMultiSample(),4565sampler.isImageClass() ? 2 : 1, TranslateImageFormat(type));4566if (sampler.isCombined() &&4567(!sampler.isBuffer() || glslangIntermediate->getSpv().spv < glslang::EShTargetSpv_1_6)) {4568// Already has both image and sampler, make the combined type. Only combine sampler to4569// buffer if before SPIR-V 1.6.4570spvType = builder.makeSampledImageType(spvType);4571}4572}4573}4574break;4575case glslang::EbtStruct:4576case glslang::EbtBlock:4577{4578// If we've seen this struct type, return it4579const glslang::TTypeList* glslangMembers = type.getStruct();45804581// Try to share structs for different layouts, but not yet for other4582// kinds of qualification (primarily not yet including interpolant qualification).4583if (! HasNonLayoutQualifiers(type, qualifier))4584spvType = structMap[explicitLayout][qualifier.layoutMatrix][glslangMembers];4585if (spvType != spv::NoResult)4586break;45874588// else, we haven't seen it...4589if (type.getBasicType() == glslang::EbtBlock)4590memberRemapper[glslangTypeToIdMap[glslangMembers]].resize(glslangMembers->size());4591spvType = convertGlslangStructToSpvType(type, glslangMembers, explicitLayout, qualifier);4592}4593break;4594case glslang::EbtString:4595// no type used for OpString4596return 0;45974598case glslang::EbtHitObjectNV: {4599builder.addExtension(spv::E_SPV_NV_shader_invocation_reorder);4600builder.addCapability(spv::CapabilityShaderInvocationReorderNV);4601spvType = builder.makeHitObjectNVType();4602}4603break;4604case glslang::EbtSpirvType: {4605// GL_EXT_spirv_intrinsics4606const auto& spirvType = type.getSpirvType();4607const auto& spirvInst = spirvType.spirvInst;46084609std::vector<spv::IdImmediate> operands;4610for (const auto& typeParam : spirvType.typeParams) {4611if (typeParam.getAsConstant() != nullptr) {4612// Constant expression4613auto constant = typeParam.getAsConstant();4614if (constant->isLiteral()) {4615if (constant->getBasicType() == glslang::EbtFloat) {4616float floatValue = static_cast<float>(constant->getConstArray()[0].getDConst());4617unsigned literal;4618static_assert(sizeof(literal) == sizeof(floatValue), "sizeof(unsigned) != sizeof(float)");4619memcpy(&literal, &floatValue, sizeof(literal));4620operands.push_back({false, literal});4621} else if (constant->getBasicType() == glslang::EbtInt) {4622unsigned literal = constant->getConstArray()[0].getIConst();4623operands.push_back({false, literal});4624} else if (constant->getBasicType() == glslang::EbtUint) {4625unsigned literal = constant->getConstArray()[0].getUConst();4626operands.push_back({false, literal});4627} else if (constant->getBasicType() == glslang::EbtBool) {4628unsigned literal = constant->getConstArray()[0].getBConst();4629operands.push_back({false, literal});4630} else if (constant->getBasicType() == glslang::EbtString) {4631auto str = constant->getConstArray()[0].getSConst()->c_str();4632unsigned literal = 0;4633char* literalPtr = reinterpret_cast<char*>(&literal);4634unsigned charCount = 0;4635char ch = 0;4636do {4637ch = *(str++);4638*(literalPtr++) = ch;4639++charCount;4640if (charCount == 4) {4641operands.push_back({false, literal});4642literalPtr = reinterpret_cast<char*>(&literal);4643charCount = 0;4644}4645} while (ch != 0);46464647// Partial literal is padded with 04648if (charCount > 0) {4649for (; charCount < 4; ++charCount)4650*(literalPtr++) = 0;4651operands.push_back({false, literal});4652}4653} else4654assert(0); // Unexpected type4655} else4656operands.push_back({true, createSpvConstant(*constant)});4657} else {4658// Type specifier4659assert(typeParam.getAsType() != nullptr);4660operands.push_back({true, convertGlslangToSpvType(*typeParam.getAsType())});4661}4662}46634664assert(spirvInst.set == ""); // Currently, couldn't be extended instructions.4665spvType = builder.makeGenericType(static_cast<spv::Op>(spirvInst.id), operands);46664667break;4668}4669default:4670assert(0);4671break;4672}46734674if (type.isMatrix())4675spvType = builder.makeMatrixType(spvType, type.getMatrixCols(), type.getMatrixRows());4676else {4677// If this variable has a vector element count greater than 1, create a SPIR-V vector4678if (type.getVectorSize() > 1)4679spvType = builder.makeVectorType(spvType, type.getVectorSize());4680}46814682if (type.isCoopMatNV()) {4683builder.addCapability(spv::CapabilityCooperativeMatrixNV);4684builder.addExtension(spv::E_SPV_NV_cooperative_matrix);46854686if (type.getBasicType() == glslang::EbtFloat16)4687builder.addCapability(spv::CapabilityFloat16);4688if (type.getBasicType() == glslang::EbtUint8 ||4689type.getBasicType() == glslang::EbtInt8) {4690builder.addCapability(spv::CapabilityInt8);4691}46924693spv::Id scope = makeArraySizeId(*type.getTypeParameters()->arraySizes, 1);4694spv::Id rows = makeArraySizeId(*type.getTypeParameters()->arraySizes, 2);4695spv::Id cols = makeArraySizeId(*type.getTypeParameters()->arraySizes, 3);46964697spvType = builder.makeCooperativeMatrixTypeNV(spvType, scope, rows, cols);4698}46994700if (type.isCoopMatKHR()) {4701builder.addCapability(spv::CapabilityCooperativeMatrixKHR);4702builder.addExtension(spv::E_SPV_KHR_cooperative_matrix);47034704if (type.getBasicType() == glslang::EbtFloat16)4705builder.addCapability(spv::CapabilityFloat16);4706if (type.getBasicType() == glslang::EbtUint8 || type.getBasicType() == glslang::EbtInt8) {4707builder.addCapability(spv::CapabilityInt8);4708}47094710spv::Id scope = makeArraySizeId(*type.getTypeParameters()->arraySizes, 0);4711spv::Id rows = makeArraySizeId(*type.getTypeParameters()->arraySizes, 1);4712spv::Id cols = makeArraySizeId(*type.getTypeParameters()->arraySizes, 2);4713spv::Id use = builder.makeUintConstant(type.getCoopMatKHRuse());47144715spvType = builder.makeCooperativeMatrixTypeKHR(spvType, scope, rows, cols, use);4716}47174718if (type.isArray()) {4719int stride = 0; // keep this 0 unless doing an explicit layout; 0 will mean no decoration, no stride47204721// Do all but the outer dimension4722if (type.getArraySizes()->getNumDims() > 1) {4723// We need to decorate array strides for types needing explicit layout, except blocks.4724if (explicitLayout != glslang::ElpNone && type.getBasicType() != glslang::EbtBlock) {4725// Use a dummy glslang type for querying internal strides of4726// arrays of arrays, but using just a one-dimensional array.4727glslang::TType simpleArrayType(type, 0); // deference type of the array4728while (simpleArrayType.getArraySizes()->getNumDims() > 1)4729simpleArrayType.getArraySizes()->dereference();47304731// Will compute the higher-order strides here, rather than making a whole4732// pile of types and doing repetitive recursion on their contents.4733stride = getArrayStride(simpleArrayType, explicitLayout, qualifier.layoutMatrix);4734}47354736// make the arrays4737for (int dim = type.getArraySizes()->getNumDims() - 1; dim > 0; --dim) {4738spvType = builder.makeArrayType(spvType, makeArraySizeId(*type.getArraySizes(), dim), stride);4739if (stride > 0)4740builder.addDecoration(spvType, spv::DecorationArrayStride, stride);4741stride *= type.getArraySizes()->getDimSize(dim);4742}4743} else {4744// single-dimensional array, and don't yet have stride47454746// We need to decorate array strides for types needing explicit layout, except blocks.4747if (explicitLayout != glslang::ElpNone && type.getBasicType() != glslang::EbtBlock)4748stride = getArrayStride(type, explicitLayout, qualifier.layoutMatrix);4749}47504751// Do the outer dimension, which might not be known for a runtime-sized array.4752// (Unsized arrays that survive through linking will be runtime-sized arrays)4753if (type.isSizedArray())4754spvType = builder.makeArrayType(spvType, makeArraySizeId(*type.getArraySizes(), 0), stride);4755else {4756if (!lastBufferBlockMember) {4757builder.addIncorporatedExtension("SPV_EXT_descriptor_indexing", spv::Spv_1_5);4758builder.addCapability(spv::CapabilityRuntimeDescriptorArrayEXT);4759}4760spvType = builder.makeRuntimeArray(spvType);4761}4762if (stride > 0)4763builder.addDecoration(spvType, spv::DecorationArrayStride, stride);4764}47654766return spvType;4767}47684769// Apply SPIR-V decorations to the SPIR-V object (provided by SPIR-V ID). If member index is provided, the4770// decorations are applied to this member.4771void TGlslangToSpvTraverser::applySpirvDecorate(const glslang::TType& type, spv::Id id, std::optional<int> member)4772{4773assert(type.getQualifier().hasSpirvDecorate());47744775const glslang::TSpirvDecorate& spirvDecorate = type.getQualifier().getSpirvDecorate();47764777// Add spirv_decorate4778for (auto& decorate : spirvDecorate.decorates) {4779if (!decorate.second.empty()) {4780std::vector<unsigned> literals;4781TranslateLiterals(decorate.second, literals);4782if (member.has_value())4783builder.addMemberDecoration(id, *member, static_cast<spv::Decoration>(decorate.first), literals);4784else4785builder.addDecoration(id, static_cast<spv::Decoration>(decorate.first), literals);4786} else {4787if (member.has_value())4788builder.addMemberDecoration(id, *member, static_cast<spv::Decoration>(decorate.first));4789else4790builder.addDecoration(id, static_cast<spv::Decoration>(decorate.first));4791}4792}47934794// Add spirv_decorate_id4795if (member.has_value()) {4796// spirv_decorate_id not applied to members4797assert(spirvDecorate.decorateIds.empty());4798} else {4799for (auto& decorateId : spirvDecorate.decorateIds) {4800std::vector<spv::Id> operandIds;4801assert(!decorateId.second.empty());4802for (auto extraOperand : decorateId.second) {4803if (extraOperand->getQualifier().isFrontEndConstant())4804operandIds.push_back(createSpvConstant(*extraOperand));4805else4806operandIds.push_back(getSymbolId(extraOperand->getAsSymbolNode()));4807}4808builder.addDecorationId(id, static_cast<spv::Decoration>(decorateId.first), operandIds);4809}4810}48114812// Add spirv_decorate_string4813for (auto& decorateString : spirvDecorate.decorateStrings) {4814std::vector<const char*> strings;4815assert(!decorateString.second.empty());4816for (auto extraOperand : decorateString.second) {4817const char* string = extraOperand->getConstArray()[0].getSConst()->c_str();4818strings.push_back(string);4819}4820if (member.has_value())4821builder.addMemberDecoration(id, *member, static_cast<spv::Decoration>(decorateString.first), strings);4822else4823builder.addDecoration(id, static_cast<spv::Decoration>(decorateString.first), strings);4824}4825}48264827// TODO: this functionality should exist at a higher level, in creating the AST4828//4829// Identify interface members that don't have their required extension turned on.4830//4831bool TGlslangToSpvTraverser::filterMember(const glslang::TType& member)4832{4833auto& extensions = glslangIntermediate->getRequestedExtensions();48344835if (member.getFieldName() == "gl_SecondaryViewportMaskNV" &&4836extensions.find("GL_NV_stereo_view_rendering") == extensions.end())4837return true;4838if (member.getFieldName() == "gl_SecondaryPositionNV" &&4839extensions.find("GL_NV_stereo_view_rendering") == extensions.end())4840return true;48414842if (glslangIntermediate->getStage() == EShLangMesh) {4843if (member.getFieldName() == "gl_PrimitiveShadingRateEXT" &&4844extensions.find("GL_EXT_fragment_shading_rate") == extensions.end())4845return true;4846}48474848if (glslangIntermediate->getStage() != EShLangMesh) {4849if (member.getFieldName() == "gl_ViewportMask" &&4850extensions.find("GL_NV_viewport_array2") == extensions.end())4851return true;4852if (member.getFieldName() == "gl_PositionPerViewNV" &&4853extensions.find("GL_NVX_multiview_per_view_attributes") == extensions.end())4854return true;4855if (member.getFieldName() == "gl_ViewportMaskPerViewNV" &&4856extensions.find("GL_NVX_multiview_per_view_attributes") == extensions.end())4857return true;4858}48594860return false;4861};48624863// Do full recursive conversion of a glslang structure (or block) type to a SPIR-V Id.4864// explicitLayout can be kept the same throughout the hierarchical recursive walk.4865// Mutually recursive with convertGlslangToSpvType().4866spv::Id TGlslangToSpvTraverser::convertGlslangStructToSpvType(const glslang::TType& type,4867const glslang::TTypeList* glslangMembers,4868glslang::TLayoutPacking explicitLayout,4869const glslang::TQualifier& qualifier)4870{4871// Create a vector of struct types for SPIR-V to consume4872std::vector<spv::Id> spvMembers;4873int memberDelta = 0; // how much the member's index changes from glslang to SPIR-V, normally 0,4874// except sometimes for blocks4875std::vector<std::pair<glslang::TType*, glslang::TQualifier> > deferredForwardPointers;4876for (int i = 0; i < (int)glslangMembers->size(); i++) {4877auto& glslangMember = (*glslangMembers)[i];4878if (glslangMember.type->hiddenMember()) {4879++memberDelta;4880if (type.getBasicType() == glslang::EbtBlock)4881memberRemapper[glslangTypeToIdMap[glslangMembers]][i] = -1;4882} else {4883if (type.getBasicType() == glslang::EbtBlock) {4884if (filterMember(*glslangMember.type)) {4885memberDelta++;4886memberRemapper[glslangTypeToIdMap[glslangMembers]][i] = -1;4887continue;4888}4889memberRemapper[glslangTypeToIdMap[glslangMembers]][i] = i - memberDelta;4890}4891// modify just this child's view of the qualifier4892glslang::TQualifier memberQualifier = glslangMember.type->getQualifier();4893InheritQualifiers(memberQualifier, qualifier);48944895// manually inherit location4896if (! memberQualifier.hasLocation() && qualifier.hasLocation())4897memberQualifier.layoutLocation = qualifier.layoutLocation;48984899// recurse4900bool lastBufferBlockMember = qualifier.storage == glslang::EvqBuffer &&4901i == (int)glslangMembers->size() - 1;49024903// Make forward pointers for any pointer members.4904if (glslangMember.type->isReference() &&4905forwardPointers.find(glslangMember.type->getReferentType()) == forwardPointers.end()) {4906deferredForwardPointers.push_back(std::make_pair(glslangMember.type, memberQualifier));4907}49084909// Create the member type.4910auto const spvMember = convertGlslangToSpvType(*glslangMember.type, explicitLayout, memberQualifier, lastBufferBlockMember,4911glslangMember.type->isReference());4912spvMembers.push_back(spvMember);49134914// Update the builder with the type's location so that we can create debug types for the structure members.4915// There doesn't exist a "clean" entry point for this information to be passed along to the builder so, for now,4916// it is stored in the builder and consumed during the construction of composite debug types.4917// TODO: This probably warrants further investigation. This approach was decided to be the least ugly of the4918// quick and dirty approaches that were tried.4919// Advantages of this approach:4920// + Relatively clean. No direct calls into debug type system.4921// + Handles nested recursive structures.4922// Disadvantages of this approach:4923// + Not as clean as desired. Traverser queries/sets persistent state. This is fragile.4924// + Table lookup during creation of composite debug types. This really shouldn't be necessary.4925if(options.emitNonSemanticShaderDebugInfo) {4926builder.debugTypeLocs[spvMember].name = glslangMember.type->getFieldName().c_str();4927builder.debugTypeLocs[spvMember].line = glslangMember.loc.line;4928builder.debugTypeLocs[spvMember].column = glslangMember.loc.column;4929}4930}4931}49324933// Make the SPIR-V type4934spv::Id spvType = builder.makeStructType(spvMembers, type.getTypeName().c_str(), false);4935if (! HasNonLayoutQualifiers(type, qualifier))4936structMap[explicitLayout][qualifier.layoutMatrix][glslangMembers] = spvType;49374938// Decorate it4939decorateStructType(type, glslangMembers, explicitLayout, qualifier, spvType, spvMembers);49404941for (int i = 0; i < (int)deferredForwardPointers.size(); ++i) {4942auto it = deferredForwardPointers[i];4943convertGlslangToSpvType(*it.first, explicitLayout, it.second, false);4944}49454946return spvType;4947}49484949void TGlslangToSpvTraverser::decorateStructType(const glslang::TType& type,4950const glslang::TTypeList* glslangMembers,4951glslang::TLayoutPacking explicitLayout,4952const glslang::TQualifier& qualifier,4953spv::Id spvType,4954const std::vector<spv::Id>& spvMembers)4955{4956// Name and decorate the non-hidden members4957int offset = -1;4958bool memberLocationInvalid = type.isArrayOfArrays() ||4959(type.isArray() && (type.getQualifier().isArrayedIo(glslangIntermediate->getStage()) == false));4960for (int i = 0; i < (int)glslangMembers->size(); i++) {4961glslang::TType& glslangMember = *(*glslangMembers)[i].type;4962int member = i;4963if (type.getBasicType() == glslang::EbtBlock) {4964member = memberRemapper[glslangTypeToIdMap[glslangMembers]][i];4965if (filterMember(glslangMember))4966continue;4967}49684969// modify just this child's view of the qualifier4970glslang::TQualifier memberQualifier = glslangMember.getQualifier();4971InheritQualifiers(memberQualifier, qualifier);49724973// using -1 above to indicate a hidden member4974if (member < 0)4975continue;49764977builder.addMemberName(spvType, member, glslangMember.getFieldName().c_str());4978builder.addMemberDecoration(spvType, member,4979TranslateLayoutDecoration(glslangMember, memberQualifier.layoutMatrix));4980builder.addMemberDecoration(spvType, member, TranslatePrecisionDecoration(glslangMember));4981// Add interpolation and auxiliary storage decorations only to4982// top-level members of Input and Output storage classes4983if (type.getQualifier().storage == glslang::EvqVaryingIn ||4984type.getQualifier().storage == glslang::EvqVaryingOut) {4985if (type.getBasicType() == glslang::EbtBlock ||4986glslangIntermediate->getSource() == glslang::EShSourceHlsl) {4987builder.addMemberDecoration(spvType, member, TranslateInterpolationDecoration(memberQualifier));4988builder.addMemberDecoration(spvType, member, TranslateAuxiliaryStorageDecoration(memberQualifier));4989addMeshNVDecoration(spvType, member, memberQualifier);4990}4991}4992builder.addMemberDecoration(spvType, member, TranslateInvariantDecoration(memberQualifier));49934994if (type.getBasicType() == glslang::EbtBlock &&4995qualifier.storage == glslang::EvqBuffer) {4996// Add memory decorations only to top-level members of shader storage block4997std::vector<spv::Decoration> memory;4998TranslateMemoryDecoration(memberQualifier, memory, glslangIntermediate->usingVulkanMemoryModel());4999for (unsigned int i = 0; i < memory.size(); ++i)5000builder.addMemberDecoration(spvType, member, memory[i]);5001}50025003// Location assignment was already completed correctly by the front end,5004// just track whether a member needs to be decorated.5005// Ignore member locations if the container is an array, as that's5006// ill-specified and decisions have been made to not allow this.5007if (!memberLocationInvalid && memberQualifier.hasLocation())5008builder.addMemberDecoration(spvType, member, spv::DecorationLocation, memberQualifier.layoutLocation);50095010// component, XFB, others5011if (glslangMember.getQualifier().hasComponent())5012builder.addMemberDecoration(spvType, member, spv::DecorationComponent,5013glslangMember.getQualifier().layoutComponent);5014if (glslangMember.getQualifier().hasXfbOffset())5015builder.addMemberDecoration(spvType, member, spv::DecorationOffset,5016glslangMember.getQualifier().layoutXfbOffset);5017else if (explicitLayout != glslang::ElpNone) {5018// figure out what to do with offset, which is accumulating5019int nextOffset;5020updateMemberOffset(type, glslangMember, offset, nextOffset, explicitLayout, memberQualifier.layoutMatrix);5021if (offset >= 0)5022builder.addMemberDecoration(spvType, member, spv::DecorationOffset, offset);5023offset = nextOffset;5024}50255026if (glslangMember.isMatrix() && explicitLayout != glslang::ElpNone)5027builder.addMemberDecoration(spvType, member, spv::DecorationMatrixStride,5028getMatrixStride(glslangMember, explicitLayout, memberQualifier.layoutMatrix));50295030// built-in variable decorations5031spv::BuiltIn builtIn = TranslateBuiltInDecoration(glslangMember.getQualifier().builtIn, true);5032if (builtIn != spv::BuiltInMax)5033builder.addMemberDecoration(spvType, member, spv::DecorationBuiltIn, (int)builtIn);50345035// nonuniform5036builder.addMemberDecoration(spvType, member, TranslateNonUniformDecoration(glslangMember.getQualifier()));50375038if (glslangIntermediate->getHlslFunctionality1() && memberQualifier.semanticName != nullptr) {5039builder.addExtension("SPV_GOOGLE_hlsl_functionality1");5040builder.addMemberDecoration(spvType, member, (spv::Decoration)spv::DecorationHlslSemanticGOOGLE,5041memberQualifier.semanticName);5042}50435044if (builtIn == spv::BuiltInLayer) {5045// SPV_NV_viewport_array2 extension5046if (glslangMember.getQualifier().layoutViewportRelative){5047builder.addMemberDecoration(spvType, member, (spv::Decoration)spv::DecorationViewportRelativeNV);5048builder.addCapability(spv::CapabilityShaderViewportMaskNV);5049builder.addExtension(spv::E_SPV_NV_viewport_array2);5050}5051if (glslangMember.getQualifier().layoutSecondaryViewportRelativeOffset != -2048){5052builder.addMemberDecoration(spvType, member,5053(spv::Decoration)spv::DecorationSecondaryViewportRelativeNV,5054glslangMember.getQualifier().layoutSecondaryViewportRelativeOffset);5055builder.addCapability(spv::CapabilityShaderStereoViewNV);5056builder.addExtension(spv::E_SPV_NV_stereo_view_rendering);5057}5058}5059if (glslangMember.getQualifier().layoutPassthrough) {5060builder.addMemberDecoration(spvType, member, (spv::Decoration)spv::DecorationPassthroughNV);5061builder.addCapability(spv::CapabilityGeometryShaderPassthroughNV);5062builder.addExtension(spv::E_SPV_NV_geometry_shader_passthrough);5063}50645065// Add SPIR-V decorations (GL_EXT_spirv_intrinsics)5066if (glslangMember.getQualifier().hasSpirvDecorate())5067applySpirvDecorate(glslangMember, spvType, member);5068}50695070// Decorate the structure5071builder.addDecoration(spvType, TranslateLayoutDecoration(type, qualifier.layoutMatrix));5072const auto basicType = type.getBasicType();5073const auto typeStorageQualifier = type.getQualifier().storage;5074if (basicType == glslang::EbtBlock) {5075builder.addDecoration(spvType, TranslateBlockDecoration(typeStorageQualifier, glslangIntermediate->usingStorageBuffer()));5076} else if (basicType == glslang::EbtStruct && glslangIntermediate->getSpv().vulkan > 0) {5077const auto hasRuntimeArray = !spvMembers.empty() && builder.getOpCode(spvMembers.back()) == spv::OpTypeRuntimeArray;5078if (hasRuntimeArray) {5079builder.addDecoration(spvType, TranslateBlockDecoration(typeStorageQualifier, glslangIntermediate->usingStorageBuffer()));5080}5081}50825083if (qualifier.hasHitObjectShaderRecordNV())5084builder.addDecoration(spvType, spv::DecorationHitObjectShaderRecordBufferNV);5085}50865087// Turn the expression forming the array size into an id.5088// This is not quite trivial, because of specialization constants.5089// Sometimes, a raw constant is turned into an Id, and sometimes5090// a specialization constant expression is.5091spv::Id TGlslangToSpvTraverser::makeArraySizeId(const glslang::TArraySizes& arraySizes, int dim, bool allowZero)5092{5093// First, see if this is sized with a node, meaning a specialization constant:5094glslang::TIntermTyped* specNode = arraySizes.getDimNode(dim);5095if (specNode != nullptr) {5096builder.clearAccessChain();5097SpecConstantOpModeGuard spec_constant_op_mode_setter(&builder);5098spec_constant_op_mode_setter.turnOnSpecConstantOpMode();5099specNode->traverse(this);5100return accessChainLoad(specNode->getAsTyped()->getType());5101}51025103// Otherwise, need a compile-time (front end) size, get it:5104int size = arraySizes.getDimSize(dim);51055106if (!allowZero)5107assert(size > 0);51085109return builder.makeUintConstant(size);5110}51115112// Wrap the builder's accessChainLoad to:5113// - localize handling of RelaxedPrecision5114// - use the SPIR-V inferred type instead of another conversion of the glslang type5115// (avoids unnecessary work and possible type punning for structures)5116// - do conversion of concrete to abstract type5117spv::Id TGlslangToSpvTraverser::accessChainLoad(const glslang::TType& type)5118{5119spv::Id nominalTypeId = builder.accessChainGetInferredType();51205121spv::Builder::AccessChain::CoherentFlags coherentFlags = builder.getAccessChain().coherentFlags;5122coherentFlags |= TranslateCoherent(type);51235124spv::MemoryAccessMask accessMask = spv::MemoryAccessMask(TranslateMemoryAccess(coherentFlags) & ~spv::MemoryAccessMakePointerAvailableKHRMask);5125// If the value being loaded is HelperInvocation, SPIR-V 1.6 is being generated (so that5126// SPV_EXT_demote_to_helper_invocation is in core) and the memory model is in use, add5127// the Volatile MemoryAccess semantic.5128if (type.getQualifier().builtIn == glslang::EbvHelperInvocation &&5129glslangIntermediate->usingVulkanMemoryModel() &&5130glslangIntermediate->getSpv().spv >= glslang::EShTargetSpv_1_6) {5131accessMask = spv::MemoryAccessMask(accessMask | spv::MemoryAccessVolatileMask);5132}51335134unsigned int alignment = builder.getAccessChain().alignment;5135alignment |= type.getBufferReferenceAlignment();51365137spv::Id loadedId = builder.accessChainLoad(TranslatePrecisionDecoration(type),5138TranslateNonUniformDecoration(builder.getAccessChain().coherentFlags),5139TranslateNonUniformDecoration(type.getQualifier()),5140nominalTypeId,5141accessMask,5142TranslateMemoryScope(coherentFlags),5143alignment);51445145// Need to convert to abstract types when necessary5146if (type.getBasicType() == glslang::EbtBool) {5147loadedId = convertLoadedBoolInUniformToUint(type, nominalTypeId, loadedId);5148}51495150return loadedId;5151}51525153// Wrap the builder's accessChainStore to:5154// - do conversion of concrete to abstract type5155//5156// Implicitly uses the existing builder.accessChain as the storage target.5157void TGlslangToSpvTraverser::accessChainStore(const glslang::TType& type, spv::Id rvalue)5158{5159// Need to convert to abstract types when necessary5160if (type.getBasicType() == glslang::EbtBool) {5161spv::Id nominalTypeId = builder.accessChainGetInferredType();51625163if (builder.isScalarType(nominalTypeId)) {5164// Conversion for bool5165spv::Id boolType = builder.makeBoolType();5166if (nominalTypeId != boolType) {5167// keep these outside arguments, for determinant order-of-evaluation5168spv::Id one = builder.makeUintConstant(1);5169spv::Id zero = builder.makeUintConstant(0);5170rvalue = builder.createTriOp(spv::OpSelect, nominalTypeId, rvalue, one, zero);5171} else if (builder.getTypeId(rvalue) != boolType)5172rvalue = builder.createBinOp(spv::OpINotEqual, boolType, rvalue, builder.makeUintConstant(0));5173} else if (builder.isVectorType(nominalTypeId)) {5174// Conversion for bvec5175int vecSize = builder.getNumTypeComponents(nominalTypeId);5176spv::Id bvecType = builder.makeVectorType(builder.makeBoolType(), vecSize);5177if (nominalTypeId != bvecType) {5178// keep these outside arguments, for determinant order-of-evaluation5179spv::Id one = makeSmearedConstant(builder.makeUintConstant(1), vecSize);5180spv::Id zero = makeSmearedConstant(builder.makeUintConstant(0), vecSize);5181rvalue = builder.createTriOp(spv::OpSelect, nominalTypeId, rvalue, one, zero);5182} else if (builder.getTypeId(rvalue) != bvecType)5183rvalue = builder.createBinOp(spv::OpINotEqual, bvecType, rvalue,5184makeSmearedConstant(builder.makeUintConstant(0), vecSize));5185}5186}51875188spv::Builder::AccessChain::CoherentFlags coherentFlags = builder.getAccessChain().coherentFlags;5189coherentFlags |= TranslateCoherent(type);51905191unsigned int alignment = builder.getAccessChain().alignment;5192alignment |= type.getBufferReferenceAlignment();51935194builder.accessChainStore(rvalue, TranslateNonUniformDecoration(builder.getAccessChain().coherentFlags),5195spv::MemoryAccessMask(TranslateMemoryAccess(coherentFlags) &5196~spv::MemoryAccessMakePointerVisibleKHRMask),5197TranslateMemoryScope(coherentFlags), alignment);5198}51995200// For storing when types match at the glslang level, but not might match at the5201// SPIR-V level.5202//5203// This especially happens when a single glslang type expands to multiple5204// SPIR-V types, like a struct that is used in a member-undecorated way as well5205// as in a member-decorated way.5206//5207// NOTE: This function can handle any store request; if it's not special it5208// simplifies to a simple OpStore.5209//5210// Implicitly uses the existing builder.accessChain as the storage target.5211void TGlslangToSpvTraverser::multiTypeStore(const glslang::TType& type, spv::Id rValue)5212{5213// we only do the complex path here if it's an aggregate5214if (! type.isStruct() && ! type.isArray()) {5215accessChainStore(type, rValue);5216return;5217}52185219// and, it has to be a case of type aliasing5220spv::Id rType = builder.getTypeId(rValue);5221spv::Id lValue = builder.accessChainGetLValue();5222spv::Id lType = builder.getContainedTypeId(builder.getTypeId(lValue));5223if (lType == rType) {5224accessChainStore(type, rValue);5225return;5226}52275228// Recursively (as needed) copy an aggregate type to a different aggregate type,5229// where the two types were the same type in GLSL. This requires member5230// by member copy, recursively.52315232// SPIR-V 1.4 added an instruction to do help do this.5233if (glslangIntermediate->getSpv().spv >= glslang::EShTargetSpv_1_4) {5234// However, bool in uniform space is changed to int, so5235// OpCopyLogical does not work for that.5236// TODO: It would be more robust to do a full recursive verification of the types satisfying SPIR-V rules.5237bool rBool = builder.containsType(builder.getTypeId(rValue), spv::OpTypeBool, 0);5238bool lBool = builder.containsType(lType, spv::OpTypeBool, 0);5239if (lBool == rBool) {5240spv::Id logicalCopy = builder.createUnaryOp(spv::OpCopyLogical, lType, rValue);5241accessChainStore(type, logicalCopy);5242return;5243}5244}52455246// If an array, copy element by element.5247if (type.isArray()) {5248glslang::TType glslangElementType(type, 0);5249spv::Id elementRType = builder.getContainedTypeId(rType);5250for (int index = 0; index < type.getOuterArraySize(); ++index) {5251// get the source member5252spv::Id elementRValue = builder.createCompositeExtract(rValue, elementRType, index);52535254// set up the target storage5255builder.clearAccessChain();5256builder.setAccessChainLValue(lValue);5257builder.accessChainPush(builder.makeIntConstant(index), TranslateCoherent(type),5258type.getBufferReferenceAlignment());52595260// store the member5261multiTypeStore(glslangElementType, elementRValue);5262}5263} else {5264assert(type.isStruct());52655266// loop over structure members5267const glslang::TTypeList& members = *type.getStruct();5268for (int m = 0; m < (int)members.size(); ++m) {5269const glslang::TType& glslangMemberType = *members[m].type;52705271// get the source member5272spv::Id memberRType = builder.getContainedTypeId(rType, m);5273spv::Id memberRValue = builder.createCompositeExtract(rValue, memberRType, m);52745275// set up the target storage5276builder.clearAccessChain();5277builder.setAccessChainLValue(lValue);5278builder.accessChainPush(builder.makeIntConstant(m), TranslateCoherent(type),5279type.getBufferReferenceAlignment());52805281// store the member5282multiTypeStore(glslangMemberType, memberRValue);5283}5284}5285}52865287// Decide whether or not this type should be5288// decorated with offsets and strides, and if so5289// whether std140 or std430 rules should be applied.5290glslang::TLayoutPacking TGlslangToSpvTraverser::getExplicitLayout(const glslang::TType& type) const5291{5292// has to be a block5293if (type.getBasicType() != glslang::EbtBlock)5294return glslang::ElpNone;52955296// has to be a uniform or buffer block or task in/out blocks5297if (type.getQualifier().storage != glslang::EvqUniform &&5298type.getQualifier().storage != glslang::EvqBuffer &&5299type.getQualifier().storage != glslang::EvqShared &&5300!type.getQualifier().isTaskMemory())5301return glslang::ElpNone;53025303// return the layout to use5304switch (type.getQualifier().layoutPacking) {5305case glslang::ElpStd140:5306case glslang::ElpStd430:5307case glslang::ElpScalar:5308return type.getQualifier().layoutPacking;5309default:5310return glslang::ElpNone;5311}5312}53135314// Given an array type, returns the integer stride required for that array5315int TGlslangToSpvTraverser::getArrayStride(const glslang::TType& arrayType, glslang::TLayoutPacking explicitLayout,5316glslang::TLayoutMatrix matrixLayout)5317{5318int size;5319int stride;5320glslangIntermediate->getMemberAlignment(arrayType, size, stride, explicitLayout,5321matrixLayout == glslang::ElmRowMajor);53225323return stride;5324}53255326// Given a matrix type, or array (of array) of matrixes type, returns the integer stride required for that matrix5327// when used as a member of an interface block5328int TGlslangToSpvTraverser::getMatrixStride(const glslang::TType& matrixType, glslang::TLayoutPacking explicitLayout,5329glslang::TLayoutMatrix matrixLayout)5330{5331glslang::TType elementType;5332elementType.shallowCopy(matrixType);5333elementType.clearArraySizes();53345335int size;5336int stride;5337glslangIntermediate->getMemberAlignment(elementType, size, stride, explicitLayout,5338matrixLayout == glslang::ElmRowMajor);53395340return stride;5341}53425343// Given a member type of a struct, realign the current offset for it, and compute5344// the next (not yet aligned) offset for the next member, which will get aligned5345// on the next call.5346// 'currentOffset' should be passed in already initialized, ready to modify, and reflecting5347// the migration of data from nextOffset -> currentOffset. It should be -1 on the first call.5348// -1 means a non-forced member offset (no decoration needed).5349void TGlslangToSpvTraverser::updateMemberOffset(const glslang::TType& structType, const glslang::TType& memberType,5350int& currentOffset, int& nextOffset, glslang::TLayoutPacking explicitLayout, glslang::TLayoutMatrix matrixLayout)5351{5352// this will get a positive value when deemed necessary5353nextOffset = -1;53545355// override anything in currentOffset with user-set offset5356if (memberType.getQualifier().hasOffset())5357currentOffset = memberType.getQualifier().layoutOffset;53585359// It could be that current linker usage in glslang updated all the layoutOffset,5360// in which case the following code does not matter. But, that's not quite right5361// once cross-compilation unit GLSL validation is done, as the original user5362// settings are needed in layoutOffset, and then the following will come into play.53635364if (explicitLayout == glslang::ElpNone) {5365if (! memberType.getQualifier().hasOffset())5366currentOffset = -1;53675368return;5369}53705371// Getting this far means we need explicit offsets5372if (currentOffset < 0)5373currentOffset = 0;53745375// Now, currentOffset is valid (either 0, or from a previous nextOffset),5376// but possibly not yet correctly aligned.53775378int memberSize;5379int dummyStride;5380int memberAlignment = glslangIntermediate->getMemberAlignment(memberType, memberSize, dummyStride, explicitLayout,5381matrixLayout == glslang::ElmRowMajor);53825383bool isVectorLike = memberType.isVector();5384if (memberType.isMatrix()) {5385if (matrixLayout == glslang::ElmRowMajor)5386isVectorLike = memberType.getMatrixRows() == 1;5387else5388isVectorLike = memberType.getMatrixCols() == 1;5389}53905391// Adjust alignment for HLSL rules5392// TODO: make this consistent in early phases of code:5393// adjusting this late means inconsistencies with earlier code, which for reflection is an issue5394// Until reflection is brought in sync with these adjustments, don't apply to $Global,5395// which is the most likely to rely on reflection, and least likely to rely implicit layouts5396if (glslangIntermediate->usingHlslOffsets() &&5397! memberType.isStruct() && structType.getTypeName().compare("$Global") != 0) {5398int componentSize;5399int componentAlignment = glslangIntermediate->getBaseAlignmentScalar(memberType, componentSize);5400if (! memberType.isArray() && isVectorLike && componentAlignment <= 4)5401memberAlignment = componentAlignment;54025403// Don't add unnecessary padding after this member5404if (memberType.isMatrix()) {5405if (matrixLayout == glslang::ElmRowMajor)5406memberSize -= componentSize * (4 - memberType.getMatrixCols());5407else5408memberSize -= componentSize * (4 - memberType.getMatrixRows());5409} else if (memberType.isArray())5410memberSize -= componentSize * (4 - memberType.getVectorSize());5411}54125413// Bump up to member alignment5414glslang::RoundToPow2(currentOffset, memberAlignment);54155416// Bump up to vec4 if there is a bad straddle5417if (explicitLayout != glslang::ElpScalar && glslangIntermediate->improperStraddle(memberType, memberSize,5418currentOffset, isVectorLike))5419glslang::RoundToPow2(currentOffset, 16);54205421nextOffset = currentOffset + memberSize;5422}54235424void TGlslangToSpvTraverser::declareUseOfStructMember(const glslang::TTypeList& members, int glslangMember)5425{5426const glslang::TBuiltInVariable glslangBuiltIn = members[glslangMember].type->getQualifier().builtIn;5427switch (glslangBuiltIn)5428{5429case glslang::EbvPointSize:5430case glslang::EbvClipDistance:5431case glslang::EbvCullDistance:5432case glslang::EbvViewportMaskNV:5433case glslang::EbvSecondaryPositionNV:5434case glslang::EbvSecondaryViewportMaskNV:5435case glslang::EbvPositionPerViewNV:5436case glslang::EbvViewportMaskPerViewNV:5437case glslang::EbvTaskCountNV:5438case glslang::EbvPrimitiveCountNV:5439case glslang::EbvPrimitiveIndicesNV:5440case glslang::EbvClipDistancePerViewNV:5441case glslang::EbvCullDistancePerViewNV:5442case glslang::EbvLayerPerViewNV:5443case glslang::EbvMeshViewCountNV:5444case glslang::EbvMeshViewIndicesNV:5445// Generate the associated capability. Delegate to TranslateBuiltInDecoration.5446// Alternately, we could just call this for any glslang built-in, since the5447// capability already guards against duplicates.5448TranslateBuiltInDecoration(glslangBuiltIn, false);5449break;5450default:5451// Capabilities were already generated when the struct was declared.5452break;5453}5454}54555456bool TGlslangToSpvTraverser::isShaderEntryPoint(const glslang::TIntermAggregate* node)5457{5458return node->getName().compare(glslangIntermediate->getEntryPointMangledName().c_str()) == 0;5459}54605461// Does parameter need a place to keep writes, separate from the original?5462// Assumes called after originalParam(), which filters out block/buffer/opaque-based5463// qualifiers such that we should have only in/out/inout/constreadonly here.5464bool TGlslangToSpvTraverser::writableParam(glslang::TStorageQualifier qualifier) const5465{5466assert(qualifier == glslang::EvqIn ||5467qualifier == glslang::EvqOut ||5468qualifier == glslang::EvqInOut ||5469qualifier == glslang::EvqUniform ||5470qualifier == glslang::EvqConstReadOnly);5471return qualifier != glslang::EvqConstReadOnly &&5472qualifier != glslang::EvqUniform;5473}54745475// Is parameter pass-by-original?5476bool TGlslangToSpvTraverser::originalParam(glslang::TStorageQualifier qualifier, const glslang::TType& paramType,5477bool implicitThisParam)5478{5479if (implicitThisParam) // implicit this5480return true;5481if (glslangIntermediate->getSource() == glslang::EShSourceHlsl)5482return paramType.getBasicType() == glslang::EbtBlock;5483return (paramType.containsOpaque() && !glslangIntermediate->getBindlessMode()) || // sampler, etc.5484paramType.getQualifier().isSpirvByReference() || // spirv_by_reference5485(paramType.getBasicType() == glslang::EbtBlock && qualifier == glslang::EvqBuffer); // SSBO5486}54875488// Make all the functions, skeletally, without actually visiting their bodies.5489void TGlslangToSpvTraverser::makeFunctions(const glslang::TIntermSequence& glslFunctions)5490{5491const auto getParamDecorations = [&](std::vector<spv::Decoration>& decorations, const glslang::TType& type,5492bool useVulkanMemoryModel) {5493spv::Decoration paramPrecision = TranslatePrecisionDecoration(type);5494if (paramPrecision != spv::NoPrecision)5495decorations.push_back(paramPrecision);5496TranslateMemoryDecoration(type.getQualifier(), decorations, useVulkanMemoryModel);5497if (type.isReference()) {5498// Original and non-writable params pass the pointer directly and5499// use restrict/aliased, others are stored to a pointer in Function5500// memory and use RestrictPointer/AliasedPointer.5501if (originalParam(type.getQualifier().storage, type, false) ||5502!writableParam(type.getQualifier().storage)) {5503// TranslateMemoryDecoration added Restrict decoration already.5504if (!type.getQualifier().isRestrict()) {5505decorations.push_back(spv::DecorationAliased);5506}5507} else {5508decorations.push_back(type.getQualifier().isRestrict() ? spv::DecorationRestrictPointerEXT :5509spv::DecorationAliasedPointerEXT);5510}5511}5512};55135514for (int f = 0; f < (int)glslFunctions.size(); ++f) {5515glslang::TIntermAggregate* glslFunction = glslFunctions[f]->getAsAggregate();5516if (! glslFunction || glslFunction->getOp() != glslang::EOpFunction)5517continue;5518if (isShaderEntryPoint(glslFunction)) {5519if (glslangIntermediate->getSource() != glslang::EShSourceHlsl) {5520builder.setupDebugFunctionEntry(shaderEntry, glslangIntermediate->getEntryPointMangledName().c_str(),5521glslFunction->getLoc().line,5522std::vector<spv::Id>(), // main function has no param5523std::vector<char const*>());5524}5525continue;5526}5527// We're on a user function. Set up the basic interface for the function now,5528// so that it's available to call. Translating the body will happen later.5529//5530// Typically (except for a "const in" parameter), an address will be passed to the5531// function. What it is an address of varies:5532//5533// - "in" parameters not marked as "const" can be written to without modifying the calling5534// argument so that write needs to be to a copy, hence the address of a copy works.5535//5536// - "const in" parameters can just be the r-value, as no writes need occur.5537//5538// - "out" and "inout" arguments can't be done as pointers to the calling argument, because5539// GLSL has copy-in/copy-out semantics. They can be handled though with a pointer to a copy.55405541std::vector<spv::Id> paramTypes;5542std::vector<char const*> paramNames;5543std::vector<std::vector<spv::Decoration>> paramDecorations; // list of decorations per parameter5544glslang::TIntermSequence& parameters = glslFunction->getSequence()[0]->getAsAggregate()->getSequence();55455546#ifdef ENABLE_HLSL5547bool implicitThis = (int)parameters.size() > 0 && parameters[0]->getAsSymbolNode()->getName() ==5548glslangIntermediate->implicitThisName;5549#else5550bool implicitThis = false;5551#endif55525553paramDecorations.resize(parameters.size());5554for (int p = 0; p < (int)parameters.size(); ++p) {5555const glslang::TType& paramType = parameters[p]->getAsTyped()->getType();5556spv::Id typeId = convertGlslangToSpvType(paramType);5557if (originalParam(paramType.getQualifier().storage, paramType, implicitThis && p == 0))5558typeId = builder.makePointer(TranslateStorageClass(paramType), typeId);5559else if (writableParam(paramType.getQualifier().storage))5560typeId = builder.makePointer(spv::StorageClassFunction, typeId);5561else5562rValueParameters.insert(parameters[p]->getAsSymbolNode()->getId());5563getParamDecorations(paramDecorations[p], paramType, glslangIntermediate->usingVulkanMemoryModel());5564paramTypes.push_back(typeId);5565}55665567for (auto const parameter:parameters) {5568paramNames.push_back(parameter->getAsSymbolNode()->getName().c_str());5569}55705571spv::Block* functionBlock;5572spv::Function* function = builder.makeFunctionEntry(5573TranslatePrecisionDecoration(glslFunction->getType()), convertGlslangToSpvType(glslFunction->getType()),5574glslFunction->getName().c_str(), convertGlslangLinkageToSpv(glslFunction->getLinkType()), paramTypes,5575paramDecorations, &functionBlock);5576builder.setupDebugFunctionEntry(function, glslFunction->getName().c_str(), glslFunction->getLoc().line,5577paramTypes, paramNames);5578if (implicitThis)5579function->setImplicitThis();55805581// Track function to emit/call later5582functionMap[glslFunction->getName().c_str()] = function;55835584// Set the parameter id's5585for (int p = 0; p < (int)parameters.size(); ++p) {5586symbolValues[parameters[p]->getAsSymbolNode()->getId()] = function->getParamId(p);5587// give a name too5588builder.addName(function->getParamId(p), parameters[p]->getAsSymbolNode()->getName().c_str());55895590const glslang::TType& paramType = parameters[p]->getAsTyped()->getType();5591if (paramType.contains8BitInt())5592builder.addCapability(spv::CapabilityInt8);5593if (paramType.contains16BitInt())5594builder.addCapability(spv::CapabilityInt16);5595if (paramType.contains16BitFloat())5596builder.addCapability(spv::CapabilityFloat16);5597}5598}5599}56005601// Process all the initializers, while skipping the functions and link objects5602void TGlslangToSpvTraverser::makeGlobalInitializers(const glslang::TIntermSequence& initializers)5603{5604builder.setBuildPoint(shaderEntry->getLastBlock());5605for (int i = 0; i < (int)initializers.size(); ++i) {5606glslang::TIntermAggregate* initializer = initializers[i]->getAsAggregate();5607if (initializer && initializer->getOp() != glslang::EOpFunction && initializer->getOp() !=5608glslang::EOpLinkerObjects) {56095610// We're on a top-level node that's not a function. Treat as an initializer, whose5611// code goes into the beginning of the entry point.5612initializer->traverse(this);5613}5614}5615}5616// Walk over all linker objects to create a map for payload and callable data linker objects5617// and their location to be used during codegen for OpTraceKHR and OpExecuteCallableKHR5618// This is done here since it is possible that these linker objects are not be referenced in the AST5619void TGlslangToSpvTraverser::collectRayTracingLinkerObjects()5620{5621glslang::TIntermAggregate* linkerObjects = glslangIntermediate->findLinkerObjects();5622for (auto& objSeq : linkerObjects->getSequence()) {5623auto objNode = objSeq->getAsSymbolNode();5624if (objNode != nullptr) {5625if (objNode->getQualifier().hasLocation()) {5626unsigned int location = objNode->getQualifier().layoutLocation;5627auto st = objNode->getQualifier().storage;5628int set;5629switch (st)5630{5631case glslang::EvqPayload:5632case glslang::EvqPayloadIn:5633set = 0;5634break;5635case glslang::EvqCallableData:5636case glslang::EvqCallableDataIn:5637set = 1;5638break;56395640case glslang::EvqHitObjectAttrNV:5641set = 2;5642break;56435644default:5645set = -1;5646}5647if (set != -1)5648locationToSymbol[set].insert(std::make_pair(location, objNode));5649}5650}5651}5652}5653// Process all the functions, while skipping initializers.5654void TGlslangToSpvTraverser::visitFunctions(const glslang::TIntermSequence& glslFunctions)5655{5656for (int f = 0; f < (int)glslFunctions.size(); ++f) {5657glslang::TIntermAggregate* node = glslFunctions[f]->getAsAggregate();5658if (node && (node->getOp() == glslang::EOpFunction || node->getOp() == glslang::EOpLinkerObjects))5659node->traverse(this);5660}5661}56625663void TGlslangToSpvTraverser::handleFunctionEntry(const glslang::TIntermAggregate* node)5664{5665// SPIR-V functions should already be in the functionMap from the prepass5666// that called makeFunctions().5667currentFunction = functionMap[node->getName().c_str()];5668spv::Block* functionBlock = currentFunction->getEntryBlock();5669builder.setBuildPoint(functionBlock);5670builder.enterFunction(currentFunction);5671}56725673void TGlslangToSpvTraverser::translateArguments(const glslang::TIntermAggregate& node, std::vector<spv::Id>& arguments,5674spv::Builder::AccessChain::CoherentFlags &lvalueCoherentFlags)5675{5676const glslang::TIntermSequence& glslangArguments = node.getSequence();56775678glslang::TSampler sampler = {};5679bool cubeCompare = false;5680bool f16ShadowCompare = false;5681if (node.isTexture() || node.isImage()) {5682sampler = glslangArguments[0]->getAsTyped()->getType().getSampler();5683cubeCompare = sampler.dim == glslang::EsdCube && sampler.arrayed && sampler.shadow;5684f16ShadowCompare = sampler.shadow &&5685glslangArguments[1]->getAsTyped()->getType().getBasicType() == glslang::EbtFloat16;5686}56875688for (int i = 0; i < (int)glslangArguments.size(); ++i) {5689builder.clearAccessChain();5690glslangArguments[i]->traverse(this);56915692// Special case l-value operands5693bool lvalue = false;5694switch (node.getOp()) {5695case glslang::EOpImageAtomicAdd:5696case glslang::EOpImageAtomicMin:5697case glslang::EOpImageAtomicMax:5698case glslang::EOpImageAtomicAnd:5699case glslang::EOpImageAtomicOr:5700case glslang::EOpImageAtomicXor:5701case glslang::EOpImageAtomicExchange:5702case glslang::EOpImageAtomicCompSwap:5703case glslang::EOpImageAtomicLoad:5704case glslang::EOpImageAtomicStore:5705if (i == 0)5706lvalue = true;5707break;5708case glslang::EOpSparseImageLoad:5709if ((sampler.ms && i == 3) || (! sampler.ms && i == 2))5710lvalue = true;5711break;5712case glslang::EOpSparseTexture:5713if (((cubeCompare || f16ShadowCompare) && i == 3) || (! (cubeCompare || f16ShadowCompare) && i == 2))5714lvalue = true;5715break;5716case glslang::EOpSparseTextureClamp:5717if (((cubeCompare || f16ShadowCompare) && i == 4) || (! (cubeCompare || f16ShadowCompare) && i == 3))5718lvalue = true;5719break;5720case glslang::EOpSparseTextureLod:5721case glslang::EOpSparseTextureOffset:5722if ((f16ShadowCompare && i == 4) || (! f16ShadowCompare && i == 3))5723lvalue = true;5724break;5725case glslang::EOpSparseTextureFetch:5726if ((sampler.dim != glslang::EsdRect && i == 3) || (sampler.dim == glslang::EsdRect && i == 2))5727lvalue = true;5728break;5729case glslang::EOpSparseTextureFetchOffset:5730if ((sampler.dim != glslang::EsdRect && i == 4) || (sampler.dim == glslang::EsdRect && i == 3))5731lvalue = true;5732break;5733case glslang::EOpSparseTextureLodOffset:5734case glslang::EOpSparseTextureGrad:5735case glslang::EOpSparseTextureOffsetClamp:5736if ((f16ShadowCompare && i == 5) || (! f16ShadowCompare && i == 4))5737lvalue = true;5738break;5739case glslang::EOpSparseTextureGradOffset:5740case glslang::EOpSparseTextureGradClamp:5741if ((f16ShadowCompare && i == 6) || (! f16ShadowCompare && i == 5))5742lvalue = true;5743break;5744case glslang::EOpSparseTextureGradOffsetClamp:5745if ((f16ShadowCompare && i == 7) || (! f16ShadowCompare && i == 6))5746lvalue = true;5747break;5748case glslang::EOpSparseTextureGather:5749if ((sampler.shadow && i == 3) || (! sampler.shadow && i == 2))5750lvalue = true;5751break;5752case glslang::EOpSparseTextureGatherOffset:5753case glslang::EOpSparseTextureGatherOffsets:5754if ((sampler.shadow && i == 4) || (! sampler.shadow && i == 3))5755lvalue = true;5756break;5757case glslang::EOpSparseTextureGatherLod:5758if (i == 3)5759lvalue = true;5760break;5761case glslang::EOpSparseTextureGatherLodOffset:5762case glslang::EOpSparseTextureGatherLodOffsets:5763if (i == 4)5764lvalue = true;5765break;5766case glslang::EOpSparseImageLoadLod:5767if (i == 3)5768lvalue = true;5769break;5770case glslang::EOpImageSampleFootprintNV:5771if (i == 4)5772lvalue = true;5773break;5774case glslang::EOpImageSampleFootprintClampNV:5775case glslang::EOpImageSampleFootprintLodNV:5776if (i == 5)5777lvalue = true;5778break;5779case glslang::EOpImageSampleFootprintGradNV:5780if (i == 6)5781lvalue = true;5782break;5783case glslang::EOpImageSampleFootprintGradClampNV:5784if (i == 7)5785lvalue = true;5786break;5787case glslang::EOpRayQueryGetIntersectionTriangleVertexPositionsEXT:5788if (i == 2)5789lvalue = true;5790break;5791default:5792break;5793}57945795if (lvalue) {5796spv::Id lvalue_id = builder.accessChainGetLValue();5797arguments.push_back(lvalue_id);5798lvalueCoherentFlags = builder.getAccessChain().coherentFlags;5799builder.addDecoration(lvalue_id, TranslateNonUniformDecoration(lvalueCoherentFlags));5800lvalueCoherentFlags |= TranslateCoherent(glslangArguments[i]->getAsTyped()->getType());5801} else5802arguments.push_back(accessChainLoad(glslangArguments[i]->getAsTyped()->getType()));5803}5804}58055806void TGlslangToSpvTraverser::translateArguments(glslang::TIntermUnary& node, std::vector<spv::Id>& arguments)5807{5808builder.clearAccessChain();5809node.getOperand()->traverse(this);5810arguments.push_back(accessChainLoad(node.getOperand()->getType()));5811}58125813spv::Id TGlslangToSpvTraverser::createImageTextureFunctionCall(glslang::TIntermOperator* node)5814{5815if (! node->isImage() && ! node->isTexture())5816return spv::NoResult;58175818builder.setDebugSourceLocation(node->getLoc().line, node->getLoc().getFilename());58195820// Process a GLSL texturing op (will be SPV image)58215822const glslang::TType &imageType = node->getAsAggregate()5823? node->getAsAggregate()->getSequence()[0]->getAsTyped()->getType()5824: node->getAsUnaryNode()->getOperand()->getAsTyped()->getType();5825const glslang::TSampler sampler = imageType.getSampler();5826bool f16ShadowCompare = (sampler.shadow && node->getAsAggregate())5827? node->getAsAggregate()->getSequence()[1]->getAsTyped()->getType().getBasicType() == glslang::EbtFloat165828: false;58295830const auto signExtensionMask = [&]() {5831if (builder.getSpvVersion() >= spv::Spv_1_4) {5832if (sampler.type == glslang::EbtUint)5833return spv::ImageOperandsZeroExtendMask;5834else if (sampler.type == glslang::EbtInt)5835return spv::ImageOperandsSignExtendMask;5836}5837return spv::ImageOperandsMaskNone;5838};58395840spv::Builder::AccessChain::CoherentFlags lvalueCoherentFlags;58415842std::vector<spv::Id> arguments;5843if (node->getAsAggregate())5844translateArguments(*node->getAsAggregate(), arguments, lvalueCoherentFlags);5845else5846translateArguments(*node->getAsUnaryNode(), arguments);5847spv::Decoration precision = TranslatePrecisionDecoration(node->getType());58485849spv::Builder::TextureParameters params = { };5850params.sampler = arguments[0];58515852glslang::TCrackedTextureOp cracked;5853node->crackTexture(sampler, cracked);58545855const bool isUnsignedResult = node->getType().getBasicType() == glslang::EbtUint;58565857if (builder.isSampledImage(params.sampler) &&5858((cracked.query && node->getOp() != glslang::EOpTextureQueryLod) || cracked.fragMask || cracked.fetch)) {5859params.sampler = builder.createUnaryOp(spv::OpImage, builder.getImageType(params.sampler), params.sampler);5860if (imageType.getQualifier().isNonUniform()) {5861builder.addDecoration(params.sampler, spv::DecorationNonUniformEXT);5862}5863}5864// Check for queries5865if (cracked.query) {5866switch (node->getOp()) {5867case glslang::EOpImageQuerySize:5868case glslang::EOpTextureQuerySize:5869if (arguments.size() > 1) {5870params.lod = arguments[1];5871return builder.createTextureQueryCall(spv::OpImageQuerySizeLod, params, isUnsignedResult);5872} else5873return builder.createTextureQueryCall(spv::OpImageQuerySize, params, isUnsignedResult);5874case glslang::EOpImageQuerySamples:5875case glslang::EOpTextureQuerySamples:5876return builder.createTextureQueryCall(spv::OpImageQuerySamples, params, isUnsignedResult);5877case glslang::EOpTextureQueryLod:5878params.coords = arguments[1];5879return builder.createTextureQueryCall(spv::OpImageQueryLod, params, isUnsignedResult);5880case glslang::EOpTextureQueryLevels:5881return builder.createTextureQueryCall(spv::OpImageQueryLevels, params, isUnsignedResult);5882case glslang::EOpSparseTexelsResident:5883return builder.createUnaryOp(spv::OpImageSparseTexelsResident, builder.makeBoolType(), arguments[0]);5884default:5885assert(0);5886break;5887}5888}58895890int components = node->getType().getVectorSize();58915892if (node->getOp() == glslang::EOpImageLoad ||5893node->getOp() == glslang::EOpImageLoadLod ||5894node->getOp() == glslang::EOpTextureFetch ||5895node->getOp() == glslang::EOpTextureFetchOffset) {5896// These must produce 4 components, per SPIR-V spec. We'll add a conversion constructor if needed.5897// This will only happen through the HLSL path for operator[], so we do not have to handle e.g.5898// the EOpTexture/Proj/Lod/etc family. It would be harmless to do so, but would need more logic5899// here around e.g. which ones return scalars or other types.5900components = 4;5901}59025903glslang::TType returnType(node->getType().getBasicType(), glslang::EvqTemporary, components);59045905auto resultType = [&returnType,this]{ return convertGlslangToSpvType(returnType); };59065907// Check for image functions other than queries5908if (node->isImage()) {5909std::vector<spv::IdImmediate> operands;5910auto opIt = arguments.begin();5911spv::IdImmediate image = { true, *(opIt++) };5912operands.push_back(image);59135914// Handle subpass operations5915// TODO: GLSL should change to have the "MS" only on the type rather than the5916// built-in function.5917if (cracked.subpass) {5918// add on the (0,0) coordinate5919spv::Id zero = builder.makeIntConstant(0);5920std::vector<spv::Id> comps;5921comps.push_back(zero);5922comps.push_back(zero);5923spv::IdImmediate coord = { true,5924builder.makeCompositeConstant(builder.makeVectorType(builder.makeIntType(32), 2), comps) };5925operands.push_back(coord);5926spv::IdImmediate imageOperands = { false, spv::ImageOperandsMaskNone };5927imageOperands.word = imageOperands.word | signExtensionMask();5928if (sampler.isMultiSample()) {5929imageOperands.word = imageOperands.word | spv::ImageOperandsSampleMask;5930}5931if (imageOperands.word != spv::ImageOperandsMaskNone) {5932operands.push_back(imageOperands);5933if (sampler.isMultiSample()) {5934spv::IdImmediate imageOperand = { true, *(opIt++) };5935operands.push_back(imageOperand);5936}5937}5938spv::Id result = builder.createOp(spv::OpImageRead, resultType(), operands);5939builder.setPrecision(result, precision);5940return result;5941}59425943if (cracked.attachmentEXT) {5944if (opIt != arguments.end()) {5945spv::IdImmediate sample = { true, *opIt };5946operands.push_back(sample);5947}5948spv::Id result = builder.createOp(spv::OpColorAttachmentReadEXT, resultType(), operands);5949builder.addExtension(spv::E_SPV_EXT_shader_tile_image);5950builder.setPrecision(result, precision);5951return result;5952}59535954spv::IdImmediate coord = { true, *(opIt++) };5955operands.push_back(coord);5956if (node->getOp() == glslang::EOpImageLoad || node->getOp() == glslang::EOpImageLoadLod) {5957spv::ImageOperandsMask mask = spv::ImageOperandsMaskNone;5958if (sampler.isMultiSample()) {5959mask = mask | spv::ImageOperandsSampleMask;5960}5961if (cracked.lod) {5962builder.addExtension(spv::E_SPV_AMD_shader_image_load_store_lod);5963builder.addCapability(spv::CapabilityImageReadWriteLodAMD);5964mask = mask | spv::ImageOperandsLodMask;5965}5966mask = mask | TranslateImageOperands(TranslateCoherent(imageType));5967mask = (spv::ImageOperandsMask)(mask & ~spv::ImageOperandsMakeTexelAvailableKHRMask);5968mask = mask | signExtensionMask();5969if (mask != spv::ImageOperandsMaskNone) {5970spv::IdImmediate imageOperands = { false, (unsigned int)mask };5971operands.push_back(imageOperands);5972}5973if (mask & spv::ImageOperandsSampleMask) {5974spv::IdImmediate imageOperand = { true, *opIt++ };5975operands.push_back(imageOperand);5976}5977if (mask & spv::ImageOperandsLodMask) {5978spv::IdImmediate imageOperand = { true, *opIt++ };5979operands.push_back(imageOperand);5980}5981if (mask & spv::ImageOperandsMakeTexelVisibleKHRMask) {5982spv::IdImmediate imageOperand = { true,5983builder.makeUintConstant(TranslateMemoryScope(TranslateCoherent(imageType))) };5984operands.push_back(imageOperand);5985}59865987if (builder.getImageTypeFormat(builder.getImageType(operands.front().word)) == spv::ImageFormatUnknown)5988builder.addCapability(spv::CapabilityStorageImageReadWithoutFormat);59895990std::vector<spv::Id> result(1, builder.createOp(spv::OpImageRead, resultType(), operands));5991builder.setPrecision(result[0], precision);59925993// If needed, add a conversion constructor to the proper size.5994if (components != node->getType().getVectorSize())5995result[0] = builder.createConstructor(precision, result, convertGlslangToSpvType(node->getType()));59965997return result[0];5998} else if (node->getOp() == glslang::EOpImageStore || node->getOp() == glslang::EOpImageStoreLod) {59996000// Push the texel value before the operands6001if (sampler.isMultiSample() || cracked.lod) {6002spv::IdImmediate texel = { true, *(opIt + 1) };6003operands.push_back(texel);6004} else {6005spv::IdImmediate texel = { true, *opIt };6006operands.push_back(texel);6007}60086009spv::ImageOperandsMask mask = spv::ImageOperandsMaskNone;6010if (sampler.isMultiSample()) {6011mask = mask | spv::ImageOperandsSampleMask;6012}6013if (cracked.lod) {6014builder.addExtension(spv::E_SPV_AMD_shader_image_load_store_lod);6015builder.addCapability(spv::CapabilityImageReadWriteLodAMD);6016mask = mask | spv::ImageOperandsLodMask;6017}6018mask = mask | TranslateImageOperands(TranslateCoherent(imageType));6019mask = (spv::ImageOperandsMask)(mask & ~spv::ImageOperandsMakeTexelVisibleKHRMask);6020mask = mask | signExtensionMask();6021if (mask != spv::ImageOperandsMaskNone) {6022spv::IdImmediate imageOperands = { false, (unsigned int)mask };6023operands.push_back(imageOperands);6024}6025if (mask & spv::ImageOperandsSampleMask) {6026spv::IdImmediate imageOperand = { true, *opIt++ };6027operands.push_back(imageOperand);6028}6029if (mask & spv::ImageOperandsLodMask) {6030spv::IdImmediate imageOperand = { true, *opIt++ };6031operands.push_back(imageOperand);6032}6033if (mask & spv::ImageOperandsMakeTexelAvailableKHRMask) {6034spv::IdImmediate imageOperand = { true,6035builder.makeUintConstant(TranslateMemoryScope(TranslateCoherent(imageType))) };6036operands.push_back(imageOperand);6037}60386039builder.createNoResultOp(spv::OpImageWrite, operands);6040if (builder.getImageTypeFormat(builder.getImageType(operands.front().word)) == spv::ImageFormatUnknown)6041builder.addCapability(spv::CapabilityStorageImageWriteWithoutFormat);6042return spv::NoResult;6043} else if (node->getOp() == glslang::EOpSparseImageLoad ||6044node->getOp() == glslang::EOpSparseImageLoadLod) {6045builder.addCapability(spv::CapabilitySparseResidency);6046if (builder.getImageTypeFormat(builder.getImageType(operands.front().word)) == spv::ImageFormatUnknown)6047builder.addCapability(spv::CapabilityStorageImageReadWithoutFormat);60486049spv::ImageOperandsMask mask = spv::ImageOperandsMaskNone;6050if (sampler.isMultiSample()) {6051mask = mask | spv::ImageOperandsSampleMask;6052}6053if (cracked.lod) {6054builder.addExtension(spv::E_SPV_AMD_shader_image_load_store_lod);6055builder.addCapability(spv::CapabilityImageReadWriteLodAMD);60566057mask = mask | spv::ImageOperandsLodMask;6058}6059mask = mask | TranslateImageOperands(TranslateCoherent(imageType));6060mask = (spv::ImageOperandsMask)(mask & ~spv::ImageOperandsMakeTexelAvailableKHRMask);6061mask = mask | signExtensionMask();6062if (mask != spv::ImageOperandsMaskNone) {6063spv::IdImmediate imageOperands = { false, (unsigned int)mask };6064operands.push_back(imageOperands);6065}6066if (mask & spv::ImageOperandsSampleMask) {6067spv::IdImmediate imageOperand = { true, *opIt++ };6068operands.push_back(imageOperand);6069}6070if (mask & spv::ImageOperandsLodMask) {6071spv::IdImmediate imageOperand = { true, *opIt++ };6072operands.push_back(imageOperand);6073}6074if (mask & spv::ImageOperandsMakeTexelVisibleKHRMask) {6075spv::IdImmediate imageOperand = { true, builder.makeUintConstant(TranslateMemoryScope(6076TranslateCoherent(imageType))) };6077operands.push_back(imageOperand);6078}60796080// Create the return type that was a special structure6081spv::Id texelOut = *opIt;6082spv::Id typeId0 = resultType();6083spv::Id typeId1 = builder.getDerefTypeId(texelOut);6084spv::Id resultTypeId = builder.makeStructResultType(typeId0, typeId1);60856086spv::Id resultId = builder.createOp(spv::OpImageSparseRead, resultTypeId, operands);60876088// Decode the return type6089builder.createStore(builder.createCompositeExtract(resultId, typeId1, 1), texelOut);6090return builder.createCompositeExtract(resultId, typeId0, 0);6091} else {6092// Process image atomic operations60936094// GLSL "IMAGE_PARAMS" will involve in constructing an image texel pointer and this pointer,6095// as the first source operand, is required by SPIR-V atomic operations.6096// For non-MS, the sample value should be 06097spv::IdImmediate sample = { true, sampler.isMultiSample() ? *(opIt++) : builder.makeUintConstant(0) };6098operands.push_back(sample);60996100spv::Id resultTypeId;6101glslang::TBasicType typeProxy = node->getBasicType();6102// imageAtomicStore has a void return type so base the pointer type on6103// the type of the value operand.6104if (node->getOp() == glslang::EOpImageAtomicStore) {6105resultTypeId = builder.makePointer(spv::StorageClassImage, builder.getTypeId(*opIt));6106typeProxy = node->getAsAggregate()->getSequence()[0]->getAsTyped()->getType().getSampler().type;6107} else {6108resultTypeId = builder.makePointer(spv::StorageClassImage, resultType());6109}6110spv::Id pointer = builder.createOp(spv::OpImageTexelPointer, resultTypeId, operands);6111if (imageType.getQualifier().nonUniform) {6112builder.addDecoration(pointer, spv::DecorationNonUniformEXT);6113}61146115std::vector<spv::Id> operands;6116operands.push_back(pointer);6117for (; opIt != arguments.end(); ++opIt)6118operands.push_back(*opIt);61196120return createAtomicOperation(node->getOp(), precision, resultType(), operands, typeProxy,6121lvalueCoherentFlags, node->getType());6122}6123}61246125// Check for fragment mask functions other than queries6126if (cracked.fragMask) {6127assert(sampler.ms);61286129auto opIt = arguments.begin();6130std::vector<spv::Id> operands;61316132operands.push_back(params.sampler);6133++opIt;61346135if (sampler.isSubpass()) {6136// add on the (0,0) coordinate6137spv::Id zero = builder.makeIntConstant(0);6138std::vector<spv::Id> comps;6139comps.push_back(zero);6140comps.push_back(zero);6141operands.push_back(builder.makeCompositeConstant(6142builder.makeVectorType(builder.makeIntType(32), 2), comps));6143}61446145for (; opIt != arguments.end(); ++opIt)6146operands.push_back(*opIt);61476148spv::Op fragMaskOp = spv::OpNop;6149if (node->getOp() == glslang::EOpFragmentMaskFetch)6150fragMaskOp = spv::OpFragmentMaskFetchAMD;6151else if (node->getOp() == glslang::EOpFragmentFetch)6152fragMaskOp = spv::OpFragmentFetchAMD;61536154builder.addExtension(spv::E_SPV_AMD_shader_fragment_mask);6155builder.addCapability(spv::CapabilityFragmentMaskAMD);6156return builder.createOp(fragMaskOp, resultType(), operands);6157}61586159// Check for texture functions other than queries6160bool sparse = node->isSparseTexture();6161bool imageFootprint = node->isImageFootprint();6162bool cubeCompare = sampler.dim == glslang::EsdCube && sampler.isArrayed() && sampler.isShadow();61636164// check for bias argument6165bool bias = false;6166if (! cracked.lod && ! cracked.grad && ! cracked.fetch && ! cubeCompare) {6167int nonBiasArgCount = 2;6168if (cracked.gather)6169++nonBiasArgCount; // comp argument should be present when bias argument is present61706171if (f16ShadowCompare)6172++nonBiasArgCount;6173if (cracked.offset)6174++nonBiasArgCount;6175else if (cracked.offsets)6176++nonBiasArgCount;6177if (cracked.grad)6178nonBiasArgCount += 2;6179if (cracked.lodClamp)6180++nonBiasArgCount;6181if (sparse)6182++nonBiasArgCount;6183if (imageFootprint)6184//Following three extra arguments6185// int granularity, bool coarse, out gl_TextureFootprint2DNV footprint6186nonBiasArgCount += 3;6187if ((int)arguments.size() > nonBiasArgCount)6188bias = true;6189}61906191if (cracked.gather) {6192const auto& sourceExtensions = glslangIntermediate->getRequestedExtensions();6193if (bias || cracked.lod ||6194sourceExtensions.find(glslang::E_GL_AMD_texture_gather_bias_lod) != sourceExtensions.end()) {6195builder.addExtension(spv::E_SPV_AMD_texture_gather_bias_lod);6196builder.addCapability(spv::CapabilityImageGatherBiasLodAMD);6197}6198}61996200// set the rest of the arguments62016202params.coords = arguments[1];6203int extraArgs = 0;6204bool noImplicitLod = false;62056206// sort out where Dref is coming from6207if (cubeCompare || f16ShadowCompare) {6208params.Dref = arguments[2];6209++extraArgs;6210} else if (sampler.shadow && cracked.gather) {6211params.Dref = arguments[2];6212++extraArgs;6213} else if (sampler.shadow) {6214std::vector<spv::Id> indexes;6215int dRefComp;6216if (cracked.proj)6217dRefComp = 2; // "The resulting 3rd component of P in the shadow forms is used as Dref"6218else6219dRefComp = builder.getNumComponents(params.coords) - 1;6220indexes.push_back(dRefComp);6221params.Dref = builder.createCompositeExtract(params.coords,6222builder.getScalarTypeId(builder.getTypeId(params.coords)), indexes);6223}62246225// lod6226if (cracked.lod) {6227params.lod = arguments[2 + extraArgs];6228++extraArgs;6229} else if (glslangIntermediate->getStage() != EShLangFragment &&6230!(glslangIntermediate->getStage() == EShLangCompute &&6231glslangIntermediate->hasLayoutDerivativeModeNone())) {6232// we need to invent the default lod for an explicit lod instruction for a non-fragment stage6233noImplicitLod = true;6234}62356236// multisample6237if (sampler.isMultiSample()) {6238params.sample = arguments[2 + extraArgs]; // For MS, "sample" should be specified6239++extraArgs;6240}62416242// gradient6243if (cracked.grad) {6244params.gradX = arguments[2 + extraArgs];6245params.gradY = arguments[3 + extraArgs];6246extraArgs += 2;6247}62486249// offset and offsets6250if (cracked.offset) {6251params.offset = arguments[2 + extraArgs];6252++extraArgs;6253} else if (cracked.offsets) {6254params.offsets = arguments[2 + extraArgs];6255++extraArgs;6256}62576258// lod clamp6259if (cracked.lodClamp) {6260params.lodClamp = arguments[2 + extraArgs];6261++extraArgs;6262}6263// sparse6264if (sparse) {6265params.texelOut = arguments[2 + extraArgs];6266++extraArgs;6267}6268// gather component6269if (cracked.gather && ! sampler.shadow) {6270// default component is 0, if missing, otherwise an argument6271if (2 + extraArgs < (int)arguments.size()) {6272params.component = arguments[2 + extraArgs];6273++extraArgs;6274} else6275params.component = builder.makeIntConstant(0);6276}6277spv::Id resultStruct = spv::NoResult;6278if (imageFootprint) {6279//Following three extra arguments6280// int granularity, bool coarse, out gl_TextureFootprint2DNV footprint6281params.granularity = arguments[2 + extraArgs];6282params.coarse = arguments[3 + extraArgs];6283resultStruct = arguments[4 + extraArgs];6284extraArgs += 3;6285}62866287// bias6288if (bias) {6289params.bias = arguments[2 + extraArgs];6290++extraArgs;6291}62926293if (imageFootprint) {6294builder.addExtension(spv::E_SPV_NV_shader_image_footprint);6295builder.addCapability(spv::CapabilityImageFootprintNV);629662976298//resultStructType(OpenGL type) contains 5 elements:6299//struct gl_TextureFootprint2DNV {6300// uvec2 anchor;6301// uvec2 offset;6302// uvec2 mask;6303// uint lod;6304// uint granularity;6305//};6306//or6307//struct gl_TextureFootprint3DNV {6308// uvec3 anchor;6309// uvec3 offset;6310// uvec2 mask;6311// uint lod;6312// uint granularity;6313//};6314spv::Id resultStructType = builder.getContainedTypeId(builder.getTypeId(resultStruct));6315assert(builder.isStructType(resultStructType));63166317//resType (SPIR-V type) contains 6 elements:6318//Member 0 must be a Boolean type scalar(LOD),6319//Member 1 must be a vector of integer type, whose Signedness operand is 0(anchor),6320//Member 2 must be a vector of integer type, whose Signedness operand is 0(offset),6321//Member 3 must be a vector of integer type, whose Signedness operand is 0(mask),6322//Member 4 must be a scalar of integer type, whose Signedness operand is 0(lod),6323//Member 5 must be a scalar of integer type, whose Signedness operand is 0(granularity).6324std::vector<spv::Id> members;6325members.push_back(resultType());6326for (int i = 0; i < 5; i++) {6327members.push_back(builder.getContainedTypeId(resultStructType, i));6328}6329spv::Id resType = builder.makeStructType(members, "ResType");63306331//call ImageFootprintNV6332spv::Id res = builder.createTextureCall(precision, resType, sparse, cracked.fetch, cracked.proj,6333cracked.gather, noImplicitLod, params, signExtensionMask());63346335//copy resType (SPIR-V type) to resultStructType(OpenGL type)6336for (int i = 0; i < 5; i++) {6337builder.clearAccessChain();6338builder.setAccessChainLValue(resultStruct);63396340//Accessing to a struct we created, no coherent flag is set6341spv::Builder::AccessChain::CoherentFlags flags;6342flags.clear();63436344builder.accessChainPush(builder.makeIntConstant(i), flags, 0);6345builder.accessChainStore(builder.createCompositeExtract(res, builder.getContainedTypeId(resType, i+1),6346i+1), TranslateNonUniformDecoration(imageType.getQualifier()));6347}6348return builder.createCompositeExtract(res, resultType(), 0);6349}63506351// projective component (might not to move)6352// GLSL: "The texture coordinates consumed from P, not including the last component of P,6353// are divided by the last component of P."6354// SPIR-V: "... (u [, v] [, w], q)... It may be a vector larger than needed, but all6355// unused components will appear after all used components."6356if (cracked.proj) {6357int projSourceComp = builder.getNumComponents(params.coords) - 1;6358int projTargetComp;6359switch (sampler.dim) {6360case glslang::Esd1D: projTargetComp = 1; break;6361case glslang::Esd2D: projTargetComp = 2; break;6362case glslang::EsdRect: projTargetComp = 2; break;6363default: projTargetComp = projSourceComp; break;6364}6365// copy the projective coordinate if we have to6366if (projTargetComp != projSourceComp) {6367spv::Id projComp = builder.createCompositeExtract(params.coords,6368builder.getScalarTypeId(builder.getTypeId(params.coords)), projSourceComp);6369params.coords = builder.createCompositeInsert(projComp, params.coords,6370builder.getTypeId(params.coords), projTargetComp);6371}6372}63736374// nonprivate6375if (imageType.getQualifier().nonprivate) {6376params.nonprivate = true;6377}63786379// volatile6380if (imageType.getQualifier().volatil) {6381params.volatil = true;6382}63836384std::vector<spv::Id> result( 1,6385builder.createTextureCall(precision, resultType(), sparse, cracked.fetch, cracked.proj, cracked.gather,6386noImplicitLod, params, signExtensionMask())6387);63886389if (components != node->getType().getVectorSize())6390result[0] = builder.createConstructor(precision, result, convertGlslangToSpvType(node->getType()));63916392return result[0];6393}63946395spv::Id TGlslangToSpvTraverser::handleUserFunctionCall(const glslang::TIntermAggregate* node)6396{6397// Grab the function's pointer from the previously created function6398spv::Function* function = functionMap[node->getName().c_str()];6399if (! function)6400return 0;64016402const glslang::TIntermSequence& glslangArgs = node->getSequence();6403const glslang::TQualifierList& qualifiers = node->getQualifierList();64046405// See comments in makeFunctions() for details about the semantics for parameter passing.6406//6407// These imply we need a four step process:6408// 1. Evaluate the arguments6409// 2. Allocate and make copies of in, out, and inout arguments6410// 3. Make the call6411// 4. Copy back the results64126413// 1. Evaluate the arguments and their types6414std::vector<spv::Builder::AccessChain> lValues;6415std::vector<spv::Id> rValues;6416std::vector<const glslang::TType*> argTypes;6417for (int a = 0; a < (int)glslangArgs.size(); ++a) {6418argTypes.push_back(&glslangArgs[a]->getAsTyped()->getType());6419// build l-value6420builder.clearAccessChain();6421glslangArgs[a]->traverse(this);6422// keep outputs and pass-by-originals as l-values, evaluate others as r-values6423if (originalParam(qualifiers[a], *argTypes[a], function->hasImplicitThis() && a == 0) ||6424writableParam(qualifiers[a])) {6425// save l-value6426lValues.push_back(builder.getAccessChain());6427} else {6428// process r-value6429rValues.push_back(accessChainLoad(*argTypes.back()));6430}6431}64326433// 2. Allocate space for anything needing a copy, and if it's "in" or "inout"6434// copy the original into that space.6435//6436// Also, build up the list of actual arguments to pass in for the call6437int lValueCount = 0;6438int rValueCount = 0;6439std::vector<spv::Id> spvArgs;6440for (int a = 0; a < (int)glslangArgs.size(); ++a) {6441spv::Id arg;6442if (originalParam(qualifiers[a], *argTypes[a], function->hasImplicitThis() && a == 0)) {6443builder.setAccessChain(lValues[lValueCount]);6444arg = builder.accessChainGetLValue();6445++lValueCount;6446} else if (writableParam(qualifiers[a])) {6447// need space to hold the copy6448arg = builder.createVariable(function->getParamPrecision(a), spv::StorageClassFunction,6449builder.getContainedTypeId(function->getParamType(a)), "param");6450if (qualifiers[a] == glslang::EvqIn || qualifiers[a] == glslang::EvqInOut) {6451// need to copy the input into output space6452builder.setAccessChain(lValues[lValueCount]);6453spv::Id copy = accessChainLoad(*argTypes[a]);6454builder.clearAccessChain();6455builder.setAccessChainLValue(arg);6456multiTypeStore(*argTypes[a], copy);6457}6458++lValueCount;6459} else {6460// process r-value, which involves a copy for a type mismatch6461if (function->getParamType(a) != builder.getTypeId(rValues[rValueCount]) ||6462TranslatePrecisionDecoration(*argTypes[a]) != function->getParamPrecision(a))6463{6464spv::Id argCopy = builder.createVariable(function->getParamPrecision(a), spv::StorageClassFunction, function->getParamType(a), "arg");6465builder.clearAccessChain();6466builder.setAccessChainLValue(argCopy);6467multiTypeStore(*argTypes[a], rValues[rValueCount]);6468arg = builder.createLoad(argCopy, function->getParamPrecision(a));6469} else6470arg = rValues[rValueCount];6471++rValueCount;6472}6473spvArgs.push_back(arg);6474}64756476// 3. Make the call.6477spv::Id result = builder.createFunctionCall(function, spvArgs);6478builder.setPrecision(result, TranslatePrecisionDecoration(node->getType()));6479builder.addDecoration(result, TranslateNonUniformDecoration(node->getType().getQualifier()));64806481// 4. Copy back out an "out" arguments.6482lValueCount = 0;6483for (int a = 0; a < (int)glslangArgs.size(); ++a) {6484if (originalParam(qualifiers[a], *argTypes[a], function->hasImplicitThis() && a == 0))6485++lValueCount;6486else if (writableParam(qualifiers[a])) {6487if (qualifiers[a] == glslang::EvqOut || qualifiers[a] == glslang::EvqInOut) {6488spv::Id copy = builder.createLoad(spvArgs[a], spv::NoPrecision);6489builder.addDecoration(copy, TranslateNonUniformDecoration(argTypes[a]->getQualifier()));6490builder.setAccessChain(lValues[lValueCount]);6491multiTypeStore(*argTypes[a], copy);6492}6493++lValueCount;6494}6495}64966497return result;6498}64996500// Translate AST operation to SPV operation, already having SPV-based operands/types.6501spv::Id TGlslangToSpvTraverser::createBinaryOperation(glslang::TOperator op, OpDecorations& decorations,6502spv::Id typeId, spv::Id left, spv::Id right,6503glslang::TBasicType typeProxy, bool reduceComparison)6504{6505bool isUnsigned = isTypeUnsignedInt(typeProxy);6506bool isFloat = isTypeFloat(typeProxy);6507bool isBool = typeProxy == glslang::EbtBool;65086509spv::Op binOp = spv::OpNop;6510bool needMatchingVectors = true; // for non-matrix ops, would a scalar need to smear to match a vector?6511bool comparison = false;65126513switch (op) {6514case glslang::EOpAdd:6515case glslang::EOpAddAssign:6516if (isFloat)6517binOp = spv::OpFAdd;6518else6519binOp = spv::OpIAdd;6520break;6521case glslang::EOpSub:6522case glslang::EOpSubAssign:6523if (isFloat)6524binOp = spv::OpFSub;6525else6526binOp = spv::OpISub;6527break;6528case glslang::EOpMul:6529case glslang::EOpMulAssign:6530if (isFloat)6531binOp = spv::OpFMul;6532else6533binOp = spv::OpIMul;6534break;6535case glslang::EOpVectorTimesScalar:6536case glslang::EOpVectorTimesScalarAssign:6537if (isFloat && (builder.isVector(left) || builder.isVector(right))) {6538if (builder.isVector(right))6539std::swap(left, right);6540assert(builder.isScalar(right));6541needMatchingVectors = false;6542binOp = spv::OpVectorTimesScalar;6543} else if (isFloat)6544binOp = spv::OpFMul;6545else6546binOp = spv::OpIMul;6547break;6548case glslang::EOpVectorTimesMatrix:6549case glslang::EOpVectorTimesMatrixAssign:6550binOp = spv::OpVectorTimesMatrix;6551break;6552case glslang::EOpMatrixTimesVector:6553binOp = spv::OpMatrixTimesVector;6554break;6555case glslang::EOpMatrixTimesScalar:6556case glslang::EOpMatrixTimesScalarAssign:6557binOp = spv::OpMatrixTimesScalar;6558break;6559case glslang::EOpMatrixTimesMatrix:6560case glslang::EOpMatrixTimesMatrixAssign:6561binOp = spv::OpMatrixTimesMatrix;6562break;6563case glslang::EOpOuterProduct:6564binOp = spv::OpOuterProduct;6565needMatchingVectors = false;6566break;65676568case glslang::EOpDiv:6569case glslang::EOpDivAssign:6570if (isFloat)6571binOp = spv::OpFDiv;6572else if (isUnsigned)6573binOp = spv::OpUDiv;6574else6575binOp = spv::OpSDiv;6576break;6577case glslang::EOpMod:6578case glslang::EOpModAssign:6579if (isFloat)6580binOp = spv::OpFMod;6581else if (isUnsigned)6582binOp = spv::OpUMod;6583else6584binOp = spv::OpSMod;6585break;6586case glslang::EOpRightShift:6587case glslang::EOpRightShiftAssign:6588if (isUnsigned)6589binOp = spv::OpShiftRightLogical;6590else6591binOp = spv::OpShiftRightArithmetic;6592break;6593case glslang::EOpLeftShift:6594case glslang::EOpLeftShiftAssign:6595binOp = spv::OpShiftLeftLogical;6596break;6597case glslang::EOpAnd:6598case glslang::EOpAndAssign:6599binOp = spv::OpBitwiseAnd;6600break;6601case glslang::EOpLogicalAnd:6602needMatchingVectors = false;6603binOp = spv::OpLogicalAnd;6604break;6605case glslang::EOpInclusiveOr:6606case glslang::EOpInclusiveOrAssign:6607binOp = spv::OpBitwiseOr;6608break;6609case glslang::EOpLogicalOr:6610needMatchingVectors = false;6611binOp = spv::OpLogicalOr;6612break;6613case glslang::EOpExclusiveOr:6614case glslang::EOpExclusiveOrAssign:6615binOp = spv::OpBitwiseXor;6616break;6617case glslang::EOpLogicalXor:6618needMatchingVectors = false;6619binOp = spv::OpLogicalNotEqual;6620break;66216622case glslang::EOpAbsDifference:6623binOp = isUnsigned ? spv::OpAbsUSubINTEL : spv::OpAbsISubINTEL;6624break;66256626case glslang::EOpAddSaturate:6627binOp = isUnsigned ? spv::OpUAddSatINTEL : spv::OpIAddSatINTEL;6628break;66296630case glslang::EOpSubSaturate:6631binOp = isUnsigned ? spv::OpUSubSatINTEL : spv::OpISubSatINTEL;6632break;66336634case glslang::EOpAverage:6635binOp = isUnsigned ? spv::OpUAverageINTEL : spv::OpIAverageINTEL;6636break;66376638case glslang::EOpAverageRounded:6639binOp = isUnsigned ? spv::OpUAverageRoundedINTEL : spv::OpIAverageRoundedINTEL;6640break;66416642case glslang::EOpMul32x16:6643binOp = isUnsigned ? spv::OpUMul32x16INTEL : spv::OpIMul32x16INTEL;6644break;66456646case glslang::EOpExpectEXT:6647binOp = spv::OpExpectKHR;6648break;66496650case glslang::EOpLessThan:6651case glslang::EOpGreaterThan:6652case glslang::EOpLessThanEqual:6653case glslang::EOpGreaterThanEqual:6654case glslang::EOpEqual:6655case glslang::EOpNotEqual:6656case glslang::EOpVectorEqual:6657case glslang::EOpVectorNotEqual:6658comparison = true;6659break;6660default:6661break;6662}66636664// handle mapped binary operations (should be non-comparison)6665if (binOp != spv::OpNop) {6666assert(comparison == false);6667if (builder.isMatrix(left) || builder.isMatrix(right) ||6668builder.isCooperativeMatrix(left) || builder.isCooperativeMatrix(right))6669return createBinaryMatrixOperation(binOp, decorations, typeId, left, right);66706671// No matrix involved; make both operands be the same number of components, if needed6672if (needMatchingVectors)6673builder.promoteScalar(decorations.precision, left, right);66746675spv::Id result = builder.createBinOp(binOp, typeId, left, right);6676decorations.addNoContraction(builder, result);6677decorations.addNonUniform(builder, result);6678return builder.setPrecision(result, decorations.precision);6679}66806681if (! comparison)6682return 0;66836684// Handle comparison instructions66856686if (reduceComparison && (op == glslang::EOpEqual || op == glslang::EOpNotEqual)6687&& (builder.isVector(left) || builder.isMatrix(left) || builder.isAggregate(left))) {6688spv::Id result = builder.createCompositeCompare(decorations.precision, left, right, op == glslang::EOpEqual);6689decorations.addNonUniform(builder, result);6690return result;6691}66926693switch (op) {6694case glslang::EOpLessThan:6695if (isFloat)6696binOp = spv::OpFOrdLessThan;6697else if (isUnsigned)6698binOp = spv::OpULessThan;6699else6700binOp = spv::OpSLessThan;6701break;6702case glslang::EOpGreaterThan:6703if (isFloat)6704binOp = spv::OpFOrdGreaterThan;6705else if (isUnsigned)6706binOp = spv::OpUGreaterThan;6707else6708binOp = spv::OpSGreaterThan;6709break;6710case glslang::EOpLessThanEqual:6711if (isFloat)6712binOp = spv::OpFOrdLessThanEqual;6713else if (isUnsigned)6714binOp = spv::OpULessThanEqual;6715else6716binOp = spv::OpSLessThanEqual;6717break;6718case glslang::EOpGreaterThanEqual:6719if (isFloat)6720binOp = spv::OpFOrdGreaterThanEqual;6721else if (isUnsigned)6722binOp = spv::OpUGreaterThanEqual;6723else6724binOp = spv::OpSGreaterThanEqual;6725break;6726case glslang::EOpEqual:6727case glslang::EOpVectorEqual:6728if (isFloat)6729binOp = spv::OpFOrdEqual;6730else if (isBool)6731binOp = spv::OpLogicalEqual;6732else6733binOp = spv::OpIEqual;6734break;6735case glslang::EOpNotEqual:6736case glslang::EOpVectorNotEqual:6737if (isFloat)6738binOp = spv::OpFUnordNotEqual;6739else if (isBool)6740binOp = spv::OpLogicalNotEqual;6741else6742binOp = spv::OpINotEqual;6743break;6744default:6745break;6746}67476748if (binOp != spv::OpNop) {6749spv::Id result = builder.createBinOp(binOp, typeId, left, right);6750decorations.addNoContraction(builder, result);6751decorations.addNonUniform(builder, result);6752return builder.setPrecision(result, decorations.precision);6753}67546755return 0;6756}67576758//6759// Translate AST matrix operation to SPV operation, already having SPV-based operands/types.6760// These can be any of:6761//6762// matrix * scalar6763// scalar * matrix6764// matrix * matrix linear algebraic6765// matrix * vector6766// vector * matrix6767// matrix * matrix componentwise6768// matrix op matrix op in {+, -, /}6769// matrix op scalar op in {+, -, /}6770// scalar op matrix op in {+, -, /}6771//6772spv::Id TGlslangToSpvTraverser::createBinaryMatrixOperation(spv::Op op, OpDecorations& decorations, spv::Id typeId,6773spv::Id left, spv::Id right)6774{6775bool firstClass = true;67766777// First, handle first-class matrix operations (* and matrix/scalar)6778switch (op) {6779case spv::OpFDiv:6780if (builder.isMatrix(left) && builder.isScalar(right)) {6781// turn matrix / scalar into a multiply...6782spv::Id resultType = builder.getTypeId(right);6783right = builder.createBinOp(spv::OpFDiv, resultType, builder.makeFpConstant(resultType, 1.0), right);6784op = spv::OpMatrixTimesScalar;6785} else6786firstClass = false;6787break;6788case spv::OpMatrixTimesScalar:6789if (builder.isMatrix(right) || builder.isCooperativeMatrix(right))6790std::swap(left, right);6791assert(builder.isScalar(right));6792break;6793case spv::OpVectorTimesMatrix:6794assert(builder.isVector(left));6795assert(builder.isMatrix(right));6796break;6797case spv::OpMatrixTimesVector:6798assert(builder.isMatrix(left));6799assert(builder.isVector(right));6800break;6801case spv::OpMatrixTimesMatrix:6802assert(builder.isMatrix(left));6803assert(builder.isMatrix(right));6804break;6805default:6806firstClass = false;6807break;6808}68096810if (builder.isCooperativeMatrix(left) || builder.isCooperativeMatrix(right))6811firstClass = true;68126813if (firstClass) {6814spv::Id result = builder.createBinOp(op, typeId, left, right);6815decorations.addNoContraction(builder, result);6816decorations.addNonUniform(builder, result);6817return builder.setPrecision(result, decorations.precision);6818}68196820// Handle component-wise +, -, *, %, and / for all combinations of type.6821// The result type of all of them is the same type as the (a) matrix operand.6822// The algorithm is to:6823// - break the matrix(es) into vectors6824// - smear any scalar to a vector6825// - do vector operations6826// - make a matrix out the vector results6827switch (op) {6828case spv::OpFAdd:6829case spv::OpFSub:6830case spv::OpFDiv:6831case spv::OpFMod:6832case spv::OpFMul:6833{6834// one time set up...6835bool leftMat = builder.isMatrix(left);6836bool rightMat = builder.isMatrix(right);6837unsigned int numCols = leftMat ? builder.getNumColumns(left) : builder.getNumColumns(right);6838int numRows = leftMat ? builder.getNumRows(left) : builder.getNumRows(right);6839spv::Id scalarType = builder.getScalarTypeId(typeId);6840spv::Id vecType = builder.makeVectorType(scalarType, numRows);6841std::vector<spv::Id> results;6842spv::Id smearVec = spv::NoResult;6843if (builder.isScalar(left))6844smearVec = builder.smearScalar(decorations.precision, left, vecType);6845else if (builder.isScalar(right))6846smearVec = builder.smearScalar(decorations.precision, right, vecType);68476848// do each vector op6849for (unsigned int c = 0; c < numCols; ++c) {6850std::vector<unsigned int> indexes;6851indexes.push_back(c);6852spv::Id leftVec = leftMat ? builder.createCompositeExtract( left, vecType, indexes) : smearVec;6853spv::Id rightVec = rightMat ? builder.createCompositeExtract(right, vecType, indexes) : smearVec;6854spv::Id result = builder.createBinOp(op, vecType, leftVec, rightVec);6855decorations.addNoContraction(builder, result);6856decorations.addNonUniform(builder, result);6857results.push_back(builder.setPrecision(result, decorations.precision));6858}68596860// put the pieces together6861spv::Id result = builder.setPrecision(builder.createCompositeConstruct(typeId, results), decorations.precision);6862decorations.addNonUniform(builder, result);6863return result;6864}6865default:6866assert(0);6867return spv::NoResult;6868}6869}68706871spv::Id TGlslangToSpvTraverser::createUnaryOperation(glslang::TOperator op, OpDecorations& decorations, spv::Id typeId,6872spv::Id operand, glslang::TBasicType typeProxy, const spv::Builder::AccessChain::CoherentFlags &lvalueCoherentFlags,6873const glslang::TType &opType)6874{6875spv::Op unaryOp = spv::OpNop;6876int extBuiltins = -1;6877int libCall = -1;6878bool isUnsigned = isTypeUnsignedInt(typeProxy);6879bool isFloat = isTypeFloat(typeProxy);68806881switch (op) {6882case glslang::EOpNegative:6883if (isFloat) {6884unaryOp = spv::OpFNegate;6885if (builder.isMatrixType(typeId))6886return createUnaryMatrixOperation(unaryOp, decorations, typeId, operand, typeProxy);6887} else6888unaryOp = spv::OpSNegate;6889break;68906891case glslang::EOpLogicalNot:6892case glslang::EOpVectorLogicalNot:6893unaryOp = spv::OpLogicalNot;6894break;6895case glslang::EOpBitwiseNot:6896unaryOp = spv::OpNot;6897break;68986899case glslang::EOpDeterminant:6900libCall = spv::GLSLstd450Determinant;6901break;6902case glslang::EOpMatrixInverse:6903libCall = spv::GLSLstd450MatrixInverse;6904break;6905case glslang::EOpTranspose:6906unaryOp = spv::OpTranspose;6907break;69086909case glslang::EOpRadians:6910libCall = spv::GLSLstd450Radians;6911break;6912case glslang::EOpDegrees:6913libCall = spv::GLSLstd450Degrees;6914break;6915case glslang::EOpSin:6916libCall = spv::GLSLstd450Sin;6917break;6918case glslang::EOpCos:6919libCall = spv::GLSLstd450Cos;6920break;6921case glslang::EOpTan:6922libCall = spv::GLSLstd450Tan;6923break;6924case glslang::EOpAcos:6925libCall = spv::GLSLstd450Acos;6926break;6927case glslang::EOpAsin:6928libCall = spv::GLSLstd450Asin;6929break;6930case glslang::EOpAtan:6931libCall = spv::GLSLstd450Atan;6932break;69336934case glslang::EOpAcosh:6935libCall = spv::GLSLstd450Acosh;6936break;6937case glslang::EOpAsinh:6938libCall = spv::GLSLstd450Asinh;6939break;6940case glslang::EOpAtanh:6941libCall = spv::GLSLstd450Atanh;6942break;6943case glslang::EOpTanh:6944libCall = spv::GLSLstd450Tanh;6945break;6946case glslang::EOpCosh:6947libCall = spv::GLSLstd450Cosh;6948break;6949case glslang::EOpSinh:6950libCall = spv::GLSLstd450Sinh;6951break;69526953case glslang::EOpLength:6954libCall = spv::GLSLstd450Length;6955break;6956case glslang::EOpNormalize:6957libCall = spv::GLSLstd450Normalize;6958break;69596960case glslang::EOpExp:6961libCall = spv::GLSLstd450Exp;6962break;6963case glslang::EOpLog:6964libCall = spv::GLSLstd450Log;6965break;6966case glslang::EOpExp2:6967libCall = spv::GLSLstd450Exp2;6968break;6969case glslang::EOpLog2:6970libCall = spv::GLSLstd450Log2;6971break;6972case glslang::EOpSqrt:6973libCall = spv::GLSLstd450Sqrt;6974break;6975case glslang::EOpInverseSqrt:6976libCall = spv::GLSLstd450InverseSqrt;6977break;69786979case glslang::EOpFloor:6980libCall = spv::GLSLstd450Floor;6981break;6982case glslang::EOpTrunc:6983libCall = spv::GLSLstd450Trunc;6984break;6985case glslang::EOpRound:6986libCall = spv::GLSLstd450Round;6987break;6988case glslang::EOpRoundEven:6989libCall = spv::GLSLstd450RoundEven;6990break;6991case glslang::EOpCeil:6992libCall = spv::GLSLstd450Ceil;6993break;6994case glslang::EOpFract:6995libCall = spv::GLSLstd450Fract;6996break;69976998case glslang::EOpIsNan:6999unaryOp = spv::OpIsNan;7000break;7001case glslang::EOpIsInf:7002unaryOp = spv::OpIsInf;7003break;7004case glslang::EOpIsFinite:7005unaryOp = spv::OpIsFinite;7006break;70077008case glslang::EOpFloatBitsToInt:7009case glslang::EOpFloatBitsToUint:7010case glslang::EOpIntBitsToFloat:7011case glslang::EOpUintBitsToFloat:7012case glslang::EOpDoubleBitsToInt64:7013case glslang::EOpDoubleBitsToUint64:7014case glslang::EOpInt64BitsToDouble:7015case glslang::EOpUint64BitsToDouble:7016case glslang::EOpFloat16BitsToInt16:7017case glslang::EOpFloat16BitsToUint16:7018case glslang::EOpInt16BitsToFloat16:7019case glslang::EOpUint16BitsToFloat16:7020unaryOp = spv::OpBitcast;7021break;70227023case glslang::EOpPackSnorm2x16:7024libCall = spv::GLSLstd450PackSnorm2x16;7025break;7026case glslang::EOpUnpackSnorm2x16:7027libCall = spv::GLSLstd450UnpackSnorm2x16;7028break;7029case glslang::EOpPackUnorm2x16:7030libCall = spv::GLSLstd450PackUnorm2x16;7031break;7032case glslang::EOpUnpackUnorm2x16:7033libCall = spv::GLSLstd450UnpackUnorm2x16;7034break;7035case glslang::EOpPackHalf2x16:7036libCall = spv::GLSLstd450PackHalf2x16;7037break;7038case glslang::EOpUnpackHalf2x16:7039libCall = spv::GLSLstd450UnpackHalf2x16;7040break;7041case glslang::EOpPackSnorm4x8:7042libCall = spv::GLSLstd450PackSnorm4x8;7043break;7044case glslang::EOpUnpackSnorm4x8:7045libCall = spv::GLSLstd450UnpackSnorm4x8;7046break;7047case glslang::EOpPackUnorm4x8:7048libCall = spv::GLSLstd450PackUnorm4x8;7049break;7050case glslang::EOpUnpackUnorm4x8:7051libCall = spv::GLSLstd450UnpackUnorm4x8;7052break;7053case glslang::EOpPackDouble2x32:7054libCall = spv::GLSLstd450PackDouble2x32;7055break;7056case glslang::EOpUnpackDouble2x32:7057libCall = spv::GLSLstd450UnpackDouble2x32;7058break;70597060case glslang::EOpPackInt2x32:7061case glslang::EOpUnpackInt2x32:7062case glslang::EOpPackUint2x32:7063case glslang::EOpUnpackUint2x32:7064case glslang::EOpPack16:7065case glslang::EOpPack32:7066case glslang::EOpPack64:7067case glslang::EOpUnpack32:7068case glslang::EOpUnpack16:7069case glslang::EOpUnpack8:7070case glslang::EOpPackInt2x16:7071case glslang::EOpUnpackInt2x16:7072case glslang::EOpPackUint2x16:7073case glslang::EOpUnpackUint2x16:7074case glslang::EOpPackInt4x16:7075case glslang::EOpUnpackInt4x16:7076case glslang::EOpPackUint4x16:7077case glslang::EOpUnpackUint4x16:7078case glslang::EOpPackFloat2x16:7079case glslang::EOpUnpackFloat2x16:7080unaryOp = spv::OpBitcast;7081break;70827083case glslang::EOpDPdx:7084unaryOp = spv::OpDPdx;7085break;7086case glslang::EOpDPdy:7087unaryOp = spv::OpDPdy;7088break;7089case glslang::EOpFwidth:7090unaryOp = spv::OpFwidth;7091break;70927093case glslang::EOpAny:7094unaryOp = spv::OpAny;7095break;7096case glslang::EOpAll:7097unaryOp = spv::OpAll;7098break;70997100case glslang::EOpAbs:7101if (isFloat)7102libCall = spv::GLSLstd450FAbs;7103else7104libCall = spv::GLSLstd450SAbs;7105break;7106case glslang::EOpSign:7107if (isFloat)7108libCall = spv::GLSLstd450FSign;7109else7110libCall = spv::GLSLstd450SSign;7111break;71127113case glslang::EOpDPdxFine:7114unaryOp = spv::OpDPdxFine;7115break;7116case glslang::EOpDPdyFine:7117unaryOp = spv::OpDPdyFine;7118break;7119case glslang::EOpFwidthFine:7120unaryOp = spv::OpFwidthFine;7121break;7122case glslang::EOpDPdxCoarse:7123unaryOp = spv::OpDPdxCoarse;7124break;7125case glslang::EOpDPdyCoarse:7126unaryOp = spv::OpDPdyCoarse;7127break;7128case glslang::EOpFwidthCoarse:7129unaryOp = spv::OpFwidthCoarse;7130break;7131case glslang::EOpRayQueryProceed:7132unaryOp = spv::OpRayQueryProceedKHR;7133break;7134case glslang::EOpRayQueryGetRayTMin:7135unaryOp = spv::OpRayQueryGetRayTMinKHR;7136break;7137case glslang::EOpRayQueryGetRayFlags:7138unaryOp = spv::OpRayQueryGetRayFlagsKHR;7139break;7140case glslang::EOpRayQueryGetWorldRayOrigin:7141unaryOp = spv::OpRayQueryGetWorldRayOriginKHR;7142break;7143case glslang::EOpRayQueryGetWorldRayDirection:7144unaryOp = spv::OpRayQueryGetWorldRayDirectionKHR;7145break;7146case glslang::EOpRayQueryGetIntersectionCandidateAABBOpaque:7147unaryOp = spv::OpRayQueryGetIntersectionCandidateAABBOpaqueKHR;7148break;7149case glslang::EOpInterpolateAtCentroid:7150if (typeProxy == glslang::EbtFloat16)7151builder.addExtension(spv::E_SPV_AMD_gpu_shader_half_float);7152libCall = spv::GLSLstd450InterpolateAtCentroid;7153break;7154case glslang::EOpAtomicCounterIncrement:7155case glslang::EOpAtomicCounterDecrement:7156case glslang::EOpAtomicCounter:7157{7158// Handle all of the atomics in one place, in createAtomicOperation()7159std::vector<spv::Id> operands;7160operands.push_back(operand);7161return createAtomicOperation(op, decorations.precision, typeId, operands, typeProxy, lvalueCoherentFlags, opType);7162}71637164case glslang::EOpBitFieldReverse:7165unaryOp = spv::OpBitReverse;7166break;7167case glslang::EOpBitCount:7168unaryOp = spv::OpBitCount;7169break;7170case glslang::EOpFindLSB:7171libCall = spv::GLSLstd450FindILsb;7172break;7173case glslang::EOpFindMSB:7174if (isUnsigned)7175libCall = spv::GLSLstd450FindUMsb;7176else7177libCall = spv::GLSLstd450FindSMsb;7178break;71797180case glslang::EOpCountLeadingZeros:7181builder.addCapability(spv::CapabilityIntegerFunctions2INTEL);7182builder.addExtension("SPV_INTEL_shader_integer_functions2");7183unaryOp = spv::OpUCountLeadingZerosINTEL;7184break;71857186case glslang::EOpCountTrailingZeros:7187builder.addCapability(spv::CapabilityIntegerFunctions2INTEL);7188builder.addExtension("SPV_INTEL_shader_integer_functions2");7189unaryOp = spv::OpUCountTrailingZerosINTEL;7190break;71917192case glslang::EOpBallot:7193case glslang::EOpReadFirstInvocation:7194case glslang::EOpAnyInvocation:7195case glslang::EOpAllInvocations:7196case glslang::EOpAllInvocationsEqual:7197case glslang::EOpMinInvocations:7198case glslang::EOpMaxInvocations:7199case glslang::EOpAddInvocations:7200case glslang::EOpMinInvocationsNonUniform:7201case glslang::EOpMaxInvocationsNonUniform:7202case glslang::EOpAddInvocationsNonUniform:7203case glslang::EOpMinInvocationsInclusiveScan:7204case glslang::EOpMaxInvocationsInclusiveScan:7205case glslang::EOpAddInvocationsInclusiveScan:7206case glslang::EOpMinInvocationsInclusiveScanNonUniform:7207case glslang::EOpMaxInvocationsInclusiveScanNonUniform:7208case glslang::EOpAddInvocationsInclusiveScanNonUniform:7209case glslang::EOpMinInvocationsExclusiveScan:7210case glslang::EOpMaxInvocationsExclusiveScan:7211case glslang::EOpAddInvocationsExclusiveScan:7212case glslang::EOpMinInvocationsExclusiveScanNonUniform:7213case glslang::EOpMaxInvocationsExclusiveScanNonUniform:7214case glslang::EOpAddInvocationsExclusiveScanNonUniform:7215{7216std::vector<spv::Id> operands;7217operands.push_back(operand);7218return createInvocationsOperation(op, typeId, operands, typeProxy);7219}7220case glslang::EOpSubgroupAll:7221case glslang::EOpSubgroupAny:7222case glslang::EOpSubgroupAllEqual:7223case glslang::EOpSubgroupBroadcastFirst:7224case glslang::EOpSubgroupBallot:7225case glslang::EOpSubgroupInverseBallot:7226case glslang::EOpSubgroupBallotBitCount:7227case glslang::EOpSubgroupBallotInclusiveBitCount:7228case glslang::EOpSubgroupBallotExclusiveBitCount:7229case glslang::EOpSubgroupBallotFindLSB:7230case glslang::EOpSubgroupBallotFindMSB:7231case glslang::EOpSubgroupAdd:7232case glslang::EOpSubgroupMul:7233case glslang::EOpSubgroupMin:7234case glslang::EOpSubgroupMax:7235case glslang::EOpSubgroupAnd:7236case glslang::EOpSubgroupOr:7237case glslang::EOpSubgroupXor:7238case glslang::EOpSubgroupInclusiveAdd:7239case glslang::EOpSubgroupInclusiveMul:7240case glslang::EOpSubgroupInclusiveMin:7241case glslang::EOpSubgroupInclusiveMax:7242case glslang::EOpSubgroupInclusiveAnd:7243case glslang::EOpSubgroupInclusiveOr:7244case glslang::EOpSubgroupInclusiveXor:7245case glslang::EOpSubgroupExclusiveAdd:7246case glslang::EOpSubgroupExclusiveMul:7247case glslang::EOpSubgroupExclusiveMin:7248case glslang::EOpSubgroupExclusiveMax:7249case glslang::EOpSubgroupExclusiveAnd:7250case glslang::EOpSubgroupExclusiveOr:7251case glslang::EOpSubgroupExclusiveXor:7252case glslang::EOpSubgroupQuadSwapHorizontal:7253case glslang::EOpSubgroupQuadSwapVertical:7254case glslang::EOpSubgroupQuadSwapDiagonal:7255case glslang::EOpSubgroupQuadAll:7256case glslang::EOpSubgroupQuadAny: {7257std::vector<spv::Id> operands;7258operands.push_back(operand);7259return createSubgroupOperation(op, typeId, operands, typeProxy);7260}7261case glslang::EOpMbcnt:7262extBuiltins = getExtBuiltins(spv::E_SPV_AMD_shader_ballot);7263libCall = spv::MbcntAMD;7264break;72657266case glslang::EOpCubeFaceIndex:7267extBuiltins = getExtBuiltins(spv::E_SPV_AMD_gcn_shader);7268libCall = spv::CubeFaceIndexAMD;7269break;72707271case glslang::EOpCubeFaceCoord:7272extBuiltins = getExtBuiltins(spv::E_SPV_AMD_gcn_shader);7273libCall = spv::CubeFaceCoordAMD;7274break;7275case glslang::EOpSubgroupPartition:7276unaryOp = spv::OpGroupNonUniformPartitionNV;7277break;7278case glslang::EOpConstructReference:7279unaryOp = spv::OpBitcast;7280break;72817282case glslang::EOpConvUint64ToAccStruct:7283case glslang::EOpConvUvec2ToAccStruct:7284unaryOp = spv::OpConvertUToAccelerationStructureKHR;7285break;72867287case glslang::EOpHitObjectIsEmptyNV:7288unaryOp = spv::OpHitObjectIsEmptyNV;7289break;72907291case glslang::EOpHitObjectIsMissNV:7292unaryOp = spv::OpHitObjectIsMissNV;7293break;72947295case glslang::EOpHitObjectIsHitNV:7296unaryOp = spv::OpHitObjectIsHitNV;7297break;72987299case glslang::EOpHitObjectGetObjectRayOriginNV:7300unaryOp = spv::OpHitObjectGetObjectRayOriginNV;7301break;73027303case glslang::EOpHitObjectGetObjectRayDirectionNV:7304unaryOp = spv::OpHitObjectGetObjectRayDirectionNV;7305break;73067307case glslang::EOpHitObjectGetWorldRayOriginNV:7308unaryOp = spv::OpHitObjectGetWorldRayOriginNV;7309break;73107311case glslang::EOpHitObjectGetWorldRayDirectionNV:7312unaryOp = spv::OpHitObjectGetWorldRayDirectionNV;7313break;73147315case glslang::EOpHitObjectGetObjectToWorldNV:7316unaryOp = spv::OpHitObjectGetObjectToWorldNV;7317break;73187319case glslang::EOpHitObjectGetWorldToObjectNV:7320unaryOp = spv::OpHitObjectGetWorldToObjectNV;7321break;73227323case glslang::EOpHitObjectGetRayTMinNV:7324unaryOp = spv::OpHitObjectGetRayTMinNV;7325break;73267327case glslang::EOpHitObjectGetRayTMaxNV:7328unaryOp = spv::OpHitObjectGetRayTMaxNV;7329break;73307331case glslang::EOpHitObjectGetPrimitiveIndexNV:7332unaryOp = spv::OpHitObjectGetPrimitiveIndexNV;7333break;73347335case glslang::EOpHitObjectGetInstanceIdNV:7336unaryOp = spv::OpHitObjectGetInstanceIdNV;7337break;73387339case glslang::EOpHitObjectGetInstanceCustomIndexNV:7340unaryOp = spv::OpHitObjectGetInstanceCustomIndexNV;7341break;73427343case glslang::EOpHitObjectGetGeometryIndexNV:7344unaryOp = spv::OpHitObjectGetGeometryIndexNV;7345break;73467347case glslang::EOpHitObjectGetHitKindNV:7348unaryOp = spv::OpHitObjectGetHitKindNV;7349break;73507351case glslang::EOpHitObjectGetCurrentTimeNV:7352unaryOp = spv::OpHitObjectGetCurrentTimeNV;7353break;73547355case glslang::EOpHitObjectGetShaderBindingTableRecordIndexNV:7356unaryOp = spv::OpHitObjectGetShaderBindingTableRecordIndexNV;7357break;73587359case glslang::EOpHitObjectGetShaderRecordBufferHandleNV:7360unaryOp = spv::OpHitObjectGetShaderRecordBufferHandleNV;7361break;73627363case glslang::EOpFetchMicroTriangleVertexPositionNV:7364unaryOp = spv::OpFetchMicroTriangleVertexPositionNV;7365break;73667367case glslang::EOpFetchMicroTriangleVertexBarycentricNV:7368unaryOp = spv::OpFetchMicroTriangleVertexBarycentricNV;7369break;73707371case glslang::EOpCopyObject:7372unaryOp = spv::OpCopyObject;7373break;73747375case glslang::EOpDepthAttachmentReadEXT:7376builder.addExtension(spv::E_SPV_EXT_shader_tile_image);7377builder.addCapability(spv::CapabilityTileImageDepthReadAccessEXT);7378unaryOp = spv::OpDepthAttachmentReadEXT;7379decorations.precision = spv::NoPrecision;7380break;7381case glslang::EOpStencilAttachmentReadEXT:7382builder.addExtension(spv::E_SPV_EXT_shader_tile_image);7383builder.addCapability(spv::CapabilityTileImageStencilReadAccessEXT);7384unaryOp = spv::OpStencilAttachmentReadEXT;7385decorations.precision = spv::DecorationRelaxedPrecision;7386break;73877388default:7389return 0;7390}73917392spv::Id id;7393if (libCall >= 0) {7394std::vector<spv::Id> args;7395args.push_back(operand);7396id = builder.createBuiltinCall(typeId, extBuiltins >= 0 ? extBuiltins : stdBuiltins, libCall, args);7397} else {7398id = builder.createUnaryOp(unaryOp, typeId, operand);7399}74007401decorations.addNoContraction(builder, id);7402decorations.addNonUniform(builder, id);7403return builder.setPrecision(id, decorations.precision);7404}74057406// Create a unary operation on a matrix7407spv::Id TGlslangToSpvTraverser::createUnaryMatrixOperation(spv::Op op, OpDecorations& decorations, spv::Id typeId,7408spv::Id operand, glslang::TBasicType /* typeProxy */)7409{7410// Handle unary operations vector by vector.7411// The result type is the same type as the original type.7412// The algorithm is to:7413// - break the matrix into vectors7414// - apply the operation to each vector7415// - make a matrix out the vector results74167417// get the types sorted out7418int numCols = builder.getNumColumns(operand);7419int numRows = builder.getNumRows(operand);7420spv::Id srcVecType = builder.makeVectorType(builder.getScalarTypeId(builder.getTypeId(operand)), numRows);7421spv::Id destVecType = builder.makeVectorType(builder.getScalarTypeId(typeId), numRows);7422std::vector<spv::Id> results;74237424// do each vector op7425for (int c = 0; c < numCols; ++c) {7426std::vector<unsigned int> indexes;7427indexes.push_back(c);7428spv::Id srcVec = builder.createCompositeExtract(operand, srcVecType, indexes);7429spv::Id destVec = builder.createUnaryOp(op, destVecType, srcVec);7430decorations.addNoContraction(builder, destVec);7431decorations.addNonUniform(builder, destVec);7432results.push_back(builder.setPrecision(destVec, decorations.precision));7433}74347435// put the pieces together7436spv::Id result = builder.setPrecision(builder.createCompositeConstruct(typeId, results), decorations.precision);7437decorations.addNonUniform(builder, result);7438return result;7439}74407441// For converting integers where both the bitwidth and the signedness could7442// change, but only do the width change here. The caller is still responsible7443// for the signedness conversion.7444// destType is the final type that will be converted to, but this function7445// may only be doing part of that conversion.7446spv::Id TGlslangToSpvTraverser::createIntWidthConversion(glslang::TOperator op, spv::Id operand, int vectorSize, spv::Id destType)7447{7448// Get the result type width, based on the type to convert to.7449int width = 32;7450switch(op) {7451case glslang::EOpConvInt16ToUint8:7452case glslang::EOpConvIntToUint8:7453case glslang::EOpConvInt64ToUint8:7454case glslang::EOpConvUint16ToInt8:7455case glslang::EOpConvUintToInt8:7456case glslang::EOpConvUint64ToInt8:7457width = 8;7458break;7459case glslang::EOpConvInt8ToUint16:7460case glslang::EOpConvIntToUint16:7461case glslang::EOpConvInt64ToUint16:7462case glslang::EOpConvUint8ToInt16:7463case glslang::EOpConvUintToInt16:7464case glslang::EOpConvUint64ToInt16:7465width = 16;7466break;7467case glslang::EOpConvInt8ToUint:7468case glslang::EOpConvInt16ToUint:7469case glslang::EOpConvInt64ToUint:7470case glslang::EOpConvUint8ToInt:7471case glslang::EOpConvUint16ToInt:7472case glslang::EOpConvUint64ToInt:7473width = 32;7474break;7475case glslang::EOpConvInt8ToUint64:7476case glslang::EOpConvInt16ToUint64:7477case glslang::EOpConvIntToUint64:7478case glslang::EOpConvUint8ToInt64:7479case glslang::EOpConvUint16ToInt64:7480case glslang::EOpConvUintToInt64:7481width = 64;7482break;74837484default:7485assert(false && "Default missing");7486break;7487}74887489// Get the conversion operation and result type,7490// based on the target width, but the source type.7491spv::Id type = spv::NoType;7492spv::Op convOp = spv::OpNop;7493switch(op) {7494case glslang::EOpConvInt8ToUint16:7495case glslang::EOpConvInt8ToUint:7496case glslang::EOpConvInt8ToUint64:7497case glslang::EOpConvInt16ToUint8:7498case glslang::EOpConvInt16ToUint:7499case glslang::EOpConvInt16ToUint64:7500case glslang::EOpConvIntToUint8:7501case glslang::EOpConvIntToUint16:7502case glslang::EOpConvIntToUint64:7503case glslang::EOpConvInt64ToUint8:7504case glslang::EOpConvInt64ToUint16:7505case glslang::EOpConvInt64ToUint:7506convOp = spv::OpSConvert;7507type = builder.makeIntType(width);7508break;7509default:7510convOp = spv::OpUConvert;7511type = builder.makeUintType(width);7512break;7513}75147515if (vectorSize > 0)7516type = builder.makeVectorType(type, vectorSize);7517else if (builder.getOpCode(destType) == spv::OpTypeCooperativeMatrixKHR ||7518builder.getOpCode(destType) == spv::OpTypeCooperativeMatrixNV) {75197520type = builder.makeCooperativeMatrixTypeWithSameShape(type, destType);7521}75227523return builder.createUnaryOp(convOp, type, operand);7524}75257526spv::Id TGlslangToSpvTraverser::createConversion(glslang::TOperator op, OpDecorations& decorations, spv::Id destType,7527spv::Id operand, glslang::TBasicType typeProxy)7528{7529spv::Op convOp = spv::OpNop;7530spv::Id zero = 0;7531spv::Id one = 0;75327533int vectorSize = builder.isVectorType(destType) ? builder.getNumTypeComponents(destType) : 0;75347535switch (op) {7536case glslang::EOpConvIntToBool:7537case glslang::EOpConvUintToBool:7538zero = builder.makeUintConstant(0);7539zero = makeSmearedConstant(zero, vectorSize);7540return builder.createBinOp(spv::OpINotEqual, destType, operand, zero);7541case glslang::EOpConvFloatToBool:7542zero = builder.makeFloatConstant(0.0F);7543zero = makeSmearedConstant(zero, vectorSize);7544return builder.createBinOp(spv::OpFUnordNotEqual, destType, operand, zero);7545case glslang::EOpConvBoolToFloat:7546convOp = spv::OpSelect;7547zero = builder.makeFloatConstant(0.0F);7548one = builder.makeFloatConstant(1.0F);7549break;75507551case glslang::EOpConvBoolToInt:7552case glslang::EOpConvBoolToInt64:7553if (op == glslang::EOpConvBoolToInt64) {7554zero = builder.makeInt64Constant(0);7555one = builder.makeInt64Constant(1);7556} else {7557zero = builder.makeIntConstant(0);7558one = builder.makeIntConstant(1);7559}75607561convOp = spv::OpSelect;7562break;75637564case glslang::EOpConvBoolToUint:7565case glslang::EOpConvBoolToUint64:7566if (op == glslang::EOpConvBoolToUint64) {7567zero = builder.makeUint64Constant(0);7568one = builder.makeUint64Constant(1);7569} else {7570zero = builder.makeUintConstant(0);7571one = builder.makeUintConstant(1);7572}75737574convOp = spv::OpSelect;7575break;75767577case glslang::EOpConvInt8ToFloat16:7578case glslang::EOpConvInt8ToFloat:7579case glslang::EOpConvInt8ToDouble:7580case glslang::EOpConvInt16ToFloat16:7581case glslang::EOpConvInt16ToFloat:7582case glslang::EOpConvInt16ToDouble:7583case glslang::EOpConvIntToFloat16:7584case glslang::EOpConvIntToFloat:7585case glslang::EOpConvIntToDouble:7586case glslang::EOpConvInt64ToFloat:7587case glslang::EOpConvInt64ToDouble:7588case glslang::EOpConvInt64ToFloat16:7589convOp = spv::OpConvertSToF;7590break;75917592case glslang::EOpConvUint8ToFloat16:7593case glslang::EOpConvUint8ToFloat:7594case glslang::EOpConvUint8ToDouble:7595case glslang::EOpConvUint16ToFloat16:7596case glslang::EOpConvUint16ToFloat:7597case glslang::EOpConvUint16ToDouble:7598case glslang::EOpConvUintToFloat16:7599case glslang::EOpConvUintToFloat:7600case glslang::EOpConvUintToDouble:7601case glslang::EOpConvUint64ToFloat:7602case glslang::EOpConvUint64ToDouble:7603case glslang::EOpConvUint64ToFloat16:7604convOp = spv::OpConvertUToF;7605break;76067607case glslang::EOpConvFloat16ToInt8:7608case glslang::EOpConvFloatToInt8:7609case glslang::EOpConvDoubleToInt8:7610case glslang::EOpConvFloat16ToInt16:7611case glslang::EOpConvFloatToInt16:7612case glslang::EOpConvDoubleToInt16:7613case glslang::EOpConvFloat16ToInt:7614case glslang::EOpConvFloatToInt:7615case glslang::EOpConvDoubleToInt:7616case glslang::EOpConvFloat16ToInt64:7617case glslang::EOpConvFloatToInt64:7618case glslang::EOpConvDoubleToInt64:7619convOp = spv::OpConvertFToS;7620break;76217622case glslang::EOpConvUint8ToInt8:7623case glslang::EOpConvInt8ToUint8:7624case glslang::EOpConvUint16ToInt16:7625case glslang::EOpConvInt16ToUint16:7626case glslang::EOpConvUintToInt:7627case glslang::EOpConvIntToUint:7628case glslang::EOpConvUint64ToInt64:7629case glslang::EOpConvInt64ToUint64:7630if (builder.isInSpecConstCodeGenMode()) {7631// Build zero scalar or vector for OpIAdd.7632if(op == glslang::EOpConvUint8ToInt8 || op == glslang::EOpConvInt8ToUint8) {7633zero = builder.makeUint8Constant(0);7634} else if (op == glslang::EOpConvUint16ToInt16 || op == glslang::EOpConvInt16ToUint16) {7635zero = builder.makeUint16Constant(0);7636} else if (op == glslang::EOpConvUint64ToInt64 || op == glslang::EOpConvInt64ToUint64) {7637zero = builder.makeUint64Constant(0);7638} else {7639zero = builder.makeUintConstant(0);7640}7641zero = makeSmearedConstant(zero, vectorSize);7642// Use OpIAdd, instead of OpBitcast to do the conversion when7643// generating for OpSpecConstantOp instruction.7644return builder.createBinOp(spv::OpIAdd, destType, operand, zero);7645}7646// For normal run-time conversion instruction, use OpBitcast.7647convOp = spv::OpBitcast;7648break;76497650case glslang::EOpConvFloat16ToUint8:7651case glslang::EOpConvFloatToUint8:7652case glslang::EOpConvDoubleToUint8:7653case glslang::EOpConvFloat16ToUint16:7654case glslang::EOpConvFloatToUint16:7655case glslang::EOpConvDoubleToUint16:7656case glslang::EOpConvFloat16ToUint:7657case glslang::EOpConvFloatToUint:7658case glslang::EOpConvDoubleToUint:7659case glslang::EOpConvFloatToUint64:7660case glslang::EOpConvDoubleToUint64:7661case glslang::EOpConvFloat16ToUint64:7662convOp = spv::OpConvertFToU;7663break;76647665case glslang::EOpConvInt8ToBool:7666case glslang::EOpConvUint8ToBool:7667zero = builder.makeUint8Constant(0);7668zero = makeSmearedConstant(zero, vectorSize);7669return builder.createBinOp(spv::OpINotEqual, destType, operand, zero);7670case glslang::EOpConvInt16ToBool:7671case glslang::EOpConvUint16ToBool:7672zero = builder.makeUint16Constant(0);7673zero = makeSmearedConstant(zero, vectorSize);7674return builder.createBinOp(spv::OpINotEqual, destType, operand, zero);7675case glslang::EOpConvInt64ToBool:7676case glslang::EOpConvUint64ToBool:7677zero = builder.makeUint64Constant(0);7678zero = makeSmearedConstant(zero, vectorSize);7679return builder.createBinOp(spv::OpINotEqual, destType, operand, zero);7680case glslang::EOpConvDoubleToBool:7681zero = builder.makeDoubleConstant(0.0);7682zero = makeSmearedConstant(zero, vectorSize);7683return builder.createBinOp(spv::OpFUnordNotEqual, destType, operand, zero);7684case glslang::EOpConvFloat16ToBool:7685zero = builder.makeFloat16Constant(0.0F);7686zero = makeSmearedConstant(zero, vectorSize);7687return builder.createBinOp(spv::OpFUnordNotEqual, destType, operand, zero);7688case glslang::EOpConvBoolToDouble:7689convOp = spv::OpSelect;7690zero = builder.makeDoubleConstant(0.0);7691one = builder.makeDoubleConstant(1.0);7692break;7693case glslang::EOpConvBoolToFloat16:7694convOp = spv::OpSelect;7695zero = builder.makeFloat16Constant(0.0F);7696one = builder.makeFloat16Constant(1.0F);7697break;7698case glslang::EOpConvBoolToInt8:7699zero = builder.makeInt8Constant(0);7700one = builder.makeInt8Constant(1);7701convOp = spv::OpSelect;7702break;7703case glslang::EOpConvBoolToUint8:7704zero = builder.makeUint8Constant(0);7705one = builder.makeUint8Constant(1);7706convOp = spv::OpSelect;7707break;7708case glslang::EOpConvBoolToInt16:7709zero = builder.makeInt16Constant(0);7710one = builder.makeInt16Constant(1);7711convOp = spv::OpSelect;7712break;7713case glslang::EOpConvBoolToUint16:7714zero = builder.makeUint16Constant(0);7715one = builder.makeUint16Constant(1);7716convOp = spv::OpSelect;7717break;7718case glslang::EOpConvDoubleToFloat:7719case glslang::EOpConvFloatToDouble:7720case glslang::EOpConvDoubleToFloat16:7721case glslang::EOpConvFloat16ToDouble:7722case glslang::EOpConvFloatToFloat16:7723case glslang::EOpConvFloat16ToFloat:7724convOp = spv::OpFConvert;7725if (builder.isMatrixType(destType))7726return createUnaryMatrixOperation(convOp, decorations, destType, operand, typeProxy);7727break;77287729case glslang::EOpConvInt8ToInt16:7730case glslang::EOpConvInt8ToInt:7731case glslang::EOpConvInt8ToInt64:7732case glslang::EOpConvInt16ToInt8:7733case glslang::EOpConvInt16ToInt:7734case glslang::EOpConvInt16ToInt64:7735case glslang::EOpConvIntToInt8:7736case glslang::EOpConvIntToInt16:7737case glslang::EOpConvIntToInt64:7738case glslang::EOpConvInt64ToInt8:7739case glslang::EOpConvInt64ToInt16:7740case glslang::EOpConvInt64ToInt:7741convOp = spv::OpSConvert;7742break;77437744case glslang::EOpConvUint8ToUint16:7745case glslang::EOpConvUint8ToUint:7746case glslang::EOpConvUint8ToUint64:7747case glslang::EOpConvUint16ToUint8:7748case glslang::EOpConvUint16ToUint:7749case glslang::EOpConvUint16ToUint64:7750case glslang::EOpConvUintToUint8:7751case glslang::EOpConvUintToUint16:7752case glslang::EOpConvUintToUint64:7753case glslang::EOpConvUint64ToUint8:7754case glslang::EOpConvUint64ToUint16:7755case glslang::EOpConvUint64ToUint:7756convOp = spv::OpUConvert;7757break;77587759case glslang::EOpConvInt8ToUint16:7760case glslang::EOpConvInt8ToUint:7761case glslang::EOpConvInt8ToUint64:7762case glslang::EOpConvInt16ToUint8:7763case glslang::EOpConvInt16ToUint:7764case glslang::EOpConvInt16ToUint64:7765case glslang::EOpConvIntToUint8:7766case glslang::EOpConvIntToUint16:7767case glslang::EOpConvIntToUint64:7768case glslang::EOpConvInt64ToUint8:7769case glslang::EOpConvInt64ToUint16:7770case glslang::EOpConvInt64ToUint:7771case glslang::EOpConvUint8ToInt16:7772case glslang::EOpConvUint8ToInt:7773case glslang::EOpConvUint8ToInt64:7774case glslang::EOpConvUint16ToInt8:7775case glslang::EOpConvUint16ToInt:7776case glslang::EOpConvUint16ToInt64:7777case glslang::EOpConvUintToInt8:7778case glslang::EOpConvUintToInt16:7779case glslang::EOpConvUintToInt64:7780case glslang::EOpConvUint64ToInt8:7781case glslang::EOpConvUint64ToInt16:7782case glslang::EOpConvUint64ToInt:7783// OpSConvert/OpUConvert + OpBitCast7784operand = createIntWidthConversion(op, operand, vectorSize, destType);77857786if (builder.isInSpecConstCodeGenMode()) {7787// Build zero scalar or vector for OpIAdd.7788switch(op) {7789case glslang::EOpConvInt16ToUint8:7790case glslang::EOpConvIntToUint8:7791case glslang::EOpConvInt64ToUint8:7792case glslang::EOpConvUint16ToInt8:7793case glslang::EOpConvUintToInt8:7794case glslang::EOpConvUint64ToInt8:7795zero = builder.makeUint8Constant(0);7796break;7797case glslang::EOpConvInt8ToUint16:7798case glslang::EOpConvIntToUint16:7799case glslang::EOpConvInt64ToUint16:7800case glslang::EOpConvUint8ToInt16:7801case glslang::EOpConvUintToInt16:7802case glslang::EOpConvUint64ToInt16:7803zero = builder.makeUint16Constant(0);7804break;7805case glslang::EOpConvInt8ToUint:7806case glslang::EOpConvInt16ToUint:7807case glslang::EOpConvInt64ToUint:7808case glslang::EOpConvUint8ToInt:7809case glslang::EOpConvUint16ToInt:7810case glslang::EOpConvUint64ToInt:7811zero = builder.makeUintConstant(0);7812break;7813case glslang::EOpConvInt8ToUint64:7814case glslang::EOpConvInt16ToUint64:7815case glslang::EOpConvIntToUint64:7816case glslang::EOpConvUint8ToInt64:7817case glslang::EOpConvUint16ToInt64:7818case glslang::EOpConvUintToInt64:7819zero = builder.makeUint64Constant(0);7820break;7821default:7822assert(false && "Default missing");7823break;7824}7825zero = makeSmearedConstant(zero, vectorSize);7826// Use OpIAdd, instead of OpBitcast to do the conversion when7827// generating for OpSpecConstantOp instruction.7828return builder.createBinOp(spv::OpIAdd, destType, operand, zero);7829}7830// For normal run-time conversion instruction, use OpBitcast.7831convOp = spv::OpBitcast;7832break;7833case glslang::EOpConvUint64ToPtr:7834convOp = spv::OpConvertUToPtr;7835break;7836case glslang::EOpConvPtrToUint64:7837convOp = spv::OpConvertPtrToU;7838break;7839case glslang::EOpConvPtrToUvec2:7840case glslang::EOpConvUvec2ToPtr:7841convOp = spv::OpBitcast;7842break;78437844default:7845break;7846}78477848spv::Id result = 0;7849if (convOp == spv::OpNop)7850return result;78517852if (convOp == spv::OpSelect) {7853zero = makeSmearedConstant(zero, vectorSize);7854one = makeSmearedConstant(one, vectorSize);7855result = builder.createTriOp(convOp, destType, operand, one, zero);7856} else7857result = builder.createUnaryOp(convOp, destType, operand);78587859result = builder.setPrecision(result, decorations.precision);7860decorations.addNonUniform(builder, result);7861return result;7862}78637864spv::Id TGlslangToSpvTraverser::makeSmearedConstant(spv::Id constant, int vectorSize)7865{7866if (vectorSize == 0)7867return constant;78687869spv::Id vectorTypeId = builder.makeVectorType(builder.getTypeId(constant), vectorSize);7870std::vector<spv::Id> components;7871for (int c = 0; c < vectorSize; ++c)7872components.push_back(constant);7873return builder.makeCompositeConstant(vectorTypeId, components);7874}78757876// For glslang ops that map to SPV atomic opCodes7877spv::Id TGlslangToSpvTraverser::createAtomicOperation(glslang::TOperator op, spv::Decoration /*precision*/,7878spv::Id typeId, std::vector<spv::Id>& operands, glslang::TBasicType typeProxy,7879const spv::Builder::AccessChain::CoherentFlags &lvalueCoherentFlags, const glslang::TType &opType)7880{7881spv::Op opCode = spv::OpNop;78827883switch (op) {7884case glslang::EOpAtomicAdd:7885case glslang::EOpImageAtomicAdd:7886case glslang::EOpAtomicCounterAdd:7887opCode = spv::OpAtomicIAdd;7888if (typeProxy == glslang::EbtFloat16 || typeProxy == glslang::EbtFloat || typeProxy == glslang::EbtDouble) {7889opCode = spv::OpAtomicFAddEXT;7890if (typeProxy == glslang::EbtFloat16 &&7891(opType.getVectorSize() == 2 || opType.getVectorSize() == 4)) {7892builder.addExtension(spv::E_SPV_NV_shader_atomic_fp16_vector);7893builder.addCapability(spv::CapabilityAtomicFloat16VectorNV);7894} else {7895builder.addExtension(spv::E_SPV_EXT_shader_atomic_float_add);7896if (typeProxy == glslang::EbtFloat16) {7897builder.addExtension(spv::E_SPV_EXT_shader_atomic_float16_add);7898builder.addCapability(spv::CapabilityAtomicFloat16AddEXT);7899} else if (typeProxy == glslang::EbtFloat) {7900builder.addCapability(spv::CapabilityAtomicFloat32AddEXT);7901} else {7902builder.addCapability(spv::CapabilityAtomicFloat64AddEXT);7903}7904}7905}7906break;7907case glslang::EOpAtomicSubtract:7908case glslang::EOpAtomicCounterSubtract:7909opCode = spv::OpAtomicISub;7910break;7911case glslang::EOpAtomicMin:7912case glslang::EOpImageAtomicMin:7913case glslang::EOpAtomicCounterMin:7914if (typeProxy == glslang::EbtFloat16 || typeProxy == glslang::EbtFloat || typeProxy == glslang::EbtDouble) {7915opCode = spv::OpAtomicFMinEXT;7916if (typeProxy == glslang::EbtFloat16 &&7917(opType.getVectorSize() == 2 || opType.getVectorSize() == 4)) {7918builder.addExtension(spv::E_SPV_NV_shader_atomic_fp16_vector);7919builder.addCapability(spv::CapabilityAtomicFloat16VectorNV);7920} else {7921builder.addExtension(spv::E_SPV_EXT_shader_atomic_float_min_max);7922if (typeProxy == glslang::EbtFloat16)7923builder.addCapability(spv::CapabilityAtomicFloat16MinMaxEXT);7924else if (typeProxy == glslang::EbtFloat)7925builder.addCapability(spv::CapabilityAtomicFloat32MinMaxEXT);7926else7927builder.addCapability(spv::CapabilityAtomicFloat64MinMaxEXT);7928}7929} else if (typeProxy == glslang::EbtUint || typeProxy == glslang::EbtUint64) {7930opCode = spv::OpAtomicUMin;7931} else {7932opCode = spv::OpAtomicSMin;7933}7934break;7935case glslang::EOpAtomicMax:7936case glslang::EOpImageAtomicMax:7937case glslang::EOpAtomicCounterMax:7938if (typeProxy == glslang::EbtFloat16 || typeProxy == glslang::EbtFloat || typeProxy == glslang::EbtDouble) {7939opCode = spv::OpAtomicFMaxEXT;7940if (typeProxy == glslang::EbtFloat16 &&7941(opType.getVectorSize() == 2 || opType.getVectorSize() == 4)) {7942builder.addExtension(spv::E_SPV_NV_shader_atomic_fp16_vector);7943builder.addCapability(spv::CapabilityAtomicFloat16VectorNV);7944} else {7945builder.addExtension(spv::E_SPV_EXT_shader_atomic_float_min_max);7946if (typeProxy == glslang::EbtFloat16)7947builder.addCapability(spv::CapabilityAtomicFloat16MinMaxEXT);7948else if (typeProxy == glslang::EbtFloat)7949builder.addCapability(spv::CapabilityAtomicFloat32MinMaxEXT);7950else7951builder.addCapability(spv::CapabilityAtomicFloat64MinMaxEXT);7952}7953} else if (typeProxy == glslang::EbtUint || typeProxy == glslang::EbtUint64) {7954opCode = spv::OpAtomicUMax;7955} else {7956opCode = spv::OpAtomicSMax;7957}7958break;7959case glslang::EOpAtomicAnd:7960case glslang::EOpImageAtomicAnd:7961case glslang::EOpAtomicCounterAnd:7962opCode = spv::OpAtomicAnd;7963break;7964case glslang::EOpAtomicOr:7965case glslang::EOpImageAtomicOr:7966case glslang::EOpAtomicCounterOr:7967opCode = spv::OpAtomicOr;7968break;7969case glslang::EOpAtomicXor:7970case glslang::EOpImageAtomicXor:7971case glslang::EOpAtomicCounterXor:7972opCode = spv::OpAtomicXor;7973break;7974case glslang::EOpAtomicExchange:7975case glslang::EOpImageAtomicExchange:7976case glslang::EOpAtomicCounterExchange:7977if ((typeProxy == glslang::EbtFloat16) &&7978(opType.getVectorSize() == 2 || opType.getVectorSize() == 4)) {7979builder.addExtension(spv::E_SPV_NV_shader_atomic_fp16_vector);7980builder.addCapability(spv::CapabilityAtomicFloat16VectorNV);7981}79827983opCode = spv::OpAtomicExchange;7984break;7985case glslang::EOpAtomicCompSwap:7986case glslang::EOpImageAtomicCompSwap:7987case glslang::EOpAtomicCounterCompSwap:7988opCode = spv::OpAtomicCompareExchange;7989break;7990case glslang::EOpAtomicCounterIncrement:7991opCode = spv::OpAtomicIIncrement;7992break;7993case glslang::EOpAtomicCounterDecrement:7994opCode = spv::OpAtomicIDecrement;7995break;7996case glslang::EOpAtomicCounter:7997case glslang::EOpImageAtomicLoad:7998case glslang::EOpAtomicLoad:7999opCode = spv::OpAtomicLoad;8000break;8001case glslang::EOpAtomicStore:8002case glslang::EOpImageAtomicStore:8003opCode = spv::OpAtomicStore;8004break;8005default:8006assert(0);8007break;8008}80098010if (typeProxy == glslang::EbtInt64 || typeProxy == glslang::EbtUint64)8011builder.addCapability(spv::CapabilityInt64Atomics);80128013// Sort out the operands8014// - mapping from glslang -> SPV8015// - there are extra SPV operands that are optional in glslang8016// - compare-exchange swaps the value and comparator8017// - compare-exchange has an extra memory semantics8018// - EOpAtomicCounterDecrement needs a post decrement8019spv::Id pointerId = 0, compareId = 0, valueId = 0;8020// scope defaults to Device in the old model, QueueFamilyKHR in the new model8021spv::Id scopeId;8022if (glslangIntermediate->usingVulkanMemoryModel()) {8023scopeId = builder.makeUintConstant(spv::ScopeQueueFamilyKHR);8024} else {8025scopeId = builder.makeUintConstant(spv::ScopeDevice);8026}8027// semantics default to relaxed8028spv::Id semanticsId = builder.makeUintConstant(lvalueCoherentFlags.isVolatile() &&8029glslangIntermediate->usingVulkanMemoryModel() ?8030spv::MemorySemanticsVolatileMask :8031spv::MemorySemanticsMaskNone);8032spv::Id semanticsId2 = semanticsId;80338034pointerId = operands[0];8035if (opCode == spv::OpAtomicIIncrement || opCode == spv::OpAtomicIDecrement) {8036// no additional operands8037} else if (opCode == spv::OpAtomicCompareExchange) {8038compareId = operands[1];8039valueId = operands[2];8040if (operands.size() > 3) {8041scopeId = operands[3];8042semanticsId = builder.makeUintConstant(8043builder.getConstantScalar(operands[4]) | builder.getConstantScalar(operands[5]));8044semanticsId2 = builder.makeUintConstant(8045builder.getConstantScalar(operands[6]) | builder.getConstantScalar(operands[7]));8046}8047} else if (opCode == spv::OpAtomicLoad) {8048if (operands.size() > 1) {8049scopeId = operands[1];8050semanticsId = builder.makeUintConstant(8051builder.getConstantScalar(operands[2]) | builder.getConstantScalar(operands[3]));8052}8053} else {8054// atomic store or RMW8055valueId = operands[1];8056if (operands.size() > 2) {8057scopeId = operands[2];8058semanticsId = builder.makeUintConstant8059(builder.getConstantScalar(operands[3]) | builder.getConstantScalar(operands[4]));8060}8061}80628063// Check for capabilities8064unsigned semanticsImmediate = builder.getConstantScalar(semanticsId) | builder.getConstantScalar(semanticsId2);8065if (semanticsImmediate & (spv::MemorySemanticsMakeAvailableKHRMask |8066spv::MemorySemanticsMakeVisibleKHRMask |8067spv::MemorySemanticsOutputMemoryKHRMask |8068spv::MemorySemanticsVolatileMask)) {8069builder.addCapability(spv::CapabilityVulkanMemoryModelKHR);8070}80718072if (builder.getConstantScalar(scopeId) == spv::ScopeQueueFamily) {8073builder.addCapability(spv::CapabilityVulkanMemoryModelKHR);8074}80758076if (glslangIntermediate->usingVulkanMemoryModel() && builder.getConstantScalar(scopeId) == spv::ScopeDevice) {8077builder.addCapability(spv::CapabilityVulkanMemoryModelDeviceScopeKHR);8078}80798080std::vector<spv::Id> spvAtomicOperands; // hold the spv operands8081spvAtomicOperands.reserve(6);8082spvAtomicOperands.push_back(pointerId);8083spvAtomicOperands.push_back(scopeId);8084spvAtomicOperands.push_back(semanticsId);8085if (opCode == spv::OpAtomicCompareExchange) {8086spvAtomicOperands.push_back(semanticsId2);8087spvAtomicOperands.push_back(valueId);8088spvAtomicOperands.push_back(compareId);8089} else if (opCode != spv::OpAtomicLoad && opCode != spv::OpAtomicIIncrement && opCode != spv::OpAtomicIDecrement) {8090spvAtomicOperands.push_back(valueId);8091}80928093if (opCode == spv::OpAtomicStore) {8094builder.createNoResultOp(opCode, spvAtomicOperands);8095return 0;8096} else {8097spv::Id resultId = builder.createOp(opCode, typeId, spvAtomicOperands);80988099// GLSL and HLSL atomic-counter decrement return post-decrement value,8100// while SPIR-V returns pre-decrement value. Translate between these semantics.8101if (op == glslang::EOpAtomicCounterDecrement)8102resultId = builder.createBinOp(spv::OpISub, typeId, resultId, builder.makeIntConstant(1));81038104return resultId;8105}8106}81078108// Create group invocation operations.8109spv::Id TGlslangToSpvTraverser::createInvocationsOperation(glslang::TOperator op, spv::Id typeId,8110std::vector<spv::Id>& operands, glslang::TBasicType typeProxy)8111{8112bool isUnsigned = isTypeUnsignedInt(typeProxy);8113bool isFloat = isTypeFloat(typeProxy);81148115spv::Op opCode = spv::OpNop;8116std::vector<spv::IdImmediate> spvGroupOperands;8117spv::GroupOperation groupOperation = spv::GroupOperationMax;81188119if (op == glslang::EOpBallot || op == glslang::EOpReadFirstInvocation ||8120op == glslang::EOpReadInvocation) {8121builder.addExtension(spv::E_SPV_KHR_shader_ballot);8122builder.addCapability(spv::CapabilitySubgroupBallotKHR);8123} else if (op == glslang::EOpAnyInvocation ||8124op == glslang::EOpAllInvocations ||8125op == glslang::EOpAllInvocationsEqual) {8126builder.addExtension(spv::E_SPV_KHR_subgroup_vote);8127builder.addCapability(spv::CapabilitySubgroupVoteKHR);8128} else {8129builder.addCapability(spv::CapabilityGroups);8130if (op == glslang::EOpMinInvocationsNonUniform ||8131op == glslang::EOpMaxInvocationsNonUniform ||8132op == glslang::EOpAddInvocationsNonUniform ||8133op == glslang::EOpMinInvocationsInclusiveScanNonUniform ||8134op == glslang::EOpMaxInvocationsInclusiveScanNonUniform ||8135op == glslang::EOpAddInvocationsInclusiveScanNonUniform ||8136op == glslang::EOpMinInvocationsExclusiveScanNonUniform ||8137op == glslang::EOpMaxInvocationsExclusiveScanNonUniform ||8138op == glslang::EOpAddInvocationsExclusiveScanNonUniform)8139builder.addExtension(spv::E_SPV_AMD_shader_ballot);81408141switch (op) {8142case glslang::EOpMinInvocations:8143case glslang::EOpMaxInvocations:8144case glslang::EOpAddInvocations:8145case glslang::EOpMinInvocationsNonUniform:8146case glslang::EOpMaxInvocationsNonUniform:8147case glslang::EOpAddInvocationsNonUniform:8148groupOperation = spv::GroupOperationReduce;8149break;8150case glslang::EOpMinInvocationsInclusiveScan:8151case glslang::EOpMaxInvocationsInclusiveScan:8152case glslang::EOpAddInvocationsInclusiveScan:8153case glslang::EOpMinInvocationsInclusiveScanNonUniform:8154case glslang::EOpMaxInvocationsInclusiveScanNonUniform:8155case glslang::EOpAddInvocationsInclusiveScanNonUniform:8156groupOperation = spv::GroupOperationInclusiveScan;8157break;8158case glslang::EOpMinInvocationsExclusiveScan:8159case glslang::EOpMaxInvocationsExclusiveScan:8160case glslang::EOpAddInvocationsExclusiveScan:8161case glslang::EOpMinInvocationsExclusiveScanNonUniform:8162case glslang::EOpMaxInvocationsExclusiveScanNonUniform:8163case glslang::EOpAddInvocationsExclusiveScanNonUniform:8164groupOperation = spv::GroupOperationExclusiveScan;8165break;8166default:8167break;8168}8169spv::IdImmediate scope = { true, builder.makeUintConstant(spv::ScopeSubgroup) };8170spvGroupOperands.push_back(scope);8171if (groupOperation != spv::GroupOperationMax) {8172spv::IdImmediate groupOp = { false, (unsigned)groupOperation };8173spvGroupOperands.push_back(groupOp);8174}8175}81768177for (auto opIt = operands.begin(); opIt != operands.end(); ++opIt) {8178spv::IdImmediate op = { true, *opIt };8179spvGroupOperands.push_back(op);8180}81818182switch (op) {8183case glslang::EOpAnyInvocation:8184opCode = spv::OpSubgroupAnyKHR;8185break;8186case glslang::EOpAllInvocations:8187opCode = spv::OpSubgroupAllKHR;8188break;8189case glslang::EOpAllInvocationsEqual:8190opCode = spv::OpSubgroupAllEqualKHR;8191break;8192case glslang::EOpReadInvocation:8193opCode = spv::OpSubgroupReadInvocationKHR;8194if (builder.isVectorType(typeId))8195return CreateInvocationsVectorOperation(opCode, groupOperation, typeId, operands);8196break;8197case glslang::EOpReadFirstInvocation:8198opCode = spv::OpSubgroupFirstInvocationKHR;8199if (builder.isVectorType(typeId))8200return CreateInvocationsVectorOperation(opCode, groupOperation, typeId, operands);8201break;8202case glslang::EOpBallot:8203{8204// NOTE: According to the spec, the result type of "OpSubgroupBallotKHR" must be a 4 component vector of 328205// bit integer types. The GLSL built-in function "ballotARB()" assumes the maximum number of invocations in8206// a subgroup is 64. Thus, we have to convert uvec4.xy to uint64_t as follow:8207//8208// result = Bitcast(SubgroupBallotKHR(Predicate).xy)8209//8210spv::Id uintType = builder.makeUintType(32);8211spv::Id uvec4Type = builder.makeVectorType(uintType, 4);8212spv::Id result = builder.createOp(spv::OpSubgroupBallotKHR, uvec4Type, spvGroupOperands);82138214std::vector<spv::Id> components;8215components.push_back(builder.createCompositeExtract(result, uintType, 0));8216components.push_back(builder.createCompositeExtract(result, uintType, 1));82178218spv::Id uvec2Type = builder.makeVectorType(uintType, 2);8219return builder.createUnaryOp(spv::OpBitcast, typeId,8220builder.createCompositeConstruct(uvec2Type, components));8221}82228223case glslang::EOpMinInvocations:8224case glslang::EOpMaxInvocations:8225case glslang::EOpAddInvocations:8226case glslang::EOpMinInvocationsInclusiveScan:8227case glslang::EOpMaxInvocationsInclusiveScan:8228case glslang::EOpAddInvocationsInclusiveScan:8229case glslang::EOpMinInvocationsExclusiveScan:8230case glslang::EOpMaxInvocationsExclusiveScan:8231case glslang::EOpAddInvocationsExclusiveScan:8232if (op == glslang::EOpMinInvocations ||8233op == glslang::EOpMinInvocationsInclusiveScan ||8234op == glslang::EOpMinInvocationsExclusiveScan) {8235if (isFloat)8236opCode = spv::OpGroupFMin;8237else {8238if (isUnsigned)8239opCode = spv::OpGroupUMin;8240else8241opCode = spv::OpGroupSMin;8242}8243} else if (op == glslang::EOpMaxInvocations ||8244op == glslang::EOpMaxInvocationsInclusiveScan ||8245op == glslang::EOpMaxInvocationsExclusiveScan) {8246if (isFloat)8247opCode = spv::OpGroupFMax;8248else {8249if (isUnsigned)8250opCode = spv::OpGroupUMax;8251else8252opCode = spv::OpGroupSMax;8253}8254} else {8255if (isFloat)8256opCode = spv::OpGroupFAdd;8257else8258opCode = spv::OpGroupIAdd;8259}82608261if (builder.isVectorType(typeId))8262return CreateInvocationsVectorOperation(opCode, groupOperation, typeId, operands);82638264break;8265case glslang::EOpMinInvocationsNonUniform:8266case glslang::EOpMaxInvocationsNonUniform:8267case glslang::EOpAddInvocationsNonUniform:8268case glslang::EOpMinInvocationsInclusiveScanNonUniform:8269case glslang::EOpMaxInvocationsInclusiveScanNonUniform:8270case glslang::EOpAddInvocationsInclusiveScanNonUniform:8271case glslang::EOpMinInvocationsExclusiveScanNonUniform:8272case glslang::EOpMaxInvocationsExclusiveScanNonUniform:8273case glslang::EOpAddInvocationsExclusiveScanNonUniform:8274if (op == glslang::EOpMinInvocationsNonUniform ||8275op == glslang::EOpMinInvocationsInclusiveScanNonUniform ||8276op == glslang::EOpMinInvocationsExclusiveScanNonUniform) {8277if (isFloat)8278opCode = spv::OpGroupFMinNonUniformAMD;8279else {8280if (isUnsigned)8281opCode = spv::OpGroupUMinNonUniformAMD;8282else8283opCode = spv::OpGroupSMinNonUniformAMD;8284}8285}8286else if (op == glslang::EOpMaxInvocationsNonUniform ||8287op == glslang::EOpMaxInvocationsInclusiveScanNonUniform ||8288op == glslang::EOpMaxInvocationsExclusiveScanNonUniform) {8289if (isFloat)8290opCode = spv::OpGroupFMaxNonUniformAMD;8291else {8292if (isUnsigned)8293opCode = spv::OpGroupUMaxNonUniformAMD;8294else8295opCode = spv::OpGroupSMaxNonUniformAMD;8296}8297}8298else {8299if (isFloat)8300opCode = spv::OpGroupFAddNonUniformAMD;8301else8302opCode = spv::OpGroupIAddNonUniformAMD;8303}83048305if (builder.isVectorType(typeId))8306return CreateInvocationsVectorOperation(opCode, groupOperation, typeId, operands);83078308break;8309default:8310logger->missingFunctionality("invocation operation");8311return spv::NoResult;8312}83138314assert(opCode != spv::OpNop);8315return builder.createOp(opCode, typeId, spvGroupOperands);8316}83178318// Create group invocation operations on a vector8319spv::Id TGlslangToSpvTraverser::CreateInvocationsVectorOperation(spv::Op op, spv::GroupOperation groupOperation,8320spv::Id typeId, std::vector<spv::Id>& operands)8321{8322assert(op == spv::OpGroupFMin || op == spv::OpGroupUMin || op == spv::OpGroupSMin ||8323op == spv::OpGroupFMax || op == spv::OpGroupUMax || op == spv::OpGroupSMax ||8324op == spv::OpGroupFAdd || op == spv::OpGroupIAdd || op == spv::OpGroupBroadcast ||8325op == spv::OpSubgroupReadInvocationKHR || op == spv::OpSubgroupFirstInvocationKHR ||8326op == spv::OpGroupFMinNonUniformAMD || op == spv::OpGroupUMinNonUniformAMD ||8327op == spv::OpGroupSMinNonUniformAMD ||8328op == spv::OpGroupFMaxNonUniformAMD || op == spv::OpGroupUMaxNonUniformAMD ||8329op == spv::OpGroupSMaxNonUniformAMD ||8330op == spv::OpGroupFAddNonUniformAMD || op == spv::OpGroupIAddNonUniformAMD);83318332// Handle group invocation operations scalar by scalar.8333// The result type is the same type as the original type.8334// The algorithm is to:8335// - break the vector into scalars8336// - apply the operation to each scalar8337// - make a vector out the scalar results83388339// get the types sorted out8340int numComponents = builder.getNumComponents(operands[0]);8341spv::Id scalarType = builder.getScalarTypeId(builder.getTypeId(operands[0]));8342std::vector<spv::Id> results;83438344// do each scalar op8345for (int comp = 0; comp < numComponents; ++comp) {8346std::vector<unsigned int> indexes;8347indexes.push_back(comp);8348spv::IdImmediate scalar = { true, builder.createCompositeExtract(operands[0], scalarType, indexes) };8349std::vector<spv::IdImmediate> spvGroupOperands;8350if (op == spv::OpSubgroupReadInvocationKHR) {8351spvGroupOperands.push_back(scalar);8352spv::IdImmediate operand = { true, operands[1] };8353spvGroupOperands.push_back(operand);8354} else if (op == spv::OpSubgroupFirstInvocationKHR) {8355spvGroupOperands.push_back(scalar);8356} else if (op == spv::OpGroupBroadcast) {8357spv::IdImmediate scope = { true, builder.makeUintConstant(spv::ScopeSubgroup) };8358spvGroupOperands.push_back(scope);8359spvGroupOperands.push_back(scalar);8360spv::IdImmediate operand = { true, operands[1] };8361spvGroupOperands.push_back(operand);8362} else {8363spv::IdImmediate scope = { true, builder.makeUintConstant(spv::ScopeSubgroup) };8364spvGroupOperands.push_back(scope);8365spv::IdImmediate groupOp = { false, (unsigned)groupOperation };8366spvGroupOperands.push_back(groupOp);8367spvGroupOperands.push_back(scalar);8368}83698370results.push_back(builder.createOp(op, scalarType, spvGroupOperands));8371}83728373// put the pieces together8374return builder.createCompositeConstruct(typeId, results);8375}83768377// Create subgroup invocation operations.8378spv::Id TGlslangToSpvTraverser::createSubgroupOperation(glslang::TOperator op, spv::Id typeId,8379std::vector<spv::Id>& operands, glslang::TBasicType typeProxy)8380{8381// Add the required capabilities.8382switch (op) {8383case glslang::EOpSubgroupElect:8384builder.addCapability(spv::CapabilityGroupNonUniform);8385break;8386case glslang::EOpSubgroupQuadAll:8387case glslang::EOpSubgroupQuadAny:8388builder.addExtension(spv::E_SPV_KHR_quad_control);8389builder.addCapability(spv::CapabilityQuadControlKHR);8390[[fallthrough]];8391case glslang::EOpSubgroupAll:8392case glslang::EOpSubgroupAny:8393case glslang::EOpSubgroupAllEqual:8394builder.addCapability(spv::CapabilityGroupNonUniform);8395builder.addCapability(spv::CapabilityGroupNonUniformVote);8396break;8397case glslang::EOpSubgroupBroadcast:8398case glslang::EOpSubgroupBroadcastFirst:8399case glslang::EOpSubgroupBallot:8400case glslang::EOpSubgroupInverseBallot:8401case glslang::EOpSubgroupBallotBitExtract:8402case glslang::EOpSubgroupBallotBitCount:8403case glslang::EOpSubgroupBallotInclusiveBitCount:8404case glslang::EOpSubgroupBallotExclusiveBitCount:8405case glslang::EOpSubgroupBallotFindLSB:8406case glslang::EOpSubgroupBallotFindMSB:8407builder.addCapability(spv::CapabilityGroupNonUniform);8408builder.addCapability(spv::CapabilityGroupNonUniformBallot);8409break;8410case glslang::EOpSubgroupRotate:8411case glslang::EOpSubgroupClusteredRotate:8412builder.addExtension(spv::E_SPV_KHR_subgroup_rotate);8413builder.addCapability(spv::CapabilityGroupNonUniformRotateKHR);8414break;8415case glslang::EOpSubgroupShuffle:8416case glslang::EOpSubgroupShuffleXor:8417builder.addCapability(spv::CapabilityGroupNonUniform);8418builder.addCapability(spv::CapabilityGroupNonUniformShuffle);8419break;8420case glslang::EOpSubgroupShuffleUp:8421case glslang::EOpSubgroupShuffleDown:8422builder.addCapability(spv::CapabilityGroupNonUniform);8423builder.addCapability(spv::CapabilityGroupNonUniformShuffleRelative);8424break;8425case glslang::EOpSubgroupAdd:8426case glslang::EOpSubgroupMul:8427case glslang::EOpSubgroupMin:8428case glslang::EOpSubgroupMax:8429case glslang::EOpSubgroupAnd:8430case glslang::EOpSubgroupOr:8431case glslang::EOpSubgroupXor:8432case glslang::EOpSubgroupInclusiveAdd:8433case glslang::EOpSubgroupInclusiveMul:8434case glslang::EOpSubgroupInclusiveMin:8435case glslang::EOpSubgroupInclusiveMax:8436case glslang::EOpSubgroupInclusiveAnd:8437case glslang::EOpSubgroupInclusiveOr:8438case glslang::EOpSubgroupInclusiveXor:8439case glslang::EOpSubgroupExclusiveAdd:8440case glslang::EOpSubgroupExclusiveMul:8441case glslang::EOpSubgroupExclusiveMin:8442case glslang::EOpSubgroupExclusiveMax:8443case glslang::EOpSubgroupExclusiveAnd:8444case glslang::EOpSubgroupExclusiveOr:8445case glslang::EOpSubgroupExclusiveXor:8446builder.addCapability(spv::CapabilityGroupNonUniform);8447builder.addCapability(spv::CapabilityGroupNonUniformArithmetic);8448break;8449case glslang::EOpSubgroupClusteredAdd:8450case glslang::EOpSubgroupClusteredMul:8451case glslang::EOpSubgroupClusteredMin:8452case glslang::EOpSubgroupClusteredMax:8453case glslang::EOpSubgroupClusteredAnd:8454case glslang::EOpSubgroupClusteredOr:8455case glslang::EOpSubgroupClusteredXor:8456builder.addCapability(spv::CapabilityGroupNonUniform);8457builder.addCapability(spv::CapabilityGroupNonUniformClustered);8458break;8459case glslang::EOpSubgroupQuadBroadcast:8460case glslang::EOpSubgroupQuadSwapHorizontal:8461case glslang::EOpSubgroupQuadSwapVertical:8462case glslang::EOpSubgroupQuadSwapDiagonal:8463builder.addCapability(spv::CapabilityGroupNonUniform);8464builder.addCapability(spv::CapabilityGroupNonUniformQuad);8465break;8466case glslang::EOpSubgroupPartitionedAdd:8467case glslang::EOpSubgroupPartitionedMul:8468case glslang::EOpSubgroupPartitionedMin:8469case glslang::EOpSubgroupPartitionedMax:8470case glslang::EOpSubgroupPartitionedAnd:8471case glslang::EOpSubgroupPartitionedOr:8472case glslang::EOpSubgroupPartitionedXor:8473case glslang::EOpSubgroupPartitionedInclusiveAdd:8474case glslang::EOpSubgroupPartitionedInclusiveMul:8475case glslang::EOpSubgroupPartitionedInclusiveMin:8476case glslang::EOpSubgroupPartitionedInclusiveMax:8477case glslang::EOpSubgroupPartitionedInclusiveAnd:8478case glslang::EOpSubgroupPartitionedInclusiveOr:8479case glslang::EOpSubgroupPartitionedInclusiveXor:8480case glslang::EOpSubgroupPartitionedExclusiveAdd:8481case glslang::EOpSubgroupPartitionedExclusiveMul:8482case glslang::EOpSubgroupPartitionedExclusiveMin:8483case glslang::EOpSubgroupPartitionedExclusiveMax:8484case glslang::EOpSubgroupPartitionedExclusiveAnd:8485case glslang::EOpSubgroupPartitionedExclusiveOr:8486case glslang::EOpSubgroupPartitionedExclusiveXor:8487builder.addExtension(spv::E_SPV_NV_shader_subgroup_partitioned);8488builder.addCapability(spv::CapabilityGroupNonUniformPartitionedNV);8489break;8490default: assert(0 && "Unhandled subgroup operation!");8491}849284938494const bool isUnsigned = isTypeUnsignedInt(typeProxy);8495const bool isFloat = isTypeFloat(typeProxy);8496const bool isBool = typeProxy == glslang::EbtBool;84978498spv::Op opCode = spv::OpNop;84998500// Figure out which opcode to use.8501switch (op) {8502case glslang::EOpSubgroupElect: opCode = spv::OpGroupNonUniformElect; break;8503case glslang::EOpSubgroupQuadAll: opCode = spv::OpGroupNonUniformQuadAllKHR; break;8504case glslang::EOpSubgroupAll: opCode = spv::OpGroupNonUniformAll; break;8505case glslang::EOpSubgroupQuadAny: opCode = spv::OpGroupNonUniformQuadAnyKHR; break;8506case glslang::EOpSubgroupAny: opCode = spv::OpGroupNonUniformAny; break;8507case glslang::EOpSubgroupAllEqual: opCode = spv::OpGroupNonUniformAllEqual; break;8508case glslang::EOpSubgroupBroadcast: opCode = spv::OpGroupNonUniformBroadcast; break;8509case glslang::EOpSubgroupBroadcastFirst: opCode = spv::OpGroupNonUniformBroadcastFirst; break;8510case glslang::EOpSubgroupBallot: opCode = spv::OpGroupNonUniformBallot; break;8511case glslang::EOpSubgroupInverseBallot: opCode = spv::OpGroupNonUniformInverseBallot; break;8512case glslang::EOpSubgroupBallotBitExtract: opCode = spv::OpGroupNonUniformBallotBitExtract; break;8513case glslang::EOpSubgroupBallotBitCount:8514case glslang::EOpSubgroupBallotInclusiveBitCount:8515case glslang::EOpSubgroupBallotExclusiveBitCount: opCode = spv::OpGroupNonUniformBallotBitCount; break;8516case glslang::EOpSubgroupBallotFindLSB: opCode = spv::OpGroupNonUniformBallotFindLSB; break;8517case glslang::EOpSubgroupBallotFindMSB: opCode = spv::OpGroupNonUniformBallotFindMSB; break;8518case glslang::EOpSubgroupShuffle: opCode = spv::OpGroupNonUniformShuffle; break;8519case glslang::EOpSubgroupShuffleXor: opCode = spv::OpGroupNonUniformShuffleXor; break;8520case glslang::EOpSubgroupShuffleUp: opCode = spv::OpGroupNonUniformShuffleUp; break;8521case glslang::EOpSubgroupShuffleDown: opCode = spv::OpGroupNonUniformShuffleDown; break;8522case glslang::EOpSubgroupRotate:8523case glslang::EOpSubgroupClusteredRotate: opCode = spv::OpGroupNonUniformRotateKHR; break;8524case glslang::EOpSubgroupAdd:8525case glslang::EOpSubgroupInclusiveAdd:8526case glslang::EOpSubgroupExclusiveAdd:8527case glslang::EOpSubgroupClusteredAdd:8528case glslang::EOpSubgroupPartitionedAdd:8529case glslang::EOpSubgroupPartitionedInclusiveAdd:8530case glslang::EOpSubgroupPartitionedExclusiveAdd:8531if (isFloat) {8532opCode = spv::OpGroupNonUniformFAdd;8533} else {8534opCode = spv::OpGroupNonUniformIAdd;8535}8536break;8537case glslang::EOpSubgroupMul:8538case glslang::EOpSubgroupInclusiveMul:8539case glslang::EOpSubgroupExclusiveMul:8540case glslang::EOpSubgroupClusteredMul:8541case glslang::EOpSubgroupPartitionedMul:8542case glslang::EOpSubgroupPartitionedInclusiveMul:8543case glslang::EOpSubgroupPartitionedExclusiveMul:8544if (isFloat) {8545opCode = spv::OpGroupNonUniformFMul;8546} else {8547opCode = spv::OpGroupNonUniformIMul;8548}8549break;8550case glslang::EOpSubgroupMin:8551case glslang::EOpSubgroupInclusiveMin:8552case glslang::EOpSubgroupExclusiveMin:8553case glslang::EOpSubgroupClusteredMin:8554case glslang::EOpSubgroupPartitionedMin:8555case glslang::EOpSubgroupPartitionedInclusiveMin:8556case glslang::EOpSubgroupPartitionedExclusiveMin:8557if (isFloat) {8558opCode = spv::OpGroupNonUniformFMin;8559} else if (isUnsigned) {8560opCode = spv::OpGroupNonUniformUMin;8561} else {8562opCode = spv::OpGroupNonUniformSMin;8563}8564break;8565case glslang::EOpSubgroupMax:8566case glslang::EOpSubgroupInclusiveMax:8567case glslang::EOpSubgroupExclusiveMax:8568case glslang::EOpSubgroupClusteredMax:8569case glslang::EOpSubgroupPartitionedMax:8570case glslang::EOpSubgroupPartitionedInclusiveMax:8571case glslang::EOpSubgroupPartitionedExclusiveMax:8572if (isFloat) {8573opCode = spv::OpGroupNonUniformFMax;8574} else if (isUnsigned) {8575opCode = spv::OpGroupNonUniformUMax;8576} else {8577opCode = spv::OpGroupNonUniformSMax;8578}8579break;8580case glslang::EOpSubgroupAnd:8581case glslang::EOpSubgroupInclusiveAnd:8582case glslang::EOpSubgroupExclusiveAnd:8583case glslang::EOpSubgroupClusteredAnd:8584case glslang::EOpSubgroupPartitionedAnd:8585case glslang::EOpSubgroupPartitionedInclusiveAnd:8586case glslang::EOpSubgroupPartitionedExclusiveAnd:8587if (isBool) {8588opCode = spv::OpGroupNonUniformLogicalAnd;8589} else {8590opCode = spv::OpGroupNonUniformBitwiseAnd;8591}8592break;8593case glslang::EOpSubgroupOr:8594case glslang::EOpSubgroupInclusiveOr:8595case glslang::EOpSubgroupExclusiveOr:8596case glslang::EOpSubgroupClusteredOr:8597case glslang::EOpSubgroupPartitionedOr:8598case glslang::EOpSubgroupPartitionedInclusiveOr:8599case glslang::EOpSubgroupPartitionedExclusiveOr:8600if (isBool) {8601opCode = spv::OpGroupNonUniformLogicalOr;8602} else {8603opCode = spv::OpGroupNonUniformBitwiseOr;8604}8605break;8606case glslang::EOpSubgroupXor:8607case glslang::EOpSubgroupInclusiveXor:8608case glslang::EOpSubgroupExclusiveXor:8609case glslang::EOpSubgroupClusteredXor:8610case glslang::EOpSubgroupPartitionedXor:8611case glslang::EOpSubgroupPartitionedInclusiveXor:8612case glslang::EOpSubgroupPartitionedExclusiveXor:8613if (isBool) {8614opCode = spv::OpGroupNonUniformLogicalXor;8615} else {8616opCode = spv::OpGroupNonUniformBitwiseXor;8617}8618break;8619case glslang::EOpSubgroupQuadBroadcast: opCode = spv::OpGroupNonUniformQuadBroadcast; break;8620case glslang::EOpSubgroupQuadSwapHorizontal:8621case glslang::EOpSubgroupQuadSwapVertical:8622case glslang::EOpSubgroupQuadSwapDiagonal: opCode = spv::OpGroupNonUniformQuadSwap; break;8623default: assert(0 && "Unhandled subgroup operation!");8624}86258626// get the right Group Operation8627spv::GroupOperation groupOperation = spv::GroupOperationMax;8628switch (op) {8629default:8630break;8631case glslang::EOpSubgroupBallotBitCount:8632case glslang::EOpSubgroupAdd:8633case glslang::EOpSubgroupMul:8634case glslang::EOpSubgroupMin:8635case glslang::EOpSubgroupMax:8636case glslang::EOpSubgroupAnd:8637case glslang::EOpSubgroupOr:8638case glslang::EOpSubgroupXor:8639groupOperation = spv::GroupOperationReduce;8640break;8641case glslang::EOpSubgroupBallotInclusiveBitCount:8642case glslang::EOpSubgroupInclusiveAdd:8643case glslang::EOpSubgroupInclusiveMul:8644case glslang::EOpSubgroupInclusiveMin:8645case glslang::EOpSubgroupInclusiveMax:8646case glslang::EOpSubgroupInclusiveAnd:8647case glslang::EOpSubgroupInclusiveOr:8648case glslang::EOpSubgroupInclusiveXor:8649groupOperation = spv::GroupOperationInclusiveScan;8650break;8651case glslang::EOpSubgroupBallotExclusiveBitCount:8652case glslang::EOpSubgroupExclusiveAdd:8653case glslang::EOpSubgroupExclusiveMul:8654case glslang::EOpSubgroupExclusiveMin:8655case glslang::EOpSubgroupExclusiveMax:8656case glslang::EOpSubgroupExclusiveAnd:8657case glslang::EOpSubgroupExclusiveOr:8658case glslang::EOpSubgroupExclusiveXor:8659groupOperation = spv::GroupOperationExclusiveScan;8660break;8661case glslang::EOpSubgroupClusteredAdd:8662case glslang::EOpSubgroupClusteredMul:8663case glslang::EOpSubgroupClusteredMin:8664case glslang::EOpSubgroupClusteredMax:8665case glslang::EOpSubgroupClusteredAnd:8666case glslang::EOpSubgroupClusteredOr:8667case glslang::EOpSubgroupClusteredXor:8668groupOperation = spv::GroupOperationClusteredReduce;8669break;8670case glslang::EOpSubgroupPartitionedAdd:8671case glslang::EOpSubgroupPartitionedMul:8672case glslang::EOpSubgroupPartitionedMin:8673case glslang::EOpSubgroupPartitionedMax:8674case glslang::EOpSubgroupPartitionedAnd:8675case glslang::EOpSubgroupPartitionedOr:8676case glslang::EOpSubgroupPartitionedXor:8677groupOperation = spv::GroupOperationPartitionedReduceNV;8678break;8679case glslang::EOpSubgroupPartitionedInclusiveAdd:8680case glslang::EOpSubgroupPartitionedInclusiveMul:8681case glslang::EOpSubgroupPartitionedInclusiveMin:8682case glslang::EOpSubgroupPartitionedInclusiveMax:8683case glslang::EOpSubgroupPartitionedInclusiveAnd:8684case glslang::EOpSubgroupPartitionedInclusiveOr:8685case glslang::EOpSubgroupPartitionedInclusiveXor:8686groupOperation = spv::GroupOperationPartitionedInclusiveScanNV;8687break;8688case glslang::EOpSubgroupPartitionedExclusiveAdd:8689case glslang::EOpSubgroupPartitionedExclusiveMul:8690case glslang::EOpSubgroupPartitionedExclusiveMin:8691case glslang::EOpSubgroupPartitionedExclusiveMax:8692case glslang::EOpSubgroupPartitionedExclusiveAnd:8693case glslang::EOpSubgroupPartitionedExclusiveOr:8694case glslang::EOpSubgroupPartitionedExclusiveXor:8695groupOperation = spv::GroupOperationPartitionedExclusiveScanNV;8696break;8697}86988699// build the instruction8700std::vector<spv::IdImmediate> spvGroupOperands;87018702// Every operation begins with the Execution Scope operand.8703spv::IdImmediate executionScope = { true, builder.makeUintConstant(spv::ScopeSubgroup) };8704// All other ops need the execution scope. Quad Control Ops don't need scope, it's always Quad.8705if (opCode != spv::OpGroupNonUniformQuadAllKHR && opCode != spv::OpGroupNonUniformQuadAnyKHR) {8706spvGroupOperands.push_back(executionScope);8707}87088709// Next, for all operations that use a Group Operation, push that as an operand.8710if (groupOperation != spv::GroupOperationMax) {8711spv::IdImmediate groupOperand = { false, (unsigned)groupOperation };8712spvGroupOperands.push_back(groupOperand);8713}87148715// Push back the operands next.8716for (auto opIt = operands.cbegin(); opIt != operands.cend(); ++opIt) {8717spv::IdImmediate operand = { true, *opIt };8718spvGroupOperands.push_back(operand);8719}87208721// Some opcodes have additional operands.8722spv::Id directionId = spv::NoResult;8723switch (op) {8724default: break;8725case glslang::EOpSubgroupQuadSwapHorizontal: directionId = builder.makeUintConstant(0); break;8726case glslang::EOpSubgroupQuadSwapVertical: directionId = builder.makeUintConstant(1); break;8727case glslang::EOpSubgroupQuadSwapDiagonal: directionId = builder.makeUintConstant(2); break;8728}8729if (directionId != spv::NoResult) {8730spv::IdImmediate direction = { true, directionId };8731spvGroupOperands.push_back(direction);8732}87338734return builder.createOp(opCode, typeId, spvGroupOperands);8735}87368737spv::Id TGlslangToSpvTraverser::createMiscOperation(glslang::TOperator op, spv::Decoration precision,8738spv::Id typeId, std::vector<spv::Id>& operands, glslang::TBasicType typeProxy)8739{8740bool isUnsigned = isTypeUnsignedInt(typeProxy);8741bool isFloat = isTypeFloat(typeProxy);87428743spv::Op opCode = spv::OpNop;8744int extBuiltins = -1;8745int libCall = -1;8746size_t consumedOperands = operands.size();8747spv::Id typeId0 = 0;8748if (consumedOperands > 0)8749typeId0 = builder.getTypeId(operands[0]);8750spv::Id typeId1 = 0;8751if (consumedOperands > 1)8752typeId1 = builder.getTypeId(operands[1]);8753spv::Id frexpIntType = 0;87548755switch (op) {8756case glslang::EOpMin:8757if (isFloat)8758libCall = nanMinMaxClamp ? spv::GLSLstd450NMin : spv::GLSLstd450FMin;8759else if (isUnsigned)8760libCall = spv::GLSLstd450UMin;8761else8762libCall = spv::GLSLstd450SMin;8763builder.promoteScalar(precision, operands.front(), operands.back());8764break;8765case glslang::EOpModf:8766libCall = spv::GLSLstd450Modf;8767break;8768case glslang::EOpMax:8769if (isFloat)8770libCall = nanMinMaxClamp ? spv::GLSLstd450NMax : spv::GLSLstd450FMax;8771else if (isUnsigned)8772libCall = spv::GLSLstd450UMax;8773else8774libCall = spv::GLSLstd450SMax;8775builder.promoteScalar(precision, operands.front(), operands.back());8776break;8777case glslang::EOpPow:8778libCall = spv::GLSLstd450Pow;8779break;8780case glslang::EOpDot:8781opCode = spv::OpDot;8782break;8783case glslang::EOpAtan:8784libCall = spv::GLSLstd450Atan2;8785break;87868787case glslang::EOpClamp:8788if (isFloat)8789libCall = nanMinMaxClamp ? spv::GLSLstd450NClamp : spv::GLSLstd450FClamp;8790else if (isUnsigned)8791libCall = spv::GLSLstd450UClamp;8792else8793libCall = spv::GLSLstd450SClamp;8794builder.promoteScalar(precision, operands.front(), operands[1]);8795builder.promoteScalar(precision, operands.front(), operands[2]);8796break;8797case glslang::EOpMix:8798if (! builder.isBoolType(builder.getScalarTypeId(builder.getTypeId(operands.back())))) {8799assert(isFloat);8800libCall = spv::GLSLstd450FMix;8801} else {8802opCode = spv::OpSelect;8803std::swap(operands.front(), operands.back());8804}8805builder.promoteScalar(precision, operands.front(), operands.back());8806break;8807case glslang::EOpStep:8808libCall = spv::GLSLstd450Step;8809builder.promoteScalar(precision, operands.front(), operands.back());8810break;8811case glslang::EOpSmoothStep:8812libCall = spv::GLSLstd450SmoothStep;8813builder.promoteScalar(precision, operands[0], operands[2]);8814builder.promoteScalar(precision, operands[1], operands[2]);8815break;88168817case glslang::EOpDistance:8818libCall = spv::GLSLstd450Distance;8819break;8820case glslang::EOpCross:8821libCall = spv::GLSLstd450Cross;8822break;8823case glslang::EOpFaceForward:8824libCall = spv::GLSLstd450FaceForward;8825break;8826case glslang::EOpReflect:8827libCall = spv::GLSLstd450Reflect;8828break;8829case glslang::EOpRefract:8830libCall = spv::GLSLstd450Refract;8831break;8832case glslang::EOpBarrier:8833{8834// This is for the extended controlBarrier function, with four operands.8835// The unextended barrier() goes through createNoArgOperation.8836assert(operands.size() == 4);8837unsigned int executionScope = builder.getConstantScalar(operands[0]);8838unsigned int memoryScope = builder.getConstantScalar(operands[1]);8839unsigned int semantics = builder.getConstantScalar(operands[2]) | builder.getConstantScalar(operands[3]);8840builder.createControlBarrier((spv::Scope)executionScope, (spv::Scope)memoryScope,8841(spv::MemorySemanticsMask)semantics);8842if (semantics & (spv::MemorySemanticsMakeAvailableKHRMask |8843spv::MemorySemanticsMakeVisibleKHRMask |8844spv::MemorySemanticsOutputMemoryKHRMask |8845spv::MemorySemanticsVolatileMask)) {8846builder.addCapability(spv::CapabilityVulkanMemoryModelKHR);8847}8848if (glslangIntermediate->usingVulkanMemoryModel() && (executionScope == spv::ScopeDevice ||8849memoryScope == spv::ScopeDevice)) {8850builder.addCapability(spv::CapabilityVulkanMemoryModelDeviceScopeKHR);8851}8852return 0;8853}8854break;8855case glslang::EOpMemoryBarrier:8856{8857// This is for the extended memoryBarrier function, with three operands.8858// The unextended memoryBarrier() goes through createNoArgOperation.8859assert(operands.size() == 3);8860unsigned int memoryScope = builder.getConstantScalar(operands[0]);8861unsigned int semantics = builder.getConstantScalar(operands[1]) | builder.getConstantScalar(operands[2]);8862builder.createMemoryBarrier((spv::Scope)memoryScope, (spv::MemorySemanticsMask)semantics);8863if (semantics & (spv::MemorySemanticsMakeAvailableKHRMask |8864spv::MemorySemanticsMakeVisibleKHRMask |8865spv::MemorySemanticsOutputMemoryKHRMask |8866spv::MemorySemanticsVolatileMask)) {8867builder.addCapability(spv::CapabilityVulkanMemoryModelKHR);8868}8869if (glslangIntermediate->usingVulkanMemoryModel() && memoryScope == spv::ScopeDevice) {8870builder.addCapability(spv::CapabilityVulkanMemoryModelDeviceScopeKHR);8871}8872return 0;8873}8874break;88758876case glslang::EOpInterpolateAtSample:8877if (typeProxy == glslang::EbtFloat16)8878builder.addExtension(spv::E_SPV_AMD_gpu_shader_half_float);8879libCall = spv::GLSLstd450InterpolateAtSample;8880break;8881case glslang::EOpInterpolateAtOffset:8882if (typeProxy == glslang::EbtFloat16)8883builder.addExtension(spv::E_SPV_AMD_gpu_shader_half_float);8884libCall = spv::GLSLstd450InterpolateAtOffset;8885break;8886case glslang::EOpAddCarry:8887opCode = spv::OpIAddCarry;8888typeId = builder.makeStructResultType(typeId0, typeId0);8889consumedOperands = 2;8890break;8891case glslang::EOpSubBorrow:8892opCode = spv::OpISubBorrow;8893typeId = builder.makeStructResultType(typeId0, typeId0);8894consumedOperands = 2;8895break;8896case glslang::EOpUMulExtended:8897opCode = spv::OpUMulExtended;8898typeId = builder.makeStructResultType(typeId0, typeId0);8899consumedOperands = 2;8900break;8901case glslang::EOpIMulExtended:8902opCode = spv::OpSMulExtended;8903typeId = builder.makeStructResultType(typeId0, typeId0);8904consumedOperands = 2;8905break;8906case glslang::EOpBitfieldExtract:8907if (isUnsigned)8908opCode = spv::OpBitFieldUExtract;8909else8910opCode = spv::OpBitFieldSExtract;8911break;8912case glslang::EOpBitfieldInsert:8913opCode = spv::OpBitFieldInsert;8914break;89158916case glslang::EOpFma:8917libCall = spv::GLSLstd450Fma;8918break;8919case glslang::EOpFrexp:8920{8921libCall = spv::GLSLstd450FrexpStruct;8922assert(builder.isPointerType(typeId1));8923typeId1 = builder.getContainedTypeId(typeId1);8924int width = builder.getScalarTypeWidth(typeId1);8925if (width == 16)8926// Using 16-bit exp operand, enable extension SPV_AMD_gpu_shader_int168927builder.addExtension(spv::E_SPV_AMD_gpu_shader_int16);8928if (builder.getNumComponents(operands[0]) == 1)8929frexpIntType = builder.makeIntegerType(width, true);8930else8931frexpIntType = builder.makeVectorType(builder.makeIntegerType(width, true),8932builder.getNumComponents(operands[0]));8933typeId = builder.makeStructResultType(typeId0, frexpIntType);8934consumedOperands = 1;8935}8936break;8937case glslang::EOpLdexp:8938libCall = spv::GLSLstd450Ldexp;8939break;89408941case glslang::EOpReadInvocation:8942return createInvocationsOperation(op, typeId, operands, typeProxy);89438944case glslang::EOpSubgroupBroadcast:8945case glslang::EOpSubgroupBallotBitExtract:8946case glslang::EOpSubgroupShuffle:8947case glslang::EOpSubgroupShuffleXor:8948case glslang::EOpSubgroupShuffleUp:8949case glslang::EOpSubgroupShuffleDown:8950case glslang::EOpSubgroupRotate:8951case glslang::EOpSubgroupClusteredRotate:8952case glslang::EOpSubgroupClusteredAdd:8953case glslang::EOpSubgroupClusteredMul:8954case glslang::EOpSubgroupClusteredMin:8955case glslang::EOpSubgroupClusteredMax:8956case glslang::EOpSubgroupClusteredAnd:8957case glslang::EOpSubgroupClusteredOr:8958case glslang::EOpSubgroupClusteredXor:8959case glslang::EOpSubgroupQuadBroadcast:8960case glslang::EOpSubgroupPartitionedAdd:8961case glslang::EOpSubgroupPartitionedMul:8962case glslang::EOpSubgroupPartitionedMin:8963case glslang::EOpSubgroupPartitionedMax:8964case glslang::EOpSubgroupPartitionedAnd:8965case glslang::EOpSubgroupPartitionedOr:8966case glslang::EOpSubgroupPartitionedXor:8967case glslang::EOpSubgroupPartitionedInclusiveAdd:8968case glslang::EOpSubgroupPartitionedInclusiveMul:8969case glslang::EOpSubgroupPartitionedInclusiveMin:8970case glslang::EOpSubgroupPartitionedInclusiveMax:8971case glslang::EOpSubgroupPartitionedInclusiveAnd:8972case glslang::EOpSubgroupPartitionedInclusiveOr:8973case glslang::EOpSubgroupPartitionedInclusiveXor:8974case glslang::EOpSubgroupPartitionedExclusiveAdd:8975case glslang::EOpSubgroupPartitionedExclusiveMul:8976case glslang::EOpSubgroupPartitionedExclusiveMin:8977case glslang::EOpSubgroupPartitionedExclusiveMax:8978case glslang::EOpSubgroupPartitionedExclusiveAnd:8979case glslang::EOpSubgroupPartitionedExclusiveOr:8980case glslang::EOpSubgroupPartitionedExclusiveXor:8981return createSubgroupOperation(op, typeId, operands, typeProxy);89828983case glslang::EOpSwizzleInvocations:8984extBuiltins = getExtBuiltins(spv::E_SPV_AMD_shader_ballot);8985libCall = spv::SwizzleInvocationsAMD;8986break;8987case glslang::EOpSwizzleInvocationsMasked:8988extBuiltins = getExtBuiltins(spv::E_SPV_AMD_shader_ballot);8989libCall = spv::SwizzleInvocationsMaskedAMD;8990break;8991case glslang::EOpWriteInvocation:8992extBuiltins = getExtBuiltins(spv::E_SPV_AMD_shader_ballot);8993libCall = spv::WriteInvocationAMD;8994break;89958996case glslang::EOpMin3:8997extBuiltins = getExtBuiltins(spv::E_SPV_AMD_shader_trinary_minmax);8998if (isFloat)8999libCall = spv::FMin3AMD;9000else {9001if (isUnsigned)9002libCall = spv::UMin3AMD;9003else9004libCall = spv::SMin3AMD;9005}9006break;9007case glslang::EOpMax3:9008extBuiltins = getExtBuiltins(spv::E_SPV_AMD_shader_trinary_minmax);9009if (isFloat)9010libCall = spv::FMax3AMD;9011else {9012if (isUnsigned)9013libCall = spv::UMax3AMD;9014else9015libCall = spv::SMax3AMD;9016}9017break;9018case glslang::EOpMid3:9019extBuiltins = getExtBuiltins(spv::E_SPV_AMD_shader_trinary_minmax);9020if (isFloat)9021libCall = spv::FMid3AMD;9022else {9023if (isUnsigned)9024libCall = spv::UMid3AMD;9025else9026libCall = spv::SMid3AMD;9027}9028break;90299030case glslang::EOpInterpolateAtVertex:9031if (typeProxy == glslang::EbtFloat16)9032builder.addExtension(spv::E_SPV_AMD_gpu_shader_half_float);9033extBuiltins = getExtBuiltins(spv::E_SPV_AMD_shader_explicit_vertex_parameter);9034libCall = spv::InterpolateAtVertexAMD;9035break;90369037case glslang::EOpReportIntersection:9038typeId = builder.makeBoolType();9039opCode = spv::OpReportIntersectionKHR;9040break;9041case glslang::EOpTraceNV:9042builder.createNoResultOp(spv::OpTraceNV, operands);9043return 0;9044case glslang::EOpTraceRayMotionNV:9045builder.addExtension(spv::E_SPV_NV_ray_tracing_motion_blur);9046builder.addCapability(spv::CapabilityRayTracingMotionBlurNV);9047builder.createNoResultOp(spv::OpTraceRayMotionNV, operands);9048return 0;9049case glslang::EOpTraceKHR:9050builder.createNoResultOp(spv::OpTraceRayKHR, operands);9051return 0;9052case glslang::EOpExecuteCallableNV:9053builder.createNoResultOp(spv::OpExecuteCallableNV, operands);9054return 0;9055case glslang::EOpExecuteCallableKHR:9056builder.createNoResultOp(spv::OpExecuteCallableKHR, operands);9057return 0;90589059case glslang::EOpRayQueryInitialize:9060builder.createNoResultOp(spv::OpRayQueryInitializeKHR, operands);9061return 0;9062case glslang::EOpRayQueryTerminate:9063builder.createNoResultOp(spv::OpRayQueryTerminateKHR, operands);9064return 0;9065case glslang::EOpRayQueryGenerateIntersection:9066builder.createNoResultOp(spv::OpRayQueryGenerateIntersectionKHR, operands);9067return 0;9068case glslang::EOpRayQueryConfirmIntersection:9069builder.createNoResultOp(spv::OpRayQueryConfirmIntersectionKHR, operands);9070return 0;9071case glslang::EOpRayQueryProceed:9072typeId = builder.makeBoolType();9073opCode = spv::OpRayQueryProceedKHR;9074break;9075case glslang::EOpRayQueryGetIntersectionType:9076typeId = builder.makeUintType(32);9077opCode = spv::OpRayQueryGetIntersectionTypeKHR;9078break;9079case glslang::EOpRayQueryGetRayTMin:9080typeId = builder.makeFloatType(32);9081opCode = spv::OpRayQueryGetRayTMinKHR;9082break;9083case glslang::EOpRayQueryGetRayFlags:9084typeId = builder.makeIntType(32);9085opCode = spv::OpRayQueryGetRayFlagsKHR;9086break;9087case glslang::EOpRayQueryGetIntersectionT:9088typeId = builder.makeFloatType(32);9089opCode = spv::OpRayQueryGetIntersectionTKHR;9090break;9091case glslang::EOpRayQueryGetIntersectionInstanceCustomIndex:9092typeId = builder.makeIntType(32);9093opCode = spv::OpRayQueryGetIntersectionInstanceCustomIndexKHR;9094break;9095case glslang::EOpRayQueryGetIntersectionInstanceId:9096typeId = builder.makeIntType(32);9097opCode = spv::OpRayQueryGetIntersectionInstanceIdKHR;9098break;9099case glslang::EOpRayQueryGetIntersectionInstanceShaderBindingTableRecordOffset:9100typeId = builder.makeUintType(32);9101opCode = spv::OpRayQueryGetIntersectionInstanceShaderBindingTableRecordOffsetKHR;9102break;9103case glslang::EOpRayQueryGetIntersectionGeometryIndex:9104typeId = builder.makeIntType(32);9105opCode = spv::OpRayQueryGetIntersectionGeometryIndexKHR;9106break;9107case glslang::EOpRayQueryGetIntersectionPrimitiveIndex:9108typeId = builder.makeIntType(32);9109opCode = spv::OpRayQueryGetIntersectionPrimitiveIndexKHR;9110break;9111case glslang::EOpRayQueryGetIntersectionBarycentrics:9112typeId = builder.makeVectorType(builder.makeFloatType(32), 2);9113opCode = spv::OpRayQueryGetIntersectionBarycentricsKHR;9114break;9115case glslang::EOpRayQueryGetIntersectionFrontFace:9116typeId = builder.makeBoolType();9117opCode = spv::OpRayQueryGetIntersectionFrontFaceKHR;9118break;9119case glslang::EOpRayQueryGetIntersectionCandidateAABBOpaque:9120typeId = builder.makeBoolType();9121opCode = spv::OpRayQueryGetIntersectionCandidateAABBOpaqueKHR;9122break;9123case glslang::EOpRayQueryGetIntersectionObjectRayDirection:9124typeId = builder.makeVectorType(builder.makeFloatType(32), 3);9125opCode = spv::OpRayQueryGetIntersectionObjectRayDirectionKHR;9126break;9127case glslang::EOpRayQueryGetIntersectionObjectRayOrigin:9128typeId = builder.makeVectorType(builder.makeFloatType(32), 3);9129opCode = spv::OpRayQueryGetIntersectionObjectRayOriginKHR;9130break;9131case glslang::EOpRayQueryGetWorldRayDirection:9132typeId = builder.makeVectorType(builder.makeFloatType(32), 3);9133opCode = spv::OpRayQueryGetWorldRayDirectionKHR;9134break;9135case glslang::EOpRayQueryGetWorldRayOrigin:9136typeId = builder.makeVectorType(builder.makeFloatType(32), 3);9137opCode = spv::OpRayQueryGetWorldRayOriginKHR;9138break;9139case glslang::EOpRayQueryGetIntersectionObjectToWorld:9140typeId = builder.makeMatrixType(builder.makeFloatType(32), 4, 3);9141opCode = spv::OpRayQueryGetIntersectionObjectToWorldKHR;9142break;9143case glslang::EOpRayQueryGetIntersectionWorldToObject:9144typeId = builder.makeMatrixType(builder.makeFloatType(32), 4, 3);9145opCode = spv::OpRayQueryGetIntersectionWorldToObjectKHR;9146break;9147case glslang::EOpWritePackedPrimitiveIndices4x8NV:9148builder.createNoResultOp(spv::OpWritePackedPrimitiveIndices4x8NV, operands);9149return 0;9150case glslang::EOpEmitMeshTasksEXT:9151if (taskPayloadID)9152operands.push_back(taskPayloadID);9153// As per SPV_EXT_mesh_shader make it a terminating instruction in the current block9154builder.makeStatementTerminator(spv::OpEmitMeshTasksEXT, operands, "post-OpEmitMeshTasksEXT");9155return 0;9156case glslang::EOpSetMeshOutputsEXT:9157builder.createNoResultOp(spv::OpSetMeshOutputsEXT, operands);9158return 0;9159case glslang::EOpCooperativeMatrixMulAddNV:9160opCode = spv::OpCooperativeMatrixMulAddNV;9161break;9162case glslang::EOpHitObjectTraceRayNV:9163builder.createNoResultOp(spv::OpHitObjectTraceRayNV, operands);9164return 0;9165case glslang::EOpHitObjectTraceRayMotionNV:9166builder.createNoResultOp(spv::OpHitObjectTraceRayMotionNV, operands);9167return 0;9168case glslang::EOpHitObjectRecordHitNV:9169builder.createNoResultOp(spv::OpHitObjectRecordHitNV, operands);9170return 0;9171case glslang::EOpHitObjectRecordHitMotionNV:9172builder.createNoResultOp(spv::OpHitObjectRecordHitMotionNV, operands);9173return 0;9174case glslang::EOpHitObjectRecordHitWithIndexNV:9175builder.createNoResultOp(spv::OpHitObjectRecordHitWithIndexNV, operands);9176return 0;9177case glslang::EOpHitObjectRecordHitWithIndexMotionNV:9178builder.createNoResultOp(spv::OpHitObjectRecordHitWithIndexMotionNV, operands);9179return 0;9180case glslang::EOpHitObjectRecordMissNV:9181builder.createNoResultOp(spv::OpHitObjectRecordMissNV, operands);9182return 0;9183case glslang::EOpHitObjectRecordMissMotionNV:9184builder.createNoResultOp(spv::OpHitObjectRecordMissMotionNV, operands);9185return 0;9186case glslang::EOpHitObjectExecuteShaderNV:9187builder.createNoResultOp(spv::OpHitObjectExecuteShaderNV, operands);9188return 0;9189case glslang::EOpHitObjectIsEmptyNV:9190typeId = builder.makeBoolType();9191opCode = spv::OpHitObjectIsEmptyNV;9192break;9193case glslang::EOpHitObjectIsMissNV:9194typeId = builder.makeBoolType();9195opCode = spv::OpHitObjectIsMissNV;9196break;9197case glslang::EOpHitObjectIsHitNV:9198typeId = builder.makeBoolType();9199opCode = spv::OpHitObjectIsHitNV;9200break;9201case glslang::EOpHitObjectGetRayTMinNV:9202typeId = builder.makeFloatType(32);9203opCode = spv::OpHitObjectGetRayTMinNV;9204break;9205case glslang::EOpHitObjectGetRayTMaxNV:9206typeId = builder.makeFloatType(32);9207opCode = spv::OpHitObjectGetRayTMaxNV;9208break;9209case glslang::EOpHitObjectGetObjectRayOriginNV:9210typeId = builder.makeVectorType(builder.makeFloatType(32), 3);9211opCode = spv::OpHitObjectGetObjectRayOriginNV;9212break;9213case glslang::EOpHitObjectGetObjectRayDirectionNV:9214typeId = builder.makeVectorType(builder.makeFloatType(32), 3);9215opCode = spv::OpHitObjectGetObjectRayDirectionNV;9216break;9217case glslang::EOpHitObjectGetWorldRayOriginNV:9218typeId = builder.makeVectorType(builder.makeFloatType(32), 3);9219opCode = spv::OpHitObjectGetWorldRayOriginNV;9220break;9221case glslang::EOpHitObjectGetWorldRayDirectionNV:9222typeId = builder.makeVectorType(builder.makeFloatType(32), 3);9223opCode = spv::OpHitObjectGetWorldRayDirectionNV;9224break;9225case glslang::EOpHitObjectGetWorldToObjectNV:9226typeId = builder.makeMatrixType(builder.makeFloatType(32), 4, 3);9227opCode = spv::OpHitObjectGetWorldToObjectNV;9228break;9229case glslang::EOpHitObjectGetObjectToWorldNV:9230typeId = builder.makeMatrixType(builder.makeFloatType(32), 4, 3);9231opCode = spv::OpHitObjectGetObjectToWorldNV;9232break;9233case glslang::EOpHitObjectGetInstanceCustomIndexNV:9234typeId = builder.makeIntegerType(32, 1);9235opCode = spv::OpHitObjectGetInstanceCustomIndexNV;9236break;9237case glslang::EOpHitObjectGetInstanceIdNV:9238typeId = builder.makeIntegerType(32, 1);9239opCode = spv::OpHitObjectGetInstanceIdNV;9240break;9241case glslang::EOpHitObjectGetGeometryIndexNV:9242typeId = builder.makeIntegerType(32, 1);9243opCode = spv::OpHitObjectGetGeometryIndexNV;9244break;9245case glslang::EOpHitObjectGetPrimitiveIndexNV:9246typeId = builder.makeIntegerType(32, 1);9247opCode = spv::OpHitObjectGetPrimitiveIndexNV;9248break;9249case glslang::EOpHitObjectGetHitKindNV:9250typeId = builder.makeIntegerType(32, 0);9251opCode = spv::OpHitObjectGetHitKindNV;9252break;9253case glslang::EOpHitObjectGetCurrentTimeNV:9254typeId = builder.makeFloatType(32);9255opCode = spv::OpHitObjectGetCurrentTimeNV;9256break;9257case glslang::EOpHitObjectGetShaderBindingTableRecordIndexNV:9258typeId = builder.makeIntegerType(32, 0);9259opCode = spv::OpHitObjectGetShaderBindingTableRecordIndexNV;9260return 0;9261case glslang::EOpHitObjectGetAttributesNV:9262builder.createNoResultOp(spv::OpHitObjectGetAttributesNV, operands);9263return 0;9264case glslang::EOpHitObjectGetShaderRecordBufferHandleNV:9265typeId = builder.makeVectorType(builder.makeUintType(32), 2);9266opCode = spv::OpHitObjectGetShaderRecordBufferHandleNV;9267break;9268case glslang::EOpReorderThreadNV: {9269if (operands.size() == 2) {9270builder.createNoResultOp(spv::OpReorderThreadWithHintNV, operands);9271} else {9272builder.createNoResultOp(spv::OpReorderThreadWithHitObjectNV, operands);9273}9274return 0;92759276}92779278case glslang::EOpImageSampleWeightedQCOM:9279typeId = builder.makeVectorType(builder.makeFloatType(32), 4);9280opCode = spv::OpImageSampleWeightedQCOM;9281addImageProcessingQCOMDecoration(operands[2], spv::DecorationWeightTextureQCOM);9282break;9283case glslang::EOpImageBoxFilterQCOM:9284typeId = builder.makeVectorType(builder.makeFloatType(32), 4);9285opCode = spv::OpImageBoxFilterQCOM;9286break;9287case glslang::EOpImageBlockMatchSADQCOM:9288typeId = builder.makeVectorType(builder.makeFloatType(32), 4);9289opCode = spv::OpImageBlockMatchSADQCOM;9290addImageProcessingQCOMDecoration(operands[0], spv::DecorationBlockMatchTextureQCOM);9291addImageProcessingQCOMDecoration(operands[2], spv::DecorationBlockMatchTextureQCOM);9292break;9293case glslang::EOpImageBlockMatchSSDQCOM:9294typeId = builder.makeVectorType(builder.makeFloatType(32), 4);9295opCode = spv::OpImageBlockMatchSSDQCOM;9296addImageProcessingQCOMDecoration(operands[0], spv::DecorationBlockMatchTextureQCOM);9297addImageProcessingQCOMDecoration(operands[2], spv::DecorationBlockMatchTextureQCOM);9298break;92999300case glslang::EOpFetchMicroTriangleVertexBarycentricNV:9301typeId = builder.makeVectorType(builder.makeFloatType(32), 2);9302opCode = spv::OpFetchMicroTriangleVertexBarycentricNV;9303break;93049305case glslang::EOpFetchMicroTriangleVertexPositionNV:9306typeId = builder.makeVectorType(builder.makeFloatType(32), 3);9307opCode = spv::OpFetchMicroTriangleVertexPositionNV;9308break;93099310case glslang::EOpImageBlockMatchWindowSSDQCOM:9311typeId = builder.makeVectorType(builder.makeFloatType(32), 4);9312opCode = spv::OpImageBlockMatchWindowSSDQCOM;9313addImageProcessing2QCOMDecoration(operands[0], false);9314addImageProcessing2QCOMDecoration(operands[2], false);9315break;9316case glslang::EOpImageBlockMatchWindowSADQCOM:9317typeId = builder.makeVectorType(builder.makeFloatType(32), 4);9318opCode = spv::OpImageBlockMatchWindowSADQCOM;9319addImageProcessing2QCOMDecoration(operands[0], false);9320addImageProcessing2QCOMDecoration(operands[2], false);9321break;9322case glslang::EOpImageBlockMatchGatherSSDQCOM:9323typeId = builder.makeVectorType(builder.makeFloatType(32), 4);9324opCode = spv::OpImageBlockMatchGatherSSDQCOM;9325addImageProcessing2QCOMDecoration(operands[0], true);9326addImageProcessing2QCOMDecoration(operands[2], true);9327break;9328case glslang::EOpImageBlockMatchGatherSADQCOM:9329typeId = builder.makeVectorType(builder.makeFloatType(32), 4);9330opCode = spv::OpImageBlockMatchGatherSADQCOM;9331addImageProcessing2QCOMDecoration(operands[0], true);9332addImageProcessing2QCOMDecoration(operands[2], true);9333break;9334default:9335return 0;9336}93379338spv::Id id = 0;9339if (libCall >= 0) {9340// Use an extended instruction from the standard library.9341// Construct the call arguments, without modifying the original operands vector.9342// We might need the remaining arguments, e.g. in the EOpFrexp case.9343std::vector<spv::Id> callArguments(operands.begin(), operands.begin() + consumedOperands);9344id = builder.createBuiltinCall(typeId, extBuiltins >= 0 ? extBuiltins : stdBuiltins, libCall, callArguments);9345} else if (opCode == spv::OpDot && !isFloat) {9346// int dot(int, int)9347// NOTE: never called for scalar/vector1, this is turned into simple mul before this can be reached9348const int componentCount = builder.getNumComponents(operands[0]);9349spv::Id mulOp = builder.createBinOp(spv::OpIMul, builder.getTypeId(operands[0]), operands[0], operands[1]);9350builder.setPrecision(mulOp, precision);9351id = builder.createCompositeExtract(mulOp, typeId, 0);9352for (int i = 1; i < componentCount; ++i) {9353builder.setPrecision(id, precision);9354id = builder.createBinOp(spv::OpIAdd, typeId, id, builder.createCompositeExtract(mulOp, typeId, i));9355}9356} else {9357switch (consumedOperands) {9358case 0:9359// should all be handled by visitAggregate and createNoArgOperation9360assert(0);9361return 0;9362case 1:9363// should all be handled by createUnaryOperation9364assert(0);9365return 0;9366case 2:9367id = builder.createBinOp(opCode, typeId, operands[0], operands[1]);9368break;9369default:9370// anything 3 or over doesn't have l-value operands, so all should be consumed9371assert(consumedOperands == operands.size());9372id = builder.createOp(opCode, typeId, operands);9373break;9374}9375}93769377// Decode the return types that were structures9378switch (op) {9379case glslang::EOpAddCarry:9380case glslang::EOpSubBorrow:9381builder.createStore(builder.createCompositeExtract(id, typeId0, 1), operands[2]);9382id = builder.createCompositeExtract(id, typeId0, 0);9383break;9384case glslang::EOpUMulExtended:9385case glslang::EOpIMulExtended:9386builder.createStore(builder.createCompositeExtract(id, typeId0, 0), operands[3]);9387builder.createStore(builder.createCompositeExtract(id, typeId0, 1), operands[2]);9388break;9389case glslang::EOpFrexp:9390{9391assert(operands.size() == 2);9392if (builder.isFloatType(builder.getScalarTypeId(typeId1))) {9393// "exp" is floating-point type (from HLSL intrinsic)9394spv::Id member1 = builder.createCompositeExtract(id, frexpIntType, 1);9395member1 = builder.createUnaryOp(spv::OpConvertSToF, typeId1, member1);9396builder.createStore(member1, operands[1]);9397} else9398// "exp" is integer type (from GLSL built-in function)9399builder.createStore(builder.createCompositeExtract(id, frexpIntType, 1), operands[1]);9400id = builder.createCompositeExtract(id, typeId0, 0);9401}9402break;9403default:9404break;9405}94069407return builder.setPrecision(id, precision);9408}94099410// Intrinsics with no arguments (or no return value, and no precision).9411spv::Id TGlslangToSpvTraverser::createNoArgOperation(glslang::TOperator op, spv::Decoration precision, spv::Id typeId)9412{9413// GLSL memory barriers use queuefamily scope in new model, device scope in old model9414spv::Scope memoryBarrierScope = glslangIntermediate->usingVulkanMemoryModel() ?9415spv::ScopeQueueFamilyKHR : spv::ScopeDevice;94169417switch (op) {9418case glslang::EOpBarrier:9419if (glslangIntermediate->getStage() == EShLangTessControl) {9420if (glslangIntermediate->usingVulkanMemoryModel()) {9421builder.createControlBarrier(spv::ScopeWorkgroup, spv::ScopeWorkgroup,9422spv::MemorySemanticsOutputMemoryKHRMask |9423spv::MemorySemanticsAcquireReleaseMask);9424builder.addCapability(spv::CapabilityVulkanMemoryModelKHR);9425} else {9426builder.createControlBarrier(spv::ScopeWorkgroup, spv::ScopeInvocation, spv::MemorySemanticsMaskNone);9427}9428} else {9429builder.createControlBarrier(spv::ScopeWorkgroup, spv::ScopeWorkgroup,9430spv::MemorySemanticsWorkgroupMemoryMask |9431spv::MemorySemanticsAcquireReleaseMask);9432}9433return 0;9434case glslang::EOpMemoryBarrier:9435builder.createMemoryBarrier(memoryBarrierScope, spv::MemorySemanticsAllMemory |9436spv::MemorySemanticsAcquireReleaseMask);9437return 0;9438case glslang::EOpMemoryBarrierBuffer:9439builder.createMemoryBarrier(memoryBarrierScope, spv::MemorySemanticsUniformMemoryMask |9440spv::MemorySemanticsAcquireReleaseMask);9441return 0;9442case glslang::EOpMemoryBarrierShared:9443builder.createMemoryBarrier(memoryBarrierScope, spv::MemorySemanticsWorkgroupMemoryMask |9444spv::MemorySemanticsAcquireReleaseMask);9445return 0;9446case glslang::EOpGroupMemoryBarrier:9447builder.createMemoryBarrier(spv::ScopeWorkgroup, spv::MemorySemanticsAllMemory |9448spv::MemorySemanticsAcquireReleaseMask);9449return 0;9450case glslang::EOpMemoryBarrierAtomicCounter:9451builder.createMemoryBarrier(memoryBarrierScope, spv::MemorySemanticsAtomicCounterMemoryMask |9452spv::MemorySemanticsAcquireReleaseMask);9453return 0;9454case glslang::EOpMemoryBarrierImage:9455builder.createMemoryBarrier(memoryBarrierScope, spv::MemorySemanticsImageMemoryMask |9456spv::MemorySemanticsAcquireReleaseMask);9457return 0;9458case glslang::EOpAllMemoryBarrierWithGroupSync:9459builder.createControlBarrier(spv::ScopeWorkgroup, spv::ScopeDevice,9460spv::MemorySemanticsAllMemory |9461spv::MemorySemanticsAcquireReleaseMask);9462return 0;9463case glslang::EOpDeviceMemoryBarrier:9464builder.createMemoryBarrier(spv::ScopeDevice, spv::MemorySemanticsUniformMemoryMask |9465spv::MemorySemanticsImageMemoryMask |9466spv::MemorySemanticsAcquireReleaseMask);9467return 0;9468case glslang::EOpDeviceMemoryBarrierWithGroupSync:9469builder.createControlBarrier(spv::ScopeWorkgroup, spv::ScopeDevice, spv::MemorySemanticsUniformMemoryMask |9470spv::MemorySemanticsImageMemoryMask |9471spv::MemorySemanticsAcquireReleaseMask);9472return 0;9473case glslang::EOpWorkgroupMemoryBarrier:9474builder.createMemoryBarrier(spv::ScopeWorkgroup, spv::MemorySemanticsWorkgroupMemoryMask |9475spv::MemorySemanticsAcquireReleaseMask);9476return 0;9477case glslang::EOpWorkgroupMemoryBarrierWithGroupSync:9478builder.createControlBarrier(spv::ScopeWorkgroup, spv::ScopeWorkgroup,9479spv::MemorySemanticsWorkgroupMemoryMask |9480spv::MemorySemanticsAcquireReleaseMask);9481return 0;9482case glslang::EOpSubgroupBarrier:9483builder.createControlBarrier(spv::ScopeSubgroup, spv::ScopeSubgroup, spv::MemorySemanticsAllMemory |9484spv::MemorySemanticsAcquireReleaseMask);9485return spv::NoResult;9486case glslang::EOpSubgroupMemoryBarrier:9487builder.createMemoryBarrier(spv::ScopeSubgroup, spv::MemorySemanticsAllMemory |9488spv::MemorySemanticsAcquireReleaseMask);9489return spv::NoResult;9490case glslang::EOpSubgroupMemoryBarrierBuffer:9491builder.createMemoryBarrier(spv::ScopeSubgroup, spv::MemorySemanticsUniformMemoryMask |9492spv::MemorySemanticsAcquireReleaseMask);9493return spv::NoResult;9494case glslang::EOpSubgroupMemoryBarrierImage:9495builder.createMemoryBarrier(spv::ScopeSubgroup, spv::MemorySemanticsImageMemoryMask |9496spv::MemorySemanticsAcquireReleaseMask);9497return spv::NoResult;9498case glslang::EOpSubgroupMemoryBarrierShared:9499builder.createMemoryBarrier(spv::ScopeSubgroup, spv::MemorySemanticsWorkgroupMemoryMask |9500spv::MemorySemanticsAcquireReleaseMask);9501return spv::NoResult;95029503case glslang::EOpEmitVertex:9504builder.createNoResultOp(spv::OpEmitVertex);9505return 0;9506case glslang::EOpEndPrimitive:9507builder.createNoResultOp(spv::OpEndPrimitive);9508return 0;95099510case glslang::EOpSubgroupElect: {9511std::vector<spv::Id> operands;9512return createSubgroupOperation(op, typeId, operands, glslang::EbtVoid);9513}9514case glslang::EOpTime:9515{9516std::vector<spv::Id> args; // Dummy arguments9517spv::Id id = builder.createBuiltinCall(typeId, getExtBuiltins(spv::E_SPV_AMD_gcn_shader), spv::TimeAMD, args);9518return builder.setPrecision(id, precision);9519}9520case glslang::EOpIgnoreIntersectionNV:9521builder.createNoResultOp(spv::OpIgnoreIntersectionNV);9522return 0;9523case glslang::EOpTerminateRayNV:9524builder.createNoResultOp(spv::OpTerminateRayNV);9525return 0;9526case glslang::EOpRayQueryInitialize:9527builder.createNoResultOp(spv::OpRayQueryInitializeKHR);9528return 0;9529case glslang::EOpRayQueryTerminate:9530builder.createNoResultOp(spv::OpRayQueryTerminateKHR);9531return 0;9532case glslang::EOpRayQueryGenerateIntersection:9533builder.createNoResultOp(spv::OpRayQueryGenerateIntersectionKHR);9534return 0;9535case glslang::EOpRayQueryConfirmIntersection:9536builder.createNoResultOp(spv::OpRayQueryConfirmIntersectionKHR);9537return 0;9538case glslang::EOpBeginInvocationInterlock:9539builder.createNoResultOp(spv::OpBeginInvocationInterlockEXT);9540return 0;9541case glslang::EOpEndInvocationInterlock:9542builder.createNoResultOp(spv::OpEndInvocationInterlockEXT);9543return 0;95449545case glslang::EOpIsHelperInvocation:9546{9547std::vector<spv::Id> args; // Dummy arguments9548builder.addExtension(spv::E_SPV_EXT_demote_to_helper_invocation);9549builder.addCapability(spv::CapabilityDemoteToHelperInvocationEXT);9550return builder.createOp(spv::OpIsHelperInvocationEXT, typeId, args);9551}95529553case glslang::EOpReadClockSubgroupKHR: {9554std::vector<spv::Id> args;9555args.push_back(builder.makeUintConstant(spv::ScopeSubgroup));9556builder.addExtension(spv::E_SPV_KHR_shader_clock);9557builder.addCapability(spv::CapabilityShaderClockKHR);9558return builder.createOp(spv::OpReadClockKHR, typeId, args);9559}95609561case glslang::EOpReadClockDeviceKHR: {9562std::vector<spv::Id> args;9563args.push_back(builder.makeUintConstant(spv::ScopeDevice));9564builder.addExtension(spv::E_SPV_KHR_shader_clock);9565builder.addCapability(spv::CapabilityShaderClockKHR);9566return builder.createOp(spv::OpReadClockKHR, typeId, args);9567}9568case glslang::EOpStencilAttachmentReadEXT:9569case glslang::EOpDepthAttachmentReadEXT:9570{9571builder.addExtension(spv::E_SPV_EXT_shader_tile_image);95729573spv::Decoration precision;9574spv::Op spv_op;9575if (op == glslang::EOpStencilAttachmentReadEXT)9576{9577precision = spv::DecorationRelaxedPrecision;9578spv_op = spv::OpStencilAttachmentReadEXT;9579builder.addCapability(spv::CapabilityTileImageStencilReadAccessEXT);9580}9581else9582{9583precision = spv::NoPrecision;9584spv_op = spv::OpDepthAttachmentReadEXT;9585builder.addCapability(spv::CapabilityTileImageDepthReadAccessEXT);9586}95879588std::vector<spv::Id> args; // Dummy args9589spv::Id result = builder.createOp(spv_op, typeId, args);9590return builder.setPrecision(result, precision);9591}9592default:9593break;9594}95959596logger->missingFunctionality("unknown operation with no arguments");95979598return 0;9599}96009601spv::Id TGlslangToSpvTraverser::getSymbolId(const glslang::TIntermSymbol* symbol)9602{9603auto iter = symbolValues.find(symbol->getId());9604spv::Id id;9605if (symbolValues.end() != iter) {9606id = iter->second;9607return id;9608}96099610// it was not found, create it9611spv::BuiltIn builtIn = TranslateBuiltInDecoration(symbol->getQualifier().builtIn, false);9612auto forcedType = getForcedType(symbol->getQualifier().builtIn, symbol->getType());96139614// There are pairs of symbols that map to the same SPIR-V built-in:9615// gl_ObjectToWorldEXT and gl_ObjectToWorld3x4EXT, and gl_WorldToObjectEXT9616// and gl_WorldToObject3x4EXT. SPIR-V forbids having two OpVariables9617// with the same BuiltIn in the same storage class, so we must re-use one.9618const bool mayNeedToReuseBuiltIn =9619builtIn == spv::BuiltInObjectToWorldKHR ||9620builtIn == spv::BuiltInWorldToObjectKHR;96219622if (mayNeedToReuseBuiltIn) {9623auto iter = builtInVariableIds.find(uint32_t(builtIn));9624if (builtInVariableIds.end() != iter) {9625id = iter->second;9626symbolValues[symbol->getId()] = id;9627if (forcedType.second != spv::NoType)9628forceType[id] = forcedType.second;9629return id;9630}9631}96329633id = createSpvVariable(symbol, forcedType.first);96349635if (mayNeedToReuseBuiltIn) {9636builtInVariableIds.insert({uint32_t(builtIn), id});9637}96389639symbolValues[symbol->getId()] = id;9640if (forcedType.second != spv::NoType)9641forceType[id] = forcedType.second;96429643if (symbol->getBasicType() != glslang::EbtBlock) {9644builder.addDecoration(id, TranslatePrecisionDecoration(symbol->getType()));9645builder.addDecoration(id, TranslateInterpolationDecoration(symbol->getType().getQualifier()));9646builder.addDecoration(id, TranslateAuxiliaryStorageDecoration(symbol->getType().getQualifier()));9647addMeshNVDecoration(id, /*member*/ -1, symbol->getType().getQualifier());9648if (symbol->getQualifier().hasComponent())9649builder.addDecoration(id, spv::DecorationComponent, symbol->getQualifier().layoutComponent);9650if (symbol->getQualifier().hasIndex())9651builder.addDecoration(id, spv::DecorationIndex, symbol->getQualifier().layoutIndex);9652if (symbol->getType().getQualifier().hasSpecConstantId())9653builder.addDecoration(id, spv::DecorationSpecId, symbol->getType().getQualifier().layoutSpecConstantId);9654// atomic counters use this:9655if (symbol->getQualifier().hasOffset())9656builder.addDecoration(id, spv::DecorationOffset, symbol->getQualifier().layoutOffset);9657}96589659if (symbol->getQualifier().hasLocation()) {9660if (!(glslangIntermediate->isRayTracingStage() &&9661(glslangIntermediate->IsRequestedExtension(glslang::E_GL_EXT_ray_tracing) ||9662glslangIntermediate->IsRequestedExtension(glslang::E_GL_NV_shader_invocation_reorder))9663&& (builder.getStorageClass(id) == spv::StorageClassRayPayloadKHR ||9664builder.getStorageClass(id) == spv::StorageClassIncomingRayPayloadKHR ||9665builder.getStorageClass(id) == spv::StorageClassCallableDataKHR ||9666builder.getStorageClass(id) == spv::StorageClassIncomingCallableDataKHR ||9667builder.getStorageClass(id) == spv::StorageClassHitObjectAttributeNV))) {9668// Location values are used to link TraceRayKHR/ExecuteCallableKHR/HitObjectGetAttributesNV9669// to corresponding variables but are not valid in SPIRV since they are supported only9670// for Input/Output Storage classes.9671builder.addDecoration(id, spv::DecorationLocation, symbol->getQualifier().layoutLocation);9672}9673}96749675builder.addDecoration(id, TranslateInvariantDecoration(symbol->getType().getQualifier()));9676if (symbol->getQualifier().hasStream() && glslangIntermediate->isMultiStream()) {9677builder.addCapability(spv::CapabilityGeometryStreams);9678builder.addDecoration(id, spv::DecorationStream, symbol->getQualifier().layoutStream);9679}9680if (symbol->getQualifier().hasSet())9681builder.addDecoration(id, spv::DecorationDescriptorSet, symbol->getQualifier().layoutSet);9682else if (IsDescriptorResource(symbol->getType())) {9683// default to 09684builder.addDecoration(id, spv::DecorationDescriptorSet, 0);9685}9686if (symbol->getQualifier().hasBinding())9687builder.addDecoration(id, spv::DecorationBinding, symbol->getQualifier().layoutBinding);9688else if (IsDescriptorResource(symbol->getType())) {9689// default to 09690builder.addDecoration(id, spv::DecorationBinding, 0);9691}9692if (symbol->getQualifier().hasAttachment())9693builder.addDecoration(id, spv::DecorationInputAttachmentIndex, symbol->getQualifier().layoutAttachment);9694if (glslangIntermediate->getXfbMode()) {9695builder.addCapability(spv::CapabilityTransformFeedback);9696if (symbol->getQualifier().hasXfbBuffer()) {9697builder.addDecoration(id, spv::DecorationXfbBuffer, symbol->getQualifier().layoutXfbBuffer);9698unsigned stride = glslangIntermediate->getXfbStride(symbol->getQualifier().layoutXfbBuffer);9699if (stride != glslang::TQualifier::layoutXfbStrideEnd)9700builder.addDecoration(id, spv::DecorationXfbStride, stride);9701}9702if (symbol->getQualifier().hasXfbOffset())9703builder.addDecoration(id, spv::DecorationOffset, symbol->getQualifier().layoutXfbOffset);9704}97059706// add built-in variable decoration9707if (builtIn != spv::BuiltInMax) {9708// WorkgroupSize deprecated in spirv1.69709if (glslangIntermediate->getSpv().spv < glslang::EShTargetSpv_1_6 ||9710builtIn != spv::BuiltInWorkgroupSize)9711builder.addDecoration(id, spv::DecorationBuiltIn, (int)builtIn);9712}97139714// Add volatile decoration to HelperInvocation for spirv1.6 and beyond9715if (builtIn == spv::BuiltInHelperInvocation &&9716!glslangIntermediate->usingVulkanMemoryModel() &&9717glslangIntermediate->getSpv().spv >= glslang::EShTargetSpv_1_6) {9718builder.addDecoration(id, spv::DecorationVolatile);9719}97209721// Subgroup builtins which have input storage class are volatile for ray tracing stages.9722if (symbol->getType().isImage() || symbol->getQualifier().isPipeInput()) {9723std::vector<spv::Decoration> memory;9724TranslateMemoryDecoration(symbol->getType().getQualifier(), memory,9725glslangIntermediate->usingVulkanMemoryModel());9726for (unsigned int i = 0; i < memory.size(); ++i)9727builder.addDecoration(id, memory[i]);9728}97299730if (builtIn == spv::BuiltInSampleMask) {9731spv::Decoration decoration;9732// GL_NV_sample_mask_override_coverage extension9733if (glslangIntermediate->getLayoutOverrideCoverage())9734decoration = (spv::Decoration)spv::DecorationOverrideCoverageNV;9735else9736decoration = (spv::Decoration)spv::DecorationMax;9737builder.addDecoration(id, decoration);9738if (decoration != spv::DecorationMax) {9739builder.addCapability(spv::CapabilitySampleMaskOverrideCoverageNV);9740builder.addExtension(spv::E_SPV_NV_sample_mask_override_coverage);9741}9742}9743else if (builtIn == spv::BuiltInLayer) {9744// SPV_NV_viewport_array2 extension9745if (symbol->getQualifier().layoutViewportRelative) {9746builder.addDecoration(id, (spv::Decoration)spv::DecorationViewportRelativeNV);9747builder.addCapability(spv::CapabilityShaderViewportMaskNV);9748builder.addExtension(spv::E_SPV_NV_viewport_array2);9749}9750if (symbol->getQualifier().layoutSecondaryViewportRelativeOffset != -2048) {9751builder.addDecoration(id, (spv::Decoration)spv::DecorationSecondaryViewportRelativeNV,9752symbol->getQualifier().layoutSecondaryViewportRelativeOffset);9753builder.addCapability(spv::CapabilityShaderStereoViewNV);9754builder.addExtension(spv::E_SPV_NV_stereo_view_rendering);9755}9756}97579758if (symbol->getQualifier().layoutPassthrough) {9759builder.addDecoration(id, spv::DecorationPassthroughNV);9760builder.addCapability(spv::CapabilityGeometryShaderPassthroughNV);9761builder.addExtension(spv::E_SPV_NV_geometry_shader_passthrough);9762}9763if (symbol->getQualifier().pervertexNV) {9764builder.addDecoration(id, spv::DecorationPerVertexNV);9765builder.addCapability(spv::CapabilityFragmentBarycentricNV);9766builder.addExtension(spv::E_SPV_NV_fragment_shader_barycentric);9767}97689769if (symbol->getQualifier().pervertexEXT) {9770builder.addDecoration(id, spv::DecorationPerVertexKHR);9771builder.addCapability(spv::CapabilityFragmentBarycentricKHR);9772builder.addExtension(spv::E_SPV_KHR_fragment_shader_barycentric);9773}97749775if (glslangIntermediate->getHlslFunctionality1() && symbol->getType().getQualifier().semanticName != nullptr) {9776builder.addExtension("SPV_GOOGLE_hlsl_functionality1");9777builder.addDecoration(id, (spv::Decoration)spv::DecorationHlslSemanticGOOGLE,9778symbol->getType().getQualifier().semanticName);9779}97809781if (symbol->isReference()) {9782builder.addDecoration(id, symbol->getType().getQualifier().restrict ?9783spv::DecorationRestrictPointerEXT : spv::DecorationAliasedPointerEXT);9784}97859786// Add SPIR-V decorations (GL_EXT_spirv_intrinsics)9787if (symbol->getType().getQualifier().hasSpirvDecorate())9788applySpirvDecorate(symbol->getType(), id, {});97899790return id;9791}97929793// add per-primitive, per-view. per-task decorations to a struct member (member >= 0) or an object9794void TGlslangToSpvTraverser::addMeshNVDecoration(spv::Id id, int member, const glslang::TQualifier& qualifier)9795{9796bool isMeshShaderExt = (glslangIntermediate->getRequestedExtensions().find(glslang::E_GL_EXT_mesh_shader) !=9797glslangIntermediate->getRequestedExtensions().end());97989799if (member >= 0) {9800if (qualifier.perPrimitiveNV) {9801// Need to add capability/extension for fragment shader.9802// Mesh shader already adds this by default.9803if (glslangIntermediate->getStage() == EShLangFragment) {9804if(isMeshShaderExt) {9805builder.addCapability(spv::CapabilityMeshShadingEXT);9806builder.addExtension(spv::E_SPV_EXT_mesh_shader);9807} else {9808builder.addCapability(spv::CapabilityMeshShadingNV);9809builder.addExtension(spv::E_SPV_NV_mesh_shader);9810}9811}9812builder.addMemberDecoration(id, (unsigned)member, spv::DecorationPerPrimitiveNV);9813}9814if (qualifier.perViewNV)9815builder.addMemberDecoration(id, (unsigned)member, spv::DecorationPerViewNV);9816if (qualifier.perTaskNV)9817builder.addMemberDecoration(id, (unsigned)member, spv::DecorationPerTaskNV);9818} else {9819if (qualifier.perPrimitiveNV) {9820// Need to add capability/extension for fragment shader.9821// Mesh shader already adds this by default.9822if (glslangIntermediate->getStage() == EShLangFragment) {9823if(isMeshShaderExt) {9824builder.addCapability(spv::CapabilityMeshShadingEXT);9825builder.addExtension(spv::E_SPV_EXT_mesh_shader);9826} else {9827builder.addCapability(spv::CapabilityMeshShadingNV);9828builder.addExtension(spv::E_SPV_NV_mesh_shader);9829}9830}9831builder.addDecoration(id, spv::DecorationPerPrimitiveNV);9832}9833if (qualifier.perViewNV)9834builder.addDecoration(id, spv::DecorationPerViewNV);9835if (qualifier.perTaskNV)9836builder.addDecoration(id, spv::DecorationPerTaskNV);9837}9838}98399840bool TGlslangToSpvTraverser::hasQCOMImageProceessingDecoration(spv::Id id, spv::Decoration decor)9841{9842std::vector<spv::Decoration> &decoVec = idToQCOMDecorations[id];9843for ( auto d : decoVec ) {9844if ( d == decor )9845return true;9846}9847return false;9848}98499850void TGlslangToSpvTraverser::addImageProcessingQCOMDecoration(spv::Id id, spv::Decoration decor)9851{9852spv::Op opc = builder.getOpCode(id);9853if (opc == spv::OpSampledImage) {9854id = builder.getIdOperand(id, 0);9855opc = builder.getOpCode(id);9856}98579858if (opc == spv::OpLoad) {9859spv::Id texid = builder.getIdOperand(id, 0);9860if (!hasQCOMImageProceessingDecoration(texid, decor)) {//9861builder.addDecoration(texid, decor);9862idToQCOMDecorations[texid].push_back(decor);9863}9864}9865}98669867void TGlslangToSpvTraverser::addImageProcessing2QCOMDecoration(spv::Id id, bool isForGather)9868{9869if (isForGather) {9870return addImageProcessingQCOMDecoration(id, spv::DecorationBlockMatchTextureQCOM);9871}98729873auto addDecor =9874[this](spv::Id id, spv::Decoration decor) {9875spv::Id tsopc = this->builder.getOpCode(id);9876if (tsopc == spv::OpLoad) {9877spv::Id tsid = this->builder.getIdOperand(id, 0);9878if (this->glslangIntermediate->getSpv().spv >= glslang::EShTargetSpv_1_4) {9879assert(iOSet.count(tsid) > 0);9880}9881if (!hasQCOMImageProceessingDecoration(tsid, decor)) {9882this->builder.addDecoration(tsid, decor);9883idToQCOMDecorations[tsid].push_back(decor);9884}9885}9886};98879888spv::Id opc = builder.getOpCode(id);9889bool isInterfaceObject = (opc != spv::OpSampledImage);98909891if (!isInterfaceObject) {9892addDecor(builder.getIdOperand(id, 0), spv::DecorationBlockMatchTextureQCOM);9893addDecor(builder.getIdOperand(id, 1), spv::DecorationBlockMatchSamplerQCOM);9894} else {9895addDecor(id, spv::DecorationBlockMatchTextureQCOM);9896addDecor(id, spv::DecorationBlockMatchSamplerQCOM);9897}9898}98999900// Make a full tree of instructions to build a SPIR-V specialization constant,9901// or regular constant if possible.9902//9903// TBD: this is not yet done, nor verified to be the best design, it does do the leaf symbols though9904//9905// Recursively walk the nodes. The nodes form a tree whose leaves are9906// regular constants, which themselves are trees that createSpvConstant()9907// recursively walks. So, this function walks the "top" of the tree:9908// - emit specialization constant-building instructions for specConstant9909// - when running into a non-spec-constant, switch to createSpvConstant()9910spv::Id TGlslangToSpvTraverser::createSpvConstant(const glslang::TIntermTyped& node)9911{9912assert(node.getQualifier().isConstant());99139914// Handle front-end constants first (non-specialization constants).9915if (! node.getQualifier().specConstant) {9916// hand off to the non-spec-constant path9917assert(node.getAsConstantUnion() != nullptr || node.getAsSymbolNode() != nullptr);9918int nextConst = 0;9919return createSpvConstantFromConstUnionArray(node.getType(), node.getAsConstantUnion() ?9920node.getAsConstantUnion()->getConstArray() : node.getAsSymbolNode()->getConstArray(),9921nextConst, false);9922}99239924// We now know we have a specialization constant to build99259926// Extra capabilities may be needed.9927if (node.getType().contains8BitInt())9928builder.addCapability(spv::CapabilityInt8);9929if (node.getType().contains16BitFloat())9930builder.addCapability(spv::CapabilityFloat16);9931if (node.getType().contains16BitInt())9932builder.addCapability(spv::CapabilityInt16);9933if (node.getType().contains64BitInt())9934builder.addCapability(spv::CapabilityInt64);9935if (node.getType().containsDouble())9936builder.addCapability(spv::CapabilityFloat64);99379938// gl_WorkGroupSize is a special case until the front-end handles hierarchical specialization constants,9939// even then, it's specialization ids are handled by special case syntax in GLSL: layout(local_size_x = ...9940if (node.getType().getQualifier().builtIn == glslang::EbvWorkGroupSize) {9941std::vector<spv::Id> dimConstId;9942for (int dim = 0; dim < 3; ++dim) {9943bool specConst = (glslangIntermediate->getLocalSizeSpecId(dim) != glslang::TQualifier::layoutNotSet);9944dimConstId.push_back(builder.makeUintConstant(glslangIntermediate->getLocalSize(dim), specConst));9945if (specConst) {9946builder.addDecoration(dimConstId.back(), spv::DecorationSpecId,9947glslangIntermediate->getLocalSizeSpecId(dim));9948}9949}9950return builder.makeCompositeConstant(builder.makeVectorType(builder.makeUintType(32), 3), dimConstId, true);9951}99529953// An AST node labelled as specialization constant should be a symbol node.9954// Its initializer should either be a sub tree with constant nodes, or a constant union array.9955if (auto* sn = node.getAsSymbolNode()) {9956spv::Id result;9957if (auto* sub_tree = sn->getConstSubtree()) {9958// Traverse the constant constructor sub tree like generating normal run-time instructions.9959// During the AST traversal, if the node is marked as 'specConstant', SpecConstantOpModeGuard9960// will set the builder into spec constant op instruction generating mode.9961sub_tree->traverse(this);9962result = accessChainLoad(sub_tree->getType());9963} else if (auto* const_union_array = &sn->getConstArray()) {9964int nextConst = 0;9965result = createSpvConstantFromConstUnionArray(sn->getType(), *const_union_array, nextConst, true);9966} else {9967logger->missingFunctionality("Invalid initializer for spec onstant.");9968return spv::NoResult;9969}9970builder.addName(result, sn->getName().c_str());9971return result;9972}99739974// Neither a front-end constant node, nor a specialization constant node with constant union array or9975// constant sub tree as initializer.9976logger->missingFunctionality("Neither a front-end constant nor a spec constant.");9977return spv::NoResult;9978}99799980// Use 'consts' as the flattened glslang source of scalar constants to recursively9981// build the aggregate SPIR-V constant.9982//9983// If there are not enough elements present in 'consts', 0 will be substituted;9984// an empty 'consts' can be used to create a fully zeroed SPIR-V constant.9985//9986spv::Id TGlslangToSpvTraverser::createSpvConstantFromConstUnionArray(const glslang::TType& glslangType,9987const glslang::TConstUnionArray& consts, int& nextConst, bool specConstant)9988{9989// vector of constants for SPIR-V9990std::vector<spv::Id> spvConsts;99919992// Type is used for struct and array constants9993spv::Id typeId = convertGlslangToSpvType(glslangType);99949995if (glslangType.isArray()) {9996glslang::TType elementType(glslangType, 0);9997for (int i = 0; i < glslangType.getOuterArraySize(); ++i)9998spvConsts.push_back(createSpvConstantFromConstUnionArray(elementType, consts, nextConst, false));9999} else if (glslangType.isMatrix()) {10000glslang::TType vectorType(glslangType, 0);10001for (int col = 0; col < glslangType.getMatrixCols(); ++col)10002spvConsts.push_back(createSpvConstantFromConstUnionArray(vectorType, consts, nextConst, false));10003} else if (glslangType.isCoopMat()) {10004glslang::TType componentType(glslangType.getBasicType());10005spvConsts.push_back(createSpvConstantFromConstUnionArray(componentType, consts, nextConst, false));10006} else if (glslangType.isStruct()) {10007glslang::TVector<glslang::TTypeLoc>::const_iterator iter;10008for (iter = glslangType.getStruct()->begin(); iter != glslangType.getStruct()->end(); ++iter)10009spvConsts.push_back(createSpvConstantFromConstUnionArray(*iter->type, consts, nextConst, false));10010} else if (glslangType.getVectorSize() > 1) {10011for (unsigned int i = 0; i < (unsigned int)glslangType.getVectorSize(); ++i) {10012bool zero = nextConst >= consts.size();10013switch (glslangType.getBasicType()) {10014case glslang::EbtInt:10015spvConsts.push_back(builder.makeIntConstant(zero ? 0 : consts[nextConst].getIConst()));10016break;10017case glslang::EbtUint:10018spvConsts.push_back(builder.makeUintConstant(zero ? 0 : consts[nextConst].getUConst()));10019break;10020case glslang::EbtFloat:10021spvConsts.push_back(builder.makeFloatConstant(zero ? 0.0F : (float)consts[nextConst].getDConst()));10022break;10023case glslang::EbtBool:10024spvConsts.push_back(builder.makeBoolConstant(zero ? false : consts[nextConst].getBConst()));10025break;10026case glslang::EbtInt8:10027builder.addCapability(spv::CapabilityInt8);10028spvConsts.push_back(builder.makeInt8Constant(zero ? 0 : consts[nextConst].getI8Const()));10029break;10030case glslang::EbtUint8:10031builder.addCapability(spv::CapabilityInt8);10032spvConsts.push_back(builder.makeUint8Constant(zero ? 0 : consts[nextConst].getU8Const()));10033break;10034case glslang::EbtInt16:10035builder.addCapability(spv::CapabilityInt16);10036spvConsts.push_back(builder.makeInt16Constant(zero ? 0 : consts[nextConst].getI16Const()));10037break;10038case glslang::EbtUint16:10039builder.addCapability(spv::CapabilityInt16);10040spvConsts.push_back(builder.makeUint16Constant(zero ? 0 : consts[nextConst].getU16Const()));10041break;10042case glslang::EbtInt64:10043spvConsts.push_back(builder.makeInt64Constant(zero ? 0 : consts[nextConst].getI64Const()));10044break;10045case glslang::EbtUint64:10046spvConsts.push_back(builder.makeUint64Constant(zero ? 0 : consts[nextConst].getU64Const()));10047break;10048case glslang::EbtDouble:10049spvConsts.push_back(builder.makeDoubleConstant(zero ? 0.0 : consts[nextConst].getDConst()));10050break;10051case glslang::EbtFloat16:10052builder.addCapability(spv::CapabilityFloat16);10053spvConsts.push_back(builder.makeFloat16Constant(zero ? 0.0F : (float)consts[nextConst].getDConst()));10054break;10055default:10056assert(0);10057break;10058}10059++nextConst;10060}10061} else {10062// we have a non-aggregate (scalar) constant10063bool zero = nextConst >= consts.size();10064spv::Id scalar = 0;10065switch (glslangType.getBasicType()) {10066case glslang::EbtInt:10067scalar = builder.makeIntConstant(zero ? 0 : consts[nextConst].getIConst(), specConstant);10068break;10069case glslang::EbtUint:10070scalar = builder.makeUintConstant(zero ? 0 : consts[nextConst].getUConst(), specConstant);10071break;10072case glslang::EbtFloat:10073scalar = builder.makeFloatConstant(zero ? 0.0F : (float)consts[nextConst].getDConst(), specConstant);10074break;10075case glslang::EbtBool:10076scalar = builder.makeBoolConstant(zero ? false : consts[nextConst].getBConst(), specConstant);10077break;10078case glslang::EbtInt8:10079builder.addCapability(spv::CapabilityInt8);10080scalar = builder.makeInt8Constant(zero ? 0 : consts[nextConst].getI8Const(), specConstant);10081break;10082case glslang::EbtUint8:10083builder.addCapability(spv::CapabilityInt8);10084scalar = builder.makeUint8Constant(zero ? 0 : consts[nextConst].getU8Const(), specConstant);10085break;10086case glslang::EbtInt16:10087builder.addCapability(spv::CapabilityInt16);10088scalar = builder.makeInt16Constant(zero ? 0 : consts[nextConst].getI16Const(), specConstant);10089break;10090case glslang::EbtUint16:10091builder.addCapability(spv::CapabilityInt16);10092scalar = builder.makeUint16Constant(zero ? 0 : consts[nextConst].getU16Const(), specConstant);10093break;10094case glslang::EbtInt64:10095scalar = builder.makeInt64Constant(zero ? 0 : consts[nextConst].getI64Const(), specConstant);10096break;10097case glslang::EbtUint64:10098scalar = builder.makeUint64Constant(zero ? 0 : consts[nextConst].getU64Const(), specConstant);10099break;10100case glslang::EbtDouble:10101scalar = builder.makeDoubleConstant(zero ? 0.0 : consts[nextConst].getDConst(), specConstant);10102break;10103case glslang::EbtFloat16:10104builder.addCapability(spv::CapabilityFloat16);10105scalar = builder.makeFloat16Constant(zero ? 0.0F : (float)consts[nextConst].getDConst(), specConstant);10106break;10107case glslang::EbtReference:10108scalar = builder.makeUint64Constant(zero ? 0 : consts[nextConst].getU64Const(), specConstant);10109scalar = builder.createUnaryOp(spv::OpBitcast, typeId, scalar);10110break;10111case glslang::EbtString:10112scalar = builder.getStringId(consts[nextConst].getSConst()->c_str());10113break;10114default:10115assert(0);10116break;10117}10118++nextConst;10119return scalar;10120}1012110122return builder.makeCompositeConstant(typeId, spvConsts);10123}1012410125// Return true if the node is a constant or symbol whose reading has no10126// non-trivial observable cost or effect.10127bool TGlslangToSpvTraverser::isTrivialLeaf(const glslang::TIntermTyped* node)10128{10129// don't know what this is10130if (node == nullptr)10131return false;1013210133// a constant is safe10134if (node->getAsConstantUnion() != nullptr)10135return true;1013610137// not a symbol means non-trivial10138if (node->getAsSymbolNode() == nullptr)10139return false;1014010141// a symbol, depends on what's being read10142switch (node->getType().getQualifier().storage) {10143case glslang::EvqTemporary:10144case glslang::EvqGlobal:10145case glslang::EvqIn:10146case glslang::EvqInOut:10147case glslang::EvqConst:10148case glslang::EvqConstReadOnly:10149case glslang::EvqUniform:10150return true;10151default:10152return false;10153}10154}1015510156// A node is trivial if it is a single operation with no side effects.10157// HLSL (and/or vectors) are always trivial, as it does not short circuit.10158// Otherwise, error on the side of saying non-trivial.10159// Return true if trivial.10160bool TGlslangToSpvTraverser::isTrivial(const glslang::TIntermTyped* node)10161{10162if (node == nullptr)10163return false;1016410165// count non scalars as trivial, as well as anything coming from HLSL10166if (! node->getType().isScalarOrVec1() || glslangIntermediate->getSource() == glslang::EShSourceHlsl)10167return true;1016810169// symbols and constants are trivial10170if (isTrivialLeaf(node))10171return true;1017210173// otherwise, it needs to be a simple operation or one or two leaf nodes1017410175// not a simple operation10176const glslang::TIntermBinary* binaryNode = node->getAsBinaryNode();10177const glslang::TIntermUnary* unaryNode = node->getAsUnaryNode();10178if (binaryNode == nullptr && unaryNode == nullptr)10179return false;1018010181// not on leaf nodes10182if (binaryNode && (! isTrivialLeaf(binaryNode->getLeft()) || ! isTrivialLeaf(binaryNode->getRight())))10183return false;1018410185if (unaryNode && ! isTrivialLeaf(unaryNode->getOperand())) {10186return false;10187}1018810189switch (node->getAsOperator()->getOp()) {10190case glslang::EOpLogicalNot:10191case glslang::EOpConvIntToBool:10192case glslang::EOpConvUintToBool:10193case glslang::EOpConvFloatToBool:10194case glslang::EOpConvDoubleToBool:10195case glslang::EOpEqual:10196case glslang::EOpNotEqual:10197case glslang::EOpLessThan:10198case glslang::EOpGreaterThan:10199case glslang::EOpLessThanEqual:10200case glslang::EOpGreaterThanEqual:10201case glslang::EOpIndexDirect:10202case glslang::EOpIndexDirectStruct:10203case glslang::EOpLogicalXor:10204case glslang::EOpAny:10205case glslang::EOpAll:10206return true;10207default:10208return false;10209}10210}1021110212// Emit short-circuiting code, where 'right' is never evaluated unless10213// the left side is true (for &&) or false (for ||).10214spv::Id TGlslangToSpvTraverser::createShortCircuit(glslang::TOperator op, glslang::TIntermTyped& left,10215glslang::TIntermTyped& right)10216{10217spv::Id boolTypeId = builder.makeBoolType();1021810219// emit left operand10220builder.clearAccessChain();10221left.traverse(this);10222spv::Id leftId = accessChainLoad(left.getType());1022310224// Operands to accumulate OpPhi operands10225std::vector<spv::Id> phiOperands;10226phiOperands.reserve(4);10227// accumulate left operand's phi information10228phiOperands.push_back(leftId);10229phiOperands.push_back(builder.getBuildPoint()->getId());1023010231// Make the two kinds of operation symmetric with a "!"10232// || => emit "if (! left) result = right"10233// && => emit "if ( left) result = right"10234//10235// TODO: this runtime "not" for || could be avoided by adding functionality10236// to 'builder' to have an "else" without an "then"10237if (op == glslang::EOpLogicalOr)10238leftId = builder.createUnaryOp(spv::OpLogicalNot, boolTypeId, leftId);1023910240// make an "if" based on the left value10241spv::Builder::If ifBuilder(leftId, spv::SelectionControlMaskNone, builder);1024210243// emit right operand as the "then" part of the "if"10244builder.clearAccessChain();10245right.traverse(this);10246spv::Id rightId = accessChainLoad(right.getType());1024710248// accumulate left operand's phi information10249phiOperands.push_back(rightId);10250phiOperands.push_back(builder.getBuildPoint()->getId());1025110252// finish the "if"10253ifBuilder.makeEndIf();1025410255// phi together the two results10256return builder.createOp(spv::OpPhi, boolTypeId, phiOperands);10257}1025810259// Return type Id of the imported set of extended instructions corresponds to the name.10260// Import this set if it has not been imported yet.10261spv::Id TGlslangToSpvTraverser::getExtBuiltins(const char* name)10262{10263if (extBuiltinMap.find(name) != extBuiltinMap.end())10264return extBuiltinMap[name];10265else {10266spv::Id extBuiltins = builder.import(name);10267extBuiltinMap[name] = extBuiltins;10268return extBuiltins;10269}10270}1027110272}; // end anonymous namespace1027310274namespace glslang {1027510276void GetSpirvVersion(std::string& version)10277{10278const int bufSize = 100;10279char buf[bufSize];10280snprintf(buf, bufSize, "0x%08x, Revision %d", spv::Version, spv::Revision);10281version = buf;10282}1028310284// For low-order part of the generator's magic number. Bump up10285// when there is a change in the style (e.g., if SSA form changes,10286// or a different instruction sequence to do something gets used).10287int GetSpirvGeneratorVersion()10288{10289// return 1; // start10290// return 2; // EOpAtomicCounterDecrement gets a post decrement, to map between GLSL -> SPIR-V10291// return 3; // change/correct barrier-instruction operands, to match memory model group decisions10292// return 4; // some deeper access chains: for dynamic vector component, and local Boolean component10293// return 5; // make OpArrayLength result type be an int with signedness of 010294// return 6; // revert version 5 change, which makes a different (new) kind of incorrect code,10295// versions 4 and 6 each generate OpArrayLength as it has long been done10296// return 7; // GLSL volatile keyword maps to both SPIR-V decorations Volatile and Coherent10297// return 8; // switch to new dead block eliminator; use OpUnreachable10298// return 9; // don't include opaque function parameters in OpEntryPoint global's operand list10299// return 10; // Generate OpFUnordNotEqual for != comparisons10300return 11; // Make OpEmitMeshTasksEXT a terminal instruction10301}1030210303// Write SPIR-V out to a binary file10304bool OutputSpvBin(const std::vector<unsigned int>& spirv, const char* baseName)10305{10306std::ofstream out;10307out.open(baseName, std::ios::binary | std::ios::out);10308if (out.fail()) {10309printf("ERROR: Failed to open file: %s\n", baseName);10310return false;10311}10312for (int i = 0; i < (int)spirv.size(); ++i) {10313unsigned int word = spirv[i];10314out.write((const char*)&word, 4);10315}10316out.close();10317return true;10318}1031910320// Write SPIR-V out to a text file with 32-bit hexadecimal words10321bool OutputSpvHex(const std::vector<unsigned int>& spirv, const char* baseName, const char* varName)10322{10323std::ofstream out;10324out.open(baseName, std::ios::binary | std::ios::out);10325if (out.fail()) {10326printf("ERROR: Failed to open file: %s\n", baseName);10327return false;10328}10329out << "\t// " <<10330GetSpirvGeneratorVersion() <<10331GLSLANG_VERSION_MAJOR << "." << GLSLANG_VERSION_MINOR << "." << GLSLANG_VERSION_PATCH <<10332GLSLANG_VERSION_FLAVOR << std::endl;10333if (varName != nullptr) {10334out << "\t #pragma once" << std::endl;10335out << "const uint32_t " << varName << "[] = {" << std::endl;10336}10337const int WORDS_PER_LINE = 8;10338for (int i = 0; i < (int)spirv.size(); i += WORDS_PER_LINE) {10339out << "\t";10340for (int j = 0; j < WORDS_PER_LINE && i + j < (int)spirv.size(); ++j) {10341const unsigned int word = spirv[i + j];10342out << "0x" << std::hex << std::setw(8) << std::setfill('0') << word;10343if (i + j + 1 < (int)spirv.size()) {10344out << ",";10345}10346}10347out << std::endl;10348}10349if (varName != nullptr) {10350out << "};";10351out << std::endl;10352}10353out.close();10354return true;10355}1035610357//10358// Set up the glslang traversal10359//10360void GlslangToSpv(const TIntermediate& intermediate, std::vector<unsigned int>& spirv, SpvOptions* options)10361{10362spv::SpvBuildLogger logger;10363GlslangToSpv(intermediate, spirv, &logger, options);10364}1036510366void GlslangToSpv(const TIntermediate& intermediate, std::vector<unsigned int>& spirv,10367spv::SpvBuildLogger* logger, SpvOptions* options)10368{10369TIntermNode* root = intermediate.getTreeRoot();1037010371if (root == nullptr)10372return;1037310374SpvOptions defaultOptions;10375if (options == nullptr)10376options = &defaultOptions;1037710378GetThreadPoolAllocator().push();1037910380TGlslangToSpvTraverser it(intermediate.getSpv().spv, &intermediate, logger, *options);10381root->traverse(&it);10382it.finishSpv(options->compileOnly);10383it.dumpSpv(spirv);1038410385#if ENABLE_OPT10386// If from HLSL, run spirv-opt to "legalize" the SPIR-V for Vulkan10387// eg. forward and remove memory writes of opaque types.10388bool prelegalization = intermediate.getSource() == EShSourceHlsl;10389if ((prelegalization || options->optimizeSize) && !options->disableOptimizer) {10390SpirvToolsTransform(intermediate, spirv, logger, options);10391prelegalization = false;10392}10393else if (options->stripDebugInfo) {10394// Strip debug info even if optimization is disabled.10395SpirvToolsStripDebugInfo(intermediate, spirv, logger);10396}1039710398if (options->validate)10399SpirvToolsValidate(intermediate, spirv, logger, prelegalization);1040010401if (options->disassemble)10402SpirvToolsDisassemble(std::cout, spirv);1040310404#endif1040510406GetThreadPoolAllocator().pop();10407}1040810409}; // end namespace glslang104101041110412