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