Coverage Report

Created: 2026-06-10 06:40

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/shaderc/third_party/glslang/SPIRV/SpvBuilder.cpp
Line
Count
Source
1
//
2
// Copyright (C) 2014-2015 LunarG, Inc.
3
// Copyright (C) 2015-2018 Google, Inc.
4
// Modifications Copyright (C) 2020 Advanced Micro Devices, Inc. All rights reserved.
5
//
6
// All rights reserved.
7
//
8
// Redistribution and use in source and binary forms, with or without
9
// modification, are permitted provided that the following conditions
10
// are met:
11
//
12
//    Redistributions of source code must retain the above copyright
13
//    notice, this list of conditions and the following disclaimer.
14
//
15
//    Redistributions in binary form must reproduce the above
16
//    copyright notice, this list of conditions and the following
17
//    disclaimer in the documentation and/or other materials provided
18
//    with the distribution.
19
//
20
//    Neither the name of 3Dlabs Inc. Ltd. nor the names of its
21
//    contributors may be used to endorse or promote products derived
22
//    from this software without specific prior written permission.
23
//
24
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
25
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
26
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
27
// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
28
// COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
29
// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
30
// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
31
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
32
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
33
// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
34
// ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
35
// POSSIBILITY OF SUCH DAMAGE.
36
37
//
38
// Helper for making SPIR-V IR.  Generally, this is documented in the header
39
// SpvBuilder.h.
40
//
41
42
#include <cassert>
43
#include <cstdlib>
44
45
#include <unordered_set>
46
#include <algorithm>
47
48
#include "SpvBuilder.h"
49
#include "spvUtil.h"
50
#include "hex_float.h"
51
52
#ifndef _WIN32
53
    #include <cstdio>
54
#endif
55
56
namespace spv {
57
58
Builder::Builder(unsigned int spvVersion, unsigned int magicNumber, SpvBuildLogger* buildLogger) :
59
442
    spvVersion(spvVersion),
60
442
    sourceLang(SourceLanguage::Unknown),
61
442
    sourceVersion(0),
62
442
    addressModel(AddressingModel::Logical),
63
442
    memoryModel(MemoryModel::GLSL450),
64
442
    builderNumber(magicNumber),
65
442
    buildPoint(nullptr),
66
442
    uniqueId(0),
67
442
    entryPointFunction(nullptr),
68
442
    generatingOpCodeForSpecConst(false),
69
442
    logger(buildLogger)
70
442
{
71
442
    clearAccessChain();
72
442
}
73
74
Builder::~Builder()
75
442
{
76
442
}
77
78
Id Builder::import(const char* name)
79
460
{
80
460
    Instruction* import = new Instruction(getUniqueId(), NoType, Op::OpExtInstImport);
81
460
    import->addStringOperand(name);
82
460
    module.mapInstruction(import);
83
84
460
    imports.push_back(std::unique_ptr<Instruction>(import));
85
460
    return import->getResultId();
86
460
}
87
88
// For creating new groupedTypes (will return old type if the requested one was already made).
89
Id Builder::makeVoidType()
90
1.82k
{
91
1.82k
    Instruction* type;
92
1.82k
    if (groupedTypes[enumCast(Op::OpTypeVoid)].size() == 0) {
93
442
        Id typeId = getUniqueId();
94
442
        type = new Instruction(typeId, NoType, Op::OpTypeVoid);
95
442
        groupedTypes[enumCast(Op::OpTypeVoid)].push_back(type);
96
442
        constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(type));
97
442
        module.mapInstruction(type);
98
        // Core OpTypeVoid used for debug void type
99
442
        if (emitNonSemanticShaderDebugInfo)
100
0
            debugTypeIdLookup[typeId] = typeId;
101
442
    } else
102
1.38k
        type = groupedTypes[enumCast(Op::OpTypeVoid)].back();
103
104
1.82k
    return type->getResultId();
105
1.82k
}
106
107
Id Builder::makeBoolType()
108
6.69k
{
109
6.69k
    Instruction* type;
110
6.69k
    if (groupedTypes[enumCast(Op::OpTypeBool)].size() == 0) {
111
174
        type = new Instruction(getUniqueId(), NoType, Op::OpTypeBool);
112
174
        groupedTypes[enumCast(Op::OpTypeBool)].push_back(type);
113
174
        constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(type));
114
174
        module.mapInstruction(type);
115
116
174
        if (emitNonSemanticShaderDebugInfo) {
117
0
            auto const debugResultId = makeBoolDebugType(32);
118
0
            debugTypeIdLookup[type->getResultId()] = debugResultId;
119
0
        }
120
121
174
    } else
122
6.51k
        type = groupedTypes[enumCast(Op::OpTypeBool)].back();
123
124
125
6.69k
    return type->getResultId();
126
6.69k
}
127
128
Id Builder::makeSamplerType(const char* debugName)
129
115
{
130
115
    Instruction* type;
131
115
    if (groupedTypes[enumCast(Op::OpTypeSampler)].size() == 0) {
132
88
        type = new Instruction(getUniqueId(), NoType, Op::OpTypeSampler);
133
88
        groupedTypes[enumCast(Op::OpTypeSampler)].push_back(type);
134
88
        constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(type));
135
88
        module.mapInstruction(type);
136
88
    } else
137
27
        type = groupedTypes[enumCast(Op::OpTypeSampler)].back();
138
139
115
    if (emitNonSemanticShaderDebugInfo)
140
0
    {
141
0
        auto const debugResultId = makeOpaqueDebugType(debugName);
142
0
        debugTypeIdLookup[type->getResultId()] = debugResultId;
143
0
    }
144
145
115
    return type->getResultId();
146
115
}
147
148
Id Builder::makePointer(StorageClass storageClass, Id pointee)
149
17.4k
{
150
    // try to find it
151
17.4k
    Instruction* type;
152
118k
    for (int t = 0; t < (int)groupedTypes[enumCast(Op::OpTypePointer)].size(); ++t) {
153
114k
        type = groupedTypes[enumCast(Op::OpTypePointer)][t];
154
114k
        if (type->getImmediateOperand(0) == (unsigned)storageClass &&
155
51.5k
            type->getIdOperand(1) == pointee)
156
13.1k
            return type->getResultId();
157
114k
    }
158
159
    // not found, make it
160
4.30k
    type = new Instruction(getUniqueId(), NoType, Op::OpTypePointer);
161
4.30k
    type->reserveOperands(2);
162
4.30k
    type->addImmediateOperand(storageClass);
163
4.30k
    type->addIdOperand(pointee);
164
4.30k
    groupedTypes[enumCast(Op::OpTypePointer)].push_back(type);
165
4.30k
    constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(type));
166
4.30k
    module.mapInstruction(type);
167
168
4.30k
    if (emitNonSemanticShaderDebugInfo) {
169
0
        const Id debugResultId = makePointerDebugType(storageClass, pointee);
170
0
        debugTypeIdLookup[type->getResultId()] = debugResultId;
171
0
    }
172
173
4.30k
    return type->getResultId();
174
17.4k
}
175
176
Id Builder::makeForwardPointer(StorageClass storageClass)
177
54
{
178
    // Caching/uniquifying doesn't work here, because we don't know the
179
    // pointee type and there can be multiple forward pointers of the same
180
    // storage type. Somebody higher up in the stack must keep track.
181
54
    Instruction* type = new Instruction(getUniqueId(), NoType, Op::OpTypeForwardPointer);
182
54
    type->addImmediateOperand(storageClass);
183
54
    constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(type));
184
54
    module.mapInstruction(type);
185
186
54
    if (emitNonSemanticShaderDebugInfo) {
187
0
        const Id debugResultId = makeForwardPointerDebugType(storageClass);
188
0
        debugTypeIdLookup[type->getResultId()] = debugResultId;
189
0
    }
190
54
    return type->getResultId();
191
54
}
192
193
Id Builder::makeUntypedPointer(StorageClass storageClass, bool setBufferPointer)
194
0
{
195
    // try to find it
196
0
    Instruction* type;
197
    // both typeBufferEXT and UntypedPointer only contains storage class info.
198
0
    spv::Op typeOp = setBufferPointer ? Op::OpTypeBufferEXT : Op::OpTypeUntypedPointerKHR;
199
0
    for (int t = 0; t < (int)groupedTypes[enumCast(typeOp)].size(); ++t) {
200
0
        type = groupedTypes[enumCast(typeOp)][t];
201
0
        if (type->getImmediateOperand(0) == (unsigned)storageClass)
202
0
            return type->getResultId();
203
0
    }
204
205
    // not found, make it
206
0
    type = new Instruction(getUniqueId(), NoType, typeOp);
207
0
    type->addImmediateOperand(storageClass);
208
0
    groupedTypes[enumCast(typeOp)].push_back(type);
209
0
    constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(type));
210
0
    module.mapInstruction(type);
211
0
    return type->getResultId();
212
0
}
213
214
Id Builder::makePointerFromForwardPointer(StorageClass storageClass, Id forwardPointerType, Id pointee)
215
387
{
216
    // try to find it
217
387
    Instruction* type;
218
1.31k
    for (int t = 0; t < (int)groupedTypes[enumCast(Op::OpTypePointer)].size(); ++t) {
219
1.26k
        type = groupedTypes[enumCast(Op::OpTypePointer)][t];
220
1.26k
        if (type->getImmediateOperand(0) == (unsigned)storageClass &&
221
414
            type->getIdOperand(1) == pointee)
222
333
            return type->getResultId();
223
1.26k
    }
224
225
54
    type = new Instruction(forwardPointerType, NoType, Op::OpTypePointer);
226
54
    type->reserveOperands(2);
227
54
    type->addImmediateOperand(storageClass);
228
54
    type->addIdOperand(pointee);
229
54
    groupedTypes[enumCast(Op::OpTypePointer)].push_back(type);
230
54
    constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(type));
231
54
    module.mapInstruction(type);
232
233
    // If we are emitting nonsemantic debuginfo, we need to patch the debug pointer type
234
    // that was emitted alongside the forward pointer, now that we have a pointee debug
235
    // type for it to point to.
236
54
    if (emitNonSemanticShaderDebugInfo) {
237
0
        Instruction *debugForwardPointer = module.getInstruction(getDebugType(forwardPointerType));
238
0
        assert(getDebugType(pointee));
239
0
        debugForwardPointer->setIdOperand(2, getDebugType(pointee));
240
0
    }
241
242
54
    return type->getResultId();
243
387
}
244
245
Id Builder::makeIntegerType(int width, bool hasSign)
246
51.0k
{
247
    // try to find it
248
51.0k
    Instruction* type;
249
115k
    for (int t = 0; t < (int)groupedTypes[enumCast(Op::OpTypeInt)].size(); ++t) {
250
114k
        type = groupedTypes[enumCast(Op::OpTypeInt)][t];
251
114k
        if (type->getImmediateOperand(0) == (unsigned)width &&
252
68.6k
            type->getImmediateOperand(1) == (hasSign ? 1u : 0u))
253
49.9k
            return type->getResultId();
254
114k
    }
255
256
    // not found, make it
257
1.14k
    type = new Instruction(getUniqueId(), NoType, Op::OpTypeInt);
258
1.14k
    type->reserveOperands(2);
259
1.14k
    type->addImmediateOperand(width);
260
1.14k
    type->addImmediateOperand(hasSign ? 1 : 0);
261
1.14k
    groupedTypes[enumCast(Op::OpTypeInt)].push_back(type);
262
1.14k
    constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(type));
263
1.14k
    module.mapInstruction(type);
264
265
    // deal with capabilities
266
1.14k
    switch (width) {
267
106
    case 8:
268
274
    case 16:
269
        // these are currently handled by storage-type declarations and post processing
270
274
        break;
271
177
    case 64:
272
177
        addCapability(Capability::Int64);
273
177
        break;
274
698
    default:
275
698
        break;
276
1.14k
    }
277
278
1.14k
    if (emitNonSemanticShaderDebugInfo)
279
0
    {
280
0
        auto const debugResultId = makeIntegerDebugType(width, hasSign);
281
0
        debugTypeIdLookup[type->getResultId()] = debugResultId;
282
0
    }
283
284
1.14k
    return type->getResultId();
285
1.14k
}
286
287
Id Builder::makeFloatType(int width)
288
23.8k
{
289
    // try to find it
290
23.8k
    Instruction* type;
291
24.7k
    for (int t = 0; t < (int)groupedTypes[enumCast(Op::OpTypeFloat)].size(); ++t) {
292
24.3k
        type = groupedTypes[enumCast(Op::OpTypeFloat)][t];
293
24.3k
        if (type->getNumOperands() != 1) {
294
0
            continue;
295
0
        }
296
24.3k
        if (type->getImmediateOperand(0) == (unsigned)width)
297
23.4k
            return type->getResultId();
298
24.3k
    }
299
300
    // not found, make it
301
400
    type = new Instruction(getUniqueId(), NoType, Op::OpTypeFloat);
302
400
    type->addImmediateOperand(width);
303
400
    groupedTypes[enumCast(Op::OpTypeFloat)].push_back(type);
304
400
    constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(type));
305
400
    module.mapInstruction(type);
306
307
    // deal with capabilities
308
400
    switch (width) {
309
70
    case 16:
310
        // currently handled by storage-type declarations and post processing
311
70
        break;
312
36
    case 64:
313
36
        addCapability(Capability::Float64);
314
36
        break;
315
294
    default:
316
294
        break;
317
400
    }
318
319
400
    if (emitNonSemanticShaderDebugInfo)
320
0
    {
321
0
        auto const debugResultId = makeFloatDebugType(width);
322
0
        debugTypeIdLookup[type->getResultId()] = debugResultId;
323
0
    }
324
325
400
    return type->getResultId();
326
400
}
327
328
Id Builder::makeBFloat16Type()
329
0
{
330
    // try to find it
331
0
    Instruction* type;
332
0
    for (int t = 0; t < (int)groupedTypes[enumCast(Op::OpTypeFloat)].size(); ++t) {
333
0
        type = groupedTypes[enumCast(Op::OpTypeFloat)][t];
334
0
        if (type->getNumOperands() != 2) {
335
0
            continue;
336
0
        }
337
0
        if (type->getImmediateOperand(0) == (unsigned)16 &&
338
0
            type->getImmediateOperand(1) == FPEncoding::BFloat16KHR)
339
0
            return type->getResultId();
340
0
    }
341
342
    // not found, make it
343
0
    type = new Instruction(getUniqueId(), NoType, Op::OpTypeFloat);
344
0
    type->addImmediateOperand(16);
345
0
    type->addImmediateOperand(FPEncoding::BFloat16KHR);
346
0
    groupedTypes[enumCast(Op::OpTypeFloat)].push_back(type);
347
0
    constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(type));
348
0
    module.mapInstruction(type);
349
350
0
    addExtension(spv::E_SPV_KHR_bfloat16);
351
0
    addCapability(Capability::BFloat16TypeKHR);
352
353
0
    if (emitNonSemanticShaderDebugInfo) {
354
0
        auto const debugResultId = makeFloatDebugType(16, makeUintConstant((unsigned)FPEncoding::BFloat16KHR));
355
0
        debugTypeIdLookup[type->getResultId()] = debugResultId;
356
0
    }
357
358
0
    return type->getResultId();
359
0
}
360
361
Id Builder::makeFloatE5M2Type()
362
0
{
363
    // try to find it
364
0
    Instruction* type;
365
0
    for (int t = 0; t < (int)groupedTypes[enumCast(Op::OpTypeFloat)].size(); ++t) {
366
0
        type = groupedTypes[enumCast(Op::OpTypeFloat)][t];
367
0
        if (type->getNumOperands() != 2) {
368
0
            continue;
369
0
        }
370
0
        if (type->getImmediateOperand(0) == (unsigned)8 &&
371
0
            type->getImmediateOperand(1) == FPEncoding::Float8E5M2EXT)
372
0
            return type->getResultId();
373
0
    }
374
375
    // not found, make it
376
0
    type = new Instruction(getUniqueId(), NoType, Op::OpTypeFloat);
377
0
    type->addImmediateOperand(8);
378
0
    type->addImmediateOperand(FPEncoding::Float8E5M2EXT);
379
0
    groupedTypes[enumCast(Op::OpTypeFloat)].push_back(type);
380
0
    constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(type));
381
0
    module.mapInstruction(type);
382
383
0
    addExtension(spv::E_SPV_EXT_float8);
384
0
    addCapability(Capability::Float8EXT);
385
386
0
    if (emitNonSemanticShaderDebugInfo) {
387
0
        auto const debugResultId = makeFloatDebugType(8, makeUintConstant((unsigned)FPEncoding::Float8E5M2EXT));
388
0
        debugTypeIdLookup[type->getResultId()] = debugResultId;
389
0
    }
390
391
0
    return type->getResultId();
392
0
}
393
394
Id Builder::makeFloatE4M3Type()
395
0
{
396
    // try to find it
397
0
    Instruction* type;
398
0
    for (int t = 0; t < (int)groupedTypes[enumCast(Op::OpTypeFloat)].size(); ++t) {
399
0
        type = groupedTypes[enumCast(Op::OpTypeFloat)][t];
400
0
        if (type->getNumOperands() != 2) {
401
0
            continue;
402
0
        }
403
0
        if (type->getImmediateOperand(0) == (unsigned)8 &&
404
0
            type->getImmediateOperand(1) == FPEncoding::Float8E4M3EXT)
405
0
            return type->getResultId();
406
0
    }
407
408
    // not found, make it
409
0
    type = new Instruction(getUniqueId(), NoType, Op::OpTypeFloat);
410
0
    type->addImmediateOperand(8);
411
0
    type->addImmediateOperand(FPEncoding::Float8E4M3EXT);
412
0
    groupedTypes[enumCast(Op::OpTypeFloat)].push_back(type);
413
0
    constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(type));
414
0
    module.mapInstruction(type);
415
416
0
    addExtension(spv::E_SPV_EXT_float8);
417
0
    addCapability(Capability::Float8EXT);
418
419
0
    if (emitNonSemanticShaderDebugInfo) {
420
0
        auto const debugResultId = makeFloatDebugType(8, makeUintConstant((unsigned)FPEncoding::Float8E4M3EXT));
421
0
        debugTypeIdLookup[type->getResultId()] = debugResultId;
422
0
    }
423
424
0
    return type->getResultId();
425
0
}
426
427
// Make a struct without checking for duplication.
428
// See makeStructResultType() for non-decorated structs
429
// needed as the result of some instructions, which does
430
// check for duplicates.
431
// For compiler-generated structs, debug info is ignored.
432
Id Builder::makeStructType(const std::vector<Id>& members, const std::vector<spv::StructMemberDebugInfo>& memberDebugInfo,
433
                           const char* name, bool const compilerGenerated)
434
810
{
435
    // Don't look for previous one, because in the general case,
436
    // structs can be duplicated except for decorations.
437
438
    // not found, make it
439
810
    Instruction* type = new Instruction(getUniqueId(), NoType, Op::OpTypeStruct);
440
3.53k
    for (int op = 0; op < (int)members.size(); ++op)
441
2.72k
        type->addIdOperand(members[op]);
442
810
    groupedTypes[enumCast(Op::OpTypeStruct)].push_back(type);
443
810
    constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(type));
444
810
    module.mapInstruction(type);
445
810
    addName(type->getResultId(), name);
446
447
810
    if (emitNonSemanticShaderDebugInfo && !compilerGenerated) {
448
0
        assert(members.size() == memberDebugInfo.size());
449
0
        auto const debugResultId =
450
0
            makeCompositeDebugType(members, memberDebugInfo, name, NonSemanticShaderDebugInfoStructure);
451
0
        debugTypeIdLookup[type->getResultId()] = debugResultId;
452
0
    }
453
454
810
    return type->getResultId();
455
810
}
456
457
// Make a struct for the simple results of several instructions,
458
// checking for duplication.
459
Id Builder::makeStructResultType(Id type0, Id type1)
460
553
{
461
    // try to find it
462
553
    Instruction* type;
463
815
    for (int t = 0; t < (int)groupedTypes[enumCast(Op::OpTypeStruct)].size(); ++t) {
464
756
        type = groupedTypes[enumCast(Op::OpTypeStruct)][t];
465
756
        if (type->getNumOperands() != 2)
466
87
            continue;
467
669
        if (type->getIdOperand(0) != type0 ||
468
651
            type->getIdOperand(1) != type1)
469
175
            continue;
470
494
        return type->getResultId();
471
669
    }
472
473
    // not found, make it
474
59
    std::vector<spv::Id> members;
475
59
    members.push_back(type0);
476
59
    members.push_back(type1);
477
478
59
    return makeStructType(members, {}, "ResType");
479
553
}
480
481
Id Builder::makeVectorType(Id component, int size)
482
25.3k
{
483
    // try to find it
484
25.3k
    Instruction* type;
485
84.8k
    for (int t = 0; t < (int)groupedTypes[enumCast(Op::OpTypeVector)].size(); ++t) {
486
82.9k
        type = groupedTypes[enumCast(Op::OpTypeVector)][t];
487
82.9k
        if (type->getIdOperand(0) == component &&
488
39.1k
            type->getImmediateOperand(1) == (unsigned)size)
489
23.4k
            return type->getResultId();
490
82.9k
    }
491
492
    // not found, make it
493
1.90k
    type = new Instruction(getUniqueId(), NoType, Op::OpTypeVector);
494
1.90k
    type->reserveOperands(2);
495
1.90k
    type->addIdOperand(component);
496
1.90k
    type->addImmediateOperand(size);
497
1.90k
    groupedTypes[enumCast(Op::OpTypeVector)].push_back(type);
498
1.90k
    constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(type));
499
1.90k
    module.mapInstruction(type);
500
501
1.90k
    if (emitNonSemanticShaderDebugInfo)
502
0
    {
503
0
        auto const debugResultId = makeVectorDebugType(component, size);
504
0
        debugTypeIdLookup[type->getResultId()] = debugResultId;
505
0
    }
506
507
1.90k
    return type->getResultId();
508
25.3k
}
509
510
Id Builder::makeMatrixType(Id component, int cols, int rows)
511
957
{
512
957
    assert(cols <= maxMatrixSize && rows <= maxMatrixSize);
513
514
957
    Id column = makeVectorType(component, rows);
515
516
    // try to find it
517
957
    Instruction* type;
518
1.39k
    for (int t = 0; t < (int)groupedTypes[enumCast(Op::OpTypeMatrix)].size(); ++t) {
519
1.20k
        type = groupedTypes[enumCast(Op::OpTypeMatrix)][t];
520
1.20k
        if (type->getIdOperand(0) == column &&
521
767
            type->getImmediateOperand(1) == (unsigned)cols)
522
767
            return type->getResultId();
523
1.20k
    }
524
525
    // not found, make it
526
190
    type = new Instruction(getUniqueId(), NoType, Op::OpTypeMatrix);
527
190
    type->reserveOperands(2);
528
190
    type->addIdOperand(column);
529
190
    type->addImmediateOperand(cols);
530
190
    groupedTypes[enumCast(Op::OpTypeMatrix)].push_back(type);
531
190
    constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(type));
532
190
    module.mapInstruction(type);
533
534
190
    if (emitNonSemanticShaderDebugInfo)
535
0
    {
536
0
        auto const debugResultId = makeMatrixDebugType(column, cols);
537
0
        debugTypeIdLookup[type->getResultId()] = debugResultId;
538
0
    }
539
540
190
    return type->getResultId();
541
957
}
542
543
Id Builder::makeCooperativeMatrixTypeKHR(Id component, Id scope, Id rows, Id cols, Id use)
544
0
{
545
    // try to find it
546
0
    Instruction* type;
547
0
    for (int t = 0; t < (int)groupedTypes[enumCast(Op::OpTypeCooperativeMatrixKHR)].size(); ++t) {
548
0
        type = groupedTypes[enumCast(Op::OpTypeCooperativeMatrixKHR)][t];
549
0
        if (type->getIdOperand(0) == component &&
550
0
            type->getIdOperand(1) == scope &&
551
0
            type->getIdOperand(2) == rows &&
552
0
            type->getIdOperand(3) == cols &&
553
0
            type->getIdOperand(4) == use)
554
0
            return type->getResultId();
555
0
    }
556
557
    // not found, make it
558
0
    type = new Instruction(getUniqueId(), NoType, Op::OpTypeCooperativeMatrixKHR);
559
0
    type->reserveOperands(5);
560
0
    type->addIdOperand(component);
561
0
    type->addIdOperand(scope);
562
0
    type->addIdOperand(rows);
563
0
    type->addIdOperand(cols);
564
0
    type->addIdOperand(use);
565
0
    groupedTypes[enumCast(Op::OpTypeCooperativeMatrixKHR)].push_back(type);
566
0
    constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(type));
567
0
    module.mapInstruction(type);
568
569
0
    if (emitNonSemanticShaderDebugInfo) {
570
0
        auto const debugResultId = makeCooperativeMatrixDebugTypeKHR(component, scope, rows, cols, use);
571
0
        debugTypeIdLookup[type->getResultId()] = debugResultId;
572
0
    }
573
574
0
    return type->getResultId();
575
0
}
576
577
Id Builder::makeCooperativeMatrixTypeNV(Id component, Id scope, Id rows, Id cols)
578
0
{
579
    // try to find it
580
0
    Instruction* type;
581
0
    for (int t = 0; t < (int)groupedTypes[enumCast(Op::OpTypeCooperativeMatrixNV)].size(); ++t) {
582
0
        type = groupedTypes[enumCast(Op::OpTypeCooperativeMatrixNV)][t];
583
0
        if (type->getIdOperand(0) == component && type->getIdOperand(1) == scope && type->getIdOperand(2) == rows &&
584
0
            type->getIdOperand(3) == cols)
585
0
            return type->getResultId();
586
0
    }
587
588
    // not found, make it
589
0
    type = new Instruction(getUniqueId(), NoType, Op::OpTypeCooperativeMatrixNV);
590
0
    type->reserveOperands(4);
591
0
    type->addIdOperand(component);
592
0
    type->addIdOperand(scope);
593
0
    type->addIdOperand(rows);
594
0
    type->addIdOperand(cols);
595
0
    groupedTypes[enumCast(Op::OpTypeCooperativeMatrixNV)].push_back(type);
596
0
    constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(type));
597
0
    module.mapInstruction(type);
598
599
0
    return type->getResultId();
600
0
}
601
602
Id Builder::makeCooperativeMatrixTypeWithSameShape(Id component, Id otherType)
603
0
{
604
0
    Instruction* instr = module.getInstruction(otherType);
605
0
    if (instr->getOpCode() == Op::OpTypeCooperativeMatrixNV) {
606
0
        return makeCooperativeMatrixTypeNV(component, instr->getIdOperand(1), instr->getIdOperand(2), instr->getIdOperand(3));
607
0
    } else {
608
0
        assert(instr->getOpCode() == Op::OpTypeCooperativeMatrixKHR);
609
0
        return makeCooperativeMatrixTypeKHR(component, instr->getIdOperand(1), instr->getIdOperand(2), instr->getIdOperand(3), instr->getIdOperand(4));
610
0
    }
611
0
}
612
613
Id Builder::makeCooperativeVectorTypeNV(Id componentType, Id components)
614
0
{
615
    // try to find it
616
0
    Instruction* type;
617
0
    for (int t = 0; t < (int)groupedTypes[enumCast(Op::OpTypeCooperativeVectorNV)].size(); ++t) {
618
0
        type = groupedTypes[enumCast(Op::OpTypeCooperativeVectorNV)][t];
619
0
        if (type->getIdOperand(0) == componentType &&
620
0
            type->getIdOperand(1) == components)
621
0
            return type->getResultId();
622
0
    }
623
624
    // not found, make it
625
0
    type = new Instruction(getUniqueId(), NoType, Op::OpTypeCooperativeVectorNV);
626
0
    type->addIdOperand(componentType);
627
0
    type->addIdOperand(components);
628
0
    groupedTypes[enumCast(Op::OpTypeCooperativeVectorNV)].push_back(type);
629
0
    constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(type));
630
0
    module.mapInstruction(type);
631
632
0
    if (emitNonSemanticShaderDebugInfo) {
633
0
        auto const debugResultId = makeVectorIdDebugType(componentType, components);
634
0
        debugTypeIdLookup[type->getResultId()] = debugResultId;
635
0
    }
636
637
0
    return type->getResultId();
638
0
}
639
640
Id Builder::makeTensorTypeARM(Id elementType, Id rank)
641
0
{
642
    // See if an OpTypeTensorARM with same element type and rank already exists.
643
0
    for (int t = 0; t < (int)groupedTypes[enumCast(Op::OpTypeTensorARM)].size(); ++t) {
644
0
        const Instruction *type = groupedTypes[enumCast(Op::OpTypeTensorARM)][t];
645
0
        if (type->getIdOperand(0) == elementType && type->getIdOperand(1) == rank)
646
0
            return type->getResultId();
647
0
    }
648
649
    // Not found, make it.
650
0
    std::unique_ptr<Instruction> type(new Instruction(getUniqueId(), NoType, Op::OpTypeTensorARM));
651
0
    type->addIdOperand(elementType);
652
0
    type->addIdOperand(rank);
653
0
    groupedTypes[enumCast(Op::OpTypeTensorARM)].push_back(type.get());
654
0
    module.mapInstruction(type.get());
655
0
    Id resultID = type->getResultId();
656
0
    constantsTypesGlobals.push_back(std::move(type));
657
0
    return resultID;
658
0
}
659
660
Id Builder::makeGenericType(spv::Op opcode, std::vector<spv::IdImmediate>& operands)
661
0
{
662
    // try to find it
663
0
    Instruction* type;
664
0
    for (int t = 0; t < (int)groupedTypes[enumCast(opcode)].size(); ++t) {
665
0
        type = groupedTypes[enumCast(opcode)][t];
666
0
        if (static_cast<size_t>(type->getNumOperands()) != operands.size())
667
0
            continue; // Number mismatch, find next
668
669
0
        bool match = true;
670
0
        for (int op = 0; match && op < (int)operands.size(); ++op) {
671
0
            match = (operands[op].isId ? type->getIdOperand(op) : type->getImmediateOperand(op)) == operands[op].word;
672
0
        }
673
0
        if (match)
674
0
            return type->getResultId();
675
0
    }
676
677
    // not found, make it
678
0
    type = new Instruction(getUniqueId(), NoType, opcode);
679
0
    type->reserveOperands(operands.size());
680
0
    for (size_t op = 0; op < operands.size(); ++op) {
681
0
        if (operands[op].isId)
682
0
            type->addIdOperand(operands[op].word);
683
0
        else
684
0
            type->addImmediateOperand(operands[op].word);
685
0
    }
686
0
    groupedTypes[enumCast(opcode)].push_back(type);
687
0
    constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(type));
688
0
    module.mapInstruction(type);
689
690
0
    return type->getResultId();
691
0
}
692
693
// TODO: performance: track arrays per stride
694
// If a stride is supplied (non-zero) make an array.
695
// If no stride (0), reuse previous array types.
696
// 'size' is an Id of a constant or specialization constant of the array size
697
Id Builder::makeArrayType(Id element, Id sizeId, int stride)
698
382
{
699
382
    Instruction* type;
700
382
    if (stride == 0) {
701
        // try to find existing type
702
392
        for (int t = 0; t < (int)groupedTypes[enumCast(Op::OpTypeArray)].size(); ++t) {
703
261
            type = groupedTypes[enumCast(Op::OpTypeArray)][t];
704
261
            if (type->getIdOperand(0) == element &&
705
156
                type->getIdOperand(1) == sizeId &&
706
121
                explicitlyLaidOut.find(type->getResultId()) == explicitlyLaidOut.end())
707
121
                return type->getResultId();
708
261
        }
709
252
    }
710
711
    // not found, make it
712
261
    type = new Instruction(getUniqueId(), NoType, Op::OpTypeArray);
713
261
    type->reserveOperands(2);
714
261
    type->addIdOperand(element);
715
261
    type->addIdOperand(sizeId);
716
261
    groupedTypes[enumCast(Op::OpTypeArray)].push_back(type);
717
261
    constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(type));
