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