2 // Copyright (C) 2014-2015 LunarG, Inc.
3 // Copyright (C) 2015-2016 Google, Inc.
4 // Copyright (C) 2017 ARM Limited.
6 // All rights reserved.
8 // Redistribution and use in source and binary forms, with or without
9 // modification, are permitted provided that the following conditions
12 // Redistributions of source code must retain the above copyright
13 // notice, this list of conditions and the following disclaimer.
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.
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.
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.
38 // "Builder" is an interface to fully build SPIR-V IR. Allocate one of
39 // these to build (a thread safe) internal SPIR-V representation (IR),
40 // and then dump it as a binary stream according to the SPIR-V specification.
42 // A Builder has a 1:1 relationship with a SPIR-V module.
59 #include <unordered_map>
65 Builder(unsigned int spvVersion, unsigned int userNumber, SpvBuildLogger* logger);
68 static const int maxMatrixSize = 4;
70 unsigned int getSpvVersion() const { return spvVersion; }
72 void setSource(spv::SourceLanguage lang, int version)
75 sourceVersion = version;
77 void setSourceFile(const std::string& file)
79 Instruction* fileString = new Instruction(getUniqueId(), NoType, OpString);
80 fileString->addStringOperand(file.c_str());
81 sourceFileStringId = fileString->getResultId();
82 strings.push_back(std::unique_ptr<Instruction>(fileString));
84 void setSourceText(const std::string& text) { sourceText = text; }
85 void addSourceExtension(const char* ext) { sourceExtensions.push_back(ext); }
86 void addModuleProcessed(const std::string& p) { moduleProcesses.push_back(p.c_str()); }
87 void setEmitOpLines() { emitOpLines = true; }
88 void addExtension(const char* ext) { extensions.insert(ext); }
89 Id import(const char*);
90 void setMemoryModel(spv::AddressingModel addr, spv::MemoryModel mem)
96 void addCapability(spv::Capability cap) { capabilities.insert(cap); }
98 // To get a new <id> for anything needing a new one.
99 Id getUniqueId() { return ++uniqueId; }
101 // To get a set of new <id>s, e.g., for a set of function parameters
102 Id getUniqueIds(int numIds)
104 Id id = uniqueId + 1;
109 // Log the current line, and if different than the last one,
110 // issue a new OpLine, using the current file name.
111 void setLine(int line);
112 // Low-level OpLine. See setLine() for a layered helper.
113 void addLine(Id fileName, int line, int column);
115 // For creating new types (will return old type if the requested one was already made).
118 Id makePointer(StorageClass, Id type);
119 Id makeIntegerType(int width, bool hasSign); // generic
120 Id makeIntType(int width) { return makeIntegerType(width, true); }
121 Id makeUintType(int width) { return makeIntegerType(width, false); }
122 Id makeFloatType(int width);
123 Id makeStructType(const std::vector<Id>& members, const char*);
124 Id makeStructResultType(Id type0, Id type1);
125 Id makeVectorType(Id component, int size);
126 Id makeMatrixType(Id component, int cols, int rows);
127 Id makeArrayType(Id element, Id sizeId, int stride); // 0 stride means no stride decoration
128 Id makeRuntimeArray(Id element);
129 Id makeFunctionType(Id returnType, const std::vector<Id>& paramTypes);
130 Id makeImageType(Id sampledType, Dim, bool depth, bool arrayed, bool ms, unsigned sampled, ImageFormat format);
131 Id makeSamplerType();
132 Id makeSampledImageType(Id imageType);
134 // For querying about types.
135 Id getTypeId(Id resultId) const { return module.getTypeId(resultId); }
136 Id getDerefTypeId(Id resultId) const;
137 Op getOpCode(Id id) const { return module.getInstruction(id)->getOpCode(); }
138 Op getTypeClass(Id typeId) const { return getOpCode(typeId); }
139 Op getMostBasicTypeClass(Id typeId) const;
140 int getNumComponents(Id resultId) const { return getNumTypeComponents(getTypeId(resultId)); }
141 int getNumTypeConstituents(Id typeId) const;
142 int getNumTypeComponents(Id typeId) const { return getNumTypeConstituents(typeId); }
143 Id getScalarTypeId(Id typeId) const;
144 Id getContainedTypeId(Id typeId) const;
145 Id getContainedTypeId(Id typeId, int) const;
146 StorageClass getTypeStorageClass(Id typeId) const { return module.getStorageClass(typeId); }
147 ImageFormat getImageTypeFormat(Id typeId) const { return (ImageFormat)module.getInstruction(typeId)->getImmediateOperand(6); }
149 bool isPointer(Id resultId) const { return isPointerType(getTypeId(resultId)); }
150 bool isScalar(Id resultId) const { return isScalarType(getTypeId(resultId)); }
151 bool isVector(Id resultId) const { return isVectorType(getTypeId(resultId)); }
152 bool isMatrix(Id resultId) const { return isMatrixType(getTypeId(resultId)); }
153 bool isAggregate(Id resultId) const { return isAggregateType(getTypeId(resultId)); }
154 bool isSampledImage(Id resultId) const { return isSampledImageType(getTypeId(resultId)); }
156 bool isBoolType(Id typeId) { return groupedTypes[OpTypeBool].size() > 0 && typeId == groupedTypes[OpTypeBool].back()->getResultId(); }
157 bool isIntType(Id typeId) const { return getTypeClass(typeId) == OpTypeInt && module.getInstruction(typeId)->getImmediateOperand(1) != 0; }
158 bool isUintType(Id typeId) const { return getTypeClass(typeId) == OpTypeInt && module.getInstruction(typeId)->getImmediateOperand(1) == 0; }
159 bool isFloatType(Id typeId) const { return getTypeClass(typeId) == OpTypeFloat; }
160 bool isPointerType(Id typeId) const { return getTypeClass(typeId) == OpTypePointer; }
161 bool isScalarType(Id typeId) const { return getTypeClass(typeId) == OpTypeFloat || getTypeClass(typeId) == OpTypeInt || getTypeClass(typeId) == OpTypeBool; }
162 bool isVectorType(Id typeId) const { return getTypeClass(typeId) == OpTypeVector; }
163 bool isMatrixType(Id typeId) const { return getTypeClass(typeId) == OpTypeMatrix; }
164 bool isStructType(Id typeId) const { return getTypeClass(typeId) == OpTypeStruct; }
165 bool isArrayType(Id typeId) const { return getTypeClass(typeId) == OpTypeArray; }
166 bool isAggregateType(Id typeId) const { return isArrayType(typeId) || isStructType(typeId); }
167 bool isImageType(Id typeId) const { return getTypeClass(typeId) == OpTypeImage; }
168 bool isSamplerType(Id typeId) const { return getTypeClass(typeId) == OpTypeSampler; }
169 bool isSampledImageType(Id typeId) const { return getTypeClass(typeId) == OpTypeSampledImage; }
170 bool containsType(Id typeId, Op typeOp, int width) const;
172 bool isConstantOpCode(Op opcode) const;
173 bool isSpecConstantOpCode(Op opcode) const;
174 bool isConstant(Id resultId) const { return isConstantOpCode(getOpCode(resultId)); }
175 bool isConstantScalar(Id resultId) const { return getOpCode(resultId) == OpConstant; }
176 bool isSpecConstant(Id resultId) const { return isSpecConstantOpCode(getOpCode(resultId)); }
177 unsigned int getConstantScalar(Id resultId) const { return module.getInstruction(resultId)->getImmediateOperand(0); }
178 StorageClass getStorageClass(Id resultId) const { return getTypeStorageClass(getTypeId(resultId)); }
180 int getScalarTypeWidth(Id typeId) const
182 Id scalarTypeId = getScalarTypeId(typeId);
183 assert(getTypeClass(scalarTypeId) == OpTypeInt || getTypeClass(scalarTypeId) == OpTypeFloat);
184 return module.getInstruction(scalarTypeId)->getImmediateOperand(0);
187 int getTypeNumColumns(Id typeId) const
189 assert(isMatrixType(typeId));
190 return getNumTypeConstituents(typeId);
192 int getNumColumns(Id resultId) const { return getTypeNumColumns(getTypeId(resultId)); }
193 int getTypeNumRows(Id typeId) const
195 assert(isMatrixType(typeId));
196 return getNumTypeComponents(getContainedTypeId(typeId));
198 int getNumRows(Id resultId) const { return getTypeNumRows(getTypeId(resultId)); }
200 Dim getTypeDimensionality(Id typeId) const
202 assert(isImageType(typeId));
203 return (Dim)module.getInstruction(typeId)->getImmediateOperand(1);
205 Id getImageType(Id resultId) const
207 Id typeId = getTypeId(resultId);
208 assert(isImageType(typeId) || isSampledImageType(typeId));
209 return isSampledImageType(typeId) ? module.getInstruction(typeId)->getIdOperand(0) : typeId;
211 bool isArrayedImageType(Id typeId) const
213 assert(isImageType(typeId));
214 return module.getInstruction(typeId)->getImmediateOperand(3) != 0;
217 // For making new constants (will return old constant if the requested one was already made).
218 Id makeBoolConstant(bool b, bool specConstant = false);
219 Id makeInt8Constant(int i, bool specConstant = false) { return makeIntConstant(makeIntType(8), (unsigned)i, specConstant); }
220 Id makeUint8Constant(unsigned u, bool specConstant = false) { return makeIntConstant(makeUintType(8), u, specConstant); }
221 Id makeInt16Constant(int i, bool specConstant = false) { return makeIntConstant(makeIntType(16), (unsigned)i, specConstant); }
222 Id makeUint16Constant(unsigned u, bool specConstant = false) { return makeIntConstant(makeUintType(16), u, specConstant); }
223 Id makeIntConstant(int i, bool specConstant = false) { return makeIntConstant(makeIntType(32), (unsigned)i, specConstant); }
224 Id makeUintConstant(unsigned u, bool specConstant = false) { return makeIntConstant(makeUintType(32), u, specConstant); }
225 Id makeInt64Constant(long long i, bool specConstant = false) { return makeInt64Constant(makeIntType(64), (unsigned long long)i, specConstant); }
226 Id makeUint64Constant(unsigned long long u, bool specConstant = false) { return makeInt64Constant(makeUintType(64), u, specConstant); }
227 Id makeFloatConstant(float f, bool specConstant = false);
228 Id makeDoubleConstant(double d, bool specConstant = false);
229 Id makeFloat16Constant(float f16, bool specConstant = false);
230 Id makeFpConstant(Id type, double d, bool specConstant = false);
232 // Turn the array of constants into a proper spv constant of the requested type.
233 Id makeCompositeConstant(Id type, const std::vector<Id>& comps, bool specConst = false);
235 // Methods for adding information outside the CFG.
236 Instruction* addEntryPoint(ExecutionModel, Function*, const char* name);
237 void addExecutionMode(Function*, ExecutionMode mode, int value1 = -1, int value2 = -1, int value3 = -1);
238 void addName(Id, const char* name);
239 void addMemberName(Id, int member, const char* name);
240 void addDecoration(Id, Decoration, int num = -1);
241 void addDecoration(Id, Decoration, const char*);
242 void addDecorationId(Id id, Decoration, Id idDecoration);
243 void addMemberDecoration(Id, unsigned int member, Decoration, int num = -1);
244 void addMemberDecoration(Id, unsigned int member, Decoration, const char*);
246 // At the end of what block do the next create*() instructions go?
247 void setBuildPoint(Block* bp) { buildPoint = bp; }
248 Block* getBuildPoint() const { return buildPoint; }
250 // Make the entry-point function. The returned pointer is only valid
251 // for the lifetime of this builder.
252 Function* makeEntryPoint(const char*);
254 // Make a shader-style function, and create its entry block if entry is non-zero.
255 // Return the function, pass back the entry.
256 // The returned pointer is only valid for the lifetime of this builder.
257 Function* makeFunctionEntry(Decoration precision, Id returnType, const char* name, const std::vector<Id>& paramTypes,
258 const std::vector<std::vector<Decoration>>& precisions, Block **entry = 0);
260 // Create a return. An 'implicit' return is one not appearing in the source
261 // code. In the case of an implicit return, no post-return block is inserted.
262 void makeReturn(bool implicit, Id retVal = 0);
264 // Generate all the code needed to finish up a function.
265 void leaveFunction();
270 // Create a global or function local or IO variable.
271 Id createVariable(StorageClass, Id type, const char* name = 0);
273 // Create an intermediate with an undefined value.
274 Id createUndefined(Id type);
276 // Store into an Id and return the l-value
277 void createStore(Id rValue, Id lValue);
279 // Load from an Id and return it
280 Id createLoad(Id lValue);
282 // Create an OpAccessChain instruction
283 Id createAccessChain(StorageClass, Id base, const std::vector<Id>& offsets);
285 // Create an OpArrayLength instruction
286 Id createArrayLength(Id base, unsigned int member);
288 // Create an OpCompositeExtract instruction
289 Id createCompositeExtract(Id composite, Id typeId, unsigned index);
290 Id createCompositeExtract(Id composite, Id typeId, const std::vector<unsigned>& indexes);
291 Id createCompositeInsert(Id object, Id composite, Id typeId, unsigned index);
292 Id createCompositeInsert(Id object, Id composite, Id typeId, const std::vector<unsigned>& indexes);
294 Id createVectorExtractDynamic(Id vector, Id typeId, Id componentIndex);
295 Id createVectorInsertDynamic(Id vector, Id typeId, Id component, Id componentIndex);
297 void createNoResultOp(Op);
298 void createNoResultOp(Op, Id operand);
299 void createNoResultOp(Op, const std::vector<IdImmediate>& operands);
300 void createControlBarrier(Scope execution, Scope memory, MemorySemanticsMask);
301 void createMemoryBarrier(unsigned executionScope, unsigned memorySemantics);
302 Id createUnaryOp(Op, Id typeId, Id operand);
303 Id createBinOp(Op, Id typeId, Id operand1, Id operand2);
304 Id createTriOp(Op, Id typeId, Id operand1, Id operand2, Id operand3);
305 Id createOp(Op, Id typeId, const std::vector<Id>& operands);
306 Id createOp(Op, Id typeId, const std::vector<IdImmediate>& operands);
307 Id createFunctionCall(spv::Function*, const std::vector<spv::Id>&);
308 Id createSpecConstantOp(Op, Id typeId, const std::vector<spv::Id>& operands, const std::vector<unsigned>& literals);
310 // Take an rvalue (source) and a set of channels to extract from it to
311 // make a new rvalue, which is returned.
312 Id createRvalueSwizzle(Decoration precision, Id typeId, Id source, const std::vector<unsigned>& channels);
314 // Take a copy of an lvalue (target) and a source of components, and set the
315 // source components into the lvalue where the 'channels' say to put them.
316 // An updated version of the target is returned.
317 // (No true lvalue or stores are used.)
318 Id createLvalueSwizzle(Id typeId, Id target, Id source, const std::vector<unsigned>& channels);
320 // If both the id and precision are valid, the id
321 // gets tagged with the requested precision.
322 // The passed in id is always the returned id, to simplify use patterns.
323 Id setPrecision(Id id, Decoration precision)
325 if (precision != NoPrecision && id != NoResult)
326 addDecoration(id, precision);
331 // Can smear a scalar to a vector for the following forms:
332 // - promoteScalar(scalar, vector) // smear scalar to width of vector
333 // - promoteScalar(vector, scalar) // smear scalar to width of vector
334 // - promoteScalar(pointer, scalar) // smear scalar to width of what pointer points to
335 // - promoteScalar(scalar, scalar) // do nothing
336 // Other forms are not allowed.
338 // Generally, the type of 'scalar' does not need to be the same type as the components in 'vector'.
339 // The type of the created vector is a vector of components of the same type as the scalar.
341 // Note: One of the arguments will change, with the result coming back that way rather than
342 // through the return value.
343 void promoteScalar(Decoration precision, Id& left, Id& right);
345 // Make a value by smearing the scalar to fill the type.
346 // vectorType should be the correct type for making a vector of scalarVal.
347 // (No conversions are done.)
348 Id smearScalar(Decoration precision, Id scalarVal, Id vectorType);
350 // Create a call to a built-in function.
351 Id createBuiltinCall(Id resultType, Id builtins, int entryPoint, const std::vector<Id>& args);
353 // List of parameters used to create a texture operation
354 struct TextureParameters {
370 // Select the correct texture operation based on all inputs, and emit the correct instruction
371 Id createTextureCall(Decoration precision, Id resultType, bool sparse, bool fetch, bool proj, bool gather, bool noImplicit, const TextureParameters&);
373 // Emit the OpTextureQuery* instruction that was passed in.
374 // Figure out the right return value and type, and return it.
375 Id createTextureQueryCall(Op, const TextureParameters&, bool isUnsignedResult);
377 Id createSamplePositionCall(Decoration precision, Id, Id);
379 Id createBitFieldExtractCall(Decoration precision, Id, Id, Id, bool isSigned);
380 Id createBitFieldInsertCall(Decoration precision, Id, Id, Id, Id);
382 // Reduction comparison for composites: For equal and not-equal resulting in a scalar.
383 Id createCompositeCompare(Decoration precision, Id, Id, bool /* true if for equal, false if for not-equal */);
385 // OpCompositeConstruct
386 Id createCompositeConstruct(Id typeId, const std::vector<Id>& constituents);
388 // vector or scalar constructor
389 Id createConstructor(Decoration precision, const std::vector<Id>& sources, Id resultTypeId);
391 // matrix constructor
392 Id createMatrixConstructor(Decoration precision, const std::vector<Id>& sources, Id constructee);
394 // Helper to use for building nested control flow with if-then-else.
397 If(Id condition, unsigned int ctrl, Builder& builder);
400 void makeBeginElse();
409 unsigned int control;
417 // Make a switch statement. A switch has 'numSegments' of pieces of code, not containing
418 // any case/default labels, all separated by one or more case/default labels. Each possible
419 // case value v is a jump to the caseValues[v] segment. The defaultSegment is also in this
420 // number space. How to compute the value is given by 'condition', as in switch(condition).
422 // The SPIR-V Builder will maintain the stack of post-switch merge blocks for nested switches.
424 // Use a defaultSegment < 0 if there is no default segment (to branch to post switch).
426 // Returns the right set of basic blocks to start each code segment with, so that the caller's
427 // recursion stack can hold the memory for it.
429 void makeSwitch(Id condition, unsigned int control, int numSegments, const std::vector<int>& caseValues,
430 const std::vector<int>& valueToSegment, int defaultSegment, std::vector<Block*>& segmentBB); // return argument
432 // Add a branch to the innermost switch's merge block.
433 void addSwitchBreak();
435 // Move to the next code segment, passing in the return argument in makeSwitch()
436 void nextSwitchSegment(std::vector<Block*>& segmentBB, int segment);
438 // Finish off the innermost switch.
439 void endSwitch(std::vector<Block*>& segmentBB);
442 LoopBlocks(Block& head, Block& body, Block& merge, Block& continue_target) :
443 head(head), body(body), merge(merge), continue_target(continue_target) { }
444 Block &head, &body, &merge, &continue_target;
447 LoopBlocks& operator=(const LoopBlocks&);
450 // Start a new loop and prepare the builder to generate code for it. Until
451 // closeLoop() is called for this loop, createLoopContinue() and
452 // createLoopExit() will target its corresponding blocks.
453 LoopBlocks& makeNewLoop();
455 // Create a new block in the function containing the build point. Memory is
456 // owned by the function object.
457 Block& makeNewBlock();
459 // Add a branch to the continue_target of the current (innermost) loop.
460 void createLoopContinue();
462 // Add an exit (e.g. "break") from the innermost loop that we're currently
464 void createLoopExit();
466 // Close the innermost loop that you're in
470 // Access chain design for an R-Value vs. L-Value:
472 // There is a single access chain the builder is building at
473 // any particular time. Such a chain can be used to either to a load or
474 // a store, when desired.
476 // Expressions can be r-values, l-values, or both, or only r-values:
477 // a[b.c].d = .... // l-value
478 // ... = a[b.c].d; // r-value, that also looks like an l-value
479 // ++a[b.c].d; // r-value and l-value
480 // (x + y)[2]; // r-value only, can't possibly be l-value
482 // Computing an r-value means generating code. Hence,
483 // r-values should only be computed when they are needed, not speculatively.
485 // Computing an l-value means saving away information for later use in the compiler,
486 // no code is generated until the l-value is later dereferenced. It is okay
487 // to speculatively generate an l-value, just not okay to speculatively dereference it.
489 // The base of the access chain (the left-most variable or expression
490 // from which everything is based) can be set either as an l-value
491 // or as an r-value. Most efficient would be to set an l-value if one
492 // is available. If an expression was evaluated, the resulting r-value
493 // can be set as the chain base.
495 // The users of this single access chain can save and restore if they
496 // want to nest or manage multiple chains.
500 Id base; // for l-values, pointer to the base object, for r-values, the base object
501 std::vector<Id> indexChain;
502 Id instr; // cache the instruction that generates this access chain
503 std::vector<unsigned> swizzle; // each std::vector element selects the next GLSL component number
504 Id component; // a dynamic component index, can coexist with a swizzle, done after the swizzle, NoResult if not present
505 Id preSwizzleBaseType; // dereferenced type, before swizzle or component is applied; NoType unless a swizzle or component is present
506 bool isRValue; // true if 'base' is an r-value, otherwise, base is an l-value
510 // the SPIR-V builder maintains a single active chain that
511 // the following methods operate on
514 // for external save and restore
515 AccessChain getAccessChain() { return accessChain; }
516 void setAccessChain(AccessChain newChain) { accessChain = newChain; }
519 void clearAccessChain();
521 // set new base as an l-value base
522 void setAccessChainLValue(Id lValue)
524 assert(isPointer(lValue));
525 accessChain.base = lValue;
528 // set new base value as an r-value
529 void setAccessChainRValue(Id rValue)
531 accessChain.isRValue = true;
532 accessChain.base = rValue;
535 // push offset onto the end of the chain
536 void accessChainPush(Id offset)
538 accessChain.indexChain.push_back(offset);
541 // push new swizzle onto the end of any existing swizzle, merging into a single swizzle
542 void accessChainPushSwizzle(std::vector<unsigned>& swizzle, Id preSwizzleBaseType);
544 // push a dynamic component selection onto the access chain, only applicable with a
545 // non-trivial swizzle or no swizzle
546 void accessChainPushComponent(Id component, Id preSwizzleBaseType)
548 if (accessChain.swizzle.size() != 1) {
549 accessChain.component = component;
550 if (accessChain.preSwizzleBaseType == NoType)
551 accessChain.preSwizzleBaseType = preSwizzleBaseType;
555 // use accessChain and swizzle to store value
556 void accessChainStore(Id rvalue);
558 // use accessChain and swizzle to load an r-value
559 Id accessChainLoad(Decoration precision, Decoration nonUniform, Id ResultType);
561 // get the direct pointer for an l-value
562 Id accessChainGetLValue();
564 // Get the inferred SPIR-V type of the result of the current access chain,
565 // based on the type of the base and the chain of dereferences.
566 Id accessChainGetInferredType();
568 // Add capabilities, extensions, remove unneeded decorations, etc.,
569 // based on the resulting SPIR-V.
572 // Hook to visit each instruction in a block in a function
573 void postProcess(const Instruction&);
574 // Hook to visit each instruction in a reachable block in a function.
575 void postProcessReachable(const Instruction&);
576 // Hook to visit each non-32-bit sized float/int operation in a block.
577 void postProcessType(const Instruction&, spv::Id typeId);
579 void dump(std::vector<unsigned int>&) const;
581 void createBranch(Block* block);
582 void createConditionalBranch(Id condition, Block* thenBlock, Block* elseBlock);
583 void createLoopMerge(Block* mergeBlock, Block* continueBlock, unsigned int control, unsigned int dependencyLength);
585 // Sets to generate opcode for specialization constants.
586 void setToSpecConstCodeGenMode() { generatingOpCodeForSpecConst = true; }
587 // Sets to generate opcode for non-specialization constants (normal mode).
588 void setToNormalCodeGenMode() { generatingOpCodeForSpecConst = false; }
589 // Check if the builder is generating code for spec constants.
590 bool isInSpecConstCodeGenMode() { return generatingOpCodeForSpecConst; }
593 Id makeIntConstant(Id typeId, unsigned value, bool specConstant);
594 Id makeInt64Constant(Id typeId, unsigned long long value, bool specConstant);
595 Id findScalarConstant(Op typeClass, Op opcode, Id typeId, unsigned value);
596 Id findScalarConstant(Op typeClass, Op opcode, Id typeId, unsigned v1, unsigned v2);
597 Id findCompositeConstant(Op typeClass, const std::vector<Id>& comps);
598 Id findStructConstant(Id typeId, const std::vector<Id>& comps);
599 Id collapseAccessChain();
600 void remapDynamicSwizzle();
601 void transferAccessChainSwizzle(bool dynamic);
602 void simplifyAccessChainSwizzle();
603 void createAndSetNoPredecessorBlock(const char*);
604 void createSelectionMerge(Block* mergeBlock, unsigned int control);
605 void dumpSourceInstructions(std::vector<unsigned int>&) const;
606 void dumpInstructions(std::vector<unsigned int>&, const std::vector<std::unique_ptr<Instruction> >&) const;
607 void dumpModuleProcesses(std::vector<unsigned int>&) const;
609 unsigned int spvVersion; // the version of SPIR-V to emit in the header
610 SourceLanguage source;
612 spv::Id sourceFileStringId;
613 std::string sourceText;
616 std::set<std::string> extensions;
617 std::vector<const char*> sourceExtensions;
618 std::vector<const char*> moduleProcesses;
619 AddressingModel addressModel;
620 MemoryModel memoryModel;
621 std::set<spv::Capability> capabilities;
626 Function* entryPointFunction;
627 bool generatingOpCodeForSpecConst;
628 AccessChain accessChain;
630 // special blocks of instructions for output
631 std::vector<std::unique_ptr<Instruction> > strings;
632 std::vector<std::unique_ptr<Instruction> > imports;
633 std::vector<std::unique_ptr<Instruction> > entryPoints;
634 std::vector<std::unique_ptr<Instruction> > executionModes;
635 std::vector<std::unique_ptr<Instruction> > names;
636 std::vector<std::unique_ptr<Instruction> > decorations;
637 std::vector<std::unique_ptr<Instruction> > constantsTypesGlobals;
638 std::vector<std::unique_ptr<Instruction> > externals;
639 std::vector<std::unique_ptr<Function> > functions;
641 // not output, internally used for quick & dirty canonical (unique) creation
642 std::unordered_map<unsigned int, std::vector<Instruction*>> groupedConstants; // map type opcodes to constant inst.
643 std::unordered_map<unsigned int, std::vector<Instruction*>> groupedStructConstants; // map struct-id to constant instructions
644 std::unordered_map<unsigned int, std::vector<Instruction*>> groupedTypes; // map type opcodes to type instructions
647 std::stack<Block*> switchMerges;
650 std::stack<LoopBlocks> loops;
652 // The stream for outputting warnings and errors.
653 SpvBuildLogger* logger;
654 }; // end Builder class
656 }; // end spv namespace
658 #endif // SpvBuilder_H