Add Vulkan 1.4 target and client
[glslang.git] / SPIRV / SpvBuilder.h
blob44377acb2b0be67ff1d24112b7315c0ec4e26da6
1 //
2 // Copyright (C) 2014-2015 LunarG, Inc.
3 // Copyright (C) 2015-2020 Google, Inc.
4 // Copyright (C) 2017 ARM Limited.
5 // Modifications Copyright (C) 2020 Advanced Micro Devices, Inc. All rights reserved.
6 //
7 // All rights reserved.
8 //
9 // Redistribution and use in source and binary forms, with or without
10 // modification, are permitted provided that the following conditions
11 // are met:
13 // Redistributions of source code must retain the above copyright
14 // notice, this list of conditions and the following disclaimer.
16 // Redistributions in binary form must reproduce the above
17 // copyright notice, this list of conditions and the following
18 // disclaimer in the documentation and/or other materials provided
19 // with the distribution.
21 // Neither the name of 3Dlabs Inc. Ltd. nor the names of its
22 // contributors may be used to endorse or promote products derived
23 // from this software without specific prior written permission.
25 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
26 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
27 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
28 // FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
29 // COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
30 // INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
31 // BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
32 // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
33 // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
34 // LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
35 // ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
36 // POSSIBILITY OF SUCH DAMAGE.
39 // "Builder" is an interface to fully build SPIR-V IR. Allocate one of
40 // these to build (a thread safe) internal SPIR-V representation (IR),
41 // and then dump it as a binary stream according to the SPIR-V specification.
43 // A Builder has a 1:1 relationship with a SPIR-V module.
46 #pragma once
47 #ifndef SpvBuilder_H
48 #define SpvBuilder_H
50 #include "Logger.h"
51 #define SPV_ENABLE_UTILITY_CODE
52 #include "spirv.hpp"
53 #include "spvIR.h"
54 namespace spv {
55 #include "GLSL.ext.KHR.h"
56 #include "NonSemanticShaderDebugInfo100.h"
59 #include <algorithm>
60 #include <cstdint>
61 #include <map>
62 #include <memory>
63 #include <set>
64 #include <sstream>
65 #include <stack>
66 #include <unordered_map>
67 #include <map>
69 namespace spv {
71 typedef enum {
72 Spv_1_0 = (1 << 16),
73 Spv_1_1 = (1 << 16) | (1 << 8),
74 Spv_1_2 = (1 << 16) | (2 << 8),
75 Spv_1_3 = (1 << 16) | (3 << 8),
76 Spv_1_4 = (1 << 16) | (4 << 8),
77 Spv_1_5 = (1 << 16) | (5 << 8),
78 } SpvVersion;
80 class Builder {
81 public:
82 Builder(unsigned int spvVersion, unsigned int userNumber, SpvBuildLogger* logger);
83 virtual ~Builder();
85 static const int maxMatrixSize = 4;
87 unsigned int getSpvVersion() const { return spvVersion; }
89 void setSource(spv::SourceLanguage lang, int version)
91 sourceLang = lang;
92 sourceVersion = version;
94 spv::Id getStringId(const std::string& str)
96 auto sItr = stringIds.find(str);
97 if (sItr != stringIds.end())
98 return sItr->second;
99 spv::Id strId = getUniqueId();
100 Instruction* fileString = new Instruction(strId, NoType, OpString);
101 const char* file_c_str = str.c_str();
102 fileString->addStringOperand(file_c_str);
103 strings.push_back(std::unique_ptr<Instruction>(fileString));
104 module.mapInstruction(fileString);
105 stringIds[file_c_str] = strId;
106 return strId;
109 spv::Id getMainFileId() const { return mainFileId; }
111 // Initialize the main source file name
112 void setDebugMainSourceFile(const std::string& file)
114 if (trackDebugInfo) {
115 dirtyLineTracker = true;
116 mainFileId = getStringId(file);
117 currentFileId = mainFileId;
121 // Set the debug source location tracker in the builder.
122 // The upcoming instructions in basic blocks will be associated to this location.
123 void setDebugSourceLocation(int line, const char* filename)
125 if (trackDebugInfo) {
126 dirtyLineTracker = true;
127 if (line != 0) {
128 // TODO: This is special handling of some AST nodes having (untracked) line 0.
129 // But they should have a valid line number.
130 currentLine = line;
131 if (filename) {
132 currentFileId = getStringId(filename);
138 void setSourceText(const std::string& text) { sourceText = text; }
139 void addSourceExtension(const char* ext) { sourceExtensions.push_back(ext); }
140 void addModuleProcessed(const std::string& p) { moduleProcesses.push_back(p.c_str()); }
141 void setEmitSpirvDebugInfo()
143 trackDebugInfo = true;
144 emitSpirvDebugInfo = true;
146 void setEmitNonSemanticShaderDebugInfo(bool emitSourceText)
148 trackDebugInfo = true;
149 emitNonSemanticShaderDebugInfo = true;
150 importNonSemanticShaderDebugInfoInstructions();
152 if (emitSourceText) {
153 emitNonSemanticShaderDebugSource = emitSourceText;
156 void addExtension(const char* ext) { extensions.insert(ext); }
157 void removeExtension(const char* ext)
159 extensions.erase(ext);
161 void addIncorporatedExtension(const char* ext, SpvVersion incorporatedVersion)
163 if (getSpvVersion() < static_cast<unsigned>(incorporatedVersion))
164 addExtension(ext);
166 void promoteIncorporatedExtension(const char* baseExt, const char* promoExt, SpvVersion incorporatedVersion)
168 removeExtension(baseExt);
169 addIncorporatedExtension(promoExt, incorporatedVersion);
171 void addInclude(const std::string& name, const std::string& text)
173 spv::Id incId = getStringId(name);
174 includeFiles[incId] = &text;
176 Id import(const char*);
177 void setMemoryModel(spv::AddressingModel addr, spv::MemoryModel mem)
179 addressModel = addr;
180 memoryModel = mem;
183 void addCapability(spv::Capability cap) { capabilities.insert(cap); }
185 // To get a new <id> for anything needing a new one.
186 Id getUniqueId() { return ++uniqueId; }
188 // To get a set of new <id>s, e.g., for a set of function parameters
189 Id getUniqueIds(int numIds)
191 Id id = uniqueId + 1;
192 uniqueId += numIds;
193 return id;
196 // For creating new types (will return old type if the requested one was already made).
197 Id makeVoidType();
198 Id makeBoolType();
199 Id makePointer(StorageClass, Id pointee);
200 Id makeForwardPointer(StorageClass);
201 Id makePointerFromForwardPointer(StorageClass, Id forwardPointerType, Id pointee);
202 Id makeIntegerType(int width, bool hasSign); // generic
203 Id makeIntType(int width) { return makeIntegerType(width, true); }
204 Id makeUintType(int width) { return makeIntegerType(width, false); }
205 Id makeFloatType(int width);
206 Id makeStructType(const std::vector<Id>& members, const char* name, bool const compilerGenerated = true);
207 Id makeStructResultType(Id type0, Id type1);
208 Id makeVectorType(Id component, int size);
209 Id makeMatrixType(Id component, int cols, int rows);
210 Id makeArrayType(Id element, Id sizeId, int stride); // 0 stride means no stride decoration
211 Id makeRuntimeArray(Id element);
212 Id makeFunctionType(Id returnType, const std::vector<Id>& paramTypes);
213 Id makeImageType(Id sampledType, Dim, bool depth, bool arrayed, bool ms, unsigned sampled, ImageFormat format);
214 Id makeSamplerType();
215 Id makeSampledImageType(Id imageType);
216 Id makeCooperativeMatrixTypeKHR(Id component, Id scope, Id rows, Id cols, Id use);
217 Id makeCooperativeMatrixTypeNV(Id component, Id scope, Id rows, Id cols);
218 Id makeCooperativeMatrixTypeWithSameShape(Id component, Id otherType);
219 Id makeGenericType(spv::Op opcode, std::vector<spv::IdImmediate>& operands);
221 // SPIR-V NonSemantic Shader DebugInfo Instructions
222 struct DebugTypeLoc {
223 std::string name {};
224 int line {0};
225 int column {0};
227 std::unordered_map<Id, DebugTypeLoc> debugTypeLocs;
228 Id makeDebugInfoNone();
229 Id makeBoolDebugType(int const size);
230 Id makeIntegerDebugType(int const width, bool const hasSign);
231 Id makeFloatDebugType(int const width);
232 Id makeSequentialDebugType(Id const baseType, Id const componentCount, NonSemanticShaderDebugInfo100Instructions const sequenceType);
233 Id makeArrayDebugType(Id const baseType, Id const componentCount);
234 Id makeVectorDebugType(Id const baseType, int const componentCount);
235 Id makeMatrixDebugType(Id const vectorType, int const vectorCount, bool columnMajor = true);
236 Id makeMemberDebugType(Id const memberType, DebugTypeLoc const& debugTypeLoc);
237 Id makeCompositeDebugType(std::vector<Id> const& memberTypes, char const*const name,
238 NonSemanticShaderDebugInfo100DebugCompositeType const tag, bool const isOpaqueType = false);
239 Id makePointerDebugType(StorageClass storageClass, Id const baseType);
240 Id makeForwardPointerDebugType(StorageClass storageClass);
241 Id makeDebugSource(const Id fileName);
242 Id makeDebugCompilationUnit();
243 Id createDebugGlobalVariable(Id const type, char const*const name, Id const variable);
244 Id createDebugLocalVariable(Id type, char const*const name, size_t const argNumber = 0);
245 Id makeDebugExpression();
246 Id makeDebugDeclare(Id const debugLocalVariable, Id const pointer);
247 Id makeDebugValue(Id const debugLocalVariable, Id const value);
248 Id makeDebugFunctionType(Id returnType, const std::vector<Id>& paramTypes);
249 Id makeDebugFunction(Function* function, Id nameId, Id funcTypeId);
250 Id makeDebugLexicalBlock(uint32_t line, uint32_t column);
251 std::string unmangleFunctionName(std::string const& name) const;
253 // Initialize non-semantic debug information for a function, including those of:
254 // - The function definition
255 // - The function parameters
256 void setupFunctionDebugInfo(Function* function, const char* name, const std::vector<Id>& paramTypes,
257 const std::vector<char const*>& paramNames);
259 // accelerationStructureNV type
260 Id makeAccelerationStructureType();
261 // rayQueryEXT type
262 Id makeRayQueryType();
263 // hitObjectNV type
264 Id makeHitObjectNVType();
266 // For querying about types.
267 Id getTypeId(Id resultId) const { return module.getTypeId(resultId); }
268 Id getDerefTypeId(Id resultId) const;
269 Op getOpCode(Id id) const { return module.getInstruction(id)->getOpCode(); }
270 Op getTypeClass(Id typeId) const { return getOpCode(typeId); }
271 Op getMostBasicTypeClass(Id typeId) const;
272 unsigned int getNumComponents(Id resultId) const { return getNumTypeComponents(getTypeId(resultId)); }
273 unsigned int getNumTypeConstituents(Id typeId) const;
274 unsigned int getNumTypeComponents(Id typeId) const { return getNumTypeConstituents(typeId); }
275 Id getScalarTypeId(Id typeId) const;
276 Id getContainedTypeId(Id typeId) const;
277 Id getContainedTypeId(Id typeId, int) const;
278 StorageClass getTypeStorageClass(Id typeId) const { return module.getStorageClass(typeId); }
279 ImageFormat getImageTypeFormat(Id typeId) const
280 { return (ImageFormat)module.getInstruction(typeId)->getImmediateOperand(6); }
281 Id getResultingAccessChainType() const;
282 Id getIdOperand(Id resultId, int idx) { return module.getInstruction(resultId)->getIdOperand(idx); }
284 bool isPointer(Id resultId) const { return isPointerType(getTypeId(resultId)); }
285 bool isScalar(Id resultId) const { return isScalarType(getTypeId(resultId)); }
286 bool isVector(Id resultId) const { return isVectorType(getTypeId(resultId)); }
287 bool isMatrix(Id resultId) const { return isMatrixType(getTypeId(resultId)); }
288 bool isCooperativeMatrix(Id resultId)const { return isCooperativeMatrixType(getTypeId(resultId)); }
289 bool isAggregate(Id resultId) const { return isAggregateType(getTypeId(resultId)); }
290 bool isSampledImage(Id resultId) const { return isSampledImageType(getTypeId(resultId)); }
291 bool isTensorView(Id resultId)const { return isTensorViewType(getTypeId(resultId)); }
293 bool isBoolType(Id typeId)
294 { return groupedTypes[OpTypeBool].size() > 0 && typeId == groupedTypes[OpTypeBool].back()->getResultId(); }
295 bool isIntType(Id typeId) const
296 { return getTypeClass(typeId) == OpTypeInt && module.getInstruction(typeId)->getImmediateOperand(1) != 0; }
297 bool isUintType(Id typeId) const
298 { return getTypeClass(typeId) == OpTypeInt && module.getInstruction(typeId)->getImmediateOperand(1) == 0; }
299 bool isFloatType(Id typeId) const { return getTypeClass(typeId) == OpTypeFloat; }
300 bool isPointerType(Id typeId) const { return getTypeClass(typeId) == OpTypePointer; }
301 bool isScalarType(Id typeId) const
302 { return getTypeClass(typeId) == OpTypeFloat || getTypeClass(typeId) == OpTypeInt ||
303 getTypeClass(typeId) == OpTypeBool; }
304 bool isVectorType(Id typeId) const { return getTypeClass(typeId) == OpTypeVector; }
305 bool isMatrixType(Id typeId) const { return getTypeClass(typeId) == OpTypeMatrix; }
306 bool isStructType(Id typeId) const { return getTypeClass(typeId) == OpTypeStruct; }
307 bool isArrayType(Id typeId) const { return getTypeClass(typeId) == OpTypeArray; }
308 bool isCooperativeMatrixType(Id typeId)const
310 return getTypeClass(typeId) == OpTypeCooperativeMatrixKHR || getTypeClass(typeId) == OpTypeCooperativeMatrixNV;
312 bool isTensorViewType(Id typeId) const { return getTypeClass(typeId) == OpTypeTensorViewNV; }
313 bool isAggregateType(Id typeId) const
314 { return isArrayType(typeId) || isStructType(typeId) || isCooperativeMatrixType(typeId); }
315 bool isImageType(Id typeId) const { return getTypeClass(typeId) == OpTypeImage; }
316 bool isSamplerType(Id typeId) const { return getTypeClass(typeId) == OpTypeSampler; }
317 bool isSampledImageType(Id typeId) const { return getTypeClass(typeId) == OpTypeSampledImage; }
318 bool containsType(Id typeId, Op typeOp, unsigned int width) const;
319 bool containsPhysicalStorageBufferOrArray(Id typeId) const;
321 bool isConstantOpCode(Op opcode) const;
322 bool isSpecConstantOpCode(Op opcode) const;
323 bool isConstant(Id resultId) const { return isConstantOpCode(getOpCode(resultId)); }
324 bool isConstantScalar(Id resultId) const { return getOpCode(resultId) == OpConstant; }
325 bool isSpecConstant(Id resultId) const { return isSpecConstantOpCode(getOpCode(resultId)); }
326 unsigned int getConstantScalar(Id resultId) const
327 { return module.getInstruction(resultId)->getImmediateOperand(0); }
328 StorageClass getStorageClass(Id resultId) const { return getTypeStorageClass(getTypeId(resultId)); }
330 bool isVariableOpCode(Op opcode) const { return opcode == OpVariable; }
331 bool isVariable(Id resultId) const { return isVariableOpCode(getOpCode(resultId)); }
332 bool isGlobalStorage(Id resultId) const { return getStorageClass(resultId) != StorageClassFunction; }
333 bool isGlobalVariable(Id resultId) const { return isVariable(resultId) && isGlobalStorage(resultId); }
334 // See if a resultId is valid for use as an initializer.
335 bool isValidInitializer(Id resultId) const { return isConstant(resultId) || isGlobalVariable(resultId); }
337 int getScalarTypeWidth(Id typeId) const
339 Id scalarTypeId = getScalarTypeId(typeId);
340 assert(getTypeClass(scalarTypeId) == OpTypeInt || getTypeClass(scalarTypeId) == OpTypeFloat);
341 return module.getInstruction(scalarTypeId)->getImmediateOperand(0);
344 unsigned int getTypeNumColumns(Id typeId) const
346 assert(isMatrixType(typeId));
347 return getNumTypeConstituents(typeId);
349 unsigned int getNumColumns(Id resultId) const { return getTypeNumColumns(getTypeId(resultId)); }
350 unsigned int getTypeNumRows(Id typeId) const
352 assert(isMatrixType(typeId));
353 return getNumTypeComponents(getContainedTypeId(typeId));
355 unsigned int getNumRows(Id resultId) const { return getTypeNumRows(getTypeId(resultId)); }
357 Dim getTypeDimensionality(Id typeId) const
359 assert(isImageType(typeId));
360 return (Dim)module.getInstruction(typeId)->getImmediateOperand(1);
362 Id getImageType(Id resultId) const
364 Id typeId = getTypeId(resultId);
365 assert(isImageType(typeId) || isSampledImageType(typeId));
366 return isSampledImageType(typeId) ? module.getInstruction(typeId)->getIdOperand(0) : typeId;
368 bool isArrayedImageType(Id typeId) const
370 assert(isImageType(typeId));
371 return module.getInstruction(typeId)->getImmediateOperand(3) != 0;
374 // For making new constants (will return old constant if the requested one was already made).
375 Id makeNullConstant(Id typeId);
376 Id makeBoolConstant(bool b, bool specConstant = false);
377 Id makeIntConstant(Id typeId, unsigned value, bool specConstant);
378 Id makeInt64Constant(Id typeId, unsigned long long value, bool specConstant);
379 Id makeInt8Constant(int i, bool specConstant = false)
380 { return makeIntConstant(makeIntType(8), (unsigned)i, specConstant); }
381 Id makeUint8Constant(unsigned u, bool specConstant = false)
382 { return makeIntConstant(makeUintType(8), u, specConstant); }
383 Id makeInt16Constant(int i, bool specConstant = false)
384 { return makeIntConstant(makeIntType(16), (unsigned)i, specConstant); }
385 Id makeUint16Constant(unsigned u, bool specConstant = false)
386 { return makeIntConstant(makeUintType(16), u, specConstant); }
387 Id makeIntConstant(int i, bool specConstant = false)
388 { return makeIntConstant(makeIntType(32), (unsigned)i, specConstant); }
389 Id makeUintConstant(unsigned u, bool specConstant = false)
390 { return makeIntConstant(makeUintType(32), u, specConstant); }
391 Id makeInt64Constant(long long i, bool specConstant = false)
392 { return makeInt64Constant(makeIntType(64), (unsigned long long)i, specConstant); }
393 Id makeUint64Constant(unsigned long long u, bool specConstant = false)
394 { return makeInt64Constant(makeUintType(64), u, specConstant); }
395 Id makeFloatConstant(float f, bool specConstant = false);
396 Id makeDoubleConstant(double d, bool specConstant = false);
397 Id makeFloat16Constant(float f16, bool specConstant = false);
398 Id makeFpConstant(Id type, double d, bool specConstant = false);
400 Id importNonSemanticShaderDebugInfoInstructions();
402 // Turn the array of constants into a proper spv constant of the requested type.
403 Id makeCompositeConstant(Id type, const std::vector<Id>& comps, bool specConst = false);
405 // Methods for adding information outside the CFG.
406 Instruction* addEntryPoint(ExecutionModel, Function*, const char* name);
407 void addExecutionMode(Function*, ExecutionMode mode, int value1 = -1, int value2 = -1, int value3 = -1);
408 void addExecutionMode(Function*, ExecutionMode mode, const std::vector<unsigned>& literals);
409 void addExecutionModeId(Function*, ExecutionMode mode, const std::vector<Id>& operandIds);
410 void addName(Id, const char* name);
411 void addMemberName(Id, int member, const char* name);
412 void addDecoration(Id, Decoration, int num = -1);
413 void addDecoration(Id, Decoration, const char*);
414 void addDecoration(Id, Decoration, const std::vector<unsigned>& literals);
415 void addDecoration(Id, Decoration, const std::vector<const char*>& strings);
416 void addLinkageDecoration(Id id, const char* name, spv::LinkageType linkType);
417 void addDecorationId(Id id, Decoration, Id idDecoration);
418 void addDecorationId(Id id, Decoration, const std::vector<Id>& operandIds);
419 void addMemberDecoration(Id, unsigned int member, Decoration, int num = -1);
420 void addMemberDecoration(Id, unsigned int member, Decoration, const char*);
421 void addMemberDecoration(Id, unsigned int member, Decoration, const std::vector<unsigned>& literals);
422 void addMemberDecoration(Id, unsigned int member, Decoration, const std::vector<const char*>& strings);
424 // At the end of what block do the next create*() instructions go?
425 // Also reset current last DebugScope and current source line to unknown
426 void setBuildPoint(Block* bp) {
427 buildPoint = bp;
428 dirtyLineTracker = true;
429 dirtyScopeTracker = true;
431 Block* getBuildPoint() const { return buildPoint; }
433 // Append an instruction to the end of the current build point.
434 // Optionally, additional debug info instructions may also be prepended.
435 void addInstruction(std::unique_ptr<Instruction> inst);
437 // Append an instruction to the end of the current build point without prepending any debug instructions.
438 // This is useful for insertion of some debug info instructions themselves or some control flow instructions
439 // that are attached to its predecessor instruction.
440 void addInstructionNoDebugInfo(std::unique_ptr<Instruction> inst);
442 // Make the entry-point function. The returned pointer is only valid
443 // for the lifetime of this builder.
444 Function* makeEntryPoint(const char*);
446 // Make a shader-style function, and create its entry block if entry is non-zero.
447 // Return the function, pass back the entry.
448 // The returned pointer is only valid for the lifetime of this builder.
449 Function* makeFunctionEntry(Decoration precision, Id returnType, const char* name, LinkageType linkType,
450 const std::vector<Id>& paramTypes,
451 const std::vector<std::vector<Decoration>>& precisions, Block** entry = nullptr);
453 // Create a return. An 'implicit' return is one not appearing in the source
454 // code. In the case of an implicit return, no post-return block is inserted.
455 void makeReturn(bool implicit, Id retVal = 0);
457 // Initialize state and generate instructions for new lexical scope
458 void enterLexicalBlock(uint32_t line, uint32_t column);
460 // Set state and generate instructions to exit current lexical scope
461 void leaveLexicalBlock();
463 // Prepare builder for generation of instructions for a function.
464 void enterFunction(Function const* function);
466 // Generate all the code needed to finish up a function.
467 void leaveFunction();
469 // Create block terminator instruction for certain statements like
470 // discard, terminate-invocation, terminateRayEXT, or ignoreIntersectionEXT
471 void makeStatementTerminator(spv::Op opcode, const char *name);
473 // Create block terminator instruction for statements that have input operands
474 // such as OpEmitMeshTasksEXT
475 void makeStatementTerminator(spv::Op opcode, const std::vector<Id>& operands, const char* name);
477 // Create a global or function local or IO variable.
478 Id createVariable(Decoration precision, StorageClass storageClass, Id type, const char* name = nullptr,
479 Id initializer = NoResult, bool const compilerGenerated = true);
481 // Create an intermediate with an undefined value.
482 Id createUndefined(Id type);
484 // Store into an Id and return the l-value
485 void createStore(Id rValue, Id lValue, spv::MemoryAccessMask memoryAccess = spv::MemoryAccessMaskNone,
486 spv::Scope scope = spv::ScopeMax, unsigned int alignment = 0);
488 // Load from an Id and return it
489 Id createLoad(Id lValue, spv::Decoration precision,
490 spv::MemoryAccessMask memoryAccess = spv::MemoryAccessMaskNone,
491 spv::Scope scope = spv::ScopeMax, unsigned int alignment = 0);
493 // Create an OpAccessChain instruction
494 Id createAccessChain(StorageClass, Id base, const std::vector<Id>& offsets);
496 // Create an OpArrayLength instruction
497 Id createArrayLength(Id base, unsigned int member);
499 // Create an OpCooperativeMatrixLengthKHR instruction
500 Id createCooperativeMatrixLengthKHR(Id type);
501 // Create an OpCooperativeMatrixLengthNV instruction
502 Id createCooperativeMatrixLengthNV(Id type);
504 // Create an OpCompositeExtract instruction
505 Id createCompositeExtract(Id composite, Id typeId, unsigned index);
506 Id createCompositeExtract(Id composite, Id typeId, const std::vector<unsigned>& indexes);
507 Id createCompositeInsert(Id object, Id composite, Id typeId, unsigned index);
508 Id createCompositeInsert(Id object, Id composite, Id typeId, const std::vector<unsigned>& indexes);
510 Id createVectorExtractDynamic(Id vector, Id typeId, Id componentIndex);
511 Id createVectorInsertDynamic(Id vector, Id typeId, Id component, Id componentIndex);
513 void createNoResultOp(Op);
514 void createNoResultOp(Op, Id operand);
515 void createNoResultOp(Op, const std::vector<Id>& operands);
516 void createNoResultOp(Op, const std::vector<IdImmediate>& operands);
517 void createControlBarrier(Scope execution, Scope memory, MemorySemanticsMask);
518 void createMemoryBarrier(unsigned executionScope, unsigned memorySemantics);
519 Id createUnaryOp(Op, Id typeId, Id operand);
520 Id createBinOp(Op, Id typeId, Id operand1, Id operand2);
521 Id createTriOp(Op, Id typeId, Id operand1, Id operand2, Id operand3);
522 Id createOp(Op, Id typeId, const std::vector<Id>& operands);
523 Id createOp(Op, Id typeId, const std::vector<IdImmediate>& operands);
524 Id createFunctionCall(spv::Function*, const std::vector<spv::Id>&);
525 Id createSpecConstantOp(Op, Id typeId, const std::vector<spv::Id>& operands, const std::vector<unsigned>& literals);
527 // Take an rvalue (source) and a set of channels to extract from it to
528 // make a new rvalue, which is returned.
529 Id createRvalueSwizzle(Decoration precision, Id typeId, Id source, const std::vector<unsigned>& channels);
531 // Take a copy of an lvalue (target) and a source of components, and set the
532 // source components into the lvalue where the 'channels' say to put them.
533 // An updated version of the target is returned.
534 // (No true lvalue or stores are used.)
535 Id createLvalueSwizzle(Id typeId, Id target, Id source, const std::vector<unsigned>& channels);
537 // If both the id and precision are valid, the id
538 // gets tagged with the requested precision.
539 // The passed in id is always the returned id, to simplify use patterns.
540 Id setPrecision(Id id, Decoration precision)
542 if (precision != NoPrecision && id != NoResult)
543 addDecoration(id, precision);
545 return id;
548 // Can smear a scalar to a vector for the following forms:
549 // - promoteScalar(scalar, vector) // smear scalar to width of vector
550 // - promoteScalar(vector, scalar) // smear scalar to width of vector
551 // - promoteScalar(pointer, scalar) // smear scalar to width of what pointer points to
552 // - promoteScalar(scalar, scalar) // do nothing
553 // Other forms are not allowed.
555 // Generally, the type of 'scalar' does not need to be the same type as the components in 'vector'.
556 // The type of the created vector is a vector of components of the same type as the scalar.
558 // Note: One of the arguments will change, with the result coming back that way rather than
559 // through the return value.
560 void promoteScalar(Decoration precision, Id& left, Id& right);
562 // Make a value by smearing the scalar to fill the type.
563 // vectorType should be the correct type for making a vector of scalarVal.
564 // (No conversions are done.)
565 Id smearScalar(Decoration precision, Id scalarVal, Id vectorType);
567 // Create a call to a built-in function.
568 Id createBuiltinCall(Id resultType, Id builtins, int entryPoint, const std::vector<Id>& args);
570 // List of parameters used to create a texture operation
571 struct TextureParameters {
572 Id sampler;
573 Id coords;
574 Id bias;
575 Id lod;
576 Id Dref;
577 Id offset;
578 Id offsets;
579 Id gradX;
580 Id gradY;
581 Id sample;
582 Id component;
583 Id texelOut;
584 Id lodClamp;
585 Id granularity;
586 Id coarse;
587 bool nonprivate;
588 bool volatil;
591 // Select the correct texture operation based on all inputs, and emit the correct instruction
592 Id createTextureCall(Decoration precision, Id resultType, bool sparse, bool fetch, bool proj, bool gather,
593 bool noImplicit, const TextureParameters&, ImageOperandsMask);
595 // Emit the OpTextureQuery* instruction that was passed in.
596 // Figure out the right return value and type, and return it.
597 Id createTextureQueryCall(Op, const TextureParameters&, bool isUnsignedResult);
599 Id createSamplePositionCall(Decoration precision, Id, Id);
601 Id createBitFieldExtractCall(Decoration precision, Id, Id, Id, bool isSigned);
602 Id createBitFieldInsertCall(Decoration precision, Id, Id, Id, Id);
604 // Reduction comparison for composites: For equal and not-equal resulting in a scalar.
605 Id createCompositeCompare(Decoration precision, Id, Id, bool /* true if for equal, false if for not-equal */);
607 // OpCompositeConstruct
608 Id createCompositeConstruct(Id typeId, const std::vector<Id>& constituents);
610 // vector or scalar constructor
611 Id createConstructor(Decoration precision, const std::vector<Id>& sources, Id resultTypeId);
613 // matrix constructor
614 Id createMatrixConstructor(Decoration precision, const std::vector<Id>& sources, Id constructee);
616 // coopmat conversion
617 Id createCooperativeMatrixConversion(Id typeId, Id source);
618 Id createCooperativeMatrixReduce(Op opcode, Id typeId, Id source, unsigned int mask, Id func);
619 Id createCooperativeMatrixPerElementOp(Id typeId, const std::vector<Id>& operands);
621 // Helper to use for building nested control flow with if-then-else.
622 class If {
623 public:
624 If(Id condition, unsigned int ctrl, Builder& builder);
625 ~If() {}
627 void makeBeginElse();
628 void makeEndIf();
630 private:
631 If(const If&);
632 If& operator=(If&);
634 Builder& builder;
635 Id condition;
636 unsigned int control;
637 Function* function;
638 Block* headerBlock;
639 Block* thenBlock;
640 Block* elseBlock;
641 Block* mergeBlock;
644 // Make a switch statement. A switch has 'numSegments' of pieces of code, not containing
645 // any case/default labels, all separated by one or more case/default labels. Each possible
646 // case value v is a jump to the caseValues[v] segment. The defaultSegment is also in this
647 // number space. How to compute the value is given by 'condition', as in switch(condition).
649 // The SPIR-V Builder will maintain the stack of post-switch merge blocks for nested switches.
651 // Use a defaultSegment < 0 if there is no default segment (to branch to post switch).
653 // Returns the right set of basic blocks to start each code segment with, so that the caller's
654 // recursion stack can hold the memory for it.
656 void makeSwitch(Id condition, unsigned int control, int numSegments, const std::vector<int>& caseValues,
657 const std::vector<int>& valueToSegment, int defaultSegment, std::vector<Block*>& segmentBB);
659 // Add a branch to the innermost switch's merge block.
660 void addSwitchBreak(bool implicit);
662 // Move to the next code segment, passing in the return argument in makeSwitch()
663 void nextSwitchSegment(std::vector<Block*>& segmentBB, int segment);
665 // Finish off the innermost switch.
666 void endSwitch(std::vector<Block*>& segmentBB);
668 struct LoopBlocks {
669 LoopBlocks(Block& head, Block& body, Block& merge, Block& continue_target) :
670 head(head), body(body), merge(merge), continue_target(continue_target) { }
671 Block &head, &body, &merge, &continue_target;
672 private:
673 LoopBlocks();
674 LoopBlocks& operator=(const LoopBlocks&) = delete;
677 // Start a new loop and prepare the builder to generate code for it. Until
678 // closeLoop() is called for this loop, createLoopContinue() and
679 // createLoopExit() will target its corresponding blocks.
680 LoopBlocks& makeNewLoop();
682 // Create a new block in the function containing the build point. Memory is
683 // owned by the function object.
684 Block& makeNewBlock();
686 // Add a branch to the continue_target of the current (innermost) loop.
687 void createLoopContinue();
689 // Add an exit (e.g. "break") from the innermost loop that we're currently
690 // in.
691 void createLoopExit();
693 // Close the innermost loop that you're in
694 void closeLoop();
697 // Access chain design for an R-Value vs. L-Value:
699 // There is a single access chain the builder is building at
700 // any particular time. Such a chain can be used to either to a load or
701 // a store, when desired.
703 // Expressions can be r-values, l-values, or both, or only r-values:
704 // a[b.c].d = .... // l-value
705 // ... = a[b.c].d; // r-value, that also looks like an l-value
706 // ++a[b.c].d; // r-value and l-value
707 // (x + y)[2]; // r-value only, can't possibly be l-value
709 // Computing an r-value means generating code. Hence,
710 // r-values should only be computed when they are needed, not speculatively.
712 // Computing an l-value means saving away information for later use in the compiler,
713 // no code is generated until the l-value is later dereferenced. It is okay
714 // to speculatively generate an l-value, just not okay to speculatively dereference it.
716 // The base of the access chain (the left-most variable or expression
717 // from which everything is based) can be set either as an l-value
718 // or as an r-value. Most efficient would be to set an l-value if one
719 // is available. If an expression was evaluated, the resulting r-value
720 // can be set as the chain base.
722 // The users of this single access chain can save and restore if they
723 // want to nest or manage multiple chains.
726 struct AccessChain {
727 Id base; // for l-values, pointer to the base object, for r-values, the base object
728 std::vector<Id> indexChain;
729 Id instr; // cache the instruction that generates this access chain
730 std::vector<unsigned> swizzle; // each std::vector element selects the next GLSL component number
731 Id component; // a dynamic component index, can coexist with a swizzle,
732 // done after the swizzle, NoResult if not present
733 Id preSwizzleBaseType; // dereferenced type, before swizzle or component is applied;
734 // NoType unless a swizzle or component is present
735 bool isRValue; // true if 'base' is an r-value, otherwise, base is an l-value
736 unsigned int alignment; // bitwise OR of alignment values passed in. Accumulates worst alignment.
737 // Only tracks base and (optional) component selection alignment.
739 // Accumulate whether anything in the chain of structures has coherent decorations.
740 struct CoherentFlags {
741 CoherentFlags() { clear(); }
742 bool isVolatile() const { return volatil; }
743 bool isNonUniform() const { return nonUniform; }
744 bool anyCoherent() const {
745 return coherent || devicecoherent || queuefamilycoherent || workgroupcoherent ||
746 subgroupcoherent || shadercallcoherent;
749 unsigned coherent : 1;
750 unsigned devicecoherent : 1;
751 unsigned queuefamilycoherent : 1;
752 unsigned workgroupcoherent : 1;
753 unsigned subgroupcoherent : 1;
754 unsigned shadercallcoherent : 1;
755 unsigned nonprivate : 1;
756 unsigned volatil : 1;
757 unsigned isImage : 1;
758 unsigned nonUniform : 1;
760 void clear() {
761 coherent = 0;
762 devicecoherent = 0;
763 queuefamilycoherent = 0;
764 workgroupcoherent = 0;
765 subgroupcoherent = 0;
766 shadercallcoherent = 0;
767 nonprivate = 0;
768 volatil = 0;
769 isImage = 0;
770 nonUniform = 0;
773 CoherentFlags operator |=(const CoherentFlags &other) {
774 coherent |= other.coherent;
775 devicecoherent |= other.devicecoherent;
776 queuefamilycoherent |= other.queuefamilycoherent;
777 workgroupcoherent |= other.workgroupcoherent;
778 subgroupcoherent |= other.subgroupcoherent;
779 shadercallcoherent |= other.shadercallcoherent;
780 nonprivate |= other.nonprivate;
781 volatil |= other.volatil;
782 isImage |= other.isImage;
783 nonUniform |= other.nonUniform;
784 return *this;
787 CoherentFlags coherentFlags;
791 // the SPIR-V builder maintains a single active chain that
792 // the following methods operate on
795 // for external save and restore
796 AccessChain getAccessChain() { return accessChain; }
797 void setAccessChain(AccessChain newChain) { accessChain = newChain; }
799 // clear accessChain
800 void clearAccessChain();
802 // set new base as an l-value base
803 void setAccessChainLValue(Id lValue)
805 assert(isPointer(lValue));
806 accessChain.base = lValue;
809 // set new base value as an r-value
810 void setAccessChainRValue(Id rValue)
812 accessChain.isRValue = true;
813 accessChain.base = rValue;
816 // push offset onto the end of the chain
817 void accessChainPush(Id offset, AccessChain::CoherentFlags coherentFlags, unsigned int alignment)
819 accessChain.indexChain.push_back(offset);
820 accessChain.coherentFlags |= coherentFlags;
821 accessChain.alignment |= alignment;
824 // push new swizzle onto the end of any existing swizzle, merging into a single swizzle
825 void accessChainPushSwizzle(std::vector<unsigned>& swizzle, Id preSwizzleBaseType,
826 AccessChain::CoherentFlags coherentFlags, unsigned int alignment);
828 // push a dynamic component selection onto the access chain, only applicable with a
829 // non-trivial swizzle or no swizzle
830 void accessChainPushComponent(Id component, Id preSwizzleBaseType, AccessChain::CoherentFlags coherentFlags,
831 unsigned int alignment)
833 if (accessChain.swizzle.size() != 1) {
834 accessChain.component = component;
835 if (accessChain.preSwizzleBaseType == NoType)
836 accessChain.preSwizzleBaseType = preSwizzleBaseType;
838 accessChain.coherentFlags |= coherentFlags;
839 accessChain.alignment |= alignment;
842 // use accessChain and swizzle to store value
843 void accessChainStore(Id rvalue, Decoration nonUniform,
844 spv::MemoryAccessMask memoryAccess = spv::MemoryAccessMaskNone,
845 spv::Scope scope = spv::ScopeMax, unsigned int alignment = 0);
847 // use accessChain and swizzle to load an r-value
848 Id accessChainLoad(Decoration precision, Decoration l_nonUniform, Decoration r_nonUniform, Id ResultType,
849 spv::MemoryAccessMask memoryAccess = spv::MemoryAccessMaskNone, spv::Scope scope = spv::ScopeMax,
850 unsigned int alignment = 0);
852 // Return whether or not the access chain can be represented in SPIR-V
853 // as an l-value.
854 // E.g., a[3].yx cannot be, while a[3].y and a[3].y[x] can be.
855 bool isSpvLvalue() const { return accessChain.swizzle.size() <= 1; }
857 // get the direct pointer for an l-value
858 Id accessChainGetLValue();
860 // Get the inferred SPIR-V type of the result of the current access chain,
861 // based on the type of the base and the chain of dereferences.
862 Id accessChainGetInferredType();
864 // Add capabilities, extensions, remove unneeded decorations, etc.,
865 // based on the resulting SPIR-V.
866 void postProcess(bool compileOnly);
868 // Prune unreachable blocks in the CFG and remove unneeded decorations.
869 void postProcessCFG();
871 // Add capabilities, extensions based on instructions in the module.
872 void postProcessFeatures();
873 // Hook to visit each instruction in a block in a function
874 void postProcess(Instruction&);
875 // Hook to visit each non-32-bit sized float/int operation in a block.
876 void postProcessType(const Instruction&, spv::Id typeId);
877 // move OpSampledImage instructions to be next to their users.
878 void postProcessSamplers();
880 void dump(std::vector<unsigned int>&) const;
882 // Add a branch to the target block.
883 // If set implicit, the branch instruction shouldn't have debug source location.
884 void createBranch(bool implicit, Block* block);
885 void createConditionalBranch(Id condition, Block* thenBlock, Block* elseBlock);
886 void createLoopMerge(Block* mergeBlock, Block* continueBlock, unsigned int control,
887 const std::vector<unsigned int>& operands);
889 // Sets to generate opcode for specialization constants.
890 void setToSpecConstCodeGenMode() { generatingOpCodeForSpecConst = true; }
891 // Sets to generate opcode for non-specialization constants (normal mode).
892 void setToNormalCodeGenMode() { generatingOpCodeForSpecConst = false; }
893 // Check if the builder is generating code for spec constants.
894 bool isInSpecConstCodeGenMode() { return generatingOpCodeForSpecConst; }
896 void setUseReplicatedComposites(bool use) { useReplicatedComposites = use; }
898 protected:
899 Id findScalarConstant(Op typeClass, Op opcode, Id typeId, unsigned value);
900 Id findScalarConstant(Op typeClass, Op opcode, Id typeId, unsigned v1, unsigned v2);
901 Id findCompositeConstant(Op typeClass, Id typeId, const std::vector<Id>& comps);
902 Id findStructConstant(Id typeId, const std::vector<Id>& comps);
903 Id collapseAccessChain();
904 void remapDynamicSwizzle();
905 void transferAccessChainSwizzle(bool dynamic);
906 void simplifyAccessChainSwizzle();
907 void createAndSetNoPredecessorBlock(const char*);
908 void createSelectionMerge(Block* mergeBlock, unsigned int control);
909 void dumpSourceInstructions(std::vector<unsigned int>&) const;
910 void dumpSourceInstructions(const spv::Id fileId, const std::string& text, std::vector<unsigned int>&) const;
911 template <class Range> void dumpInstructions(std::vector<unsigned int>& out, const Range& instructions) const;
912 void dumpModuleProcesses(std::vector<unsigned int>&) const;
913 spv::MemoryAccessMask sanitizeMemoryAccessForStorageClass(spv::MemoryAccessMask memoryAccess, StorageClass sc)
914 const;
915 struct DecorationInstructionLessThan {
916 bool operator()(const std::unique_ptr<Instruction>& lhs, const std::unique_ptr<Instruction>& rhs) const;
919 unsigned int spvVersion; // the version of SPIR-V to emit in the header
920 SourceLanguage sourceLang;
921 int sourceVersion;
922 spv::Id nonSemanticShaderCompilationUnitId {0};
923 spv::Id nonSemanticShaderDebugInfo {0};
924 spv::Id debugInfoNone {0};
925 spv::Id debugExpression {0}; // Debug expression with zero operations.
926 std::string sourceText;
928 // True if an new OpLine/OpDebugLine may need to be inserted. Either:
929 // 1. The current debug location changed
930 // 2. The current build point changed
931 bool dirtyLineTracker;
932 int currentLine = 0;
933 // OpString id of the current file name. Always 0 if debug info is off.
934 spv::Id currentFileId = 0;
935 // OpString id of the main file name. Always 0 if debug info is off.
936 spv::Id mainFileId = 0;
938 // True if an new OpDebugScope may need to be inserted. Either:
939 // 1. A new lexical block is pushed
940 // 2. The current build point changed
941 bool dirtyScopeTracker;
942 std::stack<spv::Id> currentDebugScopeId;
944 // This flag toggles tracking of debug info while building the SPIR-V.
945 bool trackDebugInfo = false;
946 // This flag toggles emission of SPIR-V debug instructions, like OpLine and OpSource.
947 bool emitSpirvDebugInfo = false;
948 // This flag toggles emission of Non-Semantic Debug extension debug instructions.
949 bool emitNonSemanticShaderDebugInfo = false;
950 bool restoreNonSemanticShaderDebugInfo = false;
951 bool emitNonSemanticShaderDebugSource = false;
953 std::set<std::string> extensions;
954 std::vector<const char*> sourceExtensions;
955 std::vector<const char*> moduleProcesses;
956 AddressingModel addressModel;
957 MemoryModel memoryModel;
958 std::set<spv::Capability> capabilities;
959 int builderNumber;
960 Module module;
961 Block* buildPoint;
962 Id uniqueId;
963 Function* entryPointFunction;
964 bool generatingOpCodeForSpecConst;
965 bool useReplicatedComposites { false };
966 AccessChain accessChain;
968 // special blocks of instructions for output
969 std::vector<std::unique_ptr<Instruction> > strings;
970 std::vector<std::unique_ptr<Instruction> > imports;
971 std::vector<std::unique_ptr<Instruction> > entryPoints;
972 std::vector<std::unique_ptr<Instruction> > executionModes;
973 std::vector<std::unique_ptr<Instruction> > names;
974 std::set<std::unique_ptr<Instruction>, DecorationInstructionLessThan> decorations;
975 std::vector<std::unique_ptr<Instruction> > constantsTypesGlobals;
976 std::vector<std::unique_ptr<Instruction> > externals;
977 std::vector<std::unique_ptr<Function> > functions;
979 // not output, internally used for quick & dirty canonical (unique) creation
981 // map type opcodes to constant inst.
982 std::unordered_map<unsigned int, std::vector<Instruction*>> groupedConstants;
983 // map struct-id to constant instructions
984 std::unordered_map<unsigned int, std::vector<Instruction*>> groupedStructConstants;
985 // map type opcodes to type instructions
986 std::unordered_map<unsigned int, std::vector<Instruction*>> groupedTypes;
987 // map type opcodes to debug type instructions
988 std::unordered_map<unsigned int, std::vector<Instruction*>> groupedDebugTypes;
989 // list of OpConstantNull instructions
990 std::vector<Instruction*> nullConstants;
992 // stack of switches
993 std::stack<Block*> switchMerges;
995 // Our loop stack.
996 std::stack<LoopBlocks> loops;
998 // map from strings to their string ids
999 std::unordered_map<std::string, spv::Id> stringIds;
1001 // map from include file name ids to their contents
1002 std::map<spv::Id, const std::string*> includeFiles;
1004 // map from core id to debug id
1005 std::map <spv::Id, spv::Id> debugId;
1007 // map from file name string id to DebugSource id
1008 std::unordered_map<spv::Id, spv::Id> debugSourceId;
1010 // The stream for outputting warnings and errors.
1011 SpvBuildLogger* logger;
1012 }; // end Builder class
1014 } // end spv namespace
1016 #endif // SpvBuilder_H