Coverage Report

Created: 2025-11-19 06:41

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