yum-mirror/glslang

git clone https://git.yummers.dev/yum-mirror/glslang

Saqib KhanHandle spirv_literal operands in spirv_instruction with a set (#4454)c97e126b

main
65.8 KiB1481 linesraw
1//
2// Copyright (C) 2014-2015 LunarG, Inc.
3// Copyright (C) 2015-2020 Google, Inc.
4// Copyright (C) 2017 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// "Builder" is an interface to fully build SPIR-V IR.   Allocate one of
40// these to build (a thread safe) internal SPIR-V representation (IR),
41// and then dump it as a binary stream according to the SPIR-V specification.
42//
43// A Builder has a 1:1 relationship with a SPIR-V module.
44//
45
46#pragma once
47#ifndef SpvBuilder_H
48#define SpvBuilder_H
49
50#include "Logger.h"
51#define SPV_ENABLE_UTILITY_CODE
52#include "spirv.hpp11"
53#include "spvIR.h"
54#include "spvUtil.h"
55
56namespace spv {
57    #include "GLSL.ext.KHR.h"
58    #include "GLSL.ext.EXT.h"
59    #include "NonSemanticShaderDebugInfo.h"
60}
61
62#include <algorithm>
63#include <cstdint>
64#include <map>
65#include <memory>
66#include <set>
67#include <sstream>
68#include <stack>
69#include <unordered_map>
70#include <unordered_set>
71#include <map>
72
73namespace spv {
74
75typedef enum {
76    Spv_1_0 = (1 << 16),
77    Spv_1_1 = (1 << 16) | (1 << 8),
78    Spv_1_2 = (1 << 16) | (2 << 8),
79    Spv_1_3 = (1 << 16) | (3 << 8),
80    Spv_1_4 = (1 << 16) | (4 << 8),
81    Spv_1_5 = (1 << 16) | (5 << 8),
82    Spv_1_6 = (1 << 16) | (6 << 8),
83} SpvVersion;
84
85struct StructMemberDebugInfo {
86    std::string name {};
87    int line {0};
88    int column {0};
89    // Set if the caller knows a better debug type than what is associated with the functional SPIR-V type.
90    spv::Id debugTypeOverride {0};
91};
92
93class Builder {
94    class CompositeConstantKey {
95    public:
96        enum Kind {
97            Key_Instruction,
98            Key_CompositeConstant,
99        };
100
101        CompositeConstantKey(
102            Op typeClass, Instruction* instruction)
103        : kind(Key_Instruction)
104        , instruction(instruction)
105        , typeClass(typeClass)
106        , opcode(Op::OpNop)
107        , typeId(NoType)
108        , numMembers(0)
109        , comps()
110        {}
111
112        CompositeConstantKey(
113            Op typeClass, Op opcode, Id typeId, const std::vector<Id>& comps, size_t numMembers)
114        : kind(Key_CompositeConstant)
115        , instruction(nullptr)
116        , typeClass(typeClass)
117        , opcode(opcode)
118        , typeId(typeId)
119        , numMembers(numMembers)
120        , comps(comps)
121        {}
122
123        Instruction* getInstruction() const {
124            return instruction;
125        }
126
127        // Functor to hash an instruction key.
128        struct Hash {
129            size_t operator()(CompositeConstantKey const &key) const {
130                switch (key.kind) {
131                case Key_Instruction:
132                    {
133                        Instruction* constant = key.instruction;
134                        size_t num_operands = constant->getNumOperands();
135                        size_t hash = std::hash<Op>()(key.typeClass) * 7 ^
136                            std::hash<Op>()(constant->getOpCode()) * 11 ^
137                            std::hash<Id>()(constant->getTypeId()) * 13 ^
138                            std::hash<size_t>()(num_operands) * 17;
139                        for (size_t i = 0; i < num_operands; ++i) {
140                            hash = hash * 19 ^ std::hash<Id>()(constant->getIdOperand(i));
141                        }
142                        return hash;
143                    }
144                case Key_CompositeConstant:
145                    {
146                        size_t hash = std::hash<Op>()(key.typeClass) * 7 ^
147                            std::hash<Op>()(key.opcode) * 11 ^
148                            std::hash<Id>()(key.typeId) * 13 ^
149                            std::hash<size_t>()(key.numMembers) * 17;
150                        for (size_t i = 0; i < key.numMembers; ++i) {
151                            hash = hash * 19 ^ std::hash<Id>()(key.comps[i]);
152                        }
153                        return hash;
154                    }
155                }
156                return 0;
157            }
158        };
159
160        // Functor to compare two instruction keys.
161        struct Equal {
162            bool operator() (CompositeConstantKey const &a, CompositeConstantKey const &b) const
163            {
164                if (a.typeClass != b.typeClass)
165                    return false;
166
167                if (a.kind == b.kind) {
168                    // we need only the Instruction case, as the other keys only used for searching
169                    return
170                        a.kind == Key_Instruction &&
171                        a.instruction == b.instruction;
172                }
173                const CompositeConstantKey* s = &a;
174                const CompositeConstantKey* o = &b;
175
176                if (s->kind == Key_CompositeConstant && o->kind == Key_Instruction) {
177                    s = o;
178                    o = &a;
179                }
180
181                // compare a composite constant with an instruction
182                if (s->kind == Key_Instruction && o->kind == Key_CompositeConstant) {
183                    Instruction* constant = s->instruction;
184                    if (constant->getTypeId() != o->typeId)
185                        return false;
186
187                    if (constant->getOpCode() != o->opcode) {
188                        return false;
189                    }
190
191                    if (constant->getNumOperands() != (int)o->numMembers)
192                        return false;
193
194                    // same contents?
195                    for (int op = 0; op < constant->getNumOperands(); ++op) {
196                        if (constant->getIdOperand(op) != o->comps[op]) {
197                            return false;
198                        }
199                    }
200                    return true;
201                }
202                return false;
203            }
204        };
205
206    private:
207        Kind kind;
208        Instruction* instruction;
209        Op typeClass;
210        Op opcode;
211        Id typeId;
212        size_t numMembers;
213        std::vector<Id> comps;
214    };
215
216    class StructConstantKey {
217    public:
218        enum Kind {
219            Key_Instruction,
220            Key_StructConstant,
221        };
222
223        StructConstantKey(
224            Instruction* instruction)
225        : kind(Key_Instruction)
226        , instruction(instruction)
227        , typeId(NoType)
228        , numMembers(0)
229        , comps()
230        {}
231
232        StructConstantKey(
233            Id typeId, const std::vector<Id>& comps, size_t numMembers)
234        : kind(Key_StructConstant)
235        , instruction(nullptr)
236        , typeId(typeId)
237        , numMembers(numMembers)
238        , comps(comps)
239        {}
240
241        Instruction* getInstruction() const {
242            return instruction;
243        }
244
245        // Functor to hash an instruction key.
246        struct Hash {
247            size_t operator()(StructConstantKey const &key) const {
248                switch (key.kind) {
249                case Key_Instruction:
250                    {
251                        Instruction* constant = key.instruction;
252                        size_t hash = std::hash<Id>()(constant->getTypeId()) * 13;
253                        for (size_t i = 0, n = constant->getNumOperands(); i < n; ++i) {
254                            hash = hash * 19 ^ std::hash<Id>()(constant->getIdOperand(i));
255                        }
256                        return hash;
257                    }
258                case Key_StructConstant:
259                    {
260                        size_t hash = std::hash<Id>()(key.typeId) * 13;
261                        for (size_t i = 0; i < key.numMembers; ++i) {
262                            hash = hash * 19 ^ std::hash<Id>()(key.comps[i]);
263                        }
264                        return hash;
265                    }
266                }
267                return 0;
268            }
269        };
270
271        // Functor to compare two instruction keys.
272        struct Equal {
273            bool operator() (StructConstantKey const &a, StructConstantKey const &b) const
274            {
275                if (a.kind == b.kind) {
276                    // we need only the Instruction case, as the other keys only used for searching
277                    return
278                        a.kind == Key_Instruction &&
279                        a.instruction == b.instruction;
280                }
281                const StructConstantKey* s = &a;
282                const StructConstantKey* o = &b;
283
284                if (s->kind == Key_StructConstant && o->kind == Key_Instruction) {
285                    s = o;
286                    o = &a;
287                }
288
289                // compare a composite constant with an instruction
290                if (s->kind == Key_Instruction && o->kind == Key_StructConstant) {
291                    Instruction* constant = s->instruction;
292                    if (constant->getTypeId() != o->typeId)
293                        return false;
294
295                    if (constant->getNumOperands() != (int)o->numMembers)
296                        return false;
297
298                    // same contents?
299                    for (int op = 0; op < constant->getNumOperands(); ++op) {
300                        if (constant->getIdOperand(op) != o->comps[op]) {
301                            return false;
302                        }
303                    }
304                    return true;
305                }
306                return false;
307            }
308        };
309
310    private:
311        Kind kind;
312        Instruction* instruction;
313        Id typeId;
314        size_t numMembers;
315        std::vector<Id> comps;
316    };
317
318public:
319    Builder(unsigned int spvVersion, unsigned int userNumber, SpvBuildLogger* logger);
320    virtual ~Builder();
321
322    static const int maxMatrixSize = 4;
323
324    unsigned int getSpvVersion() const { return spvVersion; }
325
326    void setSource(spv::SourceLanguage lang, int version)
327    {
328        sourceLang = lang;
329        sourceVersion = version;
330    }
331    spv::Id getStringId(const std::string& str)
332    {
333        auto sItr = stringIds.find(str);
334        if (sItr != stringIds.end())
335            return sItr->second;
336        spv::Id strId = getUniqueId();
337        Instruction* fileString = new Instruction(strId, NoType, Op::OpString);
338        const char* file_c_str = str.c_str();
339        fileString->addStringOperand(file_c_str);
340        strings.push_back(std::unique_ptr<Instruction>(fileString));
341        module.mapInstruction(fileString);
342        stringIds[file_c_str] = strId;
343        return strId;
344    }
345
346    spv::Id getMainFileId() const { return mainFileId; }
347
348    // Initialize the main source file name
349    void setDebugMainSourceFile(const std::string& file)
350    {
351        if (trackDebugInfo) {
352            dirtyLineTracker = true;
353            mainFileId = getStringId(file);
354            currentFileId = mainFileId;
355        }
356    }
357
358    // Set the debug source location tracker in the builder.
359    // The upcoming instructions in basic blocks will be associated to this location.
360    void setDebugSourceLocation(int line, const char* filename)
361    {
362        if (trackDebugInfo) {
363            dirtyLineTracker = true;
364            if (line != 0) {
365                // TODO: This is special handling of some AST nodes having (untracked) line 0.
366                //       But they should have a valid line number.
367                currentLine = line;
368                if (filename) {
369                    currentFileId = getStringId(filename);
370                }
371            }
372        }
373    }
374
375    void setSourceText(const std::string& text) { sourceText = text; }
376    void addSourceExtension(const char* ext) { sourceExtensions.push_back(ext); }
377    void addModuleProcessed(const std::string& p) { moduleProcesses.push_back(p.c_str()); }
378    void setEmitSpirvDebugInfo()
379    {
380        trackDebugInfo = true;
381        emitSpirvDebugInfo = true;
382    }
383    void setEmitNonSemanticShaderDebugInfo(bool emitSourceText)
384    {
385        trackDebugInfo = true;
386        emitNonSemanticShaderDebugInfo = true;
387        importNonSemanticShaderDebugInfoInstructions();
388
389        if (emitSourceText) {
390            emitNonSemanticShaderDebugSource = emitSourceText;
391        }
392    }
393    // Emit only an OpString with the source file name and an OpSource referencing it.
394    // Unlike the full debug modes, this does not enable line tracking or emit source text.
395    void setEmitSourceFileName(const std::string& file)
396    {
397        mainFileId = getStringId(file);
398        currentFileId = mainFileId;
399    }
400    void addExtension(const char* ext) { extensions.insert(ext); }
401    void removeExtension(const char* ext)
402    {
403        extensions.erase(ext);
404    }
405    void addIncorporatedExtension(const char* ext, SpvVersion incorporatedVersion)
406    {
407        if (getSpvVersion() < static_cast<unsigned>(incorporatedVersion))
408            addExtension(ext);
409    }
410    void promoteIncorporatedExtension(const char* baseExt, const char* promoExt, SpvVersion incorporatedVersion)
411    {
412        removeExtension(baseExt);
413        addIncorporatedExtension(promoExt, incorporatedVersion);
414    }
415    void addInclude(const std::string& name, const std::string& text)
416    {
417        spv::Id incId = getStringId(name);
418        includeFiles[incId] = &text;
419    }
420    Id import(const char*);
421    void setMemoryModel(spv::AddressingModel addr, spv::MemoryModel mem)
422    {
423        addressModel = addr;
424        memoryModel = mem;
425    }
426
427    void addCapability(spv::Capability cap) { capabilities.insert(cap); }
428
429    // To get a new <id> for anything needing a new one.
430    Id getUniqueId() { return ++uniqueId; }
431
432    // To get a set of new <id>s, e.g., for a set of function parameters
433    Id getUniqueIds(int numIds)
434    {
435        Id id = uniqueId + 1;
436        uniqueId += numIds;
437        return id;
438    }
439
440    // Maps the given OpType Id to a Non-Semantic DebugType Id.
441    Id getDebugType(Id type) {
442        if (auto it = debugTypeIdLookup.find(type); it != debugTypeIdLookup.end()) {
443            return it->second;
444        }
445
446        return NoType;
447    }
448
449    // Maps the given OpFunction Id to a Non-Semantic DebugFunction Id.
450    Id getDebugFunction(Id func) {
451        if (auto it = debugFuncIdLookup.find(func); it != debugFuncIdLookup.end()) {
452            return it->second;
453        }
454
455        return NoResult;
456    }
457
458    // For creating new types (will return old type if the requested one was already made).
459    Id makeVoidType();
460    Id makeBoolType();
461    Id makePointer(StorageClass, Id pointee);
462    Id makeForwardPointer(StorageClass);
463    Id makePointerFromForwardPointer(StorageClass, Id forwardPointerType, Id pointee);
464    Id makeUntypedPointer(StorageClass storageClass, bool setBufferPointer = false);
465    Id makeIntegerType(int width, bool hasSign);   // generic
466    Id makeIntType(int width) { return makeIntegerType(width, true); }
467    Id makeUintType(int width) { return makeIntegerType(width, false); }
468    Id makeFloatType(int width);
469    Id makeBFloat16Type();
470    Id makeFloatE5M2Type();
471    Id makeFloatE4M3Type();
472    Id makeFloatE2M1Type();
473    Id makeFloatE3M2Type();
474    Id makeFloatE2M3Type();
475    Id makeFloatUE8M0Type();
476    Id makeFloatMXINT8Type();
477    Id makeFloatOcpMicroscalingType(uint32_t width, FPEncoding encoding, Capability cap);
478    Id makeStructType(const std::vector<Id>& members, const std::vector<spv::StructMemberDebugInfo>& memberDebugInfo,
479                      const char* name, bool const compilerGenerated = true);
480    Id makeStructResultType(Id type0, Id type1);
481    Id makeVectorType(Id component, int size);
482    Id makeMatrixType(Id component, int cols, int rows);
483    Id makeArrayType(Id element, Id sizeId, int stride);  // 0 stride means no stride decoration
484    Id makeRuntimeArray(Id element);
485    Id makeFunctionType(Id returnType, const std::vector<Id>& paramTypes);
486    Id makeImageType(Id sampledType, Dim, bool depth, bool arrayed, bool ms, unsigned sampled, ImageFormat format, const char* debugNames);
487    Id makeSamplerType(const char* debugName);
488    Id makeSampledImageType(Id imageType, const char* debugName);
489    Id makeCooperativeMatrixTypeKHR(Id component, Id scope, Id rows, Id cols, Id use);
490    Id makeCooperativeMatrixTypeNV(Id component, Id scope, Id rows, Id cols);
491    Id makeCooperativeMatrixTypeWithSameShape(Id component, Id otherType);
492    Id makeCooperativeVectorTypeNV(Id componentType, Id components);
493    Id makeTensorTypeARM(Id elementType, Id rank);
494    Id makeGenericType(spv::Op opcode, std::vector<spv::IdImmediate>& operands);
495
496    // SPIR-V NonSemantic Shader DebugInfo Instructions
497    Id makeDebugInfoNone();
498    Id makeBoolDebugType(int const size);
499    Id makeIntegerDebugType(int const width, bool const hasSign);
500    Id makeFloatDebugType(int const width, Id const fpEncoding = NoType);
501    Id makeSequentialDebugType(Id const baseType, Id const componentCount, NonSemanticShaderDebugInfoInstructions const sequenceType);
502    Id makeArrayDebugType(Id const baseType, Id const componentCount);
503    Id makeVectorDebugType(Id const baseType, int const componentCount);
504    Id makeMatrixDebugType(Id const vectorType, int const vectorCount, bool columnMajor = true);
505    Id makeMemberDebugType(Id const memberType, StructMemberDebugInfo const& debugTypeLoc);
506    Id makeCompositeDebugType(std::vector<Id> const& memberTypes, std::vector<StructMemberDebugInfo> const& memberDebugInfo,
507                              char const* const name, NonSemanticShaderDebugInfoDebugCompositeType const tag);
508    Id makeOpaqueDebugType(char const* const name);
509    Id makeVectorIdDebugType(Id componentType, Id componentCount);
510    Id makeCooperativeMatrixDebugTypeKHR(Id componentType, Id scope, Id rows, Id cols, Id use);
511    Id makePointerDebugType(StorageClass storageClass, Id const baseType);
512    Id makeForwardPointerDebugType(StorageClass storageClass);
513    Id makeDebugSource(const Id fileName);
514    Id makeDebugCompilationUnit();
515    Id createDebugGlobalVariable(Id const type, char const*const name, Id const variable);
516    Id createDebugLocalVariable(Id type, char const*const name, size_t const argNumber = 0);
517    Id makeDebugExpression();
518    Id makeDebugDeclare(Id const debugLocalVariable, Id const pointer);
519    Id makeDebugValue(Id const debugLocalVariable, Id const value);
520    Id makeDebugFunctionType(Id returnType, const std::vector<Id>& paramTypes);
521    Id makeDebugFunction(Function* function, Id nameId, Id funcTypeId);
522    Id makeDebugEntryPoint(Function* function, const char* compilerSignature, const char* commandLineArguments,
523                           const char* currentWorkingDirectory = nullptr);
524    Id makeDebugLexicalBlock(uint32_t line, uint32_t column);
525    std::string unmangleFunctionName(std::string const& name) const;
526
527    // Initialize non-semantic debug information for a function, including those of:
528    // - The function definition
529    // - The function parameters
530    void setupFunctionDebugInfo(Function* function, const char* name, const std::vector<Id>& paramTypes,
531                                const std::vector<char const*>& paramNames);
532
533    // accelerationStructureNV type
534    Id makeAccelerationStructureType();
535    // rayQueryEXT type
536    Id makeRayQueryType();
537    // hitObjectNV type
538    Id makeHitObjectNVType();
539    // hitObjectEXT type
540    Id makeHitObjectEXTType();
541
542    // For querying about types.
543    Id getTypeId(Id resultId) const { return module.getTypeId(resultId); }
544    Id getDerefTypeId(Id resultId) const;
545    Op getOpCode(Id id) const { return module.getInstruction(id)->getOpCode(); }
546    Op getTypeClass(Id typeId) const { return getOpCode(typeId); }
547    Op getMostBasicTypeClass(Id typeId) const;
548    unsigned int getNumComponents(Id resultId) const { return getNumTypeComponents(getTypeId(resultId)); }
549    unsigned int getNumTypeConstituents(Id typeId) const;
550    unsigned int getNumTypeComponents(Id typeId) const { return getNumTypeConstituents(typeId); }
551    Id getScalarTypeId(Id typeId) const;
552    Id getContainedTypeId(Id typeId) const;
553    Id getContainedTypeId(Id typeId, int) const;
554    StorageClass getTypeStorageClass(Id typeId) const { return module.getStorageClass(typeId); }
555    ImageFormat getImageTypeFormat(Id typeId) const
556        { return (ImageFormat)module.getInstruction(typeId)->getImmediateOperand(6); }
557    Id getResultingAccessChainType() const;
558    Id getIdOperand(Id resultId, int idx) { return module.getInstruction(resultId)->getIdOperand(idx); }
559    Id getCooperativeVectorNumComponents(Id typeId) const { return module.getInstruction(typeId)->getIdOperand(1); }
560
561    bool isPointer(Id resultId)      const { return isPointerType(getTypeId(resultId)); }
562    bool isUntypedPointer(Id resultId) const
563    {
564        const Id tid = getTypeId(resultId);
565        // Expect that OpString have no type
566        if (tid == 0)
567            return false;
568        return isUntypedPointerType(tid);
569    }
570    bool isScalar(Id resultId)       const { return isScalarType(getTypeId(resultId)); }
571    bool isVector(Id resultId)       const { return isVectorType(getTypeId(resultId)); }
572    bool isMatrix(Id resultId)       const { return isMatrixType(getTypeId(resultId)); }
573    bool isCooperativeMatrix(Id resultId)const { return isCooperativeMatrixType(getTypeId(resultId)); }
574    bool isCooperativeVector(Id resultId)const { return isCooperativeVectorType(getTypeId(resultId)); }
575    bool isAggregate(Id resultId)    const { return isAggregateType(getTypeId(resultId)); }
576    bool isSampledImage(Id resultId) const { return isSampledImageType(getTypeId(resultId)); }
577    bool isTensorView(Id resultId)const { return isTensorViewType(getTypeId(resultId)); }
578
579    bool isBoolType(Id typeId)
580        { return groupedTypes[enumCast(Op::OpTypeBool)].size() > 0 && typeId == groupedTypes[enumCast(Op::OpTypeBool)].back()->getResultId(); }
581    bool isIntType(Id typeId)          const
582        { return getTypeClass(typeId) == Op::OpTypeInt && module.getInstruction(typeId)->getImmediateOperand(1) != 0; }
583    bool isUintType(Id typeId)         const
584        { return getTypeClass(typeId) == Op::OpTypeInt && module.getInstruction(typeId)->getImmediateOperand(1) == 0; }
585    bool isFloatType(Id typeId)        const { return getTypeClass(typeId) == Op::OpTypeFloat; }
586    bool isPointerType(Id typeId)      const { return getTypeClass(typeId) == Op::OpTypePointer; }
587    bool isUntypedPointerType(Id typeId) const { return getTypeClass(typeId) == Op::OpTypeUntypedPointerKHR; }
588    bool isScalarType(Id typeId)       const
589        { return getTypeClass(typeId) == Op::OpTypeFloat || getTypeClass(typeId) == Op::OpTypeInt ||
590          getTypeClass(typeId) == Op::OpTypeBool; }
591    bool isVectorType(Id typeId)       const { return getTypeClass(typeId) == Op::OpTypeVector; }
592    bool isMatrixType(Id typeId)       const { return getTypeClass(typeId) == Op::OpTypeMatrix; }
593    bool isStructType(Id typeId)       const { return getTypeClass(typeId) == Op::OpTypeStruct; }
594    bool isArrayType(Id typeId)        const { return getTypeClass(typeId) == Op::OpTypeArray; }
595    bool isCooperativeMatrixType(Id typeId)const
596    {
597        return getTypeClass(typeId) == Op::OpTypeCooperativeMatrixKHR || getTypeClass(typeId) == Op::OpTypeCooperativeMatrixNV;
598    }
599    bool isTensorViewType(Id typeId) const { return getTypeClass(typeId) == Op::OpTypeTensorViewNV; }
600    bool isCooperativeVectorType(Id typeId) const { return getTypeClass(typeId) == Op::OpTypeCooperativeVectorNV; }
601    bool isTensorTypeARM(Id typeId)    const { return getTypeClass(typeId) == Op::OpTypeTensorARM; }
602    bool isAggregateType(Id typeId)    const
603        { return isArrayType(typeId) || isStructType(typeId) || isCooperativeMatrixType(typeId); }
604    bool isImageType(Id typeId)        const { return getTypeClass(typeId) == Op::OpTypeImage; }
605    bool isSamplerType(Id typeId)      const { return getTypeClass(typeId) == Op::OpTypeSampler; }
606    bool isSampledImageType(Id typeId) const { return getTypeClass(typeId) == Op::OpTypeSampledImage; }
607    bool containsType(Id typeId, Op typeOp, unsigned int width) const;
608    bool containsPhysicalStorageBufferOrArray(Id typeId) const;
609
610    bool isConstantOpCode(Op opcode) const;
611    bool isSpecConstantOpCode(Op opcode) const;
612    bool isConstant(Id resultId) const { return isConstantOpCode(getOpCode(resultId)); }
613    bool isConstantScalar(Id resultId) const { return getOpCode(resultId) == Op::OpConstant; }
614    bool isSpecConstant(Id resultId) const { return isSpecConstantOpCode(getOpCode(resultId)); }
615    unsigned int getConstantScalar(Id resultId) const
616        { return module.getInstruction(resultId)->getImmediateOperand(0); }
617    StorageClass getStorageClass(Id resultId) const { return getTypeStorageClass(getTypeId(resultId)); }
618
619    bool isVariableOpCode(Op opcode) const { return opcode == Op::OpVariable; }
620    bool isVariable(Id resultId) const { return isVariableOpCode(getOpCode(resultId)); }
621    bool isGlobalStorage(Id resultId) const { return getStorageClass(resultId) != StorageClass::Function; }
622    bool isGlobalVariable(Id resultId) const { return isVariable(resultId) && isGlobalStorage(resultId); }
623    // See if a resultId is valid for use as an initializer.
624    bool isValidInitializer(Id resultId) const { return isConstant(resultId) || isGlobalVariable(resultId); }
625
626    int getScalarTypeWidth(Id typeId) const
627    {
628        Id scalarTypeId = getScalarTypeId(typeId);
629        assert(getTypeClass(scalarTypeId) == Op::OpTypeInt || getTypeClass(scalarTypeId) == Op::OpTypeFloat);
630        return module.getInstruction(scalarTypeId)->getImmediateOperand(0);
631    }
632
633    unsigned int getTypeNumColumns(Id typeId) const
634    {
635        assert(isMatrixType(typeId));
636        return getNumTypeConstituents(typeId);
637    }
638    unsigned int getNumColumns(Id resultId) const { return getTypeNumColumns(getTypeId(resultId)); }
639    unsigned int getTypeNumRows(Id typeId) const
640    {
641        assert(isMatrixType(typeId));
642        return getNumTypeComponents(getContainedTypeId(typeId));
643    }
644    unsigned int getNumRows(Id resultId) const { return getTypeNumRows(getTypeId(resultId)); }
645
646    Dim getTypeDimensionality(Id typeId) const
647    {
648        assert(isImageType(typeId));
649        return (Dim)module.getInstruction(typeId)->getImmediateOperand(1);
650    }
651    Id getImageType(Id resultId) const
652    {
653        Id typeId = getTypeId(resultId);
654        assert(isImageType(typeId) || isSampledImageType(typeId));
655        return isSampledImageType(typeId) ? module.getInstruction(typeId)->getIdOperand(0) : typeId;
656    }
657    bool isArrayedImageType(Id typeId) const
658    {
659        assert(isImageType(typeId));
660        return module.getInstruction(typeId)->getImmediateOperand(3) != 0;
661    }
662
663    // For making new constants (will return old constant if the requested one was already made).
664    Id makeNullConstant(Id typeId);
665    Id makeBoolConstant(bool b, bool specConstant = false);
666    Id makeIntConstant(Id typeId, unsigned value, bool specConstant);
667    Id makeInt64Constant(Id typeId, unsigned long long value, bool specConstant);
668    Id makeInt8Constant(int i, bool specConstant = false)
669        { return makeIntConstant(makeIntType(8),  (unsigned)i, specConstant); }
670    Id makeUint8Constant(unsigned u, bool specConstant = false)
671        { return makeIntConstant(makeUintType(8),           u, specConstant); }
672    Id makeInt16Constant(int i, bool specConstant = false)
673        { return makeIntConstant(makeIntType(16),  (unsigned)i, specConstant); }
674    Id makeUint16Constant(unsigned u, bool specConstant = false)
675        { return makeIntConstant(makeUintType(16),           u, specConstant); }
676    Id makeIntConstant(int i, bool specConstant = false)
677        { return makeIntConstant(makeIntType(32),  (unsigned)i, specConstant); }
678    Id makeUintConstant(unsigned u, bool specConstant = false)
679        { return makeIntConstant(makeUintType(32),           u, specConstant); }
680    Id makeUintConstant(Scope u, bool specConstant = false)
681        { return makeUintConstant((unsigned)u, specConstant); }
682    Id makeUintConstant(StorageClass u, bool specConstant = false)
683        { return makeUintConstant((unsigned)u, specConstant); }
684    Id makeUintConstant(MemorySemanticsMask u, bool specConstant = false)
685        { return makeUintConstant((unsigned)u, specConstant); }
686    Id makeUintConstant(SourceLanguage u, bool specConstant = false)
687        { return makeUintConstant((unsigned)u, specConstant); }
688    Id makeInt64Constant(long long i, bool specConstant = false)
689        { return makeInt64Constant(makeIntType(64),  (unsigned long long)i, specConstant); }
690    Id makeUint64Constant(unsigned long long u, bool specConstant = false)
691        { return makeInt64Constant(makeUintType(64),                     u, specConstant); }
692    Id makeFloatConstant(float f, bool specConstant = false);
693    Id makeDoubleConstant(double d, bool specConstant = false);
694    Id makeFloat16Constant(float f16, bool specConstant = false);
695    Id makeBFloat16Constant(float bf16, bool specConstant = false);
696    Id makeFloatE5M2Constant(float fe5m2, bool specConstant = false);
697    Id makeFloatE4M3Constant(float fe4m3, bool specConstant = false);
698    Id makeFloatE2M1Constant(float fe2m1, bool specConstant = false);
699    Id makeFloatE3M2Constant(float fe3m2, bool specConstant = false);
700    Id makeFloatE2M3Constant(float fe2m3, bool specConstant = false);
701    Id makeFloatUE8M0Constant(float fue8m0, bool specConstant = false);
702    Id makeFloatMXINT8Constant(float mxint8, bool specConstant = false);
703    Id makeFpConstant(Id type, double d, bool specConstant = false);
704
705    Id importNonSemanticShaderDebugInfoInstructions();
706    // Ensure the NonSemantic.Shader.DebugInfo import string names at least `version`.
707    // If the import instruction already exists, its name is patched in place.
708    // If it has not been created yet, importNonSemanticShaderDebugInfoInstructions()
709    // will use the updated version when it runs.
710    void requireNonSemanticShaderDebugInfoVersion(unsigned version);
711
712    // Turn the array of constants into a proper spv constant of the requested type.
713    Id makeCompositeConstant(Id type, const std::vector<Id>& comps, bool specConst = false);
714
715    // Methods for adding information outside the CFG.
716    Instruction* addEntryPoint(ExecutionModel, Function*, const char* name);
717    void addExecutionMode(Function*, ExecutionMode mode, int value1 = -1, int value2 = -1, int value3 = -1);
718    void addExecutionMode(Function*, ExecutionMode mode, const std::vector<unsigned>& literals);
719    void addExecutionModeId(Function*, ExecutionMode mode, const std::vector<Id>& operandIds);
720    void addName(Id, const char* name);
721    void addMemberName(Id, int member, const char* name);
722    void addDecoration(Id, Decoration, int num = -1);
723    void addDecoration(Id, Decoration, const char*);
724    void addDecoration(Id, Decoration, const std::vector<unsigned>& literals);
725    void addDecoration(Id, Decoration, const std::vector<const char*>& strings);
726    void addLinkageDecoration(Id id, const char* name, spv::LinkageType linkType);
727    void addDecorationId(Id id, Decoration, Id idDecoration);
728    void addDecorationId(Id id, Decoration, const std::vector<Id>& operandIds);
729    void addMemberDecoration(Id, unsigned int member, Decoration, int num = -1);
730    void addMemberDecoration(Id, unsigned int member, Decoration, const char*);
731    void addMemberDecoration(Id, unsigned int member, Decoration, const std::vector<unsigned>& literals);
732    void addMemberDecoration(Id, unsigned int member, Decoration, const std::vector<const char*>& strings);
733    void addMemberDecorationIdEXT(Id, unsigned int member, Decoration, const std::vector<unsigned>& operands);
734
735    // At the end of what block do the next create*() instructions go?
736    // Also reset current last DebugScope and current source line to unknown
737    void setBuildPoint(Block* bp) {
738        buildPoint = bp;
739        descHeapShiftedBaseCache.clear();
740        dirtyLineTracker = true;
741        dirtyScopeTracker = true;
742    }
743    Block* getBuildPoint() const { return buildPoint; }
744
745    // Append an instruction to the end of the current build point.
746    // Optionally, additional debug info instructions may also be prepended.
747    void addInstruction(std::unique_ptr<Instruction> inst);
748
749    // Append an instruction to the end of the current build point without prepending any debug instructions.
750    // This is useful for insertion of some debug info instructions themselves or some control flow instructions
751    // that are attached to its predecessor instruction.
752    void addInstructionNoDebugInfo(std::unique_ptr<Instruction> inst);
753
754    // Make the entry-point function. The returned pointer is only valid
755    // for the lifetime of this builder.
756    Function* makeEntryPoint(const char*);
757
758    // Make a shader-style function, and create its entry block if entry is non-zero.
759    // Return the function, pass back the entry.
760    // The returned pointer is only valid for the lifetime of this builder.
761    Function* makeFunctionEntry(Decoration precision, Id returnType, const char* name, LinkageType linkType,
762                                const std::vector<Id>& paramTypes,
763                                const std::vector<std::vector<Decoration>>& precisions, Block** entry = nullptr);
764
765    // Create a return. An 'implicit' return is one not appearing in the source
766    // code.  In the case of an implicit return, no post-return block is inserted.
767    void makeReturn(bool implicit, Id retVal = 0);
768
769    // Initialize state and generate instructions for new lexical scope
770    void enterLexicalBlock(uint32_t line, uint32_t column);
771
772    // Set state and generate instructions to exit current lexical scope
773    void leaveLexicalBlock();
774
775    // Prepare builder for generation of instructions for a function.
776    void enterFunction(Function const* function);
777
778    // Generate all the code needed to finish up a function.
779    void leaveFunction();
780
781    // Create block terminator instruction for certain statements like
782    // discard, terminate-invocation, terminateRayEXT, or ignoreIntersectionEXT
783    void makeStatementTerminator(spv::Op opcode, const char *name);
784
785    // Create block terminator instruction for statements that have input operands
786    // such as OpEmitMeshTasksEXT
787    void makeStatementTerminator(spv::Op opcode, const std::vector<Id>& operands, const char* name);
788
789    // Create a global/local constant. Because OpConstant is automatically emitted by getting the constant
790    // ids, this function only handles debug info.
791    void createConstVariable(Id type, const char* name, Id constant, bool isGlobal);
792
793    // Create a global or function local or IO variable.
794    Id createVariable(Decoration precision, StorageClass storageClass, Id type, const char* name = nullptr,
795        Id initializer = NoResult, bool const compilerGenerated = true);
796
797    // Create an untyped global or function local or IO variable.
798    Id createUntypedVariable(Decoration precision, StorageClass storageClass, const char* name = nullptr,
799                             Id dataType = NoResult, Id initializer = NoResult);
800
801    // Create an intermediate with an undefined value.
802    Id createUndefined(Id type);
803
804    // Create load/store instruction with a remapped descriptor heap base.
805    Instruction* createDescHeapLoadStoreBaseRemap(Id base, Op op);
806
807    // Store into an Id and return the l-value
808    void createStore(Id rValue, Id lValue, spv::MemoryAccessMask memoryAccess = spv::MemoryAccessMask::MaskNone,
809        spv::Scope scope = spv::Scope::Max, unsigned int alignment = 0);
810
811    // Load from an Id and return it
812    Id createLoad(Id lValue, spv::Decoration precision,
813        spv::MemoryAccessMask memoryAccess = spv::MemoryAccessMask::MaskNone,
814        spv::Scope scope = spv::Scope::Max, unsigned int alignment = 0);
815
816    // Create an OpAccessChain instruction
817    Id createAccessChain(StorageClass, Id base, const std::vector<Id>& offsets);
818
819    // Create an OpUntypedAccessChainKHR instruction
820    Id createUntypedAccessChain(Id resultType, Id base, const std::vector<Id>& offsets, Id resultId = NoResult);
821
822    // Create an OpArrayLength instruction
823    Id createArrayLength(Id base, unsigned int member, unsigned int bits);
824
825    // Create an OpCooperativeMatrixLengthKHR instruction
826    Id createCooperativeMatrixLengthKHR(Id type);
827    // Create an OpCooperativeMatrixLengthNV instruction
828    Id createCooperativeMatrixLengthNV(Id type);
829
830    // Create an OpCompositeExtract instruction
831    Id createCompositeExtract(Id composite, Id typeId, unsigned index);
832    Id createCompositeExtract(Id composite, Id typeId, const std::vector<unsigned>& indexes);
833    Id createCompositeInsert(Id object, Id composite, Id typeId, unsigned index);
834    Id createCompositeInsert(Id object, Id composite, Id typeId, const std::vector<unsigned>& indexes);
835
836    Id createVectorExtractDynamic(Id vector, Id typeId, Id componentIndex);
837    Id createVectorInsertDynamic(Id vector, Id typeId, Id component, Id componentIndex);
838
839    void createNoResultOp(Op);
840    void createNoResultOp(Op, Id operand);
841    void createNoResultOp(Op, const std::vector<Id>& operands);
842    void createNoResultOp(Op, const std::vector<IdImmediate>& operands);
843    void createControlBarrier(Scope execution, Scope memory, MemorySemanticsMask);
844    void createSplitControlBarrier(Op op, Scope execution, Scope memory, MemorySemanticsMask memorySem);
845    void createMemoryBarrier(Scope executionScope, MemorySemanticsMask memorySemantics);
846    Id createUnaryOp(Op, Id typeId, Id operand);
847    Id createBinOp(Op, Id typeId, Id operand1, Id operand2);
848    Id createTriOp(Op, Id typeId, Id operand1, Id operand2, Id operand3);
849    Id createOp(Op, Id typeId, const std::vector<Id>& operands);
850    Id createOp(Op, Id typeId, const std::vector<IdImmediate>& operands);
851    Id createConstData(Op opCode, Id typeId, const std::vector<const char*> operands);
852    Id createFunctionCall(spv::Function*, const std::vector<spv::Id>&);
853    Id createSpecConstantOp(Op, Id typeId, const std::vector<spv::Id>& operands, const std::vector<unsigned>& literals);
854    Id createSpecConstantAlignTo(Id value, Id alignment);
855    Id createSpecConstantSelectMax(Id lhs, Id rhs);
856
857    // Take an rvalue (source) and a set of channels to extract from it to
858    // make a new rvalue, which is returned.
859    Id createRvalueSwizzle(Decoration precision, Id typeId, Id source, const std::vector<unsigned>& channels);
860
861    // Take a copy of an lvalue (target) and a source of components, and set the
862    // source components into the lvalue where the 'channels' say to put them.
863    // An updated version of the target is returned.
864    // (No true lvalue or stores are used.)
865    Id createLvalueSwizzle(Id typeId, Id target, Id source, const std::vector<unsigned>& channels);
866
867    // If both the id and precision are valid, the id
868    // gets tagged with the requested precision.
869    // The passed in id is always the returned id, to simplify use patterns.
870    Id setPrecision(Id id, Decoration precision)
871    {
872        if (precision != NoPrecision && id != NoResult)
873            addDecoration(id, precision);
874
875        return id;
876    }
877
878    // Can smear a scalar to a vector for the following forms:
879    //   - promoteScalar(scalar, vector)  // smear scalar to width of vector
880    //   - promoteScalar(vector, scalar)  // smear scalar to width of vector
881    //   - promoteScalar(pointer, scalar) // smear scalar to width of what pointer points to
882    //   - promoteScalar(scalar, scalar)  // do nothing
883    // Other forms are not allowed.
884    //
885    // Generally, the type of 'scalar' does not need to be the same type as the components in 'vector'.
886    // The type of the created vector is a vector of components of the same type as the scalar.
887    //
888    // Note: One of the arguments will change, with the result coming back that way rather than
889    // through the return value.
890    void promoteScalar(Decoration precision, Id& left, Id& right);
891
892    // Make a value by smearing the scalar to fill the type.
893    // vectorType should be the correct type for making a vector of scalarVal.
894    // (No conversions are done.)
895    Id smearScalar(Decoration precision, Id scalarVal, Id vectorType);
896
897    // Create a call to a built-in function.
898    Id createBuiltinCall(Id resultType, Id builtins, int entryPoint, const std::vector<Id>& args);
899    Id createBuiltinCall(Id resultType, Id builtins, int entryPoint, const std::vector<IdImmediate>& args);
900
901    // List of parameters used to create a texture operation
902    struct TextureParameters {
903        Id sampler;
904        Id coords;
905        Id bias;
906        Id lod;
907        Id Dref;
908        Id offset;
909        Id offsets;
910        Id gradX;
911        Id gradY;
912        Id sample;
913        Id component;
914        Id texelOut;
915        Id lodClamp;
916        Id granularity;
917        Id coarse;
918        Id gatherMode;
919        bool nonprivate;
920        bool volatil;
921        bool nontemporal;
922    };
923
924    // Select the correct texture operation based on all inputs, and emit the correct instruction
925    Id createTextureCall(Decoration precision, Id resultType, bool sparse, bool fetch, bool proj, bool gather,
926        bool noImplicit, const TextureParameters&, ImageOperandsMask);
927
928    // Emit the OpTextureQuery* instruction that was passed in.
929    // Figure out the right return value and type, and return it.
930    Id createTextureQueryCall(Op, const TextureParameters&, bool isUnsignedResult);
931
932    Id createSamplePositionCall(Decoration precision, Id, Id);
933
934    Id createBitFieldExtractCall(Decoration precision, Id, Id, Id, bool isSigned);
935    Id createBitFieldInsertCall(Decoration precision, Id, Id, Id, Id);
936
937    // Reduction comparison for composites:  For equal and not-equal resulting in a scalar.
938    Id createCompositeCompare(Decoration precision, Id, Id, bool /* true if for equal, false if for not-equal */);
939
940    // OpCompositeConstruct
941    Id createCompositeConstruct(Id typeId, const std::vector<Id>& constituents);
942
943    // vector or scalar constructor
944    Id createConstructor(Decoration precision, const std::vector<Id>& sources, Id resultTypeId);
945
946    // matrix constructor
947    Id createMatrixConstructor(Decoration precision, const std::vector<Id>& sources, Id constructee);
948
949    // coopmat conversion
950    Id createCooperativeMatrixConversion(Id typeId, Id source);
951    Id createCooperativeMatrixReduce(Op opcode, Id typeId, Id source, unsigned int mask, Id func);
952    Id createCooperativeMatrixPerElementOp(Id typeId, const std::vector<Id>& operands);
953
954    // Helper to use for building nested control flow with if-then-else.
955    class If {
956    public:
957        If(Id condition, SelectionControlMask ctrl, Builder& builder);
958        ~If() {}
959
960        void makeBeginElse();
961        void makeEndIf();
962
963    private:
964        If(const If&);
965        If& operator=(If&);
966
967        Builder& builder;
968        Id condition;
969        SelectionControlMask control;
970        Function* function;
971        Block* headerBlock;
972        Block* thenBlock;
973        Block* elseBlock;
974        Block* mergeBlock;
975    };
976
977    // Make a switch statement.  A switch has 'numSegments' of pieces of code, not containing
978    // any case/default labels, all separated by one or more case/default labels.  Each possible
979    // case value v is a jump to the caseValues[v] segment.  The defaultSegment is also in this
980    // number space.  How to compute the value is given by 'condition', as in switch(condition).
981    //
982    // The SPIR-V Builder will maintain the stack of post-switch merge blocks for nested switches.
983    //
984    // Use a defaultSegment < 0 if there is no default segment (to branch to post switch).
985    //
986    // Returns the right set of basic blocks to start each code segment with, so that the caller's
987    // recursion stack can hold the memory for it.
988    //
989    void makeSwitch(Id condition, SelectionControlMask control, int numSegments, const std::vector<int>& caseValues,
990                    const std::vector<int>& valueToSegment, int defaultSegment, std::vector<Block*>& segmentBB);
991
992    // Add a branch to the innermost switch's merge block.
993    void addSwitchBreak(bool implicit);
994
995    // Move to the next code segment, passing in the return argument in makeSwitch()
996    void nextSwitchSegment(std::vector<Block*>& segmentBB, int segment);
997
998    // Finish off the innermost switch.
999    void endSwitch(std::vector<Block*>& segmentBB);
1000
1001    struct LoopBlocks {
1002        LoopBlocks(Block& head, Block& body, Block& merge, Block& continue_target) :
1003            head(head), body(body), merge(merge), continue_target(continue_target) { }
1004        Block &head, &body, &merge, &continue_target;
1005    private:
1006        LoopBlocks();
1007        LoopBlocks& operator=(const LoopBlocks&) = delete;
1008    };
1009
1010    // Start a new loop and prepare the builder to generate code for it.  Until
1011    // closeLoop() is called for this loop, createLoopContinue() and
1012    // createLoopExit() will target its corresponding blocks.
1013    LoopBlocks& makeNewLoop();
1014
1015    // Create a new block in the function containing the build point.  Memory is
1016    // owned by the function object.
1017    Block& makeNewBlock();
1018
1019    // Add a branch to the continue_target of the current (innermost) loop.
1020    void createLoopContinue();
1021
1022    // Add an exit (e.g. "break") from the innermost loop that we're currently
1023    // in.
1024    void createLoopExit();
1025
1026    // Close the innermost loop that you're in
1027    void closeLoop();
1028
1029    //
1030    // Access chain design for an R-Value vs. L-Value:
1031    //
1032    // There is a single access chain the builder is building at
1033    // any particular time.  Such a chain can be used to either to a load or
1034    // a store, when desired.
1035    //
1036    // Expressions can be r-values, l-values, or both, or only r-values:
1037    //    a[b.c].d = ....  // l-value
1038    //    ... = a[b.c].d;  // r-value, that also looks like an l-value
1039    //    ++a[b.c].d;      // r-value and l-value
1040    //    (x + y)[2];      // r-value only, can't possibly be l-value
1041    //
1042    // Computing an r-value means generating code.  Hence,
1043    // r-values should only be computed when they are needed, not speculatively.
1044    //
1045    // Computing an l-value means saving away information for later use in the compiler,
1046    // no code is generated until the l-value is later dereferenced.  It is okay
1047    // to speculatively generate an l-value, just not okay to speculatively dereference it.
1048    //
1049    // The base of the access chain (the left-most variable or expression
1050    // from which everything is based) can be set either as an l-value
1051    // or as an r-value.  Most efficient would be to set an l-value if one
1052    // is available.  If an expression was evaluated, the resulting r-value
1053    // can be set as the chain base.
1054    //
1055    // The users of this single access chain can save and restore if they
1056    // want to nest or manage multiple chains.
1057    //
1058
1059    struct AccessChain {
1060        Id base;                       // for l-values, pointer to the base object, for r-values, the base object
1061        std::vector<Id> indexChain;
1062        Id instr;                      // cache the instruction that generates this access chain
1063        std::vector<unsigned> swizzle; // each std::vector element selects the next GLSL component number
1064        Id component;                  // a dynamic component index, can coexist with a swizzle,
1065                                       // done after the swizzle, NoResult if not present
1066        Id preSwizzleBaseType;         // dereferenced type, before swizzle or component is applied;
1067                                       // NoType unless a swizzle or component is present
1068        bool isRValue;                 // true if 'base' is an r-value, otherwise, base is an l-value
1069        unsigned int alignment;        // bitwise OR of alignment values passed in. Accumulates worst alignment.
1070                                       // Only tracks base and (optional) component selection alignment.
1071
1072        struct DescHeapInfo {
1073            Id descHeapBaseTy;                  // for descriptor heap, record its base data type.
1074            Id descHeapBaseOffset;              // byte offset applied to the heap base before descriptor lookup.
1075            std::vector<Id> descHeapIndexChain;
1076            Id descTy;                          // for target resource type
1077            StorageClass descStorageClass;      // for descriptor heap, record its basic storage class.
1078            bool descReadonly;                  // for decorating OpBufferPointerEXT results.
1079            bool descWriteonly;                 // for decorating OpBufferPointerEXT results.
1080            std::vector<Instruction*> descHeapInstId;
1081                                                // for descriptor heap, record its data type for loading/store results.
1082        };
1083        DescHeapInfo descHeapInfo;
1084
1085        // Accumulate whether anything in the chain of structures has coherent decorations.
1086        struct CoherentFlags {
1087            CoherentFlags() { clear(); }
1088            bool isVolatile() const { return volatil; }
1089            bool isNonUniform() const { return nonUniform; }
1090            bool anyCoherent() const {
1091                return coherent || devicecoherent || queuefamilycoherent || workgroupcoherent ||
1092                    subgroupcoherent || shadercallcoherent;
1093            }
1094
1095            unsigned coherent : 1;
1096            unsigned devicecoherent : 1;
1097            unsigned queuefamilycoherent : 1;
1098            unsigned workgroupcoherent : 1;
1099            unsigned subgroupcoherent : 1;
1100            unsigned shadercallcoherent : 1;
1101            unsigned nonprivate : 1;
1102            unsigned volatil : 1;
1103            unsigned nontemporal : 1;
1104            unsigned isImage : 1;
1105            unsigned nonUniform : 1;
1106
1107            void clear() {
1108                coherent = 0;
1109                devicecoherent = 0;
1110                queuefamilycoherent = 0;
1111                workgroupcoherent = 0;
1112                subgroupcoherent = 0;
1113                shadercallcoherent = 0;
1114                nonprivate = 0;
1115                volatil = 0;
1116                nontemporal = 0;
1117                isImage = 0;
1118                nonUniform = 0;
1119            }
1120
1121            CoherentFlags operator |=(const CoherentFlags &other) {
1122                coherent |= other.coherent;
1123                devicecoherent |= other.devicecoherent;
1124                queuefamilycoherent |= other.queuefamilycoherent;
1125                workgroupcoherent |= other.workgroupcoherent;
1126                subgroupcoherent |= other.subgroupcoherent;
1127                shadercallcoherent |= other.shadercallcoherent;
1128                nonprivate |= other.nonprivate;
1129                volatil |= other.volatil;
1130                nontemporal |= other.nontemporal;
1131                isImage |= other.isImage;
1132                nonUniform |= other.nonUniform;
1133                return *this;
1134            }
1135        };
1136        CoherentFlags coherentFlags;
1137    };
1138
1139    //
1140    // the SPIR-V builder maintains a single active chain that
1141    // the following methods operate on
1142    //
1143
1144    // for external save and restore
1145    AccessChain getAccessChain() { return accessChain; }
1146    void setAccessChain(AccessChain newChain) { accessChain = newChain; }
1147
1148    // for EXT_descriptor_heap and EXT_structured_descriptor_heap
1149    Id getAccessChainDescHeapBaseType() const { return accessChain.descHeapInfo.descHeapBaseTy; }
1150    void setAccessChainDescHeapBaseType(Id baseType) { accessChain.descHeapInfo.descHeapBaseTy = baseType; }
1151    void setAccessChainDescHeapBaseOffset(Id baseOffset) { accessChain.descHeapInfo.descHeapBaseOffset = baseOffset; }
1152    const std::vector<Id>& getAccessChainDescHeapIndexChain() const { return accessChain.descHeapInfo.descHeapIndexChain; }
1153    void accessChainPushDescHeapIndex(Id index) { accessChain.descHeapInfo.descHeapIndexChain.push_back(index); }
1154    bool hasAccessChainIndex() const { return !accessChain.indexChain.empty(); }
1155    void moveAccessChainIndexToDescHeapIndexChain()
1156    {
1157        assert(accessChain.indexChain.size() == 1);
1158        accessChainPushDescHeapIndex(accessChain.indexChain.back());
1159        accessChain.indexChain.pop_back();
1160    }
1161    void setAccessChainDescHeapDescriptorType(Id descTy, StorageClass storageClass, bool readonly, bool writeonly)
1162    {
1163        accessChain.descHeapInfo.descTy = descTy;
1164        accessChain.descHeapInfo.descStorageClass = storageClass;
1165        accessChain.descHeapInfo.descReadonly = readonly;
1166        accessChain.descHeapInfo.descWriteonly = writeonly;
1167    }
1168
1169    // clear accessChain
1170    void clearAccessChain();
1171
1172    Id createDescHeapAccessChain();
1173    Id createConstantSizeOfEXT(Id typeId);
1174
1175    // set new base as an l-value base
1176    void setAccessChainLValue(Id lValue)
1177    {
1178        assert(isPointer(lValue) || isUntypedPointer(lValue));
1179        accessChain.base = lValue;
1180    }
1181
1182    // set new base value as an r-value
1183    void setAccessChainRValue(Id rValue)
1184    {
1185        accessChain.isRValue = true;
1186        accessChain.base = rValue;
1187    }
1188
1189    // push offset onto the end of the chain
1190    void accessChainPush(Id offset, AccessChain::CoherentFlags coherentFlags, unsigned int alignment)
1191    {
1192        accessChain.indexChain.push_back(offset);
1193        accessChain.coherentFlags |= coherentFlags;
1194        accessChain.alignment |= alignment;
1195    }
1196
1197    // push new swizzle onto the end of any existing swizzle, merging into a single swizzle
1198    void accessChainPushSwizzle(std::vector<unsigned>& swizzle, Id preSwizzleBaseType,
1199        AccessChain::CoherentFlags coherentFlags, unsigned int alignment);
1200
1201    // push a dynamic component selection onto the access chain, only applicable with a
1202    // non-trivial swizzle or no swizzle
1203    void accessChainPushComponent(Id component, Id preSwizzleBaseType, AccessChain::CoherentFlags coherentFlags,
1204        unsigned int alignment)
1205    {
1206        if (accessChain.swizzle.size() != 1) {
1207            accessChain.component = component;
1208            if (accessChain.preSwizzleBaseType == NoType)
1209                accessChain.preSwizzleBaseType = preSwizzleBaseType;
1210        }
1211        accessChain.coherentFlags |= coherentFlags;
1212        accessChain.alignment |= alignment;
1213    }
1214
1215    // use accessChain and swizzle to store value
1216    void accessChainStore(Id rvalue, Decoration nonUniform,
1217        spv::MemoryAccessMask memoryAccess = spv::MemoryAccessMask::MaskNone,
1218        spv::Scope scope = spv::Scope::Max, unsigned int alignment = 0);
1219
1220    // use accessChain and swizzle to load an r-value
1221    Id accessChainLoad(Decoration precision, Decoration l_nonUniform, Decoration r_nonUniform, Id ResultType,
1222        spv::MemoryAccessMask memoryAccess = spv::MemoryAccessMask::MaskNone, spv::Scope scope = spv::Scope::Max,
1223            unsigned int alignment = 0);
1224
1225    // Return whether or not the access chain can be represented in SPIR-V
1226    // as an l-value.
1227    // E.g., a[3].yx cannot be, while a[3].y and a[3].y[x] can be.
1228    bool isSpvLvalue() const { return accessChain.swizzle.size() <= 1; }
1229
1230    // get the direct pointer for an l-value
1231    Id accessChainGetLValue();
1232
1233    // Get the inferred SPIR-V type of the result of the current access chain,
1234    // based on the type of the base and the chain of dereferences.
1235    Id accessChainGetInferredType();
1236
1237    // Add capabilities, extensions, remove unneeded decorations, etc.,
1238    // based on the resulting SPIR-V.
1239    void postProcess(bool compileOnly);
1240
1241    // Prune unreachable blocks in the CFG and remove unneeded decorations.
1242    void postProcessCFG();
1243
1244    // Add capabilities, extensions based on instructions in the module.
1245    void postProcessFeatures();
1246    // Hook to visit each instruction in a block in a function
1247    void postProcess(Instruction&);
1248    // Hook to visit each non-32-bit sized float/int operation in a block.
1249    void postProcessType(const Instruction&, spv::Id typeId);
1250    // move OpSampledImage instructions to be next to their users.
1251    void postProcessSamplers();
1252
1253    void dump(std::vector<unsigned int>&) const;
1254
1255    // Add a branch to the target block.
1256    // If set implicit, the branch instruction shouldn't have debug source location.
1257    void createBranch(bool implicit, Block* block);
1258    void createConditionalBranch(Id condition, Block* thenBlock, Block* elseBlock);
1259    void createLoopMerge(Block* mergeBlock, Block* continueBlock, LoopControlMask control,
1260        const std::vector<unsigned int>& operands);
1261
1262    // Sets to generate opcode for specialization constants.
1263    void setToSpecConstCodeGenMode() { generatingOpCodeForSpecConst = true; }
1264    // Sets to generate opcode for non-specialization constants (normal mode).
1265    void setToNormalCodeGenMode() { generatingOpCodeForSpecConst = false; }
1266    // Check if the builder is generating code for spec constants.
1267    bool isInSpecConstCodeGenMode() { return generatingOpCodeForSpecConst; }
1268
1269    void setUseReplicatedComposites(bool use) { useReplicatedComposites = use; }
1270
1271private:
1272    // Helper to get size of a scalar (in bytes)
1273    unsigned int postProcessGetLargestScalarSize(const Instruction& type);
1274
1275protected:
1276    Id findScalarConstant(Op typeClass, Op opcode, Id typeId, unsigned value);
1277    Id findScalarConstant(Op typeClass, Op opcode, Id typeId, unsigned v1, unsigned v2);
1278    Id findCompositeConstant(Op typeClass, Op opcode, Id typeId, const std::vector<Id>& comps, size_t numMembers);
1279    Id findStructConstant(Id typeId, const std::vector<Id>& comps, size_t numMembers);
1280    Id collapseAccessChain();
1281    Id getOrCreateDescHeapByteArrayType();
1282    void remapDynamicSwizzle();
1283    void transferAccessChainSwizzle(bool dynamic);
1284    void simplifyAccessChainSwizzle();
1285    void createAndSetNoPredecessorBlock(const char*);
1286    void createSelectionMerge(Block* mergeBlock, SelectionControlMask control);
1287    void dumpSourceInstructions(std::vector<unsigned int>&) const;
1288    void dumpSourceInstructions(const spv::Id fileId, const std::string& text, std::vector<unsigned int>&) const;
1289    template <class Range> void dumpInstructions(std::vector<unsigned int>& out, const Range& instructions) const;
1290    void dumpModuleProcesses(std::vector<unsigned int>&) const;
1291    spv::MemoryAccessMask sanitizeMemoryAccessForStorageClass(spv::MemoryAccessMask memoryAccess, StorageClass sc)
1292        const;
1293    struct DecorationInstructionLessThan {
1294        bool operator()(const std::unique_ptr<Instruction>& lhs, const std::unique_ptr<Instruction>& rhs) const;
1295    };
1296    template <typename SpvUtilsType>
1297    Id makeFloatConstantHelper(float f, Id typeId, bool specConstant);
1298
1299    unsigned int spvVersion;     // the version of SPIR-V to emit in the header
1300    SourceLanguage sourceLang;
1301    int sourceVersion;
1302    spv::Id nonSemanticShaderCompilationUnitId {0};
1303    spv::Id nonSemanticShaderDebugInfo {0};
1304    // Pointer to the OpExtInstImport instruction for NonSemantic.Shader.DebugInfo.
1305    // Kept so requireNonSemanticShaderDebugInfoVersion() can patch the name in place.
1306    Instruction* nonSemanticShaderDebugInfoImportInst {nullptr};
1307    // Spec version encoded in the NonSemantic.Shader.DebugInfo import name.
1308    // Defaults to 100. Promoted to N the first time a version-N opcode is emitted.
1309    unsigned int nonSemanticShaderDebugInfoVersion{100};
1310    spv::Id debugInfoNone {0};
1311    spv::Id debugExpression {0}; // Debug expression with zero operations.
1312    std::string sourceText;
1313
1314    // True if an new OpLine/OpDebugLine may need to be inserted. Either:
1315    // 1. The current debug location changed
1316    // 2. The current build point changed
1317    bool dirtyLineTracker;
1318    int currentLine = 0;
1319    // OpString id of the current file name. Always 0 if debug info is off.
1320    spv::Id currentFileId = 0;
1321    // OpString id of the main file name. Always 0 if debug info is off.
1322    spv::Id mainFileId = 0;
1323
1324    // True if an new OpDebugScope may need to be inserted. Either:
1325    // 1. A new lexical block is pushed
1326    // 2. The current build point changed
1327    bool dirtyScopeTracker;
1328    std::stack<spv::Id> currentDebugScopeId;
1329
1330    // This flag toggles tracking of debug info while building the SPIR-V.
1331    bool trackDebugInfo = false;
1332    // This flag toggles emission of SPIR-V debug instructions, like OpLine and OpSource.
1333    bool emitSpirvDebugInfo = false;
1334    // This flag toggles emission of Non-Semantic Debug extension debug instructions.
1335    bool emitNonSemanticShaderDebugInfo = false;
1336    bool restoreNonSemanticShaderDebugInfo = false;
1337    bool emitNonSemanticShaderDebugSource = false;
1338
1339    std::set<std::string> extensions;
1340    std::vector<const char*> sourceExtensions;
1341    std::vector<const char*> moduleProcesses;
1342    AddressingModel addressModel;
1343    MemoryModel memoryModel;
1344    std::set<spv::Capability> capabilities;
1345    int builderNumber;
1346    Module module;
1347    Block* buildPoint;
1348    Id uniqueId;
1349    Function* entryPointFunction;
1350    // This tracks the current function being built, or nullptr if not in a function.
1351    Function const* currentFunction { nullptr };
1352    bool generatingOpCodeForSpecConst;
1353    bool useReplicatedComposites { false };
1354    AccessChain accessChain;
1355
1356    // special blocks of instructions for output
1357    std::vector<std::unique_ptr<Instruction> > strings;
1358    std::vector<std::unique_ptr<Instruction> > imports;
1359    std::vector<std::unique_ptr<Instruction> > entryPoints;
1360    std::vector<std::unique_ptr<Instruction> > executionModes;
1361    std::vector<std::unique_ptr<Instruction> > names;
1362    std::set<std::unique_ptr<Instruction>, DecorationInstructionLessThan> decorations;
1363    std::vector<std::unique_ptr<Instruction> > constantsTypesGlobals;
1364    std::vector<std::unique_ptr<Instruction> > externals;
1365    std::vector<std::unique_ptr<Function> > functions;
1366
1367    // not output, internally used for quick & dirty canonical (unique) creation
1368
1369    // Key for scalar constants (handles both 32-bit and 64-bit)
1370    struct ScalarConstantKey {
1371        unsigned int typeClass;  // OpTypeInt, OpTypeFloat, OpTypeBool
1372        unsigned int opcode;     // OpConstant, OpSpecConstant, OpConstantTrue, etc.
1373        Id typeId;               // The specific type
1374        unsigned value1;         // First operand (or only operand)
1375        unsigned value2;         // Second operand (0 for single-operand constants)
1376
1377        bool operator==(const ScalarConstantKey& other) const {
1378            return typeClass == other.typeClass &&
1379                   opcode == other.opcode &&
1380                   typeId == other.typeId &&
1381                   value1 == other.value1 &&
1382                   value2 == other.value2;
1383        }
1384    };
1385
1386    struct ScalarConstantKeyHash {
1387        // 64/32 bit mix function from MurmurHash3
1388        inline std::size_t hash_mix(std::size_t h) const {
1389            if constexpr (sizeof(std::size_t) == 8) {
1390                h ^= h >> 33;
1391                h *= UINT64_C(0xff51afd7ed558ccd);
1392                h ^= h >> 33;
1393                h *= UINT64_C(0xc4ceb9fe1a85ec53);
1394                h ^= h >> 33;
1395                return h;
1396            } else {
1397                h ^= h >> 16;
1398                h *= UINT32_C(0x85ebca6b);
1399                h ^= h >> 13;
1400                h *= UINT32_C(0xc2b2ae35);
1401                h ^= h >> 16;
1402                return h;
1403            }
1404        }
1405
1406        // Hash combine from boost
1407        inline std::size_t hash_combine(std::size_t seed, std::size_t v) const {
1408            return hash_mix(seed + 0x9e3779b9 + v);
1409        }
1410
1411        std::size_t operator()(const ScalarConstantKey& k) const {
1412            size_t hash1 = hash_combine(std::hash<unsigned>{}(k.typeClass), std::hash<unsigned>{}(k.opcode));
1413            size_t hash2 = hash_combine(std::hash<Id>{}(k.value1), std::hash<unsigned>{}(k.value2));
1414            size_t hash3 = hash_combine(hash1, hash2);
1415            return hash_combine(hash3, std::hash<unsigned>{}(k.typeId));
1416        }
1417    };
1418
1419    typedef std::unordered_set<
1420        CompositeConstantKey,
1421        CompositeConstantKey::Hash,
1422        CompositeConstantKey::Equal> CompositeConstantCache;
1423
1424    typedef std::unordered_set<
1425        StructConstantKey,
1426        StructConstantKey::Hash,
1427        StructConstantKey::Equal> StructConstantCache;
1428
1429    // map type opcodes to constant inst.
1430    CompositeConstantCache groupedCompositeConstants;
1431    // map struct-id to constant instructions
1432    StructConstantCache groupedStructConstants;
1433    // map type opcodes to type instructions
1434    std::unordered_map<unsigned int, std::vector<Instruction*>> groupedTypes;
1435    // map type opcodes to debug type instructions
1436    std::unordered_map<unsigned int, std::vector<Instruction*>> groupedDebugTypes;
1437    // list of OpConstantNull instructions
1438    std::vector<Instruction*> nullConstants;
1439    // map scalar constants to result IDs
1440    std::unordered_map<ScalarConstantKey, Id, ScalarConstantKeyHash> groupedScalarConstantResultIDs;
1441    // map type ids to OpConstantSizeOfEXT result IDs
1442    std::unordered_map<Id, Id> constantSizeOfEXTIds;
1443
1444    // Descriptor heap shifted base cache.
1445    std::map<std::pair<Id, Id>, Id> descHeapShiftedBaseCache;
1446
1447    // Descriptor heap byte array type.
1448    Id descHeapByteArrayType;
1449
1450    // Track which types have explicit layouts, to avoid reusing in storage classes without layout.
1451    // Currently only tracks array types.
1452    std::unordered_set<unsigned int> explicitlyLaidOut;
1453
1454    // stack of switches
1455    std::stack<Block*> switchMerges;
1456
1457    // Our loop stack.
1458    std::stack<LoopBlocks> loops;
1459
1460    // map from strings to their string ids
1461    std::unordered_map<std::string, spv::Id> stringIds;
1462
1463    // map from include file name ids to their contents
1464    std::map<spv::Id, const std::string*> includeFiles;
1465
1466    // maps from OpTypeXXX id to DebugTypeXXX id
1467    std::unordered_map<spv::Id, spv::Id> debugTypeIdLookup;
1468
1469    // maps from OpFunction id to DebugFunction id
1470    std::unordered_map<spv::Id, spv::Id> debugFuncIdLookup;
1471
1472    // map from file name string id to DebugSource id
1473    std::unordered_map<spv::Id, spv::Id> debugSourceId;
1474
1475    // The stream for outputting warnings and errors.
1476    SpvBuildLogger* logger;
1477};  // end Builder class
1478
1479} // end spv namespace
1480
1481#endif // SpvBuilder_H