Restore legacy interface for remap()
[platform/upstream/glslang.git] / SPIRV / SpvBuilder.h
1 //
2 // Copyright (C) 2014-2015 LunarG, Inc.
3 // Copyright (C) 2015-2020 Google, Inc.
4 // Copyright (C) 2017 ARM Limited.
5 // Modifications Copyright (C) 2020 Advanced Micro Devices, Inc. All rights reserved.
6 //
7 // All rights reserved.
8 //
9 // Redistribution and use in source and binary forms, with or without
10 // modification, are permitted provided that the following conditions
11 // are met:
12 //
13 //    Redistributions of source code must retain the above copyright
14 //    notice, this list of conditions and the following disclaimer.
15 //
16 //    Redistributions in binary form must reproduce the above
17 //    copyright notice, this list of conditions and the following
18 //    disclaimer in the documentation and/or other materials provided
19 //    with the distribution.
20 //
21 //    Neither the name of 3Dlabs Inc. Ltd. nor the names of its
22 //    contributors may be used to endorse or promote products derived
23 //    from this software without specific prior written permission.
24 //
25 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
26 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
27 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
28 // FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
29 // COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
30 // INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
31 // BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
32 // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
33 // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
34 // LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
35 // ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
36 // POSSIBILITY OF SUCH DAMAGE.
37
38 //
39 // "Builder" is an interface to fully build SPIR-V IR.   Allocate one of
40 // these to build (a thread safe) internal SPIR-V representation (IR),
41 // and then dump it as a binary stream according to the SPIR-V specification.
42 //
43 // A Builder has a 1:1 relationship with a SPIR-V module.
44 //
45
46 #pragma once
47 #ifndef SpvBuilder_H
48 #define SpvBuilder_H
49
50 #include "Logger.h"
51 #include "spirv.hpp"
52 #include "spvIR.h"
53
54 #include <algorithm>
55 #include <map>
56 #include <memory>
57 #include <set>
58 #include <sstream>
59 #include <stack>
60 #include <unordered_map>
61 #include <map>
62
63 namespace spv {
64
65 typedef enum {
66     Spv_1_0 = (1 << 16),
67     Spv_1_1 = (1 << 16) | (1 << 8),
68     Spv_1_2 = (1 << 16) | (2 << 8),
69     Spv_1_3 = (1 << 16) | (3 << 8),
70     Spv_1_4 = (1 << 16) | (4 << 8),
71     Spv_1_5 = (1 << 16) | (5 << 8),
72 } SpvVersion;
73
74 class Builder {
75 public:
76     Builder(unsigned int spvVersion, unsigned int userNumber, SpvBuildLogger* logger);
77     virtual ~Builder();
78
79     static const int maxMatrixSize = 4;
80
81     unsigned int getSpvVersion() const { return spvVersion; }
82
83     void setSource(spv::SourceLanguage lang, int version)
84     {
85         source = lang;
86         sourceVersion = version;
87     }
88     spv::Id getStringId(const std::string& str)
89     {
90         auto sItr = stringIds.find(str);
91         if (sItr != stringIds.end())
92             return sItr->second;
93         spv::Id strId = getUniqueId();
94         Instruction* fileString = new Instruction(strId, NoType, OpString);
95         const char* file_c_str = str.c_str();
96         fileString->addStringOperand(file_c_str);
97         strings.push_back(std::unique_ptr<Instruction>(fileString));
98         module.mapInstruction(fileString);
99         stringIds[file_c_str] = strId;
100         return strId;
101     }
102     spv::Id getSourceFile() const 
103     {
104         return sourceFileStringId;
105     }
106     void setSourceFile(const std::string& file)
107     {
108         sourceFileStringId = getStringId(file);
109     }
110     void setSourceText(const std::string& text) { sourceText = text; }
111     void addSourceExtension(const char* ext) { sourceExtensions.push_back(ext); }
112     void addModuleProcessed(const std::string& p) { moduleProcesses.push_back(p.c_str()); }
113     void setEmitOpLines() { emitOpLines = true; }
114     void addExtension(const char* ext) { extensions.insert(ext); }
115     void removeExtension(const char* ext)
116     {
117         extensions.erase(ext);
118     }
119     void addIncorporatedExtension(const char* ext, SpvVersion incorporatedVersion)
120     {
121         if (getSpvVersion() < static_cast<unsigned>(incorporatedVersion))
122             addExtension(ext);
123     }
124     void promoteIncorporatedExtension(const char* baseExt, const char* promoExt, SpvVersion incorporatedVersion)
125     {
126         removeExtension(baseExt);
127         addIncorporatedExtension(promoExt, incorporatedVersion);
128     }
129     void addInclude(const std::string& name, const std::string& text)
130     {
131         spv::Id incId = getStringId(name);
132         includeFiles[incId] = &text;
133     }
134     Id import(const char*);
135     void setMemoryModel(spv::AddressingModel addr, spv::MemoryModel mem)
136     {
137         addressModel = addr;
138         memoryModel = mem;
139     }
140
141     void addCapability(spv::Capability cap) { capabilities.insert(cap); }
142
143     // To get a new <id> for anything needing a new one.
144     Id getUniqueId() { return ++uniqueId; }
145
146     // To get a set of new <id>s, e.g., for a set of function parameters
147     Id getUniqueIds(int numIds)
148     {
149         Id id = uniqueId + 1;
150         uniqueId += numIds;
151         return id;
152     }
153
154     // Generate OpLine for non-filename-based #line directives (ie no filename
155     // seen yet): Log the current line, and if different than the last one,
156     // issue a new OpLine using the new line and current source file name.
157     void setLine(int line);
158
159     // If filename null, generate OpLine for non-filename-based line directives,
160     // else do filename-based: Log the current line and file, and if different
161     // than the last one, issue a new OpLine using the new line and file
162     // name.
163     void setLine(int line, const char* filename);
164     // Low-level OpLine. See setLine() for a layered helper.
165     void addLine(Id fileName, int line, int column);
166
167     // For creating new types (will return old type if the requested one was already made).
168     Id makeVoidType();
169     Id makeBoolType();
170     Id makePointer(StorageClass, Id pointee);
171     Id makeForwardPointer(StorageClass);
172     Id makePointerFromForwardPointer(StorageClass, Id forwardPointerType, Id pointee);
173     Id makeIntegerType(int width, bool hasSign);   // generic
174     Id makeIntType(int width) { return makeIntegerType(width, true); }
175     Id makeUintType(int width) { return makeIntegerType(width, false); }
176     Id makeFloatType(int width);
177     Id makeStructType(const std::vector<Id>& members, const char*);
178     Id makeStructResultType(Id type0, Id type1);
179     Id makeVectorType(Id component, int size);
180     Id makeMatrixType(Id component, int cols, int rows);
181     Id makeArrayType(Id element, Id sizeId, int stride);  // 0 stride means no stride decoration
182     Id makeRuntimeArray(Id element);
183     Id makeFunctionType(Id returnType, const std::vector<Id>& paramTypes);
184     Id makeImageType(Id sampledType, Dim, bool depth, bool arrayed, bool ms, unsigned sampled, ImageFormat format);
185     Id makeSamplerType();
186     Id makeSampledImageType(Id imageType);
187     Id makeCooperativeMatrixType(Id component, Id scope, Id rows, Id cols);
188     Id makeGenericType(spv::Op opcode, std::vector<spv::IdImmediate>& operands);
189
190     // accelerationStructureNV type
191     Id makeAccelerationStructureType();
192     // rayQueryEXT type
193     Id makeRayQueryType();
194
195     // For querying about types.
196     Id getTypeId(Id resultId) const { return module.getTypeId(resultId); }
197     Id getDerefTypeId(Id resultId) const;
198     Op getOpCode(Id id) const { return module.getInstruction(id)->getOpCode(); }
199     Op getTypeClass(Id typeId) const { return getOpCode(typeId); }
200     Op getMostBasicTypeClass(Id typeId) const;
201     int getNumComponents(Id resultId) const { return getNumTypeComponents(getTypeId(resultId)); }
202     int getNumTypeConstituents(Id typeId) const;
203     int getNumTypeComponents(Id typeId) const { return getNumTypeConstituents(typeId); }
204     Id getScalarTypeId(Id typeId) const;
205     Id getContainedTypeId(Id typeId) const;
206     Id getContainedTypeId(Id typeId, int) const;
207     StorageClass getTypeStorageClass(Id typeId) const { return module.getStorageClass(typeId); }
208     ImageFormat getImageTypeFormat(Id typeId) const
209         { return (ImageFormat)module.getInstruction(typeId)->getImmediateOperand(6); }
210     Id getResultingAccessChainType() const;
211
212     bool isPointer(Id resultId)      const { return isPointerType(getTypeId(resultId)); }
213     bool isScalar(Id resultId)       const { return isScalarType(getTypeId(resultId)); }
214     bool isVector(Id resultId)       const { return isVectorType(getTypeId(resultId)); }
215     bool isMatrix(Id resultId)       const { return isMatrixType(getTypeId(resultId)); }
216     bool isCooperativeMatrix(Id resultId)const { return isCooperativeMatrixType(getTypeId(resultId)); }
217     bool isAggregate(Id resultId)    const { return isAggregateType(getTypeId(resultId)); }
218     bool isSampledImage(Id resultId) const { return isSampledImageType(getTypeId(resultId)); }
219
220     bool isBoolType(Id typeId)
221         { return groupedTypes[OpTypeBool].size() > 0 && typeId == groupedTypes[OpTypeBool].back()->getResultId(); }
222     bool isIntType(Id typeId)          const
223         { return getTypeClass(typeId) == OpTypeInt && module.getInstruction(typeId)->getImmediateOperand(1) != 0; }
224     bool isUintType(Id typeId)         const
225         { return getTypeClass(typeId) == OpTypeInt && module.getInstruction(typeId)->getImmediateOperand(1) == 0; }
226     bool isFloatType(Id typeId)        const { return getTypeClass(typeId) == OpTypeFloat; }
227     bool isPointerType(Id typeId)      const { return getTypeClass(typeId) == OpTypePointer; }
228     bool isScalarType(Id typeId)       const
229         { return getTypeClass(typeId) == OpTypeFloat || getTypeClass(typeId) == OpTypeInt ||
230           getTypeClass(typeId) == OpTypeBool; }
231     bool isVectorType(Id typeId)       const { return getTypeClass(typeId) == OpTypeVector; }
232     bool isMatrixType(Id typeId)       const { return getTypeClass(typeId) == OpTypeMatrix; }
233     bool isStructType(Id typeId)       const { return getTypeClass(typeId) == OpTypeStruct; }
234     bool isArrayType(Id typeId)        const { return getTypeClass(typeId) == OpTypeArray; }
235 #ifdef GLSLANG_WEB
236     bool isCooperativeMatrixType(Id typeId)const { return false; }
237 #else
238     bool isCooperativeMatrixType(Id typeId)const { return getTypeClass(typeId) == OpTypeCooperativeMatrixNV; }
239 #endif
240     bool isAggregateType(Id typeId)    const
241         { return isArrayType(typeId) || isStructType(typeId) || isCooperativeMatrixType(typeId); }
242     bool isImageType(Id typeId)        const { return getTypeClass(typeId) == OpTypeImage; }
243     bool isSamplerType(Id typeId)      const { return getTypeClass(typeId) == OpTypeSampler; }
244     bool isSampledImageType(Id typeId) const { return getTypeClass(typeId) == OpTypeSampledImage; }
245     bool containsType(Id typeId, Op typeOp, unsigned int width) const;
246     bool containsPhysicalStorageBufferOrArray(Id typeId) const;
247
248     bool isConstantOpCode(Op opcode) const;
249     bool isSpecConstantOpCode(Op opcode) const;
250     bool isConstant(Id resultId) const { return isConstantOpCode(getOpCode(resultId)); }
251     bool isConstantScalar(Id resultId) const { return getOpCode(resultId) == OpConstant; }
252     bool isSpecConstant(Id resultId) const { return isSpecConstantOpCode(getOpCode(resultId)); }
253     unsigned int getConstantScalar(Id resultId) const
254         { return module.getInstruction(resultId)->getImmediateOperand(0); }
255     StorageClass getStorageClass(Id resultId) const { return getTypeStorageClass(getTypeId(resultId)); }
256
257     bool isVariableOpCode(Op opcode) const { return opcode == OpVariable; }
258     bool isVariable(Id resultId) const { return isVariableOpCode(getOpCode(resultId)); }
259     bool isGlobalStorage(Id resultId) const { return getStorageClass(resultId) != StorageClassFunction; }
260     bool isGlobalVariable(Id resultId) const { return isVariable(resultId) && isGlobalStorage(resultId); }
261     // See if a resultId is valid for use as an initializer.
262     bool isValidInitializer(Id resultId) const { return isConstant(resultId) || isGlobalVariable(resultId); }
263
264     int getScalarTypeWidth(Id typeId) const
265     {
266         Id scalarTypeId = getScalarTypeId(typeId);
267         assert(getTypeClass(scalarTypeId) == OpTypeInt || getTypeClass(scalarTypeId) == OpTypeFloat);
268         return module.getInstruction(scalarTypeId)->getImmediateOperand(0);
269     }
270
271     int getTypeNumColumns(Id typeId) const
272     {
273         assert(isMatrixType(typeId));
274         return getNumTypeConstituents(typeId);
275     }
276     int getNumColumns(Id resultId) const { return getTypeNumColumns(getTypeId(resultId)); }
277     int getTypeNumRows(Id typeId) const
278     {
279         assert(isMatrixType(typeId));
280         return getNumTypeComponents(getContainedTypeId(typeId));
281     }
282     int getNumRows(Id resultId) const { return getTypeNumRows(getTypeId(resultId)); }
283
284     Dim getTypeDimensionality(Id typeId) const
285     {
286         assert(isImageType(typeId));
287         return (Dim)module.getInstruction(typeId)->getImmediateOperand(1);
288     }
289     Id getImageType(Id resultId) const
290     {
291         Id typeId = getTypeId(resultId);
292         assert(isImageType(typeId) || isSampledImageType(typeId));
293         return isSampledImageType(typeId) ? module.getInstruction(typeId)->getIdOperand(0) : typeId;
294     }
295     bool isArrayedImageType(Id typeId) const
296     {
297         assert(isImageType(typeId));
298         return module.getInstruction(typeId)->getImmediateOperand(3) != 0;
299     }
300
301     // For making new constants (will return old constant if the requested one was already made).
302     Id makeNullConstant(Id typeId);
303     Id makeBoolConstant(bool b, bool specConstant = false);
304     Id makeInt8Constant(int i, bool specConstant = false)
305         { return makeIntConstant(makeIntType(8),  (unsigned)i, specConstant); }
306     Id makeUint8Constant(unsigned u, bool specConstant = false)
307         { return makeIntConstant(makeUintType(8),           u, specConstant); }
308     Id makeInt16Constant(int i, bool specConstant = false)
309         { return makeIntConstant(makeIntType(16),  (unsigned)i, specConstant); }
310     Id makeUint16Constant(unsigned u, bool specConstant = false)
311         { return makeIntConstant(makeUintType(16),           u, specConstant); }
312     Id makeIntConstant(int i, bool specConstant = false)
313         { return makeIntConstant(makeIntType(32),  (unsigned)i, specConstant); }
314     Id makeUintConstant(unsigned u, bool specConstant = false)
315         { return makeIntConstant(makeUintType(32),           u, specConstant); }
316     Id makeInt64Constant(long long i, bool specConstant = false)
317         { return makeInt64Constant(makeIntType(64),  (unsigned long long)i, specConstant); }
318     Id makeUint64Constant(unsigned long long u, bool specConstant = false)
319         { return makeInt64Constant(makeUintType(64),                     u, specConstant); }
320     Id makeFloatConstant(float f, bool specConstant = false);
321     Id makeDoubleConstant(double d, bool specConstant = false);
322     Id makeFloat16Constant(float f16, bool specConstant = false);
323     Id makeFpConstant(Id type, double d, bool specConstant = false);
324
325     // Turn the array of constants into a proper spv constant of the requested type.
326     Id makeCompositeConstant(Id type, const std::vector<Id>& comps, bool specConst = false);
327
328     // Methods for adding information outside the CFG.
329     Instruction* addEntryPoint(ExecutionModel, Function*, const char* name);
330     void addExecutionMode(Function*, ExecutionMode mode, int value1 = -1, int value2 = -1, int value3 = -1);
331     void addExecutionMode(Function*, ExecutionMode mode, const std::vector<unsigned>& literals);
332     void addExecutionModeId(Function*, ExecutionMode mode, const std::vector<Id>& operandIds);
333     void addName(Id, const char* name);
334     void addMemberName(Id, int member, const char* name);
335     void addDecoration(Id, Decoration, int num = -1);
336     void addDecoration(Id, Decoration, const char*);
337     void addDecoration(Id, Decoration, const std::vector<unsigned>& literals);
338     void addDecoration(Id, Decoration, const std::vector<const char*>& strings);
339     void addDecorationId(Id id, Decoration, Id idDecoration);
340     void addDecorationId(Id id, Decoration, const std::vector<Id>& operandIds);
341     void addMemberDecoration(Id, unsigned int member, Decoration, int num = -1);
342     void addMemberDecoration(Id, unsigned int member, Decoration, const char*);
343     void addMemberDecoration(Id, unsigned int member, Decoration, const std::vector<unsigned>& literals);
344     void addMemberDecoration(Id, unsigned int member, Decoration, const std::vector<const char*>& strings);
345
346     // At the end of what block do the next create*() instructions go?
347     void setBuildPoint(Block* bp) { buildPoint = bp; }
348     Block* getBuildPoint() const { return buildPoint; }
349
350     // Make the entry-point function. The returned pointer is only valid
351     // for the lifetime of this builder.
352     Function* makeEntryPoint(const char*);
353
354     // Make a shader-style function, and create its entry block if entry is non-zero.
355     // Return the function, pass back the entry.
356     // The returned pointer is only valid for the lifetime of this builder.
357     Function* makeFunctionEntry(Decoration precision, Id returnType, const char* name,
358         const std::vector<Id>& paramTypes, const std::vector<std::vector<Decoration>>& precisions, Block **entry = 0);
359
360     // Create a return. An 'implicit' return is one not appearing in the source
361     // code.  In the case of an implicit return, no post-return block is inserted.
362     void makeReturn(bool implicit, Id retVal = 0);
363
364     // Generate all the code needed to finish up a function.
365     void leaveFunction();
366
367     // Create block terminator instruction for certain statements like
368     // discard, terminate-invocation, terminateRayEXT, or ignoreIntersectionEXT
369     void makeStatementTerminator(spv::Op opcode, const char *name);
370
371     // Create a global or function local or IO variable.
372     Id createVariable(Decoration precision, StorageClass, Id type, const char* name = nullptr,
373         Id initializer = NoResult);
374
375     // Create an intermediate with an undefined value.
376     Id createUndefined(Id type);
377
378     // Store into an Id and return the l-value
379     void createStore(Id rValue, Id lValue, spv::MemoryAccessMask memoryAccess = spv::MemoryAccessMaskNone,
380         spv::Scope scope = spv::ScopeMax, unsigned int alignment = 0);
381
382     // Load from an Id and return it
383     Id createLoad(Id lValue, spv::Decoration precision,
384         spv::MemoryAccessMask memoryAccess = spv::MemoryAccessMaskNone,
385         spv::Scope scope = spv::ScopeMax, unsigned int alignment = 0);
386
387     // Create an OpAccessChain instruction
388     Id createAccessChain(StorageClass, Id base, const std::vector<Id>& offsets);
389
390     // Create an OpArrayLength instruction
391     Id createArrayLength(Id base, unsigned int member);
392
393     // Create an OpCooperativeMatrixLengthNV instruction
394     Id createCooperativeMatrixLength(Id type);
395
396     // Create an OpCompositeExtract instruction
397     Id createCompositeExtract(Id composite, Id typeId, unsigned index);
398     Id createCompositeExtract(Id composite, Id typeId, const std::vector<unsigned>& indexes);
399     Id createCompositeInsert(Id object, Id composite, Id typeId, unsigned index);
400     Id createCompositeInsert(Id object, Id composite, Id typeId, const std::vector<unsigned>& indexes);
401
402     Id createVectorExtractDynamic(Id vector, Id typeId, Id componentIndex);
403     Id createVectorInsertDynamic(Id vector, Id typeId, Id component, Id componentIndex);
404
405     void createNoResultOp(Op);
406     void createNoResultOp(Op, Id operand);
407     void createNoResultOp(Op, const std::vector<Id>& operands);
408     void createNoResultOp(Op, const std::vector<IdImmediate>& operands);
409     void createControlBarrier(Scope execution, Scope memory, MemorySemanticsMask);
410     void createMemoryBarrier(unsigned executionScope, unsigned memorySemantics);
411     Id createUnaryOp(Op, Id typeId, Id operand);
412     Id createBinOp(Op, Id typeId, Id operand1, Id operand2);
413     Id createTriOp(Op, Id typeId, Id operand1, Id operand2, Id operand3);
414     Id createOp(Op, Id typeId, const std::vector<Id>& operands);
415     Id createOp(Op, Id typeId, const std::vector<IdImmediate>& operands);
416     Id createFunctionCall(spv::Function*, const std::vector<spv::Id>&);
417     Id createSpecConstantOp(Op, Id typeId, const std::vector<spv::Id>& operands, const std::vector<unsigned>& literals);
418
419     // Take an rvalue (source) and a set of channels to extract from it to
420     // make a new rvalue, which is returned.
421     Id createRvalueSwizzle(Decoration precision, Id typeId, Id source, const std::vector<unsigned>& channels);
422
423     // Take a copy of an lvalue (target) and a source of components, and set the
424     // source components into the lvalue where the 'channels' say to put them.
425     // An updated version of the target is returned.
426     // (No true lvalue or stores are used.)
427     Id createLvalueSwizzle(Id typeId, Id target, Id source, const std::vector<unsigned>& channels);
428
429     // If both the id and precision are valid, the id
430     // gets tagged with the requested precision.
431     // The passed in id is always the returned id, to simplify use patterns.
432     Id setPrecision(Id id, Decoration precision)
433     {
434         if (precision != NoPrecision && id != NoResult)
435             addDecoration(id, precision);
436
437         return id;
438     }
439
440     // Can smear a scalar to a vector for the following forms:
441     //   - promoteScalar(scalar, vector)  // smear scalar to width of vector
442     //   - promoteScalar(vector, scalar)  // smear scalar to width of vector
443     //   - promoteScalar(pointer, scalar) // smear scalar to width of what pointer points to
444     //   - promoteScalar(scalar, scalar)  // do nothing
445     // Other forms are not allowed.
446     //
447     // Generally, the type of 'scalar' does not need to be the same type as the components in 'vector'.
448     // The type of the created vector is a vector of components of the same type as the scalar.
449     //
450     // Note: One of the arguments will change, with the result coming back that way rather than
451     // through the return value.
452     void promoteScalar(Decoration precision, Id& left, Id& right);
453
454     // Make a value by smearing the scalar to fill the type.
455     // vectorType should be the correct type for making a vector of scalarVal.
456     // (No conversions are done.)
457     Id smearScalar(Decoration precision, Id scalarVal, Id vectorType);
458
459     // Create a call to a built-in function.
460     Id createBuiltinCall(Id resultType, Id builtins, int entryPoint, const std::vector<Id>& args);
461
462     // List of parameters used to create a texture operation
463     struct TextureParameters {
464         Id sampler;
465         Id coords;
466         Id bias;
467         Id lod;
468         Id Dref;
469         Id offset;
470         Id offsets;
471         Id gradX;
472         Id gradY;
473         Id sample;
474         Id component;
475         Id texelOut;
476         Id lodClamp;
477         Id granularity;
478         Id coarse;
479         bool nonprivate;
480         bool volatil;
481     };
482
483     // Select the correct texture operation based on all inputs, and emit the correct instruction
484     Id createTextureCall(Decoration precision, Id resultType, bool sparse, bool fetch, bool proj, bool gather,
485         bool noImplicit, const TextureParameters&, ImageOperandsMask);
486
487     // Emit the OpTextureQuery* instruction that was passed in.
488     // Figure out the right return value and type, and return it.
489     Id createTextureQueryCall(Op, const TextureParameters&, bool isUnsignedResult);
490
491     Id createSamplePositionCall(Decoration precision, Id, Id);
492
493     Id createBitFieldExtractCall(Decoration precision, Id, Id, Id, bool isSigned);
494     Id createBitFieldInsertCall(Decoration precision, Id, Id, Id, Id);
495
496     // Reduction comparison for composites:  For equal and not-equal resulting in a scalar.
497     Id createCompositeCompare(Decoration precision, Id, Id, bool /* true if for equal, false if for not-equal */);
498
499     // OpCompositeConstruct
500     Id createCompositeConstruct(Id typeId, const std::vector<Id>& constituents);
501
502     // vector or scalar constructor
503     Id createConstructor(Decoration precision, const std::vector<Id>& sources, Id resultTypeId);
504
505     // matrix constructor
506     Id createMatrixConstructor(Decoration precision, const std::vector<Id>& sources, Id constructee);
507
508     // Helper to use for building nested control flow with if-then-else.
509     class If {
510     public:
511         If(Id condition, unsigned int ctrl, Builder& builder);
512         ~If() {}
513
514         void makeBeginElse();
515         void makeEndIf();
516
517     private:
518         If(const If&);
519         If& operator=(If&);
520
521         Builder& builder;
522         Id condition;
523         unsigned int control;
524         Function* function;
525         Block* headerBlock;
526         Block* thenBlock;
527         Block* elseBlock;
528         Block* mergeBlock;
529     };
530
531     // Make a switch statement.  A switch has 'numSegments' of pieces of code, not containing
532     // any case/default labels, all separated by one or more case/default labels.  Each possible
533     // case value v is a jump to the caseValues[v] segment.  The defaultSegment is also in this
534     // number space.  How to compute the value is given by 'condition', as in switch(condition).
535     //
536     // The SPIR-V Builder will maintain the stack of post-switch merge blocks for nested switches.
537     //
538     // Use a defaultSegment < 0 if there is no default segment (to branch to post switch).
539     //
540     // Returns the right set of basic blocks to start each code segment with, so that the caller's
541     // recursion stack can hold the memory for it.
542     //
543     void makeSwitch(Id condition, unsigned int control, int numSegments, const std::vector<int>& caseValues,
544                     const std::vector<int>& valueToSegment, int defaultSegment, std::vector<Block*>& segmentBB);
545
546     // Add a branch to the innermost switch's merge block.
547     void addSwitchBreak();
548
549     // Move to the next code segment, passing in the return argument in makeSwitch()
550     void nextSwitchSegment(std::vector<Block*>& segmentBB, int segment);
551
552     // Finish off the innermost switch.
553     void endSwitch(std::vector<Block*>& segmentBB);
554
555     struct LoopBlocks {
556         LoopBlocks(Block& head, Block& body, Block& merge, Block& continue_target) :
557             head(head), body(body), merge(merge), continue_target(continue_target) { }
558         Block &head, &body, &merge, &continue_target;
559     private:
560         LoopBlocks();
561         LoopBlocks& operator=(const LoopBlocks&) = delete;
562     };
563
564     // Start a new loop and prepare the builder to generate code for it.  Until
565     // closeLoop() is called for this loop, createLoopContinue() and
566     // createLoopExit() will target its corresponding blocks.
567     LoopBlocks& makeNewLoop();
568
569     // Create a new block in the function containing the build point.  Memory is
570     // owned by the function object.
571     Block& makeNewBlock();
572
573     // Add a branch to the continue_target of the current (innermost) loop.
574     void createLoopContinue();
575
576     // Add an exit (e.g. "break") from the innermost loop that we're currently
577     // in.
578     void createLoopExit();
579
580     // Close the innermost loop that you're in
581     void closeLoop();
582
583     //
584     // Access chain design for an R-Value vs. L-Value:
585     //
586     // There is a single access chain the builder is building at
587     // any particular time.  Such a chain can be used to either to a load or
588     // a store, when desired.
589     //
590     // Expressions can be r-values, l-values, or both, or only r-values:
591     //    a[b.c].d = ....  // l-value
592     //    ... = a[b.c].d;  // r-value, that also looks like an l-value
593     //    ++a[b.c].d;      // r-value and l-value
594     //    (x + y)[2];      // r-value only, can't possibly be l-value
595     //
596     // Computing an r-value means generating code.  Hence,
597     // r-values should only be computed when they are needed, not speculatively.
598     //
599     // Computing an l-value means saving away information for later use in the compiler,
600     // no code is generated until the l-value is later dereferenced.  It is okay
601     // to speculatively generate an l-value, just not okay to speculatively dereference it.
602     //
603     // The base of the access chain (the left-most variable or expression
604     // from which everything is based) can be set either as an l-value
605     // or as an r-value.  Most efficient would be to set an l-value if one
606     // is available.  If an expression was evaluated, the resulting r-value
607     // can be set as the chain base.
608     //
609     // The users of this single access chain can save and restore if they
610     // want to nest or manage multiple chains.
611     //
612
613     struct AccessChain {
614         Id base;                       // for l-values, pointer to the base object, for r-values, the base object
615         std::vector<Id> indexChain;
616         Id instr;                      // cache the instruction that generates this access chain
617         std::vector<unsigned> swizzle; // each std::vector element selects the next GLSL component number
618         Id component;                  // a dynamic component index, can coexist with a swizzle,
619                                        // done after the swizzle, NoResult if not present
620         Id preSwizzleBaseType;         // dereferenced type, before swizzle or component is applied;
621                                        // NoType unless a swizzle or component is present
622         bool isRValue;                 // true if 'base' is an r-value, otherwise, base is an l-value
623         unsigned int alignment;        // bitwise OR of alignment values passed in. Accumulates worst alignment.
624                                        // Only tracks base and (optional) component selection alignment.
625
626         // Accumulate whether anything in the chain of structures has coherent decorations.
627         struct CoherentFlags {
628             CoherentFlags() { clear(); }
629 #ifdef GLSLANG_WEB
630             void clear() { }
631             bool isVolatile() const { return false; }
632             CoherentFlags operator |=(const CoherentFlags &other) { return *this; }
633 #else
634             bool isVolatile() const { return volatil; }
635             bool isNonUniform() const { return nonUniform; }
636             bool anyCoherent() const {
637                 return coherent || devicecoherent || queuefamilycoherent || workgroupcoherent ||
638                     subgroupcoherent || shadercallcoherent;
639             }
640
641             unsigned coherent : 1;
642             unsigned devicecoherent : 1;
643             unsigned queuefamilycoherent : 1;
644             unsigned workgroupcoherent : 1;
645             unsigned subgroupcoherent : 1;
646             unsigned shadercallcoherent : 1;
647             unsigned nonprivate : 1;
648             unsigned volatil : 1;
649             unsigned isImage : 1;
650             unsigned nonUniform : 1;
651
652             void clear() {
653                 coherent = 0;
654                 devicecoherent = 0;
655                 queuefamilycoherent = 0;
656                 workgroupcoherent = 0;
657                 subgroupcoherent = 0;
658                 shadercallcoherent = 0;
659                 nonprivate = 0;
660                 volatil = 0;
661                 isImage = 0;
662                 nonUniform = 0;
663             }
664
665             CoherentFlags operator |=(const CoherentFlags &other) {
666                 coherent |= other.coherent;
667                 devicecoherent |= other.devicecoherent;
668                 queuefamilycoherent |= other.queuefamilycoherent;
669                 workgroupcoherent |= other.workgroupcoherent;
670                 subgroupcoherent |= other.subgroupcoherent;
671                 shadercallcoherent |= other.shadercallcoherent;
672                 nonprivate |= other.nonprivate;
673                 volatil |= other.volatil;
674                 isImage |= other.isImage;
675                 nonUniform |= other.nonUniform;
676                 return *this;
677             }
678 #endif
679         };
680         CoherentFlags coherentFlags;
681     };
682
683     //
684     // the SPIR-V builder maintains a single active chain that
685     // the following methods operate on
686     //
687
688     // for external save and restore
689     AccessChain getAccessChain() { return accessChain; }
690     void setAccessChain(AccessChain newChain) { accessChain = newChain; }
691
692     // clear accessChain
693     void clearAccessChain();
694
695     // set new base as an l-value base
696     void setAccessChainLValue(Id lValue)
697     {
698         assert(isPointer(lValue));
699         accessChain.base = lValue;
700     }
701
702     // set new base value as an r-value
703     void setAccessChainRValue(Id rValue)
704     {
705         accessChain.isRValue = true;
706         accessChain.base = rValue;
707     }
708
709     // push offset onto the end of the chain
710     void accessChainPush(Id offset, AccessChain::CoherentFlags coherentFlags, unsigned int alignment)
711     {
712         accessChain.indexChain.push_back(offset);
713         accessChain.coherentFlags |= coherentFlags;
714         accessChain.alignment |= alignment;
715     }
716
717     // push new swizzle onto the end of any existing swizzle, merging into a single swizzle
718     void accessChainPushSwizzle(std::vector<unsigned>& swizzle, Id preSwizzleBaseType,
719         AccessChain::CoherentFlags coherentFlags, unsigned int alignment);
720
721     // push a dynamic component selection onto the access chain, only applicable with a
722     // non-trivial swizzle or no swizzle
723     void accessChainPushComponent(Id component, Id preSwizzleBaseType, AccessChain::CoherentFlags coherentFlags,
724         unsigned int alignment)
725     {
726         if (accessChain.swizzle.size() != 1) {
727             accessChain.component = component;
728             if (accessChain.preSwizzleBaseType == NoType)
729                 accessChain.preSwizzleBaseType = preSwizzleBaseType;
730         }
731         accessChain.coherentFlags |= coherentFlags;
732         accessChain.alignment |= alignment;
733     }
734
735     // use accessChain and swizzle to store value
736     void accessChainStore(Id rvalue, Decoration nonUniform,
737         spv::MemoryAccessMask memoryAccess = spv::MemoryAccessMaskNone,
738         spv::Scope scope = spv::ScopeMax, unsigned int alignment = 0);
739
740     // use accessChain and swizzle to load an r-value
741     Id accessChainLoad(Decoration precision, Decoration l_nonUniform, Decoration r_nonUniform, Id ResultType,
742         spv::MemoryAccessMask memoryAccess = spv::MemoryAccessMaskNone, spv::Scope scope = spv::ScopeMax,
743             unsigned int alignment = 0);
744
745     // Return whether or not the access chain can be represented in SPIR-V
746     // as an l-value.
747     // E.g., a[3].yx cannot be, while a[3].y and a[3].y[x] can be.
748     bool isSpvLvalue() const { return accessChain.swizzle.size() <= 1; }
749
750     // get the direct pointer for an l-value
751     Id accessChainGetLValue();
752
753     // Get the inferred SPIR-V type of the result of the current access chain,
754     // based on the type of the base and the chain of dereferences.
755     Id accessChainGetInferredType();
756
757     // Add capabilities, extensions, remove unneeded decorations, etc.,
758     // based on the resulting SPIR-V.
759     void postProcess();
760
761     // Prune unreachable blocks in the CFG and remove unneeded decorations.
762     void postProcessCFG();
763
764 #ifndef GLSLANG_WEB
765     // Add capabilities, extensions based on instructions in the module.
766     void postProcessFeatures();
767     // Hook to visit each instruction in a block in a function
768     void postProcess(Instruction&);
769     // Hook to visit each non-32-bit sized float/int operation in a block.
770     void postProcessType(const Instruction&, spv::Id typeId);
771 #endif
772
773     void dump(std::vector<unsigned int>&) const;
774
775     void createBranch(Block* block);
776     void createConditionalBranch(Id condition, Block* thenBlock, Block* elseBlock);
777     void createLoopMerge(Block* mergeBlock, Block* continueBlock, unsigned int control,
778         const std::vector<unsigned int>& operands);
779
780     // Sets to generate opcode for specialization constants.
781     void setToSpecConstCodeGenMode() { generatingOpCodeForSpecConst = true; }
782     // Sets to generate opcode for non-specialization constants (normal mode).
783     void setToNormalCodeGenMode() { generatingOpCodeForSpecConst = false; }
784     // Check if the builder is generating code for spec constants.
785     bool isInSpecConstCodeGenMode() { return generatingOpCodeForSpecConst; }
786
787  protected:
788     Id makeIntConstant(Id typeId, unsigned value, bool specConstant);
789     Id makeInt64Constant(Id typeId, unsigned long long value, bool specConstant);
790     Id findScalarConstant(Op typeClass, Op opcode, Id typeId, unsigned value);
791     Id findScalarConstant(Op typeClass, Op opcode, Id typeId, unsigned v1, unsigned v2);
792     Id findCompositeConstant(Op typeClass, Id typeId, const std::vector<Id>& comps);
793     Id findStructConstant(Id typeId, const std::vector<Id>& comps);
794     Id collapseAccessChain();
795     void remapDynamicSwizzle();
796     void transferAccessChainSwizzle(bool dynamic);
797     void simplifyAccessChainSwizzle();
798     void createAndSetNoPredecessorBlock(const char*);
799     void createSelectionMerge(Block* mergeBlock, unsigned int control);
800     void dumpSourceInstructions(std::vector<unsigned int>&) const;
801     void dumpSourceInstructions(const spv::Id fileId, const std::string& text, std::vector<unsigned int>&) const;
802     void dumpInstructions(std::vector<unsigned int>&, const std::vector<std::unique_ptr<Instruction> >&) const;
803     void dumpModuleProcesses(std::vector<unsigned int>&) const;
804     spv::MemoryAccessMask sanitizeMemoryAccessForStorageClass(spv::MemoryAccessMask memoryAccess, StorageClass sc)
805         const;
806
807     unsigned int spvVersion;     // the version of SPIR-V to emit in the header
808     SourceLanguage source;
809     int sourceVersion;
810     spv::Id sourceFileStringId;
811     std::string sourceText;
812     int currentLine;
813     const char* currentFile;
814     bool emitOpLines;
815     std::set<std::string> extensions;
816     std::vector<const char*> sourceExtensions;
817     std::vector<const char*> moduleProcesses;
818     AddressingModel addressModel;
819     MemoryModel memoryModel;
820     std::set<spv::Capability> capabilities;
821     int builderNumber;
822     Module module;
823     Block* buildPoint;
824     Id uniqueId;
825     Function* entryPointFunction;
826     bool generatingOpCodeForSpecConst;
827     AccessChain accessChain;
828
829     // special blocks of instructions for output
830     std::vector<std::unique_ptr<Instruction> > strings;
831     std::vector<std::unique_ptr<Instruction> > imports;
832     std::vector<std::unique_ptr<Instruction> > entryPoints;
833     std::vector<std::unique_ptr<Instruction> > executionModes;
834     std::vector<std::unique_ptr<Instruction> > names;
835     std::vector<std::unique_ptr<Instruction> > decorations;
836     std::vector<std::unique_ptr<Instruction> > constantsTypesGlobals;
837     std::vector<std::unique_ptr<Instruction> > externals;
838     std::vector<std::unique_ptr<Function> > functions;
839
840     // not output, internally used for quick & dirty canonical (unique) creation
841
842     // map type opcodes to constant inst.
843     std::unordered_map<unsigned int, std::vector<Instruction*>> groupedConstants;
844     // map struct-id to constant instructions
845     std::unordered_map<unsigned int, std::vector<Instruction*>> groupedStructConstants;
846     // map type opcodes to type instructions
847     std::unordered_map<unsigned int, std::vector<Instruction*>> groupedTypes;
848     // list of OpConstantNull instructions
849     std::vector<Instruction*> nullConstants;
850
851     // stack of switches
852     std::stack<Block*> switchMerges;
853
854     // Our loop stack.
855     std::stack<LoopBlocks> loops;
856
857     // map from strings to their string ids
858     std::unordered_map<std::string, spv::Id> stringIds;
859
860     // map from include file name ids to their contents
861     std::map<spv::Id, const std::string*> includeFiles;
862
863     // The stream for outputting warnings and errors.
864     SpvBuildLogger* logger;
865 };  // end Builder class
866
867 };  // end spv namespace
868
869 #endif // SpvBuilder_H