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