b09ba04c3472c26b6169bb5f4d58a55faef7f417
[platform/upstream/glslang.git] / SPIRV / SpvBuilder.h
1 //
2 // Copyright (C) 2014-2015 LunarG, Inc.
3 // Copyright (C) 2015-2016 Google, Inc.
4 // Copyright (C) 2017 ARM Limited.
5 //
6 // All rights reserved.
7 //
8 // Redistribution and use in source and binary forms, with or without
9 // modification, are permitted provided that the following conditions
10 // are met:
11 //
12 //    Redistributions of source code must retain the above copyright
13 //    notice, this list of conditions and the following disclaimer.
14 //
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.
19 //
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.
23 //
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.
36
37 //
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.
41 //
42 // A Builder has a 1:1 relationship with a SPIR-V module.
43 //
44
45 #pragma once
46 #ifndef SpvBuilder_H
47 #define SpvBuilder_H
48
49 #include "Logger.h"
50 #include "spirv.hpp"
51 #include "spvIR.h"
52
53 #include <algorithm>
54 #include <map>
55 #include <memory>
56 #include <set>
57 #include <sstream>
58 #include <stack>
59 #include <unordered_map>
60
61 namespace spv {
62
63 class Builder {
64 public:
65     Builder(unsigned int spvVersion, unsigned int userNumber, SpvBuildLogger* logger);
66     virtual ~Builder();
67
68     static const int maxMatrixSize = 4;
69
70     unsigned int getSpvVersion() const { return spvVersion; }
71
72     void setSource(spv::SourceLanguage lang, int version)
73     {
74         source = lang;
75         sourceVersion = version;
76     }
77     void setSourceFile(const std::string& file)
78     {
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));
83     }
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)
91     {
92         addressModel = addr;
93         memoryModel = mem;
94     }
95
96     void addCapability(spv::Capability cap) { capabilities.insert(cap); }
97
98     // To get a new <id> for anything needing a new one.
99     Id getUniqueId() { return ++uniqueId; }
100
101     // To get a set of new <id>s, e.g., for a set of function parameters
102     Id getUniqueIds(int numIds)
103     {
104         Id id = uniqueId + 1;
105         uniqueId += numIds;
106         return id;
107     }
108
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);
114
115     // For creating new types (will return old type if the requested one was already made).
116     Id makeVoidType();
117     Id makeBoolType();
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);
133
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); }
148
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)); }
155
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;
171
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)); }
179
180     int getScalarTypeWidth(Id typeId) const
181     {
182         Id scalarTypeId = getScalarTypeId(typeId);
183         assert(getTypeClass(scalarTypeId) == OpTypeInt || getTypeClass(scalarTypeId) == OpTypeFloat);
184         return module.getInstruction(scalarTypeId)->getImmediateOperand(0);
185     }
186
187     int getTypeNumColumns(Id typeId) const
188     {
189         assert(isMatrixType(typeId));
190         return getNumTypeConstituents(typeId);
191     }
192     int getNumColumns(Id resultId) const { return getTypeNumColumns(getTypeId(resultId)); }
193     int getTypeNumRows(Id typeId) const
194     {
195         assert(isMatrixType(typeId));
196         return getNumTypeComponents(getContainedTypeId(typeId));
197     }
198     int getNumRows(Id resultId) const { return getTypeNumRows(getTypeId(resultId)); }
199
200     Dim getTypeDimensionality(Id typeId) const
201     {
202         assert(isImageType(typeId));
203         return (Dim)module.getInstruction(typeId)->getImmediateOperand(1);
204     }
205     Id getImageType(Id resultId) const
206     {
207         Id typeId = getTypeId(resultId);
208         assert(isImageType(typeId) || isSampledImageType(typeId));
209         return isSampledImageType(typeId) ? module.getInstruction(typeId)->getIdOperand(0) : typeId;
210     }
211     bool isArrayedImageType(Id typeId) const
212     {
213         assert(isImageType(typeId));
214         return module.getInstruction(typeId)->getImmediateOperand(3) != 0;
215     }
216
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);
231
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);
234
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*);
245
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; }
249
250     // Make the entry-point function. The returned pointer is only valid
251     // for the lifetime of this builder.
252     Function* makeEntryPoint(const char*);
253
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);
259
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);
263
264     // Generate all the code needed to finish up a function.
265     void leaveFunction();
266
267     // Create a discard.
268     void makeDiscard();
269
270     // Create a global or function local or IO variable.
271     Id createVariable(StorageClass, Id type, const char* name = 0);
272
273     // Create an intermediate with an undefined value.
274     Id createUndefined(Id type);
275
276     // Store into an Id and return the l-value
277     void createStore(Id rValue, Id lValue);
278
279     // Load from an Id and return it
280     Id createLoad(Id lValue);
281
282     // Create an OpAccessChain instruction
283     Id createAccessChain(StorageClass, Id base, const std::vector<Id>& offsets);
284
285     // Create an OpArrayLength instruction
286     Id createArrayLength(Id base, unsigned int member);
287
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);
293
294     Id createVectorExtractDynamic(Id vector, Id typeId, Id componentIndex);
295     Id createVectorInsertDynamic(Id vector, Id typeId, Id component, Id componentIndex);
296
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);
309
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);
313
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);
319
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)
324     {
325         if (precision != NoPrecision && id != NoResult)
326             addDecoration(id, precision);
327
328         return id;
329     }
330
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.
337     //
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.
340     //
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);
344
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);
349
350     // Create a call to a built-in function.
351     Id createBuiltinCall(Id resultType, Id builtins, int entryPoint, const std::vector<Id>& args);
352
353     // List of parameters used to create a texture operation
354     struct TextureParameters {
355         Id sampler;
356         Id coords;
357         Id bias;
358         Id lod;
359         Id Dref;
360         Id offset;
361         Id offsets;
362         Id gradX;
363         Id gradY;
364         Id sample;
365         Id component;
366         Id texelOut;
367         Id lodClamp;
368     };
369
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&);
372
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);
376
377     Id createSamplePositionCall(Decoration precision, Id, Id);
378
379     Id createBitFieldExtractCall(Decoration precision, Id, Id, Id, bool isSigned);
380     Id createBitFieldInsertCall(Decoration precision, Id, Id, Id, Id);
381
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 */);
384
385     // OpCompositeConstruct
386     Id createCompositeConstruct(Id typeId, const std::vector<Id>& constituents);
387
388     // vector or scalar constructor
389     Id createConstructor(Decoration precision, const std::vector<Id>& sources, Id resultTypeId);
390
391     // matrix constructor
392     Id createMatrixConstructor(Decoration precision, const std::vector<Id>& sources, Id constructee);
393
394     // Helper to use for building nested control flow with if-then-else.
395     class If {
396     public:
397         If(Id condition, unsigned int ctrl, Builder& builder);
398         ~If() {}
399
400         void makeBeginElse();
401         void makeEndIf();
402
403     private:
404         If(const If&);
405         If& operator=(If&);
406
407         Builder& builder;
408         Id condition;
409         unsigned int control;
410         Function* function;
411         Block* headerBlock;
412         Block* thenBlock;
413         Block* elseBlock;
414         Block* mergeBlock;
415     };
416
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).
421     //
422     // The SPIR-V Builder will maintain the stack of post-switch merge blocks for nested switches.
423     //
424     // Use a defaultSegment < 0 if there is no default segment (to branch to post switch).
425     //
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.
428     //
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
431
432     // Add a branch to the innermost switch's merge block.
433     void addSwitchBreak();
434
435     // Move to the next code segment, passing in the return argument in makeSwitch()
436     void nextSwitchSegment(std::vector<Block*>& segmentBB, int segment);
437
438     // Finish off the innermost switch.
439     void endSwitch(std::vector<Block*>& segmentBB);
440
441     struct LoopBlocks {
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;
445     private:
446         LoopBlocks();
447         LoopBlocks& operator=(const LoopBlocks&);
448     };
449
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();
454
455     // Create a new block in the function containing the build point.  Memory is
456     // owned by the function object.
457     Block& makeNewBlock();
458
459     // Add a branch to the continue_target of the current (innermost) loop.
460     void createLoopContinue();
461
462     // Add an exit (e.g. "break") from the innermost loop that we're currently
463     // in.
464     void createLoopExit();
465
466     // Close the innermost loop that you're in
467     void closeLoop();
468
469     //
470     // Access chain design for an R-Value vs. L-Value:
471     //
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.
475     //
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
481     //
482     // Computing an r-value means generating code.  Hence,
483     // r-values should only be computed when they are needed, not speculatively.
484     //
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.
488     //
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.
494     //
495     // The users of this single access chain can save and restore if they
496     // want to nest or manage multiple chains.
497     //
498
499     struct AccessChain {
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
507     };
508
509     //
510     // the SPIR-V builder maintains a single active chain that
511     // the following methods operate on
512     //
513
514     // for external save and restore
515     AccessChain getAccessChain() { return accessChain; }
516     void setAccessChain(AccessChain newChain) { accessChain = newChain; }
517
518     // clear accessChain
519     void clearAccessChain();
520
521     // set new base as an l-value base
522     void setAccessChainLValue(Id lValue)
523     {
524         assert(isPointer(lValue));
525         accessChain.base = lValue;
526     }
527
528     // set new base value as an r-value
529     void setAccessChainRValue(Id rValue)
530     {
531         accessChain.isRValue = true;
532         accessChain.base = rValue;
533     }
534
535     // push offset onto the end of the chain
536     void accessChainPush(Id offset)
537     {
538         accessChain.indexChain.push_back(offset);
539     }
540
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);
543
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)
547     {
548         if (accessChain.swizzle.size() != 1) {
549             accessChain.component = component;
550             if (accessChain.preSwizzleBaseType == NoType)
551                 accessChain.preSwizzleBaseType = preSwizzleBaseType;
552         }
553     }
554
555     // use accessChain and swizzle to store value
556     void accessChainStore(Id rvalue);
557
558     // use accessChain and swizzle to load an r-value
559     Id accessChainLoad(Decoration precision, Decoration nonUniform, Id ResultType);
560
561     // get the direct pointer for an l-value
562     Id accessChainGetLValue();
563
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();
567
568     // Add capabilities, extensions, remove unneeded decorations, etc., 
569     // based on the resulting SPIR-V.
570     void postProcess();
571
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);
578
579     void dump(std::vector<unsigned int>&) const;
580
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);
584
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; }
591
592  protected:
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;
608
609     unsigned int spvVersion;     // the version of SPIR-V to emit in the header
610     SourceLanguage source;
611     int sourceVersion;
612     spv::Id sourceFileStringId;
613     std::string sourceText;
614     int currentLine;
615     bool emitOpLines;
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;
622     int builderNumber;
623     Module module;
624     Block* buildPoint;
625     Id uniqueId;
626     Function* entryPointFunction;
627     bool generatingOpCodeForSpecConst;
628     AccessChain accessChain;
629
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;
640
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
645
646     // stack of switches
647     std::stack<Block*> switchMerges;
648
649     // Our loop stack.
650     std::stack<LoopBlocks> loops;
651
652     // The stream for outputting warnings and errors.
653     SpvBuildLogger* logger;
654 };  // end Builder class
655
656 };  // end spv namespace
657
658 #endif // SpvBuilder_H