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.
7 // All rights reserved.
9 // Redistribution and use in source and binary forms, with or without
10 // modification, are permitted provided that the following conditions
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.
51 #define SPV_ENABLE_UTILITY_CODE
55 #include "GLSL.ext.KHR.h"
56 #include "NonSemanticShaderDebugInfo100.h"
66 #include <unordered_map>
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),
82 Builder(unsigned int spvVersion
, unsigned int userNumber
, SpvBuildLogger
* logger
);
85 static const int maxMatrixSize
= 4;
87 unsigned int getSpvVersion() const { return spvVersion
; }
89 void setSource(spv::SourceLanguage lang
, int version
)
92 sourceVersion
= version
;
94 spv::Id
getStringId(const std::string
& str
)
96 auto sItr
= stringIds
.find(str
);
97 if (sItr
!= stringIds
.end())
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
;
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;
128 // TODO: This is special handling of some AST nodes having (untracked) line 0.
129 // But they should have a valid line number.
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
))
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
)
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;
196 // For creating new types (will return old type if the requested one was already made).
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
{
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();
262 Id
makeRayQueryType();
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
) {
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
);
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
{
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.
624 If(Id condition
, unsigned int ctrl
, Builder
& builder
);
627 void makeBeginElse();
636 unsigned int control
;
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
);
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
;
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
691 void createLoopExit();
693 // Close the innermost loop that you're in
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.
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;
763 queuefamilycoherent
= 0;
764 workgroupcoherent
= 0;
765 subgroupcoherent
= 0;
766 shadercallcoherent
= 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
;
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
; }
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
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
; }
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
)
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
;
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
;
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
;
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
;
993 std::stack
<Block
*> switchMerges
;
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