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