Coverage Report

Created: 2025-08-29 07:31

/src/shaderc/third_party/glslang/SPIRV/SpvBuilder.h
Line
Count
Source (jump to first uncovered line)
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
56
namespace spv {
57
    #include "GLSL.ext.KHR.h"
58
    #include "GLSL.ext.EXT.h"
59
    #include "NonSemanticShaderDebugInfo100.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
73
namespace spv {
74
75
typedef 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
85
class Builder {
86
public:
87
    Builder(unsigned int spvVersion, unsigned int userNumber, SpvBuildLogger* logger);
88
    virtual ~Builder();
89
90
    static const int maxMatrixSize = 4;
91
92
3.74k
    unsigned int getSpvVersion() const { return spvVersion; }
93
94
    void setSource(spv::SourceLanguage lang, int version)
95
2.66k
    {
96
2.66k
        sourceLang = lang;
97
2.66k
        sourceVersion = version;
98
2.66k
    }
99
    spv::Id getStringId(const std::string& str)
100
54
    {
101
54
        auto sItr = stringIds.find(str);
102
54
        if (sItr != stringIds.end())
103
0
            return sItr->second;
104
54
        spv::Id strId = getUniqueId();
105
54
        Instruction* fileString = new Instruction(strId, NoType, Op::OpString);
106
54
        const char* file_c_str = str.c_str();
107
54
        fileString->addStringOperand(file_c_str);
108
54
        strings.push_back(std::unique_ptr<Instruction>(fileString));
109
54
        module.mapInstruction(fileString);
110
54
        stringIds[file_c_str] = strId;
111
54
        return strId;
112
54
    }
113
114
0
    spv::Id getMainFileId() const { return mainFileId; }
115
116
    // Initialize the main source file name
117
    void setDebugMainSourceFile(const std::string& file)
118
0
    {
119
0
        if (trackDebugInfo) {
120
0
            dirtyLineTracker = true;
121
0
            mainFileId = getStringId(file);
122
0
            currentFileId = mainFileId;
123
0
        }
124
0
    }
125
126
    // Set the debug source location tracker in the builder.
127
    // The upcoming instructions in basic blocks will be associated to this location.
128
    void setDebugSourceLocation(int line, const char* filename)
129
250k
    {
130
250k
        if (trackDebugInfo) {
131
0
            dirtyLineTracker = true;
132
0
            if (line != 0) {
133
                // TODO: This is special handling of some AST nodes having (untracked) line 0. 
134
                //       But they should have a valid line number.
135
0
                currentLine = line;
136
0
                if (filename) {
137
0
                    currentFileId = getStringId(filename);
138
0
                }
139
0
            }
140
0
        }
141
250k
    }
142
143
0
    void setSourceText(const std::string& text) { sourceText = text; }
144
7.50k
    void addSourceExtension(const char* ext) { sourceExtensions.push_back(ext); }
145
0
    void addModuleProcessed(const std::string& p) { moduleProcesses.push_back(p.c_str()); }
146
    void setEmitSpirvDebugInfo()
147
0
    {
148
0
        trackDebugInfo = true;
149
0
        emitSpirvDebugInfo = true;
150
0
    }
151
    void setEmitNonSemanticShaderDebugInfo(bool emitSourceText)
152
0
    {
153
0
        trackDebugInfo = true;
154
0
        emitNonSemanticShaderDebugInfo = true;
155
0
        importNonSemanticShaderDebugInfoInstructions();
156
157
0
        if (emitSourceText) {
158
0
            emitNonSemanticShaderDebugSource = emitSourceText;
159
0
        }
160
0
    }
161
8.98k
    void addExtension(const char* ext) { extensions.insert(ext); }
162
    void removeExtension(const char* ext)
163
0
    {
164
0
        extensions.erase(ext);
165
0
    }
166
    void addIncorporatedExtension(const char* ext, SpvVersion incorporatedVersion)
167
656
    {
168
656
        if (getSpvVersion() < static_cast<unsigned>(incorporatedVersion))
169
656
            addExtension(ext);
170
656
    }
171
    void promoteIncorporatedExtension(const char* baseExt, const char* promoExt, SpvVersion incorporatedVersion)
172
0
    {
173
0
        removeExtension(baseExt);
174
0
        addIncorporatedExtension(promoExt, incorporatedVersion);
175
0
    }
176
    void addInclude(const std::string& name, const std::string& text)
177
0
    {
178
0
        spv::Id incId = getStringId(name);
179
0
        includeFiles[incId] = &text;
180
0
    }
181
    Id import(const char*);
182
    void setMemoryModel(spv::AddressingModel addr, spv::MemoryModel mem)
183
2.66k
    {
184
2.66k
        addressModel = addr;
185
2.66k
        memoryModel = mem;
186
2.66k
    }
187
188
68.6k
    void addCapability(spv::Capability cap) { capabilities.insert(cap); }
189
190
    // To get a new <id> for anything needing a new one.
191
294k
    Id getUniqueId() { return ++uniqueId; }
192
193
    // To get a set of new <id>s, e.g., for a set of function parameters
194
    Id getUniqueIds(int numIds)
195
1.13k
    {
196
1.13k
        Id id = uniqueId + 1;
197
1.13k
        uniqueId += numIds;
198
1.13k
        return id;
199
1.13k
    }
200
201
    // For creating new types (will return old type if the requested one was already made).
202
    Id makeVoidType();
203
    Id makeBoolType();
204
    Id makePointer(StorageClass, Id pointee);
205
    Id makeForwardPointer(StorageClass);
206
    Id makePointerFromForwardPointer(StorageClass, Id forwardPointerType, Id pointee);
207
    Id makeIntegerType(int width, bool hasSign);   // generic
208
70.8k
    Id makeIntType(int width) { return makeIntegerType(width, true); }
209
45.4k
    Id makeUintType(int width) { return makeIntegerType(width, false); }
210
    Id makeFloatType(int width);
211
    Id makeBFloat16Type();
212
    Id makeFloatE5M2Type();
213
    Id makeFloatE4M3Type();
214
    Id makeStructType(const std::vector<Id>& members, const char* name, bool const compilerGenerated = true);
215
    Id makeStructResultType(Id type0, Id type1);
216
    Id makeVectorType(Id component, int size);
217
    Id makeMatrixType(Id component, int cols, int rows);
218
    Id makeArrayType(Id element, Id sizeId, int stride);  // 0 stride means no stride decoration
219
    Id makeRuntimeArray(Id element);
220
    Id makeFunctionType(Id returnType, const std::vector<Id>& paramTypes);
221
    Id makeImageType(Id sampledType, Dim, bool depth, bool arrayed, bool ms, unsigned sampled, ImageFormat format);
222
    Id makeSamplerType();
223
    Id makeSampledImageType(Id imageType);
224
    Id makeCooperativeMatrixTypeKHR(Id component, Id scope, Id rows, Id cols, Id use);
225
    Id makeCooperativeMatrixTypeNV(Id component, Id scope, Id rows, Id cols);
226
    Id makeCooperativeMatrixTypeWithSameShape(Id component, Id otherType);
227
    Id makeCooperativeVectorTypeNV(Id componentType, Id components);
228
    Id makeTensorTypeARM(Id elementType, Id rank);
229
    Id makeGenericType(spv::Op opcode, std::vector<spv::IdImmediate>& operands);
230
231
    // SPIR-V NonSemantic Shader DebugInfo Instructions
232
    struct DebugTypeLoc {
233
        std::string name {};
234
        int line {0};
235
        int column {0};
236
    };
237
    std::unordered_map<Id, DebugTypeLoc> debugTypeLocs;
238
    Id makeDebugInfoNone();
239
    Id makeBoolDebugType(int const size);
240
    Id makeIntegerDebugType(int const width, bool const hasSign);
241
    Id makeFloatDebugType(int const width);
242
    Id makeSequentialDebugType(Id const baseType, Id const componentCount, NonSemanticShaderDebugInfo100Instructions const sequenceType);
243
    Id makeArrayDebugType(Id const baseType, Id const componentCount);
244
    Id makeVectorDebugType(Id const baseType, int const componentCount);
245
    Id makeMatrixDebugType(Id const vectorType, int const vectorCount, bool columnMajor = true);
246
    Id makeMemberDebugType(Id const memberType, DebugTypeLoc const& debugTypeLoc);
247
    Id makeCompositeDebugType(std::vector<Id> const& memberTypes, char const*const name,
248
        NonSemanticShaderDebugInfo100DebugCompositeType const tag, bool const isOpaqueType = false);
249
    Id makePointerDebugType(StorageClass storageClass, Id const baseType);
250
    Id makeForwardPointerDebugType(StorageClass storageClass);
251
    Id makeDebugSource(const Id fileName);
252
    Id makeDebugCompilationUnit();
253
    Id createDebugGlobalVariable(Id const type, char const*const name, Id const variable);
254
    Id createDebugLocalVariable(Id type, char const*const name, size_t const argNumber = 0);
255
    Id makeDebugExpression();
256
    Id makeDebugDeclare(Id const debugLocalVariable, Id const pointer);
257
    Id makeDebugValue(Id const debugLocalVariable, Id const value);
258
    Id makeDebugFunctionType(Id returnType, const std::vector<Id>& paramTypes);
259
    Id makeDebugFunction(Function* function, Id nameId, Id funcTypeId);
260
    Id makeDebugLexicalBlock(uint32_t line, uint32_t column);
261
    std::string unmangleFunctionName(std::string const& name) const;
262
263
    // Initialize non-semantic debug information for a function, including those of:
264
    // - The function definition
265
    // - The function parameters
266
    void setupFunctionDebugInfo(Function* function, const char* name, const std::vector<Id>& paramTypes,
267
                                const std::vector<char const*>& paramNames);
268
269
    // accelerationStructureNV type
270
    Id makeAccelerationStructureType();
271
    // rayQueryEXT type
272
    Id makeRayQueryType();
273
    // hitObjectNV type
274
    Id makeHitObjectNVType();
275
276
    // For querying about types.
277
1.80M
    Id getTypeId(Id resultId) const { return module.getTypeId(resultId); }
278
    Id getDerefTypeId(Id resultId) const;
279
512k
    Op getOpCode(Id id) const { return module.getInstruction(id)->getOpCode(); }
280
508k
    Op getTypeClass(Id typeId) const { return getOpCode(typeId); }
281
    Op getMostBasicTypeClass(Id typeId) const;
282
40.2k
    unsigned int getNumComponents(Id resultId) const { return getNumTypeComponents(getTypeId(resultId)); }
283
    unsigned int getNumTypeConstituents(Id typeId) const;
284
63.5k
    unsigned int getNumTypeComponents(Id typeId) const { return getNumTypeConstituents(typeId); }
285
    Id getScalarTypeId(Id typeId) const;
286
    Id getContainedTypeId(Id typeId) const;
287
    Id getContainedTypeId(Id typeId, int) const;
288
474k
    StorageClass getTypeStorageClass(Id typeId) const { return module.getStorageClass(typeId); }
289
    ImageFormat getImageTypeFormat(Id typeId) const
290
584
        { return (ImageFormat)module.getInstruction(typeId)->getImmediateOperand(6); }
291
    Id getResultingAccessChainType() const;
292
762
    Id getIdOperand(Id resultId, int idx) { return module.getInstruction(resultId)->getIdOperand(idx); }
293
0
    Id getCooperativeVectorNumComponents(Id typeId) const { return module.getInstruction(typeId)->getIdOperand(1); }
294
295
100k
    bool isPointer(Id resultId)      const { return isPointerType(getTypeId(resultId)); }
296
4.24k
    bool isScalar(Id resultId)       const { return isScalarType(getTypeId(resultId)); }
297
6.29k
    bool isVector(Id resultId)       const { return isVectorType(getTypeId(resultId)); }
298
37.0k
    bool isMatrix(Id resultId)       const { return isMatrixType(getTypeId(resultId)); }
299
35.5k
    bool isCooperativeMatrix(Id resultId)const { return isCooperativeMatrixType(getTypeId(resultId)); }
300
1.50k
    bool isCooperativeVector(Id resultId)const { return isCooperativeVectorType(getTypeId(resultId)); }
301
976
    bool isAggregate(Id resultId)    const { return isAggregateType(getTypeId(resultId)); }
302
5.32k
    bool isSampledImage(Id resultId) const { return isSampledImageType(getTypeId(resultId)); }
303
0
    bool isTensorView(Id resultId)const { return isTensorViewType(getTypeId(resultId)); }
304
305
    bool isBoolType(Id typeId)
306
60
        { return groupedTypes[enumCast(Op::OpTypeBool)].size() > 0 && typeId == groupedTypes[enumCast(Op::OpTypeBool)].back()->getResultId(); }
307
    bool isIntType(Id typeId)          const
308
5.21k
        { return getTypeClass(typeId) == Op::OpTypeInt && module.getInstruction(typeId)->getImmediateOperand(1) != 0; }
309
    bool isUintType(Id typeId)         const
310
0
        { return getTypeClass(typeId) == Op::OpTypeInt && module.getInstruction(typeId)->getImmediateOperand(1) == 0; }
311
3.40k
    bool isFloatType(Id typeId)        const { return getTypeClass(typeId) == Op::OpTypeFloat; }
312
252k
    bool isPointerType(Id typeId)      const { return getTypeClass(typeId) == Op::OpTypePointer; }
313
    bool isScalarType(Id typeId)       const
314
23.3k
        { return getTypeClass(typeId) == Op::OpTypeFloat || getTypeClass(typeId) == Op::OpTypeInt ||
315
23.3k
          getTypeClass(typeId) == Op::OpTypeBool; }
316
20.3k
    bool isVectorType(Id typeId)       const { return getTypeClass(typeId) == Op::OpTypeVector; }
317
37.3k
    bool isMatrixType(Id typeId)       const { return getTypeClass(typeId) == Op::OpTypeMatrix; }
318
35.1k
    bool isStructType(Id typeId)       const { return getTypeClass(typeId) == Op::OpTypeStruct; }
319
1.00k
    bool isArrayType(Id typeId)        const { return getTypeClass(typeId) == Op::OpTypeArray; }
320
    bool isCooperativeMatrixType(Id typeId)const
321
35.9k
    {
322
35.9k
        return getTypeClass(typeId) == Op::OpTypeCooperativeMatrixKHR || getTypeClass(typeId) == Op::OpTypeCooperativeMatrixNV;
323
35.9k
    }
324
0
    bool isTensorViewType(Id typeId) const { return getTypeClass(typeId) == Op::OpTypeTensorViewNV; }
325
6.55k
    bool isCooperativeVectorType(Id typeId) const { return getTypeClass(typeId) == Op::OpTypeCooperativeVectorNV; }
326
0
    bool isTensorTypeARM(Id typeId)    const { return getTypeClass(typeId) == Op::OpTypeTensorARM; }
327
    bool isAggregateType(Id typeId)    const
328
976
        { return isArrayType(typeId) || isStructType(typeId) || isCooperativeMatrixType(typeId); }
329
0
    bool isImageType(Id typeId)        const { return getTypeClass(typeId) == Op::OpTypeImage; }
330
0
    bool isSamplerType(Id typeId)      const { return getTypeClass(typeId) == Op::OpTypeSampler; }
331
6.90k
    bool isSampledImageType(Id typeId) const { return getTypeClass(typeId) == Op::OpTypeSampledImage; }
332
    bool containsType(Id typeId, Op typeOp, unsigned int width) const;
333
    bool containsPhysicalStorageBufferOrArray(Id typeId) const;
334
335
    bool isConstantOpCode(Op opcode) const;
336
    bool isSpecConstantOpCode(Op opcode) const;
337
581
    bool isConstant(Id resultId) const { return isConstantOpCode(getOpCode(resultId)); }
338
723
    bool isConstantScalar(Id resultId) const { return getOpCode(resultId) == Op::OpConstant; }
339
11
    bool isSpecConstant(Id resultId) const { return isSpecConstantOpCode(getOpCode(resultId)); }
340
    unsigned int getConstantScalar(Id resultId) const
341
27.7k
        { return module.getInstruction(resultId)->getImmediateOperand(0); }
342
474k
    StorageClass getStorageClass(Id resultId) const { return getTypeStorageClass(getTypeId(resultId)); }
343
344
0
    bool isVariableOpCode(Op opcode) const { return opcode == Op::OpVariable; }
345
0
    bool isVariable(Id resultId) const { return isVariableOpCode(getOpCode(resultId)); }
346
0
    bool isGlobalStorage(Id resultId) const { return getStorageClass(resultId) != StorageClass::Function; }
347
0
    bool isGlobalVariable(Id resultId) const { return isVariable(resultId) && isGlobalStorage(resultId); }
348
    // See if a resultId is valid for use as an initializer.
349
0
    bool isValidInitializer(Id resultId) const { return isConstant(resultId) || isGlobalVariable(resultId); }
350
351
    int getScalarTypeWidth(Id typeId) const
352
434k
    {
353
434k
        Id scalarTypeId = getScalarTypeId(typeId);
354
434k
        assert(getTypeClass(scalarTypeId) == Op::OpTypeInt || getTypeClass(scalarTypeId) == Op::OpTypeFloat);
355
434k
        return module.getInstruction(scalarTypeId)->getImmediateOperand(0);
356
434k
    }
357
358
    unsigned int getTypeNumColumns(Id typeId) const
359
357
    {
360
357
        assert(isMatrixType(typeId));
361
357
        return getNumTypeConstituents(typeId);
362
357
    }
363
349
    unsigned int getNumColumns(Id resultId) const { return getTypeNumColumns(getTypeId(resultId)); }
364
    unsigned int getTypeNumRows(Id typeId) const
365
652
    {
366
652
        assert(isMatrixType(typeId));
367
652
        return getNumTypeComponents(getContainedTypeId(typeId));
368
652
    }
369
644
    unsigned int getNumRows(Id resultId) const { return getTypeNumRows(getTypeId(resultId)); }
370
371
    Dim getTypeDimensionality(Id typeId) const
372
300
    {
373
300
        assert(isImageType(typeId));
374
300
        return (Dim)module.getInstruction(typeId)->getImmediateOperand(1);
375
300
    }
376
    Id getImageType(Id resultId) const
377
1.58k
    {
378
1.58k
        Id typeId = getTypeId(resultId);
379
1.58k
        assert(isImageType(typeId) || isSampledImageType(typeId));
380
1.58k
        return isSampledImageType(typeId) ? module.getInstruction(typeId)->getIdOperand(0) : typeId;
381
1.58k
    }
382
    bool isArrayedImageType(Id typeId) const
383
300
    {
384
300
        assert(isImageType(typeId));
385
300
        return module.getInstruction(typeId)->getImmediateOperand(3) != 0;
386
300
    }
387
388
    // For making new constants (will return old constant if the requested one was already made).
389
    Id makeNullConstant(Id typeId);
390
    Id makeBoolConstant(bool b, bool specConstant = false);
391
    Id makeIntConstant(Id typeId, unsigned value, bool specConstant);
392
    Id makeInt64Constant(Id typeId, unsigned long long value, bool specConstant);
393
    Id makeInt8Constant(int i, bool specConstant = false)
394
1.89k
        { return makeIntConstant(makeIntType(8),  (unsigned)i, specConstant); }
395
    Id makeUint8Constant(unsigned u, bool specConstant = false)
396
1.89k
        { return makeIntConstant(makeUintType(8),           u, specConstant); }
397
    Id makeInt16Constant(int i, bool specConstant = false)
398
2.05k
        { return makeIntConstant(makeIntType(16),  (unsigned)i, specConstant); }
399
    Id makeUint16Constant(unsigned u, bool specConstant = false)
400
2.04k
        { return makeIntConstant(makeUintType(16),           u, specConstant); }
401
    Id makeIntConstant(int i, bool specConstant = false)
402
29.2k
        { return makeIntConstant(makeIntType(32),  (unsigned)i, specConstant); }
403
    Id makeUintConstant(unsigned u, bool specConstant = false)
404
22.2k
        { return makeIntConstant(makeUintType(32),           u, specConstant); }
405
    Id makeUintConstant(Scope u, bool specConstant = false)
406
2.20k
        { return makeUintConstant((unsigned)u, specConstant); }
407
    Id makeUintConstant(StorageClass u, bool specConstant = false)
408
0
        { return makeUintConstant((unsigned)u, specConstant); }
409
    Id makeUintConstant(MemorySemanticsMask u, bool specConstant = false)
410
2.20k
        { return makeUintConstant((unsigned)u, specConstant); }
411
    Id makeUintConstant(SourceLanguage u, bool specConstant = false)
412
0
        { return makeUintConstant((unsigned)u, specConstant); }
413
    Id makeInt64Constant(long long i, bool specConstant = false)
414
1.95k
        { return makeInt64Constant(makeIntType(64),  (unsigned long long)i, specConstant); }
415
    Id makeUint64Constant(unsigned long long u, bool specConstant = false)
416
2.45k
        { return makeInt64Constant(makeUintType(64),                     u, specConstant); }
417
    Id makeFloatConstant(float f, bool specConstant = false);
418
    Id makeDoubleConstant(double d, bool specConstant = false);
419
    Id makeFloat16Constant(float f16, bool specConstant = false);
420
    Id makeBFloat16Constant(float bf16, bool specConstant = false);
421
    Id makeFloatE5M2Constant(float fe5m2, bool specConstant = false);
422
    Id makeFloatE4M3Constant(float fe4m3, bool specConstant = false);
423
    Id makeFpConstant(Id type, double d, bool specConstant = false);
424
425
    Id importNonSemanticShaderDebugInfoInstructions();
426
427
    // Turn the array of constants into a proper spv constant of the requested type.
428
    Id makeCompositeConstant(Id type, const std::vector<Id>& comps, bool specConst = false);
429
430
    // Methods for adding information outside the CFG.
431
    Instruction* addEntryPoint(ExecutionModel, Function*, const char* name);
432
    void addExecutionMode(Function*, ExecutionMode mode, int value1 = -1, int value2 = -1, int value3 = -1);
433
    void addExecutionMode(Function*, ExecutionMode mode, const std::vector<unsigned>& literals);
434
    void addExecutionModeId(Function*, ExecutionMode mode, const std::vector<Id>& operandIds);
435
    void addName(Id, const char* name);
436
    void addMemberName(Id, int member, const char* name);
437
    void addDecoration(Id, Decoration, int num = -1);
438
    void addDecoration(Id, Decoration, const char*);
439
    void addDecoration(Id, Decoration, const std::vector<unsigned>& literals);
440
    void addDecoration(Id, Decoration, const std::vector<const char*>& strings);
441
    void addLinkageDecoration(Id id, const char* name, spv::LinkageType linkType);
442
    void addDecorationId(Id id, Decoration, Id idDecoration);
443
    void addDecorationId(Id id, Decoration, const std::vector<Id>& operandIds);
444
    void addMemberDecoration(Id, unsigned int member, Decoration, int num = -1);
445
    void addMemberDecoration(Id, unsigned int member, Decoration, const char*);
446
    void addMemberDecoration(Id, unsigned int member, Decoration, const std::vector<unsigned>& literals);
447
    void addMemberDecoration(Id, unsigned int member, Decoration, const std::vector<const char*>& strings);
448
449
    // At the end of what block do the next create*() instructions go?
450
    // Also reset current last DebugScope and current source line to unknown
451
37.0k
    void setBuildPoint(Block* bp) {
452
37.0k
        buildPoint = bp;
453
37.0k
        dirtyLineTracker = true;
454
37.0k
        dirtyScopeTracker = true;
455
37.0k
    }
456
8.78k
    Block* getBuildPoint() const { return buildPoint; }
457
458
    // Append an instruction to the end of the current build point.
459
    // Optionally, additional debug info instructions may also be prepended.
460
    void addInstruction(std::unique_ptr<Instruction> inst);
461
462
    // Append an instruction to the end of the current build point without prepending any debug instructions.
463
    // This is useful for insertion of some debug info instructions themselves or some control flow instructions
464
    // that are attached to its predecessor instruction.
465
    void addInstructionNoDebugInfo(std::unique_ptr<Instruction> inst);
466
467
    // Make the entry-point function. The returned pointer is only valid
468
    // for the lifetime of this builder.
469
    Function* makeEntryPoint(const char*);
470
471
    // Make a shader-style function, and create its entry block if entry is non-zero.
472
    // Return the function, pass back the entry.
473
    // The returned pointer is only valid for the lifetime of this builder.
474
    Function* makeFunctionEntry(Decoration precision, Id returnType, const char* name, LinkageType linkType,
475
                                const std::vector<Id>& paramTypes,
476
                                const std::vector<std::vector<Decoration>>& precisions, Block** entry = nullptr);
477
478
    // Create a return. An 'implicit' return is one not appearing in the source
479
    // code.  In the case of an implicit return, no post-return block is inserted.
480
    void makeReturn(bool implicit, Id retVal = 0);
481
482
    // Initialize state and generate instructions for new lexical scope
483
    void enterLexicalBlock(uint32_t line, uint32_t column);
484
485
    // Set state and generate instructions to exit current lexical scope
486
    void leaveLexicalBlock();
487
488
    // Prepare builder for generation of instructions for a function.
489
    void enterFunction(Function const* function);
490
491
    // Generate all the code needed to finish up a function.
492
    void leaveFunction();
493
494
    // Create block terminator instruction for certain statements like
495
    // discard, terminate-invocation, terminateRayEXT, or ignoreIntersectionEXT
496
    void makeStatementTerminator(spv::Op opcode, const char *name);
497
498
    // Create block terminator instruction for statements that have input operands
499
    // such as OpEmitMeshTasksEXT
500
    void makeStatementTerminator(spv::Op opcode, const std::vector<Id>& operands, const char* name);
501
502
    // Create a global or function local or IO variable.
503
    Id createVariable(Decoration precision, StorageClass storageClass, Id type, const char* name = nullptr,
504
        Id initializer = NoResult, bool const compilerGenerated = true);
505
506
    // Create an intermediate with an undefined value.
507
    Id createUndefined(Id type);
508
509
    // Store into an Id and return the l-value
510
    void createStore(Id rValue, Id lValue, spv::MemoryAccessMask memoryAccess = spv::MemoryAccessMask::MaskNone,
511
        spv::Scope scope = spv::Scope::Max, unsigned int alignment = 0);
512
513
    // Load from an Id and return it
514
    Id createLoad(Id lValue, spv::Decoration precision,
515
        spv::MemoryAccessMask memoryAccess = spv::MemoryAccessMask::MaskNone,
516
        spv::Scope scope = spv::Scope::Max, unsigned int alignment = 0);
517
518
    // Create an OpAccessChain instruction
519
    Id createAccessChain(StorageClass, Id base, const std::vector<Id>& offsets);
520
521
    // Create an OpArrayLength instruction
522
    Id createArrayLength(Id base, unsigned int member);
523
524
    // Create an OpCooperativeMatrixLengthKHR instruction
525
    Id createCooperativeMatrixLengthKHR(Id type);
526
    // Create an OpCooperativeMatrixLengthNV instruction
527
    Id createCooperativeMatrixLengthNV(Id type);
528
529
    // Create an OpCompositeExtract instruction
530
    Id createCompositeExtract(Id composite, Id typeId, unsigned index);
531
    Id createCompositeExtract(Id composite, Id typeId, const std::vector<unsigned>& indexes);
532
    Id createCompositeInsert(Id object, Id composite, Id typeId, unsigned index);
533
    Id createCompositeInsert(Id object, Id composite, Id typeId, const std::vector<unsigned>& indexes);
534
535
    Id createVectorExtractDynamic(Id vector, Id typeId, Id componentIndex);
536
    Id createVectorInsertDynamic(Id vector, Id typeId, Id component, Id componentIndex);
537
538
    void createNoResultOp(Op);
539
    void createNoResultOp(Op, Id operand);
540
    void createNoResultOp(Op, const std::vector<Id>& operands);
541
    void createNoResultOp(Op, const std::vector<IdImmediate>& operands);
542
    void createControlBarrier(Scope execution, Scope memory, MemorySemanticsMask);
543
    void createMemoryBarrier(Scope executionScope, MemorySemanticsMask memorySemantics);
544
    Id createUnaryOp(Op, Id typeId, Id operand);
545
    Id createBinOp(Op, Id typeId, Id operand1, Id operand2);
546
    Id createTriOp(Op, Id typeId, Id operand1, Id operand2, Id operand3);
547
    Id createOp(Op, Id typeId, const std::vector<Id>& operands);
548
    Id createOp(Op, Id typeId, const std::vector<IdImmediate>& operands);
549
    Id createFunctionCall(spv::Function*, const std::vector<spv::Id>&);
550
    Id createSpecConstantOp(Op, Id typeId, const std::vector<spv::Id>& operands, const std::vector<unsigned>& literals);
551
552
    // Take an rvalue (source) and a set of channels to extract from it to
553
    // make a new rvalue, which is returned.
554
    Id createRvalueSwizzle(Decoration precision, Id typeId, Id source, const std::vector<unsigned>& channels);
555
556
    // Take a copy of an lvalue (target) and a source of components, and set the
557
    // source components into the lvalue where the 'channels' say to put them.
558
    // An updated version of the target is returned.
559
    // (No true lvalue or stores are used.)
560
    Id createLvalueSwizzle(Id typeId, Id target, Id source, const std::vector<unsigned>& channels);
561
562
    // If both the id and precision are valid, the id
563
    // gets tagged with the requested precision.
564
    // The passed in id is always the returned id, to simplify use patterns.
565
    Id setPrecision(Id id, Decoration precision)
566
155k
    {
567
155k
        if (precision != NoPrecision && id != NoResult)
568
863
            addDecoration(id, precision);
569
570
155k
        return id;
571
155k
    }
572
573
    // Can smear a scalar to a vector for the following forms:
574
    //   - promoteScalar(scalar, vector)  // smear scalar to width of vector
575
    //   - promoteScalar(vector, scalar)  // smear scalar to width of vector
576
    //   - promoteScalar(pointer, scalar) // smear scalar to width of what pointer points to
577
    //   - promoteScalar(scalar, scalar)  // do nothing
578
    // Other forms are not allowed.
579
    //
580
    // Generally, the type of 'scalar' does not need to be the same type as the components in 'vector'.
581
    // The type of the created vector is a vector of components of the same type as the scalar.
582
    //
583
    // Note: One of the arguments will change, with the result coming back that way rather than
584
    // through the return value.
585
    void promoteScalar(Decoration precision, Id& left, Id& right);
586
587
    // Make a value by smearing the scalar to fill the type.
588
    // vectorType should be the correct type for making a vector of scalarVal.
589
    // (No conversions are done.)
590
    Id smearScalar(Decoration precision, Id scalarVal, Id vectorType);
591
592
    // Create a call to a built-in function.
593
    Id createBuiltinCall(Id resultType, Id builtins, int entryPoint, const std::vector<Id>& args);
594
595
    // List of parameters used to create a texture operation
596
    struct TextureParameters {
597
        Id sampler;
598
        Id coords;
599
        Id bias;
600
        Id lod;
601
        Id Dref;
602
        Id offset;
603
        Id offsets;
604
        Id gradX;
605
        Id gradY;
606
        Id sample;
607
        Id component;
608
        Id texelOut;
609
        Id lodClamp;
610
        Id granularity;
611
        Id coarse;
612
        bool nonprivate;
613
        bool volatil;
614
        bool nontemporal;
615
    };
616
617
    // Select the correct texture operation based on all inputs, and emit the correct instruction
618
    Id createTextureCall(Decoration precision, Id resultType, bool sparse, bool fetch, bool proj, bool gather,
619
        bool noImplicit, const TextureParameters&, ImageOperandsMask);
620
621
    // Emit the OpTextureQuery* instruction that was passed in.
622
    // Figure out the right return value and type, and return it.
623
    Id createTextureQueryCall(Op, const TextureParameters&, bool isUnsignedResult);
624
625
    Id createSamplePositionCall(Decoration precision, Id, Id);
626
627
    Id createBitFieldExtractCall(Decoration precision, Id, Id, Id, bool isSigned);
628
    Id createBitFieldInsertCall(Decoration precision, Id, Id, Id, Id);
629
630
    // Reduction comparison for composites:  For equal and not-equal resulting in a scalar.
631
    Id createCompositeCompare(Decoration precision, Id, Id, bool /* true if for equal, false if for not-equal */);
632
633
    // OpCompositeConstruct
634
    Id createCompositeConstruct(Id typeId, const std::vector<Id>& constituents);
635
636
    // vector or scalar constructor
637
    Id createConstructor(Decoration precision, const std::vector<Id>& sources, Id resultTypeId);
638
639
    // matrix constructor
640
    Id createMatrixConstructor(Decoration precision, const std::vector<Id>& sources, Id constructee);
641
642
    // coopmat conversion
643
    Id createCooperativeMatrixConversion(Id typeId, Id source);
644
    Id createCooperativeMatrixReduce(Op opcode, Id typeId, Id source, unsigned int mask, Id func);
645
    Id createCooperativeMatrixPerElementOp(Id typeId, const std::vector<Id>& operands);
646
647
    // Helper to use for building nested control flow with if-then-else.
648
    class If {
649
    public:
650
        If(Id condition, SelectionControlMask ctrl, Builder& builder);
651
3.78k
        ~If() {}
652
653
        void makeBeginElse();
654
        void makeEndIf();
655
656
    private:
657
        If(const If&);
658
        If& operator=(If&);
659
660
        Builder& builder;
661
        Id condition;
662
        SelectionControlMask control;
663
        Function* function;
664
        Block* headerBlock;
665
        Block* thenBlock;
666
        Block* elseBlock;
667
        Block* mergeBlock;
668
    };
669
670
    // Make a switch statement.  A switch has 'numSegments' of pieces of code, not containing
671
    // any case/default labels, all separated by one or more case/default labels.  Each possible
672
    // case value v is a jump to the caseValues[v] segment.  The defaultSegment is also in this
673
    // number space.  How to compute the value is given by 'condition', as in switch(condition).
674
    //
675
    // The SPIR-V Builder will maintain the stack of post-switch merge blocks for nested switches.
676
    //
677
    // Use a defaultSegment < 0 if there is no default segment (to branch to post switch).
678
    //
679
    // Returns the right set of basic blocks to start each code segment with, so that the caller's
680
    // recursion stack can hold the memory for it.
681
    //
682
    void makeSwitch(Id condition, SelectionControlMask control, int numSegments, const std::vector<int>& caseValues,
683
                    const std::vector<int>& valueToSegment, int defaultSegment, std::vector<Block*>& segmentBB);
684
685
    // Add a branch to the innermost switch's merge block.
686
    void addSwitchBreak(bool implicit);
687
688
    // Move to the next code segment, passing in the return argument in makeSwitch()
689
    void nextSwitchSegment(std::vector<Block*>& segmentBB, int segment);
690
691
    // Finish off the innermost switch.
692
    void endSwitch(std::vector<Block*>& segmentBB);
693
694
    struct LoopBlocks {
695
        LoopBlocks(Block& head, Block& body, Block& merge, Block& continue_target) :
696
1.78k
            head(head), body(body), merge(merge), continue_target(continue_target) { }
697
        Block &head, &body, &merge, &continue_target;
698
    private:
699
        LoopBlocks();
700
        LoopBlocks& operator=(const LoopBlocks&) = delete;
701
    };
702
703
    // Start a new loop and prepare the builder to generate code for it.  Until
704
    // closeLoop() is called for this loop, createLoopContinue() and
705
    // createLoopExit() will target its corresponding blocks.
706
    LoopBlocks& makeNewLoop();
707
708
    // Create a new block in the function containing the build point.  Memory is
709
    // owned by the function object.
710
    Block& makeNewBlock();
711
712
    // Add a branch to the continue_target of the current (innermost) loop.
713
    void createLoopContinue();
714
715
    // Add an exit (e.g. "break") from the innermost loop that we're currently
716
    // in.
717
    void createLoopExit();
718
719
    // Close the innermost loop that you're in
720
    void closeLoop();
721
722
    //
723
    // Access chain design for an R-Value vs. L-Value:
724
    //
725
    // There is a single access chain the builder is building at
726
    // any particular time.  Such a chain can be used to either to a load or
727
    // a store, when desired.
728
    //
729
    // Expressions can be r-values, l-values, or both, or only r-values:
730
    //    a[b.c].d = ....  // l-value
731
    //    ... = a[b.c].d;  // r-value, that also looks like an l-value
732
    //    ++a[b.c].d;      // r-value and l-value
733
    //    (x + y)[2];      // r-value only, can't possibly be l-value
734
    //
735
    // Computing an r-value means generating code.  Hence,
736
    // r-values should only be computed when they are needed, not speculatively.
737
    //
738
    // Computing an l-value means saving away information for later use in the compiler,
739
    // no code is generated until the l-value is later dereferenced.  It is okay
740
    // to speculatively generate an l-value, just not okay to speculatively dereference it.
741
    //
742
    // The base of the access chain (the left-most variable or expression
743
    // from which everything is based) can be set either as an l-value
744
    // or as an r-value.  Most efficient would be to set an l-value if one
745
    // is available.  If an expression was evaluated, the resulting r-value
746
    // can be set as the chain base.
747
    //
748
    // The users of this single access chain can save and restore if they
749
    // want to nest or manage multiple chains.
750
    //
751
752
    struct AccessChain {
753
        Id base;                       // for l-values, pointer to the base object, for r-values, the base object
754
        std::vector<Id> indexChain;
755
        Id instr;                      // cache the instruction that generates this access chain
756
        std::vector<unsigned> swizzle; // each std::vector element selects the next GLSL component number
757
        Id component;                  // a dynamic component index, can coexist with a swizzle,
758
                                       // done after the swizzle, NoResult if not present
759
        Id preSwizzleBaseType;         // dereferenced type, before swizzle or component is applied;
760
                                       // NoType unless a swizzle or component is present
761
        bool isRValue;                 // true if 'base' is an r-value, otherwise, base is an l-value
762
        unsigned int alignment;        // bitwise OR of alignment values passed in. Accumulates worst alignment.
763
                                       // Only tracks base and (optional) component selection alignment.
764
765
        // Accumulate whether anything in the chain of structures has coherent decorations.
766
        struct CoherentFlags {
767
287k
            CoherentFlags() { clear(); }
768
2.57k
            bool isVolatile() const { return volatil; }
769
159k
            bool isNonUniform() const { return nonUniform; }
770
192k
            bool anyCoherent() const {
771
192k
                return coherent || devicecoherent || queuefamilycoherent || workgroupcoherent ||
772
192k
                    subgroupcoherent || shadercallcoherent;
773
192k
            }
774
775
            unsigned coherent : 1;
776
            unsigned devicecoherent : 1;
777
            unsigned queuefamilycoherent : 1;
778
            unsigned workgroupcoherent : 1;
779
            unsigned subgroupcoherent : 1;
780
            unsigned shadercallcoherent : 1;
781
            unsigned nonprivate : 1;
782
            unsigned volatil : 1;
783
            unsigned nontemporal : 1;
784
            unsigned isImage : 1;
785
            unsigned nonUniform : 1;
786
787
626k
            void clear() {
788
626k
                coherent = 0;
789
626k
                devicecoherent = 0;
790
626k
                queuefamilycoherent = 0;
791
626k
                workgroupcoherent = 0;
792
626k
                subgroupcoherent = 0;
793
626k
                shadercallcoherent = 0;
794
626k
                nonprivate = 0;
795
626k
                volatil = 0;
796
626k
                nontemporal = 0;
797
626k
                isImage = 0;
798
626k
                nonUniform = 0;
799
626k
            }
800
801
184k
            CoherentFlags operator |=(const CoherentFlags &other) {
802
184k
                coherent |= other.coherent;
803
184k
                devicecoherent |= other.devicecoherent;
804
184k
                queuefamilycoherent |= other.queuefamilycoherent;
805
184k
                workgroupcoherent |= other.workgroupcoherent;
806
184k
                subgroupcoherent |= other.subgroupcoherent;
807
184k
                shadercallcoherent |= other.shadercallcoherent;
808
184k
                nonprivate |= other.nonprivate;
809
184k
                volatil |= other.volatil;
810
184k
                nontemporal = other.nontemporal;
811
184k
                isImage |= other.isImage;
812
184k
                nonUniform |= other.nonUniform;
813
184k
                return *this;
814
184k
            }
815
        };
816
        CoherentFlags coherentFlags;
817
    };
818
819
    //
820
    // the SPIR-V builder maintains a single active chain that
821
    // the following methods operate on
822
    //
823
824
    // for external save and restore
825
485k
    AccessChain getAccessChain() { return accessChain; }
826
35.5k
    void setAccessChain(AccessChain newChain) { accessChain = newChain; }
827
828
    // clear accessChain
829
    void clearAccessChain();
830
831
    // set new base as an l-value base
832
    void setAccessChainLValue(Id lValue)
833
91.5k
    {
834
91.5k
        assert(isPointer(lValue));
835
91.5k
        accessChain.base = lValue;
836
91.5k
    }
837
838
    // set new base value as an r-value
839
    void setAccessChainRValue(Id rValue)
840
100k
    {
841
100k
        accessChain.isRValue = true;
842
100k
        accessChain.base = rValue;
843
100k
    }
844
845
    // push offset onto the end of the chain
846
    void accessChainPush(Id offset, AccessChain::CoherentFlags coherentFlags, unsigned int alignment)
847
13.2k
    {
848
13.2k
        accessChain.indexChain.push_back(offset);
849
13.2k
        accessChain.coherentFlags |= coherentFlags;
850
13.2k
        accessChain.alignment |= alignment;
851
13.2k
    }
852
853
    // push new swizzle onto the end of any existing swizzle, merging into a single swizzle
854
    void accessChainPushSwizzle(std::vector<unsigned>& swizzle, Id preSwizzleBaseType,
855
        AccessChain::CoherentFlags coherentFlags, unsigned int alignment);
856
857
    // push a dynamic component selection onto the access chain, only applicable with a
858
    // non-trivial swizzle or no swizzle
859
    void accessChainPushComponent(Id component, Id preSwizzleBaseType, AccessChain::CoherentFlags coherentFlags,
860
        unsigned int alignment)
861
6
    {
862
6
        if (accessChain.swizzle.size() != 1) {
863
6
            accessChain.component = component;
864
6
            if (accessChain.preSwizzleBaseType == NoType)
865
6
                accessChain.preSwizzleBaseType = preSwizzleBaseType;
866
6
        }
867
6
        accessChain.coherentFlags |= coherentFlags;
868
6
        accessChain.alignment |= alignment;
869
6
    }
870
871
    // use accessChain and swizzle to store value
872
    void accessChainStore(Id rvalue, Decoration nonUniform,
873
        spv::MemoryAccessMask memoryAccess = spv::MemoryAccessMask::MaskNone,
874
        spv::Scope scope = spv::Scope::Max, unsigned int alignment = 0);
875
876
    // use accessChain and swizzle to load an r-value
877
    Id accessChainLoad(Decoration precision, Decoration l_nonUniform, Decoration r_nonUniform, Id ResultType,
878
        spv::MemoryAccessMask memoryAccess = spv::MemoryAccessMask::MaskNone, spv::Scope scope = spv::Scope::Max,
879
            unsigned int alignment = 0);
880
881
    // Return whether or not the access chain can be represented in SPIR-V
882
    // as an l-value.
883
    // E.g., a[3].yx cannot be, while a[3].y and a[3].y[x] can be.
884
2.19k
    bool isSpvLvalue() const { return accessChain.swizzle.size() <= 1; }
885
886
    // get the direct pointer for an l-value
887
    Id accessChainGetLValue();
888
889
    // Get the inferred SPIR-V type of the result of the current access chain,
890
    // based on the type of the base and the chain of dereferences.
891
    Id accessChainGetInferredType();
892
893
    // Add capabilities, extensions, remove unneeded decorations, etc.,
894
    // based on the resulting SPIR-V.
895
    void postProcess(bool compileOnly);
896
897
    // Prune unreachable blocks in the CFG and remove unneeded decorations.
898
    void postProcessCFG();
899
900
    // Add capabilities, extensions based on instructions in the module.
901
    void postProcessFeatures();
902
    // Hook to visit each instruction in a block in a function
903
    void postProcess(Instruction&);
904
    // Hook to visit each non-32-bit sized float/int operation in a block.
905
    void postProcessType(const Instruction&, spv::Id typeId);
906
    // move OpSampledImage instructions to be next to their users.
907
    void postProcessSamplers();
908
909
    void dump(std::vector<unsigned int>&) const;
910
911
    // Add a branch to the target block.
912
    // If set implicit, the branch instruction shouldn't have debug source location.
913
    void createBranch(bool implicit, Block* block);
914
    void createConditionalBranch(Id condition, Block* thenBlock, Block* elseBlock);
915
    void createLoopMerge(Block* mergeBlock, Block* continueBlock, LoopControlMask control,
916
        const std::vector<unsigned int>& operands);
917
918
    // Sets to generate opcode for specialization constants.
919
3.46k
    void setToSpecConstCodeGenMode() { generatingOpCodeForSpecConst = true; }
920
    // Sets to generate opcode for non-specialization constants (normal mode).
921
258k
    void setToNormalCodeGenMode() { generatingOpCodeForSpecConst = false; }
922
    // Check if the builder is generating code for spec constants.
923
260k
    bool isInSpecConstCodeGenMode() { return generatingOpCodeForSpecConst; }
924
925
2.66k
    void setUseReplicatedComposites(bool use) { useReplicatedComposites = use; }
926
927
 protected:
928
    Id findScalarConstant(Op typeClass, Op opcode, Id typeId, unsigned value);
929
    Id findScalarConstant(Op typeClass, Op opcode, Id typeId, unsigned v1, unsigned v2);
930
    Id findCompositeConstant(Op typeClass, Op opcode, Id typeId, const std::vector<Id>& comps, size_t numMembers);
931
    Id findStructConstant(Id typeId, const std::vector<Id>& comps);
932
    Id collapseAccessChain();
933
    void remapDynamicSwizzle();
934
    void transferAccessChainSwizzle(bool dynamic);
935
    void simplifyAccessChainSwizzle();
936
    void createAndSetNoPredecessorBlock(const char*);
937
    void createSelectionMerge(Block* mergeBlock, SelectionControlMask control);
938
    void dumpSourceInstructions(std::vector<unsigned int>&) const;
939
    void dumpSourceInstructions(const spv::Id fileId, const std::string& text, std::vector<unsigned int>&) const;
940
    template <class Range> void dumpInstructions(std::vector<unsigned int>& out, const Range& instructions) const;
941
    void dumpModuleProcesses(std::vector<unsigned int>&) const;
942
    spv::MemoryAccessMask sanitizeMemoryAccessForStorageClass(spv::MemoryAccessMask memoryAccess, StorageClass sc)
943
        const;
944
    struct DecorationInstructionLessThan {
945
        bool operator()(const std::unique_ptr<Instruction>& lhs, const std::unique_ptr<Instruction>& rhs) const;
946
    };
947
948
    unsigned int spvVersion;     // the version of SPIR-V to emit in the header
949
    SourceLanguage sourceLang;
950
    int sourceVersion;
951
    spv::Id nonSemanticShaderCompilationUnitId {0};
952
    spv::Id nonSemanticShaderDebugInfo {0};
953
    spv::Id debugInfoNone {0};
954
    spv::Id debugExpression {0}; // Debug expression with zero operations.
955
    std::string sourceText;
956
957
    // True if an new OpLine/OpDebugLine may need to be inserted. Either:
958
    // 1. The current debug location changed
959
    // 2. The current build point changed
960
    bool dirtyLineTracker;
961
    int currentLine = 0;
962
    // OpString id of the current file name. Always 0 if debug info is off.
963
    spv::Id currentFileId = 0;
964
    // OpString id of the main file name. Always 0 if debug info is off.
965
    spv::Id mainFileId = 0;
966
967
    // True if an new OpDebugScope may need to be inserted. Either:
968
    // 1. A new lexical block is pushed
969
    // 2. The current build point changed
970
    bool dirtyScopeTracker;
971
    std::stack<spv::Id> currentDebugScopeId;
972
973
    // This flag toggles tracking of debug info while building the SPIR-V.
974
    bool trackDebugInfo = false;
975
    // This flag toggles emission of SPIR-V debug instructions, like OpLine and OpSource.
976
    bool emitSpirvDebugInfo = false;
977
    // This flag toggles emission of Non-Semantic Debug extension debug instructions.
978
    bool emitNonSemanticShaderDebugInfo = false;
979
    bool restoreNonSemanticShaderDebugInfo = false;
980
    bool emitNonSemanticShaderDebugSource = false;
981
982
    std::set<std::string> extensions;
983
    std::vector<const char*> sourceExtensions;
984
    std::vector<const char*> moduleProcesses;
985
    AddressingModel addressModel;
986
    MemoryModel memoryModel;
987
    std::set<spv::Capability> capabilities;
988
    int builderNumber;
989
    Module module;
990
    Block* buildPoint;
991
    Id uniqueId;
992
    Function* entryPointFunction;
993
    bool generatingOpCodeForSpecConst;
994
    bool useReplicatedComposites { false };
995
    AccessChain accessChain;
996
997
    // special blocks of instructions for output
998
    std::vector<std::unique_ptr<Instruction> > strings;
999
    std::vector<std::unique_ptr<Instruction> > imports;
1000
    std::vector<std::unique_ptr<Instruction> > entryPoints;
1001
    std::vector<std::unique_ptr<Instruction> > executionModes;
1002
    std::vector<std::unique_ptr<Instruction> > names;
1003
    std::set<std::unique_ptr<Instruction>, DecorationInstructionLessThan> decorations;
1004
    std::vector<std::unique_ptr<Instruction> > constantsTypesGlobals;
1005
    std::vector<std::unique_ptr<Instruction> > externals;
1006
    std::vector<std::unique_ptr<Function> > functions;
1007
1008
    // not output, internally used for quick & dirty canonical (unique) creation
1009
1010
    // map type opcodes to constant inst.
1011
    std::unordered_map<unsigned int, std::vector<Instruction*>> groupedConstants;
1012
    // map struct-id to constant instructions
1013
    std::unordered_map<unsigned int, std::vector<Instruction*>> groupedStructConstants;
1014
    // map type opcodes to type instructions
1015
    std::unordered_map<unsigned int, std::vector<Instruction*>> groupedTypes;
1016
    // map type opcodes to debug type instructions
1017
    std::unordered_map<unsigned int, std::vector<Instruction*>> groupedDebugTypes;
1018
    // list of OpConstantNull instructions
1019
    std::vector<Instruction*> nullConstants;
1020
1021
    // Track which types have explicit layouts, to avoid reusing in storage classes without layout.
1022
    // Currently only tracks array types.
1023
    std::unordered_set<unsigned int> explicitlyLaidOut;
1024
1025
    // stack of switches
1026
    std::stack<Block*> switchMerges;
1027
1028
    // Our loop stack.
1029
    std::stack<LoopBlocks> loops;
1030
1031
    // map from strings to their string ids
1032
    std::unordered_map<std::string, spv::Id> stringIds;
1033
1034
    // map from include file name ids to their contents
1035
    std::map<spv::Id, const std::string*> includeFiles;
1036
1037
    // map from core id to debug id
1038
    std::map <spv::Id, spv::Id> debugId;
1039
1040
    // map from file name string id to DebugSource id
1041
    std::unordered_map<spv::Id, spv::Id> debugSourceId;
1042
1043
    // The stream for outputting warnings and errors.
1044
    SpvBuildLogger* logger;
1045
};  // end Builder class
1046
1047
} // end spv namespace
1048
1049
#endif // SpvBuilder_H