718
261
    module.mapInstruction(type);
719
720
261
    if (stride != 0) {
721
130
        explicitlyLaidOut.insert(type->getResultId());
722
130
    }
723
724
261
    if (emitNonSemanticShaderDebugInfo)
725
0
    {
726
0
        auto const debugResultId = makeArrayDebugType(element, sizeId);
727
0
        debugTypeIdLookup[type->getResultId()] = debugResultId;
728
0
    }
729
730
261
    return type->getResultId();
731
382
}
732
733
Id Builder::makeRuntimeArray(Id element)
734
51
{
735
51
    Instruction* type = new Instruction(getUniqueId(), NoType, Op::OpTypeRuntimeArray);
736
51
    type->addIdOperand(element);
737
51
    constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(type));
738
51
    module.mapInstruction(type);
739
740
51
    if (emitNonSemanticShaderDebugInfo)
741
0
    {
742
0
        auto const debugResultId = makeArrayDebugType(element, makeUintConstant(0));
743
0
        debugTypeIdLookup[type->getResultId()] = debugResultId;
744
0
    }
745
746
51
    return type->getResultId();
747
51
}
748
749
Id Builder::makeFunctionType(Id returnType, const std::vector<Id>& paramTypes)
750
914
{
751
    // try to find it
752
914
    Instruction* type;
753
1.51k
    for (int t = 0; t < (int)groupedTypes[enumCast(Op::OpTypeFunction)].size(); ++t) {
754
824
        type = groupedTypes[enumCast(Op::OpTypeFunction)][t];
755
824
        if (type->getIdOperand(0) != returnType || (int)paramTypes.size() != type->getNumOperands() - 1)
756
540
            continue;
757
284
        bool mismatch = false;
758
284
        for (int p = 0; p < (int)paramTypes.size(); ++p) {
759
63
            if (paramTypes[p] != type->getIdOperand(p + 1)) {
760
63
                mismatch = true;
761
63
                break;
762
63
            }
763
63
        }
764
284
        if (! mismatch)
765
221
        {
766
            // If compiling HLSL, glslang will create a wrapper function around the entrypoint. Accordingly, a void(void)
767
            // function type is created for the wrapper function. However, nonsemantic shader debug information is disabled
768
            // while creating the HLSL wrapper. Consequently, if we encounter another void(void) function, we need to create
769
            // the associated debug function type if it hasn't been created yet.
770
221
            if(emitNonSemanticShaderDebugInfo && getDebugType(type->getResultId()) == NoType) {
771
0
                assert(sourceLang == spv::SourceLanguage::HLSL);
772
0
                assert(getTypeClass(returnType) == Op::OpTypeVoid && paramTypes.size() == 0);
773
774
0
                Id id = makeDebugFunctionType(returnType, {});
775
0
                debugTypeIdLookup[type->getResultId()] = id;
776
0
            }
777
221
            return type->getResultId();
778
221
        }
779
284
    }
780
781
    // not found, make it
782
693
    Id typeId = getUniqueId();
783
693
    type = new Instruction(typeId, NoType, Op::OpTypeFunction);
784
693
    type->reserveOperands(paramTypes.size() + 1);
785
693
    type->addIdOperand(returnType);
786
1.13k
    for (int p = 0; p < (int)paramTypes.size(); ++p)
787
443
        type->addIdOperand(paramTypes[p]);
788
693
    groupedTypes[enumCast(Op::OpTypeFunction)].push_back(type);
789
693
    constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(type));
790
693
    module.mapInstruction(type);
791
792
    // make debug type and map it
793
693
    if (emitNonSemanticShaderDebugInfo) {
794
0
        Id debugTypeId = makeDebugFunctionType(returnType, paramTypes);
795
0
        debugTypeIdLookup[typeId] = debugTypeId;
796
0
    }
797
798
693
    return type->getResultId();
799
914
}
800
801
Id Builder::makeDebugFunctionType(Id returnType, const std::vector<Id>& paramTypes)
802
0
{
803
0
    assert(getDebugType(returnType) != NoType);
804
805
0
    Id typeId = getUniqueId();
806
0
    auto type = new Instruction(typeId, makeVoidType(), Op::OpExtInst);
807
0
    type->reserveOperands(paramTypes.size() + 4);
808
0
    type->addIdOperand(nonSemanticShaderDebugInfo);
809
0
    type->addImmediateOperand(NonSemanticShaderDebugInfoDebugTypeFunction);
810
0
    type->addIdOperand(makeUintConstant(NonSemanticShaderDebugInfoFlagIsPublic));
811
0
    type->addIdOperand(getDebugType(returnType));
812
0
    for (auto const paramType : paramTypes) {
813
0
        if (isPointerType(paramType) || isArrayType(paramType)) {
814
0
            type->addIdOperand(getDebugType(getContainedTypeId(paramType)));
815
0
        }
816
0
        else {
817
0
            type->addIdOperand(getDebugType(paramType));
818
0
        }
819
0
    }
820
0
    constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(type));
821
0
    module.mapInstruction(type);
822
0
    return typeId;
823
0
}
824
825
Id Builder::makeImageType(Id sampledType, Dim dim, bool depth, bool arrayed, bool ms, unsigned sampled,
826
    ImageFormat format, const char* debugName)
827
1.49k
{
828
1.49k
    assert(sampled == 1 || sampled == 2);
829
830
    // try to find it
831
1.49k
    Instruction* type;
832
7.30k
    for (int t = 0; t < (int)groupedTypes[enumCast(Op::OpTypeImage)].size(); ++t) {
833
6.40k
        type = groupedTypes[enumCast(Op::OpTypeImage)][t];
834
6.40k
        if (type->getIdOperand(0) == sampledType &&
835
5.32k
            type->getImmediateOperand(1) == (unsigned int)dim &&
836
1.61k
            type->getImmediateOperand(2) == (  depth ? 1u : 0u) &&
837
1.44k
            type->getImmediateOperand(3) == (arrayed ? 1u : 0u) &&
838
840
            type->getImmediateOperand(4) == (     ms ? 1u : 0u) &&
839
781
            type->getImmediateOperand(5) == sampled &&
840
748
            type->getImmediateOperand(6) == (unsigned int)format)
841
594
            return type->getResultId();
842
6.40k
    }
843
844
    // not found, make it
845
899
    type = new Instruction(getUniqueId(), NoType, Op::OpTypeImage);
846
899
    type->reserveOperands(7);
847
899
    type->addIdOperand(sampledType);
848
899
    type->addImmediateOperand(   dim);
849
899
    type->addImmediateOperand(  depth ? 1 : 0);
850
899
    type->addImmediateOperand(arrayed ? 1 : 0);
851
899
    type->addImmediateOperand(     ms ? 1 : 0);
852
899
    type->addImmediateOperand(sampled);
853
899
    type->addImmediateOperand((unsigned int)format);
854
855
899
    groupedTypes[enumCast(Op::OpTypeImage)].push_back(type);
856
899
    constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(type));
857
899
    module.mapInstruction(type);
858
859
    // deal with capabilities
860
899
    switch (dim) {
861
19
    case Dim::Buffer:
862
19
        if (sampled == 1)
863
3
            addCapability(Capability::SampledBuffer);
864
16
        else
865
16
            addCapability(Capability::ImageBuffer);
866
19
        break;
867
172
    case Dim::Dim1D:
868
172
        if (sampled == 1)
869
16
            addCapability(Capability::Sampled1D);
870
156
        else
871
156
            addCapability(Capability::Image1D);
872
172
        break;
873
168
    case Dim::Cube:
874
168
        if (arrayed) {
875
84
            if (sampled == 1)
876
6
                addCapability(Capability::SampledCubeArray);
877
78
            else
878
78
                addCapability(Capability::ImageCubeArray);
879
84
        }
880
168
        break;
881
22
    case Dim::Rect:
882
22
        if (sampled == 1)
883
6
            addCapability(Capability::SampledRect);
884
16
        else
885
16
            addCapability(Capability::ImageRect);
886
22
        break;
887
6
    case Dim::SubpassData:
888
6
        addCapability(Capability::InputAttachment);
889
6
        break;
890
512
    default:
891
512
        break;
892
899
    }
893
894
899
    if (ms) {
895
41
        if (sampled == 2) {
896
            // Images used with subpass data are not storage
897
            // images, so don't require the capability for them.
898
35
            if (dim != Dim::SubpassData)
899
32
                addCapability(Capability::StorageImageMultisample);
900
35
            if (arrayed)
901
16
                addCapability(Capability::ImageMSArray);
902
35
        }
903
41
    }
904
905
899
    if (emitNonSemanticShaderDebugInfo)
906
0
    {
907
0
        auto const debugResultId = makeOpaqueDebugType(debugName);
908
0
        debugTypeIdLookup[type->getResultId()] = debugResultId;
909
0
    }
910
911
899
    return type->getResultId();
912
899
}
913
914
Id Builder::makeSampledImageType(Id imageType, const char* debugName)
915
587
{
916
    // try to find it
917
587
    Instruction* type;
918
1.58k
    for (int t = 0; t < (int)groupedTypes[enumCast(Op::OpTypeSampledImage)].size(); ++t) {
919
1.36k
        type = groupedTypes[enumCast(Op::OpTypeSampledImage)][t];
920
1.36k
        if (type->getIdOperand(0) == imageType)
921
367
            return type->getResultId();
922
1.36k
    }
923
924
    // not found, make it
925
220
    type = new Instruction(getUniqueId(), NoType, Op::OpTypeSampledImage);
926
220
    type->addIdOperand(imageType);
927
928
220
    groupedTypes[enumCast(Op::OpTypeSampledImage)].push_back(type);
929
220
    constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(type));
930
220
    module.mapInstruction(type);
931
932
220
    if (emitNonSemanticShaderDebugInfo)
933
0
    {
934
0
        auto const debugResultId = makeOpaqueDebugType(debugName);
935
0
        debugTypeIdLookup[type->getResultId()] = debugResultId;
936
0
    }
937
938
220
    return type->getResultId();
939
587
}
940
941
Id Builder::makeDebugInfoNone()
942
0
{
943
0
    if (debugInfoNone != 0)
944
0
        return debugInfoNone;
945
946
0
    Instruction* inst = new Instruction(getUniqueId(), makeVoidType(), Op::OpExtInst);
947
0
    inst->reserveOperands(2);
948
0
    inst->addIdOperand(nonSemanticShaderDebugInfo);
949
0
    inst->addImmediateOperand(NonSemanticShaderDebugInfoDebugInfoNone);
950
951
0
    constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(inst));
952
0
    module.mapInstruction(inst);
953
954
0
    debugInfoNone = inst->getResultId();
955
956
0
    return debugInfoNone;
957
0
}
958
959
Id Builder::makeBoolDebugType(int const size)
960
0
{
961
    // try to find it
962
0
    Instruction* type;
963
0
    for (int t = 0; t < (int)groupedDebugTypes[NonSemanticShaderDebugInfoDebugTypeBasic].size(); ++t) {
964
0
        type = groupedDebugTypes[NonSemanticShaderDebugInfoDebugTypeBasic][t];
965
0
        if (type->getIdOperand(0) == getStringId("bool") &&
966
0
            type->getIdOperand(1) == static_cast<unsigned int>(size) &&
967
0
            type->getIdOperand(2) == NonSemanticShaderDebugInfoBoolean)
968
0
            return type->getResultId();
969
0
    }
970
971
0
    type = new Instruction(getUniqueId(), makeVoidType(), Op::OpExtInst);
972
0
    type->reserveOperands(6);
973
0
    type->addIdOperand(nonSemanticShaderDebugInfo);
974
0
    type->addImmediateOperand(NonSemanticShaderDebugInfoDebugTypeBasic);
975
976
0
    type->addIdOperand(getStringId("bool")); // name id
977
0
    type->addIdOperand(makeUintConstant(size)); // size id
978
0
    type->addIdOperand(makeUintConstant(NonSemanticShaderDebugInfoBoolean)); // encoding id
979
0
    type->addIdOperand(makeUintConstant(NonSemanticShaderDebugInfoNone)); // flags id
980
981
0
    groupedDebugTypes[NonSemanticShaderDebugInfoDebugTypeBasic].push_back(type);
982
0
    constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(type));
983
0
    module.mapInstruction(type);
984
985
0
    return type->getResultId();
986
0
}
987
988
Id Builder::makeIntegerDebugType(int const width, bool const hasSign)
989
0
{
990
0
    const char* typeName = nullptr;
991
0
    switch (width) {
992
0
        case 8:  typeName = hasSign ? "int8_t" : "uint8_t"; break;
993
0
        case 16: typeName = hasSign ? "int16_t" : "uint16_t"; break;
994
0
        case 64: typeName = hasSign ? "int64_t" : "uint64_t"; break;
995
0
        default: typeName = hasSign ? "int" : "uint";
996
0
    }
997
0
    auto nameId = getStringId(typeName);
998
    // try to find it
999
0
    Instruction* type;
1000
0
    for (int t = 0; t < (int)groupedDebugTypes[NonSemanticShaderDebugInfoDebugTypeBasic].size(); ++t) {
1001
0
        type = groupedDebugTypes[NonSemanticShaderDebugInfoDebugTypeBasic][t];
1002
0
        if (type->getIdOperand(0) == nameId &&
1003
0
            type->getIdOperand(1) == static_cast<unsigned int>(width) &&
1004
0
            type->getIdOperand(2) == (hasSign ? NonSemanticShaderDebugInfoSigned : NonSemanticShaderDebugInfoUnsigned))
1005
0
            return type->getResultId();
1006
0
    }
1007
1008
    // not found, make it
1009
0
    type = new Instruction(getUniqueId(), makeVoidType(), Op::OpExtInst);
1010
0
    type->reserveOperands(6);
1011
0
    type->addIdOperand(nonSemanticShaderDebugInfo);
1012
0
    type->addImmediateOperand(NonSemanticShaderDebugInfoDebugTypeBasic);
1013
0
    type->addIdOperand(nameId); // name id
1014
0
    type->addIdOperand(makeUintConstant(width)); // size id
1015
0
    if(hasSign == true) {
1016
0
        type->addIdOperand(makeUintConstant(NonSemanticShaderDebugInfoSigned)); // encoding id
1017
0
    } else {
1018
0
        type->addIdOperand(makeUintConstant(NonSemanticShaderDebugInfoUnsigned)); // encoding id
1019
0
    }
1020
0
    type->addIdOperand(makeUintConstant(NonSemanticShaderDebugInfoNone)); // flags id
1021
1022
0
    groupedDebugTypes[NonSemanticShaderDebugInfoDebugTypeBasic].push_back(type);
1023
0
    constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(type));
1024
0
    module.mapInstruction(type);
1025
1026
0
    return type->getResultId();
1027
0
}
1028
1029
Id Builder::makeFloatDebugType(int const width, Id const fpEncoding)
1030
0
{
1031
0
    if (fpEncoding != NoType)
1032
0
        requireNonSemanticShaderDebugInfoVersion(101);
1033
    // Determine the debug type name. FP-encoded variants have distinct names.
1034
    // Id comparison works here because makeUintConstant deduplicates: two calls
1035
    // with the same value return the same Id.
1036
0
    const char* typeName = nullptr;
1037
0
    if (fpEncoding != NoType) {
1038
0
        if (fpEncoding == makeUintConstant((unsigned)FPEncoding::BFloat16KHR))
1039
0
            typeName = "bfloat16_t";
1040
0
        else if (fpEncoding == makeUintConstant((unsigned)FPEncoding::Float8E4M3EXT))
1041
0
            typeName = "floate4m3_t";
1042
0
        else if (fpEncoding == makeUintConstant((unsigned)FPEncoding::Float8E5M2EXT))
1043
0
            typeName = "floate5m2_t";
1044
0
        else
1045
0
            typeName = "float";
1046
0
    } else {
1047
0
        switch (width) {
1048
0
            case 16: typeName = "float16_t"; break;
1049
0
            case 64: typeName = "double"; break;
1050
0
            default: typeName = "float"; break;
1051
0
        }
1052
0
    }
1053
0
    auto nameId = getStringId(typeName);
1054
    // try to find it
1055
0
    Instruction* type;
1056
0
    for (int t = 0; t < (int)groupedDebugTypes[NonSemanticShaderDebugInfoDebugTypeBasic].size(); ++t) {
1057
0
        type = groupedDebugTypes[NonSemanticShaderDebugInfoDebugTypeBasic][t];
1058
0
        if (type->getIdOperand(0) == nameId &&
1059
0
            type->getIdOperand(1) == static_cast<unsigned int>(width) &&
1060
0
            type->getIdOperand(2) == NonSemanticShaderDebugInfoFloat) {
1061
0
            if (fpEncoding == NoType) {
1062
0
                if (type->getNumOperands() == 6)
1063
0
                    return type->getResultId();
1064
0
            } else {
1065
0
                if (type->getNumOperands() == 7 && type->getIdOperand(6) == fpEncoding)
1066
0
                    return type->getResultId();
1067
0
            }
1068
0
        }
1069
0
    }
1070
1071
    // not found, make it
1072
0
    type = new Instruction(getUniqueId(), makeVoidType(), Op::OpExtInst);
1073
0
    type->reserveOperands(fpEncoding == NoType ? 6 : 7);
1074
0
    type->addIdOperand(nonSemanticShaderDebugInfo);
1075
0
    type->addImmediateOperand(NonSemanticShaderDebugInfoDebugTypeBasic);
1076
0
    type->addIdOperand(nameId); // name id
1077
0
    type->addIdOperand(makeUintConstant(width)); // size id
1078
0
    type->addIdOperand(makeUintConstant(NonSemanticShaderDebugInfoFloat)); // encoding id
1079
0
    type->addIdOperand(makeUintConstant(NonSemanticShaderDebugInfoNone)); // flags id
1080
0
    if (fpEncoding != NoType)
1081
0
        type->addIdOperand(fpEncoding); // optional FPEncoding id (NSDI.101)
1082
1083
0
    groupedDebugTypes[NonSemanticShaderDebugInfoDebugTypeBasic].push_back(type);
1084
0
    constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(type));
1085
0
    module.mapInstruction(type);
1086
1087
0
    return type->getResultId();
1088
0
}
1089
1090
Id Builder::makeSequentialDebugType(Id const baseType, Id const componentCount, NonSemanticShaderDebugInfoInstructions const sequenceType)
1091
0
{
1092
0
    assert(sequenceType == NonSemanticShaderDebugInfoDebugTypeArray ||
1093
0
        sequenceType == NonSemanticShaderDebugInfoDebugTypeVector);
1094
1095
    // try to find it
1096
0
    Instruction* type;
1097
0
    for (int t = 0; t < (int)groupedDebugTypes[sequenceType].size(); ++t) {
1098
0
        type = groupedDebugTypes[sequenceType][t];
1099
0
        if (type->getIdOperand(0) == baseType &&
1100
0
            type->getIdOperand(1) == makeUintConstant(componentCount))
1101
0
            return type->getResultId();
1102
0
    }
1103
1104
    // not found, make it
1105
0
    type = new Instruction(getUniqueId(), makeVoidType(), Op::OpExtInst);
1106
0
    type->reserveOperands(4);
1107
0
    type->addIdOperand(nonSemanticShaderDebugInfo);
1108
0
    type->addImmediateOperand(sequenceType);
1109
0
    type->addIdOperand(getDebugType(baseType)); // base type
1110
0
    type->addIdOperand(componentCount); // component count
1111
1112
0
    groupedDebugTypes[sequenceType].push_back(type);
1113
0
    constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(type));
1114
0
    module.mapInstruction(type);
1115
1116
0
    return type->getResultId();
1117
0
}
1118
1119
Id Builder::makeArrayDebugType(Id const baseType, Id const componentCount)
1120
0
{
1121
0
    return makeSequentialDebugType(baseType, componentCount, NonSemanticShaderDebugInfoDebugTypeArray);
1122
0
}
1123
1124
Id Builder::makeVectorDebugType(Id const baseType, int const componentCount)
1125
0
{
1126
0
    return makeSequentialDebugType(baseType, makeUintConstant(componentCount), NonSemanticShaderDebugInfoDebugTypeVector);
1127
0
}
1128
1129
Id Builder::makeMatrixDebugType(Id const vectorType, int const vectorCount, bool columnMajor)
1130
0
{
1131
    // try to find it
1132
0
    Instruction* type;
1133
0
    for (int t = 0; t < (int)groupedDebugTypes[NonSemanticShaderDebugInfoDebugTypeMatrix].size(); ++t) {
1134
0
        type = groupedDebugTypes[NonSemanticShaderDebugInfoDebugTypeMatrix][t];
1135
0
        if (type->getIdOperand(0) == vectorType &&
1136
0
            type->getIdOperand(1) == makeUintConstant(vectorCount))
1137
0
            return type->getResultId();
1138
0
    }
1139
1140
    // not found, make it
1141
0
    type = new Instruction(getUniqueId(), makeVoidType(), Op::OpExtInst);
1142
0
    type->reserveOperands(5);
1143
0
    type->addIdOperand(nonSemanticShaderDebugInfo);
1144
0
    type->addImmediateOperand(NonSemanticShaderDebugInfoDebugTypeMatrix);
1145
0
    type->addIdOperand(getDebugType(vectorType)); // vector type id
1146
0
    type->addIdOperand(makeUintConstant(vectorCount)); // component count id
1147
0
    type->addIdOperand(makeBoolConstant(columnMajor)); // column-major id
1148
1149
0
    groupedDebugTypes[NonSemanticShaderDebugInfoDebugTypeMatrix].push_back(type);
1150
0
    constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(type));
1151
0
    module.mapInstruction(type);
1152
1153
0
    return type->getResultId();
1154
0
}
1155
1156
// DebugTypeVectorIdEXT (NSDI.101 opcode 109): describes OpTypeVectorIdEXT and
1157
// OpTypeCooperativeVectorNV types whose component count is a SPIR-V Id (not a
1158
// literal), including specialization-constant component counts.
1159
Id Builder::makeVectorIdDebugType(Id const componentType, Id const componentCount)
1160
0
{
1161
0
    requireNonSemanticShaderDebugInfoVersion(101);
1162
    // try to find it
1163
0
    Instruction* type;
1164
0
    for (int t = 0; t < (int)groupedDebugTypes[NonSemanticShaderDebugInfoDebugTypeVectorIdEXT].size(); ++t) {
1165
0
        type = groupedDebugTypes[NonSemanticShaderDebugInfoDebugTypeVectorIdEXT][t];
1166
0
        if (type->getIdOperand(2) == getDebugType(componentType) &&
1167
0
            type->getIdOperand(3) == componentCount)
1168
0
            return type->getResultId();
1169
0
    }
1170
1171
    // not found, make it
1172
0
    type = new Instruction(getUniqueId(), makeVoidType(), Op::OpExtInst);
1173
0
    type->reserveOperands(4);
1174
0
    type->addIdOperand(nonSemanticShaderDebugInfo);
1175
0
    type->addImmediateOperand(NonSemanticShaderDebugInfoDebugTypeVectorIdEXT);
1176
0
    type->addIdOperand(getDebugType(componentType)); // component debug type
1177
0
    type->addIdOperand(componentCount); // component count (constant instruction Id)
1178
1179
0
    groupedDebugTypes[NonSemanticShaderDebugInfoDebugTypeVectorIdEXT].push_back(type);
1180
0
    constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(type));
1181
0
    module.mapInstruction(type);
1182
1183
0
    return type->getResultId();
1184
0
}
1185
1186
// DebugTypeCooperativeMatrixKHR (NSDI.101 opcode 110): describes
1187
// OpTypeCooperativeMatrixKHR types.
1188
Id Builder::makeCooperativeMatrixDebugTypeKHR(Id const componentType, Id const scope,
1189
                                              Id const rows, Id const cols, Id const use)
1190
0
{
1191
0
    requireNonSemanticShaderDebugInfoVersion(101);
1192
    // try to find it
1193
0
    Instruction* type;
1194
0
    for (int t = 0; t < (int)groupedDebugTypes[NonSemanticShaderDebugInfoDebugTypeCooperativeMatrixKHR].size(); ++t) {
1195
0
        type = groupedDebugTypes[NonSemanticShaderDebugInfoDebugTypeCooperativeMatrixKHR][t];
1196
0
        if (type->getIdOperand(2) == getDebugType(componentType) &&
1197
0
            type->getIdOperand(3) == scope &&
1198
0
            type->getIdOperand(4) == rows &&
1199
0
            type->getIdOperand(5) == cols &&
1200
0
            type->getIdOperand(6) == use)
1201
0
            return type->getResultId();
1202
0
    }
1203
1204
    // not found, make it
1205
0
    type = new Instruction(getUniqueId(), makeVoidType(), Op::OpExtInst);
1206
0
    type->reserveOperands(7);
1207
0
    type->addIdOperand(nonSemanticShaderDebugInfo);
1208
0
    type->addImmediateOperand(NonSemanticShaderDebugInfoDebugTypeCooperativeMatrixKHR);
1209
0
    type->addIdOperand(getDebugType(componentType)); // component debug type
1210
0
    type->addIdOperand(scope); // scope
1211
0
    type->addIdOperand(rows); // rows
1212
0
    type->addIdOperand(cols); // columns
1213
0
    type->addIdOperand(use); // use (MatrixA, MatrixB, Accumulator)
1214
1215
0
    groupedDebugTypes[NonSemanticShaderDebugInfoDebugTypeCooperativeMatrixKHR].push_back(type);
1216
0
    constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(type));
1217
0
    module.mapInstruction(type);
1218
1219
0
    return type->getResultId();
1220
0
}
1221
1222
Id Builder::makeMemberDebugType(Id const memberType, StructMemberDebugInfo const& debugTypeLoc)
1223
0
{
1224
0
    assert(getDebugType(memberType) != NoType);
1225
1226
0
    Instruction* type = new Instruction(getUniqueId(), makeVoidType(), Op::OpExtInst);
1227
0
    type->reserveOperands(10);
1228
0
    type->addIdOperand(nonSemanticShaderDebugInfo);
1229
0
    type->addImmediateOperand(NonSemanticShaderDebugInfoDebugTypeMember);
1230
0
    type->addIdOperand(getStringId(debugTypeLoc.name)); // name id
1231
0
    type->addIdOperand(debugTypeLoc.debugTypeOverride != 0 ? debugTypeLoc.debugTypeOverride
1232
0
                                                           : getDebugType(memberType)); // type id
1233
0
    type->addIdOperand(makeDebugSource(currentFileId));                            // source id
1234
0
    type->addIdOperand(makeUintConstant(debugTypeLoc.line));   // line id TODO: currentLine is always zero
1235
0
    type->addIdOperand(makeUintConstant(debugTypeLoc.column)); // TODO: column id
1236
0
    type->addIdOperand(makeUintConstant(0));                   // TODO: offset id
1237
0
    type->addIdOperand(makeUintConstant(0));                   // TODO: size id
1238
0
    type->addIdOperand(makeUintConstant(NonSemanticShaderDebugInfoFlagIsPublic)); // flags id
1239
1240
0
    groupedDebugTypes[NonSemanticShaderDebugInfoDebugTypeMember].push_back(type);
1241
0
    constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(type));
1242
0
    module.mapInstruction(type);
1243
1244
0
    return type->getResultId();
1245
0
}
1246
1247
Id Builder::makeCompositeDebugType(std::vector<Id> const& memberTypes, std::vector<StructMemberDebugInfo> const& memberDebugInfo,
1248
                                   char const* const name, NonSemanticShaderDebugInfoDebugCompositeType const tag)
1249
0
{
1250
    // Create the debug member types.
1251
0
    std::vector<Id> memberDebugTypes;
1252
0
    assert(memberTypes.size() == memberDebugInfo.size());
1253
0
    for (size_t i = 0; i < memberTypes.size(); i++) {
1254
0
        if (getDebugType(memberTypes[i]) != NoType) {
1255
0
            memberDebugTypes.emplace_back(makeMemberDebugType(memberTypes[i], memberDebugInfo[i]));
1256
0
        }
1257
0
    }
1258
1259
    // Create The structure debug type.
1260
0
    Instruction* type = new Instruction(getUniqueId(), makeVoidType(), Op::OpExtInst);
1261
0
    type->reserveOperands(memberDebugTypes.size() + 11);
1262
0
    type->addIdOperand(nonSemanticShaderDebugInfo);
1263
0
    type->addImmediateOperand(NonSemanticShaderDebugInfoDebugTypeComposite);
1264
0
    type->addIdOperand(getStringId(name)); // name id
1265
0
    type->addIdOperand(makeUintConstant(tag)); // tag id
1266
0
    type->addIdOperand(makeDebugSource(currentFileId)); // source id
1267
0
    type->addIdOperand(makeUintConstant(currentLine)); // line id TODO: currentLine always zero?
1268
0
    type->addIdOperand(makeUintConstant(0)); // TODO: column id
1269
0
    type->addIdOperand(makeDebugCompilationUnit()); // scope id
1270
0
    type->addIdOperand(getStringId(name)); // linkage name id
1271
0
    type->addIdOperand(makeUintConstant(0)); // TODO: size id
1272
0
    type->addIdOperand(makeUintConstant(NonSemanticShaderDebugInfoFlagIsPublic)); // flags id
1273
0
    for(auto const memberDebugType : memberDebugTypes) {
1274
0
        type->addIdOperand(memberDebugType);
1275
0
    }
1276
1277
0
    groupedDebugTypes[NonSemanticShaderDebugInfoDebugTypeComposite].push_back(type);
1278
0
    constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(type));
1279
0
    module.mapInstruction(type);
1280
1281
0
    return type->getResultId();
1282
0
}
1283
1284
// The NonSemantic Shader Debug Info doesn't really have a dedicated opcode for opaque types. Instead, we use DebugTypeComposite.
1285
// To represent a source language opaque type, this instruction must have no Members operands, Size operand must be
1286
// DebugInfoNone, and Name must start with @ to avoid clashes with user defined names.
1287
Id Builder::makeOpaqueDebugType(char const* const name)
1288
0
{
1289
    // Create The structure debug type.
1290
0
    Instruction* type = new Instruction(getUniqueId(), makeVoidType(), Op::OpExtInst);
1291
0
    type->reserveOperands(11);
1292
0
    type->addIdOperand(nonSemanticShaderDebugInfo);
1293
0
    type->addImmediateOperand(NonSemanticShaderDebugInfoDebugTypeComposite);
1294
0
    type->addIdOperand(getStringId(name)); // name id
1295
0
    type->addIdOperand(makeUintConstant(NonSemanticShaderDebugInfoStructure)); // tag id
1296
0
    type->addIdOperand(makeDebugSource(currentFileId)); // source id
1297
0
    type->addIdOperand(makeUintConstant(currentLine)); // line id TODO: currentLine always zero?
1298
0
    type->addIdOperand(makeUintConstant(0)); // TODO: column id
1299
0
    type->addIdOperand(makeDebugCompilationUnit()); // scope id
1300
    // Prepend '@' to opaque types.
1301
0
    type->addIdOperand(getStringId('@' + std::string(name))); // linkage name id
1302
0
    type->addIdOperand(makeDebugInfoNone()); // size id
1303
0
    type->addIdOperand(makeUintConstant(NonSemanticShaderDebugInfoFlagIsPublic)); // flags id
1304
1305
0
    groupedDebugTypes[NonSemanticShaderDebugInfoDebugTypeComposite].push_back(type);
1306
0
    constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(type));
1307
0
    module.mapInstruction(type);
1308
1309
0
    return type->getResultId();
