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