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