1310
0
}
1311
1312
Id Builder::makePointerDebugType(StorageClass storageClass, Id const baseType)
1313
0
{
1314
0
    const Id debugBaseType = getDebugType(baseType);
1315
0
    if (!debugBaseType) {
1316
0
        return makeDebugInfoNone();
1317
0
    }
1318
0
    const Id scID = makeUintConstant(storageClass);
1319
0
    for (Instruction* otherType : groupedDebugTypes[NonSemanticShaderDebugInfoDebugTypePointer]) {
1320
0
        if (otherType->getIdOperand(2) == debugBaseType &&
1321
0
            otherType->getIdOperand(3) == scID) {
1322
0
            return otherType->getResultId();
1323
0
        }
1324
0
    }
1325
1326
0
    Instruction* type = new Instruction(getUniqueId(), makeVoidType(), Op::OpExtInst);
1327
0
    type->reserveOperands(5);
1328
0
    type->addIdOperand(nonSemanticShaderDebugInfo);
1329
0
    type->addImmediateOperand(NonSemanticShaderDebugInfoDebugTypePointer);
1330
0
    type->addIdOperand(debugBaseType);
1331
0
    type->addIdOperand(scID);
1332
0
    type->addIdOperand(makeUintConstant(0));
1333
1334
0
    groupedDebugTypes[NonSemanticShaderDebugInfoDebugTypePointer].push_back(type);
1335
0
    constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(type));
1336
0
    module.mapInstruction(type);
1337
1338
0
    return type->getResultId();
1339
0
}
1340
1341
// Emit a OpExtInstWithForwardRefsKHR nonsemantic instruction for a pointer debug type
1342
// where we don't have the pointee yet. Since we don't have the pointee yet, it just
1343
// points to itself and we rely on patching it later.
1344
Id Builder::makeForwardPointerDebugType(StorageClass storageClass)
1345
0
{
1346
0
    const Id scID = makeUintConstant(storageClass);
1347
1348
0
    this->addExtension(spv::E_SPV_KHR_relaxed_extended_instruction);
1349
1350
0
    Instruction *type = new Instruction(getUniqueId(), makeVoidType(), Op::OpExtInstWithForwardRefsKHR);
1351
0
    type->addIdOperand(nonSemanticShaderDebugInfo);
1352
0
    type->addImmediateOperand(NonSemanticShaderDebugInfoDebugTypePointer);
1353
0
    type->addIdOperand(type->getResultId());
1354
0
    type->addIdOperand(scID);
1355
0
    type->addIdOperand(makeUintConstant(0));
1356
1357
0
    groupedDebugTypes[NonSemanticShaderDebugInfoDebugTypePointer].push_back(type);
1358
0
    constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(type));
1359
0
    module.mapInstruction(type);
1360
1361
0
    return type->getResultId();
1362
0
}
1363
1364
0
Id Builder::makeDebugSource(const Id fileName) {
1365
0
    if (debugSourceId.find(fileName) != debugSourceId.end())
1366
0
        return debugSourceId[fileName];
1367
0
    spv::Id resultId = getUniqueId();
1368
0
    Instruction* sourceInst = new Instruction(resultId, makeVoidType(), Op::OpExtInst);
1369
0
    sourceInst->reserveOperands(3);
1370
0
    sourceInst->addIdOperand(nonSemanticShaderDebugInfo);
1371
0
    sourceInst->addImmediateOperand(NonSemanticShaderDebugInfoDebugSource);
1372
0
    sourceInst->addIdOperand(fileName);
1373
0
    constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(sourceInst));
1374
0
    module.mapInstruction(sourceInst);
1375
0
    if (emitNonSemanticShaderDebugSource) {
1376
0
        const int maxWordCount = 0xFFFF;
1377
0
        const int opSourceWordCount = 4;
1378
0
        const int nonNullBytesPerInstruction = 4 * (maxWordCount - opSourceWordCount) - 1;
1379
0
        auto processDebugSource = [&](std::string source) {
1380
0
            if (source.size() > 0) {
1381
0
                int nextByte = 0;
1382
0
                while ((int)source.size() - nextByte > 0) {
1383
0
                    auto subString = source.substr(nextByte, nonNullBytesPerInstruction);
1384
0
                    auto sourceId = getStringId(subString);
1385
0
                    if (nextByte == 0) {
1386
                        // DebugSource
1387
0
                        sourceInst->addIdOperand(sourceId);
1388
0
                    } else {
1389
                        // DebugSourceContinued
1390
0
                        Instruction* sourceContinuedInst = new Instruction(getUniqueId(), makeVoidType(), Op::OpExtInst);
1391
0
                        sourceContinuedInst->reserveOperands(2);
1392
0
                        sourceContinuedInst->addIdOperand(nonSemanticShaderDebugInfo);
1393
0
                        sourceContinuedInst->addImmediateOperand(NonSemanticShaderDebugInfoDebugSourceContinued);
1394
0
                        sourceContinuedInst->addIdOperand(sourceId);
1395
0
                        constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(sourceContinuedInst));
1396
0
                        module.mapInstruction(sourceContinuedInst);
1397
0
                    }
1398
0
                    nextByte += nonNullBytesPerInstruction;
1399
0
                }
1400
0
            } else {
1401
0
                auto sourceId = getStringId(source);
1402
0
                sourceInst->addIdOperand(sourceId);
1403
0
            }
1404
0
        };
1405
0
        if (fileName == mainFileId) {
1406
0
            processDebugSource(sourceText);
1407
0
        } else {
1408
0
            auto incItr = includeFiles.find(fileName);
1409
0
            if (incItr != includeFiles.end()) {
1410
0
                processDebugSource(*incItr->second);
1411
0
            } else {
1412
                // We omit the optional source text item if not available in glslang
1413
0
            }
1414
0
        }
1415
0
    }
1416
0
    debugSourceId[fileName] = resultId;
1417
0
    return resultId;
1418
0
}
1419
1420
0
Id Builder::makeDebugCompilationUnit() {
1421
0
    if (nonSemanticShaderCompilationUnitId != 0)
1422
0
        return nonSemanticShaderCompilationUnitId;
1423
0
    spv::Id resultId = getUniqueId();
1424
0
    Instruction* sourceInst = new Instruction(resultId, makeVoidType(), Op::OpExtInst);
1425
0
    sourceInst->reserveOperands(6);
1426
0
    sourceInst->addIdOperand(nonSemanticShaderDebugInfo);
1427
0
    sourceInst->addImmediateOperand(NonSemanticShaderDebugInfoDebugCompilationUnit);
1428
0
    sourceInst->addIdOperand(makeUintConstant(1)); // TODO(greg-lunarg): Get rid of magic number
1429
0
    sourceInst->addIdOperand(makeUintConstant(4)); // TODO(greg-lunarg): Get rid of magic number
1430
0
    sourceInst->addIdOperand(makeDebugSource(mainFileId));
1431
0
    sourceInst->addIdOperand(makeUintConstant(sourceLang));
1432
0
    constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(sourceInst));
1433
0
    module.mapInstruction(sourceInst);
1434
0
    nonSemanticShaderCompilationUnitId = resultId;
1435
1436
    // In the case of non-semantic shader debug info, preserve source text for every include
1437
    // even if no debug scope or line record ends up referencing that file.
1438
0
    if (emitNonSemanticShaderDebugSource) {
1439
0
        for (const auto& includeFile : includeFiles) {
1440
0
            makeDebugSource(includeFile.first);
1441
0
        }
1442
0
    }
1443
1444
    // We can reasonably assume that makeDebugCompilationUnit will be called before any of
1445
    // debug-scope stack. Function scopes and lexical scopes will occur afterward.
1446
0
    assert(currentDebugScopeId.empty());
1447
0
    currentDebugScopeId.push(nonSemanticShaderCompilationUnitId);
1448
1449
0
    return resultId;
1450
0
}
1451
1452
Id Builder::createDebugGlobalVariable(Id const type, char const*const name, Id const variable)
1453
0
{
1454
0
    assert(type != 0);
1455
1456
0
    Instruction* inst = new Instruction(getUniqueId(), makeVoidType(), Op::OpExtInst);
1457
0
    inst->reserveOperands(11);
1458
0
    inst->addIdOperand(nonSemanticShaderDebugInfo);
1459
0
    inst->addImmediateOperand(NonSemanticShaderDebugInfoDebugGlobalVariable);
1460
0
    inst->addIdOperand(getStringId(name)); // name id
1461
0
    inst->addIdOperand(type); // type id
1462
0
    inst->addIdOperand(makeDebugSource(currentFileId)); // source id
1463
0
    inst->addIdOperand(makeUintConstant(currentLine)); // line id TODO: currentLine always zero?
1464
0
    inst->addIdOperand(makeUintConstant(0)); // TODO: column id
1465
0
    inst->addIdOperand(makeDebugCompilationUnit()); // scope id
1466
0
    inst->addIdOperand(getStringId(name)); // linkage name id
1467
0
    inst->addIdOperand(variable); // variable id
1468
0
    inst->addIdOperand(makeUintConstant(NonSemanticShaderDebugInfoFlagIsDefinition)); // flags id
1469
1470
0
    constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(inst));
1471
0
    module.mapInstruction(inst);
1472
1473
0
    return inst->getResultId();
1474
0
}
1475
1476
Id Builder::createDebugLocalVariable(Id type, char const*const name, size_t const argNumber)
1477
0
{
1478
0
    assert(name != nullptr);
1479
0
    assert(!currentDebugScopeId.empty());
1480
1481
0
    Instruction* inst = new Instruction(getUniqueId(), makeVoidType(), Op::OpExtInst);
1482
0
    inst->reserveOperands(9);
1483
0
    inst->addIdOperand(nonSemanticShaderDebugInfo);
1484
0
    inst->addImmediateOperand(NonSemanticShaderDebugInfoDebugLocalVariable);
1485
0
    inst->addIdOperand(getStringId(name)); // name id
1486
0
    inst->addIdOperand(type); // type id
1487
0
    inst->addIdOperand(makeDebugSource(currentFileId)); // source id
1488
0
    inst->addIdOperand(makeUintConstant(currentLine)); // line id
1489
0
    inst->addIdOperand(makeUintConstant(0)); // TODO: column id
1490
0
    inst->addIdOperand(currentDebugScopeId.top()); // scope id
1491
0
    inst->addIdOperand(makeUintConstant(NonSemanticShaderDebugInfoFlagIsLocal)); // flags id
1492
0
    if(argNumber != 0) {
1493
0
        inst->addIdOperand(makeUintConstant(static_cast<unsigned int>(argNumber)));
1494
0
    }
1495
1496
0
    constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(inst));
1497
0
    module.mapInstruction(inst);
1498
1499
0
    return inst->getResultId();
1500
0
}
1501
1502
Id Builder::makeDebugExpression()
1503
0
{
1504
0
    if (debugExpression != 0)
1505
0
        return debugExpression;
1506
1507
0
    Instruction* inst = new Instruction(getUniqueId(), makeVoidType(), Op::OpExtInst);
1508
0
    inst->reserveOperands(2);
1509
0
    inst->addIdOperand(nonSemanticShaderDebugInfo);
1510
0
    inst->addImmediateOperand(NonSemanticShaderDebugInfoDebugExpression);
1511
1512
0
    constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(inst));
1513
0
    module.mapInstruction(inst);
1514
1515
0
    debugExpression = inst->getResultId();
1516
1517
0
    return debugExpression;
1518
0
}
1519
1520
Id Builder::makeDebugDeclare(Id const debugLocalVariable, Id const pointer)
1521
0
{
1522
0
    Instruction* inst = new Instruction(getUniqueId(), makeVoidType(), Op::OpExtInst);
1523
0
    inst->reserveOperands(5);
1524
0
    inst->addIdOperand(nonSemanticShaderDebugInfo);
1525
0
    inst->addImmediateOperand(NonSemanticShaderDebugInfoDebugDeclare);
1526
0
    inst->addIdOperand(debugLocalVariable); // debug local variable id
1527
0
    inst->addIdOperand(pointer); // pointer to local variable id
1528
0
    inst->addIdOperand(makeDebugExpression()); // expression id
1529
0
    addInstruction(std::unique_ptr<Instruction>(inst));
1530
1531
0
    return inst->getResultId();
1532
0
}
1533
1534
Id Builder::makeDebugValue(Id const debugLocalVariable, Id const value)
1535
0
{
1536
0
    Instruction* inst = new Instruction(getUniqueId(), makeVoidType(), Op::OpExtInst);
1537
0
    inst->reserveOperands(5);
1538
0
    inst->addIdOperand(nonSemanticShaderDebugInfo);
1539
0
    inst->addImmediateOperand(NonSemanticShaderDebugInfoDebugValue);
1540
0
    inst->addIdOperand(debugLocalVariable); // debug local variable id
1541
0
    inst->addIdOperand(value); // value of local variable id
1542
0
    inst->addIdOperand(makeDebugExpression()); // expression id
1543
0
    addInstruction(std::unique_ptr<Instruction>(inst));
1544
1545
0
    return inst->getResultId();
1546
0
}
1547
1548
Id Builder::makeAccelerationStructureType()
1549
37
{
1550
37
    Instruction *type;
1551
37
    if (groupedTypes[enumCast(Op::OpTypeAccelerationStructureKHR)].size() == 0) {
1552
37
        type = new Instruction(getUniqueId(), NoType, Op::OpTypeAccelerationStructureKHR);
1553
37
        groupedTypes[enumCast(Op::OpTypeAccelerationStructureKHR)].push_back(type);
1554
37
        constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(type));
1555
37
        module.mapInstruction(type);
1556
37
        if (emitNonSemanticShaderDebugInfo) {
1557
0
            spv::Id debugType = makeOpaqueDebugType("accelerationStructure");
1558
0
            debugTypeIdLookup[type->getResultId()] = debugType;
1559
0
        }
1560
37
    } else {
1561
0
        type = groupedTypes[enumCast(Op::OpTypeAccelerationStructureKHR)].back();
1562
0
    }
1563
1564
37
    return type->getResultId();
1565
37
}
1566
1567
Id Builder::makeRayQueryType()
1568
37
{
1569
37
    Instruction *type;
1570
37
    if (groupedTypes[enumCast(Op::OpTypeRayQueryKHR)].size() == 0) {
1571
37
        type = new Instruction(getUniqueId(), NoType, Op::OpTypeRayQueryKHR);
1572
37
        groupedTypes[enumCast(Op::OpTypeRayQueryKHR)].push_back(type);
1573
37
        constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(type));
1574
37
        module.mapInstruction(type);
1575
37
        if (emitNonSemanticShaderDebugInfo) {
1576
0
            spv::Id debugType = makeOpaqueDebugType("rayQuery");
1577
0
            debugTypeIdLookup[type->getResultId()] = debugType;
1578
0
        }
1579
37
    } else {
1580
0
        type = groupedTypes[enumCast(Op::OpTypeRayQueryKHR)].back();
1581
0
    }
1582
1583
37
    return type->getResultId();
1584
37
}
1585
1586
Id Builder::makeHitObjectEXTType()
1587
0
{
1588
0
    Instruction *type;
1589
0
    if (groupedTypes[enumCast(Op::OpTypeHitObjectEXT)].size() == 0) {
1590
0
        type = new Instruction(getUniqueId(), NoType, Op::OpTypeHitObjectEXT);
1591
0
        groupedTypes[enumCast(Op::OpTypeHitObjectEXT)].push_back(type);
1592
0
        constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(type));
1593
0
        module.mapInstruction(type);
1594
0
    } else {
1595
0
        type = groupedTypes[enumCast(Op::OpTypeHitObjectEXT)].back();
1596
0
    }
1597
1598
0
    return type->getResultId();
1599
0
}
1600
Id Builder::makeHitObjectNVType()
1601
0
{
1602
0
    Instruction *type;
1603
0
    if (groupedTypes[enumCast(Op::OpTypeHitObjectNV)].size() == 0) {
1604
0
        type = new Instruction(getUniqueId(), NoType, Op::OpTypeHitObjectNV);
1605
0
        groupedTypes[enumCast(Op::OpTypeHitObjectNV)].push_back(type);
1606
0
        constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(type));
1607
0
        module.mapInstruction(type);
1608
0
        if (emitNonSemanticShaderDebugInfo) {
1609
0
            spv::Id debugType = makeOpaqueDebugType("hitObjectNV");
1610
0
            debugTypeIdLookup[type->getResultId()] = debugType;
1611
0
        }
1612
0
    } else {
1613
0
        type = groupedTypes[enumCast(Op::OpTypeHitObjectNV)].back();
1614
0
    }
1615
1616
0
    return type->getResultId();
1617
0
}
1618
1619
Id Builder::getDerefTypeId(Id resultId) const
1620
22.6k
{
1621
22.6k
    Id typeId = getTypeId(resultId);
1622
22.6k
    assert(isPointerType(typeId));
1623
1624
22.6k
    return module.getInstruction(typeId)->getIdOperand(1);
1625
22.6k
}
1626
1627
Op Builder::getMostBasicTypeClass(Id typeId) const
1628
296k
{
1629
296k
    Instruction* instr = module.getInstruction(typeId);
1630
1631
296k
    Op typeClass = instr->getOpCode();
1632
296k
    switch (typeClass)
1633
296k
    {
1634
71.8k
    case Op::OpTypeVector:
1635
73.9k
    case Op::OpTypeMatrix:
1636
74.2k
    case Op::OpTypeArray:
1637
74.2k
    case Op::OpTypeRuntimeArray:
1638
74.2k
        return getMostBasicTypeClass(instr->getIdOperand(0));
1639
56.1k
    case Op::OpTypePointer:
1640
56.1k
        return getMostBasicTypeClass(instr->getIdOperand(1));
1641
165k
    default:
1642
165k
        return typeClass;
1643
296k
    }
1644
296k
}
1645
1646
unsigned int Builder::getNumTypeConstituents(Id typeId) const
1647
8.29k
{
1648
8.29k
    Instruction* instr = module.getInstruction(typeId);
1649
1650
8.29k
    switch (instr->getOpCode())
1651
8.29k
    {
1652
0
    case Op::OpTypeBool:
1653
88
    case Op::OpTypeInt:
1654
99
    case Op::OpTypeFloat:
1655
99
    case Op::OpTypePointer:
1656
99
        return 1;
1657
8.11k
    case Op::OpTypeVector:
1658
8.19k
    case Op::OpTypeMatrix:
1659
8.19k
        return instr->getImmediateOperand(1);
1660
0
    case Op::OpTypeCooperativeVectorNV:
1661
0
    case Op::OpTypeArray:
1662
0
    {
1663
0
        Id lengthId = instr->getIdOperand(1);
1664
0
        return module.getInstruction(lengthId)->getImmediateOperand(0);
1665
0
    }
1666
0
    case Op::OpTypeStruct:
1667
0
        return instr->getNumOperands();
1668
0
    case Op::OpTypeCooperativeMatrixKHR:
1669
0
    case Op::OpTypeCooperativeMatrixNV:
1670
        // has only one constituent when used with OpCompositeConstruct.
1671
0
        return 1;
1672
0
    default:
1673
0
        assert(0);
1674
0
        return 1;
1675
8.29k
    }
1676
8.29k
}
1677
1678
// Return the lowest-level type of scalar that an homogeneous composite is made out of.
1679
// Typically, this is just to find out if something is made out of ints or floats.
1680
// However, it includes returning a structure, if say, it is an array of structure.
1681
Id Builder::getScalarTypeId(Id typeId) const
1682
261k
{
1683
261k
    Instruction* instr = module.getInstruction(typeId);
1684
1685
261k
    Op typeClass = instr->getOpCode();
1686
261k
    switch (typeClass)
1687
261k
    {
1688
0
    case Op::OpTypeVoid:
1689
36
    case Op::OpTypeBool:
1690
65.5k
    case Op::OpTypeInt:
1691
141k
    case Op::OpTypeFloat:
1692
141k
    case Op::OpTypeStruct:
1693
141k
        return instr->getResultId();
1694
76.3k
    case Op::OpTypeVector:
1695
78.5k
    case Op::OpTypeMatrix:
1696
78.6k
    case Op::OpTypeArray:
1697
78.6k
    case Op::OpTypeRuntimeArray:
1698
119k
    case Op::OpTypePointer:
1699
119k
    case Op::OpTypeCooperativeVectorNV:
1700
119k
        return getScalarTypeId(getContainedTypeId(typeId));
1701
0
    default:
1702
0
        assert(0);
1703
0
        return NoResult;
1704
261k
    }
1705
261k
}
1706
1707
// Return the type of 'member' of a composite.
1708
Id Builder::getContainedTypeId(Id typeId, int member) const
1709
191k
{
1710
191k
    Instruction* instr = module.getInstruction(typeId);
1711
1712
191k
    Op typeClass = instr->getOpCode();
1713
191k
    switch (typeClass)
1714
191k
    {
1715
86.0k
    case Op::OpTypeVector:
1716
89.1k
    case Op::OpTypeMatrix:
1717
90.7k
    case Op::OpTypeArray:
1718
90.8k
    case Op::OpTypeRuntimeArray:
1719
90.8k
    case Op::OpTypeCooperativeMatrixKHR:
1720
90.8k
    case Op::OpTypeCooperativeMatrixNV:
1721
90.8k
    case Op::OpTypeCooperativeVectorNV:
1722
90.8k
        return instr->getIdOperand(0);
1723
89.9k
    case Op::OpTypePointer:
1724
89.9k
        return instr->getIdOperand(1);
1725
10.4k
    case Op::OpTypeStruct:
1726
10.4k
        return instr->getIdOperand(member);
1727
0
    default:
1728
0
        assert(0);
1729
0
        return NoResult;
1730
191k
    }
1731
191k
}
1732
1733
// Figure out the final resulting type of the access chain.
1734
Id Builder::getResultingAccessChainType() const
1735
9.56k
{
1736
9.56k
    assert(accessChain.base != NoResult);
1737
9.56k
    Id typeId = getTypeId(accessChain.base);
1738
1739
9.56k
    assert(isPointerType(typeId));
1740
9.56k
    typeId = getContainedTypeId(typeId);
1741
1742
19.7k
    for (int i = 0; i < (int)accessChain.indexChain.size(); ++i) {
1743
10.1k
        if (isStructType(typeId)) {
1744
6.60k
            assert(isConstantScalar(accessChain.indexChain[i]));
1745
6.60k
            typeId = getContainedTypeId(typeId, getConstantScalar(accessChain.indexChain[i]));
1746
6.60k
        } else
1747
3.55k
            typeId = getContainedTypeId(typeId, accessChain.indexChain[i]);
1748
10.1k
    }
1749
1750
9.56k
    return typeId;
1751
9.56k
}
1752
1753
// Return the immediately contained type of a given composite type.
1754
Id Builder::getContainedTypeId(Id typeId) const
1755
177k
{
1756
177k
    return getContainedTypeId(typeId, 0);
1757
177k
}
1758
1759
// Returns true if 'typeId' is or contains a scalar type declared with 'typeOp'
1760
// of width 'width'. The 'width' is only consumed for int and float types.
1761
// Returns false otherwise.
1762
bool Builder::containsType(Id typeId, spv::Op typeOp, unsigned int width) const
1763
14.8k
{
1764
14.8k
    const Instruction& instr = *module.getInstruction(typeId);
1765
1766
14.8k
    Op typeClass = instr.getOpCode();
1767
14.8k
    switch (typeClass)
1768
14.8k
    {
1769
4.23k
    case Op::OpTypeInt:
1770
7.01k
    case Op::OpTypeFloat:
1771
7.01k
        return typeClass == typeOp && instr.getImmediateOperand(0) == width;
1772
1.10k
    case Op::OpTypeStruct:
1773
3.87k
        for (int m = 0; m < instr.getNumOperands(); ++m) {
1774
2.79k
            if (containsType(instr.getIdOperand(m), typeOp, width))
1775
18
                return true;
1776
2.79k
        }
1777
1.08k
        return false;
1778
3.03k
    case Op::OpTypePointer:
1779
3.03k
        return false;
1780
3.04k
    case Op::OpTypeVector:
1781
3.41k
    case Op::OpTypeMatrix:
1782
3.55k
    case Op::OpTypeArray:
1783
3.55k
    case Op::OpTypeRuntimeArray:
1784
3.55k
        return containsType(getContainedTypeId(typeId), typeOp, width);
1785
150
    default:
1786
150
        return typeClass == typeOp;
1787
14.8k
    }
1788
14.8k
}
1789
1790
// return true if the type is a pointer to PhysicalStorageBufferEXT or an
1791
// contains such a pointer. These require restrict/aliased decorations.
1792
bool Builder::containsPhysicalStorageBufferOrArray(Id typeId) const
1793
4.24k
{
1794
4.24k
    const Instruction& instr = *module.getInstruction(typeId);
1795
1796
4.24k
    Op typeClass = instr.getOpCode();
1797
4.24k
    switch (typeClass)
1798
4.24k
    {
1799
108
    case Op::OpTypePointer:
1800
108
        return getTypeStorageClass(typeId) == StorageClass::PhysicalStorageBufferEXT;
1801
81
    case Op::OpTypeArray:
1802
81
        return containsPhysicalStorageBufferOrArray(getContainedTypeId(typeId));
1803
265
    case Op::OpTypeStruct:
1804
1.11k
        for (int m = 0; m < instr.getNumOperands(); ++m) {
1805
847
            if (containsPhysicalStorageBufferOrArray(instr.getIdOperand(m)))
1806
0
                return true;
1807
847
        }
1808
265
        return false;
1809
3.79k
    default:
1810
3.79k
        return false;
1811
4.24k
    }
1812
4.24k
}
1813
1814
// See if a scalar constant of this type has already been created, so it
1815
// can be reused rather than duplicated.  (Required by the specification).
1816
Id Builder::findScalarConstant(Op typeClass, Op opcode, Id typeId, unsigned value)
1817
33.3k
{
1818
33.3k
    ScalarConstantKey key{ enumCast(typeClass), enumCast(opcode), typeId, value, 0 };
1819
33.3k
    auto it = groupedScalarConstantResultIDs.find(key);
1820
33.3k
    return (it != groupedScalarConstantResultIDs.end()) ? it->second : 0;
1821
33.3k
}
1822
1823
// Version of findScalarConstant (see above) for scalars that take two operands (e.g. a 'double' or 'int64').
1824
Id Builder::findScalarConstant(Op typeClass, Op opcode, Id typeId, unsigned v1, unsigned v2)
1825
2.01k
{
1826
2.01k
    ScalarConstantKey key{ enumCast(typeClass), enumCast(opcode), typeId, v1, v2 };
1827
2.01k
    auto it = groupedScalarConstantResultIDs.find(key);
1828
2.01k
    return (it != groupedScalarConstantResultIDs.end()) ? it->second : 0;
1829
2.01k
}
1830
1831
// Return true if consuming 'opcode' means consuming a constant.
1832
// "constant" here means after final transform to executable code,
1833
// the value consumed will be a constant, so includes specialization.
1834
bool Builder::isConstantOpCode(Op opcode) const
1835
530
{
1836
530
    switch (opcode) {
1837
0
    case Op::OpUndef:
1838
0
    case Op::OpConstantTrue:
1839
0
    case Op::OpConstantFalse:
1840
110
    case Op::OpConstant:
1841
110
    case Op::OpConstantDataKHR:
1842
530
    case Op::OpConstantComposite:
1843
530
    case Op::OpConstantCompositeReplicateEXT:
1844
530
    case Op::OpConstantSampler:
1845
530
    case Op::OpConstantNull:
1846
530
    case Op::OpSpecConstantTrue:
1847
530
    case Op::OpSpecConstantFalse:
1848
530
    case Op::OpSpecConstant:
1849
530
    case Op::OpSpecConstantComposite:
1850
530
    case Op::OpSpecConstantCompositeReplicateEXT:
1851
530
    case Op::OpSpecConstantDataKHR:
1852
530
    case Op::OpSpecConstantOp:
1853
530
    case Op::OpConstantSizeOfEXT:
1854
530
        return true;
1855
0
    default:
1856
0
        return false;
1857
530
    }
1858
530
}
1859
1860
// Return true if consuming 'opcode' means consuming a specialization constant.
1861
bool Builder::isSpecConstantOpCode(Op opcode) const
1862
0
{
1863
0
    switch (opcode) {
1864
0
    case Op::OpSpecConstantTrue:
1865
0
    case Op::OpSpecConstantFalse:
1866
0
    case Op::OpSpecConstant:
1867
0
    case Op::OpSpecConstantComposite:
1868
0
    case Op::OpSpecConstantDataKHR:
1869
0
    case Op::OpSpecConstantOp:
1870
0
    case Op::OpSpecConstantCompositeReplicateEXT:
1871
0
        return true;
1872
0
    default:
1873
0
        return false;
1874
0
    }
1875
0
}
1876
1877
Id Builder::makeNullConstant(Id typeId)
1878
0
{
1879
0
    Instruction* constant;
1880
1881
    // See if we already made it.
1882
0
    Id existing = NoResult;
1883
0
    for (int i = 0; i < (int)nullConstants.size(); ++i) {
1884
0
        constant = nullConstants[i];
1885
0
        if (constant->getTypeId() == typeId)
1886
0
            existing = constant->getResultId();
1887
0
    }
1888
1889
0
    if (existing != NoResult)
1890
0
        return existing;
1891
1892
    // Make it
1893
0
    Instruction* c = new Instruction(getUniqueId(), typeId, Op::OpConstantNull);
1894
0
    constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(c));
1895
0
    nullConstants.push_back(c);
1896
0
    module.mapInstruction(c);
1897
1898
0
    return c->getResultId();
1899
0
}
1900
1901
Id Builder::makeBoolConstant(bool b, bool specConstant)
1902
1.12k
{
1903
1.12k
    Id typeId = makeBoolType();
1904
1.12k
    Op opcode = specConstant ? (b ? Op::OpSpecConstantTrue : Op::OpSpecConstantFalse) : (b ? Op::OpConstantTrue : Op::OpConstantFalse);
1905
1906
    // See if we already made it. Applies only to regular constants, because specialization constants
1907
    // must remain distinct for the purpose of applying a SpecId decoration.
1908
1.12k
    if (!specConstant) {
1909
1.08k
        Id existing = findScalarConstant(Op::OpTypeBool, opcode, typeId, 0);
1910
1.08k
        if (existing)
1911
913
            return existing;
1912
1.08k
    }
1913
1914
    // Make it
1915
211
    Instruction* c = new Instruction(getUniqueId(), typeId, opcode);
1916
211
    constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(c));
1917
211
    module.mapInstruction(c);
1918
1919
211
    Id resultId = c->getResultId();
1920
211
    if (!specConstant) {
1921
173
        ScalarConstantKey key{enumCast(Op::OpTypeBool), enumCast(opcode), typeId, 0, 0};
1922
173
        groupedScalarConstantResultIDs[key] = resultId;
1923
173
    }
1924
211
    return resultId;
1925
1.12k
}
1926
1927
Id Builder::makeIntConstant(Id typeId, unsigned value, bool specConstant)
1928
28.4k
{
1929
28.4k
    Op opcode = specConstant ? Op::OpSpecConstant : Op::OpConstant;
1930
1931
    // See if we already made it. Applies only to regular constants, because specialization constants
1932
    // must remain distinct for the purpose of applying a SpecId decoration.
1933
28.4k
    if (! specConstant) {
1934
28.2k
        Id existing = findScalarConstant(Op::OpTypeInt, opcode, typeId, value);
1935
28.2k
        if (existing)
1936
25.9k
            return existing;
1937
28.2k
    }
1938
1939
2.45k
    Instruction* c = new Instruction(getUniqueId(), typeId, opcode);
1940
2.45k
    c->addImmediateOperand(value);
1941
2.45k
    constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(c));
1942
2.45k
    module.mapInstruction(c);
1943
1944
2.45k
    Id resultId = c->getResultId();
1945
2.45k
    if (!specConstant) {
1946
2.25k
        ScalarConstantKey key{ enumCast(Op::OpTypeInt), enumCast(opcode), typeId, value, 0 };
1947
2.25k
        groupedScalarConstantResultIDs[key] = resultId;
1948
2.25k
    }
1949
2.45k
    return resultId;
