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