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