1950
28.4k
}
1951
1952
Id Builder::makeInt64Constant(Id typeId, unsigned long long value, bool specConstant)
1953
2.04k
{
1954
2.04k
    Op opcode = specConstant ? Op::OpSpecConstant : Op::OpConstant;
1955
1956
2.04k
    unsigned op1 = value & 0xFFFFFFFF;
1957
2.04k
    unsigned op2 = value >> 32;
1958
1959
    // See if we already made it. Applies only to regular constants, because specialization constants
1960
    // must remain distinct for the purpose of applying a SpecId decoration.
1961
2.04k
    if (! specConstant) {
1962
1.99k
        Id existing = findScalarConstant(Op::OpTypeInt, opcode, typeId, op1, op2);
1963
1.99k
        if (existing)
1964
1.69k
            return existing;
1965
1.99k
    }
1966
1967
356
    Instruction* c = new Instruction(getUniqueId(), typeId, opcode);
1968
356
    c->reserveOperands(2);
1969
356
    c->addImmediateOperand(op1);
1970
356
    c->addImmediateOperand(op2);
1971
356
    constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(c));
1972
356
    module.mapInstruction(c);
1973
1974
356
    Id resultId = c->getResultId();
1975
356
    if (!specConstant) {
1976
306
        ScalarConstantKey key{ enumCast(Op::OpTypeInt), enumCast(opcode), typeId, op1, op2 };
1977
306
        groupedScalarConstantResultIDs[key] = resultId;
1978
306
    }
1979
356
    return resultId;
1980
2.04k
}
1981
1982
Id Builder::makeFloatConstant(float f, bool specConstant)
1983
3.16k
{
1984
3.16k
    Op opcode = specConstant ? Op::OpSpecConstant : Op::OpConstant;
1985
3.16k
    Id typeId = makeFloatType(32);
1986
3.16k
    union { float fl; unsigned int ui; } u;
1987
3.16k
    u.fl = f;
1988
3.16k
    unsigned value = u.ui;
1989
1990
    // See if we already made it. Applies only to regular constants, because specialization constants
1991
    // must remain distinct for the purpose of applying a SpecId decoration.
1992
3.16k
    if (! specConstant) {
1993
3.16k
        Id existing = findScalarConstant(Op::OpTypeFloat, opcode, typeId, value);
1994
3.16k
        if (existing)
1995
2.24k
            return existing;
1996
3.16k
    }
1997
1998
917
    Instruction* c = new Instruction(getUniqueId(), typeId, opcode);
1999
917
    c->addImmediateOperand(value);
2000
917
    constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(c));
2001
917
    module.mapInstruction(c);
2002
2003
917
    Id resultId = c->getResultId();
2004
917
    if (!specConstant) {
2005
917
        ScalarConstantKey key{ enumCast(Op::OpTypeFloat), enumCast(opcode), typeId, value, 0 };
2006
917
        groupedScalarConstantResultIDs[key] = resultId;
2007
917
    }
2008
917
    return resultId;
2009
3.16k
}
2010
2011
Id Builder::makeDoubleConstant(double d, bool specConstant)
2012
18
{
2013
18
    Op opcode = specConstant ? Op::OpSpecConstant : Op::OpConstant;
2014
18
    Id typeId = makeFloatType(64);
2015
18
    union { double db; unsigned long long ull; } u;
2016
18
    u.db = d;
2017
18
    unsigned long long value = u.ull;
2018
18
    unsigned op1 = value & 0xFFFFFFFF;
2019
18
    unsigned op2 = value >> 32;
2020
2021
    // See if we already made it. Applies only to regular constants, because specialization constants
2022
    // must remain distinct for the purpose of applying a SpecId decoration.
2023
18
    if (! specConstant) {
2024
18
        Id existing = findScalarConstant(Op::OpTypeFloat, opcode, typeId, op1, op2);
2025
18
        if (existing)
2026
0
            return existing;
2027
18
    }
2028
2029
18
    Instruction* c = new Instruction(getUniqueId(), typeId, opcode);
2030
18
    c->reserveOperands(2);
2031
18
    c->addImmediateOperand(op1);
2032
18
    c->addImmediateOperand(op2);
2033
18
    constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(c));
2034
18
    module.mapInstruction(c);
2035
2036
18
    Id resultId = c->getResultId();
2037
18
    if (!specConstant) {
2038
18
        ScalarConstantKey key{ enumCast(Op::OpTypeFloat), enumCast(opcode), typeId, op1, op2 };
2039
18
        groupedScalarConstantResultIDs[key] = resultId;
2040
18
    }
2041
18
    return resultId;
2042
18
}
2043
2044
Id Builder::makeFloat16Constant(float f16, bool specConstant)
2045
846
{
2046
846
    Op opcode = specConstant ? Op::OpSpecConstant : Op::OpConstant;
2047
846
    Id typeId = makeFloatType(16);
2048
2049
846
    spvutils::HexFloat<spvutils::FloatProxy<float>> fVal(f16);
2050
846
    spvutils::HexFloat<spvutils::FloatProxy<spvutils::Float16>> f16Val(0);
2051
846
    fVal.castTo(f16Val, spvutils::kRoundToZero);
2052
2053
846
    unsigned value = f16Val.value().getAsFloat().get_value();
2054
2055
    // See if we already made it. Applies only to regular constants, because specialization constants
2056
    // must remain distinct for the purpose of applying a SpecId decoration.
2057
846
    if (!specConstant) {
2058
846
        Id existing = findScalarConstant(Op::OpTypeFloat, opcode, typeId, value);
2059
846
        if (existing)
2060
783
            return existing;
2061
846
    }
2062
2063
63
    Instruction* c = new Instruction(getUniqueId(), typeId, opcode);
2064
63
    c->addImmediateOperand(value);
2065
63
    constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(c));
2066
63
    module.mapInstruction(c);
2067
2068
63
    Id resultId = c->getResultId();
2069
63
    if (!specConstant) {
2070
63
        ScalarConstantKey key{ enumCast(Op::OpTypeFloat), enumCast(opcode), typeId, value, 0 };
2071
63
        groupedScalarConstantResultIDs[key] = resultId;
2072
63
    }
2073
63
    return resultId;
2074
846
}
2075
2076
Id Builder::makeBFloat16Constant(float bf16, bool specConstant)
2077
0
{
2078
0
    Op opcode = specConstant ? Op::OpSpecConstant : Op::OpConstant;
2079
0
    Id typeId = makeBFloat16Type();
2080
2081
0
    union {
2082
0
        float f;
2083
0
        uint32_t u;
2084
0
    } un;
2085
0
    un.f = bf16;
2086
2087
    // take high 16b of fp32 value. This is effectively round-to-zero, other than certain NaNs.
2088
0
    unsigned value = un.u >> 16;
2089
2090
    // See if we already made it. Applies only to regular constants, because specialization constants
2091
    // must remain distinct for the purpose of applying a SpecId decoration.
2092
0
    if (!specConstant) {
2093
0
        Id existing = findScalarConstant(Op::OpTypeFloat, opcode, typeId, value);
2094
0
        if (existing)
2095
0
            return existing;
2096
0
    }
2097
2098
0
    Instruction* c = new Instruction(getUniqueId(), typeId, opcode);
2099
0
    c->addImmediateOperand(value);
2100
0
    constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(c));
2101
0
    module.mapInstruction(c);
2102
2103
0
    Id resultId = c->getResultId();
2104
0
    if (!specConstant) {
2105
0
        ScalarConstantKey key{ enumCast(Op::OpTypeFloat), enumCast(opcode), typeId, value, 0 };
2106
0
        groupedScalarConstantResultIDs[key] = resultId;
2107
0
    }
2108
0
    return resultId;
2109
0
}
2110
2111
Id Builder::makeFloatE5M2Constant(float fe5m2, bool specConstant)
2112
0
{
2113
0
    Op opcode = specConstant ? Op::OpSpecConstant : Op::OpConstant;
2114
0
    Id typeId = makeFloatE5M2Type();
2115
2116
0
    spvutils::HexFloat<spvutils::FloatProxy<float>> fVal(fe5m2);
2117
0
    spvutils::HexFloat<spvutils::FloatProxy<spvutils::FloatE5M2>> fe5m2Val(0);
2118
0
    fVal.castTo(fe5m2Val, spvutils::kRoundToZero);
2119
2120
0
    unsigned value = fe5m2Val.value().getAsFloat().get_value();
2121
2122
    // See if we already made it. Applies only to regular constants, because specialization constants
2123
    // must remain distinct for the purpose of applying a SpecId decoration.
2124
0
    if (!specConstant) {
2125
0
        Id existing = findScalarConstant(Op::OpTypeFloat, opcode, typeId, value);
2126
0
        if (existing)
2127
0
            return existing;
2128
0
    }
2129
2130
0
    Instruction* c = new Instruction(getUniqueId(), typeId, opcode);
2131
0
    c->addImmediateOperand(value);
2132
0
    constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(c));
2133
0
    module.mapInstruction(c);
2134
2135
0
    Id resultId = c->getResultId();
2136
0
    if (!specConstant) {
2137
0
        ScalarConstantKey key{enumCast(Op::OpTypeFloat), enumCast(opcode), typeId, value, 0};
2138
0
        groupedScalarConstantResultIDs[key] = resultId;
2139
0
    }
2140
0
    return resultId;
2141
0
}
2142
2143
Id Builder::makeFloatE4M3Constant(float fe4m3, bool specConstant)
2144
0
{
2145
0
    Op opcode = specConstant ? Op::OpSpecConstant : Op::OpConstant;
2146
0
    Id typeId = makeFloatE4M3Type();
2147
2148
0
    spvutils::HexFloat<spvutils::FloatProxy<float>> fVal(fe4m3);
2149
0
    spvutils::HexFloat<spvutils::FloatProxy<spvutils::FloatE4M3>> fe4m3Val(0);
2150
0
    fVal.castTo(fe4m3Val, spvutils::kRoundToZero);
2151
2152
0
    unsigned value = fe4m3Val.value().getAsFloat().get_value();
2153
2154
    // See if we already made it. Applies only to regular constants, because specialization constants
2155
    // must remain distinct for the purpose of applying a SpecId decoration.
2156
0
    if (!specConstant) {
2157
0
        Id existing = findScalarConstant(Op::OpTypeFloat, opcode, typeId, value);
2158
0
        if (existing)
2159
0
            return existing;
2160
0
    }
2161
2162
0
    Instruction* c = new Instruction(getUniqueId(), typeId, opcode);
2163
0
    c->addImmediateOperand(value);
2164
0
    constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(c));
2165
0
    module.mapInstruction(c);
2166
2167
0
    Id resultId = c->getResultId();
2168
0
    if (!specConstant) {
2169
0
        ScalarConstantKey key{enumCast(Op::OpTypeFloat), enumCast(opcode), typeId, value, 0};
2170
0
        groupedScalarConstantResultIDs[key] = resultId;
2171
0
    }
2172
0
    return resultId;
2173
0
}
2174
2175
Id Builder::makeFpConstant(Id type, double d, bool specConstant)
2176
0
{
2177
0
    const int width = getScalarTypeWidth(type);
2178
2179
0
    assert(isFloatType(type));
2180
2181
0
    switch (width) {
2182
0
    case 16:
2183
0
            return makeFloat16Constant((float)d, specConstant);
2184
0
    case 32:
2185
0
            return makeFloatConstant((float)d, specConstant);
2186
0
    case 64:
2187
0
            return makeDoubleConstant(d, specConstant);
2188
0
    default:
2189
0
            break;
2190
0
    }
2191
2192
0
    assert(false);
2193
0
    return NoResult;
2194
0
}
2195
2196
Id Builder::importNonSemanticShaderDebugInfoInstructions()
2197
0
{
2198
0
    assert(emitNonSemanticShaderDebugInfo == true);
2199
2200
0
    if(nonSemanticShaderDebugInfo == 0)
2201
0
    {
2202
0
        this->addExtension(spv::E_SPV_KHR_non_semantic_info);
2203
        // Create the import instruction directly so we can save a pointer for later
2204
        // patching by requireNonSemanticShaderDebugInfoVersion().
2205
0
        std::string importName = "NonSemantic.Shader.DebugInfo." + std::to_string(nonSemanticShaderDebugInfoVersion);
2206
0
        auto* importInst = new Instruction(getUniqueId(), NoType, Op::OpExtInstImport);
2207
0
        importInst->addStringOperand(importName.c_str());
2208
0
        module.mapInstruction(importInst);
2209
0
        imports.push_back(std::unique_ptr<Instruction>(importInst));
2210
0
        nonSemanticShaderDebugInfo = importInst->getResultId();
2211
0
        nonSemanticShaderDebugInfoImportInst = importInst;
2212
0
    }
2213
2214
0
    return nonSemanticShaderDebugInfo;
2215
0
}
2216
2217
void Builder::requireNonSemanticShaderDebugInfoVersion(unsigned version)
2218
0
{
2219
0
    if (nonSemanticShaderDebugInfoVersion >= version)
2220
0
        return;
2221
0
    nonSemanticShaderDebugInfoVersion = version;
2222
0
    if (nonSemanticShaderDebugInfoImportInst != nullptr) {
2223
        // The import instruction was already emitted with an older version string.
2224
        // Rebuild the string operands in place so all referencing OpExtInst instructions
2225
        // automatically pick up the new name without needing new IDs.
2226
0
        std::string importName = "NonSemantic.Shader.DebugInfo." + std::to_string(version);
2227
0
        nonSemanticShaderDebugInfoImportInst->clearOperands();
2228
0
        nonSemanticShaderDebugInfoImportInst->addStringOperand(importName.c_str());
2229
0
    }
2230
0
}
2231
2232
Id Builder::findCompositeConstant(Op typeClass, Op opcode, Id typeId, const std::vector<Id>& comps, size_t numMembers)
2233
4.81k
{
2234
4.81k
    Instruction* constant = nullptr;
2235
4.81k
    bool found = false;
2236
33.7k
    for (int i = 0; i < (int)groupedCompositeConstants[enumCast(typeClass)].size(); ++i) {
2237
32.7k
        constant = groupedCompositeConstants[enumCast(typeClass)][i];
2238
2239
32.7k
        if (constant->getTypeId() != typeId)
2240
28.0k
            continue;
2241
2242
4.71k
        if (constant->getOpCode() != opcode) {
2243
0
            continue;
2244
0
        }
2245
2246
4.71k
        if (constant->getNumOperands() != (int)numMembers)
2247
0
            continue;
2248
2249
        // same contents?
2250
4.71k
        bool mismatch = false;
2251
15.5k
        for (int op = 0; op < constant->getNumOperands(); ++op) {
2252
11.7k
            if (constant->getIdOperand(op) != comps[op]) {
2253
896
                mismatch = true;
2254
896
                break;
2255
896
            }
2256
11.7k
        }
2257
4.71k
        if (! mismatch) {
2258
3.82k
            found = true;
2259
3.82k
            break;
2260
3.82k
        }
2261
4.71k
    }
2262
2263
4.81k
    return found ? constant->getResultId() : NoResult;
2264
4.81k
}
2265
2266
Id Builder::findStructConstant(Id typeId, const std::vector<Id>& comps)
2267
216
{
2268
216
    Instruction* constant = nullptr;
2269
216
    bool found = false;
2270
549
    for (int i = 0; i < (int)groupedStructConstants[typeId].size(); ++i) {
2271
378
        constant = groupedStructConstants[typeId][i];
2272
2273
        // same contents?
2274
378
        bool mismatch = false;
2275
468
        for (int op = 0; op < constant->getNumOperands(); ++op) {
2276
423
            if (constant->getIdOperand(op) != comps[op]) {
2277
333
                mismatch = true;
2278
333
                break;
2279
333
            }
2280
423
        }
2281
378
        if (! mismatch) {
2282
45
            found = true;
2283
45
            break;
2284
45
        }
2285
378
    }
2286
2287
216
    return found ? constant->getResultId() : NoResult;
2288
216
}
2289
2290
// Comments in header
2291
Id Builder::makeCompositeConstant(Id typeId, const std::vector<Id>& members, bool specConstant)
2292
5.02k
{
2293
5.02k
    assert(typeId);
2294
5.02k
    Op typeClass = getTypeClass(typeId);
2295
2296
5.02k
    bool replicate = false;
2297
5.02k
    size_t numMembers = members.size();
2298
5.02k
    if (useReplicatedComposites || typeClass == Op::OpTypeCooperativeVectorNV) {
2299
        // use replicate if all members are the same
2300
0
        replicate = numMembers > 0 &&
2301
0
            std::equal(members.begin() + 1, members.end(), members.begin());
2302
2303
0
        if (replicate) {
2304
0
            numMembers = 1;
2305
0
            addCapability(spv::Capability::ReplicatedCompositesEXT);
2306
0
            addExtension(spv::E_SPV_EXT_replicated_composites);
2307
0
        }
2308
0
    }
2309
2310
5.02k
    Op opcode = replicate ?
2311
0
        (specConstant ? Op::OpSpecConstantCompositeReplicateEXT : Op::OpConstantCompositeReplicateEXT) :
2312
5.02k
        (specConstant ? Op::OpSpecConstantComposite : Op::OpConstantComposite);
2313
2314
5.02k
    switch (typeClass) {
2315
4.61k
    case Op::OpTypeVector:
2316
4.73k
    case Op::OpTypeArray:
2317
4.81k
    case Op::OpTypeMatrix:
2318
4.81k
    case Op::OpTypeCooperativeMatrixKHR:
2319
4.81k
    case Op::OpTypeCooperativeMatrixNV:
2320
4.81k
    case Op::OpTypeCooperativeVectorNV:
2321
4.81k
        if (! specConstant) {
2322
4.81k
            Id existing = findCompositeConstant(typeClass, opcode, typeId, members, numMembers);
2323
4.81k
            if (existing)
2324
3.82k
                return existing;
2325
4.81k
        }
2326
987
        break;
2327
987
    case Op::OpTypeStruct:
2328
216
        if (! specConstant) {
2329
216
            Id existing = findStructConstant(typeId, members);
2330
216
            if (existing)
2331
45
                return existing;
2332
216
        }
2333
171
        break;
2334
171
    default:
2335
0
        assert(0);
2336
0
        return makeFloatConstant(0.0);
2337
5.02k
    }
2338
2339
1.15k
    Instruction* c = new Instruction(getUniqueId(), typeId, opcode);
2340
1.15k
    c->reserveOperands(members.size());
2341
4.34k
    for (size_t op = 0; op < numMembers; ++op)
2342
3.18k
        c->addIdOperand(members[op]);
2343
1.15k
    constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(c));
2344
1.15k
    if (typeClass == Op::OpTypeStruct)
2345
171
        groupedStructConstants[typeId].push_back(c);
2346
987
    else
2347
987
        groupedCompositeConstants[enumCast(typeClass)].push_back(c);
2348
1.15k
    module.mapInstruction(c);
2349
2350
1.15k
    return c->getResultId();
2351
5.02k
}
2352
2353
Instruction* Builder::addEntryPoint(ExecutionModel model, Function* function, const char* name)
2354
442
{
2355
442
    Instruction* entryPoint = new Instruction(Op::OpEntryPoint);
2356
442
    entryPoint->reserveOperands(3);
2357
442
    entryPoint->addImmediateOperand(model);
2358
442
    entryPoint->addIdOperand(function->getId());
2359
442
    entryPoint->addStringOperand(name);
2360
2361
442
    entryPoints.push_back(std::unique_ptr<Instruction>(entryPoint));
2362
2363
442
    return entryPoint;
2364
442
}
2365
2366
// Currently relying on the fact that all 'value' of interest are small non-negative values.
2367
void Builder::addExecutionMode(Function* entryPoint, ExecutionMode mode, int value1, int value2, int value3)
2368
31
{
2369
    // entryPoint can be null if we are in compile-only mode
2370
31
    if (!entryPoint)
2371
0
        return;
2372
2373
31
    Instruction* instr = new Instruction(Op::OpExecutionMode);
2374
31
    instr->reserveOperands(3);
2375
31
    instr->addIdOperand(entryPoint->getId());
2376
31
    instr->addImmediateOperand(mode);
2377
31
    if (value1 >= 0)
2378
0
        instr->addImmediateOperand(value1);
2379
31
    if (value2 >= 0)
2380
0
        instr->addImmediateOperand(value2);
2381
31
    if (value3 >= 0)
2382
0
        instr->addImmediateOperand(value3);
2383
2384
31
    executionModes.push_back(std::unique_ptr<Instruction>(instr));
2385
31
}
2386
2387
void Builder::addExecutionMode(Function* entryPoint, ExecutionMode mode, const std::vector<unsigned>& literals)
2388
0
{
2389
    // entryPoint can be null if we are in compile-only mode
2390
0
    if (!entryPoint)
2391
0
        return;
2392
2393
0
    Instruction* instr = new Instruction(Op::OpExecutionMode);
2394
0
    instr->reserveOperands(literals.size() + 2);
2395
0
    instr->addIdOperand(entryPoint->getId());
2396
0
    instr->addImmediateOperand(mode);
2397
0
    for (auto literal : literals)
2398
0
        instr->addImmediateOperand(literal);
2399
2400
0
    executionModes.push_back(std::unique_ptr<Instruction>(instr));
2401
0
}
2402
2403
void Builder::addExecutionModeId(Function* entryPoint, ExecutionMode mode, const std::vector<Id>& operandIds)
2404
0
{
2405
    // entryPoint can be null if we are in compile-only mode
2406
0
    if (!entryPoint)
2407
0
        return;
2408
2409
0
    Instruction* instr = new Instruction(Op::OpExecutionModeId);
2410
0
    instr->reserveOperands(operandIds.size() + 2);
2411
0
    instr->addIdOperand(entryPoint->getId());
2412
0
    instr->addImmediateOperand(mode);
2413
0
    for (auto operandId : operandIds)
2414
0
        instr->addIdOperand(operandId);
2415
2416
0
    executionModes.push_back(std::unique_ptr<Instruction>(instr));
2417
0
}
2418
2419
void Builder::addName(Id id, const char* string)
2420
8.94k
{
2421
8.94k
    Instruction* name = new Instruction(Op::OpName);
2422
8.94k
    name->reserveOperands(2);
2423
8.94k
    name->addIdOperand(id);
2424
8.94k
    name->addStringOperand(string);
2425
2426
8.94k
    names.push_back(std::unique_ptr<Instruction>(name));
2427
8.94k
}
2428
2429
void Builder::addMemberName(Id id, int memberNumber, const char* string)
2430
2.60k
{
2431
2.60k
    Instruction* name = new Instruction(Op::OpMemberName);
2432
2.60k
    name->reserveOperands(3);
2433
2.60k
    name->addIdOperand(id);
2434
2.60k
    name->addImmediateOperand(memberNumber);
2435
2.60k
    name->addStringOperand(string);
2436
2437
2.60k
    names.push_back(std::unique_ptr<Instruction>(name));
2438
2.60k
}
2439
2440
void Builder::addDecoration(Id id, Decoration decoration, int num)
2441
99.3k
{
2442
99.3k
    if (decoration == spv::Decoration::Max)
2443
92.6k
        return;
2444
2445
6.71k
    Instruction* dec = new Instruction(Op::OpDecorate);
2446
6.71k
    dec->reserveOperands(2);
2447
6.71k
    dec->addIdOperand(id);
2448
6.71k
    dec->addImmediateOperand(decoration);
2449
6.71k
    if (num >= 0)
2450
4.51k
        dec->addImmediateOperand(num);
2451
2452
6.71k
    decorations.insert(std::unique_ptr<Instruction>(dec));
2453
6.71k
}
2454
2455
void Builder::addDecoration(Id id, Decoration decoration, const char* s)
2456
0
{
2457
0
    if (decoration == spv::Decoration::Max)
2458
0
        return;
2459
2460
0
    Instruction* dec = new Instruction(Op::OpDecorateString);
2461
0
    dec->reserveOperands(3);
2462
0
    dec->addIdOperand(id);
2463
0
    dec->addImmediateOperand(decoration);
2464
0
    dec->addStringOperand(s);
2465
2466
0
    decorations.insert(std::unique_ptr<Instruction>(dec));
2467
0
}
2468
2469
void Builder::addDecoration(Id id, Decoration decoration, const std::vector<unsigned>& literals)
2470
126
{
2471
126
    if (decoration == spv::Decoration::Max)
2472
0
        return;
2473
2474
126
    Instruction* dec = new Instruction(Op::OpDecorate);
2475
126
    dec->reserveOperands(literals.size() + 2);
2476
126
    dec->addIdOperand(id);
2477
126
    dec->addImmediateOperand(decoration);
2478
126
    for (auto literal : literals)
2479
126
        dec->addImmediateOperand(literal);
2480
2481
126
    decorations.insert(std::unique_ptr<Instruction>(dec));
2482
126
}
2483
2484
void Builder::addDecoration(Id id, Decoration decoration, const std::vector<const char*>& strings)
2485
0
{
2486
0
    if (decoration == spv::Decoration::Max)
2487
0
        return;
2488
2489
0
    Instruction* dec = new Instruction(Op::OpDecorateString);
2490
0
    dec->reserveOperands(strings.size() + 2);
2491
0
    dec->addIdOperand(id);
2492
0
    dec->addImmediateOperand(decoration);
2493
0
    for (auto string : strings)
2494
0
        dec->addStringOperand(string);
2495
2496
0
    decorations.insert(std::unique_ptr<Instruction>(dec));
2497
0
}
2498
2499
0
void Builder::addLinkageDecoration(Id id, const char* name, spv::LinkageType linkType) {
2500
0
    Instruction* dec = new Instruction(Op::OpDecorate);
2501
0
    dec->reserveOperands(4);
2502
0
    dec->addIdOperand(id);
2503
0
    dec->addImmediateOperand(spv::Decoration::LinkageAttributes);
2504
0
    dec->addStringOperand(name);
2505
0
    dec->addImmediateOperand(linkType);
2506
2507
0
    decorations.insert(std::unique_ptr<Instruction>(dec));
2508
0
}
2509
2510
void Builder::addDecorationId(Id id, Decoration decoration, Id idDecoration)
2511
0
{
2512
0
    if (decoration == spv::Decoration::Max)
2513
0
        return;
2514
2515
0
    Instruction* dec = new Instruction(Op::OpDecorateId);
2516
0
    dec->reserveOperands(3);
2517
0
    dec->addIdOperand(id);
2518
0
    dec->addImmediateOperand(decoration);
2519
0
    dec->addIdOperand(idDecoration);
2520
2521
0
    decorations.insert(std::unique_ptr<Instruction>(dec));
2522
0
}
2523
2524
void Builder::addDecorationId(Id id, Decoration decoration, const std::vector<Id>& operandIds)
2525
0
{
2526
0
    if(decoration == spv::Decoration::Max)
2527
0
        return;
2528
2529
0
    Instruction* dec = new Instruction(Op::OpDecorateId);
2530
0
    dec->reserveOperands(operandIds.size() + 2);
2531
0
    dec->addIdOperand(id);
2532
0
    dec->addImmediateOperand(decoration);
2533
2534
0
    for (auto operandId : operandIds)
2535
0
        dec->addIdOperand(operandId);
2536
2537
0
    decorations.insert(std::unique_ptr<Instruction>(dec));
2538
0
}
2539
2540
void Builder::addMemberDecorationIdEXT(Id id, unsigned int member, Decoration decoration,
2541
                                       const std::vector<unsigned>& operands)
2542
0
{
2543
0
    if (decoration == spv::Decoration::Max)
2544
0
        return;
2545
2546
0
    Instruction* dec = new Instruction(Op::OpMemberDecorateIdEXT);
2547
0
    dec->reserveOperands(operands.size() + 3);
2548
0
    dec->addIdOperand(id);
2549
0
    dec->addImmediateOperand(member);
2550
0
    dec->addImmediateOperand(decoration);
2551
0
    for (auto operand : operands)
2552
0
        dec->addIdOperand(operand);
2553
2554
0
    decorations.insert(std::unique_ptr<Instruction>(dec));
2555
0
}
2556
2557
void Builder::addMemberDecoration(Id id, unsigned int member, Decoration decoration, int num)
2558
12.6k
{
2559
12.6k
    if (decoration == spv::Decoration::Max)
2560
10.3k
        return;
2561
2562
2.30k
    Instruction* dec = new Instruction(Op::OpMemberDecorate);
2563
2.30k
    dec->reserveOperands(3);
2564
2.30k
    dec->addIdOperand(id);
2565
2.30k
    dec->addImmediateOperand(member);
2566
2.30k
    dec->addImmediateOperand(decoration);
2567
2.30k
    if (num >= 0)
2568
2.22k
        dec->addImmediateOperand(num);
2569
2570
2.30k
    decorations.insert(std::unique_ptr<Instruction>(dec));
2571
2.30k
}
2572
2573
void Builder::addMemberDecoration(Id id, unsigned int member, Decoration decoration, const char *s)
2574
0
{
2575
0
    if (decoration == spv::Decoration::Max)
2576
0
        return;
2577
2578
0
    Instruction* dec = new Instruction(Op::OpMemberDecorateStringGOOGLE);
2579
0
    dec->reserveOperands(4);
2580
0
    dec->addIdOperand(id);
2581
0
    dec->addImmediateOperand(member);
2582
0
    dec->addImmediateOperand(decoration);
2583
0
    dec->addStringOperand(s);
2584
2585
0
    decorations.insert(std::unique_ptr<Instruction>(dec));
2586
0
}
2587
2588
void Builder::addMemberDecoration(Id id, unsigned int member, Decoration decoration, const std::vector<unsigned>& literals)
2589
0
{
2590
0
    if (decoration == spv::Decoration::Max)
2591
0
        return;
2592
2593
0
    Instruction* dec = new Instruction(Op::OpMemberDecorate);
2594
0
    dec->reserveOperands(literals.size() + 3);
2595
0
    dec->addIdOperand(id);
2596
0
    dec->addImmediateOperand(member);
2597
0
    dec->addImmediateOperand(decoration);
2598
0
    for (auto literal : literals)
2599
0
        dec->addImmediateOperand(literal);
2600
2601
0
    decorations.insert(std::unique_ptr<Instruction>(dec));
2602
0
}
2603
2604
void Builder::addMemberDecoration(Id id, unsigned int member, Decoration decoration, const std::vector<const char*>& strings)
2605
0
{
2606
0
    if (decoration == spv::Decoration::Max)
2607
0
        return;
2608
2609
0
    Instruction* dec = new Instruction(Op::OpMemberDecorateString);
2610
0
    dec->reserveOperands(strings.size() + 3);
2611
0
    dec->addIdOperand(id);
2612
0
    dec->addImmediateOperand(member);
2613
0
    dec->addImmediateOperand(decoration);
2614
0
    for (auto string : strings)
2615
0
        dec->addStringOperand(string);
2616
2617
0
    decorations.insert(std::unique_ptr<Instruction>(dec));
2618
0
}
2619
2620
66.7k
void Builder::addInstruction(std::unique_ptr<Instruction> inst) {
2621
    // Phis must appear first in their block, don't insert line tracking instructions
2622
    // in front of them, just add the OpPhi and return.
2623
66.7k
    if (inst->getOpCode() == Op::OpPhi) {
2624
104
        buildPoint->addInstruction(std::move(inst));
2625
104
        return;
2626
104
    }
2627
    // Optionally insert OpDebugScope
2628
66.6k
    if (emitNonSemanticShaderDebugInfo && dirtyScopeTracker) {
2629
0
        if (buildPoint->updateDebugScope(currentDebugScopeId.top())) {
2630
0
            auto scopeInst = std::make_unique<Instruction>(getUniqueId(), makeVoidType(), Op::OpExtInst);
2631
0
            scopeInst->reserveOperands(3);
2632
0
            scopeInst->addIdOperand(nonSemanticShaderDebugInfo);
2633
0
            scopeInst->addImmediateOperand(NonSemanticShaderDebugInfoDebugScope);
2634
0
            scopeInst->addIdOperand(currentDebugScopeId.top());
2635
0
            buildPoint->addInstruction(std::move(scopeInst));
2636
0
        }
2637
2638
0
        dirtyScopeTracker = false;
2639
0
    }
2640
2641
    // Insert OpLine/OpDebugLine if the debug source location has changed
2642
66.6k
    if (trackDebugInfo && dirtyLineTracker) {
2643
0
        if (buildPoint->updateDebugSourceLocation(currentLine, 0, currentFileId)) {
2644
0
            if (emitSpirvDebugInfo) {
2645
0
                auto lineInst = std::make_unique<Instruction>(Op::OpLine);
2646
0
                lineInst->reserveOperands(3);
2647
0
                lineInst->addIdOperand(currentFileId);
2648
0
                lineInst->addImmediateOperand(currentLine);
2649
0
                lineInst->addImmediateOperand(0);
2650
0
                buildPoint->addInstruction(std::move(lineInst));
2651
0
            }
2652
0
            if (emitNonSemanticShaderDebugInfo) {
2653
0
                auto lineInst = std::make_unique<Instruction>(getUniqueId(), makeVoidType(), Op::OpExtInst);
2654
0
                lineInst->reserveOperands(7);
2655
0
                lineInst->addIdOperand(nonSemanticShaderDebugInfo);
2656
0
                lineInst->addImmediateOperand(NonSemanticShaderDebugInfoDebugLine);
2657
0
                lineInst->addIdOperand(makeDebugSource(currentFileId));
2658
0
                lineInst->addIdOperand(makeUintConstant(currentLine));
2659
0
                lineInst->addIdOperand(makeUintConstant(currentLine));
2660
0
                lineInst->addIdOperand(makeUintConstant(0));
2661
0
                lineInst->addIdOperand(makeUintConstant(0));
2662
0
                buildPoint->addInstruction(std::move(lineInst));
2663
0
            }
2664
0
        }
2665
2666
0
        dirtyLineTracker = false;
2667
0
    }
2668
2669
66.6k
    buildPoint->addInstruction(std::move(inst));
2670
66.6k
}
2671
2672
4.60k
void Builder::addInstructionNoDebugInfo(std::unique_ptr<Instruction> inst) {
2673
4.60k
    buildPoint->addInstruction(std::move(inst));
2674
4.60k
}
2675
2676
// Comments in header
2677
Function* Builder::makeEntryPoint(const char* entryPoint)
2678
442
{
2679
442
    assert(! entryPointFunction);
2680
2681
442
    auto const returnType = makeVoidType();
2682
2683
442
    restoreNonSemanticShaderDebugInfo = emitNonSemanticShaderDebugInfo;
2684
442
    if(sourceLang == spv::SourceLanguage::HLSL) {
2685
0
        emitNonSemanticShaderDebugInfo = false;
2686
0
    }
2687
2688
442
    Block* entry = nullptr;
2689
442
    entryPointFunction = makeFunctionEntry(NoPrecision, returnType, entryPoint, LinkageType::Max, {}, {}, &entry);
2690
2691
442
    emitNonSemanticShaderDebugInfo = restoreNonSemanticShaderDebugInfo;
2692
2693
442
    return entryPointFunction;
2694
442
}
2695
2696
// Comments in header
2697
Function* Builder::makeFunctionEntry(Decoration precision, Id returnType, const char* name, LinkageType linkType,
2698
                                     const std::vector<Id>& paramTypes,
2699
                                     const std::vector<std::vector<Decoration>>& decorations, Block** entry)
