blob: 38dc1fa39536b2458fb111faece8a8c13e51c906 [file] [log] [blame]
John Kessenich140f3df2015-06-26 16:58:36 -06001//
John Kessenich6c292d32016-02-15 20:58:50 -07002//Copyright (C) 2014-2015 LunarG, Inc.
3//Copyright (C) 2015-2016 Google, Inc.
John Kessenich140f3df2015-06-26 16:58:36 -06004//
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//
John Kessenich140f3df2015-06-26 16:58:36 -060037// "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
Lei Zhang17535f72016-05-04 15:55:59 -040048#include "Logger.h"
John Kessenich5e4b1242015-08-06 22:53:06 -060049#include "spirv.hpp"
John Kessenich140f3df2015-06-26 16:58:36 -060050#include "spvIR.h"
51
52#include <algorithm>
John Kessenich140f3df2015-06-26 16:58:36 -060053#include <map>
Lei Zhang09caf122016-05-02 18:11:54 -040054#include <memory>
John Kessenich92187592016-02-01 13:45:25 -070055#include <set>
Lei Zhang09caf122016-05-02 18:11:54 -040056#include <sstream>
57#include <stack>
John Kessenich140f3df2015-06-26 16:58:36 -060058
59namespace spv {
60
61class Builder {
62public:
Lei Zhang17535f72016-05-04 15:55:59 -040063 Builder(unsigned int userNumber, SpvBuildLogger* logger);
John Kessenich140f3df2015-06-26 16:58:36 -060064 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 }
Rex Xu9d93a232016-05-05 12:30:44 +080073 void addSourceExtension(const char* ext) { sourceExtensions.push_back(ext); }
74 void addExtensions(const char* ext) { extensions.push_back(ext); }
John Kessenich140f3df2015-06-26 16:58:36 -060075 Id import(const char*);
76 void setMemoryModel(spv::AddressingModel addr, spv::MemoryModel mem)
77 {
78 addressModel = addr;
79 memoryModel = mem;
80 }
81
John Kessenich92187592016-02-01 13:45:25 -070082 void addCapability(spv::Capability cap) { capabilities.insert(cap); }
John Kessenich5e4b1242015-08-06 22:53:06 -060083
John Kessenich140f3df2015-06-26 16:58:36 -060084 // 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);
John Kessenich32cfd492016-02-02 12:37:46 -0700103 Id makeStructType(const std::vector<Id>& members, const char*);
John Kessenich55e7d112015-11-15 21:33:39 -0700104 Id makeStructResultType(Id type0, Id type1);
John Kessenich140f3df2015-06-26 16:58:36 -0600105 Id makeVectorType(Id component, int size);
106 Id makeMatrixType(Id component, int cols, int rows);
John Kessenich6c292d32016-02-15 20:58:50 -0700107 Id makeArrayType(Id element, Id sizeId, int stride); // 0 stride means no stride decoration
John Kessenichc9a80832015-09-12 12:17:44 -0600108 Id makeRuntimeArray(Id element);
John Kessenich32cfd492016-02-02 12:37:46 -0700109 Id makeFunctionType(Id returnType, const std::vector<Id>& paramTypes);
John Kessenich5e4b1242015-08-06 22:53:06 -0600110 Id makeImageType(Id sampledType, Dim, bool depth, bool arrayed, bool ms, unsigned sampled, ImageFormat format);
John Kessenich55e7d112015-11-15 21:33:39 -0700111 Id makeSamplerType();
John Kessenich5e4b1242015-08-06 22:53:06 -0600112 Id makeSampledImageType(Id imageType);
John Kessenich140f3df2015-06-26 16:58:36 -0600113
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)); }
John Kessenich22118352015-12-21 20:54:09 -0700121 int getNumTypeConstituents(Id typeId) const;
122 int getNumTypeComponents(Id typeId) const { return getNumTypeConstituents(typeId); }
John Kessenich140f3df2015-06-26 16:58:36 -0600123 Id getScalarTypeId(Id typeId) const;
124 Id getContainedTypeId(Id typeId) const;
125 Id getContainedTypeId(Id typeId, int) const;
John Kessenich55e7d112015-11-15 21:33:39 -0700126 StorageClass getTypeStorageClass(Id typeId) const { return module.getStorageClass(typeId); }
John Kessenich5d0fa972016-02-15 11:57:00 -0700127 ImageFormat getImageTypeFormat(Id typeId) const { return (ImageFormat)module.getInstruction(typeId)->getImmediateOperand(6); }
John Kessenich140f3df2015-06-26 16:58:36 -0600128
John Kessenich33661452015-12-08 19:32:47 -0700129 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)); }
John Kessenich140f3df2015-06-26 16:58:36 -0600135
John Kessenich33661452015-12-08 19:32:47 -0700136 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; }
John Kessenich140f3df2015-06-26 16:58:36 -0600147
John Kessenich71631272015-10-13 10:39:19 -0600148 bool isConstantOpCode(Op opcode) const;
qining27e04a02016-04-14 16:40:20 -0400149 bool isSpecConstantOpCode(Op opcode) const;
John Kessenich71631272015-10-13 10:39:19 -0600150 bool isConstant(Id resultId) const { return isConstantOpCode(getOpCode(resultId)); }
John Kessenich140f3df2015-06-26 16:58:36 -0600151 bool isConstantScalar(Id resultId) const { return getOpCode(resultId) == OpConstant; }
qining27e04a02016-04-14 16:40:20 -0400152 bool isSpecConstant(Id resultId) const { return isSpecConstantOpCode(getOpCode(resultId)); }
John Kessenich140f3df2015-06-26 16:58:36 -0600153 unsigned int getConstantScalar(Id resultId) const { return module.getInstruction(resultId)->getImmediateOperand(0); }
John Kessenich55e7d112015-11-15 21:33:39 -0700154 StorageClass getStorageClass(Id resultId) const { return getTypeStorageClass(getTypeId(resultId)); }
John Kessenich140f3df2015-06-26 16:58:36 -0600155
156 int getTypeNumColumns(Id typeId) const
157 {
158 assert(isMatrixType(typeId));
John Kessenich22118352015-12-21 20:54:09 -0700159 return getNumTypeConstituents(typeId);
John Kessenich140f3df2015-06-26 16:58:36 -0600160 }
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
John Kessenich5e4b1242015-08-06 22:53:06 -0600169 Dim getTypeDimensionality(Id typeId) const
John Kessenich140f3df2015-06-26 16:58:36 -0600170 {
John Kessenich5e4b1242015-08-06 22:53:06 -0600171 assert(isImageType(typeId));
172 return (Dim)module.getInstruction(typeId)->getImmediateOperand(1);
John Kessenich140f3df2015-06-26 16:58:36 -0600173 }
John Kessenich5e4b1242015-08-06 22:53:06 -0600174 Id getImageType(Id resultId) const
John Kessenich140f3df2015-06-26 16:58:36 -0600175 {
Rex Xu6b86d492015-09-16 17:48:22 +0800176 Id typeId = getTypeId(resultId);
177 assert(isImageType(typeId) || isSampledImageType(typeId));
178 return isSampledImageType(typeId) ? module.getInstruction(typeId)->getIdOperand(0) : typeId;
John Kessenich5e4b1242015-08-06 22:53:06 -0600179 }
180 bool isArrayedImageType(Id typeId) const
181 {
182 assert(isImageType(typeId));
183 return module.getInstruction(typeId)->getImmediateOperand(3) != 0;
John Kessenich140f3df2015-06-26 16:58:36 -0600184 }
185
186 // For making new constants (will return old constant if the requested one was already made).
John Kessenich55e7d112015-11-15 21:33:39 -0700187 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); }
Rex Xu8ff43de2016-04-22 16:51:45 +0800190 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); }
John Kessenich55e7d112015-11-15 21:33:39 -0700192 Id makeFloatConstant(float f, bool specConstant = false);
193 Id makeDoubleConstant(double d, bool specConstant = false);
John Kessenich140f3df2015-06-26 16:58:36 -0600194
195 // Turn the array of constants into a proper spv constant of the requested type.
John Kessenich6c292d32016-02-15 20:58:50 -0700196 Id makeCompositeConstant(Id type, std::vector<Id>& comps, bool specConst = false);
John Kessenich140f3df2015-06-26 16:58:36 -0600197
198 // Methods for adding information outside the CFG.
John Kessenich55e7d112015-11-15 21:33:39 -0700199 Instruction* addEntryPoint(ExecutionModel, Function*, const char* name);
John Kessenichb56a26a2015-09-16 16:04:05 -0600200 void addExecutionMode(Function*, ExecutionMode mode, int value1 = -1, int value2 = -1, int value3 = -1);
John Kessenich140f3df2015-06-26 16:58:36 -0600201 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
John Kessenich4d65ee32016-03-12 18:17:47 -0700211 // Make the entry-point function. The returned pointer is only valid
Andrew Woloszynb7946d12016-01-18 09:23:56 -0500212 // for the lifetime of this builder.
John Kessenich6fccb3c2016-09-19 16:01:41 -0600213 Function* makeEntryPoint(const char*);
John Kessenich140f3df2015-06-26 16:58:36 -0600214
John Kessenich140f3df2015-06-26 16:58:36 -0600215 // Make a shader-style function, and create its entry block if entry is non-zero.
216 // Return the function, pass back the entry.
Andrew Woloszynb7946d12016-01-18 09:23:56 -0500217 // The returned pointer is only valid for the lifetime of this builder.
John Kessenich32cfd492016-02-02 12:37:46 -0700218 Function* makeFunctionEntry(Decoration precision, Id returnType, const char* name, const std::vector<Id>& paramTypes,
219 const std::vector<Decoration>& precisions, Block **entry = 0);
John Kessenich140f3df2015-06-26 16:58:36 -0600220
John Kesseniche770b3e2015-09-14 20:58:02 -0600221 // 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);
John Kessenich140f3df2015-06-26 16:58:36 -0600224
225 // Generate all the code needed to finish up a function.
John Kesseniche770b3e2015-09-14 20:58:02 -0600226 void leaveFunction();
John Kessenich140f3df2015-06-26 16:58:36 -0600227
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
John Kessenich32cfd492016-02-02 12:37:46 -0700234 // Create an intermediate with an undefined value.
Miro Knejp28f9b1c2015-08-11 02:45:24 +0200235 Id createUndefined(Id type);
236
John Kessenich140f3df2015-06-26 16:58:36 -0600237 // 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
John Kessenichee21fc92015-09-21 21:50:29 -0600246 // Create an OpArrayLength instruction
247 Id createArrayLength(Id base, unsigned int member);
248
John Kessenich140f3df2015-06-26 16:58:36 -0600249 // 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);
Rex Xufc618912015-09-09 16:42:49 +0800260 void createNoResultOp(Op, const std::vector<Id>& operands);
John Kessenich5e4b1242015-08-06 22:53:06 -0600261 void createControlBarrier(Scope execution, Scope memory, MemorySemanticsMask);
John Kessenich140f3df2015-06-26 16:58:36 -0600262 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);
John Kessenich5e4b1242015-08-06 22:53:06 -0600266 Id createOp(Op, Id typeId, const std::vector<Id>& operands);
John Kessenich140f3df2015-06-26 16:58:36 -0600267 Id createFunctionCall(spv::Function*, std::vector<spv::Id>&);
qining13545202016-03-21 09:51:37 -0400268 Id createSpecConstantOp(Op, Id typeId, const std::vector<spv::Id>& operands, const std::vector<unsigned>& literals);
John Kessenich140f3df2015-06-26 16:58:36 -0600269
270 // Take an rvalue (source) and a set of channels to extract from it to
271 // make a new rvalue, which is returned.
John Kessenich32cfd492016-02-02 12:37:46 -0700272 Id createRvalueSwizzle(Decoration precision, Id typeId, Id source, std::vector<unsigned>& channels);
John Kessenich140f3df2015-06-26 16:58:36 -0600273
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
John Kessenich32cfd492016-02-02 12:37:46 -0700280 // 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)
John Kessenich140f3df2015-06-26 16:58:36 -0600284 {
John Kessenich32cfd492016-02-02 12:37:46 -0700285 if (precision != NoPrecision && id != NoResult)
286 addDecoration(id, precision);
287
288 return id;
John Kessenich140f3df2015-06-26 16:58:36 -0600289 }
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 //
John Kessenich76f71392015-12-09 19:08:42 -0700298 // 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 //
John Kessenich140f3df2015-06-26 16:58:36 -0600301 // 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
John Kessenich76f71392015-12-09 19:08:42 -0700305 // 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);
John Kessenich140f3df2015-06-26 16:58:36 -0600309
310 // Create a call to a built-in function.
John Kessenich32cfd492016-02-02 12:37:46 -0700311 Id createBuiltinCall(Id resultType, Id builtins, int entryPoint, std::vector<Id>& args);
John Kessenich140f3df2015-06-26 16:58:36 -0600312
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;
John Kessenich5e4b1242015-08-06 22:53:06 -0600321 Id offsets;
John Kessenich140f3df2015-06-26 16:58:36 -0600322 Id gradX;
323 Id gradY;
John Kessenich5e4b1242015-08-06 22:53:06 -0600324 Id sample;
John Kessenich76d4dfc2016-06-16 12:43:23 -0600325 Id component;
Rex Xu48edadf2015-12-31 16:11:41 +0800326 Id texelOut;
327 Id lodClamp;
John Kessenich140f3df2015-06-26 16:58:36 -0600328 };
329
330 // Select the correct texture operation based on all inputs, and emit the correct instruction
John Kessenich019f08f2016-02-15 15:40:42 -0700331 Id createTextureCall(Decoration precision, Id resultType, bool sparse, bool fetch, bool proj, bool gather, bool noImplicit, const TextureParameters&);
John Kessenich140f3df2015-06-26 16:58:36 -0600332
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
John Kessenich32cfd492016-02-02 12:37:46 -0700342 // Reduction comparison for composites: For equal and not-equal resulting in a scalar.
John Kessenich22118352015-12-21 20:54:09 -0700343 Id createCompositeCompare(Decoration precision, Id, Id, bool /* true if for equal, false if for not-equal */);
John Kessenich140f3df2015-06-26 16:58:36 -0600344
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
Dejan Mircevski9c6734c2016-01-10 12:15:13 -0500400 struct LoopBlocks {
John Kessenich7f349c72016-07-08 22:09:10 -0600401 LoopBlocks(Block& head, Block& body, Block& merge, Block& continue_target) :
402 head(head), body(body), merge(merge), continue_target(continue_target) { }
Dejan Mircevski832c65c2016-01-11 15:57:11 -0500403 Block &head, &body, &merge, &continue_target;
John Kessenich7f349c72016-07-08 22:09:10 -0600404 private:
405 LoopBlocks();
406 LoopBlocks& operator=(const LoopBlocks&);
Dejan Mircevski9c6734c2016-01-10 12:15:13 -0500407 };
Dejan Mircevski9c6734c2016-01-10 12:15:13 -0500408
Dejan Mircevski7819bee2016-01-11 09:35:22 -0500409 // 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.
Dejan Mircevski9c6734c2016-01-10 12:15:13 -0500416 Block& makeNewBlock();
John Kessenich140f3df2015-06-26 16:58:36 -0600417
Dejan Mircevski7819bee2016-01-11 09:35:22 -0500418 // Add a branch to the continue_target of the current (innermost) loop.
John Kessenich140f3df2015-06-26 16:58:36 -0600419 void createLoopContinue();
420
Dejan Mircevski7819bee2016-01-11 09:35:22 -0500421 // Add an exit (e.g. "break") from the innermost loop that we're currently
422 // in.
John Kessenich140f3df2015-06-26 16:58:36 -0600423 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 {
John Kessenich55e7d112015-11-15 21:33:39 -0700459 Id base; // for l-values, pointer to the base object, for r-values, the base object
John Kessenich140f3df2015-06-26 16:58:36 -0600460 std::vector<Id> indexChain;
John Kessenich55e7d112015-11-15 21:33:39 -0700461 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
John Kessenich140f3df2015-06-26 16:58:36 -0600466 };
467
468 //
469 // the SPIR-V builder maintains a single active chain that
John Kessenichf2b7f332016-09-01 17:05:23 -0600470 // the following methods operate on
John Kessenich140f3df2015-06-26 16:58:36 -0600471 //
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;
John Kessenich140f3df2015-06-26 16:58:36 -0600485 }
486
487 // set new base value as an r-value
488 void setAccessChainRValue(Id rValue)
489 {
490 accessChain.isRValue = true;
491 accessChain.base = rValue;
John Kessenich140f3df2015-06-26 16:58:36 -0600492 }
493
494 // push offset onto the end of the chain
John Kessenichfa668da2015-09-13 14:46:30 -0600495 void accessChainPush(Id offset)
John Kessenich140f3df2015-06-26 16:58:36 -0600496 {
497 accessChain.indexChain.push_back(offset);
John Kessenich140f3df2015-06-26 16:58:36 -0600498 }
499
500 // push new swizzle onto the end of any existing swizzle, merging into a single swizzle
John Kessenichfa668da2015-09-13 14:46:30 -0600501 void accessChainPushSwizzle(std::vector<unsigned>& swizzle, Id preSwizzleBaseType);
John Kessenich140f3df2015-06-26 16:58:36 -0600502
503 // push a variable component selection onto the access chain; supporting only one, so unsided
John Kessenichfa668da2015-09-13 14:46:30 -0600504 void accessChainPushComponent(Id component, Id preSwizzleBaseType)
505 {
506 accessChain.component = component;
507 if (accessChain.preSwizzleBaseType == NoType)
508 accessChain.preSwizzleBaseType = preSwizzleBaseType;
509 }
John Kessenich140f3df2015-06-26 16:58:36 -0600510
511 // use accessChain and swizzle to store value
512 void accessChainStore(Id rvalue);
513
514 // use accessChain and swizzle to load an r-value
John Kessenich32cfd492016-02-02 12:37:46 -0700515 Id accessChainLoad(Decoration precision, Id ResultType);
John Kessenich140f3df2015-06-26 16:58:36 -0600516
517 // get the direct pointer for an l-value
518 Id accessChainGetLValue();
519
John Kessenich103bef92016-02-08 21:38:15 -0700520 // 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
qiningda397332016-03-09 19:54:03 -0500524 // Remove OpDecorate instructions whose operands are defined in unreachable
525 // blocks.
526 void eliminateDeadDecorations();
John Kessenich140f3df2015-06-26 16:58:36 -0600527 void dump(std::vector<unsigned int>&) const;
528
Dejan Mircevski9c6734c2016-01-10 12:15:13 -0500529 void createBranch(Block* block);
530 void createConditionalBranch(Id condition, Block* thenBlock, Block* elseBlock);
531 void createLoopMerge(Block* mergeBlock, Block* continueBlock, unsigned int control);
532
qining13545202016-03-21 09:51:37 -0400533 // 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
Dejan Mircevski9c6734c2016-01-10 12:15:13 -0500540 protected:
John Kessenich55e7d112015-11-15 21:33:39 -0700541 Id makeIntConstant(Id typeId, unsigned value, bool specConstant);
Rex Xu8ff43de2016-04-22 16:51:45 +0800542 Id makeInt64Constant(Id typeId, unsigned long long value, bool specConstant);
John Kessenich55e7d112015-11-15 21:33:39 -0700543 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;
John Kessenich140f3df2015-06-26 16:58:36 -0600545 Id findCompositeConstant(Op typeClass, std::vector<Id>& comps) const;
546 Id collapseAccessChain();
John Kessenich55e7d112015-11-15 21:33:39 -0700547 void transferAccessChainSwizzle(bool dynamic);
John Kessenich140f3df2015-06-26 16:58:36 -0600548 void simplifyAccessChainSwizzle();
John Kessenich140f3df2015-06-26 16:58:36 -0600549 void createAndSetNoPredecessorBlock(const char*);
John Kessenich55e7d112015-11-15 21:33:39 -0700550 void createSelectionMerge(Block* mergeBlock, unsigned int control);
Andrew Woloszynb7946d12016-01-18 09:23:56 -0500551 void dumpInstructions(std::vector<unsigned int>&, const std::vector<std::unique_ptr<Instruction> >&) const;
John Kessenich140f3df2015-06-26 16:58:36 -0600552
553 SourceLanguage source;
554 int sourceVersion;
555 std::vector<const char*> extensions;
Rex Xu9d93a232016-05-05 12:30:44 +0800556 std::vector<const char*> sourceExtensions;
John Kessenich140f3df2015-06-26 16:58:36 -0600557 AddressingModel addressModel;
558 MemoryModel memoryModel;
John Kessenich92187592016-02-01 13:45:25 -0700559 std::set<spv::Capability> capabilities;
John Kessenich140f3df2015-06-26 16:58:36 -0600560 int builderNumber;
561 Module module;
562 Block* buildPoint;
563 Id uniqueId;
564 Function* mainFunction;
qining13545202016-03-21 09:51:37 -0400565 bool generatingOpCodeForSpecConst;
John Kessenich140f3df2015-06-26 16:58:36 -0600566 AccessChain accessChain;
567
568 // special blocks of instructions for output
Andrew Woloszynb7946d12016-01-18 09:23:56 -0500569 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;
John Kessenich140f3df2015-06-26 16:58:36 -0600578
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
John Kessenich140f3df2015-06-26 16:58:36 -0600586 // Our loop stack.
Dejan Mircevski7819bee2016-01-11 09:35:22 -0500587 std::stack<LoopBlocks> loops;
Lei Zhang09caf122016-05-02 18:11:54 -0400588
589 // The stream for outputing warnings and errors.
Lei Zhang17535f72016-05-04 15:55:59 -0400590 SpvBuildLogger* logger;
John Kessenich140f3df2015-06-26 16:58:36 -0600591}; // end Builder class
592
John Kessenich140f3df2015-06-26 16:58:36 -0600593}; // end spv namespace
594
595#endif // SpvBuilder_H