blob: 10d655b00b4c0dfd94a1fef0a85de87291f402aa [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 Kessenich140f3df2015-06-26 16:58:36 -06004//
John Kessenich927608b2017-01-06 12:34:14 -07005// All rights reserved.
John Kessenich140f3df2015-06-26 16:58:36 -06006//
John Kessenich927608b2017-01-06 12:34:14 -07007// Redistribution and use in source and binary forms, with or without
8// modification, are permitted provided that the following conditions
9// are met:
John Kessenich140f3df2015-06-26 16:58:36 -060010//
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//
John Kessenich927608b2017-01-06 12:34:14 -070023// 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.
John Kessenich140f3df2015-06-26 16:58:36 -060035
36//
John Kessenich140f3df2015-06-26 16:58:36 -060037// Helper for making SPIR-V IR. Generally, this is documented in the header
38// SpvBuilder.h.
39//
40
John Kessenich66ec80e2016-08-05 14:04:23 -060041#include <cassert>
42#include <cstdlib>
John Kessenich140f3df2015-06-26 16:58:36 -060043
John Kessenich426394d2015-07-23 10:22:48 -060044#include <unordered_set>
qining1f2820a2016-04-14 18:34:27 -040045#include <algorithm>
John Kessenich426394d2015-07-23 10:22:48 -060046
John Kessenich140f3df2015-06-26 16:58:36 -060047#include "SpvBuilder.h"
48
John Kessenich66011cb2018-03-06 16:12:04 -070049#include "hex_float.h"
Rex Xuc9e3c3c2016-07-29 16:00:05 +080050
John Kessenich140f3df2015-06-26 16:58:36 -060051#ifndef _WIN32
52 #include <cstdio>
53#endif
54
55namespace spv {
56
John Kessenich2b5ea9f2018-01-31 18:35:56 -070057Builder::Builder(unsigned int spvVersion, unsigned int magicNumber, SpvBuildLogger* buildLogger) :
58 spvVersion(spvVersion),
John Kessenich140f3df2015-06-26 16:58:36 -060059 source(SourceLanguageUnknown),
60 sourceVersion(0),
John Kessenich121853f2017-05-31 17:11:16 -060061 sourceFileStringId(NoResult),
John Kesseniche485c7a2017-05-31 18:50:53 -060062 currentLine(0),
63 emitOpLines(false),
John Kessenich140f3df2015-06-26 16:58:36 -060064 addressModel(AddressingModelLogical),
65 memoryModel(MemoryModelGLSL450),
John Kessenich55e7d112015-11-15 21:33:39 -070066 builderNumber(magicNumber),
John Kessenich140f3df2015-06-26 16:58:36 -060067 buildPoint(0),
68 uniqueId(0),
John Kessenich517fe7a2016-11-26 13:31:47 -070069 entryPointFunction(0),
Lei Zhang09caf122016-05-02 18:11:54 -040070 generatingOpCodeForSpecConst(false),
Lei Zhang17535f72016-05-04 15:55:59 -040071 logger(buildLogger)
John Kessenich140f3df2015-06-26 16:58:36 -060072{
73 clearAccessChain();
74}
75
76Builder::~Builder()
77{
78}
79
80Id Builder::import(const char* name)
81{
82 Instruction* import = new Instruction(getUniqueId(), NoType, OpExtInstImport);
83 import->addStringOperand(name);
John Kessenichecba76f2017-01-06 00:34:48 -070084
Andrew Woloszynb7946d12016-01-18 09:23:56 -050085 imports.push_back(std::unique_ptr<Instruction>(import));
John Kessenich140f3df2015-06-26 16:58:36 -060086 return import->getResultId();
87}
88
John Kesseniche485c7a2017-05-31 18:50:53 -060089// Emit an OpLine if we've been asked to emit OpLines and the line number
90// has changed since the last time, and is a valid line number.
91void Builder::setLine(int lineNum)
92{
93 if (lineNum != 0 && lineNum != currentLine) {
94 currentLine = lineNum;
95 if (emitOpLines)
96 addLine(sourceFileStringId, currentLine, 0);
97 }
98}
99
100void Builder::addLine(Id fileName, int lineNum, int column)
101{
102 Instruction* line = new Instruction(OpLine);
103 line->addIdOperand(fileName);
104 line->addImmediateOperand(lineNum);
105 line->addImmediateOperand(column);
106 buildPoint->addInstruction(std::unique_ptr<Instruction>(line));
107}
108
John Kessenich140f3df2015-06-26 16:58:36 -0600109// For creating new groupedTypes (will return old type if the requested one was already made).
110Id Builder::makeVoidType()
111{
112 Instruction* type;
113 if (groupedTypes[OpTypeVoid].size() == 0) {
114 type = new Instruction(getUniqueId(), NoType, OpTypeVoid);
115 groupedTypes[OpTypeVoid].push_back(type);
Andrew Woloszynb7946d12016-01-18 09:23:56 -0500116 constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(type));
John Kessenich140f3df2015-06-26 16:58:36 -0600117 module.mapInstruction(type);
118 } else
119 type = groupedTypes[OpTypeVoid].back();
120
121 return type->getResultId();
122}
123
124Id Builder::makeBoolType()
125{
126 Instruction* type;
127 if (groupedTypes[OpTypeBool].size() == 0) {
128 type = new Instruction(getUniqueId(), NoType, OpTypeBool);
129 groupedTypes[OpTypeBool].push_back(type);
Andrew Woloszynb7946d12016-01-18 09:23:56 -0500130 constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(type));
John Kessenich140f3df2015-06-26 16:58:36 -0600131 module.mapInstruction(type);
132 } else
133 type = groupedTypes[OpTypeBool].back();
134
135 return type->getResultId();
136}
137
John Kessenich55e7d112015-11-15 21:33:39 -0700138Id Builder::makeSamplerType()
139{
140 Instruction* type;
141 if (groupedTypes[OpTypeSampler].size() == 0) {
142 type = new Instruction(getUniqueId(), NoType, OpTypeSampler);
143 groupedTypes[OpTypeSampler].push_back(type);
Andrew Woloszynb7946d12016-01-18 09:23:56 -0500144 constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(type));
John Kessenich55e7d112015-11-15 21:33:39 -0700145 module.mapInstruction(type);
146 } else
147 type = groupedTypes[OpTypeSampler].back();
148
149 return type->getResultId();
150}
151
John Kessenich140f3df2015-06-26 16:58:36 -0600152Id Builder::makePointer(StorageClass storageClass, Id pointee)
153{
154 // try to find it
155 Instruction* type;
156 for (int t = 0; t < (int)groupedTypes[OpTypePointer].size(); ++t) {
157 type = groupedTypes[OpTypePointer][t];
158 if (type->getImmediateOperand(0) == (unsigned)storageClass &&
159 type->getIdOperand(1) == pointee)
160 return type->getResultId();
161 }
162
163 // not found, make it
164 type = new Instruction(getUniqueId(), NoType, OpTypePointer);
165 type->addImmediateOperand(storageClass);
166 type->addIdOperand(pointee);
167 groupedTypes[OpTypePointer].push_back(type);
Andrew Woloszynb7946d12016-01-18 09:23:56 -0500168 constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(type));
John Kessenich140f3df2015-06-26 16:58:36 -0600169 module.mapInstruction(type);
170
171 return type->getResultId();
172}
173
174Id Builder::makeIntegerType(int width, bool hasSign)
175{
176 // try to find it
177 Instruction* type;
178 for (int t = 0; t < (int)groupedTypes[OpTypeInt].size(); ++t) {
179 type = groupedTypes[OpTypeInt][t];
180 if (type->getImmediateOperand(0) == (unsigned)width &&
181 type->getImmediateOperand(1) == (hasSign ? 1u : 0u))
182 return type->getResultId();
183 }
184
185 // not found, make it
186 type = new Instruction(getUniqueId(), NoType, OpTypeInt);
187 type->addImmediateOperand(width);
188 type->addImmediateOperand(hasSign ? 1 : 0);
189 groupedTypes[OpTypeInt].push_back(type);
Andrew Woloszynb7946d12016-01-18 09:23:56 -0500190 constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(type));
John Kessenich140f3df2015-06-26 16:58:36 -0600191 module.mapInstruction(type);
192
John Kessenich3c522072016-02-14 17:11:15 -0700193 // deal with capabilities
194 switch (width) {
John Kessenich66011cb2018-03-06 16:12:04 -0700195 case 8:
196 addCapability(CapabilityInt8);
197 break;
John Kessenich3c522072016-02-14 17:11:15 -0700198 case 16:
199 addCapability(CapabilityInt16);
200 break;
201 case 64:
202 addCapability(CapabilityInt64);
203 break;
204 default:
205 break;
206 }
207
John Kessenich140f3df2015-06-26 16:58:36 -0600208 return type->getResultId();
209}
210
211Id Builder::makeFloatType(int width)
212{
213 // try to find it
214 Instruction* type;
215 for (int t = 0; t < (int)groupedTypes[OpTypeFloat].size(); ++t) {
216 type = groupedTypes[OpTypeFloat][t];
217 if (type->getImmediateOperand(0) == (unsigned)width)
218 return type->getResultId();
219 }
220
221 // not found, make it
222 type = new Instruction(getUniqueId(), NoType, OpTypeFloat);
223 type->addImmediateOperand(width);
224 groupedTypes[OpTypeFloat].push_back(type);
Andrew Woloszynb7946d12016-01-18 09:23:56 -0500225 constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(type));
John Kessenich140f3df2015-06-26 16:58:36 -0600226 module.mapInstruction(type);
227
John Kessenich3c522072016-02-14 17:11:15 -0700228 // deal with capabilities
229 switch (width) {
230 case 16:
231 addCapability(CapabilityFloat16);
232 break;
233 case 64:
234 addCapability(CapabilityFloat64);
235 break;
236 default:
237 break;
238 }
239
John Kessenich140f3df2015-06-26 16:58:36 -0600240 return type->getResultId();
241}
242
John Kessenich55e7d112015-11-15 21:33:39 -0700243// Make a struct without checking for duplication.
244// See makeStructResultType() for non-decorated structs
245// needed as the result of some instructions, which does
246// check for duplicates.
John Kessenich32cfd492016-02-02 12:37:46 -0700247Id Builder::makeStructType(const std::vector<Id>& members, const char* name)
John Kessenich140f3df2015-06-26 16:58:36 -0600248{
John Kessenich55e7d112015-11-15 21:33:39 -0700249 // Don't look for previous one, because in the general case,
250 // structs can be duplicated except for decorations.
251
John Kessenich140f3df2015-06-26 16:58:36 -0600252 // not found, make it
253 Instruction* type = new Instruction(getUniqueId(), NoType, OpTypeStruct);
254 for (int op = 0; op < (int)members.size(); ++op)
255 type->addIdOperand(members[op]);
256 groupedTypes[OpTypeStruct].push_back(type);
Andrew Woloszynb7946d12016-01-18 09:23:56 -0500257 constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(type));
John Kessenich140f3df2015-06-26 16:58:36 -0600258 module.mapInstruction(type);
259 addName(type->getResultId(), name);
260
261 return type->getResultId();
262}
263
John Kessenich55e7d112015-11-15 21:33:39 -0700264// Make a struct for the simple results of several instructions,
265// checking for duplication.
266Id Builder::makeStructResultType(Id type0, Id type1)
267{
268 // try to find it
269 Instruction* type;
270 for (int t = 0; t < (int)groupedTypes[OpTypeStruct].size(); ++t) {
271 type = groupedTypes[OpTypeStruct][t];
272 if (type->getNumOperands() != 2)
273 continue;
John Kessenichecba76f2017-01-06 00:34:48 -0700274 if (type->getIdOperand(0) != type0 ||
John Kessenich55e7d112015-11-15 21:33:39 -0700275 type->getIdOperand(1) != type1)
276 continue;
277 return type->getResultId();
278 }
279
280 // not found, make it
281 std::vector<spv::Id> members;
282 members.push_back(type0);
283 members.push_back(type1);
284
285 return makeStructType(members, "ResType");
286}
287
John Kessenich140f3df2015-06-26 16:58:36 -0600288Id Builder::makeVectorType(Id component, int size)
289{
290 // try to find it
291 Instruction* type;
292 for (int t = 0; t < (int)groupedTypes[OpTypeVector].size(); ++t) {
293 type = groupedTypes[OpTypeVector][t];
294 if (type->getIdOperand(0) == component &&
295 type->getImmediateOperand(1) == (unsigned)size)
296 return type->getResultId();
297 }
298
299 // not found, make it
300 type = new Instruction(getUniqueId(), NoType, OpTypeVector);
301 type->addIdOperand(component);
302 type->addImmediateOperand(size);
303 groupedTypes[OpTypeVector].push_back(type);
Andrew Woloszynb7946d12016-01-18 09:23:56 -0500304 constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(type));
John Kessenich140f3df2015-06-26 16:58:36 -0600305 module.mapInstruction(type);
306
307 return type->getResultId();
308}
309
310Id Builder::makeMatrixType(Id component, int cols, int rows)
311{
312 assert(cols <= maxMatrixSize && rows <= maxMatrixSize);
313
314 Id column = makeVectorType(component, rows);
315
316 // try to find it
317 Instruction* type;
318 for (int t = 0; t < (int)groupedTypes[OpTypeMatrix].size(); ++t) {
319 type = groupedTypes[OpTypeMatrix][t];
320 if (type->getIdOperand(0) == column &&
321 type->getImmediateOperand(1) == (unsigned)cols)
322 return type->getResultId();
323 }
324
325 // not found, make it
326 type = new Instruction(getUniqueId(), NoType, OpTypeMatrix);
327 type->addIdOperand(column);
328 type->addImmediateOperand(cols);
329 groupedTypes[OpTypeMatrix].push_back(type);
Andrew Woloszynb7946d12016-01-18 09:23:56 -0500330 constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(type));
John Kessenich140f3df2015-06-26 16:58:36 -0600331 module.mapInstruction(type);
332
333 return type->getResultId();
334}
335
John Kessenichc9e0a422015-12-29 21:27:24 -0700336// TODO: performance: track arrays per stride
337// If a stride is supplied (non-zero) make an array.
338// If no stride (0), reuse previous array types.
John Kessenich6c292d32016-02-15 20:58:50 -0700339// 'size' is an Id of a constant or specialization constant of the array size
340Id Builder::makeArrayType(Id element, Id sizeId, int stride)
John Kessenich140f3df2015-06-26 16:58:36 -0600341{
John Kessenich140f3df2015-06-26 16:58:36 -0600342 Instruction* type;
John Kessenichc9e0a422015-12-29 21:27:24 -0700343 if (stride == 0) {
344 // try to find existing type
345 for (int t = 0; t < (int)groupedTypes[OpTypeArray].size(); ++t) {
346 type = groupedTypes[OpTypeArray][t];
347 if (type->getIdOperand(0) == element &&
348 type->getIdOperand(1) == sizeId)
349 return type->getResultId();
350 }
John Kessenich140f3df2015-06-26 16:58:36 -0600351 }
352
353 // not found, make it
354 type = new Instruction(getUniqueId(), NoType, OpTypeArray);
355 type->addIdOperand(element);
356 type->addIdOperand(sizeId);
357 groupedTypes[OpTypeArray].push_back(type);
Andrew Woloszynb7946d12016-01-18 09:23:56 -0500358 constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(type));
John Kessenich140f3df2015-06-26 16:58:36 -0600359 module.mapInstruction(type);
360
361 return type->getResultId();
362}
363
John Kessenichc9a80832015-09-12 12:17:44 -0600364Id Builder::makeRuntimeArray(Id element)
365{
366 Instruction* type = new Instruction(getUniqueId(), NoType, OpTypeRuntimeArray);
367 type->addIdOperand(element);
Andrew Woloszynb7946d12016-01-18 09:23:56 -0500368 constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(type));
John Kessenichc9a80832015-09-12 12:17:44 -0600369 module.mapInstruction(type);
370
371 return type->getResultId();
372}
373
John Kessenich32cfd492016-02-02 12:37:46 -0700374Id Builder::makeFunctionType(Id returnType, const std::vector<Id>& paramTypes)
John Kessenich140f3df2015-06-26 16:58:36 -0600375{
376 // try to find it
377 Instruction* type;
378 for (int t = 0; t < (int)groupedTypes[OpTypeFunction].size(); ++t) {
379 type = groupedTypes[OpTypeFunction][t];
380 if (type->getIdOperand(0) != returnType || (int)paramTypes.size() != type->getNumOperands() - 1)
381 continue;
382 bool mismatch = false;
383 for (int p = 0; p < (int)paramTypes.size(); ++p) {
384 if (paramTypes[p] != type->getIdOperand(p + 1)) {
385 mismatch = true;
386 break;
387 }
388 }
389 if (! mismatch)
John Kessenichc9a80832015-09-12 12:17:44 -0600390 return type->getResultId();
John Kessenich140f3df2015-06-26 16:58:36 -0600391 }
392
393 // not found, make it
394 type = new Instruction(getUniqueId(), NoType, OpTypeFunction);
395 type->addIdOperand(returnType);
396 for (int p = 0; p < (int)paramTypes.size(); ++p)
397 type->addIdOperand(paramTypes[p]);
398 groupedTypes[OpTypeFunction].push_back(type);
Andrew Woloszynb7946d12016-01-18 09:23:56 -0500399 constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(type));
John Kessenich140f3df2015-06-26 16:58:36 -0600400 module.mapInstruction(type);
401
402 return type->getResultId();
403}
404
John Kessenich5e4b1242015-08-06 22:53:06 -0600405Id Builder::makeImageType(Id sampledType, Dim dim, bool depth, bool arrayed, bool ms, unsigned sampled, ImageFormat format)
John Kessenich140f3df2015-06-26 16:58:36 -0600406{
John Kessenich260f5062017-08-14 22:10:00 -0600407 assert(sampled == 1 || sampled == 2);
408
John Kessenich140f3df2015-06-26 16:58:36 -0600409 // try to find it
410 Instruction* type;
John Kessenich5e4b1242015-08-06 22:53:06 -0600411 for (int t = 0; t < (int)groupedTypes[OpTypeImage].size(); ++t) {
412 type = groupedTypes[OpTypeImage][t];
John Kessenich140f3df2015-06-26 16:58:36 -0600413 if (type->getIdOperand(0) == sampledType &&
414 type->getImmediateOperand(1) == (unsigned int)dim &&
John Kessenich5e4b1242015-08-06 22:53:06 -0600415 type->getImmediateOperand(2) == ( depth ? 1u : 0u) &&
John Kessenich140f3df2015-06-26 16:58:36 -0600416 type->getImmediateOperand(3) == (arrayed ? 1u : 0u) &&
John Kessenich5e4b1242015-08-06 22:53:06 -0600417 type->getImmediateOperand(4) == ( ms ? 1u : 0u) &&
418 type->getImmediateOperand(5) == sampled &&
419 type->getImmediateOperand(6) == (unsigned int)format)
John Kessenich140f3df2015-06-26 16:58:36 -0600420 return type->getResultId();
421 }
422
423 // not found, make it
John Kessenich5e4b1242015-08-06 22:53:06 -0600424 type = new Instruction(getUniqueId(), NoType, OpTypeImage);
John Kessenich140f3df2015-06-26 16:58:36 -0600425 type->addIdOperand(sampledType);
426 type->addImmediateOperand( dim);
John Kessenich5e4b1242015-08-06 22:53:06 -0600427 type->addImmediateOperand( depth ? 1 : 0);
John Kessenich140f3df2015-06-26 16:58:36 -0600428 type->addImmediateOperand(arrayed ? 1 : 0);
John Kessenich140f3df2015-06-26 16:58:36 -0600429 type->addImmediateOperand( ms ? 1 : 0);
John Kessenich5e4b1242015-08-06 22:53:06 -0600430 type->addImmediateOperand(sampled);
431 type->addImmediateOperand((unsigned int)format);
John Kessenich140f3df2015-06-26 16:58:36 -0600432
John Kessenich5e4b1242015-08-06 22:53:06 -0600433 groupedTypes[OpTypeImage].push_back(type);
Andrew Woloszynb7946d12016-01-18 09:23:56 -0500434 constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(type));
John Kessenich5e4b1242015-08-06 22:53:06 -0600435 module.mapInstruction(type);
436
John Kessenichb0364dc2016-02-14 17:37:30 -0700437 // deal with capabilities
438 switch (dim) {
439 case DimBuffer:
John Kessenich260f5062017-08-14 22:10:00 -0600440 if (sampled == 1)
John Kessenichb0364dc2016-02-14 17:37:30 -0700441 addCapability(CapabilitySampledBuffer);
442 else
443 addCapability(CapabilityImageBuffer);
444 break;
445 case Dim1D:
John Kessenich260f5062017-08-14 22:10:00 -0600446 if (sampled == 1)
John Kessenichb0364dc2016-02-14 17:37:30 -0700447 addCapability(CapabilitySampled1D);
448 else
449 addCapability(CapabilityImage1D);
450 break;
451 case DimCube:
452 if (arrayed) {
John Kessenich260f5062017-08-14 22:10:00 -0600453 if (sampled == 1)
John Kessenichb0364dc2016-02-14 17:37:30 -0700454 addCapability(CapabilitySampledCubeArray);
455 else
456 addCapability(CapabilityImageCubeArray);
457 }
458 break;
459 case DimRect:
John Kessenich260f5062017-08-14 22:10:00 -0600460 if (sampled == 1)
John Kessenichb0364dc2016-02-14 17:37:30 -0700461 addCapability(CapabilitySampledRect);
462 else
463 addCapability(CapabilityImageRect);
464 break;
465 case DimSubpassData:
466 addCapability(CapabilityInputAttachment);
467 break;
468 default:
469 break;
470 }
471
472 if (ms) {
John Kessenich260f5062017-08-14 22:10:00 -0600473 if (sampled == 2) {
John Kessenich7a9db712017-10-20 10:56:50 -0600474 // Images used with subpass data are not storage
475 // images, so don't require the capability for them.
476 if (dim != Dim::DimSubpassData)
477 addCapability(CapabilityStorageImageMultisample);
John Kessenich260f5062017-08-14 22:10:00 -0600478 if (arrayed)
479 addCapability(CapabilityImageMSArray);
480 }
John Kessenichb0364dc2016-02-14 17:37:30 -0700481 }
482
John Kessenich5e4b1242015-08-06 22:53:06 -0600483 return type->getResultId();
484}
485
486Id Builder::makeSampledImageType(Id imageType)
487{
488 // try to find it
489 Instruction* type;
490 for (int t = 0; t < (int)groupedTypes[OpTypeSampledImage].size(); ++t) {
491 type = groupedTypes[OpTypeSampledImage][t];
492 if (type->getIdOperand(0) == imageType)
493 return type->getResultId();
494 }
495
496 // not found, make it
497 type = new Instruction(getUniqueId(), NoType, OpTypeSampledImage);
498 type->addIdOperand(imageType);
499
500 groupedTypes[OpTypeSampledImage].push_back(type);
Andrew Woloszynb7946d12016-01-18 09:23:56 -0500501 constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(type));
John Kessenich140f3df2015-06-26 16:58:36 -0600502 module.mapInstruction(type);
503
504 return type->getResultId();
505}
506
507Id Builder::getDerefTypeId(Id resultId) const
508{
509 Id typeId = getTypeId(resultId);
510 assert(isPointerType(typeId));
511
512 return module.getInstruction(typeId)->getImmediateOperand(1);
513}
514
515Op Builder::getMostBasicTypeClass(Id typeId) const
516{
517 Instruction* instr = module.getInstruction(typeId);
518
519 Op typeClass = instr->getOpCode();
520 switch (typeClass)
521 {
522 case OpTypeVoid:
523 case OpTypeBool:
524 case OpTypeInt:
525 case OpTypeFloat:
526 case OpTypeStruct:
527 return typeClass;
528 case OpTypeVector:
529 case OpTypeMatrix:
530 case OpTypeArray:
531 case OpTypeRuntimeArray:
532 return getMostBasicTypeClass(instr->getIdOperand(0));
533 case OpTypePointer:
534 return getMostBasicTypeClass(instr->getIdOperand(1));
535 default:
John Kessenich55e7d112015-11-15 21:33:39 -0700536 assert(0);
John Kessenich140f3df2015-06-26 16:58:36 -0600537 return OpTypeFloat;
538 }
539}
540
John Kessenich22118352015-12-21 20:54:09 -0700541int Builder::getNumTypeConstituents(Id typeId) const
John Kessenich140f3df2015-06-26 16:58:36 -0600542{
543 Instruction* instr = module.getInstruction(typeId);
544
545 switch (instr->getOpCode())
546 {
547 case OpTypeBool:
548 case OpTypeInt:
549 case OpTypeFloat:
550 return 1;
551 case OpTypeVector:
552 case OpTypeMatrix:
553 return instr->getImmediateOperand(1);
John Kessenich6c292d32016-02-15 20:58:50 -0700554 case OpTypeArray:
555 {
556 Id lengthId = instr->getImmediateOperand(1);
557 return module.getInstruction(lengthId)->getImmediateOperand(0);
558 }
John Kessenich22118352015-12-21 20:54:09 -0700559 case OpTypeStruct:
560 return instr->getNumOperands();
John Kessenich140f3df2015-06-26 16:58:36 -0600561 default:
John Kessenich55e7d112015-11-15 21:33:39 -0700562 assert(0);
John Kessenich140f3df2015-06-26 16:58:36 -0600563 return 1;
564 }
565}
566
567// Return the lowest-level type of scalar that an homogeneous composite is made out of.
568// Typically, this is just to find out if something is made out of ints or floats.
569// However, it includes returning a structure, if say, it is an array of structure.
570Id Builder::getScalarTypeId(Id typeId) const
571{
572 Instruction* instr = module.getInstruction(typeId);
573
574 Op typeClass = instr->getOpCode();
575 switch (typeClass)
576 {
577 case OpTypeVoid:
578 case OpTypeBool:
579 case OpTypeInt:
580 case OpTypeFloat:
581 case OpTypeStruct:
582 return instr->getResultId();
583 case OpTypeVector:
584 case OpTypeMatrix:
585 case OpTypeArray:
586 case OpTypeRuntimeArray:
587 case OpTypePointer:
588 return getScalarTypeId(getContainedTypeId(typeId));
589 default:
John Kessenich55e7d112015-11-15 21:33:39 -0700590 assert(0);
John Kessenich140f3df2015-06-26 16:58:36 -0600591 return NoResult;
592 }
593}
594
595// Return the type of 'member' of a composite.
596Id Builder::getContainedTypeId(Id typeId, int member) const
597{
598 Instruction* instr = module.getInstruction(typeId);
599
600 Op typeClass = instr->getOpCode();
601 switch (typeClass)
602 {
603 case OpTypeVector:
604 case OpTypeMatrix:
605 case OpTypeArray:
606 case OpTypeRuntimeArray:
607 return instr->getIdOperand(0);
608 case OpTypePointer:
609 return instr->getIdOperand(1);
610 case OpTypeStruct:
611 return instr->getIdOperand(member);
612 default:
John Kessenich55e7d112015-11-15 21:33:39 -0700613 assert(0);
John Kessenich140f3df2015-06-26 16:58:36 -0600614 return NoResult;
615 }
616}
617
618// Return the immediately contained type of a given composite type.
619Id Builder::getContainedTypeId(Id typeId) const
620{
621 return getContainedTypeId(typeId, 0);
622}
623
624// See if a scalar constant of this type has already been created, so it
625// can be reused rather than duplicated. (Required by the specification).
John Kessenich46413d52018-02-26 19:20:05 -0700626Id Builder::findScalarConstant(Op typeClass, Op opcode, Id typeId, unsigned value)
John Kessenich140f3df2015-06-26 16:58:36 -0600627{
628 Instruction* constant;
629 for (int i = 0; i < (int)groupedConstants[typeClass].size(); ++i) {
630 constant = groupedConstants[typeClass][i];
John Kessenich55e7d112015-11-15 21:33:39 -0700631 if (constant->getOpCode() == opcode &&
John Kessenich140f3df2015-06-26 16:58:36 -0600632 constant->getTypeId() == typeId &&
633 constant->getImmediateOperand(0) == value)
634 return constant->getResultId();
635 }
636
637 return 0;
638}
639
Rex Xu8ff43de2016-04-22 16:51:45 +0800640// Version of findScalarConstant (see above) for scalars that take two operands (e.g. a 'double' or 'int64').
John Kessenich46413d52018-02-26 19:20:05 -0700641Id Builder::findScalarConstant(Op typeClass, Op opcode, Id typeId, unsigned v1, unsigned v2)
John Kessenich140f3df2015-06-26 16:58:36 -0600642{
643 Instruction* constant;
644 for (int i = 0; i < (int)groupedConstants[typeClass].size(); ++i) {
645 constant = groupedConstants[typeClass][i];
John Kessenich55e7d112015-11-15 21:33:39 -0700646 if (constant->getOpCode() == opcode &&
John Kessenich140f3df2015-06-26 16:58:36 -0600647 constant->getTypeId() == typeId &&
648 constant->getImmediateOperand(0) == v1 &&
649 constant->getImmediateOperand(1) == v2)
650 return constant->getResultId();
651 }
652
653 return 0;
654}
655
John Kessenichf685df82015-10-13 10:55:08 -0600656// Return true if consuming 'opcode' means consuming a constant.
657// "constant" here means after final transform to executable code,
658// the value consumed will be a constant, so includes specialization.
John Kessenich71631272015-10-13 10:39:19 -0600659bool Builder::isConstantOpCode(Op opcode) const
660{
661 switch (opcode) {
John Kessenichecba76f2017-01-06 00:34:48 -0700662 case OpUndef:
John Kessenich71631272015-10-13 10:39:19 -0600663 case OpConstantTrue:
664 case OpConstantFalse:
665 case OpConstant:
666 case OpConstantComposite:
667 case OpConstantSampler:
668 case OpConstantNull:
669 case OpSpecConstantTrue:
670 case OpSpecConstantFalse:
671 case OpSpecConstant:
672 case OpSpecConstantComposite:
673 case OpSpecConstantOp:
674 return true;
675 default:
676 return false;
677 }
678}
679
qining27e04a02016-04-14 16:40:20 -0400680// Return true if consuming 'opcode' means consuming a specialization constant.
681bool Builder::isSpecConstantOpCode(Op opcode) const
682{
683 switch (opcode) {
684 case OpSpecConstantTrue:
685 case OpSpecConstantFalse:
686 case OpSpecConstant:
687 case OpSpecConstantComposite:
688 case OpSpecConstantOp:
689 return true;
690 default:
691 return false;
692 }
693}
694
John Kessenich55e7d112015-11-15 21:33:39 -0700695Id Builder::makeBoolConstant(bool b, bool specConstant)
John Kessenich140f3df2015-06-26 16:58:36 -0600696{
697 Id typeId = makeBoolType();
698 Instruction* constant;
John Kessenich55e7d112015-11-15 21:33:39 -0700699 Op opcode = specConstant ? (b ? OpSpecConstantTrue : OpSpecConstantFalse) : (b ? OpConstantTrue : OpConstantFalse);
John Kessenich140f3df2015-06-26 16:58:36 -0600700
John Kessenich6c292d32016-02-15 20:58:50 -0700701 // See if we already made it. Applies only to regular constants, because specialization constants
702 // must remain distinct for the purpose of applying a SpecId decoration.
703 if (! specConstant) {
704 Id existing = 0;
705 for (int i = 0; i < (int)groupedConstants[OpTypeBool].size(); ++i) {
706 constant = groupedConstants[OpTypeBool][i];
707 if (constant->getTypeId() == typeId && constant->getOpCode() == opcode)
708 existing = constant->getResultId();
709 }
John Kessenich140f3df2015-06-26 16:58:36 -0600710
John Kessenich6c292d32016-02-15 20:58:50 -0700711 if (existing)
712 return existing;
713 }
John Kessenich140f3df2015-06-26 16:58:36 -0600714
715 // Make it
John Kessenich55e7d112015-11-15 21:33:39 -0700716 Instruction* c = new Instruction(getUniqueId(), typeId, opcode);
Andrew Woloszynb7946d12016-01-18 09:23:56 -0500717 constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(c));
John Kessenich140f3df2015-06-26 16:58:36 -0600718 groupedConstants[OpTypeBool].push_back(c);
719 module.mapInstruction(c);
720
721 return c->getResultId();
722}
723
John Kessenich55e7d112015-11-15 21:33:39 -0700724Id Builder::makeIntConstant(Id typeId, unsigned value, bool specConstant)
John Kessenich140f3df2015-06-26 16:58:36 -0600725{
John Kessenich55e7d112015-11-15 21:33:39 -0700726 Op opcode = specConstant ? OpSpecConstant : OpConstant;
John Kessenich6c292d32016-02-15 20:58:50 -0700727
728 // See if we already made it. Applies only to regular constants, because specialization constants
729 // must remain distinct for the purpose of applying a SpecId decoration.
730 if (! specConstant) {
731 Id existing = findScalarConstant(OpTypeInt, opcode, typeId, value);
732 if (existing)
733 return existing;
734 }
John Kessenich140f3df2015-06-26 16:58:36 -0600735
John Kessenich55e7d112015-11-15 21:33:39 -0700736 Instruction* c = new Instruction(getUniqueId(), typeId, opcode);
John Kessenich140f3df2015-06-26 16:58:36 -0600737 c->addImmediateOperand(value);
Andrew Woloszynb7946d12016-01-18 09:23:56 -0500738 constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(c));
John Kessenich140f3df2015-06-26 16:58:36 -0600739 groupedConstants[OpTypeInt].push_back(c);
740 module.mapInstruction(c);
741
742 return c->getResultId();
743}
744
Rex Xu8ff43de2016-04-22 16:51:45 +0800745Id Builder::makeInt64Constant(Id typeId, unsigned long long value, bool specConstant)
746{
747 Op opcode = specConstant ? OpSpecConstant : OpConstant;
748
749 unsigned op1 = value & 0xFFFFFFFF;
750 unsigned op2 = value >> 32;
751
752 // See if we already made it. Applies only to regular constants, because specialization constants
753 // must remain distinct for the purpose of applying a SpecId decoration.
754 if (! specConstant) {
755 Id existing = findScalarConstant(OpTypeInt, opcode, typeId, op1, op2);
756 if (existing)
757 return existing;
758 }
759
760 Instruction* c = new Instruction(getUniqueId(), typeId, opcode);
761 c->addImmediateOperand(op1);
762 c->addImmediateOperand(op2);
763 constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(c));
764 groupedConstants[OpTypeInt].push_back(c);
765 module.mapInstruction(c);
766
767 return c->getResultId();
768}
769
John Kessenich55e7d112015-11-15 21:33:39 -0700770Id Builder::makeFloatConstant(float f, bool specConstant)
John Kessenich140f3df2015-06-26 16:58:36 -0600771{
John Kessenich55e7d112015-11-15 21:33:39 -0700772 Op opcode = specConstant ? OpSpecConstant : OpConstant;
John Kessenich140f3df2015-06-26 16:58:36 -0600773 Id typeId = makeFloatType(32);
Mark Adams18b637f2016-02-23 12:17:11 -0500774 union { float fl; unsigned int ui; } u;
775 u.fl = f;
776 unsigned value = u.ui;
John Kessenich6c292d32016-02-15 20:58:50 -0700777
778 // See if we already made it. Applies only to regular constants, because specialization constants
779 // must remain distinct for the purpose of applying a SpecId decoration.
780 if (! specConstant) {
781 Id existing = findScalarConstant(OpTypeFloat, opcode, typeId, value);
782 if (existing)
783 return existing;
784 }
John Kessenich140f3df2015-06-26 16:58:36 -0600785
John Kessenich55e7d112015-11-15 21:33:39 -0700786 Instruction* c = new Instruction(getUniqueId(), typeId, opcode);
John Kessenich140f3df2015-06-26 16:58:36 -0600787 c->addImmediateOperand(value);
Andrew Woloszynb7946d12016-01-18 09:23:56 -0500788 constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(c));
John Kessenich140f3df2015-06-26 16:58:36 -0600789 groupedConstants[OpTypeFloat].push_back(c);
790 module.mapInstruction(c);
791
792 return c->getResultId();
793}
794
John Kessenich55e7d112015-11-15 21:33:39 -0700795Id Builder::makeDoubleConstant(double d, bool specConstant)
John Kessenich140f3df2015-06-26 16:58:36 -0600796{
John Kessenich55e7d112015-11-15 21:33:39 -0700797 Op opcode = specConstant ? OpSpecConstant : OpConstant;
John Kessenich140f3df2015-06-26 16:58:36 -0600798 Id typeId = makeFloatType(64);
Mark Adams18b637f2016-02-23 12:17:11 -0500799 union { double db; unsigned long long ull; } u;
800 u.db = d;
801 unsigned long long value = u.ull;
John Kessenich140f3df2015-06-26 16:58:36 -0600802 unsigned op1 = value & 0xFFFFFFFF;
803 unsigned op2 = value >> 32;
John Kessenich6c292d32016-02-15 20:58:50 -0700804
805 // See if we already made it. Applies only to regular constants, because specialization constants
806 // must remain distinct for the purpose of applying a SpecId decoration.
807 if (! specConstant) {
808 Id existing = findScalarConstant(OpTypeFloat, opcode, typeId, op1, op2);
809 if (existing)
810 return existing;
811 }
John Kessenich140f3df2015-06-26 16:58:36 -0600812
John Kessenich55e7d112015-11-15 21:33:39 -0700813 Instruction* c = new Instruction(getUniqueId(), typeId, opcode);
John Kessenich140f3df2015-06-26 16:58:36 -0600814 c->addImmediateOperand(op1);
815 c->addImmediateOperand(op2);
Andrew Woloszynb7946d12016-01-18 09:23:56 -0500816 constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(c));
John Kessenich140f3df2015-06-26 16:58:36 -0600817 groupedConstants[OpTypeFloat].push_back(c);
818 module.mapInstruction(c);
819
820 return c->getResultId();
821}
822
Rex Xuc9e3c3c2016-07-29 16:00:05 +0800823Id Builder::makeFloat16Constant(float f16, bool specConstant)
824{
825 Op opcode = specConstant ? OpSpecConstant : OpConstant;
826 Id typeId = makeFloatType(16);
827
828 spvutils::HexFloat<spvutils::FloatProxy<float>> fVal(f16);
829 spvutils::HexFloat<spvutils::FloatProxy<spvutils::Float16>> f16Val(0);
baldurk033d3ef2016-10-13 19:28:20 +0200830 fVal.castTo(f16Val, spvutils::kRoundToZero);
Rex Xuc9e3c3c2016-07-29 16:00:05 +0800831
832 unsigned value = f16Val.value().getAsFloat().get_value();
833
834 // See if we already made it. Applies only to regular constants, because specialization constants
835 // must remain distinct for the purpose of applying a SpecId decoration.
836 if (!specConstant) {
837 Id existing = findScalarConstant(OpTypeFloat, opcode, typeId, value);
838 if (existing)
839 return existing;
840 }
841
842 Instruction* c = new Instruction(getUniqueId(), typeId, opcode);
843 c->addImmediateOperand(value);
844 constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(c));
845 groupedConstants[OpTypeFloat].push_back(c);
846 module.mapInstruction(c);
847
848 return c->getResultId();
849}
Rex Xuc9e3c3c2016-07-29 16:00:05 +0800850
Neil Robertseddb1312018-03-13 10:57:59 +0100851Id Builder::makeFpConstant(Id type, double d, bool specConstant)
852{
853 assert(isFloatType(type));
854
855 switch (getScalarTypeWidth(type)) {
856 case 16:
John Kessenichead86222018-03-28 18:01:20 -0600857 return makeFloat16Constant((float)d, specConstant);
Neil Robertseddb1312018-03-13 10:57:59 +0100858 case 32:
John Kessenichead86222018-03-28 18:01:20 -0600859 return makeFloatConstant((float)d, specConstant);
Neil Robertseddb1312018-03-13 10:57:59 +0100860 case 64:
861 return makeDoubleConstant(d, specConstant);
John Kessenich97e35422018-03-22 23:44:11 -0600862 default:
863 break;
Neil Robertseddb1312018-03-13 10:57:59 +0100864 }
865
866 assert(false);
John Kessenich97e35422018-03-22 23:44:11 -0600867 return NoResult;
Neil Robertseddb1312018-03-13 10:57:59 +0100868}
869
John Kessenich46413d52018-02-26 19:20:05 -0700870Id Builder::findCompositeConstant(Op typeClass, const std::vector<Id>& comps)
John Kessenich140f3df2015-06-26 16:58:36 -0600871{
872 Instruction* constant = 0;
873 bool found = false;
874 for (int i = 0; i < (int)groupedConstants[typeClass].size(); ++i) {
875 constant = groupedConstants[typeClass][i];
876
877 // same shape?
878 if (constant->getNumOperands() != (int)comps.size())
879 continue;
880
881 // same contents?
882 bool mismatch = false;
883 for (int op = 0; op < constant->getNumOperands(); ++op) {
884 if (constant->getIdOperand(op) != comps[op]) {
885 mismatch = true;
886 break;
887 }
888 }
889 if (! mismatch) {
890 found = true;
891 break;
892 }
893 }
894
895 return found ? constant->getResultId() : NoResult;
896}
897
John Kessenich46413d52018-02-26 19:20:05 -0700898Id Builder::findStructConstant(Id typeId, const std::vector<Id>& comps)
899{
900 Instruction* constant = 0;
901 bool found = false;
902 for (int i = 0; i < (int)groupedStructConstants[typeId].size(); ++i) {
903 constant = groupedStructConstants[typeId][i];
904
905 // same contents?
906 bool mismatch = false;
907 for (int op = 0; op < constant->getNumOperands(); ++op) {
908 if (constant->getIdOperand(op) != comps[op]) {
909 mismatch = true;
910 break;
911 }
912 }
913 if (! mismatch) {
914 found = true;
915 break;
916 }
917 }
918
919 return found ? constant->getResultId() : NoResult;
920}
921
John Kessenich140f3df2015-06-26 16:58:36 -0600922// Comments in header
Vlad Ivanov689490f2017-01-26 20:46:02 +0300923Id Builder::makeCompositeConstant(Id typeId, const std::vector<Id>& members, bool specConstant)
John Kessenich140f3df2015-06-26 16:58:36 -0600924{
John Kessenich6c292d32016-02-15 20:58:50 -0700925 Op opcode = specConstant ? OpSpecConstantComposite : OpConstantComposite;
John Kessenich140f3df2015-06-26 16:58:36 -0600926 assert(typeId);
927 Op typeClass = getTypeClass(typeId);
928
929 switch (typeClass) {
930 case OpTypeVector:
931 case OpTypeArray:
John Kessenich140f3df2015-06-26 16:58:36 -0600932 case OpTypeMatrix:
John Kessenich46413d52018-02-26 19:20:05 -0700933 if (! specConstant) {
934 Id existing = findCompositeConstant(typeClass, members);
935 if (existing)
936 return existing;
937 }
938 break;
939 case OpTypeStruct:
940 if (! specConstant) {
941 Id existing = findStructConstant(typeId, members);
942 if (existing)
943 return existing;
944 }
John Kessenich140f3df2015-06-26 16:58:36 -0600945 break;
946 default:
John Kessenich55e7d112015-11-15 21:33:39 -0700947 assert(0);
John Kessenich140f3df2015-06-26 16:58:36 -0600948 return makeFloatConstant(0.0);
949 }
950
John Kessenich6c292d32016-02-15 20:58:50 -0700951 Instruction* c = new Instruction(getUniqueId(), typeId, opcode);
John Kessenich140f3df2015-06-26 16:58:36 -0600952 for (int op = 0; op < (int)members.size(); ++op)
953 c->addIdOperand(members[op]);
Andrew Woloszynb7946d12016-01-18 09:23:56 -0500954 constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(c));
John Kessenich46413d52018-02-26 19:20:05 -0700955 if (typeClass == OpTypeStruct)
956 groupedStructConstants[typeId].push_back(c);
957 else
958 groupedConstants[typeClass].push_back(c);
John Kessenich140f3df2015-06-26 16:58:36 -0600959 module.mapInstruction(c);
960
961 return c->getResultId();
962}
963
John Kessenich55e7d112015-11-15 21:33:39 -0700964Instruction* Builder::addEntryPoint(ExecutionModel model, Function* function, const char* name)
John Kessenich140f3df2015-06-26 16:58:36 -0600965{
966 Instruction* entryPoint = new Instruction(OpEntryPoint);
967 entryPoint->addImmediateOperand(model);
968 entryPoint->addIdOperand(function->getId());
John Kessenich5e4b1242015-08-06 22:53:06 -0600969 entryPoint->addStringOperand(name);
John Kessenich140f3df2015-06-26 16:58:36 -0600970
Andrew Woloszynb7946d12016-01-18 09:23:56 -0500971 entryPoints.push_back(std::unique_ptr<Instruction>(entryPoint));
John Kessenich55e7d112015-11-15 21:33:39 -0700972
973 return entryPoint;
John Kessenich140f3df2015-06-26 16:58:36 -0600974}
975
John Kessenichb56a26a2015-09-16 16:04:05 -0600976// Currently relying on the fact that all 'value' of interest are small non-negative values.
977void Builder::addExecutionMode(Function* entryPoint, ExecutionMode mode, int value1, int value2, int value3)
John Kessenich140f3df2015-06-26 16:58:36 -0600978{
John Kessenich140f3df2015-06-26 16:58:36 -0600979 Instruction* instr = new Instruction(OpExecutionMode);
980 instr->addIdOperand(entryPoint->getId());
981 instr->addImmediateOperand(mode);
John Kessenichb56a26a2015-09-16 16:04:05 -0600982 if (value1 >= 0)
983 instr->addImmediateOperand(value1);
984 if (value2 >= 0)
985 instr->addImmediateOperand(value2);
986 if (value3 >= 0)
987 instr->addImmediateOperand(value3);
John Kessenich140f3df2015-06-26 16:58:36 -0600988
Andrew Woloszynb7946d12016-01-18 09:23:56 -0500989 executionModes.push_back(std::unique_ptr<Instruction>(instr));
John Kessenich140f3df2015-06-26 16:58:36 -0600990}
991
992void Builder::addName(Id id, const char* string)
993{
994 Instruction* name = new Instruction(OpName);
995 name->addIdOperand(id);
996 name->addStringOperand(string);
997
Andrew Woloszynb7946d12016-01-18 09:23:56 -0500998 names.push_back(std::unique_ptr<Instruction>(name));
John Kessenich140f3df2015-06-26 16:58:36 -0600999}
1000
1001void Builder::addMemberName(Id id, int memberNumber, const char* string)
1002{
1003 Instruction* name = new Instruction(OpMemberName);
1004 name->addIdOperand(id);
1005 name->addImmediateOperand(memberNumber);
1006 name->addStringOperand(string);
1007
Andrew Woloszynb7946d12016-01-18 09:23:56 -05001008 names.push_back(std::unique_ptr<Instruction>(name));
John Kessenich140f3df2015-06-26 16:58:36 -06001009}
1010
John Kessenich140f3df2015-06-26 16:58:36 -06001011void Builder::addDecoration(Id id, Decoration decoration, int num)
1012{
John Kessenich4016e382016-07-15 11:53:56 -06001013 if (decoration == spv::DecorationMax)
John Kessenich55e7d112015-11-15 21:33:39 -07001014 return;
John Kessenich5d610ee2018-03-07 18:05:55 -07001015
John Kessenich140f3df2015-06-26 16:58:36 -06001016 Instruction* dec = new Instruction(OpDecorate);
1017 dec->addIdOperand(id);
1018 dec->addImmediateOperand(decoration);
1019 if (num >= 0)
1020 dec->addImmediateOperand(num);
1021
Andrew Woloszynb7946d12016-01-18 09:23:56 -05001022 decorations.push_back(std::unique_ptr<Instruction>(dec));
John Kessenich140f3df2015-06-26 16:58:36 -06001023}
1024
John Kessenich5d610ee2018-03-07 18:05:55 -07001025void Builder::addDecoration(Id id, Decoration decoration, const char* s)
1026{
1027 if (decoration == spv::DecorationMax)
1028 return;
1029
1030 Instruction* dec = new Instruction(OpDecorateStringGOOGLE);
1031 dec->addIdOperand(id);
1032 dec->addImmediateOperand(decoration);
1033 dec->addStringOperand(s);
1034
1035 decorations.push_back(std::unique_ptr<Instruction>(dec));
1036}
1037
1038void Builder::addDecorationId(Id id, Decoration decoration, Id idDecoration)
1039{
1040 if (decoration == spv::DecorationMax)
1041 return;
1042
1043 Instruction* dec = new Instruction(OpDecorateId);
1044 dec->addIdOperand(id);
1045 dec->addImmediateOperand(decoration);
1046 dec->addIdOperand(idDecoration);
1047
1048 decorations.push_back(std::unique_ptr<Instruction>(dec));
1049}
1050
John Kessenich140f3df2015-06-26 16:58:36 -06001051void Builder::addMemberDecoration(Id id, unsigned int member, Decoration decoration, int num)
1052{
John Kessenich5d610ee2018-03-07 18:05:55 -07001053 if (decoration == spv::DecorationMax)
1054 return;
1055
John Kessenich140f3df2015-06-26 16:58:36 -06001056 Instruction* dec = new Instruction(OpMemberDecorate);
1057 dec->addIdOperand(id);
1058 dec->addImmediateOperand(member);
1059 dec->addImmediateOperand(decoration);
1060 if (num >= 0)
1061 dec->addImmediateOperand(num);
1062
Andrew Woloszynb7946d12016-01-18 09:23:56 -05001063 decorations.push_back(std::unique_ptr<Instruction>(dec));
John Kessenich140f3df2015-06-26 16:58:36 -06001064}
1065
John Kessenich5d610ee2018-03-07 18:05:55 -07001066void Builder::addMemberDecoration(Id id, unsigned int member, Decoration decoration, const char *s)
1067{
1068 if (decoration == spv::DecorationMax)
1069 return;
1070
1071 Instruction* dec = new Instruction(OpMemberDecorateStringGOOGLE);
1072 dec->addIdOperand(id);
1073 dec->addImmediateOperand(member);
1074 dec->addImmediateOperand(decoration);
1075 dec->addStringOperand(s);
1076
1077 decorations.push_back(std::unique_ptr<Instruction>(dec));
1078}
1079
John Kessenich140f3df2015-06-26 16:58:36 -06001080// Comments in header
John Kessenich6fccb3c2016-09-19 16:01:41 -06001081Function* Builder::makeEntryPoint(const char* entryPoint)
John Kessenich140f3df2015-06-26 16:58:36 -06001082{
John Kessenich517fe7a2016-11-26 13:31:47 -07001083 assert(! entryPointFunction);
John Kessenich140f3df2015-06-26 16:58:36 -06001084
1085 Block* entry;
1086 std::vector<Id> params;
John Kessenichfad62972017-07-18 02:35:46 -06001087 std::vector<std::vector<Decoration>> decorations;
John Kessenich140f3df2015-06-26 16:58:36 -06001088
John Kessenichfad62972017-07-18 02:35:46 -06001089 entryPointFunction = makeFunctionEntry(NoPrecision, makeVoidType(), entryPoint, params, decorations, &entry);
John Kessenich140f3df2015-06-26 16:58:36 -06001090
John Kessenich517fe7a2016-11-26 13:31:47 -07001091 return entryPointFunction;
John Kessenich140f3df2015-06-26 16:58:36 -06001092}
1093
1094// Comments in header
John Kessenich32cfd492016-02-02 12:37:46 -07001095Function* Builder::makeFunctionEntry(Decoration precision, Id returnType, const char* name,
John Kessenichfad62972017-07-18 02:35:46 -06001096 const std::vector<Id>& paramTypes, const std::vector<std::vector<Decoration>>& decorations, Block **entry)
John Kessenich140f3df2015-06-26 16:58:36 -06001097{
John Kessenich32cfd492016-02-02 12:37:46 -07001098 // Make the function and initial instructions in it
John Kessenich140f3df2015-06-26 16:58:36 -06001099 Id typeId = makeFunctionType(returnType, paramTypes);
baldurkd76692d2015-07-12 11:32:58 +02001100 Id firstParamId = paramTypes.size() == 0 ? 0 : getUniqueIds((int)paramTypes.size());
John Kessenich140f3df2015-06-26 16:58:36 -06001101 Function* function = new Function(getUniqueId(), returnType, typeId, firstParamId, module);
1102
John Kessenich32cfd492016-02-02 12:37:46 -07001103 // Set up the precisions
1104 setPrecision(function->getId(), precision);
John Kessenichfad62972017-07-18 02:35:46 -06001105 for (unsigned p = 0; p < (unsigned)decorations.size(); ++p) {
1106 for (int d = 0; d < (int)decorations[p].size(); ++d)
1107 addDecoration(firstParamId + p, decorations[p][d]);
1108 }
John Kessenich32cfd492016-02-02 12:37:46 -07001109
1110 // CFG
John Kessenich140f3df2015-06-26 16:58:36 -06001111 if (entry) {
1112 *entry = new Block(getUniqueId(), *function);
1113 function->addBlock(*entry);
1114 setBuildPoint(*entry);
1115 }
1116
1117 if (name)
1118 addName(function->getId(), name);
1119
Andrew Woloszynb7946d12016-01-18 09:23:56 -05001120 functions.push_back(std::unique_ptr<Function>(function));
1121
John Kessenich140f3df2015-06-26 16:58:36 -06001122 return function;
1123}
1124
1125// Comments in header
John Kesseniche770b3e2015-09-14 20:58:02 -06001126void Builder::makeReturn(bool implicit, Id retVal)
John Kessenich140f3df2015-06-26 16:58:36 -06001127{
John Kesseniche770b3e2015-09-14 20:58:02 -06001128 if (retVal) {
John Kessenich140f3df2015-06-26 16:58:36 -06001129 Instruction* inst = new Instruction(NoResult, NoType, OpReturnValue);
1130 inst->addIdOperand(retVal);
Andrew Woloszynb7946d12016-01-18 09:23:56 -05001131 buildPoint->addInstruction(std::unique_ptr<Instruction>(inst));
John Kessenich140f3df2015-06-26 16:58:36 -06001132 } else
Andrew Woloszynb7946d12016-01-18 09:23:56 -05001133 buildPoint->addInstruction(std::unique_ptr<Instruction>(new Instruction(NoResult, NoType, OpReturn)));
John Kessenich140f3df2015-06-26 16:58:36 -06001134
1135 if (! implicit)
1136 createAndSetNoPredecessorBlock("post-return");
1137}
1138
1139// Comments in header
John Kesseniche770b3e2015-09-14 20:58:02 -06001140void Builder::leaveFunction()
John Kessenich140f3df2015-06-26 16:58:36 -06001141{
1142 Block* block = buildPoint;
1143 Function& function = buildPoint->getParent();
1144 assert(block);
1145
1146 // If our function did not contain a return, add a return void now.
1147 if (! block->isTerminated()) {
Dejan Mircevskied55bcd2016-01-19 21:13:38 -05001148 if (function.getReturnType() == makeVoidType())
1149 makeReturn(true);
1150 else {
1151 makeReturn(true, createUndefined(function.getReturnType()));
John Kessenich140f3df2015-06-26 16:58:36 -06001152 }
1153 }
John Kessenich140f3df2015-06-26 16:58:36 -06001154}
1155
1156// Comments in header
1157void Builder::makeDiscard()
1158{
Andrew Woloszynb7946d12016-01-18 09:23:56 -05001159 buildPoint->addInstruction(std::unique_ptr<Instruction>(new Instruction(OpKill)));
John Kessenich140f3df2015-06-26 16:58:36 -06001160 createAndSetNoPredecessorBlock("post-discard");
1161}
1162
1163// Comments in header
1164Id Builder::createVariable(StorageClass storageClass, Id type, const char* name)
1165{
1166 Id pointerType = makePointer(storageClass, type);
1167 Instruction* inst = new Instruction(getUniqueId(), pointerType, OpVariable);
1168 inst->addImmediateOperand(storageClass);
1169
1170 switch (storageClass) {
John Kessenich140f3df2015-06-26 16:58:36 -06001171 case StorageClassFunction:
1172 // Validation rules require the declaration in the entry block
Andrew Woloszynb7946d12016-01-18 09:23:56 -05001173 buildPoint->getParent().addLocalVariable(std::unique_ptr<Instruction>(inst));
John Kessenich140f3df2015-06-26 16:58:36 -06001174 break;
1175
1176 default:
Andrew Woloszynb7946d12016-01-18 09:23:56 -05001177 constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(inst));
John Kessenich55e7d112015-11-15 21:33:39 -07001178 module.mapInstruction(inst);
John Kessenich140f3df2015-06-26 16:58:36 -06001179 break;
1180 }
1181
1182 if (name)
1183 addName(inst->getResultId(), name);
1184
1185 return inst->getResultId();
1186}
1187
1188// Comments in header
Miro Knejp28f9b1c2015-08-11 02:45:24 +02001189Id Builder::createUndefined(Id type)
1190{
1191 Instruction* inst = new Instruction(getUniqueId(), type, OpUndef);
Andrew Woloszynb7946d12016-01-18 09:23:56 -05001192 buildPoint->addInstruction(std::unique_ptr<Instruction>(inst));
Miro Knejp28f9b1c2015-08-11 02:45:24 +02001193 return inst->getResultId();
1194}
1195
1196// Comments in header
John Kessenich140f3df2015-06-26 16:58:36 -06001197void Builder::createStore(Id rValue, Id lValue)
1198{
1199 Instruction* store = new Instruction(OpStore);
1200 store->addIdOperand(lValue);
1201 store->addIdOperand(rValue);
Andrew Woloszynb7946d12016-01-18 09:23:56 -05001202 buildPoint->addInstruction(std::unique_ptr<Instruction>(store));
John Kessenich140f3df2015-06-26 16:58:36 -06001203}
1204
1205// Comments in header
1206Id Builder::createLoad(Id lValue)
1207{
1208 Instruction* load = new Instruction(getUniqueId(), getDerefTypeId(lValue), OpLoad);
1209 load->addIdOperand(lValue);
Andrew Woloszynb7946d12016-01-18 09:23:56 -05001210 buildPoint->addInstruction(std::unique_ptr<Instruction>(load));
John Kessenich140f3df2015-06-26 16:58:36 -06001211
1212 return load->getResultId();
1213}
1214
1215// Comments in header
Vlad Ivanov689490f2017-01-26 20:46:02 +03001216Id Builder::createAccessChain(StorageClass storageClass, Id base, const std::vector<Id>& offsets)
John Kessenich140f3df2015-06-26 16:58:36 -06001217{
1218 // Figure out the final resulting type.
1219 spv::Id typeId = getTypeId(base);
1220 assert(isPointerType(typeId) && offsets.size() > 0);
1221 typeId = getContainedTypeId(typeId);
1222 for (int i = 0; i < (int)offsets.size(); ++i) {
1223 if (isStructType(typeId)) {
1224 assert(isConstantScalar(offsets[i]));
1225 typeId = getContainedTypeId(typeId, getConstantScalar(offsets[i]));
1226 } else
1227 typeId = getContainedTypeId(typeId, offsets[i]);
1228 }
1229 typeId = makePointer(storageClass, typeId);
1230
1231 // Make the instruction
1232 Instruction* chain = new Instruction(getUniqueId(), typeId, OpAccessChain);
1233 chain->addIdOperand(base);
1234 for (int i = 0; i < (int)offsets.size(); ++i)
1235 chain->addIdOperand(offsets[i]);
Andrew Woloszynb7946d12016-01-18 09:23:56 -05001236 buildPoint->addInstruction(std::unique_ptr<Instruction>(chain));
John Kessenich140f3df2015-06-26 16:58:36 -06001237
1238 return chain->getResultId();
1239}
1240
John Kessenichee21fc92015-09-21 21:50:29 -06001241Id Builder::createArrayLength(Id base, unsigned int member)
1242{
John Kessenichac370792018-03-07 11:24:50 -07001243 spv::Id intType = makeIntType(32);
steve-lunarg5da1f032017-02-12 17:50:28 -07001244 Instruction* length = new Instruction(getUniqueId(), intType, OpArrayLength);
John Kessenichee21fc92015-09-21 21:50:29 -06001245 length->addIdOperand(base);
1246 length->addImmediateOperand(member);
Andrew Woloszynb7946d12016-01-18 09:23:56 -05001247 buildPoint->addInstruction(std::unique_ptr<Instruction>(length));
John Kessenichee21fc92015-09-21 21:50:29 -06001248
1249 return length->getResultId();
1250}
1251
John Kessenich140f3df2015-06-26 16:58:36 -06001252Id Builder::createCompositeExtract(Id composite, Id typeId, unsigned index)
1253{
qining13545202016-03-21 09:51:37 -04001254 // Generate code for spec constants if in spec constant operation
1255 // generation mode.
1256 if (generatingOpCodeForSpecConst) {
baldurk0dfbe3f2016-04-02 13:38:28 +02001257 return createSpecConstantOp(OpCompositeExtract, typeId, std::vector<Id>(1, composite), std::vector<Id>(1, index));
qining13545202016-03-21 09:51:37 -04001258 }
John Kessenich140f3df2015-06-26 16:58:36 -06001259 Instruction* extract = new Instruction(getUniqueId(), typeId, OpCompositeExtract);
1260 extract->addIdOperand(composite);
1261 extract->addImmediateOperand(index);
Andrew Woloszynb7946d12016-01-18 09:23:56 -05001262 buildPoint->addInstruction(std::unique_ptr<Instruction>(extract));
John Kessenich140f3df2015-06-26 16:58:36 -06001263
1264 return extract->getResultId();
1265}
1266
Vlad Ivanov689490f2017-01-26 20:46:02 +03001267Id Builder::createCompositeExtract(Id composite, Id typeId, const std::vector<unsigned>& indexes)
John Kessenich140f3df2015-06-26 16:58:36 -06001268{
qining13545202016-03-21 09:51:37 -04001269 // Generate code for spec constants if in spec constant operation
1270 // generation mode.
1271 if (generatingOpCodeForSpecConst) {
baldurk0dfbe3f2016-04-02 13:38:28 +02001272 return createSpecConstantOp(OpCompositeExtract, typeId, std::vector<Id>(1, composite), indexes);
qining13545202016-03-21 09:51:37 -04001273 }
John Kessenich140f3df2015-06-26 16:58:36 -06001274 Instruction* extract = new Instruction(getUniqueId(), typeId, OpCompositeExtract);
1275 extract->addIdOperand(composite);
1276 for (int i = 0; i < (int)indexes.size(); ++i)
1277 extract->addImmediateOperand(indexes[i]);
Andrew Woloszynb7946d12016-01-18 09:23:56 -05001278 buildPoint->addInstruction(std::unique_ptr<Instruction>(extract));
John Kessenich140f3df2015-06-26 16:58:36 -06001279
1280 return extract->getResultId();
1281}
1282
1283Id Builder::createCompositeInsert(Id object, Id composite, Id typeId, unsigned index)
1284{
1285 Instruction* insert = new Instruction(getUniqueId(), typeId, OpCompositeInsert);
1286 insert->addIdOperand(object);
1287 insert->addIdOperand(composite);
1288 insert->addImmediateOperand(index);
Andrew Woloszynb7946d12016-01-18 09:23:56 -05001289 buildPoint->addInstruction(std::unique_ptr<Instruction>(insert));
John Kessenich140f3df2015-06-26 16:58:36 -06001290
1291 return insert->getResultId();
1292}
1293
Vlad Ivanov689490f2017-01-26 20:46:02 +03001294Id Builder::createCompositeInsert(Id object, Id composite, Id typeId, const std::vector<unsigned>& indexes)
John Kessenich140f3df2015-06-26 16:58:36 -06001295{
1296 Instruction* insert = new Instruction(getUniqueId(), typeId, OpCompositeInsert);
1297 insert->addIdOperand(object);
1298 insert->addIdOperand(composite);
1299 for (int i = 0; i < (int)indexes.size(); ++i)
1300 insert->addImmediateOperand(indexes[i]);
Andrew Woloszynb7946d12016-01-18 09:23:56 -05001301 buildPoint->addInstruction(std::unique_ptr<Instruction>(insert));
John Kessenich140f3df2015-06-26 16:58:36 -06001302
1303 return insert->getResultId();
1304}
1305
1306Id Builder::createVectorExtractDynamic(Id vector, Id typeId, Id componentIndex)
1307{
1308 Instruction* extract = new Instruction(getUniqueId(), typeId, OpVectorExtractDynamic);
1309 extract->addIdOperand(vector);
1310 extract->addIdOperand(componentIndex);
Andrew Woloszynb7946d12016-01-18 09:23:56 -05001311 buildPoint->addInstruction(std::unique_ptr<Instruction>(extract));
John Kessenich140f3df2015-06-26 16:58:36 -06001312
1313 return extract->getResultId();
1314}
1315
1316Id Builder::createVectorInsertDynamic(Id vector, Id typeId, Id component, Id componentIndex)
1317{
1318 Instruction* insert = new Instruction(getUniqueId(), typeId, OpVectorInsertDynamic);
1319 insert->addIdOperand(vector);
1320 insert->addIdOperand(component);
1321 insert->addIdOperand(componentIndex);
Andrew Woloszynb7946d12016-01-18 09:23:56 -05001322 buildPoint->addInstruction(std::unique_ptr<Instruction>(insert));
John Kessenich140f3df2015-06-26 16:58:36 -06001323
1324 return insert->getResultId();
1325}
1326
1327// An opcode that has no operands, no result id, and no type
1328void Builder::createNoResultOp(Op opCode)
1329{
1330 Instruction* op = new Instruction(opCode);
Andrew Woloszynb7946d12016-01-18 09:23:56 -05001331 buildPoint->addInstruction(std::unique_ptr<Instruction>(op));
John Kessenich140f3df2015-06-26 16:58:36 -06001332}
1333
1334// An opcode that has one operand, no result id, and no type
1335void Builder::createNoResultOp(Op opCode, Id operand)
1336{
1337 Instruction* op = new Instruction(opCode);
1338 op->addIdOperand(operand);
Andrew Woloszynb7946d12016-01-18 09:23:56 -05001339 buildPoint->addInstruction(std::unique_ptr<Instruction>(op));
John Kessenich140f3df2015-06-26 16:58:36 -06001340}
1341
Rex Xufc618912015-09-09 16:42:49 +08001342// An opcode that has one operand, no result id, and no type
1343void Builder::createNoResultOp(Op opCode, const std::vector<Id>& operands)
1344{
1345 Instruction* op = new Instruction(opCode);
rdb32084e82016-02-23 22:17:38 +01001346 for (auto it = operands.cbegin(); it != operands.cend(); ++it)
1347 op->addIdOperand(*it);
Andrew Woloszynb7946d12016-01-18 09:23:56 -05001348 buildPoint->addInstruction(std::unique_ptr<Instruction>(op));
Rex Xufc618912015-09-09 16:42:49 +08001349}
1350
John Kessenich5e4b1242015-08-06 22:53:06 -06001351void Builder::createControlBarrier(Scope execution, Scope memory, MemorySemanticsMask semantics)
John Kessenich140f3df2015-06-26 16:58:36 -06001352{
1353 Instruction* op = new Instruction(OpControlBarrier);
John Kessenich5e4b1242015-08-06 22:53:06 -06001354 op->addImmediateOperand(makeUintConstant(execution));
1355 op->addImmediateOperand(makeUintConstant(memory));
1356 op->addImmediateOperand(makeUintConstant(semantics));
Andrew Woloszynb7946d12016-01-18 09:23:56 -05001357 buildPoint->addInstruction(std::unique_ptr<Instruction>(op));
John Kessenich140f3df2015-06-26 16:58:36 -06001358}
1359
1360void Builder::createMemoryBarrier(unsigned executionScope, unsigned memorySemantics)
1361{
1362 Instruction* op = new Instruction(OpMemoryBarrier);
John Kessenich5e4b1242015-08-06 22:53:06 -06001363 op->addImmediateOperand(makeUintConstant(executionScope));
1364 op->addImmediateOperand(makeUintConstant(memorySemantics));
Andrew Woloszynb7946d12016-01-18 09:23:56 -05001365 buildPoint->addInstruction(std::unique_ptr<Instruction>(op));
John Kessenich140f3df2015-06-26 16:58:36 -06001366}
1367
1368// An opcode that has one operands, a result id, and a type
1369Id Builder::createUnaryOp(Op opCode, Id typeId, Id operand)
1370{
qining13545202016-03-21 09:51:37 -04001371 // Generate code for spec constants if in spec constant operation
1372 // generation mode.
1373 if (generatingOpCodeForSpecConst) {
baldurk0dfbe3f2016-04-02 13:38:28 +02001374 return createSpecConstantOp(opCode, typeId, std::vector<Id>(1, operand), std::vector<Id>());
qining13545202016-03-21 09:51:37 -04001375 }
John Kessenich140f3df2015-06-26 16:58:36 -06001376 Instruction* op = new Instruction(getUniqueId(), typeId, opCode);
1377 op->addIdOperand(operand);
Andrew Woloszynb7946d12016-01-18 09:23:56 -05001378 buildPoint->addInstruction(std::unique_ptr<Instruction>(op));
John Kessenich140f3df2015-06-26 16:58:36 -06001379
1380 return op->getResultId();
1381}
1382
1383Id Builder::createBinOp(Op opCode, Id typeId, Id left, Id right)
1384{
qining13545202016-03-21 09:51:37 -04001385 // Generate code for spec constants if in spec constant operation
1386 // generation mode.
1387 if (generatingOpCodeForSpecConst) {
baldurk0dfbe3f2016-04-02 13:38:28 +02001388 std::vector<Id> operands(2);
1389 operands[0] = left; operands[1] = right;
1390 return createSpecConstantOp(opCode, typeId, operands, std::vector<Id>());
qining13545202016-03-21 09:51:37 -04001391 }
John Kessenich140f3df2015-06-26 16:58:36 -06001392 Instruction* op = new Instruction(getUniqueId(), typeId, opCode);
1393 op->addIdOperand(left);
1394 op->addIdOperand(right);
Andrew Woloszynb7946d12016-01-18 09:23:56 -05001395 buildPoint->addInstruction(std::unique_ptr<Instruction>(op));
John Kessenich140f3df2015-06-26 16:58:36 -06001396
1397 return op->getResultId();
1398}
1399
1400Id Builder::createTriOp(Op opCode, Id typeId, Id op1, Id op2, Id op3)
1401{
qininge24aa5e2016-04-07 15:40:27 -04001402 // Generate code for spec constants if in spec constant operation
1403 // generation mode.
1404 if (generatingOpCodeForSpecConst) {
1405 std::vector<Id> operands(3);
qining189b2032016-04-12 23:16:20 -04001406 operands[0] = op1;
1407 operands[1] = op2;
1408 operands[2] = op3;
qininge24aa5e2016-04-07 15:40:27 -04001409 return createSpecConstantOp(
1410 opCode, typeId, operands, std::vector<Id>());
1411 }
John Kessenich140f3df2015-06-26 16:58:36 -06001412 Instruction* op = new Instruction(getUniqueId(), typeId, opCode);
1413 op->addIdOperand(op1);
1414 op->addIdOperand(op2);
1415 op->addIdOperand(op3);
Andrew Woloszynb7946d12016-01-18 09:23:56 -05001416 buildPoint->addInstruction(std::unique_ptr<Instruction>(op));
John Kessenich140f3df2015-06-26 16:58:36 -06001417
1418 return op->getResultId();
1419}
1420
John Kessenich5e4b1242015-08-06 22:53:06 -06001421Id Builder::createOp(Op opCode, Id typeId, const std::vector<Id>& operands)
John Kessenich140f3df2015-06-26 16:58:36 -06001422{
1423 Instruction* op = new Instruction(getUniqueId(), typeId, opCode);
rdb32084e82016-02-23 22:17:38 +01001424 for (auto it = operands.cbegin(); it != operands.cend(); ++it)
1425 op->addIdOperand(*it);
Andrew Woloszynb7946d12016-01-18 09:23:56 -05001426 buildPoint->addInstruction(std::unique_ptr<Instruction>(op));
John Kessenich140f3df2015-06-26 16:58:36 -06001427
1428 return op->getResultId();
1429}
1430
qining5c61d8e2016-03-31 13:57:28 -04001431Id Builder::createSpecConstantOp(Op opCode, Id typeId, const std::vector<Id>& operands, const std::vector<unsigned>& literals)
1432{
qining13545202016-03-21 09:51:37 -04001433 Instruction* op = new Instruction(getUniqueId(), typeId, OpSpecConstantOp);
1434 op->addImmediateOperand((unsigned) opCode);
1435 for (auto it = operands.cbegin(); it != operands.cend(); ++it)
1436 op->addIdOperand(*it);
1437 for (auto it = literals.cbegin(); it != literals.cend(); ++it)
1438 op->addImmediateOperand(*it);
1439 module.mapInstruction(op);
1440 constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(op));
1441
1442 return op->getResultId();
1443}
1444
Vlad Ivanov689490f2017-01-26 20:46:02 +03001445Id Builder::createFunctionCall(spv::Function* function, const std::vector<spv::Id>& args)
John Kessenich140f3df2015-06-26 16:58:36 -06001446{
1447 Instruction* op = new Instruction(getUniqueId(), function->getReturnType(), OpFunctionCall);
1448 op->addIdOperand(function->getId());
1449 for (int a = 0; a < (int)args.size(); ++a)
1450 op->addIdOperand(args[a]);
Andrew Woloszynb7946d12016-01-18 09:23:56 -05001451 buildPoint->addInstruction(std::unique_ptr<Instruction>(op));
John Kessenich140f3df2015-06-26 16:58:36 -06001452
1453 return op->getResultId();
1454}
1455
1456// Comments in header
Vlad Ivanov689490f2017-01-26 20:46:02 +03001457Id Builder::createRvalueSwizzle(Decoration precision, Id typeId, Id source, const std::vector<unsigned>& channels)
John Kessenich140f3df2015-06-26 16:58:36 -06001458{
1459 if (channels.size() == 1)
John Kessenich32cfd492016-02-02 12:37:46 -07001460 return setPrecision(createCompositeExtract(source, typeId, channels.front()), precision);
John Kessenich140f3df2015-06-26 16:58:36 -06001461
qining13545202016-03-21 09:51:37 -04001462 if (generatingOpCodeForSpecConst) {
baldurk0dfbe3f2016-04-02 13:38:28 +02001463 std::vector<Id> operands(2);
1464 operands[0] = operands[1] = source;
1465 return setPrecision(createSpecConstantOp(OpVectorShuffle, typeId, operands, channels), precision);
qining13545202016-03-21 09:51:37 -04001466 }
John Kessenich140f3df2015-06-26 16:58:36 -06001467 Instruction* swizzle = new Instruction(getUniqueId(), typeId, OpVectorShuffle);
1468 assert(isVector(source));
1469 swizzle->addIdOperand(source);
1470 swizzle->addIdOperand(source);
1471 for (int i = 0; i < (int)channels.size(); ++i)
1472 swizzle->addImmediateOperand(channels[i]);
Andrew Woloszynb7946d12016-01-18 09:23:56 -05001473 buildPoint->addInstruction(std::unique_ptr<Instruction>(swizzle));
John Kessenich140f3df2015-06-26 16:58:36 -06001474
John Kessenich32cfd492016-02-02 12:37:46 -07001475 return setPrecision(swizzle->getResultId(), precision);
John Kessenich140f3df2015-06-26 16:58:36 -06001476}
1477
1478// Comments in header
Vlad Ivanov689490f2017-01-26 20:46:02 +03001479Id Builder::createLvalueSwizzle(Id typeId, Id target, Id source, const std::vector<unsigned>& channels)
John Kessenich140f3df2015-06-26 16:58:36 -06001480{
John Kessenich140f3df2015-06-26 16:58:36 -06001481 if (channels.size() == 1 && getNumComponents(source) == 1)
1482 return createCompositeInsert(source, target, typeId, channels.front());
1483
1484 Instruction* swizzle = new Instruction(getUniqueId(), typeId, OpVectorShuffle);
John Kessenich5c3eed52018-02-05 14:44:14 -07001485
John Kessenich140f3df2015-06-26 16:58:36 -06001486 assert(isVector(target));
1487 swizzle->addIdOperand(target);
John Kessenich5c3eed52018-02-05 14:44:14 -07001488
1489 assert(getNumComponents(source) == (int)channels.size());
1490 assert(isVector(source));
1491 swizzle->addIdOperand(source);
John Kessenich140f3df2015-06-26 16:58:36 -06001492
1493 // Set up an identity shuffle from the base value to the result value
1494 unsigned int components[4];
1495 int numTargetComponents = getNumComponents(target);
1496 for (int i = 0; i < numTargetComponents; ++i)
1497 components[i] = i;
1498
1499 // Punch in the l-value swizzle
John Kessenich5c3eed52018-02-05 14:44:14 -07001500 for (int i = 0; i < (int)channels.size(); ++i)
1501 components[channels[i]] = numTargetComponents + i;
John Kessenich140f3df2015-06-26 16:58:36 -06001502
1503 // finish the instruction with these components selectors
1504 for (int i = 0; i < numTargetComponents; ++i)
1505 swizzle->addImmediateOperand(components[i]);
Andrew Woloszynb7946d12016-01-18 09:23:56 -05001506 buildPoint->addInstruction(std::unique_ptr<Instruction>(swizzle));
John Kessenich140f3df2015-06-26 16:58:36 -06001507
1508 return swizzle->getResultId();
1509}
1510
1511// Comments in header
1512void Builder::promoteScalar(Decoration precision, Id& left, Id& right)
1513{
1514 int direction = getNumComponents(right) - getNumComponents(left);
1515
1516 if (direction > 0)
John Kessenich76f71392015-12-09 19:08:42 -07001517 left = smearScalar(precision, left, makeVectorType(getTypeId(left), getNumComponents(right)));
John Kessenich140f3df2015-06-26 16:58:36 -06001518 else if (direction < 0)
John Kessenich76f71392015-12-09 19:08:42 -07001519 right = smearScalar(precision, right, makeVectorType(getTypeId(right), getNumComponents(left)));
John Kessenich140f3df2015-06-26 16:58:36 -06001520
1521 return;
1522}
1523
1524// Comments in header
John Kessenich32cfd492016-02-02 12:37:46 -07001525Id Builder::smearScalar(Decoration precision, Id scalar, Id vectorType)
John Kessenich140f3df2015-06-26 16:58:36 -06001526{
1527 assert(getNumComponents(scalar) == 1);
John Kessenich76f71392015-12-09 19:08:42 -07001528 assert(getTypeId(scalar) == getScalarTypeId(vectorType));
John Kessenich140f3df2015-06-26 16:58:36 -06001529
1530 int numComponents = getNumTypeComponents(vectorType);
1531 if (numComponents == 1)
1532 return scalar;
1533
qining13545202016-03-21 09:51:37 -04001534 Instruction* smear = nullptr;
1535 if (generatingOpCodeForSpecConst) {
1536 auto members = std::vector<spv::Id>(numComponents, scalar);
qining1f2820a2016-04-14 18:34:27 -04001537 // Sometime even in spec-constant-op mode, the temporary vector created by
1538 // promoting a scalar might not be a spec constant. This should depend on
1539 // the scalar.
1540 // e.g.:
1541 // const vec2 spec_const_result = a_spec_const_vec2 + a_front_end_const_scalar;
1542 // In such cases, the temporary vector created from a_front_end_const_scalar
1543 // is not a spec constant vector, even though the binary operation node is marked
1544 // as 'specConstant' and we are in spec-constant-op mode.
qining27e04a02016-04-14 16:40:20 -04001545 auto result_id = makeCompositeConstant(vectorType, members, isSpecConstant(scalar));
qining13545202016-03-21 09:51:37 -04001546 smear = module.getInstruction(result_id);
1547 } else {
1548 smear = new Instruction(getUniqueId(), vectorType, OpCompositeConstruct);
1549 for (int c = 0; c < numComponents; ++c)
1550 smear->addIdOperand(scalar);
1551 buildPoint->addInstruction(std::unique_ptr<Instruction>(smear));
1552 }
John Kessenich140f3df2015-06-26 16:58:36 -06001553
John Kessenich32cfd492016-02-02 12:37:46 -07001554 return setPrecision(smear->getResultId(), precision);
John Kessenich140f3df2015-06-26 16:58:36 -06001555}
1556
1557// Comments in header
Vlad Ivanov689490f2017-01-26 20:46:02 +03001558Id Builder::createBuiltinCall(Id resultType, Id builtins, int entryPoint, const std::vector<Id>& args)
John Kessenich140f3df2015-06-26 16:58:36 -06001559{
1560 Instruction* inst = new Instruction(getUniqueId(), resultType, OpExtInst);
1561 inst->addIdOperand(builtins);
1562 inst->addImmediateOperand(entryPoint);
1563 for (int arg = 0; arg < (int)args.size(); ++arg)
1564 inst->addIdOperand(args[arg]);
1565
Andrew Woloszynb7946d12016-01-18 09:23:56 -05001566 buildPoint->addInstruction(std::unique_ptr<Instruction>(inst));
John Kessenich32cfd492016-02-02 12:37:46 -07001567
John Kessenich140f3df2015-06-26 16:58:36 -06001568 return inst->getResultId();
1569}
1570
1571// Accept all parameters needed to create a texture instruction.
1572// Create the correct instruction based on the inputs, and make the call.
John Kessenichba018e62018-06-05 08:53:36 -06001573Id Builder::createTextureCall(Decoration precision, Id resultType, bool sparse, bool fetch, bool proj, bool gather,
1574 bool noImplicitLod, const TextureParameters& parameters)
John Kessenich140f3df2015-06-26 16:58:36 -06001575{
John Kessenich5e4b1242015-08-06 22:53:06 -06001576 static const int maxTextureArgs = 10;
John Kessenich140f3df2015-06-26 16:58:36 -06001577 Id texArgs[maxTextureArgs] = {};
1578
1579 //
John Kessenich5e4b1242015-08-06 22:53:06 -06001580 // Set up the fixed arguments
John Kessenich140f3df2015-06-26 16:58:36 -06001581 //
John Kessenich140f3df2015-06-26 16:58:36 -06001582 int numArgs = 0;
John Kessenich019f08f2016-02-15 15:40:42 -07001583 bool explicitLod = false;
John Kessenich140f3df2015-06-26 16:58:36 -06001584 texArgs[numArgs++] = parameters.sampler;
1585 texArgs[numArgs++] = parameters.coords;
John Kessenich76d4dfc2016-06-16 12:43:23 -06001586 if (parameters.Dref != NoResult)
John Kessenich140f3df2015-06-26 16:58:36 -06001587 texArgs[numArgs++] = parameters.Dref;
John Kessenich76d4dfc2016-06-16 12:43:23 -06001588 if (parameters.component != NoResult)
1589 texArgs[numArgs++] = parameters.component;
John Kessenich140f3df2015-06-26 16:58:36 -06001590
1591 //
John Kessenich5e4b1242015-08-06 22:53:06 -06001592 // Set up the optional arguments
1593 //
1594 int optArgNum = numArgs; // track which operand, if it exists, is the mask of optional arguments
1595 ++numArgs; // speculatively make room for the mask operand
1596 ImageOperandsMask mask = ImageOperandsMaskNone; // the mask operand
1597 if (parameters.bias) {
1598 mask = (ImageOperandsMask)(mask | ImageOperandsBiasMask);
1599 texArgs[numArgs++] = parameters.bias;
1600 }
1601 if (parameters.lod) {
1602 mask = (ImageOperandsMask)(mask | ImageOperandsLodMask);
1603 texArgs[numArgs++] = parameters.lod;
John Kessenich019f08f2016-02-15 15:40:42 -07001604 explicitLod = true;
1605 } else if (parameters.gradX) {
John Kessenich5e4b1242015-08-06 22:53:06 -06001606 mask = (ImageOperandsMask)(mask | ImageOperandsGradMask);
1607 texArgs[numArgs++] = parameters.gradX;
1608 texArgs[numArgs++] = parameters.gradY;
John Kessenich019f08f2016-02-15 15:40:42 -07001609 explicitLod = true;
1610 } else if (noImplicitLod && ! fetch && ! gather) {
1611 // have to explicitly use lod of 0 if not allowed to have them be implicit, and
1612 // we would otherwise be about to issue an implicit instruction
1613 mask = (ImageOperandsMask)(mask | ImageOperandsLodMask);
1614 texArgs[numArgs++] = makeFloatConstant(0.0);
1615 explicitLod = true;
John Kessenich5e4b1242015-08-06 22:53:06 -06001616 }
1617 if (parameters.offset) {
Rex Xu86e60812015-10-11 19:37:48 +08001618 if (isConstant(parameters.offset))
1619 mask = (ImageOperandsMask)(mask | ImageOperandsConstOffsetMask);
Rex Xu58390312016-05-11 16:38:50 +08001620 else {
1621 addCapability(CapabilityImageGatherExtended);
Rex Xu86e60812015-10-11 19:37:48 +08001622 mask = (ImageOperandsMask)(mask | ImageOperandsOffsetMask);
Rex Xu58390312016-05-11 16:38:50 +08001623 }
John Kessenich5e4b1242015-08-06 22:53:06 -06001624 texArgs[numArgs++] = parameters.offset;
1625 }
John Kessenich5e4b1242015-08-06 22:53:06 -06001626 if (parameters.offsets) {
John Kessenichba018e62018-06-05 08:53:36 -06001627 addCapability(CapabilityImageGatherExtended);
John Kessenich5e4b1242015-08-06 22:53:06 -06001628 mask = (ImageOperandsMask)(mask | ImageOperandsConstOffsetsMask);
1629 texArgs[numArgs++] = parameters.offsets;
1630 }
1631 if (parameters.sample) {
1632 mask = (ImageOperandsMask)(mask | ImageOperandsSampleMask);
1633 texArgs[numArgs++] = parameters.sample;
1634 }
Rex Xu48edadf2015-12-31 16:11:41 +08001635 if (parameters.lodClamp) {
John Kessenich5e801132016-02-15 11:09:46 -07001636 // capability if this bit is used
1637 addCapability(CapabilityMinLod);
1638
Rex Xu48edadf2015-12-31 16:11:41 +08001639 mask = (ImageOperandsMask)(mask | ImageOperandsMinLodMask);
1640 texArgs[numArgs++] = parameters.lodClamp;
1641 }
John Kessenich5e4b1242015-08-06 22:53:06 -06001642 if (mask == ImageOperandsMaskNone)
1643 --numArgs; // undo speculative reservation for the mask argument
1644 else
1645 texArgs[optArgNum] = mask;
1646
1647 //
John Kessenich140f3df2015-06-26 16:58:36 -06001648 // Set up the instruction
1649 //
John Kessenich019f08f2016-02-15 15:40:42 -07001650 Op opCode = OpNop; // All paths below need to set this
Jason Ekstrand18b9fbd2015-09-05 14:14:48 -07001651 if (fetch) {
Rex Xu48edadf2015-12-31 16:11:41 +08001652 if (sparse)
1653 opCode = OpImageSparseFetch;
1654 else
1655 opCode = OpImageFetch;
John Kessenich55e7d112015-11-15 21:33:39 -07001656 } else if (gather) {
1657 if (parameters.Dref)
Rex Xu48edadf2015-12-31 16:11:41 +08001658 if (sparse)
1659 opCode = OpImageSparseDrefGather;
1660 else
1661 opCode = OpImageDrefGather;
John Kessenich55e7d112015-11-15 21:33:39 -07001662 else
Rex Xu48edadf2015-12-31 16:11:41 +08001663 if (sparse)
1664 opCode = OpImageSparseGather;
1665 else
1666 opCode = OpImageGather;
John Kessenich019f08f2016-02-15 15:40:42 -07001667 } else if (explicitLod) {
John Kessenich5e4b1242015-08-06 22:53:06 -06001668 if (parameters.Dref) {
1669 if (proj)
Rex Xu48edadf2015-12-31 16:11:41 +08001670 if (sparse)
1671 opCode = OpImageSparseSampleProjDrefExplicitLod;
1672 else
1673 opCode = OpImageSampleProjDrefExplicitLod;
John Kessenich5e4b1242015-08-06 22:53:06 -06001674 else
Rex Xu48edadf2015-12-31 16:11:41 +08001675 if (sparse)
1676 opCode = OpImageSparseSampleDrefExplicitLod;
1677 else
1678 opCode = OpImageSampleDrefExplicitLod;
John Kessenich5e4b1242015-08-06 22:53:06 -06001679 } else {
1680 if (proj)
Rex Xu48edadf2015-12-31 16:11:41 +08001681 if (sparse)
1682 opCode = OpImageSparseSampleProjExplicitLod;
1683 else
1684 opCode = OpImageSampleProjExplicitLod;
John Kessenich5e4b1242015-08-06 22:53:06 -06001685 else
Rex Xu48edadf2015-12-31 16:11:41 +08001686 if (sparse)
1687 opCode = OpImageSparseSampleExplicitLod;
1688 else
1689 opCode = OpImageSampleExplicitLod;
John Kessenich5e4b1242015-08-06 22:53:06 -06001690 }
1691 } else {
1692 if (parameters.Dref) {
1693 if (proj)
Rex Xu48edadf2015-12-31 16:11:41 +08001694 if (sparse)
1695 opCode = OpImageSparseSampleProjDrefImplicitLod;
1696 else
1697 opCode = OpImageSampleProjDrefImplicitLod;
John Kessenich5e4b1242015-08-06 22:53:06 -06001698 else
Rex Xu48edadf2015-12-31 16:11:41 +08001699 if (sparse)
1700 opCode = OpImageSparseSampleDrefImplicitLod;
1701 else
1702 opCode = OpImageSampleDrefImplicitLod;
John Kessenich5e4b1242015-08-06 22:53:06 -06001703 } else {
1704 if (proj)
Rex Xu48edadf2015-12-31 16:11:41 +08001705 if (sparse)
1706 opCode = OpImageSparseSampleProjImplicitLod;
1707 else
1708 opCode = OpImageSampleProjImplicitLod;
John Kessenich5e4b1242015-08-06 22:53:06 -06001709 else
Rex Xu48edadf2015-12-31 16:11:41 +08001710 if (sparse)
1711 opCode = OpImageSparseSampleImplicitLod;
1712 else
1713 opCode = OpImageSampleImplicitLod;
John Kessenich5e4b1242015-08-06 22:53:06 -06001714 }
1715 }
John Kessenich140f3df2015-06-26 16:58:36 -06001716
John Kessenich7355eeb2015-09-14 22:08:12 -06001717 // See if the result type is expecting a smeared result.
1718 // This happens when a legacy shadow*() call is made, which
1719 // gets a vec4 back instead of a float.
1720 Id smearedType = resultType;
1721 if (! isScalarType(resultType)) {
1722 switch (opCode) {
1723 case OpImageSampleDrefImplicitLod:
1724 case OpImageSampleDrefExplicitLod:
1725 case OpImageSampleProjDrefImplicitLod:
1726 case OpImageSampleProjDrefExplicitLod:
1727 resultType = getScalarTypeId(resultType);
1728 break;
1729 default:
1730 break;
1731 }
1732 }
1733
Rex Xu48edadf2015-12-31 16:11:41 +08001734 Id typeId0 = 0;
1735 Id typeId1 = 0;
1736
1737 if (sparse) {
1738 typeId0 = resultType;
1739 typeId1 = getDerefTypeId(parameters.texelOut);
1740 resultType = makeStructResultType(typeId0, typeId1);
1741 }
1742
John Kessenich55e7d112015-11-15 21:33:39 -07001743 // Build the SPIR-V instruction
John Kessenich140f3df2015-06-26 16:58:36 -06001744 Instruction* textureInst = new Instruction(getUniqueId(), resultType, opCode);
John Kessenich5e4b1242015-08-06 22:53:06 -06001745 for (int op = 0; op < optArgNum; ++op)
1746 textureInst->addIdOperand(texArgs[op]);
1747 if (optArgNum < numArgs)
1748 textureInst->addImmediateOperand(texArgs[optArgNum]);
1749 for (int op = optArgNum + 1; op < numArgs; ++op)
John Kessenich140f3df2015-06-26 16:58:36 -06001750 textureInst->addIdOperand(texArgs[op]);
1751 setPrecision(textureInst->getResultId(), precision);
Andrew Woloszynb7946d12016-01-18 09:23:56 -05001752 buildPoint->addInstruction(std::unique_ptr<Instruction>(textureInst));
John Kessenich140f3df2015-06-26 16:58:36 -06001753
John Kessenich7355eeb2015-09-14 22:08:12 -06001754 Id resultId = textureInst->getResultId();
1755
Rex Xu48edadf2015-12-31 16:11:41 +08001756 if (sparse) {
John Kessenich5e801132016-02-15 11:09:46 -07001757 // set capability
1758 addCapability(CapabilitySparseResidency);
1759
Rex Xu48edadf2015-12-31 16:11:41 +08001760 // Decode the return type that was a special structure
1761 createStore(createCompositeExtract(resultId, typeId1, 1), parameters.texelOut);
1762 resultId = createCompositeExtract(resultId, typeId0, 0);
John Kessenich32cfd492016-02-02 12:37:46 -07001763 setPrecision(resultId, precision);
Rex Xu48edadf2015-12-31 16:11:41 +08001764 } else {
1765 // When a smear is needed, do it, as per what was computed
1766 // above when resultType was changed to a scalar type.
1767 if (resultType != smearedType)
1768 resultId = smearScalar(precision, resultId, smearedType);
1769 }
John Kessenich7355eeb2015-09-14 22:08:12 -06001770
1771 return resultId;
John Kessenich140f3df2015-06-26 16:58:36 -06001772}
1773
1774// Comments in header
steve-lunarg0b5c2ae2017-03-10 12:45:50 -07001775Id Builder::createTextureQueryCall(Op opCode, const TextureParameters& parameters, bool isUnsignedResult)
John Kessenich140f3df2015-06-26 16:58:36 -06001776{
John Kessenich5e801132016-02-15 11:09:46 -07001777 // All these need a capability
1778 addCapability(CapabilityImageQuery);
1779
John Kessenich140f3df2015-06-26 16:58:36 -06001780 // Figure out the result type
John Kessenich5e4b1242015-08-06 22:53:06 -06001781 Id resultType = 0;
John Kessenich140f3df2015-06-26 16:58:36 -06001782 switch (opCode) {
John Kessenich5e4b1242015-08-06 22:53:06 -06001783 case OpImageQuerySize:
1784 case OpImageQuerySizeLod:
John Kessenich140f3df2015-06-26 16:58:36 -06001785 {
Mark Adams364c21c2016-01-06 13:41:02 -05001786 int numComponents = 0;
John Kessenich5e4b1242015-08-06 22:53:06 -06001787 switch (getTypeDimensionality(getImageType(parameters.sampler))) {
John Kessenich140f3df2015-06-26 16:58:36 -06001788 case Dim1D:
1789 case DimBuffer:
1790 numComponents = 1;
1791 break;
1792 case Dim2D:
1793 case DimCube:
1794 case DimRect:
John Kessenich50e57562015-12-21 21:21:11 -07001795 case DimSubpassData:
John Kessenich140f3df2015-06-26 16:58:36 -06001796 numComponents = 2;
1797 break;
1798 case Dim3D:
1799 numComponents = 3;
1800 break;
John Kessenich55e7d112015-11-15 21:33:39 -07001801
John Kessenich140f3df2015-06-26 16:58:36 -06001802 default:
John Kessenich55e7d112015-11-15 21:33:39 -07001803 assert(0);
John Kessenich140f3df2015-06-26 16:58:36 -06001804 break;
1805 }
John Kessenich5e4b1242015-08-06 22:53:06 -06001806 if (isArrayedImageType(getImageType(parameters.sampler)))
John Kessenich140f3df2015-06-26 16:58:36 -06001807 ++numComponents;
steve-lunarg0b5c2ae2017-03-10 12:45:50 -07001808
1809 Id intType = isUnsignedResult ? makeUintType(32) : makeIntType(32);
John Kessenich140f3df2015-06-26 16:58:36 -06001810 if (numComponents == 1)
steve-lunarg0b5c2ae2017-03-10 12:45:50 -07001811 resultType = intType;
John Kessenich140f3df2015-06-26 16:58:36 -06001812 else
steve-lunarg0b5c2ae2017-03-10 12:45:50 -07001813 resultType = makeVectorType(intType, numComponents);
John Kessenich140f3df2015-06-26 16:58:36 -06001814
1815 break;
1816 }
John Kessenich5e4b1242015-08-06 22:53:06 -06001817 case OpImageQueryLod:
Rex Xu1e5d7b02016-11-29 17:36:31 +08001818#ifdef AMD_EXTENSIONS
1819 resultType = makeVectorType(getScalarTypeId(getTypeId(parameters.coords)), 2);
1820#else
John Kessenich140f3df2015-06-26 16:58:36 -06001821 resultType = makeVectorType(makeFloatType(32), 2);
Rex Xu1e5d7b02016-11-29 17:36:31 +08001822#endif
John Kessenich140f3df2015-06-26 16:58:36 -06001823 break;
John Kessenich5e4b1242015-08-06 22:53:06 -06001824 case OpImageQueryLevels:
1825 case OpImageQuerySamples:
steve-lunarg0b5c2ae2017-03-10 12:45:50 -07001826 resultType = isUnsignedResult ? makeUintType(32) : makeIntType(32);
John Kessenich140f3df2015-06-26 16:58:36 -06001827 break;
1828 default:
John Kessenich55e7d112015-11-15 21:33:39 -07001829 assert(0);
1830 break;
John Kessenich140f3df2015-06-26 16:58:36 -06001831 }
1832
1833 Instruction* query = new Instruction(getUniqueId(), resultType, opCode);
1834 query->addIdOperand(parameters.sampler);
1835 if (parameters.coords)
1836 query->addIdOperand(parameters.coords);
1837 if (parameters.lod)
1838 query->addIdOperand(parameters.lod);
Andrew Woloszynb7946d12016-01-18 09:23:56 -05001839 buildPoint->addInstruction(std::unique_ptr<Instruction>(query));
John Kessenich140f3df2015-06-26 16:58:36 -06001840
1841 return query->getResultId();
1842}
1843
John Kessenich22118352015-12-21 20:54:09 -07001844// External comments in header.
1845// Operates recursively to visit the composite's hierarchy.
1846Id Builder::createCompositeCompare(Decoration precision, Id value1, Id value2, bool equal)
John Kessenich140f3df2015-06-26 16:58:36 -06001847{
1848 Id boolType = makeBoolType();
1849 Id valueType = getTypeId(value1);
1850
Mark Adamsd5ac5382016-02-01 19:13:06 -08001851 Id resultId = NoResult;
John Kessenich140f3df2015-06-26 16:58:36 -06001852
John Kessenich22118352015-12-21 20:54:09 -07001853 int numConstituents = getNumTypeConstituents(valueType);
John Kessenich140f3df2015-06-26 16:58:36 -06001854
John Kessenich22118352015-12-21 20:54:09 -07001855 // Scalars and Vectors
1856
1857 if (isScalarType(valueType) || isVectorType(valueType)) {
John Kesseniche23c9842016-01-04 23:49:03 -07001858 assert(valueType == getTypeId(value2));
John Kessenich22118352015-12-21 20:54:09 -07001859 // These just need a single comparison, just have
1860 // to figure out what it is.
John Kessenich140f3df2015-06-26 16:58:36 -06001861 Op op;
John Kessenich22118352015-12-21 20:54:09 -07001862 switch (getMostBasicTypeClass(valueType)) {
1863 case OpTypeFloat:
John Kessenich140f3df2015-06-26 16:58:36 -06001864 op = equal ? OpFOrdEqual : OpFOrdNotEqual;
John Kessenich22118352015-12-21 20:54:09 -07001865 break;
1866 case OpTypeInt:
Mark Adamsd5ac5382016-02-01 19:13:06 -08001867 default:
John Kessenich140f3df2015-06-26 16:58:36 -06001868 op = equal ? OpIEqual : OpINotEqual;
John Kessenich22118352015-12-21 20:54:09 -07001869 break;
1870 case OpTypeBool:
1871 op = equal ? OpLogicalEqual : OpLogicalNotEqual;
1872 precision = NoPrecision;
1873 break;
1874 }
John Kessenich140f3df2015-06-26 16:58:36 -06001875
John Kessenich22118352015-12-21 20:54:09 -07001876 if (isScalarType(valueType)) {
1877 // scalar
1878 resultId = createBinOp(op, boolType, value1, value2);
John Kessenich22118352015-12-21 20:54:09 -07001879 } else {
1880 // vector
1881 resultId = createBinOp(op, makeVectorType(boolType, numConstituents), value1, value2);
1882 setPrecision(resultId, precision);
1883 // reduce vector compares...
1884 resultId = createUnaryOp(equal ? OpAll : OpAny, boolType, resultId);
1885 }
John Kessenich140f3df2015-06-26 16:58:36 -06001886
John Kessenich32cfd492016-02-02 12:37:46 -07001887 return setPrecision(resultId, precision);
John Kessenich140f3df2015-06-26 16:58:36 -06001888 }
1889
John Kessenich22118352015-12-21 20:54:09 -07001890 // Only structs, arrays, and matrices should be left.
1891 // They share in common the reduction operation across their constituents.
1892 assert(isAggregateType(valueType) || isMatrixType(valueType));
John Kessenich140f3df2015-06-26 16:58:36 -06001893
John Kessenich22118352015-12-21 20:54:09 -07001894 // Compare each pair of constituents
1895 for (int constituent = 0; constituent < numConstituents; ++constituent) {
1896 std::vector<unsigned> indexes(1, constituent);
John Kesseniche23c9842016-01-04 23:49:03 -07001897 Id constituentType1 = getContainedTypeId(getTypeId(value1), constituent);
1898 Id constituentType2 = getContainedTypeId(getTypeId(value2), constituent);
1899 Id constituent1 = createCompositeExtract(value1, constituentType1, indexes);
1900 Id constituent2 = createCompositeExtract(value2, constituentType2, indexes);
John Kessenich140f3df2015-06-26 16:58:36 -06001901
John Kessenich22118352015-12-21 20:54:09 -07001902 Id subResultId = createCompositeCompare(precision, constituent1, constituent2, equal);
John Kessenich140f3df2015-06-26 16:58:36 -06001903
John Kessenich22118352015-12-21 20:54:09 -07001904 if (constituent == 0)
1905 resultId = subResultId;
1906 else
John Kessenich32cfd492016-02-02 12:37:46 -07001907 resultId = setPrecision(createBinOp(equal ? OpLogicalAnd : OpLogicalOr, boolType, resultId, subResultId), precision);
John Kessenich22118352015-12-21 20:54:09 -07001908 }
John Kessenich140f3df2015-06-26 16:58:36 -06001909
John Kessenich22118352015-12-21 20:54:09 -07001910 return resultId;
John Kessenich140f3df2015-06-26 16:58:36 -06001911}
1912
John Kessenich140f3df2015-06-26 16:58:36 -06001913// OpCompositeConstruct
Vlad Ivanov689490f2017-01-26 20:46:02 +03001914Id Builder::createCompositeConstruct(Id typeId, const std::vector<Id>& constituents)
John Kessenich140f3df2015-06-26 16:58:36 -06001915{
John Kessenich22118352015-12-21 20:54:09 -07001916 assert(isAggregateType(typeId) || (getNumTypeConstituents(typeId) > 1 && getNumTypeConstituents(typeId) == (int)constituents.size()));
John Kessenich140f3df2015-06-26 16:58:36 -06001917
qining27e04a02016-04-14 16:40:20 -04001918 if (generatingOpCodeForSpecConst) {
qining1f2820a2016-04-14 18:34:27 -04001919 // Sometime, even in spec-constant-op mode, the constant composite to be
1920 // constructed may not be a specialization constant.
1921 // e.g.:
1922 // const mat2 m2 = mat2(a_spec_const, a_front_end_const, another_front_end_const, third_front_end_const);
1923 // The first column vector should be a spec constant one, as a_spec_const is a spec constant.
1924 // The second column vector should NOT be spec constant, as it does not contain any spec constants.
1925 // To handle such cases, we check the constituents of the constant vector to determine whether this
1926 // vector should be created as a spec constant.
1927 return makeCompositeConstant(typeId, constituents,
1928 std::any_of(constituents.begin(), constituents.end(),
1929 [&](spv::Id id) { return isSpecConstant(id); }));
qining27e04a02016-04-14 16:40:20 -04001930 }
1931
John Kessenich140f3df2015-06-26 16:58:36 -06001932 Instruction* op = new Instruction(getUniqueId(), typeId, OpCompositeConstruct);
1933 for (int c = 0; c < (int)constituents.size(); ++c)
1934 op->addIdOperand(constituents[c]);
Andrew Woloszynb7946d12016-01-18 09:23:56 -05001935 buildPoint->addInstruction(std::unique_ptr<Instruction>(op));
John Kessenich140f3df2015-06-26 16:58:36 -06001936
1937 return op->getResultId();
1938}
1939
1940// Vector or scalar constructor
1941Id Builder::createConstructor(Decoration precision, const std::vector<Id>& sources, Id resultTypeId)
1942{
John Kessenich32cfd492016-02-02 12:37:46 -07001943 Id result = NoResult;
John Kessenich140f3df2015-06-26 16:58:36 -06001944 unsigned int numTargetComponents = getNumTypeComponents(resultTypeId);
1945 unsigned int targetComponent = 0;
1946
1947 // Special case: when calling a vector constructor with a single scalar
1948 // argument, smear the scalar
1949 if (sources.size() == 1 && isScalar(sources[0]) && numTargetComponents > 1)
1950 return smearScalar(precision, sources[0], resultTypeId);
1951
John Kessenich0302bdf2017-02-17 19:06:21 -07001952 // accumulate the arguments for OpCompositeConstruct
1953 std::vector<Id> constituents;
John Kessenich140f3df2015-06-26 16:58:36 -06001954 Id scalarTypeId = getScalarTypeId(resultTypeId);
John Kessenich0302bdf2017-02-17 19:06:21 -07001955
1956 // lambda to store the result of visiting an argument component
1957 const auto latchResult = [&](Id comp) {
1958 if (numTargetComponents > 1)
1959 constituents.push_back(comp);
1960 else
1961 result = comp;
1962 ++targetComponent;
1963 };
1964
1965 // lambda to visit a vector argument's components
1966 const auto accumulateVectorConstituents = [&](Id sourceArg) {
1967 unsigned int sourceSize = getNumComponents(sourceArg);
John Kessenich140f3df2015-06-26 16:58:36 -06001968 unsigned int sourcesToUse = sourceSize;
1969 if (sourcesToUse + targetComponent > numTargetComponents)
1970 sourcesToUse = numTargetComponents - targetComponent;
1971
1972 for (unsigned int s = 0; s < sourcesToUse; ++s) {
John Kessenich0302bdf2017-02-17 19:06:21 -07001973 std::vector<unsigned> swiz;
1974 swiz.push_back(s);
1975 latchResult(createRvalueSwizzle(precision, scalarTypeId, sourceArg, swiz));
John Kessenich140f3df2015-06-26 16:58:36 -06001976 }
John Kessenich0302bdf2017-02-17 19:06:21 -07001977 };
1978
1979 // lambda to visit a matrix argument's components
1980 const auto accumulateMatrixConstituents = [&](Id sourceArg) {
1981 unsigned int sourceSize = getNumColumns(sourceArg) * getNumRows(sourceArg);
1982 unsigned int sourcesToUse = sourceSize;
1983 if (sourcesToUse + targetComponent > numTargetComponents)
1984 sourcesToUse = numTargetComponents - targetComponent;
1985
1986 int col = 0;
1987 int row = 0;
1988 for (unsigned int s = 0; s < sourcesToUse; ++s) {
1989 if (row >= getNumRows(sourceArg)) {
1990 row = 0;
1991 col++;
1992 }
1993 std::vector<Id> indexes;
1994 indexes.push_back(col);
1995 indexes.push_back(row);
1996 latchResult(createCompositeExtract(sourceArg, scalarTypeId, indexes));
1997 row++;
1998 }
1999 };
2000
2001 // Go through the source arguments, each one could have either
2002 // a single or multiple components to contribute.
2003 for (unsigned int i = 0; i < sources.size(); ++i) {
2004 if (isScalar(sources[i]))
2005 latchResult(sources[i]);
2006 else if (isVector(sources[i]))
2007 accumulateVectorConstituents(sources[i]);
2008 else if (isMatrix(sources[i]))
2009 accumulateMatrixConstituents(sources[i]);
2010 else
2011 assert(0);
John Kessenich140f3df2015-06-26 16:58:36 -06002012
2013 if (targetComponent >= numTargetComponents)
2014 break;
2015 }
2016
John Kessenich0302bdf2017-02-17 19:06:21 -07002017 // If the result is a vector, make it from the gathered constituents.
John Kessenich140f3df2015-06-26 16:58:36 -06002018 if (constituents.size() > 0)
2019 result = createCompositeConstruct(resultTypeId, constituents);
2020
John Kessenich32cfd492016-02-02 12:37:46 -07002021 return setPrecision(result, precision);
John Kessenich140f3df2015-06-26 16:58:36 -06002022}
2023
2024// Comments in header
2025Id Builder::createMatrixConstructor(Decoration precision, const std::vector<Id>& sources, Id resultTypeId)
2026{
2027 Id componentTypeId = getScalarTypeId(resultTypeId);
2028 int numCols = getTypeNumColumns(resultTypeId);
2029 int numRows = getTypeNumRows(resultTypeId);
2030
iostrowsaf7f1c82016-06-01 16:40:00 +02002031 Instruction* instr = module.getInstruction(componentTypeId);
2032 Id bitCount = instr->getIdOperand(0);
2033
John Kessenich140f3df2015-06-26 16:58:36 -06002034 // Will use a two step process
2035 // 1. make a compile-time 2D array of values
2036 // 2. construct a matrix from that array
2037
2038 // Step 1.
2039
2040 // initialize the array to the identity matrix
2041 Id ids[maxMatrixSize][maxMatrixSize];
iostrowsaf7f1c82016-06-01 16:40:00 +02002042 Id one = (bitCount == 64 ? makeDoubleConstant(1.0) : makeFloatConstant(1.0));
2043 Id zero = (bitCount == 64 ? makeDoubleConstant(0.0) : makeFloatConstant(0.0));
John Kessenich140f3df2015-06-26 16:58:36 -06002044 for (int col = 0; col < 4; ++col) {
2045 for (int row = 0; row < 4; ++row) {
2046 if (col == row)
2047 ids[col][row] = one;
2048 else
2049 ids[col][row] = zero;
2050 }
2051 }
2052
2053 // modify components as dictated by the arguments
2054 if (sources.size() == 1 && isScalar(sources[0])) {
2055 // a single scalar; resets the diagonals
2056 for (int col = 0; col < 4; ++col)
2057 ids[col][col] = sources[0];
2058 } else if (isMatrix(sources[0])) {
2059 // constructing from another matrix; copy over the parts that exist in both the argument and constructee
2060 Id matrix = sources[0];
2061 int minCols = std::min(numCols, getNumColumns(matrix));
2062 int minRows = std::min(numRows, getNumRows(matrix));
2063 for (int col = 0; col < minCols; ++col) {
2064 std::vector<unsigned> indexes;
2065 indexes.push_back(col);
2066 for (int row = 0; row < minRows; ++row) {
2067 indexes.push_back(row);
2068 ids[col][row] = createCompositeExtract(matrix, componentTypeId, indexes);
2069 indexes.pop_back();
2070 setPrecision(ids[col][row], precision);
2071 }
2072 }
2073 } else {
2074 // fill in the matrix in column-major order with whatever argument components are available
2075 int row = 0;
2076 int col = 0;
2077
2078 for (int arg = 0; arg < (int)sources.size(); ++arg) {
2079 Id argComp = sources[arg];
2080 for (int comp = 0; comp < getNumComponents(sources[arg]); ++comp) {
2081 if (getNumComponents(sources[arg]) > 1) {
2082 argComp = createCompositeExtract(sources[arg], componentTypeId, comp);
2083 setPrecision(argComp, precision);
2084 }
2085 ids[col][row++] = argComp;
2086 if (row == numRows) {
2087 row = 0;
2088 col++;
2089 }
2090 }
2091 }
2092 }
2093
John Kessenich140f3df2015-06-26 16:58:36 -06002094 // Step 2: Construct a matrix from that array.
2095 // First make the column vectors, then make the matrix.
2096
2097 // make the column vectors
2098 Id columnTypeId = getContainedTypeId(resultTypeId);
2099 std::vector<Id> matrixColumns;
2100 for (int col = 0; col < numCols; ++col) {
2101 std::vector<Id> vectorComponents;
2102 for (int row = 0; row < numRows; ++row)
2103 vectorComponents.push_back(ids[col][row]);
John Kessenich32cfd492016-02-02 12:37:46 -07002104 Id column = createCompositeConstruct(columnTypeId, vectorComponents);
2105 setPrecision(column, precision);
2106 matrixColumns.push_back(column);
John Kessenich140f3df2015-06-26 16:58:36 -06002107 }
2108
2109 // make the matrix
John Kessenich32cfd492016-02-02 12:37:46 -07002110 return setPrecision(createCompositeConstruct(resultTypeId, matrixColumns), precision);
John Kessenich140f3df2015-06-26 16:58:36 -06002111}
2112
2113// Comments in header
Rex Xu57e65922017-07-04 23:23:40 +08002114Builder::If::If(Id cond, unsigned int ctrl, Builder& gb) :
John Kessenich140f3df2015-06-26 16:58:36 -06002115 builder(gb),
2116 condition(cond),
Rex Xu57e65922017-07-04 23:23:40 +08002117 control(ctrl),
John Kessenich140f3df2015-06-26 16:58:36 -06002118 elseBlock(0)
2119{
2120 function = &builder.getBuildPoint()->getParent();
2121
2122 // make the blocks, but only put the then-block into the function,
2123 // the else-block and merge-block will be added later, in order, after
2124 // earlier code is emitted
2125 thenBlock = new Block(builder.getUniqueId(), *function);
2126 mergeBlock = new Block(builder.getUniqueId(), *function);
2127
2128 // Save the current block, so that we can add in the flow control split when
2129 // makeEndIf is called.
2130 headerBlock = builder.getBuildPoint();
2131
2132 function->addBlock(thenBlock);
2133 builder.setBuildPoint(thenBlock);
2134}
2135
2136// Comments in header
2137void Builder::If::makeBeginElse()
2138{
2139 // Close out the "then" by having it jump to the mergeBlock
2140 builder.createBranch(mergeBlock);
2141
2142 // Make the first else block and add it to the function
2143 elseBlock = new Block(builder.getUniqueId(), *function);
2144 function->addBlock(elseBlock);
2145
2146 // Start building the else block
2147 builder.setBuildPoint(elseBlock);
2148}
2149
2150// Comments in header
2151void Builder::If::makeEndIf()
2152{
2153 // jump to the merge block
2154 builder.createBranch(mergeBlock);
2155
2156 // Go back to the headerBlock and make the flow control split
2157 builder.setBuildPoint(headerBlock);
Rex Xu57e65922017-07-04 23:23:40 +08002158 builder.createSelectionMerge(mergeBlock, control);
John Kessenich140f3df2015-06-26 16:58:36 -06002159 if (elseBlock)
2160 builder.createConditionalBranch(condition, thenBlock, elseBlock);
2161 else
2162 builder.createConditionalBranch(condition, thenBlock, mergeBlock);
2163
2164 // add the merge block to the function
2165 function->addBlock(mergeBlock);
2166 builder.setBuildPoint(mergeBlock);
2167}
2168
2169// Comments in header
Rex Xu57e65922017-07-04 23:23:40 +08002170void Builder::makeSwitch(Id selector, unsigned int control, int numSegments, const std::vector<int>& caseValues,
Vlad Ivanov689490f2017-01-26 20:46:02 +03002171 const std::vector<int>& valueIndexToSegment, int defaultSegment,
John Kessenich140f3df2015-06-26 16:58:36 -06002172 std::vector<Block*>& segmentBlocks)
2173{
2174 Function& function = buildPoint->getParent();
2175
2176 // make all the blocks
2177 for (int s = 0; s < numSegments; ++s)
2178 segmentBlocks.push_back(new Block(getUniqueId(), function));
2179
2180 Block* mergeBlock = new Block(getUniqueId(), function);
2181
2182 // make and insert the switch's selection-merge instruction
Rex Xu57e65922017-07-04 23:23:40 +08002183 createSelectionMerge(mergeBlock, control);
John Kessenich140f3df2015-06-26 16:58:36 -06002184
2185 // make the switch instruction
2186 Instruction* switchInst = new Instruction(NoResult, NoType, OpSwitch);
2187 switchInst->addIdOperand(selector);
Dejan Mircevski454796e2016-01-18 16:18:01 -05002188 auto defaultOrMerge = (defaultSegment >= 0) ? segmentBlocks[defaultSegment] : mergeBlock;
2189 switchInst->addIdOperand(defaultOrMerge->getId());
2190 defaultOrMerge->addPredecessor(buildPoint);
John Kessenich140f3df2015-06-26 16:58:36 -06002191 for (int i = 0; i < (int)caseValues.size(); ++i) {
2192 switchInst->addImmediateOperand(caseValues[i]);
2193 switchInst->addIdOperand(segmentBlocks[valueIndexToSegment[i]]->getId());
Dejan Mircevski454796e2016-01-18 16:18:01 -05002194 segmentBlocks[valueIndexToSegment[i]]->addPredecessor(buildPoint);
John Kessenich140f3df2015-06-26 16:58:36 -06002195 }
Andrew Woloszynb7946d12016-01-18 09:23:56 -05002196 buildPoint->addInstruction(std::unique_ptr<Instruction>(switchInst));
John Kessenich140f3df2015-06-26 16:58:36 -06002197
2198 // push the merge block
2199 switchMerges.push(mergeBlock);
2200}
2201
2202// Comments in header
2203void Builder::addSwitchBreak()
2204{
2205 // branch to the top of the merge block stack
2206 createBranch(switchMerges.top());
2207 createAndSetNoPredecessorBlock("post-switch-break");
2208}
2209
2210// Comments in header
2211void Builder::nextSwitchSegment(std::vector<Block*>& segmentBlock, int nextSegment)
2212{
2213 int lastSegment = nextSegment - 1;
2214 if (lastSegment >= 0) {
2215 // Close out previous segment by jumping, if necessary, to next segment
2216 if (! buildPoint->isTerminated())
2217 createBranch(segmentBlock[nextSegment]);
2218 }
2219 Block* block = segmentBlock[nextSegment];
2220 block->getParent().addBlock(block);
2221 setBuildPoint(block);
2222}
2223
2224// Comments in header
2225void Builder::endSwitch(std::vector<Block*>& /*segmentBlock*/)
2226{
2227 // Close out previous segment by jumping, if necessary, to next segment
2228 if (! buildPoint->isTerminated())
2229 addSwitchBreak();
2230
2231 switchMerges.top()->getParent().addBlock(switchMerges.top());
2232 setBuildPoint(switchMerges.top());
2233
2234 switchMerges.pop();
2235}
2236
Dejan Mircevski9c6734c2016-01-10 12:15:13 -05002237Block& Builder::makeNewBlock()
2238{
2239 Function& function = buildPoint->getParent();
2240 auto block = new Block(getUniqueId(), function);
2241 function.addBlock(block);
2242 return *block;
2243}
2244
Dejan Mircevski7819bee2016-01-11 09:35:22 -05002245Builder::LoopBlocks& Builder::makeNewLoop()
Dejan Mircevski9c6734c2016-01-10 12:15:13 -05002246{
John Kessenich7f349c72016-07-08 22:09:10 -06002247 // This verbosity is needed to simultaneously get the same behavior
2248 // everywhere (id's in the same order), have a syntax that works
2249 // across lots of versions of C++, have no warnings from pedantic
2250 // compilation modes, and leave the rest of the code alone.
2251 Block& head = makeNewBlock();
2252 Block& body = makeNewBlock();
2253 Block& merge = makeNewBlock();
2254 Block& continue_target = makeNewBlock();
2255 LoopBlocks blocks(head, body, merge, continue_target);
Dejan Mircevski97605c82016-01-20 10:19:25 -05002256 loops.push(blocks);
Dejan Mircevski7819bee2016-01-11 09:35:22 -05002257 return loops.top();
John Kessenich140f3df2015-06-26 16:58:36 -06002258}
2259
2260void Builder::createLoopContinue()
2261{
Dejan Mircevski7819bee2016-01-11 09:35:22 -05002262 createBranch(&loops.top().continue_target);
John Kessenich140f3df2015-06-26 16:58:36 -06002263 // Set up a block for dead code.
2264 createAndSetNoPredecessorBlock("post-loop-continue");
2265}
2266
John Kessenich140f3df2015-06-26 16:58:36 -06002267void Builder::createLoopExit()
2268{
Dejan Mircevski7819bee2016-01-11 09:35:22 -05002269 createBranch(&loops.top().merge);
John Kessenich140f3df2015-06-26 16:58:36 -06002270 // Set up a block for dead code.
2271 createAndSetNoPredecessorBlock("post-loop-break");
2272}
2273
John Kessenich140f3df2015-06-26 16:58:36 -06002274void Builder::closeLoop()
2275{
John Kessenich140f3df2015-06-26 16:58:36 -06002276 loops.pop();
2277}
2278
2279void Builder::clearAccessChain()
2280{
John Kessenichfa668da2015-09-13 14:46:30 -06002281 accessChain.base = NoResult;
John Kessenich140f3df2015-06-26 16:58:36 -06002282 accessChain.indexChain.clear();
John Kessenichfa668da2015-09-13 14:46:30 -06002283 accessChain.instr = NoResult;
John Kessenich140f3df2015-06-26 16:58:36 -06002284 accessChain.swizzle.clear();
John Kessenichfa668da2015-09-13 14:46:30 -06002285 accessChain.component = NoResult;
2286 accessChain.preSwizzleBaseType = NoType;
John Kessenich140f3df2015-06-26 16:58:36 -06002287 accessChain.isRValue = false;
2288}
2289
2290// Comments in header
John Kessenichfa668da2015-09-13 14:46:30 -06002291void Builder::accessChainPushSwizzle(std::vector<unsigned>& swizzle, Id preSwizzleBaseType)
John Kessenich140f3df2015-06-26 16:58:36 -06002292{
John Kessenichfa668da2015-09-13 14:46:30 -06002293 // swizzles can be stacked in GLSL, but simplified to a single
2294 // one here; the base type doesn't change
2295 if (accessChain.preSwizzleBaseType == NoType)
2296 accessChain.preSwizzleBaseType = preSwizzleBaseType;
2297
John Kessenich140f3df2015-06-26 16:58:36 -06002298 // if needed, propagate the swizzle for the current access chain
John Kessenich5c3eed52018-02-05 14:44:14 -07002299 if (accessChain.swizzle.size() > 0) {
John Kessenich140f3df2015-06-26 16:58:36 -06002300 std::vector<unsigned> oldSwizzle = accessChain.swizzle;
2301 accessChain.swizzle.resize(0);
2302 for (unsigned int i = 0; i < swizzle.size(); ++i) {
John Kessenich1e275c82016-12-14 17:02:32 -07002303 assert(swizzle[i] < oldSwizzle.size());
John Kessenich140f3df2015-06-26 16:58:36 -06002304 accessChain.swizzle.push_back(oldSwizzle[swizzle[i]]);
2305 }
2306 } else
2307 accessChain.swizzle = swizzle;
2308
2309 // determine if we need to track this swizzle anymore
2310 simplifyAccessChainSwizzle();
2311}
2312
2313// Comments in header
2314void Builder::accessChainStore(Id rvalue)
2315{
2316 assert(accessChain.isRValue == false);
2317
John Kessenich55e7d112015-11-15 21:33:39 -07002318 transferAccessChainSwizzle(true);
John Kessenich140f3df2015-06-26 16:58:36 -06002319 Id base = collapseAccessChain();
John Kessenich5c3eed52018-02-05 14:44:14 -07002320 Id source = rvalue;
2321
2322 // dynamic component should be gone
2323 assert(accessChain.component == NoResult);
John Kessenich140f3df2015-06-26 16:58:36 -06002324
John Kessenich55e7d112015-11-15 21:33:39 -07002325 // If swizzle still exists, it is out-of-order or not full, we must load the target vector,
John Kessenich140f3df2015-06-26 16:58:36 -06002326 // extract and insert elements to perform writeMask and/or swizzle.
John Kessenich5c3eed52018-02-05 14:44:14 -07002327 if (accessChain.swizzle.size() > 0) {
John Kessenich140f3df2015-06-26 16:58:36 -06002328 Id tempBaseId = createLoad(base);
John Kessenich5c3eed52018-02-05 14:44:14 -07002329 source = createLvalueSwizzle(getTypeId(tempBaseId), tempBaseId, source, accessChain.swizzle);
John Kessenich140f3df2015-06-26 16:58:36 -06002330 }
2331
John Kessenich140f3df2015-06-26 16:58:36 -06002332 createStore(source, base);
2333}
2334
2335// Comments in header
John Kessenich5611c6d2018-04-05 11:25:02 -06002336Id Builder::accessChainLoad(Decoration precision, Decoration nonUniform, Id resultType)
John Kessenich140f3df2015-06-26 16:58:36 -06002337{
2338 Id id;
2339
2340 if (accessChain.isRValue) {
John Kessenich5c3eed52018-02-05 14:44:14 -07002341 // transfer access chain, but try to stay in registers
John Kessenich55e7d112015-11-15 21:33:39 -07002342 transferAccessChainSwizzle(false);
John Kessenich140f3df2015-06-26 16:58:36 -06002343 if (accessChain.indexChain.size() > 0) {
John Kessenichfa668da2015-09-13 14:46:30 -06002344 Id swizzleBase = accessChain.preSwizzleBaseType != NoType ? accessChain.preSwizzleBaseType : resultType;
John Kessenich32cfd492016-02-02 12:37:46 -07002345
John Kessenich140f3df2015-06-26 16:58:36 -06002346 // if all the accesses are constants, we can use OpCompositeExtract
2347 std::vector<unsigned> indexes;
2348 bool constant = true;
2349 for (int i = 0; i < (int)accessChain.indexChain.size(); ++i) {
2350 if (isConstantScalar(accessChain.indexChain[i]))
2351 indexes.push_back(getConstantScalar(accessChain.indexChain[i]));
2352 else {
2353 constant = false;
2354 break;
2355 }
2356 }
2357
2358 if (constant)
John Kessenichfa668da2015-09-13 14:46:30 -06002359 id = createCompositeExtract(accessChain.base, swizzleBase, indexes);
John Kessenich140f3df2015-06-26 16:58:36 -06002360 else {
2361 // make a new function variable for this r-value
2362 Id lValue = createVariable(StorageClassFunction, getTypeId(accessChain.base), "indexable");
2363
2364 // store into it
2365 createStore(accessChain.base, lValue);
2366
2367 // move base to the new variable
2368 accessChain.base = lValue;
2369 accessChain.isRValue = false;
2370
2371 // load through the access chain
2372 id = createLoad(collapseAccessChain());
2373 }
John Kessenich32cfd492016-02-02 12:37:46 -07002374 setPrecision(id, precision);
John Kessenich140f3df2015-06-26 16:58:36 -06002375 } else
John Kessenich32cfd492016-02-02 12:37:46 -07002376 id = accessChain.base; // no precision, it was set when this was defined
John Kessenich140f3df2015-06-26 16:58:36 -06002377 } else {
John Kessenich55e7d112015-11-15 21:33:39 -07002378 transferAccessChainSwizzle(true);
John Kessenich140f3df2015-06-26 16:58:36 -06002379 // load through the access chain
2380 id = createLoad(collapseAccessChain());
John Kessenich32cfd492016-02-02 12:37:46 -07002381 setPrecision(id, precision);
John Kessenich5611c6d2018-04-05 11:25:02 -06002382 addDecoration(id, nonUniform);
John Kessenich140f3df2015-06-26 16:58:36 -06002383 }
2384
2385 // Done, unless there are swizzles to do
John Kessenichfa668da2015-09-13 14:46:30 -06002386 if (accessChain.swizzle.size() == 0 && accessChain.component == NoResult)
John Kessenich140f3df2015-06-26 16:58:36 -06002387 return id;
2388
John Kessenich140f3df2015-06-26 16:58:36 -06002389 // Do remaining swizzling
John Kessenich5c3eed52018-02-05 14:44:14 -07002390
2391 // Do the basic swizzle
2392 if (accessChain.swizzle.size() > 0) {
John Kessenichfa668da2015-09-13 14:46:30 -06002393 Id swizzledType = getScalarTypeId(getTypeId(id));
John Kessenich140f3df2015-06-26 16:58:36 -06002394 if (accessChain.swizzle.size() > 1)
John Kessenichfa668da2015-09-13 14:46:30 -06002395 swizzledType = makeVectorType(swizzledType, (int)accessChain.swizzle.size());
John Kessenich32cfd492016-02-02 12:37:46 -07002396 id = createRvalueSwizzle(precision, swizzledType, id, accessChain.swizzle);
John Kessenich140f3df2015-06-26 16:58:36 -06002397 }
2398
John Kessenich5c3eed52018-02-05 14:44:14 -07002399 // Do the dynamic component
John Kessenichfa668da2015-09-13 14:46:30 -06002400 if (accessChain.component != NoResult)
John Kessenich32cfd492016-02-02 12:37:46 -07002401 id = setPrecision(createVectorExtractDynamic(id, resultType, accessChain.component), precision);
John Kessenich140f3df2015-06-26 16:58:36 -06002402
John Kessenich5611c6d2018-04-05 11:25:02 -06002403 addDecoration(id, nonUniform);
John Kessenich140f3df2015-06-26 16:58:36 -06002404 return id;
2405}
2406
2407Id Builder::accessChainGetLValue()
2408{
2409 assert(accessChain.isRValue == false);
2410
John Kessenich55e7d112015-11-15 21:33:39 -07002411 transferAccessChainSwizzle(true);
John Kessenich140f3df2015-06-26 16:58:36 -06002412 Id lvalue = collapseAccessChain();
2413
2414 // If swizzle exists, it is out-of-order or not full, we must load the target vector,
2415 // extract and insert elements to perform writeMask and/or swizzle. This does not
2416 // go with getting a direct l-value pointer.
2417 assert(accessChain.swizzle.size() == 0);
John Kessenichfa668da2015-09-13 14:46:30 -06002418 assert(accessChain.component == NoResult);
John Kessenich140f3df2015-06-26 16:58:36 -06002419
2420 return lvalue;
2421}
2422
John Kessenich103bef92016-02-08 21:38:15 -07002423// comment in header
2424Id Builder::accessChainGetInferredType()
2425{
2426 // anything to operate on?
2427 if (accessChain.base == NoResult)
2428 return NoType;
2429 Id type = getTypeId(accessChain.base);
2430
2431 // do initial dereference
2432 if (! accessChain.isRValue)
2433 type = getContainedTypeId(type);
2434
2435 // dereference each index
rdb32084e82016-02-23 22:17:38 +01002436 for (auto it = accessChain.indexChain.cbegin(); it != accessChain.indexChain.cend(); ++it) {
John Kessenich103bef92016-02-08 21:38:15 -07002437 if (isStructType(type))
rdb32084e82016-02-23 22:17:38 +01002438 type = getContainedTypeId(type, getConstantScalar(*it));
John Kessenich103bef92016-02-08 21:38:15 -07002439 else
2440 type = getContainedTypeId(type);
2441 }
2442
2443 // dereference swizzle
2444 if (accessChain.swizzle.size() == 1)
2445 type = getContainedTypeId(type);
2446 else if (accessChain.swizzle.size() > 1)
baldurk227e0262016-02-10 19:41:29 +01002447 type = makeVectorType(getContainedTypeId(type), (int)accessChain.swizzle.size());
John Kessenich103bef92016-02-08 21:38:15 -07002448
2449 // dereference component selection
2450 if (accessChain.component)
2451 type = getContainedTypeId(type);
2452
2453 return type;
2454}
2455
qiningda397332016-03-09 19:54:03 -05002456// comment in header
2457void Builder::eliminateDeadDecorations() {
2458 std::unordered_set<const Block*> reachable_blocks;
2459 std::unordered_set<Id> unreachable_definitions;
2460 // Collect IDs defined in unreachable blocks. For each function, label the
2461 // reachable blocks first. Then for each unreachable block, collect the
2462 // result IDs of the instructions in it.
qining95aa5272016-03-09 21:40:41 -05002463 for (std::vector<Function*>::const_iterator fi = module.getFunctions().cbegin();
2464 fi != module.getFunctions().cend(); fi++) {
2465 Function* f = *fi;
qiningda397332016-03-09 19:54:03 -05002466 Block* entry = f->getEntryBlock();
2467 inReadableOrder(entry, [&reachable_blocks](const Block* b) {
2468 reachable_blocks.insert(b);
2469 });
qining95aa5272016-03-09 21:40:41 -05002470 for (std::vector<Block*>::const_iterator bi = f->getBlocks().cbegin();
2471 bi != f->getBlocks().cend(); bi++) {
2472 Block* b = *bi;
qiningda397332016-03-09 19:54:03 -05002473 if (!reachable_blocks.count(b)) {
qining95aa5272016-03-09 21:40:41 -05002474 for (std::vector<std::unique_ptr<Instruction> >::const_iterator
2475 ii = b->getInstructions().cbegin();
2476 ii != b->getInstructions().cend(); ii++) {
2477 Instruction* i = ii->get();
qiningda397332016-03-09 19:54:03 -05002478 unreachable_definitions.insert(i->getResultId());
2479 }
2480 }
2481 }
2482 }
2483 decorations.erase(std::remove_if(decorations.begin(), decorations.end(),
baldurkbd9f8352016-04-02 13:38:42 +02002484 [&unreachable_definitions](std::unique_ptr<Instruction>& I) -> bool {
qiningda397332016-03-09 19:54:03 -05002485 Instruction* inst = I.get();
2486 Id decoration_id = inst->getIdOperand(0);
2487 return unreachable_definitions.count(decoration_id) != 0;
2488 }),
2489 decorations.end());
2490}
2491
John Kessenich140f3df2015-06-26 16:58:36 -06002492void Builder::dump(std::vector<unsigned int>& out) const
2493{
2494 // Header, before first instructions:
2495 out.push_back(MagicNumber);
John Kessenich2b5ea9f2018-01-31 18:35:56 -07002496 out.push_back(spvVersion);
John Kessenich140f3df2015-06-26 16:58:36 -06002497 out.push_back(builderNumber);
2498 out.push_back(uniqueId + 1);
2499 out.push_back(0);
2500
John Kessenich55e7d112015-11-15 21:33:39 -07002501 // Capabilities
rdb32084e82016-02-23 22:17:38 +01002502 for (auto it = capabilities.cbegin(); it != capabilities.cend(); ++it) {
John Kessenich55e7d112015-11-15 21:33:39 -07002503 Instruction capInst(0, 0, OpCapability);
rdb32084e82016-02-23 22:17:38 +01002504 capInst.addImmediateOperand(*it);
John Kessenich55e7d112015-11-15 21:33:39 -07002505 capInst.dump(out);
2506 }
2507
Rex Xu51596642016-09-21 18:56:12 +08002508 for (auto it = extensions.cbegin(); it != extensions.cend(); ++it) {
Rex Xu9d93a232016-05-05 12:30:44 +08002509 Instruction extInst(0, 0, OpExtension);
Rex Xu430ef402016-10-14 17:22:23 +08002510 extInst.addStringOperand(it->c_str());
Rex Xu9d93a232016-05-05 12:30:44 +08002511 extInst.dump(out);
2512 }
John Kessenich55e7d112015-11-15 21:33:39 -07002513
2514 dumpInstructions(out, imports);
2515 Instruction memInst(0, 0, OpMemoryModel);
2516 memInst.addImmediateOperand(addressModel);
2517 memInst.addImmediateOperand(memoryModel);
2518 memInst.dump(out);
2519
2520 // Instructions saved up while building:
2521 dumpInstructions(out, entryPoints);
2522 dumpInstructions(out, executionModes);
2523
2524 // Debug instructions
John Kessenich121853f2017-05-31 17:11:16 -06002525 dumpInstructions(out, strings);
2526 dumpSourceInstructions(out);
Rex Xu9d93a232016-05-05 12:30:44 +08002527 for (int e = 0; e < (int)sourceExtensions.size(); ++e) {
2528 Instruction sourceExtInst(0, 0, OpSourceExtension);
2529 sourceExtInst.addStringOperand(sourceExtensions[e]);
2530 sourceExtInst.dump(out);
John Kessenich140f3df2015-06-26 16:58:36 -06002531 }
John Kessenich140f3df2015-06-26 16:58:36 -06002532 dumpInstructions(out, names);
John Kessenich57f6a012018-02-22 19:36:18 -07002533 dumpModuleProcesses(out);
John Kessenich55e7d112015-11-15 21:33:39 -07002534
2535 // Annotation instructions
John Kessenich140f3df2015-06-26 16:58:36 -06002536 dumpInstructions(out, decorations);
John Kessenich55e7d112015-11-15 21:33:39 -07002537
John Kessenich140f3df2015-06-26 16:58:36 -06002538 dumpInstructions(out, constantsTypesGlobals);
2539 dumpInstructions(out, externals);
2540
2541 // The functions
2542 module.dump(out);
2543}
2544
2545//
2546// Protected methods.
2547//
2548
John Kessenich5c3eed52018-02-05 14:44:14 -07002549// Turn the described access chain in 'accessChain' into an instruction(s)
John Kessenich55e7d112015-11-15 21:33:39 -07002550// computing its address. This *cannot* include complex swizzles, which must
John Kessenich5c3eed52018-02-05 14:44:14 -07002551// be handled after this is called.
2552//
2553// Can generate code.
John Kessenich140f3df2015-06-26 16:58:36 -06002554Id Builder::collapseAccessChain()
2555{
John Kessenich140f3df2015-06-26 16:58:36 -06002556 assert(accessChain.isRValue == false);
2557
John Kessenich5c3eed52018-02-05 14:44:14 -07002558 // did we already emit an access chain for this?
2559 if (accessChain.instr != NoResult)
John Kessenich140f3df2015-06-26 16:58:36 -06002560 return accessChain.instr;
John Kessenich5c3eed52018-02-05 14:44:14 -07002561
2562 // If we have a dynamic component, we can still transfer
2563 // that into a final operand to the access chain. We need to remap the
2564 // dynamic component through the swizzle to get a new dynamic component to
2565 // update.
2566 //
2567 // This was not done in transferAccessChainSwizzle() because it might
2568 // generate code.
2569 remapDynamicSwizzle();
2570 if (accessChain.component != NoResult) {
2571 // transfer the dynamic component to the access chain
2572 accessChain.indexChain.push_back(accessChain.component);
2573 accessChain.component = NoResult;
2574 }
2575
2576 // note that non-trivial swizzling is left pending
2577
2578 // do we have an access chain?
2579 if (accessChain.indexChain.size() == 0)
John Kessenich140f3df2015-06-26 16:58:36 -06002580 return accessChain.base;
John Kessenich55e7d112015-11-15 21:33:39 -07002581
John Kessenich5c3eed52018-02-05 14:44:14 -07002582 // emit the access chain
2583 StorageClass storageClass = (StorageClass)module.getStorageClass(getTypeId(accessChain.base));
2584 accessChain.instr = createAccessChain(storageClass, accessChain.base, accessChain.indexChain);
2585
2586 return accessChain.instr;
2587}
2588
2589// For a dynamic component selection of a swizzle.
2590//
2591// Turn the swizzle and dynamic component into just a dynamic component.
2592//
2593// Generates code.
2594void Builder::remapDynamicSwizzle()
2595{
2596 // do we have a swizzle to remap a dynamic component through?
2597 if (accessChain.component != NoResult && accessChain.swizzle.size() > 1) {
2598 // build a vector of the swizzle for the component to map into
2599 std::vector<Id> components;
Daniel Kochbfe09522018-03-13 17:06:51 -04002600 for (int c = 0; c < (int)accessChain.swizzle.size(); ++c)
John Kessenich5c3eed52018-02-05 14:44:14 -07002601 components.push_back(makeUintConstant(accessChain.swizzle[c]));
2602 Id mapType = makeVectorType(makeUintType(32), (int)accessChain.swizzle.size());
2603 Id map = makeCompositeConstant(mapType, components);
2604
2605 // use it
2606 accessChain.component = createVectorExtractDynamic(map, makeUintType(32), accessChain.component);
2607 accessChain.swizzle.clear();
2608 }
John Kessenich140f3df2015-06-26 16:58:36 -06002609}
2610
John Kessenich55e7d112015-11-15 21:33:39 -07002611// clear out swizzle if it is redundant, that is reselecting the same components
2612// that would be present without the swizzle.
John Kessenich140f3df2015-06-26 16:58:36 -06002613void Builder::simplifyAccessChainSwizzle()
2614{
2615 // If the swizzle has fewer components than the vector, it is subsetting, and must stay
2616 // to preserve that fact.
John Kessenichfa668da2015-09-13 14:46:30 -06002617 if (getNumTypeComponents(accessChain.preSwizzleBaseType) > (int)accessChain.swizzle.size())
John Kessenich140f3df2015-06-26 16:58:36 -06002618 return;
2619
2620 // if components are out of order, it is a swizzle
2621 for (unsigned int i = 0; i < accessChain.swizzle.size(); ++i) {
2622 if (i != accessChain.swizzle[i])
2623 return;
2624 }
2625
2626 // otherwise, there is no need to track this swizzle
2627 accessChain.swizzle.clear();
John Kessenichfa668da2015-09-13 14:46:30 -06002628 if (accessChain.component == NoResult)
2629 accessChain.preSwizzleBaseType = NoType;
John Kessenich140f3df2015-06-26 16:58:36 -06002630}
2631
John Kessenich55e7d112015-11-15 21:33:39 -07002632// To the extent any swizzling can become part of the chain
2633// of accesses instead of a post operation, make it so.
John Kessenich5c3eed52018-02-05 14:44:14 -07002634// If 'dynamic' is true, include transferring the dynamic component,
2635// otherwise, leave it pending.
John Kessenich55e7d112015-11-15 21:33:39 -07002636//
John Kessenich5c3eed52018-02-05 14:44:14 -07002637// Does not generate code. just updates the access chain.
John Kessenich55e7d112015-11-15 21:33:39 -07002638void Builder::transferAccessChainSwizzle(bool dynamic)
John Kessenich140f3df2015-06-26 16:58:36 -06002639{
John Kessenich55e7d112015-11-15 21:33:39 -07002640 // non existent?
2641 if (accessChain.swizzle.size() == 0 && accessChain.component == NoResult)
John Kessenich140f3df2015-06-26 16:58:36 -06002642 return;
2643
John Kessenich5c3eed52018-02-05 14:44:14 -07002644 // too complex?
2645 // (this requires either a swizzle, or generating code for a dynamic component)
2646 if (accessChain.swizzle.size() > 1)
John Kessenich55e7d112015-11-15 21:33:39 -07002647 return;
2648
John Kessenich5c3eed52018-02-05 14:44:14 -07002649 // single component, either in the swizzle and/or dynamic component
John Kessenich55e7d112015-11-15 21:33:39 -07002650 if (accessChain.swizzle.size() == 1) {
John Kessenich5c3eed52018-02-05 14:44:14 -07002651 assert(accessChain.component == NoResult);
2652 // handle static component selection
John Kessenich140f3df2015-06-26 16:58:36 -06002653 accessChain.indexChain.push_back(makeUintConstant(accessChain.swizzle.front()));
John Kessenich55e7d112015-11-15 21:33:39 -07002654 accessChain.swizzle.clear();
John Kessenich55e7d112015-11-15 21:33:39 -07002655 accessChain.preSwizzleBaseType = NoType;
John Kessenich55e7d112015-11-15 21:33:39 -07002656 } else if (dynamic && accessChain.component != NoResult) {
John Kessenich5c3eed52018-02-05 14:44:14 -07002657 assert(accessChain.swizzle.size() == 0);
John Kessenich55e7d112015-11-15 21:33:39 -07002658 // handle dynamic component
John Kessenich140f3df2015-06-26 16:58:36 -06002659 accessChain.indexChain.push_back(accessChain.component);
John Kessenich55e7d112015-11-15 21:33:39 -07002660 accessChain.preSwizzleBaseType = NoType;
2661 accessChain.component = NoResult;
2662 }
John Kessenich140f3df2015-06-26 16:58:36 -06002663}
2664
2665// Utility method for creating a new block and setting the insert point to
2666// be in it. This is useful for flow-control operations that need a "dummy"
2667// block proceeding them (e.g. instructions after a discard, etc).
2668void Builder::createAndSetNoPredecessorBlock(const char* /*name*/)
2669{
2670 Block* block = new Block(getUniqueId(), buildPoint->getParent());
2671 block->setUnreachable();
2672 buildPoint->getParent().addBlock(block);
2673 setBuildPoint(block);
2674
John Kessenich927608b2017-01-06 12:34:14 -07002675 // if (name)
John Kessenich140f3df2015-06-26 16:58:36 -06002676 // addName(block->getId(), name);
2677}
2678
2679// Comments in header
2680void Builder::createBranch(Block* block)
2681{
2682 Instruction* branch = new Instruction(OpBranch);
2683 branch->addIdOperand(block->getId());
Andrew Woloszynb7946d12016-01-18 09:23:56 -05002684 buildPoint->addInstruction(std::unique_ptr<Instruction>(branch));
John Kessenich140f3df2015-06-26 16:58:36 -06002685 block->addPredecessor(buildPoint);
2686}
2687
John Kessenich55e7d112015-11-15 21:33:39 -07002688void Builder::createSelectionMerge(Block* mergeBlock, unsigned int control)
John Kessenich140f3df2015-06-26 16:58:36 -06002689{
John Kessenich55e7d112015-11-15 21:33:39 -07002690 Instruction* merge = new Instruction(OpSelectionMerge);
John Kessenich140f3df2015-06-26 16:58:36 -06002691 merge->addIdOperand(mergeBlock->getId());
2692 merge->addImmediateOperand(control);
Andrew Woloszynb7946d12016-01-18 09:23:56 -05002693 buildPoint->addInstruction(std::unique_ptr<Instruction>(merge));
John Kessenich140f3df2015-06-26 16:58:36 -06002694}
2695
John Kessenicha2858d92018-01-31 08:11:18 -07002696void Builder::createLoopMerge(Block* mergeBlock, Block* continueBlock, unsigned int control,
2697 unsigned int dependencyLength)
John Kessenich55e7d112015-11-15 21:33:39 -07002698{
2699 Instruction* merge = new Instruction(OpLoopMerge);
2700 merge->addIdOperand(mergeBlock->getId());
2701 merge->addIdOperand(continueBlock->getId());
2702 merge->addImmediateOperand(control);
John Kessenicha2858d92018-01-31 08:11:18 -07002703 if ((control & LoopControlDependencyLengthMask) != 0)
2704 merge->addImmediateOperand(dependencyLength);
Andrew Woloszynb7946d12016-01-18 09:23:56 -05002705 buildPoint->addInstruction(std::unique_ptr<Instruction>(merge));
John Kessenich55e7d112015-11-15 21:33:39 -07002706}
2707
John Kessenich140f3df2015-06-26 16:58:36 -06002708void Builder::createConditionalBranch(Id condition, Block* thenBlock, Block* elseBlock)
2709{
2710 Instruction* branch = new Instruction(OpBranchConditional);
2711 branch->addIdOperand(condition);
2712 branch->addIdOperand(thenBlock->getId());
2713 branch->addIdOperand(elseBlock->getId());
Andrew Woloszynb7946d12016-01-18 09:23:56 -05002714 buildPoint->addInstruction(std::unique_ptr<Instruction>(branch));
John Kessenich140f3df2015-06-26 16:58:36 -06002715 thenBlock->addPredecessor(buildPoint);
2716 elseBlock->addPredecessor(buildPoint);
2717}
2718
John Kessenich121853f2017-05-31 17:11:16 -06002719// OpSource
2720// [OpSourceContinued]
2721// ...
2722void Builder::dumpSourceInstructions(std::vector<unsigned int>& out) const
2723{
2724 const int maxWordCount = 0xFFFF;
2725 const int opSourceWordCount = 4;
2726 const int nonNullBytesPerInstruction = 4 * (maxWordCount - opSourceWordCount) - 1;
2727
2728 if (source != SourceLanguageUnknown) {
2729 // OpSource Language Version File Source
2730 Instruction sourceInst(NoResult, NoType, OpSource);
2731 sourceInst.addImmediateOperand(source);
2732 sourceInst.addImmediateOperand(sourceVersion);
2733 // File operand
2734 if (sourceFileStringId != NoResult) {
2735 sourceInst.addIdOperand(sourceFileStringId);
2736 // Source operand
2737 if (sourceText.size() > 0) {
2738 int nextByte = 0;
2739 std::string subString;
2740 while ((int)sourceText.size() - nextByte > 0) {
2741 subString = sourceText.substr(nextByte, nonNullBytesPerInstruction);
2742 if (nextByte == 0) {
2743 // OpSource
2744 sourceInst.addStringOperand(subString.c_str());
2745 sourceInst.dump(out);
2746 } else {
2747 // OpSourcContinued
2748 Instruction sourceContinuedInst(OpSourceContinued);
2749 sourceContinuedInst.addStringOperand(subString.c_str());
2750 sourceContinuedInst.dump(out);
2751 }
2752 nextByte += nonNullBytesPerInstruction;
2753 }
2754 } else
2755 sourceInst.dump(out);
2756 } else
2757 sourceInst.dump(out);
2758 }
2759}
2760
Andrew Woloszynb7946d12016-01-18 09:23:56 -05002761void Builder::dumpInstructions(std::vector<unsigned int>& out, const std::vector<std::unique_ptr<Instruction> >& instructions) const
John Kessenich140f3df2015-06-26 16:58:36 -06002762{
2763 for (int i = 0; i < (int)instructions.size(); ++i) {
2764 instructions[i]->dump(out);
2765 }
2766}
2767
John Kessenich2a271162017-07-20 20:00:36 -06002768void Builder::dumpModuleProcesses(std::vector<unsigned int>& out) const
2769{
2770 for (int i = 0; i < (int)moduleProcesses.size(); ++i) {
John Kessenich2a271162017-07-20 20:00:36 -06002771 Instruction moduleProcessed(OpModuleProcessed);
2772 moduleProcessed.addStringOperand(moduleProcesses[i]);
2773 moduleProcessed.dump(out);
2774 }
2775}
2776
John Kessenich140f3df2015-06-26 16:58:36 -06002777}; // end spv namespace