2700
914
{
2701
    // Make the function and initial instructions in it
2702
914
    Id typeId = makeFunctionType(returnType, paramTypes);
2703
914
    Id firstParamId = paramTypes.size() == 0 ? 0 : getUniqueIds((int)paramTypes.size());
2704
914
    Id funcId = getUniqueId();
2705
914
    Function* function = new Function(funcId, returnType, typeId, firstParamId, linkType, name, module);
2706
2707
    // Set up the precisions
2708
914
    setPrecision(function->getId(), precision);
2709
914
    function->setReturnPrecision(precision);
2710
1.35k
    for (unsigned p = 0; p < (unsigned)decorations.size(); ++p) {
2711
443
        for (int d = 0; d < (int)decorations[p].size(); ++d) {
2712
0
            addDecoration(firstParamId + p, decorations[p][d]);
2713
0
            function->addParamPrecision(p, decorations[p][d]);
2714
0
        }
2715
443
    }
2716
2717
    // reset last debug scope
2718
914
    if (emitNonSemanticShaderDebugInfo) {
2719
0
        dirtyScopeTracker = true;
2720
0
    }
2721
2722
    // CFG
2723
914
    assert(entry != nullptr);
2724
914
    *entry = new Block(getUniqueId(), *function);
2725
914
    function->addBlock(*entry);
2726
914
    setBuildPoint(*entry);
2727
2728
914
    if (name)
2729
914
        addName(function->getId(), name);
2730
2731
914
    functions.push_back(std::unique_ptr<Function>(function));
2732
2733
914
    return function;
2734
914
}
2735
2736
void Builder::setupFunctionDebugInfo(Function* function, const char* name, const std::vector<Id>& paramTypes,
2737
                                     const std::vector<char const*>& paramNames)
2738
914
{
2739
2740
914
    if (!emitNonSemanticShaderDebugInfo)
2741
914
        return;
2742
2743
0
    Id nameId = getStringId(unmangleFunctionName(name));
2744
0
    Id funcTypeId = function->getFuncTypeId();
2745
0
    assert(getDebugType(funcTypeId) != NoType);
2746
0
    Id funcId = function->getId();
2747
2748
0
    assert(funcId != 0);
2749
2750
    // Make the debug function instruction
2751
0
    Id debugFuncId = makeDebugFunction(function, nameId, funcTypeId);
2752
0
    debugFuncIdLookup[funcId] = debugFuncId;
2753
0
    currentDebugScopeId.push(debugFuncId);
2754
2755
    // DebugScope and DebugLine for parameter DebugDeclares
2756
0
    assert(paramTypes.size() == paramNames.size());
2757
0
    if ((int)paramTypes.size() > 0) {
2758
0
        Id firstParamId = function->getParamId(0);
2759
2760
0
        for (size_t p = 0; p < paramTypes.size(); ++p) {
2761
0
            bool passByRef = false;
2762
0
            Id paramTypeId = paramTypes[p];
2763
2764
            // For pointer-typed parameters, they are actually passed by reference and we need unwrap the pointer to get the actual parameter type.
2765
0
            if (isPointerType(paramTypeId) || isArrayType(paramTypeId)) {
2766
0
                passByRef = true;
2767
0
                paramTypeId = getContainedTypeId(paramTypeId);
2768
0
            }
2769
2770
0
            auto const& paramName = paramNames[p];
2771
0
            auto const debugLocalVariableId = createDebugLocalVariable(getDebugType(paramTypeId), paramName, p + 1);
2772
0
            auto const paramId = static_cast<Id>(firstParamId + p);
2773
2774
0
            if (passByRef) {
2775
0
                makeDebugDeclare(debugLocalVariableId, paramId);
2776
0
            } else {
2777
0
                makeDebugValue(debugLocalVariableId, paramId);
2778
0
            }
2779
0
        }
2780
0
    }
2781
2782
    // Clear debug scope stack
2783
0
    if (emitNonSemanticShaderDebugInfo)
2784
0
        currentDebugScopeId.pop();
2785
0
}
2786
2787
Id Builder::makeDebugFunction([[maybe_unused]] Function* function, Id nameId, Id funcTypeId)
2788
0
{
2789
0
    assert(function != nullptr);
2790
0
    assert(nameId != 0);
2791
0
    assert(funcTypeId != 0);
2792
0
    assert(getDebugType(funcTypeId) != NoType);
2793
2794
0
    Id funcId = getUniqueId();
2795
0
    auto type = new Instruction(funcId, makeVoidType(), Op::OpExtInst);
2796
0
    type->reserveOperands(11);
2797
0
    type->addIdOperand(nonSemanticShaderDebugInfo);
2798
0
    type->addImmediateOperand(NonSemanticShaderDebugInfoDebugFunction);
2799
0
    type->addIdOperand(nameId);
2800
0
    type->addIdOperand(getDebugType(funcTypeId));
2801
0
    type->addIdOperand(makeDebugSource(currentFileId)); // TODO: This points to file of definition instead of declaration
2802
0
    type->addIdOperand(makeUintConstant(currentLine)); // TODO: This points to line of definition instead of declaration
2803
0
    type->addIdOperand(makeUintConstant(0)); // column
2804
0
    type->addIdOperand(makeDebugCompilationUnit()); // scope
2805
0
    type->addIdOperand(nameId); // linkage name
2806
0
    type->addIdOperand(makeUintConstant(NonSemanticShaderDebugInfoFlagIsPublic));
2807
0
    type->addIdOperand(makeUintConstant(currentLine));
2808
0
    constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(type));
2809
0
    module.mapInstruction(type);
2810
0
    return funcId;
2811
0
}
2812
2813
0
Id Builder::makeDebugLexicalBlock(uint32_t line, uint32_t column) {
2814
0
    assert(!currentDebugScopeId.empty());
2815
2816
0
    Id lexId = getUniqueId();
2817
0
    auto lex = new Instruction(lexId, makeVoidType(), Op::OpExtInst);
2818
0
    lex->reserveOperands(6);
2819
0
    lex->addIdOperand(nonSemanticShaderDebugInfo);
2820
0
    lex->addImmediateOperand(NonSemanticShaderDebugInfoDebugLexicalBlock);
2821
0
    lex->addIdOperand(makeDebugSource(currentFileId));
2822
0
    lex->addIdOperand(makeUintConstant(line));
2823
0
    lex->addIdOperand(makeUintConstant(column)); // column
2824
0
    lex->addIdOperand(currentDebugScopeId.top()); // scope
2825
0
    constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(lex));
2826
0
    module.mapInstruction(lex);
2827
0
    return lexId;
2828
0
}
2829
2830
std::string Builder::unmangleFunctionName(std::string const& name) const
2831
0
{
2832
0
    assert(name.length() > 0);
2833
2834
0
    if(name.rfind('(') != std::string::npos) {
2835
0
        return name.substr(0, name.rfind('('));
2836
0
    } else {
2837
0
        return name;
2838
0
    }
2839
0
}
2840
2841
// Comments in header
2842
void Builder::makeReturn(bool implicit, Id retVal)
2843
1.27k
{
2844
1.27k
    if (retVal) {
2845
648
        Instruction* inst = new Instruction(NoResult, NoType, Op::OpReturnValue);
2846
648
        inst->addIdOperand(retVal);
2847
648
        addInstruction(std::unique_ptr<Instruction>(inst));
2848
648
    } else
2849
624
        addInstruction(std::unique_ptr<Instruction>(new Instruction(NoResult, NoType, Op::OpReturn)));
2850
2851
1.27k
    if (! implicit)
2852
358
        createAndSetNoPredecessorBlock("post-return");
2853
1.27k
}
2854
2855
// Comments in header
2856
void Builder::enterLexicalBlock(uint32_t line, uint32_t column)
2857
0
{
2858
0
    if (!emitNonSemanticShaderDebugInfo) {
2859
0
        return;
2860
0
    }
2861
2862
    // Generate new lexical scope debug instruction
2863
0
    Id lexId = makeDebugLexicalBlock(line, column);
2864
0
    currentDebugScopeId.push(lexId);
2865
0
    dirtyScopeTracker = true;
2866
0
}
2867
2868
// Comments in header
2869
void Builder::leaveLexicalBlock()
2870
0
{
2871
0
    if (!emitNonSemanticShaderDebugInfo) {
2872
0
        return;
2873
0
    }
2874
2875
    // Pop current scope from stack and clear current scope
2876
0
    currentDebugScopeId.pop();
2877
0
    dirtyScopeTracker = true;
2878
0
}
2879
2880
// Comments in header
2881
void Builder::enterFunction(Function const* function)
2882
914
{
2883
914
    currentFunction = function;
2884
2885
    // Save and disable debugInfo for HLSL entry point function. It is a wrapper
2886
    // function with no user code in it.
2887
914
    restoreNonSemanticShaderDebugInfo = emitNonSemanticShaderDebugInfo;
2888
914
    if (sourceLang == spv::SourceLanguage::HLSL && function == entryPointFunction) {
2889
0
        emitNonSemanticShaderDebugInfo = false;
2890
0
    }
2891
2892
914
    if (emitNonSemanticShaderDebugInfo) {
2893
        // Initialize scope state
2894
0
        Id funcId = function->getFuncId();
2895
0
        Id debugFuncId = getDebugFunction(funcId);
2896
0
        currentDebugScopeId.push(debugFuncId);
2897
        // Create DebugFunctionDefinition
2898
0
        spv::Id resultId = getUniqueId();
2899
0
        Instruction* defInst = new Instruction(resultId, makeVoidType(), Op::OpExtInst);
2900
0
        defInst->reserveOperands(4);
2901
0
        defInst->addIdOperand(nonSemanticShaderDebugInfo);
2902
0
        defInst->addImmediateOperand(NonSemanticShaderDebugInfoDebugFunctionDefinition);
2903
0
        defInst->addIdOperand(debugFuncId);
2904
0
        defInst->addIdOperand(funcId);
2905
0
        addInstruction(std::unique_ptr<Instruction>(defInst));
2906
0
    }
2907
2908
914
    if (auto linkType = function->getLinkType(); linkType != LinkageType::Max) {
2909
0
        Id funcId = function->getFuncId();
2910
0
        addCapability(Capability::Linkage);
2911
0
        addLinkageDecoration(funcId, function->getExportName(), linkType);
2912
0
    }
2913
914
}
2914
2915
// Comments in header
2916
void Builder::leaveFunction()
2917
914
{
2918
914
    Block* block = buildPoint;
2919
914
    Function& function = buildPoint->getParent();
2920
914
    assert(block);
2921
2922
    // If our function did not contain a return, add a return void now.
2923
914
    if (! block->isTerminated()) {
2924
914
        if (function.getReturnType() == makeVoidType())
2925
590
            makeReturn(true);
2926
324
        else {
2927
324
            makeReturn(true, createUndefined(function.getReturnType()));
2928
324
        }
2929
914
    }
2930
2931
    // Clear function scope from debug scope stack
2932
914
    if (emitNonSemanticShaderDebugInfo)
2933
0
        currentDebugScopeId.pop();
2934
2935
914
    emitNonSemanticShaderDebugInfo = restoreNonSemanticShaderDebugInfo;
2936
2937
    // Clear current function record
2938
914
    currentFunction = nullptr;
2939
914
}
2940
2941
// Comments in header
2942
void Builder::makeStatementTerminator(spv::Op opcode, const char *name)
2943
0
{
2944
0
    addInstruction(std::unique_ptr<Instruction>(new Instruction(opcode)));
2945
0
    createAndSetNoPredecessorBlock(name);
2946
0
}
2947
2948
// Comments in header
2949
void Builder::makeStatementTerminator(spv::Op opcode, const std::vector<Id>& operands, const char* name)
2950
0
{
2951
    // It's assumed that the terminator instruction is always of void return type
2952
    // However in future if there is a need for non void return type, new helper
2953
    // methods can be created.
2954
0
    createNoResultOp(opcode, operands);
2955
0
    createAndSetNoPredecessorBlock(name);
2956
0
}
2957
2958
void Builder::createConstVariable(Id type, const char* name, Id constant, bool isGlobal)
2959
758
{
2960
758
    if (emitNonSemanticShaderDebugInfo) {
2961
0
        Id debugType = getDebugType(type);
2962
0
        if (isGlobal) {
2963
0
            createDebugGlobalVariable(debugType, name, constant);
2964
0
        }
2965
0
        else {
2966
0
            auto debugLocal = createDebugLocalVariable(debugType, name);
2967
0
            makeDebugValue(debugLocal, constant);
2968
0
        }
2969
0
    }
2970
758
}
2971
2972
// Comments in header
2973
Id Builder::createUntypedVariable(Decoration precision, StorageClass storageClass, const char* name, Id dataType,
2974
                                  Id initializer)
2975
0
{
2976
0
    Id resultUntypedPointerType = makeUntypedPointer(storageClass);
2977
0
    Instruction* inst = new Instruction(getUniqueId(), resultUntypedPointerType, Op::OpUntypedVariableKHR);
2978
0
    inst->addImmediateOperand(storageClass);
2979
0
    if (dataType != NoResult) {
2980
0
        Id dataPointerType = makePointer(storageClass, dataType);
2981
0
        inst->addIdOperand(dataPointerType);
2982
0
    }
2983
0
    if (initializer != NoResult)
2984
0
        inst->addIdOperand(initializer);
2985
2986
0
    switch (storageClass) {
2987
0
    case StorageClass::Function:
2988
        // Validation rules require the declaration in the entry block
2989
0
        buildPoint->getParent().addLocalVariable(std::unique_ptr<Instruction>(inst));
2990
0
        break;
2991
0
    default:
2992
0
        constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(inst));
2993
0
        module.mapInstruction(inst);
2994
0
        break;
2995
0
    }
2996
2997
0
    if (name)
2998
0
        addName(inst->getResultId(), name);
2999
0
    setPrecision(inst->getResultId(), precision);
3000
3001
0
    return inst->getResultId();
3002
0
}
3003
3004
// Comments in header
3005
Id Builder::createVariable(Decoration precision, StorageClass storageClass, Id type, const char* name, Id initializer,
3006
    bool const compilerGenerated)
3007
6.06k
{
3008
6.06k
    Id pointerType = makePointer(storageClass, type);
3009
6.06k
    Instruction* inst = new Instruction(getUniqueId(), pointerType, Op::OpVariable);
3010
6.06k
    inst->addImmediateOperand(storageClass);
3011
6.06k
    if (initializer != NoResult)
3012
0
        inst->addIdOperand(initializer);
3013
3014
6.06k
    if (storageClass == StorageClass::Function) {
3015
        // Validation rules require the declaration in the entry block
3016
3.31k
        buildPoint->getParent().addLocalVariable(std::unique_ptr<Instruction>(inst));
3017
3.31k
    }
3018
2.74k
    else {
3019
2.74k
        constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(inst));
3020
2.74k
        module.mapInstruction(inst);
3021
2.74k
    }
3022
3023
6.06k
    if (emitNonSemanticShaderDebugInfo && !compilerGenerated)
3024
0
    {
3025
        // For debug info, we prefer respecting how the variable is declared in source code.
3026
        // We may emulate some local variables as global variable with private storage in SPIR-V, but we still want to
3027
        // treat them as local variables in debug info.
3028
0
        if (storageClass == StorageClass::Function || (currentFunction && storageClass == StorageClass::Private)) {
3029
0
            auto const debugLocalVariableId = createDebugLocalVariable(getDebugType(type), name);
3030
0
            makeDebugDeclare(debugLocalVariableId, inst->getResultId());
3031
0
        }
3032
0
        else {
3033
0
            createDebugGlobalVariable(getDebugType(type), name, inst->getResultId());
3034
0
        }
3035
0
    }
3036
3037
6.06k
    if (name)
3038
6.05k
        addName(inst->getResultId(), name);
3039
6.06k
    setPrecision(inst->getResultId(), precision);
3040
3041
6.06k
    return inst->getResultId();
3042
6.06k
}
3043
3044
// Comments in header
3045
Id Builder::createUndefined(Id type)
3046
324
{
3047
324
  Instruction* inst = new Instruction(getUniqueId(), type, Op::OpUndef);
3048
324
  addInstruction(std::unique_ptr<Instruction>(inst));
3049
324
  return inst->getResultId();
3050
324
}
3051
3052
// av/vis/nonprivate are unnecessary and illegal for some storage classes.
3053
spv::MemoryAccessMask Builder::sanitizeMemoryAccessForStorageClass(spv::MemoryAccessMask memoryAccess, StorageClass sc)
3054
    const
3055
29.2k
{
3056
29.2k
    switch (sc) {
3057
5.77k
    case spv::StorageClass::Uniform:
3058
5.77k
    case spv::StorageClass::Workgroup:
3059
5.79k
    case spv::StorageClass::StorageBuffer:
3060
5.86k
    case spv::StorageClass::PhysicalStorageBufferEXT:
3061
5.86k
        break;
3062
23.4k
    default:
3063
23.4k
        memoryAccess = spv::MemoryAccessMask(memoryAccess &
3064
23.4k
                        ~(spv::MemoryAccessMask::MakePointerAvailableKHR |
3065
23.4k
                          spv::MemoryAccessMask::MakePointerVisibleKHR |
3066
23.4k
                          spv::MemoryAccessMask::NonPrivatePointerKHR));
3067
23.4k
        break;
3068
29.2k
    }
3069
29.2k
    return memoryAccess;
3070
29.2k
}
3071
3072
// Comments in header
3073
void Builder::createStore(Id rValue, Id lValue, spv::MemoryAccessMask memoryAccess, spv::Scope scope,
3074
    unsigned int alignment)
3075
10.4k
{
3076
10.4k
    Instruction* store = nullptr;
3077
10.4k
    if (isUntypedPointer(lValue))
3078
0
        store = createDescHeapLoadStoreBaseRemap(lValue, Op::OpStore);
3079
10.4k
    else {
3080
10.4k
        store = new Instruction(Op::OpStore);
3081
10.4k
        store->reserveOperands(2);
3082
10.4k
        store->addIdOperand(lValue);
3083
10.4k
    }
3084
10.4k
    store->addIdOperand(rValue);
3085
3086
10.4k
    memoryAccess = sanitizeMemoryAccessForStorageClass(memoryAccess, getStorageClass(lValue));
3087
3088
10.4k
    if (memoryAccess != MemoryAccessMask::MaskNone) {
3089
54
        store->addImmediateOperand(memoryAccess);
3090
54
        if (anySet(memoryAccess, spv::MemoryAccessMask::Aligned)) {
3091
54
            store->addImmediateOperand(alignment);
3092
54
        }
3093
54
        if (anySet(memoryAccess, spv::MemoryAccessMask::MakePointerAvailableKHR)) {
3094
0
            store->addIdOperand(makeUintConstant(scope));
3095
0
        }
3096
54
    }
3097
3098
10.4k
    addInstruction(std::unique_ptr<Instruction>(store));
3099
10.4k
}
3100
3101
// Comments in header
3102
Id Builder::createLoad(Id lValue, spv::Decoration precision, spv::MemoryAccessMask memoryAccess,
3103
    spv::Scope scope, unsigned int alignment)
3104
18.8k
{
3105
18.8k
    Instruction* load = nullptr;
3106
18.8k
    if (isUntypedPointer(lValue))
3107
0
        load = createDescHeapLoadStoreBaseRemap(lValue, Op::OpLoad);
3108
18.8k
    else {
3109
18.8k
        load = new Instruction(getUniqueId(), getDerefTypeId(lValue), Op::OpLoad);
3110
18.8k
        load->addIdOperand(lValue);
3111
18.8k
    }
3112
3113
18.8k
    memoryAccess = sanitizeMemoryAccessForStorageClass(memoryAccess, getStorageClass(lValue));
3114
3115
18.8k
    if (memoryAccess != MemoryAccessMask::MaskNone) {
3116
18
        load->addImmediateOperand(memoryAccess);
3117
18
        if (anySet(memoryAccess, spv::MemoryAccessMask::Aligned)) {
3118
18
            load->addImmediateOperand(alignment);
3119
18
        }
3120
18
        if (anySet(memoryAccess, spv::MemoryAccessMask::MakePointerVisibleKHR)) {
3121
0
            load->addIdOperand(makeUintConstant(scope));
3122
0
        }
3123
18
    }
3124
3125
18.8k
    addInstruction(std::unique_ptr<Instruction>(load));
3126
18.8k
    setPrecision(load->getResultId(), precision);
3127
3128
18.8k
    return load->getResultId();
3129
18.8k
}
3130
3131
Instruction* Builder::createDescHeapLoadStoreBaseRemap(Id baseId, Op op)
3132
0
{
3133
    // could only be untypedAccessChain op.
3134
0
    spv::Op instOp = module.getInstruction(baseId)->getOpCode();
3135
0
    spv::Id baseVal = baseId;
3136
    // base type (from run time array)
3137
0
    spv::Id resultTy = getIdOperand(baseId, 0);
3138
    // Descriptor heap using run time array.
3139
0
    if (accessChain.descHeapInfo.descHeapStorageClass != StorageClass::Max)
3140
0
        resultTy = getIdOperand(resultTy, 0);
3141
0
    if (instOp != Op::OpUntypedAccessChainKHR) {
3142
0
        assert(false && "Not a untyped load type");
3143
0
    }
3144
3145
0
    Instruction* inst = nullptr;
3146
0
    if (op == Op::OpStore)
3147
0
        inst = new Instruction(Op::OpStore);
3148
0
    else {
3149
0
        inst = new Instruction(getUniqueId(), resultTy, Op::OpLoad);
3150
0
        accessChain.descHeapInfo.descHeapInstId.push_back(inst);
3151
0
    }
3152
0
    inst->addIdOperand(baseVal);
3153
0
    return inst;
3154
0
}
3155
3156
uint32_t Builder::isStructureHeapMember(Id id, std::vector<Id> indexChain,
3157
    unsigned int idx, spv::BuiltIn* bt, uint32_t* firstArrIndex)
