Coverage Report

Created: 2025-12-14 06:48

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/shaderc/third_party/glslang/SPIRV/GlslangToSpv.cpp
Line
Count
Source
1
//
2
// Copyright (C) 2014-2016 LunarG, Inc.
3
// Copyright (C) 2015-2020 Google, Inc.
4
// Copyright (C) 2017, 2022-2025 Arm Limited.
5
// Modifications Copyright (C) 2020 Advanced Micro Devices, Inc. All rights reserved.
6
//
7
// All rights reserved.
8
//
9
// Redistribution and use in source and binary forms, with or without
10
// modification, are permitted provided that the following conditions
11
// are met:
12
//
13
//    Redistributions of source code must retain the above copyright
14
//    notice, this list of conditions and the following disclaimer.
15
//
16
//    Redistributions in binary form must reproduce the above
17
//    copyright notice, this list of conditions and the following
18
//    disclaimer in the documentation and/or other materials provided
19
//    with the distribution.
20
//
21
//    Neither the name of 3Dlabs Inc. Ltd. nor the names of its
22
//    contributors may be used to endorse or promote products derived
23
//    from this software without specific prior written permission.
24
//
25
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
26
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
27
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
28
// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
29
// COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
30
// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
31
// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
32
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
33
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
34
// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
35
// ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
36
// POSSIBILITY OF SUCH DAMAGE.
37
38
//
39
// Visit the nodes in the glslang intermediate tree representation to
40
// translate them to SPIR-V.
41
//
42
43
#include "spirv.hpp11"
44
#include "GlslangToSpv.h"
45
#include "SpvBuilder.h"
46
#include "SpvTools.h"
47
#include "spvUtil.h"
48
49
namespace spv {
50
    #include "GLSL.std.450.h"
51
    #include "GLSL.ext.KHR.h"
52
    #include "GLSL.ext.EXT.h"
53
    #include "GLSL.ext.AMD.h"
54
    #include "GLSL.ext.NV.h"
55
    #include "GLSL.ext.ARM.h"
56
    #include "GLSL.ext.QCOM.h"
57
    #include "NonSemanticDebugPrintf.h"
58
}
59
60
// Glslang includes
61
#include "../glslang/MachineIndependent/localintermediate.h"
62
#include "../glslang/MachineIndependent/SymbolTable.h"
63
#include "../glslang/Include/Common.h"
64
65
// Build-time generated includes
66
#include "glslang/build_info.h"
67
68
#include <fstream>
69
#include <iomanip>
70
#include <list>
71
#include <map>
72
#include <optional>
73
#include <stack>
74
#include <string>
75
#include <vector>
76
77
namespace {
78
79
namespace {
80
class SpecConstantOpModeGuard {
81
public:
82
    SpecConstantOpModeGuard(spv::Builder* builder)
83
207k
        : builder_(builder) {
84
207k
        previous_flag_ = builder->isInSpecConstCodeGenMode();
85
207k
    }
86
207k
    ~SpecConstantOpModeGuard() {
87
207k
        previous_flag_ ? builder_->setToSpecConstCodeGenMode()
88
207k
                       : builder_->setToNormalCodeGenMode();
89
207k
    }
90
1.78k
    void turnOnSpecConstantOpMode() {
91
1.78k
        builder_->setToSpecConstCodeGenMode();
92
1.78k
    }
93
94
private:
95
    spv::Builder* builder_;
96
    bool previous_flag_;
97
};
98
99
struct OpDecorations {
100
    public:
101
        OpDecorations(spv::Decoration precision, spv::Decoration noContraction, spv::Decoration nonUniform) :
102
26.4k
            precision(precision)
103
            ,
104
26.4k
            noContraction(noContraction),
105
26.4k
            nonUniform(nonUniform)
106
26.4k
        { }
107
108
    spv::Decoration precision;
109
110
21.8k
        void addNoContraction(spv::Builder& builder, spv::Id t) { builder.addDecoration(t, noContraction); }
111
26.6k
        void addNonUniform(spv::Builder& builder, spv::Id t)  { builder.addDecoration(t, nonUniform); }
112
    protected:
113
        spv::Decoration noContraction;
114
        spv::Decoration nonUniform;
115
};
116
117
} // namespace
118
119
//
120
// The main holder of information for translating glslang to SPIR-V.
121
//
122
// Derives from the AST walking base class.
123
//
124
class TGlslangToSpvTraverser : public glslang::TIntermTraverser {
125
public:
126
    TGlslangToSpvTraverser(unsigned int spvVersion, const glslang::TIntermediate*, spv::SpvBuildLogger* logger,
127
        glslang::SpvOptions& options);
128
2.08k
    virtual ~TGlslangToSpvTraverser() { }
129
130
    bool visitAggregate(glslang::TVisit, glslang::TIntermAggregate*) override;
131
    bool visitBinary(glslang::TVisit, glslang::TIntermBinary*) override;
132
    void visitConstantUnion(glslang::TIntermConstantUnion*) override;
133
    bool visitSelection(glslang::TVisit, glslang::TIntermSelection*) override;
134
    bool visitSwitch(glslang::TVisit, glslang::TIntermSwitch*) override;
135
    void visitSymbol(glslang::TIntermSymbol* symbol) override;
136
    bool visitUnary(glslang::TVisit, glslang::TIntermUnary*) override;
137
    bool visitLoop(glslang::TVisit, glslang::TIntermLoop*) override;
138
    bool visitBranch(glslang::TVisit visit, glslang::TIntermBranch*) override;
139
    bool visitVariableDecl(glslang::TVisit, glslang::TIntermVariableDecl*) override;
140
141
    void finishSpv(bool compileOnly);
142
    void dumpSpv(std::vector<unsigned int>& out);
143
144
protected:
145
    TGlslangToSpvTraverser(TGlslangToSpvTraverser&);
146
    TGlslangToSpvTraverser& operator=(TGlslangToSpvTraverser&);
147
148
    spv::Decoration TranslateInterpolationDecoration(const glslang::TQualifier& qualifier);
149
    spv::Decoration TranslateAuxiliaryStorageDecoration(const glslang::TQualifier& qualifier);
150
    spv::Decoration TranslateNonUniformDecoration(const glslang::TQualifier& qualifier);
151
    spv::Decoration TranslateNonUniformDecoration(const spv::Builder::AccessChain::CoherentFlags& coherentFlags);
152
    spv::Builder::AccessChain::CoherentFlags TranslateCoherent(const glslang::TType& type);
153
    spv::MemoryAccessMask TranslateMemoryAccess(const spv::Builder::AccessChain::CoherentFlags &coherentFlags);
154
    spv::ImageOperandsMask TranslateImageOperands(const spv::Builder::AccessChain::CoherentFlags &coherentFlags);
155
    spv::Scope TranslateMemoryScope(const spv::Builder::AccessChain::CoherentFlags &coherentFlags);
156
    spv::BuiltIn TranslateBuiltInDecoration(glslang::TBuiltInVariable, bool memberDeclaration);
157
    spv::ImageFormat TranslateImageFormat(const glslang::TType& type);
158
    spv::SelectionControlMask TranslateSelectionControl(const glslang::TIntermSelection&) const;
159
    spv::SelectionControlMask TranslateSwitchControl(const glslang::TIntermSwitch&) const;
160
    spv::LoopControlMask TranslateLoopControl(const glslang::TIntermLoop&, std::vector<unsigned int>& operands) const;
161
    spv::StorageClass TranslateStorageClass(const glslang::TType&);
162
    void TranslateLiterals(const glslang::TVector<const glslang::TIntermConstantUnion*>&, std::vector<unsigned>&) const;
163
    void addIndirectionIndexCapabilities(const glslang::TType& baseType, const glslang::TType& indexType);
164
    spv::Id createSpvVariable(const glslang::TIntermSymbol*, spv::Id forcedType);
165
    spv::Id getSampledType(const glslang::TSampler&);
166
    spv::Id getInvertedSwizzleType(const glslang::TIntermTyped&);
167
    spv::Id createInvertedSwizzle(spv::Decoration precision, const glslang::TIntermTyped&, spv::Id parentResult);
168
    void convertSwizzle(const glslang::TIntermAggregate&, std::vector<unsigned>& swizzle);
169
    spv::Id convertGlslangToSpvType(const glslang::TType& type, bool forwardReferenceOnly = false);
170
    spv::Id convertGlslangToSpvType(const glslang::TType& type, glslang::TLayoutPacking, const glslang::TQualifier&,
171
        bool lastBufferBlockMember, bool forwardReferenceOnly = false);
172
    void applySpirvDecorate(const glslang::TType& type, spv::Id id, std::optional<int> member);
173
    bool filterMember(const glslang::TType& member);
174
    spv::Id convertGlslangStructToSpvType(const glslang::TType&, const glslang::TTypeList* glslangStruct,
175
                                          glslang::TLayoutPacking, const glslang::TQualifier&);
176
    spv::LinkageType convertGlslangLinkageToSpv(glslang::TLinkType glslangLinkType);
177
    void decorateStructType(const glslang::TType&, const glslang::TTypeList* glslangStruct, glslang::TLayoutPacking,
178
                            const glslang::TQualifier&, spv::Id, const std::vector<spv::Id>& spvMembers);
179
    spv::Id makeArraySizeId(const glslang::TArraySizes&, int dim, bool allowZero = false, bool boolType = false);
180
    spv::Id accessChainLoad(const glslang::TType& type);
181
    void    accessChainStore(const glslang::TType& type, spv::Id rvalue);
182
    void multiTypeStore(const glslang::TType&, spv::Id rValue);
183
    spv::Id convertLoadedBoolInUniformToUint(const glslang::TType& type, spv::Id nominalTypeId, spv::Id loadedId);
184
    glslang::TLayoutPacking getExplicitLayout(const glslang::TType& type) const;
185
    int getArrayStride(const glslang::TType& arrayType, glslang::TLayoutPacking, glslang::TLayoutMatrix);
186
    int getMatrixStride(const glslang::TType& matrixType, glslang::TLayoutPacking, glslang::TLayoutMatrix);
187
    void updateMemberOffset(const glslang::TType& structType, const glslang::TType& memberType, int& currentOffset,
188
                            int& nextOffset, glslang::TLayoutPacking, glslang::TLayoutMatrix);
189
    void declareUseOfStructMember(const glslang::TTypeList& members, int glslangMember);
190
191
    bool isShaderEntryPoint(const glslang::TIntermAggregate* node);
192
    bool writableParam(glslang::TStorageQualifier) const;
193
    bool originalParam(glslang::TStorageQualifier, const glslang::TType&, bool implicitThisParam);
194
    void makeFunctions(const glslang::TIntermSequence&);
195
    void makeGlobalInitializers(const glslang::TIntermSequence&);
196
    void collectRayTracingLinkerObjects();
197
    void visitFunctions(const glslang::TIntermSequence&);
198
    void translateArguments(const glslang::TIntermAggregate& node, std::vector<spv::Id>& arguments,
199
        spv::Builder::AccessChain::CoherentFlags &lvalueCoherentFlags);
200
    void translateArguments(glslang::TIntermUnary& node, std::vector<spv::Id>& arguments);
201
    spv::Id createImageTextureFunctionCall(glslang::TIntermOperator* node);
202
    spv::Id handleUserFunctionCall(const glslang::TIntermAggregate*);
203
204
    spv::Id createBinaryOperation(glslang::TOperator op, OpDecorations&, spv::Id typeId, spv::Id left, spv::Id right,
205
                                  glslang::TBasicType typeProxy, bool reduceComparison = true);
206
    spv::Id createBinaryMatrixOperation(spv::Op, OpDecorations&, spv::Id typeId, spv::Id left, spv::Id right);
207
    spv::Id createUnaryOperation(glslang::TOperator op, OpDecorations&, spv::Id typeId, spv::Id operand,
208
                                 glslang::TBasicType typeProxy,
209
                                 const spv::Builder::AccessChain::CoherentFlags &lvalueCoherentFlags,
210
                                 const glslang::TType &opType);
211
    spv::Id createUnaryMatrixOperation(spv::Op op, OpDecorations&, spv::Id typeId, spv::Id operand,
212
                                       glslang::TBasicType typeProxy);
213
    spv::Id createConversion(glslang::TOperator op, OpDecorations&, spv::Id destTypeId, spv::Id operand,
214
                             glslang::TBasicType resultBasicType, glslang::TBasicType operandBasicType);
215
    spv::Id createIntWidthConversion(spv::Id operand, int vectorSize, spv::Id destType,
216
                                     glslang::TBasicType resultBasicType, glslang::TBasicType operandBasicType);
217
    spv::Id makeSmearedConstant(spv::Id constant, int vectorSize);
218
    spv::Id createAtomicOperation(glslang::TOperator op, spv::Decoration precision, spv::Id typeId,
219
        std::vector<spv::Id>& operands, glslang::TBasicType typeProxy,
220
        const spv::Builder::AccessChain::CoherentFlags &lvalueCoherentFlags,
221
        const glslang::TType &opType);
222
    spv::Id createInvocationsOperation(glslang::TOperator op, spv::Id typeId, std::vector<spv::Id>& operands,
223
        glslang::TBasicType typeProxy);
224
    spv::Id CreateInvocationsVectorOperation(spv::Op op, spv::GroupOperation groupOperation,
225
        spv::Id typeId, std::vector<spv::Id>& operands);
226
    spv::Id createSubgroupOperation(glslang::TOperator op, spv::Id typeId, std::vector<spv::Id>& operands,
227
        glslang::TBasicType typeProxy);
228
    spv::Id createMiscOperation(glslang::TOperator op, spv::Decoration precision, spv::Id typeId,
229
        std::vector<spv::Id>& operands, glslang::TBasicType typeProxy);
230
    spv::Id createNoArgOperation(glslang::TOperator op, spv::Decoration precision, spv::Id typeId);
231
    spv::Id getSymbolId(const glslang::TIntermSymbol* node);
232
    void addMeshNVDecoration(spv::Id id, int member, const glslang::TQualifier & qualifier);
233
    bool hasQCOMImageProceessingDecoration(spv::Id id, spv::Decoration decor);
234
    void addImageProcessingQCOMDecoration(spv::Id id, spv::Decoration decor);
235
    void addImageProcessing2QCOMDecoration(spv::Id id, bool isForGather);
236
    spv::Id createSpvConstant(const glslang::TIntermTyped&);
237
    spv::Id createSpvConstantFromConstUnionArray(const glslang::TType& type, const glslang::TConstUnionArray&,
238
        int& nextConst, bool specConstant);
239
    bool isTrivialLeaf(const glslang::TIntermTyped* node);
240
    bool isTrivial(const glslang::TIntermTyped* node);
241
    spv::Id createShortCircuit(glslang::TOperator, glslang::TIntermTyped& left, glslang::TIntermTyped& right);
242
    spv::Id getExtBuiltins(const char* name);
243
    std::pair<spv::Id, spv::Id> getForcedType(glslang::TBuiltInVariable builtIn, const glslang::TType&);
244
    spv::Id translateForcedType(spv::Id object);
245
    spv::Id createCompositeConstruct(spv::Id typeId, std::vector<spv::Id> constituents);
246
247
    glslang::SpvOptions& options;
248
    spv::Function* shaderEntry;
249
    spv::Function* currentFunction;
250
    spv::Instruction* entryPoint;
251
    int sequenceDepth;
252
253
    spv::SpvBuildLogger* logger;
254
255
    // There is a 1:1 mapping between a spv builder and a module; this is thread safe
256
    spv::Builder builder;
257
    bool inEntryPoint;
258
    bool entryPointTerminated;
259
    bool linkageOnly;                  // true when visiting the set of objects in the AST present only for
260
                                       // establishing interface, whether or not they were statically used
261
    std::set<spv::Id> iOSet;           // all input/output variables from either static use or declaration of interface
262
    const glslang::TIntermediate* glslangIntermediate;
263
    bool nanMinMaxClamp;               // true if use NMin/NMax/NClamp instead of FMin/FMax/FClamp
264
    spv::Id stdBuiltins;
265
    spv::Id nonSemanticDebugPrintf;
266
    std::unordered_map<std::string, spv::Id> extBuiltinMap;
267
268
    std::unordered_map<long long, spv::Id> symbolValues;
269
    std::unordered_map<uint32_t, spv::Id> builtInVariableIds;
270
    std::unordered_set<long long> rValueParameters;  // set of formal function parameters passed as rValues,
271
                                               // rather than a pointer
272
    std::unordered_map<std::string, spv::Function*> functionMap;
273
    std::unordered_map<const glslang::TTypeList*, spv::Id> structMap[glslang::ElpCount][glslang::ElmCount];
274
    // for mapping glslang block indices to spv indices (e.g., due to hidden members):
275
    std::unordered_map<long long, std::vector<int>> memberRemapper;
276
    // for mapping glslang symbol struct to symbol Id
277
    std::unordered_map<const glslang::TTypeList*, long long> glslangTypeToIdMap;
278
    std::stack<bool> breakForLoop;  // false means break for switch
279
    std::unordered_map<std::string, const glslang::TIntermSymbol*> counterOriginator;
280
    // Map pointee types for EbtReference to their forward pointers
281
    std::map<const glslang::TType *, spv::Id> forwardPointers;
282
    // Type forcing, for when SPIR-V wants a different type than the AST,
283
    // requiring local translation to and from SPIR-V type on every access.
284
    // Maps <builtin-variable-id -> AST-required-type-id>
285
    std::unordered_map<spv::Id, spv::Id> forceType;
286
    // Used by Task shader while generating opearnds for OpEmitMeshTasksEXT
287
    spv::Id taskPayloadID;
288
    // Used later for generating OpTraceKHR/OpExecuteCallableKHR/OpHitObjectRecordHit*/OpHitObjectGetShaderBindingTableData
289
    std::unordered_map<unsigned int, glslang::TIntermSymbol *> locationToSymbol[4];
290
    std::unordered_map<spv::Id, std::vector<spv::Decoration> > idToQCOMDecorations;
291
};
292
293
//
294
// Helper functions for translating glslang representations to SPIR-V enumerants.
295
//
296
297
// Translate glslang profile to SPIR-V source language.
298
spv::SourceLanguage TranslateSourceLanguage(glslang::EShSource source, EProfile profile)
299
2.08k
{
300
2.08k
    switch (source) {
301
2.02k
    case glslang::EShSourceGlsl:
302
2.02k
        switch (profile) {
303
32
        case ENoProfile:
304
1.68k
        case ECoreProfile:
305
1.68k
        case ECompatibilityProfile:
306
1.68k
            return spv::SourceLanguage::GLSL;
307
334
        case EEsProfile:
308
334
            return spv::SourceLanguage::ESSL;
309
0
        default:
310
0
            return spv::SourceLanguage::Unknown;
311
2.02k
        }
312
64
    case glslang::EShSourceHlsl:
313
64
        return spv::SourceLanguage::HLSL;
314
0
    default:
315
0
        return spv::SourceLanguage::Unknown;
316
2.08k
    }
317
2.08k
}
318
319
// Translate glslang language (stage) to SPIR-V execution model.
320
spv::ExecutionModel TranslateExecutionModel(EShLanguage stage, bool isMeshShaderEXT = false)
321
2.08k
{
322
2.08k
    switch (stage) {
323
1.80k
    case EShLangVertex:           return spv::ExecutionModel::Vertex;
324
229
    case EShLangFragment:         return spv::ExecutionModel::Fragment;
325
4
    case EShLangCompute:          return spv::ExecutionModel::GLCompute;
326
0
    case EShLangTessControl:      return spv::ExecutionModel::TessellationControl;
327
0
    case EShLangTessEvaluation:   return spv::ExecutionModel::TessellationEvaluation;
328
0
    case EShLangGeometry:         return spv::ExecutionModel::Geometry;
329
38
    case EShLangRayGen:           return spv::ExecutionModel::RayGenerationKHR;
330
2
    case EShLangIntersect:        return spv::ExecutionModel::IntersectionKHR;
331
0
    case EShLangAnyHit:           return spv::ExecutionModel::AnyHitKHR;
332
6
    case EShLangClosestHit:       return spv::ExecutionModel::ClosestHitKHR;
333
0
    case EShLangMiss:             return spv::ExecutionModel::MissKHR;
334
0
    case EShLangCallable:         return spv::ExecutionModel::CallableKHR;
335
2
    case EShLangTask:             return (isMeshShaderEXT)? spv::ExecutionModel::TaskEXT : spv::ExecutionModel::TaskNV;
336
0
    case EShLangMesh:             return (isMeshShaderEXT)? spv::ExecutionModel::MeshEXT : spv::ExecutionModel::MeshNV;
337
0
    default:
338
0
        assert(0);
339
0
        return spv::ExecutionModel::Fragment;
340
2.08k
    }
341
2.08k
}
342
343
// Translate glslang sampler type to SPIR-V dimensionality.
344
spv::Dim TranslateDimensionality(const glslang::TSampler& sampler)
345
3.05k
{
346
3.05k
    switch (sampler.dim) {
347
334
    case glslang::Esd1D:      return spv::Dim::Dim1D;
348
2.10k
    case glslang::Esd2D:      return spv::Dim::Dim2D;
349
136
    case glslang::Esd3D:      return spv::Dim::Dim3D;
350
271
    case glslang::EsdCube:    return spv::Dim::Cube;
351
35
    case glslang::EsdRect:    return spv::Dim::Rect;
352
65
    case glslang::EsdBuffer:  return spv::Dim::Buffer;
353
109
    case glslang::EsdSubpass: return spv::Dim::SubpassData;
354
1
    case glslang::EsdAttachmentEXT: return spv::Dim::TileImageDataEXT;
355
0
    default:
356
0
        assert(0);
357
0
        return spv::Dim::Dim2D;
358
3.05k
    }
359
3.05k
}
360
361
// Translate glslang precision to SPIR-V precision decorations.
362
spv::Decoration TranslatePrecisionDecoration(glslang::TPrecisionQualifier glslangPrecision)
363
221k
{
364
221k
    switch (glslangPrecision) {
365
340
    case glslang::EpqLow:    return spv::Decoration::RelaxedPrecision;
366
1.26k
    case glslang::EpqMedium: return spv::Decoration::RelaxedPrecision;
367
219k
    default:
368
219k
        return spv::NoPrecision;
369
221k
    }
370
221k
}
371
372
// Translate glslang type to SPIR-V precision decorations.
373
spv::Decoration TranslatePrecisionDecoration(const glslang::TType& type)
374
136k
{
375
136k
    return TranslatePrecisionDecoration(type.getQualifier().precision);
376
136k
}
377
378
// Translate glslang type to SPIR-V block decorations.
379
spv::Decoration TranslateBlockDecoration(const glslang::TStorageQualifier storage, bool useStorageBuffer)
380
1.61k
{
381
1.61k
    switch (storage) {
382
838
    case glslang::EvqUniform:      return spv::Decoration::Block;
383
767
    case glslang::EvqBuffer:       return useStorageBuffer ? spv::Decoration::Block : spv::Decoration::BufferBlock;
384
13
    case glslang::EvqVaryingIn:    return spv::Decoration::Block;
385
0
    case glslang::EvqVaryingOut:   return spv::Decoration::Block;
386
0
    case glslang::EvqShared:       return spv::Decoration::Block;
387
0
    case glslang::EvqPayload:      return spv::Decoration::Block;
388
0
    case glslang::EvqPayloadIn:    return spv::Decoration::Block;
389
0
    case glslang::EvqHitAttr:      return spv::Decoration::Block;
390
0
    case glslang::EvqCallableData:   return spv::Decoration::Block;
391
0
    case glslang::EvqCallableDataIn: return spv::Decoration::Block;
392
0
    case glslang::EvqHitObjectAttrNV: return spv::Decoration::Block;
393
0
    case glslang::EvqHitObjectAttrEXT: return spv::Decoration::Block;
394
0
    default:
395
0
        assert(0);
396
0
        break;
397
1.61k
    }
398
399
0
    return spv::Decoration::Max;
400
1.61k
}
401
402
// Translate glslang type to SPIR-V memory decorations.
403
void TranslateMemoryDecoration(const glslang::TQualifier& qualifier, std::vector<spv::Decoration>& memory,
404
    bool useVulkanMemoryModel)
405
26.7k
{
406
26.7k
    if (!useVulkanMemoryModel) {
407
26.1k
        if (qualifier.isVolatile()) {
408
706
            memory.push_back(spv::Decoration::Volatile);
409
706
            memory.push_back(spv::Decoration::Coherent);
410
25.4k
        } else if (qualifier.isCoherent()) {
411
29
            memory.push_back(spv::Decoration::Coherent);
412
29
        }
413
26.1k
    }
414
26.7k
    if (qualifier.isRestrict())
415
306
        memory.push_back(spv::Decoration::Restrict);
416
26.7k
    if (qualifier.isReadOnly())
417
399
        memory.push_back(spv::Decoration::NonWritable);
418
26.7k
    if (qualifier.isWriteOnly())
419
162
        memory.push_back(spv::Decoration::NonReadable);
420
26.7k
}
421
422
// Translate glslang type to SPIR-V layout decorations.
423
spv::Decoration TranslateLayoutDecoration(const glslang::TType& type, glslang::TLayoutMatrix matrixLayout)
424
10.1k
{
425
10.1k
    if (type.isMatrix()) {
426
393
        switch (matrixLayout) {
427
12
        case glslang::ElmRowMajor:
428
12
            return spv::Decoration::RowMajor;
429
274
        case glslang::ElmColumnMajor:
430
274
            return spv::Decoration::ColMajor;
431
107
        default:
432
            // opaque layouts don't need a majorness
433
107
            return spv::Decoration::Max;
434
393
        }
435
9.78k
    } else {
436
9.78k
        switch (type.getBasicType()) {
437
8.17k
        default:
438
8.17k
            return spv::Decoration::Max;
439
0
            break;
440
1.61k
        case glslang::EbtBlock:
441
1.61k
            switch (type.getQualifier().storage) {
442
0
            case glslang::EvqShared:
443
838
            case glslang::EvqUniform:
444
1.60k
            case glslang::EvqBuffer:
445
1.60k
                switch (type.getQualifier().layoutPacking) {
446
0
                case glslang::ElpShared:  return spv::Decoration::GLSLShared;
447
0
                case glslang::ElpPacked:  return spv::Decoration::GLSLPacked;
448
1.60k
                default:
449
1.60k
                    return spv::Decoration::Max;
450
1.60k
                }
451
13
            case glslang::EvqVaryingIn:
452
13
            case glslang::EvqVaryingOut:
453
13
                if (type.getQualifier().isTaskMemory()) {
454
0
                    switch (type.getQualifier().layoutPacking) {
455
0
                    case glslang::ElpShared:  return spv::Decoration::GLSLShared;
456
0
                    case glslang::ElpPacked:  return spv::Decoration::GLSLPacked;
457
0
                    default: break;
458
0
                    }
459
13
                } else {
460
13
                    assert(type.getQualifier().layoutPacking == glslang::ElpNone);
461
13
                }
462
13
                return spv::Decoration::Max;
463
0
            case glslang::EvqPayload:
464
0
            case glslang::EvqPayloadIn:
465
0
            case glslang::EvqHitAttr:
466
0
            case glslang::EvqCallableData:
467
0
            case glslang::EvqCallableDataIn:
468
0
            case glslang::EvqHitObjectAttrNV:
469
0
            case glslang::EvqHitObjectAttrEXT:
470
0
                return spv::Decoration::Max;
471
0
            default:
472
0
                assert(0);
473
0
                return spv::Decoration::Max;
474
1.61k
            }
475
9.78k
        }
476
9.78k
    }
477
10.1k
}
478
479
// Translate glslang type to SPIR-V interpolation decorations.
480
// Returns spv::Decoration::Max when no decoration
481
// should be applied.
482
spv::Decoration TGlslangToSpvTraverser::TranslateInterpolationDecoration(const glslang::TQualifier& qualifier)
483
20.2k
{
484
20.2k
    if (qualifier.smooth)
485
        // Smooth decoration doesn't exist in SPIR-V 1.0
486
951
        return spv::Decoration::Max;
487
19.3k
    else if (qualifier.isNonPerspective())
488
0
        return spv::Decoration::NoPerspective;
489
19.3k
    else if (qualifier.flat)
490
81
        return spv::Decoration::Flat;
491
19.2k
    else if (qualifier.isExplicitInterpolation()) {
492
0
        builder.addExtension(spv::E_SPV_AMD_shader_explicit_vertex_parameter);
493
0
        return spv::Decoration::ExplicitInterpAMD;
494
0
    }
495
19.2k
    else
496
19.2k
        return spv::Decoration::Max;
497
20.2k
}
498
499
// Translate glslang type to SPIR-V auxiliary storage decorations.
500
// Returns spv::Decoration::Max when no decoration
501
// should be applied.
502
spv::Decoration TGlslangToSpvTraverser::TranslateAuxiliaryStorageDecoration(const glslang::TQualifier& qualifier)
503
20.2k
{
504
20.2k
    if (qualifier.centroid)
505
0
        return spv::Decoration::Centroid;
506
20.2k
    else if (qualifier.patch)
507
0
        return spv::Decoration::Patch;
508
20.2k
    else if (qualifier.sample) {
509
1
        builder.addCapability(spv::Capability::SampleRateShading);
510
1
        return spv::Decoration::Sample;
511
1
    }
512
513
20.2k
    return spv::Decoration::Max;
514
20.2k
}
515
516
// If glslang type is invariant, return SPIR-V invariant decoration.
517
spv::Decoration TranslateInvariantDecoration(const glslang::TQualifier& qualifier)
518
28.7k
{
519
28.7k
    if (qualifier.invariant)
520
0
        return spv::Decoration::Invariant;
521
28.7k
    else
522
28.7k
        return spv::Decoration::Max;
523
28.7k
}
524
525
// If glslang type is noContraction, return SPIR-V NoContraction decoration.
526
spv::Decoration TranslateNoContractionDecoration(const glslang::TQualifier& qualifier)
527
26.4k
{
528
26.4k
    if (qualifier.isNoContraction())
529
0
        return spv::Decoration::NoContraction;
530
26.4k
    else
531
26.4k
        return spv::Decoration::Max;
532
26.4k
}
533
534
// If glslang type is nonUniform, return SPIR-V NonUniform decoration.
535
spv::Decoration TGlslangToSpvTraverser::TranslateNonUniformDecoration(const glslang::TQualifier& qualifier)
536
128k
{
537
128k
    if (qualifier.isNonUniform()) {
538
70
        builder.addIncorporatedExtension("SPV_EXT_descriptor_indexing", spv::Spv_1_5);
539
70
        builder.addCapability(spv::Capability::ShaderNonUniformEXT);
540
70
        return spv::Decoration::NonUniformEXT;
541
70
    } else
542
128k
        return spv::Decoration::Max;
543
128k
}
544
545
// If lvalue flags contains nonUniform, return SPIR-V NonUniform decoration.
546
spv::Decoration TGlslangToSpvTraverser::TranslateNonUniformDecoration(
547
    const spv::Builder::AccessChain::CoherentFlags& coherentFlags)
548
132k
{
549
132k
    if (coherentFlags.isNonUniform()) {
550
33
        builder.addIncorporatedExtension("SPV_EXT_descriptor_indexing", spv::Spv_1_5);
551
33
        builder.addCapability(spv::Capability::ShaderNonUniformEXT);
552
33
        return spv::Decoration::NonUniformEXT;
553
33
    } else
554
132k
        return spv::Decoration::Max;
555
132k
}
556
557
spv::MemoryAccessMask TGlslangToSpvTraverser::TranslateMemoryAccess(
558
    const spv::Builder::AccessChain::CoherentFlags &coherentFlags)
559
122k
{
560
122k
    spv::MemoryAccessMask mask = spv::MemoryAccessMask::MaskNone;
561
562
122k
    if (!glslangIntermediate->usingVulkanMemoryModel() || coherentFlags.isImage)
563
122k
        return mask;
564
565
359
    if (coherentFlags.isVolatile() || coherentFlags.anyCoherent()) {
566
2
        mask = mask | spv::MemoryAccessMask::MakePointerAvailableKHR | 
567
2
                      spv::MemoryAccessMask::MakePointerVisibleKHR;
568
2
    }
569
570
359
    if (coherentFlags.nonprivate) {
571
2
        mask = mask | spv::MemoryAccessMask::NonPrivatePointerKHR;
572
2
    }
573
359
    if (coherentFlags.volatil) {
574
0
        mask = mask | spv::MemoryAccessMask::Volatile;
575
0
    }
576
359
    if (coherentFlags.nontemporal) {
577
92
        mask = mask | spv::MemoryAccessMask::Nontemporal;
578
92
    }
579
359
    if (mask != spv::MemoryAccessMask::MaskNone) {
580
94
        builder.addCapability(spv::Capability::VulkanMemoryModelKHR);
581
94
    }
582
583
359
    return mask;
584
122k
}
585
586
spv::ImageOperandsMask TGlslangToSpvTraverser::TranslateImageOperands(
587
    const spv::Builder::AccessChain::CoherentFlags &coherentFlags)
588
595
{
589
595
    spv::ImageOperandsMask mask = spv::ImageOperandsMask::MaskNone;
590
591
595
    if (!glslangIntermediate->usingVulkanMemoryModel())
592
543
        return mask;
593
594
52
    if (coherentFlags.volatil ||
595
52
        coherentFlags.anyCoherent()) {
596
0
        mask = mask | spv::ImageOperandsMask::MakeTexelAvailableKHR |
597
0
                      spv::ImageOperandsMask::MakeTexelVisibleKHR;
598
0
    }
599
52
    if (coherentFlags.nonprivate) {
600
0
        mask = mask | spv::ImageOperandsMask::NonPrivateTexelKHR;
601
0
    }
602
52
    if (coherentFlags.volatil) {
603
0
        mask = mask | spv::ImageOperandsMask::VolatileTexelKHR;
604
0
    }
605
52
    if (coherentFlags.nontemporal && builder.getSpvVersion() >= spv::Spv_1_6) {
606
0
        mask = mask | spv::ImageOperandsMask::Nontemporal;
607
0
    }
608
52
    if (mask != spv::ImageOperandsMask::MaskNone) {
609
0
        builder.addCapability(spv::Capability::VulkanMemoryModelKHR);
610
0
    }
611
612
52
    return mask;
613
595
}
614
615
spv::Builder::AccessChain::CoherentFlags TGlslangToSpvTraverser::TranslateCoherent(const glslang::TType& type)
616
162k
{
617
162k
    spv::Builder::AccessChain::CoherentFlags flags = {};
618
162k
    flags.coherent = type.getQualifier().coherent;
619
162k
    flags.devicecoherent = type.getQualifier().devicecoherent;
620
162k
    flags.queuefamilycoherent = type.getQualifier().queuefamilycoherent;
621
    // shared variables are implicitly workgroupcoherent in GLSL.
622
162k
    flags.workgroupcoherent = type.getQualifier().workgroupcoherent ||
623
162k
                              type.getQualifier().storage == glslang::EvqShared;
624
162k
    flags.subgroupcoherent = type.getQualifier().subgroupcoherent;
625
162k
    flags.shadercallcoherent = type.getQualifier().shadercallcoherent;
626
162k
    flags.volatil = type.getQualifier().volatil;
627
162k
    flags.nontemporal = type.getQualifier().nontemporal;
628
    // *coherent variables are implicitly nonprivate in GLSL
629
162k
    flags.nonprivate = type.getQualifier().nonprivate ||
630
162k
                       flags.anyCoherent() ||
631
161k
                       flags.volatil;
632
162k
    flags.isImage = type.getBasicType() == glslang::EbtSampler;
633
162k
    flags.nonUniform = type.getQualifier().nonUniform;
634
162k
    return flags;
635
162k
}
636
637
spv::Scope TGlslangToSpvTraverser::TranslateMemoryScope(
638
    const spv::Builder::AccessChain::CoherentFlags &coherentFlags)
639
122k
{
640
122k
    spv::Scope scope = spv::Scope::Max;
641
642
122k
    if (coherentFlags.volatil || coherentFlags.coherent) {
643
        // coherent defaults to Device scope in the old model, QueueFamilyKHR scope in the new model
644
25
        scope = glslangIntermediate->usingVulkanMemoryModel() ? spv::Scope::QueueFamilyKHR : spv::Scope::Device;
645
122k
    } else if (coherentFlags.devicecoherent) {
646
0
        scope = spv::Scope::Device;
647
122k
    } else if (coherentFlags.queuefamilycoherent) {
648
0
        scope = spv::Scope::QueueFamilyKHR;
649
122k
    } else if (coherentFlags.workgroupcoherent) {
650
0
        scope = spv::Scope::Workgroup;
651
122k
    } else if (coherentFlags.subgroupcoherent) {
652
0
        scope = spv::Scope::Subgroup;
653
122k
    } else if (coherentFlags.shadercallcoherent) {
654
0
        scope = spv::Scope::ShaderCallKHR;
655
0
    }
656
122k
    if (glslangIntermediate->usingVulkanMemoryModel() && scope == spv::Scope::Device) {
657
0
        builder.addCapability(spv::Capability::VulkanMemoryModelDeviceScopeKHR);
658
0
    }
659
660
122k
    return scope;
661
122k
}
662
663
// Translate a glslang built-in variable to a SPIR-V built in decoration.  Also generate
664
// associated capabilities when required.  For some built-in variables, a capability
665
// is generated only when using the variable in an executable instruction, but not when
666
// just declaring a struct member variable with it.  This is true for PointSize,
667
// ClipDistance, and CullDistance.
668
spv::BuiltIn TGlslangToSpvTraverser::TranslateBuiltInDecoration(glslang::TBuiltInVariable builtIn,
669
    bool memberDeclaration)
670
28.7k
{
671
28.7k
    switch (builtIn) {
672
0
    case glslang::EbvPointSize:
673
        // Defer adding the capability until the built-in is actually used.
674
0
        if (! memberDeclaration) {
675
0
            switch (glslangIntermediate->getStage()) {
676
0
            case EShLangGeometry:
677
0
                builder.addCapability(spv::Capability::GeometryPointSize);
678
0
                break;
679
0
            case EShLangTessControl:
680
0
            case EShLangTessEvaluation:
681
0
                builder.addCapability(spv::Capability::TessellationPointSize);
682
0
                break;
683
0
            default:
684
0
                break;
685
0
            }
686
0
        }
687
0
        return spv::BuiltIn::PointSize;
688
689
0
    case glslang::EbvPosition:             return spv::BuiltIn::Position;
690
0
    case glslang::EbvVertexId:             return spv::BuiltIn::VertexId;
691
0
    case glslang::EbvInstanceId:           return spv::BuiltIn::InstanceId;
692
0
    case glslang::EbvVertexIndex:          return spv::BuiltIn::VertexIndex;
693
0
    case glslang::EbvInstanceIndex:        return spv::BuiltIn::InstanceIndex;
694
695
6
    case glslang::EbvFragCoord:            return spv::BuiltIn::FragCoord;
696
0
    case glslang::EbvPointCoord:           return spv::BuiltIn::PointCoord;
697
0
    case glslang::EbvFace:                 return spv::BuiltIn::FrontFacing;
698
4
    case glslang::EbvFragDepth:            return spv::BuiltIn::FragDepth;
699
700
0
    case glslang::EbvNumWorkGroups:        return spv::BuiltIn::NumWorkgroups;
701
0
    case glslang::EbvWorkGroupSize:        return spv::BuiltIn::WorkgroupSize;
702
0
    case glslang::EbvWorkGroupId:          return spv::BuiltIn::WorkgroupId;
703
0
    case glslang::EbvLocalInvocationId:    return spv::BuiltIn::LocalInvocationId;
704
0
    case glslang::EbvLocalInvocationIndex: return spv::BuiltIn::LocalInvocationIndex;
705
0
    case glslang::EbvGlobalInvocationId:   return spv::BuiltIn::GlobalInvocationId;
706
707
    // These *Distance capabilities logically belong here, but if the member is declared and
708
    // then never used, consumers of SPIR-V prefer the capability not be declared.
709
    // They are now generated when used, rather than here when declared.
710
    // Potentially, the specification should be more clear what the minimum
711
    // use needed is to trigger the capability.
712
    //
713
0
    case glslang::EbvClipDistance:
714
0
        if (!memberDeclaration)
715
0
            builder.addCapability(spv::Capability::ClipDistance);
716
0
        return spv::BuiltIn::ClipDistance;
717
718
0
    case glslang::EbvCullDistance:
719
0
        if (!memberDeclaration)
720
0
            builder.addCapability(spv::Capability::CullDistance);
721
0
        return spv::BuiltIn::CullDistance;
722
723
0
    case glslang::EbvViewportIndex:
724
0
        if (glslangIntermediate->getStage() == EShLangGeometry ||
725
0
            glslangIntermediate->getStage() == EShLangFragment) {
726
0
            builder.addCapability(spv::Capability::MultiViewport);
727
0
        }
728
0
        if (glslangIntermediate->getStage() == EShLangVertex ||
729
0
            glslangIntermediate->getStage() == EShLangTessControl ||
730
0
            glslangIntermediate->getStage() == EShLangTessEvaluation) {
731
732
0
            if (builder.getSpvVersion() < spv::Spv_1_5) {
733
0
                builder.addIncorporatedExtension(spv::E_SPV_EXT_shader_viewport_index_layer, spv::Spv_1_5);
734
0
                builder.addCapability(spv::Capability::ShaderViewportIndexLayerEXT);
735
0
            }
736
0
            else
737
0
                builder.addCapability(spv::Capability::ShaderViewportIndex);
738
0
        }
739
0
        return spv::BuiltIn::ViewportIndex;
740
741
2
    case glslang::EbvSampleId:
742
2
        builder.addCapability(spv::Capability::SampleRateShading);
743
2
        return spv::BuiltIn::SampleId;
744
745
2
    case glslang::EbvSamplePosition:
746
2
        builder.addCapability(spv::Capability::SampleRateShading);
747
2
        return spv::BuiltIn::SamplePosition;
748
749
2
    case glslang::EbvSampleMask:
750
2
        return spv::BuiltIn::SampleMask;
751
752
0
    case glslang::EbvLayer:
753
0
        if (glslangIntermediate->getStage() == EShLangMesh) {
754
0
            return spv::BuiltIn::Layer;
755
0
        }
756
0
        if (glslangIntermediate->getStage() == EShLangGeometry ||
757
0
            glslangIntermediate->getStage() == EShLangFragment) {
758
0
            builder.addCapability(spv::Capability::Geometry);
759
0
        }
760
0
        if (glslangIntermediate->getStage() == EShLangVertex ||
761
0
            glslangIntermediate->getStage() == EShLangTessControl ||
762
0
            glslangIntermediate->getStage() == EShLangTessEvaluation) {
763
764
0
            if (builder.getSpvVersion() < spv::Spv_1_5) {
765
0
                builder.addIncorporatedExtension(spv::E_SPV_EXT_shader_viewport_index_layer, spv::Spv_1_5);
766
0
                builder.addCapability(spv::Capability::ShaderViewportIndexLayerEXT);
767
0
            } else
768
0
                builder.addCapability(spv::Capability::ShaderLayer);
769
0
        }
770
0
        return spv::BuiltIn::Layer;
771
772
0
    case glslang::EbvBaseVertex:
773
0
        builder.addIncorporatedExtension(spv::E_SPV_KHR_shader_draw_parameters, spv::Spv_1_3);
774
0
        builder.addCapability(spv::Capability::DrawParameters);
775
0
        return spv::BuiltIn::BaseVertex;
776
777
0
    case glslang::EbvBaseInstance:
778
0
        builder.addIncorporatedExtension(spv::E_SPV_KHR_shader_draw_parameters, spv::Spv_1_3);
779
0
        builder.addCapability(spv::Capability::DrawParameters);
780
0
        return spv::BuiltIn::BaseInstance;
781
782
0
    case glslang::EbvDrawId:
783
0
        builder.addIncorporatedExtension(spv::E_SPV_KHR_shader_draw_parameters, spv::Spv_1_3);
784
0
        builder.addCapability(spv::Capability::DrawParameters);
785
0
        return spv::BuiltIn::DrawIndex;
786
787
0
    case glslang::EbvPrimitiveId:
788
0
        if (glslangIntermediate->getStage() == EShLangFragment)
789
0
            builder.addCapability(spv::Capability::Geometry);
790
0
        return spv::BuiltIn::PrimitiveId;
791
792
1
    case glslang::EbvFragStencilRef:
793
1
        builder.addExtension(spv::E_SPV_EXT_shader_stencil_export);
794
1
        builder.addCapability(spv::Capability::StencilExportEXT);
795
1
        return spv::BuiltIn::FragStencilRefEXT;
796
797
0
    case glslang::EbvShadingRateKHR:
798
0
        builder.addExtension(spv::E_SPV_KHR_fragment_shading_rate);
799
0
        builder.addCapability(spv::Capability::FragmentShadingRateKHR);
800
0
        return spv::BuiltIn::ShadingRateKHR;
801
802
0
    case glslang::EbvPrimitiveShadingRateKHR:
803
0
        builder.addExtension(spv::E_SPV_KHR_fragment_shading_rate);
804
0
        builder.addCapability(spv::Capability::FragmentShadingRateKHR);
805
0
        return spv::BuiltIn::PrimitiveShadingRateKHR;
806
807
0
    case glslang::EbvInvocationId:         return spv::BuiltIn::InvocationId;
808
0
    case glslang::EbvTessLevelInner:       return spv::BuiltIn::TessLevelInner;
809
0
    case glslang::EbvTessLevelOuter:       return spv::BuiltIn::TessLevelOuter;
810
0
    case glslang::EbvTessCoord:            return spv::BuiltIn::TessCoord;
811
0
    case glslang::EbvPatchVertices:        return spv::BuiltIn::PatchVertices;
812
2
    case glslang::EbvHelperInvocation:     return spv::BuiltIn::HelperInvocation;
813
814
20
    case glslang::EbvSubGroupSize:
815
20
        builder.addExtension(spv::E_SPV_KHR_shader_ballot);
816
20
        builder.addCapability(spv::Capability::SubgroupBallotKHR);
817
20
        return spv::BuiltIn::SubgroupSize;
818
819
0
    case glslang::EbvSubGroupInvocation:
820
0
        builder.addExtension(spv::E_SPV_KHR_shader_ballot);
821
0
        builder.addCapability(spv::Capability::SubgroupBallotKHR);
822
0
        return spv::BuiltIn::SubgroupLocalInvocationId;
823
824
0
    case glslang::EbvSubGroupEqMask:
825
0
        builder.addExtension(spv::E_SPV_KHR_shader_ballot);
826
0
        builder.addCapability(spv::Capability::SubgroupBallotKHR);
827
0
        return spv::BuiltIn::SubgroupEqMask;
828
829
0
    case glslang::EbvSubGroupGeMask:
830
0
        builder.addExtension(spv::E_SPV_KHR_shader_ballot);
831
0
        builder.addCapability(spv::Capability::SubgroupBallotKHR);
832
0
        return spv::BuiltIn::SubgroupGeMask;
833
834
0
    case glslang::EbvSubGroupGtMask:
835
0
        builder.addExtension(spv::E_SPV_KHR_shader_ballot);
836
0
        builder.addCapability(spv::Capability::SubgroupBallotKHR);
837
0
        return spv::BuiltIn::SubgroupGtMask;
838
839
0
    case glslang::EbvSubGroupLeMask:
840
0
        builder.addExtension(spv::E_SPV_KHR_shader_ballot);
841
0
        builder.addCapability(spv::Capability::SubgroupBallotKHR);
842
0
        return spv::BuiltIn::SubgroupLeMask;
843
844
0
    case glslang::EbvSubGroupLtMask:
845
0
        builder.addExtension(spv::E_SPV_KHR_shader_ballot);
846
0
        builder.addCapability(spv::Capability::SubgroupBallotKHR);
847
0
        return spv::BuiltIn::SubgroupLtMask;
848
849
0
    case glslang::EbvNumSubgroups:
850
0
        builder.addCapability(spv::Capability::GroupNonUniform);
851
0
        return spv::BuiltIn::NumSubgroups;
852
853
0
    case glslang::EbvSubgroupID:
854
0
        builder.addCapability(spv::Capability::GroupNonUniform);
855
0
        return spv::BuiltIn::SubgroupId;
856
857
20
    case glslang::EbvSubgroupSize2:
858
20
        builder.addCapability(spv::Capability::GroupNonUniform);
859
20
        return spv::BuiltIn::SubgroupSize;
860
861
20
    case glslang::EbvSubgroupInvocation2:
862
20
        builder.addCapability(spv::Capability::GroupNonUniform);
863
20
        return spv::BuiltIn::SubgroupLocalInvocationId;
864
865
0
    case glslang::EbvSubgroupEqMask2:
866
0
        builder.addCapability(spv::Capability::GroupNonUniform);
867
0
        builder.addCapability(spv::Capability::GroupNonUniformBallot);
868
0
        return spv::BuiltIn::SubgroupEqMask;
869
870
0
    case glslang::EbvSubgroupGeMask2:
871
0
        builder.addCapability(spv::Capability::GroupNonUniform);
872
0
        builder.addCapability(spv::Capability::GroupNonUniformBallot);
873
0
        return spv::BuiltIn::SubgroupGeMask;
874
875
0
    case glslang::EbvSubgroupGtMask2:
876
0
        builder.addCapability(spv::Capability::GroupNonUniform);
877
0
        builder.addCapability(spv::Capability::GroupNonUniformBallot);
878
0
        return spv::BuiltIn::SubgroupGtMask;
879
880
0
    case glslang::EbvSubgroupLeMask2:
881
0
        builder.addCapability(spv::Capability::GroupNonUniform);
882
0
        builder.addCapability(spv::Capability::GroupNonUniformBallot);
883
0
        return spv::BuiltIn::SubgroupLeMask;
884
885
0
    case glslang::EbvSubgroupLtMask2:
886
0
        builder.addCapability(spv::Capability::GroupNonUniform);
887
0
        builder.addCapability(spv::Capability::GroupNonUniformBallot);
888
0
        return spv::BuiltIn::SubgroupLtMask;
889
890
0
    case glslang::EbvBaryCoordNoPersp:
891
0
        builder.addExtension(spv::E_SPV_AMD_shader_explicit_vertex_parameter);
892
0
        return spv::BuiltIn::BaryCoordNoPerspAMD;
893
894
0
    case glslang::EbvBaryCoordNoPerspCentroid:
895
0
        builder.addExtension(spv::E_SPV_AMD_shader_explicit_vertex_parameter);
896
0
        return spv::BuiltIn::BaryCoordNoPerspCentroidAMD;
897
898
0
    case glslang::EbvBaryCoordNoPerspSample:
899
0
        builder.addExtension(spv::E_SPV_AMD_shader_explicit_vertex_parameter);
900
0
        return spv::BuiltIn::BaryCoordNoPerspSampleAMD;
901
902
0
    case glslang::EbvBaryCoordSmooth:
903
0
        builder.addExtension(spv::E_SPV_AMD_shader_explicit_vertex_parameter);
904
0
        return spv::BuiltIn::BaryCoordSmoothAMD;
905
906
0
    case glslang::EbvBaryCoordSmoothCentroid:
907
0
        builder.addExtension(spv::E_SPV_AMD_shader_explicit_vertex_parameter);
908
0
        return spv::BuiltIn::BaryCoordSmoothCentroidAMD;
909
910
0
    case glslang::EbvBaryCoordSmoothSample:
911
0
        builder.addExtension(spv::E_SPV_AMD_shader_explicit_vertex_parameter);
912
0
        return spv::BuiltIn::BaryCoordSmoothSampleAMD;
913
914
0
    case glslang::EbvBaryCoordPullModel:
915
0
        builder.addExtension(spv::E_SPV_AMD_shader_explicit_vertex_parameter);
916
0
        return spv::BuiltIn::BaryCoordPullModelAMD;
917
918
2
    case glslang::EbvDeviceIndex:
919
2
        builder.addIncorporatedExtension(spv::E_SPV_KHR_device_group, spv::Spv_1_3);
920
2
        builder.addCapability(spv::Capability::DeviceGroup);
921
2
        return spv::BuiltIn::DeviceIndex;
922
923
2
    case glslang::EbvViewIndex:
924
2
        builder.addIncorporatedExtension(spv::E_SPV_KHR_multiview, spv::Spv_1_3);
925
2
        builder.addCapability(spv::Capability::MultiView);
926
2
        return spv::BuiltIn::ViewIndex;
927
928
2
    case glslang::EbvFragSizeEXT:
929
2
        builder.addExtension(spv::E_SPV_EXT_fragment_invocation_density);
930
2
        builder.addCapability(spv::Capability::FragmentDensityEXT);
931
2
        return spv::BuiltIn::FragSizeEXT;
932
933
2
    case glslang::EbvFragInvocationCountEXT:
934
2
        builder.addExtension(spv::E_SPV_EXT_fragment_invocation_density);
935
2
        builder.addCapability(spv::Capability::FragmentDensityEXT);
936
2
        return spv::BuiltIn::FragInvocationCountEXT;
937
938
0
    case glslang::EbvViewportMaskNV:
939
0
        if (!memberDeclaration) {
940
0
            builder.addExtension(spv::E_SPV_NV_viewport_array2);
941
0
            builder.addCapability(spv::Capability::ShaderViewportMaskNV);
942
0
        }
943
0
        return spv::BuiltIn::ViewportMaskNV;
944
0
    case glslang::EbvSecondaryPositionNV:
945
0
        if (!memberDeclaration) {
946
0
            builder.addExtension(spv::E_SPV_NV_stereo_view_rendering);
947
0
            builder.addCapability(spv::Capability::ShaderStereoViewNV);
948
0
        }
949
0
        return spv::BuiltIn::SecondaryPositionNV;
950
0
    case glslang::EbvSecondaryViewportMaskNV:
951
0
        if (!memberDeclaration) {
952
0
            builder.addExtension(spv::E_SPV_NV_stereo_view_rendering);
953
0
            builder.addCapability(spv::Capability::ShaderStereoViewNV);
954
0
        }
955
0
        return spv::BuiltIn::SecondaryViewportMaskNV;
956
0
    case glslang::EbvPositionPerViewNV:
957
0
        if (!memberDeclaration) {
958
0
            builder.addExtension(spv::E_SPV_NVX_multiview_per_view_attributes);
959
0
            builder.addCapability(spv::Capability::PerViewAttributesNV);
960
0
        }
961
0
        return spv::BuiltIn::PositionPerViewNV;
962
0
    case glslang::EbvViewportMaskPerViewNV:
963
0
        if (!memberDeclaration) {
964
0
            builder.addExtension(spv::E_SPV_NVX_multiview_per_view_attributes);
965
0
            builder.addCapability(spv::Capability::PerViewAttributesNV);
966
0
        }
967
0
        return spv::BuiltIn::ViewportMaskPerViewNV;
968
0
    case glslang::EbvFragFullyCoveredNV:
969
0
        builder.addExtension(spv::E_SPV_EXT_fragment_fully_covered);
970
0
        builder.addCapability(spv::Capability::FragmentFullyCoveredEXT);
971
0
        return spv::BuiltIn::FullyCoveredEXT;
972
1
    case glslang::EbvFragmentSizeNV:
973
1
        builder.addExtension(spv::E_SPV_NV_shading_rate);
974
1
        builder.addCapability(spv::Capability::ShadingRateNV);
975
1
        return spv::BuiltIn::FragmentSizeNV;
976
1
    case glslang::EbvInvocationsPerPixelNV:
977
1
        builder.addExtension(spv::E_SPV_NV_shading_rate);
978
1
        builder.addCapability(spv::Capability::ShadingRateNV);
979
1
        return spv::BuiltIn::InvocationsPerPixelNV;
980
981
    // ray tracing
982
0
    case glslang::EbvLaunchId:
983
0
        return spv::BuiltIn::LaunchIdKHR;
984
0
    case glslang::EbvLaunchSize:
985
0
        return spv::BuiltIn::LaunchSizeKHR;
986
0
    case glslang::EbvWorldRayOrigin:
987
0
        return spv::BuiltIn::WorldRayOriginKHR;
988
0
    case glslang::EbvWorldRayDirection:
989
0
        return spv::BuiltIn::WorldRayDirectionKHR;
990
0
    case glslang::EbvObjectRayOrigin:
991
0
        return spv::BuiltIn::ObjectRayOriginKHR;
992
0
    case glslang::EbvObjectRayDirection:
993
0
        return spv::BuiltIn::ObjectRayDirectionKHR;
994
0
    case glslang::EbvRayTmin:
995
0
        return spv::BuiltIn::RayTminKHR;
996
0
    case glslang::EbvRayTmax:
997
0
        return spv::BuiltIn::RayTmaxKHR;
998
0
    case glslang::EbvCullMask:
999
0
        return spv::BuiltIn::CullMaskKHR;
1000
0
    case glslang::EbvPositionFetch:
1001
0
        return spv::BuiltIn::HitTriangleVertexPositionsKHR;
1002
0
    case glslang::EbvInstanceCustomIndex:
1003
0
        return spv::BuiltIn::InstanceCustomIndexKHR;
1004
0
    case glslang::EbvHitKind:
1005
0
        return spv::BuiltIn::HitKindKHR;
1006
0
    case glslang::EbvObjectToWorld:
1007
0
    case glslang::EbvObjectToWorld3x4:
1008
0
        return spv::BuiltIn::ObjectToWorldKHR;
1009
0
    case glslang::EbvWorldToObject:
1010
0
    case glslang::EbvWorldToObject3x4:
1011
0
        return spv::BuiltIn::WorldToObjectKHR;
1012
0
    case glslang::EbvIncomingRayFlags:
1013
0
        return spv::BuiltIn::IncomingRayFlagsKHR;
1014
0
    case glslang::EbvGeometryIndex:
1015
0
        return spv::BuiltIn::RayGeometryIndexKHR;
1016
0
    case glslang::EbvCurrentRayTimeNV:
1017
0
        builder.addExtension(spv::E_SPV_NV_ray_tracing_motion_blur);
1018
0
        builder.addCapability(spv::Capability::RayTracingMotionBlurNV);
1019
0
        return spv::BuiltIn::CurrentRayTimeNV;
1020
0
    case glslang::EbvMicroTrianglePositionNV:
1021
0
        builder.addCapability(spv::Capability::RayTracingDisplacementMicromapNV);
1022
0
        builder.addExtension("SPV_NV_displacement_micromap");
1023
0
        return spv::BuiltIn::HitMicroTriangleVertexPositionsNV;
1024
0
    case glslang::EbvMicroTriangleBaryNV:
1025
0
        builder.addCapability(spv::Capability::RayTracingDisplacementMicromapNV);
1026
0
        builder.addExtension("SPV_NV_displacement_micromap");
1027
0
        return spv::BuiltIn::HitMicroTriangleVertexBarycentricsNV;
1028
0
    case glslang::EbvHitKindFrontFacingMicroTriangleNV:
1029
0
        builder.addCapability(spv::Capability::RayTracingDisplacementMicromapNV);
1030
0
        builder.addExtension("SPV_NV_displacement_micromap");
1031
0
        return spv::BuiltIn::HitKindFrontFacingMicroTriangleNV;
1032
0
    case glslang::EbvHitKindBackFacingMicroTriangleNV:
1033
0
        builder.addCapability(spv::Capability::RayTracingDisplacementMicromapNV);
1034
0
        builder.addExtension("SPV_NV_displacement_micromap");
1035
0
        return spv::BuiltIn::HitKindBackFacingMicroTriangleNV;
1036
0
    case glslang::EbvClusterIDNV:
1037
0
        builder.addCapability(spv::Capability::RayTracingClusterAccelerationStructureNV);
1038
0
        builder.addExtension("SPV_NV_cluster_acceleration_structure");
1039
0
        return spv::BuiltIn::ClusterIDNV;
1040
0
    case glslang::EbvHitIsSphereNV:
1041
0
        builder.addCapability(spv::Capability::RayTracingSpheresGeometryNV);
1042
0
        builder.addExtension("SPV_NV_linear_swept_spheres");
1043
0
        return spv::BuiltIn::HitIsSphereNV;
1044
0
    case glslang::EbvHitIsLSSNV:
1045
0
        builder.addCapability(spv::Capability::RayTracingLinearSweptSpheresGeometryNV);
1046
0
        builder.addExtension("SPV_NV_linear_swept_spheres");
1047
0
        return spv::BuiltIn::HitIsLSSNV;
1048
0
    case glslang::EbvHitSpherePositionNV:
1049
0
        builder.addCapability(spv::Capability::RayTracingSpheresGeometryNV);
1050
0
        builder.addExtension("SPV_NV_linear_swept_spheres");
1051
0
        return spv::BuiltIn::HitSpherePositionNV;
1052
0
    case glslang::EbvHitSphereRadiusNV:
1053
0
        builder.addCapability(spv::Capability::RayTracingSpheresGeometryNV);
1054
0
        builder.addExtension("SPV_NV_linear_swept_spheres");
1055
0
        return spv::BuiltIn::HitSphereRadiusNV;
1056
0
    case glslang::EbvHitLSSPositionsNV:
1057
0
        builder.addCapability(spv::Capability::RayTracingLinearSweptSpheresGeometryNV);
1058
0
        builder.addExtension("SPV_NV_linear_swept_spheres");
1059
0
        return spv::BuiltIn::HitLSSPositionsNV;
1060
0
    case glslang::EbvHitLSSRadiiNV:
1061
0
        builder.addCapability(spv::Capability::RayTracingLinearSweptSpheresGeometryNV);
1062
0
        builder.addExtension("SPV_NV_linear_swept_spheres");
1063
0
        return spv::BuiltIn::HitLSSRadiiNV;
1064
1065
    // barycentrics
1066
1
    case glslang::EbvBaryCoordNV:
1067
1
        builder.addExtension(spv::E_SPV_NV_fragment_shader_barycentric);
1068
1
        builder.addCapability(spv::Capability::FragmentBarycentricNV);
1069
1
        return spv::BuiltIn::BaryCoordNV;
1070
1
    case glslang::EbvBaryCoordNoPerspNV:
1071
1
        builder.addExtension(spv::E_SPV_NV_fragment_shader_barycentric);
1072
1
        builder.addCapability(spv::Capability::FragmentBarycentricNV);
1073
1
        return spv::BuiltIn::BaryCoordNoPerspNV;
1074
1075
1
    case glslang::EbvBaryCoordEXT:
1076
1
        builder.addExtension(spv::E_SPV_KHR_fragment_shader_barycentric);
1077
1
        builder.addCapability(spv::Capability::FragmentBarycentricKHR);
1078
1
        return spv::BuiltIn::BaryCoordKHR;
1079
1
    case glslang::EbvBaryCoordNoPerspEXT:
1080
1
        builder.addExtension(spv::E_SPV_KHR_fragment_shader_barycentric);
1081
1
        builder.addCapability(spv::Capability::FragmentBarycentricKHR);
1082
1
        return spv::BuiltIn::BaryCoordNoPerspKHR;
1083
1084
    // mesh shaders
1085
0
    case glslang::EbvTaskCountNV:
1086
0
        return spv::BuiltIn::TaskCountNV;
1087
0
    case glslang::EbvPrimitiveCountNV:
1088
0
        return spv::BuiltIn::PrimitiveCountNV;
1089
0
    case glslang::EbvPrimitiveIndicesNV:
1090
0
        return spv::BuiltIn::PrimitiveIndicesNV;
1091
0
    case glslang::EbvClipDistancePerViewNV:
1092
0
        return spv::BuiltIn::ClipDistancePerViewNV;
1093
0
    case glslang::EbvCullDistancePerViewNV:
1094
0
        return spv::BuiltIn::CullDistancePerViewNV;
1095
0
    case glslang::EbvLayerPerViewNV:
1096
0
        return spv::BuiltIn::LayerPerViewNV;
1097
0
    case glslang::EbvMeshViewCountNV:
1098
0
        return spv::BuiltIn::MeshViewCountNV;
1099
0
    case glslang::EbvMeshViewIndicesNV:
1100
0
        return spv::BuiltIn::MeshViewIndicesNV;
1101
1102
    // SPV_EXT_mesh_shader
1103
0
    case glslang::EbvPrimitivePointIndicesEXT:
1104
0
        return spv::BuiltIn::PrimitivePointIndicesEXT;
1105
0
    case glslang::EbvPrimitiveLineIndicesEXT:
1106
0
        return spv::BuiltIn::PrimitiveLineIndicesEXT;
1107
0
    case glslang::EbvPrimitiveTriangleIndicesEXT:
1108
0
        return spv::BuiltIn::PrimitiveTriangleIndicesEXT;
1109
0
    case glslang::EbvCullPrimitiveEXT:
1110
0
        return spv::BuiltIn::CullPrimitiveEXT;
1111
1112
    // sm builtins
1113
10
    case glslang::EbvWarpsPerSM:
1114
10
        builder.addExtension(spv::E_SPV_NV_shader_sm_builtins);
1115
10
        builder.addCapability(spv::Capability::ShaderSMBuiltinsNV);
1116
10
        return spv::BuiltIn::WarpsPerSMNV;
1117
10
    case glslang::EbvSMCount:
1118
10
        builder.addExtension(spv::E_SPV_NV_shader_sm_builtins);
1119
10
        builder.addCapability(spv::Capability::ShaderSMBuiltinsNV);
1120
10
        return spv::BuiltIn::SMCountNV;
1121
10
    case glslang::EbvWarpID:
1122
10
        builder.addExtension(spv::E_SPV_NV_shader_sm_builtins);
1123
10
        builder.addCapability(spv::Capability::ShaderSMBuiltinsNV);
1124
10
        return spv::BuiltIn::WarpIDNV;
1125
10
    case glslang::EbvSMID:
1126
10
        builder.addExtension(spv::E_SPV_NV_shader_sm_builtins);
1127
10
        builder.addCapability(spv::Capability::ShaderSMBuiltinsNV);
1128
10
        return spv::BuiltIn::SMIDNV;
1129
1130
   // ARM builtins
1131
10
    case glslang::EbvCoreCountARM:
1132
10
        builder.addExtension(spv::E_SPV_ARM_core_builtins);
1133
10
        builder.addCapability(spv::Capability::CoreBuiltinsARM);
1134
10
        return spv::BuiltIn::CoreCountARM;
1135
10
    case glslang::EbvCoreIDARM:
1136
10
        builder.addExtension(spv::E_SPV_ARM_core_builtins);
1137
10
        builder.addCapability(spv::Capability::CoreBuiltinsARM);
1138
10
        return spv::BuiltIn::CoreIDARM;
1139
10
    case glslang::EbvCoreMaxIDARM:
1140
10
        builder.addExtension(spv::E_SPV_ARM_core_builtins);
1141
10
        builder.addCapability(spv::Capability::CoreBuiltinsARM);
1142
10
        return spv::BuiltIn::CoreMaxIDARM;
1143
10
    case glslang::EbvWarpIDARM:
1144
10
        builder.addExtension(spv::E_SPV_ARM_core_builtins);
1145
10
        builder.addCapability(spv::Capability::CoreBuiltinsARM);
1146
10
        return spv::BuiltIn::WarpIDARM;
1147
10
    case glslang::EbvWarpMaxIDARM:
1148
10
        builder.addExtension(spv::E_SPV_ARM_core_builtins);
1149
10
        builder.addCapability(spv::Capability::CoreBuiltinsARM);
1150
10
        return spv::BuiltIn::WarpMaxIDARM;
1151
1152
    // QCOM builtins
1153
4
    case glslang::EbvTileOffsetQCOM:
1154
4
        builder.addExtension(spv::E_SPV_QCOM_tile_shading);
1155
4
        return spv::BuiltIn::TileOffsetQCOM;
1156
4
    case glslang::EbvTileDimensionQCOM:
1157
4
        builder.addExtension(spv::E_SPV_QCOM_tile_shading);
1158
4
        return spv::BuiltIn::TileDimensionQCOM;
1159
0
    case glslang::EbvTileApronSizeQCOM:
1160
0
        builder.addExtension(spv::E_SPV_QCOM_tile_shading);
1161
0
        return spv::BuiltIn::TileApronSizeQCOM;
1162
1163
28.5k
    default:
1164
28.5k
        return spv::BuiltIn::Max;
1165
28.7k
    }
1166
28.7k
}
1167
1168
// Translate glslang image layout format to SPIR-V image format.
1169
spv::ImageFormat TGlslangToSpvTraverser::TranslateImageFormat(const glslang::TType& type)
1170
3.05k
{
1171
3.05k
    assert(type.getBasicType() == glslang::EbtSampler);
1172
1173
    // Check for capabilities
1174
3.05k
    switch (type.getQualifier().getFormat()) {
1175
0
    case glslang::ElfRg32f:
1176
175
    case glslang::ElfRg16f:
1177
175
    case glslang::ElfR11fG11fB10f:
1178
175
    case glslang::ElfR16f:
1179
175
    case glslang::ElfRgba16:
1180
175
    case glslang::ElfRgb10A2:
1181
175
    case glslang::ElfRg16:
1182
175
    case glslang::ElfRg8:
1183
175
    case glslang::ElfR16:
1184
175
    case glslang::ElfR8:
1185
175
    case glslang::ElfRgba16Snorm:
1186
175
    case glslang::ElfRg16Snorm:
1187
175
    case glslang::ElfRg8Snorm:
1188
175
    case glslang::ElfR16Snorm:
1189
175
    case glslang::ElfR8Snorm:
1190
1191
175
    case glslang::ElfRg32i:
1192
175
    case glslang::ElfRg16i:
1193
175
    case glslang::ElfRg8i:
1194
175
    case glslang::ElfR16i:
1195
175
    case glslang::ElfR8i:
1196
1197
175
    case glslang::ElfRgb10a2ui:
1198
175
    case glslang::ElfRg32ui:
1199
175
    case glslang::ElfRg16ui:
1200
175
    case glslang::ElfRg8ui:
1201
175
    case glslang::ElfR16ui:
1202
175
    case glslang::ElfR8ui:
1203
175
        builder.addCapability(spv::Capability::StorageImageExtendedFormats);
1204
175
        break;
1205
1206
117
    case glslang::ElfR64ui:
1207
234
    case glslang::ElfR64i:
1208
234
        builder.addExtension(spv::E_SPV_EXT_shader_image_int64);
1209
234
        builder.addCapability(spv::Capability::Int64ImageEXT);
1210
234
        break;
1211
2.64k
    default:
1212
2.64k
        break;
1213
3.05k
    }
1214
1215
    // do the translation
1216
3.05k
    switch (type.getQualifier().getFormat()) {
1217
2.22k
    case glslang::ElfNone:          return spv::ImageFormat::Unknown;
1218
59
    case glslang::ElfRgba32f:       return spv::ImageFormat::Rgba32f;
1219
210
    case glslang::ElfRgba16f:       return spv::ImageFormat::Rgba16f;
1220
13
    case glslang::ElfR32f:          return spv::ImageFormat::R32f;
1221
66
    case glslang::ElfRgba8:         return spv::ImageFormat::Rgba8;
1222
0
    case glslang::ElfRgba8Snorm:    return spv::ImageFormat::Rgba8Snorm;
1223
0
    case glslang::ElfRg32f:         return spv::ImageFormat::Rg32f;
1224
175
    case glslang::ElfRg16f:         return spv::ImageFormat::Rg16f;
1225
0
    case glslang::ElfR11fG11fB10f:  return spv::ImageFormat::R11fG11fB10f;
1226
0
    case glslang::ElfR16f:          return spv::ImageFormat::R16f;
1227
0
    case glslang::ElfRgba16:        return spv::ImageFormat::Rgba16;
1228
0
    case glslang::ElfRgb10A2:       return spv::ImageFormat::Rgb10A2;
1229
0
    case glslang::ElfRg16:          return spv::ImageFormat::Rg16;
1230
0
    case glslang::ElfRg8:           return spv::ImageFormat::Rg8;
1231
0
    case glslang::ElfR16:           return spv::ImageFormat::R16;
1232
0
    case glslang::ElfR8:            return spv::ImageFormat::R8;
1233
0
    case glslang::ElfRgba16Snorm:   return spv::ImageFormat::Rgba16Snorm;
1234
0
    case glslang::ElfRg16Snorm:     return spv::ImageFormat::Rg16Snorm;
1235
0
    case glslang::ElfRg8Snorm:      return spv::ImageFormat::Rg8Snorm;
1236
0
    case glslang::ElfR16Snorm:      return spv::ImageFormat::R16Snorm;
1237
0
    case glslang::ElfR8Snorm:       return spv::ImageFormat::R8Snorm;
1238
30
    case glslang::ElfRgba32i:       return spv::ImageFormat::Rgba32i;
1239
0
    case glslang::ElfRgba16i:       return spv::ImageFormat::Rgba16i;
1240
0
    case glslang::ElfRgba8i:        return spv::ImageFormat::Rgba8i;
1241
0
    case glslang::ElfR32i:          return spv::ImageFormat::R32i;
1242
0
    case glslang::ElfRg32i:         return spv::ImageFormat::Rg32i;
1243
0
    case glslang::ElfRg16i:         return spv::ImageFormat::Rg16i;
1244
0
    case glslang::ElfRg8i:          return spv::ImageFormat::Rg8i;
1245
0
    case glslang::ElfR16i:          return spv::ImageFormat::R16i;
1246
0
    case glslang::ElfR8i:           return spv::ImageFormat::R8i;
1247
30
    case glslang::ElfRgba32ui:      return spv::ImageFormat::Rgba32ui;
1248
0
    case glslang::ElfRgba16ui:      return spv::ImageFormat::Rgba16ui;
1249
10
    case glslang::ElfRgba8ui:       return spv::ImageFormat::Rgba8ui;
1250
3
    case glslang::ElfR32ui:         return spv::ImageFormat::R32ui;
1251
0
    case glslang::ElfRg32ui:        return spv::ImageFormat::Rg32ui;
1252
0
    case glslang::ElfRg16ui:        return spv::ImageFormat::Rg16ui;
1253
0
    case glslang::ElfRgb10a2ui:     return spv::ImageFormat::Rgb10a2ui;
1254
0
    case glslang::ElfRg8ui:         return spv::ImageFormat::Rg8ui;
1255
0
    case glslang::ElfR16ui:         return spv::ImageFormat::R16ui;
1256
0
    case glslang::ElfR8ui:          return spv::ImageFormat::R8ui;
1257
117
    case glslang::ElfR64ui:         return spv::ImageFormat::R64ui;
1258
117
    case glslang::ElfR64i:          return spv::ImageFormat::R64i;
1259
0
    default:                        return spv::ImageFormat::Max;
1260
3.05k
    }
1261
3.05k
}
1262
1263
spv::SelectionControlMask TGlslangToSpvTraverser::TranslateSelectionControl(
1264
    const glslang::TIntermSelection& selectionNode) const
1265
1.94k
{
1266
1.94k
    if (selectionNode.getFlatten())
1267
58
        return spv::SelectionControlMask::Flatten;
1268
1.88k
    if (selectionNode.getDontFlatten())
1269
28
        return spv::SelectionControlMask::DontFlatten;
1270
1.86k
    return spv::SelectionControlMask::MaskNone;
1271
1.88k
}
1272
1273
spv::SelectionControlMask TGlslangToSpvTraverser::TranslateSwitchControl(const glslang::TIntermSwitch& switchNode)
1274
    const
1275
353
{
1276
353
    if (switchNode.getFlatten())
1277
0
        return spv::SelectionControlMask::Flatten;
1278
353
    if (switchNode.getDontFlatten())
1279
60
        return spv::SelectionControlMask::DontFlatten;
1280
293
    return spv::SelectionControlMask::MaskNone;
1281
353
}
1282
1283
// return a non-0 dependency if the dependency argument must be set
1284
spv::LoopControlMask TGlslangToSpvTraverser::TranslateLoopControl(const glslang::TIntermLoop& loopNode,
1285
    std::vector<unsigned int>& operands) const
1286
1.47k
{
1287
1.47k
    spv::LoopControlMask control = spv::LoopControlMask::MaskNone;
1288
1289
1.47k
    if (loopNode.getDontUnroll())
1290
61
        control = control | spv::LoopControlMask::DontUnroll;
1291
1.47k
    if (loopNode.getUnroll())
1292
61
        control = control | spv::LoopControlMask::Unroll;
1293
1.47k
    if (unsigned(loopNode.getLoopDependency()) == glslang::TIntermLoop::dependencyInfinite)
1294
58
        control = control | spv::LoopControlMask::DependencyInfinite;
1295
1.41k
    else if (loopNode.getLoopDependency() > 0) {
1296
64
        control = control | spv::LoopControlMask::DependencyLength;
1297
64
        operands.push_back((unsigned int)loopNode.getLoopDependency());
1298
64
    }
1299
1.47k
    if (glslangIntermediate->getSpv().spv >= glslang::EShTargetSpv_1_4) {
1300
0
        if (loopNode.getMinIterations() > 0) {
1301
0
            control = control | spv::LoopControlMask::MinIterations;
1302
0
            operands.push_back(loopNode.getMinIterations());
1303
0
        }
1304
0
        if (loopNode.getMaxIterations() < glslang::TIntermLoop::iterationsInfinite) {
1305
0
            control = control | spv::LoopControlMask::MaxIterations;
1306
0
            operands.push_back(loopNode.getMaxIterations());
1307
0
        }
1308
0
        if (loopNode.getIterationMultiple() > 1) {
1309
0
            control = control | spv::LoopControlMask::IterationMultiple;
1310
0
            operands.push_back(loopNode.getIterationMultiple());
1311
0
        }
1312
0
        if (loopNode.getPeelCount() > 0) {
1313
0
            control = control | spv::LoopControlMask::PeelCount;
1314
0
            operands.push_back(loopNode.getPeelCount());
1315
0
        }
1316
0
        if (loopNode.getPartialCount() > 0) {
1317
0
            control = control | spv::LoopControlMask::PartialCount;
1318
0
            operands.push_back(loopNode.getPartialCount());
1319
0
        }
1320
0
    }
1321
1322
1.47k
    return control;
1323
1.47k
}
1324
1325
// Translate glslang type to SPIR-V storage class.
1326
spv::StorageClass TGlslangToSpvTraverser::TranslateStorageClass(const glslang::TType& type)
1327
20.6k
{
1328
20.6k
    if (type.getBasicType() == glslang::EbtRayQuery || type.getBasicType() == glslang::EbtHitObjectNV 
1329
20.6k
        || type.getBasicType() == glslang::EbtHitObjectEXT)
1330
51
        return spv::StorageClass::Private;
1331
20.6k
    if (type.getQualifier().isSpirvByReference()) {
1332
0
        if (type.getQualifier().isParamInput() || type.getQualifier().isParamOutput())
1333
0
            return spv::StorageClass::Function;
1334
0
    }
1335
20.6k
    if (type.getQualifier().isPipeInput())
1336
1.62k
        return spv::StorageClass::Input;
1337
19.0k
    if (type.getQualifier().isPipeOutput())
1338
947
        return spv::StorageClass::Output;
1339
18.0k
    if (type.getQualifier().storage == glslang::EvqTileImageEXT || type.isAttachmentEXT()) {
1340
1
        builder.addExtension(spv::E_SPV_EXT_shader_tile_image);
1341
1
        builder.addCapability(spv::Capability::TileImageColorReadAccessEXT);
1342
1
        return spv::StorageClass::TileImageEXT;
1343
1
    }
1344
1345
18.0k
    if (type.getQualifier().isTileAttachmentQCOM()) {
1346
20
        builder.addExtension(spv::E_SPV_QCOM_tile_shading);
1347
20
        builder.addCapability(spv::Capability::TileShadingQCOM);
1348
20
        return spv::StorageClass::TileAttachmentQCOM;
1349
20
    }
1350
1351
18.0k
    if (glslangIntermediate->getSource() != glslang::EShSourceHlsl ||
1352
17.7k
            type.getQualifier().storage == glslang::EvqUniform) {
1353
17.7k
        if (type.isAtomic())
1354
0
            return spv::StorageClass::AtomicCounter;
1355
17.7k
        if (type.containsOpaque() && !glslangIntermediate->getBindlessMode())
1356
2.93k
            return spv::StorageClass::UniformConstant;
1357
17.7k
    }
1358
1359
15.1k
    if (type.getQualifier().isUniformOrBuffer() &&
1360
1.29k
        type.getQualifier().isShaderRecord()) {
1361
0
        return spv::StorageClass::ShaderRecordBufferKHR;
1362
0
    }
1363
1364
15.1k
    if (glslangIntermediate->usingStorageBuffer() && type.getQualifier().storage == glslang::EvqBuffer) {
1365
137
        builder.addIncorporatedExtension(spv::E_SPV_KHR_storage_buffer_storage_class, spv::Spv_1_3);
1366
137
        return spv::StorageClass::StorageBuffer;
1367
137
    }
1368
1369
14.9k
    if (type.getQualifier().isUniformOrBuffer()) {
1370
1.15k
        if (type.getQualifier().isPushConstant())
1371
63
            return spv::StorageClass::PushConstant;
1372
1.09k
        if (type.getBasicType() == glslang::EbtBlock)
1373
1.09k
            return spv::StorageClass::Uniform;
1374
0
        return spv::StorageClass::UniformConstant;
1375
1.09k
    }
1376
1377
13.8k
    if (type.getQualifier().storage == glslang::EvqShared && type.getBasicType() == glslang::EbtBlock) {
1378
0
        builder.addExtension(spv::E_SPV_KHR_workgroup_memory_explicit_layout);
1379
0
        builder.addCapability(spv::Capability::WorkgroupMemoryExplicitLayoutKHR);
1380
0
        return spv::StorageClass::Workgroup;
1381
0
    }
1382
1383
13.8k
    switch (type.getQualifier().storage) {
1384
1.78k
    case glslang::EvqGlobal:        return spv::StorageClass::Private;
1385
18
    case glslang::EvqConstReadOnly: return spv::StorageClass::Function;
1386
12.0k
    case glslang::EvqTemporary:     return spv::StorageClass::Function;
1387
14
    case glslang::EvqShared:           return spv::StorageClass::Workgroup;
1388
0
    case glslang::EvqPayload:        return spv::StorageClass::RayPayloadKHR;
1389
0
    case glslang::EvqPayloadIn:      return spv::StorageClass::IncomingRayPayloadKHR;
1390
0
    case glslang::EvqHitAttr:        return spv::StorageClass::HitAttributeKHR;
1391
0
    case glslang::EvqCallableData:   return spv::StorageClass::CallableDataKHR;
1392
0
    case glslang::EvqCallableDataIn: return spv::StorageClass::IncomingCallableDataKHR;
1393
0
    case glslang::EvqtaskPayloadSharedEXT : return spv::StorageClass::TaskPayloadWorkgroupEXT;
1394
0
    case glslang::EvqHitObjectAttrNV: return spv::StorageClass::HitObjectAttributeNV;
1395
0
    case glslang::EvqHitObjectAttrEXT: return spv::StorageClass::HitObjectAttributeEXT;
1396
0
    case glslang::EvqSpirvStorageClass: return static_cast<spv::StorageClass>(type.getQualifier().spirvStorageClass);
1397
0
    default:
1398
0
        assert(0);
1399
0
        break;
1400
13.8k
    }
1401
1402
0
    return spv::StorageClass::Function;
1403
13.8k
}
1404
1405
// Translate glslang constants to SPIR-V literals
1406
void TGlslangToSpvTraverser::TranslateLiterals(const glslang::TVector<const glslang::TIntermConstantUnion*>& constants,
1407
                                               std::vector<unsigned>& literals) const
1408
239
{
1409
239
    for (auto constant : constants) {
1410
239
        if (constant->getBasicType() == glslang::EbtFloat) {
1411
0
            float floatValue = static_cast<float>(constant->getConstArray()[0].getDConst());
1412
0
            unsigned literal;
1413
0
            static_assert(sizeof(literal) == sizeof(floatValue), "sizeof(unsigned) != sizeof(float)");
1414
0
            memcpy(&literal, &floatValue, sizeof(literal));
1415
0
            literals.push_back(literal);
1416
239
        } else if (constant->getBasicType() == glslang::EbtInt) {
1417
239
            unsigned literal = constant->getConstArray()[0].getIConst();
1418
239
            literals.push_back(literal);
1419
239
        } else if (constant->getBasicType() == glslang::EbtUint) {
1420
0
            unsigned literal = constant->getConstArray()[0].getUConst();
1421
0
            literals.push_back(literal);
1422
0
        } else if (constant->getBasicType() == glslang::EbtBool) {
1423
0
            unsigned literal = constant->getConstArray()[0].getBConst();
1424
0
            literals.push_back(literal);
1425
0
        } else if (constant->getBasicType() == glslang::EbtString) {
1426
0
            auto str = constant->getConstArray()[0].getSConst()->c_str();
1427
0
            unsigned literal = 0;
1428
0
            char* literalPtr = reinterpret_cast<char*>(&literal);
1429
0
            unsigned charCount = 0;
1430
0
            char ch = 0;
1431
0
            do {
1432
0
                ch = *(str++);
1433
0
                *(literalPtr++) = ch;
1434
0
                ++charCount;
1435
0
                if (charCount == 4) {
1436
0
                    literals.push_back(literal);
1437
0
                    literalPtr = reinterpret_cast<char*>(&literal);
1438
0
                    charCount = 0;
1439
0
                }
1440
0
            } while (ch != 0);
1441
1442
            // Partial literal is padded with 0
1443
0
            if (charCount > 0) {
1444
0
                for (; charCount < 4; ++charCount)
1445
0
                    *(literalPtr++) = 0;
1446
0
                literals.push_back(literal);
1447
0
            }
1448
0
        } else
1449
0
            assert(0); // Unexpected type
1450
239
    }
1451
239
}
1452
1453
// Add capabilities pertaining to how an array is indexed.
1454
void TGlslangToSpvTraverser::addIndirectionIndexCapabilities(const glslang::TType& baseType,
1455
                                                             const glslang::TType& indexType)
1456
1.15k
{
1457
1.15k
    if (indexType.getQualifier().isNonUniform()) {
1458
        // deal with an asserted non-uniform index
1459
        // SPV_EXT_descriptor_indexing already added in TranslateNonUniformDecoration
1460
24
        if (baseType.getBasicType() == glslang::EbtSampler) {
1461
9
            if (baseType.getQualifier().hasAttachment())
1462
1
                builder.addCapability(spv::Capability::InputAttachmentArrayNonUniformIndexingEXT);
1463
8
            else if (baseType.isImage() && baseType.getSampler().isBuffer())
1464
3
                builder.addCapability(spv::Capability::StorageTexelBufferArrayNonUniformIndexingEXT);
1465
5
            else if (baseType.isTexture() && baseType.getSampler().isBuffer())
1466
1
                builder.addCapability(spv::Capability::UniformTexelBufferArrayNonUniformIndexingEXT);
1467
4
            else if (baseType.isImage())
1468
1
                builder.addCapability(spv::Capability::StorageImageArrayNonUniformIndexingEXT);
1469
3
            else if (baseType.isTexture())
1470
3
                builder.addCapability(spv::Capability::SampledImageArrayNonUniformIndexingEXT);
1471
15
        } else if (baseType.getBasicType() == glslang::EbtBlock) {
1472
11
            if (baseType.getQualifier().storage == glslang::EvqBuffer)
1473
2
                builder.addCapability(spv::Capability::StorageBufferArrayNonUniformIndexingEXT);
1474
9
            else if (baseType.getQualifier().storage == glslang::EvqUniform)
1475
9
                builder.addCapability(spv::Capability::UniformBufferArrayNonUniformIndexingEXT);
1476
11
        }
1477
1.13k
    } else {
1478
        // assume a dynamically uniform index
1479
1.13k
        if (baseType.getBasicType() == glslang::EbtSampler) {
1480
17
            if (baseType.getQualifier().hasAttachment()) {
1481
1
                builder.addIncorporatedExtension("SPV_EXT_descriptor_indexing", spv::Spv_1_5);
1482
1
                builder.addCapability(spv::Capability::InputAttachmentArrayDynamicIndexingEXT);
1483
16
            } else if (baseType.isImage() && baseType.getSampler().isBuffer()) {
1484
1
                builder.addIncorporatedExtension("SPV_EXT_descriptor_indexing", spv::Spv_1_5);
1485
1
                builder.addCapability(spv::Capability::StorageTexelBufferArrayDynamicIndexingEXT);
1486
15
            } else if (baseType.isTexture() && baseType.getSampler().isBuffer()) {
1487
1
                builder.addIncorporatedExtension("SPV_EXT_descriptor_indexing", spv::Spv_1_5);
1488
1
                builder.addCapability(spv::Capability::UniformTexelBufferArrayDynamicIndexingEXT);
1489
1
            }
1490
17
        }
1491
1.13k
    }
1492
1.15k
}
1493
1494
// Return whether or not the given type is something that should be tied to a
1495
// descriptor set.
1496
bool IsDescriptorResource(const glslang::TType& type)
1497
37.5k
{
1498
    // uniform and buffer blocks are included, unless it is a push_constant
1499
37.5k
    if (type.getBasicType() == glslang::EbtBlock)
1500
976
        return type.getQualifier().isUniformOrBuffer() &&
1501
950
        ! type.getQualifier().isShaderRecord() &&
1502
950
        ! type.getQualifier().isPushConstant();
1503
1504
    // non block...
1505
    // basically samplerXXX/subpass/sampler/texture are all included
1506
    // if they are the global-scope-class, not the function parameter
1507
    // (or local, if they ever exist) class.
1508
36.5k
    if (type.getBasicType() == glslang::EbtSampler ||
1509
34.6k
        type.getBasicType() == glslang::EbtAccStruct)
1510
1.88k
        return type.getQualifier().isUniformOrBuffer();
1511
1512
    // Tensors are tied to a descriptor.
1513
34.6k
    if (type.isTensorARM())
1514
0
        return true;
1515
1516
    // None of the above.
1517
34.6k
    return false;
1518
34.6k
}
1519
1520
void InheritQualifiers(glslang::TQualifier& child, const glslang::TQualifier& parent)
1521
14.3k
{
1522
14.3k
    if (child.layoutMatrix == glslang::ElmNone)
1523
5.33k
        child.layoutMatrix = parent.layoutMatrix;
1524
1525
14.3k
    if (parent.invariant)
1526
0
        child.invariant = true;
1527
14.3k
    if (parent.flat)
1528
0
        child.flat = true;
1529
14.3k
    if (parent.centroid)
1530
0
        child.centroid = true;
1531
14.3k
    if (parent.nopersp)
1532
0
        child.nopersp = true;
1533
14.3k
    if (parent.explicitInterp)
1534
0
        child.explicitInterp = true;
1535
14.3k
    if (parent.perPrimitiveNV)
1536
0
        child.perPrimitiveNV = true;
1537
14.3k
    if (parent.perViewNV)
1538
0
        child.perViewNV = true;
1539
14.3k
    if (parent.perTaskNV)
1540
0
        child.perTaskNV = true;
1541
14.3k
    if (parent.storage == glslang::EvqtaskPayloadSharedEXT)
1542
0
        child.storage = glslang::EvqtaskPayloadSharedEXT;
1543
14.3k
    if (parent.patch)
1544
0
        child.patch = true;
1545
14.3k
    if (parent.sample)
1546
0
        child.sample = true;
1547
14.3k
    if (parent.coherent)
1548
34
        child.coherent = true;
1549
14.3k
    if (parent.devicecoherent)
1550
0
        child.devicecoherent = true;
1551
14.3k
    if (parent.queuefamilycoherent)
1552
0
        child.queuefamilycoherent = true;
1553
14.3k
    if (parent.workgroupcoherent)
1554
0
        child.workgroupcoherent = true;
1555
14.3k
    if (parent.subgroupcoherent)
1556
0
        child.subgroupcoherent = true;
1557
14.3k
    if (parent.shadercallcoherent)
1558
0
        child.shadercallcoherent = true;
1559
14.3k
    if (parent.nonprivate)
1560
0
        child.nonprivate = true;
1561
14.3k
    if (parent.volatil)
1562
0
        child.volatil = true;
1563
14.3k
    if (parent.nontemporal)
1564
208
        child.nontemporal = true;
1565
14.3k
    if (parent.restrict)
1566
1.24k
        child.restrict = true;
1567
14.3k
    if (parent.readonly)
1568
1.29k
        child.readonly = true;
1569
14.3k
    if (parent.writeonly)
1570
0
        child.writeonly = true;
1571
14.3k
    if (parent.nonUniform)
1572
2
        child.nonUniform = true;
1573
14.3k
}
1574
1575
bool HasNonLayoutQualifiers(const glslang::TType& type, const glslang::TQualifier& qualifier)
1576
8.11k
{
1577
    // This should list qualifiers that simultaneous satisfy:
1578
    // - struct members might inherit from a struct declaration
1579
    //     (note that non-block structs don't explicitly inherit,
1580
    //      only implicitly, meaning no decoration involved)
1581
    // - affect decorations on the struct members
1582
    //     (note smooth does not, and expecting something like volatile
1583
    //      to effect the whole object)
1584
    // - are not part of the offset/st430/etc or row/column-major layout
1585
8.11k
    return qualifier.invariant || (qualifier.hasLocation() && type.getBasicType() == glslang::EbtBlock);
1586
8.11k
}
1587
1588
//
1589
// Implement the TGlslangToSpvTraverser class.
1590
//
1591
1592
TGlslangToSpvTraverser::TGlslangToSpvTraverser(unsigned int spvVersion,
1593
    const glslang::TIntermediate* glslangIntermediate,
1594
    spv::SpvBuildLogger* buildLogger, glslang::SpvOptions& options) :
1595
2.08k
        TIntermTraverser(true, false, true),
1596
2.08k
        options(options),
1597
2.08k
        shaderEntry(nullptr), currentFunction(nullptr),
1598
2.08k
        sequenceDepth(0), logger(buildLogger),
1599
2.08k
        builder(spvVersion, (glslang::GetKhronosToolId() << 16) | glslang::GetSpirvGeneratorVersion(), logger),
1600
2.08k
        inEntryPoint(false), entryPointTerminated(false), linkageOnly(false),
1601
2.08k
        glslangIntermediate(glslangIntermediate),
1602
2.08k
        nanMinMaxClamp(glslangIntermediate->getNanMinMaxClamp()),
1603
2.08k
        nonSemanticDebugPrintf(0),
1604
2.08k
        taskPayloadID(0)
1605
2.08k
{
1606
2.08k
    bool isMeshShaderExt = (glslangIntermediate->getRequestedExtensions().find(glslang::E_GL_EXT_mesh_shader) !=
1607
2.08k
                            glslangIntermediate->getRequestedExtensions().end());
1608
2.08k
    spv::ExecutionModel executionModel = TranslateExecutionModel(glslangIntermediate->getStage(), isMeshShaderExt);
1609
1610
2.08k
    builder.clearAccessChain();
1611
2.08k
    builder.setSource(TranslateSourceLanguage(glslangIntermediate->getSource(), glslangIntermediate->getProfile()),
1612
2.08k
                      glslangIntermediate->getVersion());
1613
1614
2.08k
    if (options.emitNonSemanticShaderDebugSource)
1615
0
            this->options.emitNonSemanticShaderDebugInfo = true;
1616
2.08k
    if (options.emitNonSemanticShaderDebugInfo)
1617
0
            this->options.generateDebugInfo = true;
1618
1619
2.08k
    if (this->options.generateDebugInfo) {
1620
0
        if (this->options.emitNonSemanticShaderDebugInfo) {
1621
0
            builder.setEmitNonSemanticShaderDebugInfo(this->options.emitNonSemanticShaderDebugSource);
1622
0
        }
1623
0
        else {
1624
0
            builder.setEmitSpirvDebugInfo();
1625
0
        }
1626
0
        builder.setDebugMainSourceFile(glslangIntermediate->getSourceFile());
1627
1628
        // Set the source shader's text. If for SPV version 1.0, include
1629
        // a preamble in comments stating the OpModuleProcessed instructions.
1630
        // Otherwise, emit those as actual instructions.
1631
0
        std::string text;
1632
0
        const std::vector<std::string>& processes = glslangIntermediate->getProcesses();
1633
0
        for (int p = 0; p < (int)processes.size(); ++p) {
1634
0
            if (glslangIntermediate->getSpv().spv < glslang::EShTargetSpv_1_1) {
1635
0
                text.append("// OpModuleProcessed ");
1636
0
                text.append(processes[p]);
1637
0
                text.append("\n");
1638
0
            } else
1639
0
                builder.addModuleProcessed(processes[p]);
1640
0
        }
1641
0
        if (glslangIntermediate->getSpv().spv < glslang::EShTargetSpv_1_1 && (int)processes.size() > 0)
1642
0
            text.append("#line 1\n");
1643
0
        text.append(glslangIntermediate->getSourceText());
1644
0
        builder.setSourceText(text);
1645
        // Pass name and text for all included files
1646
0
        const std::map<std::string, std::string>& include_txt = glslangIntermediate->getIncludeText();
1647
0
        for (auto iItr = include_txt.begin(); iItr != include_txt.end(); ++iItr)
1648
0
            builder.addInclude(iItr->first, iItr->second);
1649
0
    }
1650
1651
2.08k
    builder.setUseReplicatedComposites(glslangIntermediate->usingReplicatedComposites());
1652
1653
2.08k
    stdBuiltins = builder.import("GLSL.std.450");
1654
1655
2.08k
    spv::AddressingModel addressingModel = spv::AddressingModel::Logical;
1656
2.08k
    spv::MemoryModel memoryModel = spv::MemoryModel::GLSL450;
1657
1658
2.08k
    if (glslangIntermediate->usingPhysicalStorageBuffer()) {
1659
188
        addressingModel = spv::AddressingModel::PhysicalStorageBuffer64EXT;
1660
188
        builder.addIncorporatedExtension(spv::E_SPV_KHR_physical_storage_buffer, spv::Spv_1_5);
1661
188
        builder.addCapability(spv::Capability::PhysicalStorageBufferAddressesEXT);
1662
188
    }
1663
2.08k
    if (glslangIntermediate->usingVulkanMemoryModel()) {
1664
39
        memoryModel = spv::MemoryModel::VulkanKHR;
1665
39
        builder.addCapability(spv::Capability::VulkanMemoryModelKHR);
1666
39
        builder.addIncorporatedExtension(spv::E_SPV_KHR_vulkan_memory_model, spv::Spv_1_5);
1667
39
    }
1668
2.08k
    builder.setMemoryModel(addressingModel, memoryModel);
1669
1670
2.08k
    if (glslangIntermediate->usingVariablePointers()) {
1671
0
        builder.addCapability(spv::Capability::VariablePointers);
1672
0
    }
1673
1674
    // If not linking, there is no entry point
1675
2.08k
    if (!options.compileOnly) {
1676
2.08k
        shaderEntry = builder.makeEntryPoint(glslangIntermediate->getEntryPointName().c_str());
1677
2.08k
        entryPoint =
1678
2.08k
            builder.addEntryPoint(executionModel, shaderEntry, glslangIntermediate->getEntryPointName().c_str());
1679
2.08k
    }
1680
1681
    // Add the source extensions
1682
2.08k
    const auto& sourceExtensions = glslangIntermediate->getRequestedExtensions();
1683
8.44k
    for (auto it = sourceExtensions.begin(); it != sourceExtensions.end(); ++it)
1684
6.35k
        builder.addSourceExtension(it->c_str());
1685
1686
    // Add the top-level modes for this shader.
1687
1688
2.08k
    if (glslangIntermediate->getXfbMode()) {
1689
0
        builder.addCapability(spv::Capability::TransformFeedback);
1690
0
        builder.addExecutionMode(shaderEntry, spv::ExecutionMode::Xfb);
1691
0
    }
1692
1693
2.08k
    if (glslangIntermediate->getLayoutPrimitiveCulling()) {
1694
0
        builder.addCapability(spv::Capability::RayTraversalPrimitiveCullingKHR);
1695
0
    }
1696
1697
2.08k
    if (glslangIntermediate->getSubgroupUniformControlFlow()) {
1698
0
        builder.addExtension(spv::E_SPV_KHR_subgroup_uniform_control_flow);
1699
0
        builder.addExecutionMode(shaderEntry, spv::ExecutionMode::SubgroupUniformControlFlowKHR);
1700
0
    }
1701
2.08k
    if (glslangIntermediate->getMaximallyReconverges()) {
1702
0
        builder.addExtension(spv::E_SPV_KHR_maximal_reconvergence);
1703
0
        builder.addExecutionMode(shaderEntry, spv::ExecutionMode::MaximallyReconvergesKHR);
1704
0
    }
1705
1706
2.08k
    if (glslangIntermediate->getQuadDerivMode())
1707
0
    {
1708
0
        builder.addCapability(spv::Capability::QuadControlKHR);
1709
0
        builder.addExtension(spv::E_SPV_KHR_quad_control);
1710
0
        builder.addExecutionMode(shaderEntry, spv::ExecutionMode::QuadDerivativesKHR);
1711
0
    }
1712
1713
2.08k
    if (glslangIntermediate->getReqFullQuadsMode())
1714
0
    {
1715
0
        builder.addCapability(spv::Capability::QuadControlKHR);
1716
0
        builder.addExtension(spv::E_SPV_KHR_quad_control);
1717
0
        builder.addExecutionMode(shaderEntry, spv::ExecutionMode::RequireFullQuadsKHR);
1718
0
    }
1719
1720
2.08k
    if (glslangIntermediate->usingShader64BitIndexing())
1721
0
    {
1722
0
        builder.addCapability(spv::Capability::Shader64BitIndexingEXT);
1723
0
        builder.addExtension(spv::E_SPV_EXT_shader_64bit_indexing);
1724
0
        builder.addExecutionMode(shaderEntry, spv::ExecutionMode::Shader64BitIndexingEXT);
1725
0
    }
1726
1727
2.08k
    spv::ExecutionMode mode;
1728
2.08k
    switch (glslangIntermediate->getStage()) {
1729
1.80k
    case EShLangVertex:
1730
1.80k
        builder.addCapability(spv::Capability::Shader);
1731
1.80k
        break;
1732
1733
229
    case EShLangFragment:
1734
229
        builder.addCapability(spv::Capability::Shader);
1735
229
        if (glslangIntermediate->getPixelCenterInteger())
1736
0
            builder.addExecutionMode(shaderEntry, spv::ExecutionMode::PixelCenterInteger);
1737
1738
229
        if (glslangIntermediate->getOriginUpperLeft())
1739
229
            builder.addExecutionMode(shaderEntry, spv::ExecutionMode::OriginUpperLeft);
1740
0
        else
1741
0
            builder.addExecutionMode(shaderEntry, spv::ExecutionMode::OriginLowerLeft);
1742
1743
229
        if (glslangIntermediate->getEarlyFragmentTests())
1744
2
            builder.addExecutionMode(shaderEntry, spv::ExecutionMode::EarlyFragmentTests);
1745
1746
229
        if (glslangIntermediate->getEarlyAndLateFragmentTestsAMD())
1747
1
        {
1748
1
            builder.addExecutionMode(shaderEntry, spv::ExecutionMode::EarlyAndLateFragmentTestsAMD);
1749
1
            builder.addExtension(spv::E_SPV_AMD_shader_early_and_late_fragment_tests);
1750
1
        }
1751
1752
229
        if (glslangIntermediate->getPostDepthCoverage()) {
1753
2
            builder.addCapability(spv::Capability::SampleMaskPostDepthCoverage);
1754
2
            builder.addExecutionMode(shaderEntry, spv::ExecutionMode::PostDepthCoverage);
1755
2
            builder.addExtension(spv::E_SPV_KHR_post_depth_coverage);
1756
2
        }
1757
1758
229
        if (glslangIntermediate->getNonCoherentColorAttachmentReadEXT()) {
1759
0
            builder.addCapability(spv::Capability::TileImageColorReadAccessEXT);
1760
0
            builder.addExecutionMode(shaderEntry, spv::ExecutionMode::NonCoherentColorAttachmentReadEXT);
1761
0
            builder.addExtension(spv::E_SPV_EXT_shader_tile_image);
1762
0
        }
1763
1764
229
        if (glslangIntermediate->getNonCoherentDepthAttachmentReadEXT()) {
1765
0
            builder.addCapability(spv::Capability::TileImageDepthReadAccessEXT);
1766
0
            builder.addExecutionMode(shaderEntry, spv::ExecutionMode::NonCoherentDepthAttachmentReadEXT);
1767
0
            builder.addExtension(spv::E_SPV_EXT_shader_tile_image);
1768
0
        }
1769
1770
229
        if (glslangIntermediate->getNonCoherentStencilAttachmentReadEXT()) {
1771
0
            builder.addCapability(spv::Capability::TileImageStencilReadAccessEXT);
1772
0
            builder.addExecutionMode(shaderEntry, spv::ExecutionMode::NonCoherentStencilAttachmentReadEXT);
1773
0
            builder.addExtension(spv::E_SPV_EXT_shader_tile_image);
1774
0
        }
1775
1776
229
        if (glslangIntermediate->getNonCoherentTileAttachmentReadQCOM()) {
1777
2
            builder.addCapability(spv::Capability::TileShadingQCOM);
1778
2
            builder.addExecutionMode(shaderEntry, spv::ExecutionMode::NonCoherentTileAttachmentReadQCOM);
1779
2
            builder.addExtension(spv::E_SPV_QCOM_tile_shading);
1780
2
        }
1781
1782
229
        if (glslangIntermediate->isDepthReplacing())
1783
4
            builder.addExecutionMode(shaderEntry, spv::ExecutionMode::DepthReplacing);
1784
1785
229
        if (glslangIntermediate->isStencilReplacing())
1786
1
            builder.addExecutionMode(shaderEntry, spv::ExecutionMode::StencilRefReplacingEXT);
1787
1788
229
        switch(glslangIntermediate->getDepth()) {
1789
0
        case glslang::EldGreater:   mode = spv::ExecutionMode::DepthGreater;   break;
1790
1
        case glslang::EldLess:      mode = spv::ExecutionMode::DepthLess;      break;
1791
2
        case glslang::EldUnchanged: mode = spv::ExecutionMode::DepthUnchanged; break;
1792
226
        default:                    mode = spv::ExecutionMode::Max;            break;
1793
229
        }
1794
1795
229
        if (mode != spv::ExecutionMode::Max)
1796
3
            builder.addExecutionMode(shaderEntry, mode);
1797
1798
229
        switch (glslangIntermediate->getStencil()) {
1799
0
        case glslang::ElsRefUnchangedFrontAMD:  mode = spv::ExecutionMode::StencilRefUnchangedFrontAMD; break;
1800
0
        case glslang::ElsRefGreaterFrontAMD:    mode = spv::ExecutionMode::StencilRefGreaterFrontAMD;   break;
1801
0
        case glslang::ElsRefLessFrontAMD:       mode = spv::ExecutionMode::StencilRefLessFrontAMD;      break;
1802
0
        case glslang::ElsRefUnchangedBackAMD:   mode = spv::ExecutionMode::StencilRefUnchangedBackAMD;  break;
1803
0
        case glslang::ElsRefGreaterBackAMD:     mode = spv::ExecutionMode::StencilRefGreaterBackAMD;    break;
1804
0
        case glslang::ElsRefLessBackAMD:        mode = spv::ExecutionMode::StencilRefLessBackAMD;       break;
1805
229
        default:                       mode = spv::ExecutionMode::Max;                         break;
1806
229
        }
1807
1808
229
        if (mode != spv::ExecutionMode::Max)
1809
0
            builder.addExecutionMode(shaderEntry, (spv::ExecutionMode)mode);
1810
229
        switch (glslangIntermediate->getInterlockOrdering()) {
1811
0
        case glslang::EioPixelInterlockOrdered:         mode = spv::ExecutionMode::PixelInterlockOrderedEXT;
1812
0
            break;
1813
0
        case glslang::EioPixelInterlockUnordered:       mode = spv::ExecutionMode::PixelInterlockUnorderedEXT;
1814
0
            break;
1815
1
        case glslang::EioSampleInterlockOrdered:        mode = spv::ExecutionMode::SampleInterlockOrderedEXT;
1816
1
            break;
1817
0
        case glslang::EioSampleInterlockUnordered:      mode = spv::ExecutionMode::SampleInterlockUnorderedEXT;
1818
0
            break;
1819
0
        case glslang::EioShadingRateInterlockOrdered:   mode = spv::ExecutionMode::ShadingRateInterlockOrderedEXT;
1820
0
            break;
1821
0
        case glslang::EioShadingRateInterlockUnordered: mode = spv::ExecutionMode::ShadingRateInterlockUnorderedEXT;
1822
0
            break;
1823
228
        default:                                        mode = spv::ExecutionMode::Max;
1824
228
            break;
1825
229
        }
1826
229
        if (mode != spv::ExecutionMode::Max) {
1827
1
            builder.addExecutionMode(shaderEntry, (spv::ExecutionMode)mode);
1828
1
            if (mode == spv::ExecutionMode::ShadingRateInterlockOrderedEXT ||
1829
1
                mode == spv::ExecutionMode::ShadingRateInterlockUnorderedEXT) {
1830
0
                builder.addCapability(spv::Capability::FragmentShaderShadingRateInterlockEXT);
1831
1
            } else if (mode == spv::ExecutionMode::PixelInterlockOrderedEXT ||
1832
1
                       mode == spv::ExecutionMode::PixelInterlockUnorderedEXT) {
1833
0
                builder.addCapability(spv::Capability::FragmentShaderPixelInterlockEXT);
1834
1
            } else {
1835
1
                builder.addCapability(spv::Capability::FragmentShaderSampleInterlockEXT);
1836
1
            }
1837
1
            builder.addExtension(spv::E_SPV_EXT_fragment_shader_interlock);
1838
1
        }
1839
229
    break;
1840
1841
4
    case EShLangCompute: {
1842
4
        builder.addCapability(spv::Capability::Shader);
1843
4
        bool needSizeId = false;
1844
16
        for (int dim = 0; dim < 3; ++dim) {
1845
12
            if ((glslangIntermediate->getLocalSizeSpecId(dim) != glslang::TQualifier::layoutNotSet)) {
1846
0
                needSizeId = true;
1847
0
                break;
1848
0
            }
1849
12
        }
1850
4
        if (glslangIntermediate->getSpv().spv >= glslang::EShTargetSpv_1_6 && needSizeId) {
1851
0
            std::vector<spv::Id> dimConstId;
1852
0
            for (int dim = 0; dim < 3; ++dim) {
1853
0
                bool specConst = (glslangIntermediate->getLocalSizeSpecId(dim) != glslang::TQualifier::layoutNotSet);
1854
0
                dimConstId.push_back(builder.makeUintConstant(glslangIntermediate->getLocalSize(dim), specConst));
1855
0
                if (specConst) {
1856
0
                    builder.addDecoration(dimConstId.back(), spv::Decoration::SpecId,
1857
0
                                          glslangIntermediate->getLocalSizeSpecId(dim));
1858
0
                    needSizeId = true;
1859
0
                }
1860
0
            }
1861
0
            builder.addExecutionModeId(shaderEntry, spv::ExecutionMode::LocalSizeId, dimConstId);
1862
4
        } else {
1863
4
            if (glslangIntermediate->getTileShadingRateQCOM(0) >= 1 || glslangIntermediate->getTileShadingRateQCOM(1) >= 1 || glslangIntermediate->getTileShadingRateQCOM(2) >= 1) {
1864
0
                auto rate_x = glslangIntermediate->getTileShadingRateQCOM(0);
1865
0
                auto rate_y = glslangIntermediate->getTileShadingRateQCOM(1);
1866
0
                auto rate_z = glslangIntermediate->getTileShadingRateQCOM(2);
1867
0
                rate_x = ( rate_x == 0 ? 1 : rate_x );
1868
0
                rate_y = ( rate_y == 0 ? 1 : rate_y );
1869
0
                rate_z = ( rate_z == 0 ? 1 : rate_z );
1870
0
                builder.addExecutionMode(shaderEntry, spv::ExecutionMode::TileShadingRateQCOM, rate_x, rate_y, rate_z);
1871
4
            } else {
1872
4
                builder.addExecutionMode(shaderEntry, spv::ExecutionMode::LocalSize, glslangIntermediate->getLocalSize(0),
1873
4
                                                                                   glslangIntermediate->getLocalSize(1),
1874
4
                                                                                   glslangIntermediate->getLocalSize(2));
1875
4
            }
1876
4
        }
1877
4
        if (glslangIntermediate->getLayoutDerivativeModeNone() == glslang::LayoutDerivativeGroupQuads) {
1878
0
            builder.addCapability(spv::Capability::ComputeDerivativeGroupQuadsNV);
1879
0
            builder.addExecutionMode(shaderEntry, spv::ExecutionMode::DerivativeGroupQuadsNV);
1880
0
            builder.addExtension(spv::E_SPV_NV_compute_shader_derivatives);
1881
4
        } else if (glslangIntermediate->getLayoutDerivativeModeNone() == glslang::LayoutDerivativeGroupLinear) {
1882
0
            builder.addCapability(spv::Capability::ComputeDerivativeGroupLinearNV);
1883
0
            builder.addExecutionMode(shaderEntry, spv::ExecutionMode::DerivativeGroupLinearNV);
1884
0
            builder.addExtension(spv::E_SPV_NV_compute_shader_derivatives);
1885
0
        }
1886
1887
4
        if (glslangIntermediate->getNonCoherentTileAttachmentReadQCOM()) {
1888
0
            builder.addCapability(spv::Capability::TileShadingQCOM);
1889
0
            builder.addExecutionMode(shaderEntry, spv::ExecutionMode::NonCoherentTileAttachmentReadQCOM);
1890
0
            builder.addExtension(spv::E_SPV_QCOM_tile_shading);
1891
0
        }
1892
1893
4
        break;
1894
229
    }
1895
0
    case EShLangTessEvaluation:
1896
0
    case EShLangTessControl:
1897
0
        builder.addCapability(spv::Capability::Tessellation);
1898
1899
0
        glslang::TLayoutGeometry primitive;
1900
1901
0
        if (glslangIntermediate->getStage() == EShLangTessControl) {
1902
0
            builder.addExecutionMode(shaderEntry, spv::ExecutionMode::OutputVertices,
1903
0
                glslangIntermediate->getVertices());
1904
0
            primitive = glslangIntermediate->getOutputPrimitive();
1905
0
        } else {
1906
0
            primitive = glslangIntermediate->getInputPrimitive();
1907
0
        }
1908
1909
0
        switch (primitive) {
1910
0
        case glslang::ElgTriangles:           mode = spv::ExecutionMode::Triangles;     break;
1911
0
        case glslang::ElgQuads:               mode = spv::ExecutionMode::Quads;         break;
1912
0
        case glslang::ElgIsolines:            mode = spv::ExecutionMode::Isolines;      break;
1913
0
        default:                              mode = spv::ExecutionMode::Max;           break;
1914
0
        }
1915
0
        if (mode != spv::ExecutionMode::Max)
1916
0
            builder.addExecutionMode(shaderEntry, mode);
1917
1918
0
        switch (glslangIntermediate->getVertexSpacing()) {
1919
0
        case glslang::EvsEqual:            mode = spv::ExecutionMode::SpacingEqual;          break;
1920
0
        case glslang::EvsFractionalEven:   mode = spv::ExecutionMode::SpacingFractionalEven; break;
1921
0
        case glslang::EvsFractionalOdd:    mode = spv::ExecutionMode::SpacingFractionalOdd;  break;
1922
0
        default:                           mode = spv::ExecutionMode::Max;                   break;
1923
0
        }
1924
0
        if (mode != spv::ExecutionMode::Max)
1925
0
            builder.addExecutionMode(shaderEntry, mode);
1926
1927
0
        switch (glslangIntermediate->getVertexOrder()) {
1928
0
        case glslang::EvoCw:     mode = spv::ExecutionMode::VertexOrderCw;  break;
1929
0
        case glslang::EvoCcw:    mode = spv::ExecutionMode::VertexOrderCcw; break;
1930
0
        default:                 mode = spv::ExecutionMode::Max;            break;
1931
0
        }
1932
0
        if (mode != spv::ExecutionMode::Max)
1933
0
            builder.addExecutionMode(shaderEntry, mode);
1934
1935
0
        if (glslangIntermediate->getPointMode())
1936
0
            builder.addExecutionMode(shaderEntry, spv::ExecutionMode::PointMode);
1937
0
        break;
1938
1939
0
    case EShLangGeometry:
1940
0
        builder.addCapability(spv::Capability::Geometry);
1941
0
        switch (glslangIntermediate->getInputPrimitive()) {
1942
0
        case glslang::ElgPoints:             mode = spv::ExecutionMode::InputPoints;             break;
1943
0
        case glslang::ElgLines:              mode = spv::ExecutionMode::InputLines;              break;
1944
0
        case glslang::ElgLinesAdjacency:     mode = spv::ExecutionMode::InputLinesAdjacency;     break;
1945
0
        case glslang::ElgTriangles:          mode = spv::ExecutionMode::Triangles;               break;
1946
0
        case glslang::ElgTrianglesAdjacency: mode = spv::ExecutionMode::InputTrianglesAdjacency; break;
1947
0
        default:                             mode = spv::ExecutionMode::Max;                     break;
1948
0
        }
1949
0
        if (mode != spv::ExecutionMode::Max)
1950
0
            builder.addExecutionMode(shaderEntry, mode);
1951
1952
0
        builder.addExecutionMode(shaderEntry, spv::ExecutionMode::Invocations, glslangIntermediate->getInvocations());
1953
1954
0
        switch (glslangIntermediate->getOutputPrimitive()) {
1955
0
        case glslang::ElgPoints:        mode = spv::ExecutionMode::OutputPoints;                 break;
1956
0
        case glslang::ElgLineStrip:     mode = spv::ExecutionMode::OutputLineStrip;              break;
1957
0
        case glslang::ElgTriangleStrip: mode = spv::ExecutionMode::OutputTriangleStrip;          break;
1958
0
        default:                        mode = spv::ExecutionMode::Max;                          break;
1959
0
        }
1960
0
        if (mode != spv::ExecutionMode::Max)
1961
0
            builder.addExecutionMode(shaderEntry, mode);
1962
0
        builder.addExecutionMode(shaderEntry, spv::ExecutionMode::OutputVertices, glslangIntermediate->getVertices());
1963
0
        break;
1964
1965
38
    case EShLangRayGen:
1966
40
    case EShLangIntersect:
1967
40
    case EShLangAnyHit:
1968
46
    case EShLangClosestHit:
1969
46
    case EShLangMiss:
1970
46
    case EShLangCallable:
1971
46
    {
1972
46
        auto& extensions = glslangIntermediate->getRequestedExtensions();
1973
46
        if (extensions.find("GL_EXT_opacity_micromap") != extensions.end()) {
1974
0
            builder.addCapability(spv::Capability::RayTracingOpacityMicromapEXT);
1975
0
            builder.addExtension("SPV_EXT_opacity_micromap");
1976
0
        }
1977
46
        if (extensions.find("GL_NV_ray_tracing") == extensions.end()) {
1978
46
            builder.addCapability(spv::Capability::RayTracingKHR);
1979
46
            builder.addExtension("SPV_KHR_ray_tracing");
1980
46
        }
1981
0
        else {
1982
0
            builder.addCapability(spv::Capability::RayTracingNV);
1983
0
            builder.addExtension("SPV_NV_ray_tracing");
1984
0
        }
1985
46
        if (glslangIntermediate->getStage() != EShLangRayGen && glslangIntermediate->getStage() != EShLangCallable) {
1986
8
            if (extensions.find("GL_EXT_ray_cull_mask") != extensions.end()) {
1987
0
                builder.addCapability(spv::Capability::RayCullMaskKHR);
1988
0
                builder.addExtension("SPV_KHR_ray_cull_mask");
1989
0
            }
1990
8
            if (extensions.find("GL_EXT_ray_tracing_position_fetch") != extensions.end()) {
1991
0
                builder.addCapability(spv::Capability::RayTracingPositionFetchKHR);
1992
0
                builder.addExtension("SPV_KHR_ray_tracing_position_fetch");
1993
0
            }
1994
8
        }
1995
46
        break;
1996
46
    }
1997
2
    case EShLangTask:
1998
2
    case EShLangMesh:
1999
2
        if(isMeshShaderExt) {
2000
0
            builder.addCapability(spv::Capability::MeshShadingEXT);
2001
0
            builder.addExtension(spv::E_SPV_EXT_mesh_shader);
2002
2
        } else {
2003
2
            builder.addCapability(spv::Capability::MeshShadingNV);
2004
2
            builder.addExtension(spv::E_SPV_NV_mesh_shader);
2005
2
        }
2006
2
        if (glslangIntermediate->getSpv().spv >= glslang::EShTargetSpv_1_6) {
2007
0
            std::vector<spv::Id> dimConstId;
2008
0
            for (int dim = 0; dim < 3; ++dim) {
2009
0
                bool specConst = (glslangIntermediate->getLocalSizeSpecId(dim) != glslang::TQualifier::layoutNotSet);
2010
0
                dimConstId.push_back(builder.makeUintConstant(glslangIntermediate->getLocalSize(dim), specConst));
2011
0
                if (specConst) {
2012
0
                    builder.addDecoration(dimConstId.back(), spv::Decoration::SpecId,
2013
0
                                          glslangIntermediate->getLocalSizeSpecId(dim));
2014
0
                }
2015
0
            }
2016
0
            builder.addExecutionModeId(shaderEntry, spv::ExecutionMode::LocalSizeId, dimConstId);
2017
2
        } else {
2018
2
            builder.addExecutionMode(shaderEntry, spv::ExecutionMode::LocalSize, glslangIntermediate->getLocalSize(0),
2019
2
                                                                               glslangIntermediate->getLocalSize(1),
2020
2
                                                                               glslangIntermediate->getLocalSize(2));
2021
2
        }
2022
2
        if (glslangIntermediate->getStage() == EShLangMesh) {
2023
0
            builder.addExecutionMode(shaderEntry, spv::ExecutionMode::OutputVertices,
2024
0
                glslangIntermediate->getVertices());
2025
0
            builder.addExecutionMode(shaderEntry, spv::ExecutionMode::OutputPrimitivesNV,
2026
0
                glslangIntermediate->getPrimitives());
2027
2028
0
            switch (glslangIntermediate->getOutputPrimitive()) {
2029
0
            case glslang::ElgPoints:        mode = spv::ExecutionMode::OutputPoints;      break;
2030
0
            case glslang::ElgLines:         mode = spv::ExecutionMode::OutputLinesNV;     break;
2031
0
            case glslang::ElgTriangles:     mode = spv::ExecutionMode::OutputTrianglesNV; break;
2032
0
            default:                        mode = spv::ExecutionMode::Max;               break;
2033
0
            }
2034
0
            if (mode != spv::ExecutionMode::Max)
2035
0
                builder.addExecutionMode(shaderEntry, (spv::ExecutionMode)mode);
2036
0
        }
2037
2
        break;
2038
2039
2
    default:
2040
0
        break;
2041
2.08k
    }
2042
2043
    //
2044
    // Add SPIR-V requirements (GL_EXT_spirv_intrinsics)
2045
    //
2046
2.08k
    if (glslangIntermediate->hasSpirvRequirement()) {
2047
47
        const glslang::TSpirvRequirement& spirvRequirement = glslangIntermediate->getSpirvRequirement();
2048
2049
        // Add SPIR-V extension requirement
2050
47
        for (auto& extension : spirvRequirement.extensions)
2051
76
            builder.addExtension(extension.c_str());
2052
2053
        // Add SPIR-V capability requirement
2054
47
        for (auto capability : spirvRequirement.capabilities)
2055
1
            builder.addCapability(static_cast<spv::Capability>(capability));
2056
47
    }
2057
2058
    //
2059
    // Add SPIR-V execution mode qualifiers (GL_EXT_spirv_intrinsics)
2060
    //
2061
2.08k
    if (glslangIntermediate->hasSpirvExecutionMode()) {
2062
1
        const glslang::TSpirvExecutionMode spirvExecutionMode = glslangIntermediate->getSpirvExecutionMode();
2063
2064
        // Add spirv_execution_mode
2065
1
        for (auto& mode : spirvExecutionMode.modes) {
2066
1
            if (!mode.second.empty()) {
2067
0
                std::vector<unsigned> literals;
2068
0
                TranslateLiterals(mode.second, literals);
2069
0
                builder.addExecutionMode(shaderEntry, static_cast<spv::ExecutionMode>(mode.first), literals);
2070
0
            } else
2071
1
                builder.addExecutionMode(shaderEntry, static_cast<spv::ExecutionMode>(mode.first));
2072
1
        }
2073
2074
        // Add spirv_execution_mode_id
2075
1
        for (auto& modeId : spirvExecutionMode.modeIds) {
2076
0
            std::vector<spv::Id> operandIds;
2077
0
            assert(!modeId.second.empty());
2078
0
            for (auto extraOperand : modeId.second) {
2079
0
                if (extraOperand->getType().getQualifier().isSpecConstant())
2080
0
                    operandIds.push_back(getSymbolId(extraOperand->getAsSymbolNode()));
2081
0
                else
2082
0
                    operandIds.push_back(createSpvConstant(*extraOperand));
2083
0
            }
2084
0
            builder.addExecutionModeId(shaderEntry, static_cast<spv::ExecutionMode>(modeId.first), operandIds);
2085
0
        }
2086
1
    }
2087
2.08k
}
2088
2089
// Finish creating SPV, after the traversal is complete.
2090
void TGlslangToSpvTraverser::finishSpv(bool compileOnly)
2091
2.08k
{
2092
    // If not linking, an entry point is not expected
2093
2.08k
    if (!compileOnly) {
2094
        // Finish the entry point function
2095
2.08k
        if (!entryPointTerminated) {
2096
58
            builder.setBuildPoint(shaderEntry->getLastBlock());
2097
58
            builder.leaveFunction();
2098
58
        }
2099
2100
        // finish off the entry-point SPV instruction by adding the Input/Output <id>
2101
2.08k
        entryPoint->reserveOperands(iOSet.size());
2102
2.08k
        for (auto id : iOSet)
2103
2.56k
            entryPoint->addIdOperand(id);
2104
2.08k
    }
2105
2106
    // Add capabilities, extensions, remove unneeded decorations, etc.,
2107
    // based on the resulting SPIR-V.
2108
    // Note: WebGPU code generation must have the opportunity to aggressively
2109
    // prune unreachable merge blocks and continue targets.
2110
2.08k
    builder.postProcess(compileOnly);
2111
2.08k
}
2112
2113
// Write the SPV into 'out'.
2114
void TGlslangToSpvTraverser::dumpSpv(std::vector<unsigned int>& out)
2115
2.08k
{
2116
2.08k
    builder.dump(out);
2117
2.08k
}
2118
2119
//
2120
// Implement the traversal functions.
2121
//
2122
// Return true from interior nodes to have the external traversal
2123
// continue on to children.  Return false if children were
2124
// already processed.
2125
//
2126
2127
//
2128
// Symbols can turn into
2129
//  - uniform/input reads
2130
//  - output writes
2131
//  - complex lvalue base setups:  foo.bar[3]....  , where we see foo and start up an access chain
2132
//  - something simple that degenerates into the last bullet
2133
//
2134
void TGlslangToSpvTraverser::visitSymbol(glslang::TIntermSymbol* symbol)
2135
81.8k
{
2136
    // We update the line information even though no code might be generated here
2137
    // This is helpful to yield correct lines for control flow instructions
2138
81.8k
    if (!linkageOnly) {
2139
72.0k
        builder.setDebugSourceLocation(symbol->getLoc().line, symbol->getLoc().getFilename());
2140
72.0k
    }
2141
2142
81.8k
    if (symbol->getBasicType() == glslang::EbtFunction) {
2143
0
        return;
2144
0
    }
2145
2146
81.8k
    SpecConstantOpModeGuard spec_constant_op_mode_setter(&builder);
2147
81.8k
    if (symbol->getType().isStruct())
2148
9.86k
        glslangTypeToIdMap[symbol->getType().getStruct()] = symbol->getId();
2149
2150
81.8k
    if (symbol->getType().getQualifier().isSpecConstant())
2151
1.29k
        spec_constant_op_mode_setter.turnOnSpecConstantOpMode();
2152
81.8k
#ifdef ENABLE_HLSL
2153
    // Skip symbol handling if it is string-typed
2154
81.8k
    if (symbol->getBasicType() == glslang::EbtString)
2155
0
        return;
2156
81.8k
#endif
2157
2158
    // getSymbolId() will set up all the IO decorations on the first call.
2159
    // Formal function parameters were mapped during makeFunctions().
2160
81.8k
    spv::Id id = getSymbolId(symbol);
2161
2162
81.8k
    if (symbol->getType().getQualifier().isTaskPayload())
2163
0
        taskPayloadID = id; // cache the taskPayloadID to be used it as operand for OpEmitMeshTasksEXT
2164
2165
81.8k
    if (builder.isPointer(id)) {
2166
80.4k
        if (!symbol->getType().getQualifier().isParamInput() &&
2167
78.1k
            !symbol->getType().getQualifier().isParamOutput()) {
2168
            // Include all "static use" and "linkage only" interface variables on the OpEntryPoint instruction
2169
            // Consider adding to the OpEntryPoint interface list.
2170
            // Only looking at structures if they have at least one member.
2171
78.1k
            if (!symbol->getType().isStruct() || symbol->getType().getStruct()->size() > 0) {
2172
78.1k
                spv::StorageClass sc = builder.getStorageClass(id);
2173
                // Before SPIR-V 1.4, we only want to include Input and Output.
2174
                // Starting with SPIR-V 1.4, we want all globals.
2175
78.1k
                if ((glslangIntermediate->getSpv().spv >= glslang::EShTargetSpv_1_4 && builder.isGlobalVariable(id)) ||
2176
78.1k
                    (sc == spv::StorageClass::Input || sc == spv::StorageClass::Output)) {
2177
9.85k
                    iOSet.insert(id);
2178
9.85k
                }
2179
78.1k
            }
2180
78.1k
        }
2181
2182
        // If the SPIR-V type is required to be different than the AST type
2183
        // (for ex SubgroupMasks or 3x4 ObjectToWorld/WorldToObject matrices),
2184
        // translate now from the SPIR-V type to the AST type, for the consuming
2185
        // operation.
2186
        // Note this turns it from an l-value to an r-value.
2187
        // Currently, all symbols needing this are inputs; avoid the map lookup when non-input.
2188
80.4k
        if (symbol->getType().getQualifier().storage == glslang::EvqVaryingIn)
2189
6.60k
            id = translateForcedType(id);
2190
80.4k
    }
2191
2192
    // Only process non-linkage-only nodes for generating actual static uses
2193
81.8k
    if (! linkageOnly || symbol->getQualifier().isSpecConstant()) {
2194
        // Prepare to generate code for the access
2195
2196
        // L-value chains will be computed left to right.  We're on the symbol now,
2197
        // which is the left-most part of the access chain, so now is "clear" time,
2198
        // followed by setting the base.
2199
73.3k
        builder.clearAccessChain();
2200
2201
        // For now, we consider all user variables as being in memory, so they are pointers,
2202
        // except for
2203
        // A) R-Value arguments to a function, which are an intermediate object.
2204
        //    See comments in handleUserFunctionCall().
2205
        // B) Specialization constants (normal constants don't even come in as a variable),
2206
        //    These are also pure R-values.
2207
        // C) R-Values from type translation, see above call to translateForcedType()
2208
73.3k
        glslang::TQualifier qualifier = symbol->getQualifier();
2209
73.3k
        if (qualifier.isSpecConstant() || rValueParameters.find(symbol->getId()) != rValueParameters.end() ||
2210
72.0k
            !builder.isPointerType(builder.getTypeId(id)))
2211
1.30k
            builder.setAccessChainRValue(id);
2212
72.0k
        else
2213
72.0k
            builder.setAccessChainLValue(id);
2214
73.3k
    }
2215
2216
81.8k
#ifdef ENABLE_HLSL
2217
    // Process linkage-only nodes for any special additional interface work.
2218
81.8k
    if (linkageOnly) {
2219
9.78k
        if (glslangIntermediate->getHlslFunctionality1()) {
2220
            // Map implicit counter buffers to their originating buffers, which should have been
2221
            // seen by now, given earlier pruning of unused counters, and preservation of order
2222
            // of declaration.
2223
1.50k
            if (symbol->getType().getQualifier().isUniformOrBuffer()) {
2224
682
                if (!glslangIntermediate->hasCounterBufferName(symbol->getName())) {
2225
                    // Save possible originating buffers for counter buffers, keyed by
2226
                    // making the potential counter-buffer name.
2227
682
                    std::string keyName = symbol->getName().c_str();
2228
682
                    keyName = glslangIntermediate->addCounterBufferName(keyName);
2229
682
                    counterOriginator[keyName] = symbol;
2230
682
                } else {
2231
                    // Handle a counter buffer, by finding the saved originating buffer.
2232
0
                    std::string keyName = symbol->getName().c_str();
2233
0
                    auto it = counterOriginator.find(keyName);
2234
0
                    if (it != counterOriginator.end()) {
2235
0
                        id = getSymbolId(it->second);
2236
0
                        if (id != spv::NoResult) {
2237
0
                            spv::Id counterId = getSymbolId(symbol);
2238
0
                            if (counterId != spv::NoResult) {
2239
0
                                builder.addExtension("SPV_GOOGLE_hlsl_functionality1");
2240
0
                                builder.addDecorationId(id, spv::Decoration::HlslCounterBufferGOOGLE, counterId);
2241
0
                            }
2242
0
                        }
2243
0
                    }
2244
0
                }
2245
682
            }
2246
1.50k
        }
2247
9.78k
    }
2248
81.8k
#endif
2249
81.8k
}
2250
2251
bool TGlslangToSpvTraverser::visitBinary(glslang::TVisit /* visit */, glslang::TIntermBinary* node)
2252
53.7k
{
2253
53.7k
    builder.setDebugSourceLocation(node->getLoc().line, node->getLoc().getFilename());
2254
53.7k
    if (node->getLeft()->getAsSymbolNode() != nullptr && node->getLeft()->getType().isStruct()) {
2255
7.98k
        glslangTypeToIdMap[node->getLeft()->getType().getStruct()] = node->getLeft()->getAsSymbolNode()->getId();
2256
7.98k
    }
2257
53.7k
    if (node->getRight()->getAsSymbolNode() != nullptr && node->getRight()->getType().isStruct()) {
2258
224
        glslangTypeToIdMap[node->getRight()->getType().getStruct()] = node->getRight()->getAsSymbolNode()->getId();
2259
224
    }
2260
2261
53.7k
    SpecConstantOpModeGuard spec_constant_op_mode_setter(&builder);
2262
53.7k
    if (node->getType().getQualifier().isSpecConstant())
2263
19
        spec_constant_op_mode_setter.turnOnSpecConstantOpMode();
2264
2265
    // First, handle special cases
2266
53.7k
    switch (node->getOp()) {
2267
15.7k
    case glslang::EOpAssign:
2268
19.0k
    case glslang::EOpAddAssign:
2269
19.3k
    case glslang::EOpSubAssign:
2270
19.7k
    case glslang::EOpMulAssign:
2271
19.7k
    case glslang::EOpVectorTimesMatrixAssign:
2272
19.9k
    case glslang::EOpVectorTimesScalarAssign:
2273
19.9k
    case glslang::EOpMatrixTimesScalarAssign:
2274
19.9k
    case glslang::EOpMatrixTimesMatrixAssign:
2275
19.9k
    case glslang::EOpDivAssign:
2276
20.2k
    case glslang::EOpModAssign:
2277
20.4k
    case glslang::EOpAndAssign:
2278
20.4k
    case glslang::EOpInclusiveOrAssign:
2279
20.4k
    case glslang::EOpExclusiveOrAssign:
2280
20.7k
    case glslang::EOpLeftShiftAssign:
2281
20.7k
    case glslang::EOpRightShiftAssign:
2282
        // A bin-op assign "a += b" means the same thing as "a = a + b"
2283
        // where a is evaluated before b. For a simple assignment, GLSL
2284
        // says to evaluate the left before the right.  So, always, left
2285
        // node then right node.
2286
20.7k
        {
2287
            // get the left l-value, save it away
2288
20.7k
            builder.clearAccessChain();
2289
20.7k
            node->getLeft()->traverse(this);
2290
20.7k
            spv::Builder::AccessChain lValue = builder.getAccessChain();
2291
2292
            // evaluate the right
2293
20.7k
            builder.clearAccessChain();
2294
20.7k
            node->getRight()->traverse(this);
2295
20.7k
            spv::Id rValue = accessChainLoad(node->getRight()->getType());
2296
2297
            // reset line number for assignment
2298
20.7k
            builder.setDebugSourceLocation(node->getLoc().line, node->getLoc().getFilename());
2299
2300
20.7k
            if (node->getOp() != glslang::EOpAssign) {
2301
                // the left is also an r-value
2302
4.95k
                builder.setAccessChain(lValue);
2303
4.95k
                spv::Id leftRValue = accessChainLoad(node->getLeft()->getType());
2304
2305
                // do the operation
2306
4.95k
                spv::Builder::AccessChain::CoherentFlags coherentFlags = TranslateCoherent(node->getLeft()->getType());
2307
4.95k
                coherentFlags |= TranslateCoherent(node->getRight()->getType());
2308
4.95k
                OpDecorations decorations = { TranslatePrecisionDecoration(node->getOperationPrecision()),
2309
4.95k
                                              TranslateNoContractionDecoration(node->getType().getQualifier()),
2310
4.95k
                                              TranslateNonUniformDecoration(coherentFlags) };
2311
4.95k
                rValue = createBinaryOperation(node->getOp(), decorations,
2312
4.95k
                                               convertGlslangToSpvType(node->getType()), leftRValue, rValue,
2313
4.95k
                                               node->getType().getBasicType());
2314
2315
                // these all need their counterparts in createBinaryOperation()
2316
4.95k
                assert(rValue != spv::NoResult);
2317
4.95k
            }
2318
2319
            // store the result
2320
20.7k
            builder.setAccessChain(lValue);
2321
20.7k
            multiTypeStore(node->getLeft()->getType(), rValue);
2322
2323
            // assignments are expressions having an rValue after they are evaluated...
2324
20.7k
            builder.clearAccessChain();
2325
20.7k
            builder.setAccessChainRValue(rValue);
2326
20.7k
        }
2327
20.7k
        return false;
2328
5.16k
    case glslang::EOpIndexDirect:
2329
14.1k
    case glslang::EOpIndexDirectStruct:
2330
14.1k
        {
2331
            // Structure, array, matrix, or vector indirection with statically known index.
2332
            // Get the left part of the access chain.
2333
14.1k
            node->getLeft()->traverse(this);
2334
2335
            // Add the next element in the chain
2336
2337
14.1k
            const int glslangIndex = node->getRight()->getAsConstantUnion()->getConstArray()[0].getIConst();
2338
14.1k
            if (! node->getLeft()->getType().isArray() &&
2339
13.1k
                node->getLeft()->getType().isVector() &&
2340
3.96k
                node->getOp() == glslang::EOpIndexDirect) {
2341
                // Swizzle is uniform so propagate uniform into access chain
2342
3.96k
                spv::Builder::AccessChain::CoherentFlags coherentFlags = TranslateCoherent(node->getLeft()->getType());
2343
3.96k
                coherentFlags.nonUniform = 0;
2344
                // This is essentially a hard-coded vector swizzle of size 1,
2345
                // so short circuit the access-chain stuff with a swizzle.
2346
3.96k
                std::vector<unsigned> swizzle;
2347
3.96k
                swizzle.push_back(glslangIndex);
2348
3.96k
                int dummySize;
2349
3.96k
                builder.accessChainPushSwizzle(swizzle, convertGlslangToSpvType(node->getLeft()->getType()),
2350
3.96k
                                               coherentFlags,
2351
3.96k
                                               glslangIntermediate->getBaseAlignmentScalar(
2352
3.96k
                                                   node->getLeft()->getType(), dummySize));
2353
10.2k
            } else {
2354
2355
                // Load through a block reference is performed with a dot operator that
2356
                // is mapped to EOpIndexDirectStruct. When we get to the actual reference,
2357
                // do a load and reset the access chain.
2358
10.2k
                if (node->getLeft()->isReference() &&
2359
639
                    !node->getLeft()->getType().isArray() &&
2360
612
                    node->getOp() == glslang::EOpIndexDirectStruct)
2361
612
                {
2362
612
                    spv::Id left = accessChainLoad(node->getLeft()->getType());
2363
612
                    builder.clearAccessChain();
2364
612
                    builder.setAccessChainLValue(left);
2365
612
                }
2366
2367
10.2k
                int spvIndex = glslangIndex;
2368
10.2k
                if (node->getLeft()->getBasicType() == glslang::EbtBlock &&
2369
7.03k
                    node->getOp() == glslang::EOpIndexDirectStruct)
2370
7.02k
                {
2371
                    // This may be, e.g., an anonymous block-member selection, which generally need
2372
                    // index remapping due to hidden members in anonymous blocks.
2373
7.02k
                    long long glslangId = glslangTypeToIdMap[node->getLeft()->getType().getStruct()];
2374
7.02k
                    if (memberRemapper.find(glslangId) != memberRemapper.end()) {
2375
7.02k
                        std::vector<int>& remapper = memberRemapper[glslangId];
2376
7.02k
                        assert(remapper.size() > 0);
2377
7.02k
                        spvIndex = remapper[glslangIndex];
2378
7.02k
                    }
2379
7.02k
                }
2380
2381
                // Struct reference propagates uniform lvalue
2382
10.2k
                spv::Builder::AccessChain::CoherentFlags coherentFlags =
2383
10.2k
                        TranslateCoherent(node->getLeft()->getType());
2384
10.2k
                coherentFlags.nonUniform = 0;
2385
2386
                // normal case for indexing array or structure or block
2387
10.2k
                if ((node->getRight()->getType().getBasicType() == glslang::EbtUint && glslangIntermediate->usingPromoteUint32Indices()) ||
2388
10.2k
                     node->getRight()->getType().contains64BitInt()) {
2389
0
                    int64_t idx = node->getRight()->getType().contains64BitInt() ?
2390
0
                                    node->getRight()->getAsConstantUnion()->getConstArray()[0].getI64Const() :
2391
0
                                    node->getRight()->getAsConstantUnion()->getConstArray()[0].getUConst();
2392
0
                    builder.accessChainPush(builder.makeInt64Constant(idx),
2393
0
                            coherentFlags,
2394
0
                            node->getLeft()->getType().getBufferReferenceAlignment());
2395
2396
10.2k
                } else {
2397
10.2k
                    builder.accessChainPush(builder.makeIntConstant(spvIndex),
2398
10.2k
                            coherentFlags,
2399
10.2k
                            node->getLeft()->getType().getBufferReferenceAlignment());
2400
10.2k
                }
2401
                // Add capabilities here for accessing PointSize and clip/cull distance.
2402
                // We have deferred generation of associated capabilities until now.
2403
10.2k
                if (node->getLeft()->getType().isStruct() && ! node->getLeft()->getType().isArray())
2404
8.40k
                    declareUseOfStructMember(*(node->getLeft()->getType().getStruct()), glslangIndex);
2405
10.2k
            }
2406
14.1k
        }
2407
14.1k
        return false;
2408
1.15k
    case glslang::EOpIndexIndirect:
2409
1.15k
        {
2410
            // Array, matrix, or vector indirection with variable index.
2411
            // Will use native SPIR-V access-chain for and array indirection;
2412
            // matrices are arrays of vectors, so will also work for a matrix.
2413
            // Will use the access chain's 'component' for variable index into a vector.
2414
2415
            // This adapter is building access chains left to right.
2416
            // Set up the access chain to the left.
2417
1.15k
            node->getLeft()->traverse(this);
2418
2419
            // save it so that computing the right side doesn't trash it
2420
1.15k
            spv::Builder::AccessChain partial = builder.getAccessChain();
2421
2422
            // compute the next index in the chain
2423
1.15k
            builder.clearAccessChain();
2424
1.15k
            node->getRight()->traverse(this);
2425
1.15k
            spv::Id index = accessChainLoad(node->getRight()->getType());
2426
2427
            // Zero-extend smaller unsigned integer types for array indexing.
2428
            // SPIR-V OpAccessChain treats indices as signed, so we need to zero-extend
2429
            // unsigned types to preserve their values (signed types are fine as-is).
2430
1.15k
            spv::Id indexType = builder.getTypeId(index);
2431
1.15k
            if (builder.isUintType(indexType) && builder.getScalarTypeWidth(indexType) < 32) {
2432
                // Zero-extend unsigned types to preserve their values
2433
0
                spv::Id uintType = builder.makeUintType(32);
2434
0
                index = builder.createUnaryOp(spv::Op::OpUConvert, uintType, index);
2435
0
            }
2436
2437
1.15k
            addIndirectionIndexCapabilities(node->getLeft()->getType(), node->getRight()->getType());
2438
2439
            // restore the saved access chain
2440
1.15k
            builder.setAccessChain(partial);
2441
2442
            // Only if index is nonUniform should we propagate nonUniform into access chain
2443
1.15k
            spv::Builder::AccessChain::CoherentFlags index_flags = TranslateCoherent(node->getRight()->getType());
2444
1.15k
            spv::Builder::AccessChain::CoherentFlags coherent_flags = TranslateCoherent(node->getLeft()->getType());
2445
1.15k
            coherent_flags.nonUniform = index_flags.nonUniform;
2446
2447
1.15k
            if (! node->getLeft()->getType().isArray() && node->getLeft()->getType().isVector()) {
2448
6
                int dummySize;
2449
6
                builder.accessChainPushComponent(
2450
6
                    index, convertGlslangToSpvType(node->getLeft()->getType()), coherent_flags,
2451
6
                                                glslangIntermediate->getBaseAlignmentScalar(node->getLeft()->getType(),
2452
6
                                                dummySize));
2453
1.15k
            } else {
2454
1.15k
                if (glslangIntermediate->usingPromoteUint32Indices() &&
2455
0
                    node->getRight()->getType().getBasicType() == glslang::EbtUint) {
2456
0
                    index = createIntWidthConversion(index, 0, builder.makeIntegerType(64, true), glslang::EbtInt64, node->getRight()->getType().getBasicType());
2457
0
                }
2458
2459
1.15k
                builder.accessChainPush(index, coherent_flags,
2460
1.15k
                                        node->getLeft()->getType().getBufferReferenceAlignment());
2461
1.15k
            }
2462
1.15k
        }
2463
1.15k
        return false;
2464
4.63k
    case glslang::EOpVectorSwizzle:
2465
4.63k
        {
2466
4.63k
            node->getLeft()->traverse(this);
2467
4.63k
            std::vector<unsigned> swizzle;
2468
4.63k
            convertSwizzle(*node->getRight()->getAsAggregate(), swizzle);
2469
4.63k
            int dummySize;
2470
4.63k
            builder.accessChainPushSwizzle(swizzle, convertGlslangToSpvType(node->getLeft()->getType()),
2471
4.63k
                                           TranslateCoherent(node->getLeft()->getType()),
2472
4.63k
                                           glslangIntermediate->getBaseAlignmentScalar(node->getLeft()->getType(),
2473
4.63k
                                               dummySize));
2474
4.63k
        }
2475
4.63k
        return false;
2476
0
    case glslang::EOpMatrixSwizzle:
2477
0
        logger->missingFunctionality("matrix swizzle");
2478
0
        return true;
2479
212
    case glslang::EOpLogicalOr:
2480
863
    case glslang::EOpLogicalAnd:
2481
863
        {
2482
2483
            // These may require short circuiting, but can sometimes be done as straight
2484
            // binary operations.  The right operand must be short circuited if it has
2485
            // side effects, and should probably be if it is complex.
2486
863
            if (isTrivial(node->getRight()->getAsTyped()))
2487
414
                break; // handle below as a normal binary operation
2488
            // otherwise, we need to do dynamic short circuiting on the right operand
2489
449
            spv::Id result = createShortCircuit(node->getOp(), *node->getLeft()->getAsTyped(),
2490
449
                *node->getRight()->getAsTyped());
2491
449
            builder.clearAccessChain();
2492
449
            builder.setAccessChainRValue(result);
2493
449
        }
2494
0
        return false;
2495
12.1k
    default:
2496
12.1k
        break;
2497
53.7k
    }
2498
2499
    // Assume generic binary op...
2500
2501
    // get right operand
2502
12.5k
    builder.clearAccessChain();
2503
12.5k
    node->getLeft()->traverse(this);
2504
12.5k
    spv::Id left = accessChainLoad(node->getLeft()->getType());
2505
2506
    // get left operand
2507
12.5k
    builder.clearAccessChain();
2508
12.5k
    node->getRight()->traverse(this);
2509
12.5k
    spv::Id right = accessChainLoad(node->getRight()->getType());
2510
2511
    // get result
2512
12.5k
    OpDecorations decorations = { TranslatePrecisionDecoration(node->getOperationPrecision()),
2513
12.5k
                                  TranslateNoContractionDecoration(node->getType().getQualifier()),
2514
12.5k
                                  TranslateNonUniformDecoration(node->getType().getQualifier()) };
2515
12.5k
    spv::Id result = createBinaryOperation(node->getOp(), decorations,
2516
12.5k
                                           convertGlslangToSpvType(node->getType()), left, right,
2517
12.5k
                                           node->getLeft()->getType().getBasicType());
2518
2519
12.5k
    builder.clearAccessChain();
2520
12.5k
    if (! result) {
2521
0
        logger->missingFunctionality("unknown glslang binary operation");
2522
0
        return true;  // pick up a child as the place-holder result
2523
12.5k
    } else {
2524
12.5k
        builder.setAccessChainRValue(result);
2525
12.5k
        return false;
2526
12.5k
    }
2527
12.5k
}
2528
2529
spv::Id TGlslangToSpvTraverser::convertLoadedBoolInUniformToUint(const glslang::TType& type,
2530
                                                                 spv::Id nominalTypeId,
2531
                                                                 spv::Id loadedId)
2532
6.60k
{
2533
6.60k
    if (builder.isScalarType(nominalTypeId)) {
2534
        // Conversion for bool
2535
6.38k
        spv::Id boolType = builder.makeBoolType();
2536
6.38k
        if (nominalTypeId != boolType)
2537
157
            return builder.createBinOp(spv::Op::OpINotEqual, boolType, loadedId, builder.makeUintConstant(0));
2538
6.38k
    } else if (builder.isVectorType(nominalTypeId)) {
2539
        // Conversion for bvec
2540
192
        int vecSize = builder.getNumTypeComponents(nominalTypeId);
2541
192
        spv::Id bvecType = builder.makeVectorType(builder.makeBoolType(), vecSize);
2542
192
        if (nominalTypeId != bvecType)
2543
10
            loadedId = builder.createBinOp(spv::Op::OpINotEqual, bvecType, loadedId,
2544
10
                makeSmearedConstant(builder.makeUintConstant(0), vecSize));
2545
192
    } else if (builder.isArrayType(nominalTypeId)) {
2546
        // Conversion for bool array
2547
30
        spv::Id boolArrayTypeId = convertGlslangToSpvType(type);
2548
30
        if (nominalTypeId != boolArrayTypeId)
2549
30
        {
2550
            // Use OpCopyLogical from SPIR-V 1.4 if available.
2551
30
            if (glslangIntermediate->getSpv().spv >= glslang::EShTargetSpv_1_4)
2552
0
                return builder.createUnaryOp(spv::Op::OpCopyLogical, boolArrayTypeId, loadedId);
2553
2554
30
            glslang::TType glslangElementType(type, 0);
2555
30
            spv::Id elementNominalTypeId = builder.getContainedTypeId(nominalTypeId);
2556
30
            std::vector<spv::Id> constituents;
2557
110
            for (int index = 0; index < type.getOuterArraySize(); ++index) {
2558
                // get the element
2559
80
                spv::Id elementValue = builder.createCompositeExtract(loadedId, elementNominalTypeId, index);
2560
2561
                // recursively convert it
2562
80
                spv::Id elementConvertedValue = convertLoadedBoolInUniformToUint(glslangElementType, elementNominalTypeId, elementValue);
2563
80
                constituents.push_back(elementConvertedValue);
2564
80
            }
2565
30
            return builder.createCompositeConstruct(boolArrayTypeId, constituents);
2566
30
        }
2567
30
    }
2568
2569
6.41k
    return loadedId;
2570
6.60k
}
2571
2572
// Figure out what, if any, type changes are needed when accessing a specific built-in.
2573
// Returns <the type SPIR-V requires for declarion, the type to translate to on use>.
2574
// Also see comment for 'forceType', regarding tracking SPIR-V-required types.
2575
std::pair<spv::Id, spv::Id> TGlslangToSpvTraverser::getForcedType(glslang::TBuiltInVariable glslangBuiltIn,
2576
    const glslang::TType& glslangType)
2577
21.5k
{
2578
21.5k
    switch(glslangBuiltIn)
2579
21.5k
    {
2580
0
        case glslang::EbvSubGroupEqMask:
2581
0
        case glslang::EbvSubGroupGeMask:
2582
0
        case glslang::EbvSubGroupGtMask:
2583
0
        case glslang::EbvSubGroupLeMask:
2584
0
        case glslang::EbvSubGroupLtMask: {
2585
            // these require changing a 64-bit scaler -> a vector of 32-bit components
2586
0
            if (glslangType.isVector())
2587
0
                break;
2588
0
            spv::Id ivec4_type = builder.makeVectorType(builder.makeUintType(32), 4);
2589
0
            spv::Id uint64_type = builder.makeUintType(64);
2590
0
            std::pair<spv::Id, spv::Id> ret(ivec4_type, uint64_type);
2591
0
            return ret;
2592
0
        }
2593
        // There are no SPIR-V builtins defined for these and map onto original non-transposed
2594
        // builtins. During visitBinary we insert a transpose
2595
0
        case glslang::EbvWorldToObject3x4:
2596
0
        case glslang::EbvObjectToWorld3x4: {
2597
0
            spv::Id mat43 = builder.makeMatrixType(builder.makeFloatType(32), 4, 3);
2598
0
            spv::Id mat34 = builder.makeMatrixType(builder.makeFloatType(32), 3, 4);
2599
0
            std::pair<spv::Id, spv::Id> ret(mat43, mat34);
2600
0
            return ret;
2601
0
        }
2602
21.5k
        default:
2603
21.5k
            break;
2604
21.5k
    }
2605
2606
21.5k
    std::pair<spv::Id, spv::Id> ret(spv::NoType, spv::NoType);
2607
21.5k
    return ret;
2608
21.5k
}
2609
2610
// For an object previously identified (see getForcedType() and forceType)
2611
// as needing type translations, do the translation needed for a load, turning
2612
// an L-value into in R-value.
2613
spv::Id TGlslangToSpvTraverser::translateForcedType(spv::Id object)
2614
6.60k
{
2615
6.60k
    const auto forceIt = forceType.find(object);
2616
6.60k
    if (forceIt == forceType.end())
2617
6.60k
        return object;
2618
2619
0
    spv::Id desiredTypeId = forceIt->second;
2620
0
    spv::Id objectTypeId = builder.getTypeId(object);
2621
0
    assert(builder.isPointerType(objectTypeId));
2622
0
    objectTypeId = builder.getContainedTypeId(objectTypeId);
2623
0
    if (builder.isVectorType(objectTypeId) &&
2624
0
        builder.getScalarTypeWidth(builder.getContainedTypeId(objectTypeId)) == 32) {
2625
0
        if (builder.getScalarTypeWidth(desiredTypeId) == 64) {
2626
            // handle 32-bit v.xy* -> 64-bit
2627
0
            builder.clearAccessChain();
2628
0
            builder.setAccessChainLValue(object);
2629
0
            object = builder.accessChainLoad(spv::NoPrecision, spv::Decoration::Max, spv::Decoration::Max, objectTypeId);
2630
0
            std::vector<spv::Id> components;
2631
0
            components.push_back(builder.createCompositeExtract(object, builder.getContainedTypeId(objectTypeId), 0));
2632
0
            components.push_back(builder.createCompositeExtract(object, builder.getContainedTypeId(objectTypeId), 1));
2633
2634
0
            spv::Id vecType = builder.makeVectorType(builder.getContainedTypeId(objectTypeId), 2);
2635
0
            return builder.createUnaryOp(spv::Op::OpBitcast, desiredTypeId,
2636
0
                                         builder.createCompositeConstruct(vecType, components));
2637
0
        } else {
2638
0
            logger->missingFunctionality("forcing 32-bit vector type to non 64-bit scalar");
2639
0
        }
2640
0
    } else if (builder.isMatrixType(objectTypeId)) {
2641
            // There are no SPIR-V builtins defined for 3x4 variants of ObjectToWorld/WorldToObject
2642
            // and we insert a transpose after loading the original non-transposed builtins
2643
0
            builder.clearAccessChain();
2644
0
            builder.setAccessChainLValue(object);
2645
0
            object = builder.accessChainLoad(spv::NoPrecision, spv::Decoration::Max, spv::Decoration::Max, objectTypeId);
2646
0
            return builder.createUnaryOp(spv::Op::OpTranspose, desiredTypeId, object);
2647
2648
0
    } else  {
2649
0
        logger->missingFunctionality("forcing non 32-bit vector type");
2650
0
    }
2651
2652
0
    return object;
2653
0
}
2654
2655
bool TGlslangToSpvTraverser::visitUnary(glslang::TVisit /* visit */, glslang::TIntermUnary* node)
2656
8.95k
{
2657
8.95k
    builder.setDebugSourceLocation(node->getLoc().line, node->getLoc().getFilename());
2658
2659
8.95k
    SpecConstantOpModeGuard spec_constant_op_mode_setter(&builder);
2660
8.95k
    if (node->getType().getQualifier().isSpecConstant())
2661
459
        spec_constant_op_mode_setter.turnOnSpecConstantOpMode();
2662
2663
8.95k
    spv::Id result = spv::NoResult;
2664
2665
    // try texturing first
2666
8.95k
    result = createImageTextureFunctionCall(node);
2667
8.95k
    if (result != spv::NoResult) {
2668
125
        builder.clearAccessChain();
2669
125
        builder.setAccessChainRValue(result);
2670
2671
125
        return false; // done with this node
2672
125
    }
2673
2674
    // Non-texturing.
2675
2676
8.83k
    if (node->getOp() == glslang::EOpArrayLength) {
2677
        // Quite special; won't want to evaluate the operand.
2678
2679
        // Currently, the front-end does not allow .length() on an array until it is sized,
2680
        // except for the last block membeor of an SSBO.
2681
        // TODO: If this changes, link-time sized arrays might show up here, and need their
2682
        // size extracted.
2683
2684
        // Normal .length() would have been constant folded by the front-end.
2685
        // So, this has to be block.lastMember.length().
2686
        // SPV wants "block" and member number as the operands, go get them.
2687
2688
0
        uint32_t bits = node->getType().contains64BitInt() ? 64 : 32;
2689
2690
0
        spv::Id length;
2691
0
        if (node->getOperand()->getType().isCoopMat()) {
2692
0
            spv::Id typeId = convertGlslangToSpvType(node->getOperand()->getType());
2693
0
            assert(builder.isCooperativeMatrixType(typeId));
2694
2695
0
            if (node->getOperand()->getType().isCoopMatKHR()) {
2696
0
                length = builder.createCooperativeMatrixLengthKHR(typeId);
2697
0
            } else {
2698
0
                spec_constant_op_mode_setter.turnOnSpecConstantOpMode();
2699
0
                length = builder.createCooperativeMatrixLengthNV(typeId);
2700
0
            }
2701
0
        } else if (node->getOperand()->getType().isCoopVecNV()) {
2702
0
            spv::Id typeId = convertGlslangToSpvType(node->getOperand()->getType());
2703
0
            length = builder.getCooperativeVectorNumComponents(typeId);
2704
0
        } else {
2705
0
            glslang::TIntermTyped* block = node->getOperand()->getAsBinaryNode()->getLeft();
2706
0
            block->traverse(this);
2707
0
            unsigned int member = node->getOperand()->getAsBinaryNode()->getRight()->getAsConstantUnion()
2708
0
                ->getConstArray()[0].getUConst();
2709
0
            length = builder.createArrayLength(builder.accessChainGetLValue(), member, bits);
2710
0
        }
2711
2712
        // GLSL semantics say the result of .length() is an int, while SPIR-V says
2713
        // signedness must be 0. So, convert from SPIR-V unsigned back to GLSL's
2714
        // AST expectation of a signed result.
2715
0
        if (glslangIntermediate->getSource() == glslang::EShSourceGlsl) {
2716
0
            if (builder.isInSpecConstCodeGenMode()) {
2717
0
                length = builder.createBinOp(spv::Op::OpIAdd, builder.makeIntType(bits), length, builder.makeIntConstant(0));
2718
0
            } else {
2719
0
                length = builder.createUnaryOp(spv::Op::OpBitcast, builder.makeIntType(bits), length);
2720
0
            }
2721
0
        }
2722
2723
0
        builder.clearAccessChain();
2724
0
        builder.setAccessChainRValue(length);
2725
2726
0
        return false;
2727
0
    }
2728
2729
    // Force variable declaration - Debug Mode Only
2730
8.83k
    if (node->getOp() == glslang::EOpDeclare) {
2731
0
        builder.clearAccessChain();
2732
0
        node->getOperand()->traverse(this);
2733
0
        builder.clearAccessChain();
2734
0
        return false;
2735
0
    }
2736
2737
    // Start by evaluating the operand
2738
2739
    // Does it need a swizzle inversion?  If so, evaluation is inverted;
2740
    // operate first on the swizzle base, then apply the swizzle.
2741
8.83k
    spv::Id invertedType = spv::NoType;
2742
13.7k
    auto resultType = [&invertedType, &node, this](){ return invertedType != spv::NoType ?
2743
13.7k
        invertedType : convertGlslangToSpvType(node->getType()); };
2744
8.83k
    if (node->getOp() == glslang::EOpInterpolateAtCentroid)
2745
0
        invertedType = getInvertedSwizzleType(*node->getOperand());
2746
2747
8.83k
    builder.clearAccessChain();
2748
8.83k
    TIntermNode *operandNode;
2749
8.83k
    if (invertedType != spv::NoType)
2750
0
        operandNode = node->getOperand()->getAsBinaryNode()->getLeft();
2751
8.83k
    else
2752
8.83k
        operandNode = node->getOperand();
2753
2754
8.83k
    operandNode->traverse(this);
2755
2756
8.83k
    spv::Id operand = spv::NoResult;
2757
2758
8.83k
    spv::Builder::AccessChain::CoherentFlags lvalueCoherentFlags;
2759
2760
8.83k
    const auto hitObjectOpsWithLvalue = [](glslang::TOperator op) {
2761
8.55k
        switch(op) {
2762
0
            case glslang::EOpReorderThreadNV:
2763
0
            case glslang::EOpHitObjectGetCurrentTimeNV:
2764
0
            case glslang::EOpHitObjectGetHitKindNV:
2765
0
            case glslang::EOpHitObjectGetPrimitiveIndexNV:
2766
0
            case glslang::EOpHitObjectGetGeometryIndexNV:
2767
0
            case glslang::EOpHitObjectGetInstanceIdNV:
2768
0
            case glslang::EOpHitObjectGetInstanceCustomIndexNV:
2769
0
            case glslang::EOpHitObjectGetObjectRayDirectionNV:
2770
0
            case glslang::EOpHitObjectGetObjectRayOriginNV:
2771
0
            case glslang::EOpHitObjectGetWorldRayDirectionNV:
2772
0
            case glslang::EOpHitObjectGetWorldRayOriginNV:
2773
0
            case glslang::EOpHitObjectGetWorldToObjectNV:
2774
0
            case glslang::EOpHitObjectGetObjectToWorldNV:
2775
0
            case glslang::EOpHitObjectGetRayTMaxNV:
2776
0
            case glslang::EOpHitObjectGetRayTMinNV:
2777
0
            case glslang::EOpHitObjectIsEmptyNV:
2778
0
            case glslang::EOpHitObjectIsHitNV:
2779
0
            case glslang::EOpHitObjectIsMissNV:
2780
0
            case glslang::EOpHitObjectRecordEmptyNV:
2781
0
            case glslang::EOpHitObjectGetShaderBindingTableRecordIndexNV:
2782
0
            case glslang::EOpHitObjectGetShaderRecordBufferHandleNV:
2783
0
            case glslang::EOpHitObjectGetClusterIdNV:
2784
0
            case glslang::EOpHitObjectGetSpherePositionNV:
2785
0
            case glslang::EOpHitObjectGetSphereRadiusNV:
2786
0
            case glslang::EOpHitObjectIsSphereHitNV:
2787
0
            case glslang::EOpHitObjectIsLSSHitNV:
2788
0
            case glslang::EOpReorderThreadEXT:
2789
0
            case glslang::EOpHitObjectGetCurrentTimeEXT:
2790
0
            case glslang::EOpHitObjectGetHitKindEXT:
2791
0
            case glslang::EOpHitObjectGetPrimitiveIndexEXT:
2792
0
            case glslang::EOpHitObjectGetGeometryIndexEXT:
2793
0
            case glslang::EOpHitObjectGetInstanceIdEXT:
2794
0
            case glslang::EOpHitObjectGetInstanceCustomIndexEXT:
2795
0
            case glslang::EOpHitObjectGetObjectRayDirectionEXT:
2796
0
            case glslang::EOpHitObjectGetObjectRayOriginEXT:
2797
0
            case glslang::EOpHitObjectGetWorldRayDirectionEXT:
2798
0
            case glslang::EOpHitObjectGetWorldRayOriginEXT:
2799
0
            case glslang::EOpHitObjectGetWorldToObjectEXT:
2800
0
            case glslang::EOpHitObjectGetObjectToWorldEXT:
2801
0
            case glslang::EOpHitObjectGetRayTMaxEXT:
2802
0
            case glslang::EOpHitObjectGetRayTMinEXT:
2803
0
            case glslang::EOpHitObjectGetRayFlagsEXT:
2804
0
            case glslang::EOpHitObjectIsEmptyEXT:
2805
0
            case glslang::EOpHitObjectIsHitEXT:
2806
0
            case glslang::EOpHitObjectIsMissEXT:
2807
0
            case glslang::EOpHitObjectRecordEmptyEXT:
2808
0
            case glslang::EOpHitObjectGetShaderBindingTableRecordIndexEXT:
2809
0
            case glslang::EOpHitObjectGetShaderRecordBufferHandleEXT:
2810
0
                return true;
2811
8.55k
            default:
2812
8.55k
                return false;
2813
8.55k
        }
2814
8.55k
    };
2815
2816
8.83k
    if (node->getOp() == glslang::EOpAtomicCounterIncrement ||
2817
8.83k
        node->getOp() == glslang::EOpAtomicCounterDecrement ||
2818
8.83k
        node->getOp() == glslang::EOpAtomicCounter          ||
2819
8.83k
        (node->getOp() == glslang::EOpInterpolateAtCentroid &&
2820
0
          glslangIntermediate->getSource() != glslang::EShSourceHlsl)  ||
2821
8.83k
        node->getOp() == glslang::EOpRayQueryProceed        ||
2822
8.80k
        node->getOp() == glslang::EOpRayQueryGetRayTMin     ||
2823
8.77k
        node->getOp() == glslang::EOpRayQueryGetRayFlags    ||
2824
8.73k
        node->getOp() == glslang::EOpRayQueryGetWorldRayOrigin ||
2825
8.70k
        node->getOp() == glslang::EOpRayQueryGetWorldRayDirection ||
2826
8.67k
        node->getOp() == glslang::EOpRayQueryGetIntersectionCandidateAABBOpaque ||
2827
8.64k
        node->getOp() == glslang::EOpRayQueryTerminate ||
2828
8.58k
        node->getOp() == glslang::EOpRayQueryConfirmIntersection ||
2829
8.55k
        (node->getOp() == glslang::EOpSpirvInst && operandNode->getAsTyped()->getQualifier().isSpirvByReference()) ||
2830
8.55k
        hitObjectOpsWithLvalue(node->getOp())) {
2831
279
        operand = builder.accessChainGetLValue(); // Special case l-value operands
2832
279
        lvalueCoherentFlags = builder.getAccessChain().coherentFlags;
2833
279
        lvalueCoherentFlags |= TranslateCoherent(operandNode->getAsTyped()->getType());
2834
8.55k
    } else if (operandNode->getAsTyped()->getQualifier().isSpirvLiteral()) {
2835
        // Will be translated to a literal value, make a placeholder here
2836
0
        operand = spv::NoResult;
2837
8.55k
    } else {
2838
8.55k
        operand = accessChainLoad(node->getOperand()->getType());
2839
8.55k
    }
2840
2841
8.83k
    OpDecorations decorations = { TranslatePrecisionDecoration(node->getOperationPrecision()),
2842
8.83k
                                  TranslateNoContractionDecoration(node->getType().getQualifier()),
2843
8.83k
                                  TranslateNonUniformDecoration(node->getType().getQualifier()) };
2844
2845
    // it could be a conversion
2846
8.83k
    if (! result) {
2847
8.83k
        result = createConversion(node->getOp(), decorations, resultType(), operand,
2848
8.83k
            node->getType().getBasicType(), node->getOperand()->getBasicType());
2849
8.83k
        if (result) {
2850
3.88k
            if (node->getType().isCoopMatKHR() && node->getOperand()->getAsTyped()->getType().isCoopMatKHR() &&
2851
0
                !node->getAsTyped()->getType().sameCoopMatUse(node->getOperand()->getAsTyped()->getType())) {
2852
                // Conversions that change use need CapabilityCooperativeMatrixConversionsNV
2853
0
                builder.addCapability(spv::Capability::CooperativeMatrixConversionsNV);
2854
0
                builder.addExtension(spv::E_SPV_NV_cooperative_matrix2);
2855
0
            }
2856
3.88k
        }
2857
8.83k
    }
2858
2859
    // if not, then possibly an operation
2860
8.83k
    if (! result)
2861
4.94k
        result = createUnaryOperation(node->getOp(), decorations, resultType(), operand,
2862
4.94k
            node->getOperand()->getBasicType(), lvalueCoherentFlags, node->getType());
2863
2864
    // it could be attached to a SPIR-V intruction
2865
8.83k
    if (!result) {
2866
1.92k
        if (node->getOp() == glslang::EOpSpirvInst) {
2867
0
            const auto& spirvInst = node->getSpirvInstruction();
2868
0
            if (spirvInst.set == "") {
2869
0
                spv::IdImmediate idImmOp = {true, operand};
2870
0
                if (operandNode->getAsTyped()->getQualifier().isSpirvLiteral()) {
2871
                    // Translate the constant to a literal value
2872
0
                    std::vector<unsigned> literals;
2873
0
                    glslang::TVector<const glslang::TIntermConstantUnion*> constants;
2874
0
                    constants.push_back(operandNode->getAsConstantUnion());
2875
0
                    TranslateLiterals(constants, literals);
2876
0
                    idImmOp = {false, literals[0]};
2877
0
                }
2878
2879
0
                if (node->getBasicType() == glslang::EbtVoid)
2880
0
                    builder.createNoResultOp(static_cast<spv::Op>(spirvInst.id), {idImmOp});
2881
0
                else
2882
0
                    result = builder.createOp(static_cast<spv::Op>(spirvInst.id), resultType(), {idImmOp});
2883
0
            } else {
2884
0
                result = builder.createBuiltinCall(
2885
0
                    resultType(), spirvInst.set == "GLSL.std.450" ? stdBuiltins : getExtBuiltins(spirvInst.set.c_str()),
2886
0
                    spirvInst.id, {operand});
2887
0
            }
2888
2889
0
            if (node->getBasicType() == glslang::EbtVoid)
2890
0
                return false; // done with this node
2891
0
        }
2892
1.92k
    }
2893
2894
8.83k
    if (result) {
2895
6.90k
        if (invertedType) {
2896
0
            result = createInvertedSwizzle(decorations.precision, *node->getOperand(), result);
2897
0
            decorations.addNonUniform(builder, result);
2898
0
        }
2899
2900
6.90k
        builder.clearAccessChain();
2901
6.90k
        builder.setAccessChainRValue(result);
2902
2903
6.90k
        return false; // done with this node
2904
6.90k
    }
2905
2906
    // it must be a special case, check...
2907
1.92k
    switch (node->getOp()) {
2908
749
    case glslang::EOpPostIncrement:
2909
803
    case glslang::EOpPostDecrement:
2910
1.55k
    case glslang::EOpPreIncrement:
2911
1.83k
    case glslang::EOpPreDecrement:
2912
1.83k
        {
2913
            // we need the integer value "1" or the floating point "1.0" to add/subtract
2914
1.83k
            spv::Id one = 0;
2915
1.83k
            if (node->getBasicType() == glslang::EbtFloat)
2916
351
                one = builder.makeFloatConstant(1.0F);
2917
1.47k
            else if (node->getBasicType() == glslang::EbtDouble)
2918
0
                one = builder.makeDoubleConstant(1.0);
2919
1.47k
            else if (node->getBasicType() == glslang::EbtFloat16)
2920
0
                one = builder.makeFloat16Constant(1.0F);
2921
1.47k
            else if (node->getBasicType() == glslang::EbtBFloat16)
2922
0
                one = builder.makeBFloat16Constant(1.0F);
2923
1.47k
            else if (node->getBasicType() == glslang::EbtFloatE5M2)
2924
0
                one = builder.makeFloatE5M2Constant(1.0F);
2925
1.47k
            else if (node->getBasicType() == glslang::EbtFloatE4M3)
2926
0
                one = builder.makeFloatE4M3Constant(1.0F);
2927
1.47k
            else if (node->getBasicType() == glslang::EbtInt8  || node->getBasicType() == glslang::EbtUint8)
2928
0
                one = builder.makeInt8Constant(1);
2929
1.47k
            else if (node->getBasicType() == glslang::EbtInt16 || node->getBasicType() == glslang::EbtUint16)
2930
35
                one = builder.makeInt16Constant(1);
2931
1.44k
            else if (node->getBasicType() == glslang::EbtInt64 || node->getBasicType() == glslang::EbtUint64)
2932
0
                one = builder.makeInt64Constant(1);
2933
1.44k
            else
2934
1.44k
                one = builder.makeIntConstant(1);
2935
1.83k
            glslang::TOperator op;
2936
1.83k
            if (node->getOp() == glslang::EOpPreIncrement ||
2937
1.07k
                node->getOp() == glslang::EOpPostIncrement)
2938
1.50k
                op = glslang::EOpAdd;
2939
330
            else
2940
330
                op = glslang::EOpSub;
2941
2942
1.83k
            spv::Id result = createBinaryOperation(op, decorations,
2943
1.83k
                                                   convertGlslangToSpvType(node->getType()), operand, one,
2944
1.83k
                                                   node->getType().getBasicType());
2945
1.83k
            assert(result != spv::NoResult);
2946
2947
            // The result of operation is always stored, but conditionally the
2948
            // consumed result.  The consumed result is always an r-value.
2949
1.83k
            builder.accessChainStore(result,
2950
1.83k
                                     TranslateNonUniformDecoration(builder.getAccessChain().coherentFlags));
2951
1.83k
            builder.clearAccessChain();
2952
1.83k
            if (node->getOp() == glslang::EOpPreIncrement ||
2953
1.07k
                node->getOp() == glslang::EOpPreDecrement)
2954
1.02k
                builder.setAccessChainRValue(result);
2955
803
            else
2956
803
                builder.setAccessChainRValue(operand);
2957
1.83k
        }
2958
2959
1.83k
        return false;
2960
2961
0
    case glslang::EOpAssumeEXT:
2962
0
        builder.addCapability(spv::Capability::ExpectAssumeKHR);
2963
0
        builder.addExtension(spv::E_SPV_KHR_expect_assume);
2964
0
        builder.createNoResultOp(spv::Op::OpAssumeTrueKHR, operand);
2965
0
        return false;
2966
0
    case glslang::EOpEmitStreamVertex:
2967
0
        builder.createNoResultOp(spv::Op::OpEmitStreamVertex, operand);
2968
0
        return false;
2969
0
    case glslang::EOpEndStreamPrimitive:
2970
0
        builder.createNoResultOp(spv::Op::OpEndStreamPrimitive, operand);
2971
0
        return false;
2972
62
    case glslang::EOpRayQueryTerminate:
2973
62
        builder.createNoResultOp(spv::Op::OpRayQueryTerminateKHR, operand);
2974
62
        return false;
2975
31
    case glslang::EOpRayQueryConfirmIntersection:
2976
31
        builder.createNoResultOp(spv::Op::OpRayQueryConfirmIntersectionKHR, operand);
2977
31
        return false;
2978
0
    case glslang::EOpReorderThreadNV:
2979
0
        builder.createNoResultOp(spv::Op::OpReorderThreadWithHitObjectNV, operand);
2980
0
        return false;
2981
0
    case glslang::EOpReorderThreadEXT:
2982
0
        builder.createNoResultOp(spv::Op::OpReorderThreadWithHitObjectEXT, operand);
2983
0
        return false;
2984
0
    case glslang::EOpHitObjectRecordEmptyNV:
2985
0
        builder.createNoResultOp(spv::Op::OpHitObjectRecordEmptyNV, operand);
2986
0
        return false;
2987
0
    case glslang::EOpHitObjectRecordEmptyEXT:
2988
0
        builder.createNoResultOp(spv::Op::OpHitObjectRecordEmptyEXT, operand);
2989
0
        return false;
2990
2991
0
    case glslang::EOpCreateTensorLayoutNV:
2992
0
        result = builder.createOp(spv::Op::OpCreateTensorLayoutNV, resultType(), std::vector<spv::Id>{});
2993
0
        builder.clearAccessChain();
2994
0
        builder.setAccessChainRValue(result);
2995
0
        return false;
2996
2997
0
    case glslang::EOpCreateTensorViewNV:
2998
0
        result = builder.createOp(spv::Op::OpCreateTensorViewNV, resultType(), std::vector<spv::Id>{});
2999
0
        builder.clearAccessChain();
3000
0
        builder.setAccessChainRValue(result);
3001
0
        return false;
3002
3003
0
    default:
3004
0
        logger->missingFunctionality("unknown glslang unary");
3005
0
        return true;  // pick up operand as placeholder result
3006
1.92k
    }
3007
1.92k
}
3008
3009
// Construct a composite object, recursively copying members if their types don't match
3010
spv::Id TGlslangToSpvTraverser::createCompositeConstruct(spv::Id resultTypeId, std::vector<spv::Id> constituents)
3011
87
{
3012
376
    for (int c = 0; c < (int)constituents.size(); ++c) {
3013
289
        spv::Id& constituent = constituents[c];
3014
289
        spv::Id lType = builder.getContainedTypeId(resultTypeId, c);
3015
289
        spv::Id rType = builder.getTypeId(constituent);
3016
289
        if (lType != rType) {
3017
0
            if (glslangIntermediate->getSpv().spv >= glslang::EShTargetSpv_1_4) {
3018
0
                constituent = builder.createUnaryOp(spv::Op::OpCopyLogical, lType, constituent);
3019
0
            } else if (builder.isStructType(rType)) {
3020
0
                std::vector<spv::Id> rTypeConstituents;
3021
0
                int numrTypeConstituents = builder.getNumTypeConstituents(rType);
3022
0
                for (int i = 0; i < numrTypeConstituents; ++i) {
3023
0
                    rTypeConstituents.push_back(builder.createCompositeExtract(constituent,
3024
0
                        builder.getContainedTypeId(rType, i), i));
3025
0
                }
3026
0
                constituents[c] = createCompositeConstruct(lType, rTypeConstituents);
3027
0
            } else {
3028
0
                assert(builder.isArrayType(rType));
3029
0
                std::vector<spv::Id> rTypeConstituents;
3030
0
                int numrTypeConstituents = builder.getNumTypeConstituents(rType);
3031
3032
0
                spv::Id elementRType = builder.getContainedTypeId(rType);
3033
0
                for (int i = 0; i < numrTypeConstituents; ++i) {
3034
0
                    rTypeConstituents.push_back(builder.createCompositeExtract(constituent, elementRType, i));
3035
0
                }
3036
0
                constituents[c] = createCompositeConstruct(lType, rTypeConstituents);
3037
0
            }
3038
0
        }
3039
289
    }
3040
87
    return builder.createCompositeConstruct(resultTypeId, constituents);
3041
87
}
3042
3043
bool TGlslangToSpvTraverser::visitAggregate(glslang::TVisit visit, glslang::TIntermAggregate* node)
3044
63.3k
{
3045
63.3k
    SpecConstantOpModeGuard spec_constant_op_mode_setter(&builder);
3046
63.3k
    if (node->getType().getQualifier().isSpecConstant())
3047
11
        spec_constant_op_mode_setter.turnOnSpecConstantOpMode();
3048
3049
63.3k
    spv::Id result = spv::NoResult;
3050
63.3k
    spv::Id invertedType = spv::NoType;                     // to use to override the natural type of the node
3051
63.3k
    std::vector<spv::Builder::AccessChain> complexLvalues;  // for holding swizzling l-values too complex for
3052
                                                            // SPIR-V, for an out parameter
3053
63.3k
    std::vector<spv::Id> temporaryLvalues;                  // temporaries to pass, as proxies for complexLValues
3054
3055
63.3k
    auto resultType = [&invertedType, &node, this](){
3056
7.57k
        if (invertedType != spv::NoType) {
3057
0
            return invertedType;
3058
7.57k
        } else {
3059
7.57k
            auto ret = convertGlslangToSpvType(node->getType());
3060
            // convertGlslangToSpvType may clobber the debug location, reset it
3061
7.57k
            builder.setDebugSourceLocation(node->getLoc().line, node->getLoc().getFilename());
3062
7.57k
            return ret;
3063
7.57k
        }
3064
7.57k
    };
3065
3066
    // try texturing
3067
63.3k
    result = createImageTextureFunctionCall(node);
3068
63.3k
    if (result != spv::NoResult) {
3069
4.66k
        builder.clearAccessChain();
3070
4.66k
        builder.setAccessChainRValue(result);
3071
3072
4.66k
        return false;
3073
58.6k
    } else if (node->getOp() == glslang::EOpImageStore ||
3074
58.5k
        node->getOp() == glslang::EOpImageStoreLod ||
3075
58.4k
        node->getOp() == glslang::EOpImageAtomicStore) {
3076
        // "imageStore" is a special case, which has no result
3077
217
        return false;
3078
217
    }
3079
3080
58.4k
    glslang::TOperator binOp = glslang::EOpNull;
3081
58.4k
    bool reduceComparison = true;
3082
58.4k
    bool isMatrix = false;
3083
58.4k
    bool noReturnValue = false;
3084
58.4k
    bool atomic = false;
3085
3086
58.4k
    spv::Builder::AccessChain::CoherentFlags lvalueCoherentFlags;
3087
3088
58.4k
    assert(node->getOp());
3089
3090
58.4k
    spv::Decoration precision = TranslatePrecisionDecoration(node->getOperationPrecision());
3091
3092
58.4k
    switch (node->getOp()) {
3093
0
    case glslang::EOpScope:
3094
34.4k
    case glslang::EOpSequence:
3095
34.4k
    {
3096
34.4k
        if (visit == glslang::EvPreVisit) {
3097
18.2k
            ++sequenceDepth;
3098
18.2k
            if (sequenceDepth == 1) {
3099
                // If this is the parent node of all the functions, we want to see them
3100
                // early, so all call points have actual SPIR-V functions to reference.
3101
                // In all cases, still let the traverser visit the children for us.
3102
2.08k
                makeFunctions(node->getAsAggregate()->getSequence());
3103
3104
                // Global initializers is specific to the shader entry point, which does not exist in compile-only mode
3105
2.08k
                if (!options.compileOnly) {
3106
                    // Also, we want all globals initializers to go into the beginning of the entry point, before
3107
                    // anything else gets there, so visit out of order, doing them all now.
3108
2.08k
                    makeGlobalInitializers(node->getAsAggregate()->getSequence());
3109
2.08k
                }
3110
3111
                //Pre process linker objects for ray tracing stages
3112
2.08k
                if (glslangIntermediate->isRayTracingStage())
3113
46
                  collectRayTracingLinkerObjects();
3114
3115
                // Initializers are done, don't want to visit again, but functions and link objects need to be processed,
3116
                // so do them manually.
3117
2.08k
                visitFunctions(node->getAsAggregate()->getSequence());
3118
3119
2.08k
                return false;
3120
16.1k
            } else {
3121
16.1k
                if (node->getOp() == glslang::EOpScope) {
3122
0
                    auto loc = node->getLoc();
3123
0
                    builder.enterLexicalBlock(loc.line, loc.column);
3124
0
                }
3125
16.1k
            }
3126
18.2k
        } else {
3127
16.1k
            if (sequenceDepth > 1 && node->getOp() == glslang::EOpScope)
3128
0
                builder.leaveLexicalBlock();
3129
16.1k
            --sequenceDepth;
3130
16.1k
        }
3131
3132
32.3k
        return true;
3133
34.4k
    }
3134
4.17k
    case glslang::EOpLinkerObjects:
3135
4.17k
    {
3136
4.17k
        if (visit == glslang::EvPreVisit)
3137
2.08k
            linkageOnly = true;
3138
2.08k
        else
3139
2.08k
            linkageOnly = false;
3140
3141
4.17k
        return true;
3142
34.4k
    }
3143
252
    case glslang::EOpComma:
3144
252
    {
3145
        // processing from left to right naturally leaves the right-most
3146
        // lying around in the access chain
3147
252
        glslang::TIntermSequence& glslangOperands = node->getSequence();
3148
756
        for (int i = 0; i < (int)glslangOperands.size(); ++i)
3149
504
            glslangOperands[i]->traverse(this);
3150
3151
252
        return false;
3152
34.4k
    }
3153
6.48k
    case glslang::EOpFunction:
3154
6.48k
        if (visit == glslang::EvPreVisit) {
3155
3.24k
            if (options.generateDebugInfo) {
3156
0
                builder.setDebugSourceLocation(node->getLoc().line, node->getLoc().getFilename());
3157
0
            }
3158
3.24k
            if (isShaderEntryPoint(node)) {
3159
2.02k
                inEntryPoint = true;
3160
2.02k
                builder.setBuildPoint(shaderEntry->getLastBlock());
3161
2.02k
                builder.enterFunction(shaderEntry);
3162
2.02k
                currentFunction = shaderEntry;
3163
2.02k
            } else {
3164
                // SPIR-V functions should already be in the functionMap from the prepass
3165
                // that called makeFunctions().
3166
1.21k
                currentFunction = functionMap[node->getName().c_str()];
3167
1.21k
                spv::Block* functionBlock = currentFunction->getEntryBlock();
3168
1.21k
                builder.setBuildPoint(functionBlock);
3169
1.21k
                builder.enterFunction(currentFunction);
3170
1.21k
            }
3171
3.24k
            if (options.generateDebugInfo && !options.emitNonSemanticShaderDebugInfo) {
3172
0
                const auto& loc = node->getLoc();
3173
0
                const char* sourceFileName = loc.getFilename();
3174
0
                spv::Id sourceFileId = sourceFileName ? builder.getStringId(sourceFileName) : builder.getMainFileId();
3175
0
                currentFunction->setDebugLineInfo(sourceFileId, loc.line, loc.column);
3176
0
            }
3177
3.24k
        } else {
3178
            // Here we have finished visiting the function (post-visit). Finalize it.
3179
3.24k
            if (options.generateDebugInfo) {
3180
0
                if (glslangIntermediate->getSource() == glslang::EShSourceGlsl && node->getSequence().size() > 1) {
3181
0
                    auto endLoc = node->getSequence()[1]->getAsAggregate()->getEndLoc();
3182
0
                    builder.setDebugSourceLocation(endLoc.line, endLoc.getFilename());
3183
0
                }
3184
0
            }
3185
3.24k
            if (inEntryPoint)
3186
2.02k
                entryPointTerminated = true;
3187
3.24k
            builder.leaveFunction();
3188
3.24k
            inEntryPoint = false;
3189
3.24k
            currentFunction = nullptr;
3190
3.24k
        }
3191
3192
6.48k
        return true;
3193
3.24k
    case glslang::EOpParameters:
3194
        // Parameters will have been consumed by EOpFunction processing, but not
3195
        // the body, so we still visited the function node's children, making this
3196
        // child redundant.
3197
3.24k
        return false;
3198
2.27k
    case glslang::EOpFunctionCall:
3199
2.27k
    {
3200
2.27k
        builder.setDebugSourceLocation(node->getLoc().line, node->getLoc().getFilename());
3201
2.27k
        if (node->isUserDefined())
3202
2.27k
            result = handleUserFunctionCall(node);
3203
2.27k
        if (result) {
3204
2.27k
            builder.clearAccessChain();
3205
2.27k
            builder.setAccessChainRValue(result);
3206
2.27k
        } else
3207
0
            logger->missingFunctionality("missing user function; linker needs to catch that");
3208
3209
2.27k
        return false;
3210
34.4k
    }
3211
2
    case glslang::EOpConstructMat2x2:
3212
2
    case glslang::EOpConstructMat2x3:
3213
2
    case glslang::EOpConstructMat2x4:
3214
2
    case glslang::EOpConstructMat3x2:
3215
2
    case glslang::EOpConstructMat3x3:
3216
6
    case glslang::EOpConstructMat3x4:
3217
6
    case glslang::EOpConstructMat4x2:
3218
6
    case glslang::EOpConstructMat4x3:
3219
8
    case glslang::EOpConstructMat4x4:
3220
8
    case glslang::EOpConstructDMat2x2:
3221
8
    case glslang::EOpConstructDMat2x3:
3222
8
    case glslang::EOpConstructDMat2x4:
3223
8
    case glslang::EOpConstructDMat3x2:
3224
8
    case glslang::EOpConstructDMat3x3:
3225
8
    case glslang::EOpConstructDMat3x4:
3226
8
    case glslang::EOpConstructDMat4x2:
3227
8
    case glslang::EOpConstructDMat4x3:
3228
8
    case glslang::EOpConstructDMat4x4:
3229
8
    case glslang::EOpConstructIMat2x2:
3230
8
    case glslang::EOpConstructIMat2x3:
3231
8
    case glslang::EOpConstructIMat2x4:
3232
8
    case glslang::EOpConstructIMat3x2:
3233
8
    case glslang::EOpConstructIMat3x3:
3234
8
    case glslang::EOpConstructIMat3x4:
3235
8
    case glslang::EOpConstructIMat4x2:
3236
8
    case glslang::EOpConstructIMat4x3:
3237
8
    case glslang::EOpConstructIMat4x4:
3238
8
    case glslang::EOpConstructUMat2x2:
3239
8
    case glslang::EOpConstructUMat2x3:
3240
8
    case glslang::EOpConstructUMat2x4:
3241
8
    case glslang::EOpConstructUMat3x2:
3242
8
    case glslang::EOpConstructUMat3x3:
3243
8
    case glslang::EOpConstructUMat3x4:
3244
8
    case glslang::EOpConstructUMat4x2:
3245
8
    case glslang::EOpConstructUMat4x3:
3246
8
    case glslang::EOpConstructUMat4x4:
3247
8
    case glslang::EOpConstructBMat2x2:
3248
8
    case glslang::EOpConstructBMat2x3:
3249
8
    case glslang::EOpConstructBMat2x4:
3250
8
    case glslang::EOpConstructBMat3x2:
3251
8
    case glslang::EOpConstructBMat3x3:
3252
8
    case glslang::EOpConstructBMat3x4:
3253
8
    case glslang::EOpConstructBMat4x2:
3254
8
    case glslang::EOpConstructBMat4x3:
3255
8
    case glslang::EOpConstructBMat4x4:
3256
8
    case glslang::EOpConstructF16Mat2x2:
3257
8
    case glslang::EOpConstructF16Mat2x3:
3258
8
    case glslang::EOpConstructF16Mat2x4:
3259
8
    case glslang::EOpConstructF16Mat3x2:
3260
8
    case glslang::EOpConstructF16Mat3x3:
3261
8
    case glslang::EOpConstructF16Mat3x4:
3262
8
    case glslang::EOpConstructF16Mat4x2:
3263
8
    case glslang::EOpConstructF16Mat4x3:
3264
8
    case glslang::EOpConstructF16Mat4x4:
3265
8
        isMatrix = true;
3266
8
        [[fallthrough]];
3267
65
    case glslang::EOpConstructFloat:
3268
256
    case glslang::EOpConstructVec2:
3269
1.01k
    case glslang::EOpConstructVec3:
3270
1.55k
    case glslang::EOpConstructVec4:
3271
1.55k
    case glslang::EOpConstructDouble:
3272
1.55k
    case glslang::EOpConstructDVec2:
3273
1.55k
    case glslang::EOpConstructDVec3:
3274
1.55k
    case glslang::EOpConstructDVec4:
3275
1.56k
    case glslang::EOpConstructFloat16:
3276
1.56k
    case glslang::EOpConstructF16Vec2:
3277
1.56k
    case glslang::EOpConstructF16Vec3:
3278
1.56k
    case glslang::EOpConstructF16Vec4:
3279
1.56k
    case glslang::EOpConstructBFloat16:
3280
1.56k
    case glslang::EOpConstructBF16Vec2:
3281
1.56k
    case glslang::EOpConstructBF16Vec3:
3282
1.56k
    case glslang::EOpConstructBF16Vec4:
3283
1.56k
    case glslang::EOpConstructFloatE5M2:
3284
1.56k
    case glslang::EOpConstructFloatE5M2Vec2:
3285
1.56k
    case glslang::EOpConstructFloatE5M2Vec3:
3286
1.56k
    case glslang::EOpConstructFloatE5M2Vec4:
3287
1.56k
    case glslang::EOpConstructFloatE4M3:
3288
1.56k
    case glslang::EOpConstructFloatE4M3Vec2:
3289
1.56k
    case glslang::EOpConstructFloatE4M3Vec3:
3290
1.56k
    case glslang::EOpConstructFloatE4M3Vec4:
3291
1.56k
    case glslang::EOpConstructBool:
3292
1.58k
    case glslang::EOpConstructBVec2:
3293
1.58k
    case glslang::EOpConstructBVec3:
3294
1.58k
    case glslang::EOpConstructBVec4:
3295
1.58k
    case glslang::EOpConstructInt8:
3296
1.58k
    case glslang::EOpConstructI8Vec2:
3297
1.59k
    case glslang::EOpConstructI8Vec3:
3298
1.59k
    case glslang::EOpConstructI8Vec4:
3299
1.59k
    case glslang::EOpConstructUint8:
3300
1.59k
    case glslang::EOpConstructU8Vec2:
3301
1.59k
    case glslang::EOpConstructU8Vec3:
3302
1.59k
    case glslang::EOpConstructU8Vec4:
3303
1.59k
    case glslang::EOpConstructInt16:
3304
1.67k
    case glslang::EOpConstructI16Vec2:
3305
1.67k
    case glslang::EOpConstructI16Vec3:
3306
1.68k
    case glslang::EOpConstructI16Vec4:
3307
1.68k
    case glslang::EOpConstructUint16:
3308
1.68k
    case glslang::EOpConstructU16Vec2:
3309
1.75k
    case glslang::EOpConstructU16Vec3:
3310
1.76k
    case glslang::EOpConstructU16Vec4:
3311
1.76k
    case glslang::EOpConstructInt:
3312
1.79k
    case glslang::EOpConstructIVec2:
3313
1.79k
    case glslang::EOpConstructIVec3:
3314
1.80k
    case glslang::EOpConstructIVec4:
3315
1.81k
    case glslang::EOpConstructUint:
3316
1.81k
    case glslang::EOpConstructUVec2:
3317
1.81k
    case glslang::EOpConstructUVec3:
3318
1.86k
    case glslang::EOpConstructUVec4:
3319
1.86k
    case glslang::EOpConstructInt64:
3320
1.86k
    case glslang::EOpConstructI64Vec2:
3321
1.86k
    case glslang::EOpConstructI64Vec3:
3322
1.86k
    case glslang::EOpConstructI64Vec4:
3323
1.86k
    case glslang::EOpConstructUint64:
3324
1.86k
    case glslang::EOpConstructU64Vec2:
3325
1.86k
    case glslang::EOpConstructU64Vec3:
3326
1.86k
    case glslang::EOpConstructU64Vec4:
3327
1.87k
    case glslang::EOpConstructStruct:
3328
2.22k
    case glslang::EOpConstructTextureSampler:
3329
2.24k
    case glslang::EOpConstructReference:
3330
2.24k
    case glslang::EOpConstructCooperativeMatrixNV:
3331
2.24k
    case glslang::EOpConstructCooperativeMatrixKHR:
3332
2.24k
    case glslang::EOpConstructCooperativeVectorNV:
3333
2.24k
    case glslang::EOpConstructSaturated:
3334
2.24k
    {
3335
2.24k
        builder.setDebugSourceLocation(node->getLoc().line, node->getLoc().getFilename());
3336
2.24k
        std::vector<spv::Id> arguments;
3337
2.24k
        translateArguments(*node, arguments, lvalueCoherentFlags);
3338
2.24k
        spv::Id constructed;
3339
2.24k
        if (node->getOp() == glslang::EOpConstructTextureSampler) {
3340
351
            const glslang::TType& texType = node->getSequence()[0]->getAsTyped()->getType();
3341
351
            if (glslangIntermediate->getSpv().spv >= glslang::EShTargetSpv_1_6 &&
3342
0
                texType.getSampler().isBuffer()) {
3343
                // SamplerBuffer is not supported in spirv1.6 so
3344
                // `samplerBuffer(textureBuffer, sampler)` is a no-op
3345
                // and textureBuffer is the result going forward
3346
0
                constructed = arguments[0];
3347
0
            } else
3348
351
                constructed = builder.createOp(spv::Op::OpSampledImage, resultType(), arguments);
3349
1.89k
        } else if (node->getOp() == glslang::EOpConstructCooperativeMatrixKHR &&
3350
0
                   node->getType().isCoopMatKHR() && node->getSequence()[0]->getAsTyped()->getType().isCoopMatKHR()) {
3351
0
            builder.addCapability(spv::Capability::CooperativeMatrixConversionsNV);
3352
0
            builder.addExtension(spv::E_SPV_NV_cooperative_matrix2);
3353
0
            constructed = builder.createCooperativeMatrixConversion(resultType(), arguments[0]);
3354
1.89k
        } else if (node->getOp() == glslang::EOpConstructCooperativeVectorNV &&
3355
0
                   arguments.size() == 1 &&
3356
0
                   builder.getTypeId(arguments[0]) == resultType()) {
3357
0
            constructed = arguments[0];
3358
1.89k
        } else if (node->getOp() == glslang::EOpConstructStruct ||
3359
1.88k
                 node->getOp() == glslang::EOpConstructCooperativeMatrixNV ||
3360
1.88k
                 node->getOp() == glslang::EOpConstructCooperativeMatrixKHR ||
3361
1.88k
                 node->getType().isArray() ||
3362
                 // Handle constructing coopvec from one component here, to avoid the component
3363
                 // getting smeared
3364
1.80k
                 (node->getOp() == glslang::EOpConstructCooperativeVectorNV && arguments.size() == 1 && builder.isScalar(arguments[0]))) {
3365
87
            std::vector<spv::Id> constituents;
3366
376
            for (int c = 0; c < (int)arguments.size(); ++c)
3367
289
                constituents.push_back(arguments[c]);
3368
87
            constructed = createCompositeConstruct(resultType(), constituents);
3369
1.80k
        } else if (isMatrix)
3370
8
            constructed = builder.createMatrixConstructor(precision, arguments, resultType());
3371
1.79k
        else if (node->getOp() == glslang::EOpConstructSaturated) {
3372
0
            OpDecorations decorations = { TranslatePrecisionDecoration(node->getOperationPrecision()),
3373
0
                                          TranslateNoContractionDecoration(node->getType().getQualifier()),
3374
0
                                          TranslateNonUniformDecoration(lvalueCoherentFlags) };
3375
3376
0
            constructed = createConversion(node->getOp(), decorations, resultType(), arguments[1],
3377
0
                                           node->getType().getBasicType(), node->getSequence()[1]->getAsTyped()->getBasicType());
3378
0
            builder.addDecoration(constructed, spv::Decoration::SaturatedToLargestFloat8NormalConversionEXT);
3379
0
            builder.createStore(constructed, arguments[0]);
3380
0
        }
3381
1.79k
        else
3382
1.79k
            constructed = builder.createConstructor(precision, arguments, resultType());
3383
3384
2.24k
        if (node->getType().getQualifier().isNonUniform()) {
3385
0
            builder.addDecoration(constructed, spv::Decoration::NonUniformEXT);
3386
0
        }
3387
3388
2.24k
        builder.clearAccessChain();
3389
2.24k
        builder.setAccessChainRValue(constructed);
3390
3391
2.24k
        return false;
3392
2.24k
    }
3393
3394
    // These six are component-wise compares with component-wise results.
3395
    // Forward on to createBinaryOperation(), requesting a vector result.
3396
18
    case glslang::EOpLessThan:
3397
36
    case glslang::EOpGreaterThan:
3398
53
    case glslang::EOpLessThanEqual:
3399
71
    case glslang::EOpGreaterThanEqual:
3400
89
    case glslang::EOpVectorEqual:
3401
99
    case glslang::EOpVectorNotEqual:
3402
99
    {
3403
        // Map the operation to a binary
3404
99
        binOp = node->getOp();
3405
99
        reduceComparison = false;
3406
99
        switch (node->getOp()) {
3407
18
        case glslang::EOpVectorEqual:     binOp = glslang::EOpVectorEqual;      break;
3408
10
        case glslang::EOpVectorNotEqual:  binOp = glslang::EOpVectorNotEqual;   break;
3409
71
        default:                          binOp = node->getOp();                break;
3410
99
        }
3411
3412
99
        break;
3413
99
    }
3414
99
    case glslang::EOpMul:
3415
        // component-wise matrix multiply
3416
6
        binOp = glslang::EOpMul;
3417
6
        break;
3418
2
    case glslang::EOpOuterProduct:
3419
        // two vectors multiplied to make a matrix
3420
2
        binOp = glslang::EOpOuterProduct;
3421
2
        break;
3422
1.47k
    case glslang::EOpDot:
3423
1.47k
    {
3424
        // for scalar dot product, use multiply
3425
1.47k
        glslang::TIntermSequence& glslangOperands = node->getSequence();
3426
1.47k
        if (glslangOperands[0]->getAsTyped()->getVectorSize() == 1)
3427
0
            binOp = glslang::EOpMul;
3428
1.47k
        break;
3429
99
    }
3430
0
    case glslang::EOpMod:
3431
        // when an aggregate, this is the floating-point mod built-in function,
3432
        // which can be emitted by the one in createBinaryOperation()
3433
0
        binOp = glslang::EOpMod;
3434
0
        break;
3435
3436
0
    case glslang::EOpEmitVertex:
3437
0
    case glslang::EOpEndPrimitive:
3438
0
    case glslang::EOpBarrier:
3439
0
    case glslang::EOpMemoryBarrier:
3440
0
    case glslang::EOpMemoryBarrierAtomicCounter:
3441
0
    case glslang::EOpMemoryBarrierBuffer:
3442
0
    case glslang::EOpMemoryBarrierImage:
3443
0
    case glslang::EOpMemoryBarrierShared:
3444
0
    case glslang::EOpGroupMemoryBarrier:
3445
0
    case glslang::EOpDeviceMemoryBarrier:
3446
0
    case glslang::EOpAllMemoryBarrierWithGroupSync:
3447
0
    case glslang::EOpDeviceMemoryBarrierWithGroupSync:
3448
0
    case glslang::EOpWorkgroupMemoryBarrier:
3449
0
    case glslang::EOpWorkgroupMemoryBarrierWithGroupSync:
3450
0
    case glslang::EOpSubgroupBarrier:
3451
0
    case glslang::EOpSubgroupMemoryBarrier:
3452
0
    case glslang::EOpSubgroupMemoryBarrierBuffer:
3453
0
    case glslang::EOpSubgroupMemoryBarrierImage:
3454
0
    case glslang::EOpSubgroupMemoryBarrierShared:
3455
0
        noReturnValue = true;
3456
        // These all have 0 operands and will naturally finish up in the code below for 0 operands
3457
0
        break;
3458
3459
132
    case glslang::EOpAtomicAdd:
3460
132
    case glslang::EOpAtomicSubtract:
3461
184
    case glslang::EOpAtomicMin:
3462
234
    case glslang::EOpAtomicMax:
3463
236
    case glslang::EOpAtomicAnd:
3464
238
    case glslang::EOpAtomicOr:
3465
242
    case glslang::EOpAtomicXor:
3466
292
    case glslang::EOpAtomicExchange:
3467
294
    case glslang::EOpAtomicCompSwap:
3468
294
        atomic = true;
3469
294
        break;
3470
3471
0
    case glslang::EOpAtomicStore:
3472
0
        noReturnValue = true;
3473
0
        [[fallthrough]];
3474
0
    case glslang::EOpAtomicLoad:
3475
0
        atomic = true;
3476
0
        break;
3477
3478
0
    case glslang::EOpAtomicCounterAdd:
3479
0
    case glslang::EOpAtomicCounterSubtract:
3480
0
    case glslang::EOpAtomicCounterMin:
3481
0
    case glslang::EOpAtomicCounterMax:
3482
0
    case glslang::EOpAtomicCounterAnd:
3483
0
    case glslang::EOpAtomicCounterOr:
3484
0
    case glslang::EOpAtomicCounterXor:
3485
0
    case glslang::EOpAtomicCounterExchange:
3486
0
    case glslang::EOpAtomicCounterCompSwap:
3487
0
        builder.addExtension("SPV_KHR_shader_atomic_counter_ops");
3488
0
        builder.addCapability(spv::Capability::AtomicStorageOps);
3489
0
        atomic = true;
3490
0
        break;
3491
3492
0
    case glslang::EOpAbsDifference:
3493
0
    case glslang::EOpAddSaturate:
3494
0
    case glslang::EOpSubSaturate:
3495
0
    case glslang::EOpAverage:
3496
0
    case glslang::EOpAverageRounded:
3497
0
    case glslang::EOpMul32x16:
3498
0
        builder.addCapability(spv::Capability::IntegerFunctions2INTEL);
3499
0
        builder.addExtension("SPV_INTEL_shader_integer_functions2");
3500
0
        binOp = node->getOp();
3501
0
        break;
3502
3503
0
    case glslang::EOpExpectEXT:
3504
0
        builder.addCapability(spv::Capability::ExpectAssumeKHR);
3505
0
        builder.addExtension(spv::E_SPV_KHR_expect_assume);
3506
0
        binOp = node->getOp();
3507
0
        break;
3508
3509
0
    case glslang::EOpIgnoreIntersectionNV:
3510
0
    case glslang::EOpTerminateRayNV:
3511
0
    case glslang::EOpTraceNV:
3512
0
    case glslang::EOpTraceRayMotionNV:
3513
0
    case glslang::EOpTraceKHR:
3514
0
    case glslang::EOpExecuteCallableNV:
3515
0
    case glslang::EOpExecuteCallableKHR:
3516
0
    case glslang::EOpWritePackedPrimitiveIndices4x8NV:
3517
0
    case glslang::EOpEmitMeshTasksEXT:
3518
0
    case glslang::EOpSetMeshOutputsEXT:
3519
0
        noReturnValue = true;
3520
0
        break;
3521
31
    case glslang::EOpRayQueryInitialize:
3522
31
    case glslang::EOpRayQueryTerminate:
3523
62
    case glslang::EOpRayQueryGenerateIntersection:
3524
62
    case glslang::EOpRayQueryConfirmIntersection:
3525
62
        builder.addExtension("SPV_KHR_ray_query");
3526
62
        builder.addCapability(spv::Capability::RayQueryKHR);
3527
62
        noReturnValue = true;
3528
62
        break;
3529
0
    case glslang::EOpRayQueryProceed:
3530
62
    case glslang::EOpRayQueryGetIntersectionType:
3531
62
    case glslang::EOpRayQueryGetRayTMin:
3532
62
    case glslang::EOpRayQueryGetRayFlags:
3533
124
    case glslang::EOpRayQueryGetIntersectionT:
3534
186
    case glslang::EOpRayQueryGetIntersectionInstanceCustomIndex:
3535
248
    case glslang::EOpRayQueryGetIntersectionInstanceId:
3536
279
    case glslang::EOpRayQueryGetIntersectionInstanceShaderBindingTableRecordOffset:
3537
310
    case glslang::EOpRayQueryGetIntersectionGeometryIndex:
3538
372
    case glslang::EOpRayQueryGetIntersectionPrimitiveIndex:
3539
434
    case glslang::EOpRayQueryGetIntersectionBarycentrics:
3540
496
    case glslang::EOpRayQueryGetIntersectionFrontFace:
3541
496
    case glslang::EOpRayQueryGetIntersectionCandidateAABBOpaque:
3542
558
    case glslang::EOpRayQueryGetIntersectionObjectRayDirection:
3543
620
    case glslang::EOpRayQueryGetIntersectionObjectRayOrigin:
3544
620
    case glslang::EOpRayQueryGetWorldRayDirection:
3545
620
    case glslang::EOpRayQueryGetWorldRayOrigin:
3546
682
    case glslang::EOpRayQueryGetIntersectionObjectToWorld:
3547
744
    case glslang::EOpRayQueryGetIntersectionWorldToObject:
3548
744
        builder.addExtension("SPV_KHR_ray_query");
3549
744
        builder.addCapability(spv::Capability::RayQueryKHR);
3550
744
        break;
3551
0
    case glslang::EOpCooperativeMatrixLoad:
3552
0
    case glslang::EOpCooperativeMatrixStore:
3553
0
    case glslang::EOpCooperativeMatrixLoadNV:
3554
0
    case glslang::EOpCooperativeMatrixStoreNV:
3555
0
    case glslang::EOpCooperativeMatrixLoadTensorNV:
3556
0
    case glslang::EOpCooperativeMatrixStoreTensorNV:
3557
0
    case glslang::EOpCooperativeMatrixReduceNV:
3558
0
    case glslang::EOpCooperativeMatrixPerElementOpNV:
3559
0
    case glslang::EOpCooperativeMatrixTransposeNV:
3560
0
    case glslang::EOpCooperativeVectorMatMulNV:
3561
0
    case glslang::EOpCooperativeVectorMatMulAddNV:
3562
0
    case glslang::EOpCooperativeVectorLoadNV:
3563
0
    case glslang::EOpCooperativeVectorStoreNV:
3564
0
    case glslang::EOpCooperativeVectorOuterProductAccumulateNV:
3565
0
    case glslang::EOpCooperativeVectorReduceSumAccumulateNV:
3566
0
        noReturnValue = true;
3567
0
        break;
3568
1
    case glslang::EOpBeginInvocationInterlock:
3569
2
    case glslang::EOpEndInvocationInterlock:
3570
2
        builder.addExtension(spv::E_SPV_EXT_fragment_shader_interlock);
3571
2
        noReturnValue = true;
3572
2
        break;
3573
3574
0
    case glslang::EOpHitObjectTraceRayNV:
3575
0
    case glslang::EOpHitObjectTraceRayMotionNV:
3576
0
    case glslang::EOpHitObjectGetAttributesNV:
3577
0
    case glslang::EOpHitObjectExecuteShaderNV:
3578
0
    case glslang::EOpHitObjectRecordEmptyNV:
3579
0
    case glslang::EOpHitObjectRecordMissNV:
3580
0
    case glslang::EOpHitObjectRecordMissMotionNV:
3581
0
    case glslang::EOpHitObjectRecordHitNV:
3582
0
    case glslang::EOpHitObjectRecordHitMotionNV:
3583
0
    case glslang::EOpHitObjectRecordHitWithIndexNV:
3584
0
    case glslang::EOpHitObjectRecordHitWithIndexMotionNV:
3585
0
    case glslang::EOpReorderThreadNV:
3586
0
        noReturnValue = true;
3587
0
        [[fallthrough]];
3588
0
    case glslang::EOpHitObjectIsEmptyNV:
3589
0
    case glslang::EOpHitObjectIsMissNV:
3590
0
    case glslang::EOpHitObjectIsHitNV:
3591
0
    case glslang::EOpHitObjectGetRayTMinNV:
3592
0
    case glslang::EOpHitObjectGetRayTMaxNV:
3593
0
    case glslang::EOpHitObjectGetObjectRayOriginNV:
3594
0
    case glslang::EOpHitObjectGetObjectRayDirectionNV:
3595
0
    case glslang::EOpHitObjectGetWorldRayOriginNV:
3596
0
    case glslang::EOpHitObjectGetWorldRayDirectionNV:
3597
0
    case glslang::EOpHitObjectGetObjectToWorldNV:
3598
0
    case glslang::EOpHitObjectGetWorldToObjectNV:
3599
0
    case glslang::EOpHitObjectGetInstanceCustomIndexNV:
3600
0
    case glslang::EOpHitObjectGetInstanceIdNV:
3601
0
    case glslang::EOpHitObjectGetGeometryIndexNV:
3602
0
    case glslang::EOpHitObjectGetPrimitiveIndexNV:
3603
0
    case glslang::EOpHitObjectGetHitKindNV:
3604
0
    case glslang::EOpHitObjectGetCurrentTimeNV:
3605
0
    case glslang::EOpHitObjectGetShaderBindingTableRecordIndexNV:
3606
0
    case glslang::EOpHitObjectGetShaderRecordBufferHandleNV:
3607
0
        builder.addExtension(spv::E_SPV_NV_shader_invocation_reorder);
3608
0
        builder.addCapability(spv::Capability::ShaderInvocationReorderNV);
3609
0
        break;
3610
3611
0
    case glslang::EOpHitObjectGetLSSPositionsNV:
3612
0
    case glslang::EOpHitObjectGetLSSRadiiNV:
3613
0
        builder.addExtension(spv::E_SPV_NV_linear_swept_spheres);
3614
0
        builder.addCapability(spv::Capability::ShaderInvocationReorderNV);
3615
0
        builder.addCapability(spv::Capability::RayTracingLinearSweptSpheresGeometryNV);
3616
0
        noReturnValue = true;
3617
0
        break;
3618
3619
0
    case glslang::EOpRayQueryGetIntersectionLSSPositionsNV:
3620
0
    case glslang::EOpRayQueryGetIntersectionLSSRadiiNV:
3621
0
        builder.addExtension(spv::E_SPV_NV_linear_swept_spheres);
3622
0
        builder.addCapability(spv::Capability::RayQueryKHR);
3623
0
        builder.addCapability(spv::Capability::RayTracingLinearSweptSpheresGeometryNV);
3624
0
        noReturnValue = true;
3625
0
        break;
3626
3627
0
    case glslang::EOpRayQueryGetIntersectionSpherePositionNV:
3628
0
    case glslang::EOpRayQueryGetIntersectionSphereRadiusNV:
3629
0
    case glslang::EOpRayQueryIsSphereHitNV:
3630
0
        builder.addExtension(spv::E_SPV_NV_linear_swept_spheres);
3631
0
        builder.addCapability(spv::Capability::RayQueryKHR);
3632
0
        builder.addCapability(spv::Capability::RayTracingSpheresGeometryNV);
3633
0
        builder.addCapability(spv::Capability::RayTracingLinearSweptSpheresGeometryNV);
3634
0
        break;
3635
3636
0
    case glslang::EOpRayQueryGetIntersectionLSSHitValueNV:
3637
0
    case glslang::EOpRayQueryIsLSSHitNV:
3638
0
        builder.addExtension(spv::E_SPV_NV_linear_swept_spheres);
3639
0
        builder.addCapability(spv::Capability::RayQueryKHR);
3640
0
        builder.addCapability(spv::Capability::RayTracingLinearSweptSpheresGeometryNV);
3641
0
        break;
3642
3643
0
    case glslang::EOpHitObjectTraceRayEXT:
3644
0
    case glslang::EOpHitObjectTraceRayMotionEXT:
3645
0
    case glslang::EOpHitObjectGetAttributesEXT:
3646
0
    case glslang::EOpHitObjectExecuteShaderEXT:
3647
0
    case glslang::EOpHitObjectRecordEmptyEXT:
3648
0
    case glslang::EOpHitObjectRecordMissEXT:
3649
0
    case glslang::EOpHitObjectRecordMissMotionEXT:
3650
0
    case glslang::EOpReorderThreadEXT:
3651
0
    case glslang::EOpHitObjectSetShaderBindingTableRecordIndexEXT:
3652
0
    case glslang::EOpHitObjectReorderExecuteEXT:
3653
0
    case glslang::EOpHitObjectTraceReorderExecuteEXT:
3654
0
    case glslang::EOpHitObjectTraceMotionReorderExecuteEXT:
3655
0
    case glslang::EOpHitObjectRecordFromQueryEXT:
3656
0
    case glslang::EOpHitObjectGetIntersectionTriangleVertexPositionsEXT:
3657
0
        noReturnValue = true;
3658
0
        [[fallthrough]];
3659
0
    case glslang::EOpHitObjectIsEmptyEXT:
3660
0
    case glslang::EOpHitObjectIsMissEXT:
3661
0
    case glslang::EOpHitObjectIsHitEXT:
3662
0
    case glslang::EOpHitObjectGetRayTMinEXT:
3663
0
    case glslang::EOpHitObjectGetRayTMaxEXT:
3664
0
    case glslang::EOpHitObjectGetRayFlagsEXT:
3665
0
    case glslang::EOpHitObjectGetObjectRayOriginEXT:
3666
0
    case glslang::EOpHitObjectGetObjectRayDirectionEXT:
3667
0
    case glslang::EOpHitObjectGetWorldRayOriginEXT:
3668
0
    case glslang::EOpHitObjectGetWorldRayDirectionEXT:
3669
0
    case glslang::EOpHitObjectGetObjectToWorldEXT:
3670
0
    case glslang::EOpHitObjectGetWorldToObjectEXT:
3671
0
    case glslang::EOpHitObjectGetInstanceCustomIndexEXT:
3672
0
    case glslang::EOpHitObjectGetInstanceIdEXT:
3673
0
    case glslang::EOpHitObjectGetGeometryIndexEXT:
3674
0
    case glslang::EOpHitObjectGetPrimitiveIndexEXT:
3675
0
    case glslang::EOpHitObjectGetHitKindEXT:
3676
0
    case glslang::EOpHitObjectGetCurrentTimeEXT:
3677
0
    case glslang::EOpHitObjectGetShaderBindingTableRecordIndexEXT:
3678
0
    case glslang::EOpHitObjectGetShaderRecordBufferHandleEXT:
3679
0
        builder.addExtension(spv::E_SPV_EXT_shader_invocation_reorder);
3680
0
        builder.addCapability(spv::Capability::ShaderInvocationReorderEXT);
3681
0
        break;
3682
3683
0
    case glslang::EOpRayQueryGetIntersectionTriangleVertexPositionsEXT:
3684
0
        builder.addExtension(spv::E_SPV_KHR_ray_tracing_position_fetch);
3685
0
        builder.addCapability(spv::Capability::RayQueryPositionFetchKHR);
3686
0
        noReturnValue = true;
3687
0
        break;
3688
29
    case glslang::EOpImageSampleWeightedQCOM:
3689
29
        builder.addCapability(spv::Capability::TextureSampleWeightedQCOM);
3690
29
        builder.addExtension(spv::E_SPV_QCOM_image_processing);
3691
29
        break;
3692
26
    case glslang::EOpImageBoxFilterQCOM:
3693
26
        builder.addCapability(spv::Capability::TextureBoxFilterQCOM);
3694
26
        builder.addExtension(spv::E_SPV_QCOM_image_processing);
3695
26
        break;
3696
39
    case glslang::EOpImageBlockMatchSADQCOM:
3697
78
    case glslang::EOpImageBlockMatchSSDQCOM:
3698
78
        builder.addCapability(spv::Capability::TextureBlockMatchQCOM);
3699
78
        builder.addExtension(spv::E_SPV_QCOM_image_processing);
3700
78
        break;
3701
0
    case glslang::EOpTensorWriteARM:
3702
0
        noReturnValue = true;
3703
0
        break;
3704
3705
26
    case glslang::EOpImageBlockMatchWindowSSDQCOM:
3706
52
    case glslang::EOpImageBlockMatchWindowSADQCOM:
3707
52
        builder.addCapability(spv::Capability::TextureBlockMatchQCOM);
3708
52
        builder.addExtension(spv::E_SPV_QCOM_image_processing);
3709
52
        builder.addCapability(spv::Capability::TextureBlockMatch2QCOM);
3710
52
        builder.addExtension(spv::E_SPV_QCOM_image_processing2);
3711
52
        break;
3712
3713
26
    case glslang::EOpImageBlockMatchGatherSSDQCOM:
3714
52
    case glslang::EOpImageBlockMatchGatherSADQCOM:
3715
52
        builder.addCapability(spv::Capability::TextureBlockMatchQCOM);
3716
52
        builder.addExtension(spv::E_SPV_QCOM_image_processing);
3717
52
        builder.addCapability(spv::Capability::TextureBlockMatch2QCOM);
3718
52
        builder.addExtension(spv::E_SPV_QCOM_image_processing2);
3719
52
        break;
3720
3721
0
    case glslang::EOpFetchMicroTriangleVertexPositionNV:
3722
0
    case glslang::EOpFetchMicroTriangleVertexBarycentricNV:
3723
0
        builder.addExtension(spv::E_SPV_NV_displacement_micromap);
3724
0
        builder.addCapability(spv::Capability::DisplacementMicromapNV);
3725
0
        break;
3726
3727
20
    case glslang::EOpRayQueryGetIntersectionClusterIdNV:
3728
20
        builder.addExtension(spv::E_SPV_NV_cluster_acceleration_structure);
3729
20
        builder.addCapability(spv::Capability::RayQueryKHR);
3730
20
        builder.addCapability(spv::Capability::RayTracingClusterAccelerationStructureNV);
3731
20
        break;
3732
3733
51
    case glslang::EOpDebugPrintf:
3734
51
        noReturnValue = true;
3735
51
        break;
3736
3737
2.39k
    default:
3738
2.39k
        break;
3739
58.4k
    }
3740
3741
    //
3742
    // See if it maps to a regular operation.
3743
    //
3744
5.38k
    if (binOp != glslang::EOpNull) {
3745
107
        glslang::TIntermTyped* left = node->getSequence()[0]->getAsTyped();
3746
107
        glslang::TIntermTyped* right = node->getSequence()[1]->getAsTyped();
3747
107
        assert(left && right);
3748
3749
107
        builder.clearAccessChain();
3750
107
        left->traverse(this);
3751
107
        spv::Id leftId = accessChainLoad(left->getType());
3752
3753
107
        builder.clearAccessChain();
3754
107
        right->traverse(this);
3755
107
        spv::Id rightId = accessChainLoad(right->getType());
3756
3757
107
        builder.setDebugSourceLocation(node->getLoc().line, node->getLoc().getFilename());
3758
107
        OpDecorations decorations = { precision,
3759
107
                                      TranslateNoContractionDecoration(node->getType().getQualifier()),
3760
107
                                      TranslateNonUniformDecoration(node->getType().getQualifier()) };
3761
107
        result = createBinaryOperation(binOp, decorations,
3762
107
                                       resultType(), leftId, rightId,
3763
107
                                       left->getType().getBasicType(), reduceComparison);
3764
3765
        // code above should only make binOp that exists in createBinaryOperation
3766
107
        assert(result != spv::NoResult);
3767
107
        builder.clearAccessChain();
3768
107
        builder.setAccessChainRValue(result);
3769
3770
107
        return false;
3771
107
    }
3772
3773
    //
3774
    // Create the list of operands.
3775
    //
3776
5.27k
    glslang::TIntermSequence& glslangOperands = node->getSequence();
3777
5.27k
    std::vector<spv::Id> operands;
3778
5.27k
    std::vector<spv::IdImmediate> memoryAccessOperands;
3779
18.0k
    for (int arg = 0; arg < (int)glslangOperands.size(); ++arg) {
3780
        // special case l-value operands; there are just a few
3781
12.7k
        bool lvalue = false;
3782
12.7k
        switch (node->getOp()) {
3783
0
        case glslang::EOpModf:
3784
0
            if (arg == 1)
3785
0
                lvalue = true;
3786
0
            break;
3787
3788
3789
3790
0
        case glslang::EOpHitObjectRecordFromQueryEXT:
3791
0
        case glslang::EOpHitObjectGetIntersectionTriangleVertexPositionsEXT:
3792
0
            if (arg == 0 || arg == 1)
3793
0
                lvalue = true;
3794
0
            break;
3795
3796
0
        case glslang::EOpHitObjectRecordHitNV:
3797
0
        case glslang::EOpHitObjectRecordHitMotionNV:
3798
0
        case glslang::EOpHitObjectRecordHitWithIndexNV:
3799
0
        case glslang::EOpHitObjectRecordHitWithIndexMotionNV:
3800
0
        case glslang::EOpHitObjectTraceRayNV:
3801
0
        case glslang::EOpHitObjectTraceRayMotionNV:
3802
0
        case glslang::EOpHitObjectExecuteShaderNV:
3803
0
        case glslang::EOpHitObjectRecordMissNV:
3804
0
        case glslang::EOpHitObjectRecordMissMotionNV:
3805
0
        case glslang::EOpHitObjectGetAttributesNV:
3806
0
        case glslang::EOpHitObjectGetClusterIdNV:
3807
0
        case glslang::EOpHitObjectTraceRayEXT:
3808
0
        case glslang::EOpHitObjectTraceRayMotionEXT:
3809
0
        case glslang::EOpHitObjectExecuteShaderEXT:
3810
0
        case glslang::EOpHitObjectRecordMissEXT:
3811
0
        case glslang::EOpHitObjectRecordMissMotionEXT:
3812
0
        case glslang::EOpHitObjectGetAttributesEXT:
3813
0
        case glslang::EOpHitObjectSetShaderBindingTableRecordIndexEXT:
3814
0
        case glslang::EOpHitObjectReorderExecuteEXT:
3815
0
        case glslang::EOpHitObjectTraceReorderExecuteEXT:
3816
0
        case glslang::EOpHitObjectTraceMotionReorderExecuteEXT:
3817
0
            if (arg == 0)
3818
0
                lvalue = true;
3819
0
            break;
3820
3821
0
        case glslang::EOpHitObjectGetLSSPositionsNV:
3822
0
        case glslang::EOpHitObjectGetLSSRadiiNV:
3823
0
            lvalue = true;
3824
0
            break;
3825
3826
248
        case glslang::EOpRayQueryInitialize:
3827
248
        case glslang::EOpRayQueryTerminate:
3828
248
        case glslang::EOpRayQueryConfirmIntersection:
3829
248
        case glslang::EOpRayQueryProceed:
3830
310
        case glslang::EOpRayQueryGenerateIntersection:
3831
434
        case glslang::EOpRayQueryGetIntersectionType:
3832
558
        case glslang::EOpRayQueryGetIntersectionT:
3833
682
        case glslang::EOpRayQueryGetIntersectionInstanceCustomIndex:
3834
806
        case glslang::EOpRayQueryGetIntersectionInstanceId:
3835
868
        case glslang::EOpRayQueryGetIntersectionInstanceShaderBindingTableRecordOffset:
3836
930
        case glslang::EOpRayQueryGetIntersectionGeometryIndex:
3837
1.05k
        case glslang::EOpRayQueryGetIntersectionPrimitiveIndex:
3838
1.17k
        case glslang::EOpRayQueryGetIntersectionBarycentrics:
3839
1.30k
        case glslang::EOpRayQueryGetIntersectionFrontFace:
3840
1.42k
        case glslang::EOpRayQueryGetIntersectionObjectRayDirection:
3841
1.55k
        case glslang::EOpRayQueryGetIntersectionObjectRayOrigin:
3842
1.67k
        case glslang::EOpRayQueryGetIntersectionObjectToWorld:
3843
1.79k
        case glslang::EOpRayQueryGetIntersectionWorldToObject:
3844
1.83k
        case glslang::EOpRayQueryGetIntersectionClusterIdNV:
3845
1.83k
        case glslang::EOpRayQueryGetIntersectionSpherePositionNV:
3846
1.83k
        case glslang::EOpRayQueryGetIntersectionSphereRadiusNV:
3847
1.83k
        case glslang::EOpRayQueryGetIntersectionLSSHitValueNV:
3848
1.83k
        case glslang::EOpRayQueryIsSphereHitNV:
3849
1.83k
        case glslang::EOpRayQueryIsLSSHitNV:
3850
1.83k
            if (arg == 0)
3851
826
                lvalue = true;
3852
1.83k
            break;
3853
3854
264
        case glslang::EOpAtomicAdd:
3855
264
        case glslang::EOpAtomicSubtract:
3856
368
        case glslang::EOpAtomicMin:
3857
468
        case glslang::EOpAtomicMax:
3858
472
        case glslang::EOpAtomicAnd:
3859
476
        case glslang::EOpAtomicOr:
3860
484
        case glslang::EOpAtomicXor:
3861
584
        case glslang::EOpAtomicExchange:
3862
590
        case glslang::EOpAtomicCompSwap:
3863
590
            if (arg == 0)
3864
294
                lvalue = true;
3865
590
            break;
3866
3867
18
        case glslang::EOpFrexp:
3868
18
            if (arg == 1)
3869
9
                lvalue = true;
3870
18
            break;
3871
0
        case glslang::EOpInterpolateAtSample:
3872
0
        case glslang::EOpInterpolateAtOffset:
3873
0
        case glslang::EOpInterpolateAtVertex:
3874
0
            if (arg == 0) {
3875
                // If GLSL, use the address of the interpolant argument.
3876
                // If HLSL, use an internal version of OpInterolates that takes
3877
                // the rvalue of the interpolant. A fixup pass in spirv-opt
3878
                // legalization will remove the OpLoad and convert to an lvalue.
3879
                // Had to do this because legalization will only propagate a
3880
                // builtin into an rvalue.
3881
0
                lvalue = glslangIntermediate->getSource() != glslang::EShSourceHlsl;
3882
3883
                // Does it need a swizzle inversion?  If so, evaluation is inverted;
3884
                // operate first on the swizzle base, then apply the swizzle.
3885
                // That is, we transform
3886
                //
3887
                //    interpolate(v.zy)  ->  interpolate(v).zy
3888
                //
3889
0
                if (glslangOperands[0]->getAsOperator() &&
3890
0
                    glslangOperands[0]->getAsOperator()->getOp() == glslang::EOpVectorSwizzle)
3891
0
                    invertedType = convertGlslangToSpvType(
3892
0
                        glslangOperands[0]->getAsBinaryNode()->getLeft()->getType());
3893
0
            }
3894
0
            break;
3895
0
        case glslang::EOpAtomicLoad:
3896
0
        case glslang::EOpAtomicStore:
3897
0
        case glslang::EOpAtomicCounterAdd:
3898
0
        case glslang::EOpAtomicCounterSubtract:
3899
0
        case glslang::EOpAtomicCounterMin:
3900
0
        case glslang::EOpAtomicCounterMax:
3901
0
        case glslang::EOpAtomicCounterAnd:
3902
0
        case glslang::EOpAtomicCounterOr:
3903
0
        case glslang::EOpAtomicCounterXor:
3904
0
        case glslang::EOpAtomicCounterExchange:
3905
0
        case glslang::EOpAtomicCounterCompSwap:
3906
0
            if (arg == 0)
3907
0
                lvalue = true;
3908
0
            break;
3909
0
        case glslang::EOpAddCarry:
3910
0
        case glslang::EOpSubBorrow:
3911
0
            if (arg == 2)
3912
0
                lvalue = true;
3913
0
            break;
3914
0
        case glslang::EOpUMulExtended:
3915
0
        case glslang::EOpIMulExtended:
3916
0
            if (arg >= 2)
3917
0
                lvalue = true;
3918
0
            break;
3919
0
        case glslang::EOpCooperativeMatrixLoad:
3920
0
        case glslang::EOpCooperativeMatrixLoadNV:
3921
0
        case glslang::EOpCooperativeMatrixLoadTensorNV:
3922
0
        case glslang::EOpCooperativeVectorLoadNV:
3923
0
            if (arg == 0 || arg == 1)
3924
0
                lvalue = true;
3925
0
            break;
3926
0
        case glslang::EOpCooperativeMatrixStore:
3927
0
        case glslang::EOpCooperativeMatrixStoreNV:
3928
0
        case glslang::EOpCooperativeMatrixStoreTensorNV:
3929
0
        case glslang::EOpCooperativeVectorStoreNV:
3930
0
            if (arg == 1)
3931
0
                lvalue = true;
3932
0
            break;
3933
0
        case glslang::EOpCooperativeVectorMatMulNV:
3934
0
            if (arg == 0 || arg == 3)
3935
0
                lvalue = true;
3936
0
            break;
3937
0
        case glslang::EOpCooperativeVectorMatMulAddNV:
3938
0
            if (arg == 0 || arg == 3 || arg == 6)
3939
0
                lvalue = true;
3940
0
            break;
3941
0
        case glslang::EOpCooperativeVectorOuterProductAccumulateNV:
3942
0
            if (arg == 2)
3943
0
                lvalue = true;
3944
0
            break;
3945
0
        case glslang::EOpCooperativeVectorReduceSumAccumulateNV:
3946
0
            if (arg == 1)
3947
0
                lvalue = true;
3948
0
            break;
3949
0
        case glslang::EOpCooperativeMatrixReduceNV:
3950
0
        case glslang::EOpCooperativeMatrixPerElementOpNV:
3951
0
        case glslang::EOpCooperativeMatrixTransposeNV:
3952
0
            if (arg == 0)
3953
0
                lvalue = true;
3954
0
            break;
3955
68
        case glslang::EOpSpirvInst:
3956
68
            if (glslangOperands[arg]->getAsTyped()->getQualifier().isSpirvByReference())
3957
0
                lvalue = true;
3958
68
            break;
3959
0
        case glslang::EOpReorderThreadNV:
3960
0
        case glslang::EOpReorderThreadEXT:
3961
            //Three variants of reorderThreadNV, two of them use hitObjectNV
3962
0
            if (arg == 0 && glslangOperands.size() != 2)
3963
0
                lvalue = true;
3964
0
            break;
3965
0
        case glslang::EOpRayQueryGetIntersectionTriangleVertexPositionsEXT:
3966
0
        case glslang::EOpRayQueryGetIntersectionLSSPositionsNV:
3967
0
        case glslang::EOpRayQueryGetIntersectionLSSRadiiNV:
3968
0
            if (arg == 0 || arg == 2)
3969
0
                lvalue = true;
3970
0
            break;
3971
4
        case glslang::EOpTensorReadARM:
3972
4
            if (arg == 2)
3973
1
                lvalue = true;
3974
4
            break;
3975
10.2k
        default:
3976
10.2k
            break;
3977
12.7k
        }
3978
12.7k
        builder.clearAccessChain();
3979
12.7k
        if (invertedType != spv::NoType && arg == 0)
3980
0
            glslangOperands[0]->getAsBinaryNode()->getLeft()->traverse(this);
3981
12.7k
        else
3982
12.7k
            glslangOperands[arg]->traverse(this);
3983
3984
12.7k
        bool isCoopMat = node->getOp() == glslang::EOpCooperativeMatrixLoad ||
3985
12.7k
                         node->getOp() == glslang::EOpCooperativeMatrixStore ||
3986
12.7k
                         node->getOp() == glslang::EOpCooperativeMatrixLoadNV ||
3987
12.7k
                         node->getOp() == glslang::EOpCooperativeMatrixStoreNV ||
3988
12.7k
                         node->getOp() == glslang::EOpCooperativeMatrixLoadTensorNV ||
3989
12.7k
                         node->getOp() == glslang::EOpCooperativeMatrixStoreTensorNV;
3990
12.7k
        bool isCoopVec = node->getOp() == glslang::EOpCooperativeVectorLoadNV ||
3991
12.7k
                         node->getOp() == glslang::EOpCooperativeVectorStoreNV;
3992
12.7k
        if (isCoopMat || isCoopVec) {
3993
3994
0
            if (arg == 1) {
3995
0
                spv::Builder::AccessChain::CoherentFlags coherentFlags {};
3996
0
                unsigned int alignment {};
3997
0
                if (isCoopMat) {
3998
                    // fold "element" parameter into the access chain
3999
0
                    spv::Builder::AccessChain save = builder.getAccessChain();
4000
0
                    builder.clearAccessChain();
4001
0
                    glslangOperands[2]->traverse(this);
4002
4003
0
                    spv::Id elementId = accessChainLoad(glslangOperands[2]->getAsTyped()->getType());
4004
4005
0
                    builder.setAccessChain(save);
4006
4007
                    // Point to the first element of the array.
4008
0
                    builder.accessChainPush(elementId,
4009
0
                        TranslateCoherent(glslangOperands[arg]->getAsTyped()->getType()),
4010
0
                                          glslangOperands[arg]->getAsTyped()->getType().getBufferReferenceAlignment());
4011
0
                    coherentFlags = builder.getAccessChain().coherentFlags;
4012
0
                    alignment = builder.getAccessChain().alignment;
4013
0
                } else {
4014
0
                    coherentFlags = builder.getAccessChain().coherentFlags;
4015
0
                    coherentFlags |= TranslateCoherent(glslangOperands[arg]->getAsTyped()->getType());
4016
0
                    alignment = 16;
4017
0
                }
4018
4019
0
                spv::MemoryAccessMask memoryAccess = TranslateMemoryAccess(coherentFlags);
4020
0
                if (node->getOp() == glslang::EOpCooperativeMatrixLoad ||
4021
0
                    node->getOp() == glslang::EOpCooperativeMatrixLoadNV ||
4022
0
                    node->getOp() == glslang::EOpCooperativeMatrixLoadTensorNV ||
4023
0
                    node->getOp() == glslang::EOpCooperativeVectorLoadNV)
4024
0
                    memoryAccess = (memoryAccess & ~spv::MemoryAccessMask::MakePointerAvailableKHR);
4025
0
                if (node->getOp() == glslang::EOpCooperativeMatrixStore ||
4026
0
                    node->getOp() == glslang::EOpCooperativeMatrixStoreNV ||
4027
0
                    node->getOp() == glslang::EOpCooperativeMatrixStoreTensorNV ||
4028
0
                    node->getOp() == glslang::EOpCooperativeVectorStoreNV)
4029
0
                    memoryAccess = (memoryAccess & ~spv::MemoryAccessMask::MakePointerVisibleKHR);
4030
0
                if (builder.getStorageClass(builder.getAccessChain().base) ==
4031
0
                    spv::StorageClass::PhysicalStorageBufferEXT) {
4032
0
                    memoryAccess = (spv::MemoryAccessMask)(memoryAccess | spv::MemoryAccessMask::Aligned);
4033
0
                }
4034
4035
0
                memoryAccessOperands.push_back(spv::IdImmediate(false, memoryAccess));
4036
4037
0
                if (anySet(memoryAccess, spv::MemoryAccessMask::Aligned)) {
4038
0
                    memoryAccessOperands.push_back(spv::IdImmediate(false, alignment));
4039
0
                }
4040
4041
0
                if (anySet(memoryAccess,
4042
0
                    spv::MemoryAccessMask::MakePointerAvailableKHR | spv::MemoryAccessMask::MakePointerVisibleKHR)) {
4043
0
                    memoryAccessOperands.push_back(spv::IdImmediate(true,
4044
0
                        builder.makeUintConstant(TranslateMemoryScope(coherentFlags))));
4045
0
                }
4046
0
            } else if (isCoopMat && arg == 2) {
4047
0
                continue;
4048
0
            }
4049
0
        }
4050
4051
        // for l-values, pass the address, for r-values, pass the value
4052
12.7k
        if (lvalue) {
4053
1.13k
            if (invertedType == spv::NoType && !builder.isSpvLvalue()) {
4054
                // SPIR-V cannot represent an l-value containing a swizzle that doesn't
4055
                // reduce to a simple access chain.  So, we need a temporary vector to
4056
                // receive the result, and must later swizzle that into the original
4057
                // l-value.
4058
0
                complexLvalues.push_back(builder.getAccessChain());
4059
0
                temporaryLvalues.push_back(builder.createVariable(
4060
0
                    spv::NoPrecision, spv::StorageClass::Function,
4061
0
                    builder.accessChainGetInferredType(), "swizzleTemp"));
4062
0
                operands.push_back(temporaryLvalues.back());
4063
1.13k
            } else {
4064
1.13k
                operands.push_back(builder.accessChainGetLValue());
4065
1.13k
            }
4066
1.13k
            lvalueCoherentFlags = builder.getAccessChain().coherentFlags;
4067
1.13k
            lvalueCoherentFlags |= TranslateCoherent(glslangOperands[arg]->getAsTyped()->getType());
4068
11.6k
        } else {
4069
11.6k
            builder.setDebugSourceLocation(node->getLoc().line, node->getLoc().getFilename());
4070
11.6k
            glslang::TOperator glslangOp = node->getOp();
4071
11.6k
            if (arg == 1 &&
4072
5.21k
                (glslangOp == glslang::EOpRayQueryGetIntersectionType ||
4073
5.15k
                 glslangOp == glslang::EOpRayQueryGetIntersectionT ||
4074
5.09k
                 glslangOp == glslang::EOpRayQueryGetIntersectionInstanceCustomIndex ||
4075
5.02k
                 glslangOp == glslang::EOpRayQueryGetIntersectionInstanceId ||
4076
4.96k
                 glslangOp == glslang::EOpRayQueryGetIntersectionInstanceShaderBindingTableRecordOffset ||
4077
4.93k
                 glslangOp == glslang::EOpRayQueryGetIntersectionGeometryIndex ||
4078
4.90k
                 glslangOp == glslang::EOpRayQueryGetIntersectionPrimitiveIndex ||
4079
4.84k
                 glslangOp == glslang::EOpRayQueryGetIntersectionBarycentrics ||
4080
4.78k
                 glslangOp == glslang::EOpRayQueryGetIntersectionFrontFace ||
4081
4.71k
                 glslangOp == glslang::EOpRayQueryGetIntersectionObjectRayDirection ||
4082
4.65k
                 glslangOp == glslang::EOpRayQueryGetIntersectionObjectRayOrigin ||
4083
4.59k
                 glslangOp == glslang::EOpRayQueryGetIntersectionObjectToWorld ||
4084
4.53k
                 glslangOp == glslang::EOpRayQueryGetIntersectionWorldToObject ||
4085
4.47k
                 glslangOp == glslang::EOpRayQueryGetIntersectionTriangleVertexPositionsEXT ||
4086
4.47k
                 glslangOp == glslang::EOpRayQueryGetIntersectionClusterIdNV ||
4087
4.45k
                 glslangOp == glslang::EOpRayQueryGetIntersectionSpherePositionNV ||
4088
4.45k
                 glslangOp == glslang::EOpRayQueryGetIntersectionSphereRadiusNV ||
4089
4.45k
                 glslangOp == glslang::EOpRayQueryGetIntersectionLSSHitValueNV ||
4090
4.45k
                 glslangOp == glslang::EOpRayQueryGetIntersectionLSSPositionsNV ||
4091
4.45k
                 glslangOp == glslang::EOpRayQueryGetIntersectionLSSRadiiNV ||
4092
4.45k
                 glslangOp == glslang::EOpRayQueryIsLSSHitNV ||
4093
4.45k
                 glslangOp == glslang::EOpRayQueryIsSphereHitNV
4094
5.21k
                    )) {
4095
764
                bool cond = glslangOperands[arg]->getAsConstantUnion()->getConstArray()[0].getBConst();
4096
764
                operands.push_back(builder.makeIntConstant(cond ? 1 : 0));
4097
10.8k
             } else if ((arg == 10 && glslangOp == glslang::EOpTraceKHR) ||
4098
10.8k
                        (arg == 11 && glslangOp == glslang::EOpTraceRayMotionNV) ||
4099
10.8k
                        (arg == 1  && glslangOp == glslang::EOpExecuteCallableKHR) ||
4100
10.8k
                        (arg == 1  && glslangOp == glslang::EOpHitObjectExecuteShaderNV) ||
4101
10.8k
                        (arg == 1  && glslangOp == glslang::EOpHitObjectExecuteShaderEXT) ||
4102
10.8k
                        (arg == 11 && glslangOp == glslang::EOpHitObjectTraceRayNV) ||
4103
10.8k
                        (arg == 11 && glslangOp == glslang::EOpHitObjectTraceRayEXT) ||
4104
10.8k
                        (arg == 12 && glslangOp == glslang::EOpHitObjectTraceRayMotionNV) ||
4105
10.8k
                        (arg == 12 && glslangOp == glslang::EOpHitObjectTraceRayMotionEXT) ||
4106
10.8k
                        (arg == 12 && glslangOp == glslang::EOpHitObjectTraceMotionReorderExecuteEXT && glslangOperands.size() == 13) ||
4107
10.8k
                        (arg == 14 && glslangOp == glslang::EOpHitObjectTraceMotionReorderExecuteEXT && glslangOperands.size() == 15) ||
4108
10.8k
                        (arg == 11 && glslangOp == glslang::EOpHitObjectTraceReorderExecuteEXT && glslangOperands.size() == 12) ||
4109
10.8k
                        (arg == 13 && glslangOp == glslang::EOpHitObjectTraceReorderExecuteEXT && glslangOperands.size() == 14) ||
4110
10.8k
                        (arg == 1  && glslangOp == glslang::EOpHitObjectReorderExecuteEXT && glslangOperands.size() == 2) ||
4111
10.8k
                        (arg == 3  && glslangOp == glslang::EOpHitObjectReorderExecuteEXT && glslangOperands.size() == 4)) {
4112
0
                 const int set = glslangOp == glslang::EOpExecuteCallableKHR ? 1 : 0;
4113
0
                 const int location = glslangOperands[arg]->getAsConstantUnion()->getConstArray()[0].getUConst();
4114
0
                 auto itNode = locationToSymbol[set].find(location);
4115
0
                 visitSymbol(itNode->second);
4116
0
                 spv::Id symId = getSymbolId(itNode->second);
4117
0
                 operands.push_back(symId);
4118
10.8k
            } else if ((arg == 12 && glslangOp == glslang::EOpHitObjectRecordHitNV) ||
4119
10.8k
                       (arg == 13 && glslangOp == glslang::EOpHitObjectRecordHitMotionNV) ||
4120
10.8k
                       (arg == 11 && glslangOp == glslang::EOpHitObjectRecordHitWithIndexNV) ||
4121
10.8k
                       (arg == 12 && glslangOp == glslang::EOpHitObjectRecordHitWithIndexMotionNV) ||
4122
10.8k
                       (arg == 3  && glslangOp == glslang::EOpHitObjectRecordFromQueryEXT) ||
4123
10.8k
                       (arg == 1  && glslangOp == glslang::EOpHitObjectGetAttributesEXT) ||
4124
10.8k
                       (arg == 1  && glslangOp == glslang::EOpHitObjectGetAttributesNV)) {
4125
0
                 const int location = glslangOperands[arg]->getAsConstantUnion()->getConstArray()[0].getUConst();
4126
0
                 const int set = 2;
4127
0
                 auto itNode = locationToSymbol[set].find(location);
4128
0
                 visitSymbol(itNode->second);
4129
0
                 spv::Id symId = getSymbolId(itNode->second);
4130
0
                 operands.push_back(symId);
4131
10.8k
            } else if (glslangOperands[arg]->getAsTyped()->getQualifier().isSpirvLiteral()) {
4132
                // Will be translated to a literal value, make a placeholder here
4133
0
                operands.push_back(spv::NoResult);
4134
10.8k
            } else if (glslangOperands[arg]->getAsTyped()->getBasicType() == glslang::EbtFunction) {
4135
0
                spv::Function* function = functionMap[glslangOperands[arg]->getAsSymbolNode()->getMangledName().c_str()];
4136
0
                assert(function);
4137
0
                operands.push_back(function->getId());
4138
10.8k
            } else  {
4139
10.8k
               operands.push_back(accessChainLoad(glslangOperands[arg]->getAsTyped()->getType()));
4140
10.8k
            }
4141
11.6k
        }
4142
12.7k
    }
4143
4144
5.27k
    builder.setDebugSourceLocation(node->getLoc().line, node->getLoc().getFilename());
4145
5.27k
    if (node->getOp() == glslang::EOpCooperativeMatrixLoadTensorNV) {
4146
0
        std::vector<spv::IdImmediate> idImmOps;
4147
4148
0
        builder.addCapability(spv::Capability::CooperativeMatrixTensorAddressingNV);
4149
0
        builder.addExtension(spv::E_SPV_NV_cooperative_matrix2);
4150
4151
0
        spv::Id object = builder.createLoad(operands[0], spv::NoPrecision);
4152
4153
0
        idImmOps.push_back(spv::IdImmediate(true, operands[1])); // Pointer
4154
0
        idImmOps.push_back(spv::IdImmediate(true, object)); // Object
4155
0
        idImmOps.push_back(spv::IdImmediate(true, operands[2])); // tensorLayout
4156
4157
0
        idImmOps.insert(idImmOps.end(), memoryAccessOperands.begin(), memoryAccessOperands.end()); // memoryaccess
4158
4159
        // initialize tensor operands to zero, then OR in flags based on the operands
4160
0
        size_t tensorOpIdx = idImmOps.size();
4161
0
        idImmOps.push_back(spv::IdImmediate(false, 0));
4162
4163
0
        for (uint32_t i = 3; i < operands.size(); ++i) {
4164
0
            if (builder.isTensorView(operands[i])) {
4165
0
                addMask(idImmOps[tensorOpIdx].word, spv::TensorAddressingOperandsMask::TensorView);
4166
0
            } else {
4167
                // must be the decode func
4168
0
                addMask(idImmOps[tensorOpIdx].word, spv::TensorAddressingOperandsMask::DecodeFunc);
4169
0
                builder.addCapability(spv::Capability::CooperativeMatrixBlockLoadsNV);
4170
0
            }
4171
0
            idImmOps.push_back(spv::IdImmediate(true, operands[i])); // tensorView or decodeFunc
4172
0
        }
4173
4174
        // get the pointee type
4175
0
        spv::Id typeId = builder.getContainedTypeId(builder.getTypeId(operands[0]));
4176
0
        assert(builder.isCooperativeMatrixType(typeId));
4177
        // do the op
4178
0
        spv::Id result = builder.createOp(spv::Op::OpCooperativeMatrixLoadTensorNV, typeId, idImmOps);
4179
        // store the result to the pointer (out param 'm')
4180
0
        builder.createStore(result, operands[0]);
4181
0
        result = 0;
4182
5.27k
    } else if (node->getOp() == glslang::EOpCooperativeMatrixLoad ||
4183
5.27k
               node->getOp() == glslang::EOpCooperativeMatrixLoadNV) {
4184
0
        std::vector<spv::IdImmediate> idImmOps;
4185
4186
0
        idImmOps.push_back(spv::IdImmediate(true, operands[1])); // buf
4187
0
        if (node->getOp() == glslang::EOpCooperativeMatrixLoad) {
4188
0
            idImmOps.push_back(spv::IdImmediate(true, operands[3])); // matrixLayout
4189
0
            auto layout = (spv::CooperativeMatrixLayout)builder.getConstantScalar(operands[3]);
4190
0
            if (layout == spv::CooperativeMatrixLayout::RowBlockedInterleavedARM ||
4191
0
                layout == spv::CooperativeMatrixLayout::ColumnBlockedInterleavedARM) {
4192
0
                builder.addExtension(spv::E_SPV_ARM_cooperative_matrix_layouts);
4193
0
                builder.addCapability(spv::Capability::CooperativeMatrixLayoutsARM);
4194
0
            }
4195
0
            idImmOps.push_back(spv::IdImmediate(true, operands[2])); // stride
4196
0
        } else {
4197
0
            idImmOps.push_back(spv::IdImmediate(true, operands[2])); // stride
4198
0
            idImmOps.push_back(spv::IdImmediate(true, operands[3])); // colMajor
4199
0
        }
4200
0
        idImmOps.insert(idImmOps.end(), memoryAccessOperands.begin(), memoryAccessOperands.end());
4201
        // get the pointee type
4202
0
        spv::Id typeId = builder.getContainedTypeId(builder.getTypeId(operands[0]));
4203
0
        assert(builder.isCooperativeMatrixType(typeId));
4204
        // do the op
4205
0
        spv::Id result = node->getOp() == glslang::EOpCooperativeMatrixLoad
4206
0
                       ? builder.createOp(spv::Op::OpCooperativeMatrixLoadKHR, typeId, idImmOps)
4207
0
                       : builder.createOp(spv::Op::OpCooperativeMatrixLoadNV, typeId, idImmOps);
4208
        // store the result to the pointer (out param 'm')
4209
0
        builder.createStore(result, operands[0]);
4210
0
        result = 0;
4211
5.27k
    } else if (node->getOp() == glslang::EOpCooperativeMatrixStoreTensorNV) {
4212
0
        std::vector<spv::IdImmediate> idImmOps;
4213
4214
0
        idImmOps.push_back(spv::IdImmediate(true, operands[1])); // buf
4215
0
        idImmOps.push_back(spv::IdImmediate(true, operands[0])); // object
4216
4217
0
        builder.addCapability(spv::Capability::CooperativeMatrixTensorAddressingNV);
4218
0
        builder.addExtension(spv::E_SPV_NV_cooperative_matrix2);
4219
4220
0
        idImmOps.push_back(spv::IdImmediate(true, operands[2])); // tensorLayout
4221
4222
0
        idImmOps.insert(idImmOps.end(), memoryAccessOperands.begin(), memoryAccessOperands.end()); // memoryaccess
4223
4224
0
        if (operands.size() > 3) {
4225
0
            idImmOps.push_back(spv::IdImmediate(false, spv::TensorAddressingOperandsMask::TensorView));
4226
0
            idImmOps.push_back(spv::IdImmediate(true, operands[3])); // tensorView
4227
0
        } else {
4228
0
            idImmOps.push_back(spv::IdImmediate(false, 0));
4229
0
        }
4230
4231
0
        builder.createNoResultOp(spv::Op::OpCooperativeMatrixStoreTensorNV, idImmOps);
4232
0
        result = 0;
4233
5.27k
    } else if (node->getOp() == glslang::EOpCooperativeMatrixStore ||
4234
5.27k
               node->getOp() == glslang::EOpCooperativeMatrixStoreNV) {
4235
0
        std::vector<spv::IdImmediate> idImmOps;
4236
4237
0
        idImmOps.push_back(spv::IdImmediate(true, operands[1])); // buf
4238
0
        idImmOps.push_back(spv::IdImmediate(true, operands[0])); // object
4239
0
        if (node->getOp() == glslang::EOpCooperativeMatrixStore) {
4240
0
            idImmOps.push_back(spv::IdImmediate(true, operands[3])); // matrixLayout
4241
0
            auto layout = (spv::CooperativeMatrixLayout)builder.getConstantScalar(operands[3]);
4242
0
            if (layout == spv::CooperativeMatrixLayout::RowBlockedInterleavedARM ||
4243
0
                layout == spv::CooperativeMatrixLayout::ColumnBlockedInterleavedARM) {
4244
0
                builder.addExtension(spv::E_SPV_ARM_cooperative_matrix_layouts);
4245
0
                builder.addCapability(spv::Capability::CooperativeMatrixLayoutsARM);
4246
0
            }
4247
0
            idImmOps.push_back(spv::IdImmediate(true, operands[2])); // stride
4248
0
        } else {
4249
0
            idImmOps.push_back(spv::IdImmediate(true, operands[2])); // stride
4250
0
            idImmOps.push_back(spv::IdImmediate(true, operands[3])); // colMajor
4251
0
        }
4252
0
        idImmOps.insert(idImmOps.end(), memoryAccessOperands.begin(), memoryAccessOperands.end());
4253
4254
0
        if (node->getOp() == glslang::EOpCooperativeMatrixStore)
4255
0
            builder.createNoResultOp(spv::Op::OpCooperativeMatrixStoreKHR, idImmOps);
4256
0
        else
4257
0
            builder.createNoResultOp(spv::Op::OpCooperativeMatrixStoreNV, idImmOps);
4258
0
        result = 0;
4259
5.27k
    } else if (node->getOp() == glslang::EOpRayQueryGetIntersectionTriangleVertexPositionsEXT) {
4260
0
        std::vector<spv::IdImmediate> idImmOps;
4261
4262
0
        idImmOps.push_back(spv::IdImmediate(true, operands[0])); // q
4263
0
        idImmOps.push_back(spv::IdImmediate(true, operands[1])); // committed
4264
4265
0
        spv::Id typeId = builder.makeArrayType(builder.makeVectorType(builder.makeFloatType(32), 3),
4266
0
                                               builder.makeUintConstant(3), 0);
4267
        // do the op
4268
4269
0
        spv::Op spvOp = spv::Op::OpRayQueryGetIntersectionTriangleVertexPositionsKHR;
4270
4271
0
        spv::Id result = builder.createOp(spvOp, typeId, idImmOps);
4272
        // store the result to the pointer (out param 'm')
4273
0
        builder.createStore(result, operands[2]);
4274
0
        result = 0;
4275
5.27k
    } else if (node->getOp() == glslang::EOpRayQueryGetIntersectionLSSPositionsNV) {
4276
0
        std::vector<spv::IdImmediate> idImmOps;
4277
4278
0
        idImmOps.push_back(spv::IdImmediate(true, operands[0])); // q
4279
0
        idImmOps.push_back(spv::IdImmediate(true, operands[1])); // committed
4280
4281
0
        spv::Id typeId = builder.makeArrayType(builder.makeVectorType(builder.makeFloatType(32), 3),
4282
0
                                               builder.makeUintConstant(2), 0);
4283
        // do the op
4284
4285
0
        spv::Op spvOp = spv::Op::OpRayQueryGetIntersectionLSSPositionsNV;
4286
4287
0
        spv::Id result = builder.createOp(spvOp, typeId, idImmOps);
4288
        // store the result to the pointer (out param 'm')
4289
0
        builder.createStore(result, operands[2]);
4290
0
        result = 0;
4291
5.27k
    } else if (node->getOp() == glslang::EOpRayQueryGetIntersectionLSSRadiiNV) {
4292
0
        std::vector<spv::IdImmediate> idImmOps;
4293
4294
0
        idImmOps.push_back(spv::IdImmediate(true, operands[0])); // q
4295
0
        idImmOps.push_back(spv::IdImmediate(true, operands[1])); // committed
4296
4297
0
        spv::Id typeId = builder.makeArrayType(builder.makeFloatType(32),
4298
0
                                               builder.makeUintConstant(2), 0);
4299
        // do the op
4300
4301
0
        spv::Op spvOp = spv::Op::OpRayQueryGetIntersectionLSSRadiiNV;
4302
4303
0
        spv::Id result = builder.createOp(spvOp, typeId, idImmOps);
4304
        // store the result to the pointer (out param 'm')
4305
0
        builder.createStore(result, operands[2]);
4306
0
        result = 0;
4307
5.27k
    } else if (node->getOp() == glslang::EOpHitObjectGetLSSPositionsNV) {
4308
0
        std::vector<spv::IdImmediate> idImmOps;
4309
4310
0
        idImmOps.push_back(spv::IdImmediate(true, operands[0])); // hitObject
4311
4312
0
        spv::Op spvOp = spv::Op::OpHitObjectGetLSSPositionsNV;
4313
0
        spv::Id typeId = builder.makeArrayType(builder.makeVectorType(builder.makeFloatType(32), 3),
4314
0
                                               builder.makeUintConstant(2), 0);
4315
4316
0
        spv::Id result = builder.createOp(spvOp, typeId, idImmOps);
4317
        // store the result to the pointer (out param 'm')
4318
0
        builder.createStore(result, operands[1]);
4319
0
        result = 0;
4320
5.27k
    } else if (node->getOp() == glslang::EOpHitObjectGetLSSRadiiNV) {
4321
0
        std::vector<spv::IdImmediate> idImmOps;
4322
4323
0
        idImmOps.push_back(spv::IdImmediate(true, operands[0])); // hitObject
4324
4325
0
        spv::Op spvOp = spv::Op::OpHitObjectGetLSSRadiiNV;
4326
0
        spv::Id typeId = builder.makeArrayType(builder.makeFloatType(32),
4327
0
                                               builder.makeUintConstant(2), 0);
4328
4329
0
        spv::Id result = builder.createOp(spvOp, typeId, idImmOps);
4330
        // store the result to the pointer (out param 'm')
4331
0
        builder.createStore(result, operands[1]);
4332
0
        result = 0;
4333
5.27k
    } else if (node->getOp() == glslang::EOpHitObjectGetIntersectionTriangleVertexPositionsEXT) {
4334
0
        std::vector<spv::IdImmediate> idImmOps;
4335
4336
0
        idImmOps.push_back(spv::IdImmediate(true, operands[0])); // hitObject
4337
4338
0
        spv::Op spvOp = spv::Op::OpHitObjectGetIntersectionTriangleVertexPositionsEXT;
4339
0
        spv::Id typeId = builder.makeArrayType(builder.makeVectorType(builder.makeFloatType(32), 3),
4340
0
                                               builder.makeUintConstant(3), 0);
4341
4342
0
        spv::Id result = builder.createOp(spvOp, typeId, idImmOps);
4343
        // store the result to the pointer (out param 'm')
4344
0
        builder.createStore(result, operands[1]);
4345
0
        result = 0;
4346
5.27k
    } else if (node->getOp() == glslang::EOpCooperativeMatrixMulAdd) {
4347
0
        auto matrixOperands = spv::CooperativeMatrixOperandsMask::MaskNone;
4348
4349
        // If the optional operand is present, initialize matrixOperands to that value.
4350
0
        if (glslangOperands.size() == 4 && glslangOperands[3]->getAsConstantUnion()) {
4351
0
            matrixOperands = (spv::CooperativeMatrixOperandsMask)glslangOperands[3]->getAsConstantUnion()->getConstArray()[0].getIConst();
4352
0
        }
4353
4354
        // Determine Cooperative Matrix Operands bits from the signedness of the types.
4355
0
        if (isTypeSignedInt(glslangOperands[0]->getAsTyped()->getBasicType()))
4356
0
            addMask(matrixOperands, spv::CooperativeMatrixOperandsMask::MatrixASignedComponentsKHR);
4357
0
        if (isTypeSignedInt(glslangOperands[1]->getAsTyped()->getBasicType()))
4358
0
            addMask(matrixOperands, spv::CooperativeMatrixOperandsMask::MatrixBSignedComponentsKHR);
4359
0
        if (isTypeSignedInt(glslangOperands[2]->getAsTyped()->getBasicType()))
4360
0
            addMask(matrixOperands, spv::CooperativeMatrixOperandsMask::MatrixCSignedComponentsKHR);
4361
0
        if (isTypeSignedInt(node->getBasicType()))
4362
0
            addMask(matrixOperands, spv::CooperativeMatrixOperandsMask::MatrixResultSignedComponentsKHR);
4363
4364
0
        std::vector<spv::IdImmediate> idImmOps;
4365
0
        idImmOps.push_back(spv::IdImmediate(true, operands[0]));
4366
0
        idImmOps.push_back(spv::IdImmediate(true, operands[1]));
4367
0
        idImmOps.push_back(spv::IdImmediate(true, operands[2]));
4368
0
        if (matrixOperands != spv::CooperativeMatrixOperandsMask::MaskNone)
4369
0
            idImmOps.push_back(spv::IdImmediate(false, matrixOperands));
4370
4371
0
        result = builder.createOp(spv::Op::OpCooperativeMatrixMulAddKHR, resultType(), idImmOps);
4372
5.27k
    } else if (node->getOp() == glslang::EOpCooperativeMatrixReduceNV) {
4373
0
        builder.addCapability(spv::Capability::CooperativeMatrixReductionsNV);
4374
0
        builder.addExtension(spv::E_SPV_NV_cooperative_matrix2);
4375
4376
0
        spv::Op opcode = spv::Op::OpCooperativeMatrixReduceNV;
4377
0
        unsigned mask = glslangOperands[2]->getAsConstantUnion()->getConstArray()[0].getUConst();
4378
4379
0
        spv::Id typeId = builder.getContainedTypeId(builder.getTypeId(operands[0]));
4380
0
        assert(builder.isCooperativeMatrixType(typeId));
4381
4382
0
        result = builder.createCooperativeMatrixReduce(opcode, typeId, operands[1], mask, operands[3]);
4383
        // store the result to the pointer (out param 'm')
4384
0
        builder.createStore(result, operands[0]);
4385
0
        result = 0;
4386
5.27k
    } else if (node->getOp() == glslang::EOpCooperativeMatrixPerElementOpNV) {
4387
0
        builder.addCapability(spv::Capability::CooperativeMatrixPerElementOperationsNV);
4388
0
        builder.addExtension(spv::E_SPV_NV_cooperative_matrix2);
4389
4390
0
        spv::Id typeId = builder.getContainedTypeId(builder.getTypeId(operands[0]));
4391
0
        assert(builder.isCooperativeMatrixType(typeId));
4392
4393
0
        result = builder.createCooperativeMatrixPerElementOp(typeId, operands);
4394
        // store the result to the pointer
4395
0
        builder.createStore(result, operands[0]);
4396
0
        result = 0;
4397
5.27k
    } else if (node->getOp() == glslang::EOpCooperativeMatrixTransposeNV) {
4398
4399
0
        builder.addCapability(spv::Capability::CooperativeMatrixConversionsNV);
4400
0
        builder.addExtension(spv::E_SPV_NV_cooperative_matrix2);
4401
4402
0
        spv::Id typeId = builder.getContainedTypeId(builder.getTypeId(operands[0]));
4403
0
        assert(builder.isCooperativeMatrixType(typeId));
4404
4405
0
        result = builder.createUnaryOp(spv::Op::OpCooperativeMatrixTransposeNV, typeId, operands[1]);
4406
        // store the result to the pointer
4407
0
        builder.createStore(result, operands[0]);
4408
0
        result = 0;
4409
5.27k
    } else if (node->getOp() == glslang::EOpBitCastArrayQCOM) {
4410
0
        builder.addCapability(spv::Capability::CooperativeMatrixConversionQCOM);
4411
0
        builder.addExtension(spv::E_SPV_QCOM_cooperative_matrix_conversion);
4412
0
        result = builder.createUnaryOp(spv::Op::OpBitCastArrayQCOM, resultType(), operands[0]);
4413
5.27k
    } else if (node->getOp() == glslang::EOpCompositeConstructCoopMatQCOM) {
4414
0
        builder.addCapability(spv::Capability::CooperativeMatrixConversionQCOM);
4415
0
        builder.addExtension(spv::E_SPV_QCOM_cooperative_matrix_conversion);
4416
0
        result = builder.createUnaryOp(spv::Op::OpCompositeConstructCoopMatQCOM, resultType(), operands[0]);
4417
5.27k
    } else if (node->getOp() == glslang::EOpCompositeExtractCoopMatQCOM) {
4418
0
        builder.addCapability(spv::Capability::CooperativeMatrixConversionQCOM);
4419
0
        builder.addExtension(spv::E_SPV_QCOM_cooperative_matrix_conversion);
4420
0
        result = builder.createUnaryOp(spv::Op::OpCompositeExtractCoopMatQCOM, resultType(), operands[0]);
4421
5.27k
    } else if (node->getOp() == glslang::EOpExtractSubArrayQCOM) {
4422
0
        builder.addCapability(spv::Capability::CooperativeMatrixConversionQCOM);
4423
0
        builder.addExtension(spv::E_SPV_QCOM_cooperative_matrix_conversion);
4424
4425
0
        std::vector<spv::Id> arguments { operands[0], operands[1] };;
4426
0
        result = builder.createOp(spv::Op::OpExtractSubArrayQCOM, resultType(), arguments);
4427
5.27k
    } else if (node->getOp() == glslang::EOpCooperativeVectorMatMulNV ||
4428
5.27k
               node->getOp() == glslang::EOpCooperativeVectorMatMulAddNV) {
4429
0
        auto matrixOperands = spv::CooperativeMatrixOperandsMask::MaskNone;
4430
4431
0
        bool isMulAdd = node->getOp() == glslang::EOpCooperativeVectorMatMulAddNV;
4432
4433
        // Determine Cooperative Matrix Operands bits from the signedness of the types.
4434
4435
0
        if (isTypeSignedInt(glslangOperands[1]->getAsTyped()->getBasicType()))
4436
0
            addMask(matrixOperands, spv::CooperativeMatrixOperandsMask::MatrixBSignedComponentsKHR);
4437
0
        if (isTypeSignedInt(glslangOperands[0]->getAsTyped()->getBasicType()))
4438
0
            addMask(matrixOperands, spv::CooperativeMatrixOperandsMask::MatrixResultSignedComponentsKHR);
4439
4440
0
        uint32_t opIdx = 1;
4441
0
        std::vector<spv::IdImmediate> idImmOps;
4442
0
        idImmOps.push_back(spv::IdImmediate(true, operands[opIdx++])); // Input
4443
0
        idImmOps.push_back(spv::IdImmediate(true, operands[opIdx++])); // InputInterpretation
4444
0
        idImmOps.push_back(spv::IdImmediate(true, operands[opIdx++])); // Matrix
4445
0
        idImmOps.push_back(spv::IdImmediate(true, operands[opIdx++])); // MatrixOffset
4446
0
        idImmOps.push_back(spv::IdImmediate(true, operands[opIdx++])); // MatrixInterpretation
4447
0
        if (isMulAdd) {
4448
0
            idImmOps.push_back(spv::IdImmediate(true, operands[opIdx++])); // Bias
4449
0
            idImmOps.push_back(spv::IdImmediate(true, operands[opIdx++])); // BiasOffset
4450
0
            idImmOps.push_back(spv::IdImmediate(true, operands[opIdx++])); // BiasInterpretation
4451
0
        }
4452
0
        idImmOps.push_back(spv::IdImmediate(true, operands[opIdx++])); // M
4453
0
        idImmOps.push_back(spv::IdImmediate(true, operands[opIdx++])); // K
4454
0
        idImmOps.push_back(spv::IdImmediate(true, operands[opIdx++])); // MemoryLayout
4455
0
        idImmOps.push_back(spv::IdImmediate(true, operands[opIdx++])); // Transpose
4456
0
        idImmOps.push_back(spv::IdImmediate(true, operands[opIdx++])); // MatrixStride
4457
0
        if (matrixOperands != spv::CooperativeMatrixOperandsMask::MaskNone)
4458
0
            idImmOps.push_back(spv::IdImmediate(false, matrixOperands));  // Cooperative Matrix Operands
4459
4460
        // get the pointee type
4461
0
        spv::Id typeId = builder.getContainedTypeId(builder.getTypeId(operands[0]));
4462
0
        assert(builder.isCooperativeVectorType(typeId));
4463
        // do the op
4464
0
        spv::Id result = builder.createOp(isMulAdd ? spv::Op::OpCooperativeVectorMatrixMulAddNV : spv::Op::OpCooperativeVectorMatrixMulNV, typeId, idImmOps);
4465
        // store the result to the pointer (out param 'res')
4466
0
        builder.createStore(result, operands[0]);
4467
0
        result = 0;
4468
5.27k
    } else if (node->getOp() == glslang::EOpCooperativeVectorLoadNV) {
4469
0
        std::vector<spv::IdImmediate> idImmOps;
4470
4471
0
        idImmOps.push_back(spv::IdImmediate(true, operands[1])); // buf
4472
0
        idImmOps.push_back(spv::IdImmediate(true, operands[2])); // offset
4473
0
        idImmOps.insert(idImmOps.end(), memoryAccessOperands.begin(), memoryAccessOperands.end());
4474
        // get the pointee type
4475
0
        spv::Id typeId = builder.getContainedTypeId(builder.getTypeId(operands[0]));
4476
0
        assert(builder.isCooperativeVectorType(typeId));
4477
        // do the op
4478
0
        spv::Id result = builder.createOp(spv::Op::OpCooperativeVectorLoadNV, typeId, idImmOps);
4479
        // store the result to the pointer (out param 'v')
4480
0
        builder.createStore(result, operands[0]);
4481
0
        result = 0;
4482
5.27k
    } else if (node->getOp() == glslang::EOpCooperativeVectorStoreNV) {
4483
0
        std::vector<spv::IdImmediate> idImmOps;
4484
4485
0
        idImmOps.push_back(spv::IdImmediate(true, operands[1])); // buf
4486
0
        idImmOps.push_back(spv::IdImmediate(true, operands[2])); // offset
4487
0
        idImmOps.push_back(spv::IdImmediate(true, operands[0])); // object
4488
0
        idImmOps.insert(idImmOps.end(), memoryAccessOperands.begin(), memoryAccessOperands.end());
4489
0
        builder.createNoResultOp(spv::Op::OpCooperativeVectorStoreNV, idImmOps);
4490
0
        result = 0;
4491
5.27k
    } else if (node->getOp() == glslang::EOpCooperativeVectorOuterProductAccumulateNV) {
4492
0
        builder.addCapability(spv::Capability::CooperativeVectorTrainingNV);
4493
0
        builder.addExtension(spv::E_SPV_NV_cooperative_vector);
4494
4495
0
        std::vector<spv::IdImmediate> idImmOps;
4496
4497
0
        idImmOps.push_back(spv::IdImmediate(true, operands[2])); // Matrix
4498
0
        idImmOps.push_back(spv::IdImmediate(true, operands[3])); // Offset
4499
0
        idImmOps.push_back(spv::IdImmediate(true, operands[0])); // A
4500
0
        idImmOps.push_back(spv::IdImmediate(true, operands[1])); // B
4501
0
        idImmOps.push_back(spv::IdImmediate(true, operands[5])); // MemoryLayout
4502
0
        idImmOps.push_back(spv::IdImmediate(true, operands[6])); // MatrixInterpretation
4503
0
        idImmOps.push_back(spv::IdImmediate(true, operands[4])); // Stride
4504
0
        builder.createNoResultOp(spv::Op::OpCooperativeVectorOuterProductAccumulateNV, idImmOps);
4505
0
        result = 0;
4506
5.27k
    } else if (node->getOp() == glslang::EOpCooperativeVectorReduceSumAccumulateNV) {
4507
0
        builder.addCapability(spv::Capability::CooperativeVectorTrainingNV);
4508
0
        builder.addExtension(spv::E_SPV_NV_cooperative_vector);
4509
4510
0
        std::vector<spv::IdImmediate> idImmOps;
4511
4512
0
        idImmOps.push_back(spv::IdImmediate(true, operands[1])); // Buf
4513
0
        idImmOps.push_back(spv::IdImmediate(true, operands[2])); // Offset
4514
0
        idImmOps.push_back(spv::IdImmediate(true, operands[0])); // A
4515
0
        builder.createNoResultOp(spv::Op::OpCooperativeVectorReduceSumAccumulateNV, idImmOps);
4516
0
        result = 0;
4517
5.27k
    } else if (node->getOp() == glslang::EOpTensorReadARM ||
4518
5.27k
               node->getOp() == glslang::EOpTensorWriteARM) {
4519
1
        const bool isWrite = node->getOp() == glslang::EOpTensorWriteARM;
4520
1
        const unsigned int tensorMinOperandCount = 3;
4521
1
        assert(operands.size() >= tensorMinOperandCount);
4522
1
        std::vector<spv::IdImmediate> idImmOps;
4523
4524
1
        idImmOps.push_back(spv::IdImmediate(true, operands[0])); // tensor
4525
1
        idImmOps.push_back(spv::IdImmediate(true, operands[1])); // coords
4526
1
        if (isWrite) {
4527
0
            idImmOps.push_back(spv::IdImmediate(true, operands[2])); // value
4528
0
        }
4529
4530
        // Analyze the tensor operands
4531
1
        spv::IdImmediate tensorOperands = { false, uint32_t(spv::TensorOperandsMask::MaskNone) };
4532
1
        bool pushExtraArg = false;
4533
1
        if (operands.size() > tensorMinOperandCount) {
4534
1
            auto enumVal = builder.getConstantScalar(operands[tensorMinOperandCount]);
4535
4536
1
            if (enumVal & uint32_t(spv::TensorOperandsMask::NontemporalARM)) {
4537
0
                tensorOperands.word |= uint32_t(spv::TensorOperandsMask::NontemporalARM);
4538
0
            }
4539
1
            if (enumVal & uint32_t(spv::TensorOperandsMask::OutOfBoundsValueARM)) {
4540
0
                tensorOperands.word |= uint32_t(spv::TensorOperandsMask::OutOfBoundsValueARM);
4541
0
                assert(operands.size() >= tensorMinOperandCount + 2 &&
4542
0
                    "TensorOperandsOutOfBoundsValueMask requires an additional value");
4543
0
                pushExtraArg = true;
4544
0
            }
4545
1
        }
4546
4547
        // Append optional tensor operands if the mask was non-zero.
4548
1
        if (tensorOperands.word) {
4549
0
            idImmOps.push_back(tensorOperands);
4550
0
            if (pushExtraArg)
4551
0
                idImmOps.push_back(spv::IdImmediate(true, operands[tensorMinOperandCount + 1]));
4552
0
        }
4553
4554
1
        if (isWrite) {
4555
0
            builder.createNoResultOp(spv::Op::OpTensorWriteARM, idImmOps);
4556
0
            result = 0;
4557
1
        } else {
4558
            // Use the result argument type as the OpTensorReadARM result type.
4559
1
            const glslang::TType &resArgType = glslangOperands[2]->getAsTyped()->getType();
4560
1
            spv::Id retType = convertGlslangToSpvType(resArgType);
4561
1
            result = builder.createOp(spv::Op::OpTensorReadARM, retType, idImmOps);
4562
            // Store the result to the result argument.
4563
1
            builder.createStore(result, operands[2]);
4564
1
        }
4565
5.27k
    } else if (node->getOp() == glslang::EOpTensorSizeARM) {
4566
        // Expected operands are (tensor, dimension)
4567
2
        assert(operands.size() == 2);
4568
4569
2
        spv::Id tensorOp = operands[0];
4570
2
        spv::Id dimOp = operands[1];
4571
2
        assert(builder.isTensorTypeARM(builder.getTypeId(tensorOp)) && "operand #0 must be a tensor");
4572
4573
2
        std::vector<spv::IdImmediate> idImmOps;
4574
2
        idImmOps.push_back(spv::IdImmediate(true, tensorOp));
4575
2
        idImmOps.push_back(spv::IdImmediate(true, dimOp));
4576
2
        result = builder.createOp(spv::Op::OpTensorQuerySizeARM, resultType(), idImmOps);
4577
5.27k
    } else if (atomic) {
4578
        // Handle all atomics
4579
294
        glslang::TBasicType typeProxy = (node->getOp() == glslang::EOpAtomicStore)
4580
294
            ? node->getSequence()[0]->getAsTyped()->getBasicType() : node->getBasicType();
4581
294
        result = createAtomicOperation(node->getOp(), precision, resultType(), operands, typeProxy,
4582
294
            lvalueCoherentFlags, node->getType());
4583
4.97k
    } else if (node->getOp() == glslang::EOpSpirvInst) {
4584
46
        const auto& spirvInst = node->getSpirvInstruction();
4585
46
        if (spirvInst.set == "") {
4586
0
            std::vector<spv::IdImmediate> idImmOps;
4587
0
            for (unsigned int i = 0; i < glslangOperands.size(); ++i) {
4588
0
                if (glslangOperands[i]->getAsTyped()->getQualifier().isSpirvLiteral()) {
4589
                    // Translate the constant to a literal value
4590
0
                    std::vector<unsigned> literals;
4591
0
                    glslang::TVector<const glslang::TIntermConstantUnion*> constants;
4592
0
                    constants.push_back(glslangOperands[i]->getAsConstantUnion());
4593
0
                    TranslateLiterals(constants, literals);
4594
0
                    idImmOps.push_back({false, literals[0]});
4595
0
                } else
4596
0
                    idImmOps.push_back({true, operands[i]});
4597
0
            }
4598
4599
0
            if (node->getBasicType() == glslang::EbtVoid)
4600
0
                builder.createNoResultOp(static_cast<spv::Op>(spirvInst.id), idImmOps);
4601
0
            else
4602
0
                result = builder.createOp(static_cast<spv::Op>(spirvInst.id), resultType(), idImmOps);
4603
46
        } else {
4604
46
            result = builder.createBuiltinCall(
4605
46
                resultType(), spirvInst.set == "GLSL.std.450" ? stdBuiltins : getExtBuiltins(spirvInst.set.c_str()),
4606
46
                spirvInst.id, operands);
4607
46
        }
4608
46
        noReturnValue = node->getBasicType() == glslang::EbtVoid;
4609
4.93k
    } else if (node->getOp() == glslang::EOpDebugPrintf) {
4610
51
        if (!nonSemanticDebugPrintf) {
4611
19
            nonSemanticDebugPrintf = builder.import("NonSemantic.DebugPrintf");
4612
19
        }
4613
51
        result = builder.createBuiltinCall(builder.makeVoidType(), nonSemanticDebugPrintf, spv::NonSemanticDebugPrintfDebugPrintf, operands);
4614
51
        builder.addExtension(spv::E_SPV_KHR_non_semantic_info);
4615
4.88k
    } else {
4616
        // Pass through to generic operations.
4617
4.88k
        switch (glslangOperands.size()) {
4618
5
        case 0:
4619
5
            result = createNoArgOperation(node->getOp(), precision, resultType());
4620
5
            break;
4621
0
        case 1:
4622
0
            {
4623
0
                OpDecorations decorations = { precision,
4624
0
                                              TranslateNoContractionDecoration(node->getType().getQualifier()),
4625
0
                                              TranslateNonUniformDecoration(node->getType().getQualifier()) };
4626
0
                result = createUnaryOperation(
4627
0
                    node->getOp(), decorations,
4628
0
                    resultType(), operands.front(),
4629
0
                    glslangOperands[0]->getAsTyped()->getBasicType(), lvalueCoherentFlags, node->getType());
4630
0
            }
4631
0
            break;
4632
4.87k
        default:
4633
4.87k
            result = createMiscOperation(node->getOp(), precision, resultType(), operands, node->getBasicType());
4634
4.87k
            break;
4635
4.88k
        }
4636
4637
4.88k
        if (invertedType != spv::NoResult)
4638
0
            result = createInvertedSwizzle(precision, *glslangOperands[0]->getAsBinaryNode(), result);
4639
4640
4.88k
        for (unsigned int i = 0; i < temporaryLvalues.size(); ++i) {
4641
0
            builder.setAccessChain(complexLvalues[i]);
4642
0
            builder.accessChainStore(builder.createLoad(temporaryLvalues[i], spv::NoPrecision),
4643
0
                TranslateNonUniformDecoration(complexLvalues[i].coherentFlags));
4644
0
        }
4645
4.88k
    }
4646
4647
5.27k
    if (noReturnValue)
4648
127
        return false;
4649
4650
5.14k
    if (! result) {
4651
0
        logger->missingFunctionality("unknown glslang aggregate");
4652
0
        return true;  // pick up a child as a placeholder operand
4653
5.14k
    } else {
4654
5.14k
        builder.clearAccessChain();
4655
5.14k
        builder.setAccessChainRValue(result);
4656
5.14k
        return false;
4657
5.14k
    }
4658
5.14k
}
4659
4660
// This path handles both if-then-else and ?:
4661
// The if-then-else has a node type of void, while
4662
// ?: has either a void or a non-void node type
4663
//
4664
// Leaving the result, when not void:
4665
// GLSL only has r-values as the result of a :?, but
4666
// if we have an l-value, that can be more efficient if it will
4667
// become the base of a complex r-value expression, because the
4668
// next layer copies r-values into memory to use the access-chain mechanism
4669
bool TGlslangToSpvTraverser::visitSelection(glslang::TVisit /* visit */, glslang::TIntermSelection* node)
4670
2.00k
{
4671
    // see if OpSelect can handle it
4672
2.00k
    const auto isOpSelectable = [&]() {
4673
152
        if (node->getBasicType() == glslang::EbtVoid)
4674
19
            return false;
4675
        // OpSelect can do all other types starting with SPV 1.4
4676
133
        if (glslangIntermediate->getSpv().spv < glslang::EShTargetSpv_1_4) {
4677
            // pre-1.4, only scalars and vectors can be handled
4678
133
            if ((!node->getType().isScalar() && !node->getType().isVector()))
4679
2
                return false;
4680
133
        }
4681
131
        return true;
4682
133
    };
4683
4684
    // See if it simple and safe, or required, to execute both sides.
4685
    // Crucially, side effects must be either semantically required or avoided,
4686
    // and there are performance trade-offs.
4687
    // Return true if required or a good idea (and safe) to execute both sides,
4688
    // false otherwise.
4689
2.00k
    const auto bothSidesPolicy = [&]() -> bool {
4690
        // do we have both sides?
4691
2.00k
        if (node->getTrueBlock()  == nullptr ||
4692
1.85k
            node->getFalseBlock() == nullptr)
4693
1.91k
            return false;
4694
4695
        // required? (unless we write additional code to look for side effects
4696
        // and make performance trade-offs if none are present)
4697
90
        if (!node->getShortCircuit())
4698
0
            return true;
4699
4700
        // if not required to execute both, decide based on performance/practicality...
4701
4702
90
        if (!isOpSelectable())
4703
21
            return false;
4704
4705
90
        assert(node->getType() == node->getTrueBlock() ->getAsTyped()->getType() &&
4706
69
               node->getType() == node->getFalseBlock()->getAsTyped()->getType());
4707
4708
        // return true if a single operand to ? : is okay for OpSelect
4709
133
        const auto operandOkay = [](glslang::TIntermTyped* node) {
4710
133
            return node->getAsSymbolNode() || node->getType().getQualifier().isConstant();
4711
133
        };
4712
4713
69
        return operandOkay(node->getTrueBlock() ->getAsTyped()) &&
4714
64
               operandOkay(node->getFalseBlock()->getAsTyped());
4715
90
    };
4716
4717
2.00k
    spv::Id result = spv::NoResult; // upcoming result selecting between trueValue and falseValue
4718
    // emit the condition before doing anything with selection
4719
2.00k
    node->getCondition()->traverse(this);
4720
2.00k
    spv::Id condition = accessChainLoad(node->getCondition()->getType());
4721
4722
    // Find a way of executing both sides and selecting the right result.
4723
2.00k
    const auto executeBothSides = [&]() -> void {
4724
        // execute both sides
4725
62
        spv::Id resultType = convertGlslangToSpvType(node->getType());
4726
62
        node->getTrueBlock()->traverse(this);
4727
62
        spv::Id trueValue = accessChainLoad(node->getTrueBlock()->getAsTyped()->getType());
4728
62
        node->getFalseBlock()->traverse(this);
4729
62
        spv::Id falseValue = accessChainLoad(node->getFalseBlock()->getAsTyped()->getType());
4730
4731
62
        builder.setDebugSourceLocation(node->getLoc().line, node->getLoc().getFilename());
4732
4733
        // done if void
4734
62
        if (node->getBasicType() == glslang::EbtVoid)
4735
0
            return;
4736
4737
        // emit code to select between trueValue and falseValue
4738
        // see if OpSelect can handle the result type, and that the SPIR-V types
4739
        // of the inputs match the result type.
4740
62
        if (isOpSelectable()) {
4741
            // Emit OpSelect for this selection.
4742
4743
            // smear condition to vector, if necessary (AST is always scalar)
4744
            // Before 1.4, smear like for mix(), starting with 1.4, keep it scalar
4745
62
            if (glslangIntermediate->getSpv().spv < glslang::EShTargetSpv_1_4 && builder.isVector(trueValue)) {
4746
3
                condition = builder.smearScalar(spv::NoPrecision, condition,
4747
3
                                                builder.makeVectorType(builder.makeBoolType(),
4748
3
                                                                       builder.getNumComponents(trueValue)));
4749
3
            }
4750
4751
            // If the types do not match, it is because of mismatched decorations on aggregates.
4752
            // Since isOpSelectable only lets us get here for SPIR-V >= 1.4, we can use OpCopyObject
4753
            // to get matching types.
4754
62
            if (builder.getTypeId(trueValue) != resultType) {
4755
0
                trueValue = builder.createUnaryOp(spv::Op::OpCopyLogical, resultType, trueValue);
4756
0
            }
4757
62
            if (builder.getTypeId(falseValue) != resultType) {
4758
0
                falseValue = builder.createUnaryOp(spv::Op::OpCopyLogical, resultType, falseValue);
4759
0
            }
4760
4761
            // OpSelect
4762
62
            result = builder.createTriOp(spv::Op::OpSelect, resultType, condition, trueValue, falseValue);
4763
4764
62
            builder.clearAccessChain();
4765
62
            builder.setAccessChainRValue(result);
4766
62
        } else {
4767
            // We need control flow to select the result.
4768
            // TODO: Once SPIR-V OpSelect allows arbitrary types, eliminate this path.
4769
0
            result = builder.createVariable(TranslatePrecisionDecoration(node->getType()),
4770
0
                spv::StorageClass::Function, resultType);
4771
4772
            // Selection control:
4773
0
            const spv::SelectionControlMask control = TranslateSelectionControl(*node);
4774
4775
            // make an "if" based on the value created by the condition
4776
0
            spv::Builder::If ifBuilder(condition, control, builder);
4777
4778
            // emit the "then" statement
4779
0
            builder.clearAccessChain();
4780
0
            builder.setAccessChainLValue(result);
4781
0
            multiTypeStore(node->getType(), trueValue);
4782
4783
0
            ifBuilder.makeBeginElse();
4784
            // emit the "else" statement
4785
0
            builder.clearAccessChain();
4786
0
            builder.setAccessChainLValue(result);
4787
0
            multiTypeStore(node->getType(), falseValue);
4788
4789
            // finish off the control flow
4790
0
            ifBuilder.makeEndIf();
4791
4792
0
            builder.clearAccessChain();
4793
0
            builder.setAccessChainLValue(result);
4794
0
        }
4795
62
    };
4796
4797
    // Execute the one side needed, as per the condition
4798
2.00k
    const auto executeOneSide = [&]() {
4799
        // Always emit control flow.
4800
1.94k
        if (node->getBasicType() != glslang::EbtVoid) {
4801
9
            result = builder.createVariable(TranslatePrecisionDecoration(node->getType()), spv::StorageClass::Function,
4802
9
                convertGlslangToSpvType(node->getType()));
4803
9
        }
4804
4805
        // Selection control:
4806
1.94k
        const spv::SelectionControlMask control = TranslateSelectionControl(*node);
4807
4808
        // make an "if" based on the value created by the condition
4809
1.94k
        spv::Builder::If ifBuilder(condition, control, builder);
4810
4811
        // emit the "then" statement
4812
1.94k
        if (node->getTrueBlock() != nullptr) {
4813
1.78k
            node->getTrueBlock()->traverse(this);
4814
1.78k
            if (result != spv::NoResult) {
4815
9
                spv::Id load = accessChainLoad(node->getTrueBlock()->getAsTyped()->getType());
4816
4817
9
                builder.clearAccessChain();
4818
9
                builder.setAccessChainLValue(result);
4819
9
                multiTypeStore(node->getType(), load);
4820
9
            }
4821
1.78k
        }
4822
4823
1.94k
        if (node->getFalseBlock() != nullptr) {
4824
28
            ifBuilder.makeBeginElse();
4825
            // emit the "else" statement
4826
28
            node->getFalseBlock()->traverse(this);
4827
28
            if (result != spv::NoResult) {
4828
9
                spv::Id load = accessChainLoad(node->getFalseBlock()->getAsTyped()->getType());
4829
4830
9
                builder.clearAccessChain();
4831
9
                builder.setAccessChainLValue(result);
4832
9
                multiTypeStore(node->getType(), load);
4833
9
            }
4834
28
        }
4835
4836
        // finish off the control flow
4837
1.94k
        ifBuilder.makeEndIf();
4838
4839
1.94k
        if (result != spv::NoResult) {
4840
9
            builder.clearAccessChain();
4841
9
            builder.setAccessChainLValue(result);
4842
9
        }
4843
1.94k
    };
4844
4845
    // Try for OpSelect (or a requirement to execute both sides)
4846
2.00k
    if (bothSidesPolicy()) {
4847
62
        SpecConstantOpModeGuard spec_constant_op_mode_setter(&builder);
4848
62
        if (node->getType().getQualifier().isSpecConstant())
4849
0
            spec_constant_op_mode_setter.turnOnSpecConstantOpMode();
4850
62
        executeBothSides();
4851
62
    } else
4852
1.94k
        executeOneSide();
4853
4854
2.00k
    return false;
4855
2.00k
}
4856
4857
bool TGlslangToSpvTraverser::visitSwitch(glslang::TVisit /* visit */, glslang::TIntermSwitch* node)
4858
353
{
4859
    // emit and get the condition before doing anything with switch
4860
353
    node->getCondition()->traverse(this);
4861
353
    spv::Id selector = accessChainLoad(node->getCondition()->getAsTyped()->getType());
4862
4863
    // Selection control:
4864
353
    const spv::SelectionControlMask control = TranslateSwitchControl(*node);
4865
4866
    // browse the children to sort out code segments
4867
353
    int defaultSegment = -1;
4868
353
    std::vector<TIntermNode*> codeSegments;
4869
353
    glslang::TIntermSequence& sequence = node->getBody()->getSequence();
4870
353
    std::vector<int> caseValues;
4871
353
    std::vector<int> valueIndexToSegment(sequence.size());  // note: probably not all are used, it is an overestimate
4872
2.71k
    for (glslang::TIntermSequence::iterator c = sequence.begin(); c != sequence.end(); ++c) {
4873
2.36k
        TIntermNode* child = *c;
4874
2.36k
        if (child->getAsBranchNode() && child->getAsBranchNode()->getFlowOp() == glslang::EOpDefault)
4875
15
            defaultSegment = (int)codeSegments.size();
4876
2.35k
        else if (child->getAsBranchNode() && child->getAsBranchNode()->getFlowOp() == glslang::EOpCase) {
4877
1.16k
            valueIndexToSegment[caseValues.size()] = (int)codeSegments.size();
4878
1.16k
            caseValues.push_back(child->getAsBranchNode()->getExpression()->getAsConstantUnion()
4879
1.16k
                ->getConstArray()[0].getIConst());
4880
1.16k
        } else
4881
1.18k
            codeSegments.push_back(child);
4882
2.36k
    }
4883
4884
    // handle the case where the last code segment is missing, due to no code
4885
    // statements between the last case and the end of the switch statement
4886
353
    if ((caseValues.size() && (int)codeSegments.size() == valueIndexToSegment[caseValues.size() - 1]) ||
4887
353
        (int)codeSegments.size() == defaultSegment)
4888
0
        codeSegments.push_back(nullptr);
4889
4890
    // make the switch statement
4891
353
    std::vector<spv::Block*> segmentBlocks; // returned, as the blocks allocated in the call
4892
353
    builder.makeSwitch(selector, control, (int)codeSegments.size(), caseValues, valueIndexToSegment, defaultSegment,
4893
353
        segmentBlocks);
4894
4895
    // emit all the code in the segments
4896
353
    breakForLoop.push(false);
4897
1.53k
    for (unsigned int s = 0; s < codeSegments.size(); ++s) {
4898
1.18k
        builder.nextSwitchSegment(segmentBlocks, s);
4899
1.18k
        if (codeSegments[s])
4900
1.18k
            codeSegments[s]->traverse(this);
4901
0
        else
4902
0
            builder.addSwitchBreak(true);
4903
1.18k
    }
4904
353
    breakForLoop.pop();
4905
4906
353
    builder.endSwitch(segmentBlocks);
4907
4908
353
    return false;
4909
353
}
4910
4911
void TGlslangToSpvTraverser::visitConstantUnion(glslang::TIntermConstantUnion* node)
4912
20.6k
{
4913
20.6k
    if (node->getQualifier().isSpirvLiteral())
4914
0
        return; // Translated to a literal value, skip further processing
4915
4916
20.6k
    int nextConst = 0;
4917
20.6k
    spv::Id constant = createSpvConstantFromConstUnionArray(node->getType(), node->getConstArray(), nextConst, false);
4918
4919
20.6k
    builder.clearAccessChain();
4920
20.6k
    builder.setAccessChainRValue(constant);
4921
20.6k
}
4922
4923
bool TGlslangToSpvTraverser::visitLoop(glslang::TVisit /* visit */, glslang::TIntermLoop* node)
4924
1.47k
{
4925
1.47k
    auto blocks = builder.makeNewLoop();
4926
1.47k
    builder.createBranch(true, &blocks.head);
4927
4928
    // Loop control:
4929
1.47k
    std::vector<unsigned int> operands;
4930
1.47k
    const spv::LoopControlMask control = TranslateLoopControl(*node, operands);
4931
4932
    // Spec requires back edges to target header blocks, and every header block
4933
    // must dominate its merge block.  Make a header block first to ensure these
4934
    // conditions are met.  By definition, it will contain OpLoopMerge, followed
4935
    // by a block-ending branch.  But we don't want to put any other body/test
4936
    // instructions in it, since the body/test may have arbitrary instructions,
4937
    // including merges of its own.
4938
1.47k
    builder.setBuildPoint(&blocks.head);
4939
1.47k
    builder.setDebugSourceLocation(node->getLoc().line, node->getLoc().getFilename());
4940
1.47k
    builder.createLoopMerge(&blocks.merge, &blocks.continue_target, control, operands);
4941
1.47k
    if (node->testFirst() && node->getTest()) {
4942
1.29k
        spv::Block& test = builder.makeNewBlock();
4943
1.29k
        builder.createBranch(true, &test);
4944
4945
1.29k
        builder.setBuildPoint(&test);
4946
1.29k
        node->getTest()->traverse(this);
4947
1.29k
        spv::Id condition = accessChainLoad(node->getTestExpr()->getType());
4948
1.29k
        builder.createConditionalBranch(condition, &blocks.body, &blocks.merge);
4949
4950
1.29k
        builder.setBuildPoint(&blocks.body);
4951
1.29k
        breakForLoop.push(true);
4952
1.29k
        if (node->getBody())
4953
731
            node->getBody()->traverse(this);
4954
1.29k
        builder.createBranch(true, &blocks.continue_target);
4955
1.29k
        breakForLoop.pop();
4956
4957
1.29k
        builder.setBuildPoint(&blocks.continue_target);
4958
1.29k
        if (node->getTerminal())
4959
1.08k
            node->getTerminal()->traverse(this);
4960
1.29k
        builder.createBranch(true, &blocks.head);
4961
1.29k
    } else {
4962
185
        builder.setDebugSourceLocation(node->getLoc().line, node->getLoc().getFilename());
4963
185
        builder.createBranch(true, &blocks.body);
4964
4965
185
        breakForLoop.push(true);
4966
185
        builder.setBuildPoint(&blocks.body);
4967
185
        if (node->getBody())
4968
0
            node->getBody()->traverse(this);
4969
185
        builder.createBranch(true, &blocks.continue_target);
4970
185
        breakForLoop.pop();
4971
4972
185
        builder.setBuildPoint(&blocks.continue_target);
4973
185
        if (node->getTerminal())
4974
1
            node->getTerminal()->traverse(this);
4975
185
        if (node->getTest()) {
4976
153
            node->getTest()->traverse(this);
4977
153
            spv::Id condition =
4978
153
                accessChainLoad(node->getTestExpr()->getType());
4979
153
            builder.createConditionalBranch(condition, &blocks.head, &blocks.merge);
4980
153
        } else {
4981
            // TODO: unless there was a break/return/discard instruction
4982
            // somewhere in the body, this is an infinite loop, so we should
4983
            // issue a warning.
4984
32
            builder.createBranch(true, &blocks.head);
4985
32
        }
4986
185
    }
4987
1.47k
    builder.setBuildPoint(&blocks.merge);
4988
1.47k
    builder.closeLoop();
4989
1.47k
    return false;
4990
1.47k
}
4991
4992
bool TGlslangToSpvTraverser::visitBranch(glslang::TVisit /* visit */, glslang::TIntermBranch* node)
4993
2.25k
{
4994
2.25k
    if (node->getExpression())
4995
885
        node->getExpression()->traverse(this);
4996
4997
2.25k
    builder.setDebugSourceLocation(node->getLoc().line, node->getLoc().getFilename());
4998
4999
2.25k
    switch (node->getFlowOp()) {
5000
6
    case glslang::EOpKill:
5001
6
        if (glslangIntermediate->getSpv().spv >= glslang::EShTargetSpv_1_6) {
5002
0
            builder.addCapability(spv::Capability::DemoteToHelperInvocation);
5003
0
            builder.createNoResultOp(spv::Op::OpDemoteToHelperInvocationEXT);
5004
6
        } else {
5005
6
            builder.makeStatementTerminator(spv::Op::OpKill, "post-discard");
5006
6
        }
5007
6
        break;
5008
1
    case glslang::EOpTerminateInvocation:
5009
1
        builder.addExtension(spv::E_SPV_KHR_terminate_invocation);
5010
1
        builder.makeStatementTerminator(spv::Op::OpTerminateInvocation, "post-terminate-invocation");
5011
1
        break;
5012
1.16k
    case glslang::EOpBreak:
5013
1.16k
        if (breakForLoop.top())
5014
1
            builder.createLoopExit();
5015
1.16k
        else
5016
1.16k
            builder.addSwitchBreak(false);
5017
1.16k
        break;
5018
1
    case glslang::EOpContinue:
5019
1
        builder.createLoopContinue();
5020
1
        break;
5021
1.07k
    case glslang::EOpReturn:
5022
1.07k
        if (node->getExpression() != nullptr) {
5023
885
            const glslang::TType& glslangReturnType = node->getExpression()->getType();
5024
885
            spv::Id returnId = accessChainLoad(glslangReturnType);
5025
885
            if (builder.getTypeId(returnId) != currentFunction->getReturnType() ||
5026
885
                TranslatePrecisionDecoration(glslangReturnType) != currentFunction->getReturnPrecision()) {
5027
23
                builder.clearAccessChain();
5028
23
                spv::Id copyId = builder.createVariable(currentFunction->getReturnPrecision(),
5029
23
                    spv::StorageClass::Function, currentFunction->getReturnType());
5030
23
                builder.setAccessChainLValue(copyId);
5031
23
                multiTypeStore(glslangReturnType, returnId);
5032
23
                returnId = builder.createLoad(copyId, currentFunction->getReturnPrecision());
5033
23
            }
5034
885
            builder.makeReturn(false, returnId);
5035
885
        } else
5036
188
            builder.makeReturn(false);
5037
5038
1.07k
        builder.clearAccessChain();
5039
1.07k
        break;
5040
5041
3
    case glslang::EOpDemote:
5042
3
        builder.createNoResultOp(spv::Op::OpDemoteToHelperInvocationEXT);
5043
3
        builder.addExtension(spv::E_SPV_EXT_demote_to_helper_invocation);
5044
3
        builder.addCapability(spv::Capability::DemoteToHelperInvocationEXT);
5045
3
        break;
5046
0
    case glslang::EOpTerminateRayKHR:
5047
0
        builder.makeStatementTerminator(spv::Op::OpTerminateRayKHR, "post-terminateRayKHR");
5048
0
        break;
5049
0
    case glslang::EOpIgnoreIntersectionKHR:
5050
0
        builder.makeStatementTerminator(spv::Op::OpIgnoreIntersectionKHR, "post-ignoreIntersectionKHR");
5051
0
        break;
5052
5053
0
    default:
5054
0
        assert(0);
5055
0
        break;
5056
2.25k
    }
5057
5058
2.25k
    return false;
5059
2.25k
}
5060
5061
bool TGlslangToSpvTraverser::visitVariableDecl(glslang::TVisit visit, glslang::TIntermVariableDecl* node)
5062
0
{
5063
0
    if (visit == glslang::EvPreVisit) {
5064
0
        builder.setDebugSourceLocation(node->getDeclSymbol()->getLoc().line, node->getDeclSymbol()->getLoc().getFilename());
5065
        // We touch the symbol once here to create the debug info.
5066
0
        getSymbolId(node->getDeclSymbol());
5067
0
    }
5068
5069
0
    return true;
5070
0
}
5071
5072
5073
spv::Id TGlslangToSpvTraverser::createSpvVariable(const glslang::TIntermSymbol* node, spv::Id forcedType)
5074
21.5k
{
5075
    // First, steer off constants, which are not SPIR-V variables, but
5076
    // can still have a mapping to a SPIR-V Id.
5077
    // This includes specialization constants.
5078
21.5k
    if (node->getQualifier().isConstant()) {
5079
905
        spv::Id result = createSpvConstant(*node);
5080
905
        if (result != spv::NoResult) {
5081
905
            auto name = node->getAsSymbolNode()->getAccessName().c_str();
5082
905
            auto typeId = convertGlslangToSpvType(node->getType());
5083
905
            builder.createConstVariable(typeId, name, result, currentFunction == nullptr);
5084
905
            return result;
5085
905
        }
5086
905
    }
5087
5088
    // Now, handle actual variables
5089
20.6k
    spv::StorageClass storageClass = TranslateStorageClass(node->getType());
5090
20.6k
    spv::Id spvType = forcedType == spv::NoType ? convertGlslangToSpvType(node->getType())
5091
20.6k
                                                : forcedType;
5092
5093
20.6k
    const bool contains16BitType = node->getType().contains16BitFloat() ||
5094
20.4k
                                   node->getType().contains16BitInt();
5095
20.6k
    if (contains16BitType) {
5096
525
        switch (storageClass) {
5097
28
        case spv::StorageClass::Input:
5098
28
        case spv::StorageClass::Output:
5099
28
            builder.addIncorporatedExtension(spv::E_SPV_KHR_16bit_storage, spv::Spv_1_3);
5100
28
            builder.addCapability(spv::Capability::StorageInputOutput16);
5101
28
            break;
5102
116
        case spv::StorageClass::Uniform:
5103
116
            builder.addIncorporatedExtension(spv::E_SPV_KHR_16bit_storage, spv::Spv_1_3);
5104
116
            if (node->getType().getQualifier().storage == glslang::EvqBuffer)
5105
45
                builder.addCapability(spv::Capability::StorageUniformBufferBlock16);
5106
71
            else
5107
71
                builder.addCapability(spv::Capability::StorageUniform16);
5108
116
            break;
5109
0
        case spv::StorageClass::PushConstant:
5110
0
            builder.addIncorporatedExtension(spv::E_SPV_KHR_16bit_storage, spv::Spv_1_3);
5111
0
            builder.addCapability(spv::Capability::StoragePushConstant16);
5112
0
            break;
5113
0
        case spv::StorageClass::StorageBuffer:
5114
0
        case spv::StorageClass::PhysicalStorageBufferEXT:
5115
0
            builder.addIncorporatedExtension(spv::E_SPV_KHR_16bit_storage, spv::Spv_1_3);
5116
0
            builder.addCapability(spv::Capability::StorageUniformBufferBlock16);
5117
0
            break;
5118
0
        case spv::StorageClass::TileAttachmentQCOM:
5119
0
            builder.addCapability(spv::Capability::TileShadingQCOM);
5120
0
            break;
5121
381
        default:
5122
381
            if (storageClass == spv::StorageClass::Workgroup &&
5123
0
                node->getType().getBasicType() == glslang::EbtBlock) {
5124
0
                builder.addCapability(spv::Capability::WorkgroupMemoryExplicitLayout16BitAccessKHR);
5125
0
                break;
5126
0
            }
5127
381
            if (node->getType().contains16BitFloat())
5128
154
                builder.addCapability(spv::Capability::Float16);
5129
381
            if (node->getType().contains16BitInt())
5130
227
                builder.addCapability(spv::Capability::Int16);
5131
381
            break;
5132
525
        }
5133
525
    }
5134
5135
20.6k
    if (node->getType().contains8BitInt()) {
5136
135
        if (storageClass == spv::StorageClass::PushConstant) {
5137
0
            builder.addIncorporatedExtension(spv::E_SPV_KHR_8bit_storage, spv::Spv_1_5);
5138
0
            builder.addCapability(spv::Capability::StoragePushConstant8);
5139
135
        } else if (storageClass == spv::StorageClass::Uniform) {
5140
45
            builder.addIncorporatedExtension(spv::E_SPV_KHR_8bit_storage, spv::Spv_1_5);
5141
45
            builder.addCapability(spv::Capability::UniformAndStorageBuffer8BitAccess);
5142
90
        } else if (storageClass == spv::StorageClass::StorageBuffer) {
5143
0
            builder.addIncorporatedExtension(spv::E_SPV_KHR_8bit_storage, spv::Spv_1_5);
5144
0
            builder.addCapability(spv::Capability::StorageBuffer8BitAccess);
5145
90
        } else if (storageClass == spv::StorageClass::Workgroup &&
5146
0
                   node->getType().getBasicType() == glslang::EbtBlock) {
5147
0
            builder.addCapability(spv::Capability::WorkgroupMemoryExplicitLayout8BitAccessKHR);
5148
90
        } else {
5149
90
            builder.addCapability(spv::Capability::Int8);
5150
90
        }
5151
135
    }
5152
5153
20.6k
    const char* name = node->getName().c_str();
5154
20.6k
    if (glslang::IsAnonymous(name))
5155
543
        name = "";
5156
5157
20.6k
    spv::Id initializer = spv::NoResult;
5158
5159
20.6k
    if (node->getType().getQualifier().storage == glslang::EvqUniform && !node->getConstArray().empty()) {
5160
0
        int nextConst = 0;
5161
0
        initializer = createSpvConstantFromConstUnionArray(node->getType(),
5162
0
                                                           node->getConstArray(),
5163
0
                                                           nextConst,
5164
0
                                                           false /* specConst */);
5165
20.6k
    } else if (node->getType().getQualifier().isNullInit()) {
5166
0
        initializer = builder.makeNullConstant(spvType);
5167
0
    }
5168
5169
20.6k
    spv::Id var = builder.createVariable(spv::NoPrecision, storageClass, spvType, name, initializer, false);
5170
5171
20.6k
    if (options.emitNonSemanticShaderDebugInfo && storageClass != spv::StorageClass::Function) {
5172
        // Create variable alias for retargeted symbols if any.
5173
        // Notably, this is only applicable to built-in variables so that it is okay to only use name as the key.
5174
0
        auto [itBegin, itEnd] = glslangIntermediate->getBuiltinAliasLookup().equal_range(name);
5175
0
        for (auto it = itBegin; it != itEnd; ++it) {
5176
0
            builder.createDebugGlobalVariable(builder.getDebugType(spvType), it->second.c_str(), var);
5177
0
        }
5178
0
    }
5179
5180
20.6k
    std::vector<spv::Decoration> topLevelDecorations;
5181
20.6k
    glslang::TQualifier typeQualifier = node->getType().getQualifier();
5182
20.6k
    TranslateMemoryDecoration(typeQualifier, topLevelDecorations, glslangIntermediate->usingVulkanMemoryModel());
5183
20.6k
    for (auto deco : topLevelDecorations) {
5184
944
        builder.addDecoration(var, deco);
5185
944
    }
5186
20.6k
    return var;
5187
20.6k
}
5188
5189
// Return type Id of the sampled type.
5190
spv::Id TGlslangToSpvTraverser::getSampledType(const glslang::TSampler& sampler)
5191
3.05k
{
5192
3.05k
    switch (sampler.type) {
5193
103
        case glslang::EbtInt:      return builder.makeIntType(32);
5194
114
        case glslang::EbtUint:     return builder.makeUintType(32);
5195
2.53k
        case glslang::EbtFloat:    return builder.makeFloatType(32);
5196
72
        case glslang::EbtFloat16:
5197
72
            builder.addExtension(spv::E_SPV_AMD_gpu_shader_half_float_fetch);
5198
72
            builder.addCapability(spv::Capability::Float16ImageAMD);
5199
72
            return builder.makeFloatType(16);
5200
117
        case glslang::EbtInt64:
5201
117
            builder.addExtension(spv::E_SPV_EXT_shader_image_int64);
5202
117
            builder.addCapability(spv::Capability::Int64ImageEXT);
5203
117
            return builder.makeIntType(64);
5204
117
        case glslang::EbtUint64:
5205
117
            builder.addExtension(spv::E_SPV_EXT_shader_image_int64);
5206
117
            builder.addCapability(spv::Capability::Int64ImageEXT);
5207
117
            return builder.makeUintType(64);
5208
0
        default:
5209
0
            assert(0);
5210
0
            return builder.makeFloatType(32);
5211
3.05k
    }
5212
3.05k
}
5213
5214
// If node is a swizzle operation, return the type that should be used if
5215
// the swizzle base is first consumed by another operation, before the swizzle
5216
// is applied.
5217
spv::Id TGlslangToSpvTraverser::getInvertedSwizzleType(const glslang::TIntermTyped& node)
5218
0
{
5219
0
    if (node.getAsOperator() &&
5220
0
        node.getAsOperator()->getOp() == glslang::EOpVectorSwizzle)
5221
0
        return convertGlslangToSpvType(node.getAsBinaryNode()->getLeft()->getType());
5222
0
    else
5223
0
        return spv::NoType;
5224
0
}
5225
5226
// When inverting a swizzle with a parent op, this function
5227
// will apply the swizzle operation to a completed parent operation.
5228
spv::Id TGlslangToSpvTraverser::createInvertedSwizzle(spv::Decoration precision, const glslang::TIntermTyped& node,
5229
    spv::Id parentResult)
5230
0
{
5231
0
    std::vector<unsigned> swizzle;
5232
0
    convertSwizzle(*node.getAsBinaryNode()->getRight()->getAsAggregate(), swizzle);
5233
0
    return builder.createRvalueSwizzle(precision, convertGlslangToSpvType(node.getType()), parentResult, swizzle);
5234
0
}
5235
5236
// Convert a glslang AST swizzle node to a swizzle vector for building SPIR-V.
5237
void TGlslangToSpvTraverser::convertSwizzle(const glslang::TIntermAggregate& node, std::vector<unsigned>& swizzle)
5238
4.63k
{
5239
4.63k
    const glslang::TIntermSequence& swizzleSequence = node.getSequence();
5240
17.3k
    for (int i = 0; i < (int)swizzleSequence.size(); ++i)
5241
12.6k
        swizzle.push_back(swizzleSequence[i]->getAsConstantUnion()->getConstArray()[0].getIConst());
5242
4.63k
}
5243
5244
// Convert from a glslang type to an SPV type, by calling into a
5245
// recursive version of this function. This establishes the inherited
5246
// layout state rooted from the top-level type.
5247
spv::Id TGlslangToSpvTraverser::convertGlslangToSpvType(const glslang::TType& type, bool forwardReferenceOnly)
5248
105k
{
5249
105k
    return convertGlslangToSpvType(type, getExplicitLayout(type), type.getQualifier(), false, forwardReferenceOnly);
5250
105k
}
5251
5252
spv::LinkageType TGlslangToSpvTraverser::convertGlslangLinkageToSpv(glslang::TLinkType linkType)
5253
1.21k
{
5254
1.21k
    switch (linkType) {
5255
0
    case glslang::ELinkExport:
5256
0
        return spv::LinkageType::Export;
5257
1.21k
    default:
5258
1.21k
        return spv::LinkageType::Max;
5259
1.21k
    }
5260
1.21k
}
5261
5262
// Do full recursive conversion of an arbitrary glslang type to a SPIR-V Id.
5263
// explicitLayout can be kept the same throughout the hierarchical recursive walk.
5264
// Mutually recursive with convertGlslangStructToSpvType().
5265
spv::Id TGlslangToSpvTraverser::convertGlslangToSpvType(const glslang::TType& type,
5266
    glslang::TLayoutPacking explicitLayout, const glslang::TQualifier& qualifier,
5267
    bool lastBufferBlockMember, bool forwardReferenceOnly)
5268
113k
{
5269
113k
    spv::Id spvType = spv::NoResult;
5270
5271
113k
    switch (type.getBasicType()) {
5272
617
    case glslang::EbtVoid:
5273
617
        spvType = builder.makeVoidType();
5274
617
        assert (! type.isArray());
5275
617
        break;
5276
7.88k
    case glslang::EbtBool:
5277
        // "transparent" bool doesn't exist in SPIR-V.  The GLSL convention is
5278
        // a 32-bit int where non-0 means true.
5279
7.88k
        if (explicitLayout != glslang::ElpNone)
5280
71
            spvType = builder.makeUintType(32);
5281
7.81k
        else
5282
7.81k
            spvType = builder.makeBoolType();
5283
7.88k
        break;
5284
24.8k
    case glslang::EbtInt:
5285
24.8k
        spvType = builder.makeIntType(32);
5286
24.8k
        break;
5287
8.28k
    case glslang::EbtUint:
5288
8.28k
        spvType = builder.makeUintType(32);
5289
8.28k
        break;
5290
44.9k
    case glslang::EbtFloat:
5291
44.9k
        spvType = builder.makeFloatType(32);
5292
44.9k
        break;
5293
103
    case glslang::EbtDouble:
5294
103
        spvType = builder.makeFloatType(64);
5295
103
        break;
5296
6.40k
    case glslang::EbtFloat16:
5297
6.40k
        spvType = builder.makeFloatType(16);
5298
6.40k
        break;
5299
0
    case glslang::EbtBFloat16:
5300
0
        spvType = builder.makeBFloat16Type();
5301
0
        break;
5302
0
    case glslang::EbtFloatE5M2:
5303
0
        spvType = builder.makeFloatE5M2Type();
5304
0
        break;
5305
0
    case glslang::EbtFloatE4M3:
5306
0
        spvType = builder.makeFloatE4M3Type();
5307
0
        break;
5308
744
    case glslang::EbtInt8:
5309
744
        spvType = builder.makeIntType(8);
5310
744
        break;
5311
790
    case glslang::EbtUint8:
5312
790
        spvType = builder.makeUintType(8);
5313
790
        break;
5314
1.65k
    case glslang::EbtInt16:
5315
1.65k
        spvType = builder.makeIntType(16);
5316
1.65k
        break;
5317
1.93k
    case glslang::EbtUint16:
5318
1.93k
        spvType = builder.makeUintType(16);
5319
1.93k
        break;
5320
2.23k
    case glslang::EbtInt64:
5321
2.23k
        spvType = builder.makeIntType(64);
5322
2.23k
        break;
5323
3.08k
    case glslang::EbtUint64:
5324
3.08k
        spvType = builder.makeUintType(64);
5325
3.08k
        break;
5326
0
    case glslang::EbtAtomicUint:
5327
0
        builder.addCapability(spv::Capability::AtomicStorage);
5328
0
        spvType = builder.makeUintType(32);
5329
0
        break;
5330
51
    case glslang::EbtAccStruct:
5331
51
        switch (glslangIntermediate->getStage()) {
5332
0
        case EShLangRayGen:
5333
0
        case EShLangIntersect:
5334
0
        case EShLangAnyHit:
5335
0
        case EShLangClosestHit:
5336
0
        case EShLangMiss:
5337
0
        case EShLangCallable:
5338
            // these all should have the RayTracingNV/KHR capability already
5339
0
            break;
5340
51
        default:
5341
51
            {
5342
51
                auto& extensions = glslangIntermediate->getRequestedExtensions();
5343
51
                if (extensions.find("GL_EXT_ray_query") != extensions.end()) {
5344
51
                    builder.addExtension(spv::E_SPV_KHR_ray_query);
5345
51
                    builder.addCapability(spv::Capability::RayQueryKHR);
5346
51
                }
5347
51
            }
5348
51
            break;
5349
51
        }
5350
51
        spvType = builder.makeAccelerationStructureType();
5351
51
        break;
5352
51
    case glslang::EbtRayQuery:
5353
51
        {
5354
51
            auto& extensions = glslangIntermediate->getRequestedExtensions();
5355
51
            if (extensions.find("GL_EXT_ray_query") != extensions.end()) {
5356
51
                builder.addExtension(spv::E_SPV_KHR_ray_query);
5357
51
                builder.addCapability(spv::Capability::RayQueryKHR);
5358
51
            }
5359
51
            spvType = builder.makeRayQueryType();
5360
51
        }
5361
51
        break;
5362
1.30k
    case glslang::EbtReference:
5363
1.30k
        {
5364
            // Make the forward pointer, then recurse to convert the structure type, then
5365
            // patch up the forward pointer with a real pointer type.
5366
1.30k
            if (forwardPointers.find(type.getReferentType()) == forwardPointers.end()) {
5367
315
                spv::Id forwardId = builder.makeForwardPointer(spv::StorageClass::PhysicalStorageBufferEXT);
5368
315
                forwardPointers[type.getReferentType()] = forwardId;
5369
315
            }
5370
1.30k
            spvType = forwardPointers[type.getReferentType()];
5371
1.30k
            if (!forwardReferenceOnly) {
5372
1.04k
                spv::Id referentType = convertGlslangToSpvType(*type.getReferentType());
5373
1.04k
                builder.makePointerFromForwardPointer(spv::StorageClass::PhysicalStorageBufferEXT,
5374
1.04k
                                                      forwardPointers[type.getReferentType()],
5375
1.04k
                                                      referentType);
5376
1.04k
            }
5377
1.30k
        }
5378
1.30k
        break;
5379
3.25k
    case glslang::EbtSampler:
5380
3.25k
        {
5381
3.25k
            const glslang::TSampler& sampler = type.getSampler();
5382
3.25k
            std::string debugName;
5383
5384
3.25k
            if (sampler.isPureSampler()) {
5385
204
                if (options.emitNonSemanticShaderDebugInfo) {
5386
0
                    if (glslangIntermediate->getSource() == glslang::EShSourceGlsl) {
5387
0
                        debugName = sampler.getString();
5388
0
                    }
5389
0
                    else {
5390
0
                        debugName = "type.sampler";
5391
0
                    }
5392
0
                }
5393
204
                spvType = builder.makeSamplerType(debugName.c_str());
5394
3.05k
            } else {
5395
                // an image is present, make its type
5396
3.05k
                if (options.emitNonSemanticShaderDebugInfo) {
5397
0
                    if (glslangIntermediate->getSource() == glslang::EShSourceGlsl) {
5398
0
                        debugName = sampler.removeCombined().getString();
5399
0
                    }
5400
0
                    else {
5401
0
                        switch (sampler.dim) {
5402
0
                        case glslang::Esd1D:           debugName = "type.1d.image"; break;
5403
0
                        case glslang::Esd2D:           debugName = "type.2d.image"; break;
5404
0
                        case glslang::Esd3D:           debugName = "type.3d.image"; break;
5405
0
                        case glslang::EsdCube:         debugName = "type.cube.image"; break;
5406
0
                        default:                       debugName = "type.image"; break;
5407
0
                        }
5408
0
                    }
5409
0
                }
5410
3.05k
                spvType = builder.makeImageType(getSampledType(sampler), TranslateDimensionality(sampler),
5411
3.05k
                                                sampler.isShadow(), sampler.isArrayed(), sampler.isMultiSample(),
5412
3.05k
                                                sampler.isImageClass() ? 2 : 1, TranslateImageFormat(type), debugName.c_str());
5413
3.05k
                if (sampler.isCombined() &&
5414
1.49k
                    (!sampler.isBuffer() || glslangIntermediate->getSpv().spv < glslang::EShTargetSpv_1_6)) {
5415
                    // Already has both image and sampler, make the combined type. Only combine sampler to
5416
                    // buffer if before SPIR-V 1.6.
5417
1.49k
                    if (options.emitNonSemanticShaderDebugInfo) {
5418
0
                        if (glslangIntermediate->getSource() == glslang::EShSourceGlsl) {
5419
0
                            debugName = sampler.getString();
5420
0
                        }
5421
0
                        else {
5422
0
                            debugName = "type.sampled.image";
5423
0
                        }
5424
0
                    }
5425
1.49k
                    spvType = builder.makeSampledImageType(spvType, debugName.c_str());
5426
1.49k
                }
5427
3.05k
            }
5428
3.25k
        }
5429
3.25k
        break;
5430
3.25k
    case glslang::EbtStruct:
5431
5.10k
    case glslang::EbtBlock:
5432
5.10k
        {
5433
            // If we've seen this struct type, return it
5434
5.10k
            const glslang::TTypeList* glslangMembers = type.getStruct();
5435
5436
            // Try to share structs for different layouts, but not yet for other
5437
            // kinds of qualification (primarily not yet including interpolant qualification).
5438
5.10k
            if (! HasNonLayoutQualifiers(type, qualifier))
5439
5.08k
                spvType = structMap[explicitLayout][qualifier.layoutMatrix][glslangMembers];
5440
5.10k
            if (spvType != spv::NoResult)
5441
2.08k
                break;
5442
5443
            // else, we haven't seen it...
5444
3.01k
            if (type.getBasicType() == glslang::EbtBlock)
5445
1.61k
                memberRemapper[glslangTypeToIdMap[glslangMembers]].resize(glslangMembers->size());
5446
3.01k
            spvType = convertGlslangStructToSpvType(type, glslangMembers, explicitLayout, qualifier);
5447
3.01k
        }
5448
0
        break;
5449
51
    case glslang::EbtString:
5450
        // no type used for OpString
5451
51
        return 0;
5452
5453
0
    case glslang::EbtHitObjectNV: {
5454
0
        builder.addExtension(spv::E_SPV_NV_shader_invocation_reorder);
5455
0
        builder.addCapability(spv::Capability::ShaderInvocationReorderNV);
5456
0
        spvType = builder.makeHitObjectNVType();
5457
0
    }
5458
0
    break;
5459
5460
0
    case glslang::EbtHitObjectEXT: {
5461
0
        builder.addExtension(spv::E_SPV_EXT_shader_invocation_reorder);
5462
0
        builder.addCapability(spv::Capability::ShaderInvocationReorderEXT);
5463
0
        spvType = builder.makeHitObjectEXTType();
5464
0
    }
5465
0
    break;
5466
0
    case glslang::EbtSpirvType: {
5467
        // GL_EXT_spirv_intrinsics
5468
0
        const auto& spirvType = type.getSpirvType();
5469
0
        const auto& spirvInst = spirvType.spirvInst;
5470
5471
0
        std::vector<spv::IdImmediate> operands;
5472
0
        for (const auto& typeParam : spirvType.typeParams) {
5473
0
            if (typeParam.getAsConstant() != nullptr) {
5474
                // Constant expression
5475
0
                auto constant = typeParam.getAsConstant();
5476
0
                if (constant->isLiteral()) {
5477
0
                    if (constant->getBasicType() == glslang::EbtFloat) {
5478
0
                        float floatValue = static_cast<float>(constant->getConstArray()[0].getDConst());
5479
0
                        unsigned literal;
5480
0
                        static_assert(sizeof(literal) == sizeof(floatValue), "sizeof(unsigned) != sizeof(float)");
5481
0
                        memcpy(&literal, &floatValue, sizeof(literal));
5482
0
                        operands.push_back({false, literal});
5483
0
                    } else if (constant->getBasicType() == glslang::EbtInt) {
5484
0
                        unsigned literal = constant->getConstArray()[0].getIConst();
5485
0
                        operands.push_back({false, literal});
5486
0
                    } else if (constant->getBasicType() == glslang::EbtUint) {
5487
0
                        unsigned literal = constant->getConstArray()[0].getUConst();
5488
0
                        operands.push_back({false, literal});
5489
0
                    } else if (constant->getBasicType() == glslang::EbtBool) {
5490
0
                        unsigned literal = constant->getConstArray()[0].getBConst();
5491
0
                        operands.push_back({false, literal});
5492
0
                    } else if (constant->getBasicType() == glslang::EbtString) {
5493
0
                        auto str = constant->getConstArray()[0].getSConst()->c_str();
5494
0
                        unsigned literal = 0;
5495
0
                        char* literalPtr = reinterpret_cast<char*>(&literal);
5496
0
                        unsigned charCount = 0;
5497
0
                        char ch = 0;
5498
0
                        do {
5499
0
                            ch = *(str++);
5500
0
                            *(literalPtr++) = ch;
5501
0
                            ++charCount;
5502
0
                            if (charCount == 4) {
5503
0
                                operands.push_back({false, literal});
5504
0
                                literalPtr = reinterpret_cast<char*>(&literal);
5505
0
                                charCount = 0;
5506
0
                            }
5507
0
                        } while (ch != 0);
5508
5509
                        // Partial literal is padded with 0
5510
0
                        if (charCount > 0) {
5511
0
                            for (; charCount < 4; ++charCount)
5512
0
                                *(literalPtr++) = 0;
5513
0
                            operands.push_back({false, literal});
5514
0
                        }
5515
0
                    } else
5516
0
                        assert(0); // Unexpected type
5517
0
                } else
5518
0
                    operands.push_back({true, createSpvConstant(*constant)});
5519
0
            } else {
5520
                // Type specifier
5521
0
                assert(typeParam.getAsType() != nullptr);
5522
0
                operands.push_back({true, convertGlslangToSpvType(*typeParam.getAsType())});
5523
0
            }
5524
0
        }
5525
5526
0
        assert(spirvInst.set == ""); // Currently, couldn't be extended instructions.
5527
0
        spvType = builder.makeGenericType(static_cast<spv::Op>(spirvInst.id), operands);
5528
5529
0
        break;
5530
5.10k
    }
5531
0
    case glslang::EbtTensorLayoutNV:
5532
0
    {
5533
0
        builder.addCapability(spv::Capability::TensorAddressingNV);
5534
0
        builder.addExtension(spv::E_SPV_NV_tensor_addressing);
5535
5536
0
        std::vector<spv::IdImmediate> operands;
5537
0
        for (uint32_t i = 0; i < 2; ++i) {
5538
0
            operands.push_back({true, makeArraySizeId(*type.getTypeParameters()->arraySizes, i, true)});
5539
0
        }
5540
0
        spvType = builder.makeGenericType(spv::Op::OpTypeTensorLayoutNV, operands);
5541
0
        break;
5542
5.10k
    }
5543
0
    case glslang::EbtTensorViewNV:
5544
0
    {
5545
0
        builder.addCapability(spv::Capability::TensorAddressingNV);
5546
0
        builder.addExtension(spv::E_SPV_NV_tensor_addressing);
5547
5548
0
        uint32_t dim = type.getTypeParameters()->arraySizes->getDimSize(0);
5549
0
        assert(dim >= 1 && dim <= 5);
5550
0
        std::vector<spv::IdImmediate> operands;
5551
0
        for (uint32_t i = 0; i < dim + 2; ++i) {
5552
0
            operands.push_back({true, makeArraySizeId(*type.getTypeParameters()->arraySizes, i, true, i==1)});
5553
0
        }
5554
0
        spvType = builder.makeGenericType(spv::Op::OpTypeTensorViewNV, operands);
5555
0
        break;
5556
5.10k
    }
5557
0
    default:
5558
0
        assert(0);
5559
0
        break;
5560
113k
    }
5561
5562
113k
    if (type.isMatrix())
5563
2.29k
        spvType = builder.makeMatrixType(spvType, type.getMatrixCols(), type.getMatrixRows());
5564
110k
    else {
5565
        // If this variable has a vector element count greater than 1, create a SPIR-V vector
5566
110k
        if (type.getVectorSize() > 1)
5567
47.1k
            spvType = builder.makeVectorType(spvType, type.getVectorSize());
5568
110k
    }
5569
5570
113k
    if (type.isCoopMatNV()) {
5571
0
        builder.addCapability(spv::Capability::CooperativeMatrixNV);
5572
0
        builder.addExtension(spv::E_SPV_NV_cooperative_matrix);
5573
5574
0
        if (type.getBasicType() == glslang::EbtFloat16)
5575
0
            builder.addCapability(spv::Capability::Float16);
5576
0
        if (type.getBasicType() == glslang::EbtUint8 ||
5577
0
            type.getBasicType() == glslang::EbtInt8) {
5578
0
            builder.addCapability(spv::Capability::Int8);
5579
0
        }
5580
5581
0
        spv::Id scope = makeArraySizeId(*type.getTypeParameters()->arraySizes, 1);
5582
0
        spv::Id rows = makeArraySizeId(*type.getTypeParameters()->arraySizes, 2);
5583
0
        spv::Id cols = makeArraySizeId(*type.getTypeParameters()->arraySizes, 3);
5584
5585
0
        spvType = builder.makeCooperativeMatrixTypeNV(spvType, scope, rows, cols);
5586
0
    }
5587
5588
113k
    if (type.isCoopMatKHR()) {
5589
0
        builder.addCapability(spv::Capability::CooperativeMatrixKHR);
5590
0
        builder.addExtension(spv::E_SPV_KHR_cooperative_matrix);
5591
5592
0
        if (type.getBasicType() == glslang::EbtBFloat16) {
5593
0
            builder.addExtension(spv::E_SPV_KHR_bfloat16);
5594
0
            builder.addCapability(spv::Capability::BFloat16CooperativeMatrixKHR);
5595
0
        }
5596
5597
0
        if (type.getBasicType() == glslang::EbtFloatE5M2 || type.getBasicType() == glslang::EbtFloatE4M3) {
5598
0
            builder.addExtension(spv::E_SPV_EXT_float8);
5599
0
            builder.addCapability(spv::Capability::Float8CooperativeMatrixEXT);
5600
0
        }
5601
5602
0
        if (type.getBasicType() == glslang::EbtFloat16)
5603
0
            builder.addCapability(spv::Capability::Float16);
5604
0
        if (type.getBasicType() == glslang::EbtUint8 || type.getBasicType() == glslang::EbtInt8) {
5605
0
            builder.addCapability(spv::Capability::Int8);
5606
0
        }
5607
5608
0
        spv::Id scope = makeArraySizeId(*type.getTypeParameters()->arraySizes, 0);
5609
0
        spv::Id rows = makeArraySizeId(*type.getTypeParameters()->arraySizes, 1);
5610
0
        spv::Id cols = makeArraySizeId(*type.getTypeParameters()->arraySizes, 2);
5611
0
        spv::Id use = makeArraySizeId(*type.getTypeParameters()->arraySizes, 3, true);
5612
5613
0
        spvType = builder.makeCooperativeMatrixTypeKHR(spvType, scope, rows, cols, use);
5614
0
    }
5615
113k
    else if (type.isTensorARM()) {
5616
1
        builder.addCapability(spv::Capability::TensorsARM);
5617
1
        builder.addExtension(spv::E_SPV_ARM_tensors);
5618
1
        if (type.getBasicType() == glslang::EbtInt8 || type.getBasicType() == glslang::EbtUint8) {
5619
1
            builder.addCapability(spv::Capability::Int8);
5620
1
        } else if (type.getBasicType() == glslang::EbtInt16 ||
5621
0
                   type.getBasicType() == glslang::EbtUint16) {
5622
0
            builder.addCapability(spv::Capability::Int16);
5623
0
        } else if (type.getBasicType() == glslang::EbtInt64 ||
5624
0
                   type.getBasicType() == glslang::EbtUint64) {
5625
0
            builder.addCapability(spv::Capability::Int64);
5626
0
        } else if (type.getBasicType() == glslang::EbtFloat16) {
5627
0
            builder.addCapability(spv::Capability::Float16);
5628
0
        }
5629
5630
1
        spv::Id rank = makeArraySizeId(*type.getTypeParameters()->arraySizes, 0);
5631
5632
1
        spvType = builder.makeTensorTypeARM(spvType, rank);
5633
1
    }
5634
5635
113k
    if (type.isCoopVecNV()) {
5636
0
        builder.addCapability(spv::Capability::CooperativeVectorNV);
5637
0
        builder.addExtension(spv::E_SPV_NV_cooperative_vector);
5638
5639
0
        if (type.getBasicType() == glslang::EbtFloat16)
5640
0
            builder.addCapability(spv::Capability::Float16);
5641
0
        if (type.getBasicType() == glslang::EbtUint8 || type.getBasicType() == glslang::EbtInt8) {
5642
0
            builder.addCapability(spv::Capability::Int8);
5643
0
        }
5644
5645
0
        spv::Id components = makeArraySizeId(*type.getTypeParameters()->arraySizes, 0);
5646
5647
0
        spvType = builder.makeCooperativeVectorTypeNV(spvType, components);
5648
0
    }
5649
5650
113k
    if (type.isArray()) {
5651
2.13k
        int stride = 0;  // keep this 0 unless doing an explicit layout; 0 will mean no decoration, no stride
5652
5653
        // Do all but the outer dimension
5654
2.13k
        if (type.getArraySizes()->getNumDims() > 1) {
5655
            // We need to decorate array strides for types needing explicit layout, except blocks.
5656
88
            if (explicitLayout != glslang::ElpNone && type.getBasicType() != glslang::EbtBlock) {
5657
                // Use a dummy glslang type for querying internal strides of
5658
                // arrays of arrays, but using just a one-dimensional array.
5659
78
                glslang::TType simpleArrayType(type, 0); // deference type of the array
5660
252
                while (simpleArrayType.getArraySizes()->getNumDims() > 1)
5661
174
                    simpleArrayType.getArraySizes()->dereference();
5662
5663
                // Will compute the higher-order strides here, rather than making a whole
5664
                // pile of types and doing repetitive recursion on their contents.
5665
78
                stride = getArrayStride(simpleArrayType, explicitLayout, qualifier.layoutMatrix);
5666
78
            }
5667
5668
            // make the arrays
5669
350
            for (int dim = type.getArraySizes()->getNumDims() - 1; dim > 0; --dim) {
5670
262
                spvType = builder.makeArrayType(spvType, makeArraySizeId(*type.getArraySizes(), dim), stride);
5671
262
                if (stride > 0)
5672
252
                    builder.addDecoration(spvType, spv::Decoration::ArrayStride, stride);
5673
262
                stride *= type.getArraySizes()->getDimSize(dim);
5674
262
            }
5675
2.04k
        } else {
5676
            // single-dimensional array, and don't yet have stride
5677
5678
            // We need to decorate array strides for types needing explicit layout, except blocks.
5679
2.04k
            if (explicitLayout != glslang::ElpNone && type.getBasicType() != glslang::EbtBlock)
5680
411
                stride = getArrayStride(type, explicitLayout, qualifier.layoutMatrix);
5681
2.04k
        }
5682
5683
        // Do the outer dimension, which might not be known for a runtime-sized array.
5684
        // (Unsized arrays that survive through linking will be runtime-sized arrays)
5685
2.13k
        if (type.isSizedArray())
5686
2.03k
            spvType = builder.makeArrayType(spvType, makeArraySizeId(*type.getArraySizes(), 0), stride);
5687
107
        else {
5688
            // If we see an runtime array in a buffer_reference, it is not a descriptor
5689
107
            if (!lastBufferBlockMember && type.getBasicType() != glslang::EbtReference) {
5690
14
                builder.addIncorporatedExtension("SPV_EXT_descriptor_indexing", spv::Spv_1_5);
5691
14
                builder.addCapability(spv::Capability::RuntimeDescriptorArrayEXT);
5692
14
            }
5693
107
            spvType = builder.makeRuntimeArray(spvType);
5694
107
        }
5695
2.13k
        if (stride > 0)
5696
489
            builder.addDecoration(spvType, spv::Decoration::ArrayStride, stride);
5697
2.13k
    }
5698
5699
113k
    return spvType;
5700
113k
}
5701
5702
// Apply SPIR-V decorations to the SPIR-V object (provided by SPIR-V ID). If member index is provided, the
5703
// decorations are applied to this member.
5704
void TGlslangToSpvTraverser::applySpirvDecorate(const glslang::TType& type, spv::Id id, std::optional<int> member)
5705
273
{
5706
273
    assert(type.getQualifier().hasSpirvDecorate());
5707
5708
273
    const glslang::TSpirvDecorate& spirvDecorate = type.getQualifier().getSpirvDecorate();
5709
5710
    // Add spirv_decorate
5711
273
    for (auto& decorate : spirvDecorate.decorates) {
5712
273
        if (!decorate.second.empty()) {
5713
239
            std::vector<unsigned> literals;
5714
239
            TranslateLiterals(decorate.second, literals);
5715
239
            if (member.has_value())
5716
0
                builder.addMemberDecoration(id, *member, static_cast<spv::Decoration>(decorate.first), literals);
5717
239
            else
5718
239
                builder.addDecoration(id, static_cast<spv::Decoration>(decorate.first), literals);
5719
239
        } else {
5720
34
            if (member.has_value())
5721
0
                builder.addMemberDecoration(id, *member, static_cast<spv::Decoration>(decorate.first));
5722
34
            else
5723
34
                builder.addDecoration(id, static_cast<spv::Decoration>(decorate.first));
5724
34
        }
5725
273
    }
5726
5727
    // Add spirv_decorate_id
5728
273
    if (member.has_value()) {
5729
        // spirv_decorate_id not applied to members
5730
0
        assert(spirvDecorate.decorateIds.empty());
5731
273
    } else {
5732
273
        for (auto& decorateId : spirvDecorate.decorateIds) {
5733
0
            std::vector<spv::Id> operandIds;
5734
0
            assert(!decorateId.second.empty());
5735
0
            for (auto extraOperand : decorateId.second) {
5736
0
                if (extraOperand->getQualifier().isFrontEndConstant())
5737
0
                    operandIds.push_back(createSpvConstant(*extraOperand));
5738
0
                else
5739
0
                    operandIds.push_back(getSymbolId(extraOperand->getAsSymbolNode()));
5740
0
            }
5741
0
            builder.addDecorationId(id, static_cast<spv::Decoration>(decorateId.first), operandIds);
5742
0
        }
5743
273
    }
5744
5745
    // Add spirv_decorate_string
5746
273
    for (auto& decorateString : spirvDecorate.decorateStrings) {
5747
0
        std::vector<const char*> strings;
5748
0
        assert(!decorateString.second.empty());
5749
0
        for (auto extraOperand : decorateString.second) {
5750
0
            const char* string = extraOperand->getConstArray()[0].getSConst()->c_str();
5751
0
            strings.push_back(string);
5752
0
        }
5753
0
        if (member.has_value())
5754
0
            builder.addMemberDecoration(id, *member, static_cast<spv::Decoration>(decorateString.first), strings);
5755
0
        else
5756
0
            builder.addDecoration(id, static_cast<spv::Decoration>(decorateString.first), strings);
5757
0
    }
5758
273
}
5759
5760
// TODO: this functionality should exist at a higher level, in creating the AST
5761
//
5762
// Identify interface members that don't have their required extension turned on.
5763
//
5764
bool TGlslangToSpvTraverser::filterMember(const glslang::TType& member)
5765
8.32k
{
5766
8.32k
    auto& extensions = glslangIntermediate->getRequestedExtensions();
5767
5768
8.32k
    if (member.getFieldName() == "gl_SecondaryViewportMaskNV" &&
5769
0
        extensions.find("GL_NV_stereo_view_rendering") == extensions.end())
5770
0
        return true;
5771
8.32k
    if (member.getFieldName() == "gl_SecondaryPositionNV" &&
5772
0
        extensions.find("GL_NV_stereo_view_rendering") == extensions.end())
5773
0
        return true;
5774
5775
8.32k
    if (glslangIntermediate->getStage() == EShLangMesh) {
5776
0
        if (member.getFieldName() == "gl_PrimitiveShadingRateEXT" &&
5777
0
            extensions.find("GL_EXT_fragment_shading_rate") == extensions.end())
5778
0
            return true;
5779
0
    }
5780
5781
8.32k
    if (glslangIntermediate->getStage() != EShLangMesh) {
5782
8.32k
        if (member.getFieldName() == "gl_ViewportMask" &&
5783
0
            extensions.find("GL_NV_viewport_array2") == extensions.end())
5784
0
            return true;
5785
8.32k
        if (member.getFieldName() == "gl_PositionPerViewNV" &&
5786
0
            extensions.find("GL_NVX_multiview_per_view_attributes") == extensions.end())
5787
0
            return true;
5788
8.32k
        if (member.getFieldName() == "gl_ViewportMaskPerViewNV" &&
5789
0
            extensions.find("GL_NVX_multiview_per_view_attributes") == extensions.end())
5790
0
            return true;
5791
8.32k
    }
5792
5793
8.32k
    return false;
5794
8.32k
}
5795
5796
// Do full recursive conversion of a glslang structure (or block) type to a SPIR-V Id.
5797
// explicitLayout can be kept the same throughout the hierarchical recursive walk.
5798
// Mutually recursive with convertGlslangToSpvType().
5799
spv::Id TGlslangToSpvTraverser::convertGlslangStructToSpvType(const glslang::TType& type,
5800
                                                              const glslang::TTypeList* glslangMembers,
5801
                                                              glslang::TLayoutPacking explicitLayout,
5802
                                                              const glslang::TQualifier& qualifier)
5803
3.01k
{
5804
    // Create a vector of struct types for SPIR-V to consume
5805
3.01k
    std::vector<spv::Id> spvMembers;
5806
3.01k
    int memberDelta = 0;  // how much the member's index changes from glslang to SPIR-V, normally 0,
5807
                          // except sometimes for blocks
5808
3.01k
    std::vector<std::pair<glslang::TType*, glslang::TQualifier> > deferredForwardPointers;
5809
3.01k
    std::vector<spv::StructMemberDebugInfo> memberDebugInfo;
5810
10.1k
    for (int i = 0; i < (int)glslangMembers->size(); i++) {
5811
7.17k
        auto& glslangMember = (*glslangMembers)[i];
5812
7.17k
        if (glslangMember.type->hiddenMember()) {
5813
8
            ++memberDelta;
5814
8
            if (type.getBasicType() == glslang::EbtBlock)
5815
8
                memberRemapper[glslangTypeToIdMap[glslangMembers]][i] = -1;
5816
7.16k
        } else {
5817
7.16k
            if (type.getBasicType() == glslang::EbtBlock) {
5818
4.15k
                if (filterMember(*glslangMember.type)) {
5819
0
                    memberDelta++;
5820
0
                    memberRemapper[glslangTypeToIdMap[glslangMembers]][i] = -1;
5821
0
                    continue;
5822
0
                }
5823
4.15k
                memberRemapper[glslangTypeToIdMap[glslangMembers]][i] = i - memberDelta;
5824
4.15k
            }
5825
            // modify just this child's view of the qualifier
5826
7.16k
            glslang::TQualifier memberQualifier = glslangMember.type->getQualifier();
5827
7.16k
            InheritQualifiers(memberQualifier, qualifier);
5828
5829
            // manually inherit location
5830
7.16k
            if (! memberQualifier.hasLocation() && qualifier.hasLocation())
5831
26
                memberQualifier.layoutLocation = qualifier.layoutLocation;
5832
5833
            // recurse
5834
7.16k
            bool lastBufferBlockMember = qualifier.storage == glslang::EvqBuffer &&
5835
2.53k
                                         i == (int)glslangMembers->size() - 1;
5836
5837
            // Make forward pointers for any pointer members.
5838
7.16k
            if (glslangMember.type->isReference() &&
5839
257
                forwardPointers.find(glslangMember.type->getReferentType()) == forwardPointers.end()) {
5840
158
                deferredForwardPointers.push_back(std::make_pair(glslangMember.type, memberQualifier));
5841
158
            }
5842
5843
            // Create the member type.
5844
7.16k
            auto const spvMember = convertGlslangToSpvType(*glslangMember.type, explicitLayout, memberQualifier, lastBufferBlockMember,
5845
7.16k
                glslangMember.type->isReference());
5846
7.16k
            spvMembers.push_back(spvMember);
5847
5848
            // Update the builder with the type's location so that we can create debug types for the structure members.
5849
            // There doesn't exist a "clean" entry point for this information to be passed along to the builder so, for now,
5850
            // it is stored in the builder and consumed during the construction of composite debug types.
5851
            // TODO: This probably warrants further investigation. This approach was decided to be the least ugly of the
5852
            // quick and dirty approaches that were tried.
5853
            // Advantages of this approach:
5854
            //  + Relatively clean. No direct calls into debug type system.
5855
            //  + Handles nested recursive structures.
5856
            // Disadvantages of this approach:
5857
            //  + Not as clean as desired. Traverser queries/sets persistent state. This is fragile.
5858
            //  + Table lookup during creation of composite debug types. This really shouldn't be necessary.
5859
7.16k
            if(options.emitNonSemanticShaderDebugInfo) {
5860
0
                spv::StructMemberDebugInfo debugInfo{};
5861
0
                debugInfo.name = glslangMember.type->getFieldName();
5862
0
                debugInfo.line = glslangMember.loc.line;
5863
0
                debugInfo.column = glslangMember.loc.column;
5864
5865
                // Per the GLSL spec, bool variables inside of a uniform or buffer block are generated as uint.
5866
                // But for debug info, we want to represent them as bool because that is the original type in
5867
                // the source code. The bool type can be nested within a vector or a multidimensional array,
5868
                // so we must construct the chain of types up from the scalar bool.
5869
0
                if (glslangIntermediate->getSource() == glslang::EShSourceGlsl && explicitLayout != glslang::ElpNone &&
5870
0
                    glslangMember.type->getBasicType() == glslang::EbtBool) {
5871
0
                    auto typeId = builder.makeBoolType();
5872
0
                    if (glslangMember.type->isVector()) {
5873
0
                        typeId = builder.makeVectorType(typeId, glslangMember.type->getVectorSize());
5874
0
                    }
5875
0
                    if (glslangMember.type->isArray()) {
5876
0
                        const auto* arraySizes = glslangMember.type->getArraySizes();
5877
0
                        int dims = arraySizes->getNumDims();
5878
0
                        for (int i = dims - 1; i >= 0; --i) {
5879
0
                            spv::Id size = builder.makeIntConstant(arraySizes->getDimSize(i));
5880
0
                            typeId = builder.makeArrayType(typeId, size, 0);
5881
0
                        }
5882
0
                    }
5883
0
                    debugInfo.debugTypeOverride = builder.getDebugType(typeId);
5884
0
                }
5885
5886
0
                memberDebugInfo.push_back(debugInfo);
5887
0
            }
5888
7.16k
        }
5889
7.17k
    }
5890
5891
    // Make the SPIR-V type
5892
3.01k
    spv::Id spvType = builder.makeStructType(spvMembers, memberDebugInfo, type.getTypeName().c_str(), false);
5893
3.01k
    if (! HasNonLayoutQualifiers(type, qualifier))
5894
3.00k
        structMap[explicitLayout][qualifier.layoutMatrix][glslangMembers] = spvType;
5895
5896
    // Decorate it
5897
3.01k
    decorateStructType(type, glslangMembers, explicitLayout, qualifier, spvType, spvMembers);
5898
5899
3.17k
    for (int i = 0; i < (int)deferredForwardPointers.size(); ++i) {
5900
158
        auto it = deferredForwardPointers[i];
5901
158
        convertGlslangToSpvType(*it.first, explicitLayout, it.second, false);
5902
158
    }
5903
5904
3.01k
    return spvType;
5905
3.01k
}
5906
5907
void TGlslangToSpvTraverser::decorateStructType(const glslang::TType& type,
5908
                                                const glslang::TTypeList* glslangMembers,
5909
                                                glslang::TLayoutPacking explicitLayout,
5910
                                                const glslang::TQualifier& qualifier,
5911
                                                spv::Id spvType,
5912
                                                const std::vector<spv::Id>& spvMembers)
5913
3.01k
{
5914
    // Name and decorate the non-hidden members
5915
3.01k
    int offset = -1;
5916
3.01k
    bool memberLocationInvalid = type.isArrayOfArrays() ||
5917
3.01k
        (type.isArray() && (type.getQualifier().isArrayedIo(glslangIntermediate->getStage()) == false));
5918
10.1k
    for (int i = 0; i < (int)glslangMembers->size(); i++) {
5919
7.17k
        glslang::TType& glslangMember = *(*glslangMembers)[i].type;
5920
7.17k
        int member = i;
5921
7.17k
        if (type.getBasicType() == glslang::EbtBlock) {
5922
4.16k
            member = memberRemapper[glslangTypeToIdMap[glslangMembers]][i];
5923
4.16k
            if (filterMember(glslangMember))
5924
0
                continue;
5925
4.16k
        }
5926
5927
        // modify just this child's view of the qualifier
5928
7.17k
        glslang::TQualifier memberQualifier = glslangMember.getQualifier();
5929
7.17k
        InheritQualifiers(memberQualifier, qualifier);
5930
5931
        // using -1 above to indicate a hidden member
5932
7.17k
        if (member < 0)
5933
8
            continue;
5934
5935
7.16k
        builder.addMemberName(spvType, member, glslangMember.getFieldName().c_str());
5936
7.16k
        builder.addMemberDecoration(spvType, member,
5937
7.16k
                                    TranslateLayoutDecoration(glslangMember, memberQualifier.layoutMatrix));
5938
7.16k
        builder.addMemberDecoration(spvType, member, TranslatePrecisionDecoration(glslangMember));
5939
        // Add interpolation and auxiliary storage decorations only to
5940
        // top-level members of Input and Output storage classes
5941
7.16k
        if (type.getQualifier().storage == glslang::EvqVaryingIn ||
5942
7.13k
            type.getQualifier().storage == glslang::EvqVaryingOut) {
5943
26
            if (type.getBasicType() == glslang::EbtBlock ||
5944
22
                glslangIntermediate->getSource() == glslang::EShSourceHlsl) {
5945
22
                builder.addMemberDecoration(spvType, member, TranslateInterpolationDecoration(memberQualifier));
5946
22
                builder.addMemberDecoration(spvType, member, TranslateAuxiliaryStorageDecoration(memberQualifier));
5947
22
                addMeshNVDecoration(spvType, member, memberQualifier);
5948
22
            }
5949
26
        }
5950
7.16k
        builder.addMemberDecoration(spvType, member, TranslateInvariantDecoration(memberQualifier));
5951
5952
7.16k
        if (type.getBasicType() == glslang::EbtBlock &&
5953
4.15k
            qualifier.storage == glslang::EvqBuffer) {
5954
            // Add memory decorations only to top-level members of shader storage block
5955
1.68k
            std::vector<spv::Decoration> memory;
5956
1.68k
            TranslateMemoryDecoration(memberQualifier, memory, glslangIntermediate->usingVulkanMemoryModel());
5957
2.19k
            for (unsigned int i = 0; i < memory.size(); ++i)
5958
512
                builder.addMemberDecoration(spvType, member, memory[i]);
5959
1.68k
        }
5960
5961
        // Location assignment was already completed correctly by the front end,
5962
        // just track whether a member needs to be decorated.
5963
        // Ignore member locations if the container is an array, as that's
5964
        // ill-specified and decisions have been made to not allow this.
5965
7.16k
        if (!memberLocationInvalid && memberQualifier.hasLocation())
5966
0
            builder.addMemberDecoration(spvType, member, spv::Decoration::Location, memberQualifier.layoutLocation);
5967
5968
        // component, XFB, others
5969
7.16k
        if (glslangMember.getQualifier().hasComponent())
5970
0
            builder.addMemberDecoration(spvType, member, spv::Decoration::Component,
5971
0
                                        glslangMember.getQualifier().layoutComponent);
5972
7.16k
        if (glslangMember.getQualifier().hasXfbOffset())
5973
0
            builder.addMemberDecoration(spvType, member, spv::Decoration::Offset,
5974
0
                                        glslangMember.getQualifier().layoutXfbOffset);
5975
7.16k
        else if (explicitLayout != glslang::ElpNone) {
5976
            // figure out what to do with offset, which is accumulating
5977
6.00k
            int nextOffset;
5978
6.00k
            updateMemberOffset(type, glslangMember, offset, nextOffset, explicitLayout, memberQualifier.layoutMatrix);
5979
6.00k
            if (offset >= 0)
5980
6.00k
                builder.addMemberDecoration(spvType, member, spv::Decoration::Offset, offset);
5981
6.00k
            offset = nextOffset;
5982
6.00k
        }
5983
5984
7.16k
        if (glslangMember.isMatrix() && explicitLayout != glslang::ElpNone)
5985
286
            builder.addMemberDecoration(spvType, member, spv::Decoration::MatrixStride,
5986
286
                                        getMatrixStride(glslangMember, explicitLayout, memberQualifier.layoutMatrix));
5987
5988
        // built-in variable decorations
5989
7.16k
        spv::BuiltIn builtIn = TranslateBuiltInDecoration(glslangMember.getQualifier().builtIn, true);
5990
7.16k
        if (builtIn != spv::BuiltIn::Max)
5991
0
            builder.addMemberDecoration(spvType, member, spv::Decoration::BuiltIn, (int)builtIn);
5992
5993
        // nonuniform
5994
7.16k
        builder.addMemberDecoration(spvType, member, TranslateNonUniformDecoration(glslangMember.getQualifier()));
5995
5996
7.16k
        if (glslangIntermediate->getHlslFunctionality1() && memberQualifier.semanticName != nullptr) {
5997
0
            builder.addExtension("SPV_GOOGLE_hlsl_functionality1");
5998
0
            builder.addMemberDecoration(spvType, member, spv::Decoration::HlslSemanticGOOGLE,
5999
0
                                        memberQualifier.semanticName);
6000
0
        }
6001
6002
7.16k
        if (builtIn == spv::BuiltIn::Layer) {
6003
            // SPV_NV_viewport_array2 extension
6004
0
            if (glslangMember.getQualifier().layoutViewportRelative){
6005
0
                builder.addMemberDecoration(spvType, member, spv::Decoration::ViewportRelativeNV);
6006
0
                builder.addCapability(spv::Capability::ShaderViewportMaskNV);
6007
0
                builder.addExtension(spv::E_SPV_NV_viewport_array2);
6008
0
            }
6009
0
            if (glslangMember.getQualifier().layoutSecondaryViewportRelativeOffset != -2048){
6010
0
                builder.addMemberDecoration(spvType, member,
6011
0
                                            spv::Decoration::SecondaryViewportRelativeNV,
6012
0
                                            glslangMember.getQualifier().layoutSecondaryViewportRelativeOffset);
6013
0
                builder.addCapability(spv::Capability::ShaderStereoViewNV);
6014
0
                builder.addExtension(spv::E_SPV_NV_stereo_view_rendering);
6015
0
            }
6016
0
        }
6017
7.16k
        if (glslangMember.getQualifier().layoutPassthrough) {
6018
0
            builder.addMemberDecoration(spvType, member, spv::Decoration::PassthroughNV);
6019
0
            builder.addCapability(spv::Capability::GeometryShaderPassthroughNV);
6020
0
            builder.addExtension(spv::E_SPV_NV_geometry_shader_passthrough);
6021
0
        }
6022
6023
        // Add SPIR-V decorations (GL_EXT_spirv_intrinsics)
6024
7.16k
        if (glslangMember.getQualifier().hasSpirvDecorate())
6025
0
            applySpirvDecorate(glslangMember, spvType, member);
6026
7.16k
    }
6027
6028
    // Decorate the structure
6029
3.01k
    builder.addDecoration(spvType, TranslateLayoutDecoration(type, qualifier.layoutMatrix));
6030
3.01k
    const auto basicType = type.getBasicType();
6031
3.01k
    const auto typeStorageQualifier = type.getQualifier().storage;
6032
3.01k
    if (basicType == glslang::EbtBlock) {
6033
1.61k
        builder.addDecoration(spvType, TranslateBlockDecoration(typeStorageQualifier, glslangIntermediate->usingStorageBuffer()));
6034
1.61k
    } else if (basicType == glslang::EbtStruct && glslangIntermediate->getSpv().vulkan > 0) {
6035
1.39k
        const auto hasRuntimeArray = !spvMembers.empty() && builder.getOpCode(spvMembers.back()) == spv::Op::OpTypeRuntimeArray;
6036
1.39k
        if (hasRuntimeArray) {
6037
0
            builder.addDecoration(spvType, TranslateBlockDecoration(typeStorageQualifier, glslangIntermediate->usingStorageBuffer()));
6038
0
        }
6039
1.39k
    }
6040
6041
3.01k
    if (qualifier.hasHitObjectShaderRecordNV())
6042
0
        builder.addDecoration(spvType, spv::Decoration::HitObjectShaderRecordBufferNV);
6043
3.01k
    if (qualifier.hasHitObjectShaderRecordEXT())
6044
0
        builder.addDecoration(spvType, spv::Decoration::HitObjectShaderRecordBufferEXT);
6045
3.01k
}
6046
6047
// Turn the expression forming the array size into an id.
6048
// This is not quite trivial, because of specialization constants.
6049
// Sometimes, a raw constant is turned into an Id, and sometimes
6050
// a specialization constant expression is.
6051
spv::Id TGlslangToSpvTraverser::makeArraySizeId(const glslang::TArraySizes& arraySizes, int dim, bool allowZero, bool boolType)
6052
2.29k
{
6053
    // First, see if this is sized with a node, meaning a specialization constant:
6054
2.29k
    glslang::TIntermTyped* specNode = arraySizes.getDimNode(dim);
6055
2.29k
    if (specNode != nullptr) {
6056
0
        builder.clearAccessChain();
6057
0
        SpecConstantOpModeGuard spec_constant_op_mode_setter(&builder);
6058
0
        spec_constant_op_mode_setter.turnOnSpecConstantOpMode();
6059
0
        specNode->traverse(this);
6060
0
        return accessChainLoad(specNode->getAsTyped()->getType());
6061
0
    }
6062
6063
    // Otherwise, need a compile-time (front end) size, get it:
6064
2.29k
    int size = arraySizes.getDimSize(dim);
6065
6066
2.29k
    if (!allowZero)
6067
2.29k
        assert(size > 0);
6068
6069
2.29k
    if (boolType) {
6070
0
        return builder.makeBoolConstant(size);
6071
2.29k
    } else {
6072
2.29k
        return builder.makeUintConstant(size);
6073
2.29k
    }
6074
2.29k
}
6075
6076
// Wrap the builder's accessChainLoad to:
6077
//  - localize handling of RelaxedPrecision
6078
//  - use the SPIR-V inferred type instead of another conversion of the glslang type
6079
//    (avoids unnecessary work and possible type punning for structures)
6080
//  - do conversion of concrete to abstract type
6081
spv::Id TGlslangToSpvTraverser::accessChainLoad(const glslang::TType& type)
6082
97.7k
{
6083
97.7k
    spv::Id nominalTypeId = builder.accessChainGetInferredType();
6084
6085
97.7k
    spv::Builder::AccessChain::CoherentFlags coherentFlags = builder.getAccessChain().coherentFlags;
6086
97.7k
    coherentFlags |= TranslateCoherent(type);
6087
6088
97.7k
    spv::MemoryAccessMask accessMask = spv::MemoryAccessMask(TranslateMemoryAccess(coherentFlags) & ~spv::MemoryAccessMask::MakePointerAvailableKHR);
6089
    // If the value being loaded is HelperInvocation, SPIR-V 1.6 is being generated (so that
6090
    // SPV_EXT_demote_to_helper_invocation is in core) and the memory model is in use, add
6091
    // the Volatile MemoryAccess semantic.
6092
97.7k
    if (type.getQualifier().builtIn == glslang::EbvHelperInvocation &&
6093
2
        glslangIntermediate->usingVulkanMemoryModel() &&
6094
1
        glslangIntermediate->getSpv().spv >= glslang::EShTargetSpv_1_6) {
6095
0
        accessMask = spv::MemoryAccessMask(accessMask | spv::MemoryAccessMask::Volatile);
6096
0
    }
6097
6098
97.7k
    unsigned int alignment = builder.getAccessChain().alignment;
6099
97.7k
    alignment |= type.getBufferReferenceAlignment();
6100
6101
97.7k
    spv::Id loadedId = builder.accessChainLoad(TranslatePrecisionDecoration(type),
6102
97.7k
        TranslateNonUniformDecoration(builder.getAccessChain().coherentFlags),
6103
97.7k
        TranslateNonUniformDecoration(type.getQualifier()),
6104
97.7k
        nominalTypeId,
6105
97.7k
        accessMask,
6106
97.7k
        TranslateMemoryScope(coherentFlags),
6107
97.7k
        alignment);
6108
6109
    // Need to convert to abstract types when necessary
6110
97.7k
    if (type.getBasicType() == glslang::EbtBool) {
6111
6.52k
        loadedId = convertLoadedBoolInUniformToUint(type, nominalTypeId, loadedId);
6112
6.52k
    }
6113
6114
97.7k
    return loadedId;
6115
97.7k
}
6116
6117
// Wrap the builder's accessChainStore to:
6118
//  - do conversion of concrete to abstract type
6119
//
6120
// Implicitly uses the existing builder.accessChain as the storage target.
6121
void TGlslangToSpvTraverser::accessChainStore(const glslang::TType& type, spv::Id rvalue)
6122
25.1k
{
6123
    // Need to convert to abstract types when necessary
6124
25.1k
    if (type.getBasicType() == glslang::EbtBool) {
6125
492
        spv::Id nominalTypeId = builder.accessChainGetInferredType();
6126
6127
492
        if (builder.isScalarType(nominalTypeId)) {
6128
            // Conversion for bool
6129
325
            spv::Id boolType = builder.makeBoolType();
6130
325
            if (nominalTypeId != boolType) {
6131
                // keep these outside arguments, for determinant order-of-evaluation
6132
60
                spv::Id one = builder.makeUintConstant(1);
6133
60
                spv::Id zero = builder.makeUintConstant(0);
6134
60
                rvalue = builder.createTriOp(spv::Op::OpSelect, nominalTypeId, rvalue, one, zero);
6135
265
            } else if (builder.getTypeId(rvalue) != boolType)
6136
0
                rvalue = builder.createBinOp(spv::Op::OpINotEqual, boolType, rvalue, builder.makeUintConstant(0));
6137
325
        } else if (builder.isVectorType(nominalTypeId)) {
6138
            // Conversion for bvec
6139
167
            int vecSize = builder.getNumTypeComponents(nominalTypeId);
6140
167
            spv::Id bvecType = builder.makeVectorType(builder.makeBoolType(), vecSize);
6141
167
            if (nominalTypeId != bvecType) {
6142
                // keep these outside arguments, for determinant order-of-evaluation
6143
30
                spv::Id one = makeSmearedConstant(builder.makeUintConstant(1), vecSize);
6144
30
                spv::Id zero = makeSmearedConstant(builder.makeUintConstant(0), vecSize);
6145
30
                rvalue = builder.createTriOp(spv::Op::OpSelect, nominalTypeId, rvalue, one, zero);
6146
137
            } else if (builder.getTypeId(rvalue) != bvecType)
6147
0
                rvalue = builder.createBinOp(spv::Op::OpINotEqual, bvecType, rvalue,
6148
0
                                             makeSmearedConstant(builder.makeUintConstant(0), vecSize));
6149
167
        }
6150
492
    }
6151
6152
25.1k
    spv::Builder::AccessChain::CoherentFlags coherentFlags = builder.getAccessChain().coherentFlags;
6153
25.1k
    coherentFlags |= TranslateCoherent(type);
6154
6155
25.1k
    unsigned int alignment = builder.getAccessChain().alignment;
6156
25.1k
    alignment |= type.getBufferReferenceAlignment();
6157
6158
25.1k
    builder.accessChainStore(rvalue, TranslateNonUniformDecoration(builder.getAccessChain().coherentFlags),
6159
25.1k
                             spv::MemoryAccessMask(TranslateMemoryAccess(coherentFlags) &
6160
25.1k
                                ~spv::MemoryAccessMask::MakePointerVisibleKHR),
6161
25.1k
                             TranslateMemoryScope(coherentFlags), alignment);
6162
25.1k
}
6163
6164
// For storing when types match at the glslang level, but not might match at the
6165
// SPIR-V level.
6166
//
6167
// This especially happens when a single glslang type expands to multiple
6168
// SPIR-V types, like a struct that is used in a member-undecorated way as well
6169
// as in a member-decorated way.
6170
//
6171
// NOTE: This function can handle any store request; if it's not special it
6172
// simplifies to a simple OpStore.
6173
//
6174
// Implicitly uses the existing builder.accessChain as the storage target.
6175
void TGlslangToSpvTraverser::multiTypeStore(const glslang::TType& type, spv::Id rValue)
6176
27.3k
{
6177
    // we only do the complex path here if it's an aggregate
6178
27.3k
    if (! type.isStruct() && ! type.isArray()) {
6179
24.4k
        accessChainStore(type, rValue);
6180
24.4k
        return;
6181
24.4k
    }
6182
6183
    // and, it has to be a case of type aliasing
6184
2.88k
    spv::Id rType = builder.getTypeId(rValue);
6185
2.88k
    spv::Id lValue = builder.accessChainGetLValue();
6186
2.88k
    spv::Id lType = builder.getContainedTypeId(builder.getTypeId(lValue));
6187
2.88k
    if (lType == rType) {
6188
689
        accessChainStore(type, rValue);
6189
689
        return;
6190
689
    }
6191
6192
    // Recursively (as needed) copy an aggregate type to a different aggregate type,
6193
    // where the two types were the same type in GLSL. This requires member
6194
    // by member copy, recursively.
6195
6196
    // SPIR-V 1.4 added an instruction to do help do this.
6197
2.19k
    if (glslangIntermediate->getSpv().spv >= glslang::EShTargetSpv_1_4) {
6198
        // However, bool in uniform space is changed to int, so
6199
        // OpCopyLogical does not work for that.
6200
        // TODO: It would be more robust to do a full recursive verification of the types satisfying SPIR-V rules.
6201
0
        bool rBool = builder.containsType(builder.getTypeId(rValue), spv::Op::OpTypeBool, 0);
6202
0
        bool lBool = builder.containsType(lType, spv::Op::OpTypeBool, 0);
6203
0
        if (lBool == rBool) {
6204
0
            spv::Id logicalCopy = builder.createUnaryOp(spv::Op::OpCopyLogical, lType, rValue);
6205
0
            accessChainStore(type, logicalCopy);
6206
0
            return;
6207
0
        }
6208
0
    }
6209
6210
    // If an array, copy element by element.
6211
2.19k
    if (type.isArray()) {
6212
1.89k
        glslang::TType glslangElementType(type, 0);
6213
1.89k
        spv::Id elementRType = builder.getContainedTypeId(rType);
6214
5.72k
        for (int index = 0; index < type.getOuterArraySize(); ++index) {
6215
            // get the source member
6216
3.82k
            spv::Id elementRValue = builder.createCompositeExtract(rValue, elementRType, index);
6217
6218
            // set up the target storage
6219
3.82k
            builder.clearAccessChain();
6220
3.82k
            builder.setAccessChainLValue(lValue);
6221
3.82k
            builder.accessChainPush(builder.makeIntConstant(index), TranslateCoherent(type),
6222
3.82k
                type.getBufferReferenceAlignment());
6223
6224
            // store the member
6225
3.82k
            multiTypeStore(glslangElementType, elementRValue);
6226
3.82k
        }
6227
1.89k
    } else {
6228
298
        assert(type.isStruct());
6229
6230
        // loop over structure members
6231
298
        const glslang::TTypeList& members = *type.getStruct();
6232
707
        for (int m = 0; m < (int)members.size(); ++m) {
6233
409
            const glslang::TType& glslangMemberType = *members[m].type;
6234
6235
            // get the source member
6236
409
            spv::Id memberRType = builder.getContainedTypeId(rType, m);
6237
409
            spv::Id memberRValue = builder.createCompositeExtract(rValue, memberRType, m);
6238
6239
            // set up the target storage
6240
409
            builder.clearAccessChain();
6241
409
            builder.setAccessChainLValue(lValue);
6242
409
            builder.accessChainPush(builder.makeIntConstant(m), TranslateCoherent(type),
6243
409
                type.getBufferReferenceAlignment());
6244
6245
            // store the member
6246
409
            multiTypeStore(glslangMemberType, memberRValue);
6247
409
        }
6248
298
    }
6249
2.19k
}
6250
6251
// Decide whether or not this type should be
6252
// decorated with offsets and strides, and if so
6253
// whether std140 or std430 rules should be applied.
6254
glslang::TLayoutPacking TGlslangToSpvTraverser::getExplicitLayout(const glslang::TType& type) const
6255
105k
{
6256
    // has to be a block
6257
105k
    if (type.getBasicType() != glslang::EbtBlock)
6258
103k
        return glslang::ElpNone;
6259
6260
    // has to be a uniform or buffer block or task in/out blocks
6261
2.35k
    if (type.getQualifier().storage != glslang::EvqUniform &&
6262
1.51k
        type.getQualifier().storage != glslang::EvqBuffer &&
6263
13
        type.getQualifier().storage != glslang::EvqShared &&
6264
13
        !type.getQualifier().isTaskMemory())
6265
13
        return glslang::ElpNone;
6266
6267
    // return the layout to use
6268
2.33k
    switch (type.getQualifier().layoutPacking) {
6269
839
    case glslang::ElpStd140:
6270
2.33k
    case glslang::ElpStd430:
6271
2.33k
    case glslang::ElpScalar:
6272
2.33k
        return type.getQualifier().layoutPacking;
6273
0
    default:
6274
0
        return glslang::ElpNone;
6275
2.33k
    }
6276
2.33k
}
6277
6278
// Given an array type, returns the integer stride required for that array
6279
int TGlslangToSpvTraverser::getArrayStride(const glslang::TType& arrayType, glslang::TLayoutPacking explicitLayout,
6280
    glslang::TLayoutMatrix matrixLayout)
6281
489
{
6282
489
    int size;
6283
489
    int stride;
6284
489
    glslangIntermediate->getMemberAlignment(arrayType, size, stride, explicitLayout,
6285
489
        matrixLayout == glslang::ElmRowMajor);
6286
6287
489
    return stride;
6288
489
}
6289
6290
// Given a matrix type, or array (of array) of matrixes type, returns the integer stride required for that matrix
6291
// when used as a member of an interface block
6292
int TGlslangToSpvTraverser::getMatrixStride(const glslang::TType& matrixType, glslang::TLayoutPacking explicitLayout,
6293
    glslang::TLayoutMatrix matrixLayout)
6294
286
{
6295
286
    glslang::TType elementType;
6296
286
    elementType.shallowCopy(matrixType);
6297
286
    elementType.clearArraySizes();
6298
6299
286
    int size;
6300
286
    int stride;
6301
286
    glslangIntermediate->getMemberAlignment(elementType, size, stride, explicitLayout,
6302
286
        matrixLayout == glslang::ElmRowMajor);
6303
6304
286
    return stride;
6305
286
}
6306
6307
// Given a member type of a struct, realign the current offset for it, and compute
6308
// the next (not yet aligned) offset for the next member, which will get aligned
6309
// on the next call.
6310
// 'currentOffset' should be passed in already initialized, ready to modify, and reflecting
6311
// the migration of data from nextOffset -> currentOffset.  It should be -1 on the first call.
6312
// -1 means a non-forced member offset (no decoration needed).
6313
void TGlslangToSpvTraverser::updateMemberOffset(const glslang::TType& structType, const glslang::TType& memberType,
6314
    int& currentOffset, int& nextOffset, glslang::TLayoutPacking explicitLayout, glslang::TLayoutMatrix matrixLayout)
6315
6.00k
{
6316
    // this will get a positive value when deemed necessary
6317
6.00k
    nextOffset = -1;
6318
6319
    // override anything in currentOffset with user-set offset
6320
6.00k
    if (memberType.getQualifier().hasOffset())
6321
1.94k
        currentOffset = memberType.getQualifier().layoutOffset;
6322
6323
    // It could be that current linker usage in glslang updated all the layoutOffset,
6324
    // in which case the following code does not matter.  But, that's not quite right
6325
    // once cross-compilation unit GLSL validation is done, as the original user
6326
    // settings are needed in layoutOffset, and then the following will come into play.
6327
6328
6.00k
    if (explicitLayout == glslang::ElpNone) {
6329
0
        if (! memberType.getQualifier().hasOffset())
6330
0
            currentOffset = -1;
6331
6332
0
        return;
6333
0
    }
6334
6335
    // Getting this far means we need explicit offsets
6336
6.00k
    if (currentOffset < 0)
6337
1.87k
        currentOffset = 0;
6338
6339
    // Now, currentOffset is valid (either 0, or from a previous nextOffset),
6340
    // but possibly not yet correctly aligned.
6341
6342
6.00k
    int memberSize;
6343
6.00k
    int dummyStride;
6344
6.00k
    int memberAlignment = glslangIntermediate->getMemberAlignment(memberType, memberSize, dummyStride, explicitLayout,
6345
6.00k
        matrixLayout == glslang::ElmRowMajor);
6346
6347
6.00k
    bool isVectorLike = memberType.isVector();
6348
6.00k
    if (memberType.isMatrix()) {
6349
286
        if (matrixLayout == glslang::ElmRowMajor)
6350
12
            isVectorLike = memberType.getMatrixRows() == 1;
6351
274
        else
6352
274
            isVectorLike = memberType.getMatrixCols() == 1;
6353
286
    }
6354
6355
    // Adjust alignment for HLSL rules
6356
    // TODO: make this consistent in early phases of code:
6357
    //       adjusting this late means inconsistencies with earlier code, which for reflection is an issue
6358
    // Until reflection is brought in sync with these adjustments, don't apply to $Global,
6359
    // which is the most likely to rely on reflection, and least likely to rely implicit layouts
6360
6.00k
    if (glslangIntermediate->usingHlslOffsets() &&
6361
1.24k
        ! memberType.isStruct() && structType.getTypeName().compare("$Global") != 0) {
6362
1.03k
        int componentSize;
6363
1.03k
        int componentAlignment = glslangIntermediate->getBaseAlignmentScalar(memberType, componentSize);
6364
1.03k
        if (! memberType.isArray() && isVectorLike && componentAlignment <= 4)
6365
310
            memberAlignment = componentAlignment;
6366
6367
        // Don't add unnecessary padding after this member
6368
        // (undo std140 bumping size to a mutliple of vec4)
6369
1.03k
        if (explicitLayout == glslang::ElpStd140) {
6370
456
            if (memberType.isMatrix()) {
6371
2
                if (matrixLayout == glslang::ElmRowMajor)
6372
0
                    memberSize -= componentSize * (4 - memberType.getMatrixCols());
6373
2
                else
6374
2
                    memberSize -= componentSize * (4 - memberType.getMatrixRows());
6375
454
            } else if (memberType.isArray())
6376
50
                memberSize -= componentSize * (4 - memberType.getVectorSize());
6377
456
        }
6378
1.03k
    }
6379
6380
    // Bump up to member alignment
6381
6.00k
    glslang::RoundToPow2(currentOffset, memberAlignment);
6382
6383
    // Bump up to vec4 if there is a bad straddle
6384
6.00k
    if (explicitLayout != glslang::ElpScalar && glslangIntermediate->improperStraddle(memberType, memberSize,
6385
5.95k
        currentOffset, isVectorLike))
6386
8
        glslang::RoundToPow2(currentOffset, 16);
6387
6388
6.00k
    nextOffset = currentOffset + memberSize;
6389
6.00k
}
6390
6391
void TGlslangToSpvTraverser::declareUseOfStructMember(const glslang::TTypeList& members, int glslangMember)
6392
8.40k
{
6393
8.40k
    const glslang::TBuiltInVariable glslangBuiltIn = members[glslangMember].type->getQualifier().builtIn;
6394
8.40k
    switch (glslangBuiltIn)
6395
8.40k
    {
6396
0
    case glslang::EbvPointSize:
6397
0
    case glslang::EbvClipDistance:
6398
0
    case glslang::EbvCullDistance:
6399
0
    case glslang::EbvViewportMaskNV:
6400
0
    case glslang::EbvSecondaryPositionNV:
6401
0
    case glslang::EbvSecondaryViewportMaskNV:
6402
0
    case glslang::EbvPositionPerViewNV:
6403
0
    case glslang::EbvViewportMaskPerViewNV:
6404
0
    case glslang::EbvTaskCountNV:
6405
0
    case glslang::EbvPrimitiveCountNV:
6406
0
    case glslang::EbvPrimitiveIndicesNV:
6407
0
    case glslang::EbvClipDistancePerViewNV:
6408
0
    case glslang::EbvCullDistancePerViewNV:
6409
0
    case glslang::EbvLayerPerViewNV:
6410
0
    case glslang::EbvMeshViewCountNV:
6411
0
    case glslang::EbvMeshViewIndicesNV:
6412
        // Generate the associated capability.  Delegate to TranslateBuiltInDecoration.
6413
        // Alternately, we could just call this for any glslang built-in, since the
6414
        // capability already guards against duplicates.
6415
0
        TranslateBuiltInDecoration(glslangBuiltIn, false);
6416
0
        break;
6417
8.40k
    default:
6418
        // Capabilities were already generated when the struct was declared.
6419
8.40k
        break;
6420
8.40k
    }
6421
8.40k
}
6422
6423
bool TGlslangToSpvTraverser::isShaderEntryPoint(const glslang::TIntermAggregate* node)
6424
6.48k
{
6425
6.48k
    return node->getName().compare(glslangIntermediate->getEntryPointMangledName().c_str()) == 0;
6426
6.48k
}
6427
6428
// Does parameter need a place to keep writes, separate from the original?
6429
// Assumes called after originalParam(), which filters out block/buffer/opaque-based
6430
// qualifiers such that we should have only in/out/inout/constreadonly here.
6431
bool TGlslangToSpvTraverser::writableParam(glslang::TStorageQualifier qualifier) const
6432
9.03k
{
6433
9.03k
    assert(qualifier == glslang::EvqIn ||
6434
9.03k
           qualifier == glslang::EvqOut ||
6435
9.03k
           qualifier == glslang::EvqInOut ||
6436
9.03k
           qualifier == glslang::EvqUniform ||
6437
9.03k
           qualifier == glslang::EvqConstReadOnly);
6438
9.03k
    return qualifier != glslang::EvqConstReadOnly &&
6439
8.83k
           qualifier != glslang::EvqUniform;
6440
9.03k
}
6441
6442
// Is parameter pass-by-original?
6443
bool TGlslangToSpvTraverser::originalParam(glslang::TStorageQualifier qualifier, const glslang::TType& paramType,
6444
                                           bool implicitThisParam)
6445
9.20k
{
6446
9.20k
    if (implicitThisParam)                                                                     // implicit this
6447
0
        return true;
6448
9.20k
    if (glslangIntermediate->getSource() == glslang::EShSourceHlsl)
6449
8
        return paramType.getBasicType() == glslang::EbtBlock;
6450
9.19k
    return (paramType.containsOpaque() && !glslangIntermediate->getBindlessMode()) ||       // sampler, etc.
6451
9.02k
           paramType.getQualifier().isSpirvByReference() ||                                    // spirv_by_reference
6452
9.02k
           (paramType.getBasicType() == glslang::EbtBlock && qualifier == glslang::EvqBuffer); // SSBO
6453
9.20k
}
6454
6455
// Make all the functions, skeletally, without actually visiting their bodies.
6456
void TGlslangToSpvTraverser::makeFunctions(const glslang::TIntermSequence& glslFunctions)
6457
2.08k
{
6458
2.08k
    const auto getParamDecorations = [&](std::vector<spv::Decoration>& decorations, const glslang::TType& type,
6459
2.08k
        bool useVulkanMemoryModel) {
6460
1.84k
        spv::Decoration paramPrecision = TranslatePrecisionDecoration(type);
6461
1.84k
        if (paramPrecision != spv::NoPrecision)
6462
49
            decorations.push_back(paramPrecision);
6463
1.84k
        TranslateMemoryDecoration(type.getQualifier(), decorations, useVulkanMemoryModel);
6464
1.84k
        if (type.isReference()) {
6465
            // Original and non-writable params pass the pointer directly and
6466
            // use restrict/aliased, others are stored to a pointer in Function
6467
            // memory and use RestrictPointer/AliasedPointer.
6468
8
            if (originalParam(type.getQualifier().storage, type, false) ||
6469
8
                !writableParam(type.getQualifier().storage)) {
6470
                // TranslateMemoryDecoration added Restrict decoration already.
6471
4
                if (!type.getQualifier().isRestrict()) {
6472
2
                    decorations.push_back(spv::Decoration::Aliased);
6473
2
                }
6474
4
            } else {
6475
4
                decorations.push_back(type.getQualifier().isRestrict() ? spv::Decoration::RestrictPointerEXT :
6476
4
                                                                         spv::Decoration::AliasedPointerEXT);
6477
4
            }
6478
8
        }
6479
1.84k
    };
6480
6481
7.84k
    for (int f = 0; f < (int)glslFunctions.size(); ++f) {
6482
5.75k
        glslang::TIntermAggregate* glslFunction = glslFunctions[f]->getAsAggregate();
6483
5.75k
        if (! glslFunction || glslFunction->getOp() != glslang::EOpFunction)
6484
2.51k
            continue;
6485
6486
3.24k
        builder.setDebugSourceLocation(glslFunction->getLoc().line, glslFunction->getLoc().getFilename());
6487
6488
3.24k
        if (isShaderEntryPoint(glslFunction)) {
6489
            // For HLSL, the entry function is actually a compiler generated function to resolve the difference of
6490
            // entry function signature between HLSL and SPIR-V. So we don't emit debug information for that.
6491
2.02k
            if (glslangIntermediate->getSource() != glslang::EShSourceHlsl) {
6492
2.02k
                builder.setupFunctionDebugInfo(shaderEntry, glslangIntermediate->getEntryPointMangledName().c_str(),
6493
2.02k
                                               std::vector<spv::Id>(), // main function has no param
6494
2.02k
                                               std::vector<char const*>());
6495
2.02k
            }
6496
2.02k
            continue;
6497
2.02k
        }
6498
        // We're on a user function.  Set up the basic interface for the function now,
6499
        // so that it's available to call.  Translating the body will happen later.
6500
        //
6501
        // Typically (except for a "const in" parameter), an address will be passed to the
6502
        // function.  What it is an address of varies:
6503
        //
6504
        // - "in" parameters not marked as "const" can be written to without modifying the calling
6505
        //   argument so that write needs to be to a copy, hence the address of a copy works.
6506
        //
6507
        // - "const in" parameters can just be the r-value, as no writes need occur.
6508
        //
6509
        // - "out" and "inout" arguments can't be done as pointers to the calling argument, because
6510
        //   GLSL has copy-in/copy-out semantics.  They can be handled though with a pointer to a copy.
6511
6512
1.21k
        std::vector<spv::Id> paramTypes;
6513
1.21k
        std::vector<char const*> paramNames;
6514
1.21k
        std::vector<std::vector<spv::Decoration>> paramDecorations; // list of decorations per parameter
6515
1.21k
        glslang::TIntermSequence& parameters = glslFunction->getSequence()[0]->getAsAggregate()->getSequence();
6516
6517
1.21k
#ifdef ENABLE_HLSL
6518
1.21k
        bool implicitThis = (int)parameters.size() > 0 && parameters[0]->getAsSymbolNode()->getName() ==
6519
921
                                                          glslangIntermediate->implicitThisName;
6520
#else
6521
        bool implicitThis = false;
6522
#endif
6523
6524
1.21k
        paramDecorations.resize(parameters.size());
6525
3.06k
        for (int p = 0; p < (int)parameters.size(); ++p) {
6526
1.84k
            const glslang::TType& paramType = parameters[p]->getAsTyped()->getType();
6527
1.84k
            spv::Id typeId = convertGlslangToSpvType(paramType);
6528
1.84k
            if (originalParam(paramType.getQualifier().storage, paramType, implicitThis && p == 0))
6529
29
                typeId = builder.makePointer(TranslateStorageClass(paramType), typeId);
6530
1.82k
            else if (writableParam(paramType.getQualifier().storage))
6531
1.78k
                typeId = builder.makePointer(spv::StorageClass::Function, typeId);
6532
32
            else
6533
32
                rValueParameters.insert(parameters[p]->getAsSymbolNode()->getId());
6534
1.84k
            getParamDecorations(paramDecorations[p], paramType, glslangIntermediate->usingVulkanMemoryModel());
6535
1.84k
            paramTypes.push_back(typeId);
6536
1.84k
        }
6537
6538
1.84k
        for (auto const parameter:parameters) {
6539
1.84k
            paramNames.push_back(parameter->getAsSymbolNode()->getName().c_str());
6540
1.84k
        }
6541
6542
1.21k
        spv::Block* functionBlock;
6543
1.21k
        spv::Function* function = builder.makeFunctionEntry(
6544
1.21k
            TranslatePrecisionDecoration(glslFunction->getType()), convertGlslangToSpvType(glslFunction->getType()),
6545
1.21k
            glslFunction->getName().c_str(), convertGlslangLinkageToSpv(glslFunction->getLinkType()), paramTypes,
6546
1.21k
            paramDecorations, &functionBlock);
6547
1.21k
        builder.setupFunctionDebugInfo(function, glslFunction->getName().c_str(), paramTypes, paramNames);
6548
1.21k
        if (implicitThis)
6549
0
            function->setImplicitThis();
6550
6551
        // Track function to emit/call later
6552
1.21k
        functionMap[glslFunction->getName().c_str()] = function;
6553
6554
        // Set the parameter id's
6555
3.06k
        for (int p = 0; p < (int)parameters.size(); ++p) {
6556
1.84k
            symbolValues[parameters[p]->getAsSymbolNode()->getId()] = function->getParamId(p);
6557
            // give a name too
6558
1.84k
            builder.addName(function->getParamId(p), parameters[p]->getAsSymbolNode()->getName().c_str());
6559
6560
1.84k
            const glslang::TType& paramType = parameters[p]->getAsTyped()->getType();
6561
1.84k
            if (paramType.contains8BitInt())
6562
0
                builder.addCapability(spv::Capability::Int8);
6563
1.84k
            if (paramType.contains16BitInt())
6564
0
                builder.addCapability(spv::Capability::Int16);
6565
1.84k
            if (paramType.contains16BitFloat())
6566
1
                builder.addCapability(spv::Capability::Float16);
6567
1.84k
        }
6568
1.21k
    }
6569
2.08k
}
6570
6571
// Process all the initializers, while skipping the functions and link objects
6572
void TGlslangToSpvTraverser::makeGlobalInitializers(const glslang::TIntermSequence& initializers)
6573
2.08k
{
6574
2.08k
    builder.setBuildPoint(shaderEntry->getLastBlock());
6575
7.84k
    for (int i = 0; i < (int)initializers.size(); ++i) {
6576
5.75k
        glslang::TIntermAggregate* initializer = initializers[i]->getAsAggregate();
6577
5.75k
        if (initializer && initializer->getOp() != glslang::EOpFunction && initializer->getOp() !=
6578
2.51k
            glslang::EOpLinkerObjects) {
6579
6580
            // We're on a top-level node that's not a function.  Treat as an initializer, whose
6581
            // code goes into the beginning of the entry point.
6582
429
            initializer->traverse(this);
6583
429
        }
6584
5.75k
    }
6585
2.08k
}
6586
// Walk over all linker objects to create a map for payload and callable data linker objects
6587
// and their location to be used during codegen for OpTraceKHR and OpExecuteCallableKHR
6588
// This is done here since it is possible that these linker objects are not be referenced in the AST
6589
void TGlslangToSpvTraverser::collectRayTracingLinkerObjects()
6590
46
{
6591
46
    glslang::TIntermAggregate* linkerObjects = glslangIntermediate->findLinkerObjects();
6592
438
    for (auto& objSeq : linkerObjects->getSequence()) {
6593
438
        auto objNode = objSeq->getAsSymbolNode();
6594
438
        if (objNode != nullptr) {
6595
438
            if (objNode->getQualifier().hasLocation()) {
6596
4
                unsigned int location = objNode->getQualifier().layoutLocation;
6597
4
                auto st = objNode->getQualifier().storage;
6598
4
                int set;
6599
4
                switch (st)
6600
4
                {
6601
0
                case glslang::EvqPayload:
6602
0
                case glslang::EvqPayloadIn:
6603
0
                    set = 0;
6604
0
                    break;
6605
0
                case glslang::EvqCallableData:
6606
0
                case glslang::EvqCallableDataIn:
6607
0
                    set = 1;
6608
0
                    break;
6609
6610
0
                case glslang::EvqHitObjectAttrNV:
6611
0
                case glslang::EvqHitObjectAttrEXT:
6612
0
                    set = 2;
6613
0
                    break;
6614
6615
4
                default:
6616
4
                    set = -1;
6617
4
                }
6618
4
                if (set != -1)
6619
0
                    locationToSymbol[set].insert(std::make_pair(location, objNode));
6620
4
            }
6621
438
        }
6622
438
    }
6623
46
}
6624
// Process all the functions, while skipping initializers.
6625
void TGlslangToSpvTraverser::visitFunctions(const glslang::TIntermSequence& glslFunctions)
6626
2.08k
{
6627
7.84k
    for (int f = 0; f < (int)glslFunctions.size(); ++f) {
6628
5.75k
        glslang::TIntermAggregate* node = glslFunctions[f]->getAsAggregate();
6629
5.75k
        if (node && (node->getOp() == glslang::EOpFunction || node->getOp() == glslang::EOpLinkerObjects))
6630
5.32k
            node->traverse(this);
6631
5.75k
    }
6632
2.08k
}
6633
6634
void TGlslangToSpvTraverser::translateArguments(const glslang::TIntermAggregate& node, std::vector<spv::Id>& arguments,
6635
    spv::Builder::AccessChain::CoherentFlags &lvalueCoherentFlags)
6636
7.12k
{
6637
7.12k
    const glslang::TIntermSequence& glslangArguments = node.getSequence();
6638
6639
7.12k
    glslang::TSampler sampler = {};
6640
7.12k
    bool cubeCompare = false;
6641
7.12k
    bool f16ShadowCompare = false;
6642
7.12k
    if (node.isTexture() || node.isImage()) {
6643
4.88k
        sampler = glslangArguments[0]->getAsTyped()->getType().getSampler();
6644
4.88k
        cubeCompare = sampler.dim == glslang::EsdCube && sampler.arrayed && sampler.shadow;
6645
4.88k
        f16ShadowCompare = sampler.shadow &&
6646
561
            glslangArguments[1]->getAsTyped()->getType().getBasicType() == glslang::EbtFloat16;
6647
4.88k
    }
6648
6649
26.7k
    for (int i = 0; i < (int)glslangArguments.size(); ++i) {
6650
19.5k
        builder.clearAccessChain();
6651
19.5k
        glslangArguments[i]->traverse(this);
6652
6653
        // Special case l-value operands
6654
19.5k
        bool lvalue = false;
6655
19.5k
        switch (node.getOp()) {
6656
1.28k
        case glslang::EOpImageAtomicAdd:
6657
2.57k
        case glslang::EOpImageAtomicMin:
6658
3.85k
        case glslang::EOpImageAtomicMax:
6659
4.08k
        case glslang::EOpImageAtomicAnd:
6660
4.34k
        case glslang::EOpImageAtomicOr:
6661
4.60k
        case glslang::EOpImageAtomicXor:
6662
5.89k
        case glslang::EOpImageAtomicExchange:
6663
6.23k
        case glslang::EOpImageAtomicCompSwap:
6664
6.36k
        case glslang::EOpImageAtomicLoad:
6665
6.53k
        case glslang::EOpImageAtomicStore:
6666
6.53k
            if (i == 0)
6667
1.86k
                lvalue = true;
6668
6.53k
            break;
6669
312
        case glslang::EOpSparseImageLoad:
6670
312
            if ((sampler.ms && i == 3) || (! sampler.ms && i == 2))
6671
102
                lvalue = true;
6672
312
            break;
6673
147
        case glslang::EOpSparseTexture:
6674
147
            if (((cubeCompare || f16ShadowCompare) && i == 3) || (! (cubeCompare || f16ShadowCompare) && i == 2))
6675
44
                lvalue = true;
6676
147
            break;
6677
158
        case glslang::EOpSparseTextureClamp:
6678
158
            if (((cubeCompare || f16ShadowCompare) && i == 4) || (! (cubeCompare || f16ShadowCompare) && i == 3))
6679
36
                lvalue = true;
6680
158
            break;
6681
97
        case glslang::EOpSparseTextureLod:
6682
216
        case glslang::EOpSparseTextureOffset:
6683
216
            if  ((f16ShadowCompare && i == 4) || (! f16ShadowCompare && i == 3))
6684
52
                lvalue = true;
6685
216
            break;
6686
69
        case glslang::EOpSparseTextureFetch:
6687
69
            if ((sampler.dim != glslang::EsdRect && i == 3) || (sampler.dim == glslang::EsdRect && i == 2))
6688
18
                lvalue = true;
6689
69
            break;
6690
57
        case glslang::EOpSparseTextureFetchOffset:
6691
57
            if ((sampler.dim != glslang::EsdRect && i == 4) || (sampler.dim == glslang::EsdRect && i == 3))
6692
12
                lvalue = true;
6693
57
            break;
6694
81
        case glslang::EOpSparseTextureLodOffset:
6695
285
        case glslang::EOpSparseTextureGrad:
6696
391
        case glslang::EOpSparseTextureOffsetClamp:
6697
391
            if ((f16ShadowCompare && i == 5) || (! f16ShadowCompare && i == 4))
6698
76
                lvalue = true;
6699
391
            break;
6700
171
        case glslang::EOpSparseTextureGradOffset:
6701
171
        case glslang::EOpSparseTextureGradClamp:
6702
171
            if ((f16ShadowCompare && i == 6) || (! f16ShadowCompare && i == 5))
6703
28
                lvalue = true;
6704
171
            break;
6705
142
        case glslang::EOpSparseTextureGradOffsetClamp:
6706
142
            if ((f16ShadowCompare && i == 7) || (! f16ShadowCompare && i == 6))
6707
20
                lvalue = true;
6708
142
            break;
6709
164
        case glslang::EOpSparseTextureGather:
6710
164
            if ((sampler.shadow && i == 3) || (! sampler.shadow && i == 2))
6711
40
                lvalue = true;
6712
164
            break;
6713
122
        case glslang::EOpSparseTextureGatherOffset:
6714
244
        case glslang::EOpSparseTextureGatherOffsets:
6715
244
            if ((sampler.shadow && i == 4) || (! sampler.shadow && i == 3))
6716
48
                lvalue = true;
6717
244
            break;
6718
80
        case glslang::EOpSparseTextureGatherLod:
6719
80
            if (i == 3)
6720
16
                lvalue = true;
6721
80
            break;
6722
48
        case glslang::EOpSparseTextureGatherLodOffset:
6723
96
        case glslang::EOpSparseTextureGatherLodOffsets:
6724
96
            if (i == 4)
6725
16
                lvalue = true;
6726
96
            break;
6727
208
        case glslang::EOpSparseImageLoadLod:
6728
208
            if (i == 3)
6729
52
                lvalue = true;
6730
208
            break;
6731
0
        case glslang::EOpImageSampleFootprintNV:
6732
0
            if (i == 4)
6733
0
                lvalue = true;
6734
0
            break;
6735
0
        case glslang::EOpImageSampleFootprintClampNV:
6736
0
        case glslang::EOpImageSampleFootprintLodNV:
6737
0
            if (i == 5)
6738
0
                lvalue = true;
6739
0
            break;
6740
0
        case glslang::EOpImageSampleFootprintGradNV:
6741
0
            if (i == 6)
6742
0
                lvalue = true;
6743
0
            break;
6744
0
        case glslang::EOpImageSampleFootprintGradClampNV:
6745
0
            if (i == 7)
6746
0
                lvalue = true;
6747
0
            break;
6748
0
        case glslang::EOpRayQueryGetIntersectionTriangleVertexPositionsEXT:
6749
0
        case glslang::EOpRayQueryGetIntersectionLSSPositionsNV:
6750
0
        case glslang::EOpRayQueryGetIntersectionLSSRadiiNV:
6751
0
            if (i == 2)
6752
0
                lvalue = true;
6753
0
            break;
6754
0
        case glslang::EOpConstructSaturated:
6755
0
            if (i == 0)
6756
0
                lvalue = true;
6757
0
            break;
6758
10.6k
        default:
6759
10.6k
            break;
6760
19.5k
        }
6761
6762
19.5k
        if (lvalue) {
6763
2.42k
            spv::Id lvalue_id = builder.accessChainGetLValue();
6764
2.42k
            arguments.push_back(lvalue_id);
6765
2.42k
            lvalueCoherentFlags = builder.getAccessChain().coherentFlags;
6766
2.42k
            builder.addDecoration(lvalue_id, TranslateNonUniformDecoration(lvalueCoherentFlags));
6767
2.42k
            lvalueCoherentFlags |= TranslateCoherent(glslangArguments[i]->getAsTyped()->getType());
6768
17.1k
        } else {
6769
17.1k
            if (i > 0 &&
6770
11.9k
                glslangArguments[i]->getAsSymbolNode() && glslangArguments[i-1]->getAsSymbolNode() &&
6771
3.41k
                glslangArguments[i]->getAsSymbolNode()->getId() == glslangArguments[i-1]->getAsSymbolNode()->getId()) {
6772
                // Reuse the id if possible
6773
321
                arguments.push_back(arguments[i-1]);
6774
16.8k
            } else {
6775
16.8k
                arguments.push_back(accessChainLoad(glslangArguments[i]->getAsTyped()->getType()));
6776
16.8k
            }
6777
17.1k
        }
6778
19.5k
    }
6779
7.12k
}
6780
6781
void TGlslangToSpvTraverser::translateArguments(glslang::TIntermUnary& node, std::vector<spv::Id>& arguments)
6782
125
{
6783
125
    builder.clearAccessChain();
6784
125
    node.getOperand()->traverse(this);
6785
125
    arguments.push_back(accessChainLoad(node.getOperand()->getType()));
6786
125
}
6787
6788
spv::Id TGlslangToSpvTraverser::createImageTextureFunctionCall(glslang::TIntermOperator* node)
6789
72.3k
{
6790
72.3k
    if (! node->isImage() && ! node->isTexture())
6791
67.2k
        return spv::NoResult;
6792
6793
5.00k
    builder.setDebugSourceLocation(node->getLoc().line, node->getLoc().getFilename());
6794
6795
    // Process a GLSL texturing op (will be SPV image)
6796
6797
5.00k
    const glslang::TType &imageType = node->getAsAggregate()
6798
5.00k
                                        ? node->getAsAggregate()->getSequence()[0]->getAsTyped()->getType()
6799
5.00k
                                        : node->getAsUnaryNode()->getOperand()->getAsTyped()->getType();
6800
5.00k
    const glslang::TSampler sampler = imageType.getSampler();
6801
5.00k
    bool f16ShadowCompare = (sampler.shadow && node->getAsAggregate())
6802
5.00k
            ? node->getAsAggregate()->getSequence()[1]->getAsTyped()->getType().getBasicType() == glslang::EbtFloat16
6803
5.00k
            : false;
6804
6805
5.00k
    const auto signExtensionMask = [&]() {
6806
2.75k
        if (builder.getSpvVersion() >= spv::Spv_1_4) {
6807
0
            if (sampler.type == glslang::EbtUint)
6808
0
                return spv::ImageOperandsMask::ZeroExtend;
6809
0
            else if (sampler.type == glslang::EbtInt)
6810
0
                return spv::ImageOperandsMask::SignExtend;
6811
0
        }
6812
2.75k
        return spv::ImageOperandsMask::MaskNone;
6813
2.75k
    };
6814
6815
5.00k
    spv::Builder::AccessChain::CoherentFlags lvalueCoherentFlags;
6816
6817
5.00k
    std::vector<spv::Id> arguments;
6818
5.00k
    if (node->getAsAggregate())
6819
4.88k
        translateArguments(*node->getAsAggregate(), arguments, lvalueCoherentFlags);
6820
125
    else
6821
125
        translateArguments(*node->getAsUnaryNode(), arguments);
6822
5.00k
    spv::Decoration precision = TranslatePrecisionDecoration(node->getType());
6823
6824
5.00k
    spv::Builder::TextureParameters params = { };
6825
5.00k
    params.sampler = arguments[0];
6826
6827
5.00k
    glslang::TCrackedTextureOp cracked;
6828
5.00k
    node->crackTexture(sampler, cracked);
6829
6830
5.00k
    const bool isUnsignedResult = node->getType().getBasicType() == glslang::EbtUint;
6831
6832
5.00k
    if (builder.isSampledImage(params.sampler) &&
6833
2.43k
        ((cracked.query && node->getOp() != glslang::EOpTextureQueryLod) || cracked.fragMask || cracked.fetch)) {
6834
357
        params.sampler = builder.createUnaryOp(spv::Op::OpImage, builder.getImageType(params.sampler), params.sampler);
6835
357
        if (imageType.getQualifier().isNonUniform()) {
6836
1
            builder.addDecoration(params.sampler, spv::Decoration::NonUniformEXT);
6837
1
        }
6838
357
    }
6839
    // Check for queries
6840
5.00k
    if (cracked.query) {
6841
380
        switch (node->getOp()) {
6842
0
        case glslang::EOpImageQuerySize:
6843
261
        case glslang::EOpTextureQuerySize:
6844
261
            if (arguments.size() > 1) {
6845
210
                params.lod = arguments[1];
6846
210
                return builder.createTextureQueryCall(spv::Op::OpImageQuerySizeLod, params, isUnsignedResult);
6847
210
            } else
6848
51
                return builder.createTextureQueryCall(spv::Op::OpImageQuerySize, params, isUnsignedResult);
6849
0
        case glslang::EOpImageQuerySamples:
6850
17
        case glslang::EOpTextureQuerySamples:
6851
17
            return builder.createTextureQueryCall(spv::Op::OpImageQuerySamples, params, isUnsignedResult);
6852
52
        case glslang::EOpTextureQueryLod:
6853
52
            params.coords = arguments[1];
6854
52
            return builder.createTextureQueryCall(spv::Op::OpImageQueryLod, params, isUnsignedResult);
6855
50
        case glslang::EOpTextureQueryLevels:
6856
50
            return builder.createTextureQueryCall(spv::Op::OpImageQueryLevels, params, isUnsignedResult);
6857
0
        case glslang::EOpSparseTexelsResident:
6858
0
            return builder.createUnaryOp(spv::Op::OpImageSparseTexelsResident, builder.makeBoolType(), arguments[0]);
6859
0
        default:
6860
0
            assert(0);
6861
0
            break;
6862
380
        }
6863
380
    }
6864
6865
4.62k
    int components = node->getType().getVectorSize();
6866
6867
4.62k
    if (node->getOp() == glslang::EOpImageLoad ||
6868
4.45k
        node->getOp() == glslang::EOpImageLoadLod ||
6869
4.37k
        node->getOp() == glslang::EOpTextureFetch ||
6870
4.31k
        node->getOp() == glslang::EOpTextureFetchOffset) {
6871
        // These must produce 4 components, per SPIR-V spec.  We'll add a conversion constructor if needed.
6872
        // This will only happen through the HLSL path for operator[], so we do not have to handle e.g.
6873
        // the EOpTexture/Proj/Lod/etc family.  It would be harmless to do so, but would need more logic
6874
        // here around e.g. which ones return scalars or other types.
6875
344
        components = 4;
6876
344
    }
6877
6878
4.62k
    glslang::TType returnType(node->getType().getBasicType(), glslang::EvqTemporary, components);
6879
6880
6.28k
    auto resultType = [&returnType,this]{ return convertGlslangToSpvType(returnType); };
6881
6882
    // Check for image functions other than queries
6883
4.62k
    if (node->isImage()) {
6884
2.47k
        std::vector<spv::IdImmediate> operands;
6885
2.47k
        auto opIt = arguments.begin();
6886
2.47k
        spv::IdImmediate image = { true, *(opIt++) };
6887
2.47k
        operands.push_back(image);
6888
6889
        // Handle subpass operations
6890
        // TODO: GLSL should change to have the "MS" only on the type rather than the
6891
        // built-in function.
6892
2.47k
        if (cracked.subpass) {
6893
            // add on the (0,0) coordinate
6894
8
            spv::Id zero = builder.makeIntConstant(0);
6895
8
            std::vector<spv::Id> comps;
6896
8
            comps.push_back(zero);
6897
8
            comps.push_back(zero);
6898
8
            spv::IdImmediate coord = { true,
6899
8
                builder.makeCompositeConstant(builder.makeVectorType(builder.makeIntType(32), 2), comps) };
6900
8
            operands.push_back(coord);
6901
8
            spv::IdImmediate imageOperands = { false, spv::ImageOperandsMask::MaskNone };
6902
8
            imageOperands.word = imageOperands.word | (unsigned)signExtensionMask();
6903
8
            if (sampler.isMultiSample()) {
6904
3
                imageOperands.word = imageOperands.word | (unsigned)spv::ImageOperandsMask::Sample;
6905
3
            }
6906
8
            if (imageOperands.word != (unsigned)spv::ImageOperandsMask::MaskNone) {
6907
3
                operands.push_back(imageOperands);
6908
3
                if (sampler.isMultiSample()) {
6909
3
                    spv::IdImmediate imageOperand = { true, *(opIt++) };
6910
3
                    operands.push_back(imageOperand);
6911
3
                }
6912
3
            }
6913
8
            spv::Id result = builder.createOp(spv::Op::OpImageRead, resultType(), operands);
6914
8
            builder.setPrecision(result, precision);
6915
8
            return result;
6916
8
        }
6917
6918
2.46k
        if (cracked.attachmentEXT) {
6919
1
            if (opIt != arguments.end()) {
6920
0
                spv::IdImmediate sample = { true, *opIt };
6921
0
                operands.push_back(sample);
6922
0
            }
6923
1
            spv::Id result = builder.createOp(spv::Op::OpColorAttachmentReadEXT, resultType(), operands);
6924
1
            builder.addExtension(spv::E_SPV_EXT_shader_tile_image);
6925
1
            builder.setPrecision(result, precision);
6926
1
            return result;
6927
1
        }
6928
6929
2.46k
        spv::IdImmediate coord = { true, *(opIt++) };
6930
2.46k
        operands.push_back(coord);
6931
2.46k
        if (node->getOp() == glslang::EOpImageLoad || node->getOp() == glslang::EOpImageLoadLod) {
6932
250
            spv::ImageOperandsMask mask = spv::ImageOperandsMask::MaskNone;
6933
250
            if (sampler.isMultiSample()) {
6934
19
                mask = mask | spv::ImageOperandsMask::Sample;
6935
19
            }
6936
250
            if (cracked.lod) {
6937
78
                builder.addExtension(spv::E_SPV_AMD_shader_image_load_store_lod);
6938
78
                builder.addCapability(spv::Capability::ImageReadWriteLodAMD);
6939
78
                mask = mask | spv::ImageOperandsMask::Lod;
6940
78
            }
6941
250
            mask = mask | TranslateImageOperands(TranslateCoherent(imageType));
6942
250
            mask = (spv::ImageOperandsMask)(mask & ~spv::ImageOperandsMask::MakeTexelAvailableKHR);
6943
250
            mask = mask | signExtensionMask();
6944
250
            if (mask != spv::ImageOperandsMask::MaskNone) {
6945
97
                spv::IdImmediate imageOperands = { false, (unsigned int)mask };
6946
97
                operands.push_back(imageOperands);
6947
97
            }
6948
250
            if (anySet(mask, spv::ImageOperandsMask::Sample)) {
6949
19
                spv::IdImmediate imageOperand = { true, *opIt++ };
6950
19
                operands.push_back(imageOperand);
6951
19
            }
6952
250
            if (anySet(mask, spv::ImageOperandsMask::Lod)) {
6953
78
                spv::IdImmediate imageOperand = { true, *opIt++ };
6954
78
                operands.push_back(imageOperand);
6955
78
            }
6956
250
            if (anySet(mask, spv::ImageOperandsMask::MakeTexelVisibleKHR)) {
6957
0
                spv::IdImmediate imageOperand = { true,
6958
0
                                    builder.makeUintConstant(TranslateMemoryScope(TranslateCoherent(imageType))) };
6959
0
                operands.push_back(imageOperand);
6960
0
            }
6961
6962
250
            if (builder.getImageTypeFormat(builder.getImageType(operands.front().word)) == spv::ImageFormat::Unknown)
6963
1
                builder.addCapability(spv::Capability::StorageImageReadWithoutFormat);
6964
6965
250
            std::vector<spv::Id> result(1, builder.createOp(spv::Op::OpImageRead, resultType(), operands));
6966
250
            builder.setPrecision(result[0], precision);
6967
6968
            // If needed, add a conversion constructor to the proper size.
6969
250
            if (components != node->getType().getVectorSize())
6970
0
                result[0] = builder.createConstructor(precision, result, convertGlslangToSpvType(node->getType()));
6971
6972
250
            return result[0];
6973
2.21k
        } else if (node->getOp() == glslang::EOpImageStore || node->getOp() == glslang::EOpImageStoreLod) {
6974
6975
            // Push the texel value before the operands
6976
191
            if (sampler.isMultiSample() || cracked.lod) {
6977
71
                spv::IdImmediate texel = { true, *(opIt + 1) };
6978
71
                operands.push_back(texel);
6979
120
            } else {
6980
120
                spv::IdImmediate texel = { true, *opIt };
6981
120
                operands.push_back(texel);
6982
120
            }
6983
6984
191
            spv::ImageOperandsMask mask = spv::ImageOperandsMask::MaskNone;
6985
191
            if (sampler.isMultiSample()) {
6986
19
                mask = mask | spv::ImageOperandsMask::Sample;
6987
19
            }
6988
191
            if (cracked.lod) {
6989
52
                builder.addExtension(spv::E_SPV_AMD_shader_image_load_store_lod);
6990
52
                builder.addCapability(spv::Capability::ImageReadWriteLodAMD);
6991
52
                mask = mask | spv::ImageOperandsMask::Lod;
6992
52
            }
6993
191
            mask = mask | TranslateImageOperands(TranslateCoherent(imageType));
6994
191
            mask = (spv::ImageOperandsMask)(mask & ~spv::ImageOperandsMask::MakeTexelVisibleKHR);
6995
191
            mask = mask | signExtensionMask();
6996
191
            if (mask != spv::ImageOperandsMask::MaskNone) {
6997
71
                spv::IdImmediate imageOperands = { false, (unsigned int)mask };
6998
71
                operands.push_back(imageOperands);
6999
71
            }
7000
191
            if (anySet(mask, spv::ImageOperandsMask::Sample)) {
7001
19
                spv::IdImmediate imageOperand = { true, *opIt++ };
7002
19
                operands.push_back(imageOperand);
7003
19
            }
7004
191
            if (anySet(mask, spv::ImageOperandsMask::Lod)) {
7005
52
                spv::IdImmediate imageOperand = { true, *opIt++ };
7006
52
                operands.push_back(imageOperand);
7007
52
            }
7008
191
            if (anySet(mask, spv::ImageOperandsMask::MakeTexelAvailableKHR)) {
7009
0
                spv::IdImmediate imageOperand = { true,
7010
0
                    builder.makeUintConstant(TranslateMemoryScope(TranslateCoherent(imageType))) };
7011
0
                operands.push_back(imageOperand);
7012
0
            }
7013
7014
191
            builder.createNoResultOp(spv::Op::OpImageWrite, operands);
7015
191
            if (builder.getImageTypeFormat(builder.getImageType(operands.front().word)) == spv::ImageFormat::Unknown)
7016
2
                builder.addCapability(spv::Capability::StorageImageWriteWithoutFormat);
7017
191
            return spv::NoResult;
7018
2.02k
        } else if (node->getOp() == glslang::EOpSparseImageLoad ||
7019
1.92k
                   node->getOp() == glslang::EOpSparseImageLoadLod) {
7020
154
            builder.addCapability(spv::Capability::SparseResidency);
7021
154
            if (builder.getImageTypeFormat(builder.getImageType(operands.front().word)) == spv::ImageFormat::Unknown)
7022
0
                builder.addCapability(spv::Capability::StorageImageReadWithoutFormat);
7023
7024
154
            spv::ImageOperandsMask mask = spv::ImageOperandsMask::MaskNone;
7025
154
            if (sampler.isMultiSample()) {
7026
6
                mask = mask | spv::ImageOperandsMask::Sample;
7027
6
            }
7028
154
            if (cracked.lod) {
7029
52
                builder.addExtension(spv::E_SPV_AMD_shader_image_load_store_lod);
7030
52
                builder.addCapability(spv::Capability::ImageReadWriteLodAMD);
7031
7032
52
                mask = mask | spv::ImageOperandsMask::Lod;
7033
52
            }
7034
154
            mask = mask | TranslateImageOperands(TranslateCoherent(imageType));
7035
154
            mask = (spv::ImageOperandsMask)(mask & ~spv::ImageOperandsMask::MakeTexelAvailableKHR);
7036
154
            mask = mask | signExtensionMask();
7037
154
            if (mask != spv::ImageOperandsMask::MaskNone) {
7038
58
                spv::IdImmediate imageOperands = { false, (unsigned int)mask };
7039
58
                operands.push_back(imageOperands);
7040
58
            }
7041
154
            if (anySet(mask, spv::ImageOperandsMask::Sample)) {
7042
6
                spv::IdImmediate imageOperand = { true, *opIt++ };
7043
6
                operands.push_back(imageOperand);
7044
6
            }
7045
154
            if (anySet(mask, spv::ImageOperandsMask::Lod)) {
7046
52
                spv::IdImmediate imageOperand = { true, *opIt++ };
7047
52
                operands.push_back(imageOperand);
7048
52
            }
7049
154
            if (anySet(mask, spv::ImageOperandsMask::MakeTexelVisibleKHR)) {
7050
0
                spv::IdImmediate imageOperand = { true, builder.makeUintConstant(TranslateMemoryScope(
7051
0
                    TranslateCoherent(imageType))) };
7052
0
                operands.push_back(imageOperand);
7053
0
            }
7054
7055
            // Create the return type that was a special structure
7056
154
            spv::Id texelOut = *opIt;
7057
154
            spv::Id typeId0 = resultType();
7058
154
            spv::Id typeId1 = builder.getDerefTypeId(texelOut);
7059
154
            spv::Id resultTypeId = builder.makeStructResultType(typeId0, typeId1);
7060
7061
154
            spv::Id resultId = builder.createOp(spv::Op::OpImageSparseRead, resultTypeId, operands);
7062
7063
            // Decode the return type
7064
154
            builder.createStore(builder.createCompositeExtract(resultId, typeId1, 1), texelOut);
7065
154
            return builder.createCompositeExtract(resultId, typeId0, 0);
7066
1.86k
        } else {
7067
            // Process image atomic operations
7068
7069
            // GLSL "IMAGE_PARAMS" will involve in constructing an image texel pointer and this pointer,
7070
            // as the first source operand, is required by SPIR-V atomic operations.
7071
            // For non-MS, the sample value should be 0
7072
1.86k
            spv::IdImmediate sample = { true, sampler.isMultiSample() ? *(opIt++) : builder.makeUintConstant(0) };
7073
1.86k
            operands.push_back(sample);
7074
7075
1.86k
            spv::Id resultTypeId;
7076
1.86k
            glslang::TBasicType typeProxy = node->getBasicType();
7077
            // imageAtomicStore has a void return type so base the pointer type on
7078
            // the type of the value operand.
7079
1.86k
            if (node->getOp() == glslang::EOpImageAtomicStore) {
7080
26
                resultTypeId = builder.makePointer(spv::StorageClass::Image, builder.getTypeId(*opIt));
7081
26
                typeProxy = node->getAsAggregate()->getSequence()[0]->getAsTyped()->getType().getSampler().type;
7082
1.84k
            } else {
7083
1.84k
                resultTypeId = builder.makePointer(spv::StorageClass::Image, resultType());
7084
1.84k
            }
7085
1.86k
            spv::Id pointer = builder.createOp(spv::Op::OpImageTexelPointer, resultTypeId, operands);
7086
1.86k
            if (imageType.getQualifier().nonUniform) {
7087
1
                builder.addDecoration(pointer, spv::Decoration::NonUniformEXT);
7088
1
            }
7089
7090
1.86k
            std::vector<spv::Id> operands;
7091
1.86k
            operands.push_back(pointer);
7092
4.59k
            for (; opIt != arguments.end(); ++opIt)
7093
2.72k
                operands.push_back(*opIt);
7094
7095
1.86k
            return createAtomicOperation(node->getOp(), precision, resultType(), operands, typeProxy,
7096
1.86k
                lvalueCoherentFlags, node->getType());
7097
1.86k
        }
7098
2.46k
    }
7099
7100
    // Check for fragment mask functions other than queries
7101
2.15k
    if (cracked.fragMask) {
7102
6
        assert(sampler.ms);
7103
7104
6
        auto opIt = arguments.begin();
7105
6
        std::vector<spv::Id> operands;
7106
7107
6
        operands.push_back(params.sampler);
7108
6
        ++opIt;
7109
7110
6
        if (sampler.isSubpass()) {
7111
            // add on the (0,0) coordinate
7112
2
            spv::Id zero = builder.makeIntConstant(0);
7113
2
            std::vector<spv::Id> comps;
7114
2
            comps.push_back(zero);
7115
2
            comps.push_back(zero);
7116
2
            operands.push_back(builder.makeCompositeConstant(
7117
2
                builder.makeVectorType(builder.makeIntType(32), 2), comps));
7118
2
        }
7119
7120
13
        for (; opIt != arguments.end(); ++opIt)
7121
7
            operands.push_back(*opIt);
7122
7123
6
        spv::Op fragMaskOp = spv::Op::OpNop;
7124
6
        if (node->getOp() == glslang::EOpFragmentMaskFetch)
7125
3
            fragMaskOp = spv::Op::OpFragmentMaskFetchAMD;
7126
3
        else if (node->getOp() == glslang::EOpFragmentFetch)
7127
3
            fragMaskOp = spv::Op::OpFragmentFetchAMD;
7128
7129
6
        builder.addExtension(spv::E_SPV_AMD_shader_fragment_mask);
7130
6
        builder.addCapability(spv::Capability::FragmentMaskAMD);
7131
6
        return builder.createOp(fragMaskOp, resultType(), operands);
7132
6
    }
7133
7134
    // Check for texture functions other than queries
7135
2.15k
    bool sparse = node->isSparseTexture();
7136
2.15k
    bool imageFootprint = node->isImageFootprint();
7137
2.15k
    bool cubeCompare = sampler.dim == glslang::EsdCube && sampler.isArrayed() && sampler.isShadow();
7138
7139
    // check for bias argument
7140
2.15k
    bool bias = false;
7141
2.15k
    if (! cracked.lod && ! cracked.grad && ! cracked.fetch && ! cubeCompare) {
7142
1.40k
        int nonBiasArgCount = 2;
7143
1.40k
        if (cracked.gather)
7144
168
            ++nonBiasArgCount; // comp argument should be present when bias argument is present
7145
7146
1.40k
        if (f16ShadowCompare)
7147
61
            ++nonBiasArgCount;
7148
1.40k
        if (cracked.offset)
7149
189
            ++nonBiasArgCount;
7150
1.21k
        else if (cracked.offsets)
7151
48
            ++nonBiasArgCount;
7152
1.40k
        if (cracked.grad)
7153
0
            nonBiasArgCount += 2;
7154
1.40k
        if (cracked.lodClamp)
7155
136
            ++nonBiasArgCount;
7156
1.40k
        if (sparse)
7157
204
            ++nonBiasArgCount;
7158
1.40k
        if (imageFootprint)
7159
            //Following three extra arguments
7160
            // int granularity, bool coarse, out gl_TextureFootprint2DNV footprint
7161
0
            nonBiasArgCount += 3;
7162
1.40k
        if ((int)arguments.size() > nonBiasArgCount)
7163
119
            bias = true;
7164
1.40k
    }
7165
7166
2.15k
    if (cracked.gather) {
7167
240
        const auto& sourceExtensions = glslangIntermediate->getRequestedExtensions();
7168
240
        if (bias || cracked.lod ||
7169
240
            sourceExtensions.find(glslang::E_GL_AMD_texture_gather_bias_lod) != sourceExtensions.end()) {
7170
240
            builder.addExtension(spv::E_SPV_AMD_texture_gather_bias_lod);
7171
240
            builder.addCapability(spv::Capability::ImageGatherBiasLodAMD);
7172
240
        }
7173
240
    }
7174
7175
    // set the rest of the arguments
7176
7177
2.15k
    params.coords = arguments[1];
7178
2.15k
    int extraArgs = 0;
7179
2.15k
    bool noImplicitLod = false;
7180
7181
    // sort out where Dref is coming from
7182
2.15k
    if (cubeCompare || f16ShadowCompare) {
7183
153
        params.Dref = arguments[2];
7184
153
        ++extraArgs;
7185
1.99k
    } else if (sampler.shadow && cracked.gather) {
7186
60
        params.Dref = arguments[2];
7187
60
        ++extraArgs;
7188
1.93k
    } else if (sampler.shadow) {
7189
305
        std::vector<spv::Id> indexes;
7190
305
        int dRefComp;
7191
305
        if (cracked.proj)
7192
33
            dRefComp = 2;  // "The resulting 3rd component of P in the shadow forms is used as Dref"
7193
272
        else
7194
272
            dRefComp = builder.getNumComponents(params.coords) - 1;
7195
305
        indexes.push_back(dRefComp);
7196
305
        params.Dref = builder.createCompositeExtract(params.coords,
7197
305
            builder.getScalarTypeId(builder.getTypeId(params.coords)), indexes);
7198
305
    }
7199
7200
    // lod
7201
2.15k
    if (cracked.lod) {
7202
343
        params.lod = arguments[2 + extraArgs];
7203
343
        ++extraArgs;
7204
1.80k
    } else if (glslangIntermediate->getStage() != EShLangFragment &&
7205
820
               !(glslangIntermediate->getStage() == EShLangCompute &&
7206
820
                 glslangIntermediate->hasLayoutDerivativeModeNone())) {
7207
        // we need to invent the default lod for an explicit lod instruction for a non-fragment stage
7208
820
        noImplicitLod = true;
7209
820
    }
7210
7211
    // multisample
7212
2.15k
    if (sampler.isMultiSample()) {
7213
23
        params.sample = arguments[2 + extraArgs]; // For MS, "sample" should be specified
7214
23
        ++extraArgs;
7215
23
    }
7216
7217
    // gradient
7218
2.15k
    if (cracked.grad) {
7219
309
        params.gradX = arguments[2 + extraArgs];
7220
309
        params.gradY = arguments[3 + extraArgs];
7221
309
        extraArgs += 2;
7222
309
    }
7223
7224
    // offset and offsets
7225
2.15k
    if (cracked.offset) {
7226
517
        params.offset = arguments[2 + extraArgs];
7227
517
        ++extraArgs;
7228
1.63k
    } else if (cracked.offsets) {
7229
64
        params.offsets = arguments[2 + extraArgs];
7230
64
        ++extraArgs;
7231
64
    }
7232
7233
    // lod clamp
7234
2.15k
    if (cracked.lodClamp) {
7235
200
        params.lodClamp = arguments[2 + extraArgs];
7236
200
        ++extraArgs;
7237
200
    }
7238
    // sparse
7239
2.15k
    if (sparse) {
7240
406
        params.texelOut = arguments[2 + extraArgs];
7241
406
        ++extraArgs;
7242
406
    }
7243
    // gather component
7244
2.15k
    if (cracked.gather && ! sampler.shadow) {
7245
        // default component is 0, if missing, otherwise an argument
7246
152
        if (2 + extraArgs < (int)arguments.size()) {
7247
152
            params.component = arguments[2 + extraArgs];
7248
152
            ++extraArgs;
7249
152
        } else
7250
0
            params.component = builder.makeIntConstant(0);
7251
152
    }
7252
2.15k
    spv::Id  resultStruct = spv::NoResult;
7253
2.15k
    if (imageFootprint) {
7254
        //Following three extra arguments
7255
        // int granularity, bool coarse, out gl_TextureFootprint2DNV footprint
7256
0
        params.granularity = arguments[2 + extraArgs];
7257
0
        params.coarse = arguments[3 + extraArgs];
7258
0
        resultStruct = arguments[4 + extraArgs];
7259
0
        extraArgs += 3;
7260
0
    }
7261
7262
    // bias
7263
2.15k
    if (bias) {
7264
119
        params.bias = arguments[2 + extraArgs];
7265
119
        ++extraArgs;
7266
119
    }
7267
7268
2.15k
    if (imageFootprint) {
7269
0
        builder.addExtension(spv::E_SPV_NV_shader_image_footprint);
7270
0
        builder.addCapability(spv::Capability::ImageFootprintNV);
7271
7272
7273
        //resultStructType(OpenGL type) contains 5 elements:
7274
        //struct gl_TextureFootprint2DNV {
7275
        //    uvec2 anchor;
7276
        //    uvec2 offset;
7277
        //    uvec2 mask;
7278
        //    uint  lod;
7279
        //    uint  granularity;
7280
        //};
7281
        //or
7282
        //struct gl_TextureFootprint3DNV {
7283
        //    uvec3 anchor;
7284
        //    uvec3 offset;
7285
        //    uvec2 mask;
7286
        //    uint  lod;
7287
        //    uint  granularity;
7288
        //};
7289
0
        spv::Id resultStructType = builder.getContainedTypeId(builder.getTypeId(resultStruct));
7290
0
        assert(builder.isStructType(resultStructType));
7291
7292
        //resType (SPIR-V type) contains 6 elements:
7293
        //Member 0 must be a Boolean type scalar(LOD),
7294
        //Member 1 must be a vector of integer type, whose Signedness operand is 0(anchor),
7295
        //Member 2 must be a vector of integer type, whose Signedness operand is 0(offset),
7296
        //Member 3 must be a vector of integer type, whose Signedness operand is 0(mask),
7297
        //Member 4 must be a scalar of integer type, whose Signedness operand is 0(lod),
7298
        //Member 5 must be a scalar of integer type, whose Signedness operand is 0(granularity).
7299
0
        std::vector<spv::Id> members;
7300
0
        members.push_back(resultType());
7301
0
        for (int i = 0; i < 5; i++) {
7302
0
            members.push_back(builder.getContainedTypeId(resultStructType, i));
7303
0
        }
7304
0
        spv::Id resType = builder.makeStructType(members, {}, "ResType");
7305
7306
        //call ImageFootprintNV
7307
0
        spv::Id res = builder.createTextureCall(precision, resType, sparse, cracked.fetch, cracked.proj,
7308
0
                                                cracked.gather, noImplicitLod, params, signExtensionMask());
7309
7310
        //copy resType (SPIR-V type) to resultStructType(OpenGL type)
7311
0
        for (int i = 0; i < 5; i++) {
7312
0
            builder.clearAccessChain();
7313
0
            builder.setAccessChainLValue(resultStruct);
7314
7315
            //Accessing to a struct we created, no coherent flag is set
7316
0
            spv::Builder::AccessChain::CoherentFlags flags;
7317
0
            flags.clear();
7318
7319
0
            builder.accessChainPush(builder.makeIntConstant(i), flags, 0);
7320
0
            builder.accessChainStore(builder.createCompositeExtract(res, builder.getContainedTypeId(resType, i+1),
7321
0
                i+1), TranslateNonUniformDecoration(imageType.getQualifier()));
7322
0
        }
7323
0
        return builder.createCompositeExtract(res, resultType(), 0);
7324
0
    }
7325
7326
    // projective component (might not to move)
7327
    // GLSL: "The texture coordinates consumed from P, not including the last component of P,
7328
    //       are divided by the last component of P."
7329
    // SPIR-V:  "... (u [, v] [, w], q)... It may be a vector larger than needed, but all
7330
    //          unused components will appear after all used components."
7331
2.15k
    if (cracked.proj) {
7332
157
        int projSourceComp = builder.getNumComponents(params.coords) - 1;
7333
157
        int projTargetComp;
7334
157
        switch (sampler.dim) {
7335
48
        case glslang::Esd1D:   projTargetComp = 1;              break;
7336
55
        case glslang::Esd2D:   projTargetComp = 2;              break;
7337
36
        case glslang::EsdRect: projTargetComp = 2;              break;
7338
18
        default:               projTargetComp = projSourceComp; break;
7339
157
        }
7340
        // copy the projective coordinate if we have to
7341
157
        if (projTargetComp != projSourceComp) {
7342
81
            spv::Id projComp = builder.createCompositeExtract(params.coords,
7343
81
                                    builder.getScalarTypeId(builder.getTypeId(params.coords)), projSourceComp);
7344
81
            params.coords = builder.createCompositeInsert(projComp, params.coords,
7345
81
                                    builder.getTypeId(params.coords), projTargetComp);
7346
81
        }
7347
157
    }
7348
7349
    // nonprivate
7350
2.15k
    if (imageType.getQualifier().nonprivate) {
7351
0
        params.nonprivate = true;
7352
0
    }
7353
7354
    // volatile
7355
2.15k
    if (imageType.getQualifier().volatil) {
7356
0
        params.volatil = true;
7357
0
    }
7358
7359
2.15k
    if (imageType.getQualifier().nontemporal) {
7360
0
        params.nontemporal = true;
7361
0
    }
7362
7363
2.15k
    std::vector<spv::Id> result( 1,
7364
2.15k
        builder.createTextureCall(precision, resultType(), sparse, cracked.fetch, cracked.proj, cracked.gather,
7365
2.15k
                                  noImplicitLod, params, signExtensionMask())
7366
2.15k
    );
7367
7368
2.15k
    if (components != node->getType().getVectorSize())
7369
0
        result[0] = builder.createConstructor(precision, result, convertGlslangToSpvType(node->getType()));
7370
7371
2.15k
    return result[0];
7372
2.15k
}
7373
7374
spv::Id TGlslangToSpvTraverser::handleUserFunctionCall(const glslang::TIntermAggregate* node)
7375
2.27k
{
7376
    // Grab the function's pointer from the previously created function
7377
2.27k
    spv::Function* function = functionMap[node->getName().c_str()];
7378
2.27k
    if (! function)
7379
0
        return 0;
7380
7381
2.27k
    const glslang::TIntermSequence& glslangArgs = node->getSequence();
7382
2.27k
    const glslang::TQualifierList& qualifiers = node->getQualifierList();
7383
7384
    //  See comments in makeFunctions() for details about the semantics for parameter passing.
7385
    //
7386
    // These imply we need a four step process:
7387
    // 1. Evaluate the arguments
7388
    // 2. Allocate and make copies of in, out, and inout arguments
7389
    // 3. Make the call
7390
    // 4. Copy back the results
7391
7392
    // 1. Evaluate the arguments and their types
7393
2.27k
    std::vector<spv::Builder::AccessChain> lValues;
7394
2.27k
    std::vector<spv::Id> rValues;
7395
2.27k
    std::vector<const glslang::TType*> argTypes;
7396
4.71k
    for (int a = 0; a < (int)glslangArgs.size(); ++a) {
7397
2.44k
        argTypes.push_back(&glslangArgs[a]->getAsTyped()->getType());
7398
        // build l-value
7399
2.44k
        builder.clearAccessChain();
7400
2.44k
        glslangArgs[a]->traverse(this);
7401
        // keep outputs and pass-by-originals as l-values, evaluate others as r-values
7402
2.44k
        if (originalParam(qualifiers[a], *argTypes[a], function->hasImplicitThis() && a == 0) ||
7403
2.40k
            writableParam(qualifiers[a])) {
7404
            // save l-value
7405
2.39k
            lValues.push_back(builder.getAccessChain());
7406
2.39k
        } else {
7407
            // process r-value
7408
56
            rValues.push_back(accessChainLoad(*argTypes.back()));
7409
56
        }
7410
2.44k
    }
7411
7412
    // Reset source location to the function call location after argument evaluation
7413
2.27k
    builder.setDebugSourceLocation(node->getLoc().line, node->getLoc().getFilename());
7414
7415
    // 2. Allocate space for anything needing a copy, and if it's "in" or "inout"
7416
    // copy the original into that space.
7417
    //
7418
    // Also, build up the list of actual arguments to pass in for the call
7419
2.27k
    int lValueCount = 0;
7420
2.27k
    int rValueCount = 0;
7421
2.27k
    std::vector<spv::Id> spvArgs;
7422
4.71k
    for (int a = 0; a < (int)glslangArgs.size(); ++a) {
7423
2.44k
        spv::Id arg;
7424
2.44k
        if (originalParam(qualifiers[a], *argTypes[a], function->hasImplicitThis() && a == 0)) {
7425
45
            builder.setAccessChain(lValues[lValueCount]);
7426
45
            arg = builder.accessChainGetLValue();
7427
45
            ++lValueCount;
7428
2.40k
        } else if (writableParam(qualifiers[a])) {
7429
            // need space to hold the copy
7430
2.34k
            arg = builder.createVariable(function->getParamPrecision(a), spv::StorageClass::Function,
7431
2.34k
                builder.getContainedTypeId(function->getParamType(a)), "param");
7432
2.34k
            if (qualifiers[a] == glslang::EvqIn || qualifiers[a] == glslang::EvqInOut) {
7433
                // need to copy the input into output space
7434
2.33k
                builder.setAccessChain(lValues[lValueCount]);
7435
2.33k
                spv::Id copy = accessChainLoad(*argTypes[a]);
7436
2.33k
                builder.clearAccessChain();
7437
2.33k
                builder.setAccessChainLValue(arg);
7438
2.33k
                multiTypeStore(*argTypes[a], copy);
7439
2.33k
            }
7440
2.34k
            ++lValueCount;
7441
2.34k
        } else {
7442
            // process r-value, which involves a copy for a type mismatch
7443
56
            if (function->getParamType(a) != builder.getTypeId(rValues[rValueCount]) ||
7444
50
                TranslatePrecisionDecoration(*argTypes[a]) != function->getParamPrecision(a))
7445
28
            {
7446
28
                spv::Id argCopy = builder.createVariable(function->getParamPrecision(a), spv::StorageClass::Function, function->getParamType(a), "arg");
7447
28
                builder.clearAccessChain();
7448
28
                builder.setAccessChainLValue(argCopy);
7449
28
                multiTypeStore(*argTypes[a], rValues[rValueCount]);
7450
28
                arg = builder.createLoad(argCopy, function->getParamPrecision(a));
7451
28
            } else
7452
28
                arg = rValues[rValueCount];
7453
56
            ++rValueCount;
7454
56
        }
7455
2.44k
        spvArgs.push_back(arg);
7456
2.44k
    }
7457
7458
    // 3. Make the call.
7459
2.27k
    spv::Id result = builder.createFunctionCall(function, spvArgs);
7460
2.27k
    builder.setPrecision(result, TranslatePrecisionDecoration(node->getType()));
7461
2.27k
    builder.addDecoration(result, TranslateNonUniformDecoration(node->getType().getQualifier()));
7462
7463
    // 4. Copy back out an "out" arguments.
7464
2.27k
    lValueCount = 0;
7465
4.71k
    for (int a = 0; a < (int)glslangArgs.size(); ++a) {
7466
2.44k
        if (originalParam(qualifiers[a], *argTypes[a], function->hasImplicitThis() && a == 0))
7467
45
            ++lValueCount;
7468
2.40k
        else if (writableParam(qualifiers[a])) {
7469
2.34k
            if (qualifiers[a] == glslang::EvqOut || qualifiers[a] == glslang::EvqInOut) {
7470
15
                spv::Id copy = builder.createLoad(spvArgs[a], spv::NoPrecision);
7471
15
                builder.addDecoration(copy, TranslateNonUniformDecoration(argTypes[a]->getQualifier()));
7472
15
                builder.setAccessChain(lValues[lValueCount]);
7473
15
                multiTypeStore(*argTypes[a], copy);
7474
15
            }
7475
2.34k
            ++lValueCount;
7476
2.34k
        }
7477
2.44k
    }
7478
7479
2.27k
    return result;
7480
2.27k
}
7481
7482
// Translate AST operation to SPV operation, already having SPV-based operands/types.
7483
spv::Id TGlslangToSpvTraverser::createBinaryOperation(glslang::TOperator op, OpDecorations& decorations,
7484
                                                      spv::Id typeId, spv::Id left, spv::Id right,
7485
                                                      glslang::TBasicType typeProxy, bool reduceComparison)
7486
19.4k
{
7487
19.4k
    bool isUnsigned = isTypeUnsignedInt(typeProxy);
7488
19.4k
    bool isFloat = isTypeFloat(typeProxy);
7489
19.4k
    bool isBool = typeProxy == glslang::EbtBool;
7490
7491
19.4k
    spv::Op binOp = spv::Op::OpNop;
7492
19.4k
    bool needMatchingVectors = true;  // for non-matrix ops, would a scalar need to smear to match a vector?
7493
19.4k
    bool comparison = false;
7494
7495
19.4k
    switch (op) {
7496
3.06k
    case glslang::EOpAdd:
7497
6.37k
    case glslang::EOpAddAssign:
7498
6.37k
        if (isFloat)
7499
4.06k
            binOp = spv::Op::OpFAdd;
7500
2.31k
        else
7501
2.31k
            binOp = spv::Op::OpIAdd;
7502
6.37k
        break;
7503
989
    case glslang::EOpSub:
7504
1.22k
    case glslang::EOpSubAssign:
7505
1.22k
        if (isFloat)
7506
886
            binOp = spv::Op::OpFSub;
7507
337
        else
7508
337
            binOp = spv::Op::OpISub;
7509
1.22k
        break;
7510
1.56k
    case glslang::EOpMul:
7511
2.02k
    case glslang::EOpMulAssign:
7512
2.02k
        if (isFloat)
7513
1.88k
            binOp = spv::Op::OpFMul;
7514
143
        else
7515
143
            binOp = spv::Op::OpIMul;
7516
2.02k
        break;
7517
1.00k
    case glslang::EOpVectorTimesScalar:
7518
1.20k
    case glslang::EOpVectorTimesScalarAssign:
7519
1.20k
        if (isFloat && (builder.isVector(left) || builder.isVector(right) || builder.isCooperativeVector(left) || builder.isCooperativeVector(right))) {
7520
1.19k
            if (builder.isVector(right) || builder.isCooperativeVector(right))
7521
230
                std::swap(left, right);
7522
1.19k
            assert(builder.isScalar(right));
7523
1.19k
            needMatchingVectors = false;
7524
1.19k
            binOp = spv::Op::OpVectorTimesScalar;
7525
1.19k
        } else if (isFloat) {
7526
0
            binOp = spv::Op::OpFMul;
7527
9
        } else if (builder.isCooperativeVector(left) || builder.isCooperativeVector(right)) {
7528
0
            if (builder.isCooperativeVector(right))
7529
0
                std::swap(left, right);
7530
0
            assert(builder.isScalar(right));
7531
            // Construct a cooperative vector from the scalar
7532
0
            right = builder.createCompositeConstruct(builder.getTypeId(left), { right });
7533
0
            binOp = spv::Op::OpIMul;
7534
9
        } else {
7535
9
            binOp = spv::Op::OpIMul;
7536
9
        }
7537
1.20k
        break;
7538
12
    case glslang::EOpVectorTimesMatrix:
7539
16
    case glslang::EOpVectorTimesMatrixAssign:
7540
16
        binOp = spv::Op::OpVectorTimesMatrix;
7541
16
        break;
7542
188
    case glslang::EOpMatrixTimesVector:
7543
188
        binOp = spv::Op::OpMatrixTimesVector;
7544
188
        break;
7545
4
    case glslang::EOpMatrixTimesScalar:
7546
6
    case glslang::EOpMatrixTimesScalarAssign:
7547
6
        binOp = spv::Op::OpMatrixTimesScalar;
7548
6
        break;
7549
4
    case glslang::EOpMatrixTimesMatrix:
7550
4
    case glslang::EOpMatrixTimesMatrixAssign:
7551
4
        binOp = spv::Op::OpMatrixTimesMatrix;
7552
4
        break;
7553
2
    case glslang::EOpOuterProduct:
7554
2
        binOp = spv::Op::OpOuterProduct;
7555
2
        needMatchingVectors = false;
7556
2
        break;
7557
7558
903
    case glslang::EOpDiv:
7559
914
    case glslang::EOpDivAssign:
7560
914
        if (isFloat)
7561
674
            binOp = spv::Op::OpFDiv;
7562
240
        else if (isUnsigned)
7563
223
            binOp = spv::Op::OpUDiv;
7564
17
        else
7565
17
            binOp = spv::Op::OpSDiv;
7566
914
        break;
7567
224
    case glslang::EOpMod:
7568
453
    case glslang::EOpModAssign:
7569
453
        if (isFloat)
7570
0
            binOp = spv::Op::OpFMod;
7571
453
        else if (isUnsigned)
7572
222
            binOp = spv::Op::OpUMod;
7573
231
        else
7574
231
            binOp = spv::Op::OpSMod;
7575
453
        break;
7576
418
    case glslang::EOpRightShift:
7577
427
    case glslang::EOpRightShiftAssign:
7578
427
        if (isUnsigned)
7579
5
            binOp = spv::Op::OpShiftRightLogical;
7580
422
        else
7581
422
            binOp = spv::Op::OpShiftRightArithmetic;
7582
427
        break;
7583
221
    case glslang::EOpLeftShift:
7584
436
    case glslang::EOpLeftShiftAssign:
7585
436
        binOp = spv::Op::OpShiftLeftLogical;
7586
436
        break;
7587
433
    case glslang::EOpAnd:
7588
663
    case glslang::EOpAndAssign:
7589
663
        binOp = spv::Op::OpBitwiseAnd;
7590
663
        break;
7591
212
    case glslang::EOpLogicalAnd:
7592
212
        needMatchingVectors = false;
7593
212
        binOp = spv::Op::OpLogicalAnd;
7594
212
        break;
7595
424
    case glslang::EOpInclusiveOr:
7596
457
    case glslang::EOpInclusiveOrAssign:
7597
457
        binOp = spv::Op::OpBitwiseOr;
7598
457
        break;
7599
202
    case glslang::EOpLogicalOr:
7600
202
        needMatchingVectors = false;
7601
202
        binOp = spv::Op::OpLogicalOr;
7602
202
        break;
7603
221
    case glslang::EOpExclusiveOr:
7604
230
    case glslang::EOpExclusiveOrAssign:
7605
230
        binOp = spv::Op::OpBitwiseXor;
7606
230
        break;
7607
211
    case glslang::EOpLogicalXor:
7608
211
        needMatchingVectors = false;
7609
211
        binOp = spv::Op::OpLogicalNotEqual;
7610
211
        break;
7611
7612
0
    case glslang::EOpAbsDifference:
7613
0
        binOp = isUnsigned ? spv::Op::OpAbsUSubINTEL : spv::Op::OpAbsISubINTEL;
7614
0
        break;
7615
7616
0
    case glslang::EOpAddSaturate:
7617
0
        binOp = isUnsigned ? spv::Op::OpUAddSatINTEL : spv::Op::OpIAddSatINTEL;
7618
0
        break;
7619
7620
0
    case glslang::EOpSubSaturate:
7621
0
        binOp = isUnsigned ? spv::Op::OpUSubSatINTEL : spv::Op::OpISubSatINTEL;
7622
0
        break;
7623
7624
0
    case glslang::EOpAverage:
7625
0
        binOp = isUnsigned ? spv::Op::OpUAverageINTEL : spv::Op::OpIAverageINTEL;
7626
0
        break;
7627
7628
0
    case glslang::EOpAverageRounded:
7629
0
        binOp = isUnsigned ? spv::Op::OpUAverageRoundedINTEL : spv::Op::OpIAverageRoundedINTEL;
7630
0
        break;
7631
7632
0
    case glslang::EOpMul32x16:
7633
0
        binOp = isUnsigned ? spv::Op::OpUMul32x16INTEL : spv::Op::OpIMul32x16INTEL;
7634
0
        break;
7635
7636
0
    case glslang::EOpExpectEXT:
7637
0
        binOp = spv::Op::OpExpectKHR;
7638
0
        break;
7639
7640
1.17k
    case glslang::EOpLessThan:
7641
2.42k
    case glslang::EOpGreaterThan:
7642
2.97k
    case glslang::EOpLessThanEqual:
7643
3.00k
    case glslang::EOpGreaterThanEqual:
7644
3.71k
    case glslang::EOpEqual:
7645
4.16k
    case glslang::EOpNotEqual:
7646
4.18k
    case glslang::EOpVectorEqual:
7647
4.19k
    case glslang::EOpVectorNotEqual:
7648
4.19k
        comparison = true;
7649
4.19k
        break;
7650
0
    default:
7651
0
        break;
7652
19.4k
    }
7653
7654
    // handle mapped binary operations (should be non-comparison)
7655
19.4k
    if (binOp != spv::Op::OpNop) {
7656
15.2k
        assert(comparison == false);
7657
15.2k
        if (builder.isMatrix(left) || builder.isMatrix(right) ||
7658
14.7k
            builder.isCooperativeMatrix(left) || builder.isCooperativeMatrix(right))
7659
457
            return createBinaryMatrixOperation(binOp, decorations, typeId, left, right);
7660
7661
        // No matrix involved; make both operands be the same number of components, if needed
7662
14.7k
        if (needMatchingVectors)
7663
12.9k
            builder.promoteScalar(decorations.precision, left, right);
7664
7665
14.7k
        spv::Id result = builder.createBinOp(binOp, typeId, left, right);
7666
14.7k
        decorations.addNoContraction(builder, result);
7667
14.7k
        decorations.addNonUniform(builder, result);
7668
14.7k
        return builder.setPrecision(result, decorations.precision);
7669
15.2k
    }
7670
7671
4.19k
    if (! comparison)
7672
0
        return 0;
7673
7674
    // Handle comparison instructions
7675
7676
4.19k
    if (reduceComparison && (op == glslang::EOpEqual || op == glslang::EOpNotEqual)
7677
1.16k
                         && (builder.isVector(left) || builder.isMatrix(left) || builder.isAggregate(left))) {
7678
942
        spv::Id result = builder.createCompositeCompare(decorations.precision, left, right, op == glslang::EOpEqual);
7679
942
        decorations.addNonUniform(builder, result);
7680
942
        return result;
7681
942
    }
7682
7683
3.25k
    switch (op) {
7684
1.17k
    case glslang::EOpLessThan:
7685
1.17k
        if (isFloat)
7686
368
            binOp = spv::Op::OpFOrdLessThan;
7687
803
        else if (isUnsigned)
7688
21
            binOp = spv::Op::OpULessThan;
7689
782
        else
7690
782
            binOp = spv::Op::OpSLessThan;
7691
1.17k
        break;
7692
1.25k
    case glslang::EOpGreaterThan:
7693
1.25k
        if (isFloat)
7694
573
            binOp = spv::Op::OpFOrdGreaterThan;
7695
677
        else if (isUnsigned)
7696
83
            binOp = spv::Op::OpUGreaterThan;
7697
594
        else
7698
594
            binOp = spv::Op::OpSGreaterThan;
7699
1.25k
        break;
7700
555
    case glslang::EOpLessThanEqual:
7701
555
        if (isFloat)
7702
0
            binOp = spv::Op::OpFOrdLessThanEqual;
7703
555
        else if (isUnsigned)
7704
8
            binOp = spv::Op::OpULessThanEqual;
7705
547
        else
7706
547
            binOp = spv::Op::OpSLessThanEqual;
7707
555
        break;
7708
27
    case glslang::EOpGreaterThanEqual:
7709
27
        if (isFloat)
7710
0
            binOp = spv::Op::OpFOrdGreaterThanEqual;
7711
27
        else if (isUnsigned)
7712
18
            binOp = spv::Op::OpUGreaterThanEqual;
7713
9
        else
7714
9
            binOp = spv::Op::OpSGreaterThanEqual;
7715
27
        break;
7716
208
    case glslang::EOpEqual:
7717
226
    case glslang::EOpVectorEqual:
7718
226
        if (isFloat)
7719
155
            binOp = spv::Op::OpFOrdEqual;
7720
71
        else if (isBool)
7721
0
            binOp = spv::Op::OpLogicalEqual;
7722
71
        else
7723
71
            binOp = spv::Op::OpIEqual;
7724
226
        break;
7725
14
    case glslang::EOpNotEqual:
7726
24
    case glslang::EOpVectorNotEqual:
7727
24
        if (isFloat)
7728
2
            binOp = spv::Op::OpFUnordNotEqual;
7729
22
        else if (isBool)
7730
0
            binOp = spv::Op::OpLogicalNotEqual;
7731
22
        else
7732
22
            binOp = spv::Op::OpINotEqual;
7733
24
        break;
7734
0
    default:
7735
0
        break;
7736
3.25k
    }
7737
7738
3.25k
    if (binOp != spv::Op::OpNop) {
7739
3.25k
        spv::Id result = builder.createBinOp(binOp, typeId, left, right);
7740
3.25k
        decorations.addNoContraction(builder, result);
7741
3.25k
        decorations.addNonUniform(builder, result);
7742
3.25k
        return builder.setPrecision(result, decorations.precision);
7743
3.25k
    }
7744
7745
0
    return 0;
7746
3.25k
}
7747
7748
//
7749
// Translate AST matrix operation to SPV operation, already having SPV-based operands/types.
7750
// These can be any of:
7751
//
7752
//   matrix * scalar
7753
//   scalar * matrix
7754
//   matrix * matrix     linear algebraic
7755
//   matrix * vector
7756
//   vector * matrix
7757
//   matrix * matrix     componentwise
7758
//   matrix op matrix    op in {+, -, /}
7759
//   matrix op scalar    op in {+, -, /}
7760
//   scalar op matrix    op in {+, -, /}
7761
//
7762
spv::Id TGlslangToSpvTraverser::createBinaryMatrixOperation(spv::Op op, OpDecorations& decorations, spv::Id typeId,
7763
                                                            spv::Id left, spv::Id right)
7764
457
{
7765
457
    bool firstClass = true;
7766
7767
    // First, handle first-class matrix operations (* and matrix/scalar)
7768
457
    switch (op) {
7769
6
    case spv::Op::OpFDiv:
7770
6
        if (builder.isMatrix(left) && builder.isScalar(right)) {
7771
            // turn matrix / scalar into a multiply...
7772
2
            spv::Id resultType = builder.getTypeId(right);
7773
2
            right = builder.createBinOp(spv::Op::OpFDiv, resultType, builder.makeFpConstant(resultType, 1.0), right);
7774
2
            op = spv::Op::OpMatrixTimesScalar;
7775
2
        } else
7776
4
            firstClass = false;
7777
6
        break;
7778
6
    case spv::Op::OpMatrixTimesScalar:
7779
6
        if (builder.isMatrix(right) || builder.isCooperativeMatrix(right))
7780
2
            std::swap(left, right);
7781
6
        assert(builder.isScalar(right));
7782
6
        break;
7783
16
    case spv::Op::OpVectorTimesMatrix:
7784
16
        assert(builder.isVector(left));
7785
16
        assert(builder.isMatrix(right));
7786
16
        break;
7787
188
    case spv::Op::OpMatrixTimesVector:
7788
188
        assert(builder.isMatrix(left));
7789
188
        assert(builder.isVector(right));
7790
188
        break;
7791
4
    case spv::Op::OpMatrixTimesMatrix:
7792
4
        assert(builder.isMatrix(left));
7793
4
        assert(builder.isMatrix(right));
7794
4
        break;
7795
237
    default:
7796
237
        firstClass = false;
7797
237
        break;
7798
457
    }
7799
7800
457
    if (builder.isCooperativeMatrix(left) || builder.isCooperativeMatrix(right))
7801
0
        firstClass = true;
7802
7803
457
    if (firstClass) {
7804
216
        spv::Id result = builder.createBinOp(op, typeId, left, right);
7805
216
        decorations.addNoContraction(builder, result);
7806
216
        decorations.addNonUniform(builder, result);
7807
216
        return builder.setPrecision(result, decorations.precision);
7808
216
    }
7809
7810
    // Handle component-wise +, -, *, %, and / for all combinations of type.
7811
    // The result type of all of them is the same type as the (a) matrix operand.
7812
    // The algorithm is to:
7813
    //   - break the matrix(es) into vectors
7814
    //   - smear any scalar to a vector
7815
    //   - do vector operations
7816
    //   - make a matrix out the vector results
7817
241
    switch (op) {
7818
20
    case spv::Op::OpFAdd:
7819
231
    case spv::Op::OpFSub:
7820
235
    case spv::Op::OpFDiv:
7821
235
    case spv::Op::OpFMod:
7822
241
    case spv::Op::OpFMul:
7823
241
    {
7824
        // one time set up...
7825
241
        bool  leftMat = builder.isMatrix(left);
7826
241
        bool rightMat = builder.isMatrix(right);
7827
241
        unsigned int numCols = leftMat ? builder.getNumColumns(left) : builder.getNumColumns(right);
7828
241
        int numRows = leftMat ? builder.getNumRows(left) : builder.getNumRows(right);
7829
241
        spv::Id scalarType = builder.getScalarTypeId(typeId);
7830
241
        spv::Id vecType = builder.makeVectorType(scalarType, numRows);
7831
241
        std::vector<spv::Id> results;
7832
241
        spv::Id smearVec = spv::NoResult;
7833
241
        if (builder.isScalar(left))
7834
2
            smearVec = builder.smearScalar(decorations.precision, left, vecType);
7835
239
        else if (builder.isScalar(right))
7836
213
            smearVec = builder.smearScalar(decorations.precision, right, vecType);
7837
7838
        // do each vector op
7839
763
        for (unsigned int c = 0; c < numCols; ++c) {
7840
522
            std::vector<unsigned int> indexes;
7841
522
            indexes.push_back(c);
7842
522
            spv::Id  leftVec =  leftMat ? builder.createCompositeExtract( left, vecType, indexes) : smearVec;
7843
522
            spv::Id rightVec = rightMat ? builder.createCompositeExtract(right, vecType, indexes) : smearVec;
7844
522
            spv::Id result = builder.createBinOp(op, vecType, leftVec, rightVec);
7845
522
            decorations.addNoContraction(builder, result);
7846
522
            decorations.addNonUniform(builder, result);
7847
522
            results.push_back(builder.setPrecision(result, decorations.precision));
7848
522
        }
7849
7850
        // put the pieces together
7851
241
        spv::Id result = builder.setPrecision(builder.createCompositeConstruct(typeId, results), decorations.precision);
7852
241
        decorations.addNonUniform(builder, result);
7853
241
        return result;
7854
235
    }
7855
0
    default:
7856
0
        assert(0);
7857
0
        return spv::NoResult;
7858
241
    }
7859
241
}
7860
7861
spv::Id TGlslangToSpvTraverser::createUnaryOperation(glslang::TOperator op, OpDecorations& decorations, spv::Id typeId,
7862
    spv::Id operand, glslang::TBasicType typeProxy, const spv::Builder::AccessChain::CoherentFlags &lvalueCoherentFlags,
7863
    const glslang::TType &opType)
7864
4.94k
{
7865
4.94k
    spv::Op unaryOp = spv::Op::OpNop;
7866
4.94k
    int extBuiltins = -1;
7867
4.94k
    int libCall = -1;
7868
4.94k
    bool isUnsigned = isTypeUnsignedInt(typeProxy);
7869
4.94k
    bool isFloat = isTypeFloat(typeProxy);
7870
7871
4.94k
    switch (op) {
7872
573
    case glslang::EOpNegative:
7873
573
        if (isFloat) {
7874
186
            unaryOp = spv::Op::OpFNegate;
7875
186
            if (builder.isMatrixType(typeId))
7876
2
                return createUnaryMatrixOperation(unaryOp, decorations, typeId, operand, typeProxy);
7877
186
        } else
7878
387
            unaryOp = spv::Op::OpSNegate;
7879
571
        break;
7880
7881
571
    case glslang::EOpLogicalNot:
7882
211
    case glslang::EOpVectorLogicalNot:
7883
211
        unaryOp = spv::Op::OpLogicalNot;
7884
211
        break;
7885
832
    case glslang::EOpBitwiseNot:
7886
832
        unaryOp = spv::Op::OpNot;
7887
832
        break;
7888
7889
2
    case glslang::EOpDeterminant:
7890
2
        libCall = spv::GLSLstd450Determinant;
7891
2
        break;
7892
6
    case glslang::EOpMatrixInverse:
7893
6
        libCall = spv::GLSLstd450MatrixInverse;
7894
6
        break;
7895
128
    case glslang::EOpTranspose:
7896
128
        unaryOp = spv::Op::OpTranspose;
7897
128
        break;
7898
7899
0
    case glslang::EOpRadians:
7900
0
        libCall = spv::GLSLstd450Radians;
7901
0
        break;
7902
0
    case glslang::EOpDegrees:
7903
0
        libCall = spv::GLSLstd450Degrees;
7904
0
        break;
7905
3
    case glslang::EOpSin:
7906
3
        libCall = spv::GLSLstd450Sin;
7907
3
        break;
7908
2
    case glslang::EOpCos:
7909
2
        libCall = spv::GLSLstd450Cos;
7910
2
        break;
7911
1
    case glslang::EOpTan:
7912
1
        libCall = spv::GLSLstd450Tan;
7913
1
        break;
7914
0
    case glslang::EOpAcos:
7915
0
        libCall = spv::GLSLstd450Acos;
7916
0
        break;
7917
0
    case glslang::EOpAsin:
7918
0
        libCall = spv::GLSLstd450Asin;
7919
0
        break;
7920
0
    case glslang::EOpAtan:
7921
0
        libCall = spv::GLSLstd450Atan;
7922
0
        break;
7923
7924
1
    case glslang::EOpAcosh:
7925
1
        libCall = spv::GLSLstd450Acosh;
7926
1
        break;
7927
1
    case glslang::EOpAsinh:
7928
1
        libCall = spv::GLSLstd450Asinh;
7929
1
        break;
7930
1
    case glslang::EOpAtanh:
7931
1
        libCall = spv::GLSLstd450Atanh;
7932
1
        break;
7933
1
    case glslang::EOpTanh:
7934
1
        libCall = spv::GLSLstd450Tanh;
7935
1
        break;
7936
1
    case glslang::EOpCosh:
7937
1
        libCall = spv::GLSLstd450Cosh;
7938
1
        break;
7939
1
    case glslang::EOpSinh:
7940
1
        libCall = spv::GLSLstd450Sinh;
7941
1
        break;
7942
7943
184
    case glslang::EOpLength:
7944
184
        libCall = spv::GLSLstd450Length;
7945
184
        break;
7946
736
    case glslang::EOpNormalize:
7947
736
        libCall = spv::GLSLstd450Normalize;
7948
736
        break;
7949
7950
0
    case glslang::EOpExp:
7951
0
        libCall = spv::GLSLstd450Exp;
7952
0
        break;
7953
0
    case glslang::EOpLog:
7954
0
        libCall = spv::GLSLstd450Log;
7955
0
        break;
7956
0
    case glslang::EOpExp2:
7957
0
        libCall = spv::GLSLstd450Exp2;
7958
0
        break;
7959
0
    case glslang::EOpLog2:
7960
0
        libCall = spv::GLSLstd450Log2;
7961
0
        break;
7962
0
    case glslang::EOpSqrt:
7963
0
        libCall = spv::GLSLstd450Sqrt;
7964
0
        break;
7965
0
    case glslang::EOpInverseSqrt:
7966
0
        libCall = spv::GLSLstd450InverseSqrt;
7967
0
        break;
7968
7969
0
    case glslang::EOpFloor:
7970
0
        libCall = spv::GLSLstd450Floor;
7971
0
        break;
7972
0
    case glslang::EOpTrunc:
7973
0
        libCall = spv::GLSLstd450Trunc;
7974
0
        break;
7975
0
    case glslang::EOpRound:
7976
0
        libCall = spv::GLSLstd450Round;
7977
0
        break;
7978
0
    case glslang::EOpRoundEven:
7979
0
        libCall = spv::GLSLstd450RoundEven;
7980
0
        break;
7981
0
    case glslang::EOpCeil:
7982
0
        libCall = spv::GLSLstd450Ceil;
7983
0
        break;
7984
0
    case glslang::EOpFract:
7985
0
        libCall = spv::GLSLstd450Fract;
7986
0
        break;
7987
7988
0
    case glslang::EOpIsNan:
7989
0
        unaryOp = spv::Op::OpIsNan;
7990
0
        break;
7991
0
    case glslang::EOpIsInf:
7992
0
        unaryOp = spv::Op::OpIsInf;
7993
0
        break;
7994
0
    case glslang::EOpIsFinite:
7995
0
        unaryOp = spv::Op::OpIsFinite;
7996
0
        break;
7997
7998
0
    case glslang::EOpFloatBitsToInt:
7999
0
    case glslang::EOpFloatBitsToUint:
8000
0
    case glslang::EOpIntBitsToFloat:
8001
0
    case glslang::EOpUintBitsToFloat:
8002
0
    case glslang::EOpDoubleBitsToInt64:
8003
0
    case glslang::EOpDoubleBitsToUint64:
8004
0
    case glslang::EOpInt64BitsToDouble:
8005
0
    case glslang::EOpUint64BitsToDouble:
8006
9
    case glslang::EOpFloat16BitsToInt16:
8007
18
    case glslang::EOpFloat16BitsToUint16:
8008
27
    case glslang::EOpInt16BitsToFloat16:
8009
36
    case glslang::EOpUint16BitsToFloat16:
8010
36
        unaryOp = spv::Op::OpBitcast;
8011
36
        break;
8012
8013
0
    case glslang::EOpPackSnorm2x16:
8014
0
        libCall = spv::GLSLstd450PackSnorm2x16;
8015
0
        break;
8016
0
    case glslang::EOpUnpackSnorm2x16:
8017
0
        libCall = spv::GLSLstd450UnpackSnorm2x16;
8018
0
        break;
8019
0
    case glslang::EOpPackUnorm2x16:
8020
0
        libCall = spv::GLSLstd450PackUnorm2x16;
8021
0
        break;
8022
0
    case glslang::EOpUnpackUnorm2x16:
8023
0
        libCall = spv::GLSLstd450UnpackUnorm2x16;
8024
0
        break;
8025
0
    case glslang::EOpPackHalf2x16:
8026
0
        libCall = spv::GLSLstd450PackHalf2x16;
8027
0
        break;
8028
0
    case glslang::EOpUnpackHalf2x16:
8029
0
        libCall = spv::GLSLstd450UnpackHalf2x16;
8030
0
        break;
8031
0
    case glslang::EOpPackSnorm4x8:
8032
0
        libCall = spv::GLSLstd450PackSnorm4x8;
8033
0
        break;
8034
0
    case glslang::EOpUnpackSnorm4x8:
8035
0
        libCall = spv::GLSLstd450UnpackSnorm4x8;
8036
0
        break;
8037
0
    case glslang::EOpPackUnorm4x8:
8038
0
        libCall = spv::GLSLstd450PackUnorm4x8;
8039
0
        break;
8040
0
    case glslang::EOpUnpackUnorm4x8:
8041
0
        libCall = spv::GLSLstd450UnpackUnorm4x8;
8042
0
        break;
8043
0
    case glslang::EOpPackDouble2x32:
8044
0
        libCall = spv::GLSLstd450PackDouble2x32;
8045
0
        break;
8046
0
    case glslang::EOpUnpackDouble2x32:
8047
0
        libCall = spv::GLSLstd450UnpackDouble2x32;
8048
0
        break;
8049
8050
0
    case glslang::EOpPackInt2x32:
8051
0
    case glslang::EOpUnpackInt2x32:
8052
0
    case glslang::EOpPackUint2x32:
8053
0
    case glslang::EOpUnpackUint2x32:
8054
0
    case glslang::EOpPack16:
8055
0
    case glslang::EOpPack32:
8056
0
    case glslang::EOpPack64:
8057
0
    case glslang::EOpUnpack32:
8058
0
    case glslang::EOpUnpack16:
8059
0
    case glslang::EOpUnpack8:
8060
9
    case glslang::EOpPackInt2x16:
8061
18
    case glslang::EOpUnpackInt2x16:
8062
27
    case glslang::EOpPackUint2x16:
8063
36
    case glslang::EOpUnpackUint2x16:
8064
45
    case glslang::EOpPackInt4x16:
8065
54
    case glslang::EOpUnpackInt4x16:
8066
63
    case glslang::EOpPackUint4x16:
8067
72
    case glslang::EOpUnpackUint4x16:
8068
72
    case glslang::EOpPackFloat2x16:
8069
72
    case glslang::EOpUnpackFloat2x16:
8070
72
        unaryOp = spv::Op::OpBitcast;
8071
72
        break;
8072
8073
0
    case glslang::EOpDPdx:
8074
0
        unaryOp = spv::Op::OpDPdx;
8075
0
        break;
8076
0
    case glslang::EOpDPdy:
8077
0
        unaryOp = spv::Op::OpDPdy;
8078
0
        break;
8079
0
    case glslang::EOpFwidth:
8080
0
        unaryOp = spv::Op::OpFwidth;
8081
0
        break;
8082
8083
0
    case glslang::EOpAny:
8084
0
        unaryOp = spv::Op::OpAny;
8085
0
        break;
8086
0
    case glslang::EOpAll:
8087
0
        unaryOp = spv::Op::OpAll;
8088
0
        break;
8089
8090
25
    case glslang::EOpAbs:
8091
25
        if (isFloat)
8092
16
            libCall = spv::GLSLstd450FAbs;
8093
9
        else
8094
9
            libCall = spv::GLSLstd450SAbs;
8095
25
        break;
8096
9
    case glslang::EOpSign:
8097
9
        if (isFloat)
8098
0
            libCall = spv::GLSLstd450FSign;
8099
9
        else
8100
9
            libCall = spv::GLSLstd450SSign;
8101
9
        break;
8102
8103
0
    case glslang::EOpDPdxFine:
8104
0
        unaryOp = spv::Op::OpDPdxFine;
8105
0
        break;
8106
0
    case glslang::EOpDPdyFine:
8107
0
        unaryOp = spv::Op::OpDPdyFine;
8108
0
        break;
8109
0
    case glslang::EOpFwidthFine:
8110
0
        unaryOp = spv::Op::OpFwidthFine;
8111
0
        break;
8112
0
    case glslang::EOpDPdxCoarse:
8113
0
        unaryOp = spv::Op::OpDPdxCoarse;
8114
0
        break;
8115
0
    case glslang::EOpDPdyCoarse:
8116
0
        unaryOp = spv::Op::OpDPdyCoarse;
8117
0
        break;
8118
0
    case glslang::EOpFwidthCoarse:
8119
0
        unaryOp = spv::Op::OpFwidthCoarse;
8120
0
        break;
8121
31
    case glslang::EOpRayQueryProceed:
8122
31
        unaryOp = spv::Op::OpRayQueryProceedKHR;
8123
31
        break;
8124
31
    case glslang::EOpRayQueryGetRayTMin:
8125
31
        unaryOp = spv::Op::OpRayQueryGetRayTMinKHR;
8126
31
        break;
8127
31
    case glslang::EOpRayQueryGetRayFlags:
8128
31
        unaryOp = spv::Op::OpRayQueryGetRayFlagsKHR;
8129
31
        break;
8130
31
    case glslang::EOpRayQueryGetWorldRayOrigin:
8131
31
        unaryOp = spv::Op::OpRayQueryGetWorldRayOriginKHR;
8132
31
        break;
8133
31
    case glslang::EOpRayQueryGetWorldRayDirection:
8134
31
        unaryOp = spv::Op::OpRayQueryGetWorldRayDirectionKHR;
8135
31
        break;
8136
31
    case glslang::EOpRayQueryGetIntersectionCandidateAABBOpaque:
8137
31
        unaryOp = spv::Op::OpRayQueryGetIntersectionCandidateAABBOpaqueKHR;
8138
31
        break;
8139
0
    case glslang::EOpInterpolateAtCentroid:
8140
0
        if (typeProxy == glslang::EbtFloat16)
8141
0
            builder.addExtension(spv::E_SPV_AMD_gpu_shader_half_float);
8142
0
        libCall = spv::GLSLstd450InterpolateAtCentroid;
8143
0
        break;
8144
0
    case glslang::EOpAtomicCounterIncrement:
8145
0
    case glslang::EOpAtomicCounterDecrement:
8146
0
    case glslang::EOpAtomicCounter:
8147
0
    {
8148
        // Handle all of the atomics in one place, in createAtomicOperation()
8149
0
        std::vector<spv::Id> operands;
8150
0
        operands.push_back(operand);
8151
0
        return createAtomicOperation(op, decorations.precision, typeId, operands, typeProxy, lvalueCoherentFlags, opType);
8152
0
    }
8153
8154
0
    case glslang::EOpBitFieldReverse:
8155
0
        unaryOp = spv::Op::OpBitReverse;
8156
0
        break;
8157
0
    case glslang::EOpBitCount:
8158
0
        unaryOp = spv::Op::OpBitCount;
8159
0
        break;
8160
0
    case glslang::EOpFindLSB:
8161
0
        libCall = spv::GLSLstd450FindILsb;
8162
0
        break;
8163
0
    case glslang::EOpFindMSB:
8164
0
        if (isUnsigned)
8165
0
            libCall = spv::GLSLstd450FindUMsb;
8166
0
        else
8167
0
            libCall = spv::GLSLstd450FindSMsb;
8168
0
        break;
8169
8170
0
    case glslang::EOpCountLeadingZeros:
8171
0
        builder.addCapability(spv::Capability::IntegerFunctions2INTEL);
8172
0
        builder.addExtension("SPV_INTEL_shader_integer_functions2");
8173
0
        unaryOp = spv::Op::OpUCountLeadingZerosINTEL;
8174
0
        break;
8175
8176
0
    case glslang::EOpCountTrailingZeros:
8177
0
        builder.addCapability(spv::Capability::IntegerFunctions2INTEL);
8178
0
        builder.addExtension("SPV_INTEL_shader_integer_functions2");
8179
0
        unaryOp = spv::Op::OpUCountTrailingZerosINTEL;
8180
0
        break;
8181
8182
0
    case glslang::EOpBallot:
8183
0
    case glslang::EOpReadFirstInvocation:
8184
0
    case glslang::EOpAnyInvocation:
8185
0
    case glslang::EOpAllInvocations:
8186
0
    case glslang::EOpAllInvocationsEqual:
8187
0
    case glslang::EOpMinInvocations:
8188
0
    case glslang::EOpMaxInvocations:
8189
0
    case glslang::EOpAddInvocations:
8190
0
    case glslang::EOpMinInvocationsNonUniform:
8191
0
    case glslang::EOpMaxInvocationsNonUniform:
8192
0
    case glslang::EOpAddInvocationsNonUniform:
8193
0
    case glslang::EOpMinInvocationsInclusiveScan:
8194
0
    case glslang::EOpMaxInvocationsInclusiveScan:
8195
0
    case glslang::EOpAddInvocationsInclusiveScan:
8196
0
    case glslang::EOpMinInvocationsInclusiveScanNonUniform:
8197
0
    case glslang::EOpMaxInvocationsInclusiveScanNonUniform:
8198
0
    case glslang::EOpAddInvocationsInclusiveScanNonUniform:
8199
0
    case glslang::EOpMinInvocationsExclusiveScan:
8200
0
    case glslang::EOpMaxInvocationsExclusiveScan:
8201
0
    case glslang::EOpAddInvocationsExclusiveScan:
8202
0
    case glslang::EOpMinInvocationsExclusiveScanNonUniform:
8203
0
    case glslang::EOpMaxInvocationsExclusiveScanNonUniform:
8204
0
    case glslang::EOpAddInvocationsExclusiveScanNonUniform:
8205
0
    {
8206
0
        std::vector<spv::Id> operands;
8207
0
        operands.push_back(operand);
8208
0
        return createInvocationsOperation(op, typeId, operands, typeProxy);
8209
0
    }
8210
0
    case glslang::EOpSubgroupAll:
8211
0
    case glslang::EOpSubgroupAny:
8212
0
    case glslang::EOpSubgroupAllEqual:
8213
0
    case glslang::EOpSubgroupBroadcastFirst:
8214
0
    case glslang::EOpSubgroupBallot:
8215
0
    case glslang::EOpSubgroupInverseBallot:
8216
0
    case glslang::EOpSubgroupBallotBitCount:
8217
0
    case glslang::EOpSubgroupBallotInclusiveBitCount:
8218
0
    case glslang::EOpSubgroupBallotExclusiveBitCount:
8219
0
    case glslang::EOpSubgroupBallotFindLSB:
8220
0
    case glslang::EOpSubgroupBallotFindMSB:
8221
0
    case glslang::EOpSubgroupAdd:
8222
0
    case glslang::EOpSubgroupMul:
8223
0
    case glslang::EOpSubgroupMin:
8224
0
    case glslang::EOpSubgroupMax:
8225
0
    case glslang::EOpSubgroupAnd:
8226
0
    case glslang::EOpSubgroupOr:
8227
0
    case glslang::EOpSubgroupXor:
8228
0
    case glslang::EOpSubgroupInclusiveAdd:
8229
0
    case glslang::EOpSubgroupInclusiveMul:
8230
0
    case glslang::EOpSubgroupInclusiveMin:
8231
0
    case glslang::EOpSubgroupInclusiveMax:
8232
0
    case glslang::EOpSubgroupInclusiveAnd:
8233
0
    case glslang::EOpSubgroupInclusiveOr:
8234
0
    case glslang::EOpSubgroupInclusiveXor:
8235
0
    case glslang::EOpSubgroupExclusiveAdd:
8236
0
    case glslang::EOpSubgroupExclusiveMul:
8237
0
    case glslang::EOpSubgroupExclusiveMin:
8238
0
    case glslang::EOpSubgroupExclusiveMax:
8239
0
    case glslang::EOpSubgroupExclusiveAnd:
8240
0
    case glslang::EOpSubgroupExclusiveOr:
8241
0
    case glslang::EOpSubgroupExclusiveXor:
8242
0
    case glslang::EOpSubgroupQuadSwapHorizontal:
8243
0
    case glslang::EOpSubgroupQuadSwapVertical:
8244
0
    case glslang::EOpSubgroupQuadSwapDiagonal:
8245
0
    case glslang::EOpSubgroupQuadAll:
8246
0
    case glslang::EOpSubgroupQuadAny: {
8247
0
        std::vector<spv::Id> operands;
8248
0
        operands.push_back(operand);
8249
0
        return createSubgroupOperation(op, typeId, operands, typeProxy);
8250
0
    }
8251
0
    case glslang::EOpMbcnt:
8252
0
        extBuiltins = getExtBuiltins(spv::E_SPV_AMD_shader_ballot);
8253
0
        libCall = spv::MbcntAMD;
8254
0
        break;
8255
8256
0
    case glslang::EOpCubeFaceIndex:
8257
0
        extBuiltins = getExtBuiltins(spv::E_SPV_AMD_gcn_shader);
8258
0
        libCall = spv::CubeFaceIndexAMD;
8259
0
        break;
8260
8261
0
    case glslang::EOpCubeFaceCoord:
8262
0
        extBuiltins = getExtBuiltins(spv::E_SPV_AMD_gcn_shader);
8263
0
        libCall = spv::CubeFaceCoordAMD;
8264
0
        break;
8265
0
    case glslang::EOpSubgroupPartition:
8266
0
        unaryOp = spv::Op::OpGroupNonUniformPartitionNV;
8267
0
        break;
8268
2
    case glslang::EOpConstructReference:
8269
2
        unaryOp = spv::Op::OpBitcast;
8270
2
        break;
8271
8272
0
    case glslang::EOpConvUint64ToAccStruct:
8273
0
    case glslang::EOpConvUvec2ToAccStruct:
8274
0
        unaryOp = spv::Op::OpConvertUToAccelerationStructureKHR;
8275
0
        break;
8276
8277
0
    case glslang::EOpHitObjectIsEmptyNV:
8278
0
        unaryOp = spv::Op::OpHitObjectIsEmptyNV;
8279
0
        break;
8280
8281
0
    case glslang::EOpHitObjectIsEmptyEXT:
8282
0
        unaryOp = spv::Op::OpHitObjectIsEmptyEXT;
8283
0
        break;
8284
8285
0
    case glslang::EOpHitObjectIsMissNV:
8286
0
        unaryOp = spv::Op::OpHitObjectIsMissNV;
8287
0
        break;
8288
8289
0
    case glslang::EOpHitObjectIsMissEXT:
8290
0
        unaryOp = spv::Op::OpHitObjectIsMissEXT;
8291
0
        break;
8292
8293
0
    case glslang::EOpHitObjectIsHitNV:
8294
0
        unaryOp = spv::Op::OpHitObjectIsHitNV;
8295
0
        break;
8296
8297
0
    case glslang::EOpHitObjectIsHitEXT:
8298
0
        unaryOp = spv::Op::OpHitObjectIsHitEXT;
8299
0
        break;
8300
8301
0
    case glslang::EOpHitObjectGetObjectRayOriginNV:
8302
0
        unaryOp = spv::Op::OpHitObjectGetObjectRayOriginNV;
8303
0
        break;
8304
8305
0
    case glslang::EOpHitObjectGetObjectRayOriginEXT:
8306
0
        unaryOp = spv::Op::OpHitObjectGetObjectRayOriginEXT;
8307
0
        break;
8308
8309
0
    case glslang::EOpHitObjectGetObjectRayDirectionNV:
8310
0
        unaryOp = spv::Op::OpHitObjectGetObjectRayDirectionNV;
8311
0
        break;
8312
8313
0
    case glslang::EOpHitObjectGetObjectRayDirectionEXT:
8314
0
        unaryOp = spv::Op::OpHitObjectGetObjectRayDirectionEXT;
8315
0
        break;
8316
8317
0
    case glslang::EOpHitObjectGetWorldRayOriginNV:
8318
0
        unaryOp = spv::Op::OpHitObjectGetWorldRayOriginNV;
8319
0
        break;
8320
8321
0
    case glslang::EOpHitObjectGetWorldRayOriginEXT:
8322
0
        unaryOp = spv::Op::OpHitObjectGetWorldRayOriginEXT;
8323
0
        break;
8324
8325
0
    case glslang::EOpHitObjectGetWorldRayDirectionNV:
8326
0
        unaryOp = spv::Op::OpHitObjectGetWorldRayDirectionNV;
8327
0
        break;
8328
8329
0
    case glslang::EOpHitObjectGetWorldRayDirectionEXT:
8330
0
        unaryOp = spv::Op::OpHitObjectGetWorldRayDirectionEXT;
8331
0
        break;
8332
8333
0
    case glslang::EOpHitObjectGetObjectToWorldNV:
8334
0
        unaryOp = spv::Op::OpHitObjectGetObjectToWorldNV;
8335
0
        break;
8336
8337
0
    case glslang::EOpHitObjectGetObjectToWorldEXT:
8338
0
        unaryOp = spv::Op::OpHitObjectGetObjectToWorldEXT;
8339
0
        break;
8340
8341
0
    case glslang::EOpHitObjectGetWorldToObjectNV:
8342
0
        unaryOp = spv::Op::OpHitObjectGetWorldToObjectNV;
8343
0
        break;
8344
8345
0
    case glslang::EOpHitObjectGetWorldToObjectEXT:
8346
0
        unaryOp = spv::Op::OpHitObjectGetWorldToObjectEXT;
8347
0
        break;
8348
8349
0
    case glslang::EOpHitObjectGetRayTMinNV:
8350
0
        unaryOp = spv::Op::OpHitObjectGetRayTMinNV;
8351
0
        break;
8352
8353
0
    case glslang::EOpHitObjectGetRayTMinEXT:
8354
0
        unaryOp = spv::Op::OpHitObjectGetRayTMinEXT;
8355
0
        break;
8356
8357
0
    case glslang::EOpHitObjectGetRayTMaxNV:
8358
0
        unaryOp = spv::Op::OpHitObjectGetRayTMaxNV;
8359
0
        break;
8360
8361
0
    case glslang::EOpHitObjectGetRayTMaxEXT:
8362
0
        unaryOp = spv::Op::OpHitObjectGetRayTMaxEXT;
8363
0
        break;
8364
8365
0
    case glslang::EOpHitObjectGetRayFlagsEXT:
8366
0
        unaryOp = spv::Op::OpHitObjectGetRayFlagsEXT;
8367
0
        break;
8368
8369
0
    case glslang::EOpHitObjectGetPrimitiveIndexNV:
8370
0
        unaryOp = spv::Op::OpHitObjectGetPrimitiveIndexNV;
8371
0
        break;
8372
8373
0
    case glslang::EOpHitObjectGetPrimitiveIndexEXT:
8374
0
        unaryOp = spv::Op::OpHitObjectGetPrimitiveIndexEXT;
8375
0
        break;
8376
8377
0
    case glslang::EOpHitObjectGetInstanceIdNV:
8378
0
        unaryOp = spv::Op::OpHitObjectGetInstanceIdNV;
8379
0
        break;
8380
8381
0
    case glslang::EOpHitObjectGetInstanceIdEXT:
8382
0
        unaryOp = spv::Op::OpHitObjectGetInstanceIdEXT;
8383
0
        break;
8384
8385
0
    case glslang::EOpHitObjectGetInstanceCustomIndexNV:
8386
0
        unaryOp = spv::Op::OpHitObjectGetInstanceCustomIndexNV;
8387
0
        break;
8388
8389
0
    case glslang::EOpHitObjectGetInstanceCustomIndexEXT:
8390
0
        unaryOp = spv::Op::OpHitObjectGetInstanceCustomIndexEXT;
8391
0
        break;
8392
8393
0
    case glslang::EOpHitObjectGetGeometryIndexNV:
8394
0
        unaryOp = spv::Op::OpHitObjectGetGeometryIndexNV;
8395
0
        break;
8396
8397
0
    case glslang::EOpHitObjectGetGeometryIndexEXT:
8398
0
        unaryOp = spv::Op::OpHitObjectGetGeometryIndexEXT;
8399
0
        break;
8400
8401
0
    case glslang::EOpHitObjectGetHitKindNV:
8402
0
        unaryOp = spv::Op::OpHitObjectGetHitKindNV;
8403
0
        break;
8404
8405
0
    case glslang::EOpHitObjectGetHitKindEXT:
8406
0
        unaryOp = spv::Op::OpHitObjectGetHitKindEXT;
8407
0
        break;
8408
8409
0
    case glslang::EOpHitObjectGetCurrentTimeNV:
8410
0
        unaryOp = spv::Op::OpHitObjectGetCurrentTimeNV;
8411
0
        break;
8412
8413
0
    case glslang::EOpHitObjectGetCurrentTimeEXT:
8414
0
        unaryOp = spv::Op::OpHitObjectGetCurrentTimeEXT;
8415
0
        break;
8416
8417
0
    case glslang::EOpHitObjectGetShaderBindingTableRecordIndexNV:
8418
0
        unaryOp = spv::Op::OpHitObjectGetShaderBindingTableRecordIndexNV;
8419
0
        break;
8420
8421
0
    case glslang::EOpHitObjectGetShaderBindingTableRecordIndexEXT:
8422
0
        unaryOp = spv::Op::OpHitObjectGetShaderBindingTableRecordIndexEXT;
8423
0
        break;
8424
8425
0
    case glslang::EOpHitObjectGetShaderRecordBufferHandleNV:
8426
0
        unaryOp = spv::Op::OpHitObjectGetShaderRecordBufferHandleNV;
8427
0
        break;
8428
8429
0
    case glslang::EOpHitObjectGetClusterIdNV:
8430
0
        unaryOp = spv::Op::OpHitObjectGetClusterIdNV;
8431
0
        builder.addExtension(spv::E_SPV_NV_cluster_acceleration_structure);
8432
0
        builder.addCapability(spv::Capability::ShaderInvocationReorderNV);
8433
0
        builder.addCapability(spv::Capability::RayTracingClusterAccelerationStructureNV);
8434
0
        break;
8435
8436
0
    case glslang::EOpHitObjectGetSpherePositionNV:
8437
0
        unaryOp = spv::Op::OpHitObjectGetSpherePositionNV;
8438
0
        builder.addExtension(spv::E_SPV_NV_linear_swept_spheres);
8439
0
        builder.addCapability(spv::Capability::ShaderInvocationReorderNV);
8440
0
        builder.addCapability(spv::Capability::RayTracingSpheresGeometryNV);
8441
0
        break;
8442
8443
0
    case glslang::EOpHitObjectGetSphereRadiusNV:
8444
0
        unaryOp = spv::Op::OpHitObjectGetSphereRadiusNV;
8445
0
        builder.addExtension(spv::E_SPV_NV_linear_swept_spheres);
8446
0
        builder.addCapability(spv::Capability::ShaderInvocationReorderNV);
8447
0
        builder.addCapability(spv::Capability::RayTracingSpheresGeometryNV);
8448
0
        break;
8449
8450
0
    case glslang::EOpHitObjectIsSphereHitNV:
8451
0
        unaryOp = spv::Op::OpHitObjectIsSphereHitNV;
8452
0
        builder.addExtension(spv::E_SPV_NV_linear_swept_spheres);
8453
0
        builder.addCapability(spv::Capability::ShaderInvocationReorderNV);
8454
0
        builder.addCapability(spv::Capability::RayTracingSpheresGeometryNV);
8455
0
        break;
8456
8457
0
    case glslang::EOpHitObjectIsLSSHitNV:
8458
0
        unaryOp = spv::Op::OpHitObjectIsLSSHitNV;
8459
0
        builder.addExtension(spv::E_SPV_NV_linear_swept_spheres);
8460
0
        builder.addCapability(spv::Capability::ShaderInvocationReorderNV);
8461
0
        builder.addCapability(spv::Capability::RayTracingLinearSweptSpheresGeometryNV);
8462
0
        break;
8463
8464
0
    case glslang::EOpHitObjectGetShaderRecordBufferHandleEXT:
8465
0
        unaryOp = spv::Op::OpHitObjectGetShaderRecordBufferHandleEXT;
8466
0
        break;
8467
8468
0
    case glslang::EOpFetchMicroTriangleVertexPositionNV:
8469
0
        unaryOp = spv::Op::OpFetchMicroTriangleVertexPositionNV;
8470
0
        break;
8471
8472
0
    case glslang::EOpFetchMicroTriangleVertexBarycentricNV:
8473
0
        unaryOp = spv::Op::OpFetchMicroTriangleVertexBarycentricNV;
8474
0
        break;
8475
8476
8
    case glslang::EOpCopyObject:
8477
8
        unaryOp = spv::Op::OpCopyObject;
8478
8
        break;
8479
8480
0
    case glslang::EOpDepthAttachmentReadEXT:
8481
0
        builder.addExtension(spv::E_SPV_EXT_shader_tile_image);
8482
0
        builder.addCapability(spv::Capability::TileImageDepthReadAccessEXT);
8483
0
        unaryOp = spv::Op::OpDepthAttachmentReadEXT;
8484
0
        decorations.precision = spv::NoPrecision;
8485
0
        break;
8486
0
    case glslang::EOpStencilAttachmentReadEXT:
8487
0
        builder.addExtension(spv::E_SPV_EXT_shader_tile_image);
8488
0
        builder.addCapability(spv::Capability::TileImageStencilReadAccessEXT);
8489
0
        unaryOp = spv::Op::OpStencilAttachmentReadEXT;
8490
0
        decorations.precision = spv::Decoration::RelaxedPrecision;
8491
0
        break;
8492
8493
1.92k
    default:
8494
1.92k
        return 0;
8495
4.94k
    }
8496
8497
3.02k
    spv::Id id;
8498
3.02k
    if (libCall >= 0) {
8499
974
        std::vector<spv::Id> args;
8500
974
        args.push_back(operand);
8501
974
        id = builder.createBuiltinCall(typeId, extBuiltins >= 0 ? extBuiltins : stdBuiltins, libCall, args);
8502
2.04k
    } else {
8503
2.04k
        id = builder.createUnaryOp(unaryOp, typeId, operand);
8504
2.04k
    }
8505
8506
3.02k
    decorations.addNoContraction(builder, id);
8507
3.02k
    decorations.addNonUniform(builder, id);
8508
3.02k
    return builder.setPrecision(id, decorations.precision);
8509
4.94k
}
8510
8511
// Create a unary operation on a matrix
8512
spv::Id TGlslangToSpvTraverser::createUnaryMatrixOperation(spv::Op op, OpDecorations& decorations, spv::Id typeId,
8513
                                                           spv::Id operand, glslang::TBasicType /* typeProxy */)
8514
6
{
8515
    // Handle unary operations vector by vector.
8516
    // The result type is the same type as the original type.
8517
    // The algorithm is to:
8518
    //   - break the matrix into vectors
8519
    //   - apply the operation to each vector
8520
    //   - make a matrix out the vector results
8521
8522
    // get the types sorted out
8523
6
    int numCols = builder.getNumColumns(operand);
8524
6
    int numRows = builder.getNumRows(operand);
8525
6
    spv::Id srcVecType  = builder.makeVectorType(builder.getScalarTypeId(builder.getTypeId(operand)), numRows);
8526
6
    spv::Id destVecType = builder.makeVectorType(builder.getScalarTypeId(typeId), numRows);
8527
6
    std::vector<spv::Id> results;
8528
8529
    // do each vector op
8530
26
    for (int c = 0; c < numCols; ++c) {
8531
20
        std::vector<unsigned int> indexes;
8532
20
        indexes.push_back(c);
8533
20
        spv::Id srcVec  = builder.createCompositeExtract(operand, srcVecType, indexes);
8534
20
        spv::Id destVec = builder.createUnaryOp(op, destVecType, srcVec);
8535
20
        decorations.addNoContraction(builder, destVec);
8536
20
        decorations.addNonUniform(builder, destVec);
8537
20
        results.push_back(builder.setPrecision(destVec, decorations.precision));
8538
20
    }
8539
8540
    // put the pieces together
8541
6
    spv::Id result = builder.setPrecision(builder.createCompositeConstruct(typeId, results), decorations.precision);
8542
6
    decorations.addNonUniform(builder, result);
8543
6
    return result;
8544
6
}
8545
8546
// For converting integers where both the bitwidth and the signedness could
8547
// change, but only do the width change here. The caller is still responsible
8548
// for the signedness conversion.
8549
// destType is the final type that will be converted to, but this function
8550
// may only be doing part of that conversion.
8551
spv::Id TGlslangToSpvTraverser::createIntWidthConversion(spv::Id operand, int vectorSize, spv::Id destType,
8552
                                                         glslang::TBasicType resultBasicType, glslang::TBasicType operandBasicType)
8553
224
{
8554
    // Get the result type width, based on the type to convert to.
8555
224
    int width = GetNumBits(resultBasicType);
8556
8557
    // Get the conversion operation and result type,
8558
    // based on the target width, but the source type.
8559
224
    spv::Id type = spv::NoType;
8560
224
    spv::Op convOp = spv::Op::OpNop;
8561
224
    if (isTypeSignedInt(operandBasicType)) {
8562
115
        convOp = spv::Op::OpSConvert;
8563
115
        type = builder.makeIntType(width);
8564
115
    } else {
8565
109
        convOp = spv::Op::OpUConvert;
8566
109
        type = builder.makeUintType(width);
8567
109
    }
8568
8569
224
    if (builder.getOpCode(destType) == spv::Op::OpTypeCooperativeVectorNV) {
8570
0
        type = builder.makeCooperativeVectorTypeNV(type, builder.getCooperativeVectorNumComponents(destType));
8571
224
    } else if (vectorSize > 0)
8572
71
        type = builder.makeVectorType(type, vectorSize);
8573
153
    else if (builder.getOpCode(destType) == spv::Op::OpTypeCooperativeMatrixKHR ||
8574
153
             builder.getOpCode(destType) == spv::Op::OpTypeCooperativeMatrixNV) {
8575
8576
0
        type = builder.makeCooperativeMatrixTypeWithSameShape(type, destType);
8577
0
    }
8578
8579
224
    return builder.createUnaryOp(convOp, type, operand);
8580
224
}
8581
8582
spv::Id TGlslangToSpvTraverser::createConversion(glslang::TOperator op, OpDecorations& decorations, spv::Id destType,
8583
                                                 spv::Id operand, glslang::TBasicType resultBasicType, glslang::TBasicType operandBasicType)
8584
8.83k
{
8585
8.83k
    spv::Op convOp = spv::Op::OpNop;
8586
8.83k
    spv::Id zero = 0;
8587
8.83k
    spv::Id one = 0;
8588
8589
8.83k
    int vectorSize = builder.isVectorType(destType) ? builder.getNumTypeComponents(destType) : 0;
8590
8591
8.83k
    if (IsOpNumericConv(op) || op == glslang::EOpConstructSaturated) {
8592
3.23k
        if (isTypeSignedInt(operandBasicType) && isTypeFloat(resultBasicType)) {
8593
1.06k
            convOp = spv::Op::OpConvertSToF;
8594
1.06k
        }
8595
3.23k
        if (isTypeUnsignedInt(operandBasicType) && isTypeFloat(resultBasicType)) {
8596
49
            convOp = spv::Op::OpConvertUToF;
8597
49
        }
8598
3.23k
        if (isTypeFloat(operandBasicType) && isTypeSignedInt(resultBasicType)) {
8599
402
            convOp = spv::Op::OpConvertFToS;
8600
402
        }
8601
3.23k
        if (isTypeFloat(operandBasicType) && isTypeUnsignedInt(resultBasicType)) {
8602
397
            convOp = spv::Op::OpConvertFToU;
8603
397
        }
8604
3.23k
        if (isTypeSignedInt(operandBasicType) && isTypeSignedInt(resultBasicType)) {
8605
315
            convOp = spv::Op::OpSConvert;
8606
315
        }
8607
3.23k
        if (isTypeUnsignedInt(operandBasicType) && isTypeUnsignedInt(resultBasicType)) {
8608
228
            convOp = spv::Op::OpUConvert;
8609
228
        }
8610
3.23k
        if (isTypeFloat(operandBasicType) && isTypeFloat(resultBasicType)) {
8611
42
            convOp = spv::Op::OpFConvert;
8612
42
            if (builder.isMatrixType(destType))
8613
4
                return createUnaryMatrixOperation(convOp, decorations, destType, operand, operandBasicType);
8614
42
        }
8615
3.22k
        if (isTypeInt(operandBasicType) && isTypeInt(resultBasicType) &&
8616
1.10k
            isTypeUnsignedInt(operandBasicType) != isTypeUnsignedInt(resultBasicType)) {
8617
8618
560
            if (GetNumBits(operandBasicType) != GetNumBits(resultBasicType)) {
8619
                // OpSConvert/OpUConvert + OpBitCast
8620
224
                operand = createIntWidthConversion(operand, vectorSize, destType, resultBasicType, operandBasicType);
8621
224
            }
8622
8623
560
            if (builder.isInSpecConstCodeGenMode()) {
8624
200
                uint32_t bits = GetNumBits(resultBasicType);
8625
200
                spv::Id zeroType = builder.makeUintType(bits);
8626
200
                if (bits == 64) {
8627
93
                    zero = builder.makeInt64Constant(zeroType, 0, false);
8628
107
                } else {
8629
107
                    zero = builder.makeIntConstant(zeroType, 0, false);
8630
107
                }
8631
200
                zero = makeSmearedConstant(zero, vectorSize);
8632
                // Use OpIAdd, instead of OpBitcast to do the conversion when
8633
                // generating for OpSpecConstantOp instruction.
8634
200
                return builder.createBinOp(spv::Op::OpIAdd, destType, operand, zero);
8635
200
            }
8636
            // For normal run-time conversion instruction, use OpBitcast.
8637
360
            convOp = spv::Op::OpBitcast;
8638
360
        }
8639
3.02k
        if (resultBasicType == glslang::EbtBool) {
8640
74
            uint32_t bits = GetNumBits(operandBasicType);
8641
74
            if (isTypeInt(operandBasicType)) {
8642
74
                spv::Id zeroType = builder.makeUintType(bits);
8643
74
                if (bits == 64) {
8644
38
                    zero = builder.makeInt64Constant(zeroType, 0, false);
8645
38
                } else {
8646
36
                    zero = builder.makeIntConstant(zeroType, 0, false);
8647
36
                }
8648
74
                zero = makeSmearedConstant(zero, vectorSize);
8649
74
                return builder.createBinOp(spv::Op::OpINotEqual, destType, operand, zero);
8650
74
            } else {
8651
0
                assert(isTypeFloat(operandBasicType));
8652
0
                if (bits == 64) {
8653
0
                    zero = builder.makeDoubleConstant(0.0);
8654
0
                } else if (bits == 32) {
8655
0
                    zero = builder.makeFloatConstant(0.0);
8656
0
                } else {
8657
0
                    assert(bits == 16);
8658
0
                    zero = builder.makeFloat16Constant(0.0);
8659
0
                }
8660
0
                zero = makeSmearedConstant(zero, vectorSize);
8661
0
                return builder.createBinOp(spv::Op::OpFUnordNotEqual, destType, operand, zero);
8662
0
            }
8663
74
        }
8664
2.95k
        if (operandBasicType == glslang::EbtBool) {
8665
98
            uint32_t bits = GetNumBits(resultBasicType);
8666
98
            convOp = spv::Op::OpSelect;
8667
98
            if (isTypeInt(resultBasicType)) {
8668
73
                spv::Id zeroType = isTypeSignedInt(resultBasicType) ? builder.makeIntType(bits) : builder.makeUintType(bits);
8669
73
                if (bits == 64) {
8670
38
                    zero = builder.makeInt64Constant(zeroType, 0, false);
8671
38
                    one = builder.makeInt64Constant(zeroType, 1, false);
8672
38
                } else {
8673
35
                    zero = builder.makeIntConstant(zeroType, 0, false);
8674
35
                    one = builder.makeIntConstant(zeroType, 1, false);
8675
35
                }
8676
73
            } else {
8677
25
                assert(isTypeFloat(resultBasicType));
8678
25
                if (bits == 64) {
8679
0
                    zero = builder.makeDoubleConstant(0.0);
8680
0
                    one = builder.makeDoubleConstant(1.0);
8681
25
                } else if (bits == 32) {
8682
25
                    zero = builder.makeFloatConstant(0.0);
8683
25
                    one = builder.makeFloatConstant(1.0);
8684
25
                } else {
8685
0
                    assert(bits == 16);
8686
0
                    zero = builder.makeFloat16Constant(0.0);
8687
0
                    one = builder.makeFloat16Constant(1.0);
8688
0
                }
8689
25
            }
8690
98
        }
8691
2.95k
    }
8692
8693
8.55k
    if (convOp == spv::Op::OpNop) {
8694
5.60k
        switch (op) {
8695
316
        case glslang::EOpConvUint64ToPtr:
8696
316
            convOp = spv::Op::OpConvertUToPtr;
8697
316
            break;
8698
340
        case glslang::EOpConvPtrToUint64:
8699
340
            convOp = spv::Op::OpConvertPtrToU;
8700
340
            break;
8701
0
        case glslang::EOpConvPtrToUvec2:
8702
0
        case glslang::EOpConvUvec2ToPtr:
8703
0
            convOp = spv::Op::OpBitcast;
8704
0
            break;
8705
8706
4.94k
        default:
8707
4.94k
            break;
8708
5.60k
        }
8709
5.60k
    }
8710
8711
8.55k
    spv::Id result = 0;
8712
8.55k
    if (convOp == spv::Op::OpNop)
8713
4.94k
        return result;
8714
8715
3.60k
    if (convOp == spv::Op::OpSelect) {
8716
98
        zero = makeSmearedConstant(zero, vectorSize);
8717
98
        one  = makeSmearedConstant(one, vectorSize);
8718
98
        result = builder.createTriOp(convOp, destType, operand, one, zero);
8719
98
    } else
8720
3.51k
        result = builder.createUnaryOp(convOp, destType, operand);
8721
8722
3.60k
    result = builder.setPrecision(result, decorations.precision);
8723
3.60k
    decorations.addNonUniform(builder, result);
8724
3.60k
    return result;
8725
8.55k
}
8726
8727
spv::Id TGlslangToSpvTraverser::makeSmearedConstant(spv::Id constant, int vectorSize)
8728
540
{
8729
540
    if (vectorSize == 0)
8730
418
        return constant;
8731
8732
122
    spv::Id vectorTypeId = builder.makeVectorType(builder.getTypeId(constant), vectorSize);
8733
122
    std::vector<spv::Id> components;
8734
386
    for (int c = 0; c < vectorSize; ++c)
8735
264
        components.push_back(constant);
8736
122
    return builder.makeCompositeConstant(vectorTypeId, components);
8737
540
}
8738
8739
// For glslang ops that map to SPV atomic opCodes
8740
spv::Id TGlslangToSpvTraverser::createAtomicOperation(glslang::TOperator op, spv::Decoration /*precision*/,
8741
    spv::Id typeId, std::vector<spv::Id>& operands, glslang::TBasicType typeProxy,
8742
    const spv::Builder::AccessChain::CoherentFlags &lvalueCoherentFlags, const glslang::TType &opType)
8743
2.16k
{
8744
2.16k
    spv::Op opCode = spv::Op::OpNop;
8745
8746
2.16k
    switch (op) {
8747
132
    case glslang::EOpAtomicAdd:
8748
535
    case glslang::EOpImageAtomicAdd:
8749
535
    case glslang::EOpAtomicCounterAdd:
8750
535
        opCode = spv::Op::OpAtomicIAdd;
8751
535
        if (typeProxy == glslang::EbtFloat16 || typeProxy == glslang::EbtFloat || typeProxy == glslang::EbtDouble) {
8752
400
            opCode = spv::Op::OpAtomicFAddEXT;
8753
400
            if (typeProxy == glslang::EbtFloat16 &&
8754
400
                (opType.getVectorSize() == 2 || opType.getVectorSize() == 4)) {
8755
400
                builder.addExtension(spv::E_SPV_NV_shader_atomic_fp16_vector);
8756
400
                builder.addCapability(spv::Capability::AtomicFloat16VectorNV);
8757
400
            } else {
8758
0
                builder.addExtension(spv::E_SPV_EXT_shader_atomic_float_add);
8759
0
                if (typeProxy == glslang::EbtFloat16) {
8760
0
                    builder.addExtension(spv::E_SPV_EXT_shader_atomic_float16_add);
8761
0
                    builder.addCapability(spv::Capability::AtomicFloat16AddEXT);
8762
0
                } else if (typeProxy == glslang::EbtFloat) {
8763
0
                    builder.addCapability(spv::Capability::AtomicFloat32AddEXT);
8764
0
                } else {
8765
0
                    builder.addCapability(spv::Capability::AtomicFloat64AddEXT);
8766
0
                }
8767
0
            }
8768
400
        }
8769
535
        break;
8770
0
    case glslang::EOpAtomicSubtract:
8771
0
    case glslang::EOpAtomicCounterSubtract:
8772
0
        opCode = spv::Op::OpAtomicISub;
8773
0
        break;
8774
52
    case glslang::EOpAtomicMin:
8775
454
    case glslang::EOpImageAtomicMin:
8776
454
    case glslang::EOpAtomicCounterMin:
8777
454
        if (typeProxy == glslang::EbtFloat16 || typeProxy == glslang::EbtFloat || typeProxy == glslang::EbtDouble) {
8778
400
            opCode = spv::Op::OpAtomicFMinEXT;
8779
400
            if (typeProxy == glslang::EbtFloat16 &&
8780
400
                (opType.getVectorSize() == 2 || opType.getVectorSize() == 4)) {
8781
400
                builder.addExtension(spv::E_SPV_NV_shader_atomic_fp16_vector);
8782
400
                builder.addCapability(spv::Capability::AtomicFloat16VectorNV);
8783
400
            } else {
8784
0
                builder.addExtension(spv::E_SPV_EXT_shader_atomic_float_min_max);
8785
0
                if (typeProxy == glslang::EbtFloat16)
8786
0
                    builder.addCapability(spv::Capability::AtomicFloat16MinMaxEXT);
8787
0
                else if (typeProxy == glslang::EbtFloat)
8788
0
                    builder.addCapability(spv::Capability::AtomicFloat32MinMaxEXT);
8789
0
                else
8790
0
                    builder.addCapability(spv::Capability::AtomicFloat64MinMaxEXT);
8791
0
            }
8792
400
        } else if (typeProxy == glslang::EbtUint || typeProxy == glslang::EbtUint64) {
8793
28
            opCode = spv::Op::OpAtomicUMin;
8794
28
        } else {
8795
26
            opCode = spv::Op::OpAtomicSMin;
8796
26
        }
8797
454
        break;
8798
50
    case glslang::EOpAtomicMax:
8799
452
    case glslang::EOpImageAtomicMax:
8800
452
    case glslang::EOpAtomicCounterMax:
8801
452
        if (typeProxy == glslang::EbtFloat16 || typeProxy == glslang::EbtFloat || typeProxy == glslang::EbtDouble) {
8802
400
            opCode = spv::Op::OpAtomicFMaxEXT;
8803
400
            if (typeProxy == glslang::EbtFloat16 &&
8804
400
                (opType.getVectorSize() == 2 || opType.getVectorSize() == 4)) {
8805
400
                builder.addExtension(spv::E_SPV_NV_shader_atomic_fp16_vector);
8806
400
                builder.addCapability(spv::Capability::AtomicFloat16VectorNV);
8807
400
            } else {
8808
0
                builder.addExtension(spv::E_SPV_EXT_shader_atomic_float_min_max);
8809
0
                if (typeProxy == glslang::EbtFloat16)
8810
0
                    builder.addCapability(spv::Capability::AtomicFloat16MinMaxEXT);
8811
0
                else if (typeProxy == glslang::EbtFloat)
8812
0
                    builder.addCapability(spv::Capability::AtomicFloat32MinMaxEXT);
8813
0
                else
8814
0
                    builder.addCapability(spv::Capability::AtomicFloat64MinMaxEXT);
8815
0
            }
8816
400
        } else if (typeProxy == glslang::EbtUint || typeProxy == glslang::EbtUint64) {
8817
26
            opCode = spv::Op::OpAtomicUMax;
8818
26
        } else {
8819
26
            opCode = spv::Op::OpAtomicSMax;
8820
26
        }
8821
452
        break;
8822
2
    case glslang::EOpAtomicAnd:
8823
54
    case glslang::EOpImageAtomicAnd:
8824
54
    case glslang::EOpAtomicCounterAnd:
8825
54
        opCode = spv::Op::OpAtomicAnd;
8826
54
        break;
8827
2
    case glslang::EOpAtomicOr:
8828
54
    case glslang::EOpImageAtomicOr:
8829
54
    case glslang::EOpAtomicCounterOr:
8830
54
        opCode = spv::Op::OpAtomicOr;
8831
54
        break;
8832
4
    case glslang::EOpAtomicXor:
8833
56
    case glslang::EOpImageAtomicXor:
8834
56
    case glslang::EOpAtomicCounterXor:
8835
56
        opCode = spv::Op::OpAtomicXor;
8836
56
        break;
8837
50
    case glslang::EOpAtomicExchange:
8838
452
    case glslang::EOpImageAtomicExchange:
8839
452
    case glslang::EOpAtomicCounterExchange:
8840
452
        if ((typeProxy == glslang::EbtFloat16) && 
8841
400
            (opType.getVectorSize() == 2 || opType.getVectorSize() == 4)) {
8842
400
                builder.addExtension(spv::E_SPV_NV_shader_atomic_fp16_vector);
8843
400
                builder.addCapability(spv::Capability::AtomicFloat16VectorNV);
8844
400
        }
8845
8846
452
        opCode = spv::Op::OpAtomicExchange;
8847
452
        break;
8848
2
    case glslang::EOpAtomicCompSwap:
8849
54
    case glslang::EOpImageAtomicCompSwap:
8850
54
    case glslang::EOpAtomicCounterCompSwap:
8851
54
        opCode = spv::Op::OpAtomicCompareExchange;
8852
54
        break;
8853
0
    case glslang::EOpAtomicCounterIncrement:
8854
0
        opCode = spv::Op::OpAtomicIIncrement;
8855
0
        break;
8856
0
    case glslang::EOpAtomicCounterDecrement:
8857
0
        opCode = spv::Op::OpAtomicIDecrement;
8858
0
        break;
8859
0
    case glslang::EOpAtomicCounter:
8860
26
    case glslang::EOpImageAtomicLoad:
8861
26
    case glslang::EOpAtomicLoad:
8862
26
        opCode = spv::Op::OpAtomicLoad;
8863
26
        break;
8864
0
    case glslang::EOpAtomicStore:
8865
26
    case glslang::EOpImageAtomicStore:
8866
26
        opCode = spv::Op::OpAtomicStore;
8867
26
        break;
8868
0
    default:
8869
0
        assert(0);
8870
0
        break;
8871
2.16k
    }
8872
8873
2.16k
    if (typeProxy == glslang::EbtInt64 || typeProxy == glslang::EbtUint64)
8874
468
        builder.addCapability(spv::Capability::Int64Atomics);
8875
8876
    // Sort out the operands
8877
    //  - mapping from glslang -> SPV
8878
    //  - there are extra SPV operands that are optional in glslang
8879
    //  - compare-exchange swaps the value and comparator
8880
    //  - compare-exchange has an extra memory semantics
8881
    //  - EOpAtomicCounterDecrement needs a post decrement
8882
2.16k
    spv::Id pointerId = 0, compareId = 0, valueId = 0;
8883
    // scope defaults to Device in the old model, QueueFamilyKHR in the new model
8884
2.16k
    spv::Id scopeId;
8885
2.16k
    if (glslangIntermediate->usingVulkanMemoryModel()) {
8886
69
        scopeId = builder.makeUintConstant(spv::Scope::QueueFamilyKHR);
8887
2.09k
    } else {
8888
2.09k
        scopeId = builder.makeUintConstant(spv::Scope::Device);
8889
2.09k
    }
8890
    // semantics default to relaxed
8891
2.16k
    spv::Id semanticsId = builder.makeUintConstant(lvalueCoherentFlags.isVolatile() &&
8892
1.40k
        glslangIntermediate->usingVulkanMemoryModel() ?
8893
0
                                                    spv::MemorySemanticsMask::Volatile :
8894
2.16k
                                                    spv::MemorySemanticsMask::MaskNone);
8895
2.16k
    spv::Id semanticsId2 = semanticsId;
8896
8897
2.16k
    pointerId = operands[0];
8898
2.16k
    if (opCode == spv::Op::OpAtomicIIncrement || opCode == spv::Op::OpAtomicIDecrement) {
8899
        // no additional operands
8900
2.16k
    } else if (opCode == spv::Op::OpAtomicCompareExchange) {
8901
54
        compareId = operands[1];
8902
54
        valueId = operands[2];
8903
54
        if (operands.size() > 3) {
8904
26
            scopeId = operands[3];
8905
26
            semanticsId = builder.makeUintConstant(
8906
26
                builder.getConstantScalar(operands[4]) | builder.getConstantScalar(operands[5]));
8907
26
            semanticsId2 = builder.makeUintConstant(
8908
26
                builder.getConstantScalar(operands[6]) | builder.getConstantScalar(operands[7]));
8909
26
        }
8910
2.10k
    } else if (opCode == spv::Op::OpAtomicLoad) {
8911
26
        if (operands.size() > 1) {
8912
26
            scopeId = operands[1];
8913
26
            semanticsId = builder.makeUintConstant(
8914
26
                builder.getConstantScalar(operands[2]) | builder.getConstantScalar(operands[3]));
8915
26
        }
8916
2.08k
    } else {
8917
        // atomic store or RMW
8918
2.08k
        valueId = operands[1];
8919
2.08k
        if (operands.size() > 2) {
8920
208
            scopeId = operands[2];
8921
208
            semanticsId = builder.makeUintConstant
8922
208
                (builder.getConstantScalar(operands[3]) | builder.getConstantScalar(operands[4]));
8923
208
        }
8924
2.08k
    }
8925
8926
    // Check for capabilities
8927
2.16k
    auto const semanticsImmediate = (spv::MemorySemanticsMask)(builder.getConstantScalar(semanticsId) | builder.getConstantScalar(semanticsId2));
8928
2.16k
    if (anySet(semanticsImmediate, spv::MemorySemanticsMask::MakeAvailableKHR |
8929
2.16k
                                   spv::MemorySemanticsMask::MakeVisibleKHR |
8930
2.16k
                                   spv::MemorySemanticsMask::OutputMemoryKHR |
8931
2.16k
                                   spv::MemorySemanticsMask::Volatile)) {
8932
0
        builder.addCapability(spv::Capability::VulkanMemoryModelKHR);
8933
0
    }
8934
8935
2.16k
    auto const scope = (spv::Scope)builder.getConstantScalar(scopeId);
8936
2.16k
    if (scope == spv::Scope::QueueFamily) {
8937
69
        builder.addCapability(spv::Capability::VulkanMemoryModelKHR);
8938
69
    }
8939
8940
2.16k
    if (glslangIntermediate->usingVulkanMemoryModel() && scope == spv::Scope::Device) {
8941
0
        builder.addCapability(spv::Capability::VulkanMemoryModelDeviceScopeKHR);
8942
0
    }
8943
8944
2.16k
    std::vector<spv::Id> spvAtomicOperands;  // hold the spv operands
8945
2.16k
    spvAtomicOperands.reserve(6);
8946
2.16k
    spvAtomicOperands.push_back(pointerId);
8947
2.16k
    spvAtomicOperands.push_back(scopeId);
8948
2.16k
    spvAtomicOperands.push_back(semanticsId);
8949
2.16k
    if (opCode == spv::Op::OpAtomicCompareExchange) {
8950
54
        spvAtomicOperands.push_back(semanticsId2);
8951
54
        spvAtomicOperands.push_back(valueId);
8952
54
        spvAtomicOperands.push_back(compareId);
8953
2.10k
    } else if (opCode != spv::Op::OpAtomicLoad && opCode != spv::Op::OpAtomicIIncrement && opCode != spv::Op::OpAtomicIDecrement) {
8954
2.08k
        spvAtomicOperands.push_back(valueId);
8955
2.08k
    }
8956
8957
2.16k
    if (opCode == spv::Op::OpAtomicStore) {
8958
26
        builder.createNoResultOp(opCode, spvAtomicOperands);
8959
26
        return 0;
8960
2.13k
    } else {
8961
2.13k
        spv::Id resultId = builder.createOp(opCode, typeId, spvAtomicOperands);
8962
8963
        // GLSL and HLSL atomic-counter decrement return post-decrement value,
8964
        // while SPIR-V returns pre-decrement value. Translate between these semantics.
8965
2.13k
        if (op == glslang::EOpAtomicCounterDecrement)
8966
0
            resultId = builder.createBinOp(spv::Op::OpISub, typeId, resultId, builder.makeIntConstant(1));
8967
8968
2.13k
        return resultId;
8969
2.13k
    }
8970
2.16k
}
8971
8972
// Create group invocation operations.
8973
spv::Id TGlslangToSpvTraverser::createInvocationsOperation(glslang::TOperator op, spv::Id typeId,
8974
    std::vector<spv::Id>& operands, glslang::TBasicType typeProxy)
8975
0
{
8976
0
    bool isUnsigned = isTypeUnsignedInt(typeProxy);
8977
0
    bool isFloat = isTypeFloat(typeProxy);
8978
8979
0
    spv::Op opCode = spv::Op::OpNop;
8980
0
    std::vector<spv::IdImmediate> spvGroupOperands;
8981
0
    spv::GroupOperation groupOperation = spv::GroupOperation::Max;
8982
8983
0
    if (op == glslang::EOpBallot || op == glslang::EOpReadFirstInvocation ||
8984
0
        op == glslang::EOpReadInvocation) {
8985
0
        builder.addExtension(spv::E_SPV_KHR_shader_ballot);
8986
0
        builder.addCapability(spv::Capability::SubgroupBallotKHR);
8987
0
    } else if (op == glslang::EOpAnyInvocation ||
8988
0
        op == glslang::EOpAllInvocations ||
8989
0
        op == glslang::EOpAllInvocationsEqual) {
8990
0
        builder.addExtension(spv::E_SPV_KHR_subgroup_vote);
8991
0
        builder.addCapability(spv::Capability::SubgroupVoteKHR);
8992
0
    } else {
8993
0
        builder.addCapability(spv::Capability::Groups);
8994
0
        if (op == glslang::EOpMinInvocationsNonUniform ||
8995
0
            op == glslang::EOpMaxInvocationsNonUniform ||
8996
0
            op == glslang::EOpAddInvocationsNonUniform ||
8997
0
            op == glslang::EOpMinInvocationsInclusiveScanNonUniform ||
8998
0
            op == glslang::EOpMaxInvocationsInclusiveScanNonUniform ||
8999
0
            op == glslang::EOpAddInvocationsInclusiveScanNonUniform ||
9000
0
            op == glslang::EOpMinInvocationsExclusiveScanNonUniform ||
9001
0
            op == glslang::EOpMaxInvocationsExclusiveScanNonUniform ||
9002
0
            op == glslang::EOpAddInvocationsExclusiveScanNonUniform)
9003
0
            builder.addExtension(spv::E_SPV_AMD_shader_ballot);
9004
9005
0
        switch (op) {
9006
0
        case glslang::EOpMinInvocations:
9007
0
        case glslang::EOpMaxInvocations:
9008
0
        case glslang::EOpAddInvocations:
9009
0
        case glslang::EOpMinInvocationsNonUniform:
9010
0
        case glslang::EOpMaxInvocationsNonUniform:
9011
0
        case glslang::EOpAddInvocationsNonUniform:
9012
0
            groupOperation = spv::GroupOperation::Reduce;
9013
0
            break;
9014
0
        case glslang::EOpMinInvocationsInclusiveScan:
9015
0
        case glslang::EOpMaxInvocationsInclusiveScan:
9016
0
        case glslang::EOpAddInvocationsInclusiveScan:
9017
0
        case glslang::EOpMinInvocationsInclusiveScanNonUniform:
9018
0
        case glslang::EOpMaxInvocationsInclusiveScanNonUniform:
9019
0
        case glslang::EOpAddInvocationsInclusiveScanNonUniform:
9020
0
            groupOperation = spv::GroupOperation::InclusiveScan;
9021
0
            break;
9022
0
        case glslang::EOpMinInvocationsExclusiveScan:
9023
0
        case glslang::EOpMaxInvocationsExclusiveScan:
9024
0
        case glslang::EOpAddInvocationsExclusiveScan:
9025
0
        case glslang::EOpMinInvocationsExclusiveScanNonUniform:
9026
0
        case glslang::EOpMaxInvocationsExclusiveScanNonUniform:
9027
0
        case glslang::EOpAddInvocationsExclusiveScanNonUniform:
9028
0
            groupOperation = spv::GroupOperation::ExclusiveScan;
9029
0
            break;
9030
0
        default:
9031
0
            break;
9032
0
        }
9033
0
        spv::IdImmediate scope = { true, builder.makeUintConstant(spv::Scope::Subgroup) };
9034
0
        spvGroupOperands.push_back(scope);
9035
0
        if (groupOperation != spv::GroupOperation::Max) {
9036
0
            spv::IdImmediate groupOp = { false, (unsigned)groupOperation };
9037
0
            spvGroupOperands.push_back(groupOp);
9038
0
        }
9039
0
    }
9040
9041
0
    for (auto opIt = operands.begin(); opIt != operands.end(); ++opIt) {
9042
0
        spv::IdImmediate op = { true, *opIt };
9043
0
        spvGroupOperands.push_back(op);
9044
0
    }
9045
9046
0
    switch (op) {
9047
0
    case glslang::EOpAnyInvocation:
9048
0
        opCode = spv::Op::OpSubgroupAnyKHR;
9049
0
        break;
9050
0
    case glslang::EOpAllInvocations:
9051
0
        opCode = spv::Op::OpSubgroupAllKHR;
9052
0
        break;
9053
0
    case glslang::EOpAllInvocationsEqual:
9054
0
        opCode = spv::Op::OpSubgroupAllEqualKHR;
9055
0
        break;
9056
0
    case glslang::EOpReadInvocation:
9057
0
        opCode = spv::Op::OpSubgroupReadInvocationKHR;
9058
0
        if (builder.isVectorType(typeId))
9059
0
            return CreateInvocationsVectorOperation(opCode, groupOperation, typeId, operands);
9060
0
        break;
9061
0
    case glslang::EOpReadFirstInvocation:
9062
0
        opCode = spv::Op::OpSubgroupFirstInvocationKHR;
9063
0
        if (builder.isVectorType(typeId))
9064
0
            return CreateInvocationsVectorOperation(opCode, groupOperation, typeId, operands);
9065
0
        break;
9066
0
    case glslang::EOpBallot:
9067
0
    {
9068
        // NOTE: According to the spec, the result type of "OpSubgroupBallotKHR" must be a 4 component vector of 32
9069
        // bit integer types. The GLSL built-in function "ballotARB()" assumes the maximum number of invocations in
9070
        // a subgroup is 64. Thus, we have to convert uvec4.xy to uint64_t as follow:
9071
        //
9072
        //     result = Bitcast(SubgroupBallotKHR(Predicate).xy)
9073
        //
9074
0
        spv::Id uintType  = builder.makeUintType(32);
9075
0
        spv::Id uvec4Type = builder.makeVectorType(uintType, 4);
9076
0
        spv::Id result = builder.createOp(spv::Op::OpSubgroupBallotKHR, uvec4Type, spvGroupOperands);
9077
9078
0
        std::vector<spv::Id> components;
9079
0
        components.push_back(builder.createCompositeExtract(result, uintType, 0));
9080
0
        components.push_back(builder.createCompositeExtract(result, uintType, 1));
9081
9082
0
        spv::Id uvec2Type = builder.makeVectorType(uintType, 2);
9083
0
        return builder.createUnaryOp(spv::Op::OpBitcast, typeId,
9084
0
                                     builder.createCompositeConstruct(uvec2Type, components));
9085
0
    }
9086
9087
0
    case glslang::EOpMinInvocations:
9088
0
    case glslang::EOpMaxInvocations:
9089
0
    case glslang::EOpAddInvocations:
9090
0
    case glslang::EOpMinInvocationsInclusiveScan:
9091
0
    case glslang::EOpMaxInvocationsInclusiveScan:
9092
0
    case glslang::EOpAddInvocationsInclusiveScan:
9093
0
    case glslang::EOpMinInvocationsExclusiveScan:
9094
0
    case glslang::EOpMaxInvocationsExclusiveScan:
9095
0
    case glslang::EOpAddInvocationsExclusiveScan:
9096
0
        if (op == glslang::EOpMinInvocations ||
9097
0
            op == glslang::EOpMinInvocationsInclusiveScan ||
9098
0
            op == glslang::EOpMinInvocationsExclusiveScan) {
9099
0
            if (isFloat)
9100
0
                opCode = spv::Op::OpGroupFMin;
9101
0
            else {
9102
0
                if (isUnsigned)
9103
0
                    opCode = spv::Op::OpGroupUMin;
9104
0
                else
9105
0
                    opCode = spv::Op::OpGroupSMin;
9106
0
            }
9107
0
        } else if (op == glslang::EOpMaxInvocations ||
9108
0
                   op == glslang::EOpMaxInvocationsInclusiveScan ||
9109
0
                   op == glslang::EOpMaxInvocationsExclusiveScan) {
9110
0
            if (isFloat)
9111
0
                opCode = spv::Op::OpGroupFMax;
9112
0
            else {
9113
0
                if (isUnsigned)
9114
0
                    opCode = spv::Op::OpGroupUMax;
9115
0
                else
9116
0
                    opCode = spv::Op::OpGroupSMax;
9117
0
            }
9118
0
        } else {
9119
0
            if (isFloat)
9120
0
                opCode = spv::Op::OpGroupFAdd;
9121
0
            else
9122
0
                opCode = spv::Op::OpGroupIAdd;
9123
0
        }
9124
9125
0
        if (builder.isVectorType(typeId))
9126
0
            return CreateInvocationsVectorOperation(opCode, groupOperation, typeId, operands);
9127
9128
0
        break;
9129
0
    case glslang::EOpMinInvocationsNonUniform:
9130
0
    case glslang::EOpMaxInvocationsNonUniform:
9131
0
    case glslang::EOpAddInvocationsNonUniform:
9132
0
    case glslang::EOpMinInvocationsInclusiveScanNonUniform:
9133
0
    case glslang::EOpMaxInvocationsInclusiveScanNonUniform:
9134
0
    case glslang::EOpAddInvocationsInclusiveScanNonUniform:
9135
0
    case glslang::EOpMinInvocationsExclusiveScanNonUniform:
9136
0
    case glslang::EOpMaxInvocationsExclusiveScanNonUniform:
9137
0
    case glslang::EOpAddInvocationsExclusiveScanNonUniform:
9138
0
        if (op == glslang::EOpMinInvocationsNonUniform ||
9139
0
            op == glslang::EOpMinInvocationsInclusiveScanNonUniform ||
9140
0
            op == glslang::EOpMinInvocationsExclusiveScanNonUniform) {
9141
0
            if (isFloat)
9142
0
                opCode = spv::Op::OpGroupFMinNonUniformAMD;
9143
0
            else {
9144
0
                if (isUnsigned)
9145
0
                    opCode = spv::Op::OpGroupUMinNonUniformAMD;
9146
0
                else
9147
0
                    opCode = spv::Op::OpGroupSMinNonUniformAMD;
9148
0
            }
9149
0
        }
9150
0
        else if (op == glslang::EOpMaxInvocationsNonUniform ||
9151
0
                 op == glslang::EOpMaxInvocationsInclusiveScanNonUniform ||
9152
0
                 op == glslang::EOpMaxInvocationsExclusiveScanNonUniform) {
9153
0
            if (isFloat)
9154
0
                opCode = spv::Op::OpGroupFMaxNonUniformAMD;
9155
0
            else {
9156
0
                if (isUnsigned)
9157
0
                    opCode = spv::Op::OpGroupUMaxNonUniformAMD;
9158
0
                else
9159
0
                    opCode = spv::Op::OpGroupSMaxNonUniformAMD;
9160
0
            }
9161
0
        }
9162
0
        else {
9163
0
            if (isFloat)
9164
0
                opCode = spv::Op::OpGroupFAddNonUniformAMD;
9165
0
            else
9166
0
                opCode = spv::Op::OpGroupIAddNonUniformAMD;
9167
0
        }
9168
9169
0
        if (builder.isVectorType(typeId))
9170
0
            return CreateInvocationsVectorOperation(opCode, groupOperation, typeId, operands);
9171
9172
0
        break;
9173
0
    default:
9174
0
        logger->missingFunctionality("invocation operation");
9175
0
        return spv::NoResult;
9176
0
    }
9177
9178
0
    assert(opCode != spv::Op::OpNop);
9179
0
    return builder.createOp(opCode, typeId, spvGroupOperands);
9180
0
}
9181
9182
// Create group invocation operations on a vector
9183
spv::Id TGlslangToSpvTraverser::CreateInvocationsVectorOperation(spv::Op op, spv::GroupOperation groupOperation,
9184
    spv::Id typeId, std::vector<spv::Id>& operands)
9185
0
{
9186
0
    assert(op == spv::Op::OpGroupFMin || op == spv::Op::OpGroupUMin || op == spv::Op::OpGroupSMin ||
9187
0
           op == spv::Op::OpGroupFMax || op == spv::Op::OpGroupUMax || op == spv::Op::OpGroupSMax ||
9188
0
           op == spv::Op::OpGroupFAdd || op == spv::Op::OpGroupIAdd || op == spv::Op::OpGroupBroadcast ||
9189
0
           op == spv::Op::OpSubgroupReadInvocationKHR || op == spv::Op::OpSubgroupFirstInvocationKHR ||
9190
0
           op == spv::Op::OpGroupFMinNonUniformAMD || op == spv::Op::OpGroupUMinNonUniformAMD ||
9191
0
           op == spv::Op::OpGroupSMinNonUniformAMD ||
9192
0
           op == spv::Op::OpGroupFMaxNonUniformAMD || op == spv::Op::OpGroupUMaxNonUniformAMD ||
9193
0
           op == spv::Op::OpGroupSMaxNonUniformAMD ||
9194
0
           op == spv::Op::OpGroupFAddNonUniformAMD || op == spv::Op::OpGroupIAddNonUniformAMD);
9195
9196
    // Handle group invocation operations scalar by scalar.
9197
    // The result type is the same type as the original type.
9198
    // The algorithm is to:
9199
    //   - break the vector into scalars
9200
    //   - apply the operation to each scalar
9201
    //   - make a vector out the scalar results
9202
9203
    // get the types sorted out
9204
0
    int numComponents = builder.getNumComponents(operands[0]);
9205
0
    spv::Id scalarType = builder.getScalarTypeId(builder.getTypeId(operands[0]));
9206
0
    std::vector<spv::Id> results;
9207
9208
    // do each scalar op
9209
0
    for (int comp = 0; comp < numComponents; ++comp) {
9210
0
        std::vector<unsigned int> indexes;
9211
0
        indexes.push_back(comp);
9212
0
        spv::IdImmediate scalar = { true, builder.createCompositeExtract(operands[0], scalarType, indexes) };
9213
0
        std::vector<spv::IdImmediate> spvGroupOperands;
9214
0
        if (op == spv::Op::OpSubgroupReadInvocationKHR) {
9215
0
            spvGroupOperands.push_back(scalar);
9216
0
            spv::IdImmediate operand = { true, operands[1] };
9217
0
            spvGroupOperands.push_back(operand);
9218
0
        } else if (op == spv::Op::OpSubgroupFirstInvocationKHR) {
9219
0
            spvGroupOperands.push_back(scalar);
9220
0
        } else if (op == spv::Op::OpGroupBroadcast) {
9221
0
            spv::IdImmediate scope = { true, builder.makeUintConstant(spv::Scope::Subgroup) };
9222
0
            spvGroupOperands.push_back(scope);
9223
0
            spvGroupOperands.push_back(scalar);
9224
0
            spv::IdImmediate operand = { true, operands[1] };
9225
0
            spvGroupOperands.push_back(operand);
9226
0
        } else {
9227
0
            spv::IdImmediate scope = { true, builder.makeUintConstant(spv::Scope::Subgroup) };
9228
0
            spvGroupOperands.push_back(scope);
9229
0
            spv::IdImmediate groupOp = { false, (unsigned)groupOperation };
9230
0
            spvGroupOperands.push_back(groupOp);
9231
0
            spvGroupOperands.push_back(scalar);
9232
0
        }
9233
9234
0
        results.push_back(builder.createOp(op, scalarType, spvGroupOperands));
9235
0
    }
9236
9237
    // put the pieces together
9238
0
    return builder.createCompositeConstruct(typeId, results);
9239
0
}
9240
9241
// Create subgroup invocation operations.
9242
spv::Id TGlslangToSpvTraverser::createSubgroupOperation(glslang::TOperator op, spv::Id typeId,
9243
    std::vector<spv::Id>& operands, glslang::TBasicType typeProxy)
9244
0
{
9245
    // Add the required capabilities.
9246
0
    switch (op) {
9247
0
    case glslang::EOpSubgroupElect:
9248
0
        builder.addCapability(spv::Capability::GroupNonUniform);
9249
0
        break;
9250
0
    case glslang::EOpSubgroupQuadAll:
9251
0
    case glslang::EOpSubgroupQuadAny:
9252
0
        builder.addExtension(spv::E_SPV_KHR_quad_control);
9253
0
        builder.addCapability(spv::Capability::QuadControlKHR);
9254
0
        [[fallthrough]];
9255
0
    case glslang::EOpSubgroupAll:
9256
0
    case glslang::EOpSubgroupAny:
9257
0
    case glslang::EOpSubgroupAllEqual:
9258
0
        builder.addCapability(spv::Capability::GroupNonUniform);
9259
0
        builder.addCapability(spv::Capability::GroupNonUniformVote);
9260
0
        break;
9261
0
    case glslang::EOpSubgroupBroadcast:
9262
0
    case glslang::EOpSubgroupBroadcastFirst:
9263
0
    case glslang::EOpSubgroupBallot:
9264
0
    case glslang::EOpSubgroupInverseBallot:
9265
0
    case glslang::EOpSubgroupBallotBitExtract:
9266
0
    case glslang::EOpSubgroupBallotBitCount:
9267
0
    case glslang::EOpSubgroupBallotInclusiveBitCount:
9268
0
    case glslang::EOpSubgroupBallotExclusiveBitCount:
9269
0
    case glslang::EOpSubgroupBallotFindLSB:
9270
0
    case glslang::EOpSubgroupBallotFindMSB:
9271
0
        builder.addCapability(spv::Capability::GroupNonUniform);
9272
0
        builder.addCapability(spv::Capability::GroupNonUniformBallot);
9273
0
        break;
9274
0
    case glslang::EOpSubgroupRotate:
9275
0
    case glslang::EOpSubgroupClusteredRotate:
9276
0
        builder.addExtension(spv::E_SPV_KHR_subgroup_rotate);
9277
0
        builder.addCapability(spv::Capability::GroupNonUniformRotateKHR);
9278
0
        break;
9279
0
    case glslang::EOpSubgroupShuffle:
9280
0
    case glslang::EOpSubgroupShuffleXor:
9281
0
        builder.addCapability(spv::Capability::GroupNonUniform);
9282
0
        builder.addCapability(spv::Capability::GroupNonUniformShuffle);
9283
0
        break;
9284
0
    case glslang::EOpSubgroupShuffleUp:
9285
0
    case glslang::EOpSubgroupShuffleDown:
9286
0
        builder.addCapability(spv::Capability::GroupNonUniform);
9287
0
        builder.addCapability(spv::Capability::GroupNonUniformShuffleRelative);
9288
0
        break;
9289
0
    case glslang::EOpSubgroupAdd:
9290
0
    case glslang::EOpSubgroupMul:
9291
0
    case glslang::EOpSubgroupMin:
9292
0
    case glslang::EOpSubgroupMax:
9293
0
    case glslang::EOpSubgroupAnd:
9294
0
    case glslang::EOpSubgroupOr:
9295
0
    case glslang::EOpSubgroupXor:
9296
0
    case glslang::EOpSubgroupInclusiveAdd:
9297
0
    case glslang::EOpSubgroupInclusiveMul:
9298
0
    case glslang::EOpSubgroupInclusiveMin:
9299
0
    case glslang::EOpSubgroupInclusiveMax:
9300
0
    case glslang::EOpSubgroupInclusiveAnd:
9301
0
    case glslang::EOpSubgroupInclusiveOr:
9302
0
    case glslang::EOpSubgroupInclusiveXor:
9303
0
    case glslang::EOpSubgroupExclusiveAdd:
9304
0
    case glslang::EOpSubgroupExclusiveMul:
9305
0
    case glslang::EOpSubgroupExclusiveMin:
9306
0
    case glslang::EOpSubgroupExclusiveMax:
9307
0
    case glslang::EOpSubgroupExclusiveAnd:
9308
0
    case glslang::EOpSubgroupExclusiveOr:
9309
0
    case glslang::EOpSubgroupExclusiveXor:
9310
0
        builder.addCapability(spv::Capability::GroupNonUniform);
9311
0
        builder.addCapability(spv::Capability::GroupNonUniformArithmetic);
9312
0
        break;
9313
0
    case glslang::EOpSubgroupClusteredAdd:
9314
0
    case glslang::EOpSubgroupClusteredMul:
9315
0
    case glslang::EOpSubgroupClusteredMin:
9316
0
    case glslang::EOpSubgroupClusteredMax:
9317
0
    case glslang::EOpSubgroupClusteredAnd:
9318
0
    case glslang::EOpSubgroupClusteredOr:
9319
0
    case glslang::EOpSubgroupClusteredXor:
9320
0
        builder.addCapability(spv::Capability::GroupNonUniform);
9321
0
        builder.addCapability(spv::Capability::GroupNonUniformClustered);
9322
0
        break;
9323
0
    case glslang::EOpSubgroupQuadBroadcast:
9324
0
    case glslang::EOpSubgroupQuadSwapHorizontal:
9325
0
    case glslang::EOpSubgroupQuadSwapVertical:
9326
0
    case glslang::EOpSubgroupQuadSwapDiagonal:
9327
0
        builder.addCapability(spv::Capability::GroupNonUniform);
9328
0
        builder.addCapability(spv::Capability::GroupNonUniformQuad);
9329
0
        break;
9330
0
    case glslang::EOpSubgroupPartitionedAdd:
9331
0
    case glslang::EOpSubgroupPartitionedMul:
9332
0
    case glslang::EOpSubgroupPartitionedMin:
9333
0
    case glslang::EOpSubgroupPartitionedMax:
9334
0
    case glslang::EOpSubgroupPartitionedAnd:
9335
0
    case glslang::EOpSubgroupPartitionedOr:
9336
0
    case glslang::EOpSubgroupPartitionedXor:
9337
0
    case glslang::EOpSubgroupPartitionedInclusiveAdd:
9338
0
    case glslang::EOpSubgroupPartitionedInclusiveMul:
9339
0
    case glslang::EOpSubgroupPartitionedInclusiveMin:
9340
0
    case glslang::EOpSubgroupPartitionedInclusiveMax:
9341
0
    case glslang::EOpSubgroupPartitionedInclusiveAnd:
9342
0
    case glslang::EOpSubgroupPartitionedInclusiveOr:
9343
0
    case glslang::EOpSubgroupPartitionedInclusiveXor:
9344
0
    case glslang::EOpSubgroupPartitionedExclusiveAdd:
9345
0
    case glslang::EOpSubgroupPartitionedExclusiveMul:
9346
0
    case glslang::EOpSubgroupPartitionedExclusiveMin:
9347
0
    case glslang::EOpSubgroupPartitionedExclusiveMax:
9348
0
    case glslang::EOpSubgroupPartitionedExclusiveAnd:
9349
0
    case glslang::EOpSubgroupPartitionedExclusiveOr:
9350
0
    case glslang::EOpSubgroupPartitionedExclusiveXor:
9351
0
        builder.addExtension(spv::E_SPV_NV_shader_subgroup_partitioned);
9352
0
        builder.addCapability(spv::Capability::GroupNonUniformPartitionedNV);
9353
0
        break;
9354
0
    default: assert(0 && "Unhandled subgroup operation!");
9355
0
    }
9356
9357
9358
0
    const bool isUnsigned = isTypeUnsignedInt(typeProxy);
9359
0
    const bool isFloat = isTypeFloat(typeProxy);
9360
0
    const bool isBool = typeProxy == glslang::EbtBool;
9361
9362
0
    spv::Op opCode = spv::Op::OpNop;
9363
9364
    // Figure out which opcode to use.
9365
0
    switch (op) {
9366
0
    case glslang::EOpSubgroupElect:                   opCode = spv::Op::OpGroupNonUniformElect; break;
9367
0
    case glslang::EOpSubgroupQuadAll:                 opCode = spv::Op::OpGroupNonUniformQuadAllKHR; break;
9368
0
    case glslang::EOpSubgroupAll:                     opCode = spv::Op::OpGroupNonUniformAll; break;
9369
0
    case glslang::EOpSubgroupQuadAny:                 opCode = spv::Op::OpGroupNonUniformQuadAnyKHR; break;
9370
0
    case glslang::EOpSubgroupAny:                     opCode = spv::Op::OpGroupNonUniformAny; break;
9371
0
    case glslang::EOpSubgroupAllEqual:                opCode = spv::Op::OpGroupNonUniformAllEqual; break;
9372
0
    case glslang::EOpSubgroupBroadcast:               opCode = spv::Op::OpGroupNonUniformBroadcast; break;
9373
0
    case glslang::EOpSubgroupBroadcastFirst:          opCode = spv::Op::OpGroupNonUniformBroadcastFirst; break;
9374
0
    case glslang::EOpSubgroupBallot:                  opCode = spv::Op::OpGroupNonUniformBallot; break;
9375
0
    case glslang::EOpSubgroupInverseBallot:           opCode = spv::Op::OpGroupNonUniformInverseBallot; break;
9376
0
    case glslang::EOpSubgroupBallotBitExtract:        opCode = spv::Op::OpGroupNonUniformBallotBitExtract; break;
9377
0
    case glslang::EOpSubgroupBallotBitCount:
9378
0
    case glslang::EOpSubgroupBallotInclusiveBitCount:
9379
0
    case glslang::EOpSubgroupBallotExclusiveBitCount: opCode = spv::Op::OpGroupNonUniformBallotBitCount; break;
9380
0
    case glslang::EOpSubgroupBallotFindLSB:           opCode = spv::Op::OpGroupNonUniformBallotFindLSB; break;
9381
0
    case glslang::EOpSubgroupBallotFindMSB:           opCode = spv::Op::OpGroupNonUniformBallotFindMSB; break;
9382
0
    case glslang::EOpSubgroupShuffle:                 opCode = spv::Op::OpGroupNonUniformShuffle; break;
9383
0
    case glslang::EOpSubgroupShuffleXor:              opCode = spv::Op::OpGroupNonUniformShuffleXor; break;
9384
0
    case glslang::EOpSubgroupShuffleUp:               opCode = spv::Op::OpGroupNonUniformShuffleUp; break;
9385
0
    case glslang::EOpSubgroupShuffleDown:             opCode = spv::Op::OpGroupNonUniformShuffleDown; break;
9386
0
    case glslang::EOpSubgroupRotate:
9387
0
    case glslang::EOpSubgroupClusteredRotate:         opCode = spv::Op::OpGroupNonUniformRotateKHR; break;
9388
0
    case glslang::EOpSubgroupAdd:
9389
0
    case glslang::EOpSubgroupInclusiveAdd:
9390
0
    case glslang::EOpSubgroupExclusiveAdd:
9391
0
    case glslang::EOpSubgroupClusteredAdd:
9392
0
    case glslang::EOpSubgroupPartitionedAdd:
9393
0
    case glslang::EOpSubgroupPartitionedInclusiveAdd:
9394
0
    case glslang::EOpSubgroupPartitionedExclusiveAdd:
9395
0
        if (isFloat) {
9396
0
            opCode = spv::Op::OpGroupNonUniformFAdd;
9397
0
        } else {
9398
0
            opCode = spv::Op::OpGroupNonUniformIAdd;
9399
0
        }
9400
0
        break;
9401
0
    case glslang::EOpSubgroupMul:
9402
0
    case glslang::EOpSubgroupInclusiveMul:
9403
0
    case glslang::EOpSubgroupExclusiveMul:
9404
0
    case glslang::EOpSubgroupClusteredMul:
9405
0
    case glslang::EOpSubgroupPartitionedMul:
9406
0
    case glslang::EOpSubgroupPartitionedInclusiveMul:
9407
0
    case glslang::EOpSubgroupPartitionedExclusiveMul:
9408
0
        if (isFloat) {
9409
0
            opCode = spv::Op::OpGroupNonUniformFMul;
9410
0
        } else {
9411
0
            opCode = spv::Op::OpGroupNonUniformIMul;
9412
0
        }
9413
0
        break;
9414
0
    case glslang::EOpSubgroupMin:
9415
0
    case glslang::EOpSubgroupInclusiveMin:
9416
0
    case glslang::EOpSubgroupExclusiveMin:
9417
0
    case glslang::EOpSubgroupClusteredMin:
9418
0
    case glslang::EOpSubgroupPartitionedMin:
9419
0
    case glslang::EOpSubgroupPartitionedInclusiveMin:
9420
0
    case glslang::EOpSubgroupPartitionedExclusiveMin:
9421
0
        if (isFloat) {
9422
0
            opCode = spv::Op::OpGroupNonUniformFMin;
9423
0
        } else if (isUnsigned) {
9424
0
            opCode = spv::Op::OpGroupNonUniformUMin;
9425
0
        } else {
9426
0
            opCode = spv::Op::OpGroupNonUniformSMin;
9427
0
        }
9428
0
        break;
9429
0
    case glslang::EOpSubgroupMax:
9430
0
    case glslang::EOpSubgroupInclusiveMax:
9431
0
    case glslang::EOpSubgroupExclusiveMax:
9432
0
    case glslang::EOpSubgroupClusteredMax:
9433
0
    case glslang::EOpSubgroupPartitionedMax:
9434
0
    case glslang::EOpSubgroupPartitionedInclusiveMax:
9435
0
    case glslang::EOpSubgroupPartitionedExclusiveMax:
9436
0
        if (isFloat) {
9437
0
            opCode = spv::Op::OpGroupNonUniformFMax;
9438
0
        } else if (isUnsigned) {
9439
0
            opCode = spv::Op::OpGroupNonUniformUMax;
9440
0
        } else {
9441
0
            opCode = spv::Op::OpGroupNonUniformSMax;
9442
0
        }
9443
0
        break;
9444
0
    case glslang::EOpSubgroupAnd:
9445
0
    case glslang::EOpSubgroupInclusiveAnd:
9446
0
    case glslang::EOpSubgroupExclusiveAnd:
9447
0
    case glslang::EOpSubgroupClusteredAnd:
9448
0
    case glslang::EOpSubgroupPartitionedAnd:
9449
0
    case glslang::EOpSubgroupPartitionedInclusiveAnd:
9450
0
    case glslang::EOpSubgroupPartitionedExclusiveAnd:
9451
0
        if (isBool) {
9452
0
            opCode = spv::Op::OpGroupNonUniformLogicalAnd;
9453
0
        } else {
9454
0
            opCode = spv::Op::OpGroupNonUniformBitwiseAnd;
9455
0
        }
9456
0
        break;
9457
0
    case glslang::EOpSubgroupOr:
9458
0
    case glslang::EOpSubgroupInclusiveOr:
9459
0
    case glslang::EOpSubgroupExclusiveOr:
9460
0
    case glslang::EOpSubgroupClusteredOr:
9461
0
    case glslang::EOpSubgroupPartitionedOr:
9462
0
    case glslang::EOpSubgroupPartitionedInclusiveOr:
9463
0
    case glslang::EOpSubgroupPartitionedExclusiveOr:
9464
0
        if (isBool) {
9465
0
            opCode = spv::Op::OpGroupNonUniformLogicalOr;
9466
0
        } else {
9467
0
            opCode = spv::Op::OpGroupNonUniformBitwiseOr;
9468
0
        }
9469
0
        break;
9470
0
    case glslang::EOpSubgroupXor:
9471
0
    case glslang::EOpSubgroupInclusiveXor:
9472
0
    case glslang::EOpSubgroupExclusiveXor:
9473
0
    case glslang::EOpSubgroupClusteredXor:
9474
0
    case glslang::EOpSubgroupPartitionedXor:
9475
0
    case glslang::EOpSubgroupPartitionedInclusiveXor:
9476
0
    case glslang::EOpSubgroupPartitionedExclusiveXor:
9477
0
        if (isBool) {
9478
0
            opCode = spv::Op::OpGroupNonUniformLogicalXor;
9479
0
        } else {
9480
0
            opCode = spv::Op::OpGroupNonUniformBitwiseXor;
9481
0
        }
9482
0
        break;
9483
0
    case glslang::EOpSubgroupQuadBroadcast:      opCode = spv::Op::OpGroupNonUniformQuadBroadcast; break;
9484
0
    case glslang::EOpSubgroupQuadSwapHorizontal:
9485
0
    case glslang::EOpSubgroupQuadSwapVertical:
9486
0
    case glslang::EOpSubgroupQuadSwapDiagonal:   opCode = spv::Op::OpGroupNonUniformQuadSwap; break;
9487
0
    default: assert(0 && "Unhandled subgroup operation!");
9488
0
    }
9489
9490
    // get the right Group Operation
9491
0
    spv::GroupOperation groupOperation = spv::GroupOperation::Max;
9492
0
    switch (op) {
9493
0
    default:
9494
0
        break;
9495
0
    case glslang::EOpSubgroupBallotBitCount:
9496
0
    case glslang::EOpSubgroupAdd:
9497
0
    case glslang::EOpSubgroupMul:
9498
0
    case glslang::EOpSubgroupMin:
9499
0
    case glslang::EOpSubgroupMax:
9500
0
    case glslang::EOpSubgroupAnd:
9501
0
    case glslang::EOpSubgroupOr:
9502
0
    case glslang::EOpSubgroupXor:
9503
0
        groupOperation = spv::GroupOperation::Reduce;
9504
0
        break;
9505
0
    case glslang::EOpSubgroupBallotInclusiveBitCount:
9506
0
    case glslang::EOpSubgroupInclusiveAdd:
9507
0
    case glslang::EOpSubgroupInclusiveMul:
9508
0
    case glslang::EOpSubgroupInclusiveMin:
9509
0
    case glslang::EOpSubgroupInclusiveMax:
9510
0
    case glslang::EOpSubgroupInclusiveAnd:
9511
0
    case glslang::EOpSubgroupInclusiveOr:
9512
0
    case glslang::EOpSubgroupInclusiveXor:
9513
0
        groupOperation = spv::GroupOperation::InclusiveScan;
9514
0
        break;
9515
0
    case glslang::EOpSubgroupBallotExclusiveBitCount:
9516
0
    case glslang::EOpSubgroupExclusiveAdd:
9517
0
    case glslang::EOpSubgroupExclusiveMul:
9518
0
    case glslang::EOpSubgroupExclusiveMin:
9519
0
    case glslang::EOpSubgroupExclusiveMax:
9520
0
    case glslang::EOpSubgroupExclusiveAnd:
9521
0
    case glslang::EOpSubgroupExclusiveOr:
9522
0
    case glslang::EOpSubgroupExclusiveXor:
9523
0
        groupOperation = spv::GroupOperation::ExclusiveScan;
9524
0
        break;
9525
0
    case glslang::EOpSubgroupClusteredAdd:
9526
0
    case glslang::EOpSubgroupClusteredMul:
9527
0
    case glslang::EOpSubgroupClusteredMin:
9528
0
    case glslang::EOpSubgroupClusteredMax:
9529
0
    case glslang::EOpSubgroupClusteredAnd:
9530
0
    case glslang::EOpSubgroupClusteredOr:
9531
0
    case glslang::EOpSubgroupClusteredXor:
9532
0
        groupOperation = spv::GroupOperation::ClusteredReduce;
9533
0
        break;
9534
0
    case glslang::EOpSubgroupPartitionedAdd:
9535
0
    case glslang::EOpSubgroupPartitionedMul:
9536
0
    case glslang::EOpSubgroupPartitionedMin:
9537
0
    case glslang::EOpSubgroupPartitionedMax:
9538
0
    case glslang::EOpSubgroupPartitionedAnd:
9539
0
    case glslang::EOpSubgroupPartitionedOr:
9540
0
    case glslang::EOpSubgroupPartitionedXor:
9541
0
        groupOperation = spv::GroupOperation::PartitionedReduceNV;
9542
0
        break;
9543
0
    case glslang::EOpSubgroupPartitionedInclusiveAdd:
9544
0
    case glslang::EOpSubgroupPartitionedInclusiveMul:
9545
0
    case glslang::EOpSubgroupPartitionedInclusiveMin:
9546
0
    case glslang::EOpSubgroupPartitionedInclusiveMax:
9547
0
    case glslang::EOpSubgroupPartitionedInclusiveAnd:
9548
0
    case glslang::EOpSubgroupPartitionedInclusiveOr:
9549
0
    case glslang::EOpSubgroupPartitionedInclusiveXor:
9550
0
        groupOperation = spv::GroupOperation::PartitionedInclusiveScanNV;
9551
0
        break;
9552
0
    case glslang::EOpSubgroupPartitionedExclusiveAdd:
9553
0
    case glslang::EOpSubgroupPartitionedExclusiveMul:
9554
0
    case glslang::EOpSubgroupPartitionedExclusiveMin:
9555
0
    case glslang::EOpSubgroupPartitionedExclusiveMax:
9556
0
    case glslang::EOpSubgroupPartitionedExclusiveAnd:
9557
0
    case glslang::EOpSubgroupPartitionedExclusiveOr:
9558
0
    case glslang::EOpSubgroupPartitionedExclusiveXor:
9559
0
        groupOperation = spv::GroupOperation::PartitionedExclusiveScanNV;
9560
0
        break;
9561
0
    }
9562
9563
    // build the instruction
9564
0
    std::vector<spv::IdImmediate> spvGroupOperands;
9565
9566
    // Every operation begins with the Execution Scope operand.
9567
0
    spv::IdImmediate executionScope = { true, builder.makeUintConstant(spv::Scope::Subgroup) };
9568
    // All other ops need the execution scope. Quad Control Ops don't need scope, it's always Quad.
9569
0
    if (opCode != spv::Op::OpGroupNonUniformQuadAllKHR && opCode != spv::Op::OpGroupNonUniformQuadAnyKHR) {
9570
0
        spvGroupOperands.push_back(executionScope);
9571
0
    }
9572
9573
    // Next, for all operations that use a Group Operation, push that as an operand.
9574
0
    if (groupOperation != spv::GroupOperation::Max) {
9575
0
        spv::IdImmediate groupOperand = { false, (unsigned)groupOperation };
9576
0
        spvGroupOperands.push_back(groupOperand);
9577
0
    }
9578
9579
    // Push back the operands next.
9580
0
    for (auto opIt = operands.cbegin(); opIt != operands.cend(); ++opIt) {
9581
0
        spv::IdImmediate operand = { true, *opIt };
9582
0
        spvGroupOperands.push_back(operand);
9583
0
    }
9584
9585
    // Some opcodes have additional operands.
9586
0
    spv::Id directionId = spv::NoResult;
9587
0
    switch (op) {
9588
0
    default: break;
9589
0
    case glslang::EOpSubgroupQuadSwapHorizontal: directionId = builder.makeUintConstant(0); break;
9590
0
    case glslang::EOpSubgroupQuadSwapVertical:   directionId = builder.makeUintConstant(1); break;
9591
0
    case glslang::EOpSubgroupQuadSwapDiagonal:   directionId = builder.makeUintConstant(2); break;
9592
0
    }
9593
0
    if (directionId != spv::NoResult) {
9594
0
        spv::IdImmediate direction = { true, directionId };
9595
0
        spvGroupOperands.push_back(direction);
9596
0
    }
9597
9598
0
    return builder.createOp(opCode, typeId, spvGroupOperands);
9599
0
}
9600
9601
spv::Id TGlslangToSpvTraverser::createMiscOperation(glslang::TOperator op, spv::Decoration precision,
9602
    spv::Id typeId, std::vector<spv::Id>& operands, glslang::TBasicType typeProxy)
9603
4.87k
{
9604
4.87k
    bool isUnsigned = isTypeUnsignedInt(typeProxy);
9605
4.87k
    bool isFloat = isTypeFloat(typeProxy);
9606
9607
4.87k
    spv::Op opCode = spv::Op::OpNop;
9608
4.87k
    int extBuiltins = -1;
9609
4.87k
    int libCall = -1;
9610
4.87k
    size_t consumedOperands = operands.size();
9611
4.87k
    spv::Id typeId0 = 0;
9612
4.87k
    if (consumedOperands > 0)
9613
4.87k
        typeId0 = builder.getTypeId(operands[0]);
9614
4.87k
    spv::Id typeId1 = 0;
9615
4.87k
    if (consumedOperands > 1)
9616
4.87k
        typeId1 = builder.getTypeId(operands[1]);
9617
4.87k
    spv::Id frexpIntType = 0;
9618
9619
4.87k
    switch (op) {
9620
36
    case glslang::EOpMin:
9621
36
        if (isFloat)
9622
0
            libCall = nanMinMaxClamp ? spv::GLSLstd450NMin : spv::GLSLstd450FMin;
9623
36
        else if (isUnsigned)
9624
18
            libCall = spv::GLSLstd450UMin;
9625
18
        else
9626
18
            libCall = spv::GLSLstd450SMin;
9627
36
        builder.promoteScalar(precision, operands.front(), operands.back());
9628
36
        break;
9629
0
    case glslang::EOpModf:
9630
0
        {
9631
0
            libCall = spv::GLSLstd450ModfStruct;
9632
0
            assert(builder.isFloatType(builder.getScalarTypeId(typeId0)));
9633
            // The returned struct has two members of the same type as the first argument
9634
0
            typeId = builder.makeStructResultType(typeId0, typeId0);
9635
0
            consumedOperands = 1;
9636
0
        }
9637
0
        break;
9638
404
    case glslang::EOpMax:
9639
404
        if (isFloat)
9640
368
            libCall = nanMinMaxClamp ? spv::GLSLstd450NMax : spv::GLSLstd450FMax;
9641
36
        else if (isUnsigned)
9642
18
            libCall = spv::GLSLstd450UMax;
9643
18
        else
9644
18
            libCall = spv::GLSLstd450SMax;
9645
404
        builder.promoteScalar(precision, operands.front(), operands.back());
9646
404
        break;
9647
184
    case glslang::EOpPow:
9648
184
        libCall = spv::GLSLstd450Pow;
9649
184
        break;
9650
1.47k
    case glslang::EOpDot:
9651
1.54k
    case glslang::EOpDotPackedEXT:
9652
2.46k
    case glslang::EOpDotAccSatEXT:
9653
2.54k
    case glslang::EOpDotPackedAccSatEXT:
9654
2.54k
        {
9655
2.54k
            if (builder.isFloatType(builder.getScalarTypeId(typeId0)) ||
9656
                // HLSL supports dot(int,int) which is just a multiply
9657
1.99k
                glslangIntermediate->getSource() == glslang::EShSourceHlsl) {
9658
552
                if (typeProxy == glslang::EbtBFloat16) {
9659
0
                    builder.addExtension(spv::E_SPV_KHR_bfloat16);
9660
0
                    builder.addCapability(spv::Capability::BFloat16DotProductKHR);
9661
0
                }
9662
552
                opCode = spv::Op::OpDot;
9663
1.99k
            } else {
9664
1.99k
                builder.addExtension(spv::E_SPV_KHR_integer_dot_product);
9665
1.99k
                builder.addCapability(spv::Capability::DotProductKHR);
9666
1.99k
                const unsigned int vectorSize = builder.getNumComponents(operands[0]);
9667
1.99k
                if (op == glslang::EOpDotPackedEXT || op == glslang::EOpDotPackedAccSatEXT) {
9668
157
                    builder.addCapability(spv::Capability::DotProductInput4x8BitPackedKHR);
9669
1.83k
                } else if (vectorSize == 4 && builder.getScalarTypeWidth(typeId0) == 8) {
9670
160
                    builder.addCapability(spv::Capability::DotProductInput4x8BitKHR);
9671
1.67k
                } else {
9672
1.67k
                    builder.addCapability(spv::Capability::DotProductInputAllKHR);
9673
1.67k
                }
9674
1.99k
                const bool type0isSigned = builder.isIntType(builder.getScalarTypeId(typeId0));
9675
1.99k
                const bool type1isSigned = builder.isIntType(builder.getScalarTypeId(typeId1));
9676
1.99k
                const bool accSat = (op == glslang::EOpDotAccSatEXT || op == glslang::EOpDotPackedAccSatEXT);
9677
1.99k
                if (!type0isSigned && !type1isSigned) {
9678
501
                    opCode = accSat ? spv::Op::OpUDotAccSatKHR : spv::Op::OpUDotKHR;
9679
1.49k
                } else if (type0isSigned && type1isSigned) {
9680
495
                    opCode = accSat ? spv::Op::OpSDotAccSatKHR : spv::Op::OpSDotKHR;
9681
1.00k
                } else {
9682
1.00k
                    opCode = accSat ? spv::Op::OpSUDotAccSatKHR : spv::Op::OpSUDotKHR;
9683
                    // the spir-v opcode assumes the operands to be "signed, unsigned" in that order, so swap if needed
9684
1.00k
                    if (type1isSigned) {
9685
500
                        std::swap(operands[0], operands[1]);
9686
500
                    }
9687
1.00k
                }
9688
1.99k
                std::vector<spv::IdImmediate> operands2;
9689
4.99k
                for (auto &o : operands) {
9690
4.99k
                    operands2.push_back({true, o});
9691
4.99k
                }
9692
1.99k
                if (op == glslang::EOpDotPackedEXT || op == glslang::EOpDotPackedAccSatEXT) {
9693
157
                    operands2.push_back({false, 0});
9694
157
                }
9695
1.99k
                return builder.createOp(opCode, typeId, operands2);
9696
1.99k
            }
9697
2.54k
        }
9698
552
        break;
9699
552
    case glslang::EOpAtan:
9700
0
        libCall = spv::GLSLstd450Atan2;
9701
0
        break;
9702
9703
36
    case glslang::EOpClamp:
9704
36
        if (isFloat)
9705
0
            libCall = nanMinMaxClamp ? spv::GLSLstd450NClamp : spv::GLSLstd450FClamp;
9706
36
        else if (isUnsigned)
9707
18
            libCall = spv::GLSLstd450UClamp;
9708
18
        else
9709
18
            libCall = spv::GLSLstd450SClamp;
9710
36
        builder.promoteScalar(precision, operands.front(), operands[1]);
9711
36
        builder.promoteScalar(precision, operands.front(), operands[2]);
9712
36
        break;
9713
36
    case glslang::EOpMix:
9714
36
        if (! builder.isBoolType(builder.getScalarTypeId(builder.getTypeId(operands.back())))) {
9715
0
            assert(isFloat);
9716
0
            libCall = spv::GLSLstd450FMix;
9717
36
        } else {
9718
36
            opCode = spv::Op::OpSelect;
9719
36
            std::swap(operands.front(), operands.back());
9720
36
        }
9721
36
        builder.promoteScalar(precision, operands.front(), operands.back());
9722
36
        break;
9723
0
    case glslang::EOpStep:
9724
0
        libCall = spv::GLSLstd450Step;
9725
0
        builder.promoteScalar(precision, operands.front(), operands.back());
9726
0
        break;
9727
368
    case glslang::EOpSmoothStep:
9728
368
        libCall = spv::GLSLstd450SmoothStep;
9729
368
        builder.promoteScalar(precision, operands[0], operands[2]);
9730
368
        builder.promoteScalar(precision, operands[1], operands[2]);
9731
368
        break;
9732
9733
0
    case glslang::EOpDistance:
9734
0
        libCall = spv::GLSLstd450Distance;
9735
0
        break;
9736
0
    case glslang::EOpCross:
9737
0
        libCall = spv::GLSLstd450Cross;
9738
0
        break;
9739
0
    case glslang::EOpFaceForward:
9740
0
        libCall = spv::GLSLstd450FaceForward;
9741
0
        break;
9742
184
    case glslang::EOpReflect:
9743
184
        libCall = spv::GLSLstd450Reflect;
9744
184
        break;
9745
0
    case glslang::EOpRefract:
9746
0
        libCall = spv::GLSLstd450Refract;
9747
0
        break;
9748
0
    case glslang::EOpBarrier:
9749
0
        {
9750
            // This is for the extended controlBarrier function, with four operands.
9751
            // The unextended barrier() goes through createNoArgOperation.
9752
0
            assert(operands.size() == 4);
9753
0
            auto const executionScope = (spv::Scope)builder.getConstantScalar(operands[0]);
9754
0
            auto const memoryScope = (spv::Scope)builder.getConstantScalar(operands[1]);
9755
0
            auto const semantics = (spv::MemorySemanticsMask)(builder.getConstantScalar(operands[2]) | builder.getConstantScalar(operands[3]));
9756
0
            builder.createControlBarrier(executionScope, memoryScope,
9757
0
                semantics);
9758
0
            if (anySet(semantics, spv::MemorySemanticsMask::MakeAvailableKHR |
9759
0
                                  spv::MemorySemanticsMask::MakeVisibleKHR |
9760
0
                                  spv::MemorySemanticsMask::OutputMemoryKHR |
9761
0
                                  spv::MemorySemanticsMask::Volatile)) {
9762
0
                builder.addCapability(spv::Capability::VulkanMemoryModelKHR);
9763
0
            }
9764
0
            if (glslangIntermediate->usingVulkanMemoryModel() && (executionScope == spv::Scope::Device ||
9765
0
                memoryScope == spv::Scope::Device)) {
9766
0
                builder.addCapability(spv::Capability::VulkanMemoryModelDeviceScopeKHR);
9767
0
            }
9768
0
            return 0;
9769
2.54k
        }
9770
0
        break;
9771
0
    case glslang::EOpMemoryBarrier:
9772
0
        {
9773
            // This is for the extended memoryBarrier function, with three operands.
9774
            // The unextended memoryBarrier() goes through createNoArgOperation.
9775
0
            assert(operands.size() == 3);
9776
0
            auto const memoryScope = (spv::Scope)builder.getConstantScalar(operands[0]);
9777
0
            auto const semantics = (spv::MemorySemanticsMask)(builder.getConstantScalar(operands[1]) | builder.getConstantScalar(operands[2]));
9778
0
            builder.createMemoryBarrier(memoryScope, semantics);
9779
0
            if (anySet(semantics, spv::MemorySemanticsMask::MakeAvailableKHR |
9780
0
                                  spv::MemorySemanticsMask::MakeVisibleKHR |
9781
0
                                  spv::MemorySemanticsMask::OutputMemoryKHR |
9782
0
                                  spv::MemorySemanticsMask::Volatile)) {
9783
0
                builder.addCapability(spv::Capability::VulkanMemoryModelKHR);
9784
0
            }
9785
0
            if (glslangIntermediate->usingVulkanMemoryModel() && memoryScope == spv::Scope::Device) {
9786
0
                builder.addCapability(spv::Capability::VulkanMemoryModelDeviceScopeKHR);
9787
0
            }
9788
0
            return 0;
9789
2.54k
        }
9790
0
        break;
9791
9792
0
    case glslang::EOpInterpolateAtSample:
9793
0
        if (typeProxy == glslang::EbtFloat16)
9794
0
            builder.addExtension(spv::E_SPV_AMD_gpu_shader_half_float);
9795
0
        libCall = spv::GLSLstd450InterpolateAtSample;
9796
0
        break;
9797
0
    case glslang::EOpInterpolateAtOffset:
9798
0
        if (typeProxy == glslang::EbtFloat16)
9799
0
            builder.addExtension(spv::E_SPV_AMD_gpu_shader_half_float);
9800
0
        libCall = spv::GLSLstd450InterpolateAtOffset;
9801
0
        break;
9802
0
    case glslang::EOpAddCarry:
9803
0
        opCode = spv::Op::OpIAddCarry;
9804
0
        typeId = builder.makeStructResultType(typeId0, typeId0);
9805
0
        consumedOperands = 2;
9806
0
        break;
9807
0
    case glslang::EOpSubBorrow:
9808
0
        opCode = spv::Op::OpISubBorrow;
9809
0
        typeId = builder.makeStructResultType(typeId0, typeId0);
9810
0
        consumedOperands = 2;
9811
0
        break;
9812
0
    case glslang::EOpUMulExtended:
9813
0
        opCode = spv::Op::OpUMulExtended;
9814
0
        typeId = builder.makeStructResultType(typeId0, typeId0);
9815
0
        consumedOperands = 2;
9816
0
        break;
9817
0
    case glslang::EOpIMulExtended:
9818
0
        opCode = spv::Op::OpSMulExtended;
9819
0
        typeId = builder.makeStructResultType(typeId0, typeId0);
9820
0
        consumedOperands = 2;
9821
0
        break;
9822
0
    case glslang::EOpBitfieldExtract:
9823
0
        if (isUnsigned)
9824
0
            opCode = spv::Op::OpBitFieldUExtract;
9825
0
        else
9826
0
            opCode = spv::Op::OpBitFieldSExtract;
9827
0
        break;
9828
0
    case glslang::EOpBitfieldInsert:
9829
0
        opCode = spv::Op::OpBitFieldInsert;
9830
0
        break;
9831
9832
0
    case glslang::EOpFma:
9833
0
        libCall = spv::GLSLstd450Fma;
9834
0
        break;
9835
9
    case glslang::EOpFrexp:
9836
9
        {
9837
9
            libCall = spv::GLSLstd450FrexpStruct;
9838
9
            assert(builder.isPointerType(typeId1));
9839
9
            typeId1 = builder.getContainedTypeId(typeId1);
9840
9
            int width = builder.getScalarTypeWidth(typeId1);
9841
9
            if (width == 16)
9842
                // Using 16-bit exp operand, enable extension SPV_AMD_gpu_shader_int16
9843
9
                builder.addExtension(spv::E_SPV_AMD_gpu_shader_int16);
9844
9
            if (builder.getNumComponents(operands[0]) == 1)
9845
0
                frexpIntType = builder.makeIntegerType(width, true);
9846
9
            else
9847
9
                frexpIntType = builder.makeVectorType(builder.makeIntegerType(width, true),
9848
9
                    builder.getNumComponents(operands[0]));
9849
9
            typeId = builder.makeStructResultType(typeId0, frexpIntType);
9850
9
            consumedOperands = 1;
9851
9
        }
9852
9
        break;
9853
9
    case glslang::EOpLdexp:
9854
9
        libCall = spv::GLSLstd450Ldexp;
9855
9
        break;
9856
9857
0
    case glslang::EOpReadInvocation:
9858
0
        return createInvocationsOperation(op, typeId, operands, typeProxy);
9859
9860
0
    case glslang::EOpSubgroupBroadcast:
9861
0
    case glslang::EOpSubgroupBallotBitExtract:
9862
0
    case glslang::EOpSubgroupShuffle:
9863
0
    case glslang::EOpSubgroupShuffleXor:
9864
0
    case glslang::EOpSubgroupShuffleUp:
9865
0
    case glslang::EOpSubgroupShuffleDown:
9866
0
    case glslang::EOpSubgroupRotate:
9867
0
    case glslang::EOpSubgroupClusteredRotate:
9868
0
    case glslang::EOpSubgroupClusteredAdd:
9869
0
    case glslang::EOpSubgroupClusteredMul:
9870
0
    case glslang::EOpSubgroupClusteredMin:
9871
0
    case glslang::EOpSubgroupClusteredMax:
9872
0
    case glslang::EOpSubgroupClusteredAnd:
9873
0
    case glslang::EOpSubgroupClusteredOr:
9874
0
    case glslang::EOpSubgroupClusteredXor:
9875
0
    case glslang::EOpSubgroupQuadBroadcast:
9876
0
    case glslang::EOpSubgroupPartitionedAdd:
9877
0
    case glslang::EOpSubgroupPartitionedMul:
9878
0
    case glslang::EOpSubgroupPartitionedMin:
9879
0
    case glslang::EOpSubgroupPartitionedMax:
9880
0
    case glslang::EOpSubgroupPartitionedAnd:
9881
0
    case glslang::EOpSubgroupPartitionedOr:
9882
0
    case glslang::EOpSubgroupPartitionedXor:
9883
0
    case glslang::EOpSubgroupPartitionedInclusiveAdd:
9884
0
    case glslang::EOpSubgroupPartitionedInclusiveMul:
9885
0
    case glslang::EOpSubgroupPartitionedInclusiveMin:
9886
0
    case glslang::EOpSubgroupPartitionedInclusiveMax:
9887
0
    case glslang::EOpSubgroupPartitionedInclusiveAnd:
9888
0
    case glslang::EOpSubgroupPartitionedInclusiveOr:
9889
0
    case glslang::EOpSubgroupPartitionedInclusiveXor:
9890
0
    case glslang::EOpSubgroupPartitionedExclusiveAdd:
9891
0
    case glslang::EOpSubgroupPartitionedExclusiveMul:
9892
0
    case glslang::EOpSubgroupPartitionedExclusiveMin:
9893
0
    case glslang::EOpSubgroupPartitionedExclusiveMax:
9894
0
    case glslang::EOpSubgroupPartitionedExclusiveAnd:
9895
0
    case glslang::EOpSubgroupPartitionedExclusiveOr:
9896
0
    case glslang::EOpSubgroupPartitionedExclusiveXor:
9897
0
        return createSubgroupOperation(op, typeId, operands, typeProxy);
9898
9899
0
    case glslang::EOpSwizzleInvocations:
9900
0
        extBuiltins = getExtBuiltins(spv::E_SPV_AMD_shader_ballot);
9901
0
        libCall = spv::SwizzleInvocationsAMD;
9902
0
        break;
9903
0
    case glslang::EOpSwizzleInvocationsMasked:
9904
0
        extBuiltins = getExtBuiltins(spv::E_SPV_AMD_shader_ballot);
9905
0
        libCall = spv::SwizzleInvocationsMaskedAMD;
9906
0
        break;
9907
0
    case glslang::EOpWriteInvocation:
9908
0
        extBuiltins = getExtBuiltins(spv::E_SPV_AMD_shader_ballot);
9909
0
        libCall = spv::WriteInvocationAMD;
9910
0
        break;
9911
9912
0
    case glslang::EOpMin3:
9913
0
        extBuiltins = getExtBuiltins(spv::E_SPV_AMD_shader_trinary_minmax);
9914
0
        if (isFloat)
9915
0
            libCall = spv::FMin3AMD;
9916
0
        else {
9917
0
            if (isUnsigned)
9918
0
                libCall = spv::UMin3AMD;
9919
0
            else
9920
0
                libCall = spv::SMin3AMD;
9921
0
        }
9922
0
        break;
9923
0
    case glslang::EOpMax3:
9924
0
        extBuiltins = getExtBuiltins(spv::E_SPV_AMD_shader_trinary_minmax);
9925
0
        if (isFloat)
9926
0
            libCall = spv::FMax3AMD;
9927
0
        else {
9928
0
            if (isUnsigned)
9929
0
                libCall = spv::UMax3AMD;
9930
0
            else
9931
0
                libCall = spv::SMax3AMD;
9932
0
        }
9933
0
        break;
9934
0
    case glslang::EOpMid3:
9935
0
        extBuiltins = getExtBuiltins(spv::E_SPV_AMD_shader_trinary_minmax);
9936
0
        if (isFloat)
9937
0
            libCall = spv::FMid3AMD;
9938
0
        else {
9939
0
            if (isUnsigned)
9940
0
                libCall = spv::UMid3AMD;
9941
0
            else
9942
0
                libCall = spv::SMid3AMD;
9943
0
        }
9944
0
        break;
9945
9946
0
    case glslang::EOpInterpolateAtVertex:
9947
0
        if (typeProxy == glslang::EbtFloat16)
9948
0
            builder.addExtension(spv::E_SPV_AMD_gpu_shader_half_float);
9949
0
        extBuiltins = getExtBuiltins(spv::E_SPV_AMD_shader_explicit_vertex_parameter);
9950
0
        libCall = spv::InterpolateAtVertexAMD;
9951
0
        break;
9952
9953
0
    case glslang::EOpReportIntersection:
9954
0
        typeId = builder.makeBoolType();
9955
0
        opCode = spv::Op::OpReportIntersectionKHR;
9956
0
        break;
9957
0
    case glslang::EOpTraceNV:
9958
0
        builder.createNoResultOp(spv::Op::OpTraceNV, operands);
9959
0
        return 0;
9960
0
    case glslang::EOpTraceRayMotionNV:
9961
0
        builder.addExtension(spv::E_SPV_NV_ray_tracing_motion_blur);
9962
0
        builder.addCapability(spv::Capability::RayTracingMotionBlurNV);
9963
0
        builder.createNoResultOp(spv::Op::OpTraceRayMotionNV, operands);
9964
0
        return 0;
9965
0
    case glslang::EOpTraceKHR:
9966
0
        builder.createNoResultOp(spv::Op::OpTraceRayKHR, operands);
9967
0
        return 0;
9968
0
    case glslang::EOpExecuteCallableNV:
9969
0
        builder.createNoResultOp(spv::Op::OpExecuteCallableNV, operands);
9970
0
        return 0;
9971
0
    case glslang::EOpExecuteCallableKHR:
9972
0
        builder.createNoResultOp(spv::Op::OpExecuteCallableKHR, operands);
9973
0
        return 0;
9974
9975
31
    case glslang::EOpRayQueryInitialize:
9976
31
        builder.createNoResultOp(spv::Op::OpRayQueryInitializeKHR, operands);
9977
31
        return 0;
9978
0
    case glslang::EOpRayQueryTerminate:
9979
0
        builder.createNoResultOp(spv::Op::OpRayQueryTerminateKHR, operands);
9980
0
        return 0;
9981
31
    case glslang::EOpRayQueryGenerateIntersection:
9982
31
        builder.createNoResultOp(spv::Op::OpRayQueryGenerateIntersectionKHR, operands);
9983
31
        return 0;
9984
0
    case glslang::EOpRayQueryConfirmIntersection:
9985
0
        builder.createNoResultOp(spv::Op::OpRayQueryConfirmIntersectionKHR, operands);
9986
0
        return 0;
9987
0
    case glslang::EOpRayQueryProceed:
9988
0
        typeId = builder.makeBoolType();
9989
0
        opCode = spv::Op::OpRayQueryProceedKHR;
9990
0
        break;
9991
62
    case glslang::EOpRayQueryGetIntersectionType:
9992
62
        typeId = builder.makeUintType(32);
9993
62
        opCode = spv::Op::OpRayQueryGetIntersectionTypeKHR;
9994
62
        break;
9995
0
    case glslang::EOpRayQueryGetRayTMin:
9996
0
        typeId = builder.makeFloatType(32);
9997
0
        opCode = spv::Op::OpRayQueryGetRayTMinKHR;
9998
0
        break;
9999
0
    case glslang::EOpRayQueryGetRayFlags:
10000
0
        typeId = builder.makeIntType(32);
10001
0
        opCode = spv::Op::OpRayQueryGetRayFlagsKHR;
10002
0
        break;
10003
62
    case glslang::EOpRayQueryGetIntersectionT:
10004
62
        typeId = builder.makeFloatType(32);
10005
62
        opCode = spv::Op::OpRayQueryGetIntersectionTKHR;
10006
62
        break;
10007
62
    case glslang::EOpRayQueryGetIntersectionInstanceCustomIndex:
10008
62
        typeId = builder.makeIntType(32);
10009
62
        opCode = spv::Op::OpRayQueryGetIntersectionInstanceCustomIndexKHR;
10010
62
        break;
10011
62
    case glslang::EOpRayQueryGetIntersectionInstanceId:
10012
62
        typeId = builder.makeIntType(32);
10013
62
        opCode = spv::Op::OpRayQueryGetIntersectionInstanceIdKHR;
10014
62
        break;
10015
31
    case glslang::EOpRayQueryGetIntersectionInstanceShaderBindingTableRecordOffset:
10016
31
        typeId = builder.makeUintType(32);
10017
31
        opCode = spv::Op::OpRayQueryGetIntersectionInstanceShaderBindingTableRecordOffsetKHR;
10018
31
        break;
10019
31
    case glslang::EOpRayQueryGetIntersectionGeometryIndex:
10020
31
        typeId = builder.makeIntType(32);
10021
31
        opCode = spv::Op::OpRayQueryGetIntersectionGeometryIndexKHR;
10022
31
        break;
10023
62
    case glslang::EOpRayQueryGetIntersectionPrimitiveIndex:
10024
62
        typeId = builder.makeIntType(32);
10025
62
        opCode = spv::Op::OpRayQueryGetIntersectionPrimitiveIndexKHR;
10026
62
        break;
10027
62
    case glslang::EOpRayQueryGetIntersectionBarycentrics:
10028
62
        typeId = builder.makeVectorType(builder.makeFloatType(32), 2);
10029
62
        opCode = spv::Op::OpRayQueryGetIntersectionBarycentricsKHR;
10030
62
        break;
10031
62
    case glslang::EOpRayQueryGetIntersectionFrontFace:
10032
62
        typeId = builder.makeBoolType();
10033
62
        opCode = spv::Op::OpRayQueryGetIntersectionFrontFaceKHR;
10034
62
        break;
10035
0
    case glslang::EOpRayQueryGetIntersectionCandidateAABBOpaque:
10036
0
        typeId = builder.makeBoolType();
10037
0
        opCode = spv::Op::OpRayQueryGetIntersectionCandidateAABBOpaqueKHR;
10038
0
        break;
10039
62
    case glslang::EOpRayQueryGetIntersectionObjectRayDirection:
10040
62
        typeId = builder.makeVectorType(builder.makeFloatType(32), 3);
10041
62
        opCode = spv::Op::OpRayQueryGetIntersectionObjectRayDirectionKHR;
10042
62
        break;
10043
62
    case glslang::EOpRayQueryGetIntersectionObjectRayOrigin:
10044
62
        typeId = builder.makeVectorType(builder.makeFloatType(32), 3);
10045
62
        opCode = spv::Op::OpRayQueryGetIntersectionObjectRayOriginKHR;
10046
62
        break;
10047
0
    case glslang::EOpRayQueryGetWorldRayDirection:
10048
0
        typeId = builder.makeVectorType(builder.makeFloatType(32), 3);
10049
0
        opCode = spv::Op::OpRayQueryGetWorldRayDirectionKHR;
10050
0
        break;
10051
0
    case glslang::EOpRayQueryGetWorldRayOrigin:
10052
0
        typeId = builder.makeVectorType(builder.makeFloatType(32), 3);
10053
0
        opCode = spv::Op::OpRayQueryGetWorldRayOriginKHR;
10054
0
        break;
10055
62
    case glslang::EOpRayQueryGetIntersectionObjectToWorld:
10056
62
        typeId = builder.makeMatrixType(builder.makeFloatType(32), 4, 3);
10057
62
        opCode = spv::Op::OpRayQueryGetIntersectionObjectToWorldKHR;
10058
62
        break;
10059
20
    case glslang::EOpRayQueryGetIntersectionClusterIdNV:
10060
20
        typeId = builder.makeIntegerType(32, 1);
10061
20
        opCode = spv::Op::OpRayQueryGetClusterIdNV;
10062
20
        break;
10063
62
    case glslang::EOpRayQueryGetIntersectionWorldToObject:
10064
62
        typeId = builder.makeMatrixType(builder.makeFloatType(32), 4, 3);
10065
62
        opCode = spv::Op::OpRayQueryGetIntersectionWorldToObjectKHR;
10066
62
        break;
10067
0
    case glslang::EOpRayQueryGetIntersectionSpherePositionNV:
10068
0
        typeId = builder.makeVectorType(builder.makeFloatType(32), 3);
10069
0
        opCode = spv::Op::OpRayQueryGetIntersectionSpherePositionNV;
10070
0
        break;
10071
0
    case glslang::EOpRayQueryGetIntersectionSphereRadiusNV:
10072
0
        typeId = builder.makeFloatType(32);
10073
0
        opCode = spv::Op::OpRayQueryGetIntersectionSphereRadiusNV;
10074
0
        break;
10075
0
    case glslang::EOpRayQueryGetIntersectionLSSHitValueNV:
10076
0
        typeId = builder.makeFloatType(32);
10077
0
        opCode = spv::Op::OpRayQueryGetIntersectionLSSHitValueNV;
10078
0
        break;
10079
0
    case glslang::EOpRayQueryIsSphereHitNV:
10080
0
        typeId = builder.makeBoolType();
10081
0
        opCode = spv::Op::OpRayQueryIsSphereHitNV;
10082
0
        break;
10083
0
    case glslang::EOpRayQueryIsLSSHitNV:
10084
0
        typeId = builder.makeBoolType();
10085
0
        opCode = spv::Op::OpRayQueryIsLSSHitNV;
10086
0
        break;
10087
0
    case glslang::EOpWritePackedPrimitiveIndices4x8NV:
10088
0
        builder.createNoResultOp(spv::Op::OpWritePackedPrimitiveIndices4x8NV, operands);
10089
0
        return 0;
10090
0
    case glslang::EOpEmitMeshTasksEXT:
10091
0
        if (taskPayloadID)
10092
0
            operands.push_back(taskPayloadID);
10093
        // As per SPV_EXT_mesh_shader make it a terminating instruction in the current block
10094
0
        builder.makeStatementTerminator(spv::Op::OpEmitMeshTasksEXT, operands, "post-OpEmitMeshTasksEXT");
10095
0
        return 0;
10096
0
    case glslang::EOpSetMeshOutputsEXT:
10097
0
        builder.createNoResultOp(spv::Op::OpSetMeshOutputsEXT, operands);
10098
0
        return 0;
10099
0
    case glslang::EOpCooperativeMatrixMulAddNV:
10100
0
        opCode = spv::Op::OpCooperativeMatrixMulAddNV;
10101
0
        break;
10102
0
    case glslang::EOpHitObjectTraceRayNV:
10103
0
        builder.createNoResultOp(spv::Op::OpHitObjectTraceRayNV, operands);
10104
0
        return 0;
10105
0
    case glslang::EOpHitObjectTraceRayEXT:
10106
0
        builder.createNoResultOp(spv::Op::OpHitObjectTraceRayEXT, operands);
10107
0
        return 0;
10108
0
    case glslang::EOpHitObjectTraceRayMotionNV:
10109
0
        builder.createNoResultOp(spv::Op::OpHitObjectTraceRayMotionNV, operands);
10110
0
        return 0;
10111
0
    case glslang::EOpHitObjectTraceRayMotionEXT:
10112
0
        builder.createNoResultOp(spv::Op::OpHitObjectTraceRayMotionEXT, operands);
10113
0
        return 0;
10114
0
    case glslang::EOpHitObjectRecordHitNV:
10115
0
        builder.createNoResultOp(spv::Op::OpHitObjectRecordHitNV, operands);
10116
0
        return 0;
10117
0
    case glslang::EOpHitObjectRecordHitMotionNV:
10118
0
        builder.createNoResultOp(spv::Op::OpHitObjectRecordHitMotionNV, operands);
10119
0
        return 0;
10120
0
    case glslang::EOpHitObjectRecordHitWithIndexNV:
10121
0
        builder.createNoResultOp(spv::Op::OpHitObjectRecordHitWithIndexNV, operands);
10122
0
        return 0;
10123
0
    case glslang::EOpHitObjectRecordHitWithIndexMotionNV:
10124
0
        builder.createNoResultOp(spv::Op::OpHitObjectRecordHitWithIndexMotionNV, operands);
10125
0
        return 0;
10126
0
    case glslang::EOpHitObjectRecordMissNV:
10127
0
        builder.createNoResultOp(spv::Op::OpHitObjectRecordMissNV, operands);
10128
0
        return 0;
10129
0
    case glslang::EOpHitObjectRecordMissEXT:
10130
0
        builder.createNoResultOp(spv::Op::OpHitObjectRecordMissEXT, operands);
10131
0
        return 0;
10132
0
    case glslang::EOpHitObjectRecordMissMotionNV:
10133
0
        builder.createNoResultOp(spv::Op::OpHitObjectRecordMissMotionNV, operands);
10134
0
        return 0;
10135
0
    case glslang::EOpHitObjectRecordMissMotionEXT:
10136
0
        builder.createNoResultOp(spv::Op::OpHitObjectRecordMissMotionEXT, operands);
10137
0
        return 0;
10138
0
    case glslang::EOpHitObjectExecuteShaderNV:
10139
0
        builder.createNoResultOp(spv::Op::OpHitObjectExecuteShaderNV, operands);
10140
0
        return 0;
10141
0
    case glslang::EOpHitObjectExecuteShaderEXT:
10142
0
        builder.createNoResultOp(spv::Op::OpHitObjectExecuteShaderEXT, operands);
10143
0
        return 0;
10144
0
    case glslang::EOpHitObjectIsEmptyNV:
10145
0
        typeId = builder.makeBoolType();
10146
0
        opCode = spv::Op::OpHitObjectIsEmptyNV;
10147
0
        break;
10148
0
    case glslang::EOpHitObjectIsEmptyEXT:
10149
0
        typeId = builder.makeBoolType();
10150
0
        opCode = spv::Op::OpHitObjectIsEmptyEXT;
10151
0
        break;
10152
0
    case glslang::EOpHitObjectIsMissNV:
10153
0
        typeId = builder.makeBoolType();
10154
0
        opCode = spv::Op::OpHitObjectIsMissNV;
10155
0
        break;
10156
0
    case glslang::EOpHitObjectIsMissEXT:
10157
0
        typeId = builder.makeBoolType();
10158
0
        opCode = spv::Op::OpHitObjectIsMissEXT;
10159
0
        break;
10160
0
    case glslang::EOpHitObjectIsHitNV:
10161
0
        typeId = builder.makeBoolType();
10162
0
        opCode = spv::Op::OpHitObjectIsHitNV;
10163
0
        break;
10164
0
    case glslang::EOpHitObjectIsSphereHitNV:
10165
0
        typeId = builder.makeBoolType();
10166
0
        opCode = spv::Op::OpHitObjectIsSphereHitNV;
10167
0
        break;
10168
0
    case glslang::EOpHitObjectIsLSSHitNV:
10169
0
        typeId = builder.makeBoolType();
10170
0
        opCode = spv::Op::OpHitObjectIsLSSHitNV;
10171
0
        break;
10172
0
    case glslang::EOpHitObjectIsHitEXT:
10173
0
        typeId = builder.makeBoolType();
10174
0
        opCode = spv::Op::OpHitObjectIsHitEXT;
10175
0
        break;
10176
0
    case glslang::EOpHitObjectGetRayTMinNV:
10177
0
        typeId = builder.makeFloatType(32);
10178
0
        opCode = spv::Op::OpHitObjectGetRayTMinNV;
10179
0
        break;
10180
0
    case glslang::EOpHitObjectGetRayTMinEXT:
10181
0
        typeId = builder.makeFloatType(32);
10182
0
        opCode = spv::Op::OpHitObjectGetRayTMinEXT;
10183
0
        break;
10184
0
    case glslang::EOpHitObjectGetRayTMaxNV:
10185
0
        typeId = builder.makeFloatType(32);
10186
0
        opCode = spv::Op::OpHitObjectGetRayTMaxNV;
10187
0
        break;
10188
0
    case glslang::EOpHitObjectGetRayTMaxEXT:
10189
0
        typeId = builder.makeFloatType(32);
10190
0
        opCode = spv::Op::OpHitObjectGetRayTMaxEXT;
10191
0
        break;
10192
0
    case glslang::EOpHitObjectGetRayFlagsEXT:
10193
0
        typeId = builder.makeIntegerType(32, 0);
10194
0
        opCode = spv::Op::OpHitObjectGetRayFlagsEXT;
10195
0
        break;
10196
0
    case glslang::EOpHitObjectGetObjectRayOriginNV:
10197
0
        typeId = builder.makeVectorType(builder.makeFloatType(32), 3);
10198
0
        opCode = spv::Op::OpHitObjectGetObjectRayOriginNV;
10199
0
        break;
10200
0
    case glslang::EOpHitObjectGetObjectRayOriginEXT:
10201
0
        typeId = builder.makeVectorType(builder.makeFloatType(32), 3);
10202
0
        opCode = spv::Op::OpHitObjectGetObjectRayOriginEXT;
10203
0
        break;
10204
0
    case glslang::EOpHitObjectGetObjectRayDirectionNV:
10205
0
        typeId = builder.makeVectorType(builder.makeFloatType(32), 3);
10206
0
        opCode = spv::Op::OpHitObjectGetObjectRayDirectionNV;
10207
0
        break;
10208
0
    case glslang::EOpHitObjectGetObjectRayDirectionEXT:
10209
0
        typeId = builder.makeVectorType(builder.makeFloatType(32), 3);
10210
0
        opCode = spv::Op::OpHitObjectGetObjectRayDirectionEXT;
10211
0
        break;
10212
0
    case glslang::EOpHitObjectGetWorldRayOriginNV:
10213
0
        typeId = builder.makeVectorType(builder.makeFloatType(32), 3);
10214
0
        opCode = spv::Op::OpHitObjectGetWorldRayOriginNV;
10215
0
        break;
10216
0
    case glslang::EOpHitObjectGetWorldRayOriginEXT:
10217
0
        typeId = builder.makeVectorType(builder.makeFloatType(32), 3);
10218
0
        opCode = spv::Op::OpHitObjectGetWorldRayOriginEXT;
10219
0
        break;
10220
0
    case glslang::EOpHitObjectGetWorldRayDirectionNV:
10221
0
        typeId = builder.makeVectorType(builder.makeFloatType(32), 3);
10222
0
        opCode = spv::Op::OpHitObjectGetWorldRayDirectionNV;
10223
0
        break;
10224
0
    case glslang::EOpHitObjectGetWorldRayDirectionEXT:
10225
0
        typeId = builder.makeVectorType(builder.makeFloatType(32), 3);
10226
0
        opCode = spv::Op::OpHitObjectGetWorldRayDirectionEXT;
10227
0
        break;
10228
0
    case glslang::EOpHitObjectGetWorldToObjectNV:
10229
0
        typeId = builder.makeMatrixType(builder.makeFloatType(32), 4, 3);
10230
0
        opCode = spv::Op::OpHitObjectGetWorldToObjectNV;
10231
0
        break;
10232
0
    case glslang::EOpHitObjectGetWorldToObjectEXT:
10233
0
        typeId = builder.makeMatrixType(builder.makeFloatType(32), 4, 3);
10234
0
        opCode = spv::Op::OpHitObjectGetWorldToObjectEXT;
10235
0
        break;
10236
0
    case glslang::EOpHitObjectGetObjectToWorldNV:
10237
0
        typeId = builder.makeMatrixType(builder.makeFloatType(32), 4, 3);
10238
0
        opCode = spv::Op::OpHitObjectGetObjectToWorldNV;
10239
0
        break;
10240
0
    case glslang::EOpHitObjectGetObjectToWorldEXT:
10241
0
        typeId = builder.makeMatrixType(builder.makeFloatType(32), 4, 3);
10242
0
        opCode = spv::Op::OpHitObjectGetObjectToWorldEXT;
10243
0
        break;
10244
0
    case glslang::EOpHitObjectGetInstanceCustomIndexNV:
10245
0
        typeId = builder.makeIntegerType(32, 1);
10246
0
        opCode = spv::Op::OpHitObjectGetInstanceCustomIndexNV;
10247
0
        break;
10248
0
    case glslang::EOpHitObjectGetInstanceCustomIndexEXT:
10249
0
        typeId = builder.makeIntegerType(32, 1);
10250
0
        opCode = spv::Op::OpHitObjectGetInstanceCustomIndexEXT;
10251
0
        break;
10252
0
    case glslang::EOpHitObjectGetInstanceIdNV:
10253
0
        typeId = builder.makeIntegerType(32, 1);
10254
0
        opCode = spv::Op::OpHitObjectGetInstanceIdNV;
10255
0
        break;
10256
0
    case glslang::EOpHitObjectGetInstanceIdEXT:
10257
0
        typeId = builder.makeIntegerType(32, 1);
10258
0
        opCode = spv::Op::OpHitObjectGetInstanceIdEXT;
10259
0
        break;
10260
0
    case glslang::EOpHitObjectGetGeometryIndexNV:
10261
0
        typeId = builder.makeIntegerType(32, 1);
10262
0
        opCode = spv::Op::OpHitObjectGetGeometryIndexNV;
10263
0
        break;
10264
0
    case glslang::EOpHitObjectGetGeometryIndexEXT:
10265
0
        typeId = builder.makeIntegerType(32, 1);
10266
0
        opCode = spv::Op::OpHitObjectGetGeometryIndexEXT;
10267
0
        break;
10268
0
    case glslang::EOpHitObjectGetPrimitiveIndexNV:
10269
0
        typeId = builder.makeIntegerType(32, 1);
10270
0
        opCode = spv::Op::OpHitObjectGetPrimitiveIndexNV;
10271
0
        break;
10272
0
    case glslang::EOpHitObjectGetPrimitiveIndexEXT:
10273
0
        typeId = builder.makeIntegerType(32, 1);
10274
0
        opCode = spv::Op::OpHitObjectGetPrimitiveIndexEXT;
10275
0
        break;
10276
0
    case glslang::EOpHitObjectGetHitKindNV:
10277
0
        typeId = builder.makeIntegerType(32, 0);
10278
0
        opCode = spv::Op::OpHitObjectGetHitKindNV;
10279
0
        break;
10280
0
    case glslang::EOpHitObjectGetHitKindEXT:
10281
0
        typeId = builder.makeIntegerType(32, 0);
10282
0
        opCode = spv::Op::OpHitObjectGetHitKindEXT;
10283
0
        break;
10284
0
    case glslang::EOpHitObjectGetCurrentTimeNV:
10285
0
        typeId = builder.makeFloatType(32);
10286
0
        opCode = spv::Op::OpHitObjectGetCurrentTimeNV;
10287
0
        break;
10288
0
    case glslang::EOpHitObjectGetCurrentTimeEXT:
10289
0
        typeId = builder.makeFloatType(32);
10290
0
        opCode = spv::Op::OpHitObjectGetCurrentTimeEXT;
10291
0
        break;
10292
0
    case glslang::EOpHitObjectGetShaderBindingTableRecordIndexNV:
10293
0
        typeId = builder.makeIntegerType(32, 0);
10294
0
        opCode = spv::Op::OpHitObjectGetShaderBindingTableRecordIndexNV;
10295
0
        return 0;
10296
0
    case glslang::EOpHitObjectGetShaderBindingTableRecordIndexEXT:
10297
0
        typeId = builder.makeIntegerType(32, 0);
10298
0
        opCode = spv::Op::OpHitObjectGetShaderBindingTableRecordIndexEXT;
10299
0
        return 0;
10300
0
    case glslang::EOpHitObjectGetAttributesNV:
10301
0
        builder.createNoResultOp(spv::Op::OpHitObjectGetAttributesNV, operands);
10302
0
        return 0;
10303
0
    case glslang::EOpHitObjectGetAttributesEXT:
10304
0
        builder.createNoResultOp(spv::Op::OpHitObjectGetAttributesEXT, operands);
10305
0
        return 0;
10306
0
    case glslang::EOpHitObjectRecordFromQueryEXT:
10307
0
        builder.createNoResultOp(spv::Op::OpHitObjectRecordFromQueryEXT, operands);
10308
0
        return 0;
10309
0
    case glslang::EOpHitObjectGetShaderRecordBufferHandleNV:
10310
0
        typeId = builder.makeVectorType(builder.makeUintType(32), 2);
10311
0
        opCode = spv::Op::OpHitObjectGetShaderRecordBufferHandleNV;
10312
0
        break;
10313
0
    case glslang::EOpHitObjectGetClusterIdNV:
10314
0
        typeId = builder.makeIntegerType(32, 1);
10315
0
        opCode = spv::Op::OpHitObjectGetClusterIdNV;
10316
0
        break;
10317
0
    case glslang::EOpHitObjectGetShaderRecordBufferHandleEXT:
10318
0
        typeId = builder.makeVectorType(builder.makeUintType(32), 2);
10319
0
        opCode = spv::Op::OpHitObjectGetShaderRecordBufferHandleEXT;
10320
0
        break;
10321
0
    case glslang::EOpHitObjectSetShaderBindingTableRecordIndexEXT:
10322
0
        builder.createNoResultOp(spv::Op::OpHitObjectSetShaderBindingTableRecordIndexEXT, operands);
10323
0
        return 0;
10324
0
    case glslang::EOpReorderThreadNV: {
10325
0
        if (operands.size() == 2) {
10326
0
            builder.createNoResultOp(spv::Op::OpReorderThreadWithHintNV, operands);
10327
0
        } else {
10328
0
            builder.createNoResultOp(spv::Op::OpReorderThreadWithHitObjectNV, operands);
10329
0
        }
10330
0
        return 0;
10331
0
    }
10332
0
    case glslang::EOpReorderThreadEXT: {
10333
0
        if (operands.size() == 2) {
10334
0
            builder.createNoResultOp(spv::Op::OpReorderThreadWithHintEXT, operands);
10335
0
        } else {
10336
0
            builder.createNoResultOp(spv::Op::OpReorderThreadWithHitObjectEXT, operands);
10337
0
        }
10338
0
        return 0;
10339
0
    }
10340
10341
0
    case glslang::EOpHitObjectReorderExecuteEXT: {
10342
0
        if (operands.size() == 2) {
10343
0
            builder.createNoResultOp(spv::Op::OpHitObjectReorderExecuteShaderEXT, operands);
10344
0
        } else {
10345
            // GLSL intrinsic is
10346
            // hitObjectReorderExecuteEXT(hitObjectEXT hitObject, uint hint, uint bits,int payload) while
10347
            // SPIRV is hitObject id , payload id, optional hint id, optional bits id hence reorder operands
10348
0
            builder.createNoResultOp(spv::Op::OpHitObjectReorderExecuteShaderEXT, {operands[0], operands[3], operands[1], operands[2]});
10349
0
        }
10350
0
        return 0;
10351
0
    }
10352
10353
0
    case glslang::EOpHitObjectTraceReorderExecuteEXT: {
10354
0
        if (operands.size() == 12) {
10355
0
            builder.createNoResultOp(spv::Op::OpHitObjectTraceReorderExecuteEXT, operands);
10356
0
        } else {
10357
0
            std::vector<spv::Id> argOperands;
10358
0
            std::copy(operands.begin(), operands.begin() + 11, std::back_inserter(argOperands));
10359
0
            argOperands.push_back(operands[13]);
10360
0
            argOperands.push_back(operands[11]);
10361
0
            argOperands.push_back(operands[12]);
10362
0
            builder.createNoResultOp(spv::Op::OpHitObjectTraceReorderExecuteEXT, argOperands);
10363
0
        }
10364
0
        return 0;
10365
0
    }
10366
0
    case glslang::EOpHitObjectTraceMotionReorderExecuteEXT: {
10367
0
        if (operands.size() == 13) {
10368
0
            builder.createNoResultOp(spv::Op::OpHitObjectTraceMotionReorderExecuteEXT, operands);
10369
0
        } else {
10370
0
            std::vector<spv::Id> argOperands;
10371
0
            std::copy(operands.begin(), operands.begin() + 12, std::back_inserter(argOperands));
10372
0
            argOperands.push_back(operands[14]);
10373
0
            argOperands.push_back(operands[12]);
10374
0
            argOperands.push_back(operands[13]);
10375
0
            builder.createNoResultOp(spv::Op::OpHitObjectTraceMotionReorderExecuteEXT, argOperands);
10376
0
        }
10377
0
        return 0;
10378
0
    }
10379
29
    case glslang::EOpImageSampleWeightedQCOM:
10380
29
        typeId = builder.makeVectorType(builder.makeFloatType(32), 4);
10381
29
        opCode = spv::Op::OpImageSampleWeightedQCOM;
10382
29
        addImageProcessingQCOMDecoration(operands[2], spv::Decoration::WeightTextureQCOM);
10383
29
        break;
10384
26
    case glslang::EOpImageBoxFilterQCOM:
10385
26
        typeId = builder.makeVectorType(builder.makeFloatType(32), 4);
10386
26
        opCode = spv::Op::OpImageBoxFilterQCOM;
10387
26
        break;
10388
39
    case glslang::EOpImageBlockMatchSADQCOM:
10389
39
        typeId = builder.makeVectorType(builder.makeFloatType(32), 4);
10390
39
        opCode = spv::Op::OpImageBlockMatchSADQCOM;
10391
39
        addImageProcessingQCOMDecoration(operands[0], spv::Decoration::BlockMatchTextureQCOM);
10392
39
        addImageProcessingQCOMDecoration(operands[2], spv::Decoration::BlockMatchTextureQCOM);
10393
39
        break;
10394
39
    case glslang::EOpImageBlockMatchSSDQCOM:
10395
39
        typeId = builder.makeVectorType(builder.makeFloatType(32), 4);
10396
39
        opCode = spv::Op::OpImageBlockMatchSSDQCOM;
10397
39
        addImageProcessingQCOMDecoration(operands[0], spv::Decoration::BlockMatchTextureQCOM);
10398
39
        addImageProcessingQCOMDecoration(operands[2], spv::Decoration::BlockMatchTextureQCOM);
10399
39
        break;
10400
10401
0
    case glslang::EOpFetchMicroTriangleVertexBarycentricNV:
10402
0
        typeId = builder.makeVectorType(builder.makeFloatType(32), 2);
10403
0
        opCode = spv::Op::OpFetchMicroTriangleVertexBarycentricNV;
10404
0
        break;
10405
10406
0
    case glslang::EOpFetchMicroTriangleVertexPositionNV:
10407
0
        typeId = builder.makeVectorType(builder.makeFloatType(32), 3);
10408
0
        opCode = spv::Op::OpFetchMicroTriangleVertexPositionNV;
10409
0
        break;
10410
10411
26
    case glslang::EOpImageBlockMatchWindowSSDQCOM:
10412
26
        typeId = builder.makeVectorType(builder.makeFloatType(32), 4);
10413
26
        opCode = spv::Op::OpImageBlockMatchWindowSSDQCOM;
10414
26
        addImageProcessing2QCOMDecoration(operands[0], false);
10415
26
        addImageProcessing2QCOMDecoration(operands[2], false);
10416
26
        break;
10417
26
    case glslang::EOpImageBlockMatchWindowSADQCOM:
10418
26
        typeId = builder.makeVectorType(builder.makeFloatType(32), 4);
10419
26
        opCode = spv::Op::OpImageBlockMatchWindowSADQCOM;
10420
26
        addImageProcessing2QCOMDecoration(operands[0], false);
10421
26
        addImageProcessing2QCOMDecoration(operands[2], false);
10422
26
        break;
10423
26
    case glslang::EOpImageBlockMatchGatherSSDQCOM:
10424
26
        typeId = builder.makeVectorType(builder.makeFloatType(32), 4);
10425
26
        opCode = spv::Op::OpImageBlockMatchGatherSSDQCOM;
10426
26
        addImageProcessing2QCOMDecoration(operands[0], true);
10427
26
        addImageProcessing2QCOMDecoration(operands[2], true);
10428
26
        break;
10429
26
    case glslang::EOpImageBlockMatchGatherSADQCOM:
10430
26
        typeId = builder.makeVectorType(builder.makeFloatType(32), 4);
10431
26
        opCode = spv::Op::OpImageBlockMatchGatherSADQCOM;
10432
26
        addImageProcessing2QCOMDecoration(operands[0], true);
10433
26
        addImageProcessing2QCOMDecoration(operands[2], true);
10434
26
        break;
10435
0
    case glslang::EOpCreateTensorLayoutNV:
10436
0
        return builder.createOp(spv::Op::OpCreateTensorLayoutNV, typeId, std::vector<spv::Id>{});
10437
0
    case glslang::EOpCreateTensorViewNV:
10438
0
        return builder.createOp(spv::Op::OpCreateTensorViewNV, typeId, std::vector<spv::Id>{});
10439
0
    case glslang::EOpTensorLayoutSetBlockSizeNV:
10440
0
        opCode = spv::Op::OpTensorLayoutSetBlockSizeNV;
10441
0
        break;
10442
0
    case glslang::EOpTensorLayoutSetDimensionNV:
10443
0
        opCode = spv::Op::OpTensorLayoutSetDimensionNV;
10444
0
        break;
10445
0
    case glslang::EOpTensorLayoutSetStrideNV:
10446
0
        opCode = spv::Op::OpTensorLayoutSetStrideNV;
10447
0
        break;
10448
0
    case glslang::EOpTensorLayoutSliceNV:
10449
0
        opCode = spv::Op::OpTensorLayoutSliceNV;
10450
0
        break;
10451
0
    case glslang::EOpTensorLayoutSetClampValueNV:
10452
0
        opCode = spv::Op::OpTensorLayoutSetClampValueNV;
10453
0
        break;
10454
0
    case glslang::EOpTensorViewSetDimensionNV:
10455
0
        opCode = spv::Op::OpTensorViewSetDimensionNV;
10456
0
        break;
10457
0
    case glslang::EOpTensorViewSetStrideNV:
10458
0
        opCode = spv::Op::OpTensorViewSetStrideNV;
10459
0
        break;
10460
0
    case glslang::EOpTensorViewSetClipNV:
10461
0
        opCode = spv::Op::OpTensorViewSetClipNV;
10462
0
        break;
10463
0
    default:
10464
0
        return 0;
10465
4.87k
    }
10466
10467
2.81k
    spv::Id id = 0;
10468
2.81k
    if (libCall >= 0) {
10469
        // Use an extended instruction from the standard library.
10470
        // Construct the call arguments, without modifying the original operands vector.
10471
        // We might need the remaining arguments, e.g. in the EOpFrexp case.
10472
1.23k
        std::vector<spv::Id> callArguments(operands.begin(), operands.begin() + consumedOperands);
10473
1.23k
        id = builder.createBuiltinCall(typeId, extBuiltins >= 0 ? extBuiltins : stdBuiltins, libCall, callArguments);
10474
1.58k
    } else if (opCode == spv::Op::OpDot && !isFloat) {
10475
        // int dot(int, int)
10476
        // NOTE: never called for scalar/vector1, this is turned into simple mul before this can be reached
10477
0
        const int componentCount = builder.getNumComponents(operands[0]);
10478
0
        spv::Id mulOp = builder.createBinOp(spv::Op::OpIMul, builder.getTypeId(operands[0]), operands[0], operands[1]);
10479
0
        builder.setPrecision(mulOp, precision);
10480
0
        id = builder.createCompositeExtract(mulOp, typeId, 0);
10481
0
        for (int i = 1; i < componentCount; ++i) {
10482
0
            builder.setPrecision(id, precision);
10483
0
            id = builder.createBinOp(spv::Op::OpIAdd, typeId, id, builder.createCompositeExtract(mulOp, typeId, i));
10484
0
        }
10485
1.58k
    } else {
10486
1.58k
        switch (consumedOperands) {
10487
0
        case 0:
10488
            // should all be handled by visitAggregate and createNoArgOperation
10489
0
            assert(0);
10490
0
            return 0;
10491
0
        case 1:
10492
            // should all be handled by createUnaryOperation
10493
0
            assert(0);
10494
0
            return 0;
10495
1.31k
        case 2:
10496
1.31k
            id = builder.createBinOp(opCode, typeId, operands[0], operands[1]);
10497
1.31k
            break;
10498
273
        default:
10499
            // anything 3 or over doesn't have l-value operands, so all should be consumed
10500
273
            assert(consumedOperands == operands.size());
10501
273
            id = builder.createOp(opCode, typeId, operands);
10502
273
            break;
10503
1.58k
        }
10504
1.58k
    }
10505
10506
    // Decode the return types that were structures
10507
2.81k
    switch (op) {
10508
0
    case glslang::EOpAddCarry:
10509
0
    case glslang::EOpSubBorrow:
10510
0
        builder.createStore(builder.createCompositeExtract(id, typeId0, 1), operands[2]);
10511
0
        id = builder.createCompositeExtract(id, typeId0, 0);
10512
0
        break;
10513
0
    case glslang::EOpUMulExtended:
10514
0
    case glslang::EOpIMulExtended:
10515
0
        builder.createStore(builder.createCompositeExtract(id, typeId0, 0), operands[3]);
10516
0
        builder.createStore(builder.createCompositeExtract(id, typeId0, 1), operands[2]);
10517
0
        break;
10518
0
    case glslang::EOpModf:
10519
0
        {
10520
0
            assert(operands.size() == 2);
10521
0
            builder.createStore(builder.createCompositeExtract(id, typeId0, 1), operands[1]);
10522
0
            id = builder.createCompositeExtract(id, typeId0, 0);
10523
0
        }
10524
0
        break;
10525
9
    case glslang::EOpFrexp:
10526
9
        {
10527
9
            assert(operands.size() == 2);
10528
9
            if (builder.isFloatType(builder.getScalarTypeId(typeId1))) {
10529
                // "exp" is floating-point type (from HLSL intrinsic)
10530
0
                spv::Id member1 = builder.createCompositeExtract(id, frexpIntType, 1);
10531
0
                member1 = builder.createUnaryOp(spv::Op::OpConvertSToF, typeId1, member1);
10532
0
                builder.createStore(member1, operands[1]);
10533
0
            } else
10534
                // "exp" is integer type (from GLSL built-in function)
10535
9
                builder.createStore(builder.createCompositeExtract(id, frexpIntType, 1), operands[1]);
10536
9
            id = builder.createCompositeExtract(id, typeId0, 0);
10537
9
        }
10538
9
        break;
10539
2.81k
    default:
10540
2.81k
        break;
10541
2.81k
    }
10542
10543
2.81k
    return builder.setPrecision(id, precision);
10544
2.81k
}
10545
10546
// Intrinsics with no arguments (or no return value, and no precision).
10547
spv::Id TGlslangToSpvTraverser::createNoArgOperation(glslang::TOperator op, spv::Decoration precision, spv::Id typeId)
10548
5
{
10549
    // GLSL memory barriers use queuefamily scope in new model, device scope in old model
10550
5
    spv::Scope memoryBarrierScope = glslangIntermediate->usingVulkanMemoryModel() ?
10551
5
        spv::Scope::QueueFamilyKHR : spv::Scope::Device;
10552
10553
5
    switch (op) {
10554
0
    case glslang::EOpBarrier:
10555
0
        if (glslangIntermediate->getStage() == EShLangTessControl) {
10556
0
            if (glslangIntermediate->usingVulkanMemoryModel()) {
10557
0
                builder.createControlBarrier(spv::Scope::Workgroup, spv::Scope::Workgroup,
10558
0
                                             spv::MemorySemanticsMask::OutputMemoryKHR |
10559
0
                                             spv::MemorySemanticsMask::AcquireRelease);
10560
0
                builder.addCapability(spv::Capability::VulkanMemoryModelKHR);
10561
0
            } else {
10562
0
                builder.createControlBarrier(spv::Scope::Workgroup, spv::Scope::Invocation, spv::MemorySemanticsMask::MaskNone);
10563
0
            }
10564
0
        } else {
10565
0
            builder.createControlBarrier(spv::Scope::Workgroup, spv::Scope::Workgroup,
10566
0
                                            spv::MemorySemanticsMask::WorkgroupMemory |
10567
0
                                            spv::MemorySemanticsMask::AcquireRelease);
10568
0
        }
10569
0
        return 0;
10570
0
    case glslang::EOpMemoryBarrier:
10571
0
        builder.createMemoryBarrier(memoryBarrierScope, spv::MemorySemanticsAllMemory |
10572
0
                                                        spv::MemorySemanticsMask::AcquireRelease);
10573
0
        return 0;
10574
0
    case glslang::EOpMemoryBarrierBuffer:
10575
0
        builder.createMemoryBarrier(memoryBarrierScope, spv::MemorySemanticsMask::UniformMemory |
10576
0
                                                        spv::MemorySemanticsMask::AcquireRelease);
10577
0
        return 0;
10578
0
    case glslang::EOpMemoryBarrierShared:
10579
0
        builder.createMemoryBarrier(memoryBarrierScope, spv::MemorySemanticsMask::WorkgroupMemory |
10580
0
                                                        spv::MemorySemanticsMask::AcquireRelease);
10581
0
        return 0;
10582
0
    case glslang::EOpGroupMemoryBarrier:
10583
0
        builder.createMemoryBarrier(spv::Scope::Workgroup, spv::MemorySemanticsAllMemory |
10584
0
                                                           spv::MemorySemanticsMask::AcquireRelease);
10585
0
        return 0;
10586
0
    case glslang::EOpMemoryBarrierAtomicCounter:
10587
0
        builder.createMemoryBarrier(memoryBarrierScope, spv::MemorySemanticsMask::AtomicCounterMemory |
10588
0
                                                        spv::MemorySemanticsMask::AcquireRelease);
10589
0
        return 0;
10590
0
    case glslang::EOpMemoryBarrierImage:
10591
0
        builder.createMemoryBarrier(memoryBarrierScope, spv::MemorySemanticsMask::ImageMemory |
10592
0
                                                        spv::MemorySemanticsMask::AcquireRelease);
10593
0
        return 0;
10594
0
    case glslang::EOpAllMemoryBarrierWithGroupSync:
10595
0
        builder.createControlBarrier(spv::Scope::Workgroup, spv::Scope::Device,
10596
0
                                        spv::MemorySemanticsAllMemory |
10597
0
                                        spv::MemorySemanticsMask::AcquireRelease);
10598
0
        return 0;
10599
0
    case glslang::EOpDeviceMemoryBarrier:
10600
0
        builder.createMemoryBarrier(spv::Scope::Device, spv::MemorySemanticsMask::UniformMemory |
10601
0
                                                        spv::MemorySemanticsMask::ImageMemory |
10602
0
                                                        spv::MemorySemanticsMask::AcquireRelease);
10603
0
        return 0;
10604
0
    case glslang::EOpDeviceMemoryBarrierWithGroupSync:
10605
0
        builder.createControlBarrier(spv::Scope::Workgroup, spv::Scope::Device, spv::MemorySemanticsMask::UniformMemory |
10606
0
                                                                                spv::MemorySemanticsMask::ImageMemory |
10607
0
                                                                                spv::MemorySemanticsMask::AcquireRelease);
10608
0
        return 0;
10609
0
    case glslang::EOpWorkgroupMemoryBarrier:
10610
0
        builder.createMemoryBarrier(spv::Scope::Workgroup, spv::MemorySemanticsMask::WorkgroupMemory |
10611
0
                                                           spv::MemorySemanticsMask::AcquireRelease);
10612
0
        return 0;
10613
0
    case glslang::EOpWorkgroupMemoryBarrierWithGroupSync:
10614
0
        builder.createControlBarrier(spv::Scope::Workgroup, spv::Scope::Workgroup,
10615
0
                                        spv::MemorySemanticsMask::WorkgroupMemory |
10616
0
                                        spv::MemorySemanticsMask::AcquireRelease);
10617
0
        return 0;
10618
0
    case glslang::EOpSubgroupBarrier:
10619
0
        builder.createControlBarrier(spv::Scope::Subgroup, spv::Scope::Subgroup, spv::MemorySemanticsAllMemory |
10620
0
                                                                                 spv::MemorySemanticsMask::AcquireRelease);
10621
0
        return spv::NoResult;
10622
0
    case glslang::EOpSubgroupMemoryBarrier:
10623
0
        builder.createMemoryBarrier(spv::Scope::Subgroup, spv::MemorySemanticsAllMemory |
10624
0
                                                          spv::MemorySemanticsMask::AcquireRelease);
10625
0
        return spv::NoResult;
10626
0
    case glslang::EOpSubgroupMemoryBarrierBuffer:
10627
0
        builder.createMemoryBarrier(spv::Scope::Subgroup, spv::MemorySemanticsMask::UniformMemory |
10628
0
                                                          spv::MemorySemanticsMask::AcquireRelease);
10629
0
        return spv::NoResult;
10630
0
    case glslang::EOpSubgroupMemoryBarrierImage:
10631
0
        builder.createMemoryBarrier(spv::Scope::Subgroup, spv::MemorySemanticsMask::ImageMemory |
10632
0
                                                          spv::MemorySemanticsMask::AcquireRelease);
10633
0
        return spv::NoResult;
10634
0
    case glslang::EOpSubgroupMemoryBarrierShared:
10635
0
        builder.createMemoryBarrier(spv::Scope::Subgroup, spv::MemorySemanticsMask::WorkgroupMemory |
10636
0
                                                          spv::MemorySemanticsMask::AcquireRelease);
10637
0
        return spv::NoResult;
10638
10639
0
    case glslang::EOpEmitVertex:
10640
0
        builder.createNoResultOp(spv::Op::OpEmitVertex);
10641
0
        return 0;
10642
0
    case glslang::EOpEndPrimitive:
10643
0
        builder.createNoResultOp(spv::Op::OpEndPrimitive);
10644
0
        return 0;
10645
10646
0
    case glslang::EOpSubgroupElect: {
10647
0
        std::vector<spv::Id> operands;
10648
0
        return createSubgroupOperation(op, typeId, operands, glslang::EbtVoid);
10649
0
    }
10650
0
    case glslang::EOpTime:
10651
0
    {
10652
0
        std::vector<spv::Id> args; // Dummy arguments
10653
0
        spv::Id id = builder.createBuiltinCall(typeId, getExtBuiltins(spv::E_SPV_AMD_gcn_shader), spv::TimeAMD, args);
10654
0
        return builder.setPrecision(id, precision);
10655
0
    }
10656
0
    case glslang::EOpIgnoreIntersectionNV:
10657
0
        builder.createNoResultOp(spv::Op::OpIgnoreIntersectionNV);
10658
0
        return 0;
10659
0
    case glslang::EOpTerminateRayNV:
10660
0
        builder.createNoResultOp(spv::Op::OpTerminateRayNV);
10661
0
        return 0;
10662
0
    case glslang::EOpRayQueryInitialize:
10663
0
        builder.createNoResultOp(spv::Op::OpRayQueryInitializeKHR);
10664
0
        return 0;
10665
0
    case glslang::EOpRayQueryTerminate:
10666
0
        builder.createNoResultOp(spv::Op::OpRayQueryTerminateKHR);
10667
0
        return 0;
10668
0
    case glslang::EOpRayQueryGenerateIntersection:
10669
0
        builder.createNoResultOp(spv::Op::OpRayQueryGenerateIntersectionKHR);
10670
0
        return 0;
10671
0
    case glslang::EOpRayQueryConfirmIntersection:
10672
0
        builder.createNoResultOp(spv::Op::OpRayQueryConfirmIntersectionKHR);
10673
0
        return 0;
10674
1
    case glslang::EOpBeginInvocationInterlock:
10675
1
        builder.createNoResultOp(spv::Op::OpBeginInvocationInterlockEXT);
10676
1
        return 0;
10677
1
    case glslang::EOpEndInvocationInterlock:
10678
1
        builder.createNoResultOp(spv::Op::OpEndInvocationInterlockEXT);
10679
1
        return 0;
10680
10681
1
    case glslang::EOpIsHelperInvocation:
10682
1
    {
10683
1
        std::vector<spv::Id> args; // Dummy arguments
10684
1
        builder.addExtension(spv::E_SPV_EXT_demote_to_helper_invocation);
10685
1
        builder.addCapability(spv::Capability::DemoteToHelperInvocationEXT);
10686
1
        return builder.createOp(spv::Op::OpIsHelperInvocationEXT, typeId, args);
10687
0
    }
10688
10689
0
    case glslang::EOpReadClockSubgroupKHR: {
10690
0
        std::vector<spv::Id> args;
10691
0
        args.push_back(builder.makeUintConstant(spv::Scope::Subgroup));
10692
0
        builder.addExtension(spv::E_SPV_KHR_shader_clock);
10693
0
        builder.addCapability(spv::Capability::ShaderClockKHR);
10694
0
        return builder.createOp(spv::Op::OpReadClockKHR, typeId, args);
10695
0
    }
10696
10697
0
    case glslang::EOpReadClockDeviceKHR: {
10698
0
        std::vector<spv::Id> args;
10699
0
        args.push_back(builder.makeUintConstant(spv::Scope::Device));
10700
0
        builder.addExtension(spv::E_SPV_KHR_shader_clock);
10701
0
        builder.addCapability(spv::Capability::ShaderClockKHR);
10702
0
        return builder.createOp(spv::Op::OpReadClockKHR, typeId, args);
10703
0
    }
10704
1
    case glslang::EOpStencilAttachmentReadEXT:
10705
2
    case glslang::EOpDepthAttachmentReadEXT:
10706
2
    {
10707
2
        builder.addExtension(spv::E_SPV_EXT_shader_tile_image);
10708
10709
2
        spv::Decoration precision;
10710
2
        spv::Op spv_op;
10711
2
        if (op == glslang::EOpStencilAttachmentReadEXT)
10712
1
        {
10713
1
            precision = spv::Decoration::RelaxedPrecision;
10714
1
            spv_op = spv::Op::OpStencilAttachmentReadEXT;
10715
1
            builder.addCapability(spv::Capability::TileImageStencilReadAccessEXT);
10716
1
        }
10717
1
        else
10718
1
        {
10719
1
            precision = spv::NoPrecision;
10720
1
            spv_op = spv::Op::OpDepthAttachmentReadEXT;
10721
1
            builder.addCapability(spv::Capability::TileImageDepthReadAccessEXT);
10722
1
        }
10723
10724
2
        std::vector<spv::Id> args; // Dummy args
10725
2
        spv::Id result = builder.createOp(spv_op, typeId, args);
10726
2
        return builder.setPrecision(result, precision);
10727
1
    }
10728
0
    default:
10729
0
        break;
10730
5
    }
10731
10732
0
    logger->missingFunctionality("unknown operation with no arguments");
10733
10734
0
    return 0;
10735
5
}
10736
10737
spv::Id TGlslangToSpvTraverser::getSymbolId(const glslang::TIntermSymbol* symbol)
10738
81.8k
{
10739
81.8k
    auto iter = symbolValues.find(symbol->getId());
10740
81.8k
    spv::Id id;
10741
81.8k
    if (symbolValues.end() != iter) {
10742
60.2k
        id = iter->second;
10743
60.2k
        return id;
10744
60.2k
    }
10745
10746
    // it was not found, create it
10747
21.5k
    spv::BuiltIn builtIn = TranslateBuiltInDecoration(symbol->getQualifier().builtIn, false);
10748
21.5k
    auto forcedType = getForcedType(symbol->getQualifier().builtIn, symbol->getType());
10749
10750
    // There are pairs of symbols that map to the same SPIR-V built-in:
10751
    // gl_ObjectToWorldEXT and gl_ObjectToWorld3x4EXT, and gl_WorldToObjectEXT
10752
    // and gl_WorldToObject3x4EXT. SPIR-V forbids having two OpVariables
10753
    // with the same BuiltIn in the same storage class, so we must re-use one.
10754
21.5k
    const bool mayNeedToReuseBuiltIn =
10755
21.5k
        builtIn == spv::BuiltIn::ObjectToWorldKHR ||
10756
21.5k
        builtIn == spv::BuiltIn::WorldToObjectKHR;
10757
10758
21.5k
    if (mayNeedToReuseBuiltIn) {
10759
0
        auto iter = builtInVariableIds.find(uint32_t(builtIn));
10760
0
        if (builtInVariableIds.end() != iter) {
10761
0
            id = iter->second;
10762
0
            symbolValues[symbol->getId()] = id;
10763
0
            if (forcedType.second != spv::NoType)
10764
0
                forceType[id] = forcedType.second;
10765
0
            return id;
10766
0
        }
10767
0
    }
10768
10769
21.5k
    if (symbol->getBasicType() == glslang::EbtFunction) {
10770
0
        return 0;
10771
0
    }
10772
10773
21.5k
    id = createSpvVariable(symbol, forcedType.first);
10774
10775
21.5k
    if (mayNeedToReuseBuiltIn) {
10776
0
        builtInVariableIds.insert({uint32_t(builtIn), id});
10777
0
    }
10778
10779
21.5k
    symbolValues[symbol->getId()] = id;
10780
21.5k
    if (forcedType.second != spv::NoType)
10781
0
        forceType[id] = forcedType.second;
10782
10783
21.5k
    if (symbol->getBasicType() != glslang::EbtBlock) {
10784
20.2k
        builder.addDecoration(id, TranslatePrecisionDecoration(symbol->getType()));
10785
20.2k
        builder.addDecoration(id, TranslateInterpolationDecoration(symbol->getType().getQualifier()));
10786
20.2k
        builder.addDecoration(id, TranslateAuxiliaryStorageDecoration(symbol->getType().getQualifier()));
10787
20.2k
        addMeshNVDecoration(id, /*member*/ -1, symbol->getType().getQualifier());
10788
20.2k
        if (symbol->getQualifier().hasComponent())
10789
3
            builder.addDecoration(id, spv::Decoration::Component, symbol->getQualifier().layoutComponent);
10790
20.2k
        if (symbol->getQualifier().hasIndex())
10791
0
            builder.addDecoration(id, spv::Decoration::Index, symbol->getQualifier().layoutIndex);
10792
20.2k
        if (symbol->getType().getQualifier().hasSpecConstantId())
10793
334
            builder.addDecoration(id, spv::Decoration::SpecId, symbol->getType().getQualifier().layoutSpecConstantId);
10794
        // atomic counters use this:
10795
20.2k
        if (symbol->getQualifier().hasOffset())
10796
0
            builder.addDecoration(id, spv::Decoration::Offset, symbol->getQualifier().layoutOffset);
10797
20.2k
    }
10798
10799
21.5k
    if (symbol->getQualifier().hasLocation()) {
10800
2.13k
        if (!(glslangIntermediate->isRayTracingStage() &&
10801
4
              (glslangIntermediate->IsRequestedExtension(glslang::E_GL_EXT_ray_tracing) ||
10802
4
               glslangIntermediate->IsRequestedExtension(glslang::E_GL_NV_shader_invocation_reorder) ||
10803
4
               glslangIntermediate->IsRequestedExtension(glslang::E_GL_EXT_shader_invocation_reorder))
10804
0
              && (builder.getStorageClass(id) == spv::StorageClass::RayPayloadKHR ||
10805
0
                  builder.getStorageClass(id) == spv::StorageClass::IncomingRayPayloadKHR ||
10806
0
                  builder.getStorageClass(id) == spv::StorageClass::CallableDataKHR ||
10807
0
                  builder.getStorageClass(id) == spv::StorageClass::IncomingCallableDataKHR ||
10808
0
                  builder.getStorageClass(id) == spv::StorageClass::HitObjectAttributeEXT ||
10809
2.13k
                  builder.getStorageClass(id) == spv::StorageClass::HitObjectAttributeNV))) {
10810
            // Location values are used to link TraceRayKHR/ExecuteCallableKHR/HitObjectGetAttributesNV
10811
            // to corresponding variables but are not valid in SPIRV since they are supported only
10812
            // for Input/Output Storage classes.
10813
2.13k
            builder.addDecoration(id, spv::Decoration::Location, symbol->getQualifier().layoutLocation);
10814
2.13k
        }
10815
2.13k
    }
10816
10817
21.5k
    builder.addDecoration(id, TranslateInvariantDecoration(symbol->getType().getQualifier()));
10818
21.5k
    if (symbol->getQualifier().hasStream() && glslangIntermediate->isMultiStream()) {
10819
0
        builder.addCapability(spv::Capability::GeometryStreams);
10820
0
        builder.addDecoration(id, spv::Decoration::Stream, symbol->getQualifier().layoutStream);
10821
0
    }
10822
21.5k
    if (symbol->getQualifier().hasSet())
10823
1.63k
        builder.addDecoration(id, spv::Decoration::DescriptorSet, symbol->getQualifier().layoutSet);
10824
19.9k
    else if (IsDescriptorResource(symbol->getType())) {
10825
        // default to 0
10826
2.51k
        builder.addDecoration(id, spv::Decoration::DescriptorSet, 0);
10827
2.51k
    }
10828
21.5k
    if (symbol->getQualifier().hasBinding())
10829
3.95k
        builder.addDecoration(id, spv::Decoration::Binding, symbol->getQualifier().layoutBinding);
10830
17.6k
    else if (IsDescriptorResource(symbol->getType())) {
10831
        // default to 0
10832
196
        builder.addDecoration(id, spv::Decoration::Binding, 0);
10833
196
    }
10834
21.5k
    if (symbol->getQualifier().hasAttachment())
10835
109
        builder.addDecoration(id, spv::Decoration::InputAttachmentIndex, symbol->getQualifier().layoutAttachment);
10836
21.5k
    if (glslangIntermediate->getXfbMode()) {
10837
0
        builder.addCapability(spv::Capability::TransformFeedback);
10838
0
        if (symbol->getQualifier().hasXfbBuffer()) {
10839
0
            builder.addDecoration(id, spv::Decoration::XfbBuffer, symbol->getQualifier().layoutXfbBuffer);
10840
0
            unsigned stride = glslangIntermediate->getXfbStride(symbol->getQualifier().layoutXfbBuffer);
10841
0
            if (stride != glslang::TQualifier::layoutXfbStrideEnd)
10842
0
                builder.addDecoration(id, spv::Decoration::XfbStride, stride);
10843
0
        }
10844
0
        if (symbol->getQualifier().hasXfbOffset())
10845
0
            builder.addDecoration(id, spv::Decoration::Offset, symbol->getQualifier().layoutXfbOffset);
10846
0
    }
10847
10848
    // add built-in variable decoration
10849
21.5k
    if (builtIn != spv::BuiltIn::Max) {
10850
        // WorkgroupSize deprecated in spirv1.6
10851
191
        if (glslangIntermediate->getSpv().spv < glslang::EShTargetSpv_1_6 ||
10852
0
            builtIn != spv::BuiltIn::WorkgroupSize)
10853
191
            builder.addDecoration(id, spv::Decoration::BuiltIn, (int)builtIn);
10854
191
    }
10855
10856
    // Add volatile decoration to HelperInvocation for spirv1.6 and beyond
10857
21.5k
    if (builtIn == spv::BuiltIn::HelperInvocation &&
10858
2
        !glslangIntermediate->usingVulkanMemoryModel() &&
10859
1
        glslangIntermediate->getSpv().spv >= glslang::EShTargetSpv_1_6) {
10860
0
        builder.addDecoration(id, spv::Decoration::Volatile);
10861
0
    }
10862
10863
    // Subgroup builtins which have input storage class are volatile for ray tracing stages.
10864
21.5k
    if (symbol->getType().isImage() || symbol->getQualifier().isPipeInput()) {
10865
2.50k
        std::vector<spv::Decoration> memory;
10866
2.50k
        TranslateMemoryDecoration(symbol->getType().getQualifier(), memory,
10867
2.50k
            glslangIntermediate->usingVulkanMemoryModel());
10868
3.32k
        for (unsigned int i = 0; i < memory.size(); ++i)
10869
816
            builder.addDecoration(id, memory[i]);
10870
2.50k
    }
10871
10872
21.5k
    if (builtIn == spv::BuiltIn::SampleMask) {
10873
2
          spv::Decoration decoration;
10874
          // GL_NV_sample_mask_override_coverage extension
10875
2
          if (glslangIntermediate->getLayoutOverrideCoverage())
10876
0
              decoration = spv::Decoration::OverrideCoverageNV;
10877
2
          else
10878
2
              decoration = spv::Decoration::Max;
10879
2
        builder.addDecoration(id, decoration);
10880
2
        if (decoration != spv::Decoration::Max) {
10881
0
            builder.addCapability(spv::Capability::SampleMaskOverrideCoverageNV);
10882
0
            builder.addExtension(spv::E_SPV_NV_sample_mask_override_coverage);
10883
0
        }
10884
2
    }
10885
21.5k
    else if (builtIn == spv::BuiltIn::Layer) {
10886
        // SPV_NV_viewport_array2 extension
10887
0
        if (symbol->getQualifier().layoutViewportRelative) {
10888
0
            builder.addDecoration(id, spv::Decoration::ViewportRelativeNV);
10889
0
            builder.addCapability(spv::Capability::ShaderViewportMaskNV);
10890
0
            builder.addExtension(spv::E_SPV_NV_viewport_array2);
10891
0
        }
10892
0
        if (symbol->getQualifier().layoutSecondaryViewportRelativeOffset != -2048) {
10893
0
            builder.addDecoration(id, spv::Decoration::SecondaryViewportRelativeNV,
10894
0
                                  symbol->getQualifier().layoutSecondaryViewportRelativeOffset);
10895
0
            builder.addCapability(spv::Capability::ShaderStereoViewNV);
10896
0
            builder.addExtension(spv::E_SPV_NV_stereo_view_rendering);
10897
0
        }
10898
0
    }
10899
10900
21.5k
    if (symbol->getQualifier().layoutPassthrough) {
10901
0
        builder.addDecoration(id, spv::Decoration::PassthroughNV);
10902
0
        builder.addCapability(spv::Capability::GeometryShaderPassthroughNV);
10903
0
        builder.addExtension(spv::E_SPV_NV_geometry_shader_passthrough);
10904
0
    }
10905
21.5k
    if (symbol->getQualifier().pervertexNV) {
10906
3
        builder.addDecoration(id, spv::Decoration::PerVertexNV);
10907
3
        builder.addCapability(spv::Capability::FragmentBarycentricNV);
10908
3
        builder.addExtension(spv::E_SPV_NV_fragment_shader_barycentric);
10909
3
    }
10910
10911
21.5k
    if (symbol->getQualifier().pervertexEXT) {
10912
3
        builder.addDecoration(id, spv::Decoration::PerVertexKHR);
10913
3
        builder.addCapability(spv::Capability::FragmentBarycentricKHR);
10914
3
        builder.addExtension(spv::E_SPV_KHR_fragment_shader_barycentric);
10915
3
    }
10916
10917
21.5k
    if (glslangIntermediate->getHlslFunctionality1() && symbol->getType().getQualifier().semanticName != nullptr) {
10918
4
        builder.addExtension("SPV_GOOGLE_hlsl_functionality1");
10919
4
        builder.addDecoration(id, spv::Decoration::HlslSemanticGOOGLE,
10920
4
                              symbol->getType().getQualifier().semanticName);
10921
4
    }
10922
10923
21.5k
    if (symbol->isReference()) {
10924
345
        builder.addDecoration(id, symbol->getType().getQualifier().restrict ?
10925
341
            spv::Decoration::RestrictPointerEXT : spv::Decoration::AliasedPointerEXT);
10926
345
    }
10927
10928
    // Add SPIR-V decorations (GL_EXT_spirv_intrinsics)
10929
21.5k
    if (symbol->getType().getQualifier().hasSpirvDecorate())
10930
273
        applySpirvDecorate(symbol->getType(), id, {});
10931
10932
21.5k
    return id;
10933
21.5k
}
10934
10935
// add per-primitive, per-view. per-task decorations to a struct member (member >= 0) or an object
10936
void TGlslangToSpvTraverser::addMeshNVDecoration(spv::Id id, int member, const glslang::TQualifier& qualifier)
10937
20.2k
{
10938
20.2k
    bool isMeshShaderExt = (glslangIntermediate->getRequestedExtensions().find(glslang::E_GL_EXT_mesh_shader) !=
10939
20.2k
                            glslangIntermediate->getRequestedExtensions().end());
10940
10941
20.2k
    if (member >= 0) {
10942
22
        if (qualifier.perPrimitiveNV) {
10943
            // Need to add capability/extension for fragment shader.
10944
            // Mesh shader already adds this by default.
10945
0
            if (glslangIntermediate->getStage() == EShLangFragment) {
10946
0
                if(isMeshShaderExt) {
10947
0
                    builder.addCapability(spv::Capability::MeshShadingEXT);
10948
0
                    builder.addExtension(spv::E_SPV_EXT_mesh_shader);
10949
0
                } else {
10950
0
                    builder.addCapability(spv::Capability::MeshShadingNV);
10951
0
                    builder.addExtension(spv::E_SPV_NV_mesh_shader);
10952
0
                }
10953
0
            }
10954
0
            builder.addMemberDecoration(id, (unsigned)member, spv::Decoration::PerPrimitiveNV);
10955
0
        }
10956
22
        if (qualifier.perViewNV)
10957
0
            builder.addMemberDecoration(id, (unsigned)member, spv::Decoration::PerViewNV);
10958
22
        if (qualifier.perTaskNV)
10959
0
            builder.addMemberDecoration(id, (unsigned)member, spv::Decoration::PerTaskNV);
10960
20.2k
    } else {
10961
20.2k
        if (qualifier.perPrimitiveNV) {
10962
            // Need to add capability/extension for fragment shader.
10963
            // Mesh shader already adds this by default.
10964
0
            if (glslangIntermediate->getStage() == EShLangFragment) {
10965
0
                if(isMeshShaderExt) {
10966
0
                    builder.addCapability(spv::Capability::MeshShadingEXT);
10967
0
                    builder.addExtension(spv::E_SPV_EXT_mesh_shader);
10968
0
                } else {
10969
0
                    builder.addCapability(spv::Capability::MeshShadingNV);
10970
0
                    builder.addExtension(spv::E_SPV_NV_mesh_shader);
10971
0
                }
10972
0
            }
10973
0
            builder.addDecoration(id, spv::Decoration::PerPrimitiveNV);
10974
0
        }
10975
20.2k
        if (qualifier.perViewNV)
10976
0
            builder.addDecoration(id, spv::Decoration::PerViewNV);
10977
20.2k
        if (qualifier.perTaskNV)
10978
0
            builder.addDecoration(id, spv::Decoration::PerTaskNV);
10979
20.2k
    }
10980
20.2k
}
10981
10982
bool TGlslangToSpvTraverser::hasQCOMImageProceessingDecoration(spv::Id id, spv::Decoration decor)
10983
497
{
10984
497
  std::vector<spv::Decoration> &decoVec = idToQCOMDecorations[id];
10985
497
  for ( auto d : decoVec ) {
10986
78
    if ( d == decor )
10987
26
      return true;
10988
78
  }
10989
471
  return false;
10990
497
}
10991
10992
void TGlslangToSpvTraverser::addImageProcessingQCOMDecoration(spv::Id id, spv::Decoration decor)
10993
289
{
10994
289
  spv::Op opc = builder.getOpCode(id);
10995
289
  if (opc == spv::Op::OpSampledImage) {
10996
143
    id  = builder.getIdOperand(id, 0);
10997
143
    opc = builder.getOpCode(id);
10998
143
  }
10999
11000
289
  if (opc == spv::Op::OpLoad) {
11001
289
    spv::Id texid = builder.getIdOperand(id, 0);
11002
289
    if (!hasQCOMImageProceessingDecoration(texid, decor)) {//
11003
289
      builder.addDecoration(texid, decor);
11004
289
      idToQCOMDecorations[texid].push_back(decor);
11005
289
    }
11006
289
  }
11007
289
}
11008
11009
void TGlslangToSpvTraverser::addImageProcessing2QCOMDecoration(spv::Id id, bool isForGather)
11010
208
{
11011
208
  if (isForGather) {
11012
104
    return addImageProcessingQCOMDecoration(id, spv::Decoration::BlockMatchTextureQCOM);
11013
104
  }
11014
11015
104
  auto addDecor =
11016
208
    [this](spv::Id id, spv::Decoration decor) {
11017
208
      spv::Op tsopc = this->builder.getOpCode(id);
11018
208
      if (tsopc == spv::Op::OpLoad) {
11019
208
        spv::Id tsid = this->builder.getIdOperand(id, 0);
11020
208
        if (this->glslangIntermediate->getSpv().spv >= glslang::EShTargetSpv_1_4) {
11021
0
          assert(iOSet.count(tsid) > 0);
11022
0
        }
11023
208
        if (!hasQCOMImageProceessingDecoration(tsid, decor)) {
11024
182
          this->builder.addDecoration(tsid, decor);
11025
182
          idToQCOMDecorations[tsid].push_back(decor);
11026
182
        }
11027
208
      }
11028
208
    };
11029
11030
104
  spv::Op opc = builder.getOpCode(id);
11031
104
  bool isInterfaceObject = (opc != spv::Op::OpSampledImage);
11032
11033
104
  if (!isInterfaceObject) {
11034
52
    addDecor(builder.getIdOperand(id, 0), spv::Decoration::BlockMatchTextureQCOM);
11035
52
    addDecor(builder.getIdOperand(id, 1), spv::Decoration::BlockMatchSamplerQCOM);
11036
52
  } else {
11037
52
    addDecor(id, spv::Decoration::BlockMatchTextureQCOM);
11038
52
    addDecor(id, spv::Decoration::BlockMatchSamplerQCOM);
11039
52
  }
11040
104
}
11041
11042
// Make a full tree of instructions to build a SPIR-V specialization constant,
11043
// or regular constant if possible.
11044
//
11045
// TBD: this is not yet done, nor verified to be the best design, it does do the leaf symbols though
11046
//
11047
// Recursively walk the nodes.  The nodes form a tree whose leaves are
11048
// regular constants, which themselves are trees that createSpvConstant()
11049
// recursively walks.  So, this function walks the "top" of the tree:
11050
//  - emit specialization constant-building instructions for specConstant
11051
//  - when running into a non-spec-constant, switch to createSpvConstant()
11052
spv::Id TGlslangToSpvTraverser::createSpvConstant(const glslang::TIntermTyped& node)
11053
905
{
11054
905
    assert(node.getQualifier().isConstant());
11055
11056
    // Handle front-end constants first (non-specialization constants).
11057
905
    if (! node.getQualifier().specConstant) {
11058
        // hand off to the non-spec-constant path
11059
112
        assert(node.getAsConstantUnion() != nullptr || node.getAsSymbolNode() != nullptr);
11060
112
        int nextConst = 0;
11061
112
        return createSpvConstantFromConstUnionArray(node.getType(), node.getAsConstantUnion() ?
11062
112
            node.getAsConstantUnion()->getConstArray() : node.getAsSymbolNode()->getConstArray(),
11063
112
            nextConst, false);
11064
112
    }
11065
11066
    // We now know we have a specialization constant to build
11067
11068
    // Extra capabilities may be needed.
11069
793
    if (node.getType().contains8BitInt())
11070
27
        builder.addCapability(spv::Capability::Int8);
11071
793
    if (node.getType().contains16BitFloat())
11072
0
        builder.addCapability(spv::Capability::Float16);
11073
793
    if (node.getType().contains16BitInt())
11074
180
        builder.addCapability(spv::Capability::Int16);
11075
793
    if (node.getType().contains64BitInt())
11076
261
        builder.addCapability(spv::Capability::Int64);
11077
793
    if (node.getType().containsDouble())
11078
0
        builder.addCapability(spv::Capability::Float64);
11079
11080
    // gl_WorkGroupSize is a special case until the front-end handles hierarchical specialization constants,
11081
    // even then, it's specialization ids are handled by special case syntax in GLSL: layout(local_size_x = ...
11082
793
    if (node.getType().getQualifier().builtIn == glslang::EbvWorkGroupSize) {
11083
0
        std::vector<spv::Id> dimConstId;
11084
0
        for (int dim = 0; dim < 3; ++dim) {
11085
0
            bool specConst = (glslangIntermediate->getLocalSizeSpecId(dim) != glslang::TQualifier::layoutNotSet);
11086
0
            dimConstId.push_back(builder.makeUintConstant(glslangIntermediate->getLocalSize(dim), specConst));
11087
0
            if (specConst) {
11088
0
                builder.addDecoration(dimConstId.back(), spv::Decoration::SpecId,
11089
0
                                      glslangIntermediate->getLocalSizeSpecId(dim));
11090
0
            }
11091
0
        }
11092
0
        return builder.makeCompositeConstant(builder.makeVectorType(builder.makeUintType(32), 3), dimConstId, true);
11093
0
    }
11094
11095
    // An AST node labelled as specialization constant should be a symbol node.
11096
    // Its initializer should either be a sub tree with constant nodes, or a constant union array.
11097
793
    if (auto* sn = node.getAsSymbolNode()) {
11098
793
        spv::Id result;
11099
793
        if (auto* sub_tree = sn->getConstSubtree()) {
11100
            // Traverse the constant constructor sub tree like generating normal run-time instructions.
11101
            // During the AST traversal, if the node is marked as 'specConstant', SpecConstantOpModeGuard
11102
            // will set the builder into spec constant op instruction generating mode.
11103
478
            sub_tree->traverse(this);
11104
478
            result = accessChainLoad(sub_tree->getType());
11105
478
        } else if (auto* const_union_array = &sn->getConstArray()) {
11106
315
            int nextConst = 0;
11107
315
            result = createSpvConstantFromConstUnionArray(sn->getType(), *const_union_array, nextConst, true);
11108
315
        } else {
11109
0
            logger->missingFunctionality("Invalid initializer for spec constant.");
11110
0
            return spv::NoResult;
11111
0
        }
11112
793
        builder.addName(result, sn->getName().c_str());
11113
793
        return result;
11114
793
    }
11115
11116
    // Neither a front-end constant node, nor a specialization constant node with constant union array or
11117
    // constant sub tree as initializer.
11118
0
    logger->missingFunctionality("Neither a front-end constant nor a spec constant.");
11119
0
    return spv::NoResult;
11120
793
}
11121
11122
// Use 'consts' as the flattened glslang source of scalar constants to recursively
11123
// build the aggregate SPIR-V constant.
11124
//
11125
// If there are not enough elements present in 'consts', 0 will be substituted;
11126
// an empty 'consts' can be used to create a fully zeroed SPIR-V constant.
11127
//
11128
spv::Id TGlslangToSpvTraverser::createSpvConstantFromConstUnionArray(const glslang::TType& glslangType,
11129
    const glslang::TConstUnionArray& consts, int& nextConst, bool specConstant)
11130
24.6k
{
11131
    // vector of constants for SPIR-V
11132
24.6k
    std::vector<spv::Id> spvConsts;
11133
11134
    // Type is used for struct and array constants
11135
24.6k
    spv::Id typeId = convertGlslangToSpvType(glslangType);
11136
11137
24.6k
    if (glslangType.isArray()) {
11138
283
        glslang::TType elementType(glslangType, 0);
11139
1.36k
        for (int i = 0; i < glslangType.getOuterArraySize(); ++i)
11140
1.08k
            spvConsts.push_back(createSpvConstantFromConstUnionArray(elementType, consts, nextConst, false));
11141
24.3k
    } else if (glslangType.isMatrix()) {
11142
243
        glslang::TType vectorType(glslangType, 0);
11143
785
        for (int col = 0; col < glslangType.getMatrixCols(); ++col)
11144
542
            spvConsts.push_back(createSpvConstantFromConstUnionArray(vectorType, consts, nextConst, false));
11145
24.0k
    } else if (glslangType.isCoopMat()) {
11146
0
        glslang::TType componentType(glslangType.getBasicType());
11147
0
        spvConsts.push_back(createSpvConstantFromConstUnionArray(componentType, consts, nextConst, false));
11148
24.0k
    } else if (glslangType.isStruct()) {
11149
785
        glslang::TVector<glslang::TTypeLoc>::const_iterator iter;
11150
2.75k
        for (iter = glslangType.getStruct()->begin(); iter != glslangType.getStruct()->end(); ++iter)
11151
1.96k
            spvConsts.push_back(createSpvConstantFromConstUnionArray(*iter->type, consts, nextConst, false));
11152
23.3k
    } else if (glslangType.getVectorSize() > 1 || glslangType.isCoopVecNV()) {
11153
7.65k
        unsigned int numComponents = glslangType.isCoopVecNV() ? glslangType.getTypeParameters()->arraySizes->getDimSize(0) : glslangType.getVectorSize();
11154
29.3k
        for (unsigned int i = 0; i < numComponents; ++i) {
11155
21.7k
            bool zero = nextConst >= consts.size();
11156
21.7k
            switch (glslangType.getBasicType()) {
11157
6.51k
            case glslang::EbtInt:
11158
6.51k
                spvConsts.push_back(builder.makeIntConstant(zero ? 0 : consts[nextConst].getIConst()));
11159
6.51k
                break;
11160
1.65k
            case glslang::EbtUint:
11161
1.65k
                spvConsts.push_back(builder.makeUintConstant(zero ? 0 : consts[nextConst].getUConst()));
11162
1.65k
                break;
11163
4.19k
            case glslang::EbtFloat:
11164
4.19k
                spvConsts.push_back(builder.makeFloatConstant(zero ? 0.0F : (float)consts[nextConst].getDConst()));
11165
4.19k
                break;
11166
65
            case glslang::EbtBool:
11167
65
                spvConsts.push_back(builder.makeBoolConstant(zero ? false : consts[nextConst].getBConst()));
11168
65
                break;
11169
1.40k
            case glslang::EbtInt8:
11170
1.40k
                builder.addCapability(spv::Capability::Int8);
11171
1.40k
                spvConsts.push_back(builder.makeInt8Constant(zero ? 0 : consts[nextConst].getI8Const()));
11172
1.40k
                break;
11173
1.40k
            case glslang::EbtUint8:
11174
1.40k
                builder.addCapability(spv::Capability::Int8);
11175
1.40k
                spvConsts.push_back(builder.makeUint8Constant(zero ? 0 : consts[nextConst].getU8Const()));
11176
1.40k
                break;
11177
1.39k
            case glslang::EbtInt16:
11178
1.39k
                builder.addCapability(spv::Capability::Int16);
11179
1.39k
                spvConsts.push_back(builder.makeInt16Constant(zero ? 0 : consts[nextConst].getI16Const()));
11180
1.39k
                break;
11181
1.42k
            case glslang::EbtUint16:
11182
1.42k
                builder.addCapability(spv::Capability::Int16);
11183
1.42k
                spvConsts.push_back(builder.makeUint16Constant(zero ? 0 : consts[nextConst].getU16Const()));
11184
1.42k
                break;
11185
1.38k
            case glslang::EbtInt64:
11186
1.38k
                spvConsts.push_back(builder.makeInt64Constant(zero ? 0 : consts[nextConst].getI64Const()));
11187
1.38k
                break;
11188
1.38k
            case glslang::EbtUint64:
11189
1.38k
                spvConsts.push_back(builder.makeUint64Constant(zero ? 0 : consts[nextConst].getU64Const()));
11190
1.38k
                break;
11191
0
            case glslang::EbtDouble:
11192
0
                spvConsts.push_back(builder.makeDoubleConstant(zero ? 0.0 : consts[nextConst].getDConst()));
11193
0
                break;
11194
918
            case glslang::EbtFloat16:
11195
918
                builder.addCapability(spv::Capability::Float16);
11196
918
                spvConsts.push_back(builder.makeFloat16Constant(zero ? 0.0F : (float)consts[nextConst].getDConst()));
11197
918
                break;
11198
0
            case glslang::EbtBFloat16:
11199
0
                spvConsts.push_back(builder.makeBFloat16Constant(zero ? 0.0F : (float)consts[nextConst].getDConst()));
11200
0
                break;
11201
0
            case glslang::EbtFloatE5M2:
11202
0
                spvConsts.push_back(builder.makeFloatE5M2Constant(zero ? 0.0F : (float)consts[nextConst].getDConst()));
11203
0
                break;
11204
0
            case glslang::EbtFloatE4M3:
11205
0
                spvConsts.push_back(builder.makeFloatE4M3Constant(zero ? 0.0F : (float)consts[nextConst].getDConst()));
11206
0
                break;
11207
0
            default:
11208
0
                assert(0);
11209
0
                break;
11210
21.7k
            }
11211
21.7k
            ++nextConst;
11212
21.7k
        }
11213
15.6k
    } else {
11214
        // we have a non-aggregate (scalar) constant
11215
15.6k
        bool zero = nextConst >= consts.size();
11216
15.6k
        spv::Id scalar = 0;
11217
15.6k
        switch (glslangType.getBasicType()) {
11218
6.21k
        case glslang::EbtInt:
11219
6.21k
            scalar = builder.makeIntConstant(zero ? 0 : consts[nextConst].getIConst(), specConstant);
11220
6.21k
            break;
11221
925
        case glslang::EbtUint:
11222
925
            scalar = builder.makeUintConstant(zero ? 0 : consts[nextConst].getUConst(), specConstant);
11223
925
            break;
11224
5.84k
        case glslang::EbtFloat:
11225
5.84k
            scalar = builder.makeFloatConstant(zero ? 0.0F : (float)consts[nextConst].getDConst(), specConstant);
11226
5.84k
            break;
11227
1.45k
        case glslang::EbtBool:
11228
1.45k
            scalar = builder.makeBoolConstant(zero ? false : consts[nextConst].getBConst(), specConstant);
11229
1.45k
            break;
11230
47
        case glslang::EbtInt8:
11231
47
            builder.addCapability(spv::Capability::Int8);
11232
47
            scalar = builder.makeInt8Constant(zero ? 0 : consts[nextConst].getI8Const(), specConstant);
11233
47
            break;
11234
49
        case glslang::EbtUint8:
11235
49
            builder.addCapability(spv::Capability::Int8);
11236
49
            scalar = builder.makeUint8Constant(zero ? 0 : consts[nextConst].getU8Const(), specConstant);
11237
49
            break;
11238
117
        case glslang::EbtInt16:
11239
117
            builder.addCapability(spv::Capability::Int16);
11240
117
            scalar = builder.makeInt16Constant(zero ? 0 : consts[nextConst].getI16Const(), specConstant);
11241
117
            break;
11242
116
        case glslang::EbtUint16:
11243
116
            builder.addCapability(spv::Capability::Int16);
11244
116
            scalar = builder.makeUint16Constant(zero ? 0 : consts[nextConst].getU16Const(), specConstant);
11245
116
            break;
11246
125
        case glslang::EbtInt64:
11247
125
            scalar = builder.makeInt64Constant(zero ? 0 : consts[nextConst].getI64Const(), specConstant);
11248
125
            break;
11249
513
        case glslang::EbtUint64:
11250
513
            scalar = builder.makeUint64Constant(zero ? 0 : consts[nextConst].getU64Const(), specConstant);
11251
513
            break;
11252
34
        case glslang::EbtDouble:
11253
34
            scalar = builder.makeDoubleConstant(zero ? 0.0 : consts[nextConst].getDConst(), specConstant);
11254
34
            break;
11255
34
        case glslang::EbtFloat16:
11256
34
            builder.addCapability(spv::Capability::Float16);
11257
34
            scalar = builder.makeFloat16Constant(zero ? 0.0F : (float)consts[nextConst].getDConst(), specConstant);
11258
34
            break;
11259
0
        case glslang::EbtBFloat16:
11260
0
            scalar = builder.makeBFloat16Constant(zero ? 0.0F : (float)consts[nextConst].getDConst(), specConstant);
11261
0
            break;
11262
0
        case glslang::EbtFloatE5M2:
11263
0
            scalar = builder.makeFloatE5M2Constant(zero ? 0.0F : (float)consts[nextConst].getDConst(), specConstant);
11264
0
            break;
11265
0
        case glslang::EbtFloatE4M3:
11266
0
            scalar = builder.makeFloatE4M3Constant(zero ? 0.0F : (float)consts[nextConst].getDConst(), specConstant);
11267
0
            break;
11268
135
        case glslang::EbtReference:
11269
135
            scalar = builder.makeUint64Constant(zero ? 0 : consts[nextConst].getU64Const(), specConstant);
11270
135
            scalar = builder.createUnaryOp(spv::Op::OpBitcast, typeId, scalar);
11271
135
            break;
11272
51
        case glslang::EbtString:
11273
51
            scalar = builder.getStringId(consts[nextConst].getSConst()->c_str());
11274
51
            break;
11275
0
        default:
11276
0
            assert(0);
11277
0
            break;
11278
15.6k
        }
11279
15.6k
        ++nextConst;
11280
15.6k
        return scalar;
11281
15.6k
    }
11282
11283
8.96k
    return builder.makeCompositeConstant(typeId, spvConsts);
11284
24.6k
}
11285
11286
// Return true if the node is a constant or symbol whose reading has no
11287
// non-trivial observable cost or effect.
11288
bool TGlslangToSpvTraverser::isTrivialLeaf(const glslang::TIntermTyped* node)
11289
1.41k
{
11290
    // don't know what this is
11291
1.41k
    if (node == nullptr)
11292
0
        return false;
11293
11294
    // a constant is safe
11295
1.41k
    if (node->getAsConstantUnion() != nullptr)
11296
10
        return true;
11297
11298
    // not a symbol means non-trivial
11299
1.40k
    if (node->getAsSymbolNode() == nullptr)
11300
823
        return false;
11301
11302
    // a symbol, depends on what's being read
11303
586
    switch (node->getType().getQualifier().storage) {
11304
586
    case glslang::EvqTemporary:
11305
586
    case glslang::EvqGlobal:
11306
586
    case glslang::EvqIn:
11307
586
    case glslang::EvqInOut:
11308
586
    case glslang::EvqConst:
11309
586
    case glslang::EvqConstReadOnly:
11310
586
    case glslang::EvqUniform:
11311
586
        return true;
11312
0
    default:
11313
0
        return false;
11314
586
    }
11315
586
}
11316
11317
// A node is trivial if it is a single operation with no side effects.
11318
// HLSL (and/or vectors) are always trivial, as it does not short circuit.
11319
// Otherwise, error on the side of saying non-trivial.
11320
// Return true if trivial.
11321
bool TGlslangToSpvTraverser::isTrivial(const glslang::TIntermTyped* node)
11322
863
{
11323
863
    if (node == nullptr)
11324
0
        return false;
11325
11326
    // count non scalars as trivial, as well as anything coming from HLSL
11327
863
    if (! node->getType().isScalarOrVec1() || glslangIntermediate->getSource() == glslang::EShSourceHlsl)
11328
0
        return true;
11329
11330
    // symbols and constants are trivial
11331
863
    if (isTrivialLeaf(node))
11332
404
        return true;
11333
11334
    // otherwise, it needs to be a simple operation or one or two leaf nodes
11335
11336
    // not a simple operation
11337
459
    const glslang::TIntermBinary* binaryNode = node->getAsBinaryNode();
11338
459
    const glslang::TIntermUnary* unaryNode = node->getAsUnaryNode();
11339
459
    if (binaryNode == nullptr && unaryNode == nullptr)
11340
85
        return false;
11341
11342
    // not on leaf nodes
11343
374
    if (binaryNode && (! isTrivialLeaf(binaryNode->getLeft()) || ! isTrivialLeaf(binaryNode->getRight())))
11344
364
        return false;
11345
11346
10
    if (unaryNode && ! isTrivialLeaf(unaryNode->getOperand())) {
11347
0
        return false;
11348
0
    }
11349
11350
10
    if (IsOpNumericConv(node->getAsOperator()->getOp()) &&
11351
0
        node->getType().getBasicType() == glslang::EbtBool) {
11352
0
        return true;
11353
0
    }
11354
11355
10
    switch (node->getAsOperator()->getOp()) {
11356
0
    case glslang::EOpLogicalNot:
11357
10
    case glslang::EOpEqual:
11358
10
    case glslang::EOpNotEqual:
11359
10
    case glslang::EOpLessThan:
11360
10
    case glslang::EOpGreaterThan:
11361
10
    case glslang::EOpLessThanEqual:
11362
10
    case glslang::EOpGreaterThanEqual:
11363
10
    case glslang::EOpIndexDirect:
11364
10
    case glslang::EOpIndexDirectStruct:
11365
10
    case glslang::EOpLogicalXor:
11366
10
    case glslang::EOpAny:
11367
10
    case glslang::EOpAll:
11368
10
        return true;
11369
0
    default:
11370
0
        return false;
11371
10
    }
11372
10
}
11373
11374
// Emit short-circuiting code, where 'right' is never evaluated unless
11375
// the left side is true (for &&) or false (for ||).
11376
spv::Id TGlslangToSpvTraverser::createShortCircuit(glslang::TOperator op, glslang::TIntermTyped& left,
11377
    glslang::TIntermTyped& right)
11378
449
{
11379
449
    spv::Id boolTypeId = builder.makeBoolType();
11380
11381
    // emit left operand
11382
449
    builder.clearAccessChain();
11383
449
    left.traverse(this);
11384
449
    spv::Id leftId = accessChainLoad(left.getType());
11385
11386
    // Operands to accumulate OpPhi operands
11387
449
    std::vector<spv::Id> phiOperands;
11388
449
    phiOperands.reserve(4);
11389
    // accumulate left operand's phi information
11390
449
    phiOperands.push_back(leftId);
11391
449
    phiOperands.push_back(builder.getBuildPoint()->getId());
11392
11393
    // Make the two kinds of operation symmetric with a "!"
11394
    //   || => emit "if (! left) result = right"
11395
    //   && => emit "if (  left) result = right"
11396
    //
11397
    // TODO: this runtime "not" for || could be avoided by adding functionality
11398
    // to 'builder' to have an "else" without an "then"
11399
449
    if (op == glslang::EOpLogicalOr)
11400
10
        leftId = builder.createUnaryOp(spv::Op::OpLogicalNot, boolTypeId, leftId);
11401
11402
    // make an "if" based on the left value
11403
449
    spv::Builder::If ifBuilder(leftId, spv::SelectionControlMask::MaskNone, builder);
11404
11405
    // emit right operand as the "then" part of the "if"
11406
449
    builder.clearAccessChain();
11407
449
    right.traverse(this);
11408
449
    spv::Id rightId = accessChainLoad(right.getType());
11409
11410
    // accumulate left operand's phi information
11411
449
    phiOperands.push_back(rightId);
11412
449
    phiOperands.push_back(builder.getBuildPoint()->getId());
11413
11414
    // finish the "if"
11415
449
    ifBuilder.makeEndIf();
11416
11417
    // phi together the two results
11418
449
    return builder.createOp(spv::Op::OpPhi, boolTypeId, phiOperands);
11419
449
}
11420
11421
// Return type Id of the imported set of extended instructions corresponds to the name.
11422
// Import this set if it has not been imported yet.
11423
spv::Id TGlslangToSpvTraverser::getExtBuiltins(const char* name)
11424
46
{
11425
46
    if (extBuiltinMap.find(name) != extBuiltinMap.end())
11426
0
        return extBuiltinMap[name];
11427
46
    else {
11428
46
        spv::Id extBuiltins = builder.import(name);
11429
46
        extBuiltinMap[name] = extBuiltins;
11430
46
        return extBuiltins;
11431
46
    }
11432
46
}
11433
11434
} // end anonymous namespace
11435
11436
namespace glslang {
11437
11438
void GetSpirvVersion(std::string& version)
11439
0
{
11440
0
    const int bufSize = 100;
11441
0
    char buf[bufSize];
11442
0
    snprintf(buf, bufSize, "0x%08x, Revision %d", spv::Version, spv::Revision);
11443
0
    version = buf;
11444
0
}
11445
11446
// For low-order part of the generator's magic number. Bump up
11447
// when there is a change in the style (e.g., if SSA form changes,
11448
// or a different instruction sequence to do something gets used).
11449
int GetSpirvGeneratorVersion()
11450
2.08k
{
11451
    // return 1; // start
11452
    // return 2; // EOpAtomicCounterDecrement gets a post decrement, to map between GLSL -> SPIR-V
11453
    // return 3; // change/correct barrier-instruction operands, to match memory model group decisions
11454
    // return 4; // some deeper access chains: for dynamic vector component, and local Boolean component
11455
    // return 5; // make OpArrayLength result type be an int with signedness of 0
11456
    // return 6; // revert version 5 change, which makes a different (new) kind of incorrect code,
11457
                 // versions 4 and 6 each generate OpArrayLength as it has long been done
11458
    // return 7; // GLSL volatile keyword maps to both SPIR-V decorations Volatile and Coherent
11459
    // return 8; // switch to new dead block eliminator; use OpUnreachable
11460
    // return 9; // don't include opaque function parameters in OpEntryPoint global's operand list
11461
    // return 10; // Generate OpFUnordNotEqual for != comparisons
11462
2.08k
    return 11; // Make OpEmitMeshTasksEXT a terminal instruction
11463
2.08k
}
11464
11465
// Write SPIR-V out to a binary file
11466
bool OutputSpvBin(const std::vector<unsigned int>& spirv, const char* baseName)
11467
0
{
11468
0
    std::ofstream out;
11469
0
    out.open(baseName, std::ios::binary | std::ios::out);
11470
0
    if (out.fail()) {
11471
0
        printf("ERROR: Failed to open file: %s\n", baseName);
11472
0
        return false;
11473
0
    }
11474
0
    for (int i = 0; i < (int)spirv.size(); ++i) {
11475
0
        unsigned int word = spirv[i];
11476
0
        out.write((const char*)&word, 4);
11477
0
    }
11478
0
    out.close();
11479
0
    return true;
11480
0
}
11481
11482
// Write SPIR-V out to a text file with 32-bit hexadecimal words
11483
bool OutputSpvHex(const std::vector<unsigned int>& spirv, const char* baseName, const char* varName)
11484
0
{
11485
0
    std::ofstream out;
11486
0
    out.open(baseName, std::ios::binary | std::ios::out);
11487
0
    if (out.fail()) {
11488
0
        printf("ERROR: Failed to open file: %s\n", baseName);
11489
0
        return false;
11490
0
    }
11491
0
    out << "\t// " <<
11492
0
        GetSpirvGeneratorVersion() <<
11493
0
        GLSLANG_VERSION_MAJOR << "." << GLSLANG_VERSION_MINOR << "." << GLSLANG_VERSION_PATCH <<
11494
0
        GLSLANG_VERSION_FLAVOR << std::endl;
11495
0
    if (varName != nullptr) {
11496
0
        out << "\t #pragma once" << std::endl;
11497
0
        out << "const uint32_t " << varName << "[] = {" << std::endl;
11498
0
    }
11499
0
    const int WORDS_PER_LINE = 8;
11500
0
    for (int i = 0; i < (int)spirv.size(); i += WORDS_PER_LINE) {
11501
0
        out << "\t";
11502
0
        for (int j = 0; j < WORDS_PER_LINE && i + j < (int)spirv.size(); ++j) {
11503
0
            const unsigned int word = spirv[i + j];
11504
0
            out << "0x" << std::hex << std::setw(8) << std::setfill('0') << word;
11505
0
            if (i + j + 1 < (int)spirv.size()) {
11506
0
                out << ",";
11507
0
            }
11508
0
        }
11509
0
        out << std::endl;
11510
0
    }
11511
0
    if (varName != nullptr) {
11512
0
        out << "};";
11513
0
        out << std::endl;
11514
0
    }
11515
0
    out.close();
11516
0
    return true;
11517
0
}
11518
11519
//
11520
// Set up the glslang traversal
11521
//
11522
void GlslangToSpv(const TIntermediate& intermediate, std::vector<unsigned int>& spirv, SpvOptions* options)
11523
2.08k
{
11524
2.08k
    spv::SpvBuildLogger logger;
11525
2.08k
    GlslangToSpv(intermediate, spirv, &logger, options);
11526
2.08k
}
11527
11528
void GlslangToSpv(const TIntermediate& intermediate, std::vector<unsigned int>& spirv,
11529
                  spv::SpvBuildLogger* logger, SpvOptions* options)
11530
2.08k
{
11531
2.08k
    TIntermNode* root = intermediate.getTreeRoot();
11532
11533
2.08k
    if (root == nullptr)
11534
0
        return;
11535
11536
2.08k
    SpvOptions defaultOptions;
11537
2.08k
    if (options == nullptr)
11538
0
        options = &defaultOptions;
11539
11540
2.08k
    GetThreadPoolAllocator().push();
11541
11542
2.08k
    TGlslangToSpvTraverser it(intermediate.getSpv().spv, &intermediate, logger, *options);
11543
2.08k
    root->traverse(&it);
11544
2.08k
    it.finishSpv(options->compileOnly);
11545
2.08k
    it.dumpSpv(spirv);
11546
11547
2.08k
#if ENABLE_OPT
11548
    // If from HLSL, run spirv-opt to "legalize" the SPIR-V for Vulkan
11549
    // eg. forward and remove memory writes of opaque types.
11550
2.08k
    bool prelegalization = intermediate.getSource() == EShSourceHlsl;
11551
2.08k
    if ((prelegalization || options->optimizeSize) && !options->disableOptimizer) {
11552
0
        SpirvToolsTransform(intermediate, spirv, logger, options);
11553
0
        prelegalization = false;
11554
0
    }
11555
2.08k
    else if (options->stripDebugInfo) {
11556
        // Strip debug info even if optimization is disabled.
11557
0
        SpirvToolsStripDebugInfo(intermediate, spirv, logger);
11558
0
    }
11559
11560
2.08k
    if (options->validate)
11561
0
        SpirvToolsValidate(intermediate, spirv, logger, prelegalization);
11562
11563
2.08k
    if (options->disassemble)
11564
0
        SpirvToolsDisassemble(std::cout, spirv);
11565
11566
2.08k
#endif
11567
11568
2.08k
    GetThreadPoolAllocator().pop();
11569
2.08k
}
11570
11571
} // end namespace glslang