blob: 38dc1fa39536b2458fb111faece8a8c13e51c906 [file] [log] [blame]
Dan Albert287553d2017-02-16 10:47:51 -08001//
2//Copyright (C) 2014-2015 LunarG, Inc.
3//Copyright (C) 2015-2016 Google, Inc.
4//
5//All rights reserved.
6//
7//Redistribution and use in source and binary forms, with or without
8//modification, are permitted provided that the following conditions
9//are met:
10//
11// Redistributions of source code must retain the above copyright
12// notice, this list of conditions and the following disclaimer.
13//
14// Redistributions in binary form must reproduce the above
15// copyright notice, this list of conditions and the following
16// disclaimer in the documentation and/or other materials provided
17// with the distribution.
18//
19// Neither the name of 3Dlabs Inc. Ltd. nor the names of its
20// contributors may be used to endorse or promote products derived
21// from this software without specific prior written permission.
22//
23//THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
24//"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
25//LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
26//FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
27//COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
28//INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
29//BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
30//LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
31//CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32//LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
33//ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
34//POSSIBILITY OF SUCH DAMAGE.
35
36//
37// "Builder" is an interface to fully build SPIR-V IR. Allocate one of
38// these to build (a thread safe) internal SPIR-V representation (IR),
39// and then dump it as a binary stream according to the SPIR-V specification.
40//
41// A Builder has a 1:1 relationship with a SPIR-V module.
42//
43
44#pragma once
45#ifndef SpvBuilder_H
46#define SpvBuilder_H
47
48#include "Logger.h"
49#include "spirv.hpp"
50#include "spvIR.h"
51
52#include <algorithm>
53#include <map>
54#include <memory>
55#include <set>
56#include <sstream>
57#include <stack>
58
59namespace spv {
60
61class Builder {
62public:
63 Builder(unsigned int userNumber, SpvBuildLogger* logger);
64 virtual ~Builder();
65
66 static const int maxMatrixSize = 4;
67
68 void setSource(spv::SourceLanguage lang, int version)
69 {
70 source = lang;
71 sourceVersion = version;
72 }
73 void addSourceExtension(const char* ext) { sourceExtensions.push_back(ext); }
74 void addExtensions(const char* ext) { extensions.push_back(ext); }
75 Id import(const char*);
76 void setMemoryModel(spv::AddressingModel addr, spv::MemoryModel mem)
77 {
78 addressModel = addr;
79 memoryModel = mem;
80 }
81
82 void addCapability(spv::Capability cap) { capabilities.insert(cap); }
83
84 // To get a new <id> for anything needing a new one.
85 Id getUniqueId() { return ++uniqueId; }
86
87 // To get a set of new <id>s, e.g., for a set of function parameters
88 Id getUniqueIds(int numIds)
89 {
90 Id id = uniqueId + 1;
91 uniqueId += numIds;
92 return id;
93 }
94
95 // For creating new types (will return old type if the requested one was already made).
96 Id makeVoidType();
97 Id makeBoolType();
98 Id makePointer(StorageClass, Id type);
99 Id makeIntegerType(int width, bool hasSign); // generic
100 Id makeIntType(int width) { return makeIntegerType(width, true); }
101 Id makeUintType(int width) { return makeIntegerType(width, false); }
102 Id makeFloatType(int width);
103 Id makeStructType(const std::vector<Id>& members, const char*);
104 Id makeStructResultType(Id type0, Id type1);
105 Id makeVectorType(Id component, int size);
106 Id makeMatrixType(Id component, int cols, int rows);
107 Id makeArrayType(Id element, Id sizeId, int stride); // 0 stride means no stride decoration
108 Id makeRuntimeArray(Id element);
109 Id makeFunctionType(Id returnType, const std::vector<Id>& paramTypes);
110 Id makeImageType(Id sampledType, Dim, bool depth, bool arrayed, bool ms, unsigned sampled, ImageFormat format);
111 Id makeSamplerType();
112 Id makeSampledImageType(Id imageType);
113
114 // For querying about types.
115 Id getTypeId(Id resultId) const { return module.getTypeId(resultId); }
116 Id getDerefTypeId(Id resultId) const;
117 Op getOpCode(Id id) const { return module.getInstruction(id)->getOpCode(); }
118 Op getTypeClass(Id typeId) const { return getOpCode(typeId); }
119 Op getMostBasicTypeClass(Id typeId) const;
120 int getNumComponents(Id resultId) const { return getNumTypeComponents(getTypeId(resultId)); }
121 int getNumTypeConstituents(Id typeId) const;
122 int getNumTypeComponents(Id typeId) const { return getNumTypeConstituents(typeId); }
123 Id getScalarTypeId(Id typeId) const;
124 Id getContainedTypeId(Id typeId) const;
125 Id getContainedTypeId(Id typeId, int) const;
126 StorageClass getTypeStorageClass(Id typeId) const { return module.getStorageClass(typeId); }
127 ImageFormat getImageTypeFormat(Id typeId) const { return (ImageFormat)module.getInstruction(typeId)->getImmediateOperand(6); }
128
129 bool isPointer(Id resultId) const { return isPointerType(getTypeId(resultId)); }
130 bool isScalar(Id resultId) const { return isScalarType(getTypeId(resultId)); }
131 bool isVector(Id resultId) const { return isVectorType(getTypeId(resultId)); }
132 bool isMatrix(Id resultId) const { return isMatrixType(getTypeId(resultId)); }
133 bool isAggregate(Id resultId) const { return isAggregateType(getTypeId(resultId)); }
134 bool isSampledImage(Id resultId) const { return isSampledImageType(getTypeId(resultId)); }
135
136 bool isBoolType(Id typeId) const { return groupedTypes[OpTypeBool].size() > 0 && typeId == groupedTypes[OpTypeBool].back()->getResultId(); }
137 bool isPointerType(Id typeId) const { return getTypeClass(typeId) == OpTypePointer; }
138 bool isScalarType(Id typeId) const { return getTypeClass(typeId) == OpTypeFloat || getTypeClass(typeId) == OpTypeInt || getTypeClass(typeId) == OpTypeBool; }
139 bool isVectorType(Id typeId) const { return getTypeClass(typeId) == OpTypeVector; }
140 bool isMatrixType(Id typeId) const { return getTypeClass(typeId) == OpTypeMatrix; }
141 bool isStructType(Id typeId) const { return getTypeClass(typeId) == OpTypeStruct; }
142 bool isArrayType(Id typeId) const { return getTypeClass(typeId) == OpTypeArray; }
143 bool isAggregateType(Id typeId) const { return isArrayType(typeId) || isStructType(typeId); }
144 bool isImageType(Id typeId) const { return getTypeClass(typeId) == OpTypeImage; }
145 bool isSamplerType(Id typeId) const { return getTypeClass(typeId) == OpTypeSampler; }
146 bool isSampledImageType(Id typeId) const { return getTypeClass(typeId) == OpTypeSampledImage; }
147
148 bool isConstantOpCode(Op opcode) const;
149 bool isSpecConstantOpCode(Op opcode) const;
150 bool isConstant(Id resultId) const { return isConstantOpCode(getOpCode(resultId)); }
151 bool isConstantScalar(Id resultId) const { return getOpCode(resultId) == OpConstant; }
152 bool isSpecConstant(Id resultId) const { return isSpecConstantOpCode(getOpCode(resultId)); }
153 unsigned int getConstantScalar(Id resultId) const { return module.getInstruction(resultId)->getImmediateOperand(0); }
154 StorageClass getStorageClass(Id resultId) const { return getTypeStorageClass(getTypeId(resultId)); }
155
156 int getTypeNumColumns(Id typeId) const
157 {
158 assert(isMatrixType(typeId));
159 return getNumTypeConstituents(typeId);
160 }
161 int getNumColumns(Id resultId) const { return getTypeNumColumns(getTypeId(resultId)); }
162 int getTypeNumRows(Id typeId) const
163 {
164 assert(isMatrixType(typeId));
165 return getNumTypeComponents(getContainedTypeId(typeId));
166 }
167 int getNumRows(Id resultId) const { return getTypeNumRows(getTypeId(resultId)); }
168
169 Dim getTypeDimensionality(Id typeId) const
170 {
171 assert(isImageType(typeId));
172 return (Dim)module.getInstruction(typeId)->getImmediateOperand(1);
173 }
174 Id getImageType(Id resultId) const
175 {
176 Id typeId = getTypeId(resultId);
177 assert(isImageType(typeId) || isSampledImageType(typeId));
178 return isSampledImageType(typeId) ? module.getInstruction(typeId)->getIdOperand(0) : typeId;
179 }
180 bool isArrayedImageType(Id typeId) const
181 {
182 assert(isImageType(typeId));
183 return module.getInstruction(typeId)->getImmediateOperand(3) != 0;
184 }
185
186 // For making new constants (will return old constant if the requested one was already made).
187 Id makeBoolConstant(bool b, bool specConstant = false);
188 Id makeIntConstant(int i, bool specConstant = false) { return makeIntConstant(makeIntType(32), (unsigned)i, specConstant); }
189 Id makeUintConstant(unsigned u, bool specConstant = false) { return makeIntConstant(makeUintType(32), u, specConstant); }
190 Id makeInt64Constant(long long i, bool specConstant = false) { return makeInt64Constant(makeIntType(64), (unsigned long long)i, specConstant); }
191 Id makeUint64Constant(unsigned long long u, bool specConstant = false) { return makeInt64Constant(makeUintType(64), u, specConstant); }
192 Id makeFloatConstant(float f, bool specConstant = false);
193 Id makeDoubleConstant(double d, bool specConstant = false);
194
195 // Turn the array of constants into a proper spv constant of the requested type.
196 Id makeCompositeConstant(Id type, std::vector<Id>& comps, bool specConst = false);
197
198 // Methods for adding information outside the CFG.
199 Instruction* addEntryPoint(ExecutionModel, Function*, const char* name);
200 void addExecutionMode(Function*, ExecutionMode mode, int value1 = -1, int value2 = -1, int value3 = -1);
201 void addName(Id, const char* name);
202 void addMemberName(Id, int member, const char* name);
203 void addLine(Id target, Id fileName, int line, int column);
204 void addDecoration(Id, Decoration, int num = -1);
205 void addMemberDecoration(Id, unsigned int member, Decoration, int num = -1);
206
207 // At the end of what block do the next create*() instructions go?
208 void setBuildPoint(Block* bp) { buildPoint = bp; }
209 Block* getBuildPoint() const { return buildPoint; }
210
211 // Make the entry-point function. The returned pointer is only valid
212 // for the lifetime of this builder.
213 Function* makeEntryPoint(const char*);
214
215 // Make a shader-style function, and create its entry block if entry is non-zero.
216 // Return the function, pass back the entry.
217 // The returned pointer is only valid for the lifetime of this builder.
218 Function* makeFunctionEntry(Decoration precision, Id returnType, const char* name, const std::vector<Id>& paramTypes,
219 const std::vector<Decoration>& precisions, Block **entry = 0);
220
221 // Create a return. An 'implicit' return is one not appearing in the source
222 // code. In the case of an implicit return, no post-return block is inserted.
223 void makeReturn(bool implicit, Id retVal = 0);
224
225 // Generate all the code needed to finish up a function.
226 void leaveFunction();
227
228 // Create a discard.
229 void makeDiscard();
230
231 // Create a global or function local or IO variable.
232 Id createVariable(StorageClass, Id type, const char* name = 0);
233
234 // Create an intermediate with an undefined value.
235 Id createUndefined(Id type);
236
237 // Store into an Id and return the l-value
238 void createStore(Id rValue, Id lValue);
239
240 // Load from an Id and return it
241 Id createLoad(Id lValue);
242
243 // Create an OpAccessChain instruction
244 Id createAccessChain(StorageClass, Id base, std::vector<Id>& offsets);
245
246 // Create an OpArrayLength instruction
247 Id createArrayLength(Id base, unsigned int member);
248
249 // Create an OpCompositeExtract instruction
250 Id createCompositeExtract(Id composite, Id typeId, unsigned index);
251 Id createCompositeExtract(Id composite, Id typeId, std::vector<unsigned>& indexes);
252 Id createCompositeInsert(Id object, Id composite, Id typeId, unsigned index);
253 Id createCompositeInsert(Id object, Id composite, Id typeId, std::vector<unsigned>& indexes);
254
255 Id createVectorExtractDynamic(Id vector, Id typeId, Id componentIndex);
256 Id createVectorInsertDynamic(Id vector, Id typeId, Id component, Id componentIndex);
257
258 void createNoResultOp(Op);
259 void createNoResultOp(Op, Id operand);
260 void createNoResultOp(Op, const std::vector<Id>& operands);
261 void createControlBarrier(Scope execution, Scope memory, MemorySemanticsMask);
262 void createMemoryBarrier(unsigned executionScope, unsigned memorySemantics);
263 Id createUnaryOp(Op, Id typeId, Id operand);
264 Id createBinOp(Op, Id typeId, Id operand1, Id operand2);
265 Id createTriOp(Op, Id typeId, Id operand1, Id operand2, Id operand3);
266 Id createOp(Op, Id typeId, const std::vector<Id>& operands);
267 Id createFunctionCall(spv::Function*, std::vector<spv::Id>&);
268 Id createSpecConstantOp(Op, Id typeId, const std::vector<spv::Id>& operands, const std::vector<unsigned>& literals);
269
270 // Take an rvalue (source) and a set of channels to extract from it to
271 // make a new rvalue, which is returned.
272 Id createRvalueSwizzle(Decoration precision, Id typeId, Id source, std::vector<unsigned>& channels);
273
274 // Take a copy of an lvalue (target) and a source of components, and set the
275 // source components into the lvalue where the 'channels' say to put them.
276 // An updated version of the target is returned.
277 // (No true lvalue or stores are used.)
278 Id createLvalueSwizzle(Id typeId, Id target, Id source, std::vector<unsigned>& channels);
279
280 // If both the id and precision are valid, the id
281 // gets tagged with the requested precision.
282 // The passed in id is always the returned id, to simplify use patterns.
283 Id setPrecision(Id id, Decoration precision)
284 {
285 if (precision != NoPrecision && id != NoResult)
286 addDecoration(id, precision);
287
288 return id;
289 }
290
291 // Can smear a scalar to a vector for the following forms:
292 // - promoteScalar(scalar, vector) // smear scalar to width of vector
293 // - promoteScalar(vector, scalar) // smear scalar to width of vector
294 // - promoteScalar(pointer, scalar) // smear scalar to width of what pointer points to
295 // - promoteScalar(scalar, scalar) // do nothing
296 // Other forms are not allowed.
297 //
298 // Generally, the type of 'scalar' does not need to be the same type as the components in 'vector'.
299 // The type of the created vector is a vector of components of the same type as the scalar.
300 //
301 // Note: One of the arguments will change, with the result coming back that way rather than
302 // through the return value.
303 void promoteScalar(Decoration precision, Id& left, Id& right);
304
305 // Make a value by smearing the scalar to fill the type.
306 // vectorType should be the correct type for making a vector of scalarVal.
307 // (No conversions are done.)
308 Id smearScalar(Decoration precision, Id scalarVal, Id vectorType);
309
310 // Create a call to a built-in function.
311 Id createBuiltinCall(Id resultType, Id builtins, int entryPoint, std::vector<Id>& args);
312
313 // List of parameters used to create a texture operation
314 struct TextureParameters {
315 Id sampler;
316 Id coords;
317 Id bias;
318 Id lod;
319 Id Dref;
320 Id offset;
321 Id offsets;
322 Id gradX;
323 Id gradY;
324 Id sample;
325 Id component;
326 Id texelOut;
327 Id lodClamp;
328 };
329
330 // Select the correct texture operation based on all inputs, and emit the correct instruction
331 Id createTextureCall(Decoration precision, Id resultType, bool sparse, bool fetch, bool proj, bool gather, bool noImplicit, const TextureParameters&);
332
333 // Emit the OpTextureQuery* instruction that was passed in.
334 // Figure out the right return value and type, and return it.
335 Id createTextureQueryCall(Op, const TextureParameters&);
336
337 Id createSamplePositionCall(Decoration precision, Id, Id);
338
339 Id createBitFieldExtractCall(Decoration precision, Id, Id, Id, bool isSigned);
340 Id createBitFieldInsertCall(Decoration precision, Id, Id, Id, Id);
341
342 // Reduction comparison for composites: For equal and not-equal resulting in a scalar.
343 Id createCompositeCompare(Decoration precision, Id, Id, bool /* true if for equal, false if for not-equal */);
344
345 // OpCompositeConstruct
346 Id createCompositeConstruct(Id typeId, std::vector<Id>& constituents);
347
348 // vector or scalar constructor
349 Id createConstructor(Decoration precision, const std::vector<Id>& sources, Id resultTypeId);
350
351 // matrix constructor
352 Id createMatrixConstructor(Decoration precision, const std::vector<Id>& sources, Id constructee);
353
354 // Helper to use for building nested control flow with if-then-else.
355 class If {
356 public:
357 If(Id condition, Builder& builder);
358 ~If() {}
359
360 void makeBeginElse();
361 void makeEndIf();
362
363 private:
364 If(const If&);
365 If& operator=(If&);
366
367 Builder& builder;
368 Id condition;
369 Function* function;
370 Block* headerBlock;
371 Block* thenBlock;
372 Block* elseBlock;
373 Block* mergeBlock;
374 };
375
376 // Make a switch statement. A switch has 'numSegments' of pieces of code, not containing
377 // any case/default labels, all separated by one or more case/default labels. Each possible
378 // case value v is a jump to the caseValues[v] segment. The defaultSegment is also in this
379 // number space. How to compute the value is given by 'condition', as in switch(condition).
380 //
381 // The SPIR-V Builder will maintain the stack of post-switch merge blocks for nested switches.
382 //
383 // Use a defaultSegment < 0 if there is no default segment (to branch to post switch).
384 //
385 // Returns the right set of basic blocks to start each code segment with, so that the caller's
386 // recursion stack can hold the memory for it.
387 //
388 void makeSwitch(Id condition, int numSegments, std::vector<int>& caseValues, std::vector<int>& valueToSegment, int defaultSegment,
389 std::vector<Block*>& segmentBB); // return argument
390
391 // Add a branch to the innermost switch's merge block.
392 void addSwitchBreak();
393
394 // Move to the next code segment, passing in the return argument in makeSwitch()
395 void nextSwitchSegment(std::vector<Block*>& segmentBB, int segment);
396
397 // Finish off the innermost switch.
398 void endSwitch(std::vector<Block*>& segmentBB);
399
400 struct LoopBlocks {
401 LoopBlocks(Block& head, Block& body, Block& merge, Block& continue_target) :
402 head(head), body(body), merge(merge), continue_target(continue_target) { }
403 Block &head, &body, &merge, &continue_target;
404 private:
405 LoopBlocks();
406 LoopBlocks& operator=(const LoopBlocks&);
407 };
408
409 // Start a new loop and prepare the builder to generate code for it. Until
410 // closeLoop() is called for this loop, createLoopContinue() and
411 // createLoopExit() will target its corresponding blocks.
412 LoopBlocks& makeNewLoop();
413
414 // Create a new block in the function containing the build point. Memory is
415 // owned by the function object.
416 Block& makeNewBlock();
417
418 // Add a branch to the continue_target of the current (innermost) loop.
419 void createLoopContinue();
420
421 // Add an exit (e.g. "break") from the innermost loop that we're currently
422 // in.
423 void createLoopExit();
424
425 // Close the innermost loop that you're in
426 void closeLoop();
427
428 //
429 // Access chain design for an R-Value vs. L-Value:
430 //
431 // There is a single access chain the builder is building at
432 // any particular time. Such a chain can be used to either to a load or
433 // a store, when desired.
434 //
435 // Expressions can be r-values, l-values, or both, or only r-values:
436 // a[b.c].d = .... // l-value
437 // ... = a[b.c].d; // r-value, that also looks like an l-value
438 // ++a[b.c].d; // r-value and l-value
439 // (x + y)[2]; // r-value only, can't possibly be l-value
440 //
441 // Computing an r-value means generating code. Hence,
442 // r-values should only be computed when they are needed, not speculatively.
443 //
444 // Computing an l-value means saving away information for later use in the compiler,
445 // no code is generated until the l-value is later dereferenced. It is okay
446 // to speculatively generate an l-value, just not okay to speculatively dereference it.
447 //
448 // The base of the access chain (the left-most variable or expression
449 // from which everything is based) can be set either as an l-value
450 // or as an r-value. Most efficient would be to set an l-value if one
451 // is available. If an expression was evaluated, the resulting r-value
452 // can be set as the chain base.
453 //
454 // The users of this single access chain can save and restore if they
455 // want to nest or manage multiple chains.
456 //
457
458 struct AccessChain {
459 Id base; // for l-values, pointer to the base object, for r-values, the base object
460 std::vector<Id> indexChain;
461 Id instr; // cache the instruction that generates this access chain
462 std::vector<unsigned> swizzle; // each std::vector element selects the next GLSL component number
463 Id component; // a dynamic component index, can coexist with a swizzle, done after the swizzle, NoResult if not present
464 Id preSwizzleBaseType; // dereferenced type, before swizzle or component is applied; NoType unless a swizzle or component is present
465 bool isRValue; // true if 'base' is an r-value, otherwise, base is an l-value
466 };
467
468 //
469 // the SPIR-V builder maintains a single active chain that
470 // the following methods operate on
471 //
472
473 // for external save and restore
474 AccessChain getAccessChain() { return accessChain; }
475 void setAccessChain(AccessChain newChain) { accessChain = newChain; }
476
477 // clear accessChain
478 void clearAccessChain();
479
480 // set new base as an l-value base
481 void setAccessChainLValue(Id lValue)
482 {
483 assert(isPointer(lValue));
484 accessChain.base = lValue;
485 }
486
487 // set new base value as an r-value
488 void setAccessChainRValue(Id rValue)
489 {
490 accessChain.isRValue = true;
491 accessChain.base = rValue;
492 }
493
494 // push offset onto the end of the chain
495 void accessChainPush(Id offset)
496 {
497 accessChain.indexChain.push_back(offset);
498 }
499
500 // push new swizzle onto the end of any existing swizzle, merging into a single swizzle
501 void accessChainPushSwizzle(std::vector<unsigned>& swizzle, Id preSwizzleBaseType);
502
503 // push a variable component selection onto the access chain; supporting only one, so unsided
504 void accessChainPushComponent(Id component, Id preSwizzleBaseType)
505 {
506 accessChain.component = component;
507 if (accessChain.preSwizzleBaseType == NoType)
508 accessChain.preSwizzleBaseType = preSwizzleBaseType;
509 }
510
511 // use accessChain and swizzle to store value
512 void accessChainStore(Id rvalue);
513
514 // use accessChain and swizzle to load an r-value
515 Id accessChainLoad(Decoration precision, Id ResultType);
516
517 // get the direct pointer for an l-value
518 Id accessChainGetLValue();
519
520 // Get the inferred SPIR-V type of the result of the current access chain,
521 // based on the type of the base and the chain of dereferences.
522 Id accessChainGetInferredType();
523
524 // Remove OpDecorate instructions whose operands are defined in unreachable
525 // blocks.
526 void eliminateDeadDecorations();
527 void dump(std::vector<unsigned int>&) const;
528
529 void createBranch(Block* block);
530 void createConditionalBranch(Id condition, Block* thenBlock, Block* elseBlock);
531 void createLoopMerge(Block* mergeBlock, Block* continueBlock, unsigned int control);
532
533 // Sets to generate opcode for specialization constants.
534 void setToSpecConstCodeGenMode() { generatingOpCodeForSpecConst = true; }
535 // Sets to generate opcode for non-specialization constants (normal mode).
536 void setToNormalCodeGenMode() { generatingOpCodeForSpecConst = false; }
537 // Check if the builder is generating code for spec constants.
538 bool isInSpecConstCodeGenMode() { return generatingOpCodeForSpecConst; }
539
540 protected:
541 Id makeIntConstant(Id typeId, unsigned value, bool specConstant);
542 Id makeInt64Constant(Id typeId, unsigned long long value, bool specConstant);
543 Id findScalarConstant(Op typeClass, Op opcode, Id typeId, unsigned value) const;
544 Id findScalarConstant(Op typeClass, Op opcode, Id typeId, unsigned v1, unsigned v2) const;
545 Id findCompositeConstant(Op typeClass, std::vector<Id>& comps) const;
546 Id collapseAccessChain();
547 void transferAccessChainSwizzle(bool dynamic);
548 void simplifyAccessChainSwizzle();
549 void createAndSetNoPredecessorBlock(const char*);
550 void createSelectionMerge(Block* mergeBlock, unsigned int control);
551 void dumpInstructions(std::vector<unsigned int>&, const std::vector<std::unique_ptr<Instruction> >&) const;
552
553 SourceLanguage source;
554 int sourceVersion;
555 std::vector<const char*> extensions;
556 std::vector<const char*> sourceExtensions;
557 AddressingModel addressModel;
558 MemoryModel memoryModel;
559 std::set<spv::Capability> capabilities;
560 int builderNumber;
561 Module module;
562 Block* buildPoint;
563 Id uniqueId;
564 Function* mainFunction;
565 bool generatingOpCodeForSpecConst;
566 AccessChain accessChain;
567
568 // special blocks of instructions for output
569 std::vector<std::unique_ptr<Instruction> > imports;
570 std::vector<std::unique_ptr<Instruction> > entryPoints;
571 std::vector<std::unique_ptr<Instruction> > executionModes;
572 std::vector<std::unique_ptr<Instruction> > names;
573 std::vector<std::unique_ptr<Instruction> > lines;
574 std::vector<std::unique_ptr<Instruction> > decorations;
575 std::vector<std::unique_ptr<Instruction> > constantsTypesGlobals;
576 std::vector<std::unique_ptr<Instruction> > externals;
577 std::vector<std::unique_ptr<Function> > functions;
578
579 // not output, internally used for quick & dirty canonical (unique) creation
580 std::vector<Instruction*> groupedConstants[OpConstant]; // all types appear before OpConstant
581 std::vector<Instruction*> groupedTypes[OpConstant];
582
583 // stack of switches
584 std::stack<Block*> switchMerges;
585
586 // Our loop stack.
587 std::stack<LoopBlocks> loops;
588
589 // The stream for outputing warnings and errors.
590 SpvBuildLogger* logger;
591}; // end Builder class
592
593}; // end spv namespace
594
595#endif // SpvBuilder_H