3158
41.0k
{
3159
41.0k
    unsigned currentIdx = idx;
3160
    // Process types, only array types could contain no constant id operands.
3161
41.0k
    Id baseId = id;
3162
41.0k
    if (baseId == NoType)
3163
0
        return 0;
3164
41.0k
    if (isPointerType(baseId))
3165
19.2k
        baseId = getContainedTypeId(baseId);
3166
41.0k
    auto baseInst = module.getInstruction(baseId);
3167
41.0k
    if (baseInst->getOpCode() == spv::Op::OpTypeArray ||
3168
40.5k
        baseInst->getOpCode() == spv::Op::OpTypeRuntimeArray) {
3169
507
        if (firstArrIndex)
3170
0
            *firstArrIndex = currentIdx;
3171
507
        baseId = getContainedTypeId(baseId);
3172
507
        baseInst = module.getInstruction(baseId);
3173
507
        currentIdx++;
3174
507
    }
3175
41.0k
    if (currentIdx >= indexChain.size())
3176
36.9k
        return 0;
3177
    // Process index op.
3178
4.05k
    auto indexInst = module.getInstruction(indexChain[currentIdx]);
3179
4.05k
    if (indexInst->getOpCode() != spv::Op::OpConstant)
3180
0
        return 0;
3181
4.05k
    auto index = indexInst->getImmediateOperand(0);
3182
134k
    for (auto dec = decorations.begin(); dec != decorations.end(); dec++) {
3183
130k
        if (dec->get()->getOpCode() == spv::Op::OpMemberDecorate && dec->get()->getIdOperand(0) == baseId &&
3184
17.4k
            dec->get()->getImmediateOperand(1) == index &&
3185
3.83k
            dec->get()->getImmediateOperand(2) == spv::Decoration::BuiltIn &&
3186
0
            (dec->get()->getImmediateOperand(3) == (unsigned)spv::BuiltIn::ResourceHeapEXT ||
3187
0
             dec->get()->getImmediateOperand(3) == (unsigned)spv::BuiltIn::SamplerHeapEXT)) {
3188
0
            if (bt)
3189
0
                *bt = (spv::BuiltIn)dec->get()->getImmediateOperand(3);
3190
0
            return currentIdx;
3191
0
        }
3192
130k
    }
3193
    // New base.
3194
4.05k
    if (baseInst->getOpCode() == spv::Op::OpTypeStruct) {
3195
3.86k
        if (!baseInst->isIdOperand(index) || idx == indexChain.size() - 1)
3196
3.38k
            return 0;
3197
480
        return isStructureHeapMember(baseInst->getIdOperand(index), indexChain, currentIdx + 1, bt, firstArrIndex);
3198
3.86k
    }
3199
3200
184
    return 0;
3201
4.05k
}
3202
3203
// Comments in header
3204
Id Builder::createDescHeapAccessChain()
3205
0
{
3206
0
    uint32_t rsrcOffsetIdx = accessChain.descHeapInfo.structRsrcTyOffsetCount;
3207
0
    if (rsrcOffsetIdx != 0)
3208
0
        accessChain.base = accessChain.descHeapInfo.structRemappedBase;
3209
0
    Id base = accessChain.base;
3210
0
    Id baseTy = accessChain.descHeapInfo.descHeapBaseTy;
3211
0
    uint32_t explicitArrayStride = accessChain.descHeapInfo.descHeapBaseArrayStride;
3212
0
    std::vector<Id>& offsets = accessChain.indexChain;
3213
0
    uint32_t firstArrIndex = accessChain.descHeapInfo.structRsrcTyFirstArrIndex;
3214
    // both typeBufferEXT and UntypedPointer only contains storage class info.
3215
0
    StorageClass storageClass = (StorageClass)accessChain.descHeapInfo.descHeapStorageClass;
3216
    // Make the untyped access chain instruction
3217
0
    Instruction* chain = new Instruction(getUniqueId(), makeUntypedPointer(getStorageClass(base)), Op::OpUntypedAccessChainKHR);
3218
3219
0
    if (storageClass == spv::StorageClass::Uniform || storageClass == spv::StorageClass::StorageBuffer) {
3220
        // For buffer and uniform heap, split first index as heap array index
3221
        // Insert BufferPointer op and construct another access chain with following indexes.
3222
0
        Id bufferTy = makeUntypedPointer(storageClass, true);
3223
0
        Id strideId = NoResult;
3224
0
        if (explicitArrayStride == 0) {
3225
0
            strideId = createConstantSizeOfEXT(bufferTy);
3226
0
        } else {
3227
0
            strideId = makeUintConstant(explicitArrayStride);
3228
0
        }
3229
0
        Id runtimeArrTy = makeRuntimeArray(bufferTy);
3230
0
        addDecorationId(runtimeArrTy, spv::Decoration::ArrayStrideIdEXT, strideId);
3231
0
        chain->addIdOperand(runtimeArrTy);
3232
0
        chain->addIdOperand(base);
3233
        // We would only re-target current member resource directly to resource/sampler heap base.
3234
        // So the previous access chain index towards final resource type is not needed?
3235
        // In current draft, only keep the first 'array index' into last access chain index.
3236
        // As those resource can't be declared as an array, in current first draft, array index will
3237
        // be the second index. This will be refined later.
3238
0
        chain->addIdOperand(offsets[firstArrIndex]);
3239
0
        if (rsrcOffsetIdx != 0) {
3240
0
            for (uint32_t i = 0; i < rsrcOffsetIdx + 1; i++) {
3241
0
                if (rsrcOffsetIdx + i + 1 < offsets.size())
3242
0
                    offsets[i] = offsets[i + rsrcOffsetIdx + 1];
3243
0
            }
3244
0
        } else {
3245
0
            for (uint32_t i = 0; i < offsets.size() - 1; i++) {
3246
0
                offsets[i] = offsets[i + 1];
3247
0
            }
3248
0
        }
3249
0
        for (uint32_t i = 0; i < rsrcOffsetIdx + 1; i++)
3250
0
            offsets.pop_back();
3251
0
        addInstruction(std::unique_ptr<Instruction>(chain));
3252
        // Create OpBufferPointer for loading target buffer descriptor.
3253
0
        Id bufferPtrTy = makePointer(storageClass, baseTy);
3254
0
        Instruction* bufferDataPtr = new Instruction(getUniqueId(), bufferPtrTy, Op::OpBufferPointerEXT);
3255
0
        bufferDataPtr->addIdOperand(chain->getResultId());
3256
0
        addInstruction(std::unique_ptr<Instruction>(bufferDataPtr));
3257
3258
        // Form a second, typed access chain for accessing buffer data.
3259
0
        Id resultTy = baseTy;
3260
0
        for (int i = 0; i < (int)offsets.size(); ++i) {
3261
0
            if (isStructType(resultTy)) {
3262
0
                assert(isConstantScalar(offsets[i]));
3263
0
                resultTy = getContainedTypeId(resultTy, getConstantScalar(offsets[i]));
3264
0
            } else
3265
0
                resultTy = getContainedTypeId(resultTy, offsets[i]);
3266
0
        }
3267
0
        resultTy = makePointer(storageClass, resultTy);
3268
3269
0
        Instruction* bufferChain = new Instruction(getUniqueId(), resultTy, Op::OpAccessChain);
3270
0
        bufferChain->reserveOperands(offsets.size() + 1);
3271
0
        bufferChain->addIdOperand(bufferDataPtr->getResultId());
3272
0
        for (int i = 0; i < (int)offsets.size(); ++i)
3273
0
            bufferChain->addIdOperand(offsets[i]);
3274
0
        addInstruction(std::unique_ptr<Instruction>(bufferChain));
3275
0
        return bufferChain->getResultId();
3276
0
    } else {
3277
        // image/sampler heap
3278
0
        Id strideId = NoResult;
3279
0
        if (explicitArrayStride == 0) {
3280
0
            strideId = createConstantSizeOfEXT(baseTy);
3281
0
        } else {
3282
0
            strideId = makeUintConstant(explicitArrayStride);
3283
0
        }
3284
0
        Id runtimeArrTy = makeRuntimeArray(baseTy);
3285
0
        addDecorationId(runtimeArrTy, spv::Decoration::ArrayStrideIdEXT, strideId);
3286
0
        chain->addIdOperand(runtimeArrTy);
3287
0
        chain->addIdOperand(base);
3288
0
        for (int i = 0; i < (int)offsets.size(); ++i)
3289
0
            chain->addIdOperand(offsets[i]);
3290
0
        addInstruction(std::unique_ptr<Instruction>(chain));
3291
0
        return chain->getResultId();
3292
0
    }
3293
0
}
3294
3295
// Comments in header
3296
Id Builder::createAccessChain(StorageClass storageClass, Id base, const std::vector<Id>& offsets)
3297
9.23k
{
3298
    // Figure out the final resulting type.
3299
9.23k
    Id typeId = getResultingAccessChainType();
3300
9.23k
    typeId = makePointer(storageClass, typeId);
3301
3302
    // Make the instruction
3303
9.23k
    Instruction* chain = new Instruction(getUniqueId(), typeId, Op::OpAccessChain);
3304
9.23k
    chain->reserveOperands(offsets.size() + 1);
3305
9.23k
    chain->addIdOperand(base);
3306
19.3k
    for (int i = 0; i < (int)offsets.size(); ++i)
3307
10.1k
        chain->addIdOperand(offsets[i]);
3308
9.23k
    addInstruction(std::unique_ptr<Instruction>(chain));
3309
3310
9.23k
    return chain->getResultId();
3311
9.23k
}
3312
3313
Id Builder::createArrayLength(Id base, unsigned int member, unsigned int bits)
3314
0
{
3315
0
    spv::Id intType = makeUintType(bits);
3316
0
    Instruction* length = new Instruction(getUniqueId(), intType, Op::OpArrayLength);
3317
0
    length->reserveOperands(2);
3318
0
    length->addIdOperand(base);
3319
0
    length->addImmediateOperand(member);
3320
0
    addInstruction(std::unique_ptr<Instruction>(length));
3321
3322
0
    return length->getResultId();
3323
0
}
3324
3325
Id Builder::createCooperativeMatrixLengthKHR(Id type)
3326
0
{
3327
0
    spv::Id intType = makeUintType(32);
3328
3329
    // Generate code for spec constants if in spec constant operation
3330
    // generation mode.
3331
0
    if (generatingOpCodeForSpecConst) {
3332
0
        return createSpecConstantOp(Op::OpCooperativeMatrixLengthKHR, intType, std::vector<Id>(1, type), std::vector<Id>());
3333
0
    }
3334
3335
0
    Instruction* length = new Instruction(getUniqueId(), intType, Op::OpCooperativeMatrixLengthKHR);
3336
0
    length->addIdOperand(type);
3337
0
    addInstruction(std::unique_ptr<Instruction>(length));
3338
3339
0
    return length->getResultId();
3340
0
}
3341
3342
Id Builder::createCooperativeMatrixLengthNV(Id type)
3343
0
{
3344
0
    spv::Id intType = makeUintType(32);
3345
3346
    // Generate code for spec constants if in spec constant operation
3347
    // generation mode.
3348
0
    if (generatingOpCodeForSpecConst) {
3349
0
        return createSpecConstantOp(Op::OpCooperativeMatrixLengthNV, intType, std::vector<Id>(1, type), std::vector<Id>());
3350
0
    }
3351
3352
0
    Instruction* length = new Instruction(getUniqueId(), intType, Op::OpCooperativeMatrixLengthNV);
3353
0
    length->addIdOperand(type);
3354
0
    addInstruction(std::unique_ptr<Instruction>(length));
3355
3356
0
    return length->getResultId();
3357
0
}
3358
3359
Id Builder::createCompositeExtract(Id composite, Id typeId, unsigned index)
3360
2.36k
{
3361
    // Generate code for spec constants if in spec constant operation
3362
    // generation mode.
3363
2.36k
    if (generatingOpCodeForSpecConst) {
3364
0
        return createSpecConstantOp(Op::OpCompositeExtract, typeId, std::vector<Id>(1, composite),
3365
0
            std::vector<Id>(1, index));
3366
0
    }
3367
2.36k
    Instruction* extract = new Instruction(getUniqueId(), typeId, Op::OpCompositeExtract);
3368
2.36k
    extract->reserveOperands(2);
3369
2.36k
    extract->addIdOperand(composite);
3370
2.36k
    extract->addImmediateOperand(index);
3371
2.36k
    addInstruction(std::unique_ptr<Instruction>(extract));
3372
3373
2.36k
    return extract->getResultId();
3374
2.36k
}
3375
3376
Id Builder::createCompositeExtract(Id composite, Id typeId, const std::vector<unsigned>& indexes)
3377
653
{
3378
    // Generate code for spec constants if in spec constant operation
3379
    // generation mode.
3380
653
    if (generatingOpCodeForSpecConst) {
3381
0
        return createSpecConstantOp(Op::OpCompositeExtract, typeId, std::vector<Id>(1, composite), indexes);
3382
0
    }
3383
653
    Instruction* extract = new Instruction(getUniqueId(), typeId, Op::OpCompositeExtract);
3384
653
    extract->reserveOperands(indexes.size() + 1);
3385
653
    extract->addIdOperand(composite);
3386
1.38k
    for (int i = 0; i < (int)indexes.size(); ++i)
3387
734
        extract->addImmediateOperand(indexes[i]);
3388
653
    addInstruction(std::unique_ptr<Instruction>(extract));
3389
3390
653
    return extract->getResultId();
3391
653
}
3392
3393
Id Builder::createCompositeInsert(Id object, Id composite, Id typeId, unsigned index)
3394
80
{
3395
80
    Instruction* insert = new Instruction(getUniqueId(), typeId, Op::OpCompositeInsert);
3396
80
    insert->reserveOperands(3);
3397
80
    insert->addIdOperand(object);
3398
80
    insert->addIdOperand(composite);
3399
80
    insert->addImmediateOperand(index);
3400
80
    addInstruction(std::unique_ptr<Instruction>(insert));
3401
3402
80
    return insert->getResultId();
3403
80
}
3404
3405
Id Builder::createCompositeInsert(Id object, Id composite, Id typeId, const std::vector<unsigned>& indexes)
3406
0
{
3407
0
    Instruction* insert = new Instruction(getUniqueId(), typeId, Op::OpCompositeInsert);
3408
0
    insert->reserveOperands(indexes.size() + 2);
3409
0
    insert->addIdOperand(object);
3410
0
    insert->addIdOperand(composite);
3411
0
    for (int i = 0; i < (int)indexes.size(); ++i)
3412
0
        insert->addImmediateOperand(indexes[i]);
3413
0
    addInstruction(std::unique_ptr<Instruction>(insert));
3414
3415
0
    return insert->getResultId();
3416
0
}
3417
3418
Id Builder::createVectorExtractDynamic(Id vector, Id typeId, Id componentIndex)
3419
0
{
3420
0
    Instruction* extract = new Instruction(getUniqueId(), typeId, Op::OpVectorExtractDynamic);
3421
0
    extract->reserveOperands(2);
3422
0
    extract->addIdOperand(vector);
3423
0
    extract->addIdOperand(componentIndex);
3424
0
    addInstruction(std::unique_ptr<Instruction>(extract));
3425
3426
0
    return extract->getResultId();
3427
0
}
3428
3429
Id Builder::createVectorInsertDynamic(Id vector, Id typeId, Id component, Id componentIndex)
3430
0
{
3431
0
    Instruction* insert = new Instruction(getUniqueId(), typeId, Op::OpVectorInsertDynamic);
3432
0
    insert->reserveOperands(3);
3433
0
    insert->addIdOperand(vector);
3434
0
    insert->addIdOperand(component);
3435
0
    insert->addIdOperand(componentIndex);
3436
0
    addInstruction(std::unique_ptr<Instruction>(insert));
3437
3438
0
    return insert->getResultId();
3439
0
}
3440
3441
// An opcode that has no operands, no result id, and no type
3442
void Builder::createNoResultOp(Op opCode)
3443
0
{
3444
0
    Instruction* op = new Instruction(opCode);
3445
0
    addInstruction(std::unique_ptr<Instruction>(op));
3446
0
}
3447
3448
// An opcode that has one id operand, no result id, and no type
3449
void Builder::createNoResultOp(Op opCode, Id operand)
3450
111
{
3451
111
    Instruction* op = new Instruction(opCode);
3452
111
    op->addIdOperand(operand);
3453
111
    addInstruction(std::unique_ptr<Instruction>(op));
3454
111
}
3455
3456
// An opcode that has one or more operands, no result id, and no type
3457
void Builder::createNoResultOp(Op opCode, const std::vector<Id>& operands)
3458
100
{
3459
100
    Instruction* op = new Instruction(opCode);
3460
100
    op->reserveOperands(operands.size());
3461
474
    for (auto id : operands) {
3462
474
        op->addIdOperand(id);
3463
474
    }
3464
100
    addInstruction(std::unique_ptr<Instruction>(op));
3465
100
}
3466
3467
// An opcode that has multiple operands, no result id, and no type
3468
void Builder::createNoResultOp(Op opCode, const std::vector<IdImmediate>& operands)
3469
134
{
3470
134
    Instruction* op = new Instruction(opCode);
3471
134
    op->reserveOperands(operands.size());
3472
646
    for (auto it = operands.cbegin(); it != operands.cend(); ++it) {
3473
512
        if (it->isId)
3474
457
            op->addIdOperand(it->word);
3475
55
        else
3476
55
            op->addImmediateOperand(it->word);
3477
512
    }
3478
134
    addInstruction(std::unique_ptr<Instruction>(op));
3479
134
}
3480
3481
void Builder::createControlBarrier(Scope execution, Scope memory, MemorySemanticsMask semantics)
3482
0
{
3483
0
    Instruction* op = new Instruction(Op::OpControlBarrier);
3484
0
    op->reserveOperands(3);
3485
0
    op->addIdOperand(makeUintConstant(execution));
3486
0
    op->addIdOperand(makeUintConstant(memory));
3487
0
    op->addIdOperand(makeUintConstant(semantics));
3488
0
    addInstruction(std::unique_ptr<Instruction>(op));
3489
0
}
3490
3491
void Builder::createMemoryBarrier(Scope executionScope, MemorySemanticsMask memorySemantics)
3492
0
{
3493
0
    Instruction* op = new Instruction(Op::OpMemoryBarrier);
3494
0
    op->reserveOperands(2);
3495
0
    op->addIdOperand(makeUintConstant((unsigned)executionScope));
3496
0
    op->addIdOperand(makeUintConstant((unsigned)memorySemantics));
3497
0
    addInstruction(std::unique_ptr<Instruction>(op));
3498
0
}
3499
3500
// An opcode that has one operands, a result id, and a type
3501
Id Builder::createUnaryOp(Op opCode, Id typeId, Id operand)
3502
3.26k
{
3503
    // Generate code for spec constants if in spec constant operation
3504
    // generation mode.
3505
3.26k
    if (generatingOpCodeForSpecConst) {
3506
264
        return createSpecConstantOp(opCode, typeId, std::vector<Id>(1, operand), std::vector<Id>());
3507
264
    }
3508
3.00k
    Instruction* op = new Instruction(getUniqueId(), typeId, opCode);
3509
3.00k
    op->addIdOperand(operand);
3510
3.00k
    addInstruction(std::unique_ptr<Instruction>(op));
3511
3512
3.00k
    return op->getResultId();
3513
3.26k
}
3514
3515
Id Builder::createBinOp(Op opCode, Id typeId, Id left, Id right)
3516
7.12k
{
3517
    // Generate code for spec constants if in spec constant operation
3518
    // generation mode.
3519
7.12k
    if (generatingOpCodeForSpecConst) {
3520
245
        std::vector<Id> operands(2);
3521
245
        operands[0] = left; operands[1] = right;
3522
245
        return createSpecConstantOp(opCode, typeId, operands, std::vector<Id>());
3523
245
    }
3524
6.88k
    Instruction* op = new Instruction(getUniqueId(), typeId, opCode);
3525
6.88k
    op->reserveOperands(2);
3526
6.88k
    op->addIdOperand(left);
3527
6.88k
    op->addIdOperand(right);
3528
6.88k
    addInstruction(std::unique_ptr<Instruction>(op));
3529
3530
6.88k
    return op->getResultId();
3531
7.12k
}
3532
3533
Id Builder::createTriOp(Op opCode, Id typeId, Id op1, Id op2, Id op3)
3534
89
{
3535
    // Generate code for spec constants if in spec constant operation
3536
    // generation mode.
3537
89
    if (generatingOpCodeForSpecConst) {
3538
50
        std::vector<Id> operands(3);
3539
50
        operands[0] = op1;
3540
50
        operands[1] = op2;
3541
50
        operands[2] = op3;
3542
50
        return createSpecConstantOp(
3543
50
            opCode, typeId, operands, std::vector<Id>());
3544
50
    }
3545
39
    Instruction* op = new Instruction(getUniqueId(), typeId, opCode);
3546
39
    op->reserveOperands(3);
3547
39
    op->addIdOperand(op1);
3548
39
    op->addIdOperand(op2);
3549
39
    op->addIdOperand(op3);
3550
39
    addInstruction(std::unique_ptr<Instruction>(op));
3551
3552
39
    return op->getResultId();
3553
89
}
3554
3555
Id Builder::createConstData(Op opCode, Id typeId, const std::vector<const char*> operands)
3556
0
{
3557
0
    Instruction* op = new Instruction(getUniqueId(), typeId, opCode);
3558
0
    op->reserveOperands(operands.size());
3559
0
    for (auto id : operands)
3560
0
        op->addStringOperand(id);
3561
0
    module.mapInstruction(op);
3562
0
    constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(op));
3563
3564
0
    return op->getResultId();
3565
0
}
3566
3567
Id Builder::createOp(Op opCode, Id typeId, const std::vector<Id>& operands)
3568
2.40k
{
3569
2.40k
    Instruction* op = new Instruction(getUniqueId(), typeId, opCode);
3570
2.40k
    op->reserveOperands(operands.size());
3571
2.40k
    for (auto id : operands)
3572
9.23k
        op->addIdOperand(id);
3573
2.40k
    addInstruction(std::unique_ptr<Instruction>(op));
3574
3575
2.40k
    return op->getResultId();
3576
2.40k
}
3577
3578
Id Builder::createOp(Op opCode, Id typeId, const std::vector<IdImmediate>& operands)
3579
3.04k
{
3580
3.04k
    Instruction* op = new Instruction(getUniqueId(), typeId, opCode);
3581
3.04k
    op->reserveOperands(operands.size());
3582
11.6k
    for (auto it = operands.cbegin(); it != operands.cend(); ++it) {
3583
8.63k
        if (it->isId)
3584
8.43k
            op->addIdOperand(it->word);
3585
198
        else
3586
198
            op->addImmediateOperand(it->word);
3587
8.63k
    }
3588
3.04k
    addInstruction(std::unique_ptr<Instruction>(op));
3589
3590
3.04k
    return op->getResultId();
3591
3.04k
}
3592
3593
Id Builder::createSpecConstantOp(Op opCode, Id typeId, const std::vector<Id>& operands,
3594
    const std::vector<unsigned>& literals)
3595
559
{
3596
559
    Instruction* op = new Instruction(getUniqueId(), typeId, Op::OpSpecConstantOp);
3597
559
    op->reserveOperands(operands.size() + literals.size() + 1);
3598
559
    op->addImmediateOperand((unsigned) opCode);
3599
1.46k
    for (auto it = operands.cbegin(); it != operands.cend(); ++it)
3600
904
        op->addIdOperand(*it);
3601
559
    for (auto it = literals.cbegin(); it != literals.cend(); ++it)
3602
0
        op->addImmediateOperand(*it);
3603
559
    module.mapInstruction(op);
3604
559
    constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(op));
3605
3606
    // OpSpecConstantOp's using 8 or 16 bit types require the associated capability
3607
559
    if (containsType(typeId, Op::OpTypeInt, 8))
3608
0
        addCapability(Capability::Int8);
3609
559
    if (containsType(typeId, Op::OpTypeInt, 16))
3610
144
        addCapability(Capability::Int16);
3611
559
    if (containsType(typeId, Op::OpTypeFloat, 16))
3612
0
        addCapability(Capability::Float16);
3613
3614
559
    return op->getResultId();
3615
559
}
3616
3617
Id Builder::createFunctionCall(spv::Function* function, const std::vector<spv::Id>& args)
3618
1.39k
{
3619
1.39k
    Instruction* op = new Instruction(getUniqueId(), function->getReturnType(), Op::OpFunctionCall);
3620
1.39k
    op->reserveOperands(args.size() + 1);
3621
1.39k
    op->addIdOperand(function->getId());
3622
1.95k
    for (int a = 0; a < (int)args.size(); ++a)
3623
565
        op->addIdOperand(args[a]);
3624
1.39k
    addInstruction(std::unique_ptr<Instruction>(op));
3625
3626
1.39k
    return op->getResultId();
3627
1.39k
}
3628
3629
// Comments in header
3630
Id Builder::createRvalueSwizzle(Decoration precision, Id typeId, Id source, const std::vector<unsigned>& channels)
3631
1.57k
{
3632
1.57k
    if (channels.size() == 1)
3633
337
        return setPrecision(createCompositeExtract(source, typeId, channels.front()), precision);
3634
3635
1.23k
    if (generatingOpCodeForSpecConst) {
3636
0
        std::vector<Id> operands(2);
3637
0
        operands[0] = operands[1] = source;
3638
0
        return setPrecision(createSpecConstantOp(Op::OpVectorShuffle, typeId, operands, channels), precision);
3639
0
    }
3640
1.23k
    Instruction* swizzle = new Instruction(getUniqueId(), typeId, Op::OpVectorShuffle);
3641
1.23k
    assert(isVector(source));
3642
1.23k
    swizzle->reserveOperands(channels.size() + 2);
3643
1.23k
    swizzle->addIdOperand(source);
3644
1.23k
    swizzle->addIdOperand(source);
3645
4.45k
    for (int i = 0; i < (int)channels.size(); ++i)
3646
3.22k
        swizzle->addImmediateOperand(channels[i]);
3647
1.23k
    addInstruction(std::unique_ptr<Instruction>(swizzle));
3648
3649
1.23k
    return setPrecision(swizzle->getResultId(), precision);
3650
1.23k
}
3651
3652
// Comments in header
3653
Id Builder::createLvalueSwizzle(Id typeId, Id target, Id source, const std::vector<unsigned>& channels)
3654
0
{
3655
0
    if (channels.size() == 1 && getNumComponents(source) == 1)
3656
0
        return createCompositeInsert(source, target, typeId, channels.front());
3657
3658
0
    Instruction* swizzle = new Instruction(getUniqueId(), typeId, Op::OpVectorShuffle);
3659
3660
0
    assert(isVector(target));
3661
0
    swizzle->reserveOperands(2);
3662
0
    swizzle->addIdOperand(target);
3663
3664
0
    assert(getNumComponents(source) == channels.size());
3665
0
    assert(isVector(source));
3666
0
    swizzle->addIdOperand(source);
3667
3668
    // Set up an identity shuffle from the base value to the result value
3669
0
    unsigned int components[4];
3670
0
    int numTargetComponents = getNumComponents(target);
3671
0
    for (int i = 0; i < numTargetComponents; ++i)
3672
0
        components[i] = i;
3673
3674
    // Punch in the l-value swizzle
3675
0
    for (int i = 0; i < (int)channels.size(); ++i)
3676
0
        components[channels[i]] = numTargetComponents + i;
3677
3678
    // finish the instruction with these components selectors
3679
0
    swizzle->reserveOperands(numTargetComponents);
3680
0
    for (int i = 0; i < numTargetComponents; ++i)
3681
0
        swizzle->addImmediateOperand(components[i]);
3682
0
    addInstruction(std::unique_ptr<Instruction>(swizzle));
3683
3684
0
    return swizzle->getResultId();
3685
0
}
3686
3687
// Comments in header
3688
void Builder::promoteScalar(Decoration precision, Id& left, Id& right)
3689
4.79k
{
3690
    // choose direction of promotion (+1 for left to right, -1 for right to left)
3691
4.79k
    int direction = !isScalar(right) - !isScalar(left);
3692
3693
4.79k
    auto const &makeVec = [&](Id component, Id other) {
3694
236
        if (isCooperativeVector(other)) {
3695
0
            return makeCooperativeVectorTypeNV(getTypeId(component), getCooperativeVectorNumComponents(getTypeId(other)));
3696
236
        } else {
3697
236
            return makeVectorType(getTypeId(component), getNumComponents(other));
3698
236
        }
3699
236
    };
3700
3701
4.79k
    if (direction > 0)
3702
0
        left = smearScalar(precision, left, makeVec(left, right));
3703
4.79k
    else if (direction < 0)
3704
236
        right = smearScalar(precision, right, makeVec(right, left));
3705
3706
4.79k
    return;
3707
4.79k
}
3708
3709
// Comments in header
3710
Id Builder::smearScalar(Decoration precision, Id scalar, Id vectorType)
3711
502
{
3712
502
    assert(getNumComponents(scalar) == 1);
3713
502
    assert(getTypeId(scalar) == getScalarTypeId(vectorType));
3714
3715
502
    int numComponents = getNumTypeComponents(vectorType);
3716
502
    if (numComponents == 1 && !isCooperativeVectorType(vectorType) && !isVectorType(vectorType))
3717
0
        return scalar;
3718
3719
502
    Instruction* smear = nullptr;
3720
502
    if (generatingOpCodeForSpecConst) {
3721
0
        auto members = std::vector<spv::Id>(numComponents, scalar);
3722
        // Sometime even in spec-constant-op mode, the temporary vector created by
3723
        // promoting a scalar might not be a spec constant. This should depend on
3724
        // the scalar.
3725
        // e.g.:
3726
        //  const vec2 spec_const_result = a_spec_const_vec2 + a_front_end_const_scalar;
3727
        // In such cases, the temporary vector created from a_front_end_const_scalar
3728
        // is not a spec constant vector, even though the binary operation node is marked
3729
        // as 'specConstant' and we are in spec-constant-op mode.
3730
0
        auto result_id = makeCompositeConstant(vectorType, members, isSpecConstant(scalar));
3731
0
        smear = module.getInstruction(result_id);
3732
502
    } else {
3733
502
        bool replicate = (useReplicatedComposites || isCooperativeVectorType(vectorType)) && (numComponents > 0);
3734
3735
502
        if (replicate) {
3736
0
            numComponents = 1;
3737
0
            addCapability(spv::Capability::ReplicatedCompositesEXT);
3738
0
            addExtension(spv::E_SPV_EXT_replicated_composites);
3739
0
        }
3740
3741
502
        Op opcode = replicate ? Op::OpCompositeConstructReplicateEXT : Op::OpCompositeConstruct;
3742
3743
502
        smear = new Instruction(getUniqueId(), vectorType, opcode);
3744
502
        smear->reserveOperands(numComponents);
3745
1.92k
        for (int c = 0; c < numComponents; ++c)
3746
1.42k
            smear->addIdOperand(scalar);
3747
502
        addInstruction(std::unique_ptr<Instruction>(smear));
3748
502
    }
3749
3750
502
    return setPrecision(smear->getResultId(), precision);
3751
502
}
3752
3753
// Comments in header
3754
Id Builder::createBuiltinCall(Id resultType, Id builtins, int entryPoint, const std::vector<Id>& args)
3755
549
{
3756
549
    Instruction* inst = new Instruction(getUniqueId(), resultType, Op::OpExtInst);
3757
549
    inst->reserveOperands(args.size() + 2);
3758
549
    inst->addIdOperand(builtins);
3759
549
    inst->addImmediateOperand(entryPoint);
3760
1.54k
    for (int arg = 0; arg < (int)args.size(); ++arg)
3761
992
        inst->addIdOperand(args[arg]);
3762
3763
549
    addInstruction(std::unique_ptr<Instruction>(inst));
3764
3765
549
    return inst->getResultId();
3766
549
}
3767
3768
// Accept all parameters needed to create a texture instruction.
3769
// Create the correct instruction based on the inputs, and make the call.
3770
Id Builder::createTextureCall(Decoration precision, Id resultType, bool sparse, bool fetch, bool proj, bool gather,
3771
    bool noImplicitLod, const TextureParameters& parameters, ImageOperandsMask signExtensionMask)
3772
1.35k
{
3773
1.35k
    std::vector<Id> texArgs;
3774
3775
    //
3776
    // Set up the fixed arguments
3777
    //
3778
1.35k
    bool explicitLod = false;
3779
1.35k
    texArgs.push_back(parameters.sampler);
3780
1.35k
    texArgs.push_back(parameters.coords);
3781
1.35k
    if (parameters.Dref != NoResult)
3782
432
        texArgs.push_back(parameters.Dref);
3783
1.35k
    if (parameters.component != NoResult)
3784
152
        texArgs.push_back(parameters.component);
3785
3786
1.35k
    if (parameters.granularity != NoResult)
3787
0
        texArgs.push_back(parameters.granularity);
3788
1.35k
    if (parameters.coarse != NoResult)
3789
0
        texArgs.push_back(parameters.coarse);
3790
3791
    //
3792
    // Set up the optional arguments
3793
    //
3794
1.35k
    size_t optArgNum = texArgs.size(); // the position of the mask for the optional arguments, if any.
3795
1.35k
    ImageOperandsMask mask = ImageOperandsMask::MaskNone; // the mask operand
3796
1.35k
    if (parameters.bias) {
3797
94
        mask = (ImageOperandsMask)(mask | ImageOperandsMask::Bias);
3798
94
        texArgs.push_back(parameters.bias);
3799
94
    }
3800
1.35k
    if (parameters.lod) {
3801
252
        mask = (ImageOperandsMask)(mask | ImageOperandsMask::Lod);
3802
252
        texArgs.push_back(parameters.lod);
3803
252
        explicitLod = true;
3804
1.10k
    } else if (parameters.gradX) {
3805
304
        mask = (ImageOperandsMask)(mask | ImageOperandsMask::Grad);
3806
304
        texArgs.push_back(parameters.gradX);
3807
304
        texArgs.push_back(parameters.gradY);
3808
304
        explicitLod = true;
3809
799
    } else if (noImplicitLod && ! fetch && ! gather) {
3810
        // have to explicitly use lod of 0 if not allowed to have them be implicit, and
3811
        // we would otherwise be about to issue an implicit instruction
3812
160
        mask = (ImageOperandsMask)(mask | ImageOperandsMask::Lod);
3813
160
        texArgs.push_back(makeFloatConstant(0.0));
3814
160
        explicitLod = true;
3815
160
    }
3816
1.35k
    if (parameters.offset) {
3817
466
        if (isConstant(parameters.offset))
3818
466
            mask = (ImageOperandsMask)(mask | ImageOperandsMask::ConstOffset);
3819
0
        else {
3820
0
            addCapability(Capability::ImageGatherExtended);
3821
0
            mask = (ImageOperandsMask)(mask | ImageOperandsMask::Offset);
3822
0
        }
3823
466
        texArgs.push_back(parameters.offset);
3824
466
    }
3825
1.35k
    if (parameters.offsets) {
3826
64
        if (!isConstant(parameters.offsets) && sourceLang == spv::SourceLanguage::GLSL) {
3827
0
            mask = (ImageOperandsMask)(mask | ImageOperandsMask::Offsets);
3828
64
        } else {
3829
64
            addCapability(Capability::ImageGatherExtended);
3830
64
            mask = (ImageOperandsMask)(mask | ImageOperandsMask::ConstOffsets);
3831
64
        }
3832
64
        texArgs.push_back(parameters.offsets);
3833
64
    }
3834
1.35k
    if (parameters.sample) {
3835
12
        mask = (ImageOperandsMask)(mask | ImageOperandsMask::Sample);
3836
12
        texArgs.push_back(parameters.sample);
3837
12
    }
3838
1.35k
    if (parameters.lodClamp) {
3839
        // capability if this bit is used
3840
200
        addCapability(Capability::MinLod);
3841
3842
200
        mask = (ImageOperandsMask)(mask | ImageOperandsMask::MinLod);
3843
200
        texArgs.push_back(parameters.lodClamp);
3844
200
    }
3845
1.35k
    if (parameters.nonprivate) {
3846
0
        mask = mask | ImageOperandsMask::NonPrivateTexelKHR;
3847
0
    }
3848
1.35k
    if (parameters.volatil) {
3849
0
        mask = mask | ImageOperandsMask::VolatileTexelKHR;
3850
0
    }
3851
1.35k
    if (parameters.nontemporal) {
3852
0
        mask = mask | ImageOperandsMask::Nontemporal;
3853
0
    }
3854
1.35k
    mask = mask | signExtensionMask;
3855
    // insert the operand for the mask, if any bits were set.
3856
1.35k
    if (mask != ImageOperandsMask::MaskNone)
3857
1.09k
        texArgs.insert(texArgs.begin() + optArgNum, (Id)mask);
3858
3859
    //
3860
    // Set up the instruction
3861
    //
3862
1.35k
    Op opCode = Op::OpNop;  // All paths below need to set this
3863
1.35k
    if (fetch) {
3864
75
        if (sparse)
3865
30
            opCode = Op::OpImageSparseFetch;
3866
45
        else
3867
45
            opCode = Op::OpImageFetch;
3868
1.28k
    } else if (parameters.granularity && parameters.coarse) {
3869
0
        opCode = Op::OpImageSampleFootprintNV;
3870
1.28k
    } else if (gather) {
3871
240
        if (parameters.Dref)
3872
88
            if (sparse)
3873
44
                opCode = Op::OpImageSparseDrefGather;
3874
44
            else
3875
44
                opCode = Op::OpImageDrefGather;
3876
152
        else
3877
152
            if (sparse)
3878
76
                opCode = Op::OpImageSparseGather;
3879
76
            else
3880
76
                opCode = Op::OpImageGather;
3881
1.04k
    } else if (explicitLod) {
3882
604
        if (parameters.Dref) {
3883
160
            if (proj)
3884
32
                if (sparse)
3885
0
                    opCode = Op::OpImageSparseSampleProjDrefExplicitLod;
3886
32
                else
3887
32
                    opCode = Op::OpImageSampleProjDrefExplicitLod;
3888
128
            else
3889
128
                if (sparse)
3890
44
                    opCode = Op::OpImageSparseSampleDrefExplicitLod;
3891
84
                else
3892
84
                    opCode = Op::OpImageSampleDrefExplicitLod;
3893
444
        } else {
3894
444
            if (proj)
3895
76
                if (sparse)
3896
0
                    opCode = Op::OpImageSparseSampleProjExplicitLod;
3897
76
                else
3898
76
                    opCode = Op::OpImageSampleProjExplicitLod;
3899
368
            else
3900
368
                if (sparse)
3901
84
                    opCode = Op::OpImageSparseSampleExplicitLod;
3902
284
                else
3903
284
                    opCode = Op::OpImageSampleExplicitLod;
3904
444
        }
3905
604
    } else {
3906
436
        if (parameters.Dref) {
3907
184
            if (proj)
3908
12
                if (sparse)
3909
0
                    opCode = Op::OpImageSparseSampleProjDrefImplicitLod;
3910
12
                else
3911
12
                    opCode = Op::OpImageSampleProjDrefImplicitLod;
3912
172
            else
3913
172
                if (sparse)
3914
56
                    opCode = Op::OpImageSparseSampleDrefImplicitLod;
3915
116
                else
3916
116
                    opCode = Op::OpImageSampleDrefImplicitLod;
3917
252
        } else {
3918
252
            if (proj)
3919
28
                if (sparse)
3920
0
                    opCode = Op::OpImageSparseSampleProjImplicitLod;
3921
28
                else
3922
28
                    opCode = Op::OpImageSampleProjImplicitLod;
3923
224
            else
3924
224
                if (sparse)
3925
72
                    opCode = Op::OpImageSparseSampleImplicitLod;
3926
152
                else
3927
152
                    opCode = Op::OpImageSampleImplicitLod;
3928
252
        }
3929
436
    }
3930
3931
    // See if the result type is expecting a smeared result.
3932
    // This happens when a legacy shadow*() call is made, which
3933
    // gets a vec4 back instead of a float.
3934
1.35k
    Id smearedType = resultType;
3935
1.35k
    if (! isScalarType(resultType)) {
3936
705
        switch (opCode) {
3937
0
        case Op::OpImageSampleDrefImplicitLod:
3938
0
        case Op::OpImageSampleDrefExplicitLod:
3939
0
        case Op::OpImageSampleProjDrefImplicitLod:
3940
0
        case Op::OpImageSampleProjDrefExplicitLod:
3941
0
            resultType = getScalarTypeId(resultType);
3942
0
            break;
3943
705
        default:
3944
705
            break;
3945
705
        }
3946
705
    }
3947
3948
1.35k
    Id typeId0 = 0;
3949
1.35k
    Id typeId1 = 0;
3950
3951
1.35k
    if (sparse) {
3952
406
        typeId0 = resultType;
3953
406
        typeId1 = getDerefTypeId(parameters.texelOut);
3954
406
        resultType = makeStructResultType(typeId0, typeId1);
3955
406
    }
3956
3957
    // Build the SPIR-V instruction
3958
1.35k
    Instruction* textureInst = new Instruction(getUniqueId(), resultType, opCode);
3959
1.35k
    textureInst->reserveOperands(optArgNum + (texArgs.size() - (optArgNum + 1)));
3960
4.64k
    for (size_t op = 0; op < optArgNum; ++op)
3961
3.29k
        textureInst->addIdOperand(texArgs[op]);
3962
1.35k
    if (optArgNum < texArgs.size())
3963
1.09k
        textureInst->addImmediateOperand(texArgs[optArgNum]);
3964
3.21k
    for (size_t op = optArgNum + 1; op < texArgs.size(); ++op)
3965
1.85k
        textureInst->addIdOperand(texArgs[op]);
3966
1.35k
    setPrecision(textureInst->getResultId(), precision);
3967
1.35k
    addInstruction(std::unique_ptr<Instruction>(textureInst));
3968
3969
1.35k
    Id resultId = textureInst->getResultId();
3970
3971
1.35k
    if (sparse) {
3972
        // set capability
3973
406
        addCapability(Capability::SparseResidency);
3974
3975
        // Decode the return type that was a special structure
3976
406
        createStore(createCompositeExtract(resultId, typeId1, 1), parameters.texelOut);
3977
406
        resultId = createCompositeExtract(resultId, typeId0, 0);
3978
406
        setPrecision(resultId, precision);
3979
949
    } else {
3980
        // When a smear is needed, do it, as per what was computed
3981
        // above when resultType was changed to a scalar type.
3982
949
        if (resultType != smearedType)
3983
0
            resultId = smearScalar(precision, resultId, smearedType);
3984
949
    }
3985
3986
1.35k
    return resultId;
3987
1.35k
}
3988
3989
// Comments in header
3990
Id Builder::createTextureQueryCall(Op opCode, const TextureParameters& parameters, bool isUnsignedResult)
3991
184
{
3992
    // Figure out the result type
3993
184
    Id resultType = 0;
3994
184
    switch (opCode) {
3995
15
    case Op::OpImageQuerySize:
3996
87
    case Op::OpImageQuerySizeLod:
3997
87
    {
3998
87
        int numComponents = 0;
3999
87
        switch (getTypeDimensionality(getImageType(parameters.sampler))) {
4000
12
        case Dim::Dim1D:
4001
15
        case Dim::Buffer:
4002
15
            numComponents = 1;
4003
15
            break;
4004
51
        case Dim::Dim2D:
4005
63
        case Dim::Cube:
4006
69
        case Dim::Rect:
4007
69
        case Dim::SubpassData:
4008
69
            numComponents = 2;
4009
69
            break;
4010
3
        case Dim::Dim3D:
4011
3
            numComponents = 3;
4012
3
            break;
4013
4014
0
        default:
4015
0
            assert(0);
4016
0
            break;
4017
87
        }
4018
87
        if (isArrayedImageType(getImageType(parameters.sampler)))
4019
54
            ++numComponents;
4020
4021
87
        Id intType = isUnsignedResult ? makeUintType(32) : makeIntType(32);
4022
87
        if (numComponents == 1)
4023
9
            resultType = intType;
4024
78
        else
4025
78
            resultType = makeVectorType(intType, numComponents);
4026
4027
87
        break;
4028
87
    }
4029
52
    case Op::OpImageQueryLod:
4030
52
        resultType = makeVectorType(getScalarTypeId(getTypeId(parameters.coords)), 2);
4031
52
        break;
4032
39
    case Op::OpImageQueryLevels:
4033
45
    case Op::OpImageQuerySamples:
4034
45
        resultType = isUnsignedResult ? makeUintType(32) : makeIntType(32);
4035
45
        break;
4036
0
    default:
4037
0
        assert(0);
4038
0
        break;
4039
184
    }
4040
4041
184
    Instruction* query = new Instruction(getUniqueId(), resultType, opCode);
4042
184
    query->addIdOperand(parameters.sampler);
4043
184
    if (parameters.coords)
4044
52
        query->addIdOperand(parameters.coords);
4045
184
    if (parameters.lod)
4046
72
        query->addIdOperand(parameters.lod);
4047
184
    addInstruction(std::unique_ptr<Instruction>(query));
4048
184
    addCapability(Capability::ImageQuery);
4049
4050
184
    return query->getResultId();
4051
184
}
4052
4053
// External comments in header.
4054
// Operates recursively to visit the composite's hierarchy.
4055
Id Builder::createCompositeCompare(Decoration precision, Id value1, Id value2, bool equal)
4056
0
{
4057
0
    Id boolType = makeBoolType();
4058
0
    Id valueType = getTypeId(value1);
4059
4060
0
    Id resultId = NoResult;
4061
4062
0
    int numConstituents = getNumTypeConstituents(valueType);
4063
4064
    // Scalars and Vectors
4065
4066
0
    if (isScalarType(valueType) || isVectorType(valueType)) {
4067
0
        assert(valueType == getTypeId(value2));
4068
        // These just need a single comparison, just have
4069
        // to figure out what it is.
4070
0
        Op op;
4071
0
        switch (getMostBasicTypeClass(valueType)) {
4072
0
        case Op::OpTypeFloat:
4073
0
            op = equal ? Op::OpFOrdEqual : Op::OpFUnordNotEqual;
4074
0
            break;
4075
0
        case Op::OpTypeInt:
4076
0
        default:
4077
0
            op = equal ? Op::OpIEqual : Op::OpINotEqual;
4078
0
            break;
4079
0
        case Op::OpTypeBool:
4080
0
            op = equal ? Op::OpLogicalEqual : Op::OpLogicalNotEqual;
4081
0
            precision = NoPrecision;
4082
0
            break;
4083
0
        }
4084
4085
0
        if (isScalarType(valueType)) {
4086
            // scalar
4087
0
            resultId = createBinOp(op, boolType, value1, value2);
4088
0
        } else {
4089
            // vector
4090
0
            resultId = createBinOp(op, makeVectorType(boolType, numConstituents), value1, value2);
4091
0
            setPrecision(resultId, precision);
4092
            // reduce vector compares...
4093
0
            resultId = createUnaryOp(equal ? Op::OpAll : Op::OpAny, boolType, resultId);
4094
0
        }
4095
4096
0
        return setPrecision(resultId, precision);
4097
0
    }
4098
4099
    // Only structs, arrays, and matrices should be left.
4100
    // They share in common the reduction operation across their constituents.
4101
0
    assert(isAggregateType(valueType) || isMatrixType(valueType));
4102
4103
    // Compare each pair of constituents
4104
0
    for (int constituent = 0; constituent < numConstituents; ++constituent) {
4105
0
        std::vector<unsigned> indexes(1, constituent);
4106
0
        Id constituentType1 = getContainedTypeId(getTypeId(value1), constituent);
4107
0
        Id constituentType2 = getContainedTypeId(getTypeId(value2), constituent);
4108
0
        Id constituent1 = createCompositeExtract(value1, constituentType1, indexes);
4109
0
        Id constituent2 = createCompositeExtract(value2, constituentType2, indexes);
4110
4111
0
        Id subResultId = createCompositeCompare(precision, constituent1, constituent2, equal);
4112
4113
0
        if (constituent == 0)
4114
0
            resultId = subResultId;
4115
0
        else
4116
0
            resultId = setPrecision(createBinOp(equal ? Op::OpLogicalAnd : Op::OpLogicalOr, boolType, resultId, subResultId),
4117
0
                                    precision);
4118
0
    }
4119
4120
0
    return resultId;
4121
0
}
4122
4123
// OpCompositeConstruct
4124
Id Builder::createCompositeConstruct(Id typeId, const std::vector<Id>& constituents)
4125
291
{
4126
291
    assert(isAggregateType(typeId) || (getNumTypeConstituents(typeId) > 1 &&
4127
291
           getNumTypeConstituents(typeId) == constituents.size()) ||
4128
291
           ((isCooperativeVectorType(typeId) || isVectorType(typeId)) && constituents.size() == 1));
4129
4130
291
    if (generatingOpCodeForSpecConst) {
4131
        // Sometime, even in spec-constant-op mode, the constant composite to be
4132
        // constructed may not be a specialization constant.
4133
        // e.g.:
4134
        //  const mat2 m2 = mat2(a_spec_const, a_front_end_const, another_front_end_const, third_front_end_const);
4135
        // The first column vector should be a spec constant one, as a_spec_const is a spec constant.
4136
        // The second column vector should NOT be spec constant, as it does not contain any spec constants.
4137
        // To handle such cases, we check the constituents of the constant vector to determine whether this
4138
        // vector should be created as a spec constant.
4139
0
        return makeCompositeConstant(typeId, constituents,
4140
0
                                     std::any_of(constituents.begin(), constituents.end(),
4141
0
                                                 [&](spv::Id id) { return isSpecConstant(id); }));
4142
0
    }
4143
4144
291
    bool replicate = false;
4145
291
    size_t numConstituents = constituents.size();
4146
4147
291
    if (useReplicatedComposites || isCooperativeVectorType(typeId)) {
4148
0
        replicate = numConstituents > 0 &&
4149
0
            std::equal(constituents.begin() + 1, constituents.end(), constituents.begin());
4150
0
    }
4151
4152
291
    if (replicate) {
4153
0
        numConstituents = 1;
4154
0
        addCapability(spv::Capability::ReplicatedCompositesEXT);
4155
0
        addExtension(spv::E_SPV_EXT_replicated_composites);
4156
0
    }
4157
4158
291
    Op opcode = replicate ? Op::OpCompositeConstructReplicateEXT : Op::OpCompositeConstruct;
4159
4160
291
    Instruction* op = new Instruction(getUniqueId(), typeId, opcode);
4161
291
    op->reserveOperands(constituents.size());
4162
1.19k
    for (size_t c = 0; c < numConstituents; ++c)
4163
900
        op->addIdOperand(constituents[c]);
4164
291
    addInstruction(std::unique_ptr<Instruction>(op));
4165
4166
291
    return op->getResultId();
4167
291
}
4168
4169
// coopmat conversion
4170
Id Builder::createCooperativeMatrixConversion(Id typeId, Id source)
4171
0
{
4172
0
    Instruction* op = new Instruction(getUniqueId(), typeId, Op::OpCooperativeMatrixConvertNV);
4173
0
    op->addIdOperand(source);
4174
0
    addInstruction(std::unique_ptr<Instruction>(op));
4175
4176
0
    return op->getResultId();
4177
0
}
4178
4179
// coopmat reduce
4180
Id Builder::createCooperativeMatrixReduce(Op opcode, Id typeId, Id source, unsigned int mask, Id func)
4181
0
{
4182
0
    Instruction* op = new Instruction(getUniqueId(), typeId, opcode);
4183
0
    op->addIdOperand(source);
4184
0
    op->addImmediateOperand(mask);
4185
0
    op->addIdOperand(func);
4186
0
    addInstruction(std::unique_ptr<Instruction>(op));
4187
4188
0
    return op->getResultId();
4189
0
}
4190
4191
// coopmat per-element operation
4192
Id Builder::createCooperativeMatrixPerElementOp(Id typeId, const std::vector<Id>& operands)
4193
0
{
4194
0
    Instruction* op = new Instruction(getUniqueId(), typeId, spv::Op::OpCooperativeMatrixPerElementOpNV);
4195
    // skip operand[0], which is where the result is stored
4196
0
    for (uint32_t i = 1; i < operands.size(); ++i) {
4197
0
        op->addIdOperand(operands[i]);
4198
0
    }
4199
0
    addInstruction(std::unique_ptr<Instruction>(op));
4200
4201
0
    return op->getResultId();
4202
0
}
4203
4204
// Vector or scalar constructor
4205
Id Builder::createConstructor(Decoration precision, const std::vector<Id>& sources, Id resultTypeId)
4206
533
{
4207
533
    Id result = NoResult;
4208
533
    unsigned int numTargetComponents = getNumTypeComponents(resultTypeId);
4209
533
    unsigned int targetComponent = 0;
4210
4211
    // Special case: when calling a vector constructor with a single scalar
4212
    // argument, smear the scalar
4213
533
    if (sources.size() == 1 && isScalar(sources[0]) && (numTargetComponents > 1 || isCooperativeVectorType(resultTypeId)))
4214
266
        return smearScalar(precision, sources[0], resultTypeId);
4215
4216
    // Special case: 2 vectors of equal size
4217
267
    if (sources.size() == 1 &&
4218
102
        (isVector(sources[0]) || isCooperativeVector(sources[0])) &&
4219
83
        numTargetComponents == getNumComponents(sources[0])) {
4220
65
        if (isCooperativeVector(sources[0]) != isCooperativeVectorType(resultTypeId)) {
4221
0
            assert(isVector(sources[0]) != isVectorType(resultTypeId));
4222
0
            return createUnaryOp(spv::Op::OpBitcast, resultTypeId, sources[0]);
4223
65
        } else {
4224
65
            assert(resultTypeId == getTypeId(sources[0]));
4225
65
            return sources[0];
4226
65
        }
4227
65
    }
4228
4229
    // accumulate the arguments for OpCompositeConstruct
4230
202
    std::vector<Id> constituents;
4231
202
    Id scalarTypeId = getScalarTypeId(resultTypeId);
4232
4233
    // lambda to store the result of visiting an argument component
4234
604
    const auto latchResult = [&](Id comp) {
4235
604
        if (numTargetComponents > 1 || isVectorType(resultTypeId))
4236
585
            constituents.push_back(comp);
4237
19
        else
4238
19
            result = comp;
4239
604
        ++targetComponent;
4240
604
    };
4241
4242
    // lambda to visit a vector argument's components
4243
202
    const auto accumulateVectorConstituents = [&](Id sourceArg) {
4244
130
        unsigned int sourceSize = getNumComponents(sourceArg);
4245
130
        unsigned int sourcesToUse = sourceSize;
4246
130
        if (sourcesToUse + targetComponent > numTargetComponents)
4247
18
            sourcesToUse = numTargetComponents - targetComponent;
4248
4249
467
        for (unsigned int s = 0; s < sourcesToUse; ++s) {
4250
337
            std::vector<unsigned> swiz;
4251
337
            swiz.push_back(s);
4252
337
            latchResult(createRvalueSwizzle(precision, scalarTypeId, sourceArg, swiz));
4253
337
        }
4254
130
    };
4255
4256
    // lambda to visit a matrix argument's components
4257
202
    const auto accumulateMatrixConstituents = [&](Id sourceArg) {
4258
0
        unsigned int sourceSize = getNumColumns(sourceArg) * getNumRows(sourceArg);
4259
0
        unsigned int sourcesToUse = sourceSize;
4260
0
        if (sourcesToUse + targetComponent > numTargetComponents)
4261
0
            sourcesToUse = numTargetComponents - targetComponent;
4262
4263
0
        unsigned int col = 0;
4264
0
        unsigned int row = 0;
4265
0
        for (unsigned int s = 0; s < sourcesToUse; ++s) {
4266
0
            if (row >= getNumRows(sourceArg)) {
4267
0
                row = 0;
4268
0
                col++;
4269
0
            }
4270
0
            std::vector<Id> indexes;
4271
0
            indexes.push_back(col);
4272
0
            indexes.push_back(row);
4273
0
            latchResult(createCompositeExtract(sourceArg, scalarTypeId, indexes));
4274
0
            row++;
4275
0
        }
4276
0
    };
4277
4278
    // Go through the source arguments, each one could have either
4279
    // a single or multiple components to contribute.
4280
397
    for (unsigned int i = 0; i < sources.size(); ++i) {
4281
4282
397
        if (isScalar(sources[i]) || isPointer(sources[i]))
4283
267
            latchResult(sources[i]);
4284
130
        else if (isVector(sources[i]) || isCooperativeVector(sources[i]))
4285
130
            accumulateVectorConstituents(sources[i]);
4286
0
        else if (isMatrix(sources[i]))
4287
0
            accumulateMatrixConstituents(sources[i]);
4288
0
        else
4289
0
            assert(0);
4290
4291
397
        if (targetComponent >= numTargetComponents)
4292
202
            break;
4293
397
    }
4294
4295
    // If the result is a vector, make it from the gathered constituents.
4296
202
    if (constituents.size() > 0) {
4297
183
        result = createCompositeConstruct(resultTypeId, constituents);
4298
183
        return setPrecision(result, precision);
4299
183
    } else {
4300
      // Precision was set when generating this component.
4301
19
      return result;
4302
19
    }
4303
202
}
4304
4305
// Comments in header
4306
Id Builder::createMatrixConstructor(Decoration precision, const std::vector<Id>& sources, Id resultTypeId)
4307
36
{
4308
36
    Id componentTypeId = getScalarTypeId(resultTypeId);
4309
36
    unsigned int numCols = getTypeNumColumns(resultTypeId);
4310
36
    unsigned int numRows = getTypeNumRows(resultTypeId);
4311
4312
36
    Instruction* instr = module.getInstruction(componentTypeId);
4313
36
    const unsigned bitCount = instr->getImmediateOperand(0);
4314
4315
    // Optimize matrix constructed from a bigger matrix
4316
36
    if (isMatrix(sources[0]) && getNumColumns(sources[0]) >= numCols && getNumRows(sources[0]) >= numRows) {
4317
        // To truncate the matrix to a smaller number of rows/columns, we need to:
4318
        // 1. For each column, extract the column and truncate it to the required size using shuffle
4319
        // 2. Assemble the resulting matrix from all columns
4320
18
        Id matrix = sources[0];
4321
18
        Id columnTypeId = getContainedTypeId(resultTypeId);
4322
18
        Id sourceColumnTypeId = getContainedTypeId(getTypeId(matrix));
4323
4324
18
        std::vector<unsigned> channels;
4325
63
        for (unsigned int row = 0; row < numRows; ++row)
4326
45
            channels.push_back(row);
4327
4328
18
        std::vector<Id> matrixColumns;
4329
63
        for (unsigned int col = 0; col < numCols; ++col) {
4330
45
            std::vector<unsigned> indexes;
4331
45
            indexes.push_back(col);
4332
45
            Id colv = createCompositeExtract(matrix, sourceColumnTypeId, indexes);
4333
45
            setPrecision(colv, precision);
4334
4335
45
            if (numRows != getNumRows(matrix)) {
4336
27
                matrixColumns.push_back(createRvalueSwizzle(precision, columnTypeId, colv, channels));
4337
27
            } else {
4338
18
                matrixColumns.push_back(colv);
4339
18
            }
4340
45
        }
4341
4342
18
        return setPrecision(createCompositeConstruct(resultTypeId, matrixColumns), precision);
4343
18
    }
4344
4345
    // Detect a matrix being constructed from a repeated vector of the correct size.
4346
    // Create the composite directly from it.
4347
18
    if (sources.size() == numCols && isVector(sources[0]) && getNumComponents(sources[0]) == numRows &&
4348
0
        std::equal(sources.begin() + 1, sources.end(), sources.begin())) {
4349
0
        return setPrecision(createCompositeConstruct(resultTypeId, sources), precision);
4350
0
    }
4351
4352
    // Otherwise, will use a two step process
4353
    // 1. make a compile-time 2D array of values
4354
    // 2. construct a matrix from that array
4355
4356
    // Step 1.
4357
4358
    // initialize the array to the identity matrix
4359
18
    Id ids[maxMatrixSize][maxMatrixSize];
4360
18
    Id  one = (bitCount == 64 ? makeDoubleConstant(1.0) : makeFloatConstant(1.0));
4361
18
    Id zero = (bitCount == 64 ? makeDoubleConstant(0.0) : makeFloatConstant(0.0));
4362
90
    for (int col = 0; col < 4; ++col) {
4363
360
        for (int row = 0; row < 4; ++row) {
4364
288
            if (col == row)
4365
72
                ids[col][row] = one;
4366
216
            else
4367
216
                ids[col][row] = zero;
4368
288
        }
4369
72
    }
4370
4371
    // modify components as dictated by the arguments
4372
18
    if (sources.size() == 1 && isScalar(sources[0])) {
4373
        // a single scalar; resets the diagonals
4374
45
        for (int col = 0; col < 4; ++col)
4375
36
            ids[col][col] = sources[0];
4376
9
    } else if (isMatrix(sources[0])) {
4377
        // constructing from another matrix; copy over the parts that exist in both the argument and constructee
4378
9
        Id matrix = sources[0];
4379
9
        unsigned int minCols = std::min(numCols, getNumColumns(matrix));
4380
9
        unsigned int minRows = std::min(numRows, getNumRows(matrix));
4381
36
        for (unsigned int col = 0; col < minCols; ++col) {
4382
27
            std::vector<unsigned> indexes;
4383
27
            indexes.push_back(col);
4384
108
            for (unsigned int row = 0; row < minRows; ++row) {
4385
81
                indexes.push_back(row);
4386
81
                ids[col][row] = createCompositeExtract(matrix, componentTypeId, indexes);
4387
81
                indexes.pop_back();
4388
81
                setPrecision(ids[col][row], precision);
4389
81
            }
4390
27
        }
4391
9
    } else {
4392
        // fill in the matrix in column-major order with whatever argument components are available
4393
0
        unsigned int row = 0;
4394
0
        unsigned int col = 0;
4395
4396
0
        for (unsigned int arg = 0; arg < sources.size() && col < numCols; ++arg) {
4397
0
            Id argComp = sources[arg];
4398
0
            for (unsigned int comp = 0; comp < getNumComponents(sources[arg]); ++comp) {
4399
0
                if (getNumComponents(sources[arg]) > 1) {
4400
0
                    argComp = createCompositeExtract(sources[arg], componentTypeId, comp);
4401
0
                    setPrecision(argComp, precision);
4402
0
                }
4403
0
                ids[col][row++] = argComp;
4404
0
                if (row == numRows) {
4405
0
                    row = 0;
4406
0
                    col++;
4407
0
                }
4408
0
                if (col == numCols) {
4409
                    // If more components are provided than fit the matrix, discard the rest.
4410
0
                    break;
4411
0
                }
4412
0
            }
4413
0
        }
4414
0
    }
4415
4416
    // Step 2:  Construct a matrix from that array.
4417
    // First make the column vectors, then make the matrix.
4418
4419
    // make the column vectors
4420
18
    Id columnTypeId = getContainedTypeId(resultTypeId);
4421
18
    std::vector<Id> matrixColumns;
4422
72
    for (unsigned int col = 0; col < numCols; ++col) {
4423
54
        std::vector<Id> vectorComponents;
4424
234
        for (unsigned int row = 0; row < numRows; ++row)
4425
180
            vectorComponents.push_back(ids[col][row]);
4426
54
        Id column = createCompositeConstruct(columnTypeId, vectorComponents);
4427
54
        setPrecision(column, precision);
4428
54
        matrixColumns.push_back(column);
4429
54
    }
4430
4431
    // make the matrix
4432
18
    return setPrecision(createCompositeConstruct(resultTypeId, matrixColumns), precision);
4433
18
}
4434
4435
// Comments in header
4436
Builder::If::If(Id cond, SelectionControlMask ctrl, Builder& gb) :
4437
1.23k
    builder(gb),
4438
1.23k
    condition(cond),
4439
1.23k
    control(ctrl),
4440
1.23k
    elseBlock(nullptr)
4441
1.23k
{
4442
1.23k
    function = &builder.getBuildPoint()->getParent();
4443
4444
    // make the blocks, but only put the then-block into the function,
4445
    // the else-block and merge-block will be added later, in order, after
4446
    // earlier code is emitted
4447
1.23k
    thenBlock = new Block(builder.getUniqueId(), *function);
4448
1.23k
    mergeBlock = new Block(builder.getUniqueId(), *function);
4449
4450
    // Save the current block, so that we can add in the flow control split when
4451
    // makeEndIf is called.
4452
1.23k
    headerBlock = builder.getBuildPoint();
4453
1.23k
    builder.createSelectionMerge(mergeBlock, control);
4454
4455
1.23k
    function->addBlock(thenBlock);
4456
1.23k
    builder.setBuildPoint(thenBlock);
4457
1.23k
}
4458
4459
// Comments in header
4460
void Builder::If::makeBeginElse()
4461
8
{
4462
    // Close out the "then" by having it jump to the mergeBlock
4463
8
    builder.createBranch(true, mergeBlock);
4464
4465
    // Make the first else block and add it to the function
4466
8
    elseBlock = new Block(builder.getUniqueId(), *function);
4467
8
    function->addBlock(elseBlock);
4468
4469
    // Start building the else block
4470
8
    builder.setBuildPoint(elseBlock);
4471
8
}
4472
4473
// Comments in header
4474
void Builder::If::makeEndIf()
4475
1.23k
{
4476
    // jump to the merge block
4477
1.23k
    builder.createBranch(true, mergeBlock);
4478
4479
    // Go back to the headerBlock and make the flow control split
4480
1.23k
    builder.setBuildPoint(headerBlock);
4481
1.23k
    if (elseBlock)
4482
8
        builder.createConditionalBranch(condition, thenBlock, elseBlock);
4483
1.22k
    else
4484
1.22k
        builder.createConditionalBranch(condition, thenBlock, mergeBlock);
4485
4486
    // add the merge block to the function
4487
1.23k
    function->addBlock(mergeBlock);
4488
1.23k
    builder.setBuildPoint(mergeBlock);
4489
1.23k
}
4490
4491
// Comments in header
4492
void Builder::makeSwitch(Id selector, SelectionControlMask control, int numSegments, const std::vector<int>& caseValues,
4493
                         const std::vector<int>& valueIndexToSegment, int defaultSegment,
4494
                         std::vector<Block*>& segmentBlocks)
4495
164
{
4496
164
    Function& function = buildPoint->getParent();
4497
4498
    // make all the blocks
4499
578
    for (int s = 0; s < numSegments; ++s)
4500
414
        segmentBlocks.push_back(new Block(getUniqueId(), function));
4501
4502
164
    Block* mergeBlock = new Block(getUniqueId(), function);
4503
4504
    // make and insert the switch's selection-merge instruction
4505
164
    createSelectionMerge(mergeBlock, control);
4506
4507
    // make the switch instruction
4508
164
    Instruction* switchInst = new Instruction(NoResult, NoType, Op::OpSwitch);
4509
164
    switchInst->reserveOperands((caseValues.size() * 2) + 2);
4510
164
    switchInst->addIdOperand(selector);
4511
164
    auto defaultOrMerge = (defaultSegment >= 0) ? segmentBlocks[defaultSegment] : mergeBlock;
4512
164
    switchInst->addIdOperand(defaultOrMerge->getId());
4513
164
    defaultOrMerge->addPredecessor(buildPoint);
4514
576
    for (int i = 0; i < (int)caseValues.size(); ++i) {
4515
412
        switchInst->addImmediateOperand(caseValues[i]);
4516
412
        switchInst->addIdOperand(segmentBlocks[valueIndexToSegment[i]]->getId());
4517
412
        segmentBlocks[valueIndexToSegment[i]]->addPredecessor(buildPoint);
4518
412
    }
4519
164
    addInstruction(std::unique_ptr<Instruction>(switchInst));
4520
4521
    // push the merge block
4522
164
    switchMerges.push(mergeBlock);
4523
164
}
4524
4525
// Comments in header
4526
void Builder::addSwitchBreak(bool implicit)
4527
575
{
4528
    // branch to the top of the merge block stack
4529
575
    createBranch(implicit, switchMerges.top());
4530
575
    createAndSetNoPredecessorBlock("post-switch-break");
4531
575
}
4532
4533
// Comments in header
4534
void Builder::nextSwitchSegment(std::vector<Block*>& segmentBlock, int nextSegment)
4535
414
{
4536
414
    int lastSegment = nextSegment - 1;
4537
414
    if (lastSegment >= 0) {
4538
        // Close out previous segment by jumping, if necessary, to next segment
4539
250
        if (! buildPoint->isTerminated())
4540
250
            createBranch(true, segmentBlock[nextSegment]);
4541
250
    }
4542
414
    Block* block = segmentBlock[nextSegment];
4543
414
    block->getParent().addBlock(block);
4544
414
    setBuildPoint(block);
4545
414
}
4546
4547
// Comments in header
4548
void Builder::endSwitch(std::vector<Block*>& /*segmentBlock*/)
4549
164
{
4550
    // Close out previous segment by jumping, if necessary, to next segment
4551
164
    if (! buildPoint->isTerminated())
4552
164
        addSwitchBreak(true);
4553
4554
164
    switchMerges.top()->getParent().addBlock(switchMerges.top());
4555
164
    setBuildPoint(switchMerges.top());
4556
4557
164
    switchMerges.pop();
4558
164
}
4559
4560
Block& Builder::makeNewBlock()
4561
1.71k
{
4562
1.71k
    Function& function = buildPoint->getParent();
4563
1.71k
    auto block = new Block(getUniqueId(), function);
4564
1.71k
    function.addBlock(block);
4565
1.71k
    return *block;
4566
1.71k
}
4567
4568
Builder::LoopBlocks& Builder::makeNewLoop()
4569
353
{
4570
    // This verbosity is needed to simultaneously get the same behavior
4571
    // everywhere (id's in the same order), have a syntax that works
4572
    // across lots of versions of C++, have no warnings from pedantic
4573
    // compilation modes, and leave the rest of the code alone.
4574
353
    Block& head            = makeNewBlock();
4575
353
    Block& body            = makeNewBlock();
4576
353
    Block& merge           = makeNewBlock();
4577
353
    Block& continue_target = makeNewBlock();
4578
353
    LoopBlocks blocks(head, body, merge, continue_target);
4579
353
    loops.push(blocks);
4580
353
    return loops.top();
4581
353
}
4582
4583
void Builder::createLoopContinue()
4584
0
{
4585
0
    createBranch(false, &loops.top().continue_target);
4586
    // Set up a block for dead code.
4587
0
    createAndSetNoPredecessorBlock("post-loop-continue");
4588
0
}
4589
4590
void Builder::createLoopExit()
4591
0
{
4592
0
    createBranch(false, &loops.top().merge);
4593
    // Set up a block for dead code.
4594
0
    createAndSetNoPredecessorBlock("post-loop-break");
4595
0
}
4596
4597
void Builder::closeLoop()
4598
353
{
4599
353
    loops.pop();
4600
353
}
4601
4602
void Builder::clearAccessChain()
4603
113k
{
4604
113k
    accessChain.base = NoResult;
4605
113k
    accessChain.indexChain.clear();
4606
113k
    accessChain.instr = NoResult;
4607
113k
    accessChain.swizzle.clear();
4608
113k
    accessChain.component = NoResult;
4609
113k
    accessChain.preSwizzleBaseType = NoType;
4610
113k
    accessChain.isRValue = false;
4611
113k
    accessChain.coherentFlags.clear();
4612
113k
    accessChain.alignment = 0;
4613
113k
    accessChain.descHeapInfo.descHeapBaseTy = NoResult;
4614
113k
    accessChain.descHeapInfo.descHeapStorageClass = StorageClass::Max;
4615
113k
    accessChain.descHeapInfo.descHeapInstId.clear();
4616
113k
    accessChain.descHeapInfo.descHeapBaseArrayStride = NoResult;
4617
113k
    accessChain.descHeapInfo.structRemappedBase = NoResult;
4618
113k
    accessChain.descHeapInfo.structRsrcTyOffsetCount = 0;
4619
113k
    accessChain.descHeapInfo.structRsrcTyFirstArrIndex = 0;
4620
113k
}
4621
4622
// Comments in header
4623
void Builder::accessChainPushSwizzle(std::vector<unsigned>& swizzle, Id preSwizzleBaseType,
4624
    AccessChain::CoherentFlags coherentFlags, unsigned int alignment)
4625
3.60k
{
4626
3.60k
    accessChain.coherentFlags |= coherentFlags;
4627
3.60k
    accessChain.alignment |= alignment;
4628
4629
    // swizzles can be stacked in GLSL, but simplified to a single
4630
    // one here; the base type doesn't change
4631
3.60k
    if (accessChain.preSwizzleBaseType == NoType)
4632
3.60k
        accessChain.preSwizzleBaseType = preSwizzleBaseType;
4633
4634
    // if needed, propagate the swizzle for the current access chain
4635
3.60k
    if (accessChain.swizzle.size() > 0) {
4636
0
        std::vector<unsigned> oldSwizzle = accessChain.swizzle;
4637
0
        accessChain.swizzle.resize(0);
4638
0
        for (unsigned int i = 0; i < swizzle.size(); ++i) {
4639
0
            assert(swizzle[i] < oldSwizzle.size());
4640
0
            accessChain.swizzle.push_back(oldSwizzle[swizzle[i]]);
4641
0
        }
4642
0
    } else
4643
3.60k
        accessChain.swizzle = swizzle;
4644
4645
    // determine if we need to track this swizzle anymore
4646
3.60k
    simplifyAccessChainSwizzle();
4647
3.60k
}
4648
4649
// Comments in header
4650
void Builder::accessChainStore(Id rvalue, Decoration nonUniform, spv::MemoryAccessMask memoryAccess, spv::Scope scope, unsigned int alignment)
4651
9.39k
{
4652
9.39k
    assert(accessChain.isRValue == false);
4653
4654
9.39k
    transferAccessChainSwizzle(true);
4655
4656
    // MeshShadingEXT outputs don't support loads, so split swizzled stores
4657
9.39k
    bool isMeshOutput = getStorageClass(accessChain.base) == StorageClass::Output &&
4658
478
                        capabilities.find(spv::Capability::MeshShadingEXT) != capabilities.end();
4659
4660
    // If a swizzle exists and is not full and is not dynamic, then the swizzle will be broken into individual stores.
4661
9.39k
    if (accessChain.swizzle.size() > 0 &&
4662
324
        ((getNumTypeComponents(getResultingAccessChainType()) != accessChain.swizzle.size() && accessChain.component == NoResult) || isMeshOutput)) {
4663
1.16k
        for (unsigned int i = 0; i < accessChain.swizzle.size(); ++i) {
4664
836
            accessChain.indexChain.push_back(makeUintConstant(accessChain.swizzle[i]));
4665
836
            accessChain.instr = NoResult;
4666
4667
836
            Id base = collapseAccessChain();
4668
836
            addDecoration(base, nonUniform);
4669
4670
836
            accessChain.indexChain.pop_back();
4671
836
            accessChain.instr = NoResult;
4672
4673
            // dynamic component should be gone
4674
836
            assert(accessChain.component == NoResult);
4675
4676
836
            Id source = createCompositeExtract(rvalue, getContainedTypeId(getTypeId(rvalue)), i);
4677
4678
            // take LSB of alignment
4679
836
            alignment = alignment & ~(alignment & (alignment-1));
4680
836
            if (getStorageClass(base) == StorageClass::PhysicalStorageBufferEXT) {
4681
0
                memoryAccess = (spv::MemoryAccessMask)(memoryAccess | spv::MemoryAccessMask::Aligned);
4682
0
            }
4683
4684
836
            createStore(source, base, memoryAccess, scope, alignment);
4685
836
        }
4686
324
    }
4687
9.07k
    else {
4688
9.07k
        Id base = collapseAccessChain();
4689
9.07k
        addDecoration(base, nonUniform);
4690
4691
9.07k
        Id source = rvalue;
4692
4693
        // dynamic component should be gone
4694
9.07k
        assert(accessChain.component == NoResult);
4695
4696
        // If swizzle still exists, it may be out-of-order, we must load the target vector,
4697
        // extract and insert elements to perform writeMask and/or swizzle.
4698
9.07k
        if (accessChain.swizzle.size() > 0) {
4699
0
            Id tempBaseId = createLoad(base, spv::NoPrecision);
4700
0
            source = createLvalueSwizzle(getTypeId(tempBaseId), tempBaseId, source, accessChain.swizzle);
4701
0
        }
4702
4703
        // take LSB of alignment
4704
9.07k
        alignment = alignment & ~(alignment & (alignment-1));
4705
9.07k
        if (getStorageClass(base) == StorageClass::PhysicalStorageBufferEXT) {
4706
54
            memoryAccess = (spv::MemoryAccessMask)(memoryAccess | spv::MemoryAccessMask::Aligned);
4707
54
        }
4708
4709
9.07k
        createStore(source, base, memoryAccess, scope, alignment);
4710
9.07k
    }
4711
9.39k
}
4712
4713
// Comments in header
4714
Id Builder::accessChainLoad(Decoration precision, Decoration l_nonUniform,
4715
    Decoration r_nonUniform, Id resultType, spv::MemoryAccessMask memoryAccess,
4716
    spv::Scope scope, unsigned int alignment)
4717
40.3k
{
4718
40.3k
    Id id;
4719
4720
40.3k
    if (accessChain.isRValue) {
4721
        // transfer access chain, but try to stay in registers
4722
21.5k
        transferAccessChainSwizzle(false);
4723
21.5k
        if (accessChain.indexChain.size() > 0) {
4724
284
            Id swizzleBase = accessChain.preSwizzleBaseType != NoType ? accessChain.preSwizzleBaseType : resultType;
4725
4726
            // if all the accesses are constants, we can use OpCompositeExtract
4727
284
            std::vector<unsigned> indexes;
4728
284
            bool constant = true;
4729
550
            for (int i = 0; i < (int)accessChain.indexChain.size(); ++i) {
4730
284
                if (isConstantScalar(accessChain.indexChain[i]))
4731
266
                    indexes.push_back(getConstantScalar(accessChain.indexChain[i]));
4732
18
                else {
4733
18
                    constant = false;
4734
18
                    break;
4735
18
                }
4736
284
            }
4737
4738
284
            if (constant) {
4739
266
                id = createCompositeExtract(accessChain.base, swizzleBase, indexes);
4740
266
                setPrecision(id, precision);
4741
266
            } else if (isVector(accessChain.base) || isCooperativeVector(accessChain.base)) {
4742
0
                assert(accessChain.indexChain.size() == 1);
4743
0
                id = createVectorExtractDynamic(accessChain.base, resultType, accessChain.indexChain[0]);
4744
18
            } else {
4745
18
                Id lValue = NoResult;
4746
18
                if (spvVersion >= Spv_1_4 && isValidInitializer(accessChain.base)) {
4747
                    // make a new function variable for this r-value, using an initializer,
4748
                    // and mark it as NonWritable so that downstream it can be detected as a lookup
4749
                    // table
4750
0
                    lValue = createVariable(NoPrecision, StorageClass::Function, getTypeId(accessChain.base),
4751
0
                        "indexable", accessChain.base);
4752
0
                    addDecoration(lValue, Decoration::NonWritable);
4753
18
                } else {
4754
18
                    lValue = createVariable(NoPrecision, StorageClass::Function, getTypeId(accessChain.base),
4755
18
                        "indexable");
4756
                    // store into it
4757
18
                    createStore(accessChain.base, lValue);
4758
18
                }
4759
                // move base to the new variable
4760
18
                accessChain.base = lValue;
4761
18
                accessChain.isRValue = false;
4762
4763
                // load through the access chain
4764
18
                id = createLoad(collapseAccessChain(), precision);
4765
18
            }
4766
284
        } else
4767
21.2k
            id = accessChain.base;  // no precision, it was set when this was defined
4768
21.5k
    } else {
4769
18.7k
        transferAccessChainSwizzle(true);
4770
4771
        // take LSB of alignment
4772
18.7k
        alignment = alignment & ~(alignment & (alignment-1));
4773
18.7k
        if (getStorageClass(accessChain.base) == StorageClass::PhysicalStorageBufferEXT) {
4774
18
            memoryAccess = (spv::MemoryAccessMask)(memoryAccess | spv::MemoryAccessMask::Aligned);
4775
18
        }
4776
4777
        // load through the access chain
4778
18.7k
        id = collapseAccessChain();
4779
        // Apply nonuniform both to the access chain and the loaded value.
4780
        // Buffer accesses need the access chain decorated, and this is where
4781
        // loaded image types get decorated. TODO: This should maybe move to
4782
        // createImageTextureFunctionCall.
4783
18.7k
        addDecoration(id, l_nonUniform);
4784
18.7k
        id = createLoad(id, precision, memoryAccess, scope, alignment);
4785
18.7k
        addDecoration(id, r_nonUniform);
4786
18.7k
    }
4787
4788
    // Done, unless there are swizzles to do
4789
40.3k
    if (accessChain.swizzle.size() == 0 && accessChain.component == NoResult)
4790
39.1k
        return id;
4791
4792
    // Do remaining swizzling
4793
4794
    // Do the basic swizzle
4795
1.20k
    if (accessChain.swizzle.size() > 0) {
4796
1.20k
        Id swizzledType = getScalarTypeId(getTypeId(id));
4797
1.20k
        if (accessChain.swizzle.size() > 1)
4798
1.20k
            swizzledType = makeVectorType(swizzledType, (int)accessChain.swizzle.size());
4799
1.20k
        id = createRvalueSwizzle(precision, swizzledType, id, accessChain.swizzle);
4800
1.20k
    }
4801
4802
    // Do the dynamic component
4803
1.20k
    if (accessChain.component != NoResult)
4804
0
        id = setPrecision(createVectorExtractDynamic(id, resultType, accessChain.component), precision);
4805
4806
1.20k
    addDecoration(id, r_nonUniform);
4807
1.20k
    return id;
4808
40.3k
}
4809
4810
Id Builder::accessChainGetLValue()
4811
3.93k
{
4812
3.93k
    assert(accessChain.isRValue == false);
4813
4814
3.93k
    transferAccessChainSwizzle(true);
4815
3.93k
    Id lvalue = collapseAccessChain();
4816
4817
    // If swizzle exists, it is out-of-order or not full, we must load the target vector,
4818
    // extract and insert elements to perform writeMask and/or swizzle.  This does not
4819
    // go with getting a direct l-value pointer.
4820
3.93k
    assert(accessChain.swizzle.size() == 0);
4821
3.93k
    assert(accessChain.component == NoResult);
4822
4823
3.93k
    return lvalue;
4824
3.93k
}
4825
4826
// comment in header
4827
Id Builder::accessChainGetInferredType()
4828
40.5k
{
4829
    // anything to operate on?
4830
    // for untyped pointer, it may be remapped to a descriptor heap.
4831
    // for descriptor heap, its base data type will be determined later,
4832
    // according to load/store results' types.
4833
40.5k
    if (accessChain.base == NoResult || isUntypedPointer(accessChain.base) ||
4834
40.5k
        isStructureHeapMember(getTypeId(accessChain.base), accessChain.indexChain, 0) != 0)
4835
0
        return NoType;
4836
40.5k
    Id type = getTypeId(accessChain.base);
4837
    // do initial dereference
4838
40.5k
    if (! accessChain.isRValue)
4839
19.0k
        type = getContainedTypeId(type);
4840
4841
    // dereference each index
4842
45.0k
    for (auto it = accessChain.indexChain.cbegin(); it != accessChain.indexChain.cend(); ++it) {
4843
4.46k
        if (isStructType(type))
4844
3.86k
            type = getContainedTypeId(type, getConstantScalar(*it));
4845
591
        else
4846
591
            type = getContainedTypeId(type);
4847
4.46k
    }
4848
4849
    // dereference swizzle
4850
40.5k
    if (accessChain.swizzle.size() == 1)
4851
1.67k
        type = getContainedTypeId(type);
4852
38.8k
    else if (accessChain.swizzle.size() > 1)
4853
1.26k
        type = makeVectorType(getContainedTypeId(type), (int)accessChain.swizzle.size());
4854
4855
    // dereference component selection
4856
40.5k
    if (accessChain.component)
4857
0
        type = getContainedTypeId(type);
4858
4859
40.5k
    return type;
4860
40.5k
}
4861
4862
void Builder::dump(std::vector<unsigned int>& out) const
4863
442
{
4864
    // Header, before first instructions:
4865
442
    out.push_back(MagicNumber);
4866
442
    out.push_back(spvVersion);
4867
442
    out.push_back(builderNumber);
4868
442
    out.push_back(uniqueId + 1);
4869
442
    out.push_back(0);
4870
4871
    // Capabilities
4872
1.86k
    for (auto it = capabilities.cbegin(); it != capabilities.cend(); ++it) {
4873
1.42k
        Instruction capInst(0, 0, Op::OpCapability);
4874
1.42k
        capInst.addImmediateOperand(*it);
4875
1.42k
        capInst.dump(out);
4876
1.42k
    }
4877
4878
836
    for (auto it = extensions.cbegin(); it != extensions.cend(); ++it) {
4879
394
        Instruction extInst(0, 0, Op::OpExtension);
4880
394
        extInst.addStringOperand(it->c_str());
4881
394
        extInst.dump(out);
4882
394
    }
4883
4884
442
    dumpInstructions(out, imports);
4885
442
    Instruction memInst(0, 0, Op::OpMemoryModel);
4886
442
    memInst.addImmediateOperand(addressModel);
4887
442
    memInst.addImmediateOperand(memoryModel);
4888
442
    memInst.dump(out);
4889
4890
    // Instructions saved up while building:
4891
442
    dumpInstructions(out, entryPoints);
4892
442
    dumpInstructions(out, executionModes);
4893
4894
    // Debug instructions
4895
442
    dumpInstructions(out, strings);
4896
442
    dumpSourceInstructions(out);
4897
2.49k
    for (int e = 0; e < (int)sourceExtensions.size(); ++e) {
4898
2.05k
        Instruction sourceExtInst(0, 0, Op::OpSourceExtension);
4899
2.05k
        sourceExtInst.addStringOperand(sourceExtensions[e]);
4900
2.05k
        sourceExtInst.dump(out);
4901
2.05k
    }
4902
442
    dumpInstructions(out, names);
4903
442
    dumpModuleProcesses(out);
4904
4905
    // Annotation instructions
4906
442
    dumpInstructions(out, decorations);
4907
4908
442
    dumpInstructions(out, constantsTypesGlobals);
4909
442
    dumpInstructions(out, externals);
4910
4911
    // The functions
4912
442
    module.dump(out);
4913
442
}
4914
4915
//
4916
// Protected methods.
4917
//
4918
4919
// Turn the described access chain in 'accessChain' into an instruction(s)
4920
// computing its address.  This *cannot* include complex swizzles, which must
4921
// be handled after this is called.
4922
//
4923
// Can generate code.
4924
Id Builder::collapseAccessChain()
4925
32.6k
{
4926
32.6k
    assert(accessChain.isRValue == false);
4927
4928
    // did we already emit an access chain for this?
4929
32.6k
    if (accessChain.instr != NoResult)
4930
9
        return accessChain.instr;
4931
4932
    // If we have a dynamic component, we can still transfer
4933
    // that into a final operand to the access chain.  We need to remap the
4934
    // dynamic component through the swizzle to get a new dynamic component to
4935
    // update.
4936
    //
4937
    // This was not done in transferAccessChainSwizzle() because it might
4938
    // generate code.
4939
32.6k
    remapDynamicSwizzle();
4940
32.6k
    if (accessChain.component != NoResult) {
4941
        // transfer the dynamic component to the access chain
4942
0
        accessChain.indexChain.push_back(accessChain.component);
4943
0
        accessChain.component = NoResult;
4944
0
    }
4945
4946
    // note that non-trivial swizzling is left pending
4947
4948
    // do we have an access chain?
4949
32.6k
    if (accessChain.indexChain.size() == 0)
4950
23.4k
        return accessChain.base;
4951
4952
    // emit the access chain
4953
9.23k
    StorageClass storageClass = (StorageClass)module.getStorageClass(getTypeId(accessChain.base));
4954
    // when descHeap info is set, use another access chain process.
4955
9.23k
    if ((isUntypedPointer(accessChain.base) || accessChain.descHeapInfo.structRsrcTyOffsetCount!= 0) &&
4956
0
        accessChain.descHeapInfo.descHeapStorageClass != StorageClass::Max) {
4957
0
        accessChain.instr = createDescHeapAccessChain();
4958
9.23k
    } else {
4959
9.23k
        accessChain.instr = createAccessChain(storageClass, accessChain.base, accessChain.indexChain);
4960
9.23k
    }
4961
4962
9.23k
    return accessChain.instr;
4963
32.6k
}
4964
4965
// For a dynamic component selection of a swizzle.
4966
//
4967
// Turn the swizzle and dynamic component into just a dynamic component.
4968
//
4969
// Generates code.
4970
void Builder::remapDynamicSwizzle()
4971
32.6k
{
4972
    // do we have a swizzle to remap a dynamic component through?
4973
32.6k
    if (accessChain.component != NoResult && accessChain.swizzle.size() > 1) {
4974
        // build a vector of the swizzle for the component to map into
4975
0
        std::vector<Id> components;
4976
0
        for (int c = 0; c < (int)accessChain.swizzle.size(); ++c)
4977
0
            components.push_back(makeUintConstant(accessChain.swizzle[c]));
4978
0
        Id mapType = makeVectorType(makeUintType(32), (int)accessChain.swizzle.size());
4979
0
        Id map = makeCompositeConstant(mapType, components);
4980
4981
        // use it
4982
0
        accessChain.component = createVectorExtractDynamic(map, makeUintType(32), accessChain.component);
4983
0
        accessChain.swizzle.clear();
4984
0
    }
4985
32.6k
}
4986
4987
// clear out swizzle if it is redundant, that is reselecting the same components
4988
// that would be present without the swizzle.
4989
void Builder::simplifyAccessChainSwizzle()
4990
3.60k
{
4991
    // If the swizzle has fewer components than the vector, it is subsetting, and must stay
4992
    // to preserve that fact.
4993
3.60k
    if (getNumTypeComponents(accessChain.preSwizzleBaseType) > accessChain.swizzle.size())
4994
3.56k
        return;
4995
4996
    // if components are out of order, it is a swizzle
4997
136
    for (unsigned int i = 0; i < accessChain.swizzle.size(); ++i) {
4998
102
        if (i != accessChain.swizzle[i])
4999
0
            return;
5000
102
    }
5001
5002
    // otherwise, there is no need to track this swizzle
5003
34
    accessChain.swizzle.clear();
5004
34
    if (accessChain.component == NoResult)
5005
34
        accessChain.preSwizzleBaseType = NoType;
5006
34
}
5007
5008
// To the extent any swizzling can become part of the chain
5009
// of accesses instead of a post operation, make it so.
5010
// If 'dynamic' is true, include transferring the dynamic component,
5011
// otherwise, leave it pending.
5012
//
5013
// Does not generate code. just updates the access chain.
5014
void Builder::transferAccessChainSwizzle(bool dynamic)
5015
53.6k
{
5016
    // non existent?
5017
53.6k
    if (accessChain.swizzle.size() == 0 && accessChain.component == NoResult)
5018
49.7k
        return;
5019
5020
    // too complex?
5021
    // (this requires either a swizzle, or generating code for a dynamic component)
5022
3.87k
    if (accessChain.swizzle.size() > 1)
5023
1.53k
        return;
5024
5025
    // single component, either in the swizzle and/or dynamic component
5026
2.34k
    if (accessChain.swizzle.size() == 1) {
5027
2.34k
        assert(accessChain.component == NoResult);
5028
        // handle static component selection
5029
2.34k
        accessChain.indexChain.push_back(makeUintConstant(accessChain.swizzle.front()));
5030
2.34k
        accessChain.swizzle.clear();
5031
2.34k
        accessChain.preSwizzleBaseType = NoType;
5032
2.34k
    } else if (dynamic && accessChain.component != NoResult) {
5033
0
        assert(accessChain.swizzle.size() == 0);
5034
        // handle dynamic component
5035
0
        accessChain.indexChain.push_back(accessChain.component);
5036
0
        accessChain.preSwizzleBaseType = NoType;
5037
0
        accessChain.component = NoResult;
5038
0
    }
5039
2.34k
}
5040
5041
// Utility method for creating a new block and setting the insert point to
5042
// be in it. This is useful for flow-control operations that need a "dummy"
5043
// block proceeding them (e.g. instructions after a discard, etc).
5044
void Builder::createAndSetNoPredecessorBlock(const char* /*name*/)
5045
933
{
5046
933
    Block* block = new Block(getUniqueId(), buildPoint->getParent());
5047
933
    block->setUnreachable();
5048
933
    buildPoint->getParent().addBlock(block);
5049
933
    setBuildPoint(block);
5050
5051
    // if (name)
5052
    //    addName(block->getId(), name);
5053
933
}
5054
5055
// Comments in header
5056
void Builder::createBranch(bool implicit, Block* block)
5057
3.44k
{
5058
3.44k
    Instruction* branch = new Instruction(Op::OpBranch);
5059
3.44k
    branch->addIdOperand(block->getId());
5060
3.44k
    if (implicit) {
5061
3.03k
        addInstructionNoDebugInfo(std::unique_ptr<Instruction>(branch));
5062
3.03k
    }
5063
411
    else {
5064
411
        addInstruction(std::unique_ptr<Instruction>(branch));
5065
411
    }
5066
3.44k
    block->addPredecessor(buildPoint);
5067
3.44k
}
5068
5069
// Create OpConstantSizeOfEXT
5070
Id Builder::createConstantSizeOfEXT(Id typeId)
5071
0
{
5072
0
    Instruction* inst = new Instruction(getUniqueId(), makeIntType(32), Op::OpConstantSizeOfEXT);
5073
0
    inst->addIdOperand(typeId);
5074
0
    constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(inst));
5075
0
    module.mapInstruction(inst);
5076
0
    return inst->getResultId();
5077
0
}
5078
5079
void Builder::createSelectionMerge(Block* mergeBlock, SelectionControlMask control)
5080
1.40k
{
5081
1.40k
    Instruction* merge = new Instruction(Op::OpSelectionMerge);
5082
1.40k
    merge->reserveOperands(2);
5083
1.40k
    merge->addIdOperand(mergeBlock->getId());
5084
1.40k
    merge->addImmediateOperand(control);
5085
1.40k
    addInstruction(std::unique_ptr<Instruction>(merge));
5086
1.40k
}
5087
5088
void Builder::createLoopMerge(Block* mergeBlock, Block* continueBlock, LoopControlMask control,
5089
                              const std::vector<unsigned int>& operands)
5090
353
{
5091
353
    Instruction* merge = new Instruction(Op::OpLoopMerge);
5092
353
    merge->reserveOperands(operands.size() + 3);
5093
353
    merge->addIdOperand(mergeBlock->getId());
5094
353
    merge->addIdOperand(continueBlock->getId());
5095
353
    merge->addImmediateOperand(control);
5096
389
    for (int op = 0; op < (int)operands.size(); ++op)
5097
36
        merge->addImmediateOperand(operands[op]);
5098
353
    addInstruction(std::unique_ptr<Instruction>(merge));
5099
353
}
5100
5101
void Builder::createConditionalBranch(Id condition, Block* thenBlock, Block* elseBlock)
5102
1.57k
{
5103
1.57k
    Instruction* branch = new Instruction(Op::OpBranchConditional);
5104
1.57k
    branch->reserveOperands(3);
5105
1.57k
    branch->addIdOperand(condition);
5106
1.57k
    branch->addIdOperand(thenBlock->getId());
5107
1.57k
    branch->addIdOperand(elseBlock->getId());
5108
5109
    // A conditional branch is always attached to a condition expression
5110
1.57k
    addInstructionNoDebugInfo(std::unique_ptr<Instruction>(branch));
5111
5112
1.57k
    thenBlock->addPredecessor(buildPoint);
5113
1.57k
    elseBlock->addPredecessor(buildPoint);
5114
1.57k
}
5115
5116
// OpSource
5117
// [OpSourceContinued]
5118
// ...
5119
void Builder::dumpSourceInstructions(const spv::Id fileId, const std::string& text,
5120
                                     std::vector<unsigned int>& out) const
5121
442
{
5122
442
    const int maxWordCount = 0xFFFF;
5123
442
    const int opSourceWordCount = 4;
5124
442
    const int nonNullBytesPerInstruction = 4 * (maxWordCount - opSourceWordCount) - 1;
5125
5126
442
    if (sourceLang != SourceLanguage::Unknown) {
5127
        // OpSource Language Version File Source
5128
442
        Instruction sourceInst(NoResult, NoType, Op::OpSource);
5129
442
        sourceInst.reserveOperands(3);
5130
442
        sourceInst.addImmediateOperand(sourceLang);
5131
442
        sourceInst.addImmediateOperand(sourceVersion);
5132
        // File operand
5133
442
        if (fileId != NoResult) {
5134
0
            sourceInst.addIdOperand(fileId);
5135
            // Source operand
5136
0
            if (text.size() > 0) {
5137
0
                int nextByte = 0;
5138
0
                std::string subString;
5139
0
                while ((int)text.size() - nextByte > 0) {
5140
0
                    subString = text.substr(nextByte, nonNullBytesPerInstruction);
5141
0
                    if (nextByte == 0) {
5142
                        // OpSource
5143
0
                        sourceInst.addStringOperand(subString.c_str());
5144
0
                        sourceInst.dump(out);
5145
0
                    } else {
5146
                        // OpSourcContinued
5147
0
                        Instruction sourceContinuedInst(Op::OpSourceContinued);
5148
0
                        sourceContinuedInst.addStringOperand(subString.c_str());
5149
0
                        sourceContinuedInst.dump(out);
5150
0
                    }
5151
0
                    nextByte += nonNullBytesPerInstruction;
5152
0
                }
5153
0
            } else
5154
0
                sourceInst.dump(out);
5155
0
        } else
5156
442
            sourceInst.dump(out);
5157
442
    }
5158
442
}
5159
5160
// Dump an OpSource[Continued] sequence for the source and every include file
5161
void Builder::dumpSourceInstructions(std::vector<unsigned int>& out) const
5162
442
{
5163
442
    if (emitNonSemanticShaderDebugInfo) return;
5164
442
    dumpSourceInstructions(mainFileId, sourceText, out);
5165
442
    for (auto iItr = includeFiles.begin(); iItr != includeFiles.end(); ++iItr)
5166
0
        dumpSourceInstructions(iItr->first, *iItr->second, out);
5167
442
}
5168
5169
template <class Range> void Builder::dumpInstructions(std::vector<unsigned int>& out, const Range& instructions) const
5170
3.53k
{
5171
41.2k
    for (const auto& inst : instructions) {
5172
41.2k
        inst->dump(out);
5173
41.2k
    }
5174
3.53k
}
void spv::Builder::dumpInstructions<std::__1::vector<std::__1::unique_ptr<spv::Instruction, std::__1::default_delete<spv::Instruction> >, std::__1::allocator<std::__1::unique_ptr<spv::Instruction, std::__1::default_delete<spv::Instruction> > > > >(std::__1::vector<unsigned int, std::__1::allocator<unsigned int> >&, std::__1::vector<std::__1::unique_ptr<spv::Instruction, std::__1::default_delete<spv::Instruction> >, std::__1::allocator<std::__1::unique_ptr<spv::Instruction, std::__1::default_delete<spv::Instruction> > > > const&) const
Line
Count
Source
5170
3.09k
{
5171
32.7k
    for (const auto& inst : instructions) {
5172
32.7k
        inst->dump(out);
5173
32.7k
    }
5174
3.09k
}
void spv::Builder::dumpInstructions<std::__1::set<std::__1::unique_ptr<spv::Instruction, std::__1::default_delete<spv::Instruction> >, spv::Builder::DecorationInstructionLessThan, std::__1::allocator<std::__1::unique_ptr<spv::Instruction, std::__1::default_delete<spv::Instruction> > > > >(std::__1::vector<unsigned int, std::__1::allocator<unsigned int> >&, std::__1::set<std::__1::unique_ptr<spv::Instruction, std::__1::default_delete<spv::Instruction> >, spv::Builder::DecorationInstructionLessThan, std::__1::allocator<std::__1::unique_ptr<spv::Instruction, std::__1::default_delete<spv::Instruction> > > > const&) const
Line
Count
Source
5170
442
{
5171
8.53k
    for (const auto& inst : instructions) {
5172
8.53k
        inst->dump(out);
5173
8.53k
    }
5174
442
}
5175
5176
void Builder::dumpModuleProcesses(std::vector<unsigned int>& out) const
5177
442
{
5178
442
    for (int i = 0; i < (int)moduleProcesses.size(); ++i) {
5179
0
        Instruction moduleProcessed(Op::OpModuleProcessed);
5180
0
        moduleProcessed.addStringOperand(moduleProcesses[i]);
5181
0
        moduleProcessed.dump(out);
5182
0
    }
5183
442
}
5184
5185
bool Builder::DecorationInstructionLessThan::operator()(const std::unique_ptr<Instruction>& lhs,
5186
                                                        const std::unique_ptr<Instruction>& rhs) const
5187
84.9k
{
5188
    // Order by the id to which the decoration applies first. This is more intuitive.
5189
84.9k
    assert(lhs->isIdOperand(0) && rhs->isIdOperand(0));
5190
84.9k
    if (lhs->getIdOperand(0) != rhs->getIdOperand(0)) {
5191
69.1k
        return lhs->getIdOperand(0) < rhs->getIdOperand(0);
5192
69.1k
    }
5193
5194
15.7k
    if (lhs->getOpCode() != rhs->getOpCode())
5195
702
        return lhs->getOpCode() < rhs->getOpCode();
5196
5197
    // Now compare the operands.
5198
15.0k
    int minSize = std::min(lhs->getNumOperands(), rhs->getNumOperands());
5199
16.6k
    for (int i = 1; i < minSize; ++i) {
5200
15.4k
        if (lhs->isIdOperand(i) != rhs->isIdOperand(i)) {
5201
0
            return lhs->isIdOperand(i) < rhs->isIdOperand(i);
5202
0
        }
5203
5204
15.4k
        if (lhs->isIdOperand(i)) {
5205
0
            if (lhs->getIdOperand(i) != rhs->getIdOperand(i)) {
5206
0
                return lhs->getIdOperand(i) < rhs->getIdOperand(i);
5207
0
            }
5208
15.4k
        } else {
5209
15.4k
            if (lhs->getImmediateOperand(i) != rhs->getImmediateOperand(i)) {
5210
13.8k
                return lhs->getImmediateOperand(i) < rhs->getImmediateOperand(i);
5211
13.8k
            }
5212
15.4k
        }
5213
15.4k
    }
5214
5215
1.23k
    if (lhs->getNumOperands() != rhs->getNumOperands())
5216
0
        return lhs->getNumOperands() < rhs->getNumOperands();
5217
5218
    // In this case they are equal.
5219
1.23k
    return false;
5220
1.23k
}
5221
} // end spv namespace