2 //Copyright (C) 2014 LunarG, Inc.
6 //Redistribution and use in source and binary forms, with or without
7 //modification, are permitted provided that the following conditions
10 // Redistributions of source code must retain the above copyright
11 // notice, this list of conditions and the following disclaimer.
13 // Redistributions in binary form must reproduce the above
14 // copyright notice, this list of conditions and the following
15 // disclaimer in the documentation and/or other materials provided
16 // with the distribution.
18 // Neither the name of 3Dlabs Inc. Ltd. nor the names of its
19 // contributors may be used to endorse or promote products derived
20 // from this software without specific prior written permission.
22 //THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
23 //"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
24 //LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
25 //FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
26 //COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
27 //INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
28 //BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
29 //LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
30 //CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 //LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
32 //ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
33 //POSSIBILITY OF SUCH DAMAGE.
36 // Author: John Kessenich, LunarG
40 // Helper for making SPIR-V IR. Generally, this is documented in the header
48 #include <unordered_set>
50 #include "SpvBuilder.h"
58 Builder::Builder(unsigned int magicNumber) :
59 source(SourceLanguageUnknown),
61 addressModel(AddressingModelLogical),
62 memoryModel(MemoryModelGLSL450),
63 builderNumber(magicNumber),
75 Id Builder::import(const char* name)
77 Instruction* import = new Instruction(getUniqueId(), NoType, OpExtInstImport);
78 import->addStringOperand(name);
80 imports.push_back(std::unique_ptr<Instruction>(import));
81 return import->getResultId();
84 // For creating new groupedTypes (will return old type if the requested one was already made).
85 Id Builder::makeVoidType()
88 if (groupedTypes[OpTypeVoid].size() == 0) {
89 type = new Instruction(getUniqueId(), NoType, OpTypeVoid);
90 groupedTypes[OpTypeVoid].push_back(type);
91 constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(type));
92 module.mapInstruction(type);
94 type = groupedTypes[OpTypeVoid].back();
96 return type->getResultId();
99 Id Builder::makeBoolType()
102 if (groupedTypes[OpTypeBool].size() == 0) {
103 type = new Instruction(getUniqueId(), NoType, OpTypeBool);
104 groupedTypes[OpTypeBool].push_back(type);
105 constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(type));
106 module.mapInstruction(type);
108 type = groupedTypes[OpTypeBool].back();
110 return type->getResultId();
113 Id Builder::makeSamplerType()
116 if (groupedTypes[OpTypeSampler].size() == 0) {
117 type = new Instruction(getUniqueId(), NoType, OpTypeSampler);
118 groupedTypes[OpTypeSampler].push_back(type);
119 constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(type));
120 module.mapInstruction(type);
122 type = groupedTypes[OpTypeSampler].back();
124 return type->getResultId();
127 Id Builder::makePointer(StorageClass storageClass, Id pointee)
131 for (int t = 0; t < (int)groupedTypes[OpTypePointer].size(); ++t) {
132 type = groupedTypes[OpTypePointer][t];
133 if (type->getImmediateOperand(0) == (unsigned)storageClass &&
134 type->getIdOperand(1) == pointee)
135 return type->getResultId();
138 // not found, make it
139 type = new Instruction(getUniqueId(), NoType, OpTypePointer);
140 type->addImmediateOperand(storageClass);
141 type->addIdOperand(pointee);
142 groupedTypes[OpTypePointer].push_back(type);
143 constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(type));
144 module.mapInstruction(type);
146 return type->getResultId();
149 Id Builder::makeIntegerType(int width, bool hasSign)
153 for (int t = 0; t < (int)groupedTypes[OpTypeInt].size(); ++t) {
154 type = groupedTypes[OpTypeInt][t];
155 if (type->getImmediateOperand(0) == (unsigned)width &&
156 type->getImmediateOperand(1) == (hasSign ? 1u : 0u))
157 return type->getResultId();
160 // not found, make it
161 type = new Instruction(getUniqueId(), NoType, OpTypeInt);
162 type->addImmediateOperand(width);
163 type->addImmediateOperand(hasSign ? 1 : 0);
164 groupedTypes[OpTypeInt].push_back(type);
165 constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(type));
166 module.mapInstruction(type);
168 return type->getResultId();
171 Id Builder::makeFloatType(int width)
175 for (int t = 0; t < (int)groupedTypes[OpTypeFloat].size(); ++t) {
176 type = groupedTypes[OpTypeFloat][t];
177 if (type->getImmediateOperand(0) == (unsigned)width)
178 return type->getResultId();
181 // not found, make it
182 type = new Instruction(getUniqueId(), NoType, OpTypeFloat);
183 type->addImmediateOperand(width);
184 groupedTypes[OpTypeFloat].push_back(type);
185 constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(type));
186 module.mapInstruction(type);
188 return type->getResultId();
191 // Make a struct without checking for duplication.
192 // See makeStructResultType() for non-decorated structs
193 // needed as the result of some instructions, which does
194 // check for duplicates.
195 Id Builder::makeStructType(std::vector<Id>& members, const char* name)
197 // Don't look for previous one, because in the general case,
198 // structs can be duplicated except for decorations.
200 // not found, make it
201 Instruction* type = new Instruction(getUniqueId(), NoType, OpTypeStruct);
202 for (int op = 0; op < (int)members.size(); ++op)
203 type->addIdOperand(members[op]);
204 groupedTypes[OpTypeStruct].push_back(type);
205 constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(type));
206 module.mapInstruction(type);
207 addName(type->getResultId(), name);
209 return type->getResultId();
212 // Make a struct for the simple results of several instructions,
213 // checking for duplication.
214 Id Builder::makeStructResultType(Id type0, Id type1)
218 for (int t = 0; t < (int)groupedTypes[OpTypeStruct].size(); ++t) {
219 type = groupedTypes[OpTypeStruct][t];
220 if (type->getNumOperands() != 2)
222 if (type->getIdOperand(0) != type0 ||
223 type->getIdOperand(1) != type1)
225 return type->getResultId();
228 // not found, make it
229 std::vector<spv::Id> members;
230 members.push_back(type0);
231 members.push_back(type1);
233 return makeStructType(members, "ResType");
236 Id Builder::makeVectorType(Id component, int size)
240 for (int t = 0; t < (int)groupedTypes[OpTypeVector].size(); ++t) {
241 type = groupedTypes[OpTypeVector][t];
242 if (type->getIdOperand(0) == component &&
243 type->getImmediateOperand(1) == (unsigned)size)
244 return type->getResultId();
247 // not found, make it
248 type = new Instruction(getUniqueId(), NoType, OpTypeVector);
249 type->addIdOperand(component);
250 type->addImmediateOperand(size);
251 groupedTypes[OpTypeVector].push_back(type);
252 constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(type));
253 module.mapInstruction(type);
255 return type->getResultId();
258 Id Builder::makeMatrixType(Id component, int cols, int rows)
260 assert(cols <= maxMatrixSize && rows <= maxMatrixSize);
262 Id column = makeVectorType(component, rows);
266 for (int t = 0; t < (int)groupedTypes[OpTypeMatrix].size(); ++t) {
267 type = groupedTypes[OpTypeMatrix][t];
268 if (type->getIdOperand(0) == column &&
269 type->getImmediateOperand(1) == (unsigned)cols)
270 return type->getResultId();
273 // not found, make it
274 type = new Instruction(getUniqueId(), NoType, OpTypeMatrix);
275 type->addIdOperand(column);
276 type->addImmediateOperand(cols);
277 groupedTypes[OpTypeMatrix].push_back(type);
278 constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(type));
279 module.mapInstruction(type);
281 return type->getResultId();
284 // TODO: performance: track arrays per stride
285 // If a stride is supplied (non-zero) make an array.
286 // If no stride (0), reuse previous array types.
287 Id Builder::makeArrayType(Id element, unsigned size, int stride)
289 // First, we need a constant instruction for the size
290 Id sizeId = makeUintConstant(size);
294 // try to find existing type
295 for (int t = 0; t < (int)groupedTypes[OpTypeArray].size(); ++t) {
296 type = groupedTypes[OpTypeArray][t];
297 if (type->getIdOperand(0) == element &&
298 type->getIdOperand(1) == sizeId)
299 return type->getResultId();
303 // not found, make it
304 type = new Instruction(getUniqueId(), NoType, OpTypeArray);
305 type->addIdOperand(element);
306 type->addIdOperand(sizeId);
307 groupedTypes[OpTypeArray].push_back(type);
308 constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(type));
309 module.mapInstruction(type);
311 return type->getResultId();
314 Id Builder::makeRuntimeArray(Id element)
316 Instruction* type = new Instruction(getUniqueId(), NoType, OpTypeRuntimeArray);
317 type->addIdOperand(element);
318 constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(type));
319 module.mapInstruction(type);
321 return type->getResultId();
324 Id Builder::makeFunctionType(Id returnType, std::vector<Id>& paramTypes)
328 for (int t = 0; t < (int)groupedTypes[OpTypeFunction].size(); ++t) {
329 type = groupedTypes[OpTypeFunction][t];
330 if (type->getIdOperand(0) != returnType || (int)paramTypes.size() != type->getNumOperands() - 1)
332 bool mismatch = false;
333 for (int p = 0; p < (int)paramTypes.size(); ++p) {
334 if (paramTypes[p] != type->getIdOperand(p + 1)) {
340 return type->getResultId();
343 // not found, make it
344 type = new Instruction(getUniqueId(), NoType, OpTypeFunction);
345 type->addIdOperand(returnType);
346 for (int p = 0; p < (int)paramTypes.size(); ++p)
347 type->addIdOperand(paramTypes[p]);
348 groupedTypes[OpTypeFunction].push_back(type);
349 constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(type));
350 module.mapInstruction(type);
352 return type->getResultId();
355 Id Builder::makeImageType(Id sampledType, Dim dim, bool depth, bool arrayed, bool ms, unsigned sampled, ImageFormat format)
359 for (int t = 0; t < (int)groupedTypes[OpTypeImage].size(); ++t) {
360 type = groupedTypes[OpTypeImage][t];
361 if (type->getIdOperand(0) == sampledType &&
362 type->getImmediateOperand(1) == (unsigned int)dim &&
363 type->getImmediateOperand(2) == ( depth ? 1u : 0u) &&
364 type->getImmediateOperand(3) == (arrayed ? 1u : 0u) &&
365 type->getImmediateOperand(4) == ( ms ? 1u : 0u) &&
366 type->getImmediateOperand(5) == sampled &&
367 type->getImmediateOperand(6) == (unsigned int)format)
368 return type->getResultId();
371 // not found, make it
372 type = new Instruction(getUniqueId(), NoType, OpTypeImage);
373 type->addIdOperand(sampledType);
374 type->addImmediateOperand( dim);
375 type->addImmediateOperand( depth ? 1 : 0);
376 type->addImmediateOperand(arrayed ? 1 : 0);
377 type->addImmediateOperand( ms ? 1 : 0);
378 type->addImmediateOperand(sampled);
379 type->addImmediateOperand((unsigned int)format);
381 groupedTypes[OpTypeImage].push_back(type);
382 constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(type));
383 module.mapInstruction(type);
385 return type->getResultId();
388 Id Builder::makeSampledImageType(Id imageType)
392 for (int t = 0; t < (int)groupedTypes[OpTypeSampledImage].size(); ++t) {
393 type = groupedTypes[OpTypeSampledImage][t];
394 if (type->getIdOperand(0) == imageType)
395 return type->getResultId();
398 // not found, make it
399 type = new Instruction(getUniqueId(), NoType, OpTypeSampledImage);
400 type->addIdOperand(imageType);
402 groupedTypes[OpTypeSampledImage].push_back(type);
403 constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(type));
404 module.mapInstruction(type);
406 return type->getResultId();
409 Id Builder::getDerefTypeId(Id resultId) const
411 Id typeId = getTypeId(resultId);
412 assert(isPointerType(typeId));
414 return module.getInstruction(typeId)->getImmediateOperand(1);
417 Op Builder::getMostBasicTypeClass(Id typeId) const
419 Instruction* instr = module.getInstruction(typeId);
421 Op typeClass = instr->getOpCode();
433 case OpTypeRuntimeArray:
434 return getMostBasicTypeClass(instr->getIdOperand(0));
436 return getMostBasicTypeClass(instr->getIdOperand(1));
443 int Builder::getNumTypeConstituents(Id typeId) const
445 Instruction* instr = module.getInstruction(typeId);
447 switch (instr->getOpCode())
456 return instr->getImmediateOperand(1);
458 return instr->getNumOperands();
465 // Return the lowest-level type of scalar that an homogeneous composite is made out of.
466 // Typically, this is just to find out if something is made out of ints or floats.
467 // However, it includes returning a structure, if say, it is an array of structure.
468 Id Builder::getScalarTypeId(Id typeId) const
470 Instruction* instr = module.getInstruction(typeId);
472 Op typeClass = instr->getOpCode();
480 return instr->getResultId();
484 case OpTypeRuntimeArray:
486 return getScalarTypeId(getContainedTypeId(typeId));
493 // Return the type of 'member' of a composite.
494 Id Builder::getContainedTypeId(Id typeId, int member) const
496 Instruction* instr = module.getInstruction(typeId);
498 Op typeClass = instr->getOpCode();
504 case OpTypeRuntimeArray:
505 return instr->getIdOperand(0);
507 return instr->getIdOperand(1);
509 return instr->getIdOperand(member);
516 // Return the immediately contained type of a given composite type.
517 Id Builder::getContainedTypeId(Id typeId) const
519 return getContainedTypeId(typeId, 0);
522 // See if a scalar constant of this type has already been created, so it
523 // can be reused rather than duplicated. (Required by the specification).
524 Id Builder::findScalarConstant(Op typeClass, Op opcode, Id typeId, unsigned value) const
526 Instruction* constant;
527 for (int i = 0; i < (int)groupedConstants[typeClass].size(); ++i) {
528 constant = groupedConstants[typeClass][i];
529 if (constant->getOpCode() == opcode &&
530 constant->getTypeId() == typeId &&
531 constant->getImmediateOperand(0) == value)
532 return constant->getResultId();
538 // Version of findScalarConstant (see above) for scalars that take two operands (e.g. a 'double').
539 Id Builder::findScalarConstant(Op typeClass, Op opcode, Id typeId, unsigned v1, unsigned v2) const
541 Instruction* constant;
542 for (int i = 0; i < (int)groupedConstants[typeClass].size(); ++i) {
543 constant = groupedConstants[typeClass][i];
544 if (constant->getOpCode() == opcode &&
545 constant->getTypeId() == typeId &&
546 constant->getImmediateOperand(0) == v1 &&
547 constant->getImmediateOperand(1) == v2)
548 return constant->getResultId();
554 // Return true if consuming 'opcode' means consuming a constant.
555 // "constant" here means after final transform to executable code,
556 // the value consumed will be a constant, so includes specialization.
557 bool Builder::isConstantOpCode(Op opcode) const
562 case OpConstantFalse:
564 case OpConstantComposite:
565 case OpConstantSampler:
567 case OpSpecConstantTrue:
568 case OpSpecConstantFalse:
570 case OpSpecConstantComposite:
571 case OpSpecConstantOp:
578 Id Builder::makeBoolConstant(bool b, bool specConstant)
580 Id typeId = makeBoolType();
581 Instruction* constant;
582 Op opcode = specConstant ? (b ? OpSpecConstantTrue : OpSpecConstantFalse) : (b ? OpConstantTrue : OpConstantFalse);
584 // See if we already made it
586 for (int i = 0; i < (int)groupedConstants[OpTypeBool].size(); ++i) {
587 constant = groupedConstants[OpTypeBool][i];
588 if (constant->getTypeId() == typeId && constant->getOpCode() == opcode)
589 existing = constant->getResultId();
596 Instruction* c = new Instruction(getUniqueId(), typeId, opcode);
597 constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(c));
598 groupedConstants[OpTypeBool].push_back(c);
599 module.mapInstruction(c);
601 return c->getResultId();
604 Id Builder::makeIntConstant(Id typeId, unsigned value, bool specConstant)
606 Op opcode = specConstant ? OpSpecConstant : OpConstant;
607 Id existing = findScalarConstant(OpTypeInt, opcode, typeId, value);
611 Instruction* c = new Instruction(getUniqueId(), typeId, opcode);
612 c->addImmediateOperand(value);
613 constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(c));
614 groupedConstants[OpTypeInt].push_back(c);
615 module.mapInstruction(c);
617 return c->getResultId();
620 Id Builder::makeFloatConstant(float f, bool specConstant)
622 Op opcode = specConstant ? OpSpecConstant : OpConstant;
623 Id typeId = makeFloatType(32);
624 unsigned value = *(unsigned int*)&f;
625 Id existing = findScalarConstant(OpTypeFloat, opcode, typeId, value);
629 Instruction* c = new Instruction(getUniqueId(), typeId, opcode);
630 c->addImmediateOperand(value);
631 constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(c));
632 groupedConstants[OpTypeFloat].push_back(c);
633 module.mapInstruction(c);
635 return c->getResultId();
638 Id Builder::makeDoubleConstant(double d, bool specConstant)
640 Op opcode = specConstant ? OpSpecConstant : OpConstant;
641 Id typeId = makeFloatType(64);
642 unsigned long long value = *(unsigned long long*)&d;
643 unsigned op1 = value & 0xFFFFFFFF;
644 unsigned op2 = value >> 32;
645 Id existing = findScalarConstant(OpTypeFloat, opcode, typeId, op1, op2);
649 Instruction* c = new Instruction(getUniqueId(), typeId, opcode);
650 c->addImmediateOperand(op1);
651 c->addImmediateOperand(op2);
652 constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(c));
653 groupedConstants[OpTypeFloat].push_back(c);
654 module.mapInstruction(c);
656 return c->getResultId();
659 Id Builder::findCompositeConstant(Op typeClass, std::vector<Id>& comps) const
661 Instruction* constant = 0;
663 for (int i = 0; i < (int)groupedConstants[typeClass].size(); ++i) {
664 constant = groupedConstants[typeClass][i];
667 if (constant->getNumOperands() != (int)comps.size())
671 bool mismatch = false;
672 for (int op = 0; op < constant->getNumOperands(); ++op) {
673 if (constant->getIdOperand(op) != comps[op]) {
684 return found ? constant->getResultId() : NoResult;
687 // Comments in header
688 Id Builder::makeCompositeConstant(Id typeId, std::vector<Id>& members)
691 Op typeClass = getTypeClass(typeId);
701 return makeFloatConstant(0.0);
704 Id existing = findCompositeConstant(typeClass, members);
708 Instruction* c = new Instruction(getUniqueId(), typeId, OpConstantComposite);
709 for (int op = 0; op < (int)members.size(); ++op)
710 c->addIdOperand(members[op]);
711 constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(c));
712 groupedConstants[typeClass].push_back(c);
713 module.mapInstruction(c);
715 return c->getResultId();
718 Instruction* Builder::addEntryPoint(ExecutionModel model, Function* function, const char* name)
720 Instruction* entryPoint = new Instruction(OpEntryPoint);
721 entryPoint->addImmediateOperand(model);
722 entryPoint->addIdOperand(function->getId());
723 entryPoint->addStringOperand(name);
725 entryPoints.push_back(std::unique_ptr<Instruction>(entryPoint));
730 // Currently relying on the fact that all 'value' of interest are small non-negative values.
731 void Builder::addExecutionMode(Function* entryPoint, ExecutionMode mode, int value1, int value2, int value3)
733 Instruction* instr = new Instruction(OpExecutionMode);
734 instr->addIdOperand(entryPoint->getId());
735 instr->addImmediateOperand(mode);
737 instr->addImmediateOperand(value1);
739 instr->addImmediateOperand(value2);
741 instr->addImmediateOperand(value3);
743 executionModes.push_back(std::unique_ptr<Instruction>(instr));
746 void Builder::addName(Id id, const char* string)
748 Instruction* name = new Instruction(OpName);
749 name->addIdOperand(id);
750 name->addStringOperand(string);
752 names.push_back(std::unique_ptr<Instruction>(name));
755 void Builder::addMemberName(Id id, int memberNumber, const char* string)
757 Instruction* name = new Instruction(OpMemberName);
758 name->addIdOperand(id);
759 name->addImmediateOperand(memberNumber);
760 name->addStringOperand(string);
762 names.push_back(std::unique_ptr<Instruction>(name));
765 void Builder::addLine(Id target, Id fileName, int lineNum, int column)
767 Instruction* line = new Instruction(OpLine);
768 line->addIdOperand(target);
769 line->addIdOperand(fileName);
770 line->addImmediateOperand(lineNum);
771 line->addImmediateOperand(column);
773 lines.push_back(std::unique_ptr<Instruction>(line));
776 void Builder::addDecoration(Id id, Decoration decoration, int num)
778 if (decoration == (spv::Decoration)spv::BadValue)
780 Instruction* dec = new Instruction(OpDecorate);
781 dec->addIdOperand(id);
782 dec->addImmediateOperand(decoration);
784 dec->addImmediateOperand(num);
786 decorations.push_back(std::unique_ptr<Instruction>(dec));
789 void Builder::addMemberDecoration(Id id, unsigned int member, Decoration decoration, int num)
791 Instruction* dec = new Instruction(OpMemberDecorate);
792 dec->addIdOperand(id);
793 dec->addImmediateOperand(member);
794 dec->addImmediateOperand(decoration);
796 dec->addImmediateOperand(num);
798 decorations.push_back(std::unique_ptr<Instruction>(dec));
801 // Comments in header
802 Function* Builder::makeMain()
804 assert(! mainFunction);
807 std::vector<Id> params;
809 mainFunction = makeFunctionEntry(makeVoidType(), "main", params, &entry);
814 // Comments in header
815 Function* Builder::makeFunctionEntry(Id returnType, const char* name, std::vector<Id>& paramTypes, Block **entry)
817 Id typeId = makeFunctionType(returnType, paramTypes);
818 Id firstParamId = paramTypes.size() == 0 ? 0 : getUniqueIds((int)paramTypes.size());
819 Function* function = new Function(getUniqueId(), returnType, typeId, firstParamId, module);
822 *entry = new Block(getUniqueId(), *function);
823 function->addBlock(*entry);
824 setBuildPoint(*entry);
828 addName(function->getId(), name);
830 functions.push_back(std::unique_ptr<Function>(function));
835 // Comments in header
836 void Builder::makeReturn(bool implicit, Id retVal)
839 Instruction* inst = new Instruction(NoResult, NoType, OpReturnValue);
840 inst->addIdOperand(retVal);
841 buildPoint->addInstruction(std::unique_ptr<Instruction>(inst));
843 buildPoint->addInstruction(std::unique_ptr<Instruction>(new Instruction(NoResult, NoType, OpReturn)));
846 createAndSetNoPredecessorBlock("post-return");
849 // Comments in header
850 void Builder::leaveFunction()
852 Block* block = buildPoint;
853 Function& function = buildPoint->getParent();
856 // If our function did not contain a return, add a return void now.
857 if (! block->isTerminated()) {
859 // Whether we're in an unreachable (non-entry) block.
860 bool unreachable = function.getEntryBlock() != block && block->getNumPredecessors() == 0;
863 // Given that this block is at the end of a function, it must be right after an
864 // explicit return, just remove it.
865 function.popBlock(block);
867 // We'll add a return instruction at the end of the current block,
868 // which for a non-void function is really error recovery (?), as the source
869 // being translated should have had an explicit return, which would have been
870 // followed by an unreachable block, which was handled above.
871 if (function.getReturnType() == makeVoidType())
874 makeReturn(true, createUndefined(function.getReturnType()));
880 // Comments in header
881 void Builder::makeDiscard()
883 buildPoint->addInstruction(std::unique_ptr<Instruction>(new Instruction(OpKill)));
884 createAndSetNoPredecessorBlock("post-discard");
887 // Comments in header
888 Id Builder::createVariable(StorageClass storageClass, Id type, const char* name)
890 Id pointerType = makePointer(storageClass, type);
891 Instruction* inst = new Instruction(getUniqueId(), pointerType, OpVariable);
892 inst->addImmediateOperand(storageClass);
894 switch (storageClass) {
895 case StorageClassFunction:
896 // Validation rules require the declaration in the entry block
897 buildPoint->getParent().addLocalVariable(std::unique_ptr<Instruction>(inst));
901 constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(inst));
902 module.mapInstruction(inst);
907 addName(inst->getResultId(), name);
909 return inst->getResultId();
912 // Comments in header
913 Id Builder::createUndefined(Id type)
915 Instruction* inst = new Instruction(getUniqueId(), type, OpUndef);
916 buildPoint->addInstruction(std::unique_ptr<Instruction>(inst));
917 return inst->getResultId();
920 // Comments in header
921 void Builder::createStore(Id rValue, Id lValue)
923 Instruction* store = new Instruction(OpStore);
924 store->addIdOperand(lValue);
925 store->addIdOperand(rValue);
926 buildPoint->addInstruction(std::unique_ptr<Instruction>(store));
929 // Comments in header
930 Id Builder::createLoad(Id lValue)
932 Instruction* load = new Instruction(getUniqueId(), getDerefTypeId(lValue), OpLoad);
933 load->addIdOperand(lValue);
934 buildPoint->addInstruction(std::unique_ptr<Instruction>(load));
936 return load->getResultId();
939 // Comments in header
940 Id Builder::createAccessChain(StorageClass storageClass, Id base, std::vector<Id>& offsets)
942 // Figure out the final resulting type.
943 spv::Id typeId = getTypeId(base);
944 assert(isPointerType(typeId) && offsets.size() > 0);
945 typeId = getContainedTypeId(typeId);
946 for (int i = 0; i < (int)offsets.size(); ++i) {
947 if (isStructType(typeId)) {
948 assert(isConstantScalar(offsets[i]));
949 typeId = getContainedTypeId(typeId, getConstantScalar(offsets[i]));
951 typeId = getContainedTypeId(typeId, offsets[i]);
953 typeId = makePointer(storageClass, typeId);
955 // Make the instruction
956 Instruction* chain = new Instruction(getUniqueId(), typeId, OpAccessChain);
957 chain->addIdOperand(base);
958 for (int i = 0; i < (int)offsets.size(); ++i)
959 chain->addIdOperand(offsets[i]);
960 buildPoint->addInstruction(std::unique_ptr<Instruction>(chain));
962 return chain->getResultId();
965 Id Builder::createArrayLength(Id base, unsigned int member)
967 Instruction* length = new Instruction(getUniqueId(), makeIntType(32), OpArrayLength);
968 length->addIdOperand(base);
969 length->addImmediateOperand(member);
970 buildPoint->addInstruction(std::unique_ptr<Instruction>(length));
972 return length->getResultId();
975 Id Builder::createCompositeExtract(Id composite, Id typeId, unsigned index)
977 Instruction* extract = new Instruction(getUniqueId(), typeId, OpCompositeExtract);
978 extract->addIdOperand(composite);
979 extract->addImmediateOperand(index);
980 buildPoint->addInstruction(std::unique_ptr<Instruction>(extract));
982 return extract->getResultId();
985 Id Builder::createCompositeExtract(Id composite, Id typeId, std::vector<unsigned>& indexes)
987 Instruction* extract = new Instruction(getUniqueId(), typeId, OpCompositeExtract);
988 extract->addIdOperand(composite);
989 for (int i = 0; i < (int)indexes.size(); ++i)
990 extract->addImmediateOperand(indexes[i]);
991 buildPoint->addInstruction(std::unique_ptr<Instruction>(extract));
993 return extract->getResultId();
996 Id Builder::createCompositeInsert(Id object, Id composite, Id typeId, unsigned index)
998 Instruction* insert = new Instruction(getUniqueId(), typeId, OpCompositeInsert);
999 insert->addIdOperand(object);
1000 insert->addIdOperand(composite);
1001 insert->addImmediateOperand(index);
1002 buildPoint->addInstruction(std::unique_ptr<Instruction>(insert));
1004 return insert->getResultId();
1007 Id Builder::createCompositeInsert(Id object, Id composite, Id typeId, std::vector<unsigned>& indexes)
1009 Instruction* insert = new Instruction(getUniqueId(), typeId, OpCompositeInsert);
1010 insert->addIdOperand(object);
1011 insert->addIdOperand(composite);
1012 for (int i = 0; i < (int)indexes.size(); ++i)
1013 insert->addImmediateOperand(indexes[i]);
1014 buildPoint->addInstruction(std::unique_ptr<Instruction>(insert));
1016 return insert->getResultId();
1019 Id Builder::createVectorExtractDynamic(Id vector, Id typeId, Id componentIndex)
1021 Instruction* extract = new Instruction(getUniqueId(), typeId, OpVectorExtractDynamic);
1022 extract->addIdOperand(vector);
1023 extract->addIdOperand(componentIndex);
1024 buildPoint->addInstruction(std::unique_ptr<Instruction>(extract));
1026 return extract->getResultId();
1029 Id Builder::createVectorInsertDynamic(Id vector, Id typeId, Id component, Id componentIndex)
1031 Instruction* insert = new Instruction(getUniqueId(), typeId, OpVectorInsertDynamic);
1032 insert->addIdOperand(vector);
1033 insert->addIdOperand(component);
1034 insert->addIdOperand(componentIndex);
1035 buildPoint->addInstruction(std::unique_ptr<Instruction>(insert));
1037 return insert->getResultId();
1040 // An opcode that has no operands, no result id, and no type
1041 void Builder::createNoResultOp(Op opCode)
1043 Instruction* op = new Instruction(opCode);
1044 buildPoint->addInstruction(std::unique_ptr<Instruction>(op));
1047 // An opcode that has one operand, no result id, and no type
1048 void Builder::createNoResultOp(Op opCode, Id operand)
1050 Instruction* op = new Instruction(opCode);
1051 op->addIdOperand(operand);
1052 buildPoint->addInstruction(std::unique_ptr<Instruction>(op));
1055 // An opcode that has one operand, no result id, and no type
1056 void Builder::createNoResultOp(Op opCode, const std::vector<Id>& operands)
1058 Instruction* op = new Instruction(opCode);
1059 for (auto operand : operands)
1060 op->addIdOperand(operand);
1061 buildPoint->addInstruction(std::unique_ptr<Instruction>(op));
1064 void Builder::createControlBarrier(Scope execution, Scope memory, MemorySemanticsMask semantics)
1066 Instruction* op = new Instruction(OpControlBarrier);
1067 op->addImmediateOperand(makeUintConstant(execution));
1068 op->addImmediateOperand(makeUintConstant(memory));
1069 op->addImmediateOperand(makeUintConstant(semantics));
1070 buildPoint->addInstruction(std::unique_ptr<Instruction>(op));
1073 void Builder::createMemoryBarrier(unsigned executionScope, unsigned memorySemantics)
1075 Instruction* op = new Instruction(OpMemoryBarrier);
1076 op->addImmediateOperand(makeUintConstant(executionScope));
1077 op->addImmediateOperand(makeUintConstant(memorySemantics));
1078 buildPoint->addInstruction(std::unique_ptr<Instruction>(op));
1081 // An opcode that has one operands, a result id, and a type
1082 Id Builder::createUnaryOp(Op opCode, Id typeId, Id operand)
1084 Instruction* op = new Instruction(getUniqueId(), typeId, opCode);
1085 op->addIdOperand(operand);
1086 buildPoint->addInstruction(std::unique_ptr<Instruction>(op));
1088 return op->getResultId();
1091 Id Builder::createBinOp(Op opCode, Id typeId, Id left, Id right)
1093 Instruction* op = new Instruction(getUniqueId(), typeId, opCode);
1094 op->addIdOperand(left);
1095 op->addIdOperand(right);
1096 buildPoint->addInstruction(std::unique_ptr<Instruction>(op));
1098 return op->getResultId();
1101 Id Builder::createTriOp(Op opCode, Id typeId, Id op1, Id op2, Id op3)
1103 Instruction* op = new Instruction(getUniqueId(), typeId, opCode);
1104 op->addIdOperand(op1);
1105 op->addIdOperand(op2);
1106 op->addIdOperand(op3);
1107 buildPoint->addInstruction(std::unique_ptr<Instruction>(op));
1109 return op->getResultId();
1112 Id Builder::createOp(Op opCode, Id typeId, const std::vector<Id>& operands)
1114 Instruction* op = new Instruction(getUniqueId(), typeId, opCode);
1115 for (auto operand : operands)
1116 op->addIdOperand(operand);
1117 buildPoint->addInstruction(std::unique_ptr<Instruction>(op));
1119 return op->getResultId();
1122 Id Builder::createFunctionCall(spv::Function* function, std::vector<spv::Id>& args)
1124 Instruction* op = new Instruction(getUniqueId(), function->getReturnType(), OpFunctionCall);
1125 op->addIdOperand(function->getId());
1126 for (int a = 0; a < (int)args.size(); ++a)
1127 op->addIdOperand(args[a]);
1128 buildPoint->addInstruction(std::unique_ptr<Instruction>(op));
1130 return op->getResultId();
1133 // Comments in header
1134 Id Builder::createRvalueSwizzle(Id typeId, Id source, std::vector<unsigned>& channels)
1136 if (channels.size() == 1)
1137 return createCompositeExtract(source, typeId, channels.front());
1139 Instruction* swizzle = new Instruction(getUniqueId(), typeId, OpVectorShuffle);
1140 assert(isVector(source));
1141 swizzle->addIdOperand(source);
1142 swizzle->addIdOperand(source);
1143 for (int i = 0; i < (int)channels.size(); ++i)
1144 swizzle->addImmediateOperand(channels[i]);
1145 buildPoint->addInstruction(std::unique_ptr<Instruction>(swizzle));
1147 return swizzle->getResultId();
1150 // Comments in header
1151 Id Builder::createLvalueSwizzle(Id typeId, Id target, Id source, std::vector<unsigned>& channels)
1153 assert(getNumComponents(source) == (int)channels.size());
1154 if (channels.size() == 1 && getNumComponents(source) == 1)
1155 return createCompositeInsert(source, target, typeId, channels.front());
1157 Instruction* swizzle = new Instruction(getUniqueId(), typeId, OpVectorShuffle);
1158 assert(isVector(source));
1159 assert(isVector(target));
1160 swizzle->addIdOperand(target);
1161 swizzle->addIdOperand(source);
1163 // Set up an identity shuffle from the base value to the result value
1164 unsigned int components[4];
1165 int numTargetComponents = getNumComponents(target);
1166 for (int i = 0; i < numTargetComponents; ++i)
1169 // Punch in the l-value swizzle
1170 for (int i = 0; i < (int)channels.size(); ++i)
1171 components[channels[i]] = numTargetComponents + i;
1173 // finish the instruction with these components selectors
1174 for (int i = 0; i < numTargetComponents; ++i)
1175 swizzle->addImmediateOperand(components[i]);
1176 buildPoint->addInstruction(std::unique_ptr<Instruction>(swizzle));
1178 return swizzle->getResultId();
1181 // Comments in header
1182 void Builder::promoteScalar(Decoration precision, Id& left, Id& right)
1184 int direction = getNumComponents(right) - getNumComponents(left);
1187 left = smearScalar(precision, left, makeVectorType(getTypeId(left), getNumComponents(right)));
1188 else if (direction < 0)
1189 right = smearScalar(precision, right, makeVectorType(getTypeId(right), getNumComponents(left)));
1194 // Comments in header
1195 Id Builder::smearScalar(Decoration /*precision*/, Id scalar, Id vectorType)
1197 assert(getNumComponents(scalar) == 1);
1198 assert(getTypeId(scalar) == getScalarTypeId(vectorType));
1200 int numComponents = getNumTypeComponents(vectorType);
1201 if (numComponents == 1)
1204 Instruction* smear = new Instruction(getUniqueId(), vectorType, OpCompositeConstruct);
1205 for (int c = 0; c < numComponents; ++c)
1206 smear->addIdOperand(scalar);
1207 buildPoint->addInstruction(std::unique_ptr<Instruction>(smear));
1209 return smear->getResultId();
1212 // Comments in header
1213 Id Builder::createBuiltinCall(Decoration /*precision*/, Id resultType, Id builtins, int entryPoint, std::vector<Id>& args)
1215 Instruction* inst = new Instruction(getUniqueId(), resultType, OpExtInst);
1216 inst->addIdOperand(builtins);
1217 inst->addImmediateOperand(entryPoint);
1218 for (int arg = 0; arg < (int)args.size(); ++arg)
1219 inst->addIdOperand(args[arg]);
1221 buildPoint->addInstruction(std::unique_ptr<Instruction>(inst));
1222 return inst->getResultId();
1225 // Accept all parameters needed to create a texture instruction.
1226 // Create the correct instruction based on the inputs, and make the call.
1227 Id Builder::createTextureCall(Decoration precision, Id resultType, bool sparse, bool fetch, bool proj, bool gather, const TextureParameters& parameters)
1229 static const int maxTextureArgs = 10;
1230 Id texArgs[maxTextureArgs] = {};
1233 // Set up the fixed arguments
1236 bool xplicit = false;
1237 texArgs[numArgs++] = parameters.sampler;
1238 texArgs[numArgs++] = parameters.coords;
1239 if (parameters.Dref)
1240 texArgs[numArgs++] = parameters.Dref;
1241 if (parameters.comp)
1242 texArgs[numArgs++] = parameters.comp;
1245 // Set up the optional arguments
1247 int optArgNum = numArgs; // track which operand, if it exists, is the mask of optional arguments
1248 ++numArgs; // speculatively make room for the mask operand
1249 ImageOperandsMask mask = ImageOperandsMaskNone; // the mask operand
1250 if (parameters.bias) {
1251 mask = (ImageOperandsMask)(mask | ImageOperandsBiasMask);
1252 texArgs[numArgs++] = parameters.bias;
1254 if (parameters.lod) {
1255 mask = (ImageOperandsMask)(mask | ImageOperandsLodMask);
1256 texArgs[numArgs++] = parameters.lod;
1259 if (parameters.gradX) {
1260 mask = (ImageOperandsMask)(mask | ImageOperandsGradMask);
1261 texArgs[numArgs++] = parameters.gradX;
1262 texArgs[numArgs++] = parameters.gradY;
1265 if (parameters.offset) {
1266 if (isConstant(parameters.offset))
1267 mask = (ImageOperandsMask)(mask | ImageOperandsConstOffsetMask);
1269 mask = (ImageOperandsMask)(mask | ImageOperandsOffsetMask);
1270 texArgs[numArgs++] = parameters.offset;
1272 if (parameters.offsets) {
1273 mask = (ImageOperandsMask)(mask | ImageOperandsConstOffsetsMask);
1274 texArgs[numArgs++] = parameters.offsets;
1276 if (parameters.sample) {
1277 mask = (ImageOperandsMask)(mask | ImageOperandsSampleMask);
1278 texArgs[numArgs++] = parameters.sample;
1280 if (parameters.lodClamp) {
1281 mask = (ImageOperandsMask)(mask | ImageOperandsMinLodMask);
1282 texArgs[numArgs++] = parameters.lodClamp;
1284 if (mask == ImageOperandsMaskNone)
1285 --numArgs; // undo speculative reservation for the mask argument
1287 texArgs[optArgNum] = mask;
1290 // Set up the instruction
1293 opCode = OpImageSampleImplicitLod;
1296 opCode = OpImageSparseFetch;
1298 opCode = OpImageFetch;
1299 } else if (gather) {
1300 if (parameters.Dref)
1302 opCode = OpImageSparseDrefGather;
1304 opCode = OpImageDrefGather;
1307 opCode = OpImageSparseGather;
1309 opCode = OpImageGather;
1310 } else if (xplicit) {
1311 if (parameters.Dref) {
1314 opCode = OpImageSparseSampleProjDrefExplicitLod;
1316 opCode = OpImageSampleProjDrefExplicitLod;
1319 opCode = OpImageSparseSampleDrefExplicitLod;
1321 opCode = OpImageSampleDrefExplicitLod;
1325 opCode = OpImageSparseSampleProjExplicitLod;
1327 opCode = OpImageSampleProjExplicitLod;
1330 opCode = OpImageSparseSampleExplicitLod;
1332 opCode = OpImageSampleExplicitLod;
1335 if (parameters.Dref) {
1338 opCode = OpImageSparseSampleProjDrefImplicitLod;
1340 opCode = OpImageSampleProjDrefImplicitLod;
1343 opCode = OpImageSparseSampleDrefImplicitLod;
1345 opCode = OpImageSampleDrefImplicitLod;
1349 opCode = OpImageSparseSampleProjImplicitLod;
1351 opCode = OpImageSampleProjImplicitLod;
1354 opCode = OpImageSparseSampleImplicitLod;
1356 opCode = OpImageSampleImplicitLod;
1360 // See if the result type is expecting a smeared result.
1361 // This happens when a legacy shadow*() call is made, which
1362 // gets a vec4 back instead of a float.
1363 Id smearedType = resultType;
1364 if (! isScalarType(resultType)) {
1366 case OpImageSampleDrefImplicitLod:
1367 case OpImageSampleDrefExplicitLod:
1368 case OpImageSampleProjDrefImplicitLod:
1369 case OpImageSampleProjDrefExplicitLod:
1370 resultType = getScalarTypeId(resultType);
1381 typeId0 = resultType;
1382 typeId1 = getDerefTypeId(parameters.texelOut);
1383 resultType = makeStructResultType(typeId0, typeId1);
1386 // Build the SPIR-V instruction
1387 Instruction* textureInst = new Instruction(getUniqueId(), resultType, opCode);
1388 for (int op = 0; op < optArgNum; ++op)
1389 textureInst->addIdOperand(texArgs[op]);
1390 if (optArgNum < numArgs)
1391 textureInst->addImmediateOperand(texArgs[optArgNum]);
1392 for (int op = optArgNum + 1; op < numArgs; ++op)
1393 textureInst->addIdOperand(texArgs[op]);
1394 setPrecision(textureInst->getResultId(), precision);
1395 buildPoint->addInstruction(std::unique_ptr<Instruction>(textureInst));
1397 Id resultId = textureInst->getResultId();
1400 // Decode the return type that was a special structure
1401 createStore(createCompositeExtract(resultId, typeId1, 1), parameters.texelOut);
1402 resultId = createCompositeExtract(resultId, typeId0, 0);
1404 // When a smear is needed, do it, as per what was computed
1405 // above when resultType was changed to a scalar type.
1406 if (resultType != smearedType)
1407 resultId = smearScalar(precision, resultId, smearedType);
1413 // Comments in header
1414 Id Builder::createTextureQueryCall(Op opCode, const TextureParameters& parameters)
1416 // Figure out the result type
1419 case OpImageQuerySize:
1420 case OpImageQuerySizeLod:
1422 int numComponents = 0;
1423 switch (getTypeDimensionality(getImageType(parameters.sampler))) {
1431 case DimSubpassData:
1442 if (isArrayedImageType(getImageType(parameters.sampler)))
1444 if (numComponents == 1)
1445 resultType = makeIntType(32);
1447 resultType = makeVectorType(makeIntType(32), numComponents);
1451 case OpImageQueryLod:
1452 resultType = makeVectorType(makeFloatType(32), 2);
1454 case OpImageQueryLevels:
1455 case OpImageQuerySamples:
1456 resultType = makeIntType(32);
1463 Instruction* query = new Instruction(getUniqueId(), resultType, opCode);
1464 query->addIdOperand(parameters.sampler);
1465 if (parameters.coords)
1466 query->addIdOperand(parameters.coords);
1468 query->addIdOperand(parameters.lod);
1469 buildPoint->addInstruction(std::unique_ptr<Instruction>(query));
1471 return query->getResultId();
1474 // External comments in header.
1475 // Operates recursively to visit the composite's hierarchy.
1476 Id Builder::createCompositeCompare(Decoration precision, Id value1, Id value2, bool equal)
1478 Id boolType = makeBoolType();
1479 Id valueType = getTypeId(value1);
1483 int numConstituents = getNumTypeConstituents(valueType);
1485 // Scalars and Vectors
1487 if (isScalarType(valueType) || isVectorType(valueType)) {
1488 assert(valueType == getTypeId(value2));
1489 // These just need a single comparison, just have
1490 // to figure out what it is.
1492 switch (getMostBasicTypeClass(valueType)) {
1494 op = equal ? OpFOrdEqual : OpFOrdNotEqual;
1497 op = equal ? OpIEqual : OpINotEqual;
1500 op = equal ? OpLogicalEqual : OpLogicalNotEqual;
1501 precision = NoPrecision;
1505 if (isScalarType(valueType)) {
1507 resultId = createBinOp(op, boolType, value1, value2);
1508 setPrecision(resultId, precision);
1511 resultId = createBinOp(op, makeVectorType(boolType, numConstituents), value1, value2);
1512 setPrecision(resultId, precision);
1513 // reduce vector compares...
1514 resultId = createUnaryOp(equal ? OpAll : OpAny, boolType, resultId);
1520 // Only structs, arrays, and matrices should be left.
1521 // They share in common the reduction operation across their constituents.
1522 assert(isAggregateType(valueType) || isMatrixType(valueType));
1524 // Compare each pair of constituents
1525 for (int constituent = 0; constituent < numConstituents; ++constituent) {
1526 std::vector<unsigned> indexes(1, constituent);
1527 Id constituentType1 = getContainedTypeId(getTypeId(value1), constituent);
1528 Id constituentType2 = getContainedTypeId(getTypeId(value2), constituent);
1529 Id constituent1 = createCompositeExtract(value1, constituentType1, indexes);
1530 Id constituent2 = createCompositeExtract(value2, constituentType2, indexes);
1532 Id subResultId = createCompositeCompare(precision, constituent1, constituent2, equal);
1534 if (constituent == 0)
1535 resultId = subResultId;
1537 resultId = createBinOp(equal ? OpLogicalAnd : OpLogicalOr, boolType, resultId, subResultId);
1543 // OpCompositeConstruct
1544 Id Builder::createCompositeConstruct(Id typeId, std::vector<Id>& constituents)
1546 assert(isAggregateType(typeId) || (getNumTypeConstituents(typeId) > 1 && getNumTypeConstituents(typeId) == (int)constituents.size()));
1548 Instruction* op = new Instruction(getUniqueId(), typeId, OpCompositeConstruct);
1549 for (int c = 0; c < (int)constituents.size(); ++c)
1550 op->addIdOperand(constituents[c]);
1551 buildPoint->addInstruction(std::unique_ptr<Instruction>(op));
1553 return op->getResultId();
1556 // Vector or scalar constructor
1557 Id Builder::createConstructor(Decoration precision, const std::vector<Id>& sources, Id resultTypeId)
1560 unsigned int numTargetComponents = getNumTypeComponents(resultTypeId);
1561 unsigned int targetComponent = 0;
1563 // Special case: when calling a vector constructor with a single scalar
1564 // argument, smear the scalar
1565 if (sources.size() == 1 && isScalar(sources[0]) && numTargetComponents > 1)
1566 return smearScalar(precision, sources[0], resultTypeId);
1568 Id scalarTypeId = getScalarTypeId(resultTypeId);
1569 std::vector<Id> constituents; // accumulate the arguments for OpCompositeConstruct
1570 for (unsigned int i = 0; i < sources.size(); ++i) {
1571 assert(! isAggregate(sources[i]));
1572 unsigned int sourceSize = getNumComponents(sources[i]);
1573 unsigned int sourcesToUse = sourceSize;
1574 if (sourcesToUse + targetComponent > numTargetComponents)
1575 sourcesToUse = numTargetComponents - targetComponent;
1577 for (unsigned int s = 0; s < sourcesToUse; ++s) {
1578 Id arg = sources[i];
1579 if (sourceSize > 1) {
1580 std::vector<unsigned> swiz;
1582 arg = createRvalueSwizzle(scalarTypeId, arg, swiz);
1585 if (numTargetComponents > 1)
1586 constituents.push_back(arg);
1592 if (targetComponent >= numTargetComponents)
1596 if (constituents.size() > 0)
1597 result = createCompositeConstruct(resultTypeId, constituents);
1599 setPrecision(result, precision);
1604 // Comments in header
1605 Id Builder::createMatrixConstructor(Decoration precision, const std::vector<Id>& sources, Id resultTypeId)
1607 Id componentTypeId = getScalarTypeId(resultTypeId);
1608 int numCols = getTypeNumColumns(resultTypeId);
1609 int numRows = getTypeNumRows(resultTypeId);
1611 // Will use a two step process
1612 // 1. make a compile-time 2D array of values
1613 // 2. construct a matrix from that array
1617 // initialize the array to the identity matrix
1618 Id ids[maxMatrixSize][maxMatrixSize];
1619 Id one = makeFloatConstant(1.0);
1620 Id zero = makeFloatConstant(0.0);
1621 for (int col = 0; col < 4; ++col) {
1622 for (int row = 0; row < 4; ++row) {
1624 ids[col][row] = one;
1626 ids[col][row] = zero;
1630 // modify components as dictated by the arguments
1631 if (sources.size() == 1 && isScalar(sources[0])) {
1632 // a single scalar; resets the diagonals
1633 for (int col = 0; col < 4; ++col)
1634 ids[col][col] = sources[0];
1635 } else if (isMatrix(sources[0])) {
1636 // constructing from another matrix; copy over the parts that exist in both the argument and constructee
1637 Id matrix = sources[0];
1638 int minCols = std::min(numCols, getNumColumns(matrix));
1639 int minRows = std::min(numRows, getNumRows(matrix));
1640 for (int col = 0; col < minCols; ++col) {
1641 std::vector<unsigned> indexes;
1642 indexes.push_back(col);
1643 for (int row = 0; row < minRows; ++row) {
1644 indexes.push_back(row);
1645 ids[col][row] = createCompositeExtract(matrix, componentTypeId, indexes);
1647 setPrecision(ids[col][row], precision);
1651 // fill in the matrix in column-major order with whatever argument components are available
1655 for (int arg = 0; arg < (int)sources.size(); ++arg) {
1656 Id argComp = sources[arg];
1657 for (int comp = 0; comp < getNumComponents(sources[arg]); ++comp) {
1658 if (getNumComponents(sources[arg]) > 1) {
1659 argComp = createCompositeExtract(sources[arg], componentTypeId, comp);
1660 setPrecision(argComp, precision);
1662 ids[col][row++] = argComp;
1663 if (row == numRows) {
1672 // Step 2: Construct a matrix from that array.
1673 // First make the column vectors, then make the matrix.
1675 // make the column vectors
1676 Id columnTypeId = getContainedTypeId(resultTypeId);
1677 std::vector<Id> matrixColumns;
1678 for (int col = 0; col < numCols; ++col) {
1679 std::vector<Id> vectorComponents;
1680 for (int row = 0; row < numRows; ++row)
1681 vectorComponents.push_back(ids[col][row]);
1682 matrixColumns.push_back(createCompositeConstruct(columnTypeId, vectorComponents));
1686 return createCompositeConstruct(resultTypeId, matrixColumns);
1689 // Comments in header
1690 Builder::If::If(Id cond, Builder& gb) :
1695 function = &builder.getBuildPoint()->getParent();
1697 // make the blocks, but only put the then-block into the function,
1698 // the else-block and merge-block will be added later, in order, after
1699 // earlier code is emitted
1700 thenBlock = new Block(builder.getUniqueId(), *function);
1701 mergeBlock = new Block(builder.getUniqueId(), *function);
1703 // Save the current block, so that we can add in the flow control split when
1704 // makeEndIf is called.
1705 headerBlock = builder.getBuildPoint();
1707 function->addBlock(thenBlock);
1708 builder.setBuildPoint(thenBlock);
1711 // Comments in header
1712 void Builder::If::makeBeginElse()
1714 // Close out the "then" by having it jump to the mergeBlock
1715 builder.createBranch(mergeBlock);
1717 // Make the first else block and add it to the function
1718 elseBlock = new Block(builder.getUniqueId(), *function);
1719 function->addBlock(elseBlock);
1721 // Start building the else block
1722 builder.setBuildPoint(elseBlock);
1725 // Comments in header
1726 void Builder::If::makeEndIf()
1728 // jump to the merge block
1729 builder.createBranch(mergeBlock);
1731 // Go back to the headerBlock and make the flow control split
1732 builder.setBuildPoint(headerBlock);
1733 builder.createSelectionMerge(mergeBlock, SelectionControlMaskNone);
1735 builder.createConditionalBranch(condition, thenBlock, elseBlock);
1737 builder.createConditionalBranch(condition, thenBlock, mergeBlock);
1739 // add the merge block to the function
1740 function->addBlock(mergeBlock);
1741 builder.setBuildPoint(mergeBlock);
1744 // Comments in header
1745 void Builder::makeSwitch(Id selector, int numSegments, std::vector<int>& caseValues, std::vector<int>& valueIndexToSegment, int defaultSegment,
1746 std::vector<Block*>& segmentBlocks)
1748 Function& function = buildPoint->getParent();
1750 // make all the blocks
1751 for (int s = 0; s < numSegments; ++s)
1752 segmentBlocks.push_back(new Block(getUniqueId(), function));
1754 Block* mergeBlock = new Block(getUniqueId(), function);
1756 // make and insert the switch's selection-merge instruction
1757 createSelectionMerge(mergeBlock, SelectionControlMaskNone);
1759 // make the switch instruction
1760 Instruction* switchInst = new Instruction(NoResult, NoType, OpSwitch);
1761 switchInst->addIdOperand(selector);
1762 switchInst->addIdOperand(defaultSegment >= 0 ? segmentBlocks[defaultSegment]->getId() : mergeBlock->getId());
1763 for (int i = 0; i < (int)caseValues.size(); ++i) {
1764 switchInst->addImmediateOperand(caseValues[i]);
1765 switchInst->addIdOperand(segmentBlocks[valueIndexToSegment[i]]->getId());
1767 buildPoint->addInstruction(std::unique_ptr<Instruction>(switchInst));
1769 // push the merge block
1770 switchMerges.push(mergeBlock);
1773 // Comments in header
1774 void Builder::addSwitchBreak()
1776 // branch to the top of the merge block stack
1777 createBranch(switchMerges.top());
1778 createAndSetNoPredecessorBlock("post-switch-break");
1781 // Comments in header
1782 void Builder::nextSwitchSegment(std::vector<Block*>& segmentBlock, int nextSegment)
1784 int lastSegment = nextSegment - 1;
1785 if (lastSegment >= 0) {
1786 // Close out previous segment by jumping, if necessary, to next segment
1787 if (! buildPoint->isTerminated())
1788 createBranch(segmentBlock[nextSegment]);
1790 Block* block = segmentBlock[nextSegment];
1791 block->getParent().addBlock(block);
1792 setBuildPoint(block);
1795 // Comments in header
1796 void Builder::endSwitch(std::vector<Block*>& /*segmentBlock*/)
1798 // Close out previous segment by jumping, if necessary, to next segment
1799 if (! buildPoint->isTerminated())
1802 switchMerges.top()->getParent().addBlock(switchMerges.top());
1803 setBuildPoint(switchMerges.top());
1808 // Comments in header
1809 void Builder::makeNewLoop(bool loopTestFirst)
1811 loops.push(Loop(*this, loopTestFirst));
1812 const Loop& loop = loops.top();
1814 // The loop test is always emitted before the loop body.
1815 // But if the loop test executes at the bottom of the loop, then
1816 // execute the test only on the second and subsequent iterations.
1818 // Remember the block that branches to the loop header. This
1819 // is required for the test-after-body case.
1820 Block* preheader = getBuildPoint();
1822 // Branch into the loop
1823 createBranch(loop.header);
1825 // Set ourselves inside the loop
1826 loop.function->addBlock(loop.header);
1827 setBuildPoint(loop.header);
1829 if (!loopTestFirst) {
1830 // Generate code to defer the loop test until the second and
1831 // subsequent iterations.
1833 // It's always the first iteration when coming from the preheader.
1834 // All other branches to this loop header will need to indicate "false",
1835 // but we don't yet know where they will come from.
1836 loop.isFirstIteration->addIdOperand(makeBoolConstant(true));
1837 loop.isFirstIteration->addIdOperand(preheader->getId());
1838 getBuildPoint()->addInstruction(std::unique_ptr<Instruction>(loop.isFirstIteration));
1840 // Mark the end of the structured loop. This must exist in the loop header block.
1841 createLoopMerge(loop.merge, loop.header, LoopControlMaskNone);
1843 // Generate code to see if this is the first iteration of the loop.
1844 // It needs to be in its own block, since the loop merge and
1845 // the selection merge instructions can't both be in the same
1847 Block* firstIterationCheck = new Block(getUniqueId(), *loop.function);
1848 createBranch(firstIterationCheck);
1849 loop.function->addBlock(firstIterationCheck);
1850 setBuildPoint(firstIterationCheck);
1852 // Control flow after this "if" normally reconverges at the loop body.
1853 // However, the loop test has a "break branch" out of this selection
1854 // construct because it can transfer control to the loop merge block.
1855 createSelectionMerge(loop.body, SelectionControlMaskNone);
1857 Block* loopTest = new Block(getUniqueId(), *loop.function);
1858 createConditionalBranch(loop.isFirstIteration->getResultId(), loop.body, loopTest);
1860 loop.function->addBlock(loopTest);
1861 setBuildPoint(loopTest);
1865 void Builder::createLoopTestBranch(Id condition)
1867 const Loop& loop = loops.top();
1869 // Generate the merge instruction. If the loop test executes before
1870 // the body, then this is a loop merge. Otherwise the loop merge
1871 // has already been generated and this is a conditional merge.
1872 if (loop.testFirst) {
1873 createLoopMerge(loop.merge, loop.header, LoopControlMaskNone);
1874 // Branching to the "body" block will keep control inside
1876 createConditionalBranch(condition, loop.body, loop.merge);
1877 loop.function->addBlock(loop.body);
1878 setBuildPoint(loop.body);
1880 // The branch to the loop merge block is the allowed exception
1881 // to the structured control flow. Otherwise, control flow will
1882 // continue to loop.body block. Since that is already the target
1883 // of a merge instruction, and a block can't be the target of more
1884 // than one merge instruction, we need to make an intermediate block.
1885 Block* stayInLoopBlock = new Block(getUniqueId(), *loop.function);
1886 createSelectionMerge(stayInLoopBlock, SelectionControlMaskNone);
1888 // This is the loop test.
1889 createConditionalBranch(condition, stayInLoopBlock, loop.merge);
1891 // The dummy block just branches to the real loop body.
1892 loop.function->addBlock(stayInLoopBlock);
1893 setBuildPoint(stayInLoopBlock);
1894 createBranchToBody();
1898 void Builder::createBranchToBody()
1900 const Loop& loop = loops.top();
1903 // This is a reconvergence of control flow, so no merge instruction
1905 createBranch(loop.body);
1906 loop.function->addBlock(loop.body);
1907 setBuildPoint(loop.body);
1910 void Builder::createLoopContinue()
1912 createBranchToLoopHeaderFromInside(loops.top());
1913 // Set up a block for dead code.
1914 createAndSetNoPredecessorBlock("post-loop-continue");
1917 // Add an exit (e.g. "break") for the innermost loop that you're in
1918 void Builder::createLoopExit()
1920 createBranch(loops.top().merge);
1921 // Set up a block for dead code.
1922 createAndSetNoPredecessorBlock("post-loop-break");
1925 // Close the innermost loop
1926 void Builder::closeLoop()
1928 const Loop& loop = loops.top();
1930 // Branch back to the top
1931 createBranchToLoopHeaderFromInside(loop);
1933 // Add the merge block and set the build point to it
1934 loop.function->addBlock(loop.merge);
1935 setBuildPoint(loop.merge);
1940 // Create a branch to the header of the given loop, from inside
1942 // Adjusts the phi node for the first-iteration value if needeed.
1943 void Builder::createBranchToLoopHeaderFromInside(const Loop& loop)
1945 createBranch(loop.header);
1946 if (loop.isFirstIteration) {
1947 loop.isFirstIteration->addIdOperand(makeBoolConstant(false));
1948 loop.isFirstIteration->addIdOperand(getBuildPoint()->getId());
1952 void Builder::clearAccessChain()
1954 accessChain.base = NoResult;
1955 accessChain.indexChain.clear();
1956 accessChain.instr = NoResult;
1957 accessChain.swizzle.clear();
1958 accessChain.component = NoResult;
1959 accessChain.preSwizzleBaseType = NoType;
1960 accessChain.isRValue = false;
1963 // Comments in header
1964 void Builder::accessChainPushSwizzle(std::vector<unsigned>& swizzle, Id preSwizzleBaseType)
1966 // swizzles can be stacked in GLSL, but simplified to a single
1967 // one here; the base type doesn't change
1968 if (accessChain.preSwizzleBaseType == NoType)
1969 accessChain.preSwizzleBaseType = preSwizzleBaseType;
1971 // if needed, propagate the swizzle for the current access chain
1972 if (accessChain.swizzle.size()) {
1973 std::vector<unsigned> oldSwizzle = accessChain.swizzle;
1974 accessChain.swizzle.resize(0);
1975 for (unsigned int i = 0; i < swizzle.size(); ++i) {
1976 accessChain.swizzle.push_back(oldSwizzle[swizzle[i]]);
1979 accessChain.swizzle = swizzle;
1981 // determine if we need to track this swizzle anymore
1982 simplifyAccessChainSwizzle();
1985 // Comments in header
1986 void Builder::accessChainStore(Id rvalue)
1988 assert(accessChain.isRValue == false);
1990 transferAccessChainSwizzle(true);
1991 Id base = collapseAccessChain();
1993 if (accessChain.swizzle.size() && accessChain.component != NoResult)
1994 MissingFunctionality("simultaneous l-value swizzle and dynamic component selection");
1996 // If swizzle still exists, it is out-of-order or not full, we must load the target vector,
1997 // extract and insert elements to perform writeMask and/or swizzle.
1998 Id source = NoResult;
1999 if (accessChain.swizzle.size()) {
2000 Id tempBaseId = createLoad(base);
2001 source = createLvalueSwizzle(getTypeId(tempBaseId), tempBaseId, rvalue, accessChain.swizzle);
2004 // dynamic component selection
2005 if (accessChain.component != NoResult) {
2006 Id tempBaseId = (source == NoResult) ? createLoad(base) : source;
2007 source = createVectorInsertDynamic(tempBaseId, getTypeId(tempBaseId), rvalue, accessChain.component);
2010 if (source == NoResult)
2013 createStore(source, base);
2016 // Comments in header
2017 Id Builder::accessChainLoad(Id resultType)
2021 if (accessChain.isRValue) {
2022 // transfer access chain, but keep it static, so we can stay in registers
2023 transferAccessChainSwizzle(false);
2024 if (accessChain.indexChain.size() > 0) {
2025 Id swizzleBase = accessChain.preSwizzleBaseType != NoType ? accessChain.preSwizzleBaseType : resultType;
2027 // if all the accesses are constants, we can use OpCompositeExtract
2028 std::vector<unsigned> indexes;
2029 bool constant = true;
2030 for (int i = 0; i < (int)accessChain.indexChain.size(); ++i) {
2031 if (isConstantScalar(accessChain.indexChain[i]))
2032 indexes.push_back(getConstantScalar(accessChain.indexChain[i]));
2040 id = createCompositeExtract(accessChain.base, swizzleBase, indexes);
2042 // make a new function variable for this r-value
2043 Id lValue = createVariable(StorageClassFunction, getTypeId(accessChain.base), "indexable");
2046 createStore(accessChain.base, lValue);
2048 // move base to the new variable
2049 accessChain.base = lValue;
2050 accessChain.isRValue = false;
2052 // load through the access chain
2053 id = createLoad(collapseAccessChain());
2056 id = accessChain.base;
2058 transferAccessChainSwizzle(true);
2059 // load through the access chain
2060 id = createLoad(collapseAccessChain());
2063 // Done, unless there are swizzles to do
2064 if (accessChain.swizzle.size() == 0 && accessChain.component == NoResult)
2067 // Do remaining swizzling
2068 // First, static swizzling
2069 if (accessChain.swizzle.size()) {
2071 Id swizzledType = getScalarTypeId(getTypeId(id));
2072 if (accessChain.swizzle.size() > 1)
2073 swizzledType = makeVectorType(swizzledType, (int)accessChain.swizzle.size());
2074 id = createRvalueSwizzle(swizzledType, id, accessChain.swizzle);
2077 // dynamic single-component selection
2078 if (accessChain.component != NoResult)
2079 id = createVectorExtractDynamic(id, resultType, accessChain.component);
2084 Id Builder::accessChainGetLValue()
2086 assert(accessChain.isRValue == false);
2088 transferAccessChainSwizzle(true);
2089 Id lvalue = collapseAccessChain();
2091 // If swizzle exists, it is out-of-order or not full, we must load the target vector,
2092 // extract and insert elements to perform writeMask and/or swizzle. This does not
2093 // go with getting a direct l-value pointer.
2094 assert(accessChain.swizzle.size() == 0);
2095 assert(accessChain.component == NoResult);
2100 void Builder::dump(std::vector<unsigned int>& out) const
2102 // Header, before first instructions:
2103 out.push_back(MagicNumber);
2104 out.push_back(Version);
2105 out.push_back(builderNumber);
2106 out.push_back(uniqueId + 1);
2110 for (auto cap : capabilities) {
2111 Instruction capInst(0, 0, OpCapability);
2112 capInst.addImmediateOperand(cap);
2116 // TBD: OpExtension ...
2118 dumpInstructions(out, imports);
2119 Instruction memInst(0, 0, OpMemoryModel);
2120 memInst.addImmediateOperand(addressModel);
2121 memInst.addImmediateOperand(memoryModel);
2124 // Instructions saved up while building:
2125 dumpInstructions(out, entryPoints);
2126 dumpInstructions(out, executionModes);
2128 // Debug instructions
2129 if (source != SourceLanguageUnknown) {
2130 Instruction sourceInst(0, 0, OpSource);
2131 sourceInst.addImmediateOperand(source);
2132 sourceInst.addImmediateOperand(sourceVersion);
2133 sourceInst.dump(out);
2135 for (int e = 0; e < (int)extensions.size(); ++e) {
2136 Instruction extInst(0, 0, OpSourceExtension);
2137 extInst.addStringOperand(extensions[e]);
2140 dumpInstructions(out, names);
2141 dumpInstructions(out, lines);
2143 // Annotation instructions
2144 dumpInstructions(out, decorations);
2146 dumpInstructions(out, constantsTypesGlobals);
2147 dumpInstructions(out, externals);
2154 // Protected methods.
2157 // Turn the described access chain in 'accessChain' into an instruction
2158 // computing its address. This *cannot* include complex swizzles, which must
2159 // be handled after this is called, but it does include swizzles that select
2160 // an individual element, as a single address of a scalar type can be
2161 // computed by an OpAccessChain instruction.
2162 Id Builder::collapseAccessChain()
2164 assert(accessChain.isRValue == false);
2166 if (accessChain.indexChain.size() > 0) {
2167 if (accessChain.instr == 0) {
2168 StorageClass storageClass = (StorageClass)module.getStorageClass(getTypeId(accessChain.base));
2169 accessChain.instr = createAccessChain(storageClass, accessChain.base, accessChain.indexChain);
2172 return accessChain.instr;
2174 return accessChain.base;
2176 // note that non-trivial swizzling is left pending...
2179 // clear out swizzle if it is redundant, that is reselecting the same components
2180 // that would be present without the swizzle.
2181 void Builder::simplifyAccessChainSwizzle()
2183 // If the swizzle has fewer components than the vector, it is subsetting, and must stay
2184 // to preserve that fact.
2185 if (getNumTypeComponents(accessChain.preSwizzleBaseType) > (int)accessChain.swizzle.size())
2188 // if components are out of order, it is a swizzle
2189 for (unsigned int i = 0; i < accessChain.swizzle.size(); ++i) {
2190 if (i != accessChain.swizzle[i])
2194 // otherwise, there is no need to track this swizzle
2195 accessChain.swizzle.clear();
2196 if (accessChain.component == NoResult)
2197 accessChain.preSwizzleBaseType = NoType;
2200 // To the extent any swizzling can become part of the chain
2201 // of accesses instead of a post operation, make it so.
2202 // If 'dynamic' is true, include transfering a non-static component index,
2203 // otherwise, only transfer static indexes.
2205 // Also, Boolean vectors are likely to be special. While
2206 // for external storage, they should only be integer types,
2207 // function-local bool vectors could use sub-word indexing,
2208 // so keep that as a separate Insert/Extract on a loaded vector.
2209 void Builder::transferAccessChainSwizzle(bool dynamic)
2212 if (accessChain.swizzle.size() > 1)
2216 if (accessChain.swizzle.size() == 0 && accessChain.component == NoResult)
2219 // single component...
2221 // skip doing it for Boolean vectors
2222 if (isBoolType(getContainedTypeId(accessChain.preSwizzleBaseType)))
2225 if (accessChain.swizzle.size() == 1) {
2226 // handle static component
2227 accessChain.indexChain.push_back(makeUintConstant(accessChain.swizzle.front()));
2228 accessChain.swizzle.clear();
2229 // note, the only valid remaining dynamic access would be to this one
2230 // component, so don't bother even looking at accessChain.component
2231 accessChain.preSwizzleBaseType = NoType;
2232 accessChain.component = NoResult;
2233 } else if (dynamic && accessChain.component != NoResult) {
2234 // handle dynamic component
2235 accessChain.indexChain.push_back(accessChain.component);
2236 accessChain.preSwizzleBaseType = NoType;
2237 accessChain.component = NoResult;
2241 // Utility method for creating a new block and setting the insert point to
2242 // be in it. This is useful for flow-control operations that need a "dummy"
2243 // block proceeding them (e.g. instructions after a discard, etc).
2244 void Builder::createAndSetNoPredecessorBlock(const char* /*name*/)
2246 Block* block = new Block(getUniqueId(), buildPoint->getParent());
2247 block->setUnreachable();
2248 buildPoint->getParent().addBlock(block);
2249 setBuildPoint(block);
2252 // addName(block->getId(), name);
2255 // Comments in header
2256 void Builder::createBranch(Block* block)
2258 Instruction* branch = new Instruction(OpBranch);
2259 branch->addIdOperand(block->getId());
2260 buildPoint->addInstruction(std::unique_ptr<Instruction>(branch));
2261 block->addPredecessor(buildPoint);
2264 void Builder::createSelectionMerge(Block* mergeBlock, unsigned int control)
2266 Instruction* merge = new Instruction(OpSelectionMerge);
2267 merge->addIdOperand(mergeBlock->getId());
2268 merge->addImmediateOperand(control);
2269 buildPoint->addInstruction(std::unique_ptr<Instruction>(merge));
2272 void Builder::createLoopMerge(Block* mergeBlock, Block* continueBlock, unsigned int control)
2274 Instruction* merge = new Instruction(OpLoopMerge);
2275 merge->addIdOperand(mergeBlock->getId());
2276 merge->addIdOperand(continueBlock->getId());
2277 merge->addImmediateOperand(control);
2278 buildPoint->addInstruction(std::unique_ptr<Instruction>(merge));
2281 void Builder::createConditionalBranch(Id condition, Block* thenBlock, Block* elseBlock)
2283 Instruction* branch = new Instruction(OpBranchConditional);
2284 branch->addIdOperand(condition);
2285 branch->addIdOperand(thenBlock->getId());
2286 branch->addIdOperand(elseBlock->getId());
2287 buildPoint->addInstruction(std::unique_ptr<Instruction>(branch));
2288 thenBlock->addPredecessor(buildPoint);
2289 elseBlock->addPredecessor(buildPoint);
2292 void Builder::dumpInstructions(std::vector<unsigned int>& out, const std::vector<std::unique_ptr<Instruction> >& instructions) const
2294 for (int i = 0; i < (int)instructions.size(); ++i) {
2295 instructions[i]->dump(out);
2299 void TbdFunctionality(const char* tbd)
2301 static std::unordered_set<const char*> issued;
2303 if (issued.find(tbd) == issued.end()) {
2304 printf("TBD functionality: %s\n", tbd);
2309 void MissingFunctionality(const char* fun)
2311 printf("Missing functionality: %s\n", fun);
2314 Builder::Loop::Loop(Builder& builder, bool testFirstArg)
2315 : function(&builder.getBuildPoint()->getParent()),
2316 header(new Block(builder.getUniqueId(), *function)),
2317 merge(new Block(builder.getUniqueId(), *function)),
2318 body(new Block(builder.getUniqueId(), *function)),
2319 testFirst(testFirstArg),
2320 isFirstIteration(nullptr)
2324 // You may be tempted to rewrite this as
2325 // new Instruction(builder.getUniqueId(), builder.makeBoolType(), OpPhi);
2326 // This will cause subtle test failures because builder.getUniqueId(),
2327 // and builder.makeBoolType() can then get run in a compiler-specific
2328 // order making tests fail for certain configurations.
2329 Id instructionId = builder.getUniqueId();
2330 isFirstIteration = new Instruction(instructionId, builder.makeBoolType(), OpPhi);
2334 }; // end spv namespace