2 //Copyright (C) 2014 LunarG, Inc.
6 //Redistribution and use in source and binary forms, with or without
7 //modification, are permitted provided that the following conditions
10 // Redistributions of source code must retain the above copyright
11 // notice, this list of conditions and the following disclaimer.
13 // Redistributions in binary form must reproduce the above
14 // copyright notice, this list of conditions and the following
15 // disclaimer in the documentation and/or other materials provided
16 // with the distribution.
18 // Neither the name of 3Dlabs Inc. Ltd. nor the names of its
19 // contributors may be used to endorse or promote products derived
20 // from this software without specific prior written permission.
22 //THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
23 //"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
24 //LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
25 //FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
26 //COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
27 //INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
28 //BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
29 //LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
30 //CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 //LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
32 //ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
33 //POSSIBILITY OF SUCH DAMAGE.
36 // Author: John Kessenich, LunarG
40 // "Builder" is an interface to fully build SPIR-V IR. Allocate one of
41 // these to build (a thread safe) internal SPIR-V representation (IR),
42 // and then dump it as a binary stream according to the SPIR-V specification.
44 // A Builder has a 1:1 relationship with a SPIR-V module.
63 Builder(unsigned int userNumber);
66 static const int maxMatrixSize = 4;
68 void setSource(spv::SourceLanguage lang, int version)
71 sourceVersion = version;
73 void addSourceExtension(const char* ext) { extensions.push_back(ext); }
74 Id import(const char*);
75 void setMemoryModel(spv::AddressingModel addr, spv::MemoryModel mem)
81 void addCapability(spv::Capability cap) { capabilities.push_back(cap); }
83 // To get a new <id> for anything needing a new one.
84 Id getUniqueId() { return ++uniqueId; }
86 // To get a set of new <id>s, e.g., for a set of function parameters
87 Id getUniqueIds(int numIds)
94 // For creating new types (will return old type if the requested one was already made).
97 Id makePointer(StorageClass, Id type);
98 Id makeIntegerType(int width, bool hasSign); // generic
99 Id makeIntType(int width) { return makeIntegerType(width, true); }
100 Id makeUintType(int width) { return makeIntegerType(width, false); }
101 Id makeFloatType(int width);
102 Id makeStructType(std::vector<Id>& members, const char*);
103 Id makeStructResultType(Id type0, Id type1);
104 Id makeVectorType(Id component, int size);
105 Id makeMatrixType(Id component, int cols, int rows);
106 Id makeArrayType(Id element, unsigned size, int stride); // 0 means no stride decoration
107 Id makeRuntimeArray(Id element);
108 Id makeFunctionType(Id returnType, std::vector<Id>& paramTypes);
109 Id makeImageType(Id sampledType, Dim, bool depth, bool arrayed, bool ms, unsigned sampled, ImageFormat format);
110 Id makeSamplerType();
111 Id makeSampledImageType(Id imageType);
113 // For querying about types.
114 Id getTypeId(Id resultId) const { return module.getTypeId(resultId); }
115 Id getDerefTypeId(Id resultId) const;
116 Op getOpCode(Id id) const { return module.getInstruction(id)->getOpCode(); }
117 Op getTypeClass(Id typeId) const { return getOpCode(typeId); }
118 Op getMostBasicTypeClass(Id typeId) const;
119 int getNumComponents(Id resultId) const { return getNumTypeComponents(getTypeId(resultId)); }
120 int getNumTypeConstituents(Id typeId) const;
121 int getNumTypeComponents(Id typeId) const { return getNumTypeConstituents(typeId); }
122 Id getScalarTypeId(Id typeId) const;
123 Id getContainedTypeId(Id typeId) const;
124 Id getContainedTypeId(Id typeId, int) const;
125 StorageClass getTypeStorageClass(Id typeId) const { return module.getStorageClass(typeId); }
127 bool isPointer(Id resultId) const { return isPointerType(getTypeId(resultId)); }
128 bool isScalar(Id resultId) const { return isScalarType(getTypeId(resultId)); }
129 bool isVector(Id resultId) const { return isVectorType(getTypeId(resultId)); }
130 bool isMatrix(Id resultId) const { return isMatrixType(getTypeId(resultId)); }
131 bool isAggregate(Id resultId) const { return isAggregateType(getTypeId(resultId)); }
132 bool isSampledImage(Id resultId) const { return isSampledImageType(getTypeId(resultId)); }
134 bool isBoolType(Id typeId) const { return groupedTypes[OpTypeBool].size() > 0 && typeId == groupedTypes[OpTypeBool].back()->getResultId(); }
135 bool isPointerType(Id typeId) const { return getTypeClass(typeId) == OpTypePointer; }
136 bool isScalarType(Id typeId) const { return getTypeClass(typeId) == OpTypeFloat || getTypeClass(typeId) == OpTypeInt || getTypeClass(typeId) == OpTypeBool; }
137 bool isVectorType(Id typeId) const { return getTypeClass(typeId) == OpTypeVector; }
138 bool isMatrixType(Id typeId) const { return getTypeClass(typeId) == OpTypeMatrix; }
139 bool isStructType(Id typeId) const { return getTypeClass(typeId) == OpTypeStruct; }
140 bool isArrayType(Id typeId) const { return getTypeClass(typeId) == OpTypeArray; }
141 bool isAggregateType(Id typeId) const { return isArrayType(typeId) || isStructType(typeId); }
142 bool isImageType(Id typeId) const { return getTypeClass(typeId) == OpTypeImage; }
143 bool isSamplerType(Id typeId) const { return getTypeClass(typeId) == OpTypeSampler; }
144 bool isSampledImageType(Id typeId) const { return getTypeClass(typeId) == OpTypeSampledImage; }
146 bool isConstantOpCode(Op opcode) const;
147 bool isConstant(Id resultId) const { return isConstantOpCode(getOpCode(resultId)); }
148 bool isConstantScalar(Id resultId) const { return getOpCode(resultId) == OpConstant; }
149 unsigned int getConstantScalar(Id resultId) const { return module.getInstruction(resultId)->getImmediateOperand(0); }
150 StorageClass getStorageClass(Id resultId) const { return getTypeStorageClass(getTypeId(resultId)); }
152 int getTypeNumColumns(Id typeId) const
154 assert(isMatrixType(typeId));
155 return getNumTypeConstituents(typeId);
157 int getNumColumns(Id resultId) const { return getTypeNumColumns(getTypeId(resultId)); }
158 int getTypeNumRows(Id typeId) const
160 assert(isMatrixType(typeId));
161 return getNumTypeComponents(getContainedTypeId(typeId));
163 int getNumRows(Id resultId) const { return getTypeNumRows(getTypeId(resultId)); }
165 Dim getTypeDimensionality(Id typeId) const
167 assert(isImageType(typeId));
168 return (Dim)module.getInstruction(typeId)->getImmediateOperand(1);
170 Id getImageType(Id resultId) const
172 Id typeId = getTypeId(resultId);
173 assert(isImageType(typeId) || isSampledImageType(typeId));
174 return isSampledImageType(typeId) ? module.getInstruction(typeId)->getIdOperand(0) : typeId;
176 bool isArrayedImageType(Id typeId) const
178 assert(isImageType(typeId));
179 return module.getInstruction(typeId)->getImmediateOperand(3) != 0;
182 // For making new constants (will return old constant if the requested one was already made).
183 Id makeBoolConstant(bool b, bool specConstant = false);
184 Id makeIntConstant(int i, bool specConstant = false) { return makeIntConstant(makeIntType(32), (unsigned)i, specConstant); }
185 Id makeUintConstant(unsigned u, bool specConstant = false) { return makeIntConstant(makeUintType(32), u, specConstant); }
186 Id makeFloatConstant(float f, bool specConstant = false);
187 Id makeDoubleConstant(double d, bool specConstant = false);
189 // Turn the array of constants into a proper spv constant of the requested type.
190 Id makeCompositeConstant(Id type, std::vector<Id>& comps);
192 // Methods for adding information outside the CFG.
193 Instruction* addEntryPoint(ExecutionModel, Function*, const char* name);
194 void addExecutionMode(Function*, ExecutionMode mode, int value1 = -1, int value2 = -1, int value3 = -1);
195 void addName(Id, const char* name);
196 void addMemberName(Id, int member, const char* name);
197 void addLine(Id target, Id fileName, int line, int column);
198 void addDecoration(Id, Decoration, int num = -1);
199 void addMemberDecoration(Id, unsigned int member, Decoration, int num = -1);
201 // At the end of what block do the next create*() instructions go?
202 void setBuildPoint(Block* bp) { buildPoint = bp; }
203 Block* getBuildPoint() const { return buildPoint; }
205 // Make the main function. The returned pointer is only valid
206 // for the lifetime of this builder.
207 Function* makeMain();
209 // Make a shader-style function, and create its entry block if entry is non-zero.
210 // Return the function, pass back the entry.
211 // The returned pointer is only valid for the lifetime of this builder.
212 Function* makeFunctionEntry(Id returnType, const char* name, std::vector<Id>& paramTypes, Block **entry = 0);
214 // Create a return. An 'implicit' return is one not appearing in the source
215 // code. In the case of an implicit return, no post-return block is inserted.
216 void makeReturn(bool implicit, Id retVal = 0);
218 // Generate all the code needed to finish up a function.
219 void leaveFunction();
224 // Create a global or function local or IO variable.
225 Id createVariable(StorageClass, Id type, const char* name = 0);
227 // Create an imtermediate with an undefined value.
228 Id createUndefined(Id type);
230 // Store into an Id and return the l-value
231 void createStore(Id rValue, Id lValue);
233 // Load from an Id and return it
234 Id createLoad(Id lValue);
236 // Create an OpAccessChain instruction
237 Id createAccessChain(StorageClass, Id base, std::vector<Id>& offsets);
239 // Create an OpArrayLength instruction
240 Id createArrayLength(Id base, unsigned int member);
242 // Create an OpCompositeExtract instruction
243 Id createCompositeExtract(Id composite, Id typeId, unsigned index);
244 Id createCompositeExtract(Id composite, Id typeId, std::vector<unsigned>& indexes);
245 Id createCompositeInsert(Id object, Id composite, Id typeId, unsigned index);
246 Id createCompositeInsert(Id object, Id composite, Id typeId, std::vector<unsigned>& indexes);
248 Id createVectorExtractDynamic(Id vector, Id typeId, Id componentIndex);
249 Id createVectorInsertDynamic(Id vector, Id typeId, Id component, Id componentIndex);
251 void createNoResultOp(Op);
252 void createNoResultOp(Op, Id operand);
253 void createNoResultOp(Op, const std::vector<Id>& operands);
254 void createControlBarrier(Scope execution, Scope memory, MemorySemanticsMask);
255 void createMemoryBarrier(unsigned executionScope, unsigned memorySemantics);
256 Id createUnaryOp(Op, Id typeId, Id operand);
257 Id createBinOp(Op, Id typeId, Id operand1, Id operand2);
258 Id createTriOp(Op, Id typeId, Id operand1, Id operand2, Id operand3);
259 Id createOp(Op, Id typeId, const std::vector<Id>& operands);
260 Id createFunctionCall(spv::Function*, std::vector<spv::Id>&);
262 // Take an rvalue (source) and a set of channels to extract from it to
263 // make a new rvalue, which is returned.
264 Id createRvalueSwizzle(Id typeId, Id source, std::vector<unsigned>& channels);
266 // Take a copy of an lvalue (target) and a source of components, and set the
267 // source components into the lvalue where the 'channels' say to put them.
268 // An updated version of the target is returned.
269 // (No true lvalue or stores are used.)
270 Id createLvalueSwizzle(Id typeId, Id target, Id source, std::vector<unsigned>& channels);
272 // If the value passed in is an instruction and the precision is not NoPrecision,
273 // it gets tagged with the requested precision.
274 void setPrecision(Id /* value */, Decoration precision)
276 if (precision != NoPrecision) {
281 // Can smear a scalar to a vector for the following forms:
282 // - promoteScalar(scalar, vector) // smear scalar to width of vector
283 // - promoteScalar(vector, scalar) // smear scalar to width of vector
284 // - promoteScalar(pointer, scalar) // smear scalar to width of what pointer points to
285 // - promoteScalar(scalar, scalar) // do nothing
286 // Other forms are not allowed.
288 // Generally, the type of 'scalar' does not need to be the same type as the components in 'vector'.
289 // The type of the created vector is a vector of components of the same type as the scalar.
291 // Note: One of the arguments will change, with the result coming back that way rather than
292 // through the return value.
293 void promoteScalar(Decoration precision, Id& left, Id& right);
295 // Make a value by smearing the scalar to fill the type.
296 // vectorType should be the correct type for making a vector of scalarVal.
297 // (No conversions are done.)
298 Id smearScalar(Decoration precision, Id scalarVal, Id vectorType);
300 // Create a call to a built-in function.
301 Id createBuiltinCall(Decoration precision, Id resultType, Id builtins, int entryPoint, std::vector<Id>& args);
303 // List of parameters used to create a texture operation
304 struct TextureParameters {
320 // Select the correct texture operation based on all inputs, and emit the correct instruction
321 Id createTextureCall(Decoration precision, Id resultType, bool sparse, bool fetch, bool proj, bool gather, const TextureParameters&);
323 // Emit the OpTextureQuery* instruction that was passed in.
324 // Figure out the right return value and type, and return it.
325 Id createTextureQueryCall(Op, const TextureParameters&);
327 Id createSamplePositionCall(Decoration precision, Id, Id);
329 Id createBitFieldExtractCall(Decoration precision, Id, Id, Id, bool isSigned);
330 Id createBitFieldInsertCall(Decoration precision, Id, Id, Id, Id);
332 // Reduction comparision for composites: For equal and not-equal resulting in a scalar.
333 Id createCompositeCompare(Decoration precision, Id, Id, bool /* true if for equal, false if for not-equal */);
335 // OpCompositeConstruct
336 Id createCompositeConstruct(Id typeId, std::vector<Id>& constituents);
338 // vector or scalar constructor
339 Id createConstructor(Decoration precision, const std::vector<Id>& sources, Id resultTypeId);
341 // matrix constructor
342 Id createMatrixConstructor(Decoration precision, const std::vector<Id>& sources, Id constructee);
344 // Helper to use for building nested control flow with if-then-else.
347 If(Id condition, Builder& builder);
350 void makeBeginElse();
366 // Make a switch statement. A switch has 'numSegments' of pieces of code, not containing
367 // any case/default labels, all separated by one or more case/default labels. Each possible
368 // case value v is a jump to the caseValues[v] segment. The defaultSegment is also in this
369 // number space. How to compute the value is given by 'condition', as in switch(condition).
371 // The SPIR-V Builder will maintain the stack of post-switch merge blocks for nested switches.
373 // Use a defaultSegment < 0 if there is no default segment (to branch to post switch).
375 // Returns the right set of basic blocks to start each code segment with, so that the caller's
376 // recursion stack can hold the memory for it.
378 void makeSwitch(Id condition, int numSegments, std::vector<int>& caseValues, std::vector<int>& valueToSegment, int defaultSegment,
379 std::vector<Block*>& segmentBB); // return argument
381 // Add a branch to the innermost switch's merge block.
382 void addSwitchBreak();
384 // Move to the next code segment, passing in the return argument in makeSwitch()
385 void nextSwitchSegment(std::vector<Block*>& segmentBB, int segment);
387 // Finish off the innermost switch.
388 void endSwitch(std::vector<Block*>& segmentBB);
390 // Start the beginning of a new loop, and prepare the builder to
391 // generate code for the loop test.
392 // The loopTestFirst parameter is true when the loop test executes before
393 // the body. (It is false for do-while loops.)
394 void makeNewLoop(bool loopTestFirst);
396 // Add the branch for the loop test, based on the given condition.
397 // The true branch goes to the first block in the loop body, and
398 // the false branch goes to the loop's merge block. The builder insertion
399 // point will be placed at the start of the body.
400 void createLoopTestBranch(Id condition);
402 // Generate an unconditional branch to the loop body. The builder insertion
403 // point will be placed at the start of the body. Use this when there is
405 void createBranchToBody();
407 // Add a branch to the test of the current (innermost) loop.
408 // The way we generate code, that's also the loop header.
409 void createLoopContinue();
411 // Add an exit (e.g. "break") for the innermost loop that you're in
412 void createLoopExit();
414 // Close the innermost loop that you're in
418 // Access chain design for an R-Value vs. L-Value:
420 // There is a single access chain the builder is building at
421 // any particular time. Such a chain can be used to either to a load or
422 // a store, when desired.
424 // Expressions can be r-values, l-values, or both, or only r-values:
425 // a[b.c].d = .... // l-value
426 // ... = a[b.c].d; // r-value, that also looks like an l-value
427 // ++a[b.c].d; // r-value and l-value
428 // (x + y)[2]; // r-value only, can't possibly be l-value
430 // Computing an r-value means generating code. Hence,
431 // r-values should only be computed when they are needed, not speculatively.
433 // Computing an l-value means saving away information for later use in the compiler,
434 // no code is generated until the l-value is later dereferenced. It is okay
435 // to speculatively generate an l-value, just not okay to speculatively dereference it.
437 // The base of the access chain (the left-most variable or expression
438 // from which everything is based) can be set either as an l-value
439 // or as an r-value. Most efficient would be to set an l-value if one
440 // is available. If an expression was evaluated, the resulting r-value
441 // can be set as the chain base.
443 // The users of this single access chain can save and restore if they
444 // want to nest or manage multiple chains.
448 Id base; // for l-values, pointer to the base object, for r-values, the base object
449 std::vector<Id> indexChain;
450 Id instr; // cache the instruction that generates this access chain
451 std::vector<unsigned> swizzle; // each std::vector element selects the next GLSL component number
452 Id component; // a dynamic component index, can coexist with a swizzle, done after the swizzle, NoResult if not present
453 Id preSwizzleBaseType; // dereferenced type, before swizzle or component is applied; NoType unless a swizzle or component is present
454 bool isRValue; // true if 'base' is an r-value, otherwise, base is an l-value
458 // the SPIR-V builder maintains a single active chain that
459 // the following methods operated on
462 // for external save and restore
463 AccessChain getAccessChain() { return accessChain; }
464 void setAccessChain(AccessChain newChain) { accessChain = newChain; }
467 void clearAccessChain();
469 // set new base as an l-value base
470 void setAccessChainLValue(Id lValue)
472 assert(isPointer(lValue));
473 accessChain.base = lValue;
476 // set new base value as an r-value
477 void setAccessChainRValue(Id rValue)
479 accessChain.isRValue = true;
480 accessChain.base = rValue;
483 // push offset onto the end of the chain
484 void accessChainPush(Id offset)
486 accessChain.indexChain.push_back(offset);
489 // push new swizzle onto the end of any existing swizzle, merging into a single swizzle
490 void accessChainPushSwizzle(std::vector<unsigned>& swizzle, Id preSwizzleBaseType);
492 // push a variable component selection onto the access chain; supporting only one, so unsided
493 void accessChainPushComponent(Id component, Id preSwizzleBaseType)
495 accessChain.component = component;
496 if (accessChain.preSwizzleBaseType == NoType)
497 accessChain.preSwizzleBaseType = preSwizzleBaseType;
500 // use accessChain and swizzle to store value
501 void accessChainStore(Id rvalue);
503 // use accessChain and swizzle to load an r-value
504 Id accessChainLoad(Id ResultType);
506 // get the direct pointer for an l-value
507 Id accessChainGetLValue();
509 void dump(std::vector<unsigned int>&) const;
512 Id makeIntConstant(Id typeId, unsigned value, bool specConstant);
513 Id findScalarConstant(Op typeClass, Op opcode, Id typeId, unsigned value) const;
514 Id findScalarConstant(Op typeClass, Op opcode, Id typeId, unsigned v1, unsigned v2) const;
515 Id findCompositeConstant(Op typeClass, std::vector<Id>& comps) const;
516 Id collapseAccessChain();
517 void transferAccessChainSwizzle(bool dynamic);
518 void simplifyAccessChainSwizzle();
519 void createAndSetNoPredecessorBlock(const char*);
520 void createBranch(Block* block);
521 void createSelectionMerge(Block* mergeBlock, unsigned int control);
522 void createLoopMerge(Block* mergeBlock, Block* continueBlock, unsigned int control);
523 void createConditionalBranch(Id condition, Block* thenBlock, Block* elseBlock);
524 void dumpInstructions(std::vector<unsigned int>&, const std::vector<std::unique_ptr<Instruction> >&) const;
526 struct Loop; // Defined below.
527 void createBranchToLoopHeaderFromInside(const Loop& loop);
529 SourceLanguage source;
531 std::vector<const char*> extensions;
532 AddressingModel addressModel;
533 MemoryModel memoryModel;
534 std::vector<spv::Capability> capabilities;
539 Function* mainFunction;
540 AccessChain accessChain;
542 // special blocks of instructions for output
543 std::vector<std::unique_ptr<Instruction> > imports;
544 std::vector<std::unique_ptr<Instruction> > entryPoints;
545 std::vector<std::unique_ptr<Instruction> > executionModes;
546 std::vector<std::unique_ptr<Instruction> > names;
547 std::vector<std::unique_ptr<Instruction> > lines;
548 std::vector<std::unique_ptr<Instruction> > decorations;
549 std::vector<std::unique_ptr<Instruction> > constantsTypesGlobals;
550 std::vector<std::unique_ptr<Instruction> > externals;
551 std::vector<std::unique_ptr<Function> > functions;
553 // not output, internally used for quick & dirty canonical (unique) creation
554 std::vector<Instruction*> groupedConstants[OpConstant]; // all types appear before OpConstant
555 std::vector<Instruction*> groupedTypes[OpConstant];
558 std::stack<Block*> switchMerges;
560 // Data that needs to be kept in order to properly handle loops.
562 // Constructs a default Loop structure containing new header, merge, and
563 // body blocks for the current function.
564 // The testFirst argument indicates whether the loop test executes at
565 // the top of the loop rather than at the bottom. In the latter case,
566 // also create a phi instruction whose value indicates whether we're on
567 // the first iteration of the loop. The phi instruction is initialized
568 // with no values or predecessor operands.
569 Loop(Builder& builder, bool testFirst);
571 // The function containing the loop.
572 Function* const function;
573 // The header is the first block generated for the loop.
574 // It dominates all the blocks in the loop, i.e. it is always
575 // executed before any others.
576 // If the loop test is executed before the body (as in "while" and
577 // "for" loops), then the header begins with the test code.
578 // Otherwise, the loop is a "do-while" loop and the header contains the
579 // start of the body of the loop (if the body exists).
581 // The merge block marks the end of the loop. Control is transferred
582 // to the merge block when either the loop test fails, or when a
583 // nested "break" is encountered.
585 // The body block is the first basic block in the body of the loop, i.e.
586 // the code that is to be repeatedly executed, aside from loop control.
587 // This member is null until we generate code that references the loop
590 // True when the loop test executes before the body.
591 const bool testFirst;
592 // When the test executes after the body, this is defined as the phi
593 // instruction that tells us whether we are on the first iteration of
594 // the loop. Otherwise this is null. This is non-const because
595 // it has to be initialized outside of the initializer-list.
596 Instruction* isFirstIteration;
600 std::stack<Loop> loops;
601 }; // end Builder class
603 // Use for non-fatal notes about what's not complete
604 void TbdFunctionality(const char*);
606 // Use for fatal missing functionality
607 void MissingFunctionality(const char*);
609 }; // end spv namespace
611 #endif // SpvBuilder_H