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.
6 // All rights reserved.
8 // Redistribution and use in source and binary forms, with or without
9 // modification, are permitted provided that the following conditions
12 // Redistributions of source code must retain the above copyright
13 // notice, this list of conditions and the following disclaimer.
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.
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.
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.
38 // Helper for making SPIR-V IR. Generally, this is documented in the header
45 #include <unordered_set>
48 #include "SpvBuilder.h"
51 #include "hex_float.h"
60 Builder::Builder(unsigned int spvVersion, unsigned int magicNumber, SpvBuildLogger* buildLogger) :
61 spvVersion(spvVersion),
62 sourceLang(SourceLanguageUnknown),
64 sourceFileStringId(NoResult),
67 currentFileId(NoResult),
68 lastDebugScopeId(NoResult),
70 emitNonSemanticShaderDebugInfo(false),
71 addressModel(AddressingModelLogical),
72 memoryModel(MemoryModelGLSL450),
73 builderNumber(magicNumber),
76 entryPointFunction(nullptr),
77 generatingOpCodeForSpecConst(false),
87 Id Builder::import(const char* name)
89 Instruction* import = new Instruction(getUniqueId(), NoType, OpExtInstImport);
90 import->addStringOperand(name);
91 module.mapInstruction(import);
93 imports.push_back(std::unique_ptr<Instruction>(import));
94 return import->getResultId();
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.
100 void Builder::setLine(int lineNum)
102 if (lineNum != 0 && lineNum != currentLine) {
103 currentLine = lineNum;
105 if (emitNonSemanticShaderDebugInfo)
106 addDebugScopeAndLine(currentFileId, currentLine, 0);
108 addLine(sourceFileStringId, currentLine, 0);
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.
116 void Builder::setLine(int lineNum, const char* filename)
118 if (filename == nullptr) {
122 if ((lineNum != 0 && lineNum != currentLine) || currentFile == nullptr ||
123 strncmp(filename, currentFile, strlen(currentFile) + 1) != 0) {
124 currentLine = lineNum;
125 currentFile = filename;
127 spv::Id strId = getStringId(filename);
128 if (emitNonSemanticShaderDebugInfo)
129 addDebugScopeAndLine(strId, currentLine, 0);
131 addLine(strId, currentLine, 0);
136 void Builder::addLine(Id fileName, int lineNum, int column)
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));
145 void Builder::addDebugScopeAndLine(Id fileName, int lineNum, int column)
147 if (currentDebugScopeId.top() != lastDebugScopeId) {
148 spv::Id resultId = getUniqueId();
149 Instruction* scopeInst = new Instruction(resultId, makeVoidType(), OpExtInst);
150 scopeInst->addIdOperand(nonSemanticShaderDebugInfo);
151 scopeInst->addImmediateOperand(NonSemanticShaderDebugInfo100DebugScope);
152 scopeInst->addIdOperand(currentDebugScopeId.top());
153 buildPoint->addInstruction(std::unique_ptr<Instruction>(scopeInst));
154 lastDebugScopeId = currentDebugScopeId.top();
156 spv::Id resultId = getUniqueId();
157 Instruction* lineInst = new Instruction(resultId, makeVoidType(), OpExtInst);
158 lineInst->addIdOperand(nonSemanticShaderDebugInfo);
159 lineInst->addImmediateOperand(NonSemanticShaderDebugInfo100DebugLine);
160 lineInst->addIdOperand(makeDebugSource(fileName));
161 lineInst->addIdOperand(makeUintConstant(lineNum));
162 lineInst->addIdOperand(makeUintConstant(lineNum));
163 lineInst->addIdOperand(makeUintConstant(column));
164 lineInst->addIdOperand(makeUintConstant(column));
165 buildPoint->addInstruction(std::unique_ptr<Instruction>(lineInst));
168 // For creating new groupedTypes (will return old type if the requested one was already made).
169 Id Builder::makeVoidType()
172 if (groupedTypes[OpTypeVoid].size() == 0) {
173 Id typeId = getUniqueId();
174 type = new Instruction(typeId, NoType, OpTypeVoid);
175 groupedTypes[OpTypeVoid].push_back(type);
176 constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(type));
177 module.mapInstruction(type);
178 // Core OpTypeVoid used for debug void type
179 if (emitNonSemanticShaderDebugInfo)
180 debugId[typeId] = typeId;
182 type = groupedTypes[OpTypeVoid].back();
184 return type->getResultId();
187 Id Builder::makeBoolType(bool const compilerGenerated)
190 if (groupedTypes[OpTypeBool].size() == 0) {
191 type = new Instruction(getUniqueId(), NoType, OpTypeBool);
192 groupedTypes[OpTypeBool].push_back(type);
193 constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(type));
194 module.mapInstruction(type);
196 type = groupedTypes[OpTypeBool].back();
198 if (emitNonSemanticShaderDebugInfo && !compilerGenerated)
200 auto const debugResultId = makeBoolDebugType(32);
201 debugId[type->getResultId()] = debugResultId;
204 return type->getResultId();
207 Id Builder::makeSamplerType()
210 if (groupedTypes[OpTypeSampler].size() == 0) {
211 type = new Instruction(getUniqueId(), NoType, OpTypeSampler);
212 groupedTypes[OpTypeSampler].push_back(type);
213 constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(type));
214 module.mapInstruction(type);
216 type = groupedTypes[OpTypeSampler].back();
218 if (emitNonSemanticShaderDebugInfo)
220 auto const debugResultId = makeCompositeDebugType({}, "type.sampler", NonSemanticShaderDebugInfo100Structure, true);
221 debugId[type->getResultId()] = debugResultId;
224 return type->getResultId();
227 Id Builder::makePointer(StorageClass storageClass, Id pointee)
231 for (int t = 0; t < (int)groupedTypes[OpTypePointer].size(); ++t) {
232 type = groupedTypes[OpTypePointer][t];
233 if (type->getImmediateOperand(0) == (unsigned)storageClass &&
234 type->getIdOperand(1) == pointee)
235 return type->getResultId();
238 // not found, make it
239 type = new Instruction(getUniqueId(), NoType, OpTypePointer);
240 type->addImmediateOperand(storageClass);
241 type->addIdOperand(pointee);
242 groupedTypes[OpTypePointer].push_back(type);
243 constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(type));
244 module.mapInstruction(type);
246 return type->getResultId();
249 Id Builder::makeForwardPointer(StorageClass storageClass)
251 // Caching/uniquifying doesn't work here, because we don't know the
252 // pointee type and there can be multiple forward pointers of the same
253 // storage type. Somebody higher up in the stack must keep track.
254 Instruction* type = new Instruction(getUniqueId(), NoType, OpTypeForwardPointer);
255 type->addImmediateOperand(storageClass);
256 constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(type));
257 module.mapInstruction(type);
259 return type->getResultId();
262 Id Builder::makePointerFromForwardPointer(StorageClass storageClass, Id forwardPointerType, Id pointee)
266 for (int t = 0; t < (int)groupedTypes[OpTypePointer].size(); ++t) {
267 type = groupedTypes[OpTypePointer][t];
268 if (type->getImmediateOperand(0) == (unsigned)storageClass &&
269 type->getIdOperand(1) == pointee)
270 return type->getResultId();
273 type = new Instruction(forwardPointerType, NoType, OpTypePointer);
274 type->addImmediateOperand(storageClass);
275 type->addIdOperand(pointee);
276 groupedTypes[OpTypePointer].push_back(type);
277 constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(type));
278 module.mapInstruction(type);
280 return type->getResultId();
283 Id Builder::makeIntegerType(int width, bool hasSign)
292 for (int t = 0; t < (int)groupedTypes[OpTypeInt].size(); ++t) {
293 type = groupedTypes[OpTypeInt][t];
294 if (type->getImmediateOperand(0) == (unsigned)width &&
295 type->getImmediateOperand(1) == (hasSign ? 1u : 0u))
296 return type->getResultId();
299 // not found, make it
300 type = new Instruction(getUniqueId(), NoType, OpTypeInt);
301 type->addImmediateOperand(width);
302 type->addImmediateOperand(hasSign ? 1 : 0);
303 groupedTypes[OpTypeInt].push_back(type);
304 constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(type));
305 module.mapInstruction(type);
307 // deal with capabilities
311 // these are currently handled by storage-type declarations and post processing
314 addCapability(CapabilityInt64);
320 if (emitNonSemanticShaderDebugInfo)
322 auto const debugResultId = makeIntegerDebugType(width, hasSign);
323 debugId[type->getResultId()] = debugResultId;
326 return type->getResultId();
329 Id Builder::makeFloatType(int width)
338 for (int t = 0; t < (int)groupedTypes[OpTypeFloat].size(); ++t) {
339 type = groupedTypes[OpTypeFloat][t];
340 if (type->getImmediateOperand(0) == (unsigned)width)
341 return type->getResultId();
344 // not found, make it
345 type = new Instruction(getUniqueId(), NoType, OpTypeFloat);
346 type->addImmediateOperand(width);
347 groupedTypes[OpTypeFloat].push_back(type);
348 constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(type));
349 module.mapInstruction(type);
351 // deal with capabilities
354 // currently handled by storage-type declarations and post processing
357 addCapability(CapabilityFloat64);
363 if (emitNonSemanticShaderDebugInfo)
365 auto const debugResultId = makeFloatDebugType(width);
366 debugId[type->getResultId()] = debugResultId;
369 return type->getResultId();
372 // Make a struct without checking for duplication.
373 // See makeStructResultType() for non-decorated structs
374 // needed as the result of some instructions, which does
375 // check for duplicates.
376 Id Builder::makeStructType(const std::vector<Id>& members, const char* name, bool const compilerGenerated)
378 // Don't look for previous one, because in the general case,
379 // structs can be duplicated except for decorations.
381 // not found, make it
382 Instruction* type = new Instruction(getUniqueId(), NoType, OpTypeStruct);
383 for (int op = 0; op < (int)members.size(); ++op)
384 type->addIdOperand(members[op]);
385 groupedTypes[OpTypeStruct].push_back(type);
386 constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(type));
387 module.mapInstruction(type);
388 addName(type->getResultId(), name);
390 if (emitNonSemanticShaderDebugInfo && !compilerGenerated)
392 auto const debugResultId = makeCompositeDebugType(members, name, NonSemanticShaderDebugInfo100Structure);
393 debugId[type->getResultId()] = debugResultId;
396 return type->getResultId();
399 // Make a struct for the simple results of several instructions,
400 // checking for duplication.
401 Id Builder::makeStructResultType(Id type0, Id type1)
405 for (int t = 0; t < (int)groupedTypes[OpTypeStruct].size(); ++t) {
406 type = groupedTypes[OpTypeStruct][t];
407 if (type->getNumOperands() != 2)
409 if (type->getIdOperand(0) != type0 ||
410 type->getIdOperand(1) != type1)
412 return type->getResultId();
415 // not found, make it
416 std::vector<spv::Id> members;
417 members.push_back(type0);
418 members.push_back(type1);
420 return makeStructType(members, "ResType");
423 Id Builder::makeVectorType(Id component, int size)
427 for (int t = 0; t < (int)groupedTypes[OpTypeVector].size(); ++t) {
428 type = groupedTypes[OpTypeVector][t];
429 if (type->getIdOperand(0) == component &&
430 type->getImmediateOperand(1) == (unsigned)size)
431 return type->getResultId();
434 // not found, make it
435 type = new Instruction(getUniqueId(), NoType, OpTypeVector);
436 type->addIdOperand(component);
437 type->addImmediateOperand(size);
438 groupedTypes[OpTypeVector].push_back(type);
439 constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(type));
440 module.mapInstruction(type);
442 if (emitNonSemanticShaderDebugInfo)
444 auto const debugResultId = makeVectorDebugType(component, size);
445 debugId[type->getResultId()] = debugResultId;
448 return type->getResultId();
451 Id Builder::makeMatrixType(Id component, int cols, int rows)
453 assert(cols <= maxMatrixSize && rows <= maxMatrixSize);
455 Id column = makeVectorType(component, rows);
459 for (int t = 0; t < (int)groupedTypes[OpTypeMatrix].size(); ++t) {
460 type = groupedTypes[OpTypeMatrix][t];
461 if (type->getIdOperand(0) == column &&
462 type->getImmediateOperand(1) == (unsigned)cols)
463 return type->getResultId();
466 // not found, make it
467 type = new Instruction(getUniqueId(), NoType, OpTypeMatrix);
468 type->addIdOperand(column);
469 type->addImmediateOperand(cols);
470 groupedTypes[OpTypeMatrix].push_back(type);
471 constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(type));
472 module.mapInstruction(type);
474 if (emitNonSemanticShaderDebugInfo)
476 auto const debugResultId = makeMatrixDebugType(column, cols);
477 debugId[type->getResultId()] = debugResultId;
480 return type->getResultId();
483 Id Builder::makeCooperativeMatrixType(Id component, Id scope, Id rows, Id cols)
487 for (int t = 0; t < (int)groupedTypes[OpTypeCooperativeMatrixNV].size(); ++t) {
488 type = groupedTypes[OpTypeCooperativeMatrixNV][t];
489 if (type->getIdOperand(0) == component &&
490 type->getIdOperand(1) == scope &&
491 type->getIdOperand(2) == rows &&
492 type->getIdOperand(3) == cols)
493 return type->getResultId();
496 // not found, make it
497 type = new Instruction(getUniqueId(), NoType, OpTypeCooperativeMatrixNV);
498 type->addIdOperand(component);
499 type->addIdOperand(scope);
500 type->addIdOperand(rows);
501 type->addIdOperand(cols);
502 groupedTypes[OpTypeCooperativeMatrixNV].push_back(type);
503 constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(type));
504 module.mapInstruction(type);
506 return type->getResultId();
509 Id Builder::makeGenericType(spv::Op opcode, std::vector<spv::IdImmediate>& operands)
513 for (int t = 0; t < (int)groupedTypes[opcode].size(); ++t) {
514 type = groupedTypes[opcode][t];
515 if (static_cast<size_t>(type->getNumOperands()) != operands.size())
516 continue; // Number mismatch, find next
519 for (int op = 0; match && op < (int)operands.size(); ++op) {
520 match = (operands[op].isId ? type->getIdOperand(op) : type->getImmediateOperand(op)) == operands[op].word;
523 return type->getResultId();
526 // not found, make it
527 type = new Instruction(getUniqueId(), NoType, opcode);
528 for (size_t op = 0; op < operands.size(); ++op) {
529 if (operands[op].isId)
530 type->addIdOperand(operands[op].word);
532 type->addImmediateOperand(operands[op].word);
534 groupedTypes[opcode].push_back(type);
535 constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(type));
536 module.mapInstruction(type);
538 return type->getResultId();
541 // TODO: performance: track arrays per stride
542 // If a stride is supplied (non-zero) make an array.
543 // If no stride (0), reuse previous array types.
544 // 'size' is an Id of a constant or specialization constant of the array size
545 Id Builder::makeArrayType(Id element, Id sizeId, int stride)
549 // try to find existing type
550 for (int t = 0; t < (int)groupedTypes[OpTypeArray].size(); ++t) {
551 type = groupedTypes[OpTypeArray][t];
552 if (type->getIdOperand(0) == element &&
553 type->getIdOperand(1) == sizeId)
554 return type->getResultId();
558 // not found, make it
559 type = new Instruction(getUniqueId(), NoType, OpTypeArray);
560 type->addIdOperand(element);
561 type->addIdOperand(sizeId);
562 groupedTypes[OpTypeArray].push_back(type);
563 constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(type));
564 module.mapInstruction(type);
566 if (emitNonSemanticShaderDebugInfo)
568 auto const debugResultId = makeArrayDebugType(element, sizeId);
569 debugId[type->getResultId()] = debugResultId;
572 return type->getResultId();
575 Id Builder::makeRuntimeArray(Id element)
577 Instruction* type = new Instruction(getUniqueId(), NoType, OpTypeRuntimeArray);
578 type->addIdOperand(element);
579 constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(type));
580 module.mapInstruction(type);
582 if (emitNonSemanticShaderDebugInfo)
584 auto const debugResultId = makeArrayDebugType(element, makeUintConstant(0));
585 debugId[type->getResultId()] = debugResultId;
588 return type->getResultId();
591 Id Builder::makeFunctionType(Id returnType, const std::vector<Id>& paramTypes)
595 for (int t = 0; t < (int)groupedTypes[OpTypeFunction].size(); ++t) {
596 type = groupedTypes[OpTypeFunction][t];
597 if (type->getIdOperand(0) != returnType || (int)paramTypes.size() != type->getNumOperands() - 1)
599 bool mismatch = false;
600 for (int p = 0; p < (int)paramTypes.size(); ++p) {
601 if (paramTypes[p] != type->getIdOperand(p + 1)) {
608 // If compiling HLSL, glslang will create a wrapper function around the entrypoint. Accordingly, a void(void)
609 // function type is created for the wrapper function. However, nonsemantic shader debug information is disabled
610 // while creating the HLSL wrapper. Consequently, if we encounter another void(void) function, we need to create
611 // the associated debug function type if it hasn't been created yet.
612 if(emitNonSemanticShaderDebugInfo && debugId[type->getResultId()] == 0) {
613 assert(sourceLang == spv::SourceLanguageHLSL);
614 assert(getTypeClass(returnType) == OpTypeVoid && paramTypes.size() == 0);
616 Id debugTypeId = makeDebugFunctionType(returnType, {});
617 debugId[type->getResultId()] = debugTypeId;
619 return type->getResultId();
623 // not found, make it
624 Id typeId = getUniqueId();
625 type = new Instruction(typeId, NoType, OpTypeFunction);
626 type->addIdOperand(returnType);
627 for (int p = 0; p < (int)paramTypes.size(); ++p)
628 type->addIdOperand(paramTypes[p]);
629 groupedTypes[OpTypeFunction].push_back(type);
630 constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(type));
631 module.mapInstruction(type);
633 // make debug type and map it
634 if (emitNonSemanticShaderDebugInfo) {
635 Id debugTypeId = makeDebugFunctionType(returnType, paramTypes);
636 debugId[typeId] = debugTypeId;
639 return type->getResultId();
642 Id Builder::makeDebugFunctionType(Id returnType, const std::vector<Id>& paramTypes)
644 assert(debugId[returnType] != 0);
646 Id typeId = getUniqueId();
647 auto type = new Instruction(typeId, makeVoidType(), OpExtInst);
648 type->addIdOperand(nonSemanticShaderDebugInfo);
649 type->addImmediateOperand(NonSemanticShaderDebugInfo100DebugTypeFunction);
650 type->addIdOperand(makeUintConstant(NonSemanticShaderDebugInfo100FlagIsPublic));
651 type->addIdOperand(debugId[returnType]);
652 for (auto const paramType : paramTypes) {
653 assert(isPointerType(paramType) || isArrayType(paramType));
654 type->addIdOperand(debugId[getContainedTypeId(paramType)]);
656 constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(type));
657 module.mapInstruction(type);
661 Id Builder::makeImageType(Id sampledType, Dim dim, bool depth, bool arrayed, bool ms, unsigned sampled,
664 assert(sampled == 1 || sampled == 2);
668 for (int t = 0; t < (int)groupedTypes[OpTypeImage].size(); ++t) {
669 type = groupedTypes[OpTypeImage][t];
670 if (type->getIdOperand(0) == sampledType &&
671 type->getImmediateOperand(1) == (unsigned int)dim &&
672 type->getImmediateOperand(2) == ( depth ? 1u : 0u) &&
673 type->getImmediateOperand(3) == (arrayed ? 1u : 0u) &&
674 type->getImmediateOperand(4) == ( ms ? 1u : 0u) &&
675 type->getImmediateOperand(5) == sampled &&
676 type->getImmediateOperand(6) == (unsigned int)format)
677 return type->getResultId();
680 // not found, make it
681 type = new Instruction(getUniqueId(), NoType, OpTypeImage);
682 type->addIdOperand(sampledType);
683 type->addImmediateOperand( dim);
684 type->addImmediateOperand( depth ? 1 : 0);
685 type->addImmediateOperand(arrayed ? 1 : 0);
686 type->addImmediateOperand( ms ? 1 : 0);
687 type->addImmediateOperand(sampled);
688 type->addImmediateOperand((unsigned int)format);
690 groupedTypes[OpTypeImage].push_back(type);
691 constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(type));
692 module.mapInstruction(type);
695 // deal with capabilities
699 addCapability(CapabilitySampledBuffer);
701 addCapability(CapabilityImageBuffer);
705 addCapability(CapabilitySampled1D);
707 addCapability(CapabilityImage1D);
712 addCapability(CapabilitySampledCubeArray);
714 addCapability(CapabilityImageCubeArray);
719 addCapability(CapabilitySampledRect);
721 addCapability(CapabilityImageRect);
724 addCapability(CapabilityInputAttachment);
732 // Images used with subpass data are not storage
733 // images, so don't require the capability for them.
734 if (dim != Dim::DimSubpassData)
735 addCapability(CapabilityStorageImageMultisample);
737 addCapability(CapabilityImageMSArray);
742 if (emitNonSemanticShaderDebugInfo)
744 auto TypeName = [&dim]() -> char const* {
746 case Dim1D: return "type.1d.image";
747 case Dim2D: return "type.2d.image";
748 case Dim3D: return "type.3d.image";
749 case DimCube: return "type.cube.image";
750 default: return "type.image";
754 auto const debugResultId = makeCompositeDebugType({}, TypeName(), NonSemanticShaderDebugInfo100Class, true);
755 debugId[type->getResultId()] = debugResultId;
758 return type->getResultId();
761 Id Builder::makeSampledImageType(Id imageType)
765 for (int t = 0; t < (int)groupedTypes[OpTypeSampledImage].size(); ++t) {
766 type = groupedTypes[OpTypeSampledImage][t];
767 if (type->getIdOperand(0) == imageType)
768 return type->getResultId();
771 // not found, make it
772 type = new Instruction(getUniqueId(), NoType, OpTypeSampledImage);
773 type->addIdOperand(imageType);
775 groupedTypes[OpTypeSampledImage].push_back(type);
776 constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(type));
777 module.mapInstruction(type);
779 if (emitNonSemanticShaderDebugInfo)
781 auto const debugResultId = makeCompositeDebugType({}, "type.sampled.image", NonSemanticShaderDebugInfo100Class, true);
782 debugId[type->getResultId()] = debugResultId;
785 return type->getResultId();
788 Id Builder::makeDebugInfoNone()
790 if (debugInfoNone != 0)
791 return debugInfoNone;
793 Instruction* inst = new Instruction(getUniqueId(), makeVoidType(), OpExtInst);
794 inst->addIdOperand(nonSemanticShaderDebugInfo);
795 inst->addImmediateOperand(NonSemanticShaderDebugInfo100DebugInfoNone);
797 constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(inst));
798 module.mapInstruction(inst);
800 debugInfoNone = inst->getResultId();
802 return debugInfoNone;
805 Id Builder::makeBoolDebugType(int const size)
809 for (int t = 0; t < (int)groupedDebugTypes[NonSemanticShaderDebugInfo100DebugTypeBasic].size(); ++t) {
810 type = groupedDebugTypes[NonSemanticShaderDebugInfo100DebugTypeBasic][t];
811 if (type->getIdOperand(0) == getStringId("bool") &&
812 type->getIdOperand(1) == static_cast<unsigned int>(size) &&
813 type->getIdOperand(2) == NonSemanticShaderDebugInfo100Boolean)
814 return type->getResultId();
817 type = new Instruction(getUniqueId(), makeVoidType(), OpExtInst);
818 type->addIdOperand(nonSemanticShaderDebugInfo);
819 type->addImmediateOperand(NonSemanticShaderDebugInfo100DebugTypeBasic);
821 type->addIdOperand(getStringId("bool")); // name id
822 type->addIdOperand(makeUintConstant(size)); // size id
823 type->addIdOperand(makeUintConstant(NonSemanticShaderDebugInfo100Boolean)); // encoding id
824 type->addIdOperand(makeUintConstant(NonSemanticShaderDebugInfo100None)); // flags id
826 groupedDebugTypes[NonSemanticShaderDebugInfo100DebugTypeBasic].push_back(type);
827 constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(type));
828 module.mapInstruction(type);
830 return type->getResultId();
833 Id Builder::makeIntegerDebugType(int const width, bool const hasSign)
837 for (int t = 0; t < (int)groupedDebugTypes[NonSemanticShaderDebugInfo100DebugTypeBasic].size(); ++t) {
838 type = groupedDebugTypes[NonSemanticShaderDebugInfo100DebugTypeBasic][t];
839 if (type->getIdOperand(0) == (hasSign ? getStringId("int") : getStringId("uint")) &&
840 type->getIdOperand(1) == static_cast<unsigned int>(width) &&
841 type->getIdOperand(2) == (hasSign ? NonSemanticShaderDebugInfo100Signed : NonSemanticShaderDebugInfo100Unsigned))
842 return type->getResultId();
845 // not found, make it
846 type = new Instruction(getUniqueId(), makeVoidType(), OpExtInst);
847 type->addIdOperand(nonSemanticShaderDebugInfo);
848 type->addImmediateOperand(NonSemanticShaderDebugInfo100DebugTypeBasic);
849 if(hasSign == true) {
850 type->addIdOperand(getStringId("int")); // name id
852 type->addIdOperand(getStringId("uint")); // name id
854 type->addIdOperand(makeUintConstant(width)); // size id
855 if(hasSign == true) {
856 type->addIdOperand(makeUintConstant(NonSemanticShaderDebugInfo100Signed)); // encoding id
858 type->addIdOperand(makeUintConstant(NonSemanticShaderDebugInfo100Unsigned)); // encoding id
860 type->addIdOperand(makeUintConstant(NonSemanticShaderDebugInfo100None)); // flags id
862 groupedDebugTypes[NonSemanticShaderDebugInfo100DebugTypeBasic].push_back(type);
863 constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(type));
864 module.mapInstruction(type);
866 return type->getResultId();
869 Id Builder::makeFloatDebugType(int const width)
873 for (int t = 0; t < (int)groupedDebugTypes[NonSemanticShaderDebugInfo100DebugTypeBasic].size(); ++t) {
874 type = groupedDebugTypes[NonSemanticShaderDebugInfo100DebugTypeBasic][t];
875 if (type->getIdOperand(0) == getStringId("float") &&
876 type->getIdOperand(1) == static_cast<unsigned int>(width) &&
877 type->getIdOperand(2) == NonSemanticShaderDebugInfo100Float)
878 return type->getResultId();
881 // not found, make it
882 type = new Instruction(getUniqueId(), makeVoidType(), OpExtInst);
883 type->addIdOperand(nonSemanticShaderDebugInfo);
884 type->addImmediateOperand(NonSemanticShaderDebugInfo100DebugTypeBasic);
885 type->addIdOperand(getStringId("float")); // name id
886 type->addIdOperand(makeUintConstant(width)); // size id
887 type->addIdOperand(makeUintConstant(NonSemanticShaderDebugInfo100Float)); // encoding id
888 type->addIdOperand(makeUintConstant(NonSemanticShaderDebugInfo100None)); // flags id
890 groupedDebugTypes[NonSemanticShaderDebugInfo100DebugTypeBasic].push_back(type);
891 constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(type));
892 module.mapInstruction(type);
894 return type->getResultId();
897 Id Builder::makeSequentialDebugType(Id const baseType, Id const componentCount, NonSemanticShaderDebugInfo100Instructions const sequenceType)
899 assert(sequenceType == NonSemanticShaderDebugInfo100DebugTypeArray ||
900 sequenceType == NonSemanticShaderDebugInfo100DebugTypeVector);
904 for (int t = 0; t < (int)groupedDebugTypes[sequenceType].size(); ++t) {
905 type = groupedDebugTypes[sequenceType][t];
906 if (type->getIdOperand(0) == baseType &&
907 type->getIdOperand(1) == makeUintConstant(componentCount))
908 return type->getResultId();
911 // not found, make it
912 type = new Instruction(getUniqueId(), makeVoidType(), OpExtInst);
913 type->addIdOperand(nonSemanticShaderDebugInfo);
914 type->addImmediateOperand(sequenceType);
915 type->addIdOperand(debugId[baseType]); // base type
916 type->addIdOperand(componentCount); // component count
918 groupedDebugTypes[sequenceType].push_back(type);
919 constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(type));
920 module.mapInstruction(type);
922 return type->getResultId();
925 Id Builder::makeArrayDebugType(Id const baseType, Id const componentCount)
927 return makeSequentialDebugType(baseType, componentCount, NonSemanticShaderDebugInfo100DebugTypeArray);
930 Id Builder::makeVectorDebugType(Id const baseType, int const componentCount)
932 return makeSequentialDebugType(baseType, makeUintConstant(componentCount), NonSemanticShaderDebugInfo100DebugTypeVector);;
935 Id Builder::makeMatrixDebugType(Id const vectorType, int const vectorCount, bool columnMajor)
939 for (int t = 0; t < (int)groupedDebugTypes[NonSemanticShaderDebugInfo100DebugTypeMatrix].size(); ++t) {
940 type = groupedDebugTypes[NonSemanticShaderDebugInfo100DebugTypeMatrix][t];
941 if (type->getIdOperand(0) == vectorType &&
942 type->getIdOperand(1) == makeUintConstant(vectorCount))
943 return type->getResultId();
946 // not found, make it
947 type = new Instruction(getUniqueId(), makeVoidType(), OpExtInst);
948 type->addIdOperand(nonSemanticShaderDebugInfo);
949 type->addImmediateOperand(NonSemanticShaderDebugInfo100DebugTypeMatrix);
950 type->addIdOperand(debugId[vectorType]); // vector type id
951 type->addIdOperand(makeUintConstant(vectorCount)); // component count id
952 type->addIdOperand(makeBoolConstant(columnMajor)); // column-major id
954 groupedDebugTypes[NonSemanticShaderDebugInfo100DebugTypeMatrix].push_back(type);
955 constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(type));
956 module.mapInstruction(type);
958 return type->getResultId();
961 Id Builder::makeMemberDebugType(Id const memberType, DebugTypeLoc const& debugTypeLoc)
963 assert(debugId[memberType] != 0);
965 Instruction* type = new Instruction(getUniqueId(), makeVoidType(), OpExtInst);
966 type->addIdOperand(nonSemanticShaderDebugInfo);
967 type->addImmediateOperand(NonSemanticShaderDebugInfo100DebugTypeMember);
968 type->addIdOperand(getStringId(debugTypeLoc.name)); // name id
969 type->addIdOperand(debugId[memberType]); // type id
970 type->addIdOperand(makeDebugSource(sourceFileStringId)); // source id TODO: verify this works across include directives
971 type->addIdOperand(makeUintConstant(debugTypeLoc.line)); // line id TODO: currentLine is always zero
972 type->addIdOperand(makeUintConstant(debugTypeLoc.column)); // TODO: column id
973 type->addIdOperand(makeUintConstant(0)); // TODO: offset id
974 type->addIdOperand(makeUintConstant(0)); // TODO: size id
975 type->addIdOperand(makeUintConstant(NonSemanticShaderDebugInfo100FlagIsPublic)); // flags id
977 groupedDebugTypes[NonSemanticShaderDebugInfo100DebugTypeMember].push_back(type);
978 constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(type));
979 module.mapInstruction(type);
981 return type->getResultId();
984 // Note: To represent a source language opaque type, this instruction must have no Members operands, Size operand must be
985 // DebugInfoNone, and Name must start with @ to avoid clashes with user defined names.
986 Id Builder::makeCompositeDebugType(std::vector<Id> const& memberTypes, char const*const name,
987 NonSemanticShaderDebugInfo100DebugCompositeType const tag, bool const isOpaqueType)
989 // Create the debug member types.
990 std::vector<Id> memberDebugTypes;
991 for(auto const memberType : memberTypes) {
992 assert(debugTypeLocs.find(memberType) != debugTypeLocs.end());
994 memberDebugTypes.emplace_back(makeMemberDebugType(memberType, debugTypeLocs[memberType]));
996 // TODO: Need to rethink this method of passing location information.
997 // debugTypeLocs.erase(memberType);
1000 // Create The structure debug type.
1001 Instruction* type = new Instruction(getUniqueId(), makeVoidType(), OpExtInst);
1002 type->addIdOperand(nonSemanticShaderDebugInfo);
1003 type->addImmediateOperand(NonSemanticShaderDebugInfo100DebugTypeComposite);
1004 type->addIdOperand(getStringId(name)); // name id
1005 type->addIdOperand(makeUintConstant(tag)); // tag id
1006 type->addIdOperand(makeDebugSource(sourceFileStringId)); // source id TODO: verify this works across include directives
1007 type->addIdOperand(makeUintConstant(currentLine)); // line id TODO: currentLine always zero?
1008 type->addIdOperand(makeUintConstant(0)); // TODO: column id
1009 type->addIdOperand(makeDebugCompilationUnit()); // scope id
1010 if(isOpaqueType == true) {
1011 // Prepend '@' to opaque types.
1012 type->addIdOperand(getStringId('@' + std::string(name))); // linkage name id
1013 type->addIdOperand(makeDebugInfoNone()); // size id
1015 type->addIdOperand(getStringId(name)); // linkage name id
1016 type->addIdOperand(makeUintConstant(0)); // TODO: size id
1018 type->addIdOperand(makeUintConstant(NonSemanticShaderDebugInfo100FlagIsPublic)); // flags id
1019 assert(isOpaqueType == false || (isOpaqueType == true && memberDebugTypes.empty()));
1020 for(auto const memberDebugType : memberDebugTypes) {
1021 type->addIdOperand(memberDebugType);
1024 groupedDebugTypes[NonSemanticShaderDebugInfo100DebugTypeComposite].push_back(type);
1025 constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(type));
1026 module.mapInstruction(type);
1028 return type->getResultId();
1031 Id Builder::makeDebugSource(const Id fileName) {
1032 if (debugSourceId.find(fileName) != debugSourceId.end())
1033 return debugSourceId[fileName];
1034 spv::Id resultId = getUniqueId();
1035 Instruction* sourceInst = new Instruction(resultId, makeVoidType(), OpExtInst);
1036 sourceInst->addIdOperand(nonSemanticShaderDebugInfo);
1037 sourceInst->addImmediateOperand(NonSemanticShaderDebugInfo100DebugSource);
1038 sourceInst->addIdOperand(fileName);
1039 if (emitNonSemanticShaderDebugSource) {
1040 spv::Id sourceId = 0;
1041 if (fileName == sourceFileStringId) {
1042 sourceId = getStringId(sourceText);
1044 auto incItr = includeFiles.find(fileName);
1045 assert(incItr != includeFiles.end());
1046 sourceId = getStringId(*incItr->second);
1048 sourceInst->addIdOperand(sourceId);
1050 constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(sourceInst));
1051 module.mapInstruction(sourceInst);
1052 debugSourceId[fileName] = resultId;
1056 Id Builder::makeDebugCompilationUnit() {
1057 if (nonSemanticShaderCompilationUnitId != 0)
1058 return nonSemanticShaderCompilationUnitId;
1059 spv::Id resultId = getUniqueId();
1060 Instruction* sourceInst = new Instruction(resultId, makeVoidType(), OpExtInst);
1061 sourceInst->addIdOperand(nonSemanticShaderDebugInfo);
1062 sourceInst->addImmediateOperand(NonSemanticShaderDebugInfo100DebugCompilationUnit);
1063 sourceInst->addIdOperand(makeUintConstant(1)); // TODO(greg-lunarg): Get rid of magic number
1064 sourceInst->addIdOperand(makeUintConstant(4)); // TODO(greg-lunarg): Get rid of magic number
1065 sourceInst->addIdOperand(makeDebugSource(sourceFileStringId));
1066 sourceInst->addIdOperand(makeUintConstant(sourceLang));
1067 constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(sourceInst));
1068 module.mapInstruction(sourceInst);
1069 nonSemanticShaderCompilationUnitId = resultId;
1073 Id Builder::createDebugGlobalVariable(Id const type, char const*const name, Id const variable)
1077 Instruction* inst = new Instruction(getUniqueId(), makeVoidType(), OpExtInst);
1078 inst->addIdOperand(nonSemanticShaderDebugInfo);
1079 inst->addImmediateOperand(NonSemanticShaderDebugInfo100DebugGlobalVariable);
1080 inst->addIdOperand(getStringId(name)); // name id
1081 inst->addIdOperand(type); // type id
1082 inst->addIdOperand(makeDebugSource(sourceFileStringId)); // source id
1083 inst->addIdOperand(makeUintConstant(currentLine)); // line id TODO: currentLine always zero?
1084 inst->addIdOperand(makeUintConstant(0)); // TODO: column id
1085 inst->addIdOperand(makeDebugCompilationUnit()); // scope id
1086 inst->addIdOperand(getStringId(name)); // linkage name id
1087 inst->addIdOperand(variable); // variable id
1088 inst->addIdOperand(makeUintConstant(NonSemanticShaderDebugInfo100FlagIsDefinition)); // flags id
1090 constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(inst));
1091 module.mapInstruction(inst);
1093 return inst->getResultId();
1096 Id Builder::createDebugLocalVariable(Id type, char const*const name, size_t const argNumber)
1098 assert(name != nullptr);
1099 Instruction* inst = new Instruction(getUniqueId(), makeVoidType(), OpExtInst);
1100 inst->addIdOperand(nonSemanticShaderDebugInfo);
1101 inst->addImmediateOperand(NonSemanticShaderDebugInfo100DebugLocalVariable);
1102 inst->addIdOperand(getStringId(name)); // name id
1103 inst->addIdOperand(type); // type id
1104 inst->addIdOperand(makeDebugSource(sourceFileStringId)); // source id
1105 inst->addIdOperand(makeUintConstant(currentLine)); // line id
1106 inst->addIdOperand(makeUintConstant(0)); // TODO: column id
1107 inst->addIdOperand(currentDebugScopeId.top()); // scope id
1108 inst->addIdOperand(makeUintConstant(NonSemanticShaderDebugInfo100FlagIsLocal)); // flags id
1109 if(argNumber != 0) {
1110 inst->addIdOperand(makeUintConstant(argNumber));
1113 constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(inst));
1114 module.mapInstruction(inst);
1116 return inst->getResultId();
1119 Id Builder::makeDebugExpression()
1121 if (debugExpression != 0)
1122 return debugExpression;
1124 Instruction* inst = new Instruction(getUniqueId(), makeVoidType(), OpExtInst);
1125 inst->addIdOperand(nonSemanticShaderDebugInfo);
1126 inst->addImmediateOperand(NonSemanticShaderDebugInfo100DebugExpression);
1128 constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(inst));
1129 module.mapInstruction(inst);
1131 debugExpression = inst->getResultId();
1133 return debugExpression;
1136 Id Builder::makeDebugDeclare(Id const debugLocalVariable, Id const localVariable)
1138 Instruction* inst = new Instruction(getUniqueId(), makeVoidType(), OpExtInst);
1139 inst->addIdOperand(nonSemanticShaderDebugInfo);
1140 inst->addImmediateOperand(NonSemanticShaderDebugInfo100DebugDeclare);
1141 inst->addIdOperand(debugLocalVariable); // debug local variable id
1142 inst->addIdOperand(localVariable); // local variable id
1143 inst->addIdOperand(makeDebugExpression()); // expression id
1144 buildPoint->addInstruction(std::unique_ptr<Instruction>(inst));
1146 return inst->getResultId();
1150 Id Builder::makeAccelerationStructureType()
1153 if (groupedTypes[OpTypeAccelerationStructureKHR].size() == 0) {
1154 type = new Instruction(getUniqueId(), NoType, OpTypeAccelerationStructureKHR);
1155 groupedTypes[OpTypeAccelerationStructureKHR].push_back(type);
1156 constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(type));
1157 module.mapInstruction(type);
1159 type = groupedTypes[OpTypeAccelerationStructureKHR].back();
1162 return type->getResultId();
1165 Id Builder::makeRayQueryType()
1168 if (groupedTypes[OpTypeRayQueryKHR].size() == 0) {
1169 type = new Instruction(getUniqueId(), NoType, OpTypeRayQueryKHR);
1170 groupedTypes[OpTypeRayQueryKHR].push_back(type);
1171 constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(type));
1172 module.mapInstruction(type);
1174 type = groupedTypes[OpTypeRayQueryKHR].back();
1177 return type->getResultId();
1180 Id Builder::makeHitObjectNVType()
1183 if (groupedTypes[OpTypeHitObjectNV].size() == 0) {
1184 type = new Instruction(getUniqueId(), NoType, OpTypeHitObjectNV);
1185 groupedTypes[OpTypeHitObjectNV].push_back(type);
1186 constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(type));
1187 module.mapInstruction(type);
1189 type = groupedTypes[OpTypeHitObjectNV].back();
1192 return type->getResultId();
1196 Id Builder::getDerefTypeId(Id resultId) const
1198 Id typeId = getTypeId(resultId);
1199 assert(isPointerType(typeId));
1201 return module.getInstruction(typeId)->getIdOperand(1);
1204 Op Builder::getMostBasicTypeClass(Id typeId) const
1206 Instruction* instr = module.getInstruction(typeId);
1208 Op typeClass = instr->getOpCode();
1214 case OpTypeRuntimeArray:
1215 return getMostBasicTypeClass(instr->getIdOperand(0));
1217 return getMostBasicTypeClass(instr->getIdOperand(1));
1223 int Builder::getNumTypeConstituents(Id typeId) const
1225 Instruction* instr = module.getInstruction(typeId);
1227 switch (instr->getOpCode())
1236 return instr->getImmediateOperand(1);
1239 Id lengthId = instr->getIdOperand(1);
1240 return module.getInstruction(lengthId)->getImmediateOperand(0);
1243 return instr->getNumOperands();
1244 case OpTypeCooperativeMatrixNV:
1245 // has only one constituent when used with OpCompositeConstruct.
1253 // Return the lowest-level type of scalar that an homogeneous composite is made out of.
1254 // Typically, this is just to find out if something is made out of ints or floats.
1255 // However, it includes returning a structure, if say, it is an array of structure.
1256 Id Builder::getScalarTypeId(Id typeId) const
1258 Instruction* instr = module.getInstruction(typeId);
1260 Op typeClass = instr->getOpCode();
1268 return instr->getResultId();
1272 case OpTypeRuntimeArray:
1274 return getScalarTypeId(getContainedTypeId(typeId));
1281 // Return the type of 'member' of a composite.
1282 Id Builder::getContainedTypeId(Id typeId, int member) const
1284 Instruction* instr = module.getInstruction(typeId);
1286 Op typeClass = instr->getOpCode();
1292 case OpTypeRuntimeArray:
1293 case OpTypeCooperativeMatrixNV:
1294 return instr->getIdOperand(0);
1296 return instr->getIdOperand(1);
1298 return instr->getIdOperand(member);
1305 // Figure out the final resulting type of the access chain.
1306 Id Builder::getResultingAccessChainType() const
1308 assert(accessChain.base != NoResult);
1309 Id typeId = getTypeId(accessChain.base);
1311 assert(isPointerType(typeId));
1312 typeId = getContainedTypeId(typeId);
1314 for (int i = 0; i < (int)accessChain.indexChain.size(); ++i) {
1315 if (isStructType(typeId)) {
1316 assert(isConstantScalar(accessChain.indexChain[i]));
1317 typeId = getContainedTypeId(typeId, getConstantScalar(accessChain.indexChain[i]));
1319 typeId = getContainedTypeId(typeId, accessChain.indexChain[i]);
1325 // Return the immediately contained type of a given composite type.
1326 Id Builder::getContainedTypeId(Id typeId) const
1328 return getContainedTypeId(typeId, 0);
1331 // Returns true if 'typeId' is or contains a scalar type declared with 'typeOp'
1332 // of width 'width'. The 'width' is only consumed for int and float types.
1333 // Returns false otherwise.
1334 bool Builder::containsType(Id typeId, spv::Op typeOp, unsigned int width) const
1336 const Instruction& instr = *module.getInstruction(typeId);
1338 Op typeClass = instr.getOpCode();
1343 return typeClass == typeOp && instr.getImmediateOperand(0) == width;
1345 for (int m = 0; m < instr.getNumOperands(); ++m) {
1346 if (containsType(instr.getIdOperand(m), typeOp, width))
1355 case OpTypeRuntimeArray:
1356 return containsType(getContainedTypeId(typeId), typeOp, width);
1358 return typeClass == typeOp;
1362 // return true if the type is a pointer to PhysicalStorageBufferEXT or an
1363 // array of such pointers. These require restrict/aliased decorations.
1364 bool Builder::containsPhysicalStorageBufferOrArray(Id typeId) const
1366 const Instruction& instr = *module.getInstruction(typeId);
1368 Op typeClass = instr.getOpCode();
1372 return getTypeStorageClass(typeId) == StorageClassPhysicalStorageBufferEXT;
1374 return containsPhysicalStorageBufferOrArray(getContainedTypeId(typeId));
1380 // See if a scalar constant of this type has already been created, so it
1381 // can be reused rather than duplicated. (Required by the specification).
1382 Id Builder::findScalarConstant(Op typeClass, Op opcode, Id typeId, unsigned value)
1384 Instruction* constant;
1385 for (int i = 0; i < (int)groupedConstants[typeClass].size(); ++i) {
1386 constant = groupedConstants[typeClass][i];
1387 if (constant->getOpCode() == opcode &&
1388 constant->getTypeId() == typeId &&
1389 constant->getImmediateOperand(0) == value)
1390 return constant->getResultId();
1396 // Version of findScalarConstant (see above) for scalars that take two operands (e.g. a 'double' or 'int64').
1397 Id Builder::findScalarConstant(Op typeClass, Op opcode, Id typeId, unsigned v1, unsigned v2)
1399 Instruction* constant;
1400 for (int i = 0; i < (int)groupedConstants[typeClass].size(); ++i) {
1401 constant = groupedConstants[typeClass][i];
1402 if (constant->getOpCode() == opcode &&
1403 constant->getTypeId() == typeId &&
1404 constant->getImmediateOperand(0) == v1 &&
1405 constant->getImmediateOperand(1) == v2)
1406 return constant->getResultId();
1412 // Return true if consuming 'opcode' means consuming a constant.
1413 // "constant" here means after final transform to executable code,
1414 // the value consumed will be a constant, so includes specialization.
1415 bool Builder::isConstantOpCode(Op opcode) const
1419 case OpConstantTrue:
1420 case OpConstantFalse:
1422 case OpConstantComposite:
1423 case OpConstantSampler:
1424 case OpConstantNull:
1425 case OpSpecConstantTrue:
1426 case OpSpecConstantFalse:
1427 case OpSpecConstant:
1428 case OpSpecConstantComposite:
1429 case OpSpecConstantOp:
1436 // Return true if consuming 'opcode' means consuming a specialization constant.
1437 bool Builder::isSpecConstantOpCode(Op opcode) const
1440 case OpSpecConstantTrue:
1441 case OpSpecConstantFalse:
1442 case OpSpecConstant:
1443 case OpSpecConstantComposite:
1444 case OpSpecConstantOp:
1451 bool Builder::isRayTracingOpCode(Op opcode) const
1454 case OpTypeAccelerationStructureKHR:
1455 case OpTypeRayQueryKHR:
1462 Id Builder::makeNullConstant(Id typeId)
1464 Instruction* constant;
1466 // See if we already made it.
1467 Id existing = NoResult;
1468 for (int i = 0; i < (int)nullConstants.size(); ++i) {
1469 constant = nullConstants[i];
1470 if (constant->getTypeId() == typeId)
1471 existing = constant->getResultId();
1474 if (existing != NoResult)
1478 Instruction* c = new Instruction(getUniqueId(), typeId, OpConstantNull);
1479 constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(c));
1480 nullConstants.push_back(c);
1481 module.mapInstruction(c);
1483 return c->getResultId();
1486 Id Builder::makeBoolConstant(bool b, bool specConstant)
1488 Id typeId = makeBoolType();
1489 Instruction* constant;
1490 Op opcode = specConstant ? (b ? OpSpecConstantTrue : OpSpecConstantFalse) : (b ? OpConstantTrue : OpConstantFalse);
1492 // See if we already made it. Applies only to regular constants, because specialization constants
1493 // must remain distinct for the purpose of applying a SpecId decoration.
1494 if (! specConstant) {
1496 for (int i = 0; i < (int)groupedConstants[OpTypeBool].size(); ++i) {
1497 constant = groupedConstants[OpTypeBool][i];
1498 if (constant->getTypeId() == typeId && constant->getOpCode() == opcode)
1499 existing = constant->getResultId();
1507 Instruction* c = new Instruction(getUniqueId(), typeId, opcode);
1508 constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(c));
1509 groupedConstants[OpTypeBool].push_back(c);
1510 module.mapInstruction(c);
1512 return c->getResultId();
1515 Id Builder::makeIntConstant(Id typeId, unsigned value, bool specConstant)
1517 Op opcode = specConstant ? OpSpecConstant : OpConstant;
1519 // See if we already made it. Applies only to regular constants, because specialization constants
1520 // must remain distinct for the purpose of applying a SpecId decoration.
1521 if (! specConstant) {
1522 Id existing = findScalarConstant(OpTypeInt, opcode, typeId, value);
1527 Instruction* c = new Instruction(getUniqueId(), typeId, opcode);
1528 c->addImmediateOperand(value);
1529 constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(c));
1530 groupedConstants[OpTypeInt].push_back(c);
1531 module.mapInstruction(c);
1533 return c->getResultId();
1536 Id Builder::makeInt64Constant(Id typeId, unsigned long long value, bool specConstant)
1538 Op opcode = specConstant ? OpSpecConstant : OpConstant;
1540 unsigned op1 = value & 0xFFFFFFFF;
1541 unsigned op2 = value >> 32;
1543 // See if we already made it. Applies only to regular constants, because specialization constants
1544 // must remain distinct for the purpose of applying a SpecId decoration.
1545 if (! specConstant) {
1546 Id existing = findScalarConstant(OpTypeInt, opcode, typeId, op1, op2);
1551 Instruction* c = new Instruction(getUniqueId(), typeId, opcode);
1552 c->addImmediateOperand(op1);
1553 c->addImmediateOperand(op2);
1554 constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(c));
1555 groupedConstants[OpTypeInt].push_back(c);
1556 module.mapInstruction(c);
1558 return c->getResultId();
1561 Id Builder::makeFloatConstant(float f, bool specConstant)
1563 Op opcode = specConstant ? OpSpecConstant : OpConstant;
1564 Id typeId = makeFloatType(32);
1565 union { float fl; unsigned int ui; } u;
1567 unsigned value = u.ui;
1569 // See if we already made it. Applies only to regular constants, because specialization constants
1570 // must remain distinct for the purpose of applying a SpecId decoration.
1571 if (! specConstant) {
1572 Id existing = findScalarConstant(OpTypeFloat, opcode, typeId, value);
1577 Instruction* c = new Instruction(getUniqueId(), typeId, opcode);
1578 c->addImmediateOperand(value);
1579 constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(c));
1580 groupedConstants[OpTypeFloat].push_back(c);
1581 module.mapInstruction(c);
1583 return c->getResultId();
1586 Id Builder::makeDoubleConstant(double d, bool specConstant)
1592 Op opcode = specConstant ? OpSpecConstant : OpConstant;
1593 Id typeId = makeFloatType(64);
1594 union { double db; unsigned long long ull; } u;
1596 unsigned long long value = u.ull;
1597 unsigned op1 = value & 0xFFFFFFFF;
1598 unsigned op2 = value >> 32;
1600 // See if we already made it. Applies only to regular constants, because specialization constants
1601 // must remain distinct for the purpose of applying a SpecId decoration.
1602 if (! specConstant) {
1603 Id existing = findScalarConstant(OpTypeFloat, opcode, typeId, op1, op2);
1608 Instruction* c = new Instruction(getUniqueId(), typeId, opcode);
1609 c->addImmediateOperand(op1);
1610 c->addImmediateOperand(op2);
1611 constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(c));
1612 groupedConstants[OpTypeFloat].push_back(c);
1613 module.mapInstruction(c);
1615 return c->getResultId();
1619 Id Builder::makeFloat16Constant(float f16, bool specConstant)
1625 Op opcode = specConstant ? OpSpecConstant : OpConstant;
1626 Id typeId = makeFloatType(16);
1628 spvutils::HexFloat<spvutils::FloatProxy<float>> fVal(f16);
1629 spvutils::HexFloat<spvutils::FloatProxy<spvutils::Float16>> f16Val(0);
1630 fVal.castTo(f16Val, spvutils::kRoundToZero);
1632 unsigned value = f16Val.value().getAsFloat().get_value();
1634 // See if we already made it. Applies only to regular constants, because specialization constants
1635 // must remain distinct for the purpose of applying a SpecId decoration.
1636 if (!specConstant) {
1637 Id existing = findScalarConstant(OpTypeFloat, opcode, typeId, value);
1642 Instruction* c = new Instruction(getUniqueId(), typeId, opcode);
1643 c->addImmediateOperand(value);
1644 constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(c));
1645 groupedConstants[OpTypeFloat].push_back(c);
1646 module.mapInstruction(c);
1648 return c->getResultId();
1652 Id Builder::makeFpConstant(Id type, double d, bool specConstant)
1655 const int width = 32;
1656 assert(width == getScalarTypeWidth(type));
1658 const int width = getScalarTypeWidth(type);
1661 assert(isFloatType(type));
1665 return makeFloat16Constant((float)d, specConstant);
1667 return makeFloatConstant((float)d, specConstant);
1669 return makeDoubleConstant(d, specConstant);
1678 Id Builder::importNonSemanticShaderDebugInfoInstructions()
1680 assert(emitNonSemanticShaderDebugInfo == true);
1682 if(nonSemanticShaderDebugInfo == 0)
1684 this->addExtension(spv::E_SPV_KHR_non_semantic_info);
1685 nonSemanticShaderDebugInfo = this->import("NonSemantic.Shader.DebugInfo.100");
1688 return nonSemanticShaderDebugInfo;
1691 Id Builder::findCompositeConstant(Op typeClass, Id typeId, const std::vector<Id>& comps)
1693 Instruction* constant = nullptr;
1695 for (int i = 0; i < (int)groupedConstants[typeClass].size(); ++i) {
1696 constant = groupedConstants[typeClass][i];
1698 if (constant->getTypeId() != typeId)
1702 bool mismatch = false;
1703 for (int op = 0; op < constant->getNumOperands(); ++op) {
1704 if (constant->getIdOperand(op) != comps[op]) {
1715 return found ? constant->getResultId() : NoResult;
1718 Id Builder::findStructConstant(Id typeId, const std::vector<Id>& comps)
1720 Instruction* constant = nullptr;
1722 for (int i = 0; i < (int)groupedStructConstants[typeId].size(); ++i) {
1723 constant = groupedStructConstants[typeId][i];
1726 bool mismatch = false;
1727 for (int op = 0; op < constant->getNumOperands(); ++op) {
1728 if (constant->getIdOperand(op) != comps[op]) {
1739 return found ? constant->getResultId() : NoResult;
1742 // Comments in header
1743 Id Builder::makeCompositeConstant(Id typeId, const std::vector<Id>& members, bool specConstant)
1745 Op opcode = specConstant ? OpSpecConstantComposite : OpConstantComposite;
1747 Op typeClass = getTypeClass(typeId);
1749 switch (typeClass) {
1753 case OpTypeCooperativeMatrixNV:
1754 if (! specConstant) {
1755 Id existing = findCompositeConstant(typeClass, typeId, members);
1761 if (! specConstant) {
1762 Id existing = findStructConstant(typeId, members);
1769 return makeFloatConstant(0.0);
1772 Instruction* c = new Instruction(getUniqueId(), typeId, opcode);
1773 for (int op = 0; op < (int)members.size(); ++op)
1774 c->addIdOperand(members[op]);
1775 constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(c));
1776 if (typeClass == OpTypeStruct)
1777 groupedStructConstants[typeId].push_back(c);
1779 groupedConstants[typeClass].push_back(c);
1780 module.mapInstruction(c);
1782 return c->getResultId();
1785 Instruction* Builder::addEntryPoint(ExecutionModel model, Function* function, const char* name)
1787 Instruction* entryPoint = new Instruction(OpEntryPoint);
1788 entryPoint->addImmediateOperand(model);
1789 entryPoint->addIdOperand(function->getId());
1790 entryPoint->addStringOperand(name);
1792 entryPoints.push_back(std::unique_ptr<Instruction>(entryPoint));
1797 // Currently relying on the fact that all 'value' of interest are small non-negative values.
1798 void Builder::addExecutionMode(Function* entryPoint, ExecutionMode mode, int value1, int value2, int value3)
1800 Instruction* instr = new Instruction(OpExecutionMode);
1801 instr->addIdOperand(entryPoint->getId());
1802 instr->addImmediateOperand(mode);
1804 instr->addImmediateOperand(value1);
1806 instr->addImmediateOperand(value2);
1808 instr->addImmediateOperand(value3);
1810 executionModes.push_back(std::unique_ptr<Instruction>(instr));
1813 void Builder::addExecutionMode(Function* entryPoint, ExecutionMode mode, const std::vector<unsigned>& literals)
1815 Instruction* instr = new Instruction(OpExecutionMode);
1816 instr->addIdOperand(entryPoint->getId());
1817 instr->addImmediateOperand(mode);
1818 for (auto literal : literals)
1819 instr->addImmediateOperand(literal);
1821 executionModes.push_back(std::unique_ptr<Instruction>(instr));
1824 void Builder::addExecutionModeId(Function* entryPoint, ExecutionMode mode, const std::vector<Id>& operandIds)
1826 Instruction* instr = new Instruction(OpExecutionModeId);
1827 instr->addIdOperand(entryPoint->getId());
1828 instr->addImmediateOperand(mode);
1829 for (auto operandId : operandIds)
1830 instr->addIdOperand(operandId);
1832 executionModes.push_back(std::unique_ptr<Instruction>(instr));
1835 void Builder::addName(Id id, const char* string)
1837 Instruction* name = new Instruction(OpName);
1838 name->addIdOperand(id);
1839 name->addStringOperand(string);
1841 names.push_back(std::unique_ptr<Instruction>(name));
1844 void Builder::addMemberName(Id id, int memberNumber, const char* string)
1846 Instruction* name = new Instruction(OpMemberName);
1847 name->addIdOperand(id);
1848 name->addImmediateOperand(memberNumber);
1849 name->addStringOperand(string);
1851 names.push_back(std::unique_ptr<Instruction>(name));
1854 void Builder::addDecoration(Id id, Decoration decoration, int num)
1856 if (decoration == spv::DecorationMax)
1859 Instruction* dec = new Instruction(OpDecorate);
1860 dec->addIdOperand(id);
1861 dec->addImmediateOperand(decoration);
1863 dec->addImmediateOperand(num);
1865 decorations.push_back(std::unique_ptr<Instruction>(dec));
1868 void Builder::addDecoration(Id id, Decoration decoration, const char* s)
1870 if (decoration == spv::DecorationMax)
1873 Instruction* dec = new Instruction(OpDecorateString);
1874 dec->addIdOperand(id);
1875 dec->addImmediateOperand(decoration);
1876 dec->addStringOperand(s);
1878 decorations.push_back(std::unique_ptr<Instruction>(dec));
1881 void Builder::addDecoration(Id id, Decoration decoration, const std::vector<unsigned>& literals)
1883 if (decoration == spv::DecorationMax)
1886 Instruction* dec = new Instruction(OpDecorate);
1887 dec->addIdOperand(id);
1888 dec->addImmediateOperand(decoration);
1889 for (auto literal : literals)
1890 dec->addImmediateOperand(literal);
1892 decorations.push_back(std::unique_ptr<Instruction>(dec));
1895 void Builder::addDecoration(Id id, Decoration decoration, const std::vector<const char*>& strings)
1897 if (decoration == spv::DecorationMax)
1900 Instruction* dec = new Instruction(OpDecorateString);
1901 dec->addIdOperand(id);
1902 dec->addImmediateOperand(decoration);
1903 for (auto string : strings)
1904 dec->addStringOperand(string);
1906 decorations.push_back(std::unique_ptr<Instruction>(dec));
1909 void Builder::addDecorationId(Id id, Decoration decoration, Id idDecoration)
1911 if (decoration == spv::DecorationMax)
1914 Instruction* dec = new Instruction(OpDecorateId);
1915 dec->addIdOperand(id);
1916 dec->addImmediateOperand(decoration);
1917 dec->addIdOperand(idDecoration);
1919 decorations.push_back(std::unique_ptr<Instruction>(dec));
1922 void Builder::addDecorationId(Id id, Decoration decoration, const std::vector<Id>& operandIds)
1924 if(decoration == spv::DecorationMax)
1927 Instruction* dec = new Instruction(OpDecorateId);
1928 dec->addIdOperand(id);
1929 dec->addImmediateOperand(decoration);
1931 for (auto operandId : operandIds)
1932 dec->addIdOperand(operandId);
1934 decorations.push_back(std::unique_ptr<Instruction>(dec));
1937 void Builder::addMemberDecoration(Id id, unsigned int member, Decoration decoration, int num)
1939 if (decoration == spv::DecorationMax)
1942 Instruction* dec = new Instruction(OpMemberDecorate);
1943 dec->addIdOperand(id);
1944 dec->addImmediateOperand(member);
1945 dec->addImmediateOperand(decoration);
1947 dec->addImmediateOperand(num);
1949 decorations.push_back(std::unique_ptr<Instruction>(dec));
1952 void Builder::addMemberDecoration(Id id, unsigned int member, Decoration decoration, const char *s)
1954 if (decoration == spv::DecorationMax)
1957 Instruction* dec = new Instruction(OpMemberDecorateStringGOOGLE);
1958 dec->addIdOperand(id);
1959 dec->addImmediateOperand(member);
1960 dec->addImmediateOperand(decoration);
1961 dec->addStringOperand(s);
1963 decorations.push_back(std::unique_ptr<Instruction>(dec));
1966 void Builder::addMemberDecoration(Id id, unsigned int member, Decoration decoration, const std::vector<unsigned>& literals)
1968 if (decoration == spv::DecorationMax)
1971 Instruction* dec = new Instruction(OpMemberDecorate);
1972 dec->addIdOperand(id);
1973 dec->addImmediateOperand(member);
1974 dec->addImmediateOperand(decoration);
1975 for (auto literal : literals)
1976 dec->addImmediateOperand(literal);
1978 decorations.push_back(std::unique_ptr<Instruction>(dec));
1981 void Builder::addMemberDecoration(Id id, unsigned int member, Decoration decoration, const std::vector<const char*>& strings)
1983 if (decoration == spv::DecorationMax)
1986 Instruction* dec = new Instruction(OpMemberDecorateString);
1987 dec->addIdOperand(id);
1988 dec->addImmediateOperand(member);
1989 dec->addImmediateOperand(decoration);
1990 for (auto string : strings)
1991 dec->addStringOperand(string);
1993 decorations.push_back(std::unique_ptr<Instruction>(dec));
1996 // Comments in header
1997 Function* Builder::makeEntryPoint(const char* entryPoint)
1999 assert(! entryPointFunction);
2002 std::vector<Id> paramsTypes;
2003 std::vector<char const*> paramNames;
2004 std::vector<std::vector<Decoration>> decorations;
2006 auto const returnType = makeVoidType();
2008 restoreNonSemanticShaderDebugInfo = emitNonSemanticShaderDebugInfo;
2009 if(sourceLang == spv::SourceLanguageHLSL) {
2010 emitNonSemanticShaderDebugInfo = false;
2013 entryPointFunction = makeFunctionEntry(NoPrecision, returnType, entryPoint, paramsTypes, paramNames, decorations, &entry);
2015 emitNonSemanticShaderDebugInfo = restoreNonSemanticShaderDebugInfo;
2017 return entryPointFunction;
2020 // Comments in header
2021 Function* Builder::makeFunctionEntry(Decoration precision, Id returnType, const char* name,
2022 const std::vector<Id>& paramTypes, const std::vector<char const*>& paramNames,
2023 const std::vector<std::vector<Decoration>>& decorations, Block **entry)
2025 // Make the function and initial instructions in it
2026 Id typeId = makeFunctionType(returnType, paramTypes);
2027 Id firstParamId = paramTypes.size() == 0 ? 0 : getUniqueIds((int)paramTypes.size());
2028 Id funcId = getUniqueId();
2029 Function* function = new Function(funcId, returnType, typeId, firstParamId, module);
2031 // Set up the precisions
2032 setPrecision(function->getId(), precision);
2033 function->setReturnPrecision(precision);
2034 for (unsigned p = 0; p < (unsigned)decorations.size(); ++p) {
2035 for (int d = 0; d < (int)decorations[p].size(); ++d) {
2036 addDecoration(firstParamId + p, decorations[p][d]);
2037 function->addParamPrecision(p, decorations[p][d]);
2041 // Make the debug function instruction
2042 if (emitNonSemanticShaderDebugInfo) {
2043 Id nameId = getStringId(unmangleFunctionName(name));
2044 Id debugFuncId = makeDebugFunction(function, nameId, typeId);
2045 debugId[funcId] = debugFuncId;
2046 currentDebugScopeId.push(debugFuncId);
2047 lastDebugScopeId = NoResult;
2051 assert(entry != nullptr);
2052 *entry = new Block(getUniqueId(), *function);
2053 function->addBlock(*entry);
2054 setBuildPoint(*entry);
2056 // DebugScope and DebugLine for parameter DebugDeclares
2057 if (emitNonSemanticShaderDebugInfo && (int)paramTypes.size() > 0) {
2058 addDebugScopeAndLine(currentFileId, currentLine, 0);
2061 if (emitNonSemanticShaderDebugInfo) {
2062 assert(paramTypes.size() == paramNames.size());
2063 for(size_t p = 0; p < paramTypes.size(); ++p)
2065 auto const& paramType = paramTypes[p];
2066 assert(isPointerType(paramType) || isArrayType(paramType));
2067 assert(debugId[getContainedTypeId(paramType)] != 0);
2068 auto const& paramName = paramNames[p];
2069 auto const debugLocalVariableId = createDebugLocalVariable(debugId[getContainedTypeId(paramType)], paramName, p+1);
2070 debugId[firstParamId + p] = debugLocalVariableId;
2072 makeDebugDeclare(debugLocalVariableId, firstParamId + p);
2077 addName(function->getId(), name);
2079 functions.push_back(std::unique_ptr<Function>(function));
2081 // Clear debug scope stack
2082 if (emitNonSemanticShaderDebugInfo)
2083 currentDebugScopeId.pop();
2088 Id Builder::makeDebugFunction(Function* function, Id nameId, Id funcTypeId) {
2089 assert(function != nullptr);
2090 assert(nameId != 0);
2091 assert(funcTypeId != 0);
2092 assert(debugId[funcTypeId] != 0);
2094 Id funcId = getUniqueId();
2095 auto type = new Instruction(funcId, makeVoidType(), OpExtInst);
2096 type->addIdOperand(nonSemanticShaderDebugInfo);
2097 type->addImmediateOperand(NonSemanticShaderDebugInfo100DebugFunction);
2098 type->addIdOperand(nameId);
2099 type->addIdOperand(debugId[funcTypeId]);
2100 type->addIdOperand(makeDebugSource(currentFileId)); // Will be fixed later when true filename available
2101 type->addIdOperand(makeUintConstant(currentLine)); // Will be fixed later when true line available
2102 type->addIdOperand(makeUintConstant(0)); // column
2103 type->addIdOperand(makeDebugCompilationUnit()); // scope
2104 type->addIdOperand(nameId); // linkage name
2105 type->addIdOperand(makeUintConstant(NonSemanticShaderDebugInfo100FlagIsPublic));
2106 type->addIdOperand(makeUintConstant(currentLine)); // TODO(greg-lunarg): correct scope line
2107 constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(type));
2108 module.mapInstruction(type);
2112 Id Builder::makeDebugLexicalBlock(uint32_t line) {
2113 Id lexId = getUniqueId();
2114 auto lex = new Instruction(lexId, makeVoidType(), OpExtInst);
2115 lex->addIdOperand(nonSemanticShaderDebugInfo);
2116 lex->addImmediateOperand(NonSemanticShaderDebugInfo100DebugLexicalBlock);
2117 lex->addIdOperand(makeDebugSource(currentFileId));
2118 lex->addIdOperand(makeUintConstant(line));
2119 lex->addIdOperand(makeUintConstant(0)); // column
2120 lex->addIdOperand(currentDebugScopeId.top()); // scope
2121 constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(lex));
2122 module.mapInstruction(lex);
2126 std::string Builder::unmangleFunctionName(std::string const& name) const
2128 assert(name.length() > 0);
2130 if(name.rfind('(') != std::string::npos) {
2131 return name.substr(0, name.rfind('('));
2137 // Comments in header
2138 void Builder::makeReturn(bool implicit, Id retVal)
2141 Instruction* inst = new Instruction(NoResult, NoType, OpReturnValue);
2142 inst->addIdOperand(retVal);
2143 buildPoint->addInstruction(std::unique_ptr<Instruction>(inst));
2145 buildPoint->addInstruction(std::unique_ptr<Instruction>(new Instruction(NoResult, NoType, OpReturn)));
2148 createAndSetNoPredecessorBlock("post-return");
2151 // Comments in header
2152 void Builder::enterScope(uint32_t line)
2154 // Generate new lexical scope debug instruction
2155 Id lexId = makeDebugLexicalBlock(line);
2156 currentDebugScopeId.push(lexId);
2157 lastDebugScopeId = NoResult;
2160 // Comments in header
2161 void Builder::leaveScope()
2163 // Pop current scope from stack and clear current scope
2164 currentDebugScopeId.pop();
2165 lastDebugScopeId = NoResult;
2168 // Comments in header
2169 void Builder::enterFunction(Function const* function)
2171 // Save and disable debugInfo for HLSL entry point function. It is a wrapper
2172 // function with no user code in it.
2173 restoreNonSemanticShaderDebugInfo = emitNonSemanticShaderDebugInfo;
2174 if (sourceLang == spv::SourceLanguageHLSL && function == entryPointFunction) {
2175 emitNonSemanticShaderDebugInfo = false;
2178 if (emitNonSemanticShaderDebugInfo) {
2179 // Initialize scope state
2180 Id funcId = function->getFuncId();
2181 currentDebugScopeId.push(debugId[funcId]);
2182 // Create DebugFunctionDefinition
2183 spv::Id resultId = getUniqueId();
2184 Instruction* defInst = new Instruction(resultId, makeVoidType(), OpExtInst);
2185 defInst->addIdOperand(nonSemanticShaderDebugInfo);
2186 defInst->addImmediateOperand(NonSemanticShaderDebugInfo100DebugFunctionDefinition);
2187 defInst->addIdOperand(debugId[funcId]);
2188 defInst->addIdOperand(funcId);
2189 buildPoint->addInstruction(std::unique_ptr<Instruction>(defInst));
2193 // Comments in header
2194 void Builder::leaveFunction()
2196 Block* block = buildPoint;
2197 Function& function = buildPoint->getParent();
2200 // If our function did not contain a return, add a return void now.
2201 if (! block->isTerminated()) {
2202 if (function.getReturnType() == makeVoidType())
2205 makeReturn(true, createUndefined(function.getReturnType()));
2209 // Clear function scope from debug scope stack
2210 if (emitNonSemanticShaderDebugInfo)
2211 currentDebugScopeId.pop();
2213 emitNonSemanticShaderDebugInfo = restoreNonSemanticShaderDebugInfo;
2216 // Comments in header
2217 void Builder::makeStatementTerminator(spv::Op opcode, const char *name)
2219 buildPoint->addInstruction(std::unique_ptr<Instruction>(new Instruction(opcode)));
2220 createAndSetNoPredecessorBlock(name);
2223 // Comments in header
2224 void Builder::makeStatementTerminator(spv::Op opcode, const std::vector<Id>& operands, const char* name)
2226 // It's assumed that the terminator instruction is always of void return type
2227 // However in future if there is a need for non void return type, new helper
2228 // methods can be created.
2229 createNoResultOp(opcode, operands);
2230 createAndSetNoPredecessorBlock(name);
2233 // Comments in header
2234 Id Builder::createVariable(Decoration precision, StorageClass storageClass, Id type, const char* name, Id initializer,
2235 bool const compilerGenerated)
2237 Id pointerType = makePointer(storageClass, type);
2238 Instruction* inst = new Instruction(getUniqueId(), pointerType, OpVariable);
2239 inst->addImmediateOperand(storageClass);
2240 if (initializer != NoResult)
2241 inst->addIdOperand(initializer);
2243 switch (storageClass) {
2244 case StorageClassFunction:
2245 // Validation rules require the declaration in the entry block
2246 buildPoint->getParent().addLocalVariable(std::unique_ptr<Instruction>(inst));
2248 if (emitNonSemanticShaderDebugInfo && !compilerGenerated)
2250 auto const debugLocalVariableId = createDebugLocalVariable(debugId[type], name);
2251 debugId[inst->getResultId()] = debugLocalVariableId;
2253 makeDebugDeclare(debugLocalVariableId, inst->getResultId());
2259 constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(inst));
2260 module.mapInstruction(inst);
2262 if (emitNonSemanticShaderDebugInfo && !isRayTracingOpCode(getOpCode(type)))
2264 auto const debugResultId = createDebugGlobalVariable(debugId[type], name, inst->getResultId());
2265 debugId[inst->getResultId()] = debugResultId;
2271 addName(inst->getResultId(), name);
2272 setPrecision(inst->getResultId(), precision);
2274 return inst->getResultId();
2277 // Comments in header
2278 Id Builder::createUndefined(Id type)
2280 Instruction* inst = new Instruction(getUniqueId(), type, OpUndef);
2281 buildPoint->addInstruction(std::unique_ptr<Instruction>(inst));
2282 return inst->getResultId();
2285 // av/vis/nonprivate are unnecessary and illegal for some storage classes.
2286 spv::MemoryAccessMask Builder::sanitizeMemoryAccessForStorageClass(spv::MemoryAccessMask memoryAccess, StorageClass sc)
2290 case spv::StorageClassUniform:
2291 case spv::StorageClassWorkgroup:
2292 case spv::StorageClassStorageBuffer:
2293 case spv::StorageClassPhysicalStorageBufferEXT:
2296 memoryAccess = spv::MemoryAccessMask(memoryAccess &
2297 ~(spv::MemoryAccessMakePointerAvailableKHRMask |
2298 spv::MemoryAccessMakePointerVisibleKHRMask |
2299 spv::MemoryAccessNonPrivatePointerKHRMask));
2302 return memoryAccess;
2305 // Comments in header
2306 void Builder::createStore(Id rValue, Id lValue, spv::MemoryAccessMask memoryAccess, spv::Scope scope,
2307 unsigned int alignment)
2309 Instruction* store = new Instruction(OpStore);
2310 store->addIdOperand(lValue);
2311 store->addIdOperand(rValue);
2313 memoryAccess = sanitizeMemoryAccessForStorageClass(memoryAccess, getStorageClass(lValue));
2315 if (memoryAccess != MemoryAccessMaskNone) {
2316 store->addImmediateOperand(memoryAccess);
2317 if (memoryAccess & spv::MemoryAccessAlignedMask) {
2318 store->addImmediateOperand(alignment);
2320 if (memoryAccess & spv::MemoryAccessMakePointerAvailableKHRMask) {
2321 store->addIdOperand(makeUintConstant(scope));
2325 buildPoint->addInstruction(std::unique_ptr<Instruction>(store));
2328 // Comments in header
2329 Id Builder::createLoad(Id lValue, spv::Decoration precision, spv::MemoryAccessMask memoryAccess,
2330 spv::Scope scope, unsigned int alignment)
2332 Instruction* load = new Instruction(getUniqueId(), getDerefTypeId(lValue), OpLoad);
2333 load->addIdOperand(lValue);
2335 memoryAccess = sanitizeMemoryAccessForStorageClass(memoryAccess, getStorageClass(lValue));
2337 if (memoryAccess != MemoryAccessMaskNone) {
2338 load->addImmediateOperand(memoryAccess);
2339 if (memoryAccess & spv::MemoryAccessAlignedMask) {
2340 load->addImmediateOperand(alignment);
2342 if (memoryAccess & spv::MemoryAccessMakePointerVisibleKHRMask) {
2343 load->addIdOperand(makeUintConstant(scope));
2347 buildPoint->addInstruction(std::unique_ptr<Instruction>(load));
2348 setPrecision(load->getResultId(), precision);
2350 return load->getResultId();
2353 // Comments in header
2354 Id Builder::createAccessChain(StorageClass storageClass, Id base, const std::vector<Id>& offsets)
2356 // Figure out the final resulting type.
2357 Id typeId = getResultingAccessChainType();
2358 typeId = makePointer(storageClass, typeId);
2360 // Make the instruction
2361 Instruction* chain = new Instruction(getUniqueId(), typeId, OpAccessChain);
2362 chain->addIdOperand(base);
2363 for (int i = 0; i < (int)offsets.size(); ++i)
2364 chain->addIdOperand(offsets[i]);
2365 buildPoint->addInstruction(std::unique_ptr<Instruction>(chain));
2367 return chain->getResultId();
2370 Id Builder::createArrayLength(Id base, unsigned int member)
2372 spv::Id intType = makeUintType(32);
2373 Instruction* length = new Instruction(getUniqueId(), intType, OpArrayLength);
2374 length->addIdOperand(base);
2375 length->addImmediateOperand(member);
2376 buildPoint->addInstruction(std::unique_ptr<Instruction>(length));
2378 return length->getResultId();
2381 Id Builder::createCooperativeMatrixLength(Id type)
2383 spv::Id intType = makeUintType(32);
2385 // Generate code for spec constants if in spec constant operation
2387 if (generatingOpCodeForSpecConst) {
2388 return createSpecConstantOp(OpCooperativeMatrixLengthNV, intType, std::vector<Id>(1, type), std::vector<Id>());
2391 Instruction* length = new Instruction(getUniqueId(), intType, OpCooperativeMatrixLengthNV);
2392 length->addIdOperand(type);
2393 buildPoint->addInstruction(std::unique_ptr<Instruction>(length));
2395 return length->getResultId();
2398 Id Builder::createCompositeExtract(Id composite, Id typeId, unsigned index)
2400 // Generate code for spec constants if in spec constant operation
2402 if (generatingOpCodeForSpecConst) {
2403 return createSpecConstantOp(OpCompositeExtract, typeId, std::vector<Id>(1, composite),
2404 std::vector<Id>(1, index));
2406 Instruction* extract = new Instruction(getUniqueId(), typeId, OpCompositeExtract);
2407 extract->addIdOperand(composite);
2408 extract->addImmediateOperand(index);
2409 buildPoint->addInstruction(std::unique_ptr<Instruction>(extract));
2411 return extract->getResultId();
2414 Id Builder::createCompositeExtract(Id composite, Id typeId, const std::vector<unsigned>& indexes)
2416 // Generate code for spec constants if in spec constant operation
2418 if (generatingOpCodeForSpecConst) {
2419 return createSpecConstantOp(OpCompositeExtract, typeId, std::vector<Id>(1, composite), indexes);
2421 Instruction* extract = new Instruction(getUniqueId(), typeId, OpCompositeExtract);
2422 extract->addIdOperand(composite);
2423 for (int i = 0; i < (int)indexes.size(); ++i)
2424 extract->addImmediateOperand(indexes[i]);
2425 buildPoint->addInstruction(std::unique_ptr<Instruction>(extract));
2427 return extract->getResultId();
2430 Id Builder::createCompositeInsert(Id object, Id composite, Id typeId, unsigned index)
2432 Instruction* insert = new Instruction(getUniqueId(), typeId, OpCompositeInsert);
2433 insert->addIdOperand(object);
2434 insert->addIdOperand(composite);
2435 insert->addImmediateOperand(index);
2436 buildPoint->addInstruction(std::unique_ptr<Instruction>(insert));
2438 return insert->getResultId();
2441 Id Builder::createCompositeInsert(Id object, Id composite, Id typeId, const std::vector<unsigned>& indexes)
2443 Instruction* insert = new Instruction(getUniqueId(), typeId, OpCompositeInsert);
2444 insert->addIdOperand(object);
2445 insert->addIdOperand(composite);
2446 for (int i = 0; i < (int)indexes.size(); ++i)
2447 insert->addImmediateOperand(indexes[i]);
2448 buildPoint->addInstruction(std::unique_ptr<Instruction>(insert));
2450 return insert->getResultId();
2453 Id Builder::createVectorExtractDynamic(Id vector, Id typeId, Id componentIndex)
2455 Instruction* extract = new Instruction(getUniqueId(), typeId, OpVectorExtractDynamic);
2456 extract->addIdOperand(vector);
2457 extract->addIdOperand(componentIndex);
2458 buildPoint->addInstruction(std::unique_ptr<Instruction>(extract));
2460 return extract->getResultId();
2463 Id Builder::createVectorInsertDynamic(Id vector, Id typeId, Id component, Id componentIndex)
2465 Instruction* insert = new Instruction(getUniqueId(), typeId, OpVectorInsertDynamic);
2466 insert->addIdOperand(vector);
2467 insert->addIdOperand(component);
2468 insert->addIdOperand(componentIndex);
2469 buildPoint->addInstruction(std::unique_ptr<Instruction>(insert));
2471 return insert->getResultId();
2474 // An opcode that has no operands, no result id, and no type
2475 void Builder::createNoResultOp(Op opCode)
2477 Instruction* op = new Instruction(opCode);
2478 buildPoint->addInstruction(std::unique_ptr<Instruction>(op));
2481 // An opcode that has one id operand, no result id, and no type
2482 void Builder::createNoResultOp(Op opCode, Id operand)
2484 Instruction* op = new Instruction(opCode);
2485 op->addIdOperand(operand);
2486 buildPoint->addInstruction(std::unique_ptr<Instruction>(op));
2489 // An opcode that has one or more operands, no result id, and no type
2490 void Builder::createNoResultOp(Op opCode, const std::vector<Id>& operands)
2492 Instruction* op = new Instruction(opCode);
2493 for (auto it = operands.cbegin(); it != operands.cend(); ++it) {
2494 op->addIdOperand(*it);
2496 buildPoint->addInstruction(std::unique_ptr<Instruction>(op));
2499 // An opcode that has multiple operands, no result id, and no type
2500 void Builder::createNoResultOp(Op opCode, const std::vector<IdImmediate>& operands)
2502 Instruction* op = new Instruction(opCode);
2503 for (auto it = operands.cbegin(); it != operands.cend(); ++it) {
2505 op->addIdOperand(it->word);
2507 op->addImmediateOperand(it->word);
2509 buildPoint->addInstruction(std::unique_ptr<Instruction>(op));
2512 void Builder::createControlBarrier(Scope execution, Scope memory, MemorySemanticsMask semantics)
2514 Instruction* op = new Instruction(OpControlBarrier);
2515 op->addIdOperand(makeUintConstant(execution));
2516 op->addIdOperand(makeUintConstant(memory));
2517 op->addIdOperand(makeUintConstant(semantics));
2518 buildPoint->addInstruction(std::unique_ptr<Instruction>(op));
2521 void Builder::createMemoryBarrier(unsigned executionScope, unsigned memorySemantics)
2523 Instruction* op = new Instruction(OpMemoryBarrier);
2524 op->addIdOperand(makeUintConstant(executionScope));
2525 op->addIdOperand(makeUintConstant(memorySemantics));
2526 buildPoint->addInstruction(std::unique_ptr<Instruction>(op));
2529 // An opcode that has one operands, a result id, and a type
2530 Id Builder::createUnaryOp(Op opCode, Id typeId, Id operand)
2532 // Generate code for spec constants if in spec constant operation
2534 if (generatingOpCodeForSpecConst) {
2535 return createSpecConstantOp(opCode, typeId, std::vector<Id>(1, operand), std::vector<Id>());
2537 Instruction* op = new Instruction(getUniqueId(), typeId, opCode);
2538 op->addIdOperand(operand);
2539 buildPoint->addInstruction(std::unique_ptr<Instruction>(op));
2541 return op->getResultId();
2544 Id Builder::createBinOp(Op opCode, Id typeId, Id left, Id right)
2546 // Generate code for spec constants if in spec constant operation
2548 if (generatingOpCodeForSpecConst) {
2549 std::vector<Id> operands(2);
2550 operands[0] = left; operands[1] = right;
2551 return createSpecConstantOp(opCode, typeId, operands, std::vector<Id>());
2553 Instruction* op = new Instruction(getUniqueId(), typeId, opCode);
2554 op->addIdOperand(left);
2555 op->addIdOperand(right);
2556 buildPoint->addInstruction(std::unique_ptr<Instruction>(op));
2558 return op->getResultId();
2561 Id Builder::createTriOp(Op opCode, Id typeId, Id op1, Id op2, Id op3)
2563 // Generate code for spec constants if in spec constant operation
2565 if (generatingOpCodeForSpecConst) {
2566 std::vector<Id> operands(3);
2570 return createSpecConstantOp(
2571 opCode, typeId, operands, std::vector<Id>());
2573 Instruction* op = new Instruction(getUniqueId(), typeId, opCode);
2574 op->addIdOperand(op1);
2575 op->addIdOperand(op2);
2576 op->addIdOperand(op3);
2577 buildPoint->addInstruction(std::unique_ptr<Instruction>(op));
2579 return op->getResultId();
2582 Id Builder::createOp(Op opCode, Id typeId, const std::vector<Id>& operands)
2584 Instruction* op = new Instruction(getUniqueId(), typeId, opCode);
2585 for (auto it = operands.cbegin(); it != operands.cend(); ++it)
2586 op->addIdOperand(*it);
2587 buildPoint->addInstruction(std::unique_ptr<Instruction>(op));
2589 return op->getResultId();
2592 Id Builder::createOp(Op opCode, Id typeId, const std::vector<IdImmediate>& operands)
2594 Instruction* op = new Instruction(getUniqueId(), typeId, opCode);
2595 for (auto it = operands.cbegin(); it != operands.cend(); ++it) {
2597 op->addIdOperand(it->word);
2599 op->addImmediateOperand(it->word);
2601 buildPoint->addInstruction(std::unique_ptr<Instruction>(op));
2603 return op->getResultId();
2606 Id Builder::createSpecConstantOp(Op opCode, Id typeId, const std::vector<Id>& operands,
2607 const std::vector<unsigned>& literals)
2609 Instruction* op = new Instruction(getUniqueId(), typeId, OpSpecConstantOp);
2610 op->addImmediateOperand((unsigned) opCode);
2611 for (auto it = operands.cbegin(); it != operands.cend(); ++it)
2612 op->addIdOperand(*it);
2613 for (auto it = literals.cbegin(); it != literals.cend(); ++it)
2614 op->addImmediateOperand(*it);
2615 module.mapInstruction(op);
2616 constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(op));
2618 return op->getResultId();
2621 Id Builder::createFunctionCall(spv::Function* function, const std::vector<spv::Id>& args)
2623 Instruction* op = new Instruction(getUniqueId(), function->getReturnType(), OpFunctionCall);
2624 op->addIdOperand(function->getId());
2625 for (int a = 0; a < (int)args.size(); ++a)
2626 op->addIdOperand(args[a]);
2627 buildPoint->addInstruction(std::unique_ptr<Instruction>(op));
2629 return op->getResultId();
2632 // Comments in header
2633 Id Builder::createRvalueSwizzle(Decoration precision, Id typeId, Id source, const std::vector<unsigned>& channels)
2635 if (channels.size() == 1)
2636 return setPrecision(createCompositeExtract(source, typeId, channels.front()), precision);
2638 if (generatingOpCodeForSpecConst) {
2639 std::vector<Id> operands(2);
2640 operands[0] = operands[1] = source;
2641 return setPrecision(createSpecConstantOp(OpVectorShuffle, typeId, operands, channels), precision);
2643 Instruction* swizzle = new Instruction(getUniqueId(), typeId, OpVectorShuffle);
2644 assert(isVector(source));
2645 swizzle->addIdOperand(source);
2646 swizzle->addIdOperand(source);
2647 for (int i = 0; i < (int)channels.size(); ++i)
2648 swizzle->addImmediateOperand(channels[i]);
2649 buildPoint->addInstruction(std::unique_ptr<Instruction>(swizzle));
2651 return setPrecision(swizzle->getResultId(), precision);
2654 // Comments in header
2655 Id Builder::createLvalueSwizzle(Id typeId, Id target, Id source, const std::vector<unsigned>& channels)
2657 if (channels.size() == 1 && getNumComponents(source) == 1)
2658 return createCompositeInsert(source, target, typeId, channels.front());
2660 Instruction* swizzle = new Instruction(getUniqueId(), typeId, OpVectorShuffle);
2662 assert(isVector(target));
2663 swizzle->addIdOperand(target);
2665 assert(getNumComponents(source) == (int)channels.size());
2666 assert(isVector(source));
2667 swizzle->addIdOperand(source);
2669 // Set up an identity shuffle from the base value to the result value
2670 unsigned int components[4];
2671 int numTargetComponents = getNumComponents(target);
2672 for (int i = 0; i < numTargetComponents; ++i)
2675 // Punch in the l-value swizzle
2676 for (int i = 0; i < (int)channels.size(); ++i)
2677 components[channels[i]] = numTargetComponents + i;
2679 // finish the instruction with these components selectors
2680 for (int i = 0; i < numTargetComponents; ++i)
2681 swizzle->addImmediateOperand(components[i]);
2682 buildPoint->addInstruction(std::unique_ptr<Instruction>(swizzle));
2684 return swizzle->getResultId();
2687 // Comments in header
2688 void Builder::promoteScalar(Decoration precision, Id& left, Id& right)
2690 int direction = getNumComponents(right) - getNumComponents(left);
2693 left = smearScalar(precision, left, makeVectorType(getTypeId(left), getNumComponents(right)));
2694 else if (direction < 0)
2695 right = smearScalar(precision, right, makeVectorType(getTypeId(right), getNumComponents(left)));
2700 // Comments in header
2701 Id Builder::smearScalar(Decoration precision, Id scalar, Id vectorType)
2703 assert(getNumComponents(scalar) == 1);
2704 assert(getTypeId(scalar) == getScalarTypeId(vectorType));
2706 int numComponents = getNumTypeComponents(vectorType);
2707 if (numComponents == 1)
2710 Instruction* smear = nullptr;
2711 if (generatingOpCodeForSpecConst) {
2712 auto members = std::vector<spv::Id>(numComponents, scalar);
2713 // Sometime even in spec-constant-op mode, the temporary vector created by
2714 // promoting a scalar might not be a spec constant. This should depend on
2717 // const vec2 spec_const_result = a_spec_const_vec2 + a_front_end_const_scalar;
2718 // In such cases, the temporary vector created from a_front_end_const_scalar
2719 // is not a spec constant vector, even though the binary operation node is marked
2720 // as 'specConstant' and we are in spec-constant-op mode.
2721 auto result_id = makeCompositeConstant(vectorType, members, isSpecConstant(scalar));
2722 smear = module.getInstruction(result_id);
2724 smear = new Instruction(getUniqueId(), vectorType, OpCompositeConstruct);
2725 for (int c = 0; c < numComponents; ++c)
2726 smear->addIdOperand(scalar);
2727 buildPoint->addInstruction(std::unique_ptr<Instruction>(smear));
2730 return setPrecision(smear->getResultId(), precision);
2733 // Comments in header
2734 Id Builder::createBuiltinCall(Id resultType, Id builtins, int entryPoint, const std::vector<Id>& args)
2736 Instruction* inst = new Instruction(getUniqueId(), resultType, OpExtInst);
2737 inst->addIdOperand(builtins);
2738 inst->addImmediateOperand(entryPoint);
2739 for (int arg = 0; arg < (int)args.size(); ++arg)
2740 inst->addIdOperand(args[arg]);
2742 buildPoint->addInstruction(std::unique_ptr<Instruction>(inst));
2744 return inst->getResultId();
2747 // Accept all parameters needed to create a texture instruction.
2748 // Create the correct instruction based on the inputs, and make the call.
2749 Id Builder::createTextureCall(Decoration precision, Id resultType, bool sparse, bool fetch, bool proj, bool gather,
2750 bool noImplicitLod, const TextureParameters& parameters, ImageOperandsMask signExtensionMask)
2752 static const int maxTextureArgs = 10;
2753 Id texArgs[maxTextureArgs] = {};
2756 // Set up the fixed arguments
2759 bool explicitLod = false;
2760 texArgs[numArgs++] = parameters.sampler;
2761 texArgs[numArgs++] = parameters.coords;
2762 if (parameters.Dref != NoResult)
2763 texArgs[numArgs++] = parameters.Dref;
2764 if (parameters.component != NoResult)
2765 texArgs[numArgs++] = parameters.component;
2768 if (parameters.granularity != NoResult)
2769 texArgs[numArgs++] = parameters.granularity;
2770 if (parameters.coarse != NoResult)
2771 texArgs[numArgs++] = parameters.coarse;
2775 // Set up the optional arguments
2777 int optArgNum = numArgs; // track which operand, if it exists, is the mask of optional arguments
2778 ++numArgs; // speculatively make room for the mask operand
2779 ImageOperandsMask mask = ImageOperandsMaskNone; // the mask operand
2780 if (parameters.bias) {
2781 mask = (ImageOperandsMask)(mask | ImageOperandsBiasMask);
2782 texArgs[numArgs++] = parameters.bias;
2784 if (parameters.lod) {
2785 mask = (ImageOperandsMask)(mask | ImageOperandsLodMask);
2786 texArgs[numArgs++] = parameters.lod;
2788 } else if (parameters.gradX) {
2789 mask = (ImageOperandsMask)(mask | ImageOperandsGradMask);
2790 texArgs[numArgs++] = parameters.gradX;
2791 texArgs[numArgs++] = parameters.gradY;
2793 } else if (noImplicitLod && ! fetch && ! gather) {
2794 // have to explicitly use lod of 0 if not allowed to have them be implicit, and
2795 // we would otherwise be about to issue an implicit instruction
2796 mask = (ImageOperandsMask)(mask | ImageOperandsLodMask);
2797 texArgs[numArgs++] = makeFloatConstant(0.0);
2800 if (parameters.offset) {
2801 if (isConstant(parameters.offset))
2802 mask = (ImageOperandsMask)(mask | ImageOperandsConstOffsetMask);
2804 addCapability(CapabilityImageGatherExtended);
2805 mask = (ImageOperandsMask)(mask | ImageOperandsOffsetMask);
2807 texArgs[numArgs++] = parameters.offset;
2809 if (parameters.offsets) {
2810 addCapability(CapabilityImageGatherExtended);
2811 mask = (ImageOperandsMask)(mask | ImageOperandsConstOffsetsMask);
2812 texArgs[numArgs++] = parameters.offsets;
2815 if (parameters.sample) {
2816 mask = (ImageOperandsMask)(mask | ImageOperandsSampleMask);
2817 texArgs[numArgs++] = parameters.sample;
2819 if (parameters.lodClamp) {
2820 // capability if this bit is used
2821 addCapability(CapabilityMinLod);
2823 mask = (ImageOperandsMask)(mask | ImageOperandsMinLodMask);
2824 texArgs[numArgs++] = parameters.lodClamp;
2826 if (parameters.nonprivate) {
2827 mask = mask | ImageOperandsNonPrivateTexelKHRMask;
2829 if (parameters.volatil) {
2830 mask = mask | ImageOperandsVolatileTexelKHRMask;
2833 mask = mask | signExtensionMask;
2834 if (mask == ImageOperandsMaskNone)
2835 --numArgs; // undo speculative reservation for the mask argument
2837 texArgs[optArgNum] = mask;
2840 // Set up the instruction
2842 Op opCode = OpNop; // All paths below need to set this
2845 opCode = OpImageSparseFetch;
2847 opCode = OpImageFetch;
2849 } else if (parameters.granularity && parameters.coarse) {
2850 opCode = OpImageSampleFootprintNV;
2851 } else if (gather) {
2852 if (parameters.Dref)
2854 opCode = OpImageSparseDrefGather;
2856 opCode = OpImageDrefGather;
2859 opCode = OpImageSparseGather;
2861 opCode = OpImageGather;
2863 } else if (explicitLod) {
2864 if (parameters.Dref) {
2867 opCode = OpImageSparseSampleProjDrefExplicitLod;
2869 opCode = OpImageSampleProjDrefExplicitLod;
2872 opCode = OpImageSparseSampleDrefExplicitLod;
2874 opCode = OpImageSampleDrefExplicitLod;
2878 opCode = OpImageSparseSampleProjExplicitLod;
2880 opCode = OpImageSampleProjExplicitLod;
2883 opCode = OpImageSparseSampleExplicitLod;
2885 opCode = OpImageSampleExplicitLod;
2888 if (parameters.Dref) {
2891 opCode = OpImageSparseSampleProjDrefImplicitLod;
2893 opCode = OpImageSampleProjDrefImplicitLod;
2896 opCode = OpImageSparseSampleDrefImplicitLod;
2898 opCode = OpImageSampleDrefImplicitLod;
2902 opCode = OpImageSparseSampleProjImplicitLod;
2904 opCode = OpImageSampleProjImplicitLod;
2907 opCode = OpImageSparseSampleImplicitLod;
2909 opCode = OpImageSampleImplicitLod;
2913 // See if the result type is expecting a smeared result.
2914 // This happens when a legacy shadow*() call is made, which
2915 // gets a vec4 back instead of a float.
2916 Id smearedType = resultType;
2917 if (! isScalarType(resultType)) {
2919 case OpImageSampleDrefImplicitLod:
2920 case OpImageSampleDrefExplicitLod:
2921 case OpImageSampleProjDrefImplicitLod:
2922 case OpImageSampleProjDrefExplicitLod:
2923 resultType = getScalarTypeId(resultType);
2934 typeId0 = resultType;
2935 typeId1 = getDerefTypeId(parameters.texelOut);
2936 resultType = makeStructResultType(typeId0, typeId1);
2939 // Build the SPIR-V instruction
2940 Instruction* textureInst = new Instruction(getUniqueId(), resultType, opCode);
2941 for (int op = 0; op < optArgNum; ++op)
2942 textureInst->addIdOperand(texArgs[op]);
2943 if (optArgNum < numArgs)
2944 textureInst->addImmediateOperand(texArgs[optArgNum]);
2945 for (int op = optArgNum + 1; op < numArgs; ++op)
2946 textureInst->addIdOperand(texArgs[op]);
2947 setPrecision(textureInst->getResultId(), precision);
2948 buildPoint->addInstruction(std::unique_ptr<Instruction>(textureInst));
2950 Id resultId = textureInst->getResultId();
2954 addCapability(CapabilitySparseResidency);
2956 // Decode the return type that was a special structure
2957 createStore(createCompositeExtract(resultId, typeId1, 1), parameters.texelOut);
2958 resultId = createCompositeExtract(resultId, typeId0, 0);
2959 setPrecision(resultId, precision);
2961 // When a smear is needed, do it, as per what was computed
2962 // above when resultType was changed to a scalar type.
2963 if (resultType != smearedType)
2964 resultId = smearScalar(precision, resultId, smearedType);
2970 // Comments in header
2971 Id Builder::createTextureQueryCall(Op opCode, const TextureParameters& parameters, bool isUnsignedResult)
2973 // Figure out the result type
2976 case OpImageQuerySize:
2977 case OpImageQuerySizeLod:
2979 int numComponents = 0;
2980 switch (getTypeDimensionality(getImageType(parameters.sampler))) {
2988 case DimSubpassData:
2999 if (isArrayedImageType(getImageType(parameters.sampler)))
3002 Id intType = isUnsignedResult ? makeUintType(32) : makeIntType(32);
3003 if (numComponents == 1)
3004 resultType = intType;
3006 resultType = makeVectorType(intType, numComponents);
3010 case OpImageQueryLod:
3011 resultType = makeVectorType(getScalarTypeId(getTypeId(parameters.coords)), 2);
3013 case OpImageQueryLevels:
3014 case OpImageQuerySamples:
3015 resultType = isUnsignedResult ? makeUintType(32) : makeIntType(32);
3022 Instruction* query = new Instruction(getUniqueId(), resultType, opCode);
3023 query->addIdOperand(parameters.sampler);
3024 if (parameters.coords)
3025 query->addIdOperand(parameters.coords);
3027 query->addIdOperand(parameters.lod);
3028 buildPoint->addInstruction(std::unique_ptr<Instruction>(query));
3029 addCapability(CapabilityImageQuery);
3031 return query->getResultId();
3034 // External comments in header.
3035 // Operates recursively to visit the composite's hierarchy.
3036 Id Builder::createCompositeCompare(Decoration precision, Id value1, Id value2, bool equal)
3038 Id boolType = makeBoolType();
3039 Id valueType = getTypeId(value1);
3041 Id resultId = NoResult;
3043 int numConstituents = getNumTypeConstituents(valueType);
3045 // Scalars and Vectors
3047 if (isScalarType(valueType) || isVectorType(valueType)) {
3048 assert(valueType == getTypeId(value2));
3049 // These just need a single comparison, just have
3050 // to figure out what it is.
3052 switch (getMostBasicTypeClass(valueType)) {
3054 op = equal ? OpFOrdEqual : OpFUnordNotEqual;
3058 op = equal ? OpIEqual : OpINotEqual;
3061 op = equal ? OpLogicalEqual : OpLogicalNotEqual;
3062 precision = NoPrecision;
3066 if (isScalarType(valueType)) {
3068 resultId = createBinOp(op, boolType, value1, value2);
3071 resultId = createBinOp(op, makeVectorType(boolType, numConstituents), value1, value2);
3072 setPrecision(resultId, precision);
3073 // reduce vector compares...
3074 resultId = createUnaryOp(equal ? OpAll : OpAny, boolType, resultId);
3077 return setPrecision(resultId, precision);
3080 // Only structs, arrays, and matrices should be left.
3081 // They share in common the reduction operation across their constituents.
3082 assert(isAggregateType(valueType) || isMatrixType(valueType));
3084 // Compare each pair of constituents
3085 for (int constituent = 0; constituent < numConstituents; ++constituent) {
3086 std::vector<unsigned> indexes(1, constituent);
3087 Id constituentType1 = getContainedTypeId(getTypeId(value1), constituent);
3088 Id constituentType2 = getContainedTypeId(getTypeId(value2), constituent);
3089 Id constituent1 = createCompositeExtract(value1, constituentType1, indexes);
3090 Id constituent2 = createCompositeExtract(value2, constituentType2, indexes);
3092 Id subResultId = createCompositeCompare(precision, constituent1, constituent2, equal);
3094 if (constituent == 0)
3095 resultId = subResultId;
3097 resultId = setPrecision(createBinOp(equal ? OpLogicalAnd : OpLogicalOr, boolType, resultId, subResultId),
3104 // OpCompositeConstruct
3105 Id Builder::createCompositeConstruct(Id typeId, const std::vector<Id>& constituents)
3107 assert(isAggregateType(typeId) || (getNumTypeConstituents(typeId) > 1 &&
3108 getNumTypeConstituents(typeId) == (int)constituents.size()));
3110 if (generatingOpCodeForSpecConst) {
3111 // Sometime, even in spec-constant-op mode, the constant composite to be
3112 // constructed may not be a specialization constant.
3114 // const mat2 m2 = mat2(a_spec_const, a_front_end_const, another_front_end_const, third_front_end_const);
3115 // The first column vector should be a spec constant one, as a_spec_const is a spec constant.
3116 // The second column vector should NOT be spec constant, as it does not contain any spec constants.
3117 // To handle such cases, we check the constituents of the constant vector to determine whether this
3118 // vector should be created as a spec constant.
3119 return makeCompositeConstant(typeId, constituents,
3120 std::any_of(constituents.begin(), constituents.end(),
3121 [&](spv::Id id) { return isSpecConstant(id); }));
3124 Instruction* op = new Instruction(getUniqueId(), typeId, OpCompositeConstruct);
3125 for (int c = 0; c < (int)constituents.size(); ++c)
3126 op->addIdOperand(constituents[c]);
3127 buildPoint->addInstruction(std::unique_ptr<Instruction>(op));
3129 return op->getResultId();
3132 // Vector or scalar constructor
3133 Id Builder::createConstructor(Decoration precision, const std::vector<Id>& sources, Id resultTypeId)
3135 Id result = NoResult;
3136 unsigned int numTargetComponents = getNumTypeComponents(resultTypeId);
3137 unsigned int targetComponent = 0;
3139 // Special case: when calling a vector constructor with a single scalar
3140 // argument, smear the scalar
3141 if (sources.size() == 1 && isScalar(sources[0]) && numTargetComponents > 1)
3142 return smearScalar(precision, sources[0], resultTypeId);
3144 // accumulate the arguments for OpCompositeConstruct
3145 std::vector<Id> constituents;
3146 Id scalarTypeId = getScalarTypeId(resultTypeId);
3148 // lambda to store the result of visiting an argument component
3149 const auto latchResult = [&](Id comp) {
3150 if (numTargetComponents > 1)
3151 constituents.push_back(comp);
3157 // lambda to visit a vector argument's components
3158 const auto accumulateVectorConstituents = [&](Id sourceArg) {
3159 unsigned int sourceSize = getNumComponents(sourceArg);
3160 unsigned int sourcesToUse = sourceSize;
3161 if (sourcesToUse + targetComponent > numTargetComponents)
3162 sourcesToUse = numTargetComponents - targetComponent;
3164 for (unsigned int s = 0; s < sourcesToUse; ++s) {
3165 std::vector<unsigned> swiz;
3167 latchResult(createRvalueSwizzle(precision, scalarTypeId, sourceArg, swiz));
3171 // lambda to visit a matrix argument's components
3172 const auto accumulateMatrixConstituents = [&](Id sourceArg) {
3173 unsigned int sourceSize = getNumColumns(sourceArg) * getNumRows(sourceArg);
3174 unsigned int sourcesToUse = sourceSize;
3175 if (sourcesToUse + targetComponent > numTargetComponents)
3176 sourcesToUse = numTargetComponents - targetComponent;
3180 for (unsigned int s = 0; s < sourcesToUse; ++s) {
3181 if (row >= getNumRows(sourceArg)) {
3185 std::vector<Id> indexes;
3186 indexes.push_back(col);
3187 indexes.push_back(row);
3188 latchResult(createCompositeExtract(sourceArg, scalarTypeId, indexes));
3193 // Go through the source arguments, each one could have either
3194 // a single or multiple components to contribute.
3195 for (unsigned int i = 0; i < sources.size(); ++i) {
3197 if (isScalar(sources[i]) || isPointer(sources[i]))
3198 latchResult(sources[i]);
3199 else if (isVector(sources[i]))
3200 accumulateVectorConstituents(sources[i]);
3201 else if (isMatrix(sources[i]))
3202 accumulateMatrixConstituents(sources[i]);
3206 if (targetComponent >= numTargetComponents)
3210 // If the result is a vector, make it from the gathered constituents.
3211 if (constituents.size() > 0)
3212 result = createCompositeConstruct(resultTypeId, constituents);
3214 return setPrecision(result, precision);
3217 // Comments in header
3218 Id Builder::createMatrixConstructor(Decoration precision, const std::vector<Id>& sources, Id resultTypeId)
3220 Id componentTypeId = getScalarTypeId(resultTypeId);
3221 int numCols = getTypeNumColumns(resultTypeId);
3222 int numRows = getTypeNumRows(resultTypeId);
3224 Instruction* instr = module.getInstruction(componentTypeId);
3226 const unsigned bitCount = 32;
3227 assert(bitCount == instr->getImmediateOperand(0));
3229 const unsigned bitCount = instr->getImmediateOperand(0);
3232 // Optimize matrix constructed from a bigger matrix
3233 if (isMatrix(sources[0]) && getNumColumns(sources[0]) >= numCols && getNumRows(sources[0]) >= numRows) {
3234 // To truncate the matrix to a smaller number of rows/columns, we need to:
3235 // 1. For each column, extract the column and truncate it to the required size using shuffle
3236 // 2. Assemble the resulting matrix from all columns
3237 Id matrix = sources[0];
3238 Id columnTypeId = getContainedTypeId(resultTypeId);
3239 Id sourceColumnTypeId = getContainedTypeId(getTypeId(matrix));
3241 std::vector<unsigned> channels;
3242 for (int row = 0; row < numRows; ++row)
3243 channels.push_back(row);
3245 std::vector<Id> matrixColumns;
3246 for (int col = 0; col < numCols; ++col) {
3247 std::vector<unsigned> indexes;
3248 indexes.push_back(col);
3249 Id colv = createCompositeExtract(matrix, sourceColumnTypeId, indexes);
3250 setPrecision(colv, precision);
3252 if (numRows != getNumRows(matrix)) {
3253 matrixColumns.push_back(createRvalueSwizzle(precision, columnTypeId, colv, channels));
3255 matrixColumns.push_back(colv);
3259 return setPrecision(createCompositeConstruct(resultTypeId, matrixColumns), precision);
3262 // Otherwise, will use a two step process
3263 // 1. make a compile-time 2D array of values
3264 // 2. construct a matrix from that array
3268 // initialize the array to the identity matrix
3269 Id ids[maxMatrixSize][maxMatrixSize];
3270 Id one = (bitCount == 64 ? makeDoubleConstant(1.0) : makeFloatConstant(1.0));
3271 Id zero = (bitCount == 64 ? makeDoubleConstant(0.0) : makeFloatConstant(0.0));
3272 for (int col = 0; col < 4; ++col) {
3273 for (int row = 0; row < 4; ++row) {
3275 ids[col][row] = one;
3277 ids[col][row] = zero;
3281 // modify components as dictated by the arguments
3282 if (sources.size() == 1 && isScalar(sources[0])) {
3283 // a single scalar; resets the diagonals
3284 for (int col = 0; col < 4; ++col)
3285 ids[col][col] = sources[0];
3286 } else if (isMatrix(sources[0])) {
3287 // constructing from another matrix; copy over the parts that exist in both the argument and constructee
3288 Id matrix = sources[0];
3289 int minCols = std::min(numCols, getNumColumns(matrix));
3290 int minRows = std::min(numRows, getNumRows(matrix));
3291 for (int col = 0; col < minCols; ++col) {
3292 std::vector<unsigned> indexes;
3293 indexes.push_back(col);
3294 for (int row = 0; row < minRows; ++row) {
3295 indexes.push_back(row);
3296 ids[col][row] = createCompositeExtract(matrix, componentTypeId, indexes);
3298 setPrecision(ids[col][row], precision);
3302 // fill in the matrix in column-major order with whatever argument components are available
3306 for (int arg = 0; arg < (int)sources.size() && col < numCols; ++arg) {
3307 Id argComp = sources[arg];
3308 for (int comp = 0; comp < getNumComponents(sources[arg]); ++comp) {
3309 if (getNumComponents(sources[arg]) > 1) {
3310 argComp = createCompositeExtract(sources[arg], componentTypeId, comp);
3311 setPrecision(argComp, precision);
3313 ids[col][row++] = argComp;
3314 if (row == numRows) {
3318 if (col == numCols) {
3319 // If more components are provided than fit the matrix, discard the rest.
3326 // Step 2: Construct a matrix from that array.
3327 // First make the column vectors, then make the matrix.
3329 // make the column vectors
3330 Id columnTypeId = getContainedTypeId(resultTypeId);
3331 std::vector<Id> matrixColumns;
3332 for (int col = 0; col < numCols; ++col) {
3333 std::vector<Id> vectorComponents;
3334 for (int row = 0; row < numRows; ++row)
3335 vectorComponents.push_back(ids[col][row]);
3336 Id column = createCompositeConstruct(columnTypeId, vectorComponents);
3337 setPrecision(column, precision);
3338 matrixColumns.push_back(column);
3342 return setPrecision(createCompositeConstruct(resultTypeId, matrixColumns), precision);
3345 // Comments in header
3346 Builder::If::If(Id cond, unsigned int ctrl, Builder& gb) :
3352 function = &builder.getBuildPoint()->getParent();
3354 // make the blocks, but only put the then-block into the function,
3355 // the else-block and merge-block will be added later, in order, after
3356 // earlier code is emitted
3357 thenBlock = new Block(builder.getUniqueId(), *function);
3358 mergeBlock = new Block(builder.getUniqueId(), *function);
3360 // Save the current block, so that we can add in the flow control split when
3361 // makeEndIf is called.
3362 headerBlock = builder.getBuildPoint();
3364 function->addBlock(thenBlock);
3365 builder.setBuildPoint(thenBlock);
3368 // Comments in header
3369 void Builder::If::makeBeginElse()
3371 // Close out the "then" by having it jump to the mergeBlock
3372 builder.createBranch(mergeBlock);
3374 // Make the first else block and add it to the function
3375 elseBlock = new Block(builder.getUniqueId(), *function);
3376 function->addBlock(elseBlock);
3378 // Start building the else block
3379 builder.setBuildPoint(elseBlock);
3382 // Comments in header
3383 void Builder::If::makeEndIf()
3385 // jump to the merge block
3386 builder.createBranch(mergeBlock);
3388 // Go back to the headerBlock and make the flow control split
3389 builder.setBuildPoint(headerBlock);
3390 builder.createSelectionMerge(mergeBlock, control);
3392 builder.createConditionalBranch(condition, thenBlock, elseBlock);
3394 builder.createConditionalBranch(condition, thenBlock, mergeBlock);
3396 // add the merge block to the function
3397 function->addBlock(mergeBlock);
3398 builder.setBuildPoint(mergeBlock);
3401 // Comments in header
3402 void Builder::makeSwitch(Id selector, unsigned int control, int numSegments, const std::vector<int>& caseValues,
3403 const std::vector<int>& valueIndexToSegment, int defaultSegment,
3404 std::vector<Block*>& segmentBlocks)
3406 Function& function = buildPoint->getParent();
3408 // make all the blocks
3409 for (int s = 0; s < numSegments; ++s)
3410 segmentBlocks.push_back(new Block(getUniqueId(), function));
3412 Block* mergeBlock = new Block(getUniqueId(), function);
3414 // make and insert the switch's selection-merge instruction
3415 createSelectionMerge(mergeBlock, control);
3417 // make the switch instruction
3418 Instruction* switchInst = new Instruction(NoResult, NoType, OpSwitch);
3419 switchInst->addIdOperand(selector);
3420 auto defaultOrMerge = (defaultSegment >= 0) ? segmentBlocks[defaultSegment] : mergeBlock;
3421 switchInst->addIdOperand(defaultOrMerge->getId());
3422 defaultOrMerge->addPredecessor(buildPoint);
3423 for (int i = 0; i < (int)caseValues.size(); ++i) {
3424 switchInst->addImmediateOperand(caseValues[i]);
3425 switchInst->addIdOperand(segmentBlocks[valueIndexToSegment[i]]->getId());
3426 segmentBlocks[valueIndexToSegment[i]]->addPredecessor(buildPoint);
3428 buildPoint->addInstruction(std::unique_ptr<Instruction>(switchInst));
3430 // push the merge block
3431 switchMerges.push(mergeBlock);
3434 // Comments in header
3435 void Builder::addSwitchBreak()
3437 // branch to the top of the merge block stack
3438 createBranch(switchMerges.top());
3439 createAndSetNoPredecessorBlock("post-switch-break");
3442 // Comments in header
3443 void Builder::nextSwitchSegment(std::vector<Block*>& segmentBlock, int nextSegment)
3445 int lastSegment = nextSegment - 1;
3446 if (lastSegment >= 0) {
3447 // Close out previous segment by jumping, if necessary, to next segment
3448 if (! buildPoint->isTerminated())
3449 createBranch(segmentBlock[nextSegment]);
3451 Block* block = segmentBlock[nextSegment];
3452 block->getParent().addBlock(block);
3453 setBuildPoint(block);
3456 // Comments in header
3457 void Builder::endSwitch(std::vector<Block*>& /*segmentBlock*/)
3459 // Close out previous segment by jumping, if necessary, to next segment
3460 if (! buildPoint->isTerminated())
3463 switchMerges.top()->getParent().addBlock(switchMerges.top());
3464 setBuildPoint(switchMerges.top());
3469 Block& Builder::makeNewBlock()
3471 Function& function = buildPoint->getParent();
3472 auto block = new Block(getUniqueId(), function);
3473 function.addBlock(block);
3477 Builder::LoopBlocks& Builder::makeNewLoop()
3479 // This verbosity is needed to simultaneously get the same behavior
3480 // everywhere (id's in the same order), have a syntax that works
3481 // across lots of versions of C++, have no warnings from pedantic
3482 // compilation modes, and leave the rest of the code alone.
3483 Block& head = makeNewBlock();
3484 Block& body = makeNewBlock();
3485 Block& merge = makeNewBlock();
3486 Block& continue_target = makeNewBlock();
3487 LoopBlocks blocks(head, body, merge, continue_target);
3492 void Builder::createLoopContinue()
3494 createBranch(&loops.top().continue_target);
3495 // Set up a block for dead code.
3496 createAndSetNoPredecessorBlock("post-loop-continue");
3499 void Builder::createLoopExit()
3501 createBranch(&loops.top().merge);
3502 // Set up a block for dead code.
3503 createAndSetNoPredecessorBlock("post-loop-break");
3506 void Builder::closeLoop()
3511 void Builder::clearAccessChain()
3513 accessChain.base = NoResult;
3514 accessChain.indexChain.clear();
3515 accessChain.instr = NoResult;
3516 accessChain.swizzle.clear();
3517 accessChain.component = NoResult;
3518 accessChain.preSwizzleBaseType = NoType;
3519 accessChain.isRValue = false;
3520 accessChain.coherentFlags.clear();
3521 accessChain.alignment = 0;
3524 // Comments in header
3525 void Builder::accessChainPushSwizzle(std::vector<unsigned>& swizzle, Id preSwizzleBaseType,
3526 AccessChain::CoherentFlags coherentFlags, unsigned int alignment)
3528 accessChain.coherentFlags |= coherentFlags;
3529 accessChain.alignment |= alignment;
3531 // swizzles can be stacked in GLSL, but simplified to a single
3532 // one here; the base type doesn't change
3533 if (accessChain.preSwizzleBaseType == NoType)
3534 accessChain.preSwizzleBaseType = preSwizzleBaseType;
3536 // if needed, propagate the swizzle for the current access chain
3537 if (accessChain.swizzle.size() > 0) {
3538 std::vector<unsigned> oldSwizzle = accessChain.swizzle;
3539 accessChain.swizzle.resize(0);
3540 for (unsigned int i = 0; i < swizzle.size(); ++i) {
3541 assert(swizzle[i] < oldSwizzle.size());
3542 accessChain.swizzle.push_back(oldSwizzle[swizzle[i]]);
3545 accessChain.swizzle = swizzle;
3547 // determine if we need to track this swizzle anymore
3548 simplifyAccessChainSwizzle();
3551 // Comments in header
3552 void Builder::accessChainStore(Id rvalue, Decoration nonUniform, spv::MemoryAccessMask memoryAccess, spv::Scope scope, unsigned int alignment)
3554 assert(accessChain.isRValue == false);
3556 transferAccessChainSwizzle(true);
3558 // If a swizzle exists and is not full and is not dynamic, then the swizzle will be broken into individual stores.
3559 if (accessChain.swizzle.size() > 0 &&
3560 getNumTypeComponents(getResultingAccessChainType()) != (int)accessChain.swizzle.size() &&
3561 accessChain.component == NoResult) {
3562 for (unsigned int i = 0; i < accessChain.swizzle.size(); ++i) {
3563 accessChain.indexChain.push_back(makeUintConstant(accessChain.swizzle[i]));
3564 accessChain.instr = NoResult;
3566 Id base = collapseAccessChain();
3567 addDecoration(base, nonUniform);
3569 accessChain.indexChain.pop_back();
3570 accessChain.instr = NoResult;
3572 // dynamic component should be gone
3573 assert(accessChain.component == NoResult);
3575 Id source = createCompositeExtract(rvalue, getContainedTypeId(getTypeId(rvalue)), i);
3577 // take LSB of alignment
3578 alignment = alignment & ~(alignment & (alignment-1));
3579 if (getStorageClass(base) == StorageClassPhysicalStorageBufferEXT) {
3580 memoryAccess = (spv::MemoryAccessMask)(memoryAccess | spv::MemoryAccessAlignedMask);
3583 createStore(source, base, memoryAccess, scope, alignment);
3587 Id base = collapseAccessChain();
3588 addDecoration(base, nonUniform);
3592 // dynamic component should be gone
3593 assert(accessChain.component == NoResult);
3595 // If swizzle still exists, it may be out-of-order, we must load the target vector,
3596 // extract and insert elements to perform writeMask and/or swizzle.
3597 if (accessChain.swizzle.size() > 0) {
3598 Id tempBaseId = createLoad(base, spv::NoPrecision);
3599 source = createLvalueSwizzle(getTypeId(tempBaseId), tempBaseId, source, accessChain.swizzle);
3602 // take LSB of alignment
3603 alignment = alignment & ~(alignment & (alignment-1));
3604 if (getStorageClass(base) == StorageClassPhysicalStorageBufferEXT) {
3605 memoryAccess = (spv::MemoryAccessMask)(memoryAccess | spv::MemoryAccessAlignedMask);
3608 createStore(source, base, memoryAccess, scope, alignment);
3612 // Comments in header
3613 Id Builder::accessChainLoad(Decoration precision, Decoration l_nonUniform,
3614 Decoration r_nonUniform, Id resultType, spv::MemoryAccessMask memoryAccess,
3615 spv::Scope scope, unsigned int alignment)
3619 if (accessChain.isRValue) {
3620 // transfer access chain, but try to stay in registers
3621 transferAccessChainSwizzle(false);
3622 if (accessChain.indexChain.size() > 0) {
3623 Id swizzleBase = accessChain.preSwizzleBaseType != NoType ? accessChain.preSwizzleBaseType : resultType;
3625 // if all the accesses are constants, we can use OpCompositeExtract
3626 std::vector<unsigned> indexes;
3627 bool constant = true;
3628 for (int i = 0; i < (int)accessChain.indexChain.size(); ++i) {
3629 if (isConstantScalar(accessChain.indexChain[i]))
3630 indexes.push_back(getConstantScalar(accessChain.indexChain[i]));
3638 id = createCompositeExtract(accessChain.base, swizzleBase, indexes);
3639 setPrecision(id, precision);
3641 Id lValue = NoResult;
3642 if (spvVersion >= Spv_1_4 && isValidInitializer(accessChain.base)) {
3643 // make a new function variable for this r-value, using an initializer,
3644 // and mark it as NonWritable so that downstream it can be detected as a lookup
3646 lValue = createVariable(NoPrecision, StorageClassFunction, getTypeId(accessChain.base),
3647 "indexable", accessChain.base);
3648 addDecoration(lValue, DecorationNonWritable);
3650 lValue = createVariable(NoPrecision, StorageClassFunction, getTypeId(accessChain.base),
3653 createStore(accessChain.base, lValue);
3655 // move base to the new variable
3656 accessChain.base = lValue;
3657 accessChain.isRValue = false;
3659 // load through the access chain
3660 id = createLoad(collapseAccessChain(), precision);
3663 id = accessChain.base; // no precision, it was set when this was defined
3665 transferAccessChainSwizzle(true);
3667 // take LSB of alignment
3668 alignment = alignment & ~(alignment & (alignment-1));
3669 if (getStorageClass(accessChain.base) == StorageClassPhysicalStorageBufferEXT) {
3670 memoryAccess = (spv::MemoryAccessMask)(memoryAccess | spv::MemoryAccessAlignedMask);
3673 // load through the access chain
3674 id = collapseAccessChain();
3675 // Apply nonuniform both to the access chain and the loaded value.
3676 // Buffer accesses need the access chain decorated, and this is where
3677 // loaded image types get decorated. TODO: This should maybe move to
3678 // createImageTextureFunctionCall.
3679 addDecoration(id, l_nonUniform);
3680 id = createLoad(id, precision, memoryAccess, scope, alignment);
3681 addDecoration(id, r_nonUniform);
3684 // Done, unless there are swizzles to do
3685 if (accessChain.swizzle.size() == 0 && accessChain.component == NoResult)
3688 // Do remaining swizzling
3690 // Do the basic swizzle
3691 if (accessChain.swizzle.size() > 0) {
3692 Id swizzledType = getScalarTypeId(getTypeId(id));
3693 if (accessChain.swizzle.size() > 1)
3694 swizzledType = makeVectorType(swizzledType, (int)accessChain.swizzle.size());
3695 id = createRvalueSwizzle(precision, swizzledType, id, accessChain.swizzle);
3698 // Do the dynamic component
3699 if (accessChain.component != NoResult)
3700 id = setPrecision(createVectorExtractDynamic(id, resultType, accessChain.component), precision);
3702 addDecoration(id, r_nonUniform);
3706 Id Builder::accessChainGetLValue()
3708 assert(accessChain.isRValue == false);
3710 transferAccessChainSwizzle(true);
3711 Id lvalue = collapseAccessChain();
3713 // If swizzle exists, it is out-of-order or not full, we must load the target vector,
3714 // extract and insert elements to perform writeMask and/or swizzle. This does not
3715 // go with getting a direct l-value pointer.
3716 assert(accessChain.swizzle.size() == 0);
3717 assert(accessChain.component == NoResult);
3722 // comment in header
3723 Id Builder::accessChainGetInferredType()
3725 // anything to operate on?
3726 if (accessChain.base == NoResult)
3728 Id type = getTypeId(accessChain.base);
3730 // do initial dereference
3731 if (! accessChain.isRValue)
3732 type = getContainedTypeId(type);
3734 // dereference each index
3735 for (auto it = accessChain.indexChain.cbegin(); it != accessChain.indexChain.cend(); ++it) {
3736 if (isStructType(type))
3737 type = getContainedTypeId(type, getConstantScalar(*it));
3739 type = getContainedTypeId(type);
3742 // dereference swizzle
3743 if (accessChain.swizzle.size() == 1)
3744 type = getContainedTypeId(type);
3745 else if (accessChain.swizzle.size() > 1)
3746 type = makeVectorType(getContainedTypeId(type), (int)accessChain.swizzle.size());
3748 // dereference component selection
3749 if (accessChain.component)
3750 type = getContainedTypeId(type);
3755 void Builder::dump(std::vector<unsigned int>& out) const
3757 // Header, before first instructions:
3758 out.push_back(MagicNumber);
3759 out.push_back(spvVersion);
3760 out.push_back(builderNumber);
3761 out.push_back(uniqueId + 1);
3765 for (auto it = capabilities.cbegin(); it != capabilities.cend(); ++it) {
3766 Instruction capInst(0, 0, OpCapability);
3767 capInst.addImmediateOperand(*it);
3771 for (auto it = extensions.cbegin(); it != extensions.cend(); ++it) {
3772 Instruction extInst(0, 0, OpExtension);
3773 extInst.addStringOperand(it->c_str());
3777 dumpInstructions(out, imports);
3778 Instruction memInst(0, 0, OpMemoryModel);
3779 memInst.addImmediateOperand(addressModel);
3780 memInst.addImmediateOperand(memoryModel);
3783 // Instructions saved up while building:
3784 dumpInstructions(out, entryPoints);
3785 dumpInstructions(out, executionModes);
3787 // Debug instructions
3788 dumpInstructions(out, strings);
3789 dumpSourceInstructions(out);
3790 for (int e = 0; e < (int)sourceExtensions.size(); ++e) {
3791 Instruction sourceExtInst(0, 0, OpSourceExtension);
3792 sourceExtInst.addStringOperand(sourceExtensions[e]);
3793 sourceExtInst.dump(out);
3795 dumpInstructions(out, names);
3796 dumpModuleProcesses(out);
3798 // Annotation instructions
3799 dumpInstructions(out, decorations);
3801 dumpInstructions(out, constantsTypesGlobals);
3802 dumpInstructions(out, externals);
3809 // Protected methods.
3812 // Turn the described access chain in 'accessChain' into an instruction(s)
3813 // computing its address. This *cannot* include complex swizzles, which must
3814 // be handled after this is called.
3816 // Can generate code.
3817 Id Builder::collapseAccessChain()
3819 assert(accessChain.isRValue == false);
3821 // did we already emit an access chain for this?
3822 if (accessChain.instr != NoResult)
3823 return accessChain.instr;
3825 // If we have a dynamic component, we can still transfer
3826 // that into a final operand to the access chain. We need to remap the
3827 // dynamic component through the swizzle to get a new dynamic component to
3830 // This was not done in transferAccessChainSwizzle() because it might
3832 remapDynamicSwizzle();
3833 if (accessChain.component != NoResult) {
3834 // transfer the dynamic component to the access chain
3835 accessChain.indexChain.push_back(accessChain.component);
3836 accessChain.component = NoResult;
3839 // note that non-trivial swizzling is left pending
3841 // do we have an access chain?
3842 if (accessChain.indexChain.size() == 0)
3843 return accessChain.base;
3845 // emit the access chain
3846 StorageClass storageClass = (StorageClass)module.getStorageClass(getTypeId(accessChain.base));
3847 accessChain.instr = createAccessChain(storageClass, accessChain.base, accessChain.indexChain);
3849 return accessChain.instr;
3852 // For a dynamic component selection of a swizzle.
3854 // Turn the swizzle and dynamic component into just a dynamic component.
3857 void Builder::remapDynamicSwizzle()
3859 // do we have a swizzle to remap a dynamic component through?
3860 if (accessChain.component != NoResult && accessChain.swizzle.size() > 1) {
3861 // build a vector of the swizzle for the component to map into
3862 std::vector<Id> components;
3863 for (int c = 0; c < (int)accessChain.swizzle.size(); ++c)
3864 components.push_back(makeUintConstant(accessChain.swizzle[c]));
3865 Id mapType = makeVectorType(makeUintType(32), (int)accessChain.swizzle.size());
3866 Id map = makeCompositeConstant(mapType, components);
3869 accessChain.component = createVectorExtractDynamic(map, makeUintType(32), accessChain.component);
3870 accessChain.swizzle.clear();
3874 // clear out swizzle if it is redundant, that is reselecting the same components
3875 // that would be present without the swizzle.
3876 void Builder::simplifyAccessChainSwizzle()
3878 // If the swizzle has fewer components than the vector, it is subsetting, and must stay
3879 // to preserve that fact.
3880 if (getNumTypeComponents(accessChain.preSwizzleBaseType) > (int)accessChain.swizzle.size())
3883 // if components are out of order, it is a swizzle
3884 for (unsigned int i = 0; i < accessChain.swizzle.size(); ++i) {
3885 if (i != accessChain.swizzle[i])
3889 // otherwise, there is no need to track this swizzle
3890 accessChain.swizzle.clear();
3891 if (accessChain.component == NoResult)
3892 accessChain.preSwizzleBaseType = NoType;
3895 // To the extent any swizzling can become part of the chain
3896 // of accesses instead of a post operation, make it so.
3897 // If 'dynamic' is true, include transferring the dynamic component,
3898 // otherwise, leave it pending.
3900 // Does not generate code. just updates the access chain.
3901 void Builder::transferAccessChainSwizzle(bool dynamic)
3904 if (accessChain.swizzle.size() == 0 && accessChain.component == NoResult)
3908 // (this requires either a swizzle, or generating code for a dynamic component)
3909 if (accessChain.swizzle.size() > 1)
3912 // single component, either in the swizzle and/or dynamic component
3913 if (accessChain.swizzle.size() == 1) {
3914 assert(accessChain.component == NoResult);
3915 // handle static component selection
3916 accessChain.indexChain.push_back(makeUintConstant(accessChain.swizzle.front()));
3917 accessChain.swizzle.clear();
3918 accessChain.preSwizzleBaseType = NoType;
3919 } else if (dynamic && accessChain.component != NoResult) {
3920 assert(accessChain.swizzle.size() == 0);
3921 // handle dynamic component
3922 accessChain.indexChain.push_back(accessChain.component);
3923 accessChain.preSwizzleBaseType = NoType;
3924 accessChain.component = NoResult;
3928 // Utility method for creating a new block and setting the insert point to
3929 // be in it. This is useful for flow-control operations that need a "dummy"
3930 // block proceeding them (e.g. instructions after a discard, etc).
3931 void Builder::createAndSetNoPredecessorBlock(const char* /*name*/)
3933 Block* block = new Block(getUniqueId(), buildPoint->getParent());
3934 block->setUnreachable();
3935 buildPoint->getParent().addBlock(block);
3936 setBuildPoint(block);
3939 // addName(block->getId(), name);
3942 // Comments in header
3943 void Builder::createBranch(Block* block)
3945 Instruction* branch = new Instruction(OpBranch);
3946 branch->addIdOperand(block->getId());
3947 buildPoint->addInstruction(std::unique_ptr<Instruction>(branch));
3948 block->addPredecessor(buildPoint);
3951 void Builder::createSelectionMerge(Block* mergeBlock, unsigned int control)
3953 Instruction* merge = new Instruction(OpSelectionMerge);
3954 merge->addIdOperand(mergeBlock->getId());
3955 merge->addImmediateOperand(control);
3956 buildPoint->addInstruction(std::unique_ptr<Instruction>(merge));
3959 void Builder::createLoopMerge(Block* mergeBlock, Block* continueBlock, unsigned int control,
3960 const std::vector<unsigned int>& operands)
3962 Instruction* merge = new Instruction(OpLoopMerge);
3963 merge->addIdOperand(mergeBlock->getId());
3964 merge->addIdOperand(continueBlock->getId());
3965 merge->addImmediateOperand(control);
3966 for (int op = 0; op < (int)operands.size(); ++op)
3967 merge->addImmediateOperand(operands[op]);
3968 buildPoint->addInstruction(std::unique_ptr<Instruction>(merge));
3971 void Builder::createConditionalBranch(Id condition, Block* thenBlock, Block* elseBlock)
3973 Instruction* branch = new Instruction(OpBranchConditional);
3974 branch->addIdOperand(condition);
3975 branch->addIdOperand(thenBlock->getId());
3976 branch->addIdOperand(elseBlock->getId());
3977 buildPoint->addInstruction(std::unique_ptr<Instruction>(branch));
3978 thenBlock->addPredecessor(buildPoint);
3979 elseBlock->addPredecessor(buildPoint);
3983 // [OpSourceContinued]
3985 void Builder::dumpSourceInstructions(const spv::Id fileId, const std::string& text,
3986 std::vector<unsigned int>& out) const
3988 const int maxWordCount = 0xFFFF;
3989 const int opSourceWordCount = 4;
3990 const int nonNullBytesPerInstruction = 4 * (maxWordCount - opSourceWordCount) - 1;
3992 if (sourceLang != SourceLanguageUnknown) {
3993 // OpSource Language Version File Source
3994 Instruction sourceInst(NoResult, NoType, OpSource);
3995 sourceInst.addImmediateOperand(sourceLang);
3996 sourceInst.addImmediateOperand(sourceVersion);
3998 if (fileId != NoResult) {
3999 sourceInst.addIdOperand(fileId);
4001 if (text.size() > 0) {
4003 std::string subString;
4004 while ((int)text.size() - nextByte > 0) {
4005 subString = text.substr(nextByte, nonNullBytesPerInstruction);
4006 if (nextByte == 0) {
4008 sourceInst.addStringOperand(subString.c_str());
4009 sourceInst.dump(out);
4012 Instruction sourceContinuedInst(OpSourceContinued);
4013 sourceContinuedInst.addStringOperand(subString.c_str());
4014 sourceContinuedInst.dump(out);
4016 nextByte += nonNullBytesPerInstruction;
4019 sourceInst.dump(out);
4021 sourceInst.dump(out);
4025 // Dump an OpSource[Continued] sequence for the source and every include file
4026 void Builder::dumpSourceInstructions(std::vector<unsigned int>& out) const
4028 if (emitNonSemanticShaderDebugInfo) return;
4029 dumpSourceInstructions(sourceFileStringId, sourceText, out);
4030 for (auto iItr = includeFiles.begin(); iItr != includeFiles.end(); ++iItr)
4031 dumpSourceInstructions(iItr->first, *iItr->second, out);
4034 void Builder::dumpInstructions(std::vector<unsigned int>& out,
4035 const std::vector<std::unique_ptr<Instruction> >& instructions) const
4037 for (int i = 0; i < (int)instructions.size(); ++i) {
4038 instructions[i]->dump(out);
4042 void Builder::dumpModuleProcesses(std::vector<unsigned int>& out) const
4044 for (int i = 0; i < (int)moduleProcesses.size(); ++i) {
4045 Instruction moduleProcessed(OpModuleProcessed);
4046 moduleProcessed.addStringOperand(moduleProcesses[i]);
4047 moduleProcessed.dump(out);
4051 }; // end spv namespace