Coverage Report

Created: 2025-07-11 07:07

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