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