blob: dc76daec9c8b5c126278aa5e2144e49c68572305 [file] [log] [blame]
John Kessenich140f3df2015-06-26 16:58:36 -06001//
John Kessenich927608b2017-01-06 12:34:14 -07002// Copyright (C) 2014-2015 LunarG, Inc.
3// Copyright (C) 2015-2016 Google, Inc.
John Kessenich66011cb2018-03-06 16:12:04 -07004// Copyright (C) 2017 ARM Limited.
John Kessenich140f3df2015-06-26 16:58:36 -06005//
John Kessenich927608b2017-01-06 12:34:14 -07006// All rights reserved.
John Kessenich140f3df2015-06-26 16:58:36 -06007//
John Kessenich927608b2017-01-06 12:34:14 -07008// Redistribution and use in source and binary forms, with or without
9// modification, are permitted provided that the following conditions
10// are met:
John Kessenich140f3df2015-06-26 16:58:36 -060011//
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//
John Kessenich927608b2017-01-06 12:34:14 -070024// 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.
John Kessenich140f3df2015-06-26 16:58:36 -060036
37//
John Kessenich140f3df2015-06-26 16:58:36 -060038// "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
Lei Zhang17535f72016-05-04 15:55:59 -040049#include "Logger.h"
John Kessenich5e4b1242015-08-06 22:53:06 -060050#include "spirv.hpp"
John Kessenich140f3df2015-06-26 16:58:36 -060051#include "spvIR.h"
52
53#include <algorithm>
John Kessenich140f3df2015-06-26 16:58:36 -060054#include <map>
Lei Zhang09caf122016-05-02 18:11:54 -040055#include <memory>
John Kessenich92187592016-02-01 13:45:25 -070056#include <set>
Lei Zhang09caf122016-05-02 18:11:54 -040057#include <sstream>
58#include <stack>
John Kessenich46413d52018-02-26 19:20:05 -070059#include <unordered_map>
John Kessenich140f3df2015-06-26 16:58:36 -060060
61namespace spv {
62
63class Builder {
64public:
John Kessenich2b5ea9f2018-01-31 18:35:56 -070065 Builder(unsigned int spvVersion, unsigned int userNumber, SpvBuildLogger* logger);
John Kessenich140f3df2015-06-26 16:58:36 -060066 virtual ~Builder();
67
68 static const int maxMatrixSize = 4;
69
John Kessenich66011cb2018-03-06 16:12:04 -070070 unsigned int getSpvVersion() const { return spvVersion; }
71
John Kessenich140f3df2015-06-26 16:58:36 -060072 void setSource(spv::SourceLanguage lang, int version)
73 {
74 source = lang;
75 sourceVersion = version;
76 }
John Kessenich121853f2017-05-31 17:11:16 -060077 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; }
Rex Xu9d93a232016-05-05 12:30:44 +080085 void addSourceExtension(const char* ext) { sourceExtensions.push_back(ext); }
John Kessenich2a271162017-07-20 20:00:36 -060086 void addModuleProcessed(const std::string& p) { moduleProcesses.push_back(p.c_str()); }
John Kesseniche485c7a2017-05-31 18:50:53 -060087 void setEmitOpLines() { emitOpLines = true; }
Rex Xu51596642016-09-21 18:56:12 +080088 void addExtension(const char* ext) { extensions.insert(ext); }
John Kessenich140f3df2015-06-26 16:58:36 -060089 Id import(const char*);
90 void setMemoryModel(spv::AddressingModel addr, spv::MemoryModel mem)
91 {
92 addressModel = addr;
93 memoryModel = mem;
94 }
95
John Kessenich92187592016-02-01 13:45:25 -070096 void addCapability(spv::Capability cap) { capabilities.insert(cap); }
John Kessenich5e4b1242015-08-06 22:53:06 -060097
John Kessenich140f3df2015-06-26 16:58:36 -060098 // 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
John Kesseniche485c7a2017-05-31 18:50:53 -0600109 // 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
John Kessenich140f3df2015-06-26 16:58:36 -0600115 // 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);
John Kessenich32cfd492016-02-02 12:37:46 -0700123 Id makeStructType(const std::vector<Id>& members, const char*);
John Kessenich55e7d112015-11-15 21:33:39 -0700124 Id makeStructResultType(Id type0, Id type1);
John Kessenich140f3df2015-06-26 16:58:36 -0600125 Id makeVectorType(Id component, int size);
126 Id makeMatrixType(Id component, int cols, int rows);
John Kessenich6c292d32016-02-15 20:58:50 -0700127 Id makeArrayType(Id element, Id sizeId, int stride); // 0 stride means no stride decoration
John Kessenichc9a80832015-09-12 12:17:44 -0600128 Id makeRuntimeArray(Id element);
John Kessenich32cfd492016-02-02 12:37:46 -0700129 Id makeFunctionType(Id returnType, const std::vector<Id>& paramTypes);
John Kessenich5e4b1242015-08-06 22:53:06 -0600130 Id makeImageType(Id sampledType, Dim, bool depth, bool arrayed, bool ms, unsigned sampled, ImageFormat format);
John Kessenich55e7d112015-11-15 21:33:39 -0700131 Id makeSamplerType();
John Kessenich5e4b1242015-08-06 22:53:06 -0600132 Id makeSampledImageType(Id imageType);
John Kessenich140f3df2015-06-26 16:58:36 -0600133
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)); }
John Kessenich22118352015-12-21 20:54:09 -0700141 int getNumTypeConstituents(Id typeId) const;
142 int getNumTypeComponents(Id typeId) const { return getNumTypeConstituents(typeId); }
John Kessenich140f3df2015-06-26 16:58:36 -0600143 Id getScalarTypeId(Id typeId) const;
144 Id getContainedTypeId(Id typeId) const;
145 Id getContainedTypeId(Id typeId, int) const;
John Kessenich55e7d112015-11-15 21:33:39 -0700146 StorageClass getTypeStorageClass(Id typeId) const { return module.getStorageClass(typeId); }
John Kessenich5d0fa972016-02-15 11:57:00 -0700147 ImageFormat getImageTypeFormat(Id typeId) const { return (ImageFormat)module.getInstruction(typeId)->getImmediateOperand(6); }
John Kessenich140f3df2015-06-26 16:58:36 -0600148
John Kessenich33661452015-12-08 19:32:47 -0700149 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)); }
John Kessenich140f3df2015-06-26 16:58:36 -0600155
John Kessenich46413d52018-02-26 19:20:05 -0700156 bool isBoolType(Id typeId) { return groupedTypes[OpTypeBool].size() > 0 && typeId == groupedTypes[OpTypeBool].back()->getResultId(); }
Rex Xu470026f2017-03-29 17:12:40 +0800157 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; }
John Kessenich33661452015-12-08 19:32:47 -0700160 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; }
John Kessenich140f3df2015-06-26 16:58:36 -0600170
John Kessenich71631272015-10-13 10:39:19 -0600171 bool isConstantOpCode(Op opcode) const;
qining27e04a02016-04-14 16:40:20 -0400172 bool isSpecConstantOpCode(Op opcode) const;
John Kessenich71631272015-10-13 10:39:19 -0600173 bool isConstant(Id resultId) const { return isConstantOpCode(getOpCode(resultId)); }
John Kessenich140f3df2015-06-26 16:58:36 -0600174 bool isConstantScalar(Id resultId) const { return getOpCode(resultId) == OpConstant; }
qining27e04a02016-04-14 16:40:20 -0400175 bool isSpecConstant(Id resultId) const { return isSpecConstantOpCode(getOpCode(resultId)); }
John Kessenich140f3df2015-06-26 16:58:36 -0600176 unsigned int getConstantScalar(Id resultId) const { return module.getInstruction(resultId)->getImmediateOperand(0); }
John Kessenich55e7d112015-11-15 21:33:39 -0700177 StorageClass getStorageClass(Id resultId) const { return getTypeStorageClass(getTypeId(resultId)); }
John Kessenich140f3df2015-06-26 16:58:36 -0600178
Rex Xu470026f2017-03-29 17:12:40 +0800179 int getScalarTypeWidth(Id typeId) const
180 {
181 Id scalarTypeId = getScalarTypeId(typeId);
182 assert(getTypeClass(scalarTypeId) == OpTypeInt || getTypeClass(scalarTypeId) == OpTypeFloat);
183 return module.getInstruction(scalarTypeId)->getImmediateOperand(0);
184 }
185
John Kessenich140f3df2015-06-26 16:58:36 -0600186 int getTypeNumColumns(Id typeId) const
187 {
188 assert(isMatrixType(typeId));
John Kessenich22118352015-12-21 20:54:09 -0700189 return getNumTypeConstituents(typeId);
John Kessenich140f3df2015-06-26 16:58:36 -0600190 }
191 int getNumColumns(Id resultId) const { return getTypeNumColumns(getTypeId(resultId)); }
192 int getTypeNumRows(Id typeId) const
193 {
194 assert(isMatrixType(typeId));
195 return getNumTypeComponents(getContainedTypeId(typeId));
196 }
197 int getNumRows(Id resultId) const { return getTypeNumRows(getTypeId(resultId)); }
198
John Kessenich5e4b1242015-08-06 22:53:06 -0600199 Dim getTypeDimensionality(Id typeId) const
John Kessenich140f3df2015-06-26 16:58:36 -0600200 {
John Kessenich5e4b1242015-08-06 22:53:06 -0600201 assert(isImageType(typeId));
202 return (Dim)module.getInstruction(typeId)->getImmediateOperand(1);
John Kessenich140f3df2015-06-26 16:58:36 -0600203 }
John Kessenich5e4b1242015-08-06 22:53:06 -0600204 Id getImageType(Id resultId) const
John Kessenich140f3df2015-06-26 16:58:36 -0600205 {
Rex Xu6b86d492015-09-16 17:48:22 +0800206 Id typeId = getTypeId(resultId);
207 assert(isImageType(typeId) || isSampledImageType(typeId));
208 return isSampledImageType(typeId) ? module.getInstruction(typeId)->getIdOperand(0) : typeId;
John Kessenich5e4b1242015-08-06 22:53:06 -0600209 }
210 bool isArrayedImageType(Id typeId) const
211 {
212 assert(isImageType(typeId));
213 return module.getInstruction(typeId)->getImmediateOperand(3) != 0;
John Kessenich140f3df2015-06-26 16:58:36 -0600214 }
215
216 // For making new constants (will return old constant if the requested one was already made).
John Kessenich55e7d112015-11-15 21:33:39 -0700217 Id makeBoolConstant(bool b, bool specConstant = false);
John Kessenich66011cb2018-03-06 16:12:04 -0700218 Id makeInt8Constant(int i, bool specConstant = false) { return makeIntConstant(makeIntType(8), (unsigned)i, specConstant); }
219 Id makeUint8Constant(unsigned u, bool specConstant = false) { return makeIntConstant(makeUintType(8), u, specConstant); }
220 Id makeInt16Constant(int i, bool specConstant = false) { return makeIntConstant(makeIntType(16), (unsigned)i, specConstant); }
221 Id makeUint16Constant(unsigned u, bool specConstant = false) { return makeIntConstant(makeUintType(16), u, specConstant); }
John Kessenich55e7d112015-11-15 21:33:39 -0700222 Id makeIntConstant(int i, bool specConstant = false) { return makeIntConstant(makeIntType(32), (unsigned)i, specConstant); }
223 Id makeUintConstant(unsigned u, bool specConstant = false) { return makeIntConstant(makeUintType(32), u, specConstant); }
Rex Xu8ff43de2016-04-22 16:51:45 +0800224 Id makeInt64Constant(long long i, bool specConstant = false) { return makeInt64Constant(makeIntType(64), (unsigned long long)i, specConstant); }
225 Id makeUint64Constant(unsigned long long u, bool specConstant = false) { return makeInt64Constant(makeUintType(64), u, specConstant); }
John Kessenich55e7d112015-11-15 21:33:39 -0700226 Id makeFloatConstant(float f, bool specConstant = false);
227 Id makeDoubleConstant(double d, bool specConstant = false);
Rex Xuc9e3c3c2016-07-29 16:00:05 +0800228 Id makeFloat16Constant(float f16, bool specConstant = false);
Neil Robertseddb1312018-03-13 10:57:59 +0100229 Id makeFpConstant(Id type, double d, bool specConstant = false);
John Kessenich140f3df2015-06-26 16:58:36 -0600230
231 // Turn the array of constants into a proper spv constant of the requested type.
Vlad Ivanov689490f2017-01-26 20:46:02 +0300232 Id makeCompositeConstant(Id type, const std::vector<Id>& comps, bool specConst = false);
John Kessenich140f3df2015-06-26 16:58:36 -0600233
234 // Methods for adding information outside the CFG.
John Kessenich55e7d112015-11-15 21:33:39 -0700235 Instruction* addEntryPoint(ExecutionModel, Function*, const char* name);
John Kessenichb56a26a2015-09-16 16:04:05 -0600236 void addExecutionMode(Function*, ExecutionMode mode, int value1 = -1, int value2 = -1, int value3 = -1);
John Kessenich140f3df2015-06-26 16:58:36 -0600237 void addName(Id, const char* name);
238 void addMemberName(Id, int member, const char* name);
John Kessenich140f3df2015-06-26 16:58:36 -0600239 void addDecoration(Id, Decoration, int num = -1);
John Kessenich5d610ee2018-03-07 18:05:55 -0700240 void addDecoration(Id, Decoration, const char*);
241 void addDecorationId(Id id, Decoration, Id idDecoration);
John Kessenich140f3df2015-06-26 16:58:36 -0600242 void addMemberDecoration(Id, unsigned int member, Decoration, int num = -1);
John Kessenich5d610ee2018-03-07 18:05:55 -0700243 void addMemberDecoration(Id, unsigned int member, Decoration, const char*);
John Kessenich140f3df2015-06-26 16:58:36 -0600244
245 // At the end of what block do the next create*() instructions go?
246 void setBuildPoint(Block* bp) { buildPoint = bp; }
247 Block* getBuildPoint() const { return buildPoint; }
248
John Kessenich4d65ee32016-03-12 18:17:47 -0700249 // Make the entry-point function. The returned pointer is only valid
Andrew Woloszynb7946d12016-01-18 09:23:56 -0500250 // for the lifetime of this builder.
John Kessenich6fccb3c2016-09-19 16:01:41 -0600251 Function* makeEntryPoint(const char*);
John Kessenich140f3df2015-06-26 16:58:36 -0600252
John Kessenich140f3df2015-06-26 16:58:36 -0600253 // Make a shader-style function, and create its entry block if entry is non-zero.
254 // Return the function, pass back the entry.
Andrew Woloszynb7946d12016-01-18 09:23:56 -0500255 // The returned pointer is only valid for the lifetime of this builder.
John Kessenich32cfd492016-02-02 12:37:46 -0700256 Function* makeFunctionEntry(Decoration precision, Id returnType, const char* name, const std::vector<Id>& paramTypes,
John Kessenichfad62972017-07-18 02:35:46 -0600257 const std::vector<std::vector<Decoration>>& precisions, Block **entry = 0);
John Kessenich140f3df2015-06-26 16:58:36 -0600258
John Kesseniche770b3e2015-09-14 20:58:02 -0600259 // Create a return. An 'implicit' return is one not appearing in the source
260 // code. In the case of an implicit return, no post-return block is inserted.
261 void makeReturn(bool implicit, Id retVal = 0);
John Kessenich140f3df2015-06-26 16:58:36 -0600262
263 // Generate all the code needed to finish up a function.
John Kesseniche770b3e2015-09-14 20:58:02 -0600264 void leaveFunction();
John Kessenich140f3df2015-06-26 16:58:36 -0600265
266 // Create a discard.
267 void makeDiscard();
268
269 // Create a global or function local or IO variable.
270 Id createVariable(StorageClass, Id type, const char* name = 0);
271
John Kessenich32cfd492016-02-02 12:37:46 -0700272 // Create an intermediate with an undefined value.
Miro Knejp28f9b1c2015-08-11 02:45:24 +0200273 Id createUndefined(Id type);
274
John Kessenich140f3df2015-06-26 16:58:36 -0600275 // Store into an Id and return the l-value
276 void createStore(Id rValue, Id lValue);
277
278 // Load from an Id and return it
279 Id createLoad(Id lValue);
280
281 // Create an OpAccessChain instruction
Vlad Ivanov689490f2017-01-26 20:46:02 +0300282 Id createAccessChain(StorageClass, Id base, const std::vector<Id>& offsets);
John Kessenich140f3df2015-06-26 16:58:36 -0600283
John Kessenichee21fc92015-09-21 21:50:29 -0600284 // Create an OpArrayLength instruction
285 Id createArrayLength(Id base, unsigned int member);
286
John Kessenich140f3df2015-06-26 16:58:36 -0600287 // Create an OpCompositeExtract instruction
288 Id createCompositeExtract(Id composite, Id typeId, unsigned index);
Vlad Ivanov689490f2017-01-26 20:46:02 +0300289 Id createCompositeExtract(Id composite, Id typeId, const std::vector<unsigned>& indexes);
John Kessenich140f3df2015-06-26 16:58:36 -0600290 Id createCompositeInsert(Id object, Id composite, Id typeId, unsigned index);
Vlad Ivanov689490f2017-01-26 20:46:02 +0300291 Id createCompositeInsert(Id object, Id composite, Id typeId, const std::vector<unsigned>& indexes);
John Kessenich140f3df2015-06-26 16:58:36 -0600292
293 Id createVectorExtractDynamic(Id vector, Id typeId, Id componentIndex);
294 Id createVectorInsertDynamic(Id vector, Id typeId, Id component, Id componentIndex);
295
296 void createNoResultOp(Op);
297 void createNoResultOp(Op, Id operand);
Rex Xufc618912015-09-09 16:42:49 +0800298 void createNoResultOp(Op, const std::vector<Id>& operands);
John Kessenich5e4b1242015-08-06 22:53:06 -0600299 void createControlBarrier(Scope execution, Scope memory, MemorySemanticsMask);
John Kessenich140f3df2015-06-26 16:58:36 -0600300 void createMemoryBarrier(unsigned executionScope, unsigned memorySemantics);
301 Id createUnaryOp(Op, Id typeId, Id operand);
302 Id createBinOp(Op, Id typeId, Id operand1, Id operand2);
303 Id createTriOp(Op, Id typeId, Id operand1, Id operand2, Id operand3);
John Kessenich5e4b1242015-08-06 22:53:06 -0600304 Id createOp(Op, Id typeId, const std::vector<Id>& operands);
Vlad Ivanov689490f2017-01-26 20:46:02 +0300305 Id createFunctionCall(spv::Function*, const std::vector<spv::Id>&);
qining13545202016-03-21 09:51:37 -0400306 Id createSpecConstantOp(Op, Id typeId, const std::vector<spv::Id>& operands, const std::vector<unsigned>& literals);
John Kessenich140f3df2015-06-26 16:58:36 -0600307
308 // Take an rvalue (source) and a set of channels to extract from it to
309 // make a new rvalue, which is returned.
Vlad Ivanov689490f2017-01-26 20:46:02 +0300310 Id createRvalueSwizzle(Decoration precision, Id typeId, Id source, const std::vector<unsigned>& channels);
John Kessenich140f3df2015-06-26 16:58:36 -0600311
312 // Take a copy of an lvalue (target) and a source of components, and set the
313 // source components into the lvalue where the 'channels' say to put them.
314 // An updated version of the target is returned.
315 // (No true lvalue or stores are used.)
Vlad Ivanov689490f2017-01-26 20:46:02 +0300316 Id createLvalueSwizzle(Id typeId, Id target, Id source, const std::vector<unsigned>& channels);
John Kessenich140f3df2015-06-26 16:58:36 -0600317
John Kessenich32cfd492016-02-02 12:37:46 -0700318 // If both the id and precision are valid, the id
319 // gets tagged with the requested precision.
320 // The passed in id is always the returned id, to simplify use patterns.
321 Id setPrecision(Id id, Decoration precision)
John Kessenich140f3df2015-06-26 16:58:36 -0600322 {
John Kessenich32cfd492016-02-02 12:37:46 -0700323 if (precision != NoPrecision && id != NoResult)
324 addDecoration(id, precision);
325
326 return id;
John Kessenich140f3df2015-06-26 16:58:36 -0600327 }
328
329 // Can smear a scalar to a vector for the following forms:
330 // - promoteScalar(scalar, vector) // smear scalar to width of vector
331 // - promoteScalar(vector, scalar) // smear scalar to width of vector
332 // - promoteScalar(pointer, scalar) // smear scalar to width of what pointer points to
333 // - promoteScalar(scalar, scalar) // do nothing
334 // Other forms are not allowed.
335 //
John Kessenich76f71392015-12-09 19:08:42 -0700336 // Generally, the type of 'scalar' does not need to be the same type as the components in 'vector'.
337 // The type of the created vector is a vector of components of the same type as the scalar.
338 //
John Kessenich66011cb2018-03-06 16:12:04 -0700339 // Note: One of the arguments will change, with the result coming back that way rather than
John Kessenich140f3df2015-06-26 16:58:36 -0600340 // through the return value.
341 void promoteScalar(Decoration precision, Id& left, Id& right);
342
John Kessenich76f71392015-12-09 19:08:42 -0700343 // Make a value by smearing the scalar to fill the type.
344 // vectorType should be the correct type for making a vector of scalarVal.
345 // (No conversions are done.)
346 Id smearScalar(Decoration precision, Id scalarVal, Id vectorType);
John Kessenich140f3df2015-06-26 16:58:36 -0600347
348 // Create a call to a built-in function.
Vlad Ivanov689490f2017-01-26 20:46:02 +0300349 Id createBuiltinCall(Id resultType, Id builtins, int entryPoint, const std::vector<Id>& args);
John Kessenich140f3df2015-06-26 16:58:36 -0600350
351 // List of parameters used to create a texture operation
352 struct TextureParameters {
353 Id sampler;
354 Id coords;
355 Id bias;
356 Id lod;
357 Id Dref;
358 Id offset;
John Kessenich5e4b1242015-08-06 22:53:06 -0600359 Id offsets;
John Kessenich140f3df2015-06-26 16:58:36 -0600360 Id gradX;
361 Id gradY;
John Kessenich5e4b1242015-08-06 22:53:06 -0600362 Id sample;
John Kessenich76d4dfc2016-06-16 12:43:23 -0600363 Id component;
Rex Xu48edadf2015-12-31 16:11:41 +0800364 Id texelOut;
365 Id lodClamp;
John Kessenich140f3df2015-06-26 16:58:36 -0600366 };
367
368 // Select the correct texture operation based on all inputs, and emit the correct instruction
John Kessenich019f08f2016-02-15 15:40:42 -0700369 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 -0600370
371 // Emit the OpTextureQuery* instruction that was passed in.
372 // Figure out the right return value and type, and return it.
steve-lunarg0b5c2ae2017-03-10 12:45:50 -0700373 Id createTextureQueryCall(Op, const TextureParameters&, bool isUnsignedResult);
John Kessenich140f3df2015-06-26 16:58:36 -0600374
375 Id createSamplePositionCall(Decoration precision, Id, Id);
376
377 Id createBitFieldExtractCall(Decoration precision, Id, Id, Id, bool isSigned);
378 Id createBitFieldInsertCall(Decoration precision, Id, Id, Id, Id);
379
John Kessenich32cfd492016-02-02 12:37:46 -0700380 // Reduction comparison for composites: For equal and not-equal resulting in a scalar.
John Kessenich22118352015-12-21 20:54:09 -0700381 Id createCompositeCompare(Decoration precision, Id, Id, bool /* true if for equal, false if for not-equal */);
John Kessenich140f3df2015-06-26 16:58:36 -0600382
383 // OpCompositeConstruct
Vlad Ivanov689490f2017-01-26 20:46:02 +0300384 Id createCompositeConstruct(Id typeId, const std::vector<Id>& constituents);
John Kessenich140f3df2015-06-26 16:58:36 -0600385
386 // vector or scalar constructor
387 Id createConstructor(Decoration precision, const std::vector<Id>& sources, Id resultTypeId);
388
389 // matrix constructor
390 Id createMatrixConstructor(Decoration precision, const std::vector<Id>& sources, Id constructee);
391
392 // Helper to use for building nested control flow with if-then-else.
393 class If {
394 public:
Rex Xu57e65922017-07-04 23:23:40 +0800395 If(Id condition, unsigned int ctrl, Builder& builder);
John Kessenich140f3df2015-06-26 16:58:36 -0600396 ~If() {}
397
398 void makeBeginElse();
399 void makeEndIf();
400
401 private:
402 If(const If&);
403 If& operator=(If&);
404
405 Builder& builder;
406 Id condition;
Rex Xu57e65922017-07-04 23:23:40 +0800407 unsigned int control;
John Kessenich140f3df2015-06-26 16:58:36 -0600408 Function* function;
409 Block* headerBlock;
410 Block* thenBlock;
411 Block* elseBlock;
412 Block* mergeBlock;
413 };
414
415 // Make a switch statement. A switch has 'numSegments' of pieces of code, not containing
416 // any case/default labels, all separated by one or more case/default labels. Each possible
417 // case value v is a jump to the caseValues[v] segment. The defaultSegment is also in this
418 // number space. How to compute the value is given by 'condition', as in switch(condition).
419 //
420 // The SPIR-V Builder will maintain the stack of post-switch merge blocks for nested switches.
421 //
422 // Use a defaultSegment < 0 if there is no default segment (to branch to post switch).
423 //
424 // Returns the right set of basic blocks to start each code segment with, so that the caller's
425 // recursion stack can hold the memory for it.
426 //
Rex Xu57e65922017-07-04 23:23:40 +0800427 void makeSwitch(Id condition, unsigned int control, int numSegments, const std::vector<int>& caseValues,
Vlad Ivanov689490f2017-01-26 20:46:02 +0300428 const std::vector<int>& valueToSegment, int defaultSegment, std::vector<Block*>& segmentBB); // return argument
John Kessenich140f3df2015-06-26 16:58:36 -0600429
430 // Add a branch to the innermost switch's merge block.
431 void addSwitchBreak();
432
433 // Move to the next code segment, passing in the return argument in makeSwitch()
434 void nextSwitchSegment(std::vector<Block*>& segmentBB, int segment);
435
436 // Finish off the innermost switch.
437 void endSwitch(std::vector<Block*>& segmentBB);
438
Dejan Mircevski9c6734c2016-01-10 12:15:13 -0500439 struct LoopBlocks {
John Kessenich7f349c72016-07-08 22:09:10 -0600440 LoopBlocks(Block& head, Block& body, Block& merge, Block& continue_target) :
441 head(head), body(body), merge(merge), continue_target(continue_target) { }
Dejan Mircevski832c65c2016-01-11 15:57:11 -0500442 Block &head, &body, &merge, &continue_target;
John Kessenich7f349c72016-07-08 22:09:10 -0600443 private:
444 LoopBlocks();
445 LoopBlocks& operator=(const LoopBlocks&);
Dejan Mircevski9c6734c2016-01-10 12:15:13 -0500446 };
Dejan Mircevski9c6734c2016-01-10 12:15:13 -0500447
Dejan Mircevski7819bee2016-01-11 09:35:22 -0500448 // Start a new loop and prepare the builder to generate code for it. Until
449 // closeLoop() is called for this loop, createLoopContinue() and
450 // createLoopExit() will target its corresponding blocks.
451 LoopBlocks& makeNewLoop();
452
453 // Create a new block in the function containing the build point. Memory is
454 // owned by the function object.
Dejan Mircevski9c6734c2016-01-10 12:15:13 -0500455 Block& makeNewBlock();
John Kessenich140f3df2015-06-26 16:58:36 -0600456
Dejan Mircevski7819bee2016-01-11 09:35:22 -0500457 // Add a branch to the continue_target of the current (innermost) loop.
John Kessenich140f3df2015-06-26 16:58:36 -0600458 void createLoopContinue();
459
Dejan Mircevski7819bee2016-01-11 09:35:22 -0500460 // Add an exit (e.g. "break") from the innermost loop that we're currently
461 // in.
John Kessenich140f3df2015-06-26 16:58:36 -0600462 void createLoopExit();
463
464 // Close the innermost loop that you're in
465 void closeLoop();
466
467 //
468 // Access chain design for an R-Value vs. L-Value:
469 //
470 // There is a single access chain the builder is building at
471 // any particular time. Such a chain can be used to either to a load or
472 // a store, when desired.
473 //
474 // Expressions can be r-values, l-values, or both, or only r-values:
475 // a[b.c].d = .... // l-value
476 // ... = a[b.c].d; // r-value, that also looks like an l-value
477 // ++a[b.c].d; // r-value and l-value
478 // (x + y)[2]; // r-value only, can't possibly be l-value
479 //
480 // Computing an r-value means generating code. Hence,
481 // r-values should only be computed when they are needed, not speculatively.
482 //
483 // Computing an l-value means saving away information for later use in the compiler,
484 // no code is generated until the l-value is later dereferenced. It is okay
485 // to speculatively generate an l-value, just not okay to speculatively dereference it.
486 //
487 // The base of the access chain (the left-most variable or expression
488 // from which everything is based) can be set either as an l-value
489 // or as an r-value. Most efficient would be to set an l-value if one
490 // is available. If an expression was evaluated, the resulting r-value
491 // can be set as the chain base.
492 //
493 // The users of this single access chain can save and restore if they
494 // want to nest or manage multiple chains.
495 //
496
497 struct AccessChain {
John Kessenich55e7d112015-11-15 21:33:39 -0700498 Id base; // for l-values, pointer to the base object, for r-values, the base object
John Kessenich140f3df2015-06-26 16:58:36 -0600499 std::vector<Id> indexChain;
John Kessenich55e7d112015-11-15 21:33:39 -0700500 Id instr; // cache the instruction that generates this access chain
501 std::vector<unsigned> swizzle; // each std::vector element selects the next GLSL component number
502 Id component; // a dynamic component index, can coexist with a swizzle, done after the swizzle, NoResult if not present
503 Id preSwizzleBaseType; // dereferenced type, before swizzle or component is applied; NoType unless a swizzle or component is present
504 bool isRValue; // true if 'base' is an r-value, otherwise, base is an l-value
John Kessenich140f3df2015-06-26 16:58:36 -0600505 };
506
507 //
508 // the SPIR-V builder maintains a single active chain that
John Kessenichf2b7f332016-09-01 17:05:23 -0600509 // the following methods operate on
John Kessenich140f3df2015-06-26 16:58:36 -0600510 //
511
512 // for external save and restore
513 AccessChain getAccessChain() { return accessChain; }
514 void setAccessChain(AccessChain newChain) { accessChain = newChain; }
515
516 // clear accessChain
517 void clearAccessChain();
518
519 // set new base as an l-value base
520 void setAccessChainLValue(Id lValue)
521 {
522 assert(isPointer(lValue));
523 accessChain.base = lValue;
John Kessenich140f3df2015-06-26 16:58:36 -0600524 }
525
526 // set new base value as an r-value
527 void setAccessChainRValue(Id rValue)
528 {
529 accessChain.isRValue = true;
530 accessChain.base = rValue;
John Kessenich140f3df2015-06-26 16:58:36 -0600531 }
532
533 // push offset onto the end of the chain
John Kessenichfa668da2015-09-13 14:46:30 -0600534 void accessChainPush(Id offset)
John Kessenich140f3df2015-06-26 16:58:36 -0600535 {
536 accessChain.indexChain.push_back(offset);
John Kessenich140f3df2015-06-26 16:58:36 -0600537 }
538
539 // push new swizzle onto the end of any existing swizzle, merging into a single swizzle
John Kessenichfa668da2015-09-13 14:46:30 -0600540 void accessChainPushSwizzle(std::vector<unsigned>& swizzle, Id preSwizzleBaseType);
John Kessenich140f3df2015-06-26 16:58:36 -0600541
John Kessenich5c3eed52018-02-05 14:44:14 -0700542 // push a dynamic component selection onto the access chain, only applicable with a
543 // non-trivial swizzle or no swizzle
John Kessenichfa668da2015-09-13 14:46:30 -0600544 void accessChainPushComponent(Id component, Id preSwizzleBaseType)
545 {
John Kessenich5c3eed52018-02-05 14:44:14 -0700546 if (accessChain.swizzle.size() != 1) {
547 accessChain.component = component;
548 if (accessChain.preSwizzleBaseType == NoType)
549 accessChain.preSwizzleBaseType = preSwizzleBaseType;
550 }
John Kessenichfa668da2015-09-13 14:46:30 -0600551 }
John Kessenich140f3df2015-06-26 16:58:36 -0600552
553 // use accessChain and swizzle to store value
554 void accessChainStore(Id rvalue);
555
556 // use accessChain and swizzle to load an r-value
John Kessenich32cfd492016-02-02 12:37:46 -0700557 Id accessChainLoad(Decoration precision, Id ResultType);
John Kessenich140f3df2015-06-26 16:58:36 -0600558
559 // get the direct pointer for an l-value
560 Id accessChainGetLValue();
561
John Kessenich103bef92016-02-08 21:38:15 -0700562 // Get the inferred SPIR-V type of the result of the current access chain,
563 // based on the type of the base and the chain of dereferences.
564 Id accessChainGetInferredType();
565
qiningda397332016-03-09 19:54:03 -0500566 // Remove OpDecorate instructions whose operands are defined in unreachable
567 // blocks.
568 void eliminateDeadDecorations();
John Kessenich140f3df2015-06-26 16:58:36 -0600569 void dump(std::vector<unsigned int>&) const;
570
Dejan Mircevski9c6734c2016-01-10 12:15:13 -0500571 void createBranch(Block* block);
572 void createConditionalBranch(Id condition, Block* thenBlock, Block* elseBlock);
John Kessenicha2858d92018-01-31 08:11:18 -0700573 void createLoopMerge(Block* mergeBlock, Block* continueBlock, unsigned int control, unsigned int dependencyLength);
Dejan Mircevski9c6734c2016-01-10 12:15:13 -0500574
qining13545202016-03-21 09:51:37 -0400575 // Sets to generate opcode for specialization constants.
576 void setToSpecConstCodeGenMode() { generatingOpCodeForSpecConst = true; }
577 // Sets to generate opcode for non-specialization constants (normal mode).
578 void setToNormalCodeGenMode() { generatingOpCodeForSpecConst = false; }
579 // Check if the builder is generating code for spec constants.
580 bool isInSpecConstCodeGenMode() { return generatingOpCodeForSpecConst; }
581
Dejan Mircevski9c6734c2016-01-10 12:15:13 -0500582 protected:
John Kessenich55e7d112015-11-15 21:33:39 -0700583 Id makeIntConstant(Id typeId, unsigned value, bool specConstant);
Rex Xu8ff43de2016-04-22 16:51:45 +0800584 Id makeInt64Constant(Id typeId, unsigned long long value, bool specConstant);
John Kessenich46413d52018-02-26 19:20:05 -0700585 Id findScalarConstant(Op typeClass, Op opcode, Id typeId, unsigned value);
586 Id findScalarConstant(Op typeClass, Op opcode, Id typeId, unsigned v1, unsigned v2);
587 Id findCompositeConstant(Op typeClass, const std::vector<Id>& comps);
588 Id findStructConstant(Id typeId, const std::vector<Id>& comps);
John Kessenich140f3df2015-06-26 16:58:36 -0600589 Id collapseAccessChain();
John Kessenich5c3eed52018-02-05 14:44:14 -0700590 void remapDynamicSwizzle();
John Kessenich55e7d112015-11-15 21:33:39 -0700591 void transferAccessChainSwizzle(bool dynamic);
John Kessenich140f3df2015-06-26 16:58:36 -0600592 void simplifyAccessChainSwizzle();
John Kessenich140f3df2015-06-26 16:58:36 -0600593 void createAndSetNoPredecessorBlock(const char*);
John Kessenich55e7d112015-11-15 21:33:39 -0700594 void createSelectionMerge(Block* mergeBlock, unsigned int control);
John Kessenich121853f2017-05-31 17:11:16 -0600595 void dumpSourceInstructions(std::vector<unsigned int>&) const;
Andrew Woloszynb7946d12016-01-18 09:23:56 -0500596 void dumpInstructions(std::vector<unsigned int>&, const std::vector<std::unique_ptr<Instruction> >&) const;
John Kessenich2a271162017-07-20 20:00:36 -0600597 void dumpModuleProcesses(std::vector<unsigned int>&) const;
John Kessenich140f3df2015-06-26 16:58:36 -0600598
John Kessenich2b5ea9f2018-01-31 18:35:56 -0700599 unsigned int spvVersion; // the version of SPIR-V to emit in the header
John Kessenich140f3df2015-06-26 16:58:36 -0600600 SourceLanguage source;
601 int sourceVersion;
John Kessenich121853f2017-05-31 17:11:16 -0600602 spv::Id sourceFileStringId;
603 std::string sourceText;
John Kesseniche485c7a2017-05-31 18:50:53 -0600604 int currentLine;
605 bool emitOpLines;
Rex Xu430ef402016-10-14 17:22:23 +0800606 std::set<std::string> extensions;
Rex Xu9d93a232016-05-05 12:30:44 +0800607 std::vector<const char*> sourceExtensions;
John Kessenich2a271162017-07-20 20:00:36 -0600608 std::vector<const char*> moduleProcesses;
John Kessenich140f3df2015-06-26 16:58:36 -0600609 AddressingModel addressModel;
610 MemoryModel memoryModel;
John Kessenich92187592016-02-01 13:45:25 -0700611 std::set<spv::Capability> capabilities;
John Kessenich140f3df2015-06-26 16:58:36 -0600612 int builderNumber;
613 Module module;
614 Block* buildPoint;
615 Id uniqueId;
John Kessenich517fe7a2016-11-26 13:31:47 -0700616 Function* entryPointFunction;
qining13545202016-03-21 09:51:37 -0400617 bool generatingOpCodeForSpecConst;
John Kessenich140f3df2015-06-26 16:58:36 -0600618 AccessChain accessChain;
619
620 // special blocks of instructions for output
John Kessenich121853f2017-05-31 17:11:16 -0600621 std::vector<std::unique_ptr<Instruction> > strings;
Andrew Woloszynb7946d12016-01-18 09:23:56 -0500622 std::vector<std::unique_ptr<Instruction> > imports;
623 std::vector<std::unique_ptr<Instruction> > entryPoints;
624 std::vector<std::unique_ptr<Instruction> > executionModes;
625 std::vector<std::unique_ptr<Instruction> > names;
Andrew Woloszynb7946d12016-01-18 09:23:56 -0500626 std::vector<std::unique_ptr<Instruction> > decorations;
627 std::vector<std::unique_ptr<Instruction> > constantsTypesGlobals;
628 std::vector<std::unique_ptr<Instruction> > externals;
629 std::vector<std::unique_ptr<Function> > functions;
John Kessenich140f3df2015-06-26 16:58:36 -0600630
631 // not output, internally used for quick & dirty canonical (unique) creation
John Kessenich46413d52018-02-26 19:20:05 -0700632 std::unordered_map<unsigned int, std::vector<Instruction*>> groupedConstants; // map type opcodes to constant inst.
633 std::unordered_map<unsigned int, std::vector<Instruction*>> groupedStructConstants; // map struct-id to constant instructions
634 std::unordered_map<unsigned int, std::vector<Instruction*>> groupedTypes; // map type opcodes to type instructions
John Kessenich140f3df2015-06-26 16:58:36 -0600635
636 // stack of switches
637 std::stack<Block*> switchMerges;
638
John Kessenich140f3df2015-06-26 16:58:36 -0600639 // Our loop stack.
Dejan Mircevski7819bee2016-01-11 09:35:22 -0500640 std::stack<LoopBlocks> loops;
Lei Zhang09caf122016-05-02 18:11:54 -0400641
John Kessenich121853f2017-05-31 17:11:16 -0600642 // The stream for outputting warnings and errors.
Lei Zhang17535f72016-05-04 15:55:59 -0400643 SpvBuildLogger* logger;
John Kessenich140f3df2015-06-26 16:58:36 -0600644}; // end Builder class
645
John Kessenich140f3df2015-06-26 16:58:36 -0600646}; // end spv namespace
647
648#endif // SpvBuilder_H