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