2 // Copyright (C) 2014-2015 LunarG, Inc.
3 // Copyright (C) 2015-2016 Google, Inc.
5 // All rights reserved.
7 // Redistribution and use in source and binary forms, with or without
8 // modification, are permitted provided that the following conditions
11 // Redistributions of source code must retain the above copyright
12 // notice, this list of conditions and the following disclaimer.
14 // Redistributions in binary form must reproduce the above
15 // copyright notice, this list of conditions and the following
16 // disclaimer in the documentation and/or other materials provided
17 // with the distribution.
19 // Neither the name of 3Dlabs Inc. Ltd. nor the names of its
20 // contributors may be used to endorse or promote products derived
21 // from this software without specific prior written permission.
23 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
24 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
25 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
26 // FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
27 // COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
28 // INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
29 // BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
30 // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
31 // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32 // LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
33 // ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
34 // POSSIBILITY OF SUCH DAMAGE.
37 // Helper for making SPIR-V IR. Generally, this is documented in the header
44 #include <unordered_set>
47 #include "SpvBuilder.h"
49 #include "hex_float.h"
57 Builder::Builder(unsigned int spvVersion, unsigned int magicNumber, SpvBuildLogger* buildLogger) :
58 spvVersion(spvVersion),
59 source(SourceLanguageUnknown),
61 sourceFileStringId(NoResult),
64 addressModel(AddressingModelLogical),
65 memoryModel(MemoryModelGLSL450),
66 builderNumber(magicNumber),
69 entryPointFunction(0),
70 generatingOpCodeForSpecConst(false),
80 Id Builder::import(const char* name)
82 Instruction* import = new Instruction(getUniqueId(), NoType, OpExtInstImport);
83 import->addStringOperand(name);
84 module.mapInstruction(import);
86 imports.push_back(std::unique_ptr<Instruction>(import));
87 return import->getResultId();
90 // Emit an OpLine if we've been asked to emit OpLines and the line number
91 // has changed since the last time, and is a valid line number.
92 void Builder::setLine(int lineNum)
94 if (lineNum != 0 && lineNum != currentLine) {
95 currentLine = lineNum;
97 addLine(sourceFileStringId, currentLine, 0);
101 void Builder::addLine(Id fileName, int lineNum, int column)
103 Instruction* line = new Instruction(OpLine);
104 line->addIdOperand(fileName);
105 line->addImmediateOperand(lineNum);
106 line->addImmediateOperand(column);
107 buildPoint->addInstruction(std::unique_ptr<Instruction>(line));
110 // For creating new groupedTypes (will return old type if the requested one was already made).
111 Id Builder::makeVoidType()
114 if (groupedTypes[OpTypeVoid].size() == 0) {
115 type = new Instruction(getUniqueId(), NoType, OpTypeVoid);
116 groupedTypes[OpTypeVoid].push_back(type);
117 constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(type));
118 module.mapInstruction(type);
120 type = groupedTypes[OpTypeVoid].back();
122 return type->getResultId();
125 Id Builder::makeBoolType()
128 if (groupedTypes[OpTypeBool].size() == 0) {
129 type = new Instruction(getUniqueId(), NoType, OpTypeBool);
130 groupedTypes[OpTypeBool].push_back(type);
131 constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(type));
132 module.mapInstruction(type);
134 type = groupedTypes[OpTypeBool].back();
136 return type->getResultId();
139 Id Builder::makeSamplerType()
142 if (groupedTypes[OpTypeSampler].size() == 0) {
143 type = new Instruction(getUniqueId(), NoType, OpTypeSampler);
144 groupedTypes[OpTypeSampler].push_back(type);
145 constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(type));
146 module.mapInstruction(type);
148 type = groupedTypes[OpTypeSampler].back();
150 return type->getResultId();
153 Id Builder::makePointer(StorageClass storageClass, Id pointee)
157 for (int t = 0; t < (int)groupedTypes[OpTypePointer].size(); ++t) {
158 type = groupedTypes[OpTypePointer][t];
159 if (type->getImmediateOperand(0) == (unsigned)storageClass &&
160 type->getIdOperand(1) == pointee)
161 return type->getResultId();
164 // not found, make it
165 type = new Instruction(getUniqueId(), NoType, OpTypePointer);
166 type->addImmediateOperand(storageClass);
167 type->addIdOperand(pointee);
168 groupedTypes[OpTypePointer].push_back(type);
169 constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(type));
170 module.mapInstruction(type);
172 return type->getResultId();
175 Id Builder::makeIntegerType(int width, bool hasSign)
179 for (int t = 0; t < (int)groupedTypes[OpTypeInt].size(); ++t) {
180 type = groupedTypes[OpTypeInt][t];
181 if (type->getImmediateOperand(0) == (unsigned)width &&
182 type->getImmediateOperand(1) == (hasSign ? 1u : 0u))
183 return type->getResultId();
186 // not found, make it
187 type = new Instruction(getUniqueId(), NoType, OpTypeInt);
188 type->addImmediateOperand(width);
189 type->addImmediateOperand(hasSign ? 1 : 0);
190 groupedTypes[OpTypeInt].push_back(type);
191 constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(type));
192 module.mapInstruction(type);
194 // deal with capabilities
198 // these are currently handled by storage-type declarations and post processing
201 addCapability(CapabilityInt64);
207 return type->getResultId();
210 Id Builder::makeFloatType(int width)
214 for (int t = 0; t < (int)groupedTypes[OpTypeFloat].size(); ++t) {
215 type = groupedTypes[OpTypeFloat][t];
216 if (type->getImmediateOperand(0) == (unsigned)width)
217 return type->getResultId();
220 // not found, make it
221 type = new Instruction(getUniqueId(), NoType, OpTypeFloat);
222 type->addImmediateOperand(width);
223 groupedTypes[OpTypeFloat].push_back(type);
224 constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(type));
225 module.mapInstruction(type);
227 // deal with capabilities
230 // currently handled by storage-type declarations and post processing
233 addCapability(CapabilityFloat64);
239 return type->getResultId();
242 // Make a struct without checking for duplication.
243 // See makeStructResultType() for non-decorated structs
244 // needed as the result of some instructions, which does
245 // check for duplicates.
246 Id Builder::makeStructType(const std::vector<Id>& members, const char* name)
248 // Don't look for previous one, because in the general case,
249 // structs can be duplicated except for decorations.
251 // not found, make it
252 Instruction* type = new Instruction(getUniqueId(), NoType, OpTypeStruct);
253 for (int op = 0; op < (int)members.size(); ++op)
254 type->addIdOperand(members[op]);
255 groupedTypes[OpTypeStruct].push_back(type);
256 constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(type));
257 module.mapInstruction(type);
258 addName(type->getResultId(), name);
260 return type->getResultId();
263 // Make a struct for the simple results of several instructions,
264 // checking for duplication.
265 Id Builder::makeStructResultType(Id type0, Id type1)
269 for (int t = 0; t < (int)groupedTypes[OpTypeStruct].size(); ++t) {
270 type = groupedTypes[OpTypeStruct][t];
271 if (type->getNumOperands() != 2)
273 if (type->getIdOperand(0) != type0 ||
274 type->getIdOperand(1) != type1)
276 return type->getResultId();
279 // not found, make it
280 std::vector<spv::Id> members;
281 members.push_back(type0);
282 members.push_back(type1);
284 return makeStructType(members, "ResType");
287 Id Builder::makeVectorType(Id component, int size)
291 for (int t = 0; t < (int)groupedTypes[OpTypeVector].size(); ++t) {
292 type = groupedTypes[OpTypeVector][t];
293 if (type->getIdOperand(0) == component &&
294 type->getImmediateOperand(1) == (unsigned)size)
295 return type->getResultId();
298 // not found, make it
299 type = new Instruction(getUniqueId(), NoType, OpTypeVector);
300 type->addIdOperand(component);
301 type->addImmediateOperand(size);
302 groupedTypes[OpTypeVector].push_back(type);
303 constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(type));
304 module.mapInstruction(type);
306 return type->getResultId();
309 Id Builder::makeMatrixType(Id component, int cols, int rows)
311 assert(cols <= maxMatrixSize && rows <= maxMatrixSize);
313 Id column = makeVectorType(component, rows);
317 for (int t = 0; t < (int)groupedTypes[OpTypeMatrix].size(); ++t) {
318 type = groupedTypes[OpTypeMatrix][t];
319 if (type->getIdOperand(0) == column &&
320 type->getImmediateOperand(1) == (unsigned)cols)
321 return type->getResultId();
324 // not found, make it
325 type = new Instruction(getUniqueId(), NoType, OpTypeMatrix);
326 type->addIdOperand(column);
327 type->addImmediateOperand(cols);
328 groupedTypes[OpTypeMatrix].push_back(type);
329 constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(type));
330 module.mapInstruction(type);
332 return type->getResultId();
335 // TODO: performance: track arrays per stride
336 // If a stride is supplied (non-zero) make an array.
337 // If no stride (0), reuse previous array types.
338 // 'size' is an Id of a constant or specialization constant of the array size
339 Id Builder::makeArrayType(Id element, Id sizeId, int stride)
343 // try to find existing type
344 for (int t = 0; t < (int)groupedTypes[OpTypeArray].size(); ++t) {
345 type = groupedTypes[OpTypeArray][t];
346 if (type->getIdOperand(0) == element &&
347 type->getIdOperand(1) == sizeId)
348 return type->getResultId();
352 // not found, make it
353 type = new Instruction(getUniqueId(), NoType, OpTypeArray);
354 type->addIdOperand(element);
355 type->addIdOperand(sizeId);
356 groupedTypes[OpTypeArray].push_back(type);
357 constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(type));
358 module.mapInstruction(type);
360 return type->getResultId();
363 Id Builder::makeRuntimeArray(Id element)
365 Instruction* type = new Instruction(getUniqueId(), NoType, OpTypeRuntimeArray);
366 type->addIdOperand(element);
367 constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(type));
368 module.mapInstruction(type);
370 return type->getResultId();
373 Id Builder::makeFunctionType(Id returnType, const std::vector<Id>& paramTypes)
377 for (int t = 0; t < (int)groupedTypes[OpTypeFunction].size(); ++t) {
378 type = groupedTypes[OpTypeFunction][t];
379 if (type->getIdOperand(0) != returnType || (int)paramTypes.size() != type->getNumOperands() - 1)
381 bool mismatch = false;
382 for (int p = 0; p < (int)paramTypes.size(); ++p) {
383 if (paramTypes[p] != type->getIdOperand(p + 1)) {
389 return type->getResultId();
392 // not found, make it
393 type = new Instruction(getUniqueId(), NoType, OpTypeFunction);
394 type->addIdOperand(returnType);
395 for (int p = 0; p < (int)paramTypes.size(); ++p)
396 type->addIdOperand(paramTypes[p]);
397 groupedTypes[OpTypeFunction].push_back(type);
398 constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(type));
399 module.mapInstruction(type);
401 return type->getResultId();
404 Id Builder::makeImageType(Id sampledType, Dim dim, bool depth, bool arrayed, bool ms, unsigned sampled, ImageFormat format)
406 assert(sampled == 1 || sampled == 2);
410 for (int t = 0; t < (int)groupedTypes[OpTypeImage].size(); ++t) {
411 type = groupedTypes[OpTypeImage][t];
412 if (type->getIdOperand(0) == sampledType &&
413 type->getImmediateOperand(1) == (unsigned int)dim &&
414 type->getImmediateOperand(2) == ( depth ? 1u : 0u) &&
415 type->getImmediateOperand(3) == (arrayed ? 1u : 0u) &&
416 type->getImmediateOperand(4) == ( ms ? 1u : 0u) &&
417 type->getImmediateOperand(5) == sampled &&
418 type->getImmediateOperand(6) == (unsigned int)format)
419 return type->getResultId();
422 // not found, make it
423 type = new Instruction(getUniqueId(), NoType, OpTypeImage);
424 type->addIdOperand(sampledType);
425 type->addImmediateOperand( dim);
426 type->addImmediateOperand( depth ? 1 : 0);
427 type->addImmediateOperand(arrayed ? 1 : 0);
428 type->addImmediateOperand( ms ? 1 : 0);
429 type->addImmediateOperand(sampled);
430 type->addImmediateOperand((unsigned int)format);
432 groupedTypes[OpTypeImage].push_back(type);
433 constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(type));
434 module.mapInstruction(type);
436 // deal with capabilities
440 addCapability(CapabilitySampledBuffer);
442 addCapability(CapabilityImageBuffer);
446 addCapability(CapabilitySampled1D);
448 addCapability(CapabilityImage1D);
453 addCapability(CapabilitySampledCubeArray);
455 addCapability(CapabilityImageCubeArray);
460 addCapability(CapabilitySampledRect);
462 addCapability(CapabilityImageRect);
465 addCapability(CapabilityInputAttachment);
473 // Images used with subpass data are not storage
474 // images, so don't require the capability for them.
475 if (dim != Dim::DimSubpassData)
476 addCapability(CapabilityStorageImageMultisample);
478 addCapability(CapabilityImageMSArray);
482 return type->getResultId();
485 Id Builder::makeSampledImageType(Id imageType)
489 for (int t = 0; t < (int)groupedTypes[OpTypeSampledImage].size(); ++t) {
490 type = groupedTypes[OpTypeSampledImage][t];
491 if (type->getIdOperand(0) == imageType)
492 return type->getResultId();
495 // not found, make it
496 type = new Instruction(getUniqueId(), NoType, OpTypeSampledImage);
497 type->addIdOperand(imageType);
499 groupedTypes[OpTypeSampledImage].push_back(type);
500 constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(type));
501 module.mapInstruction(type);
503 return type->getResultId();
507 Id Builder::makeAccelerationStructureNVType()
510 if (groupedTypes[OpTypeAccelerationStructureNV].size() == 0) {
511 type = new Instruction(getUniqueId(), NoType, OpTypeAccelerationStructureNV);
512 constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(type));
513 module.mapInstruction(type);
515 type = groupedTypes[OpTypeAccelerationStructureNV].back();
518 return type->getResultId();
521 Id Builder::getDerefTypeId(Id resultId) const
523 Id typeId = getTypeId(resultId);
524 assert(isPointerType(typeId));
526 return module.getInstruction(typeId)->getIdOperand(1);
529 Op Builder::getMostBasicTypeClass(Id typeId) const
531 Instruction* instr = module.getInstruction(typeId);
533 Op typeClass = instr->getOpCode();
539 case OpTypeRuntimeArray:
540 return getMostBasicTypeClass(instr->getIdOperand(0));
542 return getMostBasicTypeClass(instr->getIdOperand(1));
548 int Builder::getNumTypeConstituents(Id typeId) const
550 Instruction* instr = module.getInstruction(typeId);
552 switch (instr->getOpCode())
560 return instr->getImmediateOperand(1);
563 Id lengthId = instr->getIdOperand(1);
564 return module.getInstruction(lengthId)->getImmediateOperand(0);
567 return instr->getNumOperands();
574 // Return the lowest-level type of scalar that an homogeneous composite is made out of.
575 // Typically, this is just to find out if something is made out of ints or floats.
576 // However, it includes returning a structure, if say, it is an array of structure.
577 Id Builder::getScalarTypeId(Id typeId) const
579 Instruction* instr = module.getInstruction(typeId);
581 Op typeClass = instr->getOpCode();
589 return instr->getResultId();
593 case OpTypeRuntimeArray:
595 return getScalarTypeId(getContainedTypeId(typeId));
602 // Return the type of 'member' of a composite.
603 Id Builder::getContainedTypeId(Id typeId, int member) const
605 Instruction* instr = module.getInstruction(typeId);
607 Op typeClass = instr->getOpCode();
613 case OpTypeRuntimeArray:
614 return instr->getIdOperand(0);
616 return instr->getIdOperand(1);
618 return instr->getIdOperand(member);
625 // Return the immediately contained type of a given composite type.
626 Id Builder::getContainedTypeId(Id typeId) const
628 return getContainedTypeId(typeId, 0);
631 // Returns true if 'typeId' is or contains a scalar type declared with 'typeOp'
632 // of width 'width'. The 'width' is only consumed for int and float types.
633 // Returns false otherwise.
634 bool Builder::containsType(Id typeId, spv::Op typeOp, unsigned int width) const
636 const Instruction& instr = *module.getInstruction(typeId);
638 Op typeClass = instr.getOpCode();
643 return typeClass == typeOp && instr.getImmediateOperand(0) == width;
645 for (int m = 0; m < instr.getNumOperands(); ++m) {
646 if (containsType(instr.getIdOperand(m), typeOp, width))
653 case OpTypeRuntimeArray:
655 return containsType(getContainedTypeId(typeId), typeOp, width);
657 return typeClass == typeOp;
661 // See if a scalar constant of this type has already been created, so it
662 // can be reused rather than duplicated. (Required by the specification).
663 Id Builder::findScalarConstant(Op typeClass, Op opcode, Id typeId, unsigned value)
665 Instruction* constant;
666 for (int i = 0; i < (int)groupedConstants[typeClass].size(); ++i) {
667 constant = groupedConstants[typeClass][i];
668 if (constant->getOpCode() == opcode &&
669 constant->getTypeId() == typeId &&
670 constant->getImmediateOperand(0) == value)
671 return constant->getResultId();
677 // Version of findScalarConstant (see above) for scalars that take two operands (e.g. a 'double' or 'int64').
678 Id Builder::findScalarConstant(Op typeClass, Op opcode, Id typeId, unsigned v1, unsigned v2)
680 Instruction* constant;
681 for (int i = 0; i < (int)groupedConstants[typeClass].size(); ++i) {
682 constant = groupedConstants[typeClass][i];
683 if (constant->getOpCode() == opcode &&
684 constant->getTypeId() == typeId &&
685 constant->getImmediateOperand(0) == v1 &&
686 constant->getImmediateOperand(1) == v2)
687 return constant->getResultId();
693 // Return true if consuming 'opcode' means consuming a constant.
694 // "constant" here means after final transform to executable code,
695 // the value consumed will be a constant, so includes specialization.
696 bool Builder::isConstantOpCode(Op opcode) const
701 case OpConstantFalse:
703 case OpConstantComposite:
704 case OpConstantSampler:
706 case OpSpecConstantTrue:
707 case OpSpecConstantFalse:
709 case OpSpecConstantComposite:
710 case OpSpecConstantOp:
717 // Return true if consuming 'opcode' means consuming a specialization constant.
718 bool Builder::isSpecConstantOpCode(Op opcode) const
721 case OpSpecConstantTrue:
722 case OpSpecConstantFalse:
724 case OpSpecConstantComposite:
725 case OpSpecConstantOp:
732 Id Builder::makeBoolConstant(bool b, bool specConstant)
734 Id typeId = makeBoolType();
735 Instruction* constant;
736 Op opcode = specConstant ? (b ? OpSpecConstantTrue : OpSpecConstantFalse) : (b ? OpConstantTrue : OpConstantFalse);
738 // See if we already made it. Applies only to regular constants, because specialization constants
739 // must remain distinct for the purpose of applying a SpecId decoration.
740 if (! specConstant) {
742 for (int i = 0; i < (int)groupedConstants[OpTypeBool].size(); ++i) {
743 constant = groupedConstants[OpTypeBool][i];
744 if (constant->getTypeId() == typeId && constant->getOpCode() == opcode)
745 existing = constant->getResultId();
753 Instruction* c = new Instruction(getUniqueId(), typeId, opcode);
754 constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(c));
755 groupedConstants[OpTypeBool].push_back(c);
756 module.mapInstruction(c);
758 return c->getResultId();
761 Id Builder::makeIntConstant(Id typeId, unsigned value, bool specConstant)
763 Op opcode = specConstant ? OpSpecConstant : OpConstant;
765 // See if we already made it. Applies only to regular constants, because specialization constants
766 // must remain distinct for the purpose of applying a SpecId decoration.
767 if (! specConstant) {
768 Id existing = findScalarConstant(OpTypeInt, opcode, typeId, value);
773 Instruction* c = new Instruction(getUniqueId(), typeId, opcode);
774 c->addImmediateOperand(value);
775 constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(c));
776 groupedConstants[OpTypeInt].push_back(c);
777 module.mapInstruction(c);
779 return c->getResultId();
782 Id Builder::makeInt64Constant(Id typeId, unsigned long long value, bool specConstant)
784 Op opcode = specConstant ? OpSpecConstant : OpConstant;
786 unsigned op1 = value & 0xFFFFFFFF;
787 unsigned op2 = value >> 32;
789 // See if we already made it. Applies only to regular constants, because specialization constants
790 // must remain distinct for the purpose of applying a SpecId decoration.
791 if (! specConstant) {
792 Id existing = findScalarConstant(OpTypeInt, opcode, typeId, op1, op2);
797 Instruction* c = new Instruction(getUniqueId(), typeId, opcode);
798 c->addImmediateOperand(op1);
799 c->addImmediateOperand(op2);
800 constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(c));
801 groupedConstants[OpTypeInt].push_back(c);
802 module.mapInstruction(c);
804 return c->getResultId();
807 Id Builder::makeFloatConstant(float f, bool specConstant)
809 Op opcode = specConstant ? OpSpecConstant : OpConstant;
810 Id typeId = makeFloatType(32);
811 union { float fl; unsigned int ui; } u;
813 unsigned value = u.ui;
815 // See if we already made it. Applies only to regular constants, because specialization constants
816 // must remain distinct for the purpose of applying a SpecId decoration.
817 if (! specConstant) {
818 Id existing = findScalarConstant(OpTypeFloat, opcode, typeId, value);
823 Instruction* c = new Instruction(getUniqueId(), typeId, opcode);
824 c->addImmediateOperand(value);
825 constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(c));
826 groupedConstants[OpTypeFloat].push_back(c);
827 module.mapInstruction(c);
829 return c->getResultId();
832 Id Builder::makeDoubleConstant(double d, bool specConstant)
834 Op opcode = specConstant ? OpSpecConstant : OpConstant;
835 Id typeId = makeFloatType(64);
836 union { double db; unsigned long long ull; } u;
838 unsigned long long value = u.ull;
839 unsigned op1 = value & 0xFFFFFFFF;
840 unsigned op2 = value >> 32;
842 // See if we already made it. Applies only to regular constants, because specialization constants
843 // must remain distinct for the purpose of applying a SpecId decoration.
844 if (! specConstant) {
845 Id existing = findScalarConstant(OpTypeFloat, opcode, typeId, op1, op2);
850 Instruction* c = new Instruction(getUniqueId(), typeId, opcode);
851 c->addImmediateOperand(op1);
852 c->addImmediateOperand(op2);
853 constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(c));
854 groupedConstants[OpTypeFloat].push_back(c);
855 module.mapInstruction(c);
857 return c->getResultId();
860 Id Builder::makeFloat16Constant(float f16, bool specConstant)
862 Op opcode = specConstant ? OpSpecConstant : OpConstant;
863 Id typeId = makeFloatType(16);
865 spvutils::HexFloat<spvutils::FloatProxy<float>> fVal(f16);
866 spvutils::HexFloat<spvutils::FloatProxy<spvutils::Float16>> f16Val(0);
867 fVal.castTo(f16Val, spvutils::kRoundToZero);
869 unsigned value = f16Val.value().getAsFloat().get_value();
871 // See if we already made it. Applies only to regular constants, because specialization constants
872 // must remain distinct for the purpose of applying a SpecId decoration.
874 Id existing = findScalarConstant(OpTypeFloat, opcode, typeId, value);
879 Instruction* c = new Instruction(getUniqueId(), typeId, opcode);
880 c->addImmediateOperand(value);
881 constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(c));
882 groupedConstants[OpTypeFloat].push_back(c);
883 module.mapInstruction(c);
885 return c->getResultId();
888 Id Builder::makeFpConstant(Id type, double d, bool specConstant)
890 assert(isFloatType(type));
892 switch (getScalarTypeWidth(type)) {
894 return makeFloat16Constant((float)d, specConstant);
896 return makeFloatConstant((float)d, specConstant);
898 return makeDoubleConstant(d, specConstant);
907 Id Builder::findCompositeConstant(Op typeClass, const std::vector<Id>& comps)
909 Instruction* constant = 0;
911 for (int i = 0; i < (int)groupedConstants[typeClass].size(); ++i) {
912 constant = groupedConstants[typeClass][i];
915 if (constant->getNumOperands() != (int)comps.size())
919 bool mismatch = false;
920 for (int op = 0; op < constant->getNumOperands(); ++op) {
921 if (constant->getIdOperand(op) != comps[op]) {
932 return found ? constant->getResultId() : NoResult;
935 Id Builder::findStructConstant(Id typeId, const std::vector<Id>& comps)
937 Instruction* constant = 0;
939 for (int i = 0; i < (int)groupedStructConstants[typeId].size(); ++i) {
940 constant = groupedStructConstants[typeId][i];
943 bool mismatch = false;
944 for (int op = 0; op < constant->getNumOperands(); ++op) {
945 if (constant->getIdOperand(op) != comps[op]) {
956 return found ? constant->getResultId() : NoResult;
959 // Comments in header
960 Id Builder::makeCompositeConstant(Id typeId, const std::vector<Id>& members, bool specConstant)
962 Op opcode = specConstant ? OpSpecConstantComposite : OpConstantComposite;
964 Op typeClass = getTypeClass(typeId);
970 if (! specConstant) {
971 Id existing = findCompositeConstant(typeClass, members);
977 if (! specConstant) {
978 Id existing = findStructConstant(typeId, members);
985 return makeFloatConstant(0.0);
988 Instruction* c = new Instruction(getUniqueId(), typeId, opcode);
989 for (int op = 0; op < (int)members.size(); ++op)
990 c->addIdOperand(members[op]);
991 constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(c));
992 if (typeClass == OpTypeStruct)
993 groupedStructConstants[typeId].push_back(c);
995 groupedConstants[typeClass].push_back(c);
996 module.mapInstruction(c);
998 return c->getResultId();
1001 Instruction* Builder::addEntryPoint(ExecutionModel model, Function* function, const char* name)
1003 Instruction* entryPoint = new Instruction(OpEntryPoint);
1004 entryPoint->addImmediateOperand(model);
1005 entryPoint->addIdOperand(function->getId());
1006 entryPoint->addStringOperand(name);
1008 entryPoints.push_back(std::unique_ptr<Instruction>(entryPoint));
1013 // Currently relying on the fact that all 'value' of interest are small non-negative values.
1014 void Builder::addExecutionMode(Function* entryPoint, ExecutionMode mode, int value1, int value2, int value3)
1016 Instruction* instr = new Instruction(OpExecutionMode);
1017 instr->addIdOperand(entryPoint->getId());
1018 instr->addImmediateOperand(mode);
1020 instr->addImmediateOperand(value1);
1022 instr->addImmediateOperand(value2);
1024 instr->addImmediateOperand(value3);
1026 executionModes.push_back(std::unique_ptr<Instruction>(instr));
1029 void Builder::addName(Id id, const char* string)
1031 Instruction* name = new Instruction(OpName);
1032 name->addIdOperand(id);
1033 name->addStringOperand(string);
1035 names.push_back(std::unique_ptr<Instruction>(name));
1038 void Builder::addMemberName(Id id, int memberNumber, const char* string)
1040 Instruction* name = new Instruction(OpMemberName);
1041 name->addIdOperand(id);
1042 name->addImmediateOperand(memberNumber);
1043 name->addStringOperand(string);
1045 names.push_back(std::unique_ptr<Instruction>(name));
1048 void Builder::addDecoration(Id id, Decoration decoration, int num)
1050 if (decoration == spv::DecorationMax)
1053 Instruction* dec = new Instruction(OpDecorate);
1054 dec->addIdOperand(id);
1055 dec->addImmediateOperand(decoration);
1057 dec->addImmediateOperand(num);
1059 decorations.push_back(std::unique_ptr<Instruction>(dec));
1062 void Builder::addDecoration(Id id, Decoration decoration, const char* s)
1064 if (decoration == spv::DecorationMax)
1067 Instruction* dec = new Instruction(OpDecorateStringGOOGLE);
1068 dec->addIdOperand(id);
1069 dec->addImmediateOperand(decoration);
1070 dec->addStringOperand(s);
1072 decorations.push_back(std::unique_ptr<Instruction>(dec));
1075 void Builder::addDecorationId(Id id, Decoration decoration, Id idDecoration)
1077 if (decoration == spv::DecorationMax)
1080 Instruction* dec = new Instruction(OpDecorateId);
1081 dec->addIdOperand(id);
1082 dec->addImmediateOperand(decoration);
1083 dec->addIdOperand(idDecoration);
1085 decorations.push_back(std::unique_ptr<Instruction>(dec));
1088 void Builder::addMemberDecoration(Id id, unsigned int member, Decoration decoration, int num)
1090 if (decoration == spv::DecorationMax)
1093 Instruction* dec = new Instruction(OpMemberDecorate);
1094 dec->addIdOperand(id);
1095 dec->addImmediateOperand(member);
1096 dec->addImmediateOperand(decoration);
1098 dec->addImmediateOperand(num);
1100 decorations.push_back(std::unique_ptr<Instruction>(dec));
1103 void Builder::addMemberDecoration(Id id, unsigned int member, Decoration decoration, const char *s)
1105 if (decoration == spv::DecorationMax)
1108 Instruction* dec = new Instruction(OpMemberDecorateStringGOOGLE);
1109 dec->addIdOperand(id);
1110 dec->addImmediateOperand(member);
1111 dec->addImmediateOperand(decoration);
1112 dec->addStringOperand(s);
1114 decorations.push_back(std::unique_ptr<Instruction>(dec));
1117 // Comments in header
1118 Function* Builder::makeEntryPoint(const char* entryPoint)
1120 assert(! entryPointFunction);
1123 std::vector<Id> params;
1124 std::vector<std::vector<Decoration>> decorations;
1126 entryPointFunction = makeFunctionEntry(NoPrecision, makeVoidType(), entryPoint, params, decorations, &entry);
1128 return entryPointFunction;
1131 // Comments in header
1132 Function* Builder::makeFunctionEntry(Decoration precision, Id returnType, const char* name,
1133 const std::vector<Id>& paramTypes, const std::vector<std::vector<Decoration>>& decorations, Block **entry)
1135 // Make the function and initial instructions in it
1136 Id typeId = makeFunctionType(returnType, paramTypes);
1137 Id firstParamId = paramTypes.size() == 0 ? 0 : getUniqueIds((int)paramTypes.size());
1138 Function* function = new Function(getUniqueId(), returnType, typeId, firstParamId, module);
1140 // Set up the precisions
1141 setPrecision(function->getId(), precision);
1142 for (unsigned p = 0; p < (unsigned)decorations.size(); ++p) {
1143 for (int d = 0; d < (int)decorations[p].size(); ++d)
1144 addDecoration(firstParamId + p, decorations[p][d]);
1149 *entry = new Block(getUniqueId(), *function);
1150 function->addBlock(*entry);
1151 setBuildPoint(*entry);
1155 addName(function->getId(), name);
1157 functions.push_back(std::unique_ptr<Function>(function));
1162 // Comments in header
1163 void Builder::makeReturn(bool implicit, Id retVal)
1166 Instruction* inst = new Instruction(NoResult, NoType, OpReturnValue);
1167 inst->addIdOperand(retVal);
1168 buildPoint->addInstruction(std::unique_ptr<Instruction>(inst));
1170 buildPoint->addInstruction(std::unique_ptr<Instruction>(new Instruction(NoResult, NoType, OpReturn)));
1173 createAndSetNoPredecessorBlock("post-return");
1176 // Comments in header
1177 void Builder::leaveFunction()
1179 Block* block = buildPoint;
1180 Function& function = buildPoint->getParent();
1183 // If our function did not contain a return, add a return void now.
1184 if (! block->isTerminated()) {
1185 if (function.getReturnType() == makeVoidType())
1188 makeReturn(true, createUndefined(function.getReturnType()));
1193 // Comments in header
1194 void Builder::makeDiscard()
1196 buildPoint->addInstruction(std::unique_ptr<Instruction>(new Instruction(OpKill)));
1197 createAndSetNoPredecessorBlock("post-discard");
1200 // Comments in header
1201 Id Builder::createVariable(StorageClass storageClass, Id type, const char* name)
1203 Id pointerType = makePointer(storageClass, type);
1204 Instruction* inst = new Instruction(getUniqueId(), pointerType, OpVariable);
1205 inst->addImmediateOperand(storageClass);
1207 switch (storageClass) {
1208 case StorageClassFunction:
1209 // Validation rules require the declaration in the entry block
1210 buildPoint->getParent().addLocalVariable(std::unique_ptr<Instruction>(inst));
1214 constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(inst));
1215 module.mapInstruction(inst);
1220 addName(inst->getResultId(), name);
1222 return inst->getResultId();
1225 // Comments in header
1226 Id Builder::createUndefined(Id type)
1228 Instruction* inst = new Instruction(getUniqueId(), type, OpUndef);
1229 buildPoint->addInstruction(std::unique_ptr<Instruction>(inst));
1230 return inst->getResultId();
1233 // Comments in header
1234 void Builder::createStore(Id rValue, Id lValue, spv::MemoryAccessMask memoryAccess, spv::Scope scope)
1236 Instruction* store = new Instruction(OpStore);
1237 store->addIdOperand(lValue);
1238 store->addIdOperand(rValue);
1240 if (memoryAccess != MemoryAccessMaskNone) {
1241 store->addImmediateOperand(memoryAccess);
1242 if (memoryAccess & spv::MemoryAccessMakePointerAvailableKHRMask) {
1243 store->addIdOperand(makeUintConstant(scope));
1247 buildPoint->addInstruction(std::unique_ptr<Instruction>(store));
1250 // Comments in header
1251 Id Builder::createLoad(Id lValue, spv::MemoryAccessMask memoryAccess, spv::Scope scope)
1253 Instruction* load = new Instruction(getUniqueId(), getDerefTypeId(lValue), OpLoad);
1254 load->addIdOperand(lValue);
1256 if (memoryAccess != MemoryAccessMaskNone) {
1257 load->addImmediateOperand(memoryAccess);
1258 if (memoryAccess & spv::MemoryAccessMakePointerVisibleKHRMask) {
1259 load->addIdOperand(makeUintConstant(scope));
1263 buildPoint->addInstruction(std::unique_ptr<Instruction>(load));
1265 return load->getResultId();
1268 // Comments in header
1269 Id Builder::createAccessChain(StorageClass storageClass, Id base, const std::vector<Id>& offsets)
1271 // Figure out the final resulting type.
1272 spv::Id typeId = getTypeId(base);
1273 assert(isPointerType(typeId) && offsets.size() > 0);
1274 typeId = getContainedTypeId(typeId);
1275 for (int i = 0; i < (int)offsets.size(); ++i) {
1276 if (isStructType(typeId)) {
1277 assert(isConstantScalar(offsets[i]));
1278 typeId = getContainedTypeId(typeId, getConstantScalar(offsets[i]));
1280 typeId = getContainedTypeId(typeId, offsets[i]);
1282 typeId = makePointer(storageClass, typeId);
1284 // Make the instruction
1285 Instruction* chain = new Instruction(getUniqueId(), typeId, OpAccessChain);
1286 chain->addIdOperand(base);
1287 for (int i = 0; i < (int)offsets.size(); ++i)
1288 chain->addIdOperand(offsets[i]);
1289 buildPoint->addInstruction(std::unique_ptr<Instruction>(chain));
1291 return chain->getResultId();
1294 Id Builder::createArrayLength(Id base, unsigned int member)
1296 spv::Id intType = makeUintType(32);
1297 Instruction* length = new Instruction(getUniqueId(), intType, OpArrayLength);
1298 length->addIdOperand(base);
1299 length->addImmediateOperand(member);
1300 buildPoint->addInstruction(std::unique_ptr<Instruction>(length));
1302 return length->getResultId();
1305 Id Builder::createCompositeExtract(Id composite, Id typeId, unsigned index)
1307 // Generate code for spec constants if in spec constant operation
1309 if (generatingOpCodeForSpecConst) {
1310 return createSpecConstantOp(OpCompositeExtract, typeId, std::vector<Id>(1, composite), std::vector<Id>(1, index));
1312 Instruction* extract = new Instruction(getUniqueId(), typeId, OpCompositeExtract);
1313 extract->addIdOperand(composite);
1314 extract->addImmediateOperand(index);
1315 buildPoint->addInstruction(std::unique_ptr<Instruction>(extract));
1317 return extract->getResultId();
1320 Id Builder::createCompositeExtract(Id composite, Id typeId, const std::vector<unsigned>& indexes)
1322 // Generate code for spec constants if in spec constant operation
1324 if (generatingOpCodeForSpecConst) {
1325 return createSpecConstantOp(OpCompositeExtract, typeId, std::vector<Id>(1, composite), indexes);
1327 Instruction* extract = new Instruction(getUniqueId(), typeId, OpCompositeExtract);
1328 extract->addIdOperand(composite);
1329 for (int i = 0; i < (int)indexes.size(); ++i)
1330 extract->addImmediateOperand(indexes[i]);
1331 buildPoint->addInstruction(std::unique_ptr<Instruction>(extract));
1333 return extract->getResultId();
1336 Id Builder::createCompositeInsert(Id object, Id composite, Id typeId, unsigned index)
1338 Instruction* insert = new Instruction(getUniqueId(), typeId, OpCompositeInsert);
1339 insert->addIdOperand(object);
1340 insert->addIdOperand(composite);
1341 insert->addImmediateOperand(index);
1342 buildPoint->addInstruction(std::unique_ptr<Instruction>(insert));
1344 return insert->getResultId();
1347 Id Builder::createCompositeInsert(Id object, Id composite, Id typeId, const std::vector<unsigned>& indexes)
1349 Instruction* insert = new Instruction(getUniqueId(), typeId, OpCompositeInsert);
1350 insert->addIdOperand(object);
1351 insert->addIdOperand(composite);
1352 for (int i = 0; i < (int)indexes.size(); ++i)
1353 insert->addImmediateOperand(indexes[i]);
1354 buildPoint->addInstruction(std::unique_ptr<Instruction>(insert));
1356 return insert->getResultId();
1359 Id Builder::createVectorExtractDynamic(Id vector, Id typeId, Id componentIndex)
1361 Instruction* extract = new Instruction(getUniqueId(), typeId, OpVectorExtractDynamic);
1362 extract->addIdOperand(vector);
1363 extract->addIdOperand(componentIndex);
1364 buildPoint->addInstruction(std::unique_ptr<Instruction>(extract));
1366 return extract->getResultId();
1369 Id Builder::createVectorInsertDynamic(Id vector, Id typeId, Id component, Id componentIndex)
1371 Instruction* insert = new Instruction(getUniqueId(), typeId, OpVectorInsertDynamic);
1372 insert->addIdOperand(vector);
1373 insert->addIdOperand(component);
1374 insert->addIdOperand(componentIndex);
1375 buildPoint->addInstruction(std::unique_ptr<Instruction>(insert));
1377 return insert->getResultId();
1380 // An opcode that has no operands, no result id, and no type
1381 void Builder::createNoResultOp(Op opCode)
1383 Instruction* op = new Instruction(opCode);
1384 buildPoint->addInstruction(std::unique_ptr<Instruction>(op));
1387 // An opcode that has one id operand, no result id, and no type
1388 void Builder::createNoResultOp(Op opCode, Id operand)
1390 Instruction* op = new Instruction(opCode);
1391 op->addIdOperand(operand);
1392 buildPoint->addInstruction(std::unique_ptr<Instruction>(op));
1395 // An opcode that has one or more operands, no result id, and no type
1396 void Builder::createNoResultOp(Op opCode, const std::vector<Id>& operands)
1398 Instruction* op = new Instruction(opCode);
1399 for (auto it = operands.cbegin(); it != operands.cend(); ++it) {
1400 op->addIdOperand(*it);
1402 buildPoint->addInstruction(std::unique_ptr<Instruction>(op));
1405 // An opcode that has multiple operands, no result id, and no type
1406 void Builder::createNoResultOp(Op opCode, const std::vector<IdImmediate>& operands)
1408 Instruction* op = new Instruction(opCode);
1409 for (auto it = operands.cbegin(); it != operands.cend(); ++it) {
1411 op->addIdOperand(it->word);
1413 op->addImmediateOperand(it->word);
1415 buildPoint->addInstruction(std::unique_ptr<Instruction>(op));
1418 void Builder::createControlBarrier(Scope execution, Scope memory, MemorySemanticsMask semantics)
1420 Instruction* op = new Instruction(OpControlBarrier);
1421 op->addIdOperand(makeUintConstant(execution));
1422 op->addIdOperand(makeUintConstant(memory));
1423 op->addIdOperand(makeUintConstant(semantics));
1424 buildPoint->addInstruction(std::unique_ptr<Instruction>(op));
1427 void Builder::createMemoryBarrier(unsigned executionScope, unsigned memorySemantics)
1429 Instruction* op = new Instruction(OpMemoryBarrier);
1430 op->addIdOperand(makeUintConstant(executionScope));
1431 op->addIdOperand(makeUintConstant(memorySemantics));
1432 buildPoint->addInstruction(std::unique_ptr<Instruction>(op));
1435 // An opcode that has one operands, a result id, and a type
1436 Id Builder::createUnaryOp(Op opCode, Id typeId, Id operand)
1438 // Generate code for spec constants if in spec constant operation
1440 if (generatingOpCodeForSpecConst) {
1441 return createSpecConstantOp(opCode, typeId, std::vector<Id>(1, operand), std::vector<Id>());
1443 Instruction* op = new Instruction(getUniqueId(), typeId, opCode);
1444 op->addIdOperand(operand);
1445 buildPoint->addInstruction(std::unique_ptr<Instruction>(op));
1447 return op->getResultId();
1450 Id Builder::createBinOp(Op opCode, Id typeId, Id left, Id right)
1452 // Generate code for spec constants if in spec constant operation
1454 if (generatingOpCodeForSpecConst) {
1455 std::vector<Id> operands(2);
1456 operands[0] = left; operands[1] = right;
1457 return createSpecConstantOp(opCode, typeId, operands, std::vector<Id>());
1459 Instruction* op = new Instruction(getUniqueId(), typeId, opCode);
1460 op->addIdOperand(left);
1461 op->addIdOperand(right);
1462 buildPoint->addInstruction(std::unique_ptr<Instruction>(op));
1464 return op->getResultId();
1467 Id Builder::createTriOp(Op opCode, Id typeId, Id op1, Id op2, Id op3)
1469 // Generate code for spec constants if in spec constant operation
1471 if (generatingOpCodeForSpecConst) {
1472 std::vector<Id> operands(3);
1476 return createSpecConstantOp(
1477 opCode, typeId, operands, std::vector<Id>());
1479 Instruction* op = new Instruction(getUniqueId(), typeId, opCode);
1480 op->addIdOperand(op1);
1481 op->addIdOperand(op2);
1482 op->addIdOperand(op3);
1483 buildPoint->addInstruction(std::unique_ptr<Instruction>(op));
1485 return op->getResultId();
1488 Id Builder::createOp(Op opCode, Id typeId, const std::vector<Id>& operands)
1490 Instruction* op = new Instruction(getUniqueId(), typeId, opCode);
1491 for (auto it = operands.cbegin(); it != operands.cend(); ++it)
1492 op->addIdOperand(*it);
1493 buildPoint->addInstruction(std::unique_ptr<Instruction>(op));
1495 return op->getResultId();
1498 Id Builder::createOp(Op opCode, Id typeId, const std::vector<IdImmediate>& operands)
1500 Instruction* op = new Instruction(getUniqueId(), typeId, opCode);
1501 for (auto it = operands.cbegin(); it != operands.cend(); ++it) {
1503 op->addIdOperand(it->word);
1505 op->addImmediateOperand(it->word);
1507 buildPoint->addInstruction(std::unique_ptr<Instruction>(op));
1509 return op->getResultId();
1512 Id Builder::createSpecConstantOp(Op opCode, Id typeId, const std::vector<Id>& operands, const std::vector<unsigned>& literals)
1514 Instruction* op = new Instruction(getUniqueId(), typeId, OpSpecConstantOp);
1515 op->addImmediateOperand((unsigned) opCode);
1516 for (auto it = operands.cbegin(); it != operands.cend(); ++it)
1517 op->addIdOperand(*it);
1518 for (auto it = literals.cbegin(); it != literals.cend(); ++it)
1519 op->addImmediateOperand(*it);
1520 module.mapInstruction(op);
1521 constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(op));
1523 return op->getResultId();
1526 Id Builder::createFunctionCall(spv::Function* function, const std::vector<spv::Id>& args)
1528 Instruction* op = new Instruction(getUniqueId(), function->getReturnType(), OpFunctionCall);
1529 op->addIdOperand(function->getId());
1530 for (int a = 0; a < (int)args.size(); ++a)
1531 op->addIdOperand(args[a]);
1532 buildPoint->addInstruction(std::unique_ptr<Instruction>(op));
1534 return op->getResultId();
1537 // Comments in header
1538 Id Builder::createRvalueSwizzle(Decoration precision, Id typeId, Id source, const std::vector<unsigned>& channels)
1540 if (channels.size() == 1)
1541 return setPrecision(createCompositeExtract(source, typeId, channels.front()), precision);
1543 if (generatingOpCodeForSpecConst) {
1544 std::vector<Id> operands(2);
1545 operands[0] = operands[1] = source;
1546 return setPrecision(createSpecConstantOp(OpVectorShuffle, typeId, operands, channels), precision);
1548 Instruction* swizzle = new Instruction(getUniqueId(), typeId, OpVectorShuffle);
1549 assert(isVector(source));
1550 swizzle->addIdOperand(source);
1551 swizzle->addIdOperand(source);
1552 for (int i = 0; i < (int)channels.size(); ++i)
1553 swizzle->addImmediateOperand(channels[i]);
1554 buildPoint->addInstruction(std::unique_ptr<Instruction>(swizzle));
1556 return setPrecision(swizzle->getResultId(), precision);
1559 // Comments in header
1560 Id Builder::createLvalueSwizzle(Id typeId, Id target, Id source, const std::vector<unsigned>& channels)
1562 if (channels.size() == 1 && getNumComponents(source) == 1)
1563 return createCompositeInsert(source, target, typeId, channels.front());
1565 Instruction* swizzle = new Instruction(getUniqueId(), typeId, OpVectorShuffle);
1567 assert(isVector(target));
1568 swizzle->addIdOperand(target);
1570 assert(getNumComponents(source) == (int)channels.size());
1571 assert(isVector(source));
1572 swizzle->addIdOperand(source);
1574 // Set up an identity shuffle from the base value to the result value
1575 unsigned int components[4];
1576 int numTargetComponents = getNumComponents(target);
1577 for (int i = 0; i < numTargetComponents; ++i)
1580 // Punch in the l-value swizzle
1581 for (int i = 0; i < (int)channels.size(); ++i)
1582 components[channels[i]] = numTargetComponents + i;
1584 // finish the instruction with these components selectors
1585 for (int i = 0; i < numTargetComponents; ++i)
1586 swizzle->addImmediateOperand(components[i]);
1587 buildPoint->addInstruction(std::unique_ptr<Instruction>(swizzle));
1589 return swizzle->getResultId();
1592 // Comments in header
1593 void Builder::promoteScalar(Decoration precision, Id& left, Id& right)
1595 int direction = getNumComponents(right) - getNumComponents(left);
1598 left = smearScalar(precision, left, makeVectorType(getTypeId(left), getNumComponents(right)));
1599 else if (direction < 0)
1600 right = smearScalar(precision, right, makeVectorType(getTypeId(right), getNumComponents(left)));
1605 // Comments in header
1606 Id Builder::smearScalar(Decoration precision, Id scalar, Id vectorType)
1608 assert(getNumComponents(scalar) == 1);
1609 assert(getTypeId(scalar) == getScalarTypeId(vectorType));
1611 int numComponents = getNumTypeComponents(vectorType);
1612 if (numComponents == 1)
1615 Instruction* smear = nullptr;
1616 if (generatingOpCodeForSpecConst) {
1617 auto members = std::vector<spv::Id>(numComponents, scalar);
1618 // Sometime even in spec-constant-op mode, the temporary vector created by
1619 // promoting a scalar might not be a spec constant. This should depend on
1622 // const vec2 spec_const_result = a_spec_const_vec2 + a_front_end_const_scalar;
1623 // In such cases, the temporary vector created from a_front_end_const_scalar
1624 // is not a spec constant vector, even though the binary operation node is marked
1625 // as 'specConstant' and we are in spec-constant-op mode.
1626 auto result_id = makeCompositeConstant(vectorType, members, isSpecConstant(scalar));
1627 smear = module.getInstruction(result_id);
1629 smear = new Instruction(getUniqueId(), vectorType, OpCompositeConstruct);
1630 for (int c = 0; c < numComponents; ++c)
1631 smear->addIdOperand(scalar);
1632 buildPoint->addInstruction(std::unique_ptr<Instruction>(smear));
1635 return setPrecision(smear->getResultId(), precision);
1638 // Comments in header
1639 Id Builder::createBuiltinCall(Id resultType, Id builtins, int entryPoint, const std::vector<Id>& args)
1641 Instruction* inst = new Instruction(getUniqueId(), resultType, OpExtInst);
1642 inst->addIdOperand(builtins);
1643 inst->addImmediateOperand(entryPoint);
1644 for (int arg = 0; arg < (int)args.size(); ++arg)
1645 inst->addIdOperand(args[arg]);
1647 buildPoint->addInstruction(std::unique_ptr<Instruction>(inst));
1649 return inst->getResultId();
1652 // Accept all parameters needed to create a texture instruction.
1653 // Create the correct instruction based on the inputs, and make the call.
1654 Id Builder::createTextureCall(Decoration precision, Id resultType, bool sparse, bool fetch, bool proj, bool gather,
1655 bool noImplicitLod, const TextureParameters& parameters)
1657 static const int maxTextureArgs = 10;
1658 Id texArgs[maxTextureArgs] = {};
1661 // Set up the fixed arguments
1664 bool explicitLod = false;
1665 texArgs[numArgs++] = parameters.sampler;
1666 texArgs[numArgs++] = parameters.coords;
1667 if (parameters.Dref != NoResult)
1668 texArgs[numArgs++] = parameters.Dref;
1669 if (parameters.component != NoResult)
1670 texArgs[numArgs++] = parameters.component;
1672 #ifdef NV_EXTENSIONS
1673 if (parameters.granularity != NoResult)
1674 texArgs[numArgs++] = parameters.granularity;
1675 if (parameters.coarse != NoResult)
1676 texArgs[numArgs++] = parameters.coarse;
1680 // Set up the optional arguments
1682 int optArgNum = numArgs; // track which operand, if it exists, is the mask of optional arguments
1683 ++numArgs; // speculatively make room for the mask operand
1684 ImageOperandsMask mask = ImageOperandsMaskNone; // the mask operand
1685 if (parameters.bias) {
1686 mask = (ImageOperandsMask)(mask | ImageOperandsBiasMask);
1687 texArgs[numArgs++] = parameters.bias;
1689 if (parameters.lod) {
1690 mask = (ImageOperandsMask)(mask | ImageOperandsLodMask);
1691 texArgs[numArgs++] = parameters.lod;
1693 } else if (parameters.gradX) {
1694 mask = (ImageOperandsMask)(mask | ImageOperandsGradMask);
1695 texArgs[numArgs++] = parameters.gradX;
1696 texArgs[numArgs++] = parameters.gradY;
1698 } else if (noImplicitLod && ! fetch && ! gather) {
1699 // have to explicitly use lod of 0 if not allowed to have them be implicit, and
1700 // we would otherwise be about to issue an implicit instruction
1701 mask = (ImageOperandsMask)(mask | ImageOperandsLodMask);
1702 texArgs[numArgs++] = makeFloatConstant(0.0);
1705 if (parameters.offset) {
1706 if (isConstant(parameters.offset))
1707 mask = (ImageOperandsMask)(mask | ImageOperandsConstOffsetMask);
1709 addCapability(CapabilityImageGatherExtended);
1710 mask = (ImageOperandsMask)(mask | ImageOperandsOffsetMask);
1712 texArgs[numArgs++] = parameters.offset;
1714 if (parameters.offsets) {
1715 addCapability(CapabilityImageGatherExtended);
1716 mask = (ImageOperandsMask)(mask | ImageOperandsConstOffsetsMask);
1717 texArgs[numArgs++] = parameters.offsets;
1719 if (parameters.sample) {
1720 mask = (ImageOperandsMask)(mask | ImageOperandsSampleMask);
1721 texArgs[numArgs++] = parameters.sample;
1723 if (parameters.lodClamp) {
1724 // capability if this bit is used
1725 addCapability(CapabilityMinLod);
1727 mask = (ImageOperandsMask)(mask | ImageOperandsMinLodMask);
1728 texArgs[numArgs++] = parameters.lodClamp;
1730 if (parameters.nonprivate) {
1731 mask = mask | ImageOperandsNonPrivateTexelKHRMask;
1733 if (parameters.volatil) {
1734 mask = mask | ImageOperandsVolatileTexelKHRMask;
1736 if (mask == ImageOperandsMaskNone)
1737 --numArgs; // undo speculative reservation for the mask argument
1739 texArgs[optArgNum] = mask;
1742 // Set up the instruction
1744 Op opCode = OpNop; // All paths below need to set this
1747 opCode = OpImageSparseFetch;
1749 opCode = OpImageFetch;
1750 #ifdef NV_EXTENSIONS
1751 } else if (parameters.granularity && parameters.coarse) {
1752 opCode = OpImageSampleFootprintNV;
1754 } else if (gather) {
1755 if (parameters.Dref)
1757 opCode = OpImageSparseDrefGather;
1759 opCode = OpImageDrefGather;
1762 opCode = OpImageSparseGather;
1764 opCode = OpImageGather;
1765 } else if (explicitLod) {
1766 if (parameters.Dref) {
1769 opCode = OpImageSparseSampleProjDrefExplicitLod;
1771 opCode = OpImageSampleProjDrefExplicitLod;
1774 opCode = OpImageSparseSampleDrefExplicitLod;
1776 opCode = OpImageSampleDrefExplicitLod;
1780 opCode = OpImageSparseSampleProjExplicitLod;
1782 opCode = OpImageSampleProjExplicitLod;
1785 opCode = OpImageSparseSampleExplicitLod;
1787 opCode = OpImageSampleExplicitLod;
1790 if (parameters.Dref) {
1793 opCode = OpImageSparseSampleProjDrefImplicitLod;
1795 opCode = OpImageSampleProjDrefImplicitLod;
1798 opCode = OpImageSparseSampleDrefImplicitLod;
1800 opCode = OpImageSampleDrefImplicitLod;
1804 opCode = OpImageSparseSampleProjImplicitLod;
1806 opCode = OpImageSampleProjImplicitLod;
1809 opCode = OpImageSparseSampleImplicitLod;
1811 opCode = OpImageSampleImplicitLod;
1815 // See if the result type is expecting a smeared result.
1816 // This happens when a legacy shadow*() call is made, which
1817 // gets a vec4 back instead of a float.
1818 Id smearedType = resultType;
1819 if (! isScalarType(resultType)) {
1821 case OpImageSampleDrefImplicitLod:
1822 case OpImageSampleDrefExplicitLod:
1823 case OpImageSampleProjDrefImplicitLod:
1824 case OpImageSampleProjDrefExplicitLod:
1825 resultType = getScalarTypeId(resultType);
1836 typeId0 = resultType;
1837 typeId1 = getDerefTypeId(parameters.texelOut);
1838 resultType = makeStructResultType(typeId0, typeId1);
1841 // Build the SPIR-V instruction
1842 Instruction* textureInst = new Instruction(getUniqueId(), resultType, opCode);
1843 for (int op = 0; op < optArgNum; ++op)
1844 textureInst->addIdOperand(texArgs[op]);
1845 if (optArgNum < numArgs)
1846 textureInst->addImmediateOperand(texArgs[optArgNum]);
1847 for (int op = optArgNum + 1; op < numArgs; ++op)
1848 textureInst->addIdOperand(texArgs[op]);
1849 setPrecision(textureInst->getResultId(), precision);
1850 buildPoint->addInstruction(std::unique_ptr<Instruction>(textureInst));
1852 Id resultId = textureInst->getResultId();
1856 addCapability(CapabilitySparseResidency);
1858 // Decode the return type that was a special structure
1859 createStore(createCompositeExtract(resultId, typeId1, 1), parameters.texelOut);
1860 resultId = createCompositeExtract(resultId, typeId0, 0);
1861 setPrecision(resultId, precision);
1863 // When a smear is needed, do it, as per what was computed
1864 // above when resultType was changed to a scalar type.
1865 if (resultType != smearedType)
1866 resultId = smearScalar(precision, resultId, smearedType);
1872 // Comments in header
1873 Id Builder::createTextureQueryCall(Op opCode, const TextureParameters& parameters, bool isUnsignedResult)
1875 // Figure out the result type
1878 case OpImageQuerySize:
1879 case OpImageQuerySizeLod:
1881 int numComponents = 0;
1882 switch (getTypeDimensionality(getImageType(parameters.sampler))) {
1890 case DimSubpassData:
1901 if (isArrayedImageType(getImageType(parameters.sampler)))
1904 Id intType = isUnsignedResult ? makeUintType(32) : makeIntType(32);
1905 if (numComponents == 1)
1906 resultType = intType;
1908 resultType = makeVectorType(intType, numComponents);
1912 case OpImageQueryLod:
1913 #ifdef AMD_EXTENSIONS
1914 resultType = makeVectorType(getScalarTypeId(getTypeId(parameters.coords)), 2);
1916 resultType = makeVectorType(makeFloatType(32), 2);
1919 case OpImageQueryLevels:
1920 case OpImageQuerySamples:
1921 resultType = isUnsignedResult ? makeUintType(32) : makeIntType(32);
1928 Instruction* query = new Instruction(getUniqueId(), resultType, opCode);
1929 query->addIdOperand(parameters.sampler);
1930 if (parameters.coords)
1931 query->addIdOperand(parameters.coords);
1933 query->addIdOperand(parameters.lod);
1934 buildPoint->addInstruction(std::unique_ptr<Instruction>(query));
1936 return query->getResultId();
1939 // External comments in header.
1940 // Operates recursively to visit the composite's hierarchy.
1941 Id Builder::createCompositeCompare(Decoration precision, Id value1, Id value2, bool equal)
1943 Id boolType = makeBoolType();
1944 Id valueType = getTypeId(value1);
1946 Id resultId = NoResult;
1948 int numConstituents = getNumTypeConstituents(valueType);
1950 // Scalars and Vectors
1952 if (isScalarType(valueType) || isVectorType(valueType)) {
1953 assert(valueType == getTypeId(value2));
1954 // These just need a single comparison, just have
1955 // to figure out what it is.
1957 switch (getMostBasicTypeClass(valueType)) {
1959 op = equal ? OpFOrdEqual : OpFOrdNotEqual;
1963 op = equal ? OpIEqual : OpINotEqual;
1966 op = equal ? OpLogicalEqual : OpLogicalNotEqual;
1967 precision = NoPrecision;
1971 if (isScalarType(valueType)) {
1973 resultId = createBinOp(op, boolType, value1, value2);
1976 resultId = createBinOp(op, makeVectorType(boolType, numConstituents), value1, value2);
1977 setPrecision(resultId, precision);
1978 // reduce vector compares...
1979 resultId = createUnaryOp(equal ? OpAll : OpAny, boolType, resultId);
1982 return setPrecision(resultId, precision);
1985 // Only structs, arrays, and matrices should be left.
1986 // They share in common the reduction operation across their constituents.
1987 assert(isAggregateType(valueType) || isMatrixType(valueType));
1989 // Compare each pair of constituents
1990 for (int constituent = 0; constituent < numConstituents; ++constituent) {
1991 std::vector<unsigned> indexes(1, constituent);
1992 Id constituentType1 = getContainedTypeId(getTypeId(value1), constituent);
1993 Id constituentType2 = getContainedTypeId(getTypeId(value2), constituent);
1994 Id constituent1 = createCompositeExtract(value1, constituentType1, indexes);
1995 Id constituent2 = createCompositeExtract(value2, constituentType2, indexes);
1997 Id subResultId = createCompositeCompare(precision, constituent1, constituent2, equal);
1999 if (constituent == 0)
2000 resultId = subResultId;
2002 resultId = setPrecision(createBinOp(equal ? OpLogicalAnd : OpLogicalOr, boolType, resultId, subResultId), precision);
2008 // OpCompositeConstruct
2009 Id Builder::createCompositeConstruct(Id typeId, const std::vector<Id>& constituents)
2011 assert(isAggregateType(typeId) || (getNumTypeConstituents(typeId) > 1 && getNumTypeConstituents(typeId) == (int)constituents.size()));
2013 if (generatingOpCodeForSpecConst) {
2014 // Sometime, even in spec-constant-op mode, the constant composite to be
2015 // constructed may not be a specialization constant.
2017 // const mat2 m2 = mat2(a_spec_const, a_front_end_const, another_front_end_const, third_front_end_const);
2018 // The first column vector should be a spec constant one, as a_spec_const is a spec constant.
2019 // The second column vector should NOT be spec constant, as it does not contain any spec constants.
2020 // To handle such cases, we check the constituents of the constant vector to determine whether this
2021 // vector should be created as a spec constant.
2022 return makeCompositeConstant(typeId, constituents,
2023 std::any_of(constituents.begin(), constituents.end(),
2024 [&](spv::Id id) { return isSpecConstant(id); }));
2027 Instruction* op = new Instruction(getUniqueId(), typeId, OpCompositeConstruct);
2028 for (int c = 0; c < (int)constituents.size(); ++c)
2029 op->addIdOperand(constituents[c]);
2030 buildPoint->addInstruction(std::unique_ptr<Instruction>(op));
2032 return op->getResultId();
2035 // Vector or scalar constructor
2036 Id Builder::createConstructor(Decoration precision, const std::vector<Id>& sources, Id resultTypeId)
2038 Id result = NoResult;
2039 unsigned int numTargetComponents = getNumTypeComponents(resultTypeId);
2040 unsigned int targetComponent = 0;
2042 // Special case: when calling a vector constructor with a single scalar
2043 // argument, smear the scalar
2044 if (sources.size() == 1 && isScalar(sources[0]) && numTargetComponents > 1)
2045 return smearScalar(precision, sources[0], resultTypeId);
2047 // accumulate the arguments for OpCompositeConstruct
2048 std::vector<Id> constituents;
2049 Id scalarTypeId = getScalarTypeId(resultTypeId);
2051 // lambda to store the result of visiting an argument component
2052 const auto latchResult = [&](Id comp) {
2053 if (numTargetComponents > 1)
2054 constituents.push_back(comp);
2060 // lambda to visit a vector argument's components
2061 const auto accumulateVectorConstituents = [&](Id sourceArg) {
2062 unsigned int sourceSize = getNumComponents(sourceArg);
2063 unsigned int sourcesToUse = sourceSize;
2064 if (sourcesToUse + targetComponent > numTargetComponents)
2065 sourcesToUse = numTargetComponents - targetComponent;
2067 for (unsigned int s = 0; s < sourcesToUse; ++s) {
2068 std::vector<unsigned> swiz;
2070 latchResult(createRvalueSwizzle(precision, scalarTypeId, sourceArg, swiz));
2074 // lambda to visit a matrix argument's components
2075 const auto accumulateMatrixConstituents = [&](Id sourceArg) {
2076 unsigned int sourceSize = getNumColumns(sourceArg) * getNumRows(sourceArg);
2077 unsigned int sourcesToUse = sourceSize;
2078 if (sourcesToUse + targetComponent > numTargetComponents)
2079 sourcesToUse = numTargetComponents - targetComponent;
2083 for (unsigned int s = 0; s < sourcesToUse; ++s) {
2084 if (row >= getNumRows(sourceArg)) {
2088 std::vector<Id> indexes;
2089 indexes.push_back(col);
2090 indexes.push_back(row);
2091 latchResult(createCompositeExtract(sourceArg, scalarTypeId, indexes));
2096 // Go through the source arguments, each one could have either
2097 // a single or multiple components to contribute.
2098 for (unsigned int i = 0; i < sources.size(); ++i) {
2099 if (isScalar(sources[i]))
2100 latchResult(sources[i]);
2101 else if (isVector(sources[i]))
2102 accumulateVectorConstituents(sources[i]);
2103 else if (isMatrix(sources[i]))
2104 accumulateMatrixConstituents(sources[i]);
2108 if (targetComponent >= numTargetComponents)
2112 // If the result is a vector, make it from the gathered constituents.
2113 if (constituents.size() > 0)
2114 result = createCompositeConstruct(resultTypeId, constituents);
2116 return setPrecision(result, precision);
2119 // Comments in header
2120 Id Builder::createMatrixConstructor(Decoration precision, const std::vector<Id>& sources, Id resultTypeId)
2122 Id componentTypeId = getScalarTypeId(resultTypeId);
2123 int numCols = getTypeNumColumns(resultTypeId);
2124 int numRows = getTypeNumRows(resultTypeId);
2126 Instruction* instr = module.getInstruction(componentTypeId);
2127 unsigned bitCount = instr->getImmediateOperand(0);
2129 // Optimize matrix constructed from a bigger matrix
2130 if (isMatrix(sources[0]) && getNumColumns(sources[0]) >= numCols && getNumRows(sources[0]) >= numRows) {
2131 // To truncate the matrix to a smaller number of rows/columns, we need to:
2132 // 1. For each column, extract the column and truncate it to the required size using shuffle
2133 // 2. Assemble the resulting matrix from all columns
2134 Id matrix = sources[0];
2135 Id columnTypeId = getContainedTypeId(resultTypeId);
2136 Id sourceColumnTypeId = getContainedTypeId(getTypeId(matrix));
2138 std::vector<unsigned> channels;
2139 for (int row = 0; row < numRows; ++row)
2140 channels.push_back(row);
2142 std::vector<Id> matrixColumns;
2143 for (int col = 0; col < numCols; ++col) {
2144 std::vector<unsigned> indexes;
2145 indexes.push_back(col);
2146 Id colv = createCompositeExtract(matrix, sourceColumnTypeId, indexes);
2147 setPrecision(colv, precision);
2149 if (numRows != getNumRows(matrix)) {
2150 matrixColumns.push_back(createRvalueSwizzle(precision, columnTypeId, colv, channels));
2152 matrixColumns.push_back(colv);
2156 return setPrecision(createCompositeConstruct(resultTypeId, matrixColumns), precision);
2159 // Otherwise, will use a two step process
2160 // 1. make a compile-time 2D array of values
2161 // 2. construct a matrix from that array
2165 // initialize the array to the identity matrix
2166 Id ids[maxMatrixSize][maxMatrixSize];
2167 Id one = (bitCount == 64 ? makeDoubleConstant(1.0) : makeFloatConstant(1.0));
2168 Id zero = (bitCount == 64 ? makeDoubleConstant(0.0) : makeFloatConstant(0.0));
2169 for (int col = 0; col < 4; ++col) {
2170 for (int row = 0; row < 4; ++row) {
2172 ids[col][row] = one;
2174 ids[col][row] = zero;
2178 // modify components as dictated by the arguments
2179 if (sources.size() == 1 && isScalar(sources[0])) {
2180 // a single scalar; resets the diagonals
2181 for (int col = 0; col < 4; ++col)
2182 ids[col][col] = sources[0];
2183 } else if (isMatrix(sources[0])) {
2184 // constructing from another matrix; copy over the parts that exist in both the argument and constructee
2185 Id matrix = sources[0];
2186 int minCols = std::min(numCols, getNumColumns(matrix));
2187 int minRows = std::min(numRows, getNumRows(matrix));
2188 for (int col = 0; col < minCols; ++col) {
2189 std::vector<unsigned> indexes;
2190 indexes.push_back(col);
2191 for (int row = 0; row < minRows; ++row) {
2192 indexes.push_back(row);
2193 ids[col][row] = createCompositeExtract(matrix, componentTypeId, indexes);
2195 setPrecision(ids[col][row], precision);
2199 // fill in the matrix in column-major order with whatever argument components are available
2203 for (int arg = 0; arg < (int)sources.size(); ++arg) {
2204 Id argComp = sources[arg];
2205 for (int comp = 0; comp < getNumComponents(sources[arg]); ++comp) {
2206 if (getNumComponents(sources[arg]) > 1) {
2207 argComp = createCompositeExtract(sources[arg], componentTypeId, comp);
2208 setPrecision(argComp, precision);
2210 ids[col][row++] = argComp;
2211 if (row == numRows) {
2219 // Step 2: Construct a matrix from that array.
2220 // First make the column vectors, then make the matrix.
2222 // make the column vectors
2223 Id columnTypeId = getContainedTypeId(resultTypeId);
2224 std::vector<Id> matrixColumns;
2225 for (int col = 0; col < numCols; ++col) {
2226 std::vector<Id> vectorComponents;
2227 for (int row = 0; row < numRows; ++row)
2228 vectorComponents.push_back(ids[col][row]);
2229 Id column = createCompositeConstruct(columnTypeId, vectorComponents);
2230 setPrecision(column, precision);
2231 matrixColumns.push_back(column);
2235 return setPrecision(createCompositeConstruct(resultTypeId, matrixColumns), precision);
2238 // Comments in header
2239 Builder::If::If(Id cond, unsigned int ctrl, Builder& gb) :
2245 function = &builder.getBuildPoint()->getParent();
2247 // make the blocks, but only put the then-block into the function,
2248 // the else-block and merge-block will be added later, in order, after
2249 // earlier code is emitted
2250 thenBlock = new Block(builder.getUniqueId(), *function);
2251 mergeBlock = new Block(builder.getUniqueId(), *function);
2253 // Save the current block, so that we can add in the flow control split when
2254 // makeEndIf is called.
2255 headerBlock = builder.getBuildPoint();
2257 function->addBlock(thenBlock);
2258 builder.setBuildPoint(thenBlock);
2261 // Comments in header
2262 void Builder::If::makeBeginElse()
2264 // Close out the "then" by having it jump to the mergeBlock
2265 builder.createBranch(mergeBlock);
2267 // Make the first else block and add it to the function
2268 elseBlock = new Block(builder.getUniqueId(), *function);
2269 function->addBlock(elseBlock);
2271 // Start building the else block
2272 builder.setBuildPoint(elseBlock);
2275 // Comments in header
2276 void Builder::If::makeEndIf()
2278 // jump to the merge block
2279 builder.createBranch(mergeBlock);
2281 // Go back to the headerBlock and make the flow control split
2282 builder.setBuildPoint(headerBlock);
2283 builder.createSelectionMerge(mergeBlock, control);
2285 builder.createConditionalBranch(condition, thenBlock, elseBlock);
2287 builder.createConditionalBranch(condition, thenBlock, mergeBlock);
2289 // add the merge block to the function
2290 function->addBlock(mergeBlock);
2291 builder.setBuildPoint(mergeBlock);
2294 // Comments in header
2295 void Builder::makeSwitch(Id selector, unsigned int control, int numSegments, const std::vector<int>& caseValues,
2296 const std::vector<int>& valueIndexToSegment, int defaultSegment,
2297 std::vector<Block*>& segmentBlocks)
2299 Function& function = buildPoint->getParent();
2301 // make all the blocks
2302 for (int s = 0; s < numSegments; ++s)
2303 segmentBlocks.push_back(new Block(getUniqueId(), function));
2305 Block* mergeBlock = new Block(getUniqueId(), function);
2307 // make and insert the switch's selection-merge instruction
2308 createSelectionMerge(mergeBlock, control);
2310 // make the switch instruction
2311 Instruction* switchInst = new Instruction(NoResult, NoType, OpSwitch);
2312 switchInst->addIdOperand(selector);
2313 auto defaultOrMerge = (defaultSegment >= 0) ? segmentBlocks[defaultSegment] : mergeBlock;
2314 switchInst->addIdOperand(defaultOrMerge->getId());
2315 defaultOrMerge->addPredecessor(buildPoint);
2316 for (int i = 0; i < (int)caseValues.size(); ++i) {
2317 switchInst->addImmediateOperand(caseValues[i]);
2318 switchInst->addIdOperand(segmentBlocks[valueIndexToSegment[i]]->getId());
2319 segmentBlocks[valueIndexToSegment[i]]->addPredecessor(buildPoint);
2321 buildPoint->addInstruction(std::unique_ptr<Instruction>(switchInst));
2323 // push the merge block
2324 switchMerges.push(mergeBlock);
2327 // Comments in header
2328 void Builder::addSwitchBreak()
2330 // branch to the top of the merge block stack
2331 createBranch(switchMerges.top());
2332 createAndSetNoPredecessorBlock("post-switch-break");
2335 // Comments in header
2336 void Builder::nextSwitchSegment(std::vector<Block*>& segmentBlock, int nextSegment)
2338 int lastSegment = nextSegment - 1;
2339 if (lastSegment >= 0) {
2340 // Close out previous segment by jumping, if necessary, to next segment
2341 if (! buildPoint->isTerminated())
2342 createBranch(segmentBlock[nextSegment]);
2344 Block* block = segmentBlock[nextSegment];
2345 block->getParent().addBlock(block);
2346 setBuildPoint(block);
2349 // Comments in header
2350 void Builder::endSwitch(std::vector<Block*>& /*segmentBlock*/)
2352 // Close out previous segment by jumping, if necessary, to next segment
2353 if (! buildPoint->isTerminated())
2356 switchMerges.top()->getParent().addBlock(switchMerges.top());
2357 setBuildPoint(switchMerges.top());
2362 Block& Builder::makeNewBlock()
2364 Function& function = buildPoint->getParent();
2365 auto block = new Block(getUniqueId(), function);
2366 function.addBlock(block);
2370 Builder::LoopBlocks& Builder::makeNewLoop()
2372 // This verbosity is needed to simultaneously get the same behavior
2373 // everywhere (id's in the same order), have a syntax that works
2374 // across lots of versions of C++, have no warnings from pedantic
2375 // compilation modes, and leave the rest of the code alone.
2376 Block& head = makeNewBlock();
2377 Block& body = makeNewBlock();
2378 Block& merge = makeNewBlock();
2379 Block& continue_target = makeNewBlock();
2380 LoopBlocks blocks(head, body, merge, continue_target);
2385 void Builder::createLoopContinue()
2387 createBranch(&loops.top().continue_target);
2388 // Set up a block for dead code.
2389 createAndSetNoPredecessorBlock("post-loop-continue");
2392 void Builder::createLoopExit()
2394 createBranch(&loops.top().merge);
2395 // Set up a block for dead code.
2396 createAndSetNoPredecessorBlock("post-loop-break");
2399 void Builder::closeLoop()
2404 void Builder::clearAccessChain()
2406 accessChain.base = NoResult;
2407 accessChain.indexChain.clear();
2408 accessChain.instr = NoResult;
2409 accessChain.swizzle.clear();
2410 accessChain.component = NoResult;
2411 accessChain.preSwizzleBaseType = NoType;
2412 accessChain.isRValue = false;
2413 accessChain.coherentFlags.clear();
2416 // Comments in header
2417 void Builder::accessChainPushSwizzle(std::vector<unsigned>& swizzle, Id preSwizzleBaseType)
2419 // swizzles can be stacked in GLSL, but simplified to a single
2420 // one here; the base type doesn't change
2421 if (accessChain.preSwizzleBaseType == NoType)
2422 accessChain.preSwizzleBaseType = preSwizzleBaseType;
2424 // if needed, propagate the swizzle for the current access chain
2425 if (accessChain.swizzle.size() > 0) {
2426 std::vector<unsigned> oldSwizzle = accessChain.swizzle;
2427 accessChain.swizzle.resize(0);
2428 for (unsigned int i = 0; i < swizzle.size(); ++i) {
2429 assert(swizzle[i] < oldSwizzle.size());
2430 accessChain.swizzle.push_back(oldSwizzle[swizzle[i]]);
2433 accessChain.swizzle = swizzle;
2435 // determine if we need to track this swizzle anymore
2436 simplifyAccessChainSwizzle();
2439 // Comments in header
2440 void Builder::accessChainStore(Id rvalue, spv::MemoryAccessMask memoryAccess, spv::Scope scope)
2442 assert(accessChain.isRValue == false);
2444 transferAccessChainSwizzle(true);
2445 Id base = collapseAccessChain();
2448 // dynamic component should be gone
2449 assert(accessChain.component == NoResult);
2451 // If swizzle still exists, it is out-of-order or not full, we must load the target vector,
2452 // extract and insert elements to perform writeMask and/or swizzle.
2453 if (accessChain.swizzle.size() > 0) {
2454 Id tempBaseId = createLoad(base);
2455 source = createLvalueSwizzle(getTypeId(tempBaseId), tempBaseId, source, accessChain.swizzle);
2458 createStore(source, base, memoryAccess, scope);
2461 // Comments in header
2462 Id Builder::accessChainLoad(Decoration precision, Decoration nonUniform, Id resultType, spv::MemoryAccessMask memoryAccess, spv::Scope scope)
2466 if (accessChain.isRValue) {
2467 // transfer access chain, but try to stay in registers
2468 transferAccessChainSwizzle(false);
2469 if (accessChain.indexChain.size() > 0) {
2470 Id swizzleBase = accessChain.preSwizzleBaseType != NoType ? accessChain.preSwizzleBaseType : resultType;
2472 // if all the accesses are constants, we can use OpCompositeExtract
2473 std::vector<unsigned> indexes;
2474 bool constant = true;
2475 for (int i = 0; i < (int)accessChain.indexChain.size(); ++i) {
2476 if (isConstantScalar(accessChain.indexChain[i]))
2477 indexes.push_back(getConstantScalar(accessChain.indexChain[i]));
2485 id = createCompositeExtract(accessChain.base, swizzleBase, indexes);
2487 // make a new function variable for this r-value
2488 Id lValue = createVariable(StorageClassFunction, getTypeId(accessChain.base), "indexable");
2491 createStore(accessChain.base, lValue);
2493 // move base to the new variable
2494 accessChain.base = lValue;
2495 accessChain.isRValue = false;
2497 // load through the access chain
2498 id = createLoad(collapseAccessChain());
2500 setPrecision(id, precision);
2502 id = accessChain.base; // no precision, it was set when this was defined
2504 transferAccessChainSwizzle(true);
2505 // load through the access chain
2506 id = createLoad(collapseAccessChain(), memoryAccess, scope);
2507 setPrecision(id, precision);
2508 addDecoration(id, nonUniform);
2511 // Done, unless there are swizzles to do
2512 if (accessChain.swizzle.size() == 0 && accessChain.component == NoResult)
2515 // Do remaining swizzling
2517 // Do the basic swizzle
2518 if (accessChain.swizzle.size() > 0) {
2519 Id swizzledType = getScalarTypeId(getTypeId(id));
2520 if (accessChain.swizzle.size() > 1)
2521 swizzledType = makeVectorType(swizzledType, (int)accessChain.swizzle.size());
2522 id = createRvalueSwizzle(precision, swizzledType, id, accessChain.swizzle);
2525 // Do the dynamic component
2526 if (accessChain.component != NoResult)
2527 id = setPrecision(createVectorExtractDynamic(id, resultType, accessChain.component), precision);
2529 addDecoration(id, nonUniform);
2533 Id Builder::accessChainGetLValue()
2535 assert(accessChain.isRValue == false);
2537 transferAccessChainSwizzle(true);
2538 Id lvalue = collapseAccessChain();
2540 // If swizzle exists, it is out-of-order or not full, we must load the target vector,
2541 // extract and insert elements to perform writeMask and/or swizzle. This does not
2542 // go with getting a direct l-value pointer.
2543 assert(accessChain.swizzle.size() == 0);
2544 assert(accessChain.component == NoResult);
2549 // comment in header
2550 Id Builder::accessChainGetInferredType()
2552 // anything to operate on?
2553 if (accessChain.base == NoResult)
2555 Id type = getTypeId(accessChain.base);
2557 // do initial dereference
2558 if (! accessChain.isRValue)
2559 type = getContainedTypeId(type);
2561 // dereference each index
2562 for (auto it = accessChain.indexChain.cbegin(); it != accessChain.indexChain.cend(); ++it) {
2563 if (isStructType(type))
2564 type = getContainedTypeId(type, getConstantScalar(*it));
2566 type = getContainedTypeId(type);
2569 // dereference swizzle
2570 if (accessChain.swizzle.size() == 1)
2571 type = getContainedTypeId(type);
2572 else if (accessChain.swizzle.size() > 1)
2573 type = makeVectorType(getContainedTypeId(type), (int)accessChain.swizzle.size());
2575 // dereference component selection
2576 if (accessChain.component)
2577 type = getContainedTypeId(type);
2582 void Builder::dump(std::vector<unsigned int>& out) const
2584 // Header, before first instructions:
2585 out.push_back(MagicNumber);
2586 out.push_back(spvVersion);
2587 out.push_back(builderNumber);
2588 out.push_back(uniqueId + 1);
2592 for (auto it = capabilities.cbegin(); it != capabilities.cend(); ++it) {
2593 Instruction capInst(0, 0, OpCapability);
2594 capInst.addImmediateOperand(*it);
2598 for (auto it = extensions.cbegin(); it != extensions.cend(); ++it) {
2599 Instruction extInst(0, 0, OpExtension);
2600 extInst.addStringOperand(it->c_str());
2604 dumpInstructions(out, imports);
2605 Instruction memInst(0, 0, OpMemoryModel);
2606 memInst.addImmediateOperand(addressModel);
2607 memInst.addImmediateOperand(memoryModel);
2610 // Instructions saved up while building:
2611 dumpInstructions(out, entryPoints);
2612 dumpInstructions(out, executionModes);
2614 // Debug instructions
2615 dumpInstructions(out, strings);
2616 dumpSourceInstructions(out);
2617 for (int e = 0; e < (int)sourceExtensions.size(); ++e) {
2618 Instruction sourceExtInst(0, 0, OpSourceExtension);
2619 sourceExtInst.addStringOperand(sourceExtensions[e]);
2620 sourceExtInst.dump(out);
2622 dumpInstructions(out, names);
2623 dumpModuleProcesses(out);
2625 // Annotation instructions
2626 dumpInstructions(out, decorations);
2628 dumpInstructions(out, constantsTypesGlobals);
2629 dumpInstructions(out, externals);
2636 // Protected methods.
2639 // Turn the described access chain in 'accessChain' into an instruction(s)
2640 // computing its address. This *cannot* include complex swizzles, which must
2641 // be handled after this is called.
2643 // Can generate code.
2644 Id Builder::collapseAccessChain()
2646 assert(accessChain.isRValue == false);
2648 // did we already emit an access chain for this?
2649 if (accessChain.instr != NoResult)
2650 return accessChain.instr;
2652 // If we have a dynamic component, we can still transfer
2653 // that into a final operand to the access chain. We need to remap the
2654 // dynamic component through the swizzle to get a new dynamic component to
2657 // This was not done in transferAccessChainSwizzle() because it might
2659 remapDynamicSwizzle();
2660 if (accessChain.component != NoResult) {
2661 // transfer the dynamic component to the access chain
2662 accessChain.indexChain.push_back(accessChain.component);
2663 accessChain.component = NoResult;
2666 // note that non-trivial swizzling is left pending
2668 // do we have an access chain?
2669 if (accessChain.indexChain.size() == 0)
2670 return accessChain.base;
2672 // emit the access chain
2673 StorageClass storageClass = (StorageClass)module.getStorageClass(getTypeId(accessChain.base));
2674 accessChain.instr = createAccessChain(storageClass, accessChain.base, accessChain.indexChain);
2676 return accessChain.instr;
2679 // For a dynamic component selection of a swizzle.
2681 // Turn the swizzle and dynamic component into just a dynamic component.
2684 void Builder::remapDynamicSwizzle()
2686 // do we have a swizzle to remap a dynamic component through?
2687 if (accessChain.component != NoResult && accessChain.swizzle.size() > 1) {
2688 // build a vector of the swizzle for the component to map into
2689 std::vector<Id> components;
2690 for (int c = 0; c < (int)accessChain.swizzle.size(); ++c)
2691 components.push_back(makeUintConstant(accessChain.swizzle[c]));
2692 Id mapType = makeVectorType(makeUintType(32), (int)accessChain.swizzle.size());
2693 Id map = makeCompositeConstant(mapType, components);
2696 accessChain.component = createVectorExtractDynamic(map, makeUintType(32), accessChain.component);
2697 accessChain.swizzle.clear();
2701 // clear out swizzle if it is redundant, that is reselecting the same components
2702 // that would be present without the swizzle.
2703 void Builder::simplifyAccessChainSwizzle()
2705 // If the swizzle has fewer components than the vector, it is subsetting, and must stay
2706 // to preserve that fact.
2707 if (getNumTypeComponents(accessChain.preSwizzleBaseType) > (int)accessChain.swizzle.size())
2710 // if components are out of order, it is a swizzle
2711 for (unsigned int i = 0; i < accessChain.swizzle.size(); ++i) {
2712 if (i != accessChain.swizzle[i])
2716 // otherwise, there is no need to track this swizzle
2717 accessChain.swizzle.clear();
2718 if (accessChain.component == NoResult)
2719 accessChain.preSwizzleBaseType = NoType;
2722 // To the extent any swizzling can become part of the chain
2723 // of accesses instead of a post operation, make it so.
2724 // If 'dynamic' is true, include transferring the dynamic component,
2725 // otherwise, leave it pending.
2727 // Does not generate code. just updates the access chain.
2728 void Builder::transferAccessChainSwizzle(bool dynamic)
2731 if (accessChain.swizzle.size() == 0 && accessChain.component == NoResult)
2735 // (this requires either a swizzle, or generating code for a dynamic component)
2736 if (accessChain.swizzle.size() > 1)
2739 // single component, either in the swizzle and/or dynamic component
2740 if (accessChain.swizzle.size() == 1) {
2741 assert(accessChain.component == NoResult);
2742 // handle static component selection
2743 accessChain.indexChain.push_back(makeUintConstant(accessChain.swizzle.front()));
2744 accessChain.swizzle.clear();
2745 accessChain.preSwizzleBaseType = NoType;
2746 } else if (dynamic && accessChain.component != NoResult) {
2747 assert(accessChain.swizzle.size() == 0);
2748 // handle dynamic component
2749 accessChain.indexChain.push_back(accessChain.component);
2750 accessChain.preSwizzleBaseType = NoType;
2751 accessChain.component = NoResult;
2755 // Utility method for creating a new block and setting the insert point to
2756 // be in it. This is useful for flow-control operations that need a "dummy"
2757 // block proceeding them (e.g. instructions after a discard, etc).
2758 void Builder::createAndSetNoPredecessorBlock(const char* /*name*/)
2760 Block* block = new Block(getUniqueId(), buildPoint->getParent());
2761 block->setUnreachable();
2762 buildPoint->getParent().addBlock(block);
2763 setBuildPoint(block);
2766 // addName(block->getId(), name);
2769 // Comments in header
2770 void Builder::createBranch(Block* block)
2772 Instruction* branch = new Instruction(OpBranch);
2773 branch->addIdOperand(block->getId());
2774 buildPoint->addInstruction(std::unique_ptr<Instruction>(branch));
2775 block->addPredecessor(buildPoint);
2778 void Builder::createSelectionMerge(Block* mergeBlock, unsigned int control)
2780 Instruction* merge = new Instruction(OpSelectionMerge);
2781 merge->addIdOperand(mergeBlock->getId());
2782 merge->addImmediateOperand(control);
2783 buildPoint->addInstruction(std::unique_ptr<Instruction>(merge));
2786 void Builder::createLoopMerge(Block* mergeBlock, Block* continueBlock, unsigned int control,
2787 unsigned int dependencyLength)
2789 Instruction* merge = new Instruction(OpLoopMerge);
2790 merge->addIdOperand(mergeBlock->getId());
2791 merge->addIdOperand(continueBlock->getId());
2792 merge->addImmediateOperand(control);
2793 if ((control & LoopControlDependencyLengthMask) != 0)
2794 merge->addImmediateOperand(dependencyLength);
2795 buildPoint->addInstruction(std::unique_ptr<Instruction>(merge));
2798 void Builder::createConditionalBranch(Id condition, Block* thenBlock, Block* elseBlock)
2800 Instruction* branch = new Instruction(OpBranchConditional);
2801 branch->addIdOperand(condition);
2802 branch->addIdOperand(thenBlock->getId());
2803 branch->addIdOperand(elseBlock->getId());
2804 buildPoint->addInstruction(std::unique_ptr<Instruction>(branch));
2805 thenBlock->addPredecessor(buildPoint);
2806 elseBlock->addPredecessor(buildPoint);
2810 // [OpSourceContinued]
2812 void Builder::dumpSourceInstructions(std::vector<unsigned int>& out) const
2814 const int maxWordCount = 0xFFFF;
2815 const int opSourceWordCount = 4;
2816 const int nonNullBytesPerInstruction = 4 * (maxWordCount - opSourceWordCount) - 1;
2818 if (source != SourceLanguageUnknown) {
2819 // OpSource Language Version File Source
2820 Instruction sourceInst(NoResult, NoType, OpSource);
2821 sourceInst.addImmediateOperand(source);
2822 sourceInst.addImmediateOperand(sourceVersion);
2824 if (sourceFileStringId != NoResult) {
2825 sourceInst.addIdOperand(sourceFileStringId);
2827 if (sourceText.size() > 0) {
2829 std::string subString;
2830 while ((int)sourceText.size() - nextByte > 0) {
2831 subString = sourceText.substr(nextByte, nonNullBytesPerInstruction);
2832 if (nextByte == 0) {
2834 sourceInst.addStringOperand(subString.c_str());
2835 sourceInst.dump(out);
2838 Instruction sourceContinuedInst(OpSourceContinued);
2839 sourceContinuedInst.addStringOperand(subString.c_str());
2840 sourceContinuedInst.dump(out);
2842 nextByte += nonNullBytesPerInstruction;
2845 sourceInst.dump(out);
2847 sourceInst.dump(out);
2851 void Builder::dumpInstructions(std::vector<unsigned int>& out, const std::vector<std::unique_ptr<Instruction> >& instructions) const
2853 for (int i = 0; i < (int)instructions.size(); ++i) {
2854 instructions[i]->dump(out);
2858 void Builder::dumpModuleProcesses(std::vector<unsigned int>& out) const
2860 for (int i = 0; i < (int)moduleProcesses.size(); ++i) {
2861 Instruction moduleProcessed(OpModuleProcessed);
2862 moduleProcessed.addStringOperand(moduleProcesses[i]);
2863 moduleProcessed.dump(out);
2867 }; // end spv namespace