blob: 0afcc6433777bf78507632818601fcbfedde2964 [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
Rex Xuc9e3c3c2016-07-29 16:00:05 +080049#ifdef AMD_EXTENSIONS
50 #include "hex_float.h"
51#endif
52
John Kessenich140f3df2015-06-26 16:58:36 -060053#ifndef _WIN32
54 #include <cstdio>
55#endif
56
57namespace spv {
58
John Kessenich2b5ea9f2018-01-31 18:35:56 -070059Builder::Builder(unsigned int spvVersion, unsigned int magicNumber, SpvBuildLogger* buildLogger) :
60 spvVersion(spvVersion),
John Kessenich140f3df2015-06-26 16:58:36 -060061 source(SourceLanguageUnknown),
62 sourceVersion(0),
John Kessenich121853f2017-05-31 17:11:16 -060063 sourceFileStringId(NoResult),
John Kesseniche485c7a2017-05-31 18:50:53 -060064 currentLine(0),
65 emitOpLines(false),
John Kessenich140f3df2015-06-26 16:58:36 -060066 addressModel(AddressingModelLogical),
67 memoryModel(MemoryModelGLSL450),
John Kessenich55e7d112015-11-15 21:33:39 -070068 builderNumber(magicNumber),
John Kessenich140f3df2015-06-26 16:58:36 -060069 buildPoint(0),
70 uniqueId(0),
John Kessenich517fe7a2016-11-26 13:31:47 -070071 entryPointFunction(0),
Lei Zhang09caf122016-05-02 18:11:54 -040072 generatingOpCodeForSpecConst(false),
Lei Zhang17535f72016-05-04 15:55:59 -040073 logger(buildLogger)
John Kessenich140f3df2015-06-26 16:58:36 -060074{
75 clearAccessChain();
76}
77
78Builder::~Builder()
79{
80}
81
82Id Builder::import(const char* name)
83{
84 Instruction* import = new Instruction(getUniqueId(), NoType, OpExtInstImport);
85 import->addStringOperand(name);
John Kessenichecba76f2017-01-06 00:34:48 -070086
Andrew Woloszynb7946d12016-01-18 09:23:56 -050087 imports.push_back(std::unique_ptr<Instruction>(import));
John Kessenich140f3df2015-06-26 16:58:36 -060088 return import->getResultId();
89}
90
John Kesseniche485c7a2017-05-31 18:50:53 -060091// Emit an OpLine if we've been asked to emit OpLines and the line number
92// has changed since the last time, and is a valid line number.
93void Builder::setLine(int lineNum)
94{
95 if (lineNum != 0 && lineNum != currentLine) {
96 currentLine = lineNum;
97 if (emitOpLines)
98 addLine(sourceFileStringId, currentLine, 0);
99 }
100}
101
102void Builder::addLine(Id fileName, int lineNum, int column)
103{
104 Instruction* line = new Instruction(OpLine);
105 line->addIdOperand(fileName);
106 line->addImmediateOperand(lineNum);
107 line->addImmediateOperand(column);
108 buildPoint->addInstruction(std::unique_ptr<Instruction>(line));
109}
110
John Kessenich140f3df2015-06-26 16:58:36 -0600111// For creating new groupedTypes (will return old type if the requested one was already made).
112Id Builder::makeVoidType()
113{
114 Instruction* type;
115 if (groupedTypes[OpTypeVoid].size() == 0) {
116 type = new Instruction(getUniqueId(), NoType, OpTypeVoid);
117 groupedTypes[OpTypeVoid].push_back(type);
Andrew Woloszynb7946d12016-01-18 09:23:56 -0500118 constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(type));
John Kessenich140f3df2015-06-26 16:58:36 -0600119 module.mapInstruction(type);
120 } else
121 type = groupedTypes[OpTypeVoid].back();
122
123 return type->getResultId();
124}
125
126Id Builder::makeBoolType()
127{
128 Instruction* type;
129 if (groupedTypes[OpTypeBool].size() == 0) {
130 type = new Instruction(getUniqueId(), NoType, OpTypeBool);
131 groupedTypes[OpTypeBool].push_back(type);
Andrew Woloszynb7946d12016-01-18 09:23:56 -0500132 constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(type));
John Kessenich140f3df2015-06-26 16:58:36 -0600133 module.mapInstruction(type);
134 } else
135 type = groupedTypes[OpTypeBool].back();
136
137 return type->getResultId();
138}
139
John Kessenich55e7d112015-11-15 21:33:39 -0700140Id Builder::makeSamplerType()
141{
142 Instruction* type;
143 if (groupedTypes[OpTypeSampler].size() == 0) {
144 type = new Instruction(getUniqueId(), NoType, OpTypeSampler);
145 groupedTypes[OpTypeSampler].push_back(type);
Andrew Woloszynb7946d12016-01-18 09:23:56 -0500146 constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(type));
John Kessenich55e7d112015-11-15 21:33:39 -0700147 module.mapInstruction(type);
148 } else
149 type = groupedTypes[OpTypeSampler].back();
150
151 return type->getResultId();
152}
153
John Kessenich140f3df2015-06-26 16:58:36 -0600154Id Builder::makePointer(StorageClass storageClass, Id pointee)
155{
156 // try to find it
157 Instruction* type;
158 for (int t = 0; t < (int)groupedTypes[OpTypePointer].size(); ++t) {
159 type = groupedTypes[OpTypePointer][t];
160 if (type->getImmediateOperand(0) == (unsigned)storageClass &&
161 type->getIdOperand(1) == pointee)
162 return type->getResultId();
163 }
164
165 // not found, make it
166 type = new Instruction(getUniqueId(), NoType, OpTypePointer);
167 type->addImmediateOperand(storageClass);
168 type->addIdOperand(pointee);
169 groupedTypes[OpTypePointer].push_back(type);
Andrew Woloszynb7946d12016-01-18 09:23:56 -0500170 constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(type));
John Kessenich140f3df2015-06-26 16:58:36 -0600171 module.mapInstruction(type);
172
173 return type->getResultId();
174}
175
176Id Builder::makeIntegerType(int width, bool hasSign)
177{
178 // try to find it
179 Instruction* type;
180 for (int t = 0; t < (int)groupedTypes[OpTypeInt].size(); ++t) {
181 type = groupedTypes[OpTypeInt][t];
182 if (type->getImmediateOperand(0) == (unsigned)width &&
183 type->getImmediateOperand(1) == (hasSign ? 1u : 0u))
184 return type->getResultId();
185 }
186
187 // not found, make it
188 type = new Instruction(getUniqueId(), NoType, OpTypeInt);
189 type->addImmediateOperand(width);
190 type->addImmediateOperand(hasSign ? 1 : 0);
191 groupedTypes[OpTypeInt].push_back(type);
Andrew Woloszynb7946d12016-01-18 09:23:56 -0500192 constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(type));
John Kessenich140f3df2015-06-26 16:58:36 -0600193 module.mapInstruction(type);
194
John Kessenich3c522072016-02-14 17:11:15 -0700195 // deal with capabilities
196 switch (width) {
197 case 16:
198 addCapability(CapabilityInt16);
199 break;
200 case 64:
201 addCapability(CapabilityInt64);
202 break;
203 default:
204 break;
205 }
206
John Kessenich140f3df2015-06-26 16:58:36 -0600207 return type->getResultId();
208}
209
210Id Builder::makeFloatType(int width)
211{
212 // try to find it
213 Instruction* type;
214 for (int t = 0; t < (int)groupedTypes[OpTypeFloat].size(); ++t) {
215 type = groupedTypes[OpTypeFloat][t];
216 if (type->getImmediateOperand(0) == (unsigned)width)
217 return type->getResultId();
218 }
219
220 // not found, make it
221 type = new Instruction(getUniqueId(), NoType, OpTypeFloat);
222 type->addImmediateOperand(width);
223 groupedTypes[OpTypeFloat].push_back(type);
Andrew Woloszynb7946d12016-01-18 09:23:56 -0500224 constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(type));
John Kessenich140f3df2015-06-26 16:58:36 -0600225 module.mapInstruction(type);
226
John Kessenich3c522072016-02-14 17:11:15 -0700227 // deal with capabilities
228 switch (width) {
229 case 16:
230 addCapability(CapabilityFloat16);
231 break;
232 case 64:
233 addCapability(CapabilityFloat64);
234 break;
235 default:
236 break;
237 }
238
John Kessenich140f3df2015-06-26 16:58:36 -0600239 return type->getResultId();
240}
241
John Kessenich55e7d112015-11-15 21:33:39 -0700242// Make a struct without checking for duplication.
243// See makeStructResultType() for non-decorated structs
244// needed as the result of some instructions, which does
245// check for duplicates.
John Kessenich32cfd492016-02-02 12:37:46 -0700246Id Builder::makeStructType(const std::vector<Id>& members, const char* name)
John Kessenich140f3df2015-06-26 16:58:36 -0600247{
John Kessenich55e7d112015-11-15 21:33:39 -0700248 // Don't look for previous one, because in the general case,
249 // structs can be duplicated except for decorations.
250
John Kessenich140f3df2015-06-26 16:58:36 -0600251 // not found, make it
252 Instruction* type = new Instruction(getUniqueId(), NoType, OpTypeStruct);
253 for (int op = 0; op < (int)members.size(); ++op)
254 type->addIdOperand(members[op]);
255 groupedTypes[OpTypeStruct].push_back(type);
Andrew Woloszynb7946d12016-01-18 09:23:56 -0500256 constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(type));
John Kessenich140f3df2015-06-26 16:58:36 -0600257 module.mapInstruction(type);
258 addName(type->getResultId(), name);
259
260 return type->getResultId();
261}
262
John Kessenich55e7d112015-11-15 21:33:39 -0700263// Make a struct for the simple results of several instructions,
264// checking for duplication.
265Id Builder::makeStructResultType(Id type0, Id type1)
266{
267 // try to find it
268 Instruction* type;
269 for (int t = 0; t < (int)groupedTypes[OpTypeStruct].size(); ++t) {
270 type = groupedTypes[OpTypeStruct][t];
271 if (type->getNumOperands() != 2)
272 continue;
John Kessenichecba76f2017-01-06 00:34:48 -0700273 if (type->getIdOperand(0) != type0 ||
John Kessenich55e7d112015-11-15 21:33:39 -0700274 type->getIdOperand(1) != type1)
275 continue;
276 return type->getResultId();
277 }
278
279 // not found, make it
280 std::vector<spv::Id> members;
281 members.push_back(type0);
282 members.push_back(type1);
283
284 return makeStructType(members, "ResType");
285}
286
John Kessenich140f3df2015-06-26 16:58:36 -0600287Id Builder::makeVectorType(Id component, int size)
288{
289 // try to find it
290 Instruction* type;
291 for (int t = 0; t < (int)groupedTypes[OpTypeVector].size(); ++t) {
292 type = groupedTypes[OpTypeVector][t];
293 if (type->getIdOperand(0) == component &&
294 type->getImmediateOperand(1) == (unsigned)size)
295 return type->getResultId();
296 }
297
298 // not found, make it
299 type = new Instruction(getUniqueId(), NoType, OpTypeVector);
300 type->addIdOperand(component);
301 type->addImmediateOperand(size);
302 groupedTypes[OpTypeVector].push_back(type);
Andrew Woloszynb7946d12016-01-18 09:23:56 -0500303 constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(type));
John Kessenich140f3df2015-06-26 16:58:36 -0600304 module.mapInstruction(type);
305
306 return type->getResultId();
307}
308
309Id Builder::makeMatrixType(Id component, int cols, int rows)
310{
311 assert(cols <= maxMatrixSize && rows <= maxMatrixSize);
312
313 Id column = makeVectorType(component, rows);
314
315 // try to find it
316 Instruction* type;
317 for (int t = 0; t < (int)groupedTypes[OpTypeMatrix].size(); ++t) {
318 type = groupedTypes[OpTypeMatrix][t];
319 if (type->getIdOperand(0) == column &&
320 type->getImmediateOperand(1) == (unsigned)cols)
321 return type->getResultId();
322 }
323
324 // not found, make it
325 type = new Instruction(getUniqueId(), NoType, OpTypeMatrix);
326 type->addIdOperand(column);
327 type->addImmediateOperand(cols);
328 groupedTypes[OpTypeMatrix].push_back(type);
Andrew Woloszynb7946d12016-01-18 09:23:56 -0500329 constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(type));
John Kessenich140f3df2015-06-26 16:58:36 -0600330 module.mapInstruction(type);
331
332 return type->getResultId();
333}
334
John Kessenichc9e0a422015-12-29 21:27:24 -0700335// TODO: performance: track arrays per stride
336// If a stride is supplied (non-zero) make an array.
337// If no stride (0), reuse previous array types.
John Kessenich6c292d32016-02-15 20:58:50 -0700338// 'size' is an Id of a constant or specialization constant of the array size
339Id Builder::makeArrayType(Id element, Id sizeId, int stride)
John Kessenich140f3df2015-06-26 16:58:36 -0600340{
John Kessenich140f3df2015-06-26 16:58:36 -0600341 Instruction* type;
John Kessenichc9e0a422015-12-29 21:27:24 -0700342 if (stride == 0) {
343 // try to find existing type
344 for (int t = 0; t < (int)groupedTypes[OpTypeArray].size(); ++t) {
345 type = groupedTypes[OpTypeArray][t];
346 if (type->getIdOperand(0) == element &&
347 type->getIdOperand(1) == sizeId)
348 return type->getResultId();
349 }
John Kessenich140f3df2015-06-26 16:58:36 -0600350 }
351
352 // not found, make it
353 type = new Instruction(getUniqueId(), NoType, OpTypeArray);
354 type->addIdOperand(element);
355 type->addIdOperand(sizeId);
356 groupedTypes[OpTypeArray].push_back(type);
Andrew Woloszynb7946d12016-01-18 09:23:56 -0500357 constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(type));
John Kessenich140f3df2015-06-26 16:58:36 -0600358 module.mapInstruction(type);
359
360 return type->getResultId();
361}
362
John Kessenichc9a80832015-09-12 12:17:44 -0600363Id Builder::makeRuntimeArray(Id element)
364{
365 Instruction* type = new Instruction(getUniqueId(), NoType, OpTypeRuntimeArray);
366 type->addIdOperand(element);
Andrew Woloszynb7946d12016-01-18 09:23:56 -0500367 constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(type));
John Kessenichc9a80832015-09-12 12:17:44 -0600368 module.mapInstruction(type);
369
370 return type->getResultId();
371}
372
John Kessenich32cfd492016-02-02 12:37:46 -0700373Id Builder::makeFunctionType(Id returnType, const std::vector<Id>& paramTypes)
John Kessenich140f3df2015-06-26 16:58:36 -0600374{
375 // try to find it
376 Instruction* type;
377 for (int t = 0; t < (int)groupedTypes[OpTypeFunction].size(); ++t) {
378 type = groupedTypes[OpTypeFunction][t];
379 if (type->getIdOperand(0) != returnType || (int)paramTypes.size() != type->getNumOperands() - 1)
380 continue;
381 bool mismatch = false;
382 for (int p = 0; p < (int)paramTypes.size(); ++p) {
383 if (paramTypes[p] != type->getIdOperand(p + 1)) {
384 mismatch = true;
385 break;
386 }
387 }
388 if (! mismatch)
John Kessenichc9a80832015-09-12 12:17:44 -0600389 return type->getResultId();
John Kessenich140f3df2015-06-26 16:58:36 -0600390 }
391
392 // not found, make it
393 type = new Instruction(getUniqueId(), NoType, OpTypeFunction);
394 type->addIdOperand(returnType);
395 for (int p = 0; p < (int)paramTypes.size(); ++p)
396 type->addIdOperand(paramTypes[p]);
397 groupedTypes[OpTypeFunction].push_back(type);
Andrew Woloszynb7946d12016-01-18 09:23:56 -0500398 constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(type));
John Kessenich140f3df2015-06-26 16:58:36 -0600399 module.mapInstruction(type);
400
401 return type->getResultId();
402}
403
John Kessenich5e4b1242015-08-06 22:53:06 -0600404Id Builder::makeImageType(Id sampledType, Dim dim, bool depth, bool arrayed, bool ms, unsigned sampled, ImageFormat format)
John Kessenich140f3df2015-06-26 16:58:36 -0600405{
John Kessenich260f5062017-08-14 22:10:00 -0600406 assert(sampled == 1 || sampled == 2);
407
John Kessenich140f3df2015-06-26 16:58:36 -0600408 // try to find it
409 Instruction* type;
John Kessenich5e4b1242015-08-06 22:53:06 -0600410 for (int t = 0; t < (int)groupedTypes[OpTypeImage].size(); ++t) {
411 type = groupedTypes[OpTypeImage][t];
John Kessenich140f3df2015-06-26 16:58:36 -0600412 if (type->getIdOperand(0) == sampledType &&
413 type->getImmediateOperand(1) == (unsigned int)dim &&
John Kessenich5e4b1242015-08-06 22:53:06 -0600414 type->getImmediateOperand(2) == ( depth ? 1u : 0u) &&
John Kessenich140f3df2015-06-26 16:58:36 -0600415 type->getImmediateOperand(3) == (arrayed ? 1u : 0u) &&
John Kessenich5e4b1242015-08-06 22:53:06 -0600416 type->getImmediateOperand(4) == ( ms ? 1u : 0u) &&
417 type->getImmediateOperand(5) == sampled &&
418 type->getImmediateOperand(6) == (unsigned int)format)
John Kessenich140f3df2015-06-26 16:58:36 -0600419 return type->getResultId();
420 }
421
422 // not found, make it
John Kessenich5e4b1242015-08-06 22:53:06 -0600423 type = new Instruction(getUniqueId(), NoType, OpTypeImage);
John Kessenich140f3df2015-06-26 16:58:36 -0600424 type->addIdOperand(sampledType);
425 type->addImmediateOperand( dim);
John Kessenich5e4b1242015-08-06 22:53:06 -0600426 type->addImmediateOperand( depth ? 1 : 0);
John Kessenich140f3df2015-06-26 16:58:36 -0600427 type->addImmediateOperand(arrayed ? 1 : 0);
John Kessenich140f3df2015-06-26 16:58:36 -0600428 type->addImmediateOperand( ms ? 1 : 0);
John Kessenich5e4b1242015-08-06 22:53:06 -0600429 type->addImmediateOperand(sampled);
430 type->addImmediateOperand((unsigned int)format);
John Kessenich140f3df2015-06-26 16:58:36 -0600431
John Kessenich5e4b1242015-08-06 22:53:06 -0600432 groupedTypes[OpTypeImage].push_back(type);
Andrew Woloszynb7946d12016-01-18 09:23:56 -0500433 constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(type));
John Kessenich5e4b1242015-08-06 22:53:06 -0600434 module.mapInstruction(type);
435
John Kessenichb0364dc2016-02-14 17:37:30 -0700436 // deal with capabilities
437 switch (dim) {
438 case DimBuffer:
John Kessenich260f5062017-08-14 22:10:00 -0600439 if (sampled == 1)
John Kessenichb0364dc2016-02-14 17:37:30 -0700440 addCapability(CapabilitySampledBuffer);
441 else
442 addCapability(CapabilityImageBuffer);
443 break;
444 case Dim1D:
John Kessenich260f5062017-08-14 22:10:00 -0600445 if (sampled == 1)
John Kessenichb0364dc2016-02-14 17:37:30 -0700446 addCapability(CapabilitySampled1D);
447 else
448 addCapability(CapabilityImage1D);
449 break;
450 case DimCube:
451 if (arrayed) {
John Kessenich260f5062017-08-14 22:10:00 -0600452 if (sampled == 1)
John Kessenichb0364dc2016-02-14 17:37:30 -0700453 addCapability(CapabilitySampledCubeArray);
454 else
455 addCapability(CapabilityImageCubeArray);
456 }
457 break;
458 case DimRect:
John Kessenich260f5062017-08-14 22:10:00 -0600459 if (sampled == 1)
John Kessenichb0364dc2016-02-14 17:37:30 -0700460 addCapability(CapabilitySampledRect);
461 else
462 addCapability(CapabilityImageRect);
463 break;
464 case DimSubpassData:
465 addCapability(CapabilityInputAttachment);
466 break;
467 default:
468 break;
469 }
470
471 if (ms) {
John Kessenich260f5062017-08-14 22:10:00 -0600472 if (sampled == 2) {
John Kessenich7a9db712017-10-20 10:56:50 -0600473 // Images used with subpass data are not storage
474 // images, so don't require the capability for them.
475 if (dim != Dim::DimSubpassData)
476 addCapability(CapabilityStorageImageMultisample);
John Kessenich260f5062017-08-14 22:10:00 -0600477 if (arrayed)
478 addCapability(CapabilityImageMSArray);
479 }
John Kessenichb0364dc2016-02-14 17:37:30 -0700480 }
481
John Kessenich5e4b1242015-08-06 22:53:06 -0600482 return type->getResultId();
483}
484
485Id Builder::makeSampledImageType(Id imageType)
486{
487 // try to find it
488 Instruction* type;
489 for (int t = 0; t < (int)groupedTypes[OpTypeSampledImage].size(); ++t) {
490 type = groupedTypes[OpTypeSampledImage][t];
491 if (type->getIdOperand(0) == imageType)
492 return type->getResultId();
493 }
494
495 // not found, make it
496 type = new Instruction(getUniqueId(), NoType, OpTypeSampledImage);
497 type->addIdOperand(imageType);
498
499 groupedTypes[OpTypeSampledImage].push_back(type);
Andrew Woloszynb7946d12016-01-18 09:23:56 -0500500 constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(type));
John Kessenich140f3df2015-06-26 16:58:36 -0600501 module.mapInstruction(type);
502
503 return type->getResultId();
504}
505
506Id Builder::getDerefTypeId(Id resultId) const
507{
508 Id typeId = getTypeId(resultId);
509 assert(isPointerType(typeId));
510
511 return module.getInstruction(typeId)->getImmediateOperand(1);
512}
513
514Op Builder::getMostBasicTypeClass(Id typeId) const
515{
516 Instruction* instr = module.getInstruction(typeId);
517
518 Op typeClass = instr->getOpCode();
519 switch (typeClass)
520 {
521 case OpTypeVoid:
522 case OpTypeBool:
523 case OpTypeInt:
524 case OpTypeFloat:
525 case OpTypeStruct:
526 return typeClass;
527 case OpTypeVector:
528 case OpTypeMatrix:
529 case OpTypeArray:
530 case OpTypeRuntimeArray:
531 return getMostBasicTypeClass(instr->getIdOperand(0));
532 case OpTypePointer:
533 return getMostBasicTypeClass(instr->getIdOperand(1));
534 default:
John Kessenich55e7d112015-11-15 21:33:39 -0700535 assert(0);
John Kessenich140f3df2015-06-26 16:58:36 -0600536 return OpTypeFloat;
537 }
538}
539
John Kessenich22118352015-12-21 20:54:09 -0700540int Builder::getNumTypeConstituents(Id typeId) const
John Kessenich140f3df2015-06-26 16:58:36 -0600541{
542 Instruction* instr = module.getInstruction(typeId);
543
544 switch (instr->getOpCode())
545 {
546 case OpTypeBool:
547 case OpTypeInt:
548 case OpTypeFloat:
549 return 1;
550 case OpTypeVector:
551 case OpTypeMatrix:
552 return instr->getImmediateOperand(1);
John Kessenich6c292d32016-02-15 20:58:50 -0700553 case OpTypeArray:
554 {
555 Id lengthId = instr->getImmediateOperand(1);
556 return module.getInstruction(lengthId)->getImmediateOperand(0);
557 }
John Kessenich22118352015-12-21 20:54:09 -0700558 case OpTypeStruct:
559 return instr->getNumOperands();
John Kessenich140f3df2015-06-26 16:58:36 -0600560 default:
John Kessenich55e7d112015-11-15 21:33:39 -0700561 assert(0);
John Kessenich140f3df2015-06-26 16:58:36 -0600562 return 1;
563 }
564}
565
566// Return the lowest-level type of scalar that an homogeneous composite is made out of.
567// Typically, this is just to find out if something is made out of ints or floats.
568// However, it includes returning a structure, if say, it is an array of structure.
569Id Builder::getScalarTypeId(Id typeId) const
570{
571 Instruction* instr = module.getInstruction(typeId);
572
573 Op typeClass = instr->getOpCode();
574 switch (typeClass)
575 {
576 case OpTypeVoid:
577 case OpTypeBool:
578 case OpTypeInt:
579 case OpTypeFloat:
580 case OpTypeStruct:
581 return instr->getResultId();
582 case OpTypeVector:
583 case OpTypeMatrix:
584 case OpTypeArray:
585 case OpTypeRuntimeArray:
586 case OpTypePointer:
587 return getScalarTypeId(getContainedTypeId(typeId));
588 default:
John Kessenich55e7d112015-11-15 21:33:39 -0700589 assert(0);
John Kessenich140f3df2015-06-26 16:58:36 -0600590 return NoResult;
591 }
592}
593
594// Return the type of 'member' of a composite.
595Id Builder::getContainedTypeId(Id typeId, int member) const
596{
597 Instruction* instr = module.getInstruction(typeId);
598
599 Op typeClass = instr->getOpCode();
600 switch (typeClass)
601 {
602 case OpTypeVector:
603 case OpTypeMatrix:
604 case OpTypeArray:
605 case OpTypeRuntimeArray:
606 return instr->getIdOperand(0);
607 case OpTypePointer:
608 return instr->getIdOperand(1);
609 case OpTypeStruct:
610 return instr->getIdOperand(member);
611 default:
John Kessenich55e7d112015-11-15 21:33:39 -0700612 assert(0);
John Kessenich140f3df2015-06-26 16:58:36 -0600613 return NoResult;
614 }
615}
616
617// Return the immediately contained type of a given composite type.
618Id Builder::getContainedTypeId(Id typeId) const
619{
620 return getContainedTypeId(typeId, 0);
621}
622
623// See if a scalar constant of this type has already been created, so it
624// can be reused rather than duplicated. (Required by the specification).
John Kessenich55e7d112015-11-15 21:33:39 -0700625Id Builder::findScalarConstant(Op typeClass, Op opcode, Id typeId, unsigned value) const
John Kessenich140f3df2015-06-26 16:58:36 -0600626{
627 Instruction* constant;
628 for (int i = 0; i < (int)groupedConstants[typeClass].size(); ++i) {
629 constant = groupedConstants[typeClass][i];
John Kessenich55e7d112015-11-15 21:33:39 -0700630 if (constant->getOpCode() == opcode &&
John Kessenich140f3df2015-06-26 16:58:36 -0600631 constant->getTypeId() == typeId &&
632 constant->getImmediateOperand(0) == value)
633 return constant->getResultId();
634 }
635
636 return 0;
637}
638
Rex Xu8ff43de2016-04-22 16:51:45 +0800639// Version of findScalarConstant (see above) for scalars that take two operands (e.g. a 'double' or 'int64').
John Kessenich55e7d112015-11-15 21:33:39 -0700640Id Builder::findScalarConstant(Op typeClass, Op opcode, Id typeId, unsigned v1, unsigned v2) const
John Kessenich140f3df2015-06-26 16:58:36 -0600641{
642 Instruction* constant;
643 for (int i = 0; i < (int)groupedConstants[typeClass].size(); ++i) {
644 constant = groupedConstants[typeClass][i];
John Kessenich55e7d112015-11-15 21:33:39 -0700645 if (constant->getOpCode() == opcode &&
John Kessenich140f3df2015-06-26 16:58:36 -0600646 constant->getTypeId() == typeId &&
647 constant->getImmediateOperand(0) == v1 &&
648 constant->getImmediateOperand(1) == v2)
649 return constant->getResultId();
650 }
651
652 return 0;
653}
654
John Kessenichf685df82015-10-13 10:55:08 -0600655// Return true if consuming 'opcode' means consuming a constant.
656// "constant" here means after final transform to executable code,
657// the value consumed will be a constant, so includes specialization.
John Kessenich71631272015-10-13 10:39:19 -0600658bool Builder::isConstantOpCode(Op opcode) const
659{
660 switch (opcode) {
John Kessenichecba76f2017-01-06 00:34:48 -0700661 case OpUndef:
John Kessenich71631272015-10-13 10:39:19 -0600662 case OpConstantTrue:
663 case OpConstantFalse:
664 case OpConstant:
665 case OpConstantComposite:
666 case OpConstantSampler:
667 case OpConstantNull:
668 case OpSpecConstantTrue:
669 case OpSpecConstantFalse:
670 case OpSpecConstant:
671 case OpSpecConstantComposite:
672 case OpSpecConstantOp:
673 return true;
674 default:
675 return false;
676 }
677}
678
qining27e04a02016-04-14 16:40:20 -0400679// Return true if consuming 'opcode' means consuming a specialization constant.
680bool Builder::isSpecConstantOpCode(Op opcode) const
681{
682 switch (opcode) {
683 case OpSpecConstantTrue:
684 case OpSpecConstantFalse:
685 case OpSpecConstant:
686 case OpSpecConstantComposite:
687 case OpSpecConstantOp:
688 return true;
689 default:
690 return false;
691 }
692}
693
John Kessenich55e7d112015-11-15 21:33:39 -0700694Id Builder::makeBoolConstant(bool b, bool specConstant)
John Kessenich140f3df2015-06-26 16:58:36 -0600695{
696 Id typeId = makeBoolType();
697 Instruction* constant;
John Kessenich55e7d112015-11-15 21:33:39 -0700698 Op opcode = specConstant ? (b ? OpSpecConstantTrue : OpSpecConstantFalse) : (b ? OpConstantTrue : OpConstantFalse);
John Kessenich140f3df2015-06-26 16:58:36 -0600699
John Kessenich6c292d32016-02-15 20:58:50 -0700700 // See if we already made it. Applies only to regular constants, because specialization constants
701 // must remain distinct for the purpose of applying a SpecId decoration.
702 if (! specConstant) {
703 Id existing = 0;
704 for (int i = 0; i < (int)groupedConstants[OpTypeBool].size(); ++i) {
705 constant = groupedConstants[OpTypeBool][i];
706 if (constant->getTypeId() == typeId && constant->getOpCode() == opcode)
707 existing = constant->getResultId();
708 }
John Kessenich140f3df2015-06-26 16:58:36 -0600709
John Kessenich6c292d32016-02-15 20:58:50 -0700710 if (existing)
711 return existing;
712 }
John Kessenich140f3df2015-06-26 16:58:36 -0600713
714 // Make it
John Kessenich55e7d112015-11-15 21:33:39 -0700715 Instruction* c = new Instruction(getUniqueId(), typeId, opcode);
Andrew Woloszynb7946d12016-01-18 09:23:56 -0500716 constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(c));
John Kessenich140f3df2015-06-26 16:58:36 -0600717 groupedConstants[OpTypeBool].push_back(c);
718 module.mapInstruction(c);
719
720 return c->getResultId();
721}
722
John Kessenich55e7d112015-11-15 21:33:39 -0700723Id Builder::makeIntConstant(Id typeId, unsigned value, bool specConstant)
John Kessenich140f3df2015-06-26 16:58:36 -0600724{
John Kessenich55e7d112015-11-15 21:33:39 -0700725 Op opcode = specConstant ? OpSpecConstant : OpConstant;
John Kessenich6c292d32016-02-15 20:58:50 -0700726
727 // See if we already made it. Applies only to regular constants, because specialization constants
728 // must remain distinct for the purpose of applying a SpecId decoration.
729 if (! specConstant) {
730 Id existing = findScalarConstant(OpTypeInt, opcode, typeId, value);
731 if (existing)
732 return existing;
733 }
John Kessenich140f3df2015-06-26 16:58:36 -0600734
John Kessenich55e7d112015-11-15 21:33:39 -0700735 Instruction* c = new Instruction(getUniqueId(), typeId, opcode);
John Kessenich140f3df2015-06-26 16:58:36 -0600736 c->addImmediateOperand(value);
Andrew Woloszynb7946d12016-01-18 09:23:56 -0500737 constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(c));
John Kessenich140f3df2015-06-26 16:58:36 -0600738 groupedConstants[OpTypeInt].push_back(c);
739 module.mapInstruction(c);
740
741 return c->getResultId();
742}
743
Rex Xu8ff43de2016-04-22 16:51:45 +0800744Id Builder::makeInt64Constant(Id typeId, unsigned long long value, bool specConstant)
745{
746 Op opcode = specConstant ? OpSpecConstant : OpConstant;
747
748 unsigned op1 = value & 0xFFFFFFFF;
749 unsigned op2 = value >> 32;
750
751 // See if we already made it. Applies only to regular constants, because specialization constants
752 // must remain distinct for the purpose of applying a SpecId decoration.
753 if (! specConstant) {
754 Id existing = findScalarConstant(OpTypeInt, opcode, typeId, op1, op2);
755 if (existing)
756 return existing;
757 }
758
759 Instruction* c = new Instruction(getUniqueId(), typeId, opcode);
760 c->addImmediateOperand(op1);
761 c->addImmediateOperand(op2);
762 constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(c));
763 groupedConstants[OpTypeInt].push_back(c);
764 module.mapInstruction(c);
765
766 return c->getResultId();
767}
768
John Kessenich55e7d112015-11-15 21:33:39 -0700769Id Builder::makeFloatConstant(float f, bool specConstant)
John Kessenich140f3df2015-06-26 16:58:36 -0600770{
John Kessenich55e7d112015-11-15 21:33:39 -0700771 Op opcode = specConstant ? OpSpecConstant : OpConstant;
John Kessenich140f3df2015-06-26 16:58:36 -0600772 Id typeId = makeFloatType(32);
Mark Adams18b637f2016-02-23 12:17:11 -0500773 union { float fl; unsigned int ui; } u;
774 u.fl = f;
775 unsigned value = u.ui;
John Kessenich6c292d32016-02-15 20:58:50 -0700776
777 // See if we already made it. Applies only to regular constants, because specialization constants
778 // must remain distinct for the purpose of applying a SpecId decoration.
779 if (! specConstant) {
780 Id existing = findScalarConstant(OpTypeFloat, opcode, typeId, value);
781 if (existing)
782 return existing;
783 }
John Kessenich140f3df2015-06-26 16:58:36 -0600784
John Kessenich55e7d112015-11-15 21:33:39 -0700785 Instruction* c = new Instruction(getUniqueId(), typeId, opcode);
John Kessenich140f3df2015-06-26 16:58:36 -0600786 c->addImmediateOperand(value);
Andrew Woloszynb7946d12016-01-18 09:23:56 -0500787 constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(c));
John Kessenich140f3df2015-06-26 16:58:36 -0600788 groupedConstants[OpTypeFloat].push_back(c);
789 module.mapInstruction(c);
790
791 return c->getResultId();
792}
793
John Kessenich55e7d112015-11-15 21:33:39 -0700794Id Builder::makeDoubleConstant(double d, bool specConstant)
John Kessenich140f3df2015-06-26 16:58:36 -0600795{
John Kessenich55e7d112015-11-15 21:33:39 -0700796 Op opcode = specConstant ? OpSpecConstant : OpConstant;
John Kessenich140f3df2015-06-26 16:58:36 -0600797 Id typeId = makeFloatType(64);
Mark Adams18b637f2016-02-23 12:17:11 -0500798 union { double db; unsigned long long ull; } u;
799 u.db = d;
800 unsigned long long value = u.ull;
John Kessenich140f3df2015-06-26 16:58:36 -0600801 unsigned op1 = value & 0xFFFFFFFF;
802 unsigned op2 = value >> 32;
John Kessenich6c292d32016-02-15 20:58:50 -0700803
804 // See if we already made it. Applies only to regular constants, because specialization constants
805 // must remain distinct for the purpose of applying a SpecId decoration.
806 if (! specConstant) {
807 Id existing = findScalarConstant(OpTypeFloat, opcode, typeId, op1, op2);
808 if (existing)
809 return existing;
810 }
John Kessenich140f3df2015-06-26 16:58:36 -0600811
John Kessenich55e7d112015-11-15 21:33:39 -0700812 Instruction* c = new Instruction(getUniqueId(), typeId, opcode);
John Kessenich140f3df2015-06-26 16:58:36 -0600813 c->addImmediateOperand(op1);
814 c->addImmediateOperand(op2);
Andrew Woloszynb7946d12016-01-18 09:23:56 -0500815 constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(c));
John Kessenich140f3df2015-06-26 16:58:36 -0600816 groupedConstants[OpTypeFloat].push_back(c);
817 module.mapInstruction(c);
818
819 return c->getResultId();
820}
821
Rex Xuc9e3c3c2016-07-29 16:00:05 +0800822#ifdef AMD_EXTENSIONS
823Id 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}
850#endif
851
Vlad Ivanov689490f2017-01-26 20:46:02 +0300852Id Builder::findCompositeConstant(Op typeClass, const std::vector<Id>& comps) const
John Kessenich140f3df2015-06-26 16:58:36 -0600853{
854 Instruction* constant = 0;
855 bool found = false;
856 for (int i = 0; i < (int)groupedConstants[typeClass].size(); ++i) {
857 constant = groupedConstants[typeClass][i];
858
859 // same shape?
860 if (constant->getNumOperands() != (int)comps.size())
861 continue;
862
863 // same contents?
864 bool mismatch = false;
865 for (int op = 0; op < constant->getNumOperands(); ++op) {
866 if (constant->getIdOperand(op) != comps[op]) {
867 mismatch = true;
868 break;
869 }
870 }
871 if (! mismatch) {
872 found = true;
873 break;
874 }
875 }
876
877 return found ? constant->getResultId() : NoResult;
878}
879
880// Comments in header
Vlad Ivanov689490f2017-01-26 20:46:02 +0300881Id Builder::makeCompositeConstant(Id typeId, const std::vector<Id>& members, bool specConstant)
John Kessenich140f3df2015-06-26 16:58:36 -0600882{
John Kessenich6c292d32016-02-15 20:58:50 -0700883 Op opcode = specConstant ? OpSpecConstantComposite : OpConstantComposite;
John Kessenich140f3df2015-06-26 16:58:36 -0600884 assert(typeId);
885 Op typeClass = getTypeClass(typeId);
886
887 switch (typeClass) {
888 case OpTypeVector:
889 case OpTypeArray:
890 case OpTypeStruct:
891 case OpTypeMatrix:
892 break;
893 default:
John Kessenich55e7d112015-11-15 21:33:39 -0700894 assert(0);
John Kessenich140f3df2015-06-26 16:58:36 -0600895 return makeFloatConstant(0.0);
896 }
897
John Kessenich6c292d32016-02-15 20:58:50 -0700898 if (! specConstant) {
899 Id existing = findCompositeConstant(typeClass, members);
900 if (existing)
901 return existing;
902 }
John Kessenich140f3df2015-06-26 16:58:36 -0600903
John Kessenich6c292d32016-02-15 20:58:50 -0700904 Instruction* c = new Instruction(getUniqueId(), typeId, opcode);
John Kessenich140f3df2015-06-26 16:58:36 -0600905 for (int op = 0; op < (int)members.size(); ++op)
906 c->addIdOperand(members[op]);
Andrew Woloszynb7946d12016-01-18 09:23:56 -0500907 constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(c));
John Kessenich140f3df2015-06-26 16:58:36 -0600908 groupedConstants[typeClass].push_back(c);
909 module.mapInstruction(c);
910
911 return c->getResultId();
912}
913
John Kessenich55e7d112015-11-15 21:33:39 -0700914Instruction* Builder::addEntryPoint(ExecutionModel model, Function* function, const char* name)
John Kessenich140f3df2015-06-26 16:58:36 -0600915{
916 Instruction* entryPoint = new Instruction(OpEntryPoint);
917 entryPoint->addImmediateOperand(model);
918 entryPoint->addIdOperand(function->getId());
John Kessenich5e4b1242015-08-06 22:53:06 -0600919 entryPoint->addStringOperand(name);
John Kessenich140f3df2015-06-26 16:58:36 -0600920
Andrew Woloszynb7946d12016-01-18 09:23:56 -0500921 entryPoints.push_back(std::unique_ptr<Instruction>(entryPoint));
John Kessenich55e7d112015-11-15 21:33:39 -0700922
923 return entryPoint;
John Kessenich140f3df2015-06-26 16:58:36 -0600924}
925
John Kessenichb56a26a2015-09-16 16:04:05 -0600926// Currently relying on the fact that all 'value' of interest are small non-negative values.
927void Builder::addExecutionMode(Function* entryPoint, ExecutionMode mode, int value1, int value2, int value3)
John Kessenich140f3df2015-06-26 16:58:36 -0600928{
John Kessenich140f3df2015-06-26 16:58:36 -0600929 Instruction* instr = new Instruction(OpExecutionMode);
930 instr->addIdOperand(entryPoint->getId());
931 instr->addImmediateOperand(mode);
John Kessenichb56a26a2015-09-16 16:04:05 -0600932 if (value1 >= 0)
933 instr->addImmediateOperand(value1);
934 if (value2 >= 0)
935 instr->addImmediateOperand(value2);
936 if (value3 >= 0)
937 instr->addImmediateOperand(value3);
John Kessenich140f3df2015-06-26 16:58:36 -0600938
Andrew Woloszynb7946d12016-01-18 09:23:56 -0500939 executionModes.push_back(std::unique_ptr<Instruction>(instr));
John Kessenich140f3df2015-06-26 16:58:36 -0600940}
941
942void Builder::addName(Id id, const char* string)
943{
944 Instruction* name = new Instruction(OpName);
945 name->addIdOperand(id);
946 name->addStringOperand(string);
947
Andrew Woloszynb7946d12016-01-18 09:23:56 -0500948 names.push_back(std::unique_ptr<Instruction>(name));
John Kessenich140f3df2015-06-26 16:58:36 -0600949}
950
951void Builder::addMemberName(Id id, int memberNumber, const char* string)
952{
953 Instruction* name = new Instruction(OpMemberName);
954 name->addIdOperand(id);
955 name->addImmediateOperand(memberNumber);
956 name->addStringOperand(string);
957
Andrew Woloszynb7946d12016-01-18 09:23:56 -0500958 names.push_back(std::unique_ptr<Instruction>(name));
John Kessenich140f3df2015-06-26 16:58:36 -0600959}
960
John Kessenich140f3df2015-06-26 16:58:36 -0600961void Builder::addDecoration(Id id, Decoration decoration, int num)
962{
John Kessenich4016e382016-07-15 11:53:56 -0600963 if (decoration == spv::DecorationMax)
John Kessenich55e7d112015-11-15 21:33:39 -0700964 return;
John Kessenich140f3df2015-06-26 16:58:36 -0600965 Instruction* dec = new Instruction(OpDecorate);
966 dec->addIdOperand(id);
967 dec->addImmediateOperand(decoration);
968 if (num >= 0)
969 dec->addImmediateOperand(num);
970
Andrew Woloszynb7946d12016-01-18 09:23:56 -0500971 decorations.push_back(std::unique_ptr<Instruction>(dec));
John Kessenich140f3df2015-06-26 16:58:36 -0600972}
973
974void Builder::addMemberDecoration(Id id, unsigned int member, Decoration decoration, int num)
975{
976 Instruction* dec = new Instruction(OpMemberDecorate);
977 dec->addIdOperand(id);
978 dec->addImmediateOperand(member);
979 dec->addImmediateOperand(decoration);
980 if (num >= 0)
981 dec->addImmediateOperand(num);
982
Andrew Woloszynb7946d12016-01-18 09:23:56 -0500983 decorations.push_back(std::unique_ptr<Instruction>(dec));
John Kessenich140f3df2015-06-26 16:58:36 -0600984}
985
986// Comments in header
John Kessenich6fccb3c2016-09-19 16:01:41 -0600987Function* Builder::makeEntryPoint(const char* entryPoint)
John Kessenich140f3df2015-06-26 16:58:36 -0600988{
John Kessenich517fe7a2016-11-26 13:31:47 -0700989 assert(! entryPointFunction);
John Kessenich140f3df2015-06-26 16:58:36 -0600990
991 Block* entry;
992 std::vector<Id> params;
John Kessenichfad62972017-07-18 02:35:46 -0600993 std::vector<std::vector<Decoration>> decorations;
John Kessenich140f3df2015-06-26 16:58:36 -0600994
John Kessenichfad62972017-07-18 02:35:46 -0600995 entryPointFunction = makeFunctionEntry(NoPrecision, makeVoidType(), entryPoint, params, decorations, &entry);
John Kessenich140f3df2015-06-26 16:58:36 -0600996
John Kessenich517fe7a2016-11-26 13:31:47 -0700997 return entryPointFunction;
John Kessenich140f3df2015-06-26 16:58:36 -0600998}
999
1000// Comments in header
John Kessenich32cfd492016-02-02 12:37:46 -07001001Function* Builder::makeFunctionEntry(Decoration precision, Id returnType, const char* name,
John Kessenichfad62972017-07-18 02:35:46 -06001002 const std::vector<Id>& paramTypes, const std::vector<std::vector<Decoration>>& decorations, Block **entry)
John Kessenich140f3df2015-06-26 16:58:36 -06001003{
John Kessenich32cfd492016-02-02 12:37:46 -07001004 // Make the function and initial instructions in it
John Kessenich140f3df2015-06-26 16:58:36 -06001005 Id typeId = makeFunctionType(returnType, paramTypes);
baldurkd76692d2015-07-12 11:32:58 +02001006 Id firstParamId = paramTypes.size() == 0 ? 0 : getUniqueIds((int)paramTypes.size());
John Kessenich140f3df2015-06-26 16:58:36 -06001007 Function* function = new Function(getUniqueId(), returnType, typeId, firstParamId, module);
1008
John Kessenich32cfd492016-02-02 12:37:46 -07001009 // Set up the precisions
1010 setPrecision(function->getId(), precision);
John Kessenichfad62972017-07-18 02:35:46 -06001011 for (unsigned p = 0; p < (unsigned)decorations.size(); ++p) {
1012 for (int d = 0; d < (int)decorations[p].size(); ++d)
1013 addDecoration(firstParamId + p, decorations[p][d]);
1014 }
John Kessenich32cfd492016-02-02 12:37:46 -07001015
1016 // CFG
John Kessenich140f3df2015-06-26 16:58:36 -06001017 if (entry) {
1018 *entry = new Block(getUniqueId(), *function);
1019 function->addBlock(*entry);
1020 setBuildPoint(*entry);
1021 }
1022
1023 if (name)
1024 addName(function->getId(), name);
1025
Andrew Woloszynb7946d12016-01-18 09:23:56 -05001026 functions.push_back(std::unique_ptr<Function>(function));
1027
John Kessenich140f3df2015-06-26 16:58:36 -06001028 return function;
1029}
1030
1031// Comments in header
John Kesseniche770b3e2015-09-14 20:58:02 -06001032void Builder::makeReturn(bool implicit, Id retVal)
John Kessenich140f3df2015-06-26 16:58:36 -06001033{
John Kesseniche770b3e2015-09-14 20:58:02 -06001034 if (retVal) {
John Kessenich140f3df2015-06-26 16:58:36 -06001035 Instruction* inst = new Instruction(NoResult, NoType, OpReturnValue);
1036 inst->addIdOperand(retVal);
Andrew Woloszynb7946d12016-01-18 09:23:56 -05001037 buildPoint->addInstruction(std::unique_ptr<Instruction>(inst));
John Kessenich140f3df2015-06-26 16:58:36 -06001038 } else
Andrew Woloszynb7946d12016-01-18 09:23:56 -05001039 buildPoint->addInstruction(std::unique_ptr<Instruction>(new Instruction(NoResult, NoType, OpReturn)));
John Kessenich140f3df2015-06-26 16:58:36 -06001040
1041 if (! implicit)
1042 createAndSetNoPredecessorBlock("post-return");
1043}
1044
1045// Comments in header
John Kesseniche770b3e2015-09-14 20:58:02 -06001046void Builder::leaveFunction()
John Kessenich140f3df2015-06-26 16:58:36 -06001047{
1048 Block* block = buildPoint;
1049 Function& function = buildPoint->getParent();
1050 assert(block);
1051
1052 // If our function did not contain a return, add a return void now.
1053 if (! block->isTerminated()) {
Dejan Mircevskied55bcd2016-01-19 21:13:38 -05001054 if (function.getReturnType() == makeVoidType())
1055 makeReturn(true);
1056 else {
1057 makeReturn(true, createUndefined(function.getReturnType()));
John Kessenich140f3df2015-06-26 16:58:36 -06001058 }
1059 }
John Kessenich140f3df2015-06-26 16:58:36 -06001060}
1061
1062// Comments in header
1063void Builder::makeDiscard()
1064{
Andrew Woloszynb7946d12016-01-18 09:23:56 -05001065 buildPoint->addInstruction(std::unique_ptr<Instruction>(new Instruction(OpKill)));
John Kessenich140f3df2015-06-26 16:58:36 -06001066 createAndSetNoPredecessorBlock("post-discard");
1067}
1068
1069// Comments in header
1070Id Builder::createVariable(StorageClass storageClass, Id type, const char* name)
1071{
1072 Id pointerType = makePointer(storageClass, type);
1073 Instruction* inst = new Instruction(getUniqueId(), pointerType, OpVariable);
1074 inst->addImmediateOperand(storageClass);
1075
1076 switch (storageClass) {
John Kessenich140f3df2015-06-26 16:58:36 -06001077 case StorageClassFunction:
1078 // Validation rules require the declaration in the entry block
Andrew Woloszynb7946d12016-01-18 09:23:56 -05001079 buildPoint->getParent().addLocalVariable(std::unique_ptr<Instruction>(inst));
John Kessenich140f3df2015-06-26 16:58:36 -06001080 break;
1081
1082 default:
Andrew Woloszynb7946d12016-01-18 09:23:56 -05001083 constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(inst));
John Kessenich55e7d112015-11-15 21:33:39 -07001084 module.mapInstruction(inst);
John Kessenich140f3df2015-06-26 16:58:36 -06001085 break;
1086 }
1087
1088 if (name)
1089 addName(inst->getResultId(), name);
1090
1091 return inst->getResultId();
1092}
1093
1094// Comments in header
Miro Knejp28f9b1c2015-08-11 02:45:24 +02001095Id Builder::createUndefined(Id type)
1096{
1097 Instruction* inst = new Instruction(getUniqueId(), type, OpUndef);
Andrew Woloszynb7946d12016-01-18 09:23:56 -05001098 buildPoint->addInstruction(std::unique_ptr<Instruction>(inst));
Miro Knejp28f9b1c2015-08-11 02:45:24 +02001099 return inst->getResultId();
1100}
1101
1102// Comments in header
John Kessenich140f3df2015-06-26 16:58:36 -06001103void Builder::createStore(Id rValue, Id lValue)
1104{
1105 Instruction* store = new Instruction(OpStore);
1106 store->addIdOperand(lValue);
1107 store->addIdOperand(rValue);
Andrew Woloszynb7946d12016-01-18 09:23:56 -05001108 buildPoint->addInstruction(std::unique_ptr<Instruction>(store));
John Kessenich140f3df2015-06-26 16:58:36 -06001109}
1110
1111// Comments in header
1112Id Builder::createLoad(Id lValue)
1113{
1114 Instruction* load = new Instruction(getUniqueId(), getDerefTypeId(lValue), OpLoad);
1115 load->addIdOperand(lValue);
Andrew Woloszynb7946d12016-01-18 09:23:56 -05001116 buildPoint->addInstruction(std::unique_ptr<Instruction>(load));
John Kessenich140f3df2015-06-26 16:58:36 -06001117
1118 return load->getResultId();
1119}
1120
1121// Comments in header
Vlad Ivanov689490f2017-01-26 20:46:02 +03001122Id Builder::createAccessChain(StorageClass storageClass, Id base, const std::vector<Id>& offsets)
John Kessenich140f3df2015-06-26 16:58:36 -06001123{
1124 // Figure out the final resulting type.
1125 spv::Id typeId = getTypeId(base);
1126 assert(isPointerType(typeId) && offsets.size() > 0);
1127 typeId = getContainedTypeId(typeId);
1128 for (int i = 0; i < (int)offsets.size(); ++i) {
1129 if (isStructType(typeId)) {
1130 assert(isConstantScalar(offsets[i]));
1131 typeId = getContainedTypeId(typeId, getConstantScalar(offsets[i]));
1132 } else
1133 typeId = getContainedTypeId(typeId, offsets[i]);
1134 }
1135 typeId = makePointer(storageClass, typeId);
1136
1137 // Make the instruction
1138 Instruction* chain = new Instruction(getUniqueId(), typeId, OpAccessChain);
1139 chain->addIdOperand(base);
1140 for (int i = 0; i < (int)offsets.size(); ++i)
1141 chain->addIdOperand(offsets[i]);
Andrew Woloszynb7946d12016-01-18 09:23:56 -05001142 buildPoint->addInstruction(std::unique_ptr<Instruction>(chain));
John Kessenich140f3df2015-06-26 16:58:36 -06001143
1144 return chain->getResultId();
1145}
1146
John Kessenichee21fc92015-09-21 21:50:29 -06001147Id Builder::createArrayLength(Id base, unsigned int member)
1148{
steve-lunarg5da1f032017-02-12 17:50:28 -07001149 spv::Id intType = makeIntType(32);
1150 Instruction* length = new Instruction(getUniqueId(), intType, OpArrayLength);
John Kessenichee21fc92015-09-21 21:50:29 -06001151 length->addIdOperand(base);
1152 length->addImmediateOperand(member);
Andrew Woloszynb7946d12016-01-18 09:23:56 -05001153 buildPoint->addInstruction(std::unique_ptr<Instruction>(length));
John Kessenichee21fc92015-09-21 21:50:29 -06001154
1155 return length->getResultId();
1156}
1157
John Kessenich140f3df2015-06-26 16:58:36 -06001158Id Builder::createCompositeExtract(Id composite, Id typeId, unsigned index)
1159{
qining13545202016-03-21 09:51:37 -04001160 // Generate code for spec constants if in spec constant operation
1161 // generation mode.
1162 if (generatingOpCodeForSpecConst) {
baldurk0dfbe3f2016-04-02 13:38:28 +02001163 return createSpecConstantOp(OpCompositeExtract, typeId, std::vector<Id>(1, composite), std::vector<Id>(1, index));
qining13545202016-03-21 09:51:37 -04001164 }
John Kessenich140f3df2015-06-26 16:58:36 -06001165 Instruction* extract = new Instruction(getUniqueId(), typeId, OpCompositeExtract);
1166 extract->addIdOperand(composite);
1167 extract->addImmediateOperand(index);
Andrew Woloszynb7946d12016-01-18 09:23:56 -05001168 buildPoint->addInstruction(std::unique_ptr<Instruction>(extract));
John Kessenich140f3df2015-06-26 16:58:36 -06001169
1170 return extract->getResultId();
1171}
1172
Vlad Ivanov689490f2017-01-26 20:46:02 +03001173Id Builder::createCompositeExtract(Id composite, Id typeId, const std::vector<unsigned>& indexes)
John Kessenich140f3df2015-06-26 16:58:36 -06001174{
qining13545202016-03-21 09:51:37 -04001175 // Generate code for spec constants if in spec constant operation
1176 // generation mode.
1177 if (generatingOpCodeForSpecConst) {
baldurk0dfbe3f2016-04-02 13:38:28 +02001178 return createSpecConstantOp(OpCompositeExtract, typeId, std::vector<Id>(1, composite), indexes);
qining13545202016-03-21 09:51:37 -04001179 }
John Kessenich140f3df2015-06-26 16:58:36 -06001180 Instruction* extract = new Instruction(getUniqueId(), typeId, OpCompositeExtract);
1181 extract->addIdOperand(composite);
1182 for (int i = 0; i < (int)indexes.size(); ++i)
1183 extract->addImmediateOperand(indexes[i]);
Andrew Woloszynb7946d12016-01-18 09:23:56 -05001184 buildPoint->addInstruction(std::unique_ptr<Instruction>(extract));
John Kessenich140f3df2015-06-26 16:58:36 -06001185
1186 return extract->getResultId();
1187}
1188
1189Id Builder::createCompositeInsert(Id object, Id composite, Id typeId, unsigned index)
1190{
1191 Instruction* insert = new Instruction(getUniqueId(), typeId, OpCompositeInsert);
1192 insert->addIdOperand(object);
1193 insert->addIdOperand(composite);
1194 insert->addImmediateOperand(index);
Andrew Woloszynb7946d12016-01-18 09:23:56 -05001195 buildPoint->addInstruction(std::unique_ptr<Instruction>(insert));
John Kessenich140f3df2015-06-26 16:58:36 -06001196
1197 return insert->getResultId();
1198}
1199
Vlad Ivanov689490f2017-01-26 20:46:02 +03001200Id Builder::createCompositeInsert(Id object, Id composite, Id typeId, const std::vector<unsigned>& indexes)
John Kessenich140f3df2015-06-26 16:58:36 -06001201{
1202 Instruction* insert = new Instruction(getUniqueId(), typeId, OpCompositeInsert);
1203 insert->addIdOperand(object);
1204 insert->addIdOperand(composite);
1205 for (int i = 0; i < (int)indexes.size(); ++i)
1206 insert->addImmediateOperand(indexes[i]);
Andrew Woloszynb7946d12016-01-18 09:23:56 -05001207 buildPoint->addInstruction(std::unique_ptr<Instruction>(insert));
John Kessenich140f3df2015-06-26 16:58:36 -06001208
1209 return insert->getResultId();
1210}
1211
1212Id Builder::createVectorExtractDynamic(Id vector, Id typeId, Id componentIndex)
1213{
1214 Instruction* extract = new Instruction(getUniqueId(), typeId, OpVectorExtractDynamic);
1215 extract->addIdOperand(vector);
1216 extract->addIdOperand(componentIndex);
Andrew Woloszynb7946d12016-01-18 09:23:56 -05001217 buildPoint->addInstruction(std::unique_ptr<Instruction>(extract));
John Kessenich140f3df2015-06-26 16:58:36 -06001218
1219 return extract->getResultId();
1220}
1221
1222Id Builder::createVectorInsertDynamic(Id vector, Id typeId, Id component, Id componentIndex)
1223{
1224 Instruction* insert = new Instruction(getUniqueId(), typeId, OpVectorInsertDynamic);
1225 insert->addIdOperand(vector);
1226 insert->addIdOperand(component);
1227 insert->addIdOperand(componentIndex);
Andrew Woloszynb7946d12016-01-18 09:23:56 -05001228 buildPoint->addInstruction(std::unique_ptr<Instruction>(insert));
John Kessenich140f3df2015-06-26 16:58:36 -06001229
1230 return insert->getResultId();
1231}
1232
1233// An opcode that has no operands, no result id, and no type
1234void Builder::createNoResultOp(Op opCode)
1235{
1236 Instruction* op = new Instruction(opCode);
Andrew Woloszynb7946d12016-01-18 09:23:56 -05001237 buildPoint->addInstruction(std::unique_ptr<Instruction>(op));
John Kessenich140f3df2015-06-26 16:58:36 -06001238}
1239
1240// An opcode that has one operand, no result id, and no type
1241void Builder::createNoResultOp(Op opCode, Id operand)
1242{
1243 Instruction* op = new Instruction(opCode);
1244 op->addIdOperand(operand);
Andrew Woloszynb7946d12016-01-18 09:23:56 -05001245 buildPoint->addInstruction(std::unique_ptr<Instruction>(op));
John Kessenich140f3df2015-06-26 16:58:36 -06001246}
1247
Rex Xufc618912015-09-09 16:42:49 +08001248// An opcode that has one operand, no result id, and no type
1249void Builder::createNoResultOp(Op opCode, const std::vector<Id>& operands)
1250{
1251 Instruction* op = new Instruction(opCode);
rdb32084e82016-02-23 22:17:38 +01001252 for (auto it = operands.cbegin(); it != operands.cend(); ++it)
1253 op->addIdOperand(*it);
Andrew Woloszynb7946d12016-01-18 09:23:56 -05001254 buildPoint->addInstruction(std::unique_ptr<Instruction>(op));
Rex Xufc618912015-09-09 16:42:49 +08001255}
1256
John Kessenich5e4b1242015-08-06 22:53:06 -06001257void Builder::createControlBarrier(Scope execution, Scope memory, MemorySemanticsMask semantics)
John Kessenich140f3df2015-06-26 16:58:36 -06001258{
1259 Instruction* op = new Instruction(OpControlBarrier);
John Kessenich5e4b1242015-08-06 22:53:06 -06001260 op->addImmediateOperand(makeUintConstant(execution));
1261 op->addImmediateOperand(makeUintConstant(memory));
1262 op->addImmediateOperand(makeUintConstant(semantics));
Andrew Woloszynb7946d12016-01-18 09:23:56 -05001263 buildPoint->addInstruction(std::unique_ptr<Instruction>(op));
John Kessenich140f3df2015-06-26 16:58:36 -06001264}
1265
1266void Builder::createMemoryBarrier(unsigned executionScope, unsigned memorySemantics)
1267{
1268 Instruction* op = new Instruction(OpMemoryBarrier);
John Kessenich5e4b1242015-08-06 22:53:06 -06001269 op->addImmediateOperand(makeUintConstant(executionScope));
1270 op->addImmediateOperand(makeUintConstant(memorySemantics));
Andrew Woloszynb7946d12016-01-18 09:23:56 -05001271 buildPoint->addInstruction(std::unique_ptr<Instruction>(op));
John Kessenich140f3df2015-06-26 16:58:36 -06001272}
1273
1274// An opcode that has one operands, a result id, and a type
1275Id Builder::createUnaryOp(Op opCode, Id typeId, Id operand)
1276{
qining13545202016-03-21 09:51:37 -04001277 // Generate code for spec constants if in spec constant operation
1278 // generation mode.
1279 if (generatingOpCodeForSpecConst) {
baldurk0dfbe3f2016-04-02 13:38:28 +02001280 return createSpecConstantOp(opCode, typeId, std::vector<Id>(1, operand), std::vector<Id>());
qining13545202016-03-21 09:51:37 -04001281 }
John Kessenich140f3df2015-06-26 16:58:36 -06001282 Instruction* op = new Instruction(getUniqueId(), typeId, opCode);
1283 op->addIdOperand(operand);
Andrew Woloszynb7946d12016-01-18 09:23:56 -05001284 buildPoint->addInstruction(std::unique_ptr<Instruction>(op));
John Kessenich140f3df2015-06-26 16:58:36 -06001285
1286 return op->getResultId();
1287}
1288
1289Id Builder::createBinOp(Op opCode, Id typeId, Id left, Id right)
1290{
qining13545202016-03-21 09:51:37 -04001291 // Generate code for spec constants if in spec constant operation
1292 // generation mode.
1293 if (generatingOpCodeForSpecConst) {
baldurk0dfbe3f2016-04-02 13:38:28 +02001294 std::vector<Id> operands(2);
1295 operands[0] = left; operands[1] = right;
1296 return createSpecConstantOp(opCode, typeId, operands, std::vector<Id>());
qining13545202016-03-21 09:51:37 -04001297 }
John Kessenich140f3df2015-06-26 16:58:36 -06001298 Instruction* op = new Instruction(getUniqueId(), typeId, opCode);
1299 op->addIdOperand(left);
1300 op->addIdOperand(right);
Andrew Woloszynb7946d12016-01-18 09:23:56 -05001301 buildPoint->addInstruction(std::unique_ptr<Instruction>(op));
John Kessenich140f3df2015-06-26 16:58:36 -06001302
1303 return op->getResultId();
1304}
1305
1306Id Builder::createTriOp(Op opCode, Id typeId, Id op1, Id op2, Id op3)
1307{
qininge24aa5e2016-04-07 15:40:27 -04001308 // Generate code for spec constants if in spec constant operation
1309 // generation mode.
1310 if (generatingOpCodeForSpecConst) {
1311 std::vector<Id> operands(3);
qining189b2032016-04-12 23:16:20 -04001312 operands[0] = op1;
1313 operands[1] = op2;
1314 operands[2] = op3;
qininge24aa5e2016-04-07 15:40:27 -04001315 return createSpecConstantOp(
1316 opCode, typeId, operands, std::vector<Id>());
1317 }
John Kessenich140f3df2015-06-26 16:58:36 -06001318 Instruction* op = new Instruction(getUniqueId(), typeId, opCode);
1319 op->addIdOperand(op1);
1320 op->addIdOperand(op2);
1321 op->addIdOperand(op3);
Andrew Woloszynb7946d12016-01-18 09:23:56 -05001322 buildPoint->addInstruction(std::unique_ptr<Instruction>(op));
John Kessenich140f3df2015-06-26 16:58:36 -06001323
1324 return op->getResultId();
1325}
1326
John Kessenich5e4b1242015-08-06 22:53:06 -06001327Id Builder::createOp(Op opCode, Id typeId, const std::vector<Id>& operands)
John Kessenich140f3df2015-06-26 16:58:36 -06001328{
1329 Instruction* op = new Instruction(getUniqueId(), typeId, opCode);
rdb32084e82016-02-23 22:17:38 +01001330 for (auto it = operands.cbegin(); it != operands.cend(); ++it)
1331 op->addIdOperand(*it);
Andrew Woloszynb7946d12016-01-18 09:23:56 -05001332 buildPoint->addInstruction(std::unique_ptr<Instruction>(op));
John Kessenich140f3df2015-06-26 16:58:36 -06001333
1334 return op->getResultId();
1335}
1336
qining5c61d8e2016-03-31 13:57:28 -04001337Id Builder::createSpecConstantOp(Op opCode, Id typeId, const std::vector<Id>& operands, const std::vector<unsigned>& literals)
1338{
qining13545202016-03-21 09:51:37 -04001339 Instruction* op = new Instruction(getUniqueId(), typeId, OpSpecConstantOp);
1340 op->addImmediateOperand((unsigned) opCode);
1341 for (auto it = operands.cbegin(); it != operands.cend(); ++it)
1342 op->addIdOperand(*it);
1343 for (auto it = literals.cbegin(); it != literals.cend(); ++it)
1344 op->addImmediateOperand(*it);
1345 module.mapInstruction(op);
1346 constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(op));
1347
1348 return op->getResultId();
1349}
1350
Vlad Ivanov689490f2017-01-26 20:46:02 +03001351Id Builder::createFunctionCall(spv::Function* function, const std::vector<spv::Id>& args)
John Kessenich140f3df2015-06-26 16:58:36 -06001352{
1353 Instruction* op = new Instruction(getUniqueId(), function->getReturnType(), OpFunctionCall);
1354 op->addIdOperand(function->getId());
1355 for (int a = 0; a < (int)args.size(); ++a)
1356 op->addIdOperand(args[a]);
Andrew Woloszynb7946d12016-01-18 09:23:56 -05001357 buildPoint->addInstruction(std::unique_ptr<Instruction>(op));
John Kessenich140f3df2015-06-26 16:58:36 -06001358
1359 return op->getResultId();
1360}
1361
1362// Comments in header
Vlad Ivanov689490f2017-01-26 20:46:02 +03001363Id Builder::createRvalueSwizzle(Decoration precision, Id typeId, Id source, const std::vector<unsigned>& channels)
John Kessenich140f3df2015-06-26 16:58:36 -06001364{
1365 if (channels.size() == 1)
John Kessenich32cfd492016-02-02 12:37:46 -07001366 return setPrecision(createCompositeExtract(source, typeId, channels.front()), precision);
John Kessenich140f3df2015-06-26 16:58:36 -06001367
qining13545202016-03-21 09:51:37 -04001368 if (generatingOpCodeForSpecConst) {
baldurk0dfbe3f2016-04-02 13:38:28 +02001369 std::vector<Id> operands(2);
1370 operands[0] = operands[1] = source;
1371 return setPrecision(createSpecConstantOp(OpVectorShuffle, typeId, operands, channels), precision);
qining13545202016-03-21 09:51:37 -04001372 }
John Kessenich140f3df2015-06-26 16:58:36 -06001373 Instruction* swizzle = new Instruction(getUniqueId(), typeId, OpVectorShuffle);
1374 assert(isVector(source));
1375 swizzle->addIdOperand(source);
1376 swizzle->addIdOperand(source);
1377 for (int i = 0; i < (int)channels.size(); ++i)
1378 swizzle->addImmediateOperand(channels[i]);
Andrew Woloszynb7946d12016-01-18 09:23:56 -05001379 buildPoint->addInstruction(std::unique_ptr<Instruction>(swizzle));
John Kessenich140f3df2015-06-26 16:58:36 -06001380
John Kessenich32cfd492016-02-02 12:37:46 -07001381 return setPrecision(swizzle->getResultId(), precision);
John Kessenich140f3df2015-06-26 16:58:36 -06001382}
1383
1384// Comments in header
Vlad Ivanov689490f2017-01-26 20:46:02 +03001385Id Builder::createLvalueSwizzle(Id typeId, Id target, Id source, const std::vector<unsigned>& channels)
John Kessenich140f3df2015-06-26 16:58:36 -06001386{
John Kessenich140f3df2015-06-26 16:58:36 -06001387 if (channels.size() == 1 && getNumComponents(source) == 1)
1388 return createCompositeInsert(source, target, typeId, channels.front());
1389
1390 Instruction* swizzle = new Instruction(getUniqueId(), typeId, OpVectorShuffle);
John Kessenich5c3eed52018-02-05 14:44:14 -07001391
John Kessenich140f3df2015-06-26 16:58:36 -06001392 assert(isVector(target));
1393 swizzle->addIdOperand(target);
John Kessenich5c3eed52018-02-05 14:44:14 -07001394
1395 assert(getNumComponents(source) == (int)channels.size());
1396 assert(isVector(source));
1397 swizzle->addIdOperand(source);
John Kessenich140f3df2015-06-26 16:58:36 -06001398
1399 // Set up an identity shuffle from the base value to the result value
1400 unsigned int components[4];
1401 int numTargetComponents = getNumComponents(target);
1402 for (int i = 0; i < numTargetComponents; ++i)
1403 components[i] = i;
1404
1405 // Punch in the l-value swizzle
John Kessenich5c3eed52018-02-05 14:44:14 -07001406 for (int i = 0; i < (int)channels.size(); ++i)
1407 components[channels[i]] = numTargetComponents + i;
John Kessenich140f3df2015-06-26 16:58:36 -06001408
1409 // finish the instruction with these components selectors
1410 for (int i = 0; i < numTargetComponents; ++i)
1411 swizzle->addImmediateOperand(components[i]);
Andrew Woloszynb7946d12016-01-18 09:23:56 -05001412 buildPoint->addInstruction(std::unique_ptr<Instruction>(swizzle));
John Kessenich140f3df2015-06-26 16:58:36 -06001413
1414 return swizzle->getResultId();
1415}
1416
1417// Comments in header
1418void Builder::promoteScalar(Decoration precision, Id& left, Id& right)
1419{
1420 int direction = getNumComponents(right) - getNumComponents(left);
1421
1422 if (direction > 0)
John Kessenich76f71392015-12-09 19:08:42 -07001423 left = smearScalar(precision, left, makeVectorType(getTypeId(left), getNumComponents(right)));
John Kessenich140f3df2015-06-26 16:58:36 -06001424 else if (direction < 0)
John Kessenich76f71392015-12-09 19:08:42 -07001425 right = smearScalar(precision, right, makeVectorType(getTypeId(right), getNumComponents(left)));
John Kessenich140f3df2015-06-26 16:58:36 -06001426
1427 return;
1428}
1429
1430// Comments in header
John Kessenich32cfd492016-02-02 12:37:46 -07001431Id Builder::smearScalar(Decoration precision, Id scalar, Id vectorType)
John Kessenich140f3df2015-06-26 16:58:36 -06001432{
1433 assert(getNumComponents(scalar) == 1);
John Kessenich76f71392015-12-09 19:08:42 -07001434 assert(getTypeId(scalar) == getScalarTypeId(vectorType));
John Kessenich140f3df2015-06-26 16:58:36 -06001435
1436 int numComponents = getNumTypeComponents(vectorType);
1437 if (numComponents == 1)
1438 return scalar;
1439
qining13545202016-03-21 09:51:37 -04001440 Instruction* smear = nullptr;
1441 if (generatingOpCodeForSpecConst) {
1442 auto members = std::vector<spv::Id>(numComponents, scalar);
qining1f2820a2016-04-14 18:34:27 -04001443 // Sometime even in spec-constant-op mode, the temporary vector created by
1444 // promoting a scalar might not be a spec constant. This should depend on
1445 // the scalar.
1446 // e.g.:
1447 // const vec2 spec_const_result = a_spec_const_vec2 + a_front_end_const_scalar;
1448 // In such cases, the temporary vector created from a_front_end_const_scalar
1449 // is not a spec constant vector, even though the binary operation node is marked
1450 // as 'specConstant' and we are in spec-constant-op mode.
qining27e04a02016-04-14 16:40:20 -04001451 auto result_id = makeCompositeConstant(vectorType, members, isSpecConstant(scalar));
qining13545202016-03-21 09:51:37 -04001452 smear = module.getInstruction(result_id);
1453 } else {
1454 smear = new Instruction(getUniqueId(), vectorType, OpCompositeConstruct);
1455 for (int c = 0; c < numComponents; ++c)
1456 smear->addIdOperand(scalar);
1457 buildPoint->addInstruction(std::unique_ptr<Instruction>(smear));
1458 }
John Kessenich140f3df2015-06-26 16:58:36 -06001459
John Kessenich32cfd492016-02-02 12:37:46 -07001460 return setPrecision(smear->getResultId(), precision);
John Kessenich140f3df2015-06-26 16:58:36 -06001461}
1462
1463// Comments in header
Vlad Ivanov689490f2017-01-26 20:46:02 +03001464Id Builder::createBuiltinCall(Id resultType, Id builtins, int entryPoint, const std::vector<Id>& args)
John Kessenich140f3df2015-06-26 16:58:36 -06001465{
1466 Instruction* inst = new Instruction(getUniqueId(), resultType, OpExtInst);
1467 inst->addIdOperand(builtins);
1468 inst->addImmediateOperand(entryPoint);
1469 for (int arg = 0; arg < (int)args.size(); ++arg)
1470 inst->addIdOperand(args[arg]);
1471
Andrew Woloszynb7946d12016-01-18 09:23:56 -05001472 buildPoint->addInstruction(std::unique_ptr<Instruction>(inst));
John Kessenich32cfd492016-02-02 12:37:46 -07001473
John Kessenich140f3df2015-06-26 16:58:36 -06001474 return inst->getResultId();
1475}
1476
1477// Accept all parameters needed to create a texture instruction.
1478// Create the correct instruction based on the inputs, and make the call.
John Kessenich019f08f2016-02-15 15:40:42 -07001479Id Builder::createTextureCall(Decoration precision, Id resultType, bool sparse, bool fetch, bool proj, bool gather, bool noImplicitLod, const TextureParameters& parameters)
John Kessenich140f3df2015-06-26 16:58:36 -06001480{
John Kessenich5e4b1242015-08-06 22:53:06 -06001481 static const int maxTextureArgs = 10;
John Kessenich140f3df2015-06-26 16:58:36 -06001482 Id texArgs[maxTextureArgs] = {};
1483
1484 //
John Kessenich5e4b1242015-08-06 22:53:06 -06001485 // Set up the fixed arguments
John Kessenich140f3df2015-06-26 16:58:36 -06001486 //
John Kessenich140f3df2015-06-26 16:58:36 -06001487 int numArgs = 0;
John Kessenich019f08f2016-02-15 15:40:42 -07001488 bool explicitLod = false;
John Kessenich140f3df2015-06-26 16:58:36 -06001489 texArgs[numArgs++] = parameters.sampler;
1490 texArgs[numArgs++] = parameters.coords;
John Kessenich76d4dfc2016-06-16 12:43:23 -06001491 if (parameters.Dref != NoResult)
John Kessenich140f3df2015-06-26 16:58:36 -06001492 texArgs[numArgs++] = parameters.Dref;
John Kessenich76d4dfc2016-06-16 12:43:23 -06001493 if (parameters.component != NoResult)
1494 texArgs[numArgs++] = parameters.component;
John Kessenich140f3df2015-06-26 16:58:36 -06001495
1496 //
John Kessenich5e4b1242015-08-06 22:53:06 -06001497 // Set up the optional arguments
1498 //
1499 int optArgNum = numArgs; // track which operand, if it exists, is the mask of optional arguments
1500 ++numArgs; // speculatively make room for the mask operand
1501 ImageOperandsMask mask = ImageOperandsMaskNone; // the mask operand
1502 if (parameters.bias) {
1503 mask = (ImageOperandsMask)(mask | ImageOperandsBiasMask);
1504 texArgs[numArgs++] = parameters.bias;
1505 }
1506 if (parameters.lod) {
1507 mask = (ImageOperandsMask)(mask | ImageOperandsLodMask);
1508 texArgs[numArgs++] = parameters.lod;
John Kessenich019f08f2016-02-15 15:40:42 -07001509 explicitLod = true;
1510 } else if (parameters.gradX) {
John Kessenich5e4b1242015-08-06 22:53:06 -06001511 mask = (ImageOperandsMask)(mask | ImageOperandsGradMask);
1512 texArgs[numArgs++] = parameters.gradX;
1513 texArgs[numArgs++] = parameters.gradY;
John Kessenich019f08f2016-02-15 15:40:42 -07001514 explicitLod = true;
1515 } else if (noImplicitLod && ! fetch && ! gather) {
1516 // have to explicitly use lod of 0 if not allowed to have them be implicit, and
1517 // we would otherwise be about to issue an implicit instruction
1518 mask = (ImageOperandsMask)(mask | ImageOperandsLodMask);
1519 texArgs[numArgs++] = makeFloatConstant(0.0);
1520 explicitLod = true;
John Kessenich5e4b1242015-08-06 22:53:06 -06001521 }
1522 if (parameters.offset) {
Rex Xu86e60812015-10-11 19:37:48 +08001523 if (isConstant(parameters.offset))
1524 mask = (ImageOperandsMask)(mask | ImageOperandsConstOffsetMask);
Rex Xu58390312016-05-11 16:38:50 +08001525 else {
1526 addCapability(CapabilityImageGatherExtended);
Rex Xu86e60812015-10-11 19:37:48 +08001527 mask = (ImageOperandsMask)(mask | ImageOperandsOffsetMask);
Rex Xu58390312016-05-11 16:38:50 +08001528 }
John Kessenich5e4b1242015-08-06 22:53:06 -06001529 texArgs[numArgs++] = parameters.offset;
1530 }
John Kessenich5e4b1242015-08-06 22:53:06 -06001531 if (parameters.offsets) {
1532 mask = (ImageOperandsMask)(mask | ImageOperandsConstOffsetsMask);
1533 texArgs[numArgs++] = parameters.offsets;
1534 }
1535 if (parameters.sample) {
1536 mask = (ImageOperandsMask)(mask | ImageOperandsSampleMask);
1537 texArgs[numArgs++] = parameters.sample;
1538 }
Rex Xu48edadf2015-12-31 16:11:41 +08001539 if (parameters.lodClamp) {
John Kessenich5e801132016-02-15 11:09:46 -07001540 // capability if this bit is used
1541 addCapability(CapabilityMinLod);
1542
Rex Xu48edadf2015-12-31 16:11:41 +08001543 mask = (ImageOperandsMask)(mask | ImageOperandsMinLodMask);
1544 texArgs[numArgs++] = parameters.lodClamp;
1545 }
John Kessenich5e4b1242015-08-06 22:53:06 -06001546 if (mask == ImageOperandsMaskNone)
1547 --numArgs; // undo speculative reservation for the mask argument
1548 else
1549 texArgs[optArgNum] = mask;
1550
1551 //
John Kessenich140f3df2015-06-26 16:58:36 -06001552 // Set up the instruction
1553 //
John Kessenich019f08f2016-02-15 15:40:42 -07001554 Op opCode = OpNop; // All paths below need to set this
Jason Ekstrand18b9fbd2015-09-05 14:14:48 -07001555 if (fetch) {
Rex Xu48edadf2015-12-31 16:11:41 +08001556 if (sparse)
1557 opCode = OpImageSparseFetch;
1558 else
1559 opCode = OpImageFetch;
John Kessenich55e7d112015-11-15 21:33:39 -07001560 } else if (gather) {
1561 if (parameters.Dref)
Rex Xu48edadf2015-12-31 16:11:41 +08001562 if (sparse)
1563 opCode = OpImageSparseDrefGather;
1564 else
1565 opCode = OpImageDrefGather;
John Kessenich55e7d112015-11-15 21:33:39 -07001566 else
Rex Xu48edadf2015-12-31 16:11:41 +08001567 if (sparse)
1568 opCode = OpImageSparseGather;
1569 else
1570 opCode = OpImageGather;
John Kessenich019f08f2016-02-15 15:40:42 -07001571 } else if (explicitLod) {
John Kessenich5e4b1242015-08-06 22:53:06 -06001572 if (parameters.Dref) {
1573 if (proj)
Rex Xu48edadf2015-12-31 16:11:41 +08001574 if (sparse)
1575 opCode = OpImageSparseSampleProjDrefExplicitLod;
1576 else
1577 opCode = OpImageSampleProjDrefExplicitLod;
John Kessenich5e4b1242015-08-06 22:53:06 -06001578 else
Rex Xu48edadf2015-12-31 16:11:41 +08001579 if (sparse)
1580 opCode = OpImageSparseSampleDrefExplicitLod;
1581 else
1582 opCode = OpImageSampleDrefExplicitLod;
John Kessenich5e4b1242015-08-06 22:53:06 -06001583 } else {
1584 if (proj)
Rex Xu48edadf2015-12-31 16:11:41 +08001585 if (sparse)
1586 opCode = OpImageSparseSampleProjExplicitLod;
1587 else
1588 opCode = OpImageSampleProjExplicitLod;
John Kessenich5e4b1242015-08-06 22:53:06 -06001589 else
Rex Xu48edadf2015-12-31 16:11:41 +08001590 if (sparse)
1591 opCode = OpImageSparseSampleExplicitLod;
1592 else
1593 opCode = OpImageSampleExplicitLod;
John Kessenich5e4b1242015-08-06 22:53:06 -06001594 }
1595 } else {
1596 if (parameters.Dref) {
1597 if (proj)
Rex Xu48edadf2015-12-31 16:11:41 +08001598 if (sparse)
1599 opCode = OpImageSparseSampleProjDrefImplicitLod;
1600 else
1601 opCode = OpImageSampleProjDrefImplicitLod;
John Kessenich5e4b1242015-08-06 22:53:06 -06001602 else
Rex Xu48edadf2015-12-31 16:11:41 +08001603 if (sparse)
1604 opCode = OpImageSparseSampleDrefImplicitLod;
1605 else
1606 opCode = OpImageSampleDrefImplicitLod;
John Kessenich5e4b1242015-08-06 22:53:06 -06001607 } else {
1608 if (proj)
Rex Xu48edadf2015-12-31 16:11:41 +08001609 if (sparse)
1610 opCode = OpImageSparseSampleProjImplicitLod;
1611 else
1612 opCode = OpImageSampleProjImplicitLod;
John Kessenich5e4b1242015-08-06 22:53:06 -06001613 else
Rex Xu48edadf2015-12-31 16:11:41 +08001614 if (sparse)
1615 opCode = OpImageSparseSampleImplicitLod;
1616 else
1617 opCode = OpImageSampleImplicitLod;
John Kessenich5e4b1242015-08-06 22:53:06 -06001618 }
1619 }
John Kessenich140f3df2015-06-26 16:58:36 -06001620
John Kessenich7355eeb2015-09-14 22:08:12 -06001621 // See if the result type is expecting a smeared result.
1622 // This happens when a legacy shadow*() call is made, which
1623 // gets a vec4 back instead of a float.
1624 Id smearedType = resultType;
1625 if (! isScalarType(resultType)) {
1626 switch (opCode) {
1627 case OpImageSampleDrefImplicitLod:
1628 case OpImageSampleDrefExplicitLod:
1629 case OpImageSampleProjDrefImplicitLod:
1630 case OpImageSampleProjDrefExplicitLod:
1631 resultType = getScalarTypeId(resultType);
1632 break;
1633 default:
1634 break;
1635 }
1636 }
1637
Rex Xu48edadf2015-12-31 16:11:41 +08001638 Id typeId0 = 0;
1639 Id typeId1 = 0;
1640
1641 if (sparse) {
1642 typeId0 = resultType;
1643 typeId1 = getDerefTypeId(parameters.texelOut);
1644 resultType = makeStructResultType(typeId0, typeId1);
1645 }
1646
John Kessenich55e7d112015-11-15 21:33:39 -07001647 // Build the SPIR-V instruction
John Kessenich140f3df2015-06-26 16:58:36 -06001648 Instruction* textureInst = new Instruction(getUniqueId(), resultType, opCode);
John Kessenich5e4b1242015-08-06 22:53:06 -06001649 for (int op = 0; op < optArgNum; ++op)
1650 textureInst->addIdOperand(texArgs[op]);
1651 if (optArgNum < numArgs)
1652 textureInst->addImmediateOperand(texArgs[optArgNum]);
1653 for (int op = optArgNum + 1; op < numArgs; ++op)
John Kessenich140f3df2015-06-26 16:58:36 -06001654 textureInst->addIdOperand(texArgs[op]);
1655 setPrecision(textureInst->getResultId(), precision);
Andrew Woloszynb7946d12016-01-18 09:23:56 -05001656 buildPoint->addInstruction(std::unique_ptr<Instruction>(textureInst));
John Kessenich140f3df2015-06-26 16:58:36 -06001657
John Kessenich7355eeb2015-09-14 22:08:12 -06001658 Id resultId = textureInst->getResultId();
1659
Rex Xu48edadf2015-12-31 16:11:41 +08001660 if (sparse) {
John Kessenich5e801132016-02-15 11:09:46 -07001661 // set capability
1662 addCapability(CapabilitySparseResidency);
1663
Rex Xu48edadf2015-12-31 16:11:41 +08001664 // Decode the return type that was a special structure
1665 createStore(createCompositeExtract(resultId, typeId1, 1), parameters.texelOut);
1666 resultId = createCompositeExtract(resultId, typeId0, 0);
John Kessenich32cfd492016-02-02 12:37:46 -07001667 setPrecision(resultId, precision);
Rex Xu48edadf2015-12-31 16:11:41 +08001668 } else {
1669 // When a smear is needed, do it, as per what was computed
1670 // above when resultType was changed to a scalar type.
1671 if (resultType != smearedType)
1672 resultId = smearScalar(precision, resultId, smearedType);
1673 }
John Kessenich7355eeb2015-09-14 22:08:12 -06001674
1675 return resultId;
John Kessenich140f3df2015-06-26 16:58:36 -06001676}
1677
1678// Comments in header
steve-lunarg0b5c2ae2017-03-10 12:45:50 -07001679Id Builder::createTextureQueryCall(Op opCode, const TextureParameters& parameters, bool isUnsignedResult)
John Kessenich140f3df2015-06-26 16:58:36 -06001680{
John Kessenich5e801132016-02-15 11:09:46 -07001681 // All these need a capability
1682 addCapability(CapabilityImageQuery);
1683
John Kessenich140f3df2015-06-26 16:58:36 -06001684 // Figure out the result type
John Kessenich5e4b1242015-08-06 22:53:06 -06001685 Id resultType = 0;
John Kessenich140f3df2015-06-26 16:58:36 -06001686 switch (opCode) {
John Kessenich5e4b1242015-08-06 22:53:06 -06001687 case OpImageQuerySize:
1688 case OpImageQuerySizeLod:
John Kessenich140f3df2015-06-26 16:58:36 -06001689 {
Mark Adams364c21c2016-01-06 13:41:02 -05001690 int numComponents = 0;
John Kessenich5e4b1242015-08-06 22:53:06 -06001691 switch (getTypeDimensionality(getImageType(parameters.sampler))) {
John Kessenich140f3df2015-06-26 16:58:36 -06001692 case Dim1D:
1693 case DimBuffer:
1694 numComponents = 1;
1695 break;
1696 case Dim2D:
1697 case DimCube:
1698 case DimRect:
John Kessenich50e57562015-12-21 21:21:11 -07001699 case DimSubpassData:
John Kessenich140f3df2015-06-26 16:58:36 -06001700 numComponents = 2;
1701 break;
1702 case Dim3D:
1703 numComponents = 3;
1704 break;
John Kessenich55e7d112015-11-15 21:33:39 -07001705
John Kessenich140f3df2015-06-26 16:58:36 -06001706 default:
John Kessenich55e7d112015-11-15 21:33:39 -07001707 assert(0);
John Kessenich140f3df2015-06-26 16:58:36 -06001708 break;
1709 }
John Kessenich5e4b1242015-08-06 22:53:06 -06001710 if (isArrayedImageType(getImageType(parameters.sampler)))
John Kessenich140f3df2015-06-26 16:58:36 -06001711 ++numComponents;
steve-lunarg0b5c2ae2017-03-10 12:45:50 -07001712
1713 Id intType = isUnsignedResult ? makeUintType(32) : makeIntType(32);
John Kessenich140f3df2015-06-26 16:58:36 -06001714 if (numComponents == 1)
steve-lunarg0b5c2ae2017-03-10 12:45:50 -07001715 resultType = intType;
John Kessenich140f3df2015-06-26 16:58:36 -06001716 else
steve-lunarg0b5c2ae2017-03-10 12:45:50 -07001717 resultType = makeVectorType(intType, numComponents);
John Kessenich140f3df2015-06-26 16:58:36 -06001718
1719 break;
1720 }
John Kessenich5e4b1242015-08-06 22:53:06 -06001721 case OpImageQueryLod:
John Kessenich140f3df2015-06-26 16:58:36 -06001722 resultType = makeVectorType(makeFloatType(32), 2);
1723 break;
John Kessenich5e4b1242015-08-06 22:53:06 -06001724 case OpImageQueryLevels:
1725 case OpImageQuerySamples:
steve-lunarg0b5c2ae2017-03-10 12:45:50 -07001726 resultType = isUnsignedResult ? makeUintType(32) : makeIntType(32);
John Kessenich140f3df2015-06-26 16:58:36 -06001727 break;
1728 default:
John Kessenich55e7d112015-11-15 21:33:39 -07001729 assert(0);
1730 break;
John Kessenich140f3df2015-06-26 16:58:36 -06001731 }
1732
1733 Instruction* query = new Instruction(getUniqueId(), resultType, opCode);
1734 query->addIdOperand(parameters.sampler);
1735 if (parameters.coords)
1736 query->addIdOperand(parameters.coords);
1737 if (parameters.lod)
1738 query->addIdOperand(parameters.lod);
Andrew Woloszynb7946d12016-01-18 09:23:56 -05001739 buildPoint->addInstruction(std::unique_ptr<Instruction>(query));
John Kessenich140f3df2015-06-26 16:58:36 -06001740
1741 return query->getResultId();
1742}
1743
John Kessenich22118352015-12-21 20:54:09 -07001744// External comments in header.
1745// Operates recursively to visit the composite's hierarchy.
1746Id Builder::createCompositeCompare(Decoration precision, Id value1, Id value2, bool equal)
John Kessenich140f3df2015-06-26 16:58:36 -06001747{
1748 Id boolType = makeBoolType();
1749 Id valueType = getTypeId(value1);
1750
Mark Adamsd5ac5382016-02-01 19:13:06 -08001751 Id resultId = NoResult;
John Kessenich140f3df2015-06-26 16:58:36 -06001752
John Kessenich22118352015-12-21 20:54:09 -07001753 int numConstituents = getNumTypeConstituents(valueType);
John Kessenich140f3df2015-06-26 16:58:36 -06001754
John Kessenich22118352015-12-21 20:54:09 -07001755 // Scalars and Vectors
1756
1757 if (isScalarType(valueType) || isVectorType(valueType)) {
John Kesseniche23c9842016-01-04 23:49:03 -07001758 assert(valueType == getTypeId(value2));
John Kessenich22118352015-12-21 20:54:09 -07001759 // These just need a single comparison, just have
1760 // to figure out what it is.
John Kessenich140f3df2015-06-26 16:58:36 -06001761 Op op;
John Kessenich22118352015-12-21 20:54:09 -07001762 switch (getMostBasicTypeClass(valueType)) {
1763 case OpTypeFloat:
John Kessenich140f3df2015-06-26 16:58:36 -06001764 op = equal ? OpFOrdEqual : OpFOrdNotEqual;
John Kessenich22118352015-12-21 20:54:09 -07001765 break;
1766 case OpTypeInt:
Mark Adamsd5ac5382016-02-01 19:13:06 -08001767 default:
John Kessenich140f3df2015-06-26 16:58:36 -06001768 op = equal ? OpIEqual : OpINotEqual;
John Kessenich22118352015-12-21 20:54:09 -07001769 break;
1770 case OpTypeBool:
1771 op = equal ? OpLogicalEqual : OpLogicalNotEqual;
1772 precision = NoPrecision;
1773 break;
1774 }
John Kessenich140f3df2015-06-26 16:58:36 -06001775
John Kessenich22118352015-12-21 20:54:09 -07001776 if (isScalarType(valueType)) {
1777 // scalar
1778 resultId = createBinOp(op, boolType, value1, value2);
John Kessenich22118352015-12-21 20:54:09 -07001779 } else {
1780 // vector
1781 resultId = createBinOp(op, makeVectorType(boolType, numConstituents), value1, value2);
1782 setPrecision(resultId, precision);
1783 // reduce vector compares...
1784 resultId = createUnaryOp(equal ? OpAll : OpAny, boolType, resultId);
1785 }
John Kessenich140f3df2015-06-26 16:58:36 -06001786
John Kessenich32cfd492016-02-02 12:37:46 -07001787 return setPrecision(resultId, precision);
John Kessenich140f3df2015-06-26 16:58:36 -06001788 }
1789
John Kessenich22118352015-12-21 20:54:09 -07001790 // Only structs, arrays, and matrices should be left.
1791 // They share in common the reduction operation across their constituents.
1792 assert(isAggregateType(valueType) || isMatrixType(valueType));
John Kessenich140f3df2015-06-26 16:58:36 -06001793
John Kessenich22118352015-12-21 20:54:09 -07001794 // Compare each pair of constituents
1795 for (int constituent = 0; constituent < numConstituents; ++constituent) {
1796 std::vector<unsigned> indexes(1, constituent);
John Kesseniche23c9842016-01-04 23:49:03 -07001797 Id constituentType1 = getContainedTypeId(getTypeId(value1), constituent);
1798 Id constituentType2 = getContainedTypeId(getTypeId(value2), constituent);
1799 Id constituent1 = createCompositeExtract(value1, constituentType1, indexes);
1800 Id constituent2 = createCompositeExtract(value2, constituentType2, indexes);
John Kessenich140f3df2015-06-26 16:58:36 -06001801
John Kessenich22118352015-12-21 20:54:09 -07001802 Id subResultId = createCompositeCompare(precision, constituent1, constituent2, equal);
John Kessenich140f3df2015-06-26 16:58:36 -06001803
John Kessenich22118352015-12-21 20:54:09 -07001804 if (constituent == 0)
1805 resultId = subResultId;
1806 else
John Kessenich32cfd492016-02-02 12:37:46 -07001807 resultId = setPrecision(createBinOp(equal ? OpLogicalAnd : OpLogicalOr, boolType, resultId, subResultId), precision);
John Kessenich22118352015-12-21 20:54:09 -07001808 }
John Kessenich140f3df2015-06-26 16:58:36 -06001809
John Kessenich22118352015-12-21 20:54:09 -07001810 return resultId;
John Kessenich140f3df2015-06-26 16:58:36 -06001811}
1812
John Kessenich140f3df2015-06-26 16:58:36 -06001813// OpCompositeConstruct
Vlad Ivanov689490f2017-01-26 20:46:02 +03001814Id Builder::createCompositeConstruct(Id typeId, const std::vector<Id>& constituents)
John Kessenich140f3df2015-06-26 16:58:36 -06001815{
John Kessenich22118352015-12-21 20:54:09 -07001816 assert(isAggregateType(typeId) || (getNumTypeConstituents(typeId) > 1 && getNumTypeConstituents(typeId) == (int)constituents.size()));
John Kessenich140f3df2015-06-26 16:58:36 -06001817
qining27e04a02016-04-14 16:40:20 -04001818 if (generatingOpCodeForSpecConst) {
qining1f2820a2016-04-14 18:34:27 -04001819 // Sometime, even in spec-constant-op mode, the constant composite to be
1820 // constructed may not be a specialization constant.
1821 // e.g.:
1822 // const mat2 m2 = mat2(a_spec_const, a_front_end_const, another_front_end_const, third_front_end_const);
1823 // The first column vector should be a spec constant one, as a_spec_const is a spec constant.
1824 // The second column vector should NOT be spec constant, as it does not contain any spec constants.
1825 // To handle such cases, we check the constituents of the constant vector to determine whether this
1826 // vector should be created as a spec constant.
1827 return makeCompositeConstant(typeId, constituents,
1828 std::any_of(constituents.begin(), constituents.end(),
1829 [&](spv::Id id) { return isSpecConstant(id); }));
qining27e04a02016-04-14 16:40:20 -04001830 }
1831
John Kessenich140f3df2015-06-26 16:58:36 -06001832 Instruction* op = new Instruction(getUniqueId(), typeId, OpCompositeConstruct);
1833 for (int c = 0; c < (int)constituents.size(); ++c)
1834 op->addIdOperand(constituents[c]);
Andrew Woloszynb7946d12016-01-18 09:23:56 -05001835 buildPoint->addInstruction(std::unique_ptr<Instruction>(op));
John Kessenich140f3df2015-06-26 16:58:36 -06001836
1837 return op->getResultId();
1838}
1839
1840// Vector or scalar constructor
1841Id Builder::createConstructor(Decoration precision, const std::vector<Id>& sources, Id resultTypeId)
1842{
John Kessenich32cfd492016-02-02 12:37:46 -07001843 Id result = NoResult;
John Kessenich140f3df2015-06-26 16:58:36 -06001844 unsigned int numTargetComponents = getNumTypeComponents(resultTypeId);
1845 unsigned int targetComponent = 0;
1846
1847 // Special case: when calling a vector constructor with a single scalar
1848 // argument, smear the scalar
1849 if (sources.size() == 1 && isScalar(sources[0]) && numTargetComponents > 1)
1850 return smearScalar(precision, sources[0], resultTypeId);
1851
John Kessenich0302bdf2017-02-17 19:06:21 -07001852 // accumulate the arguments for OpCompositeConstruct
1853 std::vector<Id> constituents;
John Kessenich140f3df2015-06-26 16:58:36 -06001854 Id scalarTypeId = getScalarTypeId(resultTypeId);
John Kessenich0302bdf2017-02-17 19:06:21 -07001855
1856 // lambda to store the result of visiting an argument component
1857 const auto latchResult = [&](Id comp) {
1858 if (numTargetComponents > 1)
1859 constituents.push_back(comp);
1860 else
1861 result = comp;
1862 ++targetComponent;
1863 };
1864
1865 // lambda to visit a vector argument's components
1866 const auto accumulateVectorConstituents = [&](Id sourceArg) {
1867 unsigned int sourceSize = getNumComponents(sourceArg);
John Kessenich140f3df2015-06-26 16:58:36 -06001868 unsigned int sourcesToUse = sourceSize;
1869 if (sourcesToUse + targetComponent > numTargetComponents)
1870 sourcesToUse = numTargetComponents - targetComponent;
1871
1872 for (unsigned int s = 0; s < sourcesToUse; ++s) {
John Kessenich0302bdf2017-02-17 19:06:21 -07001873 std::vector<unsigned> swiz;
1874 swiz.push_back(s);
1875 latchResult(createRvalueSwizzle(precision, scalarTypeId, sourceArg, swiz));
John Kessenich140f3df2015-06-26 16:58:36 -06001876 }
John Kessenich0302bdf2017-02-17 19:06:21 -07001877 };
1878
1879 // lambda to visit a matrix argument's components
1880 const auto accumulateMatrixConstituents = [&](Id sourceArg) {
1881 unsigned int sourceSize = getNumColumns(sourceArg) * getNumRows(sourceArg);
1882 unsigned int sourcesToUse = sourceSize;
1883 if (sourcesToUse + targetComponent > numTargetComponents)
1884 sourcesToUse = numTargetComponents - targetComponent;
1885
1886 int col = 0;
1887 int row = 0;
1888 for (unsigned int s = 0; s < sourcesToUse; ++s) {
1889 if (row >= getNumRows(sourceArg)) {
1890 row = 0;
1891 col++;
1892 }
1893 std::vector<Id> indexes;
1894 indexes.push_back(col);
1895 indexes.push_back(row);
1896 latchResult(createCompositeExtract(sourceArg, scalarTypeId, indexes));
1897 row++;
1898 }
1899 };
1900
1901 // Go through the source arguments, each one could have either
1902 // a single or multiple components to contribute.
1903 for (unsigned int i = 0; i < sources.size(); ++i) {
1904 if (isScalar(sources[i]))
1905 latchResult(sources[i]);
1906 else if (isVector(sources[i]))
1907 accumulateVectorConstituents(sources[i]);
1908 else if (isMatrix(sources[i]))
1909 accumulateMatrixConstituents(sources[i]);
1910 else
1911 assert(0);
John Kessenich140f3df2015-06-26 16:58:36 -06001912
1913 if (targetComponent >= numTargetComponents)
1914 break;
1915 }
1916
John Kessenich0302bdf2017-02-17 19:06:21 -07001917 // If the result is a vector, make it from the gathered constituents.
John Kessenich140f3df2015-06-26 16:58:36 -06001918 if (constituents.size() > 0)
1919 result = createCompositeConstruct(resultTypeId, constituents);
1920
John Kessenich32cfd492016-02-02 12:37:46 -07001921 return setPrecision(result, precision);
John Kessenich140f3df2015-06-26 16:58:36 -06001922}
1923
1924// Comments in header
1925Id Builder::createMatrixConstructor(Decoration precision, const std::vector<Id>& sources, Id resultTypeId)
1926{
1927 Id componentTypeId = getScalarTypeId(resultTypeId);
1928 int numCols = getTypeNumColumns(resultTypeId);
1929 int numRows = getTypeNumRows(resultTypeId);
1930
iostrowsaf7f1c82016-06-01 16:40:00 +02001931 Instruction* instr = module.getInstruction(componentTypeId);
1932 Id bitCount = instr->getIdOperand(0);
1933
John Kessenich140f3df2015-06-26 16:58:36 -06001934 // Will use a two step process
1935 // 1. make a compile-time 2D array of values
1936 // 2. construct a matrix from that array
1937
1938 // Step 1.
1939
1940 // initialize the array to the identity matrix
1941 Id ids[maxMatrixSize][maxMatrixSize];
iostrowsaf7f1c82016-06-01 16:40:00 +02001942 Id one = (bitCount == 64 ? makeDoubleConstant(1.0) : makeFloatConstant(1.0));
1943 Id zero = (bitCount == 64 ? makeDoubleConstant(0.0) : makeFloatConstant(0.0));
John Kessenich140f3df2015-06-26 16:58:36 -06001944 for (int col = 0; col < 4; ++col) {
1945 for (int row = 0; row < 4; ++row) {
1946 if (col == row)
1947 ids[col][row] = one;
1948 else
1949 ids[col][row] = zero;
1950 }
1951 }
1952
1953 // modify components as dictated by the arguments
1954 if (sources.size() == 1 && isScalar(sources[0])) {
1955 // a single scalar; resets the diagonals
1956 for (int col = 0; col < 4; ++col)
1957 ids[col][col] = sources[0];
1958 } else if (isMatrix(sources[0])) {
1959 // constructing from another matrix; copy over the parts that exist in both the argument and constructee
1960 Id matrix = sources[0];
1961 int minCols = std::min(numCols, getNumColumns(matrix));
1962 int minRows = std::min(numRows, getNumRows(matrix));
1963 for (int col = 0; col < minCols; ++col) {
1964 std::vector<unsigned> indexes;
1965 indexes.push_back(col);
1966 for (int row = 0; row < minRows; ++row) {
1967 indexes.push_back(row);
1968 ids[col][row] = createCompositeExtract(matrix, componentTypeId, indexes);
1969 indexes.pop_back();
1970 setPrecision(ids[col][row], precision);
1971 }
1972 }
1973 } else {
1974 // fill in the matrix in column-major order with whatever argument components are available
1975 int row = 0;
1976 int col = 0;
1977
1978 for (int arg = 0; arg < (int)sources.size(); ++arg) {
1979 Id argComp = sources[arg];
1980 for (int comp = 0; comp < getNumComponents(sources[arg]); ++comp) {
1981 if (getNumComponents(sources[arg]) > 1) {
1982 argComp = createCompositeExtract(sources[arg], componentTypeId, comp);
1983 setPrecision(argComp, precision);
1984 }
1985 ids[col][row++] = argComp;
1986 if (row == numRows) {
1987 row = 0;
1988 col++;
1989 }
1990 }
1991 }
1992 }
1993
John Kessenich140f3df2015-06-26 16:58:36 -06001994 // Step 2: Construct a matrix from that array.
1995 // First make the column vectors, then make the matrix.
1996
1997 // make the column vectors
1998 Id columnTypeId = getContainedTypeId(resultTypeId);
1999 std::vector<Id> matrixColumns;
2000 for (int col = 0; col < numCols; ++col) {
2001 std::vector<Id> vectorComponents;
2002 for (int row = 0; row < numRows; ++row)
2003 vectorComponents.push_back(ids[col][row]);
John Kessenich32cfd492016-02-02 12:37:46 -07002004 Id column = createCompositeConstruct(columnTypeId, vectorComponents);
2005 setPrecision(column, precision);
2006 matrixColumns.push_back(column);
John Kessenich140f3df2015-06-26 16:58:36 -06002007 }
2008
2009 // make the matrix
John Kessenich32cfd492016-02-02 12:37:46 -07002010 return setPrecision(createCompositeConstruct(resultTypeId, matrixColumns), precision);
John Kessenich140f3df2015-06-26 16:58:36 -06002011}
2012
2013// Comments in header
Rex Xu57e65922017-07-04 23:23:40 +08002014Builder::If::If(Id cond, unsigned int ctrl, Builder& gb) :
John Kessenich140f3df2015-06-26 16:58:36 -06002015 builder(gb),
2016 condition(cond),
Rex Xu57e65922017-07-04 23:23:40 +08002017 control(ctrl),
John Kessenich140f3df2015-06-26 16:58:36 -06002018 elseBlock(0)
2019{
2020 function = &builder.getBuildPoint()->getParent();
2021
2022 // make the blocks, but only put the then-block into the function,
2023 // the else-block and merge-block will be added later, in order, after
2024 // earlier code is emitted
2025 thenBlock = new Block(builder.getUniqueId(), *function);
2026 mergeBlock = new Block(builder.getUniqueId(), *function);
2027
2028 // Save the current block, so that we can add in the flow control split when
2029 // makeEndIf is called.
2030 headerBlock = builder.getBuildPoint();
2031
2032 function->addBlock(thenBlock);
2033 builder.setBuildPoint(thenBlock);
2034}
2035
2036// Comments in header
2037void Builder::If::makeBeginElse()
2038{
2039 // Close out the "then" by having it jump to the mergeBlock
2040 builder.createBranch(mergeBlock);
2041
2042 // Make the first else block and add it to the function
2043 elseBlock = new Block(builder.getUniqueId(), *function);
2044 function->addBlock(elseBlock);
2045
2046 // Start building the else block
2047 builder.setBuildPoint(elseBlock);
2048}
2049
2050// Comments in header
2051void Builder::If::makeEndIf()
2052{
2053 // jump to the merge block
2054 builder.createBranch(mergeBlock);
2055
2056 // Go back to the headerBlock and make the flow control split
2057 builder.setBuildPoint(headerBlock);
Rex Xu57e65922017-07-04 23:23:40 +08002058 builder.createSelectionMerge(mergeBlock, control);
John Kessenich140f3df2015-06-26 16:58:36 -06002059 if (elseBlock)
2060 builder.createConditionalBranch(condition, thenBlock, elseBlock);
2061 else
2062 builder.createConditionalBranch(condition, thenBlock, mergeBlock);
2063
2064 // add the merge block to the function
2065 function->addBlock(mergeBlock);
2066 builder.setBuildPoint(mergeBlock);
2067}
2068
2069// Comments in header
Rex Xu57e65922017-07-04 23:23:40 +08002070void Builder::makeSwitch(Id selector, unsigned int control, int numSegments, const std::vector<int>& caseValues,
Vlad Ivanov689490f2017-01-26 20:46:02 +03002071 const std::vector<int>& valueIndexToSegment, int defaultSegment,
John Kessenich140f3df2015-06-26 16:58:36 -06002072 std::vector<Block*>& segmentBlocks)
2073{
2074 Function& function = buildPoint->getParent();
2075
2076 // make all the blocks
2077 for (int s = 0; s < numSegments; ++s)
2078 segmentBlocks.push_back(new Block(getUniqueId(), function));
2079
2080 Block* mergeBlock = new Block(getUniqueId(), function);
2081
2082 // make and insert the switch's selection-merge instruction
Rex Xu57e65922017-07-04 23:23:40 +08002083 createSelectionMerge(mergeBlock, control);
John Kessenich140f3df2015-06-26 16:58:36 -06002084
2085 // make the switch instruction
2086 Instruction* switchInst = new Instruction(NoResult, NoType, OpSwitch);
2087 switchInst->addIdOperand(selector);
Dejan Mircevski454796e2016-01-18 16:18:01 -05002088 auto defaultOrMerge = (defaultSegment >= 0) ? segmentBlocks[defaultSegment] : mergeBlock;
2089 switchInst->addIdOperand(defaultOrMerge->getId());
2090 defaultOrMerge->addPredecessor(buildPoint);
John Kessenich140f3df2015-06-26 16:58:36 -06002091 for (int i = 0; i < (int)caseValues.size(); ++i) {
2092 switchInst->addImmediateOperand(caseValues[i]);
2093 switchInst->addIdOperand(segmentBlocks[valueIndexToSegment[i]]->getId());
Dejan Mircevski454796e2016-01-18 16:18:01 -05002094 segmentBlocks[valueIndexToSegment[i]]->addPredecessor(buildPoint);
John Kessenich140f3df2015-06-26 16:58:36 -06002095 }
Andrew Woloszynb7946d12016-01-18 09:23:56 -05002096 buildPoint->addInstruction(std::unique_ptr<Instruction>(switchInst));
John Kessenich140f3df2015-06-26 16:58:36 -06002097
2098 // push the merge block
2099 switchMerges.push(mergeBlock);
2100}
2101
2102// Comments in header
2103void Builder::addSwitchBreak()
2104{
2105 // branch to the top of the merge block stack
2106 createBranch(switchMerges.top());
2107 createAndSetNoPredecessorBlock("post-switch-break");
2108}
2109
2110// Comments in header
2111void Builder::nextSwitchSegment(std::vector<Block*>& segmentBlock, int nextSegment)
2112{
2113 int lastSegment = nextSegment - 1;
2114 if (lastSegment >= 0) {
2115 // Close out previous segment by jumping, if necessary, to next segment
2116 if (! buildPoint->isTerminated())
2117 createBranch(segmentBlock[nextSegment]);
2118 }
2119 Block* block = segmentBlock[nextSegment];
2120 block->getParent().addBlock(block);
2121 setBuildPoint(block);
2122}
2123
2124// Comments in header
2125void Builder::endSwitch(std::vector<Block*>& /*segmentBlock*/)
2126{
2127 // Close out previous segment by jumping, if necessary, to next segment
2128 if (! buildPoint->isTerminated())
2129 addSwitchBreak();
2130
2131 switchMerges.top()->getParent().addBlock(switchMerges.top());
2132 setBuildPoint(switchMerges.top());
2133
2134 switchMerges.pop();
2135}
2136
Dejan Mircevski9c6734c2016-01-10 12:15:13 -05002137Block& Builder::makeNewBlock()
2138{
2139 Function& function = buildPoint->getParent();
2140 auto block = new Block(getUniqueId(), function);
2141 function.addBlock(block);
2142 return *block;
2143}
2144
Dejan Mircevski7819bee2016-01-11 09:35:22 -05002145Builder::LoopBlocks& Builder::makeNewLoop()
Dejan Mircevski9c6734c2016-01-10 12:15:13 -05002146{
John Kessenich7f349c72016-07-08 22:09:10 -06002147 // This verbosity is needed to simultaneously get the same behavior
2148 // everywhere (id's in the same order), have a syntax that works
2149 // across lots of versions of C++, have no warnings from pedantic
2150 // compilation modes, and leave the rest of the code alone.
2151 Block& head = makeNewBlock();
2152 Block& body = makeNewBlock();
2153 Block& merge = makeNewBlock();
2154 Block& continue_target = makeNewBlock();
2155 LoopBlocks blocks(head, body, merge, continue_target);
Dejan Mircevski97605c82016-01-20 10:19:25 -05002156 loops.push(blocks);
Dejan Mircevski7819bee2016-01-11 09:35:22 -05002157 return loops.top();
John Kessenich140f3df2015-06-26 16:58:36 -06002158}
2159
2160void Builder::createLoopContinue()
2161{
Dejan Mircevski7819bee2016-01-11 09:35:22 -05002162 createBranch(&loops.top().continue_target);
John Kessenich140f3df2015-06-26 16:58:36 -06002163 // Set up a block for dead code.
2164 createAndSetNoPredecessorBlock("post-loop-continue");
2165}
2166
John Kessenich140f3df2015-06-26 16:58:36 -06002167void Builder::createLoopExit()
2168{
Dejan Mircevski7819bee2016-01-11 09:35:22 -05002169 createBranch(&loops.top().merge);
John Kessenich140f3df2015-06-26 16:58:36 -06002170 // Set up a block for dead code.
2171 createAndSetNoPredecessorBlock("post-loop-break");
2172}
2173
John Kessenich140f3df2015-06-26 16:58:36 -06002174void Builder::closeLoop()
2175{
John Kessenich140f3df2015-06-26 16:58:36 -06002176 loops.pop();
2177}
2178
2179void Builder::clearAccessChain()
2180{
John Kessenichfa668da2015-09-13 14:46:30 -06002181 accessChain.base = NoResult;
John Kessenich140f3df2015-06-26 16:58:36 -06002182 accessChain.indexChain.clear();
John Kessenichfa668da2015-09-13 14:46:30 -06002183 accessChain.instr = NoResult;
John Kessenich140f3df2015-06-26 16:58:36 -06002184 accessChain.swizzle.clear();
John Kessenichfa668da2015-09-13 14:46:30 -06002185 accessChain.component = NoResult;
2186 accessChain.preSwizzleBaseType = NoType;
John Kessenich140f3df2015-06-26 16:58:36 -06002187 accessChain.isRValue = false;
2188}
2189
2190// Comments in header
John Kessenichfa668da2015-09-13 14:46:30 -06002191void Builder::accessChainPushSwizzle(std::vector<unsigned>& swizzle, Id preSwizzleBaseType)
John Kessenich140f3df2015-06-26 16:58:36 -06002192{
John Kessenichfa668da2015-09-13 14:46:30 -06002193 // swizzles can be stacked in GLSL, but simplified to a single
2194 // one here; the base type doesn't change
2195 if (accessChain.preSwizzleBaseType == NoType)
2196 accessChain.preSwizzleBaseType = preSwizzleBaseType;
2197
John Kessenich140f3df2015-06-26 16:58:36 -06002198 // if needed, propagate the swizzle for the current access chain
John Kessenich5c3eed52018-02-05 14:44:14 -07002199 if (accessChain.swizzle.size() > 0) {
John Kessenich140f3df2015-06-26 16:58:36 -06002200 std::vector<unsigned> oldSwizzle = accessChain.swizzle;
2201 accessChain.swizzle.resize(0);
2202 for (unsigned int i = 0; i < swizzle.size(); ++i) {
John Kessenich1e275c82016-12-14 17:02:32 -07002203 assert(swizzle[i] < oldSwizzle.size());
John Kessenich140f3df2015-06-26 16:58:36 -06002204 accessChain.swizzle.push_back(oldSwizzle[swizzle[i]]);
2205 }
2206 } else
2207 accessChain.swizzle = swizzle;
2208
2209 // determine if we need to track this swizzle anymore
2210 simplifyAccessChainSwizzle();
2211}
2212
2213// Comments in header
2214void Builder::accessChainStore(Id rvalue)
2215{
2216 assert(accessChain.isRValue == false);
2217
John Kessenich55e7d112015-11-15 21:33:39 -07002218 transferAccessChainSwizzle(true);
John Kessenich140f3df2015-06-26 16:58:36 -06002219 Id base = collapseAccessChain();
John Kessenich5c3eed52018-02-05 14:44:14 -07002220 Id source = rvalue;
2221
2222 // dynamic component should be gone
2223 assert(accessChain.component == NoResult);
John Kessenich140f3df2015-06-26 16:58:36 -06002224
John Kessenich55e7d112015-11-15 21:33:39 -07002225 // 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 -06002226 // extract and insert elements to perform writeMask and/or swizzle.
John Kessenich5c3eed52018-02-05 14:44:14 -07002227 if (accessChain.swizzle.size() > 0) {
John Kessenich140f3df2015-06-26 16:58:36 -06002228 Id tempBaseId = createLoad(base);
John Kessenich5c3eed52018-02-05 14:44:14 -07002229 source = createLvalueSwizzle(getTypeId(tempBaseId), tempBaseId, source, accessChain.swizzle);
John Kessenich140f3df2015-06-26 16:58:36 -06002230 }
2231
John Kessenich140f3df2015-06-26 16:58:36 -06002232 createStore(source, base);
2233}
2234
2235// Comments in header
John Kessenich32cfd492016-02-02 12:37:46 -07002236Id Builder::accessChainLoad(Decoration precision, Id resultType)
John Kessenich140f3df2015-06-26 16:58:36 -06002237{
2238 Id id;
2239
2240 if (accessChain.isRValue) {
John Kessenich5c3eed52018-02-05 14:44:14 -07002241 // transfer access chain, but try to stay in registers
John Kessenich55e7d112015-11-15 21:33:39 -07002242 transferAccessChainSwizzle(false);
John Kessenich140f3df2015-06-26 16:58:36 -06002243 if (accessChain.indexChain.size() > 0) {
John Kessenichfa668da2015-09-13 14:46:30 -06002244 Id swizzleBase = accessChain.preSwizzleBaseType != NoType ? accessChain.preSwizzleBaseType : resultType;
John Kessenich32cfd492016-02-02 12:37:46 -07002245
John Kessenich140f3df2015-06-26 16:58:36 -06002246 // if all the accesses are constants, we can use OpCompositeExtract
2247 std::vector<unsigned> indexes;
2248 bool constant = true;
2249 for (int i = 0; i < (int)accessChain.indexChain.size(); ++i) {
2250 if (isConstantScalar(accessChain.indexChain[i]))
2251 indexes.push_back(getConstantScalar(accessChain.indexChain[i]));
2252 else {
2253 constant = false;
2254 break;
2255 }
2256 }
2257
2258 if (constant)
John Kessenichfa668da2015-09-13 14:46:30 -06002259 id = createCompositeExtract(accessChain.base, swizzleBase, indexes);
John Kessenich140f3df2015-06-26 16:58:36 -06002260 else {
2261 // make a new function variable for this r-value
2262 Id lValue = createVariable(StorageClassFunction, getTypeId(accessChain.base), "indexable");
2263
2264 // store into it
2265 createStore(accessChain.base, lValue);
2266
2267 // move base to the new variable
2268 accessChain.base = lValue;
2269 accessChain.isRValue = false;
2270
2271 // load through the access chain
2272 id = createLoad(collapseAccessChain());
2273 }
John Kessenich32cfd492016-02-02 12:37:46 -07002274 setPrecision(id, precision);
John Kessenich140f3df2015-06-26 16:58:36 -06002275 } else
John Kessenich32cfd492016-02-02 12:37:46 -07002276 id = accessChain.base; // no precision, it was set when this was defined
John Kessenich140f3df2015-06-26 16:58:36 -06002277 } else {
John Kessenich55e7d112015-11-15 21:33:39 -07002278 transferAccessChainSwizzle(true);
John Kessenich140f3df2015-06-26 16:58:36 -06002279 // load through the access chain
2280 id = createLoad(collapseAccessChain());
John Kessenich32cfd492016-02-02 12:37:46 -07002281 setPrecision(id, precision);
John Kessenich140f3df2015-06-26 16:58:36 -06002282 }
2283
2284 // Done, unless there are swizzles to do
John Kessenichfa668da2015-09-13 14:46:30 -06002285 if (accessChain.swizzle.size() == 0 && accessChain.component == NoResult)
John Kessenich140f3df2015-06-26 16:58:36 -06002286 return id;
2287
John Kessenich140f3df2015-06-26 16:58:36 -06002288 // Do remaining swizzling
John Kessenich5c3eed52018-02-05 14:44:14 -07002289
2290 // Do the basic swizzle
2291 if (accessChain.swizzle.size() > 0) {
John Kessenichfa668da2015-09-13 14:46:30 -06002292 Id swizzledType = getScalarTypeId(getTypeId(id));
John Kessenich140f3df2015-06-26 16:58:36 -06002293 if (accessChain.swizzle.size() > 1)
John Kessenichfa668da2015-09-13 14:46:30 -06002294 swizzledType = makeVectorType(swizzledType, (int)accessChain.swizzle.size());
John Kessenich32cfd492016-02-02 12:37:46 -07002295 id = createRvalueSwizzle(precision, swizzledType, id, accessChain.swizzle);
John Kessenich140f3df2015-06-26 16:58:36 -06002296 }
2297
John Kessenich5c3eed52018-02-05 14:44:14 -07002298 // Do the dynamic component
John Kessenichfa668da2015-09-13 14:46:30 -06002299 if (accessChain.component != NoResult)
John Kessenich32cfd492016-02-02 12:37:46 -07002300 id = setPrecision(createVectorExtractDynamic(id, resultType, accessChain.component), precision);
John Kessenich140f3df2015-06-26 16:58:36 -06002301
2302 return id;
2303}
2304
2305Id Builder::accessChainGetLValue()
2306{
2307 assert(accessChain.isRValue == false);
2308
John Kessenich55e7d112015-11-15 21:33:39 -07002309 transferAccessChainSwizzle(true);
John Kessenich140f3df2015-06-26 16:58:36 -06002310 Id lvalue = collapseAccessChain();
2311
2312 // If swizzle exists, it is out-of-order or not full, we must load the target vector,
2313 // extract and insert elements to perform writeMask and/or swizzle. This does not
2314 // go with getting a direct l-value pointer.
2315 assert(accessChain.swizzle.size() == 0);
John Kessenichfa668da2015-09-13 14:46:30 -06002316 assert(accessChain.component == NoResult);
John Kessenich140f3df2015-06-26 16:58:36 -06002317
2318 return lvalue;
2319}
2320
John Kessenich103bef92016-02-08 21:38:15 -07002321// comment in header
2322Id Builder::accessChainGetInferredType()
2323{
2324 // anything to operate on?
2325 if (accessChain.base == NoResult)
2326 return NoType;
2327 Id type = getTypeId(accessChain.base);
2328
2329 // do initial dereference
2330 if (! accessChain.isRValue)
2331 type = getContainedTypeId(type);
2332
2333 // dereference each index
rdb32084e82016-02-23 22:17:38 +01002334 for (auto it = accessChain.indexChain.cbegin(); it != accessChain.indexChain.cend(); ++it) {
John Kessenich103bef92016-02-08 21:38:15 -07002335 if (isStructType(type))
rdb32084e82016-02-23 22:17:38 +01002336 type = getContainedTypeId(type, getConstantScalar(*it));
John Kessenich103bef92016-02-08 21:38:15 -07002337 else
2338 type = getContainedTypeId(type);
2339 }
2340
2341 // dereference swizzle
2342 if (accessChain.swizzle.size() == 1)
2343 type = getContainedTypeId(type);
2344 else if (accessChain.swizzle.size() > 1)
baldurk227e0262016-02-10 19:41:29 +01002345 type = makeVectorType(getContainedTypeId(type), (int)accessChain.swizzle.size());
John Kessenich103bef92016-02-08 21:38:15 -07002346
2347 // dereference component selection
2348 if (accessChain.component)
2349 type = getContainedTypeId(type);
2350
2351 return type;
2352}
2353
qiningda397332016-03-09 19:54:03 -05002354// comment in header
2355void Builder::eliminateDeadDecorations() {
2356 std::unordered_set<const Block*> reachable_blocks;
2357 std::unordered_set<Id> unreachable_definitions;
2358 // Collect IDs defined in unreachable blocks. For each function, label the
2359 // reachable blocks first. Then for each unreachable block, collect the
2360 // result IDs of the instructions in it.
qining95aa5272016-03-09 21:40:41 -05002361 for (std::vector<Function*>::const_iterator fi = module.getFunctions().cbegin();
2362 fi != module.getFunctions().cend(); fi++) {
2363 Function* f = *fi;
qiningda397332016-03-09 19:54:03 -05002364 Block* entry = f->getEntryBlock();
2365 inReadableOrder(entry, [&reachable_blocks](const Block* b) {
2366 reachable_blocks.insert(b);
2367 });
qining95aa5272016-03-09 21:40:41 -05002368 for (std::vector<Block*>::const_iterator bi = f->getBlocks().cbegin();
2369 bi != f->getBlocks().cend(); bi++) {
2370 Block* b = *bi;
qiningda397332016-03-09 19:54:03 -05002371 if (!reachable_blocks.count(b)) {
qining95aa5272016-03-09 21:40:41 -05002372 for (std::vector<std::unique_ptr<Instruction> >::const_iterator
2373 ii = b->getInstructions().cbegin();
2374 ii != b->getInstructions().cend(); ii++) {
2375 Instruction* i = ii->get();
qiningda397332016-03-09 19:54:03 -05002376 unreachable_definitions.insert(i->getResultId());
2377 }
2378 }
2379 }
2380 }
2381 decorations.erase(std::remove_if(decorations.begin(), decorations.end(),
baldurkbd9f8352016-04-02 13:38:42 +02002382 [&unreachable_definitions](std::unique_ptr<Instruction>& I) -> bool {
qiningda397332016-03-09 19:54:03 -05002383 Instruction* inst = I.get();
2384 Id decoration_id = inst->getIdOperand(0);
2385 return unreachable_definitions.count(decoration_id) != 0;
2386 }),
2387 decorations.end());
2388}
2389
John Kessenich140f3df2015-06-26 16:58:36 -06002390void Builder::dump(std::vector<unsigned int>& out) const
2391{
2392 // Header, before first instructions:
2393 out.push_back(MagicNumber);
John Kessenich2b5ea9f2018-01-31 18:35:56 -07002394 out.push_back(spvVersion);
John Kessenich140f3df2015-06-26 16:58:36 -06002395 out.push_back(builderNumber);
2396 out.push_back(uniqueId + 1);
2397 out.push_back(0);
2398
John Kessenich55e7d112015-11-15 21:33:39 -07002399 // Capabilities
rdb32084e82016-02-23 22:17:38 +01002400 for (auto it = capabilities.cbegin(); it != capabilities.cend(); ++it) {
John Kessenich55e7d112015-11-15 21:33:39 -07002401 Instruction capInst(0, 0, OpCapability);
rdb32084e82016-02-23 22:17:38 +01002402 capInst.addImmediateOperand(*it);
John Kessenich55e7d112015-11-15 21:33:39 -07002403 capInst.dump(out);
2404 }
2405
Rex Xu51596642016-09-21 18:56:12 +08002406 for (auto it = extensions.cbegin(); it != extensions.cend(); ++it) {
Rex Xu9d93a232016-05-05 12:30:44 +08002407 Instruction extInst(0, 0, OpExtension);
Rex Xu430ef402016-10-14 17:22:23 +08002408 extInst.addStringOperand(it->c_str());
Rex Xu9d93a232016-05-05 12:30:44 +08002409 extInst.dump(out);
2410 }
John Kessenich55e7d112015-11-15 21:33:39 -07002411
2412 dumpInstructions(out, imports);
2413 Instruction memInst(0, 0, OpMemoryModel);
2414 memInst.addImmediateOperand(addressModel);
2415 memInst.addImmediateOperand(memoryModel);
2416 memInst.dump(out);
2417
2418 // Instructions saved up while building:
2419 dumpInstructions(out, entryPoints);
2420 dumpInstructions(out, executionModes);
2421
2422 // Debug instructions
John Kessenich121853f2017-05-31 17:11:16 -06002423 dumpInstructions(out, strings);
John Kessenich2a271162017-07-20 20:00:36 -06002424 dumpModuleProcesses(out);
John Kessenich121853f2017-05-31 17:11:16 -06002425 dumpSourceInstructions(out);
Rex Xu9d93a232016-05-05 12:30:44 +08002426 for (int e = 0; e < (int)sourceExtensions.size(); ++e) {
2427 Instruction sourceExtInst(0, 0, OpSourceExtension);
2428 sourceExtInst.addStringOperand(sourceExtensions[e]);
2429 sourceExtInst.dump(out);
John Kessenich140f3df2015-06-26 16:58:36 -06002430 }
John Kessenich140f3df2015-06-26 16:58:36 -06002431 dumpInstructions(out, names);
2432 dumpInstructions(out, lines);
John Kessenich55e7d112015-11-15 21:33:39 -07002433
2434 // Annotation instructions
John Kessenich140f3df2015-06-26 16:58:36 -06002435 dumpInstructions(out, decorations);
John Kessenich55e7d112015-11-15 21:33:39 -07002436
John Kessenich140f3df2015-06-26 16:58:36 -06002437 dumpInstructions(out, constantsTypesGlobals);
2438 dumpInstructions(out, externals);
2439
2440 // The functions
2441 module.dump(out);
2442}
2443
2444//
2445// Protected methods.
2446//
2447
John Kessenich5c3eed52018-02-05 14:44:14 -07002448// Turn the described access chain in 'accessChain' into an instruction(s)
John Kessenich55e7d112015-11-15 21:33:39 -07002449// computing its address. This *cannot* include complex swizzles, which must
John Kessenich5c3eed52018-02-05 14:44:14 -07002450// be handled after this is called.
2451//
2452// Can generate code.
John Kessenich140f3df2015-06-26 16:58:36 -06002453Id Builder::collapseAccessChain()
2454{
John Kessenich140f3df2015-06-26 16:58:36 -06002455 assert(accessChain.isRValue == false);
2456
John Kessenich5c3eed52018-02-05 14:44:14 -07002457 // did we already emit an access chain for this?
2458 if (accessChain.instr != NoResult)
John Kessenich140f3df2015-06-26 16:58:36 -06002459 return accessChain.instr;
John Kessenich5c3eed52018-02-05 14:44:14 -07002460
2461 // If we have a dynamic component, we can still transfer
2462 // that into a final operand to the access chain. We need to remap the
2463 // dynamic component through the swizzle to get a new dynamic component to
2464 // update.
2465 //
2466 // This was not done in transferAccessChainSwizzle() because it might
2467 // generate code.
2468 remapDynamicSwizzle();
2469 if (accessChain.component != NoResult) {
2470 // transfer the dynamic component to the access chain
2471 accessChain.indexChain.push_back(accessChain.component);
2472 accessChain.component = NoResult;
2473 }
2474
2475 // note that non-trivial swizzling is left pending
2476
2477 // do we have an access chain?
2478 if (accessChain.indexChain.size() == 0)
John Kessenich140f3df2015-06-26 16:58:36 -06002479 return accessChain.base;
John Kessenich55e7d112015-11-15 21:33:39 -07002480
John Kessenich5c3eed52018-02-05 14:44:14 -07002481 // emit the access chain
2482 StorageClass storageClass = (StorageClass)module.getStorageClass(getTypeId(accessChain.base));
2483 accessChain.instr = createAccessChain(storageClass, accessChain.base, accessChain.indexChain);
2484
2485 return accessChain.instr;
2486}
2487
2488// For a dynamic component selection of a swizzle.
2489//
2490// Turn the swizzle and dynamic component into just a dynamic component.
2491//
2492// Generates code.
2493void Builder::remapDynamicSwizzle()
2494{
2495 // do we have a swizzle to remap a dynamic component through?
2496 if (accessChain.component != NoResult && accessChain.swizzle.size() > 1) {
2497 // build a vector of the swizzle for the component to map into
2498 std::vector<Id> components;
2499 for (int c = 0; c < accessChain.swizzle.size(); ++c)
2500 components.push_back(makeUintConstant(accessChain.swizzle[c]));
2501 Id mapType = makeVectorType(makeUintType(32), (int)accessChain.swizzle.size());
2502 Id map = makeCompositeConstant(mapType, components);
2503
2504 // use it
2505 accessChain.component = createVectorExtractDynamic(map, makeUintType(32), accessChain.component);
2506 accessChain.swizzle.clear();
2507 }
John Kessenich140f3df2015-06-26 16:58:36 -06002508}
2509
John Kessenich55e7d112015-11-15 21:33:39 -07002510// clear out swizzle if it is redundant, that is reselecting the same components
2511// that would be present without the swizzle.
John Kessenich140f3df2015-06-26 16:58:36 -06002512void Builder::simplifyAccessChainSwizzle()
2513{
2514 // If the swizzle has fewer components than the vector, it is subsetting, and must stay
2515 // to preserve that fact.
John Kessenichfa668da2015-09-13 14:46:30 -06002516 if (getNumTypeComponents(accessChain.preSwizzleBaseType) > (int)accessChain.swizzle.size())
John Kessenich140f3df2015-06-26 16:58:36 -06002517 return;
2518
2519 // if components are out of order, it is a swizzle
2520 for (unsigned int i = 0; i < accessChain.swizzle.size(); ++i) {
2521 if (i != accessChain.swizzle[i])
2522 return;
2523 }
2524
2525 // otherwise, there is no need to track this swizzle
2526 accessChain.swizzle.clear();
John Kessenichfa668da2015-09-13 14:46:30 -06002527 if (accessChain.component == NoResult)
2528 accessChain.preSwizzleBaseType = NoType;
John Kessenich140f3df2015-06-26 16:58:36 -06002529}
2530
John Kessenich55e7d112015-11-15 21:33:39 -07002531// To the extent any swizzling can become part of the chain
2532// of accesses instead of a post operation, make it so.
John Kessenich5c3eed52018-02-05 14:44:14 -07002533// If 'dynamic' is true, include transferring the dynamic component,
2534// otherwise, leave it pending.
John Kessenich55e7d112015-11-15 21:33:39 -07002535//
John Kessenich5c3eed52018-02-05 14:44:14 -07002536// Does not generate code. just updates the access chain.
John Kessenich55e7d112015-11-15 21:33:39 -07002537void Builder::transferAccessChainSwizzle(bool dynamic)
John Kessenich140f3df2015-06-26 16:58:36 -06002538{
John Kessenich55e7d112015-11-15 21:33:39 -07002539 // non existent?
2540 if (accessChain.swizzle.size() == 0 && accessChain.component == NoResult)
John Kessenich140f3df2015-06-26 16:58:36 -06002541 return;
2542
John Kessenich5c3eed52018-02-05 14:44:14 -07002543 // too complex?
2544 // (this requires either a swizzle, or generating code for a dynamic component)
2545 if (accessChain.swizzle.size() > 1)
John Kessenich55e7d112015-11-15 21:33:39 -07002546 return;
2547
John Kessenich5c3eed52018-02-05 14:44:14 -07002548 // single component, either in the swizzle and/or dynamic component
John Kessenich55e7d112015-11-15 21:33:39 -07002549 if (accessChain.swizzle.size() == 1) {
John Kessenich5c3eed52018-02-05 14:44:14 -07002550 assert(accessChain.component == NoResult);
2551 // handle static component selection
John Kessenich140f3df2015-06-26 16:58:36 -06002552 accessChain.indexChain.push_back(makeUintConstant(accessChain.swizzle.front()));
John Kessenich55e7d112015-11-15 21:33:39 -07002553 accessChain.swizzle.clear();
John Kessenich55e7d112015-11-15 21:33:39 -07002554 accessChain.preSwizzleBaseType = NoType;
John Kessenich55e7d112015-11-15 21:33:39 -07002555 } else if (dynamic && accessChain.component != NoResult) {
John Kessenich5c3eed52018-02-05 14:44:14 -07002556 assert(accessChain.swizzle.size() == 0);
John Kessenich55e7d112015-11-15 21:33:39 -07002557 // handle dynamic component
John Kessenich140f3df2015-06-26 16:58:36 -06002558 accessChain.indexChain.push_back(accessChain.component);
John Kessenich55e7d112015-11-15 21:33:39 -07002559 accessChain.preSwizzleBaseType = NoType;
2560 accessChain.component = NoResult;
2561 }
John Kessenich140f3df2015-06-26 16:58:36 -06002562}
2563
2564// Utility method for creating a new block and setting the insert point to
2565// be in it. This is useful for flow-control operations that need a "dummy"
2566// block proceeding them (e.g. instructions after a discard, etc).
2567void Builder::createAndSetNoPredecessorBlock(const char* /*name*/)
2568{
2569 Block* block = new Block(getUniqueId(), buildPoint->getParent());
2570 block->setUnreachable();
2571 buildPoint->getParent().addBlock(block);
2572 setBuildPoint(block);
2573
John Kessenich927608b2017-01-06 12:34:14 -07002574 // if (name)
John Kessenich140f3df2015-06-26 16:58:36 -06002575 // addName(block->getId(), name);
2576}
2577
2578// Comments in header
2579void Builder::createBranch(Block* block)
2580{
2581 Instruction* branch = new Instruction(OpBranch);
2582 branch->addIdOperand(block->getId());
Andrew Woloszynb7946d12016-01-18 09:23:56 -05002583 buildPoint->addInstruction(std::unique_ptr<Instruction>(branch));
John Kessenich140f3df2015-06-26 16:58:36 -06002584 block->addPredecessor(buildPoint);
2585}
2586
John Kessenich55e7d112015-11-15 21:33:39 -07002587void Builder::createSelectionMerge(Block* mergeBlock, unsigned int control)
John Kessenich140f3df2015-06-26 16:58:36 -06002588{
John Kessenich55e7d112015-11-15 21:33:39 -07002589 Instruction* merge = new Instruction(OpSelectionMerge);
John Kessenich140f3df2015-06-26 16:58:36 -06002590 merge->addIdOperand(mergeBlock->getId());
2591 merge->addImmediateOperand(control);
Andrew Woloszynb7946d12016-01-18 09:23:56 -05002592 buildPoint->addInstruction(std::unique_ptr<Instruction>(merge));
John Kessenich140f3df2015-06-26 16:58:36 -06002593}
2594
John Kessenicha2858d92018-01-31 08:11:18 -07002595void Builder::createLoopMerge(Block* mergeBlock, Block* continueBlock, unsigned int control,
2596 unsigned int dependencyLength)
John Kessenich55e7d112015-11-15 21:33:39 -07002597{
2598 Instruction* merge = new Instruction(OpLoopMerge);
2599 merge->addIdOperand(mergeBlock->getId());
2600 merge->addIdOperand(continueBlock->getId());
2601 merge->addImmediateOperand(control);
John Kessenicha2858d92018-01-31 08:11:18 -07002602 if ((control & LoopControlDependencyLengthMask) != 0)
2603 merge->addImmediateOperand(dependencyLength);
Andrew Woloszynb7946d12016-01-18 09:23:56 -05002604 buildPoint->addInstruction(std::unique_ptr<Instruction>(merge));
John Kessenich55e7d112015-11-15 21:33:39 -07002605}
2606
John Kessenich140f3df2015-06-26 16:58:36 -06002607void Builder::createConditionalBranch(Id condition, Block* thenBlock, Block* elseBlock)
2608{
2609 Instruction* branch = new Instruction(OpBranchConditional);
2610 branch->addIdOperand(condition);
2611 branch->addIdOperand(thenBlock->getId());
2612 branch->addIdOperand(elseBlock->getId());
Andrew Woloszynb7946d12016-01-18 09:23:56 -05002613 buildPoint->addInstruction(std::unique_ptr<Instruction>(branch));
John Kessenich140f3df2015-06-26 16:58:36 -06002614 thenBlock->addPredecessor(buildPoint);
2615 elseBlock->addPredecessor(buildPoint);
2616}
2617
John Kessenich121853f2017-05-31 17:11:16 -06002618// OpSource
2619// [OpSourceContinued]
2620// ...
2621void Builder::dumpSourceInstructions(std::vector<unsigned int>& out) const
2622{
2623 const int maxWordCount = 0xFFFF;
2624 const int opSourceWordCount = 4;
2625 const int nonNullBytesPerInstruction = 4 * (maxWordCount - opSourceWordCount) - 1;
2626
2627 if (source != SourceLanguageUnknown) {
2628 // OpSource Language Version File Source
2629 Instruction sourceInst(NoResult, NoType, OpSource);
2630 sourceInst.addImmediateOperand(source);
2631 sourceInst.addImmediateOperand(sourceVersion);
2632 // File operand
2633 if (sourceFileStringId != NoResult) {
2634 sourceInst.addIdOperand(sourceFileStringId);
2635 // Source operand
2636 if (sourceText.size() > 0) {
2637 int nextByte = 0;
2638 std::string subString;
2639 while ((int)sourceText.size() - nextByte > 0) {
2640 subString = sourceText.substr(nextByte, nonNullBytesPerInstruction);
2641 if (nextByte == 0) {
2642 // OpSource
2643 sourceInst.addStringOperand(subString.c_str());
2644 sourceInst.dump(out);
2645 } else {
2646 // OpSourcContinued
2647 Instruction sourceContinuedInst(OpSourceContinued);
2648 sourceContinuedInst.addStringOperand(subString.c_str());
2649 sourceContinuedInst.dump(out);
2650 }
2651 nextByte += nonNullBytesPerInstruction;
2652 }
2653 } else
2654 sourceInst.dump(out);
2655 } else
2656 sourceInst.dump(out);
2657 }
2658}
2659
Andrew Woloszynb7946d12016-01-18 09:23:56 -05002660void Builder::dumpInstructions(std::vector<unsigned int>& out, const std::vector<std::unique_ptr<Instruction> >& instructions) const
John Kessenich140f3df2015-06-26 16:58:36 -06002661{
2662 for (int i = 0; i < (int)instructions.size(); ++i) {
2663 instructions[i]->dump(out);
2664 }
2665}
2666
John Kessenich2a271162017-07-20 20:00:36 -06002667void Builder::dumpModuleProcesses(std::vector<unsigned int>& out) const
2668{
2669 for (int i = 0; i < (int)moduleProcesses.size(); ++i) {
John Kessenich2a271162017-07-20 20:00:36 -06002670 Instruction moduleProcessed(OpModuleProcessed);
2671 moduleProcessed.addStringOperand(moduleProcesses[i]);
2672 moduleProcessed.dump(out);
2673 }
2674}
2675
John Kessenich140f3df2015-06-26 16:58:36 -06002676}; // end